commit
ec1195bcee
6 changed files with 66 additions and 88 deletions
|
@ -46,6 +46,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bigi": "^1.4.0",
|
"bigi": "^1.4.0",
|
||||||
|
"bip66": "^1.1.0",
|
||||||
"bs58check": "^1.0.5",
|
"bs58check": "^1.0.5",
|
||||||
"create-hash": "^1.1.0",
|
"create-hash": "^1.1.0",
|
||||||
"create-hmac": "^1.1.3",
|
"create-hmac": "^1.1.3",
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
var bip66 = require('bip66')
|
||||||
var typeforce = require('typeforce')
|
var typeforce = require('typeforce')
|
||||||
var types = require('./types')
|
var types = require('./types')
|
||||||
|
|
||||||
|
@ -29,36 +30,10 @@ ECSignature.parseCompact = function (buffer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strict DER - https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
|
|
||||||
// NOTE: SIGHASH byte ignored
|
|
||||||
ECSignature.fromDER = function (buffer) {
|
ECSignature.fromDER = function (buffer) {
|
||||||
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
|
var decode = bip66.decode(buffer)
|
||||||
if (buffer.length < 8) throw new Error('DER sequence too short')
|
var r = BigInteger.fromDERInteger(decode.r)
|
||||||
if (buffer.length > 72) throw new Error('DER sequence too long')
|
var s = BigInteger.fromDERInteger(decode.s)
|
||||||
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[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)
|
return new ECSignature(r, s)
|
||||||
}
|
}
|
||||||
|
@ -93,23 +68,10 @@ ECSignature.prototype.toCompact = function (i, compressed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ECSignature.prototype.toDER = function () {
|
ECSignature.prototype.toDER = function () {
|
||||||
var rBa = this.r.toDERInteger()
|
var r = new Buffer(this.r.toDERInteger())
|
||||||
var sBa = this.s.toDERInteger()
|
var s = new Buffer(this.s.toDERInteger())
|
||||||
|
|
||||||
var sequence = []
|
return bip66.encode(r, s)
|
||||||
|
|
||||||
// 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) {
|
ECSignature.prototype.toScriptSignature = function (hashType) {
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
|
var bip66 = require('bip66')
|
||||||
var bufferutils = require('./bufferutils')
|
var bufferutils = require('./bufferutils')
|
||||||
var typeforce = require('typeforce')
|
var typeforce = require('typeforce')
|
||||||
var types = require('./types')
|
var types = require('./types')
|
||||||
|
|
||||||
var ECSignature = require('./ecsignature')
|
|
||||||
var ecurve = require('ecurve')
|
|
||||||
var curve = ecurve.getCurveByName('secp256k1')
|
|
||||||
|
|
||||||
var OPS = require('./opcodes')
|
var OPS = require('./opcodes')
|
||||||
var REVERSE_OPS = []
|
var REVERSE_OPS = []
|
||||||
for (var op in OPS) {
|
for (var op in OPS) {
|
||||||
|
@ -118,34 +115,31 @@ function decompile (buffer) {
|
||||||
|
|
||||||
function isCanonicalPubKey (buffer) {
|
function isCanonicalPubKey (buffer) {
|
||||||
if (!Buffer.isBuffer(buffer)) return false
|
if (!Buffer.isBuffer(buffer)) return false
|
||||||
|
if (buffer.length < 33) return false
|
||||||
|
|
||||||
try {
|
switch (buffer[0]) {
|
||||||
ecurve.Point.decodeFrom(curve, buffer)
|
case 0x02:
|
||||||
} catch (e) {
|
case 0x03:
|
||||||
if (!(e.message.match(/Invalid sequence (length|tag)/))) {
|
return buffer.length === 33
|
||||||
throw e
|
case 0x04:
|
||||||
|
return buffer.length === 65
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
function isCanonicalSignature (buffer) {
|
function isCanonicalSignature (buffer) {
|
||||||
if (!Buffer.isBuffer(buffer)) return false
|
if (!Buffer.isBuffer(buffer)) return false
|
||||||
|
if (!isDefinedHashType(buffer[buffer.length - 1])) return false
|
||||||
|
|
||||||
try {
|
return bip66.check(buffer.slice(0, -1))
|
||||||
ECSignature.parseScriptSignature(buffer)
|
|
||||||
} catch (e) {
|
|
||||||
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/))) {
|
|
||||||
throw e
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
function isDefinedHashType (hashType) {
|
||||||
}
|
var hashTypeMod = hashType & ~0x80
|
||||||
|
|
||||||
return true
|
// return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE
|
||||||
|
return hashTypeMod > 0x00 && hashTypeMod < 0x04
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPubKeyHashInput (script) {
|
function isPubKeyHashInput (script) {
|
||||||
|
@ -379,6 +373,7 @@ module.exports = {
|
||||||
|
|
||||||
isCanonicalPubKey: isCanonicalPubKey,
|
isCanonicalPubKey: isCanonicalPubKey,
|
||||||
isCanonicalSignature: isCanonicalSignature,
|
isCanonicalSignature: isCanonicalSignature,
|
||||||
|
isDefinedHashType: isDefinedHashType,
|
||||||
isPubKeyHashInput: isPubKeyHashInput,
|
isPubKeyHashInput: isPubKeyHashInput,
|
||||||
isPubKeyHashOutput: isPubKeyHashOutput,
|
isPubKeyHashOutput: isPubKeyHashOutput,
|
||||||
isPubKeyInput: isPubKeyInput,
|
isPubKeyInput: isPubKeyInput,
|
||||||
|
|
|
@ -243,14 +243,12 @@ describe('Bitcoin-core', function () {
|
||||||
if (i % 2 !== 0) return
|
if (i % 2 !== 0) return
|
||||||
|
|
||||||
var description = sig_noncanonical[i - 1].slice(0, -1)
|
var description = sig_noncanonical[i - 1].slice(0, -1)
|
||||||
if (description === 'too long') return // we support non secp256k1 signatures
|
|
||||||
|
|
||||||
var buffer = new Buffer(hex, 'hex')
|
var buffer = new Buffer(hex, 'hex')
|
||||||
|
|
||||||
it('throws on ' + description, function () {
|
it('throws on ' + description, function () {
|
||||||
assert.throws(function () {
|
assert.throws(function () {
|
||||||
bitcoin.ECSignature.parseScriptSignature(buffer)
|
bitcoin.ECSignature.parseScriptSignature(buffer)
|
||||||
})
|
}, /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/)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
36
test/fixtures/ecsignature.json
vendored
36
test/fixtures/ecsignature.json
vendored
|
@ -130,37 +130,33 @@
|
||||||
],
|
],
|
||||||
"DER": [
|
"DER": [
|
||||||
{
|
{
|
||||||
"exception": "DER sequence too short",
|
"exception": "DER sequence length is too short",
|
||||||
"hex": "ffffffffffffff"
|
"hex": "ffffffffffffff"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"exception": "DER sequence too long",
|
"exception": "DER sequence length is too long",
|
||||||
"hex": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
"hex": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"exception": "Invalid sequence length",
|
"exception": "Expected DER sequence",
|
||||||
|
"hex": "00ffff0400ffffff020400ffffff"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exception": "DER sequence length is invalid",
|
||||||
"hex": "30ff020400ffffff020400ffffff"
|
"hex": "30ff020400ffffff020400ffffff"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"exception": "Invalid sequence length",
|
"exception": "DER sequence length is invalid",
|
||||||
"hex": "300c030400ffffff030400ffffff0000"
|
"hex": "300c030400ffffff030400ffffff0000"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"exception": "Expected a DER integer",
|
"exception": "Expected DER integer",
|
||||||
"hex": "300cff0400ffffff020400ffffff"
|
"hex": "300cff0400ffffff020400ffffff"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"exception": "Expected a DER integer \\(2\\)",
|
"exception": "Expected DER integer \\(2\\)",
|
||||||
"hex": "300c020200ffffff020400ffffff"
|
"hex": "300c020200ffffff020400ffffff"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"exception": "Invalid DER encoding",
|
|
||||||
"hex": "300c0204ddffffff020200ffffff"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"exception": "Invalid DER encoding \\(2\\)",
|
|
||||||
"hex": "300c020400ffffff02dd00ffffff"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"exception": "R length is zero",
|
"exception": "R length is zero",
|
||||||
"hex": "30080200020400ffffff"
|
"hex": "30080200020400ffffff"
|
||||||
|
@ -169,13 +165,21 @@
|
||||||
"exception": "S length is zero",
|
"exception": "S length is zero",
|
||||||
"hex": "3008020400ffffff0200"
|
"hex": "3008020400ffffff0200"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"exception": "R length is too long",
|
||||||
|
"hex": "300c02dd00ffffff020400ffffff"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exception": "S length is invalid",
|
||||||
|
"hex": "300c020400ffffff02dd00ffffff"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"exception": "R value is negative",
|
"exception": "R value is negative",
|
||||||
"hex": "300c0204ffffffff020400ffffff"
|
"hex": "300c020480000000020400ffffff"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"exception": "S value is negative",
|
"exception": "S value is negative",
|
||||||
"hex": "300c020400ffffff0204ffffffff"
|
"hex": "300c020400ffffff020480000000"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"exception": "R value excessively padded",
|
"exception": "R value excessively padded",
|
||||||
|
|
22
test/fixtures/script.json
vendored
22
test/fixtures/script.json
vendored
|
@ -178,8 +178,26 @@
|
||||||
],
|
],
|
||||||
"isPubKeyInput": [
|
"isPubKeyInput": [
|
||||||
{
|
{
|
||||||
"description": "non-canonical signature",
|
"description": "non-canonical signature (too short)",
|
||||||
"scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf7593ffffffffffffffff"
|
"scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf7593"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "non-canonical signature (too long)",
|
||||||
|
"scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca28ffffffff01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "non-canonical signature (invalid hashType)",
|
||||||
|
"scriptSig": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca28ff"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isPubKeyOutput": [
|
||||||
|
{
|
||||||
|
"description": "non-canonical pubkey (too short)",
|
||||||
|
"scriptPubKey": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce OP_CHECKSIG"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "non-canonical pubkey (too long)",
|
||||||
|
"scriptPubKey": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1ffffff OP_CHECKSIG"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"isMultisigOutput": [
|
"isMultisigOutput": [
|
||||||
|
|
Loading…
Reference in a new issue