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: Backend>(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: TakeVecZnxDftImpl<B>
65 + TakeVecZnxBigImpl<B>
66 + TakeSvpPPolImpl<B>
67 + ScratchOwnedAllocImpl<B>
68 + ScratchOwnedBorrowImpl<B>
69 + ScratchAvailableImpl<B>
70 + TakeScalarZnxImpl<B>
71 + TakeVecZnxImpl<B>,
72{
73 let n: usize = module.n();
74 let k_autokey: usize = k + basek;
75
76 let digits: usize = 1;
77 let rows: usize = k.div_ceil(basek * digits);
78
79 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k, rank);
80 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k);
81 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k);
82
83 let mut source_xs: Source = Source::new([0u8; 32]);
84 let mut source_xe: Source = Source::new([0u8; 32]);
85 let mut source_xa: Source = Source::new([0u8; 32]);
86
87 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
88 GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, ct.k())
89 | GLWECiphertext::decrypt_scratch_space(module, n, basek, ct.k())
90 | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, n, basek, k_autokey, rank)
91 | GLWECiphertext::trace_inplace_scratch_space(module, n, basek, ct.k(), k_autokey, digits, rank),
92 );
93
94 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
95 sk.fill_ternary_prob(0.5, &mut source_xs);
96 let sk_dft: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
97
98 let mut data_want: Vec<i64> = vec![0i64; n];
99
100 data_want
101 .iter_mut()
102 .for_each(|x| *x = source_xa.next_i64() & 0xFF);
103
104 module.vec_znx_fill_uniform(basek, &mut pt_have.data, 0, k, &mut source_xa);
105
106 ct.encrypt_sk(
107 module,
108 &pt_have,
109 &sk_dft,
110 &mut source_xa,
111 &mut source_xe,
112 sigma,
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 sigma,
127 scratch.borrow(),
128 );
129 let atk_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = tmp.prepare_alloc(module, scratch.borrow());
130 auto_keys.insert(*gal_el, atk_prepared);
131 });
132
133 ct.trace_inplace(module, 0, 5, &auto_keys, scratch.borrow());
134 ct.trace_inplace(module, 5, module.log_n(), &auto_keys, scratch.borrow());
135
136 (0..pt_want.size()).for_each(|i| pt_want.data.at_mut(0, i)[0] = pt_have.data.at(0, i)[0]);
137
138 ct.decrypt(module, &mut pt_have, &sk_dft, scratch.borrow());
139
140 module.vec_znx_sub_ab_inplace(&mut pt_want.data, 0, &pt_have.data, 0);
141 module.vec_znx_normalize_inplace(basek, &mut pt_want.data, 0, scratch.borrow());
142
143 let noise_have: f64 = pt_want.std().log2();
144
145 let mut noise_want: f64 = var_noise_gglwe_product(
146 n as f64,
147 basek,
148 0.5,
149 0.5,
150 1.0 / 12.0,
151 sigma * sigma,
152 0.0,
153 rank as f64,
154 k,
155 k_autokey,
156 );
157 noise_want += sigma * sigma * (-2.0 * (k) as f64).exp2();
158 noise_want += n as f64 * 1.0 / 12.0 * 0.5 * rank as f64 * (-2.0 * (k) as f64).exp2();
159 noise_want = noise_want.sqrt().log2();
160
161 assert!(
162 (noise_have - noise_want).abs() < 1.0,
163 "{} > {}",
164 noise_have,
165 noise_want
166 );
167}