Data update
This commit is contained in:
parent
72eb4943cb
commit
4d5544505c
2347 changed files with 62432 additions and 16731 deletions
|
|
@ -0,0 +1,369 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public sealed class EllipticCurveDigitalSignatureAlgorithm
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Test parameters for elliptic curve digital signature algorithm,
|
||||
// using the short Weierstrass model: y^2 = x^3 + ax + b (mod N).
|
||||
//
|
||||
// Parameter: a, b, modulus N, base point G, order of G in the elliptic curve.
|
||||
|
||||
List<Parameter> parameters = new List<Parameter>
|
||||
{
|
||||
new Parameter(355, 671, 1073741789, new Point(13693, 10088), 1073807281),
|
||||
new Parameter(0, 7, 67096021, new Point(6580, 779), 16769911),
|
||||
new Parameter(-3, 1, 877073, new Point(0, 1), 878159),
|
||||
new Parameter(0, 14, 22651, new Point(63, 30), 151),
|
||||
new Parameter(3, 2, 5, new Point(2, 1), 5)
|
||||
};
|
||||
|
||||
// Parameters which cause failure of the algorithm for the given reasons
|
||||
// the base point is of composite order
|
||||
// new Parameter(0, 7, 67096021, new Point(2402, 6067), 33539822),
|
||||
// the given order is of composite order
|
||||
// new Parameter(0, 7, 67096021, new Point(6580, 779), 67079644),
|
||||
// the modulus is not prime (deceptive example)
|
||||
// new Parameter(0, 7, 877069, new Point(3, 97123), 877069),
|
||||
// fails if the modulus divides the discriminant
|
||||
// new Parameter(39, 387, 22651, new Point(95, 27), 22651)
|
||||
|
||||
const long f = 0x789abcde; // The message's digital signature hash which is to be verified
|
||||
const int d = 0; // Set d > 0 to simulate corrupted data
|
||||
|
||||
foreach (Parameter parameter in parameters)
|
||||
{
|
||||
EllipticCurve ellipticCurve = new EllipticCurve(parameter);
|
||||
Ecdsa(ellipticCurve, f, d);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the digital signature for a message using the hash aF with error bit aD
|
||||
private static void Ecdsa(EllipticCurve aCurve, long aF, int aD)
|
||||
{
|
||||
Point point = aCurve.Multiply(aCurve.G, aCurve.R);
|
||||
|
||||
if (aCurve.Discriminant() == 0 || aCurve.G.IsZero() || !point.IsZero() || !aCurve.Contains(aCurve.G))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid parameter in method ecdsa");
|
||||
}
|
||||
|
||||
Console.WriteLine(Environment.NewLine + "key generation");
|
||||
long s = 1 + (long)(Random() * (double)(aCurve.R - 1));
|
||||
point = aCurve.Multiply(aCurve.G, s);
|
||||
Console.WriteLine("private key s = " + s);
|
||||
aCurve.PrintPointWithPrefix(point, "public key W = sG");
|
||||
|
||||
// Find the next highest power of two minus one.
|
||||
long t = aCurve.R;
|
||||
long i = 1;
|
||||
while (i < 64)
|
||||
{
|
||||
t |= t >> (int)i;
|
||||
i <<= 1;
|
||||
}
|
||||
long f = aF;
|
||||
while (f > t)
|
||||
{
|
||||
f >>= 1;
|
||||
}
|
||||
Console.WriteLine(Environment.NewLine + "aligned hash " + $"{f:x8}");
|
||||
|
||||
Pair signature = Signature(aCurve, s, f);
|
||||
Console.WriteLine("signature c, d = " + signature.A + ", " + signature.B);
|
||||
|
||||
long d = aD;
|
||||
if (d > 0)
|
||||
{
|
||||
while (d > t)
|
||||
{
|
||||
d >>= 1;
|
||||
}
|
||||
f ^= d;
|
||||
Console.WriteLine(Environment.NewLine + "corrupted hash " + $"{f:x8}");
|
||||
}
|
||||
|
||||
Console.WriteLine(Verify(aCurve, point, f, signature) ? "Valid" : "Invalid");
|
||||
Console.WriteLine("-----------------");
|
||||
}
|
||||
|
||||
private static bool Verify(EllipticCurve aCurve, Point aPoint, long aF, Pair aSignature)
|
||||
{
|
||||
if (aSignature.A < 1 || aSignature.A >= aCurve.R || aSignature.B < 1 || aSignature.B >= aCurve.R)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLine(Environment.NewLine + "signature verification");
|
||||
long h = ExtendedGCD(aSignature.B, aCurve.R);
|
||||
long h1 = FloorMod(aF * h, aCurve.R);
|
||||
long h2 = FloorMod(aSignature.A * h, aCurve.R);
|
||||
Console.WriteLine("h1, h2 = " + h1 + ", " + h2);
|
||||
Point v = aCurve.Multiply(aCurve.G, h1);
|
||||
Point v2 = aCurve.Multiply(aPoint, h2);
|
||||
aCurve.PrintPointWithPrefix(v, "h1G");
|
||||
aCurve.PrintPointWithPrefix(v2, "h2W");
|
||||
v = aCurve.Add(v, v2);
|
||||
aCurve.PrintPointWithPrefix(v, "+ =");
|
||||
|
||||
if (v.IsZero())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
long c1 = FloorMod(v.X, aCurve.R);
|
||||
Console.WriteLine("c' = " + c1);
|
||||
return c1 == aSignature.A;
|
||||
}
|
||||
|
||||
private static Pair Signature(EllipticCurve aCurve, long aS, long aF)
|
||||
{
|
||||
long c = 0;
|
||||
long d = 0;
|
||||
long u;
|
||||
Point v;
|
||||
Console.WriteLine("Signature computation");
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
u = 1 + (long)(Random() * (double)(aCurve.R - 1));
|
||||
v = aCurve.Multiply(aCurve.G, u);
|
||||
c = FloorMod(v.X, aCurve.R);
|
||||
if (c != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
d = FloorMod(ExtendedGCD(u, aCurve.R) * FloorMod(aF + aS * c, aCurve.R), aCurve.R);
|
||||
if (d != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("one-time u = " + u);
|
||||
aCurve.PrintPointWithPrefix(v, "V = uG");
|
||||
return new Pair(c, d);
|
||||
}
|
||||
|
||||
// Return 1 / aV modulus aU
|
||||
private static long ExtendedGCD(long aV, long aU)
|
||||
{
|
||||
if (aV < 0)
|
||||
{
|
||||
aV += aU;
|
||||
}
|
||||
|
||||
long result = 0;
|
||||
long s = 1;
|
||||
while (aV != 0)
|
||||
{
|
||||
long quotient = FloorDiv(aU, aV);
|
||||
aU = FloorMod(aU, aV);
|
||||
long temp = aU; aU = aV; aV = temp;
|
||||
result -= quotient * s;
|
||||
temp = result; result = s; s = temp;
|
||||
}
|
||||
|
||||
if (aU != 1)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot inverse modulo N, gcd = " + aU);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static double Random()
|
||||
{
|
||||
return _random.NextDouble();
|
||||
}
|
||||
|
||||
// C# implementation of Java's Math.floorMod
|
||||
private static long FloorMod(long x, long y)
|
||||
{
|
||||
return ((x % y) + y) % y;
|
||||
}
|
||||
|
||||
// C# implementation of Java's Math.floorDiv
|
||||
private static long FloorDiv(long x, long y)
|
||||
{
|
||||
long r = x / y;
|
||||
if ((x ^ y) < 0 && (r * y != x))
|
||||
{
|
||||
r--;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
private class EllipticCurve
|
||||
{
|
||||
public long A { get; }
|
||||
public long B { get; }
|
||||
public long N { get; }
|
||||
public long R { get; }
|
||||
public Point G { get; }
|
||||
|
||||
public EllipticCurve(Parameter aParameter)
|
||||
{
|
||||
N = aParameter.N;
|
||||
if (N < 5 || N > MAX_MODULUS)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid value for modulus: " + N);
|
||||
}
|
||||
|
||||
A = FloorMod(aParameter.A, N);
|
||||
B = FloorMod(aParameter.B, N);
|
||||
G = aParameter.G;
|
||||
R = aParameter.R;
|
||||
|
||||
if (R < 5 || R > MAX_ORDER_G)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid value for the order of g: " + R);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Elliptic curve: y^2 = x^3 + " + A + "x + " + B + " (mod " + N + ")");
|
||||
PrintPointWithPrefix(G, "base point G");
|
||||
Console.WriteLine("order(G, E) = " + R);
|
||||
}
|
||||
|
||||
public Point Add(Point aP, Point aQ)
|
||||
{
|
||||
if (aP.IsZero())
|
||||
{
|
||||
return aQ;
|
||||
}
|
||||
if (aQ.IsZero())
|
||||
{
|
||||
return aP;
|
||||
}
|
||||
|
||||
long la;
|
||||
if (aP.X != aQ.X)
|
||||
{
|
||||
la = FloorMod((aP.Y - aQ.Y) * ExtendedGCD(aP.X - aQ.X, N), N);
|
||||
}
|
||||
else if (aP.Y == aQ.Y && aP.Y != 0)
|
||||
{
|
||||
la = FloorMod(FloorMod(FloorMod(
|
||||
aP.X * aP.X, N) * 3 + A, N) * ExtendedGCD(2 * aP.Y, N), N);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Point.ZERO;
|
||||
}
|
||||
|
||||
long xCoordinate = FloorMod(la * la - aP.X - aQ.X, N);
|
||||
long yCoordinate = FloorMod(la * (aP.X - xCoordinate) - aP.Y, N);
|
||||
return new Point(xCoordinate, yCoordinate);
|
||||
}
|
||||
|
||||
public Point Multiply(Point aPoint, long aK)
|
||||
{
|
||||
Point result = Point.ZERO;
|
||||
|
||||
while (aK != 0)
|
||||
{
|
||||
if ((aK & 1) == 1)
|
||||
{
|
||||
result = Add(result, aPoint);
|
||||
}
|
||||
aPoint = Add(aPoint, aPoint);
|
||||
aK >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool Contains(Point aPoint)
|
||||
{
|
||||
if (aPoint.IsZero())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
long r = FloorMod(FloorMod(A + aPoint.X * aPoint.X, N) * aPoint.X + B, N);
|
||||
long s = FloorMod(aPoint.Y * aPoint.Y, N);
|
||||
return r == s;
|
||||
}
|
||||
|
||||
public long Discriminant()
|
||||
{
|
||||
long constant = 4 * FloorMod(A * A, N) * FloorMod(A, N);
|
||||
return FloorMod(-16 * (FloorMod(B * B, N) * 27 + constant), N);
|
||||
}
|
||||
|
||||
public void PrintPointWithPrefix(Point aPoint, string aPrefix)
|
||||
{
|
||||
long y = aPoint.Y;
|
||||
if (aPoint.IsZero())
|
||||
{
|
||||
Console.WriteLine(aPrefix + " (0)");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (y > N - y)
|
||||
{
|
||||
y -= N;
|
||||
}
|
||||
Console.WriteLine(aPrefix + " (" + aPoint.X + ", " + y + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Point
|
||||
{
|
||||
public long X { get; }
|
||||
public long Y { get; }
|
||||
|
||||
public Point(long aX, long aY)
|
||||
{
|
||||
X = aX;
|
||||
Y = aY;
|
||||
}
|
||||
|
||||
public bool IsZero()
|
||||
{
|
||||
return X == INFINITY && Y == 0;
|
||||
}
|
||||
|
||||
private const long INFINITY = long.MaxValue;
|
||||
public static readonly Point ZERO = new Point(INFINITY, 0);
|
||||
}
|
||||
|
||||
private class Pair
|
||||
{
|
||||
public long A { get; }
|
||||
public long B { get; }
|
||||
|
||||
public Pair(long a, long b)
|
||||
{
|
||||
A = a;
|
||||
B = b;
|
||||
}
|
||||
}
|
||||
|
||||
private class Parameter
|
||||
{
|
||||
public long A { get; }
|
||||
public long B { get; }
|
||||
public long N { get; }
|
||||
public Point G { get; }
|
||||
public long R { get; }
|
||||
|
||||
public Parameter(long a, long b, long n, Point g, long r)
|
||||
{
|
||||
A = a;
|
||||
B = b;
|
||||
N = n;
|
||||
G = g;
|
||||
R = r;
|
||||
}
|
||||
}
|
||||
|
||||
private const int MAX_MODULUS = 1073741789;
|
||||
private const int MAX_ORDER_G = MAX_MODULUS + 65536;
|
||||
|
||||
private static readonly Random _random = new Random();
|
||||
}
|
||||
|
|
@ -0,0 +1,356 @@
|
|||
class EllipticCurveDigitalSignatureAlgorithm {
|
||||
static main() {
|
||||
// Test parameters for elliptic curve digital signature algorithm,
|
||||
// using the short Weierstrass model: y^2 = x^3 + ax + b (mod N).
|
||||
//
|
||||
// Parameter: a, b, modulus N, base point G, order of G in the elliptic curve.
|
||||
|
||||
const parameters = [
|
||||
new Parameter(355, 671, 1073741789, new Point(13693, 10088), 1073807281),
|
||||
new Parameter(0, 7, 67096021, new Point(6580, 779), 16769911),
|
||||
new Parameter(-3, 1, 877073, new Point(0, 1), 878159),
|
||||
new Parameter(0, 14, 22651, new Point(63, 30), 151),
|
||||
new Parameter(3, 2, 5, new Point(2, 1), 5),
|
||||
];
|
||||
|
||||
// Parameters which cause failure of the algorithm for the given reasons
|
||||
// the base point is of composite order
|
||||
// new Parameter( 0, 7, 67096021, new Point( 2402, 6067), 33539822 ),
|
||||
// the given order is of composite order
|
||||
// new Parameter( 0, 7, 67096021, new Point( 6580, 779), 67079644 ),
|
||||
// the modulus is not prime (deceptive example)
|
||||
// new Parameter( 0, 7, 877069, new Point( 3, 97123), 877069 ),
|
||||
// fails if the modulus divides the discriminant
|
||||
// new Parameter( 39, 387, 22651, new Point( 95, 27), 22651 ) );
|
||||
|
||||
const f = 0x789abcde; // The message's digital signature hash which is to be verified
|
||||
const d = 0; // Set d > 0 to simulate corrupted data
|
||||
|
||||
for (const parameter of parameters) {
|
||||
const ellipticCurve = new EllipticCurve(parameter);
|
||||
EllipticCurveDigitalSignatureAlgorithm.ecdsa(ellipticCurve, f, d);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the digital signature for a message using the hash aF with error bit aD
|
||||
static ecdsa(aCurve, aF, aD) {
|
||||
let point = aCurve.multiply(aCurve.g, aCurve.r);
|
||||
|
||||
if (
|
||||
aCurve.discriminant() == 0 ||
|
||||
aCurve.g.isZero() ||
|
||||
!point.isZero() ||
|
||||
!aCurve.contains(aCurve.g)
|
||||
) {
|
||||
//throw new Error("Invalid parameter in method ecdsa");
|
||||
}
|
||||
|
||||
console.log("\nkey generation");
|
||||
const s = 1 + Math.floor(Math.random() * (aCurve.r - 1));
|
||||
point = aCurve.multiply(aCurve.g, s);
|
||||
console.log("private key s = " + s);
|
||||
aCurve.printPointWithPrefix(point, "public key W = sG");
|
||||
|
||||
// Find the next highest power of two minus one.
|
||||
let t = aCurve.r;
|
||||
let i = 1;
|
||||
while (i < 64) {
|
||||
t |= t >> i;
|
||||
i <<= 1;
|
||||
}
|
||||
let f = aF;
|
||||
while (f > t) {
|
||||
f >>= 1;
|
||||
}
|
||||
console.log("\naligned hash " + f.toString(16).padStart(8, '0'));
|
||||
|
||||
const signature = EllipticCurveDigitalSignatureAlgorithm.signature(
|
||||
aCurve,
|
||||
s,
|
||||
f
|
||||
);
|
||||
console.log("signature c, d = " + signature.a + ", " + signature.b);
|
||||
|
||||
let d = aD;
|
||||
if (d > 0) {
|
||||
while (d > t) {
|
||||
d >>= 1;
|
||||
}
|
||||
f ^= d;
|
||||
console.log("\ncorrupted hash " + f.toString(16).padStart(8, '0'));
|
||||
}
|
||||
|
||||
console.log(
|
||||
EllipticCurveDigitalSignatureAlgorithm.verify(aCurve, point, f, signature)
|
||||
? "Valid"
|
||||
: "Invalid"
|
||||
);
|
||||
console.log("-----------------");
|
||||
}
|
||||
|
||||
static verify(aCurve, aPoint, aF, aSignature) {
|
||||
if (
|
||||
aSignature.a < 1 ||
|
||||
aSignature.a >= aCurve.r ||
|
||||
aSignature.b < 1 ||
|
||||
aSignature.b >= aCurve.r
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log("\nsignature verification");
|
||||
const h = EllipticCurveDigitalSignatureAlgorithm.extendedGCD(
|
||||
aSignature.b,
|
||||
aCurve.r
|
||||
);
|
||||
const h1 = EllipticCurveDigitalSignatureAlgorithm.floorMod(aF * h, aCurve.r);
|
||||
const h2 = EllipticCurveDigitalSignatureAlgorithm.floorMod(aSignature.a * h, aCurve.r);
|
||||
console.log("h1, h2 = " + h1 + ", " + h2);
|
||||
let v = aCurve.multiply(aCurve.g, h1);
|
||||
let v2 = aCurve.multiply(aPoint, h2);
|
||||
aCurve.printPointWithPrefix(v, "h1G");
|
||||
aCurve.printPointWithPrefix(v2, "h2W");
|
||||
v = aCurve.add(v, v2);
|
||||
aCurve.printPointWithPrefix(v, "+ =");
|
||||
|
||||
if (v.isZero()) {
|
||||
return false;
|
||||
}
|
||||
const c1 = EllipticCurveDigitalSignatureAlgorithm.floorMod(v.x, aCurve.r);
|
||||
console.log("c' = " + c1);
|
||||
return c1 == aSignature.a;
|
||||
}
|
||||
|
||||
static signature(aCurve, aS, aF) {
|
||||
let c = 0;
|
||||
let d = 0;
|
||||
let u;
|
||||
let v;
|
||||
console.log("Signature computation");
|
||||
|
||||
while (true) {
|
||||
while (true) {
|
||||
u = 1 + Math.floor(Math.random() * (aCurve.r - 1));
|
||||
v = aCurve.multiply(aCurve.g, u);
|
||||
c = EllipticCurveDigitalSignatureAlgorithm.floorMod(v.x, aCurve.r);
|
||||
if (c != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
d = EllipticCurveDigitalSignatureAlgorithm.floorMod(
|
||||
EllipticCurveDigitalSignatureAlgorithm.extendedGCD(u, aCurve.r) *
|
||||
EllipticCurveDigitalSignatureAlgorithm.floorMod(aF + aS * c, aCurve.r),
|
||||
aCurve.r
|
||||
);
|
||||
if (d != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("one-time u = " + u);
|
||||
aCurve.printPointWithPrefix(v, "V = uG");
|
||||
return new Pair(c, d);
|
||||
}
|
||||
|
||||
// Return 1 / aV modulus aU
|
||||
static extendedGCD(aV, aU) {
|
||||
if (aV < 0) {
|
||||
aV += aU;
|
||||
}
|
||||
|
||||
let result = 0;
|
||||
let s = 1;
|
||||
while (aV != 0) {
|
||||
const quotient = Math.floor(aU / aV);
|
||||
aU = EllipticCurveDigitalSignatureAlgorithm.floorMod(aU, aV);
|
||||
let temp = aU;
|
||||
aU = aV;
|
||||
aV = temp;
|
||||
result -= quotient * s;
|
||||
temp = result;
|
||||
result = s;
|
||||
s = temp;
|
||||
}
|
||||
|
||||
if (aU != 1) {
|
||||
throw new Error("Cannot inverse modulo N, gcd = " + aU);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static floorMod(x, y) {
|
||||
return ((x % y) + y) % y;
|
||||
}
|
||||
|
||||
// static random() {
|
||||
// return Math.random();
|
||||
// }
|
||||
}
|
||||
|
||||
class EllipticCurve {
|
||||
constructor(aParameter) {
|
||||
this.n = aParameter.n;
|
||||
if (this.n < 5 || this.n > EllipticCurveDigitalSignatureAlgorithm.MAX_MODULUS) {
|
||||
throw new Error("Invalid value for modulus: " + this.n);
|
||||
}
|
||||
|
||||
this.a = EllipticCurveDigitalSignatureAlgorithm.floorMod(aParameter.a, this.n);
|
||||
this.b = EllipticCurveDigitalSignatureAlgorithm.floorMod(aParameter.b, this.n);
|
||||
this.g = aParameter.g;
|
||||
this.r = aParameter.r;
|
||||
|
||||
if (this.r < 5 || this.r > EllipticCurveDigitalSignatureAlgorithm.MAX_ORDER_G) {
|
||||
throw new Error("Invalid value for the order of g: " + this.r);
|
||||
}
|
||||
|
||||
console.log();
|
||||
console.log(
|
||||
"Elliptic curve: y^2 = x^3 + " +
|
||||
this.a +
|
||||
"x + " +
|
||||
this.b +
|
||||
" (mod " +
|
||||
this.n +
|
||||
")"
|
||||
);
|
||||
this.printPointWithPrefix(this.g, "base point G");
|
||||
console.log("order(G, E) = " + this.r);
|
||||
}
|
||||
|
||||
add(aP, aQ) {
|
||||
if (aP.isZero()) {
|
||||
return aQ;
|
||||
}
|
||||
if (aQ.isZero()) {
|
||||
return aP;
|
||||
}
|
||||
|
||||
let la;
|
||||
if (aP.x != aQ.x) {
|
||||
la = EllipticCurveDigitalSignatureAlgorithm.floorMod(
|
||||
(aP.y - aQ.y) *
|
||||
EllipticCurveDigitalSignatureAlgorithm.extendedGCD(aP.x - aQ.x, this.n),
|
||||
this.n
|
||||
);
|
||||
} else if (aP.y == aQ.y && aP.y != 0) {
|
||||
la = EllipticCurveDigitalSignatureAlgorithm.floorMod(
|
||||
EllipticCurveDigitalSignatureAlgorithm.floorMod(
|
||||
EllipticCurveDigitalSignatureAlgorithm.floorMod(aP.x * aP.x, this.n) * 3 +
|
||||
this.a,
|
||||
this.n
|
||||
) * EllipticCurveDigitalSignatureAlgorithm.extendedGCD(2 * aP.y, this.n),
|
||||
this.n
|
||||
);
|
||||
} else {
|
||||
return Point.ZERO;
|
||||
}
|
||||
|
||||
const xCoordinate = EllipticCurveDigitalSignatureAlgorithm.floorMod(
|
||||
la * la - aP.x - aQ.x,
|
||||
this.n
|
||||
);
|
||||
const yCoordinate = EllipticCurveDigitalSignatureAlgorithm.floorMod(
|
||||
la * (aP.x - xCoordinate) - aP.y,
|
||||
this.n
|
||||
);
|
||||
return new Point(xCoordinate, yCoordinate);
|
||||
}
|
||||
|
||||
multiply(aPoint, aK) {
|
||||
let result = Point.ZERO;
|
||||
|
||||
while (aK != 0) {
|
||||
if ((aK & 1) == 1) {
|
||||
result = this.add(result, aPoint);
|
||||
}
|
||||
aPoint = this.add(aPoint, aPoint);
|
||||
aK >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
contains(aPoint) {
|
||||
if (aPoint.isZero()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const r = EllipticCurveDigitalSignatureAlgorithm.floorMod(
|
||||
EllipticCurveDigitalSignatureAlgorithm.floorMod(
|
||||
this.a + aPoint.x * aPoint.x,
|
||||
this.n
|
||||
) * aPoint.x + this.b,
|
||||
this.n
|
||||
);
|
||||
const s = EllipticCurveDigitalSignatureAlgorithm.floorMod(aPoint.y * aPoint.y, this.n);
|
||||
return r == s;
|
||||
}
|
||||
|
||||
discriminant() {
|
||||
const constant =
|
||||
4 *
|
||||
EllipticCurveDigitalSignatureAlgorithm.floorMod(
|
||||
this.a * this.a,
|
||||
this.n
|
||||
) *
|
||||
EllipticCurveDigitalSignatureAlgorithm.floorMod(this.a, this.n);
|
||||
return EllipticCurveDigitalSignatureAlgorithm.floorMod(
|
||||
-16 *
|
||||
(EllipticCurveDigitalSignatureAlgorithm.floorMod(this.b * this.b, this.n) *
|
||||
27 +
|
||||
constant),
|
||||
this.n
|
||||
);
|
||||
}
|
||||
|
||||
printPointWithPrefix(aPoint, aPrefix) {
|
||||
let y = aPoint.y;
|
||||
if (aPoint.isZero()) {
|
||||
console.log(aPrefix + " (0)");
|
||||
} else {
|
||||
if (y > this.n - y) {
|
||||
y -= this.n;
|
||||
}
|
||||
console.log(aPrefix + " (" + aPoint.x + ", " + y + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Point {
|
||||
constructor(aX, aY) {
|
||||
this.x = aX;
|
||||
this.y = aY;
|
||||
}
|
||||
|
||||
isZero() {
|
||||
return this.x == Point.INFINITY && this.y == 0;
|
||||
}
|
||||
}
|
||||
|
||||
class Pair {
|
||||
constructor(a, b) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
|
||||
class Parameter {
|
||||
constructor(a, b, n, g, r) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.n = n;
|
||||
this.g = g;
|
||||
this.r = r;
|
||||
}
|
||||
}
|
||||
|
||||
Point.INFINITY = Number.MAX_SAFE_INTEGER;
|
||||
Point.ZERO = new Point(Point.INFINITY, 0);
|
||||
|
||||
EllipticCurveDigitalSignatureAlgorithm.MAX_MODULUS = 1073741789;
|
||||
EllipticCurveDigitalSignatureAlgorithm.MAX_ORDER_G =
|
||||
EllipticCurveDigitalSignatureAlgorithm.MAX_MODULUS + 65536;
|
||||
|
||||
// EllipticCurveDigitalSignatureAlgorithm.RANDOM = Math.random();
|
||||
|
||||
EllipticCurveDigitalSignatureAlgorithm.main();
|
||||
|
|
@ -0,0 +1,507 @@
|
|||
use rand::Rng;
|
||||
use std::{cmp::Ordering, mem};
|
||||
|
||||
// --- Constants ---
|
||||
const MAX_MODULUS: i64 = 1_073_741_789;
|
||||
const MAX_ORDER_G: i64 = MAX_MODULUS + 65536;
|
||||
|
||||
// --- Structures ---
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
struct Point {
|
||||
x: i64,
|
||||
y: i64,
|
||||
}
|
||||
|
||||
impl Point {
|
||||
// Represents the point at infinity (identity element)
|
||||
const ZERO: Point = Point { x: i64::MAX, y: 0 };
|
||||
|
||||
fn new(x: i64, y: i64) -> Self {
|
||||
Point { x, y }
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
*self == Point::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
struct Pair {
|
||||
// Often represents (c, d) in ECDSA signature
|
||||
c: i64, // Renamed 'a' to 'c' for clarity in ECDSA context
|
||||
d: i64, // Renamed 'b' to 'd' for clarity in ECDSA context
|
||||
}
|
||||
|
||||
impl Pair {
|
||||
fn new(c: i64, d: i64) -> Self {
|
||||
Pair { c, d }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct Parameter {
|
||||
a: i64,
|
||||
b: i64,
|
||||
n: i64, // Modulus
|
||||
g: Point, // Base point
|
||||
r: i64, // Order of G
|
||||
}
|
||||
|
||||
impl Parameter {
|
||||
fn new(a: i64, b: i64, n: i64, g: Point, r: i64) -> Self {
|
||||
Parameter { a, b, n, g, r }
|
||||
}
|
||||
}
|
||||
|
||||
// --- Helper Functions ---
|
||||
|
||||
// Consistent floor modulus (handles negative numbers)
|
||||
fn floor_mod(num: i64, modulus: i64) -> i64 {
|
||||
// Assumes modulus > 0, which is true for elliptic curve 'n' and 'r'
|
||||
// If modulus can be negative, more complex logic is needed like in the C++ version.
|
||||
// For ECDSA n and r are positive.
|
||||
if modulus <= 0 {
|
||||
panic!("Modulus must be positive for floor_mod in this context.");
|
||||
}
|
||||
// ((num % modulus) + modulus) % modulus
|
||||
let rem = num % modulus;
|
||||
if rem < 0 {
|
||||
rem + modulus
|
||||
} else {
|
||||
rem
|
||||
}
|
||||
}
|
||||
|
||||
// Extended Euclidean Algorithm to find modular multiplicative inverse.
|
||||
// Returns `x` such that `(a * x) % m == 1`.
|
||||
// Returns Err if gcd(a, m) != 1 (no inverse exists).
|
||||
fn extended_gcd(a: i64, m: i64) -> Result<i64, String> {
|
||||
if m <= 0 {
|
||||
return Err("Modulus must be positive for extended_gcd".to_string());
|
||||
}
|
||||
let mut v = floor_mod(a, m); // Ensure v is in [0, m-1]
|
||||
let mut u = m;
|
||||
let mut result: i64 = 0;
|
||||
let mut s: i64 = 1;
|
||||
|
||||
while v != 0 {
|
||||
// Using standard Euclidean algorithm division, not floor_div, as 'v' and 'u' are non-negative
|
||||
let quotient = u / v;
|
||||
u = u % v;
|
||||
mem::swap(&mut u, &mut v); // Swap u and v
|
||||
|
||||
// Update Bezout coefficients
|
||||
let next_result = result.wrapping_sub(quotient.wrapping_mul(s));
|
||||
result = s;
|
||||
s = next_result;
|
||||
|
||||
// Keep result and s within i64 range reasonably
|
||||
// (Technically full modular arithmetic on coefficients is better,
|
||||
// but for typical crypto sizes i64 is usually sufficient)
|
||||
}
|
||||
|
||||
if u != 1 {
|
||||
Err(format!(
|
||||
"Cannot inverse modulo N={}, gcd({}, {}) = {}",
|
||||
m, a, m, u
|
||||
))
|
||||
} else {
|
||||
// Ensure the result is positive
|
||||
Ok(floor_mod(result, m))
|
||||
}
|
||||
}
|
||||
|
||||
// --- Elliptic Curve Logic ---
|
||||
|
||||
#[derive(Debug, Clone)] // Cannot Copy as methods take &self
|
||||
struct EllipticCurve {
|
||||
a: i64,
|
||||
b: i64,
|
||||
n: i64, // Modulus
|
||||
r: i64, // Order of G
|
||||
g: Point, // Base point
|
||||
}
|
||||
|
||||
impl EllipticCurve {
|
||||
// Constructor with validation
|
||||
fn new(param: Parameter) -> Result<Self, String> {
|
||||
if param.n < 5 || param.n > MAX_MODULUS {
|
||||
return Err(format!("Invalid value for modulus: {}", param.n));
|
||||
}
|
||||
if param.r < 5 || param.r > MAX_ORDER_G {
|
||||
return Err(format!(
|
||||
"Invalid value for the order of g: {}",
|
||||
param.r
|
||||
));
|
||||
}
|
||||
|
||||
let a = floor_mod(param.a, param.n);
|
||||
let b = floor_mod(param.b, param.n);
|
||||
|
||||
let curve = EllipticCurve {
|
||||
a,
|
||||
b,
|
||||
n: param.n,
|
||||
r: param.r,
|
||||
g: param.g,
|
||||
};
|
||||
|
||||
println!("\nElliptic curve: y^2 = x^3 + {}x + {} (mod {})", a, b, param.n);
|
||||
curve.print_point_with_prefix(curve.g, "base point G");
|
||||
println!("order(G, E) = {}", curve.r);
|
||||
|
||||
// Basic check: Base point must be on the curve
|
||||
if !param.g.is_zero() && !curve.contains(param.g) {
|
||||
return Err(format!("Base point G {:?} is not on the curve", param.g));
|
||||
}
|
||||
// Basic check: Order * G should be Zero
|
||||
let order_check = curve.multiply(curve.g, curve.r);
|
||||
// Check if multiplication failed or result is not Zero
|
||||
match order_check {
|
||||
Ok(p) if !p.is_zero() => return Err(format!("Order r={} is invalid for G: r*G is not Zero", curve.r)),
|
||||
Err(e) => return Err(format!("Failed order check multiplication: {}", e)),
|
||||
_ => {} // Ok and point is Zero, proceed
|
||||
}
|
||||
// Basic check: Discriminant non-zero (for non-singular curve)
|
||||
let disc = curve.discriminant()?;
|
||||
if disc == 0 {
|
||||
return Err("Curve discriminant is zero (singular curve)".to_string());
|
||||
}
|
||||
|
||||
Ok(curve)
|
||||
}
|
||||
|
||||
// Point addition (P + Q)
|
||||
fn add(&self, p: Point, q: Point) -> Result<Point, String> {
|
||||
if p.is_zero() {
|
||||
return Ok(q);
|
||||
}
|
||||
if q.is_zero() {
|
||||
return Ok(p);
|
||||
}
|
||||
|
||||
let lambda: i64;
|
||||
if p.x != q.x {
|
||||
// P != Q
|
||||
let dy = p.y.wrapping_sub(q.y);
|
||||
let dx = p.x.wrapping_sub(q.x);
|
||||
let dx_inv = extended_gcd(dx, self.n)?;
|
||||
lambda = floor_mod(dy.wrapping_mul(dx_inv), self.n);
|
||||
} else if p.y == q.y && p.y != 0 {
|
||||
// P == Q (Point doubling)
|
||||
// lambda = (3*x^2 + a) / (2*y) mod n
|
||||
let x_sq = floor_mod(p.x.wrapping_mul(p.x), self.n);
|
||||
let numerator = floor_mod(x_sq.wrapping_mul(3).wrapping_add(self.a), self.n);
|
||||
let denominator = floor_mod(p.y.wrapping_mul(2), self.n);
|
||||
let denominator_inv = extended_gcd(denominator, self.n)?;
|
||||
lambda = floor_mod(numerator.wrapping_mul(denominator_inv), self.n);
|
||||
} else {
|
||||
// P == -Q (p.x == q.x but p.y == -q.y mod n) or P == Q == (x, 0)
|
||||
return Ok(Point::ZERO);
|
||||
}
|
||||
|
||||
// x_r = lambda^2 - x_p - x_q mod n
|
||||
let lambda_sq = floor_mod(lambda.wrapping_mul(lambda), self.n);
|
||||
let x_r = floor_mod(
|
||||
lambda_sq.wrapping_sub(p.x).wrapping_sub(q.x),
|
||||
self.n,
|
||||
);
|
||||
|
||||
// y_r = lambda * (x_p - x_r) - y_p mod n
|
||||
let x_p_sub_x_r = p.x.wrapping_sub(x_r);
|
||||
let term1 = floor_mod(lambda.wrapping_mul(x_p_sub_x_r), self.n);
|
||||
let y_r = floor_mod(term1.wrapping_sub(p.y), self.n);
|
||||
|
||||
Ok(Point::new(x_r, y_r))
|
||||
}
|
||||
|
||||
// Scalar multiplication (k * P) using double-and-add
|
||||
fn multiply(&self, mut point: Point, mut k: i64) -> Result<Point, String> {
|
||||
let mut result = Point::ZERO;
|
||||
if k < 0 {
|
||||
// This basic implementation doesn't handle negative k easily.
|
||||
// Standard ECDSA uses positive scalars (private key, random nonce).
|
||||
// If needed, one could compute k = k mod r, or compute point negation.
|
||||
return Err("Negative scalar multiplication not directly supported".to_string());
|
||||
}
|
||||
if k == 0 {
|
||||
return Ok(Point::ZERO);
|
||||
}
|
||||
|
||||
// Ensure k is positive and reduced modulo r if necessary, though ECDSA usually handles this before calling.
|
||||
// k = floor_mod(k, self.r); // Optional: Reduce k modulo order, requires r > 0
|
||||
|
||||
while k > 0 {
|
||||
if (k & 1) == 1 {
|
||||
result = self.add(result, point)?;
|
||||
}
|
||||
point = self.add(point, point)?; // Double the point
|
||||
k >>= 1; // Halve the scalar
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// Check if a point lies on the curve y^2 = x^3 + ax + b (mod n)
|
||||
fn contains(&self, point: Point) -> bool {
|
||||
if point.is_zero() {
|
||||
return true; // Point at infinity is always on the curve
|
||||
}
|
||||
|
||||
// y^2 mod n
|
||||
let lhs = floor_mod(point.y.wrapping_mul(point.y), self.n);
|
||||
|
||||
// x^3 + ax + b mod n
|
||||
let x_sq = floor_mod(point.x.wrapping_mul(point.x), self.n);
|
||||
let x_cubed = floor_mod(x_sq.wrapping_mul(point.x), self.n);
|
||||
let ax = floor_mod(self.a.wrapping_mul(point.x), self.n);
|
||||
let rhs = floor_mod(x_cubed.wrapping_add(ax).wrapping_add(self.b), self.n);
|
||||
|
||||
lhs == rhs
|
||||
}
|
||||
|
||||
// Calculate discriminant: -16 * (4a^3 + 27b^2) mod n
|
||||
fn discriminant(&self) -> Result<i64, String> {
|
||||
// Need intermediate results, use wrapping arithmetic carefully
|
||||
let a_sq = floor_mod(self.a.wrapping_mul(self.a), self.n);
|
||||
let a_cubed = floor_mod(a_sq.wrapping_mul(self.a), self.n);
|
||||
let term1 = floor_mod(a_cubed.wrapping_mul(4), self.n); // 4a^3
|
||||
|
||||
let b_sq = floor_mod(self.b.wrapping_mul(self.b), self.n);
|
||||
let term2 = floor_mod(b_sq.wrapping_mul(27), self.n); // 27b^2
|
||||
|
||||
let inner_sum = floor_mod(term1.wrapping_add(term2), self.n); // 4a^3 + 27b^2
|
||||
let result = floor_mod(inner_sum.wrapping_mul(-16), self.n);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// Helper to print points
|
||||
fn print_point_with_prefix(&self, point: Point, prefix: &str) {
|
||||
if point.is_zero() {
|
||||
println!("{} (0 - Point at Infinity)", prefix);
|
||||
} else {
|
||||
// Optionally represent y with the smaller absolute value coordinate
|
||||
let mut y_repr = point.y;
|
||||
if y_repr > self.n / 2 { // Simplified check assuming n > 0
|
||||
y_repr = y_repr.wrapping_sub(self.n);
|
||||
}
|
||||
println!("{} ({}, {})", prefix, point.x, y_repr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- ECDSA Functions ---
|
||||
|
||||
// Generate a random number 0.0 <= x < 1.0
|
||||
fn random_f64() -> f64 {
|
||||
let mut rng = rand::thread_rng();
|
||||
rng.gen::<f64>()
|
||||
}
|
||||
|
||||
// Generate a random integer 1 <= x < limit
|
||||
fn random_i64_in_range(limit: i64) -> i64 {
|
||||
if limit <= 1 {
|
||||
// Avoid panic in gen_range(1..limit) if limit is 1 or less.
|
||||
// In ECDSA, the limit (order r) should be > 1.
|
||||
// If r was 1 or less, curve setup should have failed.
|
||||
panic!("Range limit must be greater than 1 for random generation");
|
||||
}
|
||||
let mut rng = rand::thread_rng();
|
||||
rng.gen_range(1..limit) // Exclusive upper bound
|
||||
}
|
||||
|
||||
|
||||
// Create ECDSA signature (c, d) for message hash f
|
||||
// s: private key
|
||||
fn signature(curve: &EllipticCurve, s: i64, f: i64) -> Result<Pair, String> {
|
||||
if curve.r <= 1 {
|
||||
return Err("Curve order 'r' must be greater than 1 for signing.".to_string());
|
||||
}
|
||||
|
||||
loop {
|
||||
// 1. Generate random nonce 'u' (called 'k' in many texts) in [1, r-1]
|
||||
let u = random_i64_in_range(curve.r);
|
||||
|
||||
// 2. Calculate curve point V = u * G
|
||||
let v = curve.multiply(curve.g, u)?;
|
||||
if v.is_zero() { continue; } // Should technically not happen if u in [1, r-1]
|
||||
|
||||
// 3. Calculate c = V.x mod r
|
||||
let c = floor_mod(v.x, curve.r);
|
||||
if c == 0 { continue; } // Retry if c is 0
|
||||
|
||||
// 4. Calculate d = u^-1 * (f + s*c) mod r
|
||||
let u_inv = extended_gcd(u, curve.r)?; // u^-1 mod r
|
||||
let s_times_c = floor_mod(s.wrapping_mul(c), curve.r);
|
||||
let hash_plus_sc = floor_mod(f.wrapping_add(s_times_c), curve.r);
|
||||
let d = floor_mod(u_inv.wrapping_mul(hash_plus_sc), curve.r);
|
||||
|
||||
if d == 0 { continue; } // Retry if d is 0
|
||||
|
||||
println!("one-time u = {}", u);
|
||||
curve.print_point_with_prefix(v, "V = uG");
|
||||
return Ok(Pair::new(c, d));
|
||||
}
|
||||
}
|
||||
|
||||
// Verify ECDSA signature
|
||||
// point W: public key (W = s*G)
|
||||
// f: message hash (same as used for signing)
|
||||
// signature (c, d): the signature to verify
|
||||
fn verify(curve: &EllipticCurve, public_key_w: Point, f: i64, signature: Pair) -> Result<bool, String> {
|
||||
let (c, d) = (signature.c, signature.d);
|
||||
|
||||
// 1. Check if c and d are in the valid range [1, r-1]
|
||||
if !(1..curve.r).contains(&c) || !(1..curve.r).contains(&d) {
|
||||
println!("Verification fail: c or d out of range [1, r-1]");
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
println!("\nSignature verification");
|
||||
|
||||
// 2. Calculate h = d^-1 mod r
|
||||
let h = extended_gcd(d, curve.r)?;
|
||||
|
||||
// 3. Calculate h1 = f * h mod r
|
||||
// 4. Calculate h2 = c * h mod r
|
||||
let h1 = floor_mod(f.wrapping_mul(h), curve.r);
|
||||
let h2 = floor_mod(c.wrapping_mul(h), curve.r);
|
||||
println!("h = d^-1 = {}", h);
|
||||
println!("h1 = f*h = {}", h1);
|
||||
println!("h2 = c*h = {}", h2);
|
||||
|
||||
// 5. Calculate point V' = h1*G + h2*W
|
||||
let v1 = curve.multiply(curve.g, h1)?;
|
||||
let v2 = curve.multiply(public_key_w, h2)?;
|
||||
curve.print_point_with_prefix(v1, "h1*G");
|
||||
curve.print_point_with_prefix(v2, "h2*W");
|
||||
|
||||
let v_prime = curve.add(v1, v2)?;
|
||||
curve.print_point_with_prefix(v_prime, "+ = V'");
|
||||
|
||||
// 6. Check if V' is the point at infinity
|
||||
if v_prime.is_zero() {
|
||||
println!("Verification fail: V' is point at infinity");
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// 7. Calculate c' = V'.x mod r
|
||||
let c_prime = floor_mod(v_prime.x, curve.r);
|
||||
println!("c' = V'.x mod r = {}", c_prime);
|
||||
|
||||
// 8. Signature is valid if c' == c
|
||||
Ok(c_prime == c)
|
||||
}
|
||||
|
||||
// Main ECDSA process: keygen, sign, verify
|
||||
fn ecdsa(curve: &EllipticCurve, f_original: i64, d_error: i32) -> Result<(), String> {
|
||||
// Initial curve/parameter checks (already done in EllipticCurve::new, but re-stated here)
|
||||
// if curve.discriminant()? == 0 { return Err("Invalid parameter: discriminant is 0".to_string()); }
|
||||
// if curve.g.is_zero() { return Err("Invalid parameter: base point G is zero".to_string()); }
|
||||
// let point_check = curve.multiply(curve.g, curve.r)?;
|
||||
// if !point_check.is_zero() { return Err("Invalid parameter: r*G is not zero".to_string()); }
|
||||
// if !curve.contains(curve.g) { return Err("Invalid parameter: G is not on the curve".to_string()); }
|
||||
|
||||
println!("\nKey generation");
|
||||
// 1. Generate private key 's' in [1, r-1]
|
||||
let s = random_i64_in_range(curve.r);
|
||||
// 2. Calculate public key W = s * G
|
||||
let public_key_w = curve.multiply(curve.g, s)?;
|
||||
println!("private key s = {}", s);
|
||||
curve.print_point_with_prefix(public_key_w, "public key W = sG");
|
||||
|
||||
|
||||
// Align hash f to be within the bit range related to r
|
||||
let mut f = f_original;
|
||||
// Find the next highest power of two minus one for r (rough bit mask)
|
||||
let mut t = curve.r;
|
||||
if t > 0 { // Avoid infinite loop if r is 0 or negative (shouldn't happen)
|
||||
// Efficient way to get next power of 2 minus 1 (all lower bits set)
|
||||
t |= t >> 1;
|
||||
t |= t >> 2;
|
||||
t |= t >> 4;
|
||||
t |= t >> 8;
|
||||
t |= t >> 16;
|
||||
t |= t >> 32; // For i64
|
||||
|
||||
// Reduce f if it's larger than the bit mask t
|
||||
// This step isn't standard ECDSA but mimics the C++ example's behavior.
|
||||
// Standard ECDSA typically takes the leftmost min(N, L) bits of the hash,
|
||||
// where N is bit length of r, L is bit length of hash output.
|
||||
while f > 0 && t > 0 && f > t {
|
||||
println!("Warning: Hash {} > bitmask {}. Right-shifting hash (non-standard).", f, t);
|
||||
f >>= 1;
|
||||
}
|
||||
} else {
|
||||
println!("Warning: Curve order r ({}) is not positive. Hash alignment skipped.", curve.r);
|
||||
t = i64::MAX; // Allow any hash if r is invalid
|
||||
}
|
||||
|
||||
println!("\nAligned hash f = 0x{:08x} ({})", f, f);
|
||||
|
||||
// Sign the hash
|
||||
let signature_pair = signature(curve, s, f)?;
|
||||
println!("Signature (c, d) = ({}, {})", signature_pair.c, signature_pair.d);
|
||||
|
||||
// Simulate data corruption if d_error > 0
|
||||
let mut f_verify = f;
|
||||
if d_error > 0 {
|
||||
let mut error_val = d_error as i64;
|
||||
// Align the error like the hash was aligned (mimicking C++ again)
|
||||
while error_val > 0 && t > 0 && error_val > t {
|
||||
error_val >>= 1;
|
||||
}
|
||||
f_verify ^= error_val; // Apply error using XOR
|
||||
println!(
|
||||
"\nCorrupted hash f' = 0x{:08x} ({}) (error=0x{:x})",
|
||||
f_verify, f_verify, d_error
|
||||
);
|
||||
}
|
||||
|
||||
// Verify the signature
|
||||
let is_valid = verify(curve, public_key_w, f_verify, signature_pair)?;
|
||||
println!("{}", if is_valid { "Valid" } else { "Invalid" });
|
||||
println!("-----------------");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Test parameters for elliptic curve digital signature algorithm,
|
||||
// using the short Weierstrass model: y^2 = x^3 + ax + b (mod N).
|
||||
// Parameter: a, b, modulus N, base point G(x, y), order of G.
|
||||
let parameters = vec![
|
||||
Parameter::new(355, 671, 1_073_741_789, Point::new(13693, 10088), 1_073_807_281),
|
||||
Parameter::new(0, 7, 67_096_021, Point::new(6580, 779), 16_769_911),
|
||||
Parameter::new(-3, 1, 877_073, Point::new(0, 1), 878_159), // SECp256k1 shape (a=0, b=7) is common, this is a=-3
|
||||
Parameter::new(0, 14, 22_651, Point::new(63, 30), 151),
|
||||
Parameter::new(3, 2, 5, Point::new(2, 1), 5), // Very small curve example
|
||||
];
|
||||
|
||||
// Parameters which cause failure (commented out like C++)
|
||||
// Parameter::new(0, 7, 67096021, Point::new(2402, 6067), 33539822), // G has composite order
|
||||
// Parameter::new(0, 7, 67096021, Point::new(6580, 779), 67079644), // r is composite (multiple of true order)
|
||||
// Parameter::new(0, 7, 877069, Point::new(3, 97123), 877069), // N not prime (877069 = 877 * 1000 + 69, maybe 7*125295 + 4?) Let's check: 877069 / 7 = 125295.5; 877069 / 11.. nope. 877069 is prime. The comment might be wrong, or the point/order pair fails for other reasons.
|
||||
// Parameter::new(39, 387, 22651, Point::new(95, 27), 22651) // N divides discriminant? disc = -16*(4*39^3+27*387^2) mod 22651. Let's check: 4*39^3+27*387^2 = 4*59319 + 27*149769 = 237276 + 4043763 = 4281039. 4281039 mod 22651 = 0. Yes, N divides discriminant -> singular curve.
|
||||
|
||||
// The message hash (often SHA-256 output truncated/converted to integer)
|
||||
let f_hash: i64 = 0x789a_bcde;
|
||||
// Set d_error > 0 to simulate corrupted data before verification
|
||||
let d_error: i32 = 0; // 0 means no error
|
||||
|
||||
for param in parameters {
|
||||
match EllipticCurve::new(param) {
|
||||
Ok(curve) => {
|
||||
if let Err(e) = ecdsa(&curve, f_hash, d_error) {
|
||||
eprintln!("ECDSA Error for curve {:?}: {}", param, e);
|
||||
println!("-----------------");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to create curve with parameters {:?}: {}", param, e);
|
||||
println!("-----------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue