void ecc_add_jja (const struct ecc_curve *ecc, mp_limb_t *r, const mp_limb_t *p, const mp_limb_t *q, mp_limb_t *scratch) { /* Formulas, from djb, http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b): Computation Operation Live variables ZZ = Z_1^2 sqr ZZ H = X_2*ZZ - X_1 mul (djb: U_2) ZZ, H HH = H^2 sqr ZZ, H, HH ZZZ = ZZ*Z_1 mul ZZ, H, HH, ZZZ Z_3 = (Z_1+H)^2-ZZ-HH sqr H, HH, ZZZ W = 2 (Y_2*ZZZ - Y_1) mul (djb: S_2) H, HH, W I = 4*HH H, W, I J = H*I mul W, I, J V = X_1*I mul W, J, V X_3 = W^2-J-2*V sqr W, J, V Y_3 = W*(V-X_3)-2*Y_1*J mul, mul */ #define zz scratch #define h (scratch + ecc->p.size) #define hh (scratch + 2*ecc->p.size) #define w (scratch + 3*ecc->p.size) #define j (scratch + 4*ecc->p.size) #define v scratch #define x1 p #define y1 (p + ecc->p.size) #define z1 (p + 2*ecc->p.size) #define x2 q #define y2 (q + ecc->p.size) /* zz */ ecc_modp_sqr (ecc, zz, z1); /* h*/ ecc_modp_mul (ecc, h, x2, zz); ecc_modp_sub (ecc, h, h, x1); /* hh */ ecc_modp_sqr (ecc, hh, h); /* Do z^3 early, store at w. */ ecc_modp_mul (ecc, w, zz, z1); /* z_3, use j area for scratch */ ecc_modp_add (ecc, r + 2*ecc->p.size, p + 2*ecc->p.size, h); ecc_modp_sqr (ecc, j, r + 2*ecc->p.size); ecc_modp_sub (ecc, j, j, zz); ecc_modp_sub (ecc, r + 2*ecc->p.size, j, hh); /* w */ ecc_modp_mul (ecc, j, y2, w); ecc_modp_sub (ecc, w, j, y1); ecc_modp_mul_1 (ecc, w, w, 2); /* i replaces hh, j */ ecc_modp_mul_1 (ecc, hh, hh, 4); ecc_modp_mul (ecc, j, hh, h); /* v */ ecc_modp_mul (ecc, v, x1, hh); /* x_3, use (h, hh) as sqratch */ ecc_modp_sqr (ecc, h, w); ecc_modp_sub (ecc, r, h, j); ecc_modp_submul_1 (ecc, r, v, 2); /* y_3, use (h, hh) as sqratch */ ecc_modp_mul (ecc, h, y1, j); /* frees j */ ecc_modp_sub (ecc, r + ecc->p.size, v, r); ecc_modp_mul (ecc, j, r + ecc->p.size, w); ecc_modp_submul_1 (ecc, j, h, 2); mpn_copyi (r + ecc->p.size, j, ecc->p.size); }
/* Add two points on an Edwards curve, in homogeneous coordinates */ void ecc_add_ehh (const struct ecc_curve *ecc, mp_limb_t *r, const mp_limb_t *p, const mp_limb_t *q, mp_limb_t *scratch) { #define x1 p #define y1 (p + ecc->p.size) #define z1 (p + 2*ecc->p.size) #define x2 q #define y2 (q + ecc->p.size) #define z2 (q + 2*ecc->p.size) #define x3 r #define y3 (r + ecc->p.size) #define z3 (r + 2*ecc->p.size) /* Formulas (from djb, http://www.hyperelliptic.org/EFD/g1p/auto-edwards-projective.html#addition-add-2007-bl): Computation Operation Live variables C = x1*x2 mul C D = y1*y2 mul C, D T = (x1+y1)(x2+y2) - C - D, mul C, D, T E = b*C*D 2 mul C, E, T (Replace C <-- D - C) A = z1*z2 mul A, C, E, T B = A^2 sqr A, B, C, E, T F = B - E A, B, C, E, F, T G = B + E A, C, F, G, T x3 = A*F*T 2 mul A, C, G y3 = A*G*(D-C) 2 mul F, G z3 = F*G mul But when working with the twist curve, we have to negate the factor C = x1*x2. We change subtract to add in the y3 expression, and swap F and G. */ #define C scratch #define D (scratch + ecc->p.size) #define T (scratch + 2*ecc->p.size) #define E (scratch + 3*ecc->p.size) #define A (scratch + 4*ecc->p.size) #define B (scratch + 5*ecc->p.size) #define F D #define G E ecc_modp_mul (ecc, C, x1, x2); ecc_modp_mul (ecc, D, y1, y2); ecc_modp_add (ecc, A, x1, y1); ecc_modp_add (ecc, B, x2, y2); ecc_modp_mul (ecc, T, A, B); ecc_modp_sub (ecc, T, T, C); ecc_modp_sub (ecc, T, T, D); ecc_modp_mul (ecc, x3, C, D); ecc_modp_mul (ecc, E, x3, ecc->b); ecc_modp_add (ecc, C, D, C); /* ! */ ecc_modp_mul (ecc, A, z1, z2); ecc_modp_sqr (ecc, B, A); ecc_modp_sub (ecc, F, B, E); ecc_modp_add (ecc, G, B, E); /* x3 */ ecc_modp_mul (ecc, B, G, T); /* ! */ ecc_modp_mul (ecc, x3, B, A); /* y3 */ ecc_modp_mul (ecc, B, F, C); /* ! */ ecc_modp_mul (ecc, y3, B, A); /* z3 */ ecc_modp_mul (ecc, B, F, G); mpn_copyi (z3, B, ecc->p.size); }
void ecc_add_jjj (const struct ecc_curve *ecc, mp_limb_t *r, const mp_limb_t *p, const mp_limb_t *q, mp_limb_t *scratch) { /* Formulas, from djb, http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl: Computation Operation Live variables Z1Z1 = Z1^2 sqr Z1Z1 Z2Z2 = Z2^2 sqr Z1Z1, Z2Z2 U1 = X1*Z2Z2 mul Z1Z1, Z2Z2, U1 U2 = X2*Z1Z1 mul Z1Z1, Z2Z2, U1, U2 H = U2-U1 Z1Z1, Z2Z2, U1, H Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2)*H sqr, mul Z1Z1, Z2Z2, U1, H S1 = Y1*Z2*Z2Z2 mul, mul Z1Z1, U1, H, S1 S2 = Y2*Z1*Z1Z1 mul, mul U1, H, S1, S2 W = 2*(S2-S1) (djb: r) U1, H, S1, W I = (2*H)^2 sqr U1, H, S1, W, I J = H*I mul U1, S1, W, J, V V = U1*I mul S1, W, J, V X3 = W^2-J-2*V sqr S1, W, J, V Y3 = W*(V-X3)-2*S1*J mul, mul */ mp_limb_t *z1z1 = scratch; mp_limb_t *z2z2 = scratch + ecc->size; mp_limb_t *u1 = scratch + 2*ecc->size; mp_limb_t *u2 = scratch + 3*ecc->size; mp_limb_t *s1 = scratch; /* overlap z1z1 */ mp_limb_t *s2 = scratch + ecc->size; /* overlap z2z2 */ mp_limb_t *i = scratch + 4*ecc->size; mp_limb_t *j = scratch + 5*ecc->size; mp_limb_t *v = scratch + 6*ecc->size; /* z1^2, z2^2, u1 = x1 x2^2, u2 = x2 z1^2 - u1 */ ecc_modp_sqr (ecc, z1z1, p + 2*ecc->size); ecc_modp_sqr (ecc, z2z2, q + 2*ecc->size); ecc_modp_mul (ecc, u1, p, z2z2); ecc_modp_mul (ecc, u2, q, z1z1); ecc_modp_sub (ecc, u2, u2, u1); /* Store h in u2 */ /* z3, use i, j, v as scratch, result at i. */ ecc_modp_add (ecc, i, p + 2*ecc->size, q + 2*ecc->size); ecc_modp_sqr (ecc, v, i); ecc_modp_sub (ecc, v, v, z1z1); ecc_modp_sub (ecc, v, v, z2z2); ecc_modp_mul (ecc, i, v, u2); /* Delayed write, to support in-place operation. */ /* s1 = y1 z2^3, s2 = y2 z1^3, scratch at j and v */ ecc_modp_mul (ecc, j, z1z1, p + 2*ecc->size); /* z1^3 */ ecc_modp_mul (ecc, v, z2z2, q + 2*ecc->size); /* z2^3 */ ecc_modp_mul (ecc, s1, p + ecc->size, v); ecc_modp_mul (ecc, v, j, q + ecc->size); ecc_modp_sub (ecc, s2, v, s1); ecc_modp_mul_1 (ecc, s2, s2, 2); /* Store z3 */ mpn_copyi (r + 2*ecc->size, i, ecc->size); /* i, j, v */ ecc_modp_sqr (ecc, i, u2); ecc_modp_mul_1 (ecc, i, i, 4); ecc_modp_mul (ecc, j, u2, i); ecc_modp_mul (ecc, v, u1, i); /* now, u1, u2 and i are free for reuse .*/ /* x3, use u1, u2 as scratch */ ecc_modp_sqr (ecc, u1, s2); ecc_modp_sub (ecc, r, u1, j); ecc_modp_submul_1 (ecc, r, v, 2); /* y3 */ ecc_modp_mul (ecc, u1, s1, j); /* Frees j */ ecc_modp_sub (ecc, u2, v, r); /* Frees v */ ecc_modp_mul (ecc, i, s2, u2); ecc_modp_submul_1 (ecc, i, u1, 2); mpn_copyi (r + ecc->size, i, ecc->size); }