// u2 = w * -1 * -non_square * r^2
// u2 = w * non_square * r^2
// u2 = u
-void crypto_elligator2_direct(uint8_t curve[32], const uint8_t hash[32])
+void crypto_hidden_to_curve(uint8_t curve[32], const uint8_t hidden[32])
{
static const fe ufactor = { // -sqrt(-1) * 2
-1917299, 15887451, -18755900, -7000830, -24778944,
// Representatives are encoded in 254 bits.
// The two most significant ones are random padding that must be ignored.
u8 clamped[32];
- COPY(clamped, hash, 32);
+ COPY(clamped, hidden, 32);
clamped[31] &= 0x3f;
fe r, u, t1, t2, t3;
//
// Note that to ensure the representative is fully random, we do *not*
// clear the cofactor. It is otherwise compatible with X25519 (once
-// converted with crypto_elligator2_direct()).
+// converted with crypto_hidden_to_curve()).
//
// This compatibility was achieved by clamping the scalar, like we do
// with regular X25519 key exchanges. The cost is a very small bias in
// discrete logarithm, which is conjecturally intractable).
//
// In practice, this means the bias is impossible to detect.
-int crypto_elligator2_inverse(u8 hash[32], const u8 secret_key[32], u8 tweak)
+int crypto_private_to_hidden(u8 hidden[32], const u8 secret_key[32], u8 tweak)
{
static const fe lop_x = {
21352778, 5345713, 4660180, -8347857, 24143090,
fe_add (t1, t3, t3);
fe_neg (t2, t3);
fe_ccopy(t3, t2, fe_isodd(t1));
- fe_tobytes(hash, t3);
+ fe_tobytes(hidden, t3);
// Pad with two random bits
- hash[31] |= tweak & 0xc0;
+ hidden[31] |= tweak & 0xc0;
WIPE_BUFFER(t1); WIPE_BUFFER(scalar);
WIPE_BUFFER(t2); WIPE_CTX(&pk);
return 0;
}
-void crypto_elligator2_key_pair(u8 hash[32], u8 secret_key[32], u8 seed[32])
+void crypto_hidden_key_pair(u8 hidden[32], u8 secret_key[32], u8 seed[32])
{
u8 buf[64];
COPY(buf + 32, seed, 32);
do {
crypto_chacha20(buf, 0, 64, buf+32, zero);
- } while(crypto_elligator2_inverse(buf+32, buf, buf[32]));
+ } while(crypto_private_to_hidden(buf+32, buf, buf[32]));
// Note that buf[32] is not actually reused. Either we loop one
// more time and buf[32] is used for the new seed, or we succeeded,
// and buf[32] is used as a tweak parameter.
//
- // This is because the return value of crypto_elligator2_inverse()
+ // This is because the return value of crypto_private_to_hidden()
// is independent from its tweak parameter.
crypto_wipe(seed, 32);
- COPY(hash , buf + 32, 32);
+ COPY(hidden , buf + 32, 32);
COPY(secret_key, buf , 32);
WIPE_BUFFER(buf);
}
static void elligator_dir(const vector in[], vector *out)
{
- crypto_elligator2_direct(out->buf, in->buf);
+ crypto_hidden_to_curve(out->buf, in->buf);
}
static void elligator_inv(const vector in[], vector *out)
const vector *sk = in;
u8 tweak = in[1].buf[0];
u8 failure = in[2].buf[0];
- int check = crypto_elligator2_inverse(out->buf, sk->buf, tweak);
+ int check = crypto_private_to_hidden(out->buf, sk->buf, tweak);
if ((u8)check != failure) {
fprintf(stderr, "Elligator inverse map: failure mismatch\n");
}
u8 r2[32]; memcpy(r2, r, 32); r2[31] = (r[31] & 0x3f) | 0x40;
u8 r3[32]; memcpy(r3, r, 32); r3[31] = (r[31] & 0x3f) | 0x80;
u8 r4[32]; memcpy(r4, r, 32); r4[31] = (r[31] & 0x3f) | 0xc0;
- u8 u [32]; crypto_elligator2_direct(u , r );
- u8 u1[32]; crypto_elligator2_direct(u1, r1);
- u8 u2[32]; crypto_elligator2_direct(u2, r2);
- u8 u3[32]; crypto_elligator2_direct(u3, r3);
- u8 u4[32]; crypto_elligator2_direct(u4, r4);
+ u8 u [32]; crypto_hidden_to_curve(u , r );
+ u8 u1[32]; crypto_hidden_to_curve(u1, r1);
+ u8 u2[32]; crypto_hidden_to_curve(u2, r2);
+ u8 u3[32]; crypto_hidden_to_curve(u3, r3);
+ u8 u4[32]; crypto_hidden_to_curve(u4, r4);
status |= memcmp(u, u1, 32);
status |= memcmp(u, u2, 32);
status |= memcmp(u, u3, 32);
u8 separate[32];
RANDOM_INPUT(r, 32);
memcpy(overlapping + 31, r, 32);
- crypto_elligator2_direct(overlapping + i, overlapping + 31);
- crypto_elligator2_direct(separate, r);
+ crypto_hidden_to_curve(overlapping + i, overlapping + 31);
+ crypto_hidden_to_curve(separate, r);
status |= memcmp(separate, overlapping + i, 32);
}
printf("%s: elligator direct (overlapping i/o)\n",
RANDOM_INPUT(sk, 33);
u8 tweak = sk[32];
memcpy(overlapping + 31, sk, 32);
- int a = crypto_elligator2_inverse(overlapping+i, overlapping+31, tweak);
- int b = crypto_elligator2_inverse(separate, sk, tweak);
+ int a = crypto_private_to_hidden(overlapping+i, overlapping+31, tweak);
+ int b = crypto_private_to_hidden(separate, sk, tweak);
status |= a - b;
if (a == 0) {
// The buffers are the same only if written to to begin with
RANDOM_INPUT(sk1, 32);
RANDOM_INPUT(sk2, 32);
u8 r[32];
- if (crypto_elligator2_inverse(r, sk1, i)) {
+ if (crypto_private_to_hidden(r, sk1, i)) {
continue;
}
- u8 pkr[32]; crypto_elligator2_direct(pkr, r);
+ u8 pkr[32]; crypto_hidden_to_curve(pkr, r);
u8 pk1[32]; crypto_x25519_public_key(pk1, sk1);
u8 e1 [32]; crypto_x25519(e1, sk2, pk1);
u8 e2 [32]; crypto_x25519(e2, sk2, pkr);
RANDOM_INPUT(seed, 32);
RANDOM_INPUT(sk2 , 32);
u8 r [32];
- u8 sk1[32]; crypto_elligator2_key_pair(r, sk1, seed);
- u8 pkr[32]; crypto_elligator2_direct(pkr, r);
+ u8 sk1[32]; crypto_hidden_key_pair(r, sk1, seed);
+ u8 pkr[32]; crypto_hidden_to_curve(pkr, r);
u8 pk1[32]; crypto_x25519_public_key(pk1, sk1);
u8 e1 [32]; crypto_x25519(e1, sk2, pk1);
u8 e2 [32]; crypto_x25519(e2, sk2, pkr);
RANDOM_INPUT(s1, 32);
u8 *s2 = over + 63;
memcpy(s2, s1, 32);
- crypto_elligator2_key_pair(sep , sep + 32, s1);
- crypto_elligator2_key_pair(over + i, over + i + 32, s2);
+ crypto_hidden_key_pair(sep , sep + 32, s1);
+ crypto_hidden_key_pair(over + i, over + i + 32, s2);
status |= memcmp(sep, over + i, 64);
}