diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-01-22 11:40:05 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-01-22 11:40:05 +0700 |
commit | 73cb18129e632b44ddae7f9c589fd9c17c77d3ca (patch) | |
tree | cbe867e5538f2a9d37f3eadb49a4104a64261971 /crypto/src | |
parent | Implement TwicePlus optimization in Fp curves (diff) | |
download | BouncyCastle.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.cs | 161 | ||||
-rw-r--r-- | crypto/src/asn1/x9/X9ECParameters.cs | 106 | ||||
-rw-r--r-- | crypto/src/asn1/x9/X9FieldID.cs | 144 | ||||
-rw-r--r-- | crypto/src/math/ec/ECAlgorithms.cs | 170 | ||||
-rw-r--r-- | crypto/src/math/ec/ECCurve.cs | 153 |
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; } |