1069 lines
30 KiB
C
1069 lines
30 KiB
C
// Ed25519: high-speed high-security signatures
|
|
|
|
// Contributors (alphabetical order)
|
|
// Daniel J. Bernstein, University of Illinois at Chicago
|
|
// Niels Duif, Technische Universiteit Eindhoven
|
|
// Tanja Lange, Technische Universiteit Eindhoven
|
|
// Peter Schwabe, National Taiwan University
|
|
// Bo-Yin Yang, Academia Sinica
|
|
|
|
// The Ed25519 sources were taken from the crypto_sign/ed25519 subdirectory of the SUPERCOP benchmarking tool.
|
|
// The Ed25519 software is in the public domain.
|
|
|
|
// this file (crypto_tools.h) contains fe25519.c, fe25519.h, ge25519.c, ge25519.h, sc25519.c and sc25519.h.
|
|
// ge25519_base.data is kept as a separate file and keypair.c, open.c and sign.c got merged into crypto.cpp.
|
|
|
|
// sry for just throwing this all in here...
|
|
// I'm cleaning this up later, I promise ;)
|
|
|
|
|
|
/////////////////////////////////////////// fe25519.h ////////////////////////////////////
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t v[32];
|
|
}
|
|
fe25519;
|
|
|
|
void fe25519_freeze(fe25519 *r);
|
|
void fe25519_unpack(fe25519 *r, const unsigned char x[32]);
|
|
void fe25519_pack(unsigned char r[32], const fe25519 *x);
|
|
int fe25519_iszero(const fe25519 *x);
|
|
int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y);
|
|
void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b);
|
|
void fe25519_setone(fe25519 *r);
|
|
void fe25519_setzero(fe25519 *r);
|
|
void fe25519_neg(fe25519 *r, const fe25519 *x);
|
|
unsigned char fe25519_getparity(const fe25519 *x);
|
|
void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y);
|
|
void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y);
|
|
void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y);
|
|
void fe25519_square(fe25519 *r, const fe25519 *x);
|
|
void fe25519_invert(fe25519 *r, const fe25519 *x);
|
|
void fe25519_pow2523(fe25519 *r, const fe25519 *x);
|
|
|
|
/////////////////////////////////////////// fe25519.c ////////////////////////////////////
|
|
|
|
static uint32_t equal(uint32_t a,uint32_t b) /* 16-bit inputs */
|
|
{
|
|
uint32_t x = a ^ b; /* 0: yes; 1..65535: no */
|
|
x -= 1; /* 4294967295: yes; 0..65534: no */
|
|
x >>= 31; /* 1: yes; 0: no */
|
|
return x;
|
|
}
|
|
|
|
static uint32_t ge(uint32_t a,uint32_t b) /* 16-bit inputs */
|
|
{
|
|
unsigned int x = a;
|
|
x -= (unsigned int) b; /* 0..65535: yes; 4294901761..4294967295: no */
|
|
x >>= 31; /* 0: yes; 1: no */
|
|
x ^= 1; /* 1: yes; 0: no */
|
|
return x;
|
|
}
|
|
|
|
static uint32_t times19(uint32_t a)
|
|
{
|
|
return (a << 4) + (a << 1) + a;
|
|
}
|
|
|
|
static uint32_t times38(uint32_t a)
|
|
{
|
|
return (a << 5) + (a << 2) + (a << 1);
|
|
}
|
|
|
|
static void reduce_add_sub(fe25519 *r)
|
|
{
|
|
uint32_t t;
|
|
int i,rep;
|
|
|
|
for(rep=0;rep<4;rep++)
|
|
{
|
|
t = r->v[31] >> 7;
|
|
r->v[31] &= 127;
|
|
t = times19(t);
|
|
r->v[0] += t;
|
|
for(i=0;i<31;i++)
|
|
{
|
|
t = r->v[i] >> 8;
|
|
r->v[i+1] += t;
|
|
r->v[i] &= 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void reduce_mul(fe25519 *r)
|
|
{
|
|
uint32_t t;
|
|
int i,rep;
|
|
|
|
for(rep=0;rep<2;rep++)
|
|
{
|
|
t = r->v[31] >> 7;
|
|
r->v[31] &= 127;
|
|
t = times19(t);
|
|
r->v[0] += t;
|
|
for(i=0;i<31;i++)
|
|
{
|
|
t = r->v[i] >> 8;
|
|
r->v[i+1] += t;
|
|
r->v[i] &= 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* reduction modulo 2^255-19 */
|
|
void fe25519_freeze(fe25519 *r)
|
|
{
|
|
int i;
|
|
uint32_t m = equal(r->v[31],127);
|
|
for(i=30;i>0;i--)
|
|
m &= equal(r->v[i],255);
|
|
m &= ge(r->v[0],237);
|
|
|
|
m = (uint32_t) -int(m);
|
|
|
|
r->v[31] -= m&127;
|
|
for(i=30;i>0;i--)
|
|
r->v[i] -= m&255;
|
|
r->v[0] -= m&237;
|
|
}
|
|
|
|
void fe25519_unpack(fe25519 *r, const unsigned char x[32])
|
|
{
|
|
int i;
|
|
for(i=0;i<32;i++) r->v[i] = x[i];
|
|
r->v[31] &= 127;
|
|
}
|
|
|
|
/* Assumes input x being reduced below 2^255 */
|
|
void fe25519_pack(unsigned char r[32], const fe25519 *x)
|
|
{
|
|
int i;
|
|
fe25519 y = *x;
|
|
fe25519_freeze(&y);
|
|
for(i=0;i<32;i++)
|
|
r[i] = y.v[i];
|
|
}
|
|
|
|
int fe25519_iszero(const fe25519 *x)
|
|
{
|
|
int i;
|
|
int r;
|
|
fe25519 t = *x;
|
|
fe25519_freeze(&t);
|
|
r = equal(t.v[0],0);
|
|
for(i=1;i<32;i++)
|
|
r &= equal(t.v[i],0);
|
|
return r;
|
|
}
|
|
|
|
int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y)
|
|
{
|
|
int i;
|
|
fe25519 t1 = *x;
|
|
fe25519 t2 = *y;
|
|
fe25519_freeze(&t1);
|
|
fe25519_freeze(&t2);
|
|
for(i=0;i<32;i++)
|
|
if(t1.v[i] != t2.v[i]) return 0;
|
|
return 1;
|
|
}
|
|
|
|
void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b)
|
|
{
|
|
int i;
|
|
uint32_t mask = b;
|
|
mask = (uint32_t) -int(mask);
|
|
for(i=0;i<32;i++) r->v[i] ^= mask & (x->v[i] ^ r->v[i]);
|
|
}
|
|
|
|
unsigned char fe25519_getparity(const fe25519 *x)
|
|
{
|
|
fe25519 t = *x;
|
|
fe25519_freeze(&t);
|
|
return t.v[0] & 1;
|
|
}
|
|
|
|
void fe25519_setone(fe25519 *r)
|
|
{
|
|
int i;
|
|
r->v[0] = 1;
|
|
for(i=1;i<32;i++) r->v[i]=0;
|
|
}
|
|
|
|
void fe25519_setzero(fe25519 *r)
|
|
{
|
|
int i;
|
|
for(i=0;i<32;i++) r->v[i]=0;
|
|
}
|
|
|
|
void fe25519_neg(fe25519 *r, const fe25519 *x)
|
|
{
|
|
fe25519 t;
|
|
int i;
|
|
for(i=0;i<32;i++) t.v[i]=x->v[i];
|
|
fe25519_setzero(r);
|
|
fe25519_sub(r, r, &t);
|
|
}
|
|
|
|
void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y)
|
|
{
|
|
int i;
|
|
for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i];
|
|
reduce_add_sub(r);
|
|
}
|
|
|
|
void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y)
|
|
{
|
|
int i;
|
|
uint32_t t[32];
|
|
t[0] = x->v[0] + 0x1da;
|
|
t[31] = x->v[31] + 0xfe;
|
|
for(i=1;i<31;i++) t[i] = x->v[i] + 0x1fe;
|
|
for(i=0;i<32;i++) r->v[i] = t[i] - y->v[i];
|
|
reduce_add_sub(r);
|
|
}
|
|
|
|
void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y)
|
|
{
|
|
int i,j;
|
|
uint32_t t[63];
|
|
for(i=0;i<63;i++)t[i] = 0;
|
|
|
|
for(i=0;i<32;i++)
|
|
for(j=0;j<32;j++)
|
|
t[i+j] += x->v[i] * y->v[j];
|
|
|
|
for(i=32;i<63;i++)
|
|
r->v[i-32] = t[i-32] + times38(t[i]);
|
|
r->v[31] = t[31]; /* result now in r[0]...r[31] */
|
|
|
|
reduce_mul(r);
|
|
}
|
|
|
|
void fe25519_square(fe25519 *r, const fe25519 *x)
|
|
{
|
|
fe25519_mul(r, x, x);
|
|
}
|
|
|
|
void fe25519_invert(fe25519 *r, const fe25519 *x)
|
|
{
|
|
fe25519 z2;
|
|
fe25519 z9;
|
|
fe25519 z11;
|
|
fe25519 z2_5_0;
|
|
fe25519 z2_10_0;
|
|
fe25519 z2_20_0;
|
|
fe25519 z2_50_0;
|
|
fe25519 z2_100_0;
|
|
fe25519 t0;
|
|
fe25519 t1;
|
|
int i;
|
|
|
|
/* 2 */ fe25519_square(&z2,x);
|
|
/* 4 */ fe25519_square(&t1,&z2);
|
|
/* 8 */ fe25519_square(&t0,&t1);
|
|
/* 9 */ fe25519_mul(&z9,&t0,x);
|
|
/* 11 */ fe25519_mul(&z11,&z9,&z2);
|
|
/* 22 */ fe25519_square(&t0,&z11);
|
|
/* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t0,&z9);
|
|
|
|
/* 2^6 - 2^1 */ fe25519_square(&t0,&z2_5_0);
|
|
/* 2^7 - 2^2 */ fe25519_square(&t1,&t0);
|
|
/* 2^8 - 2^3 */ fe25519_square(&t0,&t1);
|
|
/* 2^9 - 2^4 */ fe25519_square(&t1,&t0);
|
|
/* 2^10 - 2^5 */ fe25519_square(&t0,&t1);
|
|
/* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t0,&z2_5_0);
|
|
|
|
/* 2^11 - 2^1 */ fe25519_square(&t0,&z2_10_0);
|
|
/* 2^12 - 2^2 */ fe25519_square(&t1,&t0);
|
|
/* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); }
|
|
/* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t1,&z2_10_0);
|
|
|
|
/* 2^21 - 2^1 */ fe25519_square(&t0,&z2_20_0);
|
|
/* 2^22 - 2^2 */ fe25519_square(&t1,&t0);
|
|
/* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); }
|
|
/* 2^40 - 2^0 */ fe25519_mul(&t0,&t1,&z2_20_0);
|
|
|
|
/* 2^41 - 2^1 */ fe25519_square(&t1,&t0);
|
|
/* 2^42 - 2^2 */ fe25519_square(&t0,&t1);
|
|
/* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fe25519_square(&t1,&t0); fe25519_square(&t0,&t1); }
|
|
/* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t0,&z2_10_0);
|
|
|
|
/* 2^51 - 2^1 */ fe25519_square(&t0,&z2_50_0);
|
|
/* 2^52 - 2^2 */ fe25519_square(&t1,&t0);
|
|
/* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); }
|
|
/* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t1,&z2_50_0);
|
|
|
|
/* 2^101 - 2^1 */ fe25519_square(&t1,&z2_100_0);
|
|
/* 2^102 - 2^2 */ fe25519_square(&t0,&t1);
|
|
/* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fe25519_square(&t1,&t0); fe25519_square(&t0,&t1); }
|
|
/* 2^200 - 2^0 */ fe25519_mul(&t1,&t0,&z2_100_0);
|
|
|
|
/* 2^201 - 2^1 */ fe25519_square(&t0,&t1);
|
|
/* 2^202 - 2^2 */ fe25519_square(&t1,&t0);
|
|
/* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); }
|
|
/* 2^250 - 2^0 */ fe25519_mul(&t0,&t1,&z2_50_0);
|
|
|
|
/* 2^251 - 2^1 */ fe25519_square(&t1,&t0);
|
|
/* 2^252 - 2^2 */ fe25519_square(&t0,&t1);
|
|
/* 2^253 - 2^3 */ fe25519_square(&t1,&t0);
|
|
/* 2^254 - 2^4 */ fe25519_square(&t0,&t1);
|
|
/* 2^255 - 2^5 */ fe25519_square(&t1,&t0);
|
|
/* 2^255 - 21 */ fe25519_mul(r,&t1,&z11);
|
|
}
|
|
|
|
void fe25519_pow2523(fe25519 *r, const fe25519 *x)
|
|
{
|
|
fe25519 z2;
|
|
fe25519 z9;
|
|
fe25519 z11;
|
|
fe25519 z2_5_0;
|
|
fe25519 z2_10_0;
|
|
fe25519 z2_20_0;
|
|
fe25519 z2_50_0;
|
|
fe25519 z2_100_0;
|
|
fe25519 t;
|
|
int i;
|
|
|
|
/* 2 */ fe25519_square(&z2,x);
|
|
/* 4 */ fe25519_square(&t,&z2);
|
|
/* 8 */ fe25519_square(&t,&t);
|
|
/* 9 */ fe25519_mul(&z9,&t,x);
|
|
/* 11 */ fe25519_mul(&z11,&z9,&z2);
|
|
/* 22 */ fe25519_square(&t,&z11);
|
|
/* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t,&z9);
|
|
|
|
/* 2^6 - 2^1 */ fe25519_square(&t,&z2_5_0);
|
|
/* 2^10 - 2^5 */ for (i = 1;i < 5;i++) { fe25519_square(&t,&t); }
|
|
/* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t,&z2_5_0);
|
|
|
|
/* 2^11 - 2^1 */ fe25519_square(&t,&z2_10_0);
|
|
/* 2^20 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); }
|
|
/* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t,&z2_10_0);
|
|
|
|
/* 2^21 - 2^1 */ fe25519_square(&t,&z2_20_0);
|
|
/* 2^40 - 2^20 */ for (i = 1;i < 20;i++) { fe25519_square(&t,&t); }
|
|
/* 2^40 - 2^0 */ fe25519_mul(&t,&t,&z2_20_0);
|
|
|
|
/* 2^41 - 2^1 */ fe25519_square(&t,&t);
|
|
/* 2^50 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); }
|
|
/* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t,&z2_10_0);
|
|
|
|
/* 2^51 - 2^1 */ fe25519_square(&t,&z2_50_0);
|
|
/* 2^100 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); }
|
|
/* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t,&z2_50_0);
|
|
|
|
/* 2^101 - 2^1 */ fe25519_square(&t,&z2_100_0);
|
|
/* 2^200 - 2^100 */ for (i = 1;i < 100;i++) { fe25519_square(&t,&t); }
|
|
/* 2^200 - 2^0 */ fe25519_mul(&t,&t,&z2_100_0);
|
|
|
|
/* 2^201 - 2^1 */ fe25519_square(&t,&t);
|
|
/* 2^250 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); }
|
|
/* 2^250 - 2^0 */ fe25519_mul(&t,&t,&z2_50_0);
|
|
|
|
/* 2^251 - 2^1 */ fe25519_square(&t,&t);
|
|
/* 2^252 - 2^2 */ fe25519_square(&t,&t);
|
|
/* 2^252 - 3 */ fe25519_mul(r,&t,x);
|
|
}
|
|
|
|
/////////////////////////////////////////// sc25519.h ////////////////////////////////////
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t v[32];
|
|
}
|
|
sc25519;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t v[16];
|
|
}
|
|
shortsc25519;
|
|
|
|
void sc25519_from32bytes(sc25519 *r, const unsigned char x[32]);
|
|
void shortsc25519_from16bytes(shortsc25519 *r, const unsigned char x[16]);
|
|
void sc25519_from64bytes(sc25519 *r, const unsigned char x[64]);
|
|
void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x);
|
|
void sc25519_to32bytes(unsigned char r[32], const sc25519 *x);
|
|
int sc25519_iszero_vartime(const sc25519 *x);
|
|
int sc25519_isshort_vartime(const sc25519 *x);
|
|
int sc25519_lt_vartime(const sc25519 *x, const sc25519 *y);
|
|
void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y);
|
|
void sc25519_sub_nored(sc25519 *r, const sc25519 *x, const sc25519 *y);
|
|
void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y);
|
|
void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y);
|
|
|
|
/* Convert s into a representation of the form \sum_{i=0}^{84}r[i]2^3
|
|
* with r[i] in {-4,...,3}
|
|
*/
|
|
void sc25519_window3(signed char r[85], const sc25519 *s);
|
|
|
|
/* Convert s into a representation of the form \sum_{i=0}^{50}r[i]2^5
|
|
* with r[i] in {-16,...,15}
|
|
*/
|
|
void sc25519_window5(signed char r[51], const sc25519 *s);
|
|
void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2);
|
|
|
|
/////////////////////////////////////////// sc25519.c ////////////////////////////////////
|
|
|
|
/*Arithmetic modulo the group order m = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 */
|
|
|
|
static const uint32_t m[32] = {0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, 0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
|
|
|
|
static const uint32_t mu[33] = {0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, 0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21,
|
|
0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F};
|
|
|
|
static uint32_t lt(uint32_t a,uint32_t b) /* 16-bit inputs */
|
|
{
|
|
unsigned int x = a;
|
|
x -= (unsigned int) b; /* 0..65535: no; 4294901761..4294967295: yes */
|
|
x >>= 31; /* 0: no; 1: yes */
|
|
return x;
|
|
}
|
|
|
|
/* Reduce coefficients of r before calling reduce_add_sub */
|
|
static void reduce_add_sub(sc25519 *r)
|
|
{
|
|
uint32_t pb = 0;
|
|
uint32_t b;
|
|
uint32_t mask;
|
|
int i;
|
|
unsigned char t[32];
|
|
|
|
for(i=0;i<32;i++)
|
|
{
|
|
pb += m[i];
|
|
b = lt(r->v[i],pb);
|
|
t[i] = r->v[i]-pb+(b<<8);
|
|
pb = b;
|
|
}
|
|
mask = b - 1;
|
|
for(i=0;i<32;i++)
|
|
r->v[i] ^= mask & (r->v[i] ^ t[i]);
|
|
}
|
|
|
|
/* Reduce coefficients of x before calling barrett_reduce */
|
|
static void barrett_reduce(sc25519 *r, const uint32_t x[64])
|
|
{
|
|
/* See HAC, Alg. 14.42 */
|
|
int i,j;
|
|
uint32_t q2[66];
|
|
uint32_t *q3 = q2 + 33;
|
|
uint32_t r1[33];
|
|
uint32_t r2[33];
|
|
uint32_t carry;
|
|
uint32_t pb = 0;
|
|
uint32_t b;
|
|
|
|
for (i = 0;i < 66;++i) q2[i] = 0;
|
|
for (i = 0;i < 33;++i) r2[i] = 0;
|
|
|
|
for(i=0;i<33;i++)
|
|
for(j=0;j<33;j++)
|
|
if(i+j >= 31) q2[i+j] += mu[i]*x[j+31];
|
|
carry = q2[31] >> 8;
|
|
q2[32] += carry;
|
|
carry = q2[32] >> 8;
|
|
q2[33] += carry;
|
|
|
|
for(i=0;i<33;i++)r1[i] = x[i];
|
|
for(i=0;i<32;i++)
|
|
for(j=0;j<33;j++)
|
|
if(i+j < 33) r2[i+j] += m[i]*q3[j];
|
|
|
|
for(i=0;i<32;i++)
|
|
{
|
|
carry = r2[i] >> 8;
|
|
r2[i+1] += carry;
|
|
r2[i] &= 0xff;
|
|
}
|
|
|
|
for(i=0;i<32;i++)
|
|
{
|
|
pb += r2[i];
|
|
b = lt(r1[i],pb);
|
|
r->v[i] = r1[i]-pb+(b<<8);
|
|
pb = b;
|
|
}
|
|
|
|
/* XXX: Can it really happen that r<0?, See HAC, Alg 14.42, Step 3
|
|
* If so: Handle it here!
|
|
*/
|
|
|
|
reduce_add_sub(r);
|
|
reduce_add_sub(r);
|
|
}
|
|
|
|
void sc25519_from32bytes(sc25519 *r, const unsigned char x[32])
|
|
{
|
|
int i;
|
|
uint32_t t[64];
|
|
for(i=0;i<32;i++) t[i] = x[i];
|
|
for(i=32;i<64;++i) t[i] = 0;
|
|
barrett_reduce(r, t);
|
|
}
|
|
|
|
void shortsc25519_from16bytes(shortsc25519 *r, const unsigned char x[16])
|
|
{
|
|
int i;
|
|
for(i=0;i<16;i++) r->v[i] = x[i];
|
|
}
|
|
|
|
void sc25519_from64bytes(sc25519 *r, const unsigned char x[64])
|
|
{
|
|
int i;
|
|
uint32_t t[64];
|
|
for(i=0;i<64;i++) t[i] = x[i];
|
|
barrett_reduce(r, t);
|
|
}
|
|
|
|
void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x)
|
|
{
|
|
int i;
|
|
for(i=0;i<16;i++)
|
|
r->v[i] = x->v[i];
|
|
for(i=0;i<16;i++)
|
|
r->v[16+i] = 0;
|
|
}
|
|
|
|
void sc25519_to32bytes(unsigned char r[32], const sc25519 *x)
|
|
{
|
|
int i;
|
|
for(i=0;i<32;i++) r[i] = x->v[i];
|
|
}
|
|
|
|
int sc25519_iszero_vartime(const sc25519 *x)
|
|
{
|
|
int i;
|
|
for(i=0;i<32;i++)
|
|
if(x->v[i] != 0) return 0;
|
|
return 1;
|
|
}
|
|
|
|
int sc25519_isshort_vartime(const sc25519 *x)
|
|
{
|
|
int i;
|
|
for(i=31;i>15;i--)
|
|
if(x->v[i] != 0) return 0;
|
|
return 1;
|
|
}
|
|
|
|
int sc25519_lt_vartime(const sc25519 *x, const sc25519 *y)
|
|
{
|
|
int i;
|
|
for(i=31;i>=0;i--)
|
|
{
|
|
if(x->v[i] < y->v[i]) return 1;
|
|
if(x->v[i] > y->v[i]) return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y)
|
|
{
|
|
int i, carry;
|
|
for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i];
|
|
for(i=0;i<31;i++)
|
|
{
|
|
carry = r->v[i] >> 8;
|
|
r->v[i+1] += carry;
|
|
r->v[i] &= 0xff;
|
|
}
|
|
reduce_add_sub(r);
|
|
}
|
|
|
|
void sc25519_sub_nored(sc25519 *r, const sc25519 *x, const sc25519 *y)
|
|
{
|
|
uint32_t b = 0;
|
|
uint32_t t;
|
|
int i;
|
|
for(i=0;i<32;i++)
|
|
{
|
|
t = x->v[i] - y->v[i] - b;
|
|
r->v[i] = t & 255;
|
|
b = (t >> 8) & 1;
|
|
}
|
|
}
|
|
|
|
void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y)
|
|
{
|
|
int i,j,carry;
|
|
uint32_t t[64];
|
|
for(i=0;i<64;i++)t[i] = 0;
|
|
|
|
for(i=0;i<32;i++)
|
|
for(j=0;j<32;j++)
|
|
t[i+j] += x->v[i] * y->v[j];
|
|
|
|
/* Reduce coefficients */
|
|
for(i=0;i<63;i++)
|
|
{
|
|
carry = t[i] >> 8;
|
|
t[i+1] += carry;
|
|
t[i] &= 0xff;
|
|
}
|
|
|
|
barrett_reduce(r, t);
|
|
}
|
|
|
|
void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y)
|
|
{
|
|
sc25519 t;
|
|
sc25519_from_shortsc(&t, y);
|
|
sc25519_mul(r, x, &t);
|
|
}
|
|
|
|
void sc25519_window3(signed char r[85], const sc25519 *s)
|
|
{
|
|
char carry;
|
|
int i;
|
|
for(i=0;i<10;i++)
|
|
{
|
|
r[8*i+0] = s->v[3*i+0] & 7;
|
|
r[8*i+1] = (s->v[3*i+0] >> 3) & 7;
|
|
r[8*i+2] = (s->v[3*i+0] >> 6) & 7;
|
|
r[8*i+2] ^= (s->v[3*i+1] << 2) & 7;
|
|
r[8*i+3] = (s->v[3*i+1] >> 1) & 7;
|
|
r[8*i+4] = (s->v[3*i+1] >> 4) & 7;
|
|
r[8*i+5] = (s->v[3*i+1] >> 7) & 7;
|
|
r[8*i+5] ^= (s->v[3*i+2] << 1) & 7;
|
|
r[8*i+6] = (s->v[3*i+2] >> 2) & 7;
|
|
r[8*i+7] = (s->v[3*i+2] >> 5) & 7;
|
|
}
|
|
r[8*i+0] = s->v[3*i+0] & 7;
|
|
r[8*i+1] = (s->v[3*i+0] >> 3) & 7;
|
|
r[8*i+2] = (s->v[3*i+0] >> 6) & 7;
|
|
r[8*i+2] ^= (s->v[3*i+1] << 2) & 7;
|
|
r[8*i+3] = (s->v[3*i+1] >> 1) & 7;
|
|
r[8*i+4] = (s->v[3*i+1] >> 4) & 7;
|
|
|
|
/* Making it signed */
|
|
carry = 0;
|
|
for(i=0;i<84;i++)
|
|
{
|
|
r[i] += carry;
|
|
r[i+1] += r[i] >> 3;
|
|
r[i] &= 7;
|
|
carry = r[i] >> 2;
|
|
r[i] -= carry<<3;
|
|
}
|
|
r[84] += carry;
|
|
}
|
|
|
|
void sc25519_window5(signed char r[51], const sc25519 *s)
|
|
{
|
|
char carry;
|
|
int i;
|
|
for(i=0;i<6;i++)
|
|
{
|
|
r[8*i+0] = s->v[5*i+0] & 31;
|
|
r[8*i+1] = (s->v[5*i+0] >> 5) & 31;
|
|
r[8*i+1] ^= (s->v[5*i+1] << 3) & 31;
|
|
r[8*i+2] = (s->v[5*i+1] >> 2) & 31;
|
|
r[8*i+3] = (s->v[5*i+1] >> 7) & 31;
|
|
r[8*i+3] ^= (s->v[5*i+2] << 1) & 31;
|
|
r[8*i+4] = (s->v[5*i+2] >> 4) & 31;
|
|
r[8*i+4] ^= (s->v[5*i+3] << 4) & 31;
|
|
r[8*i+5] = (s->v[5*i+3] >> 1) & 31;
|
|
r[8*i+6] = (s->v[5*i+3] >> 6) & 31;
|
|
r[8*i+6] ^= (s->v[5*i+4] << 2) & 31;
|
|
r[8*i+7] = (s->v[5*i+4] >> 3) & 31;
|
|
}
|
|
r[8*i+0] = s->v[5*i+0] & 31;
|
|
r[8*i+1] = (s->v[5*i+0] >> 5) & 31;
|
|
r[8*i+1] ^= (s->v[5*i+1] << 3) & 31;
|
|
r[8*i+2] = (s->v[5*i+1] >> 2) & 31;
|
|
|
|
/* Making it signed */
|
|
carry = 0;
|
|
for(i=0;i<50;i++)
|
|
{
|
|
r[i] += carry;
|
|
r[i+1] += r[i] >> 5;
|
|
r[i] &= 31;
|
|
carry = r[i] >> 4;
|
|
r[i] -= carry<<5;
|
|
}
|
|
r[50] += carry;
|
|
}
|
|
|
|
void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2)
|
|
{
|
|
int i;
|
|
for(i=0;i<31;i++)
|
|
{
|
|
r[4*i] = ( s1->v[i] & 3) ^ (( s2->v[i] & 3) << 2);
|
|
r[4*i+1] = ((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2);
|
|
r[4*i+2] = ((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2);
|
|
r[4*i+3] = ((s1->v[i] >> 6) & 3) ^ (((s2->v[i] >> 6) & 3) << 2);
|
|
}
|
|
r[124] = ( s1->v[31] & 3) ^ (( s2->v[31] & 3) << 2);
|
|
r[125] = ((s1->v[31] >> 2) & 3) ^ (((s2->v[31] >> 2) & 3) << 2);
|
|
r[126] = ((s1->v[31] >> 4) & 3) ^ (((s2->v[31] >> 4) & 3) << 2);
|
|
}
|
|
|
|
/////////////////////////////////////////// ge25519.h ////////////////////////////////////
|
|
|
|
typedef struct
|
|
{
|
|
fe25519 x;
|
|
fe25519 y;
|
|
fe25519 z;
|
|
fe25519 t;
|
|
} ge25519;
|
|
|
|
//const ge25519 ge25519_base;
|
|
int ge25519_unpackneg_vartime(ge25519 *r, const unsigned char p[32]);
|
|
void ge25519_pack(unsigned char r[32], const ge25519 *p);
|
|
int ge25519_isneutral_vartime(const ge25519 *p);
|
|
void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const sc25519 *s1, const ge25519 *p2, const sc25519 *s2);
|
|
void ge25519_scalarmult_base(ge25519 *r, const sc25519 *s);
|
|
|
|
/////////////////////////////////////////// ge25519.c ////////////////////////////////////
|
|
|
|
/*
|
|
* Arithmetic on the twisted Edwards curve -x^2 + y^2 = 1 + dx^2y^2
|
|
* with d = -(121665/121666) = 37095705934669439343138083508754565189542113879843219016388785533085940283555
|
|
* Base point: (15112221349535400772501151409588531511454012693041857206046113283949847762202,46316835694926478169428394003475163141307993866256225615783033603165251855960);
|
|
*/
|
|
|
|
/* d */
|
|
static const fe25519 ge25519_ecd = {{0xA3, 0x78, 0x59, 0x13, 0xCA, 0x4D, 0xEB, 0x75, 0xAB, 0xD8, 0x41, 0x41, 0x4D, 0x0A, 0x70, 0x00,
|
|
0x98, 0xE8, 0x79, 0x77, 0x79, 0x40, 0xC7, 0x8C, 0x73, 0xFE, 0x6F, 0x2B, 0xEE, 0x6C, 0x03, 0x52}};
|
|
/* 2*d */
|
|
static const fe25519 ge25519_ec2d = {{0x59, 0xF1, 0xB2, 0x26, 0x94, 0x9B, 0xD6, 0xEB, 0x56, 0xB1, 0x83, 0x82, 0x9A, 0x14, 0xE0, 0x00,
|
|
0x30, 0xD1, 0xF3, 0xEE, 0xF2, 0x80, 0x8E, 0x19, 0xE7, 0xFC, 0xDF, 0x56, 0xDC, 0xD9, 0x06, 0x24}};
|
|
/* sqrt(-1) */
|
|
static const fe25519 ge25519_sqrtm1 = {{0xB0, 0xA0, 0x0E, 0x4A, 0x27, 0x1B, 0xEE, 0xC4, 0x78, 0xE4, 0x2F, 0xAD, 0x06, 0x18, 0x43, 0x2F,
|
|
0xA7, 0xD7, 0xFB, 0x3D, 0x99, 0x00, 0x4D, 0x2B, 0x0B, 0xDF, 0xC1, 0x4F, 0x80, 0x24, 0x83, 0x2B}};
|
|
|
|
#define ge25519_p3 ge25519
|
|
|
|
typedef struct
|
|
{
|
|
fe25519 x;
|
|
fe25519 z;
|
|
fe25519 y;
|
|
fe25519 t;
|
|
} ge25519_p1p1;
|
|
|
|
typedef struct
|
|
{
|
|
fe25519 x;
|
|
fe25519 y;
|
|
fe25519 z;
|
|
} ge25519_p2;
|
|
|
|
typedef struct
|
|
{
|
|
fe25519 x;
|
|
fe25519 y;
|
|
} ge25519_aff;
|
|
|
|
|
|
/* Packed coordinates of the base point */
|
|
const ge25519 ge25519_base = {{{0x1A, 0xD5, 0x25, 0x8F, 0x60, 0x2D, 0x56, 0xC9, 0xB2, 0xA7, 0x25, 0x95, 0x60, 0xC7, 0x2C, 0x69,
|
|
0x5C, 0xDC, 0xD6, 0xFD, 0x31, 0xE2, 0xA4, 0xC0, 0xFE, 0x53, 0x6E, 0xCD, 0xD3, 0x36, 0x69, 0x21}},
|
|
{{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
|
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}},
|
|
{{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
|
|
{{0xA3, 0xDD, 0xB7, 0xA5, 0xB3, 0x8A, 0xDE, 0x6D, 0xF5, 0x52, 0x51, 0x77, 0x80, 0x9F, 0xF0, 0x20,
|
|
0x7D, 0xE3, 0xAB, 0x64, 0x8E, 0x4E, 0xEA, 0x66, 0x65, 0x76, 0x8B, 0xD7, 0x0F, 0x5F, 0x87, 0x67}}};
|
|
|
|
/* Multiples of the base point in affine representation */
|
|
static const ge25519_aff ge25519_base_multiples_affine[425] = {
|
|
#include "ge25519_base.data"
|
|
};
|
|
|
|
#ifndef AC_NOALIASING
|
|
static void p1p1_to_p2_(ge25519_p3 *r, const ge25519_p1p1 *p) // to avoid errors because of aliasing
|
|
{
|
|
fe25519_mul(&r->x, &p->x, &p->t);
|
|
fe25519_mul(&r->y, &p->y, &p->z);
|
|
fe25519_mul(&r->z, &p->z, &p->t);
|
|
}
|
|
#else
|
|
static void p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p)
|
|
{
|
|
fe25519_mul(&r->x, &p->x, &p->t);
|
|
fe25519_mul(&r->y, &p->y, &p->z);
|
|
fe25519_mul(&r->z, &p->z, &p->t);
|
|
}
|
|
#endif
|
|
|
|
static void p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p)
|
|
{
|
|
#ifndef AC_NOALIASING
|
|
p1p1_to_p2_(r, p);
|
|
#else
|
|
p1p1_to_p2((ge25519_p2 *)r, p);
|
|
#endif
|
|
fe25519_mul(&r->t, &p->x, &p->y);
|
|
}
|
|
|
|
static void ge25519_mixadd2(ge25519_p3 *r, const ge25519_aff *q)
|
|
{
|
|
fe25519 a,b,t1,t2,c,d,e,f,g,h,qt;
|
|
fe25519_mul(&qt, &q->x, &q->y);
|
|
fe25519_sub(&a, &r->y, &r->x); /* A = (Y1-X1)*(Y2-X2) */
|
|
fe25519_add(&b, &r->y, &r->x); /* B = (Y1+X1)*(Y2+X2) */
|
|
fe25519_sub(&t1, &q->y, &q->x);
|
|
fe25519_add(&t2, &q->y, &q->x);
|
|
fe25519_mul(&a, &a, &t1);
|
|
fe25519_mul(&b, &b, &t2);
|
|
fe25519_sub(&e, &b, &a); /* E = B-A */
|
|
fe25519_add(&h, &b, &a); /* H = B+A */
|
|
fe25519_mul(&c, &r->t, &qt); /* C = T1*k*T2 */
|
|
fe25519_mul(&c, &c, &ge25519_ec2d);
|
|
fe25519_add(&d, &r->z, &r->z); /* D = Z1*2 */
|
|
fe25519_sub(&f, &d, &c); /* F = D-C */
|
|
fe25519_add(&g, &d, &c); /* G = D+C */
|
|
fe25519_mul(&r->x, &e, &f);
|
|
fe25519_mul(&r->y, &h, &g);
|
|
fe25519_mul(&r->z, &g, &f);
|
|
fe25519_mul(&r->t, &e, &h);
|
|
}
|
|
|
|
static void add_p1p1(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_p3 *q)
|
|
{
|
|
fe25519 a, b, c, d, t;
|
|
|
|
fe25519_sub(&a, &p->y, &p->x); /* A = (Y1-X1)*(Y2-X2) */
|
|
fe25519_sub(&t, &q->y, &q->x);
|
|
fe25519_mul(&a, &a, &t);
|
|
fe25519_add(&b, &p->x, &p->y); /* B = (Y1+X1)*(Y2+X2) */
|
|
fe25519_add(&t, &q->x, &q->y);
|
|
fe25519_mul(&b, &b, &t);
|
|
fe25519_mul(&c, &p->t, &q->t); /* C = T1*k*T2 */
|
|
fe25519_mul(&c, &c, &ge25519_ec2d);
|
|
fe25519_mul(&d, &p->z, &q->z); /* D = Z1*2*Z2 */
|
|
fe25519_add(&d, &d, &d);
|
|
fe25519_sub(&r->x, &b, &a); /* E = B-A */
|
|
fe25519_sub(&r->t, &d, &c); /* F = D-C */
|
|
fe25519_add(&r->z, &d, &c); /* G = D+C */
|
|
fe25519_add(&r->y, &b, &a); /* H = B+A */
|
|
}
|
|
|
|
/* See http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd */
|
|
static void dbl_p1p1(ge25519_p1p1 *r, const ge25519_p2 *p)
|
|
{
|
|
fe25519 a,b,c,d;
|
|
fe25519_square(&a, &p->x);
|
|
fe25519_square(&b, &p->y);
|
|
fe25519_square(&c, &p->z);
|
|
fe25519_add(&c, &c, &c);
|
|
fe25519_neg(&d, &a);
|
|
|
|
fe25519_add(&r->x, &p->x, &p->y);
|
|
fe25519_square(&r->x, &r->x);
|
|
fe25519_sub(&r->x, &r->x, &a);
|
|
fe25519_sub(&r->x, &r->x, &b);
|
|
fe25519_add(&r->z, &d, &b);
|
|
fe25519_sub(&r->t, &r->z, &c);
|
|
fe25519_sub(&r->y, &d, &b);
|
|
}
|
|
|
|
/* Constant-time version of: if(b) r = p */
|
|
static void cmov_aff(ge25519_aff *r, const ge25519_aff *p, unsigned char b)
|
|
{
|
|
fe25519_cmov(&r->x, &p->x, b);
|
|
fe25519_cmov(&r->y, &p->y, b);
|
|
}
|
|
|
|
static unsigned char equal(signed char b,signed char c)
|
|
{
|
|
unsigned char ub = b;
|
|
unsigned char uc = c;
|
|
unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
|
|
uint32_t y = x; /* 0: yes; 1..255: no */
|
|
y -= 1; /* 4294967295: yes; 0..254: no */
|
|
y >>= 31; /* 1: yes; 0: no */
|
|
return y;
|
|
}
|
|
|
|
static unsigned char negative(signed char b)
|
|
{
|
|
unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
|
|
x >>= 63; /* 1: yes; 0: no */
|
|
return x;
|
|
}
|
|
|
|
static void choose_t(ge25519_aff *t, unsigned long long pos, signed char b)
|
|
{
|
|
/* constant time */
|
|
fe25519 v;
|
|
*t = ge25519_base_multiples_affine[5*pos+0];
|
|
cmov_aff(t, &ge25519_base_multiples_affine[5*pos+1],equal(b,1) | equal(b,-1));
|
|
cmov_aff(t, &ge25519_base_multiples_affine[5*pos+2],equal(b,2) | equal(b,-2));
|
|
cmov_aff(t, &ge25519_base_multiples_affine[5*pos+3],equal(b,3) | equal(b,-3));
|
|
cmov_aff(t, &ge25519_base_multiples_affine[5*pos+4],equal(b,-4));
|
|
fe25519_neg(&v, &t->x);
|
|
fe25519_cmov(&t->x, &v, negative(b));
|
|
}
|
|
|
|
static void setneutral(ge25519 *r)
|
|
{
|
|
fe25519_setzero(&r->x);
|
|
fe25519_setone(&r->y);
|
|
fe25519_setone(&r->z);
|
|
fe25519_setzero(&r->t);
|
|
}
|
|
|
|
/* ********************************************************************
|
|
* EXPORTED FUNCTIONS
|
|
******************************************************************** */
|
|
|
|
/* return 0 on success, -1 otherwise */
|
|
int ge25519_unpackneg_vartime(ge25519_p3 *r, const unsigned char p[32])
|
|
{
|
|
unsigned char par;
|
|
fe25519 t, chk, num, den, den2, den4, den6;
|
|
fe25519_setone(&r->z);
|
|
par = p[31] >> 7;
|
|
fe25519_unpack(&r->y, p);
|
|
fe25519_square(&num, &r->y); /* x = y^2 */
|
|
fe25519_mul(&den, &num, &ge25519_ecd); /* den = dy^2 */
|
|
fe25519_sub(&num, &num, &r->z); /* x = y^2-1 */
|
|
fe25519_add(&den, &r->z, &den); /* den = dy^2+1 */
|
|
|
|
/* Computation of sqrt(num/den) */
|
|
/* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */
|
|
fe25519_square(&den2, &den);
|
|
fe25519_square(&den4, &den2);
|
|
fe25519_mul(&den6, &den4, &den2);
|
|
fe25519_mul(&t, &den6, &num);
|
|
fe25519_mul(&t, &t, &den);
|
|
|
|
fe25519_pow2523(&t, &t);
|
|
/* 2. computation of r->x = t * num * den^3 */
|
|
fe25519_mul(&t, &t, &num);
|
|
fe25519_mul(&t, &t, &den);
|
|
fe25519_mul(&t, &t, &den);
|
|
fe25519_mul(&r->x, &t, &den);
|
|
|
|
/* 3. Check whether sqrt computation gave correct result, multiply by sqrt(-1) if not: */
|
|
fe25519_square(&chk, &r->x);
|
|
fe25519_mul(&chk, &chk, &den);
|
|
if (!fe25519_iseq_vartime(&chk, &num))
|
|
fe25519_mul(&r->x, &r->x, &ge25519_sqrtm1);
|
|
|
|
/* 4. Now we have one of the two square roots, except if input was not a square */
|
|
fe25519_square(&chk, &r->x);
|
|
fe25519_mul(&chk, &chk, &den);
|
|
if (!fe25519_iseq_vartime(&chk, &num))
|
|
return -1;
|
|
|
|
/* 5. Choose the desired square root according to parity: */
|
|
if(fe25519_getparity(&r->x) != (1-par))
|
|
fe25519_neg(&r->x, &r->x);
|
|
|
|
fe25519_mul(&r->t, &r->x, &r->y);
|
|
return 0;
|
|
}
|
|
|
|
void ge25519_pack(unsigned char r[32], const ge25519_p3 *p)
|
|
{
|
|
fe25519 tx, ty, zi;
|
|
fe25519_invert(&zi, &p->z);
|
|
fe25519_mul(&tx, &p->x, &zi);
|
|
fe25519_mul(&ty, &p->y, &zi);
|
|
fe25519_pack(r, &ty);
|
|
r[31] ^= fe25519_getparity(&tx) << 7;
|
|
}
|
|
|
|
int ge25519_isneutral_vartime(const ge25519_p3 *p)
|
|
{
|
|
int ret = 1;
|
|
if(!fe25519_iszero(&p->x)) ret = 0;
|
|
if(!fe25519_iseq_vartime(&p->y, &p->z)) ret = 0;
|
|
return ret;
|
|
}
|
|
|
|
/* computes [s1]p1 + [s2]p2 */
|
|
void ge25519_double_scalarmult_vartime(ge25519_p3 *r, const ge25519_p3 *p1, const sc25519 *s1, const ge25519_p3 *p2, const sc25519 *s2)
|
|
{
|
|
ge25519_p1p1 tp1p1;
|
|
ge25519_p3 pre[16];
|
|
unsigned char b[127];
|
|
int i;
|
|
|
|
/* precomputation s2 s1 */
|
|
setneutral(pre); /* 00 00 */
|
|
pre[1] = *p1; /* 00 01 */
|
|
dbl_p1p1(&tp1p1,(ge25519_p2 *)p1); p1p1_to_p3( &pre[2], &tp1p1); /* 00 10 */
|
|
add_p1p1(&tp1p1,&pre[1], &pre[2]); p1p1_to_p3( &pre[3], &tp1p1); /* 00 11 */
|
|
pre[4] = *p2; /* 01 00 */
|
|
add_p1p1(&tp1p1,&pre[1], &pre[4]); p1p1_to_p3( &pre[5], &tp1p1); /* 01 01 */
|
|
add_p1p1(&tp1p1,&pre[2], &pre[4]); p1p1_to_p3( &pre[6], &tp1p1); /* 01 10 */
|
|
add_p1p1(&tp1p1,&pre[3], &pre[4]); p1p1_to_p3( &pre[7], &tp1p1); /* 01 11 */
|
|
dbl_p1p1(&tp1p1,(ge25519_p2 *)p2); p1p1_to_p3( &pre[8], &tp1p1); /* 10 00 */
|
|
add_p1p1(&tp1p1,&pre[1], &pre[8]); p1p1_to_p3( &pre[9], &tp1p1); /* 10 01 */
|
|
dbl_p1p1(&tp1p1,(ge25519_p2 *)&pre[5]); p1p1_to_p3(&pre[10], &tp1p1); /* 10 10 */
|
|
add_p1p1(&tp1p1,&pre[3], &pre[8]); p1p1_to_p3(&pre[11], &tp1p1); /* 10 11 */
|
|
add_p1p1(&tp1p1,&pre[4], &pre[8]); p1p1_to_p3(&pre[12], &tp1p1); /* 11 00 */
|
|
add_p1p1(&tp1p1,&pre[1],&pre[12]); p1p1_to_p3(&pre[13], &tp1p1); /* 11 01 */
|
|
add_p1p1(&tp1p1,&pre[2],&pre[12]); p1p1_to_p3(&pre[14], &tp1p1); /* 11 10 */
|
|
add_p1p1(&tp1p1,&pre[3],&pre[12]); p1p1_to_p3(&pre[15], &tp1p1); /* 11 11 */
|
|
|
|
sc25519_2interleave2(b,s1,s2);
|
|
|
|
/* scalar multiplication */
|
|
*r = pre[b[126]];
|
|
for(i=125;i>=0;i--)
|
|
{
|
|
dbl_p1p1(&tp1p1, (ge25519_p2 *)r);
|
|
#ifndef AC_NOALIASING
|
|
p1p1_to_p2_(r, &tp1p1);
|
|
#else
|
|
p1p1_to_p2((ge25519_p2 *) r, &tp1p1);
|
|
#endif
|
|
dbl_p1p1(&tp1p1, (ge25519_p2 *)r);
|
|
if(b[i]!=0)
|
|
{
|
|
p1p1_to_p3(r, &tp1p1);
|
|
add_p1p1(&tp1p1, r, &pre[b[i]]);
|
|
}
|
|
#ifndef AC_NOALIASING
|
|
if(i != 0) p1p1_to_p2_(r, &tp1p1);
|
|
#else
|
|
if(i != 0) p1p1_to_p2((ge25519_p2 *)r, &tp1p1);
|
|
#endif
|
|
else p1p1_to_p3(r, &tp1p1);
|
|
}
|
|
}
|
|
|
|
void ge25519_scalarmult_base(ge25519_p3 *r, const sc25519 *s)
|
|
{
|
|
signed char b[85];
|
|
int i;
|
|
ge25519_aff t;
|
|
sc25519_window3(b,s);
|
|
|
|
choose_t((ge25519_aff *)r, 0, b[0]);
|
|
fe25519_setone(&r->z);
|
|
fe25519_mul(&r->t, &r->x, &r->y);
|
|
for(i=1;i<85;i++)
|
|
{
|
|
choose_t(&t, (unsigned long long) i, b[i]);
|
|
ge25519_mixadd2(r, &t);
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////// misc ////////////////////////////////////
|
|
|
|
#if 0 // we're not really vulnerable to timing attacks, so we can use memcmp()
|
|
int crypto_verify_32(const unsigned char *x,const unsigned char *y)
|
|
{
|
|
unsigned int differentbits = 0;
|
|
loopi(32) differentbits |= x[i] ^ y[i];
|
|
return differentbits;
|
|
}
|
|
#endif
|
|
|
|
#undef ge25519_p3
|
|
|