Skip to content
This repository was archived by the owner on Apr 18, 2024. It is now read-only.

Commit 26debf5

Browse files
committed
vxeddsa VRF was ported to java
1 parent 70fae57 commit 26debf5

28 files changed

+1386
-50
lines changed

common/src/main/java/org/whispersystems/curve25519/BaseJavaCurve25519Provider.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.whispersystems.curve25519.java.Sha512;
1010
import org.whispersystems.curve25519.java.curve_sigs;
1111
import org.whispersystems.curve25519.java.scalarmult;
12+
import org.whispersystems.curve25519.java.gen_x;
1213

1314
abstract class BaseJavaCurve25519Provider implements Curve25519Provider {
1415

@@ -74,13 +75,26 @@ public boolean verifySignature(byte[] publicKey, byte[] message, byte[] signatur
7475
}
7576

7677
public byte[] calculateVrfSignature(byte[] random, byte[] privateKey, byte[] message) {
77-
throw new AssertionError("NYI");
78+
byte[] result = new byte[96];
79+
byte[] random32 = new byte[32];
80+
if (random.length >= 32) {
81+
System.arraycopy(random, 0, random32, 0, 32);
82+
} else throw new IllegalArgumentException("too small random");
83+
if (gen_x.generalized_xveddsa_25519_sign(sha512provider, result, privateKey, message, random32)) {
84+
return result;
85+
} else {
86+
throw new IllegalArgumentException();
87+
}
7888
}
7989

8090
public byte[] verifyVrfSignature(byte[] publicKey, byte[] message, byte[] signature)
8191
throws VrfSignatureVerificationFailedException
8292
{
83-
throw new AssertionError("NYI");
93+
byte[] result = new byte[32];
94+
if (gen_x.generalized_xveddsa_25519_verify(sha512provider, result, signature, publicKey, message) != 0) {
95+
throw new VrfSignatureVerificationFailedException();
96+
}
97+
return result;
8498
}
8599

86100
public byte[] getRandom(int length) {

common/src/main/java/org/whispersystems/curve25519/Curve25519.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ public byte[] calculateVrfSignature(byte[] privateKey, byte[] message) {
140140
* @param message The message that was signed.
141141
* @param signature The unique signature to verify.
142142
*
143+
* @throws VrfSignatureVerificationFailedException when verification is failed
144+
*
143145
* @return The vrf for this signature.
144146
*/
145147
public byte[] verifyVrfSignature(byte[] publicKey, byte[] message, byte[] signature)
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package org.whispersystems.curve25519.java;
2+
3+
public class elligator {
4+
public static int legendre_is_nonsquare(int[] in)
5+
{
6+
int[] temp = new int[10];
7+
byte[] bytes = new byte[32];
8+
fe_pow22523.fe_pow22523(temp, in); /* temp = in^((q-5)/8) */
9+
fe_sq.fe_sq(temp, temp); /* in^((q-5)/4) */
10+
fe_sq.fe_sq(temp, temp); /* in^((q-5)/2) */
11+
fe_mul.fe_mul(temp, temp, in); /* in^((q-3)/2) */
12+
fe_mul.fe_mul(temp, temp, in); /* in^((q-1)/2) */
13+
14+
/* temp is now the Legendre symbol:
15+
* 1 = square
16+
* 0 = input is zero
17+
* -1 = nonsquare
18+
*/
19+
fe_tobytes.fe_tobytes(bytes, temp);
20+
return 1 & bytes[31];
21+
}
22+
23+
public static void elligator(int[] u, int[] r)
24+
{
25+
/* r = input
26+
* gen_x = -A/(1+2r^2) # 2 is nonsquare
27+
* e = (gen_x^3 + Ax^2 + gen_x)^((q-1)/2) # legendre symbol
28+
* if e == 1 (square) or e == 0 (because gen_x == 0 and 2r^2 + 1 == 0)
29+
* u = gen_x
30+
* if e == -1 (nonsquare)
31+
* u = -gen_x - A
32+
*/
33+
int[] A = new int[10], one = new int[10], twor2 = new int[10], twor2plus1 = new int[10], twor2plus1inv = new int[10];
34+
int[] x = new int[10], e = new int[10], Atemp = new int[10], uneg = new int[10];
35+
int nonsquare;
36+
37+
fe_1.fe_1(one);
38+
fe_0.fe_0(A);
39+
A[0] = 486662; /* A = 486662 */
40+
41+
fe_sq2.fe_sq2(twor2, r); /* 2r^2 */
42+
fe_add.fe_add(twor2plus1, twor2, one); /* 1+2r^2 */
43+
fe_invert.fe_invert(twor2plus1inv, twor2plus1); /* 1/(1+2r^2) */
44+
fe_mul.fe_mul(x, twor2plus1inv, A); /* A/(1+2r^2) */
45+
fe_neg.fe_neg(x, x); /* gen_x = -A/(1+2r^2) */
46+
47+
fe_mont_rhs.fe_mont_rhs(e, x); /* e = gen_x^3 + Ax^2 + gen_x */
48+
nonsquare = legendre_is_nonsquare(e);
49+
50+
fe_0.fe_0(Atemp);
51+
fe_cmov.fe_cmov(Atemp, A, nonsquare); /* 0, or A if nonsquare */
52+
fe_add.fe_add(u, x, Atemp); /* gen_x, or gen_x+A if nonsquare */
53+
fe_neg.fe_neg(uneg, u); /* -gen_x, or -gen_x-A if nonsquare */
54+
fe_cmov.fe_cmov(u, uneg, nonsquare); /* gen_x, or -gen_x-A if nonsquare */
55+
}
56+
57+
public static void hash_to_point(Sha512 sha512provider, ge_p3 p, byte[] in)
58+
{
59+
byte[] hash = new byte[64];
60+
int[] h = new int[10], u = new int[10];
61+
ge_p3 p3 = new ge_p3();
62+
63+
sha512provider.calculateDigest(hash, in, in.length);
64+
65+
/* take the high bit as Edwards sign bit */
66+
byte sign_bit = (byte)((hash[31] & 0x80) >> 7);
67+
hash[31] &= 0x7F;
68+
fe_frombytes.fe_frombytes(h, hash);
69+
elligator(u, h);
70+
71+
ge_montx_to_p3.ge_montx_to_p3(p3, u, sign_bit);
72+
ge_scalarmult_cofactor.ge_scalarmult_cofactor(p, p3);
73+
}
74+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.whispersystems.curve25519.java;
2+
3+
public class fe_isequal {
4+
/*
5+
return 1 if f == g
6+
return 0 if f != g
7+
*/
8+
public static int fe_isequal(int[] f, int[] g)
9+
{
10+
int[] h = new int[10];
11+
fe_sub.fe_sub(h, f, g);
12+
return 1 ^ (1 & (fe_isnonzero.fe_isnonzero(h) >> 8));
13+
}
14+
15+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.whispersystems.curve25519.java;
2+
3+
public class fe_isreduced {
4+
public static boolean fe_isreduced(byte[] s)
5+
{
6+
int[] f = new int[10];
7+
byte[] strict = new byte[32];
8+
9+
fe_frombytes.fe_frombytes(f, s);
10+
fe_tobytes.fe_tobytes(strict, f);
11+
return crypto_verify_32.crypto_verify_32(strict, s) == 0;
12+
}
13+
14+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.whispersystems.curve25519.java;
2+
3+
public class fe_mont_rhs {
4+
public static void fe_mont_rhs(int[] v2, int[] u) {
5+
int[] A = new int[10], one= new int[10];
6+
int[] u2= new int[10], Au= new int[10], inner= new int[10];
7+
8+
fe_1.fe_1(one);
9+
fe_0.fe_0(A);
10+
A[0] = 486662; /* A = 486662 */
11+
12+
fe_sq.fe_sq(u2, u); /* u^2 */
13+
fe_mul.fe_mul(Au, A, u); /* Au */
14+
fe_add.fe_add(inner, u2, Au); /* u^2 + Au */
15+
fe_add.fe_add(inner, inner, one); /* u^2 + Au + 1 */
16+
fe_mul.fe_mul(v2, u, inner); /* u(u^2 + Au + 1) */
17+
}
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.whispersystems.curve25519.java;
2+
3+
public class fe_montx_to_edy {
4+
public static void fe_montx_to_edy(int[] y, int[] u)
5+
{
6+
/*
7+
y = (u - 1) / (u + 1)
8+
9+
NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp
10+
*/
11+
int[] one = new int[10], um1 = new int[10], up1 = new int[10];
12+
13+
fe_1.fe_1(one);
14+
fe_sub.fe_sub(um1, u, one);
15+
fe_add.fe_add(up1, u, one);
16+
fe_invert.fe_invert(up1, up1);
17+
fe_mul.fe_mul(y, um1, up1);
18+
}
19+
20+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.whispersystems.curve25519.java;
2+
3+
public class fe_sqrt {
4+
5+
/* sqrt(-1) */
6+
public static byte[] i_bytes = {
7+
(byte)0xb0, (byte)0xa0, 0x0e, 0x4a, 0x27, 0x1b, (byte)0xee, (byte)0xc4,
8+
0x78, (byte)0xe4, 0x2f, (byte)0xad, 0x06, 0x18, 0x43, 0x2f,
9+
(byte)0xa7, (byte)0xd7, (byte)0xfb, 0x3d, (byte)0x99, 0x00, 0x4d, 0x2b,
10+
0x0b, (byte)0xdf, (byte)0xc1, 0x4f, (byte)0x80, 0x24, (byte)0x83, 0x2b
11+
};
12+
13+
/* Preconditions: a is square or zero */
14+
15+
public static void fe_sqrt(int[] out, int[] a)
16+
{
17+
int[] exp = new int[10], b = new int[10], b2 = new int[10], bi = new int[10], i = new int[10];
18+
19+
fe_frombytes.fe_frombytes(i, i_bytes);
20+
fe_pow22523.fe_pow22523(exp, a); /* b = a^(q-5)/8 */
21+
22+
23+
fe_mul.fe_mul(b, a, exp); /* b = a * a^(q-5)/8 */
24+
fe_sq.fe_sq(b2, b); /* b^2 = a * a^(q-1)/4 */
25+
26+
/* note b^4 == a^2, so b^2 == a or -a
27+
* if b^2 != a, multiply it by sqrt(-1) */
28+
fe_mul.fe_mul(bi, b, i);
29+
fe_cmov.fe_cmov(b, bi, 1 ^ fe_isequal.fe_isequal(b2, a));
30+
fe_copy.fe_copy(out, b);
31+
32+
}
33+
34+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.whispersystems.curve25519.java;
2+
3+
public class ge_isneutral {
4+
/*
5+
return 1 if p is the neutral point
6+
return 0 otherwise
7+
*/
8+
9+
public static boolean ge_isneutral(ge_p3 p)
10+
{
11+
int[] zero = new int[10];
12+
fe_0.fe_0(zero);
13+
14+
/* Check if p == neutral element == (0, 1) */
15+
return (fe_isequal.fe_isequal(p.X, zero) & fe_isequal.fe_isequal(p.Y, p.Z)) == 1;
16+
}
17+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.whispersystems.curve25519.java;
2+
3+
public class ge_montx_to_p3 {
4+
/* sqrt(-(A+2)) */
5+
private static byte[] A_bytes = {
6+
0x06, 0x7e, 0x45, (byte)0xff, (byte)0xaa, 0x04, 0x6e, (byte)0xcc,
7+
(byte)0x82, 0x1a, 0x7d, 0x4b, (byte)0xd1, (byte)0xd3, (byte)0xa1, (byte)0xc5,
8+
0x7e, 0x4f, (byte)0xfc, 0x03, (byte)0xdc, 0x08, 0x7b, (byte)0xd2,
9+
(byte)0xbb, 0x06, (byte)0xa0, 0x60, (byte)0xf4, (byte)0xed, 0x26, 0x0f
10+
};
11+
12+
public static void ge_montx_to_p3(ge_p3 p, int[] u, byte ed_sign_bit)
13+
{
14+
int[] x = new int[10], y = new int[10], A = new int[10], v = new int[10], v2 = new int[10], iv = new int[10], nx = new int[10];
15+
16+
fe_frombytes.fe_frombytes(A, A_bytes);
17+
18+
/* given u, recover edwards y */
19+
/* given u, recover v */
20+
/* given u and v, recover edwards gen_x */
21+
22+
fe_montx_to_edy.fe_montx_to_edy(y, u); /* y = (u - 1) / (u + 1) */
23+
24+
fe_mont_rhs.fe_mont_rhs(v2, u); /* v^2 = u(u^2 + Au + 1) */
25+
fe_sqrt.fe_sqrt(v, v2); /* v = sqrt(v^2) */
26+
27+
fe_mul.fe_mul(x, u, A); /* gen_x = u * sqrt(-(A+2)) */
28+
fe_invert.fe_invert(iv, v); /* 1/v */
29+
fe_mul.fe_mul(x, x, iv); /* gen_x = (u/v) * sqrt(-(A+2)) */
30+
31+
fe_neg.fe_neg(nx, x); /* negate gen_x to match sign bit */
32+
fe_cmov.fe_cmov(x, nx, fe_isnegative.fe_isnegative(x) ^ ed_sign_bit);
33+
34+
fe_copy.fe_copy(p.X, x);
35+
fe_copy.fe_copy(p.Y, y);
36+
fe_1.fe_1(p.Z);
37+
fe_mul.fe_mul(p.T, p.X, p.Y);
38+
}
39+
}

0 commit comments

Comments
 (0)