poulpy/rlwe/src/elem_rgsw.rs
rlwe/src/elem_rgsw.rsRaw
1use base2k::{
2 Backend, FFT64, MatZnxDft, MatZnxDftAlloc, MatZnxDftOps, MatZnxDftScratch, MatZnxDftToMut, MatZnxDftToRef, Module, ScalarZnx,
3 ScalarZnxDft, ScalarZnxDftToRef, ScalarZnxToRef, Scratch, VecZnx, VecZnxAlloc, VecZnxBig, VecZnxBigOps, VecZnxBigScratch,
4 VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxDftToMut, VecZnxDftToRef, VecZnxOps, VecZnxToMut, VecZnxToRef, ZnxInfos,
5 ZnxZero,
6};
7use sampling::source::Source;
8
9use crate::{
10 elem::{GetRow, Infos, MatZnxDftProducts, SetRow},
11 elem_grlwe::GRLWECt,
12 elem_rlwe::{RLWECt, RLWECtDft, RLWEPt, encrypt_rlwe_sk},
13 keys::SecretKeyDft,
14 utils::derive_size,
15};
16
17pub struct RGSWCt<C, B: Backend> {
18 pub data: MatZnxDft<C, B>,
19 pub log_base2k: usize,
20 pub log_k: usize,
21}
22
23impl<B: Backend> RGSWCt<Vec<u8>, B> {
24 pub fn new(module: &Module<B>, log_base2k: usize, log_k: usize, rows: usize) -> Self {
25 Self {
26 data: module.new_mat_znx_dft(rows, 2, 2, derive_size(log_base2k, log_k)),
27 log_base2k: log_base2k,
28 log_k: log_k,
29 }
30 }
31}
32
33impl<T, B: Backend> Infos for RGSWCt<T, B> {
34 type Inner = MatZnxDft<T, B>;
35
36 fn inner(&self) -> &Self::Inner {
37 &self.data
38 }
39
40 fn log_base2k(&self) -> usize {
41 self.log_base2k
42 }
43
44 fn log_k(&self) -> usize {
45 self.log_k
46 }
47}
48
49impl<C, B: Backend> MatZnxDftToMut<B> for RGSWCt<C, B>
50where
51 MatZnxDft<C, B>: MatZnxDftToMut<B>,
52{
53 fn to_mut(&mut self) -> MatZnxDft<&mut [u8], B> {
54 self.data.to_mut()
55 }
56}
57
58impl<C, B: Backend> MatZnxDftToRef<B> for RGSWCt<C, B>
59where
60 MatZnxDft<C, B>: MatZnxDftToRef<B>,
61{
62 fn to_ref(&self) -> MatZnxDft<&[u8], B> {
63 self.data.to_ref()
64 }
65}
66
67impl RGSWCt<Vec<u8>, FFT64> {
68 pub fn encrypt_sk_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
69 RLWECt::encrypt_sk_scratch_space(module, size)
70 + module.bytes_of_vec_znx(2, size)
71 + module.bytes_of_vec_znx(1, size)
72 + module.bytes_of_vec_znx_dft(2, size)
73 }
74
75 pub fn mul_rlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, rgsw_size: usize) -> usize {
76 module.bytes_of_vec_znx_dft(2, rgsw_size)
77 + ((module.bytes_of_vec_znx_dft(2, a_size) + module.vmp_apply_tmp_bytes(res_size, a_size, a_size, 2, 2, rgsw_size))
78 | module.vec_znx_big_normalize_tmp_bytes())
79 }
80
81 pub fn mul_rlwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, rgsw_size: usize) -> usize {
82 Self::mul_rlwe_scratch_space(module, res_size, res_size, rgsw_size)
83 }
84
85 pub fn mul_rlwe_dft_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
86 (Self::mul_rlwe_scratch_space(module, res_size, a_size, grlwe_size) | module.vec_znx_idft_tmp_bytes())
87 + module.bytes_of_vec_znx(2, a_size)
88 + module.bytes_of_vec_znx(2, res_size)
89 }
90
91 pub fn mul_rlwe_dft_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, grlwe_size: usize) -> usize {
92 (Self::mul_rlwe_inplace_scratch_space(module, res_size, grlwe_size) | module.vec_znx_idft_tmp_bytes())
93 + module.bytes_of_vec_znx(2, res_size)
94 }
95
96 pub fn mul_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
97 Self::mul_rlwe_dft_inplace_scratch_space(module, res_size, grlwe_size) + module.bytes_of_vec_znx_dft(2, a_size)
98 }
99
100 pub fn mul_grlwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
101 Self::mul_rlwe_dft_inplace_scratch_space(module, res_size, grlwe_size) + module.bytes_of_vec_znx_dft(2, a_size)
102 }
103
104 pub fn mul_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
105 Self::mul_rlwe_dft_inplace_scratch_space(module, res_size, grlwe_size) + module.bytes_of_vec_znx_dft(2, a_size)
106 }
107
108 pub fn mul_rgsw_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
109 Self::mul_rlwe_dft_inplace_scratch_space(module, res_size, grlwe_size) + module.bytes_of_vec_znx_dft(2, a_size)
110 }
111}
112
113pub fn encrypt_rgsw_sk<C, P, S>(
114 module: &Module<FFT64>,
115 ct: &mut RGSWCt<C, FFT64>,
116 pt: &ScalarZnx<P>,
117 sk_dft: &SecretKeyDft<S, FFT64>,
118 source_xa: &mut Source,
119 source_xe: &mut Source,
120 sigma: f64,
121 bound: f64,
122 scratch: &mut Scratch,
123) where
124 MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
125 ScalarZnx<P>: ScalarZnxToRef,
126 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
127{
128 let size: usize = ct.size();
129 let log_base2k: usize = ct.log_base2k();
130
131 let (tmp_znx_pt, scratch_1) = scratch.tmp_vec_znx(module, 1, size);
132 let (tmp_znx_ct, scrach_2) = scratch_1.tmp_vec_znx(module, 2, size);
133
134 let mut vec_znx_pt: RLWEPt<&mut [u8]> = RLWEPt {
135 data: tmp_znx_pt,
136 log_base2k: log_base2k,
137 log_k: ct.log_k(),
138 };
139
140 let mut vec_znx_ct: RLWECt<&mut [u8]> = RLWECt {
141 data: tmp_znx_ct,
142 log_base2k: log_base2k,
143 log_k: ct.log_k(),
144 };
145
146 (0..ct.rows()).for_each(|row_j| {
147 // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
148 module.vec_znx_add_scalar_inplace(&mut vec_znx_pt, 0, row_j, pt, 0);
149 module.vec_znx_normalize_inplace(log_base2k, &mut vec_znx_pt, 0, scrach_2);
150
151 (0..ct.cols()).for_each(|col_i| {
152 // rlwe encrypt of vec_znx_pt into vec_znx_ct
153 encrypt_rlwe_sk(
154 module,
155 &mut vec_znx_ct,
156 Some((&vec_znx_pt, col_i)),
157 sk_dft,
158 source_xa,
159 source_xe,
160 sigma,
161 bound,
162 scrach_2,
163 );
164
165 // Switch vec_znx_ct into DFT domain
166 {
167 let (mut vec_znx_dft_ct, _) = scrach_2.tmp_vec_znx_dft(module, 2, size);
168 module.vec_znx_dft(&mut vec_znx_dft_ct, 0, &vec_znx_ct, 0);
169 module.vec_znx_dft(&mut vec_znx_dft_ct, 1, &vec_znx_ct, 1);
170 module.vmp_prepare_row(ct, row_j, col_i, &vec_znx_dft_ct);
171 }
172 });
173
174 vec_znx_pt.data.zero(); // zeroes for next iteration
175 });
176}
177
178impl<C> RGSWCt<C, FFT64> {
179 pub fn encrypt_sk<P, S>(
180 &mut self,
181 module: &Module<FFT64>,
182 pt: &ScalarZnx<P>,
183 sk_dft: &SecretKeyDft<S, FFT64>,
184 source_xa: &mut Source,
185 source_xe: &mut Source,
186 sigma: f64,
187 bound: f64,
188 scratch: &mut Scratch,
189 ) where
190 MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
191 ScalarZnx<P>: ScalarZnxToRef,
192 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
193 {
194 encrypt_rgsw_sk(
195 module, self, pt, sk_dft, source_xa, source_xe, sigma, bound, scratch,
196 )
197 }
198
199 pub fn mul_rlwe<R, A>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, a: &RLWECt<A>, scratch: &mut Scratch)
200 where
201 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>,
202 VecZnx<R>: VecZnxToMut,
203 VecZnx<A>: VecZnxToRef,
204 {
205 MatZnxDftProducts::mul_rlwe(self, module, res, a, scratch);
206 }
207
208 pub fn mul_rlwe_inplace<R>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, scratch: &mut Scratch)
209 where
210 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
211 VecZnx<R>: VecZnxToMut + VecZnxToRef,
212 {
213 MatZnxDftProducts::mul_rlwe_inplace(self, module, res, scratch);
214 }
215
216 pub fn mul_rlwe_dft<R, A>(
217 &self,
218 module: &Module<FFT64>,
219 res: &mut RLWECtDft<R, FFT64>,
220 a: &RLWECtDft<A, FFT64>,
221 scratch: &mut Scratch,
222 ) where
223 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
224 VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64> + ZnxInfos,
225 VecZnxDft<A, FFT64>: VecZnxDftToRef<FFT64> + ZnxInfos,
226 {
227 MatZnxDftProducts::mul_rlwe_dft(self, module, res, a, scratch);
228 }
229
230 pub fn mul_rlwe_dft_inplace<R>(&self, module: &Module<FFT64>, res: &mut RLWECtDft<R, FFT64>, scratch: &mut Scratch)
231 where
232 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
233 VecZnxDft<R, FFT64>: VecZnxDftToRef<FFT64> + VecZnxDftToMut<FFT64>,
234 {
235 MatZnxDftProducts::mul_rlwe_dft_inplace(self, module, res, scratch);
236 }
237
238 pub fn mul_grlwe<R, A>(
239 &self,
240 module: &Module<FFT64>,
241 res: &mut GRLWECt<R, FFT64>,
242 a: &GRLWECt<A, FFT64>,
243 scratch: &mut Scratch,
244 ) where
245 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
246 MatZnxDft<R, FFT64>: MatZnxDftToMut<FFT64> + MatZnxDftToRef<FFT64> + ZnxInfos,
247 MatZnxDft<A, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
248 {
249 MatZnxDftProducts::mul_grlwe(self, module, res, a, scratch);
250 }
251
252 pub fn mul_grlwe_inplace<R>(&self, module: &Module<FFT64>, res: &mut R, scratch: &mut Scratch)
253 where
254 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
255 R: GetRow<FFT64> + SetRow<FFT64> + Infos,
256 {
257 MatZnxDftProducts::mul_grlwe_inplace(self, module, res, scratch);
258 }
259}
260
261impl<C> GetRow<FFT64> for RGSWCt<C, FFT64>
262where
263 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>,
264{
265 fn get_row<R>(&self, module: &Module<FFT64>, row_i: usize, col_j: usize, res: &mut RLWECtDft<R, FFT64>)
266 where
267 VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64>,
268 {
269 module.vmp_extract_row(res, self, row_i, col_j);
270 }
271}
272
273impl<C> SetRow<FFT64> for RGSWCt<C, FFT64>
274where
275 MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
276{
277 fn set_row<R>(&mut self, module: &Module<FFT64>, row_i: usize, col_j: usize, a: &RLWECtDft<R, FFT64>)
278 where
279 VecZnxDft<R, FFT64>: VecZnxDftToRef<FFT64>,
280 {
281 module.vmp_prepare_row(self, row_i, col_j, a);
282 }
283}
284
285impl<C> MatZnxDftProducts<RGSWCt<C, FFT64>, C> for RGSWCt<C, FFT64>
286where
287 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
288{
289 fn mul_rlwe<R, A>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, a: &RLWECt<A>, scratch: &mut Scratch)
290 where
291 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>,
292 VecZnx<R>: VecZnxToMut,
293 VecZnx<A>: VecZnxToRef,
294 {
295 let log_base2k: usize = self.log_base2k();
296
297 #[cfg(debug_assertions)]
298 {
299 assert_eq!(res.log_base2k(), log_base2k);
300 assert_eq!(a.log_base2k(), log_base2k);
301 assert_eq!(self.n(), module.n());
302 assert_eq!(res.n(), module.n());
303 assert_eq!(a.n(), module.n());
304 }
305
306 let (mut res_dft, scratch1) = scratch.tmp_vec_znx_dft(module, 2, self.size()); // Todo optimise
307
308 {
309 let (mut a_dft, scratch2) = scratch1.tmp_vec_znx_dft(module, 2, a.size());
310 module.vec_znx_dft(&mut a_dft, 0, a, 0);
311 module.vec_znx_dft(&mut a_dft, 1, a, 1);
312 module.vmp_apply(&mut res_dft, &a_dft, self, scratch2);
313 }
314
315 let res_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(res_dft);
316
317 module.vec_znx_big_normalize(log_base2k, res, 0, &res_big, 0, scratch1);
318 module.vec_znx_big_normalize(log_base2k, res, 1, &res_big, 1, scratch1);
319 }
320}