constant-time inverses

This commit is contained in:
Leon Botros 2019-08-21 18:54:04 +02:00
parent e4a5cc3cf2
commit d3d72f64cc
3 changed files with 207 additions and 263 deletions

View File

@ -74,16 +74,6 @@ static void gf2x_mod(DIGIT out[], const DIGIT in[]) {
out[0] &= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS) - 1; out[0] &= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS) - 1;
} }
static void left_bit_shift(const int length, DIGIT in[]) {
int j;
for (j = 0; j < length - 1; j++) {
in[j] <<= 1; /* logical shift does not need clearing */
in[j] |= in[j + 1] >> (DIGIT_SIZE_b - 1);
}
in[j] <<= 1;
}
static void right_bit_shift(unsigned int length, DIGIT in[]) { static void right_bit_shift(unsigned int length, DIGIT in[]) {
unsigned int j; unsigned int j;
@ -153,17 +143,6 @@ void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_transpose_in_place(DIGIT A[]) {
A[NUM_DIGITS_GF2X_ELEMENT - 1] = (A[NUM_DIGITS_GF2X_ELEMENT - 1] & (~mask)) | a00; A[NUM_DIGITS_GF2X_ELEMENT - 1] = (A[NUM_DIGITS_GF2X_ELEMENT - 1] & (~mask)) | a00;
} }
static void rotate_bit_left(DIGIT in[]) { /* equivalent to x * in(x) mod x^P+1 */
DIGIT mask, rotated_bit;
int msb_offset_in_digit = MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS - 1;
mask = ((DIGIT)0x1) << msb_offset_in_digit;
rotated_bit = !!(in[0] & mask);
in[0] &= ~mask;
left_bit_shift(NUM_DIGITS_GF2X_ELEMENT, in);
in[NUM_DIGITS_GF2X_ELEMENT - 1] |= rotated_bit;
}
static void rotate_bit_right(DIGIT in[]) { /* x^{-1} * in(x) mod x^P+1 */ static void rotate_bit_right(DIGIT in[]) { /* x^{-1} * in(x) mod x^P+1 */
DIGIT rotated_bit = in[NUM_DIGITS_GF2X_ELEMENT - 1] & ((DIGIT)0x1); DIGIT rotated_bit = in[NUM_DIGITS_GF2X_ELEMENT - 1] & ((DIGIT)0x1);
@ -173,87 +152,90 @@ static void rotate_bit_right(DIGIT in[]) { /* x^{-1} * in(x) mod x^P+1 */
in[0] |= rotated_bit; in[0] |= rotated_bit;
} }
static void gf2x_swap(const int length, DIGIT f[], DIGIT s[]) { /* cond swap: swaps digits A and B if swap_mask == -1 */
static void gf2x_cswap(DIGIT *a, DIGIT *b, int swap_mask) {
int i;
DIGIT t; DIGIT t;
for (int i = length - 1; i >= 0; i--) { for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
t = f[i]; t = swap_mask & (a[i] ^ b[i]);
f[i] = s[i]; a[i] ^= t;
s[i] = t; b[i] ^= t;
} }
} }
/* /* returns -1 mask if x != 0, otherwise 0 */
* Optimized extended GCD algorithm to compute the multiplicative inverse of static inline int nonzero(DIGIT x) {
* a non-zero element in GF(2)[x] mod x^P+1, in polyn. representation. DIGIT t = x;
* t = -t;
* H. Brunner, A. Curiger, and M. Hofstetter. 1993. t >>= DIGIT_SIZE_b - 1;
* On Computing Multiplicative Inverses in GF(2^m). return -(int)t;
* IEEE Trans. Comput. 42, 8 (August 1993), 1010-1015. }
* DOI=http://dx.doi.org/10.1109/12.238496
*
*
* Henri Cohen, Gerhard Frey, Roberto Avanzi, Christophe Doche, Tanja Lange,
* Kim Nguyen, and Frederik Vercauteren. 2012.
* Handbook of Elliptic and Hyperelliptic Curve Cryptography,
* Second Edition (2nd ed.). Chapman & Hall/CRC.
* (Chapter 11 -- Algorithm 11.44 -- pag 223)
*
*/
int PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_inverse(DIGIT out[], const DIGIT in[]) { /* in^{-1} mod x^P-1 */
int i; /* returns -1 mask if x < 0 else 0 */
int delta = 0; static inline int negative(int x) {
DIGIT u[NUM_DIGITS_GF2X_ELEMENT] = {0}; uint32_t u = x;
DIGIT v[NUM_DIGITS_GF2X_ELEMENT] = {0}; u >>= 31;
DIGIT s[NUM_DIGITS_GF2X_MODULUS] = {0}; return -(int)u;
DIGIT f[NUM_DIGITS_GF2X_MODULUS] = {0}; // alignas(32)? }
DIGIT mask; /* return f(0) as digit */
u[NUM_DIGITS_GF2X_ELEMENT - 1] = 0x1; static inline DIGIT lsb(const DIGIT *p) {
v[NUM_DIGITS_GF2X_ELEMENT - 1] = 0x0; DIGIT mask = (DIGIT)1;
return p[NUM_DIGITS_GF2X_ELEMENT - 1] & mask;
}
s[NUM_DIGITS_GF2X_MODULUS - 1] = 0x1; /* multiply poly with scalar and accumulate, expects s all-zero of all-one mask */
static void gf2x_mult_scalar_acc(DIGIT *f, const DIGIT *g, const DIGIT s) {
for (size_t i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
f[i] = f[i] ^ (s & g[i]);
}
}
mask = (((DIGIT)0x1) << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS); /* constant-time inverse, source: gcd.cr.yp.to */
s[0] |= mask; int PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_inverse(DIGIT out[], const DIGIT in[]) {
int i, loop, swap, delta = 1;
DIGIT g0_mask;
for (i = NUM_DIGITS_GF2X_ELEMENT - 1; i >= 0 && in[i] == 0; i--) { }; DIGIT f[NUM_DIGITS_GF2X_MODULUS] = {0}; // f = x^P + 1
if (i < 0) { DIGIT g[NUM_DIGITS_GF2X_ELEMENT]; // g = in
return 0; DIGIT *v = out; // v = 0, save space
DIGIT r[NUM_DIGITS_GF2X_ELEMENT] = {0}; // r = 1
f[NUM_DIGITS_GF2X_MODULUS - 1] = 1;
f[0] |= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS);
for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
g[i] = in[i];
} }
for (i = NUM_DIGITS_GF2X_MODULUS - 1; i >= 0 ; i--) { for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
f[i] = in[i]; v[i] = 0;
} }
for (i = 1; i <= 2 * P; i++) { r[NUM_DIGITS_GF2X_ELEMENT - 1] = 1;
if ( (f[0] & mask) == 0 ) {
left_bit_shift(NUM_DIGITS_GF2X_MODULUS, f); for (loop = 0; loop < 2 * P - 1; ++loop) {
rotate_bit_left(u);
delta += 1; swap = negative(-delta) & nonzero(lsb(g)); // swap = -1 if -delta < 0 AND g(0) != 0
} else { delta ^= swap & (delta ^ -delta); // cond swap delta with -delta if swap
if ( (s[0] & mask) != 0) { delta++;
PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_add(s, s, f, NUM_DIGITS_GF2X_MODULUS);
PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_add(v, v, u); gf2x_cswap(f, g, swap);
} gf2x_cswap(v, r, swap);
left_bit_shift(NUM_DIGITS_GF2X_MODULUS, s);
if ( delta == 0 ) { g0_mask = -lsb(g);
gf2x_swap(NUM_DIGITS_GF2X_MODULUS, f, s);
gf2x_swap(NUM_DIGITS_GF2X_ELEMENT, u, v); // g = (g - g0 * f) / x
rotate_bit_left(u); gf2x_mult_scalar_acc(g, f, g0_mask);
delta = 1; right_bit_shift(NUM_DIGITS_GF2X_ELEMENT, g);
} else {
rotate_bit_right(u); // r = (r - g0 * v) / x
delta = delta - 1; gf2x_mult_scalar_acc(r, v, g0_mask);
} rotate_bit_right(r);
}
} }
for (i = NUM_DIGITS_GF2X_ELEMENT - 1; i >= 0 ; i--) { return nonzero(delta); // -1 if fail, 0 if success
out[i] = u[i];
}
return (delta == 0);
} }
void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], const DIGIT B[]) { void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], const DIGIT B[]) {

View File

@ -74,16 +74,6 @@ static void gf2x_mod(DIGIT out[], const DIGIT in[]) {
out[0] &= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS) - 1; out[0] &= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS) - 1;
} }
static void left_bit_shift(const int length, DIGIT in[]) {
int j;
for (j = 0; j < length - 1; j++) {
in[j] <<= 1; /* logical shift does not need clearing */
in[j] |= in[j + 1] >> (DIGIT_SIZE_b - 1);
}
in[j] <<= 1;
}
static void right_bit_shift(unsigned int length, DIGIT in[]) { static void right_bit_shift(unsigned int length, DIGIT in[]) {
unsigned int j; unsigned int j;
@ -94,7 +84,6 @@ static void right_bit_shift(unsigned int length, DIGIT in[]) {
in[j] >>= 1; in[j] >>= 1;
} }
/* shifts by whole digits */ /* shifts by whole digits */
static void left_DIGIT_shift_n(unsigned int length, DIGIT in[], unsigned int amount) { static void left_DIGIT_shift_n(unsigned int length, DIGIT in[], unsigned int amount) {
unsigned int j; unsigned int j;
@ -151,17 +140,6 @@ void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_transpose_in_place(DIGIT A[]) {
A[NUM_DIGITS_GF2X_ELEMENT - 1] = (A[NUM_DIGITS_GF2X_ELEMENT - 1] & (~mask)) | a00; A[NUM_DIGITS_GF2X_ELEMENT - 1] = (A[NUM_DIGITS_GF2X_ELEMENT - 1] & (~mask)) | a00;
} }
static void rotate_bit_left(DIGIT in[]) { /* equivalent to x * in(x) mod x^P+1 */
DIGIT mask, rotated_bit;
int msb_offset_in_digit = MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS - 1;
mask = ((DIGIT)0x1) << msb_offset_in_digit;
rotated_bit = !!(in[0] & mask);
in[0] &= ~mask;
left_bit_shift(NUM_DIGITS_GF2X_ELEMENT, in);
in[NUM_DIGITS_GF2X_ELEMENT - 1] |= rotated_bit;
}
static void rotate_bit_right(DIGIT in[]) { /* x^{-1} * in(x) mod x^P+1 */ static void rotate_bit_right(DIGIT in[]) { /* x^{-1} * in(x) mod x^P+1 */
DIGIT rotated_bit = in[NUM_DIGITS_GF2X_ELEMENT - 1] & ((DIGIT)0x1); DIGIT rotated_bit = in[NUM_DIGITS_GF2X_ELEMENT - 1] & ((DIGIT)0x1);
@ -171,87 +149,90 @@ static void rotate_bit_right(DIGIT in[]) { /* x^{-1} * in(x) mod x^P+1 */
in[0] |= rotated_bit; in[0] |= rotated_bit;
} }
static void gf2x_swap(const int length, DIGIT f[], DIGIT s[]) { /* cond swap: swaps digits A and B if swap_mask == -1 */
static void gf2x_cswap(DIGIT *a, DIGIT *b, int swap_mask) {
int i;
DIGIT t; DIGIT t;
for (int i = length - 1; i >= 0; i--) { for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
t = f[i]; t = swap_mask & (a[i] ^ b[i]);
f[i] = s[i]; a[i] ^= t;
s[i] = t; b[i] ^= t;
} }
} }
/* /* returns -1 mask if x != 0, otherwise 0 */
* Optimized extended GCD algorithm to compute the multiplicative inverse of static inline int nonzero(DIGIT x) {
* a non-zero element in GF(2)[x] mod x^P+1, in polyn. representation. DIGIT t = x;
* t = -t;
* H. Brunner, A. Curiger, and M. Hofstetter. 1993. t >>= DIGIT_SIZE_b - 1;
* On Computing Multiplicative Inverses in GF(2^m). return -(int)t;
* IEEE Trans. Comput. 42, 8 (August 1993), 1010-1015. }
* DOI=http://dx.doi.org/10.1109/12.238496
*
*
* Henri Cohen, Gerhard Frey, Roberto Avanzi, Christophe Doche, Tanja Lange,
* Kim Nguyen, and Frederik Vercauteren. 2012.
* Handbook of Elliptic and Hyperelliptic Curve Cryptography,
* Second Edition (2nd ed.). Chapman & Hall/CRC.
* (Chapter 11 -- Algorithm 11.44 -- pag 223)
*
*/
int PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_inverse(DIGIT out[], const DIGIT in[]) { /* in^{-1} mod x^P-1 */
int i; /* returns -1 mask if x < 0 else 0 */
int delta = 0; static inline int negative(int x) {
DIGIT u[NUM_DIGITS_GF2X_ELEMENT] = {0}; uint32_t u = x;
DIGIT v[NUM_DIGITS_GF2X_ELEMENT] = {0}; u >>= 31;
DIGIT s[NUM_DIGITS_GF2X_MODULUS] = {0}; return -(int)u;
DIGIT f[NUM_DIGITS_GF2X_MODULUS] = {0}; // alignas(32)? }
DIGIT mask; /* return f(0) as digit */
u[NUM_DIGITS_GF2X_ELEMENT - 1] = 0x1; static inline DIGIT lsb(const DIGIT *p) {
v[NUM_DIGITS_GF2X_ELEMENT - 1] = 0x0; DIGIT mask = (DIGIT)1;
return p[NUM_DIGITS_GF2X_ELEMENT - 1] & mask;
}
s[NUM_DIGITS_GF2X_MODULUS - 1] = 0x1; /* multiply poly with scalar and accumulate, expects s all-zero of all-one mask */
static void gf2x_mult_scalar_acc(DIGIT *f, const DIGIT *g, const DIGIT s) {
for (size_t i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
f[i] = f[i] ^ (s & g[i]);
}
}
mask = (((DIGIT)0x1) << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS); /* constant-time inverse, source: gcd.cr.yp.to */
s[0] |= mask; int PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_inverse(DIGIT out[], const DIGIT in[]) {
int i, loop, swap, delta = 1;
DIGIT g0_mask;
for (i = NUM_DIGITS_GF2X_ELEMENT - 1; i >= 0 && in[i] == 0; i--) { }; DIGIT f[NUM_DIGITS_GF2X_MODULUS] = {0}; // f = x^P + 1
if (i < 0) { DIGIT g[NUM_DIGITS_GF2X_ELEMENT]; // g = in
return 0; DIGIT *v = out; // v = 0, save space
DIGIT r[NUM_DIGITS_GF2X_ELEMENT] = {0}; // r = 1
f[NUM_DIGITS_GF2X_MODULUS - 1] = 1;
f[0] |= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS);
for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
g[i] = in[i];
} }
for (i = NUM_DIGITS_GF2X_MODULUS - 1; i >= 0 ; i--) { for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
f[i] = in[i]; v[i] = 0;
} }
for (i = 1; i <= 2 * P; i++) { r[NUM_DIGITS_GF2X_ELEMENT - 1] = 1;
if ( (f[0] & mask) == 0 ) {
left_bit_shift(NUM_DIGITS_GF2X_MODULUS, f); for (loop = 0; loop < 2 * P - 1; ++loop) {
rotate_bit_left(u);
delta += 1; swap = negative(-delta) & nonzero(lsb(g)); // swap = -1 if -delta < 0 AND g(0) != 0
} else { delta ^= swap & (delta ^ -delta); // cond swap delta with -delta if swap
if ( (s[0] & mask) != 0) { delta++;
PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_add(s, s, f, NUM_DIGITS_GF2X_MODULUS);
PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_add(v, v, u); gf2x_cswap(f, g, swap);
} gf2x_cswap(v, r, swap);
left_bit_shift(NUM_DIGITS_GF2X_MODULUS, s);
if ( delta == 0 ) { g0_mask = -lsb(g);
gf2x_swap(NUM_DIGITS_GF2X_MODULUS, f, s);
gf2x_swap(NUM_DIGITS_GF2X_ELEMENT, u, v); // g = (g - g0 * f) / x
rotate_bit_left(u); gf2x_mult_scalar_acc(g, f, g0_mask);
delta = 1; right_bit_shift(NUM_DIGITS_GF2X_ELEMENT, g);
} else {
rotate_bit_right(u); // r = (r - g0 * v) / x
delta = delta - 1; gf2x_mult_scalar_acc(r, v, g0_mask);
} rotate_bit_right(r);
}
} }
for (i = NUM_DIGITS_GF2X_ELEMENT - 1; i >= 0 ; i--) { return nonzero(delta); // -1 if fail, 0 if success
out[i] = u[i];
}
return (delta == 0);
} }
void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], const DIGIT B[]) { void PQCLEAN_LEDAKEMLT32_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], const DIGIT B[]) {

View File

@ -74,16 +74,6 @@ static void gf2x_mod(DIGIT out[], const DIGIT in[]) {
out[0] &= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS) - 1; out[0] &= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS) - 1;
} }
static void left_bit_shift(const int length, DIGIT in[]) {
int j;
for (j = 0; j < length - 1; j++) {
in[j] <<= 1; /* logical shift does not need clearing */
in[j] |= in[j + 1] >> (DIGIT_SIZE_b - 1);
}
in[j] <<= 1;
}
static void right_bit_shift(unsigned int length, DIGIT in[]) { static void right_bit_shift(unsigned int length, DIGIT in[]) {
unsigned int j; unsigned int j;
@ -94,7 +84,6 @@ static void right_bit_shift(unsigned int length, DIGIT in[]) {
in[j] >>= 1; in[j] >>= 1;
} }
/* shifts by whole digits */ /* shifts by whole digits */
static void left_DIGIT_shift_n(unsigned int length, DIGIT in[], unsigned int amount) { static void left_DIGIT_shift_n(unsigned int length, DIGIT in[], unsigned int amount) {
unsigned int j; unsigned int j;
@ -151,17 +140,6 @@ void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_transpose_in_place(DIGIT A[]) {
A[NUM_DIGITS_GF2X_ELEMENT - 1] = (A[NUM_DIGITS_GF2X_ELEMENT - 1] & (~mask)) | a00; A[NUM_DIGITS_GF2X_ELEMENT - 1] = (A[NUM_DIGITS_GF2X_ELEMENT - 1] & (~mask)) | a00;
} }
static void rotate_bit_left(DIGIT in[]) { /* equivalent to x * in(x) mod x^P+1 */
DIGIT mask, rotated_bit;
int msb_offset_in_digit = MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS - 1;
mask = ((DIGIT)0x1) << msb_offset_in_digit;
rotated_bit = !!(in[0] & mask);
in[0] &= ~mask;
left_bit_shift(NUM_DIGITS_GF2X_ELEMENT, in);
in[NUM_DIGITS_GF2X_ELEMENT - 1] |= rotated_bit;
}
static void rotate_bit_right(DIGIT in[]) { /* x^{-1} * in(x) mod x^P+1 */ static void rotate_bit_right(DIGIT in[]) { /* x^{-1} * in(x) mod x^P+1 */
DIGIT rotated_bit = in[NUM_DIGITS_GF2X_ELEMENT - 1] & ((DIGIT)0x1); DIGIT rotated_bit = in[NUM_DIGITS_GF2X_ELEMENT - 1] & ((DIGIT)0x1);
@ -171,87 +149,90 @@ static void rotate_bit_right(DIGIT in[]) { /* x^{-1} * in(x) mod x^P+1 */
in[0] |= rotated_bit; in[0] |= rotated_bit;
} }
static void gf2x_swap(const int length, DIGIT f[], DIGIT s[]) { /* cond swap: swaps digits A and B if swap_mask == -1 */
static void gf2x_cswap(DIGIT *a, DIGIT *b, int swap_mask) {
int i;
DIGIT t; DIGIT t;
for (int i = length - 1; i >= 0; i--) { for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
t = f[i]; t = swap_mask & (a[i] ^ b[i]);
f[i] = s[i]; a[i] ^= t;
s[i] = t; b[i] ^= t;
} }
} }
/* /* returns -1 mask if x != 0, otherwise 0 */
* Optimized extended GCD algorithm to compute the multiplicative inverse of static inline int nonzero(DIGIT x) {
* a non-zero element in GF(2)[x] mod x^P+1, in polyn. representation. DIGIT t = x;
* t = -t;
* H. Brunner, A. Curiger, and M. Hofstetter. 1993. t >>= DIGIT_SIZE_b - 1;
* On Computing Multiplicative Inverses in GF(2^m). return -(int)t;
* IEEE Trans. Comput. 42, 8 (August 1993), 1010-1015. }
* DOI=http://dx.doi.org/10.1109/12.238496
*
*
* Henri Cohen, Gerhard Frey, Roberto Avanzi, Christophe Doche, Tanja Lange,
* Kim Nguyen, and Frederik Vercauteren. 2012.
* Handbook of Elliptic and Hyperelliptic Curve Cryptography,
* Second Edition (2nd ed.). Chapman & Hall/CRC.
* (Chapter 11 -- Algorithm 11.44 -- pag 223)
*
*/
int PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_inverse(DIGIT out[], const DIGIT in[]) { /* in^{-1} mod x^P-1 */
int i; /* returns -1 mask if x < 0 else 0 */
int delta = 0; static inline int negative(int x) {
DIGIT u[NUM_DIGITS_GF2X_ELEMENT] = {0}; uint32_t u = x;
DIGIT v[NUM_DIGITS_GF2X_ELEMENT] = {0}; u >>= 31;
DIGIT s[NUM_DIGITS_GF2X_MODULUS] = {0}; return -(int)u;
DIGIT f[NUM_DIGITS_GF2X_MODULUS] = {0}; // alignas(32)? }
DIGIT mask; /* return f(0) as digit */
u[NUM_DIGITS_GF2X_ELEMENT - 1] = 0x1; static inline DIGIT lsb(const DIGIT *p) {
v[NUM_DIGITS_GF2X_ELEMENT - 1] = 0x0; DIGIT mask = (DIGIT)1;
return p[NUM_DIGITS_GF2X_ELEMENT - 1] & mask;
}
s[NUM_DIGITS_GF2X_MODULUS - 1] = 0x1; /* multiply poly with scalar and accumulate, expects s all-zero of all-one mask */
static void gf2x_mult_scalar_acc(DIGIT *f, const DIGIT *g, const DIGIT s) {
for (size_t i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
f[i] = f[i] ^ (s & g[i]);
}
}
mask = (((DIGIT)0x1) << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS); /* constant-time inverse, source: gcd.cr.yp.to */
s[0] |= mask; int PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_inverse(DIGIT out[], const DIGIT in[]) {
int i, loop, swap, delta = 1;
DIGIT g0_mask;
for (i = NUM_DIGITS_GF2X_ELEMENT - 1; i >= 0 && in[i] == 0; i--) { }; DIGIT f[NUM_DIGITS_GF2X_MODULUS] = {0}; // f = x^P + 1
if (i < 0) { DIGIT g[NUM_DIGITS_GF2X_ELEMENT]; // g = in
return 0; DIGIT *v = out; // v = 0, save space
DIGIT r[NUM_DIGITS_GF2X_ELEMENT] = {0}; // r = 1
f[NUM_DIGITS_GF2X_MODULUS - 1] = 1;
f[0] |= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS);
for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
g[i] = in[i];
} }
for (i = NUM_DIGITS_GF2X_MODULUS - 1; i >= 0 ; i--) { for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
f[i] = in[i]; v[i] = 0;
} }
for (i = 1; i <= 2 * P; i++) { r[NUM_DIGITS_GF2X_ELEMENT - 1] = 1;
if ( (f[0] & mask) == 0 ) {
left_bit_shift(NUM_DIGITS_GF2X_MODULUS, f); for (loop = 0; loop < 2 * P - 1; ++loop) {
rotate_bit_left(u);
delta += 1; swap = negative(-delta) & nonzero(lsb(g)); // swap = -1 if -delta < 0 AND g(0) != 0
} else { delta ^= swap & (delta ^ -delta); // cond swap delta with -delta if swap
if ( (s[0] & mask) != 0) { delta++;
PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_add(s, s, f, NUM_DIGITS_GF2X_MODULUS);
PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_add(v, v, u); gf2x_cswap(f, g, swap);
} gf2x_cswap(v, r, swap);
left_bit_shift(NUM_DIGITS_GF2X_MODULUS, s);
if ( delta == 0 ) { g0_mask = -lsb(g);
gf2x_swap(NUM_DIGITS_GF2X_MODULUS, f, s);
gf2x_swap(NUM_DIGITS_GF2X_ELEMENT, u, v); // g = (g - g0 * f) / x
rotate_bit_left(u); gf2x_mult_scalar_acc(g, f, g0_mask);
delta = 1; right_bit_shift(NUM_DIGITS_GF2X_ELEMENT, g);
} else {
rotate_bit_right(u); // r = (r - g0 * v) / x
delta = delta - 1; gf2x_mult_scalar_acc(r, v, g0_mask);
} rotate_bit_right(r);
}
} }
for (i = NUM_DIGITS_GF2X_ELEMENT - 1; i >= 0 ; i--) { return nonzero(delta); // -1 if fail, 0 if success
out[i] = u[i];
}
return (delta == 0);
} }
void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], const DIGIT B[]) { void PQCLEAN_LEDAKEMLT52_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], const DIGIT B[]) {