static void choose_t(ge25519_aff *t, signed char b) { fe25519 v; unsigned char u; signed char const mask = b >> 7; u = (b + mask) ^ mask; *t = ge25519_base_multiples_affine[u]; fe25519_neg(&v, &t->x); fe25519_cmov(&t->x, &v, negative(b)); }
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)); }
/* 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; }
/* 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); }
/* 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); //here, you have to fully reduce &d because subtraction needs a <= p fe25519_freeze(&c); //do not remove 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); }
/* computes [s1]p1 + [s2]p2 */ void ge25519_double_scalarmult_vartime(ge25519_p3 *r, const ge25519_p3 *p1, const sc25519 *s1, const sc25519 *s2) { signed char slide1[256], slide2[256]; ge25519_pniels pre1[PRE1_SIZE], neg; ge25519_p3 d1; ge25519_p1p1 t; ge25519_niels nneg; fe25519 d; int i; sc25519_slide(slide1, s1, S1_SWINDOWSIZE); sc25519_slide(slide2, s2, S2_SWINDOWSIZE); /* precomputation */ pre1[0] = *(ge25519_pniels *)p1; ge25519_dbl_p1p1(&t,(ge25519_p2 *)pre1); ge25519_p1p1_to_p3(&d1, &t); /* Convert pre[0] to projective Niels representation */ d = pre1[0].ysubx; fe25519_sub(&pre1[0].ysubx, &pre1[0].xaddy, &pre1[0].ysubx); fe25519_add(&pre1[0].xaddy, &pre1[0].xaddy, &d); fe25519_mul(&pre1[0].t2d, &pre1[0].t2d, &ec2d); for(i=0;i<PRE1_SIZE-1;i++) { ge25519_pnielsadd_p1p1(&t, &d1, &pre1[i]); ge25519_p1p1_to_pniels(&pre1[i+1], &t); } setneutral(r); for (i = 255;i >= 0;--i) { if (slide1[i] || slide2[i]) goto firstbit; } for(;i>=0;i--) { firstbit: ge25519_dbl_p1p1(&t, (ge25519_p2 *)r); if(slide1[i]>0) { ge25519_p1p1_to_p3(r, &t); ge25519_pnielsadd_p1p1(&t, r, &pre1[slide1[i]/2]); } else if(slide1[i]<0) { ge25519_p1p1_to_p3(r, &t); neg = pre1[-slide1[i]/2]; d = neg.ysubx; neg.ysubx = neg.xaddy; neg.xaddy = d; fe25519_neg(&neg.t2d, &neg.t2d); ge25519_pnielsadd_p1p1(&t, r, &neg); } if(slide2[i]>0) { ge25519_p1p1_to_p3(r, &t); ge25519_nielsadd_p1p1(&t, r, &pre2[slide2[i]/2]); } else if(slide2[i]<0) { ge25519_p1p1_to_p3(r, &t); nneg = pre2[-slide2[i]/2]; d = nneg.ysubx; nneg.ysubx = nneg.xaddy; nneg.xaddy = d; fe25519_neg(&nneg.t2d, &nneg.t2d); ge25519_nielsadd_p1p1(&t, r, &nneg); } ge25519_p1p1_to_p2((ge25519_p2 *)r, &t); } }