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
1 change: 1 addition & 0 deletions src/boxed/uint.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Heap-allocated big unsigned integers.

mod add;
mod add_mod;
mod bit_and;
mod cmp;
pub(crate) mod encoding;
Expand Down
72 changes: 72 additions & 0 deletions src/boxed/uint/add_mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//! [`BoxedUint`] modular addition operations.

use crate::{AddMod, BoxedUint, Limb};

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 {
debug_assert_eq!(self.nlimbs(), p.nlimbs());
debug_assert_eq!(rhs.nlimbs(), p.nlimbs());
debug_assert!(self < p);
debug_assert!(rhs < p);

let (w, carry) = self.adc(rhs, Limb::ZERO);

// Attempt to subtract the modulus, to ensure the result is in the field.
let (w, borrow) = w.sbb(p, Limb::ZERO);
let (_, borrow) = carry.sbb(Limb::ZERO, borrow);

// 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()]);

w.wrapping_add(&p.bitand(&mask))
}
}

impl AddMod for BoxedUint {
type Output = Self;

fn add_mod(&self, rhs: &Self, p: &Self) -> Self {
self.add_mod(rhs, p)
}
}

#[cfg(test)]
mod tests {
use super::BoxedUint;
use hex_literal::hex;

// TODO(tarcieri): proptests

#[test]
fn add_mod_nist_p256() {
let a = BoxedUint::from_be_slice(
&hex!("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"),
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.add_mod(&b, &n);
let expected = BoxedUint::from_be_slice(
&hex!("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"),
256,
)
.unwrap();

assert_eq!(expected, actual);
}
}
2 changes: 0 additions & 2 deletions src/uint/add_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ mod tests {
use crate::{Limb, NonZero, Random, RandomMod, Uint, U256};
use rand_core::SeedableRng;

// TODO(tarcieri): additional tests + proptests

#[test]
fn add_mod_nist_p256() {
let a =
Expand Down