From 37ba0e2efc68407e7b20c71a7f4332846a76a7fb Mon Sep 17 00:00:00 2001 From: dkostic <25055813+dkostic@users.noreply.github.com> Date: Wed, 12 Jun 2024 20:05:39 +0000 Subject: [PATCH] [EC] Unify point addition for P-256/384/521 (#1602) Implement and use a single version of point addition for implementations of NIST curves P-384, P-521, and Fiat-crypto based implementation of P-256. The change does not affect performance. --- crypto/fipsmodule/ec/ec_nistp.c | 151 +++++++++++++++++++++++++++++++- crypto/fipsmodule/ec/ec_nistp.h | 14 +++ crypto/fipsmodule/ec/p256.c | 123 +------------------------- crypto/fipsmodule/ec/p384.c | 112 ++--------------------- crypto/fipsmodule/ec/p521.c | 111 ++--------------------- 5 files changed, 177 insertions(+), 334 deletions(-) diff --git a/crypto/fipsmodule/ec/ec_nistp.c b/crypto/fipsmodule/ec/ec_nistp.c index a4484dc06c..f3eaadde07 100644 --- a/crypto/fipsmodule/ec/ec_nistp.c +++ b/crypto/fipsmodule/ec/ec_nistp.c @@ -15,7 +15,7 @@ // // | op | P-521 | P-384 | P-256 | // |----------------------------| -// | 1. | | | | +// | 1. | x | x | x* | // | 2. | x | x | x* | // | 3. | | | | // | 4. | | | | @@ -36,6 +36,18 @@ #endif typedef ec_nistp_felem_limb ec_nistp_felem[NISTP_FELEM_MAX_NUM_OF_LIMBS]; +// Conditional copy in constant-time (out = t == 0 ? z : nz). +static void cmovznz(ec_nistp_felem_limb *out, + size_t num_limbs, + ec_nistp_felem_limb t, + const ec_nistp_felem_limb *z, + const ec_nistp_felem_limb *nz) { + ec_nistp_felem_limb mask = constant_time_is_zero_w(t); + for (size_t i = 0; i < num_limbs; i++) { + out[i] = constant_time_select_w(mask, z[i], nz[i]); + } +} + // Group operations // ---------------- // @@ -110,3 +122,140 @@ void ec_nistp_point_double(const ec_nistp_felem_meth *ctx, ctx->add(gamma, gamma, gamma); ctx->sub(y_out, y_out, gamma); } + +// ec_nistp_point_add calculates (x1, y1, z1) + (x2, y2, z2) +// +// The method is taken from: +// http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-2007-bl +// adapted for mixed addition (z2 = 1, or z2 = 0 for the point at infinity). +// +// Coq transcription and correctness proof: +// +// +// +// This function includes a branch for checking whether the two input points +// 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, + 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) { + 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); + + // z1z1 = z1**2 + ec_nistp_felem z1z1; + ctx->sqr(z1z1, z1); + + ec_nistp_felem u1, s1, two_z1z2; + if (!mixed) { + // z2z2 = z2**2 + ec_nistp_felem z2z2; + ctx->sqr(z2z2, z2); + + // u1 = x1*z2z2 + ctx->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); + + // s1 = y1 * z2**3 + ctx->mul(s1, z2, z2z2); + ctx->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); + // 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); + + // h = u2 - u1 + ec_nistp_felem h; + ctx->sub(h, u2, u1); + + ec_nistp_felem_limb xneq = ctx->nz(h); + + // z_out = two_z1z2 * h + ctx->mul(z_out, h, two_z1z2); + + // z1z1z1 = z1 * z1z1 + ec_nistp_felem z1z1z1; + ctx->mul(z1z1z1, z1, z1z1); + + // s2 = y2 * z1**3 + ec_nistp_felem s2; + ctx->mul(s2, y2, z1z1z1); + + // r = (s2 - s1)*2 + ec_nistp_felem r; + ctx->sub(r, s2, s1); + ctx->add(r, r, r); + + ec_nistp_felem_limb yneq = ctx->nz(r); + + // This case will never occur in the constant-time |ec_GFp_mont_mul|. + ec_nistp_felem_limb is_nontrivial_double = + constant_time_is_zero_w(xneq | yneq) & + ~constant_time_is_zero_w(z1nz) & + ~constant_time_is_zero_w(z2nz); + if (constant_time_declassify_w(is_nontrivial_double)) { + ec_nistp_point_double(ctx, x3, y3, z3, x1, y1, z1); + return; + } + + // I = (2h)**2 + ec_nistp_felem i; + ctx->add(i, h, h); + ctx->sqr(i, i); + + // J = h * I + ec_nistp_felem j; + ctx->mul(j, h, i); + + // V = U1 * I + ec_nistp_felem v; + ctx->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); + + // y_out = r(V-x_out) - 2 * s1 * J + ctx->sub(y_out, v, x_out); + ctx->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); + + cmovznz(x_out, ctx->felem_num_limbs, z1nz, x2, x_out); + cmovznz(y_out, ctx->felem_num_limbs, z1nz, y2, y_out); + cmovznz(z_out, ctx->felem_num_limbs, z1nz, z2, z_out); + cmovznz(x3, ctx->felem_num_limbs, z2nz, x1, x_out); + cmovznz(y3, ctx->felem_num_limbs, z2nz, y1, y_out); + cmovznz(z3, ctx->felem_num_limbs, z2nz, z1, z_out); +} + diff --git a/crypto/fipsmodule/ec/ec_nistp.h b/crypto/fipsmodule/ec/ec_nistp.h index 027380581f..152cb57090 100644 --- a/crypto/fipsmodule/ec/ec_nistp.h +++ b/crypto/fipsmodule/ec/ec_nistp.h @@ -44,10 +44,12 @@ typedef uint32_t ec_nistp_felem_limb; // 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; const ec_nistp_felem_meth *p256_felem_methods(void); @@ -61,5 +63,17 @@ void ec_nistp_point_double(const ec_nistp_felem_meth *ctx, 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, + 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); #endif // EC_NISTP_H diff --git a/crypto/fipsmodule/ec/p256.c b/crypto/fipsmodule/ec/p256.c index ba81fcc912..8ca5278562 100644 --- a/crypto/fipsmodule/ec/p256.c +++ b/crypto/fipsmodule/ec/p256.c @@ -168,10 +168,12 @@ static void fiat_p256_inv_square(fiat_p256_felem out, } 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, @@ -183,20 +185,6 @@ static void fiat_p256_point_double(fiat_p256_felem x_out, ec_nistp_point_double(p256_felem_methods(), x_out, y_out, z_out, x_in, y_in, z_in); } -// fiat_p256_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: -// -// -// -// 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 fiat_p256_point_add(fiat_p256_felem x3, fiat_p256_felem y3, fiat_p256_felem z3, const fiat_p256_felem x1, const fiat_p256_felem y1, @@ -204,112 +192,7 @@ 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) { - fiat_p256_felem x_out, y_out, z_out; - fiat_p256_limb_t z1nz = fiat_p256_nz(z1); - fiat_p256_limb_t z2nz = fiat_p256_nz(z2); - - // z1z1 = z1z1 = z1**2 - fiat_p256_felem z1z1; - fiat_p256_square(z1z1, z1); - - fiat_p256_felem u1, s1, two_z1z2; - if (!mixed) { - // z2z2 = z2**2 - fiat_p256_felem z2z2; - fiat_p256_square(z2z2, z2); - - // u1 = x1*z2z2 - fiat_p256_mul(u1, x1, z2z2); - - // two_z1z2 = (z1 + z2)**2 - (z1z1 + z2z2) = 2z1z2 - fiat_p256_add(two_z1z2, z1, z2); - fiat_p256_square(two_z1z2, two_z1z2); - fiat_p256_sub(two_z1z2, two_z1z2, z1z1); - fiat_p256_sub(two_z1z2, two_z1z2, z2z2); - - // s1 = y1 * z2**3 - fiat_p256_mul(s1, z2, z2z2); - fiat_p256_mul(s1, s1, y1); - } else { - // We'll assume z2 = 1 (special case z2 = 0 is handled later). - - // u1 = x1*z2z2 - fiat_p256_copy(u1, x1); - // two_z1z2 = 2z1z2 - fiat_p256_add(two_z1z2, z1, z1); - // s1 = y1 * z2**3 - fiat_p256_copy(s1, y1); - } - - // u2 = x2*z1z1 - fiat_p256_felem u2; - fiat_p256_mul(u2, x2, z1z1); - - // h = u2 - u1 - fiat_p256_felem h; - fiat_p256_sub(h, u2, u1); - - fiat_p256_limb_t xneq = fiat_p256_nz(h); - - // z_out = two_z1z2 * h - fiat_p256_mul(z_out, h, two_z1z2); - - // z1z1z1 = z1 * z1z1 - fiat_p256_felem z1z1z1; - fiat_p256_mul(z1z1z1, z1, z1z1); - - // s2 = y2 * z1**3 - fiat_p256_felem s2; - fiat_p256_mul(s2, y2, z1z1z1); - - // r = (s2 - s1)*2 - fiat_p256_felem r; - fiat_p256_sub(r, s2, s1); - fiat_p256_add(r, r, r); - - fiat_p256_limb_t yneq = fiat_p256_nz(r); - - fiat_p256_limb_t is_nontrivial_double = constant_time_is_zero_w(xneq | yneq) & - ~constant_time_is_zero_w(z1nz) & - ~constant_time_is_zero_w(z2nz); - if (constant_time_declassify_w(is_nontrivial_double)) { - fiat_p256_point_double(x3, y3, z3, x1, y1, z1); - return; - } - - // I = (2h)**2 - fiat_p256_felem i; - fiat_p256_add(i, h, h); - fiat_p256_square(i, i); - - // J = h * I - fiat_p256_felem j; - fiat_p256_mul(j, h, i); - - // V = U1 * I - fiat_p256_felem v; - fiat_p256_mul(v, u1, i); - - // x_out = r**2 - J - 2V - fiat_p256_square(x_out, r); - fiat_p256_sub(x_out, x_out, j); - fiat_p256_sub(x_out, x_out, v); - fiat_p256_sub(x_out, x_out, v); - - // y_out = r(V-x_out) - 2 * s1 * J - fiat_p256_sub(y_out, v, x_out); - fiat_p256_mul(y_out, y_out, r); - fiat_p256_felem s1j; - fiat_p256_mul(s1j, s1, j); - fiat_p256_sub(y_out, y_out, s1j); - fiat_p256_sub(y_out, y_out, s1j); - - fiat_p256_cmovznz(x_out, z1nz, x2, x_out); - fiat_p256_cmovznz(x3, z2nz, x1, x_out); - fiat_p256_cmovznz(y_out, z1nz, y2, y_out); - fiat_p256_cmovznz(y3, z2nz, y1, y_out); - fiat_p256_cmovznz(z_out, z1nz, z2, z_out); - fiat_p256_cmovznz(z3, z2nz, z1, z_out); + ec_nistp_point_add(p256_felem_methods(), x3, y3, z3, x1, y1, z1, mixed, x2, y2, z2); } #include "./p256_table.h" diff --git a/crypto/fipsmodule/ec/p384.c b/crypto/fipsmodule/ec/p384.c index 777fd20b26..930b1ac26f 100644 --- a/crypto/fipsmodule/ec/p384.c +++ b/crypto/fipsmodule/ec/p384.c @@ -243,17 +243,21 @@ static void p384_inv_square(p384_felem out, #if defined(EC_NISTP_USE_S2N_BIGNUM) DEFINE_METHOD_FUNCTION(ec_nistp_felem_meth, p384_felem_methods) { + out->felem_num_limbs = P384_NLIMBS; out->add = bignum_add_p384; out->sub = bignum_sub_p384; out->mul = bignum_montmul_p384_selector; out->sqr = bignum_montsqr_p384_selector; + out->nz = p384_felem_nz; } #else DEFINE_METHOD_FUNCTION(ec_nistp_felem_meth, p384_felem_methods) { + out->felem_num_limbs = P384_NLIMBS; out->add = fiat_p384_add; out->sub = fiat_p384_sub; out->mul = fiat_p384_mul; out->sqr = fiat_p384_square; + out->nz = p384_felem_nz; } #endif @@ -283,113 +287,7 @@ static void p384_point_add(p384_felem x3, p384_felem y3, p384_felem z3, const p384_felem x2, const p384_felem y2, const p384_felem z2) { - p384_felem x_out, y_out, z_out; - p384_limb_t z1nz = p384_felem_nz(z1); - p384_limb_t z2nz = p384_felem_nz(z2); - - // z1z1 = z1**2 - p384_felem z1z1; - p384_felem_sqr(z1z1, z1); - - p384_felem u1, s1, two_z1z2; - if (!mixed) { - // z2z2 = z2**2 - p384_felem z2z2; - p384_felem_sqr(z2z2, z2); - - // u1 = x1*z2z2 - p384_felem_mul(u1, x1, z2z2); - - // two_z1z2 = (z1 + z2)**2 - (z1z1 + z2z2) = 2z1z2 - p384_felem_add(two_z1z2, z1, z2); - p384_felem_sqr(two_z1z2, two_z1z2); - p384_felem_sub(two_z1z2, two_z1z2, z1z1); - p384_felem_sub(two_z1z2, two_z1z2, z2z2); - - // s1 = y1 * z2**3 - p384_felem_mul(s1, z2, z2z2); - p384_felem_mul(s1, s1, y1); - } else { - // We'll assume z2 = 1 (special case z2 = 0 is handled later). - - // u1 = x1*z2z2 - p384_felem_copy(u1, x1); - // two_z1z2 = 2z1z2 - p384_felem_add(two_z1z2, z1, z1); - // s1 = y1 * z2**3 - p384_felem_copy(s1, y1); - } - - // u2 = x2*z1z1 - p384_felem u2; - p384_felem_mul(u2, x2, z1z1); - - // h = u2 - u1 - p384_felem h; - p384_felem_sub(h, u2, u1); - - p384_limb_t xneq = p384_felem_nz(h); - - // z_out = two_z1z2 * h - p384_felem_mul(z_out, h, two_z1z2); - - // z1z1z1 = z1 * z1z1 - p384_felem z1z1z1; - p384_felem_mul(z1z1z1, z1, z1z1); - - // s2 = y2 * z1**3 - p384_felem s2; - p384_felem_mul(s2, y2, z1z1z1); - - // r = (s2 - s1)*2 - p384_felem r; - p384_felem_sub(r, s2, s1); - p384_felem_add(r, r, r); - - p384_limb_t yneq = p384_felem_nz(r); - - // This case will never occur in the constant-time |ec_GFp_mont_mul|. - p384_limb_t is_nontrivial_double = constant_time_is_zero_w(xneq | yneq) & - ~constant_time_is_zero_w(z1nz) & - ~constant_time_is_zero_w(z2nz); - if (constant_time_declassify_w(is_nontrivial_double)) { - p384_point_double(x3, y3, z3, x1, y1, z1); - return; - } - - // I = (2h)**2 - p384_felem i; - p384_felem_add(i, h, h); - p384_felem_sqr(i, i); - - // J = h * I - p384_felem j; - p384_felem_mul(j, h, i); - - // V = U1 * I - p384_felem v; - p384_felem_mul(v, u1, i); - - // x_out = r**2 - J - 2V - p384_felem_sqr(x_out, r); - p384_felem_sub(x_out, x_out, j); - p384_felem_sub(x_out, x_out, v); - p384_felem_sub(x_out, x_out, v); - - // y_out = r(V-x_out) - 2 * s1 * J - p384_felem_sub(y_out, v, x_out); - p384_felem_mul(y_out, y_out, r); - p384_felem s1j; - p384_felem_mul(s1j, s1, j); - p384_felem_sub(y_out, y_out, s1j); - p384_felem_sub(y_out, y_out, s1j); - - p384_felem_cmovznz(x_out, z1nz, x2, x_out); - p384_felem_cmovznz(x3, z2nz, x1, x_out); - p384_felem_cmovznz(y_out, z1nz, y2, y_out); - p384_felem_cmovznz(y3, z2nz, y1, y_out); - p384_felem_cmovznz(z_out, z1nz, z2, z_out); - p384_felem_cmovznz(z3, z2nz, z1, z_out); + ec_nistp_point_add(p384_felem_methods(), x3, y3, z3, x1, y1, z1, mixed, x2, y2, z2); } // OPENSSL EC_METHOD FUNCTIONS diff --git a/crypto/fipsmodule/ec/p521.c b/crypto/fipsmodule/ec/p521.c index d5ad43c7ec..d3a015cd13 100644 --- a/crypto/fipsmodule/ec/p521.c +++ b/crypto/fipsmodule/ec/p521.c @@ -261,17 +261,21 @@ static void p521_felem_inv(p521_felem output, const p521_felem t1) { #if defined(EC_NISTP_USE_S2N_BIGNUM) DEFINE_METHOD_FUNCTION(ec_nistp_felem_meth, p521_felem_methods) { + out->felem_num_limbs = P521_NLIMBS; out->add = bignum_add_p521; out->sub = bignum_sub_p521; out->mul = bignum_mul_p521_selector; out->sqr = bignum_sqr_p521_selector; + out->nz = p521_felem_nz; } #else DEFINE_METHOD_FUNCTION(ec_nistp_felem_meth, p521_felem_methods) { + out->felem_num_limbs = P521_NLIMBS; out->add = fiat_secp521r1_carry_add; out->sub = fiat_secp521r1_carry_sub; out->mul = fiat_secp521r1_carry_mul; out->sqr = fiat_secp521r1_carry_square; + out->nz = p521_felem_nz; } #endif @@ -301,112 +305,7 @@ static void p521_point_add(p521_felem x3, p521_felem y3, p521_felem z3, const p521_felem x2, const p521_felem y2, const p521_felem z2) { - p521_felem x_out, y_out, z_out; - p521_limb_t z1nz = p521_felem_nz(z1); - p521_limb_t z2nz = p521_felem_nz(z2); - - // z1z1 = z1**2 - p521_felem z1z1; - p521_felem_sqr(z1z1, z1); - - p521_felem u1, s1, two_z1z2; - if (!mixed) { - // z2z2 = z2**2 - p521_felem z2z2; - p521_felem_sqr(z2z2, z2); - - // u1 = x1*z2z2 - p521_felem_mul(u1, x1, z2z2); - - // two_z1z2 = (z1 + z2)**2 - (z1z1 + z2z2) = 2z1z2 - p521_felem_add(two_z1z2, z1, z2); - p521_felem_sqr(two_z1z2, two_z1z2); - p521_felem_sub(two_z1z2, two_z1z2, z1z1); - p521_felem_sub(two_z1z2, two_z1z2, z2z2); - - // s1 = y1 * z2**3 - p521_felem_mul(s1, z2, z2z2); - p521_felem_mul(s1, s1, y1); - } else { - // We'll assume z2 = 1 (special case z2 = 0 is handled later). - - // u1 = x1*z2z2 - p521_felem_copy(u1, x1); - // two_z1z2 = 2z1z2 - p521_felem_add(two_z1z2, z1, z1); - // s1 = y1 * z2**3 - p521_felem_copy(s1, y1); - } - - // u2 = x2*z1z1 - p521_felem u2; - p521_felem_mul(u2, x2, z1z1); - - // h = u2 - u1 - p521_felem h; - p521_felem_sub(h, u2, u1); - - p521_limb_t xneq = p521_felem_nz(h); - - // z_out = two_z1z2 * h - p521_felem_mul(z_out, h, two_z1z2); - - // z1z1z1 = z1 * z1z1 - p521_felem z1z1z1; - p521_felem_mul(z1z1z1, z1, z1z1); - - // s2 = y2 * z1**3 - p521_felem s2; - p521_felem_mul(s2, y2, z1z1z1); - - // r = (s2 - s1)*2 - p521_felem r; - p521_felem_sub(r, s2, s1); - p521_felem_add(r, r, r); - - p521_limb_t yneq = p521_felem_nz(r); - - p521_limb_t is_nontrivial_double = constant_time_is_zero_w(xneq | yneq) & - ~constant_time_is_zero_w(z1nz) & - ~constant_time_is_zero_w(z2nz); - if (constant_time_declassify_w(is_nontrivial_double)) { - p521_point_double(x3, y3, z3, x1, y1, z1); - return; - } - - // I = (2h)**2 - p521_felem i; - p521_felem_add(i, h, h); - p521_felem_sqr(i, i); - - // J = h * I - p521_felem j; - p521_felem_mul(j, h, i); - - // V = U1 * I - p521_felem v; - p521_felem_mul(v, u1, i); - - // x_out = r**2 - J - 2V - p521_felem_sqr(x_out, r); - p521_felem_sub(x_out, x_out, j); - p521_felem_sub(x_out, x_out, v); - p521_felem_sub(x_out, x_out, v); - - // y_out = r(V-x_out) - 2 * s1 * J - p521_felem_sub(y_out, v, x_out); - p521_felem_mul(y_out, y_out, r); - p521_felem s1j; - p521_felem_mul(s1j, s1, j); - p521_felem_sub(y_out, y_out, s1j); - p521_felem_sub(y_out, y_out, s1j); - - p521_felem_cmovznz(x_out, z1nz, x2, x_out); - p521_felem_cmovznz(x3, z2nz, x1, x_out); - p521_felem_cmovznz(y_out, z1nz, y2, y_out); - p521_felem_cmovznz(y3, z2nz, y1, y_out); - p521_felem_cmovznz(z_out, z1nz, z2, z_out); - p521_felem_cmovznz(z3, z2nz, z1, z_out); + ec_nistp_point_add(p521_felem_methods(), x3, y3, z3, x1, y1, z1, mixed, x2, y2, z2); } // OPENSSL EC_METHOD FUNCTIONS