package org.bouncycastle.math.ec; import java.math.BigInteger; /** * base class for an elliptic curve */ public abstract class ECCurve { BigInteger q; ECFieldElement a, b; public ECCurve(BigInteger q, BigInteger a, BigInteger b) { this.q = q; this.a = fromBigInteger(a); this.b = fromBigInteger(b); } public abstract ECFieldElement fromBigInteger(BigInteger x); public abstract ECPoint decodePoint(byte[] encoded); public ECFieldElement getA() { return a; } public ECFieldElement getB() { return b; } /** * Elliptic curve over Fp */ public static class Fp extends ECCurve { public Fp(BigInteger q, BigInteger a, BigInteger b) { super(q, a, b); } public BigInteger getQ() { return q; } public ECFieldElement fromBigInteger(BigInteger x) { return new ECFieldElement.Fp(this.q, x); } /** * decode a point on this curve which has been encoded using * point compression (X9.62 s 4.2.1 pg 17) returning the point. */ public ECPoint decodePoint(byte[] encoded) { ECPoint p = null; switch (encoded[0]) { // compressed case 0x02: case 0x03: int ytilde = encoded[0] & 1; byte[] i = new byte[encoded.length - 1]; System.arraycopy(encoded, 1, i, 0, i.length); ECFieldElement x = new ECFieldElement.Fp(this.q, new BigInteger(1, i)); ECFieldElement alpha = x.multiply(x.square()).add(x.multiply(a).add(b)); ECFieldElement beta = alpha.sqrt(); // // if we can't find a sqrt we haven't got a point on the // curve - run! // if (beta == null) { throw new RuntimeException("Invalid point compression"); } int bit0 = (beta.toBigInteger().testBit(0) ? 0 : 1); if ( bit0 == ytilde ) { p = new ECPoint.Fp(this, x, beta); } else { p = new ECPoint.Fp(this, x, new ECFieldElement.Fp(this.q, q.subtract(beta.toBigInteger()))); } break; case 0x04: byte[] xEnc = new byte[(encoded.length - 1) / 2]; byte[] yEnc = new byte[(encoded.length - 1) / 2]; System.arraycopy(encoded, 1, xEnc, 0, xEnc.length); System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length); p = new ECPoint.Fp(this, new ECFieldElement.Fp(this.q, new BigInteger(1, xEnc)), new ECFieldElement.Fp(this.q, new BigInteger(1, yEnc))); break; default: throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16)); } return p; } } }