crypto_bigint/modular/boxed_monty_form/
lincomb.rs1use super::BoxedMontyForm;
4use crate::modular::lincomb::lincomb_boxed_monty_form;
5
6impl BoxedMontyForm {
7 pub fn lincomb_vartime(products: &[(&Self, &Self)]) -> Self {
15 assert!(!products.is_empty(), "empty products");
16 let params = &products[0].0.params;
17 Self {
18 montgomery_form: lincomb_boxed_monty_form(
19 products,
20 ¶ms.modulus,
21 params.mod_neg_inv,
22 params.mod_leading_zeros,
23 ),
24 params: products[0].0.params.clone(),
25 }
26 }
27}
28
29#[cfg(test)]
30mod tests {
31
32 #[cfg(feature = "rand")]
33 #[test]
34 fn lincomb_expected() {
35 use crate::modular::{BoxedMontyForm, BoxedMontyParams};
36 use crate::{BoxedUint, Odd, RandomMod};
37 use rand_core::SeedableRng;
38
39 const SIZE: u32 = 511;
40
41 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1);
42 for n in 0..100 {
43 let modulus = Odd::<BoxedUint>::random(&mut rng, SIZE);
44 let params = BoxedMontyParams::new(modulus.clone());
45 let a = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref());
46 let b = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref());
47 let c = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref());
48 let d = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref());
49 let e = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref());
50 let f = BoxedUint::random_mod(&mut rng, modulus.as_nz_ref());
51
52 let std = a
53 .mul_mod(&b, &modulus)
54 .add_mod(&c.mul_mod(&d, &modulus), &modulus)
55 .add_mod(&e.mul_mod(&f, &modulus), &modulus);
56
57 let lincomb = BoxedMontyForm::lincomb_vartime(&[
58 (
59 &BoxedMontyForm::new(a, params.clone()),
60 &BoxedMontyForm::new(b, params.clone()),
61 ),
62 (
63 &BoxedMontyForm::new(c, params.clone()),
64 &BoxedMontyForm::new(d, params.clone()),
65 ),
66 (
67 &BoxedMontyForm::new(e, params.clone()),
68 &BoxedMontyForm::new(f, params.clone()),
69 ),
70 ]);
71
72 assert_eq!(std, lincomb.retrieve(), "n={n}");
73 }
74 }
75}