@Test public void subReturnsExpectedResult() { for (int i=0; i<1000; i++) { // Arrange: final GroupElement g1 = MathUtils.getRandomGroupElement(); final GroupElement g2 = MathUtils.getRandomGroupElement(); // Act: final GroupElement h1 = g1.sub(g2.toCached()); final GroupElement h2 = MathUtils.addGroupElements(g1, MathUtils.negateGroupElement(g2)); // Assert: Assert.assertThat(h2, IsEqual.equalTo(h1)); } }
/** * Creates a group element from a byte array. * <p> * Bit 0 to 254 are the affine y-coordinate, bit 255 is the sign of the affine x-coordinate. * * @param bytes the byte array. * @return The group element. */ public static GroupElement toGroupElement(final byte[] bytes) { final boolean shouldBeNegative = (bytes[31] >> 7) != 0; bytes[31] &= 0x7f; final BigInteger y = MathUtils.toBigInteger(bytes); // x = sign(x) * sqrt((y^2 - 1) / (d * y^2 + 1)) final BigInteger u = y.multiply(y).subtract(BigInteger.ONE).mod(getQ()); final BigInteger v = d.multiply(y).multiply(y).add(BigInteger.ONE).mod(getQ()); final BigInteger tmp = u.multiply(v.pow(7)).modPow(BigInteger.ONE.shiftLeft(252).subtract(new BigInteger("3")), getQ()).mod(getQ()); BigInteger x = tmp.multiply(u).multiply(v.pow(3)).mod(getQ()); if (!v.multiply(x).multiply(x).subtract(u).mod(getQ()).equals(BigInteger.ZERO)) { if (!v.multiply(x).multiply(x).add(u).mod(getQ()).equals(BigInteger.ZERO)) { throw new IllegalArgumentException("not a valid GroupElement"); } x = x.multiply(toBigInteger(curve.getI())).mod(getQ()); } final boolean isNegative = x.mod(new BigInteger("2")).equals(BigInteger.ONE); if ((shouldBeNegative && !isNegative) || (!shouldBeNegative && isNegative)) { x = x.negate().mod(getQ()); } return GroupElement.p3(curve, toFieldElement(x), toFieldElement(y), getField().ONE, toFieldElement(x.multiply(y).mod(getQ()))); }
@Test public void multiplyAndAddReturnsExpectedResult() { for (int i=0; i<1000; i++) { // Arrange: final byte[] bytes1 = MathUtils.getRandomByteArray(32); final byte[] bytes2 = MathUtils.getRandomByteArray(32); final byte[] bytes3 = MathUtils.getRandomByteArray(32); // Act: final byte[] result1 = scalarOps.multiplyAndAdd(bytes1, bytes2, bytes3); final byte[] result2 = MathUtils.multiplyAndAddModGroupOrder(bytes1, bytes2, bytes3); // Assert: Assert.assertThat(MathUtils.toBigInteger(result1).compareTo(MathUtils.getGroupOrder()), IsEqual.equalTo(-1)); Assert.assertThat(MathUtils.toBigInteger(result1).compareTo(new BigInteger("-1")), IsEqual.equalTo(1)); Assert.assertThat(result1, IsEqual.equalTo(result2)); } } }
/** * Calculates f1 * g1 + f2 * g2. * * @param g1 The first group element. * @param f1 The first multiplier. * @param g2 The second group element. * @param f2 The second multiplier. * @return The resulting group element. */ public static GroupElement doubleScalarMultiplyGroupElements( final GroupElement g1, final FieldElement f1, final GroupElement g2, final FieldElement f2) { final GroupElement h1 = scalarMultiplyGroupElement(g1, f1); final GroupElement h2 = scalarMultiplyGroupElement(g2, f2); return addGroupElements(h1, h2); }
@Test (expected = IllegalArgumentException.class) public void toP2ThrowsIfGroupElementHasCachedRepresentation() { // Arrange: final GroupElement g = MathUtils.toRepresentation(MathUtils.getRandomGroupElement(), GroupElement.Representation.CACHED); // Assert: g.toP2(); }
/** * Converts a BigInteger to a field element. * * @param b The BigInteger. * @return The field element. */ public static FieldElement toFieldElement(final BigInteger b) { return getField().getEncoding().decode(toByteArray(b)); }
@Test public void reduceReturnsExpectedResult() { for (int i=0; i<1000; i++) { // Arrange: final byte[] bytes = MathUtils.getRandomByteArray(64); // Act: final byte[] reduced1 = scalarOps.reduce(bytes); final byte[] reduced2 = MathUtils.reduceModGroupOrder(bytes); // Assert: Assert.assertThat(MathUtils.toBigInteger(reduced1).compareTo(MathUtils.getGroupOrder()), IsEqual.equalTo(-1)); Assert.assertThat(MathUtils.toBigInteger(reduced1).compareTo(new BigInteger("-1")), IsEqual.equalTo(1)); Assert.assertThat(reduced1, IsEqual.equalTo(reduced2)); } }
@Test public void encodeReturnsCorrectByteArray() { for (int i=0; i<10000; i++){ // Arrange: final int[] t = new int[10]; for (int j=0; j<10; j++) { t[j] = random.nextInt(1 << 28) - (1 << 27); } final FieldElement fieldElement1 = new Ed25519FieldElement(MathUtils.getField(), t); final BigInteger b = MathUtils.toBigInteger(t); // Act: final byte[] bytes = MathUtils.getField().getEncoding().encode(fieldElement1); // Assert: Assert.assertThat(bytes, IsEqual.equalTo(MathUtils.toByteArray(b.mod(MathUtils.getQ())))); } }
final GroupElement neutral = GroupElement.p3(curve, curve.getField().ZERO, curve.getField().ONE, curve.getField().ONE, curve.getField().ZERO); for (int i=0; i<1000; i++) { final GroupElement g = getRandomGroupElement(); final GroupElement h1 = addGroupElements(g, neutral); final GroupElement h2 = addGroupElements(neutral, g); GroupElement g = getRandomGroupElement(); GroupElement h = toRepresentation(g, GroupElement.Representation.P2); Assert.assertThat(h, IsEqual.equalTo(g)); h = toRepresentation(g, GroupElement.Representation.P1P1); Assert.assertThat(g, IsEqual.equalTo(h)); h = toRepresentation(g, GroupElement.Representation.CACHED); Assert.assertThat(h, IsEqual.equalTo(g)); g = toRepresentation(g, GroupElement.Representation.P2); h = toRepresentation(g, GroupElement.Representation.P3); Assert.assertThat(g, IsEqual.equalTo(h)); g = toRepresentation(g, GroupElement.Representation.P2); h = toRepresentation(g, GroupElement.Representation.P1P1); Assert.assertThat(g, IsEqual.equalTo(h)); final GroupElement g = MathUtils.getRandomGroupElement(); final GroupElement h = MathUtils.scalarMultiplyGroupElement(g, curve.getField().ZERO);
@Test public void decodeReturnsCorrectFieldElement() { for (int i=0; i<10000; i++) { // Arrange: final byte[] bytes = new byte[32]; random.nextBytes(bytes); bytes[31] = (byte)(bytes[31] & 0x7f); final BigInteger b1 = MathUtils.toBigInteger(bytes); // Act: final Ed25519FieldElement f = (Ed25519FieldElement)MathUtils.getField().getEncoding().decode(bytes); final BigInteger b2 = MathUtils.toBigInteger(f.t).mod(MathUtils.getQ()); // Assert: Assert.assertThat(b2, IsEqual.equalTo(b1)); } }
@Test public void toByteArrayReturnsExpectedResult() { for (int i=0; i<100; i++) { // Arrange: final GroupElement g = MathUtils.getRandomGroupElement(); // Act: final byte[] gBytes = g.toByteArray(); final byte[] bytes = MathUtils.toByteArray(MathUtils.toBigInteger(g.getY())); if (MathUtils.toBigInteger(g.getX()).mod(new BigInteger("2")).equals(BigInteger.ONE)) { bytes[31] |= 0x80; } // Assert: Assert.assertThat(Arrays.equals(gBytes, bytes), IsEqual.equalTo(true)); } }
@Test public void doubleScalarMultiplyVariableTimeReturnsExpectedResult() { for (int i=0; i<10; i++) { // Arrange: final GroupElement basePoint = ed25519.getB(); final GroupElement g = MathUtils.getRandomGroupElement(true); final FieldElement f1 = MathUtils.getRandomFieldElement(); final FieldElement f2 = MathUtils.getRandomFieldElement(); // Act: final GroupElement h1 = basePoint.doubleScalarMultiplyVariableTime(g, f2.toByteArray(), f1.toByteArray()); final GroupElement h2 = MathUtils.doubleScalarMultiplyGroupElements(basePoint, f1, g, f2); // Assert: Assert.assertThat(h1, IsEqual.equalTo(h2)); } }
@Test public void dblPrecomputedTableContainsExpectedGroupElements() { // Arrange: GroupElement g = ed25519.getB(); GroupElement h = MathUtils.addGroupElements(g, g); // Act + Assert: for (int i=0; i<8; i++) { Assert.assertThat(MathUtils.toRepresentation(g, GroupElement.Representation.PRECOMP), IsEqual.equalTo(ed25519.getB().dblPrecmp[i])); g = MathUtils.addGroupElements(g, h); } }
protected Field getField() { return MathUtils.getField(); }
@Test public void dblReturnsExpectedResult() { for (int i=0; i<1000; i++) { // Arrange: final GroupElement g = MathUtils.getRandomGroupElement(); // Act: final GroupElement h1 = g.dbl(); final GroupElement h2 = MathUtils.doubleGroupElement(g); // Assert: Assert.assertThat(h2, IsEqual.equalTo(h1)); } }
@Test public void addReturnsExpectedResult() { for (int i=0; i<1000; i++) { // Arrange: final GroupElement g1 = MathUtils.getRandomGroupElement(); final GroupElement g2 = MathUtils.getRandomGroupElement(); // Act: final GroupElement h1 = g1.add(g2.toCached()); final GroupElement h2 = MathUtils.addGroupElements(g1, g2); // Assert: Assert.assertThat(h2, IsEqual.equalTo(h1)); } }
@Test public void decodeReturnsCorrectFieldElementForSimpleByteArrays() { // Arrange: final byte[] bytes1 = new byte[32]; final byte[] bytes2 = new byte[32]; bytes2[0] = 1; // Act: final Ed25519FieldElement f1 = (Ed25519FieldElement)MathUtils.getField().getEncoding().decode(bytes1); final Ed25519FieldElement f2 = (Ed25519FieldElement)MathUtils.getField().getEncoding().decode(bytes2); final BigInteger b1 = MathUtils.toBigInteger(f1.t); final BigInteger b2 = MathUtils.toBigInteger(f2.t); // Assert: Assert.assertThat(b1, IsEqual.equalTo(BigInteger.ZERO)); Assert.assertThat(b2, IsEqual.equalTo(BigInteger.ONE)); }
/** * Scalar multiply the group element by the field element. * * @param g The group element. * @param f The field element. * @return The resulting group element. */ public static GroupElement scalarMultiplyGroupElement(final GroupElement g, final FieldElement f) { final byte[] bytes = f.toByteArray(); GroupElement h = curve.getZero(GroupElement.Representation.P3); for (int i=254; i>=0; i--) { h = doubleGroupElement(h); if (Utils.bit(bytes, i) == 1) { h = addGroupElements(h, g); } } return h; }
@Test public void constructorUsingByteArrayReturnsExpectedResult() { for (int i=0; i<100; i++) { // Arrange: final GroupElement g = MathUtils.getRandomGroupElement(); final byte[] bytes = g.toByteArray(); // Act: final GroupElement h1 = new GroupElement(curve, bytes); final GroupElement h2 = MathUtils.toGroupElement(bytes); // Assert: Assert.assertThat(h1, IsEqual.equalTo(h2)); } }
@Test public void scalarMultiplyBasePointReturnsExpectedResult() { for (int i=0; i<10; i++) { // Arrange: final GroupElement basePoint = ed25519.getB(); final FieldElement f = MathUtils.getRandomFieldElement(); // Act: final GroupElement g = basePoint.scalarMultiply(f.toByteArray()); final GroupElement h = MathUtils.scalarMultiplyGroupElement(basePoint, f); // Assert: Assert.assertThat(g, IsEqual.equalTo(h)); } }