Skip to content

Commit 7eb3c57

Browse files
committed
Further clean up and some additional unit tests.
1 parent ab9b743 commit 7eb3c57

File tree

5 files changed

+126
-17
lines changed

5 files changed

+126
-17
lines changed

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
public class EdDSAPublicKey implements EdDSAKey, PublicKey {
4141
private static final long serialVersionUID = 9837459837498475L;
4242
private final GroupElement A;
43-
private final GroupElement Aneg;
43+
private GroupElement Aneg = null;
4444
private final byte[] Abyte;
4545
private final EdDSAParameterSpec edDsaSpec;
4646

@@ -52,7 +52,6 @@ public class EdDSAPublicKey implements EdDSAKey, PublicKey {
5252

5353
public EdDSAPublicKey(EdDSAPublicKeySpec spec) {
5454
this.A = spec.getA();
55-
this.Aneg = spec.getNegativeA();
5655
this.Abyte = this.A.toByteArray();
5756
this.edDsaSpec = spec.getParams();
5857
}
@@ -250,7 +249,13 @@ public GroupElement getA() {
250249
}
251250

252251
public GroupElement getNegativeA() {
253-
return Aneg;
252+
// Only read Aneg once, otherwise read re-ordering might occur between here and return. Requires all GroupElement's fields to be final.
253+
GroupElement ourAneg = Aneg;
254+
if(ourAneg == null) {
255+
ourAneg = A.negate();
256+
Aneg = ourAneg;
257+
}
258+
return ourAneg;
254259
}
255260

256261
public byte[] getAbyte() {

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

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public enum Representation {
5050
P2,
5151
/** Extended ($P^3$): $(X:Y:Z:T)$ satisfying $x=X/Z, y=Y/Z, XY=ZT$ */
5252
P3,
53-
/** P3 but also populate dblPrecmp */
53+
/** Can only be requested. Results in P3 representation but also populates dblPrecmp. */
5454
P3PrecomputedDouble,
5555
/** Completed ($P \times P$): $((X:Z),(Y:T))$ satisfying $x=X/Z, y=Y/T$ */
5656
P1P1,
@@ -74,11 +74,30 @@ public static GroupElement p2(
7474
final FieldElement X,
7575
final FieldElement Y,
7676
final FieldElement Z) {
77-
return new GroupElement(curve, Representation.P2, X, Y, Z, null, false);
77+
return new GroupElement(curve, Representation.P2, X, Y, Z, null);
7878
}
7979

8080
/**
81-
* Creates a new group element in P3 representation.
81+
* Creates a new group element in P3 representation, without pre-computation.
82+
*
83+
* @param curve The curve.
84+
* @param X The $X$ coordinate.
85+
* @param Y The $Y$ coordinate.
86+
* @param Z The $Z$ coordinate.
87+
* @param T The $T$ coordinate.
88+
* @return The group element in P3 representation.
89+
*/
90+
public static GroupElement p3(
91+
final Curve curve,
92+
final FieldElement X,
93+
final FieldElement Y,
94+
final FieldElement Z,
95+
final FieldElement T) {
96+
return p3(curve, X, Y, Z, T, false);
97+
}
98+
99+
/**
100+
* Creates a new group element in P3 representation, potentially with pre-computation.
82101
*
83102
* @param curve The curve.
84103
* @param X The $X$ coordinate.
@@ -114,7 +133,7 @@ public static GroupElement p1p1(
114133
final FieldElement Y,
115134
final FieldElement Z,
116135
final FieldElement T) {
117-
return new GroupElement(curve, Representation.P1P1, X, Y, Z, T, false);
136+
return new GroupElement(curve, Representation.P1P1, X, Y, Z, T);
118137
}
119138

120139
/**
@@ -131,7 +150,7 @@ public static GroupElement precomp(
131150
final FieldElement ypx,
132151
final FieldElement ymx,
133152
final FieldElement xy2d) {
134-
return new GroupElement(curve, Representation.PRECOMP, ypx, ymx, xy2d, null, false);
153+
return new GroupElement(curve, Representation.PRECOMP, ypx, ymx, xy2d, null);
135154
}
136155

137156
/**
@@ -150,7 +169,7 @@ public static GroupElement cached(
150169
final FieldElement YmX,
151170
final FieldElement Z,
152171
final FieldElement T2d) {
153-
return new GroupElement(curve, Representation.CACHED, YpX, YmX, Z, T2d, false);
172+
return new GroupElement(curve, Representation.CACHED, YpX, YmX, Z, T2d);
154173
}
155174

156175
/**
@@ -200,7 +219,27 @@ public static GroupElement cached(
200219
final GroupElement[] dblPrecmp;
201220

202221
/**
203-
* Creates a group element for a curve.
222+
* Creates a group element for a curve, without any pre-computation.
223+
*
224+
* @param curve The curve.
225+
* @param repr The representation used to represent the group element.
226+
* @param X The $X$ coordinate.
227+
* @param Y The $Y$ coordinate.
228+
* @param Z The $Z$ coordinate.
229+
* @param T The $T$ coordinate.
230+
*/
231+
public GroupElement(
232+
final Curve curve,
233+
final Representation repr,
234+
final FieldElement X,
235+
final FieldElement Y,
236+
final FieldElement Z,
237+
final FieldElement T) {
238+
this(curve, repr, X, Y, Z, T, false);
239+
}
240+
241+
/**
242+
* Creates a group element for a curve, with optional pre-computation.
204243
*
205244
* @param curve The curve.
206245
* @param repr The representation used to represent the group element.
@@ -229,7 +268,7 @@ public GroupElement(
229268
}
230269

231270
/**
232-
* Creates a group element for a curve from a given encoded point.
271+
* Creates a group element for a curve from a given encoded point. No pre-computation.
233272
* <p>
234273
* A point $(x,y)$ is encoded by storing $y$ in bit 0 to bit 254 and the sign of $x$ in bit 255.
235274
* $x$ is recovered in the following way:
@@ -249,7 +288,7 @@ public GroupElement(final Curve curve, final byte[] s) {
249288
}
250289

251290
/**
252-
* Creates a group element for a curve from a given encoded point.
291+
* Creates a group element for a curve from a given encoded point. With optional pre-computation.
253292
* <p>
254293
* A point $(x,y)$ is encoded by storing $y$ in bit 0 to bit 254 and the sign of $x$ in bit 255.
255294
* $x$ is recovered in the following way:
@@ -265,7 +304,6 @@ public GroupElement(final Curve curve, final byte[] s) {
265304
* @param s The encoded point.
266305
* @param precomputeSingleAndDouble If true, populate both precmp and dblPrecmp, else set both to null.
267306
*/
268-
// TODO
269307
public GroupElement(final Curve curve, final byte[] s, boolean precomputeSingleAndDouble) {
270308
FieldElement x, y, yy, u, v, v3, vxx, check;
271309
y = curve.getField().fromByteArray(s);

test/net/i2p/crypto/eddsa/math/GroupElementTest.java

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,24 @@ public void testP2() {
6868
}
6969

7070
/**
71-
* Test method for {@link GroupElement#p3(Curve, FieldElement, FieldElement, FieldElement, FieldElement, boolean)}.
71+
* Test method for {@link GroupElement#p3(Curve, FieldElement, FieldElement, FieldElement, FieldElement)}.
7272
*/
7373
@Test
7474
public void testP3() {
75+
final GroupElement t = GroupElement.p3(curve, ZERO, ONE, ONE, ZERO);
76+
assertThat(t.curve, is(equalTo(curve)));
77+
assertThat(t.repr, is(GroupElement.Representation.P3));
78+
assertThat(t.X, is(ZERO));
79+
assertThat(t.Y, is(ONE));
80+
assertThat(t.Z, is(ONE));
81+
assertThat(t.T, is(ZERO));
82+
}
83+
84+
/**
85+
* Test method for {@link GroupElement#p3(Curve, FieldElement, FieldElement, FieldElement, FieldElement, boolean)}.
86+
*/
87+
@Test
88+
public void testP3WithExplicitFlag() {
7589
final GroupElement t = GroupElement.p3(curve, ZERO, ONE, ONE, ZERO, false);
7690
assertThat(t.curve, is(equalTo(curve)));
7791
assertThat(t.repr, is(GroupElement.Representation.P3));
@@ -124,10 +138,24 @@ public void testCached() {
124138
}
125139

126140
/**
127-
* Test method for {@link GroupElement#GroupElement(Curve, GroupElement.Representation, FieldElement, FieldElement, FieldElement, FieldElement, boolean)}.
141+
* Test method for {@link GroupElement#GroupElement(Curve, GroupElement.Representation, FieldElement, FieldElement, FieldElement, FieldElement)}.
128142
*/
129143
@Test
130144
public void testGroupElementCurveRepresentationFieldElementFieldElementFieldElementFieldElement() {
145+
final GroupElement t = new GroupElement(curve, GroupElement.Representation.P3, ZERO, ONE, ONE, ZERO);
146+
assertThat(t.curve, is(equalTo(curve)));
147+
assertThat(t.repr, is(GroupElement.Representation.P3));
148+
assertThat(t.X, is(ZERO));
149+
assertThat(t.Y, is(ONE));
150+
assertThat(t.Z, is(ONE));
151+
assertThat(t.T, is(ZERO));
152+
}
153+
154+
/**
155+
* Test method for {@link GroupElement#GroupElement(Curve, GroupElement.Representation, FieldElement, FieldElement, FieldElement, FieldElement, boolean)}.
156+
*/
157+
@Test
158+
public void testGroupElementCurveRepresentationFieldElementFieldElementFieldElementFieldElementWithExplicitFlag() {
131159
final GroupElement t = new GroupElement(curve, GroupElement.Representation.P3, ZERO, ONE, ONE, ZERO, false);
132160
assertThat(t.curve, is(equalTo(curve)));
133161
assertThat(t.repr, is(GroupElement.Representation.P3));
@@ -157,7 +185,7 @@ public void testToAndFromByteArray() {
157185
@Test
158186
public void testGroupElementByteArray() {
159187
final GroupElement t = new GroupElement(curve, BYTES_PKR);
160-
final GroupElement s = GroupElement.p3(curve, PKR[0], PKR[1], ONE, PKR[0].multiply(PKR[1]),false);
188+
final GroupElement s = GroupElement.p3(curve, PKR[0], PKR[1], ONE, PKR[0].multiply(PKR[1]));
161189
assertThat(t, is(equalTo(s)));
162190
}
163191

@@ -391,6 +419,29 @@ public void toP3ReturnsExpectedResultIfGroupElementHasP3Representation() {
391419
}
392420
}
393421

422+
@Test
423+
public void toP3PrecomputeDoubleReturnsExpectedResultIfGroupElementHasP1P1Representation() {
424+
for (int i=0; i<10; i++) {
425+
// Arrange:
426+
final GroupElement g = MathUtils.toRepresentation(MathUtils.getRandomGroupElement(), GroupElement.Representation.P1P1);
427+
428+
// Act:
429+
final GroupElement h1 = g.toP3PrecomputeDouble();
430+
final GroupElement h2 = MathUtils.toRepresentation(g, GroupElement.Representation.P3PrecomputedDouble);
431+
432+
// Assert:
433+
Assert.assertThat(h1, IsEqual.equalTo(h2));
434+
Assert.assertThat(h1.getRepresentation(), IsEqual.equalTo(GroupElement.Representation.P3));
435+
Assert.assertThat(h1.getX(), IsEqual.equalTo(g.getX().multiply(g.getT())));
436+
Assert.assertThat(h1.getY(), IsEqual.equalTo(g.getY().multiply(g.getZ())));
437+
Assert.assertThat(h1.getZ(), IsEqual.equalTo(g.getZ().multiply(g.getT())));
438+
Assert.assertThat(h1.getT(), IsEqual.equalTo(g.getX().multiply(g.getY())));
439+
Assert.assertThat(h1.precmp, IsNull.nullValue());
440+
Assert.assertThat(h1.dblPrecmp, IsNull.notNullValue());
441+
Assert.assertThat(h1.dblPrecmp, IsEqual.equalTo(h2.dblPrecmp));
442+
}
443+
}
444+
394445
@Test (expected = IllegalArgumentException.class)
395446
public void toCachedThrowsIfGroupElementHasP2Representation() {
396447
// Arrange:
@@ -529,7 +580,7 @@ public void dblReturnsExpectedResult() {
529580

530581
@Test
531582
public void addingNeutralGroupElementDoesNotChangeGroupElement() {
532-
final GroupElement neutral = GroupElement.p3(curve, curve.getField().ZERO, curve.getField().ONE, curve.getField().ONE, curve.getField().ZERO, false);
583+
final GroupElement neutral = GroupElement.p3(curve, curve.getField().ZERO, curve.getField().ONE, curve.getField().ONE, curve.getField().ZERO);
533584
for (int i=0; i<1000; i++) {
534585
// Arrange:
535586
final GroupElement g = MathUtils.getRandomGroupElement();

test/net/i2p/crypto/eddsa/math/MathUtils.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ public static GroupElement toRepresentation(final GroupElement g, final GroupEle
260260
switch (g.getRepresentation()) {
261261
case P2:
262262
case P3:
263+
case P3PrecomputedDouble:
263264
x = gX.multiply(gZ.modInverse(getQ())).mod(getQ());
264265
y = gY.multiply(gZ.modInverse(getQ())).mod(getQ());
265266
break;
@@ -294,6 +295,13 @@ public static GroupElement toRepresentation(final GroupElement g, final GroupEle
294295
toFieldElement(y),
295296
getField().ONE,
296297
toFieldElement(x.multiply(y).mod(getQ())), false);
298+
case P3PrecomputedDouble:
299+
return GroupElement.p3(
300+
curve,
301+
toFieldElement(x),
302+
toFieldElement(y),
303+
getField().ONE,
304+
toFieldElement(x.multiply(y).mod(getQ())), true);
297305
case P1P1:
298306
return GroupElement.p1p1(
299307
curve,

test/net/i2p/crypto/eddsa/spec/EdDSANamedCurveTableTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212
package net.i2p.crypto.eddsa.spec;
1313

14+
import static net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable.ED_25519;
1415
import static org.hamcrest.Matchers.*;
1516
import static org.junit.Assert.*;
1617

@@ -33,4 +34,10 @@ public void curveNamesAreCaseInspecific() {
3334
assertThat(lower, is(equalTo(mixed)));
3435
assertThat(upper, is(equalTo(mixed)));
3536
}
37+
38+
@Test
39+
public void testConstant() {
40+
EdDSANamedCurveSpec spec = EdDSANamedCurveTable.getByName("Ed25519");
41+
assertThat("Named curve and constant should match", spec, is(equalTo(ED_25519)));
42+
}
3643
}

0 commit comments

Comments
 (0)