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.
1003 lines
30 KiB
1003 lines
30 KiB
1 year ago
|
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||
|
#pragma warning disable
|
||
|
using System;
|
||
|
using System.Diagnostics;
|
||
|
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||
|
|
||
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC
|
||
|
{
|
||
|
public abstract class ECFieldElement
|
||
|
{
|
||
|
public abstract BigInteger ToBigInteger();
|
||
|
public abstract string FieldName { get; }
|
||
|
public abstract int FieldSize { get; }
|
||
|
public abstract ECFieldElement Add(ECFieldElement b);
|
||
|
public abstract ECFieldElement AddOne();
|
||
|
public abstract ECFieldElement Subtract(ECFieldElement b);
|
||
|
public abstract ECFieldElement Multiply(ECFieldElement b);
|
||
|
public abstract ECFieldElement Divide(ECFieldElement b);
|
||
|
public abstract ECFieldElement Negate();
|
||
|
public abstract ECFieldElement Square();
|
||
|
public abstract ECFieldElement Invert();
|
||
|
public abstract ECFieldElement Sqrt();
|
||
|
|
||
|
public virtual int BitLength
|
||
|
{
|
||
|
get { return ToBigInteger().BitLength; }
|
||
|
}
|
||
|
|
||
|
public virtual bool IsOne
|
||
|
{
|
||
|
get { return BitLength == 1; }
|
||
|
}
|
||
|
|
||
|
public virtual bool IsZero
|
||
|
{
|
||
|
get { return 0 == ToBigInteger().SignValue; }
|
||
|
}
|
||
|
|
||
|
public virtual ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
return Multiply(b).Subtract(x.Multiply(y));
|
||
|
}
|
||
|
|
||
|
public virtual ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
return Multiply(b).Add(x.Multiply(y));
|
||
|
}
|
||
|
|
||
|
public virtual ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
return Square().Subtract(x.Multiply(y));
|
||
|
}
|
||
|
|
||
|
public virtual ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
return Square().Add(x.Multiply(y));
|
||
|
}
|
||
|
|
||
|
public virtual ECFieldElement SquarePow(int pow)
|
||
|
{
|
||
|
ECFieldElement r = this;
|
||
|
for (int i = 0; i < pow; ++i)
|
||
|
{
|
||
|
r = r.Square();
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
public virtual bool TestBitZero()
|
||
|
{
|
||
|
return ToBigInteger().TestBit(0);
|
||
|
}
|
||
|
|
||
|
public override bool Equals(object obj)
|
||
|
{
|
||
|
return Equals(obj as ECFieldElement);
|
||
|
}
|
||
|
|
||
|
public virtual bool Equals(ECFieldElement other)
|
||
|
{
|
||
|
if (this == other)
|
||
|
return true;
|
||
|
if (null == other)
|
||
|
return false;
|
||
|
return ToBigInteger().Equals(other.ToBigInteger());
|
||
|
}
|
||
|
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
return ToBigInteger().GetHashCode();
|
||
|
}
|
||
|
|
||
|
public override string ToString()
|
||
|
{
|
||
|
return this.ToBigInteger().ToString(16);
|
||
|
}
|
||
|
|
||
|
public virtual byte[] GetEncoded()
|
||
|
{
|
||
|
return BigIntegers.AsUnsignedByteArray((FieldSize + 7) / 8, ToBigInteger());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public abstract class AbstractFpFieldElement
|
||
|
: ECFieldElement
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public class FpFieldElement
|
||
|
: AbstractFpFieldElement
|
||
|
{
|
||
|
private readonly BigInteger q, r, x;
|
||
|
|
||
|
internal static BigInteger CalculateResidue(BigInteger p)
|
||
|
{
|
||
|
int bitLength = p.BitLength;
|
||
|
if (bitLength >= 96)
|
||
|
{
|
||
|
BigInteger firstWord = p.ShiftRight(bitLength - 64);
|
||
|
if (firstWord.LongValue == -1L)
|
||
|
{
|
||
|
return BigInteger.One.ShiftLeft(bitLength).Subtract(p);
|
||
|
}
|
||
|
if ((bitLength & 7) == 0)
|
||
|
{
|
||
|
return BigInteger.One.ShiftLeft(bitLength << 1).Divide(p).Negate();
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
|
||
|
public FpFieldElement(BigInteger q, BigInteger x)
|
||
|
: this(q, CalculateResidue(q), x)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
internal FpFieldElement(BigInteger q, BigInteger r, BigInteger x)
|
||
|
{
|
||
|
if (x == null || x.SignValue < 0 || x.CompareTo(q) >= 0)
|
||
|
throw new ArgumentException("value invalid in Fp field element", "x");
|
||
|
|
||
|
this.q = q;
|
||
|
this.r = r;
|
||
|
this.x = x;
|
||
|
}
|
||
|
|
||
|
public override BigInteger ToBigInteger()
|
||
|
{
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* return the field name for this field.
|
||
|
*
|
||
|
* @return the string "Fp".
|
||
|
*/
|
||
|
public override string FieldName
|
||
|
{
|
||
|
get { return "Fp"; }
|
||
|
}
|
||
|
|
||
|
public override int FieldSize
|
||
|
{
|
||
|
get { return q.BitLength; }
|
||
|
}
|
||
|
|
||
|
public BigInteger Q
|
||
|
{
|
||
|
get { return q; }
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Add(
|
||
|
ECFieldElement b)
|
||
|
{
|
||
|
return new FpFieldElement(q, r, ModAdd(x, b.ToBigInteger()));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement AddOne()
|
||
|
{
|
||
|
BigInteger x2 = x.Add(BigInteger.One);
|
||
|
if (x2.CompareTo(q) == 0)
|
||
|
{
|
||
|
x2 = BigInteger.Zero;
|
||
|
}
|
||
|
return new FpFieldElement(q, r, x2);
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Subtract(
|
||
|
ECFieldElement b)
|
||
|
{
|
||
|
return new FpFieldElement(q, r, ModSubtract(x, b.ToBigInteger()));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Multiply(
|
||
|
ECFieldElement b)
|
||
|
{
|
||
|
return new FpFieldElement(q, r, ModMult(x, b.ToBigInteger()));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
BigInteger ax = this.x, bx = b.ToBigInteger(), xx = x.ToBigInteger(), yx = y.ToBigInteger();
|
||
|
BigInteger ab = ax.Multiply(bx);
|
||
|
BigInteger xy = xx.Multiply(yx);
|
||
|
return new FpFieldElement(q, r, ModReduce(ab.Subtract(xy)));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
BigInteger ax = this.x, bx = b.ToBigInteger(), xx = x.ToBigInteger(), yx = y.ToBigInteger();
|
||
|
BigInteger ab = ax.Multiply(bx);
|
||
|
BigInteger xy = xx.Multiply(yx);
|
||
|
BigInteger sum = ab.Add(xy);
|
||
|
if (r != null && r.SignValue < 0 && sum.BitLength > (q.BitLength << 1))
|
||
|
{
|
||
|
sum = sum.Subtract(q.ShiftLeft(q.BitLength));
|
||
|
}
|
||
|
return new FpFieldElement(q, r, ModReduce(sum));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Divide(
|
||
|
ECFieldElement b)
|
||
|
{
|
||
|
return new FpFieldElement(q, r, ModMult(x, ModInverse(b.ToBigInteger())));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Negate()
|
||
|
{
|
||
|
return x.SignValue == 0 ? this : new FpFieldElement(q, r, q.Subtract(x));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Square()
|
||
|
{
|
||
|
return new FpFieldElement(q, r, ModMult(x, x));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
BigInteger ax = this.x, xx = x.ToBigInteger(), yx = y.ToBigInteger();
|
||
|
BigInteger aa = ax.Multiply(ax);
|
||
|
BigInteger xy = xx.Multiply(yx);
|
||
|
return new FpFieldElement(q, r, ModReduce(aa.Subtract(xy)));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
BigInteger ax = this.x, xx = x.ToBigInteger(), yx = y.ToBigInteger();
|
||
|
BigInteger aa = ax.Multiply(ax);
|
||
|
BigInteger xy = xx.Multiply(yx);
|
||
|
BigInteger sum = aa.Add(xy);
|
||
|
if (r != null && r.SignValue < 0 && sum.BitLength > (q.BitLength << 1))
|
||
|
{
|
||
|
sum = sum.Subtract(q.ShiftLeft(q.BitLength));
|
||
|
}
|
||
|
return new FpFieldElement(q, r, ModReduce(sum));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Invert()
|
||
|
{
|
||
|
// TODO Modular inversion can be faster for a (Generalized) Mersenne Prime.
|
||
|
return new FpFieldElement(q, r, ModInverse(x));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* return a sqrt root - the routine verifies that the calculation
|
||
|
* returns the right value - if none exists it returns null.
|
||
|
*/
|
||
|
public override ECFieldElement Sqrt()
|
||
|
{
|
||
|
if (IsZero || IsOne)
|
||
|
return this;
|
||
|
|
||
|
if (!q.TestBit(0))
|
||
|
throw BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateNotImplementedException("even value of q");
|
||
|
|
||
|
if (q.TestBit(1)) // q == 4m + 3
|
||
|
{
|
||
|
BigInteger e = q.ShiftRight(2).Add(BigInteger.One);
|
||
|
return CheckSqrt(new FpFieldElement(q, r, x.ModPow(e, q)));
|
||
|
}
|
||
|
|
||
|
if (q.TestBit(2)) // q == 8m + 5
|
||
|
{
|
||
|
BigInteger t1 = x.ModPow(q.ShiftRight(3), q);
|
||
|
BigInteger t2 = ModMult(t1, x);
|
||
|
BigInteger t3 = ModMult(t2, t1);
|
||
|
|
||
|
if (t3.Equals(BigInteger.One))
|
||
|
{
|
||
|
return CheckSqrt(new FpFieldElement(q, r, t2));
|
||
|
}
|
||
|
|
||
|
// TODO This is constant and could be precomputed
|
||
|
BigInteger t4 = BigInteger.Two.ModPow(q.ShiftRight(2), q);
|
||
|
|
||
|
BigInteger y = ModMult(t2, t4);
|
||
|
|
||
|
return CheckSqrt(new FpFieldElement(q, r, y));
|
||
|
}
|
||
|
|
||
|
// q == 8m + 1
|
||
|
|
||
|
BigInteger legendreExponent = q.ShiftRight(1);
|
||
|
if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.One)))
|
||
|
return null;
|
||
|
|
||
|
BigInteger X = this.x;
|
||
|
BigInteger fourX = ModDouble(ModDouble(X)); ;
|
||
|
|
||
|
BigInteger k = legendreExponent.Add(BigInteger.One), qMinusOne = q.Subtract(BigInteger.One);
|
||
|
|
||
|
BigInteger U, V;
|
||
|
do
|
||
|
{
|
||
|
BigInteger P;
|
||
|
do
|
||
|
{
|
||
|
P = BigInteger.Arbitrary(q.BitLength);
|
||
|
}
|
||
|
while (P.CompareTo(q) >= 0
|
||
|
|| !ModReduce(P.Multiply(P).Subtract(fourX)).ModPow(legendreExponent, q).Equals(qMinusOne));
|
||
|
|
||
|
BigInteger[] result = LucasSequence(P, X, k);
|
||
|
U = result[0];
|
||
|
V = result[1];
|
||
|
|
||
|
if (ModMult(V, V).Equals(fourX))
|
||
|
{
|
||
|
return new FpFieldElement(q, r, ModHalfAbs(V));
|
||
|
}
|
||
|
}
|
||
|
while (U.Equals(BigInteger.One) || U.Equals(qMinusOne));
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
private ECFieldElement CheckSqrt(ECFieldElement z)
|
||
|
{
|
||
|
return z.Square().Equals(this) ? z : null;
|
||
|
}
|
||
|
|
||
|
private BigInteger[] LucasSequence(
|
||
|
BigInteger P,
|
||
|
BigInteger Q,
|
||
|
BigInteger k)
|
||
|
{
|
||
|
// TODO Research and apply "common-multiplicand multiplication here"
|
||
|
|
||
|
int n = k.BitLength;
|
||
|
int s = k.GetLowestSetBit();
|
||
|
|
||
|
Debug.Assert(k.TestBit(s));
|
||
|
|
||
|
BigInteger Uh = BigInteger.One;
|
||
|
BigInteger Vl = BigInteger.Two;
|
||
|
BigInteger Vh = P;
|
||
|
BigInteger Ql = BigInteger.One;
|
||
|
BigInteger Qh = BigInteger.One;
|
||
|
|
||
|
for (int j = n - 1; j >= s + 1; --j)
|
||
|
{
|
||
|
Ql = ModMult(Ql, Qh);
|
||
|
|
||
|
if (k.TestBit(j))
|
||
|
{
|
||
|
Qh = ModMult(Ql, Q);
|
||
|
Uh = ModMult(Uh, Vh);
|
||
|
Vl = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
|
||
|
Vh = ModReduce(Vh.Multiply(Vh).Subtract(Qh.ShiftLeft(1)));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Qh = Ql;
|
||
|
Uh = ModReduce(Uh.Multiply(Vl).Subtract(Ql));
|
||
|
Vh = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
|
||
|
Vl = ModReduce(Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ql = ModMult(Ql, Qh);
|
||
|
Qh = ModMult(Ql, Q);
|
||
|
Uh = ModReduce(Uh.Multiply(Vl).Subtract(Ql));
|
||
|
Vl = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
|
||
|
Ql = ModMult(Ql, Qh);
|
||
|
|
||
|
for (int j = 1; j <= s; ++j)
|
||
|
{
|
||
|
Uh = ModMult(Uh, Vl);
|
||
|
Vl = ModReduce(Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)));
|
||
|
Ql = ModMult(Ql, Ql);
|
||
|
}
|
||
|
|
||
|
return new BigInteger[] { Uh, Vl };
|
||
|
}
|
||
|
|
||
|
protected virtual BigInteger ModAdd(BigInteger x1, BigInteger x2)
|
||
|
{
|
||
|
BigInteger x3 = x1.Add(x2);
|
||
|
if (x3.CompareTo(q) >= 0)
|
||
|
{
|
||
|
x3 = x3.Subtract(q);
|
||
|
}
|
||
|
return x3;
|
||
|
}
|
||
|
|
||
|
protected virtual BigInteger ModDouble(BigInteger x)
|
||
|
{
|
||
|
BigInteger _2x = x.ShiftLeft(1);
|
||
|
if (_2x.CompareTo(q) >= 0)
|
||
|
{
|
||
|
_2x = _2x.Subtract(q);
|
||
|
}
|
||
|
return _2x;
|
||
|
}
|
||
|
|
||
|
protected virtual BigInteger ModHalf(BigInteger x)
|
||
|
{
|
||
|
if (x.TestBit(0))
|
||
|
{
|
||
|
x = q.Add(x);
|
||
|
}
|
||
|
return x.ShiftRight(1);
|
||
|
}
|
||
|
|
||
|
protected virtual BigInteger ModHalfAbs(BigInteger x)
|
||
|
{
|
||
|
if (x.TestBit(0))
|
||
|
{
|
||
|
x = q.Subtract(x);
|
||
|
}
|
||
|
return x.ShiftRight(1);
|
||
|
}
|
||
|
|
||
|
protected virtual BigInteger ModInverse(BigInteger x)
|
||
|
{
|
||
|
return BigIntegers.ModOddInverse(q, x);
|
||
|
}
|
||
|
|
||
|
protected virtual BigInteger ModMult(BigInteger x1, BigInteger x2)
|
||
|
{
|
||
|
return ModReduce(x1.Multiply(x2));
|
||
|
}
|
||
|
|
||
|
protected virtual BigInteger ModReduce(BigInteger x)
|
||
|
{
|
||
|
if (r == null)
|
||
|
{
|
||
|
x = x.Mod(q);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bool negative = x.SignValue < 0;
|
||
|
if (negative)
|
||
|
{
|
||
|
x = x.Abs();
|
||
|
}
|
||
|
int qLen = q.BitLength;
|
||
|
if (r.SignValue > 0)
|
||
|
{
|
||
|
BigInteger qMod = BigInteger.One.ShiftLeft(qLen);
|
||
|
bool rIsOne = r.Equals(BigInteger.One);
|
||
|
while (x.BitLength > (qLen + 1))
|
||
|
{
|
||
|
BigInteger u = x.ShiftRight(qLen);
|
||
|
BigInteger v = x.Remainder(qMod);
|
||
|
if (!rIsOne)
|
||
|
{
|
||
|
u = u.Multiply(r);
|
||
|
}
|
||
|
x = u.Add(v);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int d = ((qLen - 1) & 31) + 1;
|
||
|
BigInteger mu = r.Negate();
|
||
|
BigInteger u = mu.Multiply(x.ShiftRight(qLen - d));
|
||
|
BigInteger quot = u.ShiftRight(qLen + d);
|
||
|
BigInteger v = quot.Multiply(q);
|
||
|
BigInteger bk1 = BigInteger.One.ShiftLeft(qLen + d);
|
||
|
v = v.Remainder(bk1);
|
||
|
x = x.Remainder(bk1);
|
||
|
x = x.Subtract(v);
|
||
|
if (x.SignValue < 0)
|
||
|
{
|
||
|
x = x.Add(bk1);
|
||
|
}
|
||
|
}
|
||
|
while (x.CompareTo(q) >= 0)
|
||
|
{
|
||
|
x = x.Subtract(q);
|
||
|
}
|
||
|
if (negative && x.SignValue != 0)
|
||
|
{
|
||
|
x = q.Subtract(x);
|
||
|
}
|
||
|
}
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
protected virtual BigInteger ModSubtract(BigInteger x1, BigInteger x2)
|
||
|
{
|
||
|
BigInteger x3 = x1.Subtract(x2);
|
||
|
if (x3.SignValue < 0)
|
||
|
{
|
||
|
x3 = x3.Add(q);
|
||
|
}
|
||
|
return x3;
|
||
|
}
|
||
|
|
||
|
public override bool Equals(
|
||
|
object obj)
|
||
|
{
|
||
|
if (obj == this)
|
||
|
return true;
|
||
|
|
||
|
FpFieldElement other = obj as FpFieldElement;
|
||
|
|
||
|
if (other == null)
|
||
|
return false;
|
||
|
|
||
|
return Equals(other);
|
||
|
}
|
||
|
|
||
|
public virtual bool Equals(
|
||
|
FpFieldElement other)
|
||
|
{
|
||
|
return q.Equals(other.q) && base.Equals(other);
|
||
|
}
|
||
|
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
return q.GetHashCode() ^ base.GetHashCode();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public abstract class AbstractF2mFieldElement
|
||
|
: ECFieldElement
|
||
|
{
|
||
|
public virtual ECFieldElement HalfTrace()
|
||
|
{
|
||
|
int m = FieldSize;
|
||
|
if ((m & 1) == 0)
|
||
|
throw new InvalidOperationException("Half-trace only defined for odd m");
|
||
|
|
||
|
//ECFieldElement ht = this;
|
||
|
//for (int i = 1; i < m; i += 2)
|
||
|
//{
|
||
|
// ht = ht.SquarePow(2).Add(this);
|
||
|
//}
|
||
|
|
||
|
int n = (m + 1) >> 1;
|
||
|
int k = 31 - Integers.NumberOfLeadingZeros(n);
|
||
|
int nk = 1;
|
||
|
|
||
|
ECFieldElement ht = this;
|
||
|
while (k > 0)
|
||
|
{
|
||
|
ht = ht.SquarePow(nk << 1).Add(ht);
|
||
|
nk = n >> --k;
|
||
|
if (0 != (nk & 1))
|
||
|
{
|
||
|
ht = ht.SquarePow(2).Add(this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ht;
|
||
|
}
|
||
|
|
||
|
public virtual bool HasFastTrace
|
||
|
{
|
||
|
get { return false; }
|
||
|
}
|
||
|
|
||
|
public virtual int Trace()
|
||
|
{
|
||
|
int m = FieldSize;
|
||
|
|
||
|
//ECFieldElement tr = this;
|
||
|
//for (int i = 1; i < m; ++i)
|
||
|
//{
|
||
|
// tr = tr.Square().Add(this);
|
||
|
//}
|
||
|
|
||
|
int k = 31 - Integers.NumberOfLeadingZeros(m);
|
||
|
int mk = 1;
|
||
|
|
||
|
ECFieldElement tr = this;
|
||
|
while (k > 0)
|
||
|
{
|
||
|
tr = tr.SquarePow(mk).Add(tr);
|
||
|
mk = m >> --k;
|
||
|
if (0 != (mk & 1))
|
||
|
{
|
||
|
tr = tr.Square().Add(this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (tr.IsZero)
|
||
|
return 0;
|
||
|
if (tr.IsOne)
|
||
|
return 1;
|
||
|
throw new InvalidOperationException("Internal error in trace calculation");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Class representing the Elements of the finite field
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB)
|
||
|
* representation. Both trinomial (Tpb) and pentanomial (Ppb) polynomial
|
||
|
* basis representations are supported. Gaussian normal basis (GNB)
|
||
|
* representation is not supported.
|
||
|
*/
|
||
|
public class F2mFieldElement
|
||
|
: AbstractF2mFieldElement
|
||
|
{
|
||
|
/**
|
||
|
* Indicates gaussian normal basis representation (GNB). Number chosen
|
||
|
* according to X9.62. GNB is not implemented at present.
|
||
|
*/
|
||
|
public const int Gnb = 1;
|
||
|
|
||
|
/**
|
||
|
* Indicates trinomial basis representation (Tpb). Number chosen
|
||
|
* according to X9.62.
|
||
|
*/
|
||
|
public const int Tpb = 2;
|
||
|
|
||
|
/**
|
||
|
* Indicates pentanomial basis representation (Ppb). Number chosen
|
||
|
* according to X9.62.
|
||
|
*/
|
||
|
public const int Ppb = 3;
|
||
|
|
||
|
/**
|
||
|
* Tpb or Ppb.
|
||
|
*/
|
||
|
private int representation;
|
||
|
|
||
|
/**
|
||
|
* The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
|
||
|
*/
|
||
|
private int m;
|
||
|
|
||
|
private int[] ks;
|
||
|
|
||
|
/**
|
||
|
* The <code>LongArray</code> holding the bits.
|
||
|
*/
|
||
|
internal LongArray x;
|
||
|
|
||
|
/**
|
||
|
* Constructor for 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 x The BigInteger representing the value of the field element.
|
||
|
*/
|
||
|
|
||
|
public F2mFieldElement(
|
||
|
int m,
|
||
|
int k1,
|
||
|
int k2,
|
||
|
int k3,
|
||
|
BigInteger x)
|
||
|
{
|
||
|
if (x == null || x.SignValue < 0 || x.BitLength > m)
|
||
|
throw new ArgumentException("value invalid in F2m field element", "x");
|
||
|
|
||
|
if ((k2 == 0) && (k3 == 0))
|
||
|
{
|
||
|
this.representation = Tpb;
|
||
|
this.ks = new int[] { k1 };
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (k2 >= k3)
|
||
|
throw new ArgumentException("k2 must be smaller than k3");
|
||
|
if (k2 <= 0)
|
||
|
throw new ArgumentException("k2 must be larger than 0");
|
||
|
|
||
|
this.representation = Ppb;
|
||
|
this.ks = new int[] { k1, k2, k3 };
|
||
|
}
|
||
|
|
||
|
this.m = m;
|
||
|
this.x = new LongArray(x);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Constructor for 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 x The BigInteger representing the value of the field element.
|
||
|
*/
|
||
|
|
||
|
public F2mFieldElement(
|
||
|
int m,
|
||
|
int k,
|
||
|
BigInteger x)
|
||
|
: this(m, k, 0, 0, x)
|
||
|
{
|
||
|
// Set k1 to k, and set k2 and k3 to 0
|
||
|
}
|
||
|
|
||
|
internal F2mFieldElement(int m, int[] ks, LongArray x)
|
||
|
{
|
||
|
this.m = m;
|
||
|
this.representation = (ks.Length == 1) ? Tpb : Ppb;
|
||
|
this.ks = ks;
|
||
|
this.x = x;
|
||
|
}
|
||
|
|
||
|
public override int BitLength
|
||
|
{
|
||
|
get { return x.Degree(); }
|
||
|
}
|
||
|
|
||
|
public override bool IsOne
|
||
|
{
|
||
|
get { return x.IsOne(); }
|
||
|
}
|
||
|
|
||
|
public override bool IsZero
|
||
|
{
|
||
|
get { return x.IsZero(); }
|
||
|
}
|
||
|
|
||
|
public override bool TestBitZero()
|
||
|
{
|
||
|
return x.TestBitZero();
|
||
|
}
|
||
|
|
||
|
public override BigInteger ToBigInteger()
|
||
|
{
|
||
|
return x.ToBigInteger();
|
||
|
}
|
||
|
|
||
|
public override string FieldName
|
||
|
{
|
||
|
get { return "F2m"; }
|
||
|
}
|
||
|
|
||
|
public override int FieldSize
|
||
|
{
|
||
|
get { return m; }
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks, if the ECFieldElements <code>a</code> and <code>b</code>
|
||
|
* are elements of the same field <code>F<sub>2<sup>m</sup></sub></code>
|
||
|
* (having the same representation).
|
||
|
* @param a field element.
|
||
|
* @param b field element to be compared.
|
||
|
* @throws ArgumentException if <code>a</code> and <code>b</code>
|
||
|
* are not elements of the same field
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code> (having the same
|
||
|
* representation).
|
||
|
*/
|
||
|
public static void CheckFieldElements(
|
||
|
ECFieldElement a,
|
||
|
ECFieldElement b)
|
||
|
{
|
||
|
if (!(a is F2mFieldElement) || !(b is F2mFieldElement))
|
||
|
{
|
||
|
throw new ArgumentException("Field elements are not "
|
||
|
+ "both instances of F2mFieldElement");
|
||
|
}
|
||
|
|
||
|
F2mFieldElement aF2m = (F2mFieldElement)a;
|
||
|
F2mFieldElement bF2m = (F2mFieldElement)b;
|
||
|
|
||
|
if (aF2m.representation != bF2m.representation)
|
||
|
{
|
||
|
// Should never occur
|
||
|
throw new ArgumentException("One of the F2m field elements has incorrect representation");
|
||
|
}
|
||
|
|
||
|
if ((aF2m.m != bF2m.m) || !Arrays.AreEqual(aF2m.ks, bF2m.ks))
|
||
|
{
|
||
|
throw new ArgumentException("Field elements are not elements of the same field F2m");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Add(
|
||
|
ECFieldElement b)
|
||
|
{
|
||
|
// No check performed here for performance reasons. Instead the
|
||
|
// elements involved are checked in ECPoint.F2m
|
||
|
// checkFieldElements(this, b);
|
||
|
LongArray iarrClone = this.x.Copy();
|
||
|
F2mFieldElement bF2m = (F2mFieldElement)b;
|
||
|
iarrClone.AddShiftedByWords(bF2m.x, 0);
|
||
|
return new F2mFieldElement(m, ks, iarrClone);
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement AddOne()
|
||
|
{
|
||
|
return new F2mFieldElement(m, ks, x.AddOne());
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Subtract(
|
||
|
ECFieldElement b)
|
||
|
{
|
||
|
// Addition and subtraction are the same in F2m
|
||
|
return Add(b);
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Multiply(
|
||
|
ECFieldElement b)
|
||
|
{
|
||
|
// Right-to-left comb multiplication in the LongArray
|
||
|
// Input: Binary polynomials a(z) and b(z) of degree at most m-1
|
||
|
// Output: c(z) = a(z) * b(z) mod f(z)
|
||
|
|
||
|
// No check performed here for performance reasons. Instead the
|
||
|
// elements involved are checked in ECPoint.F2m
|
||
|
// checkFieldElements(this, b);
|
||
|
return new F2mFieldElement(m, ks, x.ModMultiply(((F2mFieldElement)b).x, m, ks));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
return MultiplyPlusProduct(b, x, y);
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
LongArray ax = this.x, bx = ((F2mFieldElement)b).x, xx = ((F2mFieldElement)x).x, yx = ((F2mFieldElement)y).x;
|
||
|
|
||
|
LongArray ab = ax.Multiply(bx, m, ks);
|
||
|
LongArray xy = xx.Multiply(yx, m, ks);
|
||
|
|
||
|
if (ab == ax || ab == bx)
|
||
|
{
|
||
|
ab = (LongArray)ab.Copy();
|
||
|
}
|
||
|
|
||
|
ab.AddShiftedByWords(xy, 0);
|
||
|
ab.Reduce(m, ks);
|
||
|
|
||
|
return new F2mFieldElement(m, ks, ab);
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Divide(
|
||
|
ECFieldElement b)
|
||
|
{
|
||
|
// There may be more efficient implementations
|
||
|
ECFieldElement bInv = b.Invert();
|
||
|
return Multiply(bInv);
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Negate()
|
||
|
{
|
||
|
// -x == x holds for all x in F2m
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Square()
|
||
|
{
|
||
|
return new F2mFieldElement(m, ks, x.ModSquare(m, ks));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
return SquarePlusProduct(x, y);
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
|
||
|
{
|
||
|
LongArray ax = this.x, xx = ((F2mFieldElement)x).x, yx = ((F2mFieldElement)y).x;
|
||
|
|
||
|
LongArray aa = ax.Square(m, ks);
|
||
|
LongArray xy = xx.Multiply(yx, m, ks);
|
||
|
|
||
|
if (aa == ax)
|
||
|
{
|
||
|
aa = (LongArray)aa.Copy();
|
||
|
}
|
||
|
|
||
|
aa.AddShiftedByWords(xy, 0);
|
||
|
aa.Reduce(m, ks);
|
||
|
|
||
|
return new F2mFieldElement(m, ks, aa);
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement SquarePow(int pow)
|
||
|
{
|
||
|
return pow < 1 ? this : new F2mFieldElement(m, ks, x.ModSquareN(pow, m, ks));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Invert()
|
||
|
{
|
||
|
return new F2mFieldElement(this.m, this.ks, this.x.ModInverse(m, ks));
|
||
|
}
|
||
|
|
||
|
public override ECFieldElement Sqrt()
|
||
|
{
|
||
|
return (x.IsZero() || x.IsOne()) ? this : SquarePow(m - 1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return the representation of the field
|
||
|
* <code>F<sub>2<sup>m</sup></sub></code>, either of
|
||
|
* {@link F2mFieldElement.Tpb} (trinomial
|
||
|
* basis representation) or
|
||
|
* {@link F2mFieldElement.Ppb} (pentanomial
|
||
|
* basis representation).
|
||
|
*/
|
||
|
public int Representation
|
||
|
{
|
||
|
get { return this.representation; }
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return the degree <code>m</code> of the reduction polynomial
|
||
|
* <code>f(z)</code>.
|
||
|
*/
|
||
|
public int M
|
||
|
{
|
||
|
get { return this.m; }
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return 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/>
|
||
|
*/
|
||
|
public int K1
|
||
|
{
|
||
|
get { return this.ks[0]; }
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return Tpb: Always returns <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/>
|
||
|
*/
|
||
|
public int K2
|
||
|
{
|
||
|
get { return this.ks.Length >= 2 ? this.ks[1] : 0; }
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return 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/>
|
||
|
*/
|
||
|
public int K3
|
||
|
{
|
||
|
get { return this.ks.Length >= 3 ? this.ks[2] : 0; }
|
||
|
}
|
||
|
|
||
|
public override bool Equals(
|
||
|
object obj)
|
||
|
{
|
||
|
if (obj == this)
|
||
|
return true;
|
||
|
|
||
|
F2mFieldElement other = obj as F2mFieldElement;
|
||
|
|
||
|
if (other == null)
|
||
|
return false;
|
||
|
|
||
|
return Equals(other);
|
||
|
}
|
||
|
|
||
|
public virtual bool Equals(
|
||
|
F2mFieldElement other)
|
||
|
{
|
||
|
return ((this.m == other.m)
|
||
|
&& (this.representation == other.representation)
|
||
|
&& Arrays.AreEqual(this.ks, other.ks)
|
||
|
&& (this.x.Equals(other.x)));
|
||
|
}
|
||
|
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
return x.GetHashCode() ^ m ^ Arrays.GetHashCode(ks);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#pragma warning restore
|
||
|
#endif
|