arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/math/src/modulus/impl_u64/barrett.rs
math/src/modulus/impl_u64/barrett.rsRaw
 1use crate::modulus::barrett::{Barrett, BarrettPrecomp};
 2use crate::modulus::ReduceOnce;
 3use crate::modulus::{REDUCEMOD, NONE, ONCE, TWICE, FOURTIMES, BARRETT, BARRETTLAZY};
 4
 5use num_bigint::BigUint;
 6use num_traits::cast::ToPrimitive;
 7
 8impl BarrettPrecomp<u64>{
 9    
10    pub fn new(q: u64) -> BarrettPrecomp<u64> {
11        let big_r: BigUint = (BigUint::from(1 as usize)<<((u64::BITS<<1) as usize)) / BigUint::from(q);
12        let lo: u64 = (&big_r & BigUint::from(u64::MAX)).to_u64().unwrap();
13        let hi: u64 = (big_r >> u64::BITS).to_u64().unwrap();
14        let mut precomp: BarrettPrecomp<u64> = Self{q:q, two_q:q<<1, four_q:q<<2, lo:lo, hi:hi, one:Barrett(0,0)};
15        precomp.one = precomp.prepare(1);
16        precomp
17    }
18
19    #[inline(always)]
20    pub fn one(&self) -> Barrett<u64> {
21        self.one
22    }
23
24    /// Applies a modular reduction on x based on REDUCE:
25    /// - LAZY: no modular reduction.
26    /// - ONCE: subtracts q if x >= q.
27    /// - FULL: maps x to x mod q using Barrett reduction.
28    #[inline(always)]
29    pub fn reduce_assign<const REDUCE:REDUCEMOD>(&self, x: &mut u64){
30        match REDUCE {
31            NONE =>{},
32            ONCE =>{x.reduce_once_assign(self.q)},
33            TWICE=>{x.reduce_once_assign(self.two_q)},
34            FOURTIMES =>{x.reduce_once_assign(self.four_q)},
35            BARRETT =>{
36                let (_, mhi) = x.widening_mul(self.hi);
37                *x = *x - mhi.wrapping_mul(self.q);
38                x.reduce_once_assign(self.q);
39            },
40            BARRETTLAZY =>{
41                let (_, mhi) = x.widening_mul(self.hi);
42                *x = *x - mhi.wrapping_mul(self.q)
43            },
44            _ => unreachable!("invalid REDUCE argument")
45        }
46    }
47
48    #[inline(always)]
49    pub fn prepare(&self, v: u64) -> Barrett<u64> {
50        debug_assert!(v < self.q);
51        let quotient: u64 = (((v as u128) << 64) / self.q as u128) as _;
52        Barrett(v, quotient)
53    }
54
55    #[inline(always)]
56    pub fn mul_external<const REDUCE:REDUCEMOD>(&self, lhs: Barrett<u64>, rhs: u64) -> u64 {
57        let mut r: u64 = rhs;
58        self.mul_external_assign::<REDUCE>(lhs, &mut r);
59        r
60    }
61
62    #[inline(always)]
63    pub fn mul_external_assign<const REDUCE:REDUCEMOD>(&self, lhs: Barrett<u64>, rhs: &mut u64){
64        let t: u64 = ((*lhs.quotient() as u128 * *rhs as u128) >> 64) as _;
65        *rhs = (rhs.wrapping_mul(*lhs.value())).wrapping_sub(self.q.wrapping_mul(t));
66        self.reduce_assign::<REDUCE>(rhs);
67    }
68}