using System; using System.Collections; using System.Diagnostics; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Math.EC.Multiplier; namespace Org.BouncyCastle.Math.EC { /** * base class for points on elliptic curves. */ public abstract class ECPoint { internal readonly ECCurve curve; internal readonly ECFieldElement x, y; internal readonly bool withCompression; internal ECMultiplier multiplier = null; internal PreCompInfo preCompInfo = null; protected internal ECPoint( ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) { if (curve == null) throw new ArgumentNullException("curve"); this.curve = curve; this.x = x; this.y = y; this.withCompression = withCompression; } public ECCurve Curve { get { return curve; } } public ECFieldElement X { get { return x; } } public ECFieldElement Y { get { return y; } } public bool IsInfinity { get { return x == null && y == null; } } public bool IsCompressed { get { return withCompression; } } public override bool Equals( object obj) { if (obj == this) return true; ECPoint o = obj as ECPoint; if (o == null) return false; if (this.IsInfinity) return o.IsInfinity; return x.Equals(o.x) && y.Equals(o.y); } public override int GetHashCode() { if (this.IsInfinity) return 0; return x.GetHashCode() ^ y.GetHashCode(); } // /** // * Mainly for testing. Explicitly set the ECMultiplier. // * @param multiplier The ECMultiplier to be used to multiply // * this ECPoint. // */ // internal void SetECMultiplier( // ECMultiplier multiplier) // { // this.multiplier = multiplier; // } /** * Sets the PreCompInfo. Used by ECMultipliers * to save the precomputation for this ECPoint to store the * precomputation result for use by subsequent multiplication. * @param preCompInfo The values precomputed by the * ECMultiplier. */ internal void SetPreCompInfo( PreCompInfo preCompInfo) { this.preCompInfo = preCompInfo; } public virtual byte[] GetEncoded() { return GetEncoded(withCompression); } public abstract byte[] GetEncoded(bool compressed); public abstract ECPoint Add(ECPoint b); public abstract ECPoint Subtract(ECPoint b); public abstract ECPoint Negate(); public abstract ECPoint Twice(); public abstract ECPoint Multiply(BigInteger b); /** * Sets the appropriate ECMultiplier, unless already set. */ internal virtual void AssertECMultiplier() { if (this.multiplier == null) { lock (this) { if (this.multiplier == null) { this.multiplier = new FpNafMultiplier(); } } } } } public abstract class ECPointBase : ECPoint { protected internal ECPointBase( ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) : base(curve, x, y, withCompression) { } protected internal abstract bool YTilde { get; } /** * return the field element encoded with point compression. (S 4.3.6) */ public override byte[] GetEncoded(bool compressed) { if (this.IsInfinity) return new byte[1]; // Note: some of the tests rely on calculating byte length from the field element // (since the test cases use mismatching fields for curve/elements) int byteLength = X9IntegerConverter.GetByteLength(x); byte[] X = X9IntegerConverter.IntegerToBytes(this.X.ToBigInteger(), byteLength); byte[] PO; if (compressed) { PO = new byte[1 + X.Length]; PO[0] = (byte)(YTilde ? 0x03 : 0x02); } else { byte[] Y = X9IntegerConverter.IntegerToBytes(this.Y.ToBigInteger(), byteLength); PO = new byte[1 + X.Length + Y.Length]; PO[0] = 0x04; Y.CopyTo(PO, 1 + X.Length); } X.CopyTo(PO, 1); return PO; } /** * Multiplies this ECPoint by the given number. * @param k The multiplicator. * @return k * this. */ public override ECPoint Multiply( BigInteger k) { if (k.SignValue < 0) throw new ArgumentException("The multiplicator cannot be negative", "k"); if (this.IsInfinity) return this; if (k.SignValue == 0) return this.curve.Infinity; AssertECMultiplier(); return this.multiplier.Multiply(this, k, preCompInfo); } } /** * Elliptic curve points over Fp */ public class FpPoint : ECPointBase { /** * Create a point which encodes with point compression. * * @param curve the curve to use * @param x affine x co-ordinate * @param y affine y co-ordinate */ public FpPoint( ECCurve curve, ECFieldElement x, ECFieldElement y) : this(curve, x, y, false) { } /** * Create a point that encodes with or without point compresion. * * @param curve the curve to use * @param x affine x co-ordinate * @param y affine y co-ordinate * @param withCompression if true encode with point compression */ public FpPoint( ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) : base(curve, x, y, withCompression) { if ((x == null) != (y == null)) throw new ArgumentException("Exactly one of the field elements is null"); } protected internal override bool YTilde { get { return this.Y.ToBigInteger().TestBit(0); } } // B.3 pg 62 public override ECPoint Add( ECPoint b) { if (this.IsInfinity) return b; if (b.IsInfinity) return this; // Check if b = this or b = -this if (this.x.Equals(b.x)) { if (this.y.Equals(b.y)) { // this = b, i.e. this must be doubled return this.Twice(); } Debug.Assert(this.y.Equals(b.y.Negate())); // this = -b, i.e. the result is the point at infinity return this.curve.Infinity; } ECFieldElement gamma = b.y.Subtract(this.y).Divide(b.x.Subtract(this.x)); ECFieldElement x3 = gamma.Square().Subtract(this.x).Subtract(b.x); ECFieldElement y3 = gamma.Multiply(this.x.Subtract(x3)).Subtract(this.y); return new FpPoint(curve, x3, y3, withCompression); } // B.3 pg 62 public override ECPoint Twice() { // Twice identity element (point at infinity) is identity if (this.IsInfinity) return this; // if y1 == 0, then (x1, y1) == (x1, -y1) // and hence this = -this and thus 2(x1, y1) == infinity if (this.y.ToBigInteger().SignValue == 0) return this.curve.Infinity; ECFieldElement TWO = this.curve.FromBigInteger(BigInteger.Two); ECFieldElement THREE = this.curve.FromBigInteger(BigInteger.Three); ECFieldElement gamma = this.x.Square().Multiply(THREE).Add(curve.a).Divide(y.Multiply(TWO)); ECFieldElement x3 = gamma.Square().Subtract(this.x.Multiply(TWO)); ECFieldElement y3 = gamma.Multiply(this.x.Subtract(x3)).Subtract(this.y); return new FpPoint(curve, x3, y3, this.withCompression); } // D.3.2 pg 102 (see Note:) public override ECPoint Subtract( ECPoint b) { if (b.IsInfinity) return this; // Add -b return Add(b.Negate()); } public override ECPoint Negate() { return new FpPoint(this.curve, this.x, this.y.Negate(), this.withCompression); } /** * Sets the default ECMultiplier, unless already set. */ internal override void AssertECMultiplier() { if (this.multiplier == null) { lock (this) { if (this.multiplier == null) { this.multiplier = new WNafMultiplier(); } } } } } /** * Elliptic curve points over F2m */ public class F2mPoint : ECPointBase { /** * @param curve base curve * @param x x point * @param y y point */ public F2mPoint( ECCurve curve, ECFieldElement x, ECFieldElement y) : this(curve, x, y, false) { } /** * @param curve base curve * @param x x point * @param y y point * @param withCompression true if encode with point compression. */ public F2mPoint( ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) : base(curve, x, y, withCompression) { if ((x != null && y == null) || (x == null && y != null)) { throw new ArgumentException("Exactly one of the field elements is null"); } if (x != null) { // Check if x and y are elements of the same field F2mFieldElement.CheckFieldElements(this.x, this.y); // Check if x and a are elements of the same field F2mFieldElement.CheckFieldElements(this.x, this.curve.A); } } /** * Constructor for point at infinity */ [Obsolete("Use ECCurve.Infinity property")] public F2mPoint( ECCurve curve) : this(curve, null, null) { } protected internal override bool YTilde { get { // X9.62 4.2.2 and 4.3.6: // if x = 0 then ypTilde := 0, else ypTilde is the rightmost // bit of y * x^(-1) return this.X.ToBigInteger().SignValue != 0 && this.Y.Multiply(this.X.Invert()).ToBigInteger().TestBit(0); } } /** * Check, if two ECPoints can be added or subtracted. * @param a The first ECPoint to check. * @param b The second ECPoint to check. * @throws IllegalArgumentException if a and b * cannot be added. */ private static void CheckPoints( ECPoint a, ECPoint b) { // Check, if points are on the same curve if (!a.curve.Equals(b.curve)) throw new ArgumentException("Only points on the same curve can be added or subtracted"); // F2mFieldElement.CheckFieldElements(a.x, b.x); } /* (non-Javadoc) * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint) */ public override ECPoint Add(ECPoint b) { CheckPoints(this, b); return AddSimple((F2mPoint) b); } /** * Adds another ECPoints.F2m to this without * checking if both points are on the same curve. Used by multiplication * algorithms, because there all points are a multiple of the same point * and hence the checks can be omitted. * @param b The other ECPoints.F2m to add to * this. * @return this + b */ internal F2mPoint AddSimple(F2mPoint b) { if (this.IsInfinity) return b; if (b.IsInfinity) return this; F2mFieldElement x2 = (F2mFieldElement) b.X; F2mFieldElement y2 = (F2mFieldElement) b.Y; // Check if b == this or b == -this if (this.x.Equals(x2)) { // this == b, i.e. this must be doubled if (this.y.Equals(y2)) return (F2mPoint) this.Twice(); // this = -other, i.e. the result is the point at infinity return (F2mPoint) this.curve.Infinity; } ECFieldElement xSum = this.x.Add(x2); F2mFieldElement lambda = (F2mFieldElement)(this.y.Add(y2)).Divide(xSum); F2mFieldElement x3 = (F2mFieldElement)lambda.Square().Add(lambda).Add(xSum).Add(this.curve.A); F2mFieldElement y3 = (F2mFieldElement)lambda.Multiply(this.x.Add(x3)).Add(x3).Add(this.y); return new F2mPoint(curve, x3, y3, withCompression); } /* (non-Javadoc) * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint) */ public override ECPoint Subtract( ECPoint b) { CheckPoints(this, b); return SubtractSimple((F2mPoint) b); } /** * Subtracts another ECPoints.F2m from this * without checking if both points are on the same curve. Used by * multiplication algorithms, because there all points are a multiple * of the same point and hence the checks can be omitted. * @param b The other ECPoints.F2m to subtract from * this. * @return this - b */ internal F2mPoint SubtractSimple( F2mPoint b) { if (b.IsInfinity) return this; // Add -b return AddSimple((F2mPoint) b.Negate()); } /* (non-Javadoc) * @see Org.BouncyCastle.Math.EC.ECPoint#twice() */ public override ECPoint Twice() { // Twice identity element (point at infinity) is identity if (this.IsInfinity) return this; // if x1 == 0, then (x1, y1) == (x1, x1 + y1) // and hence this = -this and thus 2(x1, y1) == infinity if (this.x.ToBigInteger().SignValue == 0) return this.curve.Infinity; F2mFieldElement lambda = (F2mFieldElement) this.x.Add(this.y.Divide(this.x)); F2mFieldElement x2 = (F2mFieldElement)lambda.Square().Add(lambda).Add(this.curve.A); ECFieldElement ONE = this.curve.FromBigInteger(BigInteger.One); F2mFieldElement y2 = (F2mFieldElement)this.x.Square().Add( x2.Multiply(lambda.Add(ONE))); return new F2mPoint(this.curve, x2, y2, withCompression); } public override ECPoint Negate() { return new F2mPoint(curve, this.x, this.x.Add(this.y), withCompression); } /** * Sets the appropriate ECMultiplier, unless already set. */ internal override void AssertECMultiplier() { if (this.multiplier == null) { lock (this) { if (this.multiplier == null) { if (((F2mCurve) this.curve).IsKoblitz) { this.multiplier = new WTauNafMultiplier(); } else { this.multiplier = new WNafMultiplier(); } } } } } } }