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
30 changes: 12 additions & 18 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,24 @@ pub trait Integer:
/// The value `1`.
fn one() -> Self;

/// Calculate the number of bits required to represent a given number.
fn bits(&self) -> usize;

/// Calculate the number of bits required to represent a given number in variable-time with
/// respect to `self`.
fn bits_vartime(&self) -> usize;

/// Precision of this integer in bits.
fn bits_precision(&self) -> usize;

/// Precision of this integer in bytes.
fn bytes_precision(&self) -> usize;

/// Calculate the number of leading zeros in the binary representation of this number.
fn leading_zeros(&self) -> usize {
self.bits_precision() - self.bits()
}

/// Number of limbs in this integer.
fn nlimbs(&self) -> usize;

Expand Down Expand Up @@ -94,24 +106,6 @@ pub trait FixedInteger: Bounded + ConditionallySelectable + Constants + Copy + I
const LIMBS: usize;
}

impl<T: FixedInteger> Integer for T {
fn one() -> Self {
T::ONE
}

fn bits_precision(&self) -> usize {
T::BITS
}

fn bytes_precision(&self) -> usize {
T::BYTES
}

fn nlimbs(&self) -> usize {
T::LIMBS
}
}

/// Zero values.
pub trait Zero: ConstantTimeEq + Sized {
/// The value `0`.
Expand Down
42 changes: 34 additions & 8 deletions src/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub(crate) mod boxed;
#[cfg(feature = "rand_core")]
mod rand;

use crate::{Bounded, Constants, Encoding, FixedInteger, Limb, Word, ZeroConstant};
use crate::{Bounded, Constants, Encoding, FixedInteger, Integer, Limb, Word, ZeroConstant};
use core::fmt;
use subtle::{Choice, ConditionallySelectable};

Expand Down Expand Up @@ -203,6 +203,16 @@ impl<const LIMBS: usize> ConditionallySelectable for Uint<LIMBS> {
}
}

impl<const LIMBS: usize> Bounded for Uint<LIMBS> {
const BITS: usize = Self::BITS;
const BYTES: usize = Self::BYTES;
}

impl<const LIMBS: usize> Constants for Uint<LIMBS> {
const ONE: Self = Self::ONE;
const MAX: Self = Self::MAX;
}

impl<const LIMBS: usize> Default for Uint<LIMBS> {
fn default() -> Self {
Self::ZERO
Expand All @@ -213,14 +223,30 @@ impl<const LIMBS: usize> FixedInteger for Uint<LIMBS> {
const LIMBS: usize = LIMBS;
}

impl<const LIMBS: usize> Bounded for Uint<LIMBS> {
const BITS: usize = Self::BITS;
const BYTES: usize = Self::BYTES;
}
impl<const LIMBS: usize> Integer for Uint<LIMBS> {
fn one() -> Self {
Self::ONE
}

impl<const LIMBS: usize> Constants for Uint<LIMBS> {
const ONE: Self = Self::ONE;
const MAX: Self = Self::MAX;
fn bits(&self) -> usize {
self.bits()
}

fn bits_vartime(&self) -> usize {
self.bits_vartime()
}

fn bits_precision(&self) -> usize {
Self::BITS
}

fn bytes_precision(&self) -> usize {
Self::BYTES
}

fn nlimbs(&self) -> usize {
Self::LIMBS
}
}

impl<const LIMBS: usize> ZeroConstant for Uint<LIMBS> {
Expand Down
62 changes: 32 additions & 30 deletions src/uint/bits.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
use crate::{CtChoice, Limb, Uint, Word};

impl<const LIMBS: usize> Uint<LIMBS> {
/// Get the value of the bit at position `index`, as a truthy or falsy `CtChoice`.
/// Returns the falsy value for indices out of range.
pub const fn bit(&self, index: usize) -> CtChoice {
let limb_num = index / Limb::BITS;
let index_in_limb = index % Limb::BITS;
let index_mask = 1 << index_in_limb;

let limbs = self.as_words();

let mut result: Word = 0;
let mut i = 0;
while i < LIMBS {
let bit = limbs[i] & index_mask;
let is_right_limb = CtChoice::from_usize_equality(i, limb_num);
result |= is_right_limb.if_true(bit);
i += 1;
}

CtChoice::from_lsb(result >> index_in_limb)
}

/// Returns `true` if the bit at position `index` is set, `false` otherwise.
///
/// # Remarks
Expand All @@ -15,6 +36,13 @@ impl<const LIMBS: usize> Uint<LIMBS> {
}

/// Calculate the number of bits needed to represent this number.
#[inline]
pub const fn bits(&self) -> usize {
Self::BITS - self.leading_zeros()
}

/// Calculate the number of bits needed to represent this number in variable-time with respect
/// to `self`.
pub const fn bits_vartime(&self) -> usize {
let mut i = LIMBS - 1;
while i > 0 && self.limbs[i].0 == 0 {
Expand Down Expand Up @@ -44,8 +72,8 @@ impl<const LIMBS: usize> Uint<LIMBS> {
count as usize
}

/// Calculate the number of leading zeros in the binary representation of this number,
/// variable time in `self`.
/// Calculate the number of leading zeros in the binary representation of this number in
/// variable-time with respect to `self`.
pub const fn leading_zeros_vartime(&self) -> usize {
let limbs = self.as_limbs();

Expand Down Expand Up @@ -83,8 +111,8 @@ impl<const LIMBS: usize> Uint<LIMBS> {
count as usize
}

/// Calculate the number of trailing zeros in the binary representation of this number,
/// variable time in `self`.
/// Calculate the number of trailing zeros in the binary representation of this number in
/// variable-time with respect to `self`.
pub const fn trailing_zeros_vartime(&self) -> usize {
let limbs = self.as_limbs();

Expand Down Expand Up @@ -142,32 +170,6 @@ impl<const LIMBS: usize> Uint<LIMBS> {
count
}

/// Calculate the number of bits needed to represent this number.
pub const fn bits(&self) -> usize {
Self::BITS - self.leading_zeros()
}

/// Get the value of the bit at position `index`, as a truthy or falsy `CtChoice`.
/// Returns the falsy value for indices out of range.
pub const fn bit(&self, index: usize) -> CtChoice {
let limb_num = index / Limb::BITS;
let index_in_limb = index % Limb::BITS;
let index_mask = 1 << index_in_limb;

let limbs = self.as_words();

let mut result: Word = 0;
let mut i = 0;
while i < LIMBS {
let bit = limbs[i] & index_mask;
let is_right_limb = CtChoice::from_usize_equality(i, limb_num);
result |= is_right_limb.if_true(bit);
i += 1;
}

CtChoice::from_lsb(result >> index_in_limb)
}

/// Sets the bit at `index` to 0 or 1 depending on the value of `bit_value`.
pub(crate) const fn set_bit(self, index: usize, bit_value: CtChoice) -> Self {
let mut result = self;
Expand Down
8 changes: 8 additions & 0 deletions src/uint/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,14 @@ impl Integer for BoxedUint {
Self::one()
}

fn bits(&self) -> usize {
self.bits()
}

fn bits_vartime(&self) -> usize {
self.bits_vartime()
}

fn bits_precision(&self) -> usize {
self.bits_precision()
}
Expand Down
12 changes: 12 additions & 0 deletions src/uint/boxed/bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ impl BoxedUint {
Limb::BITS * (n as usize) - (leading_zeros as usize)
}

/// Calculate the number of bits needed to represent this number in variable-time with respect
/// to `self`.
pub fn bits_vartime(&self) -> usize {
let mut i = self.nlimbs() - 1;
while i > 0 && self.limbs[i].0 == 0 {
i -= 1;
}

let limb = self.limbs[i];
Limb::BITS * (i + 1) - limb.leading_zeros()
}

/// Get the precision of this [`BoxedUint`] in bits.
pub fn bits_precision(&self) -> usize {
self.limbs.len() * Limb::BITS
Expand Down
7 changes: 7 additions & 0 deletions tests/boxed_uint_proptests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ proptest! {
prop_assert_eq!(&a, &to_uint(to_biguint(&a)));
}

#[test]
fn bits(a in uint()) {
let expected = to_biguint(&a).bits();
assert_eq!(expected, a.bits());
assert_eq!(expected, a.bits_vartime());
}

#[test]
fn checked_add(a in uint(), b in uint()) {
let a_bi = to_biguint(&a);
Expand Down
7 changes: 7 additions & 0 deletions tests/uint_proptests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ proptest! {
assert_eq!(a, to_uint(to_biguint(&a)));
}

#[test]
fn bits(a in uint()) {
let expected = to_biguint(&a).bits();
assert_eq!(expected, a.bits());
assert_eq!(expected, a.bits_vartime());
}

#[test]
fn shl_vartime(a in uint(), shift in any::<u8>()) {
let a_bi = to_biguint(&a);
Expand Down