protected BigInteger toBigInteger(FieldElement f) { return MathUtils.toBigInteger(f); }
/** * Calculates (a * b + c) mod group order and returns the result. * <p> * a, b and c are given in 2^8 bit representation. * * @param a The first integer. * @param b The second integer. * @param c The third integer. * @return The mod group order reduced result. */ public static byte[] multiplyAndAddModGroupOrder(final byte[] a, final byte[] b, final byte[] c) { final BigInteger result = toBigInteger(a).multiply(toBigInteger(b)).add(toBigInteger(c)).mod(groupOrder); return toByteArray(result); }
/** * Converts a field element to a BigInteger. * * @param f The field element. * @return The BigInteger. */ public static BigInteger toBigInteger(final FieldElement f) { return toBigInteger(f.toByteArray()); }
/** * Reduces an integer in 2^8 bit representation modulo the group order and returns the result. * * @param bytes The integer in 2^8 bit representation. * @return The mod group order reduced integer. */ public static byte[] reduceModGroupOrder(final byte[] bytes) { final BigInteger b = toBigInteger(bytes).mod(groupOrder); return toByteArray(b); }
@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 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 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)); } }
/** * 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)); } } }
@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 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)); }
@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 BigInteger g1X = toBigInteger(g1.getX().toByteArray()); final BigInteger g1Y = toBigInteger(g1.getY().toByteArray()); final BigInteger g1Z = toBigInteger(g1.getZ().toByteArray()); final BigInteger g2X = toBigInteger(g2.getX().toByteArray()); final BigInteger g2Y = toBigInteger(g2.getY().toByteArray()); final BigInteger g2Z = toBigInteger(g2.getZ().toByteArray());
BigInteger x; BigInteger y; final BigInteger gX = toBigInteger(g.getX().toByteArray()); final BigInteger gY = toBigInteger(g.getY().toByteArray()); final BigInteger gZ = toBigInteger(g.getZ().toByteArray()); final BigInteger gT = null == g.getT()? null : toBigInteger(g.getT().toByteArray());