Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add point add/dbl to ec_nistp_felem_meth and rename it to ec_nistp_meth #1654

Merged
merged 4 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 59 additions & 59 deletions crypto/fipsmodule/ec/ec_nistp.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ static void cmovznz(ec_nistp_felem_limb *out,
//
// 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).
void ec_nistp_point_double(const ec_nistp_felem_meth *ctx,
void ec_nistp_point_double(const ec_nistp_meth *ctx,
ec_nistp_felem_limb *x_out,
ec_nistp_felem_limb *y_out,
ec_nistp_felem_limb *z_out,
Expand All @@ -79,26 +79,26 @@ void ec_nistp_point_double(const ec_nistp_felem_meth *ctx,
const ec_nistp_felem_limb *z_in) {
ec_nistp_felem delta, gamma, beta, ftmp, ftmp2, tmptmp, alpha, fourbeta;
// delta = z^2
ctx->sqr(delta, z_in);
ctx->felem_sqr(delta, z_in);
// gamma = y^2
ctx->sqr(gamma, y_in);
ctx->felem_sqr(gamma, y_in);
// beta = x*gamma
ctx->mul(beta, x_in, gamma);
ctx->felem_mul(beta, x_in, gamma);

// alpha = 3*(x-delta)*(x+delta)
ctx->sub(ftmp, x_in, delta);
ctx->add(ftmp2, x_in, delta);
ctx->felem_sub(ftmp, x_in, delta);
ctx->felem_add(ftmp2, x_in, delta);

ctx->add(tmptmp, ftmp2, ftmp2);
ctx->add(ftmp2, ftmp2, tmptmp);
ctx->mul(alpha, ftmp, ftmp2);
ctx->felem_add(tmptmp, ftmp2, ftmp2);
ctx->felem_add(ftmp2, ftmp2, tmptmp);
ctx->felem_mul(alpha, ftmp, ftmp2);

// x' = alpha^2 - 8*beta
ctx->sqr(x_out, alpha);
ctx->add(fourbeta, beta, beta);
ctx->add(fourbeta, fourbeta, fourbeta);
ctx->add(tmptmp, fourbeta, fourbeta);
ctx->sub(x_out, x_out, tmptmp);
ctx->felem_sqr(x_out, alpha);
ctx->felem_add(fourbeta, beta, beta);
ctx->felem_add(fourbeta, fourbeta, fourbeta);
ctx->felem_add(tmptmp, fourbeta, fourbeta);
ctx->felem_sub(x_out, x_out, tmptmp);

// z' = (y + z)^2 - gamma - delta
// The following calculation differs from the Coq proof cited above.
Expand All @@ -109,18 +109,18 @@ void ec_nistp_point_double(const ec_nistp_felem_meth *ctx,
// sub(z_out, z_out, delta);
// Our operations sequence is a bit more efficient because it saves us
// a certain number of conditional moves.
ctx->add(ftmp, y_in, z_in);
ctx->sqr(z_out, ftmp);
ctx->sub(z_out, z_out, gamma);
ctx->sub(z_out, z_out, delta);
ctx->felem_add(ftmp, y_in, z_in);
ctx->felem_sqr(z_out, ftmp);
ctx->felem_sub(z_out, z_out, gamma);
ctx->felem_sub(z_out, z_out, delta);

// y' = alpha*(4*beta - x') - 8*gamma^2
ctx->sub(y_out, fourbeta, x_out);
ctx->add(gamma, gamma, gamma);
ctx->sqr(gamma, gamma);
ctx->mul(y_out, alpha, y_out);
ctx->add(gamma, gamma, gamma);
ctx->sub(y_out, y_out, gamma);
ctx->felem_sub(y_out, fourbeta, x_out);
ctx->felem_add(gamma, gamma, gamma);
ctx->felem_sqr(gamma, gamma);
ctx->felem_mul(y_out, alpha, y_out);
ctx->felem_add(gamma, gamma, gamma);
ctx->felem_sub(y_out, y_out, gamma);
}

// ec_nistp_point_add calculates (x1, y1, z1) + (x2, y2, z2)
Expand All @@ -137,7 +137,7 @@ void ec_nistp_point_double(const ec_nistp_felem_meth *ctx,
// are equal, (while not equal to the point at infinity). This case should
// never happen during single point multiplication, so there is no timing leak
// for ECDH and ECDSA.
void ec_nistp_point_add(const ec_nistp_felem_meth *ctx,
void ec_nistp_point_add(const ec_nistp_meth *ctx,
ec_nistp_felem_limb *x3,
ec_nistp_felem_limb *y3,
ec_nistp_felem_limb *z3,
Expand All @@ -150,69 +150,69 @@ void ec_nistp_point_add(const ec_nistp_felem_meth *ctx,
const ec_nistp_felem_limb *z2) {
ec_nistp_felem x_out, y_out, z_out;

ec_nistp_felem_limb z1nz = ctx->nz(z1);
ec_nistp_felem_limb z2nz = ctx->nz(z2);
ec_nistp_felem_limb z1nz = ctx->felem_nz(z1);
ec_nistp_felem_limb z2nz = ctx->felem_nz(z2);

// z1z1 = z1**2
ec_nistp_felem z1z1;
ctx->sqr(z1z1, z1);
ctx->felem_sqr(z1z1, z1);

ec_nistp_felem u1, s1, two_z1z2;
if (!mixed) {
// z2z2 = z2**2
ec_nistp_felem z2z2;
ctx->sqr(z2z2, z2);
ctx->felem_sqr(z2z2, z2);

// u1 = x1*z2z2
ctx->mul(u1, x1, z2z2);
ctx->felem_mul(u1, x1, z2z2);

// two_z1z2 = (z1 + z2)**2 - (z1z1 + z2z2) = 2z1z2
ctx->add(two_z1z2, z1, z2);
ctx->sqr(two_z1z2, two_z1z2);
ctx->sub(two_z1z2, two_z1z2, z1z1);
ctx->sub(two_z1z2, two_z1z2, z2z2);
ctx->felem_add(two_z1z2, z1, z2);
ctx->felem_sqr(two_z1z2, two_z1z2);
ctx->felem_sub(two_z1z2, two_z1z2, z1z1);
ctx->felem_sub(two_z1z2, two_z1z2, z2z2);

// s1 = y1 * z2**3
ctx->mul(s1, z2, z2z2);
ctx->mul(s1, s1, y1);
ctx->felem_mul(s1, z2, z2z2);
ctx->felem_mul(s1, s1, y1);
} else {
// We'll assume z2 = 1 (special case z2 = 0 is handled later).

// u1 = x1*z2z2
OPENSSL_memcpy(u1, x1, ctx->felem_num_limbs * sizeof(ec_nistp_felem_limb));
// two_z1z2 = 2z1z2
ctx->add(two_z1z2, z1, z1);
ctx->felem_add(two_z1z2, z1, z1);
// s1 = y1 * z2**3
OPENSSL_memcpy(s1, y1, ctx->felem_num_limbs * sizeof(ec_nistp_felem_limb));
}

// u2 = x2*z1z1
ec_nistp_felem u2;
ctx->mul(u2, x2, z1z1);
ctx->felem_mul(u2, x2, z1z1);

// h = u2 - u1
ec_nistp_felem h;
ctx->sub(h, u2, u1);
ctx->felem_sub(h, u2, u1);

ec_nistp_felem_limb xneq = ctx->nz(h);
ec_nistp_felem_limb xneq = ctx->felem_nz(h);

// z_out = two_z1z2 * h
ctx->mul(z_out, h, two_z1z2);
ctx->felem_mul(z_out, h, two_z1z2);

// z1z1z1 = z1 * z1z1
ec_nistp_felem z1z1z1;
ctx->mul(z1z1z1, z1, z1z1);
ctx->felem_mul(z1z1z1, z1, z1z1);

// s2 = y2 * z1**3
ec_nistp_felem s2;
ctx->mul(s2, y2, z1z1z1);
ctx->felem_mul(s2, y2, z1z1z1);

// r = (s2 - s1)*2
ec_nistp_felem r;
ctx->sub(r, s2, s1);
ctx->add(r, r, r);
ctx->felem_sub(r, s2, s1);
ctx->felem_add(r, r, r);

ec_nistp_felem_limb yneq = ctx->nz(r);
ec_nistp_felem_limb yneq = ctx->felem_nz(r);

// This case will never occur in the constant-time |ec_GFp_mont_mul|.
ec_nistp_felem_limb is_nontrivial_double =
Expand All @@ -226,30 +226,30 @@ void ec_nistp_point_add(const ec_nistp_felem_meth *ctx,

// I = (2h)**2
ec_nistp_felem i;
ctx->add(i, h, h);
ctx->sqr(i, i);
ctx->felem_add(i, h, h);
ctx->felem_sqr(i, i);

// J = h * I
ec_nistp_felem j;
ctx->mul(j, h, i);
ctx->felem_mul(j, h, i);

// V = U1 * I
ec_nistp_felem v;
ctx->mul(v, u1, i);
ctx->felem_mul(v, u1, i);

// x_out = r**2 - J - 2V
ctx->sqr(x_out, r);
ctx->sub(x_out, x_out, j);
ctx->sub(x_out, x_out, v);
ctx->sub(x_out, x_out, v);
ctx->felem_sqr(x_out, r);
ctx->felem_sub(x_out, x_out, j);
ctx->felem_sub(x_out, x_out, v);
ctx->felem_sub(x_out, x_out, v);

// y_out = r(V-x_out) - 2 * s1 * J
ctx->sub(y_out, v, x_out);
ctx->mul(y_out, y_out, r);
ctx->felem_sub(y_out, v, x_out);
ctx->felem_mul(y_out, y_out, r);
ec_nistp_felem s1j;
ctx->mul(s1j, s1, j);
ctx->sub(y_out, y_out, s1j);
ctx->sub(y_out, y_out, s1j);
ctx->felem_mul(s1j, s1, j);
ctx->felem_sub(y_out, y_out, s1j);
ctx->felem_sub(y_out, y_out, s1j);

cmovznz(x_out, ctx->felem_num_limbs, z1nz, x2, x_out);
cmovznz(y_out, ctx->felem_num_limbs, z1nz, y2, y_out);
Expand Down
54 changes: 37 additions & 17 deletions crypto/fipsmodule/ec/ec_nistp.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#include <stdint.h>

// We have two implementations of the field arithmetic for NIST curves:
// We have two implementations of field arithmetic for NIST curves:
// - Fiat-crypto
// - s2n-bignum
// Both Fiat-crypto and s2n-bignum implementations are formally verified.
Expand All @@ -34,37 +34,57 @@ typedef uint64_t ec_nistp_felem_limb;
typedef uint32_t ec_nistp_felem_limb;
#endif

// ec_nistp_felem_meth is a struct that holds pointers to implementations of field
// arithmetic functions for specific curves. It is meant to be used
// ec_nistp_meth is a struct that holds pointers to implementations of field
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the documentation would need to be adjusted to not only mention field arithmetic functions.

// and point arithmetic functions for specific curves. It is meant to be used
// in higher level functions like this:
// void point_double(nistp_felem_methods *ctx, ...) {
// ctx->add(...);
// ctx->mul(...);
// void point_double(ec_nistp_meth *ctx, ...) {
// ctx->felem_add(...);
// ctx->felem_mul(...);
//
// ctx->point_dbl(...);
// }
// This makes the functions reusable between different curves by simply
// providing an appropriate methods object.
typedef struct {
size_t felem_num_limbs;
void (*add)(ec_nistp_felem_limb *c, const ec_nistp_felem_limb *a, const ec_nistp_felem_limb *b);
void (*sub)(ec_nistp_felem_limb *c, const ec_nistp_felem_limb *a, const ec_nistp_felem_limb *b);
void (*mul)(ec_nistp_felem_limb *c, const ec_nistp_felem_limb *a, const ec_nistp_felem_limb *b);
void (*sqr)(ec_nistp_felem_limb *c, const ec_nistp_felem_limb *a);
ec_nistp_felem_limb (*nz)(const ec_nistp_felem_limb *a);
} ec_nistp_felem_meth;
void (*felem_add)(ec_nistp_felem_limb *c, const ec_nistp_felem_limb *a, const ec_nistp_felem_limb *b);
void (*felem_sub)(ec_nistp_felem_limb *c, const ec_nistp_felem_limb *a, const ec_nistp_felem_limb *b);
void (*felem_mul)(ec_nistp_felem_limb *c, const ec_nistp_felem_limb *a, const ec_nistp_felem_limb *b);
void (*felem_sqr)(ec_nistp_felem_limb *c, const ec_nistp_felem_limb *a);
ec_nistp_felem_limb (*felem_nz)(const ec_nistp_felem_limb *a);

const ec_nistp_felem_meth *p256_felem_methods(void);
const ec_nistp_felem_meth *p384_felem_methods(void);
const ec_nistp_felem_meth *p521_felem_methods(void);
void (*point_dbl)(ec_nistp_felem_limb *x_out,
ec_nistp_felem_limb *y_out,
ec_nistp_felem_limb *z_out,
const ec_nistp_felem_limb *x_in,
const ec_nistp_felem_limb *y_in,
const ec_nistp_felem_limb *z_in);
void (*point_add)(ec_nistp_felem_limb *x3,
ec_nistp_felem_limb *y3,
ec_nistp_felem_limb *z3,
const ec_nistp_felem_limb *x1,
const ec_nistp_felem_limb *y1,
const ec_nistp_felem_limb *z1,
const int mixed,
const ec_nistp_felem_limb *x2,
const ec_nistp_felem_limb *y2,
const ec_nistp_felem_limb *z2);

void ec_nistp_point_double(const ec_nistp_felem_meth *ctx,
} ec_nistp_meth;

const ec_nistp_meth *p256_methods(void);
const ec_nistp_meth *p384_methods(void);
const ec_nistp_meth *p521_methods(void);

void ec_nistp_point_double(const ec_nistp_meth *ctx,
ec_nistp_felem_limb *x_out,
ec_nistp_felem_limb *y_out,
ec_nistp_felem_limb *z_out,
const ec_nistp_felem_limb *x_in,
const ec_nistp_felem_limb *y_in,
const ec_nistp_felem_limb *z_in);

void ec_nistp_point_add(const ec_nistp_felem_meth *ctx,
void ec_nistp_point_add(const ec_nistp_meth *ctx,
ec_nistp_felem_limb *x3,
ec_nistp_felem_limb *y3,
ec_nistp_felem_limb *z3,
Expand Down
24 changes: 13 additions & 11 deletions crypto/fipsmodule/ec/p256.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,22 +167,13 @@ static void fiat_p256_inv_square(fiat_p256_felem out,
fiat_p256_square(out, ret); // 2^256 - 2^224 + 2^192 + 2^96 - 2^2
}

DEFINE_METHOD_FUNCTION(ec_nistp_felem_meth, p256_felem_methods) {
out->felem_num_limbs = FIAT_P256_NLIMBS;
out->add = fiat_p256_add;
out->sub = fiat_p256_sub;
out->mul = fiat_p256_mul;
out->sqr = fiat_p256_square;
out->nz = fiat_p256_nz;
}

static void fiat_p256_point_double(fiat_p256_felem x_out,
fiat_p256_felem y_out,
fiat_p256_felem z_out,
const fiat_p256_felem x_in,
const fiat_p256_felem y_in,
const fiat_p256_felem z_in) {
ec_nistp_point_double(p256_felem_methods(), x_out, y_out, z_out, x_in, y_in, z_in);
ec_nistp_point_double(p256_methods(), x_out, y_out, z_out, x_in, y_in, z_in);
}

static void fiat_p256_point_add(fiat_p256_felem x3, fiat_p256_felem y3,
Expand All @@ -192,7 +183,18 @@ static void fiat_p256_point_add(fiat_p256_felem x3, fiat_p256_felem y3,
const fiat_p256_felem x2,
const fiat_p256_felem y2,
const fiat_p256_felem z2) {
ec_nistp_point_add(p256_felem_methods(), x3, y3, z3, x1, y1, z1, mixed, x2, y2, z2);
ec_nistp_point_add(p256_methods(), x3, y3, z3, x1, y1, z1, mixed, x2, y2, z2);
}

DEFINE_METHOD_FUNCTION(ec_nistp_meth, p256_methods) {
out->felem_num_limbs = FIAT_P256_NLIMBS;
out->felem_add = fiat_p256_add;
out->felem_sub = fiat_p256_sub;
out->felem_mul = fiat_p256_mul;
out->felem_sqr = fiat_p256_square;
out->felem_nz = fiat_p256_nz;
out->point_dbl = fiat_p256_point_double;
out->point_add = fiat_p256_point_add;
}

#include "./p256_table.h"
Expand Down
Loading
Loading