poulpy/core/src/tests/generics/trace.rs
core/src/tests/generics/trace.rsRaw
1use std::collections::HashMap;
2
3use backend::hal::{
4 api::{
5 ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, VecZnxAddInplace,
6 VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxBigAddInplace, VecZnxBigAddSmallInplace,
7 VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes,
8 VecZnxBigSubSmallBInplace, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftFromVecZnx, VecZnxDftToVecZnxBigConsume,
9 VecZnxFillUniform, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotateInplace,
10 VecZnxRshInplace, VecZnxSub, VecZnxSubABInplace, VecZnxSwithcDegree, VmpApply, VmpApplyAdd, VmpApplyTmpBytes,
11 VmpPMatAlloc, VmpPrepare, ZnxView, ZnxViewMut,
12 },
13 layouts::{Backend, Module, ScratchOwned},
14 oep::{
15 ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
16 TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
17 },
18};
19use sampling::source::Source;
20
21use crate::{
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, sigma: f64, rank: usize)
30where
31 Module<B>: VecZnxDftAllocBytes
32 + VecZnxAutomorphism
33 + VecZnxBigAutomorphismInplace<B>
34 + VecZnxBigSubSmallBInplace<B>
35 + VecZnxRshInplace
36 + VecZnxRotateInplace
37 + VecZnxBigNormalize<B>
38 + VecZnxDftFromVecZnx<B>
39 + SvpApplyInplace<B>
40 + VecZnxDftToVecZnxBigConsume<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, n, basek, ct.k())
90 | GLWECiphertext::decrypt_scratch_space(module, n, basek, ct.k())
91 | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, n, basek, k_autokey, rank)
92 | GLWECiphertext::trace_inplace_scratch_space(module, n, 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 sigma,
114 scratch.borrow(),
115 );
116
117 let mut auto_keys: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> = HashMap::new();
118 let gal_els: Vec<i64> = GLWECiphertext::trace_galois_elements(module);
119 let mut tmp: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_autokey, rows, digits, rank);
120 gal_els.iter().for_each(|gal_el| {
121 tmp.encrypt_sk(
122 module,
123 *gal_el,
124 &sk,
125 &mut source_xa,
126 &mut source_xe,
127 sigma,
128 scratch.borrow(),
129 );
130 let atk_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = tmp.prepare_alloc(module, scratch.borrow());
131 auto_keys.insert(*gal_el, atk_prepared);
132 });
133
134 ct.trace_inplace(module, 0, 5, &auto_keys, scratch.borrow());
135 ct.trace_inplace(module, 5, module.log_n(), &auto_keys, scratch.borrow());
136
137 (0..pt_want.size()).for_each(|i| pt_want.data.at_mut(0, i)[0] = pt_have.data.at(0, i)[0]);
138
139 ct.decrypt(module, &mut pt_have, &sk_dft, scratch.borrow());
140
141 module.vec_znx_sub_ab_inplace(&mut pt_want.data, 0, &pt_have.data, 0);
142 module.vec_znx_normalize_inplace(basek, &mut pt_want.data, 0, scratch.borrow());
143
144 let noise_have: f64 = pt_want.std().log2();
145
146 let mut noise_want: f64 = var_noise_gglwe_product(
147 n as f64,
148 basek,
149 0.5,
150 0.5,
151 1.0 / 12.0,
152 sigma * sigma,
153 0.0,
154 rank as f64,
155 k,
156 k_autokey,
157 );
158 noise_want += sigma * sigma * (-2.0 * (k) as f64).exp2();
159 noise_want += n as f64 * 1.0 / 12.0 * 0.5 * rank as f64 * (-2.0 * (k) as f64).exp2();
160 noise_want = noise_want.sqrt().log2();
161
162 assert!(
163 (noise_have - noise_want).abs() < 1.0,
164 "{} > {}",
165 noise_have,
166 noise_want
167 );
168}