rm ECSignature, add script.signature instead

This commit is contained in:
Daniel Cousens 2016-10-13 23:45:08 +11:00
parent 77e317d618
commit c58ada362e
14 changed files with 335 additions and 149 deletions

View file

@ -4,7 +4,6 @@ var typeforce = require('typeforce')
var types = require('./types') var types = require('./types')
var BigInteger = require('bigi') var BigInteger = require('bigi')
var ECSignature = require('./ecsignature')
var ZERO = Buffer.alloc(1, 0) var ZERO = Buffer.alloc(1, 0)
var ONE = Buffer.alloc(1, 1) var ONE = Buffer.alloc(1, 1)
@ -102,7 +101,10 @@ function sign (hash, d) {
s = n.subtract(s) s = n.subtract(s)
} }
return new ECSignature(r, s) return {
r: r,
s: s
}
} }
function verify (hash, signature, Q) { function verify (hash, signature, Q) {

View file

@ -1,97 +0,0 @@
var bip66 = require('bip66')
var typeforce = require('typeforce')
var types = require('./types')
var BigInteger = require('bigi')
function ECSignature (r, s) {
typeforce(types.tuple(types.BigInt, types.BigInt), arguments)
this.r = r
this.s = s
}
ECSignature.parseCompact = function (buffer) {
typeforce(types.BufferN(65), buffer)
var flagByte = buffer.readUInt8(0) - 27
if (flagByte !== (flagByte & 7)) throw new Error('Invalid signature parameter')
var compressed = !!(flagByte & 4)
var recoveryParam = flagByte & 3
var signature = ECSignature.fromRSBuffer(buffer.slice(1))
return {
compressed: compressed,
i: recoveryParam,
signature: signature
}
}
ECSignature.fromRSBuffer = function (buffer) {
typeforce(types.BufferN(64), buffer)
var r = BigInteger.fromBuffer(buffer.slice(0, 32))
var s = BigInteger.fromBuffer(buffer.slice(32, 64))
return new ECSignature(r, s)
}
ECSignature.fromDER = function (buffer) {
var decode = bip66.decode(buffer)
var r = BigInteger.fromDERInteger(decode.r)
var s = BigInteger.fromDERInteger(decode.s)
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
if (hashTypeMod <= 0x00 || hashTypeMod >= 0x04) throw new Error('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 = Buffer.alloc(65)
buffer.writeUInt8(i, 0)
this.toRSBuffer(buffer, 1)
return buffer
}
ECSignature.prototype.toDER = function () {
var r = Buffer.from(this.r.toDERInteger())
var s = Buffer.from(this.s.toDERInteger())
return bip66.encode(r, s)
}
ECSignature.prototype.toRSBuffer = function (buffer, offset) {
buffer = buffer || Buffer.alloc(64)
this.r.toBuffer(32).copy(buffer, offset)
this.s.toBuffer(32).copy(buffer, offset + 32)
return buffer
}
ECSignature.prototype.toScriptSignature = function (hashType) {
var hashTypeMod = hashType & ~0x80
if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType)
var hashTypeBuffer = Buffer.alloc(1)
hashTypeBuffer.writeUInt8(hashType, 0)
return Buffer.concat([this.toDER(), hashTypeBuffer])
}
module.exports = ECSignature

View file

@ -8,7 +8,6 @@ for (var key in templates) {
module.exports = { module.exports = {
Block: require('./block'), Block: require('./block'),
ECPair: require('./ecpair'), ECPair: require('./ecpair'),
ECSignature: require('./ecsignature'),
HDNode: require('./hdnode'), HDNode: require('./hdnode'),
Transaction: require('./transaction'), Transaction: require('./transaction'),
TransactionBuilder: require('./transaction_builder'), TransactionBuilder: require('./transaction_builder'),

View file

@ -206,6 +206,7 @@ module.exports = {
toStack: toStack, toStack: toStack,
number: require('./script_number'), number: require('./script_number'),
signature: require('./script_signature'),
isCanonicalPubKey: isCanonicalPubKey, isCanonicalPubKey: isCanonicalPubKey,
isCanonicalSignature: isCanonicalSignature, isCanonicalSignature: isCanonicalSignature,

51
src/script_signature.js Normal file
View file

@ -0,0 +1,51 @@
var bip66 = require('bip66')
var BigInteger = require('bigi')
var typeforce = require('typeforce')
var types = require('./types')
// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
function decode (buffer) {
var hashType = buffer.readUInt8(buffer.length - 1)
var hashTypeMod = hashType & ~0x80
if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType)
var decode = bip66.decode(buffer.slice(0, -1))
return {
signature: {
r: BigInteger.fromDERInteger(decode.r),
s: BigInteger.fromDERInteger(decode.s)
},
hashType: hashType
}
}
function fromRSBuffer (buffer) {
typeforce(types.BufferN(64), buffer)
var r = BigInteger.fromBuffer(buffer.slice(0, 32))
var s = BigInteger.fromBuffer(buffer.slice(32, 64))
return { r: r, s: s }
}
function encode (signature, hashType) {
var hashTypeMod = hashType & ~0x80
if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType)
var hashTypeBuffer = new Buffer(1)
hashTypeBuffer.writeUInt8(hashType, 0)
var r = new Buffer(signature.r.toDERInteger())
var s = new Buffer(signature.s.toDERInteger())
return Buffer.concat([
bip66.encode(r, s),
hashTypeBuffer
])
}
module.exports = {
fromRSBuffer,
decode: decode,
encode: encode
}

View file

@ -12,7 +12,6 @@ var SIGNABLE = [btemplates.types.P2PKH, btemplates.types.P2PK, btemplates.types.
var P2SH = SIGNABLE.concat([btemplates.types.P2WPKH, btemplates.types.P2WSH]) var P2SH = SIGNABLE.concat([btemplates.types.P2WPKH, btemplates.types.P2WSH])
var ECPair = require('./ecpair') var ECPair = require('./ecpair')
var ECSignature = require('./ecsignature')
var Transaction = require('./transaction') var Transaction = require('./transaction')
function supportedType (type) { function supportedType (type) {
@ -190,7 +189,7 @@ function fixMultisigOrder (input, transaction, vin) {
if (!signature) return false if (!signature) return false
// TODO: avoid O(n) hashForSignature // TODO: avoid O(n) hashForSignature
var parsed = ECSignature.parseScriptSignature(signature) var parsed = bscript.signature.decode(signature)
var hash = transaction.hashForSignature(vin, input.redeemScript, parsed.hashType) var hash = transaction.hashForSignature(vin, input.redeemScript, parsed.hashType)
// skip if signature does not match pubKey // skip if signature does not match pubKey
@ -717,9 +716,9 @@ TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashTy
)) throw new Error('BIP143 rejects uncompressed public keys in P2WPKH or P2WSH') )) throw new Error('BIP143 rejects uncompressed public keys in P2WPKH or P2WSH')
var signature = keyPair.sign(signatureHash) var signature = keyPair.sign(signatureHash)
if (Buffer.isBuffer(signature)) signature = ECSignature.fromRSBuffer(signature) if (Buffer.isBuffer(signature)) signature = bscript.signature.fromRSBuffer(signature)
input.signatures[i] = signature.toScriptSignature(hashType) input.signatures[i] = bscript.signature.encode(signature, hashType)
return true return true
}) })

View file

@ -198,13 +198,14 @@ describe('Bitcoin-core', function () {
}) })
}) })
describe('ECSignature.parseScriptSignature', function () { describe('script.signature.decode', function () {
sigCanonical.forEach(function (hex) { sigCanonical.forEach(function (hex) {
var buffer = Buffer.from(hex, 'hex') var buffer = Buffer.from(hex, 'hex')
it('can parse ' + hex, function () { it('can parse ' + hex, function () {
var parsed = bitcoin.ECSignature.parseScriptSignature(buffer) var parsed = bitcoin.script.signature.decode(buffer)
var actual = parsed.signature.toScriptSignature(parsed.hashType) var actual = bitcoin.script.signature.encode(parsed.signature, parsed.hashType)
assert.strictEqual(actual.toString('hex'), hex) assert.strictEqual(actual.toString('hex'), hex)
}) })
}) })
@ -218,7 +219,7 @@ describe('Bitcoin-core', function () {
it('throws on ' + description, function () { it('throws on ' + description, function () {
assert.throws(function () { assert.throws(function () {
bitcoin.ECSignature.parseScriptSignature(buffer) bitcoin.script.signature.decode(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/) }, /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/)
}) })
}) })

View file

@ -2,17 +2,31 @@
var assert = require('assert') var assert = require('assert')
var bcrypto = require('../src/crypto') var bcrypto = require('../src/crypto')
var bscript = require('../src/script')
var ecdsa = require('../src/ecdsa') var ecdsa = require('../src/ecdsa')
var hoodwink = require('hoodwink') var hoodwink = require('hoodwink')
var BigInteger = require('bigi') var BigInteger = require('bigi')
var ECSignature = require('../src/ecsignature')
var curve = ecdsa.__curve var curve = ecdsa.__curve
var fixtures = require('./fixtures/ecdsa.json') var fixtures = require('./fixtures/ecdsa.json')
describe('ecdsa', function () { describe('ecdsa', function () {
function fromRaw (signature) {
return {
r: new BigInteger(signature.r, 16),
s: new BigInteger(signature.s, 16)
}
}
function toRaw (signature) {
return {
r: signature.r.toHex(),
s: signature.s.toHex()
}
}
describe('deterministicGenerateK', function () { describe('deterministicGenerateK', function () {
function checkSig () { function checkSig () {
return true return true
@ -80,9 +94,9 @@ describe('ecdsa', function () {
it('produces a deterministic signature for "' + f.message + '"', function () { it('produces a deterministic signature for "' + f.message + '"', function () {
var d = BigInteger.fromHex(f.d) var d = BigInteger.fromHex(f.d)
var hash = bcrypto.sha256(f.message) var hash = bcrypto.sha256(f.message)
var signature = ecdsa.sign(hash, d).toDER() var signature = ecdsa.sign(hash, d)
assert.strictEqual(signature.toString('hex'), f.signature) assert.deepEqual(toRaw(signature), f.signature)
}) })
}) })
@ -101,7 +115,7 @@ describe('ecdsa', function () {
it('verifies a valid signature for "' + f.message + '"', function () { it('verifies a valid signature for "' + f.message + '"', function () {
var d = BigInteger.fromHex(f.d) var d = BigInteger.fromHex(f.d)
var H = bcrypto.sha256(f.message) var H = bcrypto.sha256(f.message)
var signature = ECSignature.fromDER(Buffer.from(f.signature, 'hex')) var signature = fromRaw(f.signature)
var Q = curve.G.multiply(d) var Q = curve.G.multiply(d)
assert(ecdsa.verify(H, signature, Q)) assert(ecdsa.verify(H, signature, Q))
@ -112,14 +126,7 @@ describe('ecdsa', function () {
it('fails to verify with ' + f.description, function () { it('fails to verify with ' + f.description, function () {
var H = bcrypto.sha256(f.message) var H = bcrypto.sha256(f.message)
var d = BigInteger.fromHex(f.d) var d = BigInteger.fromHex(f.d)
var signature = fromRaw(f.signature)
var signature
if (f.signature) {
signature = ECSignature.fromDER(Buffer.from(f.signature, 'hex'))
} else if (f.signatureRaw) {
signature = new ECSignature(new BigInteger(f.signatureRaw.r, 16), new BigInteger(f.signatureRaw.s, 16))
}
var Q = curve.G.multiply(d) var Q = curve.G.multiply(d)
assert.strictEqual(ecdsa.verify(H, signature, Q), false) assert.strictEqual(ecdsa.verify(H, signature, Q), false)

View file

@ -5,50 +5,64 @@
"d": "01", "d": "01",
"k": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5", "k": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5",
"message": "Everything should be made as simple as possible, but not simpler.", "message": "Everything should be made as simple as possible, but not simpler.",
"i": 0, "signature": {
"signature": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262" "r": "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c9",
"s": "6f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"
}
}, },
{ {
"d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
"k": "9dc74cbfd383980fb4ae5d2680acddac9dac956dca65a28c80ac9c847c2374e4", "k": "9dc74cbfd383980fb4ae5d2680acddac9dac956dca65a28c80ac9c847c2374e4",
"message": "Equations are more important to me, because politics is for the present, but an equation is something for eternity.", "message": "Equations are more important to me, because politics is for the present, but an equation is something for eternity.",
"i": 0, "signature": {
"signature": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5" "r": "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed",
"s": "07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
}
}, },
{ {
"d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
"k": "fd27071f01648ebbdd3e1cfbae48facc9fa97edc43bbbc9a7fdc28eae13296f5", "k": "fd27071f01648ebbdd3e1cfbae48facc9fa97edc43bbbc9a7fdc28eae13296f5",
"message": "Not only is the Universe stranger than we think, it is stranger than we can think.", "message": "Not only is the Universe stranger than we think, it is stranger than we can think.",
"i": 0, "signature": {
"signature": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283" "r": "ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd0",
"s": "6fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"
}
}, },
{ {
"d": "0000000000000000000000000000000000000000000000000000000000000001", "d": "0000000000000000000000000000000000000000000000000000000000000001",
"k": "f0cd2ba5fc7c183de589f6416220a36775a146740798756d8d949f7166dcc87f", "k": "f0cd2ba5fc7c183de589f6416220a36775a146740798756d8d949f7166dcc87f",
"message": "How wonderful that we have met with a paradox. Now we have some hope of making progress.", "message": "How wonderful that we have met with a paradox. Now we have some hope of making progress.",
"i": 1, "signature": {
"signature": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3" "r": "c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3",
"s": "75afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"
}
}, },
{ {
"d": "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64", "d": "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64",
"k": "6bb4a594ad57c1aa22dbe991a9d8501daf4688bf50a4892ef21bd7c711afda97", "k": "6bb4a594ad57c1aa22dbe991a9d8501daf4688bf50a4892ef21bd7c711afda97",
"message": "Computer science is no more about computers than astronomy is about telescopes.", "message": "Computer science is no more about computers than astronomy is about telescopes.",
"i": 0, "signature": {
"signature": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6" "r": "7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d",
"s": "0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"
}
}, },
{ {
"d": "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637", "d": "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637",
"k": "097b5c8ee22c3ea78a4d3635e0ff6fe85a1eb92ce317ded90b9e71aab2b861cb", "k": "097b5c8ee22c3ea78a4d3635e0ff6fe85a1eb92ce317ded90b9e71aab2b861cb",
"message": "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough", "message": "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough",
"i": 1, "signature": {
"signature": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37" "r": "fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda487",
"s": "0e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37"
}
}, },
{ {
"d": "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3", "d": "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3",
"k": "19355c36c8cbcdfb2382e23b194b79f8c97bf650040fc7728dfbf6b39a97c25b", "k": "19355c36c8cbcdfb2382e23b194b79f8c97bf650040fc7728dfbf6b39a97c25b",
"message": "The question of whether computers can think is like the question of whether submarines can swim.", "message": "The question of whether computers can think is like the question of whether submarines can swim.",
"i": 1, "signature": {
"signature": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef" "r": "cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9",
"s": "06ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"
}
} }
], ],
"rfc6979": [ "rfc6979": [
@ -130,13 +144,16 @@
"description": "The wrong signature", "description": "The wrong signature",
"d": "01", "d": "01",
"message": "foo", "message": "foo",
"signature": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5" "signature": {
"r": "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed",
"s": "07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
}
}, },
{ {
"description": "Invalid r value (< 0)", "description": "Invalid r value (< 0)",
"d": "01", "d": "01",
"message": "foo", "message": "foo",
"signatureRaw": { "signature": {
"r": "-01", "r": "-01",
"s": "02" "s": "02"
} }
@ -145,7 +162,7 @@
"description": "Invalid r value (== 0)", "description": "Invalid r value (== 0)",
"d": "01", "d": "01",
"message": "foo", "message": "foo",
"signatureRaw": { "signature": {
"r": "00", "r": "00",
"s": "02" "s": "02"
} }
@ -154,7 +171,7 @@
"description": "Invalid r value (>= n)", "description": "Invalid r value (>= n)",
"d": "01", "d": "01",
"message": "foo", "message": "foo",
"signatureRaw": { "signature": {
"r": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", "r": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
"s": "02" "s": "02"
} }
@ -163,7 +180,7 @@
"description": "Invalid s value (< 0)", "description": "Invalid s value (< 0)",
"d": "01", "d": "01",
"message": "foo", "message": "foo",
"signatureRaw": { "signature": {
"r": "02", "r": "02",
"s": "-01" "s": "-01"
} }
@ -172,7 +189,7 @@
"description": "Invalid s value (== 0)", "description": "Invalid s value (== 0)",
"d": "01", "d": "01",
"message": "foo", "message": "foo",
"signatureRaw": { "signature": {
"r": "02", "r": "02",
"s": "00" "s": "00"
} }
@ -181,7 +198,7 @@
"description": "Invalid s value (>= n)", "description": "Invalid s value (>= n)",
"d": "01", "d": "01",
"message": "foo", "message": "foo",
"signatureRaw": { "signature": {
"r": "02", "r": "02",
"s": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" "s": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
} }
@ -190,7 +207,7 @@
"description": "Invalid r, s values (r = s = -n)", "description": "Invalid r, s values (r = s = -n)",
"d": "01", "d": "01",
"message": "foo", "message": "foo",
"signatureRaw": { "signature": {
"r": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", "r": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
"s": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" "s": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
} }

140
test/fixtures/signature.json vendored Normal file
View file

@ -0,0 +1,140 @@
{
"valid": [
{
"hashType": 1,
"hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226201",
"raw": {
"r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
"s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
}
},
{
"hashType": 2,
"hex": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a502",
"raw": {
"r": "38341707918488238920692284707283974715538935465589664377561695343399725051885",
"s": "3180566392414476763164587487324397066658063772201694230600609996154610926757"
}
},
{
"hashType": 3,
"hex": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b28303",
"raw": {
"r": "115464191557905790016094131873849783294273568009648050793030031933291767741904",
"s": "50562520307781850052192542766631199590053690478900449960232079510155113443971"
}
},
{
"hashType": 129,
"hex": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d381",
"raw": {
"r": "87230998027579607140680851455601772643840468630989315269459846730712163783123",
"s": "53231320085894623106179381504478252331065330583563809963303318469380290929875"
}
},
{
"hashType": 130,
"hex": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df682",
"raw": {
"r": "51348483531757779992459563033975330355971795607481991320287437101831125115997",
"s": "6277080015686056199074771961940657638578000617958603212944619747099038735862"
}
},
{
"hashType": 131,
"hex": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd3783",
"raw": {
"r": "113979859486826658566290715281614250298918272782414232881639314569529560769671",
"s": "6517071009538626957379450615706485096874328019806177698938278220732027419959"
}
},
{
"hashType": 129,
"hex": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef81",
"raw": {
"r": "93122007060065279508564838030979550535085999589142852106617159184757394422777",
"s": "3078539468410661027472930027406594684630312677495124015420811882501887769839"
}
}
],
"invalid": [
{
"exception": "DER sequence length is too short",
"hex": "ffffffffffffff01"
},
{
"exception": "DER sequence length is too long",
"hex": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01"
},
{
"exception": "Expected DER sequence",
"hex": "00ffff0400ffffff020400ffffff01"
},
{
"exception": "DER sequence length is invalid",
"hex": "30ff020400ffffff020400ffffff01"
},
{
"exception": "DER sequence length is invalid",
"hex": "300c030400ffffff030400ffffff000001"
},
{
"exception": "Expected DER integer",
"hex": "300cff0400ffffff020400ffffff01"
},
{
"exception": "Expected DER integer \\(2\\)",
"hex": "300c020200ffffff020400ffffff01"
},
{
"exception": "R length is zero",
"hex": "30080200020400ffffff01"
},
{
"exception": "S length is zero",
"hex": "3008020400ffffff020001"
},
{
"exception": "R length is too long",
"hex": "300c02dd00ffffff020400ffffff01"
},
{
"exception": "S length is invalid",
"hex": "300c020400ffffff02dd00ffffff01"
},
{
"exception": "R value is negative",
"hex": "300c020480000000020400ffffff01"
},
{
"exception": "S value is negative",
"hex": "300c020400ffffff02048000000001"
},
{
"exception": "R value excessively padded",
"hex": "300c02040000ffff020400ffffff01"
},
{
"exception": "S value excessively padded",
"hex": "300c020400ffffff02040000ffff01"
},
{
"exception": "Invalid hashType 7",
"hashType": 7,
"hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226207",
"raw": {
"r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
"s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
}
},
{
"exception": "Invalid hashType 140",
"hashType": 140,
"hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa543422628c",
"raw": {
"r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
"s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
}
}
]
}

View file

@ -56,7 +56,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
var tx = txb.buildIncomplete() var tx = txb.buildIncomplete()
var signatureHash = tx.hashForSignature(0, redeemScript, hashType) var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
var redeemScriptSig = bitcoin.script.scriptHash.input.encode([ var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
alice.sign(signatureHash).toScriptSignature(hashType), bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
bitcoin.opcodes.OP_TRUE bitcoin.opcodes.OP_TRUE
], redeemScript) ], redeemScript)
tx.setInputScript(0, redeemScriptSig) tx.setInputScript(0, redeemScriptSig)
@ -100,7 +100,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
var tx = txb.buildIncomplete() var tx = txb.buildIncomplete()
var signatureHash = tx.hashForSignature(0, redeemScript, hashType) var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
var redeemScriptSig = bitcoin.script.scriptHash.input.encode([ var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
alice.sign(signatureHash).toScriptSignature(hashType), bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
bitcoin.opcodes.OP_TRUE bitcoin.opcodes.OP_TRUE
], redeemScript) ], redeemScript)
tx.setInputScript(0, redeemScriptSig) tx.setInputScript(0, redeemScriptSig)
@ -154,8 +154,8 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
var tx = txb.buildIncomplete() var tx = txb.buildIncomplete()
var signatureHash = tx.hashForSignature(0, redeemScript, hashType) var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
var redeemScriptSig = bitcoin.script.scriptHash.input.encode([ var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
alice.sign(signatureHash).toScriptSignature(hashType), bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
bob.sign(signatureHash).toScriptSignature(hashType), bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
bitcoin.opcodes.OP_FALSE bitcoin.opcodes.OP_FALSE
], redeemScript) ], redeemScript)
tx.setInputScript(0, redeemScriptSig) tx.setInputScript(0, redeemScriptSig)
@ -196,7 +196,8 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
var tx = txb.buildIncomplete() var tx = txb.buildIncomplete()
var signatureHash = tx.hashForSignature(0, redeemScript, hashType) var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
var redeemScriptSig = bitcoin.script.scriptHash.input.encode([ var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
alice.sign(signatureHash).toScriptSignature(hashType), bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
bitcoin.opcodes.OP_TRUE bitcoin.opcodes.OP_TRUE
], redeemScript) ], redeemScript)
tx.setInputScript(0, redeemScriptSig) tx.setInputScript(0, redeemScriptSig)

View file

@ -21,7 +21,7 @@ describe('bitcoinjs-lib (crypto)', function () {
assert(bitcoin.script.pubKeyHash.input.check(scriptChunks), 'Expected pubKeyHash script') assert(bitcoin.script.pubKeyHash.input.check(scriptChunks), 'Expected pubKeyHash script')
var prevOutScript = bitcoin.address.toOutputScript('1ArJ9vRaQcoQ29mTWZH768AmRwzb6Zif1z') var prevOutScript = bitcoin.address.toOutputScript('1ArJ9vRaQcoQ29mTWZH768AmRwzb6Zif1z')
var scriptSignature = bitcoin.ECSignature.parseScriptSignature(scriptChunks[0]) var scriptSignature = bitcoin.script.signature.decode(scriptChunks[0])
var publicKey = bitcoin.ECPair.fromPublicKeyBuffer(scriptChunks[1]) var publicKey = bitcoin.ECPair.fromPublicKeyBuffer(scriptChunks[1])
var m = tx.hashForSignature(vin, prevOutScript, scriptSignature.hashType) var m = tx.hashForSignature(vin, prevOutScript, scriptSignature.hashType)

View file

@ -230,7 +230,7 @@ describe('bitcoinjs-lib (transactions)', function () {
var keyPair = keyPairs[i] var keyPair = keyPairs[i]
var prevOutScript = bitcoin.address.toOutputScript(keyPair.getAddress()) var prevOutScript = bitcoin.address.toOutputScript(keyPair.getAddress())
var scriptSig = bitcoin.script.pubKeyHash.input.decode(input.script) var scriptSig = bitcoin.script.pubKeyHash.input.decode(input.script)
var ss = bitcoin.ECSignature.parseScriptSignature(scriptSig.signature) var ss = bitcoin.script.signature.decode(scriptSig.signature)
var hash = tx.hashForSignature(i, prevOutScript, ss.hashType) var hash = tx.hashForSignature(i, prevOutScript, ss.hashType)
assert.strictEqual(scriptSig.pubKey.toString('hex'), keyPair.getPublicKeyBuffer().toString('hex')) assert.strictEqual(scriptSig.pubKey.toString('hex'), keyPair.getPublicKeyBuffer().toString('hex'))

65
test/signature.js Normal file
View file

@ -0,0 +1,65 @@
/* global describe, it */
var assert = require('assert')
var bscriptSig = require('../src/script').signature
var BigInteger = require('bigi')
var fixtures = require('./fixtures/signature.json')
describe('Script Signatures', function () {
function fromRaw (signature) {
return {
r: new BigInteger(signature.r),
s: new BigInteger(signature.s)
}
}
function toRaw (signature) {
return {
r: signature.r.toString(),
s: signature.s.toString()
}
}
describe('encode', function () {
fixtures.valid.forEach(function (f) {
it('encodes ' + f.hex, function () {
var buffer = bscriptSig.encode(fromRaw(f.raw), f.hashType)
assert.strictEqual(buffer.toString('hex'), f.hex)
})
})
fixtures.invalid.forEach(function (f) {
if (!f.raw) return
it('throws ' + f.exception, function () {
var signature = fromRaw(f.raw)
assert.throws(function () {
bscriptSig.encode(signature, f.hashType)
}, new RegExp(f.exception))
})
})
})
describe('decode', function () {
fixtures.valid.forEach(function (f) {
it('decodes ' + f.hex, function () {
var decode = bscriptSig.decode(new Buffer(f.hex, 'hex'))
assert.deepEqual(toRaw(decode.signature), f.raw)
assert.strictEqual(decode.hashType, f.hashType)
})
})
fixtures.invalid.forEach(function (f) {
it('throws on ' + f.hex, function () {
var buffer = new Buffer(f.hex, 'hex')
assert.throws(function () {
bscriptSig.decode(buffer)
}, new RegExp(f.exception))
})
})
})
})