-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add efficient linear combination for Montgomery forms (#666)
Signed-off-by: Andrew Whitehead <[email protected]>
- Loading branch information
1 parent
20059a7
commit 21cba95
Showing
13 changed files
with
456 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
//! Linear combinations of integers in Montgomery form with a modulus set at runtime. | ||
|
||
use super::BoxedMontyForm; | ||
use crate::modular::lincomb::lincomb_boxed_monty_form; | ||
|
||
impl BoxedMontyForm { | ||
/// Calculate the sum of products of pairs `(a, b)` in `products`. | ||
/// | ||
/// This method is variable time only with the value of the modulus. | ||
/// For a modulus with leading zeros, this method is more efficient than a naive sum of products. | ||
/// | ||
/// This method will panic if `products` is empty. All terms must be associated | ||
/// with equivalent `MontyParams`. | ||
pub fn lincomb_vartime(products: &[(&Self, &Self)]) -> Self { | ||
assert!(!products.is_empty(), "empty products"); | ||
let params = &products[0].0.params; | ||
Self { | ||
montgomery_form: lincomb_boxed_monty_form( | ||
products, | ||
¶ms.modulus, | ||
params.mod_neg_inv, | ||
params.mod_leading_zeros, | ||
), | ||
params: products[0].0.params.clone(), | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
|
||
#[cfg(feature = "rand")] | ||
#[test] | ||
fn lincomb_expected() { | ||
use crate::modular::{BoxedMontyForm, BoxedMontyParams}; | ||
use crate::{BoxedUint, Odd, RandomMod}; | ||
use rand_core::SeedableRng; | ||
|
||
const SIZE: u32 = 511; | ||
|
||
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); | ||
for n in 0..100 { | ||
let modulus = Odd::<BoxedUint>::random(&mut rng, SIZE); | ||
let params = BoxedMontyParams::new(modulus.clone()); | ||
let a = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); | ||
let b = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); | ||
let c = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); | ||
let d = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); | ||
let e = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); | ||
let f = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref()); | ||
|
||
let std = a | ||
.mul_mod(&b, &modulus) | ||
.add_mod(&c.mul_mod(&d, &modulus), &modulus) | ||
.add_mod(&e.mul_mod(&f, &modulus), &modulus); | ||
|
||
let lincomb = BoxedMontyForm::lincomb_vartime(&[ | ||
( | ||
&BoxedMontyForm::new(a, params.clone()), | ||
&BoxedMontyForm::new(b, params.clone()), | ||
), | ||
( | ||
&BoxedMontyForm::new(c, params.clone()), | ||
&BoxedMontyForm::new(d, params.clone()), | ||
), | ||
( | ||
&BoxedMontyForm::new(e, params.clone()), | ||
&BoxedMontyForm::new(f, params.clone()), | ||
), | ||
]); | ||
|
||
assert_eq!(std, lincomb.retrieve(), "n={n}"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
//! Linear combinations of integers n Montgomery form with a constant modulus. | ||
|
||
use core::marker::PhantomData; | ||
|
||
use super::{ConstMontyForm, ConstMontyParams}; | ||
use crate::modular::lincomb::lincomb_const_monty_form; | ||
|
||
impl<MOD: ConstMontyParams<LIMBS>, const LIMBS: usize> ConstMontyForm<MOD, LIMBS> { | ||
/// Calculate the sum of products of pairs `(a, b)` in `products`. | ||
/// | ||
/// This method is variable time only with the value of the modulus. | ||
/// For a modulus with leading zeros, this method is more efficient than a naive sum of products. | ||
pub const fn lincomb_vartime(products: &[(Self, Self)]) -> Self { | ||
Self { | ||
montgomery_form: lincomb_const_monty_form(products, &MOD::MODULUS, MOD::MOD_NEG_INV), | ||
phantom: PhantomData, | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
|
||
#[cfg(feature = "rand")] | ||
#[test] | ||
fn lincomb_expected() { | ||
use super::{ConstMontyForm, ConstMontyParams}; | ||
use crate::{impl_modulus, RandomMod, U256}; | ||
use rand_core::SeedableRng; | ||
impl_modulus!( | ||
P, | ||
U256, | ||
"7fffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" | ||
); | ||
let modulus = P::MODULUS.as_nz_ref(); | ||
|
||
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); | ||
for n in 0..1000 { | ||
let a = U256::random_mod(&mut rng, modulus); | ||
let b = U256::random_mod(&mut rng, modulus); | ||
let c = U256::random_mod(&mut rng, modulus); | ||
let d = U256::random_mod(&mut rng, modulus); | ||
let e = U256::random_mod(&mut rng, modulus); | ||
let f = U256::random_mod(&mut rng, modulus); | ||
|
||
assert_eq!( | ||
a.mul_mod(&b, modulus) | ||
.add_mod(&c.mul_mod(&d, modulus), modulus) | ||
.add_mod(&e.mul_mod(&f, modulus), modulus), | ||
ConstMontyForm::<P, { P::LIMBS }>::lincomb_vartime(&[ | ||
(ConstMontyForm::new(&a), ConstMontyForm::new(&b)), | ||
(ConstMontyForm::new(&c), ConstMontyForm::new(&d)), | ||
(ConstMontyForm::new(&e), ConstMontyForm::new(&f)), | ||
]) | ||
.retrieve(), | ||
"n={n}" | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.