Co-authored-by: Marius A. Aardal <marius.andre.aardal@gmail.com> Co-authored-by: Gora Adj <gora.adj@tii.ae> Co-authored-by: Diego F. Aranha <dfaranha@cs.au.dk> Co-authored-by: Andrea Basso <sqisign@andreabasso.com> Co-authored-by: Isaac Andrés Canales Martínez <icanalesm0500@gmail.com> Co-authored-by: Jorge Chávez-Saab <jorgechavezsaab@gmail.com> Co-authored-by: Maria Corte-Real Santos <mariascrsantos98@gmail.com> Co-authored-by: Luca De Feo <github@defeo.lu> Co-authored-by: Max Duparc <max.duparc@epfl.ch> Co-authored-by: Jonathan Komada Eriksen <jonathan.eriksen97@gmail.com> Co-authored-by: Décio Luiz Gazzoni Filho <decio@decpp.net> Co-authored-by: Basil Hess <bhe@zurich.ibm.com> Co-authored-by: Antonin Leroux <antonin.leroux@polytechnique.org> Co-authored-by: Patrick Longa <plonga@microsoft.com> Co-authored-by: Luciano Maino <mainoluciano.96@gmail.com> Co-authored-by: Michael Meyer <michael@random-oracles.org> Co-authored-by: Hiroshi Onuki <onuki@mist.i.u-tokyo.ac.jp> Co-authored-by: Lorenz Panny <lorenz@yx7.cc> Co-authored-by: Giacomo Pope <giacomopope@gmail.com> Co-authored-by: Krijn Reijnders <reijnderskrijn@gmail.com> Co-authored-by: Damien Robert <damien.robert@inria.fr> Co-authored-by: Francisco Rodríguez-Henriquez <francisco.rodriguez@tii.ae> Co-authored-by: Sina Schaeffler <sschaeffle@student.ethz.ch> Co-authored-by: Benjamin Wesolowski <benjamin.wesolowski@ens-lyon.fr>
183 lines
4.9 KiB
C
183 lines
4.9 KiB
C
#include "hnf_internal.h"
|
|
#include "internal.h"
|
|
|
|
// Small helper for integers
|
|
void
|
|
ibz_mod_not_zero(ibz_t *res, const ibz_t *x, const ibz_t *mod)
|
|
{
|
|
ibz_t m, t;
|
|
ibz_init(&m);
|
|
ibz_init(&t);
|
|
ibz_mod(&m, x, mod);
|
|
ibz_set(&t, ibz_is_zero(&m));
|
|
ibz_mul(&t, &t, mod);
|
|
ibz_add(res, &m, &t);
|
|
ibz_finalize(&m);
|
|
ibz_finalize(&t);
|
|
}
|
|
|
|
// centered and rather positive then negative
|
|
void
|
|
ibz_centered_mod(ibz_t *remainder, const ibz_t *a, const ibz_t *mod)
|
|
{
|
|
assert(ibz_cmp(mod, &ibz_const_zero) > 0);
|
|
ibz_t tmp, d, t;
|
|
ibz_init(&tmp);
|
|
ibz_init(&d);
|
|
ibz_init(&t);
|
|
ibz_div_floor(&d, &tmp, mod, &ibz_const_two);
|
|
ibz_mod_not_zero(&tmp, a, mod);
|
|
ibz_set(&t, ibz_cmp(&tmp, &d) > 0);
|
|
ibz_mul(&t, &t, mod);
|
|
ibz_sub(remainder, &tmp, &t);
|
|
ibz_finalize(&tmp);
|
|
ibz_finalize(&d);
|
|
ibz_finalize(&t);
|
|
}
|
|
|
|
// if c, res = x, else res = y
|
|
void
|
|
ibz_conditional_assign(ibz_t *res, const ibz_t *x, const ibz_t *y, int c)
|
|
{
|
|
ibz_t s, t, r;
|
|
ibz_init(&r);
|
|
ibz_init(&s);
|
|
ibz_init(&t);
|
|
ibz_set(&s, c != 0);
|
|
ibz_sub(&t, &ibz_const_one, &s);
|
|
ibz_mul(&r, &s, x);
|
|
ibz_mul(res, &t, y);
|
|
ibz_add(res, &r, res);
|
|
ibz_finalize(&r);
|
|
ibz_finalize(&s);
|
|
ibz_finalize(&t);
|
|
}
|
|
|
|
// mpz_gcdext specification specifies unique outputs used here
|
|
void
|
|
ibz_xgcd_with_u_not_0(ibz_t *d, ibz_t *u, ibz_t *v, const ibz_t *x, const ibz_t *y)
|
|
{
|
|
if (ibz_is_zero(x) & ibz_is_zero(y)) {
|
|
ibz_set(d, 1);
|
|
ibz_set(u, 1);
|
|
ibz_set(v, 0);
|
|
return;
|
|
}
|
|
ibz_t q, r, x1, y1;
|
|
ibz_init(&q);
|
|
ibz_init(&r);
|
|
ibz_init(&x1);
|
|
ibz_init(&y1);
|
|
ibz_copy(&x1, x);
|
|
ibz_copy(&y1, y);
|
|
|
|
// xgcd
|
|
ibz_xgcd(d, u, v, &x1, &y1);
|
|
|
|
// make sure u!=0 (v can be 0 if needed)
|
|
// following GMP specification, u == 0 implies y|x
|
|
if (ibz_is_zero(u)) {
|
|
if (!ibz_is_zero(&x1)) {
|
|
if (ibz_is_zero(&y1)) {
|
|
ibz_set(&y1, 1);
|
|
}
|
|
ibz_div(&q, &r, &x1, &y1);
|
|
assert(ibz_is_zero(&r));
|
|
ibz_sub(v, v, &q);
|
|
}
|
|
ibz_set(u, 1);
|
|
}
|
|
if (!ibz_is_zero(&x1)) {
|
|
// Make sure ux > 0 (and as small as possible)
|
|
assert(ibz_cmp(d, &ibz_const_zero) > 0);
|
|
ibz_mul(&r, &x1, &y1);
|
|
int neg = ibz_cmp(&r, &ibz_const_zero) < 0;
|
|
ibz_mul(&q, &x1, u);
|
|
while (ibz_cmp(&q, &ibz_const_zero) <= 0) {
|
|
ibz_div(&q, &r, &y1, d);
|
|
assert(ibz_is_zero(&r));
|
|
if (neg) {
|
|
ibz_neg(&q, &q);
|
|
}
|
|
ibz_add(u, u, &q);
|
|
ibz_div(&q, &r, &x1, d);
|
|
assert(ibz_is_zero(&r));
|
|
if (neg) {
|
|
ibz_neg(&q, &q);
|
|
}
|
|
ibz_sub(v, v, &q);
|
|
|
|
ibz_mul(&q, &x1, u);
|
|
}
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
int res = 0;
|
|
ibz_t sum, prod, test, cmp;
|
|
ibz_init(&sum);
|
|
ibz_init(&prod);
|
|
ibz_init(&cmp);
|
|
ibz_init(&test);
|
|
// sign correct
|
|
res = res | !(ibz_cmp(d, &ibz_const_zero) >= 0);
|
|
if (ibz_is_zero(&x1) && ibz_is_zero(&y1)) {
|
|
res = res | !(ibz_is_zero(v) && ibz_is_one(u) && ibz_is_one(d));
|
|
} else {
|
|
if (!ibz_is_zero(&x1) && !ibz_is_zero(&y1)) {
|
|
// GCD divides x
|
|
ibz_div(&sum, &prod, &x1, d);
|
|
res = res | !ibz_is_zero(&prod);
|
|
// Small enough
|
|
ibz_mul(&prod, &x1, u);
|
|
res = res | !(ibz_cmp(&prod, &ibz_const_zero) > 0);
|
|
ibz_mul(&sum, &sum, &y1);
|
|
ibz_abs(&sum, &sum);
|
|
res = res | !(ibz_cmp(&prod, &sum) <= 0);
|
|
|
|
// GCD divides y
|
|
ibz_div(&sum, &prod, &y1, d);
|
|
res = res | !ibz_is_zero(&prod);
|
|
// Small enough
|
|
ibz_mul(&prod, &y1, v);
|
|
res = res | !(ibz_cmp(&prod, &ibz_const_zero) <= 0);
|
|
ibz_mul(&sum, &sum, &x1);
|
|
ibz_abs(&sum, &sum);
|
|
res = res | !(ibz_cmp(&prod, &sum) < 0);
|
|
} else {
|
|
// GCD divides x
|
|
ibz_div(&sum, &prod, &x1, d);
|
|
res = res | !ibz_is_zero(&prod);
|
|
// GCD divides y
|
|
ibz_div(&sum, &prod, &y1, d);
|
|
res = res | !ibz_is_zero(&prod);
|
|
if (ibz_is_zero(&x1) && !ibz_is_zero(&y1)) {
|
|
ibz_abs(&prod, v);
|
|
res = res | !(ibz_is_one(&prod));
|
|
res = res | !(ibz_is_one(u));
|
|
} else {
|
|
ibz_abs(&prod, u);
|
|
res = res | !(ibz_is_one(&prod));
|
|
res = res | !(ibz_is_zero(v));
|
|
}
|
|
}
|
|
|
|
// Bezout coeffs
|
|
ibz_mul(&sum, &x1, u);
|
|
ibz_mul(&prod, &y1, v);
|
|
ibz_add(&sum, &sum, &prod);
|
|
res = res | !(ibz_cmp(&sum, d) == 0);
|
|
}
|
|
assert(!res);
|
|
ibz_finalize(&sum);
|
|
ibz_finalize(&prod);
|
|
ibz_finalize(&cmp);
|
|
ibz_finalize(&test);
|
|
|
|
#endif
|
|
|
|
ibz_finalize(&x1);
|
|
ibz_finalize(&y1);
|
|
ibz_finalize(&q);
|
|
ibz_finalize(&r);
|
|
}
|