ln.crypto.ec/ln.crypto.ec/EllipticCurve.cs

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();
}
}