blob: b14e4c1545c9951a5db774324aa3934be76537f3 [file] [log] [blame]
package org.bouncycastle.math.ec;
import java.math.BigInteger;
import org.bouncycastle.asn1.x9.X9IntegerConverter;
/**
* base class for points on elliptic curves.
*/
public abstract class ECPoint
{
ECCurve curve;
ECFieldElement x;
ECFieldElement y;
protected boolean withCompression;
protected ECMultiplier multiplier = null;
protected PreCompInfo preCompInfo = null;
private static X9IntegerConverter converter = new X9IntegerConverter();
protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
{
this.curve = curve;
this.x = x;
this.y = y;
}
public ECCurve getCurve()
{
return curve;
}
public ECFieldElement getX()
{
return x;
}
public ECFieldElement getY()
{
return y;
}
public boolean isInfinity()
{
return x == null && y == null;
}
public boolean isCompressed()
{
return withCompression;
}
public boolean equals(
Object other)
{
if (other == this)
{
return true;
}
if (!(other instanceof ECPoint))
{
return false;
}
ECPoint o = (ECPoint)other;
if (this.isInfinity())
{
return o.isInfinity();
}
return x.equals(o.x) && y.equals(o.y);
}
public int hashCode()
{
if (this.isInfinity())
{
return 0;
}
return x.hashCode() ^ y.hashCode();
}
// /**
// * Mainly for testing. Explicitly set the <code>ECMultiplier</code>.
// * @param multiplier The <code>ECMultiplier</code> to be used to multiply
// * this <code>ECPoint</code>.
// */
// public void setECMultiplier(ECMultiplier multiplier)
// {
// this.multiplier = multiplier;
// }
/**
* Sets the <code>PreCompInfo</code>. Used by <code>ECMultiplier</code>s
* to save the precomputation for this <code>ECPoint</code> to store the
* precomputation result for use by subsequent multiplication.
* @param preCompInfo The values precomputed by the
* <code>ECMultiplier</code>.
*/
void setPreCompInfo(PreCompInfo preCompInfo)
{
this.preCompInfo = preCompInfo;
}
public abstract byte[] getEncoded();
public abstract ECPoint add(ECPoint b);
public abstract ECPoint subtract(ECPoint b);
public abstract ECPoint negate();
public abstract ECPoint twice();
/**
* Sets the default <code>ECMultiplier</code>, unless already set.
*/
synchronized void assertECMultiplier()
{
if (this.multiplier == null)
{
this.multiplier = new FpNafMultiplier();
}
}
/**
* Multiplies this <code>ECPoint</code> by the given number.
* @param k The multiplicator.
* @return <code>k * this</code>.
*/
public ECPoint multiply(BigInteger k)
{
if (k.signum() < 0)
{
throw new IllegalArgumentException("The multiplicator cannot be negative");
}
if (this.isInfinity())
{
return this;
}
if (k.signum() == 0)
{
return this.curve.getInfinity();
}
assertECMultiplier();
return this.multiplier.multiply(this, k, preCompInfo);
}
/**
* Elliptic curve points over Fp
*/
public static class Fp extends ECPoint
{
/**
* 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 Fp(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 Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
{
super(curve, x, y);
if ((x != null && y == null) || (x == null && y != null))
{
throw new IllegalArgumentException("Exactly one of the field elements is null");
}
this.withCompression = withCompression;
}
/**
* return the field element encoded with point compression. (S 4.3.6)
*/
public byte[] getEncoded()
{
if (this.isInfinity())
{
return new byte[1];
}
int qLength = converter.getByteLength(x);
if (withCompression)
{
byte PC;
if (this.getY().toBigInteger().testBit(0))
{
PC = 0x03;
}
else
{
PC = 0x02;
}
byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
byte[] PO = new byte[X.length + 1];
PO[0] = PC;
System.arraycopy(X, 0, PO, 1, X.length);
return PO;
}
else
{
byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), qLength);
byte[] PO = new byte[X.length + Y.length + 1];
PO[0] = 0x04;
System.arraycopy(X, 0, PO, 1, X.length);
System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
return PO;
}
}
// B.3 pg 62
public 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();
}
// this = -b, i.e. the result is the point at infinity
return this.curve.getInfinity();
}
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 ECPoint.Fp(curve, x3, y3);
}
// B.3 pg 62
public ECPoint twice()
{
if (this.isInfinity())
{
// Twice identity element (point at infinity) is identity
return this;
}
if (this.y.toBigInteger().signum() == 0)
{
// if y1 == 0, then (x1, y1) == (x1, -y1)
// and hence this = -this and thus 2(x1, y1) == infinity
return this.curve.getInfinity();
}
ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
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 ECPoint.Fp(curve, x3, y3, this.withCompression);
}
// D.3.2 pg 102 (see Note:)
public ECPoint subtract(ECPoint b)
{
if (b.isInfinity())
{
return this;
}
// Add -b
return add(b.negate());
}
public ECPoint negate()
{
return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);
}
/**
* Sets the default <code>ECMultiplier</code>, unless already set.
*/
synchronized void assertECMultiplier()
{
if (this.multiplier == null)
{
this.multiplier = new WNafMultiplier();
}
}
}
/**
* Elliptic curve points over F2m
*/
public static class F2m extends ECPoint
{
/**
* @param curve base curve
* @param x x point
* @param y y point
*/
public F2m(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 F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
{
super(curve, x, y);
if ((x != null && y == null) || (x == null && y != null))
{
throw new IllegalArgumentException("Exactly one of the field elements is null");
}
if (x != null)
{
// Check if x and y are elements of the same field
ECFieldElement.F2m.checkFieldElements(this.x, this.y);
// Check if x and a are elements of the same field
if (curve != null)
{
ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA());
}
}
this.withCompression = withCompression;
}
/* (non-Javadoc)
* @see org.bouncycastle.math.ec.ECPoint#getEncoded()
*/
public byte[] getEncoded()
{
if (this.isInfinity())
{
return new byte[1];
}
int byteCount = converter.getByteLength(this.x);
byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount);
byte[] PO;
if (withCompression)
{
// See X9.62 4.3.6 and 4.2.2
PO = new byte[byteCount + 1];
PO[0] = 0x02;
// 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)
// if ypTilde = 0, then PC := 02, else PC := 03
// Note: PC === PO[0]
if (!(this.getX().toBigInteger().equals(ECConstants.ZERO)))
{
if (this.getY().multiply(this.getX().invert())
.toBigInteger().testBit(0))
{
// ypTilde = 1, hence PC = 03
PO[0] = 0x03;
}
}
System.arraycopy(X, 0, PO, 1, byteCount);
}
else
{
byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount);
PO = new byte[byteCount + byteCount + 1];
PO[0] = 0x04;
System.arraycopy(X, 0, PO, 1, byteCount);
System.arraycopy(Y, 0, PO, byteCount + 1, byteCount);
}
return PO;
}
/**
* Check, if two <code>ECPoint</code>s can be added or subtracted.
* @param a The first <code>ECPoint</code> to check.
* @param b The second <code>ECPoint</code> to check.
* @throws IllegalArgumentException if <code>a</code> and <code>b</code>
* 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 IllegalArgumentException("Only points on the same "
+ "curve can be added or subtracted");
}
// ECFieldElement.F2m.checkFieldElements(a.x, b.x);
}
/* (non-Javadoc)
* @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
*/
public ECPoint add(ECPoint b)
{
checkPoints(this, b);
return addSimple((ECPoint.F2m)b);
}
/**
* Adds another <code>ECPoints.F2m</code> to <code>this</code> 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 <code>ECPoints.F2m</code> to add to
* <code>this</code>.
* @return <code>this + b</code>
*/
public ECPoint.F2m addSimple(ECPoint.F2m b)
{
ECPoint.F2m other = b;
if (this.isInfinity())
{
return other;
}
if (other.isInfinity())
{
return this;
}
ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX();
ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY();
// Check if other = this or other = -this
if (this.x.equals(x2))
{
if (this.y.equals(y2))
{
// this = other, i.e. this must be doubled
return (ECPoint.F2m)this.twice();
}
// this = -other, i.e. the result is the point at infinity
return (ECPoint.F2m)this.curve.getInfinity();
}
ECFieldElement.F2m lambda
= (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2));
ECFieldElement.F2m x3
= (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA());
ECFieldElement.F2m y3
= (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y);
return new ECPoint.F2m(curve, x3, y3, withCompression);
}
/* (non-Javadoc)
* @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
*/
public ECPoint subtract(ECPoint b)
{
checkPoints(this, b);
return subtractSimple((ECPoint.F2m)b);
}
/**
* Subtracts another <code>ECPoints.F2m</code> from <code>this</code>
* 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 <code>ECPoints.F2m</code> to subtract from
* <code>this</code>.
* @return <code>this - b</code>
*/
public ECPoint.F2m subtractSimple(ECPoint.F2m b)
{
if (b.isInfinity())
{
return this;
}
// Add -b
return addSimple((ECPoint.F2m)b.negate());
}
/* (non-Javadoc)
* @see org.bouncycastle.math.ec.ECPoint#twice()
*/
public ECPoint twice()
{
if (this.isInfinity())
{
// Twice identity element (point at infinity) is identity
return this;
}
if (this.x.toBigInteger().signum() == 0)
{
// if x1 == 0, then (x1, y1) == (x1, x1 + y1)
// and hence this = -this and thus 2(x1, y1) == infinity
return this.curve.getInfinity();
}
ECFieldElement.F2m lambda
= (ECFieldElement.F2m)this.x.add(this.y.divide(this.x));
ECFieldElement.F2m x3
= (ECFieldElement.F2m)lambda.square().add(lambda).
add(this.curve.getA());
ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE);
ECFieldElement.F2m y3
= (ECFieldElement.F2m)this.x.square().add(
x3.multiply(lambda.add(ONE)));
return new ECPoint.F2m(this.curve, x3, y3, withCompression);
}
public ECPoint negate()
{
return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression);
}
/**
* Sets the appropriate <code>ECMultiplier</code>, unless already set.
*/
synchronized void assertECMultiplier()
{
if (this.multiplier == null)
{
if (((ECCurve.F2m)this.curve).isKoblitz())
{
this.multiplier = new WTauNafMultiplier();
}
else
{
this.multiplier = new WNafMultiplier();
}
}
}
}
}