Data update

This commit is contained in:
Ingy döt Net 2023-09-01 09:35:06 -07:00
parent 61b93a2cd1
commit 5af6d93694
858 changed files with 20572 additions and 2082 deletions

View file

@ -1,7 +1,7 @@
;Elliptic curves.
An [[wp:Elliptic_curve|elliptic curve]] E over ℤp (p ≥ 5) is defined by an equation of the form
'''y^2 = x^3 + ax + b''', where a, b ∈ ℤp and the discriminant ≢ 0 (mod p),
'''y²= x³ + ax + b''', where a, b ∈ ℤp and the discriminant ≢ 0 (mod p),
together with a special point 𝒪 called the point at infinity.
The set '''E(ℤp)''' consists of all points (x, y), with x, y ∈ ℤp,
which satisfy the above defining equation, together with 𝒪.

View file

@ -0,0 +1,300 @@
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <random>
#include <stdexcept>
#include <string>
#include <vector>
const int32_t MAX_MODULUS = 1073741789;
const int32_t MAX_ORDER_G = MAX_MODULUS + 65536;
std::random_device random;
std::mt19937 generator(random());
std::uniform_real_distribution<double> distribution(0.0F, 1.0F);
class Point {
public:
Point(const int64_t& x, const int64_t& y) : x(x), y(y) {}
Point() : x(0),y(0) {}
bool isZero() {
return x == INT64_MAX && y == 0;
}
int64_t x, y;
};
const Point ZERO_POINT(INT64_MAX, 0);
class Pair {
public:
Pair(const int64_t& a, const int64_t& b) : a(a), b(b) {}
const int64_t a, b;
};
class Parameter {
public:
Parameter(const int64_t& a, const int64_t& b, const int64_t& n, const Point& g, const int64_t& r)
: a(a), b(b), n(n), g(g), r(r) {}
const int64_t a, b, n;
const Point g;
const int64_t r;
};
int64_t signum(const int64_t& x) {
return ( x < 0 ) ? -1 : ( x > 0 ) ? 1 : 0;
}
int64_t floor_mod(const int64_t& num, const int64_t& mod) {
const int64_t signs = ( signum(num % mod) == -signum(mod) ) ? 1 : 0;
return ( num % mod ) + signs * mod;
}
int64_t floor_div(const int64_t& number, const int64_t& modulus) {
const int32_t signs = ( signum(number % modulus) == -signum(modulus) ) ? 1 : 0;
return ( number / modulus ) - signs;
}
// Return 1 / aV modulus aU
int64_t extended_GCD(int64_t v, int64_t u) {
if ( v < 0 ) {
v += u;
}
int64_t result = 0;
int64_t s = 1;
while ( v != 0 ) {
const int64_t quotient = floor_div(u, v);
u = floor_mod(u, v);
std::swap(u, v);
result -= quotient * s;
std::swap(result, s);
}
if ( u != 1 ) {
throw std::runtime_error("Cannot inverse modulo N, gcd = " + u);
}
return result;
}
class Elliptic_Curve {
public:
Elliptic_Curve(const Parameter& parameter) {
n = parameter.n;
if ( n < 5 || n > MAX_MODULUS ) {
throw std::invalid_argument("Invalid value for modulus: " + n);
}
a = floor_mod(parameter.a, n);
b = floor_mod(parameter.b, n);
g = parameter.g;
r = parameter.r;
if ( r < 5 || r > MAX_ORDER_G ) {
throw std::invalid_argument("Invalid value for the order of g: " + r);
}
std::cout << std::endl;
std::cout << "Elliptic curve: y^2 = x^3 + " << a << "x + " << b << " (mod " << n << ")" << std::endl;
print_point_with_prefix(g, "base point G");
std::cout << "order(G, E) = " << r << std::endl;
}
Point add(Point p, Point q) {
if ( p.isZero() ) {
return q;
}
if ( q.isZero() ) {
return p;
}
int64_t la;
if ( p.x != q.x ) {
la = floor_mod(( p.y - q.y ) * extended_GCD(p.x - q.x, n), n);
} else if ( p.y == q.y && p.y != 0 ) {
la = floor_mod(floor_mod(floor_mod(p.x * p.x, n) * 3 + a, n) * extended_GCD(2 * p.y, n), n);
} else {
return ZERO_POINT;
}
const int64_t x_coord = floor_mod(la * la - p.x - q.x, n);
const int64_t y_coord = floor_mod(la * ( p.x - x_coord ) - p.y, n);
return Point(x_coord, y_coord);
}
Point multiply(Point point, int64_t k) {
Point result = ZERO_POINT;
while ( k != 0 ) {
if ( ( k & 1 ) == 1 ) {
result = add(result, point);
}
point = add(point, point);
k >>= 1;
}
return result;
}
bool contains(Point point) {
if ( point.isZero() ) {
return true;
}
int64_t r = floor_mod(floor_mod(a + point.x * point.x, n) * point.x + b, n);
int64_t s = floor_mod(point.y * point.y, n);
return r == s;
}
uint64_t discriminant() {
const int64_t constant = 4 * floor_mod(a * a, n) * floor_mod(a, n);
return floor_mod(-16 * ( floor_mod(b * b, n) * 27 + constant ), n);
}
void print_point_with_prefix(Point point, const std::string& prefix) {
int64_t y = point.y;
if ( point.isZero() ) {
std::cout << prefix + " (0)" << std::endl;
} else {
if ( y > n - y ) {
y -= n;
}
std::cout << prefix + " (" << point.x << ", " << y << ")" << std::endl;
}
}
int64_t a, b, n, r;
Point g;
};
double random_number() {
return distribution(generator);
}
Pair signature(Elliptic_Curve curve, const int64_t& s, const int64_t& f) {
int64_t c, d, u;
Point v;
while ( true ) {
while ( true ) {
u = 1 + (int64_t) ( random_number() * (double) ( curve.r - 1 ) );
v = curve.multiply(curve.g, u);
c = floor_mod(v.x, curve.r);
if ( c != 0 ) {
break;
}
}
d = floor_mod(extended_GCD(u, curve.r) * floor_mod(f + s * c, curve.r), curve.r);
if ( d != 0 ) {
break;
}
}
std::cout << "one-time u = " << u << std::endl;
curve.print_point_with_prefix(v, "V = uG");
return Pair(c, d);
}
bool verify(Elliptic_Curve curve, Point point, const int64_t& f, const Pair& signature) {
if ( signature.a < 1 || signature.a >= curve.r || signature.b < 1 || signature.b >= curve.r ) {
return false;
}
std::cout << "\n" << "signature verification" << std::endl;
const int64_t h = extended_GCD(signature.b, curve.r);
const int64_t h1 = floor_mod(f * h, curve.r);
const int64_t h2 = floor_mod(signature.a * h, curve.r);
std::cout << "h1, h2 = " << h1 << ", " << h2 << std::endl;
Point v = curve.multiply(curve.g, h1);
Point v2 = curve.multiply(point, h2);
curve.print_point_with_prefix(v, "h1G");
curve.print_point_with_prefix(v2, "h2W");
v = curve.add(v, v2);
curve.print_point_with_prefix(v, "+ =");
if ( v.isZero() ) {
return false;
}
int64_t c1 = floor_mod(v.x, curve.r);
std::cout << "c' = " << c1 << std::endl;
return c1 == signature.a;
}
// Build the digital signature for a message using the hash aF with error bit aD
void ecdsa(Elliptic_Curve curve, int64_t f, int32_t d) {
Point point = curve.multiply(curve.g, curve.r);
if ( curve.discriminant() == 0 || curve.g.isZero() || ! point.isZero() || ! curve.contains(curve.g) ) {
throw std::invalid_argument("Invalid parameter in the method ecdsa");
}
std::cout << "\n" << "key generation" << std::endl;
const int64_t s = 1 + (int64_t) ( random_number() * (double) ( curve.r - 1 ) );
point = curve.multiply(curve.g, s);
std::cout << "private key s = " << s << std::endl;
curve.print_point_with_prefix(point, "public key W = sG");
// Find the next highest power of two minus one.
int64_t t = curve.r;
int64_t i = 1;
while ( i < 64 ) {
t |= t >> i;
i <<= 1;
}
while ( f > t ) {
f >>= 1;
}
std::cout << "\n" << "aligned hash " << std::hex << std::setfill('0') << std::setw(8) << f
<< std::dec << std::endl;
const Pair signature_pair = signature(curve, s, f);
std::cout << "signature c, d = " << signature_pair.a << ", " << signature_pair.b << std::endl;
if ( d > 0 ) {
while ( d > t ) {
d >>= 1;
}
f ^= d;
std::cout << "\n" << "corrupted hash " << std::hex << std::setfill('0') << std::setw(8) << f
<< std::dec << std::endl;
}
std::cout << ( verify(curve, point, f, signature_pair) ? "Valid" : "Invalid" ) << std::endl;
std::cout << "-----------------" << std::endl;
}
int 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 std::vector<Parameter> parameters {
Parameter( 355, 671, 1073741789, Point(13693, 10088), 1073807281 ),
Parameter( 0, 7, 67096021, Point( 6580, 779), 16769911 ),
Parameter( -3, 1, 877073, Point( 0, 1), 878159 ),
Parameter( 0, 14, 22651, Point( 63, 30), 151 ),
Parameter( 3, 2, 5, Point( 2, 1), 5 ) };
// Parameters which cause failure of the algorithm for the given reasons
// the base point is of composite order
// Parameter( 0, 7, 67096021, Point( 2402, 6067), 33539822 ),
// the given order is of composite order
// Parameter( 0, 7, 67096021, Point( 6580, 779), 67079644 ),
// the modulus is not prime (deceptive example)
// Parameter( 0, 7, 877069, Point( 3, 97123), 877069 ),
// fails if the modulus divides the discriminant
// Parameter( 39, 387, 22651, Point( 95, 27), 22651 ) );
const int64_t f = 0x789abcde; // The message's digital signature hash which is to be verified
const int32_t d = 0; // Set d > 0 to simulate corrupted data
for ( const Parameter& parameter : parameters ) {
Elliptic_Curve elliptic_curve(parameter);
ecdsa(elliptic_curve, f, d);
}
}

View file

@ -0,0 +1,278 @@
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public final class EllipticCurveDigitalSignatureAlgorithm {
public static void main(String[] aArgs) {
// 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 = List.of(
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 ) );
final long f = 0x789abcde; // The message's digital signature hash which is to be verified
final int d = 0; // Set d > 0 to simulate corrupted data
for ( Parameter parameter : 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 AssertionError("Invalid parameter in method ecdsa");
}
System.out.println(System.lineSeparator() + "key generation");
final long s = 1 + (long) ( random() * (double) ( aCurve.r - 1 ) );
point = aCurve.multiply(aCurve.g, s);
System.out.println("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 >> i;
i <<= 1;
}
long f = aF;
while ( f > t ) {
f >>= 1;
}
System.out.println(System.lineSeparator() + "aligned hash " + String.format("%08x", f));
Pair signature = signature(aCurve, s, f);
System.out.println("signature c, d = " + signature.a + ", " + signature.b);
long d = aD;
if ( d > 0 ) {
while ( d > t ) {
d >>= 1;
}
f ^= d;
System.out.println(System.lineSeparator() + "corrupted hash " + String.format("%08x", f));
}
System.out.println(verify(aCurve, point, f, signature) ? "Valid" : "Invalid");
System.out.println("-----------------");
}
private static boolean 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;
}
System.out.println(System.lineSeparator() + "signature verification");
final long h = extendedGCD(aSignature.b, aCurve.r);
final long h1 = Math.floorMod(aF * h, aCurve.r);
final long h2 = Math.floorMod(aSignature.a * h, aCurve.r);
System.out.println("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 = Math.floorMod(v.x, aCurve.r);
System.out.println("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;
System.out.println("Signature computation");
while ( true ) {
while ( true ) {
u = 1 + (long) ( random() * (double) ( aCurve.r - 1 ) );
v = aCurve.multiply(aCurve.g, u);
c = Math.floorMod(v.x, aCurve.r);
if ( c != 0 ) {
break;
}
}
d = Math.floorMod(extendedGCD(u, aCurve.r) * Math.floorMod(aF + aS * c, aCurve.r), aCurve.r);
if ( d != 0 ) {
break;
}
}
System.out.println("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 ) {
final long quotient = Math.floorDiv(aU, aV);
aU = Math.floorMod(aU, aV);
long temp = aU; aU = aV; aV = temp;
result -= quotient * s;
temp = result; result = s; s = temp;
}
if ( aU != 1 ) {
throw new AssertionError("Cannot inverse modulo N, gcd = " + aU);
}
return result;
}
private static double random() {
return RANDOM.nextDouble();
}
private static class EllipticCurve {
public EllipticCurve(Parameter aParameter) {
n = aParameter.n;
if ( n < 5 || n > MAX_MODULUS ) {
throw new AssertionError("Invalid value for modulus: " + n);
}
a = Math.floorMod(aParameter.a, n);
b = Math.floorMod(aParameter.b, n);
g = aParameter.g;
r = aParameter.r;
if ( r < 5 || r > MAX_ORDER_G ) {
throw new AssertionError("Invalid value for the order of g: " + r);
}
System.out.println();
System.out.println("Elliptic curve: y^2 = x^3 + " + a + "x + " + b + " (mod " + n + ")");
printPointWithPrefix(g, "base point G");
System.out.println("order(G, E) = " + r);
}
private Point add(Point aP, Point aQ) {
if ( aP.isZero() ) {
return aQ;
}
if ( aQ.isZero() ) {
return aP;
}
long la;
if ( aP.x != aQ.x ) {
la = Math.floorMod(( aP.y - aQ.y ) * extendedGCD(aP.x - aQ.x, n), n);
} else if ( aP.y == aQ.y && aP.y != 0 ) {
la = Math.floorMod(Math.floorMod(Math.floorMod(
aP.x * aP.x, n) * 3 + a, n) * extendedGCD(2 * aP.y, n), n);
} else {
return Point.ZERO;
}
final long xCoordinate = Math.floorMod(la * la - aP.x - aQ.x, n);
final long yCoordinate = Math.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 boolean contains(Point aPoint) {
if ( aPoint.isZero() ) {
return true;
}
final long r = Math.floorMod(Math.floorMod(a + aPoint.x * aPoint.x, n) * aPoint.x + b, n);
final long s = Math.floorMod(aPoint.y * aPoint.y, n);
return r == s;
}
public long discriminant() {
final long constant = 4 * Math.floorMod(a * a, n) * Math.floorMod(a, n);
return Math.floorMod(-16 * ( Math.floorMod(b * b, n) * 27 + constant ), n);
}
public void printPointWithPrefix(Point aPoint, String aPrefix) {
long y = aPoint.y;
if ( aPoint.isZero() ) {
System.out.println(aPrefix + " (0)");
} else {
if ( y > n - y ) {
y -= n;
}
System.out.println(aPrefix + " (" + aPoint.x + ", " + y + ")");
}
}
private final long a, b, n, r;
private final Point g;
}
private static class Point {
public Point(long aX, long aY) {
x = aX;
y = aY;
}
public boolean isZero() {
return x == INFINITY && y == 0;
}
private long x, y;
private static final long INFINITY = Long.MAX_VALUE;
private static final Point ZERO = new Point(INFINITY, 0);
}
private static record Pair(long a, long b) {}
private static record Parameter(long a, long b, long n, Point g, long r) {}
private static final int MAX_MODULUS = 1073741789;
private static final int MAX_ORDER_G = MAX_MODULUS + 65536;
private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();
}

View file

@ -1,89 +1,101 @@
use Digest::SHA256::Native;
module EC {
use FiniteField;
# Following data taken from the C entry
our (\A,\B,\P,\O,\Gx,\Gy) = (355, 671, 1073741789, 1073807281, 13693, 10088);
our class Point {
has ($.x, $.y);
submethod TWEAK { fail unless $!y**2 == $!x**3 + $*a*$!x + $*b }
multi method gist(::?CLASS:U:) { "Point at Horizon" }
multi method new($x, $y) { samewith :$x, :$y }
}
multi infix:<==>(Point:D $A, Point:D $B) is export { $A.x == $B.x and $A.y == $B.y }
#`{ Following data taken from the Julia entry; 256-bit; tested
our (\A,\B,\P,\O,\Gx,\Gy) = (0, 7, # https://en.bitcoin.it/wiki/Secp256k1
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F,
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,
0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8); # }
multi prefix:<->(Point $P) returns Point is export { Point.new: $P.x, -$P.y }
multi infix:<+>(Point $A, Point:U) is export { $A }
multi infix:<+>(Point:U, Point $B) is export { $B }
multi infix:<+>(Point:D $A, Point:D $B) returns Point is export {
my ;
if $A.x == $B.x and $A.y == -$B.y { return Point }
elsif $A == $B {
return Point if $A.y == 0;
= (3*$A.x² + $*a) / (2*$A.y);
}
else { = ($A.y - $B.y) / ($A.x - $B.x); }
role Horizon { method gist { 'EC Point at horizon' } }
class Point { # modified from the Elliptic_curve_arithmetic entry
has ($.x, $.y); # handle modular arithmetic only
multi method new( \x, \y ) { self.bless(:x, :y) }
method gist { "EC Point at x=$.x, y=$.y" }
method isOn { modP(B + $.x * modP(A+$.x²)) == modP($.y²) }
sub modP ($a is copy) { ( $a %= P ) < 0 ?? ($a += P) !! $a }
given **2 - $A.x - $B.x {
return Point.new: $_, *($A.x - $_) - $A.y;
}
}
multi infix:<*>(0, Point ) is export { Point }
multi infix:<*>(1, Point $p) is export { $p }
multi infix:<*>(2, Point:D $p) is export { $p + $p }
multi infix:<*>(Int $n, Point $p) is export { 2*(($n div 2)*$p) + ($n mod 2)*$p }
}
multi infix:<>(Point \p, Point \q) {)
my = $; # slope
if p.x ~~ q.x and p.y ~~ q.y {.
return Horizon if p.y == 0 ;
λ = (3*p.x²+ A) * mult_inv(2*p.y, :modulo(P))
} else {
λ = (p.y - q.y) * mult_inv(p.x - q.x, :modulo(P)).
}
my \xr = (λ²- p.x - q.x);.
my \yr = (λ*(p.x - xr) - p.y);
return Point.bless: x => xr % P, y => yr % P
}
import EC;
multi infix:<>(Int \n, Point \p) {
return 0 if n == 0 ;
return p if n == 1 ;
return p((n-1)p ) if n % 2 == 1 ;
return ( n div 2 )( pp )
}
sub mult_inv($n, :$modulo) { # rosettacode.org/wiki/Modular_inverse#Raku
my ($c, $d, $uc, $vd, $vc, $ud, $q) = $n % $modulo, $modulo, 1, 1, 0, 0, 0;
while $c != 0 {
($q, $c, $d) = ($d div $c, $d % $c, $c);
($uc, $vc, $ud, $vd) = ($ud - $q*$uc, $vd - $q*$vc, $uc, $vc);
}
return $ud % $modulo;
}
class Signature {
has ($.n, Point $.G); # Order and Generator point
method generate_signature(Int \private_key, Str \msg) {
my \z = :16(sha256-hex msg) % $.n; # self ref: Blob.list.fmt("%02X",'')
loop ( my $k = my $s = my $r = 0 ; $s == 0 ; ) {
loop ( $r = $s = 0 ; $r == 0 ; ) {
$r = (( $k = (1..^$.n).roll )$.G).x % $.n;
}
$s = ((z + $r*private_key) * mult_inv $k, :modulo($.n)) % $.n;
module ECDSA {
use Digest::SHA256::Native;
our class Signature {
has UInt ($.c, $.d);
multi method new(Str $message, UInt :$private-key) {
my $z = :16(sha256-hex $message) % $*n;
loop (my $k = my $s = my $r = 0; $r == 0; ) {
loop ( $r = $s = 0 ; $r == 0 ; ) {
$r = (( $k = (1..^$*n).roll ) * $*G).x % $*n;
}
{
use FiniteField; my $*modulus = $*n;
$s = ($z + $r*$private-key) / $k;
}
}
return $r, $s, private_key$.G ;
}
method verify_signature(\msg, \r, \s, \public_key) {
my \z = :16(sha256-hex msg) % $.n;
my \w = mult_inv s, :modulo($.n);
my (\u1,\u2) = (z*w, r*w).map: { $_ % $.n }
my \p = (u1$.G )(u2public_key);
return (p.x % $.n) == (r % $.n)
}
samewith c => $r, d => $s;
}
multi method verify(Str $message, EC::Point :$public-key) {
my $z = :16(sha256-hex $message) % $*n;
my ($u1, $u2);
{
use FiniteField;
my $*modulus = $*n;
my $w = 1/$!d;
($u1, $u2) = $z*$w, $!c*$w;
}
my $p = ($u1 * $*G) + ($u2 * $public-key);
die unless ($p.x mod $*n) == ($!c mod $*n);
}
}
}
print "The Curve E is : ";
"𝑦² = 𝑥³ + %s 𝑥 + %s (mod %s) \n".printf(A,B,P);
"with Generator G at : (%s,%s)\n".printf(Gx,Gy);
my $ec = Signature.new: n => O, G => Point.new: x => Gx, y => Gy ;
say "Order(G, E) is : ", O;
say "Is G E ? : ", $ec.G.isOn;
say "Message : ", my \message = "Show me the monKey";
say "The private key dA is : ", my \dA = (1..^O).roll;
my ($r, $s, \Qa) = $ec.generate_signature(dA, message);
say "The public key Qa is : ", Qa;;
say "Is Qa E ? : ", Qa.isOn;.
say "Is signature valid? : ", $ec.verify_signature(message, $r, $s, Qa);)
say "Message (Tampered) : ", my \altered = "Show me the money";
say "Is signature valid? : ", $ec.verify_signature(altered, $r, $s, Qa))
my ($*a, $*b) = 355, 671;
my $*modulus = my $*p = 1073741789;
my $*G = EC::Point.new: 13693, 10088;
my $*n = 1073807281;
die "G is not of order n" if $*n*$*G;
my $private-key = ^$*n .pick;
my $public-key = $private-key*$*G;
my $message = "Show me the monKey";
my $signature = ECDSA::Signature.new: $message, :$private-key;
printf "The curve E is : 𝑦² = 𝑥³ + %s 𝑥 + %s (mod %s)\n", $*a, $*b, $*p;
printf "with generator G at : (%s, %s)\n", $*G.x, $*G.y;
printf "G's order is : %d\n", $*n;
printf "The private key is : %d\n", $private-key;
printf "The public key is at : (%s, %s)\n", $public-key.x, $public-key.y;
printf "The message is : %s\n", $message;
printf "The signature is : (%s, %s)\n", $signature.c, $signature.d;
{
use Test;
lives-ok {
$signature.verify: $message, :$public-key;
}, "good signature for <$message>";
my $altered = $message.subst(/monKey/, "money");
dies-ok {
$signature.verify: $altered, :$public-key
}, "wrong signature for <$altered>";
}