-
Notifications
You must be signed in to change notification settings - Fork 17
/
ecdsa.js
106 lines (98 loc) · 2.96 KB
/
ecdsa.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/* Author: Willem Hengeveld <itsme@xs4all.nl> */
/* https://github.com/nlitsme/bitcoinexplainer */
"use strict";
/*
* Elliptic curve Digital Signature Algorithm
*
* scalar(x) - convert the number 'x' to a Value in the grouporder field.
* calcpub(x) - calculate a public key for the private key 'x'
* sign(m, x, k) - sign message 'm' with privatekey 'x', and signing secret 'k'.
* verify(m, Y, r, s) - verify the signatue
* crack2(r, m1, m2, s1, s2) - crack a key for a pair of signatures with re-used 'k' value.
* crack1r(k, m, r, s) - crack a key, given the signing secret, and 'r' value
* crack1(k, m, s) - crack a key, given the signing secret.
* findk(m, x, r, s) - calculate 'k' for a signature and known private key.
* findpk(m, r, s, flag) - find the public key used to create a signature.
*/
class ECDSA {
constructor(ec, G)
{
this.ec = ec;
this.G = G;
}
// changes 'x' to be of galois field 'n'
scalar(x) { return this.ec.order.value(x); }
/* calculate a public key from a private key.
*
* Return value: the public key point.
*/
calcpub(x)
{
return this.G.mul(x);
}
/* create a signature.
*
* Return value: a tuple of 'r' and 's'.
*/
sign(m, x, k)
{
var R = this.G.mul(k);
var s = m.add(x.mul(this.scalar(R.x))).div(k);
return [R.x, s];
}
/* Verify a signature.
*
* Return value: true when the signature is correct.
*/
verify(m, Y, r, s)
{
var R = this.G.mul(m).add(Y.mul(r)).div(s);
return r.equals(this.scalar(R.x));
}
/* Crack a key given a pair of signatures with the same 'r'.
*
* Return value: a tuple of the signing secret, and the secret key.
*/
crack2(r, m1, m2, s1, s2)
{
var k = m1.sub(m2).div(s1.sub(s2))
var x1 = this.crack1r(k, m1, r, s1);
var x2 = this.crack1r(k, m2, r, s2);
if (x1.equals(x2))
return [k, x1];
console.log("unexpectedly: x1 != x2");
console.log("k=", k);
console.log("x1=", x1);
console.log("x2=", x2);
return [0, 0];
}
/* this variant of crack1 assumes we already have calculated 'r',
* and can directly calculate 'x'.
*
* Return value: the secret key
*/
crack1r(k, m, r, s)
{
return s.mul(k).sub(m).div(r);
}
/* this variant of crack1, calculates r, then calls crack1r.
*
* Return value: the secret key
*/
crack1(k, m, s)
{
var R = this.G.mul(k);
// we have to convert the x coord of R from the galois field with order 'p'
// to the field with order 'n'
return this.crack1r(k, m, this.scalar(R.x), s);
}
findk(m, x, r, s)
{
return m.add(x.mul(r)).div(s);
}
findpk(m, r, s, flag)
{
var R = this.ec.decompress(this.ec.coord(r), flag);
return R.mul(s.div(r)).sub(this.G.mul(m.div(r)));
}
};