+
+uint32_t
+ec_recover_y(fp2_t *y, const fp2_t *Px, const ec_curve_t *curve)
+{ // Recover y-coordinate of a point on the Montgomery curve y^2 = x^3 + Ax^2 + x
+ fp2_t t0;
+
+ fp2_sqr(&t0, Px);
+ fp2_mul(y, &t0, &curve->A); // Ax^2
+ fp2_add(y, y, Px); // Ax^2 + x
+ fp2_mul(&t0, &t0, Px);
+ fp2_add(y, y, &t0); // x^3 + Ax^2 + x
+ // This is required, because we do not yet know that our curves are
+ // supersingular so our points live on the twist with B = 1.
+ return fp2_sqrt_verify(y);
+}
+
+static void
+difference_point(ec_point_t *PQ, const ec_point_t *P, const ec_point_t *Q, const ec_curve_t *curve)
+{
+ // Given P,Q in projective x-only, computes a deterministic choice for (P-Q)
+ // Based on Proposition 3 of https://eprint.iacr.org/2017/518.pdf
+
+ fp2_t Bxx, Bxz, Bzz, t0, t1;
+
+ fp2_mul(&t0, &P->x, &Q->x);
+ fp2_mul(&t1, &P->z, &Q->z);
+ fp2_sub(&Bxx, &t0, &t1);
+ fp2_sqr(&Bxx, &Bxx);
+ fp2_mul(&Bxx, &Bxx, &curve->C); // C*(P.x*Q.x-P.z*Q.z)^2
+ fp2_add(&Bxz, &t0, &t1);
+ fp2_mul(&t0, &P->x, &Q->z);
+ fp2_mul(&t1, &P->z, &Q->x);
+ fp2_add(&Bzz, &t0, &t1);
+ fp2_mul(&Bxz, &Bxz, &Bzz); // (P.x*Q.x+P.z*Q.z)(P.x*Q.z+P.z*Q.x)
+ fp2_sub(&Bzz, &t0, &t1);
+ fp2_sqr(&Bzz, &Bzz);
+ fp2_mul(&Bzz, &Bzz, &curve->C); // C*(P.x*Q.z-P.z*Q.x)^2
+ fp2_mul(&Bxz, &Bxz, &curve->C); // C*(P.x*Q.x+P.z*Q.z)(P.x*Q.z+P.z*Q.x)
+ fp2_mul(&t0, &t0, &t1);
+ fp2_mul(&t0, &t0, &curve->A);
+ fp2_add(&t0, &t0, &t0);
+ fp2_add(&Bxz, &Bxz, &t0); // C*(P.x*Q.x+P.z*Q.z)(P.x*Q.z+P.z*Q.x) + 2*A*P.x*Q.z*P.z*Q.x
+
+ // To ensure that the denominator is a fourth power in Fp, we normalize by
+ // C*C_bar^2*(P.z)_bar^2*(Q.z)_bar^2
+ fp_copy(&t0.re, &curve->C.re);
+ fp_neg(&t0.im, &curve->C.im);
+ fp2_sqr(&t0, &t0);
+ fp2_mul(&t0, &t0, &curve->C);
+ fp_copy(&t1.re, &P->z.re);
+ fp_neg(&t1.im, &P->z.im);
+ fp2_sqr(&t1, &t1);
+ fp2_mul(&t0, &t0, &t1);
+ fp_copy(&t1.re, &Q->z.re);
+ fp_neg(&t1.im, &Q->z.im);
+ fp2_sqr(&t1, &t1);
+ fp2_mul(&t0, &t0, &t1);
+ fp2_mul(&Bxx, &Bxx, &t0);
+ fp2_mul(&Bxz, &Bxz, &t0);
+ fp2_mul(&Bzz, &Bzz, &t0);
+
+ // Solving quadratic equation
+ fp2_sqr(&t0, &Bxz);
+ fp2_mul(&t1, &Bxx, &Bzz);
+ fp2_sub(&t0, &t0, &t1);
+ // No need to check if t0 is square, as per the entangled basis algorithm.
+ fp2_sqrt(&t0);
+ fp2_add(&PQ->x, &Bxz, &t0);
+ fp2_copy(&PQ->z, &Bzz);
+}
+
+// Lifts a basis x(P), x(Q), x(P-Q) assuming the curve has (A/C : 1) and the point
+// P = (X/Z : 1). For generic implementation see lift_basis()
+uint32_t
+lift_basis_normalized(jac_point_t *P, jac_point_t *Q, ec_basis_t *B, ec_curve_t *E)
+{
+ assert(fp2_is_one(&B->P.z));
+ assert(fp2_is_one(&E->C));
+
+ fp2_copy(&P->x, &B->P.x);
+ fp2_copy(&Q->x, &B->Q.x);
+ fp2_copy(&Q->z, &B->Q.z);
+ fp2_set_one(&P->z);
+ uint32_t ret = ec_recover_y(&P->y, &P->x, E);
+
+ // Algorithm of Okeya-Sakurai to recover y.Q in the montgomery model
+ fp2_t v1, v2, v3, v4;
+ fp2_mul(&v1, &P->x, &Q->z);
+ fp2_add(&v2, &Q->x, &v1);
+ fp2_sub(&v3, &Q->x, &v1);
+ fp2_sqr(&v3, &v3);
+ fp2_mul(&v3, &v3, &B->PmQ.x);
+ fp2_add(&v1, &E->A, &E->A);
+ fp2_mul(&v1, &v1, &Q->z);
+ fp2_add(&v2, &v2, &v1);
+ fp2_mul(&v4, &P->x, &Q->x);
+ fp2_add(&v4, &v4, &Q->z);
+ fp2_mul(&v2, &v2, &v4);
+ fp2_mul(&v1, &v1, &Q->z);
+ fp2_sub(&v2, &v2, &v1);
+ fp2_mul(&v2, &v2, &B->PmQ.z);
+ fp2_sub(&Q->y, &v3, &v2);
+ fp2_add(&v1, &P->y, &P->y);
+ fp2_mul(&v1, &v1, &Q->z);
+ fp2_mul(&v1, &v1, &B->PmQ.z);
+ fp2_mul(&Q->x, &Q->x, &v1);
+ fp2_mul(&Q->z, &Q->z, &v1);
+
+ // Transforming to a jacobian coordinate
+ fp2_sqr(&v1, &Q->z);
+ fp2_mul(&Q->y, &Q->y, &v1);
+ fp2_mul(&Q->x, &Q->x, &Q->z);
+ return ret;
+}
+
+uint32_t
+lift_basis(jac_point_t *P, jac_point_t *Q, ec_basis_t *B, ec_curve_t *E)
+{
+ // Normalise the curve E such that (A : C) is (A/C : 1)
+ // and the point x(P) = (X/Z : 1).
+ fp2_t inverses[2];
+ fp2_copy(&inverses[0], &B->P.z);
+ fp2_copy(&inverses[1], &E->C);
+
+ fp2_batched_inv(inverses, 2);
+ fp2_set_one(&B->P.z);
+ fp2_set_one(&E->C);
+
+ fp2_mul(&B->P.x, &B->P.x, &inverses[0]);
+ fp2_mul(&E->A, &E->A, &inverses[1]);
+
+ // Lift the basis to Jacobian points P, Q
+ return lift_basis_normalized(P, Q, B, E);
+}
+
+// Given an x-coordinate, determines if this is a valid
+// point on the curve. Assumes C=1.
+static uint32_t
+is_on_curve(const fp2_t *x, const ec_curve_t *curve)
+{
+ assert(fp2_is_one(&curve->C));
+ fp2_t t0;
+
+ fp2_add(&t0, x, &curve->A); // x + (A/C)
+ fp2_mul(&t0, &t0, x); // x^2 + (A/C)*x
+ fp2_add_one(&t0, &t0); // x^2 + (A/C)*x + 1
+ fp2_mul(&t0, &t0, x); // x^3 + (A/C)*x^2 + x
+
+ return fp2_is_square(&t0);
+}
+
+// Helper function which given a point of order k*2^n with n maximal
+// and k odd, computes a point of order 2^f
+static inline void
+clear_cofactor_for_maximal_even_order(ec_point_t *P, ec_curve_t *curve, int f)
+{
+ // clear out the odd cofactor to get a point of order 2^n
+ ec_mul(P, p_cofactor_for_2f, P_COFACTOR_FOR_2F_BITLENGTH, P, curve);
+
+ // clear the power of two to get a point of order 2^f
+ for (int i = 0; i < TORSION_EVEN_POWER - f; i++) {
+ xDBL_A24(P, P, &curve->A24, curve->is_A24_computed_and_normalized);
+ }
+}
+
+// Helper function which finds an NQR -1 / (1 + i*b) for entangled basis generation
+static uint8_t
+find_nqr_factor(fp2_t *x, ec_curve_t *curve, const uint8_t start)
+{
+ // factor = -1/(1 + i*b) for b in Fp will be NQR whenever 1 + b^2 is NQR
+ // in Fp, so we find one of these and then invert (1 + i*b). We store b
+ // as a u8 hint to save time in verification.
+
+ // We return the hint as a u8, but use (uint16_t)n to give 2^16 - 1
+ // to make failure cryptographically negligible, with a fallback when
+ // n > 128 is required.
+ uint8_t hint;
+ uint32_t found = 0;
+ uint16_t n = start;
+
+ bool qr_b = 1;
+ fp_t b, tmp;
+ fp2_t z, t0, t1;
+
+ do {
+ while (qr_b) {
+ // find b with 1 + b^2 a non-quadratic residue
+ fp_set_small(&tmp, (uint32_t)n * n + 1);
+ qr_b = fp_is_square(&tmp);
+ n++; // keeps track of b = n - 1
+ }
+
+ // for Px := -A/(1 + i*b) to be on the curve
+ // is equivalent to A^2*(z-1) - z^2 NQR for z = 1 + i*b
+ // thus prevents unnecessary inversion pre-check
+
+ // t0 = z - 1 = i*b
+ // t1 = z = 1 + i*b
+ fp_set_small(&b, (uint32_t)n - 1);
+ fp2_set_zero(&t0);
+ fp2_set_one(&z);
+ fp_copy(&z.im, &b);
+ fp_copy(&t0.im, &b);
+
+ // A^2*(z-1) - z^2
+ fp2_sqr(&t1, &curve->A);
+ fp2_mul(&t0, &t0, &t1); // A^2 * (z - 1)
+ fp2_sqr(&t1, &z);
+ fp2_sub(&t0, &t0, &t1); // A^2 * (z - 1) - z^2
+ found = !fp2_is_square(&t0);
+
+ qr_b = 1;
+ } while (!found);
+
+ // set Px to -A/(1 + i*b)
+ fp2_copy(x, &z);
+ fp2_inv(x);
+ fp2_mul(x, x, &curve->A);
+ fp2_neg(x, x);
+
+ /*
+ * With very low probability n will not fit in 7 bits.
+ * We set hint = 0 which signals failure and the need
+ * to generate a value on the fly during verification
+ */
+ hint = n <= 128 ? n - 1 : 0;
+
+ return hint;
+}
+
+// Helper function which finds a point x(P) = n * A
+static uint8_t
+find_nA_x_coord(fp2_t *x, ec_curve_t *curve, const uint8_t start)
+{
+ assert(!fp2_is_square(&curve->A)); // Only to be called when A is a NQR
+
+ // when A is NQR we allow x(P) to be a multiple n*A of A
+ uint8_t n = start;
+ if (n == 1) {
+ fp2_copy(x, &curve->A);
+ } else {
+ fp2_mul_small(x, &curve->A, n);
+ }
+
+ while (!is_on_curve(x, curve)) {
+ fp2_add(x, x, &curve->A);
+ n++;
+ }
+
+ /*
+ * With very low probability (1/2^128), n will not fit in 7 bits.
+ * In this case, we set hint = 0 which signals failure and the need
+ * to generate a value on the fly during verification
+ */
+ uint8_t hint = n < 128 ? n : 0;
+ return hint;
+}
+
+// The entangled basis generation does not allow A = 0
+// so we simply return the one we have already precomputed
+static void
+ec_basis_E0_2f(ec_basis_t *PQ2, ec_curve_t *curve, int f)
+{
+ assert(fp2_is_zero(&curve->A));
+ ec_point_t P, Q;
+
+ // Set P, Q to precomputed (X : 1) values
+ fp2_copy(&P.x, &BASIS_E0_PX);
+ fp2_copy(&Q.x, &BASIS_E0_QX);
+ fp2_set_one(&P.z);
+ fp2_set_one(&Q.z);
+
+ // clear the power of two to get a point of order 2^f
+ for (int i = 0; i < TORSION_EVEN_POWER - f; i++) {
+ xDBL_E0(&P, &P);
+ xDBL_E0(&Q, &Q);
+ }
+
+ // Set P, Q in the basis and compute x(P - Q)
+ copy_point(&PQ2->P, &P);
+ copy_point(&PQ2->Q, &Q);
+ difference_point(&PQ2->PmQ, &P, &Q, curve);
+}
+
+// Computes a basis E[2^f] = where the point Q is above (0 : 0)
+// and stores hints as an array for faster recomputation at a later point
+uint8_t
+ec_curve_to_basis_2f_to_hint(ec_basis_t *PQ2, ec_curve_t *curve, int f)
+{
+ // Normalise (A/C : 1) and ((A + 2)/4 : 1)
+ ec_normalize_curve_and_A24(curve);
+
+ if (fp2_is_zero(&curve->A)) {
+ ec_basis_E0_2f(PQ2, curve, f);
+ return 0;
+ }
+
+ uint8_t hint;
+ bool hint_A = fp2_is_square(&curve->A);
+
+ // Compute the points P, Q
+ ec_point_t P, Q;
+
+ if (!hint_A) {
+ // when A is NQR we allow x(P) to be a multiple n*A of A
+ hint = find_nA_x_coord(&P.x, curve, 1);
+ } else {
+ // when A is QR we instead have to find (1 + b^2) a NQR
+ // such that x(P) = -A / (1 + i*b)
+ hint = find_nqr_factor(&P.x, curve, 1);
+ }
+
+ fp2_set_one(&P.z);
+ fp2_add(&Q.x, &curve->A, &P.x);
+ fp2_neg(&Q.x, &Q.x);
+ fp2_set_one(&Q.z);
+
+ // clear out the odd cofactor to get a point of order 2^f
+ clear_cofactor_for_maximal_even_order(&P, curve, f);
+ clear_cofactor_for_maximal_even_order(&Q, curve, f);
+
+ // compute PmQ, set PmQ to Q to ensure Q above (0,0)
+ difference_point(&PQ2->Q, &P, &Q, curve);
+ copy_point(&PQ2->P, &P);
+ copy_point(&PQ2->PmQ, &Q);
+
+ // Finally, we compress hint_A and hint into a single bytes.
+ // We choose to set the LSB of hint to hint_A
+ assert(hint < 128); // We expect hint to be 7-bits in size
+ return (hint << 1) | hint_A;
+}
+
+// Computes a basis E[2^f] =
where the point Q is above (0 : 0)
+// given the hints as an array for faster basis computation
+int
+ec_curve_to_basis_2f_from_hint(ec_basis_t *PQ2, ec_curve_t *curve, int f, const uint8_t hint)
+{
+ // Normalise (A/C : 1) and ((A + 2)/4 : 1)
+ ec_normalize_curve_and_A24(curve);
+
+ if (fp2_is_zero(&curve->A)) {
+ ec_basis_E0_2f(PQ2, curve, f);
+ return 1;
+ }
+
+ // The LSB of hint encodes whether A is a QR
+ // The remaining 7-bits are used to find a valid x(P)
+ bool hint_A = hint & 1;
+ uint8_t hint_P = hint >> 1;
+
+ // Compute the points P, Q
+ ec_point_t P, Q;
+
+ if (!hint_P) {
+ // When hint_P = 0 it means we did not find a point in 128 attempts
+ // this is very rare and we almost never expect to need this fallback
+ // In either case, we can start with b = 128 to skip testing the known
+ // values which will not work
+ if (!hint_A) {
+ find_nA_x_coord(&P.x, curve, 128);
+ } else {
+ find_nqr_factor(&P.x, curve, 128);
+ }
+ } else {
+ // Otherwise we use the hint to directly find x(P) based on hint_A
+ if (!hint_A) {
+ // when A is NQR, we have found n such that x(P) = n*A
+ fp2_mul_small(&P.x, &curve->A, hint_P);
+ } else {
+ // when A is QR we have found b such that (1 + b^2) is a NQR in
+ // Fp, so we must compute x(P) = -A / (1 + i*b)
+ fp_set_one(&P.x.re);
+ fp_set_small(&P.x.im, hint_P);
+ fp2_inv(&P.x);
+ fp2_mul(&P.x, &P.x, &curve->A);
+ fp2_neg(&P.x, &P.x);
+ }
+ }
+ fp2_set_one(&P.z);
+
+#ifndef NDEBUG
+ int passed = 1;
+ passed = is_on_curve(&P.x, curve);
+ passed &= !fp2_is_square(&P.x);
+
+ if (!passed)
+ return 0;
+#endif
+
+ // set xQ to -xP - A
+ fp2_add(&Q.x, &curve->A, &P.x);
+ fp2_neg(&Q.x, &Q.x);
+ fp2_set_one(&Q.z);
+
+ // clear out the odd cofactor to get a point of order 2^f
+ clear_cofactor_for_maximal_even_order(&P, curve, f);
+ clear_cofactor_for_maximal_even_order(&Q, curve, f);
+
+ // compute PmQ, set PmQ to Q to ensure Q above (0,0)
+ difference_point(&PQ2->Q, &P, &Q, curve);
+ copy_point(&PQ2->P, &P);
+ copy_point(&PQ2->PmQ, &Q);
+
+#ifndef NDEBUG
+ passed &= test_basis_order_twof(PQ2, curve, f);
+
+ if (!passed)
+ return 0;
+#endif
+
+ return 1;
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/bench.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/bench.h
new file mode 100644
index 0000000000..c253825828
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/bench.h
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: Apache-2.0
+#ifndef BENCH_H__
+#define BENCH_H__
+
+#include
+#include
+#include
+#include
+#include
+#if defined(__APPLE__)
+#include "bench_macos.h"
+#endif
+
+#if defined(TARGET_ARM) || defined(TARGET_S390X) || defined(NO_CYCLE_COUNTER)
+#define BENCH_UNIT0 "nanoseconds"
+#define BENCH_UNIT3 "microseconds"
+#define BENCH_UNIT6 "milliseconds"
+#define BENCH_UNIT9 "seconds"
+#else
+#define BENCH_UNIT0 "cycles"
+#define BENCH_UNIT3 "kilocycles"
+#define BENCH_UNIT6 "megacycles"
+#define BENCH_UNIT9 "gigacycles"
+#endif
+
+static inline void
+cpucycles_init(void) {
+#if defined(__APPLE__) && defined(TARGET_ARM64)
+ macos_init_rdtsc();
+#endif
+}
+
+static inline uint64_t
+cpucycles(void)
+{
+#if defined(TARGET_AMD64) || defined(TARGET_X86)
+ uint32_t hi, lo;
+
+ asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
+ return ((uint64_t)lo) | ((uint64_t)hi << 32);
+#elif defined(TARGET_S390X)
+ uint64_t tod;
+ asm volatile("stckf %0\n" : "=Q"(tod) : : "cc");
+ return (tod * 1000 / 4096);
+#elif defined(TARGET_ARM64) && !defined(NO_CYCLE_COUNTER)
+#if defined(__APPLE__)
+ return macos_rdtsc();
+#else
+ uint64_t cycles;
+ asm volatile("mrs %0, PMCCNTR_EL0" : "=r"(cycles));
+ return cycles;
+#endif // __APPLE__
+#else
+ struct timespec time;
+ clock_gettime(CLOCK_REALTIME, &time);
+ return (uint64_t)time.tv_sec * 1000000000 + time.tv_nsec;
+#endif
+}
+
+static inline int
+CMPFUNC(const void *a, const void *b)
+{
+ uint64_t aa = *(uint64_t *)a, bb = *(uint64_t *)b;
+
+ if (aa > bb)
+ return +1;
+ if (aa < bb)
+ return -1;
+ return 0;
+}
+
+static inline uint32_t
+ISQRT(uint64_t x)
+{
+ uint32_t r = 0;
+ for (ssize_t i = 31; i >= 0; --i) {
+ uint32_t s = r + (1 << i);
+ if ((uint64_t)s * s <= x)
+ r = s;
+ }
+ return r;
+}
+
+static inline double
+_TRUNC(uint64_t x)
+{
+ return x / 1000 / 1000.;
+}
+#define _FMT ".3lf"
+#define _UNIT BENCH_UNIT6
+
+#define BENCH_CODE_1(RUNS) \
+ { \
+ const size_t count = (RUNS); \
+ if (!count) \
+ abort(); \
+ uint64_t cycles, cycles1, cycles2; \
+ uint64_t cycles_list[count]; \
+ cycles = 0; \
+ for (size_t i = 0; i < count; ++i) { \
+ cycles1 = cpucycles();
+
+#define BENCH_CODE_2(name) \
+ cycles2 = cpucycles(); \
+ cycles_list[i] = cycles2 - cycles1; \
+ cycles += cycles2 - cycles1; \
+ } \
+ qsort(cycles_list, count, sizeof(uint64_t), CMPFUNC); \
+ uint64_t variance = 0; \
+ for (size_t i = 0; i < count; ++i) { \
+ int64_t off = cycles_list[i] - cycles / count; \
+ variance += off * off; \
+ } \
+ variance /= count; \
+ printf(" %-10s", name); \
+ printf(" | average %9" _FMT " | stddev %9" _FMT, \
+ _TRUNC(cycles / count), \
+ _TRUNC(ISQRT(variance))); \
+ printf(" | median %9" _FMT " | min %9" _FMT " | max %9" _FMT, \
+ _TRUNC(cycles_list[count / 2]), \
+ _TRUNC(cycles_list[0]), \
+ _TRUNC(cycles_list[count - 1])); \
+ printf(" (%s)\n", _UNIT); \
+ }
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/bench_macos.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/bench_macos.h
new file mode 100644
index 0000000000..0494fc85e9
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/bench_macos.h
@@ -0,0 +1,143 @@
+// WARNING: must be run as root on an M1 device
+// WARNING: fragile, uses private apple APIs
+// currently no command line interface, see variables at top of main
+
+/*
+no warranty; use at your own risk - i believe this code needs
+some minor changes to work on some later hardware and/or software revisions,
+which is unsurprising given the use of undocumented, private APIs.
+------------------------------------------------------------------------------
+This code is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2020 Dougall Johnson
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
+
+/*
+ Based on https://github.com/travisdowns/robsize
+ Henry Wong
+ http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/
+ 2014-10-14
+*/
+
+#include
+#include
+#include
+#include
+
+#define KPERF_LIST \
+ /* ret, name, params */ \
+ F(int, kpc_force_all_ctrs_set, int) \
+ F(int, kpc_set_counting, uint32_t) \
+ F(int, kpc_set_thread_counting, uint32_t) \
+ F(int, kpc_set_config, uint32_t, void *) \
+ F(int, kpc_get_thread_counters, int, unsigned int, void *)
+
+#define F(ret, name, ...) \
+ typedef ret name##proc(__VA_ARGS__); \
+ static name##proc *name;
+KPERF_LIST
+#undef F
+
+#define CFGWORD_EL0A64EN_MASK (0x20000)
+
+#define CPMU_CORE_CYCLE 0x02
+
+#define KPC_CLASS_FIXED (0)
+#define KPC_CLASS_CONFIGURABLE (1)
+
+#define COUNTERS_COUNT 10
+#define KPC_MASK ((1u << KPC_CLASS_CONFIGURABLE) | (1u << KPC_CLASS_FIXED))
+static uint64_t g_config[COUNTERS_COUNT];
+static uint64_t g_counters[COUNTERS_COUNT];
+
+static void
+macos_configure_rdtsc()
+{
+ if (kpc_force_all_ctrs_set(1)) {
+ printf("kpc_force_all_ctrs_set failed\n");
+ return;
+ }
+
+ if (kpc_set_config(KPC_MASK, g_config)) {
+ printf("kpc_set_config failed\n");
+ return;
+ }
+
+ if (kpc_set_counting(KPC_MASK)) {
+ printf("kpc_set_counting failed\n");
+ return;
+ }
+
+ if (kpc_set_thread_counting(KPC_MASK)) {
+ printf("kpc_set_thread_counting failed\n");
+ return;
+ }
+}
+
+static void
+macos_init_rdtsc()
+{
+ void *kperf =
+ dlopen("/System/Library/PrivateFrameworks/kperf.framework/Versions/A/kperf", RTLD_LAZY);
+ if (!kperf) {
+ printf("kperf = %p\n", kperf);
+ return;
+ }
+#define F(ret, name, ...) \
+ name = (name##proc *)(intptr_t)(dlsym(kperf, #name)); \
+ if (!name) { \
+ printf("%s = %p\n", #name, (void *)(intptr_t)name); \
+ return; \
+ }
+ KPERF_LIST
+#undef F
+
+ g_config[0] = CPMU_CORE_CYCLE | CFGWORD_EL0A64EN_MASK;
+
+ macos_configure_rdtsc();
+}
+
+static uint64_t
+macos_rdtsc(void)
+{
+ if (kpc_get_thread_counters(0, COUNTERS_COUNT, g_counters)) {
+ printf("kpc_get_thread_counters failed\n");
+ return 1;
+ }
+ return g_counters[2];
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/biextension.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/biextension.c
new file mode 100644
index 0000000000..1df7ab938b
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/biextension.c
@@ -0,0 +1,770 @@
+#include
+#include
+#include
+#include
+
+/*
+ * We implement the biextension arithmetic by using the cubical torsor
+ * representation. For now only implement the 2^e-ladder.
+ *
+ * Warning: cubicalADD is off by a factor x4 with respect to the correct
+ * cubical arithmetic. This does not affect the Weil pairing or the Tate
+ * pairing over F_{p^2} (due to the final exponentiation), but would give
+ * the wrong result if we compute the Tate pairing over F_p.
+ */
+
+// this would be exactly like xADD if PQ was 'antinormalised' as (1,z)
+// Cost: 3M + 2S + 3a + 3s
+// Note: if needed, cubicalDBL is simply xDBL_A24 normalized and
+// costs 3M + 2S + 2a + 2s
+
+static void
+cubicalADD(ec_point_t *R, const ec_point_t *P, const ec_point_t *Q, const fp2_t *ixPQ)
+{
+ fp2_t t0, t1, t2, t3;
+
+ fp2_add(&t0, &P->x, &P->z);
+ fp2_sub(&t1, &P->x, &P->z);
+ fp2_add(&t2, &Q->x, &Q->z);
+ fp2_sub(&t3, &Q->x, &Q->z);
+ fp2_mul(&t0, &t0, &t3);
+ fp2_mul(&t1, &t1, &t2);
+ fp2_add(&t2, &t0, &t1);
+ fp2_sub(&t3, &t0, &t1);
+ fp2_sqr(&R->z, &t3);
+ fp2_sqr(&t2, &t2);
+ fp2_mul(&R->x, ixPQ, &t2);
+}
+
+// Given cubical reps of P, Q and x(P - Q) = (1 : ixPQ)
+// compute P + Q, [2]Q
+// Cost: 6M + 4S + 4a + 4s
+static void
+cubicalDBLADD(ec_point_t *PpQ,
+ ec_point_t *QQ,
+ const ec_point_t *P,
+ const ec_point_t *Q,
+ const fp2_t *ixPQ,
+ const ec_point_t *A24)
+{
+ // A24 = (A+2C/4C: 1)
+ assert(fp2_is_one(&A24->z));
+
+ fp2_t t0, t1, t2, t3;
+
+ fp2_add(&t0, &P->x, &P->z);
+ fp2_sub(&t1, &P->x, &P->z);
+ fp2_add(&PpQ->x, &Q->x, &Q->z);
+ fp2_sub(&t3, &Q->x, &Q->z);
+ fp2_sqr(&t2, &PpQ->x);
+ fp2_sqr(&QQ->z, &t3);
+ fp2_mul(&t0, &t0, &t3);
+ fp2_mul(&t1, &t1, &PpQ->x);
+ fp2_add(&PpQ->x, &t0, &t1);
+ fp2_sub(&t3, &t0, &t1);
+ fp2_sqr(&PpQ->z, &t3);
+ fp2_sqr(&PpQ->x, &PpQ->x);
+ fp2_mul(&PpQ->x, ixPQ, &PpQ->x);
+ fp2_sub(&t3, &t2, &QQ->z);
+ fp2_mul(&QQ->x, &t2, &QQ->z);
+ fp2_mul(&t0, &t3, &A24->x);
+ fp2_add(&t0, &t0, &QQ->z);
+ fp2_mul(&QQ->z, &t0, &t3);
+}
+
+// iterative biextension doubling
+static void
+biext_ladder_2e(uint32_t e,
+ ec_point_t *PnQ,
+ ec_point_t *nQ,
+ const ec_point_t *PQ,
+ const ec_point_t *Q,
+ const fp2_t *ixP,
+ const ec_point_t *A24)
+{
+ copy_point(PnQ, PQ);
+ copy_point(nQ, Q);
+ for (uint32_t i = 0; i < e; i++) {
+ cubicalDBLADD(PnQ, nQ, PnQ, nQ, ixP, A24);
+ }
+}
+
+// Compute the monodromy ratio X/Z above as a (X:Z) point to avoid a division
+// We implicitly use (1,0) as a cubical point above 0_E
+static void
+point_ratio(ec_point_t *R, const ec_point_t *PnQ, const ec_point_t *nQ, const ec_point_t *P)
+{
+ // Sanity tests
+ assert(ec_is_zero(nQ));
+ assert(ec_is_equal(PnQ, P));
+
+ fp2_mul(&R->x, &nQ->x, &P->x);
+ fp2_copy(&R->z, &PnQ->x);
+}
+
+// Compute the cubical translation of P by a point of 2-torsion T
+static void
+translate(ec_point_t *P, const ec_point_t *T)
+{
+ // When we translate, the following three things can happen:
+ // T = (A : 0) then the translation of P should be P
+ // T = (0 : B) then the translation of P = (X : Z) should be (Z : X)
+ // Otherwise T = (A : B) and P translates to (AX - BZ : BX - AZ)
+ // We compute this in constant time by computing the generic case
+ // and then using constant time swaps.
+ fp2_t PX_new, PZ_new;
+
+ {
+ fp2_t t0, t1;
+
+ // PX_new = AX - BZ
+ fp2_mul(&t0, &T->x, &P->x);
+ fp2_mul(&t1, &T->z, &P->z);
+ fp2_sub(&PX_new, &t0, &t1);
+
+ // PZ_new = BX - AZ
+ fp2_mul(&t0, &T->z, &P->x);
+ fp2_mul(&t1, &T->x, &P->z);
+ fp2_sub(&PZ_new, &t0, &t1);
+ }
+
+ // When we have A zero we should return (Z : X)
+ uint32_t TA_is_zero = fp2_is_zero(&T->x);
+ fp2_select(&PX_new, &PX_new, &P->z, TA_is_zero);
+ fp2_select(&PZ_new, &PZ_new, &P->x, TA_is_zero);
+
+ // When we have B zero we should return (X : Z)
+ uint32_t TB_is_zero = fp2_is_zero(&T->z);
+ fp2_select(&PX_new, &PX_new, &P->x, TB_is_zero);
+ fp2_select(&PZ_new, &PZ_new, &P->z, TB_is_zero);
+
+ // Set the point to the desired result
+ fp2_copy(&P->x, &PX_new);
+ fp2_copy(&P->z, &PZ_new);
+}
+
+// Compute the biextension monodromy g_P,Q^{2^g} (in level 1) via the
+// cubical arithmetic of P+2^e Q.
+// The suffix _i means that we are given 1/x(P) as parameter. Warning: to
+// get meaningful result when using the monodromy to compute pairings, we
+// need P, Q, PQ, A24 to be normalised (this is not strictly necessary, but
+// care need to be taken when they are not normalised. Only handle the
+// normalised case for now)
+static void
+monodromy_i(ec_point_t *R, const pairing_params_t *pairing_data, bool swap_PQ)
+{
+ fp2_t ixP;
+ ec_point_t P, Q, PnQ, nQ;
+
+ // When we compute the Weil pairing we need both P + [2^e]Q and
+ // Q + [2^e]P which we can do easily with biext_ladder_2e() below
+ // we use a bool to decide wether to use Q, ixP or P, ixQ in the
+ // ladder and P or Q in translation.
+ if (!swap_PQ) {
+ copy_point(&P, &pairing_data->P);
+ copy_point(&Q, &pairing_data->Q);
+ fp2_copy(&ixP, &pairing_data->ixP);
+ } else {
+ copy_point(&P, &pairing_data->Q);
+ copy_point(&Q, &pairing_data->P);
+ fp2_copy(&ixP, &pairing_data->ixQ);
+ }
+
+ // Compute the biextension ladder P + [2^e]Q
+ biext_ladder_2e(pairing_data->e - 1, &PnQ, &nQ, &pairing_data->PQ, &Q, &ixP, &pairing_data->A24);
+ translate(&PnQ, &nQ);
+ translate(&nQ, &nQ);
+ point_ratio(R, &PnQ, &nQ, &P);
+}
+
+// Normalize the points and also store 1/x(P), 1/x(Q)
+static void
+cubical_normalization(pairing_params_t *pairing_data, const ec_point_t *P, const ec_point_t *Q)
+{
+ fp2_t t[4];
+ fp2_copy(&t[0], &P->x);
+ fp2_copy(&t[1], &P->z);
+ fp2_copy(&t[2], &Q->x);
+ fp2_copy(&t[3], &Q->z);
+ fp2_batched_inv(t, 4);
+
+ // Store PZ / PX and QZ / QX
+ fp2_mul(&pairing_data->ixP, &P->z, &t[0]);
+ fp2_mul(&pairing_data->ixQ, &Q->z, &t[2]);
+
+ // Store x(P), x(Q) normalised to (X/Z : 1)
+ fp2_mul(&pairing_data->P.x, &P->x, &t[1]);
+ fp2_mul(&pairing_data->Q.x, &Q->x, &t[3]);
+ fp2_set_one(&pairing_data->P.z);
+ fp2_set_one(&pairing_data->Q.z);
+}
+
+// Weil pairing, PQ should be P+Q in (X:Z) coordinates
+// We assume the points are normalised correctly
+static void
+weil_n(fp2_t *r, const pairing_params_t *pairing_data)
+{
+ ec_point_t R0, R1;
+ monodromy_i(&R0, pairing_data, true);
+ monodromy_i(&R1, pairing_data, false);
+
+ fp2_mul(r, &R0.x, &R1.z);
+ fp2_inv(r);
+ fp2_mul(r, r, &R0.z);
+ fp2_mul(r, r, &R1.x);
+}
+
+// Weil pairing, PQ should be P+Q in (X:Z) coordinates
+// Normalise the points and call the code above
+// The code will crash (division by 0) if either P or Q is (0:1)
+void
+weil(fp2_t *r, uint32_t e, const ec_point_t *P, const ec_point_t *Q, const ec_point_t *PQ, ec_curve_t *E)
+{
+ pairing_params_t pairing_data;
+ // Construct the structure for the Weil pairing
+ // Set (PX/PZ : 1), (QX : QZ : 1), PZ/PX and QZ/QX
+ pairing_data.e = e;
+ cubical_normalization(&pairing_data, P, Q);
+ copy_point(&pairing_data.PQ, PQ);
+
+ // Ensure the input curve has A24 normalised and store
+ // in a struct
+ ec_curve_normalize_A24(E);
+ copy_point(&pairing_data.A24, &E->A24);
+
+ // Compute the Weil pairing e_(2^n)(P, Q)
+ weil_n(r, &pairing_data);
+}
+
+// two helper functions for reducing the tate pairing
+// clear_cofac clears (p + 1) // 2^f for an Fp2 value
+void
+clear_cofac(fp2_t *r, const fp2_t *a)
+{
+ digit_t exp = *p_cofactor_for_2f;
+ exp >>= 1;
+
+ fp2_t x;
+ fp2_copy(&x, a);
+ fp2_copy(r, a);
+
+ // removes cofac
+ while (exp > 0) {
+ fp2_sqr(r, r);
+ if (exp & 1) {
+ fp2_mul(r, r, &x);
+ }
+ exp >>= 1;
+ }
+}
+
+// applies frobenius a + ib --> a - ib to an fp2 element
+void
+fp2_frob(fp2_t *out, const fp2_t *in)
+{
+ fp_copy(&(out->re), &(in->re));
+ fp_neg(&(out->im), &(in->im));
+}
+
+// reduced Tate pairing, normalizes the points, assumes PQ is P+Q in (X:Z)
+// coordinates. Computes 1/x(P) and 1/x(Q) for efficient cubical ladder
+void
+reduced_tate(fp2_t *r, uint32_t e, const ec_point_t *P, const ec_point_t *Q, const ec_point_t *PQ, ec_curve_t *E)
+{
+ uint32_t e_full = TORSION_EVEN_POWER;
+ uint32_t e_diff = e_full - e;
+ ec_point_t R;
+ pairing_params_t pairing_data;
+
+ // Construct the structure for the Weil pairing
+ // Set (PX/PZ : 1), (QX : QZ : 1), PZ/PX and QZ/QX
+ pairing_data.e = e;
+ cubical_normalization(&pairing_data, P, Q);
+ copy_point(&pairing_data.PQ, PQ);
+
+ // Ensure the input curve has A24 normalised and store
+ // in a struct
+ ec_curve_normalize_A24(E);
+ copy_point(&pairing_data.A24, &E->A24);
+
+ monodromy_i(&R, &pairing_data, true);
+
+ // we get unreduced tate as R.X, R.Z
+ // reduced tate is -(R.Z/R.X)^((p^2 - 1) div 2^f)
+ // we reuse R.X and R.Z to split reduction step ^(p-1) into frobenius and ^-1
+ fp2_t frob, tmp;
+ fp2_copy(&tmp, &R.x);
+ fp2_frob(&frob, &R.x);
+ fp2_mul(&R.x, &R.z, &frob);
+ fp2_frob(&frob, &R.z);
+ fp2_mul(&R.z, &tmp, &frob);
+ fp2_inv(&R.x);
+ fp2_mul(r, &R.x, &R.z);
+
+ clear_cofac(r, r);
+ // clear remaining 2^e_diff
+ for (uint32_t j = 0; j < e_diff; j++) {
+ fp2_sqr(r, r);
+ }
+}
+
+// Functions to compute discrete logs by computing the Weil pairing of points
+// followed by computing the dlog in Fp^2
+// (If we work with full order points, it would be faster to use the Tate
+// pairings rather than the Weil pairings; this is not implemented yet)
+
+// recursive dlog function
+static bool
+fp2_dlog_2e_rec(digit_t *a, long len, fp2_t *pows_f, fp2_t *pows_g, long stacklen)
+{
+ if (len == 0) {
+ // *a = 0;
+ for (int i = 0; i < NWORDS_ORDER; i++) {
+ a[i] = 0;
+ }
+ return true;
+ } else if (len == 1) {
+ if (fp2_is_one(&pows_f[stacklen - 1])) {
+ // a = 0;
+ for (int i = 0; i < NWORDS_ORDER; i++) {
+ a[i] = 0;
+ }
+ for (int i = 0; i < stacklen - 1; ++i) {
+ fp2_sqr(&pows_g[i], &pows_g[i]); // new_g = g^2
+ }
+ return true;
+ } else if (fp2_is_equal(&pows_f[stacklen - 1], &pows_g[stacklen - 1])) {
+ // a = 1;
+ a[0] = 1;
+ for (int i = 1; i < NWORDS_ORDER; i++) {
+ a[i] = 0;
+ }
+ for (int i = 0; i < stacklen - 1; ++i) {
+ fp2_mul(&pows_f[i], &pows_f[i], &pows_g[i]); // new_f = f*g
+ fp2_sqr(&pows_g[i], &pows_g[i]); // new_g = g^2
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ long right = (double)len * 0.5;
+ long left = len - right;
+ pows_f[stacklen] = pows_f[stacklen - 1];
+ pows_g[stacklen] = pows_g[stacklen - 1];
+ for (int i = 0; i < left; i++) {
+ fp2_sqr(&pows_f[stacklen], &pows_f[stacklen]);
+ fp2_sqr(&pows_g[stacklen], &pows_g[stacklen]);
+ }
+ // uint32_t dlp1 = 0, dlp2 = 0;
+ digit_t dlp1[NWORDS_ORDER], dlp2[NWORDS_ORDER];
+ bool ok;
+ ok = fp2_dlog_2e_rec(dlp1, right, pows_f, pows_g, stacklen + 1);
+ if (!ok)
+ return false;
+ ok = fp2_dlog_2e_rec(dlp2, left, pows_f, pows_g, stacklen);
+ if (!ok)
+ return false;
+ // a = dlp1 + 2^right * dlp2
+ multiple_mp_shiftl(dlp2, right, NWORDS_ORDER);
+ mp_add(a, dlp2, dlp1, NWORDS_ORDER);
+
+ return true;
+ }
+}
+
+// compute DLP: compute scal such that f = g^scal with f, 1/g as input
+static bool
+fp2_dlog_2e(digit_t *scal, const fp2_t *f, const fp2_t *g_inverse, int e)
+{
+ long log, len = e;
+ for (log = 0; len > 1; len >>= 1)
+ log++;
+ log += 1;
+
+ fp2_t pows_f[log], pows_g[log];
+ pows_f[0] = *f;
+ pows_g[0] = *g_inverse;
+
+ for (int i = 0; i < NWORDS_ORDER; i++) {
+ scal[i] = 0;
+ }
+
+ bool ok = fp2_dlog_2e_rec(scal, e, pows_f, pows_g, 1);
+ assert(ok);
+
+ return ok;
+}
+
+// Normalize the bases (P, Q), (R, S) and store their inverse
+// and additionally normalise the curve to (A/C : 1)
+static void
+cubical_normalization_dlog(pairing_dlog_params_t *pairing_dlog_data, ec_curve_t *curve)
+{
+ fp2_t t[11];
+ ec_basis_t *PQ = &pairing_dlog_data->PQ;
+ ec_basis_t *RS = &pairing_dlog_data->RS;
+ fp2_copy(&t[0], &PQ->P.x);
+ fp2_copy(&t[1], &PQ->P.z);
+ fp2_copy(&t[2], &PQ->Q.x);
+ fp2_copy(&t[3], &PQ->Q.z);
+ fp2_copy(&t[4], &PQ->PmQ.x);
+ fp2_copy(&t[5], &PQ->PmQ.z);
+ fp2_copy(&t[6], &RS->P.x);
+ fp2_copy(&t[7], &RS->P.z);
+ fp2_copy(&t[8], &RS->Q.x);
+ fp2_copy(&t[9], &RS->Q.z);
+ fp2_copy(&t[10], &curve->C);
+
+ fp2_batched_inv(t, 11);
+
+ fp2_mul(&pairing_dlog_data->ixP, &PQ->P.z, &t[0]);
+ fp2_mul(&PQ->P.x, &PQ->P.x, &t[1]);
+ fp2_set_one(&PQ->P.z);
+
+ fp2_mul(&pairing_dlog_data->ixQ, &PQ->Q.z, &t[2]);
+ fp2_mul(&PQ->Q.x, &PQ->Q.x, &t[3]);
+ fp2_set_one(&PQ->Q.z);
+
+ fp2_mul(&PQ->PmQ.x, &PQ->PmQ.x, &t[5]);
+ fp2_set_one(&PQ->PmQ.z);
+
+ fp2_mul(&pairing_dlog_data->ixR, &RS->P.z, &t[6]);
+ fp2_mul(&RS->P.x, &RS->P.x, &t[7]);
+ fp2_set_one(&RS->P.z);
+
+ fp2_mul(&pairing_dlog_data->ixS, &RS->Q.z, &t[8]);
+ fp2_mul(&RS->Q.x, &RS->Q.x, &t[9]);
+ fp2_set_one(&RS->Q.z);
+
+ fp2_mul(&curve->A, &curve->A, &t[10]);
+ fp2_set_one(&curve->C);
+}
+
+// Given two bases and basis = compute
+// x(P - R), x(P - S), x(R - Q), x(S - Q)
+static void
+compute_difference_points(pairing_dlog_params_t *pairing_dlog_data, ec_curve_t *curve)
+{
+ jac_point_t xyP, xyQ, xyR, xyS, temp;
+
+ // lifting the two basis points, assumes that x(P) and x(R)
+ // and the curve itself are normalised to (X : 1)
+ lift_basis_normalized(&xyP, &xyQ, &pairing_dlog_data->PQ, curve);
+ lift_basis_normalized(&xyR, &xyS, &pairing_dlog_data->RS, curve);
+
+ // computation of the differences
+ // x(P - R)
+ jac_neg(&temp, &xyR);
+ ADD(&temp, &temp, &xyP, curve);
+ jac_to_xz(&pairing_dlog_data->diff.PmR, &temp);
+
+ // x(P - S)
+ jac_neg(&temp, &xyS);
+ ADD(&temp, &temp, &xyP, curve);
+ jac_to_xz(&pairing_dlog_data->diff.PmS, &temp);
+
+ // x(R - Q)
+ jac_neg(&temp, &xyQ);
+ ADD(&temp, &temp, &xyR, curve);
+ jac_to_xz(&pairing_dlog_data->diff.RmQ, &temp);
+
+ // x(S - Q)
+ jac_neg(&temp, &xyQ);
+ ADD(&temp, &temp, &xyS, curve);
+ jac_to_xz(&pairing_dlog_data->diff.SmQ, &temp);
+}
+
+// Inline all the Weil pairing computations needed for ec_dlog_2_weil
+static void
+weil_dlog(digit_t *r1, digit_t *r2, digit_t *s1, digit_t *s2, pairing_dlog_params_t *pairing_dlog_data)
+{
+
+ ec_point_t nP, nQ, nR, nS, nPQ, PnQ, nPR, PnR, nPS, PnS, nRQ, RnQ, nSQ, SnQ;
+
+ copy_point(&nP, &pairing_dlog_data->PQ.P);
+ copy_point(&nQ, &pairing_dlog_data->PQ.Q);
+ copy_point(&nR, &pairing_dlog_data->RS.P);
+ copy_point(&nS, &pairing_dlog_data->RS.Q);
+ copy_point(&nPQ, &pairing_dlog_data->PQ.PmQ);
+ copy_point(&PnQ, &pairing_dlog_data->PQ.PmQ);
+ copy_point(&nPR, &pairing_dlog_data->diff.PmR);
+ copy_point(&nPS, &pairing_dlog_data->diff.PmS);
+ copy_point(&PnR, &pairing_dlog_data->diff.PmR);
+ copy_point(&PnS, &pairing_dlog_data->diff.PmS);
+ copy_point(&nRQ, &pairing_dlog_data->diff.RmQ);
+ copy_point(&nSQ, &pairing_dlog_data->diff.SmQ);
+ copy_point(&RnQ, &pairing_dlog_data->diff.RmQ);
+ copy_point(&SnQ, &pairing_dlog_data->diff.SmQ);
+
+ for (uint32_t i = 0; i < pairing_dlog_data->e - 1; i++) {
+ cubicalADD(&nPQ, &nPQ, &nP, &pairing_dlog_data->ixQ);
+ cubicalADD(&nPR, &nPR, &nP, &pairing_dlog_data->ixR);
+ cubicalDBLADD(&nPS, &nP, &nPS, &nP, &pairing_dlog_data->ixS, &pairing_dlog_data->A24);
+
+ cubicalADD(&PnQ, &PnQ, &nQ, &pairing_dlog_data->ixP);
+ cubicalADD(&RnQ, &RnQ, &nQ, &pairing_dlog_data->ixR);
+ cubicalDBLADD(&SnQ, &nQ, &SnQ, &nQ, &pairing_dlog_data->ixS, &pairing_dlog_data->A24);
+
+ cubicalADD(&PnR, &PnR, &nR, &pairing_dlog_data->ixP);
+ cubicalDBLADD(&nRQ, &nR, &nRQ, &nR, &pairing_dlog_data->ixQ, &pairing_dlog_data->A24);
+
+ cubicalADD(&PnS, &PnS, &nS, &pairing_dlog_data->ixP);
+ cubicalDBLADD(&nSQ, &nS, &nSQ, &nS, &pairing_dlog_data->ixQ, &pairing_dlog_data->A24);
+ }
+
+ // weil(&w0,e,&PQ->P,&PQ->Q,&PQ->PmQ,&A24);
+ translate(&nPQ, &nP);
+ translate(&nPR, &nP);
+ translate(&nPS, &nP);
+ translate(&PnQ, &nQ);
+ translate(&RnQ, &nQ);
+ translate(&SnQ, &nQ);
+ translate(&PnR, &nR);
+ translate(&nRQ, &nR);
+ translate(&PnS, &nS);
+ translate(&nSQ, &nS);
+
+ translate(&nP, &nP);
+ translate(&nQ, &nQ);
+ translate(&nR, &nR);
+ translate(&nS, &nS);
+
+ // computation of the reference weil pairing
+ ec_point_t T0, T1;
+ fp2_t w1[5], w2[5];
+
+ // e(P, Q) = w0
+ point_ratio(&T0, &nPQ, &nP, &pairing_dlog_data->PQ.Q);
+ point_ratio(&T1, &PnQ, &nQ, &pairing_dlog_data->PQ.P);
+ // For the first element we need it's inverse for
+ // fp2_dlog_2e so we swap w1 and w2 here to save inversions
+ fp2_mul(&w2[0], &T0.x, &T1.z);
+ fp2_mul(&w1[0], &T1.x, &T0.z);
+
+ // e(P,R) = w0^r2
+ point_ratio(&T0, &nPR, &nP, &pairing_dlog_data->RS.P);
+ point_ratio(&T1, &PnR, &nR, &pairing_dlog_data->PQ.P);
+ fp2_mul(&w1[1], &T0.x, &T1.z);
+ fp2_mul(&w2[1], &T1.x, &T0.z);
+
+ // e(R,Q) = w0^r1
+ point_ratio(&T0, &nRQ, &nR, &pairing_dlog_data->PQ.Q);
+ point_ratio(&T1, &RnQ, &nQ, &pairing_dlog_data->RS.P);
+ fp2_mul(&w1[2], &T0.x, &T1.z);
+ fp2_mul(&w2[2], &T1.x, &T0.z);
+
+ // e(P,S) = w0^s2
+ point_ratio(&T0, &nPS, &nP, &pairing_dlog_data->RS.Q);
+ point_ratio(&T1, &PnS, &nS, &pairing_dlog_data->PQ.P);
+ fp2_mul(&w1[3], &T0.x, &T1.z);
+ fp2_mul(&w2[3], &T1.x, &T0.z);
+
+ // e(S,Q) = w0^s1
+ point_ratio(&T0, &nSQ, &nS, &pairing_dlog_data->PQ.Q);
+ point_ratio(&T1, &SnQ, &nQ, &pairing_dlog_data->RS.Q);
+ fp2_mul(&w1[4], &T0.x, &T1.z);
+ fp2_mul(&w2[4], &T1.x, &T0.z);
+
+ fp2_batched_inv(w1, 5);
+ for (int i = 0; i < 5; i++) {
+ fp2_mul(&w1[i], &w1[i], &w2[i]);
+ }
+
+ fp2_dlog_2e(r2, &w1[1], &w1[0], pairing_dlog_data->e);
+ fp2_dlog_2e(r1, &w1[2], &w1[0], pairing_dlog_data->e);
+ fp2_dlog_2e(s2, &w1[3], &w1[0], pairing_dlog_data->e);
+ fp2_dlog_2e(s1, &w1[4], &w1[0], pairing_dlog_data->e);
+}
+
+void
+ec_dlog_2_weil(digit_t *r1,
+ digit_t *r2,
+ digit_t *s1,
+ digit_t *s2,
+ ec_basis_t *PQ,
+ const ec_basis_t *RS,
+ ec_curve_t *curve,
+ int e)
+{
+ assert(test_point_order_twof(&PQ->Q, curve, e));
+
+ // precomputing the correct curve data
+ ec_curve_normalize_A24(curve);
+
+ pairing_dlog_params_t pairing_dlog_data;
+ pairing_dlog_data.e = e;
+ pairing_dlog_data.PQ = *PQ;
+ pairing_dlog_data.RS = *RS;
+ pairing_dlog_data.A24 = curve->A24;
+
+ cubical_normalization_dlog(&pairing_dlog_data, curve);
+ compute_difference_points(&pairing_dlog_data, curve);
+
+ weil_dlog(r1, r2, s1, s2, &pairing_dlog_data);
+
+#ifndef NDEBUG
+ ec_point_t test;
+ ec_biscalar_mul(&test, r1, r2, e, PQ, curve);
+ // R = [r1]P + [r2]Q
+ assert(ec_is_equal(&test, &RS->P));
+ ec_biscalar_mul(&test, s1, s2, e, PQ, curve);
+ // S = [s1]P + [s2]Q
+ assert(ec_is_equal(&test, &RS->Q));
+#endif
+}
+
+// Inline all the Tate pairing computations needed for ec_dlog_2_weil
+// including reduction, assumes a bases PQ of full E[2^e_full] torsion
+// and a bases RS of smaller E[2^e] torsion
+static void
+tate_dlog_partial(digit_t *r1, digit_t *r2, digit_t *s1, digit_t *s2, pairing_dlog_params_t *pairing_dlog_data)
+{
+
+ uint32_t e_full = TORSION_EVEN_POWER;
+ uint32_t e_diff = e_full - pairing_dlog_data->e;
+
+ ec_point_t nP, nQ, nR, nS, nPQ, PnR, PnS, nRQ, nSQ;
+
+ copy_point(&nP, &pairing_dlog_data->PQ.P);
+ copy_point(&nQ, &pairing_dlog_data->PQ.Q);
+ copy_point(&nR, &pairing_dlog_data->RS.P);
+ copy_point(&nS, &pairing_dlog_data->RS.Q);
+ copy_point(&nPQ, &pairing_dlog_data->PQ.PmQ);
+ copy_point(&PnR, &pairing_dlog_data->diff.PmR);
+ copy_point(&PnS, &pairing_dlog_data->diff.PmS);
+ copy_point(&nRQ, &pairing_dlog_data->diff.RmQ);
+ copy_point(&nSQ, &pairing_dlog_data->diff.SmQ);
+
+ for (uint32_t i = 0; i < e_full - 1; i++) {
+ cubicalDBLADD(&nPQ, &nP, &nPQ, &nP, &pairing_dlog_data->ixQ, &pairing_dlog_data->A24);
+ }
+
+ for (uint32_t i = 0; i < pairing_dlog_data->e - 1; i++) {
+ cubicalADD(&PnR, &PnR, &nR, &pairing_dlog_data->ixP);
+ cubicalDBLADD(&nRQ, &nR, &nRQ, &nR, &pairing_dlog_data->ixQ, &pairing_dlog_data->A24);
+
+ cubicalADD(&PnS, &PnS, &nS, &pairing_dlog_data->ixP);
+ cubicalDBLADD(&nSQ, &nS, &nSQ, &nS, &pairing_dlog_data->ixQ, &pairing_dlog_data->A24);
+ }
+
+ translate(&nPQ, &nP);
+ translate(&PnR, &nR);
+ translate(&nRQ, &nR);
+ translate(&PnS, &nS);
+ translate(&nSQ, &nS);
+
+ translate(&nP, &nP);
+ translate(&nQ, &nQ);
+ translate(&nR, &nR);
+ translate(&nS, &nS);
+
+ // computation of the reference Tate pairing
+ ec_point_t T0;
+ fp2_t w1[5], w2[5];
+
+ // t(P, Q)^(2^e_diff) = w0
+ point_ratio(&T0, &nPQ, &nP, &pairing_dlog_data->PQ.Q);
+ fp2_copy(&w1[0], &T0.x);
+ fp2_copy(&w2[0], &T0.z);
+
+ // t(R,P) = w0^r2
+ point_ratio(&T0, &PnR, &nR, &pairing_dlog_data->PQ.P);
+ fp2_copy(&w1[1], &T0.x);
+ fp2_copy(&w2[1], &T0.z);
+
+ // t(R,Q) = w0^r1
+ point_ratio(&T0, &nRQ, &nR, &pairing_dlog_data->PQ.Q);
+ fp2_copy(&w2[2], &T0.x);
+ fp2_copy(&w1[2], &T0.z);
+
+ // t(S,P) = w0^s2
+ point_ratio(&T0, &PnS, &nS, &pairing_dlog_data->PQ.P);
+ fp2_copy(&w1[3], &T0.x);
+ fp2_copy(&w2[3], &T0.z);
+
+ // t(S,Q) = w0^s1
+ point_ratio(&T0, &nSQ, &nS, &pairing_dlog_data->PQ.Q);
+ fp2_copy(&w2[4], &T0.x);
+ fp2_copy(&w1[4], &T0.z);
+
+ // batched reduction using projective representation
+ for (int i = 0; i < 5; i++) {
+ fp2_t frob, tmp;
+ fp2_copy(&tmp, &w1[i]);
+ // inline frobenius for ^p
+ // multiply by inverse to get ^(p-1)
+ fp2_frob(&frob, &w1[i]);
+ fp2_mul(&w1[i], &w2[i], &frob);
+
+ // repeat for denom
+ fp2_frob(&frob, &w2[i]);
+ fp2_mul(&w2[i], &tmp, &frob);
+ }
+
+ // batched normalization
+ fp2_batched_inv(w2, 5);
+ for (int i = 0; i < 5; i++) {
+ fp2_mul(&w1[i], &w1[i], &w2[i]);
+ }
+
+ for (int i = 0; i < 5; i++) {
+ clear_cofac(&w1[i], &w1[i]);
+
+ // removes 2^e_diff
+ for (uint32_t j = 0; j < e_diff; j++) {
+ fp2_sqr(&w1[i], &w1[i]);
+ }
+ }
+
+ fp2_dlog_2e(r2, &w1[1], &w1[0], pairing_dlog_data->e);
+ fp2_dlog_2e(r1, &w1[2], &w1[0], pairing_dlog_data->e);
+ fp2_dlog_2e(s2, &w1[3], &w1[0], pairing_dlog_data->e);
+ fp2_dlog_2e(s1, &w1[4], &w1[0], pairing_dlog_data->e);
+}
+
+void
+ec_dlog_2_tate(digit_t *r1,
+ digit_t *r2,
+ digit_t *s1,
+ digit_t *s2,
+ const ec_basis_t *PQ,
+ const ec_basis_t *RS,
+ ec_curve_t *curve,
+ int e)
+{
+ // assume PQ is a full torsion basis
+ // returns a, b, c, d such that R = [a]P + [b]Q, S = [c]P + [d]Q
+
+#ifndef NDEBUG
+ int e_full = TORSION_EVEN_POWER;
+ int e_diff = e_full - e;
+#endif
+ assert(test_basis_order_twof(PQ, curve, e_full));
+
+ // precomputing the correct curve data
+ ec_curve_normalize_A24(curve);
+
+ pairing_dlog_params_t pairing_dlog_data;
+ pairing_dlog_data.e = e;
+ pairing_dlog_data.PQ = *PQ;
+ pairing_dlog_data.RS = *RS;
+ pairing_dlog_data.A24 = curve->A24;
+
+ cubical_normalization_dlog(&pairing_dlog_data, curve);
+ compute_difference_points(&pairing_dlog_data, curve);
+ tate_dlog_partial(r1, r2, s1, s2, &pairing_dlog_data);
+
+#ifndef NDEBUG
+ ec_point_t test;
+ ec_biscalar_mul(&test, r1, r2, e, PQ, curve);
+ ec_dbl_iter(&test, e_diff, &test, curve);
+ // R = [r1]P + [r2]Q
+ assert(ec_is_equal(&test, &RS->P));
+
+ ec_biscalar_mul(&test, s1, s2, e, PQ, curve);
+ ec_dbl_iter(&test, e_diff, &test, curve);
+ // S = [s1]P + [s2]Q
+ assert(ec_is_equal(&test, &RS->Q));
+#endif
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/biextension.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/biextension.h
new file mode 100644
index 0000000000..1a50fcc738
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/biextension.h
@@ -0,0 +1,82 @@
+#ifndef _BIEXT_H_
+#define _BIEXT_H_
+
+#include
+#include
+
+typedef struct pairing_params
+{
+ uint32_t e; // Points have order 2^e
+ ec_point_t P; // x(P)
+ ec_point_t Q; // x(Q)
+ ec_point_t PQ; // x(P-Q) = (PQX/PQZ : 1)
+ fp2_t ixP; // PZ/PX
+ fp2_t ixQ; // QZ/QX
+ ec_point_t A24; // ((A+2)/4 : 1)
+} pairing_params_t;
+
+// For two bases and store:
+// x(P - R), x(P - S), x(R - Q), x(S - Q)
+typedef struct pairing_dlog_diff_points
+{
+ ec_point_t PmR; // x(P - R)
+ ec_point_t PmS; // x(P - S)
+ ec_point_t RmQ; // x(R - Q)
+ ec_point_t SmQ; // x(S - Q)
+} pairing_dlog_diff_points_t;
+
+typedef struct pairing_dlog_params
+{
+ uint32_t e; // Points have order 2^e
+ ec_basis_t PQ; // x(P), x(Q), x(P-Q)
+ ec_basis_t RS; // x(R), x(S), x(R-S)
+ pairing_dlog_diff_points_t diff; // x(P - R), x(P - S), x(R - Q), x(S - Q)
+ fp2_t ixP; // PZ/PX
+ fp2_t ixQ; // QZ/QX
+ fp2_t ixR; // RZ/RX
+ fp2_t ixS; // SZ/SX
+ ec_point_t A24; // ((A+2)/4 : 1)
+} pairing_dlog_params_t;
+
+// Computes e = e_{2^e}(P, Q) using biextension ladder
+void weil(fp2_t *r, uint32_t e, const ec_point_t *P, const ec_point_t *Q, const ec_point_t *PQ, ec_curve_t *E);
+
+// Computes (reduced) z = t_{2^e}(P, Q) using biextension ladder
+void reduced_tate(fp2_t *r, uint32_t e, const ec_point_t *P, const ec_point_t *Q, const ec_point_t *PQ, ec_curve_t *E);
+
+// Given two bases and computes scalars
+// such that R = [r1]P + [r2]Q, S = [s1]P + [s2]Q
+void ec_dlog_2_weil(digit_t *r1,
+ digit_t *r2,
+ digit_t *s1,
+ digit_t *s2,
+ ec_basis_t *PQ,
+ const ec_basis_t *RS,
+ ec_curve_t *curve,
+ int e);
+
+// Given two bases and
+// where is a basis for E[2^f]
+// the full 2-torsion, and a basis
+// for smaller torsion E[2^e]
+// computes scalars r1, r2, s1, s2
+// such that R = [r1]P + [r2]Q, S = [s1]P + [s2]Q
+void ec_dlog_2_tate(digit_t *r1,
+ digit_t *r2,
+ digit_t *s1,
+ digit_t *s2,
+ const ec_basis_t *PQ,
+ const ec_basis_t *RS,
+ ec_curve_t *curve,
+ int e);
+
+void ec_dlog_2_tate_to_full(digit_t *r1,
+ digit_t *r2,
+ digit_t *s1,
+ digit_t *s2,
+ ec_basis_t *PQ,
+ ec_basis_t *RS,
+ ec_curve_t *curve,
+ int e);
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/common.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/common.c
new file mode 100644
index 0000000000..e051ac340a
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/common.c
@@ -0,0 +1,90 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+void
+public_key_init(public_key_t *pk)
+{
+ ec_curve_init(&pk->curve);
+}
+
+void
+public_key_finalize(public_key_t *pk)
+{
+ (void) pk;
+}
+
+// compute the challenge as the hash of the message and the commitment curve and public key
+void
+hash_to_challenge(scalar_t *scalar,
+ const public_key_t *pk,
+ const ec_curve_t *com_curve,
+ const unsigned char *message,
+ size_t length)
+{
+ unsigned char buf[2 * FP2_ENCODED_BYTES];
+ {
+ fp2_t j1, j2;
+ ec_j_inv(&j1, &pk->curve);
+ ec_j_inv(&j2, com_curve);
+ fp2_encode(buf, &j1);
+ fp2_encode(buf + FP2_ENCODED_BYTES, &j2);
+ }
+
+ {
+ // The type scalar_t represents an element of GF(p), which is about
+ // 2*lambda bits, where lambda = 128, 192 or 256, according to the
+ // security level. Thus, the variable scalar should have enough memory
+ // for the values produced by SHAKE256 in the intermediate iterations.
+
+ shake256incctx ctx;
+
+ size_t hash_bytes = ((2 * SECURITY_BITS) + 7) / 8;
+ size_t limbs = (hash_bytes + sizeof(digit_t) - 1) / sizeof(digit_t);
+ size_t bits = (2 * SECURITY_BITS) % RADIX;
+ digit_t mask = ((digit_t)-1) >> ((RADIX - bits) % RADIX);
+#ifdef TARGET_BIG_ENDIAN
+ mask = BSWAP_DIGIT(mask);
+#endif
+
+ shake256_inc_init(&ctx);
+ shake256_inc_absorb(&ctx, buf, 2 * FP2_ENCODED_BYTES);
+ shake256_inc_absorb(&ctx, message, length);
+ shake256_inc_finalize(&ctx);
+ shake256_inc_squeeze((void *)(*scalar), hash_bytes, &ctx);
+ (*scalar)[limbs - 1] &= mask;
+ for (int i = 2; i < HASH_ITERATIONS; i++) {
+ shake256_inc_ctx_reset(&ctx);
+ shake256_inc_absorb(&ctx, (void *)(*scalar), hash_bytes);
+ shake256_inc_finalize(&ctx);
+ shake256_inc_squeeze((void *)(*scalar), hash_bytes, &ctx);
+ (*scalar)[limbs - 1] &= mask;
+ }
+ shake256_inc_ctx_reset(&ctx);
+ shake256_inc_absorb(&ctx, (void *)(*scalar), hash_bytes);
+ shake256_inc_finalize(&ctx);
+
+ hash_bytes = ((TORSION_EVEN_POWER - SQIsign_response_length) + 7) / 8;
+ limbs = (hash_bytes + sizeof(digit_t) - 1) / sizeof(digit_t);
+ bits = (TORSION_EVEN_POWER - SQIsign_response_length) % RADIX;
+ mask = ((digit_t)-1) >> ((RADIX - bits) % RADIX);
+#ifdef TARGET_BIG_ENDIAN
+ mask = BSWAP_DIGIT(mask);
+#endif
+
+ memset(*scalar, 0, NWORDS_ORDER * sizeof(digit_t));
+ shake256_inc_squeeze((void *)(*scalar), hash_bytes, &ctx);
+ shake256_inc_ctx_release(&ctx);
+ (*scalar)[limbs - 1] &= mask;
+
+#ifdef TARGET_BIG_ENDIAN
+ for (int i = 0; i < NWORDS_ORDER; i++)
+ (*scalar)[i] = BSWAP_DIGIT((*scalar)[i]);
+#endif
+
+ mp_mod_2exp(*scalar, SECURITY_BITS, NWORDS_ORDER);
+ }
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/defs.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/defs.h
new file mode 100644
index 0000000000..09bb8b5eba
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/defs.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+* Written by Nir Drucker and Shay Gueron
+* AWS Cryptographic Algorithms Group
+* (ndrucker@amazon.com, gueron@amazon.com)
+*
+* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License").
+* You may not use this file except in compliance with the License.
+* A copy of the License is located at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* or in the "license" file accompanying this file. This file is distributed
+* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+* express or implied. See the License for the specific language governing
+* permissions and limitations under the License.
+* The license is detailed in the file LICENSE.txt, and applies to this file.
+* ***************************************************************************/
+
+#pragma once
+
+#include
+
+#ifdef __cplusplus
+ #define EXTERNC extern "C"
+#else
+ #define EXTERNC
+#endif
+
+// For code clarity.
+#define IN
+#define OUT
+
+#define ALIGN(n) __attribute__((aligned(n)))
+#define _INLINE_ static inline
+
+typedef enum
+{
+ SUCCESS=0,
+ ERROR=1
+} status_t;
+
+#define SUCCESS 0
+#define ERROR 1
+#define GUARD(func) {if(SUCCESS != func) {return ERROR;}}
+
+#if defined(__GNUC__) && __GNUC__ >= 2
+static inline uint32_t CRYPTO_bswap4(uint32_t x) {
+ return __builtin_bswap32(x);
+}
+#endif
+
+_INLINE_ void secure_clean(OUT uint8_t *p, IN const uint32_t len)
+{
+#ifdef _WIN32
+ SecureZeroMemory(p, len);
+#else
+ typedef void *(*memset_t)(void *, int, size_t);
+ static volatile memset_t memset_func = memset;
+ memset_func(p, 0, len);
+#endif
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/dim2.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/dim2.c
new file mode 100644
index 0000000000..5bf214c4e2
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/dim2.c
@@ -0,0 +1,132 @@
+#include
+#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->v[0]), a0);
+ ibz_set(&(vec->v[1]), a1);
+}
+void
+ibz_mat_2x2_set(ibz_mat_2x2_t *mat, int a00, int a01, int a10, int a11)
+{
+ ibz_set(&(mat->m[0][0]), a00);
+ ibz_set(&(mat->m[0][1]), a01);
+ ibz_set(&(mat->m[1][0]), a10);
+ ibz_set(&(mat->m[1][1]), a11);
+}
+
+void
+ibz_mat_2x2_copy(ibz_mat_2x2_t *copy, const ibz_mat_2x2_t *copied)
+{
+ ibz_copy(&(copy->m[0][0]), &(copied->m[0][0]));
+ ibz_copy(&(copy->m[0][1]), &(copied->m[0][1]));
+ ibz_copy(&(copy->m[1][0]), &(copied->m[1][0]));
+ ibz_copy(&(copy->m[1][1]), &(copied->m[1][1]));
+}
+
+void
+ibz_mat_2x2_add(ibz_mat_2x2_t *sum, const ibz_mat_2x2_t *a, const ibz_mat_2x2_t *b)
+{
+ ibz_add(&(sum->m[0][0]), &(a->m[0][0]), &(b->m[0][0]));
+ ibz_add(&(sum->m[0][1]), &(a->m[0][1]), &(b->m[0][1]));
+ ibz_add(&(sum->m[1][0]), &(a->m[1][0]), &(b->m[1][0]));
+ ibz_add(&(sum->m[1][1]), &(a->m[1][1]), &(b->m[1][1]));
+}
+
+void
+ibz_mat_2x2_det_from_ibz(ibz_t *det, const ibz_t *a11, const ibz_t *a12, const ibz_t *a21, const ibz_t *a22)
+{
+ ibz_t prod;
+ ibz_init(&prod);
+ ibz_mul(&prod, a12, a21);
+ ibz_mul(det, a11, a22);
+ ibz_sub(det, det, &prod);
+ ibz_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->m[0][0]), &(vec->v[0]));
+ ibz_copy(&(matvec.v[0]), &prod);
+ ibz_mul(&prod, &(mat->m[0][1]), &(vec->v[1]));
+ ibz_add(&(matvec.v[0]), &(matvec.v[0]), &prod);
+ ibz_mul(&prod, &(mat->m[1][0]), &(vec->v[0]));
+ ibz_copy(&(matvec.v[1]), &prod);
+ ibz_mul(&prod, &(mat->m[1][1]), &(vec->v[1]));
+ ibz_add(&(matvec.v[1]), &(matvec.v[1]), &prod);
+ ibz_copy(&(res->v[0]), &(matvec.v[0]));
+ ibz_copy(&(res->v[1]), &(matvec.v[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.m[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->m[i][k]), &(mat_b->m[k][j]));
+ ibz_add(&(sums.m[i][j]), &(sums.m[i][j]), &mul);
+ ibz_mod(&(sums.m[i][j]), &(sums.m[i][j]), m);
+ }
+ }
+ }
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ ibz_copy(&(prod->m[i][j]), &(sums.m[i][j]));
+ }
+ }
+ ibz_finalize(&mul);
+ ibz_mat_2x2_finalize(&sums);
+}
+
+int
+ibz_mat_2x2_inv_mod(ibz_mat_2x2_t *inv, const ibz_mat_2x2_t *mat, const ibz_t *m)
+{
+ ibz_t det, prod;
+ ibz_init(&det);
+ ibz_init(&prod);
+ ibz_mul(&det, &(mat->m[0][0]), &(mat->m[1][1]));
+ ibz_mod(&det, &det, m);
+ ibz_mul(&prod, &(mat->m[0][1]), &(mat->m[1][0]));
+ ibz_sub(&det, &det, &prod);
+ ibz_mod(&det, &det, m);
+ int res = ibz_invmod(&det, &det, m);
+ // return 0 matrix if non invertible determinant
+ ibz_set(&prod, res);
+ ibz_mul(&det, &det, &prod);
+ // compute inverse
+ ibz_copy(&prod, &(mat->m[0][0]));
+ ibz_copy(&(inv->m[0][0]), &(mat->m[1][1]));
+ ibz_copy(&(inv->m[1][1]), &prod);
+ ibz_neg(&(inv->m[1][0]), &(mat->m[1][0]));
+ ibz_neg(&(inv->m[0][1]), &(mat->m[0][1]));
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ ibz_mul(&(inv->m[i][j]), &(inv->m[i][j]), &det);
+ ibz_mod(&(inv->m[i][j]), &(inv->m[i][j]), m);
+ }
+ }
+ ibz_finalize(&det);
+ ibz_finalize(&prod);
+ return (res);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/dim2id2iso.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/dim2id2iso.c
new file mode 100644
index 0000000000..74184fc97b
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/dim2id2iso.c
@@ -0,0 +1,1172 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int
+_fixed_degree_isogeny_impl(quat_left_ideal_t *lideal,
+ const ibz_t *u,
+ bool small,
+ theta_couple_curve_t *E34,
+ theta_couple_point_t *P12,
+ size_t numP,
+ const int index_alternate_order)
+{
+
+ // var declaration
+ int ret;
+ ibz_t two_pow, tmp;
+ quat_alg_elem_t theta;
+
+ ec_curve_t E0;
+ copy_curve(&E0, &CURVES_WITH_ENDOMORPHISMS[index_alternate_order].curve);
+ ec_curve_normalize_A24(&E0);
+
+ unsigned length;
+
+ int u_bitsize = ibz_bitsize(u);
+
+ // deciding the power of 2 of the dim2 isogeny we use for this
+ // the smaller the faster, but if it set too low there is a risk that
+ // RepresentInteger will fail
+ if (!small) {
+ // in that case, we just set it to be the biggest value possible
+ length = TORSION_EVEN_POWER - HD_extra_torsion;
+ } else {
+ length = ibz_bitsize(&QUATALG_PINFTY.p) + QUAT_repres_bound_input - u_bitsize;
+ assert(u_bitsize < (int)length);
+ assert(length < TORSION_EVEN_POWER - HD_extra_torsion);
+ }
+ assert(length);
+
+ // var init
+ ibz_init(&two_pow);
+ ibz_init(&tmp);
+ quat_alg_elem_init(&theta);
+
+ ibz_pow(&two_pow, &ibz_const_two, length);
+ ibz_copy(&tmp, u);
+ assert(ibz_cmp(&two_pow, &tmp) > 0);
+ assert(!ibz_is_even(&tmp));
+
+ // computing the endomorphism theta of norm u * (2^(length) - u)
+ ibz_sub(&tmp, &two_pow, &tmp);
+ ibz_mul(&tmp, &tmp, u);
+ assert(!ibz_is_even(&tmp));
+
+ // setting-up the quat_represent_integer_params
+ quat_represent_integer_params_t ri_params;
+ ri_params.primality_test_iterations = QUAT_represent_integer_params.primality_test_iterations;
+
+ quat_p_extremal_maximal_order_t order_hnf;
+ quat_alg_elem_init(&order_hnf.z);
+ quat_alg_elem_copy(&order_hnf.z, &EXTREMAL_ORDERS[index_alternate_order].z);
+ quat_alg_elem_init(&order_hnf.t);
+ quat_alg_elem_copy(&order_hnf.t, &EXTREMAL_ORDERS[index_alternate_order].t);
+ quat_lattice_init(&order_hnf.order);
+ ibz_copy(&order_hnf.order.denom, &EXTREMAL_ORDERS[index_alternate_order].order.denom);
+ ibz_mat_4x4_copy(&order_hnf.order.basis, &EXTREMAL_ORDERS[index_alternate_order].order.basis);
+ order_hnf.q = EXTREMAL_ORDERS[index_alternate_order].q;
+ ri_params.order = &order_hnf;
+ ri_params.algebra = &QUATALG_PINFTY;
+
+#ifndef NDEBUG
+ assert(quat_lattice_contains(NULL, &ri_params.order->order, &ri_params.order->z));
+ assert(quat_lattice_contains(NULL, &ri_params.order->order, &ri_params.order->t));
+#endif
+
+ ret = quat_represent_integer(&theta, &tmp, 1, &ri_params);
+
+ assert(!ibz_is_even(&tmp));
+
+ if (!ret) {
+ printf("represent integer failed for the alternate order number %d and for "
+ "a target of "
+ "size %d for a u of size %d with length = "
+ "%u \n",
+ index_alternate_order,
+ ibz_bitsize(&tmp),
+ ibz_bitsize(u),
+ length);
+ goto cleanup;
+ }
+ quat_lideal_create(lideal, &theta, u, &order_hnf.order, &QUATALG_PINFTY);
+
+ quat_alg_elem_finalize(&order_hnf.z);
+ quat_alg_elem_finalize(&order_hnf.t);
+ quat_lattice_finalize(&order_hnf.order);
+
+#ifndef NDEBUG
+ ibz_t test_norm, test_denom;
+ ibz_init(&test_denom);
+ ibz_init(&test_norm);
+ quat_alg_norm(&test_norm, &test_denom, &theta, &QUATALG_PINFTY);
+ assert(ibz_is_one(&test_denom));
+ assert(ibz_cmp(&test_norm, &tmp) == 0);
+ assert(!ibz_is_even(&tmp));
+ assert(quat_lattice_contains(NULL, &EXTREMAL_ORDERS[index_alternate_order].order, &theta));
+ ibz_finalize(&test_norm);
+ ibz_finalize(&test_denom);
+#endif
+
+ ec_basis_t B0_two;
+ // copying the basis
+ copy_basis(&B0_two, &CURVES_WITH_ENDOMORPHISMS[index_alternate_order].basis_even);
+ assert(test_basis_order_twof(&B0_two, &E0, TORSION_EVEN_POWER));
+ ec_dbl_iter_basis(&B0_two, TORSION_EVEN_POWER - length - HD_extra_torsion, &B0_two, &E0);
+
+ assert(test_basis_order_twof(&B0_two, &E0, length + HD_extra_torsion));
+
+ // now we set-up the kernel
+ theta_couple_point_t T1;
+ theta_couple_point_t T2, T1m2;
+
+ copy_point(&T1.P1, &B0_two.P);
+ copy_point(&T2.P1, &B0_two.Q);
+ copy_point(&T1m2.P1, &B0_two.PmQ);
+
+ // multiplication of theta by (u)^-1 mod 2^(length+2)
+ ibz_mul(&two_pow, &two_pow, &ibz_const_two);
+ ibz_mul(&two_pow, &two_pow, &ibz_const_two);
+ ibz_copy(&tmp, u);
+ ibz_invmod(&tmp, &tmp, &two_pow);
+ assert(!ibz_is_even(&tmp));
+
+ ibz_mul(&theta.coord.v[0], &theta.coord.v[0], &tmp);
+ ibz_mul(&theta.coord.v[1], &theta.coord.v[1], &tmp);
+ ibz_mul(&theta.coord.v[2], &theta.coord.v[2], &tmp);
+ ibz_mul(&theta.coord.v[3], &theta.coord.v[3], &tmp);
+
+ // applying theta to the basis
+ ec_basis_t B0_two_theta;
+ copy_basis(&B0_two_theta, &B0_two);
+ endomorphism_application_even_basis(&B0_two_theta, index_alternate_order, &E0, &theta, length + HD_extra_torsion);
+
+ // Ensure the basis we're using has the expected order
+ assert(test_basis_order_twof(&B0_two_theta, &E0, length + HD_extra_torsion));
+
+ // Set-up the domain E0 x E0
+ theta_couple_curve_t E00;
+ E00.E1 = E0;
+ E00.E2 = E0;
+
+ // Set-up the kernel from the bases
+ theta_kernel_couple_points_t dim_two_ker;
+ copy_bases_to_kernel(&dim_two_ker, &B0_two, &B0_two_theta);
+
+ ret = theta_chain_compute_and_eval(length, &E00, &dim_two_ker, true, E34, P12, numP);
+ if (!ret)
+ goto cleanup;
+
+ assert(length);
+ ret = (int)length;
+
+cleanup:
+ // var finalize
+ ibz_finalize(&two_pow);
+ ibz_finalize(&tmp);
+ quat_alg_elem_finalize(&theta);
+
+ return ret;
+}
+
+int
+fixed_degree_isogeny_and_eval(quat_left_ideal_t *lideal,
+ const ibz_t *u,
+ bool small,
+ theta_couple_curve_t *E34,
+ theta_couple_point_t *P12,
+ size_t numP,
+ const int index_alternate_order)
+{
+ return _fixed_degree_isogeny_impl(lideal, u, small, E34, P12, numP, index_alternate_order);
+}
+
+// takes the output of LLL and apply some small treatment on the basis
+// reordering vectors and switching some signs if needed to make it in a nicer
+// shape
+static void
+post_LLL_basis_treatment(ibz_mat_4x4_t *gram, ibz_mat_4x4_t *reduced, bool is_special_order)
+{
+ // if the left order is the special one, then we apply some additional post
+ // treatment
+ if (is_special_order) {
+ // reordering the basis if needed
+ if (ibz_cmp(&gram->m[0][0], &gram->m[2][2]) == 0) {
+ for (int i = 0; i < 4; i++) {
+ ibz_swap(&reduced->m[i][1], &reduced->m[i][2]);
+ }
+ ibz_swap(&gram->m[0][2], &gram->m[0][1]);
+ ibz_swap(&gram->m[2][0], &gram->m[1][0]);
+ ibz_swap(&gram->m[3][2], &gram->m[3][1]);
+ ibz_swap(&gram->m[2][3], &gram->m[1][3]);
+ ibz_swap(&gram->m[2][2], &gram->m[1][1]);
+ } else if (ibz_cmp(&gram->m[0][0], &gram->m[3][3]) == 0) {
+ for (int i = 0; i < 4; i++) {
+ ibz_swap(&reduced->m[i][1], &reduced->m[i][3]);
+ }
+ ibz_swap(&gram->m[0][3], &gram->m[0][1]);
+ ibz_swap(&gram->m[3][0], &gram->m[1][0]);
+ ibz_swap(&gram->m[2][3], &gram->m[2][1]);
+ ibz_swap(&gram->m[3][2], &gram->m[1][2]);
+ ibz_swap(&gram->m[3][3], &gram->m[1][1]);
+ } else if (ibz_cmp(&gram->m[1][1], &gram->m[3][3]) == 0) {
+ // in this case it seems that we need to swap the second and third
+ // element, and then recompute entirely the second element from the first
+ // first we swap the second and third element
+ for (int i = 0; i < 4; i++) {
+ ibz_swap(&reduced->m[i][1], &reduced->m[i][2]);
+ }
+ ibz_swap(&gram->m[0][2], &gram->m[0][1]);
+ ibz_swap(&gram->m[2][0], &gram->m[1][0]);
+ ibz_swap(&gram->m[3][2], &gram->m[3][1]);
+ ibz_swap(&gram->m[2][3], &gram->m[1][3]);
+ ibz_swap(&gram->m[2][2], &gram->m[1][1]);
+ }
+
+ // adjusting the sign if needed
+ if (ibz_cmp(&reduced->m[0][0], &reduced->m[1][1]) != 0) {
+ for (int i = 0; i < 4; i++) {
+ ibz_neg(&reduced->m[i][1], &reduced->m[i][1]);
+ ibz_neg(&gram->m[i][1], &gram->m[i][1]);
+ ibz_neg(&gram->m[1][i], &gram->m[1][i]);
+ }
+ }
+ if (ibz_cmp(&reduced->m[0][2], &reduced->m[1][3]) != 0) {
+ for (int i = 0; i < 4; i++) {
+ ibz_neg(&reduced->m[i][3], &reduced->m[i][3]);
+ ibz_neg(&gram->m[i][3], &gram->m[i][3]);
+ ibz_neg(&gram->m[3][i], &gram->m[3][i]);
+ }
+ // assert(ibz_cmp(&reduced->m[0][2],&reduced->m[1][3])==0);
+ }
+ }
+}
+
+// enumerate all vectors in an hypercube of norm m for the infinity norm
+// with respect to a basis whose gram matrix is given by gram
+// Returns an int `count`, the number of vectors found with the desired
+// properties
+static int
+enumerate_hypercube(ibz_vec_4_t *vecs, ibz_t *norms, int m, const ibz_mat_4x4_t *gram, const ibz_t *adjusted_norm)
+{
+
+ ibz_t remain, norm;
+ ibz_vec_4_t point;
+
+ ibz_init(&remain);
+ ibz_init(&norm);
+ ibz_vec_4_init(&point);
+
+ assert(m > 0);
+
+ int count = 0;
+ int dim = 2 * m + 1;
+ int dim2 = dim * dim;
+ int dim3 = dim2 * dim;
+
+ // if the basis is of the form alpha, i*alpha, beta, i*beta
+ // we can remove some values due to symmetry of the basis that
+ bool need_remove_symmetry =
+ (ibz_cmp(&gram->m[0][0], &gram->m[1][1]) == 0 && ibz_cmp(&gram->m[3][3], &gram->m[2][2]) == 0);
+
+ int check1, check2, check3;
+
+ // Enumerate over points in a hypercube with coordinates (x, y, z, w)
+ for (int x = -m; x <= 0; x++) { // We only check non-positive x-values
+ for (int y = -m; y < m + 1; y++) {
+ // Once x = 0 we only consider non-positive y values
+ if (x == 0 && y > 0) {
+ break;
+ }
+ for (int z = -m; z < m + 1; z++) {
+ // If x and y are both zero, we only consider non-positive z values
+ if (x == 0 && y == 0 && z > 0) {
+ break;
+ }
+ for (int w = -m; w < m + 1; w++) {
+ // If x, y, z are all zero, we only consider negative w values
+ if (x == 0 && y == 0 && z == 0 && w >= 0) {
+ break;
+ }
+
+ // Now for each candidate (x, y, z, w) we need to check a number of
+ // conditions We have already filtered for symmetry with several break
+ // statements, but there are more checks.
+
+ // 1. We do not allow all (x, y, z, w) to be multiples of 2
+ // 2. We do not allow all (x, y, z, w) to be multiples of 3
+ // 3. We do not want elements of the same norm, so we quotient out the
+ // action
+ // of a group of order four generated by i for a basis expected to
+ // be of the form: [gamma, i gamma, beta, i beta ].
+
+ // Ensure that not all values are even
+ if (!((x | y | z | w) & 1)) {
+ continue;
+ }
+ // Ensure that not all values are multiples of three
+ if (x % 3 == 0 && y % 3 == 0 && z % 3 == 0 && w % 3 == 0) {
+ continue;
+ }
+
+ check1 = (m + w) + dim * (m + z) + dim2 * (m + y) + dim3 * (m + x);
+ check2 = (m - z) + dim * (m + w) + dim2 * (m - x) + dim3 * (m + y);
+ check3 = (m + z) + dim * (m - w) + dim2 * (m + x) + dim3 * (m - y);
+
+ // either the basis does not have symmetry and we are good,
+ // or there is a special symmetry that we can exploit
+ // and we ensure that we don't record the same norm in the list
+ if (!need_remove_symmetry || (check1 <= check2 && check1 <= check3)) {
+ // Set the point as a vector (x, y, z, w)
+ ibz_set(&point.v[0], x);
+ ibz_set(&point.v[1], y);
+ ibz_set(&point.v[2], z);
+ ibz_set(&point.v[3], w);
+
+ // Evaluate this through the gram matrix and divide out by the
+ // adjusted_norm
+ quat_qf_eval(&norm, gram, &point);
+ ibz_div(&norm, &remain, &norm, adjusted_norm);
+ assert(ibz_is_zero(&remain));
+
+ if (ibz_mod_ui(&norm, 2) == 1) {
+ ibz_set(&vecs[count].v[0], x);
+ ibz_set(&vecs[count].v[1], y);
+ ibz_set(&vecs[count].v[2], z);
+ ibz_set(&vecs[count].v[3], w);
+ ibz_copy(&norms[count], &norm);
+ count++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ibz_finalize(&remain);
+ ibz_finalize(&norm);
+ ibz_vec_4_finalize(&point);
+
+ return count - 1;
+}
+
+// enumerate through the two list given in input to find to integer d1,d2 such
+// that there exists u,v with u d1 + v d2 = target the bool is diagonal
+// indicates if the two lists are the same
+static int
+find_uv_from_lists(ibz_t *au,
+ ibz_t *bu,
+ ibz_t *av,
+ ibz_t *bv,
+ ibz_t *u,
+ ibz_t *v,
+ int *index_sol1,
+ int *index_sol2,
+ const ibz_t *target,
+ const ibz_t *small_norms1,
+ const ibz_t *small_norms2,
+ const ibz_t *quotients,
+ const int index1,
+ const int index2,
+ const int is_diagonal,
+ const int number_sum_square)
+{
+
+ ibz_t n, remain, adjusted_norm;
+ ibz_init(&n);
+ ibz_init(&remain);
+ ibz_init(&adjusted_norm);
+
+ int found = 0;
+ int cmp;
+ ibz_copy(&n, target);
+
+ // enumerating through the list
+ for (int i1 = 0; i1 < index1; i1++) {
+ ibz_mod(&adjusted_norm, &n, &small_norms1[i1]);
+ int starting_index2;
+ if (is_diagonal) {
+ starting_index2 = i1;
+ } else {
+ starting_index2 = 0;
+ }
+ for (int i2 = starting_index2; i2 < index2; i2++) {
+ // u = target / d1 mod d2
+ if (!ibz_invmod(&remain, &small_norms2[i2], &small_norms1[i1])) {
+ continue;
+ }
+ ibz_mul(v, &remain, &adjusted_norm);
+ ibz_mod(v, v, &small_norms1[i1]);
+ cmp = ibz_cmp(v, "ients[i2]);
+ while (!found && cmp < 0) {
+ if (number_sum_square > 0) {
+ found = ibz_cornacchia_prime(av, bv, &ibz_const_one, v);
+ } else if (number_sum_square == 0) {
+ found = 1;
+ }
+ if (found) {
+ ibz_mul(&remain, v, &small_norms2[i2]);
+ ibz_copy(au, &n);
+ ibz_sub(u, au, &remain);
+ assert(ibz_cmp(u, &ibz_const_zero) > 0);
+ ibz_div(u, &remain, u, &small_norms1[i1]);
+ assert(ibz_is_zero(&remain));
+ // we want to remove weird cases where u,v have big power of two
+ found = found && (ibz_get(u) != 0 && ibz_get(v) != 0);
+ if (number_sum_square == 2) {
+ found = ibz_cornacchia_prime(au, bu, &ibz_const_one, u);
+ }
+ }
+ if (!found) {
+ ibz_add(v, v, &small_norms1[i1]);
+ cmp = ibz_cmp(v, "ients[i2]);
+ }
+ }
+
+ if (found) {
+ // copying the indices
+ *index_sol1 = i1;
+ *index_sol2 = i2;
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+
+ ibz_finalize(&n);
+ ibz_finalize(&remain);
+ ibz_finalize(&adjusted_norm);
+
+ return found;
+}
+
+struct vec_and_norm
+{
+ ibz_vec_4_t vec;
+ ibz_t norm;
+ int idx;
+};
+
+static int
+compare_vec_by_norm(const void *_first, const void *_second)
+{
+ const struct vec_and_norm *first = _first, *second = _second;
+ int res = ibz_cmp(&first->norm, &second->norm);
+ if (res != 0)
+ return res;
+ else
+ return first->idx - second->idx;
+}
+
+// use several special curves
+// we assume that the first one is always j=1728
+int
+find_uv(ibz_t *u,
+ ibz_t *v,
+ quat_alg_elem_t *beta1,
+ quat_alg_elem_t *beta2,
+ ibz_t *d1,
+ ibz_t *d2,
+ int *index_alternate_order_1,
+ int *index_alternate_order_2,
+ const ibz_t *target,
+ const quat_left_ideal_t *lideal,
+ const quat_alg_t *Bpoo,
+ int num_alternate_order)
+
+{
+
+ // variable declaration & init
+ ibz_vec_4_t vec;
+ ibz_t n;
+ ibz_t au, bu, av, bv;
+ ibz_t norm_d;
+ ibz_t remain;
+ ibz_init(&au);
+ ibz_init(&bu);
+ ibz_init(&av);
+ ibz_init(&bv);
+ ibz_init(&norm_d);
+ ibz_init(&n);
+ ibz_vec_4_init(&vec);
+ ibz_init(&remain);
+
+ ibz_copy(&n, target);
+
+ ibz_t adjusted_norm[num_alternate_order + 1];
+ ibz_mat_4x4_t gram[num_alternate_order + 1], reduced[num_alternate_order + 1];
+ quat_left_ideal_t ideal[num_alternate_order + 1];
+
+ for (int i = 0; i < num_alternate_order + 1; i++) {
+ ibz_init(&adjusted_norm[i]);
+ ibz_mat_4x4_init(&gram[i]);
+ ibz_mat_4x4_init(&reduced[i]);
+ quat_left_ideal_init(&ideal[i]);
+ }
+
+ // first we reduce the ideal given in input
+ quat_lideal_copy(&ideal[0], lideal);
+ quat_lideal_reduce_basis(&reduced[0], &gram[0], &ideal[0], Bpoo);
+
+ ibz_mat_4x4_copy(&ideal[0].lattice.basis, &reduced[0]);
+ ibz_set(&adjusted_norm[0], 1);
+ ibz_mul(&adjusted_norm[0], &adjusted_norm[0], &ideal[0].lattice.denom);
+ ibz_mul(&adjusted_norm[0], &adjusted_norm[0], &ideal[0].lattice.denom);
+ post_LLL_basis_treatment(&gram[0], &reduced[0], true);
+
+ // for efficient lattice reduction, we replace ideal[0] by the equivalent
+ // ideal of smallest norm
+ quat_left_ideal_t reduced_id;
+ quat_left_ideal_init(&reduced_id);
+ quat_lideal_copy(&reduced_id, &ideal[0]);
+ quat_alg_elem_t delta;
+ // delta will be the element of smallest norm
+ quat_alg_elem_init(&delta);
+ ibz_set(&delta.coord.v[0], 1);
+ ibz_set(&delta.coord.v[1], 0);
+ ibz_set(&delta.coord.v[2], 0);
+ ibz_set(&delta.coord.v[3], 0);
+ ibz_copy(&delta.denom, &reduced_id.lattice.denom);
+ ibz_mat_4x4_eval(&delta.coord, &reduced[0], &delta.coord);
+ assert(quat_lattice_contains(NULL, &reduced_id.lattice, &delta));
+
+ // reduced_id = ideal[0] * \overline{delta}/n(ideal[0])
+ quat_alg_conj(&delta, &delta);
+ ibz_mul(&delta.denom, &delta.denom, &ideal[0].norm);
+ quat_lattice_alg_elem_mul(&reduced_id.lattice, &reduced_id.lattice, &delta, Bpoo);
+ ibz_copy(&reduced_id.norm, &gram[0].m[0][0]);
+ ibz_div(&reduced_id.norm, &remain, &reduced_id.norm, &adjusted_norm[0]);
+ assert(ibz_cmp(&remain, &ibz_const_zero) == 0);
+
+ // and conj_ideal is the conjugate of reduced_id
+ // init the right order;
+ quat_lattice_t right_order;
+ quat_lattice_init(&right_order);
+ // computing the conjugate
+ quat_left_ideal_t conj_ideal;
+ quat_left_ideal_init(&conj_ideal);
+ quat_lideal_conjugate_without_hnf(&conj_ideal, &right_order, &reduced_id, Bpoo);
+
+ // computing all the other connecting ideals and reducing them
+ for (int i = 1; i < num_alternate_order + 1; i++) {
+ quat_lideal_lideal_mul_reduced(&ideal[i], &gram[i], &conj_ideal, &ALTERNATE_CONNECTING_IDEALS[i - 1], Bpoo);
+ ibz_mat_4x4_copy(&reduced[i], &ideal[i].lattice.basis);
+ ibz_set(&adjusted_norm[i], 1);
+ ibz_mul(&adjusted_norm[i], &adjusted_norm[i], &ideal[i].lattice.denom);
+ ibz_mul(&adjusted_norm[i], &adjusted_norm[i], &ideal[i].lattice.denom);
+ post_LLL_basis_treatment(&gram[i], &reduced[i], false);
+ }
+
+ // enumerating small vectors
+
+ // global parameters for the enumeration
+ int m = FINDUV_box_size;
+ int m4 = FINDUV_cube_size;
+
+ ibz_vec_4_t small_vecs[num_alternate_order + 1][m4];
+ ibz_t small_norms[num_alternate_order + 1][m4];
+ ibz_vec_4_t alternate_small_vecs[num_alternate_order + 1][m4];
+ ibz_t alternate_small_norms[num_alternate_order + 1][m4];
+ ibz_t quotients[num_alternate_order + 1][m4];
+ int indices[num_alternate_order + 1];
+
+ for (int j = 0; j < num_alternate_order + 1; j++) {
+ for (int i = 0; i < m4; i++) {
+ ibz_init(&small_norms[j][i]);
+ ibz_vec_4_init(&small_vecs[j][i]);
+ ibz_init(&alternate_small_norms[j][i]);
+ ibz_init("ients[j][i]);
+ ibz_vec_4_init(&alternate_small_vecs[j][i]);
+ }
+ // enumeration in the hypercube of norm m
+ indices[j] = enumerate_hypercube(small_vecs[j], small_norms[j], m, &gram[j], &adjusted_norm[j]);
+
+ // sorting the list
+ {
+ struct vec_and_norm small_vecs_and_norms[indices[j]];
+ for (int i = 0; i < indices[j]; ++i) {
+ memcpy(&small_vecs_and_norms[i].vec, &small_vecs[j][i], sizeof(ibz_vec_4_t));
+ memcpy(&small_vecs_and_norms[i].norm, &small_norms[j][i], sizeof(ibz_t));
+ small_vecs_and_norms[i].idx = i;
+ }
+ qsort(small_vecs_and_norms, indices[j], sizeof(*small_vecs_and_norms), compare_vec_by_norm);
+ for (int i = 0; i < indices[j]; ++i) {
+ memcpy(&small_vecs[j][i], &small_vecs_and_norms[i].vec, sizeof(ibz_vec_4_t));
+ memcpy(&small_norms[j][i], &small_vecs_and_norms[i].norm, sizeof(ibz_t));
+ }
+#ifndef NDEBUG
+ for (int i = 1; i < indices[j]; ++i)
+ assert(ibz_cmp(&small_norms[j][i - 1], &small_norms[j][i]) <= 0);
+#endif
+ }
+
+ for (int i = 0; i < indices[j]; i++) {
+ ibz_div("ients[j][i], &remain, &n, &small_norms[j][i]);
+ }
+ }
+
+ int found = 0;
+ int i1;
+ int i2;
+ for (int j1 = 0; j1 < num_alternate_order + 1; j1++) {
+ for (int j2 = j1; j2 < num_alternate_order + 1; j2++) {
+ // in this case, there are some small adjustements to make
+ int is_diago = (j1 == j2);
+ found = find_uv_from_lists(&au,
+ &bu,
+ &av,
+ &bv,
+ u,
+ v,
+ &i1,
+ &i2,
+ target,
+ small_norms[j1],
+ small_norms[j2],
+ quotients[j2],
+ indices[j1],
+ indices[j2],
+ is_diago,
+ 0);
+ // }
+
+ if (found) {
+ // recording the solutions that we found
+ ibz_copy(&beta1->denom, &ideal[j1].lattice.denom);
+ ibz_copy(&beta2->denom, &ideal[j2].lattice.denom);
+ ibz_copy(d1, &small_norms[j1][i1]);
+ ibz_copy(d2, &small_norms[j2][i2]);
+ ibz_mat_4x4_eval(&beta1->coord, &reduced[j1], &small_vecs[j1][i1]);
+ ibz_mat_4x4_eval(&beta2->coord, &reduced[j2], &small_vecs[j2][i2]);
+ assert(quat_lattice_contains(NULL, &ideal[j1].lattice, beta1));
+ assert(quat_lattice_contains(NULL, &ideal[j2].lattice, beta2));
+ if (j1 != 0 || j2 != 0) {
+ ibz_div(&delta.denom, &remain, &delta.denom, &lideal->norm);
+ assert(ibz_cmp(&remain, &ibz_const_zero) == 0);
+ ibz_mul(&delta.denom, &delta.denom, &conj_ideal.norm);
+ }
+ if (j1 != 0) {
+ // we send back beta1 to the original ideal
+ quat_alg_mul(beta1, &delta, beta1, Bpoo);
+ quat_alg_normalize(beta1);
+ }
+ if (j2 != 0) {
+ // we send back beta2 to the original ideal
+ quat_alg_mul(beta2, &delta, beta2, Bpoo);
+ quat_alg_normalize(beta2);
+ }
+
+ // if the selected element belong to an alternate order, we conjugate it
+ if (j1 != 0) {
+ quat_alg_conj(beta1, beta1);
+ }
+ if (j2 != 0) {
+ quat_alg_conj(beta2, beta2);
+ }
+
+#ifndef NDEBUG
+ quat_alg_norm(&remain, &norm_d, beta1, &QUATALG_PINFTY);
+ assert(ibz_is_one(&norm_d));
+ ibz_mul(&n, d1, &ideal->norm);
+ if (j1 > 0) {
+ ibz_mul(&n, &n, &ALTERNATE_CONNECTING_IDEALS[j1 - 1].norm);
+ }
+ assert(ibz_cmp(&n, &remain) == 0);
+ quat_alg_norm(&remain, &norm_d, beta2, &QUATALG_PINFTY);
+ assert(ibz_is_one(&norm_d));
+ ibz_mul(&n, d2, &ideal->norm);
+ if (j2 > 0) {
+ ibz_mul(&n, &n, &ALTERNATE_CONNECTING_IDEALS[j2 - 1].norm);
+ }
+ assert(ibz_cmp(&n, &remain) == 0);
+ assert(quat_lattice_contains(NULL, &ideal->lattice, beta1));
+ assert(quat_lattice_contains(NULL, &ideal->lattice, beta2));
+
+ quat_left_ideal_t ideal_test;
+ quat_lattice_t ro;
+ quat_left_ideal_init(&ideal_test);
+ quat_lattice_init(&ro);
+ if (j1 > 0) {
+ quat_lideal_copy(&ideal_test, &ALTERNATE_CONNECTING_IDEALS[j1 - 1]);
+ quat_lideal_conjugate_without_hnf(&ideal_test, &ro, &ideal_test, Bpoo);
+ quat_lideal_lideal_mul_reduced(&ideal_test, &gram[0], &ideal_test, ideal, Bpoo);
+ assert(quat_lattice_contains(NULL, &ideal_test.lattice, beta1));
+ }
+ if (j2 > 0) {
+ quat_lideal_copy(&ideal_test, &ALTERNATE_CONNECTING_IDEALS[j2 - 1]);
+ quat_lideal_conjugate_without_hnf(&ideal_test, &ro, &ideal_test, Bpoo);
+ quat_lideal_lideal_mul_reduced(&ideal_test, &gram[0], &ideal_test, ideal, Bpoo);
+ assert(quat_lattice_contains(NULL, &ideal_test.lattice, beta2));
+ }
+
+ quat_lattice_finalize(&ro);
+ quat_left_ideal_finalize(&ideal_test);
+#endif
+
+ *index_alternate_order_1 = j1;
+ *index_alternate_order_2 = j2;
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+
+ for (int j = 0; j < num_alternate_order + 1; j++) {
+ for (int i = 0; i < m4; i++) {
+ ibz_finalize(&small_norms[j][i]);
+ ibz_vec_4_finalize(&small_vecs[j][i]);
+ ibz_finalize(&alternate_small_norms[j][i]);
+ ibz_finalize("ients[j][i]);
+ ibz_vec_4_finalize(&alternate_small_vecs[j][i]);
+ }
+ }
+
+ // var finalize
+ for (int i = 0; i < num_alternate_order + 1; i++) {
+ ibz_mat_4x4_finalize(&gram[i]);
+ ibz_mat_4x4_finalize(&reduced[i]);
+ quat_left_ideal_finalize(&ideal[i]);
+ ibz_finalize(&adjusted_norm[i]);
+ }
+
+ ibz_finalize(&n);
+ ibz_vec_4_finalize(&vec);
+ ibz_finalize(&au);
+ ibz_finalize(&bu);
+ ibz_finalize(&av);
+ ibz_finalize(&bv);
+ ibz_finalize(&remain);
+ ibz_finalize(&norm_d);
+ quat_lattice_finalize(&right_order);
+ quat_left_ideal_finalize(&conj_ideal);
+ quat_left_ideal_finalize(&reduced_id);
+ quat_alg_elem_finalize(&delta);
+
+ return found;
+}
+
+int
+dim2id2iso_ideal_to_isogeny_clapotis(quat_alg_elem_t *beta1,
+ quat_alg_elem_t *beta2,
+ ibz_t *u,
+ ibz_t *v,
+ ibz_t *d1,
+ ibz_t *d2,
+ ec_curve_t *codomain,
+ ec_basis_t *basis,
+ const quat_left_ideal_t *lideal,
+ const quat_alg_t *Bpoo)
+{
+ ibz_t target, tmp, two_pow;
+ ;
+ quat_alg_elem_t theta;
+
+ ibz_t norm_d;
+ ibz_init(&norm_d);
+ ibz_t test1, test2;
+ ibz_init(&test1);
+ ibz_init(&test2);
+
+ ibz_init(&target);
+ ibz_init(&tmp);
+ ibz_init(&two_pow);
+ int exp = TORSION_EVEN_POWER;
+ quat_alg_elem_init(&theta);
+
+ // first, we find u,v,d1,d2,beta1,beta2
+ // such that u*d1 + v*d2 = 2^TORSION_EVEN_POWER and there are ideals of
+ // norm d1,d2 equivalent to ideal beta1 and beta2 are elements of norm nd1,
+ // nd2 where n=n(lideal)
+ int ret;
+ int index_order1 = 0, index_order2 = 0;
+#ifndef NDEBUG
+ unsigned int Fu_length, Fv_length;
+#endif
+ ret = find_uv(u,
+ v,
+ beta1,
+ beta2,
+ d1,
+ d2,
+ &index_order1,
+ &index_order2,
+ &TORSION_PLUS_2POWER,
+ lideal,
+ Bpoo,
+ NUM_ALTERNATE_EXTREMAL_ORDERS);
+ if (!ret) {
+ goto cleanup;
+ }
+
+ assert(ibz_is_odd(d1) && ibz_is_odd(d2));
+ // compute the valuation of the GCD of u,v
+ ibz_gcd(&tmp, u, v);
+ assert(ibz_cmp(&tmp, &ibz_const_zero) != 0);
+ int exp_gcd = ibz_two_adic(&tmp);
+ exp = TORSION_EVEN_POWER - exp_gcd;
+ // removing the power of 2 from u and v
+ ibz_div(u, &test1, u, &tmp);
+ assert(ibz_cmp(&test1, &ibz_const_zero) == 0);
+ ibz_div(v, &test1, v, &tmp);
+ assert(ibz_cmp(&test1, &ibz_const_zero) == 0);
+
+#ifndef NDEBUG
+ // checking that ud1+vd2 = 2^exp
+ ibz_t pow_check, tmp_check;
+ ibz_init(&pow_check);
+ ibz_init(&tmp_check);
+ ibz_pow(&pow_check, &ibz_const_two, exp);
+ ibz_mul(&tmp_check, d1, u);
+ ibz_sub(&pow_check, &pow_check, &tmp_check);
+ ibz_mul(&tmp_check, v, d2);
+ ibz_sub(&pow_check, &pow_check, &tmp_check);
+ assert(ibz_cmp(&pow_check, &ibz_const_zero) == 0);
+ ibz_finalize(&tmp_check);
+ ibz_finalize(&pow_check);
+#endif
+
+ // now we compute the dimension 2 isogeny
+ // F : Eu x Ev -> E x E'
+ // where we have phi_u : Eu -> E_index_order1 and phi_v : Ev -> E_index_order2
+ // if we have phi1 : E_index_order_1 -> E of degree d1
+ // and phi2 : E_index_order_2 -> E of degree d2
+ // we can define theta = phi2 o hat{phi1}
+ // and the kernel of F is given by
+ // ( [ud1](P), phiv o theta o hat{phiu} (P)),( [ud1](Q), phiv o theta o
+ // hat{phiu} (Q)) where P,Q is a basis of E0[2e]
+
+ // now we set-up the kernel
+ // ec_curve_t E0 = CURVE_E0;
+ ec_curve_t E1;
+ copy_curve(&E1, &CURVES_WITH_ENDOMORPHISMS[index_order1].curve);
+ ec_curve_t E2;
+ copy_curve(&E2, &CURVES_WITH_ENDOMORPHISMS[index_order2].curve);
+ ec_basis_t bas1, bas2;
+ theta_couple_curve_t E01;
+ theta_kernel_couple_points_t ker;
+
+ ec_basis_t bas_u;
+ copy_basis(&bas1, &CURVES_WITH_ENDOMORPHISMS[index_order1].basis_even);
+ copy_basis(&bas2, &CURVES_WITH_ENDOMORPHISMS[index_order2].basis_even);
+
+ // we start by computing theta = beta2 \hat{beta1}/n
+ ibz_set(&theta.denom, 1);
+ quat_alg_conj(&theta, beta1);
+ quat_alg_mul(&theta, beta2, &theta, &QUATALG_PINFTY);
+ ibz_mul(&theta.denom, &theta.denom, &lideal->norm);
+
+ // now we perform the actual computation
+ quat_left_ideal_t idealu, idealv;
+ quat_left_ideal_init(&idealu);
+ quat_left_ideal_init(&idealv);
+ theta_couple_curve_t Fu_codomain, Fv_codomain;
+ theta_couple_point_t pushed_points[3];
+ theta_couple_point_t *const V1 = pushed_points + 0, *const V2 = pushed_points + 1, *const V1m2 = pushed_points + 2;
+ theta_couple_point_t P, Q, PmQ;
+
+ copy_point(&P.P1, &bas1.P);
+ copy_point(&PmQ.P1, &bas1.PmQ);
+ copy_point(&Q.P1, &bas1.Q);
+ // Set points to zero
+ ec_point_init(&P.P2);
+ ec_point_init(&Q.P2);
+ ec_point_init(&PmQ.P2);
+
+ pushed_points[0] = P;
+ pushed_points[1] = Q;
+ pushed_points[2] = PmQ;
+ // we perform the computation of phiu with a fixed degree isogeny
+ ret = fixed_degree_isogeny_and_eval(
+ &idealu, u, true, &Fu_codomain, pushed_points, sizeof(pushed_points) / sizeof(*pushed_points), index_order1);
+
+ if (!ret) {
+ goto cleanup;
+ }
+ assert(test_point_order_twof(&V1->P1, &Fu_codomain.E1, TORSION_EVEN_POWER));
+ assert(test_point_order_twof(&V1->P2, &Fu_codomain.E2, TORSION_EVEN_POWER));
+
+#ifndef NDEBUG
+ Fu_length = (unsigned int)ret;
+ // presumably the correct curve is the first one, we check this
+ fp2_t w0a, w1a, w2a;
+ ec_curve_t E1_tmp, Fu_codomain_E1_tmp, Fu_codomain_E2_tmp;
+ copy_curve(&E1_tmp, &E1);
+ copy_curve(&Fu_codomain_E1_tmp, &Fu_codomain.E1);
+ copy_curve(&Fu_codomain_E2_tmp, &Fu_codomain.E2);
+ weil(&w0a, TORSION_EVEN_POWER, &bas1.P, &bas1.Q, &bas1.PmQ, &E1_tmp);
+ weil(&w1a, TORSION_EVEN_POWER, &V1->P1, &V2->P1, &V1m2->P1, &Fu_codomain_E1_tmp);
+ weil(&w2a, TORSION_EVEN_POWER, &V1->P2, &V2->P2, &V1m2->P2, &Fu_codomain_E2_tmp);
+ ibz_pow(&two_pow, &ibz_const_two, Fu_length);
+ ibz_sub(&two_pow, &two_pow, u);
+
+ // now we are checking that the weil pairings are equal to the correct value
+ digit_t digit_u[NWORDS_ORDER] = { 0 };
+ ibz_to_digit_array(digit_u, u);
+ fp2_t test_powa;
+ fp2_pow_vartime(&test_powa, &w0a, digit_u, NWORDS_ORDER);
+
+ assert(fp2_is_equal(&test_powa, &w1a));
+ ibz_to_digit_array(digit_u, &two_pow);
+ fp2_pow_vartime(&test_powa, &w0a, digit_u, NWORDS_ORDER);
+ assert(fp2_is_equal(&test_powa, &w2a));
+#endif
+
+ // copying the basis images
+ copy_point(&bas_u.P, &V1->P1);
+ copy_point(&bas_u.Q, &V2->P1);
+ copy_point(&bas_u.PmQ, &V1m2->P1);
+
+ // copying the points to the first part of the kernel
+ copy_point(&ker.T1.P1, &bas_u.P);
+ copy_point(&ker.T2.P1, &bas_u.Q);
+ copy_point(&ker.T1m2.P1, &bas_u.PmQ);
+ copy_curve(&E01.E1, &Fu_codomain.E1);
+
+ copy_point(&P.P1, &bas2.P);
+ copy_point(&PmQ.P1, &bas2.PmQ);
+ copy_point(&Q.P1, &bas2.Q);
+ pushed_points[0] = P;
+ pushed_points[1] = Q;
+ pushed_points[2] = PmQ;
+
+ // computation of phiv
+ ret = fixed_degree_isogeny_and_eval(
+ &idealv, v, true, &Fv_codomain, pushed_points, sizeof(pushed_points) / sizeof(*pushed_points), index_order2);
+ if (!ret) {
+ goto cleanup;
+ }
+
+ assert(test_point_order_twof(&V1->P1, &Fv_codomain.E1, TORSION_EVEN_POWER));
+ assert(test_point_order_twof(&V1->P2, &Fv_codomain.E2, TORSION_EVEN_POWER));
+
+#ifndef NDEBUG
+ Fv_length = (unsigned int)ret;
+ ec_curve_t E2_tmp, Fv_codomain_E1_tmp, Fv_codomain_E2_tmp;
+ copy_curve(&E2_tmp, &E2);
+ copy_curve(&Fv_codomain_E1_tmp, &Fv_codomain.E1);
+ copy_curve(&Fv_codomain_E2_tmp, &Fv_codomain.E2);
+ // presumably the correct curve is the first one, we check this
+ weil(&w0a, TORSION_EVEN_POWER, &bas2.P, &bas2.Q, &bas2.PmQ, &E2_tmp);
+ weil(&w1a, TORSION_EVEN_POWER, &V1->P1, &V2->P1, &V1m2->P1, &Fv_codomain_E1_tmp);
+ weil(&w2a, TORSION_EVEN_POWER, &V1->P2, &V2->P2, &V1m2->P2, &Fv_codomain_E2_tmp);
+ if (Fv_length == 0) {
+ ibz_set(&tmp, 1);
+ ibz_set(&two_pow, 1);
+ } else {
+ ibz_pow(&two_pow, &ibz_const_two, Fv_length);
+ ibz_sub(&two_pow, &two_pow, v);
+ }
+
+ // now we are checking that one of the two is equal to the correct value
+ ibz_to_digit_array(digit_u, v);
+ fp2_pow_vartime(&test_powa, &w0a, digit_u, NWORDS_ORDER);
+ assert(fp2_is_equal(&test_powa, &w1a));
+ ibz_to_digit_array(digit_u, &two_pow);
+ fp2_pow_vartime(&test_powa, &w0a, digit_u, NWORDS_ORDER);
+ assert(fp2_is_equal(&test_powa, &w2a));
+
+#endif
+
+ copy_point(&bas2.P, &V1->P1);
+ copy_point(&bas2.Q, &V2->P1);
+ copy_point(&bas2.PmQ, &V1m2->P1);
+
+ // multiplying theta by 1 / (d1 * n(connecting_ideal2))
+ ibz_pow(&two_pow, &ibz_const_two, TORSION_EVEN_POWER);
+ ibz_copy(&tmp, d1);
+ if (index_order2 > 0) {
+ ibz_mul(&tmp, &tmp, &ALTERNATE_CONNECTING_IDEALS[index_order2 - 1].norm);
+ }
+ ibz_invmod(&tmp, &tmp, &two_pow);
+
+ ibz_mul(&theta.coord.v[0], &theta.coord.v[0], &tmp);
+ ibz_mul(&theta.coord.v[1], &theta.coord.v[1], &tmp);
+ ibz_mul(&theta.coord.v[2], &theta.coord.v[2], &tmp);
+ ibz_mul(&theta.coord.v[3], &theta.coord.v[3], &tmp);
+
+ // applying theta
+ endomorphism_application_even_basis(&bas2, 0, &Fv_codomain.E1, &theta, TORSION_EVEN_POWER);
+
+ assert(test_basis_order_twof(&bas2, &Fv_codomain.E1, TORSION_EVEN_POWER));
+
+ // copying points to the second part of the kernel
+ copy_point(&ker.T1.P2, &bas2.P);
+ copy_point(&ker.T2.P2, &bas2.Q);
+ copy_point(&ker.T1m2.P2, &bas2.PmQ);
+ copy_curve(&E01.E2, &Fv_codomain.E1);
+
+ // copying the points to the first part of the kernel
+ quat_left_ideal_finalize(&idealu);
+ quat_left_ideal_finalize(&idealv);
+
+ double_couple_point_iter(&ker.T1, TORSION_EVEN_POWER - exp, &ker.T1, &E01);
+ double_couple_point_iter(&ker.T2, TORSION_EVEN_POWER - exp, &ker.T2, &E01);
+ double_couple_point_iter(&ker.T1m2, TORSION_EVEN_POWER - exp, &ker.T1m2, &E01);
+
+ assert(test_point_order_twof(&ker.T1.P1, &E01.E1, exp));
+ assert(test_point_order_twof(&ker.T1m2.P2, &E01.E2, exp));
+
+ assert(ibz_is_odd(u));
+
+ // now we evaluate the basis points through the isogeny
+ assert(test_basis_order_twof(&bas_u, &E01.E1, TORSION_EVEN_POWER));
+
+ // evaluating the basis through the isogeny of degree u*d1
+ copy_point(&pushed_points[0].P1, &bas_u.P);
+ copy_point(&pushed_points[2].P1, &bas_u.PmQ);
+ copy_point(&pushed_points[1].P1, &bas_u.Q);
+ // Set points to zero
+ ec_point_init(&pushed_points[0].P2);
+ ec_point_init(&pushed_points[1].P2);
+ ec_point_init(&pushed_points[2].P2);
+
+ theta_couple_curve_t theta_codomain;
+
+ ret = theta_chain_compute_and_eval_randomized(
+ exp, &E01, &ker, false, &theta_codomain, pushed_points, sizeof(pushed_points) / sizeof(*pushed_points));
+ if (!ret) {
+ goto cleanup;
+ }
+
+ theta_couple_point_t T1, T2, T1m2;
+ T1 = pushed_points[0];
+ T2 = pushed_points[1];
+ T1m2 = pushed_points[2];
+
+ assert(test_point_order_twof(&T1.P2, &theta_codomain.E2, TORSION_EVEN_POWER));
+ assert(test_point_order_twof(&T1.P1, &theta_codomain.E1, TORSION_EVEN_POWER));
+ assert(test_point_order_twof(&T1m2.P2, &theta_codomain.E2, TORSION_EVEN_POWER));
+
+ copy_point(&basis->P, &T1.P1);
+ copy_point(&basis->Q, &T2.P1);
+ copy_point(&basis->PmQ, &T1m2.P1);
+ copy_curve(codomain, &theta_codomain.E1);
+
+ // using weil pairing to verify that we selected the correct curve
+ fp2_t w0, w1;
+ // ec_curve_t E0 = CURVE_E0;
+ // ec_basis_t bas0 = BASIS_EVEN;
+ weil(&w0, TORSION_EVEN_POWER, &bas1.P, &bas1.Q, &bas1.PmQ, &E1);
+ weil(&w1, TORSION_EVEN_POWER, &basis->P, &basis->Q, &basis->PmQ, codomain);
+
+ digit_t digit_d[NWORDS_ORDER] = { 0 };
+ ibz_mul(&tmp, d1, u);
+ ibz_mul(&tmp, &tmp, u);
+ ibz_mod(&tmp, &tmp, &TORSION_PLUS_2POWER);
+ ibz_to_digit_array(digit_d, &tmp);
+ fp2_t test_pow;
+ fp2_pow_vartime(&test_pow, &w0, digit_d, NWORDS_ORDER);
+
+ // then we have selected the wrong one
+ if (!fp2_is_equal(&w1, &test_pow)) {
+ copy_point(&basis->P, &T1.P2);
+ copy_point(&basis->Q, &T2.P2);
+ copy_point(&basis->PmQ, &T1m2.P2);
+ copy_curve(codomain, &theta_codomain.E2);
+
+// verifying that the other one is the good one
+#ifndef NDEBUG
+ ec_curve_t codomain_tmp;
+ copy_curve(&codomain_tmp, codomain);
+ weil(&w1, TORSION_EVEN_POWER, &basis->P, &basis->Q, &basis->PmQ, &codomain_tmp);
+ fp2_pow_vartime(&test_pow, &w0, digit_d, NWORDS_ORDER);
+ assert(fp2_is_equal(&test_pow, &w1));
+#endif
+ }
+
+ // now we apply M / (u * d1) where M is the matrix corresponding to the
+ // endomorphism beta1 = phi o dual(phi1) we multiply beta1 by the inverse of
+ // (u*d1) mod 2^TORSION_EVEN_POWER
+ ibz_mul(&tmp, u, d1);
+ if (index_order1 != 0) {
+ ibz_mul(&tmp, &tmp, &CONNECTING_IDEALS[index_order1].norm);
+ }
+ ibz_invmod(&tmp, &tmp, &TORSION_PLUS_2POWER);
+ ibz_mul(&beta1->coord.v[0], &beta1->coord.v[0], &tmp);
+ ibz_mul(&beta1->coord.v[1], &beta1->coord.v[1], &tmp);
+ ibz_mul(&beta1->coord.v[2], &beta1->coord.v[2], &tmp);
+ ibz_mul(&beta1->coord.v[3], &beta1->coord.v[3], &tmp);
+
+ endomorphism_application_even_basis(basis, 0, codomain, beta1, TORSION_EVEN_POWER);
+
+#ifndef NDEBUG
+ {
+ ec_curve_t E0 = CURVE_E0;
+ ec_curve_t codomain_tmp;
+ ec_basis_t bas0 = CURVES_WITH_ENDOMORPHISMS[0].basis_even;
+ copy_curve(&codomain_tmp, codomain);
+ copy_curve(&E1_tmp, &E1);
+ copy_curve(&E2_tmp, &E2);
+ weil(&w0a, TORSION_EVEN_POWER, &bas0.P, &bas0.Q, &bas0.PmQ, &E0);
+ weil(&w1a, TORSION_EVEN_POWER, &basis->P, &basis->Q, &basis->PmQ, &codomain_tmp);
+ digit_t tmp_d[2 * NWORDS_ORDER] = { 0 };
+ if (index_order1 != 0) {
+ copy_basis(&bas1, &CURVES_WITH_ENDOMORPHISMS[index_order1].basis_even);
+ weil(&w0, TORSION_EVEN_POWER, &bas1.P, &bas1.Q, &bas1.PmQ, &E1_tmp);
+ ibz_to_digit_array(tmp_d, &CONNECTING_IDEALS[index_order1].norm);
+ fp2_pow_vartime(&test_pow, &w0a, tmp_d, 2 * NWORDS_ORDER);
+ assert(fp2_is_equal(&test_pow, &w0));
+ }
+ if (index_order2 != 0) {
+ copy_basis(&bas2, &CURVES_WITH_ENDOMORPHISMS[index_order2].basis_even);
+ weil(&w0, TORSION_EVEN_POWER, &bas2.P, &bas2.Q, &bas2.PmQ, &E2_tmp);
+ ibz_to_digit_array(tmp_d, &CONNECTING_IDEALS[index_order2].norm);
+ fp2_pow_vartime(&test_pow, &w0a, tmp_d, 2 * NWORDS_ORDER);
+ assert(fp2_is_equal(&test_pow, &w0));
+ }
+ ibz_to_digit_array(tmp_d, &lideal->norm);
+ fp2_pow_vartime(&test_pow, &w0a, tmp_d, 2 * NWORDS_ORDER);
+ assert(fp2_is_equal(&test_pow, &w1a));
+ }
+#endif
+
+cleanup:
+ ibz_finalize(&norm_d);
+ ibz_finalize(&test1);
+ ibz_finalize(&test2);
+ ibz_finalize(&target);
+ ibz_finalize(&tmp);
+ ibz_finalize(&two_pow);
+ quat_alg_elem_finalize(&theta);
+ return ret;
+}
+
+int
+dim2id2iso_arbitrary_isogeny_evaluation(ec_basis_t *basis, ec_curve_t *codomain, const quat_left_ideal_t *lideal)
+{
+ int ret;
+
+ quat_alg_elem_t beta1, beta2;
+ ibz_t u, v, d1, d2;
+
+ quat_alg_elem_init(&beta1);
+ quat_alg_elem_init(&beta2);
+
+ ibz_init(&u);
+ ibz_init(&v);
+ ibz_init(&d1);
+ ibz_init(&d2);
+
+ ret = dim2id2iso_ideal_to_isogeny_clapotis(
+ &beta1, &beta2, &u, &v, &d1, &d2, codomain, basis, lideal, &QUATALG_PINFTY);
+
+ quat_alg_elem_finalize(&beta1);
+ quat_alg_elem_finalize(&beta2);
+
+ ibz_finalize(&u);
+ ibz_finalize(&v);
+ ibz_finalize(&d1);
+ ibz_finalize(&d2);
+
+ return ret;
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/dim4.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/dim4.c
new file mode 100644
index 0000000000..b024a7d46e
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/dim4.c
@@ -0,0 +1,470 @@
+#include
+#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.m[i][j]), 0);
+ for (int k = 0; k < 4; k++) {
+ ibz_mul(&prod, &(a->m[i][k]), &(b->m[k][j]));
+ ibz_add(&(mat.m[i][j]), &(mat.m[i][j]), &prod);
+ }
+ }
+ }
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibz_copy(&(res->m[i][j]), &(mat.m[i][j]));
+ }
+ }
+ ibz_mat_4x4_finalize(&mat);
+ ibz_finalize(&prod);
+}
+
+// helper functions for lattices
+void
+ibz_vec_4_set(ibz_vec_4_t *vec, int32_t coord0, int32_t coord1, int32_t coord2, int32_t coord3)
+{
+ ibz_set(&(vec->v[0]), coord0);
+ ibz_set(&(vec->v[1]), coord1);
+ ibz_set(&(vec->v[2]), coord2);
+ ibz_set(&(vec->v[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->v[i]), &(vec->v[i]));
+ }
+}
+
+void
+ibz_vec_4_copy_ibz(ibz_vec_4_t *res, const ibz_t *coord0, const ibz_t *coord1, const ibz_t *coord2, const ibz_t *coord3)
+{
+ ibz_copy(&(res->v[0]), coord0);
+ ibz_copy(&(res->v[1]), coord1);
+ ibz_copy(&(res->v[2]), coord2);
+ ibz_copy(&(res->v[3]), coord3);
+}
+
+void
+ibz_vec_4_content(ibz_t *content, const ibz_vec_4_t *v)
+{
+ ibz_gcd(content, &(v->v[0]), &(v->v[1]));
+ ibz_gcd(content, &(v->v[2]), content);
+ ibz_gcd(content, &(v->v[3]), content);
+}
+
+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->v[i]), &(vec->v[i]));
+ }
+}
+
+void
+ibz_vec_4_add(ibz_vec_4_t *res, const ibz_vec_4_t *a, const ibz_vec_4_t *b)
+{
+ ibz_add(&(res->v[0]), &(a->v[0]), &(b->v[0]));
+ ibz_add(&(res->v[1]), &(a->v[1]), &(b->v[1]));
+ ibz_add(&(res->v[2]), &(a->v[2]), &(b->v[2]));
+ ibz_add(&(res->v[3]), &(a->v[3]), &(b->v[3]));
+}
+
+void
+ibz_vec_4_sub(ibz_vec_4_t *res, const ibz_vec_4_t *a, const ibz_vec_4_t *b)
+{
+ ibz_sub(&(res->v[0]), &(a->v[0]), &(b->v[0]));
+ ibz_sub(&(res->v[1]), &(a->v[1]), &(b->v[1]));
+ ibz_sub(&(res->v[2]), &(a->v[2]), &(b->v[2]));
+ ibz_sub(&(res->v[3]), &(a->v[3]), &(b->v[3]));
+}
+
+int
+ibz_vec_4_is_zero(const ibz_vec_4_t *x)
+{
+ int res = 1;
+ for (int i = 0; i < 4; i++) {
+ res &= ibz_is_zero(&(x->v[i]));
+ }
+ return (res);
+}
+
+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.v[i]), coeff_a, &(vec_a->v[i]));
+ ibz_mul(&prod, coeff_b, &(vec_b->v[i]));
+ ibz_add(&(sums.v[i]), &(sums.v[i]), &prod);
+ }
+ for (int i = 0; i < 4; i++) {
+ ibz_copy(&(lc->v[i]), &(sums.v[i]));
+ }
+ ibz_finalize(&prod);
+ ibz_vec_4_finalize(&sums);
+}
+
+void
+ibz_vec_4_scalar_mul(ibz_vec_4_t *prod, const ibz_t *scalar, const ibz_vec_4_t *vec)
+{
+ for (int i = 0; i < 4; i++) {
+ ibz_mul(&(prod->v[i]), &(vec->v[i]), scalar);
+ }
+}
+
+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->v[i]), &r, &(vec->v[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->m[i][j]), &(mat->m[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->m[i][j]), &(mat->m[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.m[i][j]), &(mat->m[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->m[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->m[i][j]), 0);
+ }
+ ibz_set(&(id->m[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_is_one(&(mat->m[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->m[i][j]), &(mat2->m[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->m[i][j]), &(mat->m[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->m[0][0]));
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibz_gcd(&d, &d, &(mat->m[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->m[i][j]), &r, &(mat->m[i][j]), scalar);
+ res = res && ibz_is_zero(&r);
+ }
+ }
+ ibz_finalize(&r);
+ 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->m[0][0]), &(mat->m[0][i + 1]), &(mat->m[1][0]), &(mat->m[1][i + 1]));
+ ibz_mat_2x2_det_from_ibz(&(c[i]), &(mat->m[2][0]), &(mat->m[2][i + 1]), &(mat->m[3][0]), &(mat->m[3][i + 1]));
+ }
+ for (int i = 0; i < 2; i++) {
+ ibz_mat_2x2_det_from_ibz(
+ &(s[3 + i]), &(mat->m[0][1]), &(mat->m[0][2 + i]), &(mat->m[1][1]), &(mat->m[1][2 + i]));
+ ibz_mat_2x2_det_from_ibz(
+ &(c[3 + i]), &(mat->m[2][1]), &(mat->m[2][2 + i]), &(mat->m[3][1]), &(mat->m[3][2 + i]));
+ }
+ ibz_mat_2x2_det_from_ibz(&(s[5]), &(mat->m[0][2]), &(mat->m[0][3]), &(mat->m[1][2]), &(mat->m[1][3]));
+ ibz_mat_2x2_det_from_ibz(&(c[5]), &(mat->m[2][2]), &(mat->m[2][3]), &(mat->m[3][2]), &(mat->m[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);
+ }
+ }
+ // 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.m[j][k]),
+ &(mat->m[1 - k][(j == 0)]),
+ &(c[6 - j - (j == 0)]),
+ &(mat->m[1 - k][2 - (j > 1)]),
+ &(c[4 - j - (j == 1)]),
+ &(mat->m[1 - k][3 - (j == 3)]),
+ &(c[3 - j - (j == 1) - (j == 2)]));
+ } else {
+ ibz_inv_dim4_make_coeff_mpm(&(work.m[j][k]),
+ &(mat->m[1 - k][(j == 0)]),
+ &(c[6 - j - (j == 0)]),
+ &(mat->m[1 - k][2 - (j > 1)]),
+ &(c[4 - j - (j == 1)]),
+ &(mat->m[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.m[j][k]),
+ &(mat->m[3 - (k == 3)][(j == 0)]),
+ &(s[6 - j - (j == 0)]),
+ &(mat->m[3 - (k == 3)][2 - (j > 1)]),
+ &(s[4 - j - (j == 1)]),
+ &(mat->m[3 - (k == 3)][3 - (j == 3)]),
+ &(s[3 - j - (j == 1) - (j == 2)]));
+ } else {
+ ibz_inv_dim4_make_coeff_mpm(&(work.m[j][k]),
+ &(mat->m[3 - (k == 3)][(j == 0)]),
+ &(s[6 - j - (j == 0)]),
+ &(mat->m[3 - (k == 3)][2 - (j > 1)]),
+ &(s[4 - j - (j == 1)]),
+ &(mat->m[3 - (k == 3)][3 - (j == 3)]),
+ &(s[3 - j - (j == 1) - (j == 2)]));
+ }
+ }
+ }
+ if (inv != NULL) {
+ // put transposed adjugate in result, or 0 if no inverse
+ ibz_set(&prod, !ibz_is_zero(&work_det));
+ ibz_mat_4x4_scalar_mul(inv, &prod, &work);
+ }
+ // output det
+ 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));
+}
+
+// matrix evaluation
+
+void
+ibz_mat_4x4_eval(ibz_vec_4_t *res, const ibz_mat_4x4_t *mat, const ibz_vec_4_t *vec)
+{
+ ibz_vec_4_t sum;
+ ibz_t prod;
+ ibz_init(&prod);
+ ibz_vec_4_init(&sum);
+ // assume initialization to 0
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibz_mul(&prod, &mat->m[i][j], &vec->v[j]);
+ ibz_add(&(sum.v[i]), &(sum.v[i]), &prod);
+ }
+ }
+ ibz_vec_4_copy(res, &sum);
+ ibz_finalize(&prod);
+ ibz_vec_4_finalize(&sum);
+}
+
+void
+ibz_mat_4x4_eval_t(ibz_vec_4_t *res, const ibz_vec_4_t *vec, const ibz_mat_4x4_t *mat)
+{
+ ibz_vec_4_t sum;
+ ibz_t prod;
+ ibz_init(&prod);
+ ibz_vec_4_init(&sum);
+ // assume initialization to 0
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibz_mul(&prod, &mat->m[j][i], &vec->v[j]);
+ ibz_add(&(sum.v[i]), &(sum.v[i]), &prod);
+ }
+ }
+ ibz_vec_4_copy(res, &sum);
+ ibz_finalize(&prod);
+ ibz_vec_4_finalize(&sum);
+}
+
+// quadratic forms
+
+void
+quat_qf_eval(ibz_t *res, const ibz_mat_4x4_t *qf, const ibz_vec_4_t *coord)
+{
+ ibz_vec_4_t sum;
+ ibz_t prod;
+ ibz_init(&prod);
+ ibz_vec_4_init(&sum);
+ ibz_mat_4x4_eval(&sum, qf, coord);
+ for (int i = 0; i < 4; i++) {
+ ibz_mul(&prod, &(sum.v[i]), &coord->v[i]);
+ if (i > 0) {
+ ibz_add(&(sum.v[0]), &(sum.v[0]), &prod);
+ } else {
+ ibz_copy(&sum.v[0], &prod);
+ }
+ }
+ ibz_copy(res, &sum.v[0]);
+ ibz_finalize(&prod);
+ ibz_vec_4_finalize(&sum);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/e0_basis.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/e0_basis.c
new file mode 100644
index 0000000000..c24fe29409
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/e0_basis.c
@@ -0,0 +1,55 @@
+#include
+const fp2_t BASIS_E0_PX = {
+#if 0
+#elif RADIX == 16
+{{0x107, 0xc, 0x1890, 0xf2a, 0x52b, 0xb68, 0x152d, 0xa4c, 0x1054, 0x642, 0x36a, 0x6f8, 0x7ad, 0x146c, 0x1d66, 0x1b67, 0x236, 0x10d, 0x1933, 0x3}}
+#elif RADIX == 32
+{{0x3020e, 0xb795624, 0x5ab6829, 0x1514995, 0x1b5190a, 0x187ad37c, 0x19facd46, 0x8688db6, 0x3c998}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x52b795624001810, 0x8c8505452654b56d, 0xf59a8d87ad37c0da, 0x24e4cc21a236db3}}
+#else
+{{0x5bcab12000c08, 0x452654b56d052, 0x26f81b5190a0a, 0x36cfd66a361eb, 0x12726610d11b}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x1f87, 0x83e, 0x32e, 0xe58, 0xd9d, 0x1416, 0x752, 0x13b4, 0x1efa, 0xe62, 0x12f5, 0x1907, 0x1814, 0x1ddd, 0x1aa6, 0x1420, 0x2cd, 0x1431, 0x1be2, 0x7}}
+#elif RADIX == 32
+{{0x120fbf0f, 0x1d72c0cb, 0xa54166c, 0x1bea7687, 0x197ab98b, 0x1b814c83, 0x8354ddd, 0x188b368, 0x2df15}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xcd9d72c0cb907df8, 0x5cc5efa9da1d4a82, 0x6a9bbbb814c83cbd, 0x26ef8a8622cda10}}
+#else
+{{0x6b96065c83efc, 0x29da1d4a82cd9, 0x190797ab98bdf, 0x6841aa6eeee05, 0x1377c5431166}}
+#endif
+#endif
+};
+const fp2_t BASIS_E0_QX = {
+#if 0
+#elif RADIX == 16
+{{0x5ff, 0x1783, 0xadc, 0x775, 0xad4, 0x593, 0xb4c, 0x21e, 0x1cb2, 0x13d8, 0x179f, 0x680, 0x1a9c, 0x1824, 0x118e, 0x13d9, 0x24, 0x1956, 0x1dd2, 0x9}}
+#elif RADIX == 32
+{{0x5e0cbff, 0x143baab7, 0x9859356, 0x12c843cb, 0xbcfcf63, 0x9a9c340, 0x16631d82, 0xab00927, 0x4ee96}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x6ad43baab72f065f, 0xe7b1cb210f2d30b2, 0xc63b049a9c3405e7, 0x4ff74b2ac0249ec}}
+#else
+{{0x21dd55b97832f, 0x210f2d30b26ad, 0x680bcfcf6396, 0x27b318ec126a7, 0x4ffba5956012}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x1c7f, 0x1117, 0xa4, 0x1164, 0x6e, 0x1e63, 0x1b7b, 0x1305, 0x424, 0x131a, 0x1b61, 0xae3, 0x17b1, 0xe5e, 0x1848, 0x1e81, 0x14a5, 0x1cb5, 0x1d87, 0x8}}
+#elif RADIX == 32
+{{0x445f8ff, 0xe8b2029, 0xf7e6303, 0x109260bb, 0x1db0cc68, 0x1d7b1571, 0x7090e5, 0x5ad297d, 0x3ec3f}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x606e8b2029222fc7, 0x6634424982edefcc, 0xe121cbd7b1571ed8, 0x4f761f96b4a5f40}}
+#else
+{{0x74590149117e3, 0x4982edefcc606, 0x2ae3db0cc6884, 0x7d0384872f5ec, 0x4fbb0fcb5a52}}
+#endif
+#endif
+};
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/e0_basis.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/e0_basis.h
new file mode 100644
index 0000000000..05cafb8462
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/e0_basis.h
@@ -0,0 +1,3 @@
+#include
+extern const fp2_t BASIS_E0_PX;
+extern const fp2_t BASIS_E0_QX;
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec.c
new file mode 100644
index 0000000000..be4e4e55b1
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec.c
@@ -0,0 +1,665 @@
+#include
+#include
+#include
+#include
+
+void
+ec_point_init(ec_point_t *P)
+{ // Initialize point as identity element (1:0)
+ fp2_set_one(&(P->x));
+ fp2_set_zero(&(P->z));
+}
+
+void
+ec_curve_init(ec_curve_t *E)
+{ // Initialize the curve struct
+ // Initialize the constants
+ fp2_set_zero(&(E->A));
+ fp2_set_one(&(E->C));
+
+ // Initialize the point (A+2 : 4C)
+ ec_point_init(&(E->A24));
+
+ // Set the bool to be false by default
+ E->is_A24_computed_and_normalized = false;
+}
+
+void
+select_point(ec_point_t *Q, const ec_point_t *P1, const ec_point_t *P2, const digit_t option)
+{ // Select points in constant time
+ // If option = 0 then Q <- P1, else if option = 0xFF...FF then Q <- P2
+ fp2_select(&(Q->x), &(P1->x), &(P2->x), option);
+ fp2_select(&(Q->z), &(P1->z), &(P2->z), option);
+}
+
+void
+cswap_points(ec_point_t *P, ec_point_t *Q, const digit_t option)
+{ // Swap points in constant time
+ // If option = 0 then P <- P and Q <- Q, else if option = 0xFF...FF then P <- Q and Q <- P
+ fp2_cswap(&(P->x), &(Q->x), option);
+ fp2_cswap(&(P->z), &(Q->z), option);
+}
+
+void
+ec_normalize_point(ec_point_t *P)
+{
+ fp2_inv(&P->z);
+ fp2_mul(&P->x, &P->x, &P->z);
+ fp2_set_one(&(P->z));
+}
+
+void
+ec_normalize_curve(ec_curve_t *E)
+{
+ fp2_inv(&E->C);
+ fp2_mul(&E->A, &E->A, &E->C);
+ fp2_set_one(&E->C);
+}
+
+void
+ec_curve_normalize_A24(ec_curve_t *E)
+{
+ if (!E->is_A24_computed_and_normalized) {
+ AC_to_A24(&E->A24, E);
+ ec_normalize_point(&E->A24);
+ E->is_A24_computed_and_normalized = true;
+ }
+ assert(fp2_is_one(&E->A24.z));
+}
+
+void
+ec_normalize_curve_and_A24(ec_curve_t *E)
+{ // Neither the curve or A24 are guaranteed to be normalized.
+ // First we normalize (A/C : 1) and conditionally compute
+ if (!fp2_is_one(&E->C)) {
+ ec_normalize_curve(E);
+ }
+
+ if (!E->is_A24_computed_and_normalized) {
+ // Now compute A24 = ((A + 2) / 4 : 1)
+ fp2_add_one(&E->A24.x, &E->A); // re(A24.x) = re(A) + 1
+ fp2_add_one(&E->A24.x, &E->A24.x); // re(A24.x) = re(A) + 2
+ fp_copy(&E->A24.x.im, &E->A.im); // im(A24.x) = im(A)
+
+ fp2_half(&E->A24.x, &E->A24.x); // (A + 2) / 2
+ fp2_half(&E->A24.x, &E->A24.x); // (A + 2) / 4
+ fp2_set_one(&E->A24.z);
+
+ E->is_A24_computed_and_normalized = true;
+ }
+}
+
+uint32_t
+ec_is_zero(const ec_point_t *P)
+{
+ return fp2_is_zero(&P->z);
+}
+
+uint32_t
+ec_has_zero_coordinate(const ec_point_t *P)
+{
+ return fp2_is_zero(&P->x) | fp2_is_zero(&P->z);
+}
+
+uint32_t
+ec_is_equal(const ec_point_t *P, const ec_point_t *Q)
+{ // Evaluate if two points in Montgomery coordinates (X:Z) are equal
+ // Returns 0xFFFFFFFF (true) if P=Q, 0 (false) otherwise
+ fp2_t t0, t1;
+
+ // Check if P, Q are the points at infinity
+ uint32_t l_zero = ec_is_zero(P);
+ uint32_t r_zero = ec_is_zero(Q);
+
+ // Check if PX * QZ = QX * PZ
+ fp2_mul(&t0, &P->x, &Q->z);
+ fp2_mul(&t1, &P->z, &Q->x);
+ uint32_t lr_equal = fp2_is_equal(&t0, &t1);
+
+ // Points are equal if
+ // - Both are zero, or
+ // - neither are zero AND PX * QZ = QX * PZ
+ return (l_zero & r_zero) | (~l_zero & ~r_zero * lr_equal);
+}
+
+uint32_t
+ec_is_two_torsion(const ec_point_t *P, const ec_curve_t *E)
+{
+ if (ec_is_zero(P))
+ return 0;
+
+ uint32_t x_is_zero, tmp_is_zero;
+ fp2_t t0, t1, t2;
+ fp2_add(&t0, &P->x, &P->z);
+ fp2_sqr(&t0, &t0);
+ fp2_sub(&t1, &P->x, &P->z);
+ fp2_sqr(&t1, &t1);
+ fp2_sub(&t2, &t0, &t1);
+ fp2_add(&t1, &t0, &t1);
+ fp2_mul(&t2, &t2, &E->A);
+ fp2_mul(&t1, &t1, &E->C);
+ fp2_add(&t1, &t1, &t1);
+ fp2_add(&t0, &t1, &t2); // 4 (CX^2+CZ^2+AXZ)
+
+ x_is_zero = fp2_is_zero(&P->x);
+ tmp_is_zero = fp2_is_zero(&t0);
+
+ // two torsion if x or x^2 + Ax + 1 is zero
+ return x_is_zero | tmp_is_zero;
+}
+
+uint32_t
+ec_is_four_torsion(const ec_point_t *P, const ec_curve_t *E)
+{
+ ec_point_t test;
+ xDBL_A24(&test, P, &E->A24, E->is_A24_computed_and_normalized);
+ return ec_is_two_torsion(&test, E);
+}
+
+uint32_t
+ec_is_basis_four_torsion(const ec_basis_t *B, const ec_curve_t *E)
+{ // Check if basis points (P, Q) form a full 2^t-basis
+ ec_point_t P2, Q2;
+ xDBL_A24(&P2, &B->P, &E->A24, E->is_A24_computed_and_normalized);
+ xDBL_A24(&Q2, &B->Q, &E->A24, E->is_A24_computed_and_normalized);
+ return (ec_is_two_torsion(&P2, E) & ec_is_two_torsion(&Q2, E) & ~ec_is_equal(&P2, &Q2));
+}
+
+int
+ec_curve_verify_A(const fp2_t *A)
+{ // Verify the Montgomery coefficient A is valid (A^2-4 \ne 0)
+ // Return 1 if curve is valid, 0 otherwise
+ fp2_t t;
+ fp2_set_one(&t);
+ fp_add(&t.re, &t.re, &t.re); // t=2
+ if (fp2_is_equal(A, &t))
+ return 0;
+ fp_neg(&t.re, &t.re); // t=-2
+ if (fp2_is_equal(A, &t))
+ return 0;
+ return 1;
+}
+
+int
+ec_curve_init_from_A(ec_curve_t *E, const fp2_t *A)
+{ // Initialize the curve from the A coefficient and check it is valid
+ // Return 1 if curve is valid, 0 otherwise
+ ec_curve_init(E);
+ fp2_copy(&E->A, A); // Set A
+ return ec_curve_verify_A(A);
+}
+
+void
+ec_j_inv(fp2_t *j_inv, const ec_curve_t *curve)
+{ // j-invariant computation for Montgommery coefficient A2=(A+2C:4C)
+ fp2_t t0, t1;
+
+ fp2_sqr(&t1, &curve->C);
+ fp2_sqr(j_inv, &curve->A);
+ fp2_add(&t0, &t1, &t1);
+ fp2_sub(&t0, j_inv, &t0);
+ fp2_sub(&t0, &t0, &t1);
+ fp2_sub(j_inv, &t0, &t1);
+ fp2_sqr(&t1, &t1);
+ fp2_mul(j_inv, j_inv, &t1);
+ fp2_add(&t0, &t0, &t0);
+ fp2_add(&t0, &t0, &t0);
+ fp2_sqr(&t1, &t0);
+ fp2_mul(&t0, &t0, &t1);
+ fp2_add(&t0, &t0, &t0);
+ fp2_add(&t0, &t0, &t0);
+ fp2_inv(j_inv);
+ fp2_mul(j_inv, &t0, j_inv);
+}
+
+void
+xDBL_E0(ec_point_t *Q, const ec_point_t *P)
+{ // Doubling of a Montgomery point in projective coordinates (X:Z) on the curve E0 with (A:C) = (0:1).
+ // Input: projective Montgomery x-coordinates P = (XP:ZP), where xP=XP/ZP, and Montgomery curve constants (A:C) = (0:1).
+ // Output: projective Montgomery x-coordinates Q <- 2*P = (XQ:ZQ) such that x(2P)=XQ/ZQ.
+ fp2_t t0, t1, t2;
+
+ fp2_add(&t0, &P->x, &P->z);
+ fp2_sqr(&t0, &t0);
+ fp2_sub(&t1, &P->x, &P->z);
+ fp2_sqr(&t1, &t1);
+ fp2_sub(&t2, &t0, &t1);
+ fp2_add(&t1, &t1, &t1);
+ fp2_mul(&Q->x, &t0, &t1);
+ fp2_add(&Q->z, &t1, &t2);
+ fp2_mul(&Q->z, &Q->z, &t2);
+}
+
+void
+xDBL(ec_point_t *Q, const ec_point_t *P, const ec_point_t *AC)
+{ // Doubling of a Montgomery point in projective coordinates (X:Z). Computation of coefficient values A+2C and 4C
+ // on-the-fly.
+ // Input: projective Montgomery x-coordinates P = (XP:ZP), where xP=XP/ZP, and Montgomery curve constants (A:C).
+ // Output: projective Montgomery x-coordinates Q <- 2*P = (XQ:ZQ) such that x(2P)=XQ/ZQ.
+ fp2_t t0, t1, t2, t3;
+
+ fp2_add(&t0, &P->x, &P->z);
+ fp2_sqr(&t0, &t0);
+ fp2_sub(&t1, &P->x, &P->z);
+ fp2_sqr(&t1, &t1);
+ fp2_sub(&t2, &t0, &t1);
+ fp2_add(&t3, &AC->z, &AC->z);
+ fp2_mul(&t1, &t1, &t3);
+ fp2_add(&t1, &t1, &t1);
+ fp2_mul(&Q->x, &t0, &t1);
+ fp2_add(&t0, &t3, &AC->x);
+ fp2_mul(&t0, &t0, &t2);
+ fp2_add(&t0, &t0, &t1);
+ fp2_mul(&Q->z, &t0, &t2);
+}
+
+void
+xDBL_A24(ec_point_t *Q, const ec_point_t *P, const ec_point_t *A24, const bool A24_normalized)
+{ // Doubling of a Montgomery point in projective coordinates (X:Z).
+ // Input: projective Montgomery x-coordinates P = (XP:ZP), where xP=XP/ZP, and
+ // the Montgomery curve constants A24 = (A+2C:4C) (or A24 = (A+2C/4C:1) if normalized).
+ // Output: projective Montgomery x-coordinates Q <- 2*P = (XQ:ZQ) such that x(2P)=XQ/ZQ.
+ fp2_t t0, t1, t2;
+
+ fp2_add(&t0, &P->x, &P->z);
+ fp2_sqr(&t0, &t0);
+ fp2_sub(&t1, &P->x, &P->z);
+ fp2_sqr(&t1, &t1);
+ fp2_sub(&t2, &t0, &t1);
+ if (!A24_normalized)
+ fp2_mul(&t1, &t1, &A24->z);
+ fp2_mul(&Q->x, &t0, &t1);
+ fp2_mul(&t0, &t2, &A24->x);
+ fp2_add(&t0, &t0, &t1);
+ fp2_mul(&Q->z, &t0, &t2);
+}
+
+void
+xADD(ec_point_t *R, const ec_point_t *P, const ec_point_t *Q, const ec_point_t *PQ)
+{ // Differential addition of Montgomery points in projective coordinates (X:Z).
+ // Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, and difference
+ // PQ=P-Q=(XPQ:ZPQ).
+ // Output: projective Montgomery point R <- P+Q = (XR:ZR) such that x(P+Q)=XR/ZR.
+ fp2_t t0, t1, t2, t3;
+
+ fp2_add(&t0, &P->x, &P->z);
+ fp2_sub(&t1, &P->x, &P->z);
+ fp2_add(&t2, &Q->x, &Q->z);
+ fp2_sub(&t3, &Q->x, &Q->z);
+ fp2_mul(&t0, &t0, &t3);
+ fp2_mul(&t1, &t1, &t2);
+ fp2_add(&t2, &t0, &t1);
+ fp2_sub(&t3, &t0, &t1);
+ fp2_sqr(&t2, &t2);
+ fp2_sqr(&t3, &t3);
+ fp2_mul(&t2, &PQ->z, &t2);
+ fp2_mul(&R->z, &PQ->x, &t3);
+ fp2_copy(&R->x, &t2);
+}
+
+void
+xDBLADD(ec_point_t *R,
+ ec_point_t *S,
+ const ec_point_t *P,
+ const ec_point_t *Q,
+ const ec_point_t *PQ,
+ const ec_point_t *A24,
+ const bool A24_normalized)
+{ // Simultaneous doubling and differential addition.
+ // Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, the difference
+ // PQ=P-Q=(XPQ:ZPQ), and the Montgomery curve constants A24 = (A+2C:4C) (or A24 = (A+2C/4C:1) if normalized).
+ // Output: projective Montgomery points R <- 2*P = (XR:ZR) such that x(2P)=XR/ZR, and S <- P+Q = (XS:ZS) such that =
+ // x(Q+P)=XS/ZS.
+ fp2_t t0, t1, t2;
+
+ fp2_add(&t0, &P->x, &P->z);
+ fp2_sub(&t1, &P->x, &P->z);
+ fp2_sqr(&R->x, &t0);
+ fp2_sub(&t2, &Q->x, &Q->z);
+ fp2_add(&S->x, &Q->x, &Q->z);
+ fp2_mul(&t0, &t0, &t2);
+ fp2_sqr(&R->z, &t1);
+ fp2_mul(&t1, &t1, &S->x);
+ fp2_sub(&t2, &R->x, &R->z);
+ if (!A24_normalized)
+ fp2_mul(&R->z, &R->z, &A24->z);
+ fp2_mul(&R->x, &R->x, &R->z);
+ fp2_mul(&S->x, &A24->x, &t2);
+ fp2_sub(&S->z, &t0, &t1);
+ fp2_add(&R->z, &R->z, &S->x);
+ fp2_add(&S->x, &t0, &t1);
+ fp2_mul(&R->z, &R->z, &t2);
+ fp2_sqr(&S->z, &S->z);
+ fp2_sqr(&S->x, &S->x);
+ fp2_mul(&S->z, &S->z, &PQ->x);
+ fp2_mul(&S->x, &S->x, &PQ->z);
+}
+
+void
+xMUL(ec_point_t *Q, const ec_point_t *P, const digit_t *k, const int kbits, const ec_curve_t *curve)
+{ // The Montgomery ladder
+ // Input: projective Montgomery point P=(XP:ZP) such that xP=XP/ZP, a scalar k of bitlength kbits, and
+ // the Montgomery curve constants (A:C) (or A24 = (A+2C/4C:1) if normalized).
+ // Output: projective Montgomery points Q <- k*P = (XQ:ZQ) such that x(k*P)=XQ/ZQ.
+ ec_point_t R0, R1, A24;
+ digit_t mask;
+ unsigned int bit, prevbit = 0, swap;
+
+ if (!curve->is_A24_computed_and_normalized) {
+ // Computation of A24=(A+2C:4C)
+ fp2_add(&A24.x, &curve->C, &curve->C);
+ fp2_add(&A24.z, &A24.x, &A24.x);
+ fp2_add(&A24.x, &A24.x, &curve->A);
+ } else {
+ fp2_copy(&A24.x, &curve->A24.x);
+ fp2_copy(&A24.z, &curve->A24.z);
+ // Assert A24 has been normalised
+ assert(fp2_is_one(&A24.z));
+ }
+
+ // R0 <- (1:0), R1 <- P
+ ec_point_init(&R0);
+ fp2_copy(&R1.x, &P->x);
+ fp2_copy(&R1.z, &P->z);
+
+ // Main loop
+ for (int i = kbits - 1; i >= 0; i--) {
+ bit = (k[i >> LOG2RADIX] >> (i & (RADIX - 1))) & 1;
+ swap = bit ^ prevbit;
+ prevbit = bit;
+ mask = 0 - (digit_t)swap;
+
+ cswap_points(&R0, &R1, mask);
+ xDBLADD(&R0, &R1, &R0, &R1, P, &A24, true);
+ }
+ swap = 0 ^ prevbit;
+ mask = 0 - (digit_t)swap;
+ cswap_points(&R0, &R1, mask);
+
+ fp2_copy(&Q->x, &R0.x);
+ fp2_copy(&Q->z, &R0.z);
+}
+
+int
+xDBLMUL(ec_point_t *S,
+ const ec_point_t *P,
+ const digit_t *k,
+ const ec_point_t *Q,
+ const digit_t *l,
+ const ec_point_t *PQ,
+ const int kbits,
+ const ec_curve_t *curve)
+{ // The Montgomery biladder
+ // Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, scalars k and l of
+ // bitlength kbits, the difference PQ=P-Q=(XPQ:ZPQ), and the Montgomery curve constants (A:C).
+ // Output: projective Montgomery point S <- k*P + l*Q = (XS:ZS) such that x(k*P + l*Q)=XS/ZS.
+
+ int i, A_is_zero;
+ digit_t evens, mevens, bitk0, bitl0, maskk, maskl, temp, bs1_ip1, bs2_ip1, bs1_i, bs2_i, h;
+ digit_t sigma[2] = { 0 }, pre_sigma = 0;
+ digit_t k_t[NWORDS_ORDER], l_t[NWORDS_ORDER], one[NWORDS_ORDER] = { 0 }, r[2 * BITS] = { 0 };
+ ec_point_t DIFF1a, DIFF1b, DIFF2a, DIFF2b, R[3] = { 0 }, T[3];
+
+ // differential additions formulas are invalid in this case
+ if (ec_has_zero_coordinate(P) | ec_has_zero_coordinate(Q) | ec_has_zero_coordinate(PQ))
+ return 0;
+
+ // Derive sigma according to parity
+ bitk0 = (k[0] & 1);
+ bitl0 = (l[0] & 1);
+ maskk = 0 - bitk0; // Parity masks: 0 if even, otherwise 1...1
+ maskl = 0 - bitl0;
+ sigma[0] = (bitk0 ^ 1);
+ sigma[1] = (bitl0 ^ 1);
+ evens = sigma[0] + sigma[1]; // Count number of even scalars
+ mevens = 0 - (evens & 1); // Mask mevens <- 0 if # even of scalars = 0 or 2, otherwise mevens = 1...1
+
+ // If k and l are both even or both odd, pick sigma = (0,1)
+ sigma[0] = (sigma[0] & mevens);
+ sigma[1] = (sigma[1] & mevens) | (1 & ~mevens);
+
+ // Convert even scalars to odd
+ one[0] = 1;
+ mp_sub(k_t, k, one, NWORDS_ORDER);
+ mp_sub(l_t, l, one, NWORDS_ORDER);
+ select_ct(k_t, k_t, k, maskk, NWORDS_ORDER);
+ select_ct(l_t, l_t, l, maskl, NWORDS_ORDER);
+
+ // Scalar recoding
+ for (i = 0; i < kbits; i++) {
+ // If sigma[0] = 1 swap k_t and l_t
+ maskk = 0 - (sigma[0] ^ pre_sigma);
+ swap_ct(k_t, l_t, maskk, NWORDS_ORDER);
+
+ if (i == kbits - 1) {
+ bs1_ip1 = 0;
+ bs2_ip1 = 0;
+ } else {
+ bs1_ip1 = mp_shiftr(k_t, 1, NWORDS_ORDER);
+ bs2_ip1 = mp_shiftr(l_t, 1, NWORDS_ORDER);
+ }
+ bs1_i = k_t[0] & 1;
+ bs2_i = l_t[0] & 1;
+
+ r[2 * i] = bs1_i ^ bs1_ip1;
+ r[2 * i + 1] = bs2_i ^ bs2_ip1;
+
+ // Revert sigma if second bit, r_(2i+1), is 1
+ pre_sigma = sigma[0];
+ maskk = 0 - r[2 * i + 1];
+ select_ct(&temp, &sigma[0], &sigma[1], maskk, 1);
+ select_ct(&sigma[1], &sigma[1], &sigma[0], maskk, 1);
+ sigma[0] = temp;
+ }
+
+ // Point initialization
+ ec_point_init(&R[0]);
+ maskk = 0 - sigma[0];
+ select_point(&R[1], P, Q, maskk);
+ select_point(&R[2], Q, P, maskk);
+
+ fp2_copy(&DIFF1a.x, &R[1].x);
+ fp2_copy(&DIFF1a.z, &R[1].z);
+ fp2_copy(&DIFF1b.x, &R[2].x);
+ fp2_copy(&DIFF1b.z, &R[2].z);
+
+ // Initialize DIFF2a <- P+Q, DIFF2b <- P-Q
+ xADD(&R[2], &R[1], &R[2], PQ);
+ if (ec_has_zero_coordinate(&R[2]))
+ return 0; // non valid formulas
+
+ fp2_copy(&DIFF2a.x, &R[2].x);
+ fp2_copy(&DIFF2a.z, &R[2].z);
+ fp2_copy(&DIFF2b.x, &PQ->x);
+ fp2_copy(&DIFF2b.z, &PQ->z);
+
+ A_is_zero = fp2_is_zero(&curve->A);
+
+ // Main loop
+ for (i = kbits - 1; i >= 0; i--) {
+ h = r[2 * i] + r[2 * i + 1]; // in {0, 1, 2}
+ maskk = 0 - (h & 1);
+ select_point(&T[0], &R[0], &R[1], maskk);
+ maskk = 0 - (h >> 1);
+ select_point(&T[0], &T[0], &R[2], maskk);
+ if (A_is_zero) {
+ xDBL_E0(&T[0], &T[0]);
+ } else {
+ assert(fp2_is_one(&curve->A24.z));
+ xDBL_A24(&T[0], &T[0], &curve->A24, true);
+ }
+
+ maskk = 0 - r[2 * i + 1]; // in {0, 1}
+ select_point(&T[1], &R[0], &R[1], maskk);
+ select_point(&T[2], &R[1], &R[2], maskk);
+
+ cswap_points(&DIFF1a, &DIFF1b, maskk);
+ xADD(&T[1], &T[1], &T[2], &DIFF1a);
+ xADD(&T[2], &R[0], &R[2], &DIFF2a);
+
+ // If hw (mod 2) = 1 then swap DIFF2a and DIFF2b
+ maskk = 0 - (h & 1);
+ cswap_points(&DIFF2a, &DIFF2b, maskk);
+
+ // R <- T
+ copy_point(&R[0], &T[0]);
+ copy_point(&R[1], &T[1]);
+ copy_point(&R[2], &T[2]);
+ }
+
+ // Output R[evens]
+ select_point(S, &R[0], &R[1], mevens);
+
+ maskk = 0 - (bitk0 & bitl0);
+ select_point(S, S, &R[2], maskk);
+ return 1;
+}
+
+int
+ec_ladder3pt(ec_point_t *R,
+ const digit_t *m,
+ const ec_point_t *P,
+ const ec_point_t *Q,
+ const ec_point_t *PQ,
+ const ec_curve_t *E)
+{ // The 3-point Montgomery ladder
+ // Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, a scalar k of
+ // bitlength kbits, the difference PQ=P-Q=(XPQ:ZPQ), and the Montgomery curve constants A24 = (A+2C/4C:1).
+ // Output: projective Montgomery point R <- P + m*Q = (XR:ZR) such that x(P + m*Q)=XR/ZR.
+ assert(E->is_A24_computed_and_normalized);
+ if (!fp2_is_one(&E->A24.z)) {
+ return 0;
+ }
+ // Formulas are not valid in that case
+ if (ec_has_zero_coordinate(PQ)) {
+ return 0;
+ }
+
+ ec_point_t X0, X1, X2;
+ copy_point(&X0, Q);
+ copy_point(&X1, P);
+ copy_point(&X2, PQ);
+
+ int i, j;
+ digit_t t;
+ for (i = 0; i < NWORDS_ORDER; i++) {
+ t = 1;
+ for (j = 0; j < RADIX; j++) {
+ cswap_points(&X1, &X2, -((t & m[i]) == 0));
+ xDBLADD(&X0, &X1, &X0, &X1, &X2, &E->A24, true);
+ cswap_points(&X1, &X2, -((t & m[i]) == 0));
+ t <<= 1;
+ };
+ };
+ copy_point(R, &X1);
+ return 1;
+}
+
+// WRAPPERS to export
+
+void
+ec_dbl(ec_point_t *res, const ec_point_t *P, const ec_curve_t *curve)
+{
+ // If A24 = ((A+2)/4 : 1) we save multiplications
+ if (curve->is_A24_computed_and_normalized) {
+ assert(fp2_is_one(&curve->A24.z));
+ xDBL_A24(res, P, &curve->A24, true);
+ } else {
+ // Otherwise we compute A24 on the fly for doubling
+ xDBL(res, P, (const ec_point_t *)curve);
+ }
+}
+
+void
+ec_dbl_iter(ec_point_t *res, int n, const ec_point_t *P, ec_curve_t *curve)
+{
+ if (n == 0) {
+ copy_point(res, P);
+ return;
+ }
+
+ // When the chain is long enough, we should normalise A24
+ if (n > 50) {
+ ec_curve_normalize_A24(curve);
+ }
+
+ // When A24 is normalized we can save some multiplications
+ if (curve->is_A24_computed_and_normalized) {
+ assert(fp2_is_one(&curve->A24.z));
+ xDBL_A24(res, P, &curve->A24, true);
+ for (int i = 0; i < n - 1; i++) {
+ assert(fp2_is_one(&curve->A24.z));
+ xDBL_A24(res, res, &curve->A24, true);
+ }
+ } else {
+ // Otherwise we do normal doubling
+ xDBL(res, P, (const ec_point_t *)curve);
+ for (int i = 0; i < n - 1; i++) {
+ xDBL(res, res, (const ec_point_t *)curve);
+ }
+ }
+}
+
+void
+ec_dbl_iter_basis(ec_basis_t *res, int n, const ec_basis_t *B, ec_curve_t *curve)
+{
+ ec_dbl_iter(&res->P, n, &B->P, curve);
+ ec_dbl_iter(&res->Q, n, &B->Q, curve);
+ ec_dbl_iter(&res->PmQ, n, &B->PmQ, curve);
+}
+
+void
+ec_mul(ec_point_t *res, const digit_t *scalar, const int kbits, const ec_point_t *P, ec_curve_t *curve)
+{
+ // For large scalars it's worth normalising anyway
+ if (kbits > 50) {
+ ec_curve_normalize_A24(curve);
+ }
+
+ // When A24 is computed and normalized we save some Fp2 multiplications
+ xMUL(res, P, scalar, kbits, curve);
+}
+
+int
+ec_biscalar_mul(ec_point_t *res,
+ const digit_t *scalarP,
+ const digit_t *scalarQ,
+ const int kbits,
+ const ec_basis_t *PQ,
+ const ec_curve_t *curve)
+{
+ if (fp2_is_zero(&PQ->PmQ.z))
+ return 0;
+
+ /* Differential additions behave badly when PmQ = (0:1), so we need to
+ * treat this case specifically. Since we assume P, Q are a basis, this
+ * can happen only if kbits==1 */
+ if (kbits == 1) {
+ // Sanity check: our basis should be given by 2-torsion points
+ if (!ec_is_two_torsion(&PQ->P, curve) || !ec_is_two_torsion(&PQ->Q, curve) ||
+ !ec_is_two_torsion(&PQ->PmQ, curve))
+ return 0;
+ digit_t bP, bQ;
+ bP = (scalarP[0] & 1);
+ bQ = (scalarQ[0] & 1);
+ if (bP == 0 && bQ == 0)
+ ec_point_init(res); //(1: 0)
+ else if (bP == 1 && bQ == 0)
+ copy_point(res, &PQ->P);
+ else if (bP == 0 && bQ == 1)
+ copy_point(res, &PQ->Q);
+ else if (bP == 1 && bQ == 1)
+ copy_point(res, &PQ->PmQ);
+ else // should never happen
+ assert(0);
+ return 1;
+ } else {
+ ec_curve_t E;
+ copy_curve(&E, curve);
+
+ if (!fp2_is_zero(&curve->A)) { // If A is not zero normalize
+ ec_curve_normalize_A24(&E);
+ }
+ return xDBLMUL(res, &PQ->P, scalarP, &PQ->Q, scalarQ, &PQ->PmQ, kbits, (const ec_curve_t *)&E);
+ }
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec.h
new file mode 100644
index 0000000000..7cef95ca49
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec.h
@@ -0,0 +1,617 @@
+/** @file
+ *
+ * @authors Luca De Feo, Francisco RH
+ *
+ * @brief Elliptic curve stuff
+ */
+
+#ifndef EC_H
+#define EC_H
+#include
+#include
+#include
+#include
+#include
+
+/** @defgroup ec Elliptic curves
+ * @{
+ */
+
+/** @defgroup ec_t Data structures
+ * @{
+ */
+
+/** @brief Projective point on the Kummer line E/pm 1 in Montgomery coordinates
+ *
+ * @typedef ec_point_t
+ *
+ * @struct ec_point_t
+ *
+ * A projective point in (X:Z) or (X:Y:Z) coordinates (tbd).
+ */
+typedef struct ec_point_t
+{
+ fp2_t x;
+ fp2_t z;
+} ec_point_t;
+
+/** @brief Projective point in Montgomery coordinates
+ *
+ * @typedef jac_point_t
+ *
+ * @struct jac_point_t
+ *
+ * A projective point in (X:Y:Z) coordinates
+ */
+typedef struct jac_point_t
+{
+ fp2_t x;
+ fp2_t y;
+ fp2_t z;
+} jac_point_t;
+
+/** @brief Addition components
+ *
+ * @typedef add_components_t
+ *
+ * @struct add_components_t
+ *
+ * 3 components u,v,w that define the (X:Z) coordinates of both
+ * addition and substraction of two distinct points with
+ * P+Q =(u-v:w) and P-Q = (u+v=w)
+ */
+typedef struct add_components_t
+{
+ fp2_t u;
+ fp2_t v;
+ fp2_t w;
+} add_components_t;
+
+/** @brief A basis of a torsion subgroup
+ *
+ * @typedef ec_basis_t
+ *
+ * @struct ec_basis_t
+ *
+ * A pair of points (or a triplet, tbd) forming a basis of a torsion subgroup.
+ */
+typedef struct ec_basis_t
+{
+ ec_point_t P;
+ ec_point_t Q;
+ ec_point_t PmQ;
+} ec_basis_t;
+
+/** @brief An elliptic curve
+ *
+ * @typedef ec_curve_t
+ *
+ * @struct ec_curve_t
+ *
+ * An elliptic curve in projective Montgomery form
+ */
+typedef struct ec_curve_t
+{
+ fp2_t A;
+ fp2_t C; ///< cannot be 0
+ ec_point_t A24; // the point (A+2 : 4C)
+ bool is_A24_computed_and_normalized; // says if A24 has been computed and normalized
+} ec_curve_t;
+
+/** @brief An isogeny of degree a power of 2
+ *
+ * @typedef ec_isog_even_t
+ *
+ * @struct ec_isog_even_t
+ */
+typedef struct ec_isog_even_t
+{
+ ec_curve_t curve; ///< The domain curve
+ ec_point_t kernel; ///< A kernel generator
+ unsigned length; ///< The length as a 2-isogeny walk
+} ec_isog_even_t;
+
+/** @brief Isomorphism of Montgomery curves
+ *
+ * @typedef ec_isom_t
+ *
+ * @struct ec_isom_t
+ *
+ * The isomorphism is given by the map maps (X:Z) ↦ ( (Nx X + Nz Z) : (D Z) )
+ */
+typedef struct ec_isom_t
+{
+ fp2_t Nx;
+ fp2_t Nz;
+ fp2_t D;
+} ec_isom_t;
+
+// end ec_t
+/** @}
+ */
+
+/** @defgroup ec_curve_t Curves and isomorphisms
+ * @{
+ */
+
+// Initalisation for curves and points
+void ec_curve_init(ec_curve_t *E);
+void ec_point_init(ec_point_t *P);
+
+/**
+ * @brief Verify that a Montgomery coefficient is valid
+ *
+ * @param A an fp2_t
+ *
+ * @return 0 if curve is invalid, 1 otherwise
+ */
+int ec_curve_verify_A(const fp2_t *A);
+
+/**
+ * @brief Initialize an elliptic curve from a coefficient
+ *
+ * @param A an fp2_t
+ * @param E the elliptic curve to initialize
+ *
+ * @return 0 if curve is invalid, 1 otherwise
+ */
+int ec_curve_init_from_A(ec_curve_t *E, const fp2_t *A);
+
+// Copying points, bases and curves
+static inline void
+copy_point(ec_point_t *P, const ec_point_t *Q)
+{
+ fp2_copy(&P->x, &Q->x);
+ fp2_copy(&P->z, &Q->z);
+}
+
+static inline void
+copy_basis(ec_basis_t *B1, const ec_basis_t *B0)
+{
+ copy_point(&B1->P, &B0->P);
+ copy_point(&B1->Q, &B0->Q);
+ copy_point(&B1->PmQ, &B0->PmQ);
+}
+
+static inline void
+copy_curve(ec_curve_t *E1, const ec_curve_t *E2)
+{
+ fp2_copy(&(E1->A), &(E2->A));
+ fp2_copy(&(E1->C), &(E2->C));
+ E1->is_A24_computed_and_normalized = E2->is_A24_computed_and_normalized;
+ copy_point(&E1->A24, &E2->A24);
+}
+
+// Functions for working with the A24 point and normalisation
+
+/**
+ * @brief Reduce (A : C) to (A/C : 1) in place
+ *
+ * @param E a curve
+ */
+void ec_normalize_curve(ec_curve_t *E);
+
+/**
+ * @brief Reduce (A + 2 : 4C) to ((A+2)/4C : 1) in place
+ *
+ * @param E a curve
+ */
+void ec_curve_normalize_A24(ec_curve_t *E);
+
+/**
+ * @brief Normalise both (A : C) and (A + 2 : 4C) as above, in place
+ *
+ * @param E a curve
+ */
+void ec_normalize_curve_and_A24(ec_curve_t *E);
+
+/**
+ * @brief Given a curve E, compute (A+2 : 4C)
+ *
+ * @param A24 the value (A+2 : 4C) to return into
+ * @param E a curve
+ */
+static inline void
+AC_to_A24(ec_point_t *A24, const ec_curve_t *E)
+{
+ // Maybe we already have this computed
+ if (E->is_A24_computed_and_normalized) {
+ copy_point(A24, &E->A24);
+ return;
+ }
+
+ // A24 = (A+2C : 4C)
+ fp2_add(&A24->z, &E->C, &E->C);
+ fp2_add(&A24->x, &E->A, &A24->z);
+ fp2_add(&A24->z, &A24->z, &A24->z);
+}
+
+/**
+ * @brief Given a curve the point (A+2 : 4C) compute the curve coefficients (A : C)
+ *
+ * @param E a curve to compute
+ * @param A24 the value (A+2 : 4C)
+ */
+static inline void
+A24_to_AC(ec_curve_t *E, const ec_point_t *A24)
+{
+ // (A:C) = ((A+2C)*2-4C : 4C)
+ fp2_add(&E->A, &A24->x, &A24->x);
+ fp2_sub(&E->A, &E->A, &A24->z);
+ fp2_add(&E->A, &E->A, &E->A);
+ fp2_copy(&E->C, &A24->z);
+}
+
+/**
+ * @brief j-invariant.
+ *
+ * @param j_inv computed j_invariant
+ * @param curve input curve
+ */
+void ec_j_inv(fp2_t *j_inv, const ec_curve_t *curve);
+
+/**
+ * @brief Isomorphism of elliptic curve
+ * Takes as input two isomorphic Kummer lines in Montgomery form, and output an isomorphism between
+ * them
+ *
+ * @param isom computed isomorphism
+ * @param from domain curve
+ * @param to image curve
+ * @return 0xFFFFFFFF if there was an error during the computation, zero otherwise
+ */
+uint32_t ec_isomorphism(ec_isom_t *isom, const ec_curve_t *from, const ec_curve_t *to);
+
+/**
+ * @brief In-place evaluation of an isomorphism
+ *
+ * @param P a point
+ * @param isom an isomorphism
+ */
+void ec_iso_eval(ec_point_t *P, ec_isom_t *isom);
+
+/** @}
+ */
+/** @defgroup ec_point_t Point operations
+ * @{
+ */
+
+/**
+ * @brief Point equality
+ *
+ * @param P a point
+ * @param Q a point
+ * @return 0xFFFFFFFF if equal, zero otherwise
+ */
+uint32_t ec_is_equal(const ec_point_t *P, const ec_point_t *Q);
+
+/**
+ * @brief Point equality
+ *
+ * @param P a point
+ * @return 0xFFFFFFFF if point at infinity, zero otherwise
+ */
+uint32_t ec_is_zero(const ec_point_t *P);
+
+/**
+ * @brief Two torsion test
+ *
+ * @param P a point
+ * @param E the elliptic curve
+ * @return 0xFFFFFFFF if P is 2-torsion but not zero, zero otherwise
+ */
+uint32_t ec_is_two_torsion(const ec_point_t *P, const ec_curve_t *E);
+
+/**
+ * @brief Four torsion test
+ *
+ * @param P a point
+ * @param E the elliptic curve
+ * @return 0xFFFFFFFF if P is 2-torsion but not zero, zero otherwise
+ */
+uint32_t ec_is_four_torsion(const ec_point_t *P, const ec_curve_t *E);
+
+/**
+ * @brief Reduce Z-coordinate of point in place
+ *
+ * @param P a point
+ */
+void ec_normalize_point(ec_point_t *P);
+
+void xDBL_E0(ec_point_t *Q, const ec_point_t *P);
+void xADD(ec_point_t *R, const ec_point_t *P, const ec_point_t *Q, const ec_point_t *PQ);
+void xDBL_A24(ec_point_t *Q, const ec_point_t *P, const ec_point_t *A24, const bool A24_normalized);
+
+/**
+ * @brief Point doubling
+ *
+ * @param res computed double of P
+ * @param P a point
+ * @param curve an elliptic curve
+ */
+void ec_dbl(ec_point_t *res, const ec_point_t *P, const ec_curve_t *curve);
+
+/**
+ * @brief Point iterated doubling
+ *
+ * @param res computed double of P
+ * @param P a point
+ * @param n the number of double
+ * @param curve the curve on which P lays
+ */
+void ec_dbl_iter(ec_point_t *res, int n, const ec_point_t *P, ec_curve_t *curve);
+
+/**
+ * @brief Iterated doubling for a basis P, Q, PmQ
+ *
+ * @param res the computed iterated double of basis B
+ * @param n the number of doubles
+ * @param B the basis to double
+ * @param curve the parent curve of the basis
+ */
+void ec_dbl_iter_basis(ec_basis_t *res, int n, const ec_basis_t *B, ec_curve_t *curve);
+
+/**
+ * @brief Point multiplication
+ *
+ * @param res computed scalar * P
+ * @param curve the curve
+ * @param scalar an unsigned multi-precision integer
+ * @param P a point
+ * @param kbits numer of bits of the scalar
+ */
+void ec_mul(ec_point_t *res, const digit_t *scalar, const int kbits, const ec_point_t *P, ec_curve_t *curve);
+
+/**
+ * @brief Combination P+m*Q
+ *
+ * @param R computed P + m * Q
+ * @param curve the curve
+ * @param m an unsigned multi-precision integer
+ * @param P a point
+ * @param Q a point
+ * @param PQ the difference P-Q
+ * @return 0 if there was an error, 1 otherwise
+ */
+int ec_ladder3pt(ec_point_t *R,
+ const digit_t *m,
+ const ec_point_t *P,
+ const ec_point_t *Q,
+ const ec_point_t *PQ,
+ const ec_curve_t *curve);
+
+/**
+ * @brief Linear combination of points of a basis
+ *
+ * @param res computed scalarP * P + scalarQ * Q
+ * @param scalarP an unsigned multi-precision integer
+ * @param scalarQ an unsigned multi-precision integer
+ * @param kbits number of bits of the scalars, or n for points of order 2^n
+ * @param PQ a torsion basis consisting of points P and Q
+ * @param curve the curve
+ *
+ * @return 0 if there was an error, 1 otherwise
+ */
+int ec_biscalar_mul(ec_point_t *res,
+ const digit_t *scalarP,
+ const digit_t *scalarQ,
+ const int kbits,
+ const ec_basis_t *PQ,
+ const ec_curve_t *curve);
+
+// end point computations
+/**
+ * @}
+ */
+
+/** @defgroup ec_dlog_t Torsion basis computations
+ * @{
+ */
+
+/**
+ * @brief Generate a 2^f-torsion basis from a Montgomery curve along with a hint
+ *
+ * @param PQ2 an ec_basis_t
+ * @param curve an ec_curve_t
+ * @param f an integer
+ *
+ * @return A hint
+ *
+ * The algorithm is deterministc
+ */
+uint8_t ec_curve_to_basis_2f_to_hint(ec_basis_t *PQ2, ec_curve_t *curve, int f);
+
+/**
+ * @brief Generate a 2^f-torsion basis from a Montgomery curve and a given hint
+ *
+ * @param PQ2 an ec_basis_t
+ * @param curve an ec_curve_t
+ * @param f an integer
+ * @param hint the hint
+ *
+ * @return 1 is the basis is valid, 0 otherwise
+ *
+ * The algorithm is deterministc
+ */
+int ec_curve_to_basis_2f_from_hint(ec_basis_t *PQ2, ec_curve_t *curve, int f, const uint8_t hint);
+/** // end basis computations
+ * @}
+ */
+
+/** @defgroup ec_isog_t Isogenies
+ * @{
+ */
+
+/**
+ * @brief Evaluate isogeny of even degree on list of points.
+ * Returns 0 if successful and -1 if kernel has the wrong order or includes (0:1).
+ *
+ * @param image computed image curve
+ * @param phi isogeny
+ * @param points a list of points to evaluate the isogeny on, modified in place
+ * @param len_points length of the list points
+ *
+ * @return 0 if there was no error, 0xFFFFFFFF otherwise
+ */
+uint32_t ec_eval_even(ec_curve_t *image, ec_isog_even_t *phi, ec_point_t *points, unsigned len_points);
+
+/**
+ * @brief Multiplicative strategy for a short isogeny chain. Returns 1 if successfull and -1
+ * if kernel has the wrong order or includes (0:1) when special=false.
+ *
+ * @param curve domain curve, to be overwritten by the codomain curve.
+ * @param kernel a kernel generator of order 2^len
+ * @param len the length of t he 2-isogeny chain
+ * @param points a list of points to evaluate the isogeny on, modified in place
+ * @param len_points length of the list points
+ * @param special if true, allow isogenies with (0:1) in the kernel
+ *
+ * @return 0 if there was no error, 0xFFFFFFFF otherwise
+ */
+uint32_t ec_eval_small_chain(ec_curve_t *curve,
+ const ec_point_t *kernel,
+ int len,
+ ec_point_t *points,
+ unsigned len_points,
+ bool special);
+
+/**
+ * @brief Recover Y-coordinate from X-coordinate and curve coefficients.
+ *
+ * @param y: a y-coordinate
+ * @param Px: a x-coordinate
+ * @param curve: the elliptic curve
+ *
+ * @return 0xFFFFFFFF if the point was on the curve, 0 otherwise
+ */
+uint32_t ec_recover_y(fp2_t *y, const fp2_t *Px, const ec_curve_t *curve);
+
+// Jacobian point init and copying
+void jac_init(jac_point_t *P);
+void copy_jac_point(jac_point_t *P, const jac_point_t *Q);
+
+/**
+ * @brief Test if two Jacobian points are equal
+ *
+ * @param P: a point
+ * @param Q: a point
+ *
+ * @return 0xFFFFFFFF if they are equal, 0 otherwise
+ */
+uint32_t jac_is_equal(const jac_point_t *P, const jac_point_t *Q);
+
+// Convert from Jacobian to x-only (just drop the Y-coordinate)
+void jac_to_xz(ec_point_t *P, const jac_point_t *xyP);
+// Convert from Jacobian coordinates in Montgomery model to Weierstrass
+void jac_to_ws(jac_point_t *P, fp2_t *t, fp2_t *ao3, const jac_point_t *Q, const ec_curve_t *curve);
+void jac_from_ws(jac_point_t *Q, const jac_point_t *P, const fp2_t *ao3, const ec_curve_t *curve);
+
+// Jacobian arithmetic
+void jac_neg(jac_point_t *Q, const jac_point_t *P);
+void ADD(jac_point_t *R, const jac_point_t *P, const jac_point_t *Q, const ec_curve_t *AC);
+void DBL(jac_point_t *Q, const jac_point_t *P, const ec_curve_t *AC);
+void DBLW(jac_point_t *Q, fp2_t *u, const jac_point_t *P, const fp2_t *t);
+void jac_to_xz_add_components(add_components_t *uvw, const jac_point_t *P, const jac_point_t *Q, const ec_curve_t *AC);
+
+/**
+ * @brief Given a basis in x-only, lift to a pair of Jacobian points
+ *
+ * @param P: a point
+ * @param Q: a point
+ * @param B: a basis
+ * @param E: an elliptic curve
+ *
+ * @return 0xFFFFFFFF if there was no error, 0 otherwise
+ *
+ *
+ * Lifts a basis x(P), x(Q), x(P-Q) assuming the curve has (A/C : 1) and
+ * the point P = (X/Z : 1). For generic implementation see lift_basis()
+ */
+uint32_t lift_basis_normalized(jac_point_t *P, jac_point_t *Q, ec_basis_t *B, ec_curve_t *E);
+
+/**
+ * @brief Given a basis in x-only, lift to a pair of Jacobian points
+ *
+ * @param P: a point
+ * @param Q: a point
+ * @param B: a basis
+ * @param E: an elliptic curve
+ *
+ * @return 0xFFFFFFFF if there was no error, 0 otherwise
+ */
+uint32_t lift_basis(jac_point_t *P, jac_point_t *Q, ec_basis_t *B, ec_curve_t *E);
+
+/**
+ * @brief Check if basis points (P, Q) form a full 4-basis
+ *
+ * @param B: a basis
+ * @param E: an elliptic curve
+ *
+ * @return 0xFFFFFFFF if they form a basis, 0 otherwise
+ */
+uint32_t ec_is_basis_four_torsion(const ec_basis_t *B, const ec_curve_t *E);
+
+/*
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Test functions for printing and order checking, only used in debug mode
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ */
+
+/**
+ * @brief Check if a point (X : Z) has order exactly 2^t
+ *
+ * @param P: a point
+ * @param E: an elliptic curve
+ * @param t: an integer
+ *
+ * @return 0xFFFFFFFF if the order is correct, 0 otherwise
+ */
+static inline int
+test_point_order_twof(const ec_point_t *P, const ec_curve_t *E, int t)
+{
+ ec_point_t test;
+ ec_curve_t curve;
+ test = *P;
+ copy_curve(&curve, E);
+
+ if (ec_is_zero(&test))
+ return 0;
+ // Scale point by 2^(t-1)
+ ec_dbl_iter(&test, t - 1, &test, &curve);
+ // If it's zero now, it doesnt have order 2^t
+ if (ec_is_zero(&test))
+ return 0;
+ // Ensure [2^t] P = 0
+ ec_dbl(&test, &test, &curve);
+ return ec_is_zero(&test);
+}
+
+/**
+ * @brief Check if basis points (P, Q, PmQ) all have order exactly 2^t
+ *
+ * @param B: a basis
+ * @param E: an elliptic curve
+ * @param t: an integer
+ *
+ * @return 0xFFFFFFFF if the order is correct, 0 otherwise
+ */
+static inline int
+test_basis_order_twof(const ec_basis_t *B, const ec_curve_t *E, int t)
+{
+ int check_P = test_point_order_twof(&B->P, E, t);
+ int check_Q = test_point_order_twof(&B->Q, E, t);
+ int check_PmQ = test_point_order_twof(&B->PmQ, E, t);
+
+ return check_P & check_Q & check_PmQ;
+}
+
+#endif
+// end isogeny computations
+/**
+ * @}
+ */
+
+// end ec
+/**
+ * @}
+ */
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec_jac.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec_jac.c
new file mode 100644
index 0000000000..20ca68c9b2
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec_jac.c
@@ -0,0 +1,335 @@
+#include
+#include
+
+void
+jac_init(jac_point_t *P)
+{ // Initialize Montgomery in Jacobian coordinates as identity element (0:1:0)
+ fp2_set_zero(&P->x);
+ fp2_set_one(&P->y);
+ fp2_set_zero(&P->z);
+}
+
+uint32_t
+jac_is_equal(const jac_point_t *P, const jac_point_t *Q)
+{ // Evaluate if two points in Jacobian coordinates (X:Y:Z) are equal
+ // Returns 1 (true) if P=Q, 0 (false) otherwise
+ fp2_t t0, t1, t2, t3;
+
+ fp2_sqr(&t0, &Q->z);
+ fp2_mul(&t2, &P->x, &t0); // x1*z2^2
+ fp2_sqr(&t1, &P->z);
+ fp2_mul(&t3, &Q->x, &t1); // x2*z1^2
+ fp2_sub(&t2, &t2, &t3);
+
+ fp2_mul(&t0, &t0, &Q->z);
+ fp2_mul(&t0, &P->y, &t0); // y1*z2^3
+ fp2_mul(&t1, &t1, &P->z);
+ fp2_mul(&t1, &Q->y, &t1); // y2*z1^3
+ fp2_sub(&t0, &t0, &t1);
+
+ return fp2_is_zero(&t0) & fp2_is_zero(&t2);
+}
+
+void
+jac_to_xz(ec_point_t *P, const jac_point_t *xyP)
+{
+ fp2_copy(&P->x, &xyP->x);
+ fp2_copy(&P->z, &xyP->z);
+ fp2_sqr(&P->z, &P->z);
+
+ // If xyP = (0:1:0), we currently have P=(0 : 0) but we want to set P=(1:0)
+ uint32_t c1, c2;
+ fp2_t one;
+ fp2_set_one(&one);
+
+ c1 = fp2_is_zero(&P->x);
+ c2 = fp2_is_zero(&P->z);
+ fp2_select(&P->x, &P->x, &one, c1 & c2);
+}
+
+void
+jac_to_ws(jac_point_t *Q, fp2_t *t, fp2_t *ao3, const jac_point_t *P, const ec_curve_t *curve)
+{
+ // Cost of 3M + 2S when A != 0.
+ fp_t one;
+ fp2_t a;
+ /* a = 1 - A^2/3, U = X + (A*Z^2)/3, V = Y, W = Z, T = a*Z^4*/
+ fp_set_one(&one);
+ if (!fp2_is_zero(&(curve->A))) {
+ fp_div3(&(ao3->re), &(curve->A.re));
+ fp_div3(&(ao3->im), &(curve->A.im));
+ fp2_sqr(t, &P->z);
+ fp2_mul(&Q->x, ao3, t);
+ fp2_add(&Q->x, &Q->x, &P->x);
+ fp2_sqr(t, t);
+ fp2_mul(&a, ao3, &(curve->A));
+ fp_sub(&(a.re), &one, &(a.re));
+ fp_neg(&(a.im), &(a.im));
+ fp2_mul(t, t, &a);
+ } else {
+ fp2_copy(&Q->x, &P->x);
+ fp2_sqr(t, &P->z);
+ fp2_sqr(t, t);
+ }
+ fp2_copy(&Q->y, &P->y);
+ fp2_copy(&Q->z, &P->z);
+}
+
+void
+jac_from_ws(jac_point_t *Q, const jac_point_t *P, const fp2_t *ao3, const ec_curve_t *curve)
+{
+ // Cost of 1M + 1S when A != 0.
+ fp2_t t;
+ /* X = U - (A*W^2)/3, Y = V, Z = W. */
+ if (!fp2_is_zero(&(curve->A))) {
+ fp2_sqr(&t, &P->z);
+ fp2_mul(&t, &t, ao3);
+ fp2_sub(&Q->x, &P->x, &t);
+ }
+ fp2_copy(&Q->y, &P->y);
+ fp2_copy(&Q->z, &P->z);
+}
+
+void
+copy_jac_point(jac_point_t *P, const jac_point_t *Q)
+{
+ fp2_copy(&(P->x), &(Q->x));
+ fp2_copy(&(P->y), &(Q->y));
+ fp2_copy(&(P->z), &(Q->z));
+}
+
+void
+jac_neg(jac_point_t *Q, const jac_point_t *P)
+{
+ fp2_copy(&Q->x, &P->x);
+ fp2_neg(&Q->y, &P->y);
+ fp2_copy(&Q->z, &P->z);
+}
+
+void
+DBL(jac_point_t *Q, const jac_point_t *P, const ec_curve_t *AC)
+{ // Cost of 6M + 6S.
+ // Doubling on a Montgomery curve, representation in Jacobian coordinates (X:Y:Z) corresponding to
+ // (X/Z^2,Y/Z^3) This version receives the coefficient value A
+ fp2_t t0, t1, t2, t3;
+
+ uint32_t flag = fp2_is_zero(&P->x) & fp2_is_zero(&P->z);
+
+ fp2_sqr(&t0, &P->x); // t0 = x1^2
+ fp2_add(&t1, &t0, &t0);
+ fp2_add(&t0, &t0, &t1); // t0 = 3x1^2
+ fp2_sqr(&t1, &P->z); // t1 = z1^2
+ fp2_mul(&t2, &P->x, &AC->A);
+ fp2_add(&t2, &t2, &t2); // t2 = 2Ax1
+ fp2_add(&t2, &t1, &t2); // t2 = 2Ax1+z1^2
+ fp2_mul(&t2, &t1, &t2); // t2 = z1^2(2Ax1+z1^2)
+ fp2_add(&t2, &t0, &t2); // t2 = alpha = 3x1^2 + z1^2(2Ax1+z1^2)
+ fp2_mul(&Q->z, &P->y, &P->z);
+ fp2_add(&Q->z, &Q->z, &Q->z); // z2 = 2y1z1
+ fp2_sqr(&t0, &Q->z);
+ fp2_mul(&t0, &t0, &AC->A); // t0 = 4Ay1^2z1^2
+ fp2_sqr(&t1, &P->y);
+ fp2_add(&t1, &t1, &t1); // t1 = 2y1^2
+ fp2_add(&t3, &P->x, &P->x); // t3 = 2x1
+ fp2_mul(&t3, &t1, &t3); // t3 = 4x1y1^2
+ fp2_sqr(&Q->x, &t2); // x2 = alpha^2
+ fp2_sub(&Q->x, &Q->x, &t0); // x2 = alpha^2 - 4Ay1^2z1^2
+ fp2_sub(&Q->x, &Q->x, &t3);
+ fp2_sub(&Q->x, &Q->x, &t3); // x2 = alpha^2 - 4Ay1^2z1^2 - 8x1y1^2
+ fp2_sub(&Q->y, &t3, &Q->x); // y2 = 4x1y1^2 - x2
+ fp2_mul(&Q->y, &Q->y, &t2); // y2 = alpha(4x1y1^2 - x2)
+ fp2_sqr(&t1, &t1); // t1 = 4y1^4
+ fp2_sub(&Q->y, &Q->y, &t1);
+ fp2_sub(&Q->y, &Q->y, &t1); // y2 = alpha(4x1y1^2 - x2) - 8y1^4
+
+ fp2_select(&Q->x, &Q->x, &P->x, -flag);
+ fp2_select(&Q->z, &Q->z, &P->z, -flag);
+}
+
+void
+DBLW(jac_point_t *Q, fp2_t *u, const jac_point_t *P, const fp2_t *t)
+{ // Cost of 3M + 5S.
+ // Doubling on a Weierstrass curve, representation in modified Jacobian coordinates
+ // (X:Y:Z:T=a*Z^4) corresponding to (X/Z^2,Y/Z^3), where a is the curve coefficient.
+ // Formula from https://hyperelliptic.org/EFD/g1p/auto-shortw-modified.html
+
+ uint32_t flag = fp2_is_zero(&P->x) & fp2_is_zero(&P->z);
+
+ fp2_t xx, c, cc, r, s, m;
+ // XX = X^2
+ fp2_sqr(&xx, &P->x);
+ // A = 2*Y^2
+ fp2_sqr(&c, &P->y);
+ fp2_add(&c, &c, &c);
+ // AA = A^2
+ fp2_sqr(&cc, &c);
+ // R = 2*AA
+ fp2_add(&r, &cc, &cc);
+ // S = (X+A)^2-XX-AA
+ fp2_add(&s, &P->x, &c);
+ fp2_sqr(&s, &s);
+ fp2_sub(&s, &s, &xx);
+ fp2_sub(&s, &s, &cc);
+ // M = 3*XX+T1
+ fp2_add(&m, &xx, &xx);
+ fp2_add(&m, &m, &xx);
+ fp2_add(&m, &m, t);
+ // X3 = M^2-2*S
+ fp2_sqr(&Q->x, &m);
+ fp2_sub(&Q->x, &Q->x, &s);
+ fp2_sub(&Q->x, &Q->x, &s);
+ // Z3 = 2*Y*Z
+ fp2_mul(&Q->z, &P->y, &P->z);
+ fp2_add(&Q->z, &Q->z, &Q->z);
+ // Y3 = M*(S-X3)-R
+ fp2_sub(&Q->y, &s, &Q->x);
+ fp2_mul(&Q->y, &Q->y, &m);
+ fp2_sub(&Q->y, &Q->y, &r);
+ // T3 = 2*R*T1
+ fp2_mul(u, t, &r);
+ fp2_add(u, u, u);
+
+ fp2_select(&Q->x, &Q->x, &P->x, -flag);
+ fp2_select(&Q->z, &Q->z, &P->z, -flag);
+}
+
+void
+select_jac_point(jac_point_t *Q, const jac_point_t *P1, const jac_point_t *P2, const digit_t option)
+{ // Select points
+ // If option = 0 then Q <- P1, else if option = 0xFF...FF then Q <- P2
+ fp2_select(&(Q->x), &(P1->x), &(P2->x), option);
+ fp2_select(&(Q->y), &(P1->y), &(P2->y), option);
+ fp2_select(&(Q->z), &(P1->z), &(P2->z), option);
+}
+
+void
+ADD(jac_point_t *R, const jac_point_t *P, const jac_point_t *Q, const ec_curve_t *AC)
+{
+ // Addition on a Montgomery curve, representation in Jacobian coordinates (X:Y:Z) corresponding
+ // to (x,y) = (X/Z^2,Y/Z^3) This version receives the coefficient value A
+ //
+ // Complete routine, to handle all edge cases:
+ // if ZP == 0: # P == inf
+ // return Q
+ // if ZQ == 0: # Q == inf
+ // return P
+ // dy <- YQ*ZP**3 - YP*ZQ**3
+ // dx <- XQ*ZP**2 - XP*ZQ**2
+ // if dx == 0: # x1 == x2
+ // if dy == 0: # ... and y1 == y2: doubling case
+ // dy <- ZP*ZQ * (3*XP^2 + ZP^2 * (2*A*XP + ZP^2))
+ // dx <- 2*YP*ZP
+ // else: # ... but y1 != y2, thus P = -Q
+ // return inf
+ // XR <- dy**2 - dx**2 * (A*ZP^2*ZQ^2 + XP*ZQ^2 + XQ*ZP^2)
+ // YR <- dy * (XP*ZQ^2 * dx^2 - XR) - YP*ZQ^3 * dx^3
+ // ZR <- dx * ZP * ZQ
+
+ // Constant time processing:
+ // - The case for P == 0 or Q == 0 is handled at the end with conditional select
+ // - dy and dx are computed for both the normal and doubling cases, we switch when
+ // dx == dy == 0 for the normal case.
+ // - If we have that P = -Q then dx = 0 and so ZR will be zero, giving us the point
+ // at infinity for "free".
+ //
+ // These current formula are expensive and I'm probably missing some tricks...
+ // Thought I'd get the ball rolling.
+ // Cost 17M + 6S + 13a
+ fp2_t t0, t1, t2, t3, u1, u2, v1, dx, dy;
+
+ /* If P is zero or Q is zero we will conditionally swap before returning. */
+ uint32_t ctl1 = fp2_is_zero(&P->z);
+ uint32_t ctl2 = fp2_is_zero(&Q->z);
+
+ /* Precompute some values */
+ fp2_sqr(&t0, &P->z); // t0 = z1^2
+ fp2_sqr(&t1, &Q->z); // t1 = z2^2
+
+ /* Compute dy and dx for ordinary case */
+ fp2_mul(&v1, &t1, &Q->z); // v1 = z2^3
+ fp2_mul(&t2, &t0, &P->z); // t2 = z1^3
+ fp2_mul(&v1, &v1, &P->y); // v1 = y1z2^3
+ fp2_mul(&t2, &t2, &Q->y); // t2 = y2z1^3
+ fp2_sub(&dy, &t2, &v1); // dy = y2z1^3 - y1z2^3
+ fp2_mul(&u2, &t0, &Q->x); // u2 = x2z1^2
+ fp2_mul(&u1, &t1, &P->x); // u1 = x1z2^2
+ fp2_sub(&dx, &u2, &u1); // dx = x2z1^2 - x1z2^2
+
+ /* Compute dy and dx for doubling case */
+ fp2_add(&t1, &P->y, &P->y); // dx_dbl = t1 = 2y1
+ fp2_add(&t2, &AC->A, &AC->A); // t2 = 2A
+ fp2_mul(&t2, &t2, &P->x); // t2 = 2Ax1
+ fp2_add(&t2, &t2, &t0); // t2 = 2Ax1 + z1^2
+ fp2_mul(&t2, &t2, &t0); // t2 = z1^2 * (2Ax1 + z1^2)
+ fp2_sqr(&t0, &P->x); // t0 = x1^2
+ fp2_add(&t2, &t2, &t0); // t2 = x1^2 + z1^2 * (2Ax1 + z1^2)
+ fp2_add(&t2, &t2, &t0); // t2 = 2*x1^2 + z1^2 * (2Ax1 + z1^2)
+ fp2_add(&t2, &t2, &t0); // t2 = 3*x1^2 + z1^2 * (2Ax1 + z1^2)
+ fp2_mul(&t2, &t2, &Q->z); // dy_dbl = t2 = z2 * (3*x1^2 + z1^2 * (2Ax1 + z1^2))
+
+ /* If dx is zero and dy is zero swap with double variables */
+ uint32_t ctl = fp2_is_zero(&dx) & fp2_is_zero(&dy);
+ fp2_select(&dx, &dx, &t1, ctl);
+ fp2_select(&dy, &dy, &t2, ctl);
+
+ /* Some more precomputations */
+ fp2_mul(&t0, &P->z, &Q->z); // t0 = z1z2
+ fp2_sqr(&t1, &t0); // t1 = z1z2^2
+ fp2_sqr(&t2, &dx); // t2 = dx^2
+ fp2_sqr(&t3, &dy); // t3 = dy^2
+
+ /* Compute x3 = dy**2 - dx**2 * (A*ZP^2*ZQ^2 + XP*ZQ^2 + XQ*ZP^2) */
+ fp2_mul(&R->x, &AC->A, &t1); // x3 = A*(z1z2)^2
+ fp2_add(&R->x, &R->x, &u1); // x3 = A*(z1z2)^2 + u1
+ fp2_add(&R->x, &R->x, &u2); // x3 = A*(z1z2)^2 + u1 + u2
+ fp2_mul(&R->x, &R->x, &t2); // x3 = dx^2 * (A*(z1z2)^2 + u1 + u2)
+ fp2_sub(&R->x, &t3, &R->x); // x3 = dy^2 - dx^2 * (A*(z1z2)^2 + u1 + u2)
+
+ /* Compute y3 = dy * (XP*ZQ^2 * dx^2 - XR) - YP*ZQ^3 * dx^3*/
+ fp2_mul(&R->y, &u1, &t2); // y3 = u1 * dx^2
+ fp2_sub(&R->y, &R->y, &R->x); // y3 = u1 * dx^2 - x3
+ fp2_mul(&R->y, &R->y, &dy); // y3 = dy * (u1 * dx^2 - x3)
+ fp2_mul(&t3, &t2, &dx); // t3 = dx^3
+ fp2_mul(&t3, &t3, &v1); // t3 = v1 * dx^3
+ fp2_sub(&R->y, &R->y, &t3); // y3 = dy * (u1 * dx^2 - x3) - v1 * dx^3
+
+ /* Compute z3 = dx * z1 * z2 */
+ fp2_mul(&R->z, &dx, &t0);
+
+ /* Finally, we need to set R = P is Q.Z = 0 and R = Q if P.Z = 0 */
+ select_jac_point(R, R, Q, ctl1);
+ select_jac_point(R, R, P, ctl2);
+}
+
+void
+jac_to_xz_add_components(add_components_t *add_comp, const jac_point_t *P, const jac_point_t *Q, const ec_curve_t *AC)
+{
+ // Take P and Q in E distinct, two jac_point_t, return three components u,v and w in Fp2 such
+ // that the xz coordinates of P+Q are (u-v:w) and of P-Q are (u+v:w)
+
+ fp2_t t0, t1, t2, t3, t4, t5, t6;
+
+ fp2_sqr(&t0, &P->z); // t0 = z1^2
+ fp2_sqr(&t1, &Q->z); // t1 = z2^2
+ fp2_mul(&t2, &P->x, &t1); // t2 = x1z2^2
+ fp2_mul(&t3, &t0, &Q->x); // t3 = z1^2x2
+ fp2_mul(&t4, &P->y, &Q->z); // t4 = y1z2
+ fp2_mul(&t4, &t4, &t1); // t4 = y1z2^3
+ fp2_mul(&t5, &P->z, &Q->y); // t5 = z1y2
+ fp2_mul(&t5, &t5, &t0); // t5 = z1^3y2
+ fp2_mul(&t0, &t0, &t1); // t0 = (z1z2)^2
+ fp2_mul(&t6, &t4, &t5); // t6 = (z1z_2)^3y1y2
+ fp2_add(&add_comp->v, &t6, &t6); // v = 2(z1z_2)^3y1y2
+ fp2_sqr(&t4, &t4); // t4 = y1^2z2^6
+ fp2_sqr(&t5, &t5); // t5 = z1^6y_2^2
+ fp2_add(&t4, &t4, &t5); // t4 = z1^6y_2^2 + y1^2z2^6
+ fp2_add(&t5, &t2, &t3); // t5 = x1z2^2 +z_1^2x2
+ fp2_add(&t6, &t3, &t3); // t6 = 2z_1^2x2
+ fp2_sub(&t6, &t5, &t6); // t6 = lambda = x1z2^2 - z_1^2x2
+ fp2_sqr(&t6, &t6); // t6 = lambda^2 = (x1z2^2 - z_1^2x2)^2
+ fp2_mul(&t1, &AC->A, &t0); // t1 = A*(z1z2)^2
+ fp2_add(&t1, &t5, &t1); // t1 = gamma =A*(z1z2)^2 + x1z2^2 +z_1^2x2
+ fp2_mul(&t1, &t1, &t6); // t1 = gamma*lambda^2
+ fp2_sub(&add_comp->u, &t4, &t1); // u = z1^6y_2^2 + y1^2z2^6 - gamma*lambda^2
+ fp2_mul(&add_comp->w, &t6, &t0); // w = (z1z2)^2(lambda)^2
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec_params.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec_params.c
new file mode 100644
index 0000000000..5011f102e1
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec_params.c
@@ -0,0 +1,4 @@
+#include
+// p+1 divided by the power of 2
+const digit_t p_cofactor_for_2f[1] = {5};
+
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec_params.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec_params.h
new file mode 100644
index 0000000000..e02ac1d146
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ec_params.h
@@ -0,0 +1,12 @@
+#ifndef EC_PARAMS_H
+#define EC_PARAMS_H
+
+#include
+
+#define TORSION_EVEN_POWER 248
+
+// p+1 divided by the power of 2
+extern const digit_t p_cofactor_for_2f[1];
+#define P_COFACTOR_FOR_2F_BITLENGTH 3
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/encode_signature.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/encode_signature.c
new file mode 100644
index 0000000000..3a630cfd58
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/encode_signature.c
@@ -0,0 +1,208 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+typedef unsigned char byte_t;
+
+// digits
+
+static void
+encode_digits(byte_t *enc, const digit_t *x, size_t nbytes)
+{
+#ifdef TARGET_BIG_ENDIAN
+ const size_t ndigits = nbytes / sizeof(digit_t);
+ const size_t rem = nbytes % sizeof(digit_t);
+
+ for (size_t i = 0; i < ndigits; i++)
+ ((digit_t *)enc)[i] = BSWAP_DIGIT(x[i]);
+ if (rem) {
+ digit_t ld = BSWAP_DIGIT(x[ndigits]);
+ memcpy(enc + ndigits * sizeof(digit_t), (byte_t *)&ld, rem);
+ }
+#else
+ memcpy(enc, (const byte_t *)x, nbytes);
+#endif
+}
+
+static void
+decode_digits(digit_t *x, const byte_t *enc, size_t nbytes, size_t ndigits)
+{
+ assert(nbytes <= ndigits * sizeof(digit_t));
+ memcpy((byte_t *)x, enc, nbytes);
+ memset((byte_t *)x + nbytes, 0, ndigits * sizeof(digit_t) - nbytes);
+
+#ifdef TARGET_BIG_ENDIAN
+ for (size_t i = 0; i < ndigits; i++)
+ x[i] = BSWAP_DIGIT(x[i]);
+#endif
+}
+
+// ibz_t
+
+static byte_t *
+ibz_to_bytes(byte_t *enc, const ibz_t *x, size_t nbytes, bool sgn)
+{
+#ifndef NDEBUG
+ {
+ // make sure there is enough space
+ ibz_t abs, bnd;
+ ibz_init(&bnd);
+ ibz_init(&abs);
+ ibz_pow(&bnd, &ibz_const_two, 8 * nbytes - sgn);
+ ibz_abs(&abs, x);
+ assert(ibz_cmp(&abs, &bnd) < 0);
+ ibz_finalize(&bnd);
+ ibz_finalize(&abs);
+ }
+#endif
+ const size_t digits = (nbytes + sizeof(digit_t) - 1) / sizeof(digit_t);
+ digit_t d[digits];
+ memset(d, 0, sizeof(d));
+ if (ibz_cmp(x, &ibz_const_zero) >= 0) {
+ // non-negative, straightforward.
+ ibz_to_digits(d, x);
+ } else {
+ assert(sgn);
+ // negative; use two's complement.
+ ibz_t tmp;
+ ibz_init(&tmp);
+ ibz_neg(&tmp, x);
+ ibz_sub(&tmp, &tmp, &ibz_const_one);
+ ibz_to_digits(d, &tmp);
+ for (size_t i = 0; i < digits; ++i)
+ d[i] = ~d[i];
+#ifndef NDEBUG
+ {
+ // make sure the result is correct
+ ibz_t chk;
+ ibz_init(&chk);
+ ibz_copy_digit_array(&tmp, d);
+ ibz_sub(&tmp, &tmp, x);
+ ibz_pow(&chk, &ibz_const_two, 8 * sizeof(d));
+ assert(!ibz_cmp(&tmp, &chk));
+ ibz_finalize(&chk);
+ }
+#endif
+ ibz_finalize(&tmp);
+ }
+ encode_digits(enc, d, nbytes);
+ return enc + nbytes;
+}
+
+static const byte_t *
+ibz_from_bytes(ibz_t *x, const byte_t *enc, size_t nbytes, bool sgn)
+{
+ assert(nbytes > 0);
+ const size_t ndigits = (nbytes + sizeof(digit_t) - 1) / sizeof(digit_t);
+ assert(ndigits > 0);
+ digit_t d[ndigits];
+ memset(d, 0, sizeof(d));
+ decode_digits(d, enc, nbytes, ndigits);
+ if (sgn && enc[nbytes - 1] >> 7) {
+ // negative, decode two's complement
+ const size_t s = sizeof(digit_t) - 1 - (sizeof(d) - nbytes);
+ assert(s < sizeof(digit_t));
+ d[ndigits - 1] |= ((digit_t)-1) >> 8 * s << 8 * s;
+ for (size_t i = 0; i < ndigits; ++i)
+ d[i] = ~d[i];
+ ibz_copy_digits(x, d, ndigits);
+ ibz_add(x, x, &ibz_const_one);
+ ibz_neg(x, x);
+ } else {
+ // non-negative
+ ibz_copy_digits(x, d, ndigits);
+ }
+ return enc + nbytes;
+}
+
+// public API
+
+void
+secret_key_to_bytes(byte_t *enc, const secret_key_t *sk, const public_key_t *pk)
+{
+#ifndef NDEBUG
+ byte_t *const start = enc;
+#endif
+
+ enc = public_key_to_bytes(enc, pk);
+
+#ifndef NDEBUG
+ {
+ fp2_t lhs, rhs;
+ fp2_mul(&lhs, &sk->curve.A, &pk->curve.C);
+ fp2_mul(&rhs, &sk->curve.C, &pk->curve.A);
+ assert(fp2_is_equal(&lhs, &rhs));
+ }
+#endif
+
+ enc = ibz_to_bytes(enc, &sk->secret_ideal.norm, FP_ENCODED_BYTES, false);
+ {
+ quat_alg_elem_t gen;
+ quat_alg_elem_init(&gen);
+ int ret UNUSED = quat_lideal_generator(&gen, &sk->secret_ideal, &QUATALG_PINFTY);
+ assert(ret);
+ // we skip encoding the denominator since it won't change the generated ideal
+#ifndef NDEBUG
+ {
+ // let's make sure that the denominator is indeed coprime to the norm of the ideal
+ ibz_t gcd;
+ ibz_init(&gcd);
+ ibz_gcd(&gcd, &gen.denom, &sk->secret_ideal.norm);
+ assert(!ibz_cmp(&gcd, &ibz_const_one));
+ ibz_finalize(&gcd);
+ }
+#endif
+ enc = ibz_to_bytes(enc, &gen.coord.v[0], FP_ENCODED_BYTES, true);
+ enc = ibz_to_bytes(enc, &gen.coord.v[1], FP_ENCODED_BYTES, true);
+ enc = ibz_to_bytes(enc, &gen.coord.v[2], FP_ENCODED_BYTES, true);
+ enc = ibz_to_bytes(enc, &gen.coord.v[3], FP_ENCODED_BYTES, true);
+ quat_alg_elem_finalize(&gen);
+ }
+
+ enc = ibz_to_bytes(enc, &sk->mat_BAcan_to_BA0_two.m[0][0], TORSION_2POWER_BYTES, false);
+ enc = ibz_to_bytes(enc, &sk->mat_BAcan_to_BA0_two.m[0][1], TORSION_2POWER_BYTES, false);
+ enc = ibz_to_bytes(enc, &sk->mat_BAcan_to_BA0_two.m[1][0], TORSION_2POWER_BYTES, false);
+ enc = ibz_to_bytes(enc, &sk->mat_BAcan_to_BA0_two.m[1][1], TORSION_2POWER_BYTES, false);
+
+ assert(enc - start == SECRETKEY_BYTES);
+}
+
+void
+secret_key_from_bytes(secret_key_t *sk, public_key_t *pk, const byte_t *enc)
+{
+#ifndef NDEBUG
+ const byte_t *const start = enc;
+#endif
+
+ enc = public_key_from_bytes(pk, enc);
+
+ {
+ ibz_t norm;
+ ibz_init(&norm);
+ quat_alg_elem_t gen;
+ quat_alg_elem_init(&gen);
+ enc = ibz_from_bytes(&norm, enc, FP_ENCODED_BYTES, false);
+ enc = ibz_from_bytes(&gen.coord.v[0], enc, FP_ENCODED_BYTES, true);
+ enc = ibz_from_bytes(&gen.coord.v[1], enc, FP_ENCODED_BYTES, true);
+ enc = ibz_from_bytes(&gen.coord.v[2], enc, FP_ENCODED_BYTES, true);
+ enc = ibz_from_bytes(&gen.coord.v[3], enc, FP_ENCODED_BYTES, true);
+ quat_lideal_create(&sk->secret_ideal, &gen, &norm, &MAXORD_O0, &QUATALG_PINFTY);
+ ibz_finalize(&norm);
+ quat_alg_elem_finalize(&gen);
+ }
+
+ enc = ibz_from_bytes(&sk->mat_BAcan_to_BA0_two.m[0][0], enc, TORSION_2POWER_BYTES, false);
+ enc = ibz_from_bytes(&sk->mat_BAcan_to_BA0_two.m[0][1], enc, TORSION_2POWER_BYTES, false);
+ enc = ibz_from_bytes(&sk->mat_BAcan_to_BA0_two.m[1][0], enc, TORSION_2POWER_BYTES, false);
+ enc = ibz_from_bytes(&sk->mat_BAcan_to_BA0_two.m[1][1], enc, TORSION_2POWER_BYTES, false);
+
+ assert(enc - start == SECRETKEY_BYTES);
+
+ sk->curve = pk->curve;
+ ec_curve_to_basis_2f_from_hint(&sk->canonical_basis, &sk->curve, TORSION_EVEN_POWER, pk->hint_pk);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/encode_verification.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/encode_verification.c
new file mode 100644
index 0000000000..8aa451d366
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/encode_verification.c
@@ -0,0 +1,190 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+typedef unsigned char byte_t;
+
+// digits
+
+static void
+encode_digits(byte_t *enc, const digit_t *x, size_t nbytes)
+{
+#ifdef TARGET_BIG_ENDIAN
+ const size_t ndigits = nbytes / sizeof(digit_t);
+ const size_t rem = nbytes % sizeof(digit_t);
+
+ for (size_t i = 0; i < ndigits; i++)
+ ((digit_t *)enc)[i] = BSWAP_DIGIT(x[i]);
+ if (rem) {
+ digit_t ld = BSWAP_DIGIT(x[ndigits]);
+ memcpy(enc + ndigits * sizeof(digit_t), (byte_t *)&ld, rem);
+ }
+#else
+ memcpy(enc, (const byte_t *)x, nbytes);
+#endif
+}
+
+static void
+decode_digits(digit_t *x, const byte_t *enc, size_t nbytes, size_t ndigits)
+{
+ assert(nbytes <= ndigits * sizeof(digit_t));
+ memcpy((byte_t *)x, enc, nbytes);
+ memset((byte_t *)x + nbytes, 0, ndigits * sizeof(digit_t) - nbytes);
+
+#ifdef TARGET_BIG_ENDIAN
+ for (size_t i = 0; i < ndigits; i++)
+ x[i] = BSWAP_DIGIT(x[i]);
+#endif
+}
+
+// fp2_t
+
+static byte_t *
+fp2_to_bytes(byte_t *enc, const fp2_t *x)
+{
+ fp2_encode(enc, x);
+ return enc + FP2_ENCODED_BYTES;
+}
+
+static const byte_t *
+fp2_from_bytes(fp2_t *x, const byte_t *enc)
+{
+ fp2_decode(x, enc);
+ return enc + FP2_ENCODED_BYTES;
+}
+
+// curves and points
+
+static byte_t *
+proj_to_bytes(byte_t *enc, const fp2_t *x, const fp2_t *z)
+{
+ assert(!fp2_is_zero(z));
+ fp2_t tmp = *z;
+ fp2_inv(&tmp);
+#ifndef NDEBUG
+ {
+ fp2_t chk;
+ fp2_mul(&chk, z, &tmp);
+ fp2_t one;
+ fp2_set_one(&one);
+ assert(fp2_is_equal(&chk, &one));
+ }
+#endif
+ fp2_mul(&tmp, x, &tmp);
+ enc = fp2_to_bytes(enc, &tmp);
+ return enc;
+}
+
+static const byte_t *
+proj_from_bytes(fp2_t *x, fp2_t *z, const byte_t *enc)
+{
+ enc = fp2_from_bytes(x, enc);
+ fp2_set_one(z);
+ return enc;
+}
+
+static byte_t *
+ec_curve_to_bytes(byte_t *enc, const ec_curve_t *curve)
+{
+ return proj_to_bytes(enc, &curve->A, &curve->C);
+}
+
+static const byte_t *
+ec_curve_from_bytes(ec_curve_t *curve, const byte_t *enc)
+{
+ memset(curve, 0, sizeof(*curve));
+ return proj_from_bytes(&curve->A, &curve->C, enc);
+}
+
+// public API
+
+byte_t *
+public_key_to_bytes(byte_t *enc, const public_key_t *pk)
+{
+#ifndef NDEBUG
+ const byte_t *const start = enc;
+#endif
+ enc = ec_curve_to_bytes(enc, &pk->curve);
+ *enc++ = pk->hint_pk;
+ assert(enc - start == PUBLICKEY_BYTES);
+ return enc;
+}
+
+const byte_t *
+public_key_from_bytes(public_key_t *pk, const byte_t *enc)
+{
+#ifndef NDEBUG
+ const byte_t *const start = enc;
+#endif
+ enc = ec_curve_from_bytes(&pk->curve, enc);
+ pk->hint_pk = *enc++;
+ assert(enc - start == PUBLICKEY_BYTES);
+ return enc;
+}
+
+void
+signature_to_bytes(byte_t *enc, const signature_t *sig)
+{
+#ifndef NDEBUG
+ byte_t *const start = enc;
+#endif
+
+ enc = fp2_to_bytes(enc, &sig->E_aux_A);
+
+ *enc++ = sig->backtracking;
+ *enc++ = sig->two_resp_length;
+
+ size_t nbytes = (SQIsign_response_length + 9) / 8;
+ encode_digits(enc, sig->mat_Bchall_can_to_B_chall[0][0], nbytes);
+ enc += nbytes;
+ encode_digits(enc, sig->mat_Bchall_can_to_B_chall[0][1], nbytes);
+ enc += nbytes;
+ encode_digits(enc, sig->mat_Bchall_can_to_B_chall[1][0], nbytes);
+ enc += nbytes;
+ encode_digits(enc, sig->mat_Bchall_can_to_B_chall[1][1], nbytes);
+ enc += nbytes;
+
+ nbytes = SECURITY_BITS / 8;
+ encode_digits(enc, sig->chall_coeff, nbytes);
+ enc += nbytes;
+
+ *enc++ = sig->hint_aux;
+ *enc++ = sig->hint_chall;
+
+ assert(enc - start == SIGNATURE_BYTES);
+}
+
+void
+signature_from_bytes(signature_t *sig, const byte_t *enc)
+{
+#ifndef NDEBUG
+ const byte_t *const start = enc;
+#endif
+
+ enc = fp2_from_bytes(&sig->E_aux_A, enc);
+
+ sig->backtracking = *enc++;
+ sig->two_resp_length = *enc++;
+
+ size_t nbytes = (SQIsign_response_length + 9) / 8;
+ decode_digits(sig->mat_Bchall_can_to_B_chall[0][0], enc, nbytes, NWORDS_ORDER);
+ enc += nbytes;
+ decode_digits(sig->mat_Bchall_can_to_B_chall[0][1], enc, nbytes, NWORDS_ORDER);
+ enc += nbytes;
+ decode_digits(sig->mat_Bchall_can_to_B_chall[1][0], enc, nbytes, NWORDS_ORDER);
+ enc += nbytes;
+ decode_digits(sig->mat_Bchall_can_to_B_chall[1][1], enc, nbytes, NWORDS_ORDER);
+ enc += nbytes;
+
+ nbytes = SECURITY_BITS / 8;
+ decode_digits(sig->chall_coeff, enc, nbytes, NWORDS_ORDER);
+ enc += nbytes;
+
+ sig->hint_aux = *enc++;
+ sig->hint_chall = *enc++;
+
+ assert(enc - start == SIGNATURE_BYTES);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/encoded_sizes.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/encoded_sizes.h
new file mode 100644
index 0000000000..02f8642967
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/encoded_sizes.h
@@ -0,0 +1,11 @@
+#define SECURITY_BITS 128
+#define SQIsign_response_length 126
+#define HASH_ITERATIONS 64
+#define FP_ENCODED_BYTES 32
+#define FP2_ENCODED_BYTES 64
+#define EC_CURVE_ENCODED_BYTES 64
+#define EC_POINT_ENCODED_BYTES 64
+#define EC_BASIS_ENCODED_BYTES 192
+#define PUBLICKEY_BYTES 65
+#define SECRETKEY_BYTES 353
+#define SIGNATURE_BYTES 148
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/endomorphism_action.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/endomorphism_action.c
new file mode 100644
index 0000000000..7993e79f8c
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/endomorphism_action.c
@@ -0,0 +1,3336 @@
+#include
+#include
+#include
+const curve_with_endomorphism_ring_t CURVES_WITH_ENDOMORPHISMS[7] = {{{{
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {{
+#if 0
+#elif RADIX == 16
+{{0x199, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6}}
+#elif RADIX == 32
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x19, 0x0, 0x0, 0x300000000000000}}
+#else
+{{0xc, 0x0, 0x0, 0x0, 0x400000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, true}, {{{
+#if 0
+#elif RADIX == 16
+{{0x107, 0xc, 0x1890, 0xf2a, 0x52b, 0xb68, 0x152d, 0xa4c, 0x1054, 0x642, 0x36a, 0x6f8, 0x7ad, 0x146c, 0x1d66, 0x1b67, 0x236, 0x10d, 0x1933, 0x3}}
+#elif RADIX == 32
+{{0x3020e, 0xb795624, 0x5ab6829, 0x1514995, 0x1b5190a, 0x187ad37c, 0x19facd46, 0x8688db6, 0x3c998}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x52b795624001810, 0x8c8505452654b56d, 0xf59a8d87ad37c0da, 0x24e4cc21a236db3}}
+#else
+{{0x5bcab12000c08, 0x452654b56d052, 0x26f81b5190a0a, 0x36cfd66a361eb, 0x12726610d11b}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x1f87, 0x83e, 0x32e, 0xe58, 0xd9d, 0x1416, 0x752, 0x13b4, 0x1efa, 0xe62, 0x12f5, 0x1907, 0x1814, 0x1ddd, 0x1aa6, 0x1420, 0x2cd, 0x1431, 0x1be2, 0x7}}
+#elif RADIX == 32
+{{0x120fbf0f, 0x1d72c0cb, 0xa54166c, 0x1bea7687, 0x197ab98b, 0x1b814c83, 0x8354ddd, 0x188b368, 0x2df15}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xcd9d72c0cb907df8, 0x5cc5efa9da1d4a82, 0x6a9bbbb814c83cbd, 0x26ef8a8622cda10}}
+#else
+{{0x6b96065c83efc, 0x29da1d4a82cd9, 0x190797ab98bdf, 0x6841aa6eeee05, 0x1377c5431166}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x5ff, 0x1783, 0xadc, 0x775, 0xad4, 0x593, 0xb4c, 0x21e, 0x1cb2, 0x13d8, 0x179f, 0x680, 0x1a9c, 0x1824, 0x118e, 0x13d9, 0x24, 0x1956, 0x1dd2, 0x9}}
+#elif RADIX == 32
+{{0x5e0cbff, 0x143baab7, 0x9859356, 0x12c843cb, 0xbcfcf63, 0x9a9c340, 0x16631d82, 0xab00927, 0x4ee96}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x6ad43baab72f065f, 0xe7b1cb210f2d30b2, 0xc63b049a9c3405e7, 0x4ff74b2ac0249ec}}
+#else
+{{0x21dd55b97832f, 0x210f2d30b26ad, 0x680bcfcf6396, 0x27b318ec126a7, 0x4ffba5956012}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x1c7f, 0x1117, 0xa4, 0x1164, 0x6e, 0x1e63, 0x1b7b, 0x1305, 0x424, 0x131a, 0x1b61, 0xae3, 0x17b1, 0xe5e, 0x1848, 0x1e81, 0x14a5, 0x1cb5, 0x1d87, 0x8}}
+#elif RADIX == 32
+{{0x445f8ff, 0xe8b2029, 0xf7e6303, 0x109260bb, 0x1db0cc68, 0x1d7b1571, 0x7090e5, 0x5ad297d, 0x3ec3f}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x606e8b2029222fc7, 0x6634424982edefcc, 0xe121cbd7b1571ed8, 0x4f761f96b4a5f40}}
+#else
+{{0x74590149117e3, 0x4982edefcc606, 0x2ae3db0cc6884, 0x7d0384872f5ec, 0x4fbb0fcb5a52}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x342, 0xfb7, 0xed, 0x1d80, 0x17f1, 0x4a2, 0x1c26, 0xb96, 0x1367, 0x3dc, 0x1624, 0x1f2a, 0x5e, 0x1cab, 0x27, 0x1e89, 0x1293, 0x1e24, 0x417, 0x5}}
+#elif RADIX == 32
+{{0xbedc685, 0x11ec003b, 0x4c4a2bf, 0xd9d72dc, 0xb120f72, 0x1605ef95, 0x2404fca, 0x1124a4fd, 0x20bf}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x57f1ec003b5f6e34, 0x7b93675cb709894, 0x809f95605ef95589, 0xc905fc49293f44}}
+#else
+{{0xf6001dafb71a, 0x75cb70989457f, 0x5f2ab120f726c, 0x7d12027e55817, 0x6482fe24949}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0xf3c, 0x1d21, 0xd78, 0xe8e, 0x1f3c, 0x11b, 0x12c, 0x1851, 0x19b1, 0xd9, 0xf3f, 0x759, 0xf47, 0x1e88, 0x56e, 0x8ef, 0x116e, 0x1fa1, 0x1199, 0x0}}
+#elif RADIX == 32
+{{0x7485e78, 0x1c74735e, 0x5811bf9, 0x6c70a21, 0x179f8367, 0x10f473ac, 0x1bcadde8, 0x1d0c5b91, 0x8ccf}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x7f3c74735e3a42f3, 0xc1b39b1c2884b023, 0x95bbd10f473acbcf, 0x3c4667f4316e477}}
+#else
+{{0x63a39af1d2179, 0x1c2884b0237f3, 0x675979f836736, 0x11de56ef443d1, 0x462333fa18b7}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x56db,0x1b54,0xbda2,0xc5d3,0xdd06,0x861d,0x9780,0x7475,0x33d1,0x41af,0x34b2,0x7f9d,0x7f8c,0xaa8c,0xb471,0xca}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1b5456db,0xc5d3bda2,0x861ddd06,0x74759780,0x41af33d1,0x7f9d34b2,0xaa8c7f8c,0xcab471}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xc5d3bda21b5456db,0x74759780861ddd06,0x7f9d34b241af33d1,0xcab471aa8c7f8c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x7d7a,0x48b,0x7d32,0x7bfb,0x9bd3,0x63d8,0x9182,0xa955,0x3e1,0x344,0x6861,0x76bf,0x5cd0,0xeeb4,0x4ae3,0x57}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x48b7d7a,0x7bfb7d32,0x63d89bd3,0xa9559182,0x34403e1,0x76bf6861,0xeeb45cd0,0x574ae3}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7bfb7d32048b7d7a,0xa955918263d89bd3,0x76bf6861034403e1,0x574ae3eeb45cd0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x444f,0x3698,0xd649,0x856f,0x41db,0x498f,0xafdf,0x189c,0xcb5b,0xe50b,0xbff,0xf7e0,0x47f9,0xa88b,0x35da,0x15}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x3698444f,0x856fd649,0x498f41db,0x189cafdf,0xe50bcb5b,0xf7e00bff,0xa88b47f9,0x1535da}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x856fd6493698444f,0x189cafdf498f41db,0xf7e00bffe50bcb5b,0x1535daa88b47f9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xa925,0xe4ab,0x425d,0x3a2c,0x22f9,0x79e2,0x687f,0x8b8a,0xcc2e,0xbe50,0xcb4d,0x8062,0x8073,0x5573,0x4b8e,0x35}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe4aba925,0x3a2c425d,0x79e222f9,0x8b8a687f,0xbe50cc2e,0x8062cb4d,0x55738073,0x354b8e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3a2c425de4aba925,0x8b8a687f79e222f9,0x8062cb4dbe50cc2e,0x354b8e55738073}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xabf,0x5490,0xd5fd,0x36ba,0xda0f,0x4a59,0x4eea,0xd1,0xa3f0,0xa7ae,0x6f6,0x9146,0x5004,0xcde6,0xa2d2,0x7d}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x54900abf,0x36bad5fd,0x4a59da0f,0xd14eea,0xa7aea3f0,0x914606f6,0xcde65004,0x7da2d2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x36bad5fd54900abf,0xd14eea4a59da0f,0x914606f6a7aea3f0,0x7da2d2cde65004}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x8680,0xb787,0xbde3,0x611d,0xa95f,0x8b68,0xc9ec,0x819,0x2361,0xf73e,0x5e31,0xbd7b,0x2b45,0x40d7,0x2400,0x68}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb7878680,0x611dbde3,0x8b68a95f,0x819c9ec,0xf73e2361,0xbd7b5e31,0x40d72b45,0x682400}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x611dbde3b7878680,0x819c9ec8b68a95f,0xbd7b5e31f73e2361,0x68240040d72b45}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x4277,0x6d20,0x9e12,0x1f0c,0x977f,0xf854,0x9d1c,0x563f,0xdb,0xc2ed,0xaf54,0xe829,0x4fb,0xd83,0x7be8,0xca}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x6d204277,0x1f0c9e12,0xf854977f,0x563f9d1c,0xc2ed00db,0xe829af54,0xd8304fb,0xca7be8}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x1f0c9e126d204277,0x563f9d1cf854977f,0xe829af54c2ed00db,0xca7be80d8304fb}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xf541,0xab6f,0x2a02,0xc945,0x25f0,0xb5a6,0xb115,0xff2e,0x5c0f,0x5851,0xf909,0x6eb9,0xaffb,0x3219,0x5d2d,0x82}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xab6ff541,0xc9452a02,0xb5a625f0,0xff2eb115,0x58515c0f,0x6eb9f909,0x3219affb,0x825d2d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xc9452a02ab6ff541,0xff2eb115b5a625f0,0x6eb9f90958515c0f,0x825d2d3219affb}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x231b,0x1af2,0x1640,0xb19c,0xf713,0xe470,0x683e,0xf39a,0x3289,0x7a54,0xc26e,0x904e,0xd5a6,0x6a0c,0x55fc,0x44}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1af2231b,0xb19c1640,0xe470f713,0xf39a683e,0x7a543289,0x904ec26e,0x6a0cd5a6,0x4455fc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb19c16401af2231b,0xf39a683ee470f713,0x904ec26e7a543289,0x4455fc6a0cd5a6}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xad7a,0xb685,0xde69,0x55d2,0x5675,0x84e8,0x5916,0x925f,0x8c0a,0x1cb6,0x7c51,0x8391,0xffce,0x11d1,0x96ce,0xcd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb685ad7a,0x55d2de69,0x84e85675,0x925f5916,0x1cb68c0a,0x83917c51,0x11d1ffce,0xcd96ce}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x55d2de69b685ad7a,0x925f591684e85675,0x83917c511cb68c0a,0xcd96ce11d1ffce}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x3724,0x79bd,0x1b92,0x959b,0xb3ec,0x6f18,0x27d4,0x64a7,0x9b4b,0x8c7e,0xade7,0x664b,0xa6d9,0xa287,0x6a1d,0x48}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x79bd3724,0x959b1b92,0x6f18b3ec,0x64a727d4,0x8c7e9b4b,0x664bade7,0xa287a6d9,0x486a1d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x959b1b9279bd3724,0x64a727d46f18b3ec,0x664bade78c7e9b4b,0x486a1da287a6d9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xdce5,0xe50d,0xe9bf,0x4e63,0x8ec,0x1b8f,0x97c1,0xc65,0xcd76,0x85ab,0x3d91,0x6fb1,0x2a59,0x95f3,0xaa03,0xbb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe50ddce5,0x4e63e9bf,0x1b8f08ec,0xc6597c1,0x85abcd76,0x6fb13d91,0x95f32a59,0xbbaa03}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4e63e9bfe50ddce5,0xc6597c11b8f08ec,0x6fb13d9185abcd76,0xbbaa0395f32a59}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x56db,0x1b54,0xbda2,0xc5d3,0xdd06,0x861d,0x9780,0x7475,0x33d1,0x41af,0x34b2,0x7f9d,0x7f8c,0xaa8c,0xb471,0xca}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1b5456db,0xc5d3bda2,0x861ddd06,0x74759780,0x41af33d1,0x7f9d34b2,0xaa8c7f8c,0xcab471}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xc5d3bda21b5456db,0x74759780861ddd06,0x7f9d34b241af33d1,0xcab471aa8c7f8c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x7d7a,0x48b,0x7d32,0x7bfb,0x9bd3,0x63d8,0x9182,0xa955,0x3e1,0x344,0x6861,0x76bf,0x5cd0,0xeeb4,0x4ae3,0x57}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x48b7d7a,0x7bfb7d32,0x63d89bd3,0xa9559182,0x34403e1,0x76bf6861,0xeeb45cd0,0x574ae3}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7bfb7d32048b7d7a,0xa955918263d89bd3,0x76bf6861034403e1,0x574ae3eeb45cd0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x444f,0x3698,0xd649,0x856f,0x41db,0x498f,0xafdf,0x189c,0xcb5b,0xe50b,0xbff,0xf7e0,0x47f9,0xa88b,0x35da,0x15}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x3698444f,0x856fd649,0x498f41db,0x189cafdf,0xe50bcb5b,0xf7e00bff,0xa88b47f9,0x1535da}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x856fd6493698444f,0x189cafdf498f41db,0xf7e00bffe50bcb5b,0x1535daa88b47f9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xa925,0xe4ab,0x425d,0x3a2c,0x22f9,0x79e2,0x687f,0x8b8a,0xcc2e,0xbe50,0xcb4d,0x8062,0x8073,0x5573,0x4b8e,0x35}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe4aba925,0x3a2c425d,0x79e222f9,0x8b8a687f,0xbe50cc2e,0x8062cb4d,0x55738073,0x354b8e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3a2c425de4aba925,0x8b8a687f79e222f9,0x8062cb4dbe50cc2e,0x354b8e55738073}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x30cd,0xb7f2,0x49cf,0xfe47,0xdb8a,0x683b,0x7335,0xbaa3,0xebe0,0x74ae,0x9dd4,0x8871,0x67c8,0x3c39,0x2ba2,0x24}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb7f230cd,0xfe4749cf,0x683bdb8a,0xbaa37335,0x74aeebe0,0x88719dd4,0x3c3967c8,0x242ba2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xfe4749cfb7f230cd,0xbaa37335683bdb8a,0x88719dd474aeebe0,0x242ba23c3967c8}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x81fd,0xde09,0x9d8a,0x6e8c,0xa299,0x77a0,0xadb7,0x58b7,0x13a1,0x7d41,0x6349,0x1a1d,0xc40b,0x17c5,0xb772,0xdf}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xde0981fd,0x6e8c9d8a,0x77a0a299,0x58b7adb7,0x7d4113a1,0x1a1d6349,0x17c5c40b,0xdfb772}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x6e8c9d8ade0981fd,0x58b7adb777a0a299,0x1a1d63497d4113a1,0xdfb77217c5c40b}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x4363,0xd1dc,0x3a2d,0x523e,0xecad,0x20f1,0x267e,0x376e,0x661b,0x53fc,0xddaa,0xf004,0x267a,0x5b07,0xd8e1,0x6f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd1dc4363,0x523e3a2d,0x20f1ecad,0x376e267e,0x53fc661b,0xf004ddaa,0x5b07267a,0x6fd8e1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x523e3a2dd1dc4363,0x376e267e20f1ecad,0xf004ddaa53fc661b,0x6fd8e15b07267a}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xcf33,0x480d,0xb630,0x1b8,0x2475,0x97c4,0x8cca,0x455c,0x141f,0x8b51,0x622b,0x778e,0x9837,0xc3c6,0xd45d,0xdb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x480dcf33,0x1b8b630,0x97c42475,0x455c8cca,0x8b51141f,0x778e622b,0xc3c69837,0xdbd45d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x1b8b630480dcf33,0x455c8cca97c42475,0x778e622b8b51141f,0xdbd45dc3c69837}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x118e,0xd79,0xb20,0xd8ce,0x7b89,0x7238,0x341f,0xf9cd,0x1944,0x3d2a,0x6137,0x4827,0x6ad3,0x3506,0x2afe,0x22}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd79118e,0xd8ce0b20,0x72387b89,0xf9cd341f,0x3d2a1944,0x48276137,0x35066ad3,0x222afe}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xd8ce0b200d79118e,0xf9cd341f72387b89,0x482761373d2a1944,0x222afe35066ad3}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xd6bd,0xdb42,0x6f34,0xaae9,0x2b3a,0x4274,0xac8b,0x492f,0x4605,0x8e5b,0xbe28,0x41c8,0xffe7,0x8e8,0xcb67,0x66}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xdb42d6bd,0xaae96f34,0x42742b3a,0x492fac8b,0x8e5b4605,0x41c8be28,0x8e8ffe7,0x66cb67}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xaae96f34db42d6bd,0x492fac8b42742b3a,0x41c8be288e5b4605,0x66cb6708e8ffe7}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x9b92,0x3cde,0x8dc9,0x4acd,0x59f6,0x378c,0x93ea,0xb253,0x4da5,0xc63f,0xd6f3,0xb325,0xd36c,0xd143,0x350e,0x24}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x3cde9b92,0x4acd8dc9,0x378c59f6,0xb25393ea,0xc63f4da5,0xb325d6f3,0xd143d36c,0x24350e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4acd8dc93cde9b92,0xb25393ea378c59f6,0xb325d6f3c63f4da5,0x24350ed143d36c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xee73,0xf286,0xf4df,0x2731,0x8476,0x8dc7,0xcbe0,0x632,0xe6bb,0xc2d5,0x9ec8,0xb7d8,0x952c,0xcaf9,0xd501,0xdd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf286ee73,0x2731f4df,0x8dc78476,0x632cbe0,0xc2d5e6bb,0xb7d89ec8,0xcaf9952c,0xddd501}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x2731f4dff286ee73,0x632cbe08dc78476,0xb7d89ec8c2d5e6bb,0xddd501caf9952c}}}}
+#endif
+}}}}, {{{
+#if 0
+#elif RADIX == 16
+{{0x19e1, 0x1d98, 0x1de9, 0x1dfc, 0x922, 0x1fb8, 0x476, 0xd05, 0xc85, 0x1788, 0x1967, 0x155d, 0x1f93, 0x629, 0x188f, 0x119, 0x1f6f, 0x241, 0x1378, 0x0}}
+#elif RADIX == 32
+{{0xf6633c2, 0x2efe77a, 0xedfb849, 0x1215a0a4, 0x1cb3de21, 0x13f93aae, 0x6711e62, 0x120fdbc2, 0x9bc0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x922efe77a7b319e, 0xef10c8568291dbf7, 0xe23cc53f93aaee59, 0x54de0483f6f08c}}
+#else
+{{0x177f3bd3d98cf, 0x568291dbf7092, 0x755dcb3de2190, 0x423388f314fe4, 0x2a6f0241fb7}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {{
+#if 0
+#elif RADIX == 16
+{{0x811, 0xf66, 0x77a, 0x177f, 0x248, 0x17ee, 0x91d, 0xb41, 0x321, 0x1de2, 0xe59, 0x1d57, 0xfe4, 0x198a, 0xe23, 0x1846, 0xfdb, 0x90, 0x14de, 0x8}}
+#elif RADIX == 32
+{{0x13d99023, 0x8bbf9de, 0x3b7ee12, 0xc856829, 0x172cf788, 0x14fe4eab, 0x119c4798, 0x483f6f0, 0x3a6f0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xc248bbf9de9ecc81, 0x7bc43215a0a476fd, 0x388f314fe4eabb96, 0x95378120fdbc23}}
+#else
+{{0x45dfcef4f6640, 0x15a0a476fdc24, 0x1d5772cf78864, 0x708ce23cc53f9, 0x2ca9bc0907ed}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, true}, {{{
+#if 0
+#elif RADIX == 16
+{{0x869, 0x197b, 0xcdb, 0x1d89, 0xf9b, 0x1d79, 0x18ec, 0xafe, 0x1d41, 0x77, 0x9d4, 0x1a3f, 0x2b, 0x46d, 0x173e, 0xedd, 0x172, 0x1c77, 0x8a6, 0x8}}
+#elif RADIX == 32
+{{0x1e5ed0d3, 0x1bec4b36, 0x1d9d797c, 0x15055fd8, 0x14ea01df, 0x1a02bd1f, 0x176e7c46, 0x3b85c9d, 0x34537}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x2f9bec4b36f2f686, 0xefd4157f63b3af, 0xdcf88da02bd1fa75, 0x31229b8ee17276e}}
+#else
+{{0x5f6259b797b43, 0x157f63b3af2f9, 0x7a3f4ea01dfa8, 0x1dbb73e23680a, 0x18914dc770b9}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x124b, 0xed4, 0x1706, 0x32d, 0x1541, 0x11b8, 0x2b0, 0xbe4, 0x1ee8, 0x1a3c, 0x16e3, 0x1d25, 0x19bb, 0xb63, 0x1fc1, 0x5fa, 0xf03, 0xfa, 0x1ec, 0x9}}
+#elif RADIX == 32
+{{0x13b52497, 0x1196dc1, 0x1611b8aa, 0x1ba17c82, 0x1b71e8f3, 0x79bbe92, 0x1ebf82b6, 0x7d3c0cb, 0x40f60}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x1541196dc19da924, 0xf479ee85f20ac237, 0x7f056c79bbe92db8, 0x3b87b01f4f032fd}}
+#else
+{{0x8cb6e0ced492, 0x5f20ac237154, 0x7d25b71e8f3dd, 0x4bf5fc15b1e6e, 0x1dc3d80fa781}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x1e71, 0xd67, 0x13da, 0x19eb, 0x137a, 0x1d27, 0x1ba7, 0x1996, 0x755, 0xe3d, 0x1139, 0x1764, 0x18ac, 0x1020, 0x3c4, 0x150e, 0x1ffd, 0x14fe, 0xa16, 0x6}}
+#elif RADIX == 32
+{{0x1359fce3, 0x1acf5cf6, 0x14fd279b, 0x1d5732db, 0x89cb8f4, 0x18acbb2, 0x3878902, 0x7f7ff6a, 0x150b5}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xf37acf5cf69acfe7, 0x5c7a755ccb6e9fa4, 0xf120418acbb244e, 0x8285a9fdffda87}}
+#else
+{{0x567ae7b4d67f3, 0x5ccb6e9fa4f37, 0x176489cb8f4ea, 0x6a1c3c481062b, 0x2c142d4feffe}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x13ec, 0x10a3, 0x1e69, 0x106f, 0x619, 0x1cb5, 0x9aa, 0x362, 0x53a, 0x1af5, 0x1bae, 0x60a, 0x2a4, 0x448, 0x3d0, 0x535, 0xeb1, 0x1a6e, 0x978, 0x5}}
+#elif RADIX == 32
+{{0xc28e7d9, 0x19837f9a, 0x155cb530, 0x14e86c49, 0xdd76bd4, 0x102a4305, 0xd47a044, 0x1373ac4a, 0x4bc6}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xa619837f9a61473e, 0xb5ea53a1b126ab96, 0x8f408902a43056eb, 0x3ea5e34dceb129a}}
+#else
+{{0x4c1bfcd30a39f, 0x21b126ab96a61, 0x60add76bd4a7, 0x4a6a3d02240a9, 0x1f52f1a6e758}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x77a, 0x201, 0x168d, 0x8fe, 0x780, 0x1ccb, 0x52b, 0x1c83, 0x18dd, 0xcef, 0x11f5, 0x1446, 0x301, 0xb63, 0xe3f, 0x1b72, 0x1, 0x1da9, 0x1281, 0x8}}
+#elif RADIX == 32
+{{0x8804ef5, 0x47f5a3, 0x57ccb3c, 0x3779065, 0x8fab3bf, 0x6301a23, 0x1c9c7eb6, 0xd480076, 0x3940f}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x678047f5a3440277, 0x59df8dde4194af99, 0x38fd6c6301a2347d, 0x364a07b52001db9}}
+#else
+{{0x23fad1a2013b, 0x5e4194af99678, 0x34468fab3bf1b, 0x76e4e3f5b18c0, 0x432503da9000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x1, 0xb39, 0x969, 0x1324, 0xbe6, 0x86e, 0x1021, 0x29a, 0x1ff0, 0xd23, 0x7d5, 0x72a, 0x1e33, 0x1fd9, 0x10af, 0x15bc, 0x1d56, 0x928, 0x1d49, 0x0}}
+#elif RADIX == 32
+{{0xace4002, 0x699225a, 0x4286e5f, 0x1fc05350, 0x3eab48f, 0x13e33395, 0xf215ffd, 0x94755ab, 0xea4a}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xcbe699225a567200, 0x5a47ff014d40850d, 0x42bffb3e333951f5, 0x57525251d56ade}}
+#else
+{{0x34c912d2b3900, 0x14d40850dcbe, 0x672a3eab48ffe, 0x2b790affecf8c, 0x2ba92928eab}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xef13,0xa8dc,0x8ceb,0xe405,0xe2f5,0xfda5,0x28ac,0x3bbe,0x41e5,0xee91,0xb0ff,0x5f5c,0x1920,0x1e33,0xef67,0x95}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xa8dcef13,0xe4058ceb,0xfda5e2f5,0x3bbe28ac,0xee9141e5,0x5f5cb0ff,0x1e331920,0x95ef67}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xe4058ceba8dcef13,0x3bbe28acfda5e2f5,0x5f5cb0ffee9141e5,0x95ef671e331920}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x6b6e,0x9e93,0xfbce,0xb1b6,0x80bb,0x14b8,0x20ae,0x6bcd,0xb7f4,0xfeff,0xc4a7,0xceb3,0xd874,0x65bf,0xe003,0xe9}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x9e936b6e,0xb1b6fbce,0x14b880bb,0x6bcd20ae,0xfeffb7f4,0xceb3c4a7,0x65bfd874,0xe9e003}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb1b6fbce9e936b6e,0x6bcd20ae14b880bb,0xceb3c4a7feffb7f4,0xe9e00365bfd874}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x47ff,0xc988,0x46b6,0x5236,0x9694,0xec04,0xd563,0x7d56,0x6833,0xc48f,0x8b0a,0xe195,0xb64e,0xe957,0x58b2,0xdb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xc98847ff,0x523646b6,0xec049694,0x7d56d563,0xc48f6833,0xe1958b0a,0xe957b64e,0xdb58b2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x523646b6c98847ff,0x7d56d563ec049694,0xe1958b0ac48f6833,0xdb58b2e957b64e}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x10ed,0x5723,0x7314,0x1bfa,0x1d0a,0x25a,0xd753,0xc441,0xbe1a,0x116e,0x4f00,0xa0a3,0xe6df,0xe1cc,0x1098,0x6a}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x572310ed,0x1bfa7314,0x25a1d0a,0xc441d753,0x116ebe1a,0xa0a34f00,0xe1cce6df,0x6a1098}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x1bfa7314572310ed,0xc441d753025a1d0a,0xa0a34f00116ebe1a,0x6a1098e1cce6df}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x231b,0x1af2,0x1640,0xb19c,0xf713,0xe470,0x683e,0xf39a,0x3289,0x7a54,0xc26e,0x904e,0xd5a6,0x6a0c,0x55fc,0x44}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1af2231b,0xb19c1640,0xe470f713,0xf39a683e,0x7a543289,0x904ec26e,0x6a0cd5a6,0x4455fc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb19c16401af2231b,0xf39a683ee470f713,0x904ec26e7a543289,0x4455fc6a0cd5a6}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xad7a,0xb685,0xde69,0x55d2,0x5675,0x84e8,0x5916,0x925f,0x8c0a,0x1cb6,0x7c51,0x8391,0xffce,0x11d1,0x96ce,0xcd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb685ad7a,0x55d2de69,0x84e85675,0x925f5916,0x1cb68c0a,0x83917c51,0x11d1ffce,0xcd96ce}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x55d2de69b685ad7a,0x925f591684e85675,0x83917c511cb68c0a,0xcd96ce11d1ffce}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x3724,0x79bd,0x1b92,0x959b,0xb3ec,0x6f18,0x27d4,0x64a7,0x9b4b,0x8c7e,0xade7,0x664b,0xa6d9,0xa287,0x6a1d,0x48}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x79bd3724,0x959b1b92,0x6f18b3ec,0x64a727d4,0x8c7e9b4b,0x664bade7,0xa287a6d9,0x486a1d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x959b1b9279bd3724,0x64a727d46f18b3ec,0x664bade78c7e9b4b,0x486a1da287a6d9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xdce5,0xe50d,0xe9bf,0x4e63,0x8ec,0x1b8f,0x97c1,0xc65,0xcd76,0x85ab,0x3d91,0x6fb1,0x2a59,0x95f3,0xaa03,0xbb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe50ddce5,0x4e63e9bf,0x1b8f08ec,0xc6597c1,0x85abcd76,0x6fb13d91,0x95f32a59,0xbbaa03}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4e63e9bfe50ddce5,0xc6597c11b8f08ec,0x6fb13d9185abcd76,0xbbaa0395f32a59}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x8d79,0x38f8,0xf94c,0xe776,0x2bdf,0x2d2e,0x4242,0x8677,0xddf0,0x1736,0xa2e3,0x8ee7,0x52ac,0x4bb1,0xbb55,0xa4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x38f88d79,0xe776f94c,0x2d2e2bdf,0x86774242,0x1736ddf0,0x8ee7a2e3,0x4bb152ac,0xa4bb55}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xe776f94c38f88d79,0x867742422d2e2bdf,0x8ee7a2e31736ddf0,0xa4bb554bb152ac}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x6774,0xe280,0xc0b8,0xd49d,0x3b88,0x2577,0xc53f,0x7a5d,0x3032,0x4cfb,0xd6b2,0x3ed5,0x27b8,0x584c,0x85b1,0xfc}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe2806774,0xd49dc0b8,0x25773b88,0x7a5dc53f,0x4cfb3032,0x3ed5d6b2,0x584c27b8,0xfc85b1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xd49dc0b8e2806774,0x7a5dc53f25773b88,0x3ed5d6b24cfb3032,0xfc85b1584c27b8}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xc139,0x25cf,0xd25b,0xadb9,0xbd39,0xaa20,0x8867,0x4e7a,0x8b24,0xa81f,0x412a,0xacfc,0xee2d,0xab0c,0x1d50,0x20}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x25cfc139,0xadb9d25b,0xaa20bd39,0x4e7a8867,0xa81f8b24,0xacfc412a,0xab0cee2d,0x201d50}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xadb9d25b25cfc139,0x4e7a8867aa20bd39,0xacfc412aa81f8b24,0x201d50ab0cee2d}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x7287,0xc707,0x6b3,0x1889,0xd420,0xd2d1,0xbdbd,0x7988,0x220f,0xe8c9,0x5d1c,0x7118,0xad53,0xb44e,0x44aa,0x5b}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xc7077287,0x188906b3,0xd2d1d420,0x7988bdbd,0xe8c9220f,0x71185d1c,0xb44ead53,0x5b44aa}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x188906b3c7077287,0x7988bdbdd2d1d420,0x71185d1ce8c9220f,0x5b44aab44ead53}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xef13,0xa8dc,0x8ceb,0xe405,0xe2f5,0xfda5,0x28ac,0x3bbe,0x41e5,0xee91,0xb0ff,0x5f5c,0x1920,0x1e33,0xef67,0x95}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xa8dcef13,0xe4058ceb,0xfda5e2f5,0x3bbe28ac,0xee9141e5,0x5f5cb0ff,0x1e331920,0x95ef67}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xe4058ceba8dcef13,0x3bbe28acfda5e2f5,0x5f5cb0ffee9141e5,0x95ef671e331920}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x6b6e,0x9e93,0xfbce,0xb1b6,0x80bb,0x14b8,0x20ae,0x6bcd,0xb7f4,0xfeff,0xc4a7,0xceb3,0xd874,0x65bf,0xe003,0xe9}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x9e936b6e,0xb1b6fbce,0x14b880bb,0x6bcd20ae,0xfeffb7f4,0xceb3c4a7,0x65bfd874,0xe9e003}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb1b6fbce9e936b6e,0x6bcd20ae14b880bb,0xceb3c4a7feffb7f4,0xe9e00365bfd874}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x47ff,0xc988,0x46b6,0x5236,0x9694,0xec04,0xd563,0x7d56,0x6833,0xc48f,0x8b0a,0xe195,0xb64e,0xe957,0x58b2,0xdb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xc98847ff,0x523646b6,0xec049694,0x7d56d563,0xc48f6833,0xe1958b0a,0xe957b64e,0xdb58b2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x523646b6c98847ff,0x7d56d563ec049694,0xe1958b0ac48f6833,0xdb58b2e957b64e}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x10ed,0x5723,0x7314,0x1bfa,0x1d0a,0x25a,0xd753,0xc441,0xbe1a,0x116e,0x4f00,0xa0a3,0xe6df,0xe1cc,0x1098,0x6a}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x572310ed,0x1bfa7314,0x25a1d0a,0xc441d753,0x116ebe1a,0xa0a34f00,0xe1cce6df,0x6a1098}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x1bfa7314572310ed,0xc441d753025a1d0a,0xa0a34f00116ebe1a,0x6a1098e1cce6df}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x118e,0xd79,0xb20,0xd8ce,0x7b89,0x7238,0x341f,0xf9cd,0x1944,0x3d2a,0x6137,0x4827,0x6ad3,0x3506,0x2afe,0x22}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd79118e,0xd8ce0b20,0x72387b89,0xf9cd341f,0x3d2a1944,0x48276137,0x35066ad3,0x222afe}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xd8ce0b200d79118e,0xf9cd341f72387b89,0x482761373d2a1944,0x222afe35066ad3}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xd6bd,0xdb42,0x6f34,0xaae9,0x2b3a,0x4274,0xac8b,0x492f,0x4605,0x8e5b,0xbe28,0x41c8,0xffe7,0x8e8,0xcb67,0x66}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xdb42d6bd,0xaae96f34,0x42742b3a,0x492fac8b,0x8e5b4605,0x41c8be28,0x8e8ffe7,0x66cb67}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xaae96f34db42d6bd,0x492fac8b42742b3a,0x41c8be288e5b4605,0x66cb6708e8ffe7}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x9b92,0x3cde,0x8dc9,0x4acd,0x59f6,0x378c,0x93ea,0xb253,0x4da5,0xc63f,0xd6f3,0xb325,0xd36c,0xd143,0x350e,0x24}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x3cde9b92,0x4acd8dc9,0x378c59f6,0xb25393ea,0xc63f4da5,0xb325d6f3,0xd143d36c,0x24350e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4acd8dc93cde9b92,0xb25393ea378c59f6,0xb325d6f3c63f4da5,0x24350ed143d36c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xee73,0xf286,0xf4df,0x2731,0x8476,0x8dc7,0xcbe0,0x632,0xe6bb,0xc2d5,0x9ec8,0xb7d8,0x952c,0xcaf9,0xd501,0xdd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf286ee73,0x2731f4df,0x8dc78476,0x632cbe0,0xc2d5e6bb,0xb7d89ec8,0xcaf9952c,0xddd501}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x2731f4dff286ee73,0x632cbe08dc78476,0xb7d89ec8c2d5e6bb,0xddd501caf9952c}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x7029,0x8b30,0x7529,0x9941,0x2be8,0x7b3f,0xe3d7,0x4553,0x7065,0x7bef,0xb49c,0xc80b,0xfa3e,0x950c,0x1ece,0x18}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x8b307029,0x99417529,0x7b3f2be8,0x4553e3d7,0x7bef7065,0xc80bb49c,0x950cfa3e,0x181ece}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x994175298b307029,0x4553e3d77b3f2be8,0xc80bb49c7bef7065,0x181ece950cfa3e}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xb399,0x92ce,0x85e8,0x7c82,0x86eb,0xb186,0x8924,0x64f1,0xd93,0x5e9a,0x3165,0x4196,0x5e79,0x158,0x55d5,0x31}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x92ceb399,0x7c8285e8,0xb18686eb,0x64f18924,0x5e9a0d93,0x41963165,0x1585e79,0x3155d5}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7c8285e892ceb399,0x64f18924b18686eb,0x419631655e9a0d93,0x3155d501585e79}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xda47,0x29f8,0x7209,0xaa0c,0xfc22,0x39c9,0x6e19,0x517c,0xc94e,0xcfa4,0x20fc,0x1edc,0xe0d0,0x396d,0x85f0,0xdf}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x29f8da47,0xaa0c7209,0x39c9fc22,0x517c6e19,0xcfa4c94e,0x1edc20fc,0x396de0d0,0xdf85f0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xaa0c720929f8da47,0x517c6e1939c9fc22,0x1edc20fccfa4c94e,0xdf85f0396de0d0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x8fd7,0x74cf,0x8ad6,0x66be,0xd417,0x84c0,0x1c28,0xbaac,0x8f9a,0x8410,0x4b63,0x37f4,0x5c1,0x6af3,0xe131,0xe7}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x74cf8fd7,0x66be8ad6,0x84c0d417,0xbaac1c28,0x84108f9a,0x37f44b63,0x6af305c1,0xe7e131}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x66be8ad674cf8fd7,0xbaac1c2884c0d417,0x37f44b6384108f9a,0xe7e1316af305c1}}}}
+#endif
+}}}}, {{{
+#if 0
+#elif RADIX == 16
+{{0x13f5, 0x8b7, 0x1873, 0x144a, 0x1a89, 0x13f9, 0xd49, 0x6f2, 0x3bb, 0x102, 0x1ecb, 0x180b, 0x4d5, 0x608, 0x119, 0x5e6, 0x751, 0x961, 0xd37, 0x5}}
+#elif RADIX == 32
+{{0x1a2de7eb, 0x9a2561c, 0x933f9d4, 0xeecde4d, 0x1f658408, 0x104d5c05, 0x19823260, 0xb09d44b, 0x69ba}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x3a89a2561cd16f3f, 0xc2043bb37935267f, 0x464c104d5c05fb2, 0x1bb4dd2c27512f3}}
+#else
+{{0x4d12b0e68b79f, 0x337935267f3a8, 0x380bf65840877, 0x4bcc119304135, 0x35da6e9613a8}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {{
+#if 0
+#elif RADIX == 16
+{{0x1e96, 0x1a2d, 0x161c, 0xd12, 0xea2, 0xcfe, 0x1352, 0x19bc, 0x10ee, 0x1840, 0x1fb2, 0xe02, 0x135, 0x982, 0x1046, 0x979, 0x9d4, 0x1a58, 0x1b4d, 0x9}}
+#elif RADIX == 32
+{{0x68b7d2d, 0x2689587, 0xa4cfe75, 0x3bb3793, 0xfd96102, 0x4135701, 0x1e608c98, 0x12c27512, 0x4da6e}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xcea2689587345be9, 0xb0810eecde4d499f, 0xc1193041357017ec, 0x22ed374b09d44bc}}
+#else
+{{0x1344ac39a2df4, 0x6cde4d499fcea, 0x2e02fd961021d, 0x12f30464c104d, 0x39769ba584ea}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, true}, {{{
+#if 0
+#elif RADIX == 16
+{{0xa82, 0x1d2d, 0x15b8, 0x404, 0x1a32, 0xaf9, 0xa86, 0xddf, 0x14bf, 0x100c, 0xc42, 0xa89, 0x1df, 0x82f, 0x1f07, 0x782, 0x664, 0x1ba5, 0x5d7, 0x2}}
+#elif RADIX == 32
+{{0x74b5504, 0x1220256e, 0x10caf9d1, 0x12fdbbea, 0x16214032, 0x1e1df544, 0xbe0e82, 0x1d29990f, 0x22ebe}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x3a3220256e3a5aa8, 0xa0194bf6efaa195f, 0x7c1d05e1df544b10, 0xb175f74a6643c1}}
+#else
+{{0x11012b71d2d54, 0x76efaa195f3a3, 0x6a89621403297, 0xf05f07417877, 0x58bafba5332}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x5a1, 0x46a, 0x17ab, 0x1cfa, 0x547, 0x1b9c, 0xda5, 0x141e, 0x216, 0x1f49, 0xaca, 0x15a1, 0xfe0, 0x1afb, 0x1a47, 0x133d, 0x1887, 0x590, 0xbc2, 0x1}}
+#elif RADIX == 32
+{{0x191a8b42, 0x7e7d5ea, 0x14bb9c2a, 0x85a83cd, 0x15657d24, 0x16fe0ad0, 0xf748faf, 0xc8621e6, 0x15e11}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x8547e7d5eac8d45a, 0xbe92216a0f369773, 0xe91f5f6fe0ad0ab2, 0x5af08b2188799e}}
+#else
+{{0x3f3eaf5646a2d, 0x6a0f369773854, 0x15a15657d2442, 0x667ba47d7dbf8, 0x2d784590c43}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x1311, 0x910, 0x413, 0x1d16, 0x14f7, 0x19c9, 0x14d3, 0x1504, 0x776, 0x1c2c, 0x15b0, 0xc6e, 0x36b, 0x1777, 0x1ed2, 0xb34, 0x1281, 0x1281, 0xd0f, 0x4}}
+#elif RADIX == 32
+{{0x1a442622, 0x17e8b104, 0x1a79c9a7, 0x1ddaa094, 0xad870b0, 0xe36b637, 0xd3da577, 0x140ca056, 0x4687c}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x34f7e8b104d22131, 0x3858776a82534f39, 0x7b4aeee36b63756c, 0x7343e50328159a}}
+#else
+{{0x3f45882691098, 0x6a82534f3934f, 0x6c6ead870b0ee, 0x5669ed2bbb8da, 0x2b9a1f281940}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x12d2, 0x6d8, 0x1e2c, 0x6f9, 0x5e8, 0x4e5, 0x32c, 0x58d, 0x1bda, 0x16f9, 0x8b5, 0x3c0, 0x10c, 0xb18, 0x450, 0x834, 0x3b7, 0x8d7, 0x15bf, 0x0}}
+#elif RADIX == 32
+{{0x1b625a4, 0x837cf8b, 0x584e52f, 0xf68b1a3, 0x45adbe7, 0x1010c1e0, 0xd08a0b1, 0x6b8edd0, 0xadfa}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xa5e837cf8b0db12d, 0x6df3bda2c68cb09c, 0x114163010c1e022d, 0xa56fd1ae3b741a}}
+#else
+{{0x41be7c586d896, 0x22c68cb09ca5e, 0x3c045adbe77b, 0x506845058c043, 0x2d2b7e8d71db}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x5f, 0x444, 0x49e, 0xae7, 0x248, 0x1a37, 0x9b6, 0xc28, 0x464, 0x19b7, 0x1560, 0xd7a, 0x2e3, 0x81a, 0x6f5, 0x5f9, 0x1818, 0x164c, 0x1713, 0x7}}
+#elif RADIX == 32
+{{0x111100bf, 0x8573927, 0x16da3712, 0x11918509, 0xab066dc, 0x142e36bd, 0x1e4dea81, 0x1266060b, 0x2b89d}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xe248573927888805, 0x336e46461426db46, 0x9bd50342e36bd558, 0x4edc4ec998182fc}}
+#else
+{{0x42b9c93c44402, 0x461426db46e24, 0x6d7aab066dc8c, 0xbf26f540d0b8, 0x4f6e2764cc0c}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x19b1, 0x1912, 0x1eb, 0x1cbc, 0x210, 0x17cf, 0x1b9e, 0x754, 0x38c, 0x816, 0x1431, 0x79a, 0xa57, 0x15ff, 0x756, 0xa60, 0x1064, 0x162f, 0x1e5e, 0x0}}
+#elif RADIX == 32
+{{0x1e44b362, 0x10e5e07a, 0x13d7cf10, 0xe30ea9b, 0xa18a058, 0x1ea573cd, 0x180ead5f, 0x117c1914, 0xf2f5}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xe210e5e07af2259b, 0x502c38c3aa6e7af9, 0x1d5abfea573cd50c, 0x5797ac5f064530}}
+#else
+{{0x72f03d7912cd, 0x43aa6e7af9e21, 0x679aa18a05871, 0x14c0756affa95, 0x2abcbd62f832}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x5ff1,0xa594,0x52b3,0xe75d,0xdd09,0xd267,0x7d25,0xd976,0xbc5,0xc1a8,0x9aae,0x10bf,0xe894,0x8de3,0xae84,0x70}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xa5945ff1,0xe75d52b3,0xd267dd09,0xd9767d25,0xc1a80bc5,0x10bf9aae,0x8de3e894,0x70ae84}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xe75d52b3a5945ff1,0xd9767d25d267dd09,0x10bf9aaec1a80bc5,0x70ae848de3e894}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x11e6,0xb9e0,0x96c0,0xa6d7,0xee81,0x4b6,0x2f44,0xf4c5,0x4597,0xe75d,0x5b93,0xebb6,0x59c6,0xc08e,0x3084,0x16}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb9e011e6,0xa6d796c0,0x4b6ee81,0xf4c52f44,0xe75d4597,0xebb65b93,0xc08e59c6,0x163084}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xa6d796c0b9e011e6,0xf4c52f4404b6ee81,0xebb65b93e75d4597,0x163084c08e59c6}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xf41d,0x3463,0x6031,0x479f,0x6fe7,0x159f,0x1e6b,0x404e,0xe302,0x88a8,0xc1f7,0xad84,0x8b50,0x3175,0x3d66,0xab}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x3463f41d,0x479f6031,0x159f6fe7,0x404e1e6b,0x88a8e302,0xad84c1f7,0x31758b50,0xab3d66}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x479f60313463f41d,0x404e1e6b159f6fe7,0xad84c1f788a8e302,0xab3d6631758b50}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xa00f,0x5a6b,0xad4c,0x18a2,0x22f6,0x2d98,0x82da,0x2689,0xf43a,0x3e57,0x6551,0xef40,0x176b,0x721c,0x517b,0x8f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x5a6ba00f,0x18a2ad4c,0x2d9822f6,0x268982da,0x3e57f43a,0xef406551,0x721c176b,0x8f517b}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x18a2ad4c5a6ba00f,0x268982da2d9822f6,0xef4065513e57f43a,0x8f517b721c176b}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x231b,0x1af2,0x1640,0xb19c,0xf713,0xe470,0x683e,0xf39a,0x3289,0x7a54,0xc26e,0x904e,0xd5a6,0x6a0c,0x55fc,0x44}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1af2231b,0xb19c1640,0xe470f713,0xf39a683e,0x7a543289,0x904ec26e,0x6a0cd5a6,0x4455fc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb19c16401af2231b,0xf39a683ee470f713,0x904ec26e7a543289,0x4455fc6a0cd5a6}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xad7a,0xb685,0xde69,0x55d2,0x5675,0x84e8,0x5916,0x925f,0x8c0a,0x1cb6,0x7c51,0x8391,0xffce,0x11d1,0x96ce,0xcd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb685ad7a,0x55d2de69,0x84e85675,0x925f5916,0x1cb68c0a,0x83917c51,0x11d1ffce,0xcd96ce}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x55d2de69b685ad7a,0x925f591684e85675,0x83917c511cb68c0a,0xcd96ce11d1ffce}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x3724,0x79bd,0x1b92,0x959b,0xb3ec,0x6f18,0x27d4,0x64a7,0x9b4b,0x8c7e,0xade7,0x664b,0xa6d9,0xa287,0x6a1d,0x48}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x79bd3724,0x959b1b92,0x6f18b3ec,0x64a727d4,0x8c7e9b4b,0x664bade7,0xa287a6d9,0x486a1d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x959b1b9279bd3724,0x64a727d46f18b3ec,0x664bade78c7e9b4b,0x486a1da287a6d9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xdce5,0xe50d,0xe9bf,0x4e63,0x8ec,0x1b8f,0x97c1,0xc65,0xcd76,0x85ab,0x3d91,0x6fb1,0x2a59,0x95f3,0xaa03,0xbb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe50ddce5,0x4e63e9bf,0x1b8f08ec,0xc6597c1,0x85abcd76,0x6fb13d91,0x95f32a59,0xbbaa03}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4e63e9bfe50ddce5,0xc6597c11b8f08ec,0x6fb13d9185abcd76,0xbbaa0395f32a59}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xffc3,0x1fbe,0xc7ef,0x56c4,0x2834,0xfa5c,0x36aa,0x1ced,0x9076,0xa31d,0x8890,0xe52,0x87d2,0xef68,0x98bc,0xc2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1fbeffc3,0x56c4c7ef,0xfa5c2834,0x1ced36aa,0xa31d9076,0xe528890,0xef6887d2,0xc298bc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x56c4c7ef1fbeffc3,0x1ced36aafa5c2834,0xe528890a31d9076,0xc298bcef6887d2}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x4098,0xd740,0xb5c6,0x8109,0x299,0x3a8c,0x81c2,0xc0d0,0xe848,0x9243,0x8996,0x656a,0x8c87,0x6c99,0xb9f5,0x4c}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd7404098,0x8109b5c6,0x3a8c0299,0xc0d081c2,0x9243e848,0x656a8996,0x6c998c87,0x4cb9f5}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x8109b5c6d7404098,0xc0d081c23a8c0299,0x656a89969243e848,0x4cb9f56c998c87}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x712b,0xfeed,0x55b5,0xc5fe,0xe867,0x77a9,0x1775,0x7814,0x4780,0x73b1,0x86b1,0x3973,0x797a,0x7f0b,0x1fa,0xb0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xfeed712b,0xc5fe55b5,0x77a9e867,0x78141775,0x73b14780,0x397386b1,0x7f0b797a,0xb001fa}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xc5fe55b5feed712b,0x7814177577a9e867,0x397386b173b14780,0xb001fa7f0b797a}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x3d,0xe041,0x3810,0xa93b,0xd7cb,0x5a3,0xc955,0xe312,0x6f89,0x5ce2,0x776f,0xf1ad,0x782d,0x1097,0x6743,0x3d}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe041003d,0xa93b3810,0x5a3d7cb,0xe312c955,0x5ce26f89,0xf1ad776f,0x1097782d,0x3d6743}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xa93b3810e041003d,0xe312c95505a3d7cb,0xf1ad776f5ce26f89,0x3d67431097782d}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x5ff1,0xa594,0x52b3,0xe75d,0xdd09,0xd267,0x7d25,0xd976,0xbc5,0xc1a8,0x9aae,0x10bf,0xe894,0x8de3,0xae84,0x70}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xa5945ff1,0xe75d52b3,0xd267dd09,0xd9767d25,0xc1a80bc5,0x10bf9aae,0x8de3e894,0x70ae84}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xe75d52b3a5945ff1,0xd9767d25d267dd09,0x10bf9aaec1a80bc5,0x70ae848de3e894}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x11e6,0xb9e0,0x96c0,0xa6d7,0xee81,0x4b6,0x2f44,0xf4c5,0x4597,0xe75d,0x5b93,0xebb6,0x59c6,0xc08e,0x3084,0x16}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb9e011e6,0xa6d796c0,0x4b6ee81,0xf4c52f44,0xe75d4597,0xebb65b93,0xc08e59c6,0x163084}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xa6d796c0b9e011e6,0xf4c52f4404b6ee81,0xebb65b93e75d4597,0x163084c08e59c6}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xf41d,0x3463,0x6031,0x479f,0x6fe7,0x159f,0x1e6b,0x404e,0xe302,0x88a8,0xc1f7,0xad84,0x8b50,0x3175,0x3d66,0xab}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x3463f41d,0x479f6031,0x159f6fe7,0x404e1e6b,0x88a8e302,0xad84c1f7,0x31758b50,0xab3d66}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x479f60313463f41d,0x404e1e6b159f6fe7,0xad84c1f788a8e302,0xab3d6631758b50}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xa00f,0x5a6b,0xad4c,0x18a2,0x22f6,0x2d98,0x82da,0x2689,0xf43a,0x3e57,0x6551,0xef40,0x176b,0x721c,0x517b,0x8f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x5a6ba00f,0x18a2ad4c,0x2d9822f6,0x268982da,0x3e57f43a,0xef406551,0x721c176b,0x8f517b}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x18a2ad4c5a6ba00f,0x268982da2d9822f6,0xef4065513e57f43a,0x8f517b721c176b}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x118e,0xd79,0xb20,0xd8ce,0x7b89,0x7238,0x341f,0xf9cd,0x1944,0x3d2a,0x6137,0x4827,0x6ad3,0x3506,0x2afe,0x22}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd79118e,0xd8ce0b20,0x72387b89,0xf9cd341f,0x3d2a1944,0x48276137,0x35066ad3,0x222afe}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xd8ce0b200d79118e,0xf9cd341f72387b89,0x482761373d2a1944,0x222afe35066ad3}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xd6bd,0xdb42,0x6f34,0xaae9,0x2b3a,0x4274,0xac8b,0x492f,0x4605,0x8e5b,0xbe28,0x41c8,0xffe7,0x8e8,0xcb67,0x66}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xdb42d6bd,0xaae96f34,0x42742b3a,0x492fac8b,0x8e5b4605,0x41c8be28,0x8e8ffe7,0x66cb67}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xaae96f34db42d6bd,0x492fac8b42742b3a,0x41c8be288e5b4605,0x66cb6708e8ffe7}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x9b92,0x3cde,0x8dc9,0x4acd,0x59f6,0x378c,0x93ea,0xb253,0x4da5,0xc63f,0xd6f3,0xb325,0xd36c,0xd143,0x350e,0x24}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x3cde9b92,0x4acd8dc9,0x378c59f6,0xb25393ea,0xc63f4da5,0xb325d6f3,0xd143d36c,0x24350e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4acd8dc93cde9b92,0xb25393ea378c59f6,0xb325d6f3c63f4da5,0x24350ed143d36c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xee73,0xf286,0xf4df,0x2731,0x8476,0x8dc7,0xcbe0,0x632,0xe6bb,0xc2d5,0x9ec8,0xb7d8,0x952c,0xcaf9,0xd501,0xdd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf286ee73,0x2731f4df,0x8dc78476,0x632cbe0,0xc2d5e6bb,0xb7d89ec8,0xcaf9952c,0xddd501}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x2731f4dff286ee73,0x632cbe08dc78476,0xb7d89ec8c2d5e6bb,0xddd501caf9952c}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x5d2b,0x1bd6,0xcc3f,0x7e74,0x4fea,0xfba0,0x9f84,0xd6d4,0x42a1,0x88d1,0x68b1,0x4f4e,0x13ec,0xa60c,0xb13b,0x2e}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1bd65d2b,0x7e74cc3f,0xfba04fea,0xd6d49f84,0x88d142a1,0x4f4e68b1,0xa60c13ec,0x2eb13b}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7e74cc3f1bd65d2b,0xd6d49f84fba04fea,0x4f4e68b188d142a1,0x2eb13ba60c13ec}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x7b4f,0x9448,0xaa16,0x649a,0xe4b4,0x3bc2,0xd3fd,0x8df1,0x931e,0x4078,0x8caa,0xe896,0xdeec,0xbed5,0x166e,0x7c}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x94487b4f,0x649aaa16,0x3bc2e4b4,0x8df1d3fd,0x4078931e,0xe8968caa,0xbed5deec,0x7c166e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x649aaa1694487b4f,0x8df1d3fd3bc2e4b4,0xe8968caa4078931e,0x7c166ebed5deec}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x101d,0x51aa,0xd32d,0x2b40,0x7ba,0xc5f8,0x257a,0xb323,0x9bde,0x20c5,0xdc8f,0x2c3d,0x4e7b,0x54a6,0x17b9,0x99}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x51aa101d,0x2b40d32d,0xc5f807ba,0xb323257a,0x20c59bde,0x2c3ddc8f,0x54a64e7b,0x9917b9}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x2b40d32d51aa101d,0xb323257ac5f807ba,0x2c3ddc8f20c59bde,0x9917b954a64e7b}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xa2d5,0xe429,0x33c0,0x818b,0xb015,0x45f,0x607b,0x292b,0xbd5e,0x772e,0x974e,0xb0b1,0xec13,0x59f3,0x4ec4,0xd1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe429a2d5,0x818b33c0,0x45fb015,0x292b607b,0x772ebd5e,0xb0b1974e,0x59f3ec13,0xd14ec4}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x818b33c0e429a2d5,0x292b607b045fb015,0xb0b1974e772ebd5e,0xd14ec459f3ec13}}}}
+#endif
+}}}}, {{{
+#if 0
+#elif RADIX == 16
+{{0xa72, 0x186f, 0x81c, 0x105c, 0x151, 0x1451, 0x1b96, 0x4d1, 0x12be, 0x3bf, 0x996, 0x1130, 0x1460, 0x1ed8, 0xc2a, 0x1c23, 0x1ee, 0x3f4, 0xbe2, 0x9}}
+#elif RADIX == 32
+{{0x61bd4e5, 0x1182e207, 0x12d4510a, 0xaf89a3b, 0x4cb0efe, 0x11460898, 0x8d855ed, 0x1fa07bb8, 0x45f10}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x215182e20730dea7, 0x877f2be268ee5a8a, 0xb0abdb1460898265, 0xeaf887e81eee11}}
+#else
+{{0xc17103986f53, 0x6268ee5a8a215, 0x11304cb0efe57, 0x3846c2af6c518, 0x2f57c43f40f7}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {{
+#if 0
+#elif RADIX == 16
+{{0x1c36, 0x61b, 0x207, 0xc17, 0x854, 0x1514, 0xee5, 0x1134, 0x1caf, 0x10ef, 0x265, 0x44c, 0x518, 0x17b6, 0x1b0a, 0x1708, 0x7b, 0x10fd, 0xaf8, 0x3}}
+#elif RADIX == 32
+{{0x1986f86c, 0x1460b881, 0x1cb51442, 0x12be268e, 0x132c3bf, 0xc518226, 0x236157b, 0x7e81eee, 0x357c4}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x885460b881cc37c3, 0x61dfcaf89a3b96a2, 0x6c2af6c518226099, 0x1fabe21fa07bb84}}
+#else
+{{0x2305c40e61be1, 0x789a3b96a2885, 0x44c132c3bf95, 0x6e11b0abdb146, 0x37d5f10fd03d}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, true}, {{{
+#if 0
+#elif RADIX == 16
+{{0x1c07, 0x15d6, 0x526, 0xde7, 0x149b, 0x719, 0x1786, 0x1272, 0x18b, 0x1bac, 0xf74, 0x1588, 0xe6f, 0x24c, 0x1204, 0x1e9d, 0x13bb, 0x1ccb, 0x78d, 0x9}}
+#elif RADIX == 32
+{{0x1575b80f, 0x1b6f3949, 0x10c719a4, 0x62e4e57, 0x7ba6eb0, 0x18e6fac4, 0x7640824, 0x65ceefd, 0x43c6f}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x349b6f3949abadc0, 0x375818b9395e18e3, 0xc810498e6fac43dd, 0x279e379973bbf4e}}
+#else
+{{0x5b79ca4d5d6e0, 0x39395e18e3349, 0x75887ba6eb031, 0x7d3b20412639b, 0x13cf1bccb9dd}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0xddf, 0x238, 0xe4b, 0x1958, 0xe6e, 0x1059, 0x133, 0x1e11, 0x5ae, 0x2ab, 0x1044, 0xdd, 0xe9d, 0x1aa8, 0x15e2, 0xc9b, 0xaa6, 0x3c8, 0x10ac, 0x0}}
+#elif RADIX == 32
+{{0x188e1bbe, 0xecac392, 0x6705973, 0x16bbc221, 0x18220aac, 0x10e9d06e, 0x6ebc5aa, 0x1e42a999, 0x8560}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x2e6ecac392c470dd, 0x5565aef0884ce0b, 0xd78b550e9d06ec11, 0x4b42b0790aa664d}}
+#else
+{{0x76561c962386e, 0x6f0884ce0b2e6, 0x20dd8220aacb5, 0x19375e2d543a7, 0x4da1583c8553}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x192, 0x1c6d, 0x18a4, 0x152, 0x1aa9, 0xec4, 0x1be8, 0x1209, 0x7f, 0x797, 0x1295, 0x1433, 0x1a75, 0x15a, 0x1d64, 0x146c, 0x12df, 0x10af, 0x188f, 0x1}}
+#elif RADIX == 32
+{{0x71b4324, 0x90a9629, 0x1d0ec4d5, 0x1fe413b, 0x194a9e5c, 0x15a75a19, 0x1b3ac815, 0x57cb7e8, 0x1c47c}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x9aa90a962938da19, 0x4f2e07f904efa1d8, 0x75902b5a75a19ca5, 0xae23e15f2dfa36}}
+#else
+{{0x4854b149c6d0c, 0x7904efa1d89aa, 0x343394a9e5c0f, 0x68d9d640ad69d, 0x2d711f0af96f}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x129c, 0xe1d, 0x1bd3, 0xf2a, 0x937, 0xf81, 0xa47, 0x186b, 0x1bbe, 0x1c6d, 0x1edd, 0x1b51, 0xa10, 0x167a, 0x1f0b, 0x374, 0x720, 0x1547, 0x726, 0x1}}
+#elif RADIX == 32
+{{0x1b876538, 0x177956f4, 0x8ef8149, 0xefb0d6a, 0x1f6ef1b7, 0x14a10da8, 0x1d3e1767, 0xa39c806, 0x13935}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x29377956f4dc3b29, 0x78dbbbec35a91df0, 0x7c2ecf4a10da8fb7, 0x3c9c9aa8e7201ba}}
+#else
+{{0x3bcab7a6e1d94, 0x6c35a91df0293, 0x1b51f6ef1b777, 0x6e9f0bb3d284, 0x464e4d547390}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x12cc, 0x495, 0x1a14, 0x1db0, 0xb66, 0x76a, 0x1a77, 0xaf6, 0x1656, 0x1ad7, 0xb35, 0x4b1, 0xffa, 0x37b, 0xabf, 0xa5c, 0xdc9, 0x1a74, 0x11c9, 0x8}}
+#elif RADIX == 32
+{{0x1256599, 0x6ed8685, 0xee76a5b, 0x19595eda, 0x159aeb5e, 0x16ffa258, 0x17157e37, 0x13a37254, 0x38e4e}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x4b66ed8685092b2c, 0x75af65657b69dced, 0x2afc6f6ffa258acd, 0x4047274e8dc952e}}
+#else
+{{0x376c342849596, 0x657b69dced4b6, 0x44b159aeb5eca, 0x54b8abf1bdbfe, 0x202393a746e4}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x1379, 0x125e, 0x1c56, 0x1811, 0x144, 0x2a8, 0xbb3, 0x2ca, 0x6d2, 0x565, 0x91e, 0x1280, 0x1b4f, 0x51a, 0x1eb7, 0x35a, 0x14fe, 0x1b59, 0x182e, 0x2}}
+#elif RADIX == 32
+{{0x1497a6f2, 0x4c08f15, 0x1662a80a, 0x1b48594b, 0x48f1594, 0x15b4f940, 0x16bd6e51, 0x1acd3f86, 0x2c176}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x144c08f15a4bd37, 0x8aca6d21652ecc55, 0x7adca35b4f940247, 0x2e60bb6b34fe1ad}}
+#else
+{{0x260478ad25e9b, 0x21652ecc55014, 0x728048f1594da, 0x6b5eb728d6d3, 0x3f305db59a7f}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x323f,0x7ed2,0x4455,0x415c,0x5876,0x4282,0x76ef,0xcc11,0xbdab,0x1142,0x4729,0x3405,0x1155,0x1779,0x7c1f,0xc5}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x7ed2323f,0x415c4455,0x42825876,0xcc1176ef,0x1142bdab,0x34054729,0x17791155,0xc57c1f}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x415c44557ed2323f,0xcc1176ef42825876,0x340547291142bdab,0xc57c1f17791155}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xc9ce,0xa958,0x4fac,0x8a69,0x31e1,0x9997,0x1a17,0x8c19,0xd118,0x68c7,0xc0eb,0x8113,0x62fd,0xf8c8,0xc94e,0x3f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xa958c9ce,0x8a694fac,0x999731e1,0x8c191a17,0x68c7d118,0x8113c0eb,0xf8c862fd,0x3fc94e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x8a694faca958c9ce,0x8c191a17999731e1,0x8113c0eb68c7d118,0x3fc94ef8c862fd}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x41cb,0xed47,0x8ea0,0x127c,0x69d5,0xf74c,0xce8c,0x3826,0x3da2,0x6bf3,0x56b,0xe695,0xc45c,0x84ac,0x5817,0xd0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xed4741cb,0x127c8ea0,0xf74c69d5,0x3826ce8c,0x6bf33da2,0xe695056b,0x84acc45c,0xd05817}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x127c8ea0ed4741cb,0x3826ce8cf74c69d5,0xe695056b6bf33da2,0xd0581784acc45c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xcdc1,0x812d,0xbbaa,0xbea3,0xa789,0xbd7d,0x8910,0x33ee,0x4254,0xeebd,0xb8d6,0xcbfa,0xeeaa,0xe886,0x83e0,0x3a}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x812dcdc1,0xbea3bbaa,0xbd7da789,0x33ee8910,0xeebd4254,0xcbfab8d6,0xe886eeaa,0x3a83e0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xbea3bbaa812dcdc1,0x33ee8910bd7da789,0xcbfab8d6eebd4254,0x3a83e0e886eeaa}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xdce5,0xe50d,0xe9bf,0x4e63,0x8ec,0x1b8f,0x97c1,0xc65,0xcd76,0x85ab,0x3d91,0x6fb1,0x2a59,0x95f3,0xaa03,0xbb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe50ddce5,0x4e63e9bf,0x1b8f08ec,0xc6597c1,0x85abcd76,0x6fb13d91,0x95f32a59,0xbbaa03}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4e63e9bfe50ddce5,0xc6597c11b8f08ec,0x6fb13d9185abcd76,0xbbaa0395f32a59}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x5286,0x497a,0x2196,0xaa2d,0xa98a,0x7b17,0xa6e9,0x6da0,0x73f5,0xe349,0x83ae,0x7c6e,0x31,0xee2e,0x6931,0x32}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x497a5286,0xaa2d2196,0x7b17a98a,0x6da0a6e9,0xe34973f5,0x7c6e83ae,0xee2e0031,0x326931}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xaa2d2196497a5286,0x6da0a6e97b17a98a,0x7c6e83aee34973f5,0x326931ee2e0031}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xc8dc,0x8642,0xe46d,0x6a64,0x4c13,0x90e7,0xd82b,0x9b58,0x64b4,0x7381,0x5218,0x99b4,0x5926,0x5d78,0x95e2,0xb7}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x8642c8dc,0x6a64e46d,0x90e74c13,0x9b58d82b,0x738164b4,0x99b45218,0x5d785926,0xb795e2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x6a64e46d8642c8dc,0x9b58d82b90e74c13,0x99b45218738164b4,0xb795e25d785926}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x231b,0x1af2,0x1640,0xb19c,0xf713,0xe470,0x683e,0xf39a,0x3289,0x7a54,0xc26e,0x904e,0xd5a6,0x6a0c,0x55fc,0x44}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1af2231b,0xb19c1640,0xe470f713,0xf39a683e,0x7a543289,0x904ec26e,0x6a0cd5a6,0x4455fc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb19c16401af2231b,0xf39a683ee470f713,0x904ec26e7a543289,0x4455fc6a0cd5a6}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x7363,0xbe7a,0xc901,0xb6e0,0x6a56,0x779d,0xbc42,0xd659,0x3476,0x3868,0x12f4,0x923a,0x6fa8,0x5412,0xd5f9,0x3}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xbe7a7363,0xb6e0c901,0x779d6a56,0xd659bc42,0x38683476,0x923a12f4,0x54126fa8,0x3d5f9}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb6e0c901be7a7363,0xd659bc42779d6a56,0x923a12f438683476,0x3d5f954126fa8}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xedb4,0x4fd4,0x5c14,0x14b,0xf702,0xd6be,0x9c11,0x4bb,0x9f10,0xde25,0xb159,0x5085,0xb0a9,0x6f42,0xc4d3,0x1d}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x4fd4edb4,0x14b5c14,0xd6bef702,0x4bb9c11,0xde259f10,0x5085b159,0x6f42b0a9,0x1dc4d3}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x14b5c144fd4edb4,0x4bb9c11d6bef702,0x5085b159de259f10,0x1dc4d36f42b0a9}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xe873,0x4974,0xc7ed,0x6b01,0xaffb,0xf3d4,0xc641,0x20d6,0xca22,0x2d69,0x9f01,0x451e,0xfa05,0xef65,0xb43b,0xde}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x4974e873,0x6b01c7ed,0xf3d4affb,0x20d6c641,0x2d69ca22,0x451e9f01,0xef65fa05,0xdeb43b}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x6b01c7ed4974e873,0x20d6c641f3d4affb,0x451e9f012d69ca22,0xdeb43bef65fa05}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x8c9d,0x4185,0x36fe,0x491f,0x95a9,0x8862,0x43bd,0x29a6,0xcb89,0xc797,0xed0b,0x6dc5,0x9057,0xabed,0x2a06,0xfc}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x41858c9d,0x491f36fe,0x886295a9,0x29a643bd,0xc797cb89,0x6dc5ed0b,0xabed9057,0xfc2a06}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x491f36fe41858c9d,0x29a643bd886295a9,0x6dc5ed0bc797cb89,0xfc2a06abed9057}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x323f,0x7ed2,0x4455,0x415c,0x5876,0x4282,0x76ef,0xcc11,0xbdab,0x1142,0x4729,0x3405,0x1155,0x1779,0x7c1f,0xc5}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x7ed2323f,0x415c4455,0x42825876,0xcc1176ef,0x1142bdab,0x34054729,0x17791155,0xc57c1f}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x415c44557ed2323f,0xcc1176ef42825876,0x340547291142bdab,0xc57c1f17791155}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xc9ce,0xa958,0x4fac,0x8a69,0x31e1,0x9997,0x1a17,0x8c19,0xd118,0x68c7,0xc0eb,0x8113,0x62fd,0xf8c8,0xc94e,0x3f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xa958c9ce,0x8a694fac,0x999731e1,0x8c191a17,0x68c7d118,0x8113c0eb,0xf8c862fd,0x3fc94e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x8a694faca958c9ce,0x8c191a17999731e1,0x8113c0eb68c7d118,0x3fc94ef8c862fd}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x41cb,0xed47,0x8ea0,0x127c,0x69d5,0xf74c,0xce8c,0x3826,0x3da2,0x6bf3,0x56b,0xe695,0xc45c,0x84ac,0x5817,0xd0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xed4741cb,0x127c8ea0,0xf74c69d5,0x3826ce8c,0x6bf33da2,0xe695056b,0x84acc45c,0xd05817}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x127c8ea0ed4741cb,0x3826ce8cf74c69d5,0xe695056b6bf33da2,0xd0581784acc45c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xcdc1,0x812d,0xbbaa,0xbea3,0xa789,0xbd7d,0x8910,0x33ee,0x4254,0xeebd,0xb8d6,0xcbfa,0xeeaa,0xe886,0x83e0,0x3a}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x812dcdc1,0xbea3bbaa,0xbd7da789,0x33ee8910,0xeebd4254,0xcbfab8d6,0xe886eeaa,0x3a83e0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xbea3bbaa812dcdc1,0x33ee8910bd7da789,0xcbfab8d6eebd4254,0x3a83e0e886eeaa}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xee73,0xf286,0xf4df,0x2731,0x8476,0x8dc7,0xcbe0,0x632,0xe6bb,0xc2d5,0x9ec8,0xb7d8,0x952c,0xcaf9,0xd501,0xdd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf286ee73,0x2731f4df,0x8dc78476,0x632cbe0,0xc2d5e6bb,0xb7d89ec8,0xcaf9952c,0xddd501}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x2731f4dff286ee73,0x632cbe08dc78476,0xb7d89ec8c2d5e6bb,0xddd501caf9952c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x2943,0x24bd,0x90cb,0x5516,0xd4c5,0xbd8b,0x5374,0xb6d0,0xb9fa,0x71a4,0x41d7,0xbe37,0x18,0xf717,0x3498,0x99}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x24bd2943,0x551690cb,0xbd8bd4c5,0xb6d05374,0x71a4b9fa,0xbe3741d7,0xf7170018,0x993498}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x551690cb24bd2943,0xb6d05374bd8bd4c5,0xbe3741d771a4b9fa,0x993498f7170018}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x646e,0xc321,0x7236,0xb532,0xa609,0xc873,0x6c15,0x4dac,0xb25a,0x39c0,0x290c,0x4cda,0x2c93,0x2ebc,0xcaf1,0xdb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xc321646e,0xb5327236,0xc873a609,0x4dac6c15,0x39c0b25a,0x4cda290c,0x2ebc2c93,0xdbcaf1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb5327236c321646e,0x4dac6c15c873a609,0x4cda290c39c0b25a,0xdbcaf12ebc2c93}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x118e,0xd79,0xb20,0xd8ce,0x7b89,0x7238,0x341f,0xf9cd,0x1944,0x3d2a,0x6137,0x4827,0x6ad3,0x3506,0x2afe,0x22}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd79118e,0xd8ce0b20,0x72387b89,0xf9cd341f,0x3d2a1944,0x48276137,0x35066ad3,0x222afe}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xd8ce0b200d79118e,0xf9cd341f72387b89,0x482761373d2a1944,0x222afe35066ad3}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xca5b,0x1036,0x34a6,0x490c,0xc0ed,0x771b,0x1590,0x1c17,0x4855,0x977e,0x8054,0xdb98,0xb26f,0x1175,0x7722,0xfe}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1036ca5b,0x490c34a6,0x771bc0ed,0x1c171590,0x977e4855,0xdb988054,0x1175b26f,0xfe7722}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x490c34a61036ca5b,0x1c171590771bc0ed,0xdb988054977e4855,0xfe77221175b26f}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xf543,0x821c,0xae0a,0xb0cb,0x642d,0x5a80,0xd2bf,0x2340,0xc8f,0xe1ce,0x4e38,0xdace,0x3445,0x807e,0x9bc4,0x5}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x821cf543,0xb0cbae0a,0x5a80642d,0x2340d2bf,0xe1ce0c8f,0xdace4e38,0x807e3445,0x59bc4}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb0cbae0a821cf543,0x2340d2bf5a80642d,0xdace4e38e1ce0c8f,0x59bc4807e3445}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x6e85,0xc3dc,0xfd4,0x39a7,0x5158,0x777b,0xb83,0xb0fe,0x55de,0x45b3,0x103f,0x53dc,0x27e2,0xb6cb,0x2b18,0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xc3dc6e85,0x39a70fd4,0x777b5158,0xb0fe0b83,0x45b355de,0x53dc103f,0xb6cb27e2,0x12b18}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x39a70fd4c3dc6e85,0xb0fe0b83777b5158,0x53dc103f45b355de,0x12b18b6cb27e2}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x35a5,0xefc9,0xcb59,0xb6f3,0x3f12,0x88e4,0xea6f,0xe3e8,0xb7aa,0x6881,0x7fab,0x2467,0x4d90,0xee8a,0x88dd,0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xefc935a5,0xb6f3cb59,0x88e43f12,0xe3e8ea6f,0x6881b7aa,0x24677fab,0xee8a4d90,0x188dd}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb6f3cb59efc935a5,0xe3e8ea6f88e43f12,0x24677fab6881b7aa,0x188ddee8a4d90}}}}
+#endif
+}}}}, {{{
+#if 0
+#elif RADIX == 16
+{{0x102e, 0x4c4, 0x1586, 0x1184, 0xa12, 0x9ce, 0x1866, 0x433, 0x5ef, 0x82a, 0x13a5, 0xbc6, 0x591, 0x175b, 0x10bc, 0xfa5, 0x109d, 0x8d4, 0x1325, 0x9}}
+#elif RADIX == 32
+{{0x1131205d, 0x128c2561, 0xcc9ce50, 0x17bc8678, 0x9d2a0a8, 0x165915e3, 0x9617975, 0x6a4275f, 0x4992a}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xca128c2561898902, 0x50545ef219e19939, 0xc2f2eb65915e34e9, 0x4acc951a909d7d2}}
+#else
+{{0x14612b0c4c481, 0x7219e19939ca1, 0x2bc69d2a0a8bd, 0x5f4b0bcbad964, 0x25664a8d484e}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {{
+#if 0
+#elif RADIX == 16
+{{0x5a5, 0x1131, 0x561, 0x1461, 0x1284, 0x1273, 0x1e19, 0x190c, 0x117b, 0xa0a, 0x14e9, 0xaf1, 0x1964, 0x5d6, 0xc2f, 0xbe9, 0x427, 0xa35, 0xcc9, 0x3}}
+#elif RADIX == 32
+{{0xc4c4b4a, 0x4a30958, 0x3327394, 0x5ef219e, 0x1a74a82a, 0xd964578, 0x1a585e5d, 0x11a909d7, 0x3664a}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x7284a3095862625a, 0x541517bc8678664e, 0xb0bcbad964578d3a, 0x1ab32546a4275f4}}
+#else
+{{0x25184ac31312d, 0x3c8678664e728, 0xaf1a74a82a2f, 0x57d2c2f2eb659, 0xd5992a35213}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, true}, {{{
+#if 0
+#elif RADIX == 16
+{{0x1b4a, 0xf6a, 0xadd, 0x302, 0x196b, 0x366, 0x1399, 0xe83, 0x1540, 0xcd, 0x169d, 0x1007, 0xfe6, 0x1fd2, 0xebb, 0x808, 0x1725, 0x1c1e, 0x1009, 0x8}}
+#elif RADIX == 32
+{{0xbdab695, 0xb1812b7, 0x132366cb, 0x1501d073, 0x1b4e8336, 0x4fe6803, 0x21d77fd, 0xf5c950, 0x3804f}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xd96b1812b75ed5b4, 0x419b540741ce646c, 0x3aeffa4fe6803da7, 0x36402783d725404}}
+#else
+{{0x58c095baf6ada, 0x741ce646cd96, 0x5007b4e8336a8, 0x5010ebbfe93f9, 0x1b2013c1eb92}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x122a, 0x94e, 0x1927, 0x1701, 0x58e, 0x79, 0x134e, 0xecc, 0xa0f, 0x7be, 0xc39, 0xfb2, 0x1df0, 0x79a, 0x154a, 0x1a4a, 0x23f, 0x3de, 0x1be1, 0x9}}
+#elif RADIX == 32
+{{0x1a53a455, 0xeb80e49, 0x9c0792c, 0x83dd993, 0x61c9ef9, 0x15df07d9, 0x12aa9479, 0x1ef08ff4, 0x4df08}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x258eb80e49d29d22, 0x4f7ca0f7664d380f, 0x5528f35df07d930e, 0x36ef847bc23fd25}}
+#else
+{{0x75c0724e94e91, 0x77664d380f258, 0xfb261c9ef941, 0x749554a3cd77c, 0x1b77c23de11f}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x1943, 0x2e1, 0x677, 0x614, 0x19e, 0x11e6, 0xde2, 0x104d, 0x551, 0x1455, 0x1d7e, 0xdd, 0x15e0, 0x14c5, 0xeeb, 0x14b5, 0x168f, 0x1a03, 0xa9d, 0x4}}
+#elif RADIX == 32
+{{0x18b87286, 0x1e30a19d, 0x1c51e60c, 0x154609ad, 0x1ebf5154, 0xb5e006e, 0xd5dd74c, 0x101da3e9, 0x454ee}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xc19e30a19dc5c394, 0xa8aa551826b78a3c, 0xbbae98b5e006ef5f, 0x112a7740768fa5a}}
+#else
+{{0x71850cee2e1ca, 0x1826b78a3cc19, 0xddebf5154aa, 0x696aeeba62d78, 0x8953ba03b47}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x512, 0xda9, 0x31a, 0x1711, 0x1b65, 0x9f0, 0xe54, 0x1d4a, 0xe1c, 0xc90, 0x1837, 0x1728, 0x15fa, 0xa40, 0xf21, 0x1b43, 0x1716, 0x1277, 0x11a8, 0x9}}
+#elif RADIX == 32
+{{0x136a4a25, 0x5b888c6, 0xa89f0db, 0x1873a94e, 0xc1bb241, 0x15fab94, 0x10de42a4, 0x13bdc5b6, 0x48d44}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x1b65b888c69b5251, 0xd920e1cea539513e, 0xbc854815fab9460d, 0xec6a24ef716da1}}
+#else
+{{0x2dc44634da928, 0x4ea539513e1b6, 0x5728c1bb241c3, 0x3686f2152057e, 0x2f6351277b8b}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x822, 0x1a13, 0x11d, 0x10e0, 0x2b9, 0x1d20, 0x19f9, 0x1dc2, 0x1770, 0x135e, 0x1c13, 0x1cba, 0x14df, 0x5c8, 0x1f31, 0x215, 0x16ed, 0x1f7a, 0xc6c, 0x5}}
+#elif RADIX == 32
+{{0xe84d045, 0x19870047, 0x1f3d2015, 0x1dc3b859, 0xe09cd7a, 0x114dfe5d, 0x57e625c, 0x1bd5bb44, 0x6367}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x2b9870047742682, 0xe6bd770ee167e7a4, 0xfcc4b914dfe5d704, 0xcb1b3ef56ed10a}}
+#else
+{{0x4c38023ba1341, 0xee167e7a402b, 0x7cbae09cd7aee, 0x442bf312e4537, 0x658d9f7ab76}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x2cc, 0xd50, 0xeda, 0x1c3c, 0x8a6, 0x1659, 0xffb, 0x1cee, 0x1f14, 0x17fe, 0x1860, 0x427, 0x132c, 0x5c0, 0xb9f, 0x143d, 0x639, 0x19f0, 0x1551, 0x7}}
+#elif RADIX == 32
+{{0x13540599, 0x6e1e3b6, 0x1f765945, 0x1c539dcf, 0x1c305ffb, 0x132c213, 0xf573e5c, 0xf818e68, 0x2aa8e}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x28a6e1e3b69aa02c, 0x2ffdf14e773feecb, 0xae7cb8132c213e18, 0x3fd5473e0639a1e}}
+#else
+{{0x370f1db4d5016, 0x4e773feecb28a, 0x427c305ffbe2, 0x687ab9f2e04cb, 0x1feaa39f031c}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x900d,0xd052,0xb453,0x206a,0xe61d,0x31f2,0xc579,0xfb21,0xc870,0x2bb,0xf38f,0xf9c1,0x83aa,0x47f1,0x58d1,0xeb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd052900d,0x206ab453,0x31f2e61d,0xfb21c579,0x2bbc870,0xf9c1f38f,0x47f183aa,0xeb58d1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x206ab453d052900d,0xfb21c57931f2e61d,0xf9c1f38f02bbc870,0xeb58d147f183aa}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x727e,0xa5e8,0xebc3,0x9e04,0xf1eb,0x38d7,0x68e0,0x8ea9,0x8f77,0x8331,0x48eb,0x82c0,0xb0a3,0x3583,0xf221,0x54}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xa5e8727e,0x9e04ebc3,0x38d7f1eb,0x8ea968e0,0x83318f77,0x82c048eb,0x3583b0a3,0x54f221}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x9e04ebc3a5e8727e,0x8ea968e038d7f1eb,0x82c048eb83318f77,0x54f2213583b0a3}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xdba9,0x49e4,0xc9b3,0x34e9,0x7ab9,0xd876,0xcae0,0xcfb0,0x6177,0x26b3,0x2c98,0x1e30,0x4a38,0x53cc,0x3bdc,0x71}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x49e4dba9,0x34e9c9b3,0xd8767ab9,0xcfb0cae0,0x26b36177,0x1e302c98,0x53cc4a38,0x713bdc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x34e9c9b349e4dba9,0xcfb0cae0d8767ab9,0x1e302c9826b36177,0x713bdc53cc4a38}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x6ff3,0x2fad,0x4bac,0xdf95,0x19e2,0xce0d,0x3a86,0x4de,0x378f,0xfd44,0xc70,0x63e,0x7c55,0xb80e,0xa72e,0x14}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x2fad6ff3,0xdf954bac,0xce0d19e2,0x4de3a86,0xfd44378f,0x63e0c70,0xb80e7c55,0x14a72e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xdf954bac2fad6ff3,0x4de3a86ce0d19e2,0x63e0c70fd44378f,0x14a72eb80e7c55}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x231b,0x1af2,0x1640,0xb19c,0xf713,0xe470,0x683e,0xf39a,0x3289,0x7a54,0xc26e,0x904e,0xd5a6,0x6a0c,0x55fc,0x44}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1af2231b,0xb19c1640,0xe470f713,0xf39a683e,0x7a543289,0x904ec26e,0x6a0cd5a6,0x4455fc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb19c16401af2231b,0xf39a683ee470f713,0x904ec26e7a543289,0x4455fc6a0cd5a6}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xad7a,0xb685,0xde69,0x55d2,0x5675,0x84e8,0x5916,0x925f,0x8c0a,0x1cb6,0x7c51,0x8391,0xffce,0x11d1,0x96ce,0xcd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb685ad7a,0x55d2de69,0x84e85675,0x925f5916,0x1cb68c0a,0x83917c51,0x11d1ffce,0xcd96ce}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x55d2de69b685ad7a,0x925f591684e85675,0x83917c511cb68c0a,0xcd96ce11d1ffce}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x3724,0x79bd,0x1b92,0x959b,0xb3ec,0x6f18,0x27d4,0x64a7,0x9b4b,0x8c7e,0xade7,0x664b,0xa6d9,0xa287,0x6a1d,0x48}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x79bd3724,0x959b1b92,0x6f18b3ec,0x64a727d4,0x8c7e9b4b,0x664bade7,0xa287a6d9,0x486a1d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x959b1b9279bd3724,0x64a727d46f18b3ec,0x664bade78c7e9b4b,0x486a1da287a6d9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xdce5,0xe50d,0xe9bf,0x4e63,0x8ec,0x1b8f,0x97c1,0xc65,0xcd76,0x85ab,0x3d91,0x6fb1,0x2a59,0x95f3,0xaa03,0xbb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe50ddce5,0x4e63e9bf,0x1b8f08ec,0xc6597c1,0x85abcd76,0x6fb13d91,0x95f32a59,0xbbaa03}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4e63e9bfe50ddce5,0xc6597c11b8f08ec,0x6fb13d9185abcd76,0xbbaa0395f32a59}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x2417,0x1b00,0xcfe,0x8960,0x662e,0x42d2,0xc00f,0x222c,0x7671,0x278b,0x863f,0xbcac,0xdb9c,0x6e5e,0x4c5a,0x1b}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1b002417,0x89600cfe,0x42d2662e,0x222cc00f,0x278b7671,0xbcac863f,0x6e5edb9c,0x1b4c5a}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x89600cfe1b002417,0x222cc00f42d2662e,0xbcac863f278b7671,0x1b4c5a6e5edb9c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x21e8,0xd92b,0x5a2d,0xef86,0xf492,0x1483,0x8ae0,0x6b37,0x7f78,0x7b90,0x69c5,0xf4ec,0x2fb9,0x1660,0x8296,0xf8}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd92b21e8,0xef865a2d,0x1483f492,0x6b378ae0,0x7b907f78,0xf4ec69c5,0x16602fb9,0xf88296}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xef865a2dd92b21e8,0x6b378ae01483f492,0xf4ec69c57b907f78,0xf8829616602fb9}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x38ff,0x5dc5,0x9aea,0xbc0e,0xbea5,0x775d,0x447b,0xc311,0xf01c,0xb63a,0x15fd,0x162a,0xab76,0x9def,0x2a0d,0xc5}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x5dc538ff,0xbc0e9aea,0x775dbea5,0xc311447b,0xb63af01c,0x162a15fd,0x9defab76,0xc52a0d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xbc0e9aea5dc538ff,0xc311447b775dbea5,0x162a15fdb63af01c,0xc52a0d9defab76}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xdbe9,0xe4ff,0xf301,0x769f,0x99d1,0xbd2d,0x3ff0,0xddd3,0x898e,0xd874,0x79c0,0x4353,0x2463,0x91a1,0xb3a5,0xe4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe4ffdbe9,0x769ff301,0xbd2d99d1,0xddd33ff0,0xd874898e,0x435379c0,0x91a12463,0xe4b3a5}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x769ff301e4ffdbe9,0xddd33ff0bd2d99d1,0x435379c0d874898e,0xe4b3a591a12463}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x900d,0xd052,0xb453,0x206a,0xe61d,0x31f2,0xc579,0xfb21,0xc870,0x2bb,0xf38f,0xf9c1,0x83aa,0x47f1,0x58d1,0xeb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd052900d,0x206ab453,0x31f2e61d,0xfb21c579,0x2bbc870,0xf9c1f38f,0x47f183aa,0xeb58d1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x206ab453d052900d,0xfb21c57931f2e61d,0xf9c1f38f02bbc870,0xeb58d147f183aa}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x727e,0xa5e8,0xebc3,0x9e04,0xf1eb,0x38d7,0x68e0,0x8ea9,0x8f77,0x8331,0x48eb,0x82c0,0xb0a3,0x3583,0xf221,0x54}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xa5e8727e,0x9e04ebc3,0x38d7f1eb,0x8ea968e0,0x83318f77,0x82c048eb,0x3583b0a3,0x54f221}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x9e04ebc3a5e8727e,0x8ea968e038d7f1eb,0x82c048eb83318f77,0x54f2213583b0a3}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xdba9,0x49e4,0xc9b3,0x34e9,0x7ab9,0xd876,0xcae0,0xcfb0,0x6177,0x26b3,0x2c98,0x1e30,0x4a38,0x53cc,0x3bdc,0x71}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x49e4dba9,0x34e9c9b3,0xd8767ab9,0xcfb0cae0,0x26b36177,0x1e302c98,0x53cc4a38,0x713bdc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x34e9c9b349e4dba9,0xcfb0cae0d8767ab9,0x1e302c9826b36177,0x713bdc53cc4a38}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x6ff3,0x2fad,0x4bac,0xdf95,0x19e2,0xce0d,0x3a86,0x4de,0x378f,0xfd44,0xc70,0x63e,0x7c55,0xb80e,0xa72e,0x14}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x2fad6ff3,0xdf954bac,0xce0d19e2,0x4de3a86,0xfd44378f,0x63e0c70,0xb80e7c55,0x14a72e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xdf954bac2fad6ff3,0x4de3a86ce0d19e2,0x63e0c70fd44378f,0x14a72eb80e7c55}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x118e,0xd79,0xb20,0xd8ce,0x7b89,0x7238,0x341f,0xf9cd,0x1944,0x3d2a,0x6137,0x4827,0x6ad3,0x3506,0x2afe,0x22}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd79118e,0xd8ce0b20,0x72387b89,0xf9cd341f,0x3d2a1944,0x48276137,0x35066ad3,0x222afe}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xd8ce0b200d79118e,0xf9cd341f72387b89,0x482761373d2a1944,0x222afe35066ad3}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xd6bd,0xdb42,0x6f34,0xaae9,0x2b3a,0x4274,0xac8b,0x492f,0x4605,0x8e5b,0xbe28,0x41c8,0xffe7,0x8e8,0xcb67,0x66}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xdb42d6bd,0xaae96f34,0x42742b3a,0x492fac8b,0x8e5b4605,0x41c8be28,0x8e8ffe7,0x66cb67}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xaae96f34db42d6bd,0x492fac8b42742b3a,0x41c8be288e5b4605,0x66cb6708e8ffe7}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x9b92,0x3cde,0x8dc9,0x4acd,0x59f6,0x378c,0x93ea,0xb253,0x4da5,0xc63f,0xd6f3,0xb325,0xd36c,0xd143,0x350e,0x24}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x3cde9b92,0x4acd8dc9,0x378c59f6,0xb25393ea,0xc63f4da5,0xb325d6f3,0xd143d36c,0x24350e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4acd8dc93cde9b92,0xb25393ea378c59f6,0xb325d6f3c63f4da5,0x24350ed143d36c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xee73,0xf286,0xf4df,0x2731,0x8476,0x8dc7,0xcbe0,0x632,0xe6bb,0xc2d5,0x9ec8,0xb7d8,0x952c,0xcaf9,0xd501,0xdd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf286ee73,0x2731f4df,0x8dc78476,0x632cbe0,0xc2d5e6bb,0xb7d89ec8,0xcaf9952c,0xddd501}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x2731f4dff286ee73,0x632cbe08dc78476,0xb7d89ec8c2d5e6bb,0xddd501caf9952c}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x20f0,0x2693,0xacbf,0x731a,0xb0f3,0xd8ce,0x1bcd,0xf836,0x8469,0x44d5,0xd604,0xd3aa,0x4aa8,0xcdc3,0x9086,0x3f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x269320f0,0x731aacbf,0xd8ceb0f3,0xf8361bcd,0x44d58469,0xd3aad604,0xcdc34aa8,0x3f9086}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x731aacbf269320f0,0xf8361bcdd8ceb0f3,0xd3aad60444d58469,0x3f9086cdc34aa8}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xcc11,0xe55a,0x932f,0x9534,0x2895,0xaf43,0x2956,0x614f,0x4e84,0xe4b2,0x60c6,0x255,0xbb14,0xd70d,0xc61e,0x13}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe55acc11,0x9534932f,0xaf432895,0x614f2956,0xe4b24e84,0x25560c6,0xd70dbb14,0x13c61e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x9534932fe55acc11,0x614f2956af432895,0x25560c6e4b24e84,0x13c61ed70dbb14}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x28d6,0x450d,0xd24f,0x54e4,0x6e67,0x81d,0x9b71,0xadbe,0x1088,0x6148,0x4ebf,0x4b68,0x829e,0x65c8,0xe1a6,0xe5}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x450d28d6,0x54e4d24f,0x81d6e67,0xadbe9b71,0x61481088,0x4b684ebf,0x65c8829e,0xe5e1a6}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x54e4d24f450d28d6,0xadbe9b71081d6e67,0x4b684ebf61481088,0xe5e1a665c8829e}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xdf10,0xd96c,0x5340,0x8ce5,0x4f0c,0x2731,0xe432,0x7c9,0x7b96,0xbb2a,0x29fb,0x2c55,0xb557,0x323c,0x6f79,0xc0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd96cdf10,0x8ce55340,0x27314f0c,0x7c9e432,0xbb2a7b96,0x2c5529fb,0x323cb557,0xc06f79}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x8ce55340d96cdf10,0x7c9e43227314f0c,0x2c5529fbbb2a7b96,0xc06f79323cb557}}}}
+#endif
+}}}}, {{{
+#if 0
+#elif RADIX == 16
+{{0x6b9, 0xd4c, 0x1d8d, 0x1f99, 0x1be4, 0x1f53, 0x5c1, 0x1937, 0x9c, 0xe68, 0x61e, 0x14e8, 0x352, 0x3d6, 0x174, 0x133, 0x18a6, 0x1b19, 0x94b, 0x9}}
+#elif RADIX == 32
+{{0xb530d73, 0x4fccf63, 0x183f53df, 0x27326e5, 0x30f39a0, 0xc352a74, 0xcc2e83d, 0x18ce2982, 0x44a5e}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x7be4fccf635a986b, 0x9cd009cc9b9707ea, 0x85d07ac352a74187, 0x31a52f6338a6099}}
+#else
+{{0x27e67b1ad4c35, 0x4c9b9707ea7be, 0x54e830f39a013, 0x2661741eb0d4, 0x40d297b19c53}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {{
+#if 0
+#elif RADIX == 16
+{{0x348, 0xb53, 0xf63, 0x7e6, 0x1ef9, 0xfd4, 0x1970, 0x64d, 0x27, 0x139a, 0x187, 0x153a, 0x10d4, 0xf5, 0x185d, 0x104c, 0xe29, 0x1ec6, 0x1a52, 0x0}}
+#elif RADIX == 32
+{{0x1ad4c690, 0x193f33d8, 0xe0fd4f7, 0x9cc9b9, 0xc3ce68, 0xb0d4a9d, 0x1330ba0f, 0x16338a60, 0xd297}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x9ef93f33d8d6a634, 0xe734027326e5c1fa, 0x61741eb0d4a9d061, 0x28694bd8ce29826}}
+#else
+{{0x49f99ec6b531a, 0x7326e5c1fa9ef, 0x153a0c3ce6804, 0x609985d07ac35, 0x1434a5ec6714}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, true}, {{{
+#if 0
+#elif RADIX == 16
+{{0x18af, 0xb6e, 0x124d, 0xa49, 0xa8c, 0x11f5, 0xea9, 0x298, 0xa55, 0x1738, 0xb61, 0x2b9, 0x8a, 0x167a, 0x17e6, 0x2b0, 0x1290, 0x16ad, 0x1505, 0x2}}
+#elif RADIX == 32
+{{0xadbb15e, 0xc524c93, 0x1531f554, 0x954530e, 0x15b0dce1, 0x1408a15c, 0xc2fcd67, 0x156ca405, 0x2a82d}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xaa8c524c9356dd8a, 0x6e70a5514c3aa63e, 0x5f9acf408a15cad8, 0x4c5416d5b290158}}
+#else
+{{0x6292649ab6ec5, 0x514c3aa63eaa8, 0x42b95b0dce14a, 0x5617e6b3d022, 0x262a0b6ad948}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x1390, 0x1895, 0x9b7, 0xa5a, 0x1030, 0x16c1, 0xd21, 0x1053, 0x327, 0x1a4c, 0x1a22, 0x11e4, 0x16ba, 0x13a1, 0x1dbc, 0x1aac, 0x148c, 0x5c8, 0x15d2, 0x0}}
+#elif RADIX == 32
+{{0x1e256720, 0x1052d26d, 0x436c181, 0xc9e0a6d, 0xd116930, 0x36ba8f2, 0xb3b793a, 0xe452335, 0xae91}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x303052d26df12b39, 0xb498327829b486d8, 0x76f27436ba8f2688, 0x5748b9148cd56}}
+#else
+{{0x296936f8959c, 0x7829b486d8303, 0x51e4d11693064, 0x3559dbc9d0dae, 0x282ba45c8a46}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x1be6, 0x11b3, 0x14ba, 0xf43, 0x1bd1, 0x215, 0x1e9a, 0x137a, 0x7b2, 0x15, 0x126, 0x148, 0x1c2b, 0x1b70, 0xf1c, 0x1e48, 0x1259, 0x188a, 0x1e44, 0x7}}
+#elif RADIX == 32
+{{0x146cf7cd, 0x117a1d2e, 0x134215de, 0x1eca6f5e, 0x930054, 0x1c2b0a4, 0x121e39b7, 0x454967c, 0x2f226}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xbbd17a1d2ea367be, 0x802a7b29bd7a6842, 0x3c736e1c2b0a4049, 0x21f913115259f24}}
+#else
+{{0xbd0e9751b3df, 0x29bd7a6842bbd, 0x61480930054f6, 0x7c90f1cdb870a, 0x10fc8988a92c}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x4c5, 0x37e, 0xafa, 0x1b90, 0x13d, 0x8d3, 0xaa7, 0x489, 0x1d4a, 0x17bc, 0x168, 0x37f, 0x1ed6, 0x666, 0x1889, 0x1a4e, 0xa57, 0xeb7, 0xd37, 0x7}}
+#elif RADIX == 32
+{{0x10df898b, 0x1ddc82be, 0x14e8d309, 0x1528912a, 0x10b45ef3, 0xded61bf, 0x13b11266, 0x15ba95f4, 0x269bb}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x613ddc82be86fc4c, 0x2f79d4a244aa9d1a, 0x6224ccded61bf85a, 0x1cb4ddd6ea57d27}}
+#else
+{{0x6ee415f437e26, 0x2244aa9d1a613, 0x437f0b45ef3a9, 0x749d8893337b5, 0xe5a6eeb752b}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x447, 0x1b87, 0x1cf0, 0x155, 0xb1, 0x804, 0x97a, 0x64a, 0x886, 0x3a3, 0x126f, 0x1553, 0x74d, 0xde9, 0x941, 0x39c, 0x8f, 0x1bbb, 0xf3, 0x1}}
+#elif RADIX == 32
+{{0x6e1c88e, 0x110aaf3c, 0xf480405, 0x218c949, 0x19378e8d, 0x1274daa9, 0x71282de, 0x1dd823c7, 0x1079e}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x80b10aaf3c370e44, 0xc74688632525e900, 0x2505bd274daa9c9b, 0x2383cf77608f1ce}}
+#else
+{{0x85579e1b8722, 0x632525e90080b, 0x35539378e8d10, 0x47389416f49d3, 0x11c1e7bbb047}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0xf9d, 0x552, 0x797, 0x19fc, 0x166, 0x7a8, 0x1ee5, 0xc77, 0x1ee7, 0x15ef, 0x340, 0x10df, 0x1d5f, 0x170, 0xf2, 0x123, 0x1bb1, 0xd23, 0x3fc, 0x6}}
+#elif RADIX == 32
+{{0x19549f3b, 0x6cfe1e5, 0x1ca7a80b, 0x1b9d8efe, 0x11a057bf, 0x1d5f86f, 0x8c1e417, 0x91eec42, 0x11fe3}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x166cfe1e5caa4f9, 0x2bdfee763bfb94f5, 0x83c82e1d5f86f8d0, 0x440ff1a47bb1091}}
+#else
+{{0x367f0f2e5527c, 0x763bfb94f5016, 0x70df1a057bfdc, 0x42460f20b8757, 0x4a07f8d23dd8}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x27cb,0x4931,0x13e0,0xcd75,0x6846,0x3de7,0x5a91,0x9ff9,0xa270,0xa6d6,0x26ec,0xb972,0xb44,0xe4b8,0x52fc,0x3f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x493127cb,0xcd7513e0,0x3de76846,0x9ff95a91,0xa6d6a270,0xb97226ec,0xe4b80b44,0x3f52fc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xcd7513e0493127cb,0x9ff95a913de76846,0xb97226eca6d6a270,0x3f52fce4b80b44}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x2d7e,0x5a38,0xca74,0x1d16,0x2547,0x1674,0x8c29,0xafc2,0x2349,0x4856,0x2c73,0x7957,0x67e1,0x3c3e,0x4d3,0xad}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x5a382d7e,0x1d16ca74,0x16742547,0xafc28c29,0x48562349,0x79572c73,0x3c3e67e1,0xad04d3}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x1d16ca745a382d7e,0xafc28c2916742547,0x79572c7348562349,0xad04d33c3e67e1}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xd8d7,0x27fb,0x321e,0xcf15,0xfbd3,0x6f8e,0x5fbd,0x7ed7,0xf394,0x58d6,0x5937,0xb73c,0xbfb,0xe027,0x64ac,0x22}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x27fbd8d7,0xcf15321e,0x6f8efbd3,0x7ed75fbd,0x58d6f394,0xb73c5937,0xe0270bfb,0x2264ac}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xcf15321e27fbd8d7,0x7ed75fbd6f8efbd3,0xb73c593758d6f394,0x2264ace0270bfb}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xd835,0xb6ce,0xec1f,0x328a,0x97b9,0xc218,0xa56e,0x6006,0x5d8f,0x5929,0xd913,0x468d,0xf4bb,0x1b47,0xad03,0xc0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb6ced835,0x328aec1f,0xc21897b9,0x6006a56e,0x59295d8f,0x468dd913,0x1b47f4bb,0xc0ad03}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x328aec1fb6ced835,0x6006a56ec21897b9,0x468dd91359295d8f,0xc0ad031b47f4bb}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xdce5,0xe50d,0xe9bf,0x4e63,0x8ec,0x1b8f,0x97c1,0xc65,0xcd76,0x85ab,0x3d91,0x6fb1,0x2a59,0x95f3,0xaa03,0xbb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe50ddce5,0x4e63e9bf,0x1b8f08ec,0xc6597c1,0x85abcd76,0x6fb13d91,0x95f32a59,0xbbaa03}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4e63e9bfe50ddce5,0xc6597c11b8f08ec,0x6fb13d9185abcd76,0xbbaa0395f32a59}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x5286,0x497a,0x2196,0xaa2d,0xa98a,0x7b17,0xa6e9,0x6da0,0x73f5,0xe349,0x83ae,0x7c6e,0x31,0xee2e,0x6931,0x32}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x497a5286,0xaa2d2196,0x7b17a98a,0x6da0a6e9,0xe34973f5,0x7c6e83ae,0xee2e0031,0x326931}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xaa2d2196497a5286,0x6da0a6e97b17a98a,0x7c6e83aee34973f5,0x326931ee2e0031}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xc8dc,0x8642,0xe46d,0x6a64,0x4c13,0x90e7,0xd82b,0x9b58,0x64b4,0x7381,0x5218,0x99b4,0x5926,0x5d78,0x95e2,0xb7}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x8642c8dc,0x6a64e46d,0x90e74c13,0x9b58d82b,0x738164b4,0x99b45218,0x5d785926,0xb795e2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x6a64e46d8642c8dc,0x9b58d82b90e74c13,0x99b45218738164b4,0xb795e25d785926}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x231b,0x1af2,0x1640,0xb19c,0xf713,0xe470,0x683e,0xf39a,0x3289,0x7a54,0xc26e,0x904e,0xd5a6,0x6a0c,0x55fc,0x44}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1af2231b,0xb19c1640,0xe470f713,0xf39a683e,0x7a543289,0x904ec26e,0x6a0cd5a6,0x4455fc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb19c16401af2231b,0xf39a683ee470f713,0x904ec26e7a543289,0x4455fc6a0cd5a6}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x94df,0x6dc7,0xcd7f,0xebb2,0xb290,0x811d,0x2825,0xc88,0xd514,0x959a,0x7d64,0xc8c3,0x16a9,0x106a,0x1eea,0x32}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x6dc794df,0xebb2cd7f,0x811db290,0xc882825,0x959ad514,0xc8c37d64,0x106a16a9,0x321eea}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xebb2cd7f6dc794df,0xc882825811db290,0xc8c37d64959ad514,0x321eea106a16a9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xe08c,0xe778,0x1464,0x19fe,0xef25,0x1d24,0xa98f,0x4af0,0x70d3,0x8e4d,0x2b82,0x95ea,0x3277,0xc267,0x1695,0xf}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe778e08c,0x19fe1464,0x1d24ef25,0x4af0a98f,0x8e4d70d3,0x95ea2b82,0xc2673277,0xf1695}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x19fe1464e778e08c,0x4af0a98f1d24ef25,0x95ea2b828e4d70d3,0xf1695c2673277}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xf1df,0xb6e1,0xe2a4,0x4bc9,0xdc85,0x6365,0x3fca,0x9a38,0xee2,0xed03,0xca7f,0x1984,0xe709,0x1efe,0xc173,0x8b}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb6e1f1df,0x4bc9e2a4,0x6365dc85,0x9a383fca,0xed030ee2,0x1984ca7f,0x1efee709,0x8bc173}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4bc9e2a4b6e1f1df,0x9a383fca6365dc85,0x1984ca7fed030ee2,0x8bc1731efee709}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x6b21,0x9238,0x3280,0x144d,0x4d6f,0x7ee2,0xd7da,0xf377,0x2aeb,0x6a65,0x829b,0x373c,0xe956,0xef95,0xe115,0xcd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x92386b21,0x144d3280,0x7ee24d6f,0xf377d7da,0x6a652aeb,0x373c829b,0xef95e956,0xcde115}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x144d328092386b21,0xf377d7da7ee24d6f,0x373c829b6a652aeb,0xcde115ef95e956}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x27cb,0x4931,0x13e0,0xcd75,0x6846,0x3de7,0x5a91,0x9ff9,0xa270,0xa6d6,0x26ec,0xb972,0xb44,0xe4b8,0x52fc,0x3f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x493127cb,0xcd7513e0,0x3de76846,0x9ff95a91,0xa6d6a270,0xb97226ec,0xe4b80b44,0x3f52fc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xcd7513e0493127cb,0x9ff95a913de76846,0xb97226eca6d6a270,0x3f52fce4b80b44}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x2d7e,0x5a38,0xca74,0x1d16,0x2547,0x1674,0x8c29,0xafc2,0x2349,0x4856,0x2c73,0x7957,0x67e1,0x3c3e,0x4d3,0xad}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x5a382d7e,0x1d16ca74,0x16742547,0xafc28c29,0x48562349,0x79572c73,0x3c3e67e1,0xad04d3}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x1d16ca745a382d7e,0xafc28c2916742547,0x79572c7348562349,0xad04d33c3e67e1}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xd8d7,0x27fb,0x321e,0xcf15,0xfbd3,0x6f8e,0x5fbd,0x7ed7,0xf394,0x58d6,0x5937,0xb73c,0xbfb,0xe027,0x64ac,0x22}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x27fbd8d7,0xcf15321e,0x6f8efbd3,0x7ed75fbd,0x58d6f394,0xb73c5937,0xe0270bfb,0x2264ac}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xcf15321e27fbd8d7,0x7ed75fbd6f8efbd3,0xb73c593758d6f394,0x2264ace0270bfb}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xd835,0xb6ce,0xec1f,0x328a,0x97b9,0xc218,0xa56e,0x6006,0x5d8f,0x5929,0xd913,0x468d,0xf4bb,0x1b47,0xad03,0xc0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb6ced835,0x328aec1f,0xc21897b9,0x6006a56e,0x59295d8f,0x468dd913,0x1b47f4bb,0xc0ad03}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x328aec1fb6ced835,0x6006a56ec21897b9,0x468dd91359295d8f,0xc0ad031b47f4bb}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xee73,0xf286,0xf4df,0x2731,0x8476,0x8dc7,0xcbe0,0x632,0xe6bb,0xc2d5,0x9ec8,0xb7d8,0x952c,0xcaf9,0xd501,0xdd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf286ee73,0x2731f4df,0x8dc78476,0x632cbe0,0xc2d5e6bb,0xb7d89ec8,0xcaf9952c,0xddd501}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x2731f4dff286ee73,0x632cbe08dc78476,0xb7d89ec8c2d5e6bb,0xddd501caf9952c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x2943,0x24bd,0x90cb,0x5516,0xd4c5,0xbd8b,0x5374,0xb6d0,0xb9fa,0x71a4,0x41d7,0xbe37,0x18,0xf717,0x3498,0x99}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x24bd2943,0x551690cb,0xbd8bd4c5,0xb6d05374,0x71a4b9fa,0xbe3741d7,0xf7170018,0x993498}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x551690cb24bd2943,0xb6d05374bd8bd4c5,0xbe3741d771a4b9fa,0x993498f7170018}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x646e,0xc321,0x7236,0xb532,0xa609,0xc873,0x6c15,0x4dac,0xb25a,0x39c0,0x290c,0x4cda,0x2c93,0x2ebc,0xcaf1,0xdb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xc321646e,0xb5327236,0xc873a609,0x4dac6c15,0x39c0b25a,0x4cda290c,0x2ebc2c93,0xdbcaf1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb5327236c321646e,0x4dac6c15c873a609,0x4cda290c39c0b25a,0xdbcaf12ebc2c93}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x118e,0xd79,0xb20,0xd8ce,0x7b89,0x7238,0x341f,0xf9cd,0x1944,0x3d2a,0x6137,0x4827,0x6ad3,0x3506,0x2afe,0x22}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd79118e,0xd8ce0b20,0x72387b89,0xf9cd341f,0x3d2a1944,0x48276137,0x35066ad3,0x222afe}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xd8ce0b200d79118e,0xf9cd341f72387b89,0x482761373d2a1944,0x222afe35066ad3}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xd647,0xf187,0x9a31,0x1ee,0x193b,0xeec2,0xbfed,0x9418,0x15b6,0xe9a,0x4c74,0xae85,0x3ebe,0x2677,0x3f12,0x42}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf187d647,0x1ee9a31,0xeec2193b,0x9418bfed,0xe9a15b6,0xae854c74,0x26773ebe,0x423f12}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x1ee9a31f187d647,0x9418bfedeec2193b,0xae854c740e9a15b6,0x423f1226773ebe}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x68ff,0x99be,0x416c,0x7bbf,0xd44f,0x609f,0x7682,0xa8ff,0xa6bb,0xec03,0x8e77,0xc076,0x7873,0x9676,0xa152,0xf5}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x99be68ff,0x7bbf416c,0x609fd44f,0xa8ff7682,0xec03a6bb,0xc0768e77,0x96767873,0xf5a152}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7bbf416c99be68ff,0xa8ff7682609fd44f,0xc0768e77ec03a6bb,0xf5a15296767873}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x3739,0xf7da,0xbd23,0xa38e,0x8cf9,0x7690,0x6b0e,0x1a7,0x77f0,0xa2bd,0x5ac7,0x5101,0x3aae,0xa922,0x2d3a,0x95}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf7da3739,0xa38ebd23,0x76908cf9,0x1a76b0e,0xa2bd77f0,0x51015ac7,0xa9223aae,0x952d3a}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xa38ebd23f7da3739,0x1a76b0e76908cf9,0x51015ac7a2bd77f0,0x952d3aa9223aae}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x29b9,0xe78,0x65ce,0xfe11,0xe6c4,0x113d,0x4012,0x6be7,0xea49,0xf165,0xb38b,0x517a,0xc141,0xd988,0xc0ed,0xbd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe7829b9,0xfe1165ce,0x113de6c4,0x6be74012,0xf165ea49,0x517ab38b,0xd988c141,0xbdc0ed}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xfe1165ce0e7829b9,0x6be74012113de6c4,0x517ab38bf165ea49,0xbdc0edd988c141}}}}
+#endif
+}}}}, {{{
+#if 0
+#elif RADIX == 16
+{{0x1068, 0xf2c, 0x1ada, 0x1f58, 0x1343, 0x5cc, 0x90, 0x1bba, 0x50b, 0x1a35, 0x35f, 0x1388, 0x5ce, 0xc4f, 0x1462, 0x191f, 0x665, 0x843, 0x1cb1, 0x1}}
+#elif RADIX == 32
+{{0x13cb20d0, 0x3fac6b6, 0x1205cc9a, 0x142f7740, 0x1afe8d4, 0x1e5ce9c4, 0x7e8c4c4, 0x2199972, 0x1e58a}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x9343fac6b69e5906, 0xf46a50bddd0240b9, 0xd18989e5ce9c40d7, 0x28f2c5086665c8f}}
+#else
+{{0x1fd635b4f2c83, 0x3ddd0240b9934, 0x53881afe8d4a1, 0x723f462627973, 0x147962843332}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {{
+#if 0
+#elif RADIX == 16
+{{0x5b3, 0x13cb, 0x6b6, 0x1fd6, 0x4d0, 0x173, 0x1024, 0x1eee, 0x942, 0x1e8d, 0xd7, 0x14e2, 0x1973, 0x1313, 0x1d18, 0xe47, 0x1999, 0xa10, 0xf2c, 0x6}}
+#elif RADIX == 32
+{{0x14f2cb67, 0x10feb1ad, 0x4817326, 0x50bddd0, 0x6bfa35, 0x7973a71, 0x11fa3131, 0x1086665c, 0x17962}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x64d0feb1ada7965b, 0xfd1a942f7740902e, 0xf462627973a71035, 0x123cb1421999723}}
+#else
+{{0x7f58d6d3cb2d, 0x2f7740902e64d, 0x74e206bfa3528, 0x5c8fd18989e5c, 0x311e58a10ccc}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, true}, {{{
+#if 0
+#elif RADIX == 16
+{{0x14ba, 0xa50, 0x219, 0x1ca8, 0x1858, 0xe67, 0x1b19, 0xb09, 0x17fa, 0x89f, 0x10d7, 0x1a55, 0x14de, 0x1f37, 0x12f0, 0x1247, 0x1aa6, 0x109f, 0x493, 0x6}}
+#elif RADIX == 32
+{{0xa942975, 0x18e54086, 0x32e67c2, 0x1fe9613b, 0x186ba27e, 0xf4ded2a, 0x11e5e1f3, 0x4fea9a4, 0x1249c}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xf858e5408654a14b, 0xd13f7fa584ec65cc, 0xcbc3e6f4ded2ac35, 0x35124e13faa6923}}
+#else
+{{0x472a0432a50a5, 0x2584ec65ccf85, 0x5a5586ba27eff, 0x248f2f0f9bd37, 0x42892709fd53}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x1ba, 0xab8, 0x1ded, 0xdc9, 0xf40, 0xaa3, 0x169, 0x53c, 0x2, 0x848, 0x9a6, 0xbad, 0xb7e, 0x15dc, 0x87, 0x1cf3, 0x1791, 0x1af2, 0x1cdf, 0x7}}
+#elif RADIX == 32
+{{0xaae0375, 0x6e4f7b, 0xd2aa37a, 0x8a781, 0x14d32120, 0x18b7e5d6, 0x1cc10f5d, 0x1795e479, 0x2e6fe}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x6f406e4f7b55701b, 0x909000229e05a554, 0x821ebb8b7e5d6a69, 0x35f37f5e5791e79}}
+#else
+{{0x3727bdaab80d, 0x229e05a5546f4, 0x4bad4d3212000, 0x79e6087aee2df, 0x42f9bfaf2bc8}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x5b, 0xad0, 0x69, 0x1038, 0x18d2, 0x180d, 0x1871, 0x46b, 0x26b, 0x1ef2, 0xe46, 0x72d, 0xc0d, 0x15a4, 0x6d7, 0x221, 0x1611, 0x1a89, 0xd3f, 0x8}}
+#elif RADIX == 32
+{{0xab400b7, 0x1281c01a, 0xe380dc6, 0x9ac8d78, 0x17237bc8, 0x8c0d396, 0x84daf5a, 0x144d8444, 0x369fe}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xb8d281c01a55a005, 0xbde426b235e1c701, 0x9b5eb48c0d396b91, 0x3b34ff513611110}}
+#else
+{{0x140e00d2ad002, 0x3235e1c701b8d, 0x272d7237bc84d, 0x44426d7ad2303, 0x459a7fa89b08}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x1131, 0xac7, 0xa16, 0x918, 0x5d8, 0x1e64, 0x3e5, 0x142c, 0x1f89, 0x1cb7, 0xf96, 0x370, 0x4da, 0xf45, 0x1aa5, 0x1872, 0x1fc, 0xd83, 0x1145, 0x6}}
+#elif RADIX == 32
+{{0x12b1e263, 0x1848c285, 0x1cbe642e, 0x1e268583, 0x7cb72df, 0xa4da1b8, 0x1cb54af4, 0xc187f30, 0x18a2b}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x85d848c285958f13, 0xb96ff89a160f97cc, 0x6a95e8a4da1b83e5, 0x84515b061fcc39}}
+#else
+{{0x4246142cac789, 0x1a160f97cc85d, 0x43707cb72dff1, 0x30e5aa57a2936, 0x2c228ad830fe}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}, {{
+#if 0
+#elif RADIX == 16
+{{0x7a4, 0x388, 0xd00, 0x66c, 0x1a9a, 0xabc, 0x97b, 0xadc, 0xaab, 0x1601, 0x287, 0xb2a, 0x1ab7, 0x1803, 0x1d06, 0x81c, 0x890, 0x11e0, 0x1e19, 0x0}}
+#elif RADIX == 32
+{{0xe20f48, 0x1a336340, 0xf6abcd4, 0xaad5b89, 0x143d805, 0x7ab7595, 0x73a0d80, 0xf022410, 0xf0cc}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x9a9a33634007107a, 0xec02aab56e25ed57, 0x741b007ab75950a1, 0x1478663c089040e}}
+#else
+{{0x519b1a003883d, 0x356e25ed579a9, 0x6b2a143d80555, 0x1039d06c01ead, 0xa3c331e0448}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x1e68, 0xcde, 0x29, 0x1777, 0x1ef8, 0x1a1c, 0x204, 0x148, 0x14ba, 0x1c39, 0x175, 0x1263, 0x4de, 0x1032, 0x1649, 0x5a4, 0xad, 0xcfb, 0x870, 0x3}}
+#elif RADIX == 32
+{{0xb37bcd0, 0x18bbb80a, 0x9a1cf7, 0x12e82902, 0x10baf0e6, 0x44de931, 0x92c9303, 0x7d82b4b, 0x34383}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x9ef8bbb80a59bde6, 0x78734ba0a4081343, 0x59260644de93185d, 0x29a1c19f60ad2d2}}
+#else
+{{0x45ddc052cdef3, 0x20a40813439ef, 0x52630baf0e697, 0x4b49649819137, 0x14d0e0cfb056}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x7177,0xb186,0x73de,0xc572,0x9802,0xc0ee,0x7031,0xfe17,0xbc2e,0x41c5,0xe2a7,0xed41,0x1cbf,0x9ff9,0xf5bc,0x1e}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb1867177,0xc57273de,0xc0ee9802,0xfe177031,0x41c5bc2e,0xed41e2a7,0x9ff91cbf,0x1ef5bc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xc57273deb1867177,0xfe177031c0ee9802,0xed41e2a741c5bc2e,0x1ef5bc9ff91cbf}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x726a,0xbae3,0x32b6,0x75c2,0xe003,0x6e79,0xd172,0x382a,0x8a51,0x7962,0xa563,0x6a39,0x9cdd,0xc910,0xf6f0,0xa0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xbae3726a,0x75c232b6,0x6e79e003,0x382ad172,0x79628a51,0x6a39a563,0xc9109cdd,0xa0f6f0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x75c232b6bae3726a,0x382ad1726e79e003,0x6a39a56379628a51,0xa0f6f0c9109cdd}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x246b,0x9fa9,0x54e6,0xbd87,0x15b5,0x1c70,0x6470,0x25fa,0x3f5c,0x8940,0xa6e9,0x7eb5,0x6109,0x54a1,0xa8df,0x16}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x9fa9246b,0xbd8754e6,0x1c7015b5,0x25fa6470,0x89403f5c,0x7eb5a6e9,0x54a16109,0x16a8df}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xbd8754e69fa9246b,0x25fa64701c7015b5,0x7eb5a6e989403f5c,0x16a8df54a16109}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x8e89,0x4e79,0x8c21,0x3a8d,0x67fd,0x3f11,0x8fce,0x1e8,0x43d1,0xbe3a,0x1d58,0x12be,0xe340,0x6006,0xa43,0xe1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x4e798e89,0x3a8d8c21,0x3f1167fd,0x1e88fce,0xbe3a43d1,0x12be1d58,0x6006e340,0xe10a43}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3a8d8c214e798e89,0x1e88fce3f1167fd,0x12be1d58be3a43d1,0xe10a436006e340}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x231b,0x1af2,0x1640,0xb19c,0xf713,0xe470,0x683e,0xf39a,0x3289,0x7a54,0xc26e,0x904e,0xd5a6,0x6a0c,0x55fc,0x44}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1af2231b,0xb19c1640,0xe470f713,0xf39a683e,0x7a543289,0x904ec26e,0x6a0cd5a6,0x4455fc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb19c16401af2231b,0xf39a683ee470f713,0x904ec26e7a543289,0x4455fc6a0cd5a6}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xad7a,0xb685,0xde69,0x55d2,0x5675,0x84e8,0x5916,0x925f,0x8c0a,0x1cb6,0x7c51,0x8391,0xffce,0x11d1,0x96ce,0xcd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb685ad7a,0x55d2de69,0x84e85675,0x925f5916,0x1cb68c0a,0x83917c51,0x11d1ffce,0xcd96ce}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x55d2de69b685ad7a,0x925f591684e85675,0x83917c511cb68c0a,0xcd96ce11d1ffce}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x3724,0x79bd,0x1b92,0x959b,0xb3ec,0x6f18,0x27d4,0x64a7,0x9b4b,0x8c7e,0xade7,0x664b,0xa6d9,0xa287,0x6a1d,0x48}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x79bd3724,0x959b1b92,0x6f18b3ec,0x64a727d4,0x8c7e9b4b,0x664bade7,0xa287a6d9,0x486a1d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x959b1b9279bd3724,0x64a727d46f18b3ec,0x664bade78c7e9b4b,0x486a1da287a6d9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xdce5,0xe50d,0xe9bf,0x4e63,0x8ec,0x1b8f,0x97c1,0xc65,0xcd76,0x85ab,0x3d91,0x6fb1,0x2a59,0x95f3,0xaa03,0xbb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe50ddce5,0x4e63e9bf,0x1b8f08ec,0xc6597c1,0x85abcd76,0x6fb13d91,0x95f32a59,0xbbaa03}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4e63e9bfe50ddce5,0xc6597c11b8f08ec,0x6fb13d9185abcd76,0xbbaa0395f32a59}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x1975,0x2b02,0x86c,0x9cbe,0x7576,0xb1c3,0xd9a7,0x737e,0x4de1,0xa245,0x7652,0xf9bf,0x4bf8,0xdc2c,0xeaa1,0x8}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x2b021975,0x9cbe086c,0xb1c37576,0x737ed9a7,0xa2454de1,0xf9bf7652,0xdc2c4bf8,0x8eaa1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x9cbe086c2b021975,0x737ed9a7b1c37576,0xf9bf7652a2454de1,0x8eaa1dc2c4bf8}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xee88,0x46bc,0x7177,0x337c,0x92b6,0x40dc,0xb657,0x3366,0x6c8a,0x2b98,0x40eb,0x1146,0xe116,0xb00a,0xa22f,0xe3}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x46bcee88,0x337c7177,0x40dc92b6,0x3366b657,0x2b986c8a,0x114640eb,0xb00ae116,0xe3a22f}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x337c717746bcee88,0x3366b65740dc92b6,0x114640eb2b986c8a,0xe3a22fb00ae116}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xf28d,0x64d3,0xe248,0x40b9,0x5141,0x82bb,0x82ea,0xcf35,0xfaf0,0x3,0xd71f,0x6e88,0x7ac9,0xf4c9,0x6b9e,0xcc}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x64d3f28d,0x40b9e248,0x82bb5141,0xcf3582ea,0x3faf0,0x6e88d71f,0xf4c97ac9,0xcc6b9e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x40b9e24864d3f28d,0xcf3582ea82bb5141,0x6e88d71f0003faf0,0xcc6b9ef4c97ac9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xe68b,0xd4fd,0xf793,0x6341,0x8a89,0x4e3c,0x2658,0x8c81,0xb21e,0x5dba,0x89ad,0x640,0xb407,0x23d3,0x155e,0xf7}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd4fde68b,0x6341f793,0x4e3c8a89,0x8c812658,0x5dbab21e,0x64089ad,0x23d3b407,0xf7155e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x6341f793d4fde68b,0x8c8126584e3c8a89,0x64089ad5dbab21e,0xf7155e23d3b407}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x7177,0xb186,0x73de,0xc572,0x9802,0xc0ee,0x7031,0xfe17,0xbc2e,0x41c5,0xe2a7,0xed41,0x1cbf,0x9ff9,0xf5bc,0x1e}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xb1867177,0xc57273de,0xc0ee9802,0xfe177031,0x41c5bc2e,0xed41e2a7,0x9ff91cbf,0x1ef5bc}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xc57273deb1867177,0xfe177031c0ee9802,0xed41e2a741c5bc2e,0x1ef5bc9ff91cbf}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x726a,0xbae3,0x32b6,0x75c2,0xe003,0x6e79,0xd172,0x382a,0x8a51,0x7962,0xa563,0x6a39,0x9cdd,0xc910,0xf6f0,0xa0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xbae3726a,0x75c232b6,0x6e79e003,0x382ad172,0x79628a51,0x6a39a563,0xc9109cdd,0xa0f6f0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x75c232b6bae3726a,0x382ad1726e79e003,0x6a39a56379628a51,0xa0f6f0c9109cdd}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x246b,0x9fa9,0x54e6,0xbd87,0x15b5,0x1c70,0x6470,0x25fa,0x3f5c,0x8940,0xa6e9,0x7eb5,0x6109,0x54a1,0xa8df,0x16}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x9fa9246b,0xbd8754e6,0x1c7015b5,0x25fa6470,0x89403f5c,0x7eb5a6e9,0x54a16109,0x16a8df}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xbd8754e69fa9246b,0x25fa64701c7015b5,0x7eb5a6e989403f5c,0x16a8df54a16109}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x8e89,0x4e79,0x8c21,0x3a8d,0x67fd,0x3f11,0x8fce,0x1e8,0x43d1,0xbe3a,0x1d58,0x12be,0xe340,0x6006,0xa43,0xe1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x4e798e89,0x3a8d8c21,0x3f1167fd,0x1e88fce,0xbe3a43d1,0x12be1d58,0x6006e340,0xe10a43}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3a8d8c214e798e89,0x1e88fce3f1167fd,0x12be1d58be3a43d1,0xe10a436006e340}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x118e,0xd79,0xb20,0xd8ce,0x7b89,0x7238,0x341f,0xf9cd,0x1944,0x3d2a,0x6137,0x4827,0x6ad3,0x3506,0x2afe,0x22}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd79118e,0xd8ce0b20,0x72387b89,0xf9cd341f,0x3d2a1944,0x48276137,0x35066ad3,0x222afe}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xd8ce0b200d79118e,0xf9cd341f72387b89,0x482761373d2a1944,0x222afe35066ad3}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xd6bd,0xdb42,0x6f34,0xaae9,0x2b3a,0x4274,0xac8b,0x492f,0x4605,0x8e5b,0xbe28,0x41c8,0xffe7,0x8e8,0xcb67,0x66}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xdb42d6bd,0xaae96f34,0x42742b3a,0x492fac8b,0x8e5b4605,0x41c8be28,0x8e8ffe7,0x66cb67}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xaae96f34db42d6bd,0x492fac8b42742b3a,0x41c8be288e5b4605,0x66cb6708e8ffe7}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x9b92,0x3cde,0x8dc9,0x4acd,0x59f6,0x378c,0x93ea,0xb253,0x4da5,0xc63f,0xd6f3,0xb325,0xd36c,0xd143,0x350e,0x24}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x3cde9b92,0x4acd8dc9,0x378c59f6,0xb25393ea,0xc63f4da5,0xb325d6f3,0xd143d36c,0x24350e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x4acd8dc93cde9b92,0xb25393ea378c59f6,0xb325d6f3c63f4da5,0x24350ed143d36c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xee73,0xf286,0xf4df,0x2731,0x8476,0x8dc7,0xcbe0,0x632,0xe6bb,0xc2d5,0x9ec8,0xb7d8,0x952c,0xcaf9,0xd501,0xdd}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf286ee73,0x2731f4df,0x8dc78476,0x632cbe0,0xc2d5e6bb,0xb7d89ec8,0xcaf9952c,0xddd501}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x2731f4dff286ee73,0x632cbe08dc78476,0xb7d89ec8c2d5e6bb,0xddd501caf9952c}}}}
+#endif
+}}}, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x84a0,0x8ad1,0xbcc4,0xc440,0x94e1,0x46ea,0x15c6,0x784e,0x190,0xd26f,0x630,0x2bee,0x74b1,0x93ce,0xe061,0x3c}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x8ad184a0,0xc440bcc4,0x46ea94e1,0x784e15c6,0xd26f0190,0x2bee0630,0x93ce74b1,0x3ce061}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xc440bcc48ad184a0,0x784e15c646ea94e1,0x2bee0630d26f0190,0x3ce06193ce74b1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x1e2b,0xdafe,0xfa45,0xa69b,0xb77e,0xf670,0x927d,0xa0f9,0xccb5,0xc897,0x9607,0x5f22,0x47bf,0x867,0xf781,0xd9}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xdafe1e2b,0xa69bfa45,0xf670b77e,0xa0f9927d,0xc897ccb5,0x5f229607,0x86747bf,0xd9f781}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xa69bfa45dafe1e2b,0xa0f9927df670b77e,0x5f229607c897ccb5,0xd9f781086747bf}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x2aa2,0xbd3f,0x2ad,0x19bd,0xe6f0,0x3b95,0x3fff,0xd17e,0xf3a6,0x7888,0xda46,0x3b21,0xcc57,0x5301,0x3e50,0xc4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xbd3f2aa2,0x19bd02ad,0x3b95e6f0,0xd17e3fff,0x7888f3a6,0x3b21da46,0x5301cc57,0xc43e50}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x19bd02adbd3f2aa2,0xd17e3fff3b95e6f0,0x3b21da467888f3a6,0xc43e505301cc57}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x7b60,0x752e,0x433b,0x3bbf,0x6b1e,0xb915,0xea39,0x87b1,0xfe6f,0x2d90,0xf9cf,0xd411,0x8b4e,0x6c31,0x1f9e,0xc3}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x752e7b60,0x3bbf433b,0xb9156b1e,0x87b1ea39,0x2d90fe6f,0xd411f9cf,0x6c318b4e,0xc31f9e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3bbf433b752e7b60,0x87b1ea39b9156b1e,0xd411f9cf2d90fe6f,0xc31f9e6c318b4e}}}}
+#endif
+}}}}};
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/endomorphism_action.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/endomorphism_action.h
new file mode 100644
index 0000000000..1cc782a5bd
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/endomorphism_action.h
@@ -0,0 +1,31 @@
+#ifndef ENDOMORPHISM_ACTION_H
+#define ENDOMORPHISM_ACTION_H
+#include
+#include
+#include
+/** Type for precomputed endomorphism rings applied to precomputed torsion bases.
+ *
+ * Precomputed by the precompute scripts.
+ *
+ * @typedef curve_with_endomorphism_ring_t
+ *
+ * @struct curve_with_endomorphism_ring
+ **/
+typedef struct curve_with_endomorphism_ring {
+ ec_curve_t curve;
+ ec_basis_t basis_even;
+ ibz_mat_2x2_t action_i, action_j, action_k;
+ ibz_mat_2x2_t action_gen2, action_gen3, action_gen4;
+} curve_with_endomorphism_ring_t;
+#define CURVE_E0 (CURVES_WITH_ENDOMORPHISMS->curve)
+#define BASIS_EVEN (CURVES_WITH_ENDOMORPHISMS->basis_even)
+#define ACTION_I (CURVES_WITH_ENDOMORPHISMS->action_i)
+#define ACTION_J (CURVES_WITH_ENDOMORPHISMS->action_j)
+#define ACTION_K (CURVES_WITH_ENDOMORPHISMS->action_k)
+#define ACTION_GEN2 (CURVES_WITH_ENDOMORPHISMS->action_gen2)
+#define ACTION_GEN3 (CURVES_WITH_ENDOMORPHISMS->action_gen3)
+#define ACTION_GEN4 (CURVES_WITH_ENDOMORPHISMS->action_gen4)
+#define NUM_ALTERNATE_STARTING_CURVES 6
+#define ALTERNATE_STARTING_CURVES (CURVES_WITH_ENDOMORPHISMS+1)
+extern const curve_with_endomorphism_ring_t CURVES_WITH_ENDOMORPHISMS[7];
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/finit.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/finit.c
new file mode 100644
index 0000000000..c9a3687282
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/finit.c
@@ -0,0 +1,122 @@
+#include "internal.h"
+
+void
+quat_alg_init_set(quat_alg_t *alg, const ibz_t *p)
+{
+ ibz_init(&(*alg).p);
+ ibz_copy(&(*alg).p, p);
+}
+void
+quat_alg_finalize(quat_alg_t *alg)
+{
+ ibz_finalize(&(*alg).p);
+}
+
+void
+quat_alg_elem_init(quat_alg_elem_t *elem)
+{
+ ibz_vec_4_init(&(*elem).coord);
+ ibz_init(&(*elem).denom);
+ ibz_set(&(*elem).denom, 1);
+}
+void
+quat_alg_elem_finalize(quat_alg_elem_t *elem)
+{
+ ibz_vec_4_finalize(&(*elem).coord);
+ ibz_finalize(&(*elem).denom);
+}
+
+void
+ibz_vec_2_init(ibz_vec_2_t *vec)
+{
+ ibz_init(&(vec->v[0]));
+ ibz_init(&(vec->v[1]));
+}
+
+void
+ibz_vec_2_finalize(ibz_vec_2_t *vec)
+{
+ ibz_finalize(&(vec->v[0]));
+ ibz_finalize(&(vec->v[1]));
+}
+
+void
+ibz_vec_4_init(ibz_vec_4_t *vec)
+{
+ for (int i = 0; i < 4; i++) {
+ ibz_init(&vec->v[i]);
+ }
+}
+void
+ibz_vec_4_finalize(ibz_vec_4_t *vec)
+{
+ for (int i = 0; i < 4; i++) {
+ ibz_finalize(&vec->v[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->m)[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->m)[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->m)[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->m)[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_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);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fips202.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fips202.h
new file mode 100644
index 0000000000..d4bc8ac727
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fips202.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef FIPS202_H
+#define FIPS202_H
+
+#include
+
+#define shake256incctx OQS_SHA3_shake256_inc_ctx
+#define shake256_inc_init OQS_SHA3_shake256_inc_init
+#define shake256_inc_absorb OQS_SHA3_shake256_inc_absorb
+#define shake256_inc_finalize OQS_SHA3_shake256_inc_finalize
+#define shake256_inc_squeeze OQS_SHA3_shake256_inc_squeeze
+#define shake256_inc_ctx_release OQS_SHA3_shake256_inc_ctx_release
+#define shake256_inc_ctx_reset OQS_SHA3_shake256_inc_ctx_reset
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp.c
new file mode 100644
index 0000000000..f7c7456498
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp.c
@@ -0,0 +1,95 @@
+#include
+#include "fp.h"
+
+const digit_t p[NWORDS_FIELD] = { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x04ffffffffffffff };
+const digit_t p2[NWORDS_FIELD] = { 0xfffffffffffffffe, 0xffffffffffffffff, 0xffffffffffffffff, 0x09ffffffffffffff };
+
+void
+fp_sqrt(fp_t *x)
+{
+ (void)gf5248_sqrt(x, x);
+}
+
+uint32_t
+fp_is_square(const fp_t *a)
+{
+ // ls is (0, 1, -1) and we want fp_is_square
+ // to return 0xFF..FF when ls is 1 or 0 and 0x00..00 otherwise
+ int32_t ls = gf5248_legendre(a);
+ return ~(uint32_t)(ls >> 1);
+}
+
+void
+fp_inv(fp_t *x)
+{
+ (void)gf5248_invert(x, x);
+}
+
+void
+fp_exp3div4(fp_t *a)
+{
+ //
+ // We optimise this by using the shape of the prime
+ // to avoid almost all multiplications:
+ //
+ // We write:
+ // (p - 3) / 4 = (5*2^248 - 4) / 4
+ // = 5*2^246 - 1
+ // = 5*(2^246 - 1) + 4
+ // Then we first compute:
+ // a246 = a**(2^246 - 1)
+ // Then from this we get the desired result as:
+ // a**((p-3)/4) = a246**5 * a**4
+ // We can compute this with 12 multiplications and 247 squares.
+ fp_t z4, t3, t6, tmp;
+ // Compute a**3 and a**4
+ fp_sqr(&z4, a);
+ fp_mul(&tmp, a, &z4);
+ fp_sqr(&z4, &z4);
+ // Compute a**(2^3 - 1) = a**7
+ fp_mul(&t3, &tmp, &z4);
+ // Compute a**(2^6 - 1)
+ fp_sqr(&t6, &t3);
+ for (int i = 1; i < 3; i++)
+ fp_sqr(&t6, &t6);
+ fp_mul(&t6, &t6, &t3);
+ // Compute a**(2^12 - 1)
+ fp_sqr(a, &t6);
+ for (int i = 1; i < 6; i++)
+ fp_sqr(a, a);
+ fp_mul(a, a, &t6);
+ // Compute a**(2^15 - 1)
+ for (int i = 0; i < 3; i++)
+ fp_sqr(a, a);
+ fp_mul(a, a, &t3);
+ // Compute a**(2^30 - 1)
+ fp_sqr(&tmp, a);
+ for (int i = 1; i < 15; i++)
+ fp_sqr(&tmp, &tmp);
+ fp_mul(a, a, &tmp);
+ // Compute a**(2^60 - 1)
+ fp_sqr(&tmp, a);
+ for (int i = 1; i < 30; i++)
+ fp_sqr(&tmp, &tmp);
+ fp_mul(a, a, &tmp);
+ // Compute a**(2^120 - 1)
+ fp_sqr(&tmp, a);
+ for (int i = 1; i < 60; i++)
+ fp_sqr(&tmp, &tmp);
+ fp_mul(a, a, &tmp);
+ // Compute a**(2^123 - 1)
+ for (int i = 0; i < 3; i++)
+ fp_sqr(a, a);
+ fp_mul(a, a, &t3);
+ // Compute a**(2^246 - 1)
+ fp_sqr(&tmp, a);
+ for (int i = 1; i < 123; i++)
+ fp_sqr(&tmp, &tmp);
+ fp_mul(a, a, &tmp);
+ // Compute a**(5*(2^246 - 1))
+ fp_sqr(&tmp, a);
+ fp_sqr(&tmp, &tmp);
+ fp_mul(a, a, &tmp);
+ // Compute a**(5*(2^246 - 1) + 4)
+ fp_mul(a, a, &z4);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp.h
new file mode 100644
index 0000000000..e63ee8c5a9
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp.h
@@ -0,0 +1,135 @@
+#ifndef FP_H
+#define FP_H
+
+// Include statements
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "gf5248.h"
+
+// Type for elements of GF(p)
+#define fp_t gf5248
+
+// Operations in fp
+static inline void
+fp_neg(fp_t *d, const fp_t *a)
+{
+ gf5248_neg(d, a);
+}
+
+void fp_add(fp_t *out, const fp_t *a, const fp_t *b); // implemented in fp_asm.S
+void fp_sub(fp_t *out, const fp_t *a, const fp_t *b); // implemented in fp_asm.S
+void fp_sqr(fp_t *out, const fp_t *a); // implemented in fp_asm.S
+void fp_mul(fp_t *out, const fp_t *a, const fp_t *b); // implemented in fp_asm.S
+
+static inline void
+fp_mul_small(fp_t *d, const fp_t *a, uint32_t n)
+{
+ gf5248_mul_small(d, a, n);
+}
+
+static inline void
+fp_half(fp_t *d, const fp_t *a)
+{
+ gf5248_half(d, a);
+}
+// #define fp_half gf5248_half
+
+static inline void
+fp_div3(fp_t *d, const fp_t *a)
+{
+ gf5248_div3(d, a);
+}
+// #define fp_div3 gf5248_div3
+
+// Constant time selection and swapping
+static inline void
+fp_select(fp_t *d, const fp_t *a0, const fp_t *a1, uint32_t ctl)
+{
+ gf5248_select(d, a0, a1, ctl);
+}
+// #define fp_select gf5248_select
+static inline void
+fp_cswap(fp_t *a, fp_t *b, uint32_t ctl)
+{
+ gf5248_cswap(a, b, ctl);
+}
+// #define fp_cswap gf5248_cswap
+
+// Comparisons for fp elements
+static inline uint32_t
+fp_is_zero(const fp_t *a)
+{
+ return gf5248_iszero(a);
+}
+// #define fp_is_zero gf5248_iszero
+
+static inline uint32_t
+fp_is_equal(const fp_t *a, const fp_t *b)
+{
+ return gf5248_equals(a, b);
+}
+// #define fp_is_equal gf5248_equals
+
+// Set a uint32 to an Fp value
+static inline void
+fp_set_small(fp_t *d, uint32_t x)
+{
+ gf5248_set_small(d, x);
+}
+// #define fp_set_small gf5248_set_small
+
+// Encoding and decoding of bytes
+static inline void
+fp_encode(void *dst, const fp_t *a)
+{
+ gf5248_encode(dst, a);
+}
+// #define fp_encode gf5248_encode
+static inline uint32_t
+fp_decode(fp_t *d, const void *src)
+{
+ return gf5248_decode(d, src);
+}
+// #define fp_decode gf5248_decode
+static inline void
+fp_decode_reduce(fp_t *d, const void *src, size_t len)
+{
+ gf5248_decode_reduce(d, src, len);
+}
+// #define fp_decode_reduce gf5248_decode_reduce
+
+// These functions are essentially useless because we can just
+// use = for the shallow copies we need, but they're here for
+// now until we do a larger refactoring
+static inline void
+fp_copy(fp_t *out, const fp_t *a)
+{
+ memmove(out, a, sizeof(fp_t));
+}
+
+static inline void
+fp_set_zero(fp_t *a)
+{
+ memcpy(a, &ZERO, sizeof(fp_t));
+}
+
+static inline void
+fp_set_one(fp_t *a)
+{
+ memcpy(a, &ONE, sizeof(fp_t));
+}
+
+// Functions defined in low level code but with different API
+void fp_inv(fp_t *a);
+void fp_sqrt(fp_t *a);
+void fp_exp3div4(fp_t *a);
+uint32_t fp_is_square(const fp_t *a);
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp2.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp2.c
new file mode 100644
index 0000000000..3269f6c66f
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp2.c
@@ -0,0 +1,188 @@
+#include "fp2.h"
+#include
+#include
+
+/* Arithmetic modulo X^2 + 1 */
+
+void
+fp2_encode(void *dst, const fp2_t *a)
+{
+ uint8_t *buf = dst;
+ fp_encode(buf, &(a->re));
+ fp_encode(buf + FP_ENCODED_BYTES, &(a->im));
+}
+
+uint32_t
+fp2_decode(fp2_t *d, const void *src)
+{
+ const uint8_t *buf = src;
+ uint32_t re, im;
+
+ re = fp_decode(&(d->re), buf);
+ im = fp_decode(&(d->im), buf + FP_ENCODED_BYTES);
+ return re & im;
+}
+
+void
+fp2_inv(fp2_t *x)
+{
+ fp_t t0, t1;
+
+ fp_sqr(&t0, &(x->re));
+ fp_sqr(&t1, &(x->im));
+ fp_add(&t0, &t0, &t1);
+ fp_inv(&t0);
+ fp_mul(&(x->re), &(x->re), &t0);
+ fp_mul(&(x->im), &(x->im), &t0);
+ fp_neg(&(x->im), &(x->im));
+}
+
+void
+fp2_batched_inv(fp2_t *x, int len)
+{
+ fp2_t t1[len], t2[len];
+ fp2_t inverse;
+
+ // x = x0,...,xn
+ // t1 = x0, x0*x1, ... ,x0 * x1 * ... * xn
+ t1[0] = x[0];
+ for (int i = 1; i < len; i++) {
+ fp2_mul(&t1[i], &t1[i - 1], &x[i]);
+ }
+
+ // inverse = 1/ (x0 * x1 * ... * xn)
+ inverse = t1[len - 1];
+ fp2_inv(&inverse);
+ t2[0] = inverse;
+
+ // t2 = 1/ (x0 * x1 * ... * xn), 1/ (x0 * x1 * ... * x(n-1)) , ... , 1/xO
+ for (int i = 1; i < len; i++) {
+ fp2_mul(&t2[i], &t2[i - 1], &x[len - i]);
+ }
+
+ x[0] = t2[len - 1];
+ for (int i = 1; i < len; i++) {
+ fp2_mul(&x[i], &t1[i - 1], &t2[len - i - 1]);
+ }
+}
+
+uint32_t
+fp2_is_square(const fp2_t *x)
+{
+ fp_t t0, t1;
+
+ fp_sqr(&t0, &(x->re));
+ fp_sqr(&t1, &(x->im));
+ fp_add(&t0, &t0, &t1);
+
+ return fp_is_square(&t0);
+}
+
+void
+fp2_sqrt(fp2_t *a)
+{
+ fp_t x0, x1, t0, t1;
+
+ /* From "Optimized One-Dimensional SQIsign Verification on Intel and
+ * Cortex-M4" by Aardal et al: https://eprint.iacr.org/2024/1563 */
+
+ // x0 = \delta = sqrt(a0^2 + a1^2).
+ fp_sqr(&x0, &(a->re));
+ fp_sqr(&x1, &(a->im));
+ fp_add(&x0, &x0, &x1);
+ fp_sqrt(&x0);
+ // If a1 = 0, there is a risk of \delta = -a0, which makes x0 = 0 below.
+ // In that case, we restore the value \delta = a0.
+ fp_select(&x0, &x0, &(a->re), fp_is_zero(&(a->im)));
+ // x0 = \delta + a0, t0 = 2 * x0.
+ fp_add(&x0, &x0, &(a->re));
+ fp_add(&t0, &x0, &x0);
+ // x1 = t0^(p-3)/4.
+ fp_copy(&x1, &t0);
+ fp_exp3div4(&x1);
+ // x0 = x0 * x1, x1 = x1 * a1, t1 = (2x0)^2.
+ fp_mul(&x0, &x0, &x1);
+ fp_mul(&x1, &x1, &(a->im));
+ fp_add(&t1, &x0, &x0);
+ fp_sqr(&t1, &t1);
+ // If t1 = t0, return x0 + x1*i, otherwise x1 - x0*i.
+ fp_sub(&t0, &t0, &t1);
+ uint32_t f = fp_is_zero(&t0);
+ fp_neg(&t1, &x0);
+ fp_copy(&t0, &x1);
+ fp_select(&t0, &t0, &x0, f);
+ fp_select(&t1, &t1, &x1, f);
+
+ // Check if t0 is zero
+ uint32_t t0_is_zero = fp_is_zero(&t0);
+ // Check whether t0, t1 are odd
+ // Note: we encode to ensure canonical representation
+ uint8_t tmp_bytes[FP_ENCODED_BYTES];
+ fp_encode(tmp_bytes, &t0);
+ uint32_t t0_is_odd = -((uint32_t)tmp_bytes[0] & 1);
+ fp_encode(tmp_bytes, &t1);
+ uint32_t t1_is_odd = -((uint32_t)tmp_bytes[0] & 1);
+ // We negate the output if:
+ // t0 is odd, or
+ // t0 is zero and t1 is odd
+ uint32_t negate_output = t0_is_odd | (t0_is_zero & t1_is_odd);
+ fp_neg(&x0, &t0);
+ fp_select(&(a->re), &t0, &x0, negate_output);
+ fp_neg(&x0, &t1);
+ fp_select(&(a->im), &t1, &x0, negate_output);
+}
+
+uint32_t
+fp2_sqrt_verify(fp2_t *a)
+{
+ fp2_t t0, t1;
+
+ fp2_copy(&t0, a);
+ fp2_sqrt(a);
+ fp2_sqr(&t1, a);
+
+ return (fp2_is_equal(&t0, &t1));
+}
+
+// exponentiation
+void
+fp2_pow_vartime(fp2_t *out, const fp2_t *x, const digit_t *exp, const int size)
+{
+ fp2_t acc;
+ digit_t bit;
+
+ fp2_copy(&acc, x);
+ fp2_set_one(out);
+
+ // Iterate over each word of exp
+ for (int j = 0; j < size; j++) {
+ // Iterate over each bit of the word
+ for (int i = 0; i < RADIX; i++) {
+ bit = (exp[j] >> i) & 1;
+ if (bit == 1) {
+ fp2_mul(out, out, &acc);
+ }
+ fp2_sqr(&acc, &acc);
+ }
+ }
+}
+
+void
+fp2_print(const char *name, const fp2_t *a)
+{
+ printf("%s0x", name);
+
+ uint8_t buf[FP_ENCODED_BYTES];
+ fp_encode(&buf, &a->re); // Encoding ensures canonical rep
+ for (int i = 0; i < FP_ENCODED_BYTES; i++) {
+ printf("%02x", buf[FP_ENCODED_BYTES - i - 1]);
+ }
+
+ printf(" + i*0x");
+
+ fp_encode(&buf, &a->im);
+ for (int i = 0; i < FP_ENCODED_BYTES; i++) {
+ printf("%02x", buf[FP_ENCODED_BYTES - i - 1]);
+ }
+ printf("\n");
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp2.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp2.h
new file mode 100644
index 0000000000..3bbb68a016
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp2.h
@@ -0,0 +1,41 @@
+#ifndef FP2_H
+#define FP2_H
+
+#define NO_FP2X_MUL
+#define NO_FP2X_SQR
+
+#include
+
+extern void fp2_sq_c0(fp2_t *out, const fp2_t *in);
+extern void fp2_sq_c1(fp_t *out, const fp2_t *in);
+
+extern void fp2_mul_c0(fp_t *out, const fp2_t *in0, const fp2_t *in1);
+extern void fp2_mul_c1(fp_t *out, const fp2_t *in0, const fp2_t *in1);
+
+static inline void
+fp2_mul(fp2_t *x, const fp2_t *y, const fp2_t *z)
+{
+ fp_t t;
+
+ fp2_mul_c0(&t, y, z); // c0 = a0*b0 - a1*b1
+ fp2_mul_c1(&x->im, y, z); // c1 = a0*b1 + a1*b0
+ x->re.arr[0] = t.arr[0];
+ x->re.arr[1] = t.arr[1];
+ x->re.arr[2] = t.arr[2];
+ x->re.arr[3] = t.arr[3];
+}
+
+static inline void
+fp2_sqr(fp2_t *x, const fp2_t *y)
+{
+ fp2_t t;
+
+ fp2_sq_c0(&t, y); // c0 = (a0+a1)(a0-a1)
+ fp2_sq_c1(&x->im, y); // c1 = 2a0*a1
+ x->re.arr[0] = t.re.arr[0];
+ x->re.arr[1] = t.re.arr[1];
+ x->re.arr[2] = t.re.arr[2];
+ x->re.arr[3] = t.re.arr[3];
+}
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp2x.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp2x.h
new file mode 100644
index 0000000000..44cf103bf2
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp2x.h
@@ -0,0 +1,162 @@
+#ifndef FP2X_H
+#define FP2X_H
+
+#include
+#include "fp.h"
+#include
+
+// Structure for representing elements in GF(p^2)
+typedef struct fp2_t
+{
+ fp_t re, im;
+} fp2_t;
+
+static inline void
+fp2_set_small(fp2_t *x, const uint32_t val)
+{
+ fp_set_small(&(x->re), val);
+ fp_set_zero(&(x->im));
+}
+
+static inline void
+fp2_mul_small(fp2_t *x, const fp2_t *y, uint32_t n)
+{
+ fp_mul_small(&x->re, &y->re, n);
+ fp_mul_small(&x->im, &y->im, n);
+}
+
+static inline void
+fp2_set_zero(fp2_t *x)
+{
+ fp_set_zero(&(x->re));
+ fp_set_zero(&(x->im));
+}
+
+static inline void
+fp2_set_one(fp2_t *x)
+{
+ fp_set_one(&(x->re));
+ fp_set_zero(&(x->im));
+}
+
+static inline uint32_t
+fp2_is_equal(const fp2_t *a, const fp2_t *b)
+{ // Compare two GF(p^2) elements in constant time
+ // Returns 1 (true) if a=b, 0 (false) otherwise
+
+ return fp_is_equal(&(a->re), &(b->re)) & fp_is_equal(&(a->im), &(b->im));
+}
+
+static inline uint32_t
+fp2_is_zero(const fp2_t *a)
+{ // Is a GF(p^2) element zero?
+ // Returns 1 (true) if a=0, 0 (false) otherwise
+
+ return fp_is_zero(&(a->re)) & fp_is_zero(&(a->im));
+}
+
+static inline uint32_t
+fp2_is_one(const fp2_t *a)
+{ // Is a GF(p^2) element one?
+ // Returns 1 (true) if a=0, 0 (false) otherwise
+ return fp_is_equal(&(a->re), &ONE) & fp_is_zero(&(a->im));
+}
+
+static inline void
+fp2_half(fp2_t *x, const fp2_t *y)
+{
+ fp_half(&(x->re), &(y->re));
+ fp_half(&(x->im), &(y->im));
+}
+
+static inline void
+fp2_add(fp2_t *x, const fp2_t *y, const fp2_t *z)
+{
+ fp_add(&(x->re), &(y->re), &(z->re));
+ fp_add(&(x->im), &(y->im), &(z->im));
+}
+
+static inline void
+fp2_add_one(fp2_t *x, const fp2_t *y)
+{
+ fp_add(&x->re, &y->re, &ONE);
+ fp_copy(&x->im, &y->im);
+}
+
+static inline void
+fp2_sub(fp2_t *x, const fp2_t *y, const fp2_t *z)
+{
+ fp_sub(&(x->re), &(y->re), &(z->re));
+ fp_sub(&(x->im), &(y->im), &(z->im));
+}
+
+static inline void
+fp2_neg(fp2_t *x, const fp2_t *y)
+{
+ fp_neg(&(x->re), &(y->re));
+ fp_neg(&(x->im), &(y->im));
+}
+
+#ifndef NO_FP2X_MUL
+static inline void
+fp2_mul(fp2_t *x, const fp2_t *y, const fp2_t *z)
+{
+ fp_t t0, t1;
+
+ fp_add(&t0, &(y->re), &(y->im));
+ fp_add(&t1, &(z->re), &(z->im));
+ fp_mul(&t0, &t0, &t1);
+ fp_mul(&t1, &(y->im), &(z->im));
+ fp_mul(&(x->re), &(y->re), &(z->re));
+ fp_sub(&(x->im), &t0, &t1);
+ fp_sub(&(x->im), &(x->im), &(x->re));
+ fp_sub(&(x->re), &(x->re), &t1);
+}
+#endif
+
+#ifndef NO_FP2X_SQR
+static inline void
+fp2_sqr(fp2_t *x, const fp2_t *y)
+{
+ fp_t sum, diff;
+
+ fp_add(&sum, &(y->re), &(y->im));
+ fp_sub(&diff, &(y->re), &(y->im));
+ fp_mul(&(x->im), &(y->re), &(y->im));
+ fp_add(&(x->im), &(x->im), &(x->im));
+ fp_mul(&(x->re), &sum, &diff);
+}
+#endif
+
+static inline void
+fp2_select(fp2_t *d, const fp2_t *a0, const fp2_t *a1, uint32_t ctl)
+{
+ fp_select(&(d->re), &(a0->re), &(a1->re), ctl);
+ fp_select(&(d->im), &(a0->im), &(a1->im), ctl);
+}
+
+static inline void
+fp2_cswap(fp2_t *a, fp2_t *b, uint32_t ctl)
+{
+ fp_cswap(&(a->re), &(b->re), ctl);
+ fp_cswap(&(a->im), &(b->im), ctl);
+}
+
+static inline void
+fp2_copy(fp2_t *x, const fp2_t *y)
+{
+ *x = *y;
+}
+
+// New functions
+void fp2_encode(void *dst, const fp2_t *a);
+uint32_t fp2_decode(fp2_t *d, const void *src);
+void fp2_inv(fp2_t *x);
+uint32_t fp2_is_square(const fp2_t *x);
+void fp2_sqrt(fp2_t *x);
+uint32_t fp2_sqrt_verify(fp2_t *a);
+void fp2_batched_inv(fp2_t *x, int len);
+void fp2_pow_vartime(fp2_t *out, const fp2_t *x, const uint64_t *exp, const int size);
+void fp2_print(const char *name, const fp2_t *a);
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp_asm.S b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp_asm.S
new file mode 100755
index 0000000000..6da7ff7c9f
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp_asm.S
@@ -0,0 +1,466 @@
+#include
+.intel_syntax noprefix
+
+.set pbytes,32
+.set plimbs,4
+
+#ifdef __APPLE__
+.section __TEXT,__const
+#else
+.section .rodata
+#endif
+p_plus_1: .quad 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0500000000000000
+
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",@progbits
+#endif
+
+#include
+
+.text
+.p2align 4,,15
+
+.global fp_add
+fp_add:
+ xor rax, rax
+ mov r8, [rsi]
+ mov r9, [rsi+8]
+ mov r10, [rsi+16]
+ mov r11, [rsi+24]
+ add r8, [rdx]
+ adc r9, [rdx+8]
+ adc r10, [rdx+16]
+ adc r11, [rdx+24]
+ mov rax, r11
+ shr rax, 59
+ neg rax
+ mov rdx, [rip+p+24]
+ and rdx, rax
+ sub r8, rax
+ sbb r9, rax
+ sbb r10, rax
+ sbb r11, rdx
+
+ mov rax, r11
+ shr rax, 59
+ neg rax
+ mov rdx, [rip+p+24]
+ and rdx, rax
+ sub r8, rax
+ sbb r9, rax
+ sbb r10, rax
+ sbb r11, rdx
+ mov [rdi], r8
+ mov [rdi+8], r9
+ mov [rdi+16], r10
+ mov [rdi+24], r11
+ ret
+
+.global fp_sub
+fp_sub:
+ xor rax, rax
+ mov r8, [rsi]
+ mov r9, [rsi+8]
+ mov r10, [rsi+16]
+ mov r11, [rsi+24]
+ sub r8, [rdx]
+ sbb r9, [rdx+8]
+ sbb r10, [rdx+16]
+ sbb r11, [rdx+24]
+ sbb rax, 0
+
+ mov rdx, [rip+p+24]
+ and rdx, rax
+ add r8, rax
+ adc r9, rax
+ adc r10, rax
+ adc r11, rdx
+
+ mov rax, r11
+ sar rax, 59
+ mov rdx, [rip+p+24]
+ and rdx, rax
+ add r8, rax
+ adc r9, rax
+ adc r10, rax
+ adc r11, rdx
+
+ mov [rdi], r8
+ mov [rdi+8], r9
+ mov [rdi+16], r10
+ mov [rdi+24], r11
+ ret
+
+///////////////////////////////////////////////////////////////// MACROS
+// z = a x bi + z
+// Inputs: base memory pointer M1 (a),
+// bi pre-stored in rdx,
+// accumulator z in [Z0:Z4]
+// Output: [Z0:Z4]
+// Temps: regs T0:T1
+/////////////////////////////////////////////////////////////////
+.macro MULADD64x256 M1, Z0, Z1, Z2, Z3, Z4, T0, T1, C
+ mulx \T0, \T1, \M1 // A0*B0
+ xor \C, \C
+ adox \Z0, \T1
+ adox \Z1, \T0
+ mulx \T0, \T1, 8\M1 // A0*B1
+ adcx \Z1, \T1
+ adox \Z2, \T0
+ mulx \T0, \T1, 16\M1 // A0*B2
+ adcx \Z2, \T1
+ adox \Z3, \T0
+ mulx \T0, \T1, 24\M1 // A0*B3
+ adcx \Z3, \T1
+ adox \Z4, \T0
+ adc \Z4, 0
+.endm
+
+.macro MULADD64x64 M1, Z0, Z1, Z2, Z3, T0, T1
+ mulx \T0, \T1, \M1 // A0*B0
+ xor rax, rax
+ adox \Z2, \T1
+ adox \Z3, \T0
+.endm
+
+//***********************************************************************
+// Multiplication in GF(p^2), non-complex part
+// Operation: c [rdi] = a0 x b0 - a1 x b1
+// Inputs: a = [a1, a0] stored in [rsi]
+// b = [b1, b0] stored in [rdx]
+// Output: c stored in [rdi]
+//***********************************************************************
+.global fp2_mul_c0
+fp2_mul_c0:
+ push r12
+ push r13
+ push r14
+ mov rcx, rdx
+
+ // [rdi0:3] <- 2p - b1
+ mov r8, [rip+p2]
+ mov r9, [rip+p2+8]
+ mov r10, r9
+ mov r11, [rip+p2+24]
+ mov rax, [rcx+32]
+ mov rdx, [rcx+40]
+ sub r8, rax
+ sbb r9, rdx
+ mov rax, [rcx+48]
+ mov rdx, [rcx+56]
+ sbb r10, rax
+ sbb r11, rdx
+ mov [rdi], r8
+ mov [rdi+8], r9
+ mov [rdi+16], r10
+ mov [rdi+24], r11
+
+ // [r8:r12] <- z = a0 x b00 - a1 x b10
+ mov rdx, [rcx]
+ mulx r9, r8, [rsi]
+ xor rax, rax
+ mulx r10, r11, [rsi+8]
+ adox r9, r11
+ mulx r11, r12, [rsi+16]
+ adox r10, r12
+ mulx r12, r13, [rsi+24]
+ adox r11, r13
+ adox r12, rax
+
+ mov rdx, [rdi]
+ MULADD64x256 [rsi+32], r8, r9, r10, r11, r12, r13, r14, rax
+ // [r9:r12] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, r8 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], r9, r10, r11, r12, r13, r14
+
+ // [r9:r12, r8] <- z = a0 x b01 - a1 x b11 + z
+ mov rdx, [rcx+8]
+ MULADD64x256 [rsi], r9, r10, r11, r12, r8, r13, r14, r8
+ mov rdx, [rdi+8]
+ MULADD64x256 [rsi+32], r9, r10, r11, r12, r8, r13, r14, rax
+ // [r10:r12, r8] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, r9 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], r10, r11, r12, r8, r13, r14
+
+ // [r10:r12, r8:r9] <- z = a0 x b02 - a1 x b12 + z
+ mov rdx, [rcx+16]
+ MULADD64x256 [rsi], r10, r11, r12, r8, r9, r13, r14, r9
+ mov rdx, [rdi+16]
+ MULADD64x256 [rsi+32], r10, r11, r12, r8, r9, r13, r14, rax
+ // [r11:r12, r8:r9] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, r10 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], r11, r12, r8, r9, r13, r14
+
+ // [r11:r12, r8:r10] <- z = a0 x b03 - a1 x b13 + z
+ mov rdx, [rcx+24]
+ MULADD64x256 [rsi], r11, r12, r8, r9, r10, r13, r14, r10
+ mov rdx, [rdi+24]
+ MULADD64x256 [rsi+32], r11, r12, r8, r9, r10, r13, r14, rax
+ // [r12, r8:r10] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, r11 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], r12, r8, r9, r10, r13, r14
+
+ mov [rdi], r12
+ mov [rdi+8], r8
+ mov [rdi+16], r9
+ mov [rdi+24], r10
+ pop r14
+ pop r13
+ pop r12
+ ret
+
+//***********************************************************************
+// Multiplication in GF(p^2), complex part
+// Operation: c [rdi] = a0 x b1 + a1 x b0
+// Inputs: a = [a1, a0] stored in [rsi]
+// b = [b1, b0] stored in [rdx]
+// Output: c stored in [rdi]
+//***********************************************************************
+.global fp2_mul_c1
+fp2_mul_c1:
+ push r12
+ push r13
+ push r14
+ mov rcx, rdx
+
+ // [r8:r12] <- z = a0 x b10 + a1 x b00
+ mov rdx, [rcx+32]
+ mulx r9, r8, [rsi]
+ xor rax, rax
+ mulx r10, r11, [rsi+8]
+ adox r9, r11
+ mulx r11, r12, [rsi+16]
+ adox r10, r12
+ mulx r12, r13, [rsi+24]
+ adox r11, r13
+ adox r12, rax
+
+ mov rdx, [rcx]
+ MULADD64x256 [rsi+32], r8, r9, r10, r11, r12, r13, r14, rax
+ // [r9:r12] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, r8 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], r9, r10, r11, r12, r13, r14
+
+ // [r9:r12, r8] <- z = a0 x b01 - a1 x b11 + z
+ mov rdx, [rcx+40]
+ MULADD64x256 [rsi], r9, r10, r11, r12, r8, r13, r14, r8
+ mov rdx, [rcx+8]
+ MULADD64x256 [rsi+32], r9, r10, r11, r12, r8, r13, r14, rax
+ // [r10:r12, r8] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, r9 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], r10, r11, r12, r8, r13, r14
+
+ // [r10:r12, r8:r9] <- z = a0 x b02 - a1 x b12 + z
+ mov rdx, [rcx+48]
+ MULADD64x256 [rsi], r10, r11, r12, r8, r9, r13, r14, r9
+ mov rdx, [rcx+16]
+ MULADD64x256 [rsi+32], r10, r11, r12, r8, r9, r13, r14, rax
+ // [r11:r12, r8:r9] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, r10 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], r11, r12, r8, r9, r13, r14
+
+ // [r11:r12, r8:r10] <- z = a0 x b03 - a1 x b13 + z
+ mov rdx, [rcx+56]
+ MULADD64x256 [rsi], r11, r12, r8, r9, r10, r13, r14, r10
+ mov rdx, [rcx+24]
+ MULADD64x256 [rsi+32], r11, r12, r8, r9, r10, r13, r14, rax
+ // [r12, r8:r10] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, r11 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], r12, r8, r9, r10, r13, r14
+
+ mov [rdi], r12
+ mov [rdi+8], r8
+ mov [rdi+16], r9
+ mov [rdi+24], r10
+ pop r14
+ pop r13
+ pop r12
+ ret
+
+///////////////////////////////////////////////////////////////// MACRO
+// z = a x b (mod p)
+// Inputs: base memory pointers M0 (a), M1 (b)
+// bi pre-stored in rdx,
+// accumulator z in [Z0:Z4], pre-stores a0 x b
+// Output: [Z0:Z4]
+// Temps: regs T0:T1
+/////////////////////////////////////////////////////////////////
+.macro FPMUL256x256 M0, M1, Z0, Z1, Z2, Z3, Z4, T0, T1
+ // [Z1:Z4] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, \Z0 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], \Z1, \Z2, \Z3, \Z4, \T0, \T1
+
+ // [Z1:Z4, Z0] <- z = a01 x a1 + z
+ mov rdx, 8\M0
+ MULADD64x256 \M1, \Z1, \Z2, \Z3, \Z4, \Z0, \T0, \T1, \Z0
+ // [Z2:Z4, Z0] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, \Z1 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], \Z2, \Z3, \Z4, \Z0, \T0, \T1
+
+ // [Z2:Z4, Z0:Z1] <- z = a02 x a1 + z
+ mov rdx, 16\M0
+ MULADD64x256 \M1, \Z2, \Z3, \Z4, \Z0, \Z1, \T0, \T1, \Z1
+ // [Z3:Z4, Z0:Z1] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, \Z2 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], \Z3, \Z4, \Z0, \Z1, \T0, \T1
+
+ // [Z3:Z4, Z0:Z2] <- z = a03 x a1 + z
+ mov rdx, 24\M0
+ MULADD64x256 \M1, \Z3, \Z4, \Z0, \Z1, \Z2, \T0, \T1, \Z2
+ // [Z4, Z0:Z2] <- z = (z0 x p_plus_1 + z)/2^64
+ mov rdx, \Z3 // rdx <- z0
+ MULADD64x64 [rip+p_plus_1+24], \Z4, \Z0, \Z1, \Z2, \T0, \T1
+.endm
+
+//***********************************************************************
+// Squaring in GF(p^2), non-complex part
+// Operation: c [rdi] = (a0+a1) x (a0-a1)
+// Inputs: a = [a1, a0] stored in [rsi]
+// Output: c stored in [rdi]
+//***********************************************************************
+.global fp2_sq_c0
+fp2_sq_c0:
+ push r12
+ push r13
+
+ // a0 + a1
+ mov rdx, [rsi]
+ mov r9, [rsi+8]
+ mov r10, [rsi+16]
+ mov r11, [rsi+24]
+ add rdx, [rsi+32]
+ adc r9, [rsi+40]
+ adc r10, [rsi+48]
+ adc r11, [rsi+56]
+ mov [rdi], rdx
+ mov [rdi+8], r9
+ mov [rdi+16], r10
+ mov [rdi+24], r11
+
+ // a0 - a1 + 2p
+ mov r8, [rsi]
+ mov r10, [rsi+8]
+ mov r12, [rsi+16]
+ mov r13, [rsi+24]
+ sub r8, [rsi+32]
+ sbb r10, [rsi+40]
+ sbb r12, [rsi+48]
+ sbb r13, [rsi+56]
+ mov rax, [rip+p2]
+ add r8, rax
+ mov rax, [rip+p2+8]
+ adc r10, rax
+ adc r12, rax
+ adc r13, [rip+p2+24]
+ mov [rdi+32], r8
+ mov [rdi+40], r10
+ mov [rdi+48], r12
+ mov [rdi+56], r13
+
+ // [r8:r12] <- z = a00 x a1
+ mulx r9, r8, r8
+ xor rax, rax
+ mulx r10, r11, r10
+ adox r9, r11
+ mulx r11, r12, r12
+ adox r10, r12
+ mulx r12, r13, r13
+ adox r11, r13
+ adox r12, rax
+
+ FPMUL256x256 [rdi], [rdi+32], r8, r9, r10, r11, r12, r13, rcx
+
+ mov [rdi], r12
+ mov [rdi+8], r8
+ mov [rdi+16], r9
+ mov [rdi+24], r10
+ pop r13
+ pop r12
+ ret
+
+//***********************************************************************
+// Squaring in GF(p^2), complex part
+// Operation: c [rdi] = 2a0 x a1
+// Inputs: a = [a1, a0] stored in [reg_p1]
+// Output: c stored in [rdi]
+//***********************************************************************
+.global fp2_sq_c1
+fp2_sq_c1:
+ push r12
+ push r13
+
+ mov rdx, [rsi]
+ mov r9, [rsi+8]
+ mov r10, [rsi+16]
+ mov r11, [rsi+24]
+ add rdx, rdx
+ adc r9, r9
+ adc r10, r10
+ adc r11, r11
+ sub rsp, 32
+ mov [rsp+8], r9
+ mov [rsp+16], r10
+ mov [rsp+24], r11
+
+ // [r8:r12] <- z = a00 x a1
+ mulx r9, r8, [rsi+32]
+ xor rax, rax
+ mulx r10, r11, [rsi+40]
+ adox r9, r11
+ mulx r11, r12, [rsi+48]
+ adox r10, r12
+ mulx r12, r13, [rsi+56]
+ adox r11, r13
+ adox r12, rax
+
+ FPMUL256x256 [rsp], [rsi+32], r8, r9, r10, r11, r12, r13, rcx
+ add rsp, 32
+
+ mov [rdi], r12
+ mov [rdi+8], r8
+ mov [rdi+16], r9
+ mov [rdi+24], r10
+ pop r13
+ pop r12
+ ret
+
+//***********************************************************************
+// Field multiplication in GF(p)
+// Operation: c = a x b mod p
+// Inputs: a stored in [rsi], b stored in [rdx]
+// Output: c stored in [rdi]
+//***********************************************************************
+.global fp_mul
+fp_mul:
+ push r12
+ push r13
+ push r14
+ mov rcx, rdx
+
+ // [r8:r12] <- z = a x b0
+ mov rdx, [rcx]
+ mulx r9, r8, [rsi]
+ xor rax, rax
+ mulx r10, r11, [rsi+8]
+ adox r9, r11
+ mulx r11, r12, [rsi+16]
+ adox r10, r12
+ mulx r12, r13, [rsi+24]
+ adox r11, r13
+ adox r12, rax
+
+ FPMUL256x256 [rcx], [rsi], r8, r9, r10, r11, r12, r13, r14
+
+ mov [rdi], r12
+ mov [rdi+8], r8
+ mov [rdi+16], r9
+ mov [rdi+24], r10
+ pop r14
+ pop r13
+ pop r12
+ ret
+
+.global fp_sqr
+fp_sqr:
+ mov rdx, rsi
+ jmp fp_mul
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp_constants.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp_constants.h
new file mode 100644
index 0000000000..c770b78f58
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/fp_constants.h
@@ -0,0 +1,17 @@
+#if RADIX == 32
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+#define NWORDS_FIELD 8
+#else
+#define NWORDS_FIELD 9
+#endif
+#define NWORDS_ORDER 8
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+#define NWORDS_FIELD 4
+#else
+#define NWORDS_FIELD 5
+#endif
+#define NWORDS_ORDER 4
+#endif
+#define BITS 256
+#define LOG2P 8
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/gf5248.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/gf5248.c
new file mode 100644
index 0000000000..901d5ea5e2
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/gf5248.c
@@ -0,0 +1,767 @@
+/*
+ * This code is derived from discussions with Thomas Pornin
+ */
+
+#include "gf5248.h"
+
+// see gf5248.h
+const gf5248 ZERO = {{ 0, 0, 0, 0 }};
+
+// see gf5248.h
+const gf5248 ONE = {{ 0x0000000000000033, 0x0000000000000000, 0x0000000000000000, 0x0100000000000000 }};
+
+// see gf5248.h
+const gf5248 gf5248_MINUS_ONE = {{ 0xFFFFFFFFFFFFFFCC, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x03FFFFFFFFFFFFFF }};
+
+// Montgomery representation of 2^256.
+static const gf5248 R2 = {{ 0x3333333333333d70, 0x3333333333333333, 0x3333333333333333, 0x0333333333333333 }};
+
+// The modulus itself (this is also a valid representation of zero).
+static const gf5248 MODULUS = {{ 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x04FFFFFFFFFFFFFF }};
+
+// 1/2^244 (in Montgomery representation).
+static const gf5248 INVT244 = {{ 0x0000000000001000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 }};
+
+static const gf5248 PM1O3 = {{ 0xaaaaaaaaaaaaaaaa, 0xaaaaaaaaaaaaaaaa, 0xaaaaaaaaaaaaaaaa, 0x01aaaaaaaaaaaaaa }};
+
+// Normalize value *a into *d.
+static inline void
+inner_gf5248_normalize(gf5248 *d, const gf5248 *a)
+{
+ uint64_t d0, d1, d2, d3, m;
+ unsigned char cc;
+
+ // Subtract q.
+ cc = inner_gf5248_sbb(0, a->v0, 0xFFFFFFFFFFFFFFFF, &d0);
+ cc = inner_gf5248_sbb(cc, a->v1, 0xFFFFFFFFFFFFFFFF, &d1);
+ cc = inner_gf5248_sbb(cc, a->v2, 0xFFFFFFFFFFFFFFFF, &d2);
+ cc = inner_gf5248_sbb(cc, a->v3, 0x04FFFFFFFFFFFFFF, &d3);
+
+ // Add back q if the result is negative.
+ (void)inner_gf5248_sbb(cc, 0, 0, &m);
+ cc = inner_gf5248_adc(0, d0, m, &d0);
+ cc = inner_gf5248_adc(cc, d1, m, &d1);
+ cc = inner_gf5248_adc(cc, d2, m, &d2);
+ (void)inner_gf5248_adc(cc, d3, m & 0x04FFFFFFFFFFFFFF, &d3);
+
+ d->v0 = d0;
+ d->v1 = d1;
+ d->v2 = d2;
+ d->v3 = d3;
+}
+
+// Expand the most significant bit of x into a full-width 64-bit word
+// (0x0000000000000000 or 0xFFFFFFFFFFFFFFFF).
+static inline uint64_t
+sgnw(uint64_t x)
+{
+ return (uint64_t)(*(int64_t *)&x >> 63);
+}
+
+// d <- u*f + v*g (in the field)
+// Coefficients f and g are provided as unsigned integers, but they
+// really are signed values which must be less than 2^62 (in absolute value).
+static void
+gf5248_lin(gf5248 *d, const gf5248 *u, const gf5248 *v, uint64_t f, uint64_t g)
+{
+ // f <- abs(f), keeping the sign in sf, and negating u accordingly
+ uint64_t sf = sgnw(f);
+ f = (f ^ sf) - sf;
+ gf5248 tu;
+ gf5248_neg(&tu, u);
+ gf5248_select(&tu, u, &tu, (uint32_t)sf);
+
+ // g <- abs(g), keeping the sign in sg, and negating v accordingly
+ uint64_t sg = sgnw(g);
+ g = (g ^ sg) - sg;
+ gf5248 tv;
+ gf5248_neg(&tv, v);
+ gf5248_select(&tv, v, &tv, (uint32_t)sg);
+
+ // Linear combination over plain integers.
+ uint64_t d0, d1, d2, d3, t;
+ inner_gf5248_umul_x2(d0, t, tu.v0, f, tv.v0, g);
+ inner_gf5248_umul_x2_add(d1, t, tu.v1, f, tv.v1, g, t);
+ inner_gf5248_umul_x2_add(d2, t, tu.v2, f, tv.v2, g, t);
+ inner_gf5248_umul_x2_add(d3, t, tu.v3, f, tv.v3, g, t);
+
+ // Reduction: split into low part (248 bits) and high part
+ // (71 bits, since t can be up to 63 bits). If the high
+ // part is h, then:
+ // h*2^248 = (h mod 5)*2^248 + floor(h/5) mod q
+ uint64_t h0 = (d3 >> 56) | (t << 8);
+ uint64_t h1 = t >> 56;
+ d3 &= 0x00FFFFFFFFFFFFFF;
+ uint64_t z0, z1, quo0, rem0, quo1, rem1;
+ inner_gf5248_umul(z0, z1, h0, 0xCCCCCCCCCCCCCCCD);
+ (void)z0;
+ quo0 = z1 >> 2;
+ rem0 = h0 - (5 * quo0);
+ quo1 = (h1 * 0xCD) >> 10;
+ rem1 = h1 - (5 * quo1);
+
+ // h = rem0 + 5*quo0 + (rem1 + 5*quo1)*2^64
+ // = rem0 + rem1 + 5*(quo0 + quo1*2^64 + rem1*((2^64 - 1)/5))
+ // We add rem0 and rem1 modulo 5, with an extra carry that
+ // goes into the folded part (multiple of 5).
+ uint64_t e, f0, f1;
+ unsigned char cc;
+ cc = inner_gf5248_adc(0, rem0 + 0xFFFFFFFFFFFFFFFA, rem1, &e);
+ cc = inner_gf5248_adc(cc, quo0, rem1 * 0x3333333333333333, &f0);
+ (void)inner_gf5248_adc(cc, quo1, 0, &f1);
+ e -= 0xFFFFFFFFFFFFFFFA;
+
+ // Now we only have to add e*2^248 + f0:f1 to the low part.
+ cc = inner_gf5248_adc(0, d0, f0, &d0);
+ cc = inner_gf5248_adc(cc, d1, f1, &d1);
+ cc = inner_gf5248_adc(cc, d2, 0, &d2);
+ (void)inner_gf5248_adc(cc, d3, e << 56, &d3);
+
+ d->v0 = d0;
+ d->v1 = d1;
+ d->v2 = d2;
+ d->v3 = d3;
+}
+
+// d <- abs(floor((a*f + b*g) / 2^31))
+// Coefficients f and g are provided as unsigned integer, but they really
+// are signed values, which MUST be at most 2^31 in absolute value.
+// The computation is performed over the integers, not modulo q. The low
+// 31 bits are dropped (in practice, callers provided appropriate coefficients
+// f and g such that a*f + b*g is a multiple of 2^31.
+//
+// If a*f + b*g is negative, then the absolute value is computed, and the
+// function returns 0xFFFFFFFFFFFFFFFF; otherwise, the function returns
+// 0x0000000000000000.
+static uint64_t
+lindiv31abs(gf5248 *d, const gf5248 *a, const gf5248 *b, uint64_t f, uint64_t g)
+{
+ // f <- abs(f), keeping the sign in sf
+ uint64_t sf = sgnw(f);
+ f = (f ^ sf) - sf;
+
+ // g <- abs(g), keeping the sign in sg
+ uint64_t sg = sgnw(g);
+ g = (g ^ sg) - sg;
+
+ // Apply the signs of f and g to the source operands.
+ uint64_t a0, a1, a2, a3, a4;
+ uint64_t b0, b1, b2, b3, b4;
+ unsigned char cc;
+
+ cc = inner_gf5248_sbb(0, a->v0 ^ sf, sf, &a0);
+ cc = inner_gf5248_sbb(cc, a->v1 ^ sf, sf, &a1);
+ cc = inner_gf5248_sbb(cc, a->v2 ^ sf, sf, &a2);
+ cc = inner_gf5248_sbb(cc, a->v3 ^ sf, sf, &a3);
+ (void)inner_gf5248_sbb(cc, 0, 0, &a4);
+
+ cc = inner_gf5248_sbb(0, b->v0 ^ sg, sg, &b0);
+ cc = inner_gf5248_sbb(cc, b->v1 ^ sg, sg, &b1);
+ cc = inner_gf5248_sbb(cc, b->v2 ^ sg, sg, &b2);
+ cc = inner_gf5248_sbb(cc, b->v3 ^ sg, sg, &b3);
+ (void)inner_gf5248_sbb(cc, 0, 0, &b4);
+
+ // Compute a*f + b*g into d0:d1:d2:d3:d4. Since f and g are at
+ // most 2^31, we can add two 128-bit products with no overflow.
+ // Note: a4 and b4 are both in {0, -1}.
+ uint64_t d0, d1, d2, d3, d4, t;
+ inner_gf5248_umul_x2(d0, t, a0, f, b0, g);
+ inner_gf5248_umul_x2_add(d1, t, a1, f, b1, g, t);
+ inner_gf5248_umul_x2_add(d2, t, a2, f, b2, g, t);
+ inner_gf5248_umul_x2_add(d3, t, a3, f, b3, g, t);
+ d4 = t - (a4 & f) - (b4 & g);
+
+ // Right-shift the value by 31 bits.
+ d0 = (d0 >> 31) | (d1 << 33);
+ d1 = (d1 >> 31) | (d2 << 33);
+ d2 = (d2 >> 31) | (d3 << 33);
+ d3 = (d3 >> 31) | (d4 << 33);
+
+ // If the result is negative, negate it.
+ t = sgnw(d4);
+ cc = inner_gf5248_sbb(0, d0 ^ t, t, &d0);
+ cc = inner_gf5248_sbb(cc, d1 ^ t, t, &d1);
+ cc = inner_gf5248_sbb(cc, d2 ^ t, t, &d2);
+ (void)inner_gf5248_sbb(cc, d3 ^ t, t, &d3);
+
+ d->v0 = d0;
+ d->v1 = d1;
+ d->v2 = d2;
+ d->v3 = d3;
+ return t;
+}
+
+// lzcnt(x) returns the number of leading bits of value 0 in x. It supports
+// x == 0 (in which case the function returns 64).
+#if defined __LZCNT__
+static inline uint64_t
+lzcnt(uint64_t x)
+{
+ return _lzcnt_u64(x);
+}
+#else
+static inline uint64_t
+lzcnt(uint64_t x)
+{
+ uint64_t m, s;
+ m = sgnw((x >> 32) - 1);
+ s = m & 32;
+ x = (x >> 32) ^ (m & (x ^ (x >> 32)));
+ m = sgnw((x >> 16) - 1);
+ s |= m & 16;
+ x = (x >> 16) ^ (m & (x ^ (x >> 16)));
+ m = sgnw((x >> 8) - 1);
+ s |= m & 8;
+ x = (x >> 8) ^ (m & (x ^ (x >> 8)));
+ m = sgnw((x >> 4) - 1);
+ s |= m & 4;
+ x = (x >> 4) ^ (m & (x ^ (x >> 4)));
+ m = sgnw((x >> 2) - 1);
+ s |= m & 2;
+ x = (x >> 2) ^ (m & (x ^ (x >> 2)));
+
+ // At this point, x fits on 2 bits. Count of extra zeros:
+ // x = 0 -> 2
+ // x = 1 -> 1
+ // x = 2 -> 0
+ // x = 3 -> 0
+ s += (2 - x) & ((x - 3) >> 2);
+ return s;
+}
+#endif
+
+// see gf5248.h
+uint32_t
+gf5248_div(gf5248 *d, const gf5248 *x, const gf5248 *y)
+{
+ // Extended binary GCD:
+ //
+ // a <- y
+ // b <- q (modulus)
+ // u <- x (self)
+ // v <- 0
+ //
+ // Value a is normalized (in the 0..q-1 range). Values a and b are
+ // then considered as (signed) integers. Values u and v are field
+ // elements.
+ //
+ // Invariants:
+ // a*x = y*u mod q
+ // b*x = y*v mod q
+ // b is always odd
+ //
+ // At each step:
+ // if a is even, then:
+ // a <- a/2, u <- u/2 mod q
+ // else:
+ // if a < b:
+ // (a, u, b, v) <- (b, v, a, u)
+ // a <- (a-b)/2, u <- (u-v)/2 mod q
+ //
+ // What we implement below is the optimized version of this
+ // algorithm, as described in https://eprint.iacr.org/2020/972
+
+ gf5248 a, b, u, v;
+ uint64_t xa, xb, f0, g0, f1, g1;
+ uint32_t r;
+
+ r = ~gf5248_iszero(y);
+ inner_gf5248_normalize(&a, y);
+ b = MODULUS;
+ u = *x;
+ v = ZERO;
+
+ // Generic loop does 15*31 = 465 inner iterations.
+ for (int i = 0; i < 15; i++) {
+ // Get approximations of a and b over 64 bits:
+ // - If len(a) <= 64 and len(b) <= 64, then we just use
+ // their values (low limbs).
+ // - Otherwise, with n = max(len(a), len(b)), we use:
+ // (a mod 2^31) + 2^31*floor(a / 2^(n - 33))
+ // (b mod 2^31) + 2^31*floor(b / 2^(n - 33))
+ uint64_t m3 = a.v3 | b.v3;
+ uint64_t m2 = a.v2 | b.v2;
+ uint64_t m1 = a.v1 | b.v1;
+ uint64_t tnz3 = sgnw(m3 | -m3);
+ uint64_t tnz2 = sgnw(m2 | -m2) & ~tnz3;
+ uint64_t tnz1 = sgnw(m1 | -m1) & ~tnz3 & ~tnz2;
+ uint64_t tnzm = (m3 & tnz3) | (m2 & tnz2) | (m1 & tnz1);
+ uint64_t tnza = (a.v3 & tnz3) | (a.v2 & tnz2) | (a.v1 & tnz1);
+ uint64_t tnzb = (b.v3 & tnz3) | (b.v2 & tnz2) | (b.v1 & tnz1);
+ uint64_t snza = (a.v2 & tnz3) | (a.v1 & tnz2) | (a.v0 & tnz1);
+ uint64_t snzb = (b.v2 & tnz3) | (b.v1 & tnz2) | (b.v0 & tnz1);
+
+ // If both len(a) <= 64 and len(b) <= 64, then:
+ // tnzm = 0
+ // tnza = 0, snza = 0, tnzb = 0, snzb = 0
+ // Otherwise:
+ // tnzm != 0
+ // tnza contains the top non-zero limb of a
+ // snza contains the limb right below tnza
+ // tnzb contains the top non-zero limb of a
+ // snzb contains the limb right below tnzb
+ //
+ // We count the number of leading zero bits in tnzm:
+ // - If s <= 31, then the top 31 bits can be extracted from
+ // tnza and tnzb alone.
+ // - If 32 <= s <= 63, then we need some bits from snza and
+ // snzb as well.
+ int64_t s = lzcnt(tnzm);
+ uint64_t sm = (uint64_t)((31 - s) >> 63);
+ tnza ^= sm & (tnza ^ ((tnza << 32) | (snza >> 32)));
+ tnzb ^= sm & (tnzb ^ ((tnzb << 32) | (snzb >> 32)));
+ s -= 32 & sm;
+ tnza <<= s;
+ tnzb <<= s;
+
+ // At this point:
+ // - If len(a) <= 64 and len(b) <= 64, then:
+ // tnza = 0
+ // tnzb = 0
+ // tnz1 = tnz2 = tnz3 = 0
+ // we want to use the entire low words of a and b
+ // - Otherwise, we want to use the top 33 bits of tnza and
+ // tnzb, and the low 31 bits of the low words of a and b.
+ uint64_t tzx = ~(tnz1 | tnz2 | tnz3);
+ tnza |= a.v0 & tzx;
+ tnzb |= b.v0 & tzx;
+ xa = (a.v0 & 0x7FFFFFFF) | (tnza & 0xFFFFFFFF80000000);
+ xb = (b.v0 & 0x7FFFFFFF) | (tnzb & 0xFFFFFFFF80000000);
+
+ // Compute the 31 inner iterations on xa and xb.
+ uint64_t fg0 = (uint64_t)1;
+ uint64_t fg1 = (uint64_t)1 << 32;
+ for (int j = 0; j < 31; j++) {
+ uint64_t a_odd, swap, t0, t1, t2;
+ unsigned char cc;
+ a_odd = -(xa & 1);
+ cc = inner_gf5248_sbb(0, xa, xb, &t0);
+ (void)inner_gf5248_sbb(cc, 0, 0, &swap);
+ swap &= a_odd;
+ t1 = swap & (xa ^ xb);
+ xa ^= t1;
+ xb ^= t1;
+ t2 = swap & (fg0 ^ fg1);
+ fg0 ^= t2;
+ fg1 ^= t2;
+ xa -= a_odd & xb;
+ fg0 -= a_odd & fg1;
+ xa >>= 1;
+ fg1 <<= 1;
+ }
+ fg0 += 0x7FFFFFFF7FFFFFFF;
+ fg1 += 0x7FFFFFFF7FFFFFFF;
+ f0 = (fg0 & 0xFFFFFFFF) - (uint64_t)0x7FFFFFFF;
+ g0 = (fg0 >> 32) - (uint64_t)0x7FFFFFFF;
+ f1 = (fg1 & 0xFFFFFFFF) - (uint64_t)0x7FFFFFFF;
+ g1 = (fg1 >> 32) - (uint64_t)0x7FFFFFFF;
+
+ // Propagate updates to a, b, u and v.
+ gf5248 na, nb, nu, nv;
+ uint64_t nega = lindiv31abs(&na, &a, &b, f0, g0);
+ uint64_t negb = lindiv31abs(&nb, &a, &b, f1, g1);
+ f0 = (f0 ^ nega) - nega;
+ g0 = (g0 ^ nega) - nega;
+ f1 = (f1 ^ negb) - negb;
+ g1 = (g1 ^ negb) - negb;
+ gf5248_lin(&nu, &u, &v, f0, g0);
+ gf5248_lin(&nv, &u, &v, f1, g1);
+ a = na;
+ b = nb;
+ u = nu;
+ v = nv;
+ }
+
+ // If y is invertible, then the final GCD is 1, and
+ // len(a) + len(b) <= 37, so we can end the computation with
+ // the low words directly. We only need 35 iterations to reach
+ // the point where b = 1.
+ //
+ // If y is zero, then v is unchanged (hence zero) and none of
+ // the subsequent iterations will change it either, so we get
+ // 0 on output, which is what we want.
+ xa = a.v0;
+ xb = b.v0;
+ f0 = 1;
+ g0 = 0;
+ f1 = 0;
+ g1 = 1;
+ for (int j = 0; j < 35; j++) {
+ uint64_t a_odd, swap, t0, t1, t2, t3;
+ unsigned char cc;
+ a_odd = -(xa & 1);
+ cc = inner_gf5248_sbb(0, xa, xb, &t0);
+ (void)inner_gf5248_sbb(cc, 0, 0, &swap);
+ swap &= a_odd;
+ t1 = swap & (xa ^ xb);
+ xa ^= t1;
+ xb ^= t1;
+ t2 = swap & (f0 ^ f1);
+ f0 ^= t2;
+ f1 ^= t2;
+ t3 = swap & (g0 ^ g1);
+ g0 ^= t3;
+ g1 ^= t3;
+ xa -= a_odd & xb;
+ f0 -= a_odd & f1;
+ g0 -= a_odd & g1;
+ xa >>= 1;
+ f1 <<= 1;
+ g1 <<= 1;
+ }
+ gf5248_lin(d, &u, &v, f1, g1);
+
+ // At the point:
+ // - Numerator and denominator were both in Montgomery representation,
+ // but the two factors R canceled each other.
+ // - We have injected 31*15+35 = 500 extra factors of 2, hence we
+ // must divide the result by 2^500.
+ // - However, we also want to obtain the result in Montgomery
+ // representation, i.e. multiply by 2^256. We thus want to
+ // divide the current result by 2^(500 - 256) = 2^244.
+ // - We do this division by using a Montgomery multiplication with
+ // the Montgomery representation of 1/2^244, i.e. the integer
+ // 2^256/2^244 = 4096.
+ gf5248_mul(d, d, &INVT244);
+ return r;
+}
+
+// see gf5248.h
+uint32_t
+gf5248_invert(gf5248 *d, const gf5248 *a)
+{
+ return gf5248_div(d, &ONE, a);
+}
+
+// see gf5248.h
+int32_t
+gf5248_legendre(const gf5248 *x)
+{
+ // Same algorithm as the binary GCD in gf5248_div(), with
+ // a few differences:
+ // - We do not keep track of the Bézout coefficients u and v.
+ // - In each inner iteration we adjust the running symbol value,
+ // which uses the low 3 bits of the values.
+ // - Since we need two extra bits of look-ahead, we can only run
+ // 29 inner iterations, and then need an extra recomputation
+ // for the last 2.
+
+ gf5248 a, b;
+ uint64_t xa, xb, f0, g0, f1, g1, ls;
+
+ inner_gf5248_normalize(&a, x);
+ b = MODULUS;
+ ls = 0; // running symbol information in bit 1.
+
+ // Outer loop
+ for (int i = 0; i < 15; i++) {
+ // Get approximations of a and b over 64 bits.
+ uint64_t m3 = a.v3 | b.v3;
+ uint64_t m2 = a.v2 | b.v2;
+ uint64_t m1 = a.v1 | b.v1;
+ uint64_t tnz3 = sgnw(m3 | -m3);
+ uint64_t tnz2 = sgnw(m2 | -m2) & ~tnz3;
+ uint64_t tnz1 = sgnw(m1 | -m1) & ~tnz3 & ~tnz2;
+ uint64_t tnzm = (m3 & tnz3) | (m2 & tnz2) | (m1 & tnz1);
+ uint64_t tnza = (a.v3 & tnz3) | (a.v2 & tnz2) | (a.v1 & tnz1);
+ uint64_t tnzb = (b.v3 & tnz3) | (b.v2 & tnz2) | (b.v1 & tnz1);
+ uint64_t snza = (a.v2 & tnz3) | (a.v1 & tnz2) | (a.v0 & tnz1);
+ uint64_t snzb = (b.v2 & tnz3) | (b.v1 & tnz2) | (b.v0 & tnz1);
+
+ int64_t s = lzcnt(tnzm);
+ uint64_t sm = (uint64_t)((31 - s) >> 63);
+ tnza ^= sm & (tnza ^ ((tnza << 32) | (snza >> 32)));
+ tnzb ^= sm & (tnzb ^ ((tnzb << 32) | (snzb >> 32)));
+ s -= 32 & sm;
+ tnza <<= s;
+ tnzb <<= s;
+
+ uint64_t tzx = ~(tnz1 | tnz2 | tnz3);
+ tnza |= a.v0 & tzx;
+ tnzb |= b.v0 & tzx;
+ xa = (a.v0 & 0x7FFFFFFF) | (tnza & 0xFFFFFFFF80000000);
+ xb = (b.v0 & 0x7FFFFFFF) | (tnzb & 0xFFFFFFFF80000000);
+
+ // First 290 inner iterations.
+ uint64_t fg0 = (uint64_t)1;
+ uint64_t fg1 = (uint64_t)1 << 32;
+ for (int j = 0; j < 29; j++) {
+ uint64_t a_odd, swap, t0, t1, t2;
+ unsigned char cc;
+ a_odd = -(xa & 1);
+ cc = inner_gf5248_sbb(0, xa, xb, &t0);
+ (void)inner_gf5248_sbb(cc, 0, 0, &swap);
+ swap &= a_odd;
+ ls ^= swap & xa & xb;
+ t1 = swap & (xa ^ xb);
+ xa ^= t1;
+ xb ^= t1;
+ t2 = swap & (fg0 ^ fg1);
+ fg0 ^= t2;
+ fg1 ^= t2;
+ xa -= a_odd & xb;
+ fg0 -= a_odd & fg1;
+ xa >>= 1;
+ fg1 <<= 1;
+ ls ^= (xb + 2) >> 1;
+ }
+
+ // Compute the updated a and b (low words only) to get
+ // enough bits for the next two iterations.
+ uint64_t fg0z = fg0 + 0x7FFFFFFF7FFFFFFF;
+ uint64_t fg1z = fg1 + 0x7FFFFFFF7FFFFFFF;
+ f0 = (fg0z & 0xFFFFFFFF) - (uint64_t)0x7FFFFFFF;
+ g0 = (fg0z >> 32) - (uint64_t)0x7FFFFFFF;
+ f1 = (fg1z & 0xFFFFFFFF) - (uint64_t)0x7FFFFFFF;
+ g1 = (fg1z >> 32) - (uint64_t)0x7FFFFFFF;
+ uint64_t a0 = (a.v0 * f0 + b.v0 * g0) >> 29;
+ uint64_t b0 = (a.v0 * f1 + b.v0 * g1) >> 29;
+ for (int j = 0; j < 2; j++) {
+ uint64_t a_odd, swap, t0, t1, t2, t3;
+ unsigned char cc;
+ a_odd = -(xa & 1);
+ cc = inner_gf5248_sbb(0, xa, xb, &t0);
+ (void)inner_gf5248_sbb(cc, 0, 0, &swap);
+ swap &= a_odd;
+ ls ^= swap & a0 & b0;
+ t1 = swap & (xa ^ xb);
+ xa ^= t1;
+ xb ^= t1;
+ t2 = swap & (fg0 ^ fg1);
+ fg0 ^= t2;
+ fg1 ^= t2;
+ t3 = swap & (a0 ^ b0);
+ a0 ^= t3;
+ b0 ^= t3;
+ xa -= a_odd & xb;
+ fg0 -= a_odd & fg1;
+ a0 -= a_odd & b0;
+ xa >>= 1;
+ fg1 <<= 1;
+ a0 >>= 1;
+ ls ^= (b0 + 2) >> 1;
+ }
+
+ // Propagate updates to a and b.
+ fg0 += 0x7FFFFFFF7FFFFFFF;
+ fg1 += 0x7FFFFFFF7FFFFFFF;
+ f0 = (fg0 & 0xFFFFFFFF) - (uint64_t)0x7FFFFFFF;
+ g0 = (fg0 >> 32) - (uint64_t)0x7FFFFFFF;
+ f1 = (fg1 & 0xFFFFFFFF) - (uint64_t)0x7FFFFFFF;
+ g1 = (fg1 >> 32) - (uint64_t)0x7FFFFFFF;
+ gf5248 na, nb;
+ uint64_t nega = lindiv31abs(&na, &a, &b, f0, g0);
+ (void)lindiv31abs(&nb, &a, &b, f1, g1);
+ ls ^= nega & nb.v0;
+ a = na;
+ b = nb;
+ }
+
+ // Final iterations: values are at most 37 bits now. We do not
+ // need to keep track of update coefficients. Just like the GCD,
+ // we need only 35 iterations, because after 35 iterations,
+ // value a is 0 or 1, and b is 1, and no further modification to
+ // the Legendre symbol may happen.
+ xa = a.v0;
+ xb = b.v0;
+ for (int j = 0; j < 35; j++) {
+ uint64_t a_odd, swap, t0, t1;
+ unsigned char cc;
+ a_odd = -(xa & 1);
+ cc = inner_gf5248_sbb(0, xa, xb, &t0);
+ (void)inner_gf5248_sbb(cc, 0, 0, &swap);
+ swap &= a_odd;
+ ls ^= swap & xa & xb;
+ t1 = swap & (xa ^ xb);
+ xa ^= t1;
+ xb ^= t1;
+ xa -= a_odd & xb;
+ xa >>= 1;
+ ls ^= (xb + 2) >> 1;
+ }
+
+ // At this point, if the source value was not zero, then the low
+ // bit of ls contains the QR status (0 = square, 1 = non-square),
+ // which we need to convert to the expected value (+1 or -1).
+ // If y == 0, then we return 0, per the API.
+ uint32_t r = 1 - ((uint32_t)ls & 2);
+ r &= ~gf5248_iszero(x);
+ return *(int32_t *)&r;
+}
+
+// see gf5248.h
+uint32_t
+gf5248_sqrt(gf5248 *d, const gf5248 *a)
+{
+ // Candidate root is a^((q+1)/4), with (q+1)/4 = 5*2^246
+ gf5248 y;
+ gf5248_xsquare(&y, a, 2);
+ gf5248_mul(&y, &y, a);
+ gf5248_xsquare(&y, &y, 246);
+
+ // Normalize y and negate if necessary, to set the low bit to 0.
+ // The low bit check must be on the normal representation,
+ // not the Montgomery representation.
+ gf5248 yn;
+ inner_gf5248_montgomery_reduce(&yn, &y);
+ uint32_t ctl = -((uint32_t)yn.v0 & 1);
+ gf5248_neg(&yn, &y);
+ gf5248_select(&y, &y, &yn, ctl);
+
+ // Check whether the candidate is indeed a square root.
+ gf5248_square(&yn, &y);
+ uint32_t r = gf5248_equals(&yn, a);
+ *d = y;
+ return r;
+}
+
+// Little-endian encoding of a 64-bit integer.
+static inline void
+enc64le(void *dst, uint64_t x)
+{
+ uint8_t *buf = dst;
+ buf[0] = (uint8_t)x;
+ buf[1] = (uint8_t)(x >> 8);
+ buf[2] = (uint8_t)(x >> 16);
+ buf[3] = (uint8_t)(x >> 24);
+ buf[4] = (uint8_t)(x >> 32);
+ buf[5] = (uint8_t)(x >> 40);
+ buf[6] = (uint8_t)(x >> 48);
+ buf[7] = (uint8_t)(x >> 56);
+}
+
+// Little-endian decoding of a 64-bit integer.
+static inline uint64_t
+dec64le(const void *src)
+{
+ const uint8_t *buf = src;
+ return (uint64_t)buf[0] | ((uint64_t)buf[1] << 8) | ((uint64_t)buf[2] << 16) | ((uint64_t)buf[3] << 24) |
+ ((uint64_t)buf[4] << 32) | ((uint64_t)buf[5] << 40) | ((uint64_t)buf[6] << 48) | ((uint64_t)buf[7] << 56);
+}
+
+// see gf5248.h
+void
+gf5248_encode(void *dst, const gf5248 *a)
+{
+ uint8_t *buf = dst;
+ gf5248 x;
+
+ inner_gf5248_montgomery_reduce(&x, a);
+ enc64le(buf, x.v0);
+ enc64le(buf + 8, x.v1);
+ enc64le(buf + 16, x.v2);
+ enc64le(buf + 24, x.v3);
+}
+
+// see gf5248.h
+uint32_t
+gf5248_decode(gf5248 *d, const void *src)
+{
+ const uint8_t *buf = src;
+ uint64_t d0, d1, d2, d3, t;
+ unsigned char cc;
+
+ d0 = dec64le(buf);
+ d1 = dec64le(buf + 8);
+ d2 = dec64le(buf + 16);
+ d3 = dec64le(buf + 24);
+ cc = inner_gf5248_sbb(0, d0, MODULUS.v0, &t);
+ cc = inner_gf5248_sbb(cc, d1, MODULUS.v1, &t);
+ cc = inner_gf5248_sbb(cc, d2, MODULUS.v2, &t);
+ cc = inner_gf5248_sbb(cc, d3, MODULUS.v3, &t);
+ (void)inner_gf5248_sbb(cc, 0, 0, &t);
+
+ // If the value was not canonical then t = 0; otherwise, t = -1.
+ d->v0 = d0 & t;
+ d->v1 = d1 & t;
+ d->v2 = d2 & t;
+ d->v3 = d3 & t;
+
+ // Convert to Montgomery representation.
+ gf5248_mul(d, d, &R2);
+
+ return (uint32_t)t;
+}
+
+// see gf5248.h
+void
+gf5248_decode_reduce(gf5248 *d, const void *src, size_t len)
+{
+ const uint8_t *buf = src;
+
+ *d = ZERO;
+ if (len == 0) {
+ return;
+ }
+
+ if ((len & 31) != 0) {
+ // Input size is not a multiple of 32, we decode a partial
+ // block, which is already less than 2^248.
+ uint8_t tmp[32];
+ size_t k;
+
+ k = len & ~(size_t)31;
+ memcpy(tmp, buf + k, len - k);
+ memset(tmp + len - k, 0, (sizeof tmp) - (len - k));
+ d->v0 = dec64le(&tmp[0]);
+ d->v1 = dec64le(&tmp[8]);
+ d->v2 = dec64le(&tmp[16]);
+ d->v3 = dec64le(&tmp[24]);
+ len = k;
+ } else {
+ // Input size is a multiple of 32, we decode a full block,
+ // and a reduction is needed.
+ len -= 32;
+ uint64_t d0 = dec64le(buf + len);
+ uint64_t d1 = dec64le(buf + len + 8);
+ uint64_t d2 = dec64le(buf + len + 16);
+ uint64_t d3 = dec64le(buf + len + 24);
+ inner_gf5248_partial_reduce(d, d0, d1, d2, d3);
+ }
+
+ // Process all remaining blocks, in descending address order.
+ while (len > 0) {
+ gf5248_mul(d, d, &R2);
+ len -= 32;
+ uint64_t t0 = dec64le(buf + len);
+ uint64_t t1 = dec64le(buf + len + 8);
+ uint64_t t2 = dec64le(buf + len + 16);
+ uint64_t t3 = dec64le(buf + len + 24);
+ gf5248 t;
+ inner_gf5248_partial_reduce(&t, t0, t1, t2, t3);
+ gf5248_add(d, d, &t);
+ }
+
+ // Final conversion to Montgomery representation.
+ gf5248_mul(d, d, &R2);
+}
+
+void
+gf5248_div3(gf5248 *d, const gf5248 *a)
+{
+ const digit_t MAGIC = 0xAAAAAAAAAAAAAAAB; // 3^-1 mod 2^64
+ uint64_t c0, c1, f0, f1;
+ gf5248 t;
+
+ inner_gf5248_umul(f0, f1, a->arr[3], MAGIC);
+ t.arr[3] = f1 >> 1;
+ c1 = a->arr[3] - 3 * t.arr[3];
+
+ for (int32_t i = 2; i >= 0; i--) {
+ c0 = c1;
+ inner_gf5248_umul(f0, f1, a->arr[i], MAGIC);
+ t.arr[i] = f1 >> 1;
+ c1 = c0 + a->arr[i] - 3 * t.arr[i];
+ t.arr[i] += c0 * ((MAGIC - 1) >> 1);
+ f0 = ((c1 >> 1) & c1); /* c1 == 3 */
+ f1 = ((c1 >> 2) & !(c1 & 0x11)); /* c1 == 4 */
+ f0 |= f1;
+ t.arr[i] += f0;
+ c1 = c1 - 3 * f0;
+ }
+ *d = t;
+ gf5248_sub(&t, d, &PM1O3);
+ gf5248_select(d, d, &t, -((c1 & 1) | (c1 >> 1))); // c1 >= 1
+ gf5248_sub(&t, d, &PM1O3);
+ gf5248_select(d, d, &t, -(c1 == 2));
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/gf5248.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/gf5248.h
new file mode 100644
index 0000000000..a2e561757c
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/gf5248.h
@@ -0,0 +1,943 @@
+/*
+ * This code is derived from discussions with Thomas Pornin
+ */
+
+#ifndef gf5248_h__
+#define gf5248_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include
+#include
+#include
+#include
+
+ typedef uint64_t digit_t; // Datatype for representing field elements
+
+ /*
+ * A gf5248 instance represents an integer modulo q.
+ * This is a structure; it can be copied with a simple assignment, and
+ * passed around as a value (though exchanging pointers is possibly more
+ * efficient).
+ * The contents are opaque. No calling code should make any assumption
+ * about the contents.
+ */
+
+ typedef union
+ {
+ // Contents are opaque.
+ // Implementation note: this encodes the value in Montgomery
+ // representation, with R = 2^256, and partially reduced (value
+ // is less than 2^251, but not necessarily less than q).
+ struct
+ {
+ uint64_t v0;
+ uint64_t v1;
+ uint64_t v2;
+ uint64_t v3;
+ };
+ digit_t arr[4];
+ } gf5248;
+
+ /*
+ * Constant zero (in the field).
+ */
+ extern const gf5248 ZERO;
+
+ /*
+ * Constant one (in the field).
+ */
+ extern const gf5248 ONE;
+
+ /*
+ * Constant -1 (in the field).
+ */
+ extern const gf5248 gf5248_MINUS_ONE;
+
+ /*
+ * API RULES:
+ * ==========
+ *
+ * Elementary operations on field elements are implemented by functions
+ * which take as parameter pointers to the operands. The first parameter
+ * is the pointer to the destination. Thus:
+ * gf5248 a = ...;
+ * gf5248 b = ...;
+ * gf5248 d;
+ * gf5248_sub(&d, &a, &b)
+ * sets field element d to a - b (implicitly modulo q).
+ *
+ * Operands may be used several times: it is always valid to use as
+ * output a gf5248 structure which is also used as input.
+ *
+ * Boolean values are represented by 32-bit integer (uint32_t) which have
+ * value exactly 0xFFFFFFFF (for "true") or 0x00000000 (for "false"). This
+ * convention minimizes the risk that a "smart" compiler breaks the
+ * constant-time property of the code through unfortunated optimizations.
+ * When a function expects such a Boolean, the caller MUST take care never
+ * to provide any value other than 0x00000000 or 0xFFFFFFFF.
+ *
+ * Values are encoded into exactly 32 bytes: value x modulo q is mapped to
+ * its unique integer representant in the [0..q-1] range, which is then
+ * encoded over 32 bytes with little-endian convention. Encoding is canonical
+ * and checked: when decoding (with gf5248_decode()), the input value is
+ * verified to be in the [0..q-1] range; for an out-of-range value,
+ * gf5248_decode() fills the output structure with zero, and returns
+ * 0x00000000.
+ *
+ * For most operations, the implementation is an inline function, defined
+ * below; the compiler can thus efficiently include it in the calling code.
+ * A few expensive operations (e.g. divisions) use non-inline functions,
+ * declared below but defined in gf5248.c
+ *
+ * All functions and macro whose name starts with "inner_gf5248_" are
+ * internal to this implementation and visible here only in order to
+ * support the API inline functions; they MUST NOT be used directly.
+ */
+
+#if (defined _MSC_VER && defined _M_X64) || (defined __x86_64__ && (defined __GNUC__ || defined __clang__)) || defined(C_PEDANTIC_MODE)
+#include
+#define inner_gf5248_adc(cc, a, b, d) _addcarry_u64(cc, a, b, (unsigned long long *)(void *)d)
+#define inner_gf5248_sbb(cc, a, b, d) _subborrow_u64(cc, a, b, (unsigned long long *)(void *)d)
+#else
+static inline unsigned char
+inner_gf5248_adc(unsigned char cc, uint64_t a, uint64_t b, uint64_t *d)
+{
+ unsigned __int128 t = (unsigned __int128)a + (unsigned __int128)b + cc;
+ *d = (uint64_t)t;
+ return (unsigned char)(t >> 64);
+}
+static inline unsigned char
+inner_gf5248_sbb(unsigned char cc, uint64_t a, uint64_t b, uint64_t *d)
+{
+ unsigned __int128 t = (unsigned __int128)a - (unsigned __int128)b - cc;
+ *d = (uint64_t)t;
+ return (unsigned char)(-(uint64_t)(t >> 64));
+}
+#endif
+
+#if defined _MSC_VER || defined(C_PEDANTIC_MODE)
+#if defined _MSC_VER
+#define inner_gf5248_umul(lo, hi, x, y) \
+ do { \
+ uint64_t umul_hi; \
+ (lo) = _umul128((x), (y), &umul_hi); \
+ (hi) = umul_hi; \
+ } while (0)
+#else
+#define inner_gf5248_umul(lo, hi, a, b) \
+ do { \
+ register uint64_t al, ah, bl, bh, temp; \
+ uint64_t albl, albh, ahbl, ahbh, res1, res2, res3, carry; \
+ uint64_t mask_low = (uint64_t)(-1) >> (sizeof(uint64_t) * 4), mask_high = (uint64_t)(-1) << (sizeof(uint64_t) * 4); \
+ al = a & mask_low; \
+ ah = a >> (sizeof(uint64_t) * 4); \
+ bl = b & mask_low; \
+ bh = b >> (sizeof(uint64_t) * 4); \
+ albl = al * bl; \
+ albh = al * bh; \
+ ahbl = ah * bl; \
+ ahbh = ah * bh; \
+ (lo) = albl & mask_low; \
+ res1 = albl >> (sizeof(uint64_t) * 4); \
+ res2 = ahbl & mask_low; \
+ res3 = albh & mask_low; \
+ temp = res1 + res2 + res3 ; \
+ carry = temp >> (sizeof(uint64_t) * 4); \
+ (lo) ^= temp << (sizeof(uint64_t) * 4); \
+ res1 = ahbl >> (sizeof(uint64_t) * 4); \
+ res2 = albh >> (sizeof(uint64_t) * 4); \
+ res3 = ahbh & mask_low; \
+ temp = res1 + res2 + res3 + carry; \
+ (hi) = temp & mask_low; \
+ carry = temp & mask_high; \
+ (hi) ^= (ahbh & mask_high) + carry; \
+ } while (0)
+#endif
+#define inner_gf5248_umul_add(lo, hi, x, y, z) \
+ do { \
+ uint64_t umul_lo, umul_hi; \
+ inner_gf5248_umul(umul_lo, umul_hi, (x), (y)); \
+ unsigned char umul_cc; \
+ umul_cc = inner_gf5248_adc(0, umul_lo, (z), &umul_lo); \
+ (void)inner_gf5248_adc(umul_cc, umul_hi, 0, &umul_hi); \
+ (lo) = umul_lo; \
+ (hi) = umul_hi; \
+ } while (0)
+#define inner_gf5248_umul_x2(lo, hi, x1, y1, x2, y2) \
+ do { \
+ uint64_t umul_lo, umul_hi; \
+ inner_gf5248_umul(umul_lo, umul_hi, (x1), (y1)); \
+ uint64_t umul_lo2, umul_hi2; \
+ inner_gf5248_umul(umul_lo2, umul_hi2, (x2), (y2)); \
+ unsigned char umul_cc; \
+ umul_cc = inner_gf5248_adc(0, umul_lo, umul_lo2, &umul_lo); \
+ (void)inner_gf5248_adc(umul_cc, umul_hi, umul_hi2, &umul_hi); \
+ (lo) = umul_lo; \
+ (hi) = umul_hi; \
+ } while (0)
+#define inner_gf5248_umul_x2_add(lo, hi, x1, y1, x2, y2, z) \
+ do { \
+ uint64_t umul_lo, umul_hi; \
+ inner_gf5248_umul(umul_lo, umul_hi, (x1), (y1)); \
+ uint64_t umul_lo2, umul_hi2; \
+ inner_gf5248_umul(umul_lo2, umul_hi2, (x2), (y2)); \
+ unsigned char umul_cc; \
+ umul_cc = inner_gf5248_adc(0, umul_lo, umul_lo2, &umul_lo); \
+ (void)inner_gf5248_adc(umul_cc, umul_hi, umul_hi2, &umul_hi); \
+ umul_cc = inner_gf5248_adc(0, umul_lo, (z), &umul_lo); \
+ (void)inner_gf5248_adc(umul_cc, umul_hi, 0, &umul_hi); \
+ (lo) = umul_lo; \
+ (hi) = umul_hi; \
+ } while (0)
+#else
+#define inner_gf5248_umul(lo, hi, x, y) \
+ do { \
+ unsigned __int128 umul_tmp; \
+ umul_tmp = (unsigned __int128)(x) * (unsigned __int128)(y); \
+ (lo) = (uint64_t)umul_tmp; \
+ (hi) = (uint64_t)(umul_tmp >> 64); \
+ } while (0)
+#define inner_gf5248_umul_add(lo, hi, x, y, z) \
+ do { \
+ unsigned __int128 umul_tmp; \
+ umul_tmp = (unsigned __int128)(x) * (unsigned __int128)(y) + (unsigned __int128)(uint64_t)(z); \
+ (lo) = (uint64_t)umul_tmp; \
+ (hi) = (uint64_t)(umul_tmp >> 64); \
+ } while (0)
+#define inner_gf5248_umul_x2(lo, hi, x1, y1, x2, y2) \
+ do { \
+ unsigned __int128 umul_tmp; \
+ umul_tmp = \
+ (unsigned __int128)(x1) * (unsigned __int128)(y1) + (unsigned __int128)(x2) * (unsigned __int128)(y2); \
+ (lo) = (uint64_t)umul_tmp; \
+ (hi) = (uint64_t)(umul_tmp >> 64); \
+ } while (0)
+#define inner_gf5248_umul_x2_add(lo, hi, x1, y1, x2, y2, z) \
+ do { \
+ unsigned __int128 umul_tmp; \
+ umul_tmp = (unsigned __int128)(x1) * (unsigned __int128)(y1) + \
+ (unsigned __int128)(x2) * (unsigned __int128)(y2) + (unsigned __int128)(uint64_t)(z); \
+ (lo) = (uint64_t)umul_tmp; \
+ (hi) = (uint64_t)(umul_tmp >> 64); \
+ } while (0)
+#endif
+
+ /*
+ * d <- a + b
+ */
+ static inline void
+ gf5248_add(gf5248 *d, const gf5248 *a, const gf5248 *b)
+ {
+ uint64_t d0, d1, d2, d3, f;
+ unsigned char cc;
+
+ // Raw addition.
+ cc = inner_gf5248_adc(0, a->v0, b->v0, &d0);
+ cc = inner_gf5248_adc(cc, a->v1, b->v1, &d1);
+ cc = inner_gf5248_adc(cc, a->v2, b->v2, &d2);
+ (void)inner_gf5248_adc(cc, a->v3, b->v3, &d3);
+
+ // Sum is up to 2^252 - 2. Subtract q if the value is not lower
+ // than 2^251 (we subtract q by adding -q).
+ f = d3 >> 59;
+ cc = inner_gf5248_adc(0, d0, f, &d0);
+ cc = inner_gf5248_adc(cc, d1, 0, &d1);
+ cc = inner_gf5248_adc(cc, d2, 0, &d2);
+ (void)inner_gf5248_adc(cc, d3, ((uint64_t)0xFB << 56) & -f, &d3);
+
+ // One subtraction of q might not be enough.
+ f = d3 >> 59;
+ cc = inner_gf5248_adc(0, d0, f, &d0);
+ cc = inner_gf5248_adc(cc, d1, 0, &d1);
+ cc = inner_gf5248_adc(cc, d2, 0, &d2);
+ (void)inner_gf5248_adc(cc, d3, ((uint64_t)0xFB << 56) & -f, &d3);
+
+ d->v0 = d0;
+ d->v1 = d1;
+ d->v2 = d2;
+ d->v3 = d3;
+ }
+
+ /*
+ * d <- a - b
+ */
+ static inline void
+ gf5248_sub(gf5248 *d, const gf5248 *a, const gf5248 *b)
+ {
+ uint64_t d0, d1, d2, d3, m, f;
+ unsigned char cc;
+
+ // Raw subtraction.
+ cc = inner_gf5248_sbb(0, a->v0, b->v0, &d0);
+ cc = inner_gf5248_sbb(cc, a->v1, b->v1, &d1);
+ cc = inner_gf5248_sbb(cc, a->v2, b->v2, &d2);
+ cc = inner_gf5248_sbb(cc, a->v3, b->v3, &d3);
+
+ // Add 2*q if the result is negative.
+ (void)inner_gf5248_sbb(cc, 0, 0, &m);
+ cc = inner_gf5248_sbb(0, d0, m & 2, &d0);
+ cc = inner_gf5248_sbb(cc, d1, 0, &d1);
+ cc = inner_gf5248_sbb(cc, d2, 0, &d2);
+ (void)inner_gf5248_sbb(cc, d3, ((uint64_t)0xF6 << 56) & m, &d3);
+
+ // We might have overdone it; subtract q if necessary.
+ f = d3 >> 59;
+ cc = inner_gf5248_adc(0, d0, f, &d0);
+ cc = inner_gf5248_adc(cc, d1, 0, &d1);
+ cc = inner_gf5248_adc(cc, d2, 0, &d2);
+ (void)inner_gf5248_adc(cc, d3, ((uint64_t)0xFB << 56) & -f, &d3);
+
+ d->v0 = d0;
+ d->v1 = d1;
+ d->v2 = d2;
+ d->v3 = d3;
+ }
+
+ /*
+ * d <- -a
+ */
+ static inline void
+ gf5248_neg(gf5248 *d, const gf5248 *a)
+ {
+ uint64_t d0, d1, d2, d3, f;
+ unsigned char cc;
+
+ // 2*q - a
+ cc = inner_gf5248_sbb(0, (uint64_t)0xFFFFFFFFFFFFFFFE, a->v0, &d0);
+ cc = inner_gf5248_sbb(cc, (uint64_t)0xFFFFFFFFFFFFFFFF, a->v1, &d1);
+ cc = inner_gf5248_sbb(cc, (uint64_t)0xFFFFFFFFFFFFFFFF, a->v2, &d2);
+ (void)inner_gf5248_sbb(cc, (uint64_t)0x09FFFFFFFFFFFFFF, a->v3, &d3);
+
+ // Subtract q if the value is not lower than 2^251.
+ f = d3 >> 59;
+ cc = inner_gf5248_adc(0, d0, f, &d0);
+ cc = inner_gf5248_adc(cc, d1, 0, &d1);
+ cc = inner_gf5248_adc(cc, d2, 0, &d2);
+ (void)inner_gf5248_adc(cc, d3, ((uint64_t)0xFB << 56) & -f, &d3);
+
+ d->v0 = d0;
+ d->v1 = d1;
+ d->v2 = d2;
+ d->v3 = d3;
+ }
+
+ /*
+ * If ctl == 0x00000000, then *a0 is copied into *d.
+ * If ctl == 0xFFFFFFFF, then *a1 is copied into *d.
+ * ctl MUST be either 0x00000000 or 0xFFFFFFFF.
+ */
+ static inline void
+ gf5248_select(gf5248 *d, const gf5248 *a0, const gf5248 *a1, uint32_t ctl)
+ {
+ uint64_t cw = (uint64_t)*(int32_t *)&ctl;
+ d->v0 = a0->v0 ^ (cw & (a0->v0 ^ a1->v0));
+ d->v1 = a0->v1 ^ (cw & (a0->v1 ^ a1->v1));
+ d->v2 = a0->v2 ^ (cw & (a0->v2 ^ a1->v2));
+ d->v3 = a0->v3 ^ (cw & (a0->v3 ^ a1->v3));
+ }
+
+ /*
+ * If ctl == 0x00000000, then *a and *b are unchanged.
+ * If ctl == 0xFFFFFFFF, then the contents of *a and *b are swapped.
+ * ctl MUST be either 0x00000000 or 0xFFFFFFFF.
+ */
+ static inline void
+ gf5248_cswap(gf5248 *a, gf5248 *b, uint32_t ctl)
+ {
+ uint64_t cw = (uint64_t)*(int32_t *)&ctl;
+ uint64_t t;
+ t = cw & (a->v0 ^ b->v0);
+ a->v0 ^= t;
+ b->v0 ^= t;
+ t = cw & (a->v1 ^ b->v1);
+ a->v1 ^= t;
+ b->v1 ^= t;
+ t = cw & (a->v2 ^ b->v2);
+ a->v2 ^= t;
+ b->v2 ^= t;
+ t = cw & (a->v3 ^ b->v3);
+ a->v3 ^= t;
+ b->v3 ^= t;
+ }
+
+ /*
+ * d <- a/2
+ */
+ static inline void
+ gf5248_half(gf5248 *d, const gf5248 *a)
+ {
+ uint64_t d0, d1, d2, d3;
+
+ d0 = (a->v0 >> 1) | (a->v1 << 63);
+ d1 = (a->v1 >> 1) | (a->v2 << 63);
+ d2 = (a->v2 >> 1) | (a->v3 << 63);
+ d3 = a->v3 >> 1;
+ d3 += ((uint64_t)5 << 55) & -(a->v0 & 1);
+ d->v0 = d0;
+ d->v1 = d1;
+ d->v2 = d2;
+ d->v3 = d3;
+ }
+
+ // Inner function: 256-bit to 251-bit reduction
+ static inline void
+ inner_gf5248_partial_reduce(gf5248 *d, uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3)
+ {
+ uint64_t d0, d1, d2, d3, h, quo, rem;
+ unsigned char cc;
+
+ // Split value in high (8 bits) and low (248 bits) parts.
+ h = a3 >> 56;
+ a3 &= 0x00FFFFFFFFFFFFFF;
+
+ // 5*2^248 = 1 mod q; hence, we add floor(h/5) + (h mod 5)*2^248
+ // to the low part.
+ quo = (h * 0xCD) >> 10;
+ rem = h - (5 * quo);
+ cc = inner_gf5248_adc(0, a0, quo, &d0);
+ cc = inner_gf5248_adc(cc, a1, 0, &d1);
+ cc = inner_gf5248_adc(cc, a2, 0, &d2);
+ (void)inner_gf5248_adc(cc, a3, rem << 56, &d3);
+
+ d->v0 = d0;
+ d->v1 = d1;
+ d->v2 = d2;
+ d->v3 = d3;
+ }
+
+ /*
+ * d <- 2*a
+ */
+ static inline void
+ gf5248_mul2(gf5248 *d, const gf5248 *a)
+ {
+ gf5248_add(d, a, a);
+ }
+
+ /*
+ * d <- 4*a
+ */
+ static inline void
+ gf5248_mul4(gf5248 *d, const gf5248 *a)
+ {
+ uint64_t d0, d1, d2, d3;
+ d0 = a->v0 << 2;
+ d1 = (a->v0 >> 62) | (a->v1 << 2);
+ d2 = (a->v1 >> 62) | (a->v2 << 2);
+ d3 = (a->v2 >> 62) | (a->v3 << 2);
+ inner_gf5248_partial_reduce(d, d0, d1, d2, d3);
+ }
+
+ /*
+ * d <- 8*a
+ */
+ static inline void
+ gf5248_mul8(gf5248 *d, const gf5248 *a)
+ {
+ uint64_t d0, d1, d2, d3;
+ d0 = a->v0 << 3;
+ d1 = (a->v0 >> 61) | (a->v1 << 3);
+ d2 = (a->v1 >> 61) | (a->v2 << 3);
+ d3 = (a->v2 >> 61) | (a->v3 << 3);
+ inner_gf5248_partial_reduce(d, d0, d1, d2, d3);
+ }
+
+ /*
+ * d <- 16*a
+ */
+ static inline void
+ gf5248_mul16(gf5248 *d, const gf5248 *a)
+ {
+ uint64_t d0, d1, d2, d3;
+ d0 = a->v0 << 4;
+ d1 = (a->v0 >> 60) | (a->v1 << 4);
+ d2 = (a->v1 >> 60) | (a->v2 << 4);
+ d3 = (a->v2 >> 60) | (a->v3 << 4);
+ inner_gf5248_partial_reduce(d, d0, d1, d2, d3);
+ }
+
+ /*
+ * d <- 32*a
+ */
+ static inline void
+ gf5248_mul32(gf5248 *d, const gf5248 *a)
+ {
+ uint64_t d0, d1, d2, d3;
+ d0 = a->v0 << 5;
+ d1 = (a->v0 >> 59) | (a->v1 << 5);
+ d2 = (a->v1 >> 59) | (a->v2 << 5);
+ d3 = (a->v2 >> 59) | (a->v3 << 5);
+ inner_gf5248_partial_reduce(d, d0, d1, d2, d3);
+ }
+
+ /*
+ * d <- a*x
+ * (multiplication by a 32-bit integer)
+ */
+ static inline void
+ gf5248_mul_small(gf5248 *d, const gf5248 *a, uint32_t x)
+ {
+ uint64_t d0, d1, d2, d3, d4, lo, hi, b, h, quo, rem;
+ unsigned char cc;
+
+ // Product over the integers. Top output word (d4) is at most 27 bits.
+ b = (uint64_t)x;
+ inner_gf5248_umul(d0, d1, a->v0, b);
+ inner_gf5248_umul(d2, d3, a->v2, b);
+ inner_gf5248_umul(lo, hi, a->v1, b);
+ cc = inner_gf5248_adc(0, d1, lo, &d1);
+ cc = inner_gf5248_adc(cc, d2, hi, &d2);
+ inner_gf5248_umul(lo, d4, a->v3, b);
+ cc = inner_gf5248_adc(cc, d3, lo, &d3);
+ (void)inner_gf5248_adc(cc, d4, 0, &d4);
+
+ // Extract low 248-bit part, and the high part (at most 35 bits).
+ h = (d4 << 8) | (d3 >> 56);
+ d3 &= 0x00FFFFFFFFFFFFFF;
+
+ // Fold h by adding floor(h/5) + (h mod 5)*2^248 to the low part.
+ inner_gf5248_umul(lo, hi, h, 0xCCCCCCCCCCCCCCCD);
+ quo = hi >> 2;
+ rem = h - (5 * quo);
+ cc = inner_gf5248_adc(cc, d0, quo, &d0);
+ cc = inner_gf5248_adc(cc, d1, 0, &d1);
+ cc = inner_gf5248_adc(cc, d2, 0, &d2);
+ (void)inner_gf5248_adc(cc, d3, rem << 56, &d3);
+
+ // Max value is now 5*2^248 + 6871947672
+
+ d->v0 = d0;
+ d->v1 = d1;
+ d->v2 = d2;
+ d->v3 = d3;
+ }
+
+ /*
+ * d <- x
+ * Input value x (32-bit integer) is converted to field element x mod q.
+ */
+ static inline void
+ gf5248_set_small(gf5248 *d, uint32_t x)
+ {
+ // We want Montgomery representation, i.e. x*2^256 mod q.
+ // We set h = x*2^8; then:
+ // x*2^256 = h*2^248
+ // = (h mod 5)*2^248 + floor(h/5)*5*2^248
+ // = (h mod 5)*2^248 + floor(h/5) mod q
+ // by using the fact that 5*2^248 = 1 mod q.
+ uint64_t h, lo, hi, quo, rem;
+
+ h = (uint64_t)x << 8;
+ inner_gf5248_umul(lo, hi, h, 0xCCCCCCCCCCCCCCCD);
+ (void)lo;
+ quo = hi >> 2;
+ rem = h - (5 * quo);
+ d->v0 = quo;
+ d->v1 = 0;
+ d->v2 = 0;
+ d->v3 = rem << 56;
+ }
+
+ // Inner function: d <- a/2^256, with normalization to [0..q-1].
+ static inline void
+ inner_gf5248_montgomery_reduce(gf5248 *d, const gf5248 *a)
+ {
+ uint64_t x0, x1, x2, x3, f0, f1, f2, f3;
+ uint64_t g0, g1, g2, g3, g4, g5, g6, g7;
+ uint64_t d0, d1, d2, d3;
+ uint64_t hi, t, w;
+ unsigned char cc;
+
+ // Let m = -1/q mod 2^256 = 5*2^248 + 1
+ // For input x, we compute f = x*m mod 2^256, then
+ // h = x + f*q, which is a multiple of 2^256. The output
+ // is then h/2^256.
+ // Since x < 2^256, we have:
+ // h <= 2^256 - 1 + (2^256 - 1)*q
+ // h <= q*2^256 + 2^256 - q - 1
+ // Since h = 0 mod 2^256, this implies that h <= q*2^256.
+ // The output h/2^256 is therefore between 0 and q (inclusive).
+
+ x0 = a->v0;
+ x1 = a->v1;
+ x2 = a->v2;
+ x3 = a->v3;
+
+ // f = x*(-1/q) mod 2^256
+ f0 = x0;
+ f1 = x1;
+ f2 = x2;
+ f3 = x3 + ((x0 * 5) << 56);
+
+ // g = f*q
+ inner_gf5248_umul(g3, hi, f0, (uint64_t)5 << 56);
+ inner_gf5248_umul_add(g4, hi, f1, (uint64_t)5 << 56, hi);
+ inner_gf5248_umul_add(g5, hi, f2, (uint64_t)5 << 56, hi);
+ inner_gf5248_umul_add(g6, g7, f3, (uint64_t)5 << 56, hi);
+ cc = inner_gf5248_sbb(0, 0, f0, &g0);
+ cc = inner_gf5248_sbb(cc, 0, f1, &g1);
+ cc = inner_gf5248_sbb(cc, 0, f2, &g2);
+ cc = inner_gf5248_sbb(cc, g3, f3, &g3);
+ cc = inner_gf5248_sbb(cc, g4, 0, &g4);
+ cc = inner_gf5248_sbb(cc, g5, 0, &g5);
+ cc = inner_gf5248_sbb(cc, g6, 0, &g6);
+ (void)inner_gf5248_sbb(cc, g7, 0, &g7);
+
+ // h = x + f*q (we drop the low 256 bits).
+ cc = inner_gf5248_adc(0, g0, x0, &x0);
+ cc = inner_gf5248_adc(cc, g1, x1, &x1);
+ cc = inner_gf5248_adc(cc, g2, x2, &x2);
+ cc = inner_gf5248_adc(cc, g3, x3, &x3);
+ cc = inner_gf5248_adc(cc, g4, 0, &d0);
+ cc = inner_gf5248_adc(cc, g5, 0, &d1);
+ cc = inner_gf5248_adc(cc, g6, 0, &d2);
+ (void)inner_gf5248_adc(cc, g7, 0, &d3);
+
+ // Normalize: if h = q, replace it with zero.
+ t = d0 & d1 & d2 & (d3 ^ ~(uint64_t)0x04FFFFFFFFFFFFFF);
+ cc = inner_gf5248_adc(0, t, 1, &t);
+ (void)inner_gf5248_sbb(cc, 0, 0, &w);
+ w = ~w;
+ d->v0 = d0 & w;
+ d->v1 = d1 & w;
+ d->v2 = d2 & w;
+ d->v3 = d3 & w;
+ }
+
+ /*
+ * d <- a*b
+ */
+ static inline void
+ gf5248_mul(gf5248 *d, const gf5248 *a, const gf5248 *b)
+ {
+ uint64_t e0, e1, e2, e3, e4, e5, e6, e7;
+ uint64_t f0, f1, f2, f3, lo, hi, lo2, hi2;
+ uint64_t g0, g1, g2, g3, g4, g5, g6, g7;
+ unsigned char cc;
+
+ // Multiplication over integers.
+ inner_gf5248_umul(e0, e1, a->v0, b->v0);
+ inner_gf5248_umul(e2, e3, a->v1, b->v1);
+ inner_gf5248_umul(e4, e5, a->v2, b->v2);
+ inner_gf5248_umul(e6, e7, a->v3, b->v3);
+
+ inner_gf5248_umul(lo, hi, a->v0, b->v1);
+ cc = inner_gf5248_adc(0, e1, lo, &e1);
+ cc = inner_gf5248_adc(cc, e2, hi, &e2);
+ inner_gf5248_umul(lo, hi, a->v0, b->v3);
+ cc = inner_gf5248_adc(cc, e3, lo, &e3);
+ cc = inner_gf5248_adc(cc, e4, hi, &e4);
+ inner_gf5248_umul(lo, hi, a->v2, b->v3);
+ cc = inner_gf5248_adc(cc, e5, lo, &e5);
+ cc = inner_gf5248_adc(cc, e6, hi, &e6);
+ (void)inner_gf5248_adc(cc, e7, 0, &e7);
+
+ inner_gf5248_umul(lo, hi, a->v1, b->v0);
+ cc = inner_gf5248_adc(0, e1, lo, &e1);
+ cc = inner_gf5248_adc(cc, e2, hi, &e2);
+ inner_gf5248_umul(lo, hi, a->v3, b->v0);
+ cc = inner_gf5248_adc(cc, e3, lo, &e3);
+ cc = inner_gf5248_adc(cc, e4, hi, &e4);
+ inner_gf5248_umul(lo, hi, a->v3, b->v2);
+ cc = inner_gf5248_adc(cc, e5, lo, &e5);
+ cc = inner_gf5248_adc(cc, e6, hi, &e6);
+ (void)inner_gf5248_adc(cc, e7, 0, &e7);
+
+ inner_gf5248_umul(lo, hi, a->v0, b->v2);
+ cc = inner_gf5248_adc(0, e2, lo, &e2);
+ cc = inner_gf5248_adc(cc, e3, hi, &e3);
+ inner_gf5248_umul(lo, hi, a->v1, b->v3);
+ cc = inner_gf5248_adc(cc, e4, lo, &e4);
+ cc = inner_gf5248_adc(cc, e5, hi, &e5);
+ cc = inner_gf5248_adc(cc, e6, 0, &e6);
+ (void)inner_gf5248_adc(cc, e7, 0, &e7);
+
+ inner_gf5248_umul(lo, hi, a->v2, b->v0);
+ cc = inner_gf5248_adc(0, e2, lo, &e2);
+ cc = inner_gf5248_adc(cc, e3, hi, &e3);
+ inner_gf5248_umul(lo, hi, a->v3, b->v1);
+ cc = inner_gf5248_adc(cc, e4, lo, &e4);
+ cc = inner_gf5248_adc(cc, e5, hi, &e5);
+ cc = inner_gf5248_adc(cc, e6, 0, &e6);
+ (void)inner_gf5248_adc(cc, e7, 0, &e7);
+
+ inner_gf5248_umul(lo, hi, a->v1, b->v2);
+ inner_gf5248_umul(lo2, hi2, a->v2, b->v1);
+ cc = inner_gf5248_adc(0, lo, lo2, &lo);
+ cc = inner_gf5248_adc(cc, hi, hi2, &hi);
+ (void)inner_gf5248_adc(cc, 0, 0, &hi2);
+ cc = inner_gf5248_adc(0, e3, lo, &e3);
+ cc = inner_gf5248_adc(cc, e4, hi, &e4);
+ cc = inner_gf5248_adc(cc, e5, hi2, &e5);
+ cc = inner_gf5248_adc(cc, e6, 0, &e6);
+ (void)inner_gf5248_adc(cc, e7, 0, &e7);
+
+ // Montgomery reduction.
+ //
+ // Low part is lo(e) = e0..e3 (256 bits).
+ // Let m = -1/q mod 2^256; we add (lo(e)*m mod 2^256)*q to the
+ // high part g = e4..e7 (246 bits).
+ //
+ // We have m = 5*2^248 + 1.
+ f0 = e0;
+ f1 = e1;
+ f2 = e2;
+ f3 = e3 + ((e0 * 5) << 56);
+
+ // g = f*q
+ inner_gf5248_umul(g3, hi, f0, (uint64_t)5 << 56);
+ inner_gf5248_umul_add(g4, hi, f1, (uint64_t)5 << 56, hi);
+ inner_gf5248_umul_add(g5, hi, f2, (uint64_t)5 << 56, hi);
+ inner_gf5248_umul_add(g6, g7, f3, (uint64_t)5 << 56, hi);
+ cc = inner_gf5248_sbb(0, 0, f0, &g0);
+ cc = inner_gf5248_sbb(cc, 0, f1, &g1);
+ cc = inner_gf5248_sbb(cc, 0, f2, &g2);
+ cc = inner_gf5248_sbb(cc, g3, f3, &g3);
+ cc = inner_gf5248_sbb(cc, g4, 0, &g4);
+ cc = inner_gf5248_sbb(cc, g5, 0, &g5);
+ cc = inner_gf5248_sbb(cc, g6, 0, &g6);
+ (void)inner_gf5248_sbb(cc, g7, 0, &g7);
+
+ // Add g = f*q to e0..e7.
+ // Since e0..e7 < 2^502 and f < 2^256, we know that the result
+ // is less than 2^502 + 2^256*5*2^248, which is less than 6*2^504.
+ // This is also a multiple of 2^256. We divide by 2^256 by simply
+ // dropping the low 256 bits (which are all equal to zero), and
+ // the result is less than 6*2^248, which is already in our
+ // acceptable value range.
+ cc = inner_gf5248_adc(0, g0, e0, &e0);
+ cc = inner_gf5248_adc(cc, g1, e1, &e1);
+ cc = inner_gf5248_adc(cc, g2, e2, &e2);
+ cc = inner_gf5248_adc(cc, g3, e3, &e3);
+ cc = inner_gf5248_adc(cc, g4, e4, &e4);
+ cc = inner_gf5248_adc(cc, g5, e5, &e5);
+ cc = inner_gf5248_adc(cc, g6, e6, &e6);
+ (void)inner_gf5248_adc(cc, g7, e7, &e7);
+
+ d->v0 = e4;
+ d->v1 = e5;
+ d->v2 = e6;
+ d->v3 = e7;
+ }
+
+ /*
+ * d <- a^2
+ */
+ static inline void
+ gf5248_square(gf5248 *d, const gf5248 *a)
+ {
+ uint64_t e0, e1, e2, e3, e4, e5, e6, e7;
+ uint64_t f0, f1, f2, f3, lo, hi;
+ uint64_t g0, g1, g2, g3, g4, g5, g6, g7;
+ unsigned char cc;
+
+ // Squaring over integers.
+ inner_gf5248_umul(e1, e2, a->v0, a->v1);
+ inner_gf5248_umul(e3, e4, a->v0, a->v3);
+ inner_gf5248_umul(e5, e6, a->v2, a->v3);
+ inner_gf5248_umul(lo, hi, a->v0, a->v2);
+ cc = inner_gf5248_adc(0, e2, lo, &e2);
+ cc = inner_gf5248_adc(cc, e3, hi, &e3);
+ inner_gf5248_umul(lo, hi, a->v1, a->v3);
+ cc = inner_gf5248_adc(cc, e4, lo, &e4);
+ cc = inner_gf5248_adc(cc, e5, hi, &e5);
+ (void)inner_gf5248_adc(cc, e6, 0, &e6);
+ inner_gf5248_umul(lo, hi, a->v1, a->v2);
+ cc = inner_gf5248_adc(0, e3, lo, &e3);
+ cc = inner_gf5248_adc(cc, e4, hi, &e4);
+ cc = inner_gf5248_adc(cc, e5, 0, &e5);
+ (void)inner_gf5248_adc(cc, e6, 0, &e6);
+
+ // There cannot be extra carry here because the partial sum is
+ // necessarily lower than 2^448 at this point.
+
+ e7 = e6 >> 63;
+ e6 = (e6 << 1) | (e5 >> 63);
+ e5 = (e5 << 1) | (e4 >> 63);
+ e4 = (e4 << 1) | (e3 >> 63);
+ e3 = (e3 << 1) | (e2 >> 63);
+ e2 = (e2 << 1) | (e1 >> 63);
+ e1 = e1 << 1;
+
+ inner_gf5248_umul(e0, hi, a->v0, a->v0);
+ cc = inner_gf5248_adc(0, e1, hi, &e1);
+ inner_gf5248_umul(lo, hi, a->v1, a->v1);
+ cc = inner_gf5248_adc(cc, e2, lo, &e2);
+ cc = inner_gf5248_adc(cc, e3, hi, &e3);
+ inner_gf5248_umul(lo, hi, a->v2, a->v2);
+ cc = inner_gf5248_adc(cc, e4, lo, &e4);
+ cc = inner_gf5248_adc(cc, e5, hi, &e5);
+ inner_gf5248_umul(lo, hi, a->v3, a->v3);
+ cc = inner_gf5248_adc(cc, e6, lo, &e6);
+ (void)inner_gf5248_adc(cc, e7, hi, &e7);
+
+ // Montgomery reduction.
+ //
+ // Low part is lo(e) = e0..e3 (256 bits).
+ // Let m = -1/q mod 2^256; we add (lo(e)*m mod 2^256)*q to the
+ // high part g = e4..e7 (246 bits).
+ //
+ // We have m = 5*2^248 + 1.
+ f0 = e0;
+ f1 = e1;
+ f2 = e2;
+ f3 = e3 + ((e0 * 5) << 56);
+
+ // g = f*q
+ inner_gf5248_umul(g3, hi, f0, (uint64_t)5 << 56);
+ inner_gf5248_umul_add(g4, hi, f1, (uint64_t)5 << 56, hi);
+ inner_gf5248_umul_add(g5, hi, f2, (uint64_t)5 << 56, hi);
+ inner_gf5248_umul_add(g6, g7, f3, (uint64_t)5 << 56, hi);
+ cc = inner_gf5248_sbb(0, 0, f0, &g0);
+ cc = inner_gf5248_sbb(cc, 0, f1, &g1);
+ cc = inner_gf5248_sbb(cc, 0, f2, &g2);
+ cc = inner_gf5248_sbb(cc, g3, f3, &g3);
+ cc = inner_gf5248_sbb(cc, g4, 0, &g4);
+ cc = inner_gf5248_sbb(cc, g5, 0, &g5);
+ cc = inner_gf5248_sbb(cc, g6, 0, &g6);
+ (void)inner_gf5248_sbb(cc, g7, 0, &g7);
+
+ // Add g = f*q to e0..e7.
+ // Since e0..e7 < 2^502 and f < 2^256, we know that the result
+ // is less than 2^502 + 2^256*5*2^248, which is less than 6*2^504.
+ // This is also a multiple of 2^256. We divide by 2^256 by simply
+ // dropping the low 256 bits (which are all equal to zero), and
+ // the result is less than 6*2^248, which is already in our
+ // acceptable value range.
+ cc = inner_gf5248_adc(0, g0, e0, &e0);
+ cc = inner_gf5248_adc(cc, g1, e1, &e1);
+ cc = inner_gf5248_adc(cc, g2, e2, &e2);
+ cc = inner_gf5248_adc(cc, g3, e3, &e3);
+ cc = inner_gf5248_adc(cc, g4, e4, &e4);
+ cc = inner_gf5248_adc(cc, g5, e5, &e5);
+ cc = inner_gf5248_adc(cc, g6, e6, &e6);
+ (void)inner_gf5248_adc(cc, g7, e7, &e7);
+
+ d->v0 = e4;
+ d->v1 = e5;
+ d->v2 = e6;
+ d->v3 = e7;
+ }
+
+ /*
+ * d <- a^(2^n)
+ * This computes n successive squarings of value a, with result in d.
+ * n == 0 is a valid input (in that case, *a is copied into *d).
+ * This function is not constant-time with regard to n: the number of
+ * successive squarings may be observable through timing-based side channels.
+ */
+ static inline void
+ gf5248_xsquare(gf5248 *d, const gf5248 *a, unsigned n)
+ {
+ if (n == 0) {
+ *d = *a;
+ return;
+ }
+ gf5248_square(d, a);
+ while (n-- > 1) {
+ gf5248_square(d, d);
+ }
+ }
+
+ /*
+ * Returns 0xFFFFFFFF if *a is zero; otherwise, 0x00000000 is returned.
+ */
+ static inline uint32_t
+ gf5248_iszero(const gf5248 *a)
+ {
+ uint64_t a0, a1, a2, a3, t0, t1, r;
+
+ // Zero can be represented by 0 or by q.
+ a0 = a->v0;
+ a1 = a->v1;
+ a2 = a->v2;
+ a3 = a->v3;
+ t0 = a0 | a1 | a2 | a3;
+ t1 = ~a0 | ~a1 | ~a2 | (a3 ^ 0x04FFFFFFFFFFFFFF);
+
+ // Top bit of r is 0 if and only if one of t0 or t1 is zero.
+ r = (t0 | -t0) & (t1 | -t1);
+ return (uint32_t)(r >> 63) - 1;
+ }
+
+ /*
+ * Returns 0xFFFFFFFF if *a and *b represent the same field element;
+ * otherwise, 0x00000000 is returned.
+ */
+ static inline uint32_t
+ gf5248_equals(const gf5248 *a, const gf5248 *b)
+ {
+ gf5248 d;
+ gf5248_sub(&d, a, b);
+ return gf5248_iszero(&d);
+ }
+
+ /*
+ * d <- 1/a
+ * If *a is not zero, then the inverse is well-defined and written into *d,
+ * and the function returns 0xFFFFFFFF. If *a is zero, then this function
+ * sets *d to zero and returns 0x00000000.
+ */
+ uint32_t gf5248_invert(gf5248 *d, const gf5248 *a);
+
+ /*
+ * d <- a/b
+ * If *b is not zero, then this functions writes a/b into *d, and returns
+ * 0xFFFFFFFF. If *b is zero, then this function sets *d to zero (regardless
+ * of the value of *a) and returns 0x00000000.
+ */
+ uint32_t gf5248_div(gf5248 *d, const gf5248 *a, const gf5248 *b);
+
+ /*
+ * d <- a/3
+ * Divides by 3 in the field by implementing the algorithm proposed in
+ * "Efficient Multiplication in Finite Field Extensions of Degree 5"
+ * by El Mrabet, Guillevic and Ionica at ASIACRYPT 2011.
+ */
+ void gf5248_div3(gf5248 *out, const gf5248 *a);
+
+ /*
+ * Get the Legendre symbol of *a (0 for zero, +1 for a non-zero square,
+ * -1 for a non-square).
+ */
+ int32_t gf5248_legendre(const gf5248 *a);
+
+ /*
+ * If *a is a square, then this function sets *d to a square root of a,
+ * and returns 0xFFFFFFFF. If *a is not a square, then this function
+ * sets *d to a square root of -a, and returns 0x00000000.
+ * In all cases, the value written into *d is such that the least significant
+ * bit of its integer representation (in [0..q-1]) is zero.
+ */
+ uint32_t gf5248_sqrt(gf5248 *d, const gf5248 *a);
+
+ /*
+ * Encode field element *a into buffer dst (exactly 32 bytes are written).
+ */
+ void gf5248_encode(void *dst, const gf5248 *a);
+
+ /*
+ * Decode source buffer src (exactly 32 bytes) into a field element *d.
+ * If the source value is not a valid canonical encoding, then *d is zero
+ * and the function returns 0x00000000; otherwise, the function returns
+ * 0xFFFFFFFF.
+ */
+ uint32_t gf5248_decode(gf5248 *d, const void *src);
+
+ /*
+ * Interpret the source buffer (of size len bytes) as an unsigned integer
+ * (little-endian convention) and reduce it modulo q, yielding a field
+ * element which is written into *d. Since reduction is applied, this
+ * function cannot fail.
+ */
+ void gf5248_decode_reduce(gf5248 *d, const void *src, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd.c
new file mode 100644
index 0000000000..0424108019
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd.c
@@ -0,0 +1,93 @@
+#include
+#include
+
+void
+double_couple_point(theta_couple_point_t *out, const theta_couple_point_t *in, const theta_couple_curve_t *E1E2)
+{
+ ec_dbl(&out->P1, &in->P1, &E1E2->E1);
+ ec_dbl(&out->P2, &in->P2, &E1E2->E2);
+}
+
+void
+double_couple_point_iter(theta_couple_point_t *out,
+ unsigned n,
+ const theta_couple_point_t *in,
+ const theta_couple_curve_t *E1E2)
+{
+ if (n == 0) {
+ memmove(out, in, sizeof(theta_couple_point_t));
+ } else {
+ double_couple_point(out, in, E1E2);
+ for (unsigned i = 0; i < n - 1; i++) {
+ double_couple_point(out, out, E1E2);
+ }
+ }
+}
+
+void
+add_couple_jac_points(theta_couple_jac_point_t *out,
+ const theta_couple_jac_point_t *T1,
+ const theta_couple_jac_point_t *T2,
+ const theta_couple_curve_t *E1E2)
+{
+ ADD(&out->P1, &T1->P1, &T2->P1, &E1E2->E1);
+ ADD(&out->P2, &T1->P2, &T2->P2, &E1E2->E2);
+}
+
+void
+double_couple_jac_point(theta_couple_jac_point_t *out,
+ const theta_couple_jac_point_t *in,
+ const theta_couple_curve_t *E1E2)
+{
+ DBL(&out->P1, &in->P1, &E1E2->E1);
+ DBL(&out->P2, &in->P2, &E1E2->E2);
+}
+
+void
+double_couple_jac_point_iter(theta_couple_jac_point_t *out,
+ unsigned n,
+ const theta_couple_jac_point_t *in,
+ const theta_couple_curve_t *E1E2)
+{
+ if (n == 0) {
+ *out = *in;
+ } else if (n == 1) {
+ double_couple_jac_point(out, in, E1E2);
+ } else {
+ fp2_t a1, a2, t1, t2;
+
+ jac_to_ws(&out->P1, &t1, &a1, &in->P1, &E1E2->E1);
+ jac_to_ws(&out->P2, &t2, &a2, &in->P2, &E1E2->E2);
+
+ DBLW(&out->P1, &t1, &out->P1, &t1);
+ DBLW(&out->P2, &t2, &out->P2, &t2);
+ for (unsigned i = 0; i < n - 1; i++) {
+ DBLW(&out->P1, &t1, &out->P1, &t1);
+ DBLW(&out->P2, &t2, &out->P2, &t2);
+ }
+
+ jac_from_ws(&out->P1, &out->P1, &a1, &E1E2->E1);
+ jac_from_ws(&out->P2, &out->P2, &a2, &E1E2->E2);
+ }
+}
+
+void
+couple_jac_to_xz(theta_couple_point_t *P, const theta_couple_jac_point_t *xyP)
+{
+ jac_to_xz(&P->P1, &xyP->P1);
+ jac_to_xz(&P->P2, &xyP->P2);
+}
+
+void
+copy_bases_to_kernel(theta_kernel_couple_points_t *ker, const ec_basis_t *B1, const ec_basis_t *B2)
+{
+ // Copy the basis on E1 to (P, _) on T1, T2 and T1 - T2
+ copy_point(&ker->T1.P1, &B1->P);
+ copy_point(&ker->T2.P1, &B1->Q);
+ copy_point(&ker->T1m2.P1, &B1->PmQ);
+
+ // Copy the basis on E2 to (_, P) on T1, T2 and T1 - T2
+ copy_point(&ker->T1.P2, &B2->P);
+ copy_point(&ker->T2.P2, &B2->Q);
+ copy_point(&ker->T1m2.P2, &B2->PmQ);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd.h
new file mode 100644
index 0000000000..616504c7b1
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd.h
@@ -0,0 +1,435 @@
+/** @file
+ *
+ * @authors Antonin Leroux
+ *
+ * @brief The HD-isogenies algorithm required by the signature
+ *
+ */
+
+#ifndef HD_H
+#define HD_H
+
+#include
+#include
+#include
+
+/** @defgroup hd_module Abelian surfaces and their isogenies
+ * @{
+ */
+
+#define HD_extra_torsion 2
+
+/** @defgroup hd_struct Data structures for dimension 2
+ * @{
+ */
+
+/** @brief Type for couple point with XZ coordinates
+ * @typedef theta_couple_point_t
+ *
+ * @struct theta_couple_point
+ *
+ * Structure for the couple point on an elliptic product
+ * using XZ coordinates
+ */
+typedef struct theta_couple_point
+{
+ ec_point_t P1;
+ ec_point_t P2;
+} theta_couple_point_t;
+
+/** @brief Type for three couple points T1, T2, T1-T2 with XZ coordinates
+ * @typedef theta_kernel_couple_points_t
+ *
+ * @struct theta_kernel_couple_points
+ *
+ * Structure for a triple of theta couple points T1, T2 and T1 - T2
+ */
+typedef struct theta_kernel_couple_points
+{
+ theta_couple_point_t T1;
+ theta_couple_point_t T2;
+ theta_couple_point_t T1m2;
+} theta_kernel_couple_points_t;
+
+/** @brief Type for couple point with XYZ coordinates
+ * @typedef theta_couple_jac_point_t
+ *
+ * @struct theta_couple_jac_point
+ *
+ * Structure for the couple point on an elliptic product
+ * using XYZ coordinates
+ */
+typedef struct theta_couple_jac_point
+{
+ jac_point_t P1;
+ jac_point_t P2;
+} theta_couple_jac_point_t;
+
+/** @brief Type for couple curve *
+ * @typedef theta_couple_curve_t
+ *
+ * @struct theta_couple_curve
+ *
+ * the theta_couple_curve structure
+ */
+typedef struct theta_couple_curve
+{
+ ec_curve_t E1;
+ ec_curve_t E2;
+} theta_couple_curve_t;
+
+/** @brief Type for a product E1 x E2 with corresponding bases
+ * @typedef theta_couple_curve_with_basis_t
+ *
+ * @struct theta_couple_curve_with_basis
+ *
+ * tType for a product E1 x E2 with corresponding bases Ei[2^n]
+ */
+typedef struct theta_couple_curve_with_basis
+{
+ ec_curve_t E1;
+ ec_curve_t E2;
+ ec_basis_t B1;
+ ec_basis_t B2;
+} theta_couple_curve_with_basis_t;
+
+/** @brief Type for theta point *
+ * @typedef theta_point_t
+ *
+ * @struct theta_point
+ *
+ * the theta_point structure used
+ */
+typedef struct theta_point
+{
+ fp2_t x;
+ fp2_t y;
+ fp2_t z;
+ fp2_t t;
+} theta_point_t;
+
+/** @brief Type for theta point with repeating components
+ * @typedef theta_point_compact_t
+ *
+ * @struct theta_point_compact
+ *
+ * the theta_point structure used for points with repeated components
+ */
+typedef struct theta_point_compact
+{
+ fp2_t x;
+ fp2_t y;
+} theta_point_compact_t;
+
+/** @brief Type for theta structure *
+ * @typedef theta_structure_t
+ *
+ * @struct theta_structure
+ *
+ * the theta_structure structure used
+ */
+typedef struct theta_structure
+{
+ theta_point_t null_point;
+ bool precomputation;
+
+ // Eight precomputed values used for doubling and
+ // (2,2)-isogenies.
+ fp2_t XYZ0;
+ fp2_t YZT0;
+ fp2_t XZT0;
+ fp2_t XYT0;
+
+ fp2_t xyz0;
+ fp2_t yzt0;
+ fp2_t xzt0;
+ fp2_t xyt0;
+} theta_structure_t;
+
+/** @brief A 2x2 matrix used for action by translation
+ * @typedef translation_matrix_t
+ *
+ * @struct translation_matrix
+ *
+ * Structure to hold 4 fp2_t elements representing a 2x2 matrix used when computing
+ * a compatible theta structure during gluing.
+ */
+typedef struct translation_matrix
+{
+ fp2_t g00;
+ fp2_t g01;
+ fp2_t g10;
+ fp2_t g11;
+} translation_matrix_t;
+
+/** @brief A 4x4 matrix used for basis changes
+ * @typedef basis_change_matrix_t
+ *
+ * @struct basis_change_matrix
+ *
+ * Structure to hold 16 elements representing a 4x4 matrix used for changing
+ * the basis of a theta point.
+ */
+typedef struct basis_change_matrix
+{
+ fp2_t m[4][4];
+} basis_change_matrix_t;
+
+/** @brief Type for gluing (2,2) theta isogeny *
+ * @typedef theta_gluing_t
+ *
+ * @struct theta_gluing
+ *
+ * the theta_gluing structure
+ */
+typedef struct theta_gluing
+{
+
+ theta_couple_curve_t domain;
+ theta_couple_jac_point_t xyK1_8;
+ theta_point_compact_t imageK1_8;
+ basis_change_matrix_t M;
+ theta_point_t precomputation;
+ theta_point_t codomain;
+
+} theta_gluing_t;
+
+/** @brief Type for standard (2,2) theta isogeny *
+ * @typedef theta_isogeny_t
+ *
+ * @struct theta_isogeny
+ *
+ * the theta_isogeny structure
+ */
+typedef struct theta_isogeny
+{
+ theta_point_t T1_8;
+ theta_point_t T2_8;
+ bool hadamard_bool_1;
+ bool hadamard_bool_2;
+ theta_structure_t domain;
+ theta_point_t precomputation;
+ theta_structure_t codomain;
+} theta_isogeny_t;
+
+/** @brief Type for splitting isomorphism *
+ * @typedef theta_splitting_t
+ *
+ * @struct theta_splitting
+ *
+ * the theta_splitting structure
+ */
+typedef struct theta_splitting
+{
+ basis_change_matrix_t M;
+ theta_structure_t B;
+
+} theta_splitting_t;
+
+// end of hd_struct
+/**
+ * @}
+ */
+
+/** @defgroup hd_functions Functions for dimension 2
+ * @{
+ */
+
+/**
+ * @brief Compute the double of the theta couple point in on the elliptic product E12
+ *
+ * @param out Output: the theta_couple_point
+ * @param in the theta couple point in the elliptic product
+ * @param E1E2 an elliptic product
+ * in = (P1,P2)
+ * out = [2] (P1,P2)
+ *
+ */
+void double_couple_point(theta_couple_point_t *out, const theta_couple_point_t *in, const theta_couple_curve_t *E1E2);
+
+/**
+ * @brief Compute the iterated double of the theta couple point in on the elliptic product E12
+ *
+ * @param out Output: the theta_couple_point
+ * @param n : the number of iteration
+ * @param E1E2 an elliptic product
+ * @param in the theta couple point in the elliptic product
+ * in = (P1,P2)
+ * out = [2^n] (P1,P2)
+ *
+ */
+void double_couple_point_iter(theta_couple_point_t *out,
+ unsigned n,
+ const theta_couple_point_t *in,
+ const theta_couple_curve_t *E1E2);
+
+/**
+ * @brief Compute the addition of two points in (X : Y : Z) coordinates on the elliptic product E12
+ *
+ * @param out Output: the theta_couple_jac_point
+ * @param T1 the theta couple jac point in the elliptic product
+ * @param T2 the theta couple jac point in the elliptic product
+ * @param E1E2 an elliptic product
+ * in = (P1, P2), (Q1, Q2)
+ * out = (P1 + Q1, P2 + Q2)
+ *
+ **/
+void add_couple_jac_points(theta_couple_jac_point_t *out,
+ const theta_couple_jac_point_t *T1,
+ const theta_couple_jac_point_t *T2,
+ const theta_couple_curve_t *E1E2);
+
+/**
+ * @brief Compute the double of the theta couple point in on the elliptic product E12
+ *
+ * @param out Output: the theta_couple_point
+ * @param in the theta couple point in the elliptic product
+ * @param E1E2 an elliptic product
+ * in = (P1,P2)
+ * out = [2] (P1,P2)
+ *
+ */
+void double_couple_jac_point(theta_couple_jac_point_t *out,
+ const theta_couple_jac_point_t *in,
+ const theta_couple_curve_t *E1E2);
+
+/**
+ * @brief Compute the iterated double of the theta couple jac point in on the elliptic product E12
+ *
+ * @param out Output: the theta_couple_jac_point
+ * @param n : the number of iteration
+ * @param in the theta couple jac point in the elliptic product
+ * @param E1E2 an elliptic product
+ * in = (P1,P2)
+ * out = [2^n] (P1,P2)
+ *
+ */
+void double_couple_jac_point_iter(theta_couple_jac_point_t *out,
+ unsigned n,
+ const theta_couple_jac_point_t *in,
+ const theta_couple_curve_t *E1E2);
+
+/**
+ * @brief A forgetful function which returns (X : Z) points given a pair of (X : Y : Z) points
+ *
+ * @param P Output: the theta_couple_point
+ * @param xyP : the theta_couple_jac_point
+ **/
+void couple_jac_to_xz(theta_couple_point_t *P, const theta_couple_jac_point_t *xyP);
+
+/**
+ * @brief Compute a (2,2) isogeny chain in dimension 2 between elliptic
+ * products in the theta_model and evaluate at a list of points of the form
+ * (P1,0) or (0,P2). Returns 0 if the codomain fails to split (or there is
+ * an error during the computation) and 1 otherwise.
+ *
+ * @param n : the length of the isogeny chain
+ * @param E12 an elliptic curve product
+ * @param ker T1, T2 and T1-T2. couple points on E12[2^(n+2)]
+ * @param extra_torsion boolean indicating if we give the points in E12[2^n] or
+ * E12[2^(n+HD_extra_torsion)]
+ * @param E34 Output: the codomain curve
+ * @param P12 Input/Output: pointer to points to be pushed through the isogeny (in-place)
+ * @param numP: length of the list of points given in P12 (can be zero)
+ * @returns 1 on success 0 on failure
+ *
+ */
+int theta_chain_compute_and_eval(unsigned n,
+ /*const*/ theta_couple_curve_t *E12,
+ const theta_kernel_couple_points_t *ker,
+ bool extra_torsion,
+ theta_couple_curve_t *E34,
+ theta_couple_point_t *P12,
+ size_t numP);
+
+/**
+ * @brief Compute a (2,2) isogeny chain in dimension 2 between elliptic
+ * products in the theta_model and evaluate at a list of points of the form
+ * (P1,0) or (0,P2). Returns 0 if the codomain fails to split (or there is
+ * an error during the computation) and 1 otherwise.
+ * Compared to theta_chain_compute_and_eval, it does extra isotropy
+ * checks on the kernel.
+ *
+ * @param n : the length of the isogeny chain
+ * @param E12 an elliptic curve product
+ * @param ker T1, T2 and T1-T2. couple points on E12[2^(n+2)]
+ * @param extra_torsion boolean indicating if we give the points in E12[2^n] or
+ * E12[2^(n+HD_extra_torsion)]
+ * @param E34 Output: the codomain curve
+ * @param P12 Input/Output: pointer to points to be pushed through the isogeny (in-place)
+ * @param numP: length of the list of points given in P12 (can be zero)
+ * @returns 1 on success 0 on failure
+ *
+ */
+int theta_chain_compute_and_eval_verify(unsigned n,
+ /*const*/ theta_couple_curve_t *E12,
+ const theta_kernel_couple_points_t *ker,
+ bool extra_torsion,
+ theta_couple_curve_t *E34,
+ theta_couple_point_t *P12,
+ size_t numP);
+
+/**
+ * @brief Compute a (2,2) isogeny chain in dimension 2 between elliptic
+ * products in the theta_model and evaluate at a list of points of the form
+ * (P1,0) or (0,P2). Returns 0 if the codomain fails to split (or there is
+ * an error during the computation) and 1 otherwise.
+ * Compared to theta_chain_compute_and_eval, it selects a random Montgomery
+ * model of the codomain.
+ *
+ * @param n : the length of the isogeny chain
+ * @param E12 an elliptic curve product
+ * @param ker T1, T2 and T1-T2. couple points on E12[2^(n+2)]
+ * @param extra_torsion boolean indicating if we give the points in E12[2^n] or
+ * E12[2^(n+HD_extra_torsion)]
+ * @param E34 Output: the codomain curve
+ * @param P12 Input/Output: pointer to points to be pushed through the isogeny (in-place)
+ * @param numP: length of the list of points given in P12 (can be zero)
+ * @returns 1 on success, 0 on failure
+ *
+ */
+int theta_chain_compute_and_eval_randomized(unsigned n,
+ /*const*/ theta_couple_curve_t *E12,
+ const theta_kernel_couple_points_t *ker,
+ bool extra_torsion,
+ theta_couple_curve_t *E34,
+ theta_couple_point_t *P12,
+ size_t numP);
+
+/**
+ * @brief Given a bases B1 on E1 and B2 on E2 copies this to create a kernel
+ * on E1 x E2 as couple points T1, T2 and T1 - T2
+ *
+ * @param ker Output: a kernel for dim_two_isogenies (T1, T2, T1-T2)
+ * @param B1 Input basis on E1
+ * @param B2 Input basis on E2
+ **/
+void copy_bases_to_kernel(theta_kernel_couple_points_t *ker, const ec_basis_t *B1, const ec_basis_t *B2);
+
+/**
+ * @brief Given a couple of points (P1, P2) on a couple of curves (E1, E2)
+ * this function tests if both points are of order exactly 2^t
+ *
+ * @param T: couple point (P1, P2)
+ * @param E: a couple of curves (E1, E2)
+ * @param t: an integer
+ * @returns 0xFFFFFFFF on success, 0 on failure
+ */
+static inline int
+test_couple_point_order_twof(const theta_couple_point_t *T, const theta_couple_curve_t *E, int t)
+{
+ int check_P1 = test_point_order_twof(&T->P1, &E->E1, t);
+ int check_P2 = test_point_order_twof(&T->P2, &E->E2, t);
+
+ return check_P1 & check_P2;
+}
+
+// end of hd_functions
+/**
+ * @}
+ */
+// end of hd_module
+/**
+ * @}
+ */
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd_splitting_transforms.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd_splitting_transforms.c
new file mode 100644
index 0000000000..14482e01cd
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd_splitting_transforms.c
@@ -0,0 +1,143 @@
+#include
+
+#define FP2_ZERO 0
+#define FP2_ONE 1
+#define FP2_I 2
+#define FP2_MINUS_ONE 3
+#define FP2_MINUS_I 4
+
+const int EVEN_INDEX[10][2] = {{0, 0}, {0, 1}, {0, 2}, {0, 3}, {1, 0}, {1, 2}, {2, 0}, {2, 1}, {3, 0}, {3, 3}};
+const int CHI_EVAL[4][4] = {{1, 1, 1, 1}, {1, -1, 1, -1}, {1, 1, -1, -1}, {1, -1, -1, 1}};
+const fp2_t FP2_CONSTANTS[5] = {{
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x333, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
+#elif RADIX == 32
+{{0x666, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x33, 0x0, 0x0, 0x100000000000000}}
+#else
+{{0x19, 0x0, 0x0, 0x0, 0x300000000000}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x1ccc, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x7}}
+#elif RADIX == 32
+{{0x1ffff999, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x2ffff}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xffffffffffffffcc, 0xffffffffffffffff, 0xffffffffffffffff, 0x3ffffffffffffff}}
+#else
+{{0x7ffffffffffe6, 0x7ffffffffffff, 0x7ffffffffffff, 0x7ffffffffffff, 0x1fffffffffff}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+}, {
+#if 0
+#elif RADIX == 16
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 32
+{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0x0, 0x0, 0x0, 0x0}}
+#else
+{{0x0, 0x0, 0x0, 0x0, 0x0}}
+#endif
+#endif
+,
+#if 0
+#elif RADIX == 16
+{{0x1ccc, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x1fff, 0x7}}
+#elif RADIX == 32
+{{0x1ffff999, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x2ffff}}
+#elif RADIX == 64
+#if defined(SQISIGN_GF_IMPL_BROADWELL)
+{{0xffffffffffffffcc, 0xffffffffffffffff, 0xffffffffffffffff, 0x3ffffffffffffff}}
+#else
+{{0x7ffffffffffe6, 0x7ffffffffffff, 0x7ffffffffffff, 0x7ffffffffffff, 0x1fffffffffff}}
+#endif
+#endif
+}};
+const precomp_basis_change_matrix_t SPLITTING_TRANSFORMS[10] = {{{{FP2_ONE, FP2_I, FP2_ONE, FP2_I}, {FP2_ONE, FP2_MINUS_I, FP2_MINUS_ONE, FP2_I}, {FP2_ONE, FP2_I, FP2_MINUS_ONE, FP2_MINUS_I}, {FP2_MINUS_ONE, FP2_I, FP2_MINUS_ONE, FP2_I}}}, {{{FP2_ONE, FP2_ZERO, FP2_ZERO, FP2_ZERO}, {FP2_ZERO, FP2_ZERO, FP2_ZERO, FP2_ONE}, {FP2_ZERO, FP2_ZERO, FP2_ONE, FP2_ZERO}, {FP2_ZERO, FP2_MINUS_ONE, FP2_ZERO, FP2_ZERO}}}, {{{FP2_ONE, FP2_ZERO, FP2_ZERO, FP2_ZERO}, {FP2_ZERO, FP2_ONE, FP2_ZERO, FP2_ZERO}, {FP2_ZERO, FP2_ZERO, FP2_ZERO, FP2_ONE}, {FP2_ZERO, FP2_ZERO, FP2_MINUS_ONE, FP2_ZERO}}}, {{{FP2_ONE, FP2_ZERO, FP2_ZERO, FP2_ZERO}, {FP2_ZERO, FP2_ONE, FP2_ZERO, FP2_ZERO}, {FP2_ZERO, FP2_ZERO, FP2_ONE, FP2_ZERO}, {FP2_ZERO, FP2_ZERO, FP2_ZERO, FP2_MINUS_ONE}}}, {{{FP2_ONE, FP2_ONE, FP2_ONE, FP2_ONE}, {FP2_ONE, FP2_MINUS_ONE, FP2_MINUS_ONE, FP2_ONE}, {FP2_ONE, FP2_ONE, FP2_MINUS_ONE, FP2_MINUS_ONE}, {FP2_MINUS_ONE, FP2_ONE, FP2_MINUS_ONE, FP2_ONE}}}, {{{FP2_ONE, FP2_ZERO, FP2_ZERO, FP2_ZERO}, {FP2_ZERO, FP2_ONE, FP2_ZERO, FP2_ZERO}, {FP2_ZERO, FP2_ZERO, FP2_ZERO, FP2_ONE}, {FP2_ZERO, FP2_ZERO, FP2_ONE, FP2_ZERO}}}, {{{FP2_ONE, FP2_ONE, FP2_ONE, FP2_ONE}, {FP2_ONE, FP2_MINUS_ONE, FP2_ONE, FP2_MINUS_ONE}, {FP2_ONE, FP2_MINUS_ONE, FP2_MINUS_ONE, FP2_ONE}, {FP2_MINUS_ONE, FP2_MINUS_ONE, FP2_ONE, FP2_ONE}}}, {{{FP2_ONE, FP2_ONE, FP2_ONE, FP2_ONE}, {FP2_ONE, FP2_MINUS_ONE, FP2_ONE, FP2_MINUS_ONE}, {FP2_ONE, FP2_MINUS_ONE, FP2_MINUS_ONE, FP2_ONE}, {FP2_ONE, FP2_ONE, FP2_MINUS_ONE, FP2_MINUS_ONE}}}, {{{FP2_ONE, FP2_ONE, FP2_ONE, FP2_ONE}, {FP2_ONE, FP2_MINUS_ONE, FP2_ONE, FP2_MINUS_ONE}, {FP2_ONE, FP2_ONE, FP2_MINUS_ONE, FP2_MINUS_ONE}, {FP2_MINUS_ONE, FP2_ONE, FP2_ONE, FP2_MINUS_ONE}}}, {{{FP2_ONE, FP2_ZERO, FP2_ZERO, FP2_ZERO}, {FP2_ZERO, FP2_ONE, FP2_ZERO, FP2_ZERO}, {FP2_ZERO, FP2_ZERO, FP2_ONE, FP2_ZERO}, {FP2_ZERO, FP2_ZERO, FP2_ZERO, FP2_ONE}}}};
+const precomp_basis_change_matrix_t NORMALIZATION_TRANSFORMS[6] = {{{{FP2_ONE, FP2_ZERO, FP2_ZERO, FP2_ZERO}, {FP2_ZERO, FP2_ONE, FP2_ZERO, FP2_ZERO}, {FP2_ZERO, FP2_ZERO, FP2_ONE, FP2_ZERO}, {FP2_ZERO, FP2_ZERO, FP2_ZERO, FP2_ONE}}}, {{{FP2_ZERO, FP2_ZERO, FP2_ZERO, FP2_ONE}, {FP2_ZERO, FP2_ZERO, FP2_ONE, FP2_ZERO}, {FP2_ZERO, FP2_ONE, FP2_ZERO, FP2_ZERO}, {FP2_ONE, FP2_ZERO, FP2_ZERO, FP2_ZERO}}}, {{{FP2_ONE, FP2_ONE, FP2_ONE, FP2_ONE}, {FP2_ONE, FP2_MINUS_ONE, FP2_ONE, FP2_MINUS_ONE}, {FP2_ONE, FP2_ONE, FP2_MINUS_ONE, FP2_MINUS_ONE}, {FP2_ONE, FP2_MINUS_ONE, FP2_MINUS_ONE, FP2_ONE}}}, {{{FP2_ONE, FP2_MINUS_ONE, FP2_MINUS_ONE, FP2_ONE}, {FP2_MINUS_ONE, FP2_MINUS_ONE, FP2_ONE, FP2_ONE}, {FP2_MINUS_ONE, FP2_ONE, FP2_MINUS_ONE, FP2_ONE}, {FP2_ONE, FP2_ONE, FP2_ONE, FP2_ONE}}}, {{{FP2_MINUS_ONE, FP2_I, FP2_I, FP2_ONE}, {FP2_I, FP2_MINUS_ONE, FP2_ONE, FP2_I}, {FP2_I, FP2_ONE, FP2_MINUS_ONE, FP2_I}, {FP2_ONE, FP2_I, FP2_I, FP2_MINUS_ONE}}}, {{{FP2_ONE, FP2_I, FP2_I, FP2_MINUS_ONE}, {FP2_I, FP2_ONE, FP2_MINUS_ONE, FP2_I}, {FP2_I, FP2_MINUS_ONE, FP2_ONE, FP2_I}, {FP2_MINUS_ONE, FP2_I, FP2_I, FP2_ONE}}}};
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd_splitting_transforms.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd_splitting_transforms.h
new file mode 100644
index 0000000000..b3147a42a9
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hd_splitting_transforms.h
@@ -0,0 +1,18 @@
+#ifndef HD_SPLITTING_H
+#define HD_SPLITTING_H
+
+#include
+#include
+
+typedef struct precomp_basis_change_matrix {
+ uint8_t m[4][4];
+} precomp_basis_change_matrix_t;
+
+extern const int EVEN_INDEX[10][2];
+extern const int CHI_EVAL[4][4];
+extern const fp2_t FP2_CONSTANTS[5];
+extern const precomp_basis_change_matrix_t SPLITTING_TRANSFORMS[10];
+extern const precomp_basis_change_matrix_t NORMALIZATION_TRANSFORMS[6];
+
+#endif
+
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hnf.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hnf.c
new file mode 100644
index 0000000000..5edff425c8
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hnf.c
@@ -0,0 +1,210 @@
+#include "hnf_internal.h"
+#include "internal.h"
+
+// HNF test function
+int
+ibz_mat_4x4_is_hnf(const ibz_mat_4x4_t *mat)
+{
+ int res = 1;
+ int found;
+ int ind = 0;
+ ibz_t zero;
+ ibz_init(&zero);
+ // upper triangular
+ for (int i = 0; i < 4; i++) {
+ // upper triangular
+ for (int j = 0; j < i; j++) {
+ res = res && ibz_is_zero(&(mat->m[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->m[i][j]), &zero) >= 0);
+ res = res && (ibz_cmp(&(mat->m[i][ind]), &(mat->m[i][j])) > 0);
+ } else {
+ if (!ibz_is_zero(&(mat->m[i][j]))) {
+ found = 1;
+ ind = j;
+ // mustbe non-negative
+ res = res && (ibz_cmp(&(mat->m[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->m[i][j])))) {
+ i = i + 1;
+ }
+ if (i != 4) {
+ res = res && (linestart < i);
+ }
+ i = 0;
+ }
+ ibz_finalize(&zero);
+ return res;
+}
+
+// Untested HNF helpers
+// centered mod
+void
+ibz_vec_4_linear_combination_mod(ibz_vec_4_t *lc,
+ const ibz_t *coeff_a,
+ const ibz_vec_4_t *vec_a,
+ const ibz_t *coeff_b,
+ const ibz_vec_4_t *vec_b,
+ const ibz_t *mod)
+{
+ ibz_t prod, m;
+ ibz_vec_4_t sums;
+ ibz_vec_4_init(&sums);
+ ibz_init(&prod);
+ ibz_init(&m);
+ ibz_copy(&m, mod);
+ for (int i = 0; i < 4; i++) {
+ ibz_mul(&(sums.v[i]), coeff_a, &(vec_a->v[i]));
+ ibz_mul(&prod, coeff_b, &(vec_b->v[i]));
+ ibz_add(&(sums.v[i]), &(sums.v[i]), &prod);
+ ibz_centered_mod(&(sums.v[i]), &(sums.v[i]), &m);
+ }
+ for (int i = 0; i < 4; i++) {
+ ibz_copy(&(lc->v[i]), &(sums.v[i]));
+ }
+ ibz_finalize(&prod);
+ ibz_finalize(&m);
+ ibz_vec_4_finalize(&sums);
+}
+
+void
+ibz_vec_4_copy_mod(ibz_vec_4_t *res, const ibz_vec_4_t *vec, const ibz_t *mod)
+{
+ ibz_t m;
+ ibz_init(&m);
+ ibz_copy(&m, mod);
+ for (int i = 0; i < 4; i++) {
+ ibz_centered_mod(&(res->v[i]), &(vec->v[i]), &m);
+ }
+ ibz_finalize(&m);
+}
+
+// no need to center this, and not 0
+void
+ibz_vec_4_scalar_mul_mod(ibz_vec_4_t *prod, const ibz_t *scalar, const ibz_vec_4_t *vec, const ibz_t *mod)
+{
+ ibz_t m, s;
+ ibz_init(&m);
+ ibz_init(&s);
+ ibz_copy(&s, scalar);
+ ibz_copy(&m, mod);
+ for (int i = 0; i < 4; i++) {
+ ibz_mul(&(prod->v[i]), &(vec->v[i]), &s);
+ ibz_mod(&(prod->v[i]), &(prod->v[i]), &m);
+ }
+ ibz_finalize(&m);
+ ibz_finalize(&s);
+}
+
+// Algorithm used is the one at number 2.4.8 in Henri Cohen's "A Course in Computational Algebraic
+// Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993
+// assumes ibz_xgcd outputs u,v which are small in absolute value (as described in the
+// book)
+void
+ibz_mat_4xn_hnf_mod_core(ibz_mat_4x4_t *hnf, int generator_number, const ibz_vec_4_t *generators, const ibz_t *mod)
+{
+ int i = 3;
+ assert(generator_number > 3);
+ int n = generator_number;
+ int j = n - 1;
+ int k = n - 1;
+ ibz_t b, u, v, d, q, m, coeff_1, coeff_2, r;
+ ibz_vec_4_t c;
+ ibz_vec_4_t a[generator_number];
+ ibz_vec_4_t w[4];
+ ibz_init(&b);
+ ibz_init(&d);
+ ibz_init(&u);
+ ibz_init(&v);
+ ibz_init(&r);
+ ibz_init(&m);
+ ibz_init(&q);
+ ibz_init(&coeff_1);
+ ibz_init(&coeff_2);
+ ibz_vec_4_init(&c);
+ for (int h = 0; h < n; h++) {
+ if (h < 4)
+ ibz_vec_4_init(&(w[h]));
+ ibz_vec_4_init(&(a[h]));
+ ibz_copy(&(a[h].v[0]), &(generators[h].v[0]));
+ ibz_copy(&(a[h].v[1]), &(generators[h].v[1]));
+ ibz_copy(&(a[h].v[2]), &(generators[h].v[2]));
+ ibz_copy(&(a[h].v[3]), &(generators[h].v[3]));
+ }
+ assert(ibz_cmp(mod, &ibz_const_zero) > 0);
+ ibz_copy(&m, mod);
+ while (i != -1) {
+ while (j != 0) {
+ j = j - 1;
+ if (!ibz_is_zero(&(a[j].v[i]))) {
+ // assumtion that ibz_xgcd outputs u,v which are small in absolute
+ // value is needed here also, needs u non 0, but v can be 0 if needed
+ ibz_xgcd_with_u_not_0(&d, &u, &v, &(a[k].v[i]), &(a[j].v[i]));
+ ibz_vec_4_linear_combination(&c, &u, &(a[k]), &v, &(a[j]));
+ ibz_div(&coeff_1, &r, &(a[k].v[i]), &d);
+ ibz_div(&coeff_2, &r, &(a[j].v[i]), &d);
+ ibz_neg(&coeff_2, &coeff_2);
+ ibz_vec_4_linear_combination_mod(
+ &(a[j]), &coeff_1, &(a[j]), &coeff_2, &(a[k]), &m); // do lin comb mod m
+ ibz_vec_4_copy_mod(&(a[k]), &c, &m); // mod m in copy
+ }
+ }
+ ibz_xgcd_with_u_not_0(&d, &u, &v, &(a[k].v[i]), &m);
+ ibz_vec_4_scalar_mul_mod(&(w[i]), &u, &(a[k]), &m); // mod m in scalar mult
+ if (ibz_is_zero(&(w[i].v[i]))) {
+ ibz_copy(&(w[i].v[i]), &m);
+ }
+ for (int h = i + 1; h < 4; h++) {
+ ibz_div_floor(&q, &r, &(w[h].v[i]), &(w[i].v[i]));
+ ibz_neg(&q, &q);
+ ibz_vec_4_linear_combination(&(w[h]), &ibz_const_one, &(w[h]), &q, &(w[i]));
+ }
+ ibz_div(&m, &r, &m, &d);
+ assert(ibz_is_zero(&r));
+ if (i != 0) {
+ k = k - 1;
+ i = i - 1;
+ j = k;
+ if (ibz_is_zero(&(a[k].v[i])))
+ ibz_copy(&(a[k].v[i]), &m);
+
+ } else {
+ k = k - 1;
+ i = i - 1;
+ j = k;
+ }
+ }
+ for (j = 0; j < 4; j++) {
+ for (i = 0; i < 4; i++) {
+ ibz_copy(&((hnf->m)[i][j]), &(w[j].v[i]));
+ }
+ }
+
+ ibz_finalize(&b);
+ ibz_finalize(&d);
+ ibz_finalize(&u);
+ ibz_finalize(&v);
+ ibz_finalize(&r);
+ ibz_finalize(&q);
+ ibz_finalize(&coeff_1);
+ ibz_finalize(&coeff_2);
+ ibz_finalize(&m);
+ ibz_vec_4_finalize(&c);
+ for (int h = 0; h < n; h++) {
+ if (h < 4)
+ ibz_vec_4_finalize(&(w[h]));
+ ibz_vec_4_finalize(&(a[h]));
+ }
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hnf_internal.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hnf_internal.c
new file mode 100644
index 0000000000..b2db5b54c9
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hnf_internal.c
@@ -0,0 +1,182 @@
+#include "hnf_internal.h"
+#include "internal.h"
+
+// Small helper for integers
+void
+ibz_mod_not_zero(ibz_t *res, const ibz_t *x, const ibz_t *mod)
+{
+ ibz_t m, t;
+ ibz_init(&m);
+ ibz_init(&t);
+ ibz_mod(&m, x, mod);
+ ibz_set(&t, ibz_is_zero(&m));
+ ibz_mul(&t, &t, mod);
+ ibz_add(res, &m, &t);
+ ibz_finalize(&m);
+ ibz_finalize(&t);
+}
+
+// centered and rather positive then negative
+void
+ibz_centered_mod(ibz_t *remainder, const ibz_t *a, const ibz_t *mod)
+{
+ assert(ibz_cmp(mod, &ibz_const_zero) > 0);
+ ibz_t tmp, d, t;
+ ibz_init(&tmp);
+ ibz_init(&d);
+ ibz_init(&t);
+ ibz_div_floor(&d, &tmp, mod, &ibz_const_two);
+ ibz_mod_not_zero(&tmp, a, mod);
+ ibz_set(&t, ibz_cmp(&tmp, &d) > 0);
+ ibz_mul(&t, &t, mod);
+ ibz_sub(remainder, &tmp, &t);
+ ibz_finalize(&tmp);
+ ibz_finalize(&d);
+ ibz_finalize(&t);
+}
+
+// if c, res = x, else res = y
+void
+ibz_conditional_assign(ibz_t *res, const ibz_t *x, const ibz_t *y, int c)
+{
+ ibz_t s, t, r;
+ ibz_init(&r);
+ ibz_init(&s);
+ ibz_init(&t);
+ ibz_set(&s, c != 0);
+ ibz_sub(&t, &ibz_const_one, &s);
+ ibz_mul(&r, &s, x);
+ ibz_mul(res, &t, y);
+ ibz_add(res, &r, res);
+ ibz_finalize(&r);
+ ibz_finalize(&s);
+ ibz_finalize(&t);
+}
+
+// mpz_gcdext specification specifies unique outputs used here
+void
+ibz_xgcd_with_u_not_0(ibz_t *d, ibz_t *u, ibz_t *v, const ibz_t *x, const ibz_t *y)
+{
+ if (ibz_is_zero(x) & ibz_is_zero(y)) {
+ ibz_set(d, 1);
+ ibz_set(u, 1);
+ ibz_set(v, 0);
+ return;
+ }
+ ibz_t q, r, x1, y1;
+ ibz_init(&q);
+ ibz_init(&r);
+ ibz_init(&x1);
+ ibz_init(&y1);
+ ibz_copy(&x1, x);
+ ibz_copy(&y1, y);
+
+ // xgcd
+ ibz_xgcd(d, u, v, &x1, &y1);
+
+ // make sure u!=0 (v can be 0 if needed)
+ // following GMP specification, u == 0 implies y|x
+ if (ibz_is_zero(u)) {
+ if (!ibz_is_zero(&x1)) {
+ if (ibz_is_zero(&y1)) {
+ ibz_set(&y1, 1);
+ }
+ ibz_div(&q, &r, &x1, &y1);
+ assert(ibz_is_zero(&r));
+ ibz_sub(v, v, &q);
+ }
+ ibz_set(u, 1);
+ }
+ if (!ibz_is_zero(&x1)) {
+ // Make sure ux > 0 (and as small as possible)
+ assert(ibz_cmp(d, &ibz_const_zero) > 0);
+ ibz_mul(&r, &x1, &y1);
+ int neg = ibz_cmp(&r, &ibz_const_zero) < 0;
+ ibz_mul(&q, &x1, u);
+ while (ibz_cmp(&q, &ibz_const_zero) <= 0) {
+ ibz_div(&q, &r, &y1, d);
+ assert(ibz_is_zero(&r));
+ if (neg) {
+ ibz_neg(&q, &q);
+ }
+ ibz_add(u, u, &q);
+ ibz_div(&q, &r, &x1, d);
+ assert(ibz_is_zero(&r));
+ if (neg) {
+ ibz_neg(&q, &q);
+ }
+ ibz_sub(v, v, &q);
+
+ ibz_mul(&q, &x1, u);
+ }
+ }
+
+#ifndef NDEBUG
+ int res = 0;
+ ibz_t sum, prod, test, cmp;
+ ibz_init(&sum);
+ ibz_init(&prod);
+ ibz_init(&cmp);
+ ibz_init(&test);
+ // sign correct
+ res = res | !(ibz_cmp(d, &ibz_const_zero) >= 0);
+ if (ibz_is_zero(&x1) && ibz_is_zero(&y1)) {
+ res = res | !(ibz_is_zero(v) && ibz_is_one(u) && ibz_is_one(d));
+ } else {
+ if (!ibz_is_zero(&x1) && !ibz_is_zero(&y1)) {
+ // GCD divides x
+ ibz_div(&sum, &prod, &x1, d);
+ res = res | !ibz_is_zero(&prod);
+ // Small enough
+ ibz_mul(&prod, &x1, u);
+ res = res | !(ibz_cmp(&prod, &ibz_const_zero) > 0);
+ ibz_mul(&sum, &sum, &y1);
+ ibz_abs(&sum, &sum);
+ res = res | !(ibz_cmp(&prod, &sum) <= 0);
+
+ // GCD divides y
+ ibz_div(&sum, &prod, &y1, d);
+ res = res | !ibz_is_zero(&prod);
+ // Small enough
+ ibz_mul(&prod, &y1, v);
+ res = res | !(ibz_cmp(&prod, &ibz_const_zero) <= 0);
+ ibz_mul(&sum, &sum, &x1);
+ ibz_abs(&sum, &sum);
+ res = res | !(ibz_cmp(&prod, &sum) < 0);
+ } else {
+ // GCD divides x
+ ibz_div(&sum, &prod, &x1, d);
+ res = res | !ibz_is_zero(&prod);
+ // GCD divides y
+ ibz_div(&sum, &prod, &y1, d);
+ res = res | !ibz_is_zero(&prod);
+ if (ibz_is_zero(&x1) && !ibz_is_zero(&y1)) {
+ ibz_abs(&prod, v);
+ res = res | !(ibz_is_one(&prod));
+ res = res | !(ibz_is_one(u));
+ } else {
+ ibz_abs(&prod, u);
+ res = res | !(ibz_is_one(&prod));
+ res = res | !(ibz_is_zero(v));
+ }
+ }
+
+ // Bezout coeffs
+ ibz_mul(&sum, &x1, u);
+ ibz_mul(&prod, &y1, v);
+ ibz_add(&sum, &sum, &prod);
+ res = res | !(ibz_cmp(&sum, d) == 0);
+ }
+ assert(!res);
+ ibz_finalize(&sum);
+ ibz_finalize(&prod);
+ ibz_finalize(&cmp);
+ ibz_finalize(&test);
+
+#endif
+
+ ibz_finalize(&x1);
+ ibz_finalize(&y1);
+ ibz_finalize(&q);
+ ibz_finalize(&r);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hnf_internal.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hnf_internal.h
new file mode 100644
index 0000000000..2302bbc0c6
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/hnf_internal.h
@@ -0,0 +1,94 @@
+/** @file
+ *
+ * @authors Sina Schaeffler
+ *
+ * @brief Declarations for functions internal to the HNF computation and its tests
+ */
+
+#ifndef QUAT_HNF_HELPERS_H
+#define QUAT_HNF_HELPERS_H
+
+#include
+
+/** @internal
+ * @ingroup quat_helpers
+ * @defgroup quat_hnf_helpers Internal functions for the HNF computation and tests
+ */
+
+/** @internal
+ * @ingroup quat_hnf_helpers
+ * @defgroup quat_hnf_helpers_ibz Internal renamed GMP functions for the HNF computation
+ */
+
+/**
+ * @brief GCD and Bézout coefficients u, v such that ua + bv = gcd
+ *
+ * @param gcd Output: Set to the gcd of a and b
+ * @param u Output: integer such that ua+bv=gcd
+ * @param v Output: Integer such that ua+bv=gcd
+ * @param a
+ * @param b
+ */
+void ibz_xgcd(ibz_t *gcd,
+ ibz_t *u,
+ ibz_t *v,
+ const ibz_t *a,
+ const ibz_t *b); // integers, dim4, test/integers, test/dim4
+
+/** @}
+ */
+
+/** @internal
+ * @ingroup quat_hnf_helpers
+ * @defgroup quat_hnf_integer_helpers Integer functions internal to the HNF computation and tests
+ * @{
+ */
+
+/** @brief x mod mod, with x in [1,mod]
+ *
+ * @param res Output: res = x [mod] and 0 0
+ */
+void ibz_mod_not_zero(ibz_t *res, const ibz_t *x, const ibz_t *mod);
+
+/** @brief x mod mod, with x in ]-mod/2,mod/2]
+ *
+ * Centered and rather positive then negative.
+ *
+ * @param remainder Output: remainder = x [mod] and -mod/2 0
+ */
+void ibz_centered_mod(ibz_t *remainder, const ibz_t *a, const ibz_t *mod);
+
+/** @brief if c then x else y
+ *
+ * @param res Output: if c, res = x, else res = y
+ * @param x
+ * @param y
+ * @param c condition: must be 0 or 1
+ */
+void ibz_conditional_assign(ibz_t *res, const ibz_t *x, const ibz_t *y, int c);
+
+/** @brief d = gcd(x,y)>0 and d = ux+vy and u!= 0 and d>0 and u, v of small absolute value, u not 0
+ *
+ * More precisely:
+ * If x and y are both non 0, -|xy|/d
+#else
+#include
+#endif
+
+void
+ibz_xgcd(ibz_t *gcd, ibz_t *u, ibz_t *v, const ibz_t *a, const ibz_t *b)
+{
+ mpz_gcdext(gcd->i, u->i, v->i, a->i, b->i);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/id2iso.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/id2iso.c
new file mode 100644
index 0000000000..1be9d87e71
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/id2iso.c
@@ -0,0 +1,338 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// Scalar multiplication [x]P + [y]Q where x and y are stored
+// inside an ibz_vec_2_t [x, y] and P, Q \in E[2^f]
+void
+ec_biscalar_mul_ibz_vec(ec_point_t *res,
+ const ibz_vec_2_t *scalar_vec,
+ const int f,
+ const ec_basis_t *PQ,
+ const ec_curve_t *curve)
+{
+ digit_t scalars[2][NWORDS_ORDER];
+ ibz_to_digit_array(scalars[0], &scalar_vec->v[0]);
+ ibz_to_digit_array(scalars[1], &scalar_vec->v[1]);
+ ec_biscalar_mul(res, scalars[0], scalars[1], f, PQ, curve);
+}
+
+// Given an ideal, computes the scalars s0, s1 which determine the kernel generator
+// of the equivalent isogeny
+void
+id2iso_ideal_to_kernel_dlogs_even(ibz_vec_2_t *vec, const quat_left_ideal_t *lideal)
+{
+ ibz_t tmp;
+ ibz_init(&tmp);
+
+ ibz_mat_2x2_t mat;
+ ibz_mat_2x2_init(&mat);
+
+ // construct the matrix of the dual of alpha on the 2^f-torsion
+ {
+ quat_alg_elem_t alpha;
+ quat_alg_elem_init(&alpha);
+
+ int lideal_generator_ok UNUSED = quat_lideal_generator(&alpha, lideal, &QUATALG_PINFTY);
+ assert(lideal_generator_ok);
+ quat_alg_conj(&alpha, &alpha);
+
+ ibz_vec_4_t coeffs;
+ ibz_vec_4_init(&coeffs);
+ quat_change_to_O0_basis(&coeffs, &alpha);
+
+ for (unsigned i = 0; i < 2; ++i) {
+ ibz_add(&mat.m[i][i], &mat.m[i][i], &coeffs.v[0]);
+ for (unsigned j = 0; j < 2; ++j) {
+ ibz_mul(&tmp, &ACTION_GEN2.m[i][j], &coeffs.v[1]);
+ ibz_add(&mat.m[i][j], &mat.m[i][j], &tmp);
+ ibz_mul(&tmp, &ACTION_GEN3.m[i][j], &coeffs.v[2]);
+ ibz_add(&mat.m[i][j], &mat.m[i][j], &tmp);
+ ibz_mul(&tmp, &ACTION_GEN4.m[i][j], &coeffs.v[3]);
+ ibz_add(&mat.m[i][j], &mat.m[i][j], &tmp);
+ }
+ }
+
+ ibz_vec_4_finalize(&coeffs);
+ quat_alg_elem_finalize(&alpha);
+ }
+
+ // find the kernel of alpha modulo the norm of the ideal
+ {
+ const ibz_t *const norm = &lideal->norm;
+
+ ibz_mod(&vec->v[0], &mat.m[0][0], norm);
+ ibz_mod(&vec->v[1], &mat.m[1][0], norm);
+ ibz_gcd(&tmp, &vec->v[0], &vec->v[1]);
+ if (ibz_is_even(&tmp)) {
+ ibz_mod(&vec->v[0], &mat.m[0][1], norm);
+ ibz_mod(&vec->v[1], &mat.m[1][1], norm);
+ }
+#ifndef NDEBUG
+ ibz_gcd(&tmp, &vec->v[0], norm);
+ ibz_gcd(&tmp, &vec->v[1], &tmp);
+ assert(!ibz_cmp(&tmp, &ibz_const_one));
+#endif
+ }
+
+ ibz_mat_2x2_finalize(&mat);
+ ibz_finalize(&tmp);
+}
+
+// helper function to apply a matrix to a basis of E[2^f]
+// works in place
+int
+matrix_application_even_basis(ec_basis_t *bas, const ec_curve_t *E, ibz_mat_2x2_t *mat, int f)
+{
+ digit_t scalars[2][NWORDS_ORDER] = { 0 };
+ int ret;
+
+ ibz_t tmp, pow_two;
+ ibz_init(&tmp);
+ ibz_init(&pow_two);
+ ibz_pow(&pow_two, &ibz_const_two, f);
+
+ ec_basis_t tmp_bas;
+ copy_basis(&tmp_bas, bas);
+
+ // reduction mod 2f
+ ibz_mod(&mat->m[0][0], &mat->m[0][0], &pow_two);
+ ibz_mod(&mat->m[0][1], &mat->m[0][1], &pow_two);
+ ibz_mod(&mat->m[1][0], &mat->m[1][0], &pow_two);
+ ibz_mod(&mat->m[1][1], &mat->m[1][1], &pow_two);
+
+ // For a matrix [[a, c], [b, d]] we compute:
+ //
+ // first basis element R = [a]P + [b]Q
+ ibz_to_digit_array(scalars[0], &mat->m[0][0]);
+ ibz_to_digit_array(scalars[1], &mat->m[1][0]);
+ ec_biscalar_mul(&bas->P, scalars[0], scalars[1], f, &tmp_bas, E);
+
+ // second basis element S = [c]P + [d]Q
+ ibz_to_digit_array(scalars[0], &mat->m[0][1]);
+ ibz_to_digit_array(scalars[1], &mat->m[1][1]);
+ ec_biscalar_mul(&bas->Q, scalars[0], scalars[1], f, &tmp_bas, E);
+
+ // Their difference R - S = [a - c]P + [b - d]Q
+ ibz_sub(&tmp, &mat->m[0][0], &mat->m[0][1]);
+ ibz_mod(&tmp, &tmp, &pow_two);
+ ibz_to_digit_array(scalars[0], &tmp);
+ ibz_sub(&tmp, &mat->m[1][0], &mat->m[1][1]);
+ ibz_mod(&tmp, &tmp, &pow_two);
+ ibz_to_digit_array(scalars[1], &tmp);
+ ret = ec_biscalar_mul(&bas->PmQ, scalars[0], scalars[1], f, &tmp_bas, E);
+
+ ibz_finalize(&tmp);
+ ibz_finalize(&pow_two);
+
+ return ret;
+}
+
+// helper function to apply some endomorphism of E0 on the precomputed basis of E[2^f]
+// works in place
+void
+endomorphism_application_even_basis(ec_basis_t *bas,
+ const int index_alternate_curve,
+ const ec_curve_t *E,
+ const quat_alg_elem_t *theta,
+ int f)
+{
+ ibz_t tmp;
+ ibz_init(&tmp);
+ ibz_vec_4_t coeffs;
+ ibz_vec_4_init(&coeffs);
+ ibz_mat_2x2_t mat;
+ ibz_mat_2x2_init(&mat);
+
+ ibz_t content;
+ ibz_init(&content);
+
+ // decomposing theta on the basis
+ quat_alg_make_primitive(&coeffs, &content, theta, &EXTREMAL_ORDERS[index_alternate_curve].order);
+ assert(ibz_is_odd(&content));
+
+ ibz_set(&mat.m[0][0], 0);
+ ibz_set(&mat.m[0][1], 0);
+ ibz_set(&mat.m[1][0], 0);
+ ibz_set(&mat.m[1][1], 0);
+
+ // computing the matrix
+
+ for (unsigned i = 0; i < 2; ++i) {
+ ibz_add(&mat.m[i][i], &mat.m[i][i], &coeffs.v[0]);
+ for (unsigned j = 0; j < 2; ++j) {
+ ibz_mul(&tmp, &CURVES_WITH_ENDOMORPHISMS[index_alternate_curve].action_gen2.m[i][j], &coeffs.v[1]);
+ ibz_add(&mat.m[i][j], &mat.m[i][j], &tmp);
+ ibz_mul(&tmp, &CURVES_WITH_ENDOMORPHISMS[index_alternate_curve].action_gen3.m[i][j], &coeffs.v[2]);
+ ibz_add(&mat.m[i][j], &mat.m[i][j], &tmp);
+ ibz_mul(&tmp, &CURVES_WITH_ENDOMORPHISMS[index_alternate_curve].action_gen4.m[i][j], &coeffs.v[3]);
+ ibz_add(&mat.m[i][j], &mat.m[i][j], &tmp);
+ ibz_mul(&mat.m[i][j], &mat.m[i][j], &content);
+ }
+ }
+
+ // and now we apply it
+ matrix_application_even_basis(bas, E, &mat, f);
+
+ ibz_vec_4_finalize(&coeffs);
+ ibz_mat_2x2_finalize(&mat);
+ ibz_finalize(&content);
+
+ ibz_finalize(&tmp);
+}
+
+// compute the ideal whose kernel is generated by vec2[0]*BO[0] + vec2[1]*B0[1] where B0 is the
+// canonical basis of E0
+void
+id2iso_kernel_dlogs_to_ideal_even(quat_left_ideal_t *lideal, const ibz_vec_2_t *vec2, int f)
+{
+
+ // algorithm: apply endomorphisms 1 and j+(1+k)/2 to the kernel point,
+ // the result should form a basis of the respective torsion subgroup.
+ // then apply i to the kernel point and decompose over said basis.
+ // hence we have an equation a*P + b*[j+(1+k)/2]P == [i]P, which will
+ // easily reveal an endomorphism that kills P.
+
+ ibz_t two_pow;
+ ibz_init(&two_pow);
+
+ ibz_vec_2_t vec;
+ ibz_vec_2_init(&vec);
+
+ if (f == TORSION_EVEN_POWER) {
+ ibz_copy(&two_pow, &TORSION_PLUS_2POWER);
+ } else {
+ ibz_pow(&two_pow, &ibz_const_two, f);
+ }
+
+ {
+ ibz_mat_2x2_t mat;
+ ibz_mat_2x2_init(&mat);
+
+ ibz_copy(&mat.m[0][0], &vec2->v[0]);
+ ibz_copy(&mat.m[1][0], &vec2->v[1]);
+
+ ibz_mat_2x2_eval(&vec, &ACTION_J, vec2);
+ ibz_copy(&mat.m[0][1], &vec.v[0]);
+ ibz_copy(&mat.m[1][1], &vec.v[1]);
+
+ ibz_mat_2x2_eval(&vec, &ACTION_GEN4, vec2);
+ ibz_add(&mat.m[0][1], &mat.m[0][1], &vec.v[0]);
+ ibz_add(&mat.m[1][1], &mat.m[1][1], &vec.v[1]);
+
+ ibz_mod(&mat.m[0][1], &mat.m[0][1], &two_pow);
+ ibz_mod(&mat.m[1][1], &mat.m[1][1], &two_pow);
+
+ ibz_mat_2x2_t inv;
+ ibz_mat_2x2_init(&inv);
+ {
+ int inv_ok UNUSED = ibz_mat_2x2_inv_mod(&inv, &mat, &two_pow);
+ assert(inv_ok);
+ }
+ ibz_mat_2x2_finalize(&mat);
+
+ ibz_mat_2x2_eval(&vec, &ACTION_I, vec2);
+ ibz_mat_2x2_eval(&vec, &inv, &vec);
+
+ ibz_mat_2x2_finalize(&inv);
+ }
+
+ // final result: a - i + b*(j+(1+k)/2)
+ quat_alg_elem_t gen;
+ quat_alg_elem_init(&gen);
+ ibz_set(&gen.denom, 2);
+ ibz_add(&gen.coord.v[0], &vec.v[0], &vec.v[0]);
+ ibz_set(&gen.coord.v[1], -2);
+ ibz_add(&gen.coord.v[2], &vec.v[1], &vec.v[1]);
+ ibz_copy(&gen.coord.v[3], &vec.v[1]);
+ ibz_add(&gen.coord.v[0], &gen.coord.v[0], &vec.v[1]);
+ ibz_vec_2_finalize(&vec);
+
+ quat_lideal_create(lideal, &gen, &two_pow, &MAXORD_O0, &QUATALG_PINFTY);
+
+ assert(0 == ibz_cmp(&lideal->norm, &two_pow));
+
+ quat_alg_elem_finalize(&gen);
+ ibz_finalize(&two_pow);
+}
+
+// finds mat such that:
+// (mat*v).B2 = v.B1
+// where "." is the dot product, defined as (v1,v2).(P,Q) = v1*P + v2*Q
+// mat encodes the coordinates of the points of B1 in the basis B2
+// specifically requires B1 or B2 to be "full" w.r.t to the 2^n torsion, so that we use tate
+// full = 0 assumes B2 is "full" so the easier case.
+// if we want to switch the role of B2 and B1, we invert the matrix, e.g. set full = 1
+static void
+_change_of_basis_matrix_tate(ibz_mat_2x2_t *mat,
+ const ec_basis_t *B1,
+ const ec_basis_t *B2,
+ ec_curve_t *E,
+ int f,
+ bool invert)
+{
+ digit_t x1[NWORDS_ORDER] = { 0 }, x2[NWORDS_ORDER] = { 0 }, x3[NWORDS_ORDER] = { 0 }, x4[NWORDS_ORDER] = { 0 };
+
+#ifndef NDEBUG
+ int e_full = TORSION_EVEN_POWER;
+ int e_diff = e_full - f;
+#endif
+
+ // Ensure the input basis has points of order 2^f
+ if (invert) {
+ assert(test_basis_order_twof(B1, E, e_full));
+ ec_dlog_2_tate(x1, x2, x3, x4, B1, B2, E, f);
+ mp_invert_matrix(x1, x2, x3, x4, f, NWORDS_ORDER);
+ } else {
+ assert(test_basis_order_twof(B2, E, e_full));
+ ec_dlog_2_tate(x1, x2, x3, x4, B2, B1, E, f);
+ }
+
+#ifndef NDEBUG
+ {
+ if (invert) {
+ ec_point_t test, test2;
+ ec_biscalar_mul(&test, x1, x2, f, B2, E);
+ ec_dbl_iter(&test2, e_diff, &B1->P, E);
+ assert(ec_is_equal(&test, &test2));
+
+ ec_biscalar_mul(&test, x3, x4, f, B2, E);
+ ec_dbl_iter(&test2, e_diff, &B1->Q, E);
+ assert(ec_is_equal(&test, &test2));
+ } else {
+ ec_point_t test;
+ ec_biscalar_mul(&test, x1, x2, f, B2, E);
+ ec_dbl_iter(&test, e_diff, &test, E);
+ assert(ec_is_equal(&test, &(B1->P)));
+
+ ec_biscalar_mul(&test, x3, x4, f, B2, E);
+ ec_dbl_iter(&test, e_diff, &test, E);
+ assert(ec_is_equal(&test, &(B1->Q)));
+ }
+ }
+#endif
+
+ // Copy the results into the matrix
+ ibz_copy_digit_array(&(mat->m[0][0]), x1);
+ ibz_copy_digit_array(&(mat->m[1][0]), x2);
+ ibz_copy_digit_array(&(mat->m[0][1]), x3);
+ ibz_copy_digit_array(&(mat->m[1][1]), x4);
+}
+
+void
+change_of_basis_matrix_tate(ibz_mat_2x2_t *mat, const ec_basis_t *B1, const ec_basis_t *B2, ec_curve_t *E, int f)
+{
+ _change_of_basis_matrix_tate(mat, B1, B2, E, f, false);
+}
+
+void
+change_of_basis_matrix_tate_invert(ibz_mat_2x2_t *mat, const ec_basis_t *B1, const ec_basis_t *B2, ec_curve_t *E, int f)
+{
+ _change_of_basis_matrix_tate(mat, B1, B2, E, f, true);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/id2iso.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/id2iso.h
new file mode 100644
index 0000000000..1b4eaae3c5
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/id2iso.h
@@ -0,0 +1,280 @@
+/** @file
+ *
+ * @authors Antonin Leroux
+ *
+ * @brief The id2iso algorithms
+ */
+
+#ifndef ID2ISO_H
+#define ID2ISO_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/** @defgroup id2iso_id2iso Ideal to isogeny conversion
+ * @{
+ */
+static const quat_represent_integer_params_t QUAT_represent_integer_params = {
+ .algebra = &QUATALG_PINFTY, /// The level-specific quaternion algebra
+ .order = &(EXTREMAL_ORDERS[0]), // The special extremal order O0
+ .primality_test_iterations = QUAT_primality_num_iter // precompted bound on the iteration number in primality tests
+};
+
+/*************************** Functions *****************************/
+
+/** @defgroup id2iso_others Other functions needed for id2iso
+ * @{
+ */
+
+/**
+ * @brief Scalar multiplication [x]P + [y]Q where x and y are stored inside an
+ * ibz_vec_2_t [x, y] and P, Q in E[2^f]
+ *
+ * @param res Output: the point R = [x]P + [y]Q
+ * @param scalar_vec: a vector of ibz type elements (x, y)
+ * @param f: an integer such that P, Q are in E[2^f]
+ * @param PQ: an x-only basis x(P), x(Q) and x(P-Q)
+ * @param curve: the curve E the points P, Q, R are defined on
+ *
+ */
+void ec_biscalar_mul_ibz_vec(ec_point_t *res,
+ const ibz_vec_2_t *scalar_vec,
+ const int f,
+ const ec_basis_t *PQ,
+ const ec_curve_t *curve);
+
+/**
+ * @brief Translating an ideal of norm 2^f dividing p²-1 into the corresponding
+ * kernel coefficients
+ *
+ * @param ker_dlog Output : two coefficients indicating the decomposition of the
+ * kernel over the canonical basis of E0[2^f]
+ * @param lideal_input : O0-ideal corresponding to the ideal to be translated of
+ * norm 2^f
+ *
+ */
+void id2iso_ideal_to_kernel_dlogs_even(ibz_vec_2_t *ker_dlog, const quat_left_ideal_t *lideal_input);
+
+/**
+ * @brief Applies some 2x2 matrix on a basis of E[2^TORSION_EVEN_POWER]
+ *
+ * @param P the basis
+ * @param E the curve
+ * @param mat the matrix
+ * @param f TORSION_EVEN_POWER
+ * @returns 1 if success, 0 if error
+ *
+ * helper function, works in place
+ *
+ */
+int matrix_application_even_basis(ec_basis_t *P, const ec_curve_t *E, ibz_mat_2x2_t *mat, int f);
+
+/**
+ * @brief Applies some endomorphism of an alternate curve to E[f]
+ *
+ * @param P the basis
+ * @param index_alternate_curve index of the alternate order in the list of precomputed extremal
+ * orders
+ * @param E the curve (E is not required to be the alternate curve in question since in the end we
+ * only apply a matrix)
+ * @param theta the endomorphism
+ * @param f TORSION_EVEN_POWER
+ *
+ * helper function, works in place
+ *
+ */
+void endomorphism_application_even_basis(ec_basis_t *P,
+ const int index_alternate_curve,
+ const ec_curve_t *E,
+ const quat_alg_elem_t *theta,
+ int f);
+
+/**
+ * @brief Translating a kernel on the curve E0, represented as a vector with
+ * respect to the precomputed 2^f-torsion basis, into the corresponding O0-ideal
+ *
+ * @param lideal Output : the output O0-ideal
+ * @param f : exponent definining the norm of the ideal to compute
+ * @param vec2 : length-2 vector giving the 2-power part of the kernel with
+ * respect to the precomputed 2^f basis
+ *
+ */
+void id2iso_kernel_dlogs_to_ideal_even(quat_left_ideal_t *lideal, const ibz_vec_2_t *vec2, int f);
+
+/**
+ * @brief Change of basis matrix for full basis B2
+ * Finds mat such that:
+ * (mat*v).B2 = v.B1
+ * where "." is the dot product, defined as (v1,v2).(P,Q) = v1*P + v2*Q
+ *
+ * @param mat the computed change of basis matrix
+ * @param B1 the source basis for E[2^f]
+ * @param B2 the target basis for E[2^e]
+ * @param E the elliptic curve
+ * @param f 2^f is the order of the points of the input basis
+ *
+ * mat encodes the coordinates of the points of B1 in the basis B2
+ */
+void change_of_basis_matrix_tate(ibz_mat_2x2_t *mat, const ec_basis_t *B1, const ec_basis_t *B2, ec_curve_t *E, int f);
+
+/**
+ * @brief Change of basis matrix for full basis B2
+ * Finds mat such that:
+ * (mat*v).B1 = [2^e-f]*v.B2
+ * where "." is the dot product, defined as (v1,v2).(P,Q) = v1*P + v2*Q
+ *
+ * @param mat the computed change of basis matrix
+ * @param B1 the source basis for E[2^e]
+ * @param B2 the target basis for E[2^f]
+ * @param E the elliptic curve
+ * @param f 2^f is the order of the points of the input basis
+ *
+ * mat encodes the coordinates of the points of B1 in the basis B2, by
+ * applying change_of_basis_matrix_tate and inverting the outcome
+ */
+void change_of_basis_matrix_tate_invert(ibz_mat_2x2_t *mat,
+ const ec_basis_t *B1,
+ const ec_basis_t *B2,
+ ec_curve_t *E,
+ int f);
+
+/** @}
+ */
+
+/** @defgroup id2iso_arbitrary Arbitrary isogeny evaluation
+ * @{
+ */
+/**
+ * @brief Function to find elements u, v, d1, d2, beta1, beta2 for the ideal to isogeny
+ *
+ * @param u Output: integer
+ * @param v Output: integer
+ * @param beta1 Output: quaternion element
+ * @param beta2 Output: quaternion element
+ * @param d1 Output: integer
+ * @param d2 Output: integer
+ * @param index_alternate_order_1 Output: small integer (index of an alternate order)
+ * @param index_alternate_order_2 Output: small integer (index of an alternate order)
+ * @param target : integer, target norm
+ * @param lideal : O0-ideal defining the search space
+ * @param Bpoo : quaternion algebra
+ * @param num_alternate_order number of alternate order we consider
+ * @returns 1 if the computation succeeds, 0 otherwise
+ *
+ * Let us write ti = index_alternate_order_i,
+ * we look for u,v,beta1,beta2,d1,d2,t1,t2
+ * such that u d1 + v d2 = target
+ * and where di = norm(betai)/norm(Ii), where the ideal Ii is equal to overbar{Ji} * lideal and
+ * betai is in Ii where Ji is a connecting ideal between the maximal order O0 and O_ti t1,t2 must be
+ * contained between 0 and num_alternate_order This corresponds to the function SuitableIdeals in
+ * the spec
+ */
+int find_uv(ibz_t *u,
+ ibz_t *v,
+ quat_alg_elem_t *beta1,
+ quat_alg_elem_t *beta2,
+ ibz_t *d1,
+ ibz_t *d2,
+ int *index_alternate_order_1,
+ int *index_alternate_order_2,
+ const ibz_t *target,
+ const quat_left_ideal_t *lideal,
+ const quat_alg_t *Bpoo,
+ int num_alternate_order);
+
+/**
+ * @brief Computes an arbitrary isogeny of fixed degree starting from E0
+ * and evaluates it a list of points of the form (P1,0) or (0,P2).
+ *
+ * @param lideal Output : an ideal of norm u
+ * @param u : integer
+ * @param small : bit indicating if we the value of u is "small" meaning that we
+ expect it to be
+ * around sqrt{p}, in that case we use a length slightly above
+ * @param E34 Output: the codomain curve
+ * @param P12 Input/Output: pointer to points to be pushed through the isogeny
+ (in-place)
+ * @param numP: length of the list of points given in P12 (can be zero)
+ * @param index_alternate_order : index of the special extremal order to be used (in the list of
+ these orders)
+ * @returns the length of the chain if the computation succeeded, zero upon
+ failure
+ *
+ * F is an isogeny encoding an isogeny [adjust]*phi : E0 -> Eu of degree u
+ * note that the codomain of F can be either Eu x Eu' or Eu' x Eu for some curve
+ Eu'
+ */
+int fixed_degree_isogeny_and_eval(quat_left_ideal_t *lideal,
+ const ibz_t *u,
+ bool small,
+ theta_couple_curve_t *E34,
+ theta_couple_point_t *P12,
+ size_t numP,
+ const int index_alternate_order);
+
+/**
+ * @brief Translating an ideal into a representation of the corresponding
+ * isogeny
+ *
+ * @param beta1 Output: quaternion element
+ * @param beta2 Output: quaternion element
+ * @param u Output: integer
+ * @param v Output: integer
+ * @param d1 Output: integer
+ * @param d2 Output: integer
+ * @param codomain the codomain of the isogeny corresponding to lideal
+ * @param basis Output : evaluation of the canonical basis of E0 through the
+ * ideal corresponding to lideal
+ * @param lideal : O0 - ideal in input
+ * @param Bpoo : the quaternion algebra
+ * @returns 1 if the computation succeeded, 0 otherwise
+ *
+ * Compute the codomain and image on the basis of E0 of the isogeny
+ * E0 -> codomain corresponding to lideal
+ *
+ * There is some integer e >= 0 such that
+ * 2^e * u, 2^e * v,beta1, beta2, d1, d2 are the output of find_uv
+ * on input target = 2^TORSION_PLUS_EVEN_POWER and lideal
+ *
+ * codomain and basis are computed with the help of a dimension 2 isogeny
+ * of degree 2^TORSION_PLUS_EVEN_POWER - e using a Kani diagram
+ *
+ */
+int dim2id2iso_ideal_to_isogeny_clapotis(quat_alg_elem_t *beta1,
+ quat_alg_elem_t *beta2,
+ ibz_t *u,
+ ibz_t *v,
+ ibz_t *d1,
+ ibz_t *d2,
+ ec_curve_t *codomain,
+ ec_basis_t *basis,
+ const quat_left_ideal_t *lideal,
+ const quat_alg_t *Bpoo);
+
+/**
+ * @brief Translating an ideal into a representation of the corresponding
+ * isogeny
+ *
+ * @param basis Output : evaluation of the canonical basis of E0 through the
+ * ideal corresponding to lideal
+ * @param lideal : ideal in input
+ * @param codomain
+ * @returns 1 if the computation succeeds, 0 otherwise
+ *
+ * This is a wrapper around the ideal to isogeny clapotis function
+ */
+int dim2id2iso_arbitrary_isogeny_evaluation(ec_basis_t *basis, ec_curve_t *codomain, const quat_left_ideal_t *lideal);
+
+/** @}
+ */
+
+/** @}
+ */
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ideal.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ideal.c
new file mode 100644
index 0000000000..8634143941
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/ideal.c
@@ -0,0 +1,323 @@
+#include
+#include
+#include "internal.h"
+
+// assumes parent order and lattice correctly set, computes and sets the norm
+void
+quat_lideal_norm(quat_left_ideal_t *lideal)
+{
+ quat_lattice_index(&(lideal->norm), &(lideal->lattice), (lideal->parent_order));
+ int ok UNUSED = ibz_sqrt(&(lideal->norm), &(lideal->norm));
+ assert(ok);
+}
+
+// assumes parent order and lattice correctly set, recomputes and verifies its norm
+static int
+quat_lideal_norm_verify(const quat_left_ideal_t *lideal)
+{
+ int res;
+ ibz_t index;
+ ibz_init(&index);
+ quat_lattice_index(&index, &(lideal->lattice), (lideal->parent_order));
+ ibz_sqrt(&index, &index);
+ res = (ibz_cmp(&(lideal->norm), &index) == 0);
+ ibz_finalize(&index);
+ return (res);
+}
+
+void
+quat_lideal_copy(quat_left_ideal_t *copy, const quat_left_ideal_t *copied)
+{
+ copy->parent_order = copied->parent_order;
+ ibz_copy(©->norm, &copied->norm);
+ ibz_copy(©->lattice.denom, &copied->lattice.denom);
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibz_copy(©->lattice.basis.m[i][j], &copied->lattice.basis.m[i][j]);
+ }
+ }
+}
+
+void
+quat_lideal_create_principal(quat_left_ideal_t *lideal,
+ const quat_alg_elem_t *x,
+ const quat_lattice_t *order,
+ const quat_alg_t *alg)
+{
+ assert(quat_order_is_maximal(order, alg));
+ assert(quat_lattice_contains(NULL, order, x));
+ ibz_t norm_n, norm_d;
+ ibz_init(&norm_n);
+ ibz_init(&norm_d);
+
+ // Multiply order on the right by x
+ quat_lattice_alg_elem_mul(&(lideal->lattice), order, x, alg);
+
+ // Reduce denominator. This conserves HNF
+ quat_lattice_reduce_denom(&lideal->lattice, &lideal->lattice);
+
+ // Compute norm and check it's integral
+ quat_alg_norm(&norm_n, &norm_d, x, alg);
+ assert(ibz_is_one(&norm_d));
+ ibz_copy(&lideal->norm, &norm_n);
+
+ // Set order
+ lideal->parent_order = order;
+ ibz_finalize(&norm_n);
+ ibz_finalize(&norm_d);
+}
+
+void
+quat_lideal_create(quat_left_ideal_t *lideal,
+ const quat_alg_elem_t *x,
+ const ibz_t *N,
+ const quat_lattice_t *order,
+ const quat_alg_t *alg)
+{
+ assert(quat_order_is_maximal(order, alg));
+ assert(!quat_alg_elem_is_zero(x));
+
+ quat_lattice_t ON;
+ quat_lattice_init(&ON);
+
+ // Compute ideal generated by x
+ quat_lideal_create_principal(lideal, x, order, alg);
+
+ // Compute 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);
+ // Set order
+ lideal->parent_order = order;
+ // Compute norm
+ quat_lideal_norm(lideal);
+
+ quat_lattice_finalize(&ON);
+}
+
+int
+quat_lideal_generator(quat_alg_elem_t *gen, const quat_left_ideal_t *lideal, const quat_alg_t *alg)
+{
+ ibz_t norm_int, norm_n, gcd, r, q, norm_denom;
+ ibz_vec_4_t vec;
+ ibz_vec_4_init(&vec);
+ ibz_init(&norm_denom);
+ ibz_init(&norm_int);
+ ibz_init(&norm_n);
+ ibz_init(&r);
+ ibz_init(&q);
+ ibz_init(&gcd);
+ int a, b, c, d;
+ int found = 0;
+ int int_norm = 0;
+ while (1) {
+ int_norm++;
+ for (a = -int_norm; a <= int_norm; a++) {
+ for (b = -int_norm + abs(a); b <= int_norm - abs(a); b++) {
+ for (c = -int_norm + abs(a) + abs(b); c <= int_norm - abs(a) - abs(b); c++) {
+ d = int_norm - abs(a) - abs(b) - abs(c);
+ ibz_vec_4_set(&vec, a, b, c, d);
+ ibz_vec_4_content(&gcd, &vec);
+ if (ibz_is_one(&gcd)) {
+ ibz_mat_4x4_eval(&(gen->coord), &(lideal->lattice.basis), &vec);
+ ibz_copy(&(gen->denom), &(lideal->lattice.denom));
+ quat_alg_norm(&norm_int, &norm_denom, gen, alg);
+ assert(ibz_is_one(&norm_denom));
+ ibz_div(&q, &r, &norm_int, &(lideal->norm));
+ assert(ibz_is_zero(&r));
+ ibz_gcd(&gcd, &(lideal->norm), &q);
+ found = (0 == ibz_cmp(&gcd, &ibz_const_one));
+ if (found)
+ goto fin;
+ }
+ }
+ }
+ }
+ }
+fin:;
+ ibz_finalize(&r);
+ ibz_finalize(&q);
+ ibz_finalize(&norm_denom);
+ ibz_finalize(&norm_int);
+ ibz_finalize(&norm_n);
+ ibz_vec_4_finalize(&vec);
+ ibz_finalize(&gcd);
+ return (found);
+}
+
+void
+quat_lideal_mul(quat_left_ideal_t *product,
+ const quat_left_ideal_t *lideal,
+ const quat_alg_elem_t *alpha,
+ const quat_alg_t *alg)
+{
+ assert(quat_order_is_maximal((lideal->parent_order), alg));
+ ibz_t norm, norm_d;
+ ibz_init(&norm);
+ ibz_init(&norm_d);
+ quat_lattice_alg_elem_mul(&(product->lattice), &(lideal->lattice), alpha, alg);
+ product->parent_order = lideal->parent_order;
+ quat_alg_norm(&norm, &norm_d, alpha, alg);
+ ibz_mul(&(product->norm), &(lideal->norm), &norm);
+ assert(ibz_divides(&(product->norm), &norm_d));
+ ibz_div(&(product->norm), &norm, &(product->norm), &norm_d);
+ assert(quat_lideal_norm_verify(lideal));
+ ibz_finalize(&norm_d);
+ ibz_finalize(&norm);
+}
+
+void
+quat_lideal_add(quat_left_ideal_t *sum, const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg)
+{
+ assert(I1->parent_order == I2->parent_order);
+ assert(quat_order_is_maximal((I2->parent_order), alg));
+ quat_lattice_add(&sum->lattice, &I1->lattice, &I2->lattice);
+ sum->parent_order = I1->parent_order;
+ quat_lideal_norm(sum);
+}
+
+void
+quat_lideal_inter(quat_left_ideal_t *inter,
+ const quat_left_ideal_t *I1,
+ const quat_left_ideal_t *I2,
+ const quat_alg_t *alg)
+{
+ assert(I1->parent_order == I2->parent_order);
+ assert(quat_order_is_maximal((I2->parent_order), alg));
+ quat_lattice_intersect(&inter->lattice, &I1->lattice, &I2->lattice);
+ inter->parent_order = I1->parent_order;
+ quat_lideal_norm(inter);
+}
+
+int
+quat_lideal_equals(const quat_left_ideal_t *I1, const quat_left_ideal_t *I2, const quat_alg_t *alg)
+{
+ assert(quat_order_is_maximal((I2->parent_order), alg));
+ assert(quat_order_is_maximal((I1->parent_order), alg));
+ return (I1->parent_order == I2->parent_order) & (ibz_cmp(&I1->norm, &I2->norm) == 0) &
+ quat_lattice_equal(&I1->lattice, &I2->lattice);
+}
+
+void
+quat_lideal_inverse_lattice_without_hnf(quat_lattice_t *inv, const quat_left_ideal_t *lideal, const quat_alg_t *alg)
+{
+ assert(quat_order_is_maximal((lideal->parent_order), alg));
+ quat_lattice_conjugate_without_hnf(inv, &(lideal->lattice));
+ ibz_mul(&(inv->denom), &(inv->denom), &(lideal->norm));
+}
+
+// following the implementation of ideal isomorphisms in the code of LearningToSQI's sage
+// implementation of SQIsign
+void
+quat_lideal_right_transporter(quat_lattice_t *trans,
+ const quat_left_ideal_t *lideal1,
+ const quat_left_ideal_t *lideal2,
+ const quat_alg_t *alg)
+{
+ assert(quat_order_is_maximal((lideal1->parent_order), alg));
+ assert(quat_order_is_maximal((lideal2->parent_order), alg));
+ assert(lideal1->parent_order == lideal2->parent_order);
+ quat_lattice_t inv;
+ quat_lattice_init(&inv);
+ quat_lideal_inverse_lattice_without_hnf(&inv, lideal1, alg);
+ quat_lattice_mul(trans, &inv, &(lideal2->lattice), alg);
+ quat_lattice_finalize(&inv);
+}
+
+void
+quat_lideal_right_order(quat_lattice_t *order, const quat_left_ideal_t *lideal, const quat_alg_t *alg)
+{
+ assert(quat_order_is_maximal((lideal->parent_order), alg));
+ quat_lideal_right_transporter(order, lideal, lideal, alg);
+}
+
+void
+quat_lideal_class_gram(ibz_mat_4x4_t *G, const quat_left_ideal_t *lideal, const quat_alg_t *alg)
+{
+ quat_lattice_gram(G, &(lideal->lattice), alg);
+
+ // divide by norm · denominator²
+ ibz_t divisor, rmd;
+ ibz_init(&divisor);
+ ibz_init(&rmd);
+
+ ibz_mul(&divisor, &(lideal->lattice.denom), &(lideal->lattice.denom));
+ ibz_mul(&divisor, &divisor, &(lideal->norm));
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j <= i; j++) {
+ ibz_div(&G->m[i][j], &rmd, &G->m[i][j], &divisor);
+ assert(ibz_is_zero(&rmd));
+ }
+ }
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j <= i - 1; j++) {
+ ibz_copy(&G->m[j][i], &G->m[i][j]);
+ }
+ }
+
+ ibz_finalize(&rmd);
+ ibz_finalize(&divisor);
+}
+
+void
+quat_lideal_conjugate_without_hnf(quat_left_ideal_t *conj,
+ quat_lattice_t *new_parent_order,
+ const quat_left_ideal_t *lideal,
+ const quat_alg_t *alg)
+{
+ quat_lideal_right_order(new_parent_order, lideal, alg);
+ quat_lattice_conjugate_without_hnf(&(conj->lattice), &(lideal->lattice));
+ conj->parent_order = new_parent_order;
+ ibz_copy(&(conj->norm), &(lideal->norm));
+}
+
+int
+quat_order_discriminant(ibz_t *disc, const quat_lattice_t *order, const quat_alg_t *alg)
+{
+ int ok = 0;
+ ibz_t det, sqr, div;
+ ibz_mat_4x4_t transposed, norm, prod;
+ ibz_init(&det);
+ ibz_init(&sqr);
+ ibz_init(&div);
+ ibz_mat_4x4_init(&transposed);
+ ibz_mat_4x4_init(&norm);
+ ibz_mat_4x4_init(&prod);
+ ibz_mat_4x4_transpose(&transposed, &(order->basis));
+ // multiply gram matrix by 2 because of reduced trace
+ ibz_mat_4x4_identity(&norm);
+ ibz_copy(&(norm.m[2][2]), &(alg->p));
+ ibz_copy(&(norm.m[3][3]), &(alg->p));
+ ibz_mat_4x4_scalar_mul(&norm, &ibz_const_two, &norm);
+ ibz_mat_4x4_mul(&prod, &transposed, &norm);
+ ibz_mat_4x4_mul(&prod, &prod, &(order->basis));
+ ibz_mat_4x4_inv_with_det_as_denom(NULL, &det, &prod);
+ ibz_mul(&div, &(order->denom), &(order->denom));
+ ibz_mul(&div, &div, &div);
+ ibz_mul(&div, &div, &div);
+ ibz_div(&sqr, &div, &det, &div);
+ ok = ibz_is_zero(&div);
+ ok = ok & ibz_sqrt(disc, &sqr);
+ ibz_finalize(&det);
+ ibz_finalize(&div);
+ ibz_finalize(&sqr);
+ ibz_mat_4x4_finalize(&transposed);
+ ibz_mat_4x4_finalize(&norm);
+ ibz_mat_4x4_finalize(&prod);
+ return (ok);
+}
+
+int
+quat_order_is_maximal(const quat_lattice_t *order, const quat_alg_t *alg)
+{
+ int res;
+ ibz_t disc;
+ ibz_init(&disc);
+ quat_order_discriminant(&disc, order, alg);
+ res = (ibz_cmp(&disc, &(alg->p)) == 0);
+ ibz_finalize(&disc);
+ return (res);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/intbig.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/intbig.c
new file mode 100644
index 0000000000..e219bf3d96
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/intbig.c
@@ -0,0 +1,791 @@
+#include "intbig_internal.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+// #define DEBUG_VERBOSE
+
+#ifdef DEBUG_VERBOSE
+#define DEBUG_STR_PRINTF(x) printf("%s\n", (x));
+
+static void
+DEBUG_STR_FUN_INT_MP(const char *op, int arg1, const ibz_t *arg2)
+{
+ int arg2_size = ibz_size_in_base(arg2, 16);
+ char arg2_str[arg2_size + 2];
+ ibz_convert_to_str(arg2, arg2_str, 16);
+
+ printf("%s,%x,%s\n", op, arg1, arg2_str);
+}
+
+static void
+DEBUG_STR_FUN_3(const char *op, const ibz_t *arg1, const ibz_t *arg2, const ibz_t *arg3)
+{
+ int arg1_size = ibz_size_in_base(arg1, 16);
+ char arg1_str[arg1_size + 2];
+ ibz_convert_to_str(arg1, arg1_str, 16);
+
+ int arg2_size = ibz_size_in_base(arg2, 16);
+ char arg2_str[arg2_size + 2];
+ ibz_convert_to_str(arg2, arg2_str, 16);
+
+ int arg3_size = ibz_size_in_base(arg3, 16);
+ char arg3_str[arg3_size + 2];
+ ibz_convert_to_str(arg3, arg3_str, 16);
+
+ printf("%s,%s,%s,%s\n", op, arg1_str, arg2_str, arg3_str);
+}
+
+static void
+DEBUG_STR_FUN_MP2_INT(const char *op, const ibz_t *arg1, const ibz_t *arg2, int arg3)
+{
+ int arg1_size = ibz_size_in_base(arg1, 16);
+ char arg1_str[arg1_size + 2];
+ ibz_convert_to_str(arg1, arg1_str, 16);
+
+ int arg2_size = ibz_size_in_base(arg2, 16);
+ char arg2_str[arg2_size + 2];
+ ibz_convert_to_str(arg2, arg2_str, 16);
+
+ printf("%s,%s,%s,%x\n", op, arg1_str, arg2_str, arg3);
+}
+
+static void
+DEBUG_STR_FUN_INT_MP2(const char *op, int arg1, const ibz_t *arg2, const ibz_t *arg3)
+{
+ int arg2_size = ibz_size_in_base(arg2, 16);
+ char arg2_str[arg2_size + 2];
+ ibz_convert_to_str(arg2, arg2_str, 16);
+
+ int arg3_size = ibz_size_in_base(arg3, 16);
+ char arg3_str[arg3_size + 2];
+ ibz_convert_to_str(arg3, arg3_str, 16);
+
+ if (arg1 >= 0)
+ printf("%s,%x,%s,%s\n", op, arg1, arg2_str, arg3_str);
+ else
+ printf("%s,-%x,%s,%s\n", op, -arg1, arg2_str, arg3_str);
+}
+
+static void
+DEBUG_STR_FUN_INT_MP_INT(const char *op, int arg1, const ibz_t *arg2, int arg3)
+{
+ int arg2_size = ibz_size_in_base(arg2, 16);
+ char arg2_str[arg2_size + 2];
+ ibz_convert_to_str(arg2, arg2_str, 16);
+
+ printf("%s,%x,%s,%x\n", op, arg1, arg2_str, arg3);
+}
+
+static void
+DEBUG_STR_FUN_4(const char *op, const ibz_t *arg1, const ibz_t *arg2, const ibz_t *arg3, const ibz_t *arg4)
+{
+ int arg1_size = ibz_size_in_base(arg1, 16);
+ char arg1_str[arg1_size + 2];
+ ibz_convert_to_str(arg1, arg1_str, 16);
+
+ int arg2_size = ibz_size_in_base(arg2, 16);
+ char arg2_str[arg2_size + 2];
+ ibz_convert_to_str(arg2, arg2_str, 16);
+
+ int arg3_size = ibz_size_in_base(arg3, 16);
+ char arg3_str[arg3_size + 2];
+ ibz_convert_to_str(arg3, arg3_str, 16);
+
+ int arg4_size = ibz_size_in_base(arg4, 16);
+ char arg4_str[arg4_size + 2];
+ ibz_convert_to_str(arg4, arg4_str, 16);
+
+ printf("%s,%s,%s,%s,%s\n", op, arg1_str, arg2_str, arg3_str, arg4_str);
+}
+#else
+#define DEBUG_STR_PRINTF(x)
+#define DEBUG_STR_FUN_INT_MP(op, arg1, arg2)
+#define DEBUG_STR_FUN_3(op, arg1, arg2, arg3)
+#define DEBUG_STR_FUN_INT_MP2(op, arg1, arg2, arg3)
+#define DEBUG_STR_FUN_INT_MP_INT(op, arg1, arg2, arg3)
+#define DEBUG_STR_FUN_4(op, arg1, arg2, arg3, arg4)
+#endif
+
+/** @defgroup ibz_t Constants
+ * @{
+ */
+
+const ibz_t ibz_const_zero = {{
+ {
+ ._mp_alloc = 0,
+ ._mp_size = 0,
+ ._mp_d = (mp_limb_t[]){ 0 },
+ }
+}};
+
+const ibz_t ibz_const_one = {{
+ {
+ ._mp_alloc = 0,
+ ._mp_size = 1,
+ ._mp_d = (mp_limb_t[]){ 1 },
+ }
+}};
+
+const ibz_t ibz_const_two = {{
+ {
+ ._mp_alloc = 0,
+ ._mp_size = 1,
+ ._mp_d = (mp_limb_t[]){ 2 },
+ }
+}};
+
+const ibz_t ibz_const_three = {{
+ {
+ ._mp_alloc = 0,
+ ._mp_size = 1,
+ ._mp_d = (mp_limb_t[]){ 3 },
+ }
+}};
+
+void
+ibz_init(ibz_t *x)
+{
+ mpz_init(x->i);
+}
+
+void
+ibz_finalize(ibz_t *x)
+{
+ mpz_clear(x->i);
+}
+
+void
+ibz_add(ibz_t *sum, const ibz_t *a, const ibz_t *b)
+{
+#ifdef DEBUG_VERBOSE
+ ibz_t a_cp, b_cp;
+ ibz_init(&a_cp);
+ ibz_init(&b_cp);
+ ibz_copy(&a_cp, a);
+ ibz_copy(&b_cp, b);
+#endif
+ mpz_add(sum->i, a->i, b->i);
+#ifdef DEBUG_VERBOSE
+ DEBUG_STR_FUN_3("ibz_add", sum, &a_cp, &b_cp);
+ ibz_finalize(&a_cp);
+ ibz_finalize(&b_cp);
+#endif
+}
+
+void
+ibz_sub(ibz_t *diff, const ibz_t *a, const ibz_t *b)
+{
+#ifdef DEBUG_VERBOSE
+ ibz_t a_cp, b_cp;
+ ibz_init(&a_cp);
+ ibz_init(&b_cp);
+ ibz_copy(&a_cp, a);
+ ibz_copy(&b_cp, b);
+#endif
+ mpz_sub(diff->i, a->i, b->i);
+
+#ifdef DEBUG_VERBOSE
+ DEBUG_STR_FUN_3("ibz_sub", diff, &a_cp, &b_cp);
+ ibz_finalize(&a_cp);
+ ibz_finalize(&b_cp);
+#endif
+}
+
+void
+ibz_mul(ibz_t *prod, const ibz_t *a, const ibz_t *b)
+{
+#ifdef DEBUG_VERBOSE
+ ibz_t a_cp, b_cp;
+ ibz_init(&a_cp);
+ ibz_init(&b_cp);
+ ibz_copy(&a_cp, a);
+ ibz_copy(&b_cp, b);
+#endif
+ mpz_mul(prod->i, a->i, b->i);
+#ifdef DEBUG_VERBOSE
+ DEBUG_STR_FUN_3("ibz_mul", prod, &a_cp, &b_cp);
+ ibz_finalize(&a_cp);
+ ibz_finalize(&b_cp);
+#endif
+}
+
+void
+ibz_neg(ibz_t *neg, const ibz_t *a)
+{
+ mpz_neg(neg->i, a->i);
+}
+
+void
+ibz_abs(ibz_t *abs, const ibz_t *a)
+{
+ mpz_abs(abs->i, a->i);
+}
+
+void
+ibz_div(ibz_t *quotient, ibz_t *remainder, const ibz_t *a, const ibz_t *b)
+{
+#ifdef DEBUG_VERBOSE
+ ibz_t a_cp, b_cp;
+ ibz_init(&a_cp);
+ ibz_init(&b_cp);
+ ibz_copy(&a_cp, a);
+ ibz_copy(&b_cp, b);
+#endif
+ mpz_tdiv_qr(quotient->i, remainder->i, a->i, b->i);
+#ifdef DEBUG_VERBOSE
+ DEBUG_STR_FUN_4("ibz_div", quotient, remainder, &a_cp, &b_cp);
+ ibz_finalize(&a_cp);
+ ibz_finalize(&b_cp);
+#endif
+}
+
+void
+ibz_div_2exp(ibz_t *quotient, const ibz_t *a, uint32_t exp)
+{
+#ifdef DEBUG_VERBOSE
+ ibz_t a_cp;
+ ibz_init(&a_cp);
+ ibz_copy(&a_cp, a);
+#endif
+ mpz_tdiv_q_2exp(quotient->i, a->i, exp);
+#ifdef DEBUG_VERBOSE
+ DEBUG_STR_FUN_MP2_INT("ibz_div_2exp,%Zx,%Zx,%x\n", quotient, &a_cp, exp);
+ ibz_finalize(&a_cp);
+#endif
+}
+
+void
+ibz_div_floor(ibz_t *q, ibz_t *r, const ibz_t *n, const ibz_t *d)
+{
+ mpz_fdiv_qr(q->i, r->i, n->i, d->i);
+}
+
+void
+ibz_mod(ibz_t *r, const ibz_t *a, const ibz_t *b)
+{
+ mpz_mod(r->i, a->i, b->i);
+}
+
+unsigned long int
+ibz_mod_ui(const ibz_t *n, unsigned long int d)
+{
+ return mpz_fdiv_ui(n->i, d);
+}
+
+int
+ibz_divides(const ibz_t *a, const ibz_t *b)
+{
+ return mpz_divisible_p(a->i, b->i);
+}
+
+void
+ibz_pow(ibz_t *pow, const ibz_t *x, uint32_t e)
+{
+ mpz_pow_ui(pow->i, x->i, e);
+}
+
+void
+ibz_pow_mod(ibz_t *pow, const ibz_t *x, const ibz_t *e, const ibz_t *m)
+{
+ mpz_powm(pow->i, x->i, e->i, m->i);
+ DEBUG_STR_FUN_4("ibz_pow_mod", pow, x, e, m);
+}
+
+int
+ibz_two_adic(ibz_t *pow)
+{
+ return mpz_scan1(pow->i, 0);
+}
+
+int
+ibz_cmp(const ibz_t *a, const ibz_t *b)
+{
+ int ret = mpz_cmp(a->i, b->i);
+ DEBUG_STR_FUN_INT_MP2("ibz_cmp", ret, a, b);
+ return ret;
+}
+
+int
+ibz_is_zero(const ibz_t *x)
+{
+ int ret = !mpz_cmp_ui(x->i, 0);
+ DEBUG_STR_FUN_INT_MP("ibz_is_zero", ret, x);
+ return ret;
+}
+
+int
+ibz_is_one(const ibz_t *x)
+{
+ int ret = !mpz_cmp_ui(x->i, 1);
+ DEBUG_STR_FUN_INT_MP("ibz_is_one", ret, x);
+ return ret;
+}
+
+int
+ibz_cmp_int32(const ibz_t *x, int32_t y)
+{
+ int ret = mpz_cmp_si(x->i, (signed long int)y);
+ DEBUG_STR_FUN_INT_MP_INT("ibz_cmp_int32", ret, x, y);
+ return ret;
+}
+
+int
+ibz_is_even(const ibz_t *x)
+{
+ int ret = !mpz_tstbit(x->i, 0);
+ DEBUG_STR_FUN_INT_MP("ibz_is_even", ret, x);
+ return ret;
+}
+
+int
+ibz_is_odd(const ibz_t *x)
+{
+ int ret = mpz_tstbit(x->i, 0);
+ DEBUG_STR_FUN_INT_MP("ibz_is_odd", ret, x);
+ return ret;
+}
+
+void
+ibz_set(ibz_t *i, int32_t x)
+{
+ mpz_set_si(i->i, x);
+}
+
+int
+ibz_convert_to_str(const ibz_t *i, char *str, int base)
+{
+ if (!str || (base != 10 && base != 16))
+ return 0;
+
+ mpz_get_str(str, base, i->i);
+
+ return 1;
+}
+
+void
+ibz_print(const ibz_t *num, int base)
+{
+ assert(base == 10 || base == 16);
+
+ int num_size = ibz_size_in_base(num, base);
+ char num_str[num_size + 2];
+ ibz_convert_to_str(num, num_str, base);
+ printf("%s", num_str);
+}
+
+int
+ibz_set_from_str(ibz_t *i, const char *str, int base)
+{
+ return (1 + mpz_set_str(i->i, str, base));
+}
+
+void
+ibz_copy(ibz_t *target, const ibz_t *value)
+{
+ mpz_set(target->i, value->i);
+}
+
+void
+ibz_swap(ibz_t *a, ibz_t *b)
+{
+ mpz_swap(a->i, b->i);
+}
+
+int32_t
+ibz_get(const ibz_t *i)
+{
+#if LONG_MAX == INT32_MAX
+ return (int32_t)mpz_get_si(i->i);
+#elif LONG_MAX > INT32_MAX
+ // Extracts the sign bit and the 31 least significant bits
+ signed long int t = mpz_get_si(i->i);
+ return (int32_t)((t >> (sizeof(signed long int) * 8 - 32)) & INT32_C(0x80000000)) | (t & INT32_C(0x7FFFFFFF));
+#else
+#error Unsupported configuration: LONG_MAX must be >= INT32_MAX
+#endif
+}
+
+int
+ibz_rand_interval(ibz_t *rand, const ibz_t *a, const ibz_t *b)
+{
+ int randret;
+ int ret = 1;
+ mpz_t tmp;
+ mpz_t bmina;
+ mpz_init(bmina);
+ mpz_sub(bmina, b->i, a->i);
+
+ if (mpz_sgn(bmina) == 0) {
+ mpz_set(rand->i, a->i);
+ mpz_clear(bmina);
+ return 1;
+ }
+
+ size_t len_bits = mpz_sizeinbase(bmina, 2);
+ size_t len_bytes = (len_bits + 7) / 8;
+ size_t sizeof_limb = sizeof(mp_limb_t);
+ size_t sizeof_limb_bits = sizeof_limb * 8;
+ size_t len_limbs = (len_bytes + sizeof_limb - 1) / sizeof_limb;
+
+ mp_limb_t mask = ((mp_limb_t)-1) >> (sizeof_limb_bits - len_bits) % sizeof_limb_bits;
+ mp_limb_t r[len_limbs];
+
+#ifndef NDEBUG
+ {
+ for (size_t i = 0; i < len_limbs; ++i)
+ r[i] = (mp_limb_t)-1;
+ r[len_limbs - 1] = mask;
+ mpz_t check;
+ mpz_roinit_n(check, r, len_limbs);
+ assert(mpz_cmp(check, bmina) >= 0); // max sampled value >= b - a
+ mpz_t bmina2;
+ mpz_init(bmina2);
+ mpz_add(bmina2, bmina, bmina);
+ assert(mpz_cmp(check, bmina2) < 0); // max sampled value < 2 * (b - a)
+ mpz_clear(bmina2);
+ }
+#endif
+
+ do {
+ randret = randombytes((unsigned char *)r, len_bytes);
+ if (randret != 0) {
+ ret = 0;
+ goto err;
+ }
+#ifdef TARGET_BIG_ENDIAN
+ for (size_t i = 0; i < len_limbs; ++i)
+ r[i] = BSWAP_DIGIT(r[i]);
+#endif
+ r[len_limbs - 1] &= mask;
+ mpz_roinit_n(tmp, r, len_limbs);
+ if (mpz_cmp(tmp, bmina) <= 0)
+ break;
+ } while (1);
+
+ mpz_add(rand->i, tmp, a->i);
+err:
+ mpz_clear(bmina);
+ return ret;
+}
+
+int
+ibz_rand_interval_i(ibz_t *rand, int32_t a, int32_t b)
+{
+ uint32_t diff, mask;
+ int32_t rand32;
+
+ if (!(a >= 0 && b >= 0 && b > a)) {
+ printf("a = %d b = %d\n", a, b);
+ }
+ assert(a >= 0 && b >= 0 && b > a);
+
+ diff = b - a;
+
+ // Create a mask with 1 + ceil(log2(diff)) least significant bits set
+#if (defined(__GNUC__) || defined(__clang__)) && INT_MAX == INT32_MAX
+ mask = (1 << (32 - __builtin_clz((uint32_t)diff))) - 1;
+#else
+ uint32_t diff2 = diff, tmp;
+
+ mask = (diff2 > 0xFFFF) << 4;
+ diff2 >>= mask;
+
+ tmp = (diff2 > 0xFF) << 3;
+ diff2 >>= tmp;
+ mask |= tmp;
+
+ tmp = (diff2 > 0xF) << 2;
+ diff2 >>= tmp;
+ mask |= tmp;
+
+ tmp = (diff2 > 0x3) << 1;
+ diff2 >>= tmp;
+ mask |= tmp;
+
+ mask |= diff2 >> 1;
+
+ mask = (1 << (mask + 1)) - 1;
+#endif
+
+ assert(mask >= diff && mask < 2 * diff);
+
+ // Rejection sampling
+ do {
+ randombytes((unsigned char *)&rand32, sizeof(rand32));
+
+#ifdef TARGET_BIG_ENDIAN
+ rand32 = BSWAP32(rand32);
+#endif
+
+ rand32 &= mask;
+ } while (rand32 > (int32_t)diff);
+
+ rand32 += a;
+ ibz_set(rand, rand32);
+
+ return 1;
+}
+
+int
+ibz_rand_interval_minm_m(ibz_t *rand, int32_t m)
+{
+ int ret = 1;
+ ibz_t m_big;
+
+ // m_big = 2 * m
+ mpz_init_set_si(m_big.i, m);
+ mpz_add(m_big.i, m_big.i, m_big.i);
+
+ // Sample in [0, 2*m]
+ ret = ibz_rand_interval(rand, &ibz_const_zero, &m_big);
+
+ // Adjust to range [-m, m]
+ mpz_sub_ui(rand->i, rand->i, m);
+
+ mpz_clear(m_big.i);
+
+ return ret;
+}
+
+int
+ibz_rand_interval_bits(ibz_t *rand, uint32_t m)
+{
+ int ret = 1;
+ ibz_t tmp;
+ ibz_t low;
+ mpz_init_set_ui(tmp.i, 1);
+ mpz_mul_2exp(tmp.i, tmp.i, m);
+ mpz_init(low.i);
+ mpz_neg(low.i, tmp.i);
+ ret = ibz_rand_interval(rand, &low, &tmp);
+ mpz_clear(tmp.i);
+ mpz_clear(low.i);
+ if (ret != 1)
+ goto err;
+ mpz_sub_ui(rand->i, rand->i, (unsigned long int)m);
+ return ret;
+err:
+ mpz_clear(tmp.i);
+ mpz_clear(low.i);
+ return ret;
+}
+
+int
+ibz_bitsize(const ibz_t *a)
+{
+ return (int)mpz_sizeinbase(a->i, 2);
+}
+
+int
+ibz_size_in_base(const ibz_t *a, int base)
+{
+ return (int)mpz_sizeinbase(a->i, base);
+}
+
+void
+ibz_copy_digits(ibz_t *target, const digit_t *dig, int dig_len)
+{
+ mpz_import(target->i, dig_len, -1, sizeof(digit_t), 0, 0, dig);
+}
+
+void
+ibz_to_digits(digit_t *target, const ibz_t *ibz)
+{
+ // From the GMP documentation:
+ // "If op is zero then the count returned will be zero and nothing written to rop."
+ // The next line ensures zero is written to the first limb of target if ibz is zero;
+ // target is then overwritten by the actual value if it is not.
+ target[0] = 0;
+ mpz_export(target, NULL, -1, sizeof(digit_t), 0, 0, ibz->i);
+}
+
+int
+ibz_probab_prime(const ibz_t *n, int reps)
+{
+ int ret = mpz_probab_prime_p(n->i, reps);
+ DEBUG_STR_FUN_INT_MP_INT("ibz_probab_prime", ret, n, reps);
+ return ret;
+}
+
+void
+ibz_gcd(ibz_t *gcd, const ibz_t *a, const ibz_t *b)
+{
+ mpz_gcd(gcd->i, a->i, b->i);
+}
+
+int
+ibz_invmod(ibz_t *inv, const ibz_t *a, const ibz_t *mod)
+{
+ return (mpz_invert(inv->i, a->i, mod->i) ? 1 : 0);
+}
+
+int
+ibz_legendre(const ibz_t *a, const ibz_t *p)
+{
+ return mpz_legendre(a->i, p->i);
+}
+
+int
+ibz_sqrt(ibz_t *sqrt, const ibz_t *a)
+{
+ if (mpz_perfect_square_p(a->i)) {
+ mpz_sqrt(sqrt->i, a->i);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void
+ibz_sqrt_floor(ibz_t *sqrt, const ibz_t *a)
+{
+ mpz_sqrt(sqrt->i, a->i);
+}
+
+int
+ibz_sqrt_mod_p(ibz_t *sqrt, const ibz_t *a, const ibz_t *p)
+{
+#ifndef NDEBUG
+ assert(ibz_probab_prime(p, 100));
+#endif
+ // Case a = 0
+ {
+ ibz_t test;
+ ibz_init(&test);
+ ibz_mod(&test, a, p);
+ if (ibz_is_zero(&test)) {
+ ibz_set(sqrt, 0);
+ }
+ ibz_finalize(&test);
+ }
+#ifdef DEBUG_VERBOSE
+ ibz_t a_cp, p_cp;
+ ibz_init(&a_cp);
+ ibz_init(&p_cp);
+ ibz_copy(&a_cp, a);
+ ibz_copy(&p_cp, p);
+#endif
+
+ mpz_t amod, tmp, exp, a4, a2, q, z, qnr, x, y, b, pm1;
+ mpz_init(amod);
+ mpz_init(tmp);
+ mpz_init(exp);
+ mpz_init(a4);
+ mpz_init(a2);
+ mpz_init(q);
+ mpz_init(z);
+ mpz_init(qnr);
+ mpz_init(x);
+ mpz_init(y);
+ mpz_init(b);
+ mpz_init(pm1);
+
+ int ret = 1;
+
+ mpz_mod(amod, a->i, p->i);
+ if (mpz_cmp_ui(amod, 0) < 0) {
+ mpz_add(amod, p->i, amod);
+ }
+
+ if (mpz_legendre(amod, p->i) != 1) {
+ ret = 0;
+ goto end;
+ }
+
+ mpz_sub_ui(pm1, p->i, 1);
+
+ if (mpz_mod_ui(tmp, p->i, 4) == 3) {
+ // p % 4 == 3
+ mpz_add_ui(tmp, p->i, 1);
+ mpz_fdiv_q_2exp(tmp, tmp, 2);
+ mpz_powm(sqrt->i, amod, tmp, p->i);
+ } else if (mpz_mod_ui(tmp, p->i, 8) == 5) {
+ // p % 8 == 5
+ mpz_sub_ui(tmp, p->i, 1);
+ mpz_fdiv_q_2exp(tmp, tmp, 2);
+ mpz_powm(tmp, amod, tmp, p->i); // a^{(p-1)/4} mod p
+ if (!mpz_cmp_ui(tmp, 1)) {
+ mpz_add_ui(tmp, p->i, 3);
+ mpz_fdiv_q_2exp(tmp, tmp, 3);
+ mpz_powm(sqrt->i, amod, tmp, p->i); // a^{(p+3)/8} mod p
+ } else {
+ mpz_sub_ui(tmp, p->i, 5);
+ mpz_fdiv_q_2exp(tmp, tmp, 3); // (p - 5) / 8
+ mpz_mul_2exp(a4, amod, 2); // 4*a
+ mpz_powm(tmp, a4, tmp, p->i);
+
+ mpz_mul_2exp(a2, amod, 1);
+ mpz_mul(tmp, a2, tmp);
+ mpz_mod(sqrt->i, tmp, p->i);
+ }
+ } else {
+ // p % 8 == 1 -> Shanks-Tonelli
+ int e = 0;
+ mpz_sub_ui(q, p->i, 1);
+ while (mpz_tstbit(q, e) == 0)
+ e++;
+ mpz_fdiv_q_2exp(q, q, e);
+
+ // 1. find generator - non-quadratic residue
+ mpz_set_ui(qnr, 2);
+ while (mpz_legendre(qnr, p->i) != -1)
+ mpz_add_ui(qnr, qnr, 1);
+ mpz_powm(z, qnr, q, p->i);
+
+ // 2. Initialize
+ mpz_set(y, z);
+ mpz_powm(y, amod, q, p->i); // y = a^q mod p
+
+ mpz_add_ui(tmp, q, 1); // tmp = (q + 1) / 2
+ mpz_fdiv_q_2exp(tmp, tmp, 1);
+
+ mpz_powm(x, amod, tmp, p->i); // x = a^(q + 1)/2 mod p
+
+ mpz_set_ui(exp, 1);
+ mpz_mul_2exp(exp, exp, e - 2);
+
+ for (int i = 0; i < e; ++i) {
+ mpz_powm(b, y, exp, p->i);
+
+ if (!mpz_cmp(b, pm1)) {
+ mpz_mul(x, x, z);
+ mpz_mod(x, x, p->i);
+
+ mpz_mul(y, y, z);
+ mpz_mul(y, y, z);
+ mpz_mod(y, y, p->i);
+ }
+
+ mpz_powm_ui(z, z, 2, p->i);
+ mpz_fdiv_q_2exp(exp, exp, 1);
+ }
+
+ mpz_set(sqrt->i, x);
+ }
+
+#ifdef DEBUG_VERBOSE
+ DEBUG_STR_FUN_3("ibz_sqrt_mod_p", sqrt, &a_cp, &p_cp);
+ ibz_finalize(&a_cp);
+ ibz_finalize(&p_cp);
+#endif
+
+end:
+ mpz_clear(amod);
+ mpz_clear(tmp);
+ mpz_clear(exp);
+ mpz_clear(a4);
+ mpz_clear(a2);
+ mpz_clear(q);
+ mpz_clear(z);
+ mpz_clear(qnr);
+ mpz_clear(x);
+ mpz_clear(y);
+ mpz_clear(b);
+ mpz_clear(pm1);
+
+ return ret;
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/intbig.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/intbig.h
new file mode 100644
index 0000000000..28e478ff7f
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/intbig.h
@@ -0,0 +1,305 @@
+/** @file
+ *
+ * @authors Luca De Feo, Sina Schaeffler
+ *
+ * @brief Declarations for big integers in the reference implementation
+ */
+
+#ifndef INTBIG_H
+#define INTBIG_H
+
+#include
+#if defined(MINI_GMP)
+#include
+#include
+#else
+#include
+#endif
+#include
+#include
+
+/** @ingroup quat_quat
+ * @defgroup ibz_all Signed big integers (gmp-based)
+ * @{
+ */
+
+/** @defgroup ibz_t Precise number types
+ * @{
+ */
+
+/** @brief Type for signed long integers
+ *
+ * @typedef ibz_t
+ *
+ * For integers of arbitrary size, used by intbig module, using gmp
+ */
+typedef struct {
+ mpz_t i;
+} ibz_t;
+
+/** @}
+ */
+
+/** @defgroup ibz_c Constants
+ * @{
+ */
+
+/**
+ * Constant zero
+ */
+extern const ibz_t ibz_const_zero;
+
+/**
+ * Constant one
+ */
+extern const ibz_t ibz_const_one;
+
+/**
+ * Constant two
+ */
+extern const ibz_t ibz_const_two;
+
+/**
+ * Constant three
+ */
+extern const ibz_t ibz_const_three;
+
+/** @}
+ */
+
+/** @defgroup ibz_finit Constructors and Destructors
+ * @{
+ */
+
+void ibz_init(ibz_t *x);
+void ibz_finalize(ibz_t *x);
+
+/** @}
+ */
+
+/** @defgroup ibz_za Basic integer arithmetic
+ * @{
+ */
+
+/** @brief sum=a+b
+ */
+void ibz_add(ibz_t *sum, const ibz_t *a, const ibz_t *b);
+
+/** @brief diff=a-b
+ */
+void ibz_sub(ibz_t *diff, const ibz_t *a, const ibz_t *b);
+
+/** @brief prod=a*b
+ */
+void ibz_mul(ibz_t *prod, const ibz_t *a, const ibz_t *b);
+
+/** @brief neg=-a
+ */
+void ibz_neg(ibz_t *neg, const ibz_t *a);
+
+/** @brief abs=|a|
+ */
+void ibz_abs(ibz_t *abs, const ibz_t *a);
+
+/** @brief Euclidean division of a by b
+ *
+ * Computes quotient, remainder so that remainder+quotient*b = a where 0<=|remainder|<|b|
+ * The quotient is rounded towards zero.
+ */
+void ibz_div(ibz_t *quotient, ibz_t *remainder, const ibz_t *a, const ibz_t *b);
+
+/** @brief Euclidean division of a by 2^exp
+ *
+ * Computes a right shift of abs(a) by exp bits, then sets sign(quotient) to sign(a).
+ *
+ * Division and rounding is as in ibz_div.
+ */
+void ibz_div_2exp(ibz_t *quotient, const ibz_t *a, uint32_t exp);
+
+/** @brief Two adic valuation computation
+ *
+ * Computes the position of the first 1 in the binary representation of the integer given in input
+ *
+ * When this number is a power of two this gives the two adic valuation of the integer
+ */
+int ibz_two_adic(ibz_t *pow);
+
+/** @brief r = a mod b
+ *
+ * Assumes valid inputs
+ * The sign of the divisor is ignored, the result is always non-negative
+ */
+void ibz_mod(ibz_t *r, const ibz_t *a, const ibz_t *b);
+
+unsigned long int ibz_mod_ui(const ibz_t *n, unsigned long int d);
+
+/** @brief Test if a = 0 mod b
+ */
+int ibz_divides(const ibz_t *a, const ibz_t *b);
+
+/** @brief pow=x^e
+ *
+ * Assumes valid inputs, The case 0^0 yields 1.
+ */
+void ibz_pow(ibz_t *pow, const ibz_t *x, uint32_t e);
+
+/** @brief pow=(x^e) mod m
+ *
+ * Assumes valid inputs
+ */
+void ibz_pow_mod(ibz_t *pow, const ibz_t *x, const ibz_t *e, const ibz_t *m);
+
+/** @brief Compare a and b
+ *
+ * @returns a positive value if a > b, zero if a = b, and a negative value if a < b
+ */
+int ibz_cmp(const ibz_t *a, const ibz_t *b);
+
+/** @brief Test if x is 0
+ *
+ * @returns 1 if x=0, 0 otherwise
+ */
+int ibz_is_zero(const ibz_t *x);
+
+/** @brief Test if x is 1
+ *
+ * @returns 1 if x=1, 0 otherwise
+ */
+int ibz_is_one(const ibz_t *x);
+
+/** @brief Compare x to y
+ *
+ * @returns 0 if x=y, positive if x>y, negative if x= 0 and target must hold sufficient elements to hold ibz
+ *
+ * @param target Target digit_t array
+ * @param ibz ibz source ibz_t element
+ */
+void ibz_to_digits(digit_t *target, const ibz_t *ibz);
+#define ibz_to_digit_array(T, I) \
+ do { \
+ memset((T), 0, sizeof(T)); \
+ ibz_to_digits((T), (I)); \
+ } while (0)
+
+/** @brief get int32_t equal to the lowest bits of i
+ *
+ * Should not be used to get the value of i if its bitsize is close to 32 bit
+ * It can however be used on any i to get an int32_t of the same parity as i (and same value modulo
+ * 4)
+ *
+ * @param i Input integer
+ */
+int32_t ibz_get(const ibz_t *i);
+
+/** @brief generate random value in [a, b]
+ * assumed that a >= 0 and b >= 0 and a < b
+ * @returns 1 on success, 0 on failiure
+ */
+int ibz_rand_interval(ibz_t *rand, const ibz_t *a, const ibz_t *b);
+
+/** @brief generate random value in [-m, m]
+ * assumed that m > 0 and bitlength of m < 32 bit
+ * @returns 1 on success, 0 on failiure
+ */
+int ibz_rand_interval_minm_m(ibz_t *rand, int32_t m);
+
+/** @brief Bitsize of a.
+ *
+ * @returns Bitsize of a.
+ *
+ */
+int ibz_bitsize(const ibz_t *a);
+
+/** @brief Size of a in given base.
+ *
+ * @returns Size of a in given base.
+ *
+ */
+int ibz_size_in_base(const ibz_t *a, int base);
+
+/** @}
+ */
+
+/** @defgroup ibz_n Number theory functions
+ * @{
+ */
+
+/**
+ * @brief Greatest common divisor
+ *
+ * @param gcd Output: Set to the gcd of a and b
+ * @param a
+ * @param b
+ */
+void ibz_gcd(ibz_t *gcd, const ibz_t *a, const ibz_t *b);
+
+/**
+ * @brief Modular inverse
+ *
+ * @param inv Output: Set to the integer in [0,mod[ such that a*inv = 1 mod (mod) if it exists
+ * @param a
+ * @param mod
+ * @returns 1 if inverse exists and was computed, 0 otherwise
+ */
+int ibz_invmod(ibz_t *inv, const ibz_t *a, const ibz_t *mod);
+
+/**
+ * @brief Floor of Integer square root
+ *
+ * @param sqrt Output: Set to the floor of an integer square root
+ * @param a number of which a floor of an integer square root is searched
+ */
+void ibz_sqrt_floor(ibz_t *sqrt, const ibz_t *a);
+
+/** @}
+ */
+
+// end of ibz_all
+/** @}
+ */
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/intbig_internal.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/intbig_internal.h
new file mode 100644
index 0000000000..de4762a6d3
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/intbig_internal.h
@@ -0,0 +1,123 @@
+/** @file
+ *
+ * @authors Sina Schaeffler
+ *
+ * @brief Declarations for big integer functions only used in quaternion functions
+ */
+
+#ifndef INTBIG_INTERNAL_H
+#define INTBIG_INTERNAL_H
+
+#include "intbig.h"
+
+/** @internal
+ * @ingroup quat_helpers
+ * @defgroup ibz_helper Internal integer functions (gmp-based)
+ * @{
+ */
+
+/********************************************************************/
+
+/** @brief Euclidean division of a by b
+ *
+ * Computes quotient, remainder so that remainder+quotient*b = a where 0<=|remainder|<|b|
+ * The quotient is rounded towards minus infinity.
+ */
+void ibz_div_floor(ibz_t *q, ibz_t *r, const ibz_t *n, const ibz_t *d);
+
+/** @brief generate random value in [a, b]
+ * assumed that a >= 0, b >= 0 and a < b
+ * @returns 1 on success, 0 on failiure
+ */
+int ibz_rand_interval_i(ibz_t *rand, int32_t a, int32_t b);
+
+/** @brief generate random value in [-2^m, 2^m]
+ * assumed that m > 0 and bitlength of m < 32 bit
+ * @returns 1 on success, 0 on failiure
+ */
+int ibz_rand_interval_bits(ibz_t *rand, uint32_t m);
+
+/** @brief set str to a string containing the representation of i in base
+ *
+ * Base should be 10 or 16
+ *
+ * str should be an array of length enough to store the representation of in
+ * in base, which can be obtained by ibz_sizeinbase(i, base) + 2, where the 2
+ * is for the sign and the null terminator
+ *
+ * Case for base 16 does not matter
+ *
+ * @returns 1 if the integer could be converted to a string, 0 otherwise
+ */
+int ibz_convert_to_str(const ibz_t *i, char *str, int base);
+
+/** @brief print num in base to stdout
+ *
+ * Base should be 10 or 16
+ */
+void ibz_print(const ibz_t *num, int base);
+
+/** @brief set i to integer contained in string when read as number in base
+ *
+ * Base should be 10 or 16, and the number should be written without ponctuation or whitespaces
+ *
+ * Case for base 16 does not matter
+ *
+ * @returns 1 if the string could be converted to an integer, 0 otherwise
+ */
+int ibz_set_from_str(ibz_t *i, const char *str, int base);
+
+/**
+ * @brief Probabilistic primality test
+ *
+ * @param n The number to test
+ * @param reps Number of Miller-Rabin repetitions. The more, the slower and the less likely are
+ * false positives
+ * @return 1 if probably prime, 0 if certainly not prime, 2 if certainly prime
+ *
+ * Using GMP's implementation:
+ *
+ * From GMP's documentation: "This function performs some trial divisions, a Baillie-PSW probable
+ * prime test, then reps-24 Miller-Rabin probabilistic primality tests."
+ */
+int ibz_probab_prime(const ibz_t *n, int reps);
+
+/**
+ * @brief Square root modulo a prime
+ *
+ * @returns 1 if square root of a mod p exists and was computed, 0 otherwise
+ * @param sqrt Output: Set to a square root of a mod p if any exist
+ * @param a number of which a square root mod p is searched
+ * @param p assumed prime
+ */
+int ibz_sqrt_mod_p(ibz_t *sqrt, const ibz_t *a, const ibz_t *p);
+
+/**
+ * @brief Integer square root of a perfect square
+ *
+ * @returns 1 if an integer square root of a exists and was computed, 0 otherwise
+ * @param sqrt Output: Set to a integer square root of a if any exist
+ * @param a number of which an integer square root is searched
+ */
+int ibz_sqrt(ibz_t *sqrt, const ibz_t *a);
+
+/**
+ * @brief Legendre symbol of a mod p
+ *
+ * @returns Legendre symbol of a mod p
+ * @param a
+ * @param p assumed prime
+ *
+ * Uses GMP's implementation
+ *
+ * If output is 1, a is a square mod p, if -1, not. If 0, it is divisible by p
+ */
+int ibz_legendre(const ibz_t *a, const ibz_t *p);
+
+/** @}
+ */
+
+// end of ibz_all
+/** @}
+ */
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/integers.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/integers.c
new file mode 100644
index 0000000000..ec7cda05eb
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/integers.c
@@ -0,0 +1,116 @@
+#include
+#include "internal.h"
+#include
+#include
+#include
+
+// Random prime generation for tests
+int
+ibz_generate_random_prime(ibz_t *p, int is3mod4, int bitsize, int probability_test_iterations)
+{
+ assert(bitsize != 0);
+ int found = 0;
+ ibz_t two_pow, two_powp;
+
+ ibz_init(&two_pow);
+ ibz_init(&two_powp);
+ ibz_pow(&two_pow, &ibz_const_two, (bitsize - 1) - (0 != is3mod4));
+ ibz_pow(&two_powp, &ibz_const_two, bitsize - (0 != is3mod4));
+
+ int cnt = 0;
+ while (!found) {
+ cnt++;
+ if (cnt % 100000 == 0) {
+ printf("Random prime generation is still running after %d attempts, this is not "
+ "normal! The expected number of attempts is %d \n",
+ cnt,
+ bitsize);
+ }
+ ibz_rand_interval(p, &two_pow, &two_powp);
+ ibz_add(p, p, p);
+ if (is3mod4) {
+ ibz_add(p, p, p);
+ ibz_add(p, &ibz_const_two, p);
+ }
+ ibz_add(p, &ibz_const_one, p);
+
+ found = ibz_probab_prime(p, probability_test_iterations);
+ }
+ ibz_finalize(&two_pow);
+ ibz_finalize(&two_powp);
+ return found;
+}
+
+// solves x^2 + n y^2 == p for positive integers x, y
+// assumes that p is prime and -n mod p is a square
+int
+ibz_cornacchia_prime(ibz_t *x, ibz_t *y, const ibz_t *n, const ibz_t *p)
+{
+ ibz_t r0, r1, r2, a, prod;
+ ibz_init(&r0);
+ ibz_init(&r1);
+ ibz_init(&r2);
+ ibz_init(&a);
+ ibz_init(&prod);
+
+ int res = 0;
+
+ // manage case p = 2 separately
+ if (!ibz_cmp(p, &ibz_const_two)) {
+ if (ibz_is_one(n)) {
+ ibz_set(x, 1);
+ ibz_set(y, 1);
+ res = 1;
+ }
+ goto done;
+ }
+ // manage case p = n separately
+ if (!ibz_cmp(p, n)) {
+ ibz_set(x, 0);
+ ibz_set(y, 1);
+ res = 1;
+ goto done;
+ }
+
+ // test coprimality (should always be ok in our cases)
+ ibz_gcd(&r2, p, n);
+ if (!ibz_is_one(&r2))
+ goto done;
+
+ // get sqrt of -n mod p
+ ibz_neg(&r2, n);
+ if (!ibz_sqrt_mod_p(&r2, &r2, p))
+ goto done;
+
+ // run loop
+ ibz_copy(&prod, p);
+ ibz_copy(&r1, p);
+ ibz_copy(&r0, p);
+ while (ibz_cmp(&prod, p) >= 0) {
+ ibz_div(&a, &r0, &r2, &r1);
+ ibz_mul(&prod, &r0, &r0);
+ ibz_copy(&r2, &r1);
+ ibz_copy(&r1, &r0);
+ }
+ // test if result is solution
+ ibz_sub(&a, p, &prod);
+ ibz_div(&a, &r2, &a, n);
+ if (!ibz_is_zero(&r2))
+ goto done;
+ if (!ibz_sqrt(y, &a))
+ goto done;
+
+ ibz_copy(x, &r0);
+ ibz_mul(&a, y, y);
+ ibz_mul(&a, &a, n);
+ ibz_add(&prod, &prod, &a);
+ res = !ibz_cmp(&prod, p);
+
+done:
+ ibz_finalize(&r0);
+ ibz_finalize(&r1);
+ ibz_finalize(&r2);
+ ibz_finalize(&a);
+ ibz_finalize(&prod);
+ return res;
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/internal.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/internal.h
new file mode 100644
index 0000000000..edbba345f9
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/internal.h
@@ -0,0 +1,812 @@
+/** @file
+ *
+ * @authors Sina Schaeffler
+ *
+ * @brief Declarations for helper functions for quaternion algebra implementation
+ */
+
+#ifndef QUAT_HELPER_H
+#define QUAT_HELPER_H
+
+#include
+#include
+#include "intbig_internal.h"
+
+/** @internal
+ * @ingroup quat_quat
+ * @defgroup quat_helpers Quaternion module internal functions
+ * @{
+ */
+
+/** @internal
+ * @defgroup quat_alg_helpers Helper functions for the alg library
+ * @{
+ */
+
+/** @internal
+ * @brief helper function for initializing small quaternion algebras.
+ */
+void quat_alg_init_set_ui(quat_alg_t *alg,
+ unsigned int p); // test/lattice, test/ideal, test/algebra
+
+/** @brief a*b
+ *
+ * Multiply two coordinate vectors as elements of the algebra in basis (1,i,j,ij) with i^2 = -1, j^2
+ * = -p
+ *
+ * @param res Output: Will contain product
+ * @param a
+ * @param b
+ * @param alg The quaternion algebra
+ */
+void quat_alg_coord_mul(ibz_vec_4_t *res, const ibz_vec_4_t *a, const ibz_vec_4_t *b, const quat_alg_t *alg);
+
+/** @brief a=b
+ *
+ * Test if a and b represent the same quaternion algebra element
+ *
+ * @param a
+ * @param b
+ * @returns 1 if a=b, 0 otherwise
+ */
+int quat_alg_elem_equal(const quat_alg_elem_t *a, const quat_alg_elem_t *b);
+
+/** @brief Test if x is 0
+ *
+ * @returns 1 if x=0, 0 otherwise
+ *
+ * x is 0 iff all coordinates in x->coord are 0
+ */
+int quat_alg_elem_is_zero(const quat_alg_elem_t *x);
+
+/** @brief Compute same denominator form of two quaternion algebra elements
+ *
+ * res_a=a and res_b=b (representing the same element) and res_a.denom = res_b.denom
+ *
+ * @param res_a
+ * @param res_b
+ * @param a
+ * @param b
+ */
+void quat_alg_equal_denom(quat_alg_elem_t *res_a,
+ quat_alg_elem_t *res_b,
+ const quat_alg_elem_t *a,
+ const quat_alg_elem_t *b);
+
+/** @brief Copies the given values into an algebra element, without normalizing it
+ *
+ * @param elem Output: algebra element of coordinates [coord0,coord1,coord2,coord3] and denominator
+ * denom
+ * @param denom Denominator, must be non zero
+ * @param coord0 Coordinate on 1 (0th vector of standard algebra basis)
+ * @param coord1 Coordinate on i (1st vector of standard algebra basis)
+ * @param coord2 Coordinate on j (2nd vector of standard algebra basis)
+ * @param coord3 Coordinate on ij (3rd vector of standard algebra basis)
+ */
+void quat_alg_elem_copy_ibz(quat_alg_elem_t *elem,
+ const ibz_t *denom,
+ const ibz_t *coord0,
+ const ibz_t *coord1,
+ const ibz_t *coord2,
+ const ibz_t *coord3);
+
+/** @brief Sets an algebra element to the given integer values, without normalizing it
+ *
+ * @param elem Output: algebra element of coordinates [coord0,coord1,coord2,coord3] and denominator
+ * denom
+ * @param denom Denominator, must be non zero
+ * @param coord0 Coordinate on 1 (0th vector of standard algebra basis)
+ * @param coord1 Coordinate on i (1st vector of standard algebra basis)
+ * @param coord2 Coordinate on j (2nd vector of standard algebra basis)
+ * @param coord3 Coordinate on ij (3rd vector of standard algebra basis)
+ */
+void quat_alg_elem_set(quat_alg_elem_t *elem,
+ int32_t denom,
+ int32_t coord0,
+ int32_t coord1,
+ int32_t coord2,
+ int32_t coord3);
+
+/**
+ * @brief Creates algebra element from scalar
+ *
+ * Resulting element has 1-coordinate equal to numerator/denominator
+ *
+ * @param elem Output: algebra element with numerator/denominator as first coordiante
+ * (1-coordinate), 0 elsewhere (i,j,ij coordinates)
+ * @param numerator
+ * @param denominator Assumed non zero
+ */
+void quat_alg_scalar(quat_alg_elem_t *elem, const ibz_t *numerator, const ibz_t *denominator);
+
+/** @brief a+b for algebra elements
+ *
+ * @param res Output
+ * @param a Algebra element
+ * @param b Algebra element
+ */
+void quat_alg_add(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b);
+
+/** @brief a-b for algebra elements
+ *
+ * @param res Output
+ * @param a Algebra element
+ * @param b Algebra element
+ */
+void quat_alg_sub(quat_alg_elem_t *res, const quat_alg_elem_t *a, const quat_alg_elem_t *b);
+
+/** @brief Multiplies algebra element by integer scalar, without normalizing it
+ *
+ * @param res Output
+ * @param scalar Integer
+ * @param elem Algebra element
+ */
+void quat_alg_elem_mul_by_scalar(quat_alg_elem_t *res, const ibz_t *scalar, const quat_alg_elem_t *elem);
+
+/** @}
+ */
+
+/** @internal
+ * @defgroup quat_dim4_helpers Helper functions for functions for matrices or vectors in dimension 4
+ * @{
+ */
+
+/** @internal
+ * @defgroup quat_inv_helpers Helper functions for the integer matrix inversion function
+ * @{
+ */
+
+/** @brief a1a2+b1b2+c1c2
+ *
+ * @param coeff Output: The coefficien which was computed as a1a2+b1b2-c1c2
+ * @param a1
+ * @param a2
+ * @param b1
+ * @param b2
+ * @param c1
+ * @param c2
+ */
+void ibz_inv_dim4_make_coeff_pmp(ibz_t *coeff,
+ const ibz_t *a1,
+ const ibz_t *a2,
+ const ibz_t *b1,
+ const ibz_t *b2,
+ const ibz_t *c1,
+ const ibz_t *c2);
+
+/** @brief -a1a2+b1b2-c1c2
+ *
+ * @param coeff Output: The coefficien which was computed as -a1a2+b1b2-c1c2
+ * @param a1
+ * @param a2
+ * @param b1
+ * @param b2
+ * @param c1
+ * @param c2
+ */
+void ibz_inv_dim4_make_coeff_mpm(ibz_t *coeff,
+ const ibz_t *a1,
+ const ibz_t *a2,
+ const ibz_t *b1,
+ const ibz_t *b2,
+ const ibz_t *c1,
+ const ibz_t *c2);
+
+/** @brief Matrix determinant and a matrix inv such that inv/det is the inverse matrix of the input
+ *
+ * Implemented following the methof of 2x2 minors explained at Method from
+ * https://www.geometrictools.com/Documentation/LaplaceExpansionTheorem.pdf (visited on 3rd of May
+ * 2023, 16h15 CEST)
+ *
+ * @returns 1 if the determinant of mat is not 0 and an inverse was computed, 0 otherwise
+ * @param inv Output: Will contain an integer matrix which, dividet by det, will yield the rational
+ * inverse of the matrix if it exists, can be NULL
+ * @param det Output: Will contain the determinant of the input matrix, can be NULL
+ * @param mat Matrix of which the inverse will be computed
+ */
+int ibz_mat_4x4_inv_with_det_as_denom(ibz_mat_4x4_t *inv, ibz_t *det, const ibz_mat_4x4_t *mat);
+
+/** @}
+ */
+
+/** @internal
+ * @defgroup quat_dim4_lat_helpers Helper functions on vectors and matrices used mainly for lattices
+ * @{
+ */
+
+/** @brief Copy all values from one vector to another
+ *
+ * @param new Output: is set to same values as vec
+ * @param vec
+ */
+void ibz_vec_4_copy(ibz_vec_4_t *new, const ibz_vec_4_t *vec);
+
+/** @brief set res to values coord0,coord1,coord2,coord3
+ *
+ * @param res Output: Will contain vector (coord0,coord1,coord2,coord3)
+ * @param coord0
+ * @param coord1
+ * @param coord2
+ * @param coord3
+ */
+void ibz_vec_4_copy_ibz(ibz_vec_4_t *res,
+ const ibz_t *coord0,
+ const ibz_t *coord1,
+ const ibz_t *coord2,
+ const ibz_t *coord3);
+
+/** @brief Set a vector of 4 integers to given values
+ *
+ * @param vec Output: is set to given coordinates
+ * @param coord0
+ * @param coord1
+ * @param coord2
+ * @param coord3
+ */
+void ibz_vec_4_set(ibz_vec_4_t *vec, int32_t coord0, int32_t coord1, int32_t coord2, int32_t coord3);
+
+/** @brief a+b
+ *
+ * Add two integer 4-vectors
+ *
+ * @param res Output: Will contain sum
+ * @param a
+ * @param b
+ */
+void ibz_vec_4_add(ibz_vec_4_t *res, const ibz_vec_4_t *a, const ibz_vec_4_t *b);
+
+/** @brief a-b
+ *
+ * Substract two integer 4-vectors
+ *
+ * @param res Output: Will contain difference
+ * @param a
+ * @param b
+ */
+void ibz_vec_4_sub(ibz_vec_4_t *res, const ibz_vec_4_t *a, const ibz_vec_4_t *b);
+
+/** @brief x=0
+ *
+ * Test if a vector x has only zero coordinates
+ *
+ * @returns 0 if x has at least one non-zero coordinates, 1 otherwise
+ * @param x
+ */
+int ibz_vec_4_is_zero(const ibz_vec_4_t *x);
+
+/** @brief Compute the linear combination lc = coeff_a vec_a + coeff_b vec_b
+ *
+ * @param lc Output: linear combination lc = coeff_a vec_a + coeff_b vec_b
+ * @param coeff_a Scalar multiplied to vec_a
+ * @param vec_a
+ * @param coeff_b Scalar multiplied to vec_b
+ * @param vec_b
+ */
+void ibz_vec_4_linear_combination(ibz_vec_4_t *lc,
+ const ibz_t *coeff_a,
+ const ibz_vec_4_t *vec_a,
+ const ibz_t *coeff_b,
+ const ibz_vec_4_t *vec_b);
+
+/** @brief multiplies all values in vector by same scalar
+ *
+ * @param prod Output
+ * @param scalar
+ * @param vec
+ */
+void ibz_vec_4_scalar_mul(ibz_vec_4_t *prod, const ibz_t *scalar, const ibz_vec_4_t *vec);
+
+/** @brief divides all values in vector by same scalar
+ *
+ * @returns 1 if scalar divided all values in mat, 0 otherwise (division is performed in both cases)
+ * @param quot Output
+ * @param scalar
+ * @param vec
+ */
+int ibz_vec_4_scalar_div(ibz_vec_4_t *quot, const ibz_t *scalar, const ibz_vec_4_t *vec);
+
+/** @brief Negation for vectors of 4 integers
+ *
+ * @param neg Output: is set to -vec
+ * @param vec
+ */
+void ibz_vec_4_negate(ibz_vec_4_t *neg, const ibz_vec_4_t *vec);
+
+/**
+ * @brief content of a 4-vector of integers
+ *
+ * The content is the GCD of all entries.
+ *
+ * @param v A 4-vector of integers
+ * @param content Output: the resulting gcd
+ */
+void ibz_vec_4_content(ibz_t *content, const ibz_vec_4_t *v);
+
+/** @brief -mat for mat a 4x4 integer matrix
+ *
+ * @param neg Output: is set to -mat
+ * @param mat Input matrix
+ */
+void ibz_mat_4x4_negate(ibz_mat_4x4_t *neg, const ibz_mat_4x4_t *mat);
+
+/** @brief Set all coefficients of a matrix to zero for 4x4 integer matrices
+ *
+ * @param zero
+ */
+void ibz_mat_4x4_zero(ibz_mat_4x4_t *zero);
+
+/** @brief Set a matrix to the identity for 4x4 integer matrices
+ *
+ * @param id
+ */
+void ibz_mat_4x4_identity(ibz_mat_4x4_t *id);
+
+/** @brief Test equality to identity for 4x4 integer matrices
+ *
+ * @returns 1 if mat is the identity matrix, 0 otherwise
+ * @param mat
+ */
+int ibz_mat_4x4_is_identity(const ibz_mat_4x4_t *mat);
+
+/** @brief Equality test for 4x4 integer matrices
+ *
+ * @returns 1 if equal, 0 otherwise
+ * @param mat1
+ * @param mat2
+ */
+int ibz_mat_4x4_equal(const ibz_mat_4x4_t *mat1, const ibz_mat_4x4_t *mat2);
+
+/** @brief Copies all values from a 4x4 integer matrix to another one
+ *
+ * @param new Output: matrix which will have its entries set to mat's entries
+ * @param mat Input matrix
+ */
+void ibz_mat_4x4_copy(ibz_mat_4x4_t *new, const ibz_mat_4x4_t *mat);
+
+/** @brief Matrix by integer multiplication
+ *
+ * @param prod Output
+ * @param scalar
+ * @param mat
+ */
+void ibz_mat_4x4_scalar_mul(ibz_mat_4x4_t *prod, const ibz_t *scalar, const ibz_mat_4x4_t *mat);
+
+/** @brief gcd of all values in matrix
+ *
+ * @param gcd Output
+ * @param mat
+ */
+void ibz_mat_4x4_gcd(ibz_t *gcd, const ibz_mat_4x4_t *mat);
+
+/** @brief Verifies whether the 4x4 input matrix is in Hermite Normal Form
+ *
+ * @returns 1 if mat is in HNF, 0 otherwise
+ * @param mat Matrix to be tested
+ */
+int ibz_mat_4x4_is_hnf(const ibz_mat_4x4_t *mat);
+
+/** @brief Hermite Normal Form of a matrix of 8 integer vectors, computed using a multiple of its
+ * determinant as modulo
+ *
+ * Algorithm used is the one at number 2.4.8 in Henri Cohen's "A Course in Computational Algebraic
+ * Number Theory" (Springer Verlag, in series "Graduate texts in Mathematics") from 1993
+ *
+ * @param hnf Output: Matrix in Hermite Normal Form generating the same lattice as generators
+ * @param generators matrix whose colums generate the same lattice than the output
+ * @param generator_number number of generators given
+ * @param mod integer, must be a multiple of the volume of the lattice generated by the columns of
+ * generators
+ */
+void ibz_mat_4xn_hnf_mod_core(ibz_mat_4x4_t *hnf,
+ int generator_number,
+ const ibz_vec_4_t *generators,
+ const ibz_t *mod);
+
+/** @}
+ */
+/** @}
+ */
+
+/** @internal
+ * @defgroup quat_dim2_helpers Helper functions for dimension 2
+ * @{
+ */
+
+/** @brief Set vector coefficients to the given integers
+ *
+ * @param vec Output: Vector
+ * @param a0
+ * @param a1
+ */
+void ibz_vec_2_set(ibz_vec_2_t *vec, int a0, int a1); // test/dim2
+
+/** @brief Set matrix coefficients to the given integers
+ *
+ * @param mat Output: Matrix
+ * @param a00
+ * @param a01
+ * @param a10
+ * @param a11
+ */
+void ibz_mat_2x2_set(ibz_mat_2x2_t *mat, int a00, int a01, int a10, int a11); // test/dim2
+
+void ibz_mat_2x2_add(ibz_mat_2x2_t *sum, const ibz_mat_2x2_t *a,
+ const ibz_mat_2x2_t *b); // unused
+
+/** @brief Determinant of a 2x2 integer matrix given as 4 integers
+ *
+ * @param det Output: Determinant of the matrix
+ * @param a11 matrix coefficient (upper left corner)
+ * @param a12 matrix coefficient (upper right corner)
+ * @param a21 matrix coefficient (lower left corner)
+ * @param a22 matrix coefficient (lower right corner)
+ */
+void ibz_mat_2x2_det_from_ibz(ibz_t *det,
+ const ibz_t *a11,
+ const ibz_t *a12,
+ const ibz_t *a21,
+ const ibz_t *a22); // dim4
+
+/**
+ * @brief a*b for 2x2 integer matrices modulo m
+ *
+ * @param prod Output matrix
+ * @param mat_a Input matrix
+ * @param mat_b Input matrix
+ * @param m Integer modulo
+ */
+void ibz_2x2_mul_mod(ibz_mat_2x2_t *prod,
+ const ibz_mat_2x2_t *mat_a,
+ const ibz_mat_2x2_t *mat_b,
+ const ibz_t *m); // test/dim2
+/** @}
+ */
+
+/** @internal
+ * @defgroup quat_lattice_helper Helper functions for the lattice library (dimension 4)
+ * @{
+ */
+
+/**
+ * @brief Modifies a lattice to put it in hermite normal form
+ *
+ * In-place modification of the lattice.
+ *
+ * @param lat input lattice
+ *
+ * On a correct lattice this function changes nothing (since it is already in HNF), but it can be
+ * used to put a handmade one in correct form in order to use the other lattice functions.
+ */
+void quat_lattice_hnf(quat_lattice_t *lat); // lattice, test/lattice, test/algebra,
+
+/**
+ * @brief Lattice equality
+ *
+ * Lattice bases are assumed to be under HNF, but denominators are free.
+ *
+ * @returns 1 if both lattices are equal, 0 otherwise
+ * @param lat1
+ * @param lat2
+ */
+int quat_lattice_equal(const quat_lattice_t *lat1,
+ const quat_lattice_t *lat2); // ideal, lattice, test/lattice, test/ideal
+
+/**
+ * @brief Lattice inclusion test
+ *
+ * Lattice bases are assumed to be under HNF, but denominators are free.
+ *
+ * @returns 1 if sublat is included in overlat, 0 otherwise
+ * @param sublat Lattice whose inclusion in overlat will be testes
+ * @param overlat
+ */
+int quat_lattice_inclusion(const quat_lattice_t *sublat,
+ const quat_lattice_t *overlat); // test/lattice, test/ideal
+
+/** @brief Divides basis and denominator of a lattice by their gcd
+ *
+ * @param reduced Output
+ * @param lat Lattice
+ */
+void quat_lattice_reduce_denom(quat_lattice_t *reduced,
+ const quat_lattice_t *lat); // lattice, ideal,
+
+/** @brief a+b for lattices
+ *
+ * @param res Output
+ * @param lat1 Lattice
+ * @param lat2 Lattice
+ */
+void quat_lattice_add(quat_lattice_t *res,
+ const quat_lattice_t *lat1,
+ const quat_lattice_t *lat2); // ideal, lattice, test/lattice
+
+/** @brief a*b for lattices
+ *
+ * @param res Output
+ * @param lat1 Lattice
+ * @param lat2 Lattice
+ * @param alg The quaternion algebra
+ */
+void quat_lattice_mul(quat_lattice_t *res,
+ const quat_lattice_t *lat1,
+ const quat_lattice_t *lat2,
+ const quat_alg_t *alg); // ideal, lattie, test/ideal, test/lattice
+
+/**
+ * @brief Computes the dual lattice of lat, without putting its basis in HNF
+ *
+ * This function returns a lattice not under HNF. For careful internal use only.
+ *
+ * Computation method described in https://cseweb.ucsd.edu/classes/sp14/cse206A-a/lec4.pdf consulted
+ * on 19 of May 2023, 12h40 CEST
+ *
+ * @param dual Output: The dual lattice of lat. ATTENTION: is not under HNF. hnf computation must be
+ * applied before using lattice functions on it
+ * @param lat lattice, the dual of it will be computed
+ */
+void quat_lattice_dual_without_hnf(quat_lattice_t *dual,
+ const quat_lattice_t *lat); // lattice, ideal
+
+/**
+ * @brief Multiply all columns of lat with coord (as algebra elements)
+ *
+ * The columns and coord are seen as algebra elements in basis 1,i,j,ij, i^2 = -1, j^2 = -p). Coord
+ * is multiplied to the right of lat.
+ *
+ * The output matrix is not under HNF.
+ *
+ * @param prod Output: Matrix not under HND whose columns represent the algebra elements obtained as
+ * L*coord for L column of lat.
+ * @param lat Matrix whose columns are algebra elements in basis (1,i,j,ij)
+ * @param coord Integer coordinate algebra element in basis (1,i,j,ij)
+ * @param alg The quaternion algebra
+ */
+void quat_lattice_mat_alg_coord_mul_without_hnf(ibz_mat_4x4_t *prod,
+ const ibz_mat_4x4_t *lat,
+ const ibz_vec_4_t *coord,
+ const quat_alg_t *alg); // lattice
+
+/** @brief The index of sublat into overlat
+ *
+ * Assumes inputs are in HNF.
+ *
+ * @param index Output
+ * @param sublat A lattice in HNF, must be sublattice of overlat
+ * @param overlat A lattice in HNF, must be overlattice of sublat
+ */
+void quat_lattice_index(ibz_t *index, const quat_lattice_t *sublat,
+ const quat_lattice_t *overlat); // ideal
+
+/** @brief Compute the Gram matrix of the quaternion trace bilinear form
+ *
+ * Given a lattice of the quaternion algebra, computes the Gram matrix
+ * of the bilinear form
+ *
+ * 〈a,b〉 := [lattice->denom^2] Tr(a·conj(b))
+ *
+ * multiplied by the square of the denominator of the lattice.
+ *
+ * This matrix always has integer entries.
+ *
+ * @param G Output: Gram matrix of the trace bilinear form on the lattice, multiplied by the square
+ * of the denominator of the lattice
+ * @param lattice A lattice
+ * @param alg The quaternion algebra
+ */
+void quat_lattice_gram(ibz_mat_4x4_t *G, const quat_lattice_t *lattice, const quat_alg_t *alg);
+
+/**
+ * @brief Compute an integer parallelogram containing the ball of
+ * given radius for the positive definite quadratic form defined by
+ * the Gram matrix G.
+ *
+ * The computed parallelogram is defined by the vectors
+ *
+ * (x₁ x₂ x₃ x₄) · U
+ *
+ * with x_i ∈ [ -box[i], box[i] ].
+ *
+ * @param box Output: bounds of the parallelogram
+ * @param U Output: Unimodular transformation defining the parallelogram
+ * @param G Gram matrix of the quadratic form, must be full rank
+ * @param radius Radius of the ball, must be non-negative
+ * @returns 0 if the box only contains the origin, 1 otherwise
+ */
+int quat_lattice_bound_parallelogram(ibz_vec_4_t *box, ibz_mat_4x4_t *U, const ibz_mat_4x4_t *G, const ibz_t *radius);
+
+/** @}
+ */
+
+/** @internal
+ * @defgroup quat_lideal_helper Helper functions for ideals and orders
+ * @{
+ */
+/** @brief Set norm of an ideal given its lattice and parent order
+ *
+ * @param lideal In/Output: Ideal which has lattice and parent_order correctly set, but not
+ * necessarily the norm. Will have norm correctly set too.
+ */
+void quat_lideal_norm(quat_left_ideal_t *lideal); // ideal
+
+/**
+ * @brief Left principal ideal of order, generated by x
+ *
+ * @param lideal Output: left ideal
+ * @param alg quaternion algebra
+ * @param order maximal order of alg whose left ideal is searched
+ * @param x generating element
+ *
+ * Creates the left ideal in 'order' generated by the element 'x'
+ */
+void quat_lideal_create_principal(quat_left_ideal_t *lideal,
+ const quat_alg_elem_t *x,
+ const quat_lattice_t *order,
+ const quat_alg_t *alg); // ideal, test/ideal
+
+/**
+ * @brief Equality test for left ideals
+ *
+ * @returns 1 if both left ideals are equal, 0 otherwise
+ * @param lideal1 left ideal
+ * @param lideal2 left ideal
+ * @param alg the quaternion algebra
+ */
+int quat_lideal_equals(const quat_left_ideal_t *lideal1,
+ const quat_left_ideal_t *lideal2,
+ const quat_alg_t *alg); // test/ideal
+
+/**
+ * @brief Sum of two left ideals
+ *
+ * @param sum Output: Left ideal which is the sum of the 2 inputs
+ * @param lideal1 left ideal
+ * @param lideal2 left ideal
+ * @param alg the quaternion algebra
+ */
+void quat_lideal_add(quat_left_ideal_t *sum,
+ const quat_left_ideal_t *lideal1,
+ const quat_left_ideal_t *lideal2,
+ const quat_alg_t *alg); // Not used outside
+
+/**
+ * @brief Left ideal product of left ideal I and element alpha
+ *
+ * @param product Output: lideal I*alpha, must have integer norm
+ * @param lideal left ideal
+ * @param alpha element multiplied to lideal to get the product ideal
+ * @param alg the quaternion algebra
+ *
+ * I*alpha where I is a left-ideal and alpha an element of the algebra
+ *
+ * The resulting ideal must have an integer norm
+ *
+ */
+void quat_lideal_mul(quat_left_ideal_t *product,
+ const quat_left_ideal_t *lideal,
+ const quat_alg_elem_t *alpha,
+ const quat_alg_t *alg); // test/ideal
+
+/** @brief Computes the inverse ideal (for a left ideal of a maximal order) without putting it under
+ * HNF
+ *
+ * This function returns a lattice not under HNF. For careful internal use only
+ *
+ * Computes the inverse ideal for lideal as conjugate(lideal)/norm(lideal)
+ *
+ * @param inv Output: lattice which is lattice representation of the inverse ideal of lideal
+ * ATTENTION: is not under HNF. hnf computation must be applied before using lattice functions on it
+ * @param lideal Left ideal of a maximal order in alg
+ * @param alg The quaternion algebra
+ */
+void quat_lideal_inverse_lattice_without_hnf(quat_lattice_t *inv,
+ const quat_left_ideal_t *lideal,
+ const quat_alg_t *alg); // ideal
+
+/** @brief Computes the right transporter of two left ideals of the same maximal order
+ *
+ * Following the implementation of ideal isomorphisms in the code of LearningToSQI's sage
+ * implementation of SQIsign. Computes the right transporter of (J:I) as inverse(I)J.
+ *
+ * @param trans Output: lattice which is right transporter from lideal1 to lideal2 (lideal2:lideal1)
+ * @param lideal1 Left ideal of the same maximal order than lideal1 in alg
+ * @param lideal2 Left ideal of the same maximal order than lideal1 in alg
+ * @param alg The quaternion algebra
+ */
+void quat_lideal_right_transporter(quat_lattice_t *trans,
+ const quat_left_ideal_t *lideal1,
+ const quat_left_ideal_t *lideal2,
+ const quat_alg_t *alg);
+
+/**
+ * @brief Right order of a left ideal
+ *
+ * @param order Output: right order of the given ideal
+ * @param lideal left ideal
+ * @param alg the quaternion algebra
+ */
+void quat_lideal_right_order(quat_lattice_t *order, const quat_left_ideal_t *lideal,
+ const quat_alg_t *alg); // ideal
+
+/**
+ * @brief Gram matrix of the trace map of the ideal class
+ *
+ * Compute the Gram matrix of the bilinear form
+ *
+ * 〈a, b〉 := Tr(a·conj(b)) / norm(lideal)
+ *
+ * on the basis of the ideal. This matrix has integer entries and its
+ * integer congruence class only depends on the ideal class.
+ *
+ * @param G Output: Gram matrix of the trace map
+ * @param lideal left ideal
+ * @param alg the quaternion algebra
+ */
+void quat_lideal_class_gram(ibz_mat_4x4_t *G, const quat_left_ideal_t *lideal, const quat_alg_t *alg);
+
+/** @brief Test if order is maximal
+ *
+ * Checks if the discriminant of the order equals the prime p defining the quaternion algebra.
+ *
+ * It is not verified whether the order is really an order. The output 1 only means that if it is an
+ * order, then it is maximal.
+ *
+ * @returns 1 if order is maximal (assuming it is an order), 0 otherwise
+ * @param order An order of the quaternion algebra (assumes to be an order, this is not tested)
+ * @param alg The quaternion algebra
+ */
+int quat_order_is_maximal(const quat_lattice_t *order,
+ const quat_alg_t *alg); // ideal (only in asserts)
+
+/** @brief Compute the discriminant of an order as sqrt(det(gram(reduced_norm)))
+ *
+ * @param disc: Output: The discriminant sqrt(det(gram(reduced_norm)))
+ * @param order An order of the quaternion algebra
+ * @param alg The quaternion algebra
+ */
+int quat_order_discriminant(ibz_t *disc, const quat_lattice_t *order,
+ const quat_alg_t *alg); // ideal
+
+/** @}
+ */
+
+/** @internal
+ * @ingroup quat_normeq
+ * @{
+ */
+
+/** @brief Set lattice to O0
+ *
+ * @param O0 Lattice to be set to (1,i,(i+j)/2,(1+ij)/2)
+ */
+void quat_lattice_O0_set(quat_lattice_t *O0);
+
+/** @brief Set p-extremal maximal order to O0
+ *
+ * @param O0 p-extremal order to be set to (1,i,(i+j)/2,(1+ij)/2)
+ */
+void quat_lattice_O0_set_extremal(quat_p_extremal_maximal_order_t *O0);
+
+/**
+ * @brief Create an element of a extremal maximal order from its coefficients
+ *
+ * @param elem Output: the quaternion element
+ * @param order the order
+ * @param coeffs the vector of 4 ibz coefficients
+ * @param Bpoo quaternion algebra
+ *
+ * elem = x + z*y + z*u + t*z*v
+ * where coeffs = [x,y,u,v] and t = order.t z = order.z
+ *
+ */
+void quat_order_elem_create(quat_alg_elem_t *elem,
+ const quat_p_extremal_maximal_order_t *order,
+ const ibz_vec_4_t *coeffs,
+ const quat_alg_t *Bpoo); // normeq, untested
+
+/** @}
+ */
+/** @}
+ */
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/isog.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/isog.h
new file mode 100644
index 0000000000..b251ca3cdc
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/isog.h
@@ -0,0 +1,28 @@
+#ifndef _ISOG_H_
+#define _ISOG_H_
+#include
+#include
+
+/* KPS structure for isogenies of degree 2 or 4 */
+typedef struct
+{
+ ec_point_t K;
+} ec_kps2_t;
+typedef struct
+{
+ ec_point_t K[3];
+} ec_kps4_t;
+
+void xisog_2(ec_kps2_t *kps, ec_point_t *B, const ec_point_t P); // degree-2 isogeny construction
+void xisog_2_singular(ec_kps2_t *kps, ec_point_t *B24, ec_point_t A24);
+
+void xisog_4(ec_kps4_t *kps, ec_point_t *B, const ec_point_t P); // degree-4 isogeny construction
+void xisog_4_singular(ec_kps4_t *kps, ec_point_t *B24, const ec_point_t P, ec_point_t A24);
+
+void xeval_2(ec_point_t *R, ec_point_t *const Q, const int lenQ, const ec_kps2_t *kps);
+void xeval_2_singular(ec_point_t *R, const ec_point_t *Q, const int lenQ, const ec_kps2_t *kps);
+
+void xeval_4(ec_point_t *R, const ec_point_t *Q, const int lenQ, const ec_kps4_t *kps);
+void xeval_4_singular(ec_point_t *R, const ec_point_t *Q, const int lenQ, const ec_point_t P, const ec_kps4_t *kps);
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/isog_chains.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/isog_chains.c
new file mode 100644
index 0000000000..abc9808057
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/isog_chains.c
@@ -0,0 +1,241 @@
+#include "isog.h"
+#include
+
+// since we use degree 4 isogeny steps, we need to handle the odd case with care
+static uint32_t
+ec_eval_even_strategy(ec_curve_t *curve,
+ ec_point_t *points,
+ unsigned len_points,
+ const ec_point_t *kernel,
+ const int isog_len)
+{
+ ec_curve_normalize_A24(curve);
+ ec_point_t A24;
+ copy_point(&A24, &curve->A24);
+
+ int space = 1;
+ for (int i = 1; i < isog_len; i *= 2)
+ ++space;
+
+ // Stack of remaining kernel points and their associated orders
+ ec_point_t splits[space];
+ uint16_t todo[space];
+ splits[0] = *kernel;
+ todo[0] = isog_len;
+
+ int current = 0; // Pointer to current top of stack
+
+ // Chain of 4-isogenies
+ for (int j = 0; j < isog_len / 2; ++j) {
+ assert(current >= 0);
+ assert(todo[current] >= 1);
+ // Get the next point of order 4
+ while (todo[current] != 2) {
+ assert(todo[current] >= 3);
+ // A new split will be added
+ ++current;
+ assert(current < space);
+ // We set the seed of the new split to be computed and saved
+ copy_point(&splits[current], &splits[current - 1]);
+ // if we copied from the very first element, then we perform one additional doubling
+ unsigned num_dbls = todo[current - 1] / 4 * 2 + todo[current - 1] % 2;
+ todo[current] = todo[current - 1] - num_dbls;
+ while (num_dbls--)
+ xDBL_A24(&splits[current], &splits[current], &A24, false);
+ }
+
+ if (j == 0) {
+ assert(fp2_is_one(&A24.z));
+ if (!ec_is_four_torsion(&splits[current], curve))
+ return -1;
+
+ ec_point_t T;
+ xDBL_A24(&T, &splits[current], &A24, false);
+ if (fp2_is_zero(&T.x))
+ return -1; // special isogenies not allowed
+ } else {
+ assert(todo[current] == 2);
+#ifndef NDEBUG
+ if (fp2_is_zero(&splits[current].z))
+ debug_print("splitting point z coordinate is unexpectedly zero");
+
+ ec_point_t test;
+ xDBL_A24(&test, &splits[current], &A24, false);
+ if (fp2_is_zero(&test.z))
+ debug_print("z coordinate is unexpectedly zero before doubling");
+ xDBL_A24(&test, &test, &A24, false);
+ if (!fp2_is_zero(&test.z))
+ debug_print("z coordinate is unexpectedly not zero after doubling");
+#endif
+ }
+
+ // Evaluate 4-isogeny
+ ec_kps4_t kps4;
+ xisog_4(&kps4, &A24, splits[current]);
+ xeval_4(splits, splits, current, &kps4);
+ for (int i = 0; i < current; ++i)
+ todo[i] -= 2;
+ xeval_4(points, points, len_points, &kps4);
+
+ --current;
+ }
+ assert(isog_len % 2 ? !current : current == -1);
+
+ // Final 2-isogeny
+ if (isog_len % 2) {
+#ifndef NDEBUG
+ if (fp2_is_zero(&splits[0].z))
+ debug_print("splitting point z coordinate is unexpectedly zero");
+ ec_point_t test;
+ copy_point(&test, &splits[0]);
+ xDBL_A24(&test, &test, &A24, false);
+ if (!fp2_is_zero(&test.z))
+ debug_print("z coordinate is unexpectedly not zero after doubling");
+#endif
+
+ // We need to check the order of this point in case there were no 4-isogenies
+ if (isog_len == 1 && !ec_is_two_torsion(&splits[0], curve))
+ return -1;
+ if (fp2_is_zero(&splits[0].x)) {
+ // special isogenies not allowed
+ // this case can only happen if isog_len == 1; otherwise the
+ // previous 4-isogenies we computed ensure that $T=(0:1)$ is put
+ // as the kernel of the dual isogeny
+ return -1;
+ }
+
+ ec_kps2_t kps2;
+ xisog_2(&kps2, &A24, splits[0]);
+ xeval_2(points, points, len_points, &kps2);
+ }
+
+ // Output curve in the form (A:C)
+ A24_to_AC(curve, &A24);
+
+ curve->is_A24_computed_and_normalized = false;
+
+ return 0;
+}
+
+uint32_t
+ec_eval_even(ec_curve_t *image, ec_isog_even_t *phi, ec_point_t *points, unsigned len_points)
+{
+ copy_curve(image, &phi->curve);
+ return ec_eval_even_strategy(image, points, len_points, &phi->kernel, phi->length);
+}
+
+// naive implementation
+uint32_t
+ec_eval_small_chain(ec_curve_t *curve,
+ const ec_point_t *kernel,
+ int len,
+ ec_point_t *points,
+ unsigned len_points,
+ bool special) // do we allow special isogenies?
+{
+
+ ec_point_t A24;
+ AC_to_A24(&A24, curve);
+
+ ec_kps2_t kps;
+ ec_point_t small_K, big_K;
+ copy_point(&big_K, kernel);
+
+ for (int i = 0; i < len; i++) {
+ copy_point(&small_K, &big_K);
+ // small_K = big_K;
+ for (int j = 0; j < len - i - 1; j++) {
+ xDBL_A24(&small_K, &small_K, &A24, false);
+ }
+ // Check the order of the point before the first isogeny step
+ if (i == 0 && !ec_is_two_torsion(&small_K, curve))
+ return (uint32_t)-1;
+ // Perform isogeny step
+ if (fp2_is_zero(&small_K.x)) {
+ if (special) {
+ ec_point_t B24;
+ xisog_2_singular(&kps, &B24, A24);
+ xeval_2_singular(&big_K, &big_K, 1, &kps);
+ xeval_2_singular(points, points, len_points, &kps);
+ copy_point(&A24, &B24);
+ } else {
+ return (uint32_t)-1;
+ }
+ } else {
+ xisog_2(&kps, &A24, small_K);
+ xeval_2(&big_K, &big_K, 1, &kps);
+ xeval_2(points, points, len_points, &kps);
+ }
+ }
+ A24_to_AC(curve, &A24);
+
+ curve->is_A24_computed_and_normalized = false;
+ return 0;
+}
+
+uint32_t
+ec_isomorphism(ec_isom_t *isom, const ec_curve_t *from, const ec_curve_t *to)
+{
+ fp2_t t0, t1, t2, t3, t4;
+
+ fp2_mul(&t0, &from->A, &from->C);
+ fp2_mul(&t1, &to->A, &to->C);
+
+ fp2_mul(&t2, &t1, &to->C); // toA*toC^2
+ fp2_add(&t3, &t2, &t2);
+ fp2_add(&t3, &t3, &t3);
+ fp2_add(&t3, &t3, &t3);
+ fp2_add(&t2, &t2, &t3); // 9*toA*toC^2
+ fp2_sqr(&t3, &to->A);
+ fp2_mul(&t3, &t3, &to->A); // toA^3
+ fp2_add(&t3, &t3, &t3);
+ fp2_sub(&isom->Nx, &t3, &t2); // 2*toA^3-9*toA*toC^2
+ fp2_mul(&t2, &t0, &from->A); // fromA^2*fromC
+ fp2_sqr(&t3, &from->C);
+ fp2_mul(&t3, &t3, &from->C); // fromC^3
+ fp2_add(&t4, &t3, &t3);
+ fp2_add(&t3, &t4, &t3); // 3*fromC^3
+ fp2_sub(&t3, &t3, &t2); // 3*fromC^3-fromA^2*fromC
+ fp2_mul(&isom->Nx, &isom->Nx, &t3); // lambda_x = (2*toA^3-9*toA*toC^2)*(3*fromC^3-fromA^2*fromC)
+
+ fp2_mul(&t2, &t0, &from->C); // fromA*fromC^2
+ fp2_add(&t3, &t2, &t2);
+ fp2_add(&t3, &t3, &t3);
+ fp2_add(&t3, &t3, &t3);
+ fp2_add(&t2, &t2, &t3); // 9*fromA*fromC^2
+ fp2_sqr(&t3, &from->A);
+ fp2_mul(&t3, &t3, &from->A); // fromA^3
+ fp2_add(&t3, &t3, &t3);
+ fp2_sub(&isom->D, &t3, &t2); // 2*fromA^3-9*fromA*fromC^2
+ fp2_mul(&t2, &t1, &to->A); // toA^2*toC
+ fp2_sqr(&t3, &to->C);
+ fp2_mul(&t3, &t3, &to->C); // toC^3
+ fp2_add(&t4, &t3, &t3);
+ fp2_add(&t3, &t4, &t3); // 3*toC^3
+ fp2_sub(&t3, &t3, &t2); // 3*toC^3-toA^2*toC
+ fp2_mul(&isom->D, &isom->D, &t3); // lambda_z = (2*fromA^3-9*fromA*fromC^2)*(3*toC^3-toA^2*toC)
+
+ // Mont -> SW -> SW -> Mont
+ fp2_mul(&t0, &to->C, &from->A);
+ fp2_mul(&t0, &t0, &isom->Nx); // lambda_x*toC*fromA
+ fp2_mul(&t1, &from->C, &to->A);
+ fp2_mul(&t1, &t1, &isom->D); // lambda_z*fromC*toA
+ fp2_sub(&isom->Nz, &t0, &t1); // lambda_x*toC*fromA - lambda_z*fromC*toA
+ fp2_mul(&t0, &from->C, &to->C);
+ fp2_add(&t1, &t0, &t0);
+ fp2_add(&t0, &t0, &t1); // 3*fromC*toC
+ fp2_mul(&isom->D, &isom->D, &t0); // 3*lambda_z*fromC*toC
+ fp2_mul(&isom->Nx, &isom->Nx, &t0); // 3*lambda_x*fromC*toC
+
+ return (fp2_is_zero(&isom->Nx) | fp2_is_zero(&isom->D));
+}
+
+void
+ec_iso_eval(ec_point_t *P, ec_isom_t *isom)
+{
+ fp2_t tmp;
+ fp2_mul(&P->x, &P->x, &isom->Nx);
+ fp2_mul(&tmp, &P->z, &isom->Nz);
+ fp2_add(&P->x, &P->x, &tmp);
+ fp2_mul(&P->z, &P->z, &isom->D);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/keygen.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/keygen.c
new file mode 100644
index 0000000000..c1c206c99d
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/keygen.c
@@ -0,0 +1,64 @@
+#include
+#include
+#include
+#include
+#include
+
+void
+secret_key_init(secret_key_t *sk)
+{
+ quat_left_ideal_init(&(sk->secret_ideal));
+ ibz_mat_2x2_init(&(sk->mat_BAcan_to_BA0_two));
+ ec_curve_init(&sk->curve);
+}
+
+void
+secret_key_finalize(secret_key_t *sk)
+{
+ quat_left_ideal_finalize(&(sk->secret_ideal));
+ ibz_mat_2x2_finalize(&(sk->mat_BAcan_to_BA0_two));
+}
+
+int
+protocols_keygen(public_key_t *pk, secret_key_t *sk)
+{
+ int found = 0;
+ ec_basis_t B_0_two;
+
+ // iterating until a solution has been found
+ while (!found) {
+
+ found = quat_sampling_random_ideal_O0_given_norm(
+ &sk->secret_ideal, &SEC_DEGREE, 1, &QUAT_represent_integer_params, NULL);
+
+ // replacing the secret key ideal by a shorter equivalent one for efficiency
+ found = found && quat_lideal_prime_norm_reduced_equivalent(
+ &sk->secret_ideal, &QUATALG_PINFTY, QUAT_primality_num_iter, QUAT_equiv_bound_coeff);
+
+ // ideal to isogeny clapotis
+
+ found = found && dim2id2iso_arbitrary_isogeny_evaluation(&B_0_two, &sk->curve, &sk->secret_ideal);
+ }
+
+ // Assert the isogeny was found and images have the correct order
+ assert(test_basis_order_twof(&B_0_two, &sk->curve, TORSION_EVEN_POWER));
+
+ // Compute a deterministic basis with a hint to speed up verification
+ pk->hint_pk = ec_curve_to_basis_2f_to_hint(&sk->canonical_basis, &sk->curve, TORSION_EVEN_POWER);
+
+ // Assert the deterministic basis we computed has the correct order
+ assert(test_basis_order_twof(&sk->canonical_basis, &sk->curve, TORSION_EVEN_POWER));
+
+ // Compute the 2x2 matrix basis change from the canonical basis to the evaluation of our secret
+ // isogeny
+ change_of_basis_matrix_tate(
+ &sk->mat_BAcan_to_BA0_two, &sk->canonical_basis, &B_0_two, &sk->curve, TORSION_EVEN_POWER);
+
+ // Set the public key from the codomain curve
+ copy_curve(&pk->curve, &sk->curve);
+ pk->curve.is_A24_computed_and_normalized = false; // We don't send any precomputation
+
+ assert(fp2_is_one(&pk->curve.C) == 0xFFFFFFFF);
+
+ return found;
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/l2.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/l2.c
new file mode 100644
index 0000000000..0fed774a04
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/l2.c
@@ -0,0 +1,332 @@
+#include
+#include "lll_internals.h"
+#include "internal.h"
+
+#include
+#include
+
+
+// Access entry of symmetric matrix
+#define SYM(M, i, j) (i < j ? &M[j][i] : &M[i][j])
+
+typedef struct fp_num {
+ double s;
+ int e;
+} fp_num;
+
+static void
+copy(fp_num *x, fp_num *r)
+{
+ r->s = x->s;
+ r->e = x->e;
+}
+
+static void
+normalize(fp_num *x)
+{
+ if (fpclassify(x->s) == FP_ZERO || isfinite(x->s) == 0) {
+ if (fpclassify(x->s) == FP_ZERO) {
+ x->e = INT_MIN;
+ }
+ } else {
+ int e;
+ x->s = frexp(x->s, &e);
+ x->e += e;
+ }
+}
+
+static void
+to_one(fp_num *x)
+{
+ x->s = 1;
+ x->e = 0;
+}
+
+static void
+to_deltabar(fp_num *x)
+{
+ x->s = DELTABAR;
+ x->e = 0;
+}
+
+static void
+from_mpz(const ibz_t *x, fp_num *r)
+{
+ long exp = 0;
+ r->s = mpz_get_d_2exp(&exp, x->i);
+ r->e = exp;
+}
+
+static void
+to_mpz(const fp_num *x, ibz_t *r)
+{
+ if (x->e >= DBL_MANT_DIG) {
+ double s = x->s * 0x1P53;
+ mpz_set_d(r->i, s);
+ mpz_mul_2exp(r->i, r->i, x->e - DBL_MANT_DIG);
+ } else if (x->e < 0) {
+ mpz_set_ui(r->i, 0);
+ } else {
+ double s = ldexp(x->s, x->e);
+ mpz_set_d(r->i, round(s));
+ }
+}
+
+static void
+fp_mul(const fp_num *x, const fp_num *y, fp_num *r)
+{
+ r->s = x->s * y->s;
+ r->e = x->e + y->e;
+ normalize(r);
+
+}
+
+static void
+fp_div(const fp_num *x, const fp_num *y, fp_num *r)
+{
+ r->s = x->s / y->s;
+ r->e = x->e - y->e;
+ normalize(r);
+}
+
+static void
+fp_sub(const fp_num *x, const fp_num *y, fp_num *r)
+{
+ if (x->e > y->e + DBL_MANT_DIG) {
+ r->s = x->s;
+ r->e = x->e;
+ } else if (y->e > x->e + DBL_MANT_DIG) {
+ r->s = -y->s;
+ r->e = y->e;
+ } else {
+ int e = x->e - y->e;
+
+ if (e >= 0) {
+ r->s = x->s - ldexp(y->s, -e);
+ r->e = x->e;
+ } else {
+ r->s = ldexp(x->s, e) - y->s;
+ r->e = y->e;
+ }
+
+ normalize(r);
+ }
+}
+
+static inline int
+sign(const fp_num *x)
+{
+ if (x->s < 0.0)
+ return -1;
+ return 1;
+}
+
+static int
+fp_cmp(const fp_num *x, const fp_num *y)
+{
+ int sign_x = sign(x);
+ int sign_y = sign(y);
+
+ if (sign_x != sign_y)
+ return sign_x - sign_y;
+ else if (x->e > y->e)
+ return sign_x;
+ else if (y->e > x->e)
+ return -sign_x;
+ else if (x->s > y->s)
+ return 1;
+ else if (x->s < y->s)
+ return -1;
+ else
+ return 0;
+}
+
+static void
+fp_round(fp_num *x)
+{
+ if (x->e < 0) {
+ x->s = 0;
+ x->e = 0;
+ } else if (x->e >= DBL_MANT_DIG) {
+ return;
+ } else {
+ double tmp;
+ tmp = ldexp(x->s, x->e);
+ x->s = round(tmp);
+ x->e = 0;
+ normalize(x);
+ }
+}
+
+static void
+fp_abs(const fp_num *x, fp_num *y) {
+ if (x->s < 0.0) {
+ y->s = -x->s;
+ } else {
+ y->s = x->s;
+ }
+ y->e = x->e;
+}
+
+void
+quat_lll_core(ibz_mat_4x4_t *G, ibz_mat_4x4_t *basis)
+{
+ fp_num const_one = {0};
+ fp_num delta_bar = {0};
+ fp_num eta_bar = {0};
+ fp_num neg_eta_bar = {0};
+ to_one(&const_one);
+ to_deltabar(&delta_bar);
+ eta_bar.s = ETABAR;
+ eta_bar.e = 0;
+ neg_eta_bar.s = -ETABAR;
+ neg_eta_bar.e = 0;
+ normalize(&eta_bar);
+ normalize(&neg_eta_bar);
+
+ fp_num r[4][4] = {0};
+ fp_num u[4][4] = {0};
+ fp_num lovasz[4] = {0};
+
+ fp_num Xf = {0};
+ fp_num tmpF = {0};
+
+ ibz_t X, tmpI;
+ ibz_init(&X);
+ ibz_init(&tmpI);
+
+ // Main L² loop
+ from_mpz(&G->m[0][0], &r[0][0]);
+ int kappa = 1;
+ while (kappa < 4) {
+ // size reduce b_κ
+ int done = 0;
+ while (!done) {
+ // Recompute the κ-th row of the Choleski Factorisation
+ // Loop invariant:
+ // r[κ][j] ≈ u[κ][j] ‖b_j*‖² ≈ 〈b_κ, b_j*〉
+ for (int j = 0; j <= kappa; j++) {
+ from_mpz(&G->m[kappa][j], &r[kappa][j]);
+ for (int k = 0; k < j; k++) {
+ fp_mul(&r[kappa][k], &u[j][k], &tmpF);
+ fp_sub(&r[kappa][j], &tmpF, &r[kappa][j]);
+ }
+ if (j < kappa)
+ fp_div(&r[kappa][j], &r[j][j], &u[kappa][j]);
+ }
+
+ done = 1;
+ // size reduce
+ for (int i = kappa - 1; i >= 0; i--) {
+ if (fp_cmp(&u[kappa][i], &eta_bar) > 0 || fp_cmp(&u[kappa][i], &neg_eta_bar) < 0) {
+ done = 0;
+ copy(&u[kappa][i], &Xf);
+ fp_round(&Xf);
+ to_mpz(&Xf, &X);
+ // Update basis: b_κ ← b_κ - X·b_i
+ for (int j = 0; j < 4; j++) {
+ ibz_mul(&tmpI, &X, &basis->m[j][i]);
+ ibz_sub(&basis->m[j][kappa], &basis->m[j][kappa], &tmpI);
+ }
+ // Update lower half of the Gram matrix
+ // = - 2X + X² =
+ // - X - X( - X·)
+ //// 〈b_κ, b_κ〉 ← 〈b_κ, b_κ〉 - X·〈b_κ, b_i〉
+ ibz_mul(&tmpI, &X, &G->m[kappa][i]);
+ ibz_sub(&G->m[kappa][kappa], &G->m[kappa][kappa], &tmpI);
+ for (int j = 0; j < 4; j++) { // works because i < κ
+ // 〈b_κ, b_j〉 ← 〈b_κ, b_j〉 - X·〈b_i, b_j〉
+ ibz_mul(&tmpI, &X, SYM(G->m, i, j));
+ ibz_sub(SYM(G->m, kappa, j), SYM(G->m, kappa, j), &tmpI);
+ }
+ // After the loop:
+ //// 〈b_κ,b_κ〉 ← 〈b_κ,b_κ〉 - X·〈b_κ,b_i〉 - X·(〈b_κ,b_i〉 - X·〈b_i,
+ /// b_i〉) = 〈b_κ - X·b_i, b_κ - X·b_i〉
+ //
+ // Update u[kappa][j]
+ for (int j = 0; j < i; j++) {
+ fp_mul(&Xf, &u[i][j], &tmpF);
+ fp_sub(&u[kappa][j], &tmpF, &u[kappa][j]);
+ }
+ }
+ }
+ }
+
+ // Check Lovasz' conditions
+ // lovasz[0] = ‖b_κ‖²
+ from_mpz(&G->m[kappa][kappa], &lovasz[0]);
+ // lovasz[i] = lovasz[i-1] - u[κ][i-1]·r[κ][i-1]
+ for (int i = 1; i < kappa; i++) {
+ fp_mul(&u[kappa][i - 1], &r[kappa][i - 1], &tmpF);
+ fp_sub(&lovasz[i - 1], &tmpF, &lovasz[i]);
+ }
+ int swap;
+ for (swap = kappa; swap > 0; swap--) {
+ fp_mul(&delta_bar, &r[swap - 1][swap - 1], &tmpF);
+ if (fp_cmp(&tmpF, &lovasz[swap - 1]) < 0)
+ break;
+ }
+
+ // Insert b_κ before b_swap
+ if (kappa != swap) {
+ // Insert b_κ before b_swap in the basis and in the lower half Gram matrix
+ for (int j = kappa; j > swap; j--) {
+ for (int i = 0; i < 4; i++) {
+ ibz_swap(&basis->m[i][j], &basis->m[i][j - 1]);
+ if (i == j - 1)
+ ibz_swap(&G->m[i][i], &G->m[j][j]);
+ else if (i != j)
+ ibz_swap(SYM(G->m, i, j), SYM(G->m, i, j - 1));
+ }
+ }
+ // Copy row u[κ] and r[κ] in swap position, ignore what follows
+ for (int i = 0; i < swap; i++) {
+ copy(&u[kappa][i], &u[swap][i]);
+ copy(&r[kappa][i], &r[swap][i]);
+ }
+ copy(&lovasz[swap], &r[swap][swap]);
+ // swap complete
+ kappa = swap;
+ }
+
+ kappa += 1;
+ }
+
+#ifndef NDEBUG
+ // Check size-reducedness
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < i; j++) {
+ fp_abs(&u[i][j], &u[i][j]);
+ assert(fp_cmp(&u[i][j], &eta_bar) <= 0);
+ }
+ // Check Lovasz' conditions
+ for (int i = 1; i < 4; i++) {
+ fp_mul(&u[i][i - 1], &u[i][i - 1], &tmpF);
+ fp_sub(&delta_bar, &tmpF, &tmpF);
+ fp_mul(&tmpF, &r[i - 1][i - 1], &tmpF);
+ assert(fp_cmp(&tmpF, &r[i][i]) <= 0);
+ }
+#endif
+
+ // Fill in the upper half of the Gram matrix
+ for (int i = 0; i < 4; i++) {
+ for (int j = i + 1; j < 4; j++)
+ ibz_copy(&G->m[i][j], &G->m[j][i]);
+ }
+
+ // Clearinghouse
+ ibz_finalize(&X);
+ ibz_finalize(&tmpI);
+}
+
+int
+quat_lattice_lll(ibz_mat_4x4_t *red, const quat_lattice_t *lattice, const quat_alg_t *alg)
+{
+ ibz_mat_4x4_t G; // Gram Matrix
+ ibz_mat_4x4_init(&G);
+ quat_lattice_gram(&G, lattice, alg);
+ ibz_mat_4x4_copy(red, &lattice->basis);
+ quat_lll_core(&G, red);
+ ibz_mat_4x4_finalize(&G);
+ return 0;
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lat_ball.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lat_ball.c
new file mode 100644
index 0000000000..3f7476988c
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lat_ball.c
@@ -0,0 +1,139 @@
+#include
+#include
+#include
+#include "internal.h"
+#include "lll_internals.h"
+
+int
+quat_lattice_bound_parallelogram(ibz_vec_4_t *box, ibz_mat_4x4_t *U, const ibz_mat_4x4_t *G, const ibz_t *radius)
+{
+ ibz_t denom, rem;
+ ibz_init(&denom);
+ ibz_init(&rem);
+ ibz_mat_4x4_t dualG;
+ ibz_mat_4x4_init(&dualG);
+
+// Compute the Gram matrix of the dual lattice
+#ifndef NDEBUG
+ int inv_check = ibz_mat_4x4_inv_with_det_as_denom(&dualG, &denom, G);
+ assert(inv_check);
+#else
+ (void)ibz_mat_4x4_inv_with_det_as_denom(&dualG, &denom, G);
+#endif
+ // Initialize the dual lattice basis to the identity matrix
+ ibz_mat_4x4_identity(U);
+ // Reduce the dual lattice
+ quat_lll_core(&dualG, U);
+
+ // Compute the parallelogram's bounds
+ int trivial = 1;
+ for (int i = 0; i < 4; i++) {
+ ibz_mul(&box->v[i], &dualG.m[i][i], radius);
+ ibz_div(&box->v[i], &rem, &box->v[i], &denom);
+ ibz_sqrt_floor(&box->v[i], &box->v[i]);
+ trivial &= ibz_is_zero(&box->v[i]);
+ }
+
+ // Compute the transpose transformation matrix
+#ifndef NDEBUG
+ int inv = ibz_mat_4x4_inv_with_det_as_denom(U, &denom, U);
+#else
+ (void)ibz_mat_4x4_inv_with_det_as_denom(U, &denom, U);
+#endif
+ // U is unitary, det(U) = ± 1
+ ibz_mat_4x4_scalar_mul(U, &denom, U);
+#ifndef NDEBUG
+ assert(inv);
+ ibz_abs(&denom, &denom);
+ assert(ibz_is_one(&denom));
+#endif
+
+ ibz_mat_4x4_finalize(&dualG);
+ ibz_finalize(&denom);
+ ibz_finalize(&rem);
+ return !trivial;
+}
+
+int
+quat_lattice_sample_from_ball(quat_alg_elem_t *res,
+ const quat_lattice_t *lattice,
+ const quat_alg_t *alg,
+ const ibz_t *radius)
+{
+ assert(ibz_cmp(radius, &ibz_const_zero) > 0);
+
+ ibz_vec_4_t box;
+ ibz_vec_4_init(&box);
+ ibz_mat_4x4_t U, G;
+ ibz_mat_4x4_init(&U);
+ ibz_mat_4x4_init(&G);
+ ibz_vec_4_t x;
+ ibz_vec_4_init(&x);
+ ibz_t rad, tmp;
+ ibz_init(&rad);
+ ibz_init(&tmp);
+
+ // Compute the Gram matrix of the lattice
+ quat_lattice_gram(&G, lattice, alg);
+
+ // Correct ball radius by the denominator
+ ibz_mul(&rad, radius, &lattice->denom);
+ ibz_mul(&rad, &rad, &lattice->denom);
+ // Correct by 2 (Gram matrix corresponds to twice the norm)
+ ibz_mul(&rad, &rad, &ibz_const_two);
+
+ // Compute a bounding parallelogram for the ball, stop if it only
+ // contains the origin
+ int ok = quat_lattice_bound_parallelogram(&box, &U, &G, &rad);
+ if (!ok)
+ goto err;
+
+ // Rejection sampling from the parallelogram
+#ifndef NDEBUG
+ int cnt = 0;
+#endif
+ do {
+ // Sample vector
+ for (int i = 0; i < 4; i++) {
+ if (ibz_is_zero(&box.v[i])) {
+ ibz_copy(&x.v[i], &ibz_const_zero);
+ } else {
+ ibz_add(&tmp, &box.v[i], &box.v[i]);
+ ok &= ibz_rand_interval(&x.v[i], &ibz_const_zero, &tmp);
+ ibz_sub(&x.v[i], &x.v[i], &box.v[i]);
+ if (!ok)
+ goto err;
+ }
+ }
+ // Map to parallelogram
+ ibz_mat_4x4_eval_t(&x, &x, &U);
+ // Evaluate quadratic form
+ quat_qf_eval(&tmp, &G, &x);
+#ifndef NDEBUG
+ cnt++;
+ if (cnt % 100 == 0)
+ printf("Lattice sampling rejected %d times", cnt - 1);
+#endif
+ } while (ibz_is_zero(&tmp) || (ibz_cmp(&tmp, &rad) > 0));
+
+ // Evaluate linear combination
+ ibz_mat_4x4_eval(&(res->coord), &(lattice->basis), &x);
+ ibz_copy(&(res->denom), &(lattice->denom));
+ quat_alg_normalize(res);
+
+#ifndef NDEBUG
+ // Check norm is smaller than radius
+ quat_alg_norm(&tmp, &rad, res, alg);
+ ibz_mul(&rad, &rad, radius);
+ assert(ibz_cmp(&tmp, &rad) <= 0);
+#endif
+
+err:
+ ibz_finalize(&rad);
+ ibz_finalize(&tmp);
+ ibz_vec_4_finalize(&x);
+ ibz_mat_4x4_finalize(&U);
+ ibz_mat_4x4_finalize(&G);
+ ibz_vec_4_finalize(&box);
+ return ok;
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lattice.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lattice.c
new file mode 100644
index 0000000000..ef7b9ccdcc
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lattice.c
@@ -0,0 +1,328 @@
+#include
+#include
+#include "internal.h"
+
+// helper functions
+int
+quat_lattice_equal(const quat_lattice_t *lat1, const quat_lattice_t *lat2)
+{
+ int equal = 1;
+ quat_lattice_t a, b;
+ quat_lattice_init(&a);
+ quat_lattice_init(&b);
+ quat_lattice_reduce_denom(&a, lat1);
+ quat_lattice_reduce_denom(&b, lat2);
+ ibz_abs(&(a.denom), &(a.denom));
+ ibz_abs(&(b.denom), &(b.denom));
+ quat_lattice_hnf(&a);
+ quat_lattice_hnf(&b);
+ equal = equal && (ibz_cmp(&(a.denom), &(b.denom)) == 0);
+ equal = equal && ibz_mat_4x4_equal(&(a.basis), &(b.basis));
+ quat_lattice_finalize(&a);
+ quat_lattice_finalize(&b);
+ return (equal);
+}
+
+// sublattice test
+int
+quat_lattice_inclusion(const quat_lattice_t *sublat, const quat_lattice_t *overlat)
+{
+ int res;
+ quat_lattice_t sum;
+ quat_lattice_init(&sum);
+ quat_lattice_add(&sum, overlat, sublat);
+ res = quat_lattice_equal(&sum, overlat);
+ quat_lattice_finalize(&sum);
+ return (res);
+}
+
+void
+quat_lattice_reduce_denom(quat_lattice_t *reduced, const quat_lattice_t *lat)
+{
+ ibz_t gcd;
+ ibz_init(&gcd);
+ ibz_mat_4x4_gcd(&gcd, &(lat->basis));
+ ibz_gcd(&gcd, &gcd, &(lat->denom));
+ ibz_mat_4x4_scalar_div(&(reduced->basis), &gcd, &(lat->basis));
+ ibz_div(&(reduced->denom), &gcd, &(lat->denom), &gcd);
+ ibz_abs(&(reduced->denom), &(reduced->denom));
+ ibz_finalize(&gcd);
+}
+
+void
+quat_lattice_conjugate_without_hnf(quat_lattice_t *conj, const quat_lattice_t *lat)
+{
+ ibz_mat_4x4_copy(&(conj->basis), &(lat->basis));
+ ibz_copy(&(conj->denom), &(lat->denom));
+
+ for (int row = 1; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ ibz_neg(&(conj->basis.m[row][col]), &(conj->basis.m[row][col]));
+ }
+ }
+}
+
+// Method described in https://cseweb.ucsd.edu/classes/sp14/cse206A-a/lec4.pdf consulted on 19 of
+// May 2023, 12h40 CEST
+void
+quat_lattice_dual_without_hnf(quat_lattice_t *dual, const quat_lattice_t *lat)
+{
+ ibz_mat_4x4_t inv;
+ ibz_t det;
+ ibz_init(&det);
+ ibz_mat_4x4_init(&inv);
+ ibz_mat_4x4_inv_with_det_as_denom(&inv, &det, &(lat->basis));
+ ibz_mat_4x4_transpose(&inv, &inv);
+ // dual_denom = det/lat_denom
+ ibz_mat_4x4_scalar_mul(&(dual->basis), &(lat->denom), &inv);
+ ibz_copy(&(dual->denom), &det);
+
+ ibz_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_vec_4_t generators[8];
+ ibz_mat_4x4_t tmp;
+ ibz_t det1, det2, detprod;
+ ibz_init(&det1);
+ ibz_init(&det2);
+ ibz_init(&detprod);
+ for (int i = 0; i < 8; i++)
+ ibz_vec_4_init(&(generators[i]));
+ ibz_mat_4x4_init(&tmp);
+ ibz_mat_4x4_scalar_mul(&tmp, &(lat1->denom), &(lat2->basis));
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibz_copy(&(generators[j].v[i]), &(tmp.m[i][j]));
+ }
+ }
+ ibz_mat_4x4_inv_with_det_as_denom(NULL, &det1, &tmp);
+ ibz_mat_4x4_scalar_mul(&tmp, &(lat2->denom), &(lat1->basis));
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibz_copy(&(generators[4 + j].v[i]), &(tmp.m[i][j]));
+ }
+ }
+ ibz_mat_4x4_inv_with_det_as_denom(NULL, &det2, &tmp);
+ assert(!ibz_is_zero(&det1));
+ assert(!ibz_is_zero(&det2));
+ ibz_gcd(&detprod, &det1, &det2);
+ ibz_mat_4xn_hnf_mod_core(&(res->basis), 8, generators, &detprod);
+ ibz_mul(&(res->denom), &(lat1->denom), &(lat2->denom));
+ quat_lattice_reduce_denom(res, res);
+ ibz_mat_4x4_finalize(&tmp);
+ ibz_finalize(&det1);
+ ibz_finalize(&det2);
+ ibz_finalize(&detprod);
+ for (int i = 0; i < 8; i++)
+ ibz_vec_4_finalize(&(generators[i]));
+}
+
+// method described in https://cseweb.ucsd.edu/classes/sp14/cse206A-a/lec4.pdf consulted on 19 of
+// May 2023, 12h40 CEST
+void
+quat_lattice_intersect(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2)
+{
+ 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); // could be removed if we do not expect HNF any more
+ quat_lattice_finalize(&dual1);
+ quat_lattice_finalize(&dual2);
+ quat_lattice_finalize(&dual_res);
+}
+
+void
+quat_lattice_mat_alg_coord_mul_without_hnf(ibz_mat_4x4_t *prod,
+ const ibz_mat_4x4_t *lat,
+ const ibz_vec_4_t *coord,
+ const quat_alg_t *alg)
+{
+ ibz_vec_4_t p, a;
+ ibz_vec_4_init(&p);
+ ibz_vec_4_init(&a);
+ for (int i = 0; i < 4; i++) {
+ ibz_vec_4_copy_ibz(&a, &(lat->m[0][i]), &(lat->m[1][i]), &(lat->m[2][i]), &(lat->m[3][i]));
+ quat_alg_coord_mul(&p, &a, coord, alg);
+ ibz_copy(&(prod->m[0][i]), &(p.v[0]));
+ ibz_copy(&(prod->m[1][i]), &(p.v[1]));
+ ibz_copy(&(prod->m[2][i]), &(p.v[2]));
+ ibz_copy(&(prod->m[3][i]), &(p.v[3]));
+ }
+ ibz_vec_4_finalize(&p);
+ ibz_vec_4_finalize(&a);
+}
+
+void
+quat_lattice_alg_elem_mul(quat_lattice_t *prod,
+ const quat_lattice_t *lat,
+ const quat_alg_elem_t *elem,
+ const quat_alg_t *alg)
+{
+ quat_lattice_mat_alg_coord_mul_without_hnf(&(prod->basis), &(lat->basis), &(elem->coord), alg);
+ ibz_mul(&(prod->denom), &(lat->denom), &(elem->denom));
+ quat_lattice_hnf(prod);
+}
+
+void
+quat_lattice_mul(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2, const quat_alg_t *alg)
+{
+ ibz_vec_4_t elem1, elem2, elem_res;
+ ibz_vec_4_t generators[16];
+ ibz_mat_4x4_t detmat;
+ ibz_t det;
+ quat_lattice_t lat_res;
+ ibz_init(&det);
+ ibz_mat_4x4_init(&detmat);
+ quat_lattice_init(&lat_res);
+ ibz_vec_4_init(&elem1);
+ ibz_vec_4_init(&elem2);
+ ibz_vec_4_init(&elem_res);
+ for (int i = 0; i < 16; i++)
+ ibz_vec_4_init(&(generators[i]));
+ for (int k = 0; k < 4; k++) {
+ ibz_vec_4_copy_ibz(
+ &elem1, &(lat1->basis.m[0][k]), &(lat1->basis.m[1][k]), &(lat1->basis.m[2][k]), &(lat1->basis.m[3][k]));
+ for (int i = 0; i < 4; i++) {
+ ibz_vec_4_copy_ibz(
+ &elem2, &(lat2->basis.m[0][i]), &(lat2->basis.m[1][i]), &(lat2->basis.m[2][i]), &(lat2->basis.m[3][i]));
+ quat_alg_coord_mul(&elem_res, &elem1, &elem2, alg);
+ for (int j = 0; j < 4; j++) {
+ if (k == 0)
+ ibz_copy(&(detmat.m[i][j]), &(elem_res.v[j]));
+ ibz_copy(&(generators[4 * k + i].v[j]), &(elem_res.v[j]));
+ }
+ }
+ }
+ ibz_mat_4x4_inv_with_det_as_denom(NULL, &det, &detmat);
+ ibz_abs(&det, &det);
+ ibz_mat_4xn_hnf_mod_core(&(res->basis), 16, generators, &det);
+ ibz_mul(&(res->denom), &(lat1->denom), &(lat2->denom));
+ quat_lattice_reduce_denom(res, res);
+ ibz_vec_4_finalize(&elem1);
+ ibz_vec_4_finalize(&elem2);
+ ibz_vec_4_finalize(&elem_res);
+ quat_lattice_finalize(&lat_res);
+ ibz_finalize(&det);
+ ibz_mat_4x4_finalize(&(detmat));
+ for (int i = 0; i < 16; i++)
+ ibz_vec_4_finalize(&(generators[i]));
+}
+
+// lattice assumed of full rank
+int
+quat_lattice_contains(ibz_vec_4_t *coord, const quat_lattice_t *lat, const quat_alg_elem_t *x)
+{
+ int divisible = 0;
+ ibz_vec_4_t work_coord;
+ ibz_mat_4x4_t inv;
+ ibz_t det, prod;
+ ibz_init(&prod);
+ ibz_init(&det);
+ ibz_vec_4_init(&work_coord);
+ ibz_mat_4x4_init(&inv);
+ ibz_mat_4x4_inv_with_det_as_denom(&inv, &det, &(lat->basis));
+ assert(!ibz_is_zero(&det));
+ ibz_mat_4x4_eval(&work_coord, &inv, &(x->coord));
+ ibz_vec_4_scalar_mul(&(work_coord), &(lat->denom), &work_coord);
+ ibz_mul(&prod, &(x->denom), &det);
+ divisible = ibz_vec_4_scalar_div(&work_coord, &prod, &work_coord);
+ // copy result
+ if (divisible && (coord != NULL)) {
+ for (int i = 0; i < 4; i++) {
+ ibz_copy(&(coord->v[i]), &(work_coord.v[i]));
+ }
+ }
+ ibz_finalize(&prod);
+ ibz_finalize(&det);
+ ibz_mat_4x4_finalize(&inv);
+ ibz_vec_4_finalize(&work_coord);
+ return (divisible);
+}
+
+void
+quat_lattice_index(ibz_t *index, const quat_lattice_t *sublat, const quat_lattice_t *overlat)
+{
+ ibz_t tmp, det;
+ ibz_init(&tmp);
+ ibz_init(&det);
+
+ // det = det(sublat->basis)
+ ibz_mat_4x4_inv_with_det_as_denom(NULL, &det, &sublat->basis);
+ // tmp = (overlat->denom)⁴
+ ibz_mul(&tmp, &overlat->denom, &overlat->denom);
+ ibz_mul(&tmp, &tmp, &tmp);
+ // index = (overlat->denom)⁴ · det(sublat->basis)
+ ibz_mul(index, &det, &tmp);
+ // tmp = (sublat->denom)⁴
+ ibz_mul(&tmp, &sublat->denom, &sublat->denom);
+ ibz_mul(&tmp, &tmp, &tmp);
+ // det = det(overlat->basis)
+ ibz_mat_4x4_inv_with_det_as_denom(NULL, &det, &overlat->basis);
+ // tmp = (sublat->denom)⁴ · det(overlat->basis)
+ ibz_mul(&tmp, &tmp, &det);
+ // index = index / tmp
+ ibz_div(index, &tmp, index, &tmp);
+ assert(ibz_is_zero(&tmp));
+ // index = |index|
+ ibz_abs(index, index);
+
+ ibz_finalize(&tmp);
+ ibz_finalize(&det);
+}
+
+void
+quat_lattice_hnf(quat_lattice_t *lat)
+{
+ ibz_t mod;
+ ibz_vec_4_t generators[4];
+ ibz_init(&mod);
+ ibz_mat_4x4_inv_with_det_as_denom(NULL, &mod, &(lat->basis));
+ ibz_abs(&mod, &mod);
+ for (int i = 0; i < 4; i++)
+ ibz_vec_4_init(&(generators[i]));
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibz_copy(&(generators[j].v[i]), &(lat->basis.m[i][j]));
+ }
+ }
+ ibz_mat_4xn_hnf_mod_core(&(lat->basis), 4, generators, &mod);
+ quat_lattice_reduce_denom(lat, lat);
+ ibz_finalize(&mod);
+ for (int i = 0; i < 4; i++)
+ ibz_vec_4_finalize(&(generators[i]));
+}
+
+void
+quat_lattice_gram(ibz_mat_4x4_t *G, const quat_lattice_t *lattice, const quat_alg_t *alg)
+{
+ ibz_t tmp;
+ ibz_init(&tmp);
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j <= i; j++) {
+ ibz_set(&G->m[i][j], 0);
+ for (int k = 0; k < 4; k++) {
+ ibz_mul(&tmp, &(lattice->basis.m)[k][i], &(lattice->basis.m)[k][j]);
+ if (k >= 2)
+ ibz_mul(&tmp, &tmp, &alg->p);
+ ibz_add(&G->m[i][j], &G->m[i][j], &tmp);
+ }
+ ibz_mul(&G->m[i][j], &G->m[i][j], &ibz_const_two);
+ }
+ }
+ for (int i = 0; i < 4; i++) {
+ for (int j = i + 1; j < 4; j++) {
+ ibz_copy(&G->m[i][j], &G->m[j][i]);
+ }
+ }
+ ibz_finalize(&tmp);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lll_applications.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lll_applications.c
new file mode 100644
index 0000000000..f5e9af922b
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lll_applications.c
@@ -0,0 +1,127 @@
+#include
+#include
+#include "lll_internals.h"
+
+void
+quat_lideal_reduce_basis(ibz_mat_4x4_t *reduced,
+ ibz_mat_4x4_t *gram,
+ const quat_left_ideal_t *lideal,
+ const quat_alg_t *alg)
+{
+ assert(quat_order_is_maximal((lideal->parent_order), alg));
+ ibz_t gram_corrector;
+ ibz_init(&gram_corrector);
+ ibz_mul(&gram_corrector, &(lideal->lattice.denom), &(lideal->lattice.denom));
+ quat_lideal_class_gram(gram, lideal, alg);
+ ibz_mat_4x4_copy(reduced, &(lideal->lattice.basis));
+ quat_lll_core(gram, reduced);
+ ibz_mat_4x4_scalar_mul(gram, &gram_corrector, gram);
+ for (int i = 0; i < 4; i++) {
+ ibz_div_2exp(&(gram->m[i][i]), &(gram->m[i][i]), 1);
+ for (int j = i + 1; j < 4; j++) {
+ ibz_set(&(gram->m[i][j]), 0);
+ }
+ }
+ ibz_finalize(&gram_corrector);
+}
+
+void
+quat_lideal_lideal_mul_reduced(quat_left_ideal_t *prod,
+ ibz_mat_4x4_t *gram,
+ const quat_left_ideal_t *lideal1,
+ const quat_left_ideal_t *lideal2,
+ const quat_alg_t *alg)
+{
+ ibz_mat_4x4_t red;
+ ibz_mat_4x4_init(&red);
+
+ quat_lattice_mul(&(prod->lattice), &(lideal1->lattice), &(lideal2->lattice), alg);
+ prod->parent_order = lideal1->parent_order;
+ quat_lideal_norm(prod);
+ quat_lideal_reduce_basis(&red, gram, prod, alg);
+ ibz_mat_4x4_copy(&(prod->lattice.basis), &red);
+
+ ibz_mat_4x4_finalize(&red);
+}
+
+int
+quat_lideal_prime_norm_reduced_equivalent(quat_left_ideal_t *lideal,
+ const quat_alg_t *alg,
+ const int primality_num_iter,
+ const int equiv_bound_coeff)
+{
+ ibz_mat_4x4_t gram, red;
+ ibz_mat_4x4_init(&gram);
+ ibz_mat_4x4_init(&red);
+
+ int found = 0;
+
+ // computing the reduced basis
+ quat_lideal_reduce_basis(&red, &gram, lideal, alg);
+
+ quat_alg_elem_t new_alpha;
+ quat_alg_elem_init(&new_alpha);
+ ibz_t tmp, remainder, adjusted_norm;
+ ibz_init(&tmp);
+ ibz_init(&remainder);
+ ibz_init(&adjusted_norm);
+
+ ibz_mul(&adjusted_norm, &lideal->lattice.denom, &lideal->lattice.denom);
+
+ int ctr = 0;
+
+ // equiv_num_iter = (2 * equiv_bound_coeff + 1)^4
+ assert(equiv_bound_coeff < (1 << 20));
+ int equiv_num_iter = (2 * equiv_bound_coeff + 1);
+ equiv_num_iter = equiv_num_iter * equiv_num_iter;
+ equiv_num_iter = equiv_num_iter * equiv_num_iter;
+
+ while (!found && ctr < equiv_num_iter) {
+ ctr++;
+ // we select our linear combination at random
+ ibz_rand_interval_minm_m(&new_alpha.coord.v[0], equiv_bound_coeff);
+ ibz_rand_interval_minm_m(&new_alpha.coord.v[1], equiv_bound_coeff);
+ ibz_rand_interval_minm_m(&new_alpha.coord.v[2], equiv_bound_coeff);
+ ibz_rand_interval_minm_m(&new_alpha.coord.v[3], equiv_bound_coeff);
+
+ // computation of the norm of the vector sampled
+ quat_qf_eval(&tmp, &gram, &new_alpha.coord);
+
+ // compute the norm of the equivalent ideal
+ // can be improved by removing the power of two first and the odd part only if the trial
+ // division failed (this should always be called on an ideal of norm 2^x * N for some
+ // big prime N )
+ ibz_div(&tmp, &remainder, &tmp, &adjusted_norm);
+
+ // debug : check that the remainder is zero
+ assert(ibz_is_zero(&remainder));
+
+ // pseudo-primality test
+ if (ibz_probab_prime(&tmp, primality_num_iter)) {
+
+ // computes the generator using a matrix multiplication
+ ibz_mat_4x4_eval(&new_alpha.coord, &red, &new_alpha.coord);
+ ibz_copy(&new_alpha.denom, &lideal->lattice.denom);
+ assert(quat_lattice_contains(NULL, &lideal->lattice, &new_alpha));
+
+ quat_alg_conj(&new_alpha, &new_alpha);
+ ibz_mul(&new_alpha.denom, &new_alpha.denom, &lideal->norm);
+ quat_lideal_mul(lideal, lideal, &new_alpha, alg);
+ assert(ibz_probab_prime(&lideal->norm, primality_num_iter));
+
+ found = 1;
+ break;
+ }
+ }
+ assert(found);
+
+ ibz_finalize(&tmp);
+ ibz_finalize(&remainder);
+ ibz_finalize(&adjusted_norm);
+ quat_alg_elem_finalize(&new_alpha);
+
+ ibz_mat_4x4_finalize(&gram);
+ ibz_mat_4x4_finalize(&red);
+
+ return found;
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lll_internals.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lll_internals.h
new file mode 100644
index 0000000000..2b76857205
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lll_internals.h
@@ -0,0 +1,244 @@
+#ifndef LLL_INTERNALS_H
+#define LLL_INTERNALS_H
+
+/** @file
+ *
+ * @authors Sina Schaeffler
+ *
+ * @brief Declarations of functions only used for the LLL tets
+ */
+
+#include
+
+/** @internal
+ * @ingroup quat_helpers
+ * @defgroup lll_internal Functions only used for LLL or its tests
+ * @{
+ */
+
+/** @internal
+ * @ingroup lll_internal
+ * @defgroup lll_params Parameters used by the L2 implementation (floats) and its tests (ints)
+ * @{
+ */
+
+#define DELTABAR 0.995
+#define DELTA_NUM 99
+#define DELTA_DENOM 100
+
+#define ETABAR 0.505
+#define EPSILON_NUM 1
+#define EPSILON_DENOM 100
+
+#define PREC 64
+/**
+ * @}
+ */
+
+/** @internal
+ * @ingroup lll_internal
+ * @defgroup ibq_t Types for rationals
+ * @{
+ */
+
+/** @brief Type for fractions of integers
+ *
+* @typedef ibq_t
+ *
+ * For fractions of integers of arbitrary size, used by intbig module, using gmp
+ */
+typedef struct {
+ ibz_t q[2];
+} ibq_t;
+typedef struct {
+ ibq_t v[4];
+} ibq_vec_4_t;
+typedef struct {
+ ibq_vec_4_t m[4];
+} ibq_mat_4x4_t;
+
+/**@}
+ */
+
+/** @internal
+ * @ingroup lll_internal
+ * @defgroup lll_ibq_c Constructors and Destructors and Printers
+ * @{
+ */
+
+void ibq_init(ibq_t *x);
+void ibq_finalize(ibq_t *x);
+
+void ibq_mat_4x4_init(ibq_mat_4x4_t *mat);
+void ibq_mat_4x4_finalize(ibq_mat_4x4_t *mat);
+
+void ibq_vec_4_init(ibq_vec_4_t *vec);
+void ibq_vec_4_finalize(ibq_vec_4_t *vec);
+
+void ibq_mat_4x4_print(const ibq_mat_4x4_t *mat);
+void ibq_vec_4_print(const ibq_vec_4_t *vec);
+
+/** @}
+ */
+
+/** @internal
+ * @ingroup lll_internal
+ * @defgroup lll_qa Basic fraction arithmetic
+ * @{
+ */
+
+/** @brief sum=a+b
+ */
+void ibq_add(ibq_t *sum, const ibq_t *a, const ibq_t *b);
+
+/** @brief diff=a-b
+ */
+void ibq_sub(ibq_t *diff, const ibq_t *a, const ibq_t *b);
+
+/** @brief neg=-x
+ */
+void ibq_neg(ibq_t *neg, const ibq_t *x);
+
+/** @brief abs=|x|
+ */
+void ibq_abs(ibq_t *abs, const ibq_t *x);
+
+/** @brief prod=a*b
+ */
+void ibq_mul(ibq_t *prod, const ibq_t *a, const ibq_t *b);
+
+/** @brief inv=1/x
+ *
+ * @returns 0 if x is 0, 1 if inverse exists and was computed
+ */
+int ibq_inv(ibq_t *inv, const ibq_t *x);
+
+/** @brief Compare a and b
+ *
+ * @returns a positive value if a > b, zero if a = b, and a negative value if a < b
+ */
+int ibq_cmp(const ibq_t *a, const ibq_t *b);
+
+/** @brief Test if x is 0
+ *
+ * @returns 1 if x=0, 0 otherwise
+ */
+int ibq_is_zero(const ibq_t *x);
+
+/** @brief Test if x is 1
+ *
+ * @returns 1 if x=1, 0 otherwise
+ */
+int ibq_is_one(const ibq_t *x);
+
+/** @brief Set q to a/b if b not 0
+ *
+ * @returns 1 if b not 0 and q is set, 0 otherwise
+ */
+int ibq_set(ibq_t *q, const ibz_t *a, const ibz_t *b);
+
+/** @brief Copy value into target
+ */
+void ibq_copy(ibq_t *target, const ibq_t *value);
+
+/** @brief Checks if q is an integer
+ *
+ * @returns 1 if yes, 0 if not
+ */
+int ibq_is_ibz(const ibq_t *q);
+
+/**
+ * @brief Converts a fraction q to an integer y, if q is an integer.
+ *
+ * @returns 1 if z is an integer, 0 if not
+ */
+int ibq_to_ibz(ibz_t *z, const ibq_t *q);
+/** @}
+ */
+
+/** @internal
+ * @ingroup lll_internal
+ * @defgroup quat_lll_verify_helpers Helper functions for lll verification in dimension 4
+ * @{
+ */
+
+/** @brief Set ibq to parameters delta and eta = 1/2 + epsilon using L2 constants
+ */
+void quat_lll_set_ibq_parameters(ibq_t *delta, ibq_t *eta);
+
+/** @brief Set an ibq vector to 4 given integer coefficients
+ */
+void ibq_vec_4_copy_ibz(ibq_vec_4_t *vec,
+ const ibz_t *coeff0,
+ const ibz_t *coeff1,
+ const ibz_t *coeff2,
+ const ibz_t *coeff3); // dim4, test/dim4
+
+/** @brief Bilinear form vec00*vec10+vec01*vec11+q*vec02*vec12+q*vec03*vec13 for ibz_q
+ */
+void quat_lll_bilinear(ibq_t *b, const ibq_vec_4_t *vec0, const ibq_vec_4_t *vec1,
+ const ibz_t *q); // dim4, test/dim4
+
+/** @brief Outputs the transposition of the orthogonalised matrix of mat (as fractions)
+ *
+ * For the bilinear form vec00*vec10+vec01*vec11+q*vec02*vec12+q*vec03*vec13
+ */
+void quat_lll_gram_schmidt_transposed_with_ibq(ibq_mat_4x4_t *orthogonalised_transposed,
+ const ibz_mat_4x4_t *mat,
+ const ibz_t *q); // dim4
+
+/** @brief Verifies if mat is lll-reduced for parameter coeff and norm defined by q
+ *
+ * For the bilinear form vec00*vec10+vec01*vec11+q*vec02*vec12+q*vec03*vec13
+ */
+int quat_lll_verify(const ibz_mat_4x4_t *mat,
+ const ibq_t *delta,
+ const ibq_t *eta,
+ const quat_alg_t *alg); // test/lattice, test/dim4
+ /** @}
+ */
+
+/** @internal
+ * @ingroup lll_internal
+ * @defgroup lll_internal_gram Internal LLL function
+ * @{
+ */
+
+/** @brief In-place L2 reduction core function
+ *
+ * Given a lattice basis represented by the columns of a 4x4 matrix
+ * and the Gram matrix of its bilinear form, L2-reduces the basis
+ * in-place and updates the Gram matrix accordingly.
+ *
+ * Implements the L2 Algorithm of Nguyen-Stehlé, also known as fplll:
+ * https://iacr.org/archive/eurocrypt2005/34940217/34940217.pdf
+ *
+ * Parameters are in lll/lll_internals.h
+ *
+ * @param G In/Output: Gram matrix of the lattice basis
+ * @param basis In/Output: lattice basis
+ */
+void quat_lll_core(ibz_mat_4x4_t *G, ibz_mat_4x4_t *basis);
+
+/**
+ * @brief LLL reduction on 4-dimensional lattice
+ *
+ * Implements the L2 Algorithm of Nguyen-Stehlé, also known as fplll:
+ * https://iacr.org/archive/eurocrypt2005/34940217/34940217.pdf
+ *
+ * Parameters are in lll/lll_internals.h
+ *
+ * @param red Output: LLL reduced basis
+ * @param lattice In/Output: lattice with 4-dimensional basis
+ * @param alg The quaternion algebra
+ */
+int quat_lattice_lll(ibz_mat_4x4_t *red, const quat_lattice_t *lattice, const quat_alg_t *alg);
+
+/**
+ * @}
+ */
+
+// end of lll_internal
+/** @}
+ */
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lvlx.cmake b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lvlx.cmake
new file mode 100644
index 0000000000..3ab2d2dc90
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/lvlx.cmake
@@ -0,0 +1,12 @@
+set(SOURCE_FILES_GF_${SVARIANT_UPPER}_BROADWELL
+ ${SOURCE_FILES_GF_SPECIFIC}
+ fp.c
+ ${LVLX_DIR}/fp2.c
+)
+
+add_library(${LIB_GF_${SVARIANT_UPPER}} STATIC ${SOURCE_FILES_GF_${SVARIANT_UPPER}_BROADWELL})
+target_include_directories(${LIB_GF_${SVARIANT_UPPER}} PRIVATE ${INC_COMMON} ${PROJECT_SOURCE_DIR}/src/precomp/ref/${SVARIANT_LOWER}/include ${INC_GF} ${INC_GF_${SVARIANT_UPPER}} include ${INC_PUBLIC})
+target_compile_options(${LIB_GF_${SVARIANT_UPPER}} PRIVATE ${C_OPT_FLAGS})
+target_compile_definitions(${LIB_GF_${SVARIANT_UPPER}} PUBLIC SQISIGN_VARIANT=${SVARIANT_LOWER})
+
+add_subdirectory(test)
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/mp.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/mp.c
new file mode 100644
index 0000000000..13714eee4a
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/mp.c
@@ -0,0 +1,359 @@
+#include
+#include
+#include
+#include
+#include
+
+// double-wide multiplication
+void
+MUL(digit_t *out, const digit_t a, const digit_t b)
+{
+#ifdef RADIX_32
+ uint64_t r = (uint64_t)a * b;
+ out[0] = r & 0xFFFFFFFFUL;
+ out[1] = r >> 32;
+
+#elif defined(RADIX_64) && defined(_MSC_VER)
+ uint64_t umul_hi;
+ out[0] = _umul128(a, b, &umul_hi);
+ out[1] = umul_hi;
+
+#elif defined(RADIX_64) && (defined(HAVE_UINT128) || defined(__SIZEOF_INT128__) || defined(__int128)) && !defined(C_PEDANTIC_MODE)
+ unsigned __int128 umul_tmp;
+ umul_tmp = (unsigned __int128)(a) * (unsigned __int128)(b);
+ out[0] = (uint64_t)umul_tmp;
+ out[1] = (uint64_t)(umul_tmp >> 64);
+
+#else
+ register digit_t al, ah, bl, bh, temp;
+ digit_t albl, albh, ahbl, ahbh, res1, res2, res3, carry;
+ digit_t mask_low = (digit_t)(-1) >> (sizeof(digit_t) * 4), mask_high = (digit_t)(-1) << (sizeof(digit_t) * 4);
+ al = a & mask_low; // Low part
+ ah = a >> (sizeof(digit_t) * 4); // High part
+ bl = b & mask_low;
+ bh = b >> (sizeof(digit_t) * 4);
+
+ albl = al * bl;
+ albh = al * bh;
+ ahbl = ah * bl;
+ ahbh = ah * bh;
+ out[0] = albl & mask_low; // out00
+
+ res1 = albl >> (sizeof(digit_t) * 4);
+ res2 = ahbl & mask_low;
+ res3 = albh & mask_low;
+ temp = res1 + res2 + res3;
+ carry = temp >> (sizeof(digit_t) * 4);
+ out[0] ^= temp << (sizeof(digit_t) * 4); // out01
+
+ res1 = ahbl >> (sizeof(digit_t) * 4);
+ res2 = albh >> (sizeof(digit_t) * 4);
+ res3 = ahbh & mask_low;
+ temp = res1 + res2 + res3 + carry;
+ out[1] = temp & mask_low; // out10
+ carry = temp & mask_high;
+ out[1] ^= (ahbh & mask_high) + carry; // out11
+
+#endif
+}
+
+void
+mp_add(digit_t *c, const digit_t *a, const digit_t *b, const unsigned int nwords)
+{ // Multiprecision addition
+ unsigned int i, carry = 0;
+
+ for (i = 0; i < nwords; i++) {
+ ADDC(c[i], carry, a[i], b[i], carry);
+ }
+}
+
+digit_t
+mp_shiftr(digit_t *x, const unsigned int shift, const unsigned int nwords)
+{ // Multiprecision right shift by 1...RADIX-1
+ digit_t bit_out = x[0] & 1;
+
+ for (unsigned int i = 0; i < nwords - 1; i++) {
+ SHIFTR(x[i + 1], x[i], shift, x[i], RADIX);
+ }
+ x[nwords - 1] >>= shift;
+ return bit_out;
+}
+
+void
+mp_shiftl(digit_t *x, const unsigned int shift, const unsigned int nwords)
+{ // Multiprecision left shift by 1...RADIX-1
+
+ for (int i = nwords - 1; i > 0; i--) {
+ SHIFTL(x[i], x[i - 1], shift, x[i], RADIX);
+ }
+ x[0] <<= shift;
+}
+
+void
+multiple_mp_shiftl(digit_t *x, const unsigned int shift, const unsigned int nwords)
+{
+ int t = shift;
+ while (t > RADIX - 1) {
+ mp_shiftl(x, RADIX - 1, nwords);
+ t = t - (RADIX - 1);
+ }
+ mp_shiftl(x, t, nwords);
+}
+
+// The below functions were taken from the EC module
+
+void
+mp_sub(digit_t *c, const digit_t *a, const digit_t *b, const unsigned int nwords)
+{ // Multiprecision subtraction, assuming a > b
+ unsigned int i, borrow = 0;
+
+ for (i = 0; i < nwords; i++) {
+ SUBC(c[i], borrow, a[i], b[i], borrow);
+ }
+}
+
+void
+select_ct(digit_t *c, const digit_t *a, const digit_t *b, const digit_t mask, const int nwords)
+{ // Select c <- a if mask = 0, select c <- b if mask = 1...1
+
+ for (int i = 0; i < nwords; i++) {
+ c[i] = ((a[i] ^ b[i]) & mask) ^ a[i];
+ }
+}
+
+void
+swap_ct(digit_t *a, digit_t *b, const digit_t option, const int nwords)
+{ // Swap entries
+ // If option = 0 then P <- P and Q <- Q, else if option = 0xFF...FF then a <- b and b <- a
+ digit_t temp;
+
+ for (int i = 0; i < nwords; i++) {
+ temp = option & (a[i] ^ b[i]);
+ a[i] = temp ^ a[i];
+ b[i] = temp ^ b[i];
+ }
+}
+
+int
+mp_compare(const digit_t *a, const digit_t *b, unsigned int nwords)
+{ // Multiprecision comparison, a=b? : (1) a>b, (0) a=b, (-1) a= 0; i--) {
+ if (a[i] > b[i])
+ return 1;
+ else if (a[i] < b[i])
+ return -1;
+ }
+ return 0;
+}
+
+bool
+mp_is_zero(const digit_t *a, unsigned int nwords)
+{ // Is a multiprecision element zero?
+ // Returns 1 (true) if a=0, 0 (false) otherwise
+ digit_t r = 0;
+
+ for (unsigned int i = 0; i < nwords; i++)
+ r |= a[i] ^ 0;
+
+ return (bool)is_digit_zero_ct(r);
+}
+
+void
+mp_mul2(digit_t *c, const digit_t *a, const digit_t *b)
+{ // Multiprecision multiplication fixed to two-digit operands
+ unsigned int carry = 0;
+ digit_t t0[2], t1[2], t2[2];
+
+ MUL(t0, a[0], b[0]);
+ MUL(t1, a[0], b[1]);
+ ADDC(t0[1], carry, t0[1], t1[0], carry);
+ ADDC(t1[1], carry, 0, t1[1], carry);
+ MUL(t2, a[1], b[1]);
+ ADDC(t2[0], carry, t2[0], t1[1], carry);
+ ADDC(t2[1], carry, 0, t2[1], carry);
+ c[0] = t0[0];
+ c[1] = t0[1];
+ c[2] = t2[0];
+ c[3] = t2[1];
+}
+
+void
+mp_print(const digit_t *a, size_t nwords)
+{
+ printf("0x");
+ for (size_t i = 0; i < nwords; i++) {
+#ifdef RADIX_32
+ printf("%08" PRIx32, a[nwords - i - 1]); // Print each word with 8 hex digits
+#elif defined(RADIX_64)
+ printf("%016" PRIx64, a[nwords - i - 1]); // Print each word with 16 hex digits
+#endif
+ }
+}
+
+void
+mp_copy(digit_t *b, const digit_t *a, size_t nwords)
+{
+ for (size_t i = 0; i < nwords; i++) {
+ b[i] = a[i];
+ }
+}
+
+void
+mp_mul(digit_t *c, const digit_t *a, const digit_t *b, size_t nwords)
+{
+ // Multiprecision multiplication, c = a*b, for nwords-digit inputs, with nwords-digit output
+ // explicitly does not use the higher half of c, as we do not need in our applications
+ digit_t carry, UV[2], t[nwords], cc[nwords];
+
+ for (size_t i = 0; i < nwords; i++) {
+ cc[i] = 0;
+ }
+
+ for (size_t i = 0; i < nwords; i++) {
+
+ MUL(t, a[i], b[0]);
+
+ for (size_t j = 1; j < nwords - 1; j++) {
+ MUL(UV, a[i], b[j]);
+ ADDC(t[j], carry, t[j], UV[0], 0);
+ t[j + 1] = UV[1] + carry;
+ }
+
+ int j = nwords - 1;
+ MUL(UV, a[i], b[j]);
+ ADDC(t[j], carry, t[j], UV[0], 0);
+
+ mp_add(&cc[i], &cc[i], t, nwords - i);
+ }
+
+ mp_copy(c, cc, nwords);
+}
+
+void
+mp_mod_2exp(digit_t *a, unsigned int e, unsigned int nwords)
+{ // Multiprecision modulo 2^e, with 0 <= a < 2^(e)
+ unsigned int i, q = e >> LOG2RADIX, r = e & (RADIX - 1);
+
+ if (q < nwords) {
+ a[q] &= ((digit_t)1 << r) - 1;
+
+ for (i = q + 1; i < nwords; i++) {
+ a[i] = 0;
+ }
+ }
+}
+
+void
+mp_neg(digit_t *a, unsigned int nwords)
+{ // negates a
+ for (size_t i = 0; i < nwords; i++) {
+ a[i] ^= -1;
+ }
+
+ a[0] += 1;
+}
+
+bool
+mp_is_one(const digit_t *x, unsigned int nwords)
+{ // returns true if x represents 1, and false otherwise
+ if (x[0] != 1) {
+ return false;
+ }
+
+ for (size_t i = 1; i < nwords; i++) {
+ if (x[i] != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void
+mp_inv_2e(digit_t *b, const digit_t *a, int e, unsigned int nwords)
+{ // Inversion modulo 2^e, using Newton's method and Hensel lifting
+ // we take the first power of 2 larger than e to use
+ // requires a to be odd, of course
+ // returns b such that a*b = 1 mod 2^e
+ assert((a[0] & 1) == 1);
+
+ digit_t x[nwords], y[nwords], aa[nwords], mp_one[nwords], tmp[nwords];
+ memset(x, 0, sizeof(x));
+ mp_copy(aa, a, nwords);
+
+ mp_one[0] = 1;
+ for (unsigned int i = 1; i < nwords; i++) {
+ mp_one[i] = 0;
+ }
+
+ int p = 1;
+ while ((1 << p) < e) {
+ p++;
+ }
+ p -= 2; // using k = 4 for initial inverse
+ int w = (1 << (p + 2));
+
+ mp_mod_2exp(aa, w, nwords);
+ mp_add(x, aa, aa, nwords);
+ mp_add(x, x, aa, nwords); // should be 3a
+ x[0] ^= (1 << 1); // so that x equals (3a)^2 xor 2
+ mp_mod_2exp(x, w, nwords); // now x*a = 1 mod 2^4, which we lift
+
+ mp_mul(tmp, aa, x, nwords);
+ mp_neg(tmp, nwords);
+ mp_add(y, mp_one, tmp, nwords);
+
+ // Hensel lifting for p rounds
+ for (int i = 0; i < p; i++) {
+ mp_add(tmp, mp_one, y, nwords);
+ mp_mul(x, x, tmp, nwords);
+ mp_mul(y, y, y, nwords);
+ }
+
+ mp_mod_2exp(x, w, nwords);
+ mp_copy(b, x, nwords);
+
+ // verify results
+ mp_mul(x, x, aa, nwords);
+ mp_mod_2exp(x, w, nwords);
+ assert(mp_is_one(x, nwords));
+}
+
+void
+mp_invert_matrix(digit_t *r1, digit_t *r2, digit_t *s1, digit_t *s2, int e, unsigned int nwords)
+{
+ // given a matrix ( ( a, b ), (c, d) ) of values mod 2^e
+ // returns the inverse matrix gamma ( (d, -b), (-c, a) )
+ // where gamma is the inverse of the determinant a*d - b*c
+ // assumes the matrix is invertible, otherwises, inversion of determinant fails
+
+ int p = 1;
+ while ((1 << p) < e) {
+ p++;
+ }
+ int w = (1 << (p));
+
+ digit_t det[nwords], tmp[nwords], resa[nwords], resb[nwords], resc[nwords], resd[nwords];
+ mp_mul(tmp, r1, s2, nwords);
+ mp_mul(det, r2, s1, nwords);
+ mp_sub(det, tmp, det, nwords);
+ mp_inv_2e(det, det, e, nwords);
+
+ mp_mul(resa, det, s2, nwords);
+ mp_mul(resb, det, r2, nwords);
+ mp_mul(resc, det, s1, nwords);
+ mp_mul(resd, det, r1, nwords);
+
+ mp_neg(resb, nwords);
+ mp_neg(resc, nwords);
+
+ mp_mod_2exp(resa, w, nwords);
+ mp_mod_2exp(resb, w, nwords);
+ mp_mod_2exp(resc, w, nwords);
+ mp_mod_2exp(resd, w, nwords);
+
+ mp_copy(r1, resa, nwords);
+ mp_copy(r2, resb, nwords);
+ mp_copy(s1, resc, nwords);
+ mp_copy(s2, resd, nwords);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/mp.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/mp.h
new file mode 100644
index 0000000000..b3733b520d
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/mp.h
@@ -0,0 +1,88 @@
+#ifndef MP_H
+#define MP_H
+
+#include
+#include
+#include
+
+// Functions taken from the GF module
+
+void mp_add(digit_t *c, const digit_t *a, const digit_t *b, const unsigned int nwords);
+digit_t mp_shiftr(digit_t *x, const unsigned int shift, const unsigned int nwords);
+void multiple_mp_shiftl(digit_t *x, const unsigned int shift, const unsigned int nwords);
+void mp_shiftl(digit_t *x, const unsigned int shift, const unsigned int nwords);
+void MUL(digit_t *out, const digit_t a, const digit_t b);
+
+// Functions taken from the EC module
+
+void mp_sub(digit_t *c, const digit_t *a, const digit_t *b, const unsigned int nwords);
+void select_ct(digit_t *c, const digit_t *a, const digit_t *b, const digit_t mask, const int nwords);
+void swap_ct(digit_t *a, digit_t *b, const digit_t option, const int nwords);
+int mp_compare(const digit_t *a, const digit_t *b, unsigned int nwords);
+bool mp_is_zero(const digit_t *a, unsigned int nwords);
+void mp_mul2(digit_t *c, const digit_t *a, const digit_t *b);
+
+// Further functions for multiprecision arithmetic
+void mp_print(const digit_t *a, size_t nwords);
+void mp_copy(digit_t *b, const digit_t *a, size_t nwords);
+void mp_neg(digit_t *a, unsigned int nwords);
+bool mp_is_one(const digit_t *x, unsigned int nwords);
+void mp_mul(digit_t *c, const digit_t *a, const digit_t *b, size_t nwords);
+void mp_mod_2exp(digit_t *a, unsigned int e, unsigned int nwords);
+void mp_inv_2e(digit_t *b, const digit_t *a, int e, unsigned int nwords);
+void mp_invert_matrix(digit_t *r1, digit_t *r2, digit_t *s1, digit_t *s2, int e, unsigned int nwords);
+
+#define mp_is_odd(x, nwords) (((nwords) != 0) & (int)(x)[0])
+#define mp_is_even(x, nwords) (!mp_is_odd(x, nwords))
+
+/********************** Constant-time unsigned comparisons ***********************/
+
+// The following functions return 1 (TRUE) if condition is true, 0 (FALSE) otherwise
+static inline unsigned int
+is_digit_nonzero_ct(digit_t x)
+{ // Is x != 0?
+ return (unsigned int)((x | (0 - x)) >> (RADIX - 1));
+}
+
+static inline unsigned int
+is_digit_zero_ct(digit_t x)
+{ // Is x = 0?
+ return (unsigned int)(1 ^ is_digit_nonzero_ct(x));
+}
+
+static inline unsigned int
+is_digit_lessthan_ct(digit_t x, digit_t y)
+{ // Is x < y?
+ return (unsigned int)((x ^ ((x ^ y) | ((x - y) ^ y))) >> (RADIX - 1));
+}
+
+/********************** Platform-independent macros for digit-size operations
+ * **********************/
+
+// Digit addition with carry
+#define ADDC(sumOut, carryOut, addend1, addend2, carryIn) \
+ { \
+ digit_t tempReg = (addend1) + (digit_t)(carryIn); \
+ (sumOut) = (addend2) + tempReg; \
+ (carryOut) = (is_digit_lessthan_ct(tempReg, (digit_t)(carryIn)) | is_digit_lessthan_ct((sumOut), tempReg)); \
+ }
+
+// Digit subtraction with borrow
+#define SUBC(differenceOut, borrowOut, minuend, subtrahend, borrowIn) \
+ { \
+ digit_t tempReg = (minuend) - (subtrahend); \
+ unsigned int borrowReg = \
+ (is_digit_lessthan_ct((minuend), (subtrahend)) | ((borrowIn) & is_digit_zero_ct(tempReg))); \
+ (differenceOut) = tempReg - (digit_t)(borrowIn); \
+ (borrowOut) = borrowReg; \
+ }
+
+// Shift right with flexible datatype
+#define SHIFTR(highIn, lowIn, shift, shiftOut, DigitSize) \
+ (shiftOut) = ((lowIn) >> (shift)) ^ ((highIn) << (DigitSize - (shift)));
+
+// Digit shift left
+#define SHIFTL(highIn, lowIn, shift, shiftOut, DigitSize) \
+ (shiftOut) = ((highIn) << (shift)) ^ ((lowIn) >> (RADIX - (shift)));
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/normeq.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/normeq.c
new file mode 100644
index 0000000000..aadbbe06c7
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/normeq.c
@@ -0,0 +1,369 @@
+#include
+#include "internal.h"
+
+/** @file
+ *
+ * @authors Antonin Leroux
+ *
+ * @brief Functions related to norm equation solving or special extremal orders
+ */
+
+void
+quat_lattice_O0_set(quat_lattice_t *O0)
+{
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibz_set(&(O0->basis.m[i][j]), 0);
+ }
+ }
+ ibz_set(&(O0->denom), 2);
+ ibz_set(&(O0->basis.m[0][0]), 2);
+ ibz_set(&(O0->basis.m[1][1]), 2);
+ ibz_set(&(O0->basis.m[2][2]), 1);
+ ibz_set(&(O0->basis.m[1][2]), 1);
+ ibz_set(&(O0->basis.m[3][3]), 1);
+ ibz_set(&(O0->basis.m[0][3]), 1);
+}
+
+void
+quat_lattice_O0_set_extremal(quat_p_extremal_maximal_order_t *O0)
+{
+ ibz_set(&O0->z.coord.v[1], 1);
+ ibz_set(&O0->t.coord.v[2], 1);
+ ibz_set(&O0->z.denom, 1);
+ ibz_set(&O0->t.denom, 1);
+ O0->q = 1;
+ quat_lattice_O0_set(&(O0->order));
+}
+
+void
+quat_order_elem_create(quat_alg_elem_t *elem,
+ const quat_p_extremal_maximal_order_t *order,
+ const ibz_vec_4_t *coeffs,
+ const quat_alg_t *Bpoo)
+{
+
+ // var dec
+ quat_alg_elem_t quat_temp;
+
+ // var init
+ quat_alg_elem_init(&quat_temp);
+
+ // elem = x
+ quat_alg_scalar(elem, &coeffs->v[0], &ibz_const_one);
+
+ // quat_temp = i*y
+ quat_alg_scalar(&quat_temp, &(coeffs->v[1]), &ibz_const_one);
+ quat_alg_mul(&quat_temp, &order->z, &quat_temp, Bpoo);
+
+ // elem = x + i*y
+ quat_alg_add(elem, elem, &quat_temp);
+
+ // quat_temp = z * j
+ quat_alg_scalar(&quat_temp, &coeffs->v[2], &ibz_const_one);
+ quat_alg_mul(&quat_temp, &order->t, &quat_temp, Bpoo);
+
+ // elem = x + i* + z*j
+ quat_alg_add(elem, elem, &quat_temp);
+
+ // quat_temp = t * j * i
+ quat_alg_scalar(&quat_temp, &coeffs->v[3], &ibz_const_one);
+ quat_alg_mul(&quat_temp, &order->t, &quat_temp, Bpoo);
+ quat_alg_mul(&quat_temp, &quat_temp, &order->z, Bpoo);
+
+ // elem = x + i*y + j*z + j*i*t
+ quat_alg_add(elem, elem, &quat_temp);
+
+ quat_alg_elem_finalize(&quat_temp);
+}
+
+int
+quat_represent_integer(quat_alg_elem_t *gamma,
+ const ibz_t *n_gamma,
+ int non_diag,
+ const quat_represent_integer_params_t *params)
+{
+
+ if (ibz_is_even(n_gamma)) {
+ return 0;
+ }
+ // var dec
+ int found;
+ ibz_t cornacchia_target;
+ ibz_t adjusted_n_gamma, q;
+ ibz_t bound, sq_bound, temp;
+ ibz_t test;
+ ibz_vec_4_t coeffs; // coeffs = [x,y,z,t]
+ quat_alg_elem_t quat_temp;
+
+ if (non_diag)
+ assert(params->order->q % 4 == 1);
+
+ // var init
+ found = 0;
+ ibz_init(&bound);
+ ibz_init(&test);
+ ibz_init(&temp);
+ ibz_init(&q);
+ ibz_init(&sq_bound);
+ ibz_vec_4_init(&coeffs);
+ quat_alg_elem_init(&quat_temp);
+ ibz_init(&adjusted_n_gamma);
+ ibz_init(&cornacchia_target);
+
+ ibz_set(&q, params->order->q);
+
+ // this could be removed in the current state
+ int standard_order = (params->order->q == 1);
+
+ // adjusting the norm of gamma (multiplying by 4 to find a solution in an order of odd level)
+ if (non_diag || standard_order) {
+ ibz_mul(&adjusted_n_gamma, n_gamma, &ibz_const_two);
+ ibz_mul(&adjusted_n_gamma, &adjusted_n_gamma, &ibz_const_two);
+ } else {
+ ibz_copy(&adjusted_n_gamma, n_gamma);
+ }
+ // computation of the first bound = sqrt (adjust_n_gamma / p - q)
+ ibz_div(&sq_bound, &bound, &adjusted_n_gamma, &((params->algebra)->p));
+ ibz_set(&temp, params->order->q);
+ ibz_sub(&sq_bound, &sq_bound, &temp);
+ ibz_sqrt_floor(&bound, &sq_bound);
+
+ // the size of the search space is roughly n_gamma / (p√q)
+ ibz_t counter;
+ ibz_init(&counter);
+ ibz_mul(&temp, &temp, &((params->algebra)->p));
+ ibz_mul(&temp, &temp, &((params->algebra)->p));
+ ibz_sqrt_floor(&temp, &temp);
+ ibz_div(&counter, &temp, &adjusted_n_gamma, &temp);
+
+ // entering the main loop
+ while (!found && ibz_cmp(&counter, &ibz_const_zero) != 0) {
+ // decreasing the counter
+ ibz_sub(&counter, &counter, &ibz_const_one);
+
+ // we start by sampling the first coordinate
+ ibz_rand_interval(&coeffs.v[2], &ibz_const_one, &bound);
+
+ // then, we sample the second coordinate
+ // computing the second bound in temp as sqrt( (adjust_n_gamma - p*coeffs[2]²)/qp )
+ ibz_mul(&cornacchia_target, &coeffs.v[2], &coeffs.v[2]);
+ ibz_mul(&temp, &cornacchia_target, &(params->algebra->p));
+ ibz_sub(&temp, &adjusted_n_gamma, &temp);
+ ibz_mul(&sq_bound, &q, &(params->algebra->p));
+ ibz_div(&temp, &sq_bound, &temp, &sq_bound);
+ ibz_sqrt_floor(&temp, &temp);
+
+ if (ibz_cmp(&temp, &ibz_const_zero) == 0) {
+ continue;
+ }
+ // sampling the second value
+ ibz_rand_interval(&coeffs.v[3], &ibz_const_one, &temp);
+
+ // compute cornacchia_target = n_gamma - p * (z² + q*t²)
+ ibz_mul(&temp, &coeffs.v[3], &coeffs.v[3]);
+ ibz_mul(&temp, &q, &temp);
+ ibz_add(&cornacchia_target, &cornacchia_target, &temp);
+ ibz_mul(&cornacchia_target, &cornacchia_target, &((params->algebra)->p));
+ ibz_sub(&cornacchia_target, &adjusted_n_gamma, &cornacchia_target);
+ assert(ibz_cmp(&cornacchia_target, &ibz_const_zero) > 0);
+
+ // applying cornacchia
+ if (ibz_probab_prime(&cornacchia_target, params->primality_test_iterations))
+ found = ibz_cornacchia_prime(&(coeffs.v[0]), &(coeffs.v[1]), &q, &cornacchia_target);
+ else
+ found = 0;
+
+ if (found && non_diag && standard_order) {
+ // check that we can divide by two at least once
+ // the treatmeat depends if the basis contains (1+j)/2 or (1+k)/2
+ // we must have x = t mod 2 and y = z mod 2
+ // if q=1 we can simply swap x and y
+ if (ibz_is_odd(&coeffs.v[0]) != ibz_is_odd(&coeffs.v[3])) {
+ ibz_swap(&coeffs.v[1], &coeffs.v[0]);
+ }
+ // we further check that (x-t)/2 = 1 mod 2 and (y-z)/2 = 1 mod 2 to ensure that the
+ // resulting endomorphism will behave well for dim 2 computations
+ found = found && ((ibz_get(&coeffs.v[0]) - ibz_get(&coeffs.v[3])) % 4 == 2) &&
+ ((ibz_get(&coeffs.v[1]) - ibz_get(&coeffs.v[2])) % 4 == 2);
+ }
+ if (found) {
+
+#ifndef NDEBUG
+ ibz_set(&temp, (params->order->q));
+ ibz_mul(&temp, &temp, &(coeffs.v[1]));
+ ibz_mul(&temp, &temp, &(coeffs.v[1]));
+ ibz_mul(&test, &(coeffs.v[0]), &(coeffs.v[0]));
+ ibz_add(&temp, &temp, &test);
+ assert(0 == ibz_cmp(&temp, &cornacchia_target));
+
+ ibz_mul(&cornacchia_target, &(coeffs.v[3]), &(coeffs.v[3]));
+ ibz_mul(&cornacchia_target, &cornacchia_target, &(params->algebra->p));
+ ibz_mul(&temp, &(coeffs.v[1]), &(coeffs.v[1]));
+ ibz_add(&cornacchia_target, &cornacchia_target, &temp);
+ ibz_set(&temp, (params->order->q));
+ ibz_mul(&cornacchia_target, &cornacchia_target, &temp);
+ ibz_mul(&temp, &(coeffs.v[0]), &coeffs.v[0]);
+ ibz_add(&cornacchia_target, &cornacchia_target, &temp);
+ ibz_mul(&temp, &(coeffs.v[2]), &coeffs.v[2]);
+ ibz_mul(&temp, &temp, &(params->algebra->p));
+ ibz_add(&cornacchia_target, &cornacchia_target, &temp);
+ assert(0 == ibz_cmp(&cornacchia_target, &adjusted_n_gamma));
+#endif
+ // translate x,y,z,t into the quaternion element gamma
+ quat_order_elem_create(gamma, (params->order), &coeffs, (params->algebra));
+#ifndef NDEBUG
+ quat_alg_norm(&temp, &(coeffs.v[0]), gamma, (params->algebra));
+ assert(ibz_is_one(&(coeffs.v[0])));
+ assert(0 == ibz_cmp(&temp, &adjusted_n_gamma));
+ assert(quat_lattice_contains(NULL, &((params->order)->order), gamma));
+#endif
+ // making gamma primitive
+ // coeffs contains the coefficients of primitivized gamma in the basis of order
+ quat_alg_make_primitive(&coeffs, &temp, gamma, &((params->order)->order));
+
+ if (non_diag || standard_order)
+ found = (ibz_cmp(&temp, &ibz_const_two) == 0);
+ else
+ found = (ibz_cmp(&temp, &ibz_const_one) == 0);
+ }
+ }
+
+ if (found) {
+ // new gamma
+ ibz_mat_4x4_eval(&coeffs, &(((params->order)->order).basis), &coeffs);
+ ibz_copy(&gamma->coord.v[0], &coeffs.v[0]);
+ ibz_copy(&gamma->coord.v[1], &coeffs.v[1]);
+ ibz_copy(&gamma->coord.v[2], &coeffs.v[2]);
+ ibz_copy(&gamma->coord.v[3], &coeffs.v[3]);
+ ibz_copy(&gamma->denom, &(((params->order)->order).denom));
+ }
+ // var finalize
+ ibz_finalize(&counter);
+ ibz_finalize(&bound);
+ ibz_finalize(&temp);
+ ibz_finalize(&sq_bound);
+ ibz_vec_4_finalize(&coeffs);
+ quat_alg_elem_finalize(&quat_temp);
+ ibz_finalize(&adjusted_n_gamma);
+ ibz_finalize(&cornacchia_target);
+ ibz_finalize(&q);
+ ibz_finalize(&test);
+
+ return found;
+}
+
+int
+quat_sampling_random_ideal_O0_given_norm(quat_left_ideal_t *lideal,
+ const ibz_t *norm,
+ int is_prime,
+ const quat_represent_integer_params_t *params,
+ const ibz_t *prime_cofactor)
+{
+
+ ibz_t n_temp, norm_d;
+ ibz_t disc;
+ quat_alg_elem_t gen, gen_rerand;
+ int found = 0;
+ ibz_init(&n_temp);
+ ibz_init(&norm_d);
+ ibz_init(&disc);
+ quat_alg_elem_init(&gen);
+ quat_alg_elem_init(&gen_rerand);
+
+ // when the norm is prime we can be quite efficient
+ // by avoiding to run represent integer
+ // the first step is to generate one ideal of the correct norm
+ if (is_prime) {
+
+ // we find a quaternion element of norm divisible by norm
+ while (!found) {
+ // generating a trace-zero element at random
+ ibz_set(&gen.coord.v[0], 0);
+ ibz_sub(&n_temp, norm, &ibz_const_one);
+ for (int i = 1; i < 4; i++)
+ ibz_rand_interval(&gen.coord.v[i], &ibz_const_zero, &n_temp);
+
+ // first, we compute the norm of the gen
+ quat_alg_norm(&n_temp, &norm_d, &gen, (params->algebra));
+ assert(ibz_is_one(&norm_d));
+
+ // and finally the negation mod norm
+ ibz_neg(&disc, &n_temp);
+ ibz_mod(&disc, &disc, norm);
+ // now we check that -n is a square mod norm
+ // and if the square root exists we compute it
+ found = ibz_sqrt_mod_p(&gen.coord.v[0], &disc, norm);
+ found = found && !quat_alg_elem_is_zero(&gen);
+ }
+ } else {
+ assert(prime_cofactor != NULL);
+ // if it is not prime or we don't know if it is prime, we may just use represent integer
+ // and use a precomputed prime as cofactor
+ assert(!ibz_is_zero(norm));
+ ibz_mul(&n_temp, prime_cofactor, norm);
+ found = quat_represent_integer(&gen, &n_temp, 0, params);
+ found = found && !quat_alg_elem_is_zero(&gen);
+ }
+#ifndef NDEBUG
+ if (found) {
+ // first, we compute the norm of the gen
+ quat_alg_norm(&n_temp, &norm_d, &gen, (params->algebra));
+ assert(ibz_is_one(&norm_d));
+ ibz_mod(&n_temp, &n_temp, norm);
+ assert(ibz_cmp(&n_temp, &ibz_const_zero) == 0);
+ }
+#endif
+
+ // now we just have to rerandomize the class of the ideal generated by gen
+ found = 0;
+ while (!found) {
+ for (int i = 0; i < 4; i++) {
+ ibz_rand_interval(&gen_rerand.coord.v[i], &ibz_const_one, norm);
+ }
+ quat_alg_norm(&n_temp, &norm_d, &gen_rerand, (params->algebra));
+ assert(ibz_is_one(&norm_d));
+ ibz_gcd(&disc, &n_temp, norm);
+ found = ibz_is_one(&disc);
+ found = found && !quat_alg_elem_is_zero(&gen_rerand);
+ }
+
+ quat_alg_mul(&gen, &gen, &gen_rerand, (params->algebra));
+ // in both cases, whether norm is prime or not prime,
+ // gen is not divisible by any integer factor of the target norm
+ // therefore the call below will yield an ideal of the correct norm
+ quat_lideal_create(lideal, &gen, norm, &((params->order)->order), (params->algebra));
+ assert(ibz_cmp(norm, &(lideal->norm)) == 0);
+
+ ibz_finalize(&n_temp);
+ quat_alg_elem_finalize(&gen);
+ quat_alg_elem_finalize(&gen_rerand);
+ ibz_finalize(&norm_d);
+ ibz_finalize(&disc);
+ return (found);
+}
+
+void
+quat_change_to_O0_basis(ibz_vec_4_t *vec, const quat_alg_elem_t *el)
+{
+ ibz_t tmp;
+ ibz_init(&tmp);
+ ibz_copy(&vec->v[2], &el->coord.v[2]);
+ ibz_add(&vec->v[2], &vec->v[2], &vec->v[2]); // double (not optimal if el->denom is even...)
+ ibz_copy(&vec->v[3], &el->coord.v[3]); // double (not optimal if el->denom is even...)
+ ibz_add(&vec->v[3], &vec->v[3], &vec->v[3]);
+ ibz_sub(&vec->v[0], &el->coord.v[0], &el->coord.v[3]);
+ ibz_sub(&vec->v[1], &el->coord.v[1], &el->coord.v[2]);
+
+ assert(ibz_divides(&vec->v[0], &el->denom));
+ assert(ibz_divides(&vec->v[1], &el->denom));
+ assert(ibz_divides(&vec->v[2], &el->denom));
+ assert(ibz_divides(&vec->v[3], &el->denom));
+
+ ibz_div(&vec->v[0], &tmp, &vec->v[0], &el->denom);
+ ibz_div(&vec->v[1], &tmp, &vec->v[1], &el->denom);
+ ibz_div(&vec->v[2], &tmp, &vec->v[2], &el->denom);
+ ibz_div(&vec->v[3], &tmp, &vec->v[3], &el->denom);
+
+ ibz_finalize(&tmp);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion.h
new file mode 100644
index 0000000000..2dd70a8c19
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion.h
@@ -0,0 +1,716 @@
+/** @file
+ *
+ * @authors Luca De Feo, Sina Schaeffler
+ *
+ * @brief Declarations for quaternion algebra operations
+ */
+
+#ifndef QUATERNION_H
+#define QUATERNION_H
+
+// #include
+#include
+#include "intbig.h"
+#include
+
+/** @defgroup quat_quat Quaternion algebra
+ * @{
+ */
+
+/** @defgroup quat_vec_t Types for integer vectors and matrices
+ * @{
+ */
+
+/** @brief Type for vector of 2 big integers
+ *
+ * @typedef ibz_vec_2_t
+ */
+typedef struct {
+ ibz_t v[2];
+} ibz_vec_2_t;
+
+/** @brief Type for vectors of 4 integers
+ *
+ * @typedef ibz_vec_4_t
+ *
+ * Represented as a vector of 4 ibz_t (big integer) elements
+ */
+typedef struct {
+ ibz_t v[4];
+} ibz_vec_4_t;
+
+/** @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 struct {
+ ibz_t m[2][2];
+} ibz_mat_2x2_t;
+
+/** @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 struct {
+ ibz_t m[4][4];
+} ibz_mat_4x4_t;
+/**
+ * @}
+ */
+
+/** @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.
+} quat_alg_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)
+ ibz_vec_4_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 such that 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 (its columns divided by denom are
+ ///< algebra elements in the usual basis)
+} quat_lattice_t;
+
+/** @brief Type for left ideals of maximal orders in quaternion algebras
+ *
+ * @typedef quat_left_ideal_t
+ *
+ * @struct quat_left_ideal
+ *
+ * The basis of the lattice representing it is such that 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_lattice_t *parent_order; ///< should be a maximal order
+} 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,z,t,
+tz) where z^2 = -q, t^2 = -p.
+*/
+typedef struct quat_p_extremal_maximal_order
+{
+ quat_lattice_t order; ///< the order represented as a lattice
+ quat_alg_elem_t z; ///< the element of small discriminant
+ quat_alg_elem_t t; ///< the element of norm p orthogonal to z
+ uint32_t q; ///< the absolute value of the square of z
+} quat_p_extremal_maximal_order_t;
+
+/** @brief Type for represent integer parameters
+ *
+ * @typedef quat_p_extremal_maximal_order_t
+ *
+ * @struct quat_p_extremal_maximal_order
+ *
+ */
+typedef struct quat_represent_integer_params
+{
+ int primality_test_iterations; ///< Primality test iterations
+ const quat_p_extremal_maximal_order_t *order; ///< The standard extremal maximal order
+ const quat_alg_t *algebra; ///< The quaternion algebra
+} quat_represent_integer_params_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 ibz_vec_2_init(ibz_vec_2_t *vec);
+void ibz_vec_2_finalize(ibz_vec_2_t *vec);
+
+void ibz_vec_4_init(ibz_vec_4_t *vec);
+void ibz_vec_4_finalize(ibz_vec_4_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 quat_lattice_init(quat_lattice_t *lat);
+void quat_lattice_finalize(quat_lattice_t *lat);
+
+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_vec_2_print(const ibz_vec_2_t *vec);
+void ibz_vec_4_print(const ibz_vec_4_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_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 Copy matrix
+ *
+ * @param copy Output: Matrix into which copied will be copied
+ * @param copied
+ */
+void ibz_mat_2x2_copy(ibz_mat_2x2_t *copy, const ibz_mat_2x2_t *copied);
+
+/**
+ * @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_mat_2x2_inv_mod(ibz_mat_2x2_t *inv, const ibz_mat_2x2_t *mat, const ibz_t *m);
+
+/** @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 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); // dim4, lattice, test/dim4, ideal
+
+/** @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 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);
+
+/** @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 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 column 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 vec*mat
+ *
+ *
+ * @param res Output: coordinate vector.
+ * @param vec Integer vector (coordinate vector)
+ * @param mat Integer 4x4 matrix
+ *
+ * Multiplies 4x4 integer matrix mat by a 4-integers row vector vec (on the left)
+ */
+void ibz_mat_4x4_eval_t(ibz_vec_4_t *res, const ibz_vec_4_t *vec, const ibz_mat_4x4_t *mat);
+
+/** @}
+ */
+
+/** @defgroup quat_integer Higher-level integer functions for quaternion algebra
+ * @{
+ */
+
+/**
+ * @brief Generates a random prime
+ *
+ * A number is accepted as prime if it passes a 30-round Miller-Rabin test.
+ * This function is fairly inefficient and mostly meant for tests.
+ *
+ * @returns 1 if a prime is found, 0 otherwise
+ * @param p Output: The prime (if found)
+ * @param is3mod4 If 1, the prime is required to be 3 mod 4, if 0 no congruence condition is imposed
+ * @param bitsize Maximal size of output prime
+ * @param probability_test_iterations Miller-Rabin iteartions for probabilistic primality testing in
+ * rejection sampling
+ */
+int ibz_generate_random_prime(ibz_t *p, int is3mod4, int bitsize, int probability_test_iterations);
+
+/**
+ * @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);
+
+/** @}
+ */
+
+/** @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 ibz_vec_4_t *coord);
+/** @}
+ */
+
+/** @}
+ */
+
+/** @defgroup quat_quat_f Quaternion algebra functions
+ * @{
+ */
+/**
+ * @brief Copies an algebra element
+ *
+ * @param copy Output: The element into which another one is copied
+ * @param copied Source element copied into copy
+ */
+void quat_alg_elem_copy(quat_alg_elem_t *copy, const quat_alg_elem_t *copied);
+
+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_num Output: rational which will contain the numerator of the reduced norm of a
+ * @param res_denom Output: rational which will contain the denominator of the reduced norm of a (it
+ * is 1 if the norm is integer)
+ * @param x Algebra element whose norm is computed
+ * @param alg The quaternion algebra
+ */
+void quat_alg_norm(ibz_t *res_num, ibz_t *res_denom, const quat_alg_elem_t *x, const quat_alg_t *alg);
+
+/** @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 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 order order of `alg`
+ * @param x element of order, must be in `order`
+ */
+void quat_alg_make_primitive(ibz_vec_4_t *primitive_x,
+ ibz_t *content,
+ const quat_alg_elem_t *x,
+ const quat_lattice_t *order);
+
+// end quat_quat_f
+/** @}
+ */
+
+/** @defgroup quat_lat_f Lattice functions
+ * @{
+ */
+
+void quat_lattice_intersect(quat_lattice_t *res, const quat_lattice_t *lat1, const quat_lattice_t *lat2);
+
+/**
+ * @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, not necessarily in HNF but full rank
+ * @param x An element of the quaternion algebra
+ * @return true if x ∈ lat
+ */
+int quat_lattice_contains(ibz_vec_4_t *coord, const quat_lattice_t *lat, const quat_alg_elem_t *x);
+
+/**
+ * @brief Conjugate of a lattice with basis not in HNF
+ *
+ * @param conj Output: The lattice conjugate to lat. ATTENTION: is not under HNF
+ * @param lat Input lattice
+ */
+void quat_lattice_conjugate_without_hnf(quat_lattice_t *conj, const quat_lattice_t *lat);
+
+/**
+ * @brief Multiply a lattice and an algebra element
+ *
+ * The element is multiplied to the right of the lattice
+ *
+ * @param prod Output: Lattice lat*elem
+ * @param lat Input lattice
+ * @param elem Algebra element
+ * @param alg The quaternion algebra
+ */
+void quat_lattice_alg_elem_mul(quat_lattice_t *prod,
+ const quat_lattice_t *lat,
+ const quat_alg_elem_t *elem,
+ const quat_alg_t *alg); // ideal
+
+/**
+ * @brief Sample from the intersection of a lattice with a ball
+ *
+ * Sample a uniform non-zero vector of norm ≤ `radius` from the lattice.
+ *
+ * @param res Output: sampled quaternion from the lattice
+ * @param lattice Input lattice
+ * @param alg The quaternion algebra
+ * @param radius The ball radius (quaternion norm)
+ * @return 0 if an error occurred (ball too small or RNG error), 1 otherwise
+ */
+int quat_lattice_sample_from_ball(quat_alg_elem_t *res,
+ const quat_lattice_t *lattice,
+ const quat_alg_t *alg,
+ const ibz_t *radius);
+
+// end quat_lat_f
+/** @}
+ */
+
+/** @defgroup quat_lideal_f Functions for left ideals
+ * @{
+ */
+
+/** @defgroup quat_lideal_c Creating left ideals
+ * @{
+ */
+
+/**
+ * @brief Left ideal of order, generated by x and N as order*x+order*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 non-zero
+ * @param N generating integer
+ *
+ * Creates the left ideal in order generated by the element x and the integer N.
+ * If x is not divisible (inside the order) by any integer divisor n>1 of N,
+ * then the norm of the output ideal is N.
+ *
+ */
+void quat_lideal_create(quat_left_ideal_t *lideal,
+ const quat_alg_elem_t *x,
+ const ibz_t *N,
+ const quat_lattice_t *order,
+ const quat_alg_t *alg);
+
+/** @}
+ */
+
+/** @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
+ *
+ * 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);
+/** @}
+ */
+
+/** @defgroup quat_lideal_op Operations on left ideals
+ * @{
+ */
+
+/**
+ * @brief Copies an ideal
+ *
+ * @param copy Output: The ideal into which another one is copied
+ * @param copied Source ideal copied into copy. The parent order is not copied (only the pointer).
+ */
+void quat_lideal_copy(quat_left_ideal_t *copy, const quat_left_ideal_t *copied);
+
+/**
+ * @brief Conjugate of a left ideal (not in HNF)
+ *
+ * @param conj Output: Ideal conjugate to lideal, with norm and parent order correctly set, but its
+ * lattice not in HNF
+ * @param new_parent_order Output: Will be set to the right order of lideal, and serve as parent
+ * order for conj (so must have at least the lifetime of conj)
+ * @param lideal input left ideal (of which conj will be the conjugate)
+ * @param alg the quaternion algebra
+ */
+void quat_lideal_conjugate_without_hnf(quat_left_ideal_t *conj,
+ quat_lattice_t *new_parent_order,
+ const quat_left_ideal_t *lideal,
+ const quat_alg_t *alg);
+
+/**
+ * @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 L2-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.
+ *
+ * Implements the L2 Algorithm of Nguyen-Stehlé, also known as fplll:
+ * https://iacr.org/archive/eurocrypt2005/34940217/34940217.pdf
+ *
+ * Parameters are in lll/lll_internals.h
+ *
+ * @param 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: Matrix of the quadratic form given by the norm on the basis of the reduced
+ * ideal, divided by the norm of the ideal
+ * @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
+
+/**
+ * @brief Multplies two ideals and L2-reduces the lattice of the result
+ *
+ * Implements the L2 Algorithm of Nguyen-Stehlé, also known as fplll:
+ * https://iacr.org/archive/eurocrypt2005/34940217/34940217.pdf
+ *
+ * Parameters are in lll/lll_internals.h
+ *
+ * @param prod Output: The product ideal with its lattice basis being L2-reduced
+ * @param gram Output: Gram matrix of the reduced norm (as quadratic but not bilinear form) on the
+ * basis of prod, divided by the norm of prod
+ * @param lideal1 Ideal at left in the product
+ * @param lideal2 Ideal at right in the product
+ * @param alg The quaternion algebra
+ */
+void quat_lideal_lideal_mul_reduced(quat_left_ideal_t *prod,
+ ibz_mat_4x4_t *gram,
+ const quat_left_ideal_t *lideal1,
+ const quat_left_ideal_t *lideal2,
+ const quat_alg_t *alg);
+
+/**
+ * @brief Replaces an ideal by a smaller equivalent one of prime norm
+ *
+ * @returns 1 if the computation succeeded and 0 otherwise
+ * @param lideal In- and Output: Ideal to be replaced
+ * @param alg The quaternion algebra
+ * @param primality_num_iter number of repetition for primality testing
+ * @param equiv_bound_coeff bound on the coefficients for the candidates
+ */
+int quat_lideal_prime_norm_reduced_equivalent(quat_left_ideal_t *lideal,
+ const quat_alg_t *alg,
+ const int primality_num_iter,
+ const int equiv_bound_coeff);
+
+/** @}
+ */
+
+// end quat_lideal_f
+/** @}
+ */
+
+/** @defgroup quat_normeq Functions specific to special extremal maximal orders
+ * @{
+ */
+
+/**
+ * @brief Representing an integer by the quadratic norm form of a maximal extremal order
+ *
+ * @returns 1 if the computation succeeded
+ * @param gamma Output: a quaternion element
+ * @param n_gamma Target norm of gamma. n_gamma must be odd. If n_gamma/(p*params.order->q) <
+ * 2^QUAT_repres_bound_input failure is likely
+ * @param non_diag If set to 1 (instead of 0) and the order is O0, an additional property is ensured
+ * @param params Represent integer parameters specifying the algebra, the special extremal order,
+ * the number of trials for finding gamma and the number of iterations of the primality test.
+ * Special requirements apply if non-diag is set to 1
+ *
+ * This algorithm finds a primitive quaternion element gamma of n_gamma inside any maximal extremal
+ * order. Failure is possible. Most efficient for the standard order.
+ *
+ * If non-diag is set to 1,this algorithm finds a primitive quaternion element gamma with some
+ * special properties used in fixed degree isogeny of n_gamma inside any maximal extremal order such
+ * that params->order->q=1 mod 4. Failure is possible. Most efficient for the standard order. The
+ * most important property is to avoid diagonal isogenies, meaning that the gamma returned by the
+ * algorithm must not be contained inside ZZ + 2 O where O is the maximal order params->order When O
+ * is the special order O0 corresponding to j=1728, we further need to avoid endomorphisms of E0xE0
+ * and there is another requirement
+ *
+ * If non-diag is set to 1, the number of trials for finding gamma (in params), the number of
+ * iterations of the primality test and the value of params->order->q is required to be 1 mod 4
+ */
+int quat_represent_integer(quat_alg_elem_t *gamma,
+ const ibz_t *n_gamma,
+ int non_diag,
+ const quat_represent_integer_params_t *params);
+
+/** @brief Basis change to (1,i,(i+j)/2,(1+ij)/2) for elements of O0
+ *
+ * Change the basis in which an element is give from 1,i,j,ij to (1,i,(i+j)/2,(1+ij)/2) the ususal
+ * basis of the special maximal order O0 Only for elements of O0
+ *
+ * @param vec Output: Coordinates of el in basis (1,i,(i+j)/2,(1+ij)/2)
+ * @param el Imput: An algebra element in O0
+ */
+void quat_change_to_O0_basis(ibz_vec_4_t *vec, const quat_alg_elem_t *el);
+
+/**
+ * @brief Random O0-ideal of given norm
+ *
+ * Much faster if norm is prime and is_prime is set to 1
+ *
+ * @param lideal Output: O0-ideal of norm norm
+ * @param norm Norm of the ideal to be found
+ * @param is_prime Indicates if norm is prime: 1 if it is, 0 otherwise
+ * @param params Represent Integer parameters from the level-dependent constants
+ * @param prime_cofactor Prime distinct from the prime p defining the algebra but of similar size
+ * and coprime to norm. If is_prime is 1, it might be NULL.
+ * @returns 1 if success, 0 if no ideal found or randomness failed
+ */
+int quat_sampling_random_ideal_O0_given_norm(quat_left_ideal_t *lideal,
+ const ibz_t *norm,
+ int is_prime,
+ const quat_represent_integer_params_t *params,
+ const ibz_t *prime_cofactor);
+// end quat_normeq
+/** @}
+ */
+// end quat_quat
+/** @}
+ */
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion_constants.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion_constants.h
new file mode 100644
index 0000000000..5dca7d7cd4
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion_constants.h
@@ -0,0 +1,6 @@
+#include
+#define QUAT_primality_num_iter 32
+#define QUAT_repres_bound_input 20
+#define QUAT_equiv_bound_coeff 64
+#define FINDUV_box_size 2
+#define FINDUV_cube_size 624
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion_data.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion_data.c
new file mode 100644
index 0000000000..f9de8b4a4e
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion_data.c
@@ -0,0 +1,3176 @@
+#include
+#include
+#include
+const ibz_t QUAT_prime_cofactor =
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x41,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x41,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x41,0x0,0x0,0x800000000000000}}}}
+#endif
+;
+const quat_alg_t QUATALG_PINFTY = {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x4ff}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0x4ffffff}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xffffffffffffffff,0xffffffffffffffff,0xffffffffffffffff,0x4ffffffffffffff}}}}
+#endif
+};
+const quat_p_extremal_maximal_order_t EXTREMAL_ORDERS[7] = {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}, 1}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x10000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x0,0x1000000000000000}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x10000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x0,0x1000000000000000}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x8000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x0,0x800000000000000}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -16, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x80000000000000}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x8000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x0,0x800000000000000}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x0,0x0,0x0,0x10000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x0,0x1000000000000000}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}, 5}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x78d4,0x7b85,0x7a64,0xf5f2,0x29b9,0x3696,0x6101,0xb874}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7b8578d4,0xf5f27a64,0x369629b9,0xb8746101}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xf5f27a647b8578d4,0xb8746101369629b9}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x78d4,0x7b85,0x7a64,0xf5f2,0x29b9,0x3696,0x6101,0xb874}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7b8578d4,0xf5f27a64,0x369629b9,0xb8746101}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xf5f27a647b8578d4,0xb8746101369629b9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xbc6a,0x3dc2,0x3d32,0xfaf9,0x14dc,0x9b4b,0x3080,0x5c3a}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3dc2bc6a,0xfaf93d32,0x9b4b14dc,0x5c3a3080}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xfaf93d323dc2bc6a,0x5c3a30809b4b14dc}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 9, ._mp_d = (mp_limb_t[]) {0x7d47,0x6fa4,0x2ad5,0x95ad,0x8a4b,0x49be,0x77e7,0xc898,0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 5, ._mp_d = (mp_limb_t[]) {0x6fa47d47,0x95ad2ad5,0x49be8a4b,0xc89877e7,0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 3, ._mp_d = (mp_limb_t[]) {0x95ad2ad56fa47d47,0xc89877e749be8a4b,0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x3f47,0x7060,0x5e29,0x3e35,0xd950,0x2a1b,0x10ae,0x78dd,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x280}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x70603f47,0x3e355e29,0x2a1bd950,0x78dd10ae,0x0,0x0,0x0,0x2800000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3e355e2970603f47,0x78dd10ae2a1bd950,0x0,0x280000000000000}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xbc6a,0x3dc2,0x3d32,0xfaf9,0x14dc,0x9b4b,0x3080,0x5c3a}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3dc2bc6a,0xfaf93d32,0x9b4b14dc,0x5c3a3080}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xfaf93d323dc2bc6a,0x5c3a30809b4b14dc}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x11}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x11}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x11}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0x3fe7,0x28ee,0x26e8,0xb194,0x6d7a,0xaf58,0xe568,0xd6d}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0x28ee3fe7,0xb19426e8,0xaf586d7a,0xd6de568}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -2, ._mp_d = (mp_limb_t[]) {0xb19426e828ee3fe7,0xd6de568af586d7a}}}}
+#endif
+}}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x78d4,0x7b85,0x7a64,0xf5f2,0x29b9,0x3696,0x6101,0xb874}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7b8578d4,0xf5f27a64,0x369629b9,0xb8746101}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xf5f27a647b8578d4,0xb8746101369629b9}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 9, ._mp_d = (mp_limb_t[]) {0x7d47,0x6fa4,0x2ad5,0x95ad,0x8a4b,0x49be,0x77e7,0xc898,0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 5, ._mp_d = (mp_limb_t[]) {0x6fa47d47,0x95ad2ad5,0x49be8a4b,0xc89877e7,0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 3, ._mp_d = (mp_limb_t[]) {0x95ad2ad56fa47d47,0xc89877e749be8a4b,0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x11}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x11}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x11}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}, 17}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe5e2,0x7715,0xa8e6,0x3c6f,0x9078,0x872b,0x9bec,0x1794}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7715e5e2,0x3c6fa8e6,0x872b9078,0x17949bec}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x3c6fa8e67715e5e2,0x17949bec872b9078}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe5e2,0x7715,0xa8e6,0x3c6f,0x9078,0x872b,0x9bec,0x1794}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7715e5e2,0x3c6fa8e6,0x872b9078,0x17949bec}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x3c6fa8e67715e5e2,0x17949bec872b9078}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf2f1,0x3b8a,0xd473,0x1e37,0xc83c,0x4395,0x4df6,0xbca}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3b8af2f1,0x1e37d473,0x4395c83c,0xbca4df6}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x1e37d4733b8af2f1,0xbca4df64395c83c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0x307a,0x74c8,0x8082,0xb034,0x4e8a,0xc43a,0x399a,0x9ab}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0x74c8307a,0xb0348082,0xc43a4e8a,0x9ab399a}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -2, ._mp_d = (mp_limb_t[]) {0xb034808274c8307a,0x9ab399ac43a4e8a}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0x954f,0x6bc9,0xca46,0x3d25,0x431b,0x46ed,0x8229,0x4f5,0xe453,0x6eb3,0x4530,0xeb3e,0x5306,0xb3e4,0x306e,0x45}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x6bc9954f,0x3d25ca46,0x46ed431b,0x4f58229,0x6eb3e453,0xeb3e4530,0xb3e45306,0x45306e}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3d25ca466bc9954f,0x4f5822946ed431b,0xeb3e45306eb3e453,0x45306eb3e45306}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf2f1,0x3b8a,0xd473,0x1e37,0xc83c,0x4395,0x4df6,0xbca}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3b8af2f1,0x1e37d473,0x4395c83c,0xbca4df6}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x1e37d4733b8af2f1,0xbca4df64395c83c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe7f,0xca3a,0x2454,0xbd31,0xe562,0xcb4c,0x72f0,0x21}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xca3a0e7f,0xbd312454,0xcb4ce562,0x2172f0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xbd312454ca3a0e7f,0x2172f0cb4ce562}}}}
+#endif
+}}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe5e2,0x7715,0xa8e6,0x3c6f,0x9078,0x872b,0x9bec,0x1794}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7715e5e2,0x3c6fa8e6,0x872b9078,0x17949bec}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x3c6fa8e67715e5e2,0x17949bec872b9078}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0x307a,0x74c8,0x8082,0xb034,0x4e8a,0xc43a,0x399a,0x9ab}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0x74c8307a,0xb0348082,0xc43a4e8a,0x9ab399a}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -2, ._mp_d = (mp_limb_t[]) {0xb034808274c8307a,0x9ab399ac43a4e8a}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}, 37}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xafa2,0x6dee,0xc511,0xde33,0xc8ce,0xc89e,0x4f97,0x2df9}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x6deeafa2,0xde33c511,0xc89ec8ce,0x2df94f97}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xde33c5116deeafa2,0x2df94f97c89ec8ce}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xafa2,0x6dee,0xc511,0xde33,0xc8ce,0xc89e,0x4f97,0x2df9}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x6deeafa2,0xde33c511,0xc89ec8ce,0x2df94f97}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xde33c5116deeafa2,0x2df94f97c89ec8ce}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x57d1,0xb6f7,0xe288,0x6f19,0x6467,0xe44f,0xa7cb,0x16fc}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb6f757d1,0x6f19e288,0xe44f6467,0x16fca7cb}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x6f19e288b6f757d1,0x16fca7cbe44f6467}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xdd36,0xda6b,0xa943,0xd17a,0xe307,0x564c,0x4b0c,0x44d4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xda6bdd36,0xd17aa943,0x564ce307,0x44d44b0c}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xd17aa943da6bdd36,0x44d44b0c564ce307}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -16, ._mp_d = (mp_limb_t[]) {0x3a03,0xc406,0x47c,0xa0a2,0x6dbc,0x1df4,0x796,0x6cee,0xce0c,0xe0c7,0xc7c,0xc7ce,0x7ce0,0xce0c,0xe0c7,0x7c}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0xc4063a03,0xa0a2047c,0x1df46dbc,0x6cee0796,0xe0c7ce0c,0xc7ce0c7c,0xce0c7ce0,0x7ce0c7}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0xa0a2047cc4063a03,0x6cee07961df46dbc,0xc7ce0c7ce0c7ce0c,0x7ce0c7ce0c7ce0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x57d1,0xb6f7,0xe288,0x6f19,0x6467,0xe44f,0xa7cb,0x16fc}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb6f757d1,0x6f19e288,0xe44f6467,0x16fca7cb}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x6f19e288b6f757d1,0x16fca7cbe44f6467}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x8}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x8}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x8}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0x188f,0xa1e2,0x2148,0xd9f8,0x2e79,0x1a07,0xe1b2,0xd6}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0xa1e2188f,0xd9f82148,0x1a072e79,0xd6e1b2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -2, ._mp_d = (mp_limb_t[]) {0xd9f82148a1e2188f,0xd6e1b21a072e79}}}}
+#endif
+}}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xafa2,0x6dee,0xc511,0xde33,0xc8ce,0xc89e,0x4f97,0x2df9}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x6deeafa2,0xde33c511,0xc89ec8ce,0x2df94f97}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xde33c5116deeafa2,0x2df94f97c89ec8ce}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xdd36,0xda6b,0xa943,0xd17a,0xe307,0x564c,0x4b0c,0x44d4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xda6bdd36,0xd17aa943,0x564ce307,0x44d44b0c}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xd17aa943da6bdd36,0x44d44b0c564ce307}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x8}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x8}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x8}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}, 41}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 9, ._mp_d = (mp_limb_t[]) {0x96a4,0x25b,0x14f2,0x3800,0x4e7c,0x7958,0xab7f,0x7bbe,0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 5, ._mp_d = (mp_limb_t[]) {0x25b96a4,0x380014f2,0x79584e7c,0x7bbeab7f,0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 3, ._mp_d = (mp_limb_t[]) {0x380014f2025b96a4,0x7bbeab7f79584e7c,0x1}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 9, ._mp_d = (mp_limb_t[]) {0x96a4,0x25b,0x14f2,0x3800,0x4e7c,0x7958,0xab7f,0x7bbe,0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 5, ._mp_d = (mp_limb_t[]) {0x25b96a4,0x380014f2,0x79584e7c,0x7bbeab7f,0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 3, ._mp_d = (mp_limb_t[]) {0x380014f2025b96a4,0x7bbeab7f79584e7c,0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xcb52,0x12d,0xa79,0x1c00,0x273e,0xbcac,0x55bf,0xbddf}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x12dcb52,0x1c000a79,0xbcac273e,0xbddf55bf}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x1c000a79012dcb52,0xbddf55bfbcac273e}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -9, ._mp_d = (mp_limb_t[]) {0x73e3,0x3339,0x19e7,0x4ba1,0x6ebc,0x2702,0xee62,0xdbd0,0x7}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -5, ._mp_d = (mp_limb_t[]) {0x333973e3,0x4ba119e7,0x27026ebc,0xdbd0ee62,0x7}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -3, ._mp_d = (mp_limb_t[]) {0x4ba119e7333973e3,0xdbd0ee6227026ebc,0x7}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xca33,0x3dd0,0x1d92,0x9f0,0x2f81,0xafe9,0xe395,0x83f7,0xfffc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x27f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x3dd0ca33,0x9f01d92,0xafe92f81,0x83f7e395,0xfffffffc,0xffffffff,0xffffffff,0x27fffff}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x9f01d923dd0ca33,0x83f7e395afe92f81,0xfffffffffffffffc,0x27fffffffffffff}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xcb52,0x12d,0xa79,0x1c00,0x273e,0xbcac,0x55bf,0xbddf}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x12dcb52,0x1c000a79,0xbcac273e,0xbddf55bf}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x1c000a79012dcb52,0xbddf55bfbcac273e}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x35}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x35}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x35}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xeb73,0xf93c,0x71c0,0x87f5,0x667a,0xcb3c,0xb9cb,0x12fa}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xf93ceb73,0x87f571c0,0xcb3c667a,0x12fab9cb}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x87f571c0f93ceb73,0x12fab9cbcb3c667a}}}}
+#endif
+}}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 9, ._mp_d = (mp_limb_t[]) {0x96a4,0x25b,0x14f2,0x3800,0x4e7c,0x7958,0xab7f,0x7bbe,0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 5, ._mp_d = (mp_limb_t[]) {0x25b96a4,0x380014f2,0x79584e7c,0x7bbeab7f,0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 3, ._mp_d = (mp_limb_t[]) {0x380014f2025b96a4,0x7bbeab7f79584e7c,0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -9, ._mp_d = (mp_limb_t[]) {0x73e3,0x3339,0x19e7,0x4ba1,0x6ebc,0x2702,0xee62,0xdbd0,0x7}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -5, ._mp_d = (mp_limb_t[]) {0x333973e3,0x4ba119e7,0x27026ebc,0xdbd0ee62,0x7}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -3, ._mp_d = (mp_limb_t[]) {0x4ba119e7333973e3,0xdbd0ee6227026ebc,0x7}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x35}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x35}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x35}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}, 53}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 9, ._mp_d = (mp_limb_t[]) {0x7ffa,0x55af,0x7b9e,0xe2b9,0xa7af,0x578c,0xf76b,0xc227,0xf}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 5, ._mp_d = (mp_limb_t[]) {0x55af7ffa,0xe2b97b9e,0x578ca7af,0xc227f76b,0xf}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 3, ._mp_d = (mp_limb_t[]) {0xe2b97b9e55af7ffa,0xc227f76b578ca7af,0xf}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 9, ._mp_d = (mp_limb_t[]) {0x7ffa,0x55af,0x7b9e,0xe2b9,0xa7af,0x578c,0xf76b,0xc227,0xf}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 5, ._mp_d = (mp_limb_t[]) {0x55af7ffa,0xe2b97b9e,0x578ca7af,0xc227f76b,0xf}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 3, ._mp_d = (mp_limb_t[]) {0xe2b97b9e55af7ffa,0xc227f76b578ca7af,0xf}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 9, ._mp_d = (mp_limb_t[]) {0xbffd,0x2ad7,0xbdcf,0xf15c,0x53d7,0xabc6,0xfbb5,0xe113,0x7}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 5, ._mp_d = (mp_limb_t[]) {0x2ad7bffd,0xf15cbdcf,0xabc653d7,0xe113fbb5,0x7}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 3, ._mp_d = (mp_limb_t[]) {0xf15cbdcf2ad7bffd,0xe113fbb5abc653d7,0x7}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -9, ._mp_d = (mp_limb_t[]) {0xd16,0xf02b,0x1ce7,0xa2ef,0x54b,0x2c56,0x5963,0x667,0x6f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -5, ._mp_d = (mp_limb_t[]) {0xf02b0d16,0xa2ef1ce7,0x2c56054b,0x6675963,0x6f}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -3, ._mp_d = (mp_limb_t[]) {0xa2ef1ce7f02b0d16,0x66759632c56054b,0x6f}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 16, ._mp_d = (mp_limb_t[]) {0xf0ab,0x9d3b,0x6ea,0x84ac,0x62e5,0xdde9,0x882b,0xd021,0xffe2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x13ff}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x9d3bf0ab,0x84ac06ea,0xdde962e5,0xd021882b,0xffffffe2,0xffffffff,0xffffffff,0x13ffffff}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x84ac06ea9d3bf0ab,0xd021882bdde962e5,0xffffffffffffffe2,0x13ffffffffffffff}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 9, ._mp_d = (mp_limb_t[]) {0xbffd,0x2ad7,0xbdcf,0xf15c,0x53d7,0xabc6,0xfbb5,0xe113,0x7}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 5, ._mp_d = (mp_limb_t[]) {0x2ad7bffd,0xf15cbdcf,0xabc653d7,0xe113fbb5,0x7}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 3, ._mp_d = (mp_limb_t[]) {0xf15cbdcf2ad7bffd,0xe113fbb5abc653d7,0x7}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x308}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x308}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x308}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1f37,0x5c4a,0x13f1,0x770,0x7183,0x5600,0xda31,0x9281}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x5c4a1f37,0x77013f1,0x56007183,0x9281da31}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x77013f15c4a1f37,0x9281da3156007183}}}}
+#endif
+}}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 9, ._mp_d = (mp_limb_t[]) {0x7ffa,0x55af,0x7b9e,0xe2b9,0xa7af,0x578c,0xf76b,0xc227,0xf}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 5, ._mp_d = (mp_limb_t[]) {0x55af7ffa,0xe2b97b9e,0x578ca7af,0xc227f76b,0xf}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 3, ._mp_d = (mp_limb_t[]) {0xe2b97b9e55af7ffa,0xc227f76b578ca7af,0xf}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -9, ._mp_d = (mp_limb_t[]) {0xd16,0xf02b,0x1ce7,0xa2ef,0x54b,0x2c56,0x5963,0x667,0x6f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -5, ._mp_d = (mp_limb_t[]) {0xf02b0d16,0xa2ef1ce7,0x2c56054b,0x6675963,0x6f}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -3, ._mp_d = (mp_limb_t[]) {0xa2ef1ce7f02b0d16,0x66759632c56054b,0x6f}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x308}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x308}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x308}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}, 97}};
+const quat_left_ideal_t CONNECTING_IDEALS[7] = {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}}}},
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, &MAXORD_O0}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x6000}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x2,0x0,0x0,0x60000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x2,0x6000000000000000}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1000}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x1,0x0,0x0,0x10000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x1,0x1000000000000000}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x6000}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x2,0x0,0x0,0x60000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x2,0x6000000000000000}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x5000}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x1,0x0,0x0,0x50000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x1,0x5000000000000000}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}}}},
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x3000}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x1,0x0,0x0,0x30000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x1,0x3000000000000000}}}}
+#endif
+, &MAXORD_O0}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf5fe,0x8673,0x157b,0x7f90,0xd2c5,0xd00b,0xa646,0x78f4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x8673f5fe,0x7f90157b,0xd00bd2c5,0x78f4a646}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x7f90157b8673f5fe,0x78f4a646d00bd2c5}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xfee5,0x2b,0xd6d8,0xe65c,0x68a3,0xe72d,0x373d,0x5b1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x2bfee5,0xe65cd6d8,0xe72d68a3,0x5b1373d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xe65cd6d8002bfee5,0x5b1373de72d68a3}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf5fe,0x8673,0x157b,0x7f90,0xd2c5,0xd00b,0xa646,0x78f4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x8673f5fe,0x7f90157b,0xd00bd2c5,0x78f4a646}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x7f90157b8673f5fe,0x78f4a646d00bd2c5}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf719,0x8647,0x3ea3,0x9933,0x6a21,0xe8de,0x6f08,0x7343}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x8647f719,0x99333ea3,0xe8de6a21,0x73436f08}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x99333ea38647f719,0x73436f08e8de6a21}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}}}},
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xfaff,0xc339,0xabd,0xbfc8,0xe962,0x6805,0x5323,0x3c7a}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xc339faff,0xbfc80abd,0x6805e962,0x3c7a5323}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xbfc80abdc339faff,0x3c7a53236805e962}}}}
+#endif
+, &MAXORD_O0}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe5e2,0x7715,0xa8e6,0x3c6f,0x9078,0x872b,0x9bec,0x1794}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7715e5e2,0x3c6fa8e6,0x872b9078,0x17949bec}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x3c6fa8e67715e5e2,0x17949bec872b9078}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x8597,0x3af7,0xa5a,0xbb29,0x77c0,0xd2d9,0xf561,0x84f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3af78597,0xbb290a5a,0xd2d977c0,0x84ff561}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xbb290a5a3af78597,0x84ff561d2d977c0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xe5e2,0x7715,0xa8e6,0x3c6f,0x9078,0x872b,0x9bec,0x1794}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x7715e5e2,0x3c6fa8e6,0x872b9078,0x17949bec}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x3c6fa8e67715e5e2,0x17949bec872b9078}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x604b,0x3c1e,0x9e8c,0x8146,0x18b7,0xb452,0xa68a,0xf44}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3c1e604b,0x81469e8c,0xb45218b7,0xf44a68a}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x81469e8c3c1e604b,0xf44a68ab45218b7}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}}}},
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf2f1,0x3b8a,0xd473,0x1e37,0xc83c,0x4395,0x4df6,0xbca}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3b8af2f1,0x1e37d473,0x4395c83c,0xbca4df6}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x1e37d4733b8af2f1,0xbca4df64395c83c}}}}
+#endif
+, &MAXORD_O0}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xafa2,0x6dee,0xc511,0xde33,0xc8ce,0xc89e,0x4f97,0x2df9}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x6deeafa2,0xde33c511,0xc89ec8ce,0x2df94f97}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xde33c5116deeafa2,0x2df94f97c89ec8ce}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x519b,0xa90b,0xcdca,0xd5f5,0x757a,0x83dd,0xb354,0xe59}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xa90b519b,0xd5f5cdca,0x83dd757a,0xe59b354}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xd5f5cdcaa90b519b,0xe59b35483dd757a}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xafa2,0x6dee,0xc511,0xde33,0xc8ce,0xc89e,0x4f97,0x2df9}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x6deeafa2,0xde33c511,0xc89ec8ce,0x2df94f97}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xde33c5116deeafa2,0x2df94f97c89ec8ce}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x5e07,0xc4e3,0xf746,0x83d,0x5354,0x44c1,0x9c43,0x1f9f}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xc4e35e07,0x83df746,0x44c15354,0x1f9f9c43}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x83df746c4e35e07,0x1f9f9c4344c15354}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}}}},
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x57d1,0xb6f7,0xe288,0x6f19,0x6467,0xe44f,0xa7cb,0x16fc}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb6f757d1,0x6f19e288,0xe44f6467,0x16fca7cb}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x6f19e288b6f757d1,0x16fca7cbe44f6467}}}}
+#endif
+, &MAXORD_O0}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x19f2,0x5594,0xee77,0x52a2,0xf459,0x45c9,0x2187,0xb348}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x559419f2,0x52a2ee77,0x45c9f459,0xb3482187}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x52a2ee77559419f2,0xb348218745c9f459}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xdbd3,0x967a,0x8a96,0x1df4,0x7845,0xd70,0x419a,0x222}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x967adbd3,0x1df48a96,0xd707845,0x222419a}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x1df48a96967adbd3,0x222419a0d707845}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x19f2,0x5594,0xee77,0x52a2,0xf459,0x45c9,0x2187,0xb348}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x559419f2,0x52a2ee77,0x45c9f459,0xb3482187}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x52a2ee77559419f2,0xb348218745c9f459}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x3e1f,0xbf19,0x63e0,0x34ae,0x7c14,0x3859,0xdfed,0xb125}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xbf193e1f,0x34ae63e0,0x38597c14,0xb125dfed}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x34ae63e0bf193e1f,0xb125dfed38597c14}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}}}},
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xcf9,0xaaca,0x773b,0xa951,0xfa2c,0xa2e4,0x10c3,0x59a4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xaaca0cf9,0xa951773b,0xa2e4fa2c,0x59a410c3}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xa951773baaca0cf9,0x59a410c3a2e4fa2c}}}}
+#endif
+, &MAXORD_O0}, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xaa3a,0x67cf,0x6ad7,0xd031,0x701,0xebca,0xd852,0x2996}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x67cfaa3a,0xd0316ad7,0xebca0701,0x2996d852}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xd0316ad767cfaa3a,0x2996d852ebca0701}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x275,0xd7ab,0xedeb,0xbc67,0xad41,0xaeb5,0xf2e5,0x148e}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xd7ab0275,0xbc67edeb,0xaeb5ad41,0x148ef2e5}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xbc67edebd7ab0275,0x148ef2e5aeb5ad41}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xaa3a,0x67cf,0x6ad7,0xd031,0x701,0xebca,0xd852,0x2996}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x67cfaa3a,0xd0316ad7,0xebca0701,0x2996d852}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xd0316ad767cfaa3a,0x2996d852ebca0701}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xa7c5,0x9024,0x7ceb,0x13c9,0x59c0,0x3d14,0xe56d,0x1507}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x9024a7c5,0x13c97ceb,0x3d1459c0,0x1507e56d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x13c97ceb9024a7c5,0x1507e56d3d1459c0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}}}},
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xd51d,0xb3e7,0xb56b,0xe818,0x380,0x75e5,0x6c29,0x14cb}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb3e7d51d,0xe818b56b,0x75e50380,0x14cb6c29}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xe818b56bb3e7d51d,0x14cb6c2975e50380}}}}
+#endif
+, &MAXORD_O0}};
+const quat_alg_elem_t CONJUGATING_ELEMENTS[7] = {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1000}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x1,0x0,0x0,0x10000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x1,0x1000000000000000}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1000}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0x1,0x0,0x0,0x10000000}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -2, ._mp_d = (mp_limb_t[]) {0x1,0x1000000000000000}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf94f,0x85ef,0x90f3,0xcc79,0x98d9,0x1a83,0x8d,0x67e1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x85eff94f,0xcc7990f3,0x1a8398d9,0x67e1008d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xcc7990f385eff94f,0x67e1008d1a8398d9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0xf94f,0x85ef,0x90f3,0xcc79,0x98d9,0x1a83,0x8d,0x67e1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0x85eff94f,0xcc7990f3,0x1a8398d9,0x67e1008d}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -2, ._mp_d = (mp_limb_t[]) {0xcc7990f385eff94f,0x67e1008d1a8398d9}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x3}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x3}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x3}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x3}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x3}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x3}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0xf2f1,0x3b8a,0xd473,0x1e37,0xc83c,0x4395,0x4df6,0xbca}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x3b8af2f1,0x1e37d473,0x4395c83c,0xbca4df6}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x1e37d4733b8af2f1,0xbca4df64395c83c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0xf2f1,0x3b8a,0xd473,0x1e37,0xc83c,0x4395,0x4df6,0xbca}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0x3b8af2f1,0x1e37d473,0x4395c83c,0xbca4df6}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -2, ._mp_d = (mp_limb_t[]) {0x1e37d4733b8af2f1,0xbca4df64395c83c}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x57d1,0xb6f7,0xe288,0x6f19,0x6467,0xe44f,0xa7cb,0x16fc}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0xb6f757d1,0x6f19e288,0xe44f6467,0x16fca7cb}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x6f19e288b6f757d1,0x16fca7cbe44f6467}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0x57d1,0xb6f7,0xe288,0x6f19,0x6467,0xe44f,0xa7cb,0x16fc}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0xb6f757d1,0x6f19e288,0xe44f6467,0x16fca7cb}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -2, ._mp_d = (mp_limb_t[]) {0x6f19e288b6f757d1,0x16fca7cbe44f6467}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 0, ._mp_d = (mp_limb_t[]) {0x0}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x2}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x6511,0x45fa,0xa368,0xe869,0x4db2,0x88fc,0x6989,0xbdf3}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x45fa6511,0xe869a368,0x88fc4db2,0xbdf36989}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0xe869a36845fa6511,0xbdf3698988fc4db2}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0x6511,0x45fa,0xa368,0xe869,0x4db2,0x88fc,0x6989,0xbdf3}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0x45fa6511,0xe869a368,0x88fc4db2,0xbdf36989}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -2, ._mp_d = (mp_limb_t[]) {0xe869a36845fa6511,0xbdf3698988fc4db2}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x5}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x5}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x5}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x5}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x5}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x5}}}}
+#endif
+}}}, {
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x1}}}}
+#endif
+, {{
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 8, ._mp_d = (mp_limb_t[]) {0x1e6b,0x5c4a,0x13f1,0x770,0x7183,0x5600,0xda31,0x9281}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 4, ._mp_d = (mp_limb_t[]) {0x5c4a1e6b,0x77013f1,0x56007183,0x9281da31}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 2, ._mp_d = (mp_limb_t[]) {0x77013f15c4a1e6b,0x9281da3156007183}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -8, ._mp_d = (mp_limb_t[]) {0x1e6b,0x5c4a,0x13f1,0x770,0x7183,0x5600,0xda31,0x9281}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -4, ._mp_d = (mp_limb_t[]) {0x5c4a1e6b,0x77013f1,0x56007183,0x9281da31}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -2, ._mp_d = (mp_limb_t[]) {0x77013f15c4a1e6b,0x9281da3156007183}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = -1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#endif
+,
+#if 0
+#elif GMP_LIMB_BITS == 16
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#elif GMP_LIMB_BITS == 32
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#elif GMP_LIMB_BITS == 64
+{{{._mp_alloc = 0, ._mp_size = 1, ._mp_d = (mp_limb_t[]) {0x4}}}}
+#endif
+}}}};
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion_data.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion_data.h
new file mode 100644
index 0000000000..a5eb1106e6
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/quaternion_data.h
@@ -0,0 +1,12 @@
+#include
+#define MAXORD_O0 (EXTREMAL_ORDERS->order)
+#define STANDARD_EXTREMAL_ORDER (EXTREMAL_ORDERS[0])
+#define NUM_ALTERNATE_EXTREMAL_ORDERS 6
+#define ALTERNATE_EXTREMAL_ORDERS (EXTREMAL_ORDERS+1)
+#define ALTERNATE_CONNECTING_IDEALS (CONNECTING_IDEALS+1)
+#define ALTERNATE_CONJUGATING_ELEMENTS (CONJUGATING_ELEMENTS+1)
+extern const ibz_t QUAT_prime_cofactor;
+extern const quat_alg_t QUATALG_PINFTY;
+extern const quat_p_extremal_maximal_order_t EXTREMAL_ORDERS[7];
+extern const quat_left_ideal_t CONNECTING_IDEALS[7];
+extern const quat_alg_elem_t CONJUGATING_ELEMENTS[7];
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/rationals.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/rationals.c
new file mode 100644
index 0000000000..25f8519b3f
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/rationals.c
@@ -0,0 +1,233 @@
+ #include
+#include "internal.h"
+#include "lll_internals.h"
+
+void
+ibq_init(ibq_t *x)
+{
+ ibz_init(&(x->q[0]));
+ ibz_init(&(x->q[1]));
+ ibz_set(&(x->q[1]), 1);
+}
+
+void
+ibq_finalize(ibq_t *x)
+{
+ ibz_finalize(&(x->q[0]));
+ ibz_finalize(&(x->q[1]));
+}
+
+void
+ibq_mat_4x4_init(ibq_mat_4x4_t *mat)
+{
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibq_init(&mat->m[i].v[j]);
+ }
+ }
+}
+void
+ibq_mat_4x4_finalize(ibq_mat_4x4_t *mat)
+{
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibq_finalize(&mat->m[i].v[j]);
+ }
+ }
+}
+
+void
+ibq_vec_4_init(ibq_vec_4_t *vec)
+{
+ for (int i = 0; i < 4; i++) {
+ ibq_init(&vec->v[i]);
+ }
+}
+void
+ibq_vec_4_finalize(ibq_vec_4_t *vec)
+{
+ for (int i = 0; i < 4; i++) {
+ ibq_finalize(&vec->v[i]);
+ }
+}
+
+void
+ibq_mat_4x4_print(const ibq_mat_4x4_t *mat)
+{
+ printf("matrix: ");
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ibz_print(&(mat->m[i].v[j].q[0]), 10);
+ printf("/");
+ ibz_print(&(mat->m[i].v[j].q[1]), 10);
+ printf(" ");
+ }
+ printf("\n ");
+ }
+ printf("\n");
+}
+
+void
+ibq_vec_4_print(const ibq_vec_4_t *vec)
+{
+ printf("vector: ");
+ for (int i = 0; i < 4; i++) {
+ ibz_print(&(vec->v[i].q[0]), 10);
+ printf("/");
+ ibz_print(&(vec->v[i].q[1]), 10);
+ printf(" ");
+ }
+ printf("\n\n");
+}
+
+void
+ibq_reduce(ibq_t *x)
+{
+ ibz_t gcd, r;
+ ibz_init(&gcd);
+ ibz_init(&r);
+ ibz_gcd(&gcd, &(x->q[0]), &(x->q[1]));
+ ibz_div(&(x->q[0]), &r, &(x->q[0]), &gcd);
+ assert(ibz_is_zero(&r));
+ ibz_div(&(x->q[1]), &r, &(x->q[1]), &gcd);
+ assert(ibz_is_zero(&r));
+ ibz_finalize(&gcd);
+ ibz_finalize(&r);
+}
+
+void
+ibq_add(ibq_t *sum, const ibq_t *a, const ibq_t *b)
+{
+ ibz_t add, prod;
+ ibz_init(&add);
+ ibz_init(&prod);
+
+ ibz_mul(&add, &(a->q[0]), &(b->q[1]));
+ ibz_mul(&prod, &(b->q[0]), &(a->q[1]));
+ ibz_add(&(sum->q[0]), &add, &prod);
+ ibz_mul(&(sum->q[1]), &(a->q[1]), &(b->q[1]));
+ ibz_finalize(&add);
+ ibz_finalize(&prod);
+}
+
+void
+ibq_neg(ibq_t *neg, const ibq_t *x)
+{
+ ibz_copy(&(neg->q[1]), &(x->q[1]));
+ ibz_neg(&(neg->q[0]), &(x->q[0]));
+}
+
+void
+ibq_sub(ibq_t *diff, const ibq_t *a, const ibq_t *b)
+{
+ ibq_t neg;
+ ibq_init(&neg);
+ ibq_neg(&neg, b);
+ ibq_add(diff, a, &neg);
+ ibq_finalize(&neg);
+}
+
+void
+ibq_abs(ibq_t *abs, const ibq_t *x) // once
+{
+ ibq_t neg;
+ ibq_init(&neg);
+ ibq_neg(&neg, x);
+ if (ibq_cmp(x, &neg) < 0)
+ ibq_copy(abs, &neg);
+ else
+ ibq_copy(abs, x);
+ ibq_finalize(&neg);
+}
+
+void
+ibq_mul(ibq_t *prod, const ibq_t *a, const ibq_t *b)
+{
+ ibz_mul(&(prod->q[0]), &(a->q[0]), &(b->q[0]));
+ ibz_mul(&(prod->q[1]), &(a->q[1]), &(b->q[1]));
+}
+
+int
+ibq_inv(ibq_t *inv, const ibq_t *x)
+{
+ int res = !ibq_is_zero(x);
+ if (res) {
+ ibz_copy(&(inv->q[0]), &(x->q[0]));
+ ibz_copy(&(inv->q[1]), &(x->q[1]));
+ ibz_swap(&(inv->q[1]), &(inv->q[0]));
+ }
+ return (res);
+}
+
+int
+ibq_cmp(const ibq_t *a, const ibq_t *b)
+{
+ ibz_t x, y;
+ ibz_init(&x);
+ ibz_init(&y);
+ ibz_copy(&x, &(a->q[0]));
+ ibz_copy(&y, &(b->q[0]));
+ ibz_mul(&y, &y, &(a->q[1]));
+ ibz_mul(&x, &x, &(b->q[1]));
+ if (ibz_cmp(&(a->q[1]), &ibz_const_zero) > 0) {
+ ibz_neg(&y, &y);
+ ibz_neg(&x, &x);
+ }
+ if (ibz_cmp(&(b->q[1]), &ibz_const_zero) > 0) {
+ ibz_neg(&y, &y);
+ ibz_neg(&x, &x);
+ }
+ int res = ibz_cmp(&x, &y);
+ ibz_finalize(&x);
+ ibz_finalize(&y);
+ return (res);
+}
+
+int
+ibq_is_zero(const ibq_t *x)
+{
+ return ibz_is_zero(&(x->q[0]));
+}
+
+int
+ibq_is_one(const ibq_t *x)
+{
+ return (0 == ibz_cmp(&(x->q[0]), &(x->q[1])));
+}
+
+int
+ibq_set(ibq_t *q, const ibz_t *a, const ibz_t *b)
+{
+ ibz_copy(&(q->q[0]), a);
+ ibz_copy(&(q->q[1]), b);
+ return !ibz_is_zero(b);
+}
+
+void
+ibq_copy(ibq_t *target, const ibq_t *value) // once
+{
+ ibz_copy(&(target->q[0]), &(value->q[0]));
+ ibz_copy(&(target->q[1]), &(value->q[1]));
+}
+
+int
+ibq_is_ibz(const ibq_t *q)
+{
+ ibz_t r;
+ ibz_init(&r);
+ ibz_mod(&r, &(q->q[0]), &(q->q[1]));
+ int res = ibz_is_zero(&r);
+ ibz_finalize(&r);
+ return (res);
+}
+
+int
+ibq_to_ibz(ibz_t *z, const ibq_t *q)
+{
+ ibz_t r;
+ ibz_init(&r);
+ ibz_div(z, &r, &(q->q[0]), &(q->q[1]));
+ int res = ibz_is_zero(&r);
+ ibz_finalize(&r);
+ return (res);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/rng.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/rng.h
new file mode 100644
index 0000000000..0362ca0c42
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/rng.h
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef rng_h
+#define rng_h
+
+#include
+
+static inline int randombytes(unsigned char *x, unsigned long long xlen){
+ OQS_randombytes(x, xlen);
+ return 0;
+}
+
+#endif /* rng_h */
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sig.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sig.h
new file mode 100644
index 0000000000..a5bc04e6e4
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sig.h
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef SQISIGN_H
+#define SQISIGN_H
+
+#include
+#include
+
+#if defined(ENABLE_SIGN)
+/**
+ * SQIsign keypair generation.
+ *
+ * The implementation corresponds to SQIsign.CompactKeyGen() in the SQIsign spec.
+ * The caller is responsible to allocate sufficient memory to hold pk and sk.
+ *
+ * @param[out] pk SQIsign public key
+ * @param[out] sk SQIsign secret key
+ * @return int status code
+ */
+SQISIGN_API
+int sqisign_keypair(unsigned char *pk, unsigned char *sk);
+
+/**
+ * SQIsign signature generation.
+ *
+ * The implementation performs SQIsign.expandSK() + SQIsign.sign() in the SQIsign spec.
+ * Keys provided is a compacted secret keys.
+ * The caller is responsible to allocate sufficient memory to hold sm.
+ *
+ * @param[out] sm Signature concatenated with message
+ * @param[out] smlen Pointer to the length of sm
+ * @param[in] m Message to be signed
+ * @param[in] mlen Message length
+ * @param[in] sk Compacted secret key
+ * @return int status code
+ */
+SQISIGN_API
+int sqisign_sign(unsigned char *sm,
+ unsigned long long *smlen,
+ const unsigned char *m,
+ unsigned long long mlen,
+ const unsigned char *sk);
+
+/**
+ * Alternate SQIsign signature generation. Used for liboqs compatibility.
+ *
+ * The implementation performs SQIsign.expandSK() + SQIsign.sign() in the SQIsign spec.
+ * Keys provided is a compacted secret keys.
+ * The caller is responsible to allocate sufficient memory to hold sm.
+ *
+ * @param[out] s Signature
+ * @param[out] slen Pointer to the length of s
+ * @param[in] m Message to be signed
+ * @param[in] mlen Message length
+ * @param[in] sk Compacted secret key
+ * @return int status code
+ */
+SQISIGN_API
+int
+sqisign_sign_signature(unsigned char *s,
+ unsigned long long *slen,
+ const unsigned char *m,
+ unsigned long long mlen,
+ const unsigned char *sk);
+#endif
+
+/**
+ * SQIsign open signature.
+ *
+ * The implementation performs SQIsign.verify(). If the signature verification succeeded, the
+ * original message is stored in m. Keys provided is a compact public key. The caller is responsible
+ * to allocate sufficient memory to hold m.
+ *
+ * @param[out] m Message stored if verification succeeds
+ * @param[out] mlen Pointer to the length of m
+ * @param[in] sm Signature concatenated with message
+ * @param[in] smlen Length of sm
+ * @param[in] pk Compacted public key
+ * @return int status code
+ */
+SQISIGN_API
+int sqisign_open(unsigned char *m,
+ unsigned long long *mlen,
+ const unsigned char *sm,
+ unsigned long long smlen,
+ const unsigned char *pk);
+
+/**
+ * SQIsign verify signature.
+ *
+ * If the signature verification succeeded, returns 0, otherwise 1.
+ *
+ * @param[out] m Message stored if verification succeeds
+ * @param[out] mlen Pointer to the length of m
+ * @param[in] sig Signature
+ * @param[in] siglen Length of sig
+ * @param[in] pk Compacted public key
+ * @return int 0 if verification succeeded, 1 otherwise.
+ */
+SQISIGN_API
+int sqisign_verify(const unsigned char *m,
+ unsigned long long mlen,
+ const unsigned char *sig,
+ unsigned long long siglen,
+ const unsigned char *pk);
+
+/**
+ * Alternate SQIsign verify signature. Used for liboqs compatibility.
+ *
+ * If the signature verification succeeded, returns 0, otherwise 1.
+ *
+ * @param[in] sig Signature
+ * @param[in] siglen Length of sig
+ * @param[out] m Message stored if verification succeeds
+ * @param[out] mlen Pointer to the length of m
+ * @param[in] pk Compacted public key
+ * @return int 0 if verification succeeded, 1 otherwise.
+ */
+SQISIGN_API
+int
+sqisign_verify_signature(const unsigned char *sig,
+ unsigned long long siglen,
+ const unsigned char *m,
+ unsigned long long mlen,
+ const unsigned char *pk);
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sign.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sign.c
new file mode 100644
index 0000000000..9520a6f7fd
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sign.c
@@ -0,0 +1,634 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+// compute the commitment with ideal to isogeny clapotis
+// and apply it to the basis of E0 (together with the multiplication by some scalar u)
+static bool
+commit(ec_curve_t *E_com, ec_basis_t *basis_even_com, quat_left_ideal_t *lideal_com)
+{
+
+ bool found = false;
+
+ found = quat_sampling_random_ideal_O0_given_norm(lideal_com, &COM_DEGREE, 1, &QUAT_represent_integer_params, NULL);
+ // replacing it with a shorter prime norm equivalent ideal
+ found = found && quat_lideal_prime_norm_reduced_equivalent(
+ lideal_com, &QUATALG_PINFTY, QUAT_primality_num_iter, QUAT_equiv_bound_coeff);
+ // ideal to isogeny clapotis
+ found = found && dim2id2iso_arbitrary_isogeny_evaluation(basis_even_com, E_com, lideal_com);
+ return found;
+}
+
+static void
+compute_challenge_ideal_signature(quat_left_ideal_t *lideal_chall_two, const signature_t *sig, const secret_key_t *sk)
+{
+ ibz_vec_2_t vec;
+ ibz_vec_2_init(&vec);
+
+ // vec is a vector [1, chall_coeff] coefficients encoding the kernel of the challenge
+ // isogeny as B[0] + chall_coeff*B[1] where B is the canonical basis of the
+ // 2^TORSION_EVEN_POWER torsion of EA
+ ibz_set(&vec.v[0], 1);
+ ibz_copy_digit_array(&vec.v[1], sig->chall_coeff);
+
+ // now we compute the ideal associated to the challenge
+ // for that, we need to find vec such that
+ // the kernel of the challenge isogeny is generated by vec.v[0]*B0[0] + vec.v[1]*B0[1] where B0
+ // is the image through the secret key isogeny of the canonical basis E0
+ ibz_mat_2x2_eval(&vec, &(sk->mat_BAcan_to_BA0_two), &vec);
+
+ // lideal_chall_two is the pullback of the ideal challenge through the secret key ideal
+ id2iso_kernel_dlogs_to_ideal_even(lideal_chall_two, &vec, TORSION_EVEN_POWER);
+ assert(ibz_cmp(&lideal_chall_two->norm, &TORSION_PLUS_2POWER) == 0);
+
+ ibz_vec_2_finalize(&vec);
+}
+
+static void
+sample_response(quat_alg_elem_t *x, const quat_lattice_t *lattice, const ibz_t *lattice_content)
+{
+ ibz_t bound;
+ ibz_init(&bound);
+ ibz_pow(&bound, &ibz_const_two, SQIsign_response_length);
+ ibz_sub(&bound, &bound, &ibz_const_one);
+ ibz_mul(&bound, &bound, lattice_content);
+
+ int ok UNUSED = quat_lattice_sample_from_ball(x, lattice, &QUATALG_PINFTY, &bound);
+ assert(ok);
+
+ ibz_finalize(&bound);
+}
+
+static void
+compute_response_quat_element(quat_alg_elem_t *resp_quat,
+ ibz_t *lattice_content,
+ const secret_key_t *sk,
+ const quat_left_ideal_t *lideal_chall_two,
+ const quat_left_ideal_t *lideal_commit)
+{
+ quat_left_ideal_t lideal_chall_secret;
+ quat_lattice_t lattice_hom_chall_to_com, lat_commit;
+
+ // Init
+ quat_left_ideal_init(&lideal_chall_secret);
+ quat_lattice_init(&lat_commit);
+ quat_lattice_init(&lattice_hom_chall_to_com);
+
+ // lideal_chall_secret = lideal_secret * lideal_chall_two
+ quat_lideal_inter(&lideal_chall_secret, lideal_chall_two, &(sk->secret_ideal), &QUATALG_PINFTY);
+
+ // now we compute lideal_com_to_chall which is dual(Icom)* lideal_chall_secret
+ quat_lattice_conjugate_without_hnf(&lat_commit, &(lideal_commit->lattice));
+ quat_lattice_intersect(&lattice_hom_chall_to_com, &lideal_chall_secret.lattice, &lat_commit);
+
+ // sampling the smallest response
+ ibz_mul(lattice_content, &lideal_chall_secret.norm, &lideal_commit->norm);
+ sample_response(resp_quat, &lattice_hom_chall_to_com, lattice_content);
+
+ // Clean up
+ quat_left_ideal_finalize(&lideal_chall_secret);
+ quat_lattice_finalize(&lat_commit);
+ quat_lattice_finalize(&lattice_hom_chall_to_com);
+}
+
+static void
+compute_backtracking_signature(signature_t *sig, quat_alg_elem_t *resp_quat, ibz_t *lattice_content, ibz_t *remain)
+{
+ uint_fast8_t backtracking;
+ ibz_t tmp;
+ ibz_init(&tmp);
+
+ ibz_vec_4_t dummy_coord;
+ ibz_vec_4_init(&dummy_coord);
+
+ quat_alg_make_primitive(&dummy_coord, &tmp, resp_quat, &MAXORD_O0);
+ ibz_mul(&resp_quat->denom, &resp_quat->denom, &tmp);
+ assert(quat_lattice_contains(NULL, &MAXORD_O0, resp_quat));
+
+ // the backtracking is the common part of the response and the challenge
+ // its degree is the scalar tmp computed above such that quat_resp is in tmp * O0.
+ backtracking = ibz_two_adic(&tmp);
+ sig->backtracking = backtracking;
+
+ ibz_pow(&tmp, &ibz_const_two, backtracking);
+ ibz_div(lattice_content, remain, lattice_content, &tmp);
+
+ ibz_finalize(&tmp);
+ ibz_vec_4_finalize(&dummy_coord);
+}
+
+static uint_fast8_t
+compute_random_aux_norm_and_helpers(signature_t *sig,
+ ibz_t *random_aux_norm,
+ ibz_t *degree_resp_inv,
+ ibz_t *remain,
+ const ibz_t *lattice_content,
+ quat_alg_elem_t *resp_quat,
+ quat_left_ideal_t *lideal_com_resp,
+ quat_left_ideal_t *lideal_commit)
+{
+ uint_fast8_t pow_dim2_deg_resp;
+ uint_fast8_t exp_diadic_val_full_resp;
+
+ ibz_t tmp, degree_full_resp, degree_odd_resp, norm_d;
+
+ // Init
+ ibz_init(°ree_full_resp);
+ ibz_init(°ree_odd_resp);
+ ibz_init(&norm_d);
+ ibz_init(&tmp);
+
+ quat_alg_norm(°ree_full_resp, &norm_d, resp_quat, &QUATALG_PINFTY);
+
+ // dividing by n(lideal_com) * n(lideal_secret_chall)
+ assert(ibz_is_one(&norm_d));
+ ibz_div(°ree_full_resp, remain, °ree_full_resp, lattice_content);
+ assert(ibz_cmp(remain, &ibz_const_zero) == 0);
+
+ // computing the diadic valuation
+ exp_diadic_val_full_resp = ibz_two_adic(°ree_full_resp);
+ sig->two_resp_length = exp_diadic_val_full_resp;
+
+ // removing the power of two part
+ ibz_pow(&tmp, &ibz_const_two, exp_diadic_val_full_resp);
+ ibz_div(°ree_odd_resp, remain, °ree_full_resp, &tmp);
+ assert(ibz_cmp(remain, &ibz_const_zero) == 0);
+#ifndef NDEBUG
+ ibz_pow(&tmp, &ibz_const_two, SQIsign_response_length - sig->backtracking);
+ assert(ibz_cmp(&tmp, °ree_odd_resp) > 0);
+#endif
+
+ // creating the ideal
+ quat_alg_conj(resp_quat, resp_quat);
+
+ // setting the norm
+ ibz_mul(&tmp, &lideal_commit->norm, °ree_odd_resp);
+ quat_lideal_create(lideal_com_resp, resp_quat, &tmp, &MAXORD_O0, &QUATALG_PINFTY);
+
+ // now we compute the ideal_aux
+ // computing the norm
+ pow_dim2_deg_resp = SQIsign_response_length - exp_diadic_val_full_resp - sig->backtracking;
+ ibz_pow(remain, &ibz_const_two, pow_dim2_deg_resp);
+ ibz_sub(random_aux_norm, remain, °ree_odd_resp);
+
+ // multiplying by 2^HD_extra_torsion to account for the fact that
+ // we use extra torsion above the kernel
+ for (int i = 0; i < HD_extra_torsion; i++)
+ ibz_mul(remain, remain, &ibz_const_two);
+
+ ibz_invmod(degree_resp_inv, °ree_odd_resp, remain);
+
+ ibz_finalize(°ree_full_resp);
+ ibz_finalize(°ree_odd_resp);
+ ibz_finalize(&norm_d);
+ ibz_finalize(&tmp);
+
+ return pow_dim2_deg_resp;
+}
+
+static int
+evaluate_random_aux_isogeny_signature(ec_curve_t *E_aux,
+ ec_basis_t *B_aux,
+ const ibz_t *norm,
+ const quat_left_ideal_t *lideal_com_resp)
+{
+ quat_left_ideal_t lideal_aux;
+ quat_left_ideal_t lideal_aux_resp_com;
+
+ // Init
+ quat_left_ideal_init(&lideal_aux);
+ quat_left_ideal_init(&lideal_aux_resp_com);
+
+ // sampling the ideal at random
+ int found = quat_sampling_random_ideal_O0_given_norm(
+ &lideal_aux, norm, 0, &QUAT_represent_integer_params, &QUAT_prime_cofactor);
+
+ if (found) {
+ // pushing forward
+ quat_lideal_inter(&lideal_aux_resp_com, lideal_com_resp, &lideal_aux, &QUATALG_PINFTY);
+
+ // now we evaluate this isogeny on the basis of E0
+ found = dim2id2iso_arbitrary_isogeny_evaluation(B_aux, E_aux, &lideal_aux_resp_com);
+
+ // Clean up
+ quat_left_ideal_finalize(&lideal_aux_resp_com);
+ quat_left_ideal_finalize(&lideal_aux);
+ }
+
+ return found;
+}
+
+static int
+compute_dim2_isogeny_challenge(theta_couple_curve_with_basis_t *codomain,
+ theta_couple_curve_with_basis_t *domain,
+ const ibz_t *degree_resp_inv,
+ int pow_dim2_deg_resp,
+ int exp_diadic_val_full_resp,
+ int reduced_order)
+{
+ // now, we compute the isogeny Phi : Ecom x Eaux -> Echl' x Eaux'
+ // where Echl' is 2^exp_diadic_val_full_resp isogenous to Echal
+ // ker Phi = <(Bcom_can.P,Baux.P),(Bcom_can.Q,Baux.Q)>
+
+ // preparing the domain
+ theta_couple_curve_t EcomXEaux;
+ copy_curve(&EcomXEaux.E1, &domain->E1);
+ copy_curve(&EcomXEaux.E2, &domain->E2);
+
+ // preparing the kernel
+ theta_kernel_couple_points_t dim_two_ker;
+ copy_bases_to_kernel(&dim_two_ker, &domain->B1, &domain->B2);
+
+ // dividing by the degree of the response
+ digit_t scalar[NWORDS_ORDER];
+ ibz_to_digit_array(scalar, degree_resp_inv);
+ ec_mul(&dim_two_ker.T1.P2, scalar, reduced_order, &dim_two_ker.T1.P2, &EcomXEaux.E2);
+ ec_mul(&dim_two_ker.T2.P2, scalar, reduced_order, &dim_two_ker.T2.P2, &EcomXEaux.E2);
+ ec_mul(&dim_two_ker.T1m2.P2, scalar, reduced_order, &dim_two_ker.T1m2.P2, &EcomXEaux.E2);
+
+ // and multiplying by 2^exp_diadic...
+ double_couple_point_iter(&dim_two_ker.T1, exp_diadic_val_full_resp, &dim_two_ker.T1, &EcomXEaux);
+ double_couple_point_iter(&dim_two_ker.T2, exp_diadic_val_full_resp, &dim_two_ker.T2, &EcomXEaux);
+ double_couple_point_iter(&dim_two_ker.T1m2, exp_diadic_val_full_resp, &dim_two_ker.T1m2, &EcomXEaux);
+
+ theta_couple_point_t pushed_points[3];
+ theta_couple_point_t *const Tev1 = pushed_points + 0, *const Tev2 = pushed_points + 1,
+ *const Tev1m2 = pushed_points + 2;
+
+ // Set points on the commitment curve
+ copy_point(&Tev1->P1, &domain->B1.P);
+ copy_point(&Tev2->P1, &domain->B1.Q);
+ copy_point(&Tev1m2->P1, &domain->B1.PmQ);
+
+ // Zero points on the aux curve
+ ec_point_init(&Tev1->P2);
+ ec_point_init(&Tev2->P2);
+ ec_point_init(&Tev1m2->P2);
+
+ theta_couple_curve_t codomain_product;
+
+ // computation of the dim2 isogeny
+ if (!theta_chain_compute_and_eval_randomized(pow_dim2_deg_resp,
+ &EcomXEaux,
+ &dim_two_ker,
+ true,
+ &codomain_product,
+ pushed_points,
+ sizeof(pushed_points) / sizeof(*pushed_points)))
+ return 0;
+
+ assert(test_couple_point_order_twof(Tev1, &codomain_product, reduced_order));
+
+ // Set the auxiliary curve
+ copy_curve(&codomain->E1, &codomain_product.E2);
+
+ // Set the codomain curve from the dim 2 isogeny
+ // it should always be the first curve
+ copy_curve(&codomain->E2, &codomain_product.E1);
+
+ // Set the evaluated basis points
+ copy_point(&codomain->B1.P, &Tev1->P2);
+ copy_point(&codomain->B1.Q, &Tev2->P2);
+ copy_point(&codomain->B1.PmQ, &Tev1m2->P2);
+
+ copy_point(&codomain->B2.P, &Tev1->P1);
+ copy_point(&codomain->B2.Q, &Tev2->P1);
+ copy_point(&codomain->B2.PmQ, &Tev1m2->P1);
+ return 1;
+}
+
+static int
+compute_small_chain_isogeny_signature(ec_curve_t *E_chall_2,
+ ec_basis_t *B_chall_2,
+ const quat_alg_elem_t *resp_quat,
+ int pow_dim2_deg_resp,
+ int length)
+{
+ int ret = 1;
+
+ ibz_t two_pow;
+ ibz_init(&two_pow);
+
+ ibz_vec_2_t vec_resp_two;
+ ibz_vec_2_init(&vec_resp_two);
+
+ quat_left_ideal_t lideal_resp_two;
+ quat_left_ideal_init(&lideal_resp_two);
+
+ // computing the ideal
+ ibz_pow(&two_pow, &ibz_const_two, length);
+
+ // we compute the generator of the challenge ideal
+ quat_lideal_create(&lideal_resp_two, resp_quat, &two_pow, &MAXORD_O0, &QUATALG_PINFTY);
+
+ // computing the coefficients of the kernel in terms of the basis of O0
+ id2iso_ideal_to_kernel_dlogs_even(&vec_resp_two, &lideal_resp_two);
+
+ ec_point_t points[3];
+ copy_point(&points[0], &B_chall_2->P);
+ copy_point(&points[1], &B_chall_2->Q);
+ copy_point(&points[2], &B_chall_2->PmQ);
+
+ // getting down to the right order and applying the matrix
+ ec_dbl_iter_basis(B_chall_2, pow_dim2_deg_resp + HD_extra_torsion, B_chall_2, E_chall_2);
+ assert(test_basis_order_twof(B_chall_2, E_chall_2, length));
+
+ ec_point_t ker;
+ // applying the vector to find the kernel
+ ec_biscalar_mul_ibz_vec(&ker, &vec_resp_two, length, B_chall_2, E_chall_2);
+ assert(test_point_order_twof(&ker, E_chall_2, length));
+
+ // computing the isogeny and pushing the points
+ if (ec_eval_small_chain(E_chall_2, &ker, length, points, 3, true)) {
+ ret = 0;
+ }
+
+ // copying the result
+ copy_point(&B_chall_2->P, &points[0]);
+ copy_point(&B_chall_2->Q, &points[1]);
+ copy_point(&B_chall_2->PmQ, &points[2]);
+
+ ibz_finalize(&two_pow);
+ ibz_vec_2_finalize(&vec_resp_two);
+ quat_left_ideal_finalize(&lideal_resp_two);
+
+ return ret;
+}
+
+static int
+compute_challenge_codomain_signature(const signature_t *sig,
+ secret_key_t *sk,
+ ec_curve_t *E_chall,
+ const ec_curve_t *E_chall_2,
+ ec_basis_t *B_chall_2)
+{
+ ec_isog_even_t phi_chall;
+ ec_basis_t bas_sk;
+ copy_basis(&bas_sk, &sk->canonical_basis);
+
+ phi_chall.curve = sk->curve;
+ phi_chall.length = TORSION_EVEN_POWER - sig->backtracking;
+ assert(test_basis_order_twof(&bas_sk, &sk->curve, TORSION_EVEN_POWER));
+
+ // Compute the kernel
+ {
+ ec_ladder3pt(&phi_chall.kernel, sig->chall_coeff, &bas_sk.P, &bas_sk.Q, &bas_sk.PmQ, &sk->curve);
+ }
+ assert(test_point_order_twof(&phi_chall.kernel, &sk->curve, TORSION_EVEN_POWER));
+
+ // Double kernel to get correct order
+ ec_dbl_iter(&phi_chall.kernel, sig->backtracking, &phi_chall.kernel, &sk->curve);
+
+ assert(test_point_order_twof(&phi_chall.kernel, E_chall, phi_chall.length));
+
+ // Compute the codomain from challenge isogeny
+ if (ec_eval_even(E_chall, &phi_chall, NULL, 0))
+ return 0;
+
+#ifndef NDEBUG
+ fp2_t j_chall, j_codomain;
+ ec_j_inv(&j_codomain, E_chall_2);
+ ec_j_inv(&j_chall, E_chall);
+ // apparently its always the second one curve
+ assert(fp2_is_equal(&j_chall, &j_codomain));
+#endif
+
+ // applying the isomorphism from E_chall_2 to E_chall
+ ec_isom_t isom;
+ if (ec_isomorphism(&isom, E_chall_2, E_chall))
+ return 0; // error due to a corner case with 1/p probability
+ ec_iso_eval(&B_chall_2->P, &isom);
+ ec_iso_eval(&B_chall_2->Q, &isom);
+ ec_iso_eval(&B_chall_2->PmQ, &isom);
+
+ return 1;
+}
+
+static void
+set_aux_curve_signature(signature_t *sig, ec_curve_t *E_aux)
+{
+ ec_normalize_curve(E_aux);
+ fp2_copy(&sig->E_aux_A, &E_aux->A);
+}
+
+static void
+compute_and_set_basis_change_matrix(signature_t *sig,
+ const ec_basis_t *B_aux_2,
+ ec_basis_t *B_chall_2,
+ ec_curve_t *E_aux_2,
+ ec_curve_t *E_chall,
+ int f)
+{
+ // Matrices for change of bases matrices
+ ibz_mat_2x2_t mat_Baux2_to_Baux2_can, mat_Bchall_can_to_Bchall;
+ ibz_mat_2x2_init(&mat_Baux2_to_Baux2_can);
+ ibz_mat_2x2_init(&mat_Bchall_can_to_Bchall);
+
+ // Compute canonical bases
+ ec_basis_t B_can_chall, B_aux_2_can;
+ sig->hint_chall = ec_curve_to_basis_2f_to_hint(&B_can_chall, E_chall, TORSION_EVEN_POWER);
+ sig->hint_aux = ec_curve_to_basis_2f_to_hint(&B_aux_2_can, E_aux_2, TORSION_EVEN_POWER);
+
+#ifndef NDEBUG
+ {
+ // Ensure all points have the desired order
+ assert(test_basis_order_twof(&B_aux_2_can, E_aux_2, TORSION_EVEN_POWER));
+ assert(test_basis_order_twof(B_aux_2, E_aux_2, f));
+ fp2_t w0;
+ weil(&w0, f, &B_aux_2->P, &B_aux_2->Q, &B_aux_2->PmQ, E_aux_2);
+ }
+#endif
+
+ // compute the matrix to go from B_aux_2 to B_aux_2_can
+ change_of_basis_matrix_tate_invert(&mat_Baux2_to_Baux2_can, &B_aux_2_can, B_aux_2, E_aux_2, f);
+
+ // apply the change of basis to B_chall_2
+ matrix_application_even_basis(B_chall_2, E_chall, &mat_Baux2_to_Baux2_can, f);
+
+#ifndef NDEBUG
+ {
+ // Ensure all points have the desired order
+ assert(test_basis_order_twof(&B_can_chall, E_chall, TORSION_EVEN_POWER));
+ }
+#endif
+
+ // compute the matrix to go from B_chall_can to B_chall_2
+ change_of_basis_matrix_tate(&mat_Bchall_can_to_Bchall, B_chall_2, &B_can_chall, E_chall, f);
+
+ // Assert all values in the matrix are of the expected size for packing
+ assert(ibz_bitsize(&mat_Bchall_can_to_Bchall.m[0][0]) <= SQIsign_response_length + HD_extra_torsion);
+ assert(ibz_bitsize(&mat_Bchall_can_to_Bchall.m[0][1]) <= SQIsign_response_length + HD_extra_torsion);
+ assert(ibz_bitsize(&mat_Bchall_can_to_Bchall.m[1][0]) <= SQIsign_response_length + HD_extra_torsion);
+ assert(ibz_bitsize(&mat_Bchall_can_to_Bchall.m[1][1]) <= SQIsign_response_length + HD_extra_torsion);
+
+ // Set the basis change matrix to signature
+ ibz_to_digit_array(sig->mat_Bchall_can_to_B_chall[0][0], &(mat_Bchall_can_to_Bchall.m[0][0]));
+ ibz_to_digit_array(sig->mat_Bchall_can_to_B_chall[0][1], &(mat_Bchall_can_to_Bchall.m[0][1]));
+ ibz_to_digit_array(sig->mat_Bchall_can_to_B_chall[1][0], &(mat_Bchall_can_to_Bchall.m[1][0]));
+ ibz_to_digit_array(sig->mat_Bchall_can_to_B_chall[1][1], &(mat_Bchall_can_to_Bchall.m[1][1]));
+
+ // Finalise the matrices
+ ibz_mat_2x2_finalize(&mat_Bchall_can_to_Bchall);
+ ibz_mat_2x2_finalize(&mat_Baux2_to_Baux2_can);
+}
+
+int
+protocols_sign(signature_t *sig, const public_key_t *pk, secret_key_t *sk, const unsigned char *m, size_t l)
+{
+ int ret = 0;
+ int reduced_order = 0; // work around false positive gcc warning
+
+ uint_fast8_t pow_dim2_deg_resp;
+ assert(SQIsign_response_length <= (intmax_t)UINT_FAST8_MAX); // otherwise we might need more bits there
+
+ ibz_t remain, lattice_content, random_aux_norm, degree_resp_inv;
+ ibz_init(&remain);
+ ibz_init(&lattice_content);
+ ibz_init(&random_aux_norm);
+ ibz_init(°ree_resp_inv);
+
+ quat_alg_elem_t resp_quat;
+ quat_alg_elem_init(&resp_quat);
+
+ quat_left_ideal_t lideal_commit, lideal_com_resp;
+ quat_left_ideal_init(&lideal_commit);
+ quat_left_ideal_init(&lideal_com_resp);
+
+ // This structure holds two curves E1 x E2 together with a basis
+ // Bi of E[2^n] for each of these curves
+ theta_couple_curve_with_basis_t Ecom_Eaux;
+ // This structure holds two curves E1 x E2 together with a basis
+ // Bi of Ei[2^n]
+ theta_couple_curve_with_basis_t Eaux2_Echall2;
+
+ // This will hold the challenge curve
+ ec_curve_t E_chall = sk->curve;
+
+ ec_curve_init(&Ecom_Eaux.E1);
+ ec_curve_init(&Ecom_Eaux.E2);
+
+ while (!ret) {
+
+ // computing the commitment
+ ret = commit(&Ecom_Eaux.E1, &Ecom_Eaux.B1, &lideal_commit);
+
+ // start again if the commitment generation has failed
+ if (!ret) {
+ continue;
+ }
+
+ // Hash the message to a kernel generator
+ // i.e. a scalar such that ker = P + [s]Q
+ hash_to_challenge(&sig->chall_coeff, pk, &Ecom_Eaux.E1, m, l);
+ // Compute the challenge ideal and response quaternion element
+ {
+ quat_left_ideal_t lideal_chall_two;
+ quat_left_ideal_init(&lideal_chall_two);
+
+ // computing the challenge ideal
+ compute_challenge_ideal_signature(&lideal_chall_two, sig, sk);
+ compute_response_quat_element(&resp_quat, &lattice_content, sk, &lideal_chall_two, &lideal_commit);
+
+ // Clean up
+ quat_left_ideal_finalize(&lideal_chall_two);
+ }
+
+ // computing the amount of backtracking we're making
+ // and removing it
+ compute_backtracking_signature(sig, &resp_quat, &lattice_content, &remain);
+
+ // creating lideal_com * lideal_resp
+ // we first compute the norm of lideal_resp
+ // norm of the resp_quat
+ pow_dim2_deg_resp = compute_random_aux_norm_and_helpers(sig,
+ &random_aux_norm,
+ °ree_resp_inv,
+ &remain,
+ &lattice_content,
+ &resp_quat,
+ &lideal_com_resp,
+ &lideal_commit);
+
+ // notational conventions:
+ // B0 = canonical basis of E0
+ // B_com = image through commitment isogeny (odd degree) of canonical basis of E0
+ // B_aux = image through aux_resp_com isogeny (odd degree) of canonical basis of E0
+
+ if (pow_dim2_deg_resp > 0) {
+ // Evaluate the random aux ideal on the curve E0 and its basis to find E_aux and B_aux
+ ret =
+ evaluate_random_aux_isogeny_signature(&Ecom_Eaux.E2, &Ecom_Eaux.B2, &random_aux_norm, &lideal_com_resp);
+
+ // auxiliary isogeny computation failed we must start again
+ if (!ret) {
+ continue;
+ }
+
+#ifndef NDEBUG
+ // testing that the order of the points in the bases is as expected
+ assert(test_basis_order_twof(&Ecom_Eaux.B1, &Ecom_Eaux.E1, TORSION_EVEN_POWER));
+ assert(test_basis_order_twof(&Ecom_Eaux.B2, &Ecom_Eaux.E2, TORSION_EVEN_POWER));
+#endif
+
+ // applying the matrix to compute Baux
+ // first, we reduce to the relevant order
+ reduced_order = pow_dim2_deg_resp + HD_extra_torsion + sig->two_resp_length;
+ ec_dbl_iter_basis(&Ecom_Eaux.B1, TORSION_EVEN_POWER - reduced_order, &Ecom_Eaux.B1, &Ecom_Eaux.E1);
+ ec_dbl_iter_basis(&Ecom_Eaux.B2, TORSION_EVEN_POWER - reduced_order, &Ecom_Eaux.B2, &Ecom_Eaux.E2);
+
+ // Given all the above data, compute a dim two isogeny with domain
+ // E_com x E_aux
+ // and codomain
+ // E_aux_2 x E_chall_2 (note: E_chall_2 is isomorphic to E_chall)
+ // and evaluated points stored as bases in
+ // B_aux_2 on E_aux_2
+ // B_chall_2 on E_chall_2
+ ret = compute_dim2_isogeny_challenge(
+ &Eaux2_Echall2, &Ecom_Eaux, °ree_resp_inv, pow_dim2_deg_resp, sig->two_resp_length, reduced_order);
+ if (!ret)
+ continue;
+ } else {
+ // No 2d isogeny needed, so simulate a "Kani matrix" identity here
+ copy_curve(&Eaux2_Echall2.E1, &Ecom_Eaux.E1);
+ copy_curve(&Eaux2_Echall2.E2, &Ecom_Eaux.E1);
+
+ reduced_order = sig->two_resp_length;
+ ec_dbl_iter_basis(&Eaux2_Echall2.B1, TORSION_EVEN_POWER - reduced_order, &Ecom_Eaux.B1, &Ecom_Eaux.E1);
+ ec_dbl_iter_basis(&Eaux2_Echall2.B1, TORSION_EVEN_POWER - reduced_order, &Ecom_Eaux.B1, &Ecom_Eaux.E1);
+ copy_basis(&Eaux2_Echall2.B2, &Eaux2_Echall2.B1);
+ }
+
+ // computation of the remaining small chain of two isogenies when needed
+ if (sig->two_resp_length > 0) {
+ if (!compute_small_chain_isogeny_signature(
+ &Eaux2_Echall2.E2, &Eaux2_Echall2.B2, &resp_quat, pow_dim2_deg_resp, sig->two_resp_length)) {
+ assert(0); // this shouldn't fail
+ }
+ }
+
+ // computation of the challenge codomain
+ if (!compute_challenge_codomain_signature(sig, sk, &E_chall, &Eaux2_Echall2.E2, &Eaux2_Echall2.B2))
+ assert(0); // this shouldn't fail
+ }
+
+ // Set to the signature the Montgomery A-coefficient of E_aux_2
+ set_aux_curve_signature(sig, &Eaux2_Echall2.E1);
+
+ // Set the basis change matrix from canonical bases to the supplied bases
+ compute_and_set_basis_change_matrix(
+ sig, &Eaux2_Echall2.B1, &Eaux2_Echall2.B2, &Eaux2_Echall2.E1, &E_chall, reduced_order);
+
+ quat_alg_elem_finalize(&resp_quat);
+ quat_left_ideal_finalize(&lideal_commit);
+ quat_left_ideal_finalize(&lideal_com_resp);
+
+ ibz_finalize(&lattice_content);
+ ibz_finalize(&remain);
+ ibz_finalize(°ree_resp_inv);
+ ibz_finalize(&random_aux_norm);
+
+ return ret;
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/signature.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/signature.h
new file mode 100644
index 0000000000..ba38c360e6
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/signature.h
@@ -0,0 +1,97 @@
+/** @file
+ *
+ * @brief The key generation and signature protocols
+ */
+
+#ifndef SIGNATURE_H
+#define SIGNATURE_H
+
+#include
+#include
+#include
+#include
+
+/** @defgroup signature SQIsignHD key generation and signature protocols
+ * @{
+ */
+/** @defgroup signature_t Types for SQIsignHD key generation and signature protocols
+ * @{
+ */
+
+/** @brief Type for the secret keys
+ *
+ * @typedef secret_key_t
+ *
+ * @struct secret_key
+ *
+ */
+typedef struct secret_key
+{
+ ec_curve_t curve; /// the public curve, but with little precomputations
+ quat_left_ideal_t secret_ideal;
+ ibz_mat_2x2_t mat_BAcan_to_BA0_two; // mat_BA0_to_BAcan*BA0 = BAcan, where BAcan is the
+ // canonical basis of EA[2^e], and BA0 the image of the
+ // basis of E0[2^e] through the secret isogeny
+ ec_basis_t canonical_basis; // the canonical basis of the public key curve
+} secret_key_t;
+
+/** @}
+ */
+
+/*************************** Functions *****************************/
+
+void secret_key_init(secret_key_t *sk);
+void secret_key_finalize(secret_key_t *sk);
+
+/**
+ * @brief Key generation
+ *
+ * @param pk Output: will contain the public key
+ * @param sk Output: will contain the secret key
+ * @returns 1 if success, 0 otherwise
+ */
+int protocols_keygen(public_key_t *pk, secret_key_t *sk);
+
+/**
+ * @brief Signature computation
+ *
+ * @param sig Output: will contain the signature
+ * @param sk secret key
+ * @param pk public key
+ * @param m message
+ * @param l size
+ * @returns 1 if success, 0 otherwise
+ */
+int protocols_sign(signature_t *sig, const public_key_t *pk, secret_key_t *sk, const unsigned char *m, size_t l);
+
+/*************************** Encoding *****************************/
+
+/** @defgroup encoding Encoding and decoding functions
+ * @{
+ */
+
+/**
+ * @brief Encodes a secret key as a byte array
+ *
+ * @param enc : Byte array to encode the secret key (including public key) in
+ * @param sk : Secret key to encode
+ * @param pk : Public key to encode
+ */
+void secret_key_to_bytes(unsigned char *enc, const secret_key_t *sk, const public_key_t *pk);
+
+/**
+ * @brief Decodes a secret key (and public key) from a byte array
+ *
+ * @param sk : Structure to decode the secret key in
+ * @param pk : Structure to decode the public key in
+ * @param enc : Byte array to decode
+ */
+void secret_key_from_bytes(secret_key_t *sk, public_key_t *pk, const unsigned char *enc);
+
+/** @}
+ */
+
+/** @}
+ */
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sqisign.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sqisign.c
new file mode 100644
index 0000000000..cf2134085b
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sqisign.c
@@ -0,0 +1,146 @@
+#include
+#include
+#include
+#include
+#if defined(ENABLE_SIGN)
+#include
+#endif
+
+#if defined(ENABLE_SIGN)
+SQISIGN_API
+int
+sqisign_keypair(unsigned char *pk, unsigned char *sk)
+{
+ int ret = 0;
+ secret_key_t skt;
+ public_key_t pkt = { 0 };
+ secret_key_init(&skt);
+
+ ret = !protocols_keygen(&pkt, &skt);
+
+ secret_key_to_bytes(sk, &skt, &pkt);
+ public_key_to_bytes(pk, &pkt);
+ secret_key_finalize(&skt);
+ return ret;
+}
+
+SQISIGN_API
+int
+sqisign_sign(unsigned char *sm,
+ unsigned long long *smlen,
+ const unsigned char *m,
+ unsigned long long mlen,
+ const unsigned char *sk)
+{
+ int ret = 0;
+ secret_key_t skt;
+ public_key_t pkt = { 0 };
+ signature_t sigt;
+ secret_key_init(&skt);
+ secret_key_from_bytes(&skt, &pkt, sk);
+
+ memmove(sm + SIGNATURE_BYTES, m, mlen);
+
+ ret = !protocols_sign(&sigt, &pkt, &skt, sm + SIGNATURE_BYTES, mlen);
+ if (ret != 0) {
+ *smlen = 0;
+ goto err;
+ }
+
+ signature_to_bytes(sm, &sigt);
+ *smlen = SIGNATURE_BYTES + mlen;
+
+err:
+ secret_key_finalize(&skt);
+ return ret;
+}
+
+SQISIGN_API
+int
+sqisign_sign_signature(unsigned char *s,
+ unsigned long long *slen,
+ const unsigned char *m,
+ unsigned long long mlen,
+ const unsigned char *sk)
+{
+ int ret = 0;
+ secret_key_t skt;
+ public_key_t pkt = { 0 };
+ signature_t sigt;
+ secret_key_init(&skt);
+ secret_key_from_bytes(&skt, &pkt, sk);
+
+ ret = !protocols_sign(&sigt, &pkt, &skt, m, mlen);
+ if (ret != 0) {
+ *slen = 0;
+ goto err;
+ }
+
+ signature_to_bytes(s, &sigt);
+ *slen = SIGNATURE_BYTES;
+
+err:
+ secret_key_finalize(&skt);
+ return ret;
+}
+#endif
+
+SQISIGN_API
+int
+sqisign_open(unsigned char *m,
+ unsigned long long *mlen,
+ const unsigned char *sm,
+ unsigned long long smlen,
+ const unsigned char *pk)
+{
+ int ret = 0;
+ public_key_t pkt = { 0 };
+ signature_t sigt;
+
+ public_key_from_bytes(&pkt, pk);
+ signature_from_bytes(&sigt, sm);
+
+ ret = !protocols_verify(&sigt, &pkt, sm + SIGNATURE_BYTES, smlen - SIGNATURE_BYTES);
+
+ if (!ret) {
+ *mlen = smlen - SIGNATURE_BYTES;
+ memmove(m, sm + SIGNATURE_BYTES, *mlen);
+ } else {
+ *mlen = 0;
+ memset(m, 0, smlen - SIGNATURE_BYTES);
+ }
+
+ return ret;
+}
+
+SQISIGN_API
+int
+sqisign_verify(const unsigned char *m,
+ unsigned long long mlen,
+ const unsigned char *sig,
+ unsigned long long siglen,
+ const unsigned char *pk)
+{
+ (void) siglen;
+ int ret = 0;
+ public_key_t pkt = { 0 };
+ signature_t sigt;
+
+ public_key_from_bytes(&pkt, pk);
+ signature_from_bytes(&sigt, sig);
+
+ ret = !protocols_verify(&sigt, &pkt, m, mlen);
+
+ return ret;
+}
+
+SQISIGN_API
+int
+sqisign_verify_signature(const unsigned char *sig,
+ unsigned long long siglen,
+ const unsigned char *m,
+ unsigned long long mlen,
+ const unsigned char *pk)
+{
+ return sqisign_verify(m, mlen, sig, siglen, pk);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sqisign_namespace.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sqisign_namespace.h
new file mode 100644
index 0000000000..54e90326be
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sqisign_namespace.h
@@ -0,0 +1,1139 @@
+
+#ifndef SQISIGN_NAMESPACE_H
+#define SQISIGN_NAMESPACE_H
+
+//#define DISABLE_NAMESPACING
+
+#if defined(_WIN32)
+#define SQISIGN_API __declspec(dllexport)
+#else
+#define SQISIGN_API __attribute__((visibility("default")))
+#endif
+
+#define PARAM_JOIN3_(a, b, c) sqisign_##a##_##b##_##c
+#define PARAM_JOIN3(a, b, c) PARAM_JOIN3_(a, b, c)
+#define PARAM_NAME3(end, s) PARAM_JOIN3(SQISIGN_VARIANT, end, s)
+
+#define PARAM_JOIN2_(a, b) sqisign_##a##_##b
+#define PARAM_JOIN2(a, b) PARAM_JOIN2_(a, b)
+#define PARAM_NAME2(end, s) PARAM_JOIN2(end, s)
+
+#ifndef DISABLE_NAMESPACING
+#define SQISIGN_NAMESPACE_GENERIC(s) PARAM_NAME2(gen, s)
+#else
+#define SQISIGN_NAMESPACE_GENERIC(s) s
+#endif
+
+#if defined(SQISIGN_VARIANT) && !defined(DISABLE_NAMESPACING)
+#if defined(SQISIGN_BUILD_TYPE_REF)
+#define SQISIGN_NAMESPACE(s) PARAM_NAME3(ref, s)
+#elif defined(SQISIGN_BUILD_TYPE_OPT)
+#define SQISIGN_NAMESPACE(s) PARAM_NAME3(opt, s)
+#elif defined(SQISIGN_BUILD_TYPE_BROADWELL)
+#define SQISIGN_NAMESPACE(s) PARAM_NAME3(broadwell, s)
+#elif defined(SQISIGN_BUILD_TYPE_ARM64CRYPTO)
+#define SQISIGN_NAMESPACE(s) PARAM_NAME3(arm64crypto, s)
+#else
+#error "Build type not known"
+#endif
+
+#else
+#define SQISIGN_NAMESPACE(s) s
+#endif
+
+// Namespacing symbols exported from algebra.c:
+#undef quat_alg_add
+#undef quat_alg_conj
+#undef quat_alg_coord_mul
+#undef quat_alg_elem_copy
+#undef quat_alg_elem_copy_ibz
+#undef quat_alg_elem_equal
+#undef quat_alg_elem_is_zero
+#undef quat_alg_elem_mul_by_scalar
+#undef quat_alg_elem_set
+#undef quat_alg_equal_denom
+#undef quat_alg_init_set_ui
+#undef quat_alg_make_primitive
+#undef quat_alg_mul
+#undef quat_alg_norm
+#undef quat_alg_normalize
+#undef quat_alg_scalar
+#undef quat_alg_sub
+
+#define quat_alg_add SQISIGN_NAMESPACE(quat_alg_add)
+#define quat_alg_conj SQISIGN_NAMESPACE(quat_alg_conj)
+#define quat_alg_coord_mul SQISIGN_NAMESPACE(quat_alg_coord_mul)
+#define quat_alg_elem_copy SQISIGN_NAMESPACE(quat_alg_elem_copy)
+#define quat_alg_elem_copy_ibz SQISIGN_NAMESPACE(quat_alg_elem_copy_ibz)
+#define quat_alg_elem_equal SQISIGN_NAMESPACE(quat_alg_elem_equal)
+#define quat_alg_elem_is_zero SQISIGN_NAMESPACE(quat_alg_elem_is_zero)
+#define quat_alg_elem_mul_by_scalar SQISIGN_NAMESPACE(quat_alg_elem_mul_by_scalar)
+#define quat_alg_elem_set SQISIGN_NAMESPACE(quat_alg_elem_set)
+#define quat_alg_equal_denom SQISIGN_NAMESPACE(quat_alg_equal_denom)
+#define quat_alg_init_set_ui SQISIGN_NAMESPACE(quat_alg_init_set_ui)
+#define quat_alg_make_primitive SQISIGN_NAMESPACE(quat_alg_make_primitive)
+#define quat_alg_mul SQISIGN_NAMESPACE(quat_alg_mul)
+#define quat_alg_norm SQISIGN_NAMESPACE(quat_alg_norm)
+#define quat_alg_normalize SQISIGN_NAMESPACE(quat_alg_normalize)
+#define quat_alg_scalar SQISIGN_NAMESPACE(quat_alg_scalar)
+#define quat_alg_sub SQISIGN_NAMESPACE(quat_alg_sub)
+
+// Namespacing symbols exported from api.c:
+#undef crypto_sign
+#undef crypto_sign_keypair
+#undef crypto_sign_open
+
+#define crypto_sign SQISIGN_NAMESPACE(crypto_sign)
+#define crypto_sign_keypair SQISIGN_NAMESPACE(crypto_sign_keypair)
+#define crypto_sign_open SQISIGN_NAMESPACE(crypto_sign_open)
+
+// Namespacing symbols exported from basis.c:
+#undef ec_curve_to_basis_2f_from_hint
+#undef ec_curve_to_basis_2f_to_hint
+#undef ec_recover_y
+#undef lift_basis
+#undef lift_basis_normalized
+
+#define ec_curve_to_basis_2f_from_hint SQISIGN_NAMESPACE(ec_curve_to_basis_2f_from_hint)
+#define ec_curve_to_basis_2f_to_hint SQISIGN_NAMESPACE(ec_curve_to_basis_2f_to_hint)
+#define ec_recover_y SQISIGN_NAMESPACE(ec_recover_y)
+#define lift_basis SQISIGN_NAMESPACE(lift_basis)
+#define lift_basis_normalized SQISIGN_NAMESPACE(lift_basis_normalized)
+
+// Namespacing symbols exported from basis.c, ec.c:
+#undef xDBL_E0
+
+#define xDBL_E0 SQISIGN_NAMESPACE(xDBL_E0)
+
+// Namespacing symbols exported from basis.c, ec.c, isog_chains.c:
+#undef xDBL_A24
+
+#define xDBL_A24 SQISIGN_NAMESPACE(xDBL_A24)
+
+// Namespacing symbols exported from biextension.c:
+#undef clear_cofac
+#undef ec_dlog_2_tate
+#undef ec_dlog_2_weil
+#undef fp2_frob
+#undef reduced_tate
+#undef weil
+
+#define clear_cofac SQISIGN_NAMESPACE(clear_cofac)
+#define ec_dlog_2_tate SQISIGN_NAMESPACE(ec_dlog_2_tate)
+#define ec_dlog_2_weil SQISIGN_NAMESPACE(ec_dlog_2_weil)
+#define fp2_frob SQISIGN_NAMESPACE(fp2_frob)
+#define reduced_tate SQISIGN_NAMESPACE(reduced_tate)
+#define weil SQISIGN_NAMESPACE(weil)
+
+// Namespacing symbols exported from biextension.c, ec_jac.c, hd.c:
+#undef ADD
+
+#define ADD SQISIGN_NAMESPACE(ADD)
+
+// Namespacing symbols exported from common.c:
+#undef hash_to_challenge
+#undef public_key_finalize
+#undef public_key_init
+
+#define hash_to_challenge SQISIGN_NAMESPACE(hash_to_challenge)
+#define public_key_finalize SQISIGN_NAMESPACE(public_key_finalize)
+#define public_key_init SQISIGN_NAMESPACE(public_key_init)
+
+// Namespacing symbols exported from dim2.c:
+#undef ibz_2x2_mul_mod
+#undef ibz_mat_2x2_add
+#undef ibz_mat_2x2_copy
+#undef ibz_mat_2x2_det_from_ibz
+#undef ibz_mat_2x2_eval
+#undef ibz_mat_2x2_inv_mod
+#undef ibz_mat_2x2_set
+#undef ibz_vec_2_set
+
+#define ibz_2x2_mul_mod SQISIGN_NAMESPACE(ibz_2x2_mul_mod)
+#define ibz_mat_2x2_add SQISIGN_NAMESPACE(ibz_mat_2x2_add)
+#define ibz_mat_2x2_copy SQISIGN_NAMESPACE(ibz_mat_2x2_copy)
+#define ibz_mat_2x2_det_from_ibz SQISIGN_NAMESPACE(ibz_mat_2x2_det_from_ibz)
+#define ibz_mat_2x2_eval SQISIGN_NAMESPACE(ibz_mat_2x2_eval)
+#define ibz_mat_2x2_inv_mod SQISIGN_NAMESPACE(ibz_mat_2x2_inv_mod)
+#define ibz_mat_2x2_set SQISIGN_NAMESPACE(ibz_mat_2x2_set)
+#define ibz_vec_2_set SQISIGN_NAMESPACE(ibz_vec_2_set)
+
+// Namespacing symbols exported from dim2id2iso.c:
+#undef dim2id2iso_arbitrary_isogeny_evaluation
+#undef dim2id2iso_ideal_to_isogeny_clapotis
+#undef find_uv
+#undef fixed_degree_isogeny_and_eval
+
+#define dim2id2iso_arbitrary_isogeny_evaluation SQISIGN_NAMESPACE(dim2id2iso_arbitrary_isogeny_evaluation)
+#define dim2id2iso_ideal_to_isogeny_clapotis SQISIGN_NAMESPACE(dim2id2iso_ideal_to_isogeny_clapotis)
+#define find_uv SQISIGN_NAMESPACE(find_uv)
+#define fixed_degree_isogeny_and_eval SQISIGN_NAMESPACE(fixed_degree_isogeny_and_eval)
+
+// Namespacing symbols exported from dim2id2iso.c, encode_signature.c, id2iso.c, keygen.c, quaternion_data.c, sign.c:
+#undef EXTREMAL_ORDERS
+#undef QUATALG_PINFTY
+
+#define EXTREMAL_ORDERS SQISIGN_NAMESPACE(EXTREMAL_ORDERS)
+#define QUATALG_PINFTY SQISIGN_NAMESPACE(QUATALG_PINFTY)
+
+// Namespacing symbols exported from dim2id2iso.c, endomorphism_action.c, id2iso.c:
+#undef CURVES_WITH_ENDOMORPHISMS
+
+#define CURVES_WITH_ENDOMORPHISMS SQISIGN_NAMESPACE(CURVES_WITH_ENDOMORPHISMS)
+
+// Namespacing symbols exported from dim2id2iso.c, id2iso.c, sign.c, torsion_constants.c:
+#undef TORSION_PLUS_2POWER
+
+#define TORSION_PLUS_2POWER SQISIGN_NAMESPACE(TORSION_PLUS_2POWER)
+
+// Namespacing symbols exported from dim2id2iso.c, quaternion_data.c:
+#undef CONNECTING_IDEALS
+
+#define CONNECTING_IDEALS SQISIGN_NAMESPACE(CONNECTING_IDEALS)
+
+// Namespacing symbols exported from dim4.c:
+#undef ibz_inv_dim4_make_coeff_mpm
+#undef ibz_inv_dim4_make_coeff_pmp
+#undef ibz_mat_4x4_copy
+#undef ibz_mat_4x4_equal
+#undef ibz_mat_4x4_eval
+#undef ibz_mat_4x4_eval_t
+#undef ibz_mat_4x4_gcd
+#undef ibz_mat_4x4_identity
+#undef ibz_mat_4x4_inv_with_det_as_denom
+#undef ibz_mat_4x4_is_identity
+#undef ibz_mat_4x4_mul
+#undef ibz_mat_4x4_negate
+#undef ibz_mat_4x4_scalar_div
+#undef ibz_mat_4x4_scalar_mul
+#undef ibz_mat_4x4_transpose
+#undef ibz_mat_4x4_zero
+#undef ibz_vec_4_add
+#undef ibz_vec_4_content
+#undef ibz_vec_4_copy
+#undef ibz_vec_4_copy_ibz
+#undef ibz_vec_4_is_zero
+#undef ibz_vec_4_linear_combination
+#undef ibz_vec_4_negate
+#undef ibz_vec_4_scalar_div
+#undef ibz_vec_4_scalar_mul
+#undef ibz_vec_4_set
+#undef ibz_vec_4_sub
+#undef quat_qf_eval
+
+#define ibz_inv_dim4_make_coeff_mpm SQISIGN_NAMESPACE(ibz_inv_dim4_make_coeff_mpm)
+#define ibz_inv_dim4_make_coeff_pmp SQISIGN_NAMESPACE(ibz_inv_dim4_make_coeff_pmp)
+#define ibz_mat_4x4_copy SQISIGN_NAMESPACE(ibz_mat_4x4_copy)
+#define ibz_mat_4x4_equal SQISIGN_NAMESPACE(ibz_mat_4x4_equal)
+#define ibz_mat_4x4_eval SQISIGN_NAMESPACE(ibz_mat_4x4_eval)
+#define ibz_mat_4x4_eval_t SQISIGN_NAMESPACE(ibz_mat_4x4_eval_t)
+#define ibz_mat_4x4_gcd SQISIGN_NAMESPACE(ibz_mat_4x4_gcd)
+#define ibz_mat_4x4_identity SQISIGN_NAMESPACE(ibz_mat_4x4_identity)
+#define ibz_mat_4x4_inv_with_det_as_denom SQISIGN_NAMESPACE(ibz_mat_4x4_inv_with_det_as_denom)
+#define ibz_mat_4x4_is_identity SQISIGN_NAMESPACE(ibz_mat_4x4_is_identity)
+#define ibz_mat_4x4_mul SQISIGN_NAMESPACE(ibz_mat_4x4_mul)
+#define ibz_mat_4x4_negate SQISIGN_NAMESPACE(ibz_mat_4x4_negate)
+#define ibz_mat_4x4_scalar_div SQISIGN_NAMESPACE(ibz_mat_4x4_scalar_div)
+#define ibz_mat_4x4_scalar_mul SQISIGN_NAMESPACE(ibz_mat_4x4_scalar_mul)
+#define ibz_mat_4x4_transpose SQISIGN_NAMESPACE(ibz_mat_4x4_transpose)
+#define ibz_mat_4x4_zero SQISIGN_NAMESPACE(ibz_mat_4x4_zero)
+#define ibz_vec_4_add SQISIGN_NAMESPACE(ibz_vec_4_add)
+#define ibz_vec_4_content SQISIGN_NAMESPACE(ibz_vec_4_content)
+#define ibz_vec_4_copy SQISIGN_NAMESPACE(ibz_vec_4_copy)
+#define ibz_vec_4_copy_ibz SQISIGN_NAMESPACE(ibz_vec_4_copy_ibz)
+#define ibz_vec_4_is_zero SQISIGN_NAMESPACE(ibz_vec_4_is_zero)
+#define ibz_vec_4_linear_combination SQISIGN_NAMESPACE(ibz_vec_4_linear_combination)
+#define ibz_vec_4_negate SQISIGN_NAMESPACE(ibz_vec_4_negate)
+#define ibz_vec_4_scalar_div SQISIGN_NAMESPACE(ibz_vec_4_scalar_div)
+#define ibz_vec_4_scalar_mul SQISIGN_NAMESPACE(ibz_vec_4_scalar_mul)
+#define ibz_vec_4_set SQISIGN_NAMESPACE(ibz_vec_4_set)
+#define ibz_vec_4_sub SQISIGN_NAMESPACE(ibz_vec_4_sub)
+#define quat_qf_eval SQISIGN_NAMESPACE(quat_qf_eval)
+
+// Namespacing symbols exported from e0_basis.c:
+#undef BASIS_E0_PX
+#undef BASIS_E0_QX
+
+#define BASIS_E0_PX SQISIGN_NAMESPACE(BASIS_E0_PX)
+#define BASIS_E0_QX SQISIGN_NAMESPACE(BASIS_E0_QX)
+
+// Namespacing symbols exported from ec.c:
+#undef cswap_points
+#undef ec_biscalar_mul
+#undef ec_curve_init
+#undef ec_curve_init_from_A
+#undef ec_curve_normalize_A24
+#undef ec_curve_verify_A
+#undef ec_dbl
+#undef ec_dbl_iter
+#undef ec_dbl_iter_basis
+#undef ec_has_zero_coordinate
+#undef ec_is_basis_four_torsion
+#undef ec_is_equal
+#undef ec_is_four_torsion
+#undef ec_is_two_torsion
+#undef ec_is_zero
+#undef ec_j_inv
+#undef ec_ladder3pt
+#undef ec_mul
+#undef ec_normalize_curve
+#undef ec_normalize_curve_and_A24
+#undef ec_normalize_point
+#undef ec_point_init
+#undef select_point
+#undef xADD
+#undef xDBL
+#undef xDBLADD
+#undef xDBLMUL
+#undef xMUL
+
+#define cswap_points SQISIGN_NAMESPACE(cswap_points)
+#define ec_biscalar_mul SQISIGN_NAMESPACE(ec_biscalar_mul)
+#define ec_curve_init SQISIGN_NAMESPACE(ec_curve_init)
+#define ec_curve_init_from_A SQISIGN_NAMESPACE(ec_curve_init_from_A)
+#define ec_curve_normalize_A24 SQISIGN_NAMESPACE(ec_curve_normalize_A24)
+#define ec_curve_verify_A SQISIGN_NAMESPACE(ec_curve_verify_A)
+#define ec_dbl SQISIGN_NAMESPACE(ec_dbl)
+#define ec_dbl_iter SQISIGN_NAMESPACE(ec_dbl_iter)
+#define ec_dbl_iter_basis SQISIGN_NAMESPACE(ec_dbl_iter_basis)
+#define ec_has_zero_coordinate SQISIGN_NAMESPACE(ec_has_zero_coordinate)
+#define ec_is_basis_four_torsion SQISIGN_NAMESPACE(ec_is_basis_four_torsion)
+#define ec_is_equal SQISIGN_NAMESPACE(ec_is_equal)
+#define ec_is_four_torsion SQISIGN_NAMESPACE(ec_is_four_torsion)
+#define ec_is_two_torsion SQISIGN_NAMESPACE(ec_is_two_torsion)
+#define ec_is_zero SQISIGN_NAMESPACE(ec_is_zero)
+#define ec_j_inv SQISIGN_NAMESPACE(ec_j_inv)
+#define ec_ladder3pt SQISIGN_NAMESPACE(ec_ladder3pt)
+#define ec_mul SQISIGN_NAMESPACE(ec_mul)
+#define ec_normalize_curve SQISIGN_NAMESPACE(ec_normalize_curve)
+#define ec_normalize_curve_and_A24 SQISIGN_NAMESPACE(ec_normalize_curve_and_A24)
+#define ec_normalize_point SQISIGN_NAMESPACE(ec_normalize_point)
+#define ec_point_init SQISIGN_NAMESPACE(ec_point_init)
+#define select_point SQISIGN_NAMESPACE(select_point)
+#define xADD SQISIGN_NAMESPACE(xADD)
+#define xDBL SQISIGN_NAMESPACE(xDBL)
+#define xDBLADD SQISIGN_NAMESPACE(xDBLADD)
+#define xDBLMUL SQISIGN_NAMESPACE(xDBLMUL)
+#define xMUL SQISIGN_NAMESPACE(xMUL)
+
+// Namespacing symbols exported from ec_jac.c:
+#undef copy_jac_point
+#undef jac_from_ws
+#undef jac_init
+#undef jac_is_equal
+#undef jac_neg
+#undef jac_to_ws
+#undef jac_to_xz
+#undef jac_to_xz_add_components
+#undef select_jac_point
+
+#define copy_jac_point SQISIGN_NAMESPACE(copy_jac_point)
+#define jac_from_ws SQISIGN_NAMESPACE(jac_from_ws)
+#define jac_init SQISIGN_NAMESPACE(jac_init)
+#define jac_is_equal SQISIGN_NAMESPACE(jac_is_equal)
+#define jac_neg SQISIGN_NAMESPACE(jac_neg)
+#define jac_to_ws SQISIGN_NAMESPACE(jac_to_ws)
+#define jac_to_xz SQISIGN_NAMESPACE(jac_to_xz)
+#define jac_to_xz_add_components SQISIGN_NAMESPACE(jac_to_xz_add_components)
+#define select_jac_point SQISIGN_NAMESPACE(select_jac_point)
+
+// Namespacing symbols exported from ec_jac.c, hd.c:
+#undef DBLW
+
+#define DBLW SQISIGN_NAMESPACE(DBLW)
+
+// Namespacing symbols exported from ec_jac.c, hd.c, theta_isogenies.c:
+#undef DBL
+
+#define DBL SQISIGN_NAMESPACE(DBL)
+
+// Namespacing symbols exported from ec_params.c:
+#undef p_cofactor_for_2f
+
+#define p_cofactor_for_2f SQISIGN_NAMESPACE(p_cofactor_for_2f)
+
+// Namespacing symbols exported from encode_signature.c:
+#undef secret_key_from_bytes
+#undef secret_key_to_bytes
+
+#define secret_key_from_bytes SQISIGN_NAMESPACE(secret_key_from_bytes)
+#define secret_key_to_bytes SQISIGN_NAMESPACE(secret_key_to_bytes)
+
+// Namespacing symbols exported from encode_verification.c:
+#undef public_key_from_bytes
+#undef public_key_to_bytes
+#undef signature_from_bytes
+#undef signature_to_bytes
+
+#define public_key_from_bytes SQISIGN_NAMESPACE(public_key_from_bytes)
+#define public_key_to_bytes SQISIGN_NAMESPACE(public_key_to_bytes)
+#define signature_from_bytes SQISIGN_NAMESPACE(signature_from_bytes)
+#define signature_to_bytes SQISIGN_NAMESPACE(signature_to_bytes)
+
+// Namespacing symbols exported from finit.c:
+#undef ibz_mat_2x2_finalize
+#undef ibz_mat_2x2_init
+#undef ibz_mat_4x4_finalize
+#undef ibz_mat_4x4_init
+#undef ibz_vec_2_finalize
+#undef ibz_vec_2_init
+#undef ibz_vec_4_finalize
+#undef ibz_vec_4_init
+#undef quat_alg_elem_finalize
+#undef quat_alg_elem_init
+#undef quat_alg_finalize
+#undef quat_alg_init_set
+#undef quat_lattice_finalize
+#undef quat_lattice_init
+#undef quat_left_ideal_finalize
+#undef quat_left_ideal_init
+
+#define ibz_mat_2x2_finalize SQISIGN_NAMESPACE(ibz_mat_2x2_finalize)
+#define ibz_mat_2x2_init SQISIGN_NAMESPACE(ibz_mat_2x2_init)
+#define ibz_mat_4x4_finalize SQISIGN_NAMESPACE(ibz_mat_4x4_finalize)
+#define ibz_mat_4x4_init SQISIGN_NAMESPACE(ibz_mat_4x4_init)
+#define ibz_vec_2_finalize SQISIGN_NAMESPACE(ibz_vec_2_finalize)
+#define ibz_vec_2_init SQISIGN_NAMESPACE(ibz_vec_2_init)
+#define ibz_vec_4_finalize SQISIGN_NAMESPACE(ibz_vec_4_finalize)
+#define ibz_vec_4_init SQISIGN_NAMESPACE(ibz_vec_4_init)
+#define quat_alg_elem_finalize SQISIGN_NAMESPACE(quat_alg_elem_finalize)
+#define quat_alg_elem_init SQISIGN_NAMESPACE(quat_alg_elem_init)
+#define quat_alg_finalize SQISIGN_NAMESPACE(quat_alg_finalize)
+#define quat_alg_init_set SQISIGN_NAMESPACE(quat_alg_init_set)
+#define quat_lattice_finalize SQISIGN_NAMESPACE(quat_lattice_finalize)
+#define quat_lattice_init SQISIGN_NAMESPACE(quat_lattice_init)
+#define quat_left_ideal_finalize SQISIGN_NAMESPACE(quat_left_ideal_finalize)
+#define quat_left_ideal_init SQISIGN_NAMESPACE(quat_left_ideal_init)
+
+// Namespacing symbols exported from fp.c:
+#undef fp_select
+#undef p
+#undef p2
+
+#define fp_select SQISIGN_NAMESPACE(fp_select)
+#define p SQISIGN_NAMESPACE(p)
+#define p2 SQISIGN_NAMESPACE(p2)
+
+// Namespacing symbols exported from fp.c, fp_p27500_64.c, fp_p5248_64.c, fp_p65376_64.c:
+#undef fp_exp3div4
+#undef fp_inv
+#undef fp_is_square
+#undef fp_sqrt
+
+#define fp_exp3div4 SQISIGN_NAMESPACE(fp_exp3div4)
+#define fp_inv SQISIGN_NAMESPACE(fp_inv)
+#define fp_is_square SQISIGN_NAMESPACE(fp_is_square)
+#define fp_sqrt SQISIGN_NAMESPACE(fp_sqrt)
+
+// Namespacing symbols exported from fp2.c:
+#undef fp2_add
+#undef fp2_add_one
+#undef fp2_batched_inv
+#undef fp2_copy
+#undef fp2_cswap
+#undef fp2_decode
+#undef fp2_encode
+#undef fp2_half
+#undef fp2_inv
+#undef fp2_is_equal
+#undef fp2_is_one
+#undef fp2_is_square
+#undef fp2_is_zero
+#undef fp2_mul
+#undef fp2_mul_small
+#undef fp2_neg
+#undef fp2_pow_vartime
+#undef fp2_print
+#undef fp2_select
+#undef fp2_set_one
+#undef fp2_set_small
+#undef fp2_set_zero
+#undef fp2_sqr
+#undef fp2_sqrt
+#undef fp2_sqrt_verify
+#undef fp2_sub
+
+#define fp2_add SQISIGN_NAMESPACE(fp2_add)
+#define fp2_add_one SQISIGN_NAMESPACE(fp2_add_one)
+#define fp2_batched_inv SQISIGN_NAMESPACE(fp2_batched_inv)
+#define fp2_copy SQISIGN_NAMESPACE(fp2_copy)
+#define fp2_cswap SQISIGN_NAMESPACE(fp2_cswap)
+#define fp2_decode SQISIGN_NAMESPACE(fp2_decode)
+#define fp2_encode SQISIGN_NAMESPACE(fp2_encode)
+#define fp2_half SQISIGN_NAMESPACE(fp2_half)
+#define fp2_inv SQISIGN_NAMESPACE(fp2_inv)
+#define fp2_is_equal SQISIGN_NAMESPACE(fp2_is_equal)
+#define fp2_is_one SQISIGN_NAMESPACE(fp2_is_one)
+#define fp2_is_square SQISIGN_NAMESPACE(fp2_is_square)
+#define fp2_is_zero SQISIGN_NAMESPACE(fp2_is_zero)
+#define fp2_mul SQISIGN_NAMESPACE(fp2_mul)
+#define fp2_mul_small SQISIGN_NAMESPACE(fp2_mul_small)
+#define fp2_neg SQISIGN_NAMESPACE(fp2_neg)
+#define fp2_pow_vartime SQISIGN_NAMESPACE(fp2_pow_vartime)
+#define fp2_print SQISIGN_NAMESPACE(fp2_print)
+#define fp2_select SQISIGN_NAMESPACE(fp2_select)
+#define fp2_set_one SQISIGN_NAMESPACE(fp2_set_one)
+#define fp2_set_small SQISIGN_NAMESPACE(fp2_set_small)
+#define fp2_set_zero SQISIGN_NAMESPACE(fp2_set_zero)
+#define fp2_sqr SQISIGN_NAMESPACE(fp2_sqr)
+#define fp2_sqrt SQISIGN_NAMESPACE(fp2_sqrt)
+#define fp2_sqrt_verify SQISIGN_NAMESPACE(fp2_sqrt_verify)
+#define fp2_sub SQISIGN_NAMESPACE(fp2_sub)
+
+// Namespacing symbols exported from fp_p27500_64.c, fp_p5248_64.c, fp_p65376_64.c:
+#undef fp_copy
+#undef fp_cswap
+#undef fp_decode
+#undef fp_decode_reduce
+#undef fp_div3
+#undef fp_encode
+#undef fp_half
+#undef fp_is_equal
+#undef fp_is_zero
+#undef fp_mul_small
+#undef fp_neg
+#undef fp_set_one
+#undef fp_set_small
+#undef fp_set_zero
+
+#define fp_copy SQISIGN_NAMESPACE(fp_copy)
+#define fp_cswap SQISIGN_NAMESPACE(fp_cswap)
+#define fp_decode SQISIGN_NAMESPACE(fp_decode)
+#define fp_decode_reduce SQISIGN_NAMESPACE(fp_decode_reduce)
+#define fp_div3 SQISIGN_NAMESPACE(fp_div3)
+#define fp_encode SQISIGN_NAMESPACE(fp_encode)
+#define fp_half SQISIGN_NAMESPACE(fp_half)
+#define fp_is_equal SQISIGN_NAMESPACE(fp_is_equal)
+#define fp_is_zero SQISIGN_NAMESPACE(fp_is_zero)
+#define fp_mul_small SQISIGN_NAMESPACE(fp_mul_small)
+#define fp_neg SQISIGN_NAMESPACE(fp_neg)
+#define fp_set_one SQISIGN_NAMESPACE(fp_set_one)
+#define fp_set_small SQISIGN_NAMESPACE(fp_set_small)
+#define fp_set_zero SQISIGN_NAMESPACE(fp_set_zero)
+
+// Namespacing symbols exported from fp_p27500_64.c, fp_p5248_64.c, fp_p65376_64.c, gf27500.c, gf5248.c, gf65376.c:
+#undef ONE
+#undef ZERO
+#undef fp_add
+#undef fp_mul
+#undef fp_sqr
+#undef fp_sub
+
+#define ONE SQISIGN_NAMESPACE(ONE)
+#define ZERO SQISIGN_NAMESPACE(ZERO)
+#define fp_add SQISIGN_NAMESPACE(fp_add)
+#define fp_mul SQISIGN_NAMESPACE(fp_mul)
+#define fp_sqr SQISIGN_NAMESPACE(fp_sqr)
+#define fp_sub SQISIGN_NAMESPACE(fp_sub)
+
+// Namespacing symbols exported from gf27500.c:
+#undef gf27500_MINUS_ONE
+#undef gf27500_decode
+#undef gf27500_decode_reduce
+#undef gf27500_div
+#undef gf27500_div3
+#undef gf27500_encode
+#undef gf27500_invert
+#undef gf27500_legendre
+#undef gf27500_sqrt
+
+#define gf27500_MINUS_ONE SQISIGN_NAMESPACE(gf27500_MINUS_ONE)
+#define gf27500_decode SQISIGN_NAMESPACE(gf27500_decode)
+#define gf27500_decode_reduce SQISIGN_NAMESPACE(gf27500_decode_reduce)
+#define gf27500_div SQISIGN_NAMESPACE(gf27500_div)
+#define gf27500_div3 SQISIGN_NAMESPACE(gf27500_div3)
+#define gf27500_encode SQISIGN_NAMESPACE(gf27500_encode)
+#define gf27500_invert SQISIGN_NAMESPACE(gf27500_invert)
+#define gf27500_legendre SQISIGN_NAMESPACE(gf27500_legendre)
+#define gf27500_sqrt SQISIGN_NAMESPACE(gf27500_sqrt)
+
+// Namespacing symbols exported from gf27500.c, gf5248.c, gf65376.c:
+#undef fp2_mul_c0
+#undef fp2_mul_c1
+#undef fp2_sq_c0
+#undef fp2_sq_c1
+
+#define fp2_mul_c0 SQISIGN_NAMESPACE(fp2_mul_c0)
+#define fp2_mul_c1 SQISIGN_NAMESPACE(fp2_mul_c1)
+#define fp2_sq_c0 SQISIGN_NAMESPACE(fp2_sq_c0)
+#define fp2_sq_c1 SQISIGN_NAMESPACE(fp2_sq_c1)
+
+// Namespacing symbols exported from gf5248.c:
+#undef gf5248_MINUS_ONE
+#undef gf5248_decode
+#undef gf5248_decode_reduce
+#undef gf5248_div
+#undef gf5248_div3
+#undef gf5248_encode
+#undef gf5248_invert
+#undef gf5248_legendre
+#undef gf5248_sqrt
+
+#define gf5248_MINUS_ONE SQISIGN_NAMESPACE(gf5248_MINUS_ONE)
+#define gf5248_decode SQISIGN_NAMESPACE(gf5248_decode)
+#define gf5248_decode_reduce SQISIGN_NAMESPACE(gf5248_decode_reduce)
+#define gf5248_div SQISIGN_NAMESPACE(gf5248_div)
+#define gf5248_div3 SQISIGN_NAMESPACE(gf5248_div3)
+#define gf5248_encode SQISIGN_NAMESPACE(gf5248_encode)
+#define gf5248_invert SQISIGN_NAMESPACE(gf5248_invert)
+#define gf5248_legendre SQISIGN_NAMESPACE(gf5248_legendre)
+#define gf5248_sqrt SQISIGN_NAMESPACE(gf5248_sqrt)
+
+// Namespacing symbols exported from gf65376.c:
+#undef gf65376_MINUS_ONE
+#undef gf65376_decode
+#undef gf65376_decode_reduce
+#undef gf65376_div
+#undef gf65376_div3
+#undef gf65376_encode
+#undef gf65376_invert
+#undef gf65376_legendre
+#undef gf65376_sqrt
+
+#define gf65376_MINUS_ONE SQISIGN_NAMESPACE(gf65376_MINUS_ONE)
+#define gf65376_decode SQISIGN_NAMESPACE(gf65376_decode)
+#define gf65376_decode_reduce SQISIGN_NAMESPACE(gf65376_decode_reduce)
+#define gf65376_div SQISIGN_NAMESPACE(gf65376_div)
+#define gf65376_div3 SQISIGN_NAMESPACE(gf65376_div3)
+#define gf65376_encode SQISIGN_NAMESPACE(gf65376_encode)
+#define gf65376_invert SQISIGN_NAMESPACE(gf65376_invert)
+#define gf65376_legendre SQISIGN_NAMESPACE(gf65376_legendre)
+#define gf65376_sqrt SQISIGN_NAMESPACE(gf65376_sqrt)
+
+// Namespacing symbols exported from hd.c:
+#undef add_couple_jac_points
+#undef copy_bases_to_kernel
+#undef couple_jac_to_xz
+#undef double_couple_jac_point
+#undef double_couple_jac_point_iter
+#undef double_couple_point
+#undef double_couple_point_iter
+
+#define add_couple_jac_points SQISIGN_NAMESPACE(add_couple_jac_points)
+#define copy_bases_to_kernel SQISIGN_NAMESPACE(copy_bases_to_kernel)
+#define couple_jac_to_xz SQISIGN_NAMESPACE(couple_jac_to_xz)
+#define double_couple_jac_point SQISIGN_NAMESPACE(double_couple_jac_point)
+#define double_couple_jac_point_iter SQISIGN_NAMESPACE(double_couple_jac_point_iter)
+#define double_couple_point SQISIGN_NAMESPACE(double_couple_point)
+#define double_couple_point_iter SQISIGN_NAMESPACE(double_couple_point_iter)
+
+// Namespacing symbols exported from hd_splitting_transforms.c:
+#undef CHI_EVAL
+
+#define CHI_EVAL SQISIGN_NAMESPACE(CHI_EVAL)
+
+// Namespacing symbols exported from hd_splitting_transforms.c, theta_isogenies.c:
+#undef EVEN_INDEX
+#undef FP2_CONSTANTS
+#undef NORMALIZATION_TRANSFORMS
+#undef SPLITTING_TRANSFORMS
+
+#define EVEN_INDEX SQISIGN_NAMESPACE(EVEN_INDEX)
+#define FP2_CONSTANTS SQISIGN_NAMESPACE(FP2_CONSTANTS)
+#define NORMALIZATION_TRANSFORMS SQISIGN_NAMESPACE(NORMALIZATION_TRANSFORMS)
+#define SPLITTING_TRANSFORMS SQISIGN_NAMESPACE(SPLITTING_TRANSFORMS)
+
+// Namespacing symbols exported from hnf.c:
+#undef ibz_mat_4x4_is_hnf
+#undef ibz_mat_4xn_hnf_mod_core
+#undef ibz_vec_4_copy_mod
+#undef ibz_vec_4_linear_combination_mod
+#undef ibz_vec_4_scalar_mul_mod
+
+#define ibz_mat_4x4_is_hnf SQISIGN_NAMESPACE(ibz_mat_4x4_is_hnf)
+#define ibz_mat_4xn_hnf_mod_core SQISIGN_NAMESPACE(ibz_mat_4xn_hnf_mod_core)
+#define ibz_vec_4_copy_mod SQISIGN_NAMESPACE(ibz_vec_4_copy_mod)
+#define ibz_vec_4_linear_combination_mod SQISIGN_NAMESPACE(ibz_vec_4_linear_combination_mod)
+#define ibz_vec_4_scalar_mul_mod SQISIGN_NAMESPACE(ibz_vec_4_scalar_mul_mod)
+
+// Namespacing symbols exported from hnf_internal.c:
+#undef ibz_centered_mod
+#undef ibz_conditional_assign
+#undef ibz_mod_not_zero
+#undef ibz_xgcd_with_u_not_0
+
+#define ibz_centered_mod SQISIGN_NAMESPACE(ibz_centered_mod)
+#define ibz_conditional_assign SQISIGN_NAMESPACE(ibz_conditional_assign)
+#define ibz_mod_not_zero SQISIGN_NAMESPACE(ibz_mod_not_zero)
+#define ibz_xgcd_with_u_not_0 SQISIGN_NAMESPACE(ibz_xgcd_with_u_not_0)
+
+// Namespacing symbols exported from ibz_division.c:
+#undef ibz_xgcd
+
+#define ibz_xgcd SQISIGN_NAMESPACE(ibz_xgcd)
+
+// Namespacing symbols exported from id2iso.c:
+#undef change_of_basis_matrix_tate
+#undef change_of_basis_matrix_tate_invert
+#undef ec_biscalar_mul_ibz_vec
+#undef endomorphism_application_even_basis
+#undef id2iso_ideal_to_kernel_dlogs_even
+#undef id2iso_kernel_dlogs_to_ideal_even
+#undef matrix_application_even_basis
+
+#define change_of_basis_matrix_tate SQISIGN_NAMESPACE(change_of_basis_matrix_tate)
+#define change_of_basis_matrix_tate_invert SQISIGN_NAMESPACE(change_of_basis_matrix_tate_invert)
+#define ec_biscalar_mul_ibz_vec SQISIGN_NAMESPACE(ec_biscalar_mul_ibz_vec)
+#define endomorphism_application_even_basis SQISIGN_NAMESPACE(endomorphism_application_even_basis)
+#define id2iso_ideal_to_kernel_dlogs_even SQISIGN_NAMESPACE(id2iso_ideal_to_kernel_dlogs_even)
+#define id2iso_kernel_dlogs_to_ideal_even SQISIGN_NAMESPACE(id2iso_kernel_dlogs_to_ideal_even)
+#define matrix_application_even_basis SQISIGN_NAMESPACE(matrix_application_even_basis)
+
+// Namespacing symbols exported from ideal.c:
+#undef quat_lideal_add
+#undef quat_lideal_class_gram
+#undef quat_lideal_conjugate_without_hnf
+#undef quat_lideal_copy
+#undef quat_lideal_create
+#undef quat_lideal_create_principal
+#undef quat_lideal_equals
+#undef quat_lideal_generator
+#undef quat_lideal_inter
+#undef quat_lideal_inverse_lattice_without_hnf
+#undef quat_lideal_mul
+#undef quat_lideal_norm
+#undef quat_lideal_right_order
+#undef quat_lideal_right_transporter
+#undef quat_order_discriminant
+#undef quat_order_is_maximal
+
+#define quat_lideal_add SQISIGN_NAMESPACE(quat_lideal_add)
+#define quat_lideal_class_gram SQISIGN_NAMESPACE(quat_lideal_class_gram)
+#define quat_lideal_conjugate_without_hnf SQISIGN_NAMESPACE(quat_lideal_conjugate_without_hnf)
+#define quat_lideal_copy SQISIGN_NAMESPACE(quat_lideal_copy)
+#define quat_lideal_create SQISIGN_NAMESPACE(quat_lideal_create)
+#define quat_lideal_create_principal SQISIGN_NAMESPACE(quat_lideal_create_principal)
+#define quat_lideal_equals SQISIGN_NAMESPACE(quat_lideal_equals)
+#define quat_lideal_generator SQISIGN_NAMESPACE(quat_lideal_generator)
+#define quat_lideal_inter SQISIGN_NAMESPACE(quat_lideal_inter)
+#define quat_lideal_inverse_lattice_without_hnf SQISIGN_NAMESPACE(quat_lideal_inverse_lattice_without_hnf)
+#define quat_lideal_mul SQISIGN_NAMESPACE(quat_lideal_mul)
+#define quat_lideal_norm SQISIGN_NAMESPACE(quat_lideal_norm)
+#define quat_lideal_right_order SQISIGN_NAMESPACE(quat_lideal_right_order)
+#define quat_lideal_right_transporter SQISIGN_NAMESPACE(quat_lideal_right_transporter)
+#define quat_order_discriminant SQISIGN_NAMESPACE(quat_order_discriminant)
+#define quat_order_is_maximal SQISIGN_NAMESPACE(quat_order_is_maximal)
+
+// Namespacing symbols exported from intbig.c:
+#undef ibz_abs
+#undef ibz_add
+#undef ibz_bitsize
+#undef ibz_cmp
+#undef ibz_cmp_int32
+#undef ibz_const_one
+#undef ibz_const_three
+#undef ibz_const_two
+#undef ibz_const_zero
+#undef ibz_convert_to_str
+#undef ibz_copy
+#undef ibz_copy_digits
+#undef ibz_div
+#undef ibz_div_2exp
+#undef ibz_div_floor
+#undef ibz_divides
+#undef ibz_finalize
+#undef ibz_gcd
+#undef ibz_get
+#undef ibz_init
+#undef ibz_invmod
+#undef ibz_is_even
+#undef ibz_is_odd
+#undef ibz_is_one
+#undef ibz_is_zero
+#undef ibz_legendre
+#undef ibz_mod
+#undef ibz_mod_ui
+#undef ibz_mul
+#undef ibz_neg
+#undef ibz_pow
+#undef ibz_pow_mod
+#undef ibz_print
+#undef ibz_probab_prime
+#undef ibz_rand_interval
+#undef ibz_rand_interval_bits
+#undef ibz_rand_interval_i
+#undef ibz_rand_interval_minm_m
+#undef ibz_set
+#undef ibz_set_from_str
+#undef ibz_size_in_base
+#undef ibz_sqrt
+#undef ibz_sqrt_floor
+#undef ibz_sqrt_mod_p
+#undef ibz_sub
+#undef ibz_swap
+#undef ibz_to_digits
+#undef ibz_two_adic
+
+#define ibz_abs SQISIGN_NAMESPACE(ibz_abs)
+#define ibz_add SQISIGN_NAMESPACE(ibz_add)
+#define ibz_bitsize SQISIGN_NAMESPACE(ibz_bitsize)
+#define ibz_cmp SQISIGN_NAMESPACE(ibz_cmp)
+#define ibz_cmp_int32 SQISIGN_NAMESPACE(ibz_cmp_int32)
+#define ibz_const_one SQISIGN_NAMESPACE(ibz_const_one)
+#define ibz_const_three SQISIGN_NAMESPACE(ibz_const_three)
+#define ibz_const_two SQISIGN_NAMESPACE(ibz_const_two)
+#define ibz_const_zero SQISIGN_NAMESPACE(ibz_const_zero)
+#define ibz_convert_to_str SQISIGN_NAMESPACE(ibz_convert_to_str)
+#define ibz_copy SQISIGN_NAMESPACE(ibz_copy)
+#define ibz_copy_digits SQISIGN_NAMESPACE(ibz_copy_digits)
+#define ibz_div SQISIGN_NAMESPACE(ibz_div)
+#define ibz_div_2exp SQISIGN_NAMESPACE(ibz_div_2exp)
+#define ibz_div_floor SQISIGN_NAMESPACE(ibz_div_floor)
+#define ibz_divides SQISIGN_NAMESPACE(ibz_divides)
+#define ibz_finalize SQISIGN_NAMESPACE(ibz_finalize)
+#define ibz_gcd SQISIGN_NAMESPACE(ibz_gcd)
+#define ibz_get SQISIGN_NAMESPACE(ibz_get)
+#define ibz_init SQISIGN_NAMESPACE(ibz_init)
+#define ibz_invmod SQISIGN_NAMESPACE(ibz_invmod)
+#define ibz_is_even SQISIGN_NAMESPACE(ibz_is_even)
+#define ibz_is_odd SQISIGN_NAMESPACE(ibz_is_odd)
+#define ibz_is_one SQISIGN_NAMESPACE(ibz_is_one)
+#define ibz_is_zero SQISIGN_NAMESPACE(ibz_is_zero)
+#define ibz_legendre SQISIGN_NAMESPACE(ibz_legendre)
+#define ibz_mod SQISIGN_NAMESPACE(ibz_mod)
+#define ibz_mod_ui SQISIGN_NAMESPACE(ibz_mod_ui)
+#define ibz_mul SQISIGN_NAMESPACE(ibz_mul)
+#define ibz_neg SQISIGN_NAMESPACE(ibz_neg)
+#define ibz_pow SQISIGN_NAMESPACE(ibz_pow)
+#define ibz_pow_mod SQISIGN_NAMESPACE(ibz_pow_mod)
+#define ibz_print SQISIGN_NAMESPACE(ibz_print)
+#define ibz_probab_prime SQISIGN_NAMESPACE(ibz_probab_prime)
+#define ibz_rand_interval SQISIGN_NAMESPACE(ibz_rand_interval)
+#define ibz_rand_interval_bits SQISIGN_NAMESPACE(ibz_rand_interval_bits)
+#define ibz_rand_interval_i SQISIGN_NAMESPACE(ibz_rand_interval_i)
+#define ibz_rand_interval_minm_m SQISIGN_NAMESPACE(ibz_rand_interval_minm_m)
+#define ibz_set SQISIGN_NAMESPACE(ibz_set)
+#define ibz_set_from_str SQISIGN_NAMESPACE(ibz_set_from_str)
+#define ibz_size_in_base SQISIGN_NAMESPACE(ibz_size_in_base)
+#define ibz_sqrt SQISIGN_NAMESPACE(ibz_sqrt)
+#define ibz_sqrt_floor SQISIGN_NAMESPACE(ibz_sqrt_floor)
+#define ibz_sqrt_mod_p SQISIGN_NAMESPACE(ibz_sqrt_mod_p)
+#define ibz_sub SQISIGN_NAMESPACE(ibz_sub)
+#define ibz_swap SQISIGN_NAMESPACE(ibz_swap)
+#define ibz_to_digits SQISIGN_NAMESPACE(ibz_to_digits)
+#define ibz_two_adic SQISIGN_NAMESPACE(ibz_two_adic)
+
+// Namespacing symbols exported from integers.c:
+#undef ibz_cornacchia_prime
+#undef ibz_generate_random_prime
+
+#define ibz_cornacchia_prime SQISIGN_NAMESPACE(ibz_cornacchia_prime)
+#define ibz_generate_random_prime SQISIGN_NAMESPACE(ibz_generate_random_prime)
+
+// Namespacing symbols exported from isog_chains.c:
+#undef ec_eval_even
+#undef ec_eval_small_chain
+#undef ec_iso_eval
+#undef ec_isomorphism
+
+#define ec_eval_even SQISIGN_NAMESPACE(ec_eval_even)
+#define ec_eval_small_chain SQISIGN_NAMESPACE(ec_eval_small_chain)
+#define ec_iso_eval SQISIGN_NAMESPACE(ec_iso_eval)
+#define ec_isomorphism SQISIGN_NAMESPACE(ec_isomorphism)
+
+// Namespacing symbols exported from keygen.c:
+#undef protocols_keygen
+#undef secret_key_finalize
+#undef secret_key_init
+
+#define protocols_keygen SQISIGN_NAMESPACE(protocols_keygen)
+#define secret_key_finalize SQISIGN_NAMESPACE(secret_key_finalize)
+#define secret_key_init SQISIGN_NAMESPACE(secret_key_init)
+
+// Namespacing symbols exported from keygen.c, torsion_constants.c:
+#undef SEC_DEGREE
+
+#define SEC_DEGREE SQISIGN_NAMESPACE(SEC_DEGREE)
+
+// Namespacing symbols exported from l2.c:
+#undef quat_lattice_lll
+#undef quat_lll_core
+
+#define quat_lattice_lll SQISIGN_NAMESPACE(quat_lattice_lll)
+#define quat_lll_core SQISIGN_NAMESPACE(quat_lll_core)
+
+// Namespacing symbols exported from lat_ball.c:
+#undef quat_lattice_bound_parallelogram
+#undef quat_lattice_sample_from_ball
+
+#define quat_lattice_bound_parallelogram SQISIGN_NAMESPACE(quat_lattice_bound_parallelogram)
+#define quat_lattice_sample_from_ball SQISIGN_NAMESPACE(quat_lattice_sample_from_ball)
+
+// Namespacing symbols exported from lattice.c:
+#undef quat_lattice_add
+#undef quat_lattice_alg_elem_mul
+#undef quat_lattice_conjugate_without_hnf
+#undef quat_lattice_contains
+#undef quat_lattice_dual_without_hnf
+#undef quat_lattice_equal
+#undef quat_lattice_gram
+#undef quat_lattice_hnf
+#undef quat_lattice_inclusion
+#undef quat_lattice_index
+#undef quat_lattice_intersect
+#undef quat_lattice_mat_alg_coord_mul_without_hnf
+#undef quat_lattice_mul
+#undef quat_lattice_reduce_denom
+
+#define quat_lattice_add SQISIGN_NAMESPACE(quat_lattice_add)
+#define quat_lattice_alg_elem_mul SQISIGN_NAMESPACE(quat_lattice_alg_elem_mul)
+#define quat_lattice_conjugate_without_hnf SQISIGN_NAMESPACE(quat_lattice_conjugate_without_hnf)
+#define quat_lattice_contains SQISIGN_NAMESPACE(quat_lattice_contains)
+#define quat_lattice_dual_without_hnf SQISIGN_NAMESPACE(quat_lattice_dual_without_hnf)
+#define quat_lattice_equal SQISIGN_NAMESPACE(quat_lattice_equal)
+#define quat_lattice_gram SQISIGN_NAMESPACE(quat_lattice_gram)
+#define quat_lattice_hnf SQISIGN_NAMESPACE(quat_lattice_hnf)
+#define quat_lattice_inclusion SQISIGN_NAMESPACE(quat_lattice_inclusion)
+#define quat_lattice_index SQISIGN_NAMESPACE(quat_lattice_index)
+#define quat_lattice_intersect SQISIGN_NAMESPACE(quat_lattice_intersect)
+#define quat_lattice_mat_alg_coord_mul_without_hnf SQISIGN_NAMESPACE(quat_lattice_mat_alg_coord_mul_without_hnf)
+#define quat_lattice_mul SQISIGN_NAMESPACE(quat_lattice_mul)
+#define quat_lattice_reduce_denom SQISIGN_NAMESPACE(quat_lattice_reduce_denom)
+
+// Namespacing symbols exported from lll_applications.c:
+#undef quat_lideal_lideal_mul_reduced
+#undef quat_lideal_prime_norm_reduced_equivalent
+#undef quat_lideal_reduce_basis
+
+#define quat_lideal_lideal_mul_reduced SQISIGN_NAMESPACE(quat_lideal_lideal_mul_reduced)
+#define quat_lideal_prime_norm_reduced_equivalent SQISIGN_NAMESPACE(quat_lideal_prime_norm_reduced_equivalent)
+#define quat_lideal_reduce_basis SQISIGN_NAMESPACE(quat_lideal_reduce_basis)
+
+// Namespacing symbols exported from lll_verification.c:
+#undef ibq_vec_4_copy_ibz
+#undef quat_lll_bilinear
+#undef quat_lll_gram_schmidt_transposed_with_ibq
+#undef quat_lll_set_ibq_parameters
+#undef quat_lll_verify
+
+#define ibq_vec_4_copy_ibz SQISIGN_NAMESPACE(ibq_vec_4_copy_ibz)
+#define quat_lll_bilinear SQISIGN_NAMESPACE(quat_lll_bilinear)
+#define quat_lll_gram_schmidt_transposed_with_ibq SQISIGN_NAMESPACE(quat_lll_gram_schmidt_transposed_with_ibq)
+#define quat_lll_set_ibq_parameters SQISIGN_NAMESPACE(quat_lll_set_ibq_parameters)
+#define quat_lll_verify SQISIGN_NAMESPACE(quat_lll_verify)
+
+// Namespacing symbols exported from mem.c:
+#undef sqisign_secure_clear
+#undef sqisign_secure_free
+
+#define sqisign_secure_clear SQISIGN_NAMESPACE(sqisign_secure_clear)
+#define sqisign_secure_free SQISIGN_NAMESPACE(sqisign_secure_free)
+
+// Namespacing symbols exported from mp.c:
+#undef MUL
+#undef mp_add
+#undef mp_compare
+#undef mp_copy
+#undef mp_inv_2e
+#undef mp_invert_matrix
+#undef mp_is_one
+#undef mp_is_zero
+#undef mp_mod_2exp
+#undef mp_mul
+#undef mp_mul2
+#undef mp_neg
+#undef mp_print
+#undef mp_shiftl
+#undef mp_shiftr
+#undef mp_sub
+#undef multiple_mp_shiftl
+#undef select_ct
+#undef swap_ct
+
+#define MUL SQISIGN_NAMESPACE(MUL)
+#define mp_add SQISIGN_NAMESPACE(mp_add)
+#define mp_compare SQISIGN_NAMESPACE(mp_compare)
+#define mp_copy SQISIGN_NAMESPACE(mp_copy)
+#define mp_inv_2e SQISIGN_NAMESPACE(mp_inv_2e)
+#define mp_invert_matrix SQISIGN_NAMESPACE(mp_invert_matrix)
+#define mp_is_one SQISIGN_NAMESPACE(mp_is_one)
+#define mp_is_zero SQISIGN_NAMESPACE(mp_is_zero)
+#define mp_mod_2exp SQISIGN_NAMESPACE(mp_mod_2exp)
+#define mp_mul SQISIGN_NAMESPACE(mp_mul)
+#define mp_mul2 SQISIGN_NAMESPACE(mp_mul2)
+#define mp_neg SQISIGN_NAMESPACE(mp_neg)
+#define mp_print SQISIGN_NAMESPACE(mp_print)
+#define mp_shiftl SQISIGN_NAMESPACE(mp_shiftl)
+#define mp_shiftr SQISIGN_NAMESPACE(mp_shiftr)
+#define mp_sub SQISIGN_NAMESPACE(mp_sub)
+#define multiple_mp_shiftl SQISIGN_NAMESPACE(multiple_mp_shiftl)
+#define select_ct SQISIGN_NAMESPACE(select_ct)
+#define swap_ct SQISIGN_NAMESPACE(swap_ct)
+
+// Namespacing symbols exported from normeq.c:
+#undef quat_change_to_O0_basis
+#undef quat_lattice_O0_set
+#undef quat_lattice_O0_set_extremal
+#undef quat_order_elem_create
+#undef quat_represent_integer
+#undef quat_sampling_random_ideal_O0_given_norm
+
+#define quat_change_to_O0_basis SQISIGN_NAMESPACE(quat_change_to_O0_basis)
+#define quat_lattice_O0_set SQISIGN_NAMESPACE(quat_lattice_O0_set)
+#define quat_lattice_O0_set_extremal SQISIGN_NAMESPACE(quat_lattice_O0_set_extremal)
+#define quat_order_elem_create SQISIGN_NAMESPACE(quat_order_elem_create)
+#define quat_represent_integer SQISIGN_NAMESPACE(quat_represent_integer)
+#define quat_sampling_random_ideal_O0_given_norm SQISIGN_NAMESPACE(quat_sampling_random_ideal_O0_given_norm)
+
+// Namespacing symbols exported from printer.c:
+#undef ibz_mat_2x2_print
+#undef ibz_mat_4x4_print
+#undef ibz_vec_2_print
+#undef ibz_vec_4_print
+#undef quat_alg_elem_print
+#undef quat_alg_print
+#undef quat_lattice_print
+#undef quat_left_ideal_print
+
+#define ibz_mat_2x2_print SQISIGN_NAMESPACE(ibz_mat_2x2_print)
+#define ibz_mat_4x4_print SQISIGN_NAMESPACE(ibz_mat_4x4_print)
+#define ibz_vec_2_print SQISIGN_NAMESPACE(ibz_vec_2_print)
+#define ibz_vec_4_print SQISIGN_NAMESPACE(ibz_vec_4_print)
+#define quat_alg_elem_print SQISIGN_NAMESPACE(quat_alg_elem_print)
+#define quat_alg_print SQISIGN_NAMESPACE(quat_alg_print)
+#define quat_lattice_print SQISIGN_NAMESPACE(quat_lattice_print)
+#define quat_left_ideal_print SQISIGN_NAMESPACE(quat_left_ideal_print)
+
+// Namespacing symbols exported from quaternion_data.c:
+#undef CONJUGATING_ELEMENTS
+
+#define CONJUGATING_ELEMENTS SQISIGN_NAMESPACE(CONJUGATING_ELEMENTS)
+
+// Namespacing symbols exported from quaternion_data.c, sign.c:
+#undef QUAT_prime_cofactor
+
+#define QUAT_prime_cofactor SQISIGN_NAMESPACE(QUAT_prime_cofactor)
+
+// Namespacing symbols exported from random_input_generation.c:
+#undef quat_test_input_random_ideal_generation
+#undef quat_test_input_random_ideal_lattice_generation
+#undef quat_test_input_random_lattice_generation
+
+#define quat_test_input_random_ideal_generation SQISIGN_NAMESPACE(quat_test_input_random_ideal_generation)
+#define quat_test_input_random_ideal_lattice_generation SQISIGN_NAMESPACE(quat_test_input_random_ideal_lattice_generation)
+#define quat_test_input_random_lattice_generation SQISIGN_NAMESPACE(quat_test_input_random_lattice_generation)
+
+// Namespacing symbols exported from rationals.c:
+#undef ibq_abs
+#undef ibq_add
+#undef ibq_cmp
+#undef ibq_copy
+#undef ibq_finalize
+#undef ibq_init
+#undef ibq_inv
+#undef ibq_is_ibz
+#undef ibq_is_one
+#undef ibq_is_zero
+#undef ibq_mat_4x4_finalize
+#undef ibq_mat_4x4_init
+#undef ibq_mat_4x4_print
+#undef ibq_mul
+#undef ibq_neg
+#undef ibq_reduce
+#undef ibq_set
+#undef ibq_sub
+#undef ibq_to_ibz
+#undef ibq_vec_4_finalize
+#undef ibq_vec_4_init
+#undef ibq_vec_4_print
+
+#define ibq_abs SQISIGN_NAMESPACE(ibq_abs)
+#define ibq_add SQISIGN_NAMESPACE(ibq_add)
+#define ibq_cmp SQISIGN_NAMESPACE(ibq_cmp)
+#define ibq_copy SQISIGN_NAMESPACE(ibq_copy)
+#define ibq_finalize SQISIGN_NAMESPACE(ibq_finalize)
+#define ibq_init SQISIGN_NAMESPACE(ibq_init)
+#define ibq_inv SQISIGN_NAMESPACE(ibq_inv)
+#define ibq_is_ibz SQISIGN_NAMESPACE(ibq_is_ibz)
+#define ibq_is_one SQISIGN_NAMESPACE(ibq_is_one)
+#define ibq_is_zero SQISIGN_NAMESPACE(ibq_is_zero)
+#define ibq_mat_4x4_finalize SQISIGN_NAMESPACE(ibq_mat_4x4_finalize)
+#define ibq_mat_4x4_init SQISIGN_NAMESPACE(ibq_mat_4x4_init)
+#define ibq_mat_4x4_print SQISIGN_NAMESPACE(ibq_mat_4x4_print)
+#define ibq_mul SQISIGN_NAMESPACE(ibq_mul)
+#define ibq_neg SQISIGN_NAMESPACE(ibq_neg)
+#define ibq_reduce SQISIGN_NAMESPACE(ibq_reduce)
+#define ibq_set SQISIGN_NAMESPACE(ibq_set)
+#define ibq_sub SQISIGN_NAMESPACE(ibq_sub)
+#define ibq_to_ibz SQISIGN_NAMESPACE(ibq_to_ibz)
+#define ibq_vec_4_finalize SQISIGN_NAMESPACE(ibq_vec_4_finalize)
+#define ibq_vec_4_init SQISIGN_NAMESPACE(ibq_vec_4_init)
+#define ibq_vec_4_print SQISIGN_NAMESPACE(ibq_vec_4_print)
+
+// Namespacing symbols exported from sign.c:
+#undef protocols_sign
+
+#define protocols_sign SQISIGN_NAMESPACE(protocols_sign)
+
+// Namespacing symbols exported from sign.c, torsion_constants.c:
+#undef COM_DEGREE
+
+#define COM_DEGREE SQISIGN_NAMESPACE(COM_DEGREE)
+
+// Namespacing symbols exported from sqisign.c:
+#undef sqisign_keypair
+#undef sqisign_open
+#undef sqisign_sign
+#undef sqisign_sign_signature
+#undef sqisign_verify
+#undef sqisign_verify_signature
+
+#define sqisign_keypair SQISIGN_NAMESPACE(sqisign_keypair)
+#define sqisign_open SQISIGN_NAMESPACE(sqisign_open)
+#define sqisign_sign SQISIGN_NAMESPACE(sqisign_sign)
+#define sqisign_sign_signature SQISIGN_NAMESPACE(sqisign_sign_signature)
+#define sqisign_verify SQISIGN_NAMESPACE(sqisign_verify)
+#define sqisign_verify_signature SQISIGN_NAMESPACE(sqisign_verify_signature)
+
+// Namespacing symbols exported from theta_isogenies.c:
+#undef theta_chain_compute_and_eval
+#undef theta_chain_compute_and_eval_randomized
+#undef theta_chain_compute_and_eval_verify
+
+#define theta_chain_compute_and_eval SQISIGN_NAMESPACE(theta_chain_compute_and_eval)
+#define theta_chain_compute_and_eval_randomized SQISIGN_NAMESPACE(theta_chain_compute_and_eval_randomized)
+#define theta_chain_compute_and_eval_verify SQISIGN_NAMESPACE(theta_chain_compute_and_eval_verify)
+
+// Namespacing symbols exported from theta_structure.c:
+#undef double_iter
+#undef double_point
+#undef is_product_theta_point
+#undef theta_precomputation
+
+#define double_iter SQISIGN_NAMESPACE(double_iter)
+#define double_point SQISIGN_NAMESPACE(double_point)
+#define is_product_theta_point SQISIGN_NAMESPACE(is_product_theta_point)
+#define theta_precomputation SQISIGN_NAMESPACE(theta_precomputation)
+
+// Namespacing symbols exported from torsion_constants.c:
+#undef TWO_TO_SECURITY_BITS
+
+#define TWO_TO_SECURITY_BITS SQISIGN_NAMESPACE(TWO_TO_SECURITY_BITS)
+
+// Namespacing symbols exported from verify.c:
+#undef protocols_verify
+
+#define protocols_verify SQISIGN_NAMESPACE(protocols_verify)
+
+// Namespacing symbols exported from xeval.c:
+#undef xeval_2
+#undef xeval_2_singular
+#undef xeval_4
+
+#define xeval_2 SQISIGN_NAMESPACE(xeval_2)
+#define xeval_2_singular SQISIGN_NAMESPACE(xeval_2_singular)
+#define xeval_4 SQISIGN_NAMESPACE(xeval_4)
+
+// Namespacing symbols exported from xisog.c:
+#undef xisog_2
+#undef xisog_2_singular
+#undef xisog_4
+
+#define xisog_2 SQISIGN_NAMESPACE(xisog_2)
+#define xisog_2_singular SQISIGN_NAMESPACE(xisog_2_singular)
+#define xisog_4 SQISIGN_NAMESPACE(xisog_4)
+
+
+#endif
+
+// This file is generated by scripts/Namespace.scala, do not edit it manually!
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sqisign_parameters.txt b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sqisign_parameters.txt
new file mode 100644
index 0000000000..8a1a26a502
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/sqisign_parameters.txt
@@ -0,0 +1,3 @@
+lvl = 1
+p = 0x4ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+num_orders = 7
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_isogenies.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_isogenies.c
new file mode 100644
index 0000000000..e4fcf3caf0
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_isogenies.c
@@ -0,0 +1,1310 @@
+#include "theta_isogenies.h"
+#include
+#include
+#include
+#include
+#include
+
+// Select a base change matrix in constant time, with M1 a regular
+// base change matrix and M2 a precomputed base change matrix
+// If option = 0 then M <- M1, else if option = 0xFF...FF then M <- M2
+static inline void
+select_base_change_matrix(basis_change_matrix_t *M,
+ const basis_change_matrix_t *M1,
+ const precomp_basis_change_matrix_t *M2,
+ const uint32_t option)
+{
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ fp2_select(&M->m[i][j], &M1->m[i][j], &FP2_CONSTANTS[M2->m[i][j]], option);
+}
+
+// Set a regular base change matrix from a precomputed one
+static inline void
+set_base_change_matrix_from_precomp(basis_change_matrix_t *res, const precomp_basis_change_matrix_t *M)
+{
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ res->m[i][j] = FP2_CONSTANTS[M->m[i][j]];
+}
+
+static inline void
+choose_index_theta_point(fp2_t *res, int ind, const theta_point_t *T)
+{
+ const fp2_t *src = NULL;
+ switch (ind % 4) {
+ case 0:
+ src = &T->x;
+ break;
+ case 1:
+ src = &T->y;
+ break;
+ case 2:
+ src = &T->z;
+ break;
+ case 3:
+ src = &T->t;
+ break;
+ default:
+ assert(0);
+ }
+ fp2_copy(res, src);
+}
+
+// same as apply_isomorphism method but more efficient when the t component of P is zero.
+static void
+apply_isomorphism_general(theta_point_t *res,
+ const basis_change_matrix_t *M,
+ const theta_point_t *P,
+ const bool Pt_not_zero)
+{
+ fp2_t x1;
+ theta_point_t temp;
+
+ fp2_mul(&temp.x, &P->x, &M->m[0][0]);
+ fp2_mul(&x1, &P->y, &M->m[0][1]);
+ fp2_add(&temp.x, &temp.x, &x1);
+ fp2_mul(&x1, &P->z, &M->m[0][2]);
+ fp2_add(&temp.x, &temp.x, &x1);
+
+ fp2_mul(&temp.y, &P->x, &M->m[1][0]);
+ fp2_mul(&x1, &P->y, &M->m[1][1]);
+ fp2_add(&temp.y, &temp.y, &x1);
+ fp2_mul(&x1, &P->z, &M->m[1][2]);
+ fp2_add(&temp.y, &temp.y, &x1);
+
+ fp2_mul(&temp.z, &P->x, &M->m[2][0]);
+ fp2_mul(&x1, &P->y, &M->m[2][1]);
+ fp2_add(&temp.z, &temp.z, &x1);
+ fp2_mul(&x1, &P->z, &M->m[2][2]);
+ fp2_add(&temp.z, &temp.z, &x1);
+
+ fp2_mul(&temp.t, &P->x, &M->m[3][0]);
+ fp2_mul(&x1, &P->y, &M->m[3][1]);
+ fp2_add(&temp.t, &temp.t, &x1);
+ fp2_mul(&x1, &P->z, &M->m[3][2]);
+ fp2_add(&temp.t, &temp.t, &x1);
+
+ if (Pt_not_zero) {
+ fp2_mul(&x1, &P->t, &M->m[0][3]);
+ fp2_add(&temp.x, &temp.x, &x1);
+
+ fp2_mul(&x1, &P->t, &M->m[1][3]);
+ fp2_add(&temp.y, &temp.y, &x1);
+
+ fp2_mul(&x1, &P->t, &M->m[2][3]);
+ fp2_add(&temp.z, &temp.z, &x1);
+
+ fp2_mul(&x1, &P->t, &M->m[3][3]);
+ fp2_add(&temp.t, &temp.t, &x1);
+ }
+
+ fp2_copy(&res->x, &temp.x);
+ fp2_copy(&res->y, &temp.y);
+ fp2_copy(&res->z, &temp.z);
+ fp2_copy(&res->t, &temp.t);
+}
+
+static void
+apply_isomorphism(theta_point_t *res, const basis_change_matrix_t *M, const theta_point_t *P)
+{
+ apply_isomorphism_general(res, M, P, true);
+}
+
+// set res = M1 * M2 with matrix multiplication
+static void
+base_change_matrix_multiplication(basis_change_matrix_t *res,
+ const basis_change_matrix_t *M1,
+ const basis_change_matrix_t *M2)
+{
+ basis_change_matrix_t tmp;
+ fp2_t sum, m_ik, m_kj;
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ fp2_set_zero(&sum);
+ for (int k = 0; k < 4; k++) {
+ m_ik = M1->m[i][k];
+ m_kj = M2->m[k][j];
+ fp2_mul(&m_ik, &m_ik, &m_kj);
+ fp2_add(&sum, &sum, &m_ik);
+ }
+ tmp.m[i][j] = sum;
+ }
+ }
+ *res = tmp;
+}
+
+// compute the theta_point corresponding to the couple of point T on an elliptic product
+static void
+base_change(theta_point_t *out, const theta_gluing_t *phi, const theta_couple_point_t *T)
+{
+ theta_point_t null_point;
+
+ // null_point = (a : b : c : d)
+ // a = P1.x P2.x, b = P1.x P2.z, c = P1.z P2.x, d = P1.z P2.z
+ fp2_mul(&null_point.x, &T->P1.x, &T->P2.x);
+ fp2_mul(&null_point.y, &T->P1.x, &T->P2.z);
+ fp2_mul(&null_point.z, &T->P2.x, &T->P1.z);
+ fp2_mul(&null_point.t, &T->P1.z, &T->P2.z);
+
+ // Apply the basis change
+ apply_isomorphism(out, &phi->M, &null_point);
+}
+
+static void
+action_by_translation_z_and_det(fp2_t *z_inv, fp2_t *det_inv, const ec_point_t *P4, const ec_point_t *P2)
+{
+ // Store the Z-coordinate to invert
+ fp2_copy(z_inv, &P4->z);
+
+ // Then collect detij = xij wij - uij zij
+ fp2_t tmp;
+ fp2_mul(det_inv, &P4->x, &P2->z);
+ fp2_mul(&tmp, &P4->z, &P2->x);
+ fp2_sub(det_inv, det_inv, &tmp);
+}
+
+static void
+action_by_translation_compute_matrix(translation_matrix_t *G,
+ const ec_point_t *P4,
+ const ec_point_t *P2,
+ const fp2_t *z_inv,
+ const fp2_t *det_inv)
+{
+ fp2_t tmp;
+
+ // Gi.g10 = uij xij /detij - xij/zij
+ fp2_mul(&tmp, &P4->x, z_inv);
+ fp2_mul(&G->g10, &P4->x, &P2->x);
+ fp2_mul(&G->g10, &G->g10, det_inv);
+ fp2_sub(&G->g10, &G->g10, &tmp);
+
+ // Gi.g11 = uij zij * detij
+ fp2_mul(&G->g11, &P2->x, det_inv);
+ fp2_mul(&G->g11, &G->g11, &P4->z);
+
+ // Gi.g00 = -Gi.g11
+ fp2_neg(&G->g00, &G->g11);
+
+ // Gi.g01 = - wij zij detij
+ fp2_mul(&G->g01, &P2->z, det_inv);
+ fp2_mul(&G->g01, &G->g01, &P4->z);
+ fp2_neg(&G->g01, &G->g01);
+}
+
+// Returns 1 if the basis is as expected and 0 otherwise
+// We only expect this to fail for malformed signatures, so
+// do not require this to run in constant time.
+static int
+verify_two_torsion(const theta_couple_point_t *K1_2, const theta_couple_point_t *K2_2, const theta_couple_curve_t *E12)
+{
+ // First check if any point in K1_2 or K2_2 is zero, if they are then the points did not have
+ // order 8 when we started gluing
+ if (ec_is_zero(&K1_2->P1) | ec_is_zero(&K1_2->P2) | ec_is_zero(&K2_2->P1) | ec_is_zero(&K2_2->P2)) {
+ return 0;
+ }
+
+ // Now ensure that P1, Q1 and P2, Q2 are independent. For points of order two this means
+ // that they're not the same
+ if (ec_is_equal(&K1_2->P1, &K2_2->P1) | ec_is_equal(&K1_2->P2, &K2_2->P2)) {
+ return 0;
+ }
+
+ // Finally, double points to ensure all points have order exactly 0
+ theta_couple_point_t O1, O2;
+ double_couple_point(&O1, K1_2, E12);
+ double_couple_point(&O2, K2_2, E12);
+ // If this check fails then the points had order 2*f for some f, and the kernel is malformed.
+ if (!(ec_is_zero(&O1.P1) & ec_is_zero(&O1.P2) & ec_is_zero(&O2.P1) & ec_is_zero(&O2.P2))) {
+ return 0;
+ }
+
+ return 1;
+}
+
+// Computes the action by translation for four points
+// (P1, P2) and (Q1, Q2) on E1 x E2 simultaneously to
+// save on inversions.
+// Returns 0 if any of Pi or Qi does not have order 2
+// and 1 otherwise
+static int
+action_by_translation(translation_matrix_t *Gi,
+ const theta_couple_point_t *K1_4,
+ const theta_couple_point_t *K2_4,
+ const theta_couple_curve_t *E12)
+{
+ // Compute points of order 2 from Ki_4
+ theta_couple_point_t K1_2, K2_2;
+ double_couple_point(&K1_2, K1_4, E12);
+ double_couple_point(&K2_2, K2_4, E12);
+
+ if (!verify_two_torsion(&K1_2, &K2_2, E12)) {
+ return 0;
+ }
+
+ // We need to invert four Z coordinates and
+ // four determinants which we do with batched
+ // inversion
+ fp2_t inverses[8];
+ action_by_translation_z_and_det(&inverses[0], &inverses[4], &K1_4->P1, &K1_2.P1);
+ action_by_translation_z_and_det(&inverses[1], &inverses[5], &K1_4->P2, &K1_2.P2);
+ action_by_translation_z_and_det(&inverses[2], &inverses[6], &K2_4->P1, &K2_2.P1);
+ action_by_translation_z_and_det(&inverses[3], &inverses[7], &K2_4->P2, &K2_2.P2);
+
+ fp2_batched_inv(inverses, 8);
+ if (fp2_is_zero(&inverses[0]))
+ return 0; // something was wrong with our input (which somehow was not caught by
+ // verify_two_torsion)
+
+ action_by_translation_compute_matrix(&Gi[0], &K1_4->P1, &K1_2.P1, &inverses[0], &inverses[4]);
+ action_by_translation_compute_matrix(&Gi[1], &K1_4->P2, &K1_2.P2, &inverses[1], &inverses[5]);
+ action_by_translation_compute_matrix(&Gi[2], &K2_4->P1, &K2_2.P1, &inverses[2], &inverses[6]);
+ action_by_translation_compute_matrix(&Gi[3], &K2_4->P2, &K2_2.P2, &inverses[3], &inverses[7]);
+
+ return 1;
+}
+
+// Given the appropriate four torsion, computes the
+// change of basis to compute the correct theta null
+// point.
+// Returns 0 if the order of K1_4 or K2_4 is not 4
+static int
+gluing_change_of_basis(basis_change_matrix_t *M,
+ const theta_couple_point_t *K1_4,
+ const theta_couple_point_t *K2_4,
+ const theta_couple_curve_t *E12)
+{
+ // Compute the four 2x2 matrices for the action by translation
+ // on the four points:
+ translation_matrix_t Gi[4];
+ if (!action_by_translation(Gi, K1_4, K2_4, E12))
+ return 0;
+
+ // Computation of the 4x4 matrix from Mij
+ // t001, t101 (resp t002, t102) first column of M11 * M21 (resp M12 * M22)
+ fp2_t t001, t101, t002, t102, tmp;
+
+ fp2_mul(&t001, &Gi[0].g00, &Gi[2].g00);
+ fp2_mul(&tmp, &Gi[0].g01, &Gi[2].g10);
+ fp2_add(&t001, &t001, &tmp);
+
+ fp2_mul(&t101, &Gi[0].g10, &Gi[2].g00);
+ fp2_mul(&tmp, &Gi[0].g11, &Gi[2].g10);
+ fp2_add(&t101, &t101, &tmp);
+
+ fp2_mul(&t002, &Gi[1].g00, &Gi[3].g00);
+ fp2_mul(&tmp, &Gi[1].g01, &Gi[3].g10);
+ fp2_add(&t002, &t002, &tmp);
+
+ fp2_mul(&t102, &Gi[1].g10, &Gi[3].g00);
+ fp2_mul(&tmp, &Gi[1].g11, &Gi[3].g10);
+ fp2_add(&t102, &t102, &tmp);
+
+ // trace for the first row
+ fp2_set_one(&M->m[0][0]);
+ fp2_mul(&tmp, &t001, &t002);
+ fp2_add(&M->m[0][0], &M->m[0][0], &tmp);
+ fp2_mul(&tmp, &Gi[2].g00, &Gi[3].g00);
+ fp2_add(&M->m[0][0], &M->m[0][0], &tmp);
+ fp2_mul(&tmp, &Gi[0].g00, &Gi[1].g00);
+ fp2_add(&M->m[0][0], &M->m[0][0], &tmp);
+
+ fp2_mul(&M->m[0][1], &t001, &t102);
+ fp2_mul(&tmp, &Gi[2].g00, &Gi[3].g10);
+ fp2_add(&M->m[0][1], &M->m[0][1], &tmp);
+ fp2_mul(&tmp, &Gi[0].g00, &Gi[1].g10);
+ fp2_add(&M->m[0][1], &M->m[0][1], &tmp);
+
+ fp2_mul(&M->m[0][2], &t101, &t002);
+ fp2_mul(&tmp, &Gi[2].g10, &Gi[3].g00);
+ fp2_add(&M->m[0][2], &M->m[0][2], &tmp);
+ fp2_mul(&tmp, &Gi[0].g10, &Gi[1].g00);
+ fp2_add(&M->m[0][2], &M->m[0][2], &tmp);
+
+ fp2_mul(&M->m[0][3], &t101, &t102);
+ fp2_mul(&tmp, &Gi[2].g10, &Gi[3].g10);
+ fp2_add(&M->m[0][3], &M->m[0][3], &tmp);
+ fp2_mul(&tmp, &Gi[0].g10, &Gi[1].g10);
+ fp2_add(&M->m[0][3], &M->m[0][3], &tmp);
+
+ // Compute the action of (0,out.K2_4.P2) for the second row
+ fp2_mul(&tmp, &Gi[3].g01, &M->m[0][1]);
+ fp2_mul(&M->m[1][0], &Gi[3].g00, &M->m[0][0]);
+ fp2_add(&M->m[1][0], &M->m[1][0], &tmp);
+
+ fp2_mul(&tmp, &Gi[3].g11, &M->m[0][1]);
+ fp2_mul(&M->m[1][1], &Gi[3].g10, &M->m[0][0]);
+ fp2_add(&M->m[1][1], &M->m[1][1], &tmp);
+
+ fp2_mul(&tmp, &Gi[3].g01, &M->m[0][3]);
+ fp2_mul(&M->m[1][2], &Gi[3].g00, &M->m[0][2]);
+ fp2_add(&M->m[1][2], &M->m[1][2], &tmp);
+
+ fp2_mul(&tmp, &Gi[3].g11, &M->m[0][3]);
+ fp2_mul(&M->m[1][3], &Gi[3].g10, &M->m[0][2]);
+ fp2_add(&M->m[1][3], &M->m[1][3], &tmp);
+
+ // compute the action of (K1_4.P1,0) for the third row
+ fp2_mul(&tmp, &Gi[0].g01, &M->m[0][2]);
+ fp2_mul(&M->m[2][0], &Gi[0].g00, &M->m[0][0]);
+ fp2_add(&M->m[2][0], &M->m[2][0], &tmp);
+
+ fp2_mul(&tmp, &Gi[0].g01, &M->m[0][3]);
+ fp2_mul(&M->m[2][1], &Gi[0].g00, &M->m[0][1]);
+ fp2_add(&M->m[2][1], &M->m[2][1], &tmp);
+
+ fp2_mul(&tmp, &Gi[0].g11, &M->m[0][2]);
+ fp2_mul(&M->m[2][2], &Gi[0].g10, &M->m[0][0]);
+ fp2_add(&M->m[2][2], &M->m[2][2], &tmp);
+
+ fp2_mul(&tmp, &Gi[0].g11, &M->m[0][3]);
+ fp2_mul(&M->m[2][3], &Gi[0].g10, &M->m[0][1]);
+ fp2_add(&M->m[2][3], &M->m[2][3], &tmp);
+
+ // compute the action of (K1_4.P1,K2_4.P2) for the final row
+ fp2_mul(&tmp, &Gi[0].g01, &M->m[1][2]);
+ fp2_mul(&M->m[3][0], &Gi[0].g00, &M->m[1][0]);
+ fp2_add(&M->m[3][0], &M->m[3][0], &tmp);
+
+ fp2_mul(&tmp, &Gi[0].g01, &M->m[1][3]);
+ fp2_mul(&M->m[3][1], &Gi[0].g00, &M->m[1][1]);
+ fp2_add(&M->m[3][1], &M->m[3][1], &tmp);
+
+ fp2_mul(&tmp, &Gi[0].g11, &M->m[1][2]);
+ fp2_mul(&M->m[3][2], &Gi[0].g10, &M->m[1][0]);
+ fp2_add(&M->m[3][2], &M->m[3][2], &tmp);
+
+ fp2_mul(&tmp, &Gi[0].g11, &M->m[1][3]);
+ fp2_mul(&M->m[3][3], &Gi[0].g10, &M->m[1][1]);
+ fp2_add(&M->m[3][3], &M->m[3][3], &tmp);
+
+ return 1;
+}
+
+#ifndef NDEBUG
+/**
+ * @brief Check if a Jacobian point (X : Y : Z) has order exactly 2^f
+ *
+ * @param P: a point
+ * @param E: an elliptic curve
+ * @param t: an integer
+ *
+ * @return 0xFFFFFFFF if the order is correct, 0 otherwise
+ */
+static int
+test_jac_order_twof(const jac_point_t *P, const ec_curve_t *E, int t)
+{
+ jac_point_t test;
+ test = *P;
+ if (fp2_is_zero(&test.z))
+ return 0;
+ for (int i = 0; i < t - 1; i++) {
+ DBL(&test, &test, E);
+ }
+ if (fp2_is_zero(&test.z))
+ return 0;
+ DBL(&test, &test, E);
+ return (fp2_is_zero(&test.z));
+}
+#endif
+
+/**
+ * @brief Compute the gluing isogeny from an elliptic product
+ *
+ * @param out Output: the theta_gluing
+ * @param K1_8 a couple point
+ * @param E12 an elliptic curve product
+ * @param K2_8 a point in E2[8]
+ *
+ * out : E1xE2 -> A of kernel [4](K1_8,K2_8)
+ * if the kernel supplied has the incorrect order, or gluing seems malformed,
+ * returns 0, otherwise returns 1.
+ */
+static int
+gluing_compute(theta_gluing_t *out,
+ const theta_couple_curve_t *E12,
+ const theta_couple_jac_point_t *xyK1_8,
+ const theta_couple_jac_point_t *xyK2_8,
+ bool verify)
+{
+ // Ensure that we have been given the eight torsion
+#ifndef NDEBUG
+ {
+ int check = test_jac_order_twof(&xyK1_8->P1, &E12->E1, 3);
+ if (!check)
+ debug_print("xyK1_8->P1 does not have order 8");
+ check = test_jac_order_twof(&xyK2_8->P1, &E12->E1, 3);
+ if (!check)
+ debug_print("xyK2_8->P1 does not have order 8");
+ check = test_jac_order_twof(&xyK1_8->P2, &E12->E2, 3);
+ if (!check)
+ debug_print("xyK2_8->P1 does not have order 8");
+ check = test_jac_order_twof(&xyK2_8->P2, &E12->E2, 3);
+ if (!check)
+ debug_print("xyK2_8->P2 does not have order 8");
+ }
+#endif
+
+ out->xyK1_8 = *xyK1_8;
+ out->domain = *E12;
+
+ // Given points in E[8] x E[8] we need the four torsion below
+ theta_couple_jac_point_t xyK1_4, xyK2_4;
+
+ double_couple_jac_point(&xyK1_4, xyK1_8, E12);
+ double_couple_jac_point(&xyK2_4, xyK2_8, E12);
+
+ // Convert from (X:Y:Z) coordinates to (X:Z)
+ theta_couple_point_t K1_8, K2_8;
+ theta_couple_point_t K1_4, K2_4;
+
+ couple_jac_to_xz(&K1_8, xyK1_8);
+ couple_jac_to_xz(&K2_8, xyK2_8);
+ couple_jac_to_xz(&K1_4, &xyK1_4);
+ couple_jac_to_xz(&K2_4, &xyK2_4);
+
+ // Set the basis change matrix, if we have not been given a valid K[8] for this computation
+ // gluing_change_of_basis will detect this and return 0
+ if (!gluing_change_of_basis(&out->M, &K1_4, &K2_4, E12)) {
+ debug_print("gluing failed as kernel does not have correct order");
+ return 0;
+ }
+
+ // apply the base change to the kernel
+ theta_point_t TT1, TT2;
+
+ base_change(&TT1, out, &K1_8);
+ base_change(&TT2, out, &K2_8);
+
+ // compute the codomain
+ to_squared_theta(&TT1, &TT1);
+ to_squared_theta(&TT2, &TT2);
+
+ // If the kernel is well formed then TT1.t and TT2.t are zero
+ // if they are not, we exit early as the signature we are validating
+ // is probably malformed
+ if (!(fp2_is_zero(&TT1.t) & fp2_is_zero(&TT2.t))) {
+ debug_print("gluing failed TT1.t or TT2.t is not zero");
+ return 0;
+ }
+ // Test our projective factors are non zero
+ if (fp2_is_zero(&TT1.x) | fp2_is_zero(&TT2.x) | fp2_is_zero(&TT1.y) | fp2_is_zero(&TT2.z) | fp2_is_zero(&TT1.z))
+ return 0; // invalid input
+
+ // Projective factor: Ax
+ fp2_mul(&out->codomain.x, &TT1.x, &TT2.x);
+ fp2_mul(&out->codomain.y, &TT1.y, &TT2.x);
+ fp2_mul(&out->codomain.z, &TT1.x, &TT2.z);
+ fp2_set_zero(&out->codomain.t);
+ // Projective factor: ABCxz
+ fp2_mul(&out->precomputation.x, &TT1.y, &TT2.z);
+ fp2_copy(&out->precomputation.y, &out->codomain.z);
+ fp2_copy(&out->precomputation.z, &out->codomain.y);
+ fp2_set_zero(&out->precomputation.t);
+
+ // Compute the two components of phi(K1_8) = (x:x:y:y).
+ fp2_mul(&out->imageK1_8.x, &TT1.x, &out->precomputation.x);
+ fp2_mul(&out->imageK1_8.y, &TT1.z, &out->precomputation.z);
+
+ // If K1_8 and K2_8 are our 8-torsion points, this ensures that the
+ // 4-torsion points [2]K1_8 and [2]K2_8 are isotropic.
+ if (verify) {
+ fp2_t t1, t2;
+ fp2_mul(&t1, &TT1.y, &out->precomputation.y);
+ if (!fp2_is_equal(&out->imageK1_8.x, &t1))
+ return 0;
+ fp2_mul(&t1, &TT2.x, &out->precomputation.x);
+ fp2_mul(&t2, &TT2.z, &out->precomputation.z);
+ if (!fp2_is_equal(&t2, &t1))
+ return 0;
+ }
+
+ // compute the final codomain
+ hadamard(&out->codomain, &out->codomain);
+ return 1;
+}
+
+// sub routine of the gluing eval
+static void
+gluing_eval_point(theta_point_t *image, const theta_couple_jac_point_t *P, const theta_gluing_t *phi)
+{
+ theta_point_t T1, T2;
+ add_components_t add_comp1, add_comp2;
+
+ // Compute the cross addition components of P1+Q1 and P2+Q2
+ jac_to_xz_add_components(&add_comp1, &P->P1, &phi->xyK1_8.P1, &phi->domain.E1);
+ jac_to_xz_add_components(&add_comp2, &P->P2, &phi->xyK1_8.P2, &phi->domain.E2);
+
+ // Compute T1 and T2 derived from the cross addition components.
+ fp2_mul(&T1.x, &add_comp1.u, &add_comp2.u); // T1x = u1u2
+ fp2_mul(&T2.t, &add_comp1.v, &add_comp2.v); // T2t = v1v2
+ fp2_add(&T1.x, &T1.x, &T2.t); // T1x = u1u2 + v1v2
+ fp2_mul(&T1.y, &add_comp1.u, &add_comp2.w); // T1y = u1w2
+ fp2_mul(&T1.z, &add_comp1.w, &add_comp2.u); // T1z = w1u2
+ fp2_mul(&T1.t, &add_comp1.w, &add_comp2.w); // T1t = w1w2
+ fp2_add(&T2.x, &add_comp1.u, &add_comp1.v); // T2x = (u1+v1)
+ fp2_add(&T2.y, &add_comp2.u, &add_comp2.v); // T2y = (u2+v2)
+ fp2_mul(&T2.x, &T2.x, &T2.y); // T2x = (u1+v1)(u2+v2)
+ fp2_sub(&T2.x, &T2.x, &T1.x); // T1x = v1u2 + u1v2
+ fp2_mul(&T2.y, &add_comp1.v, &add_comp2.w); // T2y = v1w2
+ fp2_mul(&T2.z, &add_comp1.w, &add_comp2.v); // T2z = w1v2
+ fp2_set_zero(&T2.t); // T2t = 0
+
+ // Apply the basis change and compute their respective square
+ // theta(P+Q) = M.T1 - M.T2 and theta(P-Q) = M.T1 + M.T2
+ apply_isomorphism_general(&T1, &phi->M, &T1, true);
+ apply_isomorphism_general(&T2, &phi->M, &T2, false);
+ pointwise_square(&T1, &T1);
+ pointwise_square(&T2, &T2);
+
+ // the difference between the two is therefore theta(P+Q)theta(P-Q)
+ // whose hadamard transform is then the product of the dual
+ // theta_points of phi(P) and phi(Q).
+ fp2_sub(&T1.x, &T1.x, &T2.x);
+ fp2_sub(&T1.y, &T1.y, &T2.y);
+ fp2_sub(&T1.z, &T1.z, &T2.z);
+ fp2_sub(&T1.t, &T1.t, &T2.t);
+ hadamard(&T1, &T1);
+
+ // Compute (x, y, z, t)
+ // As imageK1_8 = (x:x:y:y), its inverse is (y:y:x:x).
+ fp2_mul(&image->x, &T1.x, &phi->imageK1_8.y);
+ fp2_mul(&image->y, &T1.y, &phi->imageK1_8.y);
+ fp2_mul(&image->z, &T1.z, &phi->imageK1_8.x);
+ fp2_mul(&image->t, &T1.t, &phi->imageK1_8.x);
+
+ hadamard(image, image);
+}
+
+// Same as gluing_eval_point but in the very special case where we already know that the point will
+// have a zero coordinate at the place where the zero coordinate of the dual_theta_nullpoint would
+// have made the computation difficult
+static int
+gluing_eval_point_special_case(theta_point_t *image, const theta_couple_point_t *P, const theta_gluing_t *phi)
+{
+ theta_point_t T;
+
+ // Apply the basis change
+ base_change(&T, phi, P);
+
+ // Apply the to_squared_theta transform
+ to_squared_theta(&T, &T);
+
+ // This coordinate should always be 0 in a gluing because D=0.
+ // If this is not the case, something went very wrong, so reject
+ if (!fp2_is_zero(&T.t))
+ return 0;
+
+ // Compute (x, y, z, t)
+ fp2_mul(&image->x, &T.x, &phi->precomputation.x);
+ fp2_mul(&image->y, &T.y, &phi->precomputation.y);
+ fp2_mul(&image->z, &T.z, &phi->precomputation.z);
+ fp2_set_zero(&image->t);
+
+ hadamard(image, image);
+ return 1;
+}
+
+/**
+ * @brief Evaluate a gluing isogeny from an elliptic product on a basis
+ *
+ * @param image1 Output: the theta_point of the image of the first couple of points
+ * @param image2 Output : the theta point of the image of the second couple of points
+ * @param xyT1: A pair of points (X : Y : Z) on E1E2 to glue using phi
+ * @param xyT2: A pair of points (X : Y : Z) on E1E2 to glue using phi
+ * @param phi : a gluing isogeny E1 x E2 -> A
+ *
+ **/
+static void
+gluing_eval_basis(theta_point_t *image1,
+ theta_point_t *image2,
+ const theta_couple_jac_point_t *xyT1,
+ const theta_couple_jac_point_t *xyT2,
+ const theta_gluing_t *phi)
+{
+ gluing_eval_point(image1, xyT1, phi);
+ gluing_eval_point(image2, xyT2, phi);
+}
+
+/**
+ * @brief Compute a (2,2) isogeny in dimension 2 in the theta_model
+ *
+ * @param out Output: the theta_isogeny
+ * @param A a theta null point for the domain
+ * @param T1_8 a point in A[8]
+ * @param T2_8 a point in A[8]
+ * @param hadamard_bool_1 a boolean used for the last two steps of the chain
+ * @param hadamard_bool_2 a boolean used for the last two steps of the chain
+ *
+ * out : A -> B of kernel [4](T1_8,T2_8)
+ * hadamard_bool_1 controls if the domain is in standard or dual coordinates
+ * hadamard_bool_2 controls if the codomain is in standard or dual coordinates
+ * verify: add extra sanity check to ensure our 8-torsion points are coherent with the isogeny
+ *
+ */
+static int
+theta_isogeny_compute(theta_isogeny_t *out,
+ const theta_structure_t *A,
+ const theta_point_t *T1_8,
+ const theta_point_t *T2_8,
+ bool hadamard_bool_1,
+ bool hadamard_bool_2,
+ bool verify)
+{
+ out->hadamard_bool_1 = hadamard_bool_1;
+ out->hadamard_bool_2 = hadamard_bool_2;
+ out->domain = *A;
+ out->T1_8 = *T1_8;
+ out->T2_8 = *T2_8;
+ out->codomain.precomputation = false;
+
+ theta_point_t TT1, TT2;
+
+ if (hadamard_bool_1) {
+ hadamard(&TT1, T1_8);
+ to_squared_theta(&TT1, &TT1);
+ hadamard(&TT2, T2_8);
+ to_squared_theta(&TT2, &TT2);
+ } else {
+ to_squared_theta(&TT1, T1_8);
+ to_squared_theta(&TT2, T2_8);
+ }
+
+ fp2_t t1, t2;
+
+ // Test that our projective factor ABCDxzw is non zero, where
+ // TT1=(Ax, Bx, Cy, Dy), TT2=(Az, Bw, Cz, Dw)
+ // But ABCDxzw=0 can only happen if we had an unexpected splitting in
+ // the isogeny chain.
+ // In either case reject
+ // (this is not strictly necessary, we could just return (0:0:0:0))
+ if (fp2_is_zero(&TT2.x) | fp2_is_zero(&TT2.y) | fp2_is_zero(&TT2.z) | fp2_is_zero(&TT2.t) | fp2_is_zero(&TT1.x) |
+ fp2_is_zero(&TT1.y))
+ return 0;
+
+ fp2_mul(&t1, &TT1.x, &TT2.y);
+ fp2_mul(&t2, &TT1.y, &TT2.x);
+ fp2_mul(&out->codomain.null_point.x, &TT2.x, &t1);
+ fp2_mul(&out->codomain.null_point.y, &TT2.y, &t2);
+ fp2_mul(&out->codomain.null_point.z, &TT2.z, &t1);
+ fp2_mul(&out->codomain.null_point.t, &TT2.t, &t2);
+ fp2_t t3;
+ fp2_mul(&t3, &TT2.z, &TT2.t);
+ fp2_mul(&out->precomputation.x, &t3, &TT1.y);
+ fp2_mul(&out->precomputation.y, &t3, &TT1.x);
+ fp2_copy(&out->precomputation.z, &out->codomain.null_point.t);
+ fp2_copy(&out->precomputation.t, &out->codomain.null_point.z);
+
+ // If T1_8 and T2_8 are our 8-torsion points, this ensures that the
+ // 4-torsion points 2T1_8 and 2T2_8 are isotropic.
+ if (verify) {
+ fp2_mul(&t1, &TT1.x, &out->precomputation.x);
+ fp2_mul(&t2, &TT1.y, &out->precomputation.y);
+ if (!fp2_is_equal(&t1, &t2))
+ return 0;
+ fp2_mul(&t1, &TT1.z, &out->precomputation.z);
+ fp2_mul(&t2, &TT1.t, &out->precomputation.t);
+ if (!fp2_is_equal(&t1, &t2))
+ return 0;
+ fp2_mul(&t1, &TT2.x, &out->precomputation.x);
+ fp2_mul(&t2, &TT2.z, &out->precomputation.z);
+ if (!fp2_is_equal(&t1, &t2))
+ return 0;
+ fp2_mul(&t1, &TT2.y, &out->precomputation.y);
+ fp2_mul(&t2, &TT2.t, &out->precomputation.t);
+ if (!fp2_is_equal(&t1, &t2))
+ return 0;
+ }
+
+ if (hadamard_bool_2) {
+ hadamard(&out->codomain.null_point, &out->codomain.null_point);
+ }
+ return 1;
+}
+
+/**
+ * @brief Compute a (2,2) isogeny when only the 4 torsion above the kernel is known and not the 8
+ * torsion
+ *
+ * @param out Output: the theta_isogeny
+ * @param A a theta null point for the domain
+ * @param T1_4 a point in A[4]
+ * @param T2_4 a point in A[4]
+ * @param hadamard_bool_1 a boolean
+ * @param hadamard_bool_2 a boolean
+ *
+ * out : A -> B of kernel [2](T1_4,T2_4)
+ * hadamard_bool_1 controls if the domain is in standard or dual coordinates
+ * hadamard_bool_2 controls if the codomain is in standard or dual coordinates
+ *
+ */
+static void
+theta_isogeny_compute_4(theta_isogeny_t *out,
+ const theta_structure_t *A,
+ const theta_point_t *T1_4,
+ const theta_point_t *T2_4,
+ bool hadamard_bool_1,
+ bool hadamard_bool_2)
+{
+ out->hadamard_bool_1 = hadamard_bool_1;
+ out->hadamard_bool_2 = hadamard_bool_2;
+ out->domain = *A;
+ out->T1_8 = *T1_4;
+ out->T2_8 = *T2_4;
+ out->codomain.precomputation = false;
+
+ theta_point_t TT1, TT2;
+ // we will compute:
+ // TT1 = (xAB, _ , xCD, _)
+ // TT2 = (AA,BB,CC,DD)
+
+ // fp2_t xA_inv,zA_inv,tB_inv;
+
+ if (hadamard_bool_1) {
+ hadamard(&TT1, T1_4);
+ to_squared_theta(&TT1, &TT1);
+
+ hadamard(&TT2, &A->null_point);
+ to_squared_theta(&TT2, &TT2);
+ } else {
+ to_squared_theta(&TT1, T1_4);
+ to_squared_theta(&TT2, &A->null_point);
+ }
+
+ fp2_t sqaabb, sqaacc;
+ fp2_mul(&sqaabb, &TT2.x, &TT2.y);
+ fp2_mul(&sqaacc, &TT2.x, &TT2.z);
+ // No need to check the square roots, only used for signing.
+ // sqaabb = sqrt(AA*BB)
+ fp2_sqrt(&sqaabb);
+ // sqaacc = sqrt(AA*CC)
+ fp2_sqrt(&sqaacc);
+
+ // we compute out->codomain.null_point = (xAB * sqaacc * AA, xAB *sqaabb *sqaacc, xCD*sqaabb *
+ // AA) out->precomputation = (xAB * BB * CC *DD , sqaabb * CC * DD * xAB , sqaacc * BB* DD * xAB
+ // , xCD * sqaabb *sqaacc * BB)
+
+ fp2_mul(&out->codomain.null_point.y, &sqaabb, &sqaacc);
+ fp2_mul(&out->precomputation.t, &out->codomain.null_point.y, &TT1.z);
+ fp2_mul(&out->codomain.null_point.y, &out->codomain.null_point.y,
+ &TT1.x); // done for out->codomain.null_point.y
+
+ fp2_mul(&out->codomain.null_point.t, &TT1.z, &sqaabb);
+ fp2_mul(&out->codomain.null_point.t, &out->codomain.null_point.t,
+ &TT2.x); // done for out->codomain.null_point.t
+
+ fp2_mul(&out->codomain.null_point.x, &TT1.x, &TT2.x);
+ fp2_mul(&out->codomain.null_point.z, &out->codomain.null_point.x,
+ &TT2.z); // done for out->codomain.null_point.z
+ fp2_mul(&out->codomain.null_point.x, &out->codomain.null_point.x,
+ &sqaacc); // done for out->codomain.null_point.x
+
+ fp2_mul(&out->precomputation.x, &TT1.x, &TT2.t);
+ fp2_mul(&out->precomputation.z, &out->precomputation.x, &TT2.y);
+ fp2_mul(&out->precomputation.x, &out->precomputation.x, &TT2.z);
+ fp2_mul(&out->precomputation.y, &out->precomputation.x, &sqaabb); // done for out->precomputation.y
+ fp2_mul(&out->precomputation.x, &out->precomputation.x, &TT2.y); // done for out->precomputation.x
+ fp2_mul(&out->precomputation.z, &out->precomputation.z, &sqaacc); // done for out->precomputation.z
+ fp2_mul(&out->precomputation.t, &out->precomputation.t, &TT2.y); // done for out->precomputation.t
+
+ if (hadamard_bool_2) {
+ hadamard(&out->codomain.null_point, &out->codomain.null_point);
+ }
+}
+
+/**
+ * @brief Compute a (2,2) isogeny when only the kernel is known and not the 8 or 4 torsion above
+ *
+ * @param out Output: the theta_isogeny
+ * @param A a theta null point for the domain
+ * @param T1_2 a point in A[2]
+ * @param T2_2 a point in A[2]
+ * @param hadamard_bool_1 a boolean
+ * @param boo2 a boolean
+ *
+ * out : A -> B of kernel (T1_2,T2_2)
+ * hadamard_bool_1 controls if the domain is in standard or dual coordinates
+ * hadamard_bool_2 controls if the codomain is in standard or dual coordinates
+ *
+ */
+static void
+theta_isogeny_compute_2(theta_isogeny_t *out,
+ const theta_structure_t *A,
+ const theta_point_t *T1_2,
+ const theta_point_t *T2_2,
+ bool hadamard_bool_1,
+ bool hadamard_bool_2)
+{
+ out->hadamard_bool_1 = hadamard_bool_1;
+ out->hadamard_bool_2 = hadamard_bool_2;
+ out->domain = *A;
+ out->T1_8 = *T1_2;
+ out->T2_8 = *T2_2;
+ out->codomain.precomputation = false;
+
+ theta_point_t TT2;
+ // we will compute:
+ // TT2 = (AA,BB,CC,DD)
+
+ if (hadamard_bool_1) {
+ hadamard(&TT2, &A->null_point);
+ to_squared_theta(&TT2, &TT2);
+ } else {
+ to_squared_theta(&TT2, &A->null_point);
+ }
+
+ // we compute out->codomain.null_point = (AA,sqaabb, sqaacc, sqaadd)
+ // out->precomputation = ( BB * CC *DD , sqaabb * CC * DD , sqaacc * BB* DD , sqaadd * BB * CC)
+ fp2_copy(&out->codomain.null_point.x, &TT2.x);
+ fp2_mul(&out->codomain.null_point.y, &TT2.x, &TT2.y);
+ fp2_mul(&out->codomain.null_point.z, &TT2.x, &TT2.z);
+ fp2_mul(&out->codomain.null_point.t, &TT2.x, &TT2.t);
+ // No need to check the square roots, only used for signing.
+ fp2_sqrt(&out->codomain.null_point.y);
+ fp2_sqrt(&out->codomain.null_point.z);
+ fp2_sqrt(&out->codomain.null_point.t);
+
+ fp2_mul(&out->precomputation.x, &TT2.z, &TT2.t);
+ fp2_mul(&out->precomputation.y,
+ &out->precomputation.x,
+ &out->codomain.null_point.y); // done for out->precomputation.y
+ fp2_mul(&out->precomputation.x, &out->precomputation.x, &TT2.y); // done for out->precomputation.x
+ fp2_mul(&out->precomputation.z, &TT2.t, &out->codomain.null_point.z);
+ fp2_mul(&out->precomputation.z, &out->precomputation.z, &TT2.y); // done for out->precomputation.z
+ fp2_mul(&out->precomputation.t, &TT2.z, &out->codomain.null_point.t);
+ fp2_mul(&out->precomputation.t, &out->precomputation.t, &TT2.y); // done for out->precomputation.t
+
+ if (hadamard_bool_2) {
+ hadamard(&out->codomain.null_point, &out->codomain.null_point);
+ }
+}
+
+static void
+theta_isogeny_eval(theta_point_t *out, const theta_isogeny_t *phi, const theta_point_t *P)
+{
+ if (phi->hadamard_bool_1) {
+ hadamard(out, P);
+ to_squared_theta(out, out);
+ } else {
+ to_squared_theta(out, P);
+ }
+ fp2_mul(&out->x, &out->x, &phi->precomputation.x);
+ fp2_mul(&out->y, &out->y, &phi->precomputation.y);
+ fp2_mul(&out->z, &out->z, &phi->precomputation.z);
+ fp2_mul(&out->t, &out->t, &phi->precomputation.t);
+
+ if (phi->hadamard_bool_2) {
+ hadamard(out, out);
+ }
+}
+
+#if defined(ENABLE_SIGN)
+// Sample a random secret index in [0, 5] to select one of the 6 normalisation
+// matrices for the normalisation of the output of the (2,2)-chain during
+// splitting
+static unsigned char
+sample_random_index(void)
+{
+ // To avoid bias in reduction we should only consider integers smaller
+ // than 2^32 which are a multiple of 6, so we only reduce bytes with a
+ // value in [0, 4294967292-1].
+ // We have 4294967292/2^32 = ~99.9999999% chance that the first try is "good".
+ unsigned char seed_arr[4];
+ uint32_t seed;
+
+ do {
+ randombytes(seed_arr, 4);
+ seed = (seed_arr[0] | (seed_arr[1] << 8) | (seed_arr[2] << 16) | (seed_arr[3] << 24));
+ } while (seed >= 4294967292U);
+
+ uint32_t secret_index = seed - (((uint64_t)seed * 2863311531U) >> 34) * 6;
+ assert(secret_index == seed % 6); // ensure the constant time trick above works
+ return (unsigned char)secret_index;
+}
+#endif
+
+static bool
+splitting_compute(theta_splitting_t *out, const theta_structure_t *A, int zero_index, bool randomize)
+
+{
+ // init
+ uint32_t ctl;
+ uint32_t count = 0;
+ fp2_t U_cst, t1, t2;
+
+ memset(&out->M, 0, sizeof(basis_change_matrix_t));
+
+ // enumerate through all indices
+ for (int i = 0; i < 10; i++) {
+ fp2_set_zero(&U_cst);
+ for (int t = 0; t < 4; t++) {
+ // Iterate through the null point
+ choose_index_theta_point(&t2, t, &A->null_point);
+ choose_index_theta_point(&t1, t ^ EVEN_INDEX[i][1], &A->null_point);
+
+ // Compute t1 * t2
+ fp2_mul(&t1, &t1, &t2);
+ // If CHI_EVAL(i,t) is +1 we want ctl to be 0 and
+ // If CHI_EVAL(i,t) is -1 we want ctl to be 0xFF..FF
+ ctl = (uint32_t)(CHI_EVAL[EVEN_INDEX[i][0]][t] >> 1);
+ assert(ctl == 0 || ctl == 0xffffffff);
+
+ fp2_neg(&t2, &t1);
+ fp2_select(&t1, &t1, &t2, ctl);
+
+ // Then we compute U_cst ± (t1 * t2)
+ fp2_add(&U_cst, &U_cst, &t1);
+ }
+
+ // If U_cst is 0 then update the splitting matrix
+ ctl = fp2_is_zero(&U_cst);
+ count -= ctl;
+ select_base_change_matrix(&out->M, &out->M, &SPLITTING_TRANSFORMS[i], ctl);
+ if (zero_index != -1 && i == zero_index &&
+ !ctl) { // extra checks if we know exactly where the 0 index should be
+ return 0;
+ }
+ }
+
+#if defined(ENABLE_SIGN)
+ // Pick a random normalization matrix
+ if (randomize) {
+ unsigned char secret_index = sample_random_index();
+ basis_change_matrix_t Mrandom;
+
+ set_base_change_matrix_from_precomp(&Mrandom, &NORMALIZATION_TRANSFORMS[0]);
+
+ // Use a constant time selection to pick the index we want
+ for (unsigned char i = 1; i < 6; i++) {
+ // When i == secret_index, mask == 0 and 0xFF..FF otherwise
+ int32_t mask = i - secret_index;
+ mask = (mask | -mask) >> 31;
+ select_base_change_matrix(&Mrandom, &Mrandom, &NORMALIZATION_TRANSFORMS[i], ~mask);
+ }
+ base_change_matrix_multiplication(&out->M, &Mrandom, &out->M);
+ }
+#else
+ assert(!randomize);
+#endif
+
+ // apply the isomorphism to ensure the null point is compatible with splitting
+ apply_isomorphism(&out->B.null_point, &out->M, &A->null_point);
+
+ // splitting was successful only if exactly one zero was identified
+ return count == 1;
+}
+
+static int
+theta_product_structure_to_elliptic_product(theta_couple_curve_t *E12, theta_structure_t *A)
+{
+ fp2_t xx, yy;
+
+ // This should be true from our computations in splitting_compute
+ // but still check this for sanity
+ if (!is_product_theta_point(&A->null_point))
+ return 0;
+
+ ec_curve_init(&(E12->E1));
+ ec_curve_init(&(E12->E2));
+
+ // A valid elliptic theta null point has no zero coordinate
+ if (fp2_is_zero(&A->null_point.x) | fp2_is_zero(&A->null_point.y) | fp2_is_zero(&A->null_point.z))
+ return 0;
+
+ // xx = x², yy = y²
+ fp2_sqr(&xx, &A->null_point.x);
+ fp2_sqr(&yy, &A->null_point.y);
+ // xx = x^4, yy = y^4
+ fp2_sqr(&xx, &xx);
+ fp2_sqr(&yy, &yy);
+
+ // A2 = -2(x^4+y^4)/(x^4-y^4)
+ fp2_add(&E12->E2.A, &xx, &yy);
+ fp2_sub(&E12->E2.C, &xx, &yy);
+ fp2_add(&E12->E2.A, &E12->E2.A, &E12->E2.A);
+ fp2_neg(&E12->E2.A, &E12->E2.A);
+
+ // same with x,z
+ fp2_sqr(&xx, &A->null_point.x);
+ fp2_sqr(&yy, &A->null_point.z);
+ fp2_sqr(&xx, &xx);
+ fp2_sqr(&yy, &yy);
+
+ // A1 = -2(x^4+z^4)/(x^4-z^4)
+ fp2_add(&E12->E1.A, &xx, &yy);
+ fp2_sub(&E12->E1.C, &xx, &yy);
+ fp2_add(&E12->E1.A, &E12->E1.A, &E12->E1.A);
+ fp2_neg(&E12->E1.A, &E12->E1.A);
+
+ if (fp2_is_zero(&E12->E1.C) | fp2_is_zero(&E12->E2.C))
+ return 0;
+
+ return 1;
+}
+
+static int
+theta_point_to_montgomery_point(theta_couple_point_t *P12, const theta_point_t *P, const theta_structure_t *A)
+{
+ fp2_t temp;
+ const fp2_t *x, *z;
+
+ if (!is_product_theta_point(P))
+ return 0;
+
+ x = &P->x;
+ z = &P->y;
+ if (fp2_is_zero(x) & fp2_is_zero(z)) {
+ x = &P->z;
+ z = &P->t;
+ }
+ if (fp2_is_zero(x) & fp2_is_zero(z)) {
+ return 0; // at this point P=(0:0:0:0) so is invalid
+ }
+ // P2.X = A.null_point.y * P.x + A.null_point.x * P.y
+ // P2.Z = - A.null_point.y * P.x + A.null_point.x * P.y
+ fp2_mul(&P12->P2.x, &A->null_point.y, x);
+ fp2_mul(&temp, &A->null_point.x, z);
+ fp2_sub(&P12->P2.z, &temp, &P12->P2.x);
+ fp2_add(&P12->P2.x, &P12->P2.x, &temp);
+
+ x = &P->x;
+ z = &P->z;
+ if (fp2_is_zero(x) & fp2_is_zero(z)) {
+ x = &P->y;
+ z = &P->t;
+ }
+ // P1.X = A.null_point.z * P.x + A.null_point.x * P.z
+ // P1.Z = -A.null_point.z * P.x + A.null_point.x * P.z
+ fp2_mul(&P12->P1.x, &A->null_point.z, x);
+ fp2_mul(&temp, &A->null_point.x, z);
+ fp2_sub(&P12->P1.z, &temp, &P12->P1.x);
+ fp2_add(&P12->P1.x, &P12->P1.x, &temp);
+ return 1;
+}
+
+static int
+_theta_chain_compute_impl(unsigned n,
+ theta_couple_curve_t *E12,
+ const theta_kernel_couple_points_t *ker,
+ bool extra_torsion,
+ theta_couple_curve_t *E34,
+ theta_couple_point_t *P12,
+ size_t numP,
+ bool verify,
+ bool randomize)
+{
+ theta_structure_t theta;
+
+ // lift the basis
+ theta_couple_jac_point_t xyT1, xyT2;
+
+ ec_basis_t bas1 = { .P = ker->T1.P1, .Q = ker->T2.P1, .PmQ = ker->T1m2.P1 };
+ ec_basis_t bas2 = { .P = ker->T1.P2, .Q = ker->T2.P2, .PmQ = ker->T1m2.P2 };
+ if (!lift_basis(&xyT1.P1, &xyT2.P1, &bas1, &E12->E1))
+ return 0;
+ if (!lift_basis(&xyT1.P2, &xyT2.P2, &bas2, &E12->E2))
+ return 0;
+
+ const unsigned extra = HD_extra_torsion * extra_torsion;
+
+#ifndef NDEBUG
+ assert(extra == 0 || extra == 2); // only cases implemented
+ if (!test_point_order_twof(&bas2.P, &E12->E2, n + extra))
+ debug_print("bas2.P does not have correct order");
+
+ if (!test_jac_order_twof(&xyT2.P2, &E12->E2, n + extra))
+ debug_print("xyT2.P2 does not have correct order");
+#endif
+
+ theta_point_t pts[numP ? numP : 1];
+
+ int space = 1;
+ for (unsigned i = 1; i < n; i *= 2)
+ ++space;
+
+ uint16_t todo[space];
+ todo[0] = n - 2 + extra;
+
+ int current = 0;
+
+ // kernel points for the gluing isogeny
+ theta_couple_jac_point_t jacQ1[space], jacQ2[space];
+ jacQ1[0] = xyT1;
+ jacQ2[0] = xyT2;
+ while (todo[current] != 1) {
+ assert(todo[current] >= 2);
+ ++current;
+ assert(current < space);
+ // the gluing isogeny is quite a bit more expensive than the others,
+ // so we adjust the usual splitting rule here a little bit: towards
+ // the end of the doubling chain it will be cheaper to recompute the
+ // doublings after evaluation than to push the intermediate points.
+ const unsigned num_dbls = todo[current - 1] >= 16 ? todo[current - 1] / 2 : todo[current - 1] - 1;
+ assert(num_dbls && num_dbls < todo[current - 1]);
+ double_couple_jac_point_iter(&jacQ1[current], num_dbls, &jacQ1[current - 1], E12);
+ double_couple_jac_point_iter(&jacQ2[current], num_dbls, &jacQ2[current - 1], E12);
+ todo[current] = todo[current - 1] - num_dbls;
+ }
+
+ // kernel points for the remaining isogeny steps
+ theta_point_t thetaQ1[space], thetaQ2[space];
+
+ // the gluing step
+ theta_gluing_t first_step;
+ {
+ assert(todo[current] == 1);
+
+ // compute the gluing isogeny
+ if (!gluing_compute(&first_step, E12, &jacQ1[current], &jacQ2[current], verify))
+ return 0;
+
+ // evaluate
+ for (unsigned j = 0; j < numP; ++j) {
+ assert(ec_is_zero(&P12[j].P1) || ec_is_zero(&P12[j].P2));
+ if (!gluing_eval_point_special_case(&pts[j], &P12[j], &first_step))
+ return 0;
+ }
+
+ // push kernel points through gluing isogeny
+ for (int j = 0; j < current; ++j) {
+ gluing_eval_basis(&thetaQ1[j], &thetaQ2[j], &jacQ1[j], &jacQ2[j], &first_step);
+ --todo[j];
+ }
+
+ --current;
+ }
+
+ // set-up the theta_structure for the first codomain
+ theta.null_point = first_step.codomain;
+ theta.precomputation = 0;
+ theta_precomputation(&theta);
+
+ theta_isogeny_t step;
+
+ // and now we do the remaining steps
+ for (unsigned i = 1; current >= 0 && todo[current]; ++i) {
+ assert(current < space);
+ while (todo[current] != 1) {
+ assert(todo[current] >= 2);
+ ++current;
+ assert(current < space);
+ const unsigned num_dbls = todo[current - 1] / 2;
+ assert(num_dbls && num_dbls < todo[current - 1]);
+ double_iter(&thetaQ1[current], &theta, &thetaQ1[current - 1], num_dbls);
+ double_iter(&thetaQ2[current], &theta, &thetaQ2[current - 1], num_dbls);
+ todo[current] = todo[current - 1] - num_dbls;
+ }
+
+ // computing the next step
+ int ret;
+ if (i == n - 2) // penultimate step
+ ret = theta_isogeny_compute(&step, &theta, &thetaQ1[current], &thetaQ2[current], 0, 0, verify);
+ else if (i == n - 1) // ultimate step
+ ret = theta_isogeny_compute(&step, &theta, &thetaQ1[current], &thetaQ2[current], 1, 0, false);
+ else
+ ret = theta_isogeny_compute(&step, &theta, &thetaQ1[current], &thetaQ2[current], 0, 1, verify);
+ if (!ret)
+ return 0;
+
+ for (unsigned j = 0; j < numP; ++j)
+ theta_isogeny_eval(&pts[j], &step, &pts[j]);
+
+ // updating the codomain
+ theta = step.codomain;
+
+ // pushing the kernel
+ assert(todo[current] == 1);
+ for (int j = 0; j < current; ++j) {
+ theta_isogeny_eval(&thetaQ1[j], &step, &thetaQ1[j]);
+ theta_isogeny_eval(&thetaQ2[j], &step, &thetaQ2[j]);
+ assert(todo[j]);
+ --todo[j];
+ }
+
+ --current;
+ }
+
+ assert(current == -1);
+
+ if (!extra_torsion) {
+ if (n >= 3) {
+ // in the last step we've skipped pushing the kernel since current was == 0, let's do it now
+ theta_isogeny_eval(&thetaQ1[0], &step, &thetaQ1[0]);
+ theta_isogeny_eval(&thetaQ2[0], &step, &thetaQ2[0]);
+ }
+
+ // penultimate step
+ theta_isogeny_compute_4(&step, &theta, &thetaQ1[0], &thetaQ2[0], 0, 0);
+ for (unsigned j = 0; j < numP; ++j)
+ theta_isogeny_eval(&pts[j], &step, &pts[j]);
+ theta = step.codomain;
+ theta_isogeny_eval(&thetaQ1[0], &step, &thetaQ1[0]);
+ theta_isogeny_eval(&thetaQ2[0], &step, &thetaQ2[0]);
+
+ // ultimate step
+ theta_isogeny_compute_2(&step, &theta, &thetaQ1[0], &thetaQ2[0], 1, 0);
+ for (unsigned j = 0; j < numP; ++j)
+ theta_isogeny_eval(&pts[j], &step, &pts[j]);
+ theta = step.codomain;
+ }
+
+ // final splitting step
+ theta_splitting_t last_step;
+
+ bool is_split = splitting_compute(&last_step, &theta, extra_torsion ? 8 : -1, randomize);
+
+ if (!is_split) {
+ debug_print("kernel did not generate an isogeny between elliptic products");
+ return 0;
+ }
+
+ if (!theta_product_structure_to_elliptic_product(E34, &last_step.B))
+ return 0;
+
+ // evaluate
+ for (size_t j = 0; j < numP; ++j) {
+ apply_isomorphism(&pts[j], &last_step.M, &pts[j]);
+ if (!theta_point_to_montgomery_point(&P12[j], &pts[j], &last_step.B))
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+theta_chain_compute_and_eval(unsigned n,
+ /*const*/ theta_couple_curve_t *E12,
+ const theta_kernel_couple_points_t *ker,
+ bool extra_torsion,
+ theta_couple_curve_t *E34,
+ theta_couple_point_t *P12,
+ size_t numP)
+{
+ return _theta_chain_compute_impl(n, E12, ker, extra_torsion, E34, P12, numP, false, false);
+}
+
+// Like theta_chain_compute_and_eval, adding extra verification checks;
+// used in the signature verification
+int
+theta_chain_compute_and_eval_verify(unsigned n,
+ /*const*/ theta_couple_curve_t *E12,
+ const theta_kernel_couple_points_t *ker,
+ bool extra_torsion,
+ theta_couple_curve_t *E34,
+ theta_couple_point_t *P12,
+ size_t numP)
+{
+ return _theta_chain_compute_impl(n, E12, ker, extra_torsion, E34, P12, numP, true, false);
+}
+
+int
+theta_chain_compute_and_eval_randomized(unsigned n,
+ /*const*/ theta_couple_curve_t *E12,
+ const theta_kernel_couple_points_t *ker,
+ bool extra_torsion,
+ theta_couple_curve_t *E34,
+ theta_couple_point_t *P12,
+ size_t numP)
+{
+ return _theta_chain_compute_impl(n, E12, ker, extra_torsion, E34, P12, numP, false, true);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_isogenies.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_isogenies.h
new file mode 100644
index 0000000000..d151811fe7
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_isogenies.h
@@ -0,0 +1,18 @@
+/** @file
+ *
+ * @authors Antonin Leroux
+ *
+ * @brief the theta isogeny header
+ */
+
+#ifndef THETA_ISOGENY_H
+#define THETA_ISOGENY_H
+
+#include
+#include
+#include
+#include "theta_structure.h"
+#include
+#include
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_structure.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_structure.c
new file mode 100644
index 0000000000..ce97ac61a8
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_structure.c
@@ -0,0 +1,78 @@
+#include "theta_structure.h"
+#include
+
+void
+theta_precomputation(theta_structure_t *A)
+{
+
+ if (A->precomputation) {
+ return;
+ }
+
+ theta_point_t A_dual;
+ to_squared_theta(&A_dual, &A->null_point);
+
+ fp2_t t1, t2;
+ fp2_mul(&t1, &A_dual.x, &A_dual.y);
+ fp2_mul(&t2, &A_dual.z, &A_dual.t);
+ fp2_mul(&A->XYZ0, &t1, &A_dual.z);
+ fp2_mul(&A->XYT0, &t1, &A_dual.t);
+ fp2_mul(&A->YZT0, &t2, &A_dual.y);
+ fp2_mul(&A->XZT0, &t2, &A_dual.x);
+
+ fp2_mul(&t1, &A->null_point.x, &A->null_point.y);
+ fp2_mul(&t2, &A->null_point.z, &A->null_point.t);
+ fp2_mul(&A->xyz0, &t1, &A->null_point.z);
+ fp2_mul(&A->xyt0, &t1, &A->null_point.t);
+ fp2_mul(&A->yzt0, &t2, &A->null_point.y);
+ fp2_mul(&A->xzt0, &t2, &A->null_point.x);
+
+ A->precomputation = true;
+}
+
+void
+double_point(theta_point_t *out, theta_structure_t *A, const theta_point_t *in)
+{
+ to_squared_theta(out, in);
+ fp2_sqr(&out->x, &out->x);
+ fp2_sqr(&out->y, &out->y);
+ fp2_sqr(&out->z, &out->z);
+ fp2_sqr(&out->t, &out->t);
+
+ if (!A->precomputation) {
+ theta_precomputation(A);
+ }
+ fp2_mul(&out->x, &out->x, &A->YZT0);
+ fp2_mul(&out->y, &out->y, &A->XZT0);
+ fp2_mul(&out->z, &out->z, &A->XYT0);
+ fp2_mul(&out->t, &out->t, &A->XYZ0);
+
+ hadamard(out, out);
+
+ fp2_mul(&out->x, &out->x, &A->yzt0);
+ fp2_mul(&out->y, &out->y, &A->xzt0);
+ fp2_mul(&out->z, &out->z, &A->xyt0);
+ fp2_mul(&out->t, &out->t, &A->xyz0);
+}
+
+void
+double_iter(theta_point_t *out, theta_structure_t *A, const theta_point_t *in, int exp)
+{
+ if (exp == 0) {
+ *out = *in;
+ } else {
+ double_point(out, A, in);
+ for (int i = 1; i < exp; i++) {
+ double_point(out, A, out);
+ }
+ }
+}
+
+uint32_t
+is_product_theta_point(const theta_point_t *P)
+{
+ fp2_t t1, t2;
+ fp2_mul(&t1, &P->x, &P->t);
+ fp2_mul(&t2, &P->y, &P->z);
+ return fp2_is_equal(&t1, &t2);
+}
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_structure.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_structure.h
new file mode 100644
index 0000000000..fc630b750a
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/theta_structure.h
@@ -0,0 +1,135 @@
+/** @file
+ *
+ * @authors Antonin Leroux
+ *
+ * @brief the theta structure header
+ */
+
+#ifndef THETA_STRUCTURE_H
+#define THETA_STRUCTURE_H
+
+#include
+#include
+#include
+
+/** @internal
+ * @ingroup hd_module
+ * @defgroup hd_theta Functions for theta structures
+ * @{
+ */
+
+/**
+ * @brief Perform the hadamard transform on a theta point
+ *
+ * @param out Output: the theta_point
+ * @param in a theta point*
+ * in = (x,y,z,t)
+ * out = (x+y+z+t, x-y+z-t, x+y-z-t, x-y-z+t)
+ *
+ */
+static inline void
+hadamard(theta_point_t *out, const theta_point_t *in)
+{
+ fp2_t t1, t2, t3, t4;
+
+ // t1 = x + y
+ fp2_add(&t1, &in->x, &in->y);
+ // t2 = x - y
+ fp2_sub(&t2, &in->x, &in->y);
+ // t3 = z + t
+ fp2_add(&t3, &in->z, &in->t);
+ // t4 = z - t
+ fp2_sub(&t4, &in->z, &in->t);
+
+ fp2_add(&out->x, &t1, &t3);
+ fp2_add(&out->y, &t2, &t4);
+ fp2_sub(&out->z, &t1, &t3);
+ fp2_sub(&out->t, &t2, &t4);
+}
+
+/**
+ * @brief Square the coordinates of a theta point
+ * @param out Output: the theta_point
+ * @param in a theta point*
+ * in = (x,y,z,t)
+ * out = (x^2, y^2, z^2, t^2)
+ *
+ */
+static inline void
+pointwise_square(theta_point_t *out, const theta_point_t *in)
+{
+ fp2_sqr(&out->x, &in->x);
+ fp2_sqr(&out->y, &in->y);
+ fp2_sqr(&out->z, &in->z);
+ fp2_sqr(&out->t, &in->t);
+}
+
+/**
+ * @brief Square the coordinates and then perform the hadamard transform
+ *
+ * @param out Output: the theta_point
+ * @param in a theta point*
+ * in = (x,y,z,t)
+ * out = (x^2+y^2+z^2+t^2, x^2-y^2+z^2-t^2, x^2+y^2-z^2-t^2, x^2-y^2-z^2+t^2)
+ *
+ */
+static inline void
+to_squared_theta(theta_point_t *out, const theta_point_t *in)
+{
+ pointwise_square(out, in);
+ hadamard(out, out);
+}
+
+/**
+ * @brief Perform the theta structure precomputation
+ *
+ * @param A Output: the theta_structure
+ *
+ * if A.null_point = (x,y,z,t)
+ * if (xx,yy,zz,tt) = to_squared_theta(A.null_point)
+ * Computes y0,z0,t0,Y0,Z0,T0 = x/y,x/z,x/t,XX/YY,XX/ZZ,XX/TT
+ *
+ */
+void theta_precomputation(theta_structure_t *A);
+
+/**
+ * @brief Compute the double of the theta point in on the theta struc A
+ *
+ * @param out Output: the theta_point
+ * @param A a theta structure
+ * @param in a theta point in the theta structure A
+ * in = (x,y,z,t)
+ * out = [2] (x,y,z,t)
+ * /!\ assumes that no coordinates is zero and that the precomputation of A has been done
+ *
+ */
+void double_point(theta_point_t *out, theta_structure_t *A, const theta_point_t *in);
+
+/**
+ * @brief Compute the iterated double of the theta point in on the theta struc A
+ *
+ * @param out Output: the theta_point
+ * @param A a theta structure
+ * @param in a theta point in the theta structure A
+ * @param exp the exponent
+ * in = (x,y,z,t)
+ * out = [2^2] (x,y,z,t)
+ * /!\ assumes that no coordinates is zero and that the precomputation of A has been done
+ *
+ */
+void double_iter(theta_point_t *out, theta_structure_t *A, const theta_point_t *in, int exp);
+
+/*
+ * @brief Check if a theta point is a product theta point
+ *
+ * @param P a theta point
+ * @return 0xFFFFFFFF if true, zero otherwise
+ */
+uint32_t is_product_theta_point(const theta_point_t *P);
+
+// end hd_theta
+/**
+ * @}
+ */
+
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/tools.h b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/tools.h
new file mode 100644
index 0000000000..5a6a505fc1
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/tools.h
@@ -0,0 +1,49 @@
+
+#ifndef TOOLS_H
+#define TOOLS_H
+
+#include
+
+// Debug printing:
+// https://stackoverflow.com/questions/1644868/define-macro-for-debug-printing-in-c
+#ifndef NDEBUG
+#define DEBUG_PRINT 1
+#else
+#define DEBUG_PRINT 0
+#endif
+
+#ifndef __FILE_NAME__
+#define __FILE_NAME__ "NA"
+#endif
+
+#ifndef __LINE__
+#define __LINE__ 0
+#endif
+
+#ifndef __func__
+#define __func__ "NA"
+#endif
+
+#define debug_print(fmt) \
+ do { \
+ if (DEBUG_PRINT) \
+ printf("warning: %s, file %s, line %d, function %s().\n", \
+ fmt, \
+ __FILE_NAME__, \
+ __LINE__, \
+ __func__); \
+ } while (0)
+
+
+clock_t tic(void);
+float tac(void); /* time in ms since last tic */
+float TAC(const char *str); /* same, but prints it with label 'str' */
+float toc(const clock_t t); /* time in ms since t */
+float TOC(const clock_t t, const char *str); /* same, but prints it with label 'str' */
+float TOC_clock(const clock_t t, const char *str);
+
+clock_t dclock(const clock_t t); // return the clock cycle diff between now and t
+float clock_to_time(const clock_t t,
+ const char *str); // convert the number of clock cycles t to time
+float clock_print(const clock_t t, const char *str);
+#endif
diff --git a/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/torsion_constants.c b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/torsion_constants.c
new file mode 100644
index 0000000000..55743c1989
--- /dev/null
+++ b/src/sig/sqisign/the-sqisign_sqisign_lvl1_broadwell/torsion_constants.c
@@ -0,0 +1,43 @@
+#include
+#include