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::{BARRETT, BARRETTLAZY, FOURTIMES, NONE, ONCE, REDUCEMOD, TWICE};
 4
 5use num_bigint::BigUint;
 6use num_traits::cast::ToPrimitive;
 7
 8impl BarrettPrecomp<u64> {
 9    pub fn new(q: u64) -> BarrettPrecomp<u64> {
10        let big_r: BigUint =
11            (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 {
15            q: q,
16            two_q: q << 1,
17            four_q: q << 2,
18            lo: lo,
19            hi: hi,
20            one: Barrett(0, 0),
21        };
22        precomp.one = precomp.prepare(1);
23        precomp
24    }
25
26    #[inline(always)]
27    pub fn one(&self) -> Barrett<u64> {
28        self.one
29    }
30
31    #[inline(always)]
32    pub fn reduce_assign<const REDUCE: REDUCEMOD>(&self, x: &mut u64) {
33        match REDUCE {
34            NONE => {}
35            ONCE => x.reduce_once_assign(self.q),
36            TWICE => x.reduce_once_assign(self.two_q),
37            FOURTIMES => x.reduce_once_assign(self.four_q),
38            BARRETT => {
39                let (_, mhi) = x.widening_mul(self.hi);
40                *x = *x - mhi.wrapping_mul(self.q);
41                x.reduce_once_assign(self.q);
42            }
43            BARRETTLAZY => {
44                let (_, mhi) = x.widening_mul(self.hi);
45                *x = *x - mhi.wrapping_mul(self.q)
46            }
47            _ => unreachable!("invalid REDUCE argument"),
48        }
49    }
50
51    #[inline(always)]
52    pub fn reduce<const REDUCE: REDUCEMOD>(&self, x: &u64) -> u64 {
53        let mut r = *x;
54        self.reduce_assign::<REDUCE>(&mut r);
55        r
56    }
57
58    #[inline(always)]
59    pub fn prepare(&self, v: u64) -> Barrett<u64> {
60        debug_assert!(v < self.q);
61        let quotient: u64 = (((v as u128) << 64) / self.q as u128) as _;
62        Barrett(v, quotient)
63    }
64
65    #[inline(always)]
66    pub fn mul_external<const REDUCE: REDUCEMOD>(&self, lhs: &Barrett<u64>, rhs: &u64) -> u64 {
67        let mut r: u64 = *rhs;
68        self.mul_external_assign::<REDUCE>(lhs, &mut r);
69        r
70    }
71
72    #[inline(always)]
73    pub fn mul_external_assign<const REDUCE: REDUCEMOD>(&self, lhs: &Barrett<u64>, rhs: &mut u64) {
74        let t: u64 = ((*lhs.quotient() as u128 * *rhs as u128) >> 64) as _;
75        *rhs = (rhs.wrapping_mul(*lhs.value())).wrapping_sub(self.q.wrapping_mul(t));
76        self.reduce_assign::<REDUCE>(rhs);
77    }
78}