Skip to content

Commit ec1195b

Browse files
committed
Merge pull request bitcoinjs#448 from bitcoinjs/bip66
Extract BIP66 module
2 parents 3be5dc8 + 92937a8 commit ec1195b

File tree

6 files changed

+67
-89
lines changed

6 files changed

+67
-89
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
},
4747
"dependencies": {
4848
"bigi": "^1.4.0",
49+
"bip66": "^1.1.0",
4950
"bs58check": "^1.0.5",
5051
"create-hash": "^1.1.0",
5152
"create-hmac": "^1.1.3",

src/ecsignature.js

Lines changed: 7 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
var bip66 = require('bip66')
12
var typeforce = require('typeforce')
23
var types = require('./types')
34

@@ -29,36 +30,10 @@ ECSignature.parseCompact = function (buffer) {
2930
}
3031
}
3132

32-
// Strict DER - https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
33-
// NOTE: SIGHASH byte ignored
3433
ECSignature.fromDER = function (buffer) {
35-
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
36-
if (buffer.length < 8) throw new Error('DER sequence too short')
37-
if (buffer.length > 72) throw new Error('DER sequence too long')
38-
if (buffer[0] !== 0x30) throw new Error('Not a DER sequence')
39-
if (buffer[1] !== buffer.length - 2) throw new Error('Invalid sequence length')
40-
if (buffer[2] !== 0x02) throw new Error('Expected a DER integer')
41-
42-
var lenR = buffer[3]
43-
if (lenR === 0) throw new Error('R length is zero')
44-
if (5 + lenR >= buffer.length) throw new Error('Invalid DER encoding')
45-
if (buffer[4 + lenR] !== 0x02) throw new Error('Expected a DER integer (2)')
46-
47-
var lenS = buffer[5 + lenR]
48-
if (lenS === 0) throw new Error('S length is zero')
49-
if ((lenR + lenS + 6) !== buffer.length) throw new Error('Invalid DER encoding (2)')
50-
51-
if (buffer[4] & 0x80) throw new Error('R value is negative')
52-
if (lenR > 1 && (buffer[4] === 0x00) && !(buffer[5] & 0x80)) throw new Error('R value excessively padded')
53-
54-
if (buffer[lenR + 6] & 0x80) throw new Error('S value is negative')
55-
if (lenS > 1 && (buffer[lenR + 6] === 0x00) && !(buffer[lenR + 7] & 0x80)) throw new Error('S value excessively padded')
56-
57-
// non-BIP66 - extract R, S values
58-
var rB = buffer.slice(4, 4 + lenR)
59-
var sB = buffer.slice(lenR + 6)
60-
var r = BigInteger.fromDERInteger(rB)
61-
var s = BigInteger.fromDERInteger(sB)
34+
var decode = bip66.decode(buffer)
35+
var r = BigInteger.fromDERInteger(decode.r)
36+
var s = BigInteger.fromDERInteger(decode.s)
6237

6338
return new ECSignature(r, s)
6439
}
@@ -93,23 +68,10 @@ ECSignature.prototype.toCompact = function (i, compressed) {
9368
}
9469

9570
ECSignature.prototype.toDER = function () {
96-
var rBa = this.r.toDERInteger()
97-
var sBa = this.s.toDERInteger()
71+
var r = new Buffer(this.r.toDERInteger())
72+
var s = new Buffer(this.s.toDERInteger())
9873

99-
var sequence = []
100-
101-
// INTEGER
102-
sequence.push(0x02, rBa.length)
103-
sequence = sequence.concat(rBa)
104-
105-
// INTEGER
106-
sequence.push(0x02, sBa.length)
107-
sequence = sequence.concat(sBa)
108-
109-
// SEQUENCE
110-
sequence.unshift(0x30, sequence.length)
111-
112-
return new Buffer(sequence)
74+
return bip66.encode(r, s)
11375
}
11476

11577
ECSignature.prototype.toScriptSignature = function (hashType) {

src/script.js

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1+
var bip66 = require('bip66')
12
var bufferutils = require('./bufferutils')
23
var typeforce = require('typeforce')
34
var types = require('./types')
45

5-
var ECSignature = require('./ecsignature')
6-
var ecurve = require('ecurve')
7-
var curve = ecurve.getCurveByName('secp256k1')
8-
96
var OPS = require('./opcodes')
107
var REVERSE_OPS = []
118
for (var op in OPS) {
@@ -118,34 +115,31 @@ function decompile (buffer) {
118115

119116
function isCanonicalPubKey (buffer) {
120117
if (!Buffer.isBuffer(buffer)) return false
121-
122-
try {
123-
ecurve.Point.decodeFrom(curve, buffer)
124-
} catch (e) {
125-
if (!(e.message.match(/Invalid sequence (length|tag)/))) {
126-
throw e
127-
}
128-
129-
return false
118+
if (buffer.length < 33) return false
119+
120+
switch (buffer[0]) {
121+
case 0x02:
122+
case 0x03:
123+
return buffer.length === 33
124+
case 0x04:
125+
return buffer.length === 65
130126
}
131127

132-
return true
128+
return false
133129
}
134130

135131
function isCanonicalSignature (buffer) {
136132
if (!Buffer.isBuffer(buffer)) return false
133+
if (!isDefinedHashType(buffer[buffer.length - 1])) return false
137134

138-
try {
139-
ECSignature.parseScriptSignature(buffer)
140-
} catch (e) {
141-
if (!(e.message.match(/Not a DER sequence|Invalid sequence length|Expected a DER integer|R length is zero|S length is zero|R value excessively padded|S value excessively padded|R value is negative|S value is negative|Invalid hashType/))) {
142-
throw e
143-
}
135+
return bip66.check(buffer.slice(0, -1))
136+
}
144137

145-
return false
146-
}
138+
function isDefinedHashType (hashType) {
139+
var hashTypeMod = hashType & ~0x80
147140

148-
return true
141+
// return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE
142+
return hashTypeMod > 0x00 && hashTypeMod < 0x04
149143
}
150144

151145
function isPubKeyHashInput (script) {
@@ -379,6 +373,7 @@ module.exports = {
379373

380374
isCanonicalPubKey: isCanonicalPubKey,
381375
isCanonicalSignature: isCanonicalSignature,
376+
isDefinedHashType: isDefinedHashType,
382377
isPubKeyHashInput: isPubKeyHashInput,
383378
isPubKeyHashOutput: isPubKeyHashOutput,
384379
isPubKeyInput: isPubKeyInput,

test/bitcoin.core.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,14 +243,12 @@ describe('Bitcoin-core', function () {
243243
if (i % 2 !== 0) return
244244

245245
var description = sig_noncanonical[i - 1].slice(0, -1)
246-
if (description === 'too long') return // we support non secp256k1 signatures
247-
248246
var buffer = new Buffer(hex, 'hex')
249247

250248
it('throws on ' + description, function () {
251249
assert.throws(function () {
252250
bitcoin.ECSignature.parseScriptSignature(buffer)
253-
})
251+
}, /Expected DER (integer|sequence)|(R|S) value (excessively padded|is negative)|(R|S|DER sequence) length is (zero|too short|too long|invalid)|Invalid hashType/)
254252
})
255253
})
256254
})

test/fixtures/ecsignature.json

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -130,37 +130,33 @@
130130
],
131131
"DER": [
132132
{
133-
"exception": "DER sequence too short",
133+
"exception": "DER sequence length is too short",
134134
"hex": "ffffffffffffff"
135135
},
136136
{
137-
"exception": "DER sequence too long",
137+
"exception": "DER sequence length is too long",
138138
"hex": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
139139
},
140140
{
141-
"exception": "Invalid sequence length",
141+
"exception": "Expected DER sequence",
142+
"hex": "00ffff0400ffffff020400ffffff"
143+
},
144+
{
145+
"exception": "DER sequence length is invalid",
142146
"hex": "30ff020400ffffff020400ffffff"
143147
},
144148
{
145-
"exception": "Invalid sequence length",
149+
"exception": "DER sequence length is invalid",
146150
"hex": "300c030400ffffff030400ffffff0000"
147151
},
148152
{
149-
"exception": "Expected a DER integer",
153+
"exception": "Expected DER integer",
150154
"hex": "300cff0400ffffff020400ffffff"
151155
},
152156
{
153-
"exception": "Expected a DER integer \\(2\\)",
157+
"exception": "Expected DER integer \\(2\\)",
154158
"hex": "300c020200ffffff020400ffffff"
155159
},
156-
{
157-
"exception": "Invalid DER encoding",
158-
"hex": "300c0204ddffffff020200ffffff"
159-
},
160-
{
161-
"exception": "Invalid DER encoding \\(2\\)",
162-
"hex": "300c020400ffffff02dd00ffffff"
163-
},
164160
{
165161
"exception": "R length is zero",
166162
"hex": "30080200020400ffffff"
@@ -169,13 +165,21 @@
169165
"exception": "S length is zero",
170166
"hex": "3008020400ffffff0200"
171167
},
168+
{
169+
"exception": "R length is too long",
170+
"hex": "300c02dd00ffffff020400ffffff"
171+
},
172+
{
173+
"exception": "S length is invalid",
174+
"hex": "300c020400ffffff02dd00ffffff"
175+
},
172176
{
173177
"exception": "R value is negative",
174-
"hex": "300c0204ffffffff020400ffffff"
178+
"hex": "300c020480000000020400ffffff"
175179
},
176180
{
177181
"exception": "S value is negative",
178-
"hex": "300c020400ffffff0204ffffffff"
182+
"hex": "300c020400ffffff020480000000"
179183
},
180184
{
181185
"exception": "R value excessively padded",

test/fixtures/script.json

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,26 @@
178178
],
179179
"isPubKeyInput": [
180180
{
181-
"description": "non-canonical signature",
182-
"scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf7593ffffffffffffffff"
181+
"description": "non-canonical signature (too short)",
182+
"scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf7593"
183+
},
184+
{
185+
"description": "non-canonical signature (too long)",
186+
"scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca28ffffffff01"
187+
},
188+
{
189+
"description": "non-canonical signature (invalid hashType)",
190+
"scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca28ff"
191+
}
192+
],
193+
"isPubKeyOutput": [
194+
{
195+
"description": "non-canonical pubkey (too short)",
196+
"scriptPubKey": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce OP_CHECKSIG"
197+
},
198+
{
199+
"description": "non-canonical pubkey (too long)",
200+
"scriptPubKey": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1ffffff OP_CHECKSIG"
183201
}
184202
],
185203
"isMultisigOutput": [

0 commit comments

Comments
 (0)