/** * Creates a new group element in P3 representation. * * @param curve The curve. * @param X The X coordinate. * @param Y The Y coordinate. * @param Z The Z coordinate. * @param T The T coordinate. * @return The group element in P3 representation. */ public static GroupElement p3( final Curve curve, final FieldElement X, final FieldElement Y, final FieldElement Z, final FieldElement T) { return p3(curve, X, Y, Z, T, false); }
public Curve(Field f, byte[] d, FieldElement I) { this.f = f; this.d = f.fromByteArray(d); this.d2 = this.d.add(this.d); this.I = I; FieldElement zero = f.ZERO; FieldElement one = f.ONE; zeroP2 = GroupElement.p2(this, zero, one, one); zeroP3 = GroupElement.p3(this, zero, one, one, zero, false); zeroP3PrecomputedDouble = GroupElement.p3(this, zero, one, one, zero, true); zeroPrecomp = GroupElement.precomp(this, one, one, zero); }
/** * Test method for {@link GroupElement#GroupElement(Curve, byte[])}. */ @Test public void testGroupElementByteArray() { final GroupElement t = new GroupElement(curve, BYTES_PKR); final GroupElement s = GroupElement.p3(curve, PKR[0], PKR[1], ONE, PKR[0].multiply(PKR[1])); assertThat(t, is(equalTo(s))); }
/** * Test method for {@link GroupElement#p3(Curve, FieldElement, FieldElement, FieldElement, FieldElement, boolean)}. */ @Test public void testP3WithExplicitFlag() { final GroupElement t = GroupElement.p3(curve, ZERO, ONE, ONE, ZERO, false); assertThat(t.curve, is(equalTo(curve))); assertThat(t.repr, is(GroupElement.Representation.P3)); assertThat(t.X, is(ZERO)); assertThat(t.Y, is(ONE)); assertThat(t.Z, is(ONE)); assertThat(t.T, is(ZERO)); }
/** * Test method for {@link GroupElement#p3(Curve, FieldElement, FieldElement, FieldElement, FieldElement)}. */ @Test public void testP3() { final GroupElement t = GroupElement.p3(curve, ZERO, ONE, ONE, ZERO); assertThat(t.curve, is(equalTo(curve))); assertThat(t.repr, is(GroupElement.Representation.P3)); assertThat(t.X, is(ZERO)); assertThat(t.Y, is(ONE)); assertThat(t.Z, is(ONE)); assertThat(t.T, is(ZERO)); }
/** * 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()))); }
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())); 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);
/** * Creates a new group element in P3 representation, without pre-computation. * * @param curve The curve. * @param X The $X$ coordinate. * @param Y The $Y$ coordinate. * @param Z The $Z$ coordinate. * @param T The $T$ coordinate. * @return The group element in P3 representation. */ public static GroupElement p3( final Curve curve, final FieldElement X, final FieldElement Y, final FieldElement Z, final FieldElement T) { return p3(curve, X, Y, Z, T, false); }
/** * Negates a group element. * * @param g The group element. * @return The negated group element. */ public static GroupElement negateGroupElement(final GroupElement g) { if (g.getRepresentation() != GroupElement.Representation.P3) { throw new IllegalArgumentException("g must have representation P3"); } return GroupElement.p3(g.getCurve(), g.getX().negate(), g.getY(), g.getZ(), g.getT().negate()); }
BigInteger t3 = x3.multiply(y3).mod(getQ()); return GroupElement.p3(g1.getCurve(), toFieldElement(x3), toFieldElement(y3), getField().ONE, toFieldElement(t3));
@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 public void mathUtilsWorkAsExpected() { 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();
public Curve(Field f, byte[] d, FieldElement I) { this.f = f; this.d = f.fromByteArray(d); this.d2 = this.d.add(this.d); this.I = I; FieldElement zero = f.ZERO; FieldElement one = f.ONE; zeroP2 = GroupElement.p2(this, zero, one, one); zeroP3 = GroupElement.p3(this, zero, one, one, zero, false); zeroP3PrecomputedDouble = GroupElement.p3(this, zero, one, one, zero, true); zeroPrecomp = GroupElement.precomp(this, one, one, zero); }
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())); 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);