arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
phantom-zone/src/backend.rs
src/backend.rsRaw
  1use itertools::izip;
  2
  3pub trait ModInit {
  4    type Element;
  5    fn new(q: Self::Element) -> Self;
  6}
  7
  8pub trait VectorOps {
  9    type Element;
 10
 11    fn elwise_scalar_mul(&self, out: &mut [Self::Element], a: &[Self::Element], b: &Self::Element);
 12    fn elwise_mul(&self, out: &mut [Self::Element], a: &[Self::Element], b: &[Self::Element]);
 13
 14    fn elwise_add_mut(&self, a: &mut [Self::Element], b: &[Self::Element]);
 15    fn elwise_sub_mut(&self, a: &mut [Self::Element], b: &[Self::Element]);
 16    fn elwise_mul_mut(&self, a: &mut [Self::Element], b: &[Self::Element]);
 17    fn elwise_neg_mut(&self, a: &mut [Self::Element]);
 18    /// inplace mutates `a`: a = a + b*c
 19    fn elwise_fma_mut(&self, a: &mut [Self::Element], b: &[Self::Element], c: &[Self::Element]);
 20    fn elwise_fma_scalar_mut(
 21        &self,
 22        a: &mut [Self::Element],
 23        b: &[Self::Element],
 24        c: &Self::Element,
 25    );
 26
 27    fn modulus(&self) -> Self::Element;
 28}
 29
 30pub trait ArithmeticOps {
 31    type Element;
 32
 33    fn mul(&self, a: &Self::Element, b: &Self::Element) -> Self::Element;
 34    fn add(&self, a: &Self::Element, b: &Self::Element) -> Self::Element;
 35    fn sub(&self, a: &Self::Element, b: &Self::Element) -> Self::Element;
 36    fn neg(&self, a: &Self::Element) -> Self::Element;
 37
 38    fn modulus(&self) -> Self::Element;
 39}
 40
 41pub struct ModularOpsU64 {
 42    q: u64,
 43    logq: usize,
 44    barrett_mu: u128,
 45    barrett_alpha: usize,
 46}
 47
 48impl ModInit for ModularOpsU64 {
 49    type Element = u64;
 50    fn new(q: u64) -> ModularOpsU64 {
 51        let logq = 64 - q.leading_zeros();
 52
 53        // barrett calculation
 54        let mu = (1u128 << (logq * 2 + 3)) / (q as u128);
 55        let alpha = logq + 3;
 56
 57        ModularOpsU64 {
 58            q,
 59            logq: logq as usize,
 60            barrett_alpha: alpha as usize,
 61            barrett_mu: mu,
 62        }
 63    }
 64}
 65
 66impl ModularOpsU64 {
 67    fn add_mod_fast(&self, a: u64, b: u64) -> u64 {
 68        debug_assert!(a < self.q);
 69        debug_assert!(b < self.q);
 70
 71        let mut o = a + b;
 72        if o >= self.q {
 73            o -= self.q;
 74        }
 75        o
 76    }
 77
 78    fn sub_mod_fast(&self, a: u64, b: u64) -> u64 {
 79        debug_assert!(a < self.q);
 80        debug_assert!(b < self.q);
 81
 82        if a > b {
 83            a - b
 84        } else {
 85            (self.q + a) - b
 86        }
 87    }
 88
 89    /// returns (a * b)  % q
 90    ///
 91    /// - both a and b must be in range [0, 2q)
 92    /// - output is in range [0 , q)
 93    fn mul_mod_fast(&self, a: u64, b: u64) -> u64 {
 94        debug_assert!(a < 2 * self.q);
 95        debug_assert!(b < 2 * self.q);
 96
 97        let ab = a as u128 * b as u128;
 98
 99        // ab / (2^{n + \beta})
100        // note: \beta is assumed to -2
101        let tmp = ab >> (self.logq - 2);
102
103        // k = ((ab / (2^{n + \beta})) * \mu) / 2^{\alpha - (-2)}
104        let k = (tmp * self.barrett_mu) >> (self.barrett_alpha + 2);
105
106        // ab - k*p
107        let tmp = k * (self.q as u128);
108
109        let mut out = (ab - tmp) as u64;
110
111        if out >= self.q {
112            out -= self.q;
113        }
114
115        return out;
116    }
117}
118
119impl ArithmeticOps for ModularOpsU64 {
120    type Element = u64;
121
122    fn add(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
123        self.add_mod_fast(*a, *b)
124    }
125
126    fn mul(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
127        self.mul_mod_fast(*a, *b)
128    }
129
130    fn sub(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
131        self.sub_mod_fast(*a, *b)
132    }
133
134    fn neg(&self, a: &Self::Element) -> Self::Element {
135        self.q - *a
136    }
137
138    fn modulus(&self) -> Self::Element {
139        self.q
140    }
141}
142
143impl VectorOps for ModularOpsU64 {
144    type Element = u64;
145
146    fn elwise_add_mut(&self, a: &mut [Self::Element], b: &[Self::Element]) {
147        izip!(a.iter_mut(), b.iter()).for_each(|(ai, bi)| {
148            *ai = self.add_mod_fast(*ai, *bi);
149        });
150    }
151
152    fn elwise_sub_mut(&self, a: &mut [Self::Element], b: &[Self::Element]) {
153        izip!(a.iter_mut(), b.iter()).for_each(|(ai, bi)| {
154            *ai = self.sub_mod_fast(*ai, *bi);
155        });
156    }
157
158    fn elwise_mul_mut(&self, a: &mut [Self::Element], b: &[Self::Element]) {
159        izip!(a.iter_mut(), b.iter()).for_each(|(ai, bi)| {
160            *ai = self.mul_mod_fast(*ai, *bi);
161        });
162    }
163
164    fn elwise_neg_mut(&self, a: &mut [Self::Element]) {
165        a.iter_mut().for_each(|ai| *ai = self.q - *ai);
166    }
167
168    fn elwise_scalar_mul(&self, out: &mut [Self::Element], a: &[Self::Element], b: &Self::Element) {
169        izip!(out.iter_mut(), a.iter()).for_each(|(oi, ai)| {
170            *oi = self.mul_mod_fast(*ai, *b);
171        });
172    }
173
174    fn elwise_mul(&self, out: &mut [Self::Element], a: &[Self::Element], b: &[Self::Element]) {
175        izip!(out.iter_mut(), a.iter(), b.iter()).for_each(|(oi, ai, bi)| {
176            *oi = self.mul_mod_fast(*ai, *bi);
177        });
178    }
179
180    fn elwise_fma_mut(&self, a: &mut [Self::Element], b: &[Self::Element], c: &[Self::Element]) {
181        izip!(a.iter_mut(), b.iter(), c.iter()).for_each(|(ai, bi, ci)| {
182            *ai = self.add_mod_fast(*ai, self.mul_mod_fast(*bi, *ci));
183        });
184    }
185
186    fn elwise_fma_scalar_mut(
187        &self,
188        a: &mut [Self::Element],
189        b: &[Self::Element],
190        c: &Self::Element,
191    ) {
192        izip!(a.iter_mut(), b.iter()).for_each(|(ai, bi)| {
193            *ai = self.add_mod_fast(*ai, self.mul_mod_fast(*bi, *c));
194        });
195    }
196
197    fn modulus(&self) -> Self::Element {
198        self.q
199    }
200}