diff --git a/src/boxed/uint.rs b/src/boxed/uint.rs index bec672d3d..7d5c94377 100644 --- a/src/boxed/uint.rs +++ b/src/boxed/uint.rs @@ -7,6 +7,7 @@ mod cmp; pub(crate) mod encoding; mod mul; mod sub; +mod sub_mod; use crate::{Limb, Uint, Word, Zero, U128, U64}; use alloc::{boxed::Box, vec, vec::Vec}; diff --git a/src/boxed/uint/add_mod.rs b/src/boxed/uint/add_mod.rs index b5dd15d79..4a76a9631 100644 --- a/src/boxed/uint/add_mod.rs +++ b/src/boxed/uint/add_mod.rs @@ -6,7 +6,7 @@ impl BoxedUint { /// Computes `self + rhs mod p`. /// /// Assumes `self + rhs` as unbounded integer is `< 2p`. - pub fn add_mod(&self, rhs: &BoxedUint, p: &BoxedUint) -> BoxedUint { + pub fn add_mod(&self, rhs: &Self, p: &Self) -> Self { debug_assert_eq!(self.nlimbs(), p.nlimbs()); debug_assert_eq!(rhs.nlimbs(), p.nlimbs()); debug_assert!(self < p); @@ -21,7 +21,7 @@ impl BoxedUint { // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the // modulus. - let mask = BoxedUint::from_words(vec![borrow.0; p.nlimbs()]); + let mask = Self::from_words(vec![borrow.0; p.nlimbs()]); w.wrapping_add(&p.bitand(&mask)) } diff --git a/src/boxed/uint/sub_mod.rs b/src/boxed/uint/sub_mod.rs new file mode 100644 index 000000000..cf2ce3c16 --- /dev/null +++ b/src/boxed/uint/sub_mod.rs @@ -0,0 +1,65 @@ +//! [`BoxedUint`] modular subtraction operations. + +use crate::{BoxedUint, Limb, SubMod}; + +impl BoxedUint { + /// Computes `self - rhs mod p`. + /// + /// Assumes `self - rhs` as unbounded signed integer is in `[-p, p)`. + pub fn sub_mod(&self, rhs: &Self, p: &Self) -> Self { + debug_assert_eq!(self.nlimbs(), p.nlimbs()); + debug_assert_eq!(rhs.nlimbs(), p.nlimbs()); + debug_assert!(self < p); + debug_assert!(rhs < p); + + let (out, borrow) = self.sbb(rhs, Limb::ZERO); + + // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise + // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. + let mask = Self::from_words(vec![borrow.0; p.nlimbs()]); + + out.wrapping_add(&p.bitand(&mask)) + } +} + +impl SubMod for BoxedUint { + type Output = Self; + + fn sub_mod(&self, rhs: &Self, p: &Self) -> Self { + self.sub_mod(rhs, p) + } +} + +#[cfg(test)] +mod tests { + use super::BoxedUint; + use hex_literal::hex; + + #[test] + fn sub_mod_nist_p256() { + let a = BoxedUint::from_be_slice( + &hex!("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"), + 256, + ) + .unwrap(); + let b = BoxedUint::from_be_slice( + &hex!("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"), + 256, + ) + .unwrap(); + let n = BoxedUint::from_be_slice( + &hex!("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"), + 256, + ) + .unwrap(); + + let actual = a.sub_mod(&b, &n); + let expected = BoxedUint::from_be_slice( + &hex!("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"), + 256, + ) + .unwrap(); + + assert_eq!(expected, actual); + } +} diff --git a/src/uint/add_mod.rs b/src/uint/add_mod.rs index 7674bd6b2..413ae95b4 100644 --- a/src/uint/add_mod.rs +++ b/src/uint/add_mod.rs @@ -1,4 +1,4 @@ -//! [`Uint`] addition modulus operations. +//! [`Uint`] modular addition operations. use crate::{AddMod, Limb, Uint}; @@ -6,7 +6,7 @@ impl Uint { /// Computes `self + rhs mod p`. /// /// Assumes `self + rhs` as unbounded integer is `< 2p`. - pub const fn add_mod(&self, rhs: &Uint, p: &Uint) -> Uint { + pub const fn add_mod(&self, rhs: &Self, p: &Self) -> Self { let (w, carry) = self.adc(rhs, Limb::ZERO); // Attempt to subtract the modulus, to ensure the result is in the field. @@ -16,7 +16,7 @@ impl Uint { // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the // modulus. - let mask = Uint::from_words([borrow.0; LIMBS]); + let mask = Self::from_words([borrow.0; LIMBS]); w.wrapping_add(&p.bitand(&mask)) } @@ -33,7 +33,7 @@ impl Uint { // for the overflow. Otherwise, we need to subtract `c` again, which // in that case cannot underflow. let l = carry.0.wrapping_sub(1) & c.0; - out.wrapping_sub(&Uint::from_word(l)) + out.wrapping_sub(&Self::from_word(l)) } } diff --git a/src/uint/sub_mod.rs b/src/uint/sub_mod.rs index 936c6d7a0..317dc2f0c 100644 --- a/src/uint/sub_mod.rs +++ b/src/uint/sub_mod.rs @@ -1,4 +1,4 @@ -//! [`Uint`] subtraction modulus operations. +//! [`Uint`] modular subtraction operations. use crate::{Limb, SubMod, Uint}; @@ -6,12 +6,12 @@ impl Uint { /// Computes `self - rhs mod p`. /// /// Assumes `self - rhs` as unbounded signed integer is in `[-p, p)`. - pub const fn sub_mod(&self, rhs: &Uint, p: &Uint) -> Uint { + pub const fn sub_mod(&self, rhs: &Self, p: &Self) -> Self { let (out, borrow) = self.sbb(rhs, Limb::ZERO); // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. - let mask = Uint::from_words([borrow.0; LIMBS]); + let mask = Self::from_words([borrow.0; LIMBS]); out.wrapping_add(&p.bitand(&mask)) } @@ -29,7 +29,7 @@ impl Uint { // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. - let mask = Uint::from_words([borrow; LIMBS]); + let mask = Self::from_words([borrow; LIMBS]); out.wrapping_add(&p.bitand(&mask)) } @@ -45,7 +45,7 @@ impl Uint { // the underflow. This cannot underflow due to the assumption // `self - rhs >= -p`. let l = borrow.0 & c.0; - out.wrapping_sub(&Uint::from_word(l)) + out.wrapping_sub(&Self::from_word(l)) } } @@ -61,9 +61,25 @@ impl SubMod for Uint { #[cfg(all(test, feature = "rand"))] mod tests { - use crate::{Limb, NonZero, Random, RandomMod, Uint}; + use crate::{Limb, NonZero, Random, RandomMod, Uint, U256}; use rand_core::SeedableRng; + #[test] + fn sub_mod_nist_p256() { + let a = + U256::from_be_hex("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"); + let b = + U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); + let n = + U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); + + let actual = a.sub_mod(&b, &n); + let expected = + U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); + + assert_eq!(expected, actual); + } + macro_rules! test_sub_mod { ($size:expr, $test_name:ident) => { #[test]