add pqm4
Some checks failed
CMake / build (OFF, AUTO, SYSTEM, x64, ref, 10, ) (push) Has been cancelled
CMake / build (ON, 32, BUILD, x64, ref, 10, .cmake/32bit.cmake) (push) Has been cancelled
CMake / build (ON, 32, SYSTEM, arm64, ref, 10, ) (push) Has been cancelled
CMake / build (ON, 32, SYSTEM, x64, ref, 10, ) (push) Has been cancelled
CMake / build (ON, AUTO, MINI, x64, ref, 10, ) (push) Has been cancelled
CMake / build (ON, AUTO, SYSTEM, arm64, ref, 10, ) (push) Has been cancelled
CMake / build (ON, AUTO, SYSTEM, x64, broadwell, 10, ) (push) Has been cancelled
CMake / build (ON, AUTO, SYSTEM, x64, ref, 10, ) (push) Has been cancelled
Big-endian s390x test (Daily Workflow) / s390-be (Debug) (push) Has been cancelled
Big-endian s390x test (Daily Workflow) / s390-be (Release) (push) Has been cancelled
Benchmarks (Daily Workflow) / benchmarks (arm64, ref, ) (push) Has been cancelled
Benchmarks (Daily Workflow) / benchmarks (x64, broadwell, 10, ) (push) Has been cancelled
Benchmarks (Daily Workflow) / benchmarks (x64, ref, ) (push) Has been cancelled
Benchmarks (Daily Workflow) / benchmarks (x64, ref, 10, .cmake/32bit.cmake) (push) Has been cancelled
Daily workflow for various checks / checks (push) Has been cancelled
Some checks failed
CMake / build (OFF, AUTO, SYSTEM, x64, ref, 10, ) (push) Has been cancelled
CMake / build (ON, 32, BUILD, x64, ref, 10, .cmake/32bit.cmake) (push) Has been cancelled
CMake / build (ON, 32, SYSTEM, arm64, ref, 10, ) (push) Has been cancelled
CMake / build (ON, 32, SYSTEM, x64, ref, 10, ) (push) Has been cancelled
CMake / build (ON, AUTO, MINI, x64, ref, 10, ) (push) Has been cancelled
CMake / build (ON, AUTO, SYSTEM, arm64, ref, 10, ) (push) Has been cancelled
CMake / build (ON, AUTO, SYSTEM, x64, broadwell, 10, ) (push) Has been cancelled
CMake / build (ON, AUTO, SYSTEM, x64, ref, 10, ) (push) Has been cancelled
Big-endian s390x test (Daily Workflow) / s390-be (Debug) (push) Has been cancelled
Big-endian s390x test (Daily Workflow) / s390-be (Release) (push) Has been cancelled
Benchmarks (Daily Workflow) / benchmarks (arm64, ref, ) (push) Has been cancelled
Benchmarks (Daily Workflow) / benchmarks (x64, broadwell, 10, ) (push) Has been cancelled
Benchmarks (Daily Workflow) / benchmarks (x64, ref, ) (push) Has been cancelled
Benchmarks (Daily Workflow) / benchmarks (x64, ref, 10, .cmake/32bit.cmake) (push) Has been cancelled
Daily workflow for various checks / checks (push) Has been cancelled
This commit is contained in:
31
src/pqm4/sqisign_lvl1/ref/api.h
Normal file
31
src/pqm4/sqisign_lvl1/ref/api.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#ifndef api_h
|
||||
#define api_h
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sqisign_namespace.h>
|
||||
|
||||
#define CRYPTO_SECRETKEYBYTES 353
|
||||
#define CRYPTO_PUBLICKEYBYTES 65
|
||||
#define CRYPTO_BYTES 148
|
||||
|
||||
#define CRYPTO_ALGNAME "SQIsign_lvl1"
|
||||
|
||||
SQISIGN_API
|
||||
int
|
||||
crypto_sign_keypair(unsigned char *pk, unsigned char *sk);
|
||||
|
||||
SQISIGN_API
|
||||
int
|
||||
crypto_sign(unsigned char *sm, size_t *smlen,
|
||||
const unsigned char *m, size_t mlen,
|
||||
const unsigned char *sk);
|
||||
|
||||
SQISIGN_API
|
||||
int
|
||||
crypto_sign_open(unsigned char *m, size_t *mlen,
|
||||
const unsigned char *sm, size_t smlen,
|
||||
const unsigned char *pk);
|
||||
|
||||
#endif /* api_h */
|
||||
416
src/pqm4/sqisign_lvl1/ref/basis.c
Normal file
416
src/pqm4/sqisign_lvl1/ref/basis.c
Normal file
@@ -0,0 +1,416 @@
|
||||
#include "ec.h"
|
||||
#include "fp2.h"
|
||||
#include "e0_basis.h"
|
||||
#include <assert.h>
|
||||
|
||||
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] = <P, Q> 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] = <P, Q> 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;
|
||||
}
|
||||
88
src/pqm4/sqisign_lvl1/ref/common.c
Normal file
88
src/pqm4/sqisign_lvl1/ref/common.c
Normal file
@@ -0,0 +1,88 @@
|
||||
#include <fips202.h>
|
||||
#include <tutil.h>
|
||||
#include <mp.h>
|
||||
#include <encoded_sizes.h>
|
||||
#include <ec_params.h>
|
||||
#include <verification.h>
|
||||
|
||||
void
|
||||
public_key_init(public_key_t *pk)
|
||||
{
|
||||
ec_curve_init(&pk->curve);
|
||||
}
|
||||
|
||||
void
|
||||
public_key_finalize(public_key_t *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_init(&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_init(&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);
|
||||
(*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);
|
||||
}
|
||||
}
|
||||
2
src/pqm4/sqisign_lvl1/ref/config.mk
Normal file
2
src/pqm4/sqisign_lvl1/ref/config.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
elf/crypto_sign_sqisign_lvl1_ref_%.elf: CPPFLAGS+=-DRADIX_32 -DSQISIGN_BUILD_TYPE_REF -DSQISIGN_GF_IMPL_REF -DSQISIGN_VARIANT=lvl1 -DTARGET_ARM -DTARGET_OS_OTHER -DNDEBUG -DDISABLE_NAMESPACING -DBIG_PUBLIC_KEY_TESTS
|
||||
obj/libcrypto_sign_sqisign_lvl1_ref.a: CPPFLAGS+=-DRADIX_32 -DSQISIGN_BUILD_TYPE_REF -DSQISIGN_GF_IMPL_REF -DSQISIGN_VARIANT=lvl1 -DTARGET_ARM -DTARGET_OS_OTHER -DNDEBUG -DDISABLE_NAMESPACING -DBIG_PUBLIC_KEY_TESTS
|
||||
55
src/pqm4/sqisign_lvl1/ref/e0_basis.c
Normal file
55
src/pqm4/sqisign_lvl1/ref/e0_basis.c
Normal file
@@ -0,0 +1,55 @@
|
||||
#include <e0_basis.h>
|
||||
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
|
||||
};
|
||||
3
src/pqm4/sqisign_lvl1/ref/e0_basis.h
Normal file
3
src/pqm4/sqisign_lvl1/ref/e0_basis.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#include <fp2.h>
|
||||
extern const fp2_t BASIS_E0_PX;
|
||||
extern const fp2_t BASIS_E0_QX;
|
||||
665
src/pqm4/sqisign_lvl1/ref/ec.c
Normal file
665
src/pqm4/sqisign_lvl1/ref/ec.c
Normal file
@@ -0,0 +1,665 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <mp.h>
|
||||
#include <ec.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
668
src/pqm4/sqisign_lvl1/ref/ec.h
Normal file
668
src/pqm4/sqisign_lvl1/ref/ec.h
Normal file
@@ -0,0 +1,668 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Luca De Feo, Francisco RH
|
||||
*
|
||||
* @brief Elliptic curve stuff
|
||||
*/
|
||||
|
||||
#ifndef EC_H
|
||||
#define EC_H
|
||||
#include <sqisign_namespace.h>
|
||||
#include <ec_params.h>
|
||||
#include <fp2.h>
|
||||
#include <tools.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/** @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 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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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));
|
||||
}
|
||||
|
||||
// Prints the x-coordinate of the point (X : 1)
|
||||
static void
|
||||
ec_point_print(const char *name, ec_point_t P)
|
||||
{
|
||||
fp2_t a;
|
||||
if (fp2_is_zero(&P.z)) {
|
||||
printf("%s = INF\n", name);
|
||||
} else {
|
||||
fp2_copy(&a, &P.z);
|
||||
fp2_inv(&a);
|
||||
fp2_mul(&a, &a, &P.x);
|
||||
fp2_print(name, &a);
|
||||
}
|
||||
}
|
||||
|
||||
// Prints the Montgomery coefficient A
|
||||
static void
|
||||
ec_curve_print(const char *name, ec_curve_t E)
|
||||
{
|
||||
fp2_t a;
|
||||
fp2_copy(&a, &E.C);
|
||||
fp2_inv(&a);
|
||||
fp2_mul(&a, &a, &E.A);
|
||||
fp2_print(name, &a);
|
||||
}
|
||||
|
||||
#endif
|
||||
// end isogeny computations
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
// end ec
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
335
src/pqm4/sqisign_lvl1/ref/ec_jac.c
Normal file
335
src/pqm4/sqisign_lvl1/ref/ec_jac.c
Normal file
@@ -0,0 +1,335 @@
|
||||
#include <assert.h>
|
||||
#include <ec.h>
|
||||
|
||||
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
|
||||
}
|
||||
4
src/pqm4/sqisign_lvl1/ref/ec_params.c
Normal file
4
src/pqm4/sqisign_lvl1/ref/ec_params.c
Normal file
@@ -0,0 +1,4 @@
|
||||
#include <ec_params.h>
|
||||
// p+1 divided by the power of 2
|
||||
const digit_t p_cofactor_for_2f[1] = {5};
|
||||
|
||||
12
src/pqm4/sqisign_lvl1/ref/ec_params.h
Normal file
12
src/pqm4/sqisign_lvl1/ref/ec_params.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef EC_PARAMS_H
|
||||
#define EC_PARAMS_H
|
||||
|
||||
#include <fp.h>
|
||||
|
||||
#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
|
||||
220
src/pqm4/sqisign_lvl1/ref/encode_verification.c
Normal file
220
src/pqm4/sqisign_lvl1/ref/encode_verification.c
Normal file
@@ -0,0 +1,220 @@
|
||||
#include <verification.h>
|
||||
#include <string.h>
|
||||
#include <tutil.h>
|
||||
#include <fp2.h>
|
||||
#include <encoded_sizes.h>
|
||||
#include <assert.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static byte_t *
|
||||
ec_point_to_bytes(byte_t *enc, const ec_point_t *point)
|
||||
{
|
||||
return proj_to_bytes(enc, &point->x, &point->z);
|
||||
}
|
||||
|
||||
static const byte_t *
|
||||
ec_point_from_bytes(ec_point_t *point, const byte_t *enc)
|
||||
{
|
||||
return proj_from_bytes(&point->x, &point->z, enc);
|
||||
}
|
||||
|
||||
static byte_t *
|
||||
ec_basis_to_bytes(byte_t *enc, const ec_basis_t *basis)
|
||||
{
|
||||
enc = ec_point_to_bytes(enc, &basis->P);
|
||||
enc = ec_point_to_bytes(enc, &basis->Q);
|
||||
enc = ec_point_to_bytes(enc, &basis->PmQ);
|
||||
return enc;
|
||||
}
|
||||
|
||||
static const byte_t *
|
||||
ec_basis_from_bytes(ec_basis_t *basis, const byte_t *enc)
|
||||
{
|
||||
enc = ec_point_from_bytes(&basis->P, enc);
|
||||
enc = ec_point_from_bytes(&basis->Q, enc);
|
||||
enc = ec_point_from_bytes(&basis->PmQ, enc);
|
||||
return 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);
|
||||
}
|
||||
11
src/pqm4/sqisign_lvl1/ref/encoded_sizes.h
Normal file
11
src/pqm4/sqisign_lvl1/ref/encoded_sizes.h
Normal file
@@ -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
|
||||
15
src/pqm4/sqisign_lvl1/ref/fp.c
Normal file
15
src/pqm4/sqisign_lvl1/ref/fp.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <fp.h>
|
||||
|
||||
/*
|
||||
* If ctl == 0x00000000, then *d is set to a0
|
||||
* If ctl == 0xFFFFFFFF, then *d is set to a1
|
||||
* ctl MUST be either 0x00000000 or 0xFFFFFFFF.
|
||||
*/
|
||||
void
|
||||
fp_select(fp_t *d, const fp_t *a0, const fp_t *a1, uint32_t ctl)
|
||||
{
|
||||
digit_t cw = (int32_t)ctl;
|
||||
for (unsigned int i = 0; i < NWORDS_FIELD; i++) {
|
||||
(*d)[i] = (*a0)[i] ^ (cw & ((*a0)[i] ^ (*a1)[i]));
|
||||
}
|
||||
}
|
||||
48
src/pqm4/sqisign_lvl1/ref/fp.h
Normal file
48
src/pqm4/sqisign_lvl1/ref/fp.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef FP_H
|
||||
#define FP_H
|
||||
|
||||
//////////////////////////////////////////////// NOTE: this is placed here for now
|
||||
#include <sqisign_namespace.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <tutil.h>
|
||||
#include <fp_constants.h>
|
||||
|
||||
typedef digit_t fp_t[NWORDS_FIELD]; // Datatype for representing field elements
|
||||
|
||||
extern const digit_t ONE[NWORDS_FIELD];
|
||||
extern const digit_t ZERO[NWORDS_FIELD];
|
||||
// extern const digit_t PM1O3[NWORDS_FIELD];
|
||||
|
||||
void fp_set_small(fp_t *x, const digit_t val);
|
||||
void fp_mul_small(fp_t *x, const fp_t *a, const uint32_t val);
|
||||
void fp_set_zero(fp_t *x);
|
||||
void fp_set_one(fp_t *x);
|
||||
uint32_t fp_is_equal(const fp_t *a, const fp_t *b);
|
||||
uint32_t fp_is_zero(const fp_t *a);
|
||||
void fp_copy(fp_t *out, const fp_t *a);
|
||||
|
||||
void fp_encode(void *dst, const fp_t *a);
|
||||
void fp_decode_reduce(fp_t *d, const void *src, size_t len);
|
||||
uint32_t fp_decode(fp_t *d, const void *src);
|
||||
|
||||
void fp_select(fp_t *d, const fp_t *a0, const fp_t *a1, uint32_t ctl);
|
||||
void fp_cswap(fp_t *a, fp_t *b, uint32_t ctl);
|
||||
|
||||
void fp_add(fp_t *out, const fp_t *a, const fp_t *b);
|
||||
void fp_sub(fp_t *out, const fp_t *a, const fp_t *b);
|
||||
void fp_neg(fp_t *out, const fp_t *a);
|
||||
void fp_sqr(fp_t *out, const fp_t *a);
|
||||
void fp_mul(fp_t *out, const fp_t *a, const fp_t *b);
|
||||
|
||||
void fp_inv(fp_t *x);
|
||||
uint32_t fp_is_square(const fp_t *a);
|
||||
void fp_sqrt(fp_t *a);
|
||||
void fp_half(fp_t *out, const fp_t *a);
|
||||
void fp_exp3div4(fp_t *out, const fp_t *a);
|
||||
void fp_div3(fp_t *out, const fp_t *a);
|
||||
|
||||
#endif
|
||||
328
src/pqm4/sqisign_lvl1/ref/fp2.c
Normal file
328
src/pqm4/sqisign_lvl1/ref/fp2.c
Normal file
@@ -0,0 +1,328 @@
|
||||
#include <inttypes.h>
|
||||
#include <encoded_sizes.h>
|
||||
#include <fp2.h>
|
||||
|
||||
/* Arithmetic modulo X^2 + 1 */
|
||||
|
||||
void
|
||||
fp2_set_small(fp2_t *x, const digit_t val)
|
||||
{
|
||||
fp_set_small(&(x->re), val);
|
||||
fp_set_zero(&(x->im));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
fp2_set_one(fp2_t *x)
|
||||
{
|
||||
fp_set_one(&(x->re));
|
||||
fp_set_zero(&(x->im));
|
||||
}
|
||||
|
||||
void
|
||||
fp2_set_zero(fp2_t *x)
|
||||
{
|
||||
fp_set_zero(&(x->re));
|
||||
fp_set_zero(&(x->im));
|
||||
}
|
||||
|
||||
// Is a GF(p^2) element zero?
|
||||
// Returns 0xFF...FF (true) if a=0, 0 (false) otherwise
|
||||
uint32_t
|
||||
fp2_is_zero(const fp2_t *a)
|
||||
{
|
||||
return fp_is_zero(&(a->re)) & fp_is_zero(&(a->im));
|
||||
}
|
||||
|
||||
// Compare two GF(p^2) elements in constant time
|
||||
// Returns 0xFF...FF (true) if a=b, 0 (false) otherwise
|
||||
uint32_t
|
||||
fp2_is_equal(const fp2_t *a, const fp2_t *b)
|
||||
{
|
||||
return fp_is_equal(&(a->re), &(b->re)) & fp_is_equal(&(a->im), &(b->im));
|
||||
}
|
||||
|
||||
// Is a GF(p^2) element one?
|
||||
// Returns 0xFF...FF (true) if a=1, 0 (false) otherwise
|
||||
uint32_t
|
||||
fp2_is_one(const fp2_t *a)
|
||||
{
|
||||
return fp_is_equal(&(a->re), &ONE) & fp_is_zero(&(a->im));
|
||||
}
|
||||
|
||||
void
|
||||
fp2_copy(fp2_t *x, const fp2_t *y)
|
||||
{
|
||||
fp_copy(&(x->re), &(y->re));
|
||||
fp_copy(&(x->im), &(y->im));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void
|
||||
fp2_add_one(fp2_t *x, const fp2_t *y)
|
||||
{
|
||||
fp_add(&x->re, &y->re, &ONE);
|
||||
fp_copy(&x->im, &y->im);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void
|
||||
fp2_neg(fp2_t *x, const fp2_t *y)
|
||||
{
|
||||
fp_neg(&(x->re), &(y->re));
|
||||
fp_neg(&(x->im), &(y->im));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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_exp3div4(&x1, &t0);
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
void
|
||||
fp2_half(fp2_t *x, const fp2_t *y)
|
||||
{
|
||||
fp_half(&(x->re), &(y->re));
|
||||
fp_half(&(x->im), &(y->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
|
||||
fp2_copy(&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)
|
||||
fp2_copy(&inverse, &t1[len - 1]);
|
||||
fp2_inv(&inverse);
|
||||
|
||||
fp2_copy(&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]);
|
||||
}
|
||||
|
||||
fp2_copy(&x[0], &t2[len - 1]);
|
||||
|
||||
for (int i = 1; i < len; i++) {
|
||||
fp2_mul(&x[i], &t1[i - 1], &t2[len - i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
// exponentiation using square and multiply
|
||||
// Warning!! Not constant time!
|
||||
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");
|
||||
}
|
||||
|
||||
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_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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
41
src/pqm4/sqisign_lvl1/ref/fp2.h
Normal file
41
src/pqm4/sqisign_lvl1/ref/fp2.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef FP2_H
|
||||
#define FP2_H
|
||||
|
||||
#include <sqisign_namespace.h>
|
||||
#include "fp.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// Structure for representing elements in GF(p^2)
|
||||
typedef struct fp2_t
|
||||
{
|
||||
fp_t re, im;
|
||||
} fp2_t;
|
||||
|
||||
void fp2_set_small(fp2_t *x, const digit_t val);
|
||||
void fp2_mul_small(fp2_t *x, const fp2_t *y, uint32_t n);
|
||||
void fp2_set_one(fp2_t *x);
|
||||
void fp2_set_zero(fp2_t *x);
|
||||
uint32_t fp2_is_zero(const fp2_t *a);
|
||||
uint32_t fp2_is_equal(const fp2_t *a, const fp2_t *b);
|
||||
uint32_t fp2_is_one(const fp2_t *a);
|
||||
void fp2_copy(fp2_t *x, const fp2_t *y);
|
||||
void fp2_add(fp2_t *x, const fp2_t *y, const fp2_t *z);
|
||||
void fp2_add_one(fp2_t *x, const fp2_t *y);
|
||||
void fp2_sub(fp2_t *x, const fp2_t *y, const fp2_t *z);
|
||||
void fp2_neg(fp2_t *x, const fp2_t *y);
|
||||
void fp2_mul(fp2_t *x, const fp2_t *y, const fp2_t *z);
|
||||
void fp2_sqr(fp2_t *x, const fp2_t *y);
|
||||
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_half(fp2_t *x, const fp2_t *y);
|
||||
void fp2_batched_inv(fp2_t *x, int len);
|
||||
void fp2_pow_vartime(fp2_t *out, const fp2_t *x, const digit_t *exp, const int size);
|
||||
void fp2_print(const char *name, const fp2_t *a);
|
||||
void fp2_encode(void *dst, const fp2_t *a);
|
||||
uint32_t fp2_decode(fp2_t *d, const void *src);
|
||||
void fp2_select(fp2_t *d, const fp2_t *a0, const fp2_t *a1, uint32_t ctl);
|
||||
void fp2_cswap(fp2_t *a, fp2_t *b, uint32_t ctl);
|
||||
|
||||
#endif
|
||||
17
src/pqm4/sqisign_lvl1/ref/fp_constants.h
Normal file
17
src/pqm4/sqisign_lvl1/ref/fp_constants.h
Normal file
@@ -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
|
||||
942
src/pqm4/sqisign_lvl1/ref/fp_p5248_32.c
Normal file
942
src/pqm4/sqisign_lvl1/ref/fp_p5248_32.c
Normal file
@@ -0,0 +1,942 @@
|
||||
// clang-format off
|
||||
// Command line : python monty.py 32
|
||||
// 0x4ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define sspint int32_t
|
||||
#define spint uint32_t
|
||||
#define udpint uint64_t
|
||||
#define dpint uint64_t
|
||||
|
||||
#define Wordlength 32
|
||||
#define Nlimbs 9
|
||||
#define Radix 29
|
||||
#define Nbits 251
|
||||
#define Nbytes 32
|
||||
|
||||
#define MONTGOMERY
|
||||
// propagate carries
|
||||
inline static spint prop(spint *n) {
|
||||
int i;
|
||||
spint mask = ((spint)1 << 29u) - (spint)1;
|
||||
sspint carry = (sspint)n[0];
|
||||
carry >>= 29u;
|
||||
n[0] &= mask;
|
||||
for (i = 1; i < 8; i++) {
|
||||
carry += (sspint)n[i];
|
||||
n[i] = (spint)carry & mask;
|
||||
carry >>= 29u;
|
||||
}
|
||||
n[8] += (spint)carry;
|
||||
return -((n[8] >> 1) >> 30u);
|
||||
}
|
||||
|
||||
// propagate carries and add p if negative, propagate carries again
|
||||
inline static int flatten(spint *n) {
|
||||
spint carry = prop(n);
|
||||
n[0] -= (spint)1u & carry;
|
||||
n[8] += ((spint)0x50000u) & carry;
|
||||
(void)prop(n);
|
||||
return (int)(carry & 1);
|
||||
}
|
||||
|
||||
// Montgomery final subtract
|
||||
static int modfsb(spint *n) {
|
||||
n[0] += (spint)1u;
|
||||
n[8] -= (spint)0x50000u;
|
||||
return flatten(n);
|
||||
}
|
||||
|
||||
// Modular addition - reduce less than 2p
|
||||
static void modadd(const spint *a, const spint *b, spint *n) {
|
||||
spint carry;
|
||||
n[0] = a[0] + b[0];
|
||||
n[1] = a[1] + b[1];
|
||||
n[2] = a[2] + b[2];
|
||||
n[3] = a[3] + b[3];
|
||||
n[4] = a[4] + b[4];
|
||||
n[5] = a[5] + b[5];
|
||||
n[6] = a[6] + b[6];
|
||||
n[7] = a[7] + b[7];
|
||||
n[8] = a[8] + b[8];
|
||||
n[0] += (spint)2u;
|
||||
n[8] -= (spint)0xa0000u;
|
||||
carry = prop(n);
|
||||
n[0] -= (spint)2u & carry;
|
||||
n[8] += ((spint)0xa0000u) & carry;
|
||||
(void)prop(n);
|
||||
}
|
||||
|
||||
// Modular subtraction - reduce less than 2p
|
||||
static void modsub(const spint *a, const spint *b, spint *n) {
|
||||
spint carry;
|
||||
n[0] = a[0] - b[0];
|
||||
n[1] = a[1] - b[1];
|
||||
n[2] = a[2] - b[2];
|
||||
n[3] = a[3] - b[3];
|
||||
n[4] = a[4] - b[4];
|
||||
n[5] = a[5] - b[5];
|
||||
n[6] = a[6] - b[6];
|
||||
n[7] = a[7] - b[7];
|
||||
n[8] = a[8] - b[8];
|
||||
carry = prop(n);
|
||||
n[0] -= (spint)2u & carry;
|
||||
n[8] += ((spint)0xa0000u) & carry;
|
||||
(void)prop(n);
|
||||
}
|
||||
|
||||
// Modular negation
|
||||
static void modneg(const spint *b, spint *n) {
|
||||
spint carry;
|
||||
n[0] = (spint)0 - b[0];
|
||||
n[1] = (spint)0 - b[1];
|
||||
n[2] = (spint)0 - b[2];
|
||||
n[3] = (spint)0 - b[3];
|
||||
n[4] = (spint)0 - b[4];
|
||||
n[5] = (spint)0 - b[5];
|
||||
n[6] = (spint)0 - b[6];
|
||||
n[7] = (spint)0 - b[7];
|
||||
n[8] = (spint)0 - b[8];
|
||||
carry = prop(n);
|
||||
n[0] -= (spint)2u & carry;
|
||||
n[8] += ((spint)0xa0000u) & carry;
|
||||
(void)prop(n);
|
||||
}
|
||||
|
||||
// Overflow limit = 18446744073709551616
|
||||
// maximum possible = 2594249331921584137
|
||||
// Modular multiplication, c=a*b mod 2p
|
||||
static void modmul(const spint *a, const spint *b, spint *c) {
|
||||
dpint t = 0;
|
||||
spint p8 = 0x50000u;
|
||||
spint q = ((spint)1 << 29u); // q is unsaturated radix
|
||||
spint mask = (spint)(q - (spint)1);
|
||||
t += (dpint)a[0] * b[0];
|
||||
spint v0 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[0] * b[1];
|
||||
t += (dpint)a[1] * b[0];
|
||||
spint v1 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[0] * b[2];
|
||||
t += (dpint)a[1] * b[1];
|
||||
t += (dpint)a[2] * b[0];
|
||||
spint v2 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[0] * b[3];
|
||||
t += (dpint)a[1] * b[2];
|
||||
t += (dpint)a[2] * b[1];
|
||||
t += (dpint)a[3] * b[0];
|
||||
spint v3 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[0] * b[4];
|
||||
t += (dpint)a[1] * b[3];
|
||||
t += (dpint)a[2] * b[2];
|
||||
t += (dpint)a[3] * b[1];
|
||||
t += (dpint)a[4] * b[0];
|
||||
spint v4 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[0] * b[5];
|
||||
t += (dpint)a[1] * b[4];
|
||||
t += (dpint)a[2] * b[3];
|
||||
t += (dpint)a[3] * b[2];
|
||||
t += (dpint)a[4] * b[1];
|
||||
t += (dpint)a[5] * b[0];
|
||||
spint v5 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[0] * b[6];
|
||||
t += (dpint)a[1] * b[5];
|
||||
t += (dpint)a[2] * b[4];
|
||||
t += (dpint)a[3] * b[3];
|
||||
t += (dpint)a[4] * b[2];
|
||||
t += (dpint)a[5] * b[1];
|
||||
t += (dpint)a[6] * b[0];
|
||||
spint v6 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[0] * b[7];
|
||||
t += (dpint)a[1] * b[6];
|
||||
t += (dpint)a[2] * b[5];
|
||||
t += (dpint)a[3] * b[4];
|
||||
t += (dpint)a[4] * b[3];
|
||||
t += (dpint)a[5] * b[2];
|
||||
t += (dpint)a[6] * b[1];
|
||||
t += (dpint)a[7] * b[0];
|
||||
spint v7 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[0] * b[8];
|
||||
t += (dpint)a[1] * b[7];
|
||||
t += (dpint)a[2] * b[6];
|
||||
t += (dpint)a[3] * b[5];
|
||||
t += (dpint)a[4] * b[4];
|
||||
t += (dpint)a[5] * b[3];
|
||||
t += (dpint)a[6] * b[2];
|
||||
t += (dpint)a[7] * b[1];
|
||||
t += (dpint)a[8] * b[0];
|
||||
t += (dpint)v0 * (dpint)p8;
|
||||
spint v8 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[1] * b[8];
|
||||
t += (dpint)a[2] * b[7];
|
||||
t += (dpint)a[3] * b[6];
|
||||
t += (dpint)a[4] * b[5];
|
||||
t += (dpint)a[5] * b[4];
|
||||
t += (dpint)a[6] * b[3];
|
||||
t += (dpint)a[7] * b[2];
|
||||
t += (dpint)a[8] * b[1];
|
||||
t += (dpint)v1 * (dpint)p8;
|
||||
c[0] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[2] * b[8];
|
||||
t += (dpint)a[3] * b[7];
|
||||
t += (dpint)a[4] * b[6];
|
||||
t += (dpint)a[5] * b[5];
|
||||
t += (dpint)a[6] * b[4];
|
||||
t += (dpint)a[7] * b[3];
|
||||
t += (dpint)a[8] * b[2];
|
||||
t += (dpint)v2 * (dpint)p8;
|
||||
c[1] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[3] * b[8];
|
||||
t += (dpint)a[4] * b[7];
|
||||
t += (dpint)a[5] * b[6];
|
||||
t += (dpint)a[6] * b[5];
|
||||
t += (dpint)a[7] * b[4];
|
||||
t += (dpint)a[8] * b[3];
|
||||
t += (dpint)v3 * (dpint)p8;
|
||||
c[2] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[4] * b[8];
|
||||
t += (dpint)a[5] * b[7];
|
||||
t += (dpint)a[6] * b[6];
|
||||
t += (dpint)a[7] * b[5];
|
||||
t += (dpint)a[8] * b[4];
|
||||
t += (dpint)v4 * (dpint)p8;
|
||||
c[3] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[5] * b[8];
|
||||
t += (dpint)a[6] * b[7];
|
||||
t += (dpint)a[7] * b[6];
|
||||
t += (dpint)a[8] * b[5];
|
||||
t += (dpint)v5 * (dpint)p8;
|
||||
c[4] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[6] * b[8];
|
||||
t += (dpint)a[7] * b[7];
|
||||
t += (dpint)a[8] * b[6];
|
||||
t += (dpint)v6 * (dpint)p8;
|
||||
c[5] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[7] * b[8];
|
||||
t += (dpint)a[8] * b[7];
|
||||
t += (dpint)v7 * (dpint)p8;
|
||||
c[6] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
t += (dpint)a[8] * b[8];
|
||||
t += (dpint)v8 * (dpint)p8;
|
||||
c[7] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
c[8] = (spint)t;
|
||||
}
|
||||
|
||||
// Modular squaring, c=a*a mod 2p
|
||||
static void modsqr(const spint *a, spint *c) {
|
||||
udpint tot;
|
||||
udpint t = 0;
|
||||
spint p8 = 0x50000u;
|
||||
spint q = ((spint)1 << 29u); // q is unsaturated radix
|
||||
spint mask = (spint)(q - (spint)1);
|
||||
tot = (udpint)a[0] * a[0];
|
||||
t = tot;
|
||||
spint v0 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[0] * a[1];
|
||||
tot *= 2;
|
||||
t += tot;
|
||||
spint v1 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[0] * a[2];
|
||||
tot *= 2;
|
||||
tot += (udpint)a[1] * a[1];
|
||||
t += tot;
|
||||
spint v2 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[0] * a[3];
|
||||
tot += (udpint)a[1] * a[2];
|
||||
tot *= 2;
|
||||
t += tot;
|
||||
spint v3 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[0] * a[4];
|
||||
tot += (udpint)a[1] * a[3];
|
||||
tot *= 2;
|
||||
tot += (udpint)a[2] * a[2];
|
||||
t += tot;
|
||||
spint v4 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[0] * a[5];
|
||||
tot += (udpint)a[1] * a[4];
|
||||
tot += (udpint)a[2] * a[3];
|
||||
tot *= 2;
|
||||
t += tot;
|
||||
spint v5 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[0] * a[6];
|
||||
tot += (udpint)a[1] * a[5];
|
||||
tot += (udpint)a[2] * a[4];
|
||||
tot *= 2;
|
||||
tot += (udpint)a[3] * a[3];
|
||||
t += tot;
|
||||
spint v6 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[0] * a[7];
|
||||
tot += (udpint)a[1] * a[6];
|
||||
tot += (udpint)a[2] * a[5];
|
||||
tot += (udpint)a[3] * a[4];
|
||||
tot *= 2;
|
||||
t += tot;
|
||||
spint v7 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[0] * a[8];
|
||||
tot += (udpint)a[1] * a[7];
|
||||
tot += (udpint)a[2] * a[6];
|
||||
tot += (udpint)a[3] * a[5];
|
||||
tot *= 2;
|
||||
tot += (udpint)a[4] * a[4];
|
||||
t += tot;
|
||||
t += (udpint)v0 * p8;
|
||||
spint v8 = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[1] * a[8];
|
||||
tot += (udpint)a[2] * a[7];
|
||||
tot += (udpint)a[3] * a[6];
|
||||
tot += (udpint)a[4] * a[5];
|
||||
tot *= 2;
|
||||
t += tot;
|
||||
t += (udpint)v1 * p8;
|
||||
c[0] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[2] * a[8];
|
||||
tot += (udpint)a[3] * a[7];
|
||||
tot += (udpint)a[4] * a[6];
|
||||
tot *= 2;
|
||||
tot += (udpint)a[5] * a[5];
|
||||
t += tot;
|
||||
t += (udpint)v2 * p8;
|
||||
c[1] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[3] * a[8];
|
||||
tot += (udpint)a[4] * a[7];
|
||||
tot += (udpint)a[5] * a[6];
|
||||
tot *= 2;
|
||||
t += tot;
|
||||
t += (udpint)v3 * p8;
|
||||
c[2] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[4] * a[8];
|
||||
tot += (udpint)a[5] * a[7];
|
||||
tot *= 2;
|
||||
tot += (udpint)a[6] * a[6];
|
||||
t += tot;
|
||||
t += (udpint)v4 * p8;
|
||||
c[3] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[5] * a[8];
|
||||
tot += (udpint)a[6] * a[7];
|
||||
tot *= 2;
|
||||
t += tot;
|
||||
t += (udpint)v5 * p8;
|
||||
c[4] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[6] * a[8];
|
||||
tot *= 2;
|
||||
tot += (udpint)a[7] * a[7];
|
||||
t += tot;
|
||||
t += (udpint)v6 * p8;
|
||||
c[5] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[7] * a[8];
|
||||
tot *= 2;
|
||||
t += tot;
|
||||
t += (udpint)v7 * p8;
|
||||
c[6] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
tot = (udpint)a[8] * a[8];
|
||||
t += tot;
|
||||
t += (udpint)v8 * p8;
|
||||
c[7] = ((spint)t & mask);
|
||||
t >>= 29;
|
||||
c[8] = (spint)t;
|
||||
}
|
||||
|
||||
// copy
|
||||
static void modcpy(const spint *a, spint *c) {
|
||||
int i;
|
||||
for (i = 0; i < 9; i++) {
|
||||
c[i] = a[i];
|
||||
}
|
||||
}
|
||||
|
||||
// square n times
|
||||
static void modnsqr(spint *a, int n) {
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
modsqr(a, a);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate progenitor
|
||||
static void modpro(const spint *w, spint *z) {
|
||||
spint x[9];
|
||||
spint t0[9];
|
||||
spint t1[9];
|
||||
spint t2[9];
|
||||
spint t3[9];
|
||||
spint t4[9];
|
||||
modcpy(w, x);
|
||||
modsqr(x, z);
|
||||
modmul(x, z, t0);
|
||||
modsqr(t0, z);
|
||||
modmul(x, z, z);
|
||||
modsqr(z, t1);
|
||||
modsqr(t1, t3);
|
||||
modsqr(t3, t2);
|
||||
modcpy(t2, t4);
|
||||
modnsqr(t4, 3);
|
||||
modmul(t2, t4, t2);
|
||||
modcpy(t2, t4);
|
||||
modnsqr(t4, 6);
|
||||
modmul(t2, t4, t2);
|
||||
modcpy(t2, t4);
|
||||
modnsqr(t4, 2);
|
||||
modmul(t3, t4, t3);
|
||||
modnsqr(t3, 13);
|
||||
modmul(t2, t3, t2);
|
||||
modcpy(t2, t3);
|
||||
modnsqr(t3, 27);
|
||||
modmul(t2, t3, t2);
|
||||
modmul(z, t2, z);
|
||||
modcpy(z, t2);
|
||||
modnsqr(t2, 4);
|
||||
modmul(t1, t2, t1);
|
||||
modmul(t0, t1, t0);
|
||||
modmul(t1, t0, t1);
|
||||
modmul(t0, t1, t0);
|
||||
modmul(t1, t0, t2);
|
||||
modmul(t0, t2, t0);
|
||||
modmul(t1, t0, t1);
|
||||
modnsqr(t1, 63);
|
||||
modmul(t0, t1, t1);
|
||||
modnsqr(t1, 64);
|
||||
modmul(t0, t1, t0);
|
||||
modnsqr(t0, 57);
|
||||
modmul(z, t0, z);
|
||||
}
|
||||
|
||||
// calculate inverse, provide progenitor h if available
|
||||
static void modinv(const spint *x, const spint *h, spint *z) {
|
||||
spint s[9];
|
||||
spint t[9];
|
||||
if (h == NULL) {
|
||||
modpro(x, t);
|
||||
} else {
|
||||
modcpy(h, t);
|
||||
}
|
||||
modcpy(x, s);
|
||||
modnsqr(t, 2);
|
||||
modmul(s, t, z);
|
||||
}
|
||||
|
||||
// Convert m to n-residue form, n=nres(m)
|
||||
static void nres(const spint *m, spint *n) {
|
||||
const spint c[9] = {0xcf5c28fu, 0x6666666u, 0x13333333u,
|
||||
0x19999999u, 0xcccccccu, 0x6666666u,
|
||||
0x13333333u, 0x19999999u, 0x1ccccu};
|
||||
modmul(m, c, n);
|
||||
}
|
||||
|
||||
// Convert n back to normal form, m=redc(n)
|
||||
static void redc(const spint *n, spint *m) {
|
||||
int i;
|
||||
spint c[9];
|
||||
c[0] = 1;
|
||||
for (i = 1; i < 9; i++) {
|
||||
c[i] = 0;
|
||||
}
|
||||
modmul(n, c, m);
|
||||
(void)modfsb(m);
|
||||
}
|
||||
|
||||
// is unity?
|
||||
static int modis1(const spint *a) {
|
||||
int i;
|
||||
spint c[9];
|
||||
spint c0;
|
||||
spint d = 0;
|
||||
redc(a, c);
|
||||
for (i = 1; i < 9; i++) {
|
||||
d |= c[i];
|
||||
}
|
||||
c0 = (spint)c[0];
|
||||
return ((spint)1 & ((d - (spint)1) >> 29u) &
|
||||
(((c0 ^ (spint)1) - (spint)1) >> 29u));
|
||||
}
|
||||
|
||||
// is zero?
|
||||
static int modis0(const spint *a) {
|
||||
int i;
|
||||
spint c[9];
|
||||
spint d = 0;
|
||||
redc(a, c);
|
||||
for (i = 0; i < 9; i++) {
|
||||
d |= c[i];
|
||||
}
|
||||
return ((spint)1 & ((d - (spint)1) >> 29u));
|
||||
}
|
||||
|
||||
// set to zero
|
||||
static void modzer(spint *a) {
|
||||
int i;
|
||||
for (i = 0; i < 9; i++) {
|
||||
a[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// set to one
|
||||
static void modone(spint *a) {
|
||||
int i;
|
||||
a[0] = 1;
|
||||
for (i = 1; i < 9; i++) {
|
||||
a[i] = 0;
|
||||
}
|
||||
nres(a, a);
|
||||
}
|
||||
|
||||
// set to integer
|
||||
static void modint(int x, spint *a) {
|
||||
int i;
|
||||
a[0] = (spint)x;
|
||||
for (i = 1; i < 9; i++) {
|
||||
a[i] = 0;
|
||||
}
|
||||
nres(a, a);
|
||||
}
|
||||
|
||||
// Modular multiplication by an integer, c=a*b mod 2p
|
||||
static void modmli(const spint *a, int b, spint *c) {
|
||||
spint t[9];
|
||||
modint(b, t);
|
||||
modmul(a, t, c);
|
||||
}
|
||||
|
||||
// Test for quadratic residue
|
||||
static int modqr(const spint *h, const spint *x) {
|
||||
spint r[9];
|
||||
if (h == NULL) {
|
||||
modpro(x, r);
|
||||
modsqr(r, r);
|
||||
} else {
|
||||
modsqr(h, r);
|
||||
}
|
||||
modmul(r, x, r);
|
||||
return modis1(r) | modis0(x);
|
||||
}
|
||||
|
||||
// conditional move g to f if d=1
|
||||
// strongly recommend inlining be disabled using compiler specific syntax
|
||||
static void modcmv(int b, const spint *g, volatile spint *f) {
|
||||
int i;
|
||||
spint c0, c1, s, t;
|
||||
spint r = 0x5aa5a55au;
|
||||
c0 = (1 - b) + r;
|
||||
c1 = b + r;
|
||||
for (i = 0; i < 9; i++) {
|
||||
s = g[i];
|
||||
t = f[i];
|
||||
f[i] = c0 * t + c1 * s;
|
||||
f[i] -= r * (t + s);
|
||||
}
|
||||
}
|
||||
|
||||
// conditional swap g and f if d=1
|
||||
// strongly recommend inlining be disabled using compiler specific syntax
|
||||
static void modcsw(int b, volatile spint *g, volatile spint *f) {
|
||||
int i;
|
||||
spint c0, c1, s, t, w;
|
||||
spint r = 0x5aa5a55au;
|
||||
c0 = (1 - b) + r;
|
||||
c1 = b + r;
|
||||
for (i = 0; i < 9; i++) {
|
||||
s = g[i];
|
||||
t = f[i];
|
||||
w = r * (t + s);
|
||||
f[i] = c0 * t + c1 * s;
|
||||
f[i] -= w;
|
||||
g[i] = c0 * s + c1 * t;
|
||||
g[i] -= w;
|
||||
}
|
||||
}
|
||||
|
||||
// Modular square root, provide progenitor h if available, NULL if not
|
||||
static void modsqrt(const spint *x, const spint *h, spint *r) {
|
||||
spint s[9];
|
||||
spint y[9];
|
||||
if (h == NULL) {
|
||||
modpro(x, y);
|
||||
} else {
|
||||
modcpy(h, y);
|
||||
}
|
||||
modmul(y, x, s);
|
||||
modcpy(s, r);
|
||||
}
|
||||
|
||||
// shift left by less than a word
|
||||
static void modshl(unsigned int n, spint *a) {
|
||||
int i;
|
||||
a[8] = ((a[8] << n)) | (a[7] >> (29u - n));
|
||||
for (i = 7; i > 0; i--) {
|
||||
a[i] = ((a[i] << n) & (spint)0x1fffffff) | (a[i - 1] >> (29u - n));
|
||||
}
|
||||
a[0] = (a[0] << n) & (spint)0x1fffffff;
|
||||
}
|
||||
|
||||
// shift right by less than a word. Return shifted out part
|
||||
static int modshr(unsigned int n, spint *a) {
|
||||
int i;
|
||||
spint r = a[0] & (((spint)1 << n) - (spint)1);
|
||||
for (i = 0; i < 8; i++) {
|
||||
a[i] = (a[i] >> n) | ((a[i + 1] << (29u - n)) & (spint)0x1fffffff);
|
||||
}
|
||||
a[8] = a[8] >> n;
|
||||
return r;
|
||||
}
|
||||
|
||||
// set a= 2^r
|
||||
static void mod2r(unsigned int r, spint *a) {
|
||||
unsigned int n = r / 29u;
|
||||
unsigned int m = r % 29u;
|
||||
modzer(a);
|
||||
if (r >= 32 * 8)
|
||||
return;
|
||||
a[n] = 1;
|
||||
a[n] <<= m;
|
||||
nres(a, a);
|
||||
}
|
||||
|
||||
// export to byte array
|
||||
static void modexp(const spint *a, char *b) {
|
||||
int i;
|
||||
spint c[9];
|
||||
redc(a, c);
|
||||
for (i = 31; i >= 0; i--) {
|
||||
b[i] = c[0] & (spint)0xff;
|
||||
(void)modshr(8, c);
|
||||
}
|
||||
}
|
||||
|
||||
// import from byte array
|
||||
// returns 1 if in range, else 0
|
||||
static int modimp(const char *b, spint *a) {
|
||||
int i, res;
|
||||
for (i = 0; i < 9; i++) {
|
||||
a[i] = 0;
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
modshl(8, a);
|
||||
a[0] += (spint)(unsigned char)b[i];
|
||||
}
|
||||
res = modfsb(a);
|
||||
nres(a, a);
|
||||
return res;
|
||||
}
|
||||
|
||||
// determine sign
|
||||
static int modsign(const spint *a) {
|
||||
spint c[9];
|
||||
redc(a, c);
|
||||
return c[0] % 2;
|
||||
}
|
||||
|
||||
// return true if equal
|
||||
static int modcmp(const spint *a, const spint *b) {
|
||||
spint c[9], d[9];
|
||||
int i, eq = 1;
|
||||
redc(a, c);
|
||||
redc(b, d);
|
||||
for (i = 0; i < 9; i++) {
|
||||
eq &= (((c[i] ^ d[i]) - 1) >> 29) & 1;
|
||||
}
|
||||
return eq;
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
/******************************************************************************
|
||||
API functions calling generated code above
|
||||
******************************************************************************/
|
||||
|
||||
#include <fp.h>
|
||||
|
||||
const digit_t ZERO[NWORDS_FIELD] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
|
||||
const digit_t ONE[NWORDS_FIELD] = { 0x00000666, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00020000 };
|
||||
// Montgomery representation of 2^-1
|
||||
static const digit_t TWO_INV[NWORDS_FIELD] = { 0x00000333, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00010000 };
|
||||
// Montgomery representation of 3^-1
|
||||
static const digit_t THREE_INV[NWORDS_FIELD] = {
|
||||
0x15555777, 0x0aaaaaaa, 0x15555555, 0x0aaaaaaa, 0x15555555, 0x0aaaaaaa, 0x15555555, 0x0aaaaaaa, 0x00025555,
|
||||
};
|
||||
// Montgomery representation of 2^256
|
||||
static const digit_t R2[NWORDS_FIELD] = { 0x0667ae14, 0x13333333, 0x19999999, 0x0ccccccc, 0x06666666,
|
||||
0x13333333, 0x19999999, 0x0ccccccc, 0x00026666 };
|
||||
|
||||
void
|
||||
fp_set_small(fp_t *x, const digit_t val)
|
||||
{
|
||||
modint((int)val, *x);
|
||||
}
|
||||
|
||||
void
|
||||
fp_mul_small(fp_t *x, const fp_t *a, const uint32_t val)
|
||||
{
|
||||
modmli(*a, (int)val, *x);
|
||||
}
|
||||
|
||||
void
|
||||
fp_set_zero(fp_t *x)
|
||||
{
|
||||
modzer(*x);
|
||||
}
|
||||
|
||||
void
|
||||
fp_set_one(fp_t *x)
|
||||
{
|
||||
modone(*x);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
fp_is_equal(const fp_t *a, const fp_t *b)
|
||||
{
|
||||
return -(uint32_t)modcmp(*a, *b);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
fp_is_zero(const fp_t *a)
|
||||
{
|
||||
return -(uint32_t)modis0(*a);
|
||||
}
|
||||
|
||||
void
|
||||
fp_copy(fp_t *out, const fp_t *a)
|
||||
{
|
||||
modcpy(*a, *out);
|
||||
}
|
||||
|
||||
void
|
||||
fp_cswap(fp_t *a, fp_t *b, uint32_t ctl)
|
||||
{
|
||||
modcsw((int)(ctl & 0x1), *a, *b);
|
||||
}
|
||||
|
||||
void
|
||||
fp_add(fp_t *out, const fp_t *a, const fp_t *b)
|
||||
{
|
||||
modadd(*a, *b, *out);
|
||||
}
|
||||
|
||||
void
|
||||
fp_sub(fp_t *out, const fp_t *a, const fp_t *b)
|
||||
{
|
||||
modsub(*a, *b, *out);
|
||||
}
|
||||
|
||||
void
|
||||
fp_neg(fp_t *out, const fp_t *a)
|
||||
{
|
||||
modneg(*a, *out);
|
||||
}
|
||||
|
||||
void
|
||||
fp_sqr(fp_t *out, const fp_t *a)
|
||||
{
|
||||
modsqr(*a, *out);
|
||||
}
|
||||
|
||||
void
|
||||
fp_mul(fp_t *out, const fp_t *a, const fp_t *b)
|
||||
{
|
||||
modmul(*a, *b, *out);
|
||||
}
|
||||
|
||||
void
|
||||
fp_inv(fp_t *x)
|
||||
{
|
||||
modinv(*x, NULL, *x);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
fp_is_square(const fp_t *a)
|
||||
{
|
||||
return -(uint32_t)modqr(NULL, *a);
|
||||
}
|
||||
|
||||
void
|
||||
fp_sqrt(fp_t *a)
|
||||
{
|
||||
modsqrt(*a, NULL, *a);
|
||||
}
|
||||
|
||||
void
|
||||
fp_half(fp_t *out, const fp_t *a)
|
||||
{
|
||||
modmul(TWO_INV, *a, *out);
|
||||
}
|
||||
|
||||
void
|
||||
fp_exp3div4(fp_t *out, const fp_t *a)
|
||||
{
|
||||
modpro(*a, *out);
|
||||
}
|
||||
|
||||
void
|
||||
fp_div3(fp_t *out, const fp_t *a)
|
||||
{
|
||||
modmul(THREE_INV, *a, *out);
|
||||
}
|
||||
|
||||
void
|
||||
fp_encode(void *dst, const fp_t *a)
|
||||
{
|
||||
// Modified version of modexp()
|
||||
int i;
|
||||
spint c[9];
|
||||
redc(*a, c);
|
||||
for (i = 0; i < 32; i++) {
|
||||
((char *)dst)[i] = c[0] & (spint)0xff;
|
||||
(void)modshr(8, c);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
fp_decode(fp_t *d, const void *src)
|
||||
{
|
||||
// Modified version of modimp()
|
||||
int i;
|
||||
spint res;
|
||||
const unsigned char *b = src;
|
||||
for (i = 0; i < 9; i++) {
|
||||
(*d)[i] = 0;
|
||||
}
|
||||
for (i = 31; i >= 0; i--) {
|
||||
modshl(8, *d);
|
||||
(*d)[0] += (spint)b[i];
|
||||
}
|
||||
res = (spint)-modfsb(*d);
|
||||
nres(*d, *d);
|
||||
// If the value was canonical then res = -1; otherwise, res = 0
|
||||
for (i = 0; i < 9; i++) {
|
||||
(*d)[i] &= res;
|
||||
}
|
||||
return (uint32_t)res;
|
||||
}
|
||||
|
||||
static inline unsigned char
|
||||
add_carry(unsigned char cc, spint a, spint b, spint *d)
|
||||
{
|
||||
udpint t = (udpint)a + (udpint)b + cc;
|
||||
*d = (spint)t;
|
||||
return (unsigned char)(t >> Wordlength);
|
||||
}
|
||||
|
||||
static void
|
||||
partial_reduce(spint *out, const spint *src)
|
||||
{
|
||||
spint h, l, quo, rem;
|
||||
unsigned char cc;
|
||||
|
||||
// Split value in high (8 bits) and low (248 bits) parts.
|
||||
h = src[7] >> 24;
|
||||
l = src[7] & 0x00FFFFFF;
|
||||
|
||||
// 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 = add_carry(0, src[0], quo, &out[0]);
|
||||
cc = add_carry(cc, src[1], 0, &out[1]);
|
||||
cc = add_carry(cc, src[2], 0, &out[2]);
|
||||
cc = add_carry(cc, src[3], 0, &out[3]);
|
||||
cc = add_carry(cc, src[4], 0, &out[4]);
|
||||
cc = add_carry(cc, src[5], 0, &out[5]);
|
||||
cc = add_carry(cc, src[6], 0, &out[6]);
|
||||
(void)add_carry(cc, l, rem << 24, &out[7]);
|
||||
}
|
||||
|
||||
// Little-endian encoding of a 32-bit integer.
|
||||
static inline void
|
||||
enc32le(void *dst, uint32_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);
|
||||
}
|
||||
|
||||
// Little-endian decoding of a 32-bit integer.
|
||||
static inline uint32_t
|
||||
dec32le(const void *src)
|
||||
{
|
||||
const uint8_t *buf = src;
|
||||
return (spint)buf[0] | ((spint)buf[1] << 8) | ((spint)buf[2] << 16) | ((spint)buf[3] << 24);
|
||||
}
|
||||
|
||||
void
|
||||
fp_decode_reduce(fp_t *d, const void *src, size_t len)
|
||||
{
|
||||
uint32_t t[8]; // Stores Nbytes * 8 bits
|
||||
uint8_t tmp[32]; // Nbytes
|
||||
const uint8_t *b = src;
|
||||
|
||||
fp_set_zero(d);
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t rem = len % 32;
|
||||
if (rem != 0) {
|
||||
// Input size is not a multiple of 32, we decode a partial
|
||||
// block, which is already less than 2^248.
|
||||
size_t k = len - rem;
|
||||
memcpy(tmp, b + k, len - k);
|
||||
memset(tmp + len - k, 0, (sizeof tmp) - (len - k));
|
||||
fp_decode(d, tmp);
|
||||
len = k;
|
||||
}
|
||||
// Process all remaining blocks, in descending address order.
|
||||
while (len > 0) {
|
||||
fp_mul(d, d, &R2);
|
||||
len -= 32;
|
||||
t[0] = dec32le(b + len);
|
||||
t[1] = dec32le(b + len + 4);
|
||||
t[2] = dec32le(b + len + 8);
|
||||
t[3] = dec32le(b + len + 12);
|
||||
t[4] = dec32le(b + len + 16);
|
||||
t[5] = dec32le(b + len + 20);
|
||||
t[6] = dec32le(b + len + 24);
|
||||
t[7] = dec32le(b + len + 28);
|
||||
partial_reduce(t, t);
|
||||
enc32le(tmp, t[0]);
|
||||
enc32le(tmp + 4, t[1]);
|
||||
enc32le(tmp + 8, t[2]);
|
||||
enc32le(tmp + 12, t[3]);
|
||||
enc32le(tmp + 16, t[4]);
|
||||
enc32le(tmp + 20, t[5]);
|
||||
enc32le(tmp + 24, t[6]);
|
||||
enc32le(tmp + 28, t[7]);
|
||||
fp_t a;
|
||||
fp_decode(&a, tmp);
|
||||
fp_add(d, d, &a);
|
||||
}
|
||||
}
|
||||
93
src/pqm4/sqisign_lvl1/ref/hd.c
Normal file
93
src/pqm4/sqisign_lvl1/ref/hd.c
Normal file
@@ -0,0 +1,93 @@
|
||||
#include <hd.h>
|
||||
#include <assert.h>
|
||||
|
||||
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);
|
||||
}
|
||||
435
src/pqm4/sqisign_lvl1/ref/hd.h
Normal file
435
src/pqm4/sqisign_lvl1/ref/hd.h
Normal file
@@ -0,0 +1,435 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Antonin Leroux
|
||||
*
|
||||
* @brief The HD-isogenies algorithm required by the signature
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HD_H
|
||||
#define HD_H
|
||||
|
||||
#include <sqisign_namespace.h>
|
||||
#include <ec.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/** @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 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
|
||||
143
src/pqm4/sqisign_lvl1/ref/hd_splitting_transforms.c
Normal file
143
src/pqm4/sqisign_lvl1/ref/hd_splitting_transforms.c
Normal file
@@ -0,0 +1,143 @@
|
||||
#include <hd_splitting_transforms.h>
|
||||
|
||||
#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}}}};
|
||||
18
src/pqm4/sqisign_lvl1/ref/hd_splitting_transforms.h
Normal file
18
src/pqm4/sqisign_lvl1/ref/hd_splitting_transforms.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef HD_SPLITTING_H
|
||||
#define HD_SPLITTING_H
|
||||
|
||||
#include <hd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
||||
|
||||
28
src/pqm4/sqisign_lvl1/ref/isog.h
Normal file
28
src/pqm4/sqisign_lvl1/ref/isog.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef _ISOG_H_
|
||||
#define _ISOG_H_
|
||||
#include <sqisign_namespace.h>
|
||||
#include <ec.h>
|
||||
|
||||
/* 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
|
||||
241
src/pqm4/sqisign_lvl1/ref/isog_chains.c
Normal file
241
src/pqm4/sqisign_lvl1/ref/isog_chains.c
Normal file
@@ -0,0 +1,241 @@
|
||||
#include "isog.h"
|
||||
#include <assert.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
357
src/pqm4/sqisign_lvl1/ref/mp.c
Normal file
357
src/pqm4/sqisign_lvl1/ref/mp.c
Normal file
@@ -0,0 +1,357 @@
|
||||
#include <mp.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// 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)
|
||||
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<b
|
||||
|
||||
for (int i = nwords - 1; i >= 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];
|
||||
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);
|
||||
}
|
||||
88
src/pqm4/sqisign_lvl1/ref/mp.h
Normal file
88
src/pqm4/sqisign_lvl1/ref/mp.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef MP_H
|
||||
#define MP_H
|
||||
|
||||
#include <sqisign_namespace.h>
|
||||
#include <stdbool.h>
|
||||
#include <tutil.h>
|
||||
|
||||
// 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
|
||||
60
src/pqm4/sqisign_lvl1/ref/pqm4_api.c
Normal file
60
src/pqm4/sqisign_lvl1/ref/pqm4_api.c
Normal file
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include <api.h>
|
||||
#include <sig.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
size_t mlen;
|
||||
char msg[59];
|
||||
size_t smlen;
|
||||
char sm[59 + CRYPTO_BYTES];
|
||||
} SQISign_KAT_t;
|
||||
|
||||
const char kat_lvl1_pk[CRYPTO_PUBLICKEYBYTES] = {
|
||||
0x9F, 0x5F, 0x7F, 0xF0, 0x79, 0x3F, 0x17, 0x1C, 0x9B, 0x5D, 0x1B, 0x05, 0x99, 0xA8, 0x17, 0x68, 0x95, 0x14, 0x35, 0xFE, 0x8B, 0x18, 0x6D, 0xE0, 0xA1, 0x8B, 0xA0, 0xAB, 0x58, 0x39, 0x8C, 0x03, 0x7F, 0x40, 0xCC, 0x35, 0x7B, 0x0F, 0x4C, 0xAE, 0x9A, 0x93, 0x23, 0xCB, 0x31, 0xF2, 0x4C, 0x24, 0x47, 0xCA, 0x47, 0x17, 0x38, 0xD6, 0x00, 0x09, 0x34, 0xC3, 0x16, 0x54, 0x10, 0x8B, 0x42, 0x01, 0x0B,
|
||||
};
|
||||
|
||||
const SQISign_KAT_t kat_lvl1[2] = {
|
||||
{
|
||||
.mlen = 32,
|
||||
.msg = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
.smlen = 32 + CRYPTO_BYTES,
|
||||
.sm = { 0x7A, 0x34, 0xF2, 0xA7, 0xA8, 0x4F, 0xC0, 0x27, 0x0A, 0x4C, 0xEF, 0x98, 0x59, 0x0A, 0x18, 0x15, 0x6D, 0xBC, 0xC0, 0x22, 0xB5, 0x63, 0x1D, 0x20, 0xED, 0xB7, 0x37, 0x01, 0xC1, 0xF6, 0x02, 0x01, 0xF8, 0x51, 0x62, 0xA6, 0xA4, 0xF9, 0x6D, 0x92, 0xEA, 0x96, 0xE3, 0x11, 0x8B, 0x1A, 0x8C, 0xC9, 0x4A, 0x22, 0xF2, 0xD9, 0x36, 0x9A, 0xF6, 0xBD, 0x29, 0x84, 0x5A, 0xC8, 0x17, 0x2E, 0x73, 0x02, 0x00, 0x01, 0x36, 0x4C, 0x4B, 0x39, 0xFD, 0xF0, 0x1A, 0x6A, 0x89, 0xA4, 0xAB, 0x69, 0x67, 0x9D, 0xA0, 0x84, 0x5B, 0x2A, 0x9D, 0x1A, 0x89, 0x69, 0xAB, 0x7E, 0x6B, 0x44, 0xE5, 0xC9, 0x26, 0xEA, 0x3F, 0x16, 0x5A, 0x19, 0xFB, 0x24, 0x13, 0x4E, 0x69, 0x2B, 0x76, 0xBB, 0x41, 0x58, 0x90, 0x30, 0x2A, 0x37, 0x14, 0x84, 0xC9, 0x25, 0x92, 0x8D, 0xAB, 0x3C, 0x8E, 0x79, 0x08, 0x5C, 0xA6, 0x7F, 0x2F, 0x85, 0x10, 0x03, 0xB4, 0xE6, 0xCC, 0xB2, 0x09, 0xF2, 0xE2, 0x98, 0xC3, 0x8A, 0x47, 0xEF, 0x83, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
},
|
||||
{
|
||||
.mlen = 59,
|
||||
.msg = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
.smlen = 59 + CRYPTO_BYTES,
|
||||
.sm = { 0xB5, 0xCC, 0x8D, 0xAA, 0xC9, 0xFD, 0x34, 0x72, 0xB7, 0xF5, 0xC8, 0x92, 0x9E, 0x4B, 0x3B, 0x6E, 0xF7, 0x32, 0x50, 0x9F, 0xC0, 0xFD, 0xA4, 0xDD, 0x54, 0xFB, 0xFB, 0x28, 0x60, 0xAB, 0x40, 0x00, 0xD8, 0x60, 0xE0, 0xDD, 0x7E, 0xBD, 0xB1, 0x0F, 0xB6, 0x0A, 0xDC, 0x5E, 0xCC, 0x47, 0xC7, 0xDE, 0x50, 0x39, 0x87, 0x04, 0x4D, 0xF3, 0xC1, 0xBB, 0xDE, 0xAC, 0x9D, 0x55, 0x01, 0x61, 0x75, 0x03, 0x02, 0x01, 0xEE, 0xC8, 0x45, 0x75, 0xBD, 0xAC, 0x80, 0xC8, 0x06, 0x0F, 0xB0, 0x64, 0x34, 0x38, 0x8F, 0x39, 0x45, 0x75, 0xFF, 0x58, 0x0D, 0x78, 0xB2, 0xB5, 0x90, 0x17, 0x51, 0x39, 0x42, 0xAC, 0x21, 0x1E, 0x78, 0x90, 0xD3, 0xFA, 0x8D, 0xDC, 0x02, 0xC7, 0xB8, 0x31, 0x8B, 0x8E, 0x31, 0xD2, 0xF1, 0x25, 0xE9, 0xA3, 0xAC, 0x1E, 0x16, 0x9B, 0xD2, 0xA4, 0x6B, 0xC9, 0x27, 0xF1, 0xE0, 0x13, 0x50, 0x28, 0x7B, 0x23, 0x10, 0xCB, 0x69, 0x7D, 0x67, 0x8C, 0xB2, 0xB7, 0x07, 0x7F, 0xD4, 0xF5, 0x48, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
},
|
||||
};
|
||||
|
||||
int crypto_sign_keypair(unsigned char *pk, unsigned char *sk) {
|
||||
memcpy(pk, kat_lvl1_pk, CRYPTO_PUBLICKEYBYTES);
|
||||
// We don't need the secret key
|
||||
memset(sk, 0, CRYPTO_SECRETKEYBYTES);
|
||||
}
|
||||
|
||||
int crypto_sign(unsigned char *sm, size_t *smlen, const unsigned char *m,
|
||||
size_t mlen, const unsigned char *sk) {
|
||||
for (size_t i = 0; i < sizeof(kat_lvl1) / sizeof(kat_lvl1[0]); i++) {
|
||||
if (mlen == kat_lvl1[i].mlen) {
|
||||
memcpy(sm, kat_lvl1[i].sm, kat_lvl1[i].smlen);
|
||||
*smlen = kat_lvl1[i].smlen;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int crypto_sign_open(unsigned char *m, size_t *mlen, const unsigned char *sm,
|
||||
size_t smlen, const unsigned char *pk) {
|
||||
unsigned long long mlen_ull = *mlen;
|
||||
int ret = sqisign_open(m, &mlen_ull, sm, smlen, pk);
|
||||
if (mlen) {
|
||||
*mlen = mlen_ull;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
8
src/pqm4/sqisign_lvl1/ref/rng.h
Normal file
8
src/pqm4/sqisign_lvl1/ref/rng.h
Normal file
@@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#ifndef rng_h
|
||||
#define rng_h
|
||||
|
||||
#include "randombytes.h"
|
||||
|
||||
#endif /* rng_h */
|
||||
85
src/pqm4/sqisign_lvl1/ref/sig.h
Normal file
85
src/pqm4/sqisign_lvl1/ref/sig.h
Normal file
@@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#ifndef SQISIGN_H
|
||||
#define SQISIGN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sqisign_namespace.h>
|
||||
|
||||
#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);
|
||||
#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);
|
||||
|
||||
#endif
|
||||
106
src/pqm4/sqisign_lvl1/ref/sqisign.c
Normal file
106
src/pqm4/sqisign_lvl1/ref/sqisign.c
Normal file
@@ -0,0 +1,106 @@
|
||||
#include <sig.h>
|
||||
#include <string.h>
|
||||
#include <encoded_sizes.h>
|
||||
#include <verification.h>
|
||||
#if defined(ENABLE_SIGN)
|
||||
#include <signature.h>
|
||||
#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;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
|
||||
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;
|
||||
}
|
||||
1022
src/pqm4/sqisign_lvl1/ref/sqisign_namespace.h
Normal file
1022
src/pqm4/sqisign_lvl1/ref/sqisign_namespace.h
Normal file
File diff suppressed because it is too large
Load Diff
1283
src/pqm4/sqisign_lvl1/ref/theta_isogenies.c
Normal file
1283
src/pqm4/sqisign_lvl1/ref/theta_isogenies.c
Normal file
File diff suppressed because it is too large
Load Diff
18
src/pqm4/sqisign_lvl1/ref/theta_isogenies.h
Normal file
18
src/pqm4/sqisign_lvl1/ref/theta_isogenies.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Antonin Leroux
|
||||
*
|
||||
* @brief the theta isogeny header
|
||||
*/
|
||||
|
||||
#ifndef THETA_ISOGENY_H
|
||||
#define THETA_ISOGENY_H
|
||||
|
||||
#include <sqisign_namespace.h>
|
||||
#include <ec.h>
|
||||
#include <fp2.h>
|
||||
#include "theta_structure.h"
|
||||
#include <hd.h>
|
||||
#include <hd_splitting_transforms.h>
|
||||
|
||||
#endif
|
||||
78
src/pqm4/sqisign_lvl1/ref/theta_structure.c
Normal file
78
src/pqm4/sqisign_lvl1/ref/theta_structure.c
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "theta_structure.h"
|
||||
#include <assert.h>
|
||||
|
||||
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);
|
||||
}
|
||||
135
src/pqm4/sqisign_lvl1/ref/theta_structure.h
Normal file
135
src/pqm4/sqisign_lvl1/ref/theta_structure.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/** @file
|
||||
*
|
||||
* @authors Antonin Leroux
|
||||
*
|
||||
* @brief the theta structure header
|
||||
*/
|
||||
|
||||
#ifndef THETA_STRUCTURE_H
|
||||
#define THETA_STRUCTURE_H
|
||||
|
||||
#include <ec.h>
|
||||
#include <fp2.h>
|
||||
#include <hd.h>
|
||||
|
||||
/** @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
|
||||
49
src/pqm4/sqisign_lvl1/ref/tools.h
Normal file
49
src/pqm4/sqisign_lvl1/ref/tools.h
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
#ifndef TOOLS_H
|
||||
#define TOOLS_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
// 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
|
||||
36
src/pqm4/sqisign_lvl1/ref/tutil.h
Normal file
36
src/pqm4/sqisign_lvl1/ref/tutil.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef TUTIL_H
|
||||
#define TUTIL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define BSWAP16(i) __builtin_bswap16((i))
|
||||
#define BSWAP32(i) __builtin_bswap32((i))
|
||||
#define BSWAP64(i) __builtin_bswap64((i))
|
||||
#define UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define BSWAP16(i) ((((i) >> 8) & 0xff) | (((i) & 0xff00) << 8))
|
||||
#define BSWAP32(i) \
|
||||
((((i) >> 24) & 0xff) | (((i) >> 8) & 0xff00) | (((i) & 0xff00) << 8) | ((i) << 24))
|
||||
#define BSWAP64(i) ((BSWAP32((i) >> 32) & 0xffffffff) | (BSWAP32(i) << 32)
|
||||
#define UNUSED
|
||||
#endif
|
||||
|
||||
#if defined(RADIX_64)
|
||||
#define digit_t uint64_t
|
||||
#define sdigit_t int64_t
|
||||
#define RADIX 64
|
||||
#define LOG2RADIX 6
|
||||
#define BSWAP_DIGIT(i) BSWAP64(i)
|
||||
#elif defined(RADIX_32)
|
||||
#define digit_t uint32_t
|
||||
#define sdigit_t int32_t
|
||||
#define RADIX 32
|
||||
#define LOG2RADIX 5
|
||||
#define BSWAP_DIGIT(i) BSWAP32(i)
|
||||
#else
|
||||
#error "Radix must be 32bit or 64 bit"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
123
src/pqm4/sqisign_lvl1/ref/verification.h
Normal file
123
src/pqm4/sqisign_lvl1/ref/verification.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/** @file
|
||||
*
|
||||
* @brief The verification protocol
|
||||
*/
|
||||
|
||||
#ifndef VERIFICATION_H
|
||||
#define VERIFICATION_H
|
||||
|
||||
#include <sqisign_namespace.h>
|
||||
#include <ec.h>
|
||||
|
||||
/** @defgroup verification SQIsignHD verification protocol
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup verification_t Types for SQIsignHD verification protocol
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef digit_t scalar_t[NWORDS_ORDER];
|
||||
typedef scalar_t scalar_mtx_2x2_t[2][2];
|
||||
|
||||
/** @brief Type for the signature
|
||||
*
|
||||
* @typedef signature_t
|
||||
*
|
||||
* @struct signature
|
||||
*
|
||||
*/
|
||||
typedef struct signature
|
||||
{
|
||||
fp2_t E_aux_A; // the Montgomery A-coefficient for the auxiliary curve
|
||||
uint8_t backtracking;
|
||||
uint8_t two_resp_length;
|
||||
scalar_mtx_2x2_t mat_Bchall_can_to_B_chall; // the matrix of the desired basis
|
||||
scalar_t chall_coeff;
|
||||
uint8_t hint_aux;
|
||||
uint8_t hint_chall;
|
||||
} signature_t;
|
||||
|
||||
/** @brief Type for the public keys
|
||||
*
|
||||
* @typedef public_key_t
|
||||
*
|
||||
* @struct public_key
|
||||
*
|
||||
*/
|
||||
typedef struct public_key
|
||||
{
|
||||
ec_curve_t curve; // the normalized A-coefficient of the Montgomery curve
|
||||
uint8_t hint_pk;
|
||||
} public_key_t;
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/*************************** Functions *****************************/
|
||||
|
||||
void public_key_init(public_key_t *pk);
|
||||
void public_key_finalize(public_key_t *pk);
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Verification
|
||||
*
|
||||
* @param sig signature
|
||||
* @param pk public key
|
||||
* @param m message
|
||||
* @param l size
|
||||
* @returns 1 if the signature verifies, 0 otherwise
|
||||
*/
|
||||
int protocols_verify(signature_t *sig, const public_key_t *pk, const unsigned char *m, size_t l);
|
||||
|
||||
/*************************** Encoding *****************************/
|
||||
|
||||
/** @defgroup encoding Encoding and decoding functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Encodes a signature as a byte array
|
||||
*
|
||||
* @param enc : Byte array to encode the signature in
|
||||
* @param sig : Signature to encode
|
||||
*/
|
||||
void signature_to_bytes(unsigned char *enc, const signature_t *sig);
|
||||
|
||||
/**
|
||||
* @brief Decodes a signature from a byte array
|
||||
*
|
||||
* @param sig : Structure to decode the signature in
|
||||
* @param enc : Byte array to decode
|
||||
*/
|
||||
void signature_from_bytes(signature_t *sig, const unsigned char *enc);
|
||||
|
||||
/**
|
||||
* @brief Encodes a public key as a byte array
|
||||
*
|
||||
* @param enc : Byte array to encode the public key in
|
||||
* @param pk : Public key to encode
|
||||
*/
|
||||
unsigned char *public_key_to_bytes(unsigned char *enc, const public_key_t *pk);
|
||||
|
||||
/**
|
||||
* @brief Decodes a public key from a byte array
|
||||
*
|
||||
* @param pk : Structure to decode the public key in
|
||||
* @param enc : Byte array to decode
|
||||
*/
|
||||
const unsigned char *public_key_from_bytes(public_key_t *pk, const unsigned char *enc);
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @}
|
||||
*/
|
||||
|
||||
#endif
|
||||
309
src/pqm4/sqisign_lvl1/ref/verify.c
Normal file
309
src/pqm4/sqisign_lvl1/ref/verify.c
Normal file
@@ -0,0 +1,309 @@
|
||||
#include <verification.h>
|
||||
#include <mp.h>
|
||||
#include <hd.h>
|
||||
#include <encoded_sizes.h>
|
||||
#include <assert.h>
|
||||
|
||||
// Check that the basis change matrix elements are canonical
|
||||
// representatives modulo 2^(SQIsign_response_length + 2).
|
||||
static int
|
||||
check_canonical_basis_change_matrix(const signature_t *sig)
|
||||
{
|
||||
// This works as long as all values in sig->mat_Bchall_can_to_B_chall are
|
||||
// positive integers.
|
||||
int ret = 1;
|
||||
scalar_t aux;
|
||||
|
||||
memset(aux, 0, NWORDS_ORDER * sizeof(digit_t));
|
||||
aux[0] = 0x1;
|
||||
multiple_mp_shiftl(aux, SQIsign_response_length + HD_extra_torsion - (int)sig->backtracking, NWORDS_ORDER);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
if (mp_compare(aux, sig->mat_Bchall_can_to_B_chall[i][j], NWORDS_ORDER) <= 0) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Compute the 2^n isogeny from the signature with kernel
|
||||
// P + [chall_coeff]Q and store the codomain in E_chall
|
||||
static int
|
||||
compute_challenge_verify(ec_curve_t *E_chall, const signature_t *sig, const ec_curve_t *Epk, const uint8_t hint_pk)
|
||||
{
|
||||
ec_basis_t bas_EA;
|
||||
ec_isog_even_t phi_chall;
|
||||
|
||||
// Set domain and length of 2^n isogeny
|
||||
copy_curve(&phi_chall.curve, Epk);
|
||||
phi_chall.length = TORSION_EVEN_POWER - sig->backtracking;
|
||||
|
||||
// Compute the basis from the supplied hint
|
||||
if (!ec_curve_to_basis_2f_from_hint(&bas_EA, &phi_chall.curve, TORSION_EVEN_POWER, hint_pk)) // canonical
|
||||
return 0;
|
||||
|
||||
// recovering the exact challenge
|
||||
{
|
||||
if (!ec_ladder3pt(&phi_chall.kernel, sig->chall_coeff, &bas_EA.P, &bas_EA.Q, &bas_EA.PmQ, &phi_chall.curve)) {
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
// Double the kernel until is has the correct order
|
||||
ec_dbl_iter(&phi_chall.kernel, sig->backtracking, &phi_chall.kernel, &phi_chall.curve);
|
||||
|
||||
// Compute the codomain
|
||||
copy_curve(E_chall, &phi_chall.curve);
|
||||
if (ec_eval_even(E_chall, &phi_chall, NULL, 0))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// same as matrix_application_even_basis() in id2iso.c, with some modifications:
|
||||
// - this version works with a matrix of scalars (not ibz_t).
|
||||
// - reduction modulo 2^f of matrix elements is removed here, because it is
|
||||
// assumed that the elements are already cannonical representatives modulo
|
||||
// 2^f; this is ensured by calling check_canonical_basis_change_matrix() at
|
||||
// the beginning of protocols_verify().
|
||||
static int
|
||||
matrix_scalar_application_even_basis(ec_basis_t *bas, const ec_curve_t *E, scalar_mtx_2x2_t *mat, int f)
|
||||
{
|
||||
scalar_t scalar0, scalar1;
|
||||
memset(scalar0, 0, NWORDS_ORDER * sizeof(digit_t));
|
||||
memset(scalar1, 0, NWORDS_ORDER * sizeof(digit_t));
|
||||
|
||||
ec_basis_t tmp_bas;
|
||||
copy_basis(&tmp_bas, bas);
|
||||
|
||||
// For a matrix [[a, c], [b, d]] we compute:
|
||||
//
|
||||
// first basis element R = [a]P + [b]Q
|
||||
if (!ec_biscalar_mul(&bas->P, (*mat)[0][0], (*mat)[1][0], f, &tmp_bas, E))
|
||||
return 0;
|
||||
// second basis element S = [c]P + [d]Q
|
||||
if (!ec_biscalar_mul(&bas->Q, (*mat)[0][1], (*mat)[1][1], f, &tmp_bas, E))
|
||||
return 0;
|
||||
// Their difference R - S = [a - c]P + [b - d]Q
|
||||
mp_sub(scalar0, (*mat)[0][0], (*mat)[0][1], NWORDS_ORDER);
|
||||
mp_mod_2exp(scalar0, f, NWORDS_ORDER);
|
||||
mp_sub(scalar1, (*mat)[1][0], (*mat)[1][1], NWORDS_ORDER);
|
||||
mp_mod_2exp(scalar1, f, NWORDS_ORDER);
|
||||
return ec_biscalar_mul(&bas->PmQ, scalar0, scalar1, f, &tmp_bas, E);
|
||||
}
|
||||
|
||||
// Compute the bases for the challenge and auxillary curve from
|
||||
// the canonical bases. Challenge basis is reconstructed from the
|
||||
// compressed scalars within the challenge.
|
||||
static int
|
||||
challenge_and_aux_basis_verify(ec_basis_t *B_chall_can,
|
||||
ec_basis_t *B_aux_can,
|
||||
ec_curve_t *E_chall,
|
||||
ec_curve_t *E_aux,
|
||||
signature_t *sig,
|
||||
const int pow_dim2_deg_resp)
|
||||
{
|
||||
|
||||
// recovering the canonical basis as TORSION_EVEN_POWER for consistency with signing
|
||||
if (!ec_curve_to_basis_2f_from_hint(B_chall_can, E_chall, TORSION_EVEN_POWER, sig->hint_chall))
|
||||
return 0;
|
||||
|
||||
// setting to the right order
|
||||
ec_dbl_iter_basis(B_chall_can,
|
||||
TORSION_EVEN_POWER - pow_dim2_deg_resp - HD_extra_torsion - sig->two_resp_length,
|
||||
B_chall_can,
|
||||
E_chall);
|
||||
|
||||
if (!ec_curve_to_basis_2f_from_hint(B_aux_can, E_aux, TORSION_EVEN_POWER, sig->hint_aux))
|
||||
return 0;
|
||||
|
||||
// setting to the right order
|
||||
ec_dbl_iter_basis(B_aux_can, TORSION_EVEN_POWER - pow_dim2_deg_resp - HD_extra_torsion, B_aux_can, E_aux);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (!test_basis_order_twof(B_chall_can, E_chall, HD_extra_torsion + pow_dim2_deg_resp + sig->two_resp_length))
|
||||
debug_print("canonical basis has wrong order, expect something to fail");
|
||||
#endif
|
||||
|
||||
// applying the change matrix on the basis of E_chall
|
||||
return matrix_scalar_application_even_basis(B_chall_can,
|
||||
E_chall,
|
||||
&sig->mat_Bchall_can_to_B_chall,
|
||||
pow_dim2_deg_resp + HD_extra_torsion + sig->two_resp_length);
|
||||
}
|
||||
|
||||
// When two_resp_length is non-zero, we must compute a small 2^n-isogeny
|
||||
// updating E_chall as the codomain as well as push the basis on E_chall
|
||||
// through this isogeny
|
||||
static int
|
||||
two_response_isogeny_verify(ec_curve_t *E_chall, ec_basis_t *B_chall_can, const signature_t *sig, int pow_dim2_deg_resp)
|
||||
{
|
||||
ec_point_t ker, points[3];
|
||||
|
||||
// choosing the right point for the small two_isogenies
|
||||
if (mp_is_even(sig->mat_Bchall_can_to_B_chall[0][0], NWORDS_ORDER) &&
|
||||
mp_is_even(sig->mat_Bchall_can_to_B_chall[1][0], NWORDS_ORDER)) {
|
||||
copy_point(&ker, &B_chall_can->Q);
|
||||
} else {
|
||||
copy_point(&ker, &B_chall_can->P);
|
||||
}
|
||||
|
||||
copy_point(&points[0], &B_chall_can->P);
|
||||
copy_point(&points[1], &B_chall_can->Q);
|
||||
copy_point(&points[2], &B_chall_can->PmQ);
|
||||
|
||||
ec_dbl_iter(&ker, pow_dim2_deg_resp + HD_extra_torsion, &ker, E_chall);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (!test_point_order_twof(&ker, E_chall, sig->two_resp_length))
|
||||
debug_print("kernel does not have order 2^(two_resp_length");
|
||||
#endif
|
||||
|
||||
if (ec_eval_small_chain(E_chall, &ker, sig->two_resp_length, points, 3, false)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (!test_point_order_twof(&points[0], E_chall, HD_extra_torsion + pow_dim2_deg_resp))
|
||||
debug_print("points[0] does not have order 2^(HD_extra_torsion + pow_dim2_deg_resp");
|
||||
if (!test_point_order_twof(&points[1], E_chall, HD_extra_torsion + pow_dim2_deg_resp))
|
||||
debug_print("points[1] does not have order 2^(HD_extra_torsion + pow_dim2_deg_resp");
|
||||
if (!test_point_order_twof(&points[2], E_chall, HD_extra_torsion + pow_dim2_deg_resp))
|
||||
debug_print("points[2] does not have order 2^(HD_extra_torsion + pow_dim2_deg_resp");
|
||||
#endif
|
||||
|
||||
copy_point(&B_chall_can->P, &points[0]);
|
||||
copy_point(&B_chall_can->Q, &points[1]);
|
||||
copy_point(&B_chall_can->PmQ, &points[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// The commitment curve can be recovered from the codomain of the 2D
|
||||
// isogeny built from the bases computed during verification.
|
||||
static int
|
||||
compute_commitment_curve_verify(ec_curve_t *E_com,
|
||||
const ec_basis_t *B_chall_can,
|
||||
const ec_basis_t *B_aux_can,
|
||||
const ec_curve_t *E_chall,
|
||||
const ec_curve_t *E_aux,
|
||||
int pow_dim2_deg_resp)
|
||||
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// Check all the points are the correct order
|
||||
if (!test_basis_order_twof(B_chall_can, E_chall, HD_extra_torsion + pow_dim2_deg_resp))
|
||||
debug_print("B_chall_can does not have order 2^(HD_extra_torsion + pow_dim2_deg_resp");
|
||||
|
||||
if (!test_basis_order_twof(B_aux_can, E_aux, HD_extra_torsion + pow_dim2_deg_resp))
|
||||
debug_print("B_aux_can does not have order 2^(HD_extra_torsion + pow_dim2_deg_resp");
|
||||
#endif
|
||||
|
||||
// now compute the dim2 isogeny from Echall x E_aux -> E_com x E_aux'
|
||||
// of kernel B_chall_can x B_aux_can
|
||||
|
||||
// first we set-up the kernel
|
||||
theta_couple_curve_t EchallxEaux;
|
||||
copy_curve(&EchallxEaux.E1, E_chall);
|
||||
copy_curve(&EchallxEaux.E2, E_aux);
|
||||
|
||||
theta_kernel_couple_points_t dim_two_ker;
|
||||
copy_bases_to_kernel(&dim_two_ker, B_chall_can, B_aux_can);
|
||||
|
||||
// computing the isogeny
|
||||
theta_couple_curve_t codomain;
|
||||
int codomain_splits;
|
||||
ec_curve_init(&codomain.E1);
|
||||
ec_curve_init(&codomain.E2);
|
||||
// handling the special case where we don't need to perform any dim2 computation
|
||||
if (pow_dim2_deg_resp == 0) {
|
||||
codomain_splits = 1;
|
||||
copy_curve(&codomain.E1, &EchallxEaux.E1);
|
||||
copy_curve(&codomain.E2, &EchallxEaux.E2);
|
||||
// We still need to check that E_chall is supersingular
|
||||
// This assumes that HD_extra_torsion == 2
|
||||
if (!ec_is_basis_four_torsion(B_chall_can, E_chall)) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
codomain_splits = theta_chain_compute_and_eval_verify(
|
||||
pow_dim2_deg_resp, &EchallxEaux, &dim_two_ker, true, &codomain, NULL, 0);
|
||||
}
|
||||
|
||||
// computing the commitment curve
|
||||
// its always the first one because of our (2^n,2^n)-isogeny formulae
|
||||
copy_curve(E_com, &codomain.E1);
|
||||
|
||||
return codomain_splits;
|
||||
}
|
||||
|
||||
// SQIsign verification
|
||||
int
|
||||
protocols_verify(signature_t *sig, const public_key_t *pk, const unsigned char *m, size_t l)
|
||||
{
|
||||
int verify;
|
||||
|
||||
if (!check_canonical_basis_change_matrix(sig))
|
||||
return 0;
|
||||
|
||||
// Computation of the length of the dim 2 2^n isogeny
|
||||
int pow_dim2_deg_resp = SQIsign_response_length - (int)sig->two_resp_length - (int)sig->backtracking;
|
||||
|
||||
// basic sanity test: checking that the response is not too long
|
||||
if (pow_dim2_deg_resp < 0)
|
||||
return 0;
|
||||
// The dim 2 isogeny embeds a dim 1 isogeny of odd degree, so it can
|
||||
// never be of length 2.
|
||||
if (pow_dim2_deg_resp == 1)
|
||||
return 0;
|
||||
|
||||
// check the public curve is valid
|
||||
if (!ec_curve_verify_A(&(pk->curve).A))
|
||||
return 0;
|
||||
|
||||
// Set auxiliary curve from the A-coefficient within the signature
|
||||
ec_curve_t E_aux;
|
||||
if (!ec_curve_init_from_A(&E_aux, &sig->E_aux_A))
|
||||
return 0; // invalid curve
|
||||
|
||||
// checking that we are given A-coefficients and no precomputation
|
||||
assert(fp2_is_one(&pk->curve.C) == 0xFFFFFFFF && !pk->curve.is_A24_computed_and_normalized);
|
||||
|
||||
// computation of the challenge
|
||||
ec_curve_t E_chall;
|
||||
if (!compute_challenge_verify(&E_chall, sig, &pk->curve, pk->hint_pk)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Computation of the canonical bases for the challenge and aux curve
|
||||
ec_basis_t B_chall_can, B_aux_can;
|
||||
|
||||
if (!challenge_and_aux_basis_verify(&B_chall_can, &B_aux_can, &E_chall, &E_aux, sig, pow_dim2_deg_resp)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// When two_resp_length != 0 we need to compute a second, short 2^r-isogeny
|
||||
if (sig->two_resp_length > 0) {
|
||||
if (!two_response_isogeny_verify(&E_chall, &B_chall_can, sig, pow_dim2_deg_resp)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// We can recover the commitment curve with a 2D isogeny
|
||||
// The supplied signature did not compute an isogeny between eliptic products
|
||||
// and so definitely is an invalid signature.
|
||||
ec_curve_t E_com;
|
||||
if (!compute_commitment_curve_verify(&E_com, &B_chall_can, &B_aux_can, &E_chall, &E_aux, pow_dim2_deg_resp))
|
||||
return 0;
|
||||
|
||||
scalar_t chk_chall;
|
||||
|
||||
// recomputing the challenge vector
|
||||
hash_to_challenge(&chk_chall, pk, &E_com, m, l);
|
||||
|
||||
// performing the final check
|
||||
verify = mp_compare(sig->chall_coeff, chk_chall, NWORDS_ORDER) == 0;
|
||||
|
||||
return verify;
|
||||
}
|
||||
64
src/pqm4/sqisign_lvl1/ref/xeval.c
Normal file
64
src/pqm4/sqisign_lvl1/ref/xeval.c
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "isog.h"
|
||||
#include "ec.h"
|
||||
#include <assert.h>
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// Degree-2 isogeny evaluation with kenerl generated by P != (0, 0)
|
||||
void
|
||||
xeval_2(ec_point_t *R, ec_point_t *const Q, const int lenQ, const ec_kps2_t *kps)
|
||||
{
|
||||
fp2_t t0, t1, t2;
|
||||
for (int j = 0; j < lenQ; j++) {
|
||||
fp2_add(&t0, &Q[j].x, &Q[j].z);
|
||||
fp2_sub(&t1, &Q[j].x, &Q[j].z);
|
||||
fp2_mul(&t2, &kps->K.x, &t1);
|
||||
fp2_mul(&t1, &kps->K.z, &t0);
|
||||
fp2_add(&t0, &t2, &t1);
|
||||
fp2_sub(&t1, &t2, &t1);
|
||||
fp2_mul(&R[j].x, &Q[j].x, &t0);
|
||||
fp2_mul(&R[j].z, &Q[j].z, &t1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xeval_2_singular(ec_point_t *R, const ec_point_t *Q, const int lenQ, const ec_kps2_t *kps)
|
||||
{
|
||||
fp2_t t0, t1;
|
||||
for (int i = 0; i < lenQ; i++) {
|
||||
fp2_mul(&t0, &Q[i].x, &Q[i].z);
|
||||
fp2_mul(&t1, &kps->K.x, &Q[i].z);
|
||||
fp2_add(&t1, &t1, &Q[i].x);
|
||||
fp2_mul(&t1, &t1, &Q[i].x);
|
||||
fp2_sqr(&R[i].x, &Q[i].z);
|
||||
fp2_add(&R[i].x, &R[i].x, &t1);
|
||||
fp2_mul(&R[i].z, &t0, &kps->K.z);
|
||||
}
|
||||
}
|
||||
|
||||
// Degree-4 isogeny evaluation with kenerl generated by P such that [2]P != (0, 0)
|
||||
void
|
||||
xeval_4(ec_point_t *R, const ec_point_t *Q, const int lenQ, const ec_kps4_t *kps)
|
||||
{
|
||||
const ec_point_t *K = kps->K;
|
||||
|
||||
fp2_t t0, t1;
|
||||
|
||||
for (int i = 0; i < lenQ; i++) {
|
||||
fp2_add(&t0, &Q[i].x, &Q[i].z);
|
||||
fp2_sub(&t1, &Q[i].x, &Q[i].z);
|
||||
fp2_mul(&(R[i].x), &t0, &K[1].x);
|
||||
fp2_mul(&(R[i].z), &t1, &K[2].x);
|
||||
fp2_mul(&t0, &t0, &t1);
|
||||
fp2_mul(&t0, &t0, &K[0].x);
|
||||
fp2_add(&t1, &(R[i].x), &(R[i].z));
|
||||
fp2_sub(&(R[i].z), &(R[i].x), &(R[i].z));
|
||||
fp2_sqr(&t1, &t1);
|
||||
fp2_sqr(&(R[i].z), &(R[i].z));
|
||||
fp2_add(&(R[i].x), &t0, &t1);
|
||||
fp2_sub(&t0, &t0, &(R[i].z));
|
||||
fp2_mul(&(R[i].x), &(R[i].x), &t1);
|
||||
fp2_mul(&(R[i].z), &(R[i].z), &t0);
|
||||
}
|
||||
}
|
||||
61
src/pqm4/sqisign_lvl1/ref/xisog.c
Normal file
61
src/pqm4/sqisign_lvl1/ref/xisog.c
Normal file
@@ -0,0 +1,61 @@
|
||||
#include "isog.h"
|
||||
#include "ec.h"
|
||||
#include <assert.h>
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Degree-2 isogeny with kernel generated by P != (0 ,0)
|
||||
// Outputs the curve coefficient in the form A24=(A+2C:4C)
|
||||
void
|
||||
xisog_2(ec_kps2_t *kps, ec_point_t *B, const ec_point_t P)
|
||||
{
|
||||
fp2_sqr(&B->x, &P.x);
|
||||
fp2_sqr(&B->z, &P.z);
|
||||
fp2_sub(&B->x, &B->z, &B->x);
|
||||
fp2_add(&kps->K.x, &P.x, &P.z);
|
||||
fp2_sub(&kps->K.z, &P.x, &P.z);
|
||||
}
|
||||
|
||||
void
|
||||
xisog_2_singular(ec_kps2_t *kps, ec_point_t *B24, ec_point_t A24)
|
||||
{
|
||||
// No need to check the square root, only used for signing.
|
||||
fp2_t t0, four;
|
||||
fp2_set_small(&four, 4);
|
||||
fp2_add(&t0, &A24.x, &A24.x);
|
||||
fp2_sub(&t0, &t0, &A24.z);
|
||||
fp2_add(&t0, &t0, &t0);
|
||||
fp2_inv(&A24.z);
|
||||
fp2_mul(&t0, &t0, &A24.z);
|
||||
fp2_copy(&kps->K.x, &t0);
|
||||
fp2_add(&B24->x, &t0, &t0);
|
||||
fp2_sqr(&t0, &t0);
|
||||
fp2_sub(&t0, &t0, &four);
|
||||
fp2_sqrt(&t0);
|
||||
fp2_neg(&kps->K.z, &t0);
|
||||
fp2_add(&B24->z, &t0, &t0);
|
||||
fp2_add(&B24->x, &B24->x, &B24->z);
|
||||
fp2_add(&B24->z, &B24->z, &B24->z);
|
||||
}
|
||||
|
||||
// Degree-4 isogeny with kernel generated by P such that [2]P != (0 ,0)
|
||||
// Outputs the curve coefficient in the form A24=(A+2C:4C)
|
||||
void
|
||||
xisog_4(ec_kps4_t *kps, ec_point_t *B, const ec_point_t P)
|
||||
{
|
||||
ec_point_t *K = kps->K;
|
||||
|
||||
fp2_sqr(&K[0].x, &P.x);
|
||||
fp2_sqr(&K[0].z, &P.z);
|
||||
fp2_add(&K[1].x, &K[0].z, &K[0].x);
|
||||
fp2_sub(&K[1].z, &K[0].z, &K[0].x);
|
||||
fp2_mul(&B->x, &K[1].x, &K[1].z);
|
||||
fp2_sqr(&B->z, &K[0].z);
|
||||
|
||||
// Constants for xeval_4
|
||||
fp2_add(&K[2].x, &P.x, &P.z);
|
||||
fp2_sub(&K[1].x, &P.x, &P.z);
|
||||
fp2_add(&K[0].x, &K[0].z, &K[0].z);
|
||||
fp2_add(&K[0].x, &K[0].x, &K[0].x);
|
||||
}
|
||||
Reference in New Issue
Block a user