Test: Backport EdDSA junit changes from github; fixes NPE in 2 tests

This commit is contained in:
zzz
2018-07-20 15:25:15 +00:00
parent c35d1583d4
commit 2800791f00
11 changed files with 432 additions and 327 deletions

View File

@ -329,6 +329,7 @@
<include name="**/*IT.java" if="runIntegrationTests" />
<exclude name="**/ElGamalAESEngineTest.java" />
<exclude name="**/StructureTest.java" />
<exclude name="**/AbstractFieldElementTest.java" />
<!-- DataHelperTest is *very* slow with cobertura -->
<!--
<exclude name="**/DataHelperTest.java" />

View File

@ -1,7 +1,8 @@
package net.i2p.crypto.eddsa;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.nio.charset.Charset;
import java.security.MessageDigest;
@ -34,9 +35,9 @@ public class EdDSAEngineTest {
@Test
public void testSign() throws Exception {
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
//Signature sgr = Signature.getInstance("EdDSA", "I2P");
Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512");
Signature sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
for (Ed25519TestVectors.TestTuple testCase : Ed25519TestVectors.testCases) {
EdDSAPrivateKeySpec privKey = new EdDSAPrivateKeySpec(testCase.seed, spec);
@ -52,10 +53,9 @@ public class EdDSAEngineTest {
@Test
public void testVerify() throws Exception {
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
//Signature sgr = Signature.getInstance("EdDSA", "I2P");
Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512");
Signature sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
for (Ed25519TestVectors.TestTuple testCase : Ed25519TestVectors.testCases) {
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(testCase.pk, spec);
PublicKey vKey = new EdDSAPublicKey(pubKey);
@ -73,11 +73,10 @@ public class EdDSAEngineTest {
*/
@Test
public void testVerifyWrongSigLength() throws Exception {
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
//Signature sgr = Signature.getInstance("EdDSA", "I2P");
Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(TEST_PK,
EdDSANamedCurveTable.getByName("ed25519-sha-512"));
Signature sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(TEST_PK, spec);
PublicKey vKey = new EdDSAPublicKey(pubKey);
sgr.initVerify(vKey);
@ -90,9 +89,8 @@ public class EdDSAEngineTest {
@Test
public void testSignResetsForReuse() throws Exception {
Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512");
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
Signature sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
EdDSAPrivateKeySpec privKey = new EdDSAPrivateKeySpec(TEST_SEED, spec);
PrivateKey sKey = new EdDSAPrivateKey(privKey);
sgr.initSign(sKey);
@ -108,10 +106,9 @@ public class EdDSAEngineTest {
@Test
public void testVerifyResetsForReuse() throws Exception {
Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(TEST_PK,
EdDSANamedCurveTable.getByName("ed25519-sha-512"));
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
Signature sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(TEST_PK, spec);
PublicKey vKey = new EdDSAPublicKey(pubKey);
sgr.initVerify(vKey);
@ -126,9 +123,8 @@ public class EdDSAEngineTest {
@Test
public void testSignOneShotMode() throws Exception {
Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512");
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
Signature sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
EdDSAPrivateKeySpec privKey = new EdDSAPrivateKeySpec(TEST_SEED, spec);
PrivateKey sKey = new EdDSAPrivateKey(privKey);
sgr.initSign(sKey);
@ -141,10 +137,9 @@ public class EdDSAEngineTest {
@Test
public void testVerifyOneShotMode() throws Exception {
Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(TEST_PK,
EdDSANamedCurveTable.getByName("ed25519-sha-512"));
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
Signature sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(TEST_PK, spec);
PublicKey vKey = new EdDSAPublicKey(pubKey);
sgr.initVerify(vKey);
sgr.setParameter(EdDSAEngine.ONE_SHOT_MODE);
@ -156,9 +151,8 @@ public class EdDSAEngineTest {
@Test
public void testSignOneShotModeMultipleUpdates() throws Exception {
Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512");
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
Signature sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
EdDSAPrivateKeySpec privKey = new EdDSAPrivateKeySpec(TEST_SEED, spec);
PrivateKey sKey = new EdDSAPrivateKey(privKey);
sgr.initSign(sKey);
@ -173,10 +167,9 @@ public class EdDSAEngineTest {
@Test
public void testVerifyOneShotModeMultipleUpdates() throws Exception {
Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(TEST_PK,
EdDSANamedCurveTable.getByName("ed25519-sha-512"));
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(TEST_PK, spec);
Signature sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
PublicKey vKey = new EdDSAPublicKey(pubKey);
sgr.initVerify(vKey);
sgr.setParameter(EdDSAEngine.ONE_SHOT_MODE);
@ -190,10 +183,9 @@ public class EdDSAEngineTest {
@Test
public void testSignOneShot() throws Exception {
EdDSAEngine sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512");
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
EdDSAPrivateKeySpec privKey = new EdDSAPrivateKeySpec(TEST_SEED, spec);
EdDSAEngine sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
PrivateKey sKey = new EdDSAPrivateKey(privKey);
sgr.initSign(sKey);
@ -202,10 +194,9 @@ public class EdDSAEngineTest {
@Test
public void testVerifyOneShot() throws Exception {
EdDSAEngine sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(TEST_PK,
EdDSANamedCurveTable.getByName("ed25519-sha-512"));
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(TEST_PK, spec);
EdDSAEngine sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
PublicKey vKey = new EdDSAPublicKey(pubKey);
sgr.initVerify(vKey);

View File

@ -0,0 +1,232 @@
package net.i2p.crypto.eddsa.math;
import net.i2p.crypto.eddsa.math.*;
import org.hamcrest.core.*;
import org.junit.*;
import java.math.BigInteger;
/**
* Tests rely on the BigInteger class.
*/
public abstract class AbstractFieldElementTest {
protected abstract FieldElement getRandomFieldElement();
protected abstract BigInteger toBigInteger(FieldElement f);
protected abstract BigInteger getQ();
protected abstract Field getField();
// region isNonZero
protected abstract FieldElement getZeroFieldElement();
protected abstract FieldElement getNonZeroFieldElement();
@Test
public void isNonZeroReturnsFalseIfFieldElementIsZero() {
// Act:
final FieldElement f = getZeroFieldElement();
// Assert:
Assert.assertThat(f.isNonZero(), IsEqual.equalTo(false));
}
@Test
public void isNonZeroReturnsTrueIfFieldElementIsNonZero() {
// Act:
final FieldElement f = getNonZeroFieldElement();
// Assert:
Assert.assertThat(f.isNonZero(), IsEqual.equalTo(true));
}
// endregion
// region mod q arithmetic
@Test
public void addReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = getRandomFieldElement();
final FieldElement f2 = getRandomFieldElement();
final BigInteger b1 = toBigInteger(f1);
final BigInteger b2 = toBigInteger(f2);
// Act:
final FieldElement f3 = f1.add(f2);
final BigInteger b3 = toBigInteger(f3).mod(getQ());
// Assert:
Assert.assertThat(b3, IsEqual.equalTo(b1.add(b2).mod(getQ())));
}
}
@Test
public void subtractReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = getRandomFieldElement();
final FieldElement f2 = getRandomFieldElement();
final BigInteger b1 = toBigInteger(f1);
final BigInteger b2 = toBigInteger(f2);
// Act:
final FieldElement f3 = f1.subtract(f2);
final BigInteger b3 = toBigInteger(f3).mod(getQ());
// Assert:
Assert.assertThat(b3, IsEqual.equalTo(b1.subtract(b2).mod(getQ())));
}
}
@Test
public void negateReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = getRandomFieldElement();
final BigInteger b1 = toBigInteger(f1);
// Act:
final FieldElement f2 = f1.negate();
final BigInteger b2 = toBigInteger(f2).mod(getQ());
// Assert:
Assert.assertThat(b2, IsEqual.equalTo(b1.negate().mod(getQ())));
}
}
@Test
public void multiplyReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = getRandomFieldElement();
final FieldElement f2 = getRandomFieldElement();
final BigInteger b1 = toBigInteger(f1);
final BigInteger b2 = toBigInteger(f2);
// Act:
final FieldElement f3 = f1.multiply(f2);
final BigInteger b3 = toBigInteger(f3).mod(getQ());
// Assert:
Assert.assertThat(b3, IsEqual.equalTo(b1.multiply(b2).mod(getQ())));
}
}
@Test
public void squareReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = getRandomFieldElement();
final BigInteger b1 = toBigInteger(f1);
// Act:
final FieldElement f2 = f1.square();
final BigInteger b2 = toBigInteger(f2).mod(getQ());
// Assert:
Assert.assertThat(b2, IsEqual.equalTo(b1.multiply(b1).mod(getQ())));
}
}
@Test
public void squareAndDoubleReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = getRandomFieldElement();
final BigInteger b1 = toBigInteger(f1);
// Act:
final FieldElement f2 = f1.squareAndDouble();
final BigInteger b2 = toBigInteger(f2).mod(getQ());
// Assert:
Assert.assertThat(b2, IsEqual.equalTo(b1.multiply(b1).multiply(new BigInteger("2")).mod(getQ())));
}
}
@Test
public void invertReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = getRandomFieldElement();
final BigInteger b1 = toBigInteger(f1);
// Act:
final FieldElement f2 = f1.invert();
final BigInteger b2 = toBigInteger(f2).mod(getQ());
// Assert:
Assert.assertThat(b2, IsEqual.equalTo(b1.modInverse(getQ())));
}
}
@Test
public void pow22523ReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = getRandomFieldElement();
final BigInteger b1 = toBigInteger(f1);
// Act:
final FieldElement f2 = f1.pow22523();
final BigInteger b2 = toBigInteger(f2).mod(getQ());
// Assert:
Assert.assertThat(b2, IsEqual.equalTo(b1.modPow(BigInteger.ONE.shiftLeft(252).subtract(new BigInteger("3")), getQ())));
}
}
// endregion
// region cmov
@Test
public void cmovReturnsCorrectResult() {
final FieldElement zero = getZeroFieldElement();
final FieldElement nz = getNonZeroFieldElement();
final FieldElement f = getRandomFieldElement();
Assert.assertThat(zero.cmov(nz, 0), IsEqual.equalTo(zero));
Assert.assertThat(zero.cmov(nz, 1), IsEqual.equalTo(nz));
Assert.assertThat(f.cmov(nz, 0), IsEqual.equalTo(f));
Assert.assertThat(f.cmov(nz, 1), IsEqual.equalTo(nz));
}
// endregion
// region hashCode / equals
@Test
public void equalsOnlyReturnsTrueForEquivalentObjects() {
// Arrange:
final FieldElement f1 = getRandomFieldElement();
final FieldElement f2 = getField().getEncoding().decode(f1.toByteArray());
final FieldElement f3 = getRandomFieldElement();
final FieldElement f4 = getRandomFieldElement();
// Assert:
Assert.assertThat(f1, IsEqual.equalTo(f2));
Assert.assertThat(f1, IsNot.not(IsEqual.equalTo(f3)));
Assert.assertThat(f1, IsNot.not(IsEqual.equalTo(f4)));
Assert.assertThat(f3, IsNot.not(IsEqual.equalTo(f4)));
}
@Test
public void hashCodesAreEqualForEquivalentObjects() {
// Arrange:
final FieldElement f1 = getRandomFieldElement();
final FieldElement f2 = getField().getEncoding().decode(f1.toByteArray());
final FieldElement f3 = getRandomFieldElement();
final FieldElement f4 = getRandomFieldElement();
// Assert:
Assert.assertThat(f1.hashCode(), IsEqual.equalTo(f2.hashCode()));
Assert.assertThat(f1.hashCode(), IsNot.not(IsEqual.equalTo(f3.hashCode())));
Assert.assertThat(f1.hashCode(), IsNot.not(IsEqual.equalTo(f4.hashCode())));
Assert.assertThat(f3.hashCode(), IsNot.not(IsEqual.equalTo(f4.hashCode())));
}
// endregion
}

View File

@ -1,7 +1,10 @@
package net.i2p.crypto.eddsa.math;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@ -17,7 +20,7 @@ import org.junit.Test;
*
*/
public class ConstantsTest {
static final EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("ed25519-sha-512");
static final EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
static final Curve curve = ed25519.getCurve();
static final FieldElement ZERO = curve.getField().ZERO;

View File

@ -23,7 +23,7 @@ public class GroupElementTest {
static final byte[] BYTES_TENZERO = Utils.hexToBytes("0000000000000000000000000000000000000000000000000000000000000000");
static final byte[] BYTES_ONETEN = Utils.hexToBytes("0a00000000000000000000000000000000000000000000000000000000000080");
static final EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("ed25519-sha-512");
static final EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
static final Curve curve = ed25519.getCurve();
static final FieldElement ZERO = curve.getField().ZERO;
@ -70,6 +70,20 @@ public class GroupElementTest {
assertThat(t.T, is(ZERO));
}
/**
* Test method for {@link GroupElement#p3(Curve, FieldElement, FieldElement, FieldElement, FieldElement, boolean)}.
*/
@Test
public void testP3WithExplicitFlag() {
final GroupElement t = GroupElement.p3(curve, ZERO, ONE, ONE, ZERO, false);
assertThat(t.curve, is(equalTo(curve)));
assertThat(t.repr, is(GroupElement.Representation.P3));
assertThat(t.X, is(ZERO));
assertThat(t.Y, is(ONE));
assertThat(t.Z, is(ONE));
assertThat(t.T, is(ZERO));
}
/**
* Test method for {@link GroupElement#p1p1(Curve, FieldElement, FieldElement, FieldElement, FieldElement)}.
*/
@ -126,6 +140,20 @@ public class GroupElementTest {
assertThat(t.T, is(ZERO));
}
/**
* Test method for {@link GroupElement#GroupElement(Curve, GroupElement.Representation, FieldElement, FieldElement, FieldElement, FieldElement, boolean)}.
*/
@Test
public void testGroupElementCurveRepresentationFieldElementFieldElementFieldElementFieldElementWithExplicitFlag() {
final GroupElement t = new GroupElement(curve, GroupElement.Representation.P3, ZERO, ONE, ONE, ZERO, false);
assertThat(t.curve, is(equalTo(curve)));
assertThat(t.repr, is(GroupElement.Representation.P3));
assertThat(t.X, is(ZERO));
assertThat(t.Y, is(ONE));
assertThat(t.Z, is(ONE));
assertThat(t.T, is(ZERO));
}
/**
* Tests {@link GroupElement#GroupElement(Curve, byte[])} and
* {@link GroupElement#toByteArray()} against valid public keys.
@ -380,6 +408,29 @@ public class GroupElementTest {
}
}
@Test
public void toP3PrecomputeDoubleReturnsExpectedResultIfGroupElementHasP1P1Representation() {
for (int i=0; i<10; i++) {
// Arrange:
final GroupElement g = MathUtils.toRepresentation(MathUtils.getRandomGroupElement(), GroupElement.Representation.P1P1);
// Act:
final GroupElement h1 = g.toP3PrecomputeDouble();
final GroupElement h2 = MathUtils.toRepresentation(g, GroupElement.Representation.P3PrecomputedDouble);
// Assert:
Assert.assertThat(h1, IsEqual.equalTo(h2));
Assert.assertThat(h1.getRepresentation(), IsEqual.equalTo(GroupElement.Representation.P3));
Assert.assertThat(h1.getX(), IsEqual.equalTo(g.getX().multiply(g.getT())));
Assert.assertThat(h1.getY(), IsEqual.equalTo(g.getY().multiply(g.getZ())));
Assert.assertThat(h1.getZ(), IsEqual.equalTo(g.getZ().multiply(g.getT())));
Assert.assertThat(h1.getT(), IsEqual.equalTo(g.getX().multiply(g.getY())));
Assert.assertThat(h1.precmp, IsNull.nullValue());
Assert.assertThat(h1.dblPrecmp, IsNull.notNullValue());
Assert.assertThat(h1.dblPrecmp, IsEqual.equalTo(h2.dblPrecmp));
}
}
@Test (expected = IllegalArgumentException.class)
public void toCachedThrowsIfGroupElementHasP2Representation() {
// Arrange:
@ -451,7 +502,7 @@ public class GroupElementTest {
// endregion
/**
* Test method for {@link GroupElement#precompute(boolean)}.
* Test method for precomputation.
*/
@Test
public void testPrecompute() {
@ -736,7 +787,7 @@ public class GroupElementTest {
// This test is slow (~6s) due to math utils using an inferior algorithm to calculate the result.
@Test
public void scalarMultiplyBasePointReturnsExpectedResult() {
for (int i=0; i<100; i++) {
for (int i=0; i<10; i++) {
// Arrange:
final GroupElement basePoint = ed25519.getB();
final FieldElement f = MathUtils.getRandomFieldElement();
@ -759,8 +810,7 @@ public class GroupElementTest {
byte[] a = Utils.hexToBytes("d072f8dd9c07fa7bc8d22a4b325d26301ee9202f6db89aa7c3731529e37e437c");
GroupElement A = new GroupElement(curve, Utils.hexToBytes("d4cf8595571830644bd14af416954d09ab7159751ad9e0f7a6cbd92379e71a66"));
GroupElement B = ed25519.getB();
GroupElement geZero = curve.getZero(GroupElement.Representation.P3);
//geZero.precompute(false);
GroupElement geZero = curve.getZero(GroupElement.Representation.P3PrecomputedDouble);
// 0 * GE(0) + 0 * GE(0) = GE(0)
assertThat(geZero.doubleScalarMultiplyVariableTime(geZero, zero, zero),
@ -798,11 +848,10 @@ public class GroupElementTest {
// This test is slow (~6s) due to math utils using an inferior algorithm to calculate the result.
@Test
public void doubleScalarMultiplyVariableTimeReturnsExpectedResult() {
for (int i=0; i<50; i++) {
for (int i=0; i<10; i++) {
// Arrange:
final GroupElement basePoint = ed25519.getB();
final GroupElement g = MathUtils.getRandomGroupElement();
//g.precompute(false);
final GroupElement g = MathUtils.getRandomGroupElement(true);
final FieldElement f1 = MathUtils.getRandomFieldElement();
final FieldElement f2 = MathUtils.getRandomFieldElement();

View File

@ -15,7 +15,7 @@ import java.security.SecureRandom;
public class MathUtils {
private static final int[] exponents = {0, 26, 26 + 25, 2*26 + 25, 2*26 + 2*25, 3*26 + 2*25, 3*26 + 3*25, 4*26 + 3*25, 4*26 + 4*25, 5*26 + 4*25};
private static final SecureRandom random = new SecureRandom();
private static final EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("ed25519-sha-512");
private static final EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
private static final Curve curve = ed25519.getCurve();
private static final BigInteger d = new BigInteger("-121665").multiply(new BigInteger("121666").modInverse(getQ()));
private static final BigInteger groupOrder = BigInteger.ONE.shiftLeft(252).add(new BigInteger("27742317777372353535851937790883648493"));
@ -178,12 +178,19 @@ public class MathUtils {
*
* @return The group element.
*/
public static GroupElement getRandomGroupElement() {
public static GroupElement getRandomGroupElement() { return getRandomGroupElement(false); }
/**
* Gets a random group element in P3 representation, with precmp and dblPrecmp populated.
*
* @return The group element.
*/
public static GroupElement getRandomGroupElement(boolean precompute) {
final byte[] bytes = new byte[32];
while (true) {
try {
random.nextBytes(bytes);
return new GroupElement(curve, bytes);
return new GroupElement(curve, bytes, precompute);
} catch (IllegalArgumentException e) {
// Will fail in about 87.5%, so try again.
}
@ -242,6 +249,7 @@ public class MathUtils {
switch (g.getRepresentation()) {
case P2:
case P3:
case P3PrecomputedDouble:
x = gX.multiply(gZ.modInverse(getQ())).mod(getQ());
y = gY.multiply(gZ.modInverse(getQ())).mod(getQ());
break;
@ -275,7 +283,14 @@ public class MathUtils {
toFieldElement(x),
toFieldElement(y),
getField().ONE,
toFieldElement(x.multiply(y).mod(getQ())));
toFieldElement(x.multiply(y).mod(getQ())), false);
case P3PrecomputedDouble:
return GroupElement.p3(
curve,
toFieldElement(x),
toFieldElement(y),
getField().ONE,
toFieldElement(x.multiply(y).mod(getQ())), true);
case P1P1:
return GroupElement.p1p1(
curve,

View File

@ -16,7 +16,7 @@ public class PrecomputationTestVectors {
static GroupElement[] testDblPrecmp = getDoublePrecomputation("baseDblPrecmp");
public static GroupElement[][] getPrecomputation(String fileName) {
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("ed25519-sha-512");
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
Curve curve = ed25519.getCurve();
Field field = curve.getField();
GroupElement[][] precmp = new GroupElement[32][8];
@ -59,7 +59,7 @@ public class PrecomputationTestVectors {
}
public static GroupElement[] getDoublePrecomputation(String fileName) {
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("ed25519-sha-512");
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
Curve curve = ed25519.getCurve();
Field field = curve.getField();
GroupElement[] dblPrecmp = new GroupElement[8];

View File

@ -4,17 +4,20 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.math.BigInteger;
import java.util.Random;
import net.i2p.crypto.eddsa.Utils;
import net.i2p.crypto.eddsa.math.Field;
import net.i2p.crypto.eddsa.math.FieldElement;
import net.i2p.crypto.eddsa.math.MathUtils;
import net.i2p.crypto.eddsa.math.AbstractFieldElementTest;
import org.junit.Test;
/**
* @author str4d
*
*/
public class BigIntegerFieldElementTest {
public class BigIntegerFieldElementTest extends AbstractFieldElementTest {
static final byte[] BYTES_ZERO = Utils.hexToBytes("0000000000000000000000000000000000000000000000000000000000000000");
static final byte[] BYTES_ONE = Utils.hexToBytes("0100000000000000000000000000000000000000000000000000000000000000");
static final byte[] BYTES_TEN = Utils.hexToBytes("0a00000000000000000000000000000000000000000000000000000000000000");
@ -28,6 +31,27 @@ public class BigIntegerFieldElementTest {
static final FieldElement ONE = new BigIntegerFieldElement(ed25519Field, BigInteger.ONE);
static final FieldElement TWO = new BigIntegerFieldElement(ed25519Field, BigInteger.valueOf(2));
protected FieldElement getRandomFieldElement() {
BigInteger r;
Random rnd = new Random();
do {
r = new BigInteger(255, rnd);
} while (r.compareTo(getQ()) >= 0);
return new BigIntegerFieldElement(ed25519Field, r);
}
protected BigInteger toBigInteger(FieldElement f) {
return ((BigIntegerFieldElement)f).bi;
}
protected BigInteger getQ() {
return MathUtils.getQ();
}
protected Field getField() {
return ed25519Field;
}
/**
* Test method for {@link BigIntegerFieldElement#BigIntegerFieldElement(Field, BigInteger)}.
*/
@ -58,92 +82,16 @@ public class BigIntegerFieldElementTest {
// region isNonZero
@Test
public void isNonZeroReturnsFalseIfFieldElementIsZero() {
// Assert:
assertThat(ZERO.isNonZero(), is(equalTo(false)));
protected FieldElement getZeroFieldElement() {
return ZERO;
}
@Test
public void isNonZeroReturnsTrueIfFieldElementIsNonZero() {
// Assert:
assertThat(TWO.isNonZero(), is(equalTo(true)));
protected FieldElement getNonZeroFieldElement() {
return TWO;
}
// endregion
/**
* Test method for {@link FieldElement#isNegative()}.
*/
@Test
public void testIsNegative() {
//fail("Not yet implemented");
}
/**
* Test method for {@link FieldElement#add(FieldElement)}.
*/
@Test
public void testAdd() {
//fail("Not yet implemented");
}
/**
* Test method for {@link FieldElement#subtract(FieldElement)}.
*/
@Test
public void testSubtract() {
//fail("Not yet implemented");
}
/**
* Test method for {@link FieldElement#negate()}.
*/
@Test
public void testNegate() {
//fail("Not yet implemented");
}
/**
* Test method for {@link FieldElement#multiply(FieldElement)}.
*/
@Test
public void testMultiply() {
//fail("Not yet implemented");
}
/**
* Test method for {@link FieldElement#square()}.
*/
@Test
public void testSquare() {
//fail("Not yet implemented");
}
/**
* Test method for {@link FieldElement#squareAndDouble()}.
*/
@Test
public void testSquareAndDouble() {
//fail("Not yet implemented");
}
/**
* Test method for {@link FieldElement#invert()}.
*/
@Test
public void testInvert() {
//fail("Not yet implemented");
}
/**
* Test method for {@link FieldElement#pow22523()}.
*/
@Test
public void testPow22523() {
//fail("Not yet implemented");
}
/**
* Test method for {@link FieldElement#equals(java.lang.Object)}.
*/

View File

@ -22,7 +22,7 @@ import org.junit.Test;
*/
public class BigIntegerScalarOpsTest {
static final EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("ed25519-sha-512");
static final EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
static final Field ed25519Field = ed25519.getCurve().getField();
/**

View File

@ -9,7 +9,23 @@ import java.math.BigInteger;
/**
* Tests rely on the BigInteger class.
*/
public class Ed25519FieldElementTest {
public class Ed25519FieldElementTest extends AbstractFieldElementTest {
protected FieldElement getRandomFieldElement() {
return MathUtils.getRandomFieldElement();
}
protected BigInteger toBigInteger(FieldElement f) {
return MathUtils.toBigInteger(f);
}
protected BigInteger getQ() {
return MathUtils.getQ();
}
protected Field getField() {
return MathUtils.getField();
}
// region constructor
@ -35,201 +51,19 @@ public class Ed25519FieldElementTest {
// region isNonZero
@Test
public void isNonZeroReturnsFalseIfFieldElementIsZero() {
// Act:
final FieldElement f = new Ed25519FieldElement(MathUtils.getField(), new int[10]);
// Assert:
Assert.assertThat(f.isNonZero(), IsEqual.equalTo(false));
protected FieldElement getZeroFieldElement() {
return new Ed25519FieldElement(MathUtils.getField(), new int[10]);
}
@Test
public void isNonZeroReturnsTrueIfFieldElementIsNonZero() {
// Act:
protected FieldElement getNonZeroFieldElement() {
final int[] t = new int[10];
t[0] = 5;
final FieldElement f = new Ed25519FieldElement(MathUtils.getField(), t);
// Assert:
Assert.assertThat(f.isNonZero(), IsEqual.equalTo(true));
return new Ed25519FieldElement(MathUtils.getField(), t);
}
// endregion
// region mod q arithmetic
@Test
public void addReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = MathUtils.getRandomFieldElement();
final FieldElement f2 = MathUtils.getRandomFieldElement();
final BigInteger b1 = MathUtils.toBigInteger(f1);
final BigInteger b2 = MathUtils.toBigInteger(f2);
// Act:
final FieldElement f3 = f1.add(f2);
final BigInteger b3 = MathUtils.toBigInteger(f3).mod(MathUtils.getQ());
// Assert:
Assert.assertThat(b3, IsEqual.equalTo(b1.add(b2).mod(MathUtils.getQ())));
}
}
@Test
public void subtractReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = MathUtils.getRandomFieldElement();
final FieldElement f2 = MathUtils.getRandomFieldElement();
final BigInteger b1 = MathUtils.toBigInteger(f1);
final BigInteger b2 = MathUtils.toBigInteger(f2);
// Act:
final FieldElement f3 = f1.subtract(f2);
final BigInteger b3 = MathUtils.toBigInteger(f3).mod(MathUtils.getQ());
// Assert:
Assert.assertThat(b3, IsEqual.equalTo(b1.subtract(b2).mod(MathUtils.getQ())));
}
}
@Test
public void negateReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = MathUtils.getRandomFieldElement();
final BigInteger b1 = MathUtils.toBigInteger(f1);
// Act:
final FieldElement f2 = f1.negate();
final BigInteger b2 = MathUtils.toBigInteger(f2).mod(MathUtils.getQ());
// Assert:
Assert.assertThat(b2, IsEqual.equalTo(b1.negate().mod(MathUtils.getQ())));
}
}
@Test
public void multiplyReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = MathUtils.getRandomFieldElement();
final FieldElement f2 = MathUtils.getRandomFieldElement();
final BigInteger b1 = MathUtils.toBigInteger(f1);
final BigInteger b2 = MathUtils.toBigInteger(f2);
// Act:
final FieldElement f3 = f1.multiply(f2);
final BigInteger b3 = MathUtils.toBigInteger(f3).mod(MathUtils.getQ());
// Assert:
Assert.assertThat(b3, IsEqual.equalTo(b1.multiply(b2).mod(MathUtils.getQ())));
}
}
@Test
public void squareReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = MathUtils.getRandomFieldElement();
final BigInteger b1 = MathUtils.toBigInteger(f1);
// Act:
final FieldElement f2 = f1.square();
final BigInteger b2 = MathUtils.toBigInteger(f2).mod(MathUtils.getQ());
// Assert:
Assert.assertThat(b2, IsEqual.equalTo(b1.multiply(b1).mod(MathUtils.getQ())));
}
}
@Test
public void squareAndDoubleReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = MathUtils.getRandomFieldElement();
final BigInteger b1 = MathUtils.toBigInteger(f1);
// Act:
final FieldElement f2 = f1.squareAndDouble();
final BigInteger b2 = MathUtils.toBigInteger(f2).mod(MathUtils.getQ());
// Assert:
Assert.assertThat(b2, IsEqual.equalTo(b1.multiply(b1).multiply(new BigInteger("2")).mod(MathUtils.getQ())));
}
}
@Test
public void invertReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = MathUtils.getRandomFieldElement();
final BigInteger b1 = MathUtils.toBigInteger(f1);
// Act:
final FieldElement f2 = f1.invert();
final BigInteger b2 = MathUtils.toBigInteger(f2).mod(MathUtils.getQ());
// Assert:
Assert.assertThat(b2, IsEqual.equalTo(b1.modInverse(MathUtils.getQ())));
}
}
@Test
public void pow22523ReturnsCorrectResult() {
for (int i=0; i<1000; i++) {
// Arrange:
final FieldElement f1 = MathUtils.getRandomFieldElement();
final BigInteger b1 = MathUtils.toBigInteger(f1);
// Act:
final FieldElement f2 = f1.pow22523();
final BigInteger b2 = MathUtils.toBigInteger(f2).mod(MathUtils.getQ());
// Assert:
Assert.assertThat(b2, IsEqual.equalTo(b1.modPow(BigInteger.ONE.shiftLeft(252).subtract(new BigInteger("3")), MathUtils.getQ())));
}
}
// endregion
// region hashCode / equals
@Test
public void equalsOnlyReturnsTrueForEquivalentObjects() {
// Arrange:
final FieldElement f1 = MathUtils.getRandomFieldElement();
final FieldElement f2 = MathUtils.getField().getEncoding().decode(f1.toByteArray());
final FieldElement f3 = MathUtils.getRandomFieldElement();
final FieldElement f4 = MathUtils.getRandomFieldElement();
// Assert:
Assert.assertThat(f1, IsEqual.equalTo(f2));
Assert.assertThat(f1, IsNot.not(IsEqual.equalTo(f3)));
Assert.assertThat(f1, IsNot.not(IsEqual.equalTo(f4)));
Assert.assertThat(f3, IsNot.not(IsEqual.equalTo(f4)));
}
@Test
public void hashCodesAreEqualForEquivalentObjects() {
// Arrange:
final FieldElement f1 = MathUtils.getRandomFieldElement();
final FieldElement f2 = MathUtils.getField().getEncoding().decode(f1.toByteArray());
final FieldElement f3 = MathUtils.getRandomFieldElement();
final FieldElement f4 = MathUtils.getRandomFieldElement();
// Assert:
Assert.assertThat(f1.hashCode(), IsEqual.equalTo(f2.hashCode()));
Assert.assertThat(f1.hashCode(), IsNot.not(IsEqual.equalTo(f3.hashCode())));
Assert.assertThat(f1.hashCode(), IsNot.not(IsEqual.equalTo(f4.hashCode())));
Assert.assertThat(f3.hashCode(), IsNot.not(IsEqual.equalTo(f4.hashCode())));
}
// endregion
//region toString
// region toString
@Test
public void toStringReturnsCorrectRepresentation() {

View File

@ -3,8 +3,11 @@ package net.i2p.crypto.eddsa.spec;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import net.i2p.crypto.eddsa.Utils;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
/**
* @author str4d
@ -12,9 +15,13 @@ import org.junit.Test;
*/
public class EdDSAPrivateKeySpecTest {
static final byte[] ZERO_SEED = Utils.hexToBytes("0000000000000000000000000000000000000000000000000000000000000000");
static final byte[] ZERO_H = Utils.hexToBytes("5046adc1dba838867b2bbbfdd0c3423e58b57970b5267a90f57960924a87f1960a6a85eaa642dac835424b5d7c8d637c00408c7a73da672b7f498521420b6dd3");
static final byte[] ZERO_PK = Utils.hexToBytes("3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29");
static final EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("ed25519-sha-512");
static final EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
@Rule
public ExpectedException exception = ExpectedException.none();
/**
* Test method for {@link net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec#EdDSAPrivateKeySpec(byte[], net.i2p.crypto.eddsa.spec.EdDSAParameterSpec)}.
@ -23,7 +30,32 @@ public class EdDSAPrivateKeySpecTest {
public void testEdDSAPrivateKeySpecFromSeed() {
EdDSAPrivateKeySpec key = new EdDSAPrivateKeySpec(ZERO_SEED, ed25519);
assertThat(key.getSeed(), is(equalTo(ZERO_SEED)));
assertThat(key.getH(), is(equalTo(ZERO_H)));
assertThat(key.getA().toByteArray(), is(equalTo(ZERO_PK)));
}
@Test
public void incorrectSeedLengthThrows() {
exception.expect(IllegalArgumentException.class);
exception.expectMessage("seed length is wrong");
EdDSAPrivateKeySpec key = new EdDSAPrivateKeySpec(new byte[2], ed25519);
}
/**
* Test method for {@link net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec#EdDSAPrivateKeySpec(net.i2p.crypto.eddsa.spec.EdDSAParameterSpec, byte[])}.
*/
@Test
public void testEdDSAPrivateKeySpecFromH() {
EdDSAPrivateKeySpec key = new EdDSAPrivateKeySpec(ed25519, ZERO_H);
assertThat(key.getSeed(), is(nullValue()));
assertThat(key.getH(), is(equalTo(ZERO_H)));
assertThat(key.getA().toByteArray(), is(equalTo(ZERO_PK)));
}
@Test
public void incorrectHashLengthThrows() {
exception.expect(IllegalArgumentException.class);
exception.expectMessage("hash length is wrong");
EdDSAPrivateKeySpec key = new EdDSAPrivateKeySpec(ed25519, new byte[2]);
}
}