use crate::modulus::barrett::{Barrett, BarrettPrecomp}; use crate::modulus::ReduceOnce; use crate::modulus::{REDUCEMOD, NONE, ONCE, TWICE, FOURTIMES, BARRETT, BARRETTLAZY}; use num_bigint::BigUint; use num_traits::cast::ToPrimitive; impl BarrettPrecomp{ pub fn new(q: u64) -> BarrettPrecomp { let big_r: BigUint = (BigUint::from(1 as usize)<<((u64::BITS<<1) as usize)) / BigUint::from(q); let lo: u64 = (&big_r & BigUint::from(u64::MAX)).to_u64().unwrap(); let hi: u64 = (big_r >> u64::BITS).to_u64().unwrap(); let mut precomp: BarrettPrecomp = Self{q:q, two_q:q<<1, four_q:q<<2, lo:lo, hi:hi, one:Barrett(0,0)}; precomp.one = precomp.prepare(1); precomp } #[inline(always)] pub fn one(&self) -> Barrett { self.one } /// Applies a modular reduction on x based on REDUCE: /// - LAZY: no modular reduction. /// - ONCE: subtracts q if x >= q. /// - FULL: maps x to x mod q using Barrett reduction. #[inline(always)] pub fn reduce_assign(&self, x: &mut u64){ match REDUCE { NONE =>{}, ONCE =>{x.reduce_once_assign(self.q)}, TWICE=>{x.reduce_once_assign(self.two_q)}, FOURTIMES =>{x.reduce_once_assign(self.four_q)}, BARRETT =>{ let (_, mhi) = x.widening_mul(self.hi); *x = *x - mhi.wrapping_mul(self.q); x.reduce_once_assign(self.q); }, BARRETTLAZY =>{ let (_, mhi) = x.widening_mul(self.hi); *x = *x - mhi.wrapping_mul(self.q) }, _ => unreachable!("invalid REDUCE argument") } } #[inline(always)] pub fn prepare(&self, v: u64) -> Barrett { debug_assert!(v < self.q); let quotient: u64 = (((v as u128) << 64) / self.q as u128) as _; Barrett(v, quotient) } #[inline(always)] pub fn mul_external(&self, lhs: Barrett, rhs: u64) -> u64 { let mut r: u64 = rhs; self.mul_external_assign::(lhs, &mut r); r } #[inline(always)] pub fn mul_external_assign(&self, lhs: Barrett, rhs: &mut u64){ let t: u64 = ((*lhs.quotient() as u128 * *rhs as u128) >> 64) as _; *rhs = (rhs.wrapping_mul(*lhs.value())).wrapping_sub(self.q.wrapping_mul(t)); self.reduce_assign::(rhs); } }