-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathEcdsa.ts
60 lines (57 loc) · 2.07 KB
/
Ecdsa.ts
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
import { Rfc6979 } from "./Rfc6979";
import { Secp256k1 } from "./Secp256k1";
import { EcdsaSig } from "./EcdsaSig";
import { mod, pow } from "./util/BigIntMath";
import { CurvePoint } from "./CurvePoint";
export class Ecdsa {
/**
* Signs a message `z` using the provided `secret`. By default this
* makes the signature use a low-s value (that is s is <= n/2 where
* n is the order of the group for the curve.
*
* @param secret
* @param z hash of the message
* @param lowS indicates if BIP146 low-s compliant is required
*/
public static sign(secret: bigint, z: bigint, lowS: boolean = true): EcdsaSig {
const g = Secp256k1.group;
const k = Rfc6979.genK(secret, z, Secp256k1.N);
const r = Secp256k1.G.smul(k).x;
// const kinv = pow(k, Secp256k1.N - 2n, Secp256k1.N);
// let s = mod((z + r * secret) * kinv, Secp256k1.N);
let s = g.div(g.add(z, g.mul(r, secret)), k);
if (lowS && s > g.p / 2n) {
s = g.neg(s);
}
return new EcdsaSig(r, s);
}
/**
* Verifies a signature.
*
* The verification process is as follows:
* We are provided (r,s) as the signature and z as the hash
* of the thing being signed, and P as the public key (public point) of the signer.
*
* This calculates:
* `u = z/s`
* `v = r/s`
*
* We then calculate `uG + vP = R`
* If `R's` `x` coordinate equals `r`, then signature is valid!
*
* Implementation notes:
* - `s_inv` is calculated using Fermat's Little Theorem to calculate `1/s` since `n` is prime.
* - `uG + vP = (r,y)` but we only care about r.
*
* @point point to verify
* @param z hash of information that was signed
* @param sig signature r,s
*/
public static verify(point: CurvePoint, z: bigint, sig: EcdsaSig): boolean {
const g = Secp256k1.group;
const u = g.div(z, sig.s);
const v = g.div(sig.r, sig.s);
const total = Secp256k1.G.smul(u).add(point.smul(v));
return sig.r === total.x;
}
}