poulpy/poulpy-core/src/tests/generics/trace.rs
poulpy-core/src/tests/generics/trace.rsRaw
1use std::collections::HashMap;
2
3use poulpy_hal::{
4 api::{
5 DFT, IDFTConsume, ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare,
6 VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxBigAddInplace,
7 VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, VecZnxBigNormalize,
8 VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallBInplace, VecZnxCopy, VecZnxDftAllocBytes, VecZnxFillUniform,
9 VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub,
10 VecZnxSubABInplace, VecZnxSwithcDegree, VmpApply, VmpApplyAdd, VmpApplyTmpBytes, VmpPMatAlloc, VmpPrepare,
11 },
12 layouts::{Backend, Module, ScratchOwned, ZnxView, ZnxViewMut},
13 oep::{
14 ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
15 TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
16 },
17 source::Source,
18};
19
20use crate::{
21 encryption::SIGMA,
22 layouts::{
23 GGLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos,
24 prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, PrepareAlloc},
25 },
26 noise::var_noise_gglwe_product,
27};
28
29pub fn test_glwe_trace_inplace<B>(module: &Module<B>, basek: usize, k: usize, rank: usize)
30where
31 Module<B>: VecZnxDftAllocBytes
32 + VecZnxAutomorphism
33 + VecZnxBigAutomorphismInplace<B>
34 + VecZnxBigSubSmallBInplace<B>
35 + VecZnxRshInplace
36 + VecZnxRotateInplace
37 + VecZnxBigNormalize<B>
38 + DFT<B>
39 + SvpApplyInplace<B>
40 + IDFTConsume<B>
41 + VecZnxFillUniform
42 + VecZnxSubABInplace
43 + VecZnxAddInplace
44 + VecZnxNormalizeInplace<B>
45 + VecZnxAddNormal
46 + VecZnxNormalize<B>
47 + VecZnxSub
48 + SvpPrepare<B>
49 + SvpPPolAllocBytes
50 + SvpPPolAlloc<B>
51 + VecZnxBigAllocBytes
52 + VecZnxBigAddInplace<B>
53 + VecZnxBigAddSmallInplace<B>
54 + VecZnxNormalizeTmpBytes
55 + VecZnxAddScalarInplace
56 + VmpPMatAlloc<B>
57 + VmpPrepare<B>
58 + VmpApplyTmpBytes
59 + VmpApply<B>
60 + VmpApplyAdd<B>
61 + VecZnxBigNormalizeTmpBytes
62 + VecZnxSwithcDegree
63 + VecZnxCopy,
64 B: Backend
65 + TakeVecZnxDftImpl<B>
66 + TakeVecZnxBigImpl<B>
67 + TakeSvpPPolImpl<B>
68 + ScratchOwnedAllocImpl<B>
69 + ScratchOwnedBorrowImpl<B>
70 + ScratchAvailableImpl<B>
71 + TakeScalarZnxImpl<B>
72 + TakeVecZnxImpl<B>,
73{
74 let n: usize = module.n();
75 let k_autokey: usize = k + basek;
76
77 let digits: usize = 1;
78 let rows: usize = k.div_ceil(basek * digits);
79
80 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k, rank);
81 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k);
82 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k);
83
84 let mut source_xs: Source = Source::new([0u8; 32]);
85 let mut source_xe: Source = Source::new([0u8; 32]);
86 let mut source_xa: Source = Source::new([0u8; 32]);
87
88 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
89 GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct.k())
90 | GLWECiphertext::decrypt_scratch_space(module, basek, ct.k())
91 | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, basek, k_autokey, rank)
92 | GLWECiphertext::trace_inplace_scratch_space(module, basek, ct.k(), k_autokey, digits, rank),
93 );
94
95 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
96 sk.fill_ternary_prob(0.5, &mut source_xs);
97 let sk_dft: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
98
99 let mut data_want: Vec<i64> = vec![0i64; n];
100
101 data_want
102 .iter_mut()
103 .for_each(|x| *x = source_xa.next_i64() & 0xFF);
104
105 module.vec_znx_fill_uniform(basek, &mut pt_have.data, 0, k, &mut source_xa);
106
107 ct.encrypt_sk(
108 module,
109 &pt_have,
110 &sk_dft,
111 &mut source_xa,
112 &mut source_xe,
113 scratch.borrow(),
114 );
115
116 let mut auto_keys: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> = HashMap::new();
117 let gal_els: Vec<i64> = GLWECiphertext::trace_galois_elements(module);
118 let mut tmp: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_autokey, rows, digits, rank);
119 gal_els.iter().for_each(|gal_el| {
120 tmp.encrypt_sk(
121 module,
122 *gal_el,
123 &sk,
124 &mut source_xa,
125 &mut source_xe,
126 scratch.borrow(),
127 );
128 let atk_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = tmp.prepare_alloc(module, scratch.borrow());
129 auto_keys.insert(*gal_el, atk_prepared);
130 });
131
132 ct.trace_inplace(module, 0, 5, &auto_keys, scratch.borrow());
133 ct.trace_inplace(module, 5, module.log_n(), &auto_keys, scratch.borrow());
134
135 (0..pt_want.size()).for_each(|i| pt_want.data.at_mut(0, i)[0] = pt_have.data.at(0, i)[0]);
136
137 ct.decrypt(module, &mut pt_have, &sk_dft, scratch.borrow());
138
139 module.vec_znx_sub_ab_inplace(&mut pt_want.data, 0, &pt_have.data, 0);
140 module.vec_znx_normalize_inplace(basek, &mut pt_want.data, 0, scratch.borrow());
141
142 let noise_have: f64 = pt_want.std().log2();
143
144 let mut noise_want: f64 = var_noise_gglwe_product(
145 n as f64,
146 basek,
147 0.5,
148 0.5,
149 1.0 / 12.0,
150 SIGMA * SIGMA,
151 0.0,
152 rank as f64,
153 k,
154 k_autokey,
155 );
156 noise_want += SIGMA * SIGMA * (-2.0 * (k) as f64).exp2();
157 noise_want += n as f64 * 1.0 / 12.0 * 0.5 * rank as f64 * (-2.0 * (k) as f64).exp2();
158 noise_want = noise_want.sqrt().log2();
159
160 assert!(
161 (noise_have - noise_want).abs() < 1.0,
162 "{} > {}",
163 noise_have,
164 noise_want
165 );
166}