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 ECMultiplier
s
* 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 ECPoint
s 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();
}
}
}
}
}
}
}