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
64 changes: 63 additions & 1 deletion src/boxed/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

mod add;
mod cmp;
mod mul;
mod sub;

use crate::{Limb, Word};
use crate::{Limb, Uint, Word, Zero, U128, U64};
use alloc::{boxed::Box, vec, vec::Vec};
use core::fmt;
use subtle::Choice;

#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
Expand Down Expand Up @@ -40,6 +42,13 @@ impl BoxedUint {
}
}

/// Is this [`BoxedUint`] equal to zero?
pub fn is_zero(&self) -> Choice {
self.limbs
.iter()
.fold(Choice::from(1), |acc, limb| acc & limb.is_zero())
}

/// Create a new [`BoxedUint`] with the given number of bits of precision.
///
/// Returns `None` if the number of bits is not a multiple of the
Expand Down Expand Up @@ -129,6 +138,11 @@ impl BoxedUint {
self.limbs
}

/// Get the number of limbs in this [`BoxedUint`].
pub fn nlimbs(&self) -> usize {
self.limbs.len()
}

/// Get the precision of this [`BoxedUint`] in bits.
pub fn bits(&self) -> usize {
self.limbs.len() * Limb::BITS
Expand Down Expand Up @@ -210,6 +224,54 @@ impl fmt::Display for BoxedUint {
}
}

impl From<u8> for BoxedUint {
fn from(n: u8) -> Self {
vec![Limb::from(n); 1].into()
}
}

impl From<u16> for BoxedUint {
fn from(n: u16) -> Self {
vec![Limb::from(n); 1].into()
}
}

impl From<u32> for BoxedUint {
fn from(n: u32) -> Self {
vec![Limb::from(n); 1].into()
}
}

impl From<u64> for BoxedUint {
fn from(n: u64) -> Self {
U64::from(n).into()
}
}

impl From<u128> for BoxedUint {
fn from(n: u128) -> Self {
U128::from(n).into()
}
}

impl From<Box<[Limb]>> for BoxedUint {
fn from(limbs: Box<[Limb]>) -> BoxedUint {
Self { limbs }
}
}

impl From<Vec<Limb>> for BoxedUint {
fn from(limbs: Vec<Limb>) -> BoxedUint {
limbs.into_boxed_slice().into()
}
}

impl<const LIMBS: usize> From<Uint<LIMBS>> for BoxedUint {
fn from(uint: Uint<LIMBS>) -> BoxedUint {
Vec::from(uint.to_limbs()).into()
}
}

impl fmt::LowerHex for BoxedUint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.limbs.is_empty() {
Expand Down
61 changes: 61 additions & 0 deletions src/boxed/uint/mul.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! [`BoxedUint`] multiplication operations.

use crate::{BoxedUint, Limb};

impl BoxedUint {
/// Multiply `self` by `rhs`.
pub fn mul(&self, rhs: &Self) -> Self {
let mut ret = Self {
limbs: vec![Limb::ZERO; self.nlimbs() + rhs.nlimbs()].into(),
};

// Schoolbook multiplication.
// TODO(tarcieri): use Karatsuba for better performance? Share impl with `Uint::mul`?
for i in 0..self.nlimbs() {
let mut carry = Limb::ZERO;

for j in 0..rhs.nlimbs() {
let k = i + j;
let (n, c) = ret.limbs[k].mac(self.limbs[i], rhs.limbs[j], carry);
ret.limbs[k] = n;
carry = c;
}

ret.limbs[i + rhs.nlimbs()] = carry;
}

ret
}
}

#[cfg(test)]
mod tests {
use crate::BoxedUint;

#[test]
fn mul_zero_and_one() {
assert!(bool::from(
BoxedUint::zero().mul(&BoxedUint::zero()).is_zero()
));
assert!(bool::from(
BoxedUint::zero().mul(&BoxedUint::one()).is_zero()
));
assert!(bool::from(
BoxedUint::one().mul(&BoxedUint::zero()).is_zero()
));
assert_eq!(BoxedUint::one().mul(&BoxedUint::one()), BoxedUint::one());
}

#[test]
fn mul_primes() {
let primes: &[u32] = &[3, 5, 17, 257, 65537];

for &a_int in primes {
for &b_int in primes {
let actual = BoxedUint::from(a_int).mul(&BoxedUint::from(b_int));
let expected = BoxedUint::from(a_int as u64 * b_int as u64);
assert_eq!(actual, expected);
}
}
}
}
2 changes: 1 addition & 1 deletion src/uint/mul.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! [`Uint`] addition operations.
//! [`Uint`] multiplication operations.

use crate::{Checked, CheckedMul, Concat, ConcatMixed, Limb, Uint, WideWord, Word, Wrapping, Zero};
use core::ops::{Mul, MulAssign};
Expand Down