fhe-study/generalized-fhe/src/glwe.rs
generalized-fhe/src/glwe.rsRaw
1use anyhow::Result;
2use rand::Rng;
3use rand_distr::{Normal, Uniform};
4use std::ops::Add;
5
6use arith::{Ring, Rq, TR};
7
8const ERR_SIGMA: f64 = 3.2;
9
10pub struct GLWE<const Q: u64, const N: usize, const K: usize>(TR<Rq<Q, N>, K>, Rq<Q, N>);
11
12#[derive(Clone, Debug)]
13pub struct SecretKey<const Q: u64, const N: usize, const K: usize>(TR<Rq<Q, N>, K>);
14#[derive(Clone, Debug)]
15pub struct PublicKey<const Q: u64, const N: usize, const K: usize>(Rq<Q, N>, TR<Rq<Q, N>, K>);
16
17impl<const Q: u64, const N: usize, const K: usize> GLWE<Q, N, K> {
18 pub fn new_key(mut rng: impl Rng) -> Result<(SecretKey<Q, N, K>, PublicKey<Q, N, K>)> {
19 let Xi_key = Uniform::new(0_f64, 2_f64);
20 let Xi_err = Normal::new(0_f64, ERR_SIGMA)?;
21
22 let s: TR<Rq<Q, N>, K> = TR::rand(&mut rng, Xi_key);
23 let a: TR<Rq<Q, N>, K> = TR::rand(&mut rng, Uniform::new(0_f64, Q as f64));
24 let e = Rq::<Q, N>::rand(&mut rng, Xi_err);
25
26 let pk: PublicKey<Q, N, K> = PublicKey((&a * &s) + e, a);
27 Ok((SecretKey(s), pk))
28 }
29
30 // TODO delta not as input
31 pub fn encrypt_s<const T: u64>(
32 mut rng: impl Rng,
33 sk: &SecretKey<Q, N, K>,
34 m: &Rq<T, N>,
35 delta: u64,
36 ) -> Result<Self> {
37 let m: Rq<Q, N> = m.remodule::<Q>();
38
39 let Xi_key = Uniform::new(0_f64, 2_f64);
40 let Xi_err = Normal::new(0_f64, ERR_SIGMA)?;
41
42 let a: TR<Rq<Q, N>, K> = TR::rand(&mut rng, Xi_key);
43 let e = Rq::<Q, N>::rand(&mut rng, Xi_err);
44
45 let b: Rq<Q, N> = (&a * &sk.0) + m * delta + e;
46 Ok(Self(a, b))
47 }
48 pub fn encrypt<const T: u64>(
49 mut rng: impl Rng,
50 pk: &PublicKey<Q, N, K>,
51 m: &Rq<T, N>,
52 delta: u64,
53 ) -> Result<Self> {
54 let m: Rq<Q, N> = m.remodule::<Q>();
55
56 let Xi_key = Uniform::new(0_f64, 2_f64);
57 let Xi_err = Normal::new(0_f64, ERR_SIGMA)?;
58
59 let u: Rq<Q, N> = Rq::rand(&mut rng, Xi_key);
60
61 let e0 = Rq::<Q, N>::rand(&mut rng, Xi_err);
62 let e1 = TR::<Rq<Q, N>, K>::rand(&mut rng, Xi_err);
63
64 let b: Rq<Q, N> = pk.0 * u + m * delta + e0;
65 let d: TR<Rq<Q, N>, K> = &pk.1 * &u + e1;
66
67 Ok(Self(d, b))
68 }
69 pub fn decrypt<const T: u64>(&self, sk: &SecretKey<Q, N, K>, delta: u64) -> Rq<T, N> {
70 let (d, b): (TR<Rq<Q, N>, K>, Rq<Q, N>) = (self.0.clone(), self.1);
71 let r: Rq<Q, N> = b - &d * &sk.0;
72 let r_scaled: Vec<f64> = r
73 .coeffs()
74 .iter()
75 .map(|e| (e.0 as f64 / delta as f64).round())
76 .collect();
77 let r = Rq::<Q, N>::from_vec_f64(r_scaled);
78 r.remodule::<T>()
79 }
80}
81
82impl<const Q: u64, const N: usize, const K: usize> Add<GLWE<Q, N, K>> for GLWE<Q, N, K> {
83 type Output = Self;
84 fn add(self, other: Self) -> Self {
85 let a: TR<Rq<Q, N>, K> = self.0 + other.0;
86 let b: Rq<Q, N> = self.1 + other.1;
87 Self(a, b)
88 }
89}
90
91impl<const Q: u64, const N: usize, const K: usize> Add<Rq<Q, N>> for GLWE<Q, N, K> {
92 type Output = Self;
93 fn add(self, plaintext: Rq<Q, N>) -> Self {
94 let a: TR<Rq<Q, N>, K> = self.0;
95 let b: Rq<Q, N> = self.1 + plaintext;
96 Self(a, b)
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use anyhow::Result;
103 use rand::distributions::Uniform;
104
105 use super::*;
106
107 #[test]
108 fn test_encrypt_decrypt() -> Result<()> {
109 const Q: u64 = 2u64.pow(16) + 1;
110 const N: usize = 128;
111 const T: u64 = 32; // plaintext modulus
112 const K: usize = 16;
113 type S = GLWE<Q, N, K>;
114
115 let delta: u64 = Q / T; // floored
116 let mut rng = rand::thread_rng();
117
118 for _ in 0..200 {
119 let (sk, pk) = S::new_key(&mut rng)?;
120
121 let msg_dist = Uniform::new(0_u64, T);
122 let m = Rq::<T, N>::rand_u64(&mut rng, msg_dist)?;
123
124 let c = S::encrypt(&mut rng, &pk, &m, delta)?;
125 let m_recovered = c.decrypt(&sk, delta);
126
127 assert_eq!(m, m_recovered);
128 }
129
130 Ok(())
131 }
132
133 #[test]
134 fn test_addition() -> Result<()> {
135 const Q: u64 = 2u64.pow(16) + 1;
136 const N: usize = 128;
137 const T: u64 = 20;
138 const K: usize = 16;
139 type S = GLWE<Q, N, K>;
140
141 let delta: u64 = Q / T; // floored
142 let mut rng = rand::thread_rng();
143
144 for _ in 0..200 {
145 let (sk, pk) = S::new_key(&mut rng)?;
146
147 let msg_dist = Uniform::new(0_u64, T);
148 let m1 = Rq::<T, N>::rand_u64(&mut rng, msg_dist)?;
149 let m2 = Rq::<T, N>::rand_u64(&mut rng, msg_dist)?;
150
151 let c1 = S::encrypt(&mut rng, &pk, &m1, delta)?;
152 let c2 = S::encrypt(&mut rng, &pk, &m2, delta)?;
153
154 let c3 = c1 + c2;
155
156 let m3_recovered = c3.decrypt(&sk, delta);
157
158 assert_eq!(m1 + m2, m3_recovered);
159 }
160
161 Ok(())
162 }
163
164 #[test]
165 fn test_add_plaintext() -> Result<()> {
166 const Q: u64 = 2u64.pow(16) + 1;
167 const N: usize = 128;
168 const T: u64 = 32;
169 const K: usize = 16;
170 type S = GLWE<Q, N, K>;
171
172 let delta: u64 = Q / T; // floored
173 let mut rng = rand::thread_rng();
174
175 for _ in 0..200 {
176 let (sk, pk) = S::new_key(&mut rng)?;
177
178 let msg_dist = Uniform::new(0_u64, T);
179 let m1 = Rq::<T, N>::rand_u64(&mut rng, msg_dist)?;
180 let m2 = Rq::<T, N>::rand_u64(&mut rng, msg_dist)?;
181 let m2_scaled: Rq<Q, N> = m2.remodule::<Q>() * delta;
182
183 let c1 = S::encrypt(&mut rng, &pk, &m1, delta)?;
184
185 let c3 = c1 + m2_scaled;
186
187 let m3_recovered = c3.decrypt(&sk, delta);
188
189 assert_eq!(m1 + m2, m3_recovered);
190 }
191
192 Ok(())
193 }
194}