use super::BoxedMontyForm;
use crate::modular::lincomb::lincomb_boxed_monty_form;
impl BoxedMontyForm {
#[must_use]
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,
params.modulus(),
params.mod_neg_inv(),
params.mod_leading_zeros(),
),
params: products[0].0.params.clone(),
}
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "rand_core")]
#[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 = chacha20::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_vartime(&mut rng, modulus.as_nz_ref());
let b = BoxedUint::random_mod_vartime(&mut rng, modulus.as_nz_ref());
let c = BoxedUint::random_mod_vartime(&mut rng, modulus.as_nz_ref());
let d = BoxedUint::random_mod_vartime(&mut rng, modulus.as_nz_ref());
let e = BoxedUint::random_mod_vartime(&mut rng, modulus.as_nz_ref());
let f = BoxedUint::random_mod_vartime(&mut rng, modulus.as_nz_ref());
let std = a
.mul_mod(&b, modulus.as_nz_ref())
.add_mod(&c.mul_mod(&d, modulus.as_nz_ref()), modulus.as_nz_ref())
.add_mod(&e.mul_mod(&f, modulus.as_nz_ref()), modulus.as_nz_ref());
let lincomb = BoxedMontyForm::lincomb_vartime(&[
(
&BoxedMontyForm::new(a, ¶ms),
&BoxedMontyForm::new(b, ¶ms),
),
(
&BoxedMontyForm::new(c, ¶ms),
&BoxedMontyForm::new(d, ¶ms),
),
(
&BoxedMontyForm::new(e, ¶ms),
&BoxedMontyForm::new(f, ¶ms),
),
]);
assert_eq!(std, lincomb.retrieve(), "n={n}");
}
}
}