void ge_neg(ge_p3* r, const ge_p3 *p) { fe_neg(r->X, p->X); fe_copy(r->Y, p->Y); fe_copy(r->Z, p->Z); fe_neg(r->T, p->T); }
void ge_montx_to_p2(ge_p2* p, const fe u, const unsigned char ed_sign_bit) { fe x, y, A, v, v2, iv, nx; fe_frombytes(A, A_bytes); /* given u, recover edwards y */ /* given u, recover v */ /* given u and v, recover edwards x */ fe_montx_to_edy(y, u); /* y = (u - 1) / (u + 1) */ fe_mont_rhs(v2, u); /* v^2 = u(u^2 + Au + 1) */ fe_sqrt(v, v2); /* v = sqrt(v^2) */ fe_mul(x, u, A); /* x = u * sqrt(-(A+2)) */ fe_invert(iv, v); /* 1/v */ fe_mul(x, x, iv); /* x = (u/v) * sqrt(-(A+2)) */ fe_neg(nx, x); /* negate x to match sign bit */ fe_cmov(x, nx, fe_isnegative(x) ^ ed_sign_bit); fe_copy(p->X, x); fe_copy(p->Y, y); fe_1(p->Z); /* POSTCONDITION: check that p->X and p->Y satisfy the Ed curve equation */ /* -x^2 + y^2 = 1 + dx^2y^2 */ #ifndef NDEBUG { fe one, d, x2, y2, x2y2, dx2y2; unsigned char dbytes[32] = { 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 }; fe_frombytes(d, dbytes); fe_1(one); fe_sq(x2, p->X); /* x^2 */ fe_sq(y2, p->Y); /* y^2 */ fe_mul(dx2y2, x2, y2); /* x^2y^2 */ fe_mul(dx2y2, dx2y2, d); /* dx^2y^2 */ fe_add(dx2y2, dx2y2, one); /* dx^2y^2 + 1 */ fe_neg(x2y2, x2); /* -x^2 */ fe_add(x2y2, x2y2, y2); /* -x^2 + y^2 */ assert(fe_isequal(x2y2, dx2y2)); } #endif }
/* see http://crypto.stackexchange.com/a/6215/4697 */ void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) { const unsigned char SC_1[32] = {1}; /* scalar with value 1 */ unsigned char n[32]; ge_p3 nB; ge_p1p1 A_p1p1; ge_p3 A; ge_p3 public_key_unpacked; ge_cached T; int i; /* copy the scalar and clear highest bit */ for (i = 0; i < 31; ++i) { n[i] = scalar[i]; } n[31] = scalar[31] & 127; /* private key: a = n + t */ if (private_key) { sc_muladd(private_key, SC_1, n, private_key); } /* public key: A = nB + T */ if (public_key) { /* if we know the private key we don't need a point addition, which is faster */ /* using a "timing attack" you could find out wether or not we know the private key, but this information seems rather useless - if this is important pass public_key and private_key seperately in 2 function calls */ if (private_key) { ge_scalarmult_base(&A, private_key); } else { /* unpack public key into T */ ge_frombytes_negate_vartime(&public_key_unpacked, public_key); fe_neg(public_key_unpacked.X, public_key_unpacked.X); // undo negate fe_neg(public_key_unpacked.T, public_key_unpacked.T); // undo negate ge_p3_to_cached(&T, &public_key_unpacked); /* calculate n*B */ ge_scalarmult_base(&nB, n); /* A = n*B + T */ ge_add(&A_p1p1, &nB, &T); ge_p1p1_to_p3(&A, &A_p1p1); } /* pack public key */ ge_p3_tobytes(public_key, &A); } }
/* Test if the public key can be uncommpressed and negate it (-X,Y,Z,-T) return 0 on success */ int ge_frombytes_negate_vartime(ge_p3 *p,const unsigned char *s) { byte parity; byte x[F25519_SIZE]; byte y[F25519_SIZE]; byte a[F25519_SIZE]; byte b[F25519_SIZE]; byte c[F25519_SIZE]; int ret = 0; /* unpack the key s */ parity = s[31] >> 7; fe_copy(y, s); y[31] &= 127; fe_mul__distinct(c, y, y); fe_mul__distinct(b, c, ed25519_d); fe_add(a, b, f25519_one); fe_inv__distinct(b, a); fe_sub(a, c, f25519_one); fe_mul__distinct(c, a, b); fe_sqrt(a, c); fe_neg(b, a); fe_select(x, a, b, (a[0] ^ parity) & 1); /* test that x^2 is equal to c */ fe_mul__distinct(a, x, x); fe_normalize(a); fe_normalize(c); ret |= ConstantCompare(a, c, F25519_SIZE); /* project the key s onto p */ fe_copy(p->X, x); fe_copy(p->Y, y); fe_load(p->Z, 1); fe_mul__distinct(p->T, x, y); /* negate, the point becomes (-X,Y,Z,-T) */ fe_neg(p->X,p->X); fe_neg(p->T,p->T); return ret; }
void ed25519_double(ge_p3 *r, const ge_p3 *p) { /* Explicit formulas database: dbl-2008-hwcd * * source 2008 Hisil--Wong--Carter--Dawson, * http://eprint.iacr.org/2008/522, Section 3.3 * compute A = X1^2 * compute B = Y1^2 * compute C = 2 Z1^2 * compute D = a A * compute E = (X1+Y1)^2-A-B * compute G = D + B * compute F = G - C * compute H = D - B * compute X3 = E F * compute Y3 = G H * compute T3 = E H * compute Z3 = F G */ byte a[F25519_SIZE]; byte b[F25519_SIZE]; byte c[F25519_SIZE]; byte e[F25519_SIZE]; byte f[F25519_SIZE]; byte g[F25519_SIZE]; byte h[F25519_SIZE]; /* A = X1^2 */ fe_mul__distinct(a, p->X, p->X); /* B = Y1^2 */ fe_mul__distinct(b, p->Y, p->Y); /* C = 2 Z1^2 */ fe_mul__distinct(c, p->Z, p->Z); fe_add(c, c, c); /* D = a A (alter sign) */ /* E = (X1+Y1)^2-A-B */ fe_add(f, p->X, p->Y); fe_mul__distinct(e, f, f); fe_sub(e, e, a); fe_sub(e, e, b); /* G = D + B */ fe_sub(g, b, a); /* F = G - C */ fe_sub(f, g, c); /* H = D - B */ fe_neg(h, b); fe_sub(h, h, a); /* X3 = E F */ fe_mul__distinct(r->X, e, f); /* Y3 = G H */ fe_mul__distinct(r->Y, g, h); /* T3 = E H */ fe_mul__distinct(r->T, e, h); /* Z3 = F G */ fe_mul__distinct(r->Z, f, g); }