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:
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);
|
||||
}
|
||||
Reference in New Issue
Block a user