147 lines
4.1 KiB
C#
147 lines
4.1 KiB
C#
using System;
|
|
using System.Text;
|
|
using ln.crypto.ec;
|
|
using System.Security.Cryptography;
|
|
using System.Numerics;
|
|
using System.Globalization;
|
|
|
|
namespace Crypto.EC
|
|
{
|
|
public class EllipticCurve
|
|
{
|
|
public BigInteger a { get; private set; }
|
|
public BigInteger b { get; private set; }
|
|
public BigInteger n { get; private set; }
|
|
public int h { get; private set; }
|
|
|
|
public CurvePoint G { get; private set; }
|
|
public Field Fp { get; private set; }
|
|
|
|
public EllipticCurve(BigInteger p,BigInteger a,BigInteger b,BigInteger xG,BigInteger yG,BigInteger n,int h)
|
|
{
|
|
this.Fp = new Field(p);
|
|
this.a = a;
|
|
this.b = b;
|
|
this.n = n;
|
|
this.h = h;
|
|
this.G = new CurvePoint(this, xG, yG);
|
|
|
|
if (!isOnCurve(this.G)){
|
|
throw new ArgumentException("G is not part of the curve");
|
|
}
|
|
}
|
|
|
|
public BigInteger Y2(BigInteger x)
|
|
{
|
|
BigInteger yy = BigInteger.ModPow(x, 3, Fp.FieldModulo);
|
|
yy += (a * x);
|
|
yy += b;
|
|
yy %= this.Fp.FieldModulo;
|
|
return yy;
|
|
}
|
|
|
|
public bool isOnCurve(CurvePoint p){
|
|
BigInteger py2 = BigInteger.ModPow(p.Y, 2, this.Fp.FieldModulo);
|
|
BigInteger pcy2 = Y2(p.X);
|
|
|
|
//Console.WriteLine("CHECK A: {0}",py2.toHexString());
|
|
//Console.WriteLine("CHECK B: {0}",pcy2.toHexString());
|
|
|
|
return (py2 == pcy2);
|
|
}
|
|
|
|
public CurvePoint Add(CurvePoint p1, CurvePoint p2)
|
|
{
|
|
if ((p1 is null) || (p2 is null))
|
|
{
|
|
throw new ArgumentException("SignedCurvePoints to be added must not be null");
|
|
}
|
|
|
|
if (p1.Curve != p2.Curve)
|
|
{
|
|
throw new ArgumentException("SignedCurvePoints to be added must belong to the same curve!");
|
|
}
|
|
|
|
if ((p1 != p2) && (p1.X == p2.X)){
|
|
return CurvePoint.INFINITY;
|
|
}
|
|
|
|
BigInteger lambda,divlambda;
|
|
|
|
if (p1 == p2){
|
|
lambda = Fp.Fit(3 * BigInteger.ModPow(p1.X, 2, Fp.FieldModulo) + a);
|
|
divlambda = Fp.Fit(2 * p1.Y);
|
|
} else {
|
|
lambda = Fp.Fit(p2.Y - p1.Y);
|
|
divlambda = Fp.Fit(p2.X - p1.X);
|
|
}
|
|
|
|
|
|
|
|
lambda = lambda * Euclid.inverse(divlambda, Fp.FieldModulo);
|
|
|
|
BigInteger xR = (BigInteger.ModPow(lambda, 2, Fp.FieldModulo) - p1.X - p2.X);
|
|
BigInteger yR = (lambda * (p1.X - xR)) - p1.Y;
|
|
|
|
xR = Fp.Fit(xR);
|
|
yR = Fp.Fit(yR);
|
|
|
|
return new CurvePoint(this, xR, yR);
|
|
}
|
|
|
|
public CurvePoint HashToPoint(byte[] message)
|
|
{
|
|
byte[] hash = SHA256.Create().ComputeHash(message);
|
|
BigInteger bi = new BigInteger(hash) * 16;
|
|
return MapToCurve(bi);
|
|
}
|
|
|
|
public BigInteger[] HashToField(byte[] message, int n)
|
|
{
|
|
byte[] hash = SHA256.Create().ComputeHash(message);
|
|
BigInteger[] results = new BigInteger[n];
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
hash = SHA256.Create().ComputeHash(hash);
|
|
results[i] = Fp.Fit(new BigInteger(hash));
|
|
}
|
|
return results;
|
|
}
|
|
public BigInteger HashToField(byte[] message) => HashToField(message, 1)[0];
|
|
|
|
public CurvePoint MapToCurve(BigInteger u) => G * Fp.Fit(u);
|
|
|
|
public override string ToString()
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.AppendFormat("[EllipticCurve] Fp={0}\n",(Fp == null) ? "" : Fp.ToString());
|
|
sb.AppendFormat("[EllipticCurve] a={0}\n",a.ToString("X"));
|
|
sb.AppendFormat("[EllipticCurve] b={0}\n",b.ToString("X"));
|
|
sb.AppendFormat("[EllipticCurve] Gx={0}\n",G.X.ToString("X"));
|
|
sb.AppendFormat("[EllipticCurve] Gy={0}\n",G.Y.ToString("X"));
|
|
sb.AppendFormat("[EllipticCurve] G on curve? {0}",isOnCurve(G));
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
public static EllipticCurve createSecp256k1(){
|
|
BigInteger p = (BigInteger.One << 256);
|
|
p -= BigInteger.One;
|
|
p -= (BigInteger.One << 32);
|
|
p -= (BigInteger.One << 9);
|
|
p -= (BigInteger.One << 8);
|
|
p -= (BigInteger.One << 7);
|
|
p -= (BigInteger.One << 6);
|
|
p -= (BigInteger.One << 4);
|
|
|
|
BigInteger xG = BigInteger.Parse("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", NumberStyles.HexNumber);
|
|
BigInteger yG = BigInteger.Parse("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", NumberStyles.HexNumber);
|
|
|
|
BigInteger n = BigInteger.Parse("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", NumberStyles.HexNumber);
|
|
return new EllipticCurve(p, BigInteger.Zero, 7, xG, yG, n, 1);
|
|
}
|
|
|
|
public static readonly EllipticCurve SECP256K1 = createSecp256k1();
|
|
}
|
|
}
|