diff --git a/Crypto/src/math/ec/ECCurve.cs b/Crypto/src/math/ec/ECCurve.cs
new file mode 100644
index 000000000..4dd5e74e2
--- /dev/null
+++ b/Crypto/src/math/ec/ECCurve.cs
@@ -0,0 +1,661 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math.EC.Abc;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ /// <remarks>Base class for an elliptic curve.</remarks>
+ public abstract class ECCurve
+ {
+ internal ECFieldElement a, b;
+
+ public abstract int FieldSize { get; }
+ public abstract ECFieldElement FromBigInteger(BigInteger x);
+ public abstract ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression);
+ public abstract ECPoint DecodePoint(byte[] encoded);
+ public abstract ECPoint Infinity { get; }
+
+ public ECFieldElement A
+ {
+ get { return a; }
+ }
+
+ public ECFieldElement B
+ {
+ get { return b; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECCurve other = obj as ECCurve;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ECCurve other)
+ {
+ return a.Equals(other.a) && b.Equals(other.b);
+ }
+
+ public override int GetHashCode()
+ {
+ return a.GetHashCode() ^ b.GetHashCode();
+ }
+ }
+
+ public abstract class ECCurveBase : ECCurve
+ {
+ protected internal ECCurveBase()
+ {
+ }
+
+ protected internal abstract ECPoint DecompressPoint(int yTilde, BigInteger X1);
+
+ /**
+ * 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 override ECPoint DecodePoint(
+ byte[] encoded)
+ {
+ ECPoint p = null;
+ int expectedLength = (FieldSize + 7) / 8;
+
+ switch (encoded[0])
+ {
+ case 0x00: // infinity
+ {
+ if (encoded.Length != 1)
+ throw new ArgumentException("Incorrect length for infinity encoding", "encoded");
+
+ p = Infinity;
+ break;
+ }
+
+ case 0x02: // compressed
+ case 0x03: // compressed
+ {
+ if (encoded.Length != (expectedLength + 1))
+ throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
+
+ int yTilde = encoded[0] & 1;
+ BigInteger X1 = new BigInteger(1, encoded, 1, encoded.Length - 1);
+
+ p = DecompressPoint(yTilde, X1);
+ break;
+ }
+
+ case 0x04: // uncompressed
+ case 0x06: // hybrid
+ case 0x07: // hybrid
+ {
+ if (encoded.Length != (2 * expectedLength + 1))
+ throw new ArgumentException("Incorrect length for uncompressed/hybrid encoding", "encoded");
+
+ BigInteger X1 = new BigInteger(1, encoded, 1, expectedLength);
+ BigInteger Y1 = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
+
+ p = CreatePoint(X1, Y1, false);
+ break;
+ }
+
+ default:
+ throw new FormatException("Invalid point encoding " + encoded[0]);
+ }
+
+ return p;
+ }
+ }
+
+ /**
+ * Elliptic curve over Fp
+ */
+ public class FpCurve : ECCurveBase
+ {
+ private readonly BigInteger q;
+ private readonly FpPoint infinity;
+
+ public FpCurve(BigInteger q, BigInteger a, BigInteger b)
+ {
+ this.q = q;
+ this.a = FromBigInteger(a);
+ this.b = FromBigInteger(b);
+ this.infinity = new FpPoint(this, null, null);
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new FpFieldElement(this.q, x);
+ }
+
+ public override ECPoint CreatePoint(
+ BigInteger X1,
+ BigInteger Y1,
+ bool withCompression)
+ {
+ // TODO Validation of X1, Y1?
+ return new FpPoint(
+ this,
+ FromBigInteger(X1),
+ FromBigInteger(Y1),
+ withCompression);
+ }
+
+ protected internal override 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 ArithmeticException("Invalid point compression");
+
+ BigInteger betaValue = beta.ToBigInteger();
+ int bit0 = betaValue.TestBit(0) ? 1 : 0;
+
+ if (bit0 != yTilde)
+ {
+ // Use the other root
+ beta = FromBigInteger(q.Subtract(betaValue));
+ }
+
+ return new FpPoint(this, x, beta, true);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ FpCurve other = obj as FpCurve;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ FpCurve other)
+ {
+ return base.Equals(other) && q.Equals(other.q);
+ }
+
+ public override int GetHashCode()
+ {
+ return base.GetHashCode() ^ q.GetHashCode();
+ }
+ }
+
+ /**
+ * 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 class F2mCurve : ECCurveBase
+ {
+ /**
+ * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+ */
+ private readonly int m;
+
+ /**
+ * 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 readonly int k1;
+
+ /**
+ * 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 readonly int k2;
+
+ /**
+ * 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 readonly int k3;
+
+ /**
+ * The order of the base point of the curve.
+ */
+ private readonly BigInteger n;
+
+ /**
+ * The cofactor of the curve.
+ */
+ private readonly BigInteger h;
+
+ /**
+ * The point at infinity on this curve.
+ */
+ private readonly F2mPoint infinity;
+
+ /**
+ * The parameter <code>μ</code> of the elliptic curve if this is
+ * a Koblitz curve.
+ */
+ private sbyte 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 F2mCurve(
+ 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 F2mCurve(
+ 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 F2mCurve(
+ 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 F2mCurve(
+ 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;
+ this.infinity = new F2mPoint(this, null, null);
+
+ if (k1 == 0)
+ throw new ArgumentException("k1 must be > 0");
+
+ if (k2 == 0)
+ {
+ if (k3 != 0)
+ throw new ArgumentException("k3 must be 0 if k2 == 0");
+ }
+ else
+ {
+ if (k2 <= k1)
+ throw new ArgumentException("k2 must be > k1");
+
+ if (k3 <= k2)
+ throw new ArgumentException("k3 must be > k2");
+ }
+
+ this.a = FromBigInteger(a);
+ this.b = FromBigInteger(b);
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return m; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, x);
+ }
+
+ /**
+ * Returns true if this is a Koblitz curve (ABC curve).
+ * @return true if this is a Koblitz curve (ABC curve), false otherwise
+ */
+ public bool IsKoblitz
+ {
+ get
+ {
+ return n != null && h != null
+ && (a.ToBigInteger().Equals(BigInteger.Zero)
+ || a.ToBigInteger().Equals(BigInteger.One))
+ && b.ToBigInteger().Equals(BigInteger.One);
+ }
+ }
+
+ /**
+ * Returns the parameter <code>μ</code> of the elliptic curve.
+ * @return <code>μ</code> of the elliptic curve.
+ * @throws ArgumentException if the given ECCurve is not a
+ * Koblitz curve.
+ */
+ internal sbyte GetMu()
+ {
+ if (mu == 0)
+ {
+ lock (this)
+ {
+ 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.
+ */
+ internal BigInteger[] GetSi()
+ {
+ if (si == null)
+ {
+ lock (this)
+ {
+ if (si == null)
+ {
+ si = Tnaf.GetSi(this);
+ }
+ }
+ }
+ return si;
+ }
+
+ public override ECPoint CreatePoint(
+ BigInteger X1,
+ BigInteger Y1,
+ bool withCompression)
+ {
+ // TODO Validation of X1, Y1?
+ return new F2mPoint(
+ this,
+ FromBigInteger(X1),
+ FromBigInteger(Y1),
+ withCompression);
+ }
+
+ protected internal override ECPoint DecompressPoint(
+ int yTilde,
+ BigInteger X1)
+ {
+ ECFieldElement xp = FromBigInteger(X1);
+ ECFieldElement yp = null;
+ if (xp.ToBigInteger().SignValue == 0)
+ {
+ yp = (F2mFieldElement)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 ArithmeticException("Invalid point compression");
+
+ int zBit = z.ToBigInteger().TestBit(0) ? 1 : 0;
+ if (zBit != yTilde)
+ {
+ z = z.Add(FromBigInteger(BigInteger.One));
+ }
+
+ yp = xp.Multiply(z);
+ }
+
+ return new F2mPoint(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 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)
+ {
+ if (beta.ToBigInteger().SignValue == 0)
+ {
+ return FromBigInteger(BigInteger.Zero);
+ }
+
+ ECFieldElement z = null;
+ ECFieldElement gamma = FromBigInteger(BigInteger.Zero);
+
+ while (gamma.ToBigInteger().SignValue == 0)
+ {
+ ECFieldElement t = FromBigInteger(new BigInteger(m, new Random()));
+ z = FromBigInteger(BigInteger.Zero);
+
+ 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().SignValue != 0)
+ {
+ return null;
+ }
+ gamma = z.Square().Add(z);
+ }
+ return z;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ F2mCurve other = obj as F2mCurve;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ F2mCurve other)
+ {
+ return m == other.m
+ && k1 == other.k1
+ && k2 == other.k2
+ && k3 == other.k3
+ && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return base.GetHashCode() ^ m ^ k1 ^ k2 ^ k3;
+ }
+
+ public int M
+ {
+ get { return m; }
+ }
+
+ /**
+ * Return true if curve uses a Trinomial basis.
+ *
+ * @return true if curve Trinomial, false otherwise.
+ */
+ public bool IsTrinomial()
+ {
+ return k2 == 0 && k3 == 0;
+ }
+
+ public int K1
+ {
+ get { return k1; }
+ }
+
+ public int K2
+ {
+ get { return k2; }
+ }
+
+ public int K3
+ {
+ get { return k3; }
+ }
+
+ public BigInteger N
+ {
+ get { return n; }
+ }
+
+ public BigInteger H
+ {
+ get { return h; }
+ }
+ }
+}
|