crypto_bigint/modular/monty_form/
lincomb.rs1use super::MontyForm;
4use crate::modular::lincomb::lincomb_monty_form;
5
6impl<const LIMBS: usize> MontyForm<LIMBS> {
7 pub const 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_monty_form(
19 products,
20 ¶ms.modulus,
21 params.mod_neg_inv,
22 params.mod_leading_zeros,
23 ),
24 params: products[0].0.params,
25 }
26 }
27}
28
29#[cfg(test)]
30mod tests {
31 #[cfg(feature = "rand")]
32 #[test]
33 fn lincomb_expected() {
34 use crate::U256;
35 use crate::{
36 modular::{MontyForm, MontyParams},
37 Odd, Random, RandomMod,
38 };
39 use rand_core::SeedableRng;
40
41 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1);
42 for n in 0..1500 {
43 let modulus = Odd::<U256>::random(&mut rng);
44 let params = MontyParams::new_vartime(modulus);
45 let m = modulus.as_nz_ref();
46 let a = U256::random_mod(&mut rng, m);
47 let b = U256::random_mod(&mut rng, m);
48 let c = U256::random_mod(&mut rng, m);
49 let d = U256::random_mod(&mut rng, m);
50
51 assert_eq!(
52 a.mul_mod(&b, m).add_mod(&c.mul_mod(&d, m), m),
53 MontyForm::lincomb_vartime(&[
54 (&MontyForm::new(&a, params), &MontyForm::new(&b, params)),
55 (&MontyForm::new(&c, params), &MontyForm::new(&d, params)),
56 ])
57 .retrieve(),
58 "n={n}, a={a}, b={b}, c={c}, d={d}"
59 )
60 }
61 }
62}