poulpy/core/src/glwe/tests/generic_encryption.rs
core/src/glwe/tests/generic_encryption.rsRaw
1use backend::hal::{
2 api::{ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxCopy, VecZnxDftAlloc, VecZnxFillUniform, VecZnxStd, VecZnxSubABInplace},
3 layouts::{Backend, Module, ScratchOwned},
4 oep::{
5 ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
6 TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
7 },
8};
9use sampling::source::Source;
10
11use crate::{
12 Decompress, GLWECiphertext, GLWECiphertextCompressed, GLWEDecryptFamily, GLWEEncryptPkFamily, GLWEEncryptSkFamily, GLWEOps,
13 GLWEPlaintext, GLWEPublicKey, GLWEPublicKeyExec, GLWESecret, GLWESecretExec, GLWESecretFamily, Infos,
14};
15
16pub(crate) trait EncryptionTestModuleFamily<B: Backend> = GLWEDecryptFamily<B> + GLWESecretFamily<B> + VecZnxStd;
17
18pub(crate) trait EncryptionTestScratchFamily<B: Backend> = TakeVecZnxDftImpl<B>
19 + TakeVecZnxBigImpl<B>
20 + TakeSvpPPolImpl<B>
21 + ScratchOwnedAllocImpl<B>
22 + ScratchOwnedBorrowImpl<B>
23 + ScratchAvailableImpl<B>
24 + TakeScalarZnxImpl<B>
25 + TakeVecZnxImpl<B>;
26
27pub(crate) fn test_encrypt_sk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, k_pt: usize, sigma: f64, rank: usize)
28where
29 Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B>,
30 B: EncryptionTestScratchFamily<B>,
31{
32 let n = module.n();
33 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
34 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
35 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
36
37 let mut source_xs: Source = Source::new([0u8; 32]);
38 let mut source_xe: Source = Source::new([0u8; 32]);
39 let mut source_xa: Source = Source::new([0u8; 32]);
40
41 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
42 GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, ct.k())
43 | GLWECiphertext::decrypt_scratch_space(module, n, basek, ct.k()),
44 );
45
46 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
47 sk.fill_ternary_prob(0.5, &mut source_xs);
48 let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
49
50 module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_pt, &mut source_xa);
51
52 ct.encrypt_sk(
53 module,
54 &pt_want,
55 &sk_exec,
56 &mut source_xa,
57 &mut source_xe,
58 sigma,
59 scratch.borrow(),
60 );
61
62 ct.decrypt(module, &mut pt_have, &sk_exec, scratch.borrow());
63
64 pt_want.sub_inplace_ab(module, &pt_have);
65
66 let noise_have: f64 = module.vec_znx_std(basek, &pt_want.data, 0) * (ct.k() as f64).exp2();
67 let noise_want: f64 = sigma;
68
69 assert!(noise_have <= noise_want + 0.2);
70}
71
72pub(crate) fn test_encrypt_sk_compressed<B: Backend>(
73 module: &Module<B>,
74 basek: usize,
75 k_ct: usize,
76 k_pt: usize,
77 sigma: f64,
78 rank: usize,
79) where
80 Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B> + VecZnxCopy,
81 B: EncryptionTestScratchFamily<B>,
82{
83 let n = module.n();
84 let mut ct_compressed: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc(n, basek, k_ct, rank);
85
86 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
87 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
88
89 let mut source_xs: Source = Source::new([0u8; 32]);
90 let mut source_xe: Source = Source::new([0u8; 32]);
91 let mut source_xa: Source = Source::new([0u8; 32]);
92
93 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
94 GLWECiphertextCompressed::encrypt_sk_scratch_space(module, n, basek, k_ct)
95 | GLWECiphertext::decrypt_scratch_space(module, n, basek, k_ct),
96 );
97
98 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
99 sk.fill_ternary_prob(0.5, &mut source_xs);
100 let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
101
102 module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_pt, &mut source_xa);
103
104 let seed_xa: [u8; 32] = [1u8; 32];
105
106 ct_compressed.encrypt_sk(
107 module,
108 &pt_want,
109 &sk_exec,
110 seed_xa,
111 &mut source_xe,
112 sigma,
113 scratch.borrow(),
114 );
115
116 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
117 ct.decompress(module, &ct_compressed);
118
119 ct.decrypt(module, &mut pt_have, &sk_exec, scratch.borrow());
120
121 pt_want.sub_inplace_ab(module, &pt_have);
122
123 let noise_have: f64 = module.vec_znx_std(basek, &pt_want.data, 0) * (ct.k() as f64).exp2();
124 let noise_want: f64 = sigma;
125
126 assert!(
127 noise_have <= noise_want + 0.2,
128 "{} <= {}",
129 noise_have,
130 noise_want + 0.2
131 );
132}
133
134pub(crate) fn test_encrypt_zero_sk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, sigma: f64, rank: usize)
135where
136 Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B>,
137 B: EncryptionTestScratchFamily<B>,
138{
139 let n = module.n();
140 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
141
142 let mut source_xs: Source = Source::new([0u8; 32]);
143 let mut source_xe: Source = Source::new([1u8; 32]);
144 let mut source_xa: Source = Source::new([0u8; 32]);
145
146 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
147 sk.fill_ternary_prob(0.5, &mut source_xs);
148 let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
149
150 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
151
152 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
153 GLWECiphertext::decrypt_scratch_space(module, n, basek, k_ct)
154 | GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, k_ct),
155 );
156
157 ct.encrypt_zero_sk(
158 module,
159 &sk_exec,
160 &mut source_xa,
161 &mut source_xe,
162 sigma,
163 scratch.borrow(),
164 );
165 ct.decrypt(module, &mut pt, &sk_exec, scratch.borrow());
166
167 assert!((sigma - module.vec_znx_std(basek, &pt.data, 0) * (k_ct as f64).exp2()) <= 0.2);
168}
169
170pub(crate) fn test_encrypt_pk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, k_pk: usize, sigma: f64, rank: usize)
171where
172 Module<B>: EncryptionTestModuleFamily<B>
173 + GLWEEncryptPkFamily<B>
174 + GLWEEncryptSkFamily<B>
175 + VecZnxDftAlloc<B>
176 + VecZnxFillUniform
177 + VecZnxSubABInplace,
178 B: EncryptionTestScratchFamily<B>,
179{
180 let n: usize = module.n();
181 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
182 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
183 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
184
185 let mut source_xs: Source = Source::new([0u8; 32]);
186 let mut source_xe: Source = Source::new([0u8; 32]);
187 let mut source_xa: Source = Source::new([0u8; 32]);
188 let mut source_xu: Source = Source::new([0u8; 32]);
189
190 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
191 sk.fill_ternary_prob(0.5, &mut source_xs);
192 let sk_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk);
193
194 let mut pk: GLWEPublicKey<Vec<u8>> = GLWEPublicKey::alloc(n, basek, k_pk, rank);
195 pk.generate_from_sk(module, &sk_exec, &mut source_xa, &mut source_xe, sigma);
196
197 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
198 GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, ct.k())
199 | GLWECiphertext::decrypt_scratch_space(module, n, basek, ct.k())
200 | GLWECiphertext::encrypt_pk_scratch_space(module, n, basek, pk.k()),
201 );
202
203 module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_ct, &mut source_xa);
204
205 let pk_exec: GLWEPublicKeyExec<Vec<u8>, B> = GLWEPublicKeyExec::from(module, &pk, scratch.borrow());
206
207 ct.encrypt_pk(
208 module,
209 &pt_want,
210 &pk_exec,
211 &mut source_xu,
212 &mut source_xe,
213 sigma,
214 scratch.borrow(),
215 );
216
217 ct.decrypt(module, &mut pt_have, &sk_exec, scratch.borrow());
218
219 pt_want.sub_inplace_ab(module, &pt_have);
220
221 let noise_have: f64 = module.vec_znx_std(basek, &pt_want.data, 0).log2();
222 let noise_want: f64 = ((((rank as f64) + 1.0) * n as f64 * 0.5 * sigma * sigma).sqrt()).log2() - (k_ct as f64);
223
224 assert!(
225 noise_have <= noise_want + 0.2,
226 "{} {}",
227 noise_have,
228 noise_want
229 );
230}