-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathecsignature.js
More file actions
128 lines (95 loc) · 3.61 KB
/
ecsignature.js
File metadata and controls
128 lines (95 loc) · 3.61 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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
var assert = require('assert')
var typeForce = require('typeforce')
var BigInteger = require('bigi')
function ECSignature (r, s) {
typeForce('BigInteger', r)
typeForce('BigInteger', s)
this.r = r
this.s = s
}
ECSignature.parseCompact = function (buffer) {
assert.equal(buffer.length, 65, 'Invalid signature length')
var i = buffer.readUInt8(0) - 27
// At most 3 bits
assert.equal(i, i & 7, 'Invalid signature parameter')
var compressed = !!(i & 4)
// Recovery param only
i = i & 3
var r = BigInteger.fromBuffer(buffer.slice(1, 33))
var s = BigInteger.fromBuffer(buffer.slice(33))
return {
compressed: compressed,
i: i,
signature: new ECSignature(r, s)
}
}
// Strict DER - https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
// NOTE: SIGHASH byte ignored
ECSignature.fromDER = function (buffer) {
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
if (buffer.length < 8) throw new Error('DER sequence too short')
if (buffer.length > 72) throw new Error('DER sequence too long')
if (buffer[0] !== 0x30) throw new Error('Not a DER sequence')
if (buffer[1] !== buffer.length - 2) throw new Error('Invalid sequence length')
if (buffer[2] !== 0x02) throw new Error('Expected a DER integer')
var lenR = buffer.readUInt8(3)
if (lenR === 0) throw new Error('R length is zero')
if (5 + lenR >= buffer.length) throw new Error('Invalid DER encoding')
if (buffer[4 + lenR] !== 0x02) throw new Error('Expected a DER integer (2)')
var lenS = buffer[5 + lenR]
if (lenS === 0) throw new Error('S length is zero')
if ((lenR + lenS + 6) !== buffer.length) throw new Error('Invalid DER encoding (2)')
if (buffer[4] & 0x80) throw new Error('R value is negative')
if (lenR > 1 && (buffer[4] === 0x00) && !(buffer[5] & 0x80)) throw new Error('R value excessively padded')
if (buffer[lenR + 6] & 0x80) throw new Error('S value is negative')
if (lenS > 1 && (buffer[lenR + 6] === 0x00) && !(buffer[lenR + 7] & 0x80)) throw new Error('S value excessively padded')
// non-BIP66 - extract R, S values
var rB = buffer.slice(4, 4 + lenR)
var sB = buffer.slice(lenR + 6)
var r = BigInteger.fromDERInteger(rB)
var s = BigInteger.fromDERInteger(sB)
return new ECSignature(r, s)
}
// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
ECSignature.parseScriptSignature = function (buffer) {
var hashType = buffer.readUInt8(buffer.length - 1)
var hashTypeMod = hashType & ~0x80
assert(hashTypeMod > 0x00 && hashTypeMod < 0x04, 'Invalid hashType ' + hashType)
return {
signature: ECSignature.fromDER(buffer.slice(0, -1)),
hashType: hashType
}
}
ECSignature.prototype.toCompact = function (i, compressed) {
if (compressed) {
i += 4
}
i += 27
var buffer = new Buffer(65)
buffer.writeUInt8(i, 0)
this.r.toBuffer(32).copy(buffer, 1)
this.s.toBuffer(32).copy(buffer, 33)
return buffer
}
ECSignature.prototype.toDER = function () {
var rBa = this.r.toDERInteger()
var sBa = this.s.toDERInteger()
var sequence = []
// INTEGER
sequence.push(0x02, rBa.length)
sequence = sequence.concat(rBa)
// INTEGER
sequence.push(0x02, sBa.length)
sequence = sequence.concat(sBa)
// SEQUENCE
sequence.unshift(0x30, sequence.length)
return new Buffer(sequence)
}
ECSignature.prototype.toScriptSignature = function (hashType) {
var hashTypeMod = hashType & ~0x80
assert(hashTypeMod > 0x00 && hashTypeMod < 0x04, 'Invalid hashType ' + hashType)
var hashTypeBuffer = new Buffer(1)
hashTypeBuffer.writeUInt8(hashType, 0)
return Buffer.concat([this.toDER(), hashTypeBuffer])
}
module.exports = ECSignature