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

Added generic EC scalar rwnaf encoding for ec_nistp #1664

Merged
merged 5 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
38 changes: 38 additions & 0 deletions crypto/fipsmodule/ec/ec_nistp.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,41 @@ 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) {
uint8_t *in_bytes = (uint8_t*)in->words;
return (in_bytes[i >> 3] >> (i & 7)) & 1;
}

#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;
dkostic marked this conversation as resolved.
Show resolved Hide resolved
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
Loading