325 lines
5.6 KiB
C
325 lines
5.6 KiB
C
/* Arithmetic mod p = 2^255-19
|
|
* Daniel Beer <dlbeer@gmail.com>, 5 Jan 2014
|
|
*
|
|
* This file is in the public domain.
|
|
*/
|
|
|
|
#include "f25519.h"
|
|
|
|
const uint8_t f25519_zero[F25519_SIZE] = {0};
|
|
const uint8_t f25519_one[F25519_SIZE] = {1};
|
|
|
|
void f25519_load(uint8_t *x, uint32_t c)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < sizeof(c); i++) {
|
|
x[i] = c;
|
|
c >>= 8;
|
|
}
|
|
|
|
for (; i < F25519_SIZE; i++)
|
|
x[i] = 0;
|
|
}
|
|
|
|
void f25519_normalize(uint8_t *x)
|
|
{
|
|
uint8_t minusp[F25519_SIZE];
|
|
uint16_t c;
|
|
int i;
|
|
|
|
/* Reduce using 2^255 = 19 mod p */
|
|
c = (x[31] >> 7) * 19;
|
|
x[31] &= 127;
|
|
|
|
for (i = 0; i < F25519_SIZE; i++) {
|
|
c += x[i];
|
|
x[i] = c;
|
|
c >>= 8;
|
|
}
|
|
|
|
/* The number is now less than 2^255 + 18, and therefore less than
|
|
* 2p. Try subtracting p, and conditionally load the subtracted
|
|
* value if underflow did not occur.
|
|
*/
|
|
c = 19;
|
|
|
|
for (i = 0; i + 1 < F25519_SIZE; i++) {
|
|
c += x[i];
|
|
minusp[i] = c;
|
|
c >>= 8;
|
|
}
|
|
|
|
c += ((uint16_t)x[i]) - 128;
|
|
minusp[31] = c;
|
|
|
|
/* Load x-p if no underflow */
|
|
f25519_select(x, minusp, x, (c >> 15) & 1);
|
|
}
|
|
|
|
uint8_t f25519_eq(const uint8_t *x, const uint8_t *y)
|
|
{
|
|
uint8_t sum = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < F25519_SIZE; i++)
|
|
sum |= x[i] ^ y[i];
|
|
|
|
sum |= (sum >> 4);
|
|
sum |= (sum >> 2);
|
|
sum |= (sum >> 1);
|
|
|
|
return (sum ^ 1) & 1;
|
|
}
|
|
|
|
void f25519_select(uint8_t *dst,
|
|
const uint8_t *zero, const uint8_t *one,
|
|
uint8_t condition)
|
|
{
|
|
const uint8_t mask = -condition;
|
|
int i;
|
|
|
|
for (i = 0; i < F25519_SIZE; i++)
|
|
dst[i] = zero[i] ^ (mask & (one[i] ^ zero[i]));
|
|
}
|
|
|
|
void f25519_add(uint8_t *r, const uint8_t *a, const uint8_t *b)
|
|
{
|
|
uint16_t c = 0;
|
|
int i;
|
|
|
|
/* Add */
|
|
for (i = 0; i < F25519_SIZE; i++) {
|
|
c >>= 8;
|
|
c += ((uint16_t)a[i]) + ((uint16_t)b[i]);
|
|
r[i] = c;
|
|
}
|
|
|
|
/* Reduce with 2^255 = 19 mod p */
|
|
r[31] &= 127;
|
|
c = (c >> 7) * 19;
|
|
|
|
for (i = 0; i < F25519_SIZE; i++) {
|
|
c += r[i];
|
|
r[i] = c;
|
|
c >>= 8;
|
|
}
|
|
}
|
|
|
|
void f25519_sub(uint8_t *r, const uint8_t *a, const uint8_t *b)
|
|
{
|
|
uint32_t c = 0;
|
|
int i;
|
|
|
|
/* Calculate a + 2p - b, to avoid underflow */
|
|
c = 218;
|
|
for (i = 0; i + 1 < F25519_SIZE; i++) {
|
|
c += 65280 + ((uint32_t)a[i]) - ((uint32_t)b[i]);
|
|
r[i] = c;
|
|
c >>= 8;
|
|
}
|
|
|
|
c += ((uint32_t)a[31]) - ((uint32_t)b[31]);
|
|
r[31] = c & 127;
|
|
c = (c >> 7) * 19;
|
|
|
|
for (i = 0; i < F25519_SIZE; i++) {
|
|
c += r[i];
|
|
r[i] = c;
|
|
c >>= 8;
|
|
}
|
|
}
|
|
|
|
void f25519_neg(uint8_t *r, const uint8_t *a)
|
|
{
|
|
uint32_t c = 0;
|
|
int i;
|
|
|
|
/* Calculate 2p - a, to avoid underflow */
|
|
c = 218;
|
|
for (i = 0; i + 1 < F25519_SIZE; i++) {
|
|
c += 65280 - ((uint32_t)a[i]);
|
|
r[i] = c;
|
|
c >>= 8;
|
|
}
|
|
|
|
c -= ((uint32_t)a[31]);
|
|
r[31] = c & 127;
|
|
c = (c >> 7) * 19;
|
|
|
|
for (i = 0; i < F25519_SIZE; i++) {
|
|
c += r[i];
|
|
r[i] = c;
|
|
c >>= 8;
|
|
}
|
|
}
|
|
|
|
void f25519_mul__distinct(uint8_t *r, const uint8_t *a, const uint8_t *b)
|
|
{
|
|
uint32_t c = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < F25519_SIZE; i++) {
|
|
int j;
|
|
|
|
c >>= 8;
|
|
for (j = 0; j <= i; j++)
|
|
c += ((uint32_t)a[j]) * ((uint32_t)b[i - j]);
|
|
|
|
for (; j < F25519_SIZE; j++)
|
|
c += ((uint32_t)a[j]) *
|
|
((uint32_t)b[i + F25519_SIZE - j]) * 38;
|
|
|
|
r[i] = c;
|
|
}
|
|
|
|
r[31] &= 127;
|
|
c = (c >> 7) * 19;
|
|
|
|
for (i = 0; i < F25519_SIZE; i++) {
|
|
c += r[i];
|
|
r[i] = c;
|
|
c >>= 8;
|
|
}
|
|
}
|
|
|
|
void f25519_mul(uint8_t *r, const uint8_t *a, const uint8_t *b)
|
|
{
|
|
uint8_t tmp[F25519_SIZE];
|
|
|
|
f25519_mul__distinct(tmp, a, b);
|
|
f25519_copy(r, tmp);
|
|
}
|
|
|
|
void f25519_mul_c(uint8_t *r, const uint8_t *a, uint32_t b)
|
|
{
|
|
uint32_t c = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < F25519_SIZE; i++) {
|
|
c >>= 8;
|
|
c += b * ((uint32_t)a[i]);
|
|
r[i] = c;
|
|
}
|
|
|
|
r[31] &= 127;
|
|
c >>= 7;
|
|
c *= 19;
|
|
|
|
for (i = 0; i < F25519_SIZE; i++) {
|
|
c += r[i];
|
|
r[i] = c;
|
|
c >>= 8;
|
|
}
|
|
}
|
|
|
|
void f25519_inv__distinct(uint8_t *r, const uint8_t *x)
|
|
{
|
|
uint8_t s[F25519_SIZE];
|
|
int i;
|
|
|
|
/* This is a prime field, so by Fermat's little theorem:
|
|
*
|
|
* x^(p-1) = 1 mod p
|
|
*
|
|
* Therefore, raise to (p-2) = 2^255-21 to get a multiplicative
|
|
* inverse.
|
|
*
|
|
* This is a 255-bit binary number with the digits:
|
|
*
|
|
* 11111111... 01011
|
|
*
|
|
* We compute the result by the usual binary chain, but
|
|
* alternate between keeping the accumulator in r and s, so as
|
|
* to avoid copying temporaries.
|
|
*/
|
|
|
|
/* 1 1 */
|
|
f25519_mul__distinct(s, x, x);
|
|
f25519_mul__distinct(r, s, x);
|
|
|
|
/* 1 x 248 */
|
|
for (i = 0; i < 248; i++) {
|
|
f25519_mul__distinct(s, r, r);
|
|
f25519_mul__distinct(r, s, x);
|
|
}
|
|
|
|
/* 0 */
|
|
f25519_mul__distinct(s, r, r);
|
|
|
|
/* 1 */
|
|
f25519_mul__distinct(r, s, s);
|
|
f25519_mul__distinct(s, r, x);
|
|
|
|
/* 0 */
|
|
f25519_mul__distinct(r, s, s);
|
|
|
|
/* 1 */
|
|
f25519_mul__distinct(s, r, r);
|
|
f25519_mul__distinct(r, s, x);
|
|
|
|
/* 1 */
|
|
f25519_mul__distinct(s, r, r);
|
|
f25519_mul__distinct(r, s, x);
|
|
}
|
|
|
|
void f25519_inv(uint8_t *r, const uint8_t *x)
|
|
{
|
|
uint8_t tmp[F25519_SIZE];
|
|
|
|
f25519_inv__distinct(tmp, x);
|
|
f25519_copy(r, tmp);
|
|
}
|
|
|
|
/* Raise x to the power of (p-5)/8 = 2^252-3, using s for temporary
|
|
* storage.
|
|
*/
|
|
static void exp2523(uint8_t *r, const uint8_t *x, uint8_t *s)
|
|
{
|
|
int i;
|
|
|
|
/* This number is a 252-bit number with the binary expansion:
|
|
*
|
|
* 111111... 01
|
|
*/
|
|
|
|
/* 1 1 */
|
|
f25519_mul__distinct(r, x, x);
|
|
f25519_mul__distinct(s, r, x);
|
|
|
|
/* 1 x 248 */
|
|
for (i = 0; i < 248; i++) {
|
|
f25519_mul__distinct(r, s, s);
|
|
f25519_mul__distinct(s, r, x);
|
|
}
|
|
|
|
/* 0 */
|
|
f25519_mul__distinct(r, s, s);
|
|
|
|
/* 1 */
|
|
f25519_mul__distinct(s, r, r);
|
|
f25519_mul__distinct(r, s, x);
|
|
}
|
|
|
|
void f25519_sqrt(uint8_t *r, const uint8_t *a)
|
|
{
|
|
uint8_t v[F25519_SIZE];
|
|
uint8_t i[F25519_SIZE];
|
|
uint8_t x[F25519_SIZE];
|
|
uint8_t y[F25519_SIZE];
|
|
|
|
/* v = (2a)^((p-5)/8) [x = 2a] */
|
|
f25519_mul_c(x, a, 2);
|
|
exp2523(v, x, y);
|
|
|
|
/* i = 2av^2 - 1 */
|
|
f25519_mul__distinct(y, v, v);
|
|
f25519_mul__distinct(i, x, y);
|
|
f25519_load(y, 1);
|
|
f25519_sub(i, i, y);
|
|
|
|
/* r = avi */
|
|
f25519_mul__distinct(x, v, a);
|
|
f25519_mul__distinct(r, x, i);
|
|
}
|