/** * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). * * @param xEnc The encoding of field element xp. * @param ypBit ~yp, an indication bit for the decompression of yp. * @return the decompressed point. */ private ECPoint decompressPoint(byte[] xEnc, int ypBit) { ECFieldElement xp = new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, new BigInteger(1, xEnc)); ECFieldElement yp = null; if (xp.toBigInteger().equals(ECConstants.ZERO)) { yp = (ECFieldElement.F2m) b; for (int i = 0; i < m - 1; i++) { yp = yp.square(); } } else { ECFieldElement beta = xp.add(a).add(b.multiply(xp.square().invert())); ECFieldElement z = solveQuadradicEquation(beta); if (z == null) { throw new RuntimeException("Invalid point compression"); } int zBit = 0; if (z.toBigInteger().testBit(0)) { zBit = 1; } if (zBit != ypBit) { z = z.add(new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, ECConstants.ONE)); } yp = xp.multiply(z); } return new ECPoint.F2m(this, xp, yp); }
/** * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 D.1.6) The other * solution is <code>z + 1</code>. * * @param beta The value to solve the qradratic equation for. * @return the solution for <code>z<sup>2</sup> + z = beta</code> or <code>null</code> if no * solution exists. */ private ECFieldElement solveQuadradicEquation(ECFieldElement beta) { ECFieldElement zeroElement = new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, ECConstants.ZERO); if (beta.toBigInteger().equals(ECConstants.ZERO)) { return zeroElement; } ECFieldElement z = null; ECFieldElement gamma = zeroElement; Random rand = new Random(); do { ECFieldElement t = new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, new BigInteger(m, rand)); z = zeroElement; ECFieldElement w = beta; for (int i = 1; i <= m - 1; i++) { ECFieldElement w2 = w.square(); z = z.square().add(w2.multiply(t)); w = w2.add(beta); } if (!w.toBigInteger().equals(ECConstants.ZERO)) { return null; } gamma = z.square().add(z); } while (gamma.toBigInteger().equals(ECConstants.ZERO)); return z; }
/** * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 D.1.6) The other * solution is <code>z + 1</code>. * * @param beta The value to solve the quadratic equation for. * @return the solution for <code>z<sup>2</sup> + z = beta</code> or <code>null</code> if no * solution exists. */ private ECFieldElement solveQuadraticEquation(ECFieldElement beta) { if (beta.isZero()) { return beta; } ECFieldElement zeroElement = fromBigInteger(ECConstants.ZERO); ECFieldElement z = null; ECFieldElement gamma = null; Random rand = new Random(); do { ECFieldElement t = fromBigInteger(new BigInteger(m, rand)); z = zeroElement; ECFieldElement w = beta; for (int i = 1; i <= m - 1; i++) { ECFieldElement w2 = w.square(); z = z.square().add(w2.multiply(t)); w = w2.add(beta); } if (!w.isZero()) { return null; } gamma = z.square().add(z); } while (gamma.isZero()); return z; }
protected ECFieldElement doubleProductFromSquares( ECFieldElement a, ECFieldElement b, ECFieldElement aSquared, ECFieldElement bSquared) { /* * NOTE: If squaring in the field is faster than multiplication, then this is a quicker * way to calculate 2.A.B, if A^2 and B^2 are already known. */ return a.add(b).square().subtract(aSquared).subtract(bSquared); }
/** * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). * * @param yTilde ~yp, an indication bit for the decompression of yp. * @param X1 The field element xp. * @return the decompressed point. */ protected ECPoint decompressPoint(int yTilde, BigInteger X1) { ECFieldElement xp = fromBigInteger(X1); ECFieldElement yp = null; if (xp.isZero()) { yp = (ECFieldElement.F2m) b; for (int i = 0; i < m - 1; i++) { yp = yp.square(); } } else { ECFieldElement beta = xp.add(a).add(b.multiply(xp.square().invert())); ECFieldElement z = solveQuadraticEquation(beta); if (z == null) { throw new IllegalArgumentException("Invalid point compression"); } if (z.testBitZero() != (yTilde == 1)) { z = z.addOne(); } yp = xp.multiply(z); switch (this.getCoordinateSystem()) { case COORD_LAMBDA_AFFINE: case COORD_LAMBDA_PROJECTIVE: { yp = yp.divide(xp).add(xp); break; } default: { break; } } } return new ECPoint.F2m(this, xp, yp, true); }
protected ECFieldElement two(ECFieldElement x) { return x.add(x); }