poulpy/poulpy-core/src/tests/generics/packing.rs
poulpy-core/src/tests/generics/packing.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, VecZnxAutomorphismInplace,
7 VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, VecZnxBigNormalize,
8 VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallBInplace, VecZnxCopy, VecZnxDftAllocBytes, VecZnxFillUniform,
9 VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace,
10 VecZnxRshInplace, VecZnxSub, VecZnxSubABInplace, VecZnxSwithcDegree, VmpApplyDftToDft, VmpApplyDftToDftAdd,
11 VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
12 },
13 layouts::{Backend, Module, ScratchOwned},
14 oep::{
15 ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
16 TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
17 },
18 source::Source,
19};
20
21use crate::{
22 GLWEOperations, GLWEPacker,
23 layouts::{
24 GGLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret,
25 prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, PrepareAlloc},
26 },
27};
28
29pub fn test_glwe_packing<B>(module: &Module<B>)
30where
31 Module<B>: VecZnxDftAllocBytes
32 + VecZnxAutomorphism
33 + VecZnxBigAutomorphismInplace<B>
34 + VecZnxBigSubSmallBInplace<B>
35 + VecZnxNegateInplace
36 + VecZnxRshInplace
37 + VecZnxRotateInplace
38 + VecZnxBigNormalize<B>
39 + DFT<B>
40 + VecZnxRotate
41 + SvpApplyInplace<B>
42 + IDFTConsume<B>
43 + VecZnxFillUniform
44 + VecZnxSubABInplace
45 + VecZnxAddInplace
46 + VecZnxNormalizeInplace<B>
47 + VecZnxAddNormal
48 + VecZnxNormalize<B>
49 + VecZnxSub
50 + SvpPrepare<B>
51 + SvpPPolAllocBytes
52 + SvpPPolAlloc<B>
53 + VecZnxBigAllocBytes
54 + VecZnxBigAddInplace<B>
55 + VecZnxBigAddSmallInplace<B>
56 + VecZnxNormalizeTmpBytes
57 + VecZnxAddScalarInplace
58 + VmpPMatAlloc<B>
59 + VmpPrepare<B>
60 + VmpApplyDftToDftTmpBytes
61 + VmpApplyDftToDft<B>
62 + VmpApplyDftToDftAdd<B>
63 + VecZnxBigNormalizeTmpBytes
64 + VecZnxSwithcDegree
65 + VecZnxAutomorphismInplace
66 + VecZnxCopy,
67 B: Backend
68 + TakeVecZnxDftImpl<B>
69 + TakeVecZnxBigImpl<B>
70 + TakeSvpPPolImpl<B>
71 + ScratchOwnedAllocImpl<B>
72 + ScratchOwnedBorrowImpl<B>
73 + ScratchAvailableImpl<B>
74 + TakeScalarZnxImpl<B>
75 + TakeVecZnxImpl<B>,
76{
77 let mut source_xs: Source = Source::new([0u8; 32]);
78 let mut source_xe: Source = Source::new([0u8; 32]);
79 let mut source_xa: Source = Source::new([0u8; 32]);
80
81 let n: usize = module.n();
82 let basek: usize = 18;
83 let k_ct: usize = 36;
84 let pt_k: usize = 18;
85 let rank: usize = 3;
86 let digits: usize = 1;
87 let k_ksk: usize = k_ct + basek * digits;
88
89 let rows: usize = k_ct.div_ceil(basek * digits);
90
91 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
92 GLWECiphertext::encrypt_sk_scratch_space(module, basek, k_ct)
93 | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank)
94 | GLWEPacker::scratch_space(module, basek, k_ct, k_ksk, digits, rank),
95 );
96
97 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
98 sk.fill_ternary_prob(0.5, &mut source_xs);
99 let sk_dft: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
100
101 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
102 let mut data: Vec<i64> = vec![0i64; n];
103 data.iter_mut().enumerate().for_each(|(i, x)| {
104 *x = i as i64;
105 });
106
107 pt.encode_vec_i64(&data, pt_k);
108
109 let gal_els: Vec<i64> = GLWEPacker::galois_elements(module);
110
111 let mut auto_keys: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> = HashMap::new();
112 let mut tmp: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_ksk, rows, digits, rank);
113 gal_els.iter().for_each(|gal_el| {
114 tmp.encrypt_sk(
115 module,
116 *gal_el,
117 &sk,
118 &mut source_xa,
119 &mut source_xe,
120 scratch.borrow(),
121 );
122 let atk_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = tmp.prepare_alloc(module, scratch.borrow());
123 auto_keys.insert(*gal_el, atk_prepared);
124 });
125
126 let log_batch: usize = 0;
127
128 let mut packer: GLWEPacker = GLWEPacker::new(n, log_batch, basek, k_ct, rank);
129
130 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
131
132 ct.encrypt_sk(
133 module,
134 &pt,
135 &sk_dft,
136 &mut source_xa,
137 &mut source_xe,
138 scratch.borrow(),
139 );
140
141 let log_n: usize = module.log_n();
142
143 (0..n >> log_batch).for_each(|i| {
144 ct.encrypt_sk(
145 module,
146 &pt,
147 &sk_dft,
148 &mut source_xa,
149 &mut source_xe,
150 scratch.borrow(),
151 );
152
153 pt.rotate_inplace(module, -(1 << log_batch)); // X^-batch * pt
154
155 if reverse_bits_msb(i, log_n as u32).is_multiple_of(5) {
156 packer.add(module, Some(&ct), &auto_keys, scratch.borrow());
157 } else {
158 packer.add(
159 module,
160 None::<&GLWECiphertext<Vec<u8>>>,
161 &auto_keys,
162 scratch.borrow(),
163 )
164 }
165 });
166
167 let mut res = GLWECiphertext::alloc(n, basek, k_ct, rank);
168 packer.flush(module, &mut res);
169
170 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
171 let mut data: Vec<i64> = vec![0i64; n];
172 data.iter_mut().enumerate().for_each(|(i, x)| {
173 if i.is_multiple_of(5) {
174 *x = reverse_bits_msb(i, log_n as u32) as i64;
175 }
176 });
177
178 pt_want.encode_vec_i64(&data, pt_k);
179
180 res.decrypt(module, &mut pt, &sk_dft, scratch.borrow());
181
182 pt.sub_inplace_ab(module, &pt_want);
183
184 let noise_have: f64 = pt.std().log2();
185 // println!("noise_have: {}", noise_have);
186 assert!(
187 noise_have < -((k_ct - basek) as f64),
188 "noise: {}",
189 noise_have
190 );
191}
192
193#[inline(always)]
194fn reverse_bits_msb(x: usize, n: u32) -> usize {
195 x.reverse_bits() >> (usize::BITS - n)
196}