second-round version of SQIsign
Co-authored-by: Marius A. Aardal <marius.andre.aardal@gmail.com> Co-authored-by: Gora Adj <gora.adj@tii.ae> Co-authored-by: Diego F. Aranha <dfaranha@cs.au.dk> Co-authored-by: Andrea Basso <sqisign@andreabasso.com> Co-authored-by: Isaac Andrés Canales Martínez <icanalesm0500@gmail.com> Co-authored-by: Jorge Chávez-Saab <jorgechavezsaab@gmail.com> Co-authored-by: Maria Corte-Real Santos <mariascrsantos98@gmail.com> Co-authored-by: Luca De Feo <github@defeo.lu> Co-authored-by: Max Duparc <max.duparc@epfl.ch> Co-authored-by: Jonathan Komada Eriksen <jonathan.eriksen97@gmail.com> Co-authored-by: Décio Luiz Gazzoni Filho <decio@decpp.net> Co-authored-by: Basil Hess <bhe@zurich.ibm.com> Co-authored-by: Antonin Leroux <antonin.leroux@polytechnique.org> Co-authored-by: Patrick Longa <plonga@microsoft.com> Co-authored-by: Luciano Maino <mainoluciano.96@gmail.com> Co-authored-by: Michael Meyer <michael@random-oracles.org> Co-authored-by: Hiroshi Onuki <onuki@mist.i.u-tokyo.ac.jp> Co-authored-by: Lorenz Panny <lorenz@yx7.cc> Co-authored-by: Giacomo Pope <giacomopope@gmail.com> Co-authored-by: Krijn Reijnders <reijnderskrijn@gmail.com> Co-authored-by: Damien Robert <damien.robert@inria.fr> Co-authored-by: Francisco Rodríguez-Henriquez <francisco.rodriguez@tii.ae> Co-authored-by: Sina Schaeffler <sschaeffle@student.ethz.ch> Co-authored-by: Benjamin Wesolowski <benjamin.wesolowski@ens-lyon.fr>
This commit is contained in:
committed by
Lorenz Panny
parent
ff34a8cd18
commit
91e9e464fe
@@ -1,18 +1,29 @@
|
||||
set(SOURCE_FILES_QUATERNION_GENERIC_REF
|
||||
intbig.c
|
||||
algebra.c
|
||||
ideal.c
|
||||
dim4.c
|
||||
dim2.c
|
||||
integers.c
|
||||
lattice.c
|
||||
lat_ball.c
|
||||
finit.c
|
||||
printer.c
|
||||
lll.c
|
||||
matkermod.c
|
||||
lll/rationals.c
|
||||
lll/l2.c
|
||||
lll/lll_verification.c
|
||||
lll/lll_applications.c
|
||||
lll/rationals.c
|
||||
normeq.c
|
||||
hnf/ibz_division.c
|
||||
hnf/hnf_internal.c
|
||||
hnf/hnf.c
|
||||
test/random_input_generation.c
|
||||
)
|
||||
|
||||
add_library(${LIB_QUATERNION} ${SOURCE_FILES_QUATERNION_GENERIC_REF})
|
||||
target_include_directories(${LIB_QUATERNION} PRIVATE common ${INC_PUBLIC} ${INC_COMMON} ${INC_INTBIG} ${INC_QUATERNION})
|
||||
add_library(${LIB_QUATERNION} STATIC ${SOURCE_FILES_QUATERNION_GENERIC_REF})
|
||||
target_link_libraries(${LIB_QUATERNION} GMP m)
|
||||
target_include_directories(${LIB_QUATERNION} PRIVATE common ${INC_PUBLIC} ${INC_COMMON} ${INC_QUATERNION} internal_quaternion_headers)
|
||||
target_compile_options(${LIB_QUATERNION} PRIVATE ${C_OPT_FLAGS})
|
||||
|
||||
add_subdirectory(test)
|
||||
|
||||
@@ -1,287 +1,280 @@
|
||||
#include <quaternion.h>
|
||||
#include "internal.h"
|
||||
|
||||
//Internal helper functions
|
||||
// Internal helper functions
|
||||
|
||||
//in internal.h:
|
||||
//static inline void quat_alg_init_set_ui(quat_alg_t *alg, unsigned int p) {
|
||||
// ibz_t bp;
|
||||
// ibz_init(&bp);
|
||||
// ibz_set(&bp, p);
|
||||
// quat_alg_init_set(alg, &bp);
|
||||
// ibz_finalize(&bp);
|
||||
//}
|
||||
|
||||
void quat_alg_coord_add(quat_alg_coord_t *res, const quat_alg_coord_t *a, const quat_alg_coord_t *b){
|
||||
ibz_add(&((*res)[0]),&((*a)[0]),&((*b)[0]));
|
||||
ibz_add(&((*res)[1]),&((*a)[1]),&((*b)[1]));
|
||||
ibz_add(&((*res)[2]),&((*a)[2]),&((*b)[2]));
|
||||
ibz_add(&((*res)[3]),&((*a)[3]),&((*b)[3]));
|
||||
void
|
||||
quat_alg_init_set_ui(quat_alg_t *alg, unsigned int p)
|
||||
{
|
||||
ibz_t bp;
|
||||
ibz_init(&bp);
|
||||
ibz_set(&bp, p);
|
||||
quat_alg_init_set(alg, &bp);
|
||||
ibz_finalize(&bp);
|
||||
}
|
||||
|
||||
void quat_alg_coord_sub(quat_alg_coord_t *res, const quat_alg_coord_t *a, const quat_alg_coord_t *b){
|
||||
ibz_sub(&((*res)[0]),&((*a)[0]),&((*b)[0]));
|
||||
ibz_sub(&((*res)[1]),&((*a)[1]),&((*b)[1]));
|
||||
ibz_sub(&((*res)[2]),&((*a)[2]),&((*b)[2]));
|
||||
ibz_sub(&((*res)[3]),&((*a)[3]),&((*b)[3]));
|
||||
void
|
||||
quat_alg_coord_mul(ibz_vec_4_t *res, const ibz_vec_4_t *a, const ibz_vec_4_t *b, const quat_alg_t *alg)
|
||||
{
|
||||
ibz_t prod;
|
||||
ibz_vec_4_t sum;
|
||||
ibz_init(&prod);
|
||||
ibz_vec_4_init(&sum);
|
||||
|
||||
ibz_set(&(sum[0]), 0);
|
||||
ibz_set(&(sum[1]), 0);
|
||||
ibz_set(&(sum[2]), 0);
|
||||
ibz_set(&(sum[3]), 0);
|
||||
|
||||
// compute 1 coordinate
|
||||
ibz_mul(&prod, &((*a)[2]), &((*b)[2]));
|
||||
ibz_sub(&(sum[0]), &(sum[0]), &prod);
|
||||
ibz_mul(&prod, &((*a)[3]), &((*b)[3]));
|
||||
ibz_sub(&(sum[0]), &(sum[0]), &prod);
|
||||
ibz_mul(&(sum[0]), &(sum[0]), &(alg->p));
|
||||
ibz_mul(&prod, &((*a)[0]), &((*b)[0]));
|
||||
ibz_add(&(sum[0]), &(sum[0]), &prod);
|
||||
ibz_mul(&prod, &((*a)[1]), &((*b)[1]));
|
||||
ibz_sub(&(sum[0]), &(sum[0]), &prod);
|
||||
// compute i coordiante
|
||||
ibz_mul(&prod, &((*a)[2]), &((*b)[3]));
|
||||
ibz_add(&(sum[1]), &(sum[1]), &prod);
|
||||
ibz_mul(&prod, &((*a)[3]), &((*b)[2]));
|
||||
ibz_sub(&(sum[1]), &(sum[1]), &prod);
|
||||
ibz_mul(&(sum[1]), &(sum[1]), &(alg->p));
|
||||
ibz_mul(&prod, &((*a)[0]), &((*b)[1]));
|
||||
ibz_add(&(sum[1]), &(sum[1]), &prod);
|
||||
ibz_mul(&prod, &((*a)[1]), &((*b)[0]));
|
||||
ibz_add(&(sum[1]), &(sum[1]), &prod);
|
||||
// compute j coordiante
|
||||
ibz_mul(&prod, &((*a)[0]), &((*b)[2]));
|
||||
ibz_add(&(sum[2]), &(sum[2]), &prod);
|
||||
ibz_mul(&prod, &((*a)[2]), &((*b)[0]));
|
||||
ibz_add(&(sum[2]), &(sum[2]), &prod);
|
||||
ibz_mul(&prod, &((*a)[1]), &((*b)[3]));
|
||||
ibz_sub(&(sum[2]), &(sum[2]), &prod);
|
||||
ibz_mul(&prod, &((*a)[3]), &((*b)[1]));
|
||||
ibz_add(&(sum[2]), &(sum[2]), &prod);
|
||||
// compute ij coordiante
|
||||
ibz_mul(&prod, &((*a)[0]), &((*b)[3]));
|
||||
ibz_add(&(sum[3]), &(sum[3]), &prod);
|
||||
ibz_mul(&prod, &((*a)[3]), &((*b)[0]));
|
||||
ibz_add(&(sum[3]), &(sum[3]), &prod);
|
||||
ibz_mul(&prod, &((*a)[2]), &((*b)[1]));
|
||||
ibz_sub(&(sum[3]), &(sum[3]), &prod);
|
||||
ibz_mul(&prod, &((*a)[1]), &((*b)[2]));
|
||||
ibz_add(&(sum[3]), &(sum[3]), &prod);
|
||||
|
||||
ibz_copy(&((*res)[0]), &(sum[0]));
|
||||
ibz_copy(&((*res)[1]), &(sum[1]));
|
||||
ibz_copy(&((*res)[2]), &(sum[2]));
|
||||
ibz_copy(&((*res)[3]), &(sum[3]));
|
||||
|
||||
ibz_finalize(&prod);
|
||||
ibz_vec_4_finalize(&sum);
|
||||
}
|
||||
|
||||
void quat_alg_equal_denom(quat_alg_elem_t *res_a, quat_alg_elem_t *res_b, const quat_alg_elem_t *a, const quat_alg_elem_t *b){
|
||||
ibz_t gcd, r;
|
||||
ibz_init(&gcd);
|
||||
ibz_init(&r);
|
||||
ibz_gcd(&gcd, &(a->denom), &(b->denom));
|
||||
//temporarily set res_a.denom to a.denom/gcd, and res_b.denom to b.denom/gcd
|
||||
ibz_div(&(res_a->denom), &r, &(a->denom), &gcd);
|
||||
ibz_div(&(res_b->denom), &r, &(b->denom), &gcd);
|
||||
for (int i = 0; i<4;i++){
|
||||
//multiply coordiates by reduced denominators from the other element
|
||||
ibz_mul(&(res_a->coord[i]), &(a->coord[i]), &(res_b->denom));
|
||||
ibz_mul(&(res_b->coord[i]), &(b->coord[i]), &(res_a->denom));
|
||||
}
|
||||
// multiply both reduced denominators
|
||||
ibz_mul(&(res_a->denom), &(res_a->denom), &(res_b->denom));
|
||||
// multiply them by the gcd to get the new common denominator
|
||||
ibz_mul(&(res_b->denom), &(res_a->denom), &gcd);
|
||||
ibz_mul(&(res_a->denom), &(res_a->denom), &gcd);
|
||||
ibz_finalize(&gcd);
|
||||
ibz_finalize(&r);
|
||||
}
|
||||
|
||||
//Public Functions
|
||||
|
||||
void quat_alg_add(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b){
|
||||
quat_alg_elem_t res_a, res_b;
|
||||
quat_alg_elem_init(&res_a);
|
||||
quat_alg_elem_init(&res_b);
|
||||
// put both on the same denominator
|
||||
quat_alg_equal_denom(&res_a,&res_b,a,b);
|
||||
//then add
|
||||
ibz_copy(&(res->denom), &(res_a.denom));
|
||||
quat_alg_coord_add(&(res->coord),&(res_a.coord),&(res_b.coord));
|
||||
quat_alg_elem_finalize(&res_a);
|
||||
quat_alg_elem_finalize(&res_b);
|
||||
}
|
||||
|
||||
void quat_alg_sub(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b){
|
||||
quat_alg_elem_t res_a, res_b;
|
||||
quat_alg_elem_init(&res_a);
|
||||
quat_alg_elem_init(&res_b);
|
||||
// put both on the same denominator
|
||||
quat_alg_equal_denom(&res_a,&res_b,a,b);
|
||||
//then substract
|
||||
ibz_copy(&res->denom, &res_a.denom);
|
||||
quat_alg_coord_sub(&res->coord,&res_a.coord,&res_b.coord);
|
||||
quat_alg_elem_finalize(&res_a);
|
||||
quat_alg_elem_finalize(&res_b);
|
||||
}
|
||||
|
||||
void quat_alg_mul(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b, const quat_alg_t *alg){
|
||||
ibz_t prod;
|
||||
quat_alg_coord_t sum;
|
||||
ibz_init(&prod);
|
||||
quat_alg_coord_init(&sum);
|
||||
|
||||
ibz_set(&(sum[0]), 0);
|
||||
ibz_set(&(sum[1]), 0);
|
||||
ibz_set(&(sum[2]), 0);
|
||||
ibz_set(&(sum[3]), 0);
|
||||
|
||||
//denominator: product of denominators
|
||||
ibz_mul(&(res->denom), &(a->denom),&(b->denom));
|
||||
|
||||
// compute 1 coordinate
|
||||
ibz_mul(&prod, &(a->coord[2]),&(b->coord[2]));
|
||||
ibz_sub(&(sum[0]),&(sum[0]),&prod);
|
||||
ibz_mul(&prod, &(a->coord[3]),&(b->coord[3]));
|
||||
ibz_sub(&(sum[0]),&(sum[0]),&prod);
|
||||
ibz_mul(&(sum[0]), &(sum[0]),&(alg->p));
|
||||
ibz_mul(&prod, &(a->coord[0]),&(b->coord[0]));
|
||||
ibz_add(&(sum[0]),&(sum[0]),&prod);
|
||||
ibz_mul(&prod, &(a->coord[1]),&(b->coord[1]));
|
||||
ibz_sub(&(sum[0]),&(sum[0]),&prod);
|
||||
// compute i coordiante
|
||||
ibz_mul(&prod, &(a->coord[2]),&(b->coord[3]));
|
||||
ibz_add(&(sum[1]),&(sum[1]),&prod);
|
||||
ibz_mul(&prod, &(a->coord[3]),&(b->coord[2]));
|
||||
ibz_sub(&(sum[1]),&(sum[1]),&prod);
|
||||
ibz_mul(&(sum[1]), &(sum[1]),&(alg->p));
|
||||
ibz_mul(&prod, &(a->coord[0]),&(b->coord[1]));
|
||||
ibz_add(&(sum[1]),&(sum[1]),&prod);
|
||||
ibz_mul(&prod, &(a->coord[1]),&(b->coord[0]));
|
||||
ibz_add(&(sum[1]),&(sum[1]),&prod);
|
||||
// compute j coordiante
|
||||
ibz_mul(&prod, &(a->coord[0]),&(b->coord[2]));
|
||||
ibz_add(&(sum[2]),&(sum[2]),&prod);
|
||||
ibz_mul(&prod, &(a->coord[2]),&(b->coord[0]));
|
||||
ibz_add(&(sum[2]),&(sum[2]),&prod);
|
||||
ibz_mul(&prod, &(a->coord[1]),&(b->coord[3]));
|
||||
ibz_sub(&(sum[2]),&(sum[2]),&prod);
|
||||
ibz_mul(&prod, &(a->coord[3]),&(b->coord[1]));
|
||||
ibz_add(&(sum[2]),&(sum[2]),&prod);
|
||||
// compute ij coordiante
|
||||
ibz_mul(&prod, &(a->coord[0]),&(b->coord[3]));
|
||||
ibz_add(&(sum[3]),&(sum[3]),&prod);
|
||||
ibz_mul(&prod, &(a->coord[3]),&(b->coord[0]));
|
||||
ibz_add(&(sum[3]),&(sum[3]),&prod);
|
||||
ibz_mul(&prod, &(a->coord[2]),&(b->coord[1]));
|
||||
ibz_sub(&(sum[3]),&(sum[3]),&prod);
|
||||
ibz_mul(&prod, &(a->coord[1]),&(b->coord[2]));
|
||||
ibz_add(&(sum[3]),&(sum[3]),&prod);
|
||||
|
||||
ibz_copy(&(res->coord[0]),&(sum[0]));
|
||||
ibz_copy(&(res->coord[1]),&(sum[1]));
|
||||
ibz_copy(&(res->coord[2]),&(sum[2]));
|
||||
ibz_copy(&(res->coord[3]),&(sum[3]));
|
||||
|
||||
ibz_finalize(&prod);
|
||||
quat_alg_coord_finalize(&sum);
|
||||
}
|
||||
|
||||
void quat_alg_rightmul_mat(ibz_mat_4x4_t *mulmat, const quat_alg_elem_t *a, const quat_alg_t *alg) {
|
||||
quat_alg_elem_t e, res;
|
||||
quat_alg_elem_init(&e);
|
||||
quat_alg_elem_init(&res);
|
||||
void
|
||||
quat_alg_equal_denom(quat_alg_elem_t *res_a, quat_alg_elem_t *res_b, const quat_alg_elem_t *a, const quat_alg_elem_t *b)
|
||||
{
|
||||
ibz_t gcd, r;
|
||||
ibz_init(&gcd);
|
||||
ibz_init(&r);
|
||||
ibz_gcd(&gcd, &(a->denom), &(b->denom));
|
||||
// temporarily set res_a.denom to a.denom/gcd, and res_b.denom to b.denom/gcd
|
||||
ibz_div(&(res_a->denom), &r, &(a->denom), &gcd);
|
||||
ibz_div(&(res_b->denom), &r, &(b->denom), &gcd);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// i-th standard basis vector
|
||||
if (i)
|
||||
ibz_set(&e.coord[i-1], 0);
|
||||
ibz_set(&e.coord[i], 1);
|
||||
quat_alg_mul(&res, &e, a, alg);
|
||||
for (int j = 0; j < 4; j++)
|
||||
ibz_copy(&(*mulmat)[j][i], &res.coord[j]);
|
||||
// multiply coordiates by reduced denominators from the other element
|
||||
ibz_mul(&(res_a->coord[i]), &(a->coord[i]), &(res_b->denom));
|
||||
ibz_mul(&(res_b->coord[i]), &(b->coord[i]), &(res_a->denom));
|
||||
}
|
||||
quat_alg_elem_finalize(&e);
|
||||
quat_alg_elem_finalize(&res);
|
||||
// multiply both reduced denominators
|
||||
ibz_mul(&(res_a->denom), &(res_a->denom), &(res_b->denom));
|
||||
// multiply them by the gcd to get the new common denominator
|
||||
ibz_mul(&(res_b->denom), &(res_a->denom), &gcd);
|
||||
ibz_mul(&(res_a->denom), &(res_a->denom), &gcd);
|
||||
ibz_finalize(&gcd);
|
||||
ibz_finalize(&r);
|
||||
}
|
||||
|
||||
void quat_alg_norm(ibq_t *res, const quat_alg_elem_t *a, const quat_alg_t *alg){
|
||||
quat_alg_elem_t conj, norm;
|
||||
quat_alg_elem_init(&conj);
|
||||
quat_alg_elem_init(&norm);
|
||||
|
||||
quat_alg_conj(&conj,a);
|
||||
quat_alg_mul(&norm,a,&conj,alg);
|
||||
ibq_set(res,&(norm.coord[0]),&(norm.denom));
|
||||
// Public Functions
|
||||
|
||||
quat_alg_elem_finalize(&conj);
|
||||
quat_alg_elem_finalize(&norm);
|
||||
void
|
||||
quat_alg_add(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b)
|
||||
{
|
||||
quat_alg_elem_t res_a, res_b;
|
||||
quat_alg_elem_init(&res_a);
|
||||
quat_alg_elem_init(&res_b);
|
||||
// put both on the same denominator
|
||||
quat_alg_equal_denom(&res_a, &res_b, a, b);
|
||||
// then add
|
||||
ibz_copy(&(res->denom), &(res_a.denom));
|
||||
ibz_vec_4_add(&(res->coord), &(res_a.coord), &(res_b.coord));
|
||||
quat_alg_elem_finalize(&res_a);
|
||||
quat_alg_elem_finalize(&res_b);
|
||||
}
|
||||
|
||||
void quat_alg_trace(ibq_t *res, const quat_alg_elem_t *a){
|
||||
quat_alg_elem_t trace;
|
||||
quat_alg_elem_init(&trace);
|
||||
|
||||
ibz_copy(&(trace.denom), &(a->denom));
|
||||
ibz_add(&(trace.coord[0]),&(a->coord[0]),&(a->coord[0]));
|
||||
ibz_sub(&(trace.coord[1]),&(a->coord[1]),&(a->coord[1]));
|
||||
ibz_sub(&(trace.coord[2]),&(a->coord[2]),&(a->coord[2]));
|
||||
ibz_sub(&(trace.coord[3]),&(a->coord[3]),&(a->coord[3]));
|
||||
ibq_set(res,&(trace.coord[0]),&(trace.denom));
|
||||
|
||||
quat_alg_elem_finalize(&trace);
|
||||
void
|
||||
quat_alg_sub(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b)
|
||||
{
|
||||
quat_alg_elem_t res_a, res_b;
|
||||
quat_alg_elem_init(&res_a);
|
||||
quat_alg_elem_init(&res_b);
|
||||
// put both on the same denominator
|
||||
quat_alg_equal_denom(&res_a, &res_b, a, b);
|
||||
// then substract
|
||||
ibz_copy(&res->denom, &res_a.denom);
|
||||
ibz_vec_4_sub(&res->coord, &res_a.coord, &res_b.coord);
|
||||
quat_alg_elem_finalize(&res_a);
|
||||
quat_alg_elem_finalize(&res_b);
|
||||
}
|
||||
|
||||
void quat_alg_scalar(quat_alg_elem_t *elem, const ibz_t *numerator, const ibz_t *denominator){
|
||||
ibz_copy(&(elem->denom),denominator);
|
||||
ibz_copy(&(elem->coord[0]),numerator);
|
||||
ibz_set(&(elem->coord[1]),0);
|
||||
ibz_set(&(elem->coord[2]),0);
|
||||
ibz_set(&(elem->coord[3]),0);
|
||||
void
|
||||
quat_alg_mul(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b, const quat_alg_t *alg)
|
||||
{
|
||||
// denominator: product of denominators
|
||||
ibz_mul(&(res->denom), &(a->denom), &(b->denom));
|
||||
quat_alg_coord_mul(&(res->coord), &(a->coord), &(b->coord), alg);
|
||||
}
|
||||
|
||||
void quat_alg_conj(quat_alg_elem_t *conj, const quat_alg_elem_t *x){
|
||||
ibz_copy(&(conj->denom), &(x->denom));
|
||||
ibz_copy(&(conj->coord[0]),&(x->coord[0]));
|
||||
ibz_neg(&(conj->coord[1]),&(x->coord[1]));
|
||||
ibz_neg(&(conj->coord[2]),&(x->coord[2]));
|
||||
ibz_neg(&(conj->coord[3]),&(x->coord[3]));
|
||||
void
|
||||
quat_alg_norm(ibz_t *res_num, ibz_t *res_denom, const quat_alg_elem_t *a, const quat_alg_t *alg)
|
||||
{
|
||||
ibz_t r, g;
|
||||
quat_alg_elem_t norm;
|
||||
ibz_init(&r);
|
||||
ibz_init(&g);
|
||||
quat_alg_elem_init(&norm);
|
||||
|
||||
quat_alg_conj(&norm, a);
|
||||
quat_alg_mul(&norm, a, &norm, alg);
|
||||
ibz_gcd(&g, &(norm.coord[0]), &(norm.denom));
|
||||
ibz_div(res_num, &r, &(norm.coord[0]), &g);
|
||||
ibz_div(res_denom, &r, &(norm.denom), &g);
|
||||
ibz_abs(res_denom, res_denom);
|
||||
ibz_abs(res_num, res_num);
|
||||
assert(ibz_cmp(res_denom, &ibz_const_zero) > 0);
|
||||
|
||||
quat_alg_elem_finalize(&norm);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&g);
|
||||
}
|
||||
|
||||
//defined in header
|
||||
//int quat_alg_is_primitive(const quat_alg_elem_t *x, const quat_order_t *order, const quat_alg_t *alg) {
|
||||
// quat_alg_coord_t *coord;
|
||||
// quat_alg_coord_init(coord);
|
||||
// int ok = quat_lattice_contains(coord, order, x);
|
||||
//assert(ok);
|
||||
//unused(ok);
|
||||
// ibz_t *cnt;
|
||||
// ibz_init(cnt);
|
||||
// ibz_content(cnt, coord);
|
||||
// ok = ibz_is_one(cnt);
|
||||
// ibz_finalize(cnt);
|
||||
// quat_alg_coord_finalize(coord);
|
||||
// return ok;
|
||||
//}
|
||||
//
|
||||
//static inline void quat_alg_make_primitive(quat_alg_coord_t *primitive_x, ibz_t *content, const quat_alg_elem_t *x, const quat_order_t *order, const quat_alg_t *alg){
|
||||
// int ok = quat_lattice_contains(primitive_x, order, x);
|
||||
//assert(ok);
|
||||
//unused(ok);
|
||||
// ibz_content(content, primitive_x);
|
||||
// for(int i = 0; i <4; i++){
|
||||
// ibz_div(primitive_x[i], NULL, primitive_x[i], content);
|
||||
// }
|
||||
//}
|
||||
void
|
||||
quat_alg_scalar(quat_alg_elem_t *elem, const ibz_t *numerator, const ibz_t *denominator)
|
||||
{
|
||||
ibz_copy(&(elem->denom), denominator);
|
||||
ibz_copy(&(elem->coord[0]), numerator);
|
||||
ibz_set(&(elem->coord[1]), 0);
|
||||
ibz_set(&(elem->coord[2]), 0);
|
||||
ibz_set(&(elem->coord[3]), 0);
|
||||
}
|
||||
|
||||
void quat_alg_normalize(quat_alg_elem_t *x){
|
||||
ibz_t gcd,r, zero;
|
||||
ibz_init(&gcd);
|
||||
ibz_init(&r);
|
||||
ibz_init(&zero);
|
||||
ibz_content(&gcd,&(x->coord));
|
||||
ibz_gcd(&gcd,&gcd,&(x->denom));
|
||||
ibz_div(&(x->denom),&r,&(x->denom),&gcd);
|
||||
for (int i = 0; i < 4; i++){
|
||||
ibz_div(&(x->coord[i]),&r,&(x->coord[i]),&gcd);
|
||||
}
|
||||
ibz_set(&zero,0);
|
||||
if (0<ibz_cmp(&zero,&(x->denom))){
|
||||
for (int i = 0; i < 4; i++){
|
||||
ibz_neg(&(x->coord[i]),&(x->coord[i]));
|
||||
void
|
||||
quat_alg_conj(quat_alg_elem_t *conj, const quat_alg_elem_t *x)
|
||||
{
|
||||
ibz_copy(&(conj->denom), &(x->denom));
|
||||
ibz_copy(&(conj->coord[0]), &(x->coord[0]));
|
||||
ibz_neg(&(conj->coord[1]), &(x->coord[1]));
|
||||
ibz_neg(&(conj->coord[2]), &(x->coord[2]));
|
||||
ibz_neg(&(conj->coord[3]), &(x->coord[3]));
|
||||
}
|
||||
|
||||
void
|
||||
quat_alg_make_primitive(ibz_vec_4_t *primitive_x, ibz_t *content, const quat_alg_elem_t *x, const quat_lattice_t *order)
|
||||
{
|
||||
int ok UNUSED = quat_lattice_contains(primitive_x, order, x);
|
||||
assert(ok);
|
||||
ibz_vec_4_content(content, primitive_x);
|
||||
ibz_t r;
|
||||
ibz_init(&r);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_div(*primitive_x + i, &r, *primitive_x + i, content);
|
||||
}
|
||||
ibz_neg(&(x->denom),&(x->denom));
|
||||
}
|
||||
ibz_finalize(&gcd);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&zero);
|
||||
ibz_finalize(&r);
|
||||
}
|
||||
|
||||
int quat_alg_elem_is_zero(const quat_alg_elem_t *x){
|
||||
int res = quat_alg_coord_is_zero(&(x->coord));
|
||||
return(res);
|
||||
void
|
||||
quat_alg_normalize(quat_alg_elem_t *x)
|
||||
{
|
||||
ibz_t gcd, sign, r;
|
||||
ibz_init(&gcd);
|
||||
ibz_init(&sign);
|
||||
ibz_init(&r);
|
||||
ibz_vec_4_content(&gcd, &(x->coord));
|
||||
ibz_gcd(&gcd, &gcd, &(x->denom));
|
||||
ibz_div(&(x->denom), &r, &(x->denom), &gcd);
|
||||
ibz_vec_4_scalar_div(&(x->coord), &gcd, &(x->coord));
|
||||
ibz_set(&sign, 2 * (0 > ibz_cmp(&ibz_const_zero, &(x->denom))) - 1);
|
||||
ibz_vec_4_scalar_mul(&(x->coord), &sign, &(x->coord));
|
||||
ibz_mul(&(x->denom), &sign, &(x->denom));
|
||||
ibz_finalize(&gcd);
|
||||
ibz_finalize(&sign);
|
||||
ibz_finalize(&r);
|
||||
}
|
||||
|
||||
int quat_alg_coord_is_zero(const quat_alg_coord_t *x){
|
||||
int res = 1;
|
||||
for (int i = 0; i < 4; i++){
|
||||
res &= ibz_is_zero(&((*x)[i]));
|
||||
}
|
||||
return(res);
|
||||
int
|
||||
quat_alg_elem_equal(const quat_alg_elem_t *a, const quat_alg_elem_t *b)
|
||||
{
|
||||
quat_alg_elem_t diff;
|
||||
quat_alg_elem_init(&diff);
|
||||
quat_alg_sub(&diff, a, b);
|
||||
int res = quat_alg_elem_is_zero(&diff);
|
||||
quat_alg_elem_finalize(&diff);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// helper functions for lattices
|
||||
void quat_alg_elem_copy_ibz(quat_alg_elem_t *elem, const ibz_t *denom, const ibz_t *coord0,const ibz_t *coord1,const ibz_t *coord2,const ibz_t *coord3){
|
||||
ibz_copy(&(elem->coord[0]), coord0);
|
||||
ibz_copy(&(elem->coord[1]), coord1);
|
||||
ibz_copy(&(elem->coord[2]), coord2);
|
||||
ibz_copy(&(elem->coord[3]), coord3);
|
||||
|
||||
ibz_copy(&(elem->denom),denom);
|
||||
int
|
||||
quat_alg_elem_is_zero(const quat_alg_elem_t *x)
|
||||
{
|
||||
int res = ibz_vec_4_is_zero(&(x->coord));
|
||||
return (res);
|
||||
}
|
||||
|
||||
void quat_alg_elem_set(quat_alg_elem_t *elem, int64_t denom, int64_t coord0, int64_t coord1, int64_t coord2, int64_t coord3){
|
||||
void
|
||||
quat_alg_elem_set(quat_alg_elem_t *elem, int32_t denom, int32_t coord0, int32_t coord1, int32_t coord2, int32_t coord3)
|
||||
{
|
||||
ibz_set(&(elem->coord[0]), coord0);
|
||||
ibz_set(&(elem->coord[1]), coord1);
|
||||
ibz_set(&(elem->coord[2]), coord2);
|
||||
ibz_set(&(elem->coord[3]), coord3);
|
||||
|
||||
ibz_set(&(elem->denom),denom);
|
||||
ibz_set(&(elem->denom), denom);
|
||||
}
|
||||
|
||||
void quat_alg_elem_mul_by_scalar(quat_alg_elem_t *res, const ibz_t *scalar, const quat_alg_elem_t *elem){
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_mul(&(res->coord[i]), &(elem->coord[i]),scalar);
|
||||
}
|
||||
ibz_copy(&(res->denom),&(elem->denom));
|
||||
void
|
||||
quat_alg_elem_copy(quat_alg_elem_t *copy, const quat_alg_elem_t *copied)
|
||||
{
|
||||
ibz_copy(©->denom, &copied->denom);
|
||||
ibz_copy(©->coord[0], &copied->coord[0]);
|
||||
ibz_copy(©->coord[1], &copied->coord[1]);
|
||||
ibz_copy(©->coord[2], &copied->coord[2]);
|
||||
ibz_copy(©->coord[3], &copied->coord[3]);
|
||||
}
|
||||
|
||||
// helper functions for lattices
|
||||
void
|
||||
quat_alg_elem_copy_ibz(quat_alg_elem_t *elem,
|
||||
const ibz_t *denom,
|
||||
const ibz_t *coord0,
|
||||
const ibz_t *coord1,
|
||||
const ibz_t *coord2,
|
||||
const ibz_t *coord3)
|
||||
{
|
||||
ibz_copy(&(elem->coord[0]), coord0);
|
||||
ibz_copy(&(elem->coord[1]), coord1);
|
||||
ibz_copy(&(elem->coord[2]), coord2);
|
||||
ibz_copy(&(elem->coord[3]), coord3);
|
||||
|
||||
ibz_copy(&(elem->denom), denom);
|
||||
}
|
||||
|
||||
void
|
||||
quat_alg_elem_mul_by_scalar(quat_alg_elem_t *res, const ibz_t *scalar, const quat_alg_elem_t *elem)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_mul(&(res->coord[i]), &(elem->coord[i]), scalar);
|
||||
}
|
||||
ibz_copy(&(res->denom), &(elem->denom));
|
||||
}
|
||||
|
||||
@@ -1,40 +1,66 @@
|
||||
#include <quaternion.h>
|
||||
#include "internal.h"
|
||||
|
||||
//internal helpers, also for other files
|
||||
void ibz_vec_2_set(ibz_vec_2_t *vec, int a0, int a1){
|
||||
ibz_set(&((*vec)[0]),a0);
|
||||
ibz_set(&((*vec)[1]),a1);
|
||||
// internal helpers, also for other files
|
||||
void
|
||||
ibz_vec_2_set(ibz_vec_2_t *vec, int a0, int a1)
|
||||
{
|
||||
ibz_set(&((*vec)[0]), a0);
|
||||
ibz_set(&((*vec)[1]), a1);
|
||||
}
|
||||
void ibz_mat_2x2_set(ibz_mat_2x2_t *mat, int a00, int a01, int a10, int a11){
|
||||
ibz_set(&((*mat)[0][0]),a00);
|
||||
ibz_set(&((*mat)[0][1]),a01);
|
||||
ibz_set(&((*mat)[1][0]),a10);
|
||||
ibz_set(&((*mat)[1][1]),a11);
|
||||
void
|
||||
ibz_mat_2x2_set(ibz_mat_2x2_t *mat, int a00, int a01, int a10, int a11)
|
||||
{
|
||||
ibz_set(&((*mat)[0][0]), a00);
|
||||
ibz_set(&((*mat)[0][1]), a01);
|
||||
ibz_set(&((*mat)[1][0]), a10);
|
||||
ibz_set(&((*mat)[1][1]), a11);
|
||||
}
|
||||
|
||||
void ibz_mat_2x2_det_from_ibz(ibz_t *det, const ibz_t *a11, const ibz_t *a12, const ibz_t *a21, const ibz_t *a22){
|
||||
void
|
||||
ibz_mat_2x2_copy(ibz_mat_2x2_t *copy, const ibz_mat_2x2_t *copied)
|
||||
{
|
||||
ibz_copy(&((*copy)[0][0]), &((*copied)[0][0]));
|
||||
ibz_copy(&((*copy)[0][1]), &((*copied)[0][1]));
|
||||
ibz_copy(&((*copy)[1][0]), &((*copied)[1][0]));
|
||||
ibz_copy(&((*copy)[1][1]), &((*copied)[1][1]));
|
||||
}
|
||||
|
||||
void
|
||||
ibz_mat_2x2_add(ibz_mat_2x2_t *sum, const ibz_mat_2x2_t *a, const ibz_mat_2x2_t *b)
|
||||
{
|
||||
ibz_add(&((*sum)[0][0]), &((*a)[0][0]), &((*b)[0][0]));
|
||||
ibz_add(&((*sum)[0][1]), &((*a)[0][1]), &((*b)[0][1]));
|
||||
ibz_add(&((*sum)[1][0]), &((*a)[1][0]), &((*b)[1][0]));
|
||||
ibz_add(&((*sum)[1][1]), &((*a)[1][1]), &((*b)[1][1]));
|
||||
}
|
||||
|
||||
void
|
||||
ibz_mat_2x2_det_from_ibz(ibz_t *det, const ibz_t *a11, const ibz_t *a12, const ibz_t *a21, const ibz_t *a22)
|
||||
{
|
||||
ibz_t prod;
|
||||
ibz_init(&prod);
|
||||
ibz_mul(&prod,a12,a21);
|
||||
ibz_mul(det,a11,a22);
|
||||
ibz_sub(det,det,&prod);
|
||||
ibz_mul(&prod, a12, a21);
|
||||
ibz_mul(det, a11, a22);
|
||||
ibz_sub(det, det, &prod);
|
||||
ibz_finalize(&prod);
|
||||
}
|
||||
|
||||
void ibz_mat_2x2_eval(ibz_vec_2_t *res, const ibz_mat_2x2_t *mat, const ibz_vec_2_t *vec){
|
||||
void
|
||||
ibz_mat_2x2_eval(ibz_vec_2_t *res, const ibz_mat_2x2_t *mat, const ibz_vec_2_t *vec)
|
||||
{
|
||||
ibz_t prod;
|
||||
ibz_vec_2_t matvec;
|
||||
ibz_init(&prod);
|
||||
ibz_vec_2_init(&matvec);
|
||||
ibz_mul(&prod,&((*mat)[0][0]),&((*vec)[0]));
|
||||
ibz_mul(&prod, &((*mat)[0][0]), &((*vec)[0]));
|
||||
ibz_copy(&(matvec[0]), &prod);
|
||||
ibz_mul(&prod,&((*mat)[0][1]),&((*vec)[1]));
|
||||
ibz_add(&(matvec[0]),&(matvec[0]), &prod);
|
||||
ibz_mul(&prod,&((*mat)[1][0]),&((*vec)[0]));
|
||||
ibz_mul(&prod, &((*mat)[0][1]), &((*vec)[1]));
|
||||
ibz_add(&(matvec[0]), &(matvec[0]), &prod);
|
||||
ibz_mul(&prod, &((*mat)[1][0]), &((*vec)[0]));
|
||||
ibz_copy(&(matvec[1]), &prod);
|
||||
ibz_mul(&prod,&((*mat)[1][1]),&((*vec)[1]));
|
||||
ibz_add(&(matvec[1]),&(matvec[1]), &prod);
|
||||
ibz_mul(&prod, &((*mat)[1][1]), &((*vec)[1]));
|
||||
ibz_add(&(matvec[1]), &(matvec[1]), &prod);
|
||||
ibz_copy(&((*res)[0]), &(matvec[0]));
|
||||
ibz_copy(&((*res)[1]), &(matvec[1]));
|
||||
ibz_finalize(&prod);
|
||||
@@ -43,511 +69,64 @@ void ibz_mat_2x2_eval(ibz_vec_2_t *res, const ibz_mat_2x2_t *mat, const ibz_vec_
|
||||
|
||||
// modular 2x2 operations
|
||||
|
||||
void ibz_2x2_mul_mod(ibz_mat_2x2_t *prod, const ibz_mat_2x2_t *mat_a, const ibz_mat_2x2_t *mat_b, const ibz_t *m){
|
||||
void
|
||||
ibz_2x2_mul_mod(ibz_mat_2x2_t *prod, const ibz_mat_2x2_t *mat_a, const ibz_mat_2x2_t *mat_b, const ibz_t *m)
|
||||
{
|
||||
ibz_t mul;
|
||||
ibz_mat_2x2_t sums;
|
||||
ibz_init(&mul);
|
||||
ibz_mat_2x2_init(&sums);
|
||||
for(int i = 0; i < 2; i++){
|
||||
for(int j = 0; j < 2; j++){
|
||||
ibz_set(&(sums[i][j]),0);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
ibz_set(&(sums[i][j]), 0);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < 2; i++){
|
||||
for(int j = 0; j < 2; j++){
|
||||
for(int k = 0; k < 2; k++){
|
||||
ibz_mul(&mul,&((*mat_a)[i][k]), &((*mat_b)[k][j]));
|
||||
ibz_add(&(sums[i][j]),&(sums[i][j]), &mul);
|
||||
ibz_mod(&(sums[i][j]),&(sums[i][j]), m);
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
for (int k = 0; k < 2; k++) {
|
||||
ibz_mul(&mul, &((*mat_a)[i][k]), &((*mat_b)[k][j]));
|
||||
ibz_add(&(sums[i][j]), &(sums[i][j]), &mul);
|
||||
ibz_mod(&(sums[i][j]), &(sums[i][j]), m);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < 2; i++){
|
||||
for(int j = 0; j < 2; j++){
|
||||
ibz_copy(&((*prod)[i][j]),&(sums[i][j]));
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
ibz_copy(&((*prod)[i][j]), &(sums[i][j]));
|
||||
}
|
||||
}
|
||||
ibz_finalize(&mul);
|
||||
ibz_mat_2x2_finalize(&sums);
|
||||
}
|
||||
|
||||
int ibz_2x2_inv_mod(ibz_mat_2x2_t *inv, const ibz_mat_2x2_t *mat, const ibz_t *m){
|
||||
ibz_t det, prod;
|
||||
int
|
||||
ibz_mat_2x2_inv_mod(ibz_mat_2x2_t *inv, const ibz_mat_2x2_t *mat, const ibz_t *m)
|
||||
{
|
||||
ibz_t det, prod;
|
||||
ibz_init(&det);
|
||||
ibz_init(&prod);
|
||||
ibz_mul(&det,&((*mat)[0][0]),&((*mat)[1][1]));
|
||||
ibz_mod(&det,&det,m);
|
||||
ibz_mul(&prod,&((*mat)[0][1]),&((*mat)[1][0]));
|
||||
ibz_sub(&det,&det,&prod);
|
||||
ibz_mod(&det,&det,m);
|
||||
int res = ibz_invmod(&det,&det,m);
|
||||
if(res){
|
||||
ibz_copy(&prod,&((*mat)[0][0]));
|
||||
ibz_copy(&((*inv)[0][0]), &((*mat)[1][1]));
|
||||
ibz_copy(&((*inv)[1][1]), &prod);
|
||||
ibz_neg(&((*inv)[1][0]), &((*mat)[1][0]));
|
||||
ibz_neg(&((*inv)[0][1]), &((*mat)[0][1]));
|
||||
for(int i = 0; i<2;i++){
|
||||
for(int j = 0; j<2;j++){
|
||||
ibz_mul(&((*inv)[i][j]),&((*inv)[i][j]),&det);
|
||||
ibz_mod(&((*inv)[i][j]),&((*inv)[i][j]),m);
|
||||
}
|
||||
ibz_mul(&det, &((*mat)[0][0]), &((*mat)[1][1]));
|
||||
ibz_mod(&det, &det, m);
|
||||
ibz_mul(&prod, &((*mat)[0][1]), &((*mat)[1][0]));
|
||||
ibz_sub(&det, &det, &prod);
|
||||
ibz_mod(&det, &det, m);
|
||||
int res = ibz_invmod(&det, &det, m);
|
||||
// return 0 matrix if non invertible determinant
|
||||
ibz_set(&prod, res);
|
||||
ibz_mul(&det, &det, &prod);
|
||||
// compute inverse
|
||||
ibz_copy(&prod, &((*mat)[0][0]));
|
||||
ibz_copy(&((*inv)[0][0]), &((*mat)[1][1]));
|
||||
ibz_copy(&((*inv)[1][1]), &prod);
|
||||
ibz_neg(&((*inv)[1][0]), &((*mat)[1][0]));
|
||||
ibz_neg(&((*inv)[0][1]), &((*mat)[0][1]));
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
ibz_mul(&((*inv)[i][j]), &((*inv)[i][j]), &det);
|
||||
ibz_mod(&((*inv)[i][j]), &((*inv)[i][j]), m);
|
||||
}
|
||||
}
|
||||
ibz_finalize(&det);
|
||||
ibz_finalize(&prod);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//helper for cvp
|
||||
int quat_dim2_lattice_contains(ibz_mat_2x2_t *basis, ibz_t *coord1, ibz_t *coord2){
|
||||
int res = 1;
|
||||
ibz_t prod, sum, det, r;
|
||||
ibz_init(&det);
|
||||
ibz_init(&r);
|
||||
ibz_init(&sum);
|
||||
ibz_init(&prod);
|
||||
// compute det, then both coordinates (inverse*det)*vec, where vec is (coord1, coord2) and check wthether det divides both results
|
||||
ibz_mat_2x2_det_from_ibz(&det, &((*basis)[0][0]), &((*basis)[0][1]), &((*basis)[1][0]), &((*basis)[1][1]));
|
||||
ibz_mul(&sum,coord1,&((*basis)[1][1]));
|
||||
ibz_mul(&prod,coord2,&((*basis)[0][1]));
|
||||
ibz_sub(&sum,&sum,&prod);
|
||||
ibz_div(&prod,&r,&sum,&det);
|
||||
res = res && ibz_is_zero(&r);
|
||||
ibz_mul(&sum,coord2,&((*basis)[0][0]));
|
||||
ibz_mul(&prod,coord1,&((*basis)[1][0]));
|
||||
ibz_sub(&sum,&sum,&prod);
|
||||
ibz_div(&prod,&r,&sum,&det);
|
||||
res = res && ibz_is_zero(&r);
|
||||
ibz_finalize(&det);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&sum);
|
||||
ibz_finalize(&prod);
|
||||
return(res);
|
||||
}
|
||||
|
||||
void quat_dim2_lattice_norm(ibz_t *norm, const ibz_t *coord1, const ibz_t *coord2, const ibz_t *norm_q){
|
||||
ibz_t prod, sum;
|
||||
ibz_init(&prod);
|
||||
ibz_init(&sum);
|
||||
ibz_mul(&sum,coord1,coord1);
|
||||
ibz_mul(&prod,coord2,coord2);
|
||||
ibz_mul(&prod,&prod,norm_q);
|
||||
ibz_add(norm,&sum,&prod);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&sum);
|
||||
}
|
||||
|
||||
void quat_dim2_lattice_bilinear(ibz_t *res, const ibz_t *v11, const ibz_t *v12,const ibz_t *v21, const ibz_t *v22, const ibz_t *norm_q){
|
||||
ibz_t prod, sum;
|
||||
ibz_init(&prod);
|
||||
ibz_init(&sum);
|
||||
ibz_mul(&sum,v11,v21);
|
||||
ibz_mul(&prod,v12,v22);
|
||||
ibz_mul(&prod,&prod,norm_q);
|
||||
ibz_add(res,&sum,&prod);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&sum);
|
||||
}
|
||||
|
||||
// algo 3.1.14 Cohen (exact solution for shortest vector in dimension 2, than take a second, orthogonal vector)
|
||||
void quat_dim2_lattice_short_basis(ibz_mat_2x2_t *reduced, const ibz_mat_2x2_t *basis, const ibz_t *norm_q){
|
||||
ibz_vec_2_t a,b,t;
|
||||
ibz_t prod,sum, norm_a, norm_b, r, norm_t, n;
|
||||
ibz_vec_2_init(&a);
|
||||
ibz_vec_2_init(&b);
|
||||
ibz_vec_2_init(&t);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&sum);
|
||||
ibz_init(&r);
|
||||
ibz_init(&n);
|
||||
ibz_init(&norm_t);
|
||||
ibz_init(&norm_a);
|
||||
ibz_init(&norm_b);
|
||||
// init a,b
|
||||
ibz_copy(&(a[0]),&((*basis)[0][0]));
|
||||
ibz_copy(&(a[1]),&((*basis)[1][0]));
|
||||
ibz_copy(&(b[0]),&((*basis)[0][1]));
|
||||
ibz_copy(&(b[1]),&((*basis)[1][1]));
|
||||
// compute initial norms
|
||||
quat_dim2_lattice_norm(&norm_a,&(a[0]),&(a[1]), norm_q);
|
||||
quat_dim2_lattice_norm(&norm_b,&(b[0]),&(b[1]), norm_q);
|
||||
// exchange if needed
|
||||
if(ibz_cmp(&norm_a,&norm_b)<0){
|
||||
ibz_copy(&sum,&(a[0]));
|
||||
ibz_copy(&(a[0]),&(b[0]));
|
||||
ibz_copy(&(b[0]),&sum);
|
||||
ibz_copy(&sum,&(a[1]));
|
||||
ibz_copy(&(a[1]),&(b[1]));
|
||||
ibz_copy(&(b[1]),&sum);
|
||||
ibz_copy(&sum,&norm_a);
|
||||
ibz_copy(&norm_a,&norm_b);
|
||||
ibz_copy(&norm_b,&sum);
|
||||
}
|
||||
int test = 1;
|
||||
while(test){
|
||||
//compute n
|
||||
quat_dim2_lattice_bilinear(&n,&(a[0]),&(a[1]),&(b[0]),&(b[1]),norm_q);
|
||||
// set r
|
||||
ibz_rounded_div(&r,&n,&norm_b);
|
||||
// compute t_norm
|
||||
ibz_set(&prod,2);
|
||||
ibz_mul(&prod,&prod,&n);
|
||||
ibz_mul(&prod,&prod,&r);
|
||||
ibz_sub(&sum,&norm_a,&prod);
|
||||
ibz_mul(&prod,&r,&r);
|
||||
ibz_mul(&prod,&prod,&norm_b);
|
||||
ibz_add(&norm_t,&sum,&prod);
|
||||
// test:
|
||||
if(ibz_cmp(&norm_b,&norm_t)>0){
|
||||
// compute t, a, b
|
||||
ibz_copy(&norm_a,&norm_b);
|
||||
ibz_copy(&norm_b,&norm_t);
|
||||
// t is a -rb, a is b, b is t
|
||||
ibz_mul(&prod,&r,&(b[0]));
|
||||
ibz_sub(&(t[0]),&(a[0]),&prod);
|
||||
ibz_mul(&prod,&r,&(b[1]));
|
||||
ibz_sub(&(t[1]),&(a[1]),&prod);
|
||||
ibz_copy(&(a[0]),&(b[0]));
|
||||
ibz_copy(&(a[1]),&(b[1]));
|
||||
ibz_copy(&(b[0]),&(t[0]));
|
||||
ibz_copy(&(b[1]),&(t[1]));
|
||||
} else {
|
||||
test = 0;
|
||||
}
|
||||
}
|
||||
// output : now b is short: need to get 2nd short vector: idea: take shortest among t and a
|
||||
if(ibz_cmp(&norm_t,&norm_a)<0){
|
||||
ibz_mul(&prod,&r,&(b[0]));
|
||||
ibz_sub(&(a[0]),&(a[0]),&prod);
|
||||
ibz_mul(&prod,&r,&(b[1]));
|
||||
ibz_sub(&(a[1]),&(a[1]),&prod);
|
||||
}
|
||||
ibz_copy(&((*reduced)[0][0]),&(b[0]));
|
||||
ibz_copy(&((*reduced)[1][0]),&(b[1]));
|
||||
ibz_copy(&((*reduced)[0][1]),&(a[0]));
|
||||
ibz_copy(&((*reduced)[1][1]),&(a[1]));
|
||||
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&sum);
|
||||
ibz_finalize(&norm_a);
|
||||
ibz_finalize(&norm_b);
|
||||
ibz_finalize(&norm_t);
|
||||
ibz_vec_2_finalize(&a);
|
||||
ibz_vec_2_finalize(&b);
|
||||
ibz_vec_2_finalize(&t);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&n);
|
||||
}
|
||||
|
||||
// compute the rounded value of <a*,t>/<a*,a*>, where a* is a orthogonalised with respect to b
|
||||
void quat_dim2_lattice_get_coefficient_with_orthogonalisation(ibz_t *res, const ibz_t *a0,const ibz_t *a1,const ibz_t *b0,const ibz_t *b1,const ibz_t *t0,const ibz_t *t1,const ibz_t *norm_q){
|
||||
ibz_t norm_b, bilinear, astar1,astar0, prod, norm_astar;
|
||||
ibz_init(&norm_b);
|
||||
ibz_init(&norm_astar);
|
||||
ibz_init(&bilinear);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&astar0);
|
||||
ibz_init(&astar1);
|
||||
quat_dim2_lattice_norm(&norm_b,b0,b1,norm_q);
|
||||
quat_dim2_lattice_bilinear(&bilinear,a0,a1,b0,b1,norm_q);
|
||||
ibz_mul(&astar0,a0,&norm_b);
|
||||
ibz_mul(&prod,b0,&bilinear);
|
||||
ibz_sub(&astar0,&astar0,&prod);
|
||||
ibz_mul(&astar1,a1,&norm_b);
|
||||
ibz_mul(&prod,b1,&bilinear);
|
||||
ibz_sub(&astar1,&astar1,&prod);
|
||||
quat_dim2_lattice_norm(&norm_astar,&astar0,&astar1,norm_q);
|
||||
quat_dim2_lattice_bilinear(&bilinear,&astar0,&astar1,t0,t1,norm_q);
|
||||
ibz_mul(&bilinear,&bilinear,&norm_b);
|
||||
ibz_rounded_div(res,&bilinear,&norm_astar);
|
||||
ibz_finalize(&norm_b);
|
||||
ibz_finalize(&norm_astar);
|
||||
ibz_finalize(&bilinear);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&astar0);
|
||||
ibz_finalize(&astar1);
|
||||
}
|
||||
|
||||
// find a closest vector to target in lattice, using a reduced basis given as argument basis.
|
||||
//nearest plane algo as in https://cims.nyu.edu/~regev/teaching/lattices_fall_2004/ln/cvp.pdf, but without basis: basicallly just a projection
|
||||
void quat_dim2_lattice_closest_vector(ibz_vec_2_t *target_minus_closest, ibz_vec_2_t *closest_coords_in_basis, const ibz_mat_2x2_t *reduced_basis, const ibz_vec_2_t *target, const ibz_t *norm_q){
|
||||
ibz_vec_2_t coords, work;
|
||||
ibz_t prod, sum, norm_a, norm_b, r;
|
||||
ibz_vec_2_init(&coords);
|
||||
ibz_vec_2_init(&work);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&sum);
|
||||
ibz_init(&norm_a);
|
||||
ibz_init(&norm_b);
|
||||
ibz_init(&r);
|
||||
// init work
|
||||
ibz_copy(&(work[0]),&((*target)[0]));
|
||||
ibz_copy(&(work[1]),&((*target)[1]));
|
||||
// norm a,b
|
||||
quat_dim2_lattice_norm(&norm_a,&((*reduced_basis)[0][0]),&((*reduced_basis)[1][0]), norm_q);
|
||||
quat_dim2_lattice_norm(&norm_b,&((*reduced_basis)[0][1]),&((*reduced_basis)[1][1]), norm_q);
|
||||
// use 2nd basis vector (the larger one), and orthogonalise it with respect to the first one
|
||||
quat_dim2_lattice_get_coefficient_with_orthogonalisation(&(coords[1]),&((*reduced_basis)[0][1]),&((*reduced_basis)[1][1]), &((*reduced_basis)[0][0]),&((*reduced_basis)[1][0]),&(work[0]),&(work[1]),norm_q);
|
||||
// sustract projection from vector
|
||||
ibz_mul(&prod,&((*reduced_basis)[0][1]),&(coords[1]));
|
||||
ibz_sub(&(work[0]),&(work[0]),&prod);
|
||||
ibz_mul(&prod,&((*reduced_basis)[1][1]),&(coords[1]));
|
||||
ibz_sub(&(work[1]),&(work[1]),&prod );
|
||||
// use 1st basis vector (the smaller one)
|
||||
quat_dim2_lattice_bilinear(&(coords[0]),&(work[0]),&(work[1]),&((*reduced_basis)[0][0]),&((*reduced_basis)[1][0]),norm_q);
|
||||
ibz_rounded_div(&(coords[0]),&(coords[0]),&norm_a);
|
||||
// substract projection from vector
|
||||
ibz_mul(&prod,&((*reduced_basis)[0][0]),&(coords[0]));
|
||||
ibz_sub(&(work[0]),&(work[0]),&prod);
|
||||
ibz_mul(&prod,&((*reduced_basis)[1][0]),&(coords[0]));
|
||||
ibz_sub(&(work[1]),&(work[1]),&prod );
|
||||
// copy results to output
|
||||
ibz_copy(&((*target_minus_closest)[0]),&(work[0]));
|
||||
ibz_copy(&((*target_minus_closest)[1]),&(work[1]));
|
||||
ibz_copy(&((*closest_coords_in_basis)[0]),&(coords[0]));
|
||||
ibz_copy(&((*closest_coords_in_basis)[1]),&(coords[1]));
|
||||
|
||||
ibz_vec_2_finalize(&coords);
|
||||
ibz_vec_2_finalize(&work);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&sum);
|
||||
ibz_finalize(&norm_a);
|
||||
ibz_finalize(&norm_b);
|
||||
ibz_finalize(&r);
|
||||
}
|
||||
|
||||
// give a,b,c such that ax^2 + bxy + cy^2 = N(Bz), where B is the basis, z the vector x,y and N the quadratic form (coord1^2 + q coord2^2)
|
||||
void quat_dim2_lattice_get_qf_on_lattice(ibz_t *qf_a, ibz_t *qf_b,ibz_t *qf_c, const ibz_mat_2x2_t *basis ,const ibz_t *norm_q){
|
||||
ibz_t a, b, c;
|
||||
ibz_init(&a);
|
||||
ibz_init(&b);
|
||||
ibz_init(&c);
|
||||
quat_dim2_lattice_bilinear(&b,&((*basis)[0][0]), &((*basis)[1][0]), &((*basis)[0][1]), &((*basis)[1][1]),norm_q);
|
||||
ibz_set(&a,2);
|
||||
ibz_mul(&b,&b,&a);
|
||||
quat_dim2_lattice_norm(&a,&((*basis)[0][0]), &((*basis)[1][0]),norm_q);
|
||||
quat_dim2_lattice_norm(&c, &((*basis)[0][1]), &((*basis)[1][1]),norm_q);
|
||||
ibz_copy(qf_a,&a);
|
||||
ibz_copy(qf_b,&b);
|
||||
ibz_copy(qf_c,&c);
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&c);
|
||||
}
|
||||
|
||||
int quat_dim2_lattice_test_cvp_condition(quat_alg_elem_t* elem, const ibz_vec_2_t* vec, const void* params){
|
||||
ibz_t *p = ((ibz_t *) params);
|
||||
ibz_t sum, two;
|
||||
ibz_init(&sum);
|
||||
ibz_init(&two);
|
||||
ibz_set(&two,2);
|
||||
ibz_add(&sum,&((*vec)[0]),&((*vec)[1]));
|
||||
ibz_mod(&sum,&sum,p);
|
||||
int res = (0 ==ibz_cmp(&sum,&two));
|
||||
if(res){
|
||||
quat_alg_elem_copy_ibz(elem,&two,&((*vec)[0]),&((*vec)[1]),&((*vec)[0]),&((*vec)[1]));
|
||||
}
|
||||
ibz_finalize(&sum);
|
||||
ibz_finalize(&two);
|
||||
return(res);
|
||||
}
|
||||
|
||||
int quat_dim2_lattice_bound_and_condition(quat_alg_elem_t *res, const ibz_t *x, const ibz_t *y, int (*condition)(quat_alg_elem_t* , const ibz_vec_2_t*, const void*), const void* params, const ibz_vec_2_t* target_minus_closest, const ibz_mat_2x2_t *lat_basis, const ibz_t* norm_q, const ibz_t* norm_bound){
|
||||
ibz_vec_2_t sum, proposal;
|
||||
ibz_t norm;
|
||||
int ok = 0;
|
||||
ibz_init(&norm);
|
||||
ibz_vec_2_init(&sum);
|
||||
ibz_vec_2_init(&proposal);
|
||||
// put x,y from lattice basis in canonical basis
|
||||
ibz_copy(&(proposal[0]), x);
|
||||
ibz_copy(&(proposal[1]), y);
|
||||
ibz_mat_2x2_eval(&proposal,lat_basis,&proposal);
|
||||
//compute norm of target -closest-proposal
|
||||
ibz_sub(&(sum[0]),&((*target_minus_closest)[0]),&((proposal)[0]));
|
||||
ibz_sub(&(sum[1]),&((*target_minus_closest)[1]),&((proposal)[1]));
|
||||
quat_dim2_lattice_norm(&norm,&(sum[0]),&(sum[1]),norm_q);
|
||||
// test
|
||||
if( ibz_cmp(&norm,norm_bound) <= 0){
|
||||
ok = condition(res,&sum,params);
|
||||
}
|
||||
ibz_finalize(&norm);
|
||||
ibz_vec_2_finalize(&sum);
|
||||
ibz_vec_2_finalize(&proposal);
|
||||
return(ok);
|
||||
}
|
||||
|
||||
int quat_dim2_lattice_qf_value_bound_generation(ibz_t *res, const ibz_t *num_a, const ibz_t *denom_a, const ibz_t *num_b, const ibz_t *denom_b){
|
||||
int ok = 1;
|
||||
ibz_t sqrt_num, sqrt_denom, one, zero, common_denom, r;
|
||||
ibz_init(&sqrt_num);
|
||||
ibz_init(&sqrt_denom);
|
||||
ibz_init(&one);
|
||||
ibz_init(&zero);
|
||||
ibz_init(&common_denom);
|
||||
ibz_init(&r);
|
||||
ibz_set(&zero,0);
|
||||
ibz_set(&one,1);
|
||||
ibz_mul(&r,num_a,denom_a);
|
||||
if((ibz_cmp(denom_a,&zero)<0)||ibz_is_zero(denom_a)||ibz_is_zero(denom_b)){
|
||||
ok = 0;
|
||||
}
|
||||
if(ok){
|
||||
ibz_sqrt_floor(&sqrt_num,num_a);
|
||||
ibz_add(&sqrt_num,&sqrt_num, &one);
|
||||
ibz_sqrt_floor(&sqrt_denom,denom_a);
|
||||
|
||||
ibz_mul(&common_denom,denom_b,&sqrt_denom);
|
||||
ibz_mul(&sqrt_num,&sqrt_num,denom_b);
|
||||
ibz_mul(&r,&sqrt_denom,num_b);
|
||||
ibz_add(&sqrt_num,&sqrt_num,&r);
|
||||
ibz_div(res,&r,&sqrt_num,&common_denom);
|
||||
ibz_add(res,res,&one);
|
||||
|
||||
}
|
||||
ibz_finalize(&sqrt_num);
|
||||
ibz_finalize(&sqrt_denom);
|
||||
ibz_finalize(&one);
|
||||
ibz_finalize(&zero);
|
||||
ibz_finalize(&common_denom);
|
||||
ibz_finalize(&r);
|
||||
return(ok);
|
||||
}
|
||||
|
||||
//Uses algorithm 2.7.5 (Fincke-Pohst) from Henri Cohen's "A Course in Computational Algebraic Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993
|
||||
//Slightly adapted to work without rational numbers and their square roots
|
||||
//Therefore needing a test to make sure the bounds are respected
|
||||
int quat_dim2_lattice_qf_enumerate_short_vec(quat_alg_elem_t *res,int (*condition)(quat_alg_elem_t*, const ibz_vec_2_t*, const void*), const void *params, const ibz_vec_2_t *target_minus_closest, const ibz_mat_2x2_t *lat_basis, const ibz_t *norm_q,const ibz_t *norm_bound, const int max_tries){
|
||||
int ok = 1;
|
||||
int found = 0;
|
||||
int tries = 0;
|
||||
int stop = 0;
|
||||
ibz_t bound_y, bound_x, x, y, disc, prod, var, one, four_a2, four_a2_norm_bound, four_a2_c_minus_b2, four_a3,two_a, zero, y2, qf_a, qf_b, qf_c, norm_bound_for_enumeration;
|
||||
ibz_init(&bound_y);
|
||||
ibz_init(&bound_x);
|
||||
ibz_init(&y);
|
||||
ibz_init(&y2);
|
||||
ibz_init(&x);
|
||||
ibz_init(&qf_a);
|
||||
ibz_init(&qf_b);
|
||||
ibz_init(&qf_c);
|
||||
ibz_init(&var);
|
||||
ibz_init(&one);
|
||||
ibz_init(&zero);
|
||||
ibz_init(&disc);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&four_a2);
|
||||
ibz_init(&two_a);
|
||||
ibz_init(&norm_bound_for_enumeration);
|
||||
ibz_init(&four_a2_norm_bound);
|
||||
ibz_init(&four_a2_c_minus_b2);
|
||||
ibz_init(&four_a3);
|
||||
ibz_set(&one,1);
|
||||
ibz_set(&zero,0);
|
||||
// substract norm of distance from bound to not enumerate too large vectors at beginning
|
||||
// this is an heuristic which can fail, so in case it is really bad, we do not do it
|
||||
quat_dim2_lattice_norm(&norm_bound_for_enumeration,&((*target_minus_closest)[0]),&((*target_minus_closest)[1]),norm_q);
|
||||
ibz_sub(&norm_bound_for_enumeration,norm_bound,&norm_bound_for_enumeration);
|
||||
if(ibz_cmp(&norm_bound_for_enumeration,&zero)<=0){
|
||||
ibz_copy(&norm_bound_for_enumeration, norm_bound);
|
||||
}
|
||||
//Set qf_a, qf_b, qf_c such that for x,y, a vector represented in lat_basis, ax^2 + bxy + cy^2 is the norm defined by norm_q
|
||||
quat_dim2_lattice_get_qf_on_lattice(&qf_a,&qf_b,&qf_c,lat_basis,norm_q);
|
||||
//discriminant computation
|
||||
ibz_mul(&disc,&qf_a,&qf_c);
|
||||
ibz_set(&var,4);
|
||||
ibz_mul(&disc,&disc,&var);
|
||||
ibz_mul(&prod,&qf_b,&qf_b);
|
||||
ibz_sub(&disc,&disc,&prod);
|
||||
// only continue if disc is not zero nor negative
|
||||
if (ibz_cmp(&disc,&zero)<=0){
|
||||
ok = 0;
|
||||
}
|
||||
if(ok){
|
||||
// precomputations
|
||||
ibz_set(&var,2);
|
||||
ibz_mul(&two_a,&var,&qf_a);//2a init
|
||||
ibz_mul(&four_a2,&two_a,&two_a);//4a^2 init
|
||||
ibz_mul(&four_a2_norm_bound,&four_a2,&norm_bound_for_enumeration);//4a^2*norm_bound init
|
||||
ibz_mul(&four_a3,&four_a2,&qf_a);//4a^3 init
|
||||
ibz_copy(&four_a2_c_minus_b2,&prod);//equals b^2 now, since prod was not reused since
|
||||
ibz_mul(&prod,&four_a2,&qf_c);
|
||||
ibz_sub(&four_a2_c_minus_b2,&prod,&four_a2_c_minus_b2);//now has correct value
|
||||
// y bound generation
|
||||
quat_dim2_lattice_qf_value_bound_generation(&bound_y,&four_a2_norm_bound,&four_a2_c_minus_b2,&zero,&one);
|
||||
ibz_neg(&y,&bound_y);
|
||||
ibz_sub(&y,&y,&one); // y is set
|
||||
while((!found) && (!stop) && (ibz_cmp(&y,&bound_y)<0) && (tries <max_tries)){
|
||||
ibz_add(&y,&y,&one);
|
||||
ibz_mul(&y2,&y,&y);
|
||||
ibz_mul(&prod,&qf_b,&y);
|
||||
ibz_neg(&var,&prod);//var = -by
|
||||
ibz_mul(&prod,&y2,&four_a2_c_minus_b2);
|
||||
ibz_add(&prod,&prod,&four_a2_norm_bound);//prod = 4a^2*norm_bound + (4ca^2 - b^2)y^2
|
||||
quat_dim2_lattice_qf_value_bound_generation(&bound_x,&prod, &four_a3,&var,&two_a);
|
||||
ibz_neg(&var,&var);
|
||||
quat_dim2_lattice_qf_value_bound_generation(&x,&prod, &four_a3,&var,&two_a);
|
||||
ibz_neg(&x,&x);
|
||||
ibz_sub(&x,&x,&one);// x is set
|
||||
while((!found) && (!stop) && (ibz_cmp(&x,&bound_x)<0) && (tries <max_tries)){
|
||||
tries +=1;
|
||||
ibz_add(&x,&x,&one);
|
||||
found = quat_dim2_lattice_bound_and_condition(res,&x, &y,condition, params, target_minus_closest, lat_basis, norm_q, norm_bound);
|
||||
stop = (ibz_is_zero(&x) && ibz_is_zero(&y));
|
||||
}
|
||||
}
|
||||
}
|
||||
ibz_finalize(&norm_bound_for_enumeration);
|
||||
ibz_finalize(&bound_y);
|
||||
ibz_finalize(&bound_x);
|
||||
ibz_finalize(&y);
|
||||
ibz_finalize(&y2);
|
||||
ibz_finalize(&x);
|
||||
ibz_finalize(&qf_a);
|
||||
ibz_finalize(&qf_b);
|
||||
ibz_finalize(&qf_c);
|
||||
ibz_finalize(&var);
|
||||
ibz_finalize(&one);
|
||||
ibz_finalize(&zero);
|
||||
ibz_finalize(&disc);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&four_a2);
|
||||
ibz_finalize(&four_a2_norm_bound);
|
||||
ibz_finalize(&four_a2_c_minus_b2);
|
||||
ibz_finalize(&four_a3);
|
||||
ibz_finalize(&two_a);
|
||||
return(ok && found);
|
||||
}
|
||||
|
||||
int quat_2x2_lattice_enumerate_cvp_filter(quat_alg_elem_t *res, const ibz_mat_2x2_t *lat_basis, const ibz_vec_2_t *target,unsigned int qf, unsigned int dist_bound, int (*condition)(quat_alg_elem_t* , const ibz_vec_2_t*, const void*), const void* params, unsigned int max_tries){
|
||||
int found = 0;
|
||||
unsigned int counter = 0;
|
||||
ibz_t norm_q, norm_bound;
|
||||
ibz_mat_2x2_t reduced;
|
||||
ibz_vec_2_t closest_coords, target_minus_closest;
|
||||
ibz_init(&norm_q);
|
||||
ibz_init(&norm_bound);
|
||||
ibz_mat_2x2_init(&reduced);
|
||||
ibz_vec_2_init(&target_minus_closest);
|
||||
ibz_vec_2_init(&closest_coords);
|
||||
|
||||
ibz_set(&norm_q,qf);
|
||||
ibz_set(&norm_bound,2);
|
||||
ibz_pow(&norm_bound,&norm_bound,dist_bound);
|
||||
// reduce lattice basis
|
||||
quat_dim2_lattice_short_basis(&reduced,lat_basis,&norm_q);
|
||||
|
||||
// find closest vector
|
||||
quat_dim2_lattice_closest_vector(&target_minus_closest,&closest_coords,&reduced,target,&norm_q);
|
||||
|
||||
// enumerate short vector and test
|
||||
found = quat_dim2_lattice_qf_enumerate_short_vec(res,condition,params, &target_minus_closest, &reduced, &norm_q, &norm_bound, max_tries);
|
||||
|
||||
ibz_finalize(&norm_q);
|
||||
ibz_finalize(&norm_bound);
|
||||
ibz_mat_2x2_finalize(&reduced);
|
||||
ibz_vec_2_finalize(&target_minus_closest);
|
||||
ibz_vec_2_finalize(&closest_coords);
|
||||
return(found);
|
||||
return (res);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,158 +1,122 @@
|
||||
#include <quaternion.h>
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
void quat_alg_init_set(quat_alg_t *alg, const ibz_t *p){
|
||||
void
|
||||
quat_alg_init_set(quat_alg_t *alg, const ibz_t *p)
|
||||
{
|
||||
ibz_init(&(*alg).p);
|
||||
ibz_mat_4x4_init(&(*alg).gram);
|
||||
ibz_copy(&(*alg).p, p);
|
||||
ibz_set(&(*alg).gram[0][0], 1);
|
||||
ibz_set(&(*alg).gram[1][1], 1);
|
||||
ibz_copy(&(*alg).gram[2][2], p);
|
||||
ibz_copy(&(*alg).gram[3][3], p);
|
||||
}
|
||||
void quat_alg_finalize(quat_alg_t *alg){
|
||||
void
|
||||
quat_alg_finalize(quat_alg_t *alg)
|
||||
{
|
||||
ibz_finalize(&(*alg).p);
|
||||
ibz_mat_4x4_finalize(&(*alg).gram);
|
||||
}
|
||||
|
||||
void quat_alg_elem_init(quat_alg_elem_t *elem){
|
||||
quat_alg_coord_init(&(*elem).coord);
|
||||
void
|
||||
quat_alg_elem_init(quat_alg_elem_t *elem)
|
||||
{
|
||||
ibz_vec_4_init(&(*elem).coord);
|
||||
ibz_init(&(*elem).denom);
|
||||
ibz_set(&(*elem).denom, 1);
|
||||
}
|
||||
void quat_alg_elem_finalize(quat_alg_elem_t *elem){
|
||||
quat_alg_coord_finalize(&(*elem).coord);
|
||||
void
|
||||
quat_alg_elem_finalize(quat_alg_elem_t *elem)
|
||||
{
|
||||
ibz_vec_4_finalize(&(*elem).coord);
|
||||
ibz_finalize(&(*elem).denom);
|
||||
}
|
||||
|
||||
void quat_alg_coord_init(quat_alg_coord_t *coord){
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_init(&(*coord)[i]);
|
||||
void
|
||||
ibz_vec_2_init(ibz_vec_2_t *vec)
|
||||
{
|
||||
ibz_init(&((*vec)[0]));
|
||||
ibz_init(&((*vec)[1]));
|
||||
}
|
||||
|
||||
void
|
||||
ibz_vec_2_finalize(ibz_vec_2_t *vec)
|
||||
{
|
||||
ibz_finalize(&((*vec)[0]));
|
||||
ibz_finalize(&((*vec)[1]));
|
||||
}
|
||||
|
||||
void
|
||||
ibz_vec_4_init(ibz_vec_4_t *vec)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_init(&(*vec)[i]);
|
||||
}
|
||||
}
|
||||
void quat_alg_coord_finalize(quat_alg_coord_t *coord){
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_finalize(&(*coord)[i]);
|
||||
void
|
||||
ibz_vec_4_finalize(ibz_vec_4_t *vec)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_finalize(&(*vec)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_vec_4_init(ibz_vec_4_t *vec){
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_init(&(*vec)[i]);
|
||||
}
|
||||
}
|
||||
void ibz_vec_4_finalize(ibz_vec_4_t *vec){
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_finalize(&(*vec)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_vec_5_init(ibz_vec_5_t *vec){
|
||||
for(int i = 0; i < 5; i++){
|
||||
ibz_init(&(*vec)[i]);
|
||||
}
|
||||
}
|
||||
void ibz_vec_5_finalize(ibz_vec_5_t *vec){
|
||||
for(int i = 0; i < 5; i++){
|
||||
ibz_finalize(&(*vec)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_mat_2x2_init(ibz_mat_2x2_t *mat){
|
||||
for(int i = 0; i < 2; i++){
|
||||
for(int j = 0; j < 2; j++){
|
||||
void
|
||||
ibz_mat_2x2_init(ibz_mat_2x2_t *mat)
|
||||
{
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
ibz_init(&(*mat)[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
void ibz_mat_2x2_finalize(ibz_mat_2x2_t *mat){
|
||||
for(int i = 0; i < 2; i++){
|
||||
for(int j = 0; j < 2; j++){
|
||||
void
|
||||
ibz_mat_2x2_finalize(ibz_mat_2x2_t *mat)
|
||||
{
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
ibz_finalize(&(*mat)[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_mat_4x4_init(ibz_mat_4x4_t *mat){
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
void
|
||||
ibz_mat_4x4_init(ibz_mat_4x4_t *mat)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_init(&(*mat)[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
void ibz_mat_4x4_finalize(ibz_mat_4x4_t *mat){
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
void
|
||||
ibz_mat_4x4_finalize(ibz_mat_4x4_t *mat)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_finalize(&(*mat)[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_mat_4x5_init(ibz_mat_4x5_t *mat){
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 5; j++){
|
||||
ibz_init(&(*mat)[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
void ibz_mat_4x5_finalize(ibz_mat_4x5_t *mat){
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 5; j++){
|
||||
ibz_finalize(&(*mat)[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_mat_4x8_init(ibz_mat_4x8_t *mat){
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 8; j++){
|
||||
ibz_init(&(*mat)[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
void ibz_mat_4x8_finalize(ibz_mat_4x8_t *mat){
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 8; j++){
|
||||
ibz_finalize(&(*mat)[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_mat_init(int rows, int cols, ibz_t mat[rows][cols]) {
|
||||
for (int i = 0; i < rows; i++)
|
||||
for (int j = 0; j < cols; j++)
|
||||
ibz_init(&mat[i][j]);
|
||||
}
|
||||
|
||||
void ibz_mat_finalize(int rows, int cols, ibz_t mat[rows][cols]) {
|
||||
for (int i = 0; i < rows; i++)
|
||||
for (int j = 0; j < cols; j++)
|
||||
ibz_finalize(&mat[i][j]);
|
||||
}
|
||||
|
||||
void quat_lattice_init(quat_lattice_t *lat){
|
||||
void
|
||||
quat_lattice_init(quat_lattice_t *lat)
|
||||
{
|
||||
ibz_mat_4x4_init(&(*lat).basis);
|
||||
ibz_init(&(*lat).denom);
|
||||
ibz_set(&(*lat).denom, 1);
|
||||
}
|
||||
void quat_lattice_finalize(quat_lattice_t *lat){
|
||||
void
|
||||
quat_lattice_finalize(quat_lattice_t *lat)
|
||||
{
|
||||
ibz_finalize(&(*lat).denom);
|
||||
ibz_mat_4x4_finalize(&(*lat).basis);
|
||||
}
|
||||
|
||||
void quat_order_init(quat_order_t *order){
|
||||
quat_lattice_init(order);
|
||||
}
|
||||
void quat_order_finalize(quat_order_t *order){
|
||||
quat_lattice_finalize(order);
|
||||
}
|
||||
|
||||
void quat_left_ideal_init(quat_left_ideal_t *lideal){
|
||||
void
|
||||
quat_left_ideal_init(quat_left_ideal_t *lideal)
|
||||
{
|
||||
quat_lattice_init(&(*lideal).lattice);
|
||||
ibz_init(&(*lideal).norm);
|
||||
(*lideal).parent_order=NULL;
|
||||
(*lideal).parent_order = NULL;
|
||||
}
|
||||
void quat_left_ideal_finalize(quat_left_ideal_t *lideal){
|
||||
void
|
||||
quat_left_ideal_finalize(quat_left_ideal_t *lideal)
|
||||
{
|
||||
ibz_finalize(&(*lideal).norm);
|
||||
quat_lattice_finalize(&(*lideal).lattice);
|
||||
}
|
||||
|
||||
210
src/quaternion/ref/generic/hnf/hnf.c
Normal file
210
src/quaternion/ref/generic/hnf/hnf.c
Normal file
@@ -0,0 +1,210 @@
|
||||
#include "hnf_internal.h"
|
||||
#include "internal.h"
|
||||
|
||||
// HNF test function
|
||||
int
|
||||
ibz_mat_4x4_is_hnf(const ibz_mat_4x4_t *mat)
|
||||
{
|
||||
int res = 1;
|
||||
int found;
|
||||
int ind = 0;
|
||||
ibz_t zero;
|
||||
ibz_init(&zero);
|
||||
// upper triangular
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// upper triangular
|
||||
for (int j = 0; j < i; j++) {
|
||||
res = res && ibz_is_zero(&((*mat)[i][j]));
|
||||
}
|
||||
// find first non 0 element of line
|
||||
found = 0;
|
||||
for (int j = i; j < 4; j++) {
|
||||
if (found) {
|
||||
// all values are positive, and first non-0 is the largest of that line
|
||||
res = res && (ibz_cmp(&((*mat)[i][j]), &zero) >= 0);
|
||||
res = res && (ibz_cmp(&((*mat)[i][ind]), &((*mat)[i][j])) > 0);
|
||||
} else {
|
||||
if (!ibz_is_zero(&((*mat)[i][j]))) {
|
||||
found = 1;
|
||||
ind = j;
|
||||
// mustbe non-negative
|
||||
res = res && (ibz_cmp(&((*mat)[i][j]), &zero) > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// check that first nom-zero elements ndex per column is strictly increasing
|
||||
int linestart = -1;
|
||||
int i = 0;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
while ((i < 4) && (ibz_is_zero(&((*mat)[i][j])))) {
|
||||
i = i + 1;
|
||||
}
|
||||
if (i != 4) {
|
||||
res = res && (linestart < i);
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
ibz_finalize(&zero);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Untested HNF helpers
|
||||
// centered mod
|
||||
void
|
||||
ibz_vec_4_linear_combination_mod(ibz_vec_4_t *lc,
|
||||
const ibz_t *coeff_a,
|
||||
const ibz_vec_4_t *vec_a,
|
||||
const ibz_t *coeff_b,
|
||||
const ibz_vec_4_t *vec_b,
|
||||
const ibz_t *mod)
|
||||
{
|
||||
ibz_t prod, m;
|
||||
ibz_vec_4_t sums;
|
||||
ibz_vec_4_init(&sums);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&m);
|
||||
ibz_copy(&m, mod);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_mul(&(sums[i]), coeff_a, &((*vec_a)[i]));
|
||||
ibz_mul(&prod, coeff_b, &((*vec_b)[i]));
|
||||
ibz_add(&(sums[i]), &(sums[i]), &prod);
|
||||
ibz_centered_mod(&(sums[i]), &(sums[i]), &m);
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_copy(&((*lc)[i]), &(sums[i]));
|
||||
}
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&m);
|
||||
ibz_vec_4_finalize(&sums);
|
||||
}
|
||||
|
||||
void
|
||||
ibz_vec_4_copy_mod(ibz_vec_4_t *res, const ibz_vec_4_t *vec, const ibz_t *mod)
|
||||
{
|
||||
ibz_t m;
|
||||
ibz_init(&m);
|
||||
ibz_copy(&m, mod);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_centered_mod(&((*res)[i]), &((*vec)[i]), &m);
|
||||
}
|
||||
ibz_finalize(&m);
|
||||
}
|
||||
|
||||
// no need to center this, and not 0
|
||||
void
|
||||
ibz_vec_4_scalar_mul_mod(ibz_vec_4_t *prod, const ibz_t *scalar, const ibz_vec_4_t *vec, const ibz_t *mod)
|
||||
{
|
||||
ibz_t m, s;
|
||||
ibz_init(&m);
|
||||
ibz_init(&s);
|
||||
ibz_copy(&s, scalar);
|
||||
ibz_copy(&m, mod);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_mul(&((*prod)[i]), &((*vec)[i]), &s);
|
||||
ibz_mod(&((*prod)[i]), &((*prod)[i]), &m);
|
||||
}
|
||||
ibz_finalize(&m);
|
||||
ibz_finalize(&s);
|
||||
}
|
||||
|
||||
// Algorithm used is the one at number 2.4.8 in Henri Cohen's "A Course in Computational Algebraic
|
||||
// Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993
|
||||
// assumes ibz_xgcd outputs u,v which are small in absolute value (as described in the
|
||||
// book)
|
||||
void
|
||||
ibz_mat_4xn_hnf_mod_core(ibz_mat_4x4_t *hnf, int generator_number, const ibz_vec_4_t *generators, const ibz_t *mod)
|
||||
{
|
||||
int i = 3;
|
||||
assert(generator_number > 3);
|
||||
int n = generator_number;
|
||||
int j = n - 1;
|
||||
int k = n - 1;
|
||||
ibz_t b, u, v, d, q, m, coeff_1, coeff_2, r;
|
||||
ibz_vec_4_t c;
|
||||
ibz_vec_4_t a[generator_number];
|
||||
ibz_vec_4_t w[4];
|
||||
ibz_init(&b);
|
||||
ibz_init(&d);
|
||||
ibz_init(&u);
|
||||
ibz_init(&v);
|
||||
ibz_init(&r);
|
||||
ibz_init(&m);
|
||||
ibz_init(&q);
|
||||
ibz_init(&coeff_1);
|
||||
ibz_init(&coeff_2);
|
||||
ibz_vec_4_init(&c);
|
||||
for (int h = 0; h < n; h++) {
|
||||
if (h < 4)
|
||||
ibz_vec_4_init(&(w[h]));
|
||||
ibz_vec_4_init(&(a[h]));
|
||||
ibz_copy(&(a[h][0]), &(generators[h][0]));
|
||||
ibz_copy(&(a[h][1]), &(generators[h][1]));
|
||||
ibz_copy(&(a[h][2]), &(generators[h][2]));
|
||||
ibz_copy(&(a[h][3]), &(generators[h][3]));
|
||||
}
|
||||
assert(ibz_cmp(mod, &ibz_const_zero) > 0);
|
||||
ibz_copy(&m, mod);
|
||||
while (i != -1) {
|
||||
while (j != 0) {
|
||||
j = j - 1;
|
||||
if (!ibz_is_zero(&(a[j][i]))) {
|
||||
// assumtion that ibz_xgcd outputs u,v which are small in absolute
|
||||
// value is needed here also, needs u non 0, but v can be 0 if needed
|
||||
ibz_xgcd_with_u_not_0(&d, &u, &v, &(a[k][i]), &(a[j][i]));
|
||||
ibz_vec_4_linear_combination(&c, &u, &(a[k]), &v, &(a[j]));
|
||||
ibz_div(&coeff_1, &r, &(a[k][i]), &d);
|
||||
ibz_div(&coeff_2, &r, &(a[j][i]), &d);
|
||||
ibz_neg(&coeff_2, &coeff_2);
|
||||
ibz_vec_4_linear_combination_mod(
|
||||
&(a[j]), &coeff_1, &(a[j]), &coeff_2, &(a[k]), &m); // do lin comb mod m
|
||||
ibz_vec_4_copy_mod(&(a[k]), &c, &m); // mod m in copy
|
||||
}
|
||||
}
|
||||
ibz_xgcd_with_u_not_0(&d, &u, &v, &(a[k][i]), &m);
|
||||
ibz_vec_4_scalar_mul_mod(&(w[i]), &u, &(a[k]), &m); // mod m in scalar mult
|
||||
if (ibz_is_zero(&(w[i][i]))) {
|
||||
ibz_copy(&(w[i][i]), &m);
|
||||
}
|
||||
for (int h = i + 1; h < 4; h++) {
|
||||
ibz_div_floor(&q, &r, &(w[h][i]), &(w[i][i]));
|
||||
ibz_neg(&q, &q);
|
||||
ibz_vec_4_linear_combination(&(w[h]), &ibz_const_one, &(w[h]), &q, &(w[i]));
|
||||
}
|
||||
ibz_div(&m, &r, &m, &d);
|
||||
assert(ibz_is_zero(&r));
|
||||
if (i != 0) {
|
||||
k = k - 1;
|
||||
i = i - 1;
|
||||
j = k;
|
||||
if (ibz_is_zero(&(a[k][i])))
|
||||
ibz_copy(&(a[k][i]), &m);
|
||||
|
||||
} else {
|
||||
k = k - 1;
|
||||
i = i - 1;
|
||||
j = k;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
ibz_copy(&((*hnf)[i][j]), &(w[j][i]));
|
||||
}
|
||||
}
|
||||
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&d);
|
||||
ibz_finalize(&u);
|
||||
ibz_finalize(&v);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&coeff_1);
|
||||
ibz_finalize(&coeff_2);
|
||||
ibz_finalize(&m);
|
||||
ibz_vec_4_finalize(&c);
|
||||
for (int h = 0; h < n; h++) {
|
||||
if (h < 4)
|
||||
ibz_vec_4_finalize(&(w[h]));
|
||||
ibz_vec_4_finalize(&(a[h]));
|
||||
}
|
||||
}
|
||||
182
src/quaternion/ref/generic/hnf/hnf_internal.c
Normal file
182
src/quaternion/ref/generic/hnf/hnf_internal.c
Normal file
@@ -0,0 +1,182 @@
|
||||
#include "hnf_internal.h"
|
||||
#include "internal.h"
|
||||
|
||||
// Small helper for integers
|
||||
void
|
||||
ibz_mod_not_zero(ibz_t *res, const ibz_t *x, const ibz_t *mod)
|
||||
{
|
||||
ibz_t m, t;
|
||||
ibz_init(&m);
|
||||
ibz_init(&t);
|
||||
ibz_mod(&m, x, mod);
|
||||
ibz_set(&t, ibz_is_zero(&m));
|
||||
ibz_mul(&t, &t, mod);
|
||||
ibz_add(res, &m, &t);
|
||||
ibz_finalize(&m);
|
||||
ibz_finalize(&t);
|
||||
}
|
||||
|
||||
// centered and rather positive then negative
|
||||
void
|
||||
ibz_centered_mod(ibz_t *remainder, const ibz_t *a, const ibz_t *mod)
|
||||
{
|
||||
assert(ibz_cmp(mod, &ibz_const_zero) > 0);
|
||||
ibz_t tmp, d, t;
|
||||
ibz_init(&tmp);
|
||||
ibz_init(&d);
|
||||
ibz_init(&t);
|
||||
ibz_div_floor(&d, &tmp, mod, &ibz_const_two);
|
||||
ibz_mod_not_zero(&tmp, a, mod);
|
||||
ibz_set(&t, ibz_cmp(&tmp, &d) > 0);
|
||||
ibz_mul(&t, &t, mod);
|
||||
ibz_sub(remainder, &tmp, &t);
|
||||
ibz_finalize(&tmp);
|
||||
ibz_finalize(&d);
|
||||
ibz_finalize(&t);
|
||||
}
|
||||
|
||||
// if c, res = x, else res = y
|
||||
void
|
||||
ibz_conditional_assign(ibz_t *res, const ibz_t *x, const ibz_t *y, int c)
|
||||
{
|
||||
ibz_t s, t, r;
|
||||
ibz_init(&r);
|
||||
ibz_init(&s);
|
||||
ibz_init(&t);
|
||||
ibz_set(&s, c != 0);
|
||||
ibz_sub(&t, &ibz_const_one, &s);
|
||||
ibz_mul(&r, &s, x);
|
||||
ibz_mul(res, &t, y);
|
||||
ibz_add(res, &r, res);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&s);
|
||||
ibz_finalize(&t);
|
||||
}
|
||||
|
||||
// mpz_gcdext specification specifies unique outputs used here
|
||||
void
|
||||
ibz_xgcd_with_u_not_0(ibz_t *d, ibz_t *u, ibz_t *v, const ibz_t *x, const ibz_t *y)
|
||||
{
|
||||
if (ibz_is_zero(x) & ibz_is_zero(y)) {
|
||||
ibz_set(d, 1);
|
||||
ibz_set(u, 1);
|
||||
ibz_set(v, 0);
|
||||
return;
|
||||
}
|
||||
ibz_t q, r, x1, y1;
|
||||
ibz_init(&q);
|
||||
ibz_init(&r);
|
||||
ibz_init(&x1);
|
||||
ibz_init(&y1);
|
||||
ibz_copy(&x1, x);
|
||||
ibz_copy(&y1, y);
|
||||
|
||||
// xgcd
|
||||
ibz_xgcd(d, u, v, &x1, &y1);
|
||||
|
||||
// make sure u!=0 (v can be 0 if needed)
|
||||
// following GMP specification, u == 0 implies y|x
|
||||
if (ibz_is_zero(u)) {
|
||||
if (!ibz_is_zero(&x1)) {
|
||||
if (ibz_is_zero(&y1)) {
|
||||
ibz_set(&y1, 1);
|
||||
}
|
||||
ibz_div(&q, &r, &x1, &y1);
|
||||
assert(ibz_is_zero(&r));
|
||||
ibz_sub(v, v, &q);
|
||||
}
|
||||
ibz_set(u, 1);
|
||||
}
|
||||
if (!ibz_is_zero(&x1)) {
|
||||
// Make sure ux > 0 (and as small as possible)
|
||||
assert(ibz_cmp(d, &ibz_const_zero) > 0);
|
||||
ibz_mul(&r, &x1, &y1);
|
||||
int neg = ibz_cmp(&r, &ibz_const_zero) < 0;
|
||||
ibz_mul(&q, &x1, u);
|
||||
while (ibz_cmp(&q, &ibz_const_zero) <= 0) {
|
||||
ibz_div(&q, &r, &y1, d);
|
||||
assert(ibz_is_zero(&r));
|
||||
if (neg) {
|
||||
ibz_neg(&q, &q);
|
||||
}
|
||||
ibz_add(u, u, &q);
|
||||
ibz_div(&q, &r, &x1, d);
|
||||
assert(ibz_is_zero(&r));
|
||||
if (neg) {
|
||||
ibz_neg(&q, &q);
|
||||
}
|
||||
ibz_sub(v, v, &q);
|
||||
|
||||
ibz_mul(&q, &x1, u);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
int res = 0;
|
||||
ibz_t sum, prod, test, cmp;
|
||||
ibz_init(&sum);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&cmp);
|
||||
ibz_init(&test);
|
||||
// sign correct
|
||||
res = res | !(ibz_cmp(d, &ibz_const_zero) >= 0);
|
||||
if (ibz_is_zero(&x1) && ibz_is_zero(&y1)) {
|
||||
res = res | !(ibz_is_zero(v) && ibz_is_one(u) && ibz_is_one(d));
|
||||
} else {
|
||||
if (!ibz_is_zero(&x1) && !ibz_is_zero(&y1)) {
|
||||
// GCD divides x
|
||||
ibz_div(&sum, &prod, &x1, d);
|
||||
res = res | !ibz_is_zero(&prod);
|
||||
// Small enough
|
||||
ibz_mul(&prod, &x1, u);
|
||||
res = res | !(ibz_cmp(&prod, &ibz_const_zero) > 0);
|
||||
ibz_mul(&sum, &sum, &y1);
|
||||
ibz_abs(&sum, &sum);
|
||||
res = res | !(ibz_cmp(&prod, &sum) <= 0);
|
||||
|
||||
// GCD divides y
|
||||
ibz_div(&sum, &prod, &y1, d);
|
||||
res = res | !ibz_is_zero(&prod);
|
||||
// Small enough
|
||||
ibz_mul(&prod, &y1, v);
|
||||
res = res | !(ibz_cmp(&prod, &ibz_const_zero) <= 0);
|
||||
ibz_mul(&sum, &sum, &x1);
|
||||
ibz_abs(&sum, &sum);
|
||||
res = res | !(ibz_cmp(&prod, &sum) < 0);
|
||||
} else {
|
||||
// GCD divides x
|
||||
ibz_div(&sum, &prod, &x1, d);
|
||||
res = res | !ibz_is_zero(&prod);
|
||||
// GCD divides y
|
||||
ibz_div(&sum, &prod, &y1, d);
|
||||
res = res | !ibz_is_zero(&prod);
|
||||
if (ibz_is_zero(&x1) && !ibz_is_zero(&y1)) {
|
||||
ibz_abs(&prod, v);
|
||||
res = res | !(ibz_is_one(&prod));
|
||||
res = res | !(ibz_is_one(u));
|
||||
} else {
|
||||
ibz_abs(&prod, u);
|
||||
res = res | !(ibz_is_one(&prod));
|
||||
res = res | !(ibz_is_zero(v));
|
||||
}
|
||||
}
|
||||
|
||||
// Bezout coeffs
|
||||
ibz_mul(&sum, &x1, u);
|
||||
ibz_mul(&prod, &y1, v);
|
||||
ibz_add(&sum, &sum, &prod);
|
||||
res = res | !(ibz_cmp(&sum, d) == 0);
|
||||
}
|
||||
assert(!res);
|
||||
ibz_finalize(&sum);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&cmp);
|
||||
ibz_finalize(&test);
|
||||
|
||||
#endif
|
||||
|
||||
ibz_finalize(&x1);
|
||||
ibz_finalize(&y1);
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&r);
|
||||
}
|
||||
1019
src/quaternion/ref/generic/hnf/hnf_tests.c
Normal file
1019
src/quaternion/ref/generic/hnf/hnf_tests.c
Normal file
File diff suppressed because it is too large
Load Diff
12
src/quaternion/ref/generic/hnf/ibz_division.c
Normal file
12
src/quaternion/ref/generic/hnf/ibz_division.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "hnf_internal.h"
|
||||
#if defined(MINI_GMP)
|
||||
#include <mini-gmp.h>
|
||||
#else
|
||||
#include <gmp.h>
|
||||
#endif
|
||||
|
||||
void
|
||||
ibz_xgcd(ibz_t *gcd, ibz_t *u, ibz_t *v, const ibz_t *a, const ibz_t *b)
|
||||
{
|
||||
mpz_gcdext(*gcd, *u, *v, *a, *b);
|
||||
}
|
||||
@@ -2,370 +2,322 @@
|
||||
#include <stdlib.h>
|
||||
#include "internal.h"
|
||||
|
||||
void quat_lideal_create_principal(quat_left_ideal_t *lideal, const quat_alg_elem_t *x, const quat_order_t *order, const quat_alg_t *alg) {
|
||||
ibz_mat_4x4_t mulmat;
|
||||
ibq_t norm;
|
||||
ibz_mat_4x4_init(&mulmat);
|
||||
ibq_init(&norm);
|
||||
|
||||
// Multiply order basis on the right by x
|
||||
quat_alg_rightmul_mat(&mulmat, x, alg);
|
||||
ibz_mat_4x4_mul(&lideal->lattice.basis, &mulmat, &order->basis);
|
||||
|
||||
// Adjust denominators
|
||||
ibz_mul(&lideal->lattice.denom, &x->denom, &order->denom);
|
||||
quat_lattice_reduce_denom(&lideal->lattice, &lideal->lattice);
|
||||
|
||||
// Compute HNF
|
||||
quat_lattice_hnf(&lideal->lattice);
|
||||
|
||||
// Compute norm and check it's integral
|
||||
quat_alg_norm(&norm, x, alg);
|
||||
assert(ibq_is_ibz(&norm));
|
||||
ibq_to_ibz(&lideal->norm, &norm);
|
||||
|
||||
// Set order
|
||||
lideal->parent_order = order;
|
||||
|
||||
ibq_finalize(&norm);
|
||||
ibz_mat_4x4_finalize(&mulmat);
|
||||
// assumes parent order and lattice correctly set, computes and sets the norm
|
||||
void
|
||||
quat_lideal_norm(quat_left_ideal_t *lideal)
|
||||
{
|
||||
quat_lattice_index(&(lideal->norm), &(lideal->lattice), (lideal->parent_order));
|
||||
int ok UNUSED = ibz_sqrt(&(lideal->norm), &(lideal->norm));
|
||||
assert(ok);
|
||||
}
|
||||
|
||||
void quat_lideal_create_from_primitive(quat_left_ideal_t *lideal, const quat_alg_elem_t *x, const ibz_t *N, const quat_order_t *order, const quat_alg_t *alg) {
|
||||
// assumes parent order and lattice correctly set, recomputes and verifies its norm
|
||||
static int
|
||||
quat_lideal_norm_verify(const quat_left_ideal_t *lideal)
|
||||
{
|
||||
int res;
|
||||
ibz_t index;
|
||||
ibz_init(&index);
|
||||
quat_lattice_index(&index, &(lideal->lattice), (lideal->parent_order));
|
||||
ibz_sqrt(&index, &index);
|
||||
res = (ibz_cmp(&(lideal->norm), &index) == 0);
|
||||
ibz_finalize(&index);
|
||||
return (res);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lideal_copy(quat_left_ideal_t *copy, const quat_left_ideal_t *copied)
|
||||
{
|
||||
copy->parent_order = copied->parent_order;
|
||||
ibz_copy(©->norm, &copied->norm);
|
||||
ibz_copy(©->lattice.denom, &copied->lattice.denom);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_copy(©->lattice.basis[i][j], &copied->lattice.basis[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
quat_lideal_create_principal(quat_left_ideal_t *lideal,
|
||||
const quat_alg_elem_t *x,
|
||||
const quat_lattice_t *order,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
assert(quat_order_is_maximal(order, alg));
|
||||
assert(quat_lattice_contains(NULL, order, x));
|
||||
ibz_t norm_n, norm_d;
|
||||
ibz_init(&norm_n);
|
||||
ibz_init(&norm_d);
|
||||
|
||||
// Multiply order on the right by x
|
||||
quat_lattice_alg_elem_mul(&(lideal->lattice), order, x, alg);
|
||||
|
||||
// Reduce denominator. This conserves HNF
|
||||
quat_lattice_reduce_denom(&lideal->lattice, &lideal->lattice);
|
||||
|
||||
// Compute norm and check it's integral
|
||||
quat_alg_norm(&norm_n, &norm_d, x, alg);
|
||||
assert(ibz_is_one(&norm_d));
|
||||
ibz_copy(&lideal->norm, &norm_n);
|
||||
|
||||
// Set order
|
||||
lideal->parent_order = order;
|
||||
ibz_finalize(&norm_n);
|
||||
ibz_finalize(&norm_d);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lideal_create(quat_left_ideal_t *lideal,
|
||||
const quat_alg_elem_t *x,
|
||||
const ibz_t *N,
|
||||
const quat_lattice_t *order,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
assert(quat_order_is_maximal(order, alg));
|
||||
assert(!quat_alg_elem_is_zero(x));
|
||||
|
||||
quat_lattice_t ON;
|
||||
quat_lattice_init(&ON);
|
||||
|
||||
|
||||
// Compute ideal generated by x
|
||||
quat_lideal_create_principal(lideal, x, order, alg);
|
||||
|
||||
// Compute norm
|
||||
ibz_gcd(&lideal->norm, &lideal->norm, N);
|
||||
|
||||
// Compute ideal generated by N (without reducing denominator)
|
||||
ibz_mat_4x4_scalar_mul(&ON.basis, N, &order->basis);
|
||||
ibz_copy(&ON.denom, &order->denom);
|
||||
|
||||
|
||||
// Add lattices (reduces denominators)
|
||||
quat_lattice_add(&lideal->lattice, &lideal->lattice, &ON);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// verify norm
|
||||
ibz_t tmp;
|
||||
ibz_init(&tmp);
|
||||
quat_lattice_index(&tmp,&(lideal->lattice),(lideal->parent_order));
|
||||
int ok = ibz_sqrt(&tmp,&tmp);
|
||||
assert(ok);
|
||||
ok = (0==ibz_cmp(&tmp,&(lideal->norm)));
|
||||
assert(ok);
|
||||
ibz_finalize(&tmp);
|
||||
#endif
|
||||
|
||||
// Set order
|
||||
lideal->parent_order = order;
|
||||
// Compute norm
|
||||
quat_lideal_norm(lideal);
|
||||
|
||||
quat_lattice_finalize(&ON);
|
||||
}
|
||||
|
||||
void quat_lideal_make_primitive_then_create(quat_left_ideal_t *lideal, const quat_alg_elem_t *x, const ibz_t *N, const quat_order_t *order, const quat_alg_t *alg) {
|
||||
quat_alg_elem_t prim;
|
||||
ibz_t imprim, n1;
|
||||
quat_alg_elem_init(&prim);
|
||||
ibz_init(&imprim);
|
||||
ibz_init(&n1);
|
||||
|
||||
// Store the primitive part of x in elem
|
||||
quat_alg_make_primitive(&prim.coord, &imprim, x, order, alg);
|
||||
ibz_mat_4x4_eval(&prim.coord, &order->basis, &prim.coord);
|
||||
ibz_copy(&prim.denom, &order->denom);
|
||||
|
||||
// imprim = gcd(imprimitive part of x, N)
|
||||
// n1 = N / imprim
|
||||
ibz_gcd(&imprim, &imprim, N);
|
||||
ibz_div(&n1, &imprim, N, &imprim);
|
||||
|
||||
// Generate the ideal (elem, n1)
|
||||
quat_lideal_create_from_primitive(lideal, &prim, &n1, order, alg);
|
||||
|
||||
quat_alg_elem_finalize(&prim);
|
||||
ibz_finalize(&imprim);
|
||||
ibz_finalize(&n1);
|
||||
}
|
||||
|
||||
int quat_lideal_random_2e(quat_left_ideal_t *lideal, const quat_order_t *order, const quat_alg_t *alg, int64_t e, unsigned char n) {
|
||||
ibq_t norm;
|
||||
ibz_t norm_num;
|
||||
ibq_init(&norm);
|
||||
ibz_init(&norm_num);
|
||||
|
||||
quat_alg_elem_t gen;
|
||||
quat_alg_elem_init(&gen);
|
||||
ibz_set(&gen.coord[0], 1);
|
||||
|
||||
// Start with the trivial left ideal of O
|
||||
quat_lideal_create_principal(lideal, &gen, order, alg);
|
||||
|
||||
// Create the lattice 2·O
|
||||
quat_lattice_t O2;
|
||||
quat_lattice_init(&O2);
|
||||
if (ibz_get(&order->denom) % 2 == 0) {
|
||||
ibz_mat_4x4_copy(&O2.basis, &order->basis);
|
||||
ibz_div_2exp(&O2.denom, &order->denom, 1);
|
||||
} else {
|
||||
ibz_mat_4x4_scalar_mul(&O2.basis, &ibz_const_two, &order->basis);
|
||||
ibz_copy(&O2.denom, &order->denom);
|
||||
}
|
||||
|
||||
for (int i = 0; i < e; ++i) {
|
||||
// Take random gen ∈ lideal until one is found such that
|
||||
// val₂(N(gen)) > i and gen ∉ 2·O
|
||||
do {
|
||||
if (!quat_lattice_random_elem(&gen, &lideal->lattice, n))
|
||||
return 0;
|
||||
|
||||
quat_alg_norm(&norm, &gen, alg);
|
||||
int ok = ibq_to_ibz(&norm_num, &norm);
|
||||
assert(ok);
|
||||
// N(gen)/N(I)
|
||||
ibz_div_2exp(&norm_num, &norm_num, i);
|
||||
}
|
||||
// Check that 2-norm has increased, do not backtrack
|
||||
while ((ibz_get(&norm_num) % 2 != 0) ||
|
||||
quat_lattice_contains(NULL, &O2, &gen, alg));
|
||||
|
||||
// Redefine lideal as (gen, 2^(i+1))
|
||||
ibz_mul(&norm_num, &lideal->norm, &ibz_const_two);
|
||||
quat_lideal_create_from_primitive(lideal, &gen, &norm_num, order, alg);
|
||||
assert(ibz_cmp(&lideal->norm, &norm_num) == 0);
|
||||
}
|
||||
|
||||
quat_lattice_finalize(&O2);
|
||||
ibq_finalize(&norm);
|
||||
ibz_finalize(&norm_num);
|
||||
quat_alg_elem_finalize(&gen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int quat_lideal_generator(quat_alg_elem_t *gen, const quat_left_ideal_t *lideal, const quat_alg_t *alg, int bound) {
|
||||
return(quat_lideal_generator_coprime(gen, lideal, &ibz_const_one, alg,bound));
|
||||
}
|
||||
|
||||
int quat_lideal_generator_coprime(quat_alg_elem_t *gen, const quat_left_ideal_t *lideal, const ibz_t *n, const quat_alg_t *alg, int bound) {
|
||||
ibq_t norm;
|
||||
ibz_t norm_int, norm_n,gcd, r, q, n2, gcd_ref;
|
||||
int
|
||||
quat_lideal_generator(quat_alg_elem_t *gen, const quat_left_ideal_t *lideal, const quat_alg_t *alg)
|
||||
{
|
||||
ibz_t norm_int, norm_n, gcd, r, q, norm_denom;
|
||||
ibz_vec_4_t vec;
|
||||
ibz_vec_4_init(&vec);
|
||||
ibq_init(&norm);
|
||||
ibz_init(&norm_denom);
|
||||
ibz_init(&norm_int);
|
||||
ibz_init(&norm_n);
|
||||
ibz_init(&gcd_ref);
|
||||
ibz_init(&n2);
|
||||
ibz_init(&r);
|
||||
ibz_init(&q);
|
||||
ibz_init(&gcd);
|
||||
ibz_mul(&norm_n, &lideal->norm, n);
|
||||
ibz_mul(&n2, n, n);
|
||||
ibz_gcd(&gcd_ref,n,&(lideal->norm));
|
||||
int a, b, c, d, int_norm;
|
||||
int used_bound = QUATERNION_lideal_generator_search_bound;
|
||||
if(bound != 0)
|
||||
used_bound = bound;
|
||||
assert(used_bound > 0);
|
||||
int a, b, c, d;
|
||||
int found = 0;
|
||||
for (int_norm = 1; int_norm < used_bound; int_norm++){
|
||||
for (a = -int_norm; a <= int_norm; a++){
|
||||
for (b = -int_norm + abs(a); b <= int_norm - abs(a); b++){
|
||||
for (c = -int_norm + abs(a) + abs(b); c <= int_norm - abs(a) - abs(b); c++){
|
||||
int int_norm = 0;
|
||||
while (1) {
|
||||
int_norm++;
|
||||
for (a = -int_norm; a <= int_norm; a++) {
|
||||
for (b = -int_norm + abs(a); b <= int_norm - abs(a); b++) {
|
||||
for (c = -int_norm + abs(a) + abs(b); c <= int_norm - abs(a) - abs(b); c++) {
|
||||
d = int_norm - abs(a) - abs(b) - abs(c);
|
||||
ibz_vec_4_set(&vec,a,b,c,d);
|
||||
ibz_content(&gcd, &vec);
|
||||
if(ibz_is_one(&gcd)){
|
||||
ibz_mat_4x4_eval(&(gen->coord),&(lideal->lattice.basis),&vec);
|
||||
ibz_copy(&(gen->denom),&(lideal->lattice.denom));
|
||||
quat_alg_norm(&norm, gen, alg);
|
||||
found = ibq_to_ibz(&norm_int, &norm);
|
||||
if(found){
|
||||
ibz_div(&q,&r,&norm_int,&(lideal->norm));
|
||||
found = ibz_is_zero(&r);
|
||||
if(found){
|
||||
ibz_gcd(&gcd, &norm_n, &q);
|
||||
found = (0==ibz_cmp(&gcd, &ibz_const_one));
|
||||
if(found){
|
||||
ibz_gcd(&gcd, &n2, &norm_int);
|
||||
found = (0==ibz_cmp(&gcd, &gcd_ref));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(found)
|
||||
ibz_vec_4_set(&vec, a, b, c, d);
|
||||
ibz_vec_4_content(&gcd, &vec);
|
||||
if (ibz_is_one(&gcd)) {
|
||||
ibz_mat_4x4_eval(&(gen->coord), &(lideal->lattice.basis), &vec);
|
||||
ibz_copy(&(gen->denom), &(lideal->lattice.denom));
|
||||
quat_alg_norm(&norm_int, &norm_denom, gen, alg);
|
||||
assert(ibz_is_one(&norm_denom));
|
||||
ibz_div(&q, &r, &norm_int, &(lideal->norm));
|
||||
assert(ibz_is_zero(&r));
|
||||
ibz_gcd(&gcd, &(lideal->norm), &q);
|
||||
found = (0 == ibz_cmp(&gcd, &ibz_const_one));
|
||||
if (found)
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fin:;
|
||||
fin:;
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&q);
|
||||
ibq_finalize(&norm);
|
||||
ibz_finalize(&norm_denom);
|
||||
ibz_finalize(&norm_int);
|
||||
ibz_finalize(&norm_n);
|
||||
ibz_finalize(&gcd_ref);
|
||||
ibz_finalize(&n2);
|
||||
ibz_vec_4_finalize(&vec);
|
||||
ibz_finalize(&gcd);
|
||||
return(found);
|
||||
return (found);
|
||||
}
|
||||
|
||||
int quat_lideal_mul(quat_left_ideal_t *product, const quat_left_ideal_t *lideal, const quat_alg_elem_t *alpha, const quat_alg_t *alg, int bound) {
|
||||
ibq_t norm, norm_lideal;
|
||||
ibz_t norm_int, num, denom;
|
||||
quat_alg_elem_t gen;
|
||||
ibq_init(&norm);
|
||||
ibq_init(&norm_lideal);
|
||||
ibz_init(&norm_int);
|
||||
ibz_init(&num);
|
||||
ibz_init(&denom);
|
||||
quat_alg_elem_init(&gen);
|
||||
|
||||
quat_alg_norm(&norm, alpha, alg);
|
||||
ibq_num(&num,&norm);
|
||||
ibq_denom(&denom,&norm);
|
||||
ibz_gcd(&denom,&denom,&num);
|
||||
ibz_div(&norm_int,&denom,&num,&denom);
|
||||
// Find a random generator gen of norm coprime to N(alpha)
|
||||
// Warning: hardcoded the default constant, and this call can fail!
|
||||
int found = quat_lideal_generator_coprime(&gen, lideal, &norm_int, alg,0);
|
||||
if(found){
|
||||
// Define the ideal (gen·α, N(lideal)·N(α))
|
||||
quat_alg_mul(&gen, &gen, alpha, alg);
|
||||
ibz_copy(&num,&(lideal->norm));
|
||||
ibz_set(&denom,1);
|
||||
ibq_set(&norm_lideal,&num,&denom);
|
||||
ibq_mul(&norm, &norm, &norm_lideal);
|
||||
int ok = ibq_to_ibz(&norm_int, &norm);
|
||||
assert(ok);
|
||||
quat_lideal_create_from_primitive(product, &gen, &norm_int, lideal->parent_order, alg);
|
||||
}
|
||||
|
||||
ibq_finalize(&norm);
|
||||
ibz_finalize(&norm_int);
|
||||
ibq_finalize(&norm_lideal);
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&denom);
|
||||
quat_alg_elem_finalize(&gen);
|
||||
return(found);
|
||||
}
|
||||
|
||||
void quat_lideal_add(quat_left_ideal_t *sum, const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg) {
|
||||
assert(I1->parent_order == I2->parent_order);
|
||||
quat_lattice_add(&sum->lattice, &I1->lattice, &I2->lattice);
|
||||
quat_lattice_index(&sum->norm, &sum->lattice, I1->parent_order);
|
||||
int ok = ibz_sqrt(&sum->norm, &sum->norm);
|
||||
assert(ok);
|
||||
sum->parent_order = I1->parent_order;
|
||||
}
|
||||
|
||||
void quat_lideal_inter(quat_left_ideal_t *inter, const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg) {
|
||||
assert(I1->parent_order == I2->parent_order);
|
||||
quat_lattice_intersect(&inter->lattice, &I1->lattice, &I2->lattice);
|
||||
quat_lattice_index(&inter->norm, &inter->lattice, I1->parent_order);
|
||||
int ok = ibz_sqrt(&inter->norm, &inter->norm);
|
||||
assert(ok);
|
||||
inter->parent_order = I1->parent_order;
|
||||
}
|
||||
|
||||
int quat_lideal_equals(const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg) {
|
||||
return I1->parent_order == I2->parent_order
|
||||
&& ibz_cmp(&I1->norm, &I2->norm) == 0
|
||||
&& quat_lattice_equal(&I1->lattice, &I2->lattice);
|
||||
}
|
||||
|
||||
int quat_lideal_isom(quat_alg_elem_t *iso, const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg){
|
||||
// Only accept strict equality of parent orders
|
||||
if (I1->parent_order != I2->parent_order)
|
||||
return 0;
|
||||
|
||||
quat_lattice_t trans;
|
||||
ibz_mat_4x4_t lll;
|
||||
ibq_t norm, norm_bound;
|
||||
quat_lattice_init(&trans);
|
||||
ibz_mat_4x4_init(&lll);
|
||||
ibq_init(&norm_bound); ibq_init(&norm);
|
||||
|
||||
quat_lattice_right_transporter(&trans, &I1->lattice, &I2->lattice, alg);
|
||||
|
||||
int err = quat_lattice_lll(&lll, &trans, &alg->p, 0);
|
||||
assert(!err);
|
||||
// The shortest vector found by lll is a candidate
|
||||
for (int i = 0; i < 4; i++)
|
||||
ibz_copy(&iso->coord[i], &lll[i][0]);
|
||||
ibz_copy(&iso->denom, &trans.denom);
|
||||
|
||||
// bound on the smallest vector in transporter: N₂ / N₁
|
||||
ibq_set(&norm_bound, &I2->norm, &I1->norm);
|
||||
quat_alg_norm(&norm, iso, alg);
|
||||
|
||||
int isom = ibq_cmp(&norm, &norm_bound) <= 0;
|
||||
|
||||
quat_lattice_finalize(&trans);
|
||||
ibz_mat_4x4_finalize(&lll);
|
||||
ibq_finalize(&norm_bound); ibq_finalize(&norm);
|
||||
|
||||
return isom;
|
||||
}
|
||||
|
||||
void quat_lideal_right_order(quat_order_t *order, const quat_left_ideal_t *lideal, const quat_alg_t *alg){
|
||||
quat_lattice_right_transporter(order, &lideal->lattice, &lideal->lattice, alg);
|
||||
}
|
||||
|
||||
void quat_lideal_reduce_basis(ibz_mat_4x4_t *reduced, ibz_mat_4x4_t *gram, const quat_left_ideal_t *lideal, const quat_alg_t *alg){
|
||||
ibz_mat_4x4_t prod;
|
||||
ibz_mat_4x4_init(&prod);
|
||||
quat_lattice_lll(reduced,&(lideal ->lattice),&(alg->p),0);
|
||||
ibz_mat_4x4_transpose(&prod,reduced);
|
||||
ibz_mat_4x4_mul(&prod,&prod,&(alg ->gram));
|
||||
ibz_mat_4x4_mul(gram,&prod,reduced);
|
||||
ibz_mat_4x4_finalize(&prod);
|
||||
}
|
||||
|
||||
/***************************** Function from quaternion_tools.c ***************************************/
|
||||
|
||||
void quat_connecting_ideal(quat_left_ideal_t *connecting_ideal, const quat_order_t *O1, const quat_order_t *O2, const quat_alg_t *alg){
|
||||
quat_lattice_t inter;
|
||||
ibz_t norm,one;
|
||||
ibz_mat_4x4_t gens;
|
||||
quat_alg_elem_t gen;
|
||||
quat_left_ideal_t I[4];
|
||||
void
|
||||
quat_lideal_mul(quat_left_ideal_t *product,
|
||||
const quat_left_ideal_t *lideal,
|
||||
const quat_alg_elem_t *alpha,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
assert(quat_order_is_maximal((lideal->parent_order), alg));
|
||||
ibz_t norm, norm_d;
|
||||
ibz_init(&norm);
|
||||
ibz_init(&one);
|
||||
quat_lattice_init(&inter);
|
||||
ibz_mat_4x4_init(&gens);
|
||||
quat_alg_elem_init(&gen);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
quat_left_ideal_init(I + i);
|
||||
}
|
||||
ibz_set(&one,1);
|
||||
|
||||
quat_lattice_intersect(&inter,O1,O2);
|
||||
quat_lattice_index(&norm,&inter,O1);
|
||||
ibz_mat_4x4_scalar_mul(&gens,&norm,&(O2->basis));
|
||||
quat_alg_scalar(&gen,&norm,&one);
|
||||
quat_lideal_create_principal(connecting_ideal, &gen, O1, alg);
|
||||
for (int i = 0; i < 4; i++) {;
|
||||
quat_alg_elem_copy_ibz(&gen,&(O2->denom),&(gens[0][i]),&(gens[1][i]),&(gens[2][i]),&(gens[3][i]));
|
||||
quat_lideal_create_principal(I + i, &gen, O1, alg);
|
||||
}
|
||||
|
||||
quat_lideal_add(connecting_ideal, connecting_ideal, I+0, alg);
|
||||
quat_lideal_add(connecting_ideal, connecting_ideal, I+1, alg);
|
||||
quat_lideal_add(connecting_ideal, connecting_ideal, I+2, alg);
|
||||
quat_lideal_add(connecting_ideal, connecting_ideal, I+3, alg);
|
||||
|
||||
ibz_init(&norm_d);
|
||||
quat_lattice_alg_elem_mul(&(product->lattice), &(lideal->lattice), alpha, alg);
|
||||
product->parent_order = lideal->parent_order;
|
||||
quat_alg_norm(&norm, &norm_d, alpha, alg);
|
||||
ibz_mul(&(product->norm), &(lideal->norm), &norm);
|
||||
assert(ibz_divides(&(product->norm), &norm_d));
|
||||
ibz_div(&(product->norm), &norm, &(product->norm), &norm_d);
|
||||
assert(quat_lideal_norm_verify(lideal));
|
||||
ibz_finalize(&norm_d);
|
||||
ibz_finalize(&norm);
|
||||
ibz_finalize(&one);
|
||||
quat_lattice_finalize(&inter);
|
||||
ibz_mat_4x4_finalize(&gens);
|
||||
quat_alg_elem_finalize(&gen);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
quat_left_ideal_finalize(I + i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
quat_lideal_add(quat_left_ideal_t *sum, const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg)
|
||||
{
|
||||
assert(I1->parent_order == I2->parent_order);
|
||||
assert(quat_order_is_maximal((I2->parent_order), alg));
|
||||
quat_lattice_add(&sum->lattice, &I1->lattice, &I2->lattice);
|
||||
sum->parent_order = I1->parent_order;
|
||||
quat_lideal_norm(sum);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lideal_inter(quat_left_ideal_t *inter,
|
||||
const quat_left_ideal_t *I1,
|
||||
const quat_left_ideal_t *I2,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
assert(I1->parent_order == I2->parent_order);
|
||||
assert(quat_order_is_maximal((I2->parent_order), alg));
|
||||
quat_lattice_intersect(&inter->lattice, &I1->lattice, &I2->lattice);
|
||||
inter->parent_order = I1->parent_order;
|
||||
quat_lideal_norm(inter);
|
||||
}
|
||||
|
||||
int
|
||||
quat_lideal_equals(const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg)
|
||||
{
|
||||
assert(quat_order_is_maximal((I2->parent_order), alg));
|
||||
assert(quat_order_is_maximal((I1->parent_order), alg));
|
||||
return (I1->parent_order == I2->parent_order) & (ibz_cmp(&I1->norm, &I2->norm) == 0) &
|
||||
quat_lattice_equal(&I1->lattice, &I2->lattice);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lideal_inverse_lattice_without_hnf(quat_lattice_t *inv, const quat_left_ideal_t *lideal, const quat_alg_t *alg)
|
||||
{
|
||||
assert(quat_order_is_maximal((lideal->parent_order), alg));
|
||||
quat_lattice_conjugate_without_hnf(inv, &(lideal->lattice));
|
||||
ibz_mul(&(inv->denom), &(inv->denom), &(lideal->norm));
|
||||
}
|
||||
|
||||
// following the implementation of ideal isomorphisms in the code of LearningToSQI's sage
|
||||
// implementation of SQIsign
|
||||
void
|
||||
quat_lideal_right_transporter(quat_lattice_t *trans,
|
||||
const quat_left_ideal_t *lideal1,
|
||||
const quat_left_ideal_t *lideal2,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
assert(quat_order_is_maximal((lideal1->parent_order), alg));
|
||||
assert(quat_order_is_maximal((lideal2->parent_order), alg));
|
||||
assert(lideal1->parent_order == lideal2->parent_order);
|
||||
quat_lattice_t inv;
|
||||
quat_lattice_init(&inv);
|
||||
quat_lideal_inverse_lattice_without_hnf(&inv, lideal1, alg);
|
||||
quat_lattice_mul(trans, &inv, &(lideal2->lattice), alg);
|
||||
quat_lattice_finalize(&inv);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lideal_right_order(quat_lattice_t *order, const quat_left_ideal_t *lideal, const quat_alg_t *alg)
|
||||
{
|
||||
assert(quat_order_is_maximal((lideal->parent_order), alg));
|
||||
quat_lideal_right_transporter(order, lideal, lideal, alg);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lideal_class_gram(ibz_mat_4x4_t *G, const quat_left_ideal_t *lideal, const quat_alg_t *alg)
|
||||
{
|
||||
quat_lattice_gram(G, &(lideal->lattice), alg);
|
||||
|
||||
// divide by norm · denominator²
|
||||
ibz_t divisor, rmd;
|
||||
ibz_init(&divisor);
|
||||
ibz_init(&rmd);
|
||||
|
||||
ibz_mul(&divisor, &(lideal->lattice.denom), &(lideal->lattice.denom));
|
||||
ibz_mul(&divisor, &divisor, &(lideal->norm));
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j <= i; j++) {
|
||||
ibz_div(&(*G)[i][j], &rmd, &(*G)[i][j], &divisor);
|
||||
assert(ibz_is_zero(&rmd));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j <= i - 1; j++) {
|
||||
ibz_copy(&(*G)[j][i], &(*G)[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
ibz_finalize(&rmd);
|
||||
ibz_finalize(&divisor);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lideal_conjugate_without_hnf(quat_left_ideal_t *conj,
|
||||
quat_lattice_t *new_parent_order,
|
||||
const quat_left_ideal_t *lideal,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
quat_lideal_right_order(new_parent_order, lideal, alg);
|
||||
quat_lattice_conjugate_without_hnf(&(conj->lattice), &(lideal->lattice));
|
||||
conj->parent_order = new_parent_order;
|
||||
ibz_copy(&(conj->norm), &(lideal->norm));
|
||||
}
|
||||
|
||||
int
|
||||
quat_order_discriminant(ibz_t *disc, const quat_lattice_t *order, const quat_alg_t *alg)
|
||||
{
|
||||
int ok = 0;
|
||||
ibz_t det, sqr, div;
|
||||
ibz_mat_4x4_t transposed, norm, prod;
|
||||
ibz_init(&det);
|
||||
ibz_init(&sqr);
|
||||
ibz_init(&div);
|
||||
ibz_mat_4x4_init(&transposed);
|
||||
ibz_mat_4x4_init(&norm);
|
||||
ibz_mat_4x4_init(&prod);
|
||||
ibz_mat_4x4_transpose(&transposed, &(order->basis));
|
||||
// multiply gram matrix by 2 because of reduced trace
|
||||
ibz_mat_4x4_identity(&norm);
|
||||
ibz_copy(&(norm[2][2]), &(alg->p));
|
||||
ibz_copy(&(norm[3][3]), &(alg->p));
|
||||
ibz_mat_4x4_scalar_mul(&norm, &ibz_const_two, &norm);
|
||||
ibz_mat_4x4_mul(&prod, &transposed, &norm);
|
||||
ibz_mat_4x4_mul(&prod, &prod, &(order->basis));
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL, &det, &prod);
|
||||
ibz_mul(&div, &(order->denom), &(order->denom));
|
||||
ibz_mul(&div, &div, &div);
|
||||
ibz_mul(&div, &div, &div);
|
||||
ibz_div(&sqr, &div, &det, &div);
|
||||
ok = ibz_is_zero(&div);
|
||||
ok = ok & ibz_sqrt(disc, &sqr);
|
||||
ibz_finalize(&det);
|
||||
ibz_finalize(&div);
|
||||
ibz_finalize(&sqr);
|
||||
ibz_mat_4x4_finalize(&transposed);
|
||||
ibz_mat_4x4_finalize(&norm);
|
||||
ibz_mat_4x4_finalize(&prod);
|
||||
return (ok);
|
||||
}
|
||||
|
||||
int
|
||||
quat_order_is_maximal(const quat_lattice_t *order, const quat_alg_t *alg)
|
||||
{
|
||||
int res;
|
||||
ibz_t disc;
|
||||
ibz_init(&disc);
|
||||
quat_order_discriminant(&disc, order, alg);
|
||||
res = (ibz_cmp(&disc, &(alg->p)) == 0);
|
||||
ibz_finalize(&disc);
|
||||
return (res);
|
||||
}
|
||||
|
||||
303
src/quaternion/ref/generic/include/intbig.h
Normal file
303
src/quaternion/ref/generic/include/intbig.h
Normal file
@@ -0,0 +1,303 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Luca De Feo, Sina Schaeffler
|
||||
*
|
||||
* @brief Declarations for big integers in the reference implementation
|
||||
*/
|
||||
|
||||
#ifndef INTBIG_H
|
||||
#define INTBIG_H
|
||||
|
||||
#include <sqisign_namespace.h>
|
||||
#if defined(MINI_GMP)
|
||||
#include <mini-gmp.h>
|
||||
#include <mini-gmp-extra.h>
|
||||
#else
|
||||
#include <gmp.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <tutil.h>
|
||||
|
||||
/** @ingroup quat_quat
|
||||
* @defgroup ibz_all Signed big integers (gmp-based)
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup ibz_t Precise number types
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Type for signed long integers
|
||||
*
|
||||
* @typedef ibz_t
|
||||
*
|
||||
* For integers of arbitrary size, used by intbig module, using gmp
|
||||
*/
|
||||
typedef mpz_t ibz_t;
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @defgroup ibz_c Constants
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constant zero
|
||||
*/
|
||||
extern const ibz_t ibz_const_zero;
|
||||
|
||||
/**
|
||||
* Constant one
|
||||
*/
|
||||
extern const ibz_t ibz_const_one;
|
||||
|
||||
/**
|
||||
* Constant two
|
||||
*/
|
||||
extern const ibz_t ibz_const_two;
|
||||
|
||||
/**
|
||||
* Constant three
|
||||
*/
|
||||
extern const ibz_t ibz_const_three;
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @defgroup ibz_finit Constructors and Destructors
|
||||
* @{
|
||||
*/
|
||||
|
||||
void ibz_init(ibz_t *x);
|
||||
void ibz_finalize(ibz_t *x);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @defgroup ibz_za Basic integer arithmetic
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief sum=a+b
|
||||
*/
|
||||
void ibz_add(ibz_t *sum, const ibz_t *a, const ibz_t *b);
|
||||
|
||||
/** @brief diff=a-b
|
||||
*/
|
||||
void ibz_sub(ibz_t *diff, const ibz_t *a, const ibz_t *b);
|
||||
|
||||
/** @brief prod=a*b
|
||||
*/
|
||||
void ibz_mul(ibz_t *prod, const ibz_t *a, const ibz_t *b);
|
||||
|
||||
/** @brief neg=-a
|
||||
*/
|
||||
void ibz_neg(ibz_t *neg, const ibz_t *a);
|
||||
|
||||
/** @brief abs=|a|
|
||||
*/
|
||||
void ibz_abs(ibz_t *abs, const ibz_t *a);
|
||||
|
||||
/** @brief Euclidean division of a by b
|
||||
*
|
||||
* Computes quotient, remainder so that remainder+quotient*b = a where 0<=|remainder|<|b|
|
||||
* The quotient is rounded towards zero.
|
||||
*/
|
||||
void ibz_div(ibz_t *quotient, ibz_t *remainder, const ibz_t *a, const ibz_t *b);
|
||||
|
||||
/** @brief Euclidean division of a by 2^exp
|
||||
*
|
||||
* Computes a right shift of abs(a) by exp bits, then sets sign(quotient) to sign(a).
|
||||
*
|
||||
* Division and rounding is as in ibz_div.
|
||||
*/
|
||||
void ibz_div_2exp(ibz_t *quotient, const ibz_t *a, uint32_t exp);
|
||||
|
||||
/** @brief Two adic valuation computation
|
||||
*
|
||||
* Computes the position of the first 1 in the binary representation of the integer given in input
|
||||
*
|
||||
* When this number is a power of two this gives the two adic valuation of the integer
|
||||
*/
|
||||
int ibz_two_adic(ibz_t *pow);
|
||||
|
||||
/** @brief r = a mod b
|
||||
*
|
||||
* Assumes valid inputs
|
||||
* The sign of the divisor is ignored, the result is always non-negative
|
||||
*/
|
||||
void ibz_mod(ibz_t *r, const ibz_t *a, const ibz_t *b);
|
||||
|
||||
unsigned long int ibz_mod_ui(const mpz_t *n, unsigned long int d);
|
||||
|
||||
/** @brief Test if a = 0 mod b
|
||||
*/
|
||||
int ibz_divides(const ibz_t *a, const ibz_t *b);
|
||||
|
||||
/** @brief pow=x^e
|
||||
*
|
||||
* Assumes valid inputs, The case 0^0 yields 1.
|
||||
*/
|
||||
void ibz_pow(ibz_t *pow, const ibz_t *x, uint32_t e);
|
||||
|
||||
/** @brief pow=(x^e) mod m
|
||||
*
|
||||
* Assumes valid inputs
|
||||
*/
|
||||
void ibz_pow_mod(ibz_t *pow, const ibz_t *x, const ibz_t *e, const ibz_t *m);
|
||||
|
||||
/** @brief Compare a and b
|
||||
*
|
||||
* @returns a positive value if a > b, zero if a = b, and a negative value if a < b
|
||||
*/
|
||||
int ibz_cmp(const ibz_t *a, const ibz_t *b);
|
||||
|
||||
/** @brief Test if x is 0
|
||||
*
|
||||
* @returns 1 if x=0, 0 otherwise
|
||||
*/
|
||||
int ibz_is_zero(const ibz_t *x);
|
||||
|
||||
/** @brief Test if x is 1
|
||||
*
|
||||
* @returns 1 if x=1, 0 otherwise
|
||||
*/
|
||||
int ibz_is_one(const ibz_t *x);
|
||||
|
||||
/** @brief Compare x to y
|
||||
*
|
||||
* @returns 0 if x=y, positive if x>y, negative if x<y
|
||||
*/
|
||||
int ibz_cmp_int32(const ibz_t *x, int32_t y);
|
||||
|
||||
/** @brief Test if x is even
|
||||
*
|
||||
* @returns 1 if x is even, 0 otherwise
|
||||
*/
|
||||
int ibz_is_even(const ibz_t *x);
|
||||
|
||||
/** @brief Test if x is odd
|
||||
*
|
||||
* @returns 1 if x is odd, 0 otherwise
|
||||
*/
|
||||
int ibz_is_odd(const ibz_t *x);
|
||||
|
||||
/** @brief set i to value x
|
||||
*/
|
||||
void ibz_set(ibz_t *i, int32_t x);
|
||||
|
||||
/** @brief Copy value into target
|
||||
*/
|
||||
void ibz_copy(ibz_t *target, const ibz_t *value);
|
||||
|
||||
/** @brief Exchange values of a and b
|
||||
*/
|
||||
void ibz_swap(ibz_t *a, ibz_t *b);
|
||||
|
||||
/** @brief Copy dig array to target, given digits and the length of the dig array
|
||||
* Restriction: dig represents a non-negative integer
|
||||
*
|
||||
* @param target Target ibz_t element
|
||||
* @param dig array of digits
|
||||
* @param dig_len length of the digits array
|
||||
*/
|
||||
void ibz_copy_digits(ibz_t *target, const digit_t *dig, int dig_len);
|
||||
#define ibz_copy_digit_array(I, T) \
|
||||
do { \
|
||||
ibz_copy_digits((I), (T), sizeof(T) / sizeof(*(T))); \
|
||||
} while (0)
|
||||
|
||||
// void ibz_printf(const char* format, ...);
|
||||
#define ibz_printf gmp_printf
|
||||
|
||||
/** @brief Copy an ibz_t to target digit_t array.
|
||||
* Restrictions: ibz >= 0 and target must hold sufficient elements to hold ibz
|
||||
*
|
||||
* @param target Target digit_t array
|
||||
* @param ibz ibz source ibz_t element
|
||||
*/
|
||||
void ibz_to_digits(digit_t *target, const ibz_t *ibz);
|
||||
#define ibz_to_digit_array(T, I) \
|
||||
do { \
|
||||
memset((T), 0, sizeof(T)); \
|
||||
ibz_to_digits((T), (I)); \
|
||||
} while (0)
|
||||
|
||||
/** @brief get int32_t equal to the lowest bits of i
|
||||
*
|
||||
* Should not be used to get the value of i if its bitsize is close to 32 bit
|
||||
* It can however be used on any i to get an int32_t of the same parity as i (and same value modulo
|
||||
* 4)
|
||||
*
|
||||
* @param i Input integer
|
||||
*/
|
||||
int32_t ibz_get(const ibz_t *i);
|
||||
|
||||
/** @brief generate random value in [a, b]
|
||||
* assumed that a >= 0 and b >= 0 and a < b
|
||||
* @returns 1 on success, 0 on failiure
|
||||
*/
|
||||
int ibz_rand_interval(ibz_t *rand, const ibz_t *a, const ibz_t *b);
|
||||
|
||||
/** @brief generate random value in [-m, m]
|
||||
* assumed that m > 0 and bitlength of m < 32 bit
|
||||
* @returns 1 on success, 0 on failiure
|
||||
*/
|
||||
int ibz_rand_interval_minm_m(ibz_t *rand, int32_t m);
|
||||
|
||||
/** @brief Bitsize of a.
|
||||
*
|
||||
* @returns Bitsize of a.
|
||||
*
|
||||
*/
|
||||
int ibz_bitsize(const ibz_t *a);
|
||||
|
||||
/** @brief Size of a in given base.
|
||||
*
|
||||
* @returns Size of a in given base.
|
||||
*
|
||||
*/
|
||||
int ibz_size_in_base(const ibz_t *a, int base);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @defgroup ibz_n Number theory functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Greatest common divisor
|
||||
*
|
||||
* @param gcd Output: Set to the gcd of a and b
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
void ibz_gcd(ibz_t *gcd, const ibz_t *a, const ibz_t *b);
|
||||
|
||||
/**
|
||||
* @brief Modular inverse
|
||||
*
|
||||
* @param inv Output: Set to the integer in [0,mod[ such that a*inv = 1 mod (mod) if it exists
|
||||
* @param a
|
||||
* @param mod
|
||||
* @returns 1 if inverse exists and was computed, 0 otherwise
|
||||
*/
|
||||
int ibz_invmod(ibz_t *inv, const ibz_t *a, const ibz_t *mod);
|
||||
|
||||
/**
|
||||
* @brief Floor of Integer square root
|
||||
*
|
||||
* @param sqrt Output: Set to the floor of an integer square root
|
||||
* @param a number of which a floor of an integer square root is searched
|
||||
*/
|
||||
void ibz_sqrt_floor(ibz_t *sqrt, const ibz_t *a);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
// end of ibz_all
|
||||
/** @}
|
||||
*/
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
791
src/quaternion/ref/generic/intbig.c
Normal file
791
src/quaternion/ref/generic/intbig.c
Normal file
@@ -0,0 +1,791 @@
|
||||
#include "intbig_internal.h"
|
||||
#include <limits.h>
|
||||
#include <rng.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
// #define DEBUG_VERBOSE
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
#define DEBUG_STR_PRINTF(x) printf("%s\n", (x));
|
||||
|
||||
static void
|
||||
DEBUG_STR_FUN_INT_MP(const char *op, int arg1, const ibz_t *arg2)
|
||||
{
|
||||
int arg2_size = ibz_size_in_base(arg2, 16);
|
||||
char arg2_str[arg2_size + 2];
|
||||
ibz_convert_to_str(arg2, arg2_str, 16);
|
||||
|
||||
printf("%s,%x,%s\n", op, arg1, arg2_str);
|
||||
}
|
||||
|
||||
static void
|
||||
DEBUG_STR_FUN_3(const char *op, const ibz_t *arg1, const ibz_t *arg2, const ibz_t *arg3)
|
||||
{
|
||||
int arg1_size = ibz_size_in_base(arg1, 16);
|
||||
char arg1_str[arg1_size + 2];
|
||||
ibz_convert_to_str(arg1, arg1_str, 16);
|
||||
|
||||
int arg2_size = ibz_size_in_base(arg2, 16);
|
||||
char arg2_str[arg2_size + 2];
|
||||
ibz_convert_to_str(arg2, arg2_str, 16);
|
||||
|
||||
int arg3_size = ibz_size_in_base(arg3, 16);
|
||||
char arg3_str[arg3_size + 2];
|
||||
ibz_convert_to_str(arg3, arg3_str, 16);
|
||||
|
||||
printf("%s,%s,%s,%s\n", op, arg1_str, arg2_str, arg3_str);
|
||||
}
|
||||
|
||||
static void
|
||||
DEBUG_STR_FUN_MP2_INT(const char *op, const ibz_t *arg1, const ibz_t *arg2, int arg3)
|
||||
{
|
||||
int arg1_size = ibz_size_in_base(arg1, 16);
|
||||
char arg1_str[arg1_size + 2];
|
||||
ibz_convert_to_str(arg1, arg1_str, 16);
|
||||
|
||||
int arg2_size = ibz_size_in_base(arg2, 16);
|
||||
char arg2_str[arg2_size + 2];
|
||||
ibz_convert_to_str(arg2, arg2_str, 16);
|
||||
|
||||
printf("%s,%s,%s,%x\n", op, arg1_str, arg2_str, arg3);
|
||||
}
|
||||
|
||||
static void
|
||||
DEBUG_STR_FUN_INT_MP2(const char *op, int arg1, const ibz_t *arg2, const ibz_t *arg3)
|
||||
{
|
||||
int arg2_size = ibz_size_in_base(arg2, 16);
|
||||
char arg2_str[arg2_size + 2];
|
||||
ibz_convert_to_str(arg2, arg2_str, 16);
|
||||
|
||||
int arg3_size = ibz_size_in_base(arg3, 16);
|
||||
char arg3_str[arg3_size + 2];
|
||||
ibz_convert_to_str(arg3, arg3_str, 16);
|
||||
|
||||
if (arg1 >= 0)
|
||||
printf("%s,%x,%s,%s\n", op, arg1, arg2_str, arg3_str);
|
||||
else
|
||||
printf("%s,-%x,%s,%s\n", op, -arg1, arg2_str, arg3_str);
|
||||
}
|
||||
|
||||
static void
|
||||
DEBUG_STR_FUN_INT_MP_INT(const char *op, int arg1, const ibz_t *arg2, int arg3)
|
||||
{
|
||||
int arg2_size = ibz_size_in_base(arg2, 16);
|
||||
char arg2_str[arg2_size + 2];
|
||||
ibz_convert_to_str(arg2, arg2_str, 16);
|
||||
|
||||
printf("%s,%x,%s,%x\n", op, arg1, arg2_str, arg3);
|
||||
}
|
||||
|
||||
static void
|
||||
DEBUG_STR_FUN_4(const char *op, const ibz_t *arg1, const ibz_t *arg2, const ibz_t *arg3, const ibz_t *arg4)
|
||||
{
|
||||
int arg1_size = ibz_size_in_base(arg1, 16);
|
||||
char arg1_str[arg1_size + 2];
|
||||
ibz_convert_to_str(arg1, arg1_str, 16);
|
||||
|
||||
int arg2_size = ibz_size_in_base(arg2, 16);
|
||||
char arg2_str[arg2_size + 2];
|
||||
ibz_convert_to_str(arg2, arg2_str, 16);
|
||||
|
||||
int arg3_size = ibz_size_in_base(arg3, 16);
|
||||
char arg3_str[arg3_size + 2];
|
||||
ibz_convert_to_str(arg3, arg3_str, 16);
|
||||
|
||||
int arg4_size = ibz_size_in_base(arg4, 16);
|
||||
char arg4_str[arg4_size + 2];
|
||||
ibz_convert_to_str(arg4, arg4_str, 16);
|
||||
|
||||
printf("%s,%s,%s,%s,%s\n", op, arg1_str, arg2_str, arg3_str, arg4_str);
|
||||
}
|
||||
#else
|
||||
#define DEBUG_STR_PRINTF(x)
|
||||
#define DEBUG_STR_FUN_INT_MP(op, arg1, arg2)
|
||||
#define DEBUG_STR_FUN_3(op, arg1, arg2, arg3)
|
||||
#define DEBUG_STR_FUN_INT_MP2(op, arg1, arg2, arg3)
|
||||
#define DEBUG_STR_FUN_INT_MP_INT(op, arg1, arg2, arg3)
|
||||
#define DEBUG_STR_FUN_4(op, arg1, arg2, arg3, arg4)
|
||||
#endif
|
||||
|
||||
/** @defgroup ibz_t Constants
|
||||
* @{
|
||||
*/
|
||||
|
||||
const __mpz_struct ibz_const_zero[1] = {
|
||||
{
|
||||
._mp_alloc = 0,
|
||||
._mp_size = 0,
|
||||
._mp_d = (mp_limb_t[]){ 0 },
|
||||
}
|
||||
};
|
||||
|
||||
const __mpz_struct ibz_const_one[1] = {
|
||||
{
|
||||
._mp_alloc = 0,
|
||||
._mp_size = 1,
|
||||
._mp_d = (mp_limb_t[]){ 1 },
|
||||
}
|
||||
};
|
||||
|
||||
const __mpz_struct ibz_const_two[1] = {
|
||||
{
|
||||
._mp_alloc = 0,
|
||||
._mp_size = 1,
|
||||
._mp_d = (mp_limb_t[]){ 2 },
|
||||
}
|
||||
};
|
||||
|
||||
const __mpz_struct ibz_const_three[1] = {
|
||||
{
|
||||
._mp_alloc = 0,
|
||||
._mp_size = 1,
|
||||
._mp_d = (mp_limb_t[]){ 3 },
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
ibz_init(ibz_t *x)
|
||||
{
|
||||
mpz_init(*x);
|
||||
}
|
||||
|
||||
void
|
||||
ibz_finalize(ibz_t *x)
|
||||
{
|
||||
mpz_clear(*x);
|
||||
}
|
||||
|
||||
void
|
||||
ibz_add(ibz_t *sum, const ibz_t *a, const ibz_t *b)
|
||||
{
|
||||
#ifdef DEBUG_VERBOSE
|
||||
ibz_t a_cp, b_cp;
|
||||
ibz_init(&a_cp);
|
||||
ibz_init(&b_cp);
|
||||
ibz_copy(&a_cp, a);
|
||||
ibz_copy(&b_cp, b);
|
||||
#endif
|
||||
mpz_add(*sum, *a, *b);
|
||||
#ifdef DEBUG_VERBOSE
|
||||
DEBUG_STR_FUN_3("ibz_add", sum, &a_cp, &b_cp);
|
||||
ibz_finalize(&a_cp);
|
||||
ibz_finalize(&b_cp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ibz_sub(ibz_t *diff, const ibz_t *a, const ibz_t *b)
|
||||
{
|
||||
#ifdef DEBUG_VERBOSE
|
||||
ibz_t a_cp, b_cp;
|
||||
ibz_init(&a_cp);
|
||||
ibz_init(&b_cp);
|
||||
ibz_copy(&a_cp, a);
|
||||
ibz_copy(&b_cp, b);
|
||||
#endif
|
||||
mpz_sub(*diff, *a, *b);
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
DEBUG_STR_FUN_3("ibz_sub", diff, &a_cp, &b_cp);
|
||||
ibz_finalize(&a_cp);
|
||||
ibz_finalize(&b_cp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ibz_mul(ibz_t *prod, const ibz_t *a, const ibz_t *b)
|
||||
{
|
||||
#ifdef DEBUG_VERBOSE
|
||||
ibz_t a_cp, b_cp;
|
||||
ibz_init(&a_cp);
|
||||
ibz_init(&b_cp);
|
||||
ibz_copy(&a_cp, a);
|
||||
ibz_copy(&b_cp, b);
|
||||
#endif
|
||||
mpz_mul(*prod, *a, *b);
|
||||
#ifdef DEBUG_VERBOSE
|
||||
DEBUG_STR_FUN_3("ibz_mul", prod, &a_cp, &b_cp);
|
||||
ibz_finalize(&a_cp);
|
||||
ibz_finalize(&b_cp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ibz_neg(ibz_t *neg, const ibz_t *a)
|
||||
{
|
||||
mpz_neg(*neg, *a);
|
||||
}
|
||||
|
||||
void
|
||||
ibz_abs(ibz_t *abs, const ibz_t *a)
|
||||
{
|
||||
mpz_abs(*abs, *a);
|
||||
}
|
||||
|
||||
void
|
||||
ibz_div(ibz_t *quotient, ibz_t *remainder, const ibz_t *a, const ibz_t *b)
|
||||
{
|
||||
#ifdef DEBUG_VERBOSE
|
||||
ibz_t a_cp, b_cp;
|
||||
ibz_init(&a_cp);
|
||||
ibz_init(&b_cp);
|
||||
ibz_copy(&a_cp, a);
|
||||
ibz_copy(&b_cp, b);
|
||||
#endif
|
||||
mpz_tdiv_qr(*quotient, *remainder, *a, *b);
|
||||
#ifdef DEBUG_VERBOSE
|
||||
DEBUG_STR_FUN_4("ibz_div", quotient, remainder, &a_cp, &b_cp);
|
||||
ibz_finalize(&a_cp);
|
||||
ibz_finalize(&b_cp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ibz_div_2exp(ibz_t *quotient, const ibz_t *a, uint32_t exp)
|
||||
{
|
||||
#ifdef DEBUG_VERBOSE
|
||||
ibz_t a_cp;
|
||||
ibz_init(&a_cp);
|
||||
ibz_copy(&a_cp, a);
|
||||
#endif
|
||||
mpz_tdiv_q_2exp(*quotient, *a, exp);
|
||||
#ifdef DEBUG_VERBOSE
|
||||
DEBUG_STR_FUN_MP2_INT("ibz_div_2exp,%Zx,%Zx,%x\n", quotient, &a_cp, exp);
|
||||
ibz_finalize(&a_cp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ibz_div_floor(ibz_t *q, ibz_t *r, const ibz_t *n, const ibz_t *d)
|
||||
{
|
||||
mpz_fdiv_qr(*q, *r, *n, *d);
|
||||
}
|
||||
|
||||
void
|
||||
ibz_mod(ibz_t *r, const ibz_t *a, const ibz_t *b)
|
||||
{
|
||||
mpz_mod(*r, *a, *b);
|
||||
}
|
||||
|
||||
unsigned long int
|
||||
ibz_mod_ui(const mpz_t *n, unsigned long int d)
|
||||
{
|
||||
return mpz_fdiv_ui(*n, d);
|
||||
}
|
||||
|
||||
int
|
||||
ibz_divides(const ibz_t *a, const ibz_t *b)
|
||||
{
|
||||
return mpz_divisible_p(*a, *b);
|
||||
}
|
||||
|
||||
void
|
||||
ibz_pow(ibz_t *pow, const ibz_t *x, uint32_t e)
|
||||
{
|
||||
mpz_pow_ui(*pow, *x, e);
|
||||
}
|
||||
|
||||
void
|
||||
ibz_pow_mod(ibz_t *pow, const ibz_t *x, const ibz_t *e, const ibz_t *m)
|
||||
{
|
||||
mpz_powm(*pow, *x, *e, *m);
|
||||
DEBUG_STR_FUN_4("ibz_pow_mod", pow, x, e, m);
|
||||
}
|
||||
|
||||
int
|
||||
ibz_two_adic(ibz_t *pow)
|
||||
{
|
||||
return mpz_scan1(*pow, 0);
|
||||
}
|
||||
|
||||
int
|
||||
ibz_cmp(const ibz_t *a, const ibz_t *b)
|
||||
{
|
||||
int ret = mpz_cmp(*a, *b);
|
||||
DEBUG_STR_FUN_INT_MP2("ibz_cmp", ret, a, b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_is_zero(const ibz_t *x)
|
||||
{
|
||||
int ret = !mpz_cmp_ui(*x, 0);
|
||||
DEBUG_STR_FUN_INT_MP("ibz_is_zero", ret, x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_is_one(const ibz_t *x)
|
||||
{
|
||||
int ret = !mpz_cmp_ui(*x, 1);
|
||||
DEBUG_STR_FUN_INT_MP("ibz_is_one", ret, x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_cmp_int32(const ibz_t *x, int32_t y)
|
||||
{
|
||||
int ret = mpz_cmp_si(*x, (signed long int)y);
|
||||
DEBUG_STR_FUN_INT_MP_INT("ibz_cmp_int32", ret, x, y);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_is_even(const ibz_t *x)
|
||||
{
|
||||
int ret = !mpz_tstbit(*x, 0);
|
||||
DEBUG_STR_FUN_INT_MP("ibz_is_even", ret, x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_is_odd(const ibz_t *x)
|
||||
{
|
||||
int ret = mpz_tstbit(*x, 0);
|
||||
DEBUG_STR_FUN_INT_MP("ibz_is_odd", ret, x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
ibz_set(ibz_t *i, int32_t x)
|
||||
{
|
||||
mpz_set_si(*i, x);
|
||||
}
|
||||
|
||||
int
|
||||
ibz_convert_to_str(const ibz_t *i, char *str, int base)
|
||||
{
|
||||
if (!str || (base != 10 && base != 16))
|
||||
return 0;
|
||||
|
||||
mpz_get_str(str, base, *i);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ibz_print(const ibz_t *num, int base)
|
||||
{
|
||||
assert(base == 10 || base == 16);
|
||||
|
||||
int num_size = ibz_size_in_base(num, base);
|
||||
char num_str[num_size + 2];
|
||||
ibz_convert_to_str(num, num_str, base);
|
||||
printf("%s", num_str);
|
||||
}
|
||||
|
||||
int
|
||||
ibz_set_from_str(ibz_t *i, const char *str, int base)
|
||||
{
|
||||
return (1 + mpz_set_str(*i, str, base));
|
||||
}
|
||||
|
||||
void
|
||||
ibz_copy(ibz_t *target, const ibz_t *value)
|
||||
{
|
||||
mpz_set(*target, *value);
|
||||
}
|
||||
|
||||
void
|
||||
ibz_swap(ibz_t *a, ibz_t *b)
|
||||
{
|
||||
mpz_swap(*a, *b);
|
||||
}
|
||||
|
||||
int32_t
|
||||
ibz_get(const ibz_t *i)
|
||||
{
|
||||
#if LONG_MAX == INT32_MAX
|
||||
return (int32_t)mpz_get_si(*i);
|
||||
#elif LONG_MAX > INT32_MAX
|
||||
// Extracts the sign bit and the 31 least significant bits
|
||||
signed long int t = mpz_get_si(*i);
|
||||
return (int32_t)((t >> (sizeof(signed long int) * 8 - 32)) & INT32_C(0x80000000)) | (t & INT32_C(0x7FFFFFFF));
|
||||
#else
|
||||
#error Unsupported configuration: LONG_MAX must be >= INT32_MAX
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
ibz_rand_interval(ibz_t *rand, const ibz_t *a, const ibz_t *b)
|
||||
{
|
||||
int randret;
|
||||
int ret = 1;
|
||||
mpz_t tmp;
|
||||
mpz_t bmina;
|
||||
mpz_init(bmina);
|
||||
mpz_sub(bmina, *b, *a);
|
||||
|
||||
if (mpz_sgn(bmina) == 0) {
|
||||
mpz_set(*rand, *a);
|
||||
mpz_clear(bmina);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t len_bits = mpz_sizeinbase(bmina, 2);
|
||||
size_t len_bytes = (len_bits + 7) / 8;
|
||||
size_t sizeof_limb = sizeof(mp_limb_t);
|
||||
size_t sizeof_limb_bits = sizeof_limb * 8;
|
||||
size_t len_limbs = (len_bytes + sizeof_limb - 1) / sizeof_limb;
|
||||
|
||||
mp_limb_t mask = ((mp_limb_t)-1) >> (sizeof_limb_bits - len_bits) % sizeof_limb_bits;
|
||||
mp_limb_t r[len_limbs];
|
||||
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
for (size_t i = 0; i < len_limbs; ++i)
|
||||
r[i] = (mp_limb_t)-1;
|
||||
r[len_limbs - 1] = mask;
|
||||
mpz_t check;
|
||||
mpz_roinit_n(check, r, len_limbs);
|
||||
assert(mpz_cmp(check, bmina) >= 0); // max sampled value >= b - a
|
||||
mpz_t bmina2;
|
||||
mpz_init(bmina2);
|
||||
mpz_add(bmina2, bmina, bmina);
|
||||
assert(mpz_cmp(check, bmina2) < 0); // max sampled value < 2 * (b - a)
|
||||
mpz_clear(bmina2);
|
||||
}
|
||||
#endif
|
||||
|
||||
do {
|
||||
randret = randombytes((unsigned char *)r, len_bytes);
|
||||
if (randret != 0) {
|
||||
ret = 0;
|
||||
goto err;
|
||||
}
|
||||
#ifdef TARGET_BIG_ENDIAN
|
||||
for (size_t i = 0; i < len_limbs; ++i)
|
||||
r[i] = BSWAP_DIGIT(r[i]);
|
||||
#endif
|
||||
r[len_limbs - 1] &= mask;
|
||||
mpz_roinit_n(tmp, r, len_limbs);
|
||||
if (mpz_cmp(tmp, bmina) <= 0)
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
mpz_add(*rand, tmp, *a);
|
||||
err:
|
||||
mpz_clear(bmina);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_rand_interval_i(ibz_t *rand, int32_t a, int32_t b)
|
||||
{
|
||||
uint32_t diff, mask;
|
||||
int32_t rand32;
|
||||
|
||||
if (!(a >= 0 && b >= 0 && b > a)) {
|
||||
printf("a = %d b = %d\n", a, b);
|
||||
}
|
||||
assert(a >= 0 && b >= 0 && b > a);
|
||||
|
||||
diff = b - a;
|
||||
|
||||
// Create a mask with 1 + ceil(log2(diff)) least significant bits set
|
||||
#if (defined(__GNUC__) || defined(__clang__)) && INT_MAX == INT32_MAX
|
||||
mask = (1 << (32 - __builtin_clz((uint32_t)diff))) - 1;
|
||||
#else
|
||||
uint32_t diff2 = diff, tmp;
|
||||
|
||||
mask = (diff2 > 0xFFFF) << 4;
|
||||
diff2 >>= mask;
|
||||
|
||||
tmp = (diff2 > 0xFF) << 3;
|
||||
diff2 >>= tmp;
|
||||
mask |= tmp;
|
||||
|
||||
tmp = (diff2 > 0xF) << 2;
|
||||
diff2 >>= tmp;
|
||||
mask |= tmp;
|
||||
|
||||
tmp = (diff2 > 0x3) << 1;
|
||||
diff2 >>= tmp;
|
||||
mask |= tmp;
|
||||
|
||||
mask |= diff2 >> 1;
|
||||
|
||||
mask = (1 << (mask + 1)) - 1;
|
||||
#endif
|
||||
|
||||
assert(mask >= diff && mask < 2 * diff);
|
||||
|
||||
// Rejection sampling
|
||||
do {
|
||||
randombytes((unsigned char *)&rand32, sizeof(rand32));
|
||||
|
||||
#ifdef TARGET_BIG_ENDIAN
|
||||
rand32 = BSWAP32(rand32);
|
||||
#endif
|
||||
|
||||
rand32 &= mask;
|
||||
} while (rand32 > (int32_t)diff);
|
||||
|
||||
rand32 += a;
|
||||
ibz_set(rand, rand32);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_rand_interval_minm_m(ibz_t *rand, int32_t m)
|
||||
{
|
||||
int ret = 1;
|
||||
mpz_t m_big;
|
||||
|
||||
// m_big = 2 * m
|
||||
mpz_init_set_si(m_big, m);
|
||||
mpz_add(m_big, m_big, m_big);
|
||||
|
||||
// Sample in [0, 2*m]
|
||||
ret = ibz_rand_interval(rand, &ibz_const_zero, &m_big);
|
||||
|
||||
// Adjust to range [-m, m]
|
||||
mpz_sub_ui(*rand, *rand, m);
|
||||
|
||||
mpz_clear(m_big);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_rand_interval_bits(ibz_t *rand, uint32_t m)
|
||||
{
|
||||
int ret = 1;
|
||||
mpz_t tmp;
|
||||
mpz_t low;
|
||||
mpz_init_set_ui(tmp, 1);
|
||||
mpz_mul_2exp(tmp, tmp, m);
|
||||
mpz_init(low);
|
||||
mpz_neg(low, tmp);
|
||||
ret = ibz_rand_interval(rand, &low, &tmp);
|
||||
mpz_clear(tmp);
|
||||
mpz_clear(low);
|
||||
if (ret != 1)
|
||||
goto err;
|
||||
mpz_sub_ui(*rand, *rand, (unsigned long int)m);
|
||||
return ret;
|
||||
err:
|
||||
mpz_clear(tmp);
|
||||
mpz_clear(low);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_bitsize(const ibz_t *a)
|
||||
{
|
||||
return (int)mpz_sizeinbase(*a, 2);
|
||||
}
|
||||
|
||||
int
|
||||
ibz_size_in_base(const ibz_t *a, int base)
|
||||
{
|
||||
return (int)mpz_sizeinbase(*a, base);
|
||||
}
|
||||
|
||||
void
|
||||
ibz_copy_digits(ibz_t *target, const digit_t *dig, int dig_len)
|
||||
{
|
||||
mpz_import(*target, dig_len, -1, sizeof(digit_t), 0, 0, dig);
|
||||
}
|
||||
|
||||
void
|
||||
ibz_to_digits(digit_t *target, const ibz_t *ibz)
|
||||
{
|
||||
// From the GMP documentation:
|
||||
// "If op is zero then the count returned will be zero and nothing written to rop."
|
||||
// The next line ensures zero is written to the first limb of target if ibz is zero;
|
||||
// target is then overwritten by the actual value if it is not.
|
||||
target[0] = 0;
|
||||
mpz_export(target, NULL, -1, sizeof(digit_t), 0, 0, *ibz);
|
||||
}
|
||||
|
||||
int
|
||||
ibz_probab_prime(const ibz_t *n, int reps)
|
||||
{
|
||||
int ret = mpz_probab_prime_p(*n, reps);
|
||||
DEBUG_STR_FUN_INT_MP_INT("ibz_probab_prime", ret, n, reps);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
ibz_gcd(ibz_t *gcd, const ibz_t *a, const ibz_t *b)
|
||||
{
|
||||
mpz_gcd(*gcd, *a, *b);
|
||||
}
|
||||
|
||||
int
|
||||
ibz_invmod(ibz_t *inv, const ibz_t *a, const ibz_t *mod)
|
||||
{
|
||||
return (mpz_invert(*inv, *a, *mod) ? 1 : 0);
|
||||
}
|
||||
|
||||
int
|
||||
ibz_legendre(const ibz_t *a, const ibz_t *p)
|
||||
{
|
||||
return mpz_legendre(*a, *p);
|
||||
}
|
||||
|
||||
int
|
||||
ibz_sqrt(ibz_t *sqrt, const ibz_t *a)
|
||||
{
|
||||
if (mpz_perfect_square_p(*a)) {
|
||||
mpz_sqrt(*sqrt, *a);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ibz_sqrt_floor(ibz_t *sqrt, const ibz_t *a)
|
||||
{
|
||||
mpz_sqrt(*sqrt, *a);
|
||||
}
|
||||
|
||||
int
|
||||
ibz_sqrt_mod_p(ibz_t *sqrt, const ibz_t *a, const ibz_t *p)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
assert(ibz_probab_prime(p, 100));
|
||||
#endif
|
||||
// Case a = 0
|
||||
{
|
||||
ibz_t test;
|
||||
ibz_init(&test);
|
||||
ibz_mod(&test, a, p);
|
||||
if (ibz_is_zero(&test)) {
|
||||
ibz_set(sqrt, 0);
|
||||
}
|
||||
ibz_finalize(&test);
|
||||
}
|
||||
#ifdef DEBUG_VERBOSE
|
||||
ibz_t a_cp, p_cp;
|
||||
ibz_init(&a_cp);
|
||||
ibz_init(&p_cp);
|
||||
ibz_copy(&a_cp, a);
|
||||
ibz_copy(&p_cp, p);
|
||||
#endif
|
||||
|
||||
mpz_t amod, tmp, exp, a4, a2, q, z, qnr, x, y, b, pm1;
|
||||
mpz_init(amod);
|
||||
mpz_init(tmp);
|
||||
mpz_init(exp);
|
||||
mpz_init(a4);
|
||||
mpz_init(a2);
|
||||
mpz_init(q);
|
||||
mpz_init(z);
|
||||
mpz_init(qnr);
|
||||
mpz_init(x);
|
||||
mpz_init(y);
|
||||
mpz_init(b);
|
||||
mpz_init(pm1);
|
||||
|
||||
int ret = 1;
|
||||
|
||||
mpz_mod(amod, *a, *p);
|
||||
if (mpz_cmp_ui(amod, 0) < 0) {
|
||||
mpz_add(amod, *p, amod);
|
||||
}
|
||||
|
||||
if (mpz_legendre(amod, *p) != 1) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
mpz_sub_ui(pm1, *p, 1);
|
||||
|
||||
if (mpz_mod_ui(tmp, *p, 4) == 3) {
|
||||
// p % 4 == 3
|
||||
mpz_add_ui(tmp, *p, 1);
|
||||
mpz_fdiv_q_2exp(tmp, tmp, 2);
|
||||
mpz_powm(*sqrt, amod, tmp, *p);
|
||||
} else if (mpz_mod_ui(tmp, *p, 8) == 5) {
|
||||
// p % 8 == 5
|
||||
mpz_sub_ui(tmp, *p, 1);
|
||||
mpz_fdiv_q_2exp(tmp, tmp, 2);
|
||||
mpz_powm(tmp, amod, tmp, *p); // a^{(p-1)/4} mod p
|
||||
if (!mpz_cmp_ui(tmp, 1)) {
|
||||
mpz_add_ui(tmp, *p, 3);
|
||||
mpz_fdiv_q_2exp(tmp, tmp, 3);
|
||||
mpz_powm(*sqrt, amod, tmp, *p); // a^{(p+3)/8} mod p
|
||||
} else {
|
||||
mpz_sub_ui(tmp, *p, 5);
|
||||
mpz_fdiv_q_2exp(tmp, tmp, 3); // (p - 5) / 8
|
||||
mpz_mul_2exp(a4, amod, 2); // 4*a
|
||||
mpz_powm(tmp, a4, tmp, *p);
|
||||
|
||||
mpz_mul_2exp(a2, amod, 1);
|
||||
mpz_mul(tmp, a2, tmp);
|
||||
mpz_mod(*sqrt, tmp, *p);
|
||||
}
|
||||
} else {
|
||||
// p % 8 == 1 -> Shanks-Tonelli
|
||||
int e = 0;
|
||||
mpz_sub_ui(q, *p, 1);
|
||||
while (mpz_tstbit(q, e) == 0)
|
||||
e++;
|
||||
mpz_fdiv_q_2exp(q, q, e);
|
||||
|
||||
// 1. find generator - non-quadratic residue
|
||||
mpz_set_ui(qnr, 2);
|
||||
while (mpz_legendre(qnr, *p) != -1)
|
||||
mpz_add_ui(qnr, qnr, 1);
|
||||
mpz_powm(z, qnr, q, *p);
|
||||
|
||||
// 2. Initialize
|
||||
mpz_set(y, z);
|
||||
mpz_powm(y, amod, q, *p); // y = a^q mod p
|
||||
|
||||
mpz_add_ui(tmp, q, 1); // tmp = (q + 1) / 2
|
||||
mpz_fdiv_q_2exp(tmp, tmp, 1);
|
||||
|
||||
mpz_powm(x, amod, tmp, *p); // x = a^(q + 1)/2 mod p
|
||||
|
||||
mpz_set_ui(exp, 1);
|
||||
mpz_mul_2exp(exp, exp, e - 2);
|
||||
|
||||
for (int i = 0; i < e; ++i) {
|
||||
mpz_powm(b, y, exp, *p);
|
||||
|
||||
if (!mpz_cmp(b, pm1)) {
|
||||
mpz_mul(x, x, z);
|
||||
mpz_mod(x, x, *p);
|
||||
|
||||
mpz_mul(y, y, z);
|
||||
mpz_mul(y, y, z);
|
||||
mpz_mod(y, y, *p);
|
||||
}
|
||||
|
||||
mpz_powm_ui(z, z, 2, *p);
|
||||
mpz_fdiv_q_2exp(exp, exp, 1);
|
||||
}
|
||||
|
||||
mpz_set(*sqrt, x);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
DEBUG_STR_FUN_3("ibz_sqrt_mod_p", sqrt, &a_cp, &p_cp);
|
||||
ibz_finalize(&a_cp);
|
||||
ibz_finalize(&p_cp);
|
||||
#endif
|
||||
|
||||
end:
|
||||
mpz_clear(amod);
|
||||
mpz_clear(tmp);
|
||||
mpz_clear(exp);
|
||||
mpz_clear(a4);
|
||||
mpz_clear(a2);
|
||||
mpz_clear(q);
|
||||
mpz_clear(z);
|
||||
mpz_clear(qnr);
|
||||
mpz_clear(x);
|
||||
mpz_clear(y);
|
||||
mpz_clear(b);
|
||||
mpz_clear(pm1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,319 +1,116 @@
|
||||
#include <quaternion.h>
|
||||
#include "internal.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
//Small helper for integers
|
||||
void ibz_rounded_div(ibz_t *q, const ibz_t *a, const ibz_t *b){
|
||||
ibz_t r,sign_q, abs_b;
|
||||
ibz_init(&r);
|
||||
ibz_init(&sign_q);
|
||||
ibz_init(&abs_b);
|
||||
// Random prime generation for tests
|
||||
int
|
||||
ibz_generate_random_prime(ibz_t *p, int is3mod4, int bitsize, int probability_test_iterations)
|
||||
{
|
||||
assert(bitsize != 0);
|
||||
int found = 0;
|
||||
ibz_t two_pow, two_powp;
|
||||
|
||||
//assumed to round towards 0
|
||||
ibz_abs(&abs_b,b);
|
||||
// q is of same sign as a*b (and 0 if a is 0)
|
||||
ibz_mul(&sign_q,a,b);
|
||||
ibz_div(q,&r,a,b);
|
||||
ibz_abs(&r,&r);
|
||||
ibz_add(&r,&r,&r);
|
||||
if(ibz_cmp(&r,&abs_b)>0){
|
||||
ibz_set(&r,0);
|
||||
if(ibz_cmp(&sign_q,&r)<0){
|
||||
ibz_set(&sign_q,-1);
|
||||
} else {
|
||||
ibz_set(&sign_q,1);
|
||||
ibz_init(&two_pow);
|
||||
ibz_init(&two_powp);
|
||||
ibz_pow(&two_pow, &ibz_const_two, (bitsize - 1) - (0 != is3mod4));
|
||||
ibz_pow(&two_powp, &ibz_const_two, bitsize - (0 != is3mod4));
|
||||
|
||||
int cnt = 0;
|
||||
while (!found) {
|
||||
cnt++;
|
||||
if (cnt % 100000 == 0) {
|
||||
printf("Random prime generation is still running after %d attempts, this is not "
|
||||
"normal! The expected number of attempts is %d \n",
|
||||
cnt,
|
||||
bitsize);
|
||||
}
|
||||
ibz_add(q,q,&sign_q);
|
||||
}
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&sign_q);
|
||||
ibz_finalize(&abs_b);
|
||||
ibz_rand_interval(p, &two_pow, &two_powp);
|
||||
ibz_add(p, p, p);
|
||||
if (is3mod4) {
|
||||
ibz_add(p, p, p);
|
||||
ibz_add(p, &ibz_const_two, p);
|
||||
}
|
||||
ibz_add(p, &ibz_const_one, p);
|
||||
|
||||
found = ibz_probab_prime(p, probability_test_iterations);
|
||||
}
|
||||
ibz_finalize(&two_pow);
|
||||
ibz_finalize(&two_powp);
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
// this function assumes that there is a sqrt of -1 mod p and p is prime
|
||||
//algorithm read at http://www.lix.polytechnique.fr/Labo/Francois.Morain/Articles/cornac.pdf, on 2nd of may 2023, 14h45 CEST
|
||||
int ibz_cornacchia_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p){
|
||||
int res = 1;
|
||||
ibz_t two, r0, r1, r2, a, x0, prod;
|
||||
// solves x^2 + n y^2 == p for positive integers x, y
|
||||
// assumes that p is prime and -n mod p is a square
|
||||
int
|
||||
ibz_cornacchia_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p)
|
||||
{
|
||||
ibz_t r0, r1, r2, a, prod;
|
||||
ibz_init(&r0);
|
||||
ibz_init(&r1);
|
||||
ibz_init(&r2);
|
||||
ibz_init(&a);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&two);
|
||||
|
||||
int res = 0;
|
||||
|
||||
// manage case p = 2 separately
|
||||
ibz_set(&two,2);
|
||||
int test = ibz_cmp(p,&two);
|
||||
if(test==0){
|
||||
if (ibz_is_one(n)){
|
||||
ibz_set(x,1);
|
||||
ibz_set(y,1);
|
||||
if (!ibz_cmp(p, &ibz_const_two)) {
|
||||
if (ibz_is_one(n)) {
|
||||
ibz_set(x, 1);
|
||||
ibz_set(y, 1);
|
||||
res = 1;
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
// manage case p = n separately
|
||||
if (!ibz_cmp(p, n)) {
|
||||
ibz_set(x, 0);
|
||||
ibz_set(y, 1);
|
||||
res = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
//test coprimality (should always be ok in our cases)
|
||||
ibz_gcd(&r2,p,n);
|
||||
if (ibz_is_one(&r2) && (test != 0)){
|
||||
|
||||
// get sqrt of -n mod p
|
||||
ibz_set(&r2,0);
|
||||
ibz_sub(&r2,&r2,n);
|
||||
res = res && ibz_sqrt_mod_p(&r2,&r2,p);
|
||||
if (res){
|
||||
// run loop
|
||||
ibz_copy(&prod,p);
|
||||
ibz_copy(&r1,p);
|
||||
while(ibz_cmp(&prod,p)>=0){
|
||||
ibz_div(&a,&r0,&r2,&r1);
|
||||
ibz_mul(&prod,&r0,&r0);
|
||||
ibz_copy(&r2,&r1);
|
||||
ibz_copy(&r1,&r0);
|
||||
}
|
||||
// test if result is solution
|
||||
ibz_sub(&a,p,&prod);
|
||||
ibz_div(&a,&r2,&a,n);
|
||||
res = res && (ibz_is_zero(&r2));
|
||||
res = res && ibz_sqrt(y,&a);
|
||||
if (res){
|
||||
ibz_copy(x,&r0);
|
||||
ibz_mul(&a,y,y);
|
||||
ibz_mul(&a,&a,n);
|
||||
ibz_add(&prod,&prod,&a);
|
||||
res = res && (0==ibz_cmp(&prod,p));
|
||||
}
|
||||
}
|
||||
// test coprimality (should always be ok in our cases)
|
||||
ibz_gcd(&r2, p, n);
|
||||
if (!ibz_is_one(&r2))
|
||||
goto done;
|
||||
|
||||
// get sqrt of -n mod p
|
||||
ibz_neg(&r2, n);
|
||||
if (!ibz_sqrt_mod_p(&r2, &r2, p))
|
||||
goto done;
|
||||
|
||||
// run loop
|
||||
ibz_copy(&prod, p);
|
||||
ibz_copy(&r1, p);
|
||||
ibz_copy(&r0, p);
|
||||
while (ibz_cmp(&prod, p) >= 0) {
|
||||
ibz_div(&a, &r0, &r2, &r1);
|
||||
ibz_mul(&prod, &r0, &r0);
|
||||
ibz_copy(&r2, &r1);
|
||||
ibz_copy(&r1, &r0);
|
||||
}
|
||||
// test if result is solution
|
||||
ibz_sub(&a, p, &prod);
|
||||
ibz_div(&a, &r2, &a, n);
|
||||
if (!ibz_is_zero(&r2))
|
||||
goto done;
|
||||
if (!ibz_sqrt(y, &a))
|
||||
goto done;
|
||||
|
||||
ibz_copy(x, &r0);
|
||||
ibz_mul(&a, y, y);
|
||||
ibz_mul(&a, &a, n);
|
||||
ibz_add(&prod, &prod, &a);
|
||||
res = !ibz_cmp(&prod, p);
|
||||
|
||||
done:
|
||||
ibz_finalize(&r0);
|
||||
ibz_finalize(&r1);
|
||||
ibz_finalize(&r2);
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&two);
|
||||
return(res);
|
||||
}
|
||||
|
||||
int ibz_cornacchia_special_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p, const int exp_adjust){
|
||||
int res = 1;
|
||||
ibz_t two, r0, r1, r2, a, x0, prod;
|
||||
ibz_t p4;
|
||||
ibz_t test_square;
|
||||
ibz_init(&test_square);
|
||||
ibz_init(&r0);
|
||||
ibz_init(&r1);
|
||||
ibz_init(&r2);
|
||||
ibz_init(&a);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&two);
|
||||
ibz_init(&p4);
|
||||
ibz_set(&two,2);
|
||||
ibz_pow(&p4,&two,exp_adjust);
|
||||
ibz_mul(&p4,p,&p4);
|
||||
|
||||
assert(exp_adjust>0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
ibz_set(&r0,3);
|
||||
ibz_set(&r1,4);
|
||||
ibz_mod(&r2,n,&r1);
|
||||
assert((ibz_cmp(&r2,&r0)==0));
|
||||
ibz_set(&r0,0);
|
||||
ibz_set(&r1,0);
|
||||
ibz_set(&r2,0);
|
||||
#endif
|
||||
|
||||
// manage case p = 2 separately
|
||||
int test = ibz_cmp(p,&two);
|
||||
if(test==0){
|
||||
if (ibz_is_one(n)){
|
||||
ibz_set(x,1);
|
||||
ibz_set(y,1);
|
||||
res = 1;
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//test coprimality (should always be ok in our cases)
|
||||
ibz_gcd(&r2,p,n);
|
||||
if (ibz_is_one(&r2) && (test != 0)){
|
||||
|
||||
// get sqrt of -n mod p
|
||||
ibz_set(&r2,0);
|
||||
ibz_sub(&r2,&r2,n);
|
||||
res = res && ibz_sqrt_mod_p(&r2,&r2,p);
|
||||
res = res && (ibz_get(&r2)%2 != 0);
|
||||
|
||||
|
||||
ibz_mul(&test_square,&r2,&r2);
|
||||
ibz_add(&test_square,&test_square,n);
|
||||
ibz_mod(&test_square,&test_square,&p4);
|
||||
res = res && ibz_is_zero(&test_square);
|
||||
if (res){
|
||||
// run loop
|
||||
ibz_copy(&prod,&p4);
|
||||
ibz_copy(&r1,&p4);
|
||||
while(ibz_cmp(&prod,&p4)>=0){
|
||||
ibz_div(&a,&r0,&r2,&r1);
|
||||
ibz_mul(&prod,&r0,&r0);
|
||||
ibz_copy(&r2,&r1);
|
||||
ibz_copy(&r1,&r0);
|
||||
}
|
||||
// test if result is solution
|
||||
ibz_sub(&a,&p4,&prod);
|
||||
ibz_div(&a,&r2,&a,n);
|
||||
res = res && ibz_is_zero(&r2);
|
||||
res = res && ibz_sqrt(y,&a);
|
||||
if (res){
|
||||
ibz_copy(x,&r0);
|
||||
ibz_mul(&a,y,y);
|
||||
ibz_mul(&a,&a,n);
|
||||
ibz_add(&prod,&prod,&a);
|
||||
res = res && (0==ibz_cmp(&prod,&p4));
|
||||
}
|
||||
}
|
||||
}
|
||||
ibz_finalize(&r0);
|
||||
ibz_finalize(&r1);
|
||||
ibz_finalize(&r2);
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&two);
|
||||
ibz_finalize(&p4);
|
||||
ibz_finalize(&test_square);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//returns complex product of a and b
|
||||
void ibz_complex_mul(ibz_t *re_res, ibz_t *im_res, const ibz_t *re_a, const ibz_t *im_a, const ibz_t *re_b, const ibz_t *im_b){
|
||||
ibz_t prod, re, im;
|
||||
ibz_init(&prod);
|
||||
ibz_init(&re);
|
||||
ibz_init(&im);
|
||||
ibz_mul(&re, re_a,re_b);
|
||||
ibz_mul(&prod, im_a, im_b);
|
||||
ibz_sub(&re,&re,&prod);
|
||||
ibz_mul(&im, re_a,im_b);
|
||||
ibz_mul(&prod, im_a, re_b);
|
||||
ibz_add(&im,&im,&prod);
|
||||
ibz_copy(im_res,&im);
|
||||
ibz_copy(re_res,&re);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&re);
|
||||
ibz_finalize(&im);
|
||||
}
|
||||
|
||||
//multiplies res by a^e with res and a integer complex numbers
|
||||
void ibz_complex_mul_by_complex_power(ibz_t *re_res, ibz_t *im_res, const ibz_t *re_a, const ibz_t *im_a, int64_t exp){
|
||||
ibz_t re_x,im_x;
|
||||
ibz_init(&re_x);
|
||||
ibz_init(&im_x);
|
||||
ibz_set(&re_x,1);
|
||||
ibz_set(&im_x,0);
|
||||
for (int i = 0; i < 64; i++){
|
||||
ibz_complex_mul(&re_x,&im_x,&re_x,&im_x,&re_x,&im_x);
|
||||
if((exp>>(63-i)) & 1){
|
||||
ibz_complex_mul(&re_x,&im_x,&re_x,&im_x,re_a,im_a);
|
||||
}
|
||||
}
|
||||
ibz_complex_mul(re_res,im_res,re_res,im_res,&re_x,&im_x);
|
||||
ibz_finalize(&re_x);
|
||||
ibz_finalize(&im_x);
|
||||
}
|
||||
|
||||
//multiplies to res the result of the solutions of cornacchia for prime depending on valuation val (prime-adic valuation)
|
||||
int ibz_cornacchia_extended_prime_loop(ibz_t *re_res, ibz_t *im_res, int64_t prime, int64_t val){
|
||||
ibz_t re, im, p, n;
|
||||
ibz_init(&re);
|
||||
ibz_init(&im);
|
||||
ibz_init(&p);
|
||||
ibz_init(&n);
|
||||
ibz_set(&n,1);
|
||||
ibz_set(&p, prime);
|
||||
int res = ibz_cornacchia_prime(&re,&im,&n,&p);
|
||||
if(res){
|
||||
ibz_complex_mul_by_complex_power(re_res, im_res, &re, &im, val);
|
||||
}
|
||||
ibz_finalize(&re);
|
||||
ibz_finalize(&im);
|
||||
ibz_finalize(&p);
|
||||
ibz_finalize(&n);
|
||||
return(res);
|
||||
}
|
||||
|
||||
int ibz_cornacchia_extended(ibz_t *x, ibz_t *y, const ibz_t *n, const short *prime_list, const int prime_list_length, short primality_test_iterations, const ibz_t *bad_primes_prod){
|
||||
int res = 1;
|
||||
ibz_t four, one, nodd, q, r, p;
|
||||
ibz_init(&four);
|
||||
ibz_init(&one);
|
||||
ibz_init(&nodd);
|
||||
ibz_init(&r);
|
||||
ibz_init(&q);
|
||||
ibz_init(&p);
|
||||
int64_t *valuations = malloc(prime_list_length*sizeof(int64_t));
|
||||
ibz_set(&four,4);
|
||||
ibz_set(&one,1);
|
||||
|
||||
// if a prime which is 3 mod 4 divides n, extended Cornacchia can't solve the equation
|
||||
if(bad_primes_prod != NULL){
|
||||
ibz_gcd(&q,n,bad_primes_prod);
|
||||
if(!ibz_is_one(&q)){
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(res){
|
||||
// get the valuations and the unfactored part by attempting division by all given primes
|
||||
ibz_copy(&nodd,n);
|
||||
for (int i = 0; i < prime_list_length; i++){
|
||||
valuations[i] = 0;
|
||||
if (((*(prime_list + i) % 4) == 1) || (i == 0)){
|
||||
ibz_set(&r, 0);
|
||||
ibz_set(&p, *(prime_list + i));
|
||||
ibz_copy(&q,&nodd);
|
||||
while(ibz_is_zero(&r)){
|
||||
valuations[i] +=1;
|
||||
ibz_copy(&nodd,&q);
|
||||
ibz_div(&q,&r,&nodd,&p);
|
||||
}
|
||||
valuations[i] -=1;
|
||||
}
|
||||
}
|
||||
|
||||
// compute the remainder mod 4
|
||||
ibz_mod(&r,&nodd,&four);
|
||||
if (ibz_is_one(&r)){ // we hope the 'unfactored' part is a prime 1 mod 4
|
||||
if (ibz_probab_prime(&nodd, primality_test_iterations) || ibz_is_one(&nodd)){
|
||||
if (ibz_is_one(&nodd)){ // the unfactored part is 1
|
||||
ibz_set(x,1);
|
||||
ibz_set(y,0);
|
||||
} else { // the 'unfactored' part is prime, can use Cornacchia
|
||||
res = res && ibz_cornacchia_prime(x,y,&one, &nodd);
|
||||
}
|
||||
if (res == 1){ // no need to continue if failure here
|
||||
for (int i = 0; i < prime_list_length; i++){
|
||||
if (valuations[i] != 0){
|
||||
res = res && ibz_cornacchia_extended_prime_loop(x, y, prime_list[i], valuations[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
free(valuations);
|
||||
ibz_finalize(&four);
|
||||
ibz_finalize(&one);
|
||||
ibz_finalize(&nodd);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&p);
|
||||
return(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1,740 +0,0 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Sina Schaeffler
|
||||
*
|
||||
* @brief Declarations for helper functions for quaternion algebra implementation
|
||||
*/
|
||||
|
||||
#ifndef QUAT_HELPER_H
|
||||
#define QUAT_HELPER_H
|
||||
|
||||
#include <quaternion.h>
|
||||
|
||||
/** @internal
|
||||
* @ingroup quat_quat
|
||||
* @defgroup quat_helpers Quaternion module internal functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_alg_helpers Helper functions for the alg library
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @brief helper function for initializing small quaternion algebras.
|
||||
*/
|
||||
static inline void quat_alg_init_set_ui(quat_alg_t *alg, unsigned int p) {
|
||||
ibz_t bp;
|
||||
ibz_init(&bp);
|
||||
ibz_set(&bp, p);
|
||||
quat_alg_init_set(alg, &bp);
|
||||
ibz_finalize(&bp);
|
||||
}
|
||||
|
||||
/** @brief a+b
|
||||
*
|
||||
* Add two integer 4-vectors
|
||||
*
|
||||
* @param res Output: Will contain sum
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
void quat_alg_coord_add(quat_alg_coord_t *res, const quat_alg_coord_t *a, const quat_alg_coord_t *b);
|
||||
|
||||
/** @brief a-b
|
||||
*
|
||||
* Substract two integer 4-vectors
|
||||
*
|
||||
* @param res Output: Will contain difference
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
void quat_alg_coord_sub(quat_alg_coord_t *res, const quat_alg_coord_t *a, const quat_alg_coord_t *b);
|
||||
|
||||
/** @brief Compute same denominator form of two quaternion algebra elements
|
||||
*
|
||||
* res_a=a and res_b=b (representing the same element) and res_a.denom = res_b.denom
|
||||
*
|
||||
* @param res_a
|
||||
* @param res_b
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
void quat_alg_equal_denom(quat_alg_elem_t *res_a, quat_alg_elem_t *res_b, const quat_alg_elem_t *a, const quat_alg_elem_t *b);
|
||||
|
||||
/** @brief Copies the given values into an algebra element, without normalizing it
|
||||
*
|
||||
* @param elem Output: algebra element of coordinates [coord0,coord1,coord2,coord3] and denominator denom
|
||||
* @param denom Denominator, must be non zero
|
||||
* @param coord0 Coordinate on 1 (0th vector of standard algebra basis)
|
||||
* @param coord1 Coordinate on i (1st vector of standard algebra basis)
|
||||
* @param coord2 Coordinate on j (2nd vector of standard algebra basis)
|
||||
* @param coord3 Coordinate on ij (3rd vector of standard algebra basis)
|
||||
*/
|
||||
void quat_alg_elem_copy_ibz(quat_alg_elem_t *elem, const ibz_t *denom, const ibz_t *coord0, const ibz_t *coord1, const ibz_t *coord2, const ibz_t *coord3);
|
||||
|
||||
/** @brief Sets an algebra element to the given integer values, without normalizing it
|
||||
*
|
||||
* @param elem Output: algebra element of coordinates [coord0,coord1,coord2,coord3] and denominator denom
|
||||
* @param denom Denominator, must be non zero
|
||||
* @param coord0 Coordinate on 1 (0th vector of standard algebra basis)
|
||||
* @param coord1 Coordinate on i (1st vector of standard algebra basis)
|
||||
* @param coord2 Coordinate on j (2nd vector of standard algebra basis)
|
||||
* @param coord3 Coordinate on ij (3rd vector of standard algebra basis)
|
||||
*/
|
||||
void quat_alg_elem_set(quat_alg_elem_t *elem, int64_t denom, int64_t coord0, int64_t coord1, int64_t coord2, int64_t coord3);
|
||||
|
||||
/** @brief Multiplies algebra element by integer scalar, without normalizing it
|
||||
*
|
||||
* @param res Output
|
||||
* @param scalar Integer
|
||||
* @param elem Algebra element
|
||||
*/
|
||||
void quat_alg_elem_mul_by_scalar(quat_alg_elem_t *res, const ibz_t *scalar, const quat_alg_elem_t *elem);
|
||||
|
||||
/** @brief Compute the right multiplication table of a quaternion (without denominator)
|
||||
*
|
||||
* @param mulmat Output
|
||||
* @param a Quaternion
|
||||
* @param alg The algebra
|
||||
*/
|
||||
void quat_alg_rightmul_mat(ibz_mat_4x4_t *mulmat, const quat_alg_elem_t *a, const quat_alg_t *alg);
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_int_helpers Helper functions for integer functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_int_small_helpers Small integer functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief round a/b to closest integer q
|
||||
*/
|
||||
void ibz_rounded_div(ibz_t *q, const ibz_t *a, const ibz_t *b);
|
||||
|
||||
/** @brief Compare ibz_t with long
|
||||
*/
|
||||
static int ibz_cmp_si(ibz_t *x, int64_t y) {
|
||||
ibz_t Y;
|
||||
ibz_init(&Y);
|
||||
ibz_set(&Y, y);
|
||||
int res = ibz_cmp(x, &Y);
|
||||
ibz_finalize(&Y);
|
||||
return res;
|
||||
}
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_cornacchia_helpers Helper functions for the cornacchia function
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Complex product of a and b
|
||||
*
|
||||
* re_res + i*im_res = (re_a+i*im_a)*(re_b+i*im_b) where i a usual complex 4th root of unity
|
||||
*
|
||||
* @param re_res Output: real part of the result
|
||||
* @param im_res Output: imaginary part of the result
|
||||
* @param re_a Real part of a
|
||||
* @param im_a Imaginary part of a
|
||||
* @param re_b Real part of b
|
||||
* @param im_b Imaginary part of b
|
||||
*/
|
||||
void ibz_complex_mul(ibz_t *re_res, ibz_t *im_res, const ibz_t *re_a, const ibz_t *im_a, const ibz_t *re_b, const ibz_t *im_b);
|
||||
|
||||
/** @brief Multiplies res by a^e with res and a integer complex numbers
|
||||
*
|
||||
* re_res + i*im_res = (re_res+i*im_res)*((re_a+i*im_a)^exp) where i a usual complex 4th root of unity
|
||||
*
|
||||
* @param re_res Output: real part of the result. Also used as input.
|
||||
* @param im_res Output: imaginary part of the result. Also used as input.
|
||||
* @param re_a Real part of a
|
||||
* @param im_a Imaginary part of a
|
||||
* @param exp res*(a^exp) will be computed, exp should be a positive integer or 0
|
||||
*/
|
||||
void ibz_complex_mul_by_complex_power(ibz_t *re_res, ibz_t *im_res, const ibz_t *re_a, const ibz_t *im_a, int64_t exp);
|
||||
|
||||
/** @brief Multiplies to res the result of the solutions of cornacchia for prime depending on valuation val (prime-adic valuation)
|
||||
*
|
||||
* re_res + i*im_res = (re_res+i*im_res)*((x+i*y)^val) where i a usual complex 4th root of unity, and x,y an integer sulotion to x^2 + y^2 = prime
|
||||
*
|
||||
* @param re_res Output: real part of the result. Also used as input.
|
||||
* @param im_res Output: imaginary part of the result. Also used as input.
|
||||
* @param prime a prime factor of n on which extended Cornacchia was called
|
||||
* @param val prime-adic valuation of the n on which extended Cornacchia was called
|
||||
* @returns 1 if an integer solution x,y to x^2 + y^2 = prime was found by Cornacchia_prime, 0 otherwise
|
||||
*/
|
||||
int ibz_cornacchia_extended_prime_loop(ibz_t *re_res, ibz_t *im_res, int64_t prime, int64_t val);
|
||||
/** @}
|
||||
*/
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_dim4_helpers Helper functions for functions for matrices or vectors in dimension 4
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_inv_helpers Helper functions for the integer matrix inversion function
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief a1a2+b1b2+c1c2
|
||||
*
|
||||
* @param coeff Output: The coefficien which was computed as a1a2+b1b2-c1c2
|
||||
* @param a1
|
||||
* @param a2
|
||||
* @param b1
|
||||
* @param b2
|
||||
* @param c1
|
||||
* @param c2
|
||||
*/
|
||||
void ibz_inv_dim4_make_coeff_pmp(ibz_t *coeff, const ibz_t *a1, const ibz_t *a2, const ibz_t *b1, const ibz_t *b2, const ibz_t *c1, const ibz_t *c2);
|
||||
|
||||
/** @brief -a1a2+b1b2-c1c2
|
||||
*
|
||||
* @param coeff Output: The coefficien which was computed as -a1a2+b1b2-c1c2
|
||||
* @param a1
|
||||
* @param a2
|
||||
* @param b1
|
||||
* @param b2
|
||||
* @param c1
|
||||
* @param c2
|
||||
*/
|
||||
void ibz_inv_dim4_make_coeff_mpm(ibz_t *coeff, const ibz_t *a1, const ibz_t *a2, const ibz_t *b1, const ibz_t *b2, const ibz_t *c1, const ibz_t *c2);
|
||||
|
||||
/** @brief Matrix determinant and a matrix inv such that inv/det is the inverse matrix of the input
|
||||
*
|
||||
* Implemented following the methof of 2x2 minors explained at Method from https://www.geometrictools.com/Documentation/LaplaceExpansionTheorem.pdf (visited on 3rd of May 2023, 16h15 CEST)
|
||||
*
|
||||
* @returns 1 if the determinant of mat is not 0 and an inverse was computed, 0 otherwise
|
||||
* @param inv Output: Will contain an integer matrix which, dividet by det, will yield the rational inverse of the matrix if it exists, can be NULL
|
||||
* @param det Output: Will contain the determinant of the input matrix, can be NULL
|
||||
* @param mat Matrix of which the inverse will be computed
|
||||
*/
|
||||
int ibz_mat_4x4_inv_with_det_as_denom(ibz_mat_4x4_t *inv, ibz_t *det, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief a*b for a,b integer 4x4 matrices
|
||||
*
|
||||
* Naive implementation
|
||||
*
|
||||
* @param res Output: A 4x4 integer matrix
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
void ibz_mat_4x4_mul(ibz_mat_4x4_t *res, const ibz_mat_4x4_t *a, const ibz_mat_4x4_t *b);
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_lll_verify_helpers Helper functions for lll verification in dimension 4
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Set an ibq vector to 4 given integer coefficients
|
||||
*/
|
||||
void ibq_vec_4_copy_ibz(ibq_t (*vec)[4], const ibz_t *coeff0, const ibz_t *coeff1,const ibz_t *coeff2,const ibz_t *coeff3);
|
||||
|
||||
/** @brief Bilinear form vec00*vec10+vec01*vec11+q*vec02*vec12+q*vec03*vec13 for ibz_q
|
||||
*/
|
||||
void quat_dim4_lll_bilinear(ibq_t *b, const ibq_t (*vec0)[4], const ibq_t (*vec1)[4], const ibz_t *q);
|
||||
|
||||
/** @brief Outputs the transposition of the orthogonalised matrix of mat (as fractions)
|
||||
*
|
||||
* For the bilinear form vec00*vec10+vec01*vec11+q*vec02*vec12+q*vec03*vec13
|
||||
*/
|
||||
void quat_dim4_gram_schmidt_transposed_with_ibq(ibq_t (*orthogonalised_transposed)[4][4], const ibz_mat_4x4_t *mat, const ibz_t *q);
|
||||
|
||||
/** @brief Verifies if mat is lll-reduced for parameter coeff and norm defined by q
|
||||
*
|
||||
* For the bilinear form vec00*vec10+vec01*vec11+q*vec02*vec12+q*vec03*vec13
|
||||
*/
|
||||
int quat_dim4_lll_verify(const ibz_mat_4x4_t *mat, const ibq_t *coeff, const ibz_t *q);
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_dim4_lat_helpers Helper functions on vectors and matrices used mainly for lattices
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Set a vector of 4 integers to given values
|
||||
*
|
||||
* @param vec Output: is set to given coordinates
|
||||
* @param coord0
|
||||
* @param coord1
|
||||
* @param coord2
|
||||
* @param coord3
|
||||
*/
|
||||
void ibz_vec_4_set(ibz_vec_4_t *vec, int64_t coord0, int64_t coord1, int64_t coord2, int64_t coord3);
|
||||
|
||||
/** @brief Copy all values from one vector to another
|
||||
*
|
||||
* @param new Output: is set to same values as vec
|
||||
* @param vec
|
||||
*/
|
||||
void ibz_vec_4_copy(ibz_vec_4_t *new, const ibz_vec_4_t *vec);
|
||||
|
||||
/** @brief Compute the linear combination lc = coeff_a vec_a + coeff_b vec_b
|
||||
*
|
||||
* @param lc Output: linear combination lc = coeff_a vec_a + coeff_b vec_b
|
||||
* @param coeff_a Scalar multiplied to vec_a
|
||||
* @param vec_a
|
||||
* @param coeff_b Scalar multiplied to vec_b
|
||||
* @param vec_b
|
||||
*/
|
||||
void ibz_vec_4_linear_combination(ibz_vec_4_t *lc, const ibz_t *coeff_a, const ibz_vec_4_t *vec_a, const ibz_t *coeff_b, const ibz_vec_4_t *vec_b);
|
||||
|
||||
/** @brief divides all values in vector by same scalar
|
||||
*
|
||||
* @returns 1 if scalar divided all values in mat, 0 otherwise (division is performed in both cases)
|
||||
* @param quot Output
|
||||
* @param scalar
|
||||
* @param vec
|
||||
*/
|
||||
int ibz_vec_4_scalar_div(ibz_vec_4_t *quot, const ibz_t *scalar, const ibz_vec_4_t *vec);
|
||||
|
||||
/** @brief Negation for vectors of 4 integers
|
||||
*
|
||||
* @param neg Output: is set to -vec
|
||||
* @param vec
|
||||
*/
|
||||
void ibz_vec_4_negate(ibz_vec_4_t *neg, const ibz_vec_4_t *vec);
|
||||
|
||||
/** @brief Copies all values from a 4x4 integer matrix to another one
|
||||
*
|
||||
* @param new Output: matrix which will have its entries set to mat's entries
|
||||
* @param mat Input matrix
|
||||
*/
|
||||
void ibz_mat_4x4_copy(ibz_mat_4x4_t *new, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief -mat for mat a 4x4 integer matrix
|
||||
*
|
||||
* @param neg Output: is set to -mat
|
||||
* @param mat Input matrix
|
||||
*/
|
||||
void ibz_mat_4x4_negate(ibz_mat_4x4_t *neg, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief transpose a 4x4 integer matrix
|
||||
*
|
||||
* @param transposed Output: is set to the transposition of mat
|
||||
* @param mat Input matrix
|
||||
*/
|
||||
void ibz_mat_4x4_transpose(ibz_mat_4x4_t *transposed, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief Set all coefficients of a matrix to zero for 4x4 integer matrices
|
||||
*
|
||||
* @param zero
|
||||
*/
|
||||
void ibz_mat_4x4_zero(ibz_mat_4x4_t *zero);
|
||||
|
||||
/** @brief Set a matrix to the identity for 4x4 integer matrices
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
void ibz_mat_4x4_identity(ibz_mat_4x4_t *id);
|
||||
|
||||
/** @brief Test equality to identity for 4x4 integer matrices
|
||||
*
|
||||
* @returns 1 if mat is the identity matrix, 0 otherwise
|
||||
* @param mat
|
||||
*/
|
||||
int ibz_mat_4x4_is_identity(const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief Equality test for 4x4 integer matrices
|
||||
*
|
||||
* @returns 1 if equal, 0 otherwise
|
||||
* @param mat1
|
||||
* @param mat2
|
||||
*/
|
||||
int ibz_mat_4x4_equal(const ibz_mat_4x4_t *mat1, const ibz_mat_4x4_t *mat2);
|
||||
|
||||
/** @brief Matrix by integer multiplication
|
||||
*
|
||||
* @param prod Output
|
||||
* @param scalar
|
||||
* @param mat
|
||||
*/
|
||||
void ibz_mat_4x4_scalar_mul(ibz_mat_4x4_t *prod, const ibz_t *scalar, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief gcd of all values in matrix
|
||||
*
|
||||
* @param gcd Output
|
||||
* @param mat
|
||||
*/
|
||||
void ibz_mat_4x4_gcd(ibz_t *gcd, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief divides all values in matrix by same scalar
|
||||
*
|
||||
* @returns 1 if scalar divided all values in mat, 0 otherwise (division is performed in both cases)
|
||||
* @param quot Output
|
||||
* @param scalar
|
||||
* @param mat
|
||||
*/
|
||||
int ibz_mat_4x4_scalar_div(ibz_mat_4x4_t *quot, const ibz_t *scalar, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief Modular matrix multiplication of aribitrarily sized matrices
|
||||
*
|
||||
* res = A * B (mod)
|
||||
*
|
||||
* @param from
|
||||
* @param through
|
||||
* @param to
|
||||
* @param res Output: a from × to matrix. Cannot point to the same memory as A or B.
|
||||
* @param A a from × through matrix
|
||||
* @param B a through × to matrix
|
||||
* @param mod modulo
|
||||
*/
|
||||
void ibz_mat_mulmod(int from, int through, int to, ibz_t res[from][to], const ibz_t A[from][through], const ibz_t B[through][to], const ibz_t *mod);
|
||||
|
||||
/** @brief Compute the Howell form of a matrix modulo an integer
|
||||
*
|
||||
* Source: https://link.springer.com/chapter/10.1007/3-540-68530-8_12
|
||||
* Adapted from PARI/GP
|
||||
*
|
||||
* @param rows The number of rows of the input
|
||||
* @param cols The number of columns of the input, must be <= rows
|
||||
* @param howell Output: the Howell form H of mat
|
||||
* @param trans Output: the transformation matrix U s.t. mat·U = H. May be NULL.
|
||||
* @param mat The matrix
|
||||
* @param mod The integer modulus
|
||||
* @return the number of zero-columns to the lef of `howell`.
|
||||
*/
|
||||
int ibz_mat_howell(int rows, int cols, ibz_t howell[rows][rows+1], ibz_t trans[rows+1][rows+1], const ibz_t mat[rows][cols], ibz_t *mod);
|
||||
|
||||
/** @brief Compute the right kernel of a matrix modulo an integer
|
||||
*
|
||||
* Computes the Howell normal form of the kernel.
|
||||
*
|
||||
* Source: https://link.springer.com/chapter/10.1007/3-540-68530-8_12
|
||||
* Adapted from PARI/GP
|
||||
*
|
||||
* @param rows The number of rows of the input
|
||||
* @param cols The number of columns of the input, must be <= rows
|
||||
* @param ker Output: the kernel
|
||||
* @param mat The matrix
|
||||
* @param mod The integer modulus
|
||||
*/
|
||||
void ibz_mat_right_ker_mod(int rows, int cols, ibz_t ker[cols][cols], const ibz_t mat[rows][cols], ibz_t *mod);
|
||||
|
||||
|
||||
/** @brief Verifies whether the 4x4 input matrix is in Hermite Normal Form
|
||||
*
|
||||
* @returns 1 if mat is in HNF, 0 otherwise
|
||||
* @param mat Matrix to be tested
|
||||
*/
|
||||
int ibz_mat_4x4_is_hnf(const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief Hermite Normal Form of a matrix of 8 integer vectors
|
||||
*
|
||||
* Algorithm used is the one at number 2.4.5 in Henri Cohen's "A Course in Computational Algebraic Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993
|
||||
*
|
||||
* @param hnf Output: Matrix in Hermite Normal Form generating the same lattice as generators
|
||||
* @param generators matrix whose colums generate the same lattice than the output
|
||||
*/
|
||||
void ibz_mat_4x8_hnf_core(ibz_mat_4x4_t *hnf, const ibz_mat_4x8_t *generators);
|
||||
|
||||
/** @brief Hermite Normal Form of a matrix concatenated with mod*Id
|
||||
*
|
||||
* @param hnf Output: Matrix in Hermite Normal Form generating the same lattice as generators
|
||||
* @param mat matrix whose colums and mod*Id generate the same lattice than the output
|
||||
* @param mod mod*Id is appended to the matrix. A hnf of this concatenation is then output
|
||||
*/
|
||||
void ibz_mat_4x4_hnf_mod(ibz_mat_4x4_t *hnf, const ibz_mat_4x4_t *mat, const ibz_t *mod);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_dim2_helpers Helper functions for dimension 2
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_dim2_other_helpers Set and other small helper functions for dimension 2 matrix and vector
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Set vector coefficients to the given integers
|
||||
*
|
||||
* @param vec Output: Vector
|
||||
* @param a0
|
||||
* @param a1
|
||||
*/
|
||||
void ibz_vec_2_set(ibz_vec_2_t *vec, int a0, int a1);
|
||||
|
||||
/** @brief Set matrix coefficients to the given integers
|
||||
*
|
||||
* @param mat Output: Matrix
|
||||
* @param a00
|
||||
* @param a01
|
||||
* @param a10
|
||||
* @param a11
|
||||
*/
|
||||
void ibz_mat_2x2_set(ibz_mat_2x2_t *mat, int a00, int a01, int a10, int a11);
|
||||
|
||||
/** @brief Determinant of a 2x2 integer matrix given as 4 integers
|
||||
*
|
||||
* @param det Output: Determinant of the matrix
|
||||
* @param a11 matrix coefficient (upper left corner)
|
||||
* @param a12 matrix coefficient (upper right corner)
|
||||
* @param a21 matrix coefficient (lower left corner)
|
||||
* @param a22 matrix coefficient (lower right corner)
|
||||
*/
|
||||
void ibz_mat_2x2_det_from_ibz(ibz_t *det, const ibz_t *a11, const ibz_t *a12, const ibz_t *a21, const ibz_t *a22);
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_cvp_helpers Helper functions for 2x2 cvp
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Checks if the vector (coord1,coord2) has integer coordinates in basis
|
||||
*
|
||||
* @param basis Rank 2 matrix
|
||||
* @param coord1
|
||||
* @param coord2
|
||||
* @returns 1 if the vector (coord1,coord2) has integer coordinates in basis, 0 otherwise
|
||||
*/
|
||||
int quat_dim2_lattice_contains(ibz_mat_2x2_t *basis, ibz_t *coord1, ibz_t *coord2);
|
||||
|
||||
|
||||
/** @brief coord1^2 + norm_q*coord2^2
|
||||
*
|
||||
* This defines a quadratic form in dimension 2 where coord1 is the first and coord2 the second coordinate of the vector on which it is evaluated
|
||||
*
|
||||
* @param norm Output: coord1^2 + norm_q*coord2^2
|
||||
* @param coord1
|
||||
* @param coord2
|
||||
* @param norm_q Positive integer
|
||||
*/
|
||||
void quat_dim2_lattice_norm(ibz_t *norm, const ibz_t *coord1, const ibz_t *coord2, const ibz_t *norm_q);
|
||||
|
||||
/** @brief v11*v21 + norm_q*v12*v22
|
||||
*
|
||||
* This defines a bilinear form in dimension 2 where v11,v12 are coordinates of the first vector, v21,v22 of the second vector
|
||||
*
|
||||
* @param res Output: v11*v21+q*v12*v22
|
||||
* @param v11
|
||||
* @param v12
|
||||
* @param v21
|
||||
* @param v22
|
||||
* @param norm_q Positive integer
|
||||
*/
|
||||
void quat_dim2_lattice_bilinear(ibz_t *res, const ibz_t *v11, const ibz_t *v12, const ibz_t *v21, const ibz_t *v22, const ibz_t *norm_q);
|
||||
|
||||
/** @brief Basis of the integral lattice represented by basis, which is small for the norm x^2 + qy^2 (in standard basis)
|
||||
*
|
||||
* Additionally, the first vector in the basis has a smaller norm than the second one.
|
||||
*
|
||||
* Algorithm 1.3.14 from Henri Cohen's "A Course in Computational Algebraic Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993
|
||||
* which finds a shortest vector in the lattice.
|
||||
*
|
||||
* @param reduced Output: Matrix of 2 column vectors of small norm x^2 + qy^2 which are a basis of the lattice the basis argument represents
|
||||
* @param basis Basis of a rank 2 lattice in dimension 2
|
||||
* @param norm_q Positive integer defining a quadratic form x^2 + qy^2 (x,y coordinates of a vector in the standard basis of R^2) for which the reduced output basis shound be small
|
||||
*/
|
||||
void quat_dim2_lattice_short_basis(ibz_mat_2x2_t *reduced, const ibz_mat_2x2_t *basis, const ibz_t *norm_q);
|
||||
|
||||
/** @brief Uses a and b to compute a* orthogonal to b, then computes the projection res of t on a* (uses the norm associated to norm_q)
|
||||
*
|
||||
* Helper for quat_dim2_lattice_closest_vector, implicitly computes an orthogonalised basis (b,a*) from (b,a) and a projection f the target t on its second vector
|
||||
*
|
||||
* Uses the norm associated to norm_q by x^2 + qy^2, for x,y coordinates of a vector
|
||||
*
|
||||
* @param res Output: The coefficient (projection of t on a* orthogonal to b) which was computed
|
||||
* @param a0 will be the 1st coeff of a, the second vector of the input basis
|
||||
* @param a1 will be the 2nd coeff of a, the second vector of the input basis
|
||||
* @param b0 will be the 1st coeff of b, the first vector of the input basis
|
||||
* @param b1 will be the 2nd coeff of b, the first vector of the input basis
|
||||
* @param t0 will be the 1st coeff of the target vector, which one wnat to project on the orthogonalised basis' second vector
|
||||
* @param t1 will be the 2nd coeff of the target vector, which one wnat to project on the orthogonalised basis' second vector
|
||||
* @param norm_q Positive integer defining a quadratic form x^2 + qy^2
|
||||
*/
|
||||
void quat_dim2_lattice_get_coefficient_with_orthogonalisation(ibz_t *res, const ibz_t *a0,const ibz_t *a1,const ibz_t *b0,const ibz_t *b1,const ibz_t *t0,const ibz_t *t1,const ibz_t *norm_q);
|
||||
|
||||
/** @brief Finds a vector close to the given target in a lattice of which a reduced basis is given
|
||||
*
|
||||
* Nearest plane algo as in https://cims.nyu.edu/~regev/teaching/lattices_fall_2004/ln/cvp.pdf (15.5.23,16h10), but without basis reduction:
|
||||
* Basically just two projections
|
||||
*
|
||||
* @param target_minus_closest Output: Vector in standard basis corresponding to target minus the close vector in the lattice which is output in closest_coords_in_basis
|
||||
* @param closest_coords_in_basis Output: Represents a vector in the lattice close to target, represented by its coordinates in the given absis of the lattice
|
||||
* @param reduced_basis Reduced basis of the lattice, reduction should be done using lll or an exact shortest vector algorithm
|
||||
* @param target vector to which the solution should be close
|
||||
* @param norm_q Positive integer defining a quadratic form x^2 + qy^2 (x,y coordinates of a vector in the standard basis of R^2) for which the reduced output basis shound be small
|
||||
*/
|
||||
void quat_dim2_lattice_closest_vector(ibz_vec_2_t *target_minus_closest, ibz_vec_2_t *closest_coords_in_basis, const ibz_mat_2x2_t *reduced_basis, const ibz_vec_2_t *target, const ibz_t *norm_q);
|
||||
|
||||
/** @brief give a,b,c such that ax^2 + bxy + cy^2 = N(Bz), where B is the basis, z the vector x,y and N the quadratic form (coord1^2 + q coord2^2)
|
||||
*
|
||||
* @param qf_a Output: b in the formula
|
||||
* @param qf_b Output: b in the formula
|
||||
* @param qf_c Output: c in the formula
|
||||
* @param basis Basis of the lattice
|
||||
* @param norm_q Positive integer defining a quadratic form x^2 + qy^2 (x,y coordinates of a vector in the standard basis of R^2) for which the reduced output basis shound be small
|
||||
*/
|
||||
void quat_dim2_lattice_get_qf_on_lattice(ibz_t *qf_a, ibz_t *qf_b, ibz_t *qf_c, const ibz_mat_2x2_t *basis, const ibz_t *norm_q);
|
||||
|
||||
/** @brief Test version of the condition argument in the cvp enumeration algorithms.
|
||||
*
|
||||
* Sets elem[0] and elem[2] to vec[0], elem[1] and elem[3] to vec[1] if vec[0] + vec[1] mod p is 2, where p is the ibz_t to which params points
|
||||
*
|
||||
* This defines a quadratic form in dimension 2 where coord1 is the first and coord2 the second coordinate of the vector on which it is evaluated
|
||||
*
|
||||
* @param elem Output as described below
|
||||
* @param vec
|
||||
* @param params void* which must point to an ibz_t
|
||||
*/
|
||||
int quat_dim2_lattice_test_cvp_condition(quat_alg_elem_t* elem, const ibz_vec_2_t* vec, const void* params);
|
||||
|
||||
/**
|
||||
* @brief Find vector of small norm in a positive definite quadratic form, satisfying extra conditions.
|
||||
*
|
||||
* @param res Output: The quat_alg_elem (dimension 4, with denominator) which the condition sets when it is fulfilled
|
||||
* @param x first coordinate in the lattice basis lat_basis of a short vector (for the norm written coeff1^2 + q coeff2 ^2 in the standard basis)
|
||||
* @param y first coordinate in the lattice basis lat_basis of a short vector (for the norm written coeff1^2 + q coeff2 ^2 in the standard basis)
|
||||
* @param condition a filter function returning whether res is set to a valid output or not. The algorithm stops when it succeeds (outputs 1)
|
||||
* @param params extra parameters passed to `condition`. May be NULL.
|
||||
* @param target_minus_closest vector which will be added to the enumerated short vectors before checking the bound
|
||||
* @param lat_basis reduced basis of the lattice, in which a short vector is searched for
|
||||
* @param norm_q defines the quadratic form coord1^2+norm_q*coord2^2 (in standard basis) used as norm
|
||||
* @param norm_bound only vectors with norm smaller than this bound are tested for condition
|
||||
* @return 1 if vector was found, 0 otherwise
|
||||
*/
|
||||
int quat_dim2_lattice_bound_and_condition(quat_alg_elem_t *res, const ibz_t *x, const ibz_t *y, int (*condition)(quat_alg_elem_t *, const ibz_vec_2_t *, const void *), const void *params, const ibz_vec_2_t *target_minus_closest, const ibz_mat_2x2_t *lat_basis, const ibz_t *norm_q, const ibz_t *norm_bound);
|
||||
|
||||
/** @brief Computes an integer slightly larger than sqrt(num_a/denom_a)+num_b/denom_b.
|
||||
*
|
||||
* More precisely, if denoting sqrt_ the integer part of the square root, and _ the integer part of a rational,
|
||||
* res = 1+_((sqrt_(num_a)+1)/sqrt_(denom_a) + num_b/denom_b)
|
||||
*
|
||||
* @param res upper approximation of sqrt(num_a/denom_a)+num_b/denom_b
|
||||
* @param num_a must be of same sign as denom_a
|
||||
* @param denom_a must be non 0 and of same sign as num_a
|
||||
* @param num_b
|
||||
* @param denom_b must be non 0
|
||||
*/
|
||||
int quat_dim2_lattice_qf_value_bound_generation(ibz_t *res, const ibz_t *num_a, const ibz_t *denom_a, const ibz_t *num_b, const ibz_t *denom_b);
|
||||
|
||||
/**
|
||||
* @brief Find vector of small norm in a positive definite quadratic form, satisfying extra conditions.
|
||||
*
|
||||
* Enumerates up to `max_tries` vectors `(x,y)` such that `qfa x² + qfb xy + qfc y² < norm_bound`; the first
|
||||
* vector such that `quat_dim2_lattice_bound_and_condition(res,x,y,condition,params,target_minus_closest,lat_basis, norm_q,norm_bound) == 1` is returned.
|
||||
* The vector enumeration starts by vectors close to the bound
|
||||
*
|
||||
* Uses algorithm 2.7.5 (Fincke-Pohst) from Henri Cohen's "A Course in Computational Algebraic Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993
|
||||
* Slightly adapted to work without rational numbers and their square roots
|
||||
* Therefore needing a test to make sure the bounds are respected, which is integrated in quat_dim2_lattice_bound_and_condition
|
||||
* Also the norm bound is initialised a bit lower that the bound received, to leave space for the added target_minus_closest
|
||||
*
|
||||
* @param res Output: selected vector (x,y)
|
||||
* @param condition a filter function returning whether a vector should be output or not
|
||||
* @param params extra parameters passed to `condition`. May be NULL.
|
||||
* @param target_minus_closest vector which will be added to the enumerated short vectors before checking the bound
|
||||
* @param lat_basis reduced basis of the lattice, in which a short vector is searched for
|
||||
* @param norm_q defines the quadratic form coord1^2+norm_q*coord2^2 (in standard basis) used as norm
|
||||
* @param norm_bound only vectors with norm smaller than this bound are tested for condition and output
|
||||
* @param max_tries maximum number of calls to filter
|
||||
* @return 1 if vector was found, 0 otherwise
|
||||
*/
|
||||
int quat_dim2_lattice_qf_enumerate_short_vec(quat_alg_elem_t *res, int (*condition)(quat_alg_elem_t *, const ibz_vec_2_t *, const void *), const void *params, const ibz_vec_2_t *target_minus_closest, const ibz_mat_2x2_t *lat_basis, const ibz_t *norm_q, const ibz_t *norm_bound, const int max_tries);
|
||||
/** @}
|
||||
*/
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_lattice_helper Helper functions for the lattice library (dimension 4)
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Lattice equality
|
||||
*
|
||||
* Lattice bases are assumed to be under HNF, but denominators are free.
|
||||
*
|
||||
* @returns 1 if both lattices are equal, 0 otherwise
|
||||
*/
|
||||
int quat_lattice_equal(const quat_lattice_t *lat1, const quat_lattice_t *lat2);
|
||||
|
||||
/** @brief Divides basis and denominator of a lattice by their gcd
|
||||
*
|
||||
* @param reduced Output
|
||||
* @param lat Lattice
|
||||
*/
|
||||
void quat_lattice_reduce_denom(quat_lattice_t *reduced, const quat_lattice_t *lat);
|
||||
|
||||
/**
|
||||
* @brief Computes the dual lattice of lat, without putting its basis in HNF
|
||||
*
|
||||
* This function returns a lattice not under HNF. For careful internal use only.
|
||||
*
|
||||
* Coputation method described in https://cseweb.ucsd.edu/classes/sp14/cse206A-a/lec4.pdf consulted on 19 of May 2023, 12h40 CEST
|
||||
*
|
||||
* @param dual Output: The dual lattice of lat. ATTENTION: is not under HNF. hnf computation must be applied before using lattice functions on it
|
||||
* @param lat lattice, the dual of it will be computed
|
||||
*/
|
||||
void quat_lattice_dual_without_hnf(quat_lattice_t *dual, const quat_lattice_t *lat);
|
||||
|
||||
/**
|
||||
* @brief Test whether x ∈ lat. If so, compute its coordinates in lat's basis.
|
||||
*
|
||||
* Lattice assumed of full rank and under HNF, none of both is tested so far.
|
||||
*
|
||||
* @param coord Output: Set to the coordinates of x in lat
|
||||
* @param lat The lattice
|
||||
* @param x An element of the quaternion algebra, in same basis as the lattice lat
|
||||
* @return true if x ∈ lat
|
||||
*/
|
||||
int quat_lattice_contains_without_alg(quat_alg_coord_t *coord, const quat_lattice_t *lat, const quat_alg_elem_t *x);
|
||||
|
||||
/** @brief The index of sublat into overlat
|
||||
*
|
||||
* Assumes inputs are in HNF.
|
||||
*
|
||||
* @param index Output
|
||||
* @param sublat A lattice in HNF, must be sublattice of overlat
|
||||
* @param overlat A lattice in HNF, must be overlattice of sublat
|
||||
*/
|
||||
void quat_lattice_index(ibz_t *index, const quat_lattice_t *sublat, const quat_lattice_t *overlat);
|
||||
|
||||
/** @brief Random lattice element from a small parallelogram
|
||||
*
|
||||
* Sample a random element in `lattice` by taking a random linear
|
||||
* combination of the basis with uniform coefficients in
|
||||
* [-2^(n-1),2^(n-1)-1].
|
||||
*
|
||||
* @param elem Output element
|
||||
* @param lattice Whence the element is sampled
|
||||
* @param n Number of random bits for the coefficients. Must be <= 64.
|
||||
* @return 0 if PRNG failed (in this case elem is set to 0), 1 otherwise
|
||||
*/
|
||||
int quat_lattice_random_elem(quat_alg_elem_t *elem, const quat_lattice_t *lattice, unsigned char n);
|
||||
|
||||
/** @brief Compute the right transporter from lat1 to lat2
|
||||
*
|
||||
* The ideal of those x such that lat1·x ⊂ lat2
|
||||
*/
|
||||
void quat_lattice_right_transporter(quat_lattice_t *trans, const quat_lattice_t *lat1, const quat_lattice_t *lat2, const quat_alg_t *alg);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
/** @}
|
||||
*/
|
||||
/** @}
|
||||
*/
|
||||
|
||||
#endif
|
||||
743
src/quaternion/ref/generic/internal_quaternion_headers/dpe.h
Normal file
743
src/quaternion/ref/generic/internal_quaternion_headers/dpe.h
Normal file
@@ -0,0 +1,743 @@
|
||||
/* Copyright (C) 2004-2024 Patrick Pelissier, Paul Zimmermann, LORIA/INRIA.
|
||||
|
||||
This file is part of the DPE Library.
|
||||
|
||||
The DPE Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The DPE Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the DPE Library; see the file COPYING.LIB.
|
||||
If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef __DPE
|
||||
#define __DPE
|
||||
|
||||
#include <stdlib.h> /* For abort */
|
||||
#include <stdio.h> /* For fprintf */
|
||||
#include <math.h> /* for round, floor, ceil */
|
||||
#include <limits.h>
|
||||
|
||||
/* if you change the version, please change it in Makefile too */
|
||||
#define DPE_VERSION_MAJOR 1
|
||||
#define DPE_VERSION_MINOR 7
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
# define DPE_LIKELY(x) (__builtin_expect(!!(x),1))
|
||||
# define DPE_UNLIKELY(x) (__builtin_expect((x),0))
|
||||
# define DPE_UNUSED_ATTR __attribute__((unused))
|
||||
#else
|
||||
# define DPE_LIKELY(x) (x)
|
||||
# define DPE_UNLIKELY(x) (x)
|
||||
# define DPE_UNUSED_ATTR
|
||||
#endif
|
||||
|
||||
/* If no user defined mode, define it to double */
|
||||
#if !defined(DPE_USE_DOUBLE) && !defined(DPE_USE_LONGDOUBLE) && !defined(DPE_USE_FLOAT128)
|
||||
# define DPE_USE_DOUBLE
|
||||
#endif
|
||||
|
||||
#if defined(DPE_USE_DOUBLE) && defined(DPE_USE_LONGDOUBLE)
|
||||
# error "Either DPE_USE_DOUBLE or DPE_USE_LONGDOUBLE shall be defined."
|
||||
#elif defined(DPE_USE_DOUBLE) && defined(DPE_USE_USE_FLOAT128)
|
||||
# error "Either DPE_USE_DOUBLE or DPE_USE_FLOAT128 shall be defined."
|
||||
#elif defined(DPE_USE_LONG_DOUBLE) && defined(DPE_USE_USE_FLOAT128)
|
||||
# error "Either DPE_USE_LONG_DOUBLE or DPE_USE_FLOAT128 shall be defined."
|
||||
#endif
|
||||
|
||||
#if (defined(__i386) || defined (__x86_64)) && !defined(DPE_LITTLEENDIAN32) && defined(DPE_USE_DOUBLE)
|
||||
# define DPE_LITTLEENDIAN32
|
||||
#endif
|
||||
|
||||
#if (defined(__STDC_VERSION__) && (__STDC_VERSION__>=199901L)) || defined (__GLIBC__)
|
||||
# define DPE_DEFINE_ROUND_TRUNC
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ *10 + __GNUC_MINOR__) >= 43
|
||||
# define DPE_ISFINITE __builtin_isfinite
|
||||
#elif defined(isfinite)
|
||||
# define DPE_ISFINITE isfinite /* new C99 function */
|
||||
#else
|
||||
# define DPE_ISFINITE finite /* obsolete BSD function */
|
||||
#endif
|
||||
|
||||
/* DPE_LDEXP(DPE_DOUBLE m, DPEEXP e) return x = m * 2^e */
|
||||
/* DPE_FREXP(DPE_DOUBLE x, DPEEXP *e) returns m, e such that x = m * 2^e with
|
||||
1/2 <= m < 1 */
|
||||
/* DPE_ROUND(DPE_DOUBLE x) returns the nearest integer to x */
|
||||
#if defined(DPE_USE_DOUBLE)
|
||||
# define DPE_DOUBLE double /* mantissa type */
|
||||
# define DPE_BITSIZE 53 /* bitsize of DPE_DOUBLE */
|
||||
# define DPE_2_POW_BITSIZE 0x1P53
|
||||
# if defined(__GNUC__) && (__GNUC__ *10 + __GNUC_MINOR__) >= 40
|
||||
# define DPE_LDEXP __builtin_ldexp
|
||||
# define DPE_FREXP __builtin_frexp
|
||||
# define DPE_FLOOR __builtin_floor
|
||||
# define DPE_CEIL __builtin_ceil
|
||||
# ifdef DPE_DEFINE_ROUND_TRUNC
|
||||
# define DPE_ROUND __builtin_round
|
||||
# define DPE_TRUNC __builtin_trunc
|
||||
# endif
|
||||
# else
|
||||
# define DPE_LDEXP ldexp
|
||||
# define DPE_FREXP frexp
|
||||
# define DPE_FLOOR floor
|
||||
# define DPE_CEIL ceil
|
||||
# ifdef DPE_DEFINE_ROUND_TRUNC
|
||||
# define DPE_ROUND round
|
||||
# define DPE_TRUNC trunc
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#elif defined(DPE_USE_LONGDOUBLE)
|
||||
# define DPE_DOUBLE long double
|
||||
# define DPE_BITSIZE 64
|
||||
# define DPE_2_POW_BITSIZE 0x1P64
|
||||
# define DPE_LDEXP ldexpl
|
||||
# define DPE_FREXP frexpl
|
||||
# define DPE_FLOOR floorl
|
||||
# define DPE_CEIL ceill
|
||||
# ifdef DPE_DEFINE_ROUND_TRUNC
|
||||
# define DPE_ROUND roundl
|
||||
# define DPE_TRUNC truncl
|
||||
# endif
|
||||
|
||||
#elif defined(DPE_USE_FLOAT128)
|
||||
# include "quadmath.h"
|
||||
# define DPE_DOUBLE __float128
|
||||
# define DPE_BITSIZE 113
|
||||
# define DPE_2_POW_BITSIZE 0x1P113
|
||||
# define DPE_LDEXP ldexpq
|
||||
# define DPE_FLOOR floorq
|
||||
# define DPE_CEIL ceilq
|
||||
# define DPE_FREXP frexpq
|
||||
# ifdef DPE_DEFINE_ROUND_TRUNC
|
||||
# define DPE_ROUND roundq
|
||||
# define DPE_TRUNC truncq
|
||||
# endif
|
||||
|
||||
#else
|
||||
# error "neither DPE_USE_DOUBLE, nor DPE_USE_LONGDOUBLE, nor DPE_USE_FLOAT128 is defined"
|
||||
#endif
|
||||
|
||||
/* If no C99, do what we can */
|
||||
#ifndef DPE_DEFINE_ROUND_TRUNC
|
||||
# define DPE_ROUND(x) ((DPE_DOUBLE) ((long long) ((x) + ((x) >= 0.0 ? 0.5 : -0.5))))
|
||||
# define DPE_TRUNC(x) ((DPE_DOUBLE) ((long long) ((x) + 0.0)))
|
||||
#endif
|
||||
|
||||
#if defined(DPE_USE_LONG)
|
||||
# define DPE_EXP_T long /* exponent type */
|
||||
# define DPE_EXPMIN LONG_MIN /* smallest possible exponent */
|
||||
#elif defined(DPE_USE_LONGLONG)
|
||||
# define DPE_EXP_T long long
|
||||
# define DPE_EXPMIN LLONG_MIN
|
||||
#else
|
||||
# define DPE_EXP_T int /* exponent type */
|
||||
# define DPE_EXPMIN INT_MIN /* smallest possible exponent */
|
||||
#endif
|
||||
|
||||
#ifdef DPE_LITTLEENDIAN32
|
||||
typedef union
|
||||
{
|
||||
double d;
|
||||
#if INT_MAX == 0x7FFFFFFFL
|
||||
int i[2];
|
||||
#elif LONG_MAX == 0x7FFFFFFFL
|
||||
long i[2];
|
||||
#elif SHRT_MAX == 0x7FFFFFFFL
|
||||
short i[2];
|
||||
#else
|
||||
# error Cannot find a 32 bits integer type.
|
||||
#endif
|
||||
} dpe_double_words;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DPE_DOUBLE d; /* significand */
|
||||
DPE_EXP_T exp; /* exponent */
|
||||
} dpe_struct;
|
||||
|
||||
typedef dpe_struct dpe_t[1];
|
||||
|
||||
#define DPE_MANT(x) ((x)->d)
|
||||
#define DPE_EXP(x) ((x)->exp)
|
||||
#define DPE_SIGN(x) ((DPE_MANT(x) < 0.0) ? -1 : (DPE_MANT(x) > 0.0))
|
||||
|
||||
#define DPE_INLINE static inline
|
||||
|
||||
/* initialize */
|
||||
DPE_INLINE void
|
||||
dpe_init (dpe_t x DPE_UNUSED_ATTR)
|
||||
{
|
||||
}
|
||||
|
||||
/* clear */
|
||||
DPE_INLINE void
|
||||
dpe_clear (dpe_t x DPE_UNUSED_ATTR)
|
||||
{
|
||||
}
|
||||
|
||||
/* set x to y */
|
||||
DPE_INLINE void
|
||||
dpe_set (dpe_t x, dpe_t y)
|
||||
{
|
||||
DPE_MANT(x) = DPE_MANT(y);
|
||||
DPE_EXP(x) = DPE_EXP(y);
|
||||
}
|
||||
|
||||
/* set x to -y */
|
||||
DPE_INLINE void
|
||||
dpe_neg (dpe_t x, dpe_t y)
|
||||
{
|
||||
DPE_MANT(x) = -DPE_MANT(y);
|
||||
DPE_EXP(x) = DPE_EXP(y);
|
||||
}
|
||||
|
||||
/* set x to |y| */
|
||||
DPE_INLINE void
|
||||
dpe_abs (dpe_t x, dpe_t y)
|
||||
{
|
||||
DPE_MANT(x) = (DPE_MANT(y) >= 0) ? DPE_MANT(y) : -DPE_MANT(y);
|
||||
DPE_EXP(x) = DPE_EXP(y);
|
||||
}
|
||||
|
||||
/* set mantissa in [1/2, 1), except for 0 which has minimum exponent */
|
||||
/* FIXME: don't inline this function yet ? */
|
||||
static void
|
||||
dpe_normalize (dpe_t x)
|
||||
{
|
||||
if (DPE_UNLIKELY (DPE_MANT(x) == 0.0 || DPE_ISFINITE (DPE_MANT(x)) == 0))
|
||||
{
|
||||
if (DPE_MANT(x) == 0.0)
|
||||
DPE_EXP(x) = DPE_EXPMIN;
|
||||
/* otherwise let the exponent of NaN, Inf unchanged */
|
||||
}
|
||||
else
|
||||
{
|
||||
DPE_EXP_T e;
|
||||
#ifdef DPE_LITTLEENDIAN32 /* 32-bit little endian */
|
||||
dpe_double_words dw;
|
||||
dw.d = DPE_MANT(x);
|
||||
e = (dw.i[1] >> 20) & 0x7FF; /* unbiased exponent, 1022 for m=1/2 */
|
||||
DPE_EXP(x) += e - 1022;
|
||||
dw.i[1] = (dw.i[1] & 0x800FFFFF) | 0x3FE00000;
|
||||
DPE_MANT(x) = dw.d;
|
||||
#else /* portable code */
|
||||
double m = DPE_MANT(x);
|
||||
DPE_MANT(x) = DPE_FREXP (m, &e);
|
||||
DPE_EXP(x) += e;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DPE_USE_DOUBLE)
|
||||
static const double dpe_scale_tab[54] = {
|
||||
0x1P0, 0x1P-1, 0x1P-2, 0x1P-3, 0x1P-4, 0x1P-5, 0x1P-6, 0x1P-7, 0x1P-8,
|
||||
0x1P-9, 0x1P-10, 0x1P-11, 0x1P-12, 0x1P-13, 0x1P-14, 0x1P-15, 0x1P-16,
|
||||
0x1P-17, 0x1P-18, 0x1P-19, 0x1P-20, 0x1P-21, 0x1P-22, 0x1P-23, 0x1P-24,
|
||||
0x1P-25, 0x1P-26, 0x1P-27, 0x1P-28, 0x1P-29, 0x1P-30, 0x1P-31, 0x1P-32,
|
||||
0x1P-33, 0x1P-34, 0x1P-35, 0x1P-36, 0x1P-37, 0x1P-38, 0x1P-39, 0x1P-40,
|
||||
0x1P-41, 0x1P-42, 0x1P-43, 0x1P-44, 0x1P-45, 0x1P-46, 0x1P-47, 0x1P-48,
|
||||
0x1P-49, 0x1P-50, 0x1P-51, 0x1P-52, 0x1P-53};
|
||||
#endif
|
||||
|
||||
DPE_INLINE DPE_DOUBLE
|
||||
dpe_scale (DPE_DOUBLE d, int s)
|
||||
{
|
||||
/* -DPE_BITSIZE < s <= 0 and 1/2 <= d < 1 */
|
||||
#if defined(DPE_USE_DOUBLE)
|
||||
return d * dpe_scale_tab [-s];
|
||||
#else /* portable code */
|
||||
return DPE_LDEXP (d, s);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* set x to y */
|
||||
DPE_INLINE void
|
||||
dpe_set_d (dpe_t x, double y)
|
||||
{
|
||||
DPE_MANT(x) = (DPE_DOUBLE) y;
|
||||
DPE_EXP(x) = 0;
|
||||
dpe_normalize (x);
|
||||
}
|
||||
|
||||
/* set x to y */
|
||||
DPE_INLINE void
|
||||
dpe_set_ld (dpe_t x, long double y)
|
||||
{
|
||||
DPE_MANT(x) = (DPE_DOUBLE) y;
|
||||
DPE_EXP(x) = 0;
|
||||
dpe_normalize (x);
|
||||
}
|
||||
|
||||
/* set x to y */
|
||||
DPE_INLINE void
|
||||
dpe_set_ui (dpe_t x, unsigned long y)
|
||||
{
|
||||
DPE_MANT(x) = (DPE_DOUBLE) y;
|
||||
DPE_EXP(x) = 0;
|
||||
dpe_normalize (x);
|
||||
}
|
||||
|
||||
/* set x to y */
|
||||
DPE_INLINE void
|
||||
dpe_set_si (dpe_t x, long y)
|
||||
{
|
||||
DPE_MANT(x) = (DPE_DOUBLE) y;
|
||||
DPE_EXP(x) = 0;
|
||||
dpe_normalize (x);
|
||||
}
|
||||
|
||||
DPE_INLINE long
|
||||
dpe_get_si (dpe_t x)
|
||||
{
|
||||
DPE_DOUBLE d = DPE_LDEXP (DPE_MANT (x), DPE_EXP (x));
|
||||
return (long) d;
|
||||
}
|
||||
|
||||
DPE_INLINE unsigned long
|
||||
dpe_get_ui (dpe_t x)
|
||||
{
|
||||
DPE_DOUBLE d = DPE_LDEXP (DPE_MANT (x), DPE_EXP (x));
|
||||
return (d < 0.0) ? 0 : (unsigned long) d;
|
||||
}
|
||||
|
||||
DPE_INLINE double
|
||||
dpe_get_d (dpe_t x)
|
||||
{
|
||||
return DPE_LDEXP (DPE_MANT (x), DPE_EXP (x));
|
||||
}
|
||||
|
||||
DPE_INLINE long double
|
||||
dpe_get_ld (dpe_t x)
|
||||
{
|
||||
return DPE_LDEXP (DPE_MANT (x), DPE_EXP (x));
|
||||
}
|
||||
|
||||
#if defined(__GMP_H__) || defined(__MINI_GMP_H__)
|
||||
/* set x to y */
|
||||
DPE_INLINE void
|
||||
dpe_set_z (dpe_t x, mpz_t y)
|
||||
{
|
||||
long e;
|
||||
DPE_MANT(x) = mpz_get_d_2exp (&e, y);
|
||||
DPE_EXP(x) = (DPE_EXP_T) e;
|
||||
}
|
||||
|
||||
/* set x to y, rounded to nearest */
|
||||
DPE_INLINE void
|
||||
dpe_get_z (mpz_t x, dpe_t y)
|
||||
{
|
||||
DPE_EXP_T ey = DPE_EXP(y);
|
||||
if (ey >= DPE_BITSIZE) /* y is an integer */
|
||||
{
|
||||
DPE_DOUBLE d = DPE_MANT(y) * DPE_2_POW_BITSIZE; /* d is an integer */
|
||||
mpz_set_d (x, d); /* should be exact */
|
||||
mpz_mul_2exp (x, x, (unsigned long) ey - DPE_BITSIZE);
|
||||
}
|
||||
else /* DPE_EXP(y) < DPE_BITSIZE */
|
||||
{
|
||||
if (DPE_UNLIKELY (ey < 0)) /* |y| < 1/2 */
|
||||
mpz_set_ui (x, 0);
|
||||
else
|
||||
{
|
||||
DPE_DOUBLE d = DPE_LDEXP(DPE_MANT(y), ey);
|
||||
mpz_set_d (x, (double) DPE_ROUND(d));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* return e and x such that y = x*2^e */
|
||||
DPE_INLINE mp_exp_t
|
||||
dpe_get_z_exp (mpz_t x, dpe_t y)
|
||||
{
|
||||
mpz_set_d (x, DPE_MANT (y) * DPE_2_POW_BITSIZE);
|
||||
return DPE_EXP(y) - DPE_BITSIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* x <- y + z, assuming y and z are normalized, returns x normalized */
|
||||
DPE_INLINE void
|
||||
dpe_add (dpe_t x, dpe_t y, dpe_t z)
|
||||
{
|
||||
if (DPE_UNLIKELY (DPE_EXP(y) > DPE_EXP(z) + DPE_BITSIZE))
|
||||
/* |z| < 1/2*ulp(y), thus o(y+z) = y */
|
||||
dpe_set (x, y);
|
||||
else if (DPE_UNLIKELY (DPE_EXP(z) > DPE_EXP(y) + DPE_BITSIZE))
|
||||
dpe_set (x, z);
|
||||
else
|
||||
{
|
||||
DPE_EXP_T d = DPE_EXP(y) - DPE_EXP(z); /* |d| <= DPE_BITSIZE */
|
||||
|
||||
if (d >= 0)
|
||||
{
|
||||
DPE_MANT(x) = DPE_MANT(y) + dpe_scale (DPE_MANT(z), -d);
|
||||
DPE_EXP(x) = DPE_EXP(y);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPE_MANT(x) = DPE_MANT(z) + dpe_scale (DPE_MANT(y), d);
|
||||
DPE_EXP(x) = DPE_EXP(z);
|
||||
}
|
||||
dpe_normalize (x);
|
||||
}
|
||||
}
|
||||
|
||||
/* x <- y - z, assuming y and z are normalized, returns x normalized */
|
||||
DPE_INLINE void
|
||||
dpe_sub (dpe_t x, dpe_t y, dpe_t z)
|
||||
{
|
||||
if (DPE_UNLIKELY (DPE_EXP(y) > DPE_EXP(z) + DPE_BITSIZE))
|
||||
/* |z| < 1/2*ulp(y), thus o(y-z) = y */
|
||||
dpe_set (x, y);
|
||||
else if (DPE_UNLIKELY (DPE_EXP(z) > DPE_EXP(y) + DPE_BITSIZE))
|
||||
dpe_neg (x, z);
|
||||
else
|
||||
{
|
||||
DPE_EXP_T d = DPE_EXP(y) - DPE_EXP(z); /* |d| <= DPE_BITSIZE */
|
||||
|
||||
if (d >= 0)
|
||||
{
|
||||
DPE_MANT(x) = DPE_MANT(y) - dpe_scale (DPE_MANT(z), -d);
|
||||
DPE_EXP(x) = DPE_EXP(y);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPE_MANT(x) = dpe_scale (DPE_MANT(y), d) - DPE_MANT(z);
|
||||
DPE_EXP(x) = DPE_EXP(z);
|
||||
}
|
||||
dpe_normalize (x);
|
||||
}
|
||||
}
|
||||
|
||||
/* x <- y * z, assuming y and z are normalized, returns x normalized */
|
||||
DPE_INLINE void
|
||||
dpe_mul (dpe_t x, dpe_t y, dpe_t z)
|
||||
{
|
||||
DPE_MANT(x) = DPE_MANT(y) * DPE_MANT(z);
|
||||
DPE_EXP(x) = DPE_EXP(y) + DPE_EXP(z);
|
||||
dpe_normalize (x);
|
||||
}
|
||||
|
||||
/* x <- sqrt(y), assuming y is normalized, returns x normalized */
|
||||
DPE_INLINE void
|
||||
dpe_sqrt (dpe_t x, dpe_t y)
|
||||
{
|
||||
DPE_EXP_T ey = DPE_EXP(y);
|
||||
if (ey % 2)
|
||||
{
|
||||
/* since 1/2 <= my < 1, 1/4 <= my/2 < 1 */
|
||||
DPE_MANT(x) = sqrt (0.5 * DPE_MANT(y));
|
||||
DPE_EXP(x) = (ey + 1) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPE_MANT(x) = sqrt (DPE_MANT(y));
|
||||
DPE_EXP(x) = ey / 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* x <- y / z, assuming y and z are normalized, returns x normalized.
|
||||
Assumes z is not zero. */
|
||||
DPE_INLINE void
|
||||
dpe_div (dpe_t x, dpe_t y, dpe_t z)
|
||||
{
|
||||
DPE_MANT(x) = DPE_MANT(y) / DPE_MANT(z);
|
||||
DPE_EXP(x) = DPE_EXP(y) - DPE_EXP(z);
|
||||
dpe_normalize (x);
|
||||
}
|
||||
|
||||
/* x <- y * z, assuming y normalized, returns x normalized */
|
||||
DPE_INLINE void
|
||||
dpe_mul_ui (dpe_t x, dpe_t y, unsigned long z)
|
||||
{
|
||||
DPE_MANT(x) = DPE_MANT(y) * (DPE_DOUBLE) z;
|
||||
DPE_EXP(x) = DPE_EXP(y);
|
||||
dpe_normalize (x);
|
||||
}
|
||||
|
||||
/* x <- y / z, assuming y normalized, z non-zero, returns x normalized */
|
||||
DPE_INLINE void
|
||||
dpe_div_ui (dpe_t x, dpe_t y, unsigned long z)
|
||||
{
|
||||
DPE_MANT(x) = DPE_MANT(y) / (DPE_DOUBLE) z;
|
||||
DPE_EXP(x) = DPE_EXP(y);
|
||||
dpe_normalize (x);
|
||||
}
|
||||
|
||||
/* x <- y * 2^e */
|
||||
DPE_INLINE void
|
||||
dpe_mul_2exp (dpe_t x, dpe_t y, unsigned long e)
|
||||
{
|
||||
DPE_MANT(x) = DPE_MANT(y);
|
||||
DPE_EXP(x) = DPE_EXP(y) + (DPE_EXP_T) e;
|
||||
}
|
||||
|
||||
/* x <- y / 2^e */
|
||||
DPE_INLINE void
|
||||
dpe_div_2exp (dpe_t x, dpe_t y, unsigned long e)
|
||||
{
|
||||
DPE_MANT(x) = DPE_MANT(y);
|
||||
DPE_EXP(x) = DPE_EXP(y) - (DPE_EXP_T) e;
|
||||
}
|
||||
|
||||
/* return e and x such that y = x*2^e (equality is not guaranteed if the 'long'
|
||||
type has fewer bits than the significand in dpe_t) */
|
||||
DPE_INLINE DPE_EXP_T
|
||||
dpe_get_si_exp (long *x, dpe_t y)
|
||||
{
|
||||
if (sizeof(long) == 4) /* 32-bit word: long has 31 bits */
|
||||
{
|
||||
*x = (long) (DPE_MANT(y) * 2147483648.0);
|
||||
return DPE_EXP(y) - 31;
|
||||
}
|
||||
else if (sizeof(long) == 8) /* 64-bit word: long has 63 bits */
|
||||
{
|
||||
*x = (long) (DPE_MANT (y) * 9223372036854775808.0);
|
||||
return DPE_EXP(y) - 63;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Error, neither 32-bit nor 64-bit word\n");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
static DPE_UNUSED_ATTR int dpe_str_prec = 16;
|
||||
static int dpe_out_str (FILE *s, int base, dpe_t x) DPE_UNUSED_ATTR;
|
||||
|
||||
static int
|
||||
dpe_out_str (FILE *s, int base, dpe_t x)
|
||||
{
|
||||
DPE_DOUBLE d = DPE_MANT(x);
|
||||
DPE_EXP_T e2 = DPE_EXP(x);
|
||||
int e10 = 0;
|
||||
char sign = ' ';
|
||||
if (DPE_UNLIKELY (base != 10))
|
||||
{
|
||||
fprintf (stderr, "Error in dpe_out_str, only base 10 allowed\n");
|
||||
exit (1);
|
||||
}
|
||||
if (d == 0.0)
|
||||
#ifdef DPE_USE_DOUBLE
|
||||
return fprintf (s, "%1.*f", dpe_str_prec, d);
|
||||
#else
|
||||
return fprintf (s, "%1.*Lf", dpe_str_prec, (long double) d);
|
||||
#endif
|
||||
if (d < 0)
|
||||
{
|
||||
d = -d;
|
||||
sign = '-';
|
||||
}
|
||||
if (e2 > 0)
|
||||
{
|
||||
while (e2 > 0)
|
||||
{
|
||||
e2 --;
|
||||
d *= 2.0;
|
||||
if (d >= 10.0)
|
||||
{
|
||||
d /= 10.0;
|
||||
e10 ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* e2 <= 0 */
|
||||
{
|
||||
while (e2 < 0)
|
||||
{
|
||||
e2 ++;
|
||||
d /= 2.0;
|
||||
if (d < 1.0)
|
||||
{
|
||||
d *= 10.0;
|
||||
e10 --;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DPE_USE_DOUBLE
|
||||
return fprintf (s, "%c%1.*f*10^%d", sign, dpe_str_prec, d, e10);
|
||||
#else
|
||||
return fprintf (s, "%c%1.*Lf*10^%d", sign, dpe_str_prec, (long double) d, e10);
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t dpe_inp_str (dpe_t x, FILE *s, int base) DPE_UNUSED_ATTR;
|
||||
|
||||
static size_t
|
||||
dpe_inp_str (dpe_t x, FILE *s, int base)
|
||||
{
|
||||
size_t res;
|
||||
DPE_DOUBLE d;
|
||||
if (DPE_UNLIKELY (base != 10))
|
||||
{
|
||||
fprintf (stderr, "Error in dpe_out_str, only base 10 allowed\n");
|
||||
exit (1);
|
||||
}
|
||||
#ifdef DPE_USE_DOUBLE
|
||||
res = fscanf (s, "%lf", &d);
|
||||
#elif defined(DPE_USE_LONGDOUBLE)
|
||||
res = fscanf (s, "%Lf", &d);
|
||||
#else
|
||||
{
|
||||
long double d_ld;
|
||||
res = fscanf (s, "%Lf", &d_ld);
|
||||
d = d_ld;
|
||||
}
|
||||
#endif
|
||||
dpe_set_d (x, d);
|
||||
return res;
|
||||
}
|
||||
|
||||
DPE_INLINE void
|
||||
dpe_dump (dpe_t x)
|
||||
{
|
||||
dpe_out_str (stdout, 10, x);
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
DPE_INLINE int
|
||||
dpe_zero_p (dpe_t x)
|
||||
{
|
||||
return DPE_MANT (x) == 0;
|
||||
}
|
||||
|
||||
/* return a positive value if x > y
|
||||
a negative value if x < y
|
||||
and 0 otherwise (x=y). */
|
||||
DPE_INLINE int
|
||||
dpe_cmp (dpe_t x, dpe_t y)
|
||||
{
|
||||
int sx = DPE_SIGN(x);
|
||||
int d = sx - DPE_SIGN(y);
|
||||
|
||||
if (d != 0)
|
||||
return d;
|
||||
else if (DPE_EXP(x) > DPE_EXP(y))
|
||||
return (sx > 0) ? 1 : -1;
|
||||
else if (DPE_EXP(y) > DPE_EXP(x))
|
||||
return (sx > 0) ? -1 : 1;
|
||||
else /* DPE_EXP(x) = DPE_EXP(y) */
|
||||
return (DPE_MANT(x) < DPE_MANT(y)) ? -1 : (DPE_MANT(x) > DPE_MANT(y));
|
||||
}
|
||||
|
||||
DPE_INLINE int
|
||||
dpe_cmp_d (dpe_t x, double d)
|
||||
{
|
||||
dpe_t y;
|
||||
dpe_set_d (y, d);
|
||||
return dpe_cmp (x, y);
|
||||
}
|
||||
|
||||
DPE_INLINE int
|
||||
dpe_cmp_ui (dpe_t x, unsigned long d)
|
||||
{
|
||||
dpe_t y;
|
||||
dpe_set_ui (y, d);
|
||||
return dpe_cmp (x, y);
|
||||
}
|
||||
|
||||
DPE_INLINE int
|
||||
dpe_cmp_si (dpe_t x, long d)
|
||||
{
|
||||
dpe_t y;
|
||||
dpe_set_si (y, d);
|
||||
return dpe_cmp (x, y);
|
||||
}
|
||||
|
||||
/* set x to integer nearest to y */
|
||||
DPE_INLINE void
|
||||
dpe_round (dpe_t x, dpe_t y)
|
||||
{
|
||||
if (DPE_EXP(y) < 0) /* |y| < 1/2 */
|
||||
dpe_set_ui (x, 0);
|
||||
else if (DPE_EXP(y) >= DPE_BITSIZE) /* y is an integer */
|
||||
dpe_set (x, y);
|
||||
else
|
||||
{
|
||||
DPE_DOUBLE d;
|
||||
d = DPE_LDEXP(DPE_MANT(y), DPE_EXP(y));
|
||||
dpe_set_d (x, DPE_ROUND(d));
|
||||
}
|
||||
}
|
||||
|
||||
/* set x to the fractional part of y, defined as y - trunc(y), thus the
|
||||
fractional part has absolute value in [0, 1), and same sign as y */
|
||||
DPE_INLINE void
|
||||
dpe_frac (dpe_t x, dpe_t y)
|
||||
{
|
||||
/* If |y| is smaller than 1, keep it */
|
||||
if (DPE_EXP(y) <= 0)
|
||||
dpe_set (x, y);
|
||||
else if (DPE_EXP(y) >= DPE_BITSIZE) /* y is an integer */
|
||||
dpe_set_ui (x, 0);
|
||||
else
|
||||
{
|
||||
DPE_DOUBLE d;
|
||||
d = DPE_LDEXP(DPE_MANT(y), DPE_EXP(y));
|
||||
dpe_set_d (x, d - DPE_TRUNC(d));
|
||||
}
|
||||
}
|
||||
|
||||
/* set x to largest integer <= y */
|
||||
DPE_INLINE void
|
||||
dpe_floor (dpe_t x, dpe_t y)
|
||||
{
|
||||
if (DPE_EXP(y) <= 0) /* |y| < 1 */
|
||||
{
|
||||
if (DPE_SIGN(y) >= 0) /* 0 <= y < 1 */
|
||||
dpe_set_ui (x, 0);
|
||||
else /* -1 < y < 0 */
|
||||
dpe_set_si (x, -1);
|
||||
}
|
||||
else if (DPE_EXP(y) >= DPE_BITSIZE) /* y is an integer */
|
||||
dpe_set (x, y);
|
||||
else
|
||||
{
|
||||
DPE_DOUBLE d;
|
||||
d = DPE_LDEXP(DPE_MANT(y), DPE_EXP(y));
|
||||
dpe_set_d (x, DPE_FLOOR(d));
|
||||
}
|
||||
}
|
||||
|
||||
/* set x to smallest integer >= y */
|
||||
DPE_INLINE void
|
||||
dpe_ceil (dpe_t x, dpe_t y)
|
||||
{
|
||||
if (DPE_EXP(y) <= 0) /* |y| < 1 */
|
||||
{
|
||||
if (DPE_SIGN(y) > 0) /* 0 < y < 1 */
|
||||
dpe_set_ui (x, 1);
|
||||
else /* -1 < y <= 0 */
|
||||
dpe_set_si (x, 0);
|
||||
}
|
||||
else if (DPE_EXP(y) >= DPE_BITSIZE) /* y is an integer */
|
||||
dpe_set (x, y);
|
||||
else
|
||||
{
|
||||
DPE_DOUBLE d;
|
||||
d = DPE_LDEXP(DPE_MANT(y), DPE_EXP(y));
|
||||
dpe_set_d (x, DPE_CEIL(d));
|
||||
}
|
||||
}
|
||||
|
||||
DPE_INLINE void
|
||||
dpe_swap (dpe_t x, dpe_t y)
|
||||
{
|
||||
DPE_EXP_T i = DPE_EXP (x);
|
||||
DPE_DOUBLE d = DPE_MANT (x);
|
||||
DPE_EXP (x) = DPE_EXP (y);
|
||||
DPE_MANT (x) = DPE_MANT (y);
|
||||
DPE_EXP (y) = i;
|
||||
DPE_MANT (y) = d;
|
||||
}
|
||||
|
||||
#endif /* __DPE */
|
||||
@@ -0,0 +1,94 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Sina Schaeffler
|
||||
*
|
||||
* @brief Declarations for functions internal to the HNF computation and its tests
|
||||
*/
|
||||
|
||||
#ifndef QUAT_HNF_HELPERS_H
|
||||
#define QUAT_HNF_HELPERS_H
|
||||
|
||||
#include <quaternion.h>
|
||||
|
||||
/** @internal
|
||||
* @ingroup quat_helpers
|
||||
* @defgroup quat_hnf_helpers Internal functions for the HNF computation and tests
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @ingroup quat_hnf_helpers
|
||||
* @defgroup quat_hnf_helpers_ibz Internal renamed GMP functions for the HNF computation
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief GCD and Bézout coefficients u, v such that ua + bv = gcd
|
||||
*
|
||||
* @param gcd Output: Set to the gcd of a and b
|
||||
* @param u Output: integer such that ua+bv=gcd
|
||||
* @param v Output: Integer such that ua+bv=gcd
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
void ibz_xgcd(ibz_t *gcd,
|
||||
ibz_t *u,
|
||||
ibz_t *v,
|
||||
const ibz_t *a,
|
||||
const ibz_t *b); // integers, dim4, test/integers, test/dim4
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @ingroup quat_hnf_helpers
|
||||
* @defgroup quat_hnf_integer_helpers Integer functions internal to the HNF computation and tests
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief x mod mod, with x in [1,mod]
|
||||
*
|
||||
* @param res Output: res = x [mod] and 0<res<mod+1
|
||||
* @param x
|
||||
* @param mod integer > 0
|
||||
*/
|
||||
void ibz_mod_not_zero(ibz_t *res, const ibz_t *x, const ibz_t *mod);
|
||||
|
||||
/** @brief x mod mod, with x in ]-mod/2,mod/2]
|
||||
*
|
||||
* Centered and rather positive then negative.
|
||||
*
|
||||
* @param remainder Output: remainder = x [mod] and -mod/2<remainder<=mod/2
|
||||
* @param a
|
||||
* @param mod integer > 0
|
||||
*/
|
||||
void ibz_centered_mod(ibz_t *remainder, const ibz_t *a, const ibz_t *mod);
|
||||
|
||||
/** @brief if c then x else y
|
||||
*
|
||||
* @param res Output: if c, res = x, else res = y
|
||||
* @param x
|
||||
* @param y
|
||||
* @param c condition: must be 0 or 1
|
||||
*/
|
||||
void ibz_conditional_assign(ibz_t *res, const ibz_t *x, const ibz_t *y, int c);
|
||||
|
||||
/** @brief d = gcd(x,y)>0 and d = ux+vy and u!= 0 and d>0 and u, v of small absolute value, u not 0
|
||||
*
|
||||
* More precisely:
|
||||
* If x and y are both non 0, -|xy|/d<vy<=0<ux<=|xy|/d.
|
||||
* If x=0 and y not 0, then u=1 and v=y/d
|
||||
* If x not 0 and y=0, then u=x/d and v=0
|
||||
* If y=0 and x=0, d=1, u=1 and v=0
|
||||
*
|
||||
* @param d Output: gcd of x and y
|
||||
* @param u Output: coefficient of x
|
||||
* @param v Output: coefficient of y
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
void ibz_xgcd_with_u_not_0(ibz_t *d, ibz_t *u, ibz_t *v, const ibz_t *x, const ibz_t *y);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
/** @}
|
||||
*/
|
||||
#endif
|
||||
@@ -0,0 +1,123 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Sina Schaeffler
|
||||
*
|
||||
* @brief Declarations for big integer functions only used in quaternion functions
|
||||
*/
|
||||
|
||||
#ifndef INTBIG_INTERNAL_H
|
||||
#define INTBIG_INTERNAL_H
|
||||
|
||||
#include "intbig.h"
|
||||
|
||||
/** @internal
|
||||
* @ingroup quat_helpers
|
||||
* @defgroup ibz_helper Internal integer functions (gmp-based)
|
||||
* @{
|
||||
*/
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
/** @brief Euclidean division of a by b
|
||||
*
|
||||
* Computes quotient, remainder so that remainder+quotient*b = a where 0<=|remainder|<|b|
|
||||
* The quotient is rounded towards minus infinity.
|
||||
*/
|
||||
void ibz_div_floor(ibz_t *q, ibz_t *r, const ibz_t *n, const ibz_t *d);
|
||||
|
||||
/** @brief generate random value in [a, b]
|
||||
* assumed that a >= 0, b >= 0 and a < b
|
||||
* @returns 1 on success, 0 on failiure
|
||||
*/
|
||||
int ibz_rand_interval_i(ibz_t *rand, int32_t a, int32_t b);
|
||||
|
||||
/** @brief generate random value in [-2^m, 2^m]
|
||||
* assumed that m > 0 and bitlength of m < 32 bit
|
||||
* @returns 1 on success, 0 on failiure
|
||||
*/
|
||||
int ibz_rand_interval_bits(ibz_t *rand, uint32_t m);
|
||||
|
||||
/** @brief set str to a string containing the representation of i in base
|
||||
*
|
||||
* Base should be 10 or 16
|
||||
*
|
||||
* str should be an array of length enough to store the representation of in
|
||||
* in base, which can be obtained by ibz_sizeinbase(i, base) + 2, where the 2
|
||||
* is for the sign and the null terminator
|
||||
*
|
||||
* Case for base 16 does not matter
|
||||
*
|
||||
* @returns 1 if the integer could be converted to a string, 0 otherwise
|
||||
*/
|
||||
int ibz_convert_to_str(const ibz_t *i, char *str, int base);
|
||||
|
||||
/** @brief print num in base to stdout
|
||||
*
|
||||
* Base should be 10 or 16
|
||||
*/
|
||||
void ibz_print(const ibz_t *num, int base);
|
||||
|
||||
/** @brief set i to integer contained in string when read as number in base
|
||||
*
|
||||
* Base should be 10 or 16, and the number should be written without ponctuation or whitespaces
|
||||
*
|
||||
* Case for base 16 does not matter
|
||||
*
|
||||
* @returns 1 if the string could be converted to an integer, 0 otherwise
|
||||
*/
|
||||
int ibz_set_from_str(ibz_t *i, const char *str, int base);
|
||||
|
||||
/**
|
||||
* @brief Probabilistic primality test
|
||||
*
|
||||
* @param n The number to test
|
||||
* @param reps Number of Miller-Rabin repetitions. The more, the slower and the less likely are
|
||||
* false positives
|
||||
* @return 1 if probably prime, 0 if certainly not prime, 2 if certainly prime
|
||||
*
|
||||
* Using GMP's implementation:
|
||||
*
|
||||
* From GMP's documentation: "This function performs some trial divisions, a Baillie-PSW probable
|
||||
* prime test, then reps-24 Miller-Rabin probabilistic primality tests."
|
||||
*/
|
||||
int ibz_probab_prime(const ibz_t *n, int reps);
|
||||
|
||||
/**
|
||||
* @brief Square root modulo a prime
|
||||
*
|
||||
* @returns 1 if square root of a mod p exists and was computed, 0 otherwise
|
||||
* @param sqrt Output: Set to a square root of a mod p if any exist
|
||||
* @param a number of which a square root mod p is searched
|
||||
* @param p assumed prime
|
||||
*/
|
||||
int ibz_sqrt_mod_p(ibz_t *sqrt, const ibz_t *a, const ibz_t *p);
|
||||
|
||||
/**
|
||||
* @brief Integer square root of a perfect square
|
||||
*
|
||||
* @returns 1 if an integer square root of a exists and was computed, 0 otherwise
|
||||
* @param sqrt Output: Set to a integer square root of a if any exist
|
||||
* @param a number of which an integer square root is searched
|
||||
*/
|
||||
int ibz_sqrt(ibz_t *sqrt, const ibz_t *a);
|
||||
|
||||
/**
|
||||
* @brief Legendre symbol of a mod p
|
||||
*
|
||||
* @returns Legendre symbol of a mod p
|
||||
* @param a
|
||||
* @param p assumed prime
|
||||
*
|
||||
* Uses GMP's implementation
|
||||
*
|
||||
* If output is 1, a is a square mod p, if -1, not. If 0, it is divisible by p
|
||||
*/
|
||||
int ibz_legendre(const ibz_t *a, const ibz_t *p);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
// end of ibz_all
|
||||
/** @}
|
||||
*/
|
||||
#endif
|
||||
@@ -0,0 +1,812 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Sina Schaeffler
|
||||
*
|
||||
* @brief Declarations for helper functions for quaternion algebra implementation
|
||||
*/
|
||||
|
||||
#ifndef QUAT_HELPER_H
|
||||
#define QUAT_HELPER_H
|
||||
|
||||
#include <quaternion.h>
|
||||
#include <assert.h>
|
||||
#include "intbig_internal.h"
|
||||
|
||||
/** @internal
|
||||
* @ingroup quat_quat
|
||||
* @defgroup quat_helpers Quaternion module internal functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_alg_helpers Helper functions for the alg library
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @brief helper function for initializing small quaternion algebras.
|
||||
*/
|
||||
void quat_alg_init_set_ui(quat_alg_t *alg,
|
||||
unsigned int p); // test/lattice, test/ideal, test/algebra
|
||||
|
||||
/** @brief a*b
|
||||
*
|
||||
* Multiply two coordinate vectors as elements of the algebra in basis (1,i,j,ij) with i^2 = -1, j^2
|
||||
* = -p
|
||||
*
|
||||
* @param res Output: Will contain product
|
||||
* @param a
|
||||
* @param b
|
||||
* @param alg The quaternion algebra
|
||||
*/
|
||||
void quat_alg_coord_mul(ibz_vec_4_t *res, const ibz_vec_4_t *a, const ibz_vec_4_t *b, const quat_alg_t *alg);
|
||||
|
||||
/** @brief a=b
|
||||
*
|
||||
* Test if a and b represent the same quaternion algebra element
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
* @returns 1 if a=b, 0 otherwise
|
||||
*/
|
||||
int quat_alg_elem_equal(const quat_alg_elem_t *a, const quat_alg_elem_t *b);
|
||||
|
||||
/** @brief Test if x is 0
|
||||
*
|
||||
* @returns 1 if x=0, 0 otherwise
|
||||
*
|
||||
* x is 0 iff all coordinates in x->coord are 0
|
||||
*/
|
||||
int quat_alg_elem_is_zero(const quat_alg_elem_t *x);
|
||||
|
||||
/** @brief Compute same denominator form of two quaternion algebra elements
|
||||
*
|
||||
* res_a=a and res_b=b (representing the same element) and res_a.denom = res_b.denom
|
||||
*
|
||||
* @param res_a
|
||||
* @param res_b
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
void quat_alg_equal_denom(quat_alg_elem_t *res_a,
|
||||
quat_alg_elem_t *res_b,
|
||||
const quat_alg_elem_t *a,
|
||||
const quat_alg_elem_t *b);
|
||||
|
||||
/** @brief Copies the given values into an algebra element, without normalizing it
|
||||
*
|
||||
* @param elem Output: algebra element of coordinates [coord0,coord1,coord2,coord3] and denominator
|
||||
* denom
|
||||
* @param denom Denominator, must be non zero
|
||||
* @param coord0 Coordinate on 1 (0th vector of standard algebra basis)
|
||||
* @param coord1 Coordinate on i (1st vector of standard algebra basis)
|
||||
* @param coord2 Coordinate on j (2nd vector of standard algebra basis)
|
||||
* @param coord3 Coordinate on ij (3rd vector of standard algebra basis)
|
||||
*/
|
||||
void quat_alg_elem_copy_ibz(quat_alg_elem_t *elem,
|
||||
const ibz_t *denom,
|
||||
const ibz_t *coord0,
|
||||
const ibz_t *coord1,
|
||||
const ibz_t *coord2,
|
||||
const ibz_t *coord3);
|
||||
|
||||
/** @brief Sets an algebra element to the given integer values, without normalizing it
|
||||
*
|
||||
* @param elem Output: algebra element of coordinates [coord0,coord1,coord2,coord3] and denominator
|
||||
* denom
|
||||
* @param denom Denominator, must be non zero
|
||||
* @param coord0 Coordinate on 1 (0th vector of standard algebra basis)
|
||||
* @param coord1 Coordinate on i (1st vector of standard algebra basis)
|
||||
* @param coord2 Coordinate on j (2nd vector of standard algebra basis)
|
||||
* @param coord3 Coordinate on ij (3rd vector of standard algebra basis)
|
||||
*/
|
||||
void quat_alg_elem_set(quat_alg_elem_t *elem,
|
||||
int32_t denom,
|
||||
int32_t coord0,
|
||||
int32_t coord1,
|
||||
int32_t coord2,
|
||||
int32_t coord3);
|
||||
|
||||
/**
|
||||
* @brief Creates algebra element from scalar
|
||||
*
|
||||
* Resulting element has 1-coordinate equal to numerator/denominator
|
||||
*
|
||||
* @param elem Output: algebra element with numerator/denominator as first coordiante
|
||||
* (1-coordinate), 0 elsewhere (i,j,ij coordinates)
|
||||
* @param numerator
|
||||
* @param denominator Assumed non zero
|
||||
*/
|
||||
void quat_alg_scalar(quat_alg_elem_t *elem, const ibz_t *numerator, const ibz_t *denominator);
|
||||
|
||||
/** @brief a+b for algebra elements
|
||||
*
|
||||
* @param res Output
|
||||
* @param a Algebra element
|
||||
* @param b Algebra element
|
||||
*/
|
||||
void quat_alg_add(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b);
|
||||
|
||||
/** @brief a-b for algebra elements
|
||||
*
|
||||
* @param res Output
|
||||
* @param a Algebra element
|
||||
* @param b Algebra element
|
||||
*/
|
||||
void quat_alg_sub(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b);
|
||||
|
||||
/** @brief Multiplies algebra element by integer scalar, without normalizing it
|
||||
*
|
||||
* @param res Output
|
||||
* @param scalar Integer
|
||||
* @param elem Algebra element
|
||||
*/
|
||||
void quat_alg_elem_mul_by_scalar(quat_alg_elem_t *res, const ibz_t *scalar, const quat_alg_elem_t *elem);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_dim4_helpers Helper functions for functions for matrices or vectors in dimension 4
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_inv_helpers Helper functions for the integer matrix inversion function
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief a1a2+b1b2+c1c2
|
||||
*
|
||||
* @param coeff Output: The coefficien which was computed as a1a2+b1b2-c1c2
|
||||
* @param a1
|
||||
* @param a2
|
||||
* @param b1
|
||||
* @param b2
|
||||
* @param c1
|
||||
* @param c2
|
||||
*/
|
||||
void ibz_inv_dim4_make_coeff_pmp(ibz_t *coeff,
|
||||
const ibz_t *a1,
|
||||
const ibz_t *a2,
|
||||
const ibz_t *b1,
|
||||
const ibz_t *b2,
|
||||
const ibz_t *c1,
|
||||
const ibz_t *c2);
|
||||
|
||||
/** @brief -a1a2+b1b2-c1c2
|
||||
*
|
||||
* @param coeff Output: The coefficien which was computed as -a1a2+b1b2-c1c2
|
||||
* @param a1
|
||||
* @param a2
|
||||
* @param b1
|
||||
* @param b2
|
||||
* @param c1
|
||||
* @param c2
|
||||
*/
|
||||
void ibz_inv_dim4_make_coeff_mpm(ibz_t *coeff,
|
||||
const ibz_t *a1,
|
||||
const ibz_t *a2,
|
||||
const ibz_t *b1,
|
||||
const ibz_t *b2,
|
||||
const ibz_t *c1,
|
||||
const ibz_t *c2);
|
||||
|
||||
/** @brief Matrix determinant and a matrix inv such that inv/det is the inverse matrix of the input
|
||||
*
|
||||
* Implemented following the methof of 2x2 minors explained at Method from
|
||||
* https://www.geometrictools.com/Documentation/LaplaceExpansionTheorem.pdf (visited on 3rd of May
|
||||
* 2023, 16h15 CEST)
|
||||
*
|
||||
* @returns 1 if the determinant of mat is not 0 and an inverse was computed, 0 otherwise
|
||||
* @param inv Output: Will contain an integer matrix which, dividet by det, will yield the rational
|
||||
* inverse of the matrix if it exists, can be NULL
|
||||
* @param det Output: Will contain the determinant of the input matrix, can be NULL
|
||||
* @param mat Matrix of which the inverse will be computed
|
||||
*/
|
||||
int ibz_mat_4x4_inv_with_det_as_denom(ibz_mat_4x4_t *inv, ibz_t *det, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_dim4_lat_helpers Helper functions on vectors and matrices used mainly for lattices
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Copy all values from one vector to another
|
||||
*
|
||||
* @param new Output: is set to same values as vec
|
||||
* @param vec
|
||||
*/
|
||||
void ibz_vec_4_copy(ibz_vec_4_t *new, const ibz_vec_4_t *vec);
|
||||
|
||||
/** @brief set res to values coord0,coord1,coord2,coord3
|
||||
*
|
||||
* @param res Output: Will contain vector (coord0,coord1,coord2,coord3)
|
||||
* @param coord0
|
||||
* @param coord1
|
||||
* @param coord2
|
||||
* @param coord3
|
||||
*/
|
||||
void ibz_vec_4_copy_ibz(ibz_vec_4_t *res,
|
||||
const ibz_t *coord0,
|
||||
const ibz_t *coord1,
|
||||
const ibz_t *coord2,
|
||||
const ibz_t *coord3);
|
||||
|
||||
/** @brief Set a vector of 4 integers to given values
|
||||
*
|
||||
* @param vec Output: is set to given coordinates
|
||||
* @param coord0
|
||||
* @param coord1
|
||||
* @param coord2
|
||||
* @param coord3
|
||||
*/
|
||||
void ibz_vec_4_set(ibz_vec_4_t *vec, int32_t coord0, int32_t coord1, int32_t coord2, int32_t coord3);
|
||||
|
||||
/** @brief a+b
|
||||
*
|
||||
* Add two integer 4-vectors
|
||||
*
|
||||
* @param res Output: Will contain sum
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
void ibz_vec_4_add(ibz_vec_4_t *res, const ibz_vec_4_t *a, const ibz_vec_4_t *b);
|
||||
|
||||
/** @brief a-b
|
||||
*
|
||||
* Substract two integer 4-vectors
|
||||
*
|
||||
* @param res Output: Will contain difference
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
void ibz_vec_4_sub(ibz_vec_4_t *res, const ibz_vec_4_t *a, const ibz_vec_4_t *b);
|
||||
|
||||
/** @brief x=0
|
||||
*
|
||||
* Test if a vector x has only zero coordinates
|
||||
*
|
||||
* @returns 0 if x has at least one non-zero coordinates, 1 otherwise
|
||||
* @param x
|
||||
*/
|
||||
int ibz_vec_4_is_zero(const ibz_vec_4_t *x);
|
||||
|
||||
/** @brief Compute the linear combination lc = coeff_a vec_a + coeff_b vec_b
|
||||
*
|
||||
* @param lc Output: linear combination lc = coeff_a vec_a + coeff_b vec_b
|
||||
* @param coeff_a Scalar multiplied to vec_a
|
||||
* @param vec_a
|
||||
* @param coeff_b Scalar multiplied to vec_b
|
||||
* @param vec_b
|
||||
*/
|
||||
void ibz_vec_4_linear_combination(ibz_vec_4_t *lc,
|
||||
const ibz_t *coeff_a,
|
||||
const ibz_vec_4_t *vec_a,
|
||||
const ibz_t *coeff_b,
|
||||
const ibz_vec_4_t *vec_b);
|
||||
|
||||
/** @brief multiplies all values in vector by same scalar
|
||||
*
|
||||
* @param prod Output
|
||||
* @param scalar
|
||||
* @param vec
|
||||
*/
|
||||
void ibz_vec_4_scalar_mul(ibz_vec_4_t *prod, const ibz_t *scalar, const ibz_vec_4_t *vec);
|
||||
|
||||
/** @brief divides all values in vector by same scalar
|
||||
*
|
||||
* @returns 1 if scalar divided all values in mat, 0 otherwise (division is performed in both cases)
|
||||
* @param quot Output
|
||||
* @param scalar
|
||||
* @param vec
|
||||
*/
|
||||
int ibz_vec_4_scalar_div(ibz_vec_4_t *quot, const ibz_t *scalar, const ibz_vec_4_t *vec);
|
||||
|
||||
/** @brief Negation for vectors of 4 integers
|
||||
*
|
||||
* @param neg Output: is set to -vec
|
||||
* @param vec
|
||||
*/
|
||||
void ibz_vec_4_negate(ibz_vec_4_t *neg, const ibz_vec_4_t *vec);
|
||||
|
||||
/**
|
||||
* @brief content of a 4-vector of integers
|
||||
*
|
||||
* The content is the GCD of all entries.
|
||||
*
|
||||
* @param v A 4-vector of integers
|
||||
* @param content Output: the resulting gcd
|
||||
*/
|
||||
void ibz_vec_4_content(ibz_t *content, const ibz_vec_4_t *v);
|
||||
|
||||
/** @brief -mat for mat a 4x4 integer matrix
|
||||
*
|
||||
* @param neg Output: is set to -mat
|
||||
* @param mat Input matrix
|
||||
*/
|
||||
void ibz_mat_4x4_negate(ibz_mat_4x4_t *neg, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief Set all coefficients of a matrix to zero for 4x4 integer matrices
|
||||
*
|
||||
* @param zero
|
||||
*/
|
||||
void ibz_mat_4x4_zero(ibz_mat_4x4_t *zero);
|
||||
|
||||
/** @brief Set a matrix to the identity for 4x4 integer matrices
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
void ibz_mat_4x4_identity(ibz_mat_4x4_t *id);
|
||||
|
||||
/** @brief Test equality to identity for 4x4 integer matrices
|
||||
*
|
||||
* @returns 1 if mat is the identity matrix, 0 otherwise
|
||||
* @param mat
|
||||
*/
|
||||
int ibz_mat_4x4_is_identity(const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief Equality test for 4x4 integer matrices
|
||||
*
|
||||
* @returns 1 if equal, 0 otherwise
|
||||
* @param mat1
|
||||
* @param mat2
|
||||
*/
|
||||
int ibz_mat_4x4_equal(const ibz_mat_4x4_t *mat1, const ibz_mat_4x4_t *mat2);
|
||||
|
||||
/** @brief Copies all values from a 4x4 integer matrix to another one
|
||||
*
|
||||
* @param new Output: matrix which will have its entries set to mat's entries
|
||||
* @param mat Input matrix
|
||||
*/
|
||||
void ibz_mat_4x4_copy(ibz_mat_4x4_t *new, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief Matrix by integer multiplication
|
||||
*
|
||||
* @param prod Output
|
||||
* @param scalar
|
||||
* @param mat
|
||||
*/
|
||||
void ibz_mat_4x4_scalar_mul(ibz_mat_4x4_t *prod, const ibz_t *scalar, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief gcd of all values in matrix
|
||||
*
|
||||
* @param gcd Output
|
||||
* @param mat
|
||||
*/
|
||||
void ibz_mat_4x4_gcd(ibz_t *gcd, const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief Verifies whether the 4x4 input matrix is in Hermite Normal Form
|
||||
*
|
||||
* @returns 1 if mat is in HNF, 0 otherwise
|
||||
* @param mat Matrix to be tested
|
||||
*/
|
||||
int ibz_mat_4x4_is_hnf(const ibz_mat_4x4_t *mat);
|
||||
|
||||
/** @brief Hermite Normal Form of a matrix of 8 integer vectors, computed using a multiple of its
|
||||
* determinant as modulo
|
||||
*
|
||||
* Algorithm used is the one at number 2.4.8 in Henri Cohen's "A Course in Computational Algebraic
|
||||
* Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993
|
||||
*
|
||||
* @param hnf Output: Matrix in Hermite Normal Form generating the same lattice as generators
|
||||
* @param generators matrix whose colums generate the same lattice than the output
|
||||
* @param generator_number number of generators given
|
||||
* @param mod integer, must be a multiple of the volume of the lattice generated by the columns of
|
||||
* generators
|
||||
*/
|
||||
void ibz_mat_4xn_hnf_mod_core(ibz_mat_4x4_t *hnf,
|
||||
int generator_number,
|
||||
const ibz_vec_4_t *generators,
|
||||
const ibz_t *mod);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_dim2_helpers Helper functions for dimension 2
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Set vector coefficients to the given integers
|
||||
*
|
||||
* @param vec Output: Vector
|
||||
* @param a0
|
||||
* @param a1
|
||||
*/
|
||||
void ibz_vec_2_set(ibz_vec_2_t *vec, int a0, int a1); // test/dim2
|
||||
|
||||
/** @brief Set matrix coefficients to the given integers
|
||||
*
|
||||
* @param mat Output: Matrix
|
||||
* @param a00
|
||||
* @param a01
|
||||
* @param a10
|
||||
* @param a11
|
||||
*/
|
||||
void ibz_mat_2x2_set(ibz_mat_2x2_t *mat, int a00, int a01, int a10, int a11); // test/dim2
|
||||
|
||||
void ibz_mat_2x2_add(ibz_mat_2x2_t *sum, const ibz_mat_2x2_t *a,
|
||||
const ibz_mat_2x2_t *b); // unused
|
||||
|
||||
/** @brief Determinant of a 2x2 integer matrix given as 4 integers
|
||||
*
|
||||
* @param det Output: Determinant of the matrix
|
||||
* @param a11 matrix coefficient (upper left corner)
|
||||
* @param a12 matrix coefficient (upper right corner)
|
||||
* @param a21 matrix coefficient (lower left corner)
|
||||
* @param a22 matrix coefficient (lower right corner)
|
||||
*/
|
||||
void ibz_mat_2x2_det_from_ibz(ibz_t *det,
|
||||
const ibz_t *a11,
|
||||
const ibz_t *a12,
|
||||
const ibz_t *a21,
|
||||
const ibz_t *a22); // dim4
|
||||
|
||||
/**
|
||||
* @brief a*b for 2x2 integer matrices modulo m
|
||||
*
|
||||
* @param prod Output matrix
|
||||
* @param mat_a Input matrix
|
||||
* @param mat_b Input matrix
|
||||
* @param m Integer modulo
|
||||
*/
|
||||
void ibz_2x2_mul_mod(ibz_mat_2x2_t *prod,
|
||||
const ibz_mat_2x2_t *mat_a,
|
||||
const ibz_mat_2x2_t *mat_b,
|
||||
const ibz_t *m); // test/dim2
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_lattice_helper Helper functions for the lattice library (dimension 4)
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Modifies a lattice to put it in hermite normal form
|
||||
*
|
||||
* In-place modification of the lattice.
|
||||
*
|
||||
* @param lat input lattice
|
||||
*
|
||||
* On a correct lattice this function changes nothing (since it is already in HNF), but it can be
|
||||
* used to put a handmade one in correct form in order to use the other lattice functions.
|
||||
*/
|
||||
void quat_lattice_hnf(quat_lattice_t *lat); // lattice, test/lattice, test/algebra,
|
||||
|
||||
/**
|
||||
* @brief Lattice equality
|
||||
*
|
||||
* Lattice bases are assumed to be under HNF, but denominators are free.
|
||||
*
|
||||
* @returns 1 if both lattices are equal, 0 otherwise
|
||||
* @param lat1
|
||||
* @param lat2
|
||||
*/
|
||||
int quat_lattice_equal(const quat_lattice_t *lat1,
|
||||
const quat_lattice_t *lat2); // ideal, lattice, test/lattice, test/ideal
|
||||
|
||||
/**
|
||||
* @brief Lattice inclusion test
|
||||
*
|
||||
* Lattice bases are assumed to be under HNF, but denominators are free.
|
||||
*
|
||||
* @returns 1 if sublat is included in overlat, 0 otherwise
|
||||
* @param sublat Lattice whose inclusion in overlat will be testes
|
||||
* @param overlat
|
||||
*/
|
||||
int quat_lattice_inclusion(const quat_lattice_t *sublat,
|
||||
const quat_lattice_t *overlat); // test/lattice, test/ideal
|
||||
|
||||
/** @brief Divides basis and denominator of a lattice by their gcd
|
||||
*
|
||||
* @param reduced Output
|
||||
* @param lat Lattice
|
||||
*/
|
||||
void quat_lattice_reduce_denom(quat_lattice_t *reduced,
|
||||
const quat_lattice_t *lat); // lattice, ideal,
|
||||
|
||||
/** @brief a+b for lattices
|
||||
*
|
||||
* @param res Output
|
||||
* @param lat1 Lattice
|
||||
* @param lat2 Lattice
|
||||
*/
|
||||
void quat_lattice_add(quat_lattice_t *res,
|
||||
const quat_lattice_t *lat1,
|
||||
const quat_lattice_t *lat2); // ideal, lattice, test/lattice
|
||||
|
||||
/** @brief a*b for lattices
|
||||
*
|
||||
* @param res Output
|
||||
* @param lat1 Lattice
|
||||
* @param lat2 Lattice
|
||||
* @param alg The quaternion algebra
|
||||
*/
|
||||
void quat_lattice_mul(quat_lattice_t *res,
|
||||
const quat_lattice_t *lat1,
|
||||
const quat_lattice_t *lat2,
|
||||
const quat_alg_t *alg); // ideal, lattie, test/ideal, test/lattice
|
||||
|
||||
/**
|
||||
* @brief Computes the dual lattice of lat, without putting its basis in HNF
|
||||
*
|
||||
* This function returns a lattice not under HNF. For careful internal use only.
|
||||
*
|
||||
* Computation method described in https://cseweb.ucsd.edu/classes/sp14/cse206A-a/lec4.pdf consulted
|
||||
* on 19 of May 2023, 12h40 CEST
|
||||
*
|
||||
* @param dual Output: The dual lattice of lat. ATTENTION: is not under HNF. hnf computation must be
|
||||
* applied before using lattice functions on it
|
||||
* @param lat lattice, the dual of it will be computed
|
||||
*/
|
||||
void quat_lattice_dual_without_hnf(quat_lattice_t *dual,
|
||||
const quat_lattice_t *lat); // lattice, ideal
|
||||
|
||||
/**
|
||||
* @brief Multiply all columns of lat with coord (as algebra elements)
|
||||
*
|
||||
* The columns and coord are seen as algebra elements in basis 1,i,j,ij, i^2 = -1, j^2 = -p). Coord
|
||||
* is multiplied to the right of lat.
|
||||
*
|
||||
* The output matrix is not under HNF.
|
||||
*
|
||||
* @param prod Output: Matrix not under HND whose columns represent the algebra elements obtained as
|
||||
* L*coord for L column of lat.
|
||||
* @param lat Matrix whose columns are algebra elements in basis (1,i,j,ij)
|
||||
* @param coord Integer coordinate algebra element in basis (1,i,j,ij)
|
||||
* @param alg The quaternion algebra
|
||||
*/
|
||||
void quat_lattice_mat_alg_coord_mul_without_hnf(ibz_mat_4x4_t *prod,
|
||||
const ibz_mat_4x4_t *lat,
|
||||
const ibz_vec_4_t *coord,
|
||||
const quat_alg_t *alg); // lattice
|
||||
|
||||
/** @brief The index of sublat into overlat
|
||||
*
|
||||
* Assumes inputs are in HNF.
|
||||
*
|
||||
* @param index Output
|
||||
* @param sublat A lattice in HNF, must be sublattice of overlat
|
||||
* @param overlat A lattice in HNF, must be overlattice of sublat
|
||||
*/
|
||||
void quat_lattice_index(ibz_t *index, const quat_lattice_t *sublat,
|
||||
const quat_lattice_t *overlat); // ideal
|
||||
|
||||
/** @brief Compute the Gram matrix of the quaternion trace bilinear form
|
||||
*
|
||||
* Given a lattice of the quaternion algebra, computes the Gram matrix
|
||||
* of the bilinear form
|
||||
*
|
||||
* 〈a,b〉 := [lattice->denom^2] Tr(a·conj(b))
|
||||
*
|
||||
* multiplied by the square of the denominator of the lattice.
|
||||
*
|
||||
* This matrix always has integer entries.
|
||||
*
|
||||
* @param G Output: Gram matrix of the trace bilinear form on the lattice, multiplied by the square
|
||||
* of the denominator of the lattice
|
||||
* @param lattice A lattice
|
||||
* @param alg The quaternion algebra
|
||||
*/
|
||||
void quat_lattice_gram(ibz_mat_4x4_t *G, const quat_lattice_t *lattice, const quat_alg_t *alg);
|
||||
|
||||
/**
|
||||
* @brief Compute an integer parallelogram containing the ball of
|
||||
* given radius for the positive definite quadratic form defined by
|
||||
* the Gram matrix G.
|
||||
*
|
||||
* The computed parallelogram is defined by the vectors
|
||||
*
|
||||
* (x₁ x₂ x₃ x₄) · U
|
||||
*
|
||||
* with x_i ∈ [ -box[i], box[i] ].
|
||||
*
|
||||
* @param box Output: bounds of the parallelogram
|
||||
* @param U Output: Unimodular transformation defining the parallelogram
|
||||
* @param G Gram matrix of the quadratic form, must be full rank
|
||||
* @param radius Radius of the ball, must be non-negative
|
||||
* @returns 0 if the box only contains the origin, 1 otherwise
|
||||
*/
|
||||
int quat_lattice_bound_parallelogram(ibz_vec_4_t *box, ibz_mat_4x4_t *U, const ibz_mat_4x4_t *G, const ibz_t *radius);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @defgroup quat_lideal_helper Helper functions for ideals and orders
|
||||
* @{
|
||||
*/
|
||||
/** @brief Set norm of an ideal given its lattice and parent order
|
||||
*
|
||||
* @param lideal In/Output: Ideal which has lattice and parent_order correctly set, but not
|
||||
* necessarily the norm. Will have norm correctly set too.
|
||||
*/
|
||||
void quat_lideal_norm(quat_left_ideal_t *lideal); // ideal
|
||||
|
||||
/**
|
||||
* @brief Left principal ideal of order, generated by x
|
||||
*
|
||||
* @param lideal Output: left ideal
|
||||
* @param alg quaternion algebra
|
||||
* @param order maximal order of alg whose left ideal is searched
|
||||
* @param x generating element
|
||||
*
|
||||
* Creates the left ideal in 'order' generated by the element 'x'
|
||||
*/
|
||||
void quat_lideal_create_principal(quat_left_ideal_t *lideal,
|
||||
const quat_alg_elem_t *x,
|
||||
const quat_lattice_t *order,
|
||||
const quat_alg_t *alg); // ideal, test/ideal
|
||||
|
||||
/**
|
||||
* @brief Equality test for left ideals
|
||||
*
|
||||
* @returns 1 if both left ideals are equal, 0 otherwise
|
||||
* @param lideal1 left ideal
|
||||
* @param lideal2 left ideal
|
||||
* @param alg the quaternion algebra
|
||||
*/
|
||||
int quat_lideal_equals(const quat_left_ideal_t *lideal1,
|
||||
const quat_left_ideal_t *lideal2,
|
||||
const quat_alg_t *alg); // test/ideal
|
||||
|
||||
/**
|
||||
* @brief Sum of two left ideals
|
||||
*
|
||||
* @param sum Output: Left ideal which is the sum of the 2 inputs
|
||||
* @param lideal1 left ideal
|
||||
* @param lideal2 left ideal
|
||||
* @param alg the quaternion algebra
|
||||
*/
|
||||
void quat_lideal_add(quat_left_ideal_t *sum,
|
||||
const quat_left_ideal_t *lideal1,
|
||||
const quat_left_ideal_t *lideal2,
|
||||
const quat_alg_t *alg); // Not used outside
|
||||
|
||||
/**
|
||||
* @brief Left ideal product of left ideal I and element alpha
|
||||
*
|
||||
* @param product Output: lideal I*alpha, must have integer norm
|
||||
* @param lideal left ideal
|
||||
* @param alpha element multiplied to lideal to get the product ideal
|
||||
* @param alg the quaternion algebra
|
||||
*
|
||||
* I*alpha where I is a left-ideal and alpha an element of the algebra
|
||||
*
|
||||
* The resulting ideal must have an integer norm
|
||||
*
|
||||
*/
|
||||
void quat_lideal_mul(quat_left_ideal_t *product,
|
||||
const quat_left_ideal_t *lideal,
|
||||
const quat_alg_elem_t *alpha,
|
||||
const quat_alg_t *alg); // test/ideal
|
||||
|
||||
/** @brief Computes the inverse ideal (for a left ideal of a maximal order) without putting it under
|
||||
* HNF
|
||||
*
|
||||
* This function returns a lattice not under HNF. For careful internal use only
|
||||
*
|
||||
* Computes the inverse ideal for lideal as conjugate(lideal)/norm(lideal)
|
||||
*
|
||||
* @param inv Output: lattice which is lattice representation of the inverse ideal of lideal
|
||||
* ATTENTION: is not under HNF. hnf computation must be applied before using lattice functions on it
|
||||
* @param lideal Left ideal of a maximal order in alg
|
||||
* @param alg The quaternion algebra
|
||||
*/
|
||||
void quat_lideal_inverse_lattice_without_hnf(quat_lattice_t *inv,
|
||||
const quat_left_ideal_t *lideal,
|
||||
const quat_alg_t *alg); // ideal
|
||||
|
||||
/** @brief Computes the right transporter of two left ideals of the same maximal order
|
||||
*
|
||||
* Following the implementation of ideal isomorphisms in the code of LearningToSQI's sage
|
||||
* implementation of SQIsign. Computes the right transporter of (J:I) as inverse(I)J.
|
||||
*
|
||||
* @param trans Output: lattice which is right transporter from lideal1 to lideal2 (lideal2:lideal1)
|
||||
* @param lideal1 Left ideal of the same maximal order than lideal1 in alg
|
||||
* @param lideal2 Left ideal of the same maximal order than lideal1 in alg
|
||||
* @param alg The quaternion algebra
|
||||
*/
|
||||
void quat_lideal_right_transporter(quat_lattice_t *trans,
|
||||
const quat_left_ideal_t *lideal1,
|
||||
const quat_left_ideal_t *lideal2,
|
||||
const quat_alg_t *alg);
|
||||
|
||||
/**
|
||||
* @brief Right order of a left ideal
|
||||
*
|
||||
* @param order Output: right order of the given ideal
|
||||
* @param lideal left ideal
|
||||
* @param alg the quaternion algebra
|
||||
*/
|
||||
void quat_lideal_right_order(quat_lattice_t *order, const quat_left_ideal_t *lideal,
|
||||
const quat_alg_t *alg); // ideal
|
||||
|
||||
/**
|
||||
* @brief Gram matrix of the trace map of the ideal class
|
||||
*
|
||||
* Compute the Gram matrix of the bilinear form
|
||||
*
|
||||
* 〈a, b〉 := Tr(a·conj(b)) / norm(lideal)
|
||||
*
|
||||
* on the basis of the ideal. This matrix has integer entries and its
|
||||
* integer congruence class only depends on the ideal class.
|
||||
*
|
||||
* @param G Output: Gram matrix of the trace map
|
||||
* @param lideal left ideal
|
||||
* @param alg the quaternion algebra
|
||||
*/
|
||||
void quat_lideal_class_gram(ibz_mat_4x4_t *G, const quat_left_ideal_t *lideal, const quat_alg_t *alg);
|
||||
|
||||
/** @brief Test if order is maximal
|
||||
*
|
||||
* Checks if the discriminant of the order equals the prime p defining the quaternion algebra.
|
||||
*
|
||||
* It is not verified whether the order is really an order. The output 1 only means that if it is an
|
||||
* order, then it is maximal.
|
||||
*
|
||||
* @returns 1 if order is maximal (assuming it is an order), 0 otherwise
|
||||
* @param order An order of the quaternion algebra (assumes to be an order, this is not tested)
|
||||
* @param alg The quaternion algebra
|
||||
*/
|
||||
int quat_order_is_maximal(const quat_lattice_t *order,
|
||||
const quat_alg_t *alg); // ideal (only in asserts)
|
||||
|
||||
/** @brief Compute the discriminant of an order as sqrt(det(gram(reduced_norm)))
|
||||
*
|
||||
* @param disc: Output: The discriminant sqrt(det(gram(reduced_norm)))
|
||||
* @param order An order of the quaternion algebra
|
||||
* @param alg The quaternion algebra
|
||||
*/
|
||||
int quat_order_discriminant(ibz_t *disc, const quat_lattice_t *order,
|
||||
const quat_alg_t *alg); // ideal
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @ingroup quat_normeq
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Set lattice to O0
|
||||
*
|
||||
* @param O0 Lattice to be set to (1,i,(i+j)/2,(1+ij)/2)
|
||||
*/
|
||||
void quat_lattice_O0_set(quat_lattice_t *O0);
|
||||
|
||||
/** @brief Set p-extremal maximal order to O0
|
||||
*
|
||||
* @param O0 p-extremal order to be set to (1,i,(i+j)/2,(1+ij)/2)
|
||||
*/
|
||||
void quat_lattice_O0_set_extremal(quat_p_extremal_maximal_order_t *O0);
|
||||
|
||||
/**
|
||||
* @brief Create an element of a extremal maximal order from its coefficients
|
||||
*
|
||||
* @param elem Output: the quaternion element
|
||||
* @param order the order
|
||||
* @param coeffs the vector of 4 ibz coefficients
|
||||
* @param Bpoo quaternion algebra
|
||||
*
|
||||
* elem = x + z*y + z*u + t*z*v
|
||||
* where coeffs = [x,y,u,v] and t = order.t z = order.z
|
||||
*
|
||||
*/
|
||||
void quat_order_elem_create(quat_alg_elem_t *elem,
|
||||
const quat_p_extremal_maximal_order_t *order,
|
||||
const ibz_vec_4_t *coeffs,
|
||||
const quat_alg_t *Bpoo); // normeq, untested
|
||||
|
||||
/** @}
|
||||
*/
|
||||
/** @}
|
||||
*/
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,238 @@
|
||||
#ifndef LLL_INTERNALS_H
|
||||
#define LLL_INTERNALS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* @authors Sina Schaeffler
|
||||
*
|
||||
* @brief Declarations of functions only used for the LLL tets
|
||||
*/
|
||||
|
||||
#include <quaternion.h>
|
||||
|
||||
/** @internal
|
||||
* @ingroup quat_helpers
|
||||
* @defgroup lll_internal Functions only used for LLL or its tests
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @ingroup lll_internal
|
||||
* @defgroup lll_params Parameters used by the L2 implementation (floats) and its tests (ints)
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define DELTABAR 0.995
|
||||
#define DELTA_NUM 99
|
||||
#define DELTA_DENOM 100
|
||||
|
||||
#define ETABAR 0.505
|
||||
#define EPSILON_NUM 1
|
||||
#define EPSILON_DENOM 100
|
||||
|
||||
#define PREC 64
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @ingroup lll_internal
|
||||
* @defgroup ibq_t Types for rationals
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Type for fractions of integers
|
||||
*
|
||||
* @typedef ibq_t
|
||||
*
|
||||
* For fractions of integers of arbitrary size, used by intbig module, using gmp
|
||||
*/
|
||||
typedef ibz_t ibq_t[2];
|
||||
typedef ibq_t ibq_vec_4_t[4];
|
||||
typedef ibq_t ibq_mat_4x4_t[4][4];
|
||||
|
||||
/**@}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @ingroup lll_internal
|
||||
* @defgroup lll_ibq_c Constructors and Destructors and Printers
|
||||
* @{
|
||||
*/
|
||||
|
||||
void ibq_init(ibq_t *x);
|
||||
void ibq_finalize(ibq_t *x);
|
||||
|
||||
void ibq_mat_4x4_init(ibq_mat_4x4_t *mat);
|
||||
void ibq_mat_4x4_finalize(ibq_mat_4x4_t *mat);
|
||||
|
||||
void ibq_vec_4_init(ibq_vec_4_t *vec);
|
||||
void ibq_vec_4_finalize(ibq_vec_4_t *vec);
|
||||
|
||||
void ibq_mat_4x4_print(const ibq_mat_4x4_t *mat);
|
||||
void ibq_vec_4_print(const ibq_vec_4_t *vec);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @ingroup lll_internal
|
||||
* @defgroup lll_qa Basic fraction arithmetic
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief sum=a+b
|
||||
*/
|
||||
void ibq_add(ibq_t *sum, const ibq_t *a, const ibq_t *b);
|
||||
|
||||
/** @brief diff=a-b
|
||||
*/
|
||||
void ibq_sub(ibq_t *diff, const ibq_t *a, const ibq_t *b);
|
||||
|
||||
/** @brief neg=-x
|
||||
*/
|
||||
void ibq_neg(ibq_t *neg, const ibq_t *x);
|
||||
|
||||
/** @brief abs=|x|
|
||||
*/
|
||||
void ibq_abs(ibq_t *abs, const ibq_t *x);
|
||||
|
||||
/** @brief prod=a*b
|
||||
*/
|
||||
void ibq_mul(ibq_t *prod, const ibq_t *a, const ibq_t *b);
|
||||
|
||||
/** @brief inv=1/x
|
||||
*
|
||||
* @returns 0 if x is 0, 1 if inverse exists and was computed
|
||||
*/
|
||||
int ibq_inv(ibq_t *inv, const ibq_t *x);
|
||||
|
||||
/** @brief Compare a and b
|
||||
*
|
||||
* @returns a positive value if a > b, zero if a = b, and a negative value if a < b
|
||||
*/
|
||||
int ibq_cmp(const ibq_t *a, const ibq_t *b);
|
||||
|
||||
/** @brief Test if x is 0
|
||||
*
|
||||
* @returns 1 if x=0, 0 otherwise
|
||||
*/
|
||||
int ibq_is_zero(const ibq_t *x);
|
||||
|
||||
/** @brief Test if x is 1
|
||||
*
|
||||
* @returns 1 if x=1, 0 otherwise
|
||||
*/
|
||||
int ibq_is_one(const ibq_t *x);
|
||||
|
||||
/** @brief Set q to a/b if b not 0
|
||||
*
|
||||
* @returns 1 if b not 0 and q is set, 0 otherwise
|
||||
*/
|
||||
int ibq_set(ibq_t *q, const ibz_t *a, const ibz_t *b);
|
||||
|
||||
/** @brief Copy value into target
|
||||
*/
|
||||
void ibq_copy(ibq_t *target, const ibq_t *value);
|
||||
|
||||
/** @brief Checks if q is an integer
|
||||
*
|
||||
* @returns 1 if yes, 0 if not
|
||||
*/
|
||||
int ibq_is_ibz(const ibq_t *q);
|
||||
|
||||
/**
|
||||
* @brief Converts a fraction q to an integer y, if q is an integer.
|
||||
*
|
||||
* @returns 1 if z is an integer, 0 if not
|
||||
*/
|
||||
int ibq_to_ibz(ibz_t *z, const ibq_t *q);
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @ingroup lll_internal
|
||||
* @defgroup quat_lll_verify_helpers Helper functions for lll verification in dimension 4
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Set ibq to parameters delta and eta = 1/2 + epsilon using L2 constants
|
||||
*/
|
||||
void quat_lll_set_ibq_parameters(ibq_t *delta, ibq_t *eta);
|
||||
|
||||
/** @brief Set an ibq vector to 4 given integer coefficients
|
||||
*/
|
||||
void ibq_vec_4_copy_ibz(ibq_vec_4_t *vec,
|
||||
const ibz_t *coeff0,
|
||||
const ibz_t *coeff1,
|
||||
const ibz_t *coeff2,
|
||||
const ibz_t *coeff3); // dim4, test/dim4
|
||||
|
||||
/** @brief Bilinear form vec00*vec10+vec01*vec11+q*vec02*vec12+q*vec03*vec13 for ibz_q
|
||||
*/
|
||||
void quat_lll_bilinear(ibq_t *b, const ibq_vec_4_t *vec0, const ibq_vec_4_t *vec1,
|
||||
const ibz_t *q); // dim4, test/dim4
|
||||
|
||||
/** @brief Outputs the transposition of the orthogonalised matrix of mat (as fractions)
|
||||
*
|
||||
* For the bilinear form vec00*vec10+vec01*vec11+q*vec02*vec12+q*vec03*vec13
|
||||
*/
|
||||
void quat_lll_gram_schmidt_transposed_with_ibq(ibq_mat_4x4_t *orthogonalised_transposed,
|
||||
const ibz_mat_4x4_t *mat,
|
||||
const ibz_t *q); // dim4
|
||||
|
||||
/** @brief Verifies if mat is lll-reduced for parameter coeff and norm defined by q
|
||||
*
|
||||
* For the bilinear form vec00*vec10+vec01*vec11+q*vec02*vec12+q*vec03*vec13
|
||||
*/
|
||||
int quat_lll_verify(const ibz_mat_4x4_t *mat,
|
||||
const ibq_t *delta,
|
||||
const ibq_t *eta,
|
||||
const quat_alg_t *alg); // test/lattice, test/dim4
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @ingroup lll_internal
|
||||
* @defgroup lll_internal_gram Internal LLL function
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief In-place L2 reduction core function
|
||||
*
|
||||
* Given a lattice basis represented by the columns of a 4x4 matrix
|
||||
* and the Gram matrix of its bilinear form, L2-reduces the basis
|
||||
* in-place and updates the Gram matrix accordingly.
|
||||
*
|
||||
* Implements the L2 Algorithm of Nguyen-Stehlé, also known as fplll:
|
||||
* https://iacr.org/archive/eurocrypt2005/34940217/34940217.pdf
|
||||
*
|
||||
* Parameters are in lll/lll_internals.h
|
||||
*
|
||||
* @param G In/Output: Gram matrix of the lattice basis
|
||||
* @param basis In/Output: lattice basis
|
||||
*/
|
||||
void quat_lll_core(ibz_mat_4x4_t *G, ibz_mat_4x4_t *basis);
|
||||
|
||||
/**
|
||||
* @brief LLL reduction on 4-dimensional lattice
|
||||
*
|
||||
* Implements the L2 Algorithm of Nguyen-Stehlé, also known as fplll:
|
||||
* https://iacr.org/archive/eurocrypt2005/34940217/34940217.pdf
|
||||
*
|
||||
* Parameters are in lll/lll_internals.h
|
||||
*
|
||||
* @param red Output: LLL reduced basis
|
||||
* @param lattice In/Output: lattice with 4-dimensional basis
|
||||
* @param alg The quaternion algebra
|
||||
*/
|
||||
int quat_lattice_lll(ibz_mat_4x4_t *red, const quat_lattice_t *lattice, const quat_alg_t *alg);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
// end of lll_internal
|
||||
/** @}
|
||||
*/
|
||||
#endif
|
||||
@@ -0,0 +1,349 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Sina Schaeffler
|
||||
*
|
||||
* @brief Declarations of tests of quaternion algebra operations
|
||||
*/
|
||||
|
||||
#ifndef QUATERNION_TESTS_H
|
||||
#define QUATERNION_TESTS_H
|
||||
|
||||
#include <quaternion.h>
|
||||
#include <stdio.h>
|
||||
#include "internal.h"
|
||||
|
||||
/** @internal
|
||||
* @ingroup quat_helpers
|
||||
* @defgroup quat_tests Quaternion module test functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @internal
|
||||
* @ingroup quat_tests
|
||||
* @defgroup quat_test_inputs Quaternion module random test input generation
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Generates list of random ideals of a special extremal order
|
||||
*
|
||||
* @param ideals Output: Array of iterations left ideals of the given special extremal order and of
|
||||
* norms of size norm_bitsize
|
||||
* @param norm_bitsize Bitsize of the norms of the outut ideals
|
||||
* @param iterations Number of ideals to sample. Most be smaller than ideals is long
|
||||
* @param params quat_represent_integer_params_t parameters for the left order of the ideals to be
|
||||
* sampled.
|
||||
* @return 0 if success, 1 if failure
|
||||
*/
|
||||
int quat_test_input_random_ideal_generation(quat_left_ideal_t *ideals,
|
||||
int norm_bitsize,
|
||||
int iterations,
|
||||
const quat_represent_integer_params_t *params);
|
||||
|
||||
/**
|
||||
* @brief Generates list of random ideals of a special extremal order
|
||||
*
|
||||
* @param lattices Output: Array of iterations left ideals of the given special extremal order and
|
||||
* of norms of size norm_bitsize, given only by their lattices
|
||||
* @param norms Output: Array which will contain the norms of the sampled ideals, in the same order
|
||||
* as their lattices are. Can be NULL, in which case no norm is output. Otherwise, it must be an
|
||||
* array of length at least iterations
|
||||
* @param norm_bitsize Bitsize of the norms of the outut ideals
|
||||
* @param iterations Number of ideals to sample. Most be smaller than lattices is long
|
||||
* @param params quat_represent_integer_params_t parameters for the left order of the ideals to be
|
||||
* sampled.
|
||||
* @return 0 if success, 1 if failure
|
||||
*/
|
||||
int quat_test_input_random_ideal_lattice_generation(quat_lattice_t *lattices,
|
||||
ibz_t *norms,
|
||||
int norm_bitsize,
|
||||
int iterations,
|
||||
const quat_represent_integer_params_t *params);
|
||||
|
||||
/**
|
||||
* @brief Generates list of random lattices
|
||||
*
|
||||
* @param lattices Output: Array of iterations lattices
|
||||
* @param bitsize Bitsize of the coefficients of a random basis of the lattices
|
||||
* @param iterations Number of lattices to sample.Most be smaller than lattices is long
|
||||
* @param in_hnf If not 0, the lattices are put in HNF before being outputs. Their coefficients in
|
||||
* this basis might be larger than bitsize.
|
||||
* @return 0 if success, 1 if failure
|
||||
*/
|
||||
int quat_test_input_random_lattice_generation(quat_lattice_t *lattices, int bitsize, int iterations, int in_hnf);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @brief Test for integer functions
|
||||
*
|
||||
* void ibz_init(ibz_t *x);
|
||||
*
|
||||
* void ibz_finalize(ibz_t *x);
|
||||
*
|
||||
* void ibz_add(ibz_t *sum, const ibz_t *a, const ibz_t *b);
|
||||
*
|
||||
* void ibz_sub(ibz_t *diff, const ibz_t *a, const ibz_t *b);
|
||||
*
|
||||
* void ibz_mul(ibz_t *prod, const ibz_t *a, const ibz_t *b);
|
||||
*
|
||||
* void ibz_neg(ibz_t *neg, const ibz_t *a);
|
||||
*
|
||||
* void ibz_abs(ibz_t *abs, const ibz_t *a);
|
||||
*
|
||||
* void ibz_div(ibz_t *quotient, ibz_t *remainder, const ibz_t *a, const ibz_t *b);
|
||||
*
|
||||
* void ibz_div_2exp(ibz_t *quotient, const ibz_t *a, uint32_t exp);
|
||||
*
|
||||
* void ibz_mod(ibz_t *r, const ibz_t *a, const ibz_t *b);
|
||||
*
|
||||
* unsigned long int ibz_mod_ui(const mpz_t *n, unsigned long int d);
|
||||
*
|
||||
* int ibz_divides(const ibz_t *a, const ibz_t *b);
|
||||
*
|
||||
* void ibz_pow(ibz_t *pow, const ibz_t *x, uint32_t e);
|
||||
*
|
||||
* void ibz_pow_mod(ibz_t *pow, const ibz_t *x, const ibz_t *e, const ibz_t *m);
|
||||
*
|
||||
* int ibz_cmp(const ibz_t *a, const ibz_t *b);
|
||||
*
|
||||
* int ibz_is_zero(const ibz_t *x);
|
||||
*
|
||||
* int ibz_is_one(const ibz_t *x);
|
||||
*
|
||||
* int ibz_cmp_int32(const ibz_t *x, int32_t y);
|
||||
*
|
||||
* int ibz_is_even(const ibz_t *x);
|
||||
*
|
||||
* int ibz_is_odd(const ibz_t *x);
|
||||
*
|
||||
* void ibz_set(ibz_t *i, int32_t x);
|
||||
*
|
||||
* void ibz_copy(ibz_t *target, const ibz_t *value);
|
||||
*
|
||||
* void ibz_swap(ibz_t *a, ibz_t *b);
|
||||
*
|
||||
* void ibz_copy_digits(ibz_t *target, const digit_t *dig, int dig_len);
|
||||
*
|
||||
* void ibz_to_digits(digit_t *target, const ibz_t *ibz);
|
||||
*
|
||||
* int32_t ibz_get(const ibz_t *i);
|
||||
*
|
||||
* int ibz_rand_interval(ibz_t *rand, const ibz_t *a, const ibz_t *b);
|
||||
*
|
||||
* int ibz_rand_interval_minm_m(ibz_t *rand, int32_t m);
|
||||
*
|
||||
* int ibz_bitsize(const ibz_t *a);
|
||||
*
|
||||
* void ibz_gcd(ibz_t *gcd, const ibz_t *a, const ibz_t *b);
|
||||
*
|
||||
* int ibz_invmod(ibz_t *inv, const ibz_t *a, const ibz_t *mod);
|
||||
*
|
||||
* void ibz_sqrt_floor(ibz_t *sqrt, const ibz_t *a);
|
||||
*/
|
||||
int ibz_test_intbig(void);
|
||||
|
||||
/** @brief Test for implementations of GMP functions missing from the mini-GMP API
|
||||
*
|
||||
* int mpz_legendre(const mpz_t a, const mpz_t p);
|
||||
*
|
||||
* double mpz_get_d_2exp(signed long int *exp, const mpz_t op);
|
||||
*/
|
||||
int mini_gmp_test(void);
|
||||
|
||||
/** @brief Test initializers and finalizers for quaternion algebra types
|
||||
*
|
||||
* Test initializers and finalizers for the following types:
|
||||
*
|
||||
* quat_alg_t
|
||||
*
|
||||
* quat_alg_elem_t
|
||||
*
|
||||
* quat_alg_coord_t
|
||||
*
|
||||
* ibz_vec_2_t
|
||||
*
|
||||
* ibz_vec_4_t
|
||||
*
|
||||
* ibz_mat_2x2_t
|
||||
*
|
||||
* ibz_mat_4x4_t
|
||||
*
|
||||
* quat_lattice_t
|
||||
*
|
||||
* quat_lattice_t
|
||||
*
|
||||
* quat_left_ideal_t
|
||||
*/
|
||||
int quat_test_finit(void);
|
||||
|
||||
/** @brief Test integer, quadratic form and matrix functions for dimension 4 from the quaternion
|
||||
* module
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* void ibz_mat_4x4_eval(quat_alg_coord_t *res, const ibz_mat_4x4_t *mat, const quat_alg_coord_t
|
||||
* *vec);
|
||||
*
|
||||
* void quat_qf_eval(ibz_t *res, const ibz_mat_4x4_t *qf, const quat_alg_coord_t *coord);
|
||||
*
|
||||
* void ibz_vec_4_content(ibz_t *content, const quat_alg_coord_t *v);
|
||||
*/
|
||||
int quat_test_dim4(void);
|
||||
|
||||
/** @brief Test integer, lattice and matrix functions for dimension 2 from the quaternion module
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* void ibz_mat_2x2_copy(ibz_vec_2_t *copy, const ibz_mat_2x2_t *copied);
|
||||
*
|
||||
* void ibz_mat_2x2_eval(ibz_vec_2_t *res, const ibz_mat_2x2_t *mat, const ibz_vec_2_t *vec);
|
||||
*
|
||||
* void ibz_mat_4x4_eval_t(ibz_vec_4_t *res, const ibz_vec_4_t *vec, const ibz_mat_4x4_t *mat);
|
||||
*
|
||||
* void ibz_2x2_mul_mod(ibz_mat_2x2_t *prod, const ibz_mat_2x2_t *mat_a, const ibz_mat_2x2_t *mat_b,
|
||||
* const ibz_t *m);
|
||||
*
|
||||
* int ibz_mat_2x2_inv_mod(ibz_mat_2x2_t *inv, const ibz_mat_2x2_t *mat, const ibz_t *m);
|
||||
*/
|
||||
int quat_test_dim2(void);
|
||||
|
||||
/** @brief Test integer functions
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* int ibz_generate_random_prime(ibz_t *p, int is3mod4, int bitsize);
|
||||
*
|
||||
* int ibz_cornacchia_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p);
|
||||
*/
|
||||
int quat_test_integers(void);
|
||||
|
||||
/** @brief Test operations on quaternion algebra elements
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* void quat_alg_add(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b);
|
||||
*
|
||||
* void quat_alg_sub(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b);
|
||||
*
|
||||
* void quat_alg_mul(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b, const
|
||||
* quat_alg_t *alg);
|
||||
*
|
||||
* void quat_alg_norm(ibz_t *res_num, ibz_t *res_denom, const quat_alg_elem_t *a, const quat_alg_t
|
||||
* *alg);
|
||||
*
|
||||
* void quat_alg_scalar(quat_alg_elem_t *elem, const ibz_t *numerator, const ibz_t *denominator);
|
||||
*
|
||||
* void quat_alg_conj(quat_alg_elem_t *conj, const quat_alg_elem_t *x);
|
||||
*
|
||||
* void quat_alg_make_primitive(quat_alg_coord_t *primitive_x, ibz_t *content, const quat_alg_elem_t
|
||||
* *x, const quat_lattice_t *order, const quat_alg_t *alg){
|
||||
*
|
||||
* void quat_alg_normalize(quat_alg_elem_t *x);
|
||||
*
|
||||
* int quat_alg_elem_is_zero(const quat_alg_elem_t *x);
|
||||
*
|
||||
* int quat_alg_coord_is_zero(const quat_alg_coord_t *x);
|
||||
*
|
||||
* void quat_alg_elem_copy(quat_alg_elem_t *copy, const quat_alg_elem_t *copied);
|
||||
*/
|
||||
int quat_test_algebra(void);
|
||||
|
||||
/** @brief Test operations on lattices
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* void quat_lattice_add(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t
|
||||
* *lat2);
|
||||
*
|
||||
* void quat_lattice_intersect(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t
|
||||
* *lat2);
|
||||
*
|
||||
* void quat_lattice_conjugate_without_hnf(quat_lattice_t *conj, const quat_lattice_t *lat);
|
||||
*
|
||||
* void quat_lattice_alg_elem_mul(quat_lattice_t *prod, const quat_lattice_t *lat, const
|
||||
* quat_alg_elem_t *elem, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_lattice_mul(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t
|
||||
* *lat2, const quat_alg_t *alg);
|
||||
*
|
||||
* int quat_lattice_contains(quat_alg_coord_t *coord, const quat_lattice_t *lat, const
|
||||
* quat_alg_elem_t *x, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_lattice_hnf(quat_lattice_t *lat);
|
||||
*/
|
||||
int quat_test_lattice(void);
|
||||
|
||||
/** @brief Test for lattice reduction and functions based on it
|
||||
*
|
||||
* int quat_lideal_reduce_basis(ibz_mat_4x4_t *reduced, ibz_mat_4x4_t *gram, const quat_left_ideal_t
|
||||
* *lideal, const quat_alg_t *alg);
|
||||
*
|
||||
* int quat_lideal_lideal_mul_reduced(quat_left_ideal_t *prod, ibz_mat_4x4_t *gram, const
|
||||
* quat_left_ideal_t *lideal1,const quat_left_ideal_t *lideal2, const quat_alg_t *alg);
|
||||
*
|
||||
* int quat_lideal_prime_norm_reduced_equivalent(quat_left_ideal_t *lideal, const quat_alg_t *alg,
|
||||
* const int primality_num_iter, const int equiv_bound_coeff);
|
||||
*/
|
||||
int quat_test_lll(void);
|
||||
|
||||
/** @brief Test operations on left ideals and their creation
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* void quat_lideal_copy(quat_left_ideal_t *copy, const quat_left_ideal_t *copied)
|
||||
*
|
||||
* void quat_lideal_create_principal(quat_left_ideal_t *lideal, const quat_alg_elem_t *x, const
|
||||
* quat_lattice_t *order, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_lideal_create(quat_left_ideal_t *lideal, const quat_alg_elem_t *x, const
|
||||
* ibz_t *N, const quat_lattice_t *order, const quat_alg_t *alg);
|
||||
*
|
||||
* int quat_lideal_generator(quat_alg_elem_t *gen, const quat_left_ideal_t *lideal, const
|
||||
* quat_alg_t);
|
||||
*
|
||||
* void quat_lideal_add(quat_left_ideal_t *sum, const quat_left_ideal_t *I1, const quat_left_ideal_t
|
||||
* *I2, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_lideal_inter(quat_left_ideal_t *intersection, const quat_left_ideal_t *I1, const
|
||||
* quat_left_ideal_t *I2, const quat_alg_t *alg);
|
||||
*
|
||||
* int quat_lideal_equals(const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t
|
||||
* *alg);
|
||||
*
|
||||
*/
|
||||
int quat_test_lideal(void);
|
||||
|
||||
/** @brief Test operations on represent integer
|
||||
*
|
||||
* int quat_sampling_random_ideal_O0_given_norm(quat_left_ideal_t *lideal,const ibz_t *norm,int
|
||||
* is_prime,const quat_represent_integer_params_t *params,int prime_sampling_attempts);
|
||||
*
|
||||
* void quat_change_to_O0_basis(ibz_vec_4_t *vec, const quat_alg_elem_t *el);
|
||||
*
|
||||
* int quat_represent_integer(quat_alg_elem_t *gamma, const ibz_t *n_gamma, int non_diag, const
|
||||
* quat_represent_integer_params_t *params);
|
||||
*/
|
||||
int quat_test_normeq(void);
|
||||
|
||||
/** @brief Test functions for sampling lattice points of bounded norm
|
||||
*
|
||||
* int quat_lattice_sample_from_ball(ibz_vec_4_t *x, const quat_lattice_t *lattice, const quat_alg_t
|
||||
* *alg, const ibz_t *radius);
|
||||
*/
|
||||
int quat_test_lat_ball(void);
|
||||
|
||||
/** @brief Test for hnf core and verification
|
||||
*
|
||||
*/
|
||||
int quat_test_hnf(void);
|
||||
|
||||
/** @brief Test with randomization for complex functions where this is possible
|
||||
*
|
||||
*/
|
||||
int quat_test_with_randomization(void);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
#endif
|
||||
139
src/quaternion/ref/generic/lat_ball.c
Normal file
139
src/quaternion/ref/generic/lat_ball.c
Normal file
@@ -0,0 +1,139 @@
|
||||
#include <quaternion.h>
|
||||
#include <rng.h>
|
||||
#include <stdio.h>
|
||||
#include "internal.h"
|
||||
#include "lll_internals.h"
|
||||
|
||||
int
|
||||
quat_lattice_bound_parallelogram(ibz_vec_4_t *box, ibz_mat_4x4_t *U, const ibz_mat_4x4_t *G, const ibz_t *radius)
|
||||
{
|
||||
ibz_t denom, rem;
|
||||
ibz_init(&denom);
|
||||
ibz_init(&rem);
|
||||
ibz_mat_4x4_t dualG;
|
||||
ibz_mat_4x4_init(&dualG);
|
||||
|
||||
// Compute the Gram matrix of the dual lattice
|
||||
#ifndef NDEBUG
|
||||
int inv_check = ibz_mat_4x4_inv_with_det_as_denom(&dualG, &denom, G);
|
||||
assert(inv_check);
|
||||
#else
|
||||
(void)ibz_mat_4x4_inv_with_det_as_denom(&dualG, &denom, G);
|
||||
#endif
|
||||
// Initialize the dual lattice basis to the identity matrix
|
||||
ibz_mat_4x4_identity(U);
|
||||
// Reduce the dual lattice
|
||||
quat_lll_core(&dualG, U);
|
||||
|
||||
// Compute the parallelogram's bounds
|
||||
int trivial = 1;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_mul(&(*box)[i], &dualG[i][i], radius);
|
||||
ibz_div(&(*box)[i], &rem, &(*box)[i], &denom);
|
||||
ibz_sqrt_floor(&(*box)[i], &(*box)[i]);
|
||||
trivial &= ibz_is_zero(&(*box)[i]);
|
||||
}
|
||||
|
||||
// Compute the transpose transformation matrix
|
||||
#ifndef NDEBUG
|
||||
int inv = ibz_mat_4x4_inv_with_det_as_denom(U, &denom, U);
|
||||
#else
|
||||
(void)ibz_mat_4x4_inv_with_det_as_denom(U, &denom, U);
|
||||
#endif
|
||||
// U is unitary, det(U) = ± 1
|
||||
ibz_mat_4x4_scalar_mul(U, &denom, U);
|
||||
#ifndef NDEBUG
|
||||
assert(inv);
|
||||
ibz_abs(&denom, &denom);
|
||||
assert(ibz_is_one(&denom));
|
||||
#endif
|
||||
|
||||
ibz_mat_4x4_finalize(&dualG);
|
||||
ibz_finalize(&denom);
|
||||
ibz_finalize(&rem);
|
||||
return !trivial;
|
||||
}
|
||||
|
||||
int
|
||||
quat_lattice_sample_from_ball(quat_alg_elem_t *res,
|
||||
const quat_lattice_t *lattice,
|
||||
const quat_alg_t *alg,
|
||||
const ibz_t *radius)
|
||||
{
|
||||
assert(ibz_cmp(radius, &ibz_const_zero) > 0);
|
||||
|
||||
ibz_vec_4_t box;
|
||||
ibz_vec_4_init(&box);
|
||||
ibz_mat_4x4_t U, G;
|
||||
ibz_mat_4x4_init(&U);
|
||||
ibz_mat_4x4_init(&G);
|
||||
ibz_vec_4_t x;
|
||||
ibz_vec_4_init(&x);
|
||||
ibz_t rad, tmp;
|
||||
ibz_init(&rad);
|
||||
ibz_init(&tmp);
|
||||
|
||||
// Compute the Gram matrix of the lattice
|
||||
quat_lattice_gram(&G, lattice, alg);
|
||||
|
||||
// Correct ball radius by the denominator
|
||||
ibz_mul(&rad, radius, &lattice->denom);
|
||||
ibz_mul(&rad, &rad, &lattice->denom);
|
||||
// Correct by 2 (Gram matrix corresponds to twice the norm)
|
||||
ibz_mul(&rad, &rad, &ibz_const_two);
|
||||
|
||||
// Compute a bounding parallelogram for the ball, stop if it only
|
||||
// contains the origin
|
||||
int ok = quat_lattice_bound_parallelogram(&box, &U, &G, &rad);
|
||||
if (!ok)
|
||||
goto err;
|
||||
|
||||
// Rejection sampling from the parallelogram
|
||||
#ifndef NDEBUG
|
||||
int cnt = 0;
|
||||
#endif
|
||||
do {
|
||||
// Sample vector
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (ibz_is_zero(&box[i])) {
|
||||
ibz_copy(&x[i], &ibz_const_zero);
|
||||
} else {
|
||||
ibz_add(&tmp, &box[i], &box[i]);
|
||||
ok &= ibz_rand_interval(&x[i], &ibz_const_zero, &tmp);
|
||||
ibz_sub(&x[i], &x[i], &box[i]);
|
||||
if (!ok)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
// Map to parallelogram
|
||||
ibz_mat_4x4_eval_t(&x, &x, &U);
|
||||
// Evaluate quadratic form
|
||||
quat_qf_eval(&tmp, &G, &x);
|
||||
#ifndef NDEBUG
|
||||
cnt++;
|
||||
if (cnt % 100 == 0)
|
||||
printf("Lattice sampling rejected %d times", cnt - 1);
|
||||
#endif
|
||||
} while (ibz_is_zero(&tmp) || (ibz_cmp(&tmp, &rad) > 0));
|
||||
|
||||
// Evaluate linear combination
|
||||
ibz_mat_4x4_eval(&(res->coord), &(lattice->basis), &x);
|
||||
ibz_copy(&(res->denom), &(lattice->denom));
|
||||
quat_alg_normalize(res);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Check norm is smaller than radius
|
||||
quat_alg_norm(&tmp, &rad, res, alg);
|
||||
ibz_mul(&rad, &rad, radius);
|
||||
assert(ibz_cmp(&tmp, &rad) <= 0);
|
||||
#endif
|
||||
|
||||
err:
|
||||
ibz_finalize(&rad);
|
||||
ibz_finalize(&tmp);
|
||||
ibz_vec_4_finalize(&x);
|
||||
ibz_mat_4x4_finalize(&U);
|
||||
ibz_mat_4x4_finalize(&G);
|
||||
ibz_vec_4_finalize(&box);
|
||||
return ok;
|
||||
}
|
||||
@@ -2,468 +2,327 @@
|
||||
#include <rng.h>
|
||||
#include "internal.h"
|
||||
|
||||
//helper functions
|
||||
int quat_lattice_equal(const quat_lattice_t *lat1, const quat_lattice_t *lat2){
|
||||
int equal;
|
||||
ibz_t abs_denom1, abs_denom2;
|
||||
ibz_mat_4x4_t m1,m2;
|
||||
ibz_init(&abs_denom1);
|
||||
ibz_init(&abs_denom2);
|
||||
ibz_mat_4x4_init(&m1);
|
||||
ibz_mat_4x4_init(&m2);
|
||||
// test if both are in HNF as needed
|
||||
assert(ibz_mat_4x4_is_hnf(&(lat1->basis)));
|
||||
assert(ibz_mat_4x4_is_hnf(&(lat2->basis)));
|
||||
// get absolute values of denominators
|
||||
ibz_neg(&abs_denom1,&(lat1->denom));
|
||||
if(ibz_cmp(&abs_denom1,&(lat1->denom)) <0 ){
|
||||
ibz_neg(&abs_denom1,&abs_denom1);
|
||||
}
|
||||
ibz_neg(&abs_denom2,&(lat2->denom));
|
||||
if(ibz_cmp(&abs_denom2,&(lat2->denom)) <0 ){
|
||||
ibz_neg(&abs_denom2,&abs_denom2);
|
||||
}
|
||||
// cross-multiply by denomiators to get both basis on same denominators
|
||||
ibz_mat_4x4_scalar_mul(&m1,&abs_denom2,&(lat1->basis));
|
||||
ibz_mat_4x4_scalar_mul(&m2,&abs_denom1,&(lat2->basis));
|
||||
// baoth are still HNF, so simply test for equality
|
||||
equal = ibz_mat_4x4_equal(&m1,&m2);
|
||||
ibz_finalize(&abs_denom1);
|
||||
ibz_finalize(&abs_denom2);
|
||||
ibz_mat_4x4_finalize(&m1);
|
||||
ibz_mat_4x4_finalize(&m2);
|
||||
return(equal);
|
||||
// helper functions
|
||||
int
|
||||
quat_lattice_equal(const quat_lattice_t *lat1, const quat_lattice_t *lat2)
|
||||
{
|
||||
int equal = 1;
|
||||
quat_lattice_t a, b;
|
||||
quat_lattice_init(&a);
|
||||
quat_lattice_init(&b);
|
||||
quat_lattice_reduce_denom(&a, lat1);
|
||||
quat_lattice_reduce_denom(&b, lat2);
|
||||
ibz_abs(&(a.denom), &(a.denom));
|
||||
ibz_abs(&(b.denom), &(b.denom));
|
||||
quat_lattice_hnf(&a);
|
||||
quat_lattice_hnf(&b);
|
||||
equal = equal && (ibz_cmp(&(a.denom), &(b.denom)) == 0);
|
||||
equal = equal && ibz_mat_4x4_equal(&(a.basis), &(b.basis));
|
||||
quat_lattice_finalize(&a);
|
||||
quat_lattice_finalize(&b);
|
||||
return (equal);
|
||||
}
|
||||
|
||||
void quat_lattice_reduce_denom(quat_lattice_t *reduced, const quat_lattice_t *lat){
|
||||
// sublattice test
|
||||
int
|
||||
quat_lattice_inclusion(const quat_lattice_t *sublat, const quat_lattice_t *overlat)
|
||||
{
|
||||
int res;
|
||||
quat_lattice_t sum;
|
||||
quat_lattice_init(&sum);
|
||||
quat_lattice_add(&sum, overlat, sublat);
|
||||
res = quat_lattice_equal(&sum, overlat);
|
||||
quat_lattice_finalize(&sum);
|
||||
return (res);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lattice_reduce_denom(quat_lattice_t *reduced, const quat_lattice_t *lat)
|
||||
{
|
||||
ibz_t gcd;
|
||||
ibz_init(&gcd);
|
||||
ibz_mat_4x4_gcd(&gcd,&(lat->basis));
|
||||
ibz_gcd(&gcd,&gcd,&(lat->denom));
|
||||
ibz_mat_4x4_scalar_div(&(reduced->basis),&gcd,&(lat->basis));
|
||||
ibz_div(&(reduced->denom),&gcd,&(lat->denom),&gcd);
|
||||
ibz_mat_4x4_gcd(&gcd, &(lat->basis));
|
||||
ibz_gcd(&gcd, &gcd, &(lat->denom));
|
||||
ibz_mat_4x4_scalar_div(&(reduced->basis), &gcd, &(lat->basis));
|
||||
ibz_div(&(reduced->denom), &gcd, &(lat->denom), &gcd);
|
||||
ibz_abs(&(reduced->denom), &(reduced->denom));
|
||||
ibz_finalize(&gcd);
|
||||
}
|
||||
|
||||
// This function returns a lattice not under HNF. For careful internal use only
|
||||
// method described in https://cseweb.ucsd.edu/classes/sp14/cse206A-a/lec4.pdf consulted on 19 of May 2023, 12h40 CEST
|
||||
void quat_lattice_dual_without_hnf(quat_lattice_t *dual, const quat_lattice_t *lat){
|
||||
void
|
||||
quat_lattice_conjugate_without_hnf(quat_lattice_t *conj, const quat_lattice_t *lat)
|
||||
{
|
||||
ibz_mat_4x4_copy(&(conj->basis), &(lat->basis));
|
||||
ibz_copy(&(conj->denom), &(lat->denom));
|
||||
|
||||
for (int row = 1; row < 4; ++row) {
|
||||
for (int col = 0; col < 4; ++col) {
|
||||
ibz_neg(&(conj->basis[row][col]), &(conj->basis[row][col]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method described in https://cseweb.ucsd.edu/classes/sp14/cse206A-a/lec4.pdf consulted on 19 of
|
||||
// May 2023, 12h40 CEST
|
||||
void
|
||||
quat_lattice_dual_without_hnf(quat_lattice_t *dual, const quat_lattice_t *lat)
|
||||
{
|
||||
ibz_mat_4x4_t inv;
|
||||
ibz_t det;
|
||||
ibz_init(&det);
|
||||
ibz_mat_4x4_init(&inv);
|
||||
ibz_mat_4x4_transpose(&inv,&(lat->basis));
|
||||
ibz_mat_4x4_inv_with_det_as_denom(&inv,&det,&inv);
|
||||
ibz_mat_4x4_inv_with_det_as_denom(&inv, &det, &(lat->basis));
|
||||
ibz_mat_4x4_transpose(&inv, &inv);
|
||||
// dual_denom = det/lat_denom
|
||||
ibz_mat_4x4_scalar_mul(&(dual->basis),&(lat->denom),&inv);
|
||||
ibz_copy(&(dual-> denom),&det);
|
||||
|
||||
ibz_mat_4x4_scalar_mul(&(dual->basis), &(lat->denom), &inv);
|
||||
ibz_copy(&(dual->denom), &det);
|
||||
|
||||
ibz_finalize(&det);
|
||||
ibz_mat_4x4_finalize(&inv);
|
||||
}
|
||||
|
||||
void quat_lattice_add(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2){
|
||||
ibz_mat_4x8_t hnf_input;
|
||||
void
|
||||
quat_lattice_add(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2)
|
||||
{
|
||||
ibz_vec_4_t generators[8];
|
||||
ibz_mat_4x4_t tmp;
|
||||
ibz_t det1, det2, detprod;
|
||||
ibz_init(&det1);
|
||||
ibz_init(&det2);
|
||||
ibz_init(&detprod);
|
||||
for (int i = 0; i < 8; i++)
|
||||
ibz_vec_4_init(&(generators[i]));
|
||||
ibz_mat_4x4_init(&tmp);
|
||||
ibz_mat_4x8_init(&hnf_input);
|
||||
ibz_mat_4x4_scalar_mul(&tmp,&(lat1->denom),&(lat2->basis));
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_copy(&(hnf_input[i][j]),&(tmp[i][j]));
|
||||
ibz_mat_4x4_scalar_mul(&tmp, &(lat1->denom), &(lat2->basis));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_copy(&(generators[j][i]), &(tmp[i][j]));
|
||||
}
|
||||
}
|
||||
ibz_mat_4x4_scalar_mul(&tmp,&(lat2->denom),&(lat1->basis));
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_copy(&(hnf_input[i][4+j]),&(tmp[i][j]));
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL, &det1, &tmp);
|
||||
ibz_mat_4x4_scalar_mul(&tmp, &(lat2->denom), &(lat1->basis));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_copy(&(generators[4 + j][i]), &(tmp[i][j]));
|
||||
}
|
||||
}
|
||||
ibz_mat_4x8_hnf_core(&(res->basis),&hnf_input);
|
||||
ibz_mul(&(res->denom),&(lat1->denom), &(lat2->denom));
|
||||
quat_lattice_reduce_denom(res,res);
|
||||
ibz_mat_4x8_finalize(&hnf_input);
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL, &det2, &tmp);
|
||||
assert(!ibz_is_zero(&det1));
|
||||
assert(!ibz_is_zero(&det2));
|
||||
ibz_gcd(&detprod, &det1, &det2);
|
||||
ibz_mat_4xn_hnf_mod_core(&(res->basis), 8, generators, &detprod);
|
||||
ibz_mul(&(res->denom), &(lat1->denom), &(lat2->denom));
|
||||
quat_lattice_reduce_denom(res, res);
|
||||
ibz_mat_4x4_finalize(&tmp);
|
||||
ibz_finalize(&det1);
|
||||
ibz_finalize(&det2);
|
||||
ibz_finalize(&detprod);
|
||||
for (int i = 0; i < 8; i++)
|
||||
ibz_vec_4_finalize(&(generators[i]));
|
||||
}
|
||||
|
||||
// method described in https://cseweb.ucsd.edu/classes/sp14/cse206A-a/lec4.pdf consulted on 19 of May 2023, 12h40 CEST
|
||||
void quat_lattice_intersect(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2){
|
||||
// method described in https://cseweb.ucsd.edu/classes/sp14/cse206A-a/lec4.pdf consulted on 19 of
|
||||
// May 2023, 12h40 CEST
|
||||
void
|
||||
quat_lattice_intersect(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2)
|
||||
{
|
||||
quat_lattice_t dual1, dual2, dual_res;
|
||||
quat_lattice_init(&dual1);
|
||||
quat_lattice_init(&dual2);
|
||||
quat_lattice_init(&dual_res);
|
||||
quat_lattice_dual_without_hnf(&dual1,lat1);
|
||||
|
||||
quat_lattice_dual_without_hnf(&dual2,lat2);
|
||||
quat_lattice_add(&dual_res,&dual1,&dual2);
|
||||
quat_lattice_dual_without_hnf(res,&dual_res);
|
||||
quat_lattice_hnf(res);
|
||||
quat_lattice_dual_without_hnf(&dual1, lat1);
|
||||
|
||||
quat_lattice_dual_without_hnf(&dual2, lat2);
|
||||
quat_lattice_add(&dual_res, &dual1, &dual2);
|
||||
quat_lattice_dual_without_hnf(res, &dual_res);
|
||||
quat_lattice_hnf(res); // could be removed if we do not expect HNF any more
|
||||
quat_lattice_finalize(&dual1);
|
||||
quat_lattice_finalize(&dual2);
|
||||
quat_lattice_finalize(&dual_res);
|
||||
}
|
||||
|
||||
void quat_lattice_mul(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2, const quat_alg_t *alg){
|
||||
ibz_t denom, d, r;
|
||||
ibz_mat_4x8_t hnf_input;
|
||||
ibz_mat_4x4_t tmp1,tmp2;
|
||||
quat_alg_elem_t elem1,elem2,elem_res;
|
||||
quat_lattice_t lat_res;
|
||||
ibz_init(&denom);
|
||||
ibz_init(&d);
|
||||
ibz_init(&r);
|
||||
quat_lattice_init(&lat_res);
|
||||
ibz_mat_4x4_init(&tmp1);
|
||||
ibz_mat_4x4_init(&tmp2);
|
||||
quat_alg_elem_init(&elem1);
|
||||
quat_alg_elem_init(&elem2);
|
||||
quat_alg_elem_init(&elem_res);
|
||||
ibz_mat_4x8_init(&hnf_input);
|
||||
ibz_mul(&denom,&(lat1->denom),&(lat2->denom));
|
||||
for(int k = 0; k < 2; k++){
|
||||
quat_alg_elem_copy_ibz(&elem1,&(lat1->denom),&(lat1->basis[0][k]),&(lat1->basis[1][k]),&(lat1->basis[2][k]),&(lat1->basis[3][k]));
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_copy(&(elem2.coord[j]),&(lat2->basis[i][j]));
|
||||
}
|
||||
quat_alg_elem_copy_ibz(&elem2,&(lat2->denom),&(lat2->basis[0][i]),&(lat2->basis[1][i]),&(lat2->basis[2][i]),&(lat2->basis[3][i]));
|
||||
quat_alg_mul(&elem_res,&elem1,&elem2,alg);
|
||||
//should check that denom is as expected (product of both), otherwise set it to that to avoid issues
|
||||
if(0!=ibz_cmp(&denom,&(elem_res.denom))){
|
||||
ibz_div(&d,&r,&denom,&(elem_res.denom));
|
||||
quat_alg_elem_mul_by_scalar(&elem_res,&d,&elem_res);
|
||||
}
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_copy(&(hnf_input[j][4*k+i]),&(elem_res.coord[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
ibz_mat_4x8_hnf_core(&tmp1,&hnf_input);
|
||||
|
||||
for(int k = 0; k < 2; k++){
|
||||
quat_alg_elem_copy_ibz(&elem1,&(lat1->denom),&(lat1->basis[0][2+k]),&(lat1->basis[1][2+k]),&(lat1->basis[2][2+k]),&(lat1->basis[3][2+k]));
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_copy(&(elem2.coord[j]),&(lat2->basis[i][j]));
|
||||
}
|
||||
quat_alg_elem_copy_ibz(&elem2,&(lat2->denom),&(lat2->basis[0][i]),&(lat2->basis[1][i]),&(lat2->basis[2][i]),&(lat2->basis[3][i]));
|
||||
quat_alg_mul(&elem_res,&elem1,&elem2,alg);
|
||||
//should check that denom is as expected (product of both), otherwise set it to that to avoid issues
|
||||
if(0!=ibz_cmp(&denom,&(elem_res.denom))){
|
||||
ibz_div(&d,&r,&denom,&(elem_res.denom));
|
||||
quat_alg_elem_mul_by_scalar(&elem_res,&d,&elem_res);
|
||||
}
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_copy(&(hnf_input[j][4*k+i]),&(elem_res.coord[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
ibz_mat_4x8_hnf_core(&tmp2,&hnf_input);
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_copy(&(hnf_input[i][j]),&(tmp1[i][j]));
|
||||
ibz_copy(&(hnf_input[i][4+j]),&(tmp2[i][j]));
|
||||
}
|
||||
}
|
||||
ibz_mat_4x8_hnf_core(&(res->basis),&hnf_input);
|
||||
|
||||
ibz_copy(&(res->denom),&denom);
|
||||
quat_lattice_reduce_denom(res,res);
|
||||
|
||||
ibz_mat_4x8_finalize(&hnf_input);
|
||||
ibz_mat_4x4_finalize(&tmp1);
|
||||
ibz_mat_4x4_finalize(&tmp2);
|
||||
quat_alg_elem_finalize(&elem1);
|
||||
quat_alg_elem_finalize(&elem2);
|
||||
quat_alg_elem_finalize(&elem_res);
|
||||
quat_lattice_finalize(&lat_res);
|
||||
ibz_finalize(&denom);
|
||||
ibz_finalize(&d);
|
||||
ibz_finalize(&r);
|
||||
}
|
||||
|
||||
// lattice assumed of full rank and under HNF, none of both is tested so far
|
||||
int quat_lattice_contains_without_alg(quat_alg_coord_t *coord, const quat_lattice_t *lat, const quat_alg_elem_t *x){
|
||||
int res = 1;
|
||||
ibz_vec_4_t work_coord, work_x, column;
|
||||
ibz_t r, prod, one;
|
||||
ibz_init(&r);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&one);
|
||||
ibz_vec_4_init(&work_coord);
|
||||
ibz_vec_4_init(&work_x);
|
||||
ibz_vec_4_init(&column);
|
||||
// test if rank 4 lattice under HNF
|
||||
assert(ibz_mat_4x4_is_hnf(&(lat->basis)));
|
||||
for(int i = 0; i < 4; i++){
|
||||
assert(!ibz_is_zero(&(lat->basis[i][i])));
|
||||
}
|
||||
ibz_set(&one,1);
|
||||
for(int i = 0; i < 4;i++){
|
||||
// put on same denominator, 1st part
|
||||
ibz_mul(&(work_x[i]), &(x->coord[i]),&(lat->denom));
|
||||
}
|
||||
for(int i = 0; i < 4;i++){
|
||||
if(res){
|
||||
// put on same denominator, 2nd part
|
||||
ibz_mul(&prod,&(x->denom), &(lat->basis[3-i][3-i]));
|
||||
ibz_div(&(work_coord[3-i]), &r,&(work_x[3-i]), &prod);
|
||||
if(ibz_is_zero(&r)){
|
||||
for (int j = 0; j < 4;j++){
|
||||
// put on same denominator here also
|
||||
ibz_mul(&(column[j]),&(lat->basis[j][3-i]),&(x->denom));
|
||||
}
|
||||
// negate quotient
|
||||
ibz_neg(&r,&(work_coord[3-i]));
|
||||
ibz_vec_4_linear_combination(&work_x, &one, &work_x, &r,&column);
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
//final test
|
||||
for(int i = 0; i < 4;i++){
|
||||
// now x should be 0 if it is in lattice
|
||||
res = res && ibz_is_zero(&(work_x[i]));
|
||||
}
|
||||
|
||||
//copy result
|
||||
if(res && (coord != NULL)){
|
||||
for(int i = 0; i < 4;i++){
|
||||
ibz_copy(&((*coord)[i]),&(work_coord[i]));
|
||||
}
|
||||
}
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&one);
|
||||
ibz_vec_4_finalize(&work_coord);
|
||||
ibz_vec_4_finalize(&work_x);
|
||||
ibz_vec_4_finalize(&column);
|
||||
return(res);
|
||||
}
|
||||
|
||||
// lattice assumed of full rank and under HNF, none of both is tested so far
|
||||
int quat_lattice_contains(quat_alg_coord_t *coord, const quat_lattice_t *lat, const quat_alg_elem_t *x, const quat_alg_t *alg){
|
||||
return(quat_lattice_contains_without_alg(coord,lat,x));
|
||||
}
|
||||
|
||||
void quat_lattice_index(ibz_t *index, const quat_lattice_t *sublat, const quat_lattice_t *overlat) {
|
||||
ibz_t tmp;
|
||||
ibz_init(&tmp);
|
||||
|
||||
// index = (overlat->denom)⁴
|
||||
ibz_mul(index, &overlat->denom, &overlat->denom);
|
||||
ibz_mul(index, index, index);
|
||||
// index = (overlat->denom)⁴ · det(sublat->basis)
|
||||
void
|
||||
quat_lattice_mat_alg_coord_mul_without_hnf(ibz_mat_4x4_t *prod,
|
||||
const ibz_mat_4x4_t *lat,
|
||||
const ibz_vec_4_t *coord,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
ibz_vec_4_t p, a;
|
||||
ibz_vec_4_init(&p);
|
||||
ibz_vec_4_init(&a);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_mul(index, index, &sublat->basis[i][i]);
|
||||
ibz_vec_4_copy_ibz(&a, &((*lat)[0][i]), &((*lat)[1][i]), &((*lat)[2][i]), &((*lat)[3][i]));
|
||||
quat_alg_coord_mul(&p, &a, coord, alg);
|
||||
ibz_copy(&((*prod)[0][i]), &(p[0]));
|
||||
ibz_copy(&((*prod)[1][i]), &(p[1]));
|
||||
ibz_copy(&((*prod)[2][i]), &(p[2]));
|
||||
ibz_copy(&((*prod)[3][i]), &(p[3]));
|
||||
}
|
||||
ibz_vec_4_finalize(&p);
|
||||
ibz_vec_4_finalize(&a);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lattice_alg_elem_mul(quat_lattice_t *prod,
|
||||
const quat_lattice_t *lat,
|
||||
const quat_alg_elem_t *elem,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
quat_lattice_mat_alg_coord_mul_without_hnf(&(prod->basis), &(lat->basis), &(elem->coord), alg);
|
||||
ibz_mul(&(prod->denom), &(lat->denom), &(elem->denom));
|
||||
quat_lattice_hnf(prod);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lattice_mul(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2, const quat_alg_t *alg)
|
||||
{
|
||||
ibz_vec_4_t elem1, elem2, elem_res;
|
||||
ibz_vec_4_t generators[16];
|
||||
ibz_mat_4x4_t detmat;
|
||||
ibz_t det;
|
||||
quat_lattice_t lat_res;
|
||||
ibz_init(&det);
|
||||
ibz_mat_4x4_init(&detmat);
|
||||
quat_lattice_init(&lat_res);
|
||||
ibz_vec_4_init(&elem1);
|
||||
ibz_vec_4_init(&elem2);
|
||||
ibz_vec_4_init(&elem_res);
|
||||
for (int i = 0; i < 16; i++)
|
||||
ibz_vec_4_init(&(generators[i]));
|
||||
for (int k = 0; k < 4; k++) {
|
||||
ibz_vec_4_copy_ibz(
|
||||
&elem1, &(lat1->basis[0][k]), &(lat1->basis[1][k]), &(lat1->basis[2][k]), &(lat1->basis[3][k]));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_vec_4_copy_ibz(
|
||||
&elem2, &(lat2->basis[0][i]), &(lat2->basis[1][i]), &(lat2->basis[2][i]), &(lat2->basis[3][i]));
|
||||
quat_alg_coord_mul(&elem_res, &elem1, &elem2, alg);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (k == 0)
|
||||
ibz_copy(&(detmat[i][j]), &(elem_res[j]));
|
||||
ibz_copy(&(generators[4 * k + i][j]), &(elem_res[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL, &det, &detmat);
|
||||
ibz_abs(&det, &det);
|
||||
ibz_mat_4xn_hnf_mod_core(&(res->basis), 16, generators, &det);
|
||||
ibz_mul(&(res->denom), &(lat1->denom), &(lat2->denom));
|
||||
quat_lattice_reduce_denom(res, res);
|
||||
ibz_vec_4_finalize(&elem1);
|
||||
ibz_vec_4_finalize(&elem2);
|
||||
ibz_vec_4_finalize(&elem_res);
|
||||
quat_lattice_finalize(&lat_res);
|
||||
ibz_finalize(&det);
|
||||
ibz_mat_4x4_finalize(&(detmat));
|
||||
for (int i = 0; i < 16; i++)
|
||||
ibz_vec_4_finalize(&(generators[i]));
|
||||
}
|
||||
|
||||
// lattice assumed of full rank
|
||||
int
|
||||
quat_lattice_contains(ibz_vec_4_t *coord, const quat_lattice_t *lat, const quat_alg_elem_t *x)
|
||||
{
|
||||
int divisible = 0;
|
||||
ibz_vec_4_t work_coord;
|
||||
ibz_mat_4x4_t inv;
|
||||
ibz_t det, prod;
|
||||
ibz_init(&prod);
|
||||
ibz_init(&det);
|
||||
ibz_vec_4_init(&work_coord);
|
||||
ibz_mat_4x4_init(&inv);
|
||||
ibz_mat_4x4_inv_with_det_as_denom(&inv, &det, &(lat->basis));
|
||||
assert(!ibz_is_zero(&det));
|
||||
ibz_mat_4x4_eval(&work_coord, &inv, &(x->coord));
|
||||
ibz_vec_4_scalar_mul(&(work_coord), &(lat->denom), &work_coord);
|
||||
ibz_mul(&prod, &(x->denom), &det);
|
||||
divisible = ibz_vec_4_scalar_div(&work_coord, &prod, &work_coord);
|
||||
// copy result
|
||||
if (divisible && (coord != NULL)) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_copy(&((*coord)[i]), &(work_coord[i]));
|
||||
}
|
||||
}
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&det);
|
||||
ibz_mat_4x4_finalize(&inv);
|
||||
ibz_vec_4_finalize(&work_coord);
|
||||
return (divisible);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lattice_index(ibz_t *index, const quat_lattice_t *sublat, const quat_lattice_t *overlat)
|
||||
{
|
||||
ibz_t tmp, det;
|
||||
ibz_init(&tmp);
|
||||
ibz_init(&det);
|
||||
|
||||
// det = det(sublat->basis)
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL, &det, &sublat->basis);
|
||||
// tmp = (overlat->denom)⁴
|
||||
ibz_mul(&tmp, &overlat->denom, &overlat->denom);
|
||||
ibz_mul(&tmp, &tmp, &tmp);
|
||||
// index = (overlat->denom)⁴ · det(sublat->basis)
|
||||
ibz_mul(index, &det, &tmp);
|
||||
// tmp = (sublat->denom)⁴
|
||||
ibz_mul(&tmp, &sublat->denom, &sublat->denom);
|
||||
ibz_mul(&tmp, &tmp, &tmp);
|
||||
// det = det(overlat->basis)
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL, &det, &overlat->basis);
|
||||
// tmp = (sublat->denom)⁴ · det(overlat->basis)
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_mul(&tmp, &tmp, &overlat->basis[i][i]);
|
||||
}
|
||||
ibz_mul(&tmp, &tmp, &det);
|
||||
// index = index / tmp
|
||||
ibz_div(index, &tmp, index, &tmp);
|
||||
assert(ibz_is_zero(&tmp));
|
||||
// index = |index|
|
||||
ibz_abs(index, index);
|
||||
|
||||
|
||||
ibz_finalize(&tmp);
|
||||
ibz_finalize(&det);
|
||||
}
|
||||
|
||||
void quat_lattice_hnf(quat_lattice_t *lat){
|
||||
ibz_mat_4x8_t hnf_input;
|
||||
ibz_mat_4x8_init(&hnf_input);
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_set(&(hnf_input[i][j]),0);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_copy(&(hnf_input[i][4+j]),&(lat->basis[i][j]));
|
||||
}
|
||||
}
|
||||
ibz_mat_4x8_hnf_core(&(lat->basis),&hnf_input);
|
||||
quat_lattice_reduce_denom(lat,lat);
|
||||
ibz_mat_4x8_finalize(&hnf_input);
|
||||
}
|
||||
|
||||
int quat_lattice_random_elem(quat_alg_elem_t *elem, const quat_lattice_t *lattice, unsigned char n) {
|
||||
assert(n <= 64);
|
||||
|
||||
// Set elem to 0
|
||||
for (int i = 0; i < 4; i++)
|
||||
ibz_set(&elem->coord[i], 0);
|
||||
ibz_set(&elem->denom, 1);
|
||||
|
||||
// Take random coefficients
|
||||
int64_t rand[4];
|
||||
int randret = randombytes((unsigned char*)rand, 4*sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 0;
|
||||
|
||||
// Make the linear combination
|
||||
quat_alg_elem_t tmp;
|
||||
quat_alg_elem_init(&tmp);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
rand[j] >>= (64-n);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_set(&tmp.coord[i], rand[j]);
|
||||
ibz_mul(&tmp.coord[i], &tmp.coord[i], &lattice->basis[i][j]);
|
||||
}
|
||||
quat_alg_add(elem, elem, &tmp);
|
||||
}
|
||||
quat_alg_elem_finalize(&tmp);
|
||||
|
||||
// Set the denominator
|
||||
ibz_copy(&elem->denom, &lattice->denom);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Right transporter **/
|
||||
|
||||
/** @brief to[to_row] = (-1)^neg · c · from[from_row]
|
||||
*
|
||||
* c may be NULL, in which case c = 1
|
||||
*/
|
||||
static inline void copy_row(ibz_mat_4x4_t to, int to_row, int neg, const ibz_t *c, const ibz_mat_4x4_t from, int from_row) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (c)
|
||||
ibz_mul(&to[to_row][j], c, &from[from_row][j]);
|
||||
else
|
||||
ibz_copy(&to[to_row][j], &from[from_row][j]);
|
||||
if (neg)
|
||||
ibz_neg(&to[to_row][j], &to[to_row][j]);
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief copy matrix into columns of cols
|
||||
*/
|
||||
static inline void mat_to_col_16x4(ibz_t (*cols)[16][4], int col, const ibz_mat_4x4_t *mat) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
ibz_copy(&((*cols)[j+4*i][col]), &((*mat)[i][j]));
|
||||
}
|
||||
|
||||
/** @brief take the gcd of content with all entries
|
||||
*/
|
||||
static inline void mat_16x4_content(ibz_t *content, const ibz_t (*mat)[16][4]){
|
||||
for(int i = 0; i < 16; i++)
|
||||
for(int j = 0; j < 4; j++)
|
||||
ibz_gcd(content, content, &((*mat)[i][j]));
|
||||
}
|
||||
|
||||
/** @brief take the gcd of content with all entries
|
||||
*/
|
||||
static inline void mat_16x4_mul_by_scalar(ibz_t (*prod)[16][4], const ibz_t (*mat)[16][4],const ibz_t *scalar){
|
||||
for(int i = 0; i < 16; i++)
|
||||
for(int j = 0; j < 4; j++)
|
||||
ibz_mul(&((*prod)[i][j]), scalar, &((*mat)[i][j]));
|
||||
}
|
||||
|
||||
/** @brief take the gcd of content with all entries
|
||||
*/
|
||||
static inline int mat_16x4_div_by_scalar(ibz_t (*quot)[16][4], const ibz_t (*mat)[16][4],const ibz_t *scalar){
|
||||
int ok = 1;
|
||||
ibz_t r;
|
||||
ibz_init(&r);
|
||||
for(int i = 0; i < 16; i++)
|
||||
for(int j = 0; j < 4; j++)
|
||||
ibz_div(&((*quot)[i][j]),&r,&((*mat)[i][j]),scalar);
|
||||
ok = ok && (ibz_is_zero(&r));
|
||||
ibz_finalize(&r);
|
||||
return(ok);
|
||||
}
|
||||
|
||||
void quat_lattice_right_transporter(quat_lattice_t *trans, const quat_lattice_t *lat1, const quat_lattice_t *lat2, const quat_alg_t *alg)
|
||||
void
|
||||
quat_lattice_hnf(quat_lattice_t *lat)
|
||||
{
|
||||
ibz_t det1, det2, tmp, thrash, content;
|
||||
ibz_mat_4x4_t lat2_inv, tmpmat;
|
||||
ibz_t work[16][4];
|
||||
ibz_init(&det1);
|
||||
ibz_init(&det2);
|
||||
ibz_init(&tmp);
|
||||
ibz_init(&thrash);
|
||||
ibz_init(&content);
|
||||
ibz_mat_4x4_init(&lat2_inv);
|
||||
ibz_mat_4x4_init(&tmpmat);
|
||||
ibz_mat_init(16,4,work);
|
||||
|
||||
// Compute the dual lattice Λ₂* of Λ₂ = num(lat2)
|
||||
// Could be optimized, given it's triangular
|
||||
// M₂ = Λ₂*/det₂
|
||||
int invertible = ibz_mat_4x4_inv_with_det_as_denom(&lat2_inv, &det2, &lat2->basis);
|
||||
assert(invertible);
|
||||
|
||||
// WARNING: hard-cording right multiplication table of "standard" basis
|
||||
// Prone to breakage if the basis changes
|
||||
//
|
||||
// M = d₂/(d₁ det₂) · table
|
||||
//
|
||||
// Λ₂* Id Λ₁
|
||||
ibz_mat_4x4_mul(&tmpmat, &lat2_inv, &lat1->basis);
|
||||
mat_to_col_16x4(&work, 0, &tmpmat);
|
||||
// Λ₂* [0 -1 0 0 ; 1 0 0 0 ; 0 0 0 1 ; 0 0 -1 0] Λ₁
|
||||
copy_row(tmpmat, 0, 1, NULL, lat1->basis, 1);
|
||||
copy_row(tmpmat, 1, 0, NULL, lat1->basis, 0);
|
||||
copy_row(tmpmat, 2, 0, NULL, lat1->basis, 3);
|
||||
copy_row(tmpmat, 3, 1, NULL, lat1->basis, 2);
|
||||
ibz_mat_4x4_mul(&tmpmat, &lat2_inv, &tmpmat);
|
||||
mat_to_col_16x4(&work, 1, &tmpmat);
|
||||
// Λ₂* [0 0 -p 0 ; 0 0 0 -p ; 1 0 0 0 ; 0 1 0 0] Λ₁
|
||||
copy_row(tmpmat, 0, 1, &alg->p, lat1->basis, 2);
|
||||
copy_row(tmpmat, 1, 1, &alg->p, lat1->basis, 3);
|
||||
copy_row(tmpmat, 2, 0, NULL, lat1->basis, 0);
|
||||
copy_row(tmpmat, 3, 0, NULL, lat1->basis, 1);
|
||||
ibz_mat_4x4_mul(&tmpmat, &lat2_inv, &tmpmat);
|
||||
mat_to_col_16x4(&work, 2, &tmpmat);
|
||||
// Λ₂*[0 0 0 -p ; 0 0 p 0 ; 0 -1 0 0 ; 1 0 0 0] Λ₁
|
||||
copy_row(tmpmat, 0, 1, &alg->p, lat1->basis, 3);
|
||||
copy_row(tmpmat, 1, 0, &alg->p, lat1->basis, 2);
|
||||
copy_row(tmpmat, 2, 1, NULL, lat1->basis, 1);
|
||||
copy_row(tmpmat, 3, 0, NULL, lat1->basis, 0);
|
||||
ibz_mat_4x4_mul(&tmpmat, &lat2_inv, &tmpmat);
|
||||
mat_to_col_16x4(&work, 3, &tmpmat);
|
||||
|
||||
ibz_mul(&det1, &lat1->basis[0][0], &lat1->basis[1][1]);
|
||||
ibz_mul(&tmp, &lat1->basis[2][2], &lat1->basis[3][3]);
|
||||
ibz_mul(&det1, &det1, &tmp);
|
||||
ibz_mul(&det1, &det1, &lat2->denom);
|
||||
ibz_gcd(&tmp, &det1, &lat1->denom);
|
||||
ibz_div(&det1, &thrash, &det1, &tmp);
|
||||
|
||||
{
|
||||
int ok = 1;
|
||||
mat_16x4_content(&content,&work);
|
||||
ok &= mat_16x4_div_by_scalar(&work,&work,&content);
|
||||
assert(ok);
|
||||
|
||||
ibz_mul(&content, &content, &lat2->denom);
|
||||
ibz_mul(&det2, &det2, &lat1->denom);
|
||||
ibz_gcd(&tmp, &det2, &content);
|
||||
ibz_div(&det2, &thrash, &det2, &tmp);
|
||||
ibz_div(&content, &thrash, &content, &tmp);
|
||||
mat_16x4_mul_by_scalar(&work,&work,&content);
|
||||
ibz_mul(&det2, &det2, &det1);
|
||||
|
||||
ibz_mat_right_ker_mod(16, 4, trans->basis, work, &det2);
|
||||
ibz_mat_4x4_hnf_mod(&trans->basis, &trans->basis, &det2);
|
||||
ibz_copy(&trans->denom, &det1);
|
||||
quat_lattice_reduce_denom(trans, trans);
|
||||
ibz_t mod;
|
||||
ibz_vec_4_t generators[4];
|
||||
ibz_init(&mod);
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL, &mod, &(lat->basis));
|
||||
ibz_abs(&mod, &mod);
|
||||
for (int i = 0; i < 4; i++)
|
||||
ibz_vec_4_init(&(generators[i]));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_copy(&(generators[j][i]), &(lat->basis[i][j]));
|
||||
}
|
||||
}
|
||||
|
||||
ibz_mat_finalize(16,4,work);
|
||||
ibz_finalize(&det1);
|
||||
ibz_finalize(&det2);
|
||||
ibz_finalize(&tmp);
|
||||
ibz_finalize(&thrash);
|
||||
ibz_finalize(&content);
|
||||
ibz_mat_4x4_finalize(&lat2_inv);
|
||||
ibz_mat_4x4_finalize(&tmpmat);
|
||||
ibz_mat_4xn_hnf_mod_core(&(lat->basis), 4, generators, &mod);
|
||||
quat_lattice_reduce_denom(lat, lat);
|
||||
ibz_finalize(&mod);
|
||||
for (int i = 0; i < 4; i++)
|
||||
ibz_vec_4_finalize(&(generators[i]));
|
||||
}
|
||||
|
||||
void
|
||||
quat_lattice_gram(ibz_mat_4x4_t *G, const quat_lattice_t *lattice, const quat_alg_t *alg)
|
||||
{
|
||||
ibz_t tmp;
|
||||
ibz_init(&tmp);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j <= i; j++) {
|
||||
ibz_set(&(*G)[i][j], 0);
|
||||
for (int k = 0; k < 4; k++) {
|
||||
ibz_mul(&tmp, &(lattice->basis)[k][i], &(lattice->basis)[k][j]);
|
||||
if (k >= 2)
|
||||
ibz_mul(&tmp, &tmp, &alg->p);
|
||||
ibz_add(&(*G)[i][j], &(*G)[i][j], &tmp);
|
||||
}
|
||||
ibz_mul(&(*G)[i][j], &(*G)[i][j], &ibz_const_two);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = i + 1; j < 4; j++) {
|
||||
ibz_copy(&(*G)[i][j], &(*G)[j][i]);
|
||||
}
|
||||
}
|
||||
ibz_finalize(&tmp);
|
||||
}
|
||||
|
||||
@@ -1,366 +0,0 @@
|
||||
#include <quaternion.h>
|
||||
#include "internal.h"
|
||||
|
||||
// RED(k,l) sub-algorithm
|
||||
static void RED(ibz_mat_4x4_t *basis, ibq_t (*u)[4][4], ibz_t (*H)[4][4], int k, int l) {
|
||||
ibq_t tmp, tmp2;
|
||||
ibz_t q, tibz, num, den, r;
|
||||
ibq_init(&tmp);
|
||||
ibq_init(&tmp2);
|
||||
ibz_init(&q);
|
||||
ibz_init(&tibz);
|
||||
ibz_init(&num);
|
||||
ibz_init(&den);
|
||||
ibz_init(&r);
|
||||
ibz_set(&num,1);
|
||||
ibz_set(&den,2);
|
||||
ibq_set(&tmp,&num,&den);
|
||||
ibz_set(&num,0);
|
||||
ibz_set(&den,0);
|
||||
|
||||
// if |u_{k,l}| <= 0.5, terminate
|
||||
ibq_abs(&tmp2, &((*u)[k][l]));
|
||||
if (ibq_cmp(&tmp2, &tmp) <= 0)
|
||||
goto end;
|
||||
|
||||
// q <- floor(0.5 + u_{k,l})
|
||||
ibq_add(&tmp, &tmp, &((*u)[k][l]));
|
||||
|
||||
ibq_num(&num, &tmp);
|
||||
ibq_denom(&den, &tmp);
|
||||
//FDIV was used, needs reeimplementation
|
||||
ibz_div_floor(&q,&r, &num, &den);
|
||||
//ibq_floor(tmp, tmp);
|
||||
//ibz_set_f(q, tmp);
|
||||
|
||||
// b_k = b_k - q*b_l
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibz_mul(&tibz, &q, &((*basis)[l][i]));
|
||||
ibz_sub(&((*basis)[k][i]), &((*basis)[k][i]), &tibz);
|
||||
}
|
||||
|
||||
// H_k = H_k - q*H_l
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibz_mul(&tibz, &q, &((*H)[l][i]));
|
||||
ibz_sub(&((*H)[k][i]), &((*H)[k][i]), &tibz);
|
||||
}
|
||||
|
||||
// u_{k,j} = u_{k,l}-q
|
||||
ibq_set(&tmp2, &q,&ibz_const_one);
|
||||
ibq_sub(&((*u)[k][l]), &((*u)[k][l]), &tmp2);
|
||||
|
||||
// forall_i \in 1..l-1: u_{k,i} = u_{k,i} - q*u_{l,i}
|
||||
for (int i = 0; i <= l-1; ++i) {
|
||||
ibq_mul(&tmp, &tmp2, &((*u)[l][i]));
|
||||
ibq_sub(&((*u)[k][i]), &((*u)[k][i]), &tmp);
|
||||
}
|
||||
|
||||
end:
|
||||
ibq_finalize(&tmp);
|
||||
ibq_finalize(&tmp2);
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&tibz);
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&den);
|
||||
ibz_finalize(&r);
|
||||
}
|
||||
|
||||
// SWAP(k) sub-algorithm
|
||||
static void SWAP(ibz_mat_4x4_t *basis, ibq_t (*u)[4][4], ibz_t (*H)[4][4], ibq_t (*B)[4], ibq_t (*bStar)[4][4], int k, int kmax) {
|
||||
ibq_t tmp, tmp2, tmp3, u_tmp, B_tmp, b[4];
|
||||
ibq_init(&tmp);
|
||||
ibq_init(&tmp2);
|
||||
ibq_init(&tmp3);
|
||||
ibq_init(&u_tmp);
|
||||
ibq_init(&B_tmp);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibq_init(&(b[i]));
|
||||
}
|
||||
|
||||
// swap b_k and b_{k-1}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibz_swap(&((*basis)[k][i]), &((*basis)[k-1][i]));
|
||||
}
|
||||
|
||||
// swap H_k and H_{k-1}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibz_swap(&((*H)[k][i]), &((*H)[k-1][i]));
|
||||
}
|
||||
|
||||
if (k > 1) {
|
||||
// swap u_{k,j} and u_{k-1,j}
|
||||
for (int j = 0; j <= k - 2; ++j) {
|
||||
ibq_swap(&((*u)[k][j]), &((*u)[k-1][j]));
|
||||
}
|
||||
}
|
||||
|
||||
// u = u_{k,k-1}
|
||||
ibq_copy(&u_tmp, &((*u)[k][k - 1]));
|
||||
|
||||
// B = B_k + u^2*B_{k-1}
|
||||
ibq_mul(&B_tmp, &u_tmp, &u_tmp);
|
||||
ibq_mul(&B_tmp, &B_tmp, &((*B)[k-1]));
|
||||
ibq_add(&B_tmp, &((*B)[k]), &B_tmp);
|
||||
|
||||
// u_{k,k-1} = u*B_{k-1} / B
|
||||
ibq_mul(&tmp, &u_tmp, &((*B)[k-1]));
|
||||
ibq_div(&((*u)[k][k-1]), &tmp, &B_tmp);
|
||||
|
||||
// b = bSTAR_{k-1}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibq_copy(&(b[i]), &((*bStar)[k-1][i]));
|
||||
}
|
||||
// bSTAR_{k-1}=bSTAR_k+u*b
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibq_mul(&tmp, &u_tmp, &(b[i]));
|
||||
ibq_add(&((*bStar)[k-1][i]), &((*bStar)[k][i]), &tmp);
|
||||
}
|
||||
// bSTAR_k = -u_{k,k-1}*bSTAR_k+(B_k/B)*b
|
||||
ibq_div(&tmp2, &((*B)[k]), &B_tmp); // B_k/B
|
||||
ibq_neg(&tmp, &((*u)[k][k-1]));
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibq_mul(&((*bStar)[k][i]), &tmp, &((*bStar)[k][i]));
|
||||
ibq_mul(&tmp3, &tmp2, &(b[i]));
|
||||
ibq_add(&((*bStar)[k][i]), &((*bStar)[k][i]), &tmp3);
|
||||
}
|
||||
|
||||
// B_k = B_{k-1}*B_k/B
|
||||
ibq_mul(&((*B)[k]), &((*B)[k-1]), &((*B)[k]));
|
||||
ibq_div(&((*B)[k]), &((*B)[k]), &B_tmp);
|
||||
|
||||
// B_{k-1} = B
|
||||
ibq_copy(&((*B)[k-1]), &B_tmp);
|
||||
|
||||
for (int i = k+1; i <= kmax; ++i) {
|
||||
// t = u_{i,k}
|
||||
ibq_copy(&tmp, &((*u)[i][k]));
|
||||
|
||||
// u_{i,k} = u_{i,k-1} - u*t
|
||||
ibq_mul(&((*u)[i][k]), &u_tmp, &tmp);
|
||||
ibq_sub(&((*u)[i][k]), &((*u)[i][k-1]), &((*u)[i][k]));
|
||||
|
||||
// u_{i,k-1} = t + u_{k,k-1}*u_{i,k}
|
||||
ibq_mul(&tmp2, &((*u)[k][k-1]), &((*u)[i][k]));
|
||||
ibq_add(&((*u)[i][k-1]), &tmp, &tmp2);
|
||||
}
|
||||
|
||||
ibq_finalize(&tmp);
|
||||
ibq_finalize(&tmp2);
|
||||
ibq_finalize(&tmp3);
|
||||
ibq_finalize(&u_tmp);
|
||||
ibq_finalize(&B_tmp);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibq_finalize(&(b[i]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// m1[0]*m2[0] + m1[1]*m2[1] + q*(m1[2]*m2[2] + m1[3]*m2[3])
|
||||
static void dotproduct_row(ibz_t *mul, const ibz_mat_4x4_t *m1, const ibz_mat_4x4_t *m2, const ibz_t *q, int m1j, int m2j) {
|
||||
ibz_set(mul, 0);
|
||||
ibz_t tmp1, tmp2;
|
||||
ibz_init(&tmp1);
|
||||
ibz_init(&tmp2);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ibz_mul(&tmp1, &((*m1)[m1j][i]), &((*m2)[m2j][i]));
|
||||
ibz_add(mul, mul, &tmp1);
|
||||
}
|
||||
for (int i = 2; i < 4; ++i) {
|
||||
ibz_mul(&tmp1, &((*m1)[m1j][i]), &((*m2)[m2j][i]));
|
||||
ibz_add(&tmp2, &tmp2, &tmp1);
|
||||
}
|
||||
ibz_mul(&tmp2, &tmp2, q);
|
||||
ibz_add(mul, mul, &tmp2);
|
||||
|
||||
ibz_finalize(&tmp1);
|
||||
ibz_finalize(&tmp2);
|
||||
}
|
||||
|
||||
static void dotproduct_zr_row(ibq_t *mul, const ibz_mat_4x4_t *m1, const ibq_t (*m2)[4][4], const ibz_t *q, int m1j, int m2j) {
|
||||
ibq_set(mul, &ibz_const_zero, &ibz_const_one);
|
||||
ibq_t tmp1, tmp2;
|
||||
ibq_init(&tmp1);
|
||||
ibq_init(&tmp2);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ibq_set(&tmp1, &((*m1)[m1j][i]), &ibz_const_one);
|
||||
ibq_mul(&tmp1, &tmp1, &((*m2)[m2j][i]));
|
||||
ibq_add(mul, mul, &tmp1);
|
||||
}
|
||||
for (int i = 2; i < 4; ++i) {
|
||||
ibq_set(&tmp1, &((*m1)[m1j][i]), &ibz_const_one);
|
||||
ibq_mul(&tmp1, &tmp1, &((*m2)[m2j][i]));
|
||||
ibq_add(&tmp2, &tmp2, &tmp1);
|
||||
}
|
||||
ibq_set(&tmp1, q, &ibz_const_one);
|
||||
ibq_mul(&tmp2, &tmp2, &tmp1);
|
||||
ibq_add(mul, mul, &tmp2);
|
||||
|
||||
ibq_finalize(&tmp1);
|
||||
ibq_finalize(&tmp2);
|
||||
}
|
||||
|
||||
static void dotproduct_rr_row(ibq_t *mul, const ibq_t (*m1)[4][4], const ibq_t (*m2)[4][4], const ibz_t *q, int m1j, int m2j) {
|
||||
//ibq_set(mul, 0);
|
||||
ibq_set(mul, &ibz_const_zero, &ibz_const_one);
|
||||
ibq_t tmp1, tmp2;
|
||||
ibq_init(&tmp1);
|
||||
ibq_init(&tmp2);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ibq_mul(&tmp1, &((*m1)[m1j][i]), &((*m2)[m2j][i]));
|
||||
ibq_add(mul, mul, &tmp1);
|
||||
}
|
||||
for (int i = 2; i < 4; ++i) {
|
||||
ibq_mul(&tmp1, &((*m1)[m1j][i]), &((*m2)[m2j][i]));
|
||||
ibq_add(&tmp2, &tmp2, &tmp1);
|
||||
}
|
||||
ibq_set(&tmp1, q, &ibz_const_one);
|
||||
ibq_mul(&tmp2, &tmp2, &tmp1);
|
||||
ibq_add(mul, mul, &tmp2);
|
||||
|
||||
ibq_finalize(&tmp1);
|
||||
ibq_finalize(&tmp2);
|
||||
}
|
||||
|
||||
static void mul_row(ibq_t (*mul)[4][4], const ibq_t *a, const ibq_t (*m)[4][4], int j) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibq_mul(&((*mul)[j][i]), a, &((*m)[j][i]));
|
||||
}
|
||||
}
|
||||
|
||||
static void add_row(ibz_mat_4x4_t *add, const ibz_mat_4x4_t *a, const ibz_mat_4x4_t *b, int j, int aj, int bj) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibz_add(&((*add)[j][i]), &((*a)[aj][i]), &((*b)[bj][i]));
|
||||
}
|
||||
}
|
||||
|
||||
static void sub_row(ibq_t (*add)[4][4], const ibq_t (*a)[4][4], const ibq_t (*b)[4][4], int j, int aj, int bj) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibq_sub(&((*add)[j][i]), &((*a)[aj][i]), &((*b)[bj][i]));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief LLL reduction on 4-dimensional lattice
|
||||
/// Implements Algorithm 2.6.3 from Henri Cohen's "A Course in Computational Algebraic Number Theory"
|
||||
/// @param red
|
||||
/// @param lattice
|
||||
/// @return
|
||||
int quat_lattice_lll(ibz_mat_4x4_t *red, const quat_lattice_t *lattice, const ibz_t *q, int precision) {
|
||||
(void) precision;
|
||||
int ret = 0;
|
||||
ibz_mat_4x4_t basis;
|
||||
ibq_t bStar[4][4];
|
||||
ibq_t bStar_tmp[4][4];
|
||||
ibq_t tmp;
|
||||
ibz_t tmp_z;
|
||||
ibz_t den;
|
||||
ibz_t num;
|
||||
ibq_t cnst;
|
||||
ibq_t u[4][4];
|
||||
ibz_t H[4][4]; // -> I_4
|
||||
ibq_t B[4];
|
||||
ibq_init(&tmp);
|
||||
ibz_init(&tmp_z);
|
||||
ibz_init(&den);
|
||||
ibz_init(&num);
|
||||
ibq_init(&cnst);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
ibq_init(&(B[i]));
|
||||
|
||||
ibz_mat_4x4_init(&basis);
|
||||
ibz_mat_4x4_transpose(&basis, &(lattice->basis));
|
||||
|
||||
// Step 1: Initialize: ...
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
ibq_init(&(u[i][j]));
|
||||
ibq_init(&(bStar[i][j]));
|
||||
ibq_init(&(bStar_tmp[i][j]));
|
||||
// bSTAR_1 = b_1 (we copy all)
|
||||
if (i == j){
|
||||
ibz_init(&(H[i][j]));
|
||||
ibz_set(&(H[i][j]), 1);
|
||||
}
|
||||
else {
|
||||
ibz_init(&(H[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
int k = 1, kmax = 0;
|
||||
// bStar_1 = b_1
|
||||
for (int i = 0; i < 4; ++i)
|
||||
ibq_set(&(bStar[0][i]), &(basis[0][i]), &ibz_const_one);
|
||||
// B_1 = b_1 * b_1
|
||||
dotproduct_row(&tmp_z, &basis, &basis, q, 0, 0);
|
||||
ibq_set(&(B[0]), &tmp_z, &ibz_const_one);
|
||||
ibz_set(&num,99);
|
||||
ibz_set(&den,100);
|
||||
ibq_set(&cnst,&num,&den);
|
||||
|
||||
while (k < 4) {
|
||||
// Step 2: Incremental Gram-Schmidt
|
||||
// if (k <= kmax) -> we can omit..
|
||||
if (k > kmax) {
|
||||
kmax = k;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ibq_set(&(bStar[k][i]), &(basis[k][i]), &ibz_const_one);
|
||||
}
|
||||
for (int j = 0; j <= k-1; ++j) {
|
||||
// bStar_k = b_k -> already done initially
|
||||
// nop
|
||||
// u_{k,j} = b_k*bSTAR_j/B_j
|
||||
dotproduct_zr_row(&tmp, &basis, &bStar, q, k, j);
|
||||
ibq_div(&(u[k][j]), &tmp, &(B[j]));
|
||||
// bStar_k = bStar_k - u_{k,j}*bStar_j
|
||||
mul_row(&bStar_tmp, &(u[k][j]), &bStar, j);
|
||||
sub_row(&bStar, &bStar, &bStar_tmp, k, k, j);
|
||||
}
|
||||
// B_k = bStar_k*bStar_k
|
||||
dotproduct_rr_row(&(B[k]), &bStar, &bStar, q, k, k);
|
||||
if (ibq_is_zero(&(B[k]))) {
|
||||
// b_i did not form a basis, terminate with error
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
while(1) {
|
||||
// Step 3: Test LLL condition
|
||||
RED(&basis, &u, &H, k, k - 1);
|
||||
// If B_k < (0.75 - u_{k,k-1}^2)*B_{k-1}
|
||||
ibq_mul(&tmp, &(u[k][k-1]), &(u[k][k-1]));
|
||||
ibq_sub(&tmp, &cnst, &tmp);
|
||||
ibq_mul(&tmp, &tmp, &(B[k-1]));
|
||||
if (ibq_cmp(&(B[k]), &tmp) < 0) {
|
||||
SWAP(&basis, &u, &H, &B, &bStar, k, kmax);
|
||||
k = (k - 1 > 1 ? k - 1 : 1);
|
||||
} else {
|
||||
for (int l = k - 2; l >= 0; --l) {
|
||||
RED(&basis, &u, &H, k, l);
|
||||
}
|
||||
k++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ibz_mat_4x4_transpose(red, &basis);
|
||||
|
||||
err:
|
||||
ibq_finalize(&tmp);
|
||||
ibz_finalize(&tmp_z);
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&den);
|
||||
ibq_finalize(&cnst);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
ibq_finalize(&(u[i][j]));
|
||||
ibz_finalize(&(H[i][j]));
|
||||
ibq_finalize(&(bStar[i][j]));
|
||||
ibq_finalize(&(bStar_tmp[i][j]));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 4; ++i)
|
||||
ibq_finalize(&(B[i]));
|
||||
ibz_mat_4x4_finalize(&basis);
|
||||
return ret;
|
||||
}
|
||||
190
src/quaternion/ref/generic/lll/l2.c
Normal file
190
src/quaternion/ref/generic/lll/l2.c
Normal file
@@ -0,0 +1,190 @@
|
||||
#include <quaternion.h>
|
||||
#include "lll_internals.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include "dpe.h"
|
||||
|
||||
// Access entry of symmetric matrix
|
||||
#define SYM(M, i, j) (i < j ? &M[j][i] : &M[i][j])
|
||||
|
||||
void
|
||||
quat_lll_core(ibz_mat_4x4_t *G, ibz_mat_4x4_t *basis)
|
||||
{
|
||||
dpe_t dpe_const_one, dpe_const_DELTABAR;
|
||||
|
||||
dpe_init(dpe_const_one);
|
||||
dpe_set_ui(dpe_const_one, 1);
|
||||
|
||||
dpe_init(dpe_const_DELTABAR);
|
||||
dpe_set_d(dpe_const_DELTABAR, DELTABAR);
|
||||
|
||||
// fp variables for Gram-Schmidt orthogonalization and Lovasz' conditions
|
||||
dpe_t r[4][4], u[4][4], lovasz[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dpe_init(lovasz[i]);
|
||||
for (int j = 0; j <= i; j++) {
|
||||
dpe_init(r[i][j]);
|
||||
dpe_init(u[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
// threshold for swaps
|
||||
dpe_t delta_bar;
|
||||
dpe_init(delta_bar);
|
||||
dpe_set_d(delta_bar, DELTABAR);
|
||||
|
||||
// Other work variables
|
||||
dpe_t Xf, tmpF;
|
||||
dpe_init(Xf);
|
||||
dpe_init(tmpF);
|
||||
ibz_t X, tmpI;
|
||||
ibz_init(&X);
|
||||
ibz_init(&tmpI);
|
||||
|
||||
// Main L² loop
|
||||
dpe_set_z(r[0][0], (*G)[0][0]);
|
||||
int kappa = 1;
|
||||
while (kappa < 4) {
|
||||
// size reduce b_κ
|
||||
int done = 0;
|
||||
while (!done) {
|
||||
// Recompute the κ-th row of the Choleski Factorisation
|
||||
// Loop invariant:
|
||||
// r[κ][j] ≈ u[κ][j] ‖b_j*‖² ≈ 〈b_κ, b_j*〉
|
||||
for (int j = 0; j <= kappa; j++) {
|
||||
dpe_set_z(r[kappa][j], (*G)[kappa][j]);
|
||||
for (int k = 0; k < j; k++) {
|
||||
dpe_mul(tmpF, r[kappa][k], u[j][k]);
|
||||
dpe_sub(r[kappa][j], r[kappa][j], tmpF);
|
||||
}
|
||||
if (j < kappa)
|
||||
dpe_div(u[kappa][j], r[kappa][j], r[j][j]);
|
||||
}
|
||||
|
||||
done = 1;
|
||||
// size reduce
|
||||
for (int i = kappa - 1; i >= 0; i--) {
|
||||
if (dpe_cmp_d(u[kappa][i], ETABAR) > 0 || dpe_cmp_d(u[kappa][i], -ETABAR) < 0) {
|
||||
done = 0;
|
||||
dpe_set(Xf, u[kappa][i]);
|
||||
dpe_round(Xf, Xf);
|
||||
dpe_get_z(X, Xf);
|
||||
// Update basis: b_κ ← b_κ - X·b_i
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_mul(&tmpI, &X, &(*basis)[j][i]);
|
||||
ibz_sub(&(*basis)[j][kappa], &(*basis)[j][kappa], &tmpI);
|
||||
}
|
||||
// Update lower half of the Gram matrix
|
||||
// <b_κ - X·b_i, b_κ - X·b_i> = <b_κ, b_κ> - 2X<b_κ, b_i> + X²<b_i, b_i> =
|
||||
// <b_κ,b_κ> - X<b_κ,b_i> - X(<b_κ,b_i> - X·<b_i, b_i>)
|
||||
//// 〈b_κ, b_κ〉 ← 〈b_κ, b_κ〉 - X·〈b_κ, b_i〉
|
||||
ibz_mul(&tmpI, &X, &(*G)[kappa][i]);
|
||||
ibz_sub(&(*G)[kappa][kappa], &(*G)[kappa][kappa], &tmpI);
|
||||
for (int j = 0; j < 4; j++) { // works because i < κ
|
||||
// 〈b_κ, b_j〉 ← 〈b_κ, b_j〉 - X·〈b_i, b_j〉
|
||||
ibz_mul(&tmpI, &X, SYM((*G), i, j));
|
||||
ibz_sub(SYM((*G), kappa, j), SYM((*G), kappa, j), &tmpI);
|
||||
}
|
||||
// After the loop:
|
||||
//// 〈b_κ,b_κ〉 ← 〈b_κ,b_κ〉 - X·〈b_κ,b_i〉 - X·(〈b_κ,b_i〉 - X·〈b_i,
|
||||
/// b_i〉) = 〈b_κ - X·b_i, b_κ - X·b_i〉
|
||||
//
|
||||
// Update u[kappa][j]
|
||||
for (int j = 0; j < i; j++) {
|
||||
dpe_mul(tmpF, Xf, u[i][j]);
|
||||
dpe_sub(u[kappa][j], u[kappa][j], tmpF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check Lovasz' conditions
|
||||
// lovasz[0] = ‖b_κ‖²
|
||||
dpe_set_z(lovasz[0], (*G)[kappa][kappa]);
|
||||
// lovasz[i] = lovasz[i-1] - u[κ][i-1]·r[κ][i-1]
|
||||
for (int i = 1; i < kappa; i++) {
|
||||
dpe_mul(tmpF, u[kappa][i - 1], r[kappa][i - 1]);
|
||||
dpe_sub(lovasz[i], lovasz[i - 1], tmpF);
|
||||
}
|
||||
int swap;
|
||||
for (swap = kappa; swap > 0; swap--) {
|
||||
dpe_mul(tmpF, delta_bar, r[swap - 1][swap - 1]);
|
||||
if (dpe_cmp(tmpF, lovasz[swap - 1]) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Insert b_κ before b_swap
|
||||
if (kappa != swap) {
|
||||
// Insert b_κ before b_swap in the basis and in the lower half Gram matrix
|
||||
for (int j = kappa; j > swap; j--) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_swap(&(*basis)[i][j], &(*basis)[i][j - 1]);
|
||||
if (i == j - 1)
|
||||
ibz_swap(&(*G)[i][i], &(*G)[j][j]);
|
||||
else if (i != j)
|
||||
ibz_swap(SYM((*G), i, j), SYM((*G), i, j - 1));
|
||||
}
|
||||
}
|
||||
// Copy row u[κ] and r[κ] in swap position, ignore what follows
|
||||
for (int i = 0; i < swap; i++) {
|
||||
dpe_set(u[swap][i], u[kappa][i]);
|
||||
dpe_set(r[swap][i], r[kappa][i]);
|
||||
}
|
||||
dpe_set(r[swap][swap], lovasz[swap]);
|
||||
// swap complete
|
||||
kappa = swap;
|
||||
}
|
||||
|
||||
kappa += 1;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Check size-reducedness
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < i; j++) {
|
||||
dpe_abs(u[i][j], u[i][j]);
|
||||
assert(dpe_cmp_d(u[i][j], ETABAR) <= 0);
|
||||
}
|
||||
// Check Lovasz' conditions
|
||||
for (int i = 1; i < 4; i++) {
|
||||
dpe_mul(tmpF, u[i][i - 1], u[i][i - 1]);
|
||||
dpe_sub(tmpF, dpe_const_DELTABAR, tmpF);
|
||||
dpe_mul(tmpF, tmpF, r[i - 1][i - 1]);
|
||||
assert(dpe_cmp(tmpF, r[i][i]) <= 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fill in the upper half of the Gram matrix
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = i + 1; j < 4; j++)
|
||||
ibz_copy(&(*G)[i][j], &(*G)[j][i]);
|
||||
}
|
||||
|
||||
// Clearinghouse
|
||||
ibz_finalize(&X);
|
||||
ibz_finalize(&tmpI);
|
||||
dpe_clear(dpe_const_one);
|
||||
dpe_clear(dpe_const_DELTABAR);
|
||||
dpe_clear(Xf);
|
||||
dpe_clear(tmpF);
|
||||
dpe_clear(delta_bar);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dpe_clear(lovasz[i]);
|
||||
for (int j = 0; j <= i; j++) {
|
||||
dpe_clear(r[i][j]);
|
||||
dpe_clear(u[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
quat_lattice_lll(ibz_mat_4x4_t *red, const quat_lattice_t *lattice, const quat_alg_t *alg)
|
||||
{
|
||||
ibz_mat_4x4_t G; // Gram Matrix
|
||||
ibz_mat_4x4_init(&G);
|
||||
quat_lattice_gram(&G, lattice, alg);
|
||||
ibz_mat_4x4_copy(red, &lattice->basis);
|
||||
quat_lll_core(&G, red);
|
||||
ibz_mat_4x4_finalize(&G);
|
||||
return 0;
|
||||
}
|
||||
127
src/quaternion/ref/generic/lll/lll_applications.c
Normal file
127
src/quaternion/ref/generic/lll/lll_applications.c
Normal file
@@ -0,0 +1,127 @@
|
||||
#include <quaternion.h>
|
||||
#include <internal.h>
|
||||
#include "lll_internals.h"
|
||||
|
||||
void
|
||||
quat_lideal_reduce_basis(ibz_mat_4x4_t *reduced,
|
||||
ibz_mat_4x4_t *gram,
|
||||
const quat_left_ideal_t *lideal,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
assert(quat_order_is_maximal((lideal->parent_order), alg));
|
||||
ibz_t gram_corrector;
|
||||
ibz_init(&gram_corrector);
|
||||
ibz_mul(&gram_corrector, &(lideal->lattice.denom), &(lideal->lattice.denom));
|
||||
quat_lideal_class_gram(gram, lideal, alg);
|
||||
ibz_mat_4x4_copy(reduced, &(lideal->lattice.basis));
|
||||
quat_lll_core(gram, reduced);
|
||||
ibz_mat_4x4_scalar_mul(gram, &gram_corrector, gram);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_div_2exp(&((*gram)[i][i]), &((*gram)[i][i]), 1);
|
||||
for (int j = i + 1; j < 4; j++) {
|
||||
ibz_set(&((*gram)[i][j]), 0);
|
||||
}
|
||||
}
|
||||
ibz_finalize(&gram_corrector);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lideal_lideal_mul_reduced(quat_left_ideal_t *prod,
|
||||
ibz_mat_4x4_t *gram,
|
||||
const quat_left_ideal_t *lideal1,
|
||||
const quat_left_ideal_t *lideal2,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
ibz_mat_4x4_t red;
|
||||
ibz_mat_4x4_init(&red);
|
||||
|
||||
quat_lattice_mul(&(prod->lattice), &(lideal1->lattice), &(lideal2->lattice), alg);
|
||||
prod->parent_order = lideal1->parent_order;
|
||||
quat_lideal_norm(prod);
|
||||
quat_lideal_reduce_basis(&red, gram, prod, alg);
|
||||
ibz_mat_4x4_copy(&(prod->lattice.basis), &red);
|
||||
|
||||
ibz_mat_4x4_finalize(&red);
|
||||
}
|
||||
|
||||
int
|
||||
quat_lideal_prime_norm_reduced_equivalent(quat_left_ideal_t *lideal,
|
||||
const quat_alg_t *alg,
|
||||
const int primality_num_iter,
|
||||
const int equiv_bound_coeff)
|
||||
{
|
||||
ibz_mat_4x4_t gram, red;
|
||||
ibz_mat_4x4_init(&gram);
|
||||
ibz_mat_4x4_init(&red);
|
||||
|
||||
int found = 0;
|
||||
|
||||
// computing the reduced basis
|
||||
quat_lideal_reduce_basis(&red, &gram, lideal, alg);
|
||||
|
||||
quat_alg_elem_t new_alpha;
|
||||
quat_alg_elem_init(&new_alpha);
|
||||
ibz_t tmp, remainder, adjusted_norm;
|
||||
ibz_init(&tmp);
|
||||
ibz_init(&remainder);
|
||||
ibz_init(&adjusted_norm);
|
||||
|
||||
ibz_mul(&adjusted_norm, &lideal->lattice.denom, &lideal->lattice.denom);
|
||||
|
||||
int ctr = 0;
|
||||
|
||||
// equiv_num_iter = (2 * equiv_bound_coeff + 1)^4
|
||||
assert(equiv_bound_coeff < (1 << 20));
|
||||
int equiv_num_iter = (2 * equiv_bound_coeff + 1);
|
||||
equiv_num_iter = equiv_num_iter * equiv_num_iter;
|
||||
equiv_num_iter = equiv_num_iter * equiv_num_iter;
|
||||
|
||||
while (!found && ctr < equiv_num_iter) {
|
||||
ctr++;
|
||||
// we select our linear combination at random
|
||||
ibz_rand_interval_minm_m(&new_alpha.coord[0], equiv_bound_coeff);
|
||||
ibz_rand_interval_minm_m(&new_alpha.coord[1], equiv_bound_coeff);
|
||||
ibz_rand_interval_minm_m(&new_alpha.coord[2], equiv_bound_coeff);
|
||||
ibz_rand_interval_minm_m(&new_alpha.coord[3], equiv_bound_coeff);
|
||||
|
||||
// computation of the norm of the vector sampled
|
||||
quat_qf_eval(&tmp, &gram, &new_alpha.coord);
|
||||
|
||||
// compute the norm of the equivalent ideal
|
||||
// can be improved by removing the power of two first and the odd part only if the trial
|
||||
// division failed (this should always be called on an ideal of norm 2^x * N for some
|
||||
// big prime N )
|
||||
ibz_div(&tmp, &remainder, &tmp, &adjusted_norm);
|
||||
|
||||
// debug : check that the remainder is zero
|
||||
assert(ibz_is_zero(&remainder));
|
||||
|
||||
// pseudo-primality test
|
||||
if (ibz_probab_prime(&tmp, primality_num_iter)) {
|
||||
|
||||
// computes the generator using a matrix multiplication
|
||||
ibz_mat_4x4_eval(&new_alpha.coord, &red, &new_alpha.coord);
|
||||
ibz_copy(&new_alpha.denom, &lideal->lattice.denom);
|
||||
assert(quat_lattice_contains(NULL, &lideal->lattice, &new_alpha));
|
||||
|
||||
quat_alg_conj(&new_alpha, &new_alpha);
|
||||
ibz_mul(&new_alpha.denom, &new_alpha.denom, &lideal->norm);
|
||||
quat_lideal_mul(lideal, lideal, &new_alpha, alg);
|
||||
assert(ibz_probab_prime(&lideal->norm, primality_num_iter));
|
||||
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(found);
|
||||
|
||||
ibz_finalize(&tmp);
|
||||
ibz_finalize(&remainder);
|
||||
ibz_finalize(&adjusted_norm);
|
||||
quat_alg_elem_finalize(&new_alpha);
|
||||
|
||||
ibz_mat_4x4_finalize(&gram);
|
||||
ibz_mat_4x4_finalize(&red);
|
||||
|
||||
return found;
|
||||
}
|
||||
377
src/quaternion/ref/generic/lll/lll_benchmarks.c
Normal file
377
src/quaternion/ref/generic/lll/lll_benchmarks.c
Normal file
@@ -0,0 +1,377 @@
|
||||
#include "lll_internals.h"
|
||||
#include "quaternion_tests.h"
|
||||
#include <rng.h>
|
||||
#include <bench.h>
|
||||
#include <bench_test_arguments.h>
|
||||
|
||||
// norms must be either a vector of length iterations of norms or NULL
|
||||
int
|
||||
quat_bench_lll_benchmark_lll_core(int bitsize,
|
||||
int iterations,
|
||||
int warmup_loops, //(int)(100000 / (bitsize*bitsize)) + 1;
|
||||
quat_lattice_t *lattices,
|
||||
const ibz_t *norms,
|
||||
const quat_alg_t *alg,
|
||||
int add_tests)
|
||||
{
|
||||
int res = 0;
|
||||
uint64_t start, end, time;
|
||||
quat_lattice_t test;
|
||||
ibz_t num, denom;
|
||||
ibq_t eta, delta;
|
||||
ibz_mat_4x4_t *reds;
|
||||
ibz_mat_4x4_t gram;
|
||||
ibz_init(&num);
|
||||
ibz_init(&denom);
|
||||
ibq_init(&eta);
|
||||
ibq_init(&delta);
|
||||
quat_lattice_init(&test);
|
||||
ibz_mat_4x4_init(&gram);
|
||||
quat_lll_set_ibq_parameters(&delta, &eta);
|
||||
|
||||
reds = (ibz_mat_4x4_t *)malloc(iterations * sizeof(ibz_mat_4x4_t));
|
||||
for (int i = 0; i < iterations; i++)
|
||||
ibz_mat_4x4_init(&(reds[i]));
|
||||
|
||||
// warmup setup
|
||||
quat_lattice_t *wu;
|
||||
ibz_mat_4x4_t *wur;
|
||||
wu = (quat_lattice_t *)malloc(warmup_loops * sizeof(quat_lattice_t));
|
||||
wur = (ibz_mat_4x4_t *)malloc(warmup_loops * sizeof(ibz_mat_4x4_t));
|
||||
for (int i = 0; i < warmup_loops; i++) {
|
||||
quat_lattice_init(&(wu[i]));
|
||||
ibz_mat_4x4_init(&(wur[i]));
|
||||
}
|
||||
quat_test_input_random_lattice_generation(wu, bitsize, warmup_loops, 1);
|
||||
// Case for unknown norms
|
||||
if (norms == NULL) {
|
||||
printf("Start warmup and measures for bitsize %d iterations %d with non-ideals\n", bitsize, iterations);
|
||||
// warmup loop
|
||||
for (int iter = 0; iter < warmup_loops; iter++) {
|
||||
quat_lattice_gram(&gram, &(lattices[iter]), alg);
|
||||
ibz_mat_4x4_copy(&(reds[iter]), &(lattices[iter].basis));
|
||||
quat_lll_core(&gram, &(reds[iter]));
|
||||
}
|
||||
// benchmark loop
|
||||
start = cpucycles();
|
||||
for (int iter = 0; iter < iterations; iter++) {
|
||||
quat_lattice_gram(&gram, &(lattices[iter]), alg);
|
||||
ibz_mat_4x4_copy(&(reds[iter]), &(lattices[iter].basis));
|
||||
quat_lll_core(&gram, &(reds[iter]));
|
||||
}
|
||||
end = cpucycles();
|
||||
} else {
|
||||
// Using division by norm
|
||||
quat_lattice_t O0;
|
||||
quat_left_ideal_t *ideals;
|
||||
quat_lattice_init(&O0);
|
||||
quat_lattice_O0_set(&O0);
|
||||
ideals = (quat_left_ideal_t *)malloc(iterations * sizeof(quat_left_ideal_t));
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
quat_left_ideal_init(&(ideals[i]));
|
||||
ibz_mat_4x4_copy(&(ideals[i].lattice.basis), &(lattices[i].basis));
|
||||
ibz_copy(&(ideals[i].lattice.denom), &(lattices[i].denom));
|
||||
ibz_copy(&(ideals[i].norm), &(norms[i]));
|
||||
(ideals[i].parent_order) = &O0;
|
||||
}
|
||||
|
||||
printf("Start warmup and measures for bitsize %d iterations %d with ideals\n", bitsize, iterations);
|
||||
// warmup loop
|
||||
for (int iter = 0; iter < warmup_loops; iter++) {
|
||||
quat_lideal_class_gram(&gram, &(ideals[iter % iterations]), alg);
|
||||
ibz_mat_4x4_copy(&(reds[iter % iterations]), &(ideals[iter % iterations].lattice.basis));
|
||||
quat_lll_core(&gram, &(reds[iter % iterations]));
|
||||
}
|
||||
// benchmark loop
|
||||
start = cpucycles();
|
||||
for (int iter = 0; iter < iterations; iter++) {
|
||||
quat_lideal_class_gram(&gram, &(ideals[iter]), alg);
|
||||
ibz_mat_4x4_copy(&(reds[iter]), &(ideals[iter].lattice.basis));
|
||||
quat_lll_core(&gram, &(reds[iter]));
|
||||
}
|
||||
end = cpucycles();
|
||||
for (int i = 0; i < iterations; i++)
|
||||
quat_left_ideal_finalize(&(ideals[i]));
|
||||
free(ideals);
|
||||
quat_lattice_finalize(&O0);
|
||||
}
|
||||
// results output
|
||||
time = (end - start);
|
||||
printf("%" PRIu64 " cycles per lattice\n%d Lattices %" PRIu64 " cycles total\n",
|
||||
(uint64_t)(time / iterations),
|
||||
iterations,
|
||||
time);
|
||||
|
||||
// test loop
|
||||
if (add_tests) {
|
||||
for (int iter = 0; iter < iterations; iter++) {
|
||||
// test lll reduced
|
||||
res = res || !quat_lll_verify(&(reds[iter]), &delta, &eta, alg);
|
||||
// test lattice equality
|
||||
ibz_copy(&(test.denom), &((lattices[iter]).denom));
|
||||
ibz_mat_4x4_copy(&(test.basis), &(reds[iter]));
|
||||
quat_lattice_hnf(&test);
|
||||
res = res || !quat_lattice_equal(&test, &(lattices[iter]));
|
||||
}
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion benchmark tests for lll_core failed\n");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&denom);
|
||||
ibq_finalize(&delta);
|
||||
ibq_finalize(&eta);
|
||||
quat_lattice_finalize(&test);
|
||||
ibz_mat_4x4_finalize(&gram);
|
||||
for (int i = 0; i < warmup_loops; i++) {
|
||||
quat_lattice_finalize(&(wu[i]));
|
||||
ibz_mat_4x4_finalize(&(wur[i]));
|
||||
}
|
||||
for (int i = 0; i < iterations; i++)
|
||||
ibz_mat_4x4_finalize(&(reds[i]));
|
||||
free(reds);
|
||||
free(wu);
|
||||
free(wur);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// ideals determines if generated as ideals: 0 means ideals, 1 lattices without HNF, 2 and any other
|
||||
// number lattices in HNF tests if tests are run
|
||||
int
|
||||
quat_bench_lll_one_level(const ibz_t *prime,
|
||||
const int *norm_bitsizes,
|
||||
int nb_bitsizes,
|
||||
int iterations,
|
||||
int ideals,
|
||||
int tests)
|
||||
{
|
||||
// initializations
|
||||
quat_alg_t alg;
|
||||
quat_p_extremal_maximal_order_t order;
|
||||
quat_lattice_t *lattices;
|
||||
ibz_t *norms;
|
||||
const ibz_t *used_norms;
|
||||
quat_represent_integer_params_t params;
|
||||
quat_alg_init_set(&alg, prime);
|
||||
lattices = malloc(iterations * sizeof(quat_lattice_t));
|
||||
norms = malloc(iterations * sizeof(ibz_t));
|
||||
// initialize params:
|
||||
quat_lattice_init(&(order.order));
|
||||
quat_alg_elem_init(&(order.t));
|
||||
quat_alg_elem_init(&(order.z));
|
||||
quat_lattice_O0_set_extremal(&order);
|
||||
params.algebra = &alg;
|
||||
params.order = ℴ
|
||||
params.primality_test_iterations = 30;
|
||||
int res = 0;
|
||||
int randret = 0;
|
||||
if (ideals == 0) {
|
||||
used_norms = norms;
|
||||
} else {
|
||||
used_norms = NULL;
|
||||
}
|
||||
|
||||
// run benchmarks
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
quat_lattice_init(&(lattices[i]));
|
||||
ibz_init(&(norms[i]));
|
||||
}
|
||||
for (int i = 0; i < nb_bitsizes; i++) {
|
||||
int warmups = (int)(100000 / (norm_bitsizes[i] * norm_bitsizes[i])) + 1;
|
||||
if (ideals == 0) {
|
||||
randret = randret || quat_test_input_random_ideal_lattice_generation(
|
||||
lattices, norms, norm_bitsizes[i], iterations, ¶ms);
|
||||
} else {
|
||||
randret = randret || quat_test_input_random_lattice_generation(
|
||||
lattices, norm_bitsizes[i], iterations, ideals - 1); // in HNF
|
||||
}
|
||||
if (!randret) {
|
||||
res = res || quat_bench_lll_benchmark_lll_core(
|
||||
norm_bitsizes[i], iterations, warmups, lattices, used_norms, &alg, tests);
|
||||
}
|
||||
}
|
||||
quat_alg_finalize(&alg);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
ibz_finalize(&(norms[i]));
|
||||
quat_lattice_finalize(&(lattices[i]));
|
||||
}
|
||||
quat_lattice_finalize(&(order.order));
|
||||
quat_alg_elem_finalize(&(order.t));
|
||||
quat_alg_elem_finalize(&(order.z));
|
||||
free(norms);
|
||||
free(lattices);
|
||||
return (res + 2 * (randret));
|
||||
}
|
||||
|
||||
// this function must be adapted if algorithms or parameters change
|
||||
int
|
||||
quat_bench_lll_level(int lvl, int iterations, int ideals, int tests)
|
||||
{
|
||||
if (!((lvl == 1) || (lvl == 3) || (lvl == 5))) {
|
||||
printf("Invalid input level to quat_bench_lll_level: %d\n", lvl);
|
||||
return (1);
|
||||
}
|
||||
ibz_t prime;
|
||||
int norm_bitsizes[4] = { 0 };
|
||||
int nb_bitsizes = 4;
|
||||
ibz_init(&prime);
|
||||
if (lvl == 5) {
|
||||
ibz_set_from_str(&prime,
|
||||
"1afffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
16);
|
||||
norm_bitsizes[0] = 254;
|
||||
norm_bitsizes[1] = 254;
|
||||
norm_bitsizes[2] = 747;
|
||||
norm_bitsizes[3] = 1006;
|
||||
}
|
||||
if (lvl == 3) {
|
||||
ibz_set_from_str(&prime,
|
||||
"40fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
"fffffffffffffffffffffff",
|
||||
16);
|
||||
norm_bitsizes[0] = 193;
|
||||
norm_bitsizes[1] = 193;
|
||||
norm_bitsizes[2] = 571;
|
||||
norm_bitsizes[3] = 761;
|
||||
}
|
||||
if (lvl == 1) {
|
||||
ibz_set_from_str(&prime, "4ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16);
|
||||
norm_bitsizes[0] = 127;
|
||||
norm_bitsizes[1] = 127;
|
||||
norm_bitsizes[2] = 377;
|
||||
norm_bitsizes[3] = 501;
|
||||
}
|
||||
printf("Running benchmarks for lvl %d with bitsizes of [%d, %d, %d, %d] \n",
|
||||
lvl,
|
||||
norm_bitsizes[0],
|
||||
norm_bitsizes[1],
|
||||
norm_bitsizes[2],
|
||||
norm_bitsizes[3]);
|
||||
printf("Using prime ");
|
||||
ibz_print(&prime, 10);
|
||||
printf("\n");
|
||||
printf("With %d iterations, ", iterations);
|
||||
if (tests == 0)
|
||||
printf("no ");
|
||||
printf("tests, and lattices generated as ");
|
||||
if (ideals == 0)
|
||||
printf("ideals");
|
||||
else {
|
||||
printf("lattices");
|
||||
if (ideals != 1)
|
||||
printf("not in hnf");
|
||||
}
|
||||
printf("\n\n");
|
||||
int res = quat_bench_lll_one_level(&prime, norm_bitsizes, nb_bitsizes, iterations, ideals, tests);
|
||||
ibz_finalize(&prime);
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t seed[12];
|
||||
int iterations = SQISIGN_TEST_REPS;
|
||||
int help = 0;
|
||||
int seed_set = 0;
|
||||
int tests = 0;
|
||||
int ideals = 0;
|
||||
int res = 0;
|
||||
int level = 1;
|
||||
int level_set = 0;
|
||||
|
||||
#ifndef NDEBUG
|
||||
fprintf(stderr,
|
||||
"\x1b[31mIt looks like SQIsign was compiled with assertions enabled.\n"
|
||||
"This will severely impact performance measurements.\x1b[0m\n");
|
||||
#endif
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!tests && strcmp(argv[i], "--tests") == 0) {
|
||||
tests = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!seed_set && !parse_seed(argv[i], seed)) {
|
||||
seed_set = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (level_set == 0 && sscanf(argv[i], "--level=%d", &level) == 1) {
|
||||
level_set = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!help && strcmp(argv[i], "--help") == 0) {
|
||||
help = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!help && strcmp(argv[i], "--not_ideals") == 0) {
|
||||
ideals = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(argv[i], "--iterations=%d", &iterations) == 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (help || (level != 1 && level != 3 && level != 5)) {
|
||||
printf("Usage: %s [--level=<level>] [--iterations=<iterations>] [--tests] [--seed=<seed>]\n", argv[0]);
|
||||
printf("Where <level> is either 1 or 3 or 5; if not passed, runs on all levels\n");
|
||||
printf("Where <iterations> is the number of iterations used for benchmarking; if not "
|
||||
"present, uses the default: %d)\n",
|
||||
iterations);
|
||||
printf("Where <seed> is the random seed to be used; if not present, a random seed is "
|
||||
"generated\n");
|
||||
printf("Additional verifications are run on each output if --tests is passed\n");
|
||||
printf("If --not_ideals is passed, input lattices are not generated as random O0 ideals of "
|
||||
"norm of a level-specific bitsize, but as random lattices with entries of the same "
|
||||
"bitsize\n");
|
||||
printf("Output has last bit set if tests failed, second-to-last if randomness failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!seed_set) {
|
||||
randombytes_select((unsigned char *)seed, sizeof(seed));
|
||||
}
|
||||
|
||||
print_seed(seed);
|
||||
|
||||
#if defined(TARGET_BIG_ENDIAN)
|
||||
for (int i = 0; i < 12; i++) {
|
||||
seed[i] = BSWAP32(seed[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
randombytes_init((unsigned char *)seed, NULL, 256);
|
||||
cpucycles_init();
|
||||
|
||||
if (level_set != 0) {
|
||||
res = quat_bench_lll_level(level, iterations, ideals, tests);
|
||||
} else {
|
||||
for (level = 1; level <= 5; level += 2) {
|
||||
res |= quat_bench_lll_level(level, iterations, ideals, tests);
|
||||
}
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
// Notes on realistic benchmarks:
|
||||
// Denominator is always 2
|
||||
// Lattice numerators have following maximal bitsizes (when in HNF):
|
||||
// lvl5: 254, 254, 755-757, ni 1006
|
||||
// lvl3: 193, 193, 570-571, ni 760-761
|
||||
// lvl1: 127, 127, 372-377, ni 500-501
|
||||
// where only the "ni" ones are not calls through the ideal reduction function.
|
||||
// The largest coeff of all ideals above is about 2 times its norm.
|
||||
// The quat_bench_lll_level and main functions takes the above into account.
|
||||
// In particular lattices are always generated as ideals of O0 in HNF.
|
||||
|
||||
// Measures obtained by prints in the L2 function and its applications
|
||||
794
src/quaternion/ref/generic/lll/lll_tests.c
Normal file
794
src/quaternion/ref/generic/lll/lll_tests.c
Normal file
@@ -0,0 +1,794 @@
|
||||
#include "lll_internals.h"
|
||||
#include "quaternion_tests.h"
|
||||
#include <rng.h>
|
||||
|
||||
int
|
||||
quat_test_lll_ibq_consts(void)
|
||||
{
|
||||
int ret = 0;
|
||||
ibq_t t;
|
||||
ibz_t tmp1, tmp2, tmp3;
|
||||
ibz_init(&tmp1);
|
||||
ibz_init(&tmp2);
|
||||
ibz_init(&tmp3);
|
||||
ibq_init(&t);
|
||||
|
||||
ibz_set(&tmp1, 123);
|
||||
ibz_set(&tmp2, -123);
|
||||
if (!ibq_set(&t, &tmp1, &tmp2)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ibq_is_one(&t)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ibq_is_ibz(&t)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ibq_to_ibz(&tmp3, &t)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ibz_is_one(&tmp3)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ibz_set(&tmp2, 123);
|
||||
if (!ibq_set(&t, &tmp1, &tmp2)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ibq_is_one(&t)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ibq_is_ibz(&t)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ibq_to_ibz(&tmp3, &t)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ibz_is_one(&tmp3)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ibz_set(&tmp1, 0);
|
||||
ibq_set(&t, &tmp1, &tmp2);
|
||||
|
||||
if (!ibq_is_zero(&t)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ibq_is_ibz(&t)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ibq_to_ibz(&tmp3, &t)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ibz_is_zero(&tmp3)) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
ibq_finalize(&t);
|
||||
ibz_finalize(&tmp1);
|
||||
ibz_finalize(&tmp2);
|
||||
ibz_finalize(&tmp3);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// test for lll verification
|
||||
// void ibq_vec_4_copy_ibz(ibq_vec_4_t *vec, const ibz_t *coeff0, const ibz_t *coeff1,const ibz_t
|
||||
// *coeff2,const ibz_t *coeff3);
|
||||
int
|
||||
quat_test_lll_ibq_vec_4_copy_ibz(void)
|
||||
{
|
||||
int res = 0;
|
||||
ibq_vec_4_t vec;
|
||||
ibz_vec_4_t vec_z;
|
||||
ibz_vec_4_init(&vec_z);
|
||||
ibq_vec_4_init(&vec);
|
||||
ibz_vec_4_set(&vec_z, 2, 3, 4, 5);
|
||||
ibq_vec_4_copy_ibz(&vec, &(vec_z[0]), &(vec_z[1]), &(vec_z[2]), &(vec_z[3]));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibq_to_ibz(&(vec_z[i]), &(vec[i]));
|
||||
res = res || (ibz_cmp_int32(&(vec_z[i]), i + 2) != 0);
|
||||
}
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test lll_ibq_vec_4_copy_ibz failed\n");
|
||||
}
|
||||
ibz_vec_4_finalize(&vec_z);
|
||||
ibq_vec_4_finalize(&vec);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// void quat_lll_bilinear(ibq_t *b, const ibq_vec_4_t *vec0, const ibq_vec_4_t *vec1, const
|
||||
// ibz_t *q);
|
||||
int
|
||||
quat_test_lll_bilinear(void)
|
||||
{
|
||||
int res = 0;
|
||||
ibz_vec_4_t init_helper;
|
||||
ibq_vec_4_t vec0, vec1;
|
||||
ibz_t q;
|
||||
ibq_t cmp, b;
|
||||
ibz_vec_4_init(&init_helper);
|
||||
ibq_init(&cmp);
|
||||
ibq_init(&b);
|
||||
ibz_init(&q);
|
||||
ibq_vec_4_init(&vec0);
|
||||
ibq_vec_4_init(&vec1);
|
||||
ibz_vec_4_set(&init_helper, 1, 2, 3, 4);
|
||||
ibq_vec_4_copy_ibz(&vec0, &(init_helper[0]), &(init_helper[1]), &(init_helper[2]), &(init_helper[3]));
|
||||
ibz_vec_4_set(&init_helper, 9, -8, 7, -6);
|
||||
ibq_vec_4_copy_ibz(&vec1, &(init_helper[0]), &(init_helper[1]), &(init_helper[2]), &(init_helper[3]));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibq_inv(&(vec0[i]), &(vec0[i]));
|
||||
}
|
||||
ibz_set(&q, 3);
|
||||
ibz_vec_4_set(&init_helper, 15, 2, 0, 0);
|
||||
ibq_set(&cmp, &(init_helper[0]), &(init_helper[1]));
|
||||
quat_lll_bilinear(&b, &vec0, &vec1, &q);
|
||||
res = res || (ibq_cmp(&b, &cmp));
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test quat_lll_bilinear failed\n");
|
||||
}
|
||||
ibq_finalize(&cmp);
|
||||
ibq_finalize(&b);
|
||||
ibz_finalize(&q);
|
||||
ibz_vec_4_finalize(&init_helper);
|
||||
ibq_vec_4_finalize(&vec0);
|
||||
ibq_vec_4_finalize(&vec1);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// void quat_lll_gram_schmidt_transposed_with_ibq(ibq_mat_4x4_t *orthogonalised_transposed, const
|
||||
// ibz_mat_4x4_t *mat, const ibz_t *q);
|
||||
int
|
||||
quat_test_lll_gram_schmidt_transposed_with_ibq(void)
|
||||
{
|
||||
int res = 0;
|
||||
int zero;
|
||||
ibq_mat_4x4_t ot, cmp;
|
||||
ibz_mat_4x4_t mat;
|
||||
ibz_t q, num, denom;
|
||||
ibq_t b;
|
||||
ibz_init(&q);
|
||||
ibz_init(&num);
|
||||
ibz_init(&denom);
|
||||
ibq_init(&b);
|
||||
ibz_mat_4x4_init(&mat);
|
||||
ibq_mat_4x4_init(&ot);
|
||||
ibq_mat_4x4_init(&cmp);
|
||||
|
||||
ibz_mat_4x4_zero(&mat);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_set(&(mat[i][j]), i * i + (j + 5) * j - 2 + (i == j));
|
||||
}
|
||||
}
|
||||
ibz_set(&q, 3);
|
||||
quat_lll_gram_schmidt_transposed_with_ibq(&ot, &mat, &q);
|
||||
// test orthogonality
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = i + 1; j < 4; j++) {
|
||||
quat_lll_bilinear(&b, &(ot[i]), &(ot[j]), &q);
|
||||
res = res || !ibq_is_zero(&b);
|
||||
}
|
||||
}
|
||||
// test first vector is identical to mat
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibq_to_ibz(&q, &(ot[0][i]));
|
||||
res = res || ibz_cmp(&q, &(mat[i][0]));
|
||||
}
|
||||
// test no zero vector
|
||||
for (int i = 0; i < 4; i++) {
|
||||
zero = 1;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
zero = zero && ibq_is_zero(&(ot[i][j]));
|
||||
}
|
||||
res = res || zero;
|
||||
}
|
||||
|
||||
ibz_set(&(mat[0][0]), 1);
|
||||
ibz_set(&(mat[0][1]), 0);
|
||||
ibz_set(&(mat[0][2]), 1);
|
||||
ibz_set(&(mat[0][3]), 0);
|
||||
ibz_set(&(mat[1][0]), 0);
|
||||
ibz_set(&(mat[1][1]), 1);
|
||||
ibz_set(&(mat[1][2]), 0);
|
||||
ibz_set(&(mat[1][3]), 1);
|
||||
ibz_set(&(mat[2][0]), 1);
|
||||
ibz_set(&(mat[2][1]), 0);
|
||||
ibz_set(&(mat[2][2]), 2);
|
||||
ibz_set(&(mat[2][3]), 0);
|
||||
ibz_set(&(mat[3][0]), 0);
|
||||
ibz_set(&(mat[3][1]), 1);
|
||||
ibz_set(&(mat[3][2]), 0);
|
||||
ibz_set(&(mat[3][3]), 2);
|
||||
ibz_set(&denom, 1);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibq_set(&(cmp[i][j]), &(mat[j][i]), &denom);
|
||||
}
|
||||
}
|
||||
ibz_set(&denom, 3);
|
||||
ibz_set(&num, -2);
|
||||
ibq_set(&(cmp[2][0]), &num, &denom);
|
||||
ibq_set(&(cmp[3][1]), &num, &denom);
|
||||
ibz_set(&num, 1);
|
||||
ibq_set(&(cmp[2][2]), &num, &denom);
|
||||
ibq_set(&(cmp[3][3]), &num, &denom);
|
||||
ibz_set(&q, 2);
|
||||
quat_lll_gram_schmidt_transposed_with_ibq(&ot, &mat, &q);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
res = res || ibq_cmp(&(cmp[i][j]), &(ot[i][j]));
|
||||
}
|
||||
}
|
||||
|
||||
ibz_set(&(mat[0][0]), 1);
|
||||
ibz_set(&(mat[0][1]), 0);
|
||||
ibz_set(&(mat[0][2]), 1);
|
||||
ibz_set(&(mat[0][3]), 0);
|
||||
ibz_set(&(mat[1][0]), 0);
|
||||
ibz_set(&(mat[1][1]), 1);
|
||||
ibz_set(&(mat[1][2]), 0);
|
||||
ibz_set(&(mat[1][3]), 1);
|
||||
ibz_set(&(mat[2][0]), 1);
|
||||
ibz_set(&(mat[2][1]), 0);
|
||||
ibz_set(&(mat[2][2]), 2);
|
||||
ibz_set(&(mat[2][3]), 1);
|
||||
ibz_set(&(mat[3][0]), 0);
|
||||
ibz_set(&(mat[3][1]), 1);
|
||||
ibz_set(&(mat[3][2]), 0);
|
||||
ibz_set(&(mat[3][3]), 2);
|
||||
ibz_set(&denom, 1);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibq_set(&(cmp[i][j]), &(mat[j][i]), &denom);
|
||||
}
|
||||
}
|
||||
ibz_set(&denom, 3);
|
||||
ibz_set(&num, -2);
|
||||
ibq_set(&(cmp[2][0]), &num, &denom);
|
||||
ibq_set(&(cmp[3][1]), &num, &denom);
|
||||
ibz_set(&num, 1);
|
||||
ibq_set(&(cmp[2][2]), &num, &denom);
|
||||
ibq_set(&(cmp[3][3]), &num, &denom);
|
||||
ibz_set(&num, 0);
|
||||
ibq_set(&(cmp[3][0]), &num, &denom);
|
||||
ibq_set(&(cmp[3][2]), &num, &denom);
|
||||
ibz_set(&q, 2);
|
||||
quat_lll_gram_schmidt_transposed_with_ibq(&ot, &mat, &q);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
res = res || ibq_cmp(&(cmp[i][j]), &(ot[i][j]));
|
||||
}
|
||||
}
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test dim4_gram_schmidt_transposed_with_ibq failed\n");
|
||||
}
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&denom);
|
||||
ibq_finalize(&b);
|
||||
ibz_mat_4x4_finalize(&mat);
|
||||
ibq_mat_4x4_finalize(&ot);
|
||||
ibq_mat_4x4_finalize(&cmp);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// int quat_lll_verify(const ibz_mat_4x4_t *mat, const ibq_t *delta, const ibq_t *eta, const
|
||||
// quat_alg_t *alg);
|
||||
int
|
||||
quat_test_lll_verify(void)
|
||||
{
|
||||
int res = 0;
|
||||
ibz_mat_4x4_t mat;
|
||||
ibz_t q, coeff_num, coeff_denom;
|
||||
ibq_t eta, delta;
|
||||
quat_alg_t alg;
|
||||
ibz_mat_4x4_init(&mat);
|
||||
ibz_init(&q);
|
||||
ibq_init(&delta);
|
||||
ibq_init(&eta);
|
||||
ibz_init(&coeff_num);
|
||||
ibz_init(&coeff_denom);
|
||||
|
||||
// reduced: non-1 norm
|
||||
ibz_set(&q, 3);
|
||||
quat_alg_init_set(&alg, &q);
|
||||
ibq_set(&eta, &ibz_const_one, &ibz_const_two);
|
||||
ibq_set(&delta, &ibz_const_three, &ibz_const_two);
|
||||
ibq_mul(&delta, &delta, &eta);
|
||||
ibz_set(&(mat[0][0]), 0);
|
||||
ibz_set(&(mat[0][1]), 2);
|
||||
ibz_set(&(mat[0][2]), 3);
|
||||
ibz_set(&(mat[0][3]), -14);
|
||||
ibz_set(&(mat[1][0]), 2);
|
||||
ibz_set(&(mat[1][1]), -1);
|
||||
ibz_set(&(mat[1][2]), -4);
|
||||
ibz_set(&(mat[1][3]), -8);
|
||||
ibz_set(&(mat[2][0]), 1);
|
||||
ibz_set(&(mat[2][1]), -2);
|
||||
ibz_set(&(mat[2][2]), 1);
|
||||
ibz_set(&(mat[2][3]), 0);
|
||||
ibz_set(&(mat[3][0]), 1);
|
||||
ibz_set(&(mat[3][1]), 1);
|
||||
ibz_set(&(mat[3][2]), 0);
|
||||
ibz_set(&(mat[3][3]), 7);
|
||||
res = res || !quat_lll_verify(&mat, &delta, &eta, &alg);
|
||||
quat_alg_finalize(&alg);
|
||||
|
||||
// reduced: non-1 norm
|
||||
ibz_set(&q, 103);
|
||||
quat_alg_init_set(&alg, &q);
|
||||
ibz_set(&coeff_num, 99);
|
||||
ibz_set(&coeff_denom, 100);
|
||||
ibq_set(&delta, &coeff_num, &coeff_denom);
|
||||
ibz_set(&(mat[0][0]), 3);
|
||||
ibz_set(&(mat[0][1]), 0);
|
||||
ibz_set(&(mat[0][2]), 90);
|
||||
ibz_set(&(mat[0][3]), -86);
|
||||
ibz_set(&(mat[1][0]), 11);
|
||||
ibz_set(&(mat[1][1]), 15);
|
||||
ibz_set(&(mat[1][2]), 12);
|
||||
ibz_set(&(mat[1][3]), 50);
|
||||
ibz_set(&(mat[2][0]), 1);
|
||||
ibz_set(&(mat[2][1]), -2);
|
||||
ibz_set(&(mat[2][2]), 0);
|
||||
ibz_set(&(mat[2][3]), 3);
|
||||
ibz_set(&(mat[3][0]), -1);
|
||||
ibz_set(&(mat[3][1]), 0);
|
||||
ibz_set(&(mat[3][2]), 5);
|
||||
ibz_set(&(mat[3][3]), 5);
|
||||
res = res || !quat_lll_verify(&mat, &delta, &eta, &alg);
|
||||
quat_alg_finalize(&alg);
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test quat_lll_verify failed\n");
|
||||
}
|
||||
ibz_finalize(&q);
|
||||
ibq_finalize(&delta);
|
||||
ibq_finalize(&eta);
|
||||
ibz_finalize(&coeff_num);
|
||||
ibz_finalize(&coeff_denom);
|
||||
ibz_mat_4x4_finalize(&mat);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// int quat_lattice_lll(ibz_mat_4x4_t *red, const quat_lattice_t *lattice, const ibz_t *q, int
|
||||
// precision);
|
||||
int
|
||||
quat_test_lll_lattice_lll(void)
|
||||
{
|
||||
int res = 0;
|
||||
quat_lattice_t lat, test;
|
||||
ibz_mat_4x4_t red;
|
||||
ibz_t num, denom, q;
|
||||
ibq_t eta, delta;
|
||||
quat_alg_t alg;
|
||||
ibz_init(&num);
|
||||
ibz_init(&denom);
|
||||
ibz_init(&q);
|
||||
ibq_init(&delta);
|
||||
ibq_init(&eta);
|
||||
ibz_mat_4x4_init(&red);
|
||||
quat_lattice_init(&lat);
|
||||
quat_lattice_init(&test);
|
||||
ibz_set(&q, 103);
|
||||
quat_alg_init_set(&alg, &q);
|
||||
|
||||
// set lattice
|
||||
ibz_set(&lat.denom, 60);
|
||||
ibz_mat_4x4_zero(&(lat.basis));
|
||||
ibz_set(&lat.basis[0][0], 3);
|
||||
ibz_set(&lat.basis[1][0], 7);
|
||||
ibz_set(&lat.basis[0][1], 1);
|
||||
ibz_set(&lat.basis[3][1], -6);
|
||||
ibz_set(&lat.basis[1][2], 12);
|
||||
ibz_set(&lat.basis[2][2], 5);
|
||||
ibz_set(&lat.basis[0][3], -19);
|
||||
ibz_set(&lat.basis[3][3], 3);
|
||||
|
||||
quat_lattice_hnf(&lat);
|
||||
|
||||
res = res || quat_lattice_lll(&red, &lat, &alg);
|
||||
// test lll reduced
|
||||
quat_lll_set_ibq_parameters(&delta, &eta);
|
||||
res = res || !quat_lll_verify(&red, &delta, &eta, &alg);
|
||||
// test lattice equality
|
||||
ibz_copy(&(test.denom), &(lat.denom));
|
||||
ibz_mat_4x4_copy(&(test.basis), &(red));
|
||||
quat_lattice_hnf(&test);
|
||||
res = res || !quat_lattice_equal(&test, &lat);
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test lll_lattice_lll failed\n");
|
||||
}
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&denom);
|
||||
ibz_finalize(&q);
|
||||
ibq_finalize(&eta);
|
||||
ibq_finalize(&delta);
|
||||
ibz_mat_4x4_finalize(&red);
|
||||
quat_lattice_finalize(&lat);
|
||||
quat_lattice_finalize(&test);
|
||||
quat_alg_finalize(&alg);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// int quat_lattice_lll(ibz_mat_4x4_t *red, const quat_lattice_t *lattice, const quat_alg_t *alg);
|
||||
int
|
||||
quat_test_lll_randomized_lattice_lll(void)
|
||||
{
|
||||
int res = 0;
|
||||
quat_lattice_t lat, test;
|
||||
ibz_mat_4x4_t red;
|
||||
ibz_t q, det;
|
||||
ibq_t delta, eta;
|
||||
int32_t rand[4][4];
|
||||
int32_t rand_denom;
|
||||
uint32_t rand_q;
|
||||
ibz_init(&q);
|
||||
ibz_init(&det);
|
||||
ibq_init(&eta);
|
||||
ibq_init(&delta);
|
||||
ibz_mat_4x4_init(&red);
|
||||
quat_lattice_init(&lat);
|
||||
quat_lattice_init(&test);
|
||||
quat_lll_set_ibq_parameters(&delta, &eta);
|
||||
|
||||
for (int iter = 0; iter < 20; iter++) {
|
||||
quat_alg_t alg;
|
||||
rand_denom = 0;
|
||||
while (rand_denom <= 0) {
|
||||
int randret = randombytes((unsigned char *)&rand_denom, sizeof(int32_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
}
|
||||
int randret = randombytes((unsigned char *)&rand_q, sizeof(uint32_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
// generate random invertible matrix
|
||||
ibz_set(&det, 0);
|
||||
while (ibz_is_zero(&det)) {
|
||||
randret = randombytes((unsigned char *)rand, sizeof(rand));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_set(&(lat.basis[i][j]), rand[j][i]);
|
||||
}
|
||||
}
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL, &det, &(lat.basis));
|
||||
}
|
||||
|
||||
// set lattice
|
||||
ibz_set(&lat.denom, rand_denom);
|
||||
quat_lattice_hnf(&lat);
|
||||
// set algebra
|
||||
ibz_set(&q, 1 + (rand_q % 1023));
|
||||
quat_alg_init_set(&alg, &q);
|
||||
// reduce
|
||||
res = res || quat_lattice_lll(&red, &lat, &alg);
|
||||
// test lll reduced
|
||||
res = res || !quat_lll_verify(&red, &delta, &eta, &alg);
|
||||
// test lattice equality
|
||||
ibz_copy(&(test.denom), &(lat.denom));
|
||||
ibz_mat_4x4_copy(&(test.basis), &(red));
|
||||
quat_lattice_hnf(&test);
|
||||
res = res || !quat_lattice_equal(&test, &lat);
|
||||
quat_alg_finalize(&alg);
|
||||
}
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test of lll with randomization for lattice_lll failed\n");
|
||||
}
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&det);
|
||||
ibq_finalize(&delta);
|
||||
ibq_finalize(&eta);
|
||||
ibz_mat_4x4_finalize(&red);
|
||||
quat_lattice_finalize(&lat);
|
||||
quat_lattice_finalize(&test);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// int quat_lideal_reduce_basis(ibz_mat_4x4_t *reduced, ibz_mat_4x4_t *gram, const
|
||||
// quat_left_ideal_t *lideal, const quat_alg_t *alg);
|
||||
int
|
||||
quat_test_lideal_reduce_basis()
|
||||
{
|
||||
int res = 0;
|
||||
ibz_mat_4x4_t red, gram, prod, gram_norm;
|
||||
ibz_vec_4_t vec;
|
||||
quat_left_ideal_t lideal;
|
||||
quat_lattice_t test;
|
||||
quat_alg_t alg;
|
||||
quat_alg_elem_t init_helper;
|
||||
quat_lattice_t order;
|
||||
ibq_t delta, eta;
|
||||
ibz_t num, denom, norm, test_norm;
|
||||
ibz_init(&num);
|
||||
ibz_init(&denom);
|
||||
ibz_init(&norm);
|
||||
ibz_init(&test_norm);
|
||||
ibq_init(&delta);
|
||||
ibq_init(&eta);
|
||||
ibz_vec_4_init(&vec);
|
||||
ibz_mat_4x4_init(&prod);
|
||||
ibz_mat_4x4_init(&gram_norm);
|
||||
quat_lattice_init(&test);
|
||||
quat_alg_elem_init(&init_helper);
|
||||
quat_lattice_init(&order);
|
||||
quat_alg_init_set_ui(&alg, 19);
|
||||
ibz_mat_4x4_init(&gram);
|
||||
ibz_mat_4x4_init(&red);
|
||||
quat_left_ideal_init(&lideal);
|
||||
quat_lattice_O0_set(&order);
|
||||
quat_alg_elem_set(&init_helper, 1, 1, 2, 8, 8);
|
||||
quat_lideal_create_principal(&lideal, &init_helper, &order, &alg);
|
||||
quat_lattice_reduce_denom(&(lideal.lattice), &(lideal.lattice));
|
||||
quat_lideal_reduce_basis(&red, &gram, &lideal, &alg);
|
||||
quat_lll_set_ibq_parameters(&delta, &eta);
|
||||
res = res || !quat_lll_verify(&red, &delta, &eta, &alg);
|
||||
// test reduced and lideal generate same lattice
|
||||
ibz_mat_4x4_copy(&(test.basis), &red);
|
||||
ibz_copy(&(test.denom), &(lideal.lattice.denom));
|
||||
quat_lattice_hnf(&test);
|
||||
res = res || !quat_lattice_equal(&(lideal.lattice), &test);
|
||||
// test gram matrix is gram matrix
|
||||
ibz_mat_4x4_identity(&gram_norm);
|
||||
ibz_copy(&(gram_norm[2][2]), &(alg.p));
|
||||
ibz_copy(&(gram_norm[3][3]), &(alg.p));
|
||||
ibz_mat_4x4_transpose(&prod, &red);
|
||||
ibz_mat_4x4_mul(&prod, &prod, &gram_norm);
|
||||
ibz_mat_4x4_mul(&prod, &prod, &red);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_vec_4_set(&vec, (i == 0), (i == 1), (i == 2), (i == 3));
|
||||
quat_qf_eval(&norm, &gram, &vec);
|
||||
quat_qf_eval(&test_norm, &prod, &vec);
|
||||
ibz_mul(&norm, &(lideal.norm), &norm);
|
||||
res = res || !(ibz_cmp(&norm, &test_norm) == 0);
|
||||
}
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test lideal_reduce_basis failed\n");
|
||||
}
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&denom);
|
||||
ibz_finalize(&norm);
|
||||
ibz_finalize(&test_norm);
|
||||
ibq_finalize(&delta);
|
||||
ibq_finalize(&eta);
|
||||
quat_lattice_finalize(&test);
|
||||
quat_alg_elem_finalize(&init_helper);
|
||||
ibz_mat_4x4_finalize(&prod);
|
||||
quat_lattice_finalize(&order);
|
||||
quat_alg_finalize(&alg);
|
||||
ibz_vec_4_finalize(&vec);
|
||||
ibz_mat_4x4_finalize(&gram);
|
||||
ibz_mat_4x4_finalize(&red);
|
||||
ibz_mat_4x4_finalize(&gram_norm);
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// int quat_lideal_lideal_mul_reduced(quat_left_ideal_t *prod, ibz_mat_4x4_t *gram, const
|
||||
// quat_left_ideal_t *lideal1,const quat_left_ideal_t *lideal2, const quat_alg_t *alg);
|
||||
int
|
||||
quat_test_lll_lideal_lideal_mul_reduced()
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t n, norm, test_norm;
|
||||
ibq_t delta, eta;
|
||||
ibz_vec_4_t vec;
|
||||
quat_alg_t alg;
|
||||
quat_alg_elem_t gen;
|
||||
quat_lattice_t order, ro;
|
||||
quat_left_ideal_t lideal1, lideal2, prod, i1, i2;
|
||||
ibz_mat_4x4_t gram;
|
||||
ibz_mat_4x4_t gram_test;
|
||||
|
||||
ibz_init(&n);
|
||||
ibz_init(&norm);
|
||||
ibz_init(&test_norm);
|
||||
ibq_init(&delta);
|
||||
ibq_init(&eta);
|
||||
ibz_vec_4_init(&vec);
|
||||
quat_alg_elem_init(&gen);
|
||||
quat_left_ideal_init(&lideal1);
|
||||
quat_left_ideal_init(&lideal2);
|
||||
quat_left_ideal_init(&i1);
|
||||
quat_left_ideal_init(&i2);
|
||||
quat_left_ideal_init(&prod);
|
||||
quat_lattice_init(&order);
|
||||
quat_lattice_init(&ro);
|
||||
ibz_mat_4x4_init(&gram);
|
||||
ibz_mat_4x4_init(&gram_test);
|
||||
|
||||
quat_alg_init_set_ui(&alg, 103);
|
||||
quat_lattice_O0_set(&order);
|
||||
quat_lll_set_ibq_parameters(&delta, &eta);
|
||||
|
||||
ibz_set(&n, 113);
|
||||
quat_alg_elem_set(&gen, 1, 10, 0, 1, 3);
|
||||
quat_lideal_create(&lideal1, &gen, &n, &order, &alg);
|
||||
|
||||
ibz_set(&n, 89);
|
||||
quat_alg_elem_set(&gen, 2, 2, 5, 1, 4);
|
||||
quat_lideal_create(&lideal2, &gen, &n, &order, &alg);
|
||||
|
||||
quat_lideal_copy(&i1, &lideal1);
|
||||
quat_lideal_copy(&i2, &lideal2);
|
||||
|
||||
quat_lideal_lideal_mul_reduced(&prod, &gram, &lideal1, &lideal2, &alg);
|
||||
res = res || !quat_lll_verify(&(prod.lattice.basis), &delta, &eta, &alg);
|
||||
ibz_mat_4x4_identity(&(gram_test));
|
||||
ibz_copy(&(gram_test[2][2]), &(alg.p));
|
||||
ibz_copy(&(gram_test[3][3]), &(alg.p));
|
||||
ibz_mat_4x4_mul(&(gram_test), &(gram_test), &(prod.lattice.basis));
|
||||
ibz_mat_4x4_transpose(&(gram_test), &(gram_test));
|
||||
ibz_mat_4x4_mul(&(gram_test), &(gram_test), &(prod.lattice.basis));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_vec_4_set(&vec, (i == 0), (i == 1), (i == 2), (i == 3));
|
||||
quat_qf_eval(&norm, &gram, &vec);
|
||||
quat_qf_eval(&test_norm, &gram_test, &vec);
|
||||
ibz_mul(&norm, &(prod.norm), &norm);
|
||||
res = res || !(ibz_cmp(&norm, &test_norm) == 0);
|
||||
}
|
||||
quat_lattice_hnf(&(prod.lattice));
|
||||
|
||||
res = res || !quat_lideal_equals(&i1, &lideal1, &alg);
|
||||
res = res || !quat_lideal_equals(&i2, &lideal2, &alg);
|
||||
quat_lattice_mul(&i1.lattice, &i1.lattice, &i2.lattice, &alg);
|
||||
res = res || !quat_lattice_equal(&i1.lattice, &prod.lattice);
|
||||
res = res || !(prod.parent_order == lideal1.parent_order);
|
||||
i1.parent_order = lideal1.parent_order;
|
||||
quat_lideal_norm(&i1);
|
||||
res = res || !quat_lideal_equals(&i1, &prod, &alg);
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test lideal_lideal_mul_reduced failed\n");
|
||||
}
|
||||
ibz_finalize(&n);
|
||||
ibz_finalize(&norm);
|
||||
ibz_finalize(&test_norm);
|
||||
ibq_finalize(&delta);
|
||||
ibq_finalize(&eta);
|
||||
ibz_vec_4_finalize(&vec);
|
||||
quat_alg_elem_finalize(&gen);
|
||||
quat_left_ideal_finalize(&lideal1);
|
||||
quat_left_ideal_finalize(&lideal2);
|
||||
quat_left_ideal_finalize(&i1);
|
||||
quat_left_ideal_finalize(&i2);
|
||||
quat_left_ideal_finalize(&prod);
|
||||
quat_lattice_finalize(&order);
|
||||
quat_lattice_finalize(&ro);
|
||||
quat_alg_finalize(&alg);
|
||||
ibz_mat_4x4_finalize(&gram);
|
||||
ibz_mat_4x4_finalize(&gram_test);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// int quat_lideal_prime_norm_reduced_equivalent(quat_left_ideal_t *lideal, const quat_alg_t *alg,
|
||||
// const int primality_num_iter, const int equiv_bound_coeff, const int equiv_num_iter);
|
||||
int
|
||||
quat_test_lll_lideal_prime_norm_reduced_equivalent()
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t n, d;
|
||||
quat_alg_t alg;
|
||||
quat_alg_elem_t gen;
|
||||
ibz_mat_4x4_t red, gram;
|
||||
quat_lattice_t order, ro, ro2;
|
||||
quat_left_ideal_t lideal1, lideal2, i1;
|
||||
|
||||
ibz_init(&n);
|
||||
ibz_init(&d);
|
||||
quat_alg_elem_init(&gen);
|
||||
quat_left_ideal_init(&lideal1);
|
||||
quat_left_ideal_init(&lideal2);
|
||||
quat_left_ideal_init(&i1);
|
||||
quat_lattice_init(&order);
|
||||
quat_lattice_init(&ro);
|
||||
quat_lattice_init(&ro2);
|
||||
ibz_mat_4x4_init(&red);
|
||||
ibz_mat_4x4_init(&gram);
|
||||
|
||||
quat_alg_init_set_ui(&alg, 103);
|
||||
quat_lattice_O0_set(&order);
|
||||
|
||||
ibz_set(&n, 113);
|
||||
quat_alg_elem_set(&gen, 1, 10, 0, 1, 3);
|
||||
quat_lideal_create(&lideal1, &gen, &n, &order, &alg);
|
||||
|
||||
quat_lideal_copy(&i1, &lideal1);
|
||||
quat_lideal_right_order(&ro, &lideal1, &alg);
|
||||
|
||||
quat_lideal_prime_norm_reduced_equivalent(&lideal1, &alg, 20, 20);
|
||||
|
||||
// test norm correctness
|
||||
quat_lattice_hnf(&(lideal1.lattice));
|
||||
ibz_copy(&n, &(lideal1.norm));
|
||||
quat_lideal_norm(&lideal1);
|
||||
res = res || (0 != ibz_cmp(&n, &(lideal1.norm)));
|
||||
|
||||
// test norm primality
|
||||
res = res || !ibz_probab_prime(&n, 20);
|
||||
|
||||
// test equivalence
|
||||
quat_lideal_right_order(&ro2, &lideal1, &alg);
|
||||
quat_lattice_mul(&(lideal2.lattice), &ro, &ro2, &alg);
|
||||
ibz_set(&(lideal2.lattice.denom), 1);
|
||||
lideal2.parent_order = &ro;
|
||||
quat_lattice_hnf(&(lideal2.lattice));
|
||||
quat_lideal_norm(&lideal2);
|
||||
// now lideal2 is a connecting idea of ro and ro2
|
||||
quat_lideal_reduce_basis(&red, &gram, &lideal2, &alg);
|
||||
quat_alg_elem_copy_ibz(&gen, &(lideal2.lattice.denom), &(red[0][0]), &(red[1][0]), &(red[2][0]), &(red[3][0]));
|
||||
quat_alg_norm(&n, &d, &gen, &alg);
|
||||
assert(ibz_is_one(&d));
|
||||
res = res || (0 != ibz_cmp(&n, &(lideal2.norm)));
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test lideal_prime_norm_reduced_equivalent failed\n");
|
||||
}
|
||||
ibz_finalize(&n);
|
||||
ibz_finalize(&d);
|
||||
ibz_mat_4x4_finalize(&red);
|
||||
ibz_mat_4x4_finalize(&gram);
|
||||
quat_alg_elem_finalize(&gen);
|
||||
quat_left_ideal_finalize(&lideal1);
|
||||
quat_left_ideal_finalize(&lideal2);
|
||||
quat_left_ideal_finalize(&i1);
|
||||
quat_lattice_finalize(&order);
|
||||
quat_lattice_finalize(&ro);
|
||||
quat_lattice_finalize(&ro2);
|
||||
quat_alg_finalize(&alg);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// run all previous tests
|
||||
int
|
||||
quat_test_lll(void)
|
||||
{
|
||||
int res = 0;
|
||||
printf("\nRunning quaternion tests of lll and its subfunctions\n");
|
||||
res = res | quat_test_lll_ibq_consts();
|
||||
res = res | quat_test_lll_ibq_vec_4_copy_ibz();
|
||||
res = res | quat_test_lll_bilinear();
|
||||
res = res | quat_test_lll_gram_schmidt_transposed_with_ibq();
|
||||
res = res | quat_test_lll_verify();
|
||||
res = res | quat_test_lll_lattice_lll();
|
||||
res = res | quat_test_lll_randomized_lattice_lll();
|
||||
res = res | quat_test_lideal_reduce_basis();
|
||||
res = res | quat_test_lll_lideal_lideal_mul_reduced();
|
||||
res = res | quat_test_lll_lideal_prime_norm_reduced_equivalent();
|
||||
return (res);
|
||||
}
|
||||
174
src/quaternion/ref/generic/lll/lll_verification.c
Normal file
174
src/quaternion/ref/generic/lll/lll_verification.c
Normal file
@@ -0,0 +1,174 @@
|
||||
#include "lll_internals.h"
|
||||
|
||||
// functions to verify lll
|
||||
void
|
||||
quat_lll_set_ibq_parameters(ibq_t *delta, ibq_t *eta)
|
||||
{
|
||||
ibz_t num, denom;
|
||||
ibz_init(&num);
|
||||
ibz_init(&denom);
|
||||
ibq_set(delta, &ibz_const_one, &ibz_const_two);
|
||||
ibz_set(&num, EPSILON_NUM);
|
||||
ibz_set(&denom, EPSILON_DENOM);
|
||||
ibq_set(eta, &num, &denom);
|
||||
ibq_add(eta, eta, delta);
|
||||
ibz_set(&num, DELTA_NUM);
|
||||
ibz_set(&denom, DELTA_DENOM);
|
||||
ibq_set(delta, &num, &denom);
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&denom);
|
||||
}
|
||||
|
||||
void
|
||||
ibq_vec_4_copy_ibz(ibq_vec_4_t *vec, const ibz_t *coeff0, const ibz_t *coeff1, const ibz_t *coeff2, const ibz_t *coeff3)
|
||||
{
|
||||
ibz_t one;
|
||||
ibz_init(&one);
|
||||
ibz_set(&one, 1);
|
||||
ibq_set(&((*vec)[0]), coeff0, &one);
|
||||
ibq_set(&((*vec)[1]), coeff1, &one);
|
||||
ibq_set(&((*vec)[2]), coeff2, &one);
|
||||
ibq_set(&((*vec)[3]), coeff3, &one);
|
||||
ibz_finalize(&one);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lll_bilinear(ibq_t *b, const ibq_vec_4_t *vec0, const ibq_vec_4_t *vec1, const ibz_t *q)
|
||||
{
|
||||
ibq_t sum, prod, norm_q;
|
||||
ibz_t one;
|
||||
ibz_init(&one);
|
||||
ibz_set(&one, 1);
|
||||
ibq_init(&sum);
|
||||
ibq_init(&prod);
|
||||
ibq_init(&norm_q);
|
||||
ibq_set(&norm_q, q, &one);
|
||||
|
||||
ibq_mul(&sum, &((*vec0)[0]), &((*vec1)[0]));
|
||||
ibq_mul(&prod, &((*vec0)[1]), &((*vec1)[1]));
|
||||
ibq_add(&sum, &sum, &prod);
|
||||
ibq_mul(&prod, &((*vec0)[2]), &((*vec1)[2]));
|
||||
ibq_mul(&prod, &prod, &norm_q);
|
||||
ibq_add(&sum, &sum, &prod);
|
||||
ibq_mul(&prod, &((*vec0)[3]), &((*vec1)[3]));
|
||||
ibq_mul(&prod, &prod, &norm_q);
|
||||
ibq_add(b, &sum, &prod);
|
||||
|
||||
ibz_finalize(&one);
|
||||
ibq_finalize(&sum);
|
||||
ibq_finalize(&prod);
|
||||
ibq_finalize(&norm_q);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lll_gram_schmidt_transposed_with_ibq(ibq_mat_4x4_t *orthogonalised_transposed,
|
||||
const ibz_mat_4x4_t *mat,
|
||||
const ibz_t *q)
|
||||
{
|
||||
ibq_mat_4x4_t work;
|
||||
ibq_vec_4_t vec;
|
||||
ibq_t norm, b, coeff, prod;
|
||||
ibq_init(&norm);
|
||||
ibq_init(&coeff);
|
||||
ibq_init(&prod);
|
||||
ibq_init(&b);
|
||||
ibq_mat_4x4_init(&work);
|
||||
ibq_vec_4_init(&vec);
|
||||
// transpose the input matrix to be able to work on vectors
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibq_vec_4_copy_ibz(&(work[i]), &((*mat)[0][i]), &((*mat)[1][i]), &((*mat)[2][i]), &((*mat)[3][i]));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
quat_lll_bilinear(&norm, &(work[i]), &(work[i]), q);
|
||||
ibq_inv(&norm, &norm);
|
||||
for (int j = i + 1; j < 4; j++) {
|
||||
ibq_vec_4_copy_ibz(&vec, &((*mat)[0][j]), &((*mat)[1][j]), &((*mat)[2][j]), &((*mat)[3][j]));
|
||||
quat_lll_bilinear(&b, &(work[i]), &vec, q);
|
||||
ibq_mul(&coeff, &norm, &b);
|
||||
for (int k = 0; k < 4; k++) {
|
||||
ibq_mul(&prod, &coeff, &(work[i][k]));
|
||||
ibq_sub(&(work[j][k]), &(work[j][k]), &prod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibq_copy(&((*orthogonalised_transposed)[i][j]), &(work[i][j]));
|
||||
}
|
||||
}
|
||||
|
||||
ibq_finalize(&norm);
|
||||
ibq_finalize(&coeff);
|
||||
ibq_finalize(&prod);
|
||||
ibq_finalize(&b);
|
||||
ibq_mat_4x4_finalize(&work);
|
||||
ibq_vec_4_finalize(&vec);
|
||||
}
|
||||
|
||||
int
|
||||
quat_lll_verify(const ibz_mat_4x4_t *mat, const ibq_t *delta, const ibq_t *eta, const quat_alg_t *alg)
|
||||
{
|
||||
int res = 1;
|
||||
ibq_mat_4x4_t orthogonalised_transposed;
|
||||
ibq_vec_4_t tmp_vec;
|
||||
ibq_t div, tmp, mu, two, norm, b;
|
||||
ibz_t mu2_floored, num, denom;
|
||||
ibq_mat_4x4_init(&orthogonalised_transposed);
|
||||
ibq_vec_4_init(&tmp_vec);
|
||||
ibq_init(&div);
|
||||
ibq_init(&tmp);
|
||||
ibq_init(&norm);
|
||||
ibq_init(&b);
|
||||
ibq_init(&mu);
|
||||
ibq_init(&two);
|
||||
ibz_init(&mu2_floored);
|
||||
ibz_init(&num);
|
||||
ibz_init(&denom);
|
||||
ibz_set(&num, 2);
|
||||
ibz_set(&denom, 1);
|
||||
ibq_set(&two, &num, &denom);
|
||||
|
||||
quat_lll_gram_schmidt_transposed_with_ibq(&orthogonalised_transposed, mat, &(alg->p));
|
||||
// check small bilinear products/norms
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < i; j++) {
|
||||
ibq_vec_4_copy_ibz(&tmp_vec, &((*mat)[0][i]), &((*mat)[1][i]), &((*mat)[2][i]), &((*mat)[3][i]));
|
||||
quat_lll_bilinear(&b, &(orthogonalised_transposed[j]), &tmp_vec, &(alg->p));
|
||||
quat_lll_bilinear(&norm, &(orthogonalised_transposed[j]), &(orthogonalised_transposed[j]), &(alg->p));
|
||||
ibq_inv(&tmp, &norm);
|
||||
ibq_mul(&mu, &b, &tmp);
|
||||
ibq_abs(&mu, &mu);
|
||||
// compare to eta
|
||||
res = res && (ibq_cmp(&mu, eta) <= 0);
|
||||
}
|
||||
}
|
||||
for (int i = 1; i < 4; i++) {
|
||||
ibq_vec_4_copy_ibz(&tmp_vec, &((*mat)[0][i]), &((*mat)[1][i]), &((*mat)[2][i]), &((*mat)[3][i]));
|
||||
quat_lll_bilinear(&b, &(orthogonalised_transposed[i - 1]), &tmp_vec, &(alg->p));
|
||||
quat_lll_bilinear(&norm, &(orthogonalised_transposed[i - 1]), &(orthogonalised_transposed[i - 1]), &(alg->p));
|
||||
ibq_inv(&tmp, &norm);
|
||||
ibq_mul(&mu, &b, &tmp);
|
||||
// tmp is mu^2
|
||||
ibq_mul(&tmp, &mu, &mu);
|
||||
// mu is delta-mu^2
|
||||
ibq_sub(&mu, delta, &tmp);
|
||||
quat_lll_bilinear(&tmp, &(orthogonalised_transposed[i]), &(orthogonalised_transposed[i]), &(alg->p));
|
||||
// get (delta-mu^2)norm(i-1)
|
||||
ibq_mul(&div, &norm, &mu);
|
||||
res = res && (ibq_cmp(&tmp, &div) >= 0);
|
||||
}
|
||||
ibq_mat_4x4_finalize(&orthogonalised_transposed);
|
||||
ibq_vec_4_finalize(&tmp_vec);
|
||||
ibq_finalize(&div);
|
||||
ibq_finalize(&norm);
|
||||
ibq_finalize(&b);
|
||||
ibq_finalize(&tmp);
|
||||
ibq_finalize(&mu);
|
||||
ibq_finalize(&two);
|
||||
ibz_finalize(&mu2_floored);
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&denom);
|
||||
return (res);
|
||||
}
|
||||
233
src/quaternion/ref/generic/lll/rationals.c
Normal file
233
src/quaternion/ref/generic/lll/rationals.c
Normal file
@@ -0,0 +1,233 @@
|
||||
#include <stdio.h>
|
||||
#include "internal.h"
|
||||
#include "lll_internals.h"
|
||||
|
||||
void
|
||||
ibq_init(ibq_t *x)
|
||||
{
|
||||
ibz_init(&((*x)[0]));
|
||||
ibz_init(&((*x)[1]));
|
||||
ibz_set(&((*x)[1]), 1);
|
||||
}
|
||||
|
||||
void
|
||||
ibq_finalize(ibq_t *x)
|
||||
{
|
||||
ibz_finalize(&((*x)[0]));
|
||||
ibz_finalize(&((*x)[1]));
|
||||
}
|
||||
|
||||
void
|
||||
ibq_mat_4x4_init(ibq_mat_4x4_t *mat)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibq_init(&(*mat)[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
ibq_mat_4x4_finalize(ibq_mat_4x4_t *mat)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibq_finalize(&(*mat)[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ibq_vec_4_init(ibq_vec_4_t *vec)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibq_init(&(*vec)[i]);
|
||||
}
|
||||
}
|
||||
void
|
||||
ibq_vec_4_finalize(ibq_vec_4_t *vec)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibq_finalize(&(*vec)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ibq_mat_4x4_print(const ibq_mat_4x4_t *mat)
|
||||
{
|
||||
printf("matrix: ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_print(&((*mat)[i][j][0]), 10);
|
||||
printf("/");
|
||||
ibz_print(&((*mat)[i][j][1]), 10);
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
ibq_vec_4_print(const ibq_vec_4_t *vec)
|
||||
{
|
||||
printf("vector: ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_print(&((*vec)[i][0]), 10);
|
||||
printf("/");
|
||||
ibz_print(&((*vec)[i][1]), 10);
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void
|
||||
ibq_reduce(ibq_t *x)
|
||||
{
|
||||
ibz_t gcd, r;
|
||||
ibz_init(&gcd);
|
||||
ibz_init(&r);
|
||||
ibz_gcd(&gcd, &((*x)[0]), &((*x)[1]));
|
||||
ibz_div(&((*x)[0]), &r, &((*x)[0]), &gcd);
|
||||
assert(ibz_is_zero(&r));
|
||||
ibz_div(&((*x)[1]), &r, &((*x)[1]), &gcd);
|
||||
assert(ibz_is_zero(&r));
|
||||
ibz_finalize(&gcd);
|
||||
ibz_finalize(&r);
|
||||
}
|
||||
|
||||
void
|
||||
ibq_add(ibq_t *sum, const ibq_t *a, const ibq_t *b)
|
||||
{
|
||||
ibz_t add, prod;
|
||||
ibz_init(&add);
|
||||
ibz_init(&prod);
|
||||
|
||||
ibz_mul(&add, &((*a)[0]), &((*b)[1]));
|
||||
ibz_mul(&prod, &((*b)[0]), &((*a)[1]));
|
||||
ibz_add(&((*sum)[0]), &add, &prod);
|
||||
ibz_mul(&((*sum)[1]), &((*a)[1]), &((*b)[1]));
|
||||
ibz_finalize(&add);
|
||||
ibz_finalize(&prod);
|
||||
}
|
||||
|
||||
void
|
||||
ibq_neg(ibq_t *neg, const ibq_t *x)
|
||||
{
|
||||
ibz_copy(&((*neg)[1]), &((*x)[1]));
|
||||
ibz_neg(&((*neg)[0]), &((*x)[0]));
|
||||
}
|
||||
|
||||
void
|
||||
ibq_sub(ibq_t *diff, const ibq_t *a, const ibq_t *b)
|
||||
{
|
||||
ibq_t neg;
|
||||
ibq_init(&neg);
|
||||
ibq_neg(&neg, b);
|
||||
ibq_add(diff, a, &neg);
|
||||
ibq_finalize(&neg);
|
||||
}
|
||||
|
||||
void
|
||||
ibq_abs(ibq_t *abs, const ibq_t *x) // once
|
||||
{
|
||||
ibq_t neg;
|
||||
ibq_init(&neg);
|
||||
ibq_neg(&neg, x);
|
||||
if (ibq_cmp(x, &neg) < 0)
|
||||
ibq_copy(abs, &neg);
|
||||
else
|
||||
ibq_copy(abs, x);
|
||||
ibq_finalize(&neg);
|
||||
}
|
||||
|
||||
void
|
||||
ibq_mul(ibq_t *prod, const ibq_t *a, const ibq_t *b)
|
||||
{
|
||||
ibz_mul(&((*prod)[0]), &((*a)[0]), &((*b)[0]));
|
||||
ibz_mul(&((*prod)[1]), &((*a)[1]), &((*b)[1]));
|
||||
}
|
||||
|
||||
int
|
||||
ibq_inv(ibq_t *inv, const ibq_t *x)
|
||||
{
|
||||
int res = !ibq_is_zero(x);
|
||||
if (res) {
|
||||
ibz_copy(&((*inv)[0]), &((*x)[0]));
|
||||
ibz_copy(&((*inv)[1]), &((*x)[1]));
|
||||
ibz_swap(&((*inv)[1]), &((*inv)[0]));
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
ibq_cmp(const ibq_t *a, const ibq_t *b)
|
||||
{
|
||||
ibz_t x, y;
|
||||
ibz_init(&x);
|
||||
ibz_init(&y);
|
||||
ibz_copy(&x, &((*a)[0]));
|
||||
ibz_copy(&y, &((*b)[0]));
|
||||
ibz_mul(&y, &y, &((*a)[1]));
|
||||
ibz_mul(&x, &x, &((*b)[1]));
|
||||
if (ibz_cmp(&((*a)[1]), &ibz_const_zero) > 0) {
|
||||
ibz_neg(&y, &y);
|
||||
ibz_neg(&x, &x);
|
||||
}
|
||||
if (ibz_cmp(&((*b)[1]), &ibz_const_zero) > 0) {
|
||||
ibz_neg(&y, &y);
|
||||
ibz_neg(&x, &x);
|
||||
}
|
||||
int res = ibz_cmp(&x, &y);
|
||||
ibz_finalize(&x);
|
||||
ibz_finalize(&y);
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
ibq_is_zero(const ibq_t *x)
|
||||
{
|
||||
return ibz_is_zero(&((*x)[0]));
|
||||
}
|
||||
|
||||
int
|
||||
ibq_is_one(const ibq_t *x)
|
||||
{
|
||||
return (0 == ibz_cmp(&((*x)[0]), &((*x)[1])));
|
||||
}
|
||||
|
||||
int
|
||||
ibq_set(ibq_t *q, const ibz_t *a, const ibz_t *b)
|
||||
{
|
||||
ibz_copy(&((*q)[0]), a);
|
||||
ibz_copy(&((*q)[1]), b);
|
||||
return !ibz_is_zero(b);
|
||||
}
|
||||
|
||||
void
|
||||
ibq_copy(ibq_t *target, const ibq_t *value) // once
|
||||
{
|
||||
ibz_copy(&((*target)[0]), &((*value)[0]));
|
||||
ibz_copy(&((*target)[1]), &((*value)[1]));
|
||||
}
|
||||
|
||||
int
|
||||
ibq_is_ibz(const ibq_t *q)
|
||||
{
|
||||
ibz_t r;
|
||||
ibz_init(&r);
|
||||
ibz_mod(&r, &((*q)[0]), &((*q)[1]));
|
||||
int res = ibz_is_zero(&r);
|
||||
ibz_finalize(&r);
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
ibq_to_ibz(ibz_t *z, const ibq_t *q)
|
||||
{
|
||||
ibz_t r;
|
||||
ibz_init(&r);
|
||||
ibz_div(z, &r, &((*q)[0]), &((*q)[1]));
|
||||
int res = ibz_is_zero(&r);
|
||||
ibz_finalize(&r);
|
||||
return (res);
|
||||
}
|
||||
@@ -1,421 +0,0 @@
|
||||
#include "internal.h"
|
||||
|
||||
/***************** Howell form **********************/
|
||||
|
||||
/** @brief Compute u s.t. gcd(u, mod) = 1 and ux = gcd(x, mod)
|
||||
*/
|
||||
static int unit(ibz_t *unit, ibz_t *gcd, const ibz_t *x, const ibz_t *mod) {
|
||||
if (ibz_is_zero(x))
|
||||
return 0;
|
||||
ibz_t stab, nmod, nmod2, thrash, tmp;
|
||||
ibz_init(&stab); ibz_init(&nmod); ibz_init(&nmod2); ibz_init(&thrash); ibz_init(&tmp);
|
||||
ibz_xgcd(gcd, unit, &thrash, x, mod);
|
||||
ibz_div(&nmod, &thrash, mod, gcd);
|
||||
// Stabilizer(unit, nmod)
|
||||
ibz_gcd(&stab, unit, &nmod);
|
||||
ibz_div(&nmod2, &thrash, mod, &stab);
|
||||
ibz_div(&stab, &thrash, unit, &stab);
|
||||
// Split(nmod2, stab)
|
||||
for (int i = ibz_bitsize(&nmod2); i > 0; i >>= 1) {
|
||||
ibz_mul(&stab, &stab, &stab);
|
||||
ibz_mod(&stab, &stab, &nmod2);
|
||||
}
|
||||
ibz_gcd(&stab, &stab, &nmod2);
|
||||
ibz_div(&stab, &thrash, &nmod2, &stab);
|
||||
#ifndef NDEBUG
|
||||
ibz_mul(&thrash, &stab, &nmod);
|
||||
ibz_add(&thrash, unit, &thrash);
|
||||
ibz_gcd(&thrash, &thrash, mod);
|
||||
ibz_gcd(&tmp, unit, &nmod);
|
||||
assert(ibz_cmp(&thrash, &tmp) == 0);
|
||||
#endif
|
||||
// Finish off
|
||||
ibz_mul(&stab, &stab, &nmod);
|
||||
ibz_add(unit, unit, &stab);
|
||||
ibz_mod(unit, unit, mod);
|
||||
#ifndef NDEBUG
|
||||
ibz_gcd(&stab, unit, mod);
|
||||
assert(ibz_is_one(&stab));
|
||||
ibz_mul(&stab, unit, x);
|
||||
ibz_mod(&stab, &stab, mod);
|
||||
assert(ibz_cmp(&stab, gcd) == 0);
|
||||
#endif
|
||||
ibz_finalize(&stab); ibz_finalize(&nmod); ibz_finalize(&nmod2); ibz_finalize(&thrash); ibz_finalize(&tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** @brief Linear combination of two columns
|
||||
*
|
||||
* (mat[][j] | mat[][k]) <- (mat[][j] | mat[][k]) * U (mod)
|
||||
*
|
||||
* only update columns between start (included) and end (excluded)
|
||||
*/
|
||||
static void gen_elem(int rows, int cols, ibz_t mat[rows][cols], int j, int k, int start, int end, const ibz_mat_2x2_t *U, const ibz_t *mod)
|
||||
{
|
||||
ibz_t tmp1, tmp2;
|
||||
ibz_init(&tmp1); ibz_init(&tmp2);
|
||||
for (int i = start; i < end; i++) {
|
||||
ibz_mul(&tmp1, &mat[i][j], &(*U)[0][0]);
|
||||
ibz_mul(&tmp2, &mat[i][k], &(*U)[1][0]);
|
||||
ibz_add(&tmp1, &tmp1, &tmp2);
|
||||
|
||||
ibz_mul(&tmp2, &mat[i][j], &(*U)[0][1]);
|
||||
ibz_mul(&mat[i][k], &mat[i][k], &(*U)[1][1]);
|
||||
ibz_add(&mat[i][k], &tmp2, &mat[i][k]);
|
||||
|
||||
ibz_mod(&mat[i][j], &tmp1, mod);
|
||||
ibz_mod(&mat[i][k], &mat[i][k], mod);
|
||||
}
|
||||
ibz_finalize(&tmp1); ibz_finalize(&tmp2);
|
||||
}
|
||||
|
||||
/** @brief Swap columns j and k of mat
|
||||
*/
|
||||
static inline void swap_col(int rows, int cols, ibz_t mat[rows][cols], int j, int k)
|
||||
{
|
||||
ibz_t tmp;
|
||||
ibz_init(&tmp);
|
||||
for (int i = 0; i < rows; i++) {
|
||||
ibz_copy(&tmp, &mat[i][j]);
|
||||
ibz_copy(&mat[i][j], &mat[i][k]);
|
||||
ibz_copy(&mat[i][k], &tmp);
|
||||
}
|
||||
ibz_finalize(&tmp);
|
||||
}
|
||||
|
||||
/** @brief Check if column is all zeros
|
||||
*/
|
||||
static inline int is_col_zero(int rows, int cols, ibz_t mat[rows][cols], int j)
|
||||
{
|
||||
int is_zero = 1;
|
||||
for (int i = 0; i < rows; i++)
|
||||
is_zero &= ibz_is_zero(&mat[i][j]);
|
||||
return is_zero;
|
||||
}
|
||||
|
||||
/** Check that mat * trans = howell
|
||||
*/
|
||||
static int howell_check_matrices(int rows, int cols, const ibz_t howell[rows][rows+1], const ibz_t trans[rows+1][rows+1], const ibz_t mat[rows][cols], ibz_t *mod)
|
||||
{
|
||||
const int extra = rows + 1 - cols;
|
||||
ibz_t test[rows][rows+1], res[rows][rows+1];
|
||||
ibz_mat_init(rows, rows+1, test);
|
||||
ibz_mat_init(rows, rows+1, res);
|
||||
|
||||
// copy mat to the right of test
|
||||
for (int i = 0; i < rows; i++)
|
||||
for (int j = 0; j < cols; j++)
|
||||
ibz_mod(&test[i][j+extra], &mat[i][j], mod);
|
||||
|
||||
ibz_mat_mulmod(rows, rows+1, rows+1, res, test, trans, mod);
|
||||
|
||||
int ok = 1;
|
||||
for (int i = 0; i < rows; i++)
|
||||
for (int j = 0; j < rows+1; j++)
|
||||
ok &= ibz_cmp(&howell[i][j], &res[i][j]) == 0;
|
||||
|
||||
ibz_mat_finalize(rows, rows+1, res);
|
||||
ibz_mat_finalize(rows, rows+1, test);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void ibz_mat_mulmod(int from, int through, int to, ibz_t res[from][to], const ibz_t A[from][through], const ibz_t B[through][to], const ibz_t *mod)
|
||||
{
|
||||
ibz_t tmp;
|
||||
ibz_init(&tmp);
|
||||
for (int i = 0; i < from; i++) {
|
||||
for (int j = 0; j < to; j++) {
|
||||
ibz_set(&res[i][j], 0);
|
||||
for (int k = 0; k < through; k++) {
|
||||
ibz_mul(&tmp, &A[i][k], &B[k][j]);
|
||||
ibz_add(&res[i][j], &res[i][j], &tmp);
|
||||
ibz_mod(&res[i][j], &res[i][j], mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
ibz_finalize(&tmp);
|
||||
}
|
||||
|
||||
int ibz_mat_howell(int rows, int cols, ibz_t howell[rows][rows+1], ibz_t trans[rows+1][rows+1], const ibz_t mat[rows][cols], ibz_t *mod) {
|
||||
assert(cols <= rows);
|
||||
const int extra = rows + 1 - cols;
|
||||
|
||||
ibz_mat_2x2_t U;
|
||||
ibz_t gcd, u, q;
|
||||
ibz_mat_2x2_init(&U);
|
||||
ibz_init(&gcd); ibz_init(&u); ibz_init(&q);
|
||||
|
||||
// copy mat to the right of howell
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = cols; j < rows+1; j++)
|
||||
ibz_set(&howell[i][j-cols], 0);
|
||||
for (int j = 0; j < cols; j++)
|
||||
ibz_mod(&howell[i][j+extra], &mat[i][j], mod);
|
||||
}
|
||||
// initialize trans to identity
|
||||
if (trans) {
|
||||
for (int i = 0; i < rows+1; i++) {
|
||||
for (int j = 0; j < rows+1; j++)
|
||||
if (j != i) ibz_set(&trans[i][j], 0);
|
||||
ibz_set(&trans[i][i], 1);
|
||||
}
|
||||
assert(howell_check_matrices(rows, cols, howell, trans, mat, mod));
|
||||
}
|
||||
|
||||
// Put in upper triangular form
|
||||
for (int i = rows-1; i >= extra-1; i--) {
|
||||
for (int j = extra; j <= i; j++) {
|
||||
if (ibz_is_zero(&howell[i][j]))
|
||||
continue;
|
||||
ibz_xgcd_ann(&gcd, &U[0][0], &U[1][0], &U[0][1], &U[1][1], &howell[i][j], &howell[i][i+1]);
|
||||
gen_elem(rows, rows+1, howell, j, i+1, 0, i, &U, mod);
|
||||
ibz_set(&howell[i][j], 0);
|
||||
ibz_copy(&howell[i][i+1], &gcd);
|
||||
//
|
||||
if (trans) {
|
||||
gen_elem(rows+1, rows+1, trans, j, i+1, 0, rows+1, &U, mod);
|
||||
assert(howell_check_matrices(rows, cols, howell, trans, mat, mod));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Put in reduced Howell form
|
||||
for (int i = rows-1; i >= 0; i--) {
|
||||
/* normalize diagonal coefficient */
|
||||
if (unit(&u, &gcd, &howell[i][i+1], mod)) {
|
||||
for (int k = 0; k < i; k++) {
|
||||
ibz_mul(&howell[k][i+1], &howell[k][i+1], &u);
|
||||
ibz_mod(&howell[k][i+1], &howell[k][i+1], mod);
|
||||
}
|
||||
ibz_copy(&howell[i][i+1], &gcd);
|
||||
//
|
||||
if (trans) {
|
||||
for (int k = 0; k < rows+1; k++) {
|
||||
ibz_mul(&trans[k][i+1], &trans[k][i+1], &u);
|
||||
ibz_mod(&trans[k][i+1], &trans[k][i+1], mod);
|
||||
}
|
||||
assert(howell_check_matrices(rows, cols, howell, trans, mat, mod));
|
||||
}
|
||||
}
|
||||
|
||||
/* reduce right of the diagonal */
|
||||
ibz_t *pivot = &howell[i][i+1];
|
||||
if (!ibz_is_zero(pivot)) {
|
||||
for (int j = i+2; j < rows+1; j++) {
|
||||
assert(ibz_cmp(pivot, &ibz_const_zero) > 0);
|
||||
ibz_div(&q, &howell[i][j], &howell[i][j], pivot);
|
||||
// howell[][j] -= q howell[][i+1]
|
||||
for (int k = 0; k < i; k++) {
|
||||
ibz_mul(&u, &q, &howell[k][i+1]);
|
||||
ibz_sub(&howell[k][j], &howell[k][j], &u);
|
||||
ibz_mod(&howell[k][j], &howell[k][j], mod);
|
||||
}
|
||||
// trans[][j] -= q trans[][i+1]
|
||||
if (trans) {
|
||||
for (int k = 0; k < rows+1; k++) {
|
||||
ibz_mul(&u, &q, &trans[k][i+1]);
|
||||
ibz_sub(&trans[k][j], &trans[k][j], &u);
|
||||
ibz_mod(&trans[k][j], &trans[k][j], mod);
|
||||
}
|
||||
assert(howell_check_matrices(rows, cols, howell, trans, mat, mod));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ensure Howell property */
|
||||
if (i > 0) {
|
||||
ibz_gcd(&gcd, pivot, mod);
|
||||
if (!ibz_is_one(&gcd)) {
|
||||
// Ann(pivot)
|
||||
ibz_div(&u, &gcd, mod, &gcd);
|
||||
for (int k = 0; k < rows; k++) {
|
||||
if (k < i) {
|
||||
ibz_mul(&howell[k][0], &howell[k][i+1], &u);
|
||||
ibz_mod(&howell[k][0], &howell[k][0], mod);
|
||||
} else {
|
||||
ibz_set(&howell[k][0], 0);
|
||||
}
|
||||
}
|
||||
// trans[][0] += u trans[][i+1]
|
||||
if (trans) {
|
||||
for (int k = 0; k < rows+1; k++) {
|
||||
ibz_mul(&q, &u, &trans[k][i+1]);
|
||||
ibz_add(&trans[k][0], &trans[k][0], &q);
|
||||
ibz_mod(&trans[k][0], &trans[k][0], mod);
|
||||
}
|
||||
assert(howell_check_matrices(rows, cols, howell, trans, mat, mod));
|
||||
}
|
||||
|
||||
for (int i2 = i-1; i2 >= 0; i2--) {
|
||||
if (ibz_is_zero(&howell[i2][0]))
|
||||
continue;
|
||||
if (ibz_is_zero(&howell[i2][i2+1])) {
|
||||
swap_col(rows, rows+1, howell, 0, i2+1);
|
||||
if (trans) {
|
||||
swap_col(rows+1, rows+1, trans, 0, i2+1);
|
||||
assert(howell_check_matrices(rows, cols, howell, trans, mat, mod));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
ibz_xgcd_ann(&gcd, &U[0][0], &U[1][0], &U[0][1], &U[1][1], &howell[i2][0], &howell[i2][i2+1]);
|
||||
gen_elem(rows, rows+1, howell, 0, i2+1, 0, i2, &U, mod);
|
||||
ibz_set(&howell[i2][0], 0);
|
||||
ibz_copy(&howell[i2][i2+1], &gcd);
|
||||
//
|
||||
if (trans) {
|
||||
gen_elem(rows, rows+1, trans, 0, i2+1, 0, rows+1, &U, mod);
|
||||
assert(howell_check_matrices(rows, cols, howell, trans, mat, mod));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* put zero columns first */
|
||||
int read, write;
|
||||
for (read = rows, write = rows; read >= 1; read--) {
|
||||
if (!is_col_zero(rows, rows+1, howell, read)) {
|
||||
if (read < write) {
|
||||
swap_col(rows, rows+1, howell, read, write);
|
||||
if (trans) {
|
||||
swap_col(rows+1, rows+1, trans, read, write);
|
||||
assert(howell_check_matrices(rows, cols, howell, trans, mat, mod));
|
||||
}
|
||||
}
|
||||
write--;
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize
|
||||
ibz_mat_2x2_finalize(&U);
|
||||
ibz_finalize(&gcd); ibz_finalize(&u); ibz_finalize(&q);
|
||||
|
||||
return write + 1;
|
||||
}
|
||||
|
||||
void ibz_mat_right_ker_mod(int rows, int cols, ibz_t ker[cols][cols], const ibz_t mat[rows][cols], ibz_t *mod)
|
||||
{
|
||||
assert(cols <= rows);
|
||||
const int extra = rows + 1 - cols;
|
||||
|
||||
ibz_t tmp;
|
||||
ibz_mat_2x2_t U;
|
||||
ibz_t howell[rows][rows+1], trans[rows+1][rows+1], preker[rows+1][rows+1], near_ker[cols][rows+1];
|
||||
|
||||
ibz_init(&tmp);
|
||||
ibz_mat_2x2_init(&U);
|
||||
ibz_mat_init(rows, rows+1, howell);
|
||||
ibz_mat_init(rows+1, rows+1, trans);
|
||||
ibz_mat_init(rows+1, rows+1, preker);
|
||||
ibz_mat_init(cols, rows+1, near_ker);
|
||||
|
||||
// Compute Howell form of mat
|
||||
int zeros = ibz_mat_howell(rows, cols, howell, trans, mat, mod);
|
||||
|
||||
// Compute right kernel of Howell form
|
||||
for (int j = rows, i = rows-1; j >= 0; j--) {
|
||||
while (i >= 0 && ibz_is_zero(&howell[i][j]))
|
||||
i--;
|
||||
if (i < 0) {
|
||||
ibz_set(&preker[j][j], 1);
|
||||
continue;
|
||||
}
|
||||
ibz_t *pivot = &howell[i][j];
|
||||
|
||||
// Ann(pivot)
|
||||
ibz_gcd(&tmp, pivot, mod);
|
||||
if (!ibz_is_one(&tmp))
|
||||
ibz_div(&preker[j][j], &tmp, mod, &tmp);
|
||||
|
||||
for (int j2 = j+1; j2 <= rows; j2++) {
|
||||
// howell[i][j+1..rows] * preker[j+1..rows][j2]
|
||||
for (int k = j+1; k <= rows; k++) {
|
||||
ibz_mul(&tmp, &howell[i][k], &preker[k][j2]);
|
||||
ibz_add(&preker[j][j2], &preker[j][j2], &tmp);
|
||||
}
|
||||
ibz_mod(&preker[j][j2], &preker[j][j2], mod);
|
||||
//
|
||||
ibz_div(&preker[j][j2], &tmp, &preker[j][j2], pivot);
|
||||
assert(ibz_is_zero(&tmp));
|
||||
if (!ibz_is_zero(&preker[j][j2]))
|
||||
ibz_sub(&preker[j][j2], mod, &preker[j][j2]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Check that preker is indeed a kernel of howell
|
||||
ibz_t acc;
|
||||
ibz_init(&acc);
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < rows+1; j++) {
|
||||
ibz_set(&acc, 0);
|
||||
for (int k = 0; k < rows+1; k++) {
|
||||
ibz_mul(&tmp, &howell[i][k], &preker[k][j]);
|
||||
ibz_add(&acc, &acc, &tmp);
|
||||
}
|
||||
ibz_mod(&acc, &acc, mod);
|
||||
assert(ibz_is_zero(&acc));
|
||||
}
|
||||
}
|
||||
ibz_finalize(&acc);
|
||||
#endif
|
||||
|
||||
// Apply (bottom part of) transition matrix to computed kernel
|
||||
for (int i = 0; i < cols; i++) {
|
||||
for (int j = 0; j < rows+1; j++) {
|
||||
for (int k = 0; k < rows+1; k++) {
|
||||
ibz_mul(&tmp, &trans[i+extra][k], &preker[k][j]);
|
||||
ibz_add(&near_ker[i][j], &near_ker[i][j], &tmp);
|
||||
}
|
||||
ibz_mod(&near_ker[i][j], &near_ker[i][j], mod);
|
||||
}
|
||||
}
|
||||
|
||||
// Move zero columns to the start
|
||||
int read, write;
|
||||
for (read = rows, write = rows; read >= 0; read--) {
|
||||
if (!is_col_zero(cols, rows+1, near_ker, read)) {
|
||||
if (read < write) {
|
||||
swap_col(cols, rows+1, near_ker, read, write);
|
||||
}
|
||||
write--;
|
||||
}
|
||||
}
|
||||
|
||||
// Put in upper triangular form
|
||||
const int diag_shift = rows - cols + 1; // i-th diagonal is at (i+diag_shift) column
|
||||
for (int i = cols-1; i >= 0; i--) {
|
||||
for (int j = write+1; j < i+diag_shift; j++) {
|
||||
if (ibz_is_zero(&near_ker[i][j]))
|
||||
continue;
|
||||
ibz_xgcd_ann(&tmp, &U[0][0], &U[1][0], &U[0][1], &U[1][1], &near_ker[i][j], &near_ker[i][i+diag_shift]);
|
||||
gen_elem(cols, rows+1, near_ker, j, i+diag_shift, 0, i+1, &U, mod);
|
||||
ibz_set(&howell[i][j], 0);
|
||||
ibz_copy(&howell[i][i+diag_shift], &tmp);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Check that ker is indeed a kernel of mat
|
||||
ibz_t check[rows][rows+1];
|
||||
ibz_mat_init(rows, rows+1, check);
|
||||
ibz_mat_mulmod(rows, cols, rows+1, check, mat, near_ker, mod);
|
||||
for (int i = 0; i < rows; i++)
|
||||
for (int j = 0; j < rows+1; j++)
|
||||
assert(ibz_is_zero(&check[i][j]));
|
||||
ibz_mat_finalize(rows, rows+1, check);
|
||||
#endif
|
||||
|
||||
// Copy result
|
||||
for (int i = 0; i < cols; i++)
|
||||
for (int j = 0; j < cols; j++)
|
||||
ibz_copy(&ker[i][j], &near_ker[i][j+rows-cols+1]);
|
||||
// Finalize
|
||||
ibz_finalize(&tmp);
|
||||
ibz_mat_2x2_finalize(&U);
|
||||
ibz_mat_finalize(rows, rows+1, howell);
|
||||
ibz_mat_finalize(rows+1, rows+1, trans);
|
||||
ibz_mat_finalize(rows+1, rows+1, preker);
|
||||
ibz_mat_finalize(cols, rows+1, near_ker);
|
||||
}
|
||||
369
src/quaternion/ref/generic/normeq.c
Normal file
369
src/quaternion/ref/generic/normeq.c
Normal file
@@ -0,0 +1,369 @@
|
||||
#include <quaternion.h>
|
||||
#include "internal.h"
|
||||
|
||||
/** @file
|
||||
*
|
||||
* @authors Antonin Leroux
|
||||
*
|
||||
* @brief Functions related to norm equation solving or special extremal orders
|
||||
*/
|
||||
|
||||
void
|
||||
quat_lattice_O0_set(quat_lattice_t *O0)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_set(&(O0->basis[i][j]), 0);
|
||||
}
|
||||
}
|
||||
ibz_set(&(O0->denom), 2);
|
||||
ibz_set(&(O0->basis[0][0]), 2);
|
||||
ibz_set(&(O0->basis[1][1]), 2);
|
||||
ibz_set(&(O0->basis[2][2]), 1);
|
||||
ibz_set(&(O0->basis[1][2]), 1);
|
||||
ibz_set(&(O0->basis[3][3]), 1);
|
||||
ibz_set(&(O0->basis[0][3]), 1);
|
||||
}
|
||||
|
||||
void
|
||||
quat_lattice_O0_set_extremal(quat_p_extremal_maximal_order_t *O0)
|
||||
{
|
||||
ibz_set(&O0->z.coord[1], 1);
|
||||
ibz_set(&O0->t.coord[2], 1);
|
||||
ibz_set(&O0->z.denom, 1);
|
||||
ibz_set(&O0->t.denom, 1);
|
||||
O0->q = 1;
|
||||
quat_lattice_O0_set(&(O0->order));
|
||||
}
|
||||
|
||||
void
|
||||
quat_order_elem_create(quat_alg_elem_t *elem,
|
||||
const quat_p_extremal_maximal_order_t *order,
|
||||
const ibz_vec_4_t *coeffs,
|
||||
const quat_alg_t *Bpoo)
|
||||
{
|
||||
|
||||
// var dec
|
||||
quat_alg_elem_t quat_temp;
|
||||
|
||||
// var init
|
||||
quat_alg_elem_init(&quat_temp);
|
||||
|
||||
// elem = x
|
||||
quat_alg_scalar(elem, &(*coeffs)[0], &ibz_const_one);
|
||||
|
||||
// quat_temp = i*y
|
||||
quat_alg_scalar(&quat_temp, &((*coeffs)[1]), &ibz_const_one);
|
||||
quat_alg_mul(&quat_temp, &order->z, &quat_temp, Bpoo);
|
||||
|
||||
// elem = x + i*y
|
||||
quat_alg_add(elem, elem, &quat_temp);
|
||||
|
||||
// quat_temp = z * j
|
||||
quat_alg_scalar(&quat_temp, &(*coeffs)[2], &ibz_const_one);
|
||||
quat_alg_mul(&quat_temp, &order->t, &quat_temp, Bpoo);
|
||||
|
||||
// elem = x + i* + z*j
|
||||
quat_alg_add(elem, elem, &quat_temp);
|
||||
|
||||
// quat_temp = t * j * i
|
||||
quat_alg_scalar(&quat_temp, &(*coeffs)[3], &ibz_const_one);
|
||||
quat_alg_mul(&quat_temp, &order->t, &quat_temp, Bpoo);
|
||||
quat_alg_mul(&quat_temp, &quat_temp, &order->z, Bpoo);
|
||||
|
||||
// elem = x + i*y + j*z + j*i*t
|
||||
quat_alg_add(elem, elem, &quat_temp);
|
||||
|
||||
quat_alg_elem_finalize(&quat_temp);
|
||||
}
|
||||
|
||||
int
|
||||
quat_represent_integer(quat_alg_elem_t *gamma,
|
||||
const ibz_t *n_gamma,
|
||||
int non_diag,
|
||||
const quat_represent_integer_params_t *params)
|
||||
{
|
||||
|
||||
if (ibz_is_even(n_gamma)) {
|
||||
return 0;
|
||||
}
|
||||
// var dec
|
||||
int found;
|
||||
ibz_t cornacchia_target;
|
||||
ibz_t adjusted_n_gamma, q;
|
||||
ibz_t bound, sq_bound, temp;
|
||||
ibz_t test;
|
||||
ibz_vec_4_t coeffs; // coeffs = [x,y,z,t]
|
||||
quat_alg_elem_t quat_temp;
|
||||
|
||||
if (non_diag)
|
||||
assert(params->order->q % 4 == 1);
|
||||
|
||||
// var init
|
||||
found = 0;
|
||||
ibz_init(&bound);
|
||||
ibz_init(&test);
|
||||
ibz_init(&temp);
|
||||
ibz_init(&q);
|
||||
ibz_init(&sq_bound);
|
||||
ibz_vec_4_init(&coeffs);
|
||||
quat_alg_elem_init(&quat_temp);
|
||||
ibz_init(&adjusted_n_gamma);
|
||||
ibz_init(&cornacchia_target);
|
||||
|
||||
ibz_set(&q, params->order->q);
|
||||
|
||||
// this could be removed in the current state
|
||||
int standard_order = (params->order->q == 1);
|
||||
|
||||
// adjusting the norm of gamma (multiplying by 4 to find a solution in an order of odd level)
|
||||
if (non_diag || standard_order) {
|
||||
ibz_mul(&adjusted_n_gamma, n_gamma, &ibz_const_two);
|
||||
ibz_mul(&adjusted_n_gamma, &adjusted_n_gamma, &ibz_const_two);
|
||||
} else {
|
||||
ibz_copy(&adjusted_n_gamma, n_gamma);
|
||||
}
|
||||
// computation of the first bound = sqrt (adjust_n_gamma / p - q)
|
||||
ibz_div(&sq_bound, &bound, &adjusted_n_gamma, &((params->algebra)->p));
|
||||
ibz_set(&temp, params->order->q);
|
||||
ibz_sub(&sq_bound, &sq_bound, &temp);
|
||||
ibz_sqrt_floor(&bound, &sq_bound);
|
||||
|
||||
// the size of the search space is roughly n_gamma / (p√q)
|
||||
ibz_t counter;
|
||||
ibz_init(&counter);
|
||||
ibz_mul(&temp, &temp, &((params->algebra)->p));
|
||||
ibz_mul(&temp, &temp, &((params->algebra)->p));
|
||||
ibz_sqrt_floor(&temp, &temp);
|
||||
ibz_div(&counter, &temp, &adjusted_n_gamma, &temp);
|
||||
|
||||
// entering the main loop
|
||||
while (!found && ibz_cmp(&counter, &ibz_const_zero) != 0) {
|
||||
// decreasing the counter
|
||||
ibz_sub(&counter, &counter, &ibz_const_one);
|
||||
|
||||
// we start by sampling the first coordinate
|
||||
ibz_rand_interval(&coeffs[2], &ibz_const_one, &bound);
|
||||
|
||||
// then, we sample the second coordinate
|
||||
// computing the second bound in temp as sqrt( (adjust_n_gamma - p*coeffs[2]²)/qp )
|
||||
ibz_mul(&cornacchia_target, &coeffs[2], &coeffs[2]);
|
||||
ibz_mul(&temp, &cornacchia_target, &(params->algebra->p));
|
||||
ibz_sub(&temp, &adjusted_n_gamma, &temp);
|
||||
ibz_mul(&sq_bound, &q, &(params->algebra->p));
|
||||
ibz_div(&temp, &sq_bound, &temp, &sq_bound);
|
||||
ibz_sqrt_floor(&temp, &temp);
|
||||
|
||||
if (ibz_cmp(&temp, &ibz_const_zero) == 0) {
|
||||
continue;
|
||||
}
|
||||
// sampling the second value
|
||||
ibz_rand_interval(&coeffs[3], &ibz_const_one, &temp);
|
||||
|
||||
// compute cornacchia_target = n_gamma - p * (z² + q*t²)
|
||||
ibz_mul(&temp, &coeffs[3], &coeffs[3]);
|
||||
ibz_mul(&temp, &q, &temp);
|
||||
ibz_add(&cornacchia_target, &cornacchia_target, &temp);
|
||||
ibz_mul(&cornacchia_target, &cornacchia_target, &((params->algebra)->p));
|
||||
ibz_sub(&cornacchia_target, &adjusted_n_gamma, &cornacchia_target);
|
||||
assert(ibz_cmp(&cornacchia_target, &ibz_const_zero) > 0);
|
||||
|
||||
// applying cornacchia
|
||||
if (ibz_probab_prime(&cornacchia_target, params->primality_test_iterations))
|
||||
found = ibz_cornacchia_prime(&(coeffs[0]), &(coeffs[1]), &q, &cornacchia_target);
|
||||
else
|
||||
found = 0;
|
||||
|
||||
if (found && non_diag && standard_order) {
|
||||
// check that we can divide by two at least once
|
||||
// the treatmeat depends if the basis contains (1+j)/2 or (1+k)/2
|
||||
// we must have x = t mod 2 and y = z mod 2
|
||||
// if q=1 we can simply swap x and y
|
||||
if (ibz_is_odd(&coeffs[0]) != ibz_is_odd(&coeffs[3])) {
|
||||
ibz_swap(&coeffs[1], &coeffs[0]);
|
||||
}
|
||||
// we further check that (x-t)/2 = 1 mod 2 and (y-z)/2 = 1 mod 2 to ensure that the
|
||||
// resulting endomorphism will behave well for dim 2 computations
|
||||
found = found && ((ibz_get(&coeffs[0]) - ibz_get(&coeffs[3])) % 4 == 2) &&
|
||||
((ibz_get(&coeffs[1]) - ibz_get(&coeffs[2])) % 4 == 2);
|
||||
}
|
||||
if (found) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
ibz_set(&temp, (params->order->q));
|
||||
ibz_mul(&temp, &temp, &(coeffs[1]));
|
||||
ibz_mul(&temp, &temp, &(coeffs[1]));
|
||||
ibz_mul(&test, &(coeffs[0]), &(coeffs[0]));
|
||||
ibz_add(&temp, &temp, &test);
|
||||
assert(0 == ibz_cmp(&temp, &cornacchia_target));
|
||||
|
||||
ibz_mul(&cornacchia_target, &(coeffs[3]), &(coeffs[3]));
|
||||
ibz_mul(&cornacchia_target, &cornacchia_target, &(params->algebra->p));
|
||||
ibz_mul(&temp, &(coeffs[1]), &(coeffs[1]));
|
||||
ibz_add(&cornacchia_target, &cornacchia_target, &temp);
|
||||
ibz_set(&temp, (params->order->q));
|
||||
ibz_mul(&cornacchia_target, &cornacchia_target, &temp);
|
||||
ibz_mul(&temp, &(coeffs[0]), &coeffs[0]);
|
||||
ibz_add(&cornacchia_target, &cornacchia_target, &temp);
|
||||
ibz_mul(&temp, &(coeffs[2]), &coeffs[2]);
|
||||
ibz_mul(&temp, &temp, &(params->algebra->p));
|
||||
ibz_add(&cornacchia_target, &cornacchia_target, &temp);
|
||||
assert(0 == ibz_cmp(&cornacchia_target, &adjusted_n_gamma));
|
||||
#endif
|
||||
// translate x,y,z,t into the quaternion element gamma
|
||||
quat_order_elem_create(gamma, (params->order), &coeffs, (params->algebra));
|
||||
#ifndef NDEBUG
|
||||
quat_alg_norm(&temp, &(coeffs[0]), gamma, (params->algebra));
|
||||
assert(ibz_is_one(&(coeffs[0])));
|
||||
assert(0 == ibz_cmp(&temp, &adjusted_n_gamma));
|
||||
assert(quat_lattice_contains(NULL, &((params->order)->order), gamma));
|
||||
#endif
|
||||
// making gamma primitive
|
||||
// coeffs contains the coefficients of primitivized gamma in the basis of order
|
||||
quat_alg_make_primitive(&coeffs, &temp, gamma, &((params->order)->order));
|
||||
|
||||
if (non_diag || standard_order)
|
||||
found = (ibz_cmp(&temp, &ibz_const_two) == 0);
|
||||
else
|
||||
found = (ibz_cmp(&temp, &ibz_const_one) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
// new gamma
|
||||
ibz_mat_4x4_eval(&coeffs, &(((params->order)->order).basis), &coeffs);
|
||||
ibz_copy(&gamma->coord[0], &coeffs[0]);
|
||||
ibz_copy(&gamma->coord[1], &coeffs[1]);
|
||||
ibz_copy(&gamma->coord[2], &coeffs[2]);
|
||||
ibz_copy(&gamma->coord[3], &coeffs[3]);
|
||||
ibz_copy(&gamma->denom, &(((params->order)->order).denom));
|
||||
}
|
||||
// var finalize
|
||||
ibz_finalize(&counter);
|
||||
ibz_finalize(&bound);
|
||||
ibz_finalize(&temp);
|
||||
ibz_finalize(&sq_bound);
|
||||
ibz_vec_4_finalize(&coeffs);
|
||||
quat_alg_elem_finalize(&quat_temp);
|
||||
ibz_finalize(&adjusted_n_gamma);
|
||||
ibz_finalize(&cornacchia_target);
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&test);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
int
|
||||
quat_sampling_random_ideal_O0_given_norm(quat_left_ideal_t *lideal,
|
||||
const ibz_t *norm,
|
||||
int is_prime,
|
||||
const quat_represent_integer_params_t *params,
|
||||
const ibz_t *prime_cofactor)
|
||||
{
|
||||
|
||||
ibz_t n_temp, norm_d;
|
||||
ibz_t disc;
|
||||
quat_alg_elem_t gen, gen_rerand;
|
||||
int found = 0;
|
||||
ibz_init(&n_temp);
|
||||
ibz_init(&norm_d);
|
||||
ibz_init(&disc);
|
||||
quat_alg_elem_init(&gen);
|
||||
quat_alg_elem_init(&gen_rerand);
|
||||
|
||||
// when the norm is prime we can be quite efficient
|
||||
// by avoiding to run represent integer
|
||||
// the first step is to generate one ideal of the correct norm
|
||||
if (is_prime) {
|
||||
|
||||
// we find a quaternion element of norm divisible by norm
|
||||
while (!found) {
|
||||
// generating a trace-zero element at random
|
||||
ibz_set(&gen.coord[0], 0);
|
||||
ibz_sub(&n_temp, norm, &ibz_const_one);
|
||||
for (int i = 1; i < 4; i++)
|
||||
ibz_rand_interval(&gen.coord[i], &ibz_const_zero, &n_temp);
|
||||
|
||||
// first, we compute the norm of the gen
|
||||
quat_alg_norm(&n_temp, &norm_d, &gen, (params->algebra));
|
||||
assert(ibz_is_one(&norm_d));
|
||||
|
||||
// and finally the negation mod norm
|
||||
ibz_neg(&disc, &n_temp);
|
||||
ibz_mod(&disc, &disc, norm);
|
||||
// now we check that -n is a square mod norm
|
||||
// and if the square root exists we compute it
|
||||
found = ibz_sqrt_mod_p(&gen.coord[0], &disc, norm);
|
||||
found = found && !quat_alg_elem_is_zero(&gen);
|
||||
}
|
||||
} else {
|
||||
assert(prime_cofactor != NULL);
|
||||
// if it is not prime or we don't know if it is prime, we may just use represent integer
|
||||
// and use a precomputed prime as cofactor
|
||||
assert(!ibz_is_zero(norm));
|
||||
ibz_mul(&n_temp, prime_cofactor, norm);
|
||||
found = quat_represent_integer(&gen, &n_temp, 0, params);
|
||||
found = found && !quat_alg_elem_is_zero(&gen);
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
if (found) {
|
||||
// first, we compute the norm of the gen
|
||||
quat_alg_norm(&n_temp, &norm_d, &gen, (params->algebra));
|
||||
assert(ibz_is_one(&norm_d));
|
||||
ibz_mod(&n_temp, &n_temp, norm);
|
||||
assert(ibz_cmp(&n_temp, &ibz_const_zero) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// now we just have to rerandomize the class of the ideal generated by gen
|
||||
found = 0;
|
||||
while (!found) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_rand_interval(&gen_rerand.coord[i], &ibz_const_one, norm);
|
||||
}
|
||||
quat_alg_norm(&n_temp, &norm_d, &gen_rerand, (params->algebra));
|
||||
assert(ibz_is_one(&norm_d));
|
||||
ibz_gcd(&disc, &n_temp, norm);
|
||||
found = ibz_is_one(&disc);
|
||||
found = found && !quat_alg_elem_is_zero(&gen_rerand);
|
||||
}
|
||||
|
||||
quat_alg_mul(&gen, &gen, &gen_rerand, (params->algebra));
|
||||
// in both cases, whether norm is prime or not prime,
|
||||
// gen is not divisible by any integer factor of the target norm
|
||||
// therefore the call below will yield an ideal of the correct norm
|
||||
quat_lideal_create(lideal, &gen, norm, &((params->order)->order), (params->algebra));
|
||||
assert(ibz_cmp(norm, &(lideal->norm)) == 0);
|
||||
|
||||
ibz_finalize(&n_temp);
|
||||
quat_alg_elem_finalize(&gen);
|
||||
quat_alg_elem_finalize(&gen_rerand);
|
||||
ibz_finalize(&norm_d);
|
||||
ibz_finalize(&disc);
|
||||
return (found);
|
||||
}
|
||||
|
||||
void
|
||||
quat_change_to_O0_basis(ibz_vec_4_t *vec, const quat_alg_elem_t *el)
|
||||
{
|
||||
ibz_t tmp;
|
||||
ibz_init(&tmp);
|
||||
ibz_copy(&(*vec)[2], &el->coord[2]);
|
||||
ibz_add(&(*vec)[2], &(*vec)[2], &(*vec)[2]); // double (not optimal if el->denom is even...)
|
||||
ibz_copy(&(*vec)[3], &el->coord[3]); // double (not optimal if el->denom is even...)
|
||||
ibz_add(&(*vec)[3], &(*vec)[3], &(*vec)[3]);
|
||||
ibz_sub(&(*vec)[0], &el->coord[0], &el->coord[3]);
|
||||
ibz_sub(&(*vec)[1], &el->coord[1], &el->coord[2]);
|
||||
|
||||
assert(ibz_divides(&(*vec)[0], &el->denom));
|
||||
assert(ibz_divides(&(*vec)[1], &el->denom));
|
||||
assert(ibz_divides(&(*vec)[2], &el->denom));
|
||||
assert(ibz_divides(&(*vec)[3], &el->denom));
|
||||
|
||||
ibz_div(&(*vec)[0], &tmp, &(*vec)[0], &el->denom);
|
||||
ibz_div(&(*vec)[1], &tmp, &(*vec)[1], &el->denom);
|
||||
ibz_div(&(*vec)[2], &tmp, &(*vec)[2], &el->denom);
|
||||
ibz_div(&(*vec)[3], &tmp, &(*vec)[3], &el->denom);
|
||||
|
||||
ibz_finalize(&tmp);
|
||||
}
|
||||
@@ -1,158 +1,132 @@
|
||||
#include <quaternion.h>
|
||||
#include <stdio.h>
|
||||
#include "internal.h"
|
||||
|
||||
void ibz_mat_2x2_print(const ibz_mat_2x2_t *mat){
|
||||
ibz_printf("matrix: ");
|
||||
for(int i = 0; i < 2; i++){
|
||||
for(int j = 0; j < 2; j++){
|
||||
ibz_printf("%Zd ", &((*mat)[i][j]));
|
||||
void
|
||||
ibz_mat_2x2_print(const ibz_mat_2x2_t *mat)
|
||||
{
|
||||
printf("matrix: ");
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
ibz_print(&((*mat)[i][j]), 10);
|
||||
printf(" ");
|
||||
}
|
||||
ibz_printf("\n ");
|
||||
printf("\n ");
|
||||
}
|
||||
ibz_printf("\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void ibz_mat_4x4_print(const ibz_mat_4x4_t *mat){
|
||||
ibz_printf("matrix: ");
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_printf("%Zd ", &((*mat)[i][j]));
|
||||
void
|
||||
ibz_mat_4x4_print(const ibz_mat_4x4_t *mat)
|
||||
{
|
||||
printf("matrix: ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_print(&((*mat)[i][j]), 10);
|
||||
printf(" ");
|
||||
}
|
||||
ibz_printf("\n ");
|
||||
printf("\n ");
|
||||
}
|
||||
ibz_printf("\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void ibz_mat_4x5_print(const ibz_mat_4x5_t *mat){
|
||||
ibz_printf("matrix: ");
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 5; j++){
|
||||
ibz_printf("%Zd ", &((*mat)[i][j]));
|
||||
void
|
||||
ibz_vec_2_print(const ibz_vec_2_t *vec)
|
||||
{
|
||||
printf("vector: ");
|
||||
for (int i = 0; i < 2; i++) {
|
||||
ibz_print(&((*vec)[i]), 10);
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void
|
||||
ibz_vec_4_print(const ibz_vec_4_t *vec)
|
||||
{
|
||||
printf("vector: ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_print(&((*vec)[i]), 10);
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void
|
||||
quat_lattice_print(const quat_lattice_t *lat)
|
||||
{
|
||||
printf("lattice\n");
|
||||
printf("denominator: ");
|
||||
ibz_print(&(lat->denom), 10);
|
||||
printf("\n");
|
||||
printf("basis: ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_print(&((lat->basis)[i][j]), 10);
|
||||
printf(" ");
|
||||
}
|
||||
ibz_printf("\n ");
|
||||
printf("\n ");
|
||||
}
|
||||
ibz_printf("\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void ibz_mat_4x8_print(const ibz_mat_4x8_t *mat){
|
||||
ibz_printf("matrix: ");
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 8; j++){
|
||||
ibz_printf("%Zd ", &((*mat)[i][j]));
|
||||
void
|
||||
quat_alg_print(const quat_alg_t *alg)
|
||||
{
|
||||
printf("quaternion algebra ramified at ");
|
||||
ibz_print(&(alg->p), 10);
|
||||
printf(" and infinity\n\n");
|
||||
}
|
||||
|
||||
void
|
||||
quat_alg_elem_print(const quat_alg_elem_t *elem)
|
||||
{
|
||||
printf("denominator: ");
|
||||
ibz_print(&(elem->denom), 10);
|
||||
printf("\n");
|
||||
printf("coordinates: ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_print(&((elem->coord)[i]), 10);
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void
|
||||
quat_left_ideal_print(const quat_left_ideal_t *lideal)
|
||||
{
|
||||
printf("left ideal\n");
|
||||
printf("norm: ");
|
||||
ibz_print(&(lideal->norm), 10);
|
||||
printf("\n");
|
||||
printf("denominator: ");
|
||||
ibz_print(&(lideal->lattice.denom), 10);
|
||||
printf("\n");
|
||||
printf("basis: ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_print(&((lideal->lattice.basis)[i][j]), 10);
|
||||
printf(" ");
|
||||
}
|
||||
ibz_printf("\n ");
|
||||
}
|
||||
ibz_printf("\n");
|
||||
}
|
||||
|
||||
void ibz_mat_print(int rows, int cols, const ibz_t mat[rows][cols]){
|
||||
ibz_printf("matrix: ");
|
||||
for(int i = 0; i < rows; i++){
|
||||
for(int j = 0; j < cols; j++){
|
||||
ibz_printf("%Zd ", &mat[i][j]);
|
||||
if (i != 3) {
|
||||
printf("\n ");
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
ibz_printf("\n ");
|
||||
}
|
||||
ibz_printf("\n");
|
||||
}
|
||||
|
||||
|
||||
void ibz_vec_2_print(const ibz_vec_2_t *vec){
|
||||
ibz_printf("vector: ");
|
||||
for(int i = 0; i < 2; i++){
|
||||
ibz_printf("%Zd ", &((*vec)[i]));
|
||||
}
|
||||
ibz_printf("\n\n");
|
||||
}
|
||||
|
||||
void ibz_vec_4_print(const ibz_vec_4_t *vec){
|
||||
ibz_printf("vector: ");
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_printf("%Zd ", &((*vec)[i]));
|
||||
}
|
||||
ibz_printf("\n\n");
|
||||
}
|
||||
void ibz_vec_5_print(const ibz_vec_5_t *vec){
|
||||
ibz_printf("vector: ");
|
||||
for(int i = 0; i < 5; i++){
|
||||
ibz_printf("%Zd ", &((*vec)[i]));
|
||||
}
|
||||
ibz_printf("\n\n");
|
||||
}
|
||||
|
||||
|
||||
void quat_lattice_print(const quat_lattice_t *lat){
|
||||
ibz_printf("lattice\n");
|
||||
ibz_printf("denominator: %Zd\n",(lat->denom));
|
||||
ibz_printf("basis: ");
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_printf("%Zd ", &((lat->basis)[i][j]));
|
||||
if ((lideal->parent_order) != NULL) {
|
||||
printf("parent order denominator: ");
|
||||
ibz_print(&(lideal->parent_order->denom), 10);
|
||||
printf("\n");
|
||||
printf("parent order basis: ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_print(&((lideal->parent_order->basis)[i][j]), 10);
|
||||
printf(" ");
|
||||
}
|
||||
ibz_printf("\n ");
|
||||
}
|
||||
ibz_printf("\n");
|
||||
}
|
||||
|
||||
void quat_alg_print(const quat_alg_t *alg){
|
||||
ibz_printf("quaternion algebra ramified at %Zd and infinity\n\n", &(alg->p));
|
||||
}
|
||||
|
||||
void quat_alg_elem_print(const quat_alg_elem_t *elem){
|
||||
ibz_printf("denominator: %Zd\n",(elem->denom));
|
||||
ibz_printf("coordinates: ");
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_printf("%Zd ",&((elem->coord)[i]));
|
||||
}
|
||||
ibz_printf("\n\n");
|
||||
}
|
||||
|
||||
void quat_alg_coord_print(const quat_alg_coord_t *coord){
|
||||
ibz_printf("coordinates: ");
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_printf("%Zd ",&((*coord)[i]));
|
||||
}
|
||||
ibz_printf("\n\n");
|
||||
}
|
||||
|
||||
void quat_order_print(const quat_order_t *order){
|
||||
ibz_printf("order\n");
|
||||
ibz_printf("denominator: %Zd\n",&(order->denom));
|
||||
ibz_printf("basis: ");
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_printf("%Zd ", &((order->basis)[i][j]));
|
||||
}
|
||||
ibz_printf("\n ");
|
||||
}
|
||||
ibz_printf("\n");
|
||||
}
|
||||
|
||||
void quat_left_ideal_print(const quat_left_ideal_t *lideal){
|
||||
ibz_printf("left ideal\n");
|
||||
ibz_printf("norm : %Zd\n",&(lideal->norm));
|
||||
ibz_printf("denominator: %Zd\n",&(lideal->lattice.denom));
|
||||
ibz_printf("basis: ");
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_printf("%Zd ", &((lideal->lattice.basis)[i][j]));
|
||||
}
|
||||
if(i!=3){
|
||||
ibz_printf("\n ");
|
||||
} else {
|
||||
ibz_printf("\n");
|
||||
}
|
||||
}
|
||||
if((lideal->parent_order )!= NULL){
|
||||
ibz_printf("parent order denominator: %Zd\n",&(lideal->parent_order->denom));
|
||||
ibz_printf("parent order basis: ");
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_printf("%Zd ", &((lideal->parent_order->basis)[i][j]));
|
||||
}
|
||||
ibz_printf("\n ");
|
||||
printf("\n ");
|
||||
}
|
||||
} else {
|
||||
ibz_printf("Parent order not given!\n");
|
||||
printf("Parent order not given!\n");
|
||||
}
|
||||
ibz_printf("\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -1,21 +1,40 @@
|
||||
set(SOURCE_FILES_QUATERNION_GENERIC_REF_TESTS
|
||||
set(SOURCE_FILES_QUATERNION_GENERIC_REF
|
||||
intbig.c
|
||||
algebra.c
|
||||
ideal.c
|
||||
dim4.c
|
||||
dim2.c
|
||||
integers.c
|
||||
lattice.c
|
||||
lat_ball.c
|
||||
finit.c
|
||||
matkermod.c
|
||||
mini-gmp.c
|
||||
normeq.c
|
||||
randomized.c
|
||||
test_quaternions.c
|
||||
)
|
||||
add_executable(sqisign_test_quaternion ${SOURCE_FILES_QUATERNION_GENERIC_REF_TESTS})
|
||||
target_link_libraries(sqisign_test_quaternion ${LIB_INTBIG} ${LIB_QUATERNION} ${GMP} sqisign_common_sys )
|
||||
target_include_directories(sqisign_test_quaternion PRIVATE ${INC_INTBIG} ${INC_COMMON} ${INC_QUATERNION} ${INC_PUBLIC} )
|
||||
|
||||
if (NOT GMP_LIBRARY STREQUAL "MINI")
|
||||
list(APPEND SOURCE_FILES_QUATERNION_GENERIC_REF ${PROJECT_SOURCE_DIR}/src/mini-gmp/mini-gmp-extra.c)
|
||||
endif()
|
||||
|
||||
set(SOURCE_FILES_QUATERNION_GENERIC_REF_TESTS
|
||||
${SOURCE_FILES_QUATERNION_GENERIC_REF}
|
||||
../hnf/hnf_tests.c
|
||||
../lll/lll_verification.c
|
||||
../lll/lll_tests.c
|
||||
)
|
||||
add_executable(sqisign_test_quaternion ${SOURCE_FILES_QUATERNION_GENERIC_REF_TESTS} test_quaternions.c)
|
||||
target_link_libraries(sqisign_test_quaternion ${LIB_QUATERNION} ${GMP} sqisign_common_sys)
|
||||
target_include_directories(sqisign_test_quaternion PRIVATE ../internal_quaternion_headers ${INC_COMMON} ${INC_QUATERNION} ${INC_PUBLIC} ${PROJECT_SOURCE_DIR}/src/mini-gmp)
|
||||
|
||||
add_executable(sqisign_bm_quaternion ${SOURCE_FILES_QUATERNION_GENERIC_REF_TESTS} ../lll/lll_benchmarks.c)
|
||||
target_link_libraries(sqisign_bm_quaternion ${LIB_QUATERNION} ${GMP} sqisign_common_test)
|
||||
target_include_directories(sqisign_bm_quaternion PRIVATE ../internal_quaternion_headers ${INC_COMMON} ${INC_QUATERNION} ${INC_PUBLIC} ${PROJECT_SOURCE_DIR}/src/mini-gmp)
|
||||
|
||||
# MSAN and GMP lead to false positives, see
|
||||
# https://gmplib.org/list-archives/gmp-bugs/2019-March/004529.html
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "MSAN")
|
||||
add_test(sqisign_test_quaternion sqisign_test_quaternion)
|
||||
endif()
|
||||
|
||||
set(BM_BINS ${BM_BINS} sqisign_bm_quaternion CACHE INTERNAL "List of benchmark executables")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,276 +2,193 @@
|
||||
|
||||
// Schema of tests: initialize structure, assign values, finalize
|
||||
|
||||
//void quat_alg_init(quat_alg_t *alg);
|
||||
//void quat_alg_finalize(quat_alg_t *alg);
|
||||
int quat_test_finit_alg(){
|
||||
// void quat_alg_init(quat_alg_t *alg);
|
||||
// void quat_alg_finalize(quat_alg_t *alg);
|
||||
int
|
||||
quat_test_finit_alg(void)
|
||||
{
|
||||
int res = 0;
|
||||
quat_alg_t alg;
|
||||
ibz_t p;
|
||||
ibz_mat_4x4_t cmp;
|
||||
ibz_mat_4x4_init(&cmp);
|
||||
ibz_init(&p);
|
||||
ibz_set(&p,7);
|
||||
ibz_set(&p, 7);
|
||||
quat_alg_init_set(&alg, &p);
|
||||
res = res || ibz_cmp(&(alg.p),&p);
|
||||
ibz_mat_4x4_identity(&cmp);
|
||||
ibz_copy(&(cmp[2][2]),&p);
|
||||
ibz_copy(&(cmp[3][3]),&p);
|
||||
res = res || !ibz_mat_4x4_equal(&cmp,&(alg.gram));
|
||||
if (res != 0){
|
||||
res = res || ibz_cmp(&(alg.p), &p);
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test finit_alg failed\n");
|
||||
}
|
||||
ibz_mat_4x4_finalize(&cmp);
|
||||
ibz_finalize(&p);
|
||||
quat_alg_finalize(&alg);
|
||||
return res;
|
||||
}
|
||||
|
||||
//void quat_alg_elem_init(quat_alg_elem_t *elem);
|
||||
//void quat_alg_elem_finalize(quat_alg_elem_t *elem);
|
||||
int quat_test_finit_alg_elem(){
|
||||
// void quat_alg_elem_init(quat_alg_elem_t *elem);
|
||||
// void quat_alg_elem_finalize(quat_alg_elem_t *elem);
|
||||
int
|
||||
quat_test_finit_alg_elem(void)
|
||||
{
|
||||
quat_alg_elem_t elem;
|
||||
int res;
|
||||
quat_alg_elem_init(&elem);
|
||||
ibz_set(&(elem.coord[0]),0);
|
||||
ibz_set(&(elem.coord[1]),1);
|
||||
ibz_set(&(elem.coord[2]),2);
|
||||
ibz_set(&(elem.coord[3]),3);
|
||||
ibz_set(&(elem.denom),1);
|
||||
res = 1-(1==ibz_is_one(&(elem.denom)));
|
||||
for(int i = 0; i <4; i++){
|
||||
res = res || (i!=ibz_get(&(elem.coord[i])));
|
||||
ibz_set(&(elem.coord[0]), 0);
|
||||
ibz_set(&(elem.coord[1]), 1);
|
||||
ibz_set(&(elem.coord[2]), 2);
|
||||
ibz_set(&(elem.coord[3]), 3);
|
||||
ibz_set(&(elem.denom), 1);
|
||||
res = 1 - (1 == ibz_is_one(&(elem.denom)));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
res = res || (ibz_cmp_int32(&(elem.coord[i]), i) != 0);
|
||||
}
|
||||
if (res != 0){
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test finit_alg_elem failed\n");
|
||||
}
|
||||
quat_alg_elem_finalize(&elem);
|
||||
return res;
|
||||
}
|
||||
|
||||
//void quat_alg_coord_init(quat_alg_coord_t *coord);
|
||||
//void quat_alg_coord_finalize(quat_alg_coord_t *coord);
|
||||
int quat_test_finit_alg_coord(){
|
||||
quat_alg_coord_t coord;
|
||||
// void ibz_vec_2_init(ibz_vec_2_t *vec);
|
||||
// void ibz_vec_2_finalize(ibz_vec_2_t *vec);
|
||||
int
|
||||
quat_test_finit_ibz_vec_2(void)
|
||||
{
|
||||
ibz_vec_2_t vec;
|
||||
int res = 0;
|
||||
quat_alg_coord_init(&coord);
|
||||
ibz_set(&(coord[0]),0);
|
||||
ibz_set(&(coord[1]),1);
|
||||
ibz_set(&(coord[2]),2);
|
||||
ibz_set(&(coord[3]),3);
|
||||
for(int i = 0; i <4; i++){
|
||||
res = res || (i!=ibz_get(&(coord[i])));
|
||||
ibz_vec_2_init(&vec);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
ibz_set(&(vec[i]), i);
|
||||
}
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test finit_alg_coord failed\n");
|
||||
for (int i = 0; i < 2; i++) {
|
||||
res = res || (ibz_cmp_int32(&(vec[i]), i) != 0);
|
||||
}
|
||||
quat_alg_coord_finalize(&coord);
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test finit_ibz_vec_2 failed\n");
|
||||
}
|
||||
ibz_vec_2_finalize(&vec);
|
||||
return res;
|
||||
}
|
||||
|
||||
//void ibz_vec_4_init(ibz_vec_4_t *vec);
|
||||
//void ibz_vec_4_finalize(ibz_vec_4_t *vec);
|
||||
int quat_test_finit_ibz_vec_4(){
|
||||
// void ibz_vec_4_init(ibz_vec_4_t *vec);
|
||||
// void ibz_vec_4_finalize(ibz_vec_4_t *vec);
|
||||
int
|
||||
quat_test_finit_ibz_vec_4(void)
|
||||
{
|
||||
ibz_vec_4_t vec;
|
||||
int res = 0;
|
||||
ibz_vec_4_init(&vec);
|
||||
for(int i = 0; i <4; i++){
|
||||
ibz_set(&(vec[i]),i);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_set(&(vec[i]), i);
|
||||
}
|
||||
for(int i = 0; i <4; i++){
|
||||
res = res || (i!=ibz_get(&(vec[i])));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
res = res || (ibz_cmp_int32(&(vec[i]), i) != 0);
|
||||
}
|
||||
if (res != 0){
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test finit_ibz_vec_4 failed\n");
|
||||
}
|
||||
ibz_vec_4_finalize(&vec);
|
||||
return res;
|
||||
}
|
||||
|
||||
//void ibz_vec_5_init(ibz_vec_5_t *vec);
|
||||
//void ibz_vec_5_finalize(ibz_vec_5_t *vec);
|
||||
int quat_test_finit_ibz_vec_5(){
|
||||
ibz_vec_5_t vec;
|
||||
int res = 0;
|
||||
ibz_vec_5_init(&vec);
|
||||
for(int i = 0; i <5; i++){
|
||||
ibz_set(&(vec[i]),i);
|
||||
}
|
||||
for(int i = 0; i <5; i++){
|
||||
res = res || (i!=ibz_get(&(vec[i])));
|
||||
}
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test finit_ibz_vec_5 failed\n");
|
||||
}
|
||||
ibz_vec_5_finalize(&vec);
|
||||
return res;
|
||||
}
|
||||
|
||||
//void ibz_mat_2x2_init(ibz_mat_2x2_t *mat);
|
||||
//void ibz_mat_2x2_finalize(ibz_mat_2x2_t *mat);
|
||||
int quat_test_finit_ibz_mat_2x2(){
|
||||
// void ibz_mat_2x2_init(ibz_mat_2x2_t *mat);
|
||||
// void ibz_mat_2x2_finalize(ibz_mat_2x2_t *mat);
|
||||
int
|
||||
quat_test_finit_ibz_mat_2x2(void)
|
||||
{
|
||||
ibz_mat_2x2_t mat;
|
||||
int res = 0;
|
||||
ibz_mat_2x2_init(&mat);
|
||||
for (int i = 0; i < 2; i++){
|
||||
for (int j = 0; j < 2; j++){
|
||||
ibz_set(&(mat[i][j]),i+j);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
ibz_set(&(mat[i][j]), i + j);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i <2; i++){
|
||||
for (int j = 0; j < 2; j++){
|
||||
res = res || (i+j!=ibz_get(&(mat[i][j])));
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
res = res || (ibz_cmp_int32(&(mat[i][j]), i + j) != 0);
|
||||
}
|
||||
}
|
||||
if (res != 0){
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test finit_ibz_mat_2x2 failed\n");
|
||||
}
|
||||
ibz_mat_2x2_finalize(&mat);
|
||||
return res;
|
||||
}
|
||||
|
||||
//void ibz_mat_4x4_init(ibz_mat_4x4_t *mat);
|
||||
//void ibz_mat_4x4_finalize(ibz_mat_4x4_t *mat);
|
||||
int quat_test_finit_ibz_mat_4x4(){
|
||||
// void ibz_mat_4x4_init(ibz_mat_4x4_t *mat);
|
||||
// void ibz_mat_4x4_finalize(ibz_mat_4x4_t *mat);
|
||||
int
|
||||
quat_test_finit_ibz_mat_4x4(void)
|
||||
{
|
||||
ibz_mat_4x4_t mat;
|
||||
int res = 0;
|
||||
ibz_mat_4x4_init(&mat);
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
ibz_set(&(mat[i][j]),i+j);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_set(&(mat[i][j]), i + j);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i <4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
res = res || (i+j!=ibz_get(&(mat[i][j])));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
res = res || (ibz_cmp_int32(&(mat[i][j]), i + j) != 0);
|
||||
}
|
||||
}
|
||||
if (res != 0){
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test finit_ibz_mat_4x4 failed\n");
|
||||
}
|
||||
ibz_mat_4x4_finalize(&mat);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//void ibz_mat_4x5_init(ibz_mat_4x5_t *mat);
|
||||
//void ibz_mat_4x5_finalize(ibz_mat_4x5_t *mat);
|
||||
int quat_test_finit_ibz_mat_4x5(){
|
||||
ibz_mat_4x5_t mat;
|
||||
int res = 0;
|
||||
ibz_mat_4x5_init(&mat);
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 5; j++){
|
||||
ibz_set(&(mat[i][j]),i+j);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i <4; i++){
|
||||
for (int j = 0; j < 5; j++){
|
||||
res = res || (i+j!=ibz_get(&(mat[i][j])));
|
||||
}
|
||||
}
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test finit_ibz_mat_4x5 failed\n");
|
||||
}
|
||||
ibz_mat_4x5_finalize(&mat);
|
||||
return res;
|
||||
}
|
||||
|
||||
//void ibz_mat_4x8_init(ibz_mat_4x8_t *mat);
|
||||
//void ibz_mat_4x8_finalize(ibz_mat_4x8_t *mat);
|
||||
int quat_test_finit_ibz_mat_4x8(){
|
||||
ibz_mat_4x8_t mat;
|
||||
int res = 0;
|
||||
ibz_mat_4x8_init(&mat);
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 8; j++){
|
||||
ibz_set(&(mat[i][j]),i+j);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i <4; i++){
|
||||
for (int j = 0; j < 8; j++){
|
||||
res = res || (i+j!=ibz_get(&(mat[i][j])));
|
||||
}
|
||||
}
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test finit_ibz_mat_4x8 failed\n");
|
||||
}
|
||||
ibz_mat_4x8_finalize(&mat);
|
||||
return res;
|
||||
}
|
||||
|
||||
//void quat_lattice_init(quat_lattice_t *lat);
|
||||
//void quat_lattice_finalize(quat_lattice_t *lat);
|
||||
int quat_test_finit_lattice(){
|
||||
// void quat_lattice_init(quat_lattice_t *lat);
|
||||
// void quat_lattice_finalize(quat_lattice_t *lat);
|
||||
int
|
||||
quat_test_finit_lattice(void)
|
||||
{
|
||||
quat_lattice_t lat;
|
||||
int res = 0;
|
||||
quat_lattice_init(&lat);
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
ibz_set(&(lat.basis[i][j]),i+j);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_set(&(lat.basis[i][j]), i + j);
|
||||
}
|
||||
}
|
||||
ibz_set(&(lat.denom),1);
|
||||
res = 1-(1==ibz_is_one(&(lat.denom)));
|
||||
for(int i = 0; i <4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
res = res || (i+j!=ibz_get(&(lat.basis[i][j])));
|
||||
ibz_set(&(lat.denom), 1);
|
||||
res = 1 - (1 == ibz_is_one(&(lat.denom)));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
res = res || (ibz_cmp_int32(&(lat.basis[i][j]), i + j) != 0);
|
||||
}
|
||||
}
|
||||
if (res != 0){
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test finit_alg_lattice failed\n");
|
||||
}
|
||||
quat_lattice_finalize(&lat);
|
||||
return res;
|
||||
}
|
||||
|
||||
//void quat_order_init(quat_order_t *order);
|
||||
//void quat_order_finalize(quat_order_t *order);
|
||||
int quat_test_finit_order(){
|
||||
quat_order_t order;
|
||||
int res = 0;
|
||||
quat_order_init(&order);
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
ibz_set(&(order.basis[i][j]),i+j);
|
||||
}
|
||||
}
|
||||
ibz_set(&(order.denom),1);
|
||||
res = 1-(1==ibz_is_one(&(order.denom)));
|
||||
for(int i = 0; i <4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
res = res || (i+j!=ibz_get(&(order.basis[i][j])));
|
||||
}
|
||||
}
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test finit_alg_order failed\n");
|
||||
}
|
||||
quat_order_finalize(&order);
|
||||
return res;
|
||||
}
|
||||
|
||||
//void quat_left_ideal_init(quat_left_ideal_t *lideal);
|
||||
//void quat_left_ideal_finalize(quat_left_ideal_t *lideal);
|
||||
int quat_test_finit_lideal(){
|
||||
// void quat_left_ideal_init(quat_left_ideal_t *lideal);
|
||||
// void quat_left_ideal_finalize(quat_left_ideal_t *lideal);
|
||||
int
|
||||
quat_test_finit_lideal(void)
|
||||
{
|
||||
quat_left_ideal_t lideal;
|
||||
int res = 0;
|
||||
quat_left_ideal_init(&lideal);
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
ibz_set(&(lideal.lattice.basis[i][j]),i+j);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_set(&(lideal.lattice.basis[i][j]), i + j);
|
||||
}
|
||||
}
|
||||
ibz_set(&(lideal.lattice.denom),1);
|
||||
ibz_set(&(lideal.norm),5);
|
||||
ibz_set(&(lideal.lattice.denom), 1);
|
||||
ibz_set(&(lideal.norm), 5);
|
||||
lideal.parent_order = NULL;
|
||||
res = 1-(1==ibz_is_one(&(lideal.lattice.denom)));
|
||||
for(int i = 0; i <4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
res = res || (i+j!=ibz_get(&(lideal.lattice.basis[i][j])));
|
||||
res = 1 - (1 == ibz_is_one(&(lideal.lattice.denom)));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
res = res || (ibz_cmp_int32(&(lideal.lattice.basis[i][j]), i + j) != 0);
|
||||
}
|
||||
}
|
||||
res = res || (5!=ibz_get(&(lideal.norm)));
|
||||
if (res != 0){
|
||||
res = res || (ibz_cmp_int32(&(lideal.norm), 5) != 0);
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test finit_alg_lideal failed\n");
|
||||
}
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
@@ -279,21 +196,18 @@ int quat_test_finit_lideal(){
|
||||
}
|
||||
|
||||
// run all previous tests
|
||||
int quat_test_finit(){
|
||||
int
|
||||
quat_test_finit(void)
|
||||
{
|
||||
int res = 0;
|
||||
printf("\nRunning quaternion tests of initializers and finalizers\n");
|
||||
res = res | quat_test_finit_alg();
|
||||
res = res | quat_test_finit_alg_elem();
|
||||
res = res | quat_test_finit_alg_coord();
|
||||
res = res | quat_test_finit_ibz_vec_2();
|
||||
res = res | quat_test_finit_ibz_vec_4();
|
||||
res = res | quat_test_finit_ibz_vec_5();
|
||||
res = res | quat_test_finit_ibz_mat_2x2();
|
||||
res = res | quat_test_finit_ibz_mat_4x4();
|
||||
res = res | quat_test_finit_ibz_mat_4x5();
|
||||
res = res | quat_test_finit_ibz_mat_4x8();
|
||||
res = res | quat_test_finit_lattice();
|
||||
res = res | quat_test_finit_order();
|
||||
res = res | quat_test_finit_lideal();
|
||||
return(res);
|
||||
return (res);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
977
src/quaternion/ref/generic/test/intbig.c
Normal file
977
src/quaternion/ref/generic/test/intbig.c
Normal file
@@ -0,0 +1,977 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <rng.h>
|
||||
#include "intbig_internal.h"
|
||||
|
||||
// void ibz_init(ibz_t *x);
|
||||
// void ibz_finalize(ibz_t *x);
|
||||
// int ibz_cmp(const ibz_t *a, const ibz_t *b);
|
||||
// int ibz_is_zero(const ibz_t *x);
|
||||
// int ibz_is_one(const ibz_t *x);
|
||||
// int ibz_cmp_int32(const ibz_t *x, int32_t y);
|
||||
// int ibz_is_even(const ibz_t *x);
|
||||
// int ibz_is_odd(const ibz_t *x);
|
||||
// void ibz_set(ibz_t *i, int32_t x);
|
||||
// void ibz_copy(ibz_t *target, const ibz_t *value);
|
||||
// void ibz_swap(ibz_t *a, ibz_t *b);
|
||||
// int32_t ibz_get(const ibz_t *i);
|
||||
// int ibz_bitsize(const ibz_t *a);
|
||||
int
|
||||
ibz_test_init_set_cmp()
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t a, b, c;
|
||||
ibz_init(&a);
|
||||
ibz_init(&b);
|
||||
ibz_init(&c);
|
||||
|
||||
res = res | !ibz_is_zero(&a);
|
||||
ibz_set(&a, 1);
|
||||
res = res | !ibz_is_one(&a);
|
||||
res = res | ibz_is_zero(&a);
|
||||
res = res | (0 != ibz_cmp(&b, &c));
|
||||
res = res | (0 == ibz_cmp(&a, &c));
|
||||
res = res | ibz_is_even(&a);
|
||||
res = res | !ibz_is_odd(&a);
|
||||
res = res | !ibz_is_even(&b);
|
||||
res = res | ibz_is_odd(&b);
|
||||
ibz_copy(&b, &a);
|
||||
res = res | !ibz_is_one(&a);
|
||||
res = res | !ibz_is_one(&b);
|
||||
res = res | (0 != ibz_cmp(&a, &b));
|
||||
res = res | (0 == ibz_cmp(&c, &b));
|
||||
ibz_swap(&b, &c);
|
||||
res = res | (0 == ibz_cmp(&a, &b));
|
||||
res = res | (0 == ibz_cmp(&c, &b));
|
||||
res = res | (0 != ibz_cmp(&a, &c));
|
||||
res = res | (ibz_bitsize(&a) != 1);
|
||||
res = res | (ibz_get(&a) != 1);
|
||||
res = res | (ibz_cmp_int32(&a, 1) != 0);
|
||||
res = res | (ibz_bitsize(&b) > 1);
|
||||
res = res | (ibz_get(&b) != 0);
|
||||
res = res | (ibz_cmp_int32(&b, 0) != 0);
|
||||
|
||||
ibz_set(&a, -1);
|
||||
res = res | !(ibz_cmp(&a, &b) < 0);
|
||||
res = res | !(ibz_cmp(&b, &c) < 0);
|
||||
res = res | !(ibz_cmp(&b, &a) > 0);
|
||||
res = res | !(ibz_cmp(&c, &b) > 0);
|
||||
ibz_copy(&b, &a);
|
||||
res = res | (0 != ibz_cmp(&a, &b));
|
||||
res = res | (0 == ibz_cmp(&c, &b));
|
||||
ibz_swap(&b, &c);
|
||||
res = res | (0 == ibz_cmp(&a, &b));
|
||||
res = res | (0 != ibz_cmp(&c, &a));
|
||||
|
||||
ibz_set_from_str(&a, "-10000000000000000011111100000001", 10);
|
||||
res = res | !(ibz_cmp(&a, &b) < 0);
|
||||
res = res | !(ibz_cmp(&b, &a) > 0);
|
||||
ibz_copy(&b, &a);
|
||||
res = res | (0 != ibz_cmp(&a, &b));
|
||||
res = res | (0 == ibz_cmp(&c, &b));
|
||||
ibz_swap(&b, &c);
|
||||
res = res | (0 == ibz_cmp(&a, &b));
|
||||
res = res | (0 != ibz_cmp(&c, &a));
|
||||
|
||||
ibz_set_from_str(&a, "1aaaa00000000000000000123", 16);
|
||||
res = res | !(ibz_cmp(&a, &c) > 0);
|
||||
res = res | !(ibz_cmp(&c, &a) < 0);
|
||||
res = res | (ibz_bitsize(&a) != 4 * 24 + 1);
|
||||
res = res | (ibz_get(&a) != 16 * 18 + 3);
|
||||
if (res) {
|
||||
printf("Quaternion module integer group test ibz_test_init_set_cmp failed\n");
|
||||
}
|
||||
|
||||
ibz_set_from_str(&a, "deadbeef12345678", 16);
|
||||
res = res | (ibz_get(&a) != 0x12345678);
|
||||
|
||||
// Test INT32_MAX and INT32_MIN
|
||||
ibz_set_from_str(&a, "-2147483648", 10);
|
||||
ibz_set(&b, INT32_MIN);
|
||||
res = res | (ibz_get(&a) != -2147483648);
|
||||
res = res | (ibz_cmp_int32(&a, -2147483648) != 0);
|
||||
res = res | (0 != ibz_cmp(&a, &b));
|
||||
ibz_set_from_str(&a, "2147483647", 10);
|
||||
ibz_set(&b, INT32_MAX);
|
||||
res = res | (ibz_get(&a) != 2147483647);
|
||||
res = res | (ibz_cmp_int32(&a, 2147483647) != 0);
|
||||
res = res | (0 != ibz_cmp(&a, &b));
|
||||
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&c);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// void ibz_add(ibz_t *sum, const ibz_t *a, const ibz_t *b);
|
||||
// void ibz_sub(ibz_t *diff, const ibz_t *a, const ibz_t *b);
|
||||
// void ibz_neg(ibz_t *neg, const ibz_t *a);
|
||||
// void ibz_abs(ibz_t *abs, const ibz_t *a);
|
||||
int
|
||||
ibz_test_add_sub_neg_abs()
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t a, b, c, d, r, q, m;
|
||||
ibz_init(&a);
|
||||
ibz_init(&b);
|
||||
ibz_init(&c);
|
||||
ibz_init(&d);
|
||||
ibz_init(&r);
|
||||
ibz_init(&q);
|
||||
ibz_init(&m);
|
||||
|
||||
ibz_set_from_str(&a, "10000111100002222", 16);
|
||||
ibz_copy(&c, &a);
|
||||
ibz_add(&d, &a, &b);
|
||||
res = res | (0 != ibz_cmp(&b, &q));
|
||||
res = res | (0 != ibz_cmp(&a, &c));
|
||||
res = res | (0 != ibz_cmp(&d, &c));
|
||||
ibz_add(&d, &b, &a);
|
||||
res = res | (0 != ibz_cmp(&b, &q));
|
||||
res = res | (0 != ibz_cmp(&a, &c));
|
||||
res = res | (0 != ibz_cmp(&d, &c));
|
||||
// add test for adding non-0, sub, mul, ...
|
||||
ibz_set_from_str(&b, "20000111100002223", 16);
|
||||
ibz_set_from_str(&c, "30000222200004445", 16);
|
||||
ibz_add(&d, &a, &b);
|
||||
res = res | (0 != ibz_cmp(&d, &c));
|
||||
ibz_neg(&m, &a);
|
||||
ibz_add(&q, &m, &d);
|
||||
res = res | (0 != ibz_cmp(&q, &b));
|
||||
ibz_neg(&m, &m);
|
||||
res = res | (0 != ibz_cmp(&m, &a));
|
||||
ibz_add(&q, &m, &b);
|
||||
res = res | (0 != ibz_cmp(&q, &c));
|
||||
ibz_neg(&m, &m);
|
||||
ibz_sub(&q, &b, &m);
|
||||
res = res | (0 != ibz_cmp(&q, &c));
|
||||
ibz_neg(&m, &m);
|
||||
res = res | (0 != ibz_cmp(&a, &m));
|
||||
ibz_sub(&q, &d, &a);
|
||||
res = res | (0 != ibz_cmp(&q, &b));
|
||||
ibz_neg(&d, &d);
|
||||
ibz_neg(&m, &a);
|
||||
ibz_neg(&c, &b);
|
||||
ibz_sub(&q, &d, &m);
|
||||
res = res | (0 != ibz_cmp(&q, &c));
|
||||
ibz_sub(&q, &m, &b);
|
||||
res = res | (0 != ibz_cmp(&q, &d));
|
||||
ibz_abs(&r, &r);
|
||||
res = res | !ibz_is_zero(&r);
|
||||
ibz_abs(&r, &a);
|
||||
res = res | (0 != ibz_cmp(&a, &r));
|
||||
ibz_abs(&r, &m);
|
||||
res = res | (0 != ibz_cmp(&a, &r));
|
||||
ibz_neg(&m, &m);
|
||||
res = res | (0 != ibz_cmp(&a, &m));
|
||||
|
||||
if (res) {
|
||||
printf("Quaternion module integer group test ibz_test_add_sub_neg_abs failed\n");
|
||||
}
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&c);
|
||||
ibz_finalize(&d);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&m);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// void ibz_mul(ibz_t *prod, const ibz_t *a, const ibz_t *b);
|
||||
// void ibz_sqrt_floor(ibz_t *sqrt, const ibz_t *a);
|
||||
int
|
||||
ibz_test_mul_sqrt()
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t a, b, c, d, r, q, m;
|
||||
ibz_init(&a);
|
||||
ibz_init(&b);
|
||||
ibz_init(&c);
|
||||
ibz_init(&d);
|
||||
ibz_init(&r);
|
||||
ibz_init(&q);
|
||||
ibz_init(&m);
|
||||
|
||||
// zero
|
||||
ibz_set_from_str(&a, "2113309833171849999003363", 10);
|
||||
ibz_copy(&c, &a);
|
||||
ibz_set(&b, 0);
|
||||
ibz_mul(&m, &a, &b);
|
||||
res = res | (0 != ibz_cmp(&m, &b));
|
||||
res = res | (0 != ibz_cmp(&a, &c));
|
||||
ibz_mul(&m, &b, &a);
|
||||
res = res | (0 != ibz_cmp(&m, &b));
|
||||
res = res | (0 != ibz_cmp(&a, &c));
|
||||
// one
|
||||
ibz_set(&b, 1);
|
||||
ibz_mul(&m, &a, &b);
|
||||
res = res | (0 != ibz_cmp(&m, &a));
|
||||
res = res | (0 != ibz_cmp(&a, &c));
|
||||
ibz_mul(&m, &b, &a);
|
||||
res = res | (0 != ibz_cmp(&m, &a));
|
||||
res = res | (0 != ibz_cmp(&a, &c));
|
||||
// -1
|
||||
ibz_neg(&b, &b);
|
||||
ibz_neg(&d, &a);
|
||||
ibz_mul(&m, &a, &b);
|
||||
res = res | (0 != ibz_cmp(&m, &d));
|
||||
res = res | (0 != ibz_cmp(&a, &c));
|
||||
ibz_mul(&m, &b, &a);
|
||||
res = res | (0 != ibz_cmp(&m, &d));
|
||||
res = res | (0 != ibz_cmp(&a, &c));
|
||||
// larger
|
||||
ibz_set_from_str(&b, "34575345632322576567896", 10);
|
||||
ibz_set_from_str(&c, "73068417910102676801285574959599851857101834248", 10);
|
||||
ibz_mul(&m, &a, &b);
|
||||
res = res | (0 != ibz_cmp(&m, &c));
|
||||
ibz_neg(&b, &b);
|
||||
ibz_neg(&a, &a);
|
||||
ibz_mul(&m, &a, &b);
|
||||
res = res | (0 != ibz_cmp(&m, &c));
|
||||
ibz_neg(&a, &a);
|
||||
ibz_neg(&c, &c);
|
||||
ibz_mul(&m, &a, &b);
|
||||
res = res | (0 != ibz_cmp(&m, &c));
|
||||
ibz_neg(&b, &b);
|
||||
ibz_neg(&a, &a);
|
||||
ibz_mul(&m, &a, &b);
|
||||
res = res | (0 != ibz_cmp(&m, &c));
|
||||
|
||||
// sqrt tests
|
||||
ibz_abs(&b, &b);
|
||||
ibz_abs(&a, &a);
|
||||
ibz_mul(&m, &a, &a);
|
||||
ibz_sqrt_floor(&d, &m);
|
||||
res = res | (0 != ibz_cmp(&d, &a));
|
||||
ibz_mul(&m, &b, &b);
|
||||
ibz_sqrt_floor(&d, &m);
|
||||
res = res | (0 != ibz_cmp(&d, &b));
|
||||
ibz_set(&d, 1);
|
||||
ibz_mul(&m, &b, &b);
|
||||
ibz_sub(&m, &m, &d);
|
||||
ibz_sub(&c, &b, &d);
|
||||
ibz_sqrt_floor(&d, &m);
|
||||
res = res | (0 != ibz_cmp(&d, &c));
|
||||
|
||||
if (res) {
|
||||
printf("Quaternion module integer group test ibz_test_mul_sqrt failed\n");
|
||||
}
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&c);
|
||||
ibz_finalize(&d);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&m);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// void ibz_div(ibz_t *quotient, ibz_t *remainder, const ibz_t *a, const ibz_t *b);
|
||||
// int ibz_divides(const ibz_t *a, const ibz_t *b);
|
||||
int
|
||||
ibz_test_div()
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t a, b, c, d, r, q, m;
|
||||
ibz_init(&a);
|
||||
ibz_init(&b);
|
||||
ibz_init(&c);
|
||||
ibz_init(&d);
|
||||
ibz_init(&r);
|
||||
ibz_init(&q);
|
||||
ibz_init(&m);
|
||||
|
||||
// one
|
||||
ibz_set_from_str(&a, "2113309833171849999003363", 10);
|
||||
ibz_copy(&c, &a);
|
||||
ibz_set(&b, 1);
|
||||
ibz_copy(&d, &b);
|
||||
res = res | !ibz_divides(&a, &b);
|
||||
ibz_div(&q, &r, &a, &b);
|
||||
res = res | !ibz_is_zero(&r);
|
||||
res = res | (0 != ibz_cmp(&q, &a));
|
||||
res = res | (0 != ibz_cmp(&c, &a));
|
||||
res = res | (0 != ibz_cmp(&b, &d));
|
||||
// not one, zero remainder
|
||||
ibz_set_from_str(&b, "15678200126527887351125", 10);
|
||||
ibz_mul(&d, &a, &b);
|
||||
ibz_copy(&c, &d);
|
||||
res = res | !ibz_divides(&d, &b);
|
||||
res = res | !ibz_divides(&d, &a);
|
||||
res = res | !ibz_divides(&d, &d);
|
||||
ibz_div(&q, &r, &d, &b);
|
||||
res = res | !ibz_is_zero(&r);
|
||||
res = res | (0 != ibz_cmp(&q, &a));
|
||||
ibz_div(&q, &r, &d, &a);
|
||||
res = res | !ibz_is_zero(&r);
|
||||
res = res | (0 != ibz_cmp(&q, &b));
|
||||
// flipping signs
|
||||
ibz_neg(&a, &a);
|
||||
ibz_neg(&b, &b);
|
||||
ibz_div(&q, &r, &d, &b);
|
||||
res = res | !ibz_is_zero(&r);
|
||||
res = res | (0 != ibz_cmp(&q, &a));
|
||||
ibz_div(&q, &r, &d, &a);
|
||||
res = res | !ibz_is_zero(&r);
|
||||
res = res | (0 != ibz_cmp(&q, &b));
|
||||
ibz_neg(&a, &a);
|
||||
ibz_neg(&d, &d);
|
||||
ibz_div(&q, &r, &d, &b);
|
||||
res = res | !ibz_is_zero(&r);
|
||||
res = res | (0 != ibz_cmp(&q, &a));
|
||||
ibz_div(&q, &r, &d, &a);
|
||||
res = res | !ibz_is_zero(&r);
|
||||
res = res | (0 != ibz_cmp(&q, &b));
|
||||
ibz_neg(&a, &a);
|
||||
ibz_neg(&b, &b);
|
||||
ibz_div(&q, &r, &d, &b);
|
||||
res = res | !ibz_is_zero(&r);
|
||||
res = res | (0 != ibz_cmp(&q, &a));
|
||||
ibz_div(&q, &r, &d, &a);
|
||||
res = res | !ibz_is_zero(&r);
|
||||
res = res | (0 != ibz_cmp(&q, &b));
|
||||
// non-zero remainder
|
||||
ibz_neg(&a, &a);
|
||||
ibz_neg(&d, &d);
|
||||
ibz_set_from_str(&c, "8678205677345432110000", 10);
|
||||
ibz_add(&d, &d, &c);
|
||||
ibz_div(&q, &r, &d, &b);
|
||||
ibz_mul(&m, &q, &b);
|
||||
ibz_add(&m, &m, &r);
|
||||
res = res | (0 != ibz_cmp(&d, &m));
|
||||
ibz_abs(&m, &r);
|
||||
ibz_abs(&q, &b);
|
||||
res = res | (0 <= ibz_cmp(&m, &q));
|
||||
ibz_set(&q, 0);
|
||||
res =
|
||||
res | !(((ibz_cmp(&q, &r) <= 0) && (ibz_cmp(&q, &d) < 0)) || ((ibz_cmp(&q, &r) >= 0) && (ibz_cmp(&r, &d) > 0)));
|
||||
// flip signs
|
||||
ibz_neg(&d, &d);
|
||||
ibz_div(&q, &r, &d, &b);
|
||||
ibz_mul(&m, &q, &b);
|
||||
ibz_add(&m, &m, &r);
|
||||
res = res | (0 != ibz_cmp(&d, &m));
|
||||
ibz_abs(&m, &r);
|
||||
ibz_abs(&q, &b);
|
||||
res = res | (0 <= ibz_cmp(&m, &q));
|
||||
ibz_set(&q, 0);
|
||||
res =
|
||||
res | !(((ibz_cmp(&q, &r) <= 0) && (ibz_cmp(&q, &d) < 0)) || ((ibz_cmp(&q, &r) >= 0) && (ibz_cmp(&r, &d) > 0)));
|
||||
ibz_neg(&b, &b);
|
||||
ibz_div(&q, &r, &d, &b);
|
||||
ibz_mul(&m, &q, &b);
|
||||
ibz_add(&m, &m, &r);
|
||||
res = res | (0 != ibz_cmp(&d, &m));
|
||||
ibz_abs(&m, &r);
|
||||
ibz_abs(&q, &b);
|
||||
res = res | (0 <= ibz_cmp(&m, &q));
|
||||
ibz_set(&q, 0);
|
||||
res =
|
||||
res | !(((ibz_cmp(&q, &r) <= 0) && (ibz_cmp(&q, &d) < 0)) || ((ibz_cmp(&q, &r) >= 0) && (ibz_cmp(&r, &d) > 0)));
|
||||
ibz_neg(&d, &d);
|
||||
ibz_div(&q, &r, &d, &b);
|
||||
ibz_mul(&m, &q, &b);
|
||||
ibz_add(&m, &m, &r);
|
||||
res = res | (0 != ibz_cmp(&d, &m));
|
||||
ibz_abs(&m, &r);
|
||||
ibz_abs(&q, &b);
|
||||
res = res | (0 <= ibz_cmp(&m, &q));
|
||||
ibz_set(&q, 0);
|
||||
res =
|
||||
res | !(((ibz_cmp(&q, &r) <= 0) && (ibz_cmp(&q, &d) < 0)) || ((ibz_cmp(&q, &r) >= 0) && (ibz_cmp(&r, &d) > 0)));
|
||||
|
||||
if (res) {
|
||||
printf("Quaternion module integer group test ibz_test_div failed\n");
|
||||
}
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&c);
|
||||
ibz_finalize(&d);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&m);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// void ibz_mod(ibz_t *r, const ibz_t *a, const ibz_t *b);
|
||||
// unsigned long int ibz_mod_ui(const mpz_t *n, unsigned long int d);
|
||||
int
|
||||
ibz_test_mod()
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t a, b, c, r, m;
|
||||
ibz_init(&a);
|
||||
ibz_init(&b);
|
||||
ibz_init(&c);
|
||||
ibz_init(&r);
|
||||
ibz_init(&m);
|
||||
|
||||
ibz_set_from_str(&a, "2113309833171849999003363", 10);
|
||||
res = res | (ibz_mod_ui(&a, 3) != 0);
|
||||
res = res | (ibz_mod_ui(&a, 2) != 1);
|
||||
ibz_set_from_str(&m, "2113309833171840000000000", 10);
|
||||
ibz_mod(&r, &a, &m);
|
||||
ibz_add(&c, &r, &m);
|
||||
res = res | (0 != ibz_cmp(&c, &a));
|
||||
ibz_neg(&b, &a);
|
||||
res = res | (ibz_mod_ui(&b, 3) != 0);
|
||||
res = res | (ibz_mod_ui(&b, 2) != 1);
|
||||
ibz_mod(&r, &b, &m);
|
||||
ibz_sub(&c, &r, &m);
|
||||
ibz_sub(&c, &c, &m);
|
||||
res = res | (0 != ibz_cmp(&c, &b));
|
||||
|
||||
if (res) {
|
||||
printf("Quaternion module integer group test ibz_test_mod failed\n");
|
||||
}
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&c);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&m);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// void ibz_pow(ibz_t *pow, const ibz_t *x, uint32_t e);
|
||||
// void ibz_pow_mod(ibz_t *pow, const ibz_t *x, const ibz_t *e, const ibz_t *m);
|
||||
// void ibz_div_2exp(ibz_t *quotient, const ibz_t *a, uint32_t exp);
|
||||
int
|
||||
ibz_test_pow()
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t a, b, c, d, e, m;
|
||||
ibz_init(&a);
|
||||
ibz_init(&b);
|
||||
ibz_init(&c);
|
||||
ibz_init(&d);
|
||||
ibz_init(&e);
|
||||
ibz_init(&m);
|
||||
|
||||
ibz_set_from_str(&a, "aaaaaaaabbbbbbbb2222221111", 16);
|
||||
ibz_copy(&c, &a);
|
||||
int exp = 10;
|
||||
ibz_set(&b, 1);
|
||||
for (int i = 1; i < exp + 1; i++)
|
||||
ibz_mul(&b, &b, &a);
|
||||
ibz_pow(&d, &a, exp);
|
||||
res = res | (0 != ibz_cmp(&c, &a));
|
||||
res = res | (0 != ibz_cmp(&d, &b));
|
||||
ibz_neg(&a, &a);
|
||||
ibz_copy(&c, &a);
|
||||
ibz_pow(&d, &a, exp);
|
||||
res = res | (0 != ibz_cmp(&c, &a));
|
||||
res = res | (0 != ibz_cmp(&d, &b));
|
||||
exp = 9;
|
||||
ibz_set(&b, 1);
|
||||
for (int i = 1; i < exp + 1; i++)
|
||||
ibz_mul(&b, &b, &a);
|
||||
ibz_pow(&d, &a, exp);
|
||||
res = res | (0 != ibz_cmp(&c, &a));
|
||||
res = res | (0 != ibz_cmp(&d, &b));
|
||||
|
||||
ibz_set_from_str(&a, "aaaaaaaabbbbbbbb2222221111", 16);
|
||||
ibz_set_from_str(&m, "cdabde24864122912341", 16);
|
||||
exp = 10;
|
||||
ibz_set(&m, exp);
|
||||
ibz_copy(&c, &a);
|
||||
ibz_set(&b, 1);
|
||||
for (int i = 1; i < exp + 1; i++) {
|
||||
ibz_mul(&b, &b, &a);
|
||||
ibz_mod(&b, &b, &m);
|
||||
}
|
||||
ibz_pow_mod(&d, &a, &e, &m);
|
||||
res = res | (0 != ibz_cmp(&c, &a));
|
||||
res = res | (0 != ibz_cmp(&d, &b));
|
||||
|
||||
exp = 23;
|
||||
ibz_set(&b, 2);
|
||||
ibz_pow(&b, &b, exp);
|
||||
ibz_div(&m, &b, &a, &b);
|
||||
ibz_div_2exp(&d, &a, exp);
|
||||
res = res | (0 != ibz_cmp(&c, &a));
|
||||
res = res | (0 != ibz_cmp(&m, &d));
|
||||
|
||||
if (res) {
|
||||
printf("Quaternion module integer group test ibz_test_pow failed\n");
|
||||
}
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&c);
|
||||
ibz_finalize(&d);
|
||||
ibz_finalize(&e);
|
||||
ibz_finalize(&m);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// void ibz_gcd(ibz_t *gcd, const ibz_t *a, const ibz_t *b);
|
||||
// int ibz_invmod(ibz_t *inv, const ibz_t *a, const ibz_t *mod);ibz_test_mod()
|
||||
int
|
||||
ibz_test_gcd()
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t a, b, c, d, ac, bc, m;
|
||||
ibz_init(&a);
|
||||
ibz_init(&b);
|
||||
ibz_init(&c);
|
||||
ibz_init(&d);
|
||||
ibz_init(&ac);
|
||||
ibz_init(&bc);
|
||||
ibz_init(&m);
|
||||
|
||||
// fixed large test
|
||||
ibz_set_from_str(&c, "25791357069084", 10);
|
||||
ibz_set_from_str(&a, "6173271838293993987767", 10);
|
||||
ibz_set_from_str(&b, "89882267321617266071838286", 10);
|
||||
ibz_mul(&ac, &a, &c);
|
||||
ibz_mul(&bc, &b, &c);
|
||||
ibz_gcd(&d, &ac, &bc);
|
||||
res = res | (0 != ibz_cmp(&c, &d));
|
||||
ibz_mul(&m, &a, &c);
|
||||
res = res | (0 != ibz_cmp(&ac, &m));
|
||||
ibz_mul(&m, &b, &c);
|
||||
res = res | (0 != ibz_cmp(&bc, &m));
|
||||
// gcd is positif whatever the inputs are
|
||||
ibz_neg(&ac, &ac);
|
||||
ibz_gcd(&d, &ac, &bc);
|
||||
res = res | (0 != ibz_cmp(&c, &d));
|
||||
ibz_neg(&bc, &bc);
|
||||
ibz_gcd(&d, &ac, &bc);
|
||||
res = res | (0 != ibz_cmp(&c, &d));
|
||||
ibz_neg(&ac, &ac);
|
||||
ibz_gcd(&d, &ac, &bc);
|
||||
res = res | (0 != ibz_cmp(&c, &d));
|
||||
// different sizes do not matter
|
||||
ibz_set(&d, 2);
|
||||
ibz_gcd(&m, &ac, &d);
|
||||
res = res | (0 != ibz_cmp(&m, &d));
|
||||
|
||||
// invmod
|
||||
ibz_invmod(&d, &a, &b);
|
||||
res = res | (0 >= ibz_cmp(&b, &d));
|
||||
ibz_set(&m, 0);
|
||||
res = res | (0 <= ibz_cmp(&m, &d));
|
||||
ibz_mul(&m, &d, &a);
|
||||
ibz_mod(&m, &m, &b);
|
||||
res = res | !ibz_is_one(&m);
|
||||
// negative changes nothing
|
||||
ibz_neg(&a, &a);
|
||||
ibz_invmod(&d, &a, &b);
|
||||
res = res | (0 >= ibz_cmp(&b, &d));
|
||||
ibz_set(&m, 0);
|
||||
res = res | (0 <= ibz_cmp(&m, &d));
|
||||
ibz_mul(&m, &d, &a);
|
||||
ibz_mod(&m, &m, &b);
|
||||
res = res | !ibz_is_one(&m);
|
||||
|
||||
if (res) {
|
||||
printf("Quaternion module integer group test ibz_test_gcd failed\n");
|
||||
}
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&c);
|
||||
ibz_finalize(&d);
|
||||
ibz_finalize(&ac);
|
||||
ibz_finalize(&bc);
|
||||
ibz_finalize(&m);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// Tests ibz_sqrt_mod_p
|
||||
// Allows to provide the number of repetitions and the bit-size of the primes.
|
||||
int
|
||||
ibz_test_sqrt_mod_p(int reps, int prime_n)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
// Initialize GMP variables
|
||||
ibz_t prime, a, prime_minus_a, asq, sqrt, tmp;
|
||||
ibz_t prime_p4m3, prime_p5m8, prime_p1m8;
|
||||
ibz_t prime_p4m3_x2, prime_p5m8_x2, prime_p1m8_x2;
|
||||
ibz_t two_to_the_n_minus_1;
|
||||
ibz_init(&prime);
|
||||
ibz_init(&prime_p4m3);
|
||||
ibz_init(&prime_p5m8);
|
||||
ibz_init(&prime_p1m8);
|
||||
ibz_init(&prime_p4m3_x2);
|
||||
ibz_init(&prime_p5m8_x2);
|
||||
ibz_init(&prime_p1m8_x2);
|
||||
ibz_init(&a);
|
||||
ibz_init(&prime_minus_a);
|
||||
ibz_init(&asq);
|
||||
ibz_init(&sqrt);
|
||||
ibz_init(&tmp);
|
||||
ibz_init(&two_to_the_n_minus_1);
|
||||
|
||||
// Generate random prime number
|
||||
int n = prime_n; // Number of bits
|
||||
ibz_set(&two_to_the_n_minus_1, 1);
|
||||
mpz_mul_2exp(two_to_the_n_minus_1, two_to_the_n_minus_1, n);
|
||||
ibz_sub(&two_to_the_n_minus_1, &two_to_the_n_minus_1, &ibz_const_one);
|
||||
|
||||
for (int r = 0; r < reps; ++r) {
|
||||
ibz_rand_interval(&prime, &ibz_const_zero, &two_to_the_n_minus_1);
|
||||
if (ibz_is_even(&prime))
|
||||
ibz_add(&prime, &prime, &ibz_const_one);
|
||||
|
||||
int p4m3 = 0, p5m8 = 0, p1m8 = 0;
|
||||
|
||||
while (p4m3 == 0 || p5m8 == 0 || p1m8 == 0) {
|
||||
do {
|
||||
ibz_add(&prime, &prime, &ibz_const_two);
|
||||
} while (!mpz_probab_prime_p(prime, 25));
|
||||
|
||||
if (mpz_mod_ui(tmp, prime, 4) == 3) {
|
||||
ibz_copy(&prime_p4m3, &prime);
|
||||
p4m3 = 1;
|
||||
} else if (mpz_mod_ui(tmp, prime, 8) == 5) {
|
||||
ibz_copy(&prime_p5m8, &prime);
|
||||
p5m8 = 1;
|
||||
} else if (mpz_mod_ui(tmp, prime, 8) == 1) {
|
||||
ibz_copy(&prime_p1m8, &prime);
|
||||
p1m8 = 1;
|
||||
} else {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ibz_t *primes[] = { &prime_p4m3, &prime_p5m8, &prime_p1m8 };
|
||||
ibz_t *primes_x2[] = { &prime_p4m3_x2, &prime_p5m8_x2, &prime_p1m8_x2 };
|
||||
for (int i = 0; i < 3; ++i) // 2p
|
||||
mpz_mul_2exp(*primes_x2[i], *primes[i], 1);
|
||||
|
||||
// Test sqrt mod p
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
ibz_sub(&tmp, primes[i], &ibz_const_one);
|
||||
ibz_rand_interval(&a, &ibz_const_zero, &tmp);
|
||||
ibz_sub(&prime_minus_a, (primes[i]), &a);
|
||||
mpz_powm_ui(asq, a, 2, *primes[i]);
|
||||
|
||||
int no_sqrt = !ibz_sqrt_mod_p(&sqrt, &asq, primes[i]);
|
||||
mpz_powm_ui(tmp, sqrt, 2, *primes[i]);
|
||||
|
||||
if (no_sqrt || (ibz_cmp(&sqrt, &a) && ibz_cmp(&sqrt, &prime_minus_a))) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
if (res) {
|
||||
printf("Quaternion module integer test ibz_test_sqrt_mod_p failed\n");
|
||||
}
|
||||
ibz_finalize(&prime);
|
||||
ibz_finalize(&prime_p4m3);
|
||||
ibz_finalize(&prime_p5m8);
|
||||
ibz_finalize(&prime_p1m8);
|
||||
ibz_finalize(&prime_p4m3_x2);
|
||||
ibz_finalize(&prime_p5m8_x2);
|
||||
ibz_finalize(&prime_p1m8_x2);
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&prime_minus_a);
|
||||
ibz_finalize(&asq);
|
||||
ibz_finalize(&sqrt);
|
||||
ibz_finalize(&tmp);
|
||||
ibz_finalize(&two_to_the_n_minus_1);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_test_rand_interval(int reps)
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t low, high, rand;
|
||||
ibz_init(&low);
|
||||
ibz_init(&high);
|
||||
ibz_init(&rand);
|
||||
ibz_set_from_str(&low, "ffa", 16);
|
||||
ibz_set_from_str(&high, "eeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", 16);
|
||||
|
||||
for (int i = 0; i < reps; ++i) {
|
||||
res = ibz_rand_interval(&rand, &low, &high);
|
||||
if (res != 1) {
|
||||
res = 1;
|
||||
goto err;
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
|
||||
if (ibz_cmp(&rand, &low) < 0 || ibz_cmp(&rand, &high) > 0) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
err:
|
||||
if (res) {
|
||||
printf("Quaternion module integer test ibz_test_rand_interval failed\n");
|
||||
}
|
||||
ibz_finalize(&low);
|
||||
ibz_finalize(&high);
|
||||
ibz_finalize(&rand);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_test_rand_interval_i(int reps)
|
||||
{
|
||||
int res = 0;
|
||||
int32_t low, high;
|
||||
ibz_t rand, cmp;
|
||||
ibz_init(&rand);
|
||||
ibz_init(&cmp);
|
||||
|
||||
for (int i = 0; i < reps; ++i) {
|
||||
randombytes((unsigned char *)&low, sizeof(int32_t));
|
||||
randombytes((unsigned char *)&high, sizeof(int32_t));
|
||||
if (low < 0)
|
||||
low = -low;
|
||||
if (high < 0)
|
||||
high = -high;
|
||||
// The function requires a < b, thus a != b
|
||||
if (low == high) {
|
||||
continue;
|
||||
}
|
||||
if (low > high) {
|
||||
int32_t tmp = low;
|
||||
low = high;
|
||||
high = tmp;
|
||||
}
|
||||
|
||||
res = ibz_rand_interval_i(&rand, low, high);
|
||||
if (res != 1) {
|
||||
res = 1;
|
||||
goto err;
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
ibz_set(&cmp, low);
|
||||
if (ibz_cmp(&rand, &cmp) < 0) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
ibz_set(&cmp, high);
|
||||
if (ibz_cmp(&rand, &cmp) > 0) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
if (res) {
|
||||
printf("Quaternion module integer test ibz_test_rand_interval_i failed\n");
|
||||
}
|
||||
ibz_finalize(&rand);
|
||||
ibz_finalize(&cmp);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_test_rand_interval_minm_m(int reps)
|
||||
{
|
||||
int res = 0;
|
||||
int32_t m;
|
||||
ibz_t rand;
|
||||
ibz_init(&rand);
|
||||
|
||||
for (int i = 0; i < reps; ++i) {
|
||||
randombytes((unsigned char *)&m, sizeof(int32_t));
|
||||
if (m < 0)
|
||||
m = -m;
|
||||
m >>= 1; // less than 32 bit
|
||||
|
||||
if (m < 0) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
res = ibz_rand_interval_minm_m(&rand, m);
|
||||
if (res != 1) {
|
||||
res = 1;
|
||||
goto err;
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
if (ibz_cmp_int32(&rand, -m) < 0) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
if (ibz_cmp_int32(&rand, m) > 0) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
if (res) {
|
||||
printf("Quaternion module integer test ibz_test_rand_interval_minm_m failed\n");
|
||||
}
|
||||
ibz_finalize(&rand);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_test_copy_digits(void)
|
||||
{
|
||||
int res = 0;
|
||||
const digit_t d1[] = { 0x12345678 };
|
||||
const digit_t d2[] = { 2, 1 };
|
||||
|
||||
const char d1str[] = "12345678";
|
||||
#if RADIX == 32
|
||||
const char d2str[] = "100000002";
|
||||
#elif RADIX == 64
|
||||
const char d2str[] = "10000000000000002";
|
||||
#endif
|
||||
|
||||
char d1_intbig_str[80] = { 0 };
|
||||
char d2_intbig_str[80] = { 0 };
|
||||
|
||||
ibz_t d1_intbig, d2_intbig;
|
||||
ibz_init(&d1_intbig);
|
||||
ibz_init(&d2_intbig);
|
||||
|
||||
ibz_copy_digits(&d1_intbig, d1, 1);
|
||||
ibz_copy_digits(&d2_intbig, d2, 2);
|
||||
|
||||
ibz_convert_to_str(&d1_intbig, d1_intbig_str, 16);
|
||||
ibz_convert_to_str(&d2_intbig, d2_intbig_str, 16);
|
||||
|
||||
if (memcmp(d1str, d1_intbig_str, sizeof(d1str))) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
if (memcmp(d2str, d2_intbig_str, sizeof(d2str))) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
err:
|
||||
if (res) {
|
||||
printf("Quaternion module integer test ibz_test_copy_digits failed\n");
|
||||
}
|
||||
ibz_finalize(&d1_intbig);
|
||||
ibz_finalize(&d2_intbig);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_test_to_digits(void)
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t d1_intbig, d2_intbig, zero_intbig;
|
||||
ibz_t d1_intbig_rec, d2_intbig_rec, zero_intbig_rec, cof, cof2;
|
||||
const char d1str[] = "12345678";
|
||||
const char d2str[] = "10000000000000002";
|
||||
ibz_init(&d1_intbig);
|
||||
ibz_init(&d2_intbig);
|
||||
|
||||
ibz_set_from_str(&d1_intbig, d1str, 16);
|
||||
ibz_set_from_str(&d2_intbig, d2str, 16);
|
||||
ibz_init(&zero_intbig);
|
||||
|
||||
ibz_init(&d1_intbig_rec);
|
||||
ibz_init(&d2_intbig_rec);
|
||||
ibz_init(&zero_intbig_rec);
|
||||
ibz_init(&cof);
|
||||
ibz_init(&cof2);
|
||||
|
||||
size_t d1_digits = (mpz_sizeinbase(d1_intbig, 2) + sizeof(digit_t) * 8 - 1) / (sizeof(digit_t) * 8);
|
||||
size_t d2_digits = (mpz_sizeinbase(d2_intbig, 2) + sizeof(digit_t) * 8 - 1) / (sizeof(digit_t) * 8);
|
||||
|
||||
digit_t d1[d1_digits];
|
||||
digit_t d2[d2_digits];
|
||||
digit_t zero[1];
|
||||
|
||||
ibz_to_digits(d1, &d1_intbig);
|
||||
ibz_to_digits(d2, &d2_intbig);
|
||||
ibz_to_digits(zero, &zero_intbig);
|
||||
|
||||
// A lazy test, but we know that this conversion should be correct from the previous test
|
||||
|
||||
ibz_copy_digits(&d1_intbig_rec, d1, d1_digits);
|
||||
ibz_copy_digits(&d2_intbig_rec, d2, d2_digits);
|
||||
ibz_copy_digits(&zero_intbig_rec, zero, 1);
|
||||
|
||||
if (ibz_cmp(&d1_intbig, &d1_intbig_rec) || ibz_cmp(&zero_intbig, &zero_intbig_rec)) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
#if RADIX == 64
|
||||
const digit_t p_cofactor_for_3g[5] = {
|
||||
0x0000000000000000, 0x74f9dace0d9ec800, 0x63a25b437f655001, 0x0000000000000019, 0
|
||||
};
|
||||
digit_t p_cofactor_for_3g_rec[10] = { 0 };
|
||||
#elif RADIX == 32
|
||||
const digit_t p_cofactor_for_3g[10] = { 0x00000000, 0x00000000, 0x0d9ec800, 0x74f9dace, 0x7f655001,
|
||||
0x63a25b43, 0x00000019, 0x00000000, 0, 0 };
|
||||
digit_t p_cofactor_for_3g_rec[5] = { 0 };
|
||||
#endif
|
||||
ibz_copy_digits(&cof, p_cofactor_for_3g, 5);
|
||||
ibz_to_digits(p_cofactor_for_3g_rec, &cof);
|
||||
ibz_copy_digits(&cof2, p_cofactor_for_3g_rec, 5);
|
||||
|
||||
if (ibz_cmp(&cof, &cof2)) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
#if RADIX == 32
|
||||
digit_t da[3] = { 0, 0, 0 };
|
||||
#elif RADIX == 64
|
||||
digit_t da[2] = { 0, 0 };
|
||||
#endif
|
||||
|
||||
ibz_t strval, strval_check;
|
||||
ibz_init(&strval_check);
|
||||
ibz_init(&strval);
|
||||
ibz_set_from_str(&strval, "1617406613339667622221321", 10);
|
||||
ibz_to_digits(da, &strval);
|
||||
ibz_copy_digits(&strval_check, da, sizeof(da) / sizeof(digit_t));
|
||||
// ibz_printf("strval: %Zd\nstrval_check: %Zd\n", strval, strval_check);
|
||||
if (ibz_cmp(&strval, &strval_check)) {
|
||||
res = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
if (res) {
|
||||
printf("Quaternion module integer test ibz_test_to_digits failed\n");
|
||||
}
|
||||
ibz_finalize(&d1_intbig);
|
||||
ibz_finalize(&d2_intbig);
|
||||
ibz_finalize(&zero_intbig);
|
||||
ibz_finalize(&d1_intbig_rec);
|
||||
ibz_finalize(&d2_intbig_rec);
|
||||
ibz_finalize(&zero_intbig_rec);
|
||||
ibz_finalize(&cof);
|
||||
ibz_finalize(&cof2);
|
||||
ibz_finalize(&strval);
|
||||
ibz_finalize(&strval_check);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
ibz_test_intbig()
|
||||
{
|
||||
int reps = 2;
|
||||
int prime_n = 103;
|
||||
int res = 0;
|
||||
printf("\nRunning quaternion tests of gmp-based integer functions\n");
|
||||
res = res | ibz_test_init_set_cmp();
|
||||
res = res | ibz_test_add_sub_neg_abs();
|
||||
res = res | ibz_test_mul_sqrt();
|
||||
res = res | ibz_test_div();
|
||||
res = res | ibz_test_mod();
|
||||
res = res | ibz_test_pow();
|
||||
res = res | ibz_test_gcd();
|
||||
res = res | ibz_test_sqrt_mod_p(reps, prime_n);
|
||||
res = res | ibz_test_rand_interval(reps);
|
||||
res = res | ibz_test_rand_interval_i(reps);
|
||||
res = res | ibz_test_rand_interval_minm_m(reps);
|
||||
res = res | ibz_test_copy_digits();
|
||||
res = res | ibz_test_to_digits();
|
||||
return res;
|
||||
}
|
||||
@@ -1,288 +1,44 @@
|
||||
#include "quaternion_tests.h"
|
||||
|
||||
|
||||
//integer helpers
|
||||
//void ibz_rounded_div(ibz_t *q, const ibz_t *a, const ibz_t *b);
|
||||
int quat_test_integer_ibz_rounded_div(){
|
||||
// int ibz_generate_random_prime(ibz_t *p, int is3mod4, int bitsize);
|
||||
int
|
||||
quat_test_ibz_generate_random_prime()
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t q, a, b;
|
||||
ibz_init(&a);
|
||||
ibz_init(&b);
|
||||
ibz_init(&q);
|
||||
|
||||
// basic tests
|
||||
ibz_set(&a,15);
|
||||
ibz_set(&b,3);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==5);
|
||||
ibz_set(&a,16);
|
||||
ibz_set(&b,3);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==5);
|
||||
ibz_set(&a,17);
|
||||
ibz_set(&b,3);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==6);
|
||||
ibz_set(&a,37);
|
||||
ibz_set(&b,5);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==7);
|
||||
// test sign combination
|
||||
ibz_set(&a,149);
|
||||
ibz_set(&b,12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==12);
|
||||
ibz_set(&a,149);
|
||||
ibz_set(&b,-12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==-12);
|
||||
ibz_set(&a,-149);
|
||||
ibz_set(&b,-12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==12);
|
||||
ibz_set(&a,-149);
|
||||
ibz_set(&b,12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==-12);
|
||||
ibz_set(&a,151);
|
||||
ibz_set(&b,12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==13);
|
||||
ibz_set(&a,-151);
|
||||
ibz_set(&b,-12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==13);
|
||||
ibz_set(&a,151);
|
||||
ibz_set(&b,-12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==-13);
|
||||
ibz_set(&a,-151);
|
||||
ibz_set(&b,12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==-13);
|
||||
//divisibles with sign
|
||||
ibz_set(&a,144);
|
||||
ibz_set(&b,12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==12);
|
||||
ibz_set(&a,-144);
|
||||
ibz_set(&b,-12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==12);
|
||||
ibz_set(&a,144);
|
||||
ibz_set(&b,-12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==-12);
|
||||
ibz_set(&a,-144);
|
||||
ibz_set(&b,12);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==-12);
|
||||
// tests close to 0
|
||||
ibz_set(&a,-12);
|
||||
ibz_set(&b,-25);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==0);
|
||||
ibz_set(&a,12);
|
||||
ibz_set(&b,25);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==0);
|
||||
ibz_set(&a,-12);
|
||||
ibz_set(&b,25);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==0);
|
||||
ibz_set(&a,12);
|
||||
ibz_set(&b,-25);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==0);
|
||||
ibz_set(&a,-12);
|
||||
ibz_set(&b,-23);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==1);
|
||||
ibz_set(&a,12);
|
||||
ibz_set(&b,23);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==1);
|
||||
ibz_set(&a,-12);
|
||||
ibz_set(&b,23);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==-1);
|
||||
ibz_set(&a,12);
|
||||
ibz_set(&b,-23);
|
||||
ibz_rounded_div(&q,&a,&b);
|
||||
res = res || !(ibz_get(&q)==-1);
|
||||
// test output equal input
|
||||
ibz_set(&a,-151);
|
||||
ibz_set(&b,12);
|
||||
ibz_rounded_div(&a,&a,&b);
|
||||
res = res || !(ibz_get(&a)==-13);
|
||||
ibz_set(&a,-151);
|
||||
ibz_set(&b,12);
|
||||
ibz_rounded_div(&b,&a,&b);
|
||||
res = res || !(ibz_get(&b)==-13);
|
||||
// test for cmp not returning 1 or -1 or 0
|
||||
ibz_set(&a,4292606433816540);
|
||||
ibz_set(&b,864673106105940);
|
||||
ibz_rounded_div(&b,&a,&b);
|
||||
res = res || !(ibz_get(&b)==5);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test integer_ibz_rounded_div failed\n");
|
||||
int bitsize, is3mod4, primality_test_attempts;
|
||||
ibz_t p;
|
||||
ibz_init(&p);
|
||||
bitsize = 20;
|
||||
primality_test_attempts = 30;
|
||||
is3mod4 = 1;
|
||||
res = res || !ibz_generate_random_prime(&p, is3mod4, bitsize, primality_test_attempts);
|
||||
res = res || (ibz_probab_prime(&p, 20) == 0);
|
||||
res = res || (ibz_bitsize(&p) < bitsize);
|
||||
res = res || (is3mod4 && (ibz_get(&p) % 4 != 3));
|
||||
bitsize = 30;
|
||||
is3mod4 = 0;
|
||||
res = res || !ibz_generate_random_prime(&p, is3mod4, bitsize, primality_test_attempts);
|
||||
res = res || (ibz_probab_prime(&p, 20) == 0);
|
||||
res = res || (ibz_bitsize(&p) < bitsize);
|
||||
res = res || (is3mod4 && (ibz_get(&p) % 4 != 3));
|
||||
is3mod4 = 1;
|
||||
res = res || !ibz_generate_random_prime(&p, is3mod4, bitsize, primality_test_attempts);
|
||||
res = res || (ibz_probab_prime(&p, 20) == 0);
|
||||
res = res || (ibz_bitsize(&p) < bitsize);
|
||||
res = res || (is3mod4 && (ibz_get(&p) % 4 != 3));
|
||||
if (res) {
|
||||
printf("Quaternion unit test ibz_generate_random_prime failed\n");
|
||||
}
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&q);
|
||||
return(res);
|
||||
ibz_finalize(&p);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// tests for cornacchia helper functions
|
||||
//void ibz_complex_mul(ibz_t *re_res, ibz_t *im_res, const ibz_t *re_a, const ibz_t *im_a, const ibz_t *re_b, const ibz_t *im_b);
|
||||
int quat_test_integer_ibz_complex_mul(){
|
||||
// int ibz_cornacchia_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p);
|
||||
int
|
||||
quat_test_integer_ibz_cornacchia_prime(void)
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t re_res, re_a, re_b, re_cmp, im_res, im_a, im_b, im_cmp;
|
||||
ibz_init(&re_res);
|
||||
ibz_init(&re_a);
|
||||
ibz_init(&re_b);
|
||||
ibz_init(&re_cmp);
|
||||
ibz_init(&im_res);
|
||||
ibz_init(&im_a);
|
||||
ibz_init(&im_b);
|
||||
ibz_init(&im_cmp);
|
||||
|
||||
ibz_set(&re_a, 1);
|
||||
ibz_set(&im_a, 2);
|
||||
ibz_set(&re_b, 3);
|
||||
ibz_set(&im_b, -4);
|
||||
ibz_set(&re_cmp, 11);
|
||||
ibz_set(&im_cmp, 2);
|
||||
ibz_complex_mul(&re_res,&im_res,&re_a,&im_a,&re_b,&im_b);
|
||||
res = res || ibz_cmp(&re_res,&re_cmp);
|
||||
res = res || ibz_cmp(&im_res,&im_cmp);
|
||||
|
||||
ibz_set(&re_a, -3);
|
||||
ibz_set(&im_a, -5);
|
||||
ibz_set(&re_b, 2);
|
||||
ibz_set(&im_b, 4);
|
||||
ibz_set(&re_cmp, 14);
|
||||
ibz_set(&im_cmp, -22);
|
||||
ibz_complex_mul(&re_res,&im_res,&re_a,&im_a,&re_b,&im_b);
|
||||
res = res || ibz_cmp(&re_res,&re_cmp);
|
||||
res = res || ibz_cmp(&im_res,&im_cmp);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test integer_ibz_complex_mul failed\n");
|
||||
}
|
||||
ibz_finalize(&re_res);
|
||||
ibz_finalize(&re_cmp);
|
||||
ibz_finalize(&re_a);
|
||||
ibz_finalize(&re_b);
|
||||
ibz_finalize(&im_res);
|
||||
ibz_finalize(&im_cmp);
|
||||
ibz_finalize(&im_a);
|
||||
ibz_finalize(&im_b);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//void ibz_complex_mul_by_complex_power(ibz_t *re_res, ibz_t *im_res, const ibz_t *re_a, const ibz_t *im_a, int64_t exp);
|
||||
int quat_test_integer_ibz_complex_mul_by_complex_power(){
|
||||
int res = 0;
|
||||
int64_t exp;
|
||||
ibz_t re_res, re_a, re_cmp, im_res, im_a, im_cmp;
|
||||
ibz_init(&re_res);
|
||||
ibz_init(&re_a);
|
||||
ibz_init(&re_cmp);
|
||||
ibz_init(&im_res);
|
||||
ibz_init(&im_a);
|
||||
ibz_init(&im_cmp);
|
||||
|
||||
exp = 0;
|
||||
ibz_set(&re_a, 1);
|
||||
ibz_set(&im_a, 2);
|
||||
ibz_set(&re_res, 3);
|
||||
ibz_set(&im_res, -4);
|
||||
ibz_set(&re_cmp, 3);
|
||||
ibz_set(&im_cmp, -4);
|
||||
ibz_complex_mul_by_complex_power(&re_res,&im_res,&re_a,&im_a,exp);
|
||||
res = res || ibz_cmp(&re_res,&re_cmp);
|
||||
res = res || ibz_cmp(&im_res,&im_cmp);
|
||||
|
||||
exp = 1;
|
||||
ibz_set(&re_a, 1);
|
||||
ibz_set(&im_a, 2);
|
||||
ibz_set(&re_res, 3);
|
||||
ibz_set(&im_res, -4);
|
||||
ibz_set(&re_cmp, 11);
|
||||
ibz_set(&im_cmp, 2);
|
||||
ibz_complex_mul_by_complex_power(&re_res,&im_res,&re_a,&im_a,exp);
|
||||
res = res || ibz_cmp(&re_res,&re_cmp);
|
||||
res = res || ibz_cmp(&im_res,&im_cmp);
|
||||
|
||||
exp = 2;
|
||||
ibz_set(&re_a, 1);
|
||||
ibz_set(&im_a, 2);
|
||||
ibz_set(&re_res, 3);
|
||||
ibz_set(&im_res, -4);
|
||||
ibz_set(&re_cmp, 7);
|
||||
ibz_set(&im_cmp, 24);
|
||||
ibz_complex_mul_by_complex_power(&re_res,&im_res,&re_a,&im_a,exp);
|
||||
res = res || ibz_cmp(&re_res,&re_cmp);
|
||||
res = res || ibz_cmp(&im_res,&im_cmp);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test integer_ibz_complex_mul_by_complex_power failed\n");
|
||||
}
|
||||
ibz_finalize(&re_res);
|
||||
ibz_finalize(&re_cmp);
|
||||
ibz_finalize(&re_a);
|
||||
ibz_finalize(&im_res);
|
||||
ibz_finalize(&im_cmp);
|
||||
ibz_finalize(&im_a);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//int ibz_cornacchia_extended_prime_loop(ibz_t *re_res, ibz_t *im_res, int64_t prime, int64_t val);
|
||||
int quat_test_integer_ibz_cornacchia_extended_prime_loop(){
|
||||
int res = 0;
|
||||
int64_t p, re_a, im_a;
|
||||
ibz_t re_res, re_cmp, im_res, im_cmp, prod;
|
||||
ibz_init(&re_res);
|
||||
ibz_init(&re_cmp);
|
||||
ibz_init(&im_res);
|
||||
ibz_init(&im_cmp);
|
||||
ibz_init(&prod);
|
||||
|
||||
p = 5;
|
||||
ibz_set(&re_res, 1);
|
||||
ibz_set(&im_res, 1);
|
||||
ibz_set(&re_cmp, -1);
|
||||
ibz_set(&im_cmp, 7);
|
||||
ibz_cornacchia_extended_prime_loop(&re_res, &im_res, p, 2);
|
||||
res = res || ibz_cmp(&re_res,&re_cmp);
|
||||
res = res || ibz_cmp(&im_res,&im_cmp);
|
||||
|
||||
p = 7;
|
||||
ibz_set(&re_res, -1);
|
||||
ibz_set(&im_res, 7);
|
||||
ibz_set(&re_cmp, -1);
|
||||
ibz_set(&im_cmp, 7);
|
||||
ibz_cornacchia_extended_prime_loop(&re_res, &im_res, p, 0);
|
||||
res = res || ibz_cmp(&re_res,&re_cmp);
|
||||
res = res || ibz_cmp(&im_res,&im_cmp);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test integer_ibz_cornacchia_extended_prime_loop failed\n");
|
||||
}
|
||||
ibz_finalize(&re_res);
|
||||
ibz_finalize(&re_cmp);
|
||||
ibz_finalize(&im_res);
|
||||
ibz_finalize(&im_cmp);
|
||||
ibz_finalize(&prod);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//int ibz_cornacchia_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p);
|
||||
int quat_test_integer_ibz_cornacchia_prime(){
|
||||
int res = 0;
|
||||
ibz_t x,y,n, prod,c_res,p;
|
||||
ibz_t x, y, n, prod, c_res, p;
|
||||
ibz_init(&x);
|
||||
ibz_init(&y);
|
||||
ibz_init(&n);
|
||||
@@ -293,54 +49,54 @@ int quat_test_integer_ibz_cornacchia_prime(){
|
||||
ibz_set(&n, 1);
|
||||
// there is a solution in these cases
|
||||
ibz_set(&p, 5);
|
||||
if(ibz_cornacchia_prime(&x,&y,&n,&p)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_mul(&prod,&prod,&n);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&p,&c_res);
|
||||
if (ibz_cornacchia_prime(&x, &y, &n, &p)) {
|
||||
ibz_mul(&c_res, &x, &x);
|
||||
ibz_mul(&prod, &y, &y);
|
||||
ibz_mul(&prod, &prod, &n);
|
||||
ibz_add(&c_res, &c_res, &prod);
|
||||
res = res || ibz_cmp(&p, &c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
ibz_set(&p, 2);
|
||||
if(ibz_cornacchia_prime(&x,&y,&n,&p)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_mul(&prod,&prod,&n);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&p,&c_res);
|
||||
if (ibz_cornacchia_prime(&x, &y, &n, &p)) {
|
||||
ibz_mul(&c_res, &x, &x);
|
||||
ibz_mul(&prod, &y, &y);
|
||||
ibz_mul(&prod, &prod, &n);
|
||||
ibz_add(&c_res, &c_res, &prod);
|
||||
res = res || ibz_cmp(&p, &c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
ibz_set(&p, 41);
|
||||
if(ibz_cornacchia_prime(&x,&y,&n,&p)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_mul(&prod,&prod,&n);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&p,&c_res);
|
||||
if (ibz_cornacchia_prime(&x, &y, &n, &p)) {
|
||||
ibz_mul(&c_res, &x, &x);
|
||||
ibz_mul(&prod, &y, &y);
|
||||
ibz_mul(&prod, &prod, &n);
|
||||
ibz_add(&c_res, &c_res, &prod);
|
||||
res = res || ibz_cmp(&p, &c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
ibz_set(&n, 2);
|
||||
ibz_set(&p, 3);
|
||||
if(ibz_cornacchia_prime(&x,&y,&n,&p)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_mul(&prod,&prod,&n);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&p,&c_res);
|
||||
if (ibz_cornacchia_prime(&x, &y, &n, &p)) {
|
||||
ibz_mul(&c_res, &x, &x);
|
||||
ibz_mul(&prod, &y, &y);
|
||||
ibz_mul(&prod, &prod, &n);
|
||||
ibz_add(&c_res, &c_res, &prod);
|
||||
res = res || ibz_cmp(&p, &c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
ibz_set(&n, 3);
|
||||
ibz_set(&p, 7);
|
||||
if(ibz_cornacchia_prime(&x,&y,&n,&p)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_mul(&prod,&prod,&n);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&p,&c_res);
|
||||
if (ibz_cornacchia_prime(&x, &y, &n, &p)) {
|
||||
ibz_mul(&c_res, &x, &x);
|
||||
ibz_mul(&prod, &y, &y);
|
||||
ibz_mul(&prod, &prod, &n);
|
||||
ibz_add(&c_res, &c_res, &prod);
|
||||
res = res || ibz_cmp(&p, &c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
@@ -348,13 +104,17 @@ int quat_test_integer_ibz_cornacchia_prime(){
|
||||
ibz_set(&n, 1);
|
||||
// there is no solution in these cases
|
||||
ibz_set(&p, 7);
|
||||
res = res || ibz_cornacchia_prime(&x,&y,&n,&p);
|
||||
res = res || ibz_cornacchia_prime(&x, &y, &n, &p);
|
||||
ibz_set(&p, 3);
|
||||
res = res || ibz_cornacchia_prime(&x,&y,&n,&p);
|
||||
res = res || ibz_cornacchia_prime(&x, &y, &n, &p);
|
||||
ibz_set(&n, 3);
|
||||
ibz_set(&p, 5);
|
||||
res = res || ibz_cornacchia_prime(&x,&y,&n,&p);
|
||||
if (res != 0){
|
||||
res = res || ibz_cornacchia_prime(&x, &y, &n, &p);
|
||||
// This should be solved
|
||||
ibz_set(&n, 3);
|
||||
ibz_set(&p, 3);
|
||||
res = res || !ibz_cornacchia_prime(&x, &y, &n, &p);
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test integer_ibz_cornacchia_prime failed\n");
|
||||
}
|
||||
ibz_finalize(&x);
|
||||
@@ -366,222 +126,13 @@ int quat_test_integer_ibz_cornacchia_prime(){
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//int ibz_cornacchia_special_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p, const int exp_adjust);
|
||||
int quat_test_integer_ibz_cornacchia_special_prime(){
|
||||
int res = 0;
|
||||
int exp_adjust;
|
||||
ibz_t x,y,n, prod,c_res,p, cmp, two;
|
||||
ibz_init(&x);
|
||||
ibz_init(&y);
|
||||
ibz_init(&n);
|
||||
ibz_init(&p);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&c_res);
|
||||
ibz_init(&cmp);
|
||||
ibz_init(&two);
|
||||
ibz_set(&two,2);
|
||||
|
||||
ibz_set(&n, 3);
|
||||
// there is a solution in these cases
|
||||
ibz_set(&p, 43);
|
||||
exp_adjust = 2;
|
||||
//x^2 + 3y^2 = 4*43, (5,7) is solution
|
||||
if(ibz_cornacchia_special_prime(&x,&y,&n,&p, exp_adjust)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_mul(&prod,&prod,&n);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
ibz_pow(&cmp,&two,exp_adjust);
|
||||
ibz_mul(&cmp,&cmp,&p);
|
||||
res = res || ibz_cmp(&cmp,&c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
ibz_set(&n, 7);
|
||||
exp_adjust = 3;
|
||||
ibz_set(&p, 11);
|
||||
//x^2 + 7y^2 = 8*11, (5,3) is solution
|
||||
if(ibz_cornacchia_special_prime(&x,&y,&n,&p, exp_adjust)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_mul(&prod,&prod,&n);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
ibz_pow(&cmp,&two,exp_adjust);
|
||||
ibz_mul(&cmp,&cmp,&p);
|
||||
res = res || ibz_cmp(&cmp,&c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
/* Failing testcase, needs investigation
|
||||
ibz_set(&n, 15);
|
||||
exp_adjust = 4;
|
||||
ibz_set(&p, 31);
|
||||
//x^2 + 15y^2 = 16*31, (19,3) is solution
|
||||
if(ibz_cornacchia_special_prime(&x,&y,&n,&p, exp_adjust)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_mul(&prod,&prod,&n);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
ibz_pow(&cmp,&two,exp_adjust);
|
||||
ibz_mul(&cmp,&cmp,&p);
|
||||
res = res || ibz_cmp(&cmp,&c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
ibz_set(&n, 3);
|
||||
exp_adjust = 2;
|
||||
ibz_set(&p, 7);
|
||||
//x^2 + 3y^2 = 4*7, (1,3) is solution
|
||||
if(ibz_cornacchia_special_prime(&x,&y,&n,&p, exp_adjust)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_mul(&prod,&prod,&n);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
ibz_pow(&cmp,&two,exp_adjust);
|
||||
ibz_mul(&cmp,&cmp,&p);
|
||||
res = res || ibz_cmp(&cmp,&c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
*/
|
||||
|
||||
// there is no solution in these cases
|
||||
ibz_set(&n, 3);
|
||||
ibz_set(&p, 11);
|
||||
exp_adjust = 3;
|
||||
res = res || ibz_cornacchia_special_prime(&x,&y,&n,&p, exp_adjust);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test integer_ibz_cornacchia_special_prime failed\n");
|
||||
}
|
||||
ibz_finalize(&x);
|
||||
ibz_finalize(&y);
|
||||
ibz_finalize(&n);
|
||||
ibz_finalize(&p);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&c_res);
|
||||
ibz_finalize(&two);
|
||||
ibz_finalize(&cmp);
|
||||
return res;
|
||||
}
|
||||
|
||||
//int ibz_cornacchia_extended(ibz_t *x, ibz_t *y, const ibz_t *n, const short *prime_list, const int prime_list_length, short primality_test_iterations, const ibz_t *bad_primes_prod);
|
||||
int quat_test_integer_ibz_cornacchia_extended(){
|
||||
int res = 0;
|
||||
ibz_t x,y,n, prod,c_res,bad;
|
||||
short primes[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101};
|
||||
int primes_length = 26;
|
||||
short iterations = 20;
|
||||
ibz_init(&x);
|
||||
ibz_init(&y);
|
||||
ibz_init(&n);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&c_res);
|
||||
ibz_init(&bad);
|
||||
ibz_set(&bad,3*7*11*19);
|
||||
|
||||
// there is a solution in these cases
|
||||
ibz_set(&n, 5);
|
||||
if(ibz_cornacchia_extended(&x,&y,&n, primes, 4,iterations, NULL)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&n,&c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
ibz_set(&n, 50);
|
||||
if(ibz_cornacchia_extended(&x,&y,&n, primes, 7,iterations,NULL)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&n,&c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
ibz_set(&n, 4100);
|
||||
if(ibz_cornacchia_extended(&x,&y,&n, primes, primes_length,iterations,&bad)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&n,&c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
// test product of all small primes
|
||||
ibz_set(&n, 5*13*17*29*37*41);
|
||||
ibz_set(&x, 53*61*73*89*97);
|
||||
ibz_mul(&n, &n, &x);
|
||||
ibz_set(&x, 404);
|
||||
ibz_mul(&n, &n, &x);
|
||||
if(ibz_cornacchia_extended(&x,&y,&n, primes, primes_length,iterations,NULL)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&n,&c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
// test with large prime
|
||||
ibz_set(&n, 1381); // prime and 1 mod 4
|
||||
if(ibz_cornacchia_extended(&x,&y,&n, primes, primes_length,iterations,&bad)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&n,&c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
// test with large prime part
|
||||
ibz_set(&n, 5*13*17*29*37*97);
|
||||
ibz_set(&x, 1381); // prime and 1 mod 4
|
||||
ibz_mul(&n, &n, &x);
|
||||
if(ibz_cornacchia_extended(&x,&y,&n, primes, primes_length,iterations,NULL)){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&n,&c_res);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
|
||||
// there is no solution in these cases
|
||||
ibz_set(&n, 7);
|
||||
res = res || ibz_cornacchia_extended(&x,&y,&n, primes, primes_length,iterations,&bad);
|
||||
ibz_set(&n, 3);
|
||||
res = res || ibz_cornacchia_extended(&x,&y,&n, primes, primes_length,iterations,&bad);
|
||||
ibz_set(&n, 6);
|
||||
res = res || ibz_cornacchia_extended(&x,&y,&n, primes, primes_length,iterations,NULL);
|
||||
ibz_set(&n, 30);
|
||||
res = res || ibz_cornacchia_extended(&x,&y,&n, primes, primes_length,iterations,&bad);
|
||||
ibz_set(&n, 30*1381);
|
||||
res = res || ibz_cornacchia_extended(&x,&y,&n, primes, primes_length,iterations,&bad);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test integer_ibz_cornacchia_extended failed\n");
|
||||
}
|
||||
ibz_finalize(&x);
|
||||
ibz_finalize(&y);
|
||||
ibz_finalize(&n);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&c_res);
|
||||
ibz_finalize(&bad);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// run all previous tests
|
||||
int quat_test_integers(){
|
||||
int
|
||||
quat_test_integers(void)
|
||||
{
|
||||
int res = 0;
|
||||
printf("\nRunning quaternion tests of integer functions\n");
|
||||
res = res | quat_test_integer_ibz_rounded_div();
|
||||
res = res | quat_test_integer_ibz_complex_mul();
|
||||
res = res | quat_test_integer_ibz_complex_mul_by_complex_power();
|
||||
res = res | quat_test_integer_ibz_cornacchia_extended_prime_loop();
|
||||
res = res | quat_test_ibz_generate_random_prime();
|
||||
res = res | quat_test_integer_ibz_cornacchia_prime();
|
||||
res = res | quat_test_integer_ibz_cornacchia_special_prime();
|
||||
res = res | quat_test_integer_ibz_cornacchia_extended();
|
||||
return(res);
|
||||
return (res);
|
||||
}
|
||||
|
||||
|
||||
266
src/quaternion/ref/generic/test/lat_ball.c
Normal file
266
src/quaternion/ref/generic/test/lat_ball.c
Normal file
@@ -0,0 +1,266 @@
|
||||
#include "quaternion_tests.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
// int quat_lattice_bound_parallelogram(ibz_vec_4_t *box, ibz_mat_4x4_t *U, const ibz_mat_4x4_t *G,
|
||||
// const ibz_t *radius);
|
||||
int
|
||||
quat_test_lat_ball_paralellogram_randomized(int iterations, int bitsize)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
quat_lattice_t lattice;
|
||||
ibz_t radius, length, tmp;
|
||||
ibz_mat_4x4_t U, G;
|
||||
ibz_vec_4_t box, dbox, x;
|
||||
quat_lattice_init(&lattice);
|
||||
ibz_vec_4_init(&box);
|
||||
ibz_vec_4_init(&dbox);
|
||||
ibz_vec_4_init(&x);
|
||||
ibz_mat_4x4_init(&U);
|
||||
ibz_mat_4x4_init(&G);
|
||||
ibz_init(&radius);
|
||||
ibz_init(&length);
|
||||
ibz_init(&tmp);
|
||||
|
||||
for (int it = 0; it < iterations; it++) {
|
||||
// Create a random positive definite quadatic form
|
||||
#ifndef NDEBUG
|
||||
int randret = quat_test_input_random_lattice_generation(&lattice, bitsize, 1, 0);
|
||||
assert(randret == 0);
|
||||
#else
|
||||
(void)quat_test_input_random_lattice_generation(&lattice, bitsize, 1, 0);
|
||||
#endif
|
||||
ibz_mat_4x4_transpose(&G, &lattice.basis);
|
||||
ibz_mat_4x4_mul(&G, &G, &lattice.basis);
|
||||
|
||||
// Set radius to 2 × sqrt(lattice volume)
|
||||
#ifndef NDEBUG
|
||||
int ok = ibz_mat_4x4_inv_with_det_as_denom(NULL, &radius, &(lattice.basis));
|
||||
assert(ok);
|
||||
#else
|
||||
(void)ibz_mat_4x4_inv_with_det_as_denom(NULL, &radius, &(lattice.basis));
|
||||
#endif
|
||||
ibz_abs(&radius, &radius);
|
||||
ibz_sqrt_floor(&radius, &radius);
|
||||
ibz_mul(&radius, &radius, &ibz_const_two);
|
||||
|
||||
quat_lattice_bound_parallelogram(&box, &U, &G, &radius);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// dbox is a box with sides dbox[i] = 2*box[i] + 1
|
||||
ibz_add(&dbox[i], &box[i], &box[i]);
|
||||
ibz_add(&dbox[i], &dbox[i], &ibz_const_one);
|
||||
// initialize x[i] to the bottom of dbox[i]
|
||||
ibz_neg(&x[i], &dbox[i]);
|
||||
}
|
||||
|
||||
// Integrate U into the Gram matrix
|
||||
ibz_mat_4x4_mul(&G, &U, &G);
|
||||
ibz_mat_4x4_transpose(&U, &U);
|
||||
ibz_mat_4x4_mul(&G, &G, &U);
|
||||
|
||||
// We treat x[0]...x[4] as a counter, incrementing one by one
|
||||
// but skipping values that are inside the parallelogram defined
|
||||
// by box.
|
||||
while (1) {
|
||||
// x is out of the parallelogram, so its length must be
|
||||
// greater than the radius
|
||||
quat_qf_eval(&length, &G, &x);
|
||||
if (ibz_cmp(&length, &radius) <= 0) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Increment counter
|
||||
ibz_add(&x[0], &x[0], &ibz_const_one);
|
||||
// if x[0] just entered the interval
|
||||
ibz_add(&tmp, &x[0], &box[0]);
|
||||
if (ibz_is_zero(&tmp)) {
|
||||
int inbox = 1;
|
||||
for (int i = 1; i < 4; i++) {
|
||||
ibz_abs(&tmp, &x[i]);
|
||||
inbox &= ibz_cmp(&tmp, &box[i]) <= 0;
|
||||
}
|
||||
// if x[1]...x[3] are all in the respective intervals
|
||||
// jump straight to the end of x[0]'s interval
|
||||
if (inbox)
|
||||
ibz_set(&x[0], 1);
|
||||
}
|
||||
|
||||
// if x[0] became positive, loop the counter
|
||||
if (ibz_is_one(&x[0])) {
|
||||
ibz_neg(&x[0], &dbox[0]);
|
||||
int carry = 1;
|
||||
for (int i = 1; carry && i < 4; i++) {
|
||||
ibz_add(&x[i], &x[i], &ibz_const_one);
|
||||
if (ibz_cmp(&x[i], &dbox[i]) > 0) {
|
||||
ibz_neg(&x[i], &dbox[i]);
|
||||
} else {
|
||||
carry = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If there still is a carry, we are at the end
|
||||
if (carry)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quat_lattice_finalize(&lattice);
|
||||
ibz_vec_4_finalize(&box);
|
||||
ibz_vec_4_finalize(&dbox);
|
||||
ibz_vec_4_finalize(&x);
|
||||
ibz_mat_4x4_finalize(&U);
|
||||
ibz_mat_4x4_finalize(&G);
|
||||
ibz_finalize(&radius);
|
||||
ibz_finalize(&length);
|
||||
ibz_finalize(&tmp);
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test lat_ball_paralellogram_randomized failed\n");
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
// helper which tests quat_lattice_sample_from_ball on given input
|
||||
int
|
||||
quat_test_lat_ball_sample_helper(const quat_lattice_t *lat, const ibz_t *radius, const quat_alg_t *alg)
|
||||
{
|
||||
int res = 0;
|
||||
quat_alg_elem_t vec;
|
||||
ibz_t norm_d, norm_n;
|
||||
ibz_init(&norm_d);
|
||||
ibz_init(&norm_n);
|
||||
quat_alg_elem_init(&vec);
|
||||
// check return value
|
||||
res |= !quat_lattice_sample_from_ball(&vec, lat, alg, radius);
|
||||
// check result is in lattice
|
||||
res |= !quat_lattice_contains(NULL, lat, &vec);
|
||||
quat_alg_norm(&norm_n, &norm_d, &vec, alg);
|
||||
// test that n/d <= r so that n <= rd
|
||||
ibz_mul(&norm_d, &norm_d, radius);
|
||||
res |= !(ibz_cmp(&norm_n, &norm_d) <= 0);
|
||||
|
||||
ibz_finalize(&norm_d);
|
||||
ibz_finalize(&norm_n);
|
||||
quat_alg_elem_finalize(&vec);
|
||||
return res;
|
||||
}
|
||||
|
||||
// int quat_lattice_sample_from_ball(ibz_vec_4_t *x, const quat_lattice_t *lattice, const quat_alg_t
|
||||
// *alg, const ibz_t *radius);
|
||||
int
|
||||
quat_test_lat_ball_sample_from_ball()
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
ibz_t norm_n, norm_d;
|
||||
quat_alg_t alg;
|
||||
quat_alg_elem_t vec;
|
||||
quat_lattice_t lattice;
|
||||
ibz_t radius;
|
||||
|
||||
quat_alg_init_set_ui(&alg, 11);
|
||||
ibz_init(&norm_n);
|
||||
ibz_init(&norm_d);
|
||||
quat_lattice_init(&lattice);
|
||||
ibz_init(&radius);
|
||||
quat_alg_elem_init(&vec);
|
||||
|
||||
for (int it = 0; it < 3; it++) {
|
||||
if (it == 0) {
|
||||
ibz_mat_4x4_identity(&(lattice.basis)); // Test inner product
|
||||
} else if (it == 1) {
|
||||
ibz_set(&lattice.denom, 13); // Test with denominator
|
||||
} else { // if (it == 2)
|
||||
// Test a very much non-orthogonal qf
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
ibz_add(&(lattice.basis[i][j]), &(lattice.basis[i][j]), &ibz_const_one);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ibz_set(&radius, i + 1);
|
||||
res |= quat_test_lat_ball_sample_helper(&lattice, &radius, &alg);
|
||||
if (res != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test lat_ball_sample_from_ball failed\n");
|
||||
}
|
||||
|
||||
quat_alg_finalize(&alg);
|
||||
quat_lattice_finalize(&lattice);
|
||||
ibz_finalize(&radius);
|
||||
quat_alg_elem_finalize(&vec);
|
||||
ibz_finalize(&norm_n);
|
||||
ibz_finalize(&norm_d);
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
quat_test_lat_ball_sample_from_ball_randomized(int iterations, int bitsize)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
ibz_t norm_n, norm_d;
|
||||
quat_alg_t alg;
|
||||
quat_alg_elem_t vec;
|
||||
quat_lattice_t *lattices;
|
||||
ibz_t radius;
|
||||
|
||||
quat_alg_init_set_ui(&alg, 11);
|
||||
ibz_init(&norm_n);
|
||||
ibz_init(&norm_d);
|
||||
lattices = malloc(iterations * sizeof(quat_lattice_t));
|
||||
for (int i = 0; i < iterations; i++)
|
||||
quat_lattice_init(&(lattices[i]));
|
||||
ibz_init(&radius);
|
||||
quat_alg_elem_init(&vec);
|
||||
|
||||
int randret = quat_test_input_random_lattice_generation(lattices, bitsize, iterations, 0);
|
||||
|
||||
if (!randret) {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
#ifndef NDEBUG
|
||||
|
||||
int ok = ibz_mat_4x4_inv_with_det_as_denom(NULL, &radius, &(lattices[i].basis));
|
||||
assert(ok);
|
||||
#else
|
||||
(void)ibz_mat_4x4_inv_with_det_as_denom(NULL, &radius, &(lattices[i].basis));
|
||||
#endif
|
||||
ibz_abs(&radius, &radius);
|
||||
res |= quat_test_lat_ball_sample_helper(&(lattices[i]), &radius, &alg);
|
||||
if (res != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test lat_ball_sample_from_ball_randomized failed\n");
|
||||
}
|
||||
|
||||
quat_alg_finalize(&alg);
|
||||
for (int i = 0; i < iterations; i++)
|
||||
quat_lattice_finalize(&(lattices[i]));
|
||||
free(lattices);
|
||||
ibz_finalize(&radius);
|
||||
quat_alg_elem_finalize(&vec);
|
||||
ibz_finalize(&norm_n);
|
||||
ibz_finalize(&norm_d);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// run all previous tests
|
||||
int
|
||||
quat_test_lat_ball(void)
|
||||
{
|
||||
int res = 0;
|
||||
printf("\nRunning quaternion tests for sampling lattice points of bounded norm\n");
|
||||
res = res | quat_test_lat_ball_sample_from_ball();
|
||||
res = res | quat_test_lat_ball_sample_from_ball_randomized(100, 10);
|
||||
res = res | quat_test_lat_ball_paralellogram_randomized(100, 100);
|
||||
return (res);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,218 +0,0 @@
|
||||
#include "quaternion_tests.h"
|
||||
|
||||
//void ibz_mat_howell(int rows, int cols, ibz_t howell[rows][rows+1], const ibz_t mat[rows][cols], ibz_t *mod)
|
||||
int quat_test_ibz_mat_howell(){
|
||||
int res = 0;
|
||||
|
||||
// Examples from Mulders & Storjohan
|
||||
|
||||
ibz_t mod;
|
||||
ibz_t stormin[3][3], stormout[3][4], stormtrans[4][4], expected[3][4];
|
||||
ibz_init(&mod);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++)
|
||||
ibz_init(&stormin[i][j]);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_init(&stormout[i][j]);
|
||||
ibz_init(&expected[i][j]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
ibz_init(&stormtrans[i][j]);
|
||||
|
||||
ibz_set(&mod, 12);
|
||||
ibz_set(&expected[0][2], 4);
|
||||
ibz_set(&expected[1][2], 1);
|
||||
ibz_set(&expected[2][3], 1);
|
||||
|
||||
ibz_set(&stormin[0][0], 4);
|
||||
ibz_set(&stormin[1][0], 1);
|
||||
ibz_set(&stormin[2][1], 5);
|
||||
int zeros = ibz_mat_howell(3, 3, stormout, stormtrans, stormin, &mod);
|
||||
res |= zeros != 2;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 3; j++)
|
||||
res |= ibz_cmp(&stormout[i][j], &expected[i][j]);
|
||||
|
||||
ibz_set(&stormin[0][0], 8);
|
||||
ibz_set(&stormin[1][0], 5);
|
||||
ibz_set(&stormin[2][0], 5);
|
||||
ibz_set(&stormin[1][1], 9);
|
||||
ibz_set(&stormin[2][1], 8);
|
||||
ibz_set(&stormin[2][2], 10);
|
||||
zeros = ibz_mat_howell(3, 3, stormout, stormtrans, stormin, &mod);
|
||||
res |= zeros != 2;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
res |= ibz_cmp(&stormout[i][j], &expected[i][j]);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++)
|
||||
ibz_finalize(&stormin[i][j]);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ibz_finalize(&stormout[i][j]);
|
||||
ibz_finalize(&expected[i][j]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
ibz_finalize(&stormtrans[i][j]);
|
||||
|
||||
// An example computed in Pari
|
||||
ibz_t in[5][3], out[5][6], exp[5][6], trans[6][6];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for (int j = 0; j < 3; j++)
|
||||
ibz_init(&in[i][j]);
|
||||
for (int j = 0; j < 6; j++) {
|
||||
ibz_init(&out[i][j]);
|
||||
ibz_init(&exp[i][j]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 6; i++)
|
||||
for (int j = 0; j < 6; j++)
|
||||
ibz_init(&trans[i][j]);
|
||||
|
||||
ibz_set(&mod, 60);
|
||||
|
||||
ibz_set(&in[0][0], 1);
|
||||
ibz_set(&in[0][1], 2);
|
||||
ibz_set(&in[0][2], -3);
|
||||
ibz_set(&in[1][0], 4);
|
||||
ibz_set(&in[1][1], 5);
|
||||
ibz_set(&in[1][2], 6);
|
||||
ibz_set(&in[2][0], 7);
|
||||
ibz_set(&in[2][1], 8);
|
||||
ibz_set(&in[2][2], 19);
|
||||
ibz_set(&in[3][0], 10);
|
||||
ibz_set(&in[3][1], 11);
|
||||
ibz_set(&in[3][2], 12);
|
||||
ibz_set(&in[4][0], 13);
|
||||
ibz_set(&in[4][1], 14);
|
||||
ibz_set(&in[4][2], 15);
|
||||
|
||||
ibz_set(&exp[0][2], 12);
|
||||
ibz_set(&exp[0][3], 6);
|
||||
ibz_set(&exp[2][3], 10);
|
||||
ibz_set(&exp[1][4], 9);
|
||||
ibz_set(&exp[2][4], 6);
|
||||
ibz_set(&exp[3][4], 3);
|
||||
ibz_set(&exp[0][5], 1);
|
||||
ibz_set(&exp[1][5], 1);
|
||||
ibz_set(&exp[2][5], 1);
|
||||
ibz_set(&exp[3][5], 1);
|
||||
ibz_set(&exp[4][5], 1);
|
||||
|
||||
zeros = ibz_mat_howell(5, 3, out, trans, in, &mod);
|
||||
res |= zeros != 2;
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
for (int j = 0; j < 6; j++)
|
||||
res |= ibz_cmp(&out[i][j], &exp[i][j]);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test ibz_mat_howell failed\n");
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for (int j = 0; j < 3; j++)
|
||||
ibz_finalize(&in[i][j]);
|
||||
for (int j = 0; j < 6; j++) {
|
||||
ibz_finalize(&out[i][j]);
|
||||
ibz_finalize(&exp[i][j]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 6; i++)
|
||||
for (int j = 0; j < 6; j++)
|
||||
ibz_finalize(&trans[i][j]);
|
||||
ibz_finalize(&mod);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//void ibz_mat_right_ker_mod(int rows, int cols, ibz_t ker[cols][rows], const ibz_t mat[rows][cols], ibz_t *mod)
|
||||
int quat_test_ibz_mat_right_ker_mod() {
|
||||
int res = 0;
|
||||
|
||||
// An example computed in Pari
|
||||
ibz_t mod, a, b, tmp;
|
||||
ibz_init(&mod);
|
||||
ibz_init(&a);
|
||||
ibz_init(&b);
|
||||
ibz_init(&tmp);
|
||||
ibz_t mat[5][3], ker[3][5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
ibz_init(&mat[i][j]);
|
||||
ibz_init(&ker[j][i]);
|
||||
}
|
||||
}
|
||||
|
||||
ibz_set(&mod, 60);
|
||||
|
||||
ibz_set(&mat[0][0], 1);
|
||||
ibz_set(&mat[0][1], 2);
|
||||
ibz_set(&mat[0][2], -3);
|
||||
ibz_set(&mat[1][0], 4);
|
||||
ibz_set(&mat[1][1], 5);
|
||||
ibz_set(&mat[1][2], 6);
|
||||
ibz_set(&mat[2][0], 7);
|
||||
ibz_set(&mat[2][1], 8);
|
||||
ibz_set(&mat[2][2], 19);
|
||||
ibz_set(&mat[3][0], 10);
|
||||
ibz_set(&mat[3][1], 11);
|
||||
ibz_set(&mat[3][2], 12);
|
||||
ibz_set(&mat[4][0], 13);
|
||||
ibz_set(&mat[4][1], 14);
|
||||
ibz_set(&mat[4][2], 15);
|
||||
|
||||
// self-testing thanks to assertions
|
||||
ibz_mat_right_ker_mod(5, 3, ker, mat, &mod);
|
||||
|
||||
// Randomized test
|
||||
ibz_set(&mod, 6402373705728000l);
|
||||
for (int r = 0; r < 10; r++) {
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (int j = 0; j < 3; j++)
|
||||
ibz_rand_interval(&mat[i][j], &ibz_const_zero, &mod);
|
||||
for (int i = 2; i < 5; i++) {
|
||||
ibz_rand_interval(&a, &ibz_const_zero, &mod);
|
||||
ibz_rand_interval(&b, &ibz_const_zero, &mod);
|
||||
for (int j = 0; j < 3; j++) {
|
||||
ibz_mul(&tmp, &mat[0][j], &a);
|
||||
ibz_mul(&mat[i][j], &mat[1][1], &b);
|
||||
ibz_add(&mat[i][j], &mat[i][j], &tmp);
|
||||
ibz_mod(&mat[i][j], &mat[i][j], &mod);
|
||||
}
|
||||
}
|
||||
|
||||
// self-testing thanks to assertions
|
||||
ibz_mat_right_ker_mod(5, 3, ker, mat, &mod);
|
||||
}
|
||||
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test ibz_mat_howell failed\n");
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
ibz_finalize(&mat[i][j]);
|
||||
ibz_finalize(&ker[j][i]);
|
||||
}
|
||||
}
|
||||
ibz_finalize(&mod);
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&tmp);
|
||||
return res;
|
||||
}
|
||||
|
||||
// run all previous tests
|
||||
int quat_test_matkermod(){
|
||||
int res = 0;
|
||||
printf("\nRunning quaternion tests of matkermod\n");
|
||||
res = res | quat_test_ibz_mat_howell();
|
||||
res = res | quat_test_ibz_mat_right_ker_mod();
|
||||
return(res);
|
||||
}
|
||||
211
src/quaternion/ref/generic/test/mini-gmp.c
Normal file
211
src/quaternion/ref/generic/test/mini-gmp.c
Normal file
@@ -0,0 +1,211 @@
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "mini-gmp-extra.h"
|
||||
#include "intbig_internal.h"
|
||||
#include "rng.h"
|
||||
|
||||
#define RANDOM_TEST_ITERS 1000
|
||||
|
||||
int
|
||||
mini_gmp_test_mpz_legendre(void)
|
||||
{
|
||||
int res = 0;
|
||||
const int levels = 3;
|
||||
const int cofactor[] = { 5, 65, 27 };
|
||||
const int e[] = { 248, 376, 500 };
|
||||
|
||||
int as[] = { -2, -1, 0, 1, 2 };
|
||||
// clang-format off
|
||||
int legendre[3][5] = {
|
||||
{ -1, -1, 0, 1, 1, },
|
||||
{ -1, -1, 0, 1, 1, },
|
||||
{ -1, -1, 0, 1, 1, },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
mpz_t a, p;
|
||||
mpz_init(a);
|
||||
mpz_init(p);
|
||||
|
||||
for (int i = 0; i < levels; i++) {
|
||||
// build cofactor*2^e - 1 for the i-th level
|
||||
mpz_set_ui(p, 1);
|
||||
mpz_mul_2exp(p, p, e[i]);
|
||||
mpz_mul_ui(p, p, cofactor[i]);
|
||||
mpz_sub_ui(p, p, 1);
|
||||
|
||||
for (unsigned long j = 0; j < sizeof(as) / sizeof(as[0]); j++) {
|
||||
mpz_set_si(a, as[j]);
|
||||
res = res | (mini_mpz_legendre(a, p) != legendre[i][j]);
|
||||
}
|
||||
|
||||
#if defined(__GMP_H__)
|
||||
for (int j = 0; j < RANDOM_TEST_ITERS; j++) {
|
||||
ibz_rand_interval(&a, &ibz_const_zero, &p);
|
||||
// Compare against the full GMP implementation
|
||||
res = res | (mini_mpz_legendre(a, p) != mpz_legendre(a, p));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
mpz_clear(a);
|
||||
mpz_clear(p);
|
||||
|
||||
if (res) {
|
||||
printf("mini-gmp test mpz_legendre failed\n");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef union
|
||||
{
|
||||
double d;
|
||||
int64_t s64;
|
||||
unsigned char uc[sizeof(int64_t)];
|
||||
} double_int64_uchar_t;
|
||||
|
||||
int
|
||||
mini_gmp_test_mpz_get_d_2exp(void)
|
||||
{
|
||||
int res = 0;
|
||||
signed long int e, e2 UNUSED;
|
||||
double d, d2 UNUSED;
|
||||
mpz_t op;
|
||||
|
||||
mpz_init(op);
|
||||
|
||||
// Test 0
|
||||
mpz_set_si(op, 0);
|
||||
d = mini_mpz_get_d_2exp(&e, op);
|
||||
res = res | (e != 0);
|
||||
res = res | (d != 0.0); // exact floating point comparison
|
||||
|
||||
// Test 1
|
||||
mpz_set_si(op, 1);
|
||||
d = mini_mpz_get_d_2exp(&e, op);
|
||||
res = res | (e != 1);
|
||||
res = res | (d != 0.5); // exact floating point comparison
|
||||
|
||||
// Test -1
|
||||
mpz_set_si(op, -1);
|
||||
d = mini_mpz_get_d_2exp(&e, op);
|
||||
res = res | (e != 1);
|
||||
res = res | (d != -0.5); // exact floating point comparison
|
||||
|
||||
// Test a few powers of 2: 2^1, 2^2, 2^4, 2^8, ..., 2^65536, and their negatives
|
||||
for (int i = 0; i <= 16; i++) {
|
||||
mpz_set_ui(op, 1);
|
||||
mpz_mul_2exp(op, op, 1 << i);
|
||||
|
||||
d = mini_mpz_get_d_2exp(&e, op);
|
||||
res = res | (e != (1 << i) + 1);
|
||||
res = res | (d != 0.5); // exact floating point comparison
|
||||
|
||||
mpz_neg(op, op);
|
||||
d = mini_mpz_get_d_2exp(&e, op);
|
||||
res = res | (e != (1 << i) + 1);
|
||||
res = res | (d != -0.5); // exact floating point comparison
|
||||
}
|
||||
|
||||
// Test random doubles with random exponent
|
||||
double_int64_uchar_t dd;
|
||||
volatile uint16_t ee;
|
||||
|
||||
for (uint32_t i = 0; i < RANDOM_TEST_ITERS; i++) {
|
||||
randombytes(dd.uc, sizeof(dd.uc));
|
||||
randombytes((unsigned char *)&ee, sizeof(ee));
|
||||
|
||||
#ifdef TARGET_BIG_ENDIAN
|
||||
// Ensure reproducibility in big-endian systems
|
||||
dd.s64 = BSWAP64(dd.s64);
|
||||
ee = BSWAP16(ee);
|
||||
#endif
|
||||
|
||||
dd.s64 &= 0x800fffffffffffff; // clear exponent
|
||||
dd.s64 |= 0x3fe0000000000000; // set exponent to -1
|
||||
|
||||
if (ee >= DBL_MANT_DIG) {
|
||||
mpz_set_d(op, dd.d * (INT64_C(1) << DBL_MANT_DIG));
|
||||
mpz_mul_2exp(op, op, ee - DBL_MANT_DIG);
|
||||
} else {
|
||||
// Since it fits in a double, round it first to ensure it's an integer
|
||||
dd.d = round(dd.d * (INT64_C(1) << ee));
|
||||
mpz_set_d(op, dd.d);
|
||||
dd.d /= INT64_C(1) << ee;
|
||||
// These cases (-1, 0, 1) were already tested, and +/- 1 would require special-casing below
|
||||
if (fabs(dd.d) <= 1.0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
d = mini_mpz_get_d_2exp(&e, op);
|
||||
|
||||
res = res | (e != ee);
|
||||
res = res | (d != dd.d);
|
||||
|
||||
#if defined(__GMP_H__)
|
||||
// Compare against the full GMP implementation
|
||||
d2 = mpz_get_d_2exp(&e2, op);
|
||||
|
||||
res = res | (e != e2);
|
||||
res = res | (d != d2);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__GMP_H__)
|
||||
for (int exp2 = 1023; exp2 <= 1025; exp2++) {
|
||||
for (int sign_outer = -1; sign_outer <= 1; sign_outer += 2) {
|
||||
for (int sign_inner = -1; sign_inner <= 1; sign_inner += 2) {
|
||||
for (int i = 1; i < 15; i++) {
|
||||
mpz_set_si(op, i);
|
||||
mpz_mul_2exp(op, op, 55);
|
||||
if (sign_inner > 0)
|
||||
mpz_add_ui(op, op, 1);
|
||||
else
|
||||
mpz_sub_ui(op, op, 1);
|
||||
mpz_mul_2exp(op, op, exp2 - 55);
|
||||
mpz_mul_si(op, op, sign_outer);
|
||||
|
||||
d = mini_mpz_get_d_2exp(&e, op);
|
||||
d2 = mpz_get_d_2exp(&e2, op);
|
||||
|
||||
res = res | (e != e2);
|
||||
res = res | (d != d2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test random integers
|
||||
for (uint32_t i = 0; i < RANDOM_TEST_ITERS; i++) {
|
||||
ibz_rand_interval_bits(&op, 8 * (i + 1));
|
||||
|
||||
d = mini_mpz_get_d_2exp(&e, op);
|
||||
d2 = mpz_get_d_2exp(&e2, op);
|
||||
|
||||
res = res | (e != e2);
|
||||
res = res | (d != d2);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (res) {
|
||||
printf("mini-gmp test mpz_get_d_2exp failed\n");
|
||||
}
|
||||
|
||||
mpz_clear(op);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
mini_gmp_test(void)
|
||||
{
|
||||
int res = 0;
|
||||
printf("\nRunning tests for implementations of GMP functions missing from the mini-GMP API\n");
|
||||
res = res | mini_gmp_test_mpz_legendre();
|
||||
res = res | mini_gmp_test_mpz_get_d_2exp();
|
||||
return res;
|
||||
}
|
||||
384
src/quaternion/ref/generic/test/normeq.c
Normal file
384
src/quaternion/ref/generic/test/normeq.c
Normal file
@@ -0,0 +1,384 @@
|
||||
#include "quaternion_tests.h"
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
// helpers for setting parameters
|
||||
|
||||
// test if parameters are such that represent_inter is likely to find a solution
|
||||
int
|
||||
quat_test_input_for_repres_bound(const ibz_t *p, const ibz_t *M, int q)
|
||||
{
|
||||
ibz_t c, r;
|
||||
ibz_init(&c);
|
||||
ibz_init(&r);
|
||||
ibz_set(&r, q);
|
||||
ibz_mul(&r, &r, p);
|
||||
ibz_div(&c, &r, M, &r);
|
||||
ibz_set(&r, 1 << 20);
|
||||
int res = (ibz_cmp(&r, &c) <= 0);
|
||||
ibz_finalize(&c);
|
||||
ibz_finalize(&r);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// 1 if ok, 0 if error
|
||||
int
|
||||
quat_test_special_extremal_setup(quat_represent_integer_params_t *params, const quat_alg_t *alg)
|
||||
{ // check the order is maximal and i,j generate a suborder
|
||||
int res = 1;
|
||||
ibz_vec_4_t ij;
|
||||
quat_lattice_t lat;
|
||||
quat_lattice_t test;
|
||||
ibz_vec_4_init(&ij);
|
||||
quat_lattice_init(&lat);
|
||||
quat_lattice_init(&test);
|
||||
quat_alg_coord_mul(&ij, &(params->order->z.coord), &(params->order->t.coord), alg);
|
||||
ibz_copy(&(lat.denom), &(params->order->z.denom));
|
||||
ibz_copy(&(lat.basis[0][0]), &(lat.denom));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_copy(&(lat.basis[i][3]), &(ij[i]));
|
||||
ibz_mul(&(lat.basis[i][2]), &(params->order->t.coord[i]), &(lat.denom));
|
||||
ibz_copy(&(lat.basis[i][1]), &(params->order->z.coord[i]));
|
||||
}
|
||||
quat_lattice_hnf(&lat);
|
||||
quat_lattice_mul(&test, &lat, &lat, alg);
|
||||
res = res && quat_lattice_inclusion(&test, &lat);
|
||||
quat_lattice_mul(&test, &(params->order->order), &(params->order->order), alg);
|
||||
res = res && quat_lattice_inclusion(&test, &(params->order->order));
|
||||
res = res && quat_order_is_maximal(&(params->order->order), alg);
|
||||
res = res && quat_lattice_inclusion(&lat, &(params->order->order));
|
||||
ibz_vec_4_finalize(&ij);
|
||||
quat_lattice_finalize(&lat);
|
||||
quat_lattice_finalize(&test);
|
||||
return (res);
|
||||
}
|
||||
|
||||
void
|
||||
quat_test_set_params_standard(quat_represent_integer_params_t *params,
|
||||
quat_p_extremal_maximal_order_t *order,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
quat_lattice_O0_set_extremal(order);
|
||||
|
||||
params->algebra = alg;
|
||||
params->order = order;
|
||||
assert(quat_test_special_extremal_setup(params, alg));
|
||||
}
|
||||
|
||||
void
|
||||
quat_test_set_params_non_standard(quat_represent_integer_params_t *params,
|
||||
quat_p_extremal_maximal_order_t *order,
|
||||
const quat_alg_t *alg)
|
||||
{
|
||||
ibz_set_from_str(&order->z.coord[1], "214764116738303679745780048598183569015", 10);
|
||||
ibz_set(&order->z.coord[2], 0);
|
||||
ibz_set_from_str(&order->z.coord[3], "1", 10);
|
||||
ibz_set_from_str(&order->z.denom, "73403150722045993989123427738005336972", 10);
|
||||
ibz_set(&order->t.coord[2], 1);
|
||||
ibz_set(&order->t.denom, 1);
|
||||
order->q = 13;
|
||||
ibz_set_from_str(&(order->order.basis[0][0]), "73403150722045993989123427738005336972", 10);
|
||||
ibz_set_from_str(&(order->order.basis[1][1]),
|
||||
"2694011267961700664357934052637599020390646823337886018360381743577635064392",
|
||||
10);
|
||||
ibz_set_from_str(&(order->order.basis[2][2]), "36701575361022996994561713869002668486", 10);
|
||||
ibz_set(&(order->order.basis[3][3]), 1);
|
||||
ibz_set_from_str(&(order->order.basis[0][2]), "36701575361022996994561713869002668486", 10);
|
||||
ibz_set_from_str(&(order->order.basis[0][3]), "0", 10);
|
||||
ibz_set_from_str(&(order->order.basis[1][2]), "0", 10);
|
||||
ibz_set_from_str(&(order->order.basis[1][3]), "214764116738303679745780048598183569015", 10);
|
||||
ibz_set_from_str(&(order->order.denom), "73403150722045993989123427738005336972", 10);
|
||||
|
||||
params->algebra = alg;
|
||||
params->order = order;
|
||||
|
||||
assert(quat_test_special_extremal_setup(params, alg));
|
||||
}
|
||||
|
||||
// void quat_order_elem_create(quat_alg_elem_t *elem, const quat_p_extremal_maximal_order_t *order,
|
||||
// const ibz_vec_4_t *coeffs, const quat_alg_t *Bpoo);
|
||||
int
|
||||
quat_test_order_elem_create()
|
||||
{
|
||||
int res = 0;
|
||||
quat_p_extremal_maximal_order_t O0;
|
||||
ibz_vec_4_t vec, cmp;
|
||||
quat_alg_t alg;
|
||||
quat_alg_elem_t elem;
|
||||
ibz_vec_4_init(&vec);
|
||||
ibz_vec_4_init(&cmp);
|
||||
quat_alg_elem_init(&elem);
|
||||
quat_alg_elem_init(&(O0.z));
|
||||
quat_alg_elem_init(&(O0.t));
|
||||
quat_lattice_init(&(O0.order));
|
||||
quat_alg_init_set_ui(&alg, 103);
|
||||
|
||||
quat_lattice_O0_set_extremal(&O0);
|
||||
ibz_vec_4_set(&vec, 1, 7, 2, -2);
|
||||
ibz_vec_4_copy(&cmp, &vec);
|
||||
ibz_neg(&(cmp[3]), &(cmp[3]));
|
||||
quat_order_elem_create(&elem, &O0, &vec, &alg);
|
||||
res = res | ibz_cmp(&(elem.denom), &ibz_const_one);
|
||||
for (int i = 0; i < 4; i++)
|
||||
res = res | ibz_cmp(&(elem.coord[i]), &cmp[i]);
|
||||
|
||||
if (res) {
|
||||
printf("Quaternion unit test order_elem_create failed\n");
|
||||
}
|
||||
ibz_vec_4_finalize(&vec);
|
||||
ibz_vec_4_finalize(&cmp);
|
||||
quat_alg_elem_finalize(&elem);
|
||||
quat_alg_elem_finalize(&(O0.z));
|
||||
quat_alg_elem_finalize(&(O0.t));
|
||||
quat_lattice_finalize(&(O0.order));
|
||||
quat_alg_finalize(&alg);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// int quat_sampling_random_ideal_O0_given_norm(quat_left_ideal_t *lideal,const ibz_t *norm,int
|
||||
// is_prime,const quat_represent_integer_params_t *params,int prime_sampling_attempts);
|
||||
int
|
||||
quat_test_sampling_random_ideal_O0_given_norm()
|
||||
{
|
||||
int res = 0;
|
||||
quat_left_ideal_t lideal;
|
||||
quat_lattice_t test;
|
||||
quat_represent_integer_params_t params;
|
||||
quat_p_extremal_maximal_order_t O0;
|
||||
quat_alg_t alg;
|
||||
ibz_t p, norm, coprime;
|
||||
quat_lattice_init(&test);
|
||||
ibz_init(&norm);
|
||||
ibz_init(&p);
|
||||
ibz_init(&coprime);
|
||||
quat_left_ideal_init(&lideal);
|
||||
quat_alg_elem_init(&(O0.z));
|
||||
quat_alg_elem_init(&(O0.t));
|
||||
quat_lattice_init(&(O0.order));
|
||||
params.primality_test_iterations = 30;
|
||||
ibz_set(&p, 1533069323);
|
||||
quat_alg_init_set(&alg, &p);
|
||||
quat_test_set_params_standard(¶ms, &O0, &alg);
|
||||
ibz_set(&p, 1338708463);
|
||||
res = res || !quat_sampling_random_ideal_O0_given_norm(&lideal, &p, 1, ¶ms, NULL);
|
||||
res = res || (ibz_cmp(&(lideal.norm), &p) != 0);
|
||||
quat_lideal_norm(&lideal);
|
||||
res = res || (ibz_cmp(&(lideal.norm), &p) != 0);
|
||||
res = res || !ibz_mat_4x4_equal(&(O0.order.basis), &(lideal.parent_order->basis));
|
||||
res = res || (0 != ibz_cmp(&(O0.order.denom), &(lideal.parent_order->denom)));
|
||||
quat_lattice_mul(&test, &(lideal.lattice), &(lideal.lattice), &alg);
|
||||
res = res || !quat_lattice_inclusion(&test, &(lideal.lattice));
|
||||
|
||||
ibz_set(&p, 3093 * 59471);
|
||||
ibz_set(&coprime, 1533069337);
|
||||
res = res || !quat_sampling_random_ideal_O0_given_norm(&lideal, &p, 0, ¶ms, &coprime);
|
||||
res = res || (ibz_cmp(&(lideal.norm), &p) != 0);
|
||||
quat_lideal_norm(&lideal);
|
||||
res = res || (ibz_cmp(&(lideal.norm), &p) != 0);
|
||||
res = res || !ibz_mat_4x4_equal(&(O0.order.basis), &(lideal.parent_order->basis));
|
||||
res = res || (0 != ibz_cmp(&(O0.order.denom), &(lideal.parent_order->denom)));
|
||||
quat_lattice_mul(&test, &(lideal.lattice), &(lideal.lattice), &alg);
|
||||
res = res || !quat_lattice_inclusion(&test, &(lideal.lattice));
|
||||
|
||||
if (res) {
|
||||
printf("Quaternion unit test sampling_random_ideal_O0_given_norm failed\n");
|
||||
}
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
quat_alg_elem_finalize(&(O0.z));
|
||||
quat_alg_elem_finalize(&(O0.t));
|
||||
quat_lattice_finalize(&(O0.order));
|
||||
ibz_finalize(&norm);
|
||||
ibz_finalize(&p);
|
||||
ibz_finalize(&coprime);
|
||||
quat_lattice_finalize(&test);
|
||||
quat_alg_finalize(&alg);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// void quat_change_to_O0_basis(ibz_vec_4_t *vec, const quat_alg_elem_t *el);
|
||||
int
|
||||
quat_test_change_to_O0_basis()
|
||||
{
|
||||
int res = 0;
|
||||
quat_alg_elem_t cmp, elem;
|
||||
ibz_vec_4_t out;
|
||||
quat_lattice_t O0;
|
||||
quat_alg_elem_init(&elem);
|
||||
quat_alg_elem_init(&cmp);
|
||||
ibz_vec_4_init(&out);
|
||||
quat_lattice_init(&O0);
|
||||
quat_lattice_O0_set(&O0);
|
||||
|
||||
quat_alg_elem_set(&cmp, 2, 2, 7, 1, -4);
|
||||
quat_alg_elem_copy(&elem, &cmp);
|
||||
quat_change_to_O0_basis(&out, &elem);
|
||||
res = res || !quat_alg_elem_equal(&elem, &cmp);
|
||||
quat_alg_elem_set(&elem, 1, 0, 0, 0, 0);
|
||||
ibz_mat_4x4_eval(&(elem.coord), &(O0.basis), &out);
|
||||
ibz_copy(&(elem.denom), &(O0.denom));
|
||||
res = res || !quat_alg_elem_equal(&elem, &cmp);
|
||||
|
||||
quat_alg_elem_set(&cmp, 2, 1, 0, 6, -3);
|
||||
quat_alg_elem_copy(&elem, &cmp);
|
||||
quat_change_to_O0_basis(&out, &elem);
|
||||
res = res || !quat_alg_elem_equal(&elem, &cmp);
|
||||
quat_alg_elem_set(&elem, 1, 0, 0, 0, 0);
|
||||
ibz_mat_4x4_eval(&(elem.coord), &(O0.basis), &out);
|
||||
ibz_copy(&(elem.denom), &(O0.denom));
|
||||
res = res || !quat_alg_elem_equal(&elem, &cmp);
|
||||
|
||||
quat_alg_elem_set(&cmp, 1, -8, 2, 1, 3);
|
||||
quat_alg_elem_copy(&elem, &cmp);
|
||||
quat_change_to_O0_basis(&out, &elem);
|
||||
res = res || !quat_alg_elem_equal(&elem, &cmp);
|
||||
quat_alg_elem_set(&elem, 1, 0, 0, 0, 0);
|
||||
ibz_mat_4x4_eval(&(elem.coord), &(O0.basis), &out);
|
||||
ibz_copy(&(elem.denom), &(O0.denom));
|
||||
res = res || !quat_alg_elem_equal(&elem, &cmp);
|
||||
|
||||
if (res) {
|
||||
printf("Quaternion unit test change_to_O0_basis failed");
|
||||
}
|
||||
quat_alg_elem_finalize(&elem);
|
||||
quat_alg_elem_finalize(&cmp);
|
||||
ibz_vec_4_finalize(&out);
|
||||
quat_lattice_finalize(&O0);
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
quat_test_represent_integer_internal(int gamma_iter,
|
||||
int prim_iter,
|
||||
int nbits,
|
||||
int randomized,
|
||||
int standard,
|
||||
int non_diag)
|
||||
{
|
||||
int tested = 0;
|
||||
int rand_ret = 1;
|
||||
int res = 0;
|
||||
ibz_t p, norm_n, M, norm_d;
|
||||
ibz_vec_4_t coord;
|
||||
quat_alg_t Bpoo;
|
||||
quat_alg_elem_t gamma;
|
||||
// must initialize special extremal order, product and primes
|
||||
quat_represent_integer_params_t params;
|
||||
quat_p_extremal_maximal_order_t order;
|
||||
quat_lattice_init(&order.order);
|
||||
quat_alg_elem_init(&order.z);
|
||||
quat_alg_elem_init(&order.t);
|
||||
quat_alg_elem_init(&gamma);
|
||||
ibz_vec_4_init(&coord);
|
||||
ibz_init(&M);
|
||||
ibz_init(&p);
|
||||
ibz_init(&norm_d);
|
||||
ibz_init(&norm_n);
|
||||
quat_alg_init_set_ui(&Bpoo, 101);
|
||||
|
||||
// setup
|
||||
params.primality_test_iterations = gamma_iter;
|
||||
|
||||
while (!tested) {
|
||||
if (standard) {
|
||||
ibz_set(&p, 0);
|
||||
rand_ret = !ibz_generate_random_prime(&p, 1, 2 * nbits, 32);
|
||||
rand_ret = rand_ret || !ibz_rand_interval_bits(&M, 2 * nbits + 24 + 100 * non_diag);
|
||||
ibz_copy(&(Bpoo.p), &p);
|
||||
quat_test_set_params_standard(¶ms, &order, &Bpoo);
|
||||
} else {
|
||||
ibz_set_from_str(&p, "23920667128620486487914848107166358953830561597426178123910317653495243603967", 10);
|
||||
int real_nbits = ibz_bitsize(&p);
|
||||
rand_ret = !ibz_rand_interval_bits(&M, real_nbits + 24 + 100 * non_diag);
|
||||
ibz_copy(&(Bpoo.p), &p);
|
||||
quat_test_set_params_non_standard(¶ms, &order, &Bpoo);
|
||||
}
|
||||
// make test more realistic by keeping some properties always given in SQIsign
|
||||
tested = (ibz_get(&p) % 8 == 7);
|
||||
tested = tested && (ibz_get(&M) % 2 == 1);
|
||||
tested = tested && quat_test_input_for_repres_bound(&(Bpoo.p), &M, params.order->q);
|
||||
if (rand_ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!rand_ret) {
|
||||
res = !quat_represent_integer(&gamma, &M, non_diag, ¶ms);
|
||||
if (!res) {
|
||||
quat_alg_norm(&norm_n, &norm_d, &gamma, &Bpoo);
|
||||
res = res || !ibz_is_one(&norm_d);
|
||||
res = res || !(ibz_cmp(&norm_n, &M) == 0);
|
||||
res = res || !quat_lattice_contains(NULL, &(params.order->order), &gamma);
|
||||
if (non_diag) {
|
||||
if (standard) {
|
||||
ibz_mul(&norm_n, &ibz_const_two, &ibz_const_two);
|
||||
// add not sub since basis in quat_order_elem_create is 1,i,j,-ij for O0
|
||||
ibz_add(&norm_d, &(gamma.coord[0]), &(gamma.coord[3]));
|
||||
ibz_mod(&norm_d, &norm_d, &norm_n);
|
||||
res = res || (0 != ibz_cmp(&ibz_const_two, &norm_d));
|
||||
ibz_sub(&norm_d, &(gamma.coord[1]), &(gamma.coord[2]));
|
||||
ibz_mod(&norm_d, &norm_d, &norm_n);
|
||||
res = res || (0 != ibz_cmp(&ibz_const_two, &norm_d));
|
||||
} else {
|
||||
quat_lattice_contains(&coord, &(params.order->order), &gamma);
|
||||
ibz_gcd(&norm_d, &(coord[1]), &(coord[2]));
|
||||
ibz_gcd(&norm_d, &norm_d, &(coord[3]));
|
||||
res = res || ibz_is_even(&norm_d);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("Randomness failure in quat_represent_integer test\n");
|
||||
}
|
||||
|
||||
quat_alg_finalize(&Bpoo);
|
||||
ibz_finalize(&p);
|
||||
ibz_finalize(&M);
|
||||
ibz_finalize(&norm_n);
|
||||
ibz_finalize(&norm_d);
|
||||
ibz_vec_4_finalize(&coord);
|
||||
quat_lattice_finalize(&order.order);
|
||||
quat_alg_elem_finalize(&order.z);
|
||||
quat_alg_elem_finalize(&order.t);
|
||||
quat_alg_elem_finalize(&gamma);
|
||||
return res | (rand_ret);
|
||||
}
|
||||
|
||||
// int quat_represent_integer(quat_alg_elem_t *gamma, const ibz_t *n_gamma, const
|
||||
// quat_represent_integer_params_t *params);
|
||||
int
|
||||
quat_test_represent_integer(void)
|
||||
{
|
||||
int res = 0;
|
||||
int prim_iter = 32;
|
||||
int gamma_iter = 16384;
|
||||
|
||||
res = res | quat_test_represent_integer_internal(prim_iter, gamma_iter, 64, 1, 1, 0);
|
||||
res = res | quat_test_represent_integer_internal(prim_iter, gamma_iter, 64, 1, 1, 1);
|
||||
|
||||
gamma_iter = 32768;
|
||||
res = res | quat_test_represent_integer_internal(prim_iter, gamma_iter, 128, 1, 1, 0);
|
||||
res = res | quat_test_represent_integer_internal(prim_iter, gamma_iter, 128, 1, 1, 1);
|
||||
|
||||
gamma_iter = 100000;
|
||||
res = res | quat_test_represent_integer_internal(prim_iter, gamma_iter, 128, 1, 0, 0);
|
||||
res = res | quat_test_represent_integer_internal(prim_iter, gamma_iter, 128, 1, 0, 1);
|
||||
|
||||
if (res) {
|
||||
printf("Quaternion unit test represent_integer failed\n");
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
quat_test_normeq(void)
|
||||
{
|
||||
|
||||
int res = 0;
|
||||
printf("\nRunning quaternion tests of functions for special extremal orders\n");
|
||||
|
||||
res = res | quat_test_change_to_O0_basis();
|
||||
res = res | quat_test_order_elem_create();
|
||||
res = res | quat_test_sampling_random_ideal_O0_given_norm();
|
||||
res = res | quat_test_represent_integer();
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Sina Schaeffler
|
||||
*
|
||||
* @brief Declarations of tests of quaternion algebra operations
|
||||
*/
|
||||
|
||||
#ifndef QUATERNION_TESTS_H
|
||||
#define QUATERNION_TESTS_H
|
||||
|
||||
#include <quaternion.h>
|
||||
#include <stdio.h>
|
||||
#include "../internal.h"
|
||||
|
||||
/** @internal
|
||||
* @ingroup quat_quat
|
||||
* @defgroup quat_tests Quaternion module test functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Test initializers and finalizers for quaternion algebra types
|
||||
*
|
||||
* Test initializers and finalizers for the following types:
|
||||
*
|
||||
* quat_alg_t
|
||||
*
|
||||
* quat_alg_elem_t
|
||||
*
|
||||
* quat_alg_coord_t
|
||||
*
|
||||
* ibz_vec_4_t
|
||||
*
|
||||
* ibz_vec_5_t
|
||||
*
|
||||
* ibz_mat_2x2_t
|
||||
*
|
||||
* ibz_mat_4x4_t
|
||||
*
|
||||
* ibz_mat_4x5_t
|
||||
*
|
||||
* ibz_mat_4x8_t
|
||||
*
|
||||
* quat_lattice_t
|
||||
*
|
||||
* quat_order_t
|
||||
*
|
||||
* quat_left_ideal_t
|
||||
*/
|
||||
int quat_test_finit();
|
||||
|
||||
/** @brief Test integer, quadratic form and matrix functions for dimension 4 from the quaternion module
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* int ibz_4x5_right_ker_mod_prime(ibz_vec_5_t *ker, const ibz_mat_4x5_t *mat, const ibz_t *p);
|
||||
*
|
||||
* int ibz_4x4_right_ker_mod_prime(ibz_vec_4_t *ker, const ibz_mat_4x4_t *mat, const ibz_t *p);
|
||||
*
|
||||
* int ibz_4x4_right_ker_mod_power_of_2(ibz_vec_4_t *ker, const ibz_mat_4x4_t *mat, unsigned short exp);
|
||||
*
|
||||
* void ibz_mat_4x4_eval(quat_alg_coord_t *res, const ibz_mat_4x4_t *mat, const quat_alg_coord_t *vec);
|
||||
*
|
||||
* void quat_qf_eval(ibz_t *res, const ibz_mat_4x4_t *qf, const quat_alg_coord_t *coord);
|
||||
*
|
||||
* void ibz_content(ibz_t *content, const quat_alg_coord_t *v);
|
||||
*/
|
||||
int quat_test_dim4();
|
||||
|
||||
/** @brief Test integer, lattice and matrix functions for dimension 2 from the quaternion module
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* void ibz_mat_2x2_eval(ibz_vec_2_t *res, const ibz_mat_2x2_t *mat, const ibz_vec_2_t *vec);
|
||||
*
|
||||
* void ibz_2x2_mul_mod(ibz_mat_2x2_t *prod, const ibz_mat_2x2_t *mat_a, const ibz_mat_2x2_t *mat_b, const ibz_t *m);
|
||||
*
|
||||
* int ibz_2x2_inv_mod(ibz_mat_2x2_t *inv, const ibz_mat_2x2_t *mat, const ibz_t *m);
|
||||
*
|
||||
* int quat_2x2_lattice_enumerate_cvp_filter(quat_alg_elem_t *res, const ibz_mat_2x2_t *lat_basis, const ibz_vec_2_t *target,unsigned int qf, unsigned int dist_bound, int (*condition)(quat_alg_elem_t* , const ibz_vec_2_t*, const void*), const void* params, unsigned int max_tries);
|
||||
*/
|
||||
int quat_test_dim2();
|
||||
|
||||
/** @brief Test integer functions
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* int ibz_cornacchia_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p);
|
||||
*
|
||||
* int ibz_cornacchia_special_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p, const int exp_adjust);
|
||||
*
|
||||
* int ibz_cornacchia_extended(ibz_t *x, ibz_t *y, const ibz_t *n, const short *prime_list, const int prime_list_length, short primality_test_iterations, const ibz_t *bad_primes_prod);
|
||||
*/
|
||||
int quat_test_integers();
|
||||
|
||||
/** @brief Test operations on quaternion algebra elements
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* void quat_alg_add(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b);
|
||||
*
|
||||
* void quat_alg_sub(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b);
|
||||
*
|
||||
* void quat_alg_mul(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_alg_norm(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_alg_trace(quat_alg_elem_t *res, const quat_alg_elem_t *a);
|
||||
*
|
||||
* void quat_alg_scalar(quat_alg_elem_t *elem, const ibz_t *numerator, const ibz_t *denominator);
|
||||
*
|
||||
* void quat_alg_conj(quat_alg_elem_t *conj, const quat_alg_elem_t *x);
|
||||
*
|
||||
* void quat_alg_make_primitive(quat_alg_coord_t *primitive_x, ibz_t *content, const quat_alg_elem_t *x, const quat_order_t *order, const quat_alg_t *alg){
|
||||
*
|
||||
* int quat_alg_is_primitive(const quat_alg_elem_t *x, const quat_order_t *order, const quat_alg_t *alg):
|
||||
*
|
||||
* void quat_alg_normalize(quat_alg_elem_t *x);
|
||||
*
|
||||
* int quat_alg_elem_is_zero(const quat_alg_elem_t *x);
|
||||
*
|
||||
* int quat_alg_coord_is_zero(const quat_alg_coord_t *x);
|
||||
*/
|
||||
int quat_test_algebra();
|
||||
|
||||
/** @brief Test operations on lattices
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* void quat_lattice_add(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2);
|
||||
*
|
||||
* void quat_lattice_intersect(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2);
|
||||
*
|
||||
* void quat_lattice_mul(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2, const quat_alg_t *alg);
|
||||
*
|
||||
* int quat_lattice_contains(quat_alg_coord_t *coord, const quat_lattice_t *lat, const quat_alg_elem_t *x, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_lattice_hnf(quat_lattice_t *lat);
|
||||
*/
|
||||
int quat_test_lattice();
|
||||
|
||||
/** @brief Test operations on left ideals and their creation
|
||||
*
|
||||
* Runs unit tests for the following functions
|
||||
*
|
||||
* void quat_lideal_create_principal(quat_left_ideal_t *lideal, const quat_alg_elem_t *x, const quat_order_t *order, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_lideal_create_from_primitive(quat_left_ideal_t *lideal, const quat_alg_elem_t *x, const ibz_t *N, const quat_order_t *order, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_lideal_make_primitive_then_create(quat_left_ideal_t *lideal, const quat_alg_elem_t *x, const ibz_t *N, const quat_order_t *order, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_lideal_random_2e(quat_left_ideal_t *lideal, const quat_order_t *order, const quat_alg_t *alg, int64_t e);
|
||||
*
|
||||
* int quat_lideal_generator(quat_alg_elem_t *gen, const quat_left_ideal_t *lideal, const quat_alg_t *alg, int bound);
|
||||
*
|
||||
* int quat_lideal_generator_coprime(quat_alg_elem_t *gen, const quat_left_ideal_t *lideal, const ibz_t *n, const quat_alg_t *alg, int bound);
|
||||
*
|
||||
* int quat_lideal_mul(quat_left_ideal_t *product, const quat_left_ideal_t *lideal, const quat_alg_elem_t *alpha, const quat_alg_t *alg, int bound);
|
||||
*
|
||||
* void quat_lideal_add(quat_left_ideal_t *sum, const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_lideal_inter(quat_left_ideal_t *intersection, const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg);
|
||||
*
|
||||
* int quat_lideal_equals(const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg);
|
||||
*
|
||||
* int quat_lideal_isom(quat_alg_elem_t *iso, const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_lideal_right_order(quat_order_t *order, const quat_left_ideal_t *lideal, const quat_alg_t *alg);
|
||||
*
|
||||
* void quat_lideal_reduce_basis(ibz_mat_4x4_t *reduced, ibz_mat_4x4_t *gram, const quat_left_ideal_t *lideal, const quat_alg_t *alg); //replaces lideal_lll
|
||||
*
|
||||
* void quat_connecting_ideal(quat_left_ideal_t *connecting_ideal, const quat_order_t *O1, const quat_order_t *O2, const quat_alg_t *alg);
|
||||
*/
|
||||
int quat_test_lideal();
|
||||
|
||||
/** @brief test matkermod and Howell form
|
||||
*/
|
||||
int quat_test_matkermod();
|
||||
|
||||
/** @brief Test with randomization for complex functions where this is possible
|
||||
*
|
||||
*/
|
||||
int quat_test_with_randomization();
|
||||
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
#endif
|
||||
109
src/quaternion/ref/generic/test/random_input_generation.c
Normal file
109
src/quaternion/ref/generic/test/random_input_generation.c
Normal file
@@ -0,0 +1,109 @@
|
||||
#include "quaternion_tests.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
int
|
||||
quat_test_input_random_ideal_generation(quat_left_ideal_t *ideals,
|
||||
int norm_bitsize,
|
||||
int iterations,
|
||||
const quat_represent_integer_params_t *params)
|
||||
{
|
||||
int randret = 0;
|
||||
ibz_t norm, cofactor;
|
||||
ibz_init(&norm);
|
||||
ibz_init(&cofactor);
|
||||
int size_p = ibz_bitsize(&(params->algebra->p));
|
||||
randret = !ibz_generate_random_prime(&cofactor,
|
||||
0,
|
||||
((norm_bitsize + 5) > size_p) * (norm_bitsize + 5) +
|
||||
((norm_bitsize + 5) <= size_p) * size_p,
|
||||
params->primality_test_iterations);
|
||||
if ((randret != 0) || ibz_is_zero(&cofactor)) {
|
||||
printf("Random generation failed in quat_test_input_random_ideal_generation\n");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
for (int iter = 0; iter < iterations; iter++) {
|
||||
// generate random odd norm
|
||||
randret = !ibz_rand_interval_bits(&norm, norm_bitsize - 1);
|
||||
ibz_add(&norm, &norm, &norm);
|
||||
ibz_add(&norm, &norm, &ibz_const_one);
|
||||
if ((randret != 0) || ibz_is_zero(&norm)) {
|
||||
printf("Random generation failed in quat_test_input_random_ideal_generation\n");
|
||||
goto fin;
|
||||
}
|
||||
ibz_abs(&norm, &norm);
|
||||
// compute ideal
|
||||
randret = !quat_sampling_random_ideal_O0_given_norm(&(ideals[iter]), &norm, 0, params, &cofactor);
|
||||
if (randret != 0) {
|
||||
printf("Random generation failed in quat_test_input_random_ideal_generation\n");
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
fin:;
|
||||
ibz_finalize(&norm);
|
||||
ibz_finalize(&cofactor);
|
||||
return (randret);
|
||||
}
|
||||
|
||||
// norms is either of length iterations or NULL
|
||||
int
|
||||
quat_test_input_random_ideal_lattice_generation(quat_lattice_t *lattices,
|
||||
ibz_t *norms,
|
||||
int norm_bitsize,
|
||||
int iterations,
|
||||
const quat_represent_integer_params_t *params)
|
||||
{
|
||||
quat_left_ideal_t *ideals;
|
||||
ideals = malloc(iterations * sizeof(quat_left_ideal_t));
|
||||
for (int i = 0; i < iterations; i++)
|
||||
quat_left_ideal_init(&(ideals[i]));
|
||||
int randret = quat_test_input_random_ideal_generation(ideals, norm_bitsize, iterations, params);
|
||||
|
||||
for (int iter = 0; iter < iterations; iter++) {
|
||||
ibz_mat_4x4_copy(&(lattices[iter].basis), &(ideals[iter].lattice.basis));
|
||||
ibz_copy(&(lattices[iter].denom), &(ideals[iter].lattice.denom));
|
||||
if (norms != NULL) {
|
||||
ibz_copy(&(norms[iter]), &(ideals[iter].norm));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < iterations; i++)
|
||||
quat_left_ideal_finalize(&(ideals[i]));
|
||||
free(ideals);
|
||||
return randret;
|
||||
}
|
||||
|
||||
int
|
||||
quat_test_input_random_lattice_generation(quat_lattice_t *lattices, int bitsize, int iterations, int in_hnf)
|
||||
{
|
||||
ibz_t det;
|
||||
ibz_init(&det);
|
||||
int randret = 0;
|
||||
for (int iter = 0; iter < iterations; iter++) {
|
||||
// generate random invertible matrix
|
||||
ibz_set(&det, 0);
|
||||
while (ibz_is_zero(&det)) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
randret = !ibz_rand_interval_bits(&((lattices[iter]).basis[i][j]), bitsize);
|
||||
if (randret != 0) {
|
||||
printf("Random generation failed in "
|
||||
"quat_test_input_random_lattice_generation\n");
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
}
|
||||
randret = !ibz_rand_interval_bits(&((lattices[iter]).denom), bitsize);
|
||||
if (randret != 0) {
|
||||
printf("Random generation failed in quat_test_input_random_lattice_generation\n");
|
||||
goto fin;
|
||||
}
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL, &det, &((lattices[iter]).basis));
|
||||
ibz_mul(&det, &det, &(lattices[iter].denom));
|
||||
if (in_hnf && !ibz_is_zero(&det))
|
||||
quat_lattice_hnf(&(lattices[iter]));
|
||||
}
|
||||
}
|
||||
fin:;
|
||||
ibz_finalize(&det);
|
||||
return (randret);
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "quaternion_tests.h"
|
||||
#include <rng.h>
|
||||
|
||||
// int ibz_2x2_inv_mod(ibz_mat_2x2_t *inv, const ibz_mat_2x2_t *mat, const ibz_t *m);
|
||||
int quat_test_randomized_ibz_mat_2x2_inv_mod()
|
||||
// int ibz_mat_2x2_inv_mod(ibz_mat_2x2_t *inv, const ibz_mat_2x2_t *mat, const ibz_t *m);
|
||||
int
|
||||
quat_test_randomized_ibz_mat_2x2_inv_mod(int bitsize_matrix, int bitsize_modulus, int iterations)
|
||||
{
|
||||
int randret = 0;
|
||||
int res = 0;
|
||||
ibz_t m, det, gcd;
|
||||
ibz_mat_2x2_t a, inv, id, prod;
|
||||
int64_t rand[4];
|
||||
int64_t rand_m;
|
||||
ibz_init(&m);
|
||||
ibz_init(&det);
|
||||
ibz_init(&gcd);
|
||||
@@ -18,47 +18,46 @@ int quat_test_randomized_ibz_mat_2x2_inv_mod()
|
||||
ibz_mat_2x2_init(&id);
|
||||
ibz_mat_2x2_set(&id, 1, 0, 0, 1);
|
||||
|
||||
|
||||
for (int iter = 0; iter < 100; iter++){
|
||||
for (int iter = 0; iter < iterations; iter++) {
|
||||
// generate random matrix and modulo, with modulo larger than 2
|
||||
int randret = randombytes((unsigned char*)rand, 4*sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
ibz_mat_2x2_set(&a, rand[0],rand[1],rand[2],rand[3]);
|
||||
rand_m = 0;
|
||||
while(rand_m < 2) {
|
||||
int randret = randombytes((unsigned char*)&rand_m, sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
randret = randret | !ibz_rand_interval_bits(&(a[i][j]), bitsize_matrix);
|
||||
}
|
||||
}
|
||||
ibz_set(&m,rand_m);
|
||||
randret = randret | !ibz_rand_interval_bits(&m, bitsize_modulus);
|
||||
ibz_abs(&m, &m);
|
||||
ibz_add(&m, &m, &ibz_const_two);
|
||||
if (randret != 0)
|
||||
goto fin;
|
||||
|
||||
// compute det
|
||||
ibz_mat_2x2_det_from_ibz(&det,&(a[0][0]),&(a[0][1]),&(a[1][0]),&(a[1][1]));
|
||||
ibz_mat_2x2_det_from_ibz(&det, &(a[0][0]), &(a[0][1]), &(a[1][0]), &(a[1][1]));
|
||||
// is it prime to mod
|
||||
ibz_gcd(&gcd,&det,&m);
|
||||
if(ibz_is_one(&gcd)){
|
||||
ibz_gcd(&gcd, &det, &m);
|
||||
if (ibz_is_one(&gcd)) {
|
||||
// matrix should be invertible mod m
|
||||
if (ibz_2x2_inv_mod(&inv, &a, &m))
|
||||
{
|
||||
if (ibz_mat_2x2_inv_mod(&inv, &a, &m)) {
|
||||
// ibz_2x2_mul_mod(&prod,&a,&inv, &m);
|
||||
ibz_2x2_mul_mod(&prod, &inv, &a, &m);
|
||||
res = res || ibz_cmp(&(prod[0][0]), &(id[0][0]));
|
||||
res = res || ibz_cmp(&(prod[0][1]), &(id[0][1]));
|
||||
res = res || ibz_cmp(&(prod[1][0]), &(id[1][0]));
|
||||
res = res || ibz_cmp(&(prod[1][1]), &(id[1][1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
} else {
|
||||
res = res || ibz_2x2_inv_mod(&inv, &a, &m);
|
||||
res = res || ibz_mat_2x2_inv_mod(&inv, &a, &m);
|
||||
}
|
||||
}
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
fin:;
|
||||
if (randret != 0) {
|
||||
printf("Randomness failed in quaternion unit test with randomization for "
|
||||
"ibz_mat_2x2_inv_mod\n");
|
||||
}
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test with randomization for ibz_mat_2x2_inv_mod failed\n");
|
||||
}
|
||||
ibz_mat_2x2_finalize(&a);
|
||||
@@ -71,94 +70,12 @@ int quat_test_randomized_ibz_mat_2x2_inv_mod()
|
||||
return (res);
|
||||
}
|
||||
|
||||
// int quat_2x2_lattice_enumerate_cvp_filter(quat_alg_elem_t *res, const ibz_mat_2x2_t *lat_basis, const ibz_vec_2_t *target,unsigned int qf, unsigned int dist_bound, int (*condition)(quat_alg_elem_t* , const ibz_vec_2_t*, const void*), const void* params, unsigned int max_tries);
|
||||
int quat_test_randomized_2x2_lattice_enumerate_cvp_filter()
|
||||
// int ibz_4x4_inv_with_det_as_denom(ibz_mat_4x4_t *inv, ibz_t *det, const ibz_mat_4x4_t mat);
|
||||
int
|
||||
quat_test_randomized_ibz_mat_4x4_inv_with_det_as_denom(int matrix_bitsize, int iterations)
|
||||
{
|
||||
// test only wether a result is returned which verifies the conditions, if true is returned
|
||||
// cannot test wether false is retured correctly or not
|
||||
int res = 0;
|
||||
ibz_t p, bound, norm_q, norm;
|
||||
quat_alg_elem_t cvp_res;
|
||||
ibz_mat_2x2_t basis;
|
||||
ibz_vec_2_t target, diff, found;
|
||||
ibz_mat_2x2_init(&basis);
|
||||
quat_alg_elem_init(&cvp_res);
|
||||
ibz_vec_2_init(&target);
|
||||
ibz_vec_2_init(&diff);
|
||||
ibz_vec_2_init(&found);
|
||||
ibz_init(&p);
|
||||
ibz_init(&norm_q);
|
||||
ibz_init(&norm);
|
||||
ibz_init(&bound);
|
||||
unsigned int q;
|
||||
unsigned int dist_bound;
|
||||
void *params = (void *)&p;
|
||||
unsigned int max_tries;
|
||||
int64_t rand[9];
|
||||
|
||||
// fix p since only used inside condition which is internal, unused by any external function
|
||||
ibz_set(&p, 3);
|
||||
|
||||
|
||||
for (int iter = 0; iter < 20; iter++){
|
||||
// generate random matrix with non-0 det
|
||||
ibz_set(&bound,0);
|
||||
while(ibz_is_zero(&bound)){
|
||||
int randret = randombytes((unsigned char*)rand, 9*sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
ibz_mat_2x2_set(&basis, rand[0],rand[1],rand[2],rand[3]);
|
||||
// check det is not 0
|
||||
ibz_mat_2x2_det_from_ibz(&bound,&(basis[0][0]),&(basis[0][1]),&(basis[1][0]),&(basis[1][1]));
|
||||
}
|
||||
// set target
|
||||
ibz_vec_2_set(&target, rand[4], rand[5]);
|
||||
//set other params randomly in reasonable ranges
|
||||
q = ((unsigned int)rand[6]) % 1024;
|
||||
if(q == 0){
|
||||
q = 1;
|
||||
}
|
||||
dist_bound = ((unsigned int)rand[7]) % 128;
|
||||
max_tries = ((unsigned int)rand[8]) % 16384;
|
||||
if (quat_2x2_lattice_enumerate_cvp_filter(&cvp_res, &basis, &target, q, dist_bound, &quat_dim2_lattice_test_cvp_condition, params, max_tries)){
|
||||
// used cvp_res and condition to exfiltrate standard coords of distance to target from close vector found
|
||||
ibz_copy(&(diff[0]), &(cvp_res.coord[0]));
|
||||
ibz_copy(&(diff[1]), &(cvp_res.coord[1]));
|
||||
// compute close vector in lattice from target and diff
|
||||
ibz_sub(&(found[0]), &(target[0]), &(diff[0]));
|
||||
ibz_sub(&(found[1]), &(target[1]), &(diff[1]));
|
||||
// norm bound on diff ok?
|
||||
ibz_set(&norm_q, q);
|
||||
ibz_set(&bound, 2);
|
||||
ibz_pow(&bound, &bound, dist_bound);
|
||||
quat_dim2_lattice_norm(&norm, &(diff[0]), &(diff[1]), &norm_q);
|
||||
res = res || !(ibz_cmp(&norm, &bound) < 0);
|
||||
// Condition ok
|
||||
res = res || (!quat_dim2_lattice_test_cvp_condition(&cvp_res, &diff, params));
|
||||
// Is in lattice
|
||||
res = res || (!quat_dim2_lattice_contains(&basis, &(found[0]), &(found[1])));
|
||||
}
|
||||
}
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
printf("Quaternion unit test with randomization for 2x2_lattice_enumerate_cvp_filter failed\n");
|
||||
}
|
||||
ibz_mat_2x2_finalize(&basis);
|
||||
quat_alg_elem_finalize(&cvp_res);
|
||||
ibz_vec_2_finalize(&target);
|
||||
ibz_vec_2_finalize(&diff);
|
||||
ibz_vec_2_finalize(&found);
|
||||
ibz_finalize(&p);
|
||||
ibz_finalize(&norm_q);
|
||||
ibz_finalize(&norm);
|
||||
ibz_finalize(&bound);
|
||||
return res;
|
||||
}
|
||||
|
||||
//int ibz_4x4_inv_with_det_as_denom(ibz_mat_4x4_t *inv, ibz_t *det, const ibz_mat_4x4_t mat);
|
||||
int quat_test_randomized_ibz_mat_4x4_inv_with_det_as_denom(){
|
||||
int res = 0;
|
||||
int randret = 0;
|
||||
ibz_t det;
|
||||
ibz_mat_4x4_t mat, inv;
|
||||
ibz_mat_4x4_t det_id, prod;
|
||||
@@ -168,22 +85,31 @@ int quat_test_randomized_ibz_mat_4x4_inv_with_det_as_denom(){
|
||||
ibz_mat_4x4_init(&mat);
|
||||
ibz_mat_4x4_init(&inv);
|
||||
|
||||
for (int r = 0; r < 10; r++) {
|
||||
for (int r = 0; r < iterations; r++) {
|
||||
do {
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
ibz_rand_interval_i(&mat[i][j], -(1 << 20), 1 << 20);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
randret = randret | !ibz_rand_interval_bits(&mat[i][j], matrix_bitsize);
|
||||
if (randret != 0)
|
||||
goto fin;
|
||||
}
|
||||
} while (!ibz_mat_4x4_inv_with_det_as_denom(&inv, &det, &mat));
|
||||
ibz_mat_4x4_identity(&det_id);
|
||||
ibz_mat_4x4_scalar_mul(&det_id,&det,&det_id);
|
||||
ibz_mat_4x4_scalar_mul(&det_id, &det, &det_id);
|
||||
ibz_mat_4x4_mul(&prod, &inv, &mat);
|
||||
res = res || !ibz_mat_4x4_equal(&det_id,&prod);
|
||||
res = res || !ibz_mat_4x4_equal(&det_id, &prod);
|
||||
ibz_mat_4x4_mul(&prod, &mat, &inv);
|
||||
res = res || !ibz_mat_4x4_equal(&det_id,&prod);
|
||||
res = res || !ibz_mat_4x4_equal(&det_id, &prod);
|
||||
}
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test with randomization for ibz_mat_4x4_inv_with_det_as_denom failed\n");
|
||||
|
||||
fin:;
|
||||
if (randret != 0) {
|
||||
printf("Randomness failed in quaternion unit test with randomization for "
|
||||
"ibz_mat_2x2_inv_mod\n");
|
||||
}
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test with randomization for ibz_mat_4x4_inv_with_det_as_denom "
|
||||
"failed\n");
|
||||
}
|
||||
ibz_mat_4x4_finalize(&det_id);
|
||||
ibz_mat_4x4_finalize(&prod);
|
||||
@@ -193,545 +119,155 @@ int quat_test_randomized_ibz_mat_4x4_inv_with_det_as_denom(){
|
||||
return res;
|
||||
}
|
||||
|
||||
//void ibz_mat_4x8_hnf_core(ibz_mat_4x4_t *hnf, const ibz_mat_4x8_t *generators);
|
||||
int quat_test_randomized_ibz_mat_4x8_hnf_core(){
|
||||
// only partial test, since lattice equality cannot be tested without hnf, so only one inclusion is checked
|
||||
int res = 0;
|
||||
quat_alg_elem_t vec;
|
||||
quat_lattice_t lat;
|
||||
ibz_mat_4x8_t mat;
|
||||
ibz_mat_4x4_t hnf,cmp;
|
||||
quat_lattice_init(&lat);
|
||||
quat_alg_elem_init(&vec);
|
||||
ibz_mat_4x8_init(&mat);
|
||||
ibz_mat_4x4_init(&hnf);
|
||||
ibz_mat_4x4_init(&cmp);
|
||||
int64_t rand[8][4];
|
||||
int det_non_0;
|
||||
|
||||
for (int iter = 0; iter < 100; iter++){
|
||||
int randret = randombytes((unsigned char*)rand, 8*4*sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 8; j++){
|
||||
ibz_set(&(mat[i][j]),rand[j][i]);
|
||||
}
|
||||
}
|
||||
ibz_mat_4x8_hnf_core(&hnf,&mat);
|
||||
res = res || (!ibz_mat_4x4_is_hnf(&hnf));
|
||||
// also should test that they generate the same lattice. However, can only check one inclusion efficiently (and this only if full rank), so do so
|
||||
det_non_0 = 1;
|
||||
for(int i = 0; i <4; i ++){
|
||||
det_non_0 = det_non_0 && ibz_is_zero(&(hnf[i][i]));
|
||||
}
|
||||
if(det_non_0){
|
||||
ibz_mat_4x4_copy(&(lat.basis),&hnf);
|
||||
ibz_set(&(lat.denom),1);
|
||||
for(int i = 0; i <8; i ++){
|
||||
quat_alg_elem_copy_ibz(&vec,&(lat.denom), &(mat[i][0]), &(mat[i][1]), &(mat[i][2]), &(mat[i][3]));
|
||||
res = res || !quat_lattice_contains_without_alg(NULL,&lat,&vec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test with randomization for ibz_mat_4x8_hnf_core failed\n");
|
||||
}
|
||||
quat_lattice_finalize(&lat);
|
||||
quat_alg_elem_finalize(&vec);
|
||||
ibz_mat_4x8_finalize(&mat);
|
||||
ibz_mat_4x4_finalize(&hnf);
|
||||
ibz_mat_4x4_finalize(&cmp);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//int ibz_4x5_right_ker_mod_prime(ibz_vec_5_t *ker, const ibz_mat_4x5_t *mat, const ibz_t *p);
|
||||
int quat_test_randomized_ibz_4x5_right_ker_mod_prime(){
|
||||
// check that if the function returns 1, the vector is in the kernel
|
||||
int res = 0;
|
||||
ibz_t prime;
|
||||
ibz_mat_4x5_t mat;
|
||||
ibz_vec_5_t ker;
|
||||
ibz_t prod, sum;
|
||||
ibz_init(&prod);
|
||||
ibz_init(&sum);
|
||||
ibz_mat_4x5_init(&mat);
|
||||
ibz_vec_5_init(&ker);
|
||||
ibz_init(&prime);
|
||||
int64_t rand[5][4];
|
||||
int64_t rand_p;
|
||||
|
||||
|
||||
for (int iter = 0; iter < 100; iter++){
|
||||
// generate random matrix and modulo, with modulo larger than 2
|
||||
int randret = randombytes((unsigned char*)rand, 4*5*sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 5; j++){
|
||||
ibz_set(&(mat[i][j]),rand[j][i]);
|
||||
}
|
||||
}
|
||||
rand_p = 0;
|
||||
while(rand_p ==0) {
|
||||
int randret = randombytes((unsigned char*)&rand_p, sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
ibz_set(&prime,rand_p);
|
||||
if(!ibz_probab_prime(&prime,20))
|
||||
rand_p = 0;
|
||||
}
|
||||
if (ibz_4x5_right_ker_mod_prime(&ker,&mat,&prime)){
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_set(&sum,0);
|
||||
for(int j = 0; j < 5; j++){
|
||||
ibz_mul(&prod,&(mat[i][j]),&(ker[j]));
|
||||
ibz_add(&sum,&sum,&prod);
|
||||
ibz_mod(&sum,&sum,&prime);
|
||||
}
|
||||
res = res || !ibz_is_zero(&sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test with randomization for ibz_4x5_right_ker_mod_prime failed\n");
|
||||
}
|
||||
ibz_finalize(&sum);
|
||||
ibz_finalize(&prod);
|
||||
ibz_vec_5_finalize(&ker);
|
||||
ibz_mat_4x5_finalize(&mat);
|
||||
ibz_finalize(&prime);
|
||||
return(res);
|
||||
}
|
||||
|
||||
|
||||
//int ibz_4x4_right_ker_mod_prime(ibz_vec_4_t *ker, const ibz_mat_4x4_t *mat, const ibz_t *p);
|
||||
int quat_test_randomized_ibz_4x4_right_ker_mod_prime(){
|
||||
int res = 0;
|
||||
ibz_t prime;
|
||||
ibz_mat_4x4_t mat, rank3, rank2;
|
||||
ibz_vec_4_t ker;
|
||||
ibz_t prod, sum,det;
|
||||
ibz_init(&prod);
|
||||
ibz_init(&sum);
|
||||
ibz_init(&det);
|
||||
ibz_mat_4x4_init(&mat);
|
||||
ibz_mat_4x4_init(&rank3);
|
||||
ibz_mat_4x4_init(&rank2);
|
||||
ibz_vec_4_init(&ker);
|
||||
ibz_init(&prime);
|
||||
int64_t rand[4][4];
|
||||
int64_t rand_p;
|
||||
ibz_mat_4x4_identity(&rank3);
|
||||
ibz_set(&(rank3[3][3]),0);
|
||||
ibz_mat_4x4_identity(&rank2);
|
||||
ibz_set(&(rank2[3][3]),0);
|
||||
ibz_set(&(rank2[2][2]),0);
|
||||
|
||||
// test case where always 1 solution
|
||||
for (int iter = 0; iter < 100; iter++){
|
||||
rand_p = 0;
|
||||
while(rand_p ==0) {
|
||||
int randret = randombytes((unsigned char*)&rand_p, sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
ibz_set(&prime,rand_p);
|
||||
if(!ibz_probab_prime(&prime,20))
|
||||
rand_p = 0;
|
||||
}
|
||||
// generate random invertible matrix
|
||||
ibz_set(&det,0);
|
||||
while(ibz_is_zero(&det)){
|
||||
int randret = randombytes((unsigned char*)rand, 4*4*sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
ibz_set(&(mat[i][j]),rand[j][i]);
|
||||
}
|
||||
}
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL,&det,&mat);
|
||||
ibz_mod(&det,&det,&prime);
|
||||
}
|
||||
// rank 4 matrix does not work
|
||||
res = res || ibz_4x4_right_ker_mod_prime(&ker,&mat,&prime);
|
||||
// multiply with rank3 to get random rank 3 matrix
|
||||
ibz_mat_4x4_mul(&mat,&mat,&rank3);
|
||||
|
||||
if (ibz_4x4_right_ker_mod_prime(&ker,&mat,&prime)){
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_set(&sum,0);
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_mul(&prod,&(mat[i][j]),&(ker[j]));
|
||||
ibz_add(&sum,&sum,&prod);
|
||||
ibz_mod(&sum,&sum,&prime);
|
||||
}
|
||||
res = res || !ibz_is_zero(&sum);
|
||||
}
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
// multiply with rank2 to get matrix of too small rank
|
||||
ibz_mat_4x4_mul(&mat,&mat,&rank2);
|
||||
res = res || ibz_4x4_right_ker_mod_prime(&ker,&mat,&prime);
|
||||
ibz_mat_4x4_mul(&mat,&mat,&rank2);
|
||||
res = res || ibz_4x4_right_ker_mod_prime(&ker,&mat,&prime);
|
||||
ibz_mat_4x4_mul(&mat,&mat,&rank2);
|
||||
res = res || ibz_4x4_right_ker_mod_prime(&ker,&mat,&prime);
|
||||
}
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test with randomization for ibz_4x4_right_ker_mod_prime failed\n");
|
||||
}
|
||||
ibz_finalize(&sum);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&det);
|
||||
ibz_vec_4_finalize(&ker);
|
||||
ibz_mat_4x4_finalize(&mat);
|
||||
ibz_mat_4x4_finalize(&rank3);
|
||||
ibz_mat_4x4_finalize(&rank2);
|
||||
ibz_finalize(&prime);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//int ibz_4x4_right_ker_mod_power_of_2(ibz_vec_4_t *ker, const ibz_mat_4x4_t *mat, unsigned short exp);
|
||||
int quat_test_randomized_ibz_4x4_right_ker_mod_power_of_2(){
|
||||
// this only tests that if a vector is returned, it fullfills the conditions
|
||||
int res = 0;
|
||||
int zero = 1;
|
||||
short exp;
|
||||
int64_t rand[4][4];
|
||||
uint64_t rand_exp;
|
||||
ibz_mat_4x4_t mat, rank3;
|
||||
ibz_vec_4_t ker;
|
||||
ibz_vec_4_t prod;
|
||||
ibz_t q, r, two, det;
|
||||
ibz_mat_4x4_init(&mat);
|
||||
ibz_mat_4x4_init(&rank3);
|
||||
ibz_vec_4_init(&ker);
|
||||
ibz_vec_4_init(&prod);
|
||||
ibz_init(&q);
|
||||
ibz_init(&r);
|
||||
ibz_init(&det);
|
||||
ibz_init(&two);
|
||||
ibz_set(&two,2);
|
||||
ibz_mat_4x4_identity(&rank3);
|
||||
ibz_set(&(rank3[3][3]),0);
|
||||
|
||||
for (int iter = 0; iter < 100; iter++){
|
||||
rand_exp = 0;
|
||||
while(rand_exp <=0) {
|
||||
int randret = randombytes((unsigned char*)&rand_exp, sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
exp = ((short) ((unsigned char) rand_exp));
|
||||
}
|
||||
// generate random invertible matrix
|
||||
ibz_set(&det,0);
|
||||
while(ibz_is_zero(&det)){
|
||||
int randret = randombytes((unsigned char*)rand, 4*4*sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
ibz_set(&(mat[i][j]),rand[j][i]);
|
||||
}
|
||||
}
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL,&det,&mat);
|
||||
ibz_div(&q,&det,&det,&two);
|
||||
}
|
||||
|
||||
|
||||
// rank 4 matrix does not work
|
||||
res = res || ibz_4x4_right_ker_mod_power_of_2(&ker,&mat,exp);
|
||||
// multiply with rank3 to get random rank 3 matrix
|
||||
ibz_mat_4x4_mul(&mat,&mat,&rank3);
|
||||
|
||||
if (ibz_4x4_right_ker_mod_power_of_2(&ker, &mat, exp)){
|
||||
zero = 1;
|
||||
ibz_mat_4x4_eval(&prod,&mat,&ker);
|
||||
for (int i = 0; i < 4; i++){
|
||||
ibz_div(&q,&r,&(ker[i]),&two);
|
||||
zero = zero && ibz_is_zero(&r);
|
||||
ibz_pow(&q,&two,exp);
|
||||
ibz_mod(&(prod[i]),&(prod[i]),&q);
|
||||
}
|
||||
res |= !quat_alg_coord_is_zero(&prod);
|
||||
res |= zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test with randomization for ibz_4x4_right_ker_mod_power_of_2 failed\n");
|
||||
}
|
||||
ibz_mat_4x4_finalize(&mat);
|
||||
ibz_mat_4x4_finalize(&rank3);
|
||||
ibz_vec_4_finalize(&ker);
|
||||
ibz_vec_4_finalize(&prod);
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&two);
|
||||
ibz_finalize(&det);
|
||||
return(res);
|
||||
}
|
||||
|
||||
|
||||
//int quat_lattice_lll(ibz_mat_4x4_t *red, const quat_lattice_t *lattice, const ibz_t *q, int precision);
|
||||
int quat_test_randomized_lattice_lll(){
|
||||
int res = 0;
|
||||
quat_lattice_t lat, test;
|
||||
ibz_mat_4x4_t red;
|
||||
ibz_t num, denom, q, det;
|
||||
ibq_t coeff;
|
||||
int64_t rand[4][4];
|
||||
uint32_t rand_q, rand_prec, rand_denom;
|
||||
ibz_init(&num);
|
||||
ibz_init(&denom);
|
||||
ibz_init(&q);
|
||||
ibz_init(&det);
|
||||
ibq_init(&coeff);
|
||||
ibz_mat_4x4_init(&red);
|
||||
quat_lattice_init(&lat);
|
||||
quat_lattice_init(&test);
|
||||
ibz_set(&num,3);
|
||||
ibz_set(&denom,4);
|
||||
ibq_set(&coeff,&num,&denom);
|
||||
|
||||
for (int iter = 0; iter < 20; iter++){
|
||||
rand_denom = 0;
|
||||
while(rand_denom ==0) {
|
||||
int randret = randombytes((unsigned char*)&rand_denom, sizeof(uint32_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
}
|
||||
int randret = randombytes((unsigned char*)&rand_q, sizeof(uint32_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
// generate random invertible matrix
|
||||
ibz_set(&det,0);
|
||||
while(ibz_is_zero(&det)){
|
||||
int randret = randombytes((unsigned char*)rand, 4*4*sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
ibz_set(&(lat.basis[i][j]),rand[j][i]);
|
||||
}
|
||||
}
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL,&det,&(lat.basis));
|
||||
}
|
||||
|
||||
// set lattice
|
||||
ibz_set(&lat.denom, rand_denom);
|
||||
quat_lattice_hnf(&lat);
|
||||
// set other parameter
|
||||
ibz_set(&q,rand_q % 1024);
|
||||
//reduce
|
||||
res = res || quat_lattice_lll(&red,&lat,&q,0);
|
||||
// test lll reduced
|
||||
res = res || !quat_dim4_lll_verify(&red,&coeff,&q);
|
||||
// test lattice equality
|
||||
ibz_copy(&(test.denom),&(lat.denom));
|
||||
ibz_mat_4x4_copy(&(test.basis),&(red));
|
||||
quat_lattice_hnf(&test);
|
||||
res = res || !quat_lattice_equal(&test,&lat);
|
||||
}
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test with randomization for lattice_lll failed\n");
|
||||
}
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&denom);
|
||||
ibz_finalize(&q);
|
||||
ibz_finalize(&det);
|
||||
ibq_finalize(&coeff);
|
||||
ibz_mat_4x4_finalize(&red);
|
||||
quat_lattice_finalize(&lat);
|
||||
quat_lattice_finalize(&test);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//int quat_lattice_contains_without_alg(quat_alg_coord_t *coord, const quat_lattice_t *lat, const quat_alg_elem_t *x);
|
||||
int quat_test_randomized_lattice_contains_without_alg(){
|
||||
// int quat_lattice_contains(ibz_vec_4_t *coord, const quat_lattice_t *lat, const quat_alg_elem_t
|
||||
// *x);
|
||||
int
|
||||
quat_test_randomized_lattice_contains(int lattice_bitsize, int coord_bitsize, int iterations)
|
||||
{
|
||||
// only tests the case where the element is in the lattice
|
||||
int res = 0;
|
||||
int randret = 0;
|
||||
ibz_t det;
|
||||
quat_alg_elem_t x, cmp;
|
||||
quat_alg_coord_t coord;
|
||||
ibz_vec_4_t coord, set_coord;
|
||||
quat_lattice_t lat;
|
||||
uint64_t rand_denom;
|
||||
int64_t rand[5][4];
|
||||
ibz_init(&det);
|
||||
quat_alg_coord_init(&coord);
|
||||
ibz_vec_4_init(&coord);
|
||||
ibz_vec_4_init(&set_coord);
|
||||
quat_alg_elem_init(&cmp);
|
||||
quat_alg_elem_init(&x);
|
||||
quat_lattice_init(&lat);
|
||||
|
||||
for (int iter = 0; iter < 10; iter++){
|
||||
rand_denom = 0;
|
||||
while(rand_denom ==0) {
|
||||
int randret = randombytes((unsigned char*)&rand_denom, sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
}
|
||||
// generate random invertible matrix
|
||||
ibz_set(&det,0);
|
||||
while(ibz_is_zero(&det)){
|
||||
int randret = randombytes((unsigned char*)rand, 5*4*sizeof(uint64_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
ibz_set(&(lat.basis[i][j]),rand[j][i]);
|
||||
}
|
||||
ibz_set(&(coord[i]),rand[4][i]);
|
||||
}
|
||||
ibz_mat_4x4_inv_with_det_as_denom(NULL,&det,&(lat.basis));
|
||||
for (int iter = 0; iter < iterations; iter++) {
|
||||
randret = quat_test_input_random_lattice_generation(&lat, lattice_bitsize, 1, 1);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
randret = randret | !ibz_rand_interval_bits(&(set_coord[i]), coord_bitsize);
|
||||
}
|
||||
if (randret != 0)
|
||||
goto fin;
|
||||
|
||||
ibz_set(&(lat.denom),rand_denom);
|
||||
quat_lattice_hnf(&lat);
|
||||
ibz_mat_4x4_eval(&(x.coord),&(lat.basis),&coord);
|
||||
ibz_copy(&(x.denom),&(lat.denom));
|
||||
ibz_vec_4_set(&coord,1,0,1,0);
|
||||
if(quat_lattice_contains_without_alg(&coord,&lat,&x)){
|
||||
ibz_mat_4x4_eval(&(cmp.coord),&(lat.basis),&coord);
|
||||
ibz_copy(&(cmp.denom),&(lat.denom));
|
||||
quat_alg_sub(&cmp,&x,&cmp);
|
||||
ibz_mat_4x4_eval(&(x.coord), &(lat.basis), &set_coord);
|
||||
ibz_copy(&(x.denom), &(lat.denom));
|
||||
ibz_vec_4_set(&coord, 1, 0, 1, 0);
|
||||
if (quat_lattice_contains(&coord, &lat, &x)) {
|
||||
ibz_mat_4x4_eval(&(cmp.coord), &(lat.basis), &coord);
|
||||
ibz_copy(&(cmp.denom), &(lat.denom));
|
||||
quat_alg_sub(&cmp, &x, &cmp);
|
||||
res = res || !quat_alg_elem_is_zero(&cmp);
|
||||
ibz_vec_4_sub(&coord, &coord, &set_coord);
|
||||
res = res || !ibz_vec_4_is_zero(&coord);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test with randomization for lattice_contains_without_alg failed\n");
|
||||
fin:;
|
||||
if (randret != 0) {
|
||||
printf("Randomness failed in quaternion unit test with randomization for lattice_contains\n");
|
||||
}
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test with randomization for lattice_contains failed\n");
|
||||
}
|
||||
ibz_finalize(&det);
|
||||
quat_alg_coord_finalize(&coord);
|
||||
ibz_vec_4_finalize(&coord);
|
||||
ibz_vec_4_finalize(&set_coord);
|
||||
quat_alg_elem_finalize(&x);
|
||||
quat_alg_elem_finalize(&cmp);
|
||||
quat_lattice_finalize(&lat);
|
||||
return(res);
|
||||
return (res);
|
||||
}
|
||||
|
||||
|
||||
//int ibz_cornacchia_extended(ibz_t *x, ibz_t *y, const ibz_t *n, const short *prime_list, const int prime_list_length, short primality_test_iterations, const ibz_t *bad_primes_prod);
|
||||
int quat_test_randomized_ibz_cornacchia_extended(){
|
||||
// void quat_lattice_add(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t
|
||||
// *lat2)
|
||||
int
|
||||
quat_test_randomized_lattice_add(int lattice_bitsize, int iterations)
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t x,y,n, prod,c_res,bad, p;
|
||||
int counter = 1;
|
||||
int counter_p = 3;
|
||||
int counter_good = 1;
|
||||
short rand_exps[100];
|
||||
int64_t rand_fact;
|
||||
short primes[100];
|
||||
short good_primes[100];
|
||||
int primes_length = 100;
|
||||
short iterations = 20;
|
||||
int randret = 0;
|
||||
ibz_t det;
|
||||
quat_lattice_t lat1, lat2, sum;
|
||||
ibz_init(&det);
|
||||
quat_lattice_init(&lat1);
|
||||
quat_lattice_init(&lat2);
|
||||
quat_lattice_init(&sum);
|
||||
|
||||
for (int iter = 0; iter < iterations; iter++) {
|
||||
randret = quat_test_input_random_lattice_generation(&lat1, lattice_bitsize, 1, 1);
|
||||
randret = randret | quat_test_input_random_lattice_generation(&lat2, lattice_bitsize, 1, 1);
|
||||
if (!randret)
|
||||
goto fin;
|
||||
quat_lattice_add(&sum, &lat1, &lat2);
|
||||
res = res | !quat_lattice_inclusion(&lat1, &sum);
|
||||
res = res | !quat_lattice_inclusion(&lat2, &sum);
|
||||
}
|
||||
|
||||
fin:;
|
||||
if (randret != 0) {
|
||||
printf("Randomness failed in quaternion unit test with randomization for lattice_add\n");
|
||||
}
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test with randomization for lattice_add failed\n");
|
||||
}
|
||||
ibz_finalize(&det);
|
||||
quat_lattice_finalize(&lat1);
|
||||
quat_lattice_finalize(&lat2);
|
||||
quat_lattice_finalize(&sum);
|
||||
return (res);
|
||||
}
|
||||
|
||||
// int ibz_cornacchia_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p);
|
||||
int
|
||||
quat_test_randomized_ibz_cornacchia_prime(int bitsize, int n_bound, int iterations)
|
||||
{
|
||||
int res = 0;
|
||||
ibz_t x, y, n, prod, c_res, p;
|
||||
int32_t rand_fact;
|
||||
int randret = 0;
|
||||
ibz_init(&x);
|
||||
ibz_init(&y);
|
||||
ibz_init(&n);
|
||||
ibz_init(&p);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&c_res);
|
||||
ibz_init(&bad);
|
||||
ibz_set(&bad,1);
|
||||
good_primes[0] = 2;
|
||||
primes[0] = 2;
|
||||
while(counter <100){
|
||||
ibz_set(&p,counter_p);
|
||||
if(ibz_probab_prime(&p,20)){
|
||||
primes[counter]=(short) counter_p;
|
||||
if(counter_p%4 == 3){
|
||||
ibz_mul(&bad,&bad,&p);
|
||||
} else {
|
||||
good_primes[counter_good]=(short) counter_p;
|
||||
counter_good++;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
counter_p++;
|
||||
}
|
||||
|
||||
for (int iter = 0; iter < 1000; iter++){
|
||||
ibz_set(&n,1);
|
||||
int randret = randombytes((unsigned char*)&rand_exps, 100*sizeof(short));
|
||||
for(int i = 0; i < counter_good; i++){
|
||||
ibz_set(&p,good_primes[i]);
|
||||
ibz_pow(&p,&p,((int)((unsigned short)rand_exps[i])%16));
|
||||
ibz_mul(&n,&n,&p);
|
||||
}
|
||||
// sample large prime as last factor
|
||||
for (int iter = 0; iter < iterations; iter++) {
|
||||
// Sample small n for cornacchia
|
||||
rand_fact = 0;
|
||||
while(rand_fact == 0) {
|
||||
int randret = randombytes((unsigned char*)&rand_fact, sizeof(uint64_t));
|
||||
while (rand_fact < 1) {
|
||||
randret = randret | randombytes((unsigned char *)&rand_fact, sizeof(int32_t));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
if(rand_fact < 0)
|
||||
rand_fact = - rand_fact;
|
||||
ibz_set(&p,rand_fact);
|
||||
if(!ibz_probab_prime(&p,20))
|
||||
rand_fact = 0;
|
||||
goto fin;
|
||||
if (rand_fact < 0)
|
||||
rand_fact = -rand_fact;
|
||||
rand_fact = rand_fact % n_bound;
|
||||
ibz_set(&n, rand_fact);
|
||||
}
|
||||
ibz_mul(&n,&n,&p);
|
||||
|
||||
ibz_set(&prod,4);
|
||||
ibz_mod(&prod,&p,&prod);
|
||||
if((ibz_probab_prime(&p,100) || (ibz_is_one(&p))) && (ibz_is_one(&prod))){
|
||||
res = res || (!ibz_cornacchia_extended(&x,&y,&n,primes,100,100,&bad));
|
||||
if(res){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&n,&c_res);
|
||||
randret = randret | !ibz_generate_random_prime(&p, 0, bitsize, 32);
|
||||
if (randret != 0)
|
||||
goto fin;
|
||||
// If the legendre symbol is ok, Cornacchia should sometimes be able to solve
|
||||
ibz_neg(&prod, &n);
|
||||
ibz_mod(&prod, &prod, &p);
|
||||
if (ibz_legendre(&prod, &p) > -1) {
|
||||
// If there is output, check the output is correct
|
||||
if (ibz_cornacchia_prime(&x, &y, &n, &p)) {
|
||||
ibz_mul(&c_res, &x, &x);
|
||||
ibz_mul(&prod, &y, &y);
|
||||
ibz_mul(&prod, &prod, &n);
|
||||
ibz_add(&c_res, &c_res, &prod);
|
||||
res = res || (0 != ibz_cmp(&p, &c_res));
|
||||
}
|
||||
//(this test depends on the primality test)
|
||||
// now it is not a prime factor any more
|
||||
ibz_set(&p,rand_fact);
|
||||
ibz_mul(&n,&n,&p);
|
||||
res = res || ibz_cornacchia_extended(&x,&y,&n,primes,100,1000,&bad);
|
||||
// multiply with random bad primes
|
||||
ibz_div(&n,&p,&n,&p);
|
||||
int randret = randombytes((unsigned char*)&rand_exps, 100*sizeof(short));
|
||||
if (randret != 0)
|
||||
return 1;
|
||||
for(int i = 0; i < 100; i++){
|
||||
ibz_set(&p,primes[i]);
|
||||
ibz_pow(&p,&p,((int)((unsigned short)rand_exps[i])%8));
|
||||
ibz_mul(&n,&n,&p);
|
||||
}
|
||||
ibz_gcd(&p,&n,&bad);
|
||||
if(ibz_is_one(&p)){
|
||||
res = res || !ibz_cornacchia_extended(&x,&y,&n,primes,100,100,&bad);
|
||||
if(res){
|
||||
ibz_mul(&c_res,&x,&x);
|
||||
ibz_mul(&prod,&y,&y);
|
||||
ibz_add(&c_res,&c_res,&prod);
|
||||
res = res || ibz_cmp(&n,&c_res);
|
||||
}
|
||||
} else {
|
||||
res = res || ibz_cornacchia_extended(&x,&y,&n,primes,100,100,&bad);
|
||||
}
|
||||
} else {
|
||||
res = res || ibz_cornacchia_extended(&x,&y,&n,primes,100,1000,&bad);
|
||||
for(int i = 0; i < 100; i++){
|
||||
ibz_set(&p,primes[i]);
|
||||
ibz_pow(&p,&p,((int)((unsigned short)rand_exps[i])%8));
|
||||
ibz_mul(&n,&n,&p);
|
||||
}
|
||||
ibz_gcd(&p,&n,&bad);
|
||||
res = res || ibz_cornacchia_extended(&x,&y,&n,primes,100,100,&bad);
|
||||
}
|
||||
// Otherwise Cornacchia should fail
|
||||
res = res || (ibz_cornacchia_prime(&x, &y, &n, &p));
|
||||
}
|
||||
}
|
||||
fin:;
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test with randomization for ibz_cornacchia_extended failed\n");
|
||||
if (randret != 0) {
|
||||
printf("Randomness failed in quaternion unit test with randomization for "
|
||||
"ibz_cornacchia_prime\n");
|
||||
}
|
||||
if (res != 0) {
|
||||
printf("Quaternion unit test with randomization for ibz_cornacchia_prime failed\n");
|
||||
}
|
||||
ibz_finalize(&x);
|
||||
ibz_finalize(&y);
|
||||
@@ -739,24 +275,19 @@ int quat_test_randomized_ibz_cornacchia_extended(){
|
||||
ibz_finalize(&p);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&c_res);
|
||||
ibz_finalize(&bad);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// run all previous tests
|
||||
int quat_test_with_randomization(){
|
||||
int
|
||||
quat_test_with_randomization(void)
|
||||
{
|
||||
int res = 0;
|
||||
printf("\nRunning randomized tests from quaternion module\n");
|
||||
res = res | quat_test_randomized_ibz_mat_2x2_inv_mod();
|
||||
res = res | quat_test_randomized_2x2_lattice_enumerate_cvp_filter();
|
||||
res = res | quat_test_randomized_ibz_mat_4x4_inv_with_det_as_denom();
|
||||
res = res | quat_test_randomized_ibz_mat_4x8_hnf_core();
|
||||
res = res | quat_test_randomized_ibz_4x5_right_ker_mod_prime();
|
||||
res = res | quat_test_randomized_ibz_4x4_right_ker_mod_prime();
|
||||
res = res | quat_test_randomized_ibz_4x4_right_ker_mod_power_of_2();
|
||||
res = res | quat_test_randomized_lattice_lll();
|
||||
res = res | quat_test_randomized_lattice_contains_without_alg();
|
||||
res = res | quat_test_randomized_ibz_cornacchia_extended();
|
||||
return(res);
|
||||
res = res | quat_test_randomized_ibz_mat_2x2_inv_mod(370, 270, 100);
|
||||
res = res | quat_test_randomized_ibz_mat_4x4_inv_with_det_as_denom(1500, 10);
|
||||
res = res | quat_test_randomized_lattice_contains(250, 250, 10);
|
||||
res = res | quat_test_randomized_lattice_add(700, 100);
|
||||
res = res | quat_test_randomized_ibz_cornacchia_prime(128, 6, 10);
|
||||
return (res);
|
||||
}
|
||||
|
||||
@@ -1,20 +1,70 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "quaternion_tests.h"
|
||||
#include <rng.h>
|
||||
#include <bench_test_arguments.h>
|
||||
|
||||
// run all tests in module
|
||||
int main(){
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t seed[12] = { 0 };
|
||||
int help = 0;
|
||||
int seed_set = 0;
|
||||
int res = 0;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!help && strcmp(argv[i], "--help") == 0) {
|
||||
help = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!seed_set && !parse_seed(argv[i], seed)) {
|
||||
seed_set = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (help) {
|
||||
printf("Usage: %s [--seed=<seed>]\n", argv[0]);
|
||||
printf("Where <seed> is the random seed to be used; if not present, a random seed is "
|
||||
"generated\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!seed_set) {
|
||||
randombytes_select((unsigned char *)seed, sizeof(seed));
|
||||
}
|
||||
|
||||
print_seed(seed);
|
||||
|
||||
#if defined(TARGET_BIG_ENDIAN)
|
||||
for (int i = 0; i < 12; i++) {
|
||||
seed[i] = BSWAP32(seed[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("Running quaternion module unit tests\n");
|
||||
|
||||
res = res | ibz_test_intbig();
|
||||
res = res | mini_gmp_test();
|
||||
res = res | quat_test_finit();
|
||||
res = res | quat_test_dim4();
|
||||
res = res | quat_test_dim2();
|
||||
res = res | quat_test_matkermod();
|
||||
res = res | quat_test_integers();
|
||||
res = res | quat_test_hnf();
|
||||
res = res | quat_test_algebra();
|
||||
res = res | quat_test_lattice();
|
||||
res = res | quat_test_lll();
|
||||
res = res | quat_test_lideal();
|
||||
res = res | quat_test_normeq();
|
||||
res = res | quat_test_lat_ball();
|
||||
res = res | quat_test_with_randomization();
|
||||
if(res != 0){
|
||||
if (res != 0) {
|
||||
printf("\nSome tests failed!\n");
|
||||
}
|
||||
return(res);
|
||||
return (res);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user