poulpy/poulpy-core/benches/keyswitch_glwe_fft64.rs
poulpy-core/benches/keyswitch_glwe_fft64.rsRaw
1use poulpy_core::layouts::{
2 Base2K, Degree, Dnum, Dsize, GLWE, GLWEAutomorphismKey, GLWEAutomorphismKeyLayout, GLWELayout, GLWESecret, GLWESwitchingKey,
3 GLWESwitchingKeyLayout, GLWESwitchingKeyPrepared, Rank, TorusPrecision,
4 prepared::{GLWEAutomorphismKeyPrepared, GLWESecretPrepared},
5};
6use std::{hint::black_box, time::Duration};
7
8use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
9
10#[cfg(all(feature = "enable-avx", target_arch = "x86_64"))]
11pub use poulpy_cpu_avx::FFT64Avx as BackendImpl;
12
13#[cfg(not(all(feature = "enable-avx", target_arch = "x86_64")))]
14pub use poulpy_cpu_ref::FFT64Ref as BackendImpl;
15
16use poulpy_hal::{
17 api::{ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow},
18 layouts::{Module, ScratchOwned},
19 source::Source,
20};
21
22fn bench_keyswitch_glwe_fft64(c: &mut Criterion) {
23 let mut group = c.benchmark_group("keyswitch_glwe_fft64");
24
25 struct Params {
26 log_n: usize,
27 base2k: Base2K,
28 k_ct_in: TorusPrecision,
29 k_ct_out: TorusPrecision,
30 k_ksk: TorusPrecision,
31 dsize: Dsize,
32 rank: Rank,
33 }
34
35 fn runner(p: Params) -> impl FnMut() {
36 let module: Module<BackendImpl> = Module::<BackendImpl>::new(1 << p.log_n);
37
38 let n: Degree = Degree(module.n() as u32);
39 let base2k: Base2K = p.base2k;
40 let k_glwe_in: TorusPrecision = p.k_ct_in;
41 let k_glwe_out: TorusPrecision = p.k_ct_out;
42 let k_gglwe: TorusPrecision = p.k_ksk;
43 let rank: Rank = p.rank;
44 let dsize: Dsize = p.dsize;
45
46 let dnum: Dnum = p.k_ct_in.div_ceil(p.base2k.0 * dsize.0).into();
47
48 let gglwe_atk_layout: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout {
49 n,
50 base2k,
51 k: k_gglwe,
52 dnum,
53 rank,
54 dsize,
55 };
56
57 let glwe_in_layout: GLWELayout = GLWELayout {
58 n,
59 base2k,
60 k: k_glwe_in,
61 rank,
62 };
63
64 let glwe_out_layout: GLWELayout = GLWELayout {
65 n,
66 base2k,
67 k: k_glwe_out,
68 rank,
69 };
70
71 let mut ksk: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&gglwe_atk_layout);
72 let mut ct_in: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_in_layout);
73 let mut ct_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_layout);
74
75 let mut scratch: ScratchOwned<BackendImpl> = ScratchOwned::alloc(
76 GLWESwitchingKey::encrypt_sk_tmp_bytes(&module, &gglwe_atk_layout)
77 | GLWE::encrypt_sk_tmp_bytes(&module, &glwe_in_layout)
78 | GLWE::keyswitch_tmp_bytes(&module, &glwe_out_layout, &glwe_in_layout, &gglwe_atk_layout),
79 );
80
81 let mut source_xs: Source = Source::new([0u8; 32]);
82 let mut source_xe: Source = Source::new([0u8; 32]);
83 let mut source_xa: Source = Source::new([0u8; 32]);
84
85 let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_in_layout);
86 sk_in.fill_ternary_prob(0.5, &mut source_xs);
87
88 let mut sk_in_dft: GLWESecretPrepared<Vec<u8>, BackendImpl> = GLWESecretPrepared::alloc(&module, rank);
89 sk_in_dft.prepare(&module, &sk_in);
90
91 ksk.encrypt_sk(&module, -1, &sk_in, &mut source_xa, &mut source_xe, scratch.borrow());
92
93 ct_in.encrypt_zero_sk(&module, &sk_in_dft, &mut source_xa, &mut source_xe, scratch.borrow());
94
95 let mut ksk_prepared: GLWEAutomorphismKeyPrepared<Vec<u8>, _> =
96 GLWEAutomorphismKeyPrepared::alloc_from_infos(&module, &ksk);
97 ksk_prepared.prepare(&module, &ksk, scratch.borrow());
98
99 move || {
100 ct_out.automorphism(&module, &ct_in, &ksk_prepared, scratch.borrow());
101 black_box(());
102 }
103 }
104
105 let base2k: usize = 19;
106 let dsize = 1;
107
108 let params_set: Vec<Params> = vec![Params {
109 log_n: 15,
110 base2k: base2k.into(),
111 k_ct_in: (874 - dsize * base2k).into(),
112 k_ct_out: (874 - dsize * base2k).into(),
113 k_ksk: 874_u32.into(),
114 dsize: 1_u32.into(),
115 rank: 1_u32.into(),
116 }];
117
118 for params in params_set {
119 let id = BenchmarkId::new("KEYSWITCH_GLWE_FFT64", "");
120 let mut runner = runner(params);
121 group.sample_size(500);
122 group.measurement_time(Duration::from_secs(40));
123 group.bench_with_input(id, &(), |b, _| b.iter(&mut runner));
124 }
125
126 group.finish();
127}
128
129fn bench_keyswitch_glwe_inplace_fft64(c: &mut Criterion) {
130 let mut group = c.benchmark_group("keyswitch_glwe_inplace_fft64");
131
132 struct Params {
133 log_n: usize,
134 base2k: Base2K,
135 k_ct: TorusPrecision,
136 k_ksk: TorusPrecision,
137 rank: Rank,
138 }
139
140 fn runner(p: Params) -> impl FnMut() {
141 let module: Module<BackendImpl> = Module::<BackendImpl>::new(1 << p.log_n);
142
143 let n: Degree = Degree(module.n() as u32);
144 let base2k: Base2K = p.base2k;
145 let k_ct: TorusPrecision = p.k_ct;
146 let k_ksk: TorusPrecision = p.k_ksk;
147 let rank: Rank = p.rank;
148 let dsize: Dsize = Dsize(1);
149
150 let dnum: Dnum = p.k_ct.div_ceil(p.base2k).into();
151
152 let gglwe_layout: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
153 n,
154 base2k,
155 k: k_ksk,
156 dnum,
157 dsize,
158 rank_in: rank,
159 rank_out: rank,
160 };
161
162 let glwe_layout: GLWELayout = GLWELayout {
163 n,
164 base2k,
165 k: k_ct,
166 rank,
167 };
168
169 let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_layout);
170 let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_layout);
171
172 let mut scratch: ScratchOwned<BackendImpl> = ScratchOwned::alloc(
173 GLWESwitchingKey::encrypt_sk_tmp_bytes(&module, &gglwe_layout)
174 | GLWE::encrypt_sk_tmp_bytes(&module, &glwe_layout)
175 | GLWE::keyswitch_tmp_bytes(&module, &glwe_layout, &glwe_layout, &gglwe_layout),
176 );
177
178 let mut source_xs: Source = Source::new([0u8; 32]);
179 let mut source_xe: Source = Source::new([0u8; 32]);
180 let mut source_xa: Source = Source::new([0u8; 32]);
181
182 let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_layout);
183 sk_in.fill_ternary_prob(0.5, &mut source_xs);
184
185 let mut sk_in_dft: GLWESecretPrepared<Vec<u8>, BackendImpl> = GLWESecretPrepared::alloc(&module, rank);
186 sk_in_dft.prepare(&module, &sk_in);
187
188 let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_layout);
189 sk_out.fill_ternary_prob(0.5, &mut source_xs);
190
191 ksk.encrypt_sk(&module, &sk_in, &sk_out, &mut source_xa, &mut source_xe, scratch.borrow());
192
193 ct.encrypt_zero_sk(&module, &sk_in_dft, &mut source_xa, &mut source_xe, scratch.borrow());
194
195 let mut ksk_prepared: GLWESwitchingKeyPrepared<Vec<u8>, _> = GLWESwitchingKeyPrepared::alloc_from_infos(&module, &ksk);
196 ksk_prepared.prepare(&module, &ksk, scratch.borrow());
197
198 move || {
199 ct.keyswitch_inplace(&module, &ksk_prepared, scratch.borrow());
200 black_box(());
201 }
202 }
203
204 let params_set: Vec<Params> = vec![Params {
205 log_n: 9,
206 base2k: 18_u32.into(),
207 k_ct: 27_u32.into(),
208 k_ksk: 27_u32.into(),
209 rank: 1_u32.into(),
210 }];
211
212 for params in params_set {
213 let id = BenchmarkId::new("KEYSWITCH_GLWE_INPLACE_FFT64", "");
214 let mut runner = runner(params);
215 group.bench_with_input(id, &(), |b, _| b.iter(&mut runner));
216 }
217
218 group.finish();
219}
220
221criterion_group!(benches, bench_keyswitch_glwe_fft64, bench_keyswitch_glwe_inplace_fft64);
222criterion_main!(benches);