summary refs log tree commit diff
path: root/crypto/src/math/ec/ECCurve.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/math/ec/ECCurve.cs')
-rw-r--r--crypto/src/math/ec/ECCurve.cs1482
1 files changed, 966 insertions, 516 deletions
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index 4dd5e74e2..eaa3e0c3d 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -2,230 +2,635 @@ using System;
 using System.Collections;
 
 using Org.BouncyCastle.Math.EC.Abc;
+using Org.BouncyCastle.Math.EC.Endo;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Math.Field;
+using Org.BouncyCastle.Utilities;
 
 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
+    /// <remarks>Base class for an elliptic curve.</remarks>
+    public abstract class ECCurve
     {
-        private readonly BigInteger q;
-		private readonly FpPoint infinity;
+        public const int COORD_AFFINE = 0;
+        public const int COORD_HOMOGENEOUS = 1;
+        public const int COORD_JACOBIAN = 2;
+        public const int COORD_JACOBIAN_CHUDNOVSKY = 3;
+        public const int COORD_JACOBIAN_MODIFIED = 4;
+        public const int COORD_LAMBDA_AFFINE = 5;
+        public const int COORD_LAMBDA_PROJECTIVE = 6;
+        public const 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 FpCurve(BigInteger q, BigInteger a, BigInteger b)
+        public class Config
         {
-            this.q = q;
-            this.a = FromBigInteger(a);
-            this.b = FromBigInteger(b);
-			this.infinity = new FpPoint(this, null, null);
+            protected ECCurve outer;
+            protected int coord;
+            protected ECEndomorphism endomorphism;
+            protected ECMultiplier multiplier;
+
+            internal Config(ECCurve outer, int coord, ECEndomorphism endomorphism, ECMultiplier multiplier)
+            {
+                this.outer = outer;
+                this.coord = coord;
+                this.endomorphism = endomorphism;
+                this.multiplier = multiplier;
+            }
+
+            public Config SetCoordinateSystem(int coord)
+            {
+                this.coord = coord;
+                return this;
+            }
+
+            public Config SetEndomorphism(ECEndomorphism endomorphism)
+            {
+                this.endomorphism = endomorphism;
+                return this;
+            }
+
+            public Config SetMultiplier(ECMultiplier multiplier)
+            {
+                this.multiplier = multiplier;
+                return this;
+            }
+
+            public ECCurve Create()
+            {
+                if (!outer.SupportsCoordinateSystem(coord))
+                {
+                    throw new InvalidOperationException("unsupported coordinate system");
+                }
+
+                ECCurve c = outer.CloneCurve();
+                if (c == outer)
+                {
+                    throw new InvalidOperationException("implementation returned current curve");
+                }
+
+                c.m_coord = coord;
+                c.m_endomorphism = endomorphism;
+                c.m_multiplier = multiplier;
+
+                return c;
+            }
+        }
+
+        protected readonly IFiniteField m_field;
+        protected ECFieldElement m_a, m_b;
+        protected BigInteger m_order, m_cofactor;
+
+        protected int m_coord = COORD_AFFINE;
+        protected ECEndomorphism m_endomorphism = null;
+        protected ECMultiplier m_multiplier = null;
+
+        protected ECCurve(IFiniteField field)
+        {
+            this.m_field = field;
         }
 
-		public BigInteger Q
+        public abstract int FieldSize { get; }
+        public abstract ECFieldElement FromBigInteger(BigInteger x);
+
+        public virtual Config Configure()
         {
-			get { return q; }
+            return new Config(this, this.m_coord, this.m_endomorphism, this.m_multiplier);
         }
 
-		public override ECPoint Infinity
-		{
-			get { return infinity; }
-		}
+        public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y)
+        {
+            ECPoint p = CreatePoint(x, y);
+            if (!p.IsValid())
+            {
+                throw new ArgumentException("Invalid point coordinates");
+            }
+            return p;
+        }
 
-		public override int FieldSize
-		{
-			get { return q.BitLength; }
-		}
+        [Obsolete("Per-point compression property will be removed")]
+        public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y, bool withCompression)
+        {
+            ECPoint p = CreatePoint(x, y, withCompression);
+            if (!p.IsValid())
+            {
+                throw new ArgumentException("Invalid point coordinates");
+            }
+            return p;
+        }
 
-		public override ECFieldElement FromBigInteger(BigInteger x)
+        public virtual ECPoint CreatePoint(BigInteger x, BigInteger y)
         {
-            return new FpFieldElement(this.q, x);
+            return CreatePoint(x, y, false);
         }
 
-		public override ECPoint CreatePoint(
-			BigInteger	X1,
-			BigInteger	Y1,
-			bool		withCompression)
-		{
-			// TODO Validation of X1, Y1?
-			return new FpPoint(
-				this,
-				FromBigInteger(X1),
-				FromBigInteger(Y1),
-				withCompression);
-		}
+        [Obsolete("Per-point compression property will be removed")]
+        public virtual ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
+        {
+            return CreateRawPoint(FromBigInteger(x), FromBigInteger(y), 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();
+        protected abstract ECCurve CloneCurve();
 
-			//
-			// 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");
+        protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression);
 
-			BigInteger betaValue = beta.ToBigInteger();
-			int bit0 = betaValue.TestBit(0) ? 1 : 0;
+        protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression);
 
-			if (bit0 != yTilde)
-			{
-				// Use the other root
-				beta = FromBigInteger(q.Subtract(betaValue));
-			}
+        protected virtual ECMultiplier CreateDefaultMultiplier()
+        {
+            GlvEndomorphism glvEndomorphism = m_endomorphism as GlvEndomorphism;
+            if (glvEndomorphism != null)
+            {
+                return new GlvMultiplier(this, glvEndomorphism);
+            }
 
-			return new FpPoint(this, x, beta, true);
-		}
+            return new WNafL2RMultiplier();
+        }
 
-		public override bool Equals(
-            object obj)
+        public virtual bool SupportsCoordinateSystem(int coord)
         {
-            if (obj == this)
-                return true;
+            return coord == COORD_AFFINE;
+        }
 
-			FpCurve other = obj as FpCurve;
+        public virtual PreCompInfo GetPreCompInfo(ECPoint point, string name)
+        {
+            CheckPoint(point);
+            lock (point)
+            {
+                IDictionary table = point.m_preCompTable;
+                return table == null ? null : (PreCompInfo)table[name];
+            }
+        }
+
+        /**
+         * Adds <code>PreCompInfo</code> for a point on this curve, under a given name. 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 name
+         *            A <code>String</code> used to index precomputations of different types.
+         * @param preCompInfo
+         *            The values precomputed by the <code>ECMultiplier</code>.
+         */
+        public virtual void SetPreCompInfo(ECPoint point, string name, PreCompInfo preCompInfo)
+        {
+            CheckPoint(point);
+            lock (point)
+            {
+                IDictionary table = point.m_preCompTable;
+                if (null == table)
+                {
+                    point.m_preCompTable = table = Platform.CreateHashtable(4);
+                }
+                table[name] = preCompInfo;
+            }
+        }
+
+        public virtual ECPoint ImportPoint(ECPoint p)
+        {
+            if (this == p.Curve)
+            {
+                return p;
+            }
+            if (p.IsInfinity)
+            {
+                return Infinity;
+            }
+
+            // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
+            p = p.Normalize();
+
+            return ValidatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
+        }
+
+        /**
+         * 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 virtual void NormalizeAll(ECPoint[] points)
+        {
+            CheckPoints(points);
+
+            if (this.CoordinateSystem == 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.MontgomeryTrick(zs, 0, count);
+
+            for (int j = 0; j < count; ++j)
+            {
+                int index = indices[j];
+                points[index] = points[index].Normalize(zs[j]);
+            }
+        }
+
+        public abstract ECPoint Infinity { get; }
+
+        public virtual IFiniteField Field
+        {
+            get { return m_field; }
+        }
+
+        public virtual ECFieldElement A
+        {
+            get { return m_a; }
+        }
 
-			if (other == null)
+        public virtual ECFieldElement B
+        {
+            get { return m_b; }
+        }
+
+        public virtual BigInteger Order
+        {
+            get { return m_order; }
+        }
+
+        public virtual BigInteger Cofactor
+        {
+            get { return m_cofactor; }
+        }
+
+        public virtual int CoordinateSystem
+        {
+            get { return m_coord; }
+        }
+
+        protected virtual void CheckPoint(ECPoint point)
+        {
+            if (null == point || (this != point.Curve))
+                throw new ArgumentException("must be non-null and on this curve", "point");
+        }
+
+        protected virtual void CheckPoints(ECPoint[] points)
+        {
+            if (points == null)
+                throw new ArgumentNullException("points");
+
+            for (int i = 0; i < points.Length; ++i)
+            {
+                ECPoint point = points[i];
+                if (null != point && this != point.Curve)
+                    throw new ArgumentException("entries must be null or on this curve", "points");
+            }
+        }
+
+        public virtual bool Equals(ECCurve other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
                 return false;
+            return Field.Equals(other.Field)
+                && A.ToBigInteger().Equals(other.A.ToBigInteger())
+                && B.ToBigInteger().Equals(other.B.ToBigInteger());
+        }
+
+        public override bool Equals(object obj) 
+        {
+            return Equals(obj as ECCurve);
+        }
+
+        public override int GetHashCode()
+        {
+            return Field.GetHashCode()
+                ^ Integers.RotateLeft(A.ToBigInteger().GetHashCode(), 8)
+                ^ Integers.RotateLeft(B.ToBigInteger().GetHashCode(), 16);
+        }
+
+        protected abstract ECPoint DecompressPoint(int yTilde, BigInteger X1);
+
+        public virtual ECEndomorphism GetEndomorphism()
+        {
+            return m_endomorphism;
+        }
+
+        /**
+         * Sets the default <code>ECMultiplier</code>, unless already set. 
+         */
+        public virtual ECMultiplier GetMultiplier()
+        {
+            lock (this)
+            {
+                if (this.m_multiplier == null)
+                {
+                    this.m_multiplier = CreateDefaultMultiplier();
+                }
+                return this.m_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 virtual ECPoint DecodePoint(byte[] encoded)
+        {
+            ECPoint p = null;
+            int expectedLength = (FieldSize + 7) / 8;
+
+            byte type = encoded[0];
+            switch (type)
+            {
+                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 = type & 1;
+                    BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
+
+                    p = DecompressPoint(yTilde, X);
+                    if (!p.SatisfiesCofactor())
+                        throw new ArgumentException("Invalid point");
+
+                    break;
+                }
+
+                case 0x04: // uncompressed
+                {
+                    if (encoded.Length != (2 * expectedLength + 1))
+                        throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded");
+
+                    BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
+                    BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
+
+                    p = ValidatePoint(X, Y);
+                    break;
+                }
+
+                case 0x06: // hybrid
+                case 0x07: // hybrid
+                {
+                    if (encoded.Length != (2 * expectedLength + 1))
+                        throw new ArgumentException("Incorrect length for hybrid encoding", "encoded");
+
+                    BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
+                    BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
+
+                    if (Y.TestBit(0) != (type == 0x07))
+                        throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded");
+
+                    p = ValidatePoint(X, Y);
+                    break;
+                }
+
+                default:
+                    throw new FormatException("Invalid point encoding " + type);
+            }
+
+            if (type != 0x00 && p.IsInfinity)
+                throw new ArgumentException("Invalid infinity encoding", "encoded");
 
-			return Equals(other);
+            return p;
         }
+    }
 
-		protected bool Equals(
-			FpCurve other)
-		{
-			return base.Equals(other) && q.Equals(other.q);
-		}
+    public abstract class AbstractFpCurve
+        : ECCurve
+    {
+        protected AbstractFpCurve(BigInteger q)
+            : base(FiniteFields.GetPrimeField(q))
+        {
+        }
 
-		public override int GetHashCode()
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
         {
-            return base.GetHashCode() ^ q.GetHashCode();
+            ECFieldElement x = FromBigInteger(X1);
+            ECFieldElement rhs = x.Square().Add(A).Multiply(x).Add(B);
+            ECFieldElement y = rhs.Sqrt();
+
+            /*
+             * If y is not a square, then we haven't got a point on the curve
+             */
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            if (y.TestBitZero() != (yTilde == 1))
+            {
+                // Use the other root
+                y = y.Negate();
+            }
+
+            return CreateRawPoint(x, y, true);
         }
     }
 
-	/**
+    /**
+     * Elliptic curve over Fp
+     */
+    public class FpCurve
+        : AbstractFpCurve
+    {
+        private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
+
+        protected readonly BigInteger m_q, m_r;
+        protected readonly FpPoint m_infinity;
+
+        public FpCurve(BigInteger q, BigInteger a, BigInteger b)
+            : this(q, a, b, null, null)
+        {
+        }
+
+        public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
+            : base(q)
+        {
+            this.m_q = q;
+            this.m_r = FpFieldElement.CalculateResidue(q);
+            this.m_infinity = new FpPoint(this, null, null);
+
+            this.m_a = FromBigInteger(a);
+            this.m_b = FromBigInteger(b);
+            this.m_order = order;
+            this.m_cofactor = cofactor;
+            this.m_coord = FP_DEFAULT_COORDS;
+        }
+
+        protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
+            : this(q, r, a, b, null, null)
+        {
+        }
+
+        protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
+            : base(q)
+        {
+            this.m_q = q;
+            this.m_r = r;
+            this.m_infinity = new FpPoint(this, null, null);
+
+            this.m_a = a;
+            this.m_b = b;
+            this.m_order = order;
+            this.m_cofactor = cofactor;
+            this.m_coord = FP_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new FpCurve(m_q, m_r, m_a, m_b, m_order, m_cofactor);
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+                case COORD_AFFINE:
+                case COORD_HOMOGENEOUS:
+                case COORD_JACOBIAN:
+                case COORD_JACOBIAN_MODIFIED:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return m_q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return m_q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new FpFieldElement(this.m_q, this.m_r, x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new FpPoint(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new FpPoint(this, x, y, zs, withCompression);
+        }
+
+        public override ECPoint ImportPoint(ECPoint p)
+        {
+            if (this != p.Curve && this.CoordinateSystem == COORD_JACOBIAN && !p.IsInfinity)
+            {
+                switch (p.Curve.CoordinateSystem)
+                {
+                    case COORD_JACOBIAN:
+                    case COORD_JACOBIAN_CHUDNOVSKY:
+                    case COORD_JACOBIAN_MODIFIED:
+                        return new FpPoint(this,
+                            FromBigInteger(p.RawXCoord.ToBigInteger()),
+                            FromBigInteger(p.RawYCoord.ToBigInteger()),
+                            new ECFieldElement[] { FromBigInteger(p.GetZCoord(0).ToBigInteger()) },
+                            p.IsCompressed);
+                    default:
+                        break;
+                }
+            }
+
+            return base.ImportPoint(p);
+        }
+    }
+
+    public abstract class AbstractF2mCurve
+        : ECCurve
+    {
+        private static IFiniteField BuildField(int m, int k1, int k2, int k3)
+        {
+            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");
+                }
+
+                return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, m });
+            }
+
+            if (k2 <= k1)
+            {
+                throw new ArgumentException("k2 must be > k1");
+            }
+
+            if (k3 <= k2)
+            {
+                throw new ArgumentException("k3 must be > k2");
+            }
+
+            return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, k2, k3, m });
+        }
+
+        protected AbstractF2mCurve(int m, int k1, int k2, int k3)
+            : base(BuildField(m, k1, k2, k3))
+        {
+        }
+    }
+
+    /**
      * 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
+    public class F2mCurve
+        : AbstractF2mCurve
     {
+        private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
         /**
          * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
          */
@@ -257,161 +662,152 @@ namespace Org.BouncyCastle.Math.EC
          */
         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>&#956;</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)
+        /**
+         * The point at infinity on this curve.
+         */
+        protected readonly F2mPoint m_infinity;
+
+        /**
+         * The parameter <code>&#956;</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 order The order of the main subgroup of the elliptic curve.
+         * @param cofactor 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	order,
+            BigInteger	cofactor)
+            : this(m, k, 0, 0, a, b, order, cofactor)
+        {
+        }
+
+        /**
+         * 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 order The order of the main subgroup of the elliptic curve.
+         * @param cofactor 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	order,
+            BigInteger	cofactor)
+            : base(m, k1, k2, k3)
+        {
+            this.m = m;
+            this.k1 = k1;
+            this.k2 = k2;
+            this.k3 = k3;
+            this.m_order = order;
+            this.m_cofactor = cofactor;
+            this.m_infinity = new F2mPoint(this, null, null);
+
+            if (k1 == 0)
                 throw new ArgumentException("k1 must be > 0");
 
-			if (k2 == 0)
+            if (k2 == 0)
             {
                 if (k3 != 0)
                     throw new ArgumentException("k3 must be 0 if k2 == 0");
@@ -421,135 +817,212 @@ namespace Org.BouncyCastle.Math.EC
                 if (k2 <= k1)
                     throw new ArgumentException("k2 must be > k1");
 
-				if (k3 <= k2)
+                if (k3 <= k2)
                     throw new ArgumentException("k3 must be > k2");
             }
 
-			this.a = FromBigInteger(a);
-            this.b = FromBigInteger(b);
+            this.m_a = FromBigInteger(a);
+            this.m_b = FromBigInteger(b);
+            this.m_coord = F2M_DEFAULT_COORDS;
+        }
+
+        protected F2mCurve(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
+            : base(m, k1, k2, k3)
+        {
+            this.m = m;
+            this.k1 = k1;
+            this.k2 = k2;
+            this.k3 = k3;
+            this.m_order = order;
+            this.m_cofactor = cofactor;
+
+            this.m_infinity = new F2mPoint(this, null, null);
+            this.m_a = a;
+            this.m_b = b;
+            this.m_coord = F2M_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new F2mCurve(m, k1, k2, k3, m_a, m_b, m_order, m_cofactor);
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+                case COORD_AFFINE:
+                case COORD_HOMOGENEOUS:
+                case COORD_LAMBDA_PROJECTIVE:
+                    return true;
+                default:
+                    return false;
+            }
         }
 
-		public override ECPoint Infinity
-		{
-			get { return infinity; }
-		}
+        protected override ECMultiplier CreateDefaultMultiplier()
+        {
+            if (IsKoblitz)
+            {
+                return new WTauNafMultiplier();
+            }
 
-		public override int FieldSize
-		{
-			get { return m; }
-		}
+            return base.CreateDefaultMultiplier();
+        }
+
+        public override int FieldSize
+        {
+            get { return m; }
+        }
 
-		public override ECFieldElement FromBigInteger(BigInteger x)
+        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>&#956;</code> of the elliptic curve.
-		 * @return <code>&#956;</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);
-		}
-
-		/**
+        [Obsolete("Per-point compression property will be removed")]
+        public override ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
+        {
+            ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y);
+
+            switch (this.CoordinateSystem)
+            {
+                case COORD_LAMBDA_AFFINE:
+                case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        if (X.IsZero)
+                        {
+                            if (!Y.Square().Equals(B))
+                                throw new ArgumentException();
+                        }
+                        else
+                        {
+                            // Y becomes Lambda (X + Y/X) here
+                            Y = Y.Divide(X).Add(X);
+                        }
+                        break;
+                    }
+                default:
+                    {
+                        break;
+                    }
+            }
+
+            return CreateRawPoint(X, Y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new F2mPoint(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new F2mPoint(this, x, y, zs, withCompression);
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        /**
+         * Returns true if this is a Koblitz curve (ABC curve).
+         * @return true if this is a Koblitz curve (ABC curve), false otherwise
+         */
+        public virtual bool IsKoblitz
+        {
+            get
+            {
+                return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne);
+            }
+        }
+
+        /**
+         * Returns the parameter <code>&#956;</code> of the elliptic curve.
+         * @return <code>&#956;</code> of the elliptic curve.
+         * @throws ArgumentException if the given ECCurve is not a
+         * Koblitz curve.
+         */
+        internal virtual 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 virtual BigInteger[] GetSi()
+        {
+            if (si == null)
+            {
+                lock (this)
+                {
+                    if (si == null)
+                    {
+                        si = Tnaf.GetSi(this);
+                    }
+                }
+            }
+            return si;
+        }
+
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement xp = FromBigInteger(X1), yp = null;
+            if (xp.IsZero)
+            {
+                yp = m_b.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
+                ECFieldElement z = SolveQuadradicEquation(beta);
+
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                        case COORD_LAMBDA_AFFINE:
+                        case COORD_LAMBDA_PROJECTIVE:
+                        {
+                            yp = z.Add(xp);
+                            break;
+                        }
+                        default:
+                        {
+                            yp = z.Multiply(xp);
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if (yp == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return CreateRawPoint(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>.
          *
@@ -558,72 +1031,47 @@ namespace Org.BouncyCastle.Math.EC
          * @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)
+        private ECFieldElement SolveQuadradicEquation(ECFieldElement beta)
         {
-            if (beta.ToBigInteger().SignValue == 0)
+            if (beta.IsZero)
             {
-                return FromBigInteger(BigInteger.Zero);
+                return beta;
             }
 
-			ECFieldElement z = null;
-            ECFieldElement gamma = FromBigInteger(BigInteger.Zero);
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
 
-			while (gamma.ToBigInteger().SignValue == 0)
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(m, new Random()));
-				z = FromBigInteger(BigInteger.Zero);
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
 
-				ECFieldElement w = beta;
+            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();
+                    ECFieldElement w2 = w.Square();
                     z = z.Square().Add(w2.Multiply(t));
                     w = w2.Add(beta);
                 }
-                if (w.ToBigInteger().SignValue != 0)
+                if (!w.IsZero)
                 {
                     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);
-        }
+            while (gamma.IsZero);
 
-		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;
+            return z;
         }
 
-		public int M
+        public int M
         {
-			get { return m; }
+            get { return m; }
         }
 
-		/**
+        /**
          * Return true if curve uses a Trinomial basis.
          *
          * @return true if curve Trinomial, false otherwise.
@@ -633,29 +1081,31 @@ namespace Org.BouncyCastle.Math.EC
             return k2 == 0 && k3 == 0;
         }
 
-		public int K1
+        public int K1
         {
-			get { return k1; }
+            get { return k1; }
         }
 
-		public int K2
+        public int K2
         {
-			get { return k2; }
+            get { return k2; }
         }
 
-		public int K3
+        public int K3
         {
-			get { return k3; }
+            get { return k3; }
         }
 
-		public BigInteger N
-		{
-			get { return n; }
-		}
+        [Obsolete("Use 'Order' property instead")]
+        public BigInteger N
+        {
+            get { return m_order; }
+        }
 
-		public BigInteger H
-		{
-			get { return h; }
-		}
-	}
+        [Obsolete("Use 'Cofactor' property instead")]
+        public BigInteger H
+        {
+            get { return m_cofactor; }
+        }
+    }
 }