arnaucube
arnaucube/poulpyPublic Self-hosted repository
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}