This repository was archived by the owner on May 14, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathSignature.ts
More file actions
108 lines (90 loc) · 2.86 KB
/
Copy pathSignature.ts
File metadata and controls
108 lines (90 loc) · 2.86 KB
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
107
108
import { S256Field } from "./S256Field";
import { bigToBuf, bigFromBufLE, bigFromBuf } from "../util/BigIntUtil";
import * as bufutil from "../util/BufferUtil";
import { Readable } from "stream";
/**
* Signature for secp256k1 that houses the `r` and `s` points.
*/
export class Signature {
constructor(readonly r: bigint, readonly s: bigint) {}
/**
* Decodes the DER encoded signature stream
*/
public static parse(buffer: Buffer) {
let pos = 0;
// ensure prefix
const prefix = buffer.readUInt8(pos);
if (prefix !== 0x30) {
throw new Error("Bad signature");
}
pos += 1;
// verify signature length
const len = buffer.readUInt8(pos);
if (len + 2 !== buffer.length) {
throw new Error("Bad signature length");
}
pos += 1;
// verify marker byte
let marker = buffer.readUInt8(pos);
if (marker !== 0x02) {
throw new Error("Bad signature");
}
pos += 1;
// read r-length
const rlen = buffer.readUInt8(pos);
pos += 1;
// read r
const r = bigFromBuf(buffer.slice(pos, pos + rlen));
pos += rlen;
// verify marker byte
marker = buffer.readUInt8(pos);
if (marker !== 0x02) {
throw new Error("Bad signature");
}
pos += 1;
// read s-length
const slen = buffer.readUInt8(pos);
pos += 1;
// read s
const s = bigFromBuf(buffer.slice(pos, pos + slen));
pos += slen;
// return object!
return new Signature(r, s);
}
public toString() {
return `Signature_${this.r}_${this.s}`;
}
/**
* Encodes the signature using the DER (Distinguished Encoding Rules) for
* encoding a signature with `r` and `s`.
*
* The format is defined as:
*
* 1. Start with the 0x30 byte
* 2. Encode the length of the rest of the signature (usually 0x44 or 0x45) and append
* 3. Append the marker byte 0x02
* 4. Encode r as a big-endian integer, but prepend it with the 0x00 byte if r's first
* byte >= 0x80. Prepend the resulting length to r. Add this to the result.
* 5. Append the market byte 0x02
* 6. Encode s as a big-endian integer, but prepend it with the 0x00 byte if s' first
* byte >= 0x80. Prepend the resulting length to s. Add this to the result.
*/
public der() {
const encodePart = (v: bigint) => {
// convert bigint to buffer
let bytes = bigToBuf(v);
// remove leading null bytes
bytes = bufutil.lstrip(bytes, 0x00);
// if r/s has high byte, prepend a 0x00
if (bytes[0] & 0x80) {
bytes = Buffer.concat([Buffer.from([0x00]), bytes]);
}
// prepend the marker and length to the r/s
return Buffer.concat([Buffer.from([2, bytes.length]), bytes]);
};
const r = encodePart(this.r);
const s = encodePart(this.s);
// return 0x30 + total_len + r + s
return Buffer.concat([Buffer.from([0x30, r.length + s.length]), r, s]);
}
}