-
Notifications
You must be signed in to change notification settings - Fork 2
rnx api
The spqlios arithmetic library provides fast approximate arithmetic over vectors of real polynomials (typically suited for cases where 52 bits of floating point precision are sufficient). It exposes fast prepared vector-matrix and prepared scalar-vector products, internally powered by FFT.
A single small polynomial double[N]
contiguous array.
A vector of
Concretely, given the ring dimension uint64_t N
, a vector of polynomial is represented by one pointer double* p
, the size of the vector ell
, and a stride/slice size slice >= N
. The &p[i*slice+j]
(C notation): For double
element at this address shall be properly allocated and accessible.
The double*
pointer can be allocated and freed using standard allocators (malloc
, new double[]
, ...), using the default endianess of the machine (usually little-endian on most cpus). The structure can be allocated, filled, and read externally to the library. If the layout is not contiguous (slice is
Alignment: An alignment of 64-bytes is recommended for speed reasons, but not mandatory. Serialization/IO: fread and fwrite-based are fine. Some care may be needed to make the endianess canonical (TBD)
Real numbers modulo 1 can be represented either as:
- a
double
whose value in the interval$[-0.5,0.5)$ . Functions using this representation are qualified with the prefix or suffixtnxdbl
. In this case, the number has$\approx$ 52 bits of precision. - an
torus32
: it shares its bit layout with a 32-bit integers mod$2^{32}$ (a.k.a we cantypedef int32_t torus32
), but the value it represents is implicitly scaled by a factor$2^{-32}$ : If anint32_t x
represents an integer value$v\in[-2^{31}; 2^{31}[$ mod$2^{32}$ , then the same 32 bits typed astorus32 x
represents$v.2^{-32}\in[-0.5,0.5)$ mod 1.torus32
andint32_t
arithmetic are bit-wise equivalent: addition, subtraction between twotorus32
can use the standard +,- operators, and the external multiplication between an integer and atorus32
can use the * operator. (it also holds for the assembly instructions)
/**
* @brief obtain a module for ring dimension N
* currently, the only module_type supported is FFT64
*/
MOD_RNX* new_rnx_module_info(uint64_t N, MODULE_TYPE mode);
void delete_module_info(MOD_RNX* module_info);
uint64_t module_get_n(const MOD_RNX* module);
/** @brief sets res = 0 */
void vec_rnx_zero(const MOD_RNX* module, // N
double* res, uint64_t res_size, uint64_t res_sl // res
);
/** @brief sets res = a */
void vec_rnx_copy(const MOD_RNX* module, // N
double* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl // a
);
/** @brief sets res = -a */
void vec_rnx_negate(const MOD_RNX* module, // N
double* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl // a
);
/** @brief sets res = a + b */
void vec_rnx_add(const MOD_RNX* module, // N
double* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl, // a
const double* b, uint64_t b_size, uint64_t b_sl // b
);
/** @brief sets res = a - b */
void vec_rnx_sub(const MOD_RNX* module, // N
double* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl, // a
const double* b, uint64_t b_size, uint64_t b_sl // b
);
/** @brief sets res = a . X^p */
void vec_rnx_rotate(
const MOD_RNX* module, // N
const int64_t p, // rotation value
double* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl // a
);
/** @brief sets res = a . (X^p - 1) */
void vec_rnx_mul_xp_minus_one(
const MOD_RNX* module, // N
const int64_t p, // rotation value
double* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl // a
);
/** @brief sets res = a(X^p) */
void vec_rnx_automorphism(
const MOD_RNX* module, // N
int64_t p, // X -> X^p
double* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl // a
);
/** @brief res = a * b : small polynomial product */
void rnx_small_single_product(const MOD_RNX* module, // N
double* res, // output
const double* a, // a
const double* b, // b
uint8_t* tmp); // scratch space
/** @brief res = a * b centermod 1: small polynomial product */
void tnxdbl_small_single_product(const MOD_RNX* module, // N
double* torus_res, // output
const double* int_a, // a
const double* torus_b, // b
uint8_t* tmp); // scratch space
/** @brief res = a * b: small polynomial product */
void znx32_small_single_product(const MOD_RNX* module, // N
int32_t* int_res, // output
const int32_t* int_a, // a
const int32_t* int_b, // b
uint8_t* tmp); // scratch space
/** @brief res = a * b centermod 1: small polynomial product */
void tnx32_small_single_product(const MOD_RNX* module, // N
int32_t* torus_res, // output
const int32_t* int_a, // a
const int32_t* torus_b, // b
uint8_t* tmp); // scratch space
void vec_rnx_to_znx32(MOD_RNX* module, // N
int32_t* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl // a
);
void vec_rnx_from_znx32(MOD_RNX* module, // N
double* res, uint64_t res_size, uint64_t res_sl, // res
const int32_t* a, uint64_t a_size, uint64_t a_sl // a
);
void vec_rnx_to_tnx32(MOD_RNX* module, // N
int32_t* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl // a
);
void vec_rnx_from_tnx32(MOD_RNX* module, // N
double* res, uint64_t res_size, uint64_t res_sl, // res
const int32_t* a, uint64_t a_size, uint64_t a_sl // a
);
void vec_rnx_to_tnx32x2(MOD_RNX* module, // N
int32_t* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl // a
);
void vec_rnx_from_tnx32x2(MOD_RNX* module, // N
double* res, uint64_t res_size, uint64_t res_sl, // res
const int32_t* a, uint64_t a_size, uint64_t a_sl // a
);
void vec_rnx_to_tnxdbl(MOD_RNX* module, // N
double* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl // a
);
/** @brief new gadget: delete with delete_tnx32_approxdec_gadget */
TNX32_APPROXDEC_GADGET* new_tnx32_approxdec_gadget(
const MOD_RNX* module // N
uint64_t k, uint64_t ell // base 2^K and size
);
/** @brief new gadget: delete with delete_tnx32_approxdec_gadget */
TNXDBL_APPROXDEC_GADGET* new_tnxdbl_approxdec_gadget(
const MOD_RNX* module, // N
uint64_t k, uint64_t ell // base 2^K and size
);
/** @brief new gadget: delete with delete_tnx32_approxdec_gadget */
TNX32X2_APPROXDEC_GADGET* new_tnx32x2_approxdec_gadget(
const MOD_RNX* module // N
uint64_t k, uint64_t ell // base 2^K and size
);
/** @brief sets res = gadget_decompose(a) */
void vec_rnx_approxdec_from_tnx32(
MOD_RNX* module, // N
const TNX32_APPROXDEC_GADGET* gadget, // output base 2^K
double* res, uint64_t res_size, uint64_t res_sl, // res
const int32_t* a, uint64_t a_size, uint64_t a_sl // a
);
/** @brief sets res = gadget_decompose(a) */
void vec_rnx_approxdec_from_tnx32x2(
const MOD_RNX* module, // N
const TNX32X2_APPROXDEC_GADGET* gadget, // output base 2^K
double* res, uint64_t res_size, uint64_t res_sl, // res
const int32_t* a, uint64_t a_size, uint64_t a_sl // a
);
/** @brief sets res = gadget_decompose(a) */
void vec_rnx_approxdec_from_tnxdbl(
const MOD_RNX* module, // N
const TNXDBL_APPROXDEC_GADGET* gadget, // output base 2^K
double* res, uint64_t res_size, uint64_t res_sl, // res
const double* a, uint64_t a_size, uint64_t a_sl // a
);
-
Allocate the space for a pmat matrix to the right dimension
/** @brief allocates a prepared matrix (release with delete_rnx_vmp_pmat) */ RNX_VMP_PMAT* new_rnx_vmp_pmat(const MOD_RNX* module, // N uint64_t nrows, uint64_t ncols); // dimensions // it also is possible to use a standard allocation function: // malloc/free, new int8_t[...]/delete[], // or spqlios_alloc/spqlios_free // in this case, the number of bytes to allocate are: /** @brief number of bytes in a RNX_VMP_PMAT (for manual allocation) */ uint64_t bytes_of_rnx_vmp_pmat(const MOD_RNX* module, // N uint64_t nrows, uint64_t ncols); // dimensions
-
Prepare the matrix
/** @brief prepares a vmp matrix (contiguous row-major version) */ void rnx_vmp_prepare_contiguous( MOD_RNX* module, // N RNX_VMP_PMAT* pmat, // output double* input_mat, nrows, ncols // a );
-
Execute a vector matrix product
/** @brief applies a vmp product res = a x pmat (result in DFT space) */ void rnx_vmp_apply_tmp_a( MOD_RNX* module, // N double* res, res_size, res_sl // res double* tmpa, a_size, a_sl, // a (will be overwritten) const VMP_PMAT* pmat, nrows, ncols // prep matrix );
It is possible to use dimensions
a_size <= nrows
andres_size <= ncols
. If the dimensions are smaller, this function will do a product with a submatrix.tmpa will be overwritten by the function: it the content is important, please copy it beforehand.
-
Remember that the product is done over
$\mathbb{R}_N[X]$ . If the result is meant to be mod 1, use the conversion or gadget decomposition functions.
-
Allocate the space for a pmat matrix to the right dimension
/** @brief allocates a prepared matrix (release with delete_rnx_vmp_pmat) */ RNX_SVP_PPOL* new_rnx_svp_ppol(const MOD_RNX* module); // N // it also is possible to use a standard allocation function: // malloc/free, new int8_t[...]/delete[], // or spqlios_alloc/spqlios_free // in this case, the number of bytes to allocate are: /** @brief number of bytes in a RNX_VMP_PMAT (for manual allocation) */ uint64_t bytes_of_rnx_svp_ppol(const MOD_RNX* module); // N
-
Prepare the vector
/** @brief prepares a svp polynomial */ void rnx_svp_prepare(const MOD_RNX* module, // N RNX_SVP_PPOL* ppol, // output const double* pol // a );
-
Execute a vector matrix product
/** @brief apply a svp product, result = ppol * a */ void rnx_svp_apply( const MOD_RNX* module, // N double* res, uint64_t res_size, uint64_t res_sl, // output const RNX_SVP_PPOL* ppol, // prepared pol const double* a, uint64_t a_size, uint64_t a_sl // a );
-
Remember that the product is done over
$\mathbb{R}_N[X]$ . If the result is meant to be mod 1, use the conversion or gadget decomposition functions.