You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1423 lines
47 KiB
1423 lines
47 KiB
1 year ago
|
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||
|
#pragma warning disable
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Abc;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Endo;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Multiplier;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.Field;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||
|
|
||
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC
|
||
|
{
|
||
|
/// <remarks>Base class for an elliptic curve.</remarks>
|
||
|
public abstract class ECCurve
|
||
|
{
|
||
|
public const int COORD_AFFINE = 0;
|
||
|
public const int COORD_HOMOGENEOUS = 1;
|
||
|
public const int COORD_JACOBIAN = 2;
|
||
|
public const int COORD_JACOBIAN_CHUDNOVSKY = 3;
|
||
|
public const int COORD_JACOBIAN_MODIFIED = 4;
|
||
|
public const int COORD_LAMBDA_AFFINE = 5;
|
||
|
public const int COORD_LAMBDA_PROJECTIVE = 6;
|
||
|
public const int COORD_SKEWED = 7;
|
||
|
|
||
|
public static int[] GetAllCoordinateSystems()
|
||
|
{
|
||
|
return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY,
|
||
|
COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED };
|
||
|
}
|
||
|
|
||
|
public class Config
|
||
|
{
|
||
|
protected ECCurve outer;
|
||
|
protected int coord;
|
||
|
protected ECEndomorphism endomorphism;
|
||
|
protected ECMultiplier multiplier;
|
||
|
|
||
|
internal Config(ECCurve outer, int coord, ECEndomorphism endomorphism, ECMultiplier multiplier)
|
||
|
{
|
||
|
this.outer = outer;
|
||
|
this.coord = coord;
|
||
|
this.endomorphism = endomorphism;
|
||
|
this.multiplier = multiplier;
|
||
|
}
|
||
|
|
||
|
public Config SetCoordinateSystem(int coord)
|
||
|
{
|
||
|
this.coord = coord;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
public Config SetEndomorphism(ECEndomorphism endomorphism)
|
||
|
{
|
||
|
this.endomorphism = endomorphism;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
public Config SetMultiplier(ECMultiplier multiplier)
|
||
|
{
|
||
|
this.multiplier = multiplier;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
public ECCurve Create()
|
||
|
{
|
||
|
if (!outer.SupportsCoordinateSystem(coord))
|
||
|
{
|
||
|
throw new InvalidOperationException("unsupported coordinate system");
|
||
|
}
|
||
|
|
||
|
ECCurve c = outer.CloneCurve();
|
||
|
if (c == outer)
|
||
|
{
|
||
|
throw new InvalidOperationException("implementation returned current curve");
|
||
|
}
|
||
|
|
||
|
c.m_coord = coord;
|
||
|
c.m_endomorphism = endomorphism;
|
||
|
c.m_multiplier = multiplier;
|
||
|
|
||
|
return c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected readonly IFiniteField m_field;
|
||
|
protected ECFieldElement m_a, m_b;
|
||
|
protected BigInteger m_order, m_cofactor;
|
||
|
|
||
|
protected int m_coord = COORD_AFFINE;
|
||
|
protected ECEndomorphism m_endomorphism = null;
|
||
|
protected ECMultiplier m_multiplier = null;
|
||
|
|
||
|
protected ECCurve(IFiniteField field)
|
||
|
{
|
||
|
this.m_field = field;
|
||
|
}
|
||
|
|
||
|
public abstract int FieldSize { get; }
|
||
|
public abstract ECFieldElement FromBigInteger(BigInteger x);
|
||
|
public abstract bool IsValidFieldElement(BigInteger x);
|
||
|
|
||
|
public abstract ECFieldElement RandomFieldElement(SecureRandom r);
|
||
|
|
||
|
public abstract ECFieldElement RandomFieldElementMult(SecureRandom r);
|
||
|
|
||
|
public virtual Config Configure()
|
||
|
{
|
||
|
return new Config(this, this.m_coord, this.m_endomorphism, this.m_multiplier);
|
||
|
}
|
||
|
|
||
|
public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y)
|
||
|
{
|
||
|
ECPoint p = CreatePoint(x, y);
|
||
|
if (!p.IsValid())
|
||
|
{
|
||
|
throw new ArgumentException("Invalid point coordinates");
|
||
|
}
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
|
||
|
public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y, bool withCompression)
|
||
|
{
|
||
|
ECPoint p = CreatePoint(x, y, withCompression);
|
||
|
if (!p.IsValid())
|
||
|
{
|
||
|
throw new ArgumentException("Invalid point coordinates");
|
||
|
}
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
public virtual ECPoint CreatePoint(BigInteger x, BigInteger y)
|
||
|
{
|
||
|
return CreatePoint(x, y, false);
|
||
|
}
|
||
|
|
||
|
|
||
|
public virtual ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
|
||
|
{
|
||
|
return CreateRawPoint(FromBigInteger(x), FromBigInteger(y), withCompression);
|
||
|
}
|
||
|
|
||
|
protected abstract ECCurve CloneCurve();
|
||
|
|
||
|
protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression);
|
||
|
|
||
|
protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression);
|
||
|
|
||
|
protected virtual ECMultiplier CreateDefaultMultiplier()
|
||
|
{
|
||
|
GlvEndomorphism glvEndomorphism = m_endomorphism as GlvEndomorphism;
|
||
|
if (glvEndomorphism != null)
|
||
|
{
|
||
|
return new GlvMultiplier(this, glvEndomorphism);
|
||
|
}
|
||
|
|
||
|
return new WNafL2RMultiplier();
|
||
|
}
|
||
|
|
||
|
public virtual bool SupportsCoordinateSystem(int coord)
|
||
|
{
|
||
|
return coord == COORD_AFFINE;
|
||
|
}
|
||
|
|
||
|
public virtual PreCompInfo GetPreCompInfo(ECPoint point, string name)
|
||
|
{
|
||
|
CheckPoint(point);
|
||
|
|
||
|
IDictionary table;
|
||
|
lock (point)
|
||
|
{
|
||
|
table = point.m_preCompTable;
|
||
|
}
|
||
|
|
||
|
if (null == table)
|
||
|
return null;
|
||
|
|
||
|
lock (table)
|
||
|
{
|
||
|
return (PreCompInfo)table[name];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Compute a <code>PreCompInfo</code> for a point on this curve, under a given name. Used by
|
||
|
* <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use
|
||
|
* by subsequent multiplication.
|
||
|
*
|
||
|
* @param point
|
||
|
* The <code>ECPoint</code> to store precomputations for.
|
||
|
* @param name
|
||
|
* A <code>String</code> used to index precomputations of different types.
|
||
|
* @param callback
|
||
|
* Called to calculate the <code>PreCompInfo</code>.
|
||
|
*/
|
||
|
public virtual PreCompInfo Precompute(ECPoint point, string name, IPreCompCallback callback)
|
||
|
{
|
||
|
CheckPoint(point);
|
||
|
|
||
|
IDictionary table;
|
||
|
lock (point)
|
||
|
{
|
||
|
table = point.m_preCompTable;
|
||
|
if (null == table)
|
||
|
{
|
||
|
point.m_preCompTable = table = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateHashtable(4);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lock (table)
|
||
|
{
|
||
|
PreCompInfo existing = (PreCompInfo)table[name];
|
||
|
PreCompInfo result = callback.Precompute(existing);
|
||
|
|
||
|
if (result != existing)
|
||
|
{
|
||
|
table[name] = result;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public virtual ECPoint ImportPoint(ECPoint p)
|
||
|
{
|
||
|
if (this == p.Curve)
|
||
|
{
|
||
|
return p;
|
||
|
}
|
||
|
if (p.IsInfinity)
|
||
|
{
|
||
|
return Infinity;
|
||
|
}
|
||
|
|
||
|
// TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
|
||
|
p = p.Normalize();
|
||
|
|
||
|
return CreatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Normalization ensures that any projective coordinate is 1, and therefore that the x, y
|
||
|
* coordinates reflect those of the equivalent point in an affine coordinate system. Where more
|
||
|
* than one point is to be normalized, this method will generally be more efficient than
|
||
|
* normalizing each point separately.
|
||
|
*
|
||
|
* @param points
|
||
|
* An array of points that will be updated in place with their normalized versions,
|
||
|
* where necessary
|
||
|
*/
|
||
|
public virtual void NormalizeAll(ECPoint[] points)
|
||
|
{
|
||
|
NormalizeAll(points, 0, points.Length, null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Normalization ensures that any projective coordinate is 1, and therefore that the x, y
|
||
|
* coordinates reflect those of the equivalent point in an affine coordinate system. Where more
|
||
|
* than one point is to be normalized, this method will generally be more efficient than
|
||
|
* normalizing each point separately. An (optional) z-scaling factor can be applied; effectively
|
||
|
* each z coordinate is scaled by this value prior to normalization (but only one
|
||
|
* actual multiplication is needed).
|
||
|
*
|
||
|
* @param points
|
||
|
* An array of points that will be updated in place with their normalized versions,
|
||
|
* where necessary
|
||
|
* @param off
|
||
|
* The start of the range of points to normalize
|
||
|
* @param len
|
||
|
* The length of the range of points to normalize
|
||
|
* @param iso
|
||
|
* The (optional) z-scaling factor - can be null
|
||
|
*/
|
||
|
public virtual void NormalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso)
|
||
|
{
|
||
|
CheckPoints(points, off, len);
|
||
|
|
||
|
switch (this.CoordinateSystem)
|
||
|
{
|
||
|
case ECCurve.COORD_AFFINE:
|
||
|
case ECCurve.COORD_LAMBDA_AFFINE:
|
||
|
{
|
||
|
if (iso != null)
|
||
|
throw new ArgumentException("not valid for affine coordinates", "iso");
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Figure out which of the points actually need to be normalized
|
||
|
*/
|
||
|
ECFieldElement[] zs = new ECFieldElement[len];
|
||
|
int[] indices = new int[len];
|
||
|
int count = 0;
|
||
|
for (int i = 0; i < len; ++i)
|
||
|
{
|
||
|
ECPoint p = points[off + i];
|
||
|
if (null != p && (iso != null || !p.IsNormalized()))
|
||
|
{
|
||
|
zs[count] = p.GetZCoord(0);
|
||
|
indices[count++] = off + i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (count == 0)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ECAlgorithms.MontgomeryTrick(zs, 0, count, iso);
|
||
|
|
||
|
for (int j = 0; j < count; ++j)
|
||
|
{
|
||
|
int index = indices[j];
|
||
|
points[index] = points[index].Normalize(zs[j]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public abstract ECPoint Infinity { get; }
|
||
|
|
||
|
public virtual IFiniteField Field
|
||
|
{
|
||
|
get { return m_field; }
|
||
|
}
|
||
|
|
||
|
public virtual ECFieldElement A
|
||
|
{
|
||
|
get { return m_a; }
|
||
|
}
|
||
|
|
||
|
public virtual ECFieldElement B
|
||
|
{
|
||
|
get { return m_b; }
|
||
|
}
|
||
|
|
||
|
public virtual BigInteger Order
|
||
|
{
|
||
|
get { return m_order; }
|
||
|
}
|
||
|
|
||
|
public virtual BigInteger Cofactor
|
||
|
{
|
||
|
get { return m_cofactor; }
|
||
|
}
|
||
|
|
||
|
public virtual int CoordinateSystem
|
||
|
{
|
||
|
get { return m_coord; }
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a cache-safe lookup table for the specified sequence of points. All the points MUST
|
||
|
* belong to this <code>ECCurve</code> instance, and MUST already be normalized.
|
||
|
*/
|
||
|
public virtual ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len)
|
||
|
{
|
||
|
int FE_BYTES = (FieldSize + 7) / 8;
|
||
|
byte[] table = new byte[len * FE_BYTES * 2];
|
||
|
{
|
||
|
int pos = 0;
|
||
|
for (int i = 0; i < len; ++i)
|
||
|
{
|
||
|
ECPoint p = points[off + i];
|
||
|
byte[] px = p.RawXCoord.ToBigInteger().ToByteArray();
|
||
|
byte[] py = p.RawYCoord.ToBigInteger().ToByteArray();
|
||
|
|
||
|
int pxStart = px.Length > FE_BYTES ? 1 : 0, pxLen = px.Length - pxStart;
|
||
|
int pyStart = py.Length > FE_BYTES ? 1 : 0, pyLen = py.Length - pyStart;
|
||
|
|
||
|
Array.Copy(px, pxStart, table, pos + FE_BYTES - pxLen, pxLen); pos += FE_BYTES;
|
||
|
Array.Copy(py, pyStart, table, pos + FE_BYTES - pyLen, pyLen); pos += FE_BYTES;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return new DefaultLookupTable(this, table, len);
|
||
|
}
|
||
|
|
||
|
protected virtual void CheckPoint(ECPoint point)
|
||
|
{
|
||
|
if (null == point || (this != point.Curve))
|
||
|
throw new ArgumentException("must be non-null and on this curve", "point");
|
||
|
}
|
||
|
|
||
|
protected virtual void CheckPoints(ECPoint[] points)
|
||
|
{
|
||
|
CheckPoints(points, 0, points.Length);
|
||
|
}
|
||
|
|
||
|
protected virtual void CheckPoints(ECPoint[] points, int off, int len)
|
||
|
{
|
||
|
if (points == null)
|
||
|
throw new ArgumentNullException("points");
|
||
|
if (off < 0 || len < 0 || (off > (points.Length - len)))
|
||
|
throw new ArgumentException("invalid range specified", "points");
|
||
|
|
||
|
for (int i = 0; i < len; ++i)
|
||
|
{
|
||
|
ECPoint point = points[off + i];
|
||
|
if (null != point && this != point.Curve)
|
||
|
throw new ArgumentException("entries must be null or on this curve", "points");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public virtual bool Equals(ECCurve other)
|
||
|
{
|
||
|
if (this == other)
|
||
|
return true;
|
||
|
if (null == other)
|
||
|
return false;
|
||
|
return Field.Equals(other.Field)
|
||
|
&& A.ToBigInteger().Equals(other.A.ToBigInteger())
|
||
|
&& B.ToBigInteger().Equals(other.B.ToBigInteger());
|
||
|
}
|
||
|
|
||
|
public override bool Equals(object obj)
|
||
|
{
|
||
|
return Equals(obj as ECCurve);
|
||
|
}
|
||
|
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
return Field.GetHashCode()
|
||
|
^ Integers.RotateLeft(A.ToBigInteger().GetHashCode(), 8)
|
||
|
^ Integers.RotateLeft(B.ToBigInteger().GetHashCode(), 16);
|
||
|
}
|
||
|
|
||
|
protected abstract ECPoint DecompressPoint(int yTilde, BigInteger X1);
|
||
|
|
||
|
public virtual ECEndomorphism GetEndomorphism()
|
||
|
{
|
||
|
return m_endomorphism;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the default <code>ECMultiplier</code>, unless already set.
|
||
|
*
|
||
|
* We avoid locking for performance reasons, so there is no uniqueness guarantee.
|
||
|
*/
|
||
|
public virtual ECMultiplier GetMultiplier()
|
||
|
{
|
||
|
if (this.m_multiplier == null)
|
||
|
{
|
||
|
this.m_multiplier = CreateDefaultMultiplier();
|
||
|
}
|
||
|
return this.m_multiplier;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Decode a point on this curve from its ASN.1 encoding. The different
|
||
|
* encodings are taken account of, including point compression for
|
||
|
* <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
|
||
|
* @return The decoded point.
|
||
|
*/
|
||
|
public virtual ECPoint DecodePoint(byte[] encoded)
|
||
|
{
|
||
|
ECPoint p = null;
|
||
|
int expectedLength = (FieldSize + 7) / 8;
|
||
|
|
||
|
byte type = encoded[0];
|
||
|
switch (type)
|
||
|
{
|
||
|
case 0x00: // infinity
|
||
|
{
|
||
|
if (encoded.Length != 1)
|
||
|
throw new ArgumentException("Incorrect length for infinity encoding", "encoded");
|
||
|
|
||
|
p = Infinity;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 0x02: // compressed
|
||
|
case 0x03: // compressed
|
||
|
{
|
||
|
if (encoded.Length != (expectedLength + 1))
|
||
|
throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
|
||
|
|
||
|
int yTilde = type & 1;
|
||
|
BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
|
||
|
|
||
|
p = DecompressPoint(yTilde, X);
|
||
|
if (!p.ImplIsValid(true, true))
|
||
|
throw new ArgumentException("Invalid point");
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 0x04: // uncompressed
|
||
|
{
|
||
|
if (encoded.Length != (2 * expectedLength + 1))
|
||
|
throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded");
|
||
|
|
||
|
BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
|
||
|
BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
|
||
|
|
||
|
p = ValidatePoint(X, Y);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 0x06: // hybrid
|
||
|
case 0x07: // hybrid
|
||
|
{
|
||
|
if (encoded.Length != (2 * expectedLength + 1))
|
||
|
throw new ArgumentException("Incorrect length for hybrid encoding", "encoded");
|
||
|
|
||
|
BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
|
||
|
BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
|
||
|
|
||
|
if (Y.TestBit(0) != (type == 0x07))
|
||
|
throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded");
|
||
|
|
||
|
p = ValidatePoint(X, Y);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
throw new FormatException("Invalid point encoding " + type);
|
||
|
}
|
||
|
|
||
|
if (type != 0x00 && p.IsInfinity)
|
||
|
throw new ArgumentException("Invalid infinity encoding", "encoded");
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
private class DefaultLookupTable
|
||
|
: AbstractECLookupTable
|
||
|
{
|
||
|
private readonly ECCurve m_outer;
|
||
|
private readonly byte[] m_table;
|
||
|
private readonly int m_size;
|
||
|
|
||
|
internal DefaultLookupTable(ECCurve outer, byte[] table, int size)
|
||
|
{
|
||
|
this.m_outer = outer;
|
||
|
this.m_table = table;
|
||
|
this.m_size = size;
|
||
|
}
|
||
|
|
||
|
public override int Size
|
||
|
{
|
||
|
get { return m_size; }
|
||
|
}
|
||
|
|
||
|
public override ECPoint Lookup(int index)
|
||
|
{
|
||
|
int FE_BYTES = (m_outer.FieldSize + 7) / 8;
|
||
|
byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES];
|
||
|
int pos = 0;
|
||
|
|
||
|
for (int i = 0; i < m_size; ++i)
|
||
|
{
|
||
|
byte MASK = (byte)(((i ^ index) - 1) >> 31);
|
||
|
|
||
|
for (int j = 0; j < FE_BYTES; ++j)
|
||
|
{
|
||
|
x[j] ^= (byte)(m_table[pos + j] & MASK);
|
||
|
y[j] ^= (byte)(m_table[pos + FE_BYTES + j] & MASK);
|
||
|
}
|
||
|
|
||
|
pos += (FE_BYTES * 2);
|
||
|
}
|
||
|
|
||
|
return CreatePoint(x, y);
|
||
|
}
|
||
|
|
||
|
public override ECPoint LookupVar(int index)
|
||
|
{
|
||
|
int FE_BYTES = (m_outer.FieldSize + 7) / 8;
|
||
|
byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES];
|
||
|
int pos = index * FE_BYTES * 2;
|
||
|
|
||
|
for (int j = 0; j < FE_BYTES; ++j)
|
||
|
{
|
||
|
x[j] = m_table[pos + j];
|
||
|
y[j] = m_table[pos + FE_BYTES + j];
|
||
|
}
|
||
|
|
||
|
return CreatePoint(x, y);
|
||
|
}
|
||
|
|
||
|
private ECPoint CreatePoint(byte[] x, byte[] y)
|
||
|
{
|
||
|
ECFieldElement X = m_outer.FromBigInteger(new BigInteger(1, x));
|
||
|
ECFieldElement Y = m_outer.FromBigInteger(new BigInteger(1, y));
|
||
|
return m_outer.CreateRawPoint(X, Y, false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public abstract class AbstractFpCurve
|
||
|
: ECCurve
|
||
|
{
|
||
|
protected AbstractFpCurve(BigInteger q)
|
||
|
: base(FiniteFields.GetPrimeField(q))
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public override bool IsValidFieldElement(BigInteger x)
|
||
|
{
|
||
|
return x != null && x.SignValue >= 0 && x.CompareTo(Field.Characteristic) < 0;
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement RandomFieldElement(SecureRandom r)
|
||
|
{
|
||
|
/*
|
||
|
* NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we
|
||
|
* use the product of two independent elements to mitigate side-channels.
|
||
|
*/
|
||
|
BigInteger p = Field.Characteristic;
|
||
|
ECFieldElement fe1 = FromBigInteger(ImplRandomFieldElement(r, p));
|
||
|
ECFieldElement fe2 = FromBigInteger(ImplRandomFieldElement(r, p));
|
||
|
return fe1.Multiply(fe2);
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement RandomFieldElementMult(SecureRandom r)
|
||
|
{
|
||
|
/*
|
||
|
* NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we
|
||
|
* use the product of two independent elements to mitigate side-channels.
|
||
|
*/
|
||
|
BigInteger p = Field.Characteristic;
|
||
|
ECFieldElement fe1 = FromBigInteger(ImplRandomFieldElementMult(r, p));
|
||
|
ECFieldElement fe2 = FromBigInteger(ImplRandomFieldElementMult(r, p));
|
||
|
return fe1.Multiply(fe2);
|
||
|
}
|
||
|
|
||
|
protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
|
||
|
{
|
||
|
ECFieldElement x = FromBigInteger(X1);
|
||
|
ECFieldElement rhs = x.Square().Add(A).Multiply(x).Add(B);
|
||
|
ECFieldElement y = rhs.Sqrt();
|
||
|
|
||
|
/*
|
||
|
* If y is not a square, then we haven't got a point on the curve
|
||
|
*/
|
||
|
if (y == null)
|
||
|
throw new ArgumentException("Invalid point compression");
|
||
|
|
||
|
if (y.TestBitZero() != (yTilde == 1))
|
||
|
{
|
||
|
// Use the other root
|
||
|
y = y.Negate();
|
||
|
}
|
||
|
|
||
|
return CreateRawPoint(x, y, true);
|
||
|
}
|
||
|
|
||
|
private static BigInteger ImplRandomFieldElement(SecureRandom r, BigInteger p)
|
||
|
{
|
||
|
BigInteger x;
|
||
|
do
|
||
|
{
|
||
|
x = BigIntegers.CreateRandomBigInteger(p.BitLength, r);
|
||
|
}
|
||
|
while (x.CompareTo(p) >= 0);
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
private static BigInteger ImplRandomFieldElementMult(SecureRandom r, BigInteger p)
|
||
|
{
|
||
|
BigInteger x;
|
||
|
do
|
||
|
{
|
||
|
x = BigIntegers.CreateRandomBigInteger(p.BitLength, r);
|
||
|
}
|
||
|
while (x.SignValue <= 0 || x.CompareTo(p) >= 0);
|
||
|
return x;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Elliptic curve over Fp
|
||
|
*/
|
||
|
public class FpCurve
|
||
|
: AbstractFpCurve
|
||
|
{
|
||
|
private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
|
||
|
|
||
|
protected readonly BigInteger m_q, m_r;
|
||
|
protected readonly FpPoint m_infinity;
|
||
|
|
||
|
|
||
|
public FpCurve(BigInteger q, BigInteger a, BigInteger b)
|
||
|
: this(q, a, b, null, null)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
|
||
|
: base(q)
|
||
|
{
|
||
|
this.m_q = q;
|
||
|
this.m_r = FpFieldElement.CalculateResidue(q);
|
||
|
this.m_infinity = new FpPoint(this, null, null, false);
|
||
|
|
||
|
this.m_a = FromBigInteger(a);
|
||
|
this.m_b = FromBigInteger(b);
|
||
|
this.m_order = order;
|
||
|
this.m_cofactor = cofactor;
|
||
|
this.m_coord = FP_DEFAULT_COORDS;
|
||
|
}
|
||
|
|
||
|
|
||
|
protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
|
||
|
: this(q, r, a, b, null, null)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
|
||
|
: base(q)
|
||
|
{
|
||
|
this.m_q = q;
|
||
|
this.m_r = r;
|
||
|
this.m_infinity = new FpPoint(this, null, null, false);
|
||
|
|
||
|
this.m_a = a;
|
||
|
this.m_b = b;
|
||
|
this.m_order = order;
|
||
|
this.m_cofactor = cofactor;
|
||
|
this.m_coord = FP_DEFAULT_COORDS;
|
||
|
}
|
||
|
|
||
|
protected override ECCurve CloneCurve()
|
||
|
{
|
||
|
return new FpCurve(m_q, m_r, m_a, m_b, m_order, m_cofactor);
|
||
|
}
|
||
|
|
||
|
public override bool SupportsCoordinateSystem(int coord)
|
||
|
{
|
||
|
switch (coord)
|
||
|
{
|
||
|
case COORD_AFFINE:
|
||
|
case COORD_HOMOGENEOUS:
|
||
|
case COORD_JACOBIAN:
|
||
|
case COORD_JACOBIAN_MODIFIED:
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public virtual BigInteger Q
|
||
|
{
|
||
|
get { return m_q; }
|
||
|
}
|
||
|
|
||
|
public override ECPoint Infinity
|
||
|
{
|
||
|
get { return m_infinity; }
|
||
|
}
|
||
|
|
||
|
public override int FieldSize
|
||
|
{
|
||
|
get { return m_q.BitLength; }
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement FromBigInteger(BigInteger x)
|
||
|
{
|
||
|
return new FpFieldElement(this.m_q, this.m_r, x);
|
||
|
}
|
||
|
|
||
|
protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
|
||
|
{
|
||
|
return new FpPoint(this, x, y, withCompression);
|
||
|
}
|
||
|
|
||
|
protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
|
||
|
{
|
||
|
return new FpPoint(this, x, y, zs, withCompression);
|
||
|
}
|
||
|
|
||
|
public override ECPoint ImportPoint(ECPoint p)
|
||
|
{
|
||
|
if (this != p.Curve && this.CoordinateSystem == COORD_JACOBIAN && !p.IsInfinity)
|
||
|
{
|
||
|
switch (p.Curve.CoordinateSystem)
|
||
|
{
|
||
|
case COORD_JACOBIAN:
|
||
|
case COORD_JACOBIAN_CHUDNOVSKY:
|
||
|
case COORD_JACOBIAN_MODIFIED:
|
||
|
return new FpPoint(this,
|
||
|
FromBigInteger(p.RawXCoord.ToBigInteger()),
|
||
|
FromBigInteger(p.RawYCoord.ToBigInteger()),
|
||
|
new ECFieldElement[] { FromBigInteger(p.GetZCoord(0).ToBigInteger()) },
|
||
|
p.IsCompressed);
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return base.ImportPoint(p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public abstract class AbstractF2mCurve
|
||
|
: ECCurve
|
||
|
{
|
||
|
public static BigInteger Inverse(int m, int[] ks, BigInteger x)
|
||
|
{
|
||
|
return new LongArray(x).ModInverse(m, ks).ToBigInteger();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The auxiliary values <code>s<sub>0</sub></code> and
|
||
|
* <code>s<sub>1</sub></code> used for partial modular reduction for
|
||
|
* Koblitz curves.
|
||
|
*/
|
||
|
private BigInteger[] si = null;
|
||
|
|
||
|
private static IFiniteField BuildField(int m, int k1, int k2, int k3)
|
||
|
{
|
||
|
if (k1 == 0)
|
||
|
{
|
||
|
throw new ArgumentException("k1 must be > 0");
|
||
|
}
|
||
|
|
||
|
if (k2 == 0)
|
||
|
{
|
||
|
if (k3 != 0)
|
||
|
{
|
||
|
throw new ArgumentException("k3 must be 0 if k2 == 0");
|
||
|
}
|
||
|
|
||
|
return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, m });
|
||
|
}
|
||
|
|
||
|
if (k2 <= k1)
|
||
|
{
|
||
|
throw new ArgumentException("k2 must be > k1");
|
||
|
}
|
||
|
|
||
|
if (k3 <= k2)
|
||
|
{
|
||
|
throw new ArgumentException("k3 must be > k2");
|
||
|
}
|
||
|
|
||
|
return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, k2, k3, m });
|
||
|
}
|
||
|
|
||
|
protected AbstractF2mCurve(int m, int k1, int k2, int k3)
|
||
|
: base(BuildField(m, k1, k2, k3))
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
public override ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
|
||
|
{
|
||
|
ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y);
|
||
|
|
||
|
switch (this.CoordinateSystem)
|
||
|
{
|
||
|
case COORD_LAMBDA_AFFINE:
|
||
|
case COORD_LAMBDA_PROJECTIVE:
|
||
|
{
|
||
|
if (X.IsZero)
|
||
|
{
|
||
|
if (!Y.Square().Equals(B))
|
||
|
throw new ArgumentException();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Y becomes Lambda (X + Y/X) here
|
||
|
Y = Y.Divide(X).Add(X);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return CreateRawPoint(X, Y, withCompression);
|
||
|
}
|
||
|
|
||
|
public override bool IsValidFieldElement(BigInteger x)
|
||
|
{
|
||
|
return x != null && x.SignValue >= 0 && x.BitLength <= FieldSize;
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement RandomFieldElement(SecureRandom r)
|
||
|
{
|
||
|
int m = FieldSize;
|
||
|
return FromBigInteger(BigIntegers.CreateRandomBigInteger(m, r));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement RandomFieldElementMult(SecureRandom r)
|
||
|
{
|
||
|
/*
|
||
|
* NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we
|
||
|
* use the product of two independent elements to mitigate side-channels.
|
||
|
*/
|
||
|
int m = FieldSize;
|
||
|
ECFieldElement fe1 = FromBigInteger(ImplRandomFieldElementMult(r, m));
|
||
|
ECFieldElement fe2 = FromBigInteger(ImplRandomFieldElementMult(r, m));
|
||
|
return fe1.Multiply(fe2);
|
||
|
}
|
||
|
|
||
|
protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
|
||
|
{
|
||
|
ECFieldElement xp = FromBigInteger(X1), yp = null;
|
||
|
if (xp.IsZero)
|
||
|
{
|
||
|
yp = B.Sqrt();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
|
||
|
ECFieldElement z = SolveQuadraticEquation(beta);
|
||
|
|
||
|
if (z != null)
|
||
|
{
|
||
|
if (z.TestBitZero() != (yTilde == 1))
|
||
|
{
|
||
|
z = z.AddOne();
|
||
|
}
|
||
|
|
||
|
switch (this.CoordinateSystem)
|
||
|
{
|
||
|
case COORD_LAMBDA_AFFINE:
|
||
|
case COORD_LAMBDA_PROJECTIVE:
|
||
|
{
|
||
|
yp = z.Add(xp);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
yp = z.Multiply(xp);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (yp == null)
|
||
|
throw new ArgumentException("Invalid point compression");
|
||
|
|
||
|
return CreateRawPoint(xp, yp, true);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
|
||
|
* D.1.6) The other solution is <code>z + 1</code>.
|
||
|
*
|
||
|
* @param beta
|
||
|
* The value to solve the quadratic equation for.
|
||
|
* @return the solution for <code>z<sup>2</sup> + z = beta</code> or
|
||
|
* <code>null</code> if no solution exists.
|
||
|
*/
|
||
|
internal ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
|
||
|
{
|
||
|
AbstractF2mFieldElement betaF2m = (AbstractF2mFieldElement)beta;
|
||
|
|
||
|
bool fastTrace = betaF2m.HasFastTrace;
|
||
|
if (fastTrace && 0 != betaF2m.Trace())
|
||
|
return null;
|
||
|
|
||
|
int m = FieldSize;
|
||
|
|
||
|
// For odd m, use the half-trace
|
||
|
if (0 != (m & 1))
|
||
|
{
|
||
|
ECFieldElement r = betaF2m.HalfTrace();
|
||
|
if (fastTrace || r.Square().Add(r).Add(beta).IsZero)
|
||
|
return r;
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
if (beta.IsZero)
|
||
|
return beta;
|
||
|
|
||
|
ECFieldElement gamma, z, zeroElement = FromBigInteger(BigInteger.Zero);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
ECFieldElement t = FromBigInteger(BigInteger.Arbitrary(m));
|
||
|
z = zeroElement;
|
||
|
ECFieldElement w = beta;
|
||
|
for (int i = 1; i < m; i++)
|
||
|
{
|
||
|
ECFieldElement w2 = w.Square();
|
||
|
z = z.Square().Add(w2.Multiply(t));
|
||
|
w = w2.Add(beta);
|
||
|
}
|
||
|
if (!w.IsZero)
|
||
|
{
|
||
|
return null;
|
||
|
}
|
||
|
gamma = z.Square().Add(z);
|
||
|
}
|
||
|
while (gamma.IsZero);
|
||
|
|
||
|
return z;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return the auxiliary values <code>s<sub>0</sub></code> and
|
||
|
* <code>s<sub>1</sub></code> used for partial modular reduction for
|
||
|
* Koblitz curves.
|
||
|
*/
|
||
|
internal virtual BigInteger[] GetSi()
|
||
|
{
|
||
|
if (si == null)
|
||
|
{
|
||
|
lock (this)
|
||
|
{
|
||
|
if (si == null)
|
||
|
{
|
||
|
si = Tnaf.GetSi(this);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return si;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if this is a Koblitz curve (ABC curve).
|
||
|
* @return true if this is a Koblitz curve (ABC curve), false otherwise
|
||
|
*/
|
||
|
public virtual bool IsKoblitz
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static BigInteger ImplRandomFieldElementMult(SecureRandom r, int m)
|
||
|
{
|
||
|
BigInteger x;
|
||
|
do
|
||
|
{
|
||
|
x = BigIntegers.CreateRandomBigInteger(m, r);
|
||
|
}
|
||
|
while (x.SignValue <= 0);
|
||
|
return x;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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
|
||
|
: AbstractF2mCurve
|
||
|
{
|
||
|
private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
|
||
|
|
||
|
/**
|
||
|
* The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
*/
|
||
|
private readonly int m;
|
||
|
|
||
|
/**
|
||
|
* TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
|
||
|
* x<sup>k</sup> + 1</code> represents the reduction polynomial
|
||
|
* <code>f(z)</code>.<br/>
|
||
|
* PPB: 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>.<br/>
|
||
|
*/
|
||
|
private readonly int k1;
|
||
|
|
||
|
/**
|
||
|
* TPB: Always set to <code>0</code><br/>
|
||
|
* PPB: 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>.<br/>
|
||
|
*/
|
||
|
private readonly int k2;
|
||
|
|
||
|
/**
|
||
|
* TPB: Always set to <code>0</code><br/>
|
||
|
* PPB: 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>.<br/>
|
||
|
*/
|
||
|
private readonly int k3;
|
||
|
|
||
|
/**
|
||
|
* The point at infinity on this curve.
|
||
|
*/
|
||
|
protected readonly F2mPoint m_infinity;
|
||
|
|
||
|
/**
|
||
|
* Constructor for Trinomial Polynomial Basis (TPB).
|
||
|
* @param m The exponent <code>m</code> of
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
* @param k The integer <code>k</code> where <code>x<sup>m</sup> +
|
||
|
* x<sup>k</sup> + 1</code> represents the reduction
|
||
|
* polynomial <code>f(z)</code>.
|
||
|
* @param a The coefficient <code>a</code> in the Weierstrass equation
|
||
|
* for non-supersingular elliptic curves over
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
* @param b The coefficient <code>b</code> in the Weierstrass equation
|
||
|
* for non-supersingular elliptic curves over
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
*/
|
||
|
|
||
|
public F2mCurve(
|
||
|
int m,
|
||
|
int k,
|
||
|
BigInteger a,
|
||
|
BigInteger b)
|
||
|
: this(m, k, 0, 0, a, b, null, null)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Constructor for Trinomial Polynomial Basis (TPB).
|
||
|
* @param m The exponent <code>m</code> of
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
* @param k The integer <code>k</code> where <code>x<sup>m</sup> +
|
||
|
* x<sup>k</sup> + 1</code> represents the reduction
|
||
|
* polynomial <code>f(z)</code>.
|
||
|
* @param a The coefficient <code>a</code> in the Weierstrass equation
|
||
|
* for non-supersingular elliptic curves over
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
* @param b The coefficient <code>b</code> in the Weierstrass equation
|
||
|
* for non-supersingular elliptic curves over
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
* @param order The order of the main subgroup of the elliptic curve.
|
||
|
* @param cofactor The cofactor of the elliptic curve, i.e.
|
||
|
* <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
|
||
|
*/
|
||
|
public F2mCurve(
|
||
|
int m,
|
||
|
int k,
|
||
|
BigInteger a,
|
||
|
BigInteger b,
|
||
|
BigInteger order,
|
||
|
BigInteger cofactor)
|
||
|
: this(m, k, 0, 0, a, b, order, cofactor)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Constructor for Pentanomial Polynomial Basis (PPB).
|
||
|
* @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>.
|
||
|
* @param a The coefficient <code>a</code> in the Weierstrass equation
|
||
|
* for non-supersingular elliptic curves over
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
* @param b The coefficient <code>b</code> in the Weierstrass equation
|
||
|
* for non-supersingular elliptic curves over
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
*/
|
||
|
|
||
|
public F2mCurve(
|
||
|
int m,
|
||
|
int k1,
|
||
|
int k2,
|
||
|
int k3,
|
||
|
BigInteger a,
|
||
|
BigInteger b)
|
||
|
: this(m, k1, k2, k3, a, b, null, null)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Constructor for Pentanomial Polynomial Basis (PPB).
|
||
|
* @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>.
|
||
|
* @param a The coefficient <code>a</code> in the Weierstrass equation
|
||
|
* for non-supersingular elliptic curves over
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
* @param b The coefficient <code>b</code> in the Weierstrass equation
|
||
|
* for non-supersingular elliptic curves over
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
* @param order The order of the main subgroup of the elliptic curve.
|
||
|
* @param cofactor The cofactor of the elliptic curve, i.e.
|
||
|
* <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
|
||
|
*/
|
||
|
public F2mCurve(
|
||
|
int m,
|
||
|
int k1,
|
||
|
int k2,
|
||
|
int k3,
|
||
|
BigInteger a,
|
||
|
BigInteger b,
|
||
|
BigInteger order,
|
||
|
BigInteger cofactor)
|
||
|
: base(m, k1, k2, k3)
|
||
|
{
|
||
|
this.m = m;
|
||
|
this.k1 = k1;
|
||
|
this.k2 = k2;
|
||
|
this.k3 = k3;
|
||
|
this.m_order = order;
|
||
|
this.m_cofactor = cofactor;
|
||
|
this.m_infinity = new F2mPoint(this, null, null, false);
|
||
|
|
||
|
if (k1 == 0)
|
||
|
throw new ArgumentException("k1 must be > 0");
|
||
|
|
||
|
if (k2 == 0)
|
||
|
{
|
||
|
if (k3 != 0)
|
||
|
throw new ArgumentException("k3 must be 0 if k2 == 0");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (k2 <= k1)
|
||
|
throw new ArgumentException("k2 must be > k1");
|
||
|
|
||
|
if (k3 <= k2)
|
||
|
throw new ArgumentException("k3 must be > k2");
|
||
|
}
|
||
|
|
||
|
this.m_a = FromBigInteger(a);
|
||
|
this.m_b = FromBigInteger(b);
|
||
|
this.m_coord = F2M_DEFAULT_COORDS;
|
||
|
}
|
||
|
|
||
|
protected F2mCurve(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
|
||
|
: base(m, k1, k2, k3)
|
||
|
{
|
||
|
this.m = m;
|
||
|
this.k1 = k1;
|
||
|
this.k2 = k2;
|
||
|
this.k3 = k3;
|
||
|
this.m_order = order;
|
||
|
this.m_cofactor = cofactor;
|
||
|
|
||
|
this.m_infinity = new F2mPoint(this, null, null, false);
|
||
|
this.m_a = a;
|
||
|
this.m_b = b;
|
||
|
this.m_coord = F2M_DEFAULT_COORDS;
|
||
|
}
|
||
|
|
||
|
protected override ECCurve CloneCurve()
|
||
|
{
|
||
|
return new F2mCurve(m, k1, k2, k3, m_a, m_b, m_order, m_cofactor);
|
||
|
}
|
||
|
|
||
|
public override bool SupportsCoordinateSystem(int coord)
|
||
|
{
|
||
|
switch (coord)
|
||
|
{
|
||
|
case COORD_AFFINE:
|
||
|
case COORD_HOMOGENEOUS:
|
||
|
case COORD_LAMBDA_PROJECTIVE:
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected override ECMultiplier CreateDefaultMultiplier()
|
||
|
{
|
||
|
if (IsKoblitz)
|
||
|
{
|
||
|
return new WTauNafMultiplier();
|
||
|
}
|
||
|
|
||
|
return base.CreateDefaultMultiplier();
|
||
|
}
|
||
|
|
||
|
public override int FieldSize
|
||
|
{
|
||
|
get { return m; }
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement FromBigInteger(BigInteger x)
|
||
|
{
|
||
|
return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, x);
|
||
|
}
|
||
|
|
||
|
protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
|
||
|
{
|
||
|
return new F2mPoint(this, x, y, withCompression);
|
||
|
}
|
||
|
|
||
|
protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
|
||
|
{
|
||
|
return new F2mPoint(this, x, y, zs, withCompression);
|
||
|
}
|
||
|
|
||
|
public override ECPoint Infinity
|
||
|
{
|
||
|
get { return m_infinity; }
|
||
|
}
|
||
|
|
||
|
public int M
|
||
|
{
|
||
|
get { return m; }
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return true if curve uses a Trinomial basis.
|
||
|
*
|
||
|
* @return true if curve Trinomial, false otherwise.
|
||
|
*/
|
||
|
public bool IsTrinomial()
|
||
|
{
|
||
|
return k2 == 0 && k3 == 0;
|
||
|
}
|
||
|
|
||
|
public int K1
|
||
|
{
|
||
|
get { return k1; }
|
||
|
}
|
||
|
|
||
|
public int K2
|
||
|
{
|
||
|
get { return k2; }
|
||
|
}
|
||
|
|
||
|
public int K3
|
||
|
{
|
||
|
get { return k3; }
|
||
|
}
|
||
|
|
||
|
public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len)
|
||
|
{
|
||
|
int FE_LONGS = (m + 63) / 64;
|
||
|
|
||
|
long[] table = new long[len * FE_LONGS * 2];
|
||
|
{
|
||
|
int pos = 0;
|
||
|
for (int i = 0; i < len; ++i)
|
||
|
{
|
||
|
ECPoint p = points[off + i];
|
||
|
((F2mFieldElement)p.RawXCoord).x.CopyTo(table, pos); pos += FE_LONGS;
|
||
|
((F2mFieldElement)p.RawYCoord).x.CopyTo(table, pos); pos += FE_LONGS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return new DefaultF2mLookupTable(this, table, len);
|
||
|
}
|
||
|
|
||
|
private class DefaultF2mLookupTable
|
||
|
: AbstractECLookupTable
|
||
|
{
|
||
|
private readonly F2mCurve m_outer;
|
||
|
private readonly long[] m_table;
|
||
|
private readonly int m_size;
|
||
|
|
||
|
internal DefaultF2mLookupTable(F2mCurve outer, long[] table, int size)
|
||
|
{
|
||
|
this.m_outer = outer;
|
||
|
this.m_table = table;
|
||
|
this.m_size = size;
|
||
|
}
|
||
|
|
||
|
public override int Size
|
||
|
{
|
||
|
get { return m_size; }
|
||
|
}
|
||
|
|
||
|
public override ECPoint Lookup(int index)
|
||
|
{
|
||
|
int FE_LONGS = (m_outer.m + 63) / 64;
|
||
|
long[] x = new long[FE_LONGS], y = new long[FE_LONGS];
|
||
|
int pos = 0;
|
||
|
|
||
|
for (int i = 0; i < m_size; ++i)
|
||
|
{
|
||
|
long MASK =((i ^ index) - 1) >> 31;
|
||
|
|
||
|
for (int j = 0; j < FE_LONGS; ++j)
|
||
|
{
|
||
|
x[j] ^= m_table[pos + j] & MASK;
|
||
|
y[j] ^= m_table[pos + FE_LONGS + j] & MASK;
|
||
|
}
|
||
|
|
||
|
pos += (FE_LONGS * 2);
|
||
|
}
|
||
|
|
||
|
return CreatePoint(x, y);
|
||
|
}
|
||
|
|
||
|
public override ECPoint LookupVar(int index)
|
||
|
{
|
||
|
int FE_LONGS = (m_outer.m + 63) / 64;
|
||
|
long[] x = new long[FE_LONGS], y = new long[FE_LONGS];
|
||
|
int pos = index * FE_LONGS * 2;
|
||
|
|
||
|
for (int j = 0; j < FE_LONGS; ++j)
|
||
|
{
|
||
|
x[j] = m_table[pos + j];
|
||
|
y[j] = m_table[pos + FE_LONGS + j];
|
||
|
}
|
||
|
|
||
|
return CreatePoint(x, y);
|
||
|
}
|
||
|
|
||
|
private ECPoint CreatePoint(long[] x, long[] y)
|
||
|
{
|
||
|
int m = m_outer.m;
|
||
|
int[] ks = m_outer.IsTrinomial() ? new int[] { m_outer.k1 } : new int[] { m_outer.k1, m_outer.k2, m_outer.k3 };
|
||
|
|
||
|
ECFieldElement X = new F2mFieldElement(m, ks, new LongArray(x));
|
||
|
ECFieldElement Y = new F2mFieldElement(m, ks, new LongArray(y));
|
||
|
return m_outer.CreateRawPoint(X, Y, false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#pragma warning restore
|
||
|
#endif
|