return x1.equals(x2) && y1.equals(y2); case P1P1: return toP2().equals(ge); case PRECOMP:
/** * 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; }
@Test (expected = IllegalArgumentException.class) public void toP2ThrowsIfGroupElementHasPrecompRepresentation() { // Arrange: final GroupElement g = MathUtils.toRepresentation(MathUtils.getRandomGroupElement(), GroupElement.Representation.PRECOMP); // Assert: g.toP2(); }
@Test (expected = IllegalArgumentException.class) public void toP2ThrowsIfGroupElementHasCachedRepresentation() { // Arrange: final GroupElement g = MathUtils.toRepresentation(MathUtils.getRandomGroupElement(), GroupElement.Representation.CACHED); // Assert: g.toP2(); }
/** * 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(); } }
/** * Test method for {@link GroupElement#toP2()}. */ @Test public void testToP2() { GroupElement p3zero = curve.getZero(GroupElement.Representation.P3); GroupElement t = p3zero.toP2(); assertThat(t.repr, is(GroupElement.Representation.P2)); assertThat(t.X, is(p3zero.X)); assertThat(t.Y, is(p3zero.Y)); assertThat(t.Z, is(p3zero.Z)); assertThat(t.T, is((FieldElement) null)); GroupElement B = ed25519.getB(); t = B.toP2(); assertThat(t.repr, is(GroupElement.Representation.P2)); assertThat(t.X, is(B.X)); assertThat(t.Y, is(B.Y)); assertThat(t.Z, is(B.Z)); assertThat(t.T, is((FieldElement) null)); }
/** * Verify that a point is on the curve. * @param curve The curve to check. * @return true if the point lies on the curve. */ public boolean isOnCurve(Curve curve) { switch (repr) { case P2: case P3: FieldElement recip = Z.invert(); FieldElement x = X.multiply(recip); FieldElement y = Y.multiply(recip); FieldElement xx = x.square(); FieldElement yy = y.square(); FieldElement dxxyy = curve.getD().multiply(xx).multiply(yy); return curve.getField().ONE.add(dxxyy).add(xx).equals(yy); default: return toP2().isOnCurve(curve); } }
@Test public void toP2ReturnsExpectedResultIfGroupElementHasP3Representation() { for (int i=0; i<10; i++) { // Arrange: final GroupElement g = MathUtils.getRandomGroupElement(); // Act: final GroupElement h1 = g.toP2(); final GroupElement h2 = MathUtils.toRepresentation(g, GroupElement.Representation.P2); // Assert: Assert.assertThat(h1, IsEqual.equalTo(h2)); Assert.assertThat(h1.getRepresentation(), IsEqual.equalTo(GroupElement.Representation.P2)); Assert.assertThat(h1.getX(), IsEqual.equalTo(g.getX())); Assert.assertThat(h1.getY(), IsEqual.equalTo(g.getY())); Assert.assertThat(h1.getZ(), IsEqual.equalTo(g.getZ())); Assert.assertThat(h1.getT(), IsEqual.equalTo(null)); } }
@Test public void toP2ReturnsExpectedResultIfGroupElementHasP2Representation() { for (int i=0; i<10; i++) { // Arrange: final GroupElement g = MathUtils.toRepresentation(MathUtils.getRandomGroupElement(), GroupElement.Representation.P2); // Act: final GroupElement h = g.toP2(); // Assert: Assert.assertThat(h, IsEqual.equalTo(g)); Assert.assertThat(h.getRepresentation(), IsEqual.equalTo(GroupElement.Representation.P2)); Assert.assertThat(h.getX(), IsEqual.equalTo(g.getX())); Assert.assertThat(h.getY(), IsEqual.equalTo(g.getY())); Assert.assertThat(h.getZ(), IsEqual.equalTo(g.getZ())); Assert.assertThat(h.getT(), IsEqual.equalTo(null)); } }
@Test public void toP2ReturnsExpectedResultIfGroupElementHasP1P1Representation() { for (int i=0; i<10; i++) { // Arrange: final GroupElement g = MathUtils.toRepresentation(MathUtils.getRandomGroupElement(), GroupElement.Representation.P1P1); // Act: final GroupElement h1 = g.toP2(); final GroupElement h2 = MathUtils.toRepresentation(g, GroupElement.Representation.P2); // Assert: Assert.assertThat(h1, IsEqual.equalTo(h2)); Assert.assertThat(h1.getRepresentation(), IsEqual.equalTo(GroupElement.Representation.P2)); 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(null)); } }
r = t.toP2();
return x1.equals(x2) && y1.equals(y2); case P1P1: return toP2().equals(ge); case PRECOMP:
/** * $h = a * B$ where $a = a[0]+256*a[1]+\dots+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] \le 127$ * @param a $= a[0]+256*a[1]+\dots+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; }
/** * 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(); } }
/** * Verify that a point is on the curve. * @param curve The curve to check. * @return true if the point lies on the curve. */ public boolean isOnCurve(Curve curve) { switch (repr) { case P2: case P3: FieldElement recip = Z.invert(); FieldElement x = X.multiply(recip); FieldElement y = Y.multiply(recip); FieldElement xx = x.square(); FieldElement yy = y.square(); FieldElement dxxyy = curve.getD().multiply(xx).multiply(yy); return curve.getField().ONE.add(dxxyy).add(xx).equals(yy); default: return toP2().isOnCurve(curve); } }
r = t.toP2();