Files
sqisign_new/src/quaternion/ref/generic/dim2.c
SQIsign team 28ff420dd0 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>
2023-07-09 12:48:54 +02:00

554 lines
20 KiB
C

#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);
}