Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions spqlios/arithmetic/module_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static void fill_fft64_virtual_table(MODULE* module) {
module->func.vec_znx_big_automorphism = fft64_vec_znx_big_automorphism;
module->func.svp_prepare = fft64_svp_prepare_ref;
module->func.svp_apply_dft = fft64_svp_apply_dft_ref;
module->func.svp_apply_dft_to_dft = fft64_svp_apply_dft_to_dft_ref;
module->func.znx_small_single_product = fft64_znx_small_single_product;
module->func.znx_small_single_product_tmp_bytes = fft64_znx_small_single_product_tmp_bytes;
module->func.vmp_prepare_contiguous = fft64_vmp_prepare_contiguous_ref;
Expand Down
35 changes: 35 additions & 0 deletions spqlios/arithmetic/scalar_vector_product.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ EXPORT void svp_apply_dft(const MODULE* module, // N
a, a_size, a_sl);
}

// result = ppol * a_dft
EXPORT void svp_apply_dft_to_dft(const MODULE* module, // N
const VEC_ZNX_DFT* res, uint64_t res_size, // output
const SVP_PPOL* ppol, // prepared pol
const VEC_ZNX_DFT* a_dft, uint64_t a_size // a
) {
module->func.svp_apply_dft_to_dft(module, // N
res,
res_size, // output
ppol, // prepared pol
a_dft, a_size);
}
// result = ppol * a
EXPORT void fft64_svp_apply_dft_ref(const MODULE* module, // N
const VEC_ZNX_DFT* res, uint64_t res_size, // output
Expand All @@ -61,3 +73,26 @@ EXPORT void fft64_svp_apply_dft_ref(const MODULE* module,
// then extend with zeros
memset(dres + auto_end_idx * nn, 0, (res_size - auto_end_idx) * nn * sizeof(double));
}

// result = ppol * a_dft
EXPORT void fft64_svp_apply_dft_to_dft_ref(const MODULE* module, // N
const VEC_ZNX_DFT* res, uint64_t res_size, // output
const SVP_PPOL* ppol, // prepared pol
const VEC_ZNX_DFT* a_dft, uint64_t a_size // a
) {
const uint64_t nn = module->nn;
double* const dres = (double*)res;
double* const dppol = (double*)ppol;

const uint64_t auto_end_idx = res_size < a_size ? res_size : a_size;
for (uint64_t i = 0; i < auto_end_idx; ++i) {
double* const res_ptr = dres + i * nn;
// copy the polynomial to res, apply fft in place, call fftvec_mul in place.
double* vec_input = (double*)a_dft;
reim_fftvec_mul(module->mod.fft64.mul_fft, res_ptr, dppol, vec_input + i * nn);
;
}

// then extend with zeros
memset(dres + auto_end_idx * nn, 0, (res_size - auto_end_idx) * nn * sizeof(double));
}
7 changes: 7 additions & 0 deletions spqlios/arithmetic/vec_znx_arithmetic.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,13 @@ EXPORT void svp_apply_dft(const MODULE* module, // N
const int64_t* a, uint64_t a_size, uint64_t a_sl // a
);

/** @brief apply a svp product, result = ppol * a_dft, presented in DFT space */
EXPORT void svp_apply_dft_to_dft(const MODULE* module, // N
const VEC_ZNX_DFT* res, uint64_t res_size, // output
const SVP_PPOL* ppol, // prepared pol
const VEC_ZNX_DFT* a_dft, uint64_t a_size // a
);

/** @brief prepares a svp polynomial */
EXPORT void svp_prepare(const MODULE* module, // N
SVP_PPOL* ppol, // output
Expand Down
9 changes: 9 additions & 0 deletions spqlios/arithmetic/vec_znx_arithmetic_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ typedef typeof(vec_znx_big_rotate) VEC_ZNX_BIG_ROTATE_F;
typedef typeof(vec_znx_big_automorphism) VEC_ZNX_BIG_AUTOMORPHISM_F;
typedef typeof(svp_prepare) SVP_PREPARE;
typedef typeof(svp_apply_dft) SVP_APPLY_DFT_F;
typedef typeof(svp_apply_dft_to_dft) SVP_APPLY_DFT_TO_DFT_F;
typedef typeof(znx_small_single_product) ZNX_SMALL_SINGLE_PRODUCT_F;
typedef typeof(znx_small_single_product_tmp_bytes) ZNX_SMALL_SINGLE_PRODUCT_TMP_BYTES_F;
typedef typeof(vmp_prepare_contiguous) VMP_PREPARE_CONTIGUOUS_F;
Expand Down Expand Up @@ -130,6 +131,7 @@ struct module_virtual_functions_t {
VEC_ZNX_BIG_AUTOMORPHISM_F* vec_znx_big_automorphism;
SVP_PREPARE* svp_prepare;
SVP_APPLY_DFT_F* svp_apply_dft;
SVP_APPLY_DFT_TO_DFT_F* svp_apply_dft_to_dft;
ZNX_SMALL_SINGLE_PRODUCT_F* znx_small_single_product;
ZNX_SMALL_SINGLE_PRODUCT_TMP_BYTES_F* znx_small_single_product_tmp_bytes;
VMP_PREPARE_CONTIGUOUS_F* vmp_prepare_contiguous;
Expand Down Expand Up @@ -290,6 +292,13 @@ EXPORT void fft64_svp_apply_dft_ref(const MODULE* module,
const int64_t* a, uint64_t a_size, uint64_t a_sl // a
);

/** @brief apply a svp product, result = ppol * a_dft, presented in DFT space */
EXPORT void fft64_svp_apply_dft_to_dft_ref(const MODULE* module, // N
const VEC_ZNX_DFT* res, uint64_t res_size, // output
const SVP_PPOL* ppol, // prepared pol
const VEC_ZNX_DFT* a_dft, uint64_t a_size // a
);

/** @brief sets res = k-normalize(a) -- output in int64 coeffs space */
EXPORT void fft64_vec_znx_big_normalize_base2k(const MODULE* module, // N
uint64_t k, // base-2^k
Expand Down
42 changes: 42 additions & 0 deletions test/spqlios_svp_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,45 @@ void test_fft64_svp_apply_dft(SVP_APPLY_DFT_F svp) {

TEST(fft64_svp_apply_dft, svp_apply_dft) { test_fft64_svp_apply_dft(svp_apply_dft); }
TEST(fft64_svp_apply_dft, fft64_svp_apply_dft_ref) { test_fft64_svp_apply_dft(fft64_svp_apply_dft_ref); }

void test_fft64_svp_apply_dft_to_dft(SVP_APPLY_DFT_TO_DFT_F svp_dft) {
for (uint64_t n : {2, 4, 8, 64, 128}) {
MODULE* module = new_module_info(n, FFT64);
// poly 1 to multiply - create and prepare
fft64_svp_ppol_layout ppol(n);
ppol.fill_random(1.);
for (uint64_t sa : {3, 5, 8}) {
for (uint64_t sr : {3, 5, 8}) {
// poly 2 to multiply
fft64_vec_znx_dft_layout a_dft(n, sa);
a_dft.fill_dft_random_log2bound(19);
// original operation result
fft64_vec_znx_dft_layout res(n, sr);
thash hash_a_before = a_dft.content_hash();
thash hash_ppol_before = ppol.content_hash();
svp_dft(module, res.data, sr, ppol.data, a_dft.data, sa);
ASSERT_EQ(a_dft.content_hash(), hash_a_before);
ASSERT_EQ(ppol.content_hash(), hash_ppol_before);
// create expected value
reim_fft64vec ppo = ppol.get_copy();
std::vector<reim_fft64vec> expect(sr);
for (uint64_t i = 0; i < sr; ++i) {
expect[i] = ppo * a_dft.get_copy_zext(i);
}
// this is the largest precision we can safely expect
double prec_expect = n * pow(2., 19 - 52);
for (uint64_t i = 0; i < sr; ++i) {
reim_fft64vec actual = res.get_copy_zext(i);
ASSERT_LE(infty_dist(actual, expect[i]), prec_expect);
}
}
}

delete_module_info(module);
}
}

TEST(fft64_svp_apply_dft_to_dft, svp_apply_dft_to_dft) { test_fft64_svp_apply_dft_to_dft(svp_apply_dft_to_dft); }
TEST(fft64_svp_apply_dft_to_dft, fft64_svp_apply_dft_to_dft_ref) {
test_fft64_svp_apply_dft_to_dft(fft64_svp_apply_dft_to_dft_ref);
}
Loading