Skip to content

Commit

Permalink
Added generic EC scalar rwnaf encoding for ec_nistp (#1664)
Browse files Browse the repository at this point in the history
Scalar encoding for scalar multiplication for curves P-384 and P-521
was implemented for each curve separately and with hard-coded
parameters. This commit refactors the encoding function to be
generic and uses removes the hard-coded ones.
  • Loading branch information
dkostic authored Jul 1, 2024
1 parent 972832d commit dd7bb4a
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 77 deletions.
44 changes: 44 additions & 0 deletions crypto/fipsmodule/ec/ec_nistp.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,47 @@ void ec_nistp_point_add(const ec_nistp_meth *ctx,
cmovznz(z3, ctx->felem_num_limbs, z2nz, z1, z_out);
}

// Returns i-th bit of the scalar (zero or one).
// The caller is responsible for making sure i is within bounds of the scalar.
static int16_t get_bit(const EC_SCALAR *in, size_t i) {
// |in->words| is an array of BN_ULONGs which can be either 8 or 4 bytes long.
#if defined(OPENSSL_64_BIT)
OPENSSL_STATIC_ASSERT(sizeof(BN_ULONG) == 8, bn_ulong_not_eight_bytes);
return (in->words[i >> 6] >> (i & 63)) & 1;
#else
OPENSSL_STATIC_ASSERT(sizeof(BN_ULONG) == 4, bn_ulong_not_four_bytes);
return (in->words[i >> 5] >> (i & 31)) & 1;
#endif
}

#define DIV_AND_CEIL(a, b) ((a + b - 1) / b)

// Compute "regular" wNAF representation of a scalar, see
// Joye, Tunstall, "Exponent Recoding and Regular Exponentiation Algorithms",
// AfricaCrypt 2009, Alg 6.
// It forces an odd scalar and outputs digits in
// {\pm 1, \pm 3, \pm 5, \pm 7, \pm 9, ...}
// i.e. signed odd digits with _no zeroes_ -- that makes it "regular".
void scalar_rwnaf(int16_t *out, size_t window_size,
const EC_SCALAR *scalar, size_t scalar_bit_size) {
assert(window_size < 14);

// The assert above ensures this works correctly.
const int16_t window_mask = (1 << (window_size + 1)) - 1;
int16_t window = (int16_t)(scalar->words[0] & (BN_ULONG)window_mask);
window |= 1;

const size_t num_windows = DIV_AND_CEIL(scalar_bit_size, window_size);
for (size_t i = 0; i < num_windows - 1; i++) {
int16_t d = (window & window_mask) - (int16_t)(1 << window_size);
out[i] = d;
window = (window - d) >> window_size;
for (size_t j = 1; j <= window_size; j++) {
size_t idx = (i + 1) * window_size + j;
if (idx < scalar_bit_size) {
window |= get_bit(scalar, idx) << j;
}
}
}
out[num_windows - 1] = window;
}
3 changes: 3 additions & 0 deletions crypto/fipsmodule/ec/ec_nistp.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,8 @@ void ec_nistp_point_add(const ec_nistp_meth *ctx,
const ec_nistp_felem_limb *x2,
const ec_nistp_felem_limb *y2,
const ec_nistp_felem_limb *z2);

void scalar_rwnaf(int16_t *out, size_t window_size,
const EC_SCALAR *scalar, size_t scalar_bit_size);
#endif // EC_NISTP_H

41 changes: 2 additions & 39 deletions crypto/fipsmodule/ec/p384.c
Original file line number Diff line number Diff line change
Expand Up @@ -470,21 +470,6 @@ static int ec_GFp_nistp384_cmp_x_coordinate(const EC_GROUP *group,
//
// For detailed analysis of different window sizes see the bottom of this file.


// p384_get_bit returns the |i|-th bit in |in|
static crypto_word_t p384_get_bit(const EC_SCALAR *in, int i) {
if (i < 0 || i >= 384) {
return 0;
}
#if defined(OPENSSL_64_BIT)
assert(sizeof(BN_ULONG) == 8);
return (in->words[i >> 6] >> (i & 63)) & 1;
#else
assert(sizeof(BN_ULONG) == 4);
return (in->words[i >> 5] >> (i & 31)) & 1;
#endif
}

// Constants for scalar encoding in the scalar multiplication functions.
#define P384_MUL_WSIZE (5) // window size w
// Assert the window size is 5 because the pre-computed table in |p384_table.h|
Expand All @@ -493,7 +478,6 @@ OPENSSL_STATIC_ASSERT(P384_MUL_WSIZE == 5,
p384_scalar_mul_window_size_is_not_equal_to_five)

#define P384_MUL_TWO_TO_WSIZE (1 << P384_MUL_WSIZE)
#define P384_MUL_WSIZE_MASK ((P384_MUL_TWO_TO_WSIZE << 1) - 1)

// Number of |P384_MUL_WSIZE|-bit windows in a 384-bit value
#define P384_MUL_NWINDOWS ((384 + P384_MUL_WSIZE - 1)/P384_MUL_WSIZE)
Expand All @@ -506,27 +490,6 @@ OPENSSL_STATIC_ASSERT(P384_MUL_WSIZE == 5,
#define P384_MUL_TABLE_SIZE (P384_MUL_TWO_TO_WSIZE >> 1)
#define P384_MUL_PUB_TABLE_SIZE (1 << (P384_MUL_PUB_WSIZE - 1))

// Compute "regular" wNAF representation of a scalar, see
// Joye, Tunstall, "Exponent Recoding and Regular Exponentiation Algorithms",
// AfricaCrypt 2009, Alg 6.
// It forces an odd scalar and outputs digits in
// {\pm 1, \pm 3, \pm 5, \pm 7, \pm 9, ...}
// i.e. signed odd digits with _no zeroes_ -- that makes it "regular".
static void p384_felem_mul_scalar_rwnaf(int16_t *out, const EC_SCALAR *in) {
int16_t window, d;

window = (in->words[0] & P384_MUL_WSIZE_MASK) | 1;
for (size_t i = 0; i < P384_MUL_NWINDOWS - 1; i++) {
d = (window & P384_MUL_WSIZE_MASK) - P384_MUL_TWO_TO_WSIZE;
out[i] = d;
window = (window - d) >> P384_MUL_WSIZE;
for (size_t j = 1; j <= P384_MUL_WSIZE; j++) {
window += p384_get_bit(in, (i + 1) * P384_MUL_WSIZE + j) << j;
}
}
out[P384_MUL_NWINDOWS - 1] = window;
}

// p384_select_point selects the |idx|-th projective point from the given
// precomputed table and copies it to |out| in constant time.
static void p384_select_point(p384_felem out[3],
Expand Down Expand Up @@ -614,7 +577,7 @@ static void ec_GFp_nistp384_point_mul(const EC_GROUP *group, EC_JACOBIAN *r,

// Recode the scalar.
int16_t rnaf[P384_MUL_NWINDOWS] = {0};
p384_felem_mul_scalar_rwnaf(rnaf, scalar);
scalar_rwnaf(rnaf, P384_MUL_WSIZE, scalar, 384);

// Initialize the accumulator |res| with the table entry corresponding to
// the most significant digit of the recoded scalar (note that this digit
Expand Down Expand Up @@ -738,7 +701,7 @@ static void ec_GFp_nistp384_point_mul_base(const EC_GROUP *group,
int16_t rnaf[P384_MUL_NWINDOWS] = {0};

// Recode the scalar.
p384_felem_mul_scalar_rwnaf(rnaf, scalar);
scalar_rwnaf(rnaf, P384_MUL_WSIZE, scalar, 384);

// Process the 4 groups of digits starting from group (3) down to group (0).
for (int i = 3; i >= 0; i--) {
Expand Down
40 changes: 2 additions & 38 deletions crypto/fipsmodule/ec/p521.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,20 +407,6 @@ static void ec_GFp_nistp521_dbl(const EC_GROUP *group, EC_JACOBIAN *r,
// The precomputed table of base point multiples is generated by the code in
// |make_tables.go| script.

// p521_get_bit returns the |i|-th bit in |in|
static crypto_word_t p521_get_bit(const EC_SCALAR *in, int i) {
if (i < 0 || i >= 521) {
return 0;
}
#if defined(OPENSSL_64_BIT)
assert(sizeof(BN_ULONG) == 8);
return (in->words[i >> 6] >> (i & 63)) & 1;
#else
assert(sizeof(BN_ULONG) == 4);
return (in->words[i >> 5] >> (i & 31)) & 1;
#endif
}

// Constants for scalar encoding in the scalar multiplication functions.
#define P521_MUL_WSIZE (5) // window size w
// Assert the window size is 5 because the pre-computed table in |p521_table.h|
Expand All @@ -429,7 +415,6 @@ OPENSSL_STATIC_ASSERT(P521_MUL_WSIZE == 5,
p521_scalar_mul_window_size_is_not_equal_to_five)

#define P521_MUL_TWO_TO_WSIZE (1 << P521_MUL_WSIZE)
#define P521_MUL_WSIZE_MASK ((P521_MUL_TWO_TO_WSIZE << 1) - 1)

// Number of |P521_MUL_WSIZE|-bit windows in a 521-bit value
#define P521_MUL_NWINDOWS ((521 + P521_MUL_WSIZE - 1)/P521_MUL_WSIZE)
Expand All @@ -442,27 +427,6 @@ OPENSSL_STATIC_ASSERT(P521_MUL_WSIZE == 5,
#define P521_MUL_TABLE_SIZE (P521_MUL_TWO_TO_WSIZE >> 1)
#define P521_MUL_PUB_TABLE_SIZE (1 << (P521_MUL_PUB_WSIZE - 1))

// Compute "regular" wNAF representation of a scalar, see
// Joye, Tunstall, "Exponent Recoding and Regular Exponentiation Algorithms",
// AfricaCrypt 2009, Alg 6.
// It forces an odd scalar and outputs digits in
// {\pm 1, \pm 3, \pm 5, \pm 7, \pm 9, ...}
// i.e. signed odd digits with _no zeroes_ -- that makes it "regular".
static void p521_felem_mul_scalar_rwnaf(int16_t *out, const EC_SCALAR *in) {
int16_t window, d;

window = (in->words[0] & P521_MUL_WSIZE_MASK) | 1;
for (size_t i = 0; i < P521_MUL_NWINDOWS - 1; i++) {
d = (window & P521_MUL_WSIZE_MASK) - P521_MUL_TWO_TO_WSIZE;
out[i] = d;
window = (window - d) >> P521_MUL_WSIZE;
for (size_t j = 1; j <= P521_MUL_WSIZE; j++) {
window += p521_get_bit(in, (i + 1) * P521_MUL_WSIZE + j) << j;
}
}
out[P521_MUL_NWINDOWS - 1] = window;
}

// p521_select_point selects the |idx|-th projective point from the given
// precomputed table and copies it to |out| in constant time.
static void p521_select_point(p521_felem out[3],
Expand Down Expand Up @@ -550,7 +514,7 @@ static void ec_GFp_nistp521_point_mul(const EC_GROUP *group, EC_JACOBIAN *r,

// Recode the scalar.
int16_t rnaf[P521_MUL_NWINDOWS] = {0};
p521_felem_mul_scalar_rwnaf(rnaf, scalar);
scalar_rwnaf(rnaf, P521_MUL_WSIZE, scalar, 521);

// Initialize the accumulator |res| with the table entry corresponding to
// the most significant digit of the recoded scalar (note that this digit
Expand Down Expand Up @@ -674,7 +638,7 @@ static void ec_GFp_nistp521_point_mul_base(const EC_GROUP *group,
int16_t rnaf[P521_MUL_NWINDOWS] = {0};

// Recode the scalar.
p521_felem_mul_scalar_rwnaf(rnaf, scalar);
scalar_rwnaf(rnaf, P521_MUL_WSIZE, scalar, 521);

// Process the 4 groups of digits starting from group (3) down to group (0).
for (int i = 3; i >= 0; i--) {
Expand Down

0 comments on commit dd7bb4a

Please sign in to comment.