Skip to content
Merged
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
97 changes: 83 additions & 14 deletions src/ct_choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,63 +15,132 @@ impl CtChoice {
/// The truthy value.
pub const TRUE: Self = Self(Word::MAX);

#[inline]
pub(crate) const fn as_u32_mask(&self) -> u32 {
#[allow(trivial_numeric_casts)]
(self.0.wrapping_neg() as u32).wrapping_neg()
}

/// Returns the truthy value if `value == Word::MAX`, and the falsy value if `value == 0`.
/// Panics for other values.
pub(crate) const fn from_mask(value: Word) -> Self {
#[inline]
pub(crate) const fn from_word_mask(value: Word) -> Self {
debug_assert!(value == Self::FALSE.0 || value == Self::TRUE.0);
Self(value)
}

/// Returns the truthy value if `value == 1`, and the falsy value if `value == 0`.
/// Panics for other values.
pub(crate) const fn from_lsb(value: Word) -> Self {
#[inline]
pub(crate) const fn from_word_lsb(value: Word) -> Self {
debug_assert!(value == 0 || value == 1);
Self(value.wrapping_neg())
}

#[inline]
pub(crate) const fn from_u32_lsb(value: u32) -> Self {
debug_assert!(value == 0 || value == 1);
#[allow(trivial_numeric_casts)]
Self((value as Word).wrapping_neg())
}

/// Returns the truthy value if `value != 0`, and the falsy value otherwise.
#[inline]
pub(crate) const fn from_u32_nonzero(value: u32) -> Self {
Self::from_u32_lsb((value | value.wrapping_neg()) >> (u32::BITS - 1))
}

/// Returns the truthy value if `value != 0`, and the falsy value otherwise.
pub(crate) const fn from_usize_being_nonzero(value: usize) -> Self {
const HI_BIT: u32 = usize::BITS - 1;
Self::from_lsb(((value | value.wrapping_neg()) >> HI_BIT) as Word)
#[inline]
pub(crate) const fn from_word_nonzero(value: Word) -> Self {
Self::from_word_lsb((value | value.wrapping_neg()) >> (Word::BITS - 1))
}

/// Returns the truthy value if `x == y`, and the falsy value otherwise.
#[inline]
pub(crate) const fn from_u32_eq(x: u32, y: u32) -> Self {
Self::from_u32_nonzero(x ^ y).not()
}

/// Returns the truthy value if `x == y`, and the falsy value otherwise.
pub(crate) const fn from_usize_equality(x: usize, y: usize) -> Self {
Self::from_usize_being_nonzero(x.wrapping_sub(y)).not()
#[inline]
pub(crate) const fn from_word_eq(x: Word, y: Word) -> Self {
Self::from_word_nonzero(x ^ y).not()
}

/// Returns the truthy value if `x < y`, and the falsy value otherwise.
#[inline]
pub(crate) const fn from_word_lt(x: Word, y: Word) -> Self {
let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (Word::BITS - 1);
Self::from_word_lsb(bit)
}

/// Returns the truthy value if `x < y`, and the falsy value otherwise.
pub(crate) const fn from_usize_lt(x: usize, y: usize) -> Self {
let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (usize::BITS - 1);
Self::from_lsb(bit as Word)
#[inline]
pub(crate) const fn from_u32_lt(x: u32, y: u32) -> Self {
let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (u32::BITS - 1);
Self::from_u32_lsb(bit)
}

/// Returns the truthy value if `x <= y` and the falsy value otherwise.
#[inline]
pub(crate) const fn from_word_le(x: Word, y: Word) -> Self {
let bit = (((!x) | y) & ((x ^ y) | !(y.wrapping_sub(x)))) >> (Word::BITS - 1);
Self::from_word_lsb(bit)
}

/// 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 {
let bit = (((!x) | y) & ((x ^ y) | !(y.wrapping_sub(x)))) >> (u32::BITS - 1);
Self::from_u32_lsb(bit)
}

#[inline]
pub(crate) const fn not(&self) -> Self {
Self(!self.0)
}

#[inline]
pub(crate) const fn or(&self, other: Self) -> Self {
Self(self.0 | other.0)
}

#[inline]
pub(crate) const fn and(&self, other: Self) -> Self {
Self(self.0 & other.0)
}

/// Return `b` if `self` is truthy, otherwise return `a`.
pub(crate) const fn select(&self, a: Word, b: Word) -> Word {
#[inline]
pub(crate) const fn select_word(&self, a: Word, b: Word) -> Word {
a ^ (self.0 & (a ^ b))
}

/// Return `b` if `self` is truthy, otherwise return `a`.
#[inline]
pub(crate) const fn select_u32(&self, a: u32, b: u32) -> u32 {
a ^ (self.as_u32_mask() & (a ^ b))
}

/// Return `x` if `self` is truthy, otherwise return 0.
pub(crate) const fn if_true(&self, x: Word) -> Word {
#[inline]
pub(crate) const fn if_true_word(&self, x: Word) -> Word {
x & self.0
}

/// Return `x` if `self` is truthy, otherwise return 0.
#[inline]
pub(crate) const fn if_true_u32(&self, x: u32) -> u32 {
x & self.as_u32_mask()
}

#[inline]
pub(crate) const fn is_true_vartime(&self) -> bool {
self.0 == CtChoice::TRUE.0
}

#[inline]
pub(crate) const fn to_u8(self) -> u8 {
(self.0 as u8) & 1
}
Expand All @@ -98,7 +167,7 @@ mod tests {
fn select() {
let a: Word = 1;
let b: Word = 2;
assert_eq!(CtChoice::TRUE.select(a, b), b);
assert_eq!(CtChoice::FALSE.select(a, b), a);
assert_eq!(CtChoice::TRUE.select_word(a, b), b);
assert_eq!(CtChoice::FALSE.select_word(a, b), a);
}
}
8 changes: 4 additions & 4 deletions src/limb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub type Word = u64;
pub type WideWord = u128;

/// Highest bit in a [`Limb`].
pub(crate) const HI_BIT: usize = Limb::BITS - 1;
pub(crate) const HI_BIT: u32 = Limb::BITS - 1;

/// Big integers are represented as an array of smaller CPU word-size integers
/// called "limbs".
Expand All @@ -78,7 +78,7 @@ impl Limb {

/// Size of the inner integer in bits.
#[cfg(target_pointer_width = "32")]
pub const BITS: usize = 32;
pub const BITS: u32 = 32;
/// Size of the inner integer in bytes.
#[cfg(target_pointer_width = "32")]
pub const BYTES: usize = 4;
Expand All @@ -87,14 +87,14 @@ impl Limb {

/// Size of the inner integer in bits.
#[cfg(target_pointer_width = "64")]
pub const BITS: usize = 64;
pub const BITS: u32 = 64;
/// Size of the inner integer in bytes.
#[cfg(target_pointer_width = "64")]
pub const BYTES: usize = 8;
}

impl Bounded for Limb {
const BITS: usize = Self::BITS;
const BITS: u32 = Self::BITS;
const BYTES: usize = Self::BYTES;
}

Expand Down
16 changes: 8 additions & 8 deletions src/limb/bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ use super::Limb;

impl Limb {
/// Calculate the number of bits needed to represent this number.
pub const fn bits(self) -> usize {
Limb::BITS - (self.0.leading_zeros() as usize)
pub const fn bits(self) -> u32 {
Limb::BITS - self.0.leading_zeros()
}

/// Calculate the number of leading zeros in the binary representation of this number.
pub const fn leading_zeros(self) -> usize {
self.0.leading_zeros() as usize
pub const fn leading_zeros(self) -> u32 {
self.0.leading_zeros()
}

/// Calculate the number of trailing zeros in the binary representation of this number.
pub const fn trailing_zeros(self) -> usize {
self.0.trailing_zeros() as usize
pub const fn trailing_zeros(self) -> u32 {
self.0.trailing_zeros()
}

/// Calculate the number of trailing ones the binary representation of this number.
pub const fn trailing_ones(self) -> usize {
self.0.trailing_ones() as usize
pub const fn trailing_ones(self) -> u32 {
self.0.trailing_ones()
}
}
34 changes: 2 additions & 32 deletions src/limb/cmp.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Limb comparisons

use super::HI_BIT;
use crate::{CtChoice, Limb};
use core::cmp::Ordering;
use subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess};
Expand Down Expand Up @@ -28,42 +27,13 @@ impl Limb {
/// Return `b` if `c` is truthy, otherwise return `a`.
#[inline]
pub(crate) const fn ct_select(a: Self, b: Self, c: CtChoice) -> Self {
Self(c.select(a.0, b.0))
Self(c.select_word(a.0, b.0))
}

/// Returns the truthy value if `self != 0` and the falsy value otherwise.
#[inline]
pub(crate) const fn ct_is_nonzero(&self) -> CtChoice {
let inner = self.0;
CtChoice::from_lsb((inner | inner.wrapping_neg()) >> HI_BIT)
}

/// Returns the truthy value if `lhs == rhs` and the falsy value otherwise.
#[inline]
pub(crate) const fn ct_eq(lhs: Self, rhs: Self) -> CtChoice {
let x = lhs.0;
let y = rhs.0;

// x ^ y == 0 if and only if x == y
Self(x ^ y).ct_is_nonzero().not()
}

/// Returns the truthy value if `lhs < rhs` and the falsy value otherwise.
#[inline]
pub(crate) const fn ct_lt(lhs: Self, rhs: Self) -> CtChoice {
let x = lhs.0;
let y = rhs.0;
let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (Limb::BITS - 1);
CtChoice::from_lsb(bit)
}

/// Returns the truthy value if `lhs <= rhs` and the falsy value otherwise.
#[inline]
pub(crate) const fn ct_le(lhs: Self, rhs: Self) -> CtChoice {
let x = lhs.0;
let y = rhs.0;
let bit = (((!x) | y) & ((x ^ y) | !(y.wrapping_sub(x)))) >> (Limb::BITS - 1);
CtChoice::from_lsb(bit)
CtChoice::from_word_nonzero(self.0)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/limb/rand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ impl RandomMod for Limb {
fn random_mod(rng: &mut impl CryptoRngCore, modulus: &NonZero<Self>) -> Self {
let mut bytes = <Self as Encoding>::Repr::default();

let n_bits = modulus.bits();
let n_bits = modulus.bits() as usize;
let n_bytes = (n_bits + 7) / 8;
let mask = 0xff >> (8 * n_bytes - n_bits);
let mask = 0xffu8 >> (8 * n_bytes - n_bits);

loop {
rng.fill_bytes(&mut bytes[..n_bytes]);
Expand Down
38 changes: 11 additions & 27 deletions src/limb/shl.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,30 @@
//! Limb left bitshift

use crate::{Limb, Word};
use crate::Limb;
use core::ops::{Shl, ShlAssign};

impl Limb {
/// Computes `self << rhs`.
/// Panics if `rhs` overflows `Limb::BITS`.
/// Computes `self << shift`.
/// Panics if `shift` overflows `Limb::BITS`.
#[inline(always)]
pub const fn shl(self, rhs: Self) -> Self {
Limb(self.0 << rhs.0)
pub const fn shl(self, shift: u32) -> Self {
Limb(self.0 << shift)
}
}

impl Shl for Limb {
impl Shl<u32> for Limb {
type Output = Self;

#[inline(always)]
fn shl(self, rhs: Self) -> Self::Output {
self.shl(rhs)
fn shl(self, shift: u32) -> Self::Output {
self.shl(shift)
}
}

impl Shl<usize> for Limb {
type Output = Self;

#[inline(always)]
fn shl(self, rhs: usize) -> Self::Output {
self.shl(Limb(rhs as Word))
}
}

impl ShlAssign for Limb {
#[inline(always)]
fn shl_assign(&mut self, other: Self) {
*self = self.shl(other);
}
}

impl ShlAssign<usize> for Limb {
impl ShlAssign<u32> for Limb {
#[inline(always)]
fn shl_assign(&mut self, other: usize) {
*self = self.shl(Limb(other as Word));
fn shl_assign(&mut self, shift: u32) {
*self = self.shl(shift);
}
}

Expand Down
Loading