Skip to content

Commit 23d5126

Browse files
committed
Refactored BigInteger-dependent code into a subpackage
Sign/verify tests fail, but all other tests pass. The problem is probably in ScalarOps somewhere.
1 parent c2bbb69 commit 23d5126

29 files changed

+1278
-1193
lines changed

src/net/i2p/crypto/eddsa/EdDSAEngine.java

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package net.i2p.crypto.eddsa;
22

33
import java.io.ByteArrayOutputStream;
4-
import java.math.BigInteger;
54
import java.nio.ByteBuffer;
65
import java.security.InvalidKeyException;
76
import java.security.MessageDigest;
@@ -13,9 +12,8 @@
1312
import java.util.Arrays;
1413

1514
import net.i2p.crypto.eddsa.math.Curve;
16-
import net.i2p.crypto.eddsa.math.FieldElement;
1715
import net.i2p.crypto.eddsa.math.GroupElement;
18-
import net.i2p.crypto.eddsa.math.LittleEndianEncoding;
16+
import net.i2p.crypto.eddsa.math.ScalarOps;
1917

2018
/**
2119
* @author str4d
@@ -25,7 +23,6 @@ public class EdDSAEngine extends Signature {
2523
private MessageDigest digest;
2624
private final ByteArrayOutputStream baos;
2725
private EdDSAKey key;
28-
private static final LittleEndianEncoding leEnc = new LittleEndianEncoding();
2926

3027
/**
3128
* No specific hash requested, allows any EdDSA key.
@@ -112,20 +109,16 @@ protected void engineUpdate(byte[] b, int off, int len)
112109
@Override
113110
protected byte[] engineSign() throws SignatureException {
114111
Curve curve = key.getParams().getCurve();
115-
BigInteger l = key.getParams().getL();
116-
BigInteger a = ((EdDSAPrivateKey) key).geta();
112+
ScalarOps sc = key.getParams().getScalarOps();
113+
byte[] a = ((EdDSAPrivateKey) key).geta();
117114

118115
byte[] message = baos.toByteArray();
119116
// r = H(h_b,...,h_2b-1,M)
120117
byte[] r = digest.digest(message);
121-
// From the Ed25519 paper:
122-
// Here we interpret 2b-bit strings in little-endian form as integers in
123-
// {0, 1,..., 2^(2b)-1}.
124-
BigInteger rBI = leEnc.decode(r);
125118

126119
// r mod l
127120
// Reduces r from 64 bytes to 32 bytes
128-
r = leEnc.encode(rBI.mod(l), curve.getField().getb()/8);
121+
r = sc.reduce(r);
129122

130123
// R = rB
131124
GroupElement R = key.getParams().getB().scalarMultiply(r);
@@ -134,12 +127,14 @@ protected byte[] engineSign() throws SignatureException {
134127
// S = (r + H(Rbar,Abar,M)*a) mod l
135128
digest.update(Rbyte);
136129
digest.update(((EdDSAPrivateKey) key).getAbyte());
137-
FieldElement S = curve.fromBigInteger(leEnc.decode(digest.digest(message)).multiply(a).add(rBI).mod(l));
130+
byte[] h = digest.digest(message);
131+
h = sc.reduce(h);
132+
byte[] S = sc.multiplyAndAdd(h, a, r);
138133

139134
// R+S
140135
int b = curve.getField().getb();
141136
ByteBuffer out = ByteBuffer.allocate(b/4);
142-
out.put(Rbyte).put(S.toByteArray());
137+
out.put(Rbyte).put(S);
143138
return out.array();
144139
}
145140

@@ -158,7 +153,7 @@ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
158153
byte[] h = digest.digest(message);
159154

160155
// h mod l
161-
h = leEnc.encode(leEnc.decode(h).mod(key.getParams().getL()), b/8);
156+
h = key.getParams().getScalarOps().reduce(h);
162157

163158
byte[] Sbyte = Arrays.copyOfRange(sigBytes, b/8, b/4);
164159
// R = SB - H(Rbar,Abar,M)A

src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package net.i2p.crypto.eddsa;
22

3-
import java.math.BigInteger;
43
import java.security.PrivateKey;
54

65
import net.i2p.crypto.eddsa.math.GroupElement;
@@ -16,7 +15,7 @@ public class EdDSAPrivateKey implements EdDSAKey, PrivateKey {
1615
private static final long serialVersionUID = 23495873459878957L;
1716
private transient final byte[] seed;
1817
private transient final byte[] h;
19-
private transient final BigInteger a;
18+
private transient final byte[] a;
2019
private transient final GroupElement A;
2120
private transient final byte[] Abyte;
2221
private transient final EdDSAParameterSpec edDsaSpec;
@@ -55,7 +54,7 @@ public byte[] getH() {
5554
return h;
5655
}
5756

58-
public BigInteger geta() {
57+
public byte[] geta() {
5958
return a;
6059
}
6160

src/net/i2p/crypto/eddsa/Utils.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,19 @@ public static int negative(int b) {
3636
public static int bit(byte[] h, int i) {
3737
return (h[i/8] >> (i%8)) & 1;
3838
}
39+
40+
/**
41+
* Converts a hex string to bytes.
42+
* @param s the hex string to be converted.
43+
* @return the byte[]
44+
*/
45+
public static byte[] hexToBytes(String s) {
46+
int len = s.length();
47+
byte[] data = new byte[len / 2];
48+
for (int i = 0; i < len; i += 2) {
49+
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
50+
+ Character.digit(s.charAt(i+1), 16));
51+
}
52+
return data;
53+
}
3954
}
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package net.i2p.crypto.eddsa.math;
22

3-
import java.math.BigInteger;
3+
import net.i2p.crypto.eddsa.Utils;
44

55
public class Constants {
6-
public static final BigInteger ZERO = BigInteger.ZERO;
7-
public static final BigInteger ONE = BigInteger.ONE;
8-
public static final BigInteger TWO = BigInteger.valueOf(2);
9-
public static final BigInteger FOUR = BigInteger.valueOf(4);
10-
public static final BigInteger FIVE = BigInteger.valueOf(5);
11-
public static final BigInteger EIGHT = BigInteger.valueOf(8);
6+
public static final byte[] ZERO = Utils.hexToBytes("0000000000000000000000000000000000000000000000000000000000000000");
7+
public static final byte[] ONE = Utils.hexToBytes("0100000000000000000000000000000000000000000000000000000000000000");
8+
public static final byte[] TWO = Utils.hexToBytes("0200000000000000000000000000000000000000000000000000000000000000");
9+
public static final byte[] FOUR = Utils.hexToBytes("0400000000000000000000000000000000000000000000000000000000000000");
10+
public static final byte[] FIVE = Utils.hexToBytes("0500000000000000000000000000000000000000000000000000000000000000");
11+
public static final byte[] EIGHT = Utils.hexToBytes("0800000000000000000000000000000000000000000000000000000000000000");
1212
}

src/net/i2p/crypto/eddsa/math/Curve.java

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package net.i2p.crypto.eddsa.math;
22

33
import java.io.Serializable;
4-
import java.math.BigInteger;
54

65
/**
76
* A twisted Edwards curve.
@@ -14,23 +13,20 @@ public class Curve implements Serializable {
1413
private final Field f;
1514
private final FieldElement d;
1615
private final FieldElement d2;
17-
private final FieldElement I;
18-
private final FieldElement one;
1916

2017
private final GroupElement zeroP2;
2118
private final GroupElement zeroP3;
2219
private final GroupElement zeroPrecomp;
2320

24-
public Curve(Field f, BigInteger d) {
21+
public Curve(Field f, byte[] d) {
2522
this.f = f;
26-
this.d = fromBigInteger(d);
23+
this.d = f.fromByteArray(d);
2724
this.d2 = this.d.add(this.d);
28-
this.I = fromBigInteger(Constants.TWO).modPow(f.getQ().subtract(Constants.ONE).divide(Constants.FOUR), f.getQ());
2925

30-
FieldElement zero = fromBigInteger(Constants.ZERO);
31-
one = fromBigInteger(Constants.ONE);
26+
FieldElement zero = f.zero;
27+
FieldElement one = f.one;
3228
zeroP2 = GroupElement.p2(this, zero, one, one);
33-
zeroP3 = createPoint(Constants.ZERO, Constants.ONE);
29+
zeroP3 = GroupElement.p3(this, zero, one, one, zero);
3430
zeroPrecomp = GroupElement.precomp(this, one, one, zero);
3531
}
3632

@@ -46,14 +42,6 @@ public FieldElement get2D() {
4642
return d2;
4743
}
4844

49-
public FieldElement getI() {
50-
return I;
51-
}
52-
53-
public FieldElement getOne() {
54-
return one;
55-
}
56-
5745
public GroupElement getZero(GroupElement.Representation repr) {
5846
switch (repr) {
5947
case P2:
@@ -67,22 +55,8 @@ public GroupElement getZero(GroupElement.Representation repr) {
6755
}
6856
}
6957

70-
public FieldElement fromBigInteger(BigInteger x) {
71-
return new FieldElement(f, x);
72-
}
73-
74-
public FieldElement fromByteArray(byte[] x) {
75-
return new FieldElement(f, x);
76-
}
77-
78-
public GroupElement createPoint(BigInteger x, BigInteger y) {
79-
return createPoint(x, y, false);
80-
}
81-
82-
public GroupElement createPoint(BigInteger x, BigInteger y, boolean precompute) {
83-
FieldElement X = fromBigInteger(x);
84-
FieldElement Y = fromBigInteger(y);
85-
GroupElement ge = GroupElement.p3(this, X, Y, one, X.multiply(Y));
58+
public GroupElement createPoint(byte[] P, boolean precompute) {
59+
GroupElement ge = new GroupElement(this, P);
8660
if (precompute)
8761
ge.precompute(true);
8862
return ge;
Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,31 @@
11
package net.i2p.crypto.eddsa.math;
22

3-
import java.math.BigInteger;
4-
53
/**
64
* Common interface for all (b-1)-bit encodings of elements
75
* of EdDSA finite fields.
86
* @author str4d
97
*
108
*/
11-
public interface Encoding {
12-
public byte[] encode(BigInteger x, int len);
13-
public BigInteger decode(byte[] in);
9+
public abstract class Encoding {
10+
protected Field f;
11+
12+
public void setField(Field f) {
13+
this.f = f;
14+
}
15+
16+
/**
17+
* Encode a FieldElement in its (b-1)-bit encoding.
18+
* @return the (b-1)-bit encoding of this FieldElement.
19+
*/
20+
public abstract byte[] encode(FieldElement x);
21+
22+
/**
23+
* Decode a FieldElement from its (b-1)-bit encoding.
24+
* The highest bit is masked out.
25+
* @param val the (b-1)-bit encoding of a FieldElement.
26+
* @return the FieldElement represented by 'val'.
27+
*/
28+
public abstract FieldElement decode(byte[] in);
1429

1530
/**
1631
* From the Ed25519 paper:
@@ -20,5 +35,5 @@ public interface Encoding {
2035
* elements of F_q are {1, 3, 5,..., q-2}.
2136
* @return
2237
*/
23-
public boolean isNegative(BigInteger x);
38+
public abstract boolean isNegative(FieldElement x);
2439
}

src/net/i2p/crypto/eddsa/math/Field.java

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package net.i2p.crypto.eddsa.math;
22

33
import java.io.Serializable;
4-
import java.math.BigInteger;
54

65
/**
76
* An EdDSA finite field. Includes several pre-computed values.
@@ -10,55 +9,76 @@
109
*/
1110
public class Field implements Serializable {
1211
private static final long serialVersionUID = 8746587465875676L;
12+
13+
public final FieldElement zero;
14+
public final FieldElement one;
15+
public final FieldElement two;
16+
public final FieldElement four;
17+
public final FieldElement five;
18+
public final FieldElement eight;
19+
1320
private final int b;
14-
private final BigInteger q;
21+
private final FieldElement q;
1522
/**
1623
* q-2
1724
*/
18-
private final BigInteger qm2;
25+
private final FieldElement qm2;
1926
/**
2027
* (q-5) / 8
2128
*/
22-
private final BigInteger qm5d8;
23-
/**
24-
* Mask where only the first b-1 bits are set.
25-
*/
26-
private final BigInteger mask;
29+
private final FieldElement qm5d8;
2730
private final Encoding enc;
31+
private final FieldElement I;
2832

29-
public Field(int b, BigInteger q, Encoding enc) {
33+
public Field(int b, byte[] q, Encoding enc) {
3034
this.b = b;
31-
this.q = q;
32-
this.qm2 = q.subtract(Constants.TWO);
33-
this.qm5d8 = q.subtract(Constants.FIVE).divide(Constants.EIGHT);
34-
this.mask = Constants.ONE.shiftLeft(b-1).subtract(Constants.ONE);
3535
this.enc = enc;
36+
this.enc.setField(this);
37+
38+
this.q = fromByteArray(q);
39+
40+
// Set up constants
41+
zero = fromByteArray(Constants.ZERO);
42+
one = fromByteArray(Constants.ONE);
43+
two = fromByteArray(Constants.TWO);
44+
four = fromByteArray(Constants.FOUR);
45+
five = fromByteArray(Constants.FIVE);
46+
eight = fromByteArray(Constants.EIGHT);
47+
48+
// Precompute values
49+
qm2 = this.q.subtract(two);
50+
qm5d8 = this.q.subtract(five).divide(eight);
51+
I = two.pow(this.q.subtract(one).divide(four));
52+
}
53+
54+
public FieldElement fromByteArray(byte[] x) {
55+
return enc.decode(x);
3656
}
3757

3858
public int getb() {
3959
return b;
4060
}
4161

42-
public BigInteger getQ() {
62+
public FieldElement getQ() {
4363
return q;
4464
}
4565

46-
public BigInteger getQm2() {
66+
public FieldElement getQm2() {
4767
return qm2;
4868
}
4969

50-
public BigInteger getQm5d8() {
70+
public FieldElement getQm5d8() {
5171
return qm5d8;
5272
}
5373

54-
public BigInteger getMask() {
55-
return mask;
56-
}
57-
5874
public Encoding getEncoding(){
5975
return enc;
6076
}
6177

78+
public FieldElement getI() {
79+
return I;
80+
}
81+
6282
@Override
6383
public int hashCode() {
6484
return q.hashCode();

0 commit comments

Comments
 (0)