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