summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2014-01-22 11:40:05 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2014-01-22 11:40:05 +0700
commit73cb18129e632b44ddae7f9c589fd9c17c77d3ca (patch)
treecbe867e5538f2a9d37f3eadb49a4104a64261971 /crypto/src
parentImplement TwicePlus optimization in Fp curves (diff)
downloadBouncyCastle.NET-ed25519-73cb18129e632b44ddae7f9c589fd9c17c77d3ca.tar.xz
Use new Math.Field classes in EC curves, and avoid casting in client code
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/asn1/x9/X9Curve.cs161
-rw-r--r--crypto/src/asn1/x9/X9ECParameters.cs106
-rw-r--r--crypto/src/asn1/x9/X9FieldID.cs144
-rw-r--r--crypto/src/math/ec/ECAlgorithms.cs170
-rw-r--r--crypto/src/math/ec/ECCurve.cs153
5 files changed, 385 insertions, 349 deletions
diff --git a/crypto/src/asn1/x9/X9Curve.cs b/crypto/src/asn1/x9/X9Curve.cs
index b92e7b3b5..f05a946c2 100644
--- a/crypto/src/asn1/x9/X9Curve.cs
+++ b/crypto/src/asn1/x9/X9Curve.cs
@@ -15,51 +15,50 @@ namespace Org.BouncyCastle.Asn1.X9
     {
         private readonly ECCurve curve;
         private readonly byte[] seed;
-		private readonly DerObjectIdentifier fieldIdentifier;
+        private readonly DerObjectIdentifier fieldIdentifier;
 
-		public X9Curve(
+        public X9Curve(
             ECCurve curve)
-			: this(curve, null)
+            : this(curve, null)
         {
-            this.curve = curve;
         }
 
-		public X9Curve(
+        public X9Curve(
             ECCurve	curve,
             byte[]	seed)
         {
-			if (curve == null)
-				throw new ArgumentNullException("curve");
+            if (curve == null)
+                throw new ArgumentNullException("curve");
 
-			this.curve = curve;
+            this.curve = curve;
             this.seed = Arrays.Clone(seed);
 
-			if (curve is FpCurve)
-			{
-				this.fieldIdentifier = X9ObjectIdentifiers.PrimeField;
-			}
-			else if (curve is F2mCurve)
-			{
-				this.fieldIdentifier = X9ObjectIdentifiers.CharacteristicTwoField;
-			}
-			else
-			{
-				throw new ArgumentException("This type of ECCurve is not implemented");
-			}
-		}
-
-		public X9Curve(
+            if (ECAlgorithms.IsFpCurve(curve))
+            {
+                this.fieldIdentifier = X9ObjectIdentifiers.PrimeField;
+            }
+            else if (ECAlgorithms.IsF2mCurve(curve))
+            {
+                this.fieldIdentifier = X9ObjectIdentifiers.CharacteristicTwoField;
+            }
+            else
+            {
+                throw new ArgumentException("This type of ECCurve is not implemented");
+            }
+        }
+
+        public X9Curve(
             X9FieldID		fieldID,
             Asn1Sequence	seq)
         {
-			if (fieldID == null)
-				throw new ArgumentNullException("fieldID");
-			if (seq == null)
-				throw new ArgumentNullException("seq");
+            if (fieldID == null)
+                throw new ArgumentNullException("fieldID");
+            if (seq == null)
+                throw new ArgumentNullException("seq");
 
-			this.fieldIdentifier = fieldID.Identifier;
+            this.fieldIdentifier = fieldID.Identifier;
 
-			if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField))
+            if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField))
             {
                 BigInteger q = ((DerInteger) fieldID.Parameters).Value;
                 X9FieldElement x9A = new X9FieldElement(q, (Asn1OctetString) seq[0]);
@@ -68,54 +67,54 @@ namespace Org.BouncyCastle.Asn1.X9
             }
             else
             {
-				if (fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
-				{
-					// Characteristic two field
-					DerSequence parameters = (DerSequence)fieldID.Parameters;
-					int m = ((DerInteger)parameters[0]).Value.IntValue;
-					DerObjectIdentifier representation
-						= (DerObjectIdentifier)parameters[1];
-
-					int k1 = 0;
-					int k2 = 0;
-					int k3 = 0;
-					if (representation.Equals(X9ObjectIdentifiers.TPBasis)) 
-					{
-						// Trinomial basis representation
-						k1 = ((DerInteger)parameters[2]).Value.IntValue;
-					}
-					else 
-					{
-						// Pentanomial basis representation
-						DerSequence pentanomial = (DerSequence) parameters[2];
-						k1 = ((DerInteger) pentanomial[0]).Value.IntValue;
-						k2 = ((DerInteger) pentanomial[1]).Value.IntValue;
-						k3 = ((DerInteger) pentanomial[2]).Value.IntValue;
-					}
-					X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[0]);
-					X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[1]);
-					// TODO Is it possible to get the order (n) and cofactor(h) too?
-					curve = new F2mCurve(m, k1, k2, k3, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger());
-				}
-			}
-
-			if (seq.Count == 3)
+                if (fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
+                {
+                    // Characteristic two field
+                    DerSequence parameters = (DerSequence)fieldID.Parameters;
+                    int m = ((DerInteger)parameters[0]).Value.IntValue;
+                    DerObjectIdentifier representation
+                        = (DerObjectIdentifier)parameters[1];
+
+                    int k1 = 0;
+                    int k2 = 0;
+                    int k3 = 0;
+                    if (representation.Equals(X9ObjectIdentifiers.TPBasis)) 
+                    {
+                        // Trinomial basis representation
+                        k1 = ((DerInteger)parameters[2]).Value.IntValue;
+                    }
+                    else 
+                    {
+                        // Pentanomial basis representation
+                        DerSequence pentanomial = (DerSequence) parameters[2];
+                        k1 = ((DerInteger) pentanomial[0]).Value.IntValue;
+                        k2 = ((DerInteger) pentanomial[1]).Value.IntValue;
+                        k3 = ((DerInteger) pentanomial[2]).Value.IntValue;
+                    }
+                    X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[0]);
+                    X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[1]);
+                    // TODO Is it possible to get the order (n) and cofactor(h) too?
+                    curve = new F2mCurve(m, k1, k2, k3, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger());
+                }
+            }
+
+            if (seq.Count == 3)
             {
                 seed = ((DerBitString) seq[2]).GetBytes();
             }
         }
 
-		public ECCurve Curve
+        public ECCurve Curve
         {
-			get { return curve; }
+            get { return curve; }
         }
 
-		public byte[] GetSeed()
+        public byte[] GetSeed()
         {
             return Arrays.Clone(seed);
         }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          *  Curve ::= Sequence {
@@ -127,21 +126,21 @@ namespace Org.BouncyCastle.Asn1.X9
          */
         public override Asn1Object ToAsn1Object()
         {
-			Asn1EncodableVector v = new Asn1EncodableVector();
-
-			if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField)
-				|| fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
-			{ 
-				v.Add(new X9FieldElement(curve.A).ToAsn1Object());
-				v.Add(new X9FieldElement(curve.B).ToAsn1Object());
-			} 
-
-			if (seed != null)
-			{
-				v.Add(new DerBitString(seed));
-			}
-
-			return new DerSequence(v);
-		}
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField)
+                || fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
+            { 
+                v.Add(new X9FieldElement(curve.A).ToAsn1Object());
+                v.Add(new X9FieldElement(curve.B).ToAsn1Object());
+            } 
+
+            if (seed != null)
+            {
+                v.Add(new DerBitString(seed));
+            }
+
+            return new DerSequence(v);
+        }
     }
 }
diff --git a/crypto/src/asn1/x9/X9ECParameters.cs b/crypto/src/asn1/x9/X9ECParameters.cs
index d025b36ce..6389defa8 100644
--- a/crypto/src/asn1/x9/X9ECParameters.cs
+++ b/crypto/src/asn1/x9/X9ECParameters.cs
@@ -2,6 +2,7 @@ using System;
 
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.Field;
 
 namespace Org.BouncyCastle.Asn1.X9
 {
@@ -19,7 +20,7 @@ namespace Org.BouncyCastle.Asn1.X9
         private BigInteger	h;
         private byte[]		seed;
 
-		public X9ECParameters(
+        public X9ECParameters(
             Asn1Sequence seq)
         {
             if (!(seq[0] is DerInteger)
@@ -28,7 +29,7 @@ namespace Org.BouncyCastle.Asn1.X9
                 throw new ArgumentException("bad version in X9ECParameters");
             }
 
-			X9Curve x9c = null;
+            X9Curve x9c = null;
             if (seq[2] is X9Curve)
             {
                 x9c = (X9Curve) seq[2];
@@ -36,14 +37,14 @@ namespace Org.BouncyCastle.Asn1.X9
             else
             {
                 x9c = new X9Curve(
-					new X9FieldID(
-						(Asn1Sequence) seq[1]),
-						(Asn1Sequence) seq[2]);
+                    new X9FieldID(
+                        (Asn1Sequence) seq[1]),
+                        (Asn1Sequence) seq[2]);
             }
 
-			this.curve = x9c.Curve;
+            this.curve = x9c.Curve;
 
-			if (seq[3] is X9ECPoint)
+            if (seq[3] is X9ECPoint)
             {
                 this.g = ((X9ECPoint) seq[3]).Point;
             }
@@ -52,16 +53,16 @@ namespace Org.BouncyCastle.Asn1.X9
                 this.g = new X9ECPoint(curve, (Asn1OctetString) seq[3]).Point;
             }
 
-			this.n = ((DerInteger) seq[4]).Value;
+            this.n = ((DerInteger) seq[4]).Value;
             this.seed = x9c.GetSeed();
 
-			if (seq.Count == 6)
+            if (seq.Count == 6)
             {
                 this.h = ((DerInteger) seq[5]).Value;
             }
         }
 
-		public X9ECParameters(
+        public X9ECParameters(
             ECCurve		curve,
             ECPoint		g,
             BigInteger	n)
@@ -69,7 +70,7 @@ namespace Org.BouncyCastle.Asn1.X9
         {
         }
 
-		public X9ECParameters(
+        public X9ECParameters(
             ECCurve		curve,
             ECPoint		g,
             BigInteger	n,
@@ -78,7 +79,7 @@ namespace Org.BouncyCastle.Asn1.X9
         {
         }
 
-		public X9ECParameters(
+        public X9ECParameters(
             ECCurve		curve,
             ECPoint		g,
             BigInteger	n,
@@ -91,53 +92,68 @@ namespace Org.BouncyCastle.Asn1.X9
             this.h = h;
             this.seed = seed;
 
-			if (curve is FpCurve)
-			{
-				this.fieldID = new X9FieldID(((FpCurve) curve).Q);
-			}
-			else if (curve is F2mCurve)
-			{
-				F2mCurve curveF2m = (F2mCurve) curve;
-				this.fieldID = new X9FieldID(curveF2m.M, curveF2m.K1,
-					curveF2m.K2, curveF2m.K3);
-			}
+            if (ECAlgorithms.IsFpCurve(curve))
+            {
+                this.fieldID = new X9FieldID(curve.Field.Characteristic);
+            }
+            else if (ECAlgorithms.IsF2mCurve(curve))
+            {
+                IPolynomialExtensionField field = (IPolynomialExtensionField)curve.Field;
+                int[] exponents = field.MinimalPolynomial.GetExponentsPresent();
+                if (exponents.Length == 3)
+                {
+                    this.fieldID = new X9FieldID(exponents[2], exponents[1]);
+                }
+                else if (exponents.Length == 5)
+                {
+                    this.fieldID = new X9FieldID(exponents[4], exponents[1], exponents[2], exponents[3]);
+                }
+                else
+                {
+                    throw new ArgumentException("Only trinomial and pentomial curves are supported");
+                }
+            }
+            else
+            {
+                throw new ArgumentException("'curve' is of an unsupported type");
+            }
         }
 
-		public ECCurve Curve
+        public ECCurve Curve
         {
-			get { return curve; }
+            get { return curve; }
         }
 
-		public ECPoint G
+        public ECPoint G
         {
             get { return g; }
         }
 
-		public BigInteger N
+        public BigInteger N
         {
             get { return n; }
         }
 
-		public BigInteger H
+        public BigInteger H
         {
             get
-			{
-				if (h == null)
-				{
-					// TODO - this should be calculated, it will cause issues with custom curves.
-					return BigInteger.One;
-				}
-
-				return h;
-			}
+            {
+                if (h == null)
+                {
+                    // TODO - this should be calculated, it will cause issues with custom curves.
+                    return BigInteger.One;
+                }
+
+                return h;
+            }
         }
 
-		public byte[] GetSeed()
+        public byte[] GetSeed()
         {
             return seed;
         }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          *  ECParameters ::= Sequence {
@@ -153,18 +169,18 @@ namespace Org.BouncyCastle.Asn1.X9
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector v = new Asn1EncodableVector(
-				new DerInteger(1),
-				fieldID,
-				new X9Curve(curve, seed),
-				new X9ECPoint(g),
-				new DerInteger(n));
+                new DerInteger(1),
+                fieldID,
+                new X9Curve(curve, seed),
+                new X9ECPoint(g),
+                new DerInteger(n));
 
-			if (h != null)
+            if (h != null)
             {
                 v.Add(new DerInteger(h));
             }
 
-			return new DerSequence(v);
+            return new DerSequence(v);
         }
     }
 }
diff --git a/crypto/src/asn1/x9/X9FieldID.cs b/crypto/src/asn1/x9/X9FieldID.cs
index c51cc4df2..58823a285 100644
--- a/crypto/src/asn1/x9/X9FieldID.cs
+++ b/crypto/src/asn1/x9/X9FieldID.cs
@@ -1,3 +1,5 @@
+using System;
+
 using Org.BouncyCastle.Math;
 
 namespace Org.BouncyCastle.Asn1.X9
@@ -12,80 +14,100 @@ namespace Org.BouncyCastle.Asn1.X9
         private readonly DerObjectIdentifier	id;
         private readonly Asn1Object parameters;
 
-		/**
-		 * Constructor for elliptic curves over prime fields
-		 * <code>F<sub>2</sub></code>.
-		 * @param primeP The prime <code>p</code> defining the prime field.
-		 */
-		public X9FieldID(
-			BigInteger primeP)
-		{
-			this.id = X9ObjectIdentifiers.PrimeField;
-			this.parameters = new DerInteger(primeP);
-		}
+        /**
+         * Constructor for elliptic curves over prime fields
+         * <code>F<sub>2</sub></code>.
+         * @param primeP The prime <code>p</code> defining the prime field.
+         */
+        public X9FieldID(
+            BigInteger primeP)
+        {
+            this.id = X9ObjectIdentifiers.PrimeField;
+            this.parameters = new DerInteger(primeP);
+        }
 
-		/**
-		 * Constructor for elliptic curves over binary fields
-		 * <code>F<sub>2<sup>m</sup></sub></code>.
-		 * @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>..
-		 */
-		public X9FieldID(
-			int m,
-			int k1,
-			int k2,
-			int k3)
-		{
-			this.id = X9ObjectIdentifiers.CharacteristicTwoField;
+        /**
+         * Constructor for elliptic curves over binary fields
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @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>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         */
+        public X9FieldID(int m, int k1)
+            : this(m, k1, 0, 0)
+        {
+        }
 
-			Asn1EncodableVector fieldIdParams = new Asn1EncodableVector(new DerInteger(m));
+        /**
+         * Constructor for elliptic curves over binary fields
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @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>..
+         */
+        public X9FieldID(
+            int m,
+            int k1,
+            int k2,
+            int k3)
+        {
+            this.id = X9ObjectIdentifiers.CharacteristicTwoField;
+
+            Asn1EncodableVector fieldIdParams = new Asn1EncodableVector(new DerInteger(m));
 
-			if (k2 == 0)
-			{
-				fieldIdParams.Add(
-					X9ObjectIdentifiers.TPBasis,
-					new DerInteger(k1));
-			}
-			else
-			{
-				fieldIdParams.Add(
-					X9ObjectIdentifiers.PPBasis,
-					new DerSequence(
-						new DerInteger(k1),
-						new DerInteger(k2),
-						new DerInteger(k3)));
-			}
+            if (k2 == 0)
+            {
+                if (k3 != 0)
+                    throw new ArgumentException("inconsistent k values");
 
-			this.parameters = new DerSequence(fieldIdParams);
-		}
+                fieldIdParams.Add(
+                    X9ObjectIdentifiers.TPBasis,
+                    new DerInteger(k1));
+            }
+            else
+            {
+                if (k2 <= k1 || k3 <= k2)
+                    throw new ArgumentException("inconsistent k values");
 
-		internal X9FieldID(
-			Asn1Sequence seq)
-		{
-			this.id = (DerObjectIdentifier) seq[0];
-			this.parameters = (Asn1Object) seq[1];
-		}
+                fieldIdParams.Add(
+                    X9ObjectIdentifiers.PPBasis,
+                    new DerSequence(
+                        new DerInteger(k1),
+                        new DerInteger(k2),
+                        new DerInteger(k3)));
+            }
+
+            this.parameters = new DerSequence(fieldIdParams);
+        }
+
+        internal X9FieldID(
+            Asn1Sequence seq)
+        {
+            this.id = (DerObjectIdentifier) seq[0];
+            this.parameters = (Asn1Object) seq[1];
+        }
 
-		public DerObjectIdentifier Identifier
+        public DerObjectIdentifier Identifier
         {
             get { return id; }
         }
 
-		public Asn1Object Parameters
+        public Asn1Object Parameters
         {
             get { return parameters; }
         }
 
-		/**
+        /**
          * Produce a Der encoding of the following structure.
          * <pre>
          *  FieldID ::= Sequence {
@@ -96,7 +118,7 @@ namespace Org.BouncyCastle.Asn1.X9
          */
         public override Asn1Object ToAsn1Object()
         {
-			return new DerSequence(id, parameters);
+            return new DerSequence(id, parameters);
         }
     }
 }
diff --git a/crypto/src/math/ec/ECAlgorithms.cs b/crypto/src/math/ec/ECAlgorithms.cs
index be4fd1b14..06288132b 100644
--- a/crypto/src/math/ec/ECAlgorithms.cs
+++ b/crypto/src/math/ec/ECAlgorithms.cs
@@ -1,93 +1,105 @@
 using System;
 
-using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.Field;
 
 namespace Org.BouncyCastle.Math.EC
 {
-	public class ECAlgorithms
-	{
-		public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a,
-			ECPoint Q, BigInteger b)
-		{
-			ECCurve c = P.Curve;
-			if (!c.Equals(Q.Curve))
-				throw new ArgumentException("P and Q must be on same curve");
+    public class ECAlgorithms
+    {
+        public static bool IsF2mCurve(ECCurve c)
+        {
+            IFiniteField field = c.Field;
+            return field.Dimension > 1 && field.Characteristic.Equals(BigInteger.Two)
+                && field is IPolynomialExtensionField;
+        }
 
-			// Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
-			if (c is F2mCurve)
-			{
-				F2mCurve f2mCurve = (F2mCurve) c;
-				if (f2mCurve.IsKoblitz)
-				{
-					return P.Multiply(a).Add(Q.Multiply(b));
-				}
-			}
+        public static bool IsFpCurve(ECCurve c)
+        {
+            return c.Field.Dimension == 1;
+        }
 
-			return ImplShamirsTrick(P, a, Q, b);
-		}
+        public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a,
+            ECPoint Q, BigInteger b)
+        {
+            ECCurve c = P.Curve;
+            if (!c.Equals(Q.Curve))
+                throw new ArgumentException("P and Q must be on same curve");
 
-		/*
-		* "Shamir's Trick", originally due to E. G. Straus
-		* (Addition chains of vectors. American Mathematical Monthly,
-		* 71(7):806-808, Aug./Sept. 1964)
-		*  
-		* Input: The points P, Q, scalar k = (km?, ... , k1, k0)
-		* and scalar l = (lm?, ... , l1, l0).
-		* Output: R = k * P + l * Q.
-		* 1: Z <- P + Q
-		* 2: R <- O
-		* 3: for i from m-1 down to 0 do
-		* 4:        R <- R + R        {point doubling}
-		* 5:        if (ki = 1) and (li = 0) then R <- R + P end if
-		* 6:        if (ki = 0) and (li = 1) then R <- R + Q end if
-		* 7:        if (ki = 1) and (li = 1) then R <- R + Z end if
-		* 8: end for
-		* 9: return R
-		*/
-		public static ECPoint ShamirsTrick(
-			ECPoint		P,
-			BigInteger	k,
-			ECPoint		Q,
-			BigInteger	l)
-		{
-			if (!P.Curve.Equals(Q.Curve))
-				throw new ArgumentException("P and Q must be on same curve");
+            // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
+            if (c is F2mCurve)
+            {
+                F2mCurve f2mCurve = (F2mCurve) c;
+                if (f2mCurve.IsKoblitz)
+                {
+                    return P.Multiply(a).Add(Q.Multiply(b));
+                }
+            }
 
-			return ImplShamirsTrick(P, k, Q, l);
-		}
+            return ImplShamirsTrick(P, a, Q, b);
+        }
 
-		private static ECPoint ImplShamirsTrick(ECPoint P, BigInteger k,
-			ECPoint Q, BigInteger l)
-		{
-			int m = System.Math.Max(k.BitLength, l.BitLength);
-			ECPoint Z = P.Add(Q);
-			ECPoint R = P.Curve.Infinity;
+        /*
+        * "Shamir's Trick", originally due to E. G. Straus
+        * (Addition chains of vectors. American Mathematical Monthly,
+        * 71(7):806-808, Aug./Sept. 1964)
+        *  
+        * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
+        * and scalar l = (lm?, ... , l1, l0).
+        * Output: R = k * P + l * Q.
+        * 1: Z <- P + Q
+        * 2: R <- O
+        * 3: for i from m-1 down to 0 do
+        * 4:        R <- R + R        {point doubling}
+        * 5:        if (ki = 1) and (li = 0) then R <- R + P end if
+        * 6:        if (ki = 0) and (li = 1) then R <- R + Q end if
+        * 7:        if (ki = 1) and (li = 1) then R <- R + Z end if
+        * 8: end for
+        * 9: return R
+        */
+        public static ECPoint ShamirsTrick(
+            ECPoint		P,
+            BigInteger	k,
+            ECPoint		Q,
+            BigInteger	l)
+        {
+            if (!P.Curve.Equals(Q.Curve))
+                throw new ArgumentException("P and Q must be on same curve");
 
-			for (int i = m - 1; i >= 0; --i)
-			{
-				R = R.Twice();
+            return ImplShamirsTrick(P, k, Q, l);
+        }
 
-				if (k.TestBit(i))
-				{
-					if (l.TestBit(i))
-					{
-						R = R.Add(Z);
-					}
-					else
-					{
-						R = R.Add(P);
-					}
-				}
-				else
-				{
-					if (l.TestBit(i))
-					{
-						R = R.Add(Q);
-					}
-				}
-			}
+        private static ECPoint ImplShamirsTrick(ECPoint P, BigInteger k,
+            ECPoint Q, BigInteger l)
+        {
+            int m = System.Math.Max(k.BitLength, l.BitLength);
+            ECPoint Z = P.Add(Q);
+            ECPoint R = P.Curve.Infinity;
 
-			return R;
-		}
-	}
+            for (int i = m - 1; i >= 0; --i)
+            {
+                R = R.Twice();
+
+                if (k.TestBit(i))
+                {
+                    if (l.TestBit(i))
+                    {
+                        R = R.Add(Z);
+                    }
+                    else
+                    {
+                        R = R.Add(P);
+                    }
+                }
+                else
+                {
+                    if (l.TestBit(i))
+                    {
+                        R = R.Add(Q);
+                    }
+                }
+            }
+
+            return R;
+        }
+    }
 }
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index ab98af8f1..6f4492e5c 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -2,52 +2,63 @@ using System;
 using System.Collections;
 
 using Org.BouncyCastle.Math.EC.Abc;
+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;
+        protected IFiniteField m_field;
+        protected ECFieldElement m_a, m_b;
+
+        protected ECCurve(IFiniteField field)
+        {
+            this.m_field = field;
+        }
 
         public abstract int FieldSize { get; }
         public abstract ECFieldElement FromBigInteger(BigInteger x);
         public abstract ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression);
         public abstract ECPoint Infinity { get; }
 
-        public ECFieldElement A
+        public virtual IFiniteField Field
         {
-            get { return a; }
+            get { return m_field; }
         }
 
-        public ECFieldElement B
+        public virtual ECFieldElement A
         {
-            get { return b; }
+            get { return m_a; }
         }
 
-        public override bool Equals(
-            object obj)
+        public virtual ECFieldElement B
         {
-            if (obj == this)
-                return true;
-
-            ECCurve other = obj as ECCurve;
+            get { return m_b; }
+        }
 
-            if (other == null)
+        public virtual bool Equals(ECCurve other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
                 return false;
-
-            return Equals(other);
+            return Field.Equals(other.Field)
+                && A.Equals(other.A)
+                && B.Equals(other.B);
         }
 
-        protected bool Equals(
-            ECCurve other)
+        public override bool Equals(object obj) 
         {
-            return a.Equals(other.a) && b.Equals(other.b);
+            return Equals(obj as ECCurve);
         }
 
         public override int GetHashCode()
         {
-            return a.GetHashCode() ^ b.GetHashCode();
+            return Field.GetHashCode()
+                ^ Integers.RotateLeft(A.GetHashCode(), 8)
+                ^ Integers.RotateLeft(B.GetHashCode(), 16);
         }
 
         protected abstract ECPoint DecompressPoint(int yTilde, BigInteger X1);
@@ -112,17 +123,19 @@ namespace Org.BouncyCastle.Math.EC
     /**
      * Elliptic curve over Fp
      */
-    public class FpCurve : ECCurve
+    public class FpCurve
+        : ECCurve
     {
         private readonly BigInteger q, r;
         private readonly FpPoint infinity;
 
         public FpCurve(BigInteger q, BigInteger a, BigInteger b)
+            : base(FiniteFields.GetPrimeField(q))
         {
             this.q = q;
             this.r = FpFieldElement.CalculateResidue(q);
-            this.a = FromBigInteger(a);
-            this.b = FromBigInteger(b);
+            this.m_a = FromBigInteger(a);
+            this.m_b = FromBigInteger(b);
             this.infinity = new FpPoint(this, null, null);
         }
 
@@ -164,7 +177,7 @@ namespace Org.BouncyCastle.Math.EC
             BigInteger	X1)
         {
             ECFieldElement x = FromBigInteger(X1);
-            ECFieldElement alpha = x.Multiply(x.Square().Add(a)).Add(b);
+            ECFieldElement alpha = x.Multiply(x.Square().Add(m_a)).Add(m_b);
             ECFieldElement beta = alpha.Sqrt();
 
             //
@@ -185,39 +198,44 @@ namespace Org.BouncyCastle.Math.EC
 
             return new FpPoint(this, x, beta, true);
         }
+    }
 
-        public override bool Equals(
-            object obj)
+    /**
+     * 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 : ECCurve
+    {
+        private static IFiniteField BuildField(int m, int k1, int k2, int k3)
         {
-            if (obj == this)
-                return true;
+            if (k1 == 0)
+            {
+                throw new ArgumentException("k1 must be > 0");
+            }
 
-            FpCurve other = obj as FpCurve;
+            if (k2 == 0)
+            {
+                if (k3 != 0)
+                {
+                    throw new ArgumentException("k3 must be 0 if k2 == 0");
+                }
 
-            if (other == null)
-                return false;
+                return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, m });
+            }
 
-            return Equals(other);
-        }
+            if (k2 <= k1)
+            {
+                throw new ArgumentException("k2 must be > k1");
+            }
 
-        protected bool Equals(
-            FpCurve other)
-        {
-            return base.Equals(other) && q.Equals(other.q);
-        }
+            if (k3 <= k2)
+            {
+                throw new ArgumentException("k3 must be > k2");
+            }
 
-        public override int GetHashCode()
-        {
-            return base.GetHashCode() ^ q.GetHashCode();
+            return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, k2, k3, m });
         }
-    }
 
-    /**
-     * 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 : ECCurve
-    {
         /**
          * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
          */
@@ -391,6 +409,7 @@ namespace Org.BouncyCastle.Math.EC
             BigInteger	b,
             BigInteger	n,
             BigInteger	h)
+            : base(BuildField(m, k1, k2, k3))
         {
             this.m = m;
             this.k1 = k1;
@@ -417,8 +436,8 @@ namespace Org.BouncyCastle.Math.EC
                     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);
         }
 
         public override ECPoint Infinity
@@ -444,10 +463,7 @@ namespace Org.BouncyCastle.Math.EC
         {
             get
             {
-                return n != null && h != null
-                    && (a.ToBigInteger().Equals(BigInteger.Zero)
-                        || a.ToBigInteger().Equals(BigInteger.One))
-                    && b.ToBigInteger().Equals(BigInteger.One);
+                return n != null && h != null && m_a.BitLength <= 1 && m_b.IsOne;
             }
         }
 
@@ -514,7 +530,7 @@ namespace Org.BouncyCastle.Math.EC
             ECFieldElement yp = null;
             if (xp.ToBigInteger().SignValue == 0)
             {
-                yp = (F2mFieldElement)b;
+                yp = (F2mFieldElement)m_b;
                 for (int i = 0; i < m - 1; i++)
                 {
                     yp = yp.Square();
@@ -522,7 +538,7 @@ namespace Org.BouncyCastle.Math.EC
             }
             else
             {
-                ECFieldElement beta = xp.Add(a).Add(b.Multiply(xp.Square().Invert()));
+                ECFieldElement beta = xp.Add(m_a).Add(m_b.Multiply(xp.Square().Invert()));
                 ECFieldElement z = solveQuadradicEquation(beta);
 
                 if (z == null)
@@ -580,35 +596,6 @@ namespace Org.BouncyCastle.Math.EC
             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; }