@Override public int hashCode() { return Arrays.hashCode(this.toByteArray()); }
@Override public int hashCode() { return getA().hashCode(); } }
public GroupElement createPoint(byte[] P, boolean precompute) { GroupElement ge = new GroupElement(this, P, precompute); return ge; }
/** * h = a * B where a = a[0]+256*a[1]+...+256^31 a[31] and * B is this point. If its lookup table has not been precomputed, it * will be at the start of the method (and cached for later calls). * Constant time. * <p> * Preconditions: (TODO: Check this applies here) * a[31] <= 127 * @param a = a[0]+256*a[1]+...+256^31 a[31] * @return the GroupElement */ public GroupElement scalarMultiply(final byte[] a) { GroupElement t; int i; final byte[] e = toRadix16(a); GroupElement h = this.curve.getZero(Representation.P3); for (i = 1; i < 64; i += 2) { t = select(i/2, e[i]); h = h.madd(t).toP3(); } h = h.dbl().toP2().dbl().toP2().dbl().toP2().dbl().toP3(); for (i = 0; i < 64; i += 2) { t = select(i/2, e[i]); h = h.madd(t).toP3(); } return h; }
final byte[] aslide = slide(a); final byte[] bslide = slide(b); GroupElement t = r.dbl(); t = t.toP3().madd(A.dblPrecmp[aslide[i]/2]); } else if(aslide[i] < 0) { t = t.toP3().msub(A.dblPrecmp[(-aslide[i])/2]); t = t.toP3().madd(this.dblPrecmp[bslide[i]/2]); } else if(bslide[i] < 0) { t = t.toP3().msub(this.dblPrecmp[(-bslide[i])/2]); r = t.toP2();
/** * Precomputes table for {@link #doubleScalarMultiplyVariableTime(GroupElement, byte[], byte[])}. * @since 0.9.36 split out from precompute() */ private GroupElement[] precomputeDouble() { // Precomputation for double scalar multiplication. // P,3P,5P,7P,9P,11P,13P,15P GroupElement[] dblPrecmp = new GroupElement[8]; GroupElement Bi = this; for (int i = 0; i < 8; i++) { final FieldElement recip = Bi.Z.invert(); final FieldElement x = Bi.X.multiply(recip); final FieldElement y = Bi.Y.multiply(recip); dblPrecmp[i] = precomp(this.curve, y.add(x), y.subtract(x), x.multiply(y).multiply(this.curve.get2D())); // Bi = edwards(B,edwards(B,Bi)) Bi = this.add(this.add(Bi.toCached()).toP3().toCached()).toP3(); } return dblPrecmp; }
byte[] two = Utils.hexToBytes("0200000000000000000000000000000000000000000000000000000000000000"); byte[] a = Utils.hexToBytes("d072f8dd9c07fa7bc8d22a4b325d26301ee9202f6db89aa7c3731529e37e437c"); GroupElement A = new GroupElement(curve, Utils.hexToBytes("d4cf8595571830644bd14af416954d09ab7159751ad9e0f7a6cbd92379e71a66")); GroupElement B = ed25519.getB(); GroupElement geZero = curve.getZero(GroupElement.Representation.P3PrecomputedDouble); assertThat(geZero.doubleScalarMultiplyVariableTime(geZero, zero, zero), is(equalTo(geZero))); assertThat(B.doubleScalarMultiplyVariableTime(geZero, zero, zero), is(equalTo(geZero))); assertThat(B.doubleScalarMultiplyVariableTime(geZero, one, zero), is(equalTo(geZero))); assertThat(B.doubleScalarMultiplyVariableTime(geZero, one, one), is(equalTo(B))); assertThat(B.doubleScalarMultiplyVariableTime(B, one, one), is(equalTo(B.dbl()))); assertThat(B.doubleScalarMultiplyVariableTime(B, one, two), is(equalTo(B.dbl().toP3().add(B.toCached())))); assertThat(B.doubleScalarMultiplyVariableTime(B, two, two), is(equalTo(B.dbl().toP3().dbl()))); assertThat(B.doubleScalarMultiplyVariableTime(B, zero, a), is(equalTo(A)));
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()); switch (g.getRepresentation()) { case P2: case P3: return GroupElement.p2( curve, toFieldElement(x), getField().ONE); case P3: return GroupElement.p3( curve, toFieldElement(x), toFieldElement(x.multiply(y).mod(getQ())), false); case P3PrecomputedDouble: return GroupElement.p3( curve, toFieldElement(x), toFieldElement(x.multiply(y).mod(getQ())), true); case P1P1:
switch (repr) { case P2: return p2(this.curve, this.X, this.Y, this.Z); default: throw new IllegalArgumentException(); switch (repr) { case P2: return p2(this.curve, this.X, this.Y, this.Z); case P3: return p3(this.curve, this.X, this.Y, this.Z, this.T); case CACHED: return cached(this.curve, this.Y.add(this.X), this.Y.subtract(this.X), this.Z, this.T.multiply(this.curve.get2D())); default: throw new IllegalArgumentException(); switch (repr) { case P2: return p2(this.curve, this.X.multiply(this.T), Y.multiply(this.Z), this.Z.multiply(this.T)); case P3: return p3(this.curve, this.X.multiply(this.T), Y.multiply(this.Z), this.Z.multiply(this.T), this.X.multiply(this.Y), false); case P3PrecomputedDouble: return p3(this.curve, this.X.multiply(this.T), Y.multiply(this.Z), this.Z.multiply(this.T), this.X.multiply(this.Y), true); case P1P1: return p1p1(this.curve, this.X, this.Y, this.Z, this.T); default: throw new IllegalArgumentException(); switch (repr) {
/** * Tests {@link GroupElement#GroupElement(Curve, byte[])} and * {@link GroupElement#toByteArray()} against valid public keys. */ @Test public void testToAndFromByteArray() { GroupElement t; for (Ed25519TestVectors.TestTuple testCase : Ed25519TestVectors.testCases) { t = new GroupElement(curve, testCase.pk); assertThat("Test case " + testCase.caseNum + " failed", t.toByteArray(), is(equalTo(testCase.pk))); } }
/** * Converts the group element to an encoded point on the curve. * * @return The encoded point as byte array. */ public byte[] toByteArray() { switch (this.repr) { case P2: case P3: FieldElement recip = Z.invert(); FieldElement x = X.multiply(recip); FieldElement y = Y.multiply(recip); byte[] s = y.toByteArray(); s[s.length-1] |= (x.isNegative() ? (byte) 0x80 : 0); return s; default: return toP2().toByteArray(); } }
GroupElement R = key.getParams().getB().doubleScalarMultiplyVariableTime( ((EdDSAPublicKey) key).getNegativeA(), h, Sbyte); byte[] Rcalc = R.toByteArray(); for (int i = 0; i < Rcalc.length; i++) { if (Rcalc[i] != sigBytes[i])
GroupElement R = key.getParams().getB().scalarMultiply(r); byte[] Rbyte = R.toByteArray();
@Test public void isOnCurveReturnsFalseForPointsNotOnTheCurve() { for (int i=0; i<100; i++) { // Arrange: final GroupElement g = MathUtils.getRandomGroupElement(); final GroupElement h = GroupElement.p2(curve, g.getX(), g.getY(), g.getZ().multiply(curve.getField().TWO)); // Assert (can only fail for 5*Z^2=1): Assert.assertThat(h.isOnCurve(), IsEqual.equalTo(false)); } } }
/** * Test method for {@link GroupElement#toByteArray()}. * <p> * TODO 20141001 BR: why test with points which are not on the curve? */ @Test public void testToByteArray() { byte[] zerozero = GroupElement.p2(curve, ZERO, ZERO, ONE).toByteArray(); assertThat(zerozero.length, is(equalTo(BYTES_ZEROZERO.length))); assertThat(zerozero, is(equalTo(BYTES_ZEROZERO))); byte[] oneone = GroupElement.p2(curve, ONE, ONE, ONE).toByteArray(); assertThat(oneone.length, is(equalTo(BYTES_ONEONE.length))); assertThat(oneone, is(equalTo(BYTES_ONEONE))); byte[] tenzero = GroupElement.p2(curve, TEN, ZERO, ONE).toByteArray(); assertThat(tenzero.length, is(equalTo(BYTES_TENZERO.length))); assertThat(tenzero, is(equalTo(BYTES_TENZERO))); byte[] oneten = GroupElement.p2(curve, ONE, TEN, ONE).toByteArray(); assertThat(oneten.length, is(equalTo(BYTES_ONETEN.length))); assertThat(oneten, is(equalTo(BYTES_ONETEN))); byte[] pkr = GroupElement.p2(curve, PKR[0], PKR[1], ONE).toByteArray(); assertThat(pkr.length, is(equalTo(BYTES_PKR.length))); assertThat(pkr, is(equalTo(BYTES_PKR))); }
@Test public void addingNeutralGroupElementDoesNotChangeGroupElement() { 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++) { // Arrange: final GroupElement g = MathUtils.getRandomGroupElement(); // Act: final GroupElement h1 = g.add(neutral.toCached()); final GroupElement h2 = neutral.add(g.toCached()); // Assert: Assert.assertThat(g, IsEqual.equalTo(h1)); Assert.assertThat(g, IsEqual.equalTo(h2)); } }
/** * Test method for {@link GroupElement#scalarMultiply(byte[])}. * Test values generated with Python Ed25519 implementation. */ @Test public void testScalarMultiplyByteArray() { // Little-endian byte[] zero = Utils.hexToBytes("0000000000000000000000000000000000000000000000000000000000000000"); byte[] one = Utils.hexToBytes("0100000000000000000000000000000000000000000000000000000000000000"); byte[] two = Utils.hexToBytes("0200000000000000000000000000000000000000000000000000000000000000"); byte[] a = Utils.hexToBytes("d072f8dd9c07fa7bc8d22a4b325d26301ee9202f6db89aa7c3731529e37e437c"); GroupElement A = new GroupElement(curve, Utils.hexToBytes("d4cf8595571830644bd14af416954d09ab7159751ad9e0f7a6cbd92379e71a66")); assertThat("scalarMultiply(0) failed", ed25519.getB().scalarMultiply(zero), is(equalTo(curve.getZero(GroupElement.Representation.P3)))); assertThat("scalarMultiply(1) failed", ed25519.getB().scalarMultiply(one), is(equalTo(ed25519.getB()))); assertThat("scalarMultiply(2) failed", ed25519.getB().scalarMultiply(two), is(equalTo(ed25519.getB().dbl()))); assertThat("scalarMultiply(a) failed", ed25519.getB().scalarMultiply(a), is(equalTo(A))); }
@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)); } }
.cmov(this.precmp[pos][0], Utils.equal(babs, 1)) .cmov(this.precmp[pos][1], Utils.equal(babs, 2)) .cmov(this.precmp[pos][2], Utils.equal(babs, 3)) .cmov(this.precmp[pos][3], Utils.equal(babs, 4)) .cmov(this.precmp[pos][4], Utils.equal(babs, 5)) .cmov(this.precmp[pos][5], Utils.equal(babs, 6)) .cmov(this.precmp[pos][6], Utils.equal(babs, 7)) .cmov(this.precmp[pos][7], Utils.equal(babs, 8)); final GroupElement tminus = precomp(curve, t.Y, t.X, t.Z.negate()); return t.cmov(tminus, bnegative);