protected Field getField() { return MathUtils.getField(); }
protected FieldElement getNonZeroFieldElement() { final int[] t = new int[10]; t[0] = 5; return new Ed25519FieldElement(MathUtils.getField(), t); }
/** * Gets a random field element where |t[i]| <= 2^24 for 0 <= i <= 9. * * @return The field element. */ public static FieldElement getRandomFieldElement() { final int[] t = new int[10]; for (int j=0; j<10; j++) { t[j] = random.nextInt(1 << 25) - (1 << 24); } return new Ed25519FieldElement(getField(), t); }
protected FieldElement getZeroFieldElement() { return new Ed25519FieldElement(MathUtils.getField(), new int[10]); }
@Test public void canConstructFieldElementFromArrayWithCorrectLength() { // Assert: new Ed25519FieldElement(MathUtils.getField(), new int[10]); }
@Test (expected = IllegalArgumentException.class) public void cannotConstructFieldElementFromArrayWithIncorrectLength() { // Assert: new Ed25519FieldElement(MathUtils.getField(), new int[9]); }
@Test public void toStringReturnsCorrectRepresentation() { // Arrange: final byte[] bytes = new byte[32]; for (int i=0; i<32; i++) { bytes[i] = (byte)(i+1); } final FieldElement f = MathUtils.getField().getEncoding().decode(bytes); // Act: final String fAsString = f.toString(); final StringBuilder builder = new StringBuilder(); builder.append("[Ed25519FieldElement val="); for (byte b : bytes) { builder.append(String.format("%02x", b)); } builder.append("]"); // Assert: Assert.assertThat(fAsString, IsEqual.equalTo(builder.toString())); }
@Test public void isNegativeReturnsCorrectResult() { 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 boolean isNegative = MathUtils.toBigInteger(t).mod(MathUtils.getQ()).mod(new BigInteger("2")).equals(BigInteger.ONE); final FieldElement f = new Ed25519FieldElement(MathUtils.getField(), t); // Assert: Assert.assertThat(MathUtils.getField().getEncoding().isNegative(f), IsEqual.equalTo(isNegative)); } } }
@Test public void encodeReturnsCorrectByteArrayForSimpleFieldElements() { // Arrange: final int[] t1 = new int[10]; final int[] t2 = new int[10]; t2[0] = 1; final FieldElement fieldElement1 = new Ed25519FieldElement(MathUtils.getField(), t1); final FieldElement fieldElement2 = new Ed25519FieldElement(MathUtils.getField(), t2); // Act: final byte[] bytes1 = MathUtils.getField().getEncoding().encode(fieldElement1); final byte[] bytes2 = MathUtils.getField().getEncoding().encode(fieldElement2); // Assert: Assert.assertThat(bytes1, IsEqual.equalTo(MathUtils.toByteArray(BigInteger.ZERO))); Assert.assertThat(bytes2, IsEqual.equalTo(MathUtils.toByteArray(BigInteger.ONE))); }
/** * 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)); }
/** * 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 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())))); } }
@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 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)); }
toFieldElement(x), toFieldElement(y), getField().ONE); case P3: return GroupElement.p3( toFieldElement(x), toFieldElement(y), getField().ONE, toFieldElement(x.multiply(y).mod(getQ())), false); case P3PrecomputedDouble: toFieldElement(x), toFieldElement(y), getField().ONE, toFieldElement(x.multiply(y).mod(getQ())), true); case P1P1: toFieldElement(x), toFieldElement(y), getField().ONE, getField().ONE); case CACHED: return GroupElement.cached( toFieldElement(y.add(x).mod(getQ())), toFieldElement(y.subtract(x).mod(getQ())), getField().ONE, toFieldElement(d.multiply(new BigInteger("2")).multiply(x).multiply(y).mod(getQ())));
BigInteger t3 = x3.multiply(y3).mod(getQ()); return GroupElement.p3(g1.getCurve(), toFieldElement(x3), toFieldElement(y3), getField().ONE, toFieldElement(t3));