ECCurve
using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Endo;
using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier;
using Renci.SshNet.Security.Org.BouncyCastle.Math.Field;
using Renci.SshNet.Security.Org.BouncyCastle.Utilities;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC
{
internal abstract class ECCurve
{
internal 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 eCCurve = outer.CloneCurve();
if (eCCurve == outer)
throw new InvalidOperationException("implementation returned current curve");
eCCurve.m_coord = coord;
eCCurve.m_endomorphism = endomorphism;
eCCurve.m_multiplier = multiplier;
return eCCurve;
}
}
private class DefaultLookupTable : ECLookupTable
{
private readonly ECCurve m_outer;
private readonly byte[] m_table;
private readonly int m_size;
public virtual int Size => m_size;
internal DefaultLookupTable(ECCurve outer, byte[] table, int size)
{
m_outer = outer;
m_table = table;
m_size = size;
}
public virtual ECPoint Lookup(int index)
{
int num = (m_outer.FieldSize + 7) / 8;
byte[] array = new byte[num];
byte[] array2 = new byte[num];
int num2 = 0;
for (int i = 0; i < m_size; i++) {
byte b = (byte)((i ^ index) - 1 >> 31);
for (int j = 0; j < num; j++) {
array[j] ^= (byte)(m_table[num2 + j] & b);
array2[j] ^= (byte)(m_table[num2 + num + j] & b);
}
num2 += num * 2;
}
ECFieldElement x = m_outer.FromBigInteger(new BigInteger(1, array));
ECFieldElement y = m_outer.FromBigInteger(new BigInteger(1, array2));
return m_outer.CreateRawPoint(x, y, false);
}
}
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;
protected readonly IFiniteField m_field;
protected ECFieldElement m_a;
protected ECFieldElement m_b;
protected BigInteger m_order;
protected BigInteger m_cofactor;
protected int m_coord;
protected ECEndomorphism m_endomorphism;
protected ECMultiplier m_multiplier;
public abstract int FieldSize { get; }
public abstract ECPoint Infinity { get; }
public virtual IFiniteField Field => m_field;
public virtual ECFieldElement A => m_a;
public virtual ECFieldElement B => m_b;
public virtual BigInteger Order => m_order;
public virtual BigInteger Cofactor => m_cofactor;
public virtual int CoordinateSystem => m_coord;
public static int[] GetAllCoordinateSystems()
{
return new int[8] {
0,
1,
2,
3,
4,
5,
6,
7
};
}
protected ECCurve(IFiniteField field)
{
m_field = field;
}
public abstract ECFieldElement FromBigInteger(BigInteger x);
public abstract bool IsValidFieldElement(BigInteger x);
public virtual Config Configure()
{
return new Config(this, m_coord, m_endomorphism, m_multiplier);
}
public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y)
{
ECPoint eCPoint = CreatePoint(x, y);
if (!eCPoint.IsValid())
throw new ArgumentException("Invalid point coordinates");
return eCPoint;
}
public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y, bool withCompression)
{
ECPoint eCPoint = CreatePoint(x, y, withCompression);
if (!eCPoint.IsValid())
throw new ArgumentException("Invalid point coordinates");
return eCPoint;
}
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 == 0;
}
public virtual PreCompInfo GetPreCompInfo(ECPoint point, string name)
{
CheckPoint(point);
IDictionary preCompTable = default(IDictionary);
lock (point) {
preCompTable = point.m_preCompTable;
}
if (preCompTable == null)
return null;
lock (preCompTable) {
return (PreCompInfo)preCompTable[name];
}
}
public virtual PreCompInfo Precompute(ECPoint point, string name, IPreCompCallback callback)
{
CheckPoint(point);
IDictionary dictionary = default(IDictionary);
lock (point) {
dictionary = point.m_preCompTable;
if (dictionary == null)
dictionary = (point.m_preCompTable = new Dictionary<object, object>(4));
}
lock (dictionary) {
PreCompInfo preCompInfo = (PreCompInfo)dictionary[name];
PreCompInfo preCompInfo2 = callback.Precompute(preCompInfo);
if (preCompInfo2 != preCompInfo)
dictionary[name] = preCompInfo2;
return preCompInfo2;
}
}
public virtual ECPoint ImportPoint(ECPoint p)
{
if (this == p.Curve)
return p;
if (p.IsInfinity)
return Infinity;
p = p.Normalize();
return CreatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
}
public virtual void NormalizeAll(ECPoint[] points)
{
NormalizeAll(points, 0, points.Length, null);
}
public virtual void NormalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso)
{
CheckPoints(points, off, len);
int coordinateSystem = CoordinateSystem;
if (coordinateSystem == 0 || coordinateSystem == 5) {
if (iso != null)
throw new ArgumentException("not valid for affine coordinates", "iso");
} else {
ECFieldElement[] array = new ECFieldElement[len];
int[] array2 = new int[len];
int num = 0;
for (int i = 0; i < len; i++) {
ECPoint eCPoint = points[off + i];
if (eCPoint != null && (iso != null || !eCPoint.IsNormalized())) {
array[num] = eCPoint.GetZCoord(0);
array2[num++] = off + i;
}
}
if (num != 0) {
ECAlgorithms.MontgomeryTrick(array, 0, num, iso);
for (int j = 0; j < num; j++) {
int num3 = array2[j];
points[num3] = points[num3].Normalize(array[j]);
}
}
}
}
public virtual ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len)
{
int num = (FieldSize + 7) / 8;
byte[] array = new byte[len * num * 2];
int num2 = 0;
for (int i = 0; i < len; i++) {
ECPoint obj = points[off + i];
byte[] array2 = obj.RawXCoord.ToBigInteger().ToByteArray();
byte[] array3 = obj.RawYCoord.ToBigInteger().ToByteArray();
int num3 = (array2.Length > num) ? 1 : 0;
int num4 = array2.Length - num3;
int num5 = (array3.Length > num) ? 1 : 0;
int num6 = array3.Length - num5;
Array.Copy(array2, num3, array, num2 + num - num4, num4);
num2 += num;
Array.Copy(array3, num5, array, num2 + num - num6, num6);
num2 += num;
}
return new DefaultLookupTable(this, array, len);
}
protected virtual void CheckPoint(ECPoint point)
{
if (point == null || 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");
int num = 0;
while (true) {
if (num >= len)
return;
ECPoint eCPoint = points[off + num];
if (eCPoint != null && this != eCPoint.Curve)
break;
num++;
}
throw new ArgumentException("entries must be null or on this curve", "points");
}
public virtual bool Equals(ECCurve other)
{
if (this == other)
return true;
if (other == null)
return false;
if (Field.Equals(other.Field) && A.ToBigInteger().Equals(other.A.ToBigInteger()))
return B.ToBigInteger().Equals(other.B.ToBigInteger());
return false;
}
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;
}
public virtual ECMultiplier GetMultiplier()
{
lock (this) {
if (m_multiplier == null)
m_multiplier = CreateDefaultMultiplier();
return m_multiplier;
}
}
public virtual ECPoint DecodePoint(byte[] encoded)
{
ECPoint eCPoint = null;
int num = (FieldSize + 7) / 8;
byte b = encoded[0];
switch (b) {
case 0:
if (encoded.Length != 1)
throw new ArgumentException("Incorrect length for infinity encoding", "encoded");
eCPoint = Infinity;
break;
case 2:
case 3: {
if (encoded.Length != num + 1)
throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
int yTilde = b & 1;
BigInteger x3 = new BigInteger(1, encoded, 1, num);
eCPoint = DecompressPoint(yTilde, x3);
if (!eCPoint.ImplIsValid(true, true))
throw new ArgumentException("Invalid point");
break;
}
case 4: {
if (encoded.Length != 2 * num + 1)
throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded");
BigInteger x2 = new BigInteger(1, encoded, 1, num);
BigInteger y = new BigInteger(1, encoded, 1 + num, num);
eCPoint = ValidatePoint(x2, y);
break;
}
case 6:
case 7: {
if (encoded.Length != 2 * num + 1)
throw new ArgumentException("Incorrect length for hybrid encoding", "encoded");
BigInteger x = new BigInteger(1, encoded, 1, num);
BigInteger bigInteger = new BigInteger(1, encoded, 1 + num, num);
if (bigInteger.TestBit(0) != (b == 7))
throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded");
eCPoint = ValidatePoint(x, bigInteger);
break;
}
default:
throw new FormatException("Invalid point encoding " + b.ToString());
}
if (b != 0 && eCPoint.IsInfinity)
throw new ArgumentException("Invalid infinity encoding", "encoded");
return eCPoint;
}
}
}