initial version of SQIsign
Co-authored-by: Jorge Chavez-Saab <jorgechavezsaab@gmail.com> Co-authored-by: Maria Corte-Real Santos <36373796+mariascrs@users.noreply.github.com> Co-authored-by: Luca De Feo <github@defeo.lu> Co-authored-by: Jonathan Komada Eriksen <jonathan.eriksen97@gmail.com> Co-authored-by: Basil Hess <bhe@zurich.ibm.com> Co-authored-by: Antonin Leroux <18654258+tonioecto@users.noreply.github.com> Co-authored-by: Patrick Longa <plonga@microsoft.com> Co-authored-by: Lorenz Panny <lorenz@yx7.cc> Co-authored-by: Francisco Rodríguez-Henríquez <francisco.rodriguez@tii.ae> Co-authored-by: Sina Schaeffler <108983332+syndrakon@users.noreply.github.com> Co-authored-by: Benjamin Wesolowski <19474926+Calodeon@users.noreply.github.com>
This commit is contained in:
1
src/quaternion/CMakeLists.txt
Normal file
1
src/quaternion/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
||||
include(${SELECT_IMPL_TYPE})
|
||||
1
src/quaternion/ref/CMakeLists.txt
Normal file
1
src/quaternion/ref/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
||||
include(${SELECT_SQISIGN_VARIANT})
|
||||
18
src/quaternion/ref/generic/CMakeLists.txt
Normal file
18
src/quaternion/ref/generic/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
set(SOURCE_FILES_QUATERNION_GENERIC_REF
|
||||
algebra.c
|
||||
ideal.c
|
||||
dim4.c
|
||||
dim2.c
|
||||
integers.c
|
||||
lattice.c
|
||||
finit.c
|
||||
printer.c
|
||||
lll.c
|
||||
matkermod.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})
|
||||
target_compile_options(${LIB_QUATERNION} PRIVATE ${C_OPT_FLAGS})
|
||||
|
||||
add_subdirectory(test)
|
||||
287
src/quaternion/ref/generic/algebra.c
Normal file
287
src/quaternion/ref/generic/algebra.c
Normal file
@@ -0,0 +1,287 @@
|
||||
#include <quaternion.h>
|
||||
#include "internal.h"
|
||||
|
||||
//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_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_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);
|
||||
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]);
|
||||
}
|
||||
quat_alg_elem_finalize(&e);
|
||||
quat_alg_elem_finalize(&res);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
quat_alg_elem_finalize(&conj);
|
||||
quat_alg_elem_finalize(&norm);
|
||||
}
|
||||
|
||||
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_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_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]));
|
||||
}
|
||||
|
||||
//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_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]));
|
||||
}
|
||||
ibz_neg(&(x->denom),&(x->denom));
|
||||
}
|
||||
ibz_finalize(&gcd);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&zero);
|
||||
}
|
||||
|
||||
int quat_alg_elem_is_zero(const quat_alg_elem_t *x){
|
||||
int res = quat_alg_coord_is_zero(&(x->coord));
|
||||
return(res);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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_set(quat_alg_elem_t *elem, int64_t denom, int64_t coord0, int64_t coord1, int64_t coord2, int64_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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
553
src/quaternion/ref/generic/dim2.c
Normal file
553
src/quaternion/ref/generic/dim2.c
Normal file
@@ -0,0 +1,553 @@
|
||||
#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);
|
||||
}
|
||||
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){
|
||||
ibz_t prod;
|
||||
ibz_init(&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){
|
||||
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_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_copy(&(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);
|
||||
ibz_vec_2_finalize(&matvec);
|
||||
}
|
||||
|
||||
// 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){
|
||||
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++){
|
||||
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]));
|
||||
}
|
||||
}
|
||||
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;
|
||||
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_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);
|
||||
}
|
||||
842
src/quaternion/ref/generic/dim4.c
Normal file
842
src/quaternion/ref/generic/dim4.c
Normal file
@@ -0,0 +1,842 @@
|
||||
#include <quaternion.h>
|
||||
#include "internal.h"
|
||||
|
||||
//internal helper functions
|
||||
void ibz_mat_4x4_mul(ibz_mat_4x4_t *res, const ibz_mat_4x4_t *a, const ibz_mat_4x4_t *b){
|
||||
ibz_mat_4x4_t mat;
|
||||
ibz_t prod;
|
||||
ibz_init(&prod);
|
||||
ibz_mat_4x4_init(&mat);
|
||||
for (int i = 0; i <4; i++){
|
||||
for (int j = 0; j <4; j++){
|
||||
ibz_set(&(mat[i][j]),0);
|
||||
for (int k = 0; k <4; k++){
|
||||
ibz_mul(&prod,&((*a)[i][k]), &((*b)[k][j]));
|
||||
ibz_add(&(mat[i][j]), &(mat[i][j]), &prod);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i <4; i++){
|
||||
for (int j = 0; j <4; j++){
|
||||
ibz_copy(&((*res)[i][j]),&(mat[i][j]));
|
||||
}
|
||||
}
|
||||
ibz_mat_4x4_finalize(&mat);
|
||||
ibz_finalize(&prod);
|
||||
}
|
||||
|
||||
//helper functions for lattices
|
||||
void ibz_vec_4_set(ibz_vec_4_t *vec, int64_t coord0, int64_t coord1, int64_t coord2, int64_t coord3){
|
||||
ibz_set(&((*vec)[0]),coord0);
|
||||
ibz_set(&((*vec)[1]),coord1);
|
||||
ibz_set(&((*vec)[2]),coord2);
|
||||
ibz_set(&((*vec)[3]),coord3);
|
||||
}
|
||||
|
||||
void ibz_vec_4_copy(ibz_vec_4_t *new, const ibz_vec_4_t *vec){
|
||||
for (int i = 0; i <4; i++){
|
||||
ibz_copy(&((*new)[i]),&((*vec)[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_vec_4_negate(ibz_vec_4_t *neg, const ibz_vec_4_t *vec){
|
||||
for (int i = 0; i <4; i++){
|
||||
ibz_neg(&((*neg)[i]),&((*vec)[i]));
|
||||
}
|
||||
}
|
||||
|
||||
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){
|
||||
ibz_t prod;
|
||||
ibz_vec_4_t sums;
|
||||
ibz_vec_4_init(&sums);
|
||||
ibz_init(&prod);
|
||||
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);
|
||||
}
|
||||
for (int i = 0; i <4; i++){
|
||||
ibz_copy(&((*lc)[i]),&(sums[i]));
|
||||
}
|
||||
ibz_finalize(&prod);
|
||||
ibz_vec_4_finalize(&sums);
|
||||
}
|
||||
|
||||
int ibz_vec_4_scalar_div(ibz_vec_4_t *quot, const ibz_t *scalar, const ibz_vec_4_t *vec){
|
||||
int res = 1;
|
||||
ibz_t r;
|
||||
ibz_init(&r);
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_div(&((*quot)[i]),&r,&((*vec)[i]),scalar);
|
||||
res = res && ibz_is_zero(&r);
|
||||
}
|
||||
ibz_finalize(&r);
|
||||
return(res);
|
||||
}
|
||||
|
||||
void ibz_mat_4x4_copy(ibz_mat_4x4_t *new, const ibz_mat_4x4_t *mat){
|
||||
for(int i = 0; i <4; i++){
|
||||
for(int j = 0; j<4; j++){
|
||||
ibz_copy(&((*new)[i][j]),&((*mat)[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_mat_4x4_negate(ibz_mat_4x4_t *neg, const ibz_mat_4x4_t *mat){
|
||||
for(int i = 0; i <4; i++){
|
||||
for(int j = 0; j<4; j++){
|
||||
ibz_neg(&((*neg)[i][j]),&((*mat)[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_mat_4x4_transpose(ibz_mat_4x4_t *transposed, const ibz_mat_4x4_t *mat){
|
||||
ibz_mat_4x4_t work;
|
||||
ibz_mat_4x4_init(&work);
|
||||
for(int i = 0; i < 4; i ++){
|
||||
for(int j = 0; j < 4; j ++){
|
||||
ibz_copy(&(work[i][j]),&((*mat)[j][i]));
|
||||
}
|
||||
}
|
||||
ibz_mat_4x4_copy(transposed,&work);
|
||||
ibz_mat_4x4_finalize(&work);
|
||||
}
|
||||
|
||||
void ibz_mat_4x4_zero(ibz_mat_4x4_t *zero){
|
||||
for(int i = 0; i <4; i++){
|
||||
for(int j = 0; j<4; j++){
|
||||
ibz_set(&((*zero)[i][j]),0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_mat_4x4_identity(ibz_mat_4x4_t *id){
|
||||
for(int i = 0; i <4; i++){
|
||||
for(int j = 0; j<4; j++){
|
||||
ibz_set(&((*id)[i][j]),0);
|
||||
}
|
||||
ibz_set(&((*id)[i][i]),1);
|
||||
}
|
||||
}
|
||||
|
||||
int ibz_mat_4x4_is_identity(const ibz_mat_4x4_t *mat){
|
||||
int res = 1;
|
||||
for(int i = 0; i <4; i++){
|
||||
for(int j = 0; j<4; j++){
|
||||
res = res && (ibz_get(&((*mat)[i][j])) == (i==j));
|
||||
}
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
int ibz_mat_4x4_equal(const ibz_mat_4x4_t *mat1, const ibz_mat_4x4_t *mat2){
|
||||
int res = 0;
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
res = res || ibz_cmp(&((*mat1)[i][j]),&((*mat2)[i][j]));
|
||||
}
|
||||
}
|
||||
return(!res);
|
||||
}
|
||||
|
||||
void ibz_mat_4x4_scalar_mul(ibz_mat_4x4_t *prod, const ibz_t *scalar, const ibz_mat_4x4_t *mat){
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_mul(&((*prod)[i][j]),&((*mat)[i][j]),scalar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_mat_4x4_gcd(ibz_t *gcd, const ibz_mat_4x4_t *mat){
|
||||
ibz_t d;
|
||||
ibz_init(&d);
|
||||
ibz_copy(&d, &((*mat)[0][0]));
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_gcd(&d,&d,&((*mat)[i][j]));
|
||||
}
|
||||
}
|
||||
ibz_copy(gcd,&d);
|
||||
ibz_finalize(&d);
|
||||
}
|
||||
|
||||
int ibz_mat_4x4_scalar_div(ibz_mat_4x4_t *quot, const ibz_t *scalar, const ibz_mat_4x4_t *mat){
|
||||
int res = 1;
|
||||
ibz_t r;
|
||||
ibz_init(&r);
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_div(&((*quot)[i][j]),&r,&((*mat)[i][j]),scalar);
|
||||
res = res && ibz_is_zero(&r);
|
||||
}
|
||||
}
|
||||
ibz_finalize(&r);
|
||||
return(res);
|
||||
}
|
||||
|
||||
|
||||
int ibz_mat_4x4_is_hnf(const ibz_mat_4x4_t *mat){
|
||||
int res = 1;
|
||||
int found = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
//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
|
||||
// assumes ibz_xgcd outputs u,v which are small in absolute value (as described in the book)void ibz_mat_4x8_hnf_core(ibz_mat_4x4_t *hnf, const ibz_mat_4x8_t *generators)
|
||||
void ibz_mat_4x8_hnf_core(ibz_mat_4x4_t *hnf, const ibz_mat_4x8_t *generators)
|
||||
{
|
||||
int i = 3;
|
||||
int j = 7;
|
||||
int k = 7;
|
||||
ibz_t b, u, v, d, zero, coeff_1, coeff_2, r;
|
||||
ibz_vec_4_t c;
|
||||
ibz_vec_4_t a[8];
|
||||
ibz_init(&b);
|
||||
ibz_init(&d);
|
||||
ibz_init(&u);
|
||||
ibz_init(&v);
|
||||
ibz_init(&r);
|
||||
ibz_init(&coeff_1);
|
||||
ibz_init(&coeff_2);
|
||||
ibz_init(&zero);
|
||||
ibz_set(&zero,0);
|
||||
ibz_vec_4_init(&c);
|
||||
for (int h = 0; h < 8; h++){
|
||||
ibz_vec_4_init(&(a[h]));
|
||||
ibz_copy(&(a[h][0]), &((*generators)[0][h]));
|
||||
ibz_copy(&(a[h][1]), &((*generators)[1][h]));
|
||||
ibz_copy(&(a[h][2]), &((*generators)[2][h]));
|
||||
ibz_copy(&(a[h][3]), &((*generators)[3][h]));
|
||||
}
|
||||
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
|
||||
ibz_xgcd(&d,&u,&v,&(a[k][i]),&(a[j][i]));
|
||||
// also, needs u non 0, but v can be 0 if needed
|
||||
if(ibz_is_zero(&u)){
|
||||
ibz_div(&v,&r,&(a[k][i]),&(a[j][i]));
|
||||
ibz_set(&u,1);
|
||||
ibz_sub(&v,&u,&v);
|
||||
}
|
||||
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(&(a[j]),&coeff_1,&(a[j]),&coeff_2,&(a[k]));
|
||||
ibz_vec_4_copy(&(a[k]),&c);
|
||||
}
|
||||
}
|
||||
ibz_copy(&b,&(a[k][i]));
|
||||
if (ibz_cmp(&b, &zero) < 0){
|
||||
ibz_vec_4_negate(&(a[k]),&(a[k]));
|
||||
ibz_neg(&b, &b);
|
||||
}
|
||||
if (ibz_is_zero(&b)){
|
||||
k = k + 1;
|
||||
} else {
|
||||
for(j = k+1; j < 8; j++) {
|
||||
ibz_div(&d,&r,&(a[j][i]),&b);
|
||||
if(ibz_cmp(&r,&zero) < 0){
|
||||
ibz_set(&r,1);
|
||||
ibz_sub(&d,&d,&r);
|
||||
}
|
||||
ibz_set(&r,1);
|
||||
ibz_neg(&d,&d);
|
||||
ibz_vec_4_linear_combination(&(a[j]),&r,&(a[j]),&d ,&(a[k]));
|
||||
}
|
||||
}
|
||||
if (i != 0) {
|
||||
k = k - 1;
|
||||
j = k;
|
||||
}
|
||||
i = i - 1;
|
||||
}
|
||||
for (j = 4; j < 8; j++) {
|
||||
for(i = 0; i < 4; i++){
|
||||
ibz_copy(&((*hnf)[i][j-4]),&(a[j][i]));
|
||||
}
|
||||
}
|
||||
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&d);
|
||||
ibz_finalize(&u);
|
||||
ibz_finalize(&v);
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&coeff_1);
|
||||
ibz_finalize(&coeff_2);
|
||||
ibz_finalize(&zero);
|
||||
ibz_vec_4_finalize(&c);
|
||||
for (int h = 0; h < 8; h++)
|
||||
{
|
||||
ibz_vec_4_finalize(&(a[h]));
|
||||
}
|
||||
}
|
||||
|
||||
void ibz_mat_4x4_hnf_mod(ibz_mat_4x4_t *hnf, const ibz_mat_4x4_t *mat, const ibz_t *mod){
|
||||
ibz_mat_4x8_t input;
|
||||
ibz_mat_4x8_init(&input);
|
||||
for(int i = 0; i <4; i++){
|
||||
for(int j = 0; j <4; j++){
|
||||
ibz_copy(&(input[i][j]),&((*mat)[i][j]));
|
||||
ibz_set(&(input[i][j+4]),0);
|
||||
}
|
||||
ibz_copy(&(input[i][i+4]),mod);
|
||||
}
|
||||
ibz_mat_4x8_hnf_core(hnf,&input);
|
||||
ibz_mat_4x8_finalize(&input);
|
||||
}
|
||||
|
||||
|
||||
// functions to verify lll
|
||||
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){
|
||||
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_dim4_lll_bilinear(ibq_t *b, const ibq_t (*vec0)[4], const ibq_t (*vec1)[4], 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_dim4_gram_schmidt_transposed_with_ibq(ibq_t (*orthogonalised_transposed)[4][4], const ibz_mat_4x4_t *mat, const ibz_t *q){
|
||||
ibq_t work[4][4];
|
||||
ibq_t vec[4];
|
||||
ibq_t norm, b, coeff, prod;
|
||||
ibq_init(&norm);
|
||||
ibq_init(&coeff);
|
||||
ibq_init(&prod);
|
||||
ibq_init(&b);
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibq_init(&(work[i][j]));
|
||||
}
|
||||
ibq_init(&(vec[i]));
|
||||
}
|
||||
// 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_dim4_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_dim4_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]));
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibq_finalize(&(work[i][j]));
|
||||
}
|
||||
ibq_finalize(&(vec[i]));
|
||||
}
|
||||
ibq_finalize(&norm);
|
||||
ibq_finalize(&coeff);
|
||||
ibq_finalize(&prod);
|
||||
ibq_finalize(&b);
|
||||
}
|
||||
|
||||
int quat_dim4_lll_verify(const ibz_mat_4x4_t *mat, const ibq_t *coeff, const ibz_t *q){
|
||||
int res = 1;
|
||||
ibq_t orthogonalised_transposed[4][4];
|
||||
ibq_t tmp_vec[4];
|
||||
ibq_t div,tmp,mu,two, norm, b;
|
||||
ibz_t mu2_floored,num,denom;
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibq_init(&(orthogonalised_transposed[i][j]));
|
||||
}
|
||||
ibq_init(&(tmp_vec[i]));
|
||||
}
|
||||
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_dim4_gram_schmidt_transposed_with_ibq(&orthogonalised_transposed, mat,q);
|
||||
// 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_dim4_lll_bilinear(&b, &(orthogonalised_transposed[j]),&tmp_vec,q);
|
||||
quat_dim4_lll_bilinear(&norm, &(orthogonalised_transposed[j]),&(orthogonalised_transposed[j]),q);
|
||||
ibq_inv(&tmp,&norm);
|
||||
ibq_mul(&mu,&b,&tmp);
|
||||
//mu contains 2mu from now on
|
||||
ibq_mul(&tmp,&mu,&two);
|
||||
ibq_num(&num,&tmp);
|
||||
ibq_denom(&denom,&tmp);
|
||||
//assume rounding to 0
|
||||
ibz_div(&mu2_floored,&denom,&num,&denom);
|
||||
// 2*mu floores is 0 or mu is exactly 1/2, so (2mu)^2 is exactly 1
|
||||
ibq_mul(&tmp,&tmp,&tmp);
|
||||
res = res && (ibz_is_zero(&mu2_floored) || ibq_is_one(&tmp));
|
||||
}
|
||||
}
|
||||
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_dim4_lll_bilinear(&b, &(orthogonalised_transposed[i-1]),&tmp_vec,q);
|
||||
quat_dim4_lll_bilinear(&norm, &(orthogonalised_transposed[i-1]),&(orthogonalised_transposed[i-1]),q);
|
||||
ibq_inv(&tmp,&norm);
|
||||
ibq_mul(&mu,&b,&tmp);
|
||||
// tmp is mu^2
|
||||
ibq_mul(&tmp,&mu,&mu);
|
||||
// mu is coeff-mu^2
|
||||
ibq_sub(&mu,coeff,&tmp);
|
||||
quat_dim4_lll_bilinear(&tmp, &(orthogonalised_transposed[i]),&(orthogonalised_transposed[i]),q);
|
||||
//get (3/4-mu^2)norm(i-1)
|
||||
ibq_mul(&div,&norm,&mu);
|
||||
res = res && (ibq_cmp(&tmp,&div) >= 0);
|
||||
}
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibq_finalize(&(orthogonalised_transposed[i][j]));
|
||||
}
|
||||
ibq_finalize(&(tmp_vec[i]));
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
//4x4 inversion helper functions
|
||||
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){
|
||||
ibz_t prod, sum;
|
||||
ibz_init(&prod);
|
||||
ibz_init(&sum);
|
||||
ibz_mul(&sum,a1,a2);
|
||||
ibz_mul(&prod,b1,b2);
|
||||
ibz_sub(&sum,&sum,&prod);
|
||||
ibz_mul(&prod,c1,c2);
|
||||
ibz_add(coeff,&sum,&prod);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&sum);
|
||||
}
|
||||
|
||||
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){
|
||||
ibz_t prod, sum;
|
||||
ibz_init(&prod);
|
||||
ibz_init(&sum);
|
||||
ibz_mul(&sum,b1,b2);
|
||||
ibz_mul(&prod,a1,a2);
|
||||
ibz_sub(&sum,&sum,&prod);
|
||||
ibz_mul(&prod,c1,c2);
|
||||
ibz_sub(coeff,&sum,&prod);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&sum);
|
||||
}
|
||||
|
||||
//Method from https://www.geometrictools.com/Documentation/LaplaceExpansionTheorem.pdf 3rd of May 2023, 16h15 CEST
|
||||
int ibz_mat_4x4_inv_with_det_as_denom(ibz_mat_4x4_t *inv, ibz_t *det, const ibz_mat_4x4_t *mat){
|
||||
ibz_t prod,work_det;
|
||||
ibz_mat_4x4_t work;
|
||||
ibz_t s[6];
|
||||
ibz_t c[6];
|
||||
for (int i = 0; i < 6; i++){
|
||||
ibz_init(&(s[i]));
|
||||
ibz_init(&(c[i]));
|
||||
}
|
||||
ibz_mat_4x4_init(&work);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&work_det);
|
||||
|
||||
//compute some 2x2 minors, store them in s and c
|
||||
for (int i = 0; i < 3; i++){
|
||||
ibz_mat_2x2_det_from_ibz(&(s[i]),&((*mat)[0][0]),&((*mat)[0][i+1]),&((*mat)[1][0]),&((*mat)[1][i+1]));
|
||||
ibz_mat_2x2_det_from_ibz(&(c[i]),&((*mat)[2][0]),&((*mat)[2][i+1]),&((*mat)[3][0]),&((*mat)[3][i+1]));
|
||||
}
|
||||
for (int i = 0; i < 2; i++){
|
||||
ibz_mat_2x2_det_from_ibz(&(s[3+i]),&((*mat)[0][1]),&((*mat)[0][2+i]),&((*mat)[1][1]),&((*mat)[1][2+i]));
|
||||
ibz_mat_2x2_det_from_ibz(&(c[3+i]),&((*mat)[2][1]),&((*mat)[2][2+i]),&((*mat)[3][1]),&((*mat)[3][2+i]));
|
||||
}
|
||||
ibz_mat_2x2_det_from_ibz(&(s[5]),&((*mat)[0][2]),&((*mat)[0][3]),&((*mat)[1][2]),&((*mat)[1][3]));
|
||||
ibz_mat_2x2_det_from_ibz(&(c[5]),&((*mat)[2][2]),&((*mat)[2][3]),&((*mat)[3][2]),&((*mat)[3][3]));
|
||||
|
||||
//compute det
|
||||
ibz_set(&work_det,0);
|
||||
for (int i = 0; i < 6; i++){
|
||||
ibz_mul(&prod,&(s[i]),&(c[5-i]));
|
||||
if ((i != 1) && (i != 4)){
|
||||
ibz_add(&work_det,&work_det,&prod);
|
||||
} else {
|
||||
ibz_sub(&work_det,&work_det,&prod);
|
||||
}
|
||||
}
|
||||
if (!ibz_is_zero(&work_det)){
|
||||
//compute transposed adjugate
|
||||
for (int j = 0; j < 4; j++){
|
||||
for (int k = 0; k < 2; k++){
|
||||
if ((k + j + 1) % 2 == 1){
|
||||
ibz_inv_dim4_make_coeff_pmp(&(work[j][k]), &((*mat)[1-k][(j==0)]), &(c[6-j-(j==0)]), &((*mat)[1-k][2-(j>1)]), &(c[4-j-(j==1)]), &((*mat)[1-k][3-(j==3)]), &(c[3-j-(j==1)-(j==2)]));
|
||||
} else {
|
||||
ibz_inv_dim4_make_coeff_mpm(&(work[j][k]), &((*mat)[1-k][(j==0)]), &(c[6-j-(j==0)]), &((*mat)[1-k][2-(j>1)]), &(c[4-j-(j==1)]), &((*mat)[1-k][3-(j==3)]), &(c[3-j-(j==1)-(j==2)]));
|
||||
}
|
||||
}
|
||||
for (int k = 2; k < 4; k++){
|
||||
if ((k + j + 1) % 2 == 1){
|
||||
ibz_inv_dim4_make_coeff_pmp(&(work[j][k]), &((*mat)[3-(k==3)][(j==0)]), &(s[6-j-(j==0)]),&((*mat)[3-(k==3)][2-(j>1)]), &(s[4-j-(j==1)]),&((*mat)[3-(k==3)][3-(j==3)]), &(s[3-j-(j==1)-(j==2)]));
|
||||
} else {
|
||||
ibz_inv_dim4_make_coeff_mpm(&(work[j][k]), &((*mat)[3-(k==3)][(j==0)]), &(s[6-j-(j==0)]),&((*mat)[3-(k==3)][2-(j>1)]), &(s[4-j-(j==1)]),&((*mat)[3-(k==3)][3-(j==3)]), &(s[3-j-(j==1)-(j==2)]));
|
||||
}
|
||||
}
|
||||
}
|
||||
// put transposed adjugate in result
|
||||
if(inv != NULL)
|
||||
ibz_mat_4x4_copy(inv,&work);
|
||||
}
|
||||
//output det in any case
|
||||
if(det != NULL)
|
||||
ibz_copy(det,&work_det);
|
||||
for (int i = 0; i < 6; i++){
|
||||
ibz_finalize(&s[i]);
|
||||
ibz_finalize(&c[i]);
|
||||
}
|
||||
ibz_mat_4x4_finalize(&work);
|
||||
ibz_finalize(&work_det);
|
||||
ibz_finalize(&prod);
|
||||
return(!ibz_is_zero(det));
|
||||
}
|
||||
|
||||
// larger matrix modular kernel
|
||||
|
||||
//Algorithm used is the one at number 2.3.1 in Henri Cohen's "A Course in Computational Algebraic Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993
|
||||
//most notations also are from there, except their r becoming kernel_dimension here and prod being used instaed of d as temporary variable.
|
||||
int ibz_4x5_right_ker_mod_prime(ibz_vec_5_t *ker, const ibz_mat_4x5_t *mat, const ibz_t *p){
|
||||
int k, i, j, kernel_dim, columns, rows;
|
||||
int c[4] ={0,0,0,0};
|
||||
int d[5];
|
||||
ibz_mat_4x5_t work_mat;
|
||||
ibz_t prod, var;
|
||||
ibz_init(&prod);
|
||||
ibz_init(&var);
|
||||
k = 0;
|
||||
columns = 5;
|
||||
rows = 4;
|
||||
j = 0;
|
||||
kernel_dim = 0;
|
||||
ibz_mat_4x5_init(&work_mat);
|
||||
for(int s = 0; s < rows; s++){
|
||||
for(int t = 0; t < columns; t++){
|
||||
ibz_mod(&(work_mat[s][t]),&((*mat)[s][t]),p);
|
||||
}
|
||||
}
|
||||
while(k<columns){
|
||||
j = 0;
|
||||
while((j<rows)&&(ibz_is_zero(&(work_mat[j][k]))||(c[j]!=0))){
|
||||
j = j + 1;
|
||||
}
|
||||
// found none
|
||||
if(j == rows){
|
||||
kernel_dim = kernel_dim+1;
|
||||
d[k]=0;
|
||||
k = k+1;
|
||||
} else { // found such a j
|
||||
ibz_invmod(&prod,&(work_mat[j][k]),p);
|
||||
ibz_neg(&prod,&prod);
|
||||
ibz_mod(&prod,&prod,p);
|
||||
ibz_set(&(work_mat[j][k]),-1);
|
||||
ibz_mod(&(work_mat[j][k]),&(work_mat[j][k]),p);
|
||||
for(int s = k+1; s < columns; s++){
|
||||
ibz_mul(&(work_mat[j][s]),&(work_mat[j][s]),&prod);
|
||||
ibz_mod(&(work_mat[j][s]),&(work_mat[j][s]),p);
|
||||
}
|
||||
for(i = 0; i< rows; i++){
|
||||
if(i!=j){
|
||||
ibz_copy(&var,&(work_mat[i][k]));
|
||||
ibz_set(&(work_mat[i][k]),0);
|
||||
for(int s = k+1; s < columns; s++){
|
||||
ibz_mul(&prod,&(work_mat[j][s]),&var);
|
||||
ibz_add(&(work_mat[i][s]),&(work_mat[i][s]),&prod);
|
||||
ibz_mod(&(work_mat[i][s]),&(work_mat[i][s]),p);
|
||||
}
|
||||
}
|
||||
}
|
||||
c[j] = k+1;
|
||||
d[k] = j+1;
|
||||
k = k + 1;
|
||||
}
|
||||
}
|
||||
//create output
|
||||
if(kernel_dim==1){
|
||||
for(k = 0; k <columns; k++){
|
||||
// should be true exactly for 1 k, since kernel_dim = 1
|
||||
if(d[k]== 0){
|
||||
for(int s = 0; s < columns; s++){
|
||||
ibz_set(&((*ker)[s]),0);
|
||||
if(s == k){
|
||||
ibz_set(&((*ker)[s]),1);
|
||||
}
|
||||
if(d[s] > 0){
|
||||
ibz_mod(&((*ker)[s]),&(work_mat[d[s]-1][k]),p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&var);
|
||||
ibz_mat_4x5_finalize(&work_mat);
|
||||
return(kernel_dim==1);
|
||||
}
|
||||
|
||||
//same algo as ibz_4x5_right_ker_mod_prime, same notations, just the column number changes
|
||||
int ibz_4x4_right_ker_mod_prime(ibz_vec_4_t *ker, const ibz_mat_4x4_t *mat, const ibz_t *p){
|
||||
int k, i, j, kernel_dim, columns, rows;
|
||||
int c[4] ={0,0,0,0};
|
||||
int d[4];
|
||||
ibz_mat_4x4_t work_mat;
|
||||
ibz_t prod, var;
|
||||
ibz_init(&prod);
|
||||
ibz_init(&var);
|
||||
k = 0;
|
||||
columns = 4;
|
||||
rows = 4;
|
||||
j = 0;
|
||||
kernel_dim = 0;
|
||||
ibz_mat_4x4_init(&work_mat);
|
||||
for(int s = 0; s < rows; s++){
|
||||
for(int t = 0; t < columns; t++){
|
||||
ibz_mod(&(work_mat[s][t]),&((*mat)[s][t]),p);
|
||||
}
|
||||
}
|
||||
while(k<columns){
|
||||
j = 0;
|
||||
while((j<rows)&&(ibz_is_zero(&(work_mat[j][k]))||(c[j]!=0))){
|
||||
j = j + 1;
|
||||
}
|
||||
// found none
|
||||
if(j == rows){
|
||||
kernel_dim = kernel_dim+1;
|
||||
d[k]=0;
|
||||
k = k+1;
|
||||
} else { // found such a j
|
||||
ibz_invmod(&prod,&(work_mat[j][k]),p);
|
||||
ibz_neg(&prod,&prod);
|
||||
ibz_mod(&prod,&prod,p);
|
||||
ibz_set(&(work_mat[j][k]),-1);
|
||||
ibz_mod(&(work_mat[j][k]),&(work_mat[j][k]),p);
|
||||
for(int s = k+1; s < columns; s++){
|
||||
ibz_mul(&(work_mat[j][s]),&(work_mat[j][s]),&prod);
|
||||
ibz_mod(&(work_mat[j][s]),&(work_mat[j][s]),p);
|
||||
}
|
||||
for(i = 0; i< rows; i++){
|
||||
if(i!=j){
|
||||
ibz_copy(&var,&(work_mat[i][k]));
|
||||
ibz_set(&(work_mat[i][k]),0);
|
||||
for(int s = k+1; s < columns; s++){
|
||||
ibz_mul(&prod,&(work_mat[j][s]),&var);
|
||||
ibz_add(&(work_mat[i][s]),&(work_mat[i][s]),&prod);
|
||||
ibz_mod(&(work_mat[i][s]),&(work_mat[i][s]),p);
|
||||
}
|
||||
}
|
||||
}
|
||||
c[j] = k+1;
|
||||
d[k] = j+1;
|
||||
k = k + 1;
|
||||
}
|
||||
}
|
||||
//create output
|
||||
if(kernel_dim==1){
|
||||
for(k = 0; k <columns; k++){
|
||||
// should be true exactly for 1 k, since kernel_dim = 1
|
||||
if(d[k]== 0){
|
||||
for(int s = 0; s < columns; s++){
|
||||
ibz_set(&((*ker)[s]),0);
|
||||
if(s == k){
|
||||
ibz_set(&((*ker)[s]),1);
|
||||
}
|
||||
if(d[s] > 0){
|
||||
ibz_mod(&((*ker)[s]),&(work_mat[d[s]-1][k]),p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&var);
|
||||
ibz_mat_4x4_finalize(&work_mat);
|
||||
return(kernel_dim==1);
|
||||
}
|
||||
|
||||
int ibz_4x4_right_ker_mod_power_of_2(ibz_vec_4_t *ker, const ibz_mat_4x4_t *mat, unsigned short exp)
|
||||
{
|
||||
ibz_mat_4x4_t full_ker;
|
||||
ibz_mat_4x5_t howell;
|
||||
ibz_t pow2;
|
||||
ibz_mat_4x4_init(&full_ker);
|
||||
ibz_mat_4x5_init(&howell);
|
||||
ibz_init(&pow2);
|
||||
|
||||
// 2^exp
|
||||
ibz_set(&pow2, 1);
|
||||
ibz_mul_2exp(&pow2, &pow2, exp);
|
||||
|
||||
ibz_mat_right_ker_mod(4, 4, full_ker, *mat, &pow2);
|
||||
int zeros = ibz_mat_howell(4, 4, howell, NULL, full_ker, &pow2);
|
||||
|
||||
int dim = 0;
|
||||
for (int j = zeros; j < 5; j++) {
|
||||
int primitive = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
primitive |= !ibz_is_even(&howell[i][j]);
|
||||
if (primitive) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
ibz_copy(&(*ker)[i], &howell[i][j]);
|
||||
dim++;
|
||||
}
|
||||
}
|
||||
|
||||
ibz_mat_4x4_finalize(&full_ker);
|
||||
ibz_mat_4x5_finalize(&howell);
|
||||
ibz_finalize(&pow2);
|
||||
|
||||
return dim == 1;
|
||||
}
|
||||
|
||||
// matrix evaluation
|
||||
|
||||
void ibz_mat_4x4_eval(quat_alg_coord_t *res, const ibz_mat_4x4_t *mat, const quat_alg_coord_t *vec){
|
||||
quat_alg_coord_t sum;
|
||||
ibz_t prod;
|
||||
ibz_init(&prod);
|
||||
quat_alg_coord_init(&sum);
|
||||
for (int i = 0; i <4; i++){
|
||||
ibz_set(&(sum[i]),0);
|
||||
}
|
||||
for (int i = 0; i <4; i++){
|
||||
for (int j = 0; j <4; j++){
|
||||
ibz_mul(&prod, &(*mat)[i][j], &(*vec)[j]);
|
||||
ibz_add(&(sum[i]),&(sum[i]), &prod);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i <4; i++){
|
||||
ibz_copy(&(*res)[i],&(sum[i]));
|
||||
}
|
||||
ibz_finalize(&prod);
|
||||
quat_alg_coord_finalize(&sum);
|
||||
}
|
||||
|
||||
// quadratic forms
|
||||
|
||||
void quat_qf_eval(ibz_t *res, const ibz_mat_4x4_t *qf, const quat_alg_coord_t *coord){
|
||||
quat_alg_coord_t sum;
|
||||
ibz_t prod;
|
||||
ibz_init(&prod);
|
||||
quat_alg_coord_init(&sum);
|
||||
ibz_mat_4x4_eval(&sum, qf, coord);
|
||||
for (int i = 0; i <4; i++){
|
||||
ibz_mul(&prod,&(sum[i]), &(*coord)[i]);
|
||||
if (i>0){
|
||||
ibz_add(&(sum[0]),&(sum[0]), &prod);
|
||||
} else {
|
||||
ibz_copy(&sum[0],&prod);
|
||||
}
|
||||
}
|
||||
ibz_copy(res,&sum[0]);
|
||||
ibz_finalize(&prod);
|
||||
quat_alg_coord_finalize(&sum);
|
||||
}
|
||||
|
||||
|
||||
//Defined in headerfile
|
||||
//static void ibz_content(ibz_t *content, const quat_alg_coord_t *v) {
|
||||
// ibz_gcd(content, v[0], v[1]);
|
||||
// ibz_gcd(content, v[2], content);
|
||||
// ibz_gcd(content, v[3], content);
|
||||
//}
|
||||
158
src/quaternion/ref/generic/finit.c
Normal file
158
src/quaternion/ref/generic/finit.c
Normal file
@@ -0,0 +1,158 @@
|
||||
#include <quaternion.h>
|
||||
|
||||
|
||||
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){
|
||||
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);
|
||||
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);
|
||||
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 quat_alg_coord_finalize(quat_alg_coord_t *coord){
|
||||
for(int i = 0; i < 4; i++){
|
||||
ibz_finalize(&(*coord)[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++){
|
||||
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++){
|
||||
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++){
|
||||
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++){
|
||||
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){
|
||||
ibz_mat_4x4_init(&(*lat).basis);
|
||||
ibz_init(&(*lat).denom);
|
||||
ibz_set(&(*lat).denom, 1);
|
||||
}
|
||||
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){
|
||||
quat_lattice_init(&(*lideal).lattice);
|
||||
ibz_init(&(*lideal).norm);
|
||||
(*lideal).parent_order=NULL;
|
||||
}
|
||||
void quat_left_ideal_finalize(quat_left_ideal_t *lideal){
|
||||
ibz_finalize(&(*lideal).norm);
|
||||
quat_lattice_finalize(&(*lideal).lattice);
|
||||
}
|
||||
371
src/quaternion/ref/generic/ideal.c
Normal file
371
src/quaternion/ref/generic/ideal.c
Normal file
@@ -0,0 +1,371 @@
|
||||
#include <quaternion.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
|
||||
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;
|
||||
ibz_vec_4_t vec;
|
||||
ibz_vec_4_init(&vec);
|
||||
ibq_init(&norm);
|
||||
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 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++){
|
||||
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)
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fin:;
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&q);
|
||||
ibq_finalize(&norm);
|
||||
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);
|
||||
}
|
||||
|
||||
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];
|
||||
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_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);
|
||||
}
|
||||
}
|
||||
876
src/quaternion/ref/generic/include/quaternion.h
Normal file
876
src/quaternion/ref/generic/include/quaternion.h
Normal file
@@ -0,0 +1,876 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Luca De Feo, Sina Schaeffler
|
||||
*
|
||||
* @brief Declarations for quaternion algebra operations
|
||||
*/
|
||||
|
||||
#ifndef QUATERNION_H
|
||||
#define QUATERNION_H
|
||||
|
||||
//#include <rng.h>
|
||||
#include <intbig.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
#define QUATERNION_lideal_generator_search_bound 1024
|
||||
|
||||
/** @defgroup quat_quat Quaternion algebra
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup quat_vec_t Types for integer vectors and matrices
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Type for vectors of 4 integers
|
||||
*
|
||||
* @typedef ibz_vec_4_t
|
||||
*
|
||||
* Represented as a vector of 4 ibz_t (big integer) elements
|
||||
*/
|
||||
typedef ibz_t ibz_vec_4_t[4];
|
||||
|
||||
/** @brief Type for vectors of 5 integers
|
||||
*
|
||||
* @typedef ibz_vec_5_t
|
||||
*
|
||||
* Represented as a vector of 5 ibz_t (big integer) elements
|
||||
*/
|
||||
typedef ibz_t ibz_vec_5_t[5];
|
||||
|
||||
/** @brief Type for 2 by 2 matrices of integers
|
||||
*
|
||||
* @typedef ibz_mat_2x2_t
|
||||
*
|
||||
* Represented as a matrix of 2 vectors of 2 ibz_t (big integer) elements
|
||||
*/
|
||||
typedef ibz_t ibz_mat_2x2_t[2][2];
|
||||
|
||||
/** @brief Type for 4 by 4 matrices of integers
|
||||
*
|
||||
* @typedef ibz_mat_4x4_t
|
||||
*
|
||||
* Represented as a matrix of 4 vectors of 4 ibz_t (big integer) elements
|
||||
*/
|
||||
typedef ibz_t ibz_mat_4x4_t[4][4];
|
||||
|
||||
/** @brief Type for 4 by 5 matrices of integers
|
||||
*
|
||||
* @typedef ibz_mat_4x5_t
|
||||
*
|
||||
* Represented as a matrix of 4 vectors of 5 ibz_t (big integer) elements
|
||||
*/
|
||||
typedef ibz_t ibz_mat_4x5_t[4][5];
|
||||
|
||||
/** @brief Type for 4 by 8 matrices of integers
|
||||
*
|
||||
* @typedef ibz_mat_4x8_t
|
||||
*
|
||||
* Consists in and 4 by 8 matrix of ibz_t (big integers)
|
||||
*/
|
||||
typedef ibz_t ibz_mat_4x8_t[4][8];
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup quat_quat_t Types for quaternion algebras
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Type for quaternion algebras
|
||||
*
|
||||
* @typedef quat_alg_t
|
||||
*
|
||||
* @struct quat_alg
|
||||
*
|
||||
* The quaternion algebra ramified at p = 3 mod 4 and ∞.
|
||||
*/
|
||||
typedef struct quat_alg {
|
||||
ibz_t p; ///< Prime number, must be = 3 mod 4.
|
||||
ibz_mat_4x4_t gram; ///< Gram matrix of the norm form
|
||||
} quat_alg_t;
|
||||
|
||||
/** @brief Type for integer coordinates in a basis
|
||||
*
|
||||
* @typedef quat_alg_coord_t
|
||||
*
|
||||
* Represented as a vector of 4 ibz_t (big integer) elements
|
||||
*/
|
||||
typedef ibz_vec_4_t quat_alg_coord_t;
|
||||
|
||||
/** @brief Type for quaternion algebra elements
|
||||
*
|
||||
* @typedef quat_alg_elem_t
|
||||
*
|
||||
* @struct quat_alg_elem
|
||||
*
|
||||
* Represented as a array *coord* of 4 ibz_t integers and a common ibz_t denominator *denom*.
|
||||
*
|
||||
* The representation is not necessarily normalized, that is, gcd(denom, content(coord)) might not be 1.
|
||||
* For getting a normalized representation, use the quat_alg_normalize function
|
||||
*
|
||||
* The elements are always represented in basis (1,i,j,ij) of the quaternion algebra, with i^2=-1 and j^2 = -p
|
||||
*/
|
||||
typedef struct quat_alg_elem {
|
||||
ibz_t denom; ///< Denominator by which all coordinates are divided (big integer, must not be 0)
|
||||
quat_alg_coord_t coord; ///< Numerators of the 4 coordinates of the quaternion algebra element in basis (1,i,j,ij)
|
||||
} quat_alg_elem_t;
|
||||
|
||||
/** @brief Type for lattices in dimension 4
|
||||
*
|
||||
* @typedef quat_lattice_t
|
||||
*
|
||||
* @struct quat_lattice
|
||||
*
|
||||
* Represented as a rational (`frac`) times an integreal lattice (`basis`)
|
||||
*
|
||||
* The basis is in hermite normal form, and its columns divided by its denominator are elements of the quaternion algebra, represented in basis (1,i,j,ij) where i^2 = -1, j^2 = -p.
|
||||
*
|
||||
* All lattices must have full rank (4)
|
||||
*/
|
||||
typedef struct quat_lattice {
|
||||
ibz_t denom; ///< Denominator by which the basis is divided (big integer, must not be 0)
|
||||
ibz_mat_4x4_t basis; ///< Integer basis of the lattice in hermite normal form (its columns divided by denom are algebra elements in the usual basis)
|
||||
} quat_lattice_t;
|
||||
|
||||
/** @brief Type for quaternion orders
|
||||
*
|
||||
* @typedef quat_order_t
|
||||
*
|
||||
* Internally represented as a quat_lattice_t.
|
||||
*
|
||||
* That means that the basis is in hermite normal form, and its columns divided by its denominator are elements of the quaternion algebra, represented in basis (1,i,j,ij) where i^2 = -1, j^2 = -p.
|
||||
*/
|
||||
typedef quat_lattice_t quat_order_t;
|
||||
|
||||
/** @brief Type for left ideals in quaternion algebras
|
||||
*
|
||||
* @typedef quat_left_ideal_t
|
||||
*
|
||||
* @struct quat_left_ideal
|
||||
*
|
||||
* The basis of the lattice representing it is in hermite normal form, and its columns divided by its denominator are elements of the quaternion algebra, represented in basis (1,i,j,ij) where i^2 = -1, j^2 = -p.
|
||||
*/
|
||||
typedef struct quat_left_ideal {
|
||||
quat_lattice_t lattice; ///< lattice representing the ideal
|
||||
ibz_t norm; ///< norm of the lattice
|
||||
const quat_order_t* parent_order; ///< should be a maximal ideal
|
||||
} quat_left_ideal_t;
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @brief Type for extremal maximal orders
|
||||
*
|
||||
* @typedef quat_p_extremal_maximal_order_t
|
||||
*
|
||||
* @struct quat_p_extremal_maximal_order
|
||||
*
|
||||
* The basis of the order representing it is in hermite normal form, and its columns divid
|
||||
ed by its denominator are elements of the quaternion algebra, represented in basis (1,i,j,
|
||||
ij) where i^2 = -q, j^2 = -p.
|
||||
*/
|
||||
typedef struct quat_p_extremal_maximal_order {
|
||||
quat_order_t order; ///< the order represented as a lattice
|
||||
quat_alg_elem_t i; ///< the element of small discriminant
|
||||
quat_alg_elem_t j; ///< the element of norm p orthogonal to i
|
||||
int64_t q; ///< the absolute value of sqrt of i
|
||||
} quat_p_extremal_maximal_order_t;
|
||||
|
||||
/*************************** Functions *****************************/
|
||||
|
||||
|
||||
/** @defgroup quat_c Constructors and Destructors
|
||||
* @{
|
||||
*/
|
||||
void quat_alg_init_set(quat_alg_t *alg, const ibz_t *p);
|
||||
void quat_alg_finalize(quat_alg_t *alg);
|
||||
|
||||
void quat_alg_elem_init(quat_alg_elem_t *elem);
|
||||
void quat_alg_elem_finalize(quat_alg_elem_t *elem);
|
||||
|
||||
void quat_alg_coord_init(quat_alg_coord_t *coord);
|
||||
void quat_alg_coord_finalize(quat_alg_coord_t *coord);
|
||||
|
||||
void ibz_vec_4_init(ibz_vec_4_t *vec);
|
||||
void ibz_vec_4_finalize(ibz_vec_4_t *vec);
|
||||
|
||||
void ibz_vec_5_init(ibz_vec_5_t *vec);
|
||||
void ibz_vec_5_finalize(ibz_vec_5_t *vec);
|
||||
|
||||
void ibz_mat_2x2_init(ibz_mat_2x2_t *mat);
|
||||
void ibz_mat_2x2_finalize(ibz_mat_2x2_t *mat);
|
||||
|
||||
void ibz_mat_4x4_init(ibz_mat_4x4_t *mat);
|
||||
void ibz_mat_4x4_finalize(ibz_mat_4x4_t *mat);
|
||||
|
||||
void ibz_mat_4x5_init(ibz_mat_4x5_t *mat);
|
||||
void ibz_mat_4x5_finalize(ibz_mat_4x5_t *mat);
|
||||
|
||||
void ibz_mat_4x8_init(ibz_mat_4x8_t *mat);
|
||||
void ibz_mat_4x8_finalize(ibz_mat_4x8_t *mat);
|
||||
|
||||
/** @brief initiazlize matrix with arbitrary dimensions
|
||||
*/
|
||||
void ibz_mat_init(int rows, int cols, ibz_t mat[rows][cols]);
|
||||
/** @brief finalize matrix with arbitrary dimensions
|
||||
*/
|
||||
void ibz_mat_finalize(int rows, int cols, ibz_t mat[rows][cols]);
|
||||
|
||||
void quat_lattice_init(quat_lattice_t *lat);
|
||||
void quat_lattice_finalize(quat_lattice_t *lat);
|
||||
|
||||
void quat_order_init(quat_order_t *order);
|
||||
void quat_order_finalize(quat_order_t *order);
|
||||
|
||||
void quat_left_ideal_init(quat_left_ideal_t *lideal);
|
||||
void quat_left_ideal_finalize(quat_left_ideal_t *lideal);
|
||||
/** @}
|
||||
*/
|
||||
|
||||
|
||||
/** @defgroup quat_printers Print functions for types from the quaternion module
|
||||
* @{
|
||||
*/
|
||||
void ibz_mat_2x2_print(const ibz_mat_2x2_t *mat);
|
||||
void ibz_mat_4x4_print(const ibz_mat_4x4_t *mat);
|
||||
void ibz_mat_4x5_print(const ibz_mat_4x5_t *mat);
|
||||
void ibz_mat_4x8_print(const ibz_mat_4x8_t *mat);
|
||||
void ibz_mat_print(int rows, int cols, const ibz_t mat[rows][cols]);
|
||||
void ibz_vec_2_print(const ibz_vec_2_t *vec);
|
||||
void ibz_vec_4_print(const ibz_vec_4_t *vec);
|
||||
void ibz_vec_5_print(const ibz_vec_5_t *vec);
|
||||
|
||||
|
||||
void quat_lattice_print(const quat_lattice_t *lat);
|
||||
void quat_alg_print(const quat_alg_t *alg);
|
||||
void quat_alg_elem_print(const quat_alg_elem_t *elem);
|
||||
void quat_alg_coord_print(const quat_alg_coord_t *coord);
|
||||
void quat_order_print(const quat_order_t *order);
|
||||
void quat_left_ideal_print(const quat_left_ideal_t *lideal);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @defgroup quat_int Integer functions for quaternion algebra
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup quat_int_mat Integer matrix and vector functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief mat*vec in dimension 2 for integers
|
||||
*
|
||||
* @param res Output vector
|
||||
* @param mat Input vector
|
||||
* @param vec Input vector
|
||||
*/
|
||||
void ibz_mat_2x2_eval(ibz_vec_2_t *res, const ibz_mat_2x2_t *mat, const ibz_vec_2_t *vec);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Inverse of 2x2 integer matrices modulo m
|
||||
*
|
||||
* @param inv Output matrix
|
||||
* @param mat Input matrix
|
||||
* @param m Integer modulo
|
||||
* @return 1 if inverse exists 0 otherwise
|
||||
*/
|
||||
int ibz_2x2_inv_mod(ibz_mat_2x2_t *inv, const ibz_mat_2x2_t *mat, const ibz_t *m);
|
||||
|
||||
/**
|
||||
* @brief mat*vec
|
||||
*
|
||||
*
|
||||
* @param res Output: coordinate vector
|
||||
* @param mat Integer 4x4 matrix
|
||||
* @param vec Integer vector (coordinate vector)
|
||||
*
|
||||
* Multiplies 4x4 integer matrix mat by a 4-integers vector vec
|
||||
*/
|
||||
void ibz_mat_4x4_eval(ibz_vec_4_t *res, const ibz_mat_4x4_t *mat, const ibz_vec_4_t *vec);
|
||||
|
||||
/**
|
||||
* @brief Computes modulo p the left kernel of mat where p is prime
|
||||
*
|
||||
* Algorithm used is the one at number 2.3.1 in Henri Cohen's "A Course in Computational Algebraic Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993
|
||||
*
|
||||
* @param ker Output: a vector in kernel which is not 0 modulo p if exists, otherwise 0
|
||||
* @param mat A 4×5 matrix
|
||||
* @param p Integer modulo which the kernel computation is done, must be prime
|
||||
* @return 1 if a unique such vector was found, 0 otherwise
|
||||
*
|
||||
*/
|
||||
int ibz_4x5_right_ker_mod_prime(ibz_vec_5_t *ker, const ibz_mat_4x5_t *mat, const ibz_t *p);
|
||||
|
||||
/**
|
||||
* @brief Computes modulo p the left kernel of mat where p is prime
|
||||
*
|
||||
* Algorithm used is the one at number 2.3.1 in Henri Cohen's "A Course in Computational Algebraic Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993
|
||||
*
|
||||
* @param ker Output: a vector in kernel which is not 0 modulo p if exists, otherwise 0
|
||||
* @param mat A 4×4 matrix
|
||||
* @param p Integer modulo which the kernel computation is done, must be prime
|
||||
* @return 1 if a unique such vector was found, 0 otherwise
|
||||
*
|
||||
*/
|
||||
int ibz_4x4_right_ker_mod_prime(ibz_vec_4_t *ker, const ibz_mat_4x4_t *mat, const ibz_t *p);
|
||||
|
||||
/**
|
||||
* @brief Computes the right kernel of mat modulo 2^exp
|
||||
*
|
||||
* @param ker Output: a vector in kernel which is not 0 modulo 2, if it exists, otherwise 0
|
||||
* @param mat A 4×4 matrix
|
||||
* @param exp exponent defining the modulus
|
||||
* @return 1 if a unique such vector was found, 0 otherwise
|
||||
*
|
||||
*/
|
||||
int ibz_4x4_right_ker_mod_power_of_2(ibz_vec_4_t *ker, const ibz_mat_4x4_t *mat, unsigned short exp);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
static inline void ibz_content(ibz_t *content, const ibz_vec_4_t *v) {
|
||||
ibz_gcd(content, &((*v)[0]), &((*v)[1]));
|
||||
ibz_gcd(content, &((*v)[2]), content);
|
||||
ibz_gcd(content, &((*v)[3]), content);
|
||||
}
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
|
||||
/** @defgroup quat_integer Integer functions for quaternion algebra
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Find integers x and y such that x^2 + n*y^2 = p
|
||||
*
|
||||
* Uses Cornacchia's algorithm, should be used only for prime p
|
||||
*
|
||||
* @param x Output
|
||||
* @param y Output
|
||||
* @param n first parameter defining the equation
|
||||
* @param p seond parameter defining the equation, must be prime
|
||||
* @return 1 if success, 0 otherwise
|
||||
*/
|
||||
int ibz_cornacchia_prime(ibz_t *x, ibz_t *y, const ibz_t *n , const ibz_t *p);
|
||||
|
||||
/**
|
||||
* @brief Solving cornacchia to find x² + n y³ = 2^exp_adjust * p in the special case of n=3 mod 4
|
||||
*
|
||||
* This function sometimes fails to find a solution even if one exists and all parameters are as specified.
|
||||
*
|
||||
* @param x Output: an integer
|
||||
* @param y Output: an integer
|
||||
* @param n an integer
|
||||
* @param p a prime integer
|
||||
* @param exp_adjust an exponent, must be > 0
|
||||
* @returns 1 if success, 0 if failure to find a solution
|
||||
*/
|
||||
int ibz_cornacchia_special_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p, const int exp_adjust);
|
||||
|
||||
/**
|
||||
* @brief Find x and y such that x^2 + y^2 = n
|
||||
*
|
||||
* Uses "extended" version of Cornacchia's algorithm which also allows to solve x^2 + y^2 = n for some composite numbers.
|
||||
* This uses a prime factor decomposition of n via trial division for primes in the list, computes solutions for n's prime factors
|
||||
* and then uses complex multiplication. Since (x+iz)(x-iy) = x^2 + y^2,
|
||||
* so a solution xp,yp for p and xq,yq for q give a solution for pq by computing (xp+iyp)*(xq+iyq).
|
||||
*
|
||||
* @param x Output
|
||||
* @param y Output
|
||||
* @param n parameter defining the equation. To get an output if one exists, only 1 of its prime factors can exceed the largest prime in prime_list
|
||||
* @param prime_list list of consecutive primes starting from 2
|
||||
* @param prime_list_length number of elements of prime_list. Cans be smaller than that number, in which case only the beginning of the list is used.
|
||||
* @param primality_test_iterations number of Miller-Rabin iterations to verify primality before trying to compute a square root of 1 modulo the remaining number once all small primes were factored out
|
||||
* @param bad_primes_prod Assumed to be a product of small primes which are 3 mod 4. Used only to accelerate failure in case its gcd with n is not 1. Can be NULL
|
||||
* @return 1 if success, 0 otherwise
|
||||
*/
|
||||
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);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
|
||||
/** @defgroup quat_qf Quadratic form functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Quadratic form evaluation
|
||||
*
|
||||
* qf and coord must be represented in the same basis.
|
||||
*
|
||||
* @param res Output: coordinate vector
|
||||
* @param qf Quadratic form (4x4 integer matrix)
|
||||
* @param coord Integer vector (coordinate vector)
|
||||
*/
|
||||
void quat_qf_eval(ibz_t *res, const ibz_mat_4x4_t *qf, const quat_alg_coord_t *coord);
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @defgroup quat_lat_2x2 Functions for lattices in dimension 2
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Find a lattice vector close to a target vector satisfying extra conditions.
|
||||
*
|
||||
* Given a target vector `target` = (x₀,y₀), enumerate vectors `v` = (x,y) in lattice `lat` with distance
|
||||
* (x₀ - x)² + `qf` (y₀ - y)² < 2^`dist_bound`. On each vector `condition(res, target - v, params)` is called: if it returns a
|
||||
* non-zero value, processing stops and the same value is returned; if it returns 0 processing continues
|
||||
* until `max_tries` vectors have been tried.
|
||||
*
|
||||
* The implementation will first reduce the basis by finding a short vector with algorithm 1.3.14 (Gauss) from Henri Cohen's "A Course in Computational Algebraic Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993.
|
||||
* Then a second one is added to this basis after reduction by projection on the first one.
|
||||
* A close vector is found using 2 projection as in https://cims.nyu.edu/~regev/teaching/lattices_fall_2004/ln/cvp.pdf (15.5.2023,16h15CEST) using the already reduced matrix
|
||||
* Finally, short vectors are enumerated below an enumeration bound set to (2 ^ dist_bound - (distance of target to close vector)).
|
||||
* Each short vector is added to the close vector, and then the distance to the target is measured. If it is below 2^dist_bound, it is tested for condition.
|
||||
* If coundition returns 1, the algorithm terminates and returns 1, otherwise it returns 0 when max_tries vectors have been tried
|
||||
*
|
||||
* The enumeration bound is an heuristic to avoid starting the search with vectors which will be too far from the target, since enumeration starts at the largest vectors.
|
||||
* It can in some cases lead to failures even though solutions do exist, an in other cases be insufficient to get a valid result in reasonable time.
|
||||
*
|
||||
* Enumeration 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
|
||||
*
|
||||
* @param res Output: quaternion element returned by `condition`
|
||||
* @param lat_basis basis of an integral 2-dimensional lattice
|
||||
* @param target target vector for CVP
|
||||
* @param qf Small integer defining a quadratic form x² + qf y²
|
||||
* @param dist_bound Log of the maximum distance between `target` and the enumerated vectors
|
||||
* @param condition Filter the vectors of `lat` by passing them to `condition`. When it returns a non-zero value, the result is put into `res` and the processing stops.
|
||||
* @param params Extra parameters passed to `condition`. May be NULL.
|
||||
* @param max_tries Try at most `max_tries` vectors close to `target`
|
||||
* @return 1 if an element was found, 0 otherwise
|
||||
*/
|
||||
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);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @defgroup quat_quat_f Quaternion algebra 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);
|
||||
|
||||
/** @brief reduced norm of alg_elem x
|
||||
*
|
||||
* @param res Output: rational which will contain the reduced norm of a
|
||||
* @param x Algebra element whose norm is computed
|
||||
* @param alg The quaternion algebra
|
||||
*/
|
||||
void quat_alg_norm(ibq_t *res, const quat_alg_elem_t *x, const quat_alg_t *alg);
|
||||
|
||||
/** @brief reduced trace of alg_elem x
|
||||
*
|
||||
* @param res Output: rational which will contain the reduced trace of a
|
||||
* @param x Algebra element whose trace will be computed
|
||||
*/
|
||||
void quat_alg_trace(ibq_t *res, const quat_alg_elem_t *x);
|
||||
|
||||
|
||||
/** @brief Normalize representation of alg_elem x
|
||||
*
|
||||
* @param x Algebra element whose representation will be normalized
|
||||
*
|
||||
* Modification of x.
|
||||
* Sets coord and denom of x so that gcd(denom, content(coord))=1
|
||||
* without changing the value of x = (coord0/denom, coord1/denom, coord2/denom, coord3/denom).
|
||||
*/
|
||||
void quat_alg_normalize(quat_alg_elem_t *x);
|
||||
|
||||
/** @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 Test if x is 0
|
||||
*
|
||||
* @returns 1 if x=0, 0 otherwise
|
||||
*
|
||||
* x is 0 iff all coordinates in x are 0
|
||||
*/
|
||||
int quat_alg_coord_is_zero(const quat_alg_coord_t *x);
|
||||
|
||||
|
||||
// end quat_quat_f
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @defgroup quat_lat_f Lattice 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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Test whether x ∈ lat. If so, compute its coordinates in lat's basis.
|
||||
*
|
||||
* @param coord Output: Set to the coordinates of x in lat. May be NULL.
|
||||
* @param lat The lattice
|
||||
* @param x An element of the quaternion algebra
|
||||
* @param alg The quaternion algebra
|
||||
* @return true if x ∈ lat
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
/********************************* Functions from ideal.c ************************************/
|
||||
|
||||
/** @addtogroup quat_quat_f
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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 Standard involution in a quaternion algebra
|
||||
*
|
||||
* @param conj Output: image of x by standard involution of the quaternion algebra alg
|
||||
* @param x element of alg whose image is searched
|
||||
*/
|
||||
void quat_alg_conj(quat_alg_elem_t *conj, const quat_alg_elem_t *x);
|
||||
|
||||
/**
|
||||
* @brief Given `x` ∈ `order`, factor it into its primitive and impritive parts
|
||||
*
|
||||
* Given `x` ∈ `order`, return a coordinate vector `primitive_x` and an integer `content`
|
||||
* such that `x` = `content` · Λ `primitive_x`, where Λ is the basis of `order`
|
||||
* and `x` / `content` is primitive in `order`.
|
||||
*
|
||||
* @param primitive_x Output: coordinates of a primitive element of `order` (in `order`'s basis)
|
||||
* @param content Output: content of `x`'s coordinate vector in order's basis
|
||||
* @param alg the quaternion algebra
|
||||
* @param order order of `alg`
|
||||
* @param x element of order, must be in `order`
|
||||
*/
|
||||
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, alg);
|
||||
assert(ok);
|
||||
ibz_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_finalize(&r);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests if x ∈ order is primitive
|
||||
*
|
||||
* @param alg quaternion algebra
|
||||
* @param order quaternion order
|
||||
* @param x element of the order (fails if x ∉ order)
|
||||
*
|
||||
* @returns 1 if x is primitive, 0 otherwise
|
||||
*/
|
||||
static inline 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;
|
||||
ibz_t cnt;
|
||||
quat_alg_coord_init(&coord);
|
||||
ibz_init(&cnt);
|
||||
|
||||
quat_alg_make_primitive(&coord,&cnt,x,order,alg);
|
||||
int ok = ibz_is_one(&cnt);
|
||||
|
||||
ibz_finalize(&cnt);
|
||||
quat_alg_coord_finalize(&coord);
|
||||
return ok;
|
||||
}
|
||||
|
||||
//end quat_quat_f
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @defgroup quat_lideal_f Functions for left ideals
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup quat_lideal_c Creating left ideals
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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_order_t *order, const quat_alg_t *alg);
|
||||
|
||||
/**
|
||||
* @brief Left ideal of order, generated by primitive x and N
|
||||
*
|
||||
* @param lideal Output: left ideal
|
||||
* @param alg quaternion algebra
|
||||
* @param order maximal order of alg whose left ideal is searched
|
||||
* @param x generating element, must be a primitive element of order
|
||||
* @param N generating integer
|
||||
*
|
||||
* Creates the left ideal in order generated by the element x and the integer N
|
||||
*
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Make x primitive, remove content from N, then generate ideal
|
||||
*
|
||||
* @param lideal Output: left ideal
|
||||
* @param alg quaternion algebra
|
||||
* @param order maximal order of alg whose left ideal is searched
|
||||
* @param x generating element, a primitive element of order obtained from it will be used for generation
|
||||
* @param N generating integer
|
||||
*
|
||||
* Given `x` = n·y ∈ order` with `y` primitive, given an integer `N`, create the ideal
|
||||
* generated by `y` and `N / gcd(n, N)`.
|
||||
*
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Random left ideal of norm 2^e
|
||||
*
|
||||
* @param lideal Output: random left ideal (of parents alg and order) with norm 2^e
|
||||
* @param alg parent algebra for which an ideal is chosen. Is a quaterion algebra
|
||||
* @param order parent order for which an ideal is chosen. Must be maximal
|
||||
* @param e int64_t determining the norm of the resulting ideal
|
||||
* @param n Parameter controlling the amount of randomness used by the algorithm
|
||||
* @return 0 if PRNG failed, 1 otherwise.
|
||||
*/
|
||||
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);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @defgroup quat_lideal_gen Generators of left ideals
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Generator of 'lideal'
|
||||
*
|
||||
* @returns 1 if such a generator was found, 0 otherwise
|
||||
* @param gen Output: non scalar generator of lideal
|
||||
* @param lideal left ideal
|
||||
* @param alg the quaternion algebra
|
||||
* @param bound Bound used for enumeration of elements. Must be non-negative. If 0, a default value is used.
|
||||
*
|
||||
* Ideal is generated by gen and the ideal's norm
|
||||
*
|
||||
* Bound has as default value QUATERNION_lideal_generator_search_bound
|
||||
*/
|
||||
int quat_lideal_generator(quat_alg_elem_t *gen, const quat_left_ideal_t *lideal, const quat_alg_t *alg, int bound);
|
||||
|
||||
/**
|
||||
* @brief Primitive generator of a left ideal of norm coprime to a given integer
|
||||
*
|
||||
* @returns 1 if such a generator was found, 0 otherwise
|
||||
* @param gen Output: generator of lideal, coprime to n
|
||||
* @param lideal left ideal
|
||||
* @param n value to which the generator norm should be coprime. (assumes gcd(n, norm(lideal)) = 1). If this is not fulfilled, the returned element is a generator such that gcd(n^2,norm(gen)) = gcd(n,norm(lideal))
|
||||
* @param alg the quaternion algebra
|
||||
* @param bound Bound used for enumeration of elements. Must be non-negative. If 0, a default value 0 is used.
|
||||
*
|
||||
* Finds a primitive generator of 'lideal' of norm coprime with n (assumes gcd(n, norm(lideal)) = 1)
|
||||
*
|
||||
* gen is such that lideal is generated by gen and the ideal's norm
|
||||
*
|
||||
* Bound has as default value QUATERNION_lideal_generator_search_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);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @defgroup quat_lideal_op Operations on left ideals
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Left ideal product of left ideal I and element alpha
|
||||
*
|
||||
* @returns 1 if a product could be computed, 0 otherwise (in the later case, one might retry with a higher bound)
|
||||
* @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
|
||||
* @param bound used for internal ideal_generator search. Must be positive. Setting it to 0 uses the default value.
|
||||
*
|
||||
* I*alpha where I is a left-ideal and alpha an element of the algebra
|
||||
*
|
||||
* The resulting ideal must have an integer norm
|
||||
*
|
||||
* Bound has as default value QUATERNION_lideal_generator_search_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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Intersection of two left ideals
|
||||
*
|
||||
* @param intersection Output: Left ideal which is the intersection of the 2 inputs
|
||||
* @param lideal1 left ideal
|
||||
* @param lideal2 left ideal
|
||||
* @param alg the quaternion algebra
|
||||
*/
|
||||
void quat_lideal_inter(quat_left_ideal_t *intersection, const quat_left_ideal_t *lideal1, const quat_left_ideal_t *lideal2, const quat_alg_t *alg);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Element representing an isomorphism between I1 and I2
|
||||
*
|
||||
* @returns 1 if isomorphic, 0 otherwise
|
||||
* @param iso Output: algebra element such that I1*iso = I2.
|
||||
* @param lideal1 left ideal
|
||||
* @param lideal2 left ideal
|
||||
* @param alg the quaternion algebra
|
||||
*
|
||||
* If I1 and I2 are isomorphic, set `iso` to an element of `alg` such that I1*iso = I2,
|
||||
* and return 1. Otherwise return 0.
|
||||
*
|
||||
* I1 and I2 must have the same parent order (where "same" means they
|
||||
* point to the same object), in order to be considered isomorphic.
|
||||
*/
|
||||
int quat_lideal_isom(quat_alg_elem_t *iso, 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_order_t *order, const quat_left_ideal_t *lideal, const quat_alg_t *alg);
|
||||
|
||||
|
||||
/**
|
||||
* @brief LLL-reduce the basis of the left ideal, without considering its denominator
|
||||
*
|
||||
* This function reduce the basis of the lattice of the ideal, but it does completely ignore its denominator.
|
||||
* So the outputs of this function must still e divided by the appropriate power of lideal.lattice.denom.
|
||||
*
|
||||
* @param reduced Output: Lattice defining the ideal, which has its basis in a lll-reduced form. Must be divided by lideal.lattice.denom before usage
|
||||
* @param gram Output: gram matrix of the reduced basis. Must be divided by (lideal.lattice.denom)^2 before usage
|
||||
* @param lideal Ideal whose basis will be reduced
|
||||
* @param alg the quaternion algebra
|
||||
*/
|
||||
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
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
// end quat_lideal_f
|
||||
/** @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/***************************** Functions from quaternion_tools.c ***************************************/
|
||||
|
||||
/** @defgroup quat_order_op Operations on orders
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Connecting ideal of 2 orders in the same algebra
|
||||
*
|
||||
* @param connecting_ideal Output: ideal which is a right ideal of O1 and a left ideal of O2
|
||||
* @param alg quaternion algebra
|
||||
* @param order1 maximal order left of the searched ideal
|
||||
* @param order2 order right of the searched ideal
|
||||
*/
|
||||
void quat_connecting_ideal(quat_left_ideal_t *connecting_ideal, const quat_order_t *order1, const quat_order_t *order2, const quat_alg_t *alg);
|
||||
|
||||
/**
|
||||
* @brief LLL reduction on 4-dimensional lattice, coefficient is 0.99
|
||||
*
|
||||
* @param red Output: LLL reduced basis
|
||||
* @param lattice lattice with 4-dimensional basis
|
||||
* @param q parameter q for non-standard basis
|
||||
* @param precision floating-point precision for LLL algorithm, if 0 is provided a default precision is taken
|
||||
*/
|
||||
int quat_lattice_lll(ibz_mat_4x4_t *red, const quat_lattice_t *lattice, const ibz_t *q, int precision);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
// end quat_quat
|
||||
/** @}
|
||||
*/
|
||||
|
||||
#endif
|
||||
319
src/quaternion/ref/generic/integers.c
Normal file
319
src/quaternion/ref/generic/integers.c
Normal file
@@ -0,0 +1,319 @@
|
||||
#include <quaternion.h>
|
||||
#include "internal.h"
|
||||
#include <stdlib.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);
|
||||
|
||||
//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_add(q,q,&sign_q);
|
||||
}
|
||||
ibz_finalize(&r);
|
||||
ibz_finalize(&sign_q);
|
||||
ibz_finalize(&abs_b);
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
ibz_init(&r0);
|
||||
ibz_init(&r1);
|
||||
ibz_init(&r2);
|
||||
ibz_init(&a);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&two);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
740
src/quaternion/ref/generic/internal.h
Normal file
740
src/quaternion/ref/generic/internal.h
Normal file
@@ -0,0 +1,740 @@
|
||||
/** @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
|
||||
469
src/quaternion/ref/generic/lattice.c
Normal file
469
src/quaternion/ref/generic/lattice.c
Normal file
@@ -0,0 +1,469 @@
|
||||
#include <quaternion.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
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_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){
|
||||
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);
|
||||
// dual_denom = det/lat_denom
|
||||
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;
|
||||
ibz_mat_4x4_t tmp;
|
||||
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,&(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_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_finalize(&tmp);
|
||||
}
|
||||
|
||||
// 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_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)
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_mul(index, index, &sublat->basis[i][i]);
|
||||
}
|
||||
// tmp = (sublat->denom)⁴
|
||||
ibz_mul(&tmp, &sublat->denom, &sublat->denom);
|
||||
ibz_mul(&tmp, &tmp, &tmp);
|
||||
// tmp = (sublat->denom)⁴ · det(overlat->basis)
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ibz_mul(&tmp, &tmp, &overlat->basis[i][i]);
|
||||
}
|
||||
// index = index / tmp
|
||||
ibz_div(index, &tmp, index, &tmp);
|
||||
assert(ibz_is_zero(&tmp));
|
||||
// index = |index|
|
||||
ibz_abs(index, index);
|
||||
|
||||
ibz_finalize(&tmp);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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_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);
|
||||
}
|
||||
366
src/quaternion/ref/generic/lll.c
Normal file
366
src/quaternion/ref/generic/lll.c
Normal file
@@ -0,0 +1,366 @@
|
||||
#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;
|
||||
}
|
||||
421
src/quaternion/ref/generic/matkermod.c
Normal file
421
src/quaternion/ref/generic/matkermod.c
Normal file
@@ -0,0 +1,421 @@
|
||||
#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);
|
||||
}
|
||||
158
src/quaternion/ref/generic/printer.c
Normal file
158
src/quaternion/ref/generic/printer.c
Normal file
@@ -0,0 +1,158 @@
|
||||
#include <quaternion.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]));
|
||||
}
|
||||
ibz_printf("\n ");
|
||||
}
|
||||
ibz_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]));
|
||||
}
|
||||
ibz_printf("\n ");
|
||||
}
|
||||
ibz_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]));
|
||||
}
|
||||
ibz_printf("\n ");
|
||||
}
|
||||
ibz_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]));
|
||||
}
|
||||
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]);
|
||||
}
|
||||
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]));
|
||||
}
|
||||
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 ");
|
||||
}
|
||||
} else {
|
||||
ibz_printf("Parent order not given!\n");
|
||||
}
|
||||
ibz_printf("\n");
|
||||
}
|
||||
21
src/quaternion/ref/generic/test/CMakeLists.txt
Normal file
21
src/quaternion/ref/generic/test/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
set(SOURCE_FILES_QUATERNION_GENERIC_REF_TESTS
|
||||
algebra.c
|
||||
ideal.c
|
||||
dim4.c
|
||||
dim2.c
|
||||
integers.c
|
||||
lattice.c
|
||||
finit.c
|
||||
matkermod.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} )
|
||||
|
||||
# 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()
|
||||
1292
src/quaternion/ref/generic/test/algebra.c
Normal file
1292
src/quaternion/ref/generic/test/algebra.c
Normal file
File diff suppressed because it is too large
Load Diff
1187
src/quaternion/ref/generic/test/dim2.c
Normal file
1187
src/quaternion/ref/generic/test/dim2.c
Normal file
File diff suppressed because it is too large
Load Diff
1859
src/quaternion/ref/generic/test/dim4.c
Normal file
1859
src/quaternion/ref/generic/test/dim4.c
Normal file
File diff suppressed because it is too large
Load Diff
299
src/quaternion/ref/generic/test/finit.c
Normal file
299
src/quaternion/ref/generic/test/finit.c
Normal file
@@ -0,0 +1,299 @@
|
||||
#include "quaternion_tests.h"
|
||||
|
||||
// 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(){
|
||||
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);
|
||||
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){
|
||||
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(){
|
||||
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])));
|
||||
}
|
||||
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;
|
||||
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])));
|
||||
}
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test finit_alg_coord failed\n");
|
||||
}
|
||||
quat_alg_coord_finalize(&coord);
|
||||
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(){
|
||||
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++){
|
||||
res = res || (i!=ibz_get(&(vec[i])));
|
||||
}
|
||||
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(){
|
||||
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++){
|
||||
res = res || (i+j!=ibz_get(&(mat[i][j])));
|
||||
}
|
||||
}
|
||||
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(){
|
||||
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++){
|
||||
res = res || (i+j!=ibz_get(&(mat[i][j])));
|
||||
}
|
||||
}
|
||||
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(){
|
||||
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);
|
||||
}
|
||||
}
|
||||
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])));
|
||||
}
|
||||
}
|
||||
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(){
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 = res || (5!=ibz_get(&(lideal.norm)));
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test finit_alg_lideal failed\n");
|
||||
}
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
return res;
|
||||
}
|
||||
|
||||
// run all previous tests
|
||||
int quat_test_finit(){
|
||||
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_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);
|
||||
}
|
||||
|
||||
967
src/quaternion/ref/generic/test/ideal.c
Normal file
967
src/quaternion/ref/generic/test/ideal.c
Normal file
@@ -0,0 +1,967 @@
|
||||
#include "quaternion_tests.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);
|
||||
int quat_test_lideal_create_principal(){
|
||||
int res = 0;
|
||||
|
||||
// Example from https://github.com/SQISign/sqisign-nist/issues/38#issuecomment-1554585079
|
||||
quat_alg_t alg;
|
||||
quat_order_t lat;
|
||||
quat_alg_elem_t gamma;
|
||||
quat_left_ideal_t I;
|
||||
quat_alg_init_set_ui(&alg, 367);
|
||||
quat_order_init(&lat);
|
||||
quat_alg_elem_init(&gamma);
|
||||
quat_left_ideal_init(&I);
|
||||
ibz_set(&lat.denom, 2);
|
||||
ibz_set(&lat.basis[0][0], 2);
|
||||
ibz_set(&lat.basis[1][1], 2);
|
||||
ibz_set(&lat.basis[1][2], 1);
|
||||
ibz_set(&lat.basis[2][2], 1);
|
||||
ibz_set(&lat.basis[3][3], 1);
|
||||
ibz_set(&lat.basis[0][3], 1);
|
||||
ibz_set(&gamma.coord[0], 219);
|
||||
ibz_set(&gamma.coord[1], 200);
|
||||
ibz_set(&gamma.coord[2], 78);
|
||||
ibz_set(&gamma.coord[3], -1);
|
||||
|
||||
quat_lideal_create_principal(&I, &gamma, &lat, &alg);
|
||||
|
||||
res |= I.parent_order != ⪫
|
||||
res |= ibz_cmp_si(&I.norm, 2321156);
|
||||
res |= ibz_cmp(&I.lattice.denom, &ibz_const_one);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][0], 1160578);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][0], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][0], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][0], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][1], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][1], 1160578);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][1], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][1], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][2], 310126);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][2], 182529);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][2], 1);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][2], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][3], 978049);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][3], 310126);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][3], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][3], 1);
|
||||
|
||||
// same test, just with gamma not reduced
|
||||
ibz_set(&gamma.coord[0], 438);
|
||||
ibz_set(&gamma.coord[1], 400);
|
||||
ibz_set(&gamma.coord[2], 156);
|
||||
ibz_set(&gamma.coord[3], -2);
|
||||
ibz_set(&gamma.denom, 2);
|
||||
|
||||
quat_lideal_create_principal(&I, &gamma, &lat, &alg);
|
||||
|
||||
res |= I.parent_order != ⪫
|
||||
res |= ibz_cmp_si(&I.norm, 2321156);
|
||||
res |= ibz_cmp(&I.lattice.denom, &ibz_const_one);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][0], 1160578);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][0], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][0], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][0], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][1], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][1], 1160578);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][1], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][1], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][2], 310126);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][2], 182529);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][2], 1);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][2], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][3], 978049);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][3], 310126);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][3], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][3], 1);
|
||||
|
||||
// same test, just with gamma and basis not reduced
|
||||
ibz_set(&lat.denom, 6);
|
||||
ibz_set(&lat.basis[0][0], 6);
|
||||
ibz_set(&lat.basis[1][1], 6);
|
||||
ibz_set(&lat.basis[1][2], 3);
|
||||
ibz_set(&lat.basis[2][2], 3);
|
||||
ibz_set(&lat.basis[3][3], 3);
|
||||
ibz_set(&lat.basis[0][3], 3);
|
||||
ibz_set(&gamma.coord[0], 438);
|
||||
ibz_set(&gamma.coord[1], 400);
|
||||
ibz_set(&gamma.coord[2], 156);
|
||||
ibz_set(&gamma.coord[3], -2);
|
||||
ibz_set(&gamma.denom, 2);
|
||||
|
||||
quat_lideal_create_principal(&I, &gamma, &lat, &alg);
|
||||
|
||||
res |= I.parent_order != ⪫
|
||||
res |= ibz_cmp_si(&I.norm, 2321156);
|
||||
res |= ibz_cmp(&I.lattice.denom, &ibz_const_one);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][0], 1160578);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][0], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][0], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][0], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][1], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][1], 1160578);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][1], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][1], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][2], 310126);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][2], 182529);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][2], 1);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][2], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][3], 978049);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][3], 310126);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][3], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][3], 1);
|
||||
|
||||
|
||||
quat_alg_finalize(&alg);
|
||||
quat_order_finalize(&lat);
|
||||
quat_alg_elem_finalize(&gamma);
|
||||
quat_left_ideal_finalize(&I);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_create_principal failed\n");
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
//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);
|
||||
int quat_test_lideal_create_from_primitive(){
|
||||
int res = 0;
|
||||
|
||||
// Example from https://github.com/SQISign/sqisign-nist/issues/38#issuecomment-1554585079
|
||||
quat_alg_t alg;
|
||||
quat_order_t lat;
|
||||
quat_alg_elem_t gamma;
|
||||
ibz_t N;
|
||||
quat_left_ideal_t I;
|
||||
quat_alg_init_set_ui(&alg, 367);
|
||||
quat_order_init(&lat);
|
||||
quat_alg_elem_init(&gamma);
|
||||
ibz_init(&N);
|
||||
quat_left_ideal_init(&I);
|
||||
ibz_set(&lat.denom, 2);
|
||||
ibz_set(&lat.basis[0][0], 2);
|
||||
ibz_set(&lat.basis[1][1], 2);
|
||||
ibz_set(&lat.basis[1][2], 1);
|
||||
ibz_set(&lat.basis[2][2], 1);
|
||||
ibz_set(&lat.basis[3][3], 1);
|
||||
ibz_set(&lat.basis[0][3], 1);
|
||||
ibz_set(&gamma.coord[0], 219);
|
||||
ibz_set(&gamma.coord[1], 200);
|
||||
ibz_set(&gamma.coord[2], 78);
|
||||
ibz_set(&gamma.coord[3], -1);
|
||||
ibz_set(&N, 31);
|
||||
|
||||
quat_lideal_create_from_primitive(&I, &gamma, &N, &lat, &alg);
|
||||
|
||||
res |= I.parent_order != ⪫
|
||||
res |= ibz_cmp(&I.norm, &N);
|
||||
res |= ibz_cmp(&I.lattice.denom, &ibz_const_two);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][0], 62);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][0], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][0], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][0], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][1], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][1], 62);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][1], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][1], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][2], 2);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][2], 1);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][2], 1);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][2], 0);
|
||||
|
||||
res |= ibz_cmp_si(&I.lattice.basis[0][3], 61);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[1][3], 2);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[2][3], 0);
|
||||
res |= ibz_cmp_si(&I.lattice.basis[3][3], 1);
|
||||
|
||||
quat_alg_finalize(&alg);
|
||||
quat_order_finalize(&lat);
|
||||
quat_alg_elem_finalize(&gamma);
|
||||
ibz_finalize(&N);
|
||||
quat_left_ideal_finalize(&I);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_create_from_primitive failed\n");
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
//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);
|
||||
int quat_test_lideal_make_primitive_then_create(){
|
||||
int res = 0;
|
||||
ibz_t n, cnt;
|
||||
quat_alg_t alg;
|
||||
quat_alg_elem_t gen, x;
|
||||
quat_alg_coord_t prim;
|
||||
quat_order_t order;
|
||||
quat_left_ideal_t lideal,cmp;
|
||||
quat_left_ideal_init(&lideal);
|
||||
quat_left_ideal_init(&cmp);
|
||||
quat_alg_init_set_ui(&alg, 103);
|
||||
quat_alg_elem_init(&gen);
|
||||
quat_alg_elem_init(&x);
|
||||
quat_alg_coord_init(&prim);
|
||||
quat_order_init(&order);
|
||||
ibz_init(&n);
|
||||
ibz_init(&cnt);
|
||||
|
||||
|
||||
ibz_set(&order.denom, 2);
|
||||
ibz_set(&order.basis[0][0], 2);
|
||||
ibz_set(&order.basis[1][1], 2);
|
||||
ibz_set(&order.basis[1][2], 1);
|
||||
ibz_set(&order.basis[2][2], 1);
|
||||
ibz_set(&order.basis[3][3], 1);
|
||||
ibz_set(&order.basis[0][3], 1);
|
||||
|
||||
ibz_set(&x.coord[0], 6);
|
||||
ibz_set(&x.coord[1], 10);
|
||||
ibz_set(&x.coord[2], 14);
|
||||
ibz_set(&x.coord[3], 22);
|
||||
ibz_set(&n, 17);
|
||||
|
||||
quat_lideal_make_primitive_then_create(&lideal,&x,&n,&order,&alg);
|
||||
quat_alg_make_primitive(&prim,&cnt,&x,&order,&alg);
|
||||
ibz_mat_4x4_eval(&(gen.coord),&(order.basis),&prim);
|
||||
ibz_copy(&gen.denom,&order.denom);
|
||||
quat_lideal_create_from_primitive(&cmp,&gen,&n,&order,&alg);
|
||||
res = res || !quat_lideal_equals(&lideal,&cmp,&alg);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_make_primitive_then_create failed\n");
|
||||
}
|
||||
quat_alg_finalize(&alg);
|
||||
quat_alg_elem_finalize(&gen);
|
||||
quat_alg_elem_finalize(&x);
|
||||
quat_alg_coord_finalize(&prim);
|
||||
quat_order_finalize(&order);
|
||||
ibz_finalize(&n);
|
||||
ibz_finalize(&cnt);
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
quat_left_ideal_finalize(&cmp);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//void 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);
|
||||
int quat_test_lideal_random_2e(){
|
||||
int res = 0;
|
||||
|
||||
quat_alg_t alg;
|
||||
quat_order_t order;
|
||||
quat_left_ideal_t lideal;
|
||||
quat_alg_init_set_ui(&alg, 103);
|
||||
quat_order_init(&order);
|
||||
quat_left_ideal_init(&lideal);
|
||||
|
||||
ibz_set(&order.denom, 2);
|
||||
ibz_set(&order.basis[0][0], 2);
|
||||
ibz_set(&order.basis[1][1], 2);
|
||||
ibz_set(&order.basis[1][2], 1);
|
||||
ibz_set(&order.basis[2][2], 1);
|
||||
ibz_set(&order.basis[3][3], 1);
|
||||
ibz_set(&order.basis[0][3], 1);
|
||||
|
||||
// Pretty much self-testing (thanks to embedded asserts)
|
||||
res |= quat_lideal_random_2e(&lideal, &order, &alg, 100, 10) == 0;
|
||||
|
||||
quat_alg_finalize(&alg);
|
||||
quat_order_finalize(&order);
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_random_2e failed\n");
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
//int quat_lideal_generator(quat_alg_elem_t *gen, const quat_left_ideal_t *lideal, const quat_alg_t *alg, int bound)
|
||||
int quat_test_lideal_generator(){
|
||||
int res = 0;
|
||||
|
||||
quat_alg_t alg;
|
||||
quat_order_t order;
|
||||
quat_alg_elem_t gen;
|
||||
ibz_t N;
|
||||
quat_left_ideal_t lideal, lideal2;
|
||||
quat_alg_init_set_ui(&alg, 103);
|
||||
quat_order_init(&order);
|
||||
quat_alg_elem_init(&gen);
|
||||
ibz_init(&N);
|
||||
quat_left_ideal_init(&lideal);
|
||||
quat_left_ideal_init(&lideal2);
|
||||
|
||||
ibz_set(&order.denom, 2);
|
||||
ibz_set(&order.basis[0][0], 2);
|
||||
ibz_set(&order.basis[1][1], 2);
|
||||
ibz_set(&order.basis[1][2], 1);
|
||||
ibz_set(&order.basis[2][2], 1);
|
||||
ibz_set(&order.basis[3][3], 1);
|
||||
ibz_set(&order.basis[0][3], 1);
|
||||
|
||||
ibz_set(&gen.coord[0], 3);
|
||||
ibz_set(&gen.coord[1], 5);
|
||||
ibz_set(&gen.coord[2], 7);
|
||||
ibz_set(&gen.coord[3], 11);
|
||||
ibz_set(&N, 17);
|
||||
|
||||
quat_lideal_create_from_primitive(&lideal, &gen, &N, &order, &alg);
|
||||
|
||||
// Try to regenerate the same ideal
|
||||
for (int i = 0; i <= 10; i++) {
|
||||
res |= !quat_lideal_generator(&gen, &lideal, &alg,0);
|
||||
quat_lideal_create_from_primitive(&lideal2, &gen, &N, &order, &alg);
|
||||
res |= !quat_lideal_equals(&lideal, &lideal2, &alg);
|
||||
}
|
||||
|
||||
quat_alg_finalize(&alg);
|
||||
quat_order_finalize(&order);
|
||||
quat_alg_elem_finalize(&gen);
|
||||
ibz_finalize(&N);
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
quat_left_ideal_finalize(&lideal2);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_generator failed\n");
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
//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_test_lideal_generator_coprime(){
|
||||
int res = 0;
|
||||
|
||||
quat_alg_t alg;
|
||||
quat_order_t order, order2;
|
||||
quat_alg_elem_t gen;
|
||||
ibz_t N, M, gcd, norm_int, prod;
|
||||
ibq_t norm;
|
||||
quat_left_ideal_t lideal, lideal2;
|
||||
quat_alg_init_set_ui(&alg, 103);
|
||||
quat_order_init(&order);
|
||||
quat_order_init(&order2);
|
||||
quat_alg_elem_init(&gen);
|
||||
ibz_init(&N);
|
||||
ibz_init(&M);
|
||||
ibz_init(&norm_int);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&gcd);
|
||||
ibq_init(&norm);
|
||||
quat_left_ideal_init(&lideal);
|
||||
quat_left_ideal_init(&lideal2);
|
||||
|
||||
ibz_set(&order.denom, 2);
|
||||
ibz_set(&order.basis[0][0], 2);
|
||||
ibz_set(&order.basis[1][1], 2);
|
||||
ibz_set(&order.basis[1][2], 1);
|
||||
ibz_set(&order.basis[2][2], 1);
|
||||
ibz_set(&order.basis[3][3], 1);
|
||||
ibz_set(&order.basis[0][3], 1);
|
||||
|
||||
ibz_set(&gen.coord[0], 3);
|
||||
ibz_set(&gen.coord[1], 5);
|
||||
ibz_set(&gen.coord[2], 7);
|
||||
ibz_set(&gen.coord[3], 11);
|
||||
ibz_set(&N, 5);
|
||||
// product of primes < 50
|
||||
ibz_set(&M, 614889782588491410l);
|
||||
|
||||
quat_lideal_create_from_primitive(&lideal, &gen, &N, &order, &alg);
|
||||
|
||||
res |= !quat_lideal_generator_coprime(&gen, &lideal, &M, &alg,0);
|
||||
quat_alg_norm(&norm, &gen, &alg);
|
||||
res |= !ibq_to_ibz(&norm_int, &norm);
|
||||
// case with coprimality
|
||||
ibz_gcd(&gcd, &norm_int, &M);
|
||||
res |= !ibz_is_one(&gcd);
|
||||
// test other formula
|
||||
ibz_mul(&prod,&M,&M);
|
||||
ibz_gcd(&prod,&prod,&norm_int);
|
||||
ibz_gcd(&gcd, &(lideal.norm), &M);
|
||||
res |= ibz_cmp(&gcd,&prod);
|
||||
|
||||
quat_lideal_create_from_primitive(&lideal2, &gen, &N, &order, &alg);
|
||||
res |= !quat_lideal_equals(&lideal, &lideal2, &alg);
|
||||
res |= !quat_alg_is_primitive(&gen,&(lideal.lattice), &alg);
|
||||
|
||||
|
||||
|
||||
ibz_set(&(order.denom),1);
|
||||
quat_alg_elem_set(&gen,1,2,4,2,6);
|
||||
|
||||
quat_lideal_create_from_primitive(&lideal, &gen, &N, &order, &alg);
|
||||
|
||||
ibz_set(&M,15);
|
||||
res |= !quat_lideal_generator_coprime(&gen, &lideal, &M, &alg,0);
|
||||
quat_alg_norm(&norm, &gen, &alg);
|
||||
res |= !ibq_to_ibz(&norm_int, &norm);
|
||||
// test other formula
|
||||
ibz_mul(&prod,&M,&M);
|
||||
ibz_gcd(&prod,&prod,&norm_int);
|
||||
ibz_gcd(&gcd, &(lideal.norm), &M);
|
||||
res |= ibz_cmp(&gcd,&prod);
|
||||
|
||||
quat_lideal_create_from_primitive(&lideal2, &gen, &N, &order, &alg);
|
||||
res |= !quat_lideal_equals(&lideal, &lideal2, &alg);
|
||||
res |= !quat_alg_is_primitive(&gen,&(lideal.lattice), &alg);
|
||||
|
||||
quat_alg_finalize(&alg);
|
||||
quat_order_finalize(&order);
|
||||
quat_order_finalize(&order2);
|
||||
quat_alg_elem_finalize(&gen);
|
||||
ibz_finalize(&N);
|
||||
ibz_finalize(&M);
|
||||
ibz_finalize(&norm_int);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&gcd);
|
||||
ibq_finalize(&norm);
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
quat_left_ideal_finalize(&lideal2);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_generator_coprime failed\n");
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
//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);
|
||||
int quat_test_lideal_mul(){
|
||||
int res = 0;
|
||||
|
||||
quat_alg_t alg;
|
||||
quat_order_t order;
|
||||
quat_alg_elem_t gen1, gen2, gen_prod;
|
||||
quat_left_ideal_t lideal, lideal2;
|
||||
quat_alg_init_set_ui(&alg, 103);
|
||||
quat_order_init(&order);
|
||||
quat_alg_elem_init(&gen1);
|
||||
quat_alg_elem_init(&gen2);
|
||||
quat_alg_elem_init(&gen_prod);
|
||||
quat_left_ideal_init(&lideal);
|
||||
quat_left_ideal_init(&lideal2);
|
||||
|
||||
ibz_set(&order.denom, 2);
|
||||
ibz_set(&order.basis[0][0], 2);
|
||||
ibz_set(&order.basis[1][1], 2);
|
||||
ibz_set(&order.basis[1][2], 1);
|
||||
ibz_set(&order.basis[2][2], 1);
|
||||
ibz_set(&order.basis[3][3], 1);
|
||||
ibz_set(&order.basis[0][3], 1);
|
||||
|
||||
ibz_set(&gen1.coord[0], 3);
|
||||
ibz_set(&gen1.coord[1], 5);
|
||||
ibz_set(&gen1.coord[2], 7);
|
||||
ibz_set(&gen1.coord[3], 11);
|
||||
ibz_set(&gen2.coord[0], -2);
|
||||
ibz_set(&gen2.coord[1], 13);
|
||||
ibz_set(&gen2.coord[2], -17);
|
||||
ibz_set(&gen2.coord[3], 19);
|
||||
|
||||
// Check that (O·gen1)·gen2 == O·(gen1·gen2)
|
||||
quat_lideal_create_principal(&lideal, &gen1, &order, &alg);
|
||||
res |= !quat_lideal_mul(&lideal, &lideal, &gen2, &alg,0);
|
||||
quat_alg_mul(&gen_prod, &gen1, &gen2, &alg);
|
||||
quat_lideal_create_principal(&lideal2, &gen_prod, &order, &alg);
|
||||
res |= !quat_lideal_equals(&lideal, &lideal2, &alg);
|
||||
|
||||
// Same test, but with non-integral gen2
|
||||
ibz_set(&(gen2.denom),2);
|
||||
quat_lideal_create_principal(&lideal, &gen1, &order, &alg);
|
||||
res |= !quat_lideal_mul(&lideal, &lideal, &gen2, &alg,0);
|
||||
quat_alg_mul(&gen_prod, &gen1, &gen2, &alg);
|
||||
quat_lideal_create_principal(&lideal2, &gen_prod, &order, &alg);
|
||||
res |= !quat_lideal_equals(&lideal, &lideal2, &alg);
|
||||
|
||||
quat_alg_finalize(&alg);
|
||||
quat_order_finalize(&order);
|
||||
quat_alg_elem_finalize(&gen1);
|
||||
quat_alg_elem_finalize(&gen2);
|
||||
quat_alg_elem_finalize(&gen_prod);
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
quat_left_ideal_finalize(&lideal2);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_mul failed\n");
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
//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_add_intersect_equals(){
|
||||
int res = 0;
|
||||
|
||||
quat_alg_t alg;
|
||||
quat_order_t order;
|
||||
quat_alg_elem_t gen1, gen2, gen3;
|
||||
ibz_t N1, N2, N3;
|
||||
quat_left_ideal_t lideal1, lideal2, lideal3, lideal4, lideal5;
|
||||
quat_alg_init_set_ui(&alg, 103);
|
||||
quat_order_init(&order);
|
||||
quat_alg_elem_init(&gen1);
|
||||
quat_alg_elem_init(&gen2);
|
||||
quat_alg_elem_init(&gen3);
|
||||
ibz_init(&N1);
|
||||
ibz_init(&N2);
|
||||
ibz_init(&N3);
|
||||
quat_left_ideal_init(&lideal1);
|
||||
quat_left_ideal_init(&lideal2);
|
||||
quat_left_ideal_init(&lideal3);
|
||||
quat_left_ideal_init(&lideal4);
|
||||
quat_left_ideal_init(&lideal5);
|
||||
|
||||
ibz_set(&order.denom, 2);
|
||||
ibz_set(&order.basis[0][0], 2);
|
||||
ibz_set(&order.basis[1][1], 2);
|
||||
ibz_set(&order.basis[1][2], 1);
|
||||
ibz_set(&order.basis[2][2], 1);
|
||||
ibz_set(&order.basis[3][3], 1);
|
||||
ibz_set(&order.basis[0][3], 1);
|
||||
|
||||
ibz_set(&gen1.coord[0], 3);
|
||||
ibz_set(&gen1.coord[1], 5);
|
||||
ibz_set(&gen1.coord[2], 7);
|
||||
ibz_set(&gen1.coord[3], 11);
|
||||
ibz_set(&N1, 17);
|
||||
quat_lideal_create_from_primitive(&lideal1, &gen1, &N1, &order, &alg);
|
||||
|
||||
ibz_set(&gen2.coord[0], -2);
|
||||
ibz_set(&gen2.coord[1], 13);
|
||||
ibz_set(&gen2.coord[2], -17);
|
||||
ibz_set(&gen2.coord[3], 19);
|
||||
ibz_set(&N2, 43);
|
||||
quat_lideal_create_from_primitive(&lideal2, &gen2, &N2, &order, &alg);
|
||||
|
||||
quat_alg_mul(&gen3, &gen2, &gen1, &alg);
|
||||
quat_lideal_create_principal(&lideal3, &gen3, &order, &alg);
|
||||
|
||||
// Union should be the whole ring
|
||||
quat_lideal_add(&lideal4, &lideal1, &lideal2, &alg);
|
||||
res |= !ibz_is_one(&lideal4.norm);
|
||||
res |= !quat_lattice_equal(&lideal4.lattice, &order);
|
||||
|
||||
// Self-intersection should be stable
|
||||
quat_lideal_inter(&lideal4, &lideal1, &lideal1, &alg);
|
||||
res |= !quat_lideal_equals(&lideal4, &lideal1, &alg);
|
||||
|
||||
// Self-union should be stable
|
||||
quat_lideal_add(&lideal4, &lideal1, &lideal1, &alg);
|
||||
res |= !quat_lideal_equals(&lideal4, &lideal1, &alg);
|
||||
|
||||
// lideal3 ⊂ lideal1
|
||||
quat_lideal_add(&lideal4, &lideal1, &lideal3, &alg);
|
||||
res |= !quat_lideal_equals(&lideal4, &lideal1, &alg);
|
||||
quat_lideal_inter(&lideal4, &lideal1, &lideal3, &alg);
|
||||
res |= !quat_lideal_equals(&lideal4, &lideal3, &alg);
|
||||
|
||||
// Intersection then union should be stable
|
||||
quat_lideal_inter(&lideal4, &lideal1, &lideal2, &alg);
|
||||
quat_lideal_add(&lideal4, &lideal4, &lideal2, &alg);
|
||||
res |= !quat_lideal_equals(&lideal4, &lideal2, &alg);
|
||||
|
||||
// (A ∩ B) ∪ (A ∩ C) == A ∩ (B ∪ C)
|
||||
quat_lideal_inter(&lideal4, &lideal1, &lideal2, &alg);
|
||||
quat_lideal_inter(&lideal5, &lideal1, &lideal3, &alg);
|
||||
quat_lideal_add(&lideal4, &lideal4, &lideal5, &alg);
|
||||
quat_lideal_add(&lideal5, &lideal2, &lideal3, &alg);
|
||||
quat_lideal_inter(&lideal5, &lideal1, &lideal5, &alg);
|
||||
res |= !quat_lideal_equals(&lideal4, &lideal5, &alg);
|
||||
res |= ibz_cmp_si(&lideal4.norm, 17);
|
||||
|
||||
quat_alg_finalize(&alg);
|
||||
quat_order_finalize(&order);
|
||||
quat_alg_elem_finalize(&gen1);
|
||||
quat_alg_elem_finalize(&gen2);
|
||||
quat_alg_elem_finalize(&gen3);
|
||||
ibz_finalize(&N1);
|
||||
ibz_finalize(&N2);
|
||||
ibz_finalize(&N3);
|
||||
quat_left_ideal_finalize(&lideal1);
|
||||
quat_left_ideal_finalize(&lideal2);
|
||||
quat_left_ideal_finalize(&lideal3);
|
||||
quat_left_ideal_finalize(&lideal4);
|
||||
quat_left_ideal_finalize(&lideal5);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_add_intersect_equals failed\n");
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
//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);
|
||||
int quat_test_lideal_isom(){
|
||||
int res = 0;
|
||||
quat_left_ideal_t lideal1,lideal2,prod;
|
||||
ibz_t norm;
|
||||
quat_alg_elem_t init_helper, isom;
|
||||
quat_order_t order, order2;
|
||||
quat_alg_t alg;
|
||||
ibz_init(&norm);
|
||||
quat_left_ideal_init(&lideal1);
|
||||
quat_left_ideal_init(&lideal2);
|
||||
quat_left_ideal_init(&prod);
|
||||
quat_alg_init_set_ui(&alg,19);
|
||||
quat_order_init(&order);
|
||||
quat_order_init(&order2);
|
||||
quat_alg_elem_init(&isom);
|
||||
quat_alg_elem_init(&init_helper);
|
||||
|
||||
ibz_set(&(order.basis[0][0]),4);
|
||||
ibz_set(&(order.basis[0][1]),0);
|
||||
ibz_set(&(order.basis[0][2]),2);
|
||||
ibz_set(&(order.basis[0][3]),2);
|
||||
ibz_set(&(order.basis[1][0]),0);
|
||||
ibz_set(&(order.basis[1][1]),8);
|
||||
ibz_set(&(order.basis[1][2]),4);
|
||||
ibz_set(&(order.basis[1][3]),3);
|
||||
ibz_set(&(order.basis[2][0]),0);
|
||||
ibz_set(&(order.basis[2][1]),0);
|
||||
ibz_set(&(order.basis[2][2]),2);
|
||||
ibz_set(&(order.basis[2][3]),0);
|
||||
ibz_set(&(order.basis[3][0]),0);
|
||||
ibz_set(&(order.basis[3][1]),0);
|
||||
ibz_set(&(order.basis[3][2]),0);
|
||||
ibz_set(&(order.basis[3][3]),1);
|
||||
ibz_set(&(order.denom),4);
|
||||
quat_alg_elem_set(&init_helper,1,2,6,2,1);
|
||||
quat_lideal_create_principal(&lideal1,&init_helper,&order,&alg);
|
||||
quat_alg_elem_set(&init_helper,3,1,6,5,1);
|
||||
res |= !quat_lideal_mul(&lideal2,&lideal1,&init_helper,&alg,0);
|
||||
res = res || !quat_lideal_isom(&isom,&lideal1,&lideal2,&alg);
|
||||
if(!res){
|
||||
res |= !quat_lideal_mul(&prod,&lideal1,&isom,&alg,0);
|
||||
res = res || !quat_lideal_equals(&prod,&lideal2,&alg);
|
||||
}
|
||||
|
||||
// not same order
|
||||
ibz_set(&(order2.basis[0][0]),2);
|
||||
ibz_set(&(order2.basis[0][1]),0);
|
||||
ibz_set(&(order2.basis[0][2]),1);
|
||||
ibz_set(&(order2.basis[0][3]),0);
|
||||
ibz_set(&(order2.basis[1][0]),0);
|
||||
ibz_set(&(order2.basis[1][1]),2);
|
||||
ibz_set(&(order2.basis[1][2]),0);
|
||||
ibz_set(&(order2.basis[1][3]),1);
|
||||
ibz_set(&(order2.basis[2][0]),0);
|
||||
ibz_set(&(order2.basis[2][1]),0);
|
||||
ibz_set(&(order2.basis[2][2]),1);
|
||||
ibz_set(&(order2.basis[2][3]),0);
|
||||
ibz_set(&(order2.basis[3][0]),0);
|
||||
ibz_set(&(order2.basis[3][1]),0);
|
||||
ibz_set(&(order2.basis[3][2]),0);
|
||||
ibz_set(&(order2.basis[3][3]),1);
|
||||
ibz_set(&(order2.denom),2);
|
||||
quat_alg_elem_set(&init_helper,1,2,6,2,1);
|
||||
quat_lideal_create_principal(&lideal2,&init_helper,&order2,&alg);
|
||||
res = res || quat_lideal_isom(&isom,&lideal1,&lideal2,&alg);
|
||||
|
||||
// should add test for not isomorphic ideals
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_isom failed\n");
|
||||
}
|
||||
quat_left_ideal_finalize(&lideal1);
|
||||
quat_left_ideal_finalize(&lideal2);
|
||||
quat_left_ideal_finalize(&prod);
|
||||
ibz_finalize(&norm);
|
||||
quat_alg_finalize(&alg);
|
||||
quat_order_finalize(&order);
|
||||
quat_order_finalize(&order2);
|
||||
quat_alg_elem_finalize(&isom);
|
||||
quat_alg_elem_finalize(&init_helper);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//void quat_lideal_right_order(quat_order_t *order, const quat_left_ideal_t *lideal, const quat_alg_t *alg);
|
||||
int quat_test_lideal_right_order(){
|
||||
int res = 0;
|
||||
ibz_t norm;
|
||||
quat_alg_t alg;
|
||||
quat_alg_elem_t gen;
|
||||
quat_order_t order,rorder;
|
||||
quat_lattice_t prod;
|
||||
quat_alg_elem_t test;
|
||||
quat_left_ideal_t lideal, cmp;
|
||||
quat_order_init(&order);
|
||||
quat_order_init(&rorder);
|
||||
quat_lattice_init(&prod);
|
||||
quat_alg_init_set_ui(&alg,19);
|
||||
quat_left_ideal_init(&lideal);
|
||||
quat_alg_elem_init(&test);
|
||||
quat_alg_elem_init(&gen);
|
||||
|
||||
ibz_set(&(order.basis[0][0]),4);
|
||||
ibz_set(&(order.basis[0][1]),0);
|
||||
ibz_set(&(order.basis[0][2]),2);
|
||||
ibz_set(&(order.basis[0][3]),2);
|
||||
ibz_set(&(order.basis[1][0]),0);
|
||||
ibz_set(&(order.basis[1][1]),8);
|
||||
ibz_set(&(order.basis[1][2]),4);
|
||||
ibz_set(&(order.basis[1][3]),3);
|
||||
ibz_set(&(order.basis[2][0]),0);
|
||||
ibz_set(&(order.basis[2][1]),0);
|
||||
ibz_set(&(order.basis[2][2]),2);
|
||||
ibz_set(&(order.basis[2][3]),0);
|
||||
ibz_set(&(order.basis[3][0]),0);
|
||||
ibz_set(&(order.basis[3][1]),0);
|
||||
ibz_set(&(order.basis[3][2]),0);
|
||||
ibz_set(&(order.basis[3][3]),1);
|
||||
ibz_set(&(order.denom),4);
|
||||
quat_alg_elem_set(&gen,1,2,1,8,-8);
|
||||
quat_lideal_create_principal(&lideal,&gen,&order,&alg);
|
||||
|
||||
quat_lideal_right_order(&rorder,&lideal,&alg);
|
||||
// test order is in HNF
|
||||
res = res || !ibz_mat_4x4_is_hnf(&(rorder.basis));
|
||||
// test order is of dimension 4 (assuming HNF)
|
||||
for(int i = 0; i < 4; i++){
|
||||
quat_alg_elem_copy_ibz(&test,&(rorder.denom),&(rorder.basis[0][i]),&(rorder.basis[1][i]),&(rorder.basis[2][i]),&(rorder.basis[3][i]));
|
||||
res = res || quat_alg_elem_is_zero(&test);
|
||||
}
|
||||
// test order contains 1
|
||||
quat_alg_elem_set(&test,1,1,0,0,0);
|
||||
res = res || !quat_lattice_contains(NULL,&rorder,&test,&alg);
|
||||
// test it is right order of ideal
|
||||
quat_lattice_mul(&prod,&(lideal.lattice),&rorder,&alg);
|
||||
for(int i = 0; i < 4; i++){
|
||||
quat_alg_elem_copy_ibz(&test,&(prod.denom),&(prod.basis[0][i]),&(prod.basis[1][i]),&(prod.basis[2][i]),&(prod.basis[3][i]));
|
||||
res = res || !quat_lattice_contains(NULL,&(lideal.lattice),&test,&alg);
|
||||
}
|
||||
|
||||
ibz_set(&(order.basis[0][0]),2);
|
||||
ibz_set(&(order.basis[0][1]),0);
|
||||
ibz_set(&(order.basis[0][2]),1);
|
||||
ibz_set(&(order.basis[0][3]),0);
|
||||
ibz_set(&(order.basis[1][0]),0);
|
||||
ibz_set(&(order.basis[1][1]),2);
|
||||
ibz_set(&(order.basis[1][2]),0);
|
||||
ibz_set(&(order.basis[1][3]),1);
|
||||
ibz_set(&(order.basis[2][0]),0);
|
||||
ibz_set(&(order.basis[2][1]),0);
|
||||
ibz_set(&(order.basis[2][2]),1);
|
||||
ibz_set(&(order.basis[2][3]),0);
|
||||
ibz_set(&(order.basis[3][0]),0);
|
||||
ibz_set(&(order.basis[3][1]),0);
|
||||
ibz_set(&(order.basis[3][2]),0);
|
||||
ibz_set(&(order.basis[3][3]),1);
|
||||
ibz_set(&(order.denom),2);
|
||||
quat_alg_elem_set(&gen,1,1,2,8,8);
|
||||
quat_lideal_create_principal(&lideal,&gen,&order,&alg);
|
||||
|
||||
quat_lideal_right_order(&rorder,&lideal,&alg);
|
||||
quat_lattice_mul(&prod,&(lideal.lattice),&rorder,&alg);
|
||||
// test order is in HNF
|
||||
res = res || !ibz_mat_4x4_is_hnf(&(rorder.basis));
|
||||
// test order is of dimension 4 (assuming HNF)
|
||||
for(int i = 0; i < 4; i++){
|
||||
quat_alg_elem_copy_ibz(&test,&(rorder.denom),&(rorder.basis[0][i]),&(rorder.basis[1][i]),&(rorder.basis[2][i]),&(rorder.basis[3][i]));
|
||||
res = res || quat_alg_elem_is_zero(&test);
|
||||
}
|
||||
// test order contains 1
|
||||
quat_alg_elem_set(&test,1,1,0,0,0);
|
||||
res = res || !quat_lattice_contains(NULL,&rorder,&test,&alg);
|
||||
// test it is right order of ideal
|
||||
quat_lattice_mul(&prod,&(lideal.lattice),&rorder,&alg);
|
||||
for(int i = 0; i < 4; i++){
|
||||
quat_alg_elem_copy_ibz(&test,&(prod.denom),&(prod.basis[0][i]),&(prod.basis[1][i]),&(prod.basis[2][i]),&(prod.basis[3][i]));
|
||||
res = res || !quat_lattice_contains(NULL,&(lideal.lattice),&test,&alg);
|
||||
}
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_right_order failed\n");
|
||||
}
|
||||
quat_alg_elem_finalize(&test);
|
||||
quat_order_finalize(&order);
|
||||
quat_order_finalize(&rorder);
|
||||
quat_lattice_finalize(&prod);
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
quat_alg_finalize(&alg);
|
||||
quat_alg_elem_finalize(&gen);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//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
|
||||
int quat_test_lideal_reduce_basis(){
|
||||
int res = 0;
|
||||
ibz_mat_4x4_t red, gram, prod;
|
||||
quat_left_ideal_t lideal;
|
||||
quat_lattice_t test;
|
||||
quat_alg_t alg;
|
||||
quat_alg_elem_t init_helper;
|
||||
quat_order_t order;
|
||||
ibq_t coeff;
|
||||
ibz_t num,denom;
|
||||
ibz_init(&num);
|
||||
ibz_init(&denom);
|
||||
ibq_init(&coeff);
|
||||
ibz_mat_4x4_init(&prod);
|
||||
quat_lattice_init(&test);
|
||||
quat_alg_elem_init(&init_helper);
|
||||
quat_order_init(&order);
|
||||
quat_alg_init_set_ui(&alg,19);
|
||||
ibz_mat_4x4_init(&gram);
|
||||
ibz_mat_4x4_init(&red);
|
||||
quat_left_ideal_init(&lideal);
|
||||
ibz_mat_4x4_identity(&(order.basis));
|
||||
ibz_set(&(order.denom),2);
|
||||
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);
|
||||
// test if red is lll-reduced, assuming he used coeff was at least 3/4
|
||||
ibz_set(&num,99);
|
||||
ibz_set(&denom,100);
|
||||
ibq_set(&coeff,&num,&denom);
|
||||
res = res || !quat_dim4_lll_verify(&red,&coeff,&(alg.p));
|
||||
// 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_transpose(&prod,&red);
|
||||
ibz_mat_4x4_mul(&prod,&prod,&(alg.gram));
|
||||
ibz_mat_4x4_mul(&prod,&prod,&red);
|
||||
res = res || !ibz_mat_4x4_equal(&prod,&gram);
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_reduce_basis failed\n");
|
||||
}
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&denom);
|
||||
ibq_finalize(&coeff);
|
||||
quat_lattice_finalize(&test);
|
||||
quat_alg_elem_finalize(&init_helper);
|
||||
ibz_mat_4x4_finalize(&prod);
|
||||
quat_order_finalize(&order);
|
||||
quat_alg_finalize(&alg);
|
||||
ibz_mat_4x4_finalize(&gram);
|
||||
ibz_mat_4x4_finalize(&red);
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
return(res);
|
||||
}
|
||||
|
||||
/***************************** Functions 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);
|
||||
int quat_test_lideal_connecting_ideal(){
|
||||
int res = 0;
|
||||
ibz_t norm;
|
||||
quat_alg_t alg;
|
||||
quat_alg_elem_t gen;
|
||||
quat_order_t o1, o2;
|
||||
quat_lattice_t prod;
|
||||
quat_alg_elem_t test;
|
||||
quat_left_ideal_t lideal, cmp;
|
||||
quat_order_init(&o1);
|
||||
quat_order_init(&o2);
|
||||
quat_lattice_init(&prod);
|
||||
quat_alg_init_set_ui(&alg,19);
|
||||
quat_left_ideal_init(&lideal);
|
||||
quat_alg_elem_init(&test);
|
||||
|
||||
ibz_set(&(o1.basis[0][0]),4);
|
||||
ibz_set(&(o1.basis[0][1]),0);
|
||||
ibz_set(&(o1.basis[0][2]),2);
|
||||
ibz_set(&(o1.basis[0][3]),2);
|
||||
ibz_set(&(o1.basis[1][0]),0);
|
||||
ibz_set(&(o1.basis[1][1]),8);
|
||||
ibz_set(&(o1.basis[1][2]),4);
|
||||
ibz_set(&(o1.basis[1][3]),3);
|
||||
ibz_set(&(o1.basis[2][0]),0);
|
||||
ibz_set(&(o1.basis[2][1]),0);
|
||||
ibz_set(&(o1.basis[2][2]),2);
|
||||
ibz_set(&(o1.basis[2][3]),0);
|
||||
ibz_set(&(o1.basis[3][0]),0);
|
||||
ibz_set(&(o1.basis[3][1]),0);
|
||||
ibz_set(&(o1.basis[3][2]),0);
|
||||
ibz_set(&(o1.basis[3][3]),1);
|
||||
ibz_set(&(o1.denom),4);
|
||||
|
||||
ibz_set(&(o2.basis[0][0]),2);
|
||||
ibz_set(&(o2.basis[0][1]),0);
|
||||
ibz_set(&(o2.basis[0][2]),1);
|
||||
ibz_set(&(o2.basis[0][3]),0);
|
||||
ibz_set(&(o2.basis[1][0]),0);
|
||||
ibz_set(&(o2.basis[1][1]),2);
|
||||
ibz_set(&(o2.basis[1][2]),0);
|
||||
ibz_set(&(o2.basis[1][3]),1);
|
||||
ibz_set(&(o2.basis[2][0]),0);
|
||||
ibz_set(&(o2.basis[2][1]),0);
|
||||
ibz_set(&(o2.basis[2][2]),1);
|
||||
ibz_set(&(o2.basis[2][3]),0);
|
||||
ibz_set(&(o2.basis[3][0]),0);
|
||||
ibz_set(&(o2.basis[3][1]),0);
|
||||
ibz_set(&(o2.basis[3][2]),0);
|
||||
ibz_set(&(o2.basis[3][3]),1);
|
||||
ibz_set(&(o2.denom),2);
|
||||
|
||||
quat_connecting_ideal(&lideal,&o1,&o2,&alg);
|
||||
quat_lattice_mul(&prod,&o1,&(lideal.lattice),&alg);
|
||||
for(int i = 0; i < 4; i++){
|
||||
quat_alg_elem_copy_ibz(&test,&(prod.denom),&(prod.basis[0][i]),&(prod.basis[1][i]),&(prod.basis[2][i]),&(prod.basis[3][i]));
|
||||
res = res || !quat_lattice_contains(NULL,&(lideal.lattice),&test,&alg);
|
||||
}
|
||||
quat_lattice_mul(&prod,&(lideal.lattice),&o2,&alg);
|
||||
for(int i = 0; i < 4; i++){
|
||||
quat_alg_elem_copy_ibz(&test,&(prod.denom),&(prod.basis[0][i]),&(prod.basis[1][i]),&(prod.basis[2][i]),&(prod.basis[3][i]));
|
||||
res = res || !quat_lattice_contains(NULL,&(lideal.lattice),&test,&alg);
|
||||
}
|
||||
|
||||
quat_connecting_ideal(&lideal,&o2,&o2,&alg);
|
||||
quat_lattice_mul(&prod,&o2,&(lideal.lattice),&alg);
|
||||
for(int i = 0; i < 4; i++){
|
||||
quat_alg_elem_copy_ibz(&test,&(prod.denom),&(prod.basis[0][i]),&(prod.basis[1][i]),&(prod.basis[2][i]),&(prod.basis[3][i]));
|
||||
res = res || !quat_lattice_contains(NULL,&(lideal.lattice),&test,&alg);
|
||||
}
|
||||
quat_lattice_mul(&prod,&(lideal.lattice),&o2,&alg);
|
||||
for(int i = 0; i < 4; i++){
|
||||
quat_alg_elem_copy_ibz(&test,&(prod.denom),&(prod.basis[0][i]),&(prod.basis[1][i]),&(prod.basis[2][i]),&(prod.basis[3][i]));
|
||||
res = res || !quat_lattice_contains(NULL,&(lideal.lattice),&test,&alg);
|
||||
}
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lideal_connecting_ideal failed\n");
|
||||
}
|
||||
quat_alg_elem_finalize(&test);
|
||||
quat_order_finalize(&o1);
|
||||
quat_order_finalize(&o2);
|
||||
quat_lattice_finalize(&prod);
|
||||
quat_left_ideal_finalize(&lideal);
|
||||
quat_alg_finalize(&alg);
|
||||
return(res);
|
||||
}
|
||||
|
||||
// run all previous tests
|
||||
int quat_test_lideal(){
|
||||
int res = 0;
|
||||
printf("\nRunning quaternion tests of ideal and order functions\n");
|
||||
res = res | quat_test_lideal_create_principal();
|
||||
res = res | quat_test_lideal_create_from_primitive();
|
||||
res = res | quat_test_lideal_make_primitive_then_create();
|
||||
res = res | quat_test_lideal_random_2e();
|
||||
res = res | quat_test_lideal_generator();
|
||||
res = res | quat_test_lideal_generator_coprime();
|
||||
res = res | quat_test_lideal_mul();
|
||||
res = res | quat_test_lideal_add_intersect_equals();
|
||||
res = res | quat_test_lideal_isom();
|
||||
res = res | quat_test_lideal_right_order();
|
||||
res = res | quat_test_lideal_reduce_basis();
|
||||
res = res | quat_test_lideal_connecting_ideal();
|
||||
return(res);
|
||||
}
|
||||
587
src/quaternion/ref/generic/test/integers.c
Normal file
587
src/quaternion/ref/generic/test/integers.c
Normal file
@@ -0,0 +1,587 @@
|
||||
#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 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");
|
||||
}
|
||||
ibz_finalize(&a);
|
||||
ibz_finalize(&b);
|
||||
ibz_finalize(&q);
|
||||
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 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_init(&x);
|
||||
ibz_init(&y);
|
||||
ibz_init(&n);
|
||||
ibz_init(&p);
|
||||
ibz_init(&prod);
|
||||
ibz_init(&c_res);
|
||||
|
||||
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);
|
||||
} 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);
|
||||
} 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);
|
||||
} 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);
|
||||
} 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);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
|
||||
ibz_set(&n, 1);
|
||||
// there is no solution in these cases
|
||||
ibz_set(&p, 7);
|
||||
res = res || ibz_cornacchia_prime(&x,&y,&n,&p);
|
||||
ibz_set(&p, 3);
|
||||
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){
|
||||
printf("Quaternion unit test integer_ibz_cornacchia_prime failed\n");
|
||||
}
|
||||
ibz_finalize(&x);
|
||||
ibz_finalize(&y);
|
||||
ibz_finalize(&n);
|
||||
ibz_finalize(&p);
|
||||
ibz_finalize(&prod);
|
||||
ibz_finalize(&c_res);
|
||||
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 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_integer_ibz_cornacchia_prime();
|
||||
res = res | quat_test_integer_ibz_cornacchia_special_prime();
|
||||
res = res | quat_test_integer_ibz_cornacchia_extended();
|
||||
return(res);
|
||||
}
|
||||
|
||||
786
src/quaternion/ref/generic/test/lattice.c
Normal file
786
src/quaternion/ref/generic/test/lattice.c
Normal file
@@ -0,0 +1,786 @@
|
||||
#include "quaternion_tests.h"
|
||||
|
||||
// helper functions
|
||||
|
||||
//int quat_lattice_equal(const quat_lattice_t *lat1, const quat_lattice_t *lat2);
|
||||
int quat_test_lattice_equal(){
|
||||
int res = 0;
|
||||
quat_lattice_t lat, cmp;
|
||||
quat_lattice_init(&lat);
|
||||
quat_lattice_init(&cmp);
|
||||
|
||||
ibz_mat_4x4_identity(&(lat.basis));
|
||||
ibz_mat_4x4_identity(&(cmp.basis));
|
||||
res = res || !quat_lattice_equal(&lat,&cmp);
|
||||
ibz_set(&(lat.denom),5);
|
||||
ibz_set(&(cmp.denom),4);
|
||||
res = res || quat_lattice_equal(&lat,&cmp);
|
||||
ibz_set(&(lat.denom),1);
|
||||
ibz_set(&(cmp.denom),-1);
|
||||
res = res || !quat_lattice_equal(&lat,&cmp);
|
||||
ibz_set(&(lat.denom),3);
|
||||
ibz_set(&(cmp.denom),3);
|
||||
res = res || !quat_lattice_equal(&lat,&cmp);
|
||||
ibz_set(&(lat.basis[0][0]),1);
|
||||
ibz_set(&(lat.basis[0][3]),-1);
|
||||
ibz_set(&(lat.basis[1][1]),-2);
|
||||
ibz_set(&(lat.basis[2][2]),1);
|
||||
ibz_set(&(lat.basis[2][1]),1);
|
||||
ibz_set(&(lat.basis[3][3]),-3);
|
||||
ibz_set(&(lat.denom),6);
|
||||
quat_lattice_hnf(&lat);
|
||||
ibz_mat_4x4_copy(&(cmp.basis), &(lat.basis));
|
||||
ibz_set(&(cmp.denom),6);
|
||||
res = res || !quat_lattice_equal(&lat,&cmp);
|
||||
ibz_set(&(cmp.denom),-7);
|
||||
res = res || quat_lattice_equal(&lat,&cmp);
|
||||
ibz_set(&(cmp.denom),6);
|
||||
ibz_set(&(cmp.basis[3][3]),165);
|
||||
res = res || quat_lattice_equal(&lat,&cmp);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_equal failed\n");
|
||||
}
|
||||
quat_lattice_finalize(&lat);
|
||||
quat_lattice_finalize(&cmp);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//void quat_lattice_reduce_denom(quat_lattice_t *reduced, const quat_lattice_t *lat);
|
||||
int quat_test_lattice_reduce_denom(){
|
||||
int res = 0;
|
||||
int s;
|
||||
quat_lattice_t red, lat, cmp;
|
||||
quat_lattice_init(&red);
|
||||
quat_lattice_init(&cmp);
|
||||
quat_lattice_init(&lat);
|
||||
|
||||
s = 15;
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_set(&(lat.basis[i][j]),(i+j)*s);
|
||||
ibz_set(&(cmp.basis[i][j]),(i+j));
|
||||
}
|
||||
}
|
||||
ibz_set(&(lat.denom),4*s);
|
||||
ibz_set(&(cmp.denom), 4);
|
||||
|
||||
quat_lattice_reduce_denom(&red,&lat);
|
||||
res = res || (!ibz_mat_4x4_equal(&(red.basis),&(cmp.basis)));
|
||||
res = res || ibz_cmp(&(red.denom),&(cmp.denom));
|
||||
|
||||
|
||||
quat_lattice_reduce_denom(&lat,&lat);
|
||||
res = res || (!ibz_mat_4x4_equal(&(lat.basis),&(cmp.basis)));
|
||||
res = res || ibz_cmp(&(lat.denom),&(cmp.denom));
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_reduce_denom failed\n");
|
||||
}
|
||||
quat_lattice_finalize(&red);
|
||||
quat_lattice_finalize(&cmp);
|
||||
quat_lattice_finalize(&lat);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//void quat_lattice_dual_without_hnf(quat_lattice_t *dual, const quat_lattice_t *lat);
|
||||
int quat_test_lattice_dual_without_hnf(){
|
||||
int res = 0;
|
||||
quat_lattice_t lat, dual,cmp;
|
||||
quat_lattice_init(&lat);
|
||||
quat_lattice_init(&dual);
|
||||
quat_lattice_init(&cmp);
|
||||
// set lattice
|
||||
ibz_mat_4x4_zero(&(lat.basis));
|
||||
ibz_set(&(lat.basis[0][0]),1);
|
||||
ibz_set(&(lat.basis[0][3]),-1);
|
||||
ibz_set(&(lat.basis[1][1]),-2);
|
||||
ibz_set(&(lat.basis[2][2]),1);
|
||||
ibz_set(&(lat.basis[2][1]),1);
|
||||
ibz_set(&(lat.basis[3][3]),-3);
|
||||
ibz_set(&(lat.denom),6);
|
||||
ibz_mat_4x4_zero(&(cmp.basis));
|
||||
ibz_set(&(cmp.basis[0][0]),6);
|
||||
ibz_set(&(cmp.basis[1][1]),3);
|
||||
ibz_set(&(cmp.basis[2][2]),6);
|
||||
ibz_set(&(cmp.basis[3][3]),2);
|
||||
ibz_set(&(cmp.denom),1);
|
||||
quat_lattice_hnf(&lat);
|
||||
// test whether dual of dual is original lattice, but dual is not.
|
||||
quat_lattice_dual_without_hnf(&dual,&lat);
|
||||
quat_lattice_hnf(&dual);
|
||||
quat_lattice_hnf(&cmp);
|
||||
res = res || !quat_lattice_equal(&dual,&cmp);
|
||||
res = res || quat_lattice_equal(&dual,&lat);
|
||||
quat_lattice_dual_without_hnf(&dual,&dual);
|
||||
quat_lattice_hnf(&dual);
|
||||
res = res || !quat_lattice_equal(&dual,&lat);
|
||||
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_dual_without_hnf failed\n");
|
||||
}
|
||||
quat_lattice_finalize(&lat);
|
||||
quat_lattice_finalize(&dual);
|
||||
quat_lattice_finalize(&cmp);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//void quat_lattice_add(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2);
|
||||
int quat_test_lattice_add(){
|
||||
int res = 0;
|
||||
quat_lattice_t lat1, lat2, cmp, sum;
|
||||
quat_lattice_init(&lat1);
|
||||
quat_lattice_init(&lat2);
|
||||
quat_lattice_init(&sum);
|
||||
quat_lattice_init(&cmp);
|
||||
ibz_mat_4x4_zero(&(lat1.basis));
|
||||
ibz_mat_4x4_zero(&(lat2.basis));
|
||||
ibz_mat_4x4_zero(&(cmp.basis));
|
||||
ibz_set(&(lat1.basis[0][0]),44);
|
||||
ibz_set(&(lat1.basis[0][2]),3);
|
||||
ibz_set(&(lat1.basis[0][3]),32);
|
||||
ibz_set(&(lat2.basis[0][0]),1);
|
||||
ibz_set(&(cmp.basis[0][0]),2);
|
||||
ibz_set(&(cmp.basis[0][2]),1);
|
||||
ibz_set(&(lat1.basis[1][1]),5);
|
||||
ibz_set(&(lat2.basis[1][1]),2);
|
||||
ibz_set(&(cmp.basis[1][1]),1);
|
||||
ibz_set(&(lat1.basis[2][2]),3);
|
||||
ibz_set(&(lat2.basis[2][2]),1);
|
||||
ibz_set(&(cmp.basis[2][2]),1);
|
||||
ibz_set(&(lat1.basis[3][3]),1);
|
||||
ibz_set(&(lat2.basis[3][3]),3);
|
||||
ibz_set(&(cmp.basis[3][3]),3);
|
||||
ibz_set(&(lat1.denom),4);
|
||||
ibz_set(&(lat2.denom),6);
|
||||
ibz_set(&(cmp.denom),12);
|
||||
|
||||
quat_lattice_add(&sum,&lat1,&lat2);
|
||||
res = res || (!ibz_mat_4x4_equal(&(sum.basis),&(cmp.basis)));
|
||||
res = res || ibz_cmp(&(sum.denom),&(cmp.denom));
|
||||
|
||||
// same lattices but not under hnf
|
||||
ibz_mat_4x4_zero(&(lat1.basis));
|
||||
ibz_mat_4x4_zero(&(lat2.basis));
|
||||
ibz_set(&(lat1.basis[0][0]),4);
|
||||
ibz_set(&(lat1.basis[0][2]),3);
|
||||
ibz_set(&(lat2.basis[0][0]),1);
|
||||
ibz_set(&(lat2.basis[0][3]),-1);
|
||||
ibz_set(&(lat1.basis[1][1]),5);
|
||||
ibz_set(&(lat2.basis[1][1]),-2);
|
||||
ibz_set(&(lat1.basis[2][2]),3);
|
||||
ibz_set(&(lat2.basis[2][2]),1);
|
||||
ibz_set(&(lat2.basis[2][1]),1);
|
||||
ibz_set(&(lat1.basis[3][3]),7);
|
||||
ibz_set(&(lat2.basis[3][3]),-3);
|
||||
ibz_set(&(lat1.denom),4);
|
||||
ibz_set(&(lat2.denom),6);
|
||||
|
||||
quat_lattice_add(&sum,&lat1,&lat2);
|
||||
res = res || (!ibz_mat_4x4_equal(&(sum.basis),&(cmp.basis)));
|
||||
res = res || ibz_cmp(&(sum.denom),&(cmp.denom));
|
||||
|
||||
//double in place gives hnf
|
||||
ibz_mat_4x4_copy(&(cmp.basis),&lat2.basis);
|
||||
ibz_copy(&(cmp.denom),&(lat2.denom));
|
||||
quat_lattice_hnf(&cmp);
|
||||
quat_lattice_add(&lat2,&lat2,&lat2);
|
||||
res = res || (!ibz_mat_4x4_equal(&(lat2.basis),&(cmp.basis)));
|
||||
res = res || ibz_cmp(&(lat2.denom),&(cmp.denom));
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_add failed\n");
|
||||
}
|
||||
quat_lattice_finalize(&lat1);
|
||||
quat_lattice_finalize(&lat2);
|
||||
quat_lattice_finalize(&sum);
|
||||
quat_lattice_finalize(&cmp);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//void quat_lattice_intersect(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2);
|
||||
int quat_test_lattice_intersect(){
|
||||
int res = 0;
|
||||
quat_lattice_t lat1,lat2, inter, cmp;
|
||||
quat_lattice_init(&lat1);
|
||||
quat_lattice_init(&lat2);
|
||||
quat_lattice_init(&inter);
|
||||
quat_lattice_init(&cmp);
|
||||
ibz_mat_4x4_zero(&(cmp.basis));
|
||||
ibz_mat_4x4_zero(&(lat1.basis));
|
||||
ibz_mat_4x4_zero(&(lat2.basis));
|
||||
ibz_set(&(lat1.basis[0][0]),4);
|
||||
ibz_set(&(lat1.basis[0][2]),3);
|
||||
ibz_set(&(lat2.basis[0][0]),1);
|
||||
ibz_set(&(lat2.basis[0][3]),-1);
|
||||
ibz_set(&(lat1.basis[1][1]),5);
|
||||
ibz_set(&(lat2.basis[1][1]),-2);
|
||||
ibz_set(&(lat1.basis[2][2]),3);
|
||||
ibz_set(&(lat2.basis[2][2]),1);
|
||||
ibz_set(&(lat2.basis[2][1]),1);
|
||||
ibz_set(&(lat1.basis[3][3]),7);
|
||||
ibz_set(&(lat2.basis[3][3]),-3);
|
||||
ibz_set(&(lat1.denom),4);
|
||||
ibz_set(&(lat2.denom),6);
|
||||
quat_lattice_hnf(&lat1);
|
||||
quat_lattice_hnf(&lat2);
|
||||
|
||||
ibz_set(&(cmp.basis[0][0]),2);
|
||||
ibz_set(&(cmp.basis[0][2]),1);
|
||||
ibz_set(&(cmp.basis[1][1]),10);
|
||||
ibz_set(&(cmp.basis[2][2]),3);
|
||||
ibz_set(&(cmp.basis[3][3]),7);
|
||||
ibz_set(&(cmp.denom),2);
|
||||
quat_lattice_intersect(&inter,&lat1,&lat2);
|
||||
|
||||
res = res || !quat_lattice_equal(&inter,&cmp);
|
||||
quat_lattice_intersect(&lat2,&lat1,&lat2);
|
||||
res = res || !quat_lattice_equal(&lat2,&cmp);
|
||||
ibz_mat_4x4_copy(&(cmp.basis),&(lat1.basis));
|
||||
ibz_copy(&(cmp.denom),&(lat1.denom));
|
||||
quat_lattice_intersect(&lat1,&lat1,&lat1);
|
||||
res = res || !quat_lattice_equal(&lat1,&cmp);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_intersect failed\n");
|
||||
}
|
||||
quat_lattice_finalize(&lat1);
|
||||
quat_lattice_finalize(&lat2);
|
||||
quat_lattice_finalize(&inter);
|
||||
quat_lattice_finalize(&cmp);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//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_test_lattice_mul(){
|
||||
int res = 0;
|
||||
quat_lattice_t lat1, lat2, cmp, prod;
|
||||
quat_alg_t alg;
|
||||
quat_lattice_init(&lat1);
|
||||
quat_lattice_init(&lat2);
|
||||
quat_lattice_init(&prod);
|
||||
quat_lattice_init(&cmp);
|
||||
quat_alg_init_set_ui(&alg, 19);
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_set(&(lat1.basis[i][j]),0);
|
||||
ibz_set(&(lat2.basis[i][j]),0);
|
||||
ibz_set(&(cmp.basis[i][j]),0);
|
||||
}
|
||||
}
|
||||
|
||||
ibz_set(&(lat1.basis[0][0]),44);
|
||||
ibz_set(&(lat1.basis[0][2]),3);
|
||||
ibz_set(&(lat1.basis[0][3]),32);
|
||||
ibz_set(&(lat2.basis[0][0]),1);
|
||||
ibz_set(&(cmp.basis[0][0]),1);
|
||||
ibz_set(&(lat1.basis[1][1]),5);
|
||||
ibz_set(&(lat2.basis[1][1]),2);
|
||||
ibz_set(&(cmp.basis[1][1]),1);
|
||||
ibz_set(&(lat1.basis[2][2]),3);
|
||||
ibz_set(&(lat2.basis[2][2]),1);
|
||||
ibz_set(&(cmp.basis[2][2]),1);
|
||||
ibz_set(&(lat1.basis[3][3]),1);
|
||||
ibz_set(&(lat2.basis[3][3]),3);
|
||||
ibz_set(&(cmp.basis[3][3]),1);
|
||||
ibz_set(&(lat1.denom),4);
|
||||
ibz_set(&(lat2.denom),6);
|
||||
ibz_set(&(cmp.denom),24);
|
||||
|
||||
quat_lattice_mul(&prod,&lat1,&lat2,&alg);
|
||||
res = res || (!ibz_mat_4x4_equal(&(prod.basis),&(cmp.basis)));
|
||||
res = res || ibz_cmp(&(prod.denom),&(cmp.denom));
|
||||
|
||||
// same lattices but not under hnf
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_set(&(lat1.basis[i][j]),0);
|
||||
ibz_set(&(lat2.basis[i][j]),0);
|
||||
}
|
||||
}
|
||||
ibz_set(&(lat1.basis[0][0]),4);
|
||||
ibz_set(&(lat1.basis[0][2]),3);
|
||||
ibz_set(&(lat2.basis[0][0]),1);
|
||||
ibz_set(&(lat2.basis[0][3]),-1);
|
||||
ibz_set(&(lat1.basis[1][1]),5);
|
||||
ibz_set(&(lat2.basis[1][1]),-2);
|
||||
ibz_set(&(lat1.basis[2][2]),3);
|
||||
ibz_set(&(lat2.basis[2][2]),1);
|
||||
ibz_set(&(lat2.basis[2][1]),1);
|
||||
ibz_set(&(lat1.basis[3][3]),7);
|
||||
ibz_set(&(lat2.basis[3][3]),-3);
|
||||
ibz_set(&(lat1.denom),4);
|
||||
ibz_set(&(lat2.denom),6);
|
||||
|
||||
quat_lattice_mul(&prod,&lat1,&lat2,&alg);
|
||||
res = res || (!ibz_mat_4x4_equal(&(prod.basis),&(cmp.basis)));
|
||||
res = res || ibz_cmp(&(prod.denom),&(cmp.denom));
|
||||
|
||||
//double in place gives hnf
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_set(&(cmp.basis[i][j]),0);
|
||||
}
|
||||
}
|
||||
ibz_set(&(cmp.basis[0][0]),1);
|
||||
ibz_set(&(cmp.basis[1][1]),1);
|
||||
ibz_set(&(cmp.basis[2][2]),1);
|
||||
ibz_set(&(cmp.basis[3][3]),1);
|
||||
ibz_set(&(cmp.denom),36);
|
||||
quat_lattice_mul(&lat2,&lat2,&lat2,&alg);
|
||||
res = res || (!ibz_mat_4x4_equal(&(lat2.basis),&(cmp.basis)));
|
||||
res = res || ibz_cmp(&(lat2.denom),&(cmp.denom));
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_mul failed\n");
|
||||
}
|
||||
quat_lattice_finalize(&lat1);
|
||||
quat_lattice_finalize(&lat2);
|
||||
quat_lattice_finalize(&prod);
|
||||
quat_lattice_finalize(&cmp);
|
||||
quat_alg_finalize(&alg);
|
||||
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_lattice_contains_without_alg(){
|
||||
int res = 0;
|
||||
quat_alg_elem_t x;
|
||||
quat_alg_coord_t coord, cmp;
|
||||
quat_lattice_t lat;
|
||||
quat_alg_elem_init(&x);
|
||||
quat_alg_coord_init(&coord);
|
||||
quat_alg_coord_init(&cmp);
|
||||
quat_lattice_init(&lat);
|
||||
|
||||
// lattice 1
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_set(&(lat.basis[i][j]),0);
|
||||
}
|
||||
}
|
||||
ibz_set(&(lat.basis[0][0]),4);
|
||||
ibz_set(&(lat.basis[0][2]),3);
|
||||
ibz_set(&(lat.basis[1][1]),5);
|
||||
ibz_set(&(lat.basis[2][2]),3);
|
||||
ibz_set(&(lat.basis[3][3]),7);
|
||||
ibz_set(&(lat.denom),4);
|
||||
|
||||
// x 1, should fail
|
||||
ibz_set(&(x.denom),3);
|
||||
ibz_set(&(x.coord[0]),1);
|
||||
ibz_set(&(x.coord[1]),-2);
|
||||
ibz_set(&(x.coord[2]),26);
|
||||
ibz_set(&(x.coord[3]),9);
|
||||
|
||||
res = res || quat_lattice_contains_without_alg(&coord,&lat,&x);
|
||||
// again, but with NULL
|
||||
res = res || quat_lattice_contains_without_alg(NULL,&lat,&x);
|
||||
|
||||
|
||||
// lattice 2
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_set(&(lat.basis[i][j]),0);
|
||||
}
|
||||
}
|
||||
ibz_set(&(lat.basis[0][0]),1);
|
||||
ibz_set(&(lat.basis[0][3]),-1);
|
||||
ibz_set(&(lat.basis[1][1]),-2);
|
||||
ibz_set(&(lat.basis[2][2]),1);
|
||||
ibz_set(&(lat.basis[2][1]),1);
|
||||
ibz_set(&(lat.basis[3][3]),-3);
|
||||
ibz_set(&(lat.denom),6);
|
||||
quat_lattice_hnf(&lat);
|
||||
// x 1, should succeed
|
||||
ibz_set(&(x.denom),3);
|
||||
ibz_set(&(x.coord[0]),1);
|
||||
ibz_set(&(x.coord[1]),-2);
|
||||
ibz_set(&(x.coord[2]),26);
|
||||
ibz_set(&(x.coord[3]),9);
|
||||
ibz_set(&(cmp[0]),2);
|
||||
ibz_set(&(cmp[1]),-2);
|
||||
ibz_set(&(cmp[2]),52);
|
||||
ibz_set(&(cmp[3]),6);
|
||||
|
||||
res = res || (0==quat_lattice_contains_without_alg(&coord,&lat,&x));
|
||||
|
||||
res = res || ibz_cmp(&(coord[0]),&(cmp[0]));
|
||||
res = res || ibz_cmp(&(coord[1]),&(cmp[1]));
|
||||
res = res || ibz_cmp(&(coord[2]),&(cmp[2]));
|
||||
res = res || ibz_cmp(&(coord[3]),&(cmp[3]));
|
||||
// again, but with NULL
|
||||
res = res || (0==quat_lattice_contains_without_alg(NULL,&lat,&x));
|
||||
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_contains_without_alg failed\n");
|
||||
}
|
||||
quat_alg_elem_finalize(&x);
|
||||
quat_alg_coord_finalize(&coord);
|
||||
quat_alg_coord_finalize(&cmp);
|
||||
quat_lattice_finalize(&lat);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//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);
|
||||
int quat_test_lattice_contains(){
|
||||
int res = 0;
|
||||
quat_alg_t alg;
|
||||
quat_alg_elem_t x;
|
||||
quat_alg_coord_t coord, cmp;
|
||||
quat_lattice_t lat;
|
||||
quat_alg_init_set_ui(&alg, 103);
|
||||
quat_alg_elem_init(&x);
|
||||
quat_alg_coord_init(&coord);
|
||||
quat_alg_coord_init(&cmp);
|
||||
quat_lattice_init(&lat);
|
||||
|
||||
// lattice 1
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_set(&(lat.basis[i][j]),0);
|
||||
}
|
||||
}
|
||||
ibz_set(&(lat.basis[0][0]),4);
|
||||
ibz_set(&(lat.basis[0][2]),3);
|
||||
ibz_set(&(lat.basis[1][1]),5);
|
||||
ibz_set(&(lat.basis[2][2]),3);
|
||||
ibz_set(&(lat.basis[3][3]),7);
|
||||
ibz_set(&(lat.denom),4);
|
||||
|
||||
// x 1, should fail
|
||||
ibz_set(&(x.denom),3);
|
||||
ibz_set(&(x.coord[0]),1);
|
||||
ibz_set(&(x.coord[1]),-2);
|
||||
ibz_set(&(x.coord[2]),26);
|
||||
ibz_set(&(x.coord[3]),9);
|
||||
|
||||
res = res || quat_lattice_contains(&coord,&lat,&x,&alg);
|
||||
// again, but with NULL
|
||||
res = res || quat_lattice_contains(NULL,&lat,&x,&alg);
|
||||
|
||||
|
||||
// lattice 2
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_set(&(lat.basis[i][j]),0);
|
||||
}
|
||||
}
|
||||
ibz_set(&(lat.basis[0][0]),1);
|
||||
ibz_set(&(lat.basis[0][3]),-1);
|
||||
ibz_set(&(lat.basis[1][1]),-2);
|
||||
ibz_set(&(lat.basis[2][2]),1);
|
||||
ibz_set(&(lat.basis[2][1]),1);
|
||||
ibz_set(&(lat.basis[3][3]),-3);
|
||||
ibz_set(&(lat.denom),6);
|
||||
quat_lattice_hnf(&lat);
|
||||
// x 1, should succeed
|
||||
ibz_set(&(x.denom),3);
|
||||
ibz_set(&(x.coord[0]),1);
|
||||
ibz_set(&(x.coord[1]),-2);
|
||||
ibz_set(&(x.coord[2]),26);
|
||||
ibz_set(&(x.coord[3]),9);
|
||||
ibz_set(&(cmp[0]),2);
|
||||
ibz_set(&(cmp[1]),-2);
|
||||
ibz_set(&(cmp[2]),52);
|
||||
ibz_set(&(cmp[3]),6);
|
||||
|
||||
res = res || (0==quat_lattice_contains(&coord,&lat,&x,&alg));
|
||||
|
||||
res = res || ibz_cmp(&(coord[0]),&(cmp[0]));
|
||||
res = res || ibz_cmp(&(coord[1]),&(cmp[1]));
|
||||
res = res || ibz_cmp(&(coord[2]),&(cmp[2]));
|
||||
res = res || ibz_cmp(&(coord[3]),&(cmp[3]));
|
||||
// again, but with NULL
|
||||
res = res || (0==quat_lattice_contains(NULL,&lat,&x,&alg));
|
||||
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_contains failed\n");
|
||||
}
|
||||
quat_alg_finalize(&alg);
|
||||
quat_alg_elem_finalize(&x);
|
||||
quat_alg_coord_finalize(&coord);
|
||||
quat_alg_coord_finalize(&cmp);
|
||||
quat_lattice_finalize(&lat);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//void quat_lattice_index(ibz_t *index, const quat_lattice_t *sublat, const quat_lattice_t *overlat);
|
||||
int quat_test_lattice_index(){
|
||||
int res = 0;
|
||||
quat_lattice_t sublat,overlat;
|
||||
ibz_t index;
|
||||
ibz_init(&index);
|
||||
quat_lattice_init(&sublat);
|
||||
quat_lattice_init(&overlat);
|
||||
|
||||
ibz_mat_4x4_zero(&(sublat.basis));
|
||||
ibz_mat_4x4_identity(&(overlat.basis));
|
||||
ibz_set(&(overlat.denom),2);
|
||||
ibz_set(&(sublat.basis[0][0]),2);
|
||||
ibz_set(&(sublat.basis[0][1]),0);
|
||||
ibz_set(&(sublat.basis[0][2]),1);
|
||||
ibz_set(&(sublat.basis[0][3]),0);
|
||||
ibz_set(&(sublat.basis[1][0]),0);
|
||||
ibz_set(&(sublat.basis[1][1]),4);
|
||||
ibz_set(&(sublat.basis[1][2]),2);
|
||||
ibz_set(&(sublat.basis[1][3]),3);
|
||||
ibz_set(&(sublat.basis[2][0]),0);
|
||||
ibz_set(&(sublat.basis[2][1]),0);
|
||||
ibz_set(&(sublat.basis[2][2]),1);
|
||||
ibz_set(&(sublat.basis[2][3]),0);
|
||||
ibz_set(&(sublat.basis[3][0]),0);
|
||||
ibz_set(&(sublat.basis[3][1]),0);
|
||||
ibz_set(&(sublat.basis[3][2]),0);
|
||||
ibz_set(&(sublat.basis[3][3]),1);
|
||||
ibz_set(&(sublat.denom),2);
|
||||
quat_lattice_index(&index,&sublat,&overlat);
|
||||
|
||||
res = res || !(ibz_get(&index)==8);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_index failed\n");
|
||||
}
|
||||
quat_lattice_finalize(&sublat);
|
||||
quat_lattice_finalize(&overlat);
|
||||
ibz_finalize(&index);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//void quat_lattice_hnf(quat_lattice_t *lat);
|
||||
int quat_test_lattice_hnf(){
|
||||
int res = 0;
|
||||
quat_lattice_t lat, cmp;
|
||||
quat_lattice_init(&lat);
|
||||
quat_lattice_init(&cmp);
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
ibz_set(&(lat.basis[i][j]),0);
|
||||
ibz_set(&(cmp.basis[i][j]),0);
|
||||
}
|
||||
}
|
||||
ibz_set(&(lat.basis[0][0]),1);
|
||||
ibz_set(&(lat.basis[0][3]),-1);
|
||||
ibz_set(&(lat.basis[1][1]),-2);
|
||||
ibz_set(&(lat.basis[2][2]),1);
|
||||
ibz_set(&(lat.basis[2][1]),1);
|
||||
ibz_set(&(lat.basis[3][3]),-3);
|
||||
ibz_set(&(cmp.basis[0][0]),1);
|
||||
ibz_set(&(cmp.basis[1][1]),2);
|
||||
ibz_set(&(cmp.basis[2][2]),1);
|
||||
ibz_set(&(cmp.basis[3][3]),3);
|
||||
ibz_set(&(cmp.denom),6);
|
||||
ibz_set(&(lat.denom),6);
|
||||
|
||||
quat_lattice_hnf(&lat);
|
||||
res = res || (!ibz_mat_4x4_equal(&(lat.basis),&(cmp.basis)));
|
||||
res = res || ibz_cmp(&(lat.denom),&(cmp.denom));
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_hnf failed\n");
|
||||
}
|
||||
quat_lattice_finalize(&lat);
|
||||
quat_lattice_finalize(&cmp);
|
||||
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_lattice_lll(){
|
||||
int res = 0;
|
||||
quat_lattice_t lat, test;
|
||||
ibz_mat_4x4_t red;
|
||||
ibz_t num, denom, q;
|
||||
ibq_t coeff;
|
||||
ibz_init(&num);
|
||||
ibz_init(&denom);
|
||||
ibz_init(&q);
|
||||
ibq_init(&coeff);
|
||||
ibz_mat_4x4_init(&red);
|
||||
quat_lattice_init(&lat);
|
||||
quat_lattice_init(&test);
|
||||
|
||||
// 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);
|
||||
|
||||
ibz_set(&q,103);
|
||||
res = res || quat_lattice_lll(&red,&lat,&q,10);
|
||||
// test lll reduced
|
||||
ibz_set(&num,3);
|
||||
ibz_set(&denom,4);
|
||||
ibq_set(&coeff,&num,&denom);
|
||||
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 lattice_lll failed\n");
|
||||
}
|
||||
ibz_finalize(&num);
|
||||
ibz_finalize(&denom);
|
||||
ibz_finalize(&q);
|
||||
ibq_finalize(&coeff);
|
||||
ibz_mat_4x4_finalize(&red);
|
||||
quat_lattice_finalize(&lat);
|
||||
quat_lattice_finalize(&test);
|
||||
return(res);
|
||||
}
|
||||
|
||||
//int quat_lattice_random_elem(quat_alg_elem_t *elem, const quat_lattice_t *lattice, unsigned char n)
|
||||
int quat_test_lattice_random_elem(){
|
||||
int res = 0;
|
||||
|
||||
quat_lattice_t lat;
|
||||
quat_alg_elem_t elem;
|
||||
quat_lattice_init(&lat);
|
||||
quat_alg_elem_init(&elem);
|
||||
|
||||
ibz_set(&lat.denom, 60);
|
||||
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);
|
||||
|
||||
for (int i = 0; i <= 10; i++) {
|
||||
int prng = quat_lattice_random_elem(&elem, &lat, 3);
|
||||
assert(prng);
|
||||
res |= !quat_lattice_contains_without_alg(&elem.coord, &lat, &elem);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
res |= !(ibz_get(&elem.coord[j]) < (1 << 2));
|
||||
res |= !(-(1 << 2) <= ibz_get(&elem.coord[j]));
|
||||
}
|
||||
}
|
||||
|
||||
quat_lattice_finalize(&lat);
|
||||
quat_alg_elem_finalize(&elem);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_random_elem failed\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//void quat_lattice_right_transporter(quat_lattice_t *trans, const quat_lattice_t *lat1, const quat_lattice_t *lat1)
|
||||
int quat_test_lattice_right_transporter_hnf(){
|
||||
int res = 0;
|
||||
|
||||
quat_alg_t alg;
|
||||
quat_lattice_t lat1, lat2, trans, exp;
|
||||
quat_alg_init_set_ui(&alg, 103);
|
||||
quat_lattice_init(&lat1);
|
||||
quat_lattice_init(&lat2);
|
||||
quat_lattice_init(&trans);
|
||||
quat_lattice_init(&exp);
|
||||
|
||||
ibz_set(&lat1.basis[0][0], 9);
|
||||
ibz_set(&lat1.basis[0][1], 4);
|
||||
ibz_set(&lat1.basis[0][2], 7);
|
||||
ibz_set(&lat1.basis[1][1], 12);
|
||||
ibz_set(&lat1.basis[1][3], 6);
|
||||
ibz_set(&lat1.basis[2][2], 8);
|
||||
ibz_set(&lat1.basis[2][3], 3);
|
||||
ibz_set(&lat1.basis[3][3], 3);
|
||||
ibz_set(&lat1.denom, 11);
|
||||
|
||||
quat_lattice_mul(&lat2, &lat1, &lat1, &alg);
|
||||
quat_lattice_right_transporter(&trans, &lat1, &lat2, &alg);
|
||||
|
||||
ibz_set(&exp.basis[0][0], 1);
|
||||
ibz_set(&exp.basis[1][1], 12);
|
||||
ibz_set(&exp.basis[1][3], 6);
|
||||
ibz_set(&exp.basis[2][2], 8);
|
||||
ibz_set(&exp.basis[2][3], 3);
|
||||
ibz_set(&exp.basis[3][3], 3);
|
||||
ibz_set(&exp.denom, 11);
|
||||
|
||||
res |= !quat_lattice_equal(&trans, &exp);
|
||||
|
||||
ibz_set(&(alg.p),19);
|
||||
ibz_set(&(alg.gram[2][2]),19);
|
||||
ibz_set(&(alg.gram[3][3]),19);
|
||||
ibz_set(&lat1.basis[0][0], -12);
|
||||
ibz_set(&lat1.basis[0][1], 60);
|
||||
ibz_set(&lat1.basis[0][2], 42);
|
||||
ibz_set(&lat1.basis[0][3], 60);
|
||||
ibz_set(&lat1.basis[1][0], 9);
|
||||
ibz_set(&lat1.basis[1][1], 24);
|
||||
ibz_set(&lat1.basis[1][2], 0);
|
||||
ibz_set(&lat1.basis[1][3], -21);
|
||||
ibz_set(&lat1.basis[2][0], 0);
|
||||
ibz_set(&lat1.basis[2][1], -18);
|
||||
ibz_set(&lat1.basis[2][2], 27);
|
||||
ibz_set(&lat1.basis[2][3], 3);
|
||||
ibz_set(&lat1.basis[3][0], 0);
|
||||
ibz_set(&lat1.basis[3][1], 0);
|
||||
ibz_set(&lat1.basis[3][2], 15);
|
||||
ibz_set(&lat1.basis[3][3], 3);
|
||||
ibz_set(&lat1.denom, 15);
|
||||
|
||||
quat_lattice_hnf(&lat1);
|
||||
quat_lattice_reduce_denom(&lat1, &lat1);
|
||||
quat_lattice_mul(&lat2, &lat1, &lat1, &alg);
|
||||
quat_lattice_right_transporter(&trans, &lat1, &lat2, &alg);
|
||||
ibz_mat_4x4_zero(&(exp.basis));
|
||||
ibz_set(&exp.basis[0][0], 2);
|
||||
ibz_set(&exp.basis[1][1], 1);
|
||||
ibz_set(&exp.basis[2][2], 2);
|
||||
ibz_set(&exp.basis[2][3], 1);
|
||||
ibz_set(&exp.basis[3][3], 1);
|
||||
ibz_set(&exp.denom, 5);
|
||||
|
||||
res |= !quat_lattice_equal(&trans, &exp);
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test lattice_right_transporter_hnf failed\n");
|
||||
}
|
||||
quat_alg_finalize(&alg);
|
||||
quat_lattice_finalize(&lat1);
|
||||
quat_lattice_finalize(&lat2);
|
||||
quat_lattice_finalize(&trans);
|
||||
quat_lattice_finalize(&exp);
|
||||
return(res);
|
||||
}
|
||||
|
||||
|
||||
// run all previous tests
|
||||
int quat_test_lattice(){
|
||||
int res = 0;
|
||||
printf("\nRunning quaternion tests of lattice functions\n");
|
||||
res = res | quat_test_lattice_equal();
|
||||
res = res | quat_test_lattice_reduce_denom();
|
||||
res = res | quat_test_lattice_dual_without_hnf();
|
||||
res = res | quat_test_lattice_add();
|
||||
res = res | quat_test_lattice_intersect();
|
||||
res = res | quat_test_lattice_mul();
|
||||
res = res | quat_test_lattice_contains_without_alg();
|
||||
res = res | quat_test_lattice_contains();
|
||||
res = res | quat_test_lattice_index();
|
||||
res = res | quat_test_lattice_hnf();
|
||||
res = res | quat_test_lattice_lll();
|
||||
res = res | quat_test_lattice_random_elem();
|
||||
res = res | quat_test_lattice_right_transporter_hnf();
|
||||
return(res);
|
||||
}
|
||||
218
src/quaternion/ref/generic/test/matkermod.c
Normal file
218
src/quaternion/ref/generic/test/matkermod.c
Normal file
@@ -0,0 +1,218 @@
|
||||
#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);
|
||||
}
|
||||
188
src/quaternion/ref/generic/test/quaternion_tests.h
Normal file
188
src/quaternion/ref/generic/test/quaternion_tests.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/** @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
|
||||
762
src/quaternion/ref/generic/test/randomized.c
Normal file
762
src/quaternion/ref/generic/test/randomized.c
Normal file
@@ -0,0 +1,762 @@
|
||||
#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 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);
|
||||
ibz_mat_2x2_init(&a);
|
||||
ibz_mat_2x2_init(&inv);
|
||||
ibz_mat_2x2_init(&prod);
|
||||
ibz_mat_2x2_init(&id);
|
||||
ibz_mat_2x2_set(&id, 1, 0, 0, 1);
|
||||
|
||||
|
||||
for (int iter = 0; iter < 100; 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;
|
||||
}
|
||||
ibz_set(&m,rand_m);
|
||||
|
||||
// compute det
|
||||
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)){
|
||||
// matrix should be invertible mod m
|
||||
if (ibz_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
|
||||
{
|
||||
res = 1;
|
||||
}
|
||||
} else {
|
||||
res = res || ibz_2x2_inv_mod(&inv, &a, &m);
|
||||
}
|
||||
}
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
printf("Quaternion unit test with randomization for ibz_mat_2x2_inv_mod failed\n");
|
||||
}
|
||||
ibz_mat_2x2_finalize(&a);
|
||||
ibz_mat_2x2_finalize(&inv);
|
||||
ibz_mat_2x2_finalize(&prod);
|
||||
ibz_mat_2x2_finalize(&id);
|
||||
ibz_finalize(&m);
|
||||
ibz_finalize(&det);
|
||||
ibz_finalize(&gcd);
|
||||
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()
|
||||
{
|
||||
// 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;
|
||||
ibz_t det;
|
||||
ibz_mat_4x4_t mat, inv;
|
||||
ibz_mat_4x4_t det_id, prod;
|
||||
ibz_mat_4x4_init(&det_id);
|
||||
ibz_mat_4x4_init(&prod);
|
||||
ibz_init(&det);
|
||||
ibz_mat_4x4_init(&mat);
|
||||
ibz_mat_4x4_init(&inv);
|
||||
|
||||
for (int r = 0; r < 10; 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);
|
||||
} 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_mul(&prod, &inv, &mat);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
ibz_mat_4x4_finalize(&mat);
|
||||
ibz_mat_4x4_finalize(&inv);
|
||||
ibz_finalize(&det);
|
||||
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(){
|
||||
// only tests the case where the element is in the lattice
|
||||
int res = 0;
|
||||
ibz_t det;
|
||||
quat_alg_elem_t x, cmp;
|
||||
quat_alg_coord_t coord;
|
||||
quat_lattice_t lat;
|
||||
uint64_t rand_denom;
|
||||
int64_t rand[5][4];
|
||||
ibz_init(&det);
|
||||
quat_alg_coord_init(&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));
|
||||
}
|
||||
|
||||
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);
|
||||
res = res || !quat_alg_elem_is_zero(&cmp);
|
||||
} else {
|
||||
res = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test with randomization for lattice_contains_without_alg failed\n");
|
||||
}
|
||||
ibz_finalize(&det);
|
||||
quat_alg_coord_finalize(&coord);
|
||||
quat_alg_elem_finalize(&x);
|
||||
quat_alg_elem_finalize(&cmp);
|
||||
quat_lattice_finalize(&lat);
|
||||
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(){
|
||||
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;
|
||||
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
|
||||
rand_fact = 0;
|
||||
while(rand_fact == 0) {
|
||||
int randret = randombytes((unsigned char*)&rand_fact, sizeof(uint64_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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
//(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);
|
||||
}
|
||||
}
|
||||
|
||||
if (res != 0){
|
||||
printf("Quaternion unit test with randomization for ibz_cornacchia_extended failed\n");
|
||||
}
|
||||
ibz_finalize(&x);
|
||||
ibz_finalize(&y);
|
||||
ibz_finalize(&n);
|
||||
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 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);
|
||||
}
|
||||
20
src/quaternion/ref/generic/test/test_quaternions.c
Normal file
20
src/quaternion/ref/generic/test/test_quaternions.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "quaternion_tests.h"
|
||||
|
||||
// run all tests in module
|
||||
int main(){
|
||||
int res = 0;
|
||||
printf("Running quaternion module unit tests\n");
|
||||
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_algebra();
|
||||
res = res | quat_test_lattice();
|
||||
res = res | quat_test_lideal();
|
||||
res = res | quat_test_with_randomization();
|
||||
if(res != 0){
|
||||
printf("\nSome tests failed!\n");
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
Reference in New Issue
Block a user