poulpy/poulpy-core/src/tests/test_suite/packing.rs
poulpy-core/src/tests/test_suite/packing.rsRaw
1use std::collections::HashMap;
2
3use poulpy_hal::{
4 api::{
5 ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolBytesOf, SvpPrepare,
6 VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace,
7 VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAutomorphismInplace, VecZnxBigBytesOf, VecZnxBigNormalize,
8 VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftApply, VecZnxDftBytesOf,
9 VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace,
10 VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace,
11 VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, 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 AutomorphismKey, AutomorphismKeyLayout, GLWE, GLWELayout, GLWEPlaintext, GLWESecret,
25 prepared::{AutomorphismKeyPrepared, GLWESecretPrepared, PrepareAlloc},
26 },
27};
28
29pub fn test_glwe_packing<B>(module: &Module<B>)
30where
31 Module<B>: VecZnxDftBytesOf
32 + VecZnxAutomorphism
33 + VecZnxBigAutomorphismInplace<B>
34 + VecZnxBigSubSmallNegateInplace<B>
35 + VecZnxNegateInplace
36 + VecZnxRshInplace<B>
37 + VecZnxRotateInplace<B>
38 + VecZnxBigNormalize<B>
39 + VecZnxDftApply<B>
40 + VecZnxRotate
41 + SvpApplyDftToDftInplace<B>
42 + VecZnxIdftApplyConsume<B>
43 + VecZnxFillUniform
44 + VecZnxSubInplace
45 + VecZnxAddInplace
46 + VecZnxNormalizeInplace<B>
47 + VecZnxAddNormal
48 + VecZnxNormalize<B>
49 + VecZnxSub
50 + SvpPrepare<B>
51 + SvpPPolBytesOf
52 + SvpPPolAlloc<B>
53 + VecZnxBigBytesOf
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 + VecZnxSwitchRing
65 + VecZnxAutomorphismInplace<B>
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 base2k: usize = 18;
83 let k_ct: usize = 36;
84 let pt_k: usize = 18;
85 let rank: usize = 3;
86 let dsize: usize = 1;
87 let k_ksk: usize = k_ct + base2k * dsize;
88
89 let dnum: usize = k_ct.div_ceil(base2k * dsize);
90
91 let glwe_out_infos: GLWELayout = GLWELayout {
92 n: n.into(),
93 base2k: base2k.into(),
94 k: k_ct.into(),
95 rank: rank.into(),
96 };
97
98 let key_infos: AutomorphismKeyLayout = AutomorphismKeyLayout {
99 n: n.into(),
100 base2k: base2k.into(),
101 k: k_ksk.into(),
102 rank: rank.into(),
103 dsize: dsize.into(),
104 dnum: dnum.into(),
105 };
106
107 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
108 GLWE::encrypt_sk_tmp_bytes(module, &glwe_out_infos)
109 | AutomorphismKey::encrypt_sk_tmp_bytes(module, &key_infos)
110 | GLWEPacker::tmp_bytes(module, &glwe_out_infos, &key_infos),
111 );
112
113 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_out_infos);
114 sk.fill_ternary_prob(0.5, &mut source_xs);
115 let sk_dft: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
116
117 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_out_infos);
118 let mut data: Vec<i64> = vec![0i64; n];
119 data.iter_mut().enumerate().for_each(|(i, x)| {
120 *x = i as i64;
121 });
122
123 pt.encode_vec_i64(&data, pt_k.into());
124
125 let gal_els: Vec<i64> = GLWEPacker::galois_elements(module);
126
127 let mut auto_keys: HashMap<i64, AutomorphismKeyPrepared<Vec<u8>, B>> = HashMap::new();
128 let mut tmp: AutomorphismKey<Vec<u8>> = AutomorphismKey::alloc_from_infos(&key_infos);
129 gal_els.iter().for_each(|gal_el| {
130 tmp.encrypt_sk(
131 module,
132 *gal_el,
133 &sk,
134 &mut source_xa,
135 &mut source_xe,
136 scratch.borrow(),
137 );
138 let atk_prepared: AutomorphismKeyPrepared<Vec<u8>, B> = tmp.prepare_alloc(module, scratch.borrow());
139 auto_keys.insert(*gal_el, atk_prepared);
140 });
141
142 let log_batch: usize = 0;
143
144 let mut packer: GLWEPacker = GLWEPacker::new(&glwe_out_infos, log_batch);
145
146 let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos);
147
148 ct.encrypt_sk(
149 module,
150 &pt,
151 &sk_dft,
152 &mut source_xa,
153 &mut source_xe,
154 scratch.borrow(),
155 );
156
157 let log_n: usize = module.log_n();
158
159 (0..n >> log_batch).for_each(|i| {
160 ct.encrypt_sk(
161 module,
162 &pt,
163 &sk_dft,
164 &mut source_xa,
165 &mut source_xe,
166 scratch.borrow(),
167 );
168
169 pt.rotate_inplace(module, -(1 << log_batch), scratch.borrow()); // X^-batch * pt
170
171 if reverse_bits_msb(i, log_n as u32).is_multiple_of(5) {
172 packer.add(module, Some(&ct), &auto_keys, scratch.borrow());
173 } else {
174 packer.add(module, None::<&GLWE<Vec<u8>>>, &auto_keys, scratch.borrow())
175 }
176 });
177
178 let mut res: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos);
179 packer.flush(module, &mut res);
180
181 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_out_infos);
182 let mut data: Vec<i64> = vec![0i64; n];
183 data.iter_mut().enumerate().for_each(|(i, x)| {
184 if i.is_multiple_of(5) {
185 *x = reverse_bits_msb(i, log_n as u32) as i64;
186 }
187 });
188
189 pt_want.encode_vec_i64(&data, pt_k.into());
190
191 res.decrypt(module, &mut pt, &sk_dft, scratch.borrow());
192
193 pt.sub_inplace_ab(module, &pt_want);
194
195 let noise_have: f64 = pt.std().log2();
196
197 assert!(
198 noise_have < -((k_ct - base2k) as f64),
199 "noise: {noise_have}"
200 );
201}
202
203#[inline(always)]
204fn reverse_bits_msb(x: usize, n: u32) -> usize {
205 x.reverse_bits() >> (usize::BITS - n)
206}