poulpy/rlwe/src/encryption.rs
rlwe/src/encryption.rsRaw
1use base2k::{
2 AddNormal, Backend, FFT64, FillUniform, Module, ScalarZnxDftOps, ScalarZnxDftToRef, Scratch, VecZnx, VecZnxAlloc,
3 VecZnxBigAlloc, VecZnxBigOps, VecZnxBigScratch, VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxDftToMut, VecZnxToMut,
4 VecZnxToRef, ZnxInfos,
5};
6
7use sampling::source::Source;
8
9use crate::{
10 elem::{Ciphertext, Infos, Plaintext},
11 keys::SecretKey,
12};
13
14pub trait EncryptSk<B: Backend, C, P> {
15 fn encrypt<S>(
16 module: &Module<B>,
17 res: &mut Ciphertext<C>,
18 pt: Option<&Plaintext<P>>,
19 sk: &SecretKey<S>,
20 source_xa: &mut Source,
21 source_xe: &mut Source,
22 scratch: &mut Scratch,
23 sigma: f64,
24 bound: f64,
25 ) where
26 S: ScalarZnxDftToRef<B>;
27
28 fn encrypt_scratch_bytes(module: &Module<B>, size: usize) -> usize;
29}
30
31impl<C, P> EncryptSk<FFT64, C, P> for Ciphertext<C>
32where
33 C: VecZnxToMut + ZnxInfos,
34 P: VecZnxToRef + ZnxInfos,
35{
36 fn encrypt<S>(
37 module: &Module<FFT64>,
38 ct: &mut Ciphertext<C>,
39 pt: Option<&Plaintext<P>>,
40 sk: &SecretKey<S>,
41 source_xa: &mut Source,
42 source_xe: &mut Source,
43 scratch: &mut Scratch,
44 sigma: f64,
45 bound: f64,
46 ) where
47 S: ScalarZnxDftToRef<FFT64>,
48 {
49 let log_base2k: usize = ct.log_base2k();
50 let log_q: usize = ct.log_q();
51 let mut ct_mut: VecZnx<&mut [u8]> = ct.to_mut();
52 let size: usize = ct_mut.size();
53
54 // c1 = a
55 ct_mut.fill_uniform(log_base2k, 1, size, source_xa);
56
57 let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size);
58
59 {
60 let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size);
61 module.vec_znx_dft(&mut c0_dft, 0, &ct_mut, 1);
62
63 // c0_dft = DFT(a) * DFT(s)
64 module.svp_apply_inplace(&mut c0_dft, 0, &sk.data().to_ref(), 0);
65
66 // c0_big = IDFT(c0_dft)
67 module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0);
68 }
69
70 // c0_big = m - c0_big
71 if let Some(pt) = pt {
72 module.vec_znx_big_sub_small_b_inplace(&mut c0_big, 0, pt, 0);
73 }
74 // c0_big += e
75 c0_big.add_normal(log_base2k, 0, log_q, source_xe, sigma, bound);
76
77 // c0 = norm(c0_big = -as + m + e)
78 module.vec_znx_big_normalize(log_base2k, &mut ct_mut, 0, &c0_big, 0, scratch_1);
79 }
80
81 fn encrypt_scratch_bytes(module: &Module<FFT64>, size: usize) -> usize {
82 (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size)
83 }
84}
85
86impl<C> Ciphertext<C>
87where
88 C: VecZnxToMut + ZnxInfos,
89{
90 pub fn encrypt_sk<P, S>(
91 &mut self,
92 module: &Module<FFT64>,
93 pt: Option<&Plaintext<P>>,
94 sk: &SecretKey<S>,
95 source_xa: &mut Source,
96 source_xe: &mut Source,
97 scratch: &mut Scratch,
98 sigma: f64,
99 bound: f64,
100 ) where
101 P: VecZnxToRef + ZnxInfos,
102 S: ScalarZnxDftToRef<FFT64>,
103 {
104 <Self as EncryptSk<FFT64, _, _>>::encrypt(
105 module, self, pt, sk, source_xa, source_xe, scratch, sigma, bound,
106 );
107 }
108
109 pub fn encrypt_sk_scratch_bytes<P>(module: &Module<FFT64>, size: usize) -> usize
110 where
111 Self: EncryptSk<FFT64, C, P>,
112 {
113 <Self as EncryptSk<FFT64, C, P>>::encrypt_scratch_bytes(module, size)
114 }
115}
116
117pub trait EncryptZeroSk<B: Backend, D> {
118 fn encrypt_zero<S>(
119 module: &Module<B>,
120 res: &mut D,
121 sk: &SecretKey<S>,
122 source_xa: &mut Source,
123 source_xe: &mut Source,
124 scratch: &mut Scratch,
125 sigma: f64,
126 bound: f64,
127 ) where
128 S: ScalarZnxDftToRef<B>;
129
130 fn encrypt_zero_scratch_bytes(module: &Module<B>, size: usize) -> usize;
131}
132
133impl<C> EncryptZeroSk<FFT64, C> for C
134where
135 C: VecZnxDftToMut<FFT64> + ZnxInfos + Infos,
136{
137 fn encrypt_zero<S>(
138 module: &Module<FFT64>,
139 ct: &mut C,
140 sk: &SecretKey<S>,
141 source_xa: &mut Source,
142 source_xe: &mut Source,
143 scratch: &mut Scratch,
144 sigma: f64,
145 bound: f64,
146 ) where
147 S: ScalarZnxDftToRef<FFT64>,
148 {
149 let log_base2k: usize = ct.log_base2k();
150 let log_q: usize = ct.log_q();
151 let mut ct_mut: VecZnxDft<&mut [u8], FFT64> = ct.to_mut();
152 let size: usize = ct_mut.size();
153
154 // ct[1] = DFT(a)
155 {
156 let (mut tmp_znx, _) = scratch.tmp_vec_znx(module, 1, size);
157 tmp_znx.fill_uniform(log_base2k, 1, size, source_xa);
158 module.vec_znx_dft(&mut ct_mut, 1, &tmp_znx, 0);
159 }
160
161 let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size);
162
163 {
164 let (mut tmp_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size);
165 // c0_dft = DFT(a) * DFT(s)
166 module.svp_apply(&mut tmp_dft, 0, &sk.data().to_ref(), 0, &ct_mut, 1);
167 // c0_big = IDFT(c0_dft)
168 module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut tmp_dft, 0);
169 }
170
171 // c0_big += e
172 c0_big.add_normal(log_base2k, 0, log_q, source_xe, sigma, bound);
173
174 // c0 = norm(c0_big = -as + e)
175 let (mut tmp_znx, scratch_2) = scratch_1.tmp_vec_znx(module, 1, size);
176 module.vec_znx_big_normalize(log_base2k, &mut tmp_znx, 0, &c0_big, 0, scratch_2);
177 // ct[0] = DFT(-as + e)
178 module.vec_znx_dft(&mut ct_mut, 0, &tmp_znx, 0);
179 }
180
181 fn encrypt_zero_scratch_bytes(module: &Module<FFT64>, size: usize) -> usize{
182 (module.bytes_of_vec_znx(1, size) | module.bytes_of_vec_znx_dft(1, size))
183 + module.bytes_of_vec_znx_big(1, size)
184 + module.bytes_of_vec_znx(1, size)
185 + module.vec_znx_big_normalize_tmp_bytes()
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use base2k::{FFT64, Module, ScratchOwned, VecZnx, Scalar};
192 use sampling::source::Source;
193
194 use crate::{elem::{Ciphertext, Infos, Plaintext}, keys::SecretKey};
195
196 #[test]
197 fn encrypt_sk_vec_znx_fft64() {
198 let module: Module<FFT64> = Module::<FFT64>::new(32);
199 let log_base2k: usize = 8;
200 let log_q: usize = 54;
201
202 let sigma: f64 = 3.2;
203 let bound: f64 = sigma * 6;
204
205 let mut ct: Ciphertext<VecZnx<Vec<u8>>> = Ciphertext::<VecZnx<Vec<u8>>>::new(&module, log_base2k, log_q, 2);
206 let mut pt: Plaintext<VecZnx<Vec<u8>>> = Plaintext::<VecZnx<Vec<u8>>>::new(&module, log_base2k, log_q);
207
208 let mut source_xe = Source::new([0u8; 32]);
209 let mut source_xa: Source = Source::new([0u8; 32]);
210
211
212 let mut scratch: ScratchOwned = ScratchOwned::new(ct.encrypt_encsk_scratch_bytes(&module, ct.size()));
213
214 let mut sk: SecretKey<Scalar<Vec<u8>>> = SecretKey::new(&module);
215 let mut sk_prep
216 sk.svp_prepare(&module, &mut sk_prep);
217
218 ct.encrypt_sk(
219 &module,
220 Some(&pt),
221 &sk_prep,
222 &mut source_xa,
223 &mut source_xe,
224 scratch.borrow(),
225 sigma,
226 bound,
227 );
228 }
229}