Files
sqisign/src/pqm4/sqisign_lvl1/ref/ec.h
StarsAC 9f0409b6b4
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
add pqm4
2025-10-20 01:07:36 +00:00

669 lines
16 KiB
C

/** @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
/**
* @}
*/