This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
263
unikernel/duniverse/mirage-crypto/ec/native/point_operations.h
Normal file
263
unikernel/duniverse/mirage-crypto/ec/native/point_operations.h
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
#define MAKE_FN_NAME1(x,y) x ## y
|
||||
#define MAKE_FN_NAME(x,y) MAKE_FN_NAME1(x,y)
|
||||
|
||||
#define fe_one MAKE_FN_NAME(CURVE_DESCRIPTION,_set_one)
|
||||
|
||||
#define fe_add MAKE_FN_NAME(CURVE_DESCRIPTION,_add)
|
||||
#define fe_sub MAKE_FN_NAME(CURVE_DESCRIPTION,_sub)
|
||||
|
||||
#define fe_mul MAKE_FN_NAME(CURVE_DESCRIPTION,_mul)
|
||||
#define fe_sqr MAKE_FN_NAME(CURVE_DESCRIPTION,_square)
|
||||
|
||||
#define fe_nonzero MAKE_FN_NAME(CURVE_DESCRIPTION,_nonzero)
|
||||
#define fe_selectznz MAKE_FN_NAME(CURVE_DESCRIPTION,_selectznz)
|
||||
|
||||
#define fe_from_bytes MAKE_FN_NAME(CURVE_DESCRIPTION,_from_bytes)
|
||||
#define fe_to_mont MAKE_FN_NAME(CURVE_DESCRIPTION,_to_montgomery)
|
||||
|
||||
typedef WORD fe[LIMBS];
|
||||
|
||||
static WORD fe_nz(const WORD in1[LIMBS]) {
|
||||
WORD ret;
|
||||
fe_nonzero(&ret, in1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fe_copy(WORD out[LIMBS], const WORD in1[LIMBS]) {
|
||||
for (int i = 0; i < LIMBS; i++) {
|
||||
out[i] = in1[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void fe_cmovznz(WORD out[LIMBS], WORD t, const WORD z[LIMBS],
|
||||
const WORD nz[LIMBS]) {
|
||||
fe_selectznz(out, !!t, z, nz);
|
||||
}
|
||||
|
||||
// Group operations
|
||||
// ----------------
|
||||
//
|
||||
// Building on top of the field operations we have the operations on the
|
||||
// elliptic curve group itself. Points on the curve are represented in Jacobian
|
||||
// coordinates.
|
||||
//
|
||||
// Both operations were transcribed to Coq and proven to correspond to naive
|
||||
// implementations using Affine coordinates, for all suitable fields. In the
|
||||
// Coq proofs, issues of constant-time execution and memory layout (aliasing)
|
||||
// conventions were not considered. Specification of affine coordinates:
|
||||
// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Spec/WeierstrassCurve.v#L28>
|
||||
// As a sanity check, a proof that these points form a commutative group:
|
||||
// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Curves/Weierstrass/AffineProofs.v#L33>
|
||||
|
||||
// point_double calculates 2*(x_in, y_in, z_in)
|
||||
//
|
||||
// The method is taken from:
|
||||
// http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
|
||||
//
|
||||
// Coq transcription and correctness proof:
|
||||
// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Curves/Weierstrass/Jacobian.v#L93>
|
||||
// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Curves/Weierstrass/Jacobian.v#L201>
|
||||
//
|
||||
// Outputs can equal corresponding inputs, i.e., x_out == x_in is allowed.
|
||||
// while x_out == y_in is not (maybe this works, but it's not tested).
|
||||
static void point_double(fe x_out, fe y_out, fe z_out,
|
||||
const fe x_in, const fe y_in, const fe z_in) {
|
||||
fe delta, gamma, beta, ftmp, ftmp2, tmptmp, alpha, fourbeta;
|
||||
// delta = z^2
|
||||
fe_sqr(delta, z_in);
|
||||
// gamma = y^2
|
||||
fe_sqr(gamma, y_in);
|
||||
// beta = x*gamma
|
||||
fe_mul(beta, x_in, gamma);
|
||||
|
||||
// alpha = 3*(x-delta)*(x+delta)
|
||||
fe_sub(ftmp, x_in, delta);
|
||||
fe_add(ftmp2, x_in, delta);
|
||||
|
||||
fe_add(tmptmp, ftmp2, ftmp2);
|
||||
fe_add(ftmp2, ftmp2, tmptmp);
|
||||
fe_mul(alpha, ftmp, ftmp2);
|
||||
|
||||
// x' = alpha^2 - 8*beta
|
||||
fe_sqr(x_out, alpha);
|
||||
fe_add(fourbeta, beta, beta);
|
||||
fe_add(fourbeta, fourbeta, fourbeta);
|
||||
fe_add(tmptmp, fourbeta, fourbeta);
|
||||
fe_sub(x_out, x_out, tmptmp);
|
||||
|
||||
// z' = (y + z)^2 - gamma - delta
|
||||
fe_add(delta, gamma, delta);
|
||||
fe_add(ftmp, y_in, z_in);
|
||||
fe_sqr(z_out, ftmp);
|
||||
fe_sub(z_out, z_out, delta);
|
||||
|
||||
// y' = alpha*(4*beta - x') - 8*gamma^2
|
||||
fe_sub(y_out, fourbeta, x_out);
|
||||
fe_add(gamma, gamma, gamma);
|
||||
fe_sqr(gamma, gamma);
|
||||
fe_mul(y_out, alpha, y_out);
|
||||
fe_add(gamma, gamma, gamma);
|
||||
fe_sub(y_out, y_out, gamma);
|
||||
}
|
||||
|
||||
// point_add calculates (x1, y1, z1) + (x2, y2, z2)
|
||||
//
|
||||
// The method is taken from:
|
||||
// http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl,
|
||||
// adapted for mixed addition (z2 = 1, or z2 = 0 for the point at infinity).
|
||||
//
|
||||
// Coq transcription and correctness proof:
|
||||
// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Curves/Weierstrass/Jacobian.v#L135>
|
||||
// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Curves/Weierstrass/Jacobian.v#L205>
|
||||
//
|
||||
// This function includes a branch for checking whether the two input points
|
||||
// are equal, (while not equal to the point at infinity). This case never
|
||||
// happens during single point multiplication, so there is no timing leak for
|
||||
// ECDH or ECDSA signing.
|
||||
static void point_add(fe x3, fe y3, fe z3, const fe x1,
|
||||
const fe y1, const fe z1, const int mixed,
|
||||
const fe x2, const fe y2, const fe z2) {
|
||||
fe x_out, y_out, z_out;
|
||||
WORD z1nz = fe_nz(z1);
|
||||
WORD z2nz = fe_nz(z2);
|
||||
|
||||
// z1z1 = z1z1 = z1**2
|
||||
fe z1z1; fe_sqr(z1z1, z1);
|
||||
|
||||
fe u1, s1, two_z1z2;
|
||||
if (!mixed) {
|
||||
// z2z2 = z2**2
|
||||
fe z2z2; fe_sqr(z2z2, z2);
|
||||
|
||||
// u1 = x1*z2z2
|
||||
fe_mul(u1, x1, z2z2);
|
||||
|
||||
// two_z1z2 = (z1 + z2)**2 - (z1z1 + z2z2) = 2z1z2
|
||||
fe_add(two_z1z2, z1, z2);
|
||||
fe_sqr(two_z1z2, two_z1z2);
|
||||
fe_sub(two_z1z2, two_z1z2, z1z1);
|
||||
fe_sub(two_z1z2, two_z1z2, z2z2);
|
||||
|
||||
// s1 = y1 * z2**3
|
||||
fe_mul(s1, z2, z2z2);
|
||||
fe_mul(s1, s1, y1);
|
||||
} else {
|
||||
// We'll assume z2 = 1 (special case z2 = 0 is handled later).
|
||||
|
||||
// u1 = x1*z2z2
|
||||
fe_copy(u1, x1);
|
||||
// two_z1z2 = 2z1z2
|
||||
fe_add(two_z1z2, z1, z1);
|
||||
// s1 = y1 * z2**3
|
||||
fe_copy(s1, y1);
|
||||
}
|
||||
|
||||
// u2 = x2*z1z1
|
||||
fe u2; fe_mul(u2, x2, z1z1);
|
||||
|
||||
// h = u2 - u1
|
||||
fe h; fe_sub(h, u2, u1);
|
||||
|
||||
WORD xneq = fe_nz(h);
|
||||
|
||||
// z_out = two_z1z2 * h
|
||||
fe_mul(z_out, h, two_z1z2);
|
||||
|
||||
// z1z1z1 = z1 * z1z1
|
||||
fe z1z1z1; fe_mul(z1z1z1, z1, z1z1);
|
||||
|
||||
// s2 = y2 * z1**3
|
||||
fe s2; fe_mul(s2, y2, z1z1z1);
|
||||
|
||||
// r = (s2 - s1)*2
|
||||
fe r;
|
||||
fe_sub(r, s2, s1);
|
||||
fe_add(r, r, r);
|
||||
|
||||
WORD yneq = fe_nz(r);
|
||||
|
||||
if (!xneq && !yneq && z1nz && z2nz) {
|
||||
point_double(x3, y3, z3, x1, y1, z1);
|
||||
return;
|
||||
}
|
||||
|
||||
// I = (2h)**2
|
||||
fe i;
|
||||
fe_add(i, h, h);
|
||||
fe_sqr(i, i);
|
||||
|
||||
// J = h * I
|
||||
fe j; fe_mul(j, h, i);
|
||||
|
||||
// V = U1 * I
|
||||
fe v; fe_mul(v, u1, i);
|
||||
|
||||
// x_out = r**2 - J - 2V
|
||||
fe_sqr(x_out, r);
|
||||
fe_sub(x_out, x_out, j);
|
||||
fe_sub(x_out, x_out, v);
|
||||
fe_sub(x_out, x_out, v);
|
||||
|
||||
// y_out = r(V-x_out) - 2 * s1 * J
|
||||
fe_sub(y_out, v, x_out);
|
||||
fe_mul(y_out, y_out, r);
|
||||
fe s1j;
|
||||
fe_mul(s1j, s1, j);
|
||||
fe_sub(y_out, y_out, s1j);
|
||||
fe_sub(y_out, y_out, s1j);
|
||||
|
||||
fe_cmovznz(x_out, z1nz, x2, x_out);
|
||||
fe_cmovznz(x3, z2nz, x1, x_out);
|
||||
fe_cmovznz(y_out, z1nz, y2, y_out);
|
||||
fe_cmovznz(y3, z2nz, y1, y_out);
|
||||
fe_cmovznz(z_out, z1nz, z2, z_out);
|
||||
fe_cmovznz(z3, z2nz, z1, z_out);
|
||||
}
|
||||
|
||||
/* Use a sliding window optimization method for scalar multiplication
|
||||
Hard-coded window size = 4
|
||||
Implementation inspired from Go's crypto library
|
||||
https://github.com/golang/go/blob/a5cd894318677359f6d07ee74f9004d28b4d164c/src/crypto/internal/nistec/p256.go#L317
|
||||
*/
|
||||
|
||||
/* Select the n-th element of the table
|
||||
without leaking information about [n] */
|
||||
static void table_select(fe out_x, fe out_y, fe out_z, size_t index, uint8_t n) {
|
||||
fe x, y, z = {0};
|
||||
fe_one(x); fe_one(y);
|
||||
for(uint8_t i = 1 ; i < 16 ; ++i) {
|
||||
WORD cond = i ^ n;
|
||||
fe_cmovznz(x, cond, generator_table[index][n - 1][0], x);
|
||||
fe_cmovznz(y, cond, generator_table[index][n - 1][1], y);
|
||||
fe_cmovznz(z, cond, generator_table[index][n - 1][2], z);
|
||||
}
|
||||
fe_copy(out_x, x);
|
||||
fe_copy(out_y, y);
|
||||
fe_copy(out_z, z);
|
||||
}
|
||||
|
||||
/* Returns [kG] by decomposing [k] in binary form, and adding
|
||||
[2^0G * k_0 + 2^1G * k_1 + ...] in constant time using
|
||||
pre-computed values of 2^iG */
|
||||
static void scalar_mult_base(fe x2, fe y2, fe z2,
|
||||
const uint8_t* scalar, size_t len) {
|
||||
// P = 0
|
||||
fe p_x, p_y, p_z = {0};
|
||||
fe_one(p_x);
|
||||
fe_one(p_y);
|
||||
size_t index = 0;
|
||||
for(size_t i = 0 ; i < len ; ++i) {
|
||||
fe s_x, s_y, s_z;
|
||||
uint8_t window = scalar[i] & 0xf;
|
||||
table_select(s_x, s_y, s_z, index, window);
|
||||
point_add(p_x, p_y, p_z, p_x, p_y, p_z, 0, s_x, s_y, s_z);
|
||||
index++;
|
||||
window = scalar[i] >> 4;
|
||||
table_select(s_x, s_y, s_z, index, window);
|
||||
point_add(p_x, p_y, p_z, p_x, p_y, p_z, 0, s_x, s_y, s_z);
|
||||
index++;
|
||||
}
|
||||
fe_copy(x2, p_x);
|
||||
fe_copy(y2, p_y);
|
||||
fe_copy(z2, p_z);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue