poulpy/spqlios/lib/test/spqlios_vec_znx_test.cpp
spqlios/lib/test/spqlios_vec_znx_test.cppRaw
1#include <cstdint>
2#include <utility>
3
4#include "../spqlios/arithmetic/vec_znx_arithmetic.h"
5#include "gtest/gtest.h"
6#include "spqlios/arithmetic/vec_znx_arithmetic_private.h"
7#include "spqlios/coeffs/coeffs_arithmetic.h"
8#include "test/testlib/mod_q120.h"
9#include "test/testlib/negacyclic_polynomial.h"
10#include "testlib/fft64_dft.h"
11#include "testlib/polynomial_vector.h"
12
13TEST(fft64_layouts, dft_idft_fft64) {
14 uint64_t n = 128;
15 // create a random polynomial
16 znx_i64 p(n);
17 for (uint64_t i = 0; i < n; ++i) {
18 p.set_coeff(i, uniform_i64_bits(36));
19 }
20 // call fft
21 reim_fft64vec q = simple_fft64(p);
22 // call ifft and round
23 znx_i64 r = simple_rint_ifft64(q);
24 ASSERT_EQ(p, r);
25}
26
27TEST(znx_layout, valid_test) {
28 uint64_t n = 4;
29 znx_vec_i64_layout v(n, 7, 13);
30 // this should be ok
31 v.set(0, znx_i64::zero(n));
32 // this should be ok
33 ASSERT_EQ(v.get_copy_zext(0), znx_i64::zero(n));
34 ASSERT_EQ(v.data()[2], 0); // should be ok
35 // this is also ok (zero extended vector)
36 ASSERT_EQ(v.get_copy_zext(1000), znx_i64::zero(n));
37}
38
39// disabling this test by default, since it depicts on purpose wrong accesses
40#if 0
41TEST(znx_layout, valgrind_antipattern_test) {
42 uint64_t n = 4;
43 znx_vec_i64_layout v(n, 7, 13);
44 // this should be ok
45 v.set(0, znx_i64::zero(n));
46 // this should abort (wrong ring dimension)
47 ASSERT_DEATH(v.set(3, znx_i64::zero(2 * n)), "");
48 // this should abort (out of bounds)
49 ASSERT_DEATH(v.set(8, znx_i64::zero(n)), "");
50 // this should be ok
51 ASSERT_EQ(v.get_copy_zext(0), znx_i64::zero(n));
52 // should be an uninit read
53 ASSERT_TRUE(!(v.get_copy_zext(2) == znx_i64::zero(n))); // should be uninit
54 // should be an invalid read (inter-slice)
55 ASSERT_NE(v.data()[4], 0);
56 ASSERT_EQ(v.data()[2], 0); // should be ok
57 // should be an uninit read
58 ASSERT_NE(v.data()[13], 0); // should be uninit
59}
60#endif
61
62// test of binary operations
63
64// test for out of place calls
65template <typename ACTUAL_FCN, typename EXPECT_FCN>
66void test_vec_znx_elemw_binop_outplace(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
67 for (uint64_t n : {2, 4, 8, 128}) {
68 MODULE_TYPE mtype = uniform_u64() % 2 == 0 ? FFT64 : NTT120;
69 MODULE* mod = new_module_info(n, mtype);
70 for (uint64_t sa : {7, 13, 15}) {
71 for (uint64_t sb : {7, 13, 15}) {
72 for (uint64_t sc : {7, 13, 15}) {
73 uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
74 uint64_t b_sl = uniform_u64_bits(3) * 5 + n;
75 uint64_t c_sl = uniform_u64_bits(3) * 5 + n;
76 znx_vec_i64_layout la(n, sa, a_sl);
77 znx_vec_i64_layout lb(n, sb, b_sl);
78 znx_vec_i64_layout lc(n, sc, c_sl);
79 std::vector<znx_i64> expect(sc);
80 for (uint64_t i = 0; i < sa; ++i) {
81 la.set(i, znx_i64::random_log2bound(n, 62));
82 }
83 for (uint64_t i = 0; i < sb; ++i) {
84 lb.set(i, znx_i64::random_log2bound(n, 62));
85 }
86 for (uint64_t i = 0; i < sc; ++i) {
87 expect[i] = ref_binop(la.get_copy_zext(i), lb.get_copy_zext(i));
88 }
89 binop(mod, // N
90 lc.data(), sc, c_sl, // res
91 la.data(), sa, a_sl, // a
92 lb.data(), sb, b_sl);
93 for (uint64_t i = 0; i < sc; ++i) {
94 ASSERT_EQ(lc.get_copy_zext(i), expect[i]);
95 }
96 }
97 }
98 }
99 delete_module_info(mod);
100 }
101}
102// test for inplace1 calls
103template <typename ACTUAL_FCN, typename EXPECT_FCN>
104void test_vec_znx_elemw_binop_inplace1(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
105 for (uint64_t n : {2, 4, 64}) {
106 MODULE_TYPE mtype = uniform_u64() % 2 == 0 ? FFT64 : NTT120;
107 MODULE* mod = new_module_info(n, mtype);
108 for (uint64_t sa : {3, 9, 12}) {
109 for (uint64_t sb : {3, 9, 12}) {
110 uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
111 uint64_t b_sl = uniform_u64_bits(3) * 5 + n;
112 znx_vec_i64_layout la(n, sa, a_sl);
113 znx_vec_i64_layout lb(n, sb, b_sl);
114 std::vector<znx_i64> expect(sa);
115 for (uint64_t i = 0; i < sa; ++i) {
116 la.set(i, znx_i64::random_log2bound(n, 62));
117 }
118 for (uint64_t i = 0; i < sb; ++i) {
119 lb.set(i, znx_i64::random_log2bound(n, 62));
120 }
121 for (uint64_t i = 0; i < sa; ++i) {
122 expect[i] = ref_binop(la.get_copy_zext(i), lb.get_copy_zext(i));
123 }
124 binop(mod, // N
125 la.data(), sa, a_sl, // res
126 la.data(), sa, a_sl, // a
127 lb.data(), sb, b_sl);
128 for (uint64_t i = 0; i < sa; ++i) {
129 ASSERT_EQ(la.get_copy_zext(i), expect[i]);
130 }
131 }
132 }
133 delete_module_info(mod);
134 }
135}
136// test for inplace2 calls
137template <typename ACTUAL_FCN, typename EXPECT_FCN>
138void test_vec_znx_elemw_binop_inplace2(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
139 for (uint64_t n : {4, 32, 64}) {
140 MODULE_TYPE mtype = uniform_u64() % 2 == 0 ? FFT64 : NTT120;
141 MODULE* mod = new_module_info(n, mtype);
142 for (uint64_t sa : {3, 9, 12}) {
143 for (uint64_t sb : {3, 9, 12}) {
144 uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
145 uint64_t b_sl = uniform_u64_bits(3) * 5 + n;
146 znx_vec_i64_layout la(n, sa, a_sl);
147 znx_vec_i64_layout lb(n, sb, b_sl);
148 std::vector<znx_i64> expect(sb);
149 for (uint64_t i = 0; i < sa; ++i) {
150 la.set(i, znx_i64::random_log2bound(n, 62));
151 }
152 for (uint64_t i = 0; i < sb; ++i) {
153 lb.set(i, znx_i64::random_log2bound(n, 62));
154 }
155 for (uint64_t i = 0; i < sb; ++i) {
156 expect[i] = ref_binop(la.get_copy_zext(i), lb.get_copy_zext(i));
157 }
158 binop(mod, // N
159 lb.data(), sb, b_sl, // res
160 la.data(), sa, a_sl, // a
161 lb.data(), sb, b_sl);
162 for (uint64_t i = 0; i < sb; ++i) {
163 ASSERT_EQ(lb.get_copy_zext(i), expect[i]);
164 }
165 }
166 }
167 delete_module_info(mod);
168 }
169}
170// test for inplace3 calls
171template <typename ACTUAL_FCN, typename EXPECT_FCN>
172void test_vec_znx_elemw_binop_inplace3(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
173 for (uint64_t n : {2, 16, 1024}) {
174 MODULE_TYPE mtype = uniform_u64() % 2 == 0 ? FFT64 : NTT120;
175 MODULE* mod = new_module_info(n, mtype);
176 for (uint64_t sa : {2, 6, 11}) {
177 uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
178 znx_vec_i64_layout la(n, sa, a_sl);
179 std::vector<znx_i64> expect(sa);
180 for (uint64_t i = 0; i < sa; ++i) {
181 la.set(i, znx_i64::random_log2bound(n, 62));
182 }
183 for (uint64_t i = 0; i < sa; ++i) {
184 expect[i] = ref_binop(la.get_copy_zext(i), la.get_copy_zext(i));
185 }
186 binop(mod, // N
187 la.data(), sa, a_sl, // res
188 la.data(), sa, a_sl, // a
189 la.data(), sa, a_sl);
190 for (uint64_t i = 0; i < sa; ++i) {
191 ASSERT_EQ(la.get_copy_zext(i), expect[i]);
192 }
193 }
194 delete_module_info(mod);
195 }
196}
197template <typename ACTUAL_FCN, typename EXPECT_FCN>
198void test_vec_znx_elemw_binop(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
199 test_vec_znx_elemw_binop_outplace(binop, ref_binop);
200 test_vec_znx_elemw_binop_inplace1(binop, ref_binop);
201 test_vec_znx_elemw_binop_inplace2(binop, ref_binop);
202 test_vec_znx_elemw_binop_inplace3(binop, ref_binop);
203}
204
205static znx_i64 poly_add(const znx_i64& a, const znx_i64& b) { return a + b; }
206TEST(vec_znx, vec_znx_add) { test_vec_znx_elemw_binop(vec_znx_add, poly_add); }
207TEST(vec_znx, vec_znx_add_ref) { test_vec_znx_elemw_binop(vec_znx_add_ref, poly_add); }
208#ifdef __x86_64__
209TEST(vec_znx, vec_znx_add_avx) { test_vec_znx_elemw_binop(vec_znx_add_avx, poly_add); }
210#endif
211
212static znx_i64 poly_sub(const znx_i64& a, const znx_i64& b) { return a - b; }
213TEST(vec_znx, vec_znx_sub) { test_vec_znx_elemw_binop(vec_znx_sub, poly_sub); }
214TEST(vec_znx, vec_znx_sub_ref) { test_vec_znx_elemw_binop(vec_znx_sub_ref, poly_sub); }
215#ifdef __x86_64__
216TEST(vec_znx, vec_znx_sub_avx) { test_vec_znx_elemw_binop(vec_znx_sub_avx, poly_sub); }
217#endif
218
219// test of rotation operations
220
221// test for out of place calls
222template <typename ACTUAL_FCN, typename EXPECT_FCN>
223void test_vec_znx_elemw_unop_param_outplace(ACTUAL_FCN test_rotate, EXPECT_FCN ref_rotate, int64_t (*param_gen)()) {
224 for (uint64_t n : {2, 4, 8, 128}) {
225 MODULE_TYPE mtype = uniform_u64() % 2 == 0 ? FFT64 : NTT120;
226 MODULE* mod = new_module_info(n, mtype);
227 for (uint64_t sa : {7, 13, 15}) {
228 for (uint64_t sb : {7, 13, 15}) {
229 {
230 int64_t p = param_gen();
231 uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
232 uint64_t b_sl = uniform_u64_bits(3) * 4 + n;
233 znx_vec_i64_layout la(n, sa, a_sl);
234 znx_vec_i64_layout lb(n, sb, b_sl);
235 std::vector<znx_i64> expect(sb);
236 for (uint64_t i = 0; i < sa; ++i) {
237 la.set(i, znx_i64::random_log2bound(n, 62));
238 }
239 for (uint64_t i = 0; i < sb; ++i) {
240 expect[i] = ref_rotate(p, la.get_copy_zext(i));
241 }
242 test_rotate(mod, //
243 p, //
244 lb.data(), sb, b_sl, //
245 la.data(), sa, a_sl //
246 );
247 for (uint64_t i = 0; i < sb; ++i) {
248 ASSERT_EQ(lb.get_copy_zext(i), expect[i]) << n << " " << sa << " " << sb << " " << i;
249 }
250 }
251 }
252 }
253 delete_module_info(mod);
254 }
255}
256
257// test for inplace calls
258template <typename ACTUAL_FCN, typename EXPECT_FCN>
259void test_vec_znx_elemw_unop_param_inplace(ACTUAL_FCN test_rotate, EXPECT_FCN ref_rotate, int64_t (*param_gen)()) {
260 for (uint64_t n : {2, 16, 1024}) {
261 MODULE_TYPE mtype = uniform_u64() % 2 == 0 ? FFT64 : NTT120;
262 MODULE* mod = new_module_info(n, mtype);
263 for (uint64_t sa : {2, 6, 11}) {
264 {
265 int64_t p = param_gen();
266 uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
267 znx_vec_i64_layout la(n, sa, a_sl);
268 std::vector<znx_i64> expect(sa);
269 for (uint64_t i = 0; i < sa; ++i) {
270 la.set(i, znx_i64::random_log2bound(n, 62));
271 }
272 for (uint64_t i = 0; i < sa; ++i) {
273 expect[i] = ref_rotate(p, la.get_copy_zext(i));
274 }
275 test_rotate(mod, // N
276 p, //;
277 la.data(), sa, a_sl, // res
278 la.data(), sa, a_sl // a
279 );
280 for (uint64_t i = 0; i < sa; ++i) {
281 ASSERT_EQ(la.get_copy_zext(i), expect[i]) << n << " " << sa << " " << i;
282 }
283 }
284 }
285 delete_module_info(mod);
286 }
287}
288
289static int64_t random_rotate_param() { return uniform_i64(); }
290
291template <typename ACTUAL_FCN, typename EXPECT_FCN>
292void test_vec_znx_elemw_rotate(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
293 test_vec_znx_elemw_unop_param_outplace(binop, ref_binop, random_rotate_param);
294 test_vec_znx_elemw_unop_param_inplace(binop, ref_binop, random_rotate_param);
295}
296
297static znx_i64 poly_rotate(const int64_t p, const znx_i64& a) {
298 uint64_t n = a.nn();
299 znx_i64 res(n);
300 for (uint64_t i = 0; i < n; ++i) {
301 res.set_coeff(i, a.get_coeff(i - p));
302 }
303 return res;
304}
305TEST(vec_znx, vec_znx_rotate) { test_vec_znx_elemw_rotate(vec_znx_rotate, poly_rotate); }
306TEST(vec_znx, vec_znx_rotate_ref) { test_vec_znx_elemw_rotate(vec_znx_rotate_ref, poly_rotate); }
307
308static int64_t random_automorphism_param() { return uniform_i64() | 1; }
309
310template <typename ACTUAL_FCN, typename EXPECT_FCN>
311void test_vec_znx_elemw_automorphism(ACTUAL_FCN unop, EXPECT_FCN ref_unop) {
312 test_vec_znx_elemw_unop_param_outplace(unop, ref_unop, random_automorphism_param);
313 test_vec_znx_elemw_unop_param_inplace(unop, ref_unop, random_automorphism_param);
314}
315
316static znx_i64 poly_automorphism(const int64_t p, const znx_i64& a) {
317 uint64_t n = a.nn();
318 znx_i64 res(n);
319 for (uint64_t i = 0; i < n; ++i) {
320 res.set_coeff(i * p, a.get_coeff(i));
321 }
322 return res;
323}
324
325TEST(vec_znx, vec_znx_automorphism) { test_vec_znx_elemw_automorphism(vec_znx_automorphism, poly_automorphism); }
326TEST(vec_znx, vec_znx_automorphism_ref) {
327 test_vec_znx_elemw_automorphism(vec_znx_automorphism_ref, poly_automorphism);
328}
329
330// test for out of place calls
331template <typename ACTUAL_FCN, typename EXPECT_FCN>
332void test_vec_znx_elemw_unop_outplace(ACTUAL_FCN test_unop, EXPECT_FCN ref_unop) {
333 for (uint64_t n : {2, 4, 8, 128}) {
334 MODULE_TYPE mtype = uniform_u64() % 2 == 0 ? FFT64 : NTT120;
335 MODULE* mod = new_module_info(n, mtype);
336 for (uint64_t sa : {7, 13, 15}) {
337 for (uint64_t sb : {7, 13, 15}) {
338 {
339 uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
340 uint64_t b_sl = uniform_u64_bits(3) * 4 + n;
341 znx_vec_i64_layout la(n, sa, a_sl);
342 znx_vec_i64_layout lb(n, sb, b_sl);
343 std::vector<znx_i64> expect(sb);
344 for (uint64_t i = 0; i < sa; ++i) {
345 la.set(i, znx_i64::random_log2bound(n, 62));
346 }
347 for (uint64_t i = 0; i < sb; ++i) {
348 expect[i] = ref_unop(la.get_copy_zext(i));
349 }
350 test_unop(mod, //
351 lb.data(), sb, b_sl, //
352 la.data(), sa, a_sl //
353 );
354 for (uint64_t i = 0; i < sb; ++i) {
355 ASSERT_EQ(lb.get_copy_zext(i), expect[i]) << n << " " << sa << " " << sb << " " << i;
356 }
357 }
358 }
359 }
360 delete_module_info(mod);
361 }
362}
363
364// test for inplace calls
365template <typename ACTUAL_FCN, typename EXPECT_FCN>
366void test_vec_znx_elemw_unop_inplace(ACTUAL_FCN test_unop, EXPECT_FCN ref_unop) {
367 for (uint64_t n : {2, 16, 1024}) {
368 MODULE_TYPE mtype = uniform_u64() % 2 == 0 ? FFT64 : NTT120;
369 MODULE* mod = new_module_info(n, mtype);
370 for (uint64_t sa : {2, 6, 11}) {
371 {
372 uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
373 znx_vec_i64_layout la(n, sa, a_sl);
374 std::vector<znx_i64> expect(sa);
375 for (uint64_t i = 0; i < sa; ++i) {
376 la.set(i, znx_i64::random_log2bound(n, 62));
377 }
378 for (uint64_t i = 0; i < sa; ++i) {
379 expect[i] = ref_unop(la.get_copy_zext(i));
380 }
381 test_unop(mod, // N
382 la.data(), sa, a_sl, // res
383 la.data(), sa, a_sl // a
384 );
385 for (uint64_t i = 0; i < sa; ++i) {
386 ASSERT_EQ(la.get_copy_zext(i), expect[i]) << n << " " << sa << " " << i;
387 }
388 }
389 }
390 delete_module_info(mod);
391 }
392}
393
394template <typename ACTUAL_FCN, typename EXPECT_FCN>
395void test_vec_znx_elemw_unop(ACTUAL_FCN unop, EXPECT_FCN ref_unop) {
396 test_vec_znx_elemw_unop_outplace(unop, ref_unop);
397 test_vec_znx_elemw_unop_inplace(unop, ref_unop);
398}
399
400static znx_i64 poly_copy(const znx_i64& a) { return a; }
401
402TEST(vec_znx, vec_znx_copy) { test_vec_znx_elemw_unop(vec_znx_copy, poly_copy); }
403TEST(vec_znx, vec_znx_copy_ref) { test_vec_znx_elemw_unop(vec_znx_copy_ref, poly_copy); }
404
405static znx_i64 poly_negate(const znx_i64& a) { return -a; }
406
407TEST(vec_znx, vec_znx_negate) { test_vec_znx_elemw_unop(vec_znx_negate, poly_negate); }
408TEST(vec_znx, vec_znx_negate_ref) { test_vec_znx_elemw_unop(vec_znx_negate_ref, poly_negate); }
409#ifdef __x86_64__
410TEST(vec_znx, vec_znx_negate_avx) { test_vec_znx_elemw_unop(vec_znx_negate_avx, poly_negate); }
411#endif
412
413static void test_vec_znx_zero(VEC_ZNX_ZERO_F zero) {
414 for (uint64_t n : {2, 16, 1024}) {
415 MODULE_TYPE mtype = uniform_u64() % 2 == 0 ? FFT64 : NTT120;
416 MODULE* mod = new_module_info(n, mtype);
417 for (uint64_t sa : {2, 6, 11}) {
418 {
419 uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
420 znx_vec_i64_layout la(n, sa, a_sl);
421 for (uint64_t i = 0; i < sa; ++i) {
422 la.set(i, znx_i64::random_log2bound(n, 62));
423 }
424 zero(mod, // N
425 la.data(), sa, a_sl // res
426 );
427 znx_i64 ZERO = znx_i64::zero(n);
428 for (uint64_t i = 0; i < sa; ++i) {
429 ASSERT_EQ(la.get_copy_zext(i), ZERO) << n << " " << sa << " " << i;
430 }
431 }
432 }
433 delete_module_info(mod);
434 }
435}
436
437TEST(vec_znx, vec_znx_zero) { test_vec_znx_zero(vec_znx_zero); }
438TEST(vec_znx, vec_znx_zero_ref) { test_vec_znx_zero(vec_znx_zero_ref); }
439
440static void vec_poly_normalize(const uint64_t base_k, std::vector<znx_i64>& in) {
441 if (in.size() > 0) {
442 uint64_t n = in.front().nn();
443
444 znx_i64 out = znx_i64::random_log2bound(n, 62);
445 znx_i64 cinout(n);
446 for (int64_t i = in.size() - 1; i >= 0; --i) {
447 znx_normalize(n, base_k, in[i].data(), cinout.data(), in[i].data(), cinout.data());
448 }
449 }
450}
451
452template <typename ACTUAL_FCN, typename TMP_BYTES_FNC>
453void test_vec_znx_normalize_outplace(ACTUAL_FCN test_normalize, TMP_BYTES_FNC tmp_bytes) {
454 for (uint64_t n : {2, 16, 1024}) {
455 MODULE_TYPE mtype = uniform_u64() % 2 == 0 ? FFT64 : NTT120;
456 MODULE* mod = new_module_info(n, mtype);
457 for (uint64_t sa : {1, 2, 6, 11}) {
458 for (uint64_t sb : {1, 2, 6, 11}) {
459 for (uint64_t base_k : {19}) {
460 uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
461 znx_vec_i64_layout la(n, sa, a_sl);
462 for (uint64_t i = 0; i < sa; ++i) {
463 la.set(i, znx_i64::random_log2bound(n, 62));
464 }
465
466 std::vector<znx_i64> la_norm;
467 for (uint64_t i = 0; i < sa; ++i) {
468 la_norm.push_back(la.get_copy_zext(i));
469 }
470 vec_poly_normalize(base_k, la_norm);
471
472 uint64_t b_sl = uniform_u64_bits(3) * 5 + n;
473 znx_vec_i64_layout lb(n, sb, b_sl);
474
475 const uint64_t tmp_size = tmp_bytes(mod);
476 uint8_t* tmp = new uint8_t[tmp_size];
477 test_normalize(mod, // N
478 base_k, // base_k
479 lb.data(), sb, b_sl, // res
480 la.data(), sa, a_sl, // a
481 tmp);
482 delete[] tmp;
483
484 for (uint64_t i = 0; i < std::min(sa, sb); ++i) {
485 ASSERT_EQ(lb.get_copy_zext(i), la_norm[i]) << n << " " << sa << " " << sb << " " << i;
486 }
487 znx_i64 zero(n);
488 for (uint64_t i = std::min(sa, sb); i < sb; ++i) {
489 ASSERT_EQ(lb.get_copy_zext(i), zero) << n << " " << sa << " " << sb << " " << i;
490 }
491 }
492 }
493 }
494 delete_module_info(mod);
495 }
496}
497
498TEST(vec_znx, vec_znx_normalize_outplace) {
499 test_vec_znx_normalize_outplace(vec_znx_normalize_base2k, vec_znx_normalize_base2k_tmp_bytes);
500}
501TEST(vec_znx, vec_znx_normalize_outplace_ref) {
502 test_vec_znx_normalize_outplace(vec_znx_normalize_base2k_ref, vec_znx_normalize_base2k_tmp_bytes_ref);
503}
504
505template <typename ACTUAL_FCN, typename TMP_BYTES_FNC>
506void test_vec_znx_normalize_inplace(ACTUAL_FCN test_normalize, TMP_BYTES_FNC tmp_bytes) {
507 for (uint64_t n : {2, 16, 1024}) {
508 MODULE_TYPE mtype = uniform_u64() % 2 == 0 ? FFT64 : NTT120;
509 MODULE* mod = new_module_info(n, mtype);
510 for (uint64_t sa : {2, 6, 11}) {
511 for (uint64_t base_k : {19}) {
512 uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
513 znx_vec_i64_layout la(n, sa, a_sl);
514 for (uint64_t i = 0; i < sa; ++i) {
515 la.set(i, znx_i64::random_log2bound(n, 62));
516 }
517
518 std::vector<znx_i64> la_norm;
519 for (uint64_t i = 0; i < sa; ++i) {
520 la_norm.push_back(la.get_copy_zext(i));
521 }
522 vec_poly_normalize(base_k, la_norm);
523
524 const uint64_t tmp_size = tmp_bytes(mod);
525 uint8_t* tmp = new uint8_t[tmp_size];
526 test_normalize(mod, // N
527 base_k, // base_k
528 la.data(), sa, a_sl, // res
529 la.data(), sa, a_sl, // a
530 tmp);
531 delete[] tmp;
532 for (uint64_t i = 0; i < sa; ++i) {
533 ASSERT_EQ(la.get_copy_zext(i), la_norm[i]) << n << " " << sa << " " << i;
534 }
535 }
536 }
537 delete_module_info(mod);
538 }
539}
540
541TEST(vec_znx, vec_znx_normalize_inplace) {
542 test_vec_znx_normalize_inplace(vec_znx_normalize_base2k, vec_znx_normalize_base2k_tmp_bytes);
543}
544TEST(vec_znx, vec_znx_normalize_inplace_ref) {
545 test_vec_znx_normalize_inplace(vec_znx_normalize_base2k_ref, vec_znx_normalize_base2k_tmp_bytes_ref);
546}