fhe-study/arithmetic/src/zq.rs
arithmetic/src/zq.rsRaw
1use std::fmt;
2use std::ops;
3
4// Z_q, integers modulus q, not necessarily prime
5#[derive(Clone, Copy, PartialEq)]
6pub struct Zq<const Q: u64>(pub u64);
7
8// WIP
9// impl<const Q: u64> From<Vec<u64>> for Vec<Zq<Q>> {
10// fn from(v: Vec<u64>) -> Self {
11// v.into_iter().map(Zq::new).collect()
12// }
13// }
14
15impl<const Q: u64> Zq<Q> {
16 pub fn new(e: u64) -> Self {
17 if e >= Q {
18 return Zq(e % Q);
19 }
20 Zq(e)
21 }
22 pub fn from_f64(e: f64) -> Self {
23 // WIP method
24 let e: i64 = e.round() as i64;
25 if e < 0 {
26 return Zq((Q as i64 + e) as u64);
27 } else if e >= Q as i64 {
28 return Zq((e % Q as i64) as u64);
29 }
30 Zq(e as u64)
31 }
32 pub fn from_bool(b: bool) -> Self {
33 if b {
34 Zq(1)
35 } else {
36 Zq(0)
37 }
38 }
39 pub fn zero() -> Self {
40 Zq(0u64)
41 }
42 pub fn square(self) -> Self {
43 self * self
44 }
45 // modular exponentiation
46 pub fn exp(self, e: Self) -> Self {
47 // mul-square approach
48 let mut res = Self(1);
49 let mut rem = e.clone();
50 let mut exp = self;
51 // for rem != Self(0) {
52 while rem != Self(0) {
53 // if odd
54 // TODO use a more readible expression
55 if 1 - ((rem.0 & 1) << 1) as i64 == -1 {
56 res = res * exp;
57 }
58 exp = exp.square();
59 rem = Self(rem.0 >> 1);
60 }
61 res
62 }
63 // multiplicative inverse
64 // WARNING: if this is needed, it means that 'Zq' is a Finite Field. For the moment we assume
65 // we work in a Finite Field
66 pub fn inv_OLD(self) -> Self {
67 // TODO
68 // let a = self.0;
69 // let q = Q;
70 let mut t = 0;
71 let mut r = Q;
72 let mut new_t = 0;
73 let mut new_r = self.0.clone();
74 while new_r != 0 {
75 let q = r / new_r;
76
77 t = new_t.clone();
78 new_t = t - q;
79
80 r = new_r.clone();
81 new_r = r - (q * new_r);
82 }
83 // if t < 0 {
84 // t = t + q;
85 // }
86 return Zq::new(t);
87 }
88 pub fn inv(self) -> Zq<Q> {
89 let (g, x, _) = Self::egcd(self.0 as i128, Q as i128);
90 if g != 1 {
91 // None
92 panic!("E");
93 } else {
94 let q = Q as i128;
95 Zq(((x % q + q) % q) as u64) // TODO maybe just Zq::new(x)
96 }
97 }
98 fn egcd(a: i128, b: i128) -> (i128, i128, i128) {
99 if a == 0 {
100 (b, 0, 1)
101 } else {
102 let (g, x, y) = Self::egcd(b % a, a);
103 (g, y - (b / a) * x, x)
104 }
105 }
106}
107
108impl<const Q: u64> Zq<Q> {
109 fn r#mod(self) -> Self {
110 if self.0 >= Q {
111 return Zq(self.0 % Q);
112 }
113 self
114 }
115}
116
117impl<const Q: u64> ops::Add<Zq<Q>> for Zq<Q> {
118 type Output = Self;
119
120 fn add(self, rhs: Self) -> Self::Output {
121 let mut r = self.0 + rhs.0;
122 if r >= Q {
123 r -= Q;
124 }
125 Zq(r)
126 }
127}
128impl<const Q: u64> ops::Add<&Zq<Q>> for &Zq<Q> {
129 type Output = Zq<Q>;
130
131 fn add(self, rhs: &Zq<Q>) -> Self::Output {
132 let mut r = self.0 + rhs.0;
133 if r >= Q {
134 r -= Q;
135 }
136 Zq(r)
137 }
138}
139impl<const Q: u64> ops::AddAssign<Zq<Q>> for Zq<Q> {
140 fn add_assign(&mut self, rhs: Self) {
141 *self = *self + rhs
142 }
143}
144impl<const Q: u64> std::iter::Sum for Zq<Q> {
145 fn sum<I>(iter: I) -> Self
146 where
147 I: Iterator<Item = Self>,
148 {
149 iter.fold(Zq(0), |acc, x| acc + x)
150 }
151}
152impl<const Q: u64> ops::Sub<Zq<Q>> for Zq<Q> {
153 type Output = Self;
154
155 fn sub(self, rhs: Self) -> Zq<Q> {
156 if self.0 >= rhs.0 {
157 Zq(self.0 - rhs.0)
158 } else {
159 Zq((Q + self.0) - rhs.0)
160 }
161 }
162}
163impl<const Q: u64> ops::Sub<&Zq<Q>> for &Zq<Q> {
164 type Output = Zq<Q>;
165
166 fn sub(self, rhs: &Zq<Q>) -> Self::Output {
167 if self.0 >= rhs.0 {
168 Zq(self.0 - rhs.0)
169 } else {
170 Zq((Q + self.0) - rhs.0)
171 }
172 }
173}
174impl<const Q: u64> ops::SubAssign<Zq<Q>> for Zq<Q> {
175 fn sub_assign(&mut self, rhs: Self) {
176 *self = *self - rhs
177 }
178}
179impl<const Q: u64> ops::Neg for Zq<Q> {
180 type Output = Self;
181
182 fn neg(self) -> Self::Output {
183 Zq(Q - self.0)
184 }
185}
186impl<const Q: u64> ops::Mul<Zq<Q>> for Zq<Q> {
187 type Output = Self;
188
189 fn mul(self, rhs: Self) -> Zq<Q> {
190 // TODO non-naive way
191 Zq(((self.0 as u128 * rhs.0 as u128) % Q as u128) as u64)
192 // Zq((self.0 * rhs.0) % Q)
193 }
194}
195impl<const Q: u64> ops::Div<Zq<Q>> for Zq<Q> {
196 type Output = Self;
197
198 fn div(self, rhs: Self) -> Zq<Q> {
199 // TODO non-naive way
200 // Zq((self.0 / rhs.0) % Q)
201 self * rhs.inv()
202 }
203}
204
205impl<const Q: u64> fmt::Display for Zq<Q> {
206 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207 write!(f, "{}", self.0)
208 }
209}
210impl<const Q: u64> fmt::Debug for Zq<Q> {
211 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212 write!(f, "{}", self.0)
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[test]
221 fn exp() {
222 const Q: u64 = 1021;
223 let a = Zq::<Q>(3);
224 let b = Zq::<Q>(3);
225 assert_eq!(a.exp(b), Zq(27));
226
227 let a = Zq::<Q>(1000);
228 let b = Zq::<Q>(3);
229 assert_eq!(a.exp(b), Zq(949));
230 }
231 #[test]
232 fn neg() {
233 const Q: u64 = 1021;
234 let a = Zq::<Q>::from_f64(101.0);
235 let b = Zq::<Q>::from_f64(-1.0);
236 assert_eq!(-a, a * b);
237 }
238}