aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/core/src/main/java/org/spongycastle/math/ec/ECCurve.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/spongycastle/core/src/main/java/org/spongycastle/math/ec/ECCurve.java')
-rw-r--r--libraries/spongycastle/core/src/main/java/org/spongycastle/math/ec/ECCurve.java972
1 files changed, 972 insertions, 0 deletions
diff --git a/libraries/spongycastle/core/src/main/java/org/spongycastle/math/ec/ECCurve.java b/libraries/spongycastle/core/src/main/java/org/spongycastle/math/ec/ECCurve.java
new file mode 100644
index 000000000..137681e3b
--- /dev/null
+++ b/libraries/spongycastle/core/src/main/java/org/spongycastle/math/ec/ECCurve.java
@@ -0,0 +1,972 @@
+package org.spongycastle.math.ec;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+import org.spongycastle.util.BigIntegers;
+
+/**
+ * base class for an elliptic curve
+ */
+public abstract class ECCurve
+{
+ public static final int COORD_AFFINE = 0;
+ public static final int COORD_HOMOGENEOUS = 1;
+ public static final int COORD_JACOBIAN = 2;
+ public static final int COORD_JACOBIAN_CHUDNOVSKY = 3;
+ public static final int COORD_JACOBIAN_MODIFIED = 4;
+ public static final int COORD_LAMBDA_AFFINE = 5;
+ public static final int COORD_LAMBDA_PROJECTIVE = 6;
+ public static final int COORD_SKEWED = 7;
+
+ public static int[] getAllCoordinateSystems()
+ {
+ return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY,
+ COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED };
+ }
+
+ public class Config
+ {
+ protected int coord;
+ protected ECMultiplier multiplier;
+
+ Config(int coord, ECMultiplier multiplier)
+ {
+ this.coord = coord;
+ this.multiplier = multiplier;
+ }
+
+ public Config setCoordinateSystem(int coord)
+ {
+ this.coord = coord;
+ return this;
+ }
+
+ public Config setMultiplier(ECMultiplier multiplier)
+ {
+ this.multiplier = multiplier;
+ return this;
+ }
+
+ public ECCurve create()
+ {
+ if (!supportsCoordinateSystem(coord))
+ {
+ throw new IllegalStateException("unsupported coordinate system");
+ }
+
+ ECCurve c = cloneCurve();
+ if (c == ECCurve.this)
+ {
+ throw new IllegalStateException("implementation returned current curve");
+ }
+
+ c.coord = coord;
+ c.multiplier = multiplier;
+
+ return c;
+ }
+ }
+
+ protected ECFieldElement a, b;
+ protected int coord = COORD_AFFINE;
+ protected ECMultiplier multiplier = null;
+
+ public abstract int getFieldSize();
+
+ public abstract ECFieldElement fromBigInteger(BigInteger x);
+
+ public Config configure()
+ {
+ return new Config(this.coord, this.multiplier);
+ }
+
+ public ECPoint createPoint(BigInteger x, BigInteger y)
+ {
+ return createPoint(x, y, false);
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, use {@link #createPoint(BigInteger, BigInteger)}
+ * and refer {@link ECPoint#getEncoded(boolean)}
+ */
+ public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+ {
+ return createRawPoint(fromBigInteger(x), fromBigInteger(y), withCompression);
+ }
+
+ protected abstract ECCurve cloneCurve();
+
+ protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression);
+
+ protected ECMultiplier createDefaultMultiplier()
+ {
+ return new WNafL2RMultiplier();
+ }
+
+ public boolean supportsCoordinateSystem(int coord)
+ {
+ return coord == COORD_AFFINE;
+ }
+
+ public PreCompInfo getPreCompInfo(ECPoint p)
+ {
+ checkPoint(p);
+ return p.preCompInfo;
+ }
+
+ /**
+ * Sets the <code>PreCompInfo</code> for a point on this curve. Used by
+ * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use
+ * by subsequent multiplication.
+ *
+ * @param point
+ * The <code>ECPoint</code> to store precomputations for.
+ * @param preCompInfo
+ * The values precomputed by the <code>ECMultiplier</code>.
+ */
+ public void setPreCompInfo(ECPoint point, PreCompInfo preCompInfo)
+ {
+ checkPoint(point);
+ point.preCompInfo = preCompInfo;
+ }
+
+ public ECPoint importPoint(ECPoint p)
+ {
+ if (this == p.getCurve())
+ {
+ return p;
+ }
+ if (p.isInfinity())
+ {
+ return getInfinity();
+ }
+
+ // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
+ p = p.normalize();
+
+ return createPoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger(), p.withCompression);
+ }
+
+ /**
+ * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+ * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
+ * than one point is to be normalized, this method will generally be more efficient than
+ * normalizing each point separately.
+ *
+ * @param points
+ * An array of points that will be updated in place with their normalized versions,
+ * where necessary
+ */
+ public void normalizeAll(ECPoint[] points)
+ {
+ checkPoints(points);
+
+ if (this.getCoordinateSystem() == ECCurve.COORD_AFFINE)
+ {
+ return;
+ }
+
+ /*
+ * Figure out which of the points actually need to be normalized
+ */
+ ECFieldElement[] zs = new ECFieldElement[points.length];
+ int[] indices = new int[points.length];
+ int count = 0;
+ for (int i = 0; i < points.length; ++i)
+ {
+ ECPoint p = points[i];
+ if (null != p && !p.isNormalized())
+ {
+ zs[count] = p.getZCoord(0);
+ indices[count++] = i;
+ }
+ }
+
+ if (count == 0)
+ {
+ return;
+ }
+
+ ECAlgorithms.implMontgomeryTrick(zs, 0, count);
+
+ for (int j = 0; j < count; ++j)
+ {
+ int index = indices[j];
+ points[index] = points[index].normalize(zs[j]);
+ }
+ }
+
+ public abstract ECPoint getInfinity();
+
+ public ECFieldElement getA()
+ {
+ return a;
+ }
+
+ public ECFieldElement getB()
+ {
+ return b;
+ }
+
+ public int getCoordinateSystem()
+ {
+ return coord;
+ }
+
+ protected abstract ECPoint decompressPoint(int yTilde, BigInteger X1);
+
+ /**
+ * Sets the default <code>ECMultiplier</code>, unless already set.
+ */
+ public ECMultiplier getMultiplier()
+ {
+ if (this.multiplier == null)
+ {
+ this.multiplier = createDefaultMultiplier();
+ }
+ return this.multiplier;
+ }
+
+ /**
+ * Decode a point on this curve from its ASN.1 encoding. The different
+ * encodings are taken account of, including point compression for
+ * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
+ * @return The decoded point.
+ */
+ public ECPoint decodePoint(byte[] encoded)
+ {
+ ECPoint p = null;
+ int expectedLength = (getFieldSize() + 7) / 8;
+
+ switch (encoded[0])
+ {
+ case 0x00: // infinity
+ {
+ if (encoded.length != 1)
+ {
+ throw new IllegalArgumentException("Incorrect length for infinity encoding");
+ }
+
+ p = getInfinity();
+ break;
+ }
+ case 0x02: // compressed
+ case 0x03: // compressed
+ {
+ if (encoded.length != (expectedLength + 1))
+ {
+ throw new IllegalArgumentException("Incorrect length for compressed encoding");
+ }
+
+ int yTilde = encoded[0] & 1;
+ BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
+
+ p = decompressPoint(yTilde, X);
+ break;
+ }
+ case 0x04: // uncompressed
+ case 0x06: // hybrid
+ case 0x07: // hybrid
+ {
+ if (encoded.length != (2 * expectedLength + 1))
+ {
+ throw new IllegalArgumentException("Incorrect length for uncompressed/hybrid encoding");
+ }
+
+ BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
+ BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength);
+
+ p = createPoint(X, Y);
+ break;
+ }
+ default:
+ throw new IllegalArgumentException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
+ }
+
+ return p;
+ }
+
+ protected void checkPoint(ECPoint point)
+ {
+ if (null == point || (this != point.getCurve()))
+ {
+ throw new IllegalArgumentException("'point' must be non-null and on this curve");
+ }
+ }
+
+ protected void checkPoints(ECPoint[] points)
+ {
+ if (points == null)
+ {
+ throw new IllegalArgumentException("'points' cannot be null");
+ }
+
+ for (int i = 0; i < points.length; ++i)
+ {
+ ECPoint point = points[i];
+ if (null != point && this != point.getCurve())
+ {
+ throw new IllegalArgumentException("'points' entries must be null or on this curve");
+ }
+ }
+ }
+
+ /**
+ * Elliptic curve over Fp
+ */
+ public static class Fp extends ECCurve
+ {
+ private static final int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
+
+ BigInteger q, r;
+ ECPoint.Fp infinity;
+
+ public Fp(BigInteger q, BigInteger a, BigInteger b)
+ {
+ this.q = q;
+ this.r = ECFieldElement.Fp.calculateResidue(q);
+ this.infinity = new ECPoint.Fp(this, null, null);
+
+ this.a = fromBigInteger(a);
+ this.b = fromBigInteger(b);
+ this.coord = FP_DEFAULT_COORDS;
+ }
+
+ protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
+ {
+ this.q = q;
+ this.r = r;
+ this.infinity = new ECPoint.Fp(this, null, null);
+
+ this.a = a;
+ this.b = b;
+ this.coord = FP_DEFAULT_COORDS;
+ }
+
+ protected ECCurve cloneCurve()
+ {
+ return new Fp(q, r, a, b);
+ }
+
+ public boolean supportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_AFFINE:
+ case COORD_HOMOGENEOUS:
+ case COORD_JACOBIAN:
+ case COORD_JACOBIAN_MODIFIED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public int getFieldSize()
+ {
+ return q.bitLength();
+ }
+
+ public ECFieldElement fromBigInteger(BigInteger x)
+ {
+ return new ECFieldElement.Fp(this.q, this.r, x);
+ }
+
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ return new ECPoint.Fp(this, x, y, withCompression);
+ }
+
+ public ECPoint importPoint(ECPoint p)
+ {
+ if (this != p.getCurve() && this.getCoordinateSystem() == COORD_JACOBIAN && !p.isInfinity())
+ {
+ switch (p.getCurve().getCoordinateSystem())
+ {
+ case COORD_JACOBIAN:
+ case COORD_JACOBIAN_CHUDNOVSKY:
+ case COORD_JACOBIAN_MODIFIED:
+ return new ECPoint.Fp(this,
+ fromBigInteger(p.x.toBigInteger()),
+ fromBigInteger(p.y.toBigInteger()),
+ new ECFieldElement[]{ fromBigInteger(p.zs[0].toBigInteger()) },
+ p.withCompression);
+ default:
+ break;
+ }
+ }
+
+ return super.importPoint(p);
+ }
+
+ protected ECPoint decompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = fromBigInteger(X1);
+ ECFieldElement alpha = x.multiply(x.square().add(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");
+ }
+
+ BigInteger betaValue = beta.toBigInteger();
+ if (betaValue.testBit(0) != (yTilde == 1))
+ {
+ // Use the other root
+ beta = fromBigInteger(q.subtract(betaValue));
+ }
+
+ return new ECPoint.Fp(this, x, beta, true);
+ }
+
+ public ECPoint getInfinity()
+ {
+ return infinity;
+ }
+
+ public boolean equals(
+ Object anObject)
+ {
+ if (anObject == this)
+ {
+ return true;
+ }
+
+ if (!(anObject instanceof ECCurve.Fp))
+ {
+ return false;
+ }
+
+ ECCurve.Fp other = (ECCurve.Fp) anObject;
+
+ return this.q.equals(other.q)
+ && a.equals(other.a) && b.equals(other.b);
+ }
+
+ public int hashCode()
+ {
+ return a.hashCode() ^ b.hashCode() ^ q.hashCode();
+ }
+ }
+
+ /**
+ * Elliptic curves over F2m. The Weierstrass equation is given by
+ * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
+ */
+ public static class F2m extends ECCurve
+ {
+ private static final int F2M_DEFAULT_COORDS = COORD_AFFINE;
+
+ /**
+ * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+ */
+ private int m; // can't be final - JDK 1.1
+
+ /**
+ * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+ * x<sup>k</sup> + 1</code> represents the reduction polynomial
+ * <code>f(z)</code>.<br>
+ * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ private int k1; // can't be final - JDK 1.1
+
+ /**
+ * TPB: Always set to <code>0</code><br>
+ * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ private int k2; // can't be final - JDK 1.1
+
+ /**
+ * TPB: Always set to <code>0</code><br>
+ * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ private int k3; // can't be final - JDK 1.1
+
+ /**
+ * The order of the base point of the curve.
+ */
+ private BigInteger n; // can't be final - JDK 1.1
+
+ /**
+ * The cofactor of the curve.
+ */
+ private BigInteger h; // can't be final - JDK 1.1
+
+ /**
+ * The point at infinity on this curve.
+ */
+ private ECPoint.F2m infinity; // can't be final - JDK 1.1
+
+ /**
+ * The parameter <code>&mu;</code> of the elliptic curve if this is
+ * a Koblitz curve.
+ */
+ private byte mu = 0;
+
+ /**
+ * The auxiliary values <code>s<sub>0</sub></code> and
+ * <code>s<sub>1</sub></code> used for partial modular reduction for
+ * Koblitz curves.
+ */
+ private BigInteger[] si = null;
+
+ /**
+ * Constructor for Trinomial Polynomial Basis (TPB).
+ * @param m The exponent <code>m</code> of
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+ * x<sup>k</sup> + 1</code> represents the reduction
+ * polynomial <code>f(z)</code>.
+ * @param a The coefficient <code>a</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param b The coefficient <code>b</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ */
+ public F2m(
+ int m,
+ int k,
+ BigInteger a,
+ BigInteger b)
+ {
+ this(m, k, 0, 0, a, b, null, null);
+ }
+
+ /**
+ * Constructor for Trinomial Polynomial Basis (TPB).
+ * @param m The exponent <code>m</code> of
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+ * x<sup>k</sup> + 1</code> represents the reduction
+ * polynomial <code>f(z)</code>.
+ * @param a The coefficient <code>a</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param b The coefficient <code>b</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param n The order of the main subgroup of the elliptic curve.
+ * @param h The cofactor of the elliptic curve, i.e.
+ * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
+ */
+ public F2m(
+ int m,
+ int k,
+ BigInteger a,
+ BigInteger b,
+ BigInteger n,
+ BigInteger h)
+ {
+ this(m, k, 0, 0, a, b, n, h);
+ }
+
+ /**
+ * Constructor for Pentanomial Polynomial Basis (PPB).
+ * @param m The exponent <code>m</code> of
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param a The coefficient <code>a</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param b The coefficient <code>b</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ */
+ public F2m(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger a,
+ BigInteger b)
+ {
+ this(m, k1, k2, k3, a, b, null, null);
+ }
+
+ /**
+ * Constructor for Pentanomial Polynomial Basis (PPB).
+ * @param m The exponent <code>m</code> of
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param a The coefficient <code>a</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param b The coefficient <code>b</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param n The order of the main subgroup of the elliptic curve.
+ * @param h The cofactor of the elliptic curve, i.e.
+ * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
+ */
+ public F2m(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger a,
+ BigInteger b,
+ BigInteger n,
+ BigInteger h)
+ {
+ this.m = m;
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+ this.n = n;
+ this.h = h;
+
+ if (k1 == 0)
+ {
+ throw new IllegalArgumentException("k1 must be > 0");
+ }
+
+ if (k2 == 0)
+ {
+ if (k3 != 0)
+ {
+ throw new IllegalArgumentException("k3 must be 0 if k2 == 0");
+ }
+ }
+ else
+ {
+ if (k2 <= k1)
+ {
+ throw new IllegalArgumentException("k2 must be > k1");
+ }
+
+ if (k3 <= k2)
+ {
+ throw new IllegalArgumentException("k3 must be > k2");
+ }
+ }
+
+ this.infinity = new ECPoint.F2m(this, null, null);
+ this.a = fromBigInteger(a);
+ this.b = fromBigInteger(b);
+ this.coord = F2M_DEFAULT_COORDS;
+ }
+
+ protected F2m(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger n, BigInteger h)
+ {
+ this.m = m;
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+ this.n = n;
+ this.h = h;
+
+ this.infinity = new ECPoint.F2m(this, null, null);
+ this.a = a;
+ this.b = b;
+ this.coord = F2M_DEFAULT_COORDS;
+ }
+
+ protected ECCurve cloneCurve()
+ {
+ return new F2m(m, k1, k2, k3, a, b, n, h);
+ }
+
+ public boolean supportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_AFFINE:
+ case COORD_HOMOGENEOUS:
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected ECMultiplier createDefaultMultiplier()
+ {
+ if (isKoblitz())
+ {
+ return new WTauNafMultiplier();
+ }
+
+ return super.createDefaultMultiplier();
+ }
+
+ public int getFieldSize()
+ {
+ return m;
+ }
+
+ public ECFieldElement fromBigInteger(BigInteger x)
+ {
+ return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x);
+ }
+
+ public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+ {
+ ECFieldElement X = fromBigInteger(x), Y = fromBigInteger(y);
+
+ switch (this.getCoordinateSystem())
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ if (!X.isZero())
+ {
+ // Y becomes Lambda (X + Y/X) here
+ Y = Y.divide(X).add(X);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return createRawPoint(X, Y, withCompression);
+ }
+
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ return new ECPoint.F2m(this, x, y, withCompression);
+ }
+
+ public ECPoint getInfinity()
+ {
+ return infinity;
+ }
+
+ /**
+ * Returns true if this is a Koblitz curve (ABC curve).
+ * @return true if this is a Koblitz curve (ABC curve), false otherwise
+ */
+ public boolean isKoblitz()
+ {
+ return n != null && h != null && a.bitLength() <= 1 && b.bitLength() == 1;
+ }
+
+ /**
+ * Returns the parameter <code>&mu;</code> of the elliptic curve.
+ * @return <code>&mu;</code> of the elliptic curve.
+ * @throws IllegalArgumentException if the given ECCurve is not a
+ * Koblitz curve.
+ */
+ synchronized byte getMu()
+ {
+ if (mu == 0)
+ {
+ mu = Tnaf.getMu(this);
+ }
+ return mu;
+ }
+
+ /**
+ * @return the auxiliary values <code>s<sub>0</sub></code> and
+ * <code>s<sub>1</sub></code> used for partial modular reduction for
+ * Koblitz curves.
+ */
+ synchronized BigInteger[] getSi()
+ {
+ if (si == null)
+ {
+ si = Tnaf.getSi(this);
+ }
+ return si;
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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;
+ }
+
+ public boolean equals(
+ Object anObject)
+ {
+ if (anObject == this)
+ {
+ return true;
+ }
+
+ if (!(anObject instanceof ECCurve.F2m))
+ {
+ return false;
+ }
+
+ ECCurve.F2m other = (ECCurve.F2m)anObject;
+
+ return (this.m == other.m) && (this.k1 == other.k1)
+ && (this.k2 == other.k2) && (this.k3 == other.k3)
+ && a.equals(other.a) && b.equals(other.b);
+ }
+
+ public int hashCode()
+ {
+ return this.a.hashCode() ^ this.b.hashCode() ^ m ^ k1 ^ k2 ^ k3;
+ }
+
+ public int getM()
+ {
+ return m;
+ }
+
+ /**
+ * Return true if curve uses a Trinomial basis.
+ *
+ * @return true if curve Trinomial, false otherwise.
+ */
+ public boolean isTrinomial()
+ {
+ return k2 == 0 && k3 == 0;
+ }
+
+ public int getK1()
+ {
+ return k1;
+ }
+
+ public int getK2()
+ {
+ return k2;
+ }
+
+ public int getK3()
+ {
+ return k3;
+ }
+
+ public BigInteger getN()
+ {
+ return n;
+ }
+
+ public BigInteger getH()
+ {
+ return h;
+ }
+ }
+}