arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/circuit_bootstrapping/test_fft64/circuit_bootstrapping.rs
core/src/circuit_bootstrapping/test_fft64/circuit_bootstrapping.rsRaw
  1use std::time::Instant;
  2
  3use backend::{
  4    hal::{
  5        api::{
  6            ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism,
  7            VecZnxEncodeCoeffsi64, VecZnxFillUniform, VecZnxNormalizeInplace, VecZnxRotateInplace, VecZnxStd, VecZnxSwithcDegree,
  8            ZnxView, ZnxViewMut,
  9        },
 10        layouts::{Backend, Module, ScalarZnx, ScratchOwned},
 11        oep::{
 12            ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeMatZnxImpl, TakeScalarZnxImpl,
 13            TakeSvpPPolImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl,
 14        },
 15    },
 16    implementation::cpu_spqlios::FFT64,
 17};
 18use sampling::source::Source;
 19
 20use crate::{
 21    AutomorphismKeyEncryptSkFamily, BlindRotationKeyCGGIExecLayoutFamily, GGSWAssertNoiseFamily, GGSWCiphertext,
 22    GGSWCiphertextExec, GGSWEncryptSkFamily, GLWECiphertext, GLWEDecryptFamily, GLWEPlaintext, GLWESecret, GLWESecretExec,
 23    GLWESecretFamily, GLWETensorKeyEncryptSkFamily, LWECiphertext, LWESecret,
 24    circuit_bootstrapping::circuit_bootstrapping::{
 25        CGGICircuitBootstrapFamily, CircuitBootstrappingKeyCGGI, CircuitBootstrappingKeyCGGIExec,
 26        circuit_bootstrap_to_constant_cggi, circuit_bootstrap_to_exponent_cggi,
 27    },
 28    lwe::LWEPlaintext,
 29};
 30
 31#[test]
 32fn test_to_exponent() {
 33    let module: Module<FFT64> = Module::<FFT64>::new(256);
 34    to_exponent(&module);
 35}
 36
 37fn to_exponent<B: Backend>(module: &Module<B>)
 38where
 39    Module<B>: GLWESecretFamily<B>
 40        + VecZnxEncodeCoeffsi64
 41        + VecZnxFillUniform
 42        + VecZnxAddNormal
 43        + VecZnxNormalizeInplace<B>
 44        + GLWESecretFamily<B>
 45        + GGSWEncryptSkFamily<B>
 46        + VecZnxAddScalarInplace
 47        + AutomorphismKeyEncryptSkFamily<B>
 48        + VecZnxAutomorphism
 49        + VecZnxSwithcDegree
 50        + GLWETensorKeyEncryptSkFamily<B>
 51        + BlindRotationKeyCGGIExecLayoutFamily<B>
 52        + CGGICircuitBootstrapFamily<B>
 53        + GLWEDecryptFamily<B>
 54        + GGSWAssertNoiseFamily<B>
 55        + VecZnxStd,
 56    B: ScratchOwnedAllocImpl<B>
 57        + ScratchOwnedBorrowImpl<B>
 58        + TakeVecZnxDftImpl<B>
 59        + ScratchAvailableImpl<B>
 60        + TakeVecZnxImpl<B>
 61        + TakeScalarZnxImpl<B>
 62        + TakeSvpPPolImpl<B>
 63        + TakeVecZnxBigImpl<B>
 64        + TakeVecZnxDftSliceImpl<B>
 65        + TakeMatZnxImpl<B>
 66        + TakeVecZnxSliceImpl<B>,
 67{
 68    let n: usize = module.n();
 69    let basek: usize = 17;
 70    let extension_factor: usize = 1;
 71    let rank: usize = 1;
 72    let sigma: f64 = 3.2;
 73
 74    let n_lwe: usize = 77;
 75    let k_lwe_pt: usize = 4;
 76    let k_lwe_ct: usize = 22;
 77    let block_size: usize = 7;
 78
 79    let k_brk: usize = 5 * basek;
 80    let rows_brk: usize = 4;
 81
 82    let k_trace: usize = 5 * basek;
 83    let rows_trace: usize = 4;
 84
 85    let k_tsk: usize = 5 * basek;
 86    let rows_tsk: usize = 4;
 87
 88    let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(1 << 23);
 89
 90    let mut source_xs: Source = Source::new([1u8; 32]);
 91    let mut source_xa: Source = Source::new([1u8; 32]);
 92    let mut source_xe: Source = Source::new([1u8; 32]);
 93
 94    let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
 95    sk_lwe.fill_binary_block(block_size, &mut source_xs);
 96
 97    let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
 98    sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
 99
100    let sk_glwe_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_glwe);
101
102    let data: i64 = 1;
103
104    let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe_pt);
105    module.encode_coeff_i64(basek, &mut pt_lwe.data, 0, k_lwe_pt + 2, 0, data, k_lwe_pt);
106
107    println!("pt_lwe: {}", pt_lwe.data);
108
109    let mut ct_lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe, basek, k_lwe_ct);
110    ct_lwe.encrypt_sk(
111        module,
112        &pt_lwe,
113        &sk_lwe,
114        &mut source_xa,
115        &mut source_xe,
116        sigma,
117    );
118
119    let now: Instant = Instant::now();
120    let cbt_key: CircuitBootstrappingKeyCGGI<Vec<u8>> = CircuitBootstrappingKeyCGGI::generate(
121        module,
122        basek,
123        &sk_lwe,
124        &sk_glwe,
125        k_brk,
126        rows_brk,
127        k_trace,
128        rows_trace,
129        k_tsk,
130        rows_tsk,
131        &mut source_xa,
132        &mut source_xe,
133        sigma,
134        scratch.borrow(),
135    );
136    println!("CBT-KGEN: {} ms", now.elapsed().as_millis());
137
138    let k_ggsw_res: usize = 4 * basek;
139    let rows_ggsw_res: usize = 2;
140
141    let mut res: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw_res, rows_ggsw_res, 1, rank);
142
143    let log_gap_out = 1;
144
145    let cbt_exec: CircuitBootstrappingKeyCGGIExec<Vec<u8>, B> =
146        CircuitBootstrappingKeyCGGIExec::from(module, &cbt_key, scratch.borrow());
147
148    let now: Instant = Instant::now();
149    circuit_bootstrap_to_exponent_cggi(
150        module,
151        log_gap_out,
152        &mut res,
153        &ct_lwe,
154        k_lwe_pt,
155        extension_factor,
156        &cbt_exec,
157        scratch.borrow(),
158    );
159    println!("CBT: {} ms", now.elapsed().as_millis());
160
161    // X^{data * 2^log_gap_out}
162    let mut pt_ggsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
163    pt_ggsw.at_mut(0, 0)[0] = 1;
164    module.vec_znx_rotate_inplace(data * (1 << log_gap_out), &mut pt_ggsw.as_vec_znx_mut(), 0);
165
166    res.print_noise(module, &sk_glwe_exec, &pt_ggsw);
167
168    let k_glwe: usize = k_ggsw_res;
169
170    let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_glwe, rank);
171    let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, basek);
172    pt_glwe.data.at_mut(0, 0)[0] = 1 << (basek - 2);
173
174    ct_glwe.encrypt_sk(
175        module,
176        &pt_glwe,
177        &sk_glwe_exec,
178        &mut source_xa,
179        &mut source_xe,
180        sigma,
181        scratch.borrow(),
182    );
183
184    let res_exec: GGSWCiphertextExec<Vec<u8>, B> = GGSWCiphertextExec::from(module, &res, scratch.borrow());
185
186    ct_glwe.external_product_inplace(module, &res_exec, scratch.borrow());
187
188    let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_glwe);
189    ct_glwe.decrypt(module, &mut pt_res, &sk_glwe_exec, scratch.borrow());
190
191    // Parameters are set such that the first limb should be noiseless.
192    let mut pt_want: Vec<i64> = vec![0i64; module.n()];
193    pt_want[data as usize * (1 << log_gap_out)] = pt_glwe.data.at(0, 0)[0];
194    assert_eq!(pt_res.data.at(0, 0), pt_want);
195}
196
197#[test]
198fn test_to_constant() {
199    let module: Module<FFT64> = Module::<FFT64>::new(256);
200    to_constant(&module);
201}
202
203fn to_constant<B: Backend>(module: &Module<B>)
204where
205    Module<B>: GLWESecretFamily<B>
206        + VecZnxEncodeCoeffsi64
207        + VecZnxFillUniform
208        + VecZnxAddNormal
209        + VecZnxNormalizeInplace<B>
210        + GLWESecretFamily<B>
211        + GGSWEncryptSkFamily<B>
212        + VecZnxAddScalarInplace
213        + AutomorphismKeyEncryptSkFamily<B>
214        + VecZnxAutomorphism
215        + VecZnxSwithcDegree
216        + GLWETensorKeyEncryptSkFamily<B>
217        + BlindRotationKeyCGGIExecLayoutFamily<B>
218        + CGGICircuitBootstrapFamily<B>
219        + GLWEDecryptFamily<B>
220        + GGSWAssertNoiseFamily<B>
221        + VecZnxStd,
222    B: ScratchOwnedAllocImpl<B>
223        + ScratchOwnedBorrowImpl<B>
224        + TakeVecZnxDftImpl<B>
225        + ScratchAvailableImpl<B>
226        + TakeVecZnxImpl<B>
227        + TakeScalarZnxImpl<B>
228        + TakeSvpPPolImpl<B>
229        + TakeVecZnxBigImpl<B>
230        + TakeVecZnxDftSliceImpl<B>
231        + TakeMatZnxImpl<B>
232        + TakeVecZnxSliceImpl<B>,
233{
234    let n = module.n();
235    let basek: usize = 14;
236    let extension_factor: usize = 1;
237    let rank: usize = 2;
238    let sigma: f64 = 3.2;
239
240    let n_lwe: usize = 77;
241    let k_lwe_pt: usize = 1;
242    let k_lwe_ct: usize = 13;
243    let block_size: usize = 7;
244
245    let k_brk: usize = 5 * basek;
246    let rows_brk: usize = 3;
247
248    let k_trace: usize = 5 * basek;
249    let rows_trace: usize = 4;
250
251    let k_tsk: usize = 5 * basek;
252    let rows_tsk: usize = 4;
253
254    let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(1 << 23);
255
256    let mut source_xs: Source = Source::new([1u8; 32]);
257    let mut source_xa: Source = Source::new([1u8; 32]);
258    let mut source_xe: Source = Source::new([1u8; 32]);
259
260    let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
261    sk_lwe.fill_binary_block(block_size, &mut source_xs);
262
263    let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
264    sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
265
266    let sk_glwe_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_glwe);
267
268    let data: i64 = 1;
269
270    let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe_pt);
271    module.encode_coeff_i64(basek, &mut pt_lwe.data, 0, k_lwe_pt + 2, 0, data, k_lwe_pt);
272
273    println!("pt_lwe: {}", pt_lwe.data);
274
275    let mut ct_lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe, basek, k_lwe_ct);
276    ct_lwe.encrypt_sk(
277        module,
278        &pt_lwe,
279        &sk_lwe,
280        &mut source_xa,
281        &mut source_xe,
282        sigma,
283    );
284
285    let now: Instant = Instant::now();
286    let cbt_key: CircuitBootstrappingKeyCGGI<Vec<u8>> = CircuitBootstrappingKeyCGGI::generate(
287        module,
288        basek,
289        &sk_lwe,
290        &sk_glwe,
291        k_brk,
292        rows_brk,
293        k_trace,
294        rows_trace,
295        k_tsk,
296        rows_tsk,
297        &mut source_xa,
298        &mut source_xe,
299        sigma,
300        scratch.borrow(),
301    );
302    println!("CBT-KGEN: {} ms", now.elapsed().as_millis());
303
304    let k_ggsw_res: usize = 4 * basek;
305    let rows_ggsw_res: usize = 3;
306
307    let mut res: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw_res, rows_ggsw_res, 1, rank);
308
309    let cbt_exec: CircuitBootstrappingKeyCGGIExec<Vec<u8>, B> =
310        CircuitBootstrappingKeyCGGIExec::from(module, &cbt_key, scratch.borrow());
311
312    let now: Instant = Instant::now();
313    circuit_bootstrap_to_constant_cggi(
314        module,
315        &mut res,
316        &ct_lwe,
317        k_lwe_pt,
318        extension_factor,
319        &cbt_exec,
320        scratch.borrow(),
321    );
322    println!("CBT: {} ms", now.elapsed().as_millis());
323
324    // X^{data * 2^log_gap_out}
325    let mut pt_ggsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
326    pt_ggsw.at_mut(0, 0)[0] = data;
327
328    res.print_noise(module, &sk_glwe_exec, &pt_ggsw);
329
330    let k_glwe: usize = k_ggsw_res;
331
332    let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_glwe, rank);
333    let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, basek);
334    pt_glwe.data.at_mut(0, 0)[0] = 1 << (basek - k_lwe_pt - 1);
335
336    ct_glwe.encrypt_sk(
337        module,
338        &pt_glwe,
339        &sk_glwe_exec,
340        &mut source_xa,
341        &mut source_xe,
342        sigma,
343        scratch.borrow(),
344    );
345
346    let res_exec: GGSWCiphertextExec<Vec<u8>, B> = GGSWCiphertextExec::from(module, &res, scratch.borrow());
347
348    ct_glwe.external_product_inplace(module, &res_exec, scratch.borrow());
349
350    let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_glwe);
351    ct_glwe.decrypt(module, &mut pt_res, &sk_glwe_exec, scratch.borrow());
352
353    // Parameters are set such that the first limb should be noiseless.
354    let mut pt_want: Vec<i64> = vec![0i64; module.n()];
355    pt_want[0] = pt_glwe.data.at(0, 0)[0] * data;
356    assert_eq!(pt_res.data.at(0, 0), pt_want);
357}