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> {
#[must_use]
pub const fn lincomb(products: &[(Self, Self)]) -> Self {
Self {
montgomery_form: lincomb_const_monty_form(
products,
&MOD::PARAMS.modulus,
MOD::PARAMS.mod_neg_inv(),
),
phantom: PhantomData,
}
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "rand_core")]
#[test]
fn lincomb_expected() {
use super::{ConstMontyForm, ConstMontyParams};
use crate::{RandomMod, U256, const_monty_params};
use rand_core::SeedableRng;
const_monty_params!(
P,
U256,
"7fffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"
);
let modulus = P::PARAMS.modulus.as_nz_ref();
let mut rng = chacha20::ChaCha8Rng::seed_from_u64(1);
for n in 0..1000 {
let a = U256::random_mod_vartime(&mut rng, modulus);
let b = U256::random_mod_vartime(&mut rng, modulus);
let c = U256::random_mod_vartime(&mut rng, modulus);
let d = U256::random_mod_vartime(&mut rng, modulus);
let e = U256::random_mod_vartime(&mut rng, modulus);
let f = U256::random_mod_vartime(&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(&[
(ConstMontyForm::new(&a), ConstMontyForm::new(&b)),
(ConstMontyForm::new(&c), ConstMontyForm::new(&d)),
(ConstMontyForm::new(&e), ConstMontyForm::new(&f)),
])
.retrieve(),
"n={n}"
);
}
}
}