arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/test/spqlios_q120_arithmetic_test.cpp
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/test/spqlios_q120_arithmetic_test.cppRaw
  1#include <gtest/gtest.h>
  2
  3#include <cstdint>
  4#include <vector>
  5
  6#include "spqlios/q120/q120_arithmetic.h"
  7#include "test/testlib/negacyclic_polynomial.h"
  8#include "test/testlib/ntt120_layouts.h"
  9#include "testlib/mod_q120.h"
 10
 11typedef typeof(q120_vec_mat1col_product_baa_ref) vec_mat1col_product_baa_f;
 12
 13void test_vec_mat1col_product_baa(vec_mat1col_product_baa_f vec_mat1col_product_baa) {
 14  q120_mat1col_product_baa_precomp* precomp = q120_new_vec_mat1col_product_baa_precomp();
 15  for (uint64_t ell : {1, 2, 100, 10000}) {
 16    std::vector<uint64_t> a(ell * 4);
 17    std::vector<uint64_t> b(ell * 4);
 18    std::vector<uint64_t> res(4);
 19    uint64_t* pa = a.data();
 20    uint64_t* pb = b.data();
 21    uint64_t* pr = res.data();
 22    // generate some random data
 23    uniform_q120b(pr);
 24    for (uint64_t i = 0; i < ell; ++i) {
 25      uniform_q120a(pa + 4 * i);
 26      uniform_q120a(pb + 4 * i);
 27    }
 28    // compute the expected result
 29    mod_q120 expect_r;
 30    for (uint64_t i = 0; i < ell; ++i) {
 31      expect_r += mod_q120::from_q120a(pa + 4 * i) * mod_q120::from_q120a(pb + 4 * i);
 32    }
 33    // compute the function
 34    vec_mat1col_product_baa(precomp, ell, (q120b*)pr, (q120a*)pa, (q120a*)pb);
 35    mod_q120 comp_r = mod_q120::from_q120b(pr);
 36    // check for equality
 37    ASSERT_EQ(comp_r, expect_r) << ell;
 38  }
 39  q120_delete_vec_mat1col_product_baa_precomp(precomp);
 40}
 41
 42TEST(q120_arithmetic, q120_vec_mat1col_product_baa_ref) {
 43  test_vec_mat1col_product_baa(q120_vec_mat1col_product_baa_ref);
 44}
 45#ifdef __x86_64__
 46TEST(q120_arithmetic, q120_vec_mat1col_product_baa_avx2) {
 47  test_vec_mat1col_product_baa(q120_vec_mat1col_product_baa_avx2);
 48}
 49#endif
 50
 51typedef typeof(q120_vec_mat1col_product_bbb_ref) vec_mat1col_product_bbb_f;
 52
 53void test_vec_mat1col_product_bbb(vec_mat1col_product_bbb_f vec_mat1col_product_bbb) {
 54  q120_mat1col_product_bbb_precomp* precomp = q120_new_vec_mat1col_product_bbb_precomp();
 55  for (uint64_t ell : {1, 2, 100, 10000}) {
 56    std::vector<uint64_t> a(ell * 4);
 57    std::vector<uint64_t> b(ell * 4);
 58    std::vector<uint64_t> res(4);
 59    uint64_t* pa = a.data();
 60    uint64_t* pb = b.data();
 61    uint64_t* pr = res.data();
 62    // generate some random data
 63    uniform_q120b(pr);
 64    for (uint64_t i = 0; i < ell; ++i) {
 65      uniform_q120b(pa + 4 * i);
 66      uniform_q120b(pb + 4 * i);
 67    }
 68    // compute the expected result
 69    mod_q120 expect_r;
 70    for (uint64_t i = 0; i < ell; ++i) {
 71      expect_r += mod_q120::from_q120b(pa + 4 * i) * mod_q120::from_q120b(pb + 4 * i);
 72    }
 73    // compute the function
 74    vec_mat1col_product_bbb(precomp, ell, (q120b*)pr, (q120b*)pa, (q120b*)pb);
 75    mod_q120 comp_r = mod_q120::from_q120b(pr);
 76    // check for equality
 77    ASSERT_EQ(comp_r, expect_r);
 78  }
 79  q120_delete_vec_mat1col_product_bbb_precomp(precomp);
 80}
 81
 82TEST(q120_arithmetic, q120_vec_mat1col_product_bbb_ref) {
 83  test_vec_mat1col_product_bbb(q120_vec_mat1col_product_bbb_ref);
 84}
 85#ifdef __x86_64__
 86TEST(q120_arithmetic, q120_vec_mat1col_product_bbb_avx2) {
 87  test_vec_mat1col_product_bbb(q120_vec_mat1col_product_bbb_avx2);
 88}
 89#endif
 90
 91typedef typeof(q120_vec_mat1col_product_bbc_ref) vec_mat1col_product_bbc_f;
 92
 93void test_vec_mat1col_product_bbc(vec_mat1col_product_bbc_f vec_mat1col_product_bbc) {
 94  q120_mat1col_product_bbc_precomp* precomp = q120_new_vec_mat1col_product_bbc_precomp();
 95  for (uint64_t ell : {1, 2, 100, 10000}) {
 96    std::vector<uint64_t> a(ell * 4);
 97    std::vector<uint64_t> b(ell * 4);
 98    std::vector<uint64_t> res(4);
 99    uint64_t* pa = a.data();
100    uint64_t* pb = b.data();
101    uint64_t* pr = res.data();
102    // generate some random data
103    uniform_q120b(pr);
104    for (uint64_t i = 0; i < ell; ++i) {
105      uniform_q120b(pa + 4 * i);
106      uniform_q120c(pb + 4 * i);
107    }
108    // compute the expected result
109    mod_q120 expect_r;
110    for (uint64_t i = 0; i < ell; ++i) {
111      expect_r += mod_q120::from_q120b(pa + 4 * i) * mod_q120::from_q120c(pb + 4 * i);
112    }
113    // compute the function
114    vec_mat1col_product_bbc(precomp, ell, (q120b*)pr, (q120b*)pa, (q120c*)pb);
115    mod_q120 comp_r = mod_q120::from_q120b(pr);
116    // check for equality
117    ASSERT_EQ(comp_r, expect_r);
118  }
119  q120_delete_vec_mat1col_product_bbc_precomp(precomp);
120}
121
122TEST(q120_arithmetic, q120_vec_mat1col_product_bbc_ref) {
123  test_vec_mat1col_product_bbc(q120_vec_mat1col_product_bbc_ref);
124}
125#ifdef __x86_64__
126TEST(q120_arithmetic, q120_vec_mat1col_product_bbc_avx2) {
127  test_vec_mat1col_product_bbc(q120_vec_mat1col_product_bbc_avx2);
128}
129#endif
130
131EXPORT void q120x2_vec_mat2cols_product_bbc_avx2(q120_mat1col_product_bbc_precomp* precomp, const uint64_t ell,
132                                                 q120b* const res, const q120b* const x, const q120c* const y);
133EXPORT void q120x2_vec_mat1col_product_bbc_avx2(q120_mat1col_product_bbc_precomp* precomp, const uint64_t ell,
134                                                q120b* const res, const q120b* const x, const q120c* const y);
135
136typedef typeof(q120x2_vec_mat2cols_product_bbc_avx2) q120x2_prod_bbc_f;
137
138void test_q120x2_vec_mat2cols_product_bbc(q120x2_prod_bbc_f q120x2_prod_bbc) {
139  q120_mat1col_product_bbc_precomp* precomp = q120_new_vec_mat1col_product_bbc_precomp();
140  for (uint64_t ell : {1, 2, 100, 10000}) {
141    std::vector<uint64_t> a(ell * 8);
142    std::vector<uint64_t> b(ell * 16);
143    std::vector<uint64_t> res(16);
144    uint64_t* pa = a.data();
145    uint64_t* pb = b.data();
146    uint64_t* pr = res.data();
147    // generate some random data
148    uniform_q120b(pr);
149    for (uint64_t i = 0; i < 2 * ell; ++i) {
150      uniform_q120b(pa + 4 * i);
151    }
152    for (uint64_t i = 0; i < 4 * ell; ++i) {
153      uniform_q120c(pb + 4 * i);
154    }
155    // compute the expected result
156    mod_q120 expect_r[4];
157    for (uint64_t i = 0; i < ell; ++i) {
158      mod_q120 va = mod_q120::from_q120b(pa + 8 * i);
159      mod_q120 vb = mod_q120::from_q120b(pa + 8 * i + 4);
160      mod_q120 m1a = mod_q120::from_q120c(pb + 16 * i);
161      mod_q120 m1b = mod_q120::from_q120c(pb + 16 * i + 4);
162      mod_q120 m2a = mod_q120::from_q120c(pb + 16 * i + 8);
163      mod_q120 m2b = mod_q120::from_q120c(pb + 16 * i + 12);
164      expect_r[0] += va * m1a;
165      expect_r[1] += vb * m1b;
166      expect_r[2] += va * m2a;
167      expect_r[3] += vb * m2b;
168    }
169    // compute the function
170    q120x2_prod_bbc(precomp, ell, (q120b*)pr, (q120b*)pa, (q120c*)pb);
171    // check for equality
172    ASSERT_EQ(mod_q120::from_q120b(pr), expect_r[0]);
173    ASSERT_EQ(mod_q120::from_q120b(pr + 4), expect_r[1]);
174    ASSERT_EQ(mod_q120::from_q120b(pr + 8), expect_r[2]);
175    ASSERT_EQ(mod_q120::from_q120b(pr + 12), expect_r[3]);
176  }
177  q120_delete_vec_mat1col_product_bbc_precomp(precomp);
178}
179
180TEST(q120_arithmetic, q120x2_vec_mat2cols_product_bbc_ref) {
181  test_q120x2_vec_mat2cols_product_bbc(q120x2_vec_mat2cols_product_bbc_ref);
182}
183#ifdef __x86_64__
184TEST(q120_arithmetic, q120x2_vec_mat2cols_product_bbc_avx2) {
185  test_q120x2_vec_mat2cols_product_bbc(q120x2_vec_mat2cols_product_bbc_avx2);
186}
187#endif
188
189typedef typeof(q120x2_vec_mat1col_product_bbc_avx2) q120x2_c1_prod_bbc_f;
190
191void test_q120x2_vec_mat1col_product_bbc(q120x2_c1_prod_bbc_f q120x2_c1_prod_bbc) {
192  q120_mat1col_product_bbc_precomp* precomp = q120_new_vec_mat1col_product_bbc_precomp();
193  for (uint64_t ell : {1, 2, 100, 10000}) {
194    std::vector<uint64_t> a(ell * 8);
195    std::vector<uint64_t> b(ell * 8);
196    std::vector<uint64_t> res(8);
197    uint64_t* pa = a.data();
198    uint64_t* pb = b.data();
199    uint64_t* pr = res.data();
200    // generate some random data
201    uniform_q120b(pr);
202    for (uint64_t i = 0; i < 2 * ell; ++i) {
203      uniform_q120b(pa + 4 * i);
204    }
205    for (uint64_t i = 0; i < 2 * ell; ++i) {
206      uniform_q120c(pb + 4 * i);
207    }
208    // compute the expected result
209    mod_q120 expect_r[2];
210    for (uint64_t i = 0; i < ell; ++i) {
211      mod_q120 va = mod_q120::from_q120b(pa + 8 * i);
212      mod_q120 vb = mod_q120::from_q120b(pa + 8 * i + 4);
213      mod_q120 m1a = mod_q120::from_q120c(pb + 8 * i);
214      mod_q120 m1b = mod_q120::from_q120c(pb + 8 * i + 4);
215      expect_r[0] += va * m1a;
216      expect_r[1] += vb * m1b;
217    }
218    // compute the function
219    q120x2_c1_prod_bbc(precomp, ell, (q120b*)pr, (q120b*)pa, (q120c*)pb);
220    // check for equality
221    ASSERT_EQ(mod_q120::from_q120b(pr), expect_r[0]);
222    ASSERT_EQ(mod_q120::from_q120b(pr + 4), expect_r[1]);
223  }
224  q120_delete_vec_mat1col_product_bbc_precomp(precomp);
225}
226
227TEST(q120_arithmetic, q120x2_vec_mat1col_product_bbc_ref) {
228  test_q120x2_vec_mat1col_product_bbc(q120x2_vec_mat1col_product_bbc_ref);
229}
230#ifdef __x86_64__
231TEST(q120_arithmetic, q120x2_vec_mat1col_product_bbc_avx2) {
232  test_q120x2_vec_mat1col_product_bbc(q120x2_vec_mat1col_product_bbc_avx2);
233}
234#endif
235
236typedef typeof(q120x2_extract_1blk_from_q120b_ref) q120x2_extract_f;
237void test_q120x2_extract_1blk(q120x2_extract_f q120x2_extract) {
238  for (uint64_t n : {2, 4, 64}) {
239    ntt120_vec_znx_dft_layout v(n, 1);
240    std::vector<uint64_t> r(8);
241    std::vector<uint64_t> expect(8);
242    for (uint64_t blk = 0; blk < n / 2; ++blk) {
243      for (uint64_t i = 0; i < 8; ++i) {
244        expect[i] = uniform_u64();
245      }
246      memcpy(v.get_blk(0, blk), expect.data(), 8 * sizeof(uint64_t));
247      q120x2_extract_1blk_from_q120b_ref(n, blk, (q120x2b*)r.data(), (q120b*)v.data);
248      ASSERT_EQ(r, expect);
249    }
250  }
251}
252
253TEST(q120_arithmetic, q120x2_extract_1blk_from_q120b_ref) {
254  test_q120x2_extract_1blk(q120x2_extract_1blk_from_q120b_ref);
255}
256
257typedef typeof(q120x2_extract_1blk_from_contiguous_q120b_ref) q120x2_extract_vec_f;
258void test_q120x2_extract_1blk_vec(q120x2_extract_vec_f q120x2_extract) {
259  for (uint64_t n : {2, 4, 32}) {
260    for (uint64_t size : {1, 2, 7}) {
261      ntt120_vec_znx_dft_layout v(n, size);
262      std::vector<uint64_t> r(8 * size);
263      std::vector<uint64_t> expect(8 * size);
264      for (uint64_t blk = 0; blk < n / 2; ++blk) {
265        for (uint64_t i = 0; i < 8 * size; ++i) {
266          expect[i] = uniform_u64();
267        }
268        for (uint64_t i = 0; i < size; ++i) {
269          memcpy(v.get_blk(i, blk), expect.data() + 8 * i, 8 * sizeof(uint64_t));
270        }
271        q120x2_extract(n, size, blk, (q120x2b*)r.data(), (q120b*)v.data);
272        ASSERT_EQ(r, expect);
273      }
274    }
275  }
276}
277
278TEST(q120_arithmetic, q120x2_extract_1blk_from_contiguous_q120b_ref) {
279  test_q120x2_extract_1blk_vec(q120x2_extract_1blk_from_contiguous_q120b_ref);
280}
281
282typedef typeof(q120x2b_save_1blk_to_q120b_ref) q120x2_save_f;
283void test_q120x2_save_1blk(q120x2_save_f q120x2_save) {
284  for (uint64_t n : {2, 4, 64}) {
285    ntt120_vec_znx_dft_layout v(n, 1);
286    std::vector<uint64_t> r(8);
287    std::vector<uint64_t> expect(8);
288    for (uint64_t blk = 0; blk < n / 2; ++blk) {
289      for (uint64_t i = 0; i < 8; ++i) {
290        expect[i] = uniform_u64();
291      }
292      q120x2_save(n, blk, (q120b*)v.data, (q120x2b*)expect.data());
293      memcpy(r.data(), v.get_blk(0, blk), 8 * sizeof(uint64_t));
294      ASSERT_EQ(r, expect);
295    }
296  }
297}
298
299TEST(q120_arithmetic, q120x2b_save_1blk_to_q120b_ref) { test_q120x2_save_1blk(q120x2b_save_1blk_to_q120b_ref); }
300
301TEST(q120_arithmetic, q120_add_bbb_simple) {
302  for (const uint64_t n : {2, 4, 1024}) {
303    std::vector<uint64_t> a(n * 4);
304    std::vector<uint64_t> b(n * 4);
305    std::vector<uint64_t> r(n * 4);
306    uint64_t* pa = a.data();
307    uint64_t* pb = b.data();
308    uint64_t* pr = r.data();
309
310    // generate some random data
311    for (uint64_t i = 0; i < n; ++i) {
312      uniform_q120b(pa + 4 * i);
313      uniform_q120b(pb + 4 * i);
314    }
315
316    // compute the function
317    q120_add_bbb_simple(n, (q120b*)pr, (q120b*)pa, (q120b*)pb);
318
319    for (uint64_t i = 0; i < n; ++i) {
320      mod_q120 ae = mod_q120::from_q120b(pa + 4 * i);
321      mod_q120 be = mod_q120::from_q120b(pb + 4 * i);
322      mod_q120 re = mod_q120::from_q120b(pr + 4 * i);
323
324      ASSERT_EQ(ae + be, re);
325    }
326  }
327}
328
329TEST(q120_arithmetic, q120_add_ccc_simple) {
330  for (const uint64_t n : {2, 4, 1024}) {
331    std::vector<uint64_t> a(n * 4);
332    std::vector<uint64_t> b(n * 4);
333    std::vector<uint64_t> r(n * 4);
334    uint64_t* pa = a.data();
335    uint64_t* pb = b.data();
336    uint64_t* pr = r.data();
337
338    // generate some random data
339    for (uint64_t i = 0; i < n; ++i) {
340      uniform_q120c(pa + 4 * i);
341      uniform_q120c(pb + 4 * i);
342    }
343
344    // compute the function
345    q120_add_ccc_simple(n, (q120c*)pr, (q120c*)pa, (q120c*)pb);
346
347    for (uint64_t i = 0; i < n; ++i) {
348      mod_q120 ae = mod_q120::from_q120c(pa + 4 * i);
349      mod_q120 be = mod_q120::from_q120c(pb + 4 * i);
350      mod_q120 re = mod_q120::from_q120c(pr + 4 * i);
351
352      ASSERT_EQ(ae + be, re);
353    }
354  }
355}
356
357TEST(q120_arithmetic, q120_c_from_b_simple) {
358  for (const uint64_t n : {2, 4, 1024}) {
359    std::vector<uint64_t> a(n * 4);
360    std::vector<uint64_t> r(n * 4);
361    uint64_t* pa = a.data();
362    uint64_t* pr = r.data();
363
364    // generate some random data
365    for (uint64_t i = 0; i < n; ++i) {
366      uniform_q120b(pa + 4 * i);
367    }
368
369    // compute the function
370    q120_c_from_b_simple(n, (q120c*)pr, (q120b*)pa);
371
372    for (uint64_t i = 0; i < n; ++i) {
373      mod_q120 ae = mod_q120::from_q120b(pa + 4 * i);
374      mod_q120 re = mod_q120::from_q120c(pr + 4 * i);
375
376      ASSERT_EQ(ae, re);
377    }
378  }
379}
380
381TEST(q120_arithmetic, q120_b_from_znx64_simple) {
382  for (const uint64_t n : {2, 4, 1024}) {
383    znx_i64 x = znx_i64::random_log2bound(n, 62);
384    std::vector<uint64_t> r(n * 4);
385    uint64_t* pr = r.data();
386
387    q120_b_from_znx64_simple(n, (q120b*)pr, x.data());
388
389    for (uint64_t i = 0; i < n; ++i) {
390      mod_q120 re = mod_q120::from_q120b(pr + 4 * i);
391
392      for (uint64_t k = 0; k < 4; ++k) {
393        ASSERT_EQ(centermod(x.get_coeff(i), mod_q120::Qi[k]), re.a[k]);
394      }
395    }
396  }
397}
398
399TEST(q120_arithmetic, q120_c_from_znx64_simple) {
400  for (const uint64_t n : {2, 4, 1024}) {
401    znx_i64 x = znx_i64::random(n);
402    std::vector<uint64_t> r(n * 4);
403    uint64_t* pr = r.data();
404
405    q120_c_from_znx64_simple(n, (q120c*)pr, x.data());
406
407    for (uint64_t i = 0; i < n; ++i) {
408      mod_q120 re = mod_q120::from_q120c(pr + 4 * i);
409
410      for (uint64_t k = 0; k < 4; ++k) {
411        ASSERT_EQ(centermod(x.get_coeff(i), mod_q120::Qi[k]), re.a[k]);
412      }
413    }
414  }
415}
416
417TEST(q120_arithmetic, q120_b_to_znx128_simple) {
418  for (const uint64_t n : {2, 4, 1024}) {
419    std::vector<uint64_t> x(n * 4);
420    uint64_t* px = x.data();
421
422    // generate some random data
423    for (uint64_t i = 0; i < n; ++i) {
424      uniform_q120b(px + 4 * i);
425    }
426
427    znx_i128 r(n);
428    q120_b_to_znx128_simple(n, r.data(), (q120b*)px);
429
430    for (uint64_t i = 0; i < n; ++i) {
431      mod_q120 xe = mod_q120::from_q120b(px + 4 * i);
432      for (uint64_t k = 0; k < 4; ++k) {
433        ASSERT_EQ(centermod((int64_t)(r.get_coeff(i) % mod_q120::Qi[k]), mod_q120::Qi[k]), xe.a[k]);
434      }
435    }
436  }
437}