#include "include/fp.h" const uint64_t p[NWORDS_FIELD] = { 0xffffffffffffffff, 0xFFFFFFFFFFFFFFFF, 0x994C68ADA6E1FFFF, 0xFAF0A29A781974CE, 0xFE3AC5904A0DEA65, 0x02BDBE6326507D01, 0x8C15B0036936E792, 0x255946A8869BC6 }; const uint64_t R2[NWORDS_FIELD] = { 0x46E4E8A0C7549CBD, 0xCB993B5943E89EA5, 0x545AC09F2F1B55C8, 0x1ADB99DDACAA06EC, 0x87994B8955D8B8D4, 0x2CC2EA622F9E57C8, 0x2780B5F2DAF1003C, 0x1691676B8674B8 }; const uint64_t pp[NWORDS_FIELD] = { 0x01, 0x00, 0x00, 0x00 }; void fp_set(digit_t* x, const digit_t val) { // Set field element x = val, where val has wordsize x[0] = val; for (unsigned int i = 1; i < NWORDS_FIELD; i++) { x[i] = 0; } } bool fp_is_equal(const digit_t* a, const digit_t* b) { // Compare two field elements in constant time // Returns 1 (true) if a=b, 0 (false) otherwise digit_t r = 0; for (unsigned int i = 0; i < NWORDS_FIELD; i++) r |= a[i] ^ b[i]; return (bool)is_digit_zero_ct(r); } bool fp_is_zero(const digit_t* a) { // Is a field element zero? // Returns 1 (true) if a=0, 0 (false) otherwise digit_t r = 0; for (unsigned int i = 0; i < NWORDS_FIELD; i++) r |= a[i] ^ 0; return (bool)is_digit_zero_ct(r); } void fp_copy(digit_t* out, const digit_t* a) { memcpy(out, a, NWORDS_FIELD*RADIX/8); } void fp_neg(digit_t* out, const digit_t* a) { // Modular negation, out = -a mod p // Input: a in [0, p-1] // Output: out in [0, p-1] unsigned int i, borrow = 0; for (i = 0; i < NWORDS_FIELD; i++) { SUBC(out[i], borrow, ((digit_t*)p)[i], a[i], borrow); } fp_sub(out, out, (digit_t*)p); } void MUL(digit_t* out, const digit_t a, const digit_t b) { // Digit multiplication, digit*digit -> 2-digit result // Inputs: a, b in [0, 2^w-1], where w is the computer wordsize // Output: 0 < out < 2^(2w)-1 register digit_t al, ah, bl, bh, temp; digit_t albl, albh, ahbl, ahbh, res1, res2, res3, carry; digit_t mask_low = (digit_t)(-1) >> (sizeof(digit_t)*4), mask_high = (digit_t)(-1) << (sizeof(digit_t)*4); al = a & mask_low; // Low part ah = a >> (sizeof(digit_t)*4); // High part bl = b & mask_low; bh = b >> (sizeof(digit_t)*4); albl = al * bl; albh = al * bh; ahbl = ah * bl; ahbh = ah * bh; out[0] = albl & mask_low; // out00 res1 = albl >> (sizeof(digit_t)*4); res2 = ahbl & mask_low; res3 = albh & mask_low; temp = res1 + res2 + res3; carry = temp >> (sizeof(digit_t)*4); out[0] ^= temp << (sizeof(digit_t)*4); // out01 res1 = ahbl >> (sizeof(digit_t)*4); res2 = albh >> (sizeof(digit_t)*4); res3 = ahbh & mask_low; temp = res1 + res2 + res3 + carry; out[1] = temp & mask_low; // out10 carry = temp & mask_high; out[1] ^= (ahbh & mask_high) + carry; // out11 } digit_t mp_shiftr(digit_t* x, const unsigned int shift, const unsigned int nwords) { // Multiprecision right shift digit_t bit_out = x[0] & 1; for (unsigned int i = 0; i < nwords-1; i++) { SHIFTR(x[i+1], x[i], shift, x[i], RADIX); } x[nwords-1] >>= shift; return bit_out; } void mp_shiftl(digit_t* x, const unsigned int shift, const unsigned int nwords) { // Multiprecision left shift for (int i = nwords-1; i > 0; i--) { SHIFTL(x[i], x[i-1], shift, x[i], RADIX); } x[0] <<= shift; } static void fp_exp3div4(digit_t* out, const digit_t* a) { // Fixed exponentiation out = a^((p-3)/4) mod p // Input: a in [0, p-1] // Output: out in [0, p-1] // Requirement: p = 3(mod 4) fp_t p_t, acc; digit_t bit; memcpy((digit_t*)p_t, (digit_t*)p, NWORDS_FIELD*RADIX/8); memcpy((digit_t*)acc, (digit_t*)a, NWORDS_FIELD*RADIX/8); mp_shiftr(p_t, 1, NWORDS_FIELD); mp_shiftr(p_t, 1, NWORDS_FIELD); fp_set(out, 1); fp_tomont(out, out); for (int i = 0; i < NWORDS_FIELD*RADIX-2; i++) { bit = p_t[0] & 1; mp_shiftr(p_t, 1, NWORDS_FIELD); if (bit == 1) { fp_mul(out, out, acc); } fp_sqr(acc, acc); } } void fp_inv(digit_t* a) { // Modular inversion, out = x^-1*R mod p, where R = 2^(w*nwords), w is the computer wordsize and nwords is the number of words to represent p // Input: a=xR in [0, p-1] // Output: out in [0, p-1]. It outputs 0 if the input does not have an inverse // Requirement: Ceiling(Log(p)) < w*nwords fp_t t; fp_exp3div4(t, a); fp_sqr(t, t); fp_sqr(t, t); fp_mul(a, t, a); // a^(p-2) } bool fp_is_square(const digit_t* a) { // Is field element a square? // Output: out = 0 (false), 1 (true) fp_t t, one; fp_exp3div4(t, a); fp_sqr(t, t); fp_mul(t, t, a); // a^((p-1)/2) fp_frommont(t, t); fp_set(one, 1); return fp_is_equal(t, one); } void fp_sqrt(digit_t* a) { // Square root computation, out = a^((p+1)/4) mod p fp_t t; fp_exp3div4(t, a); fp_mul(a, t, a); // a^((p+1)/4) }