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