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