diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index 517e3fdbfe..3915104447 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c @@ -28,7 +28,6 @@ // to control the order. $b section will place bcm in between the start/end markers // which are in $a and $z. #if defined(BORINGSSL_FIPS) && defined(OPENSSL_WINDOWS) - #pragma code_seg(".fipstx$b") #pragma data_seg(".fipsda$b") #pragma const_seg(".fipsco$b") @@ -93,6 +92,7 @@ #include "ec/ec.c" #include "ec/ec_key.c" #include "ec/ec_montgomery.c" +#include "ec/ec_nistp.c" #include "ec/felem.c" #include "ec/oct.c" #include "ec/p224-64.c" diff --git a/crypto/fipsmodule/ec/ec_nistp.c b/crypto/fipsmodule/ec/ec_nistp.c new file mode 100644 index 0000000000..a4484dc06c --- /dev/null +++ b/crypto/fipsmodule/ec/ec_nistp.c @@ -0,0 +1,112 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +// In this file we will implement elliptic curve point operations for +// NIST curves P-256, P-384, and P-521. The idea is to implement the operations +// in a generic way such that the code can be reused instead of having +// a separate implementation for each of the curves. We implement: +// 1. point addition, +// 2. point doubling, +// 3. scalar multiplication of a base point, +// 4. scalar multiplication of an arbitrary point, +// 5. scalar multiplication of a base and an arbitrary point. +// +// Matrix of what has been done so far: +// +// | op | P-521 | P-384 | P-256 | +// |----------------------------| +// | 1. | | | | +// | 2. | x | x | x* | +// | 3. | | | | +// | 4. | | | | +// | 5. | | | | +// * For P-256, only the Fiat-crypto implementation in p256.c is replaced. + +#include "ec_nistp.h" + +// Some of the functions below need temporary field element variables. +// To avoid dynamic allocation we define nistp_felem type to have the maximum +// size possible (which is currently P-521 curve). The values are hard-coded +// for the moment, this will be fixed when we migrate the whole P-521 +// implementation to ec_nistp.c. +#if defined(EC_NISTP_USE_64BIT_LIMB) +#define NISTP_FELEM_MAX_NUM_OF_LIMBS (9) +#else +#define NISTP_FELEM_MAX_NUM_OF_LIMBS (19) +#endif +typedef ec_nistp_felem_limb ec_nistp_felem[NISTP_FELEM_MAX_NUM_OF_LIMBS]; + +// 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. +// +// ec_nistp_point_double calculates 2*(x_in, y_in, z_in) +// +// The method is based on: +// http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b +// for which there is a Coq transcription and correctness proof: +// +// +// +// However, we slighty changed the computation for efficiency (see the full +// explanation within the function body), which makes the Coq proof above +// not applicable to our implementation. +// TODO(awslc): Write a Coq correctness proof for our version of the algorithm. +// +// 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, + 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) { + ec_nistp_felem delta, gamma, beta, ftmp, ftmp2, tmptmp, alpha, fourbeta; + // delta = z^2 + ctx->sqr(delta, z_in); + // gamma = y^2 + ctx->sqr(gamma, y_in); + // beta = x*gamma + ctx->mul(beta, x_in, gamma); + + // alpha = 3*(x-delta)*(x+delta) + ctx->sub(ftmp, x_in, delta); + ctx->add(ftmp2, x_in, delta); + + ctx->add(tmptmp, ftmp2, ftmp2); + ctx->add(ftmp2, ftmp2, tmptmp); + ctx->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); + + // z' = (y + z)^2 - gamma - delta + // The following calculation differs from the Coq proof cited above. + // The proof is for: + // add(delta, gamma, delta); + // add(ftmp, y_in, z_in); + // square(z_out, ftmp); + // 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); + + // 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); +} diff --git a/crypto/fipsmodule/ec/ec_nistp.h b/crypto/fipsmodule/ec/ec_nistp.h new file mode 100644 index 0000000000..027380581f --- /dev/null +++ b/crypto/fipsmodule/ec/ec_nistp.h @@ -0,0 +1,65 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC +#ifndef EC_NISTP_H +#define EC_NISTP_H + +#include + +#include + +// We have two implementations of the field arithmetic for NIST curves: +// - Fiat-crypto +// - s2n-bignum +// Both Fiat-crypto and s2n-bignum implementations are formally verified. +// Fiat-crypto implementation is fully portable C code, while s2n-bignum +// implements the operations in assembly for x86_64 and aarch64 platforms. +// If (1) x86_64 or aarch64, (2) linux or apple, and (3) OPENSSL_NO_ASM is not +// set, s2n-bignum path is capable. +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_LINUX) || defined(OPENSSL_APPLE)) && \ + ((defined(OPENSSL_X86_64) && !defined(MY_ASSEMBLER_IS_TOO_OLD_FOR_AVX)) || \ + defined(OPENSSL_AARCH64)) +# define EC_NISTP_USE_S2N_BIGNUM +# define EC_NISTP_USE_64BIT_LIMB +#else +// Fiat-crypto has both 64-bit and 32-bit implementation. +# if defined(BORINGSSL_HAS_UINT128) +# define EC_NISTP_USE_64BIT_LIMB +# endif +#endif + +#if defined(EC_NISTP_USE_64BIT_LIMB) +typedef uint64_t ec_nistp_felem_limb; +#else +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 +// in higher level functions like this: +// void point_double(nistp_felem_methods *ctx, ...) { +// ctx->add(...); +// ctx->mul(...); +// } +// This makes the functions reusable between different curves by simply +// providing an appropriate methods object. +typedef struct { + 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_meth; + +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 ec_nistp_point_double(const ec_nistp_felem_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); +#endif // EC_NISTP_H + diff --git a/crypto/fipsmodule/ec/make_tables.go b/crypto/fipsmodule/ec/make_tables.go index 7ea6fcd4d0..08e092f656 100644 --- a/crypto/fipsmodule/ec/make_tables.go +++ b/crypto/fipsmodule/ec/make_tables.go @@ -392,7 +392,7 @@ func writeP384Table(path string) error { // is based on the generation method in: // https://gitlab.com/nisec/ecckiila/-/blob/master/main.py#L296 -#if defined(P384_USE_64BIT_LIMBS_FELEM)` +#if defined(EC_NISTP_USE_64BIT_LIMB)` table_def_str := fmt.Sprintf("static const p384_felem p384_g_pre_comp[%d][%d][2] = ", num_subtables, pts_per_subtable) @@ -462,7 +462,7 @@ func writeP521Table(path string) error { // is based on the generation method in: // https://gitlab.com/nisec/ecckiila/-/blob/master/main.py#L296 -#if defined(P521_USE_S2N_BIGNUM_FIELD_ARITH)` +#if defined(EC_NISTP_USE_S2N_BIGNUM)` table_def_str := fmt.Sprintf("static const p521_felem p521_g_pre_comp[%d][%d][2] = ", num_subtables, pts_per_subtable) @@ -472,7 +472,7 @@ func writeP521Table(path string) error { if err := writeTables(w, curve, tables, writeU64, nil); err != nil { return err } - if _, err := io.WriteString(w, ";\n#else\n#if defined(P521_USE_64BIT_LIMBS_FELEM)\n" + table_def_str); err != nil { + if _, err := io.WriteString(w, ";\n#else\n#if defined(EC_NISTP_USE_64BIT_LIMB)\n" + table_def_str); err != nil { return err } // P-521 Fiat-crypto implementation for 64-bit systems represents a field diff --git a/crypto/fipsmodule/ec/p256.c b/crypto/fipsmodule/ec/p256.c index 7572b68202..ba81fcc912 100644 --- a/crypto/fipsmodule/ec/p256.c +++ b/crypto/fipsmodule/ec/p256.c @@ -30,6 +30,7 @@ #include "../../internal.h" #include "../delocate.h" #include "./internal.h" +#include "ec_nistp.h" #if defined(BORINGSSL_HAS_UINT128) #define BORINGSSL_NISTP256_64BIT 1 @@ -166,73 +167,20 @@ 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 } -// 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: -// -// As a sanity check, a proof that these points form a commutative group: -// - -// fiat_p256_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: -// -// -// -// 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 fiat_p256_point_double(fiat_p256_felem x_out, fiat_p256_felem y_out, +DEFINE_METHOD_FUNCTION(ec_nistp_felem_meth, p256_felem_methods) { + out->add = fiat_p256_add; + out->sub = fiat_p256_sub; + out->mul = fiat_p256_mul; + out->sqr = fiat_p256_square; +} + +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) { - fiat_p256_felem delta, gamma, beta, ftmp, ftmp2, tmptmp, alpha, fourbeta; - // delta = z^2 - fiat_p256_square(delta, z_in); - // gamma = y^2 - fiat_p256_square(gamma, y_in); - // beta = x*gamma - fiat_p256_mul(beta, x_in, gamma); - - // alpha = 3*(x-delta)*(x+delta) - fiat_p256_sub(ftmp, x_in, delta); - fiat_p256_add(ftmp2, x_in, delta); - - fiat_p256_add(tmptmp, ftmp2, ftmp2); - fiat_p256_add(ftmp2, ftmp2, tmptmp); - fiat_p256_mul(alpha, ftmp, ftmp2); - - // x' = alpha^2 - 8*beta - fiat_p256_square(x_out, alpha); - fiat_p256_add(fourbeta, beta, beta); - fiat_p256_add(fourbeta, fourbeta, fourbeta); - fiat_p256_add(tmptmp, fourbeta, fourbeta); - fiat_p256_sub(x_out, x_out, tmptmp); - - // z' = (y + z)^2 - gamma - delta - fiat_p256_add(delta, gamma, delta); - fiat_p256_add(ftmp, y_in, z_in); - fiat_p256_square(z_out, ftmp); - fiat_p256_sub(z_out, z_out, delta); - - // y' = alpha*(4*beta - x') - 8*gamma^2 - fiat_p256_sub(y_out, fourbeta, x_out); - fiat_p256_add(gamma, gamma, gamma); - fiat_p256_square(gamma, gamma); - fiat_p256_mul(y_out, alpha, y_out); - fiat_p256_add(gamma, gamma, gamma); - fiat_p256_sub(y_out, y_out, gamma); + 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) diff --git a/crypto/fipsmodule/ec/p384.c b/crypto/fipsmodule/ec/p384.c index 9e1011a123..777fd20b26 100644 --- a/crypto/fipsmodule/ec/p384.c +++ b/crypto/fipsmodule/ec/p384.c @@ -14,49 +14,21 @@ #include "../cpucap/internal.h" #include "../delocate.h" #include "internal.h" +#include "ec_nistp.h" #if !defined(OPENSSL_SMALL) -// We have two implementations of the field arithmetic for P-384 curve: -// - Fiat-crypto -// - s2n-bignum -// Both Fiat-crypto and s2n-bignum implementations are formally verified. -// Fiat-crypto implementation is fully portable C code, while s2n-bignum -// implements the operations in assembly for x86_64 and aarch64 platforms. -// All the P-384 field operations supported by Fiat-crypto are supported -// by s2n-bignum as well, so s2n-bignum can be used as a drop-in replacement -// when appropriate. To do that we define macros for the functions. -// For example, field addition macro is either defined as -// #define p384_felem_add(out, in0, in1) fiat_p384_add(out, in0, in1) -// when Fiat-crypto is used, or as: -// #define p384_felem_add(out, in0, in1) bignum_add_p384(out, in0, in1) -// when s2n-bignum is used. -// -// If (1) x86_64 or aarch64, (2) linux or apple, and (3) OPENSSL_NO_ASM is not -// set, s2n-bignum path is capable. -#if !defined(OPENSSL_NO_ASM) && \ - (defined(OPENSSL_LINUX) || defined(OPENSSL_APPLE) || \ - defined(OPENSSL_OPENBSD)) && \ - ((defined(OPENSSL_X86_64) && !defined(MY_ASSEMBLER_IS_TOO_OLD_FOR_AVX)) || \ - defined(OPENSSL_AARCH64)) - +#if defined(EC_NISTP_USE_S2N_BIGNUM) # include "../../../third_party/s2n-bignum/include/s2n-bignum_aws-lc.h" - -# define P384_USE_S2N_BIGNUM_FIELD_ARITH 1 -# define P384_USE_64BIT_LIMBS_FELEM 1 - #else - -# if defined(BORINGSSL_HAS_UINT128) +# if defined(EC_NISTP_USE_64BIT_LIMB) # include "../../../third_party/fiat/p384_64.h" -# define P384_USE_64BIT_LIMBS_FELEM 1 # else # include "../../../third_party/fiat/p384_32.h" # endif - #endif -#if defined(P384_USE_64BIT_LIMBS_FELEM) +#if defined(EC_NISTP_USE_64BIT_LIMB) #define P384_NLIMBS (6) typedef uint64_t p384_limb_t; @@ -74,8 +46,7 @@ static const p384_felem p384_felem_one = { #endif // 64BIT - -#if defined(P384_USE_S2N_BIGNUM_FIELD_ARITH) +#if defined(EC_NISTP_USE_S2N_BIGNUM) #define p384_felem_add(out, in0, in1) bignum_add_p384(out, in0, in1) #define p384_felem_sub(out, in0, in1) bignum_sub_p384(out, in0, in1) @@ -91,7 +62,7 @@ static p384_limb_t p384_felem_nz(const p384_limb_t in1[P384_NLIMBS]) { return bignum_nonzero_6(in1); } -#else // P384_USE_S2N_BIGNUM_FIELD_ARITH +#else // EC_NISTP_USE_S2N_BIGNUM // Fiat-crypto implementation of field arithmetic #define p384_felem_add(out, in0, in1) fiat_p384_add(out, in0, in1) @@ -110,7 +81,7 @@ static p384_limb_t p384_felem_nz(const p384_limb_t in1[P384_NLIMBS]) { return ret; } -#endif // P384_USE_S2N_BIGNUM_FIELD_ARITH +#endif // EC_NISTP_USE_S2N_BIGNUM static void p384_felem_copy(p384_limb_t out[P384_NLIMBS], @@ -270,69 +241,29 @@ static void p384_inv_square(p384_felem out, p384_felem_sqr(out, ret); // 2^384 - 2^128 - 2^96 + 2^32 - 2^2 = p - 3 } -// 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. -// -// p384_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: -// -// -// 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). +#if defined(EC_NISTP_USE_S2N_BIGNUM) +DEFINE_METHOD_FUNCTION(ec_nistp_felem_meth, p384_felem_methods) { + out->add = bignum_add_p384; + out->sub = bignum_sub_p384; + out->mul = bignum_montmul_p384_selector; + out->sqr = bignum_montsqr_p384_selector; +} +#else +DEFINE_METHOD_FUNCTION(ec_nistp_felem_meth, p384_felem_methods) { + out->add = fiat_p384_add; + out->sub = fiat_p384_sub; + out->mul = fiat_p384_mul; + out->sqr = fiat_p384_square; +} +#endif + static void p384_point_double(p384_felem x_out, p384_felem y_out, p384_felem z_out, const p384_felem x_in, const p384_felem y_in, const p384_felem z_in) { - p384_felem delta, gamma, beta, ftmp, ftmp2, tmptmp, alpha, fourbeta; - // delta = z^2 - p384_felem_sqr(delta, z_in); - // gamma = y^2 - p384_felem_sqr(gamma, y_in); - // beta = x*gamma - p384_felem_mul(beta, x_in, gamma); - - // alpha = 3*(x-delta)*(x+delta) - p384_felem_sub(ftmp, x_in, delta); - p384_felem_add(ftmp2, x_in, delta); - - p384_felem_add(tmptmp, ftmp2, ftmp2); - p384_felem_add(ftmp2, ftmp2, tmptmp); - p384_felem_mul(alpha, ftmp, ftmp2); - - // x' = alpha^2 - 8*beta - p384_felem_sqr(x_out, alpha); - p384_felem_add(fourbeta, beta, beta); - p384_felem_add(fourbeta, fourbeta, fourbeta); - p384_felem_add(tmptmp, fourbeta, fourbeta); - p384_felem_sub(x_out, x_out, tmptmp); - - // z' = (y + z)^2 - gamma - delta - // The following calculation differs from that in p256.c: - // an add is replaced with a sub. This saves us 5 cmovznz operations - // when Fiat-crypto implementation of felem_add and felem_sub is used, - // and also a certain number of intructions when s2n-bignum is used. - p384_felem_add(ftmp, y_in, z_in); - p384_felem_sqr(z_out, ftmp); - p384_felem_sub(z_out, z_out, gamma); - p384_felem_sub(z_out, z_out, delta); - - // y' = alpha*(4*beta - x') - 8*gamma^2 - p384_felem_sub(y_out, fourbeta, x_out); - p384_felem_add(gamma, gamma, gamma); - p384_felem_sqr(gamma, gamma); - p384_felem_mul(y_out, alpha, y_out); - p384_felem_add(gamma, gamma, gamma); - p384_felem_sub(y_out, y_out, gamma); + ec_nistp_point_double(p384_felem_methods(), x_out, y_out, z_out, x_in, y_in, z_in); } // p384_point_add calculates (x1, y1, z1) + (x2, y2, z2) diff --git a/crypto/fipsmodule/ec/p384_table.h b/crypto/fipsmodule/ec/p384_table.h index 511ba6ef48..91a1396059 100644 --- a/crypto/fipsmodule/ec/p384_table.h +++ b/crypto/fipsmodule/ec/p384_table.h @@ -25,7 +25,7 @@ // is based on the generation method in: // https://gitlab.com/nisec/ecckiila/-/blob/master/main.py#L296 -#if defined(P384_USE_64BIT_LIMBS_FELEM) +#if defined(EC_NISTP_USE_64BIT_LIMB) static const p384_felem p384_g_pre_comp[20][16][2] = { {{{0x3dd0756649c0b528, 0x20e378e2a0d6ce38, 0x879c3afc541b4d6e, 0x6454868459a30eff, 0x812ff723614ede2b, 0x4d3aadc2299e1513}, diff --git a/crypto/fipsmodule/ec/p521.c b/crypto/fipsmodule/ec/p521.c index ec720651a7..d5ad43c7ec 100644 --- a/crypto/fipsmodule/ec/p521.c +++ b/crypto/fipsmodule/ec/p521.c @@ -17,46 +17,21 @@ #include "../cpucap/internal.h" #include "../delocate.h" #include "internal.h" +#include "ec_nistp.h" #if !defined(OPENSSL_SMALL) -// We have two implementations of the field arithmetic for P-521 curve: -// - Fiat-crypto -// - s2n-bignum -// Both Fiat-crypto and s2n-bignum implementations are formally verified. -// Fiat-crypto implementation is fully portable C code, while s2n-bignum -// implements the operations in assembly for x86_64 and aarch64 platforms. -// All the P-521 field operations supported by Fiat-crypto are supported -// by s2n-bignum as well, so s2n-bignum can be used as a drop-in replacement -// when appropriate. To do that we define macros for the functions. -// For example, field addition macro is either defined as -// #define p521_felem_add(out, in0, in1) fiat_p521_add(out, in0, in1) -// when Fiat-crypto is used, or as: -// #define p521_felem_add(out, in0, in1) bignum_add_p521(out, in0, in1) -// when s2n-bignum is used. -// If (1) x86_64 or aarch64, (2) linux or apple, and (3) OPENSSL_NO_ASM is not -// set, s2n-bignum path is capable. -#if !defined(OPENSSL_NO_ASM) && \ - (defined(OPENSSL_LINUX) || defined(OPENSSL_APPLE) || \ - defined(OPENSSL_OPENBSD)) && \ - ((defined(OPENSSL_X86_64) && !defined(MY_ASSEMBLER_IS_TOO_OLD_FOR_AVX)) || \ - defined(OPENSSL_AARCH64)) +#if defined(EC_NISTP_USE_S2N_BIGNUM) # include "../../../third_party/s2n-bignum/include/s2n-bignum_aws-lc.h" -# define P521_USE_S2N_BIGNUM_FIELD_ARITH 1 - #else - -// Fiat-crypto has both 64-bit and 32-bit implementation for P-521. -# if defined(BORINGSSL_HAS_UINT128) +# if defined(EC_NISTP_USE_64BIT_LIMB) # include "../../../third_party/fiat/p521_64.h" -# define P521_USE_64BIT_LIMBS_FELEM 1 # else # include "../../../third_party/fiat/p521_32.h" # endif - #endif -#if defined(P521_USE_S2N_BIGNUM_FIELD_ARITH) +#if defined(EC_NISTP_USE_S2N_BIGNUM) #define P521_NLIMBS (9) @@ -87,9 +62,9 @@ static const p521_limb_t p521_felem_p[P521_NLIMBS] = { #define p521_felem_mul(out, in0, in1) bignum_mul_p521_selector(out, in0, in1) #define p521_felem_sqr(out, in0) bignum_sqr_p521_selector(out, in0) -#else // P521_USE_S2N_BIGNUM_FIELD_ARITH +#else // EC_NISTP_USE_S2N_BIGNUM -#if defined(P521_USE_64BIT_LIMBS_FELEM) +#if defined(EC_NISTP_USE_64BIT_LIMB) // In the 64-bit case Fiat-crypto represents a field element by 9 58-bit digits. #define P521_NLIMBS (9) @@ -149,7 +124,7 @@ static const p521_limb_t p521_felem_p[P521_NLIMBS] = { #define p521_felem_to_bytes(out, in0) fiat_secp521r1_to_bytes(out, in0) #define p521_felem_from_bytes(out, in0) fiat_secp521r1_from_bytes(out, in0) -#endif // P521_USE_S2N_BIGNUM_FIELD_ARITH +#endif // EC_NISTP_USE_S2N_BIGNUM static p521_limb_t p521_felem_nz(const p521_limb_t in1[P521_NLIMBS]) { p521_limb_t is_not_zero = 0; @@ -157,7 +132,7 @@ static p521_limb_t p521_felem_nz(const p521_limb_t in1[P521_NLIMBS]) { is_not_zero |= in1[i]; } -#if defined(P521_USE_S2N_BIGNUM_FIELD_ARITH) +#if defined(EC_NISTP_USE_S2N_BIGNUM) return is_not_zero; #else // Fiat-crypto functions may return p (the field characteristic) @@ -284,69 +259,29 @@ static void p521_felem_inv(p521_felem output, const p521_felem t1) { p521_felem_mul(output, acc, t1); } -// 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. -// -// p521_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: -// -// -// 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). +#if defined(EC_NISTP_USE_S2N_BIGNUM) +DEFINE_METHOD_FUNCTION(ec_nistp_felem_meth, p521_felem_methods) { + out->add = bignum_add_p521; + out->sub = bignum_sub_p521; + out->mul = bignum_mul_p521_selector; + out->sqr = bignum_sqr_p521_selector; +} +#else +DEFINE_METHOD_FUNCTION(ec_nistp_felem_meth, p521_felem_methods) { + out->add = fiat_secp521r1_carry_add; + out->sub = fiat_secp521r1_carry_sub; + out->mul = fiat_secp521r1_carry_mul; + out->sqr = fiat_secp521r1_carry_square; +} +#endif + static void p521_point_double(p521_felem x_out, p521_felem y_out, p521_felem z_out, const p521_felem x_in, const p521_felem y_in, const p521_felem z_in) { - p521_felem delta, gamma, beta, ftmp, ftmp2, tmptmp, alpha, fourbeta; - // delta = z^2 - p521_felem_sqr(delta, z_in); - // gamma = y^2 - p521_felem_sqr(gamma, y_in); - // beta = x*gamma - p521_felem_mul(beta, x_in, gamma); - - // alpha = 3*(x-delta)*(x+delta) - p521_felem_sub(ftmp, x_in, delta); - p521_felem_add(ftmp2, x_in, delta); - - p521_felem_add(tmptmp, ftmp2, ftmp2); - p521_felem_add(ftmp2, ftmp2, tmptmp); - p521_felem_mul(alpha, ftmp, ftmp2); - - // x' = alpha^2 - 8*beta - p521_felem_sqr(x_out, alpha); - p521_felem_add(fourbeta, beta, beta); - p521_felem_add(fourbeta, fourbeta, fourbeta); - p521_felem_add(tmptmp, fourbeta, fourbeta); - p521_felem_sub(x_out, x_out, tmptmp); - - // z' = (y + z)^2 - gamma - delta - // The following calculation differs from that in p256.c: - // an add is replaced with a sub. This saves us 5 cmovznz operations - // when Fiat-crypto implementation of felem_add and felem_sub is used, - // and also a certain number of intructions when s2n-bignum is used. - p521_felem_add(ftmp, y_in, z_in); - p521_felem_sqr(z_out, ftmp); - p521_felem_sub(z_out, z_out, gamma); - p521_felem_sub(z_out, z_out, delta); - - // y' = alpha*(4*beta - x') - 8*gamma^2 - p521_felem_sub(y_out, fourbeta, x_out); - p521_felem_add(gamma, gamma, gamma); - p521_felem_sqr(gamma, gamma); - p521_felem_mul(y_out, alpha, y_out); - p521_felem_add(gamma, gamma, gamma); - p521_felem_sub(y_out, y_out, gamma); + ec_nistp_point_double(p521_felem_methods(), x_out, y_out, z_out, x_in, y_in, z_in); } // p521_point_add calculates (x1, y1, z1) + (x2, y2, z2) diff --git a/crypto/fipsmodule/ec/p521_table.h b/crypto/fipsmodule/ec/p521_table.h index 0d5e7da1db..029fd82ada 100644 --- a/crypto/fipsmodule/ec/p521_table.h +++ b/crypto/fipsmodule/ec/p521_table.h @@ -25,7 +25,7 @@ // is based on the generation method in: // https://gitlab.com/nisec/ecckiila/-/blob/master/main.py#L296 -#if defined(P521_USE_S2N_BIGNUM_FIELD_ARITH) +#if defined(EC_NISTP_USE_S2N_BIGNUM) static const p521_felem p521_g_pre_comp[27][16][2] = { {{{0xf97e7e31c2e5bd66, 0x3348b3c1856a429b, 0xfe1dc127a2ffa8de, 0xa14b5e77efe75928, 0xf828af606b4d3dba, 0x9c648139053fb521, @@ -2620,7 +2620,7 @@ static const p521_felem p521_g_pre_comp[27][16][2] = { 0xa52d88b032279d4f, 0xcbb5c865dc5e94a4, 0x438dfd2ab800eeb6, 0xca1f3410ea7c4ad8, 0x7753085f3ebf90db, 0x00000000000001d3}}}}; #else -#if defined(P521_USE_64BIT_LIMBS_FELEM) +#if defined(EC_NISTP_USE_64BIT_LIMB) static const p521_felem p521_g_pre_comp[27][16][2] = { {{{0x017e7e31c2e5bd66, 0x022cf0615a90a6fe, 0x00127a2ffa8de334, 0x01dfbf9d64a3f877, 0x006b4d3dbaa14b5e, 0x014fed487e0a2bd8,