Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 38 additions & 18 deletions src/const_choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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))
}

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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))
}

Expand All @@ -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))
}

Expand All @@ -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 {
Expand All @@ -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
}
}
Expand Down Expand Up @@ -303,20 +309,20 @@ pub struct ConstCtOption<T> {

impl<T> ConstCtOption<T> {
#[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,
}
}

#[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,
Expand All @@ -327,7 +333,7 @@ impl<T> ConstCtOption<T> {
///
/// **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
Expand Down Expand Up @@ -359,7 +365,7 @@ impl<T> ConstCtOption<T> {

/// 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
}
Expand Down Expand Up @@ -429,6 +435,20 @@ impl<const LIMBS: usize> ConstCtOption<(Uint<LIMBS>, Uint<LIMBS>)> {
}
}

impl<const LIMBS: usize> ConstCtOption<(Uint<LIMBS>, 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<LIMBS>, ConstChoice) {
assert!(self.is_some.is_true_vartime(), "{}", msg);
self.value
}
}

impl<const LIMBS: usize> ConstCtOption<NonZero<Uint<LIMBS>>> {
/// Returns the contained value, consuming the `self` value.
///
Expand Down
9 changes: 7 additions & 2 deletions src/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -151,11 +151,16 @@ impl<const LIMBS: usize> Int<LIMBS> {
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<Int<LIMBS>>`].
///
/// Returns some if the original value is odd, and false otherwise.
pub const fn to_odd(self) -> ConstCtOption<Odd<Self>> {
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.
Expand Down
14 changes: 7 additions & 7 deletions src/int/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,37 @@ use crate::{ConstChoice, Int, Uint};
impl<const LIMBS: usize> Int<LIMBS> {
/// 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)
}

Expand All @@ -51,7 +51,7 @@ impl<const LIMBS: usize> Int<LIMBS> {
/// 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)
}

Expand Down
12 changes: 10 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down
4 changes: 2 additions & 2 deletions src/limb/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}

Expand All @@ -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)
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,13 +190,13 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// 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)
}

Expand Down
23 changes: 14 additions & 9 deletions src/uint/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use super::Uint;
impl<const LIMBS: usize> Uint<LIMBS> {
/// 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;
Expand All @@ -27,7 +27,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// 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();
Expand All @@ -39,13 +39,13 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// 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 {
Expand Down Expand Up @@ -73,9 +73,14 @@ impl<const LIMBS: usize> Uint<LIMBS> {
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;

Expand All @@ -90,7 +95,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// 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.
Expand All @@ -100,13 +105,13 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// 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)
}
Expand All @@ -117,7 +122,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
/// 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;
Expand Down
Loading
Loading