Skip to content

Commit

Permalink
Reverse ordering of UInt::mul_wide return tuple (#34)
Browse files Browse the repository at this point in the history
Fixes the inconsistency between `UInt::mul_wide` and `Limb::mul_wide` by
reversing the order of the `UInt` version so it returns `(lo, hi)`.

This follows the "little endian" approach used in the rest of this
crate for consistency.

Closes #4
  • Loading branch information
tarcieri committed Nov 13, 2021
1 parent 8cb1077 commit 333ac76
Showing 1 changed file with 16 additions and 6 deletions.
22 changes: 16 additions & 6 deletions src/uint/mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ use subtle::CtOption;

impl<const LIMBS: usize> UInt<LIMBS> {
/// Compute "wide" multiplication, with a product twice the size of the input.
///
/// Returns a tuple containing the `(lo, hi)` components of the product.
///
/// # Ordering note
///
/// Releases of `crypto-bigint` prior to v0.3 used `(hi, lo)` ordering
/// instead. This has been changed for better consistency with the rest of
/// the APIs in this crate.
///
/// For more info see: <https://github.com/RustCrypto/crypto-bigint/issues/4>
// TODO(tarcieri): use `concat` (or similar) when const trait is stable
pub const fn mul_wide(&self, rhs: &Self) -> (Self, Self) {
let mut i = 0;
Expand Down Expand Up @@ -39,18 +49,18 @@ impl<const LIMBS: usize> UInt<LIMBS> {
i += 1;
}

(hi, lo)
(lo, hi)
}

/// Perform wrapping multiplication, discarding overflow.
pub const fn wrapping_mul(&self, rhs: &Self) -> Self {
self.mul_wide(rhs).1
self.mul_wide(rhs).0
}

/// Perform checked multiplication, returning a [`CtOption`] which `is_some`
/// only if the operation did not overflow.
pub fn checked_mul(&self, rhs: &Self) -> CtOption<Self> {
let (hi, lo) = self.mul_wide(rhs);
let (lo, hi) = self.mul_wide(rhs);
CtOption::new(lo, hi.is_zero())
}

Expand All @@ -59,7 +69,7 @@ impl<const LIMBS: usize> UInt<LIMBS> {
where
Self: Concat,
{
let (hi, lo) = self.mul_wide(self);
let (lo, hi) = self.mul_wide(self);
hi.concat(&lo)
}
}
Expand Down Expand Up @@ -118,7 +128,7 @@ mod tests {
assert_eq!(U64::ZERO.mul_wide(&U64::ZERO), (U64::ZERO, U64::ZERO));
assert_eq!(U64::ZERO.mul_wide(&U64::ONE), (U64::ZERO, U64::ZERO));
assert_eq!(U64::ONE.mul_wide(&U64::ZERO), (U64::ZERO, U64::ZERO));
assert_eq!(U64::ONE.mul_wide(&U64::ONE), (U64::ZERO, U64::ONE));
assert_eq!(U64::ONE.mul_wide(&U64::ONE), (U64::ONE, U64::ZERO));
}

// TODO(tarcieri): add proptests for multiplication
Expand All @@ -128,7 +138,7 @@ mod tests {

for &a_int in primes {
for &b_int in primes {
let (hi, lo) = U64::from_u32(a_int).mul_wide(&U64::from_u32(b_int));
let (lo, hi) = U64::from_u32(a_int).mul_wide(&U64::from_u32(b_int));
let expected = U64::from_u64(a_int as u64 * b_int as u64);
assert_eq!(lo, expected);
assert!(bool::from(hi.is_zero()));
Expand Down

0 comments on commit 333ac76

Please sign in to comment.