use crate::modulus::barrett::{Barrett, BarrettPrecomp}; use crate::modulus::ReduceOnce; use crate::modulus::{BARRETT, BARRETTLAZY, FOURTIMES, NONE, ONCE, REDUCEMOD, TWICE}; 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 } #[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 reduce(&self, x: &u64) -> u64 { let mut r = *x; self.reduce_assign::(&mut r); r } #[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); } }