diff --git a/Crypto.csproj b/Crypto.csproj index 08be3e4..946c98f 100644 --- a/Crypto.csproj +++ b/Crypto.csproj @@ -32,8 +32,9 @@ - + + @@ -47,6 +48,10 @@ {97CA3CA9-98B3-4492-B072-D7A5995B68E9} sharp.extensions + + {56733EC1-7D97-48D0-AA4C-98EA624A5A21} + sharp.contracts + \ No newline at end of file diff --git a/EC/CurvePoint.cs b/EC/CurvePoint.cs index 62b8974..d32c28f 100644 --- a/EC/CurvePoint.cs +++ b/EC/CurvePoint.cs @@ -1,4 +1,4 @@ -using System; +using System; using BigInt; using System.Text; using System.Runtime.CompilerServices; @@ -7,56 +7,115 @@ namespace Crypto.EC { public class CurvePoint { - public CurvePoint(EllipticCurve curve,UInteger x,UInteger y){ + public static readonly CurvePoint INFINITY = new CurvePoint(); + + public CurvePoint(EllipticCurve curve,Integer x,Integer y){ Curve = curve; X = x; Y = y; } - public string toHexString(){ + private CurvePoint(){ + this.Curve = null; + this.X = 0; + this.Y = 0; + } + + public string toHexString() + { StringBuilder sb = new StringBuilder(); - sb.Append(X.toHexString()); + sb.Append(((UInteger)X).toHexString()); sb.Append("."); - sb.Append(Y.toHexString()); + sb.Append(((UInteger)Y).toHexString()); return sb.ToString(); } + public override string ToString() + { + if ((object)this == (object)INFINITY){ + return String.Format("[CurvePoint INFINITY]"); + } + return String.Format("[CurvePoint X={0} Y={1}]",X.ToString(),Y.ToString()); + } + public EllipticCurve Curve { get; private set; } - public UInteger X { get; private set; } - public UInteger Y { get; private set; } + public Integer X { get; private set; } + public Integer Y { get; private set; } public bool isOnCurve(){ return this.Curve.isOnCurve(this); } + public bool isInfinity(){ + return ((object)this == (object)INFINITY); + } + + public CurvePoint Negated(){ + return new CurvePoint(Curve, X, Curve.Fp.AdditiveInverse(Y)); + } + public static CurvePoint operator +(CurvePoint p1, CurvePoint p2) { - return p1.Curve.Add(p1,p2); + if ((object)p1 == (object)INFINITY){ + return p2; + } + if ((object)p2 == (object)INFINITY){ + return p1; + } + + return p1.Curve.Add(p1, p2); } - public static CurvePoint operator *(CurvePoint p1, UInteger n) + + public static CurvePoint operator -(CurvePoint p1, CurvePoint p2) { - if (p1.Y == UInteger.ZERO){ - throw new NotImplementedException("Eternity point not implemented"); + if ((object)p1 == (object)INFINITY){ + return p2; + } + if ((object)p2 == (object)INFINITY){ + return p1; + } + return p1.Curve.Add(p1, p2.Negated()); + } + + public static CurvePoint operator *(CurvePoint p1, Integer n) + { + if ((object)p1 == (object)INFINITY){ + return INFINITY; + } + + if (p1.Y == Integer.ZERO){ + return INFINITY; + } + + if (n.isZero()){ + throw new NotImplementedException("CurevPoint * 0"); } CurvePoint result = null; CurvePoint p = p1; int i; + int bitwidth = n.Log2(); - for (i = 0; i < 256; i++) + if (bitwidth < 0){ + bitwidth = -bitwidth; + } + + for (i = 0; i < bitwidth; i++) { - if (n[i]){ - result = p; + if (n[i]) break; - } + p += p; } - for (; i < 256; i++) + + result = p; + + for (i++; i <= bitwidth; i++) { p += p; if (n[i]){ - result += p; + result = p + result; } } diff --git a/EC/EllipticCurve.cs b/EC/EllipticCurve.cs index 55c5636..8336e14 100644 --- a/EC/EllipticCurve.cs +++ b/EC/EllipticCurve.cs @@ -7,15 +7,15 @@ namespace Crypto.EC { public class EllipticCurve { - public UInteger a { get; private set; } - public UInteger b { get; private set; } - public UInteger n { get; private set; } + public Integer a { get; private set; } + public Integer b { get; private set; } + public Integer n { get; private set; } public int h { get; private set; } public CurvePoint G { get; private set; } public IntField Fp { get; private set; } - public EllipticCurve(UInteger p,UInteger a,UInteger b,UInteger xG,UInteger yG,UInteger n,int h) + public EllipticCurve(Integer p,Integer a,Integer b,Integer xG,Integer yG,Integer n,int h) { this.Fp = new IntField(p); this.a = a; @@ -29,38 +29,38 @@ namespace Crypto.EC } } - public UInteger Y2(UInteger x){ + public Integer Y2(Integer x){ - UInteger yy = x; + Integer yy = x; - Console.WriteLine("Y(x): X = {0}",x.toHexString()); - Console.WriteLine("Y(x): x^2 = {0}",yy.Pow(2).toHexString()); + //Console.WriteLine("Y(x): X = {0}",x.toHexString()); + //Console.WriteLine("Y(x): x^2 = {0}",yy.Pow(2).toHexString()); yy = yy.Pow(3); - Console.WriteLine("Y(x): x^3 = {0}",yy.toHexString()); + //Console.WriteLine("Y(x): x^3 = {0}",yy.toHexString()); yy += (a * x); - Console.WriteLine("Y(x): x^3 + ax = {0}",yy.toHexString()); + //Console.WriteLine("Y(x): x^3 + ax = {0}",yy.toHexString()); yy += b; - Console.WriteLine("Y(x) x^3 + ax + b = {0}",yy.toHexString()); + //Console.WriteLine("Y(x) x^3 + ax + b = {0}",yy.toHexString()); - yy %= this.Fp.FieldModulo; + yy %= (Integer)this.Fp.FieldModulo; - Console.WriteLine("Y(x) mod p = {0}",yy.toHexString()); + //Console.WriteLine("Y(x) mod p = {0}",yy.toHexString()); return yy; } public bool isOnCurve(CurvePoint p){ - UInteger py2 = this.Fp.Fit(p.Y.Pow(2)); - UInteger pcy2 = Y2(p.X); + Integer py2 = this.Fp.Fit(p.Y.Pow(2)); + Integer pcy2 = Y2(p.X); - Console.WriteLine("CHECK A: {0}",py2.toHexString()); - Console.WriteLine("CHECK B: {0}",pcy2.toHexString()); + //Console.WriteLine("CHECK A: {0}",py2.toHexString()); + //Console.WriteLine("CHECK B: {0}",pcy2.toHexString()); return (py2 == pcy2); } @@ -69,57 +69,39 @@ namespace Crypto.EC { if (((object)p1 == null) || ((object)p2 == null)) { - throw new ArgumentException("CurvePoints to be added must not be null"); + throw new ArgumentException("SignedCurvePoints to be added must not be null"); } if (p1.Curve != p2.Curve) { - throw new ArgumentException("Curvepoints to be added must belong to the same curve!"); + throw new ArgumentException("SignedCurvePoints to be added must belong to the same curve!"); } - if (p1 == p2) - { -// UInteger inv2y = Euclid.inverse(this.Fp.Fit(p1.Y << 1),this.Fp.FieldModulo); - UInteger inv2y = Euclid.inverse((p1.Y * 2),this.Fp.FieldModulo); - UInteger s = Fp.Fit(p1.X.Pow(3)) * 3; - s += p1.Curve.a; - s *= inv2y; - - //(((p1.X.Pow(2) * 3) + p1.Curve.a) / (p1.Y << 1)); - - UInteger xR = (s.Pow(2) - (p1.X * 2)); - UInteger yR = ((s * (p1.X - xR)) - p1.Y); - - xR = this.Fp.Fit(xR); - yR = this.Fp.Fit(yR); - - return new CurvePoint(p1.Curve, xR, yR); + if ((p1 != p2) && (p1.X == p2.X)){ + return CurvePoint.INFINITY; } - if (p1.X == p2.X) - { - throw new NotImplementedException("Eternity point not implemented"); - } - else - { - UInteger s = (((p1.Y - p2.Y) / (p1.X - p2.X))); - UInteger xR = (s.Pow(2) - p1.X - p2.X); - UInteger yR = ((s * (p1.X - xR)) - p1.Y); + Integer lambda,divlambda; - xR = this.Fp.Fit(xR); - yR = this.Fp.Fit(yR); - - return new CurvePoint(p1.Curve, xR, yR); + if (p1 == p2){ + lambda = Fp.Fit(3 * p1.X.Pow(2) + a); + divlambda = Fp.Fit(2 * p1.Y); + } else { + lambda = Fp.Fit(p2.Y - p1.Y); + divlambda = Fp.Fit(p2.X - p1.X); } - throw new NotImplementedException("Point addition not yet implemented"); + lambda = lambda * Euclid.inverse(divlambda, Fp.FieldModulo); + + Integer xR = (lambda.Pow(2) - p1.X - p2.X); + Integer yR = (lambda * (p1.X - xR)) - p1.Y; + + xR = Fp.Fit(xR); + yR = Fp.Fit(yR); + + return new CurvePoint(this, xR, yR); } -/* public CurvePoint getPoint(T x){ - x = new T(x, this.Fp); - return new CurvePoint(this,x,Y(x)); - } -*/ public override string ToString() { StringBuilder sb = new StringBuilder(); @@ -134,20 +116,20 @@ namespace Crypto.EC } public static EllipticCurve createSecp256k1(){ - UInteger p = (UInteger.ONE << 256); - p -= UInteger.ONE; - p -= (UInteger.ONE << 32); - p -= (UInteger.ONE << 9); - p -= (UInteger.ONE << 8); - p -= (UInteger.ONE << 7); - p -= (UInteger.ONE << 6); - p -= (UInteger.ONE << 4); + Integer p = (Integer.ONE << 256); + p -= Integer.ONE; + p -= (Integer.ONE << 32); + p -= (Integer.ONE << 9); + p -= (Integer.ONE << 8); + p -= (Integer.ONE << 7); + p -= (Integer.ONE << 6); + p -= (Integer.ONE << 4); - UInteger xG = UInteger.fromHexString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"); - UInteger yG = UInteger.fromHexString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"); + Integer xG = Integer.fromHexString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"); + Integer yG = Integer.fromHexString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"); - UInteger n = UInteger.fromHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); - return new EllipticCurve(p, new UInteger(0), new UInteger(7), xG, yG, n, 1); + Integer n = Integer.fromHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); + return new EllipticCurve(p, new Integer(0), new Integer(7), xG, yG, n, 1); } } } diff --git a/EC/ProjectiveCurvePoint.cs b/EC/ProjectiveCurvePoint.cs new file mode 100644 index 0000000..160ffac --- /dev/null +++ b/EC/ProjectiveCurvePoint.cs @@ -0,0 +1,198 @@ +using System; +using BigInt; +using System.CodeDom; +using sharp.contracts; +namespace Crypto.EC +{ + public class ProjectiveCurvePoint + { + public static readonly ProjectiveCurvePoint INFINITY = new ProjectiveCurvePoint(null,1,0,0); + + public Integer X { get; set; } + public Integer Y { get; set; } + public Integer Z { get; set; } + + public EllipticCurve Curve { get; private set; } + + public ProjectiveCurvePoint(CurvePoint p) + { + this.Curve = p.Curve; + this.X = p.X; + this.Y = p.Y; + this.Z = 1; + } + + public ProjectiveCurvePoint(EllipticCurve curve,Integer x,Integer y,Integer z) + { + this.Curve = curve; + this.X = x; + this.Y = y; + this.Z = z; + } + + public CurvePoint toCurvePoint(){ + if (Z.isZero()){ + return CurvePoint.INFINITY; + } + Integer iz = Euclid.inverse(Z, Curve.Fp.FieldModulo); + + Integer nx = Curve.Fp.Fit(X * iz); + Integer ny = Curve.Fp.Fit(Y * iz); + + return new CurvePoint(Curve, nx, ny); + } + + public override bool Equals(object obj) + { + ProjectiveCurvePoint p = INFINITY; + + return new BooleanConditional() + .requires(obj != null) + .requires(GetType().IsInstanceOfType(obj)) + .does( () => { p = (ProjectiveCurvePoint)obj; } ) + .requires(this.Curve == p.Curve) + .requires(this.X == p.X) + .requires(this.Y == p.Y) + .requires(this.Z == p.Z) + .isSuccess(); + } + + public ProjectiveCurvePoint doubled() + { + Integer s = Curve.Fp.Fit(Y * Z); + Integer B = Curve.Fp.Fit(X * Y * s); + Integer w = Curve.Fp.Fit( + (Curve.a * Z.Pow(2)) + + (X.Pow(2) * 3) + ); + Integer h = Curve.Fp.Fit(w.Pow(2) - (B * 8)); + + Integer xd = h * s * 2; + Integer yd = ( + (w * ((B * 4) - h)) - + (Y.Pow(2) * s.Pow(2) * 8) + ); + Integer zd = s.Pow(3) * 8; + + xd = Curve.Fp.Fit(xd); + yd = Curve.Fp.Fit(yd); + zd = Curve.Fp.Fit(zd); + + return new ProjectiveCurvePoint(Curve,xd,yd,zd); + } + + public ProjectiveCurvePoint add(ProjectiveCurvePoint p){ + Integer u = Curve.Fp.Fit( (p.Y * Z) - (Y * p.Z) ); + Integer v = Curve.Fp.Fit( (p.X * Z) - (X * p.Z) ); + Integer A = Curve.Fp.Fit( + (Z * p.Z * u.Pow(2)) - v.Pow(3) - (v.Pow(2) * X * p.Z * 2) + ); + + Integer xd = v * A; + Integer yd = ( + (u * ((X * p.Z * v.Pow(2)) - A)) - + (v.Pow(3) * Y * p.Z) + ); + Integer zd = Z * p.Z * v.Pow(3); + + xd = Curve.Fp.Fit(xd); + yd = Curve.Fp.Fit(yd); + zd = Curve.Fp.Fit(zd); + + if (zd == 0){ + return INFINITY; + } + + return new ProjectiveCurvePoint(Curve, xd, yd, zd); + } + + public ProjectiveCurvePoint Negated(){ + return new ProjectiveCurvePoint(Curve, X, Curve.Fp.AdditiveInverse(Y), Z); + } + + + public override string ToString() + { + return string.Format("[ProjectiveCurvePoint: Curve=... X={1} Y={2} Z={3}]", Curve,X,Y,Z); + } + + public static implicit operator ProjectiveCurvePoint(CurvePoint p){ + return new ProjectiveCurvePoint(p); + } + + public static ProjectiveCurvePoint operator +(ProjectiveCurvePoint p1, ProjectiveCurvePoint p2) + { + if ((object)p1 == INFINITY){ + return p2; + } else if ((object)p2 == INFINITY){ + return p1; + } else if (p1.Equals(p2)){ + return p1.doubled(); + } else { + return p1.add(p2); + } + } + public static ProjectiveCurvePoint operator -(ProjectiveCurvePoint p1, ProjectiveCurvePoint p2) + { + if ((object)p1 == INFINITY) + { + return p2; + } + else if ((object)p2 == INFINITY) + { + return p1; + } + return p1 + p2.Negated(); + } + public static ProjectiveCurvePoint operator *(ProjectiveCurvePoint p1, Integer n) + { + if ((object)p1 == (object)INFINITY) + { + return INFINITY; + } + + if (p1.Y == Integer.ZERO) + { + return INFINITY; + } + + if (n.isZero()) + { + throw new NotImplementedException("CurevPoint * 0"); + } + + ProjectiveCurvePoint result = null; + ProjectiveCurvePoint p = p1; + + int i; + int bitwidth = n.Log2(); + + if (bitwidth < 0) + { + bitwidth = -bitwidth; + } + + for (i = 0; i < bitwidth; i++) + { + if (n[i]) + break; + + p += p; + } + + result = p; + + for (i++; i <= bitwidth; i++) + { + p += p; + if (n[i]) + { + result = p + result; + } + } + + return result; + } + + } +}