poulpy/rlwe/src/elem_grlwe.rs
rlwe/src/elem_grlwe.rsRaw
1use base2k::{
2 Backend, FFT64, MatZnxDft, MatZnxDftAlloc, MatZnxDftOps, MatZnxDftToMut, MatZnxDftToRef, Module, ScalarZnx, ScalarZnxDft,
3 ScalarZnxDftToRef, ScalarZnxToRef, Scratch, VecZnxAlloc, VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxDftToMut, VecZnxOps,
4 ZnxZero,
5};
6use sampling::source::Source;
7
8use crate::{
9 elem::Infos,
10 elem_rlwe::{RLWECt, RLWECtDft, RLWEPt},
11 keys::SecretKeyDft,
12 utils::derive_size,
13};
14
15pub struct GRLWECt<C, B: Backend> {
16 pub data: MatZnxDft<C, B>,
17 pub log_base2k: usize,
18 pub log_k: usize,
19}
20
21impl<B: Backend> GRLWECt<Vec<u8>, B> {
22 pub fn new(module: &Module<B>, log_base2k: usize, log_k: usize, rows: usize) -> Self {
23 Self {
24 data: module.new_mat_znx_dft(rows, 1, 2, derive_size(log_base2k, log_k)),
25 log_base2k: log_base2k,
26 log_k: log_k,
27 }
28 }
29}
30
31impl<C> GRLWECt<C, FFT64>
32where
33 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>,
34{
35 pub fn get_row(&self, module: &Module<FFT64>, i: usize, res: &mut RLWECtDft<C, FFT64>)
36 where
37 VecZnxDft<C, FFT64>: VecZnxDftToMut<FFT64>,
38 {
39 module.vmp_extract_row(res, self, i, 0);
40 }
41}
42
43impl<T, B: Backend> Infos for GRLWECt<T, B> {
44 type Inner = MatZnxDft<T, B>;
45
46 fn inner(&self) -> &Self::Inner {
47 &self.data
48 }
49
50 fn log_base2k(&self) -> usize {
51 self.log_base2k
52 }
53
54 fn log_k(&self) -> usize {
55 self.log_k
56 }
57}
58
59impl<C, B: Backend> MatZnxDftToMut<B> for GRLWECt<C, B>
60where
61 MatZnxDft<C, B>: MatZnxDftToMut<B>,
62{
63 fn to_mut(&mut self) -> MatZnxDft<&mut [u8], B> {
64 self.data.to_mut()
65 }
66}
67
68impl<C, B: Backend> MatZnxDftToRef<B> for GRLWECt<C, B>
69where
70 MatZnxDft<C, B>: MatZnxDftToRef<B>,
71{
72 fn to_ref(&self) -> MatZnxDft<&[u8], B> {
73 self.data.to_ref()
74 }
75}
76
77impl GRLWECt<Vec<u8>, FFT64> {
78 pub fn encrypt_sk_scratch_bytes(module: &Module<FFT64>, size: usize) -> usize {
79 RLWECt::encrypt_sk_scratch_bytes(module, size)
80 + module.bytes_of_vec_znx(2, size)
81 + module.bytes_of_vec_znx(1, size)
82 + module.bytes_of_vec_znx_dft(2, size)
83 }
84
85 // pub fn encrypt_pk_scratch_bytes(module: &Module<FFT64>, pk_size: usize) -> usize {
86 // RLWECt::encrypt_pk_scratch_bytes(module, pk_size)
87 // }
88}
89
90pub fn encrypt_grlwe_sk<C, P, S>(
91 module: &Module<FFT64>,
92 ct: &mut GRLWECt<C, FFT64>,
93 pt: &ScalarZnx<P>,
94 sk: &SecretKeyDft<S, FFT64>,
95 source_xa: &mut Source,
96 source_xe: &mut Source,
97 sigma: f64,
98 bound: f64,
99 scratch: &mut Scratch,
100) where
101 MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
102 ScalarZnx<P>: ScalarZnxToRef,
103 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
104{
105 let rows: usize = ct.rows();
106 let size: usize = ct.size();
107 let log_base2k: usize = ct.log_base2k();
108
109 let (tmp_znx_pt, scrach_1) = scratch.tmp_vec_znx(module, 1, size);
110 let (tmp_znx_ct, scrach_2) = scrach_1.tmp_vec_znx(module, 2, size);
111 let (mut vec_znx_dft_ct, scratch_3) = scrach_2.tmp_vec_znx_dft(module, 2, size);
112
113 let mut vec_znx_pt: RLWEPt<&mut [u8]> = RLWEPt {
114 data: tmp_znx_pt,
115 log_base2k: log_base2k,
116 log_k: ct.log_k(),
117 };
118
119 let mut vec_znx_ct: RLWECt<&mut [u8]> = RLWECt {
120 data: tmp_znx_ct,
121 log_base2k: log_base2k,
122 log_k: ct.log_k(),
123 };
124
125 (0..rows).for_each(|row_i| {
126 // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
127 module.vec_znx_add_scalar_inplace(&mut vec_znx_pt, 0, row_i, pt, 0);
128 module.vec_znx_normalize_inplace(log_base2k, &mut vec_znx_pt, 0, scratch_3);
129
130 // rlwe encrypt of vec_znx_pt into vec_znx_ct
131 vec_znx_ct.encrypt_sk(
132 module,
133 Some(&vec_znx_pt),
134 sk,
135 source_xa,
136 source_xe,
137 sigma,
138 bound,
139 scratch_3,
140 );
141
142 vec_znx_pt.data.zero(); // zeroes for next iteration
143
144 // Switch vec_znx_ct into DFT domain
145 module.vec_znx_dft(&mut vec_znx_dft_ct, 0, &vec_znx_ct, 0);
146 module.vec_znx_dft(&mut vec_znx_dft_ct, 1, &vec_znx_ct, 1);
147
148 // Stores vec_znx_dft_ct into thw i-th row of the MatZnxDft
149 module.vmp_prepare_row(ct, row_i, 0, &vec_znx_dft_ct);
150 });
151}
152
153impl<C> GRLWECt<C, FFT64> {
154 pub fn encrypt_sk<P, S>(
155 &mut self,
156 module: &Module<FFT64>,
157 pt: &ScalarZnx<P>,
158 sk_dft: &SecretKeyDft<S, FFT64>,
159 source_xa: &mut Source,
160 source_xe: &mut Source,
161 sigma: f64,
162 bound: f64,
163 scratch: &mut Scratch,
164 ) where
165 MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
166 ScalarZnx<P>: ScalarZnxToRef,
167 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
168 {
169 encrypt_grlwe_sk(
170 module, self, pt, sk_dft, source_xa, source_xe, sigma, bound, scratch,
171 )
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use base2k::{FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps};
178 use sampling::source::Source;
179
180 use crate::{
181 elem::Infos,
182 elem_rlwe::{RLWECtDft, RLWEPt},
183 keys::{SecretKey, SecretKeyDft},
184 };
185
186 use super::GRLWECt;
187
188 #[test]
189 fn encrypt_sk_vec_znx_fft64() {
190 let module: Module<FFT64> = Module::<FFT64>::new(2048);
191 let log_base2k: usize = 8;
192 let log_k_ct: usize = 54;
193 let rows: usize = 4;
194
195 let sigma: f64 = 3.2;
196 let bound: f64 = sigma * 6.0;
197
198 let mut ct: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_ct, rows);
199 let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct);
200 let mut pt_scalar: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
201
202 let mut source_xs: Source = Source::new([0u8; 32]);
203 let mut source_xe: Source = Source::new([0u8; 32]);
204 let mut source_xa: Source = Source::new([0u8; 32]);
205
206 pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs);
207
208 let mut scratch: ScratchOwned = ScratchOwned::new(
209 GRLWECt::encrypt_sk_scratch_bytes(&module, ct.size()) | RLWECtDft::decrypt_scratch_bytes(&module, ct.size()),
210 );
211
212 let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module);
213 sk.fill_ternary_prob(0.5, &mut source_xs);
214
215 let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
216 sk_dft.dft(&module, &sk);
217
218 ct.encrypt_sk(
219 &module,
220 &pt_scalar,
221 &sk_dft,
222 &mut source_xa,
223 &mut source_xe,
224 sigma,
225 bound,
226 scratch.borrow(),
227 );
228
229 let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_ct, 2);
230
231 (0..ct.rows()).for_each(|row_i| {
232 ct.get_row(&module, row_i, &mut ct_rlwe_dft);
233 ct_rlwe_dft.decrypt(&module, &mut pt, &sk_dft, scratch.borrow());
234 module.vec_znx_sub_scalar_inplace(&mut pt, 0, row_i, &pt_scalar, 0);
235 let std_pt: f64 = pt.data.std(0, log_base2k) * (log_k_ct as f64).exp2();
236 assert!((sigma - std_pt) <= 0.2, "{} {}", sigma, std_pt);
237 });
238
239 module.free();
240 }
241}