From 7f734582e9a23842f5089bce4d814d55da1a9263 Mon Sep 17 00:00:00 2001 From: Yehonatan Cohen Scaly Date: Wed, 22 Oct 2025 12:29:23 +0300 Subject: [PATCH] Expose functions --- src/const_choice.rs | 56 ++++++++++++++++++++++++++++++-------------- src/int.rs | 9 +++++-- src/int/cmp.rs | 14 +++++------ src/lib.rs | 12 ++++++++-- src/limb/cmp.rs | 4 ++-- src/uint.rs | 4 ++-- src/uint/cmp.rs | 23 +++++++++++------- src/uint/div_limb.rs | 8 +------ src/uint/shl.rs | 2 +- src/uint/shr.rs | 2 +- 10 files changed, 83 insertions(+), 51 deletions(-) diff --git a/src/const_choice.rs b/src/const_choice.rs index 67dbfa8bc..3c11226ac 100644 --- a/src/const_choice.rs +++ b/src/const_choice.rs @@ -44,7 +44,7 @@ impl ConstChoice { /// Returns the truthy value if `value == Word::MAX`, and the falsy value if `value == 0`. /// Panics for other values. #[inline] - pub(crate) const fn from_word_mask(value: Word) -> Self { + pub const fn from_word_mask(value: Word) -> Self { debug_assert!(value == Self::FALSE.0 || value == Self::TRUE.0); Self(value) } @@ -88,7 +88,7 @@ impl ConstChoice { /// Returns the truthy value if `value != 0`, and the falsy value otherwise. #[inline] - pub(crate) const fn from_u32_nonzero(value: u32) -> Self { + pub const fn from_u32_nonzero(value: u32) -> Self { Self::from_u32_lsb((value | value.wrapping_neg()) >> (u32::BITS - 1)) } @@ -132,7 +132,7 @@ impl ConstChoice { /// Returns the truthy value if `x < y`, and the falsy value otherwise. #[inline] - pub(crate) const fn from_u32_lt(x: u32, y: u32) -> Self { + pub const fn from_u32_lt(x: u32, y: u32) -> Self { // See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates) let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (u32::BITS - 1); Self::from_u32_lsb(bit) @@ -156,7 +156,7 @@ impl ConstChoice { /// Returns the truthy value if `x <= y` and the falsy value otherwise. #[inline] - pub(crate) const fn from_u32_le(x: u32, y: u32) -> Self { + pub const fn from_u32_le(x: u32, y: u32) -> Self { // See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates) let bit = (((!x) | y) & ((x ^ y) | !(y.wrapping_sub(x)))) >> (u32::BITS - 1); Self::from_u32_lsb(bit) @@ -169,38 +169,38 @@ impl ConstChoice { } #[inline] - pub(crate) const fn not(&self) -> Self { + pub const fn not(&self) -> Self { Self(!self.0) } #[inline] - pub(crate) const fn or(&self, other: Self) -> Self { + pub const fn or(&self, other: Self) -> Self { Self(self.0 | other.0) } #[inline] - pub(crate) const fn and(&self, other: Self) -> Self { + pub const fn and(&self, other: Self) -> Self { Self(self.0 & other.0) } #[inline] - pub(crate) const fn xor(&self, other: Self) -> Self { + pub const fn xor(&self, other: Self) -> Self { Self(self.0 ^ other.0) } #[inline] - pub(crate) const fn ne(&self, other: Self) -> Self { + pub const fn ne(&self, other: Self) -> Self { Self::xor(self, other) } #[inline] - pub(crate) const fn eq(&self, other: Self) -> Self { + pub const fn eq(&self, other: Self) -> Self { Self::ne(self, other).not() } /// Return `b` if `self` is truthy, otherwise return `a`. #[inline] - pub(crate) const fn select_word(&self, a: Word, b: Word) -> Word { + pub const fn select_word(&self, a: Word, b: Word) -> Word { a ^ (self.0 & (a ^ b)) } @@ -213,7 +213,7 @@ impl ConstChoice { /// Return `b` if `self` is truthy, otherwise return `a`. #[inline] - pub(crate) const fn select_u32(&self, a: u32, b: u32) -> u32 { + pub const fn select_u32(&self, a: u32, b: u32) -> u32 { a ^ (self.as_u32_mask() & (a ^ b)) } @@ -229,6 +229,12 @@ impl ConstChoice { a ^ (self.as_u64_mask() & (a ^ b)) } + /// Swap `a` and `b` if `self` is truthy. Otherwise do nothing. + #[inline] + pub const fn conditional_swap_u32(&self, a: &mut u32, b: &mut u32) { + (*a, *b) = (self.select_u32(*a, *b), self.select_u32(*b, *a)) + } + /// Return `x` if `self` is truthy, otherwise return 0. #[inline] pub(crate) const fn if_true_word(&self, x: Word) -> Word { @@ -253,7 +259,7 @@ impl ConstChoice { /// WARNING: this method should only be used in contexts that aren't constant-time critical! #[inline] - pub(crate) const fn to_bool_vartime(self) -> bool { + pub const fn to_bool_vartime(self) -> bool { self.to_u8() != 0 } } @@ -303,12 +309,12 @@ pub struct ConstCtOption { impl ConstCtOption { #[inline] - pub(crate) const fn new(value: T, is_some: ConstChoice) -> Self { + pub const fn new(value: T, is_some: ConstChoice) -> Self { Self { value, is_some } } #[inline] - pub(crate) const fn some(value: T) -> Self { + pub const fn some(value: T) -> Self { Self { value, is_some: ConstChoice::TRUE, @@ -316,7 +322,7 @@ impl ConstCtOption { } #[inline] - pub(crate) const fn none(dummy_value: T) -> Self { + pub const fn none(dummy_value: T) -> Self { Self { value: dummy_value, is_some: ConstChoice::FALSE, @@ -327,7 +333,7 @@ impl ConstCtOption { /// /// **Note:** if the second element is `None`, the first value may take any value. #[inline] - pub(crate) const fn components_ref(&self) -> (&T, ConstChoice) { + pub const fn components_ref(&self) -> (&T, ConstChoice) { // Since Rust is not smart enough to tell that we would be moving the value, // and hence no destructors will be called, we have to return a reference instead. // See https://github.com/rust-lang/rust/issues/66753 @@ -359,7 +365,7 @@ impl ConstCtOption { /// Apply an additional [`ConstChoice`] requirement to `is_some`. #[inline] - pub(crate) const fn and_choice(mut self, is_some: ConstChoice) -> Self { + pub const fn and_choice(mut self, is_some: ConstChoice) -> Self { self.is_some = self.is_some.and(is_some); self } @@ -429,6 +435,20 @@ impl ConstCtOption<(Uint, Uint)> { } } +impl ConstCtOption<(Uint, ConstChoice)> { + /// Returns the contained value, consuming the `self` value. + /// + /// # Panics + /// + /// Panics if the value is none with a custom panic message provided by + /// `msg`. + #[inline] + pub const fn expect(self, msg: &str) -> (Uint, ConstChoice) { + assert!(self.is_some.is_true_vartime(), "{}", msg); + self.value + } +} + impl ConstCtOption>> { /// Returns the contained value, consuming the `self` value. /// diff --git a/src/int.rs b/src/int.rs index 6295ee255..b0dc7c204 100644 --- a/src/int.rs +++ b/src/int.rs @@ -23,7 +23,7 @@ mod div; mod div_uint; mod encoding; mod from; -mod gcd; +pub(crate) mod gcd; mod invert_mod; mod mod_symbol; mod mul; @@ -151,11 +151,16 @@ impl Int { ConstCtOption::new(NonZero(self), self.0.is_nonzero()) } + /// Whether this [`Int`] is odd. + pub const fn is_odd(self) -> ConstChoice { + self.0.is_odd() + } + /// Convert to a [`Odd>`]. /// /// Returns some if the original value is odd, and false otherwise. pub const fn to_odd(self) -> ConstCtOption> { - ConstCtOption::new(Odd(self), self.0.is_odd()) + ConstCtOption::new(Odd(self), self.is_odd()) } /// Interpret the data in this object as a [`Uint`] instead. diff --git a/src/int/cmp.rs b/src/int/cmp.rs index ce22989ce..8618b4102 100644 --- a/src/int/cmp.rs +++ b/src/int/cmp.rs @@ -11,37 +11,37 @@ use crate::{ConstChoice, Int, Uint}; impl Int { /// Return `b` if `c` is truthy, otherwise return `a`. #[inline] - pub(crate) const fn select(a: &Self, b: &Self, c: ConstChoice) -> Self { + pub const fn select(a: &Self, b: &Self, c: ConstChoice) -> Self { Self(Uint::select(&a.0, &b.0, c)) } /// Swap `a` and `b` if `c` is truthy, otherwise, do nothing. #[inline] - pub(crate) const fn conditional_swap(a: &mut Self, b: &mut Self, c: ConstChoice) { + pub const fn conditional_swap(a: &mut Self, b: &mut Self, c: ConstChoice) { Uint::conditional_swap(&mut a.0, &mut b.0, c); } /// Returns the truthy value if `self`!=0 or the falsy value otherwise. #[inline] - pub(crate) const fn is_nonzero(&self) -> ConstChoice { + pub const fn is_nonzero(&self) -> ConstChoice { Uint::is_nonzero(&self.0) } /// Returns the truthy value if `self == rhs` or the falsy value otherwise. #[inline] - pub(crate) const fn eq(lhs: &Self, rhs: &Self) -> ConstChoice { + pub const fn eq(lhs: &Self, rhs: &Self) -> ConstChoice { Uint::eq(&lhs.0, &rhs.0) } /// Returns the truthy value if `self < rhs` and the falsy value otherwise. #[inline] - pub(crate) const fn lt(lhs: &Self, rhs: &Self) -> ConstChoice { + pub const fn lt(lhs: &Self, rhs: &Self) -> ConstChoice { Uint::lt(&lhs.invert_msb().0, &rhs.invert_msb().0) } /// Returns the truthy value if `self > rhs` and the falsy value otherwise. #[inline] - pub(crate) const fn gt(lhs: &Self, rhs: &Self) -> ConstChoice { + pub const fn gt(lhs: &Self, rhs: &Self) -> ConstChoice { Uint::gt(&lhs.invert_msb().0, &rhs.invert_msb().0) } @@ -51,7 +51,7 @@ impl Int { /// 0 is Equal /// 1 is Greater #[inline] - pub(crate) const fn cmp(lhs: &Self, rhs: &Self) -> i8 { + pub const fn cmp(lhs: &Self, rhs: &Self) -> i8 { Uint::cmp(&lhs.invert_msb().0, &rhs.invert_msb().0) } diff --git a/src/lib.rs b/src/lib.rs index d98d54b2d..1cc670a9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -186,13 +186,21 @@ pub use crate::uint::boxed::BoxedUint; pub use crate::{ checked::Checked, const_choice::{ConstChoice, ConstCtOption}, - int::{types::*, *}, + int::{ + gcd::{IntXgcdOutput, NonZeroIntXgcdOutput, OddIntXgcdOutput}, + types::*, + *, + }, jacobi::JacobiSymbol, limb::{Limb, WideWord, Word}, non_zero::*, odd::*, traits::*, - uint::{div_limb::Reciprocal, *}, + uint::div_limb::{Reciprocal, div3by2}, + uint::{ + gcd::{NonZeroUintXgcdOutput, OddUintXgcdOutput, UintXgcdOutput}, + *, + }, wrapping::Wrapping, }; diff --git a/src/limb/cmp.rs b/src/limb/cmp.rs index 607f57d1a..815dd2912 100644 --- a/src/limb/cmp.rs +++ b/src/limb/cmp.rs @@ -28,7 +28,7 @@ impl Limb { /// Return `b` if `c` is truthy, otherwise return `a`. #[inline] - pub(crate) const fn select(a: Self, b: Self, c: ConstChoice) -> Self { + pub const fn select(a: Self, b: Self, c: ConstChoice) -> Self { Self(c.select_word(a.0, b.0)) } @@ -40,7 +40,7 @@ impl Limb { /// Returns the truthy value if `self != 0` and the falsy value otherwise. #[inline] - pub(crate) const fn is_nonzero(&self) -> ConstChoice { + pub const fn is_nonzero(&self) -> ConstChoice { ConstChoice::from_word_nonzero(self.0) } } diff --git a/src/uint.rs b/src/uint.rs index c27ae6a81..9ee89c77f 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -190,13 +190,13 @@ impl Uint { /// Borrow the limbs of this [`Uint`] as a [`UintRef`]. #[inline(always)] - pub(crate) const fn as_uint_ref(&self) -> &UintRef { + pub const fn as_uint_ref(&self) -> &UintRef { UintRef::new(&self.limbs) } /// Mutably borrow the limbs of this [`Uint`] as a [`UintRef`]. #[inline(always)] - pub(crate) const fn as_mut_uint_ref(&mut self) -> &mut UintRef { + pub const fn as_mut_uint_ref(&mut self) -> &mut UintRef { UintRef::new_mut(&mut self.limbs) } diff --git a/src/uint/cmp.rs b/src/uint/cmp.rs index 9281c7e80..cf13db475 100644 --- a/src/uint/cmp.rs +++ b/src/uint/cmp.rs @@ -13,7 +13,7 @@ use super::Uint; impl Uint { /// Return `b` if `c` is truthy, otherwise return `a`. #[inline] - pub(crate) const fn select(a: &Self, b: &Self, c: ConstChoice) -> Self { + pub const fn select(a: &Self, b: &Self, c: ConstChoice) -> Self { let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; @@ -27,7 +27,7 @@ impl Uint { /// Swap `a` and `b` if `c` is truthy, otherwise, do nothing. #[inline] - pub(crate) const fn conditional_swap(a: &mut Self, b: &mut Self, c: ConstChoice) { + pub const fn conditional_swap(a: &mut Self, b: &mut Self, c: ConstChoice) { let mut i = 0; let a = a.as_mut_limbs(); let b = b.as_mut_limbs(); @@ -39,13 +39,13 @@ impl Uint { /// Swap `a` and `b` #[inline] - pub(crate) const fn swap(a: &mut Self, b: &mut Self) { + pub const fn swap(a: &mut Self, b: &mut Self) { Self::conditional_swap(a, b, ConstChoice::TRUE) } /// Returns the truthy value if `self`!=0 or the falsy value otherwise. #[inline] - pub(crate) const fn is_nonzero(&self) -> ConstChoice { + pub const fn is_nonzero(&self) -> ConstChoice { let mut b = 0; let mut i = 0; while i < LIMBS { @@ -73,9 +73,14 @@ impl Uint { ConstChoice::from_word_lsb(self.limbs[0].0 & 1) } + /// Returns the truthy value if `self` is odd or the falsy value otherwise. + pub const fn is_odd_const(&self) -> ConstChoice { + self.is_odd() + } + /// Returns the truthy value if `self == rhs` or the falsy value otherwise. #[inline] - pub(crate) const fn eq(lhs: &Self, rhs: &Self) -> ConstChoice { + pub const fn eq(lhs: &Self, rhs: &Self) -> ConstChoice { let mut acc = 0; let mut i = 0; @@ -90,7 +95,7 @@ impl Uint { /// Returns the truthy value if `self < rhs` and the falsy value otherwise. #[inline] - pub(crate) const fn lt(lhs: &Self, rhs: &Self) -> ConstChoice { + pub const fn lt(lhs: &Self, rhs: &Self) -> ConstChoice { // We could use the same approach as in Limb::ct_lt(), // but since we have to use Uint::wrapping_sub(), which calls `borrowing_sub()`, // there are no savings compared to just calling `borrowing_sub()` directly. @@ -100,13 +105,13 @@ impl Uint { /// Returns the truthy value if `self <= rhs` and the falsy value otherwise. #[inline] - pub(crate) const fn lte(lhs: &Self, rhs: &Self) -> ConstChoice { + pub const fn lte(lhs: &Self, rhs: &Self) -> ConstChoice { Self::gt(lhs, rhs).not() } /// Returns the truthy value if `self > rhs` and the falsy value otherwise. #[inline] - pub(crate) const fn gt(lhs: &Self, rhs: &Self) -> ConstChoice { + pub const fn gt(lhs: &Self, rhs: &Self) -> ConstChoice { let (_res, borrow) = rhs.borrowing_sub(lhs, Limb::ZERO); ConstChoice::from_word_mask(borrow.0) } @@ -117,7 +122,7 @@ impl Uint { /// 0 is Equal /// 1 is Greater #[inline] - pub(crate) const fn cmp(lhs: &Self, rhs: &Self) -> i8 { + pub const fn cmp(lhs: &Self, rhs: &Self) -> i8 { let mut i = 0; let mut borrow = Limb::ZERO; let mut diff = Limb::ZERO; diff --git a/src/uint/div_limb.rs b/src/uint/div_limb.rs index e1402ada6..14f14b973 100644 --- a/src/uint/div_limb.rs +++ b/src/uint/div_limb.rs @@ -134,13 +134,7 @@ pub(crate) const fn div2by1(u1: Word, u0: Word, reciprocal: &Reciprocal) -> (Wor /// In place of `v1` takes its reciprocal, and assumes that `v` was already pre-shifted /// so that v1 has its most significant bit set (that is, the reciprocal's `shift` is 0). #[inline(always)] -pub(crate) const fn div3by2( - u2: Word, - u1: Word, - u0: Word, - v1_reciprocal: &Reciprocal, - v0: Word, -) -> Word { +pub const fn div3by2(u2: Word, u1: Word, u0: Word, v1_reciprocal: &Reciprocal, v0: Word) -> Word { debug_assert!(v1_reciprocal.shift == 0); debug_assert!(u2 <= v1_reciprocal.divisor_normalized); diff --git a/src/uint/shl.rs b/src/uint/shl.rs index 8a65d63bf..a371720b3 100644 --- a/src/uint/shl.rs +++ b/src/uint/shl.rs @@ -203,7 +203,7 @@ impl Uint { /// Computes `self << 1` in constant-time, returning [`ConstChoice::TRUE`] /// if the most significant bit was set, and [`ConstChoice::FALSE`] otherwise. #[inline(always)] - pub(crate) const fn overflowing_shl1(&self) -> (Self, Limb) { + pub const fn overflowing_shl1(&self) -> (Self, Limb) { self.carrying_shl1(Limb::ZERO) } diff --git a/src/uint/shr.rs b/src/uint/shr.rs index f39e4d570..347b067f4 100644 --- a/src/uint/shr.rs +++ b/src/uint/shr.rs @@ -177,7 +177,7 @@ impl Uint { } /// Computes `self >> 1` in constant-time. - pub(crate) const fn shr1(&self) -> Self { + pub const fn shr1(&self) -> Self { self.shr1_with_carry().0 }