Socket
Socket
Sign inDemoInstall

bitcoinjs-lib

Package Overview
Dependencies
Maintainers
1
Versions
88
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bitcoinjs-lib - npm Package Compare versions

Comparing version 2.3.0 to 3.0.0

src/templates/index.js

26

CHANGELOG.md

@@ -0,1 +1,27 @@

# 3.0.0
From this release users can expect out-of-the-box Segregated Witness support.
The majority of breaking changes have been in how `script` encoding/decoding occurs, with the introduction of witness stacks.
__added__
- Added `script.types` enums (#679)
- Added `script.*.*.{check,encode,decode[,encodeStack,decodeStack]}` functions (#681, #682)
- Added minimal `TransactionBuilder.prototype.build` absurd fee-safety (#696)
- Added `script.(decompile/compile)PushOnly` and `script.toStack` functions (#700)
- Added `Transaction.prototype.toBuffer` Segregated Witness serialization support (#684, #701)
- Added `Transaction.prototype.hasWitnesses` (#718)
- Added `script.witnessCommitment.*` template
__fixed__
- Fixed `script` must compile minimally (#638)
- Fixed `Transaction` and `Block` versions should be Int32, signed integers (#662)
__removed__
- Removed `ecdsa.calcPubKeyRecoveryParam`, `ecdsa.recoverPubKey` (#456)
- Removed `buffer-equals`/`buffer-compare` dependencies (#650)
- Removed `HDNode.prototype.toString` (#665)
- Removed `dogecoin` network (#675)
__renamed__
- Removed `script.*` functions in favour of `bitcoin.script.*.(input/output).(encode/decode/check)` style (#682)
# 2.3.0

@@ -2,0 +28,0 @@ __added__

54

package.json
{
"name": "bitcoinjs-lib",
"version": "2.3.0",
"version": "3.0.0",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"engines": {
"node": ">=4.0.0"
},
"keywords": [

@@ -35,8 +38,8 @@ "bitcoin",

"scripts": {
"coverage": "mocha --require blanket -R travis-cov",
"coverage-local": "mocha --require blanket -R html-cov",
"coverage-report": "nyc report --reporter=lcov",
"coverage-html": "nyc report --reporter=html",
"coverage": "nyc --check-coverage --branches 90 --functions 90 mocha",
"integration": "mocha test/integration/",
"prepublish": "npm run test",
"standard": "standard",
"test": "npm run standard && npm run unit",
"test": "npm run standard && npm run coverage",
"unit": "mocha"

@@ -51,45 +54,30 @@ },

],
"config": {
"blanket": {
"pattern": [
""
],
"data-cover-never": [
"node_modules",
"test"
]
},
"travis-cov": {
"threshold": 99
}
},
"dependencies": {
"bigi": "^1.4.0",
"bip66": "^1.1.0",
"bs58check": "^1.0.5",
"buffer-compare": "^1.1.0",
"buffer-equals": "^1.0.3",
"buffer-reverse": "^1.0.0",
"bitcoin-ops": "^1.3.0",
"bs58check": "^2.0.0",
"create-hash": "^1.1.0",
"create-hmac": "^1.1.3",
"ecurve": "^1.0.0",
"merkle-lib": "^2.0.10",
"pushdata-bitcoin": "^1.0.1",
"randombytes": "^2.0.1",
"typeforce": "^1.6.2",
"typeforce": "^1.8.7",
"varuint-bitcoin": "^1.0.4",
"wif": "^2.0.1"
},
"devDependencies": {
"async": "^1.5.0",
"blanket": "^1.1.0",
"browserify": "^10.0.0",
"bs58": "^2.0.1",
"async": "^2.0.1",
"bs58": "^4.0.0",
"cb-http-client": "^0.2.0",
"httpify": "^1.0.0",
"minimaldata": "^1.0.0",
"mocha": "^2.2.0",
"coinselect": "^3.1.1",
"minimaldata": "^1.0.2",
"mocha": "^3.1.0",
"nyc": "^10.2.0",
"proxyquire": "^1.4.0",
"sinon": "^1.12.2",
"standard": "^5.0.0",
"travis-cov": "^0.2.0"
"standard": "^9.0.2"
},
"license": "MIT"
}

@@ -60,4 +60,3 @@ # BitcoinJS (bitcoinjs-lib)

ecurve: require('ecurve'),
BigInteger: require('bigi'),
Buffer: require('buffer')
BigInteger: require('bigi')
}

@@ -68,3 +67,3 @@ ```

``` bash
npm install bs58 bitcoinjs-lib ecurve bigi buffer
npm install bs58 bitcoinjs-lib ecurve bigi
```

@@ -81,9 +80,11 @@

**NOTE**: When uglifying the javascript, you must exclude the following variable names from being mangled: `Array`, `BigInteger`, `Boolean`, `Buffer`, `ECPair`, `Function`, `Number`, `Point` and `Script`.
**NOTE**: When uglifying the javascript, you must exclude the following variable names from being mangled: `Array`, `BigInteger`, `Boolean`, `ECPair`, `Function`, `Number`, `Point` and `Script`.
This is because of the function-name-duck-typing used in [typeforce](https://github.com/dcousens/typeforce).
Example:
``` bash
uglifyjs ... --mangle --reserved 'Array,BigInteger,Boolean,Buffer,ECPair,Function,Number,Point'
uglifyjs ... --mangle --reserved 'Array,BigInteger,Boolean,ECPair,Function,Number,Point'
```
**NOTE**: If you expect this library to run on an iOS 10 device, ensure that you are using [buffer@5.0.5](https://www.npmjs.com/package/buffer) or greater.
### Flow

@@ -104,19 +105,19 @@

- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L9)
- [Generate a address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L20)
- [Generate a address and WIF for Litecoin](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L30)
- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L44)
- [Create a Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/basic.js#L51)
- [Sign a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L8)
- [Verify a Bitcoin message](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L16)
- [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/advanced.js#L24)
- [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L9)
- [Spend from a 2-of-4 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/multisig.js#L25)
- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L11)
- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L48)
- [Recover a BIP32 parent private key from the parent public key and a derived non-hardened child private key](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L14)
- [Recover a Private key from duplicate R values in a signature](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L60)
- [Create a CLTV locked transaction where the expiry is past](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L36)
- [Create a CLTV locked transaction where the parties bypass the expiry](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L70)
- [Create a CLTV locked transaction which fails due to expiry in the future](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L102)
- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/basic.js#L9)
- [Generate a address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/basic.js#L20)
- [Generate a address and WIF for Litecoin](https://github.com/bitcoin/bitcoinjs-lib/blob/d853806/test/integration/basic.js#L29)
- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/basic.js#L43)
- [Create a Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/basic.js#L50)
- [Create an OP RETURN transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/advanced.js#L24)
- [Create a 2-of-3 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/multisig.js#L9)
- [Spend from a 2-of-4 multisig P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/multisig.js#L25)
- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/stealth.js)
- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/stealth.js)
- [Create a BIP32 wallet external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/bip32.js)
- [Create a BIP44, bitcoin, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/bip32.js)
- [Recover a BIP32 parent private key from the parent public key and a derived non-hardened child private key](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/bip32.js)
- [Recover a Private key from duplicate R values in a signature](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/crypto.js)
- [Create a CLTV locked transaction where the expiry is past](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/cltv.js#L36)
- [Create a CLTV locked transaction where the parties bypass the expiry](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/cltv.js#L70)
- [Create a CLTV locked transaction which fails due to expiry in the future](https://github.com/bitcoinjs/bitcoinjs-lib/blob/d853806/test/integration/cltv.js#L102)

@@ -167,3 +168,2 @@ If you have a use case that you feel could be listed here, please [ask for it](https://github.com/bitcoinjs/bitcoinjs-lib/issues/new)!

- [BIP32-Utils](https://github.com/bitcoinjs/bip32-utils) - A set of utilities for working with BIP32
- [BIP32-Wallet](https://github.com/bitcoinjs/bip32-wallet) - A BIP32 Wallet backed by bitcoinjs-lib, lite on features but heavily tested
- [BIP66](https://github.com/bitcoinjs/bip66) - Strict DER signature decoding

@@ -174,3 +174,6 @@ - [BIP69](https://github.com/bitcoinjs/bip69) - Lexicographical Indexing of Transaction Inputs and Outputs

- [BCoin](https://github.com/indutny/bcoin) - BIP37 / Bloom Filters / SPV client
- [coinselect](https://github.com/bitcoinjs/coinselect) - A fee-optimizing, transaction input selection module for bitcoinjs-lib.
- [insight](https://github.com/bitpay/insight) - A bitcoin blockchain API for web wallets.
- [merkle-lib](https://github.com/bitcoinjs/merkle-lib) - A performance conscious library for merkle root and tree calculations.
- [minimaldata](https://github.com/bitcoinjs/minimaldata) - A module to check bitcoin policy: SCRIPT_VERIFY_MINIMALDATA

@@ -177,0 +180,0 @@

@@ -18,11 +18,2 @@ var bs58check = require('bs58check')

function fromOutputScript (scriptPubKey, network) {
network = network || networks.bitcoin
if (bscript.isPubKeyHashOutput(scriptPubKey)) return toBase58Check(bscript.compile(scriptPubKey).slice(3, 23), network.pubKeyHash)
if (bscript.isScriptHashOutput(scriptPubKey)) return toBase58Check(bscript.compile(scriptPubKey).slice(2, 22), network.scriptHash)
throw new Error(bscript.toASM(scriptPubKey) + ' has no matching Address')
}
function toBase58Check (hash, version) {

@@ -38,2 +29,11 @@ typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments)

function fromOutputScript (outputScript, network) {
network = network || networks.bitcoin
if (bscript.pubKeyHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(3, 23), network.pubKeyHash)
if (bscript.scriptHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(2, 22), network.scriptHash)
throw new Error(bscript.toASM(outputScript) + ' has no matching Address')
}
function toOutputScript (address, network) {

@@ -43,4 +43,4 @@ network = network || networks.bitcoin

var decode = fromBase58Check(address)
if (decode.version === network.pubKeyHash) return bscript.pubKeyHashOutput(decode.hash)
if (decode.version === network.scriptHash) return bscript.scriptHashOutput(decode.hash)
if (decode.version === network.pubKeyHash) return bscript.pubKeyHash.output.encode(decode.hash)
if (decode.version === network.scriptHash) return bscript.scriptHash.output.encode(decode.hash)

@@ -47,0 +47,0 @@ throw new Error(address + ' has no matching Script')

@@ -1,6 +0,7 @@

var createHash = require('create-hash')
var bcrypto = require('./crypto')
var bufferutils = require('./bufferutils')
var bcrypto = require('./crypto')
var bufferCompare = require('buffer-compare')
var bufferReverse = require('buffer-reverse')
var fastMerkleRoot = require('merkle-lib/fastRoot')
var typeforce = require('typeforce')
var types = require('./types')
var varuint = require('varuint-bitcoin')

@@ -33,4 +34,10 @@ var Transaction = require('./transaction')

function readInt32 () {
var i = buffer.readInt32LE(offset)
offset += 4
return i
}
var block = new Block()
block.version = readUInt32()
block.version = readInt32()
block.prevHash = readSlice(32)

@@ -52,3 +59,2 @@ block.merkleRoot = readSlice(32)

var tx = Transaction.fromBuffer(buffer.slice(offset), true)
offset += tx.byteLength()

@@ -69,2 +75,10 @@ return tx

Block.prototype.byteLength = function (headersOnly) {
if (headersOnly || !this.transactions) return 80
return 80 + varuint.encodingLength(this.transactions.length) + this.transactions.reduce(function (a, x) {
return a + x.byteLength()
}, 0)
}
Block.fromHex = function (hex) {

@@ -79,3 +93,3 @@ return Block.fromBuffer(new Buffer(hex, 'hex'))

Block.prototype.getId = function () {
return bufferReverse(this.getHash()).toString('hex')
return this.getHash().reverse().toString('hex')
}

@@ -90,4 +104,5 @@

// TODO: buffer, offset compatibility
Block.prototype.toBuffer = function (headersOnly) {
var buffer = new Buffer(80)
var buffer = new Buffer(this.byteLength(headersOnly))

@@ -100,2 +115,6 @@ var offset = 0

function writeInt32 (i) {
buffer.writeInt32LE(i, offset)
offset += 4
}
function writeUInt32 (i) {

@@ -106,3 +125,3 @@ buffer.writeUInt32LE(i, offset)

writeUInt32(this.version)
writeInt32(this.version)
writeSlice(this.prevHash)

@@ -116,8 +135,12 @@ writeSlice(this.merkleRoot)

var txLenBuffer = bufferutils.varIntBuffer(this.transactions.length)
var txBuffers = this.transactions.map(function (tx) {
return tx.toBuffer()
varuint.encode(this.transactions.length, buffer, offset)
offset += varuint.encode.bytes
this.transactions.forEach(function (tx) {
var txSize = tx.byteLength() // TODO: extract from toBuffer?
tx.toBuffer(buffer, offset)
offset += txSize
})
return Buffer.concat([buffer, txLenBuffer].concat(txBuffers))
return buffer
}

@@ -132,12 +155,5 @@

var mantissa = bits & 0x007fffff
var i = 31 - exponent
var target = new Buffer(32)
target.fill(0)
target[i] = mantissa & 0xff
target[i - 1] = mantissa >> 8
target[i - 2] = mantissa >> 16
target[i - 3] = mantissa >> 24
target.writeUInt32BE(mantissa, 28 - exponent)
return target

@@ -147,21 +163,10 @@ }

Block.calculateMerkleRoot = function (transactions) {
var length = transactions.length
if (length === 0) throw TypeError('Cannot compute merkle root for zero transactions')
typeforce([{ getHash: types.Function }], transactions)
if (transactions.length === 0) throw TypeError('Cannot compute merkle root for zero transactions')
var hashes = transactions.map(function (transaction) { return transaction.getHash() })
var hashes = transactions.map(function (transaction) {
return transaction.getHash()
})
while (length > 1) {
var j = 0
for (var i = 0; i < length; i += 2, ++j) {
var hasher = createHash('sha256')
hasher.update(hashes[i])
hasher.update(i + 1 !== length ? hashes[i + 1] : hashes[i])
hashes[j] = bcrypto.sha256(hasher.digest())
}
length = j
}
return hashes[0]
return fastMerkleRoot(hashes, bcrypto.hash256)
}

@@ -173,12 +178,12 @@

var actualMerkleRoot = Block.calculateMerkleRoot(this.transactions)
return bufferCompare(this.merkleRoot, actualMerkleRoot) === 0
return this.merkleRoot.compare(actualMerkleRoot) === 0
}
Block.prototype.checkProofOfWork = function () {
var hash = bufferReverse(this.getHash())
var hash = this.getHash().reverse()
var target = Block.calculateTarget(this.bits)
return bufferCompare(hash, target) <= 0
return hash.compare(target) <= 0
}
module.exports = Block

@@ -1,2 +0,3 @@

var opcodes = require('./opcodes.json')
var pushdata = require('pushdata-bitcoin')
var varuint = require('varuint-bitcoin')

@@ -7,50 +8,6 @@ // https://github.com/feross/buffer/blob/master/index.js#L1127

if (value < 0) throw new Error('specified a negative value for writing an unsigned value')
if (value > max) throw new Error('value is larger than maximum value for type')
if (value > max) throw new Error('RangeError: value out of range')
if (Math.floor(value) !== value) throw new Error('value has a fractional component')
}
function pushDataSize (i) {
return i < opcodes.OP_PUSHDATA1 ? 1
: i <= 0xff ? 2
: i <= 0xffff ? 3
: 5
}
function readPushDataInt (buffer, offset) {
var opcode = buffer.readUInt8(offset)
var number, size
// ~6 bit
if (opcode < opcodes.OP_PUSHDATA1) {
number = opcode
size = 1
// 8 bit
} else if (opcode === opcodes.OP_PUSHDATA1) {
if (offset + 2 > buffer.length) return null
number = buffer.readUInt8(offset + 1)
size = 2
// 16 bit
} else if (opcode === opcodes.OP_PUSHDATA2) {
if (offset + 3 > buffer.length) return null
number = buffer.readUInt16LE(offset + 1)
size = 3
// 32 bit
} else {
if (offset + 5 > buffer.length) return null
if (opcode !== opcodes.OP_PUSHDATA4) throw new Error('Unexpected opcode')
number = buffer.readUInt32LE(offset + 1)
size = 5
}
return {
opcode: opcode,
number: number,
size: size
}
}
function readUInt64LE (buffer, offset) {

@@ -66,59 +23,2 @@ var a = buffer.readUInt32LE(offset)

function readVarInt (buffer, offset) {
var t = buffer.readUInt8(offset)
var number, size
// 8 bit
if (t < 253) {
number = t
size = 1
// 16 bit
} else if (t < 254) {
number = buffer.readUInt16LE(offset + 1)
size = 3
// 32 bit
} else if (t < 255) {
number = buffer.readUInt32LE(offset + 1)
size = 5
// 64 bit
} else {
number = readUInt64LE(buffer, offset + 1)
size = 9
}
return {
number: number,
size: size
}
}
function writePushDataInt (buffer, number, offset) {
var size = pushDataSize(number)
// ~6 bit
if (size === 1) {
buffer.writeUInt8(number, offset)
// 8 bit
} else if (size === 2) {
buffer.writeUInt8(opcodes.OP_PUSHDATA1, offset)
buffer.writeUInt8(number, offset + 1)
// 16 bit
} else if (size === 3) {
buffer.writeUInt8(opcodes.OP_PUSHDATA2, offset)
buffer.writeUInt16LE(number, offset + 1)
// 32 bit
} else {
buffer.writeUInt8(opcodes.OP_PUSHDATA4, offset)
buffer.writeUInt32LE(number, offset + 1)
}
return size
}
function writeUInt64LE (buffer, value, offset) {

@@ -129,57 +29,31 @@ verifuint(value, 0x001fffffffffffff)

buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4)
return offset + 8
}
function varIntSize (i) {
return i < 253 ? 1
: i < 0x10000 ? 3
: i < 0x100000000 ? 5
: 9
}
// TODO: remove in 4.0.0?
function readVarInt (buffer, offset) {
var result = varuint.decode(buffer, offset)
function writeVarInt (buffer, number, offset) {
var size = varIntSize(number)
// 8 bit
if (size === 1) {
buffer.writeUInt8(number, offset)
// 16 bit
} else if (size === 3) {
buffer.writeUInt8(253, offset)
buffer.writeUInt16LE(number, offset + 1)
// 32 bit
} else if (size === 5) {
buffer.writeUInt8(254, offset)
buffer.writeUInt32LE(number, offset + 1)
// 64 bit
} else {
buffer.writeUInt8(255, offset)
writeUInt64LE(buffer, number, offset + 1)
return {
number: result,
size: varuint.decode.bytes
}
return size
}
function varIntBuffer (i) {
var size = varIntSize(i)
var buffer = new Buffer(size)
writeVarInt(buffer, i, 0)
return buffer
// TODO: remove in 4.0.0?
function writeVarInt (buffer, number, offset) {
varuint.encode(number, buffer, offset)
return varuint.encode.bytes
}
module.exports = {
equal: require('buffer-equals'),
pushDataSize: pushDataSize,
readPushDataInt: readPushDataInt,
pushDataSize: pushdata.encodingLength,
readPushDataInt: pushdata.decode,
readUInt64LE: readUInt64LE,
readVarInt: readVarInt,
reverse: require('buffer-reverse'),
varIntBuffer: varIntBuffer,
varIntSize: varIntSize,
writePushDataInt: writePushDataInt,
varIntBuffer: varuint.encode,
varIntSize: varuint.encodingLength,
writePushDataInt: pushdata.encode,
writeUInt64LE: writeUInt64LE,
writeVarInt: writeVarInt
}
var createHash = require('create-hash')
function hash160 (buffer) {
return ripemd160(sha256(buffer))
}
function hash256 (buffer) {
return sha256(sha256(buffer))
}
function ripemd160 (buffer) {

@@ -23,2 +15,10 @@ return createHash('rmd160').update(buffer).digest()

function hash160 (buffer) {
return ripemd160(sha256(buffer))
}
function hash256 (buffer) {
return sha256(sha256(buffer))
}
module.exports = {

@@ -25,0 +25,0 @@ hash160: hash160,

@@ -157,89 +157,4 @@ var createHmac = require('create-hmac')

/**
* Recover a public key from a signature.
*
* See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
* Key Recovery Operation".
*
* http://www.secg.org/download/aid-780/sec1-v2.pdf
*/
function recoverPubKey (e, signature, i) {
typeforce(types.tuple(
types.BigInt,
types.ECSignature,
types.UInt2
), arguments)
var n = secp256k1.n
var G = secp256k1.G
var r = signature.r
var s = signature.s
if (r.signum() <= 0 || r.compareTo(n) >= 0) throw new Error('Invalid r value')
if (s.signum() <= 0 || s.compareTo(n) >= 0) throw new Error('Invalid s value')
// A set LSB signifies that the y-coordinate is odd
var isYOdd = i & 1
// The more significant bit specifies whether we should use the
// first or second candidate key.
var isSecondKey = i >> 1
// 1.1 Let x = r + jn
var x = isSecondKey ? r.add(n) : r
var R = secp256k1.pointFromX(isYOdd, x)
// 1.4 Check that nR is at infinity
var nR = R.multiply(n)
if (!secp256k1.isInfinity(nR)) throw new Error('nR is not a valid curve point')
// Compute r^-1
var rInv = r.modInverse(n)
// Compute -e from e
var eNeg = e.negate().mod(n)
// 1.6.1 Compute Q = r^-1 (sR - eG)
// Q = r^-1 (sR + -eG)
var Q = R.multiplyTwo(s, G, eNeg).multiply(rInv)
secp256k1.validate(Q)
return Q
}
/**
* Calculate pubkey extraction parameter.
*
* When extracting a pubkey from a signature, we have to
* distinguish four different cases. Rather than putting this
* burden on the verifier, Bitcoin includes a 2-bit value with the
* signature.
*
* This function simply tries all four cases and returns the value
* that resulted in a successful pubkey recovery.
*/
function calcPubKeyRecoveryParam (e, signature, Q) {
typeforce(types.tuple(
types.BigInt,
types.ECSignature,
types.ECPoint
), arguments)
for (var i = 0; i < 4; i++) {
var Qprime = recoverPubKey(e, signature, i)
// 1.6.2 Verify Q
if (Qprime.equals(Q)) {
return i
}
}
throw new Error('Unable to find valid recovery factor')
}
module.exports = {
calcPubKeyRecoveryParam: calcPubKeyRecoveryParam,
deterministicGenerateK: deterministicGenerateK,
recoverPubKey: recoverPubKey,
sign: sign,

@@ -246,0 +161,0 @@ verify: verify,

@@ -64,6 +64,6 @@ var baddress = require('./address')

// [network, ...]
// list of networks?
if (types.Array(network)) {
network = network.filter(function (network) {
return version === network.wif
network = network.filter(function (x) {
return version === x.wif
}).pop()

@@ -73,3 +73,3 @@

// network
// otherwise, assume a network object (or default to bitcoin)
} else {

@@ -76,0 +76,0 @@ network = network || NETWORKS.bitcoin

@@ -64,5 +64,5 @@ var base58check = require('bs58check')

if (Array.isArray(networks)) {
network = networks.filter(function (network) {
return version === network.bip32.private ||
version === network.bip32.public
network = networks.filter(function (x) {
return version === x.bip32.private ||
version === x.bip32.public
}).pop()

@@ -103,11 +103,8 @@

var d = BigInteger.fromBuffer(buffer.slice(46, 78))
keyPair = new ECPair(d, null, { network: network })
keyPair = new ECPair(d, null, {
network: network
})
// 33 bytes: public key data (0x02 + X or 0x03 + X)
} else {
var Q = ecurve.Point.decodeFrom(curve, buffer.slice(45, 78))
if (!Q.compressed) throw new Error('Invalid public key')
// Q.compressed is assumed, if somehow this assumption is broken, `new HDNode` will throw

@@ -118,5 +115,3 @@ // Verify that the X coordinate in the public point corresponds to a point on the curve.

keyPair = new ECPair(null, Q, {
network: network
})
keyPair = new ECPair(null, Q, { network: network })
}

@@ -300,3 +295,3 @@

HDNode.prototype.derivePath = function (path) {
typeforce(types.Bip32Path, path)
typeforce(types.BIP32Path, path)

@@ -324,4 +319,2 @@ var splitPath = path.split('/')

HDNode.prototype.toString = HDNode.prototype.toBase58
module.exports = HDNode

@@ -12,6 +12,5 @@ module.exports = {

crypto: require('./crypto'),
message: require('./message'),
networks: require('./networks'),
opcodes: require('./opcodes.json'),
opcodes: require('bitcoin-ops'),
script: require('./script')
}

@@ -13,4 +13,3 @@ // https://en.bitcoin.it/wiki/List_of_address_prefixes

scriptHash: 0x05,
wif: 0x80,
dustThreshold: 546 // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162
wif: 0x80
},

@@ -25,4 +24,3 @@ testnet: {

scriptHash: 0xc4,
wif: 0xef,
dustThreshold: 546
wif: 0xef
},

@@ -37,16 +35,4 @@ litecoin: {

scriptHash: 0x05,
wif: 0xb0,
dustThreshold: 0 // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L360-L365
},
dogecoin: {
messagePrefix: '\x19Dogecoin Signed Message:\n',
bip32: {
public: 0x02facafd,
private: 0x02fac398
},
pubKeyHash: 0x1e,
scriptHash: 0x16,
wif: 0x9e,
dustThreshold: 0 // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/core.h#L155-L160
wif: 0xb0
}
}
var bip66 = require('bip66')
var bufferutils = require('./bufferutils')
var pushdata = require('pushdata-bitcoin')
var typeforce = require('typeforce')
var types = require('./types')
var scriptNumber = require('./script_number')
var OPS = require('./opcodes.json')
var REVERSE_OPS = (function () {
var result = {}
for (var op in OPS) {
var code = OPS[op]
result[code] = op
}
return result
})()
var OPS = require('bitcoin-ops')
var REVERSE_OPS = require('bitcoin-ops/map')
var OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1
function toASM (chunks) {
if (Buffer.isBuffer(chunks)) {
chunks = decompile(chunks)
}
function isOPInt (value) {
return types.Number(value) &&
((value === OPS.OP_0) ||
(value >= OPS.OP_1 && value <= OPS.OP_16) ||
(value === OPS.OP_1NEGATE))
}
return chunks.map(function (chunk) {
// data?
if (Buffer.isBuffer(chunk)) return chunk.toString('hex')
// opcode!
return REVERSE_OPS[chunk]
}).join(' ')
function isPushOnlyChunk (value) {
return types.Buffer(value) || isOPInt(value)
}
function fromASM (asm) {
typeforce(types.String, asm)
return compile(asm.split(' ').map(function (chunkStr) {
// opcode?
if (OPS[chunkStr] !== undefined) return OPS[chunkStr]
// data!
return new Buffer(chunkStr, 'hex')
}))
function isPushOnly (value) {
return types.Array(value) && value.every(isPushOnlyChunk)
}

@@ -53,3 +35,8 @@

if (Buffer.isBuffer(chunk)) {
return accum + bufferutils.pushDataSize(chunk.length) + chunk.length
// adhere to BIP62.3, minimal push policy
if (chunk.length === 1 && (chunk[0] === 0x81 || (chunk[0] >= 1 && chunk[0] <= 16))) {
return accum + 1
}
return accum + pushdata.encodingLength(chunk.length) + chunk.length
}

@@ -67,4 +54,18 @@

if (Buffer.isBuffer(chunk)) {
offset += bufferutils.writePushDataInt(buffer, chunk.length, offset)
// adhere to BIP62.3, minimal push policy
if (chunk.length === 1 && chunk[0] >= 1 && chunk[0] <= 16) {
var opcode = OP_INT_BASE + chunk[0]
buffer.writeUInt8(opcode, offset)
offset += 1
return
}
if (chunk.length === 1 && chunk[0] === 0x81) {
buffer.writeUInt8(OPS.OP_1NEGATE, offset)
offset += 1
return
}
offset += pushdata.encode(buffer, chunk.length, offset)
chunk.copy(buffer, offset)

@@ -98,3 +99,3 @@ offset += chunk.length

if ((opcode > OPS.OP_0) && (opcode <= OPS.OP_PUSHDATA4)) {
var d = bufferutils.readPushDataInt(buffer, i)
var d = pushdata.decode(buffer, i)

@@ -124,2 +125,41 @@ // did reading a pushDataInt fail? empty script

function toASM (chunks) {
if (Buffer.isBuffer(chunks)) {
chunks = decompile(chunks)
}
return chunks.map(function (chunk) {
// data?
if (Buffer.isBuffer(chunk)) return chunk.toString('hex')
// opcode!
return REVERSE_OPS[chunk]
}).join(' ')
}
function fromASM (asm) {
typeforce(types.String, asm)
return compile(asm.split(' ').map(function (chunkStr) {
// opcode?
if (OPS[chunkStr] !== undefined) return OPS[chunkStr]
typeforce(types.Hex, chunkStr)
// data!
return new Buffer(chunkStr, 'hex')
}))
}
function toStack (chunks) {
chunks = decompile(chunks)
typeforce(isPushOnly, chunks)
return chunks.map(function (op) {
if (Buffer.isBuffer(op)) return op
if (op === OPS.OP_0) return new Buffer(0)
return scriptNumber.encode(op - OP_INT_BASE)
})
}
function isCanonicalPubKey (buffer) {

@@ -140,9 +180,2 @@ if (!Buffer.isBuffer(buffer)) return false

function isCanonicalSignature (buffer) {
if (!Buffer.isBuffer(buffer)) return false
if (!isDefinedHashType(buffer[buffer.length - 1])) return false
return bip66.check(buffer.slice(0, -1))
}
function isDefinedHashType (hashType) {

@@ -155,260 +188,9 @@ var hashTypeMod = hashType & ~0x80

function isPubKeyHashInput (script) {
var chunks = decompile(script)
function isCanonicalSignature (buffer) {
if (!Buffer.isBuffer(buffer)) return false
if (!isDefinedHashType(buffer[buffer.length - 1])) return false
return chunks.length === 2 &&
isCanonicalSignature(chunks[0]) &&
isCanonicalPubKey(chunks[1])
return bip66.check(buffer.slice(0, -1))
}
function isPubKeyHashOutput (script) {
var buffer = compile(script)
return buffer.length === 25 &&
buffer[0] === OPS.OP_DUP &&
buffer[1] === OPS.OP_HASH160 &&
buffer[2] === 0x14 &&
buffer[23] === OPS.OP_EQUALVERIFY &&
buffer[24] === OPS.OP_CHECKSIG
}
function isPubKeyInput (script) {
var chunks = decompile(script)
return chunks.length === 1 &&
isCanonicalSignature(chunks[0])
}
function isPubKeyOutput (script) {
var chunks = decompile(script)
return chunks.length === 2 &&
isCanonicalPubKey(chunks[0]) &&
chunks[1] === OPS.OP_CHECKSIG
}
function isScriptHashInput (script, allowIncomplete) {
var chunks = decompile(script)
if (chunks.length < 2) return false
var lastChunk = chunks[chunks.length - 1]
if (!Buffer.isBuffer(lastChunk)) return false
var scriptSigChunks = chunks.slice(0, -1)
var redeemScriptChunks = decompile(lastChunk)
// is redeemScript a valid script?
if (redeemScriptChunks.length === 0) return false
return classifyInput(scriptSigChunks, allowIncomplete) === classifyOutput(redeemScriptChunks)
}
function isScriptHashOutput (script) {
var buffer = compile(script)
return buffer.length === 23 &&
buffer[0] === OPS.OP_HASH160 &&
buffer[1] === 0x14 &&
buffer[22] === OPS.OP_EQUAL
}
function isWitnessPubKeyHashOutput (script) {
var buffer = compile(script)
return buffer.length === 22 &&
buffer[0] === OPS.OP_0 &&
buffer[1] === 0x14
}
function isWitnessScriptHashOutput (script) {
var buffer = compile(script)
return buffer.length === 34 &&
buffer[0] === OPS.OP_0 &&
buffer[1] === 0x20
}
// allowIncomplete is to account for combining signatures
// See https://github.com/bitcoin/bitcoin/blob/f425050546644a36b0b8e0eb2f6934a3e0f6f80f/src/script/sign.cpp#L195-L197
function isMultisigInput (script, allowIncomplete) {
var chunks = decompile(script)
if (chunks.length < 2) return false
if (chunks[0] !== OPS.OP_0) return false
if (allowIncomplete) {
return chunks.slice(1).every(function (chunk) {
return chunk === OPS.OP_0 || isCanonicalSignature(chunk)
})
}
return chunks.slice(1).every(isCanonicalSignature)
}
function isMultisigOutput (script) {
var chunks = decompile(script)
if (chunks.length < 4) return false
if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false
var mOp = chunks[0]
var nOp = chunks[chunks.length - 2]
if (!types.Number(mOp)) return false
if (!types.Number(nOp)) return false
var m = mOp - OP_INT_BASE
var n = nOp - OP_INT_BASE
// 0 < m <= n <= 16
if (m <= 0) return false
if (m > n) return false
if (n > 16) return false
if (n !== chunks.length - 3) return false
return chunks.slice(1, -2).every(isCanonicalPubKey)
}
function isNullDataOutput (script) {
var chunks = decompile(script)
return chunks[0] === OPS.OP_RETURN
}
function classifyOutput (script) {
var chunks = decompile(script)
if (isWitnessPubKeyHashOutput(chunks)) {
return 'witnesspubkeyhash'
} else if (isWitnessScriptHashOutput(chunks)) {
return 'witnessscripthash'
} else if (isPubKeyHashOutput(chunks)) {
return 'pubkeyhash'
} else if (isScriptHashOutput(chunks)) {
return 'scripthash'
} else if (isMultisigOutput(chunks)) {
return 'multisig'
} else if (isPubKeyOutput(chunks)) {
return 'pubkey'
} else if (isNullDataOutput(chunks)) {
return 'nulldata'
}
return 'nonstandard'
}
function classifyInput (script, allowIncomplete) {
var chunks = decompile(script)
if (isPubKeyHashInput(chunks)) {
return 'pubkeyhash'
} else if (isMultisigInput(chunks, allowIncomplete)) {
return 'multisig'
} else if (isScriptHashInput(chunks, allowIncomplete)) {
return 'scripthash'
} else if (isPubKeyInput(chunks)) {
return 'pubkey'
}
return 'nonstandard'
}
// Standard Script Templates
// {pubKey} OP_CHECKSIG
function pubKeyOutput (pubKey) {
return compile([pubKey, OPS.OP_CHECKSIG])
}
// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
function pubKeyHashOutput (pubKeyHash) {
typeforce(types.Hash160bit, pubKeyHash)
return compile([OPS.OP_DUP, OPS.OP_HASH160, pubKeyHash, OPS.OP_EQUALVERIFY, OPS.OP_CHECKSIG])
}
// OP_HASH160 {scriptHash} OP_EQUAL
function scriptHashOutput (scriptHash) {
typeforce(types.Hash160bit, scriptHash)
return compile([OPS.OP_HASH160, scriptHash, OPS.OP_EQUAL])
}
// m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput (m, pubKeys) {
typeforce(types.tuple(types.Number, [types.Buffer]), arguments)
var n = pubKeys.length
if (n < m) throw new Error('Not enough pubKeys provided')
return compile([].concat(
OP_INT_BASE + m,
pubKeys,
OP_INT_BASE + n,
OPS.OP_CHECKMULTISIG
))
}
// OP_0 {pubKeyHash}
function witnessPubKeyHashOutput (pubKeyHash) {
typeforce(types.Hash160bit, pubKeyHash)
return compile([OPS.OP_0, pubKeyHash])
}
// OP_0 {scriptHash}
function witnessScriptHashOutput (scriptHash) {
typeforce(types.Hash256bit, scriptHash)
return compile([OPS.OP_0, scriptHash])
}
// {signature}
function pubKeyInput (signature) {
typeforce(types.Buffer, signature)
return compile([signature])
}
// {signature} {pubKey}
function pubKeyHashInput (signature, pubKey) {
typeforce(types.tuple(types.Buffer, types.Buffer), arguments)
return compile([signature, pubKey])
}
// <scriptSig> {serialized scriptPubKey script}
function scriptHashInput (scriptSig, scriptPubKey) {
var scriptSigChunks = decompile(scriptSig)
var serializedScriptPubKey = compile(scriptPubKey)
return compile([].concat(
scriptSigChunks,
serializedScriptPubKey
))
}
// <scriptSig> {serialized scriptPubKey script}
function witnessScriptHashInput (scriptSig, scriptPubKey) {
return scriptHashInput(scriptSig, scriptPubKey)
}
// OP_0 [signatures ...]
function multisigInput (signatures, scriptPubKey) {
if (scriptPubKey) {
var chunks = decompile(scriptPubKey)
if (!isMultisigOutput(chunks)) throw new Error('Expected multisig scriptPubKey')
var mOp = chunks[0]
var nOp = chunks[chunks.length - 2]
var m = mOp - OP_INT_BASE
var n = nOp - OP_INT_BASE
if (signatures.length < m) throw new Error('Not enough signatures provided')
if (signatures.length > n) throw new Error('Too many signatures provided')
}
return compile([].concat(OPS.OP_0, signatures))
}
function nullDataOutput (data) {
return compile([OPS.OP_RETURN, data])
}
module.exports = {

@@ -419,2 +201,3 @@ compile: compile,

toASM: toASM,
toStack: toStack,

@@ -425,30 +208,9 @@ number: require('./script_number'),

isCanonicalSignature: isCanonicalSignature,
isDefinedHashType: isDefinedHashType,
isPubKeyHashInput: isPubKeyHashInput,
isPubKeyHashOutput: isPubKeyHashOutput,
isPubKeyInput: isPubKeyInput,
isPubKeyOutput: isPubKeyOutput,
isScriptHashInput: isScriptHashInput,
isScriptHashOutput: isScriptHashOutput,
isWitnessPubKeyHashOutput: isWitnessPubKeyHashOutput,
isWitnessScriptHashOutput: isWitnessScriptHashOutput,
isMultisigInput: isMultisigInput,
isMultisigOutput: isMultisigOutput,
isNullDataOutput: isNullDataOutput,
isPushOnly: isPushOnly,
isDefinedHashType: isDefinedHashType
}
classifyOutput: classifyOutput,
classifyInput: classifyInput,
pubKeyOutput: pubKeyOutput,
pubKeyHashOutput: pubKeyHashOutput,
scriptHashOutput: scriptHashOutput,
witnessPubKeyHashOutput: witnessPubKeyHashOutput,
witnessScriptHashInput: witnessScriptHashInput,
witnessScriptHashOutput: witnessScriptHashOutput,
multisigOutput: multisigOutput,
pubKeyInput: pubKeyInput,
pubKeyHashInput: pubKeyHashInput,
scriptHashInput: scriptHashInput,
multisigInput: multisigInput,
nullDataOutput: nullDataOutput
var templates = require('./templates')
for (var key in templates) {
module.exports[key] = templates[key]
}
var baddress = require('./address')
var bcrypto = require('./crypto')
var bscript = require('./script')
var bufferEquals = require('buffer-equals')
var bufferReverse = require('buffer-reverse')
var networks = require('./networks')
var ops = require('./opcodes.json')
var ops = require('bitcoin-ops')
var typeforce = require('typeforce')
var types = require('./types')
var scriptTypes = bscript.types
var SIGNABLE = [bscript.types.P2PKH, bscript.types.P2PK, bscript.types.MULTISIG]
var P2SH = SIGNABLE.concat([bscript.types.P2WPKH, bscript.types.P2WSH])

@@ -15,16 +16,159 @@ var ECPair = require('./ecpair')

// re-orders signatures to match pubKeys, fills undefined otherwise
function fixMSSignatures (transaction, vin, pubKeys, signatures, prevOutScript, hashType, skipPubKey) {
// maintain a local copy of unmatched signatures
var unmatched = signatures.slice()
var cache = {}
function extractChunks (type, chunks, script) {
var pubKeys = []
var signatures = []
switch (type) {
case scriptTypes.P2PKH:
// if (redeemScript) throw new Error('Nonstandard... P2SH(P2PKH)')
pubKeys = chunks.slice(1)
signatures = chunks.slice(0, 1)
break
return pubKeys.map(function (pubKey) {
// skip optionally provided pubKey
if (skipPubKey && bufferEquals(skipPubKey, pubKey)) return undefined
case scriptTypes.P2PK:
pubKeys[0] = script ? bscript.pubKey.output.decode(script) : undefined
signatures = chunks.slice(0, 1)
break
var matched
var keyPair2 = ECPair.fromPublicKeyBuffer(pubKey)
case scriptTypes.MULTISIG:
if (script) {
var multisig = bscript.multisig.output.decode(script)
pubKeys = multisig.pubKeys
}
// check for a matching signature
signatures = chunks.slice(1).map(function (chunk) {
return chunk.length === 0 ? undefined : chunk
})
break
}
return {
pubKeys: pubKeys,
signatures: signatures
}
}
function expandInput (scriptSig, witnessStack) {
var prevOutScript
var prevOutType
var scriptType
var script
var redeemScript
var witnessScript
var witnessScriptType
var redeemScriptType
var witness = false
var p2wsh = false
var p2sh = false
var witnessProgram
var chunks
var scriptSigChunks = bscript.decompile(scriptSig)
var sigType = bscript.classifyInput(scriptSigChunks, true)
if (sigType === scriptTypes.P2SH) {
p2sh = true
redeemScript = scriptSigChunks[scriptSigChunks.length - 1]
redeemScriptType = bscript.classifyOutput(redeemScript)
prevOutScript = bscript.scriptHash.output.encode(bcrypto.hash160(redeemScript))
prevOutType = scriptTypes.P2SH
script = redeemScript
}
var classifyWitness = bscript.classifyWitness(witnessStack)
if (classifyWitness === scriptTypes.P2WSH) {
witnessScript = witnessStack[witnessStack.length - 1]
witnessScriptType = bscript.classifyOutput(witnessScript)
p2wsh = true
if (scriptSig.length === 0) {
prevOutScript = bscript.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript))
prevOutType = scriptTypes.P2WSH
if (typeof redeemScript !== 'undefined') {
throw new Error('Redeem script given when unnecessary')
}
// bare witness
} else {
if (!redeemScript) {
throw new Error('No redeemScript provided for P2WSH, but scriptSig non-empty')
}
witnessProgram = bscript.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript))
if (!redeemScript.equals(witnessProgram)) {
throw new Error('Redeem script didn\'t match witnessScript')
}
}
if (SIGNABLE.indexOf(bscript.classifyOutput(witnessScript)) === -1) {
throw new Error('unsupported witness script')
}
script = witnessScript
scriptType = witnessScriptType
chunks = witnessStack.slice(0, -1)
} else if (classifyWitness === scriptTypes.P2WPKH) {
var key = witnessStack[witnessStack.length - 1]
var keyHash = bcrypto.hash160(key)
if (scriptSig.length === 0) {
prevOutScript = bscript.witnessPubKeyHash.output.encode(keyHash)
prevOutType = scriptTypes.P2WPKH
if (typeof redeemScript !== 'undefined') {
throw new Error('Redeem script given when unnecessary')
}
} else {
if (!redeemScript) {
throw new Error('No redeemScript provided for P2WPKH, but scriptSig wasn\'t empty')
}
witnessProgram = bscript.witnessPubKeyHash.output.encode(keyHash)
if (!redeemScript.equals(witnessProgram)) {
throw new Error('Redeem script did not have the right witness program')
}
}
scriptType = scriptTypes.P2PKH
chunks = witnessStack
} else if (redeemScript) {
if (P2SH.indexOf(redeemScriptType) === -1) {
throw new Error('Bad redeemscript!')
}
script = redeemScript
scriptType = redeemScriptType
chunks = scriptSigChunks.slice(0, -1)
} else {
prevOutType = scriptType = bscript.classifyInput(scriptSig)
chunks = scriptSigChunks
}
var expanded = extractChunks(scriptType, chunks, script)
var result = {
pubKeys: expanded.pubKeys,
signatures: expanded.signatures,
prevOutScript: prevOutScript,
prevOutType: prevOutType,
signType: scriptType,
signScript: script,
witness: Boolean(witness)
}
if (p2sh) {
result.redeemScript = redeemScript
result.redeemScriptType = redeemScriptType
}
if (p2wsh) {
result.witnessScript = witnessScript
result.witnessScriptType = witnessScriptType
}
return result
}
// could be done in expandInput, but requires the original Transaction for hashForSignature
function fixMultisigOrder (input, transaction, vin) {
if (input.redeemScriptType !== scriptTypes.MULTISIG || !input.redeemScript) return
if (input.pubKeys.length === input.signatures.length) return
var unmatched = input.signatures.concat()
input.signatures = input.pubKeys.map(function (pubKey) {
var keyPair = ECPair.fromPublicKeyBuffer(pubKey)
var match
// check for a signature
unmatched.some(function (signature, i) {

@@ -34,8 +178,12 @@ // skip if undefined || OP_0

var signatureHash = cache[hashType] = cache[hashType] || transaction.hashForSignature(vin, prevOutScript, hashType)
if (!keyPair2.verify(signatureHash, signature)) return false
// TODO: avoid O(n) hashForSignature
var parsed = ECSignature.parseScriptSignature(signature)
var hash = transaction.hashForSignature(vin, input.redeemScript, parsed.hashType)
// skip if signature does not match pubKey
if (!keyPair.verify(hash, parsed.signature)) return false
// remove matched signature from unmatched
unmatched[i] = undefined
matched = signature
match = signature

@@ -45,106 +193,264 @@ return true

return matched || undefined
return match
})
}
function extractInput (transaction, txIn, vin) {
if (txIn.script.length === 0) return {}
function expandOutput (script, scriptType, ourPubKey) {
typeforce(types.Buffer, script)
var scriptSigChunks = bscript.decompile(txIn.script)
var prevOutType = bscript.classifyInput(scriptSigChunks, true)
var scriptChunks = bscript.decompile(script)
if (!scriptType) {
scriptType = bscript.classifyOutput(script)
}
function processScript (scriptType, scriptSigChunks, redeemScriptChunks) {
// ensure chunks are decompiled
scriptSigChunks = bscript.decompile(scriptSigChunks)
redeemScriptChunks = redeemScriptChunks ? bscript.decompile(redeemScriptChunks) : undefined
var pubKeys = []
var hashType, pubKeys, signatures, prevOutScript, redeemScript, redeemScriptType, result, parsed
switch (scriptType) {
// does our hash160(pubKey) match the output scripts?
case scriptTypes.P2PKH:
if (!ourPubKey) break
switch (scriptType) {
case 'scripthash':
redeemScript = scriptSigChunks.slice(-1)[0]
scriptSigChunks = bscript.compile(scriptSigChunks.slice(0, -1))
var pkh1 = scriptChunks[2]
var pkh2 = bcrypto.hash160(ourPubKey)
if (pkh1.equals(pkh2)) pubKeys = [ourPubKey]
break
redeemScriptType = bscript.classifyInput(scriptSigChunks, true)
prevOutScript = bscript.scriptHashOutput(bcrypto.hash160(redeemScript))
// does our hash160(pubKey) match the output scripts?
case scriptTypes.P2WPKH:
if (!ourPubKey) break
result = processScript(redeemScriptType, scriptSigChunks, bscript.decompile(redeemScript))
var wpkh1 = scriptChunks[1]
var wpkh2 = bcrypto.hash160(ourPubKey)
if (wpkh1.equals(wpkh2)) pubKeys = [ourPubKey]
break
result.prevOutScript = prevOutScript
result.redeemScript = redeemScript
result.redeemScriptType = redeemScriptType
case scriptTypes.P2PK:
pubKeys = scriptChunks.slice(0, 1)
break
return result
case scriptTypes.MULTISIG:
pubKeys = scriptChunks.slice(1, -2)
break
case 'pubkeyhash':
parsed = ECSignature.parseScriptSignature(scriptSigChunks[0])
hashType = parsed.hashType
pubKeys = scriptSigChunks.slice(1)
signatures = [parsed.signature]
prevOutScript = bscript.pubKeyHashOutput(bcrypto.hash160(pubKeys[0]))
default: return { scriptType: scriptType }
}
break
return {
pubKeys: pubKeys,
scriptType: scriptType,
signatures: pubKeys.map(function () { return undefined })
}
}
case 'pubkey':
parsed = ECSignature.parseScriptSignature(scriptSigChunks[0])
hashType = parsed.hashType
signatures = [parsed.signature]
function checkP2shInput (input, redeemScriptHash) {
if (input.prevOutType) {
if (input.prevOutType !== scriptTypes.P2SH) throw new Error('PrevOutScript must be P2SH')
if (redeemScriptChunks) {
pubKeys = redeemScriptChunks.slice(0, 1)
}
var prevOutScriptScriptHash = bscript.decompile(input.prevOutScript)[1]
if (!prevOutScriptScriptHash.equals(redeemScriptHash)) throw new Error('Inconsistent hash160(RedeemScript)')
}
}
break
function checkP2WSHInput (input, witnessScriptHash) {
if (input.prevOutType) {
if (input.prevOutType !== scriptTypes.P2WSH) throw new Error('PrevOutScript must be P2WSH')
case 'multisig':
signatures = scriptSigChunks.slice(1).map(function (chunk) {
if (chunk === ops.OP_0) return undefined
var scriptHash = bscript.decompile(input.prevOutScript)[1]
if (!scriptHash.equals(witnessScriptHash)) throw new Error('Inconsistent sha25(WitnessScript)')
}
}
parsed = ECSignature.parseScriptSignature(chunk)
hashType = parsed.hashType
function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScript) {
var expanded
var prevOutType
var prevOutScript
return parsed.signature
})
var p2sh = false
var p2shType
var redeemScriptHash
if (redeemScriptChunks) {
pubKeys = redeemScriptChunks.slice(1, -2)
var witness = false
var p2wsh = false
var witnessType
var witnessScriptHash
if (pubKeys.length !== signatures.length) {
signatures = fixMSSignatures(transaction, vin, pubKeys, signatures, bscript.compile(redeemScriptChunks), hashType, redeemScript)
}
}
var signType
var signScript
break
if (redeemScript && witnessScript) {
redeemScriptHash = bcrypto.hash160(redeemScript)
witnessScriptHash = bcrypto.sha256(witnessScript)
checkP2shInput(input, redeemScriptHash)
if (!redeemScript.equals(bscript.witnessScriptHash.output.encode(witnessScriptHash))) throw new Error('Witness script inconsistent with redeem script')
expanded = expandOutput(witnessScript, undefined, kpPubKey)
if (!expanded.pubKeys) throw new Error('WitnessScript not supported "' + bscript.toASM(redeemScript) + '"')
prevOutType = bscript.types.P2SH
prevOutScript = bscript.scriptHash.output.encode(redeemScriptHash)
p2sh = witness = p2wsh = true
p2shType = bscript.types.P2WSH
signType = witnessType = expanded.scriptType
signScript = witnessScript
} else if (redeemScript) {
redeemScriptHash = bcrypto.hash160(redeemScript)
checkP2shInput(input, redeemScriptHash)
expanded = expandOutput(redeemScript, undefined, kpPubKey)
if (!expanded.pubKeys) throw new Error('RedeemScript not supported "' + bscript.toASM(redeemScript) + '"')
prevOutType = bscript.types.P2SH
prevOutScript = bscript.scriptHash.output.encode(redeemScriptHash)
p2sh = true
signType = p2shType = expanded.scriptType
signScript = redeemScript
witness = signType === bscript.types.P2WPKH
} else if (witnessScript) {
witnessScriptHash = bcrypto.sha256(witnessScript)
checkP2WSHInput(input, witnessScriptHash)
expanded = expandOutput(witnessScript, undefined, kpPubKey)
if (!expanded.pubKeys) throw new Error('WitnessScript not supported "' + bscript.toASM(redeemScript) + '"')
prevOutType = bscript.types.P2WSH
prevOutScript = bscript.witnessScriptHash.output.encode(witnessScriptHash)
witness = p2wsh = true
signType = witnessType = expanded.scriptType
signScript = witnessScript
} else if (input.prevOutType) {
// embedded scripts are not possible without a redeemScript
if (input.prevOutType === scriptTypes.P2SH ||
input.prevOutType === scriptTypes.P2WSH) {
throw new Error('PrevOutScript is ' + input.prevOutType + ', requires redeemScript')
}
return {
hashType: hashType,
pubKeys: pubKeys,
signatures: signatures,
prevOutScript: prevOutScript,
redeemScript: redeemScript,
redeemScriptType: redeemScriptType
prevOutType = input.prevOutType
prevOutScript = input.prevOutScript
expanded = expandOutput(input.prevOutScript, input.prevOutType, kpPubKey)
if (!expanded.pubKeys) return
witness = (input.prevOutType === scriptTypes.P2WPKH)
signType = prevOutType
signScript = prevOutScript
} else {
prevOutScript = bscript.pubKeyHash.output.encode(bcrypto.hash160(kpPubKey))
expanded = expandOutput(prevOutScript, scriptTypes.P2PKH, kpPubKey)
prevOutType = scriptTypes.P2PKH
witness = false
signType = prevOutType
signScript = prevOutScript
}
if (witness && !types.Satoshi(witnessValue)) {
throw new Error('Input was witness but not given witness value')
}
if (signType === scriptTypes.P2WPKH) {
signScript = bscript.pubKeyHash.output.encode(bscript.witnessPubKeyHash.output.decode(signScript))
}
if (p2sh) {
input.redeemScript = redeemScript
input.redeemScriptType = p2shType
}
if (p2wsh) {
input.witnessScript = witnessScript
input.witnessScriptType = witnessType
}
input.pubKeys = expanded.pubKeys
input.signatures = expanded.signatures
input.signScript = signScript
input.signType = signType
input.prevOutScript = prevOutScript
input.prevOutType = prevOutType
input.witness = witness
}
function buildStack (type, signatures, pubKeys, allowIncomplete) {
if (type === scriptTypes.P2PKH) {
if (signatures.length === 1 && signatures[0] instanceof Buffer && pubKeys.length === 1) return bscript.pubKeyHash.input.encodeStack(signatures[0], pubKeys[0])
} else if (type === scriptTypes.P2PK) {
if (signatures.length === 1 && signatures[0] instanceof Buffer) return bscript.pubKey.input.encodeStack(signatures[0])
} else if (type === scriptTypes.MULTISIG) {
if (signatures.length > 0) {
signatures = signatures.map(function (signature) {
return signature || ops.OP_0
})
if (!allowIncomplete) {
// remove blank signatures
signatures = signatures.filter(function (x) { return x !== ops.OP_0 })
}
return bscript.multisig.input.encodeStack(signatures /* see if it's necessary first */)
}
} else {
throw new Error('Not yet supported')
}
// Extract hashType, pubKeys, signatures and prevOutScript
var result = processScript(prevOutType, scriptSigChunks)
if (!allowIncomplete) throw new Error('Not enough signatures provided')
return []
}
function buildInput (input, allowIncomplete) {
var scriptType = input.prevOutType
var sig = []
var witness = []
if (SIGNABLE.indexOf(scriptType) !== -1) {
sig = buildStack(scriptType, input.signatures, input.pubKeys, input.script, allowIncomplete)
}
var p2sh = false
if (scriptType === bscript.types.P2SH) {
// We can remove this error later when we have a guarantee prepareInput
// rejects unsignable scripts - it MUST be signable at this point.
if (P2SH.indexOf(input.redeemScriptType) === -1) {
throw new Error('Impossible to sign this type')
}
p2sh = true
if (SIGNABLE.indexOf(input.redeemScriptType) !== -1) {
sig = buildStack(input.redeemScriptType, input.signatures, input.pubKeys, allowIncomplete)
}
// If it wasn't SIGNABLE, it's witness, defer to that
scriptType = input.redeemScriptType
}
if (scriptType === bscript.types.P2WPKH) {
// P2WPKH is a special case of P2PKH
witness = buildStack(bscript.types.P2PKH, input.signatures, input.pubKeys, allowIncomplete)
} else if (scriptType === bscript.types.P2WSH) {
// We can remove this check later
if (SIGNABLE.indexOf(input.witnessScriptType) !== -1) {
witness = buildStack(input.witnessScriptType, input.signatures, input.pubKeys, allowIncomplete)
witness.push(input.witnessScript)
} else {
// We can remove this error later when we have a guarantee prepareInput
// rejects unsignble scripts - it MUST be signable at this point.
throw new Error()
}
scriptType = input.witnessScriptType
}
// append redeemScript if necessary
if (p2sh) {
sig.push(input.redeemScript)
}
return {
hashType: result.hashType,
prevOutScript: result.prevOutScript,
prevOutType: prevOutType,
pubKeys: result.pubKeys,
redeemScript: result.redeemScript,
redeemScriptType: result.redeemScriptType,
signatures: result.signatures
type: scriptType,
script: bscript.compile(sig),
witness: witness
}
}
function TransactionBuilder (network) {
function TransactionBuilder (network, maximumFeeRate) {
this.prevTxMap = {}
this.prevOutScripts = {}
this.prevOutTypes = {}
this.network = network || networks.bitcoin
// WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth)
this.maximumFeeRate = maximumFeeRate || 1000
this.inputs = []

@@ -179,12 +485,7 @@ this.tx = new Transaction()

// Copy other transaction fields
txb.tx.version = transaction.version
txb.tx.locktime = transaction.locktime
// Copy transaction fields
txb.setVersion(transaction.version)
txb.setLockTime(transaction.locktime)
// Extract/add inputs
transaction.ins.forEach(function (txIn) {
txb.addInput(txIn.hash, txIn.index, txIn.sequence)
})
// Extract/add outputs
// Copy outputs (done first to avoid signature invalidation)
transaction.outs.forEach(function (txOut) {

@@ -194,10 +495,14 @@ txb.addOutput(txOut.script, txOut.value)

// Extract/add signatures
txb.inputs = transaction.ins.map(function (txIn, vin) {
// TODO: verify whether extractInput is sane with coinbase scripts
if (Transaction.isCoinbaseHash(txIn.hash)) {
throw new Error('coinbase inputs not supported')
}
// Copy inputs
transaction.ins.forEach(function (txIn) {
txb.__addInputUnsafe(txIn.hash, txIn.index, {
sequence: txIn.sequence,
script: txIn.script,
witness: txIn.witness
})
})
return extractInput(transaction, txIn, vin)
// fix some things not possible through the public API
txb.inputs.forEach(function (input, i) {
fixMultisigOrder(input, transaction, i)
})

@@ -209,58 +514,71 @@

TransactionBuilder.prototype.addInput = function (txHash, vout, sequence, prevOutScript) {
if (!this.__canModifyInputs()) {
throw new Error('No, this would invalidate signatures')
}
var value
// is it a hex string?
if (typeof txHash === 'string') {
// transaction hashs's are displayed in reverse order, un-reverse it
txHash = bufferReverse(new Buffer(txHash, 'hex'))
txHash = new Buffer(txHash, 'hex').reverse()
// is it a Transaction object?
} else if (txHash instanceof Transaction) {
prevOutScript = txHash.outs[vout].script
var txOut = txHash.outs[vout]
prevOutScript = txOut.script
value = txOut.value
txHash = txHash.getHash()
}
return this.__addInputUnsafe(txHash, vout, {
sequence: sequence,
prevOutScript: prevOutScript,
value: value
})
}
TransactionBuilder.prototype.__addInputUnsafe = function (txHash, vout, options) {
if (Transaction.isCoinbaseHash(txHash)) {
throw new Error('coinbase inputs not supported')
}
var prevTxOut = txHash.toString('hex') + ':' + vout
if (this.prevTxMap[prevTxOut] !== undefined) throw new Error('Duplicate TxOut: ' + prevTxOut)
var input = {}
if (prevOutScript) {
var prevOutScriptChunks = bscript.decompile(prevOutScript)
var prevOutType = bscript.classifyOutput(prevOutScriptChunks)
// if we can, extract pubKey information
switch (prevOutType) {
case 'multisig':
input.pubKeys = prevOutScriptChunks.slice(1, -2)
input.signatures = input.pubKeys.map(function () { return undefined })
// derive what we can from the scriptSig
if (options.script !== undefined) {
input = expandInput(options.script, options.witness)
}
break
// if an input value was given, retain it
if (options.value !== undefined) {
input.value = options.value
}
case 'pubkey':
input.pubKeys = prevOutScriptChunks.slice(0, 1)
input.signatures = [undefined]
// derive what we can from the previous transactions output script
if (!input.prevOutScript && options.prevOutScript) {
var prevOutType
break
}
if (!input.pubKeys && !input.signatures) {
var expanded = expandOutput(options.prevOutScript)
if (prevOutType !== 'scripthash') {
input.scriptType = prevOutType
if (expanded.pubKeys) {
input.pubKeys = expanded.pubKeys
input.signatures = expanded.signatures
}
prevOutType = expanded.scriptType
}
input.prevOutScript = prevOutScript
input.prevOutType = prevOutType
input.prevOutScript = options.prevOutScript
input.prevOutType = prevOutType || bscript.classifyOutput(options.prevOutScript)
}
// if signatures exist, adding inputs is only acceptable if SIGHASH_ANYONECANPAY is used
// throw if any signatures *didn't* use SIGHASH_ANYONECANPAY
if (!this.inputs.every(function (otherInput) {
// no signature
if (otherInput.hashType === undefined) return true
return otherInput.hashType & Transaction.SIGHASH_ANYONECANPAY
})) {
throw new Error('No, this would invalidate signatures')
}
var prevOut = txHash.toString('hex') + ':' + vout
if (this.prevTxMap[prevOut]) throw new Error('Transaction is already an input')
var vin = this.tx.addInput(txHash, vout, sequence)
var vin = this.tx.addInput(txHash, vout, options.sequence, options.scriptSig)
this.inputs[vin] = input
this.prevTxMap[prevOut] = vin
this.prevTxMap[prevTxOut] = vin

@@ -271,19 +589,3 @@ return vin

TransactionBuilder.prototype.addOutput = function (scriptPubKey, value) {
var nOutputs = this.tx.outs.length
// if signatures exist, adding outputs is only acceptable if SIGHASH_NONE or SIGHASH_SINGLE is used
// throws if any signatures didn't use SIGHASH_NONE|SIGHASH_SINGLE
if (!this.inputs.every(function (input, index) {
// no signature
if (input.hashType === undefined) return true
var hashTypeMod = input.hashType & 0x1f
if (hashTypeMod === Transaction.SIGHASH_NONE) return true
if (hashTypeMod === Transaction.SIGHASH_SINGLE) {
// account for SIGHASH_SINGLE signing of a non-existing output, aka the "SIGHASH_SINGLE" bug
return index < nOutputs
}
return false
})) {
if (!this.__canModifyOutputs()) {
throw new Error('No, this would invalidate signatures')

@@ -307,50 +609,2 @@ }

var canBuildTypes = {
'multisig': true,
'pubkey': true,
'pubkeyhash': true
}
function buildFromInputData (input, scriptType, parentType, redeemScript, allowIncomplete) {
var scriptSig
switch (scriptType) {
case 'pubkeyhash':
var pkhSignature = input.signatures[0].toScriptSignature(input.hashType)
scriptSig = bscript.pubKeyHashInput(pkhSignature, input.pubKeys[0])
break
case 'pubkey':
var pkSignature = input.signatures[0].toScriptSignature(input.hashType)
scriptSig = bscript.pubKeyInput(pkSignature)
break
case 'multisig':
var msSignatures = input.signatures.map(function (signature) {
return signature && signature.toScriptSignature(input.hashType)
})
// fill in blanks with OP_0
if (allowIncomplete) {
for (var i = 0; i < msSignatures.length; ++i) {
msSignatures[i] = msSignatures[i] || ops.OP_0
}
// remove blank signatures
} else {
msSignatures = msSignatures.filter(function (x) { return x })
}
scriptSig = bscript.multisigInput(msSignatures, allowIncomplete ? undefined : redeemScript)
break
}
// wrap as scriptHash if necessary
if (parentType === 'scripthash') {
scriptSig = bscript.scriptHashInput(scriptSig, redeemScript)
}
return scriptSig
}
TransactionBuilder.prototype.__build = function (allowIncomplete) {

@@ -363,25 +617,25 @@ if (!allowIncomplete) {

var tx = this.tx.clone()
// Create script signatures from inputs
this.inputs.forEach(function (input, index) {
var scriptType = input.redeemScriptType || input.prevOutType
var scriptSig
this.inputs.forEach(function (input, i) {
var scriptType = input.witnessScriptType || input.redeemScriptType || input.prevOutType
if (!scriptType && !allowIncomplete) throw new Error('Transaction is not complete')
var result = buildInput(input, allowIncomplete)
// skip if no result
if (!allowIncomplete) {
if (!scriptType) throw new Error('Transaction is not complete')
if (!canBuildTypes[scriptType]) throw new Error(scriptType + ' not supported')
// XXX: only relevant to types that need signatures
if (!input.signatures) throw new Error('Transaction is missing signatures')
if (SIGNABLE.indexOf(result.type) === -1 && result.type !== bscript.types.P2WPKH) {
throw new Error(result.type + ' not supported')
}
}
if (input.signatures) {
scriptSig = buildFromInputData(input, scriptType, input.prevOutType, input.redeemScript, allowIncomplete)
}
tx.setInputScript(i, result.script)
tx.setWitness(i, result.witness)
})
// did we build a scriptSig? Buffer('') is allowed
if (scriptSig) {
tx.setInputScript(index, scriptSig)
if (!allowIncomplete) {
// do not rely on this, its merely a last resort
if (this.__overMaximumFees(tx.byteLength())) {
throw new Error('Transaction has absurd fees')
}
})
}

@@ -391,121 +645,107 @@ return tx

function extractFromOutputScript (outputScript, keyPair, kpPubKey) {
var scriptType = bscript.classifyOutput(outputScript)
var outputScriptChunks = bscript.decompile(outputScript)
switch (scriptType) {
case 'pubkeyhash':
var pkh1 = outputScriptChunks[2]
var pkh2 = bcrypto.hash160(keyPair.getPublicKeyBuffer())
if (!bufferEquals(pkh1, pkh2)) throw new Error('privateKey cannot sign for this input')
return {
pubKeys: [kpPubKey],
scriptType: scriptType
}
case 'pubkey':
return {
pubKeys: outputScriptChunks.slice(0, 1),
scriptType: scriptType
}
case 'multisig':
return {
pubKeys: outputScriptChunks.slice(1, -2),
scriptType: scriptType
}
}
function canSign (input) {
return input.prevOutScript !== undefined &&
input.signScript !== undefined &&
input.pubKeys !== undefined &&
input.signatures !== undefined &&
input.signatures.length === input.pubKeys.length &&
input.pubKeys.length > 0 &&
input.witness !== undefined
}
TransactionBuilder.prototype.sign = function (index, keyPair, redeemScript, hashType) {
TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashType, witnessValue, witnessScript) {
if (keyPair.network !== this.network) throw new Error('Inconsistent network')
if (!this.inputs[index]) throw new Error('No input at index: ' + index)
if (!this.inputs[vin]) throw new Error('No input at index: ' + vin)
hashType = hashType || Transaction.SIGHASH_ALL
var input = this.inputs[index]
var canSign = input.hashType &&
input.prevOutScript &&
input.prevOutType &&
input.pubKeys &&
input.redeemScriptType &&
input.signatures &&
input.signatures.length === input.pubKeys.length
var input = this.inputs[vin]
// if redeemScript was previously provided, enforce consistency
if (input.redeemScript !== undefined &&
redeemScript &&
!input.redeemScript.equals(redeemScript)) {
throw new Error('Inconsistent redeemScript')
}
var kpPubKey = keyPair.getPublicKeyBuffer()
var signatureScript
if (!canSign(input)) {
prepareInput(input, kpPubKey, redeemScript, witnessValue, witnessScript)
if (!canSign(input)) throw Error(input.prevOutType + ' not supported')
}
// are we ready to sign?
if (canSign) {
// if redeemScript was provided, enforce consistency
if (redeemScript) {
if (!bufferEquals(input.redeemScript, redeemScript)) throw new Error('Inconsistent redeemScript')
}
// ready to sign
var signatureHash
if (input.witness) {
signatureHash = this.tx.hashForWitnessV0(vin, input.signScript, witnessValue, hashType)
} else {
signatureHash = this.tx.hashForSignature(vin, input.signScript, hashType)
}
// enforce in order signing of public keys
var signed = input.pubKeys.some(function (pubKey, i) {
if (!kpPubKey.equals(pubKey)) return false
if (input.signatures[i]) throw new Error('Signature already exists')
if (input.hashType !== hashType) throw new Error('Inconsistent hashType')
input.signatures[i] = keyPair.sign(signatureHash).toScriptSignature(hashType)
return true
})
// no? prepare
} else {
// must be pay-to-scriptHash?
if (redeemScript) {
// if we have a prevOutScript, enforce scriptHash equality to the redeemScript
if (input.prevOutScript) {
if (input.prevOutType !== 'scripthash') throw new Error('PrevOutScript must be P2SH')
if (!signed) throw new Error('Key pair cannot sign for this input')
}
var scriptHash = bscript.decompile(input.prevOutScript)[1]
if (!bufferEquals(scriptHash, bcrypto.hash160(redeemScript))) throw new Error('RedeemScript does not match ' + scriptHash.toString('hex'))
}
function signatureHashType (buffer) {
return buffer.readUInt8(buffer.length - 1)
}
var extracted = extractFromOutputScript(redeemScript, keyPair, kpPubKey)
if (!extracted) throw new Error('RedeemScript not supported "' + bscript.toASM(redeemScript) + '"')
TransactionBuilder.prototype.__canModifyInputs = function () {
return this.inputs.every(function (input) {
// any signatures?
if (input.signatures === undefined) return true
// if we don't have a prevOutScript, generate a P2SH script
if (!input.prevOutScript) {
input.prevOutScript = bscript.scriptHashOutput(bcrypto.hash160(redeemScript))
input.prevOutType = 'scripthash'
}
return input.signatures.every(function (signature) {
if (!signature) return true
var hashType = signatureHashType(signature)
input.pubKeys = extracted.pubKeys
input.redeemScript = redeemScript
input.redeemScriptType = extracted.scriptType
input.signatures = extracted.pubKeys.map(function () { return undefined })
} else {
// pay-to-scriptHash is not possible without a redeemScript
if (input.prevOutType === 'scripthash') throw new Error('PrevOutScript is P2SH, missing redeemScript')
// if SIGHASH_ANYONECANPAY is set, signatures would not
// be invalidated by more inputs
return hashType & Transaction.SIGHASH_ANYONECANPAY
})
})
}
// if we don't have a scriptType, assume pubKeyHash otherwise
if (!input.scriptType) {
input.prevOutScript = bscript.pubKeyHashOutput(bcrypto.hash160(keyPair.getPublicKeyBuffer()))
input.prevOutType = 'pubkeyhash'
TransactionBuilder.prototype.__canModifyOutputs = function () {
var nInputs = this.tx.ins.length
var nOutputs = this.tx.outs.length
input.pubKeys = [kpPubKey]
input.scriptType = input.prevOutType
input.signatures = [undefined]
} else {
// throw if we can't sign with it
if (!input.pubKeys || !input.signatures) throw new Error(input.scriptType + ' not supported')
}
}
return this.inputs.every(function (input) {
if (input.signatures === undefined) return true
input.hashType = hashType
}
return input.signatures.every(function (signature) {
if (!signature) return true
var hashType = signatureHashType(signature)
// ready to sign?
signatureScript = signatureScript || input.redeemScript || input.prevOutScript
var signatureHash = this.tx.hashForSignature(index, signatureScript, hashType)
var hashTypeMod = hashType & 0x1f
if (hashTypeMod === Transaction.SIGHASH_NONE) return true
if (hashTypeMod === Transaction.SIGHASH_SINGLE) {
// if SIGHASH_SINGLE is set, and nInputs > nOutputs
// some signatures would be invalidated by the addition
// of more outputs
return nInputs <= nOutputs
}
})
})
}
// enforce in order signing of public keys
var valid = input.pubKeys.some(function (pubKey, i) {
if (!bufferEquals(kpPubKey, pubKey)) return false
if (input.signatures[i]) throw new Error('Signature already exists')
TransactionBuilder.prototype.__overMaximumFees = function (bytes) {
// not all inputs will have .value defined
var incoming = this.inputs.reduce(function (a, x) { return a + (x.value >>> 0) }, 0)
input.signatures[i] = keyPair.sign(signatureHash)
// but all outputs do, and if we have any input value
// we can immediately determine if the outputs are too small
var outgoing = this.tx.outs.reduce(function (a, x) { return a + x.value }, 0)
var fee = incoming - outgoing
var feeRate = fee / bytes
return true
})
if (!valid) throw new Error('Key pair cannot sign for this input')
return feeRate > this.maximumFeeRate
}
module.exports = TransactionBuilder
var bcrypto = require('./crypto')
var bscript = require('./script')
var bufferutils = require('./bufferutils')
var bufferReverse = require('buffer-reverse')
var opcodes = require('./opcodes.json')
var opcodes = require('bitcoin-ops')
var typeforce = require('typeforce')
var types = require('./types')
function varSliceSize (someScript) {
var length = someScript.length
return bufferutils.varIntSize(length) + length
}
function vectorSize (someVector) {
var length = someVector.length
return bufferutils.varIntSize(length) + someVector.reduce(function (sum, witness) {
return sum + varSliceSize(witness)
}, 0)
}
function Transaction () {

@@ -21,3 +34,15 @@ this.version = 1

Transaction.SIGHASH_ANYONECANPAY = 0x80
Transaction.ADVANCED_TRANSACTION_MARKER = 0x00
Transaction.ADVANCED_TRANSACTION_FLAG = 0x01
var EMPTY_SCRIPT = new Buffer(0)
var EMPTY_WITNESS = []
var ZERO = new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex')
var ONE = new Buffer('0000000000000000000000000000000000000000000000000000000000000001', 'hex')
var VALUE_UINT64_MAX = new Buffer('ffffffffffffffff', 'hex')
var BLANK_OUTPUT = {
script: EMPTY_SCRIPT,
valueBuffer: VALUE_UINT64_MAX
}
Transaction.fromBuffer = function (buffer, __noStrict) {

@@ -36,2 +61,8 @@ var offset = 0

function readInt32 () {
var i = buffer.readInt32LE(offset)
offset += 4
return i
}
function readUInt64 () {

@@ -49,9 +80,26 @@ var i = bufferutils.readUInt64LE(buffer, offset)

function readScript () {
function readVarSlice () {
return readSlice(readVarInt())
}
function readVector () {
var count = readVarInt()
var vector = []
for (var i = 0; i < count; i++) vector.push(readVarSlice())
return vector
}
var tx = new Transaction()
tx.version = readUInt32()
tx.version = readInt32()
var marker = buffer.readUInt8(offset)
var flag = buffer.readUInt8(offset + 1)
var hasWitnesses = false
if (marker === Transaction.ADVANCED_TRANSACTION_MARKER &&
flag === Transaction.ADVANCED_TRANSACTION_FLAG) {
offset += 2
hasWitnesses = true
}
var vinLen = readVarInt()

@@ -62,4 +110,5 @@ for (var i = 0; i < vinLen; ++i) {

index: readUInt32(),
script: readScript(),
sequence: readUInt32()
script: readVarSlice(),
sequence: readUInt32(),
witness: EMPTY_WITNESS
})

@@ -72,6 +121,15 @@ }

value: readUInt64(),
script: readScript()
script: readVarSlice()
})
}
if (hasWitnesses) {
for (i = 0; i < vinLen; ++i) {
tx.ins[i].witness = readVector()
}
// was this pointless?
if (!tx.hasWitnesses()) throw new Error('Transaction has superfluous witness data')
}
tx.locktime = readUInt32()

@@ -86,3 +144,3 @@

Transaction.fromHex = function (hex) {
return Transaction.fromBuffer(new Buffer(hex, 'hex'))
return Transaction.fromBuffer(Buffer.from(hex, 'hex'))
}

@@ -102,4 +160,2 @@

var EMPTY_SCRIPT = new Buffer(0)
Transaction.prototype.addInput = function (hash, index, sequence, scriptSig) {

@@ -122,3 +178,4 @@ typeforce(types.tuple(

script: scriptSig || EMPTY_SCRIPT,
sequence: sequence
sequence: sequence,
witness: EMPTY_WITNESS
}) - 1)

@@ -128,3 +185,3 @@ }

Transaction.prototype.addOutput = function (scriptPubKey, value) {
typeforce(types.tuple(types.Buffer, types.UInt53), arguments)
typeforce(types.tuple(types.Buffer, types.Satoshi), arguments)

@@ -138,15 +195,22 @@ // Add the output and return the output's index

Transaction.prototype.hasWitnesses = function () {
return this.ins.some(function (x) {
return x.witness.length !== 0
})
}
Transaction.prototype.byteLength = function () {
function scriptSize (someScript) {
var length = someScript.length
return this.__byteLength(true)
}
return bufferutils.varIntSize(length) + length
}
Transaction.prototype.__byteLength = function (__allowWitness) {
var hasWitnesses = __allowWitness && this.hasWitnesses()
return (
8 +
(hasWitnesses ? 10 : 8) +
bufferutils.varIntSize(this.ins.length) +
bufferutils.varIntSize(this.outs.length) +
this.ins.reduce(function (sum, input) { return sum + 40 + scriptSize(input.script) }, 0) +
this.outs.reduce(function (sum, output) { return sum + 8 + scriptSize(output.script) }, 0)
this.ins.reduce(function (sum, input) { return sum + 40 + varSliceSize(input.script) }, 0) +
this.outs.reduce(function (sum, output) { return sum + 8 + varSliceSize(output.script) }, 0) +
(hasWitnesses ? this.ins.reduce(function (sum, input) { return sum + vectorSize(input.witness) }, 0) : 0)
)

@@ -165,3 +229,4 @@ }

script: txIn.script,
sequence: txIn.sequence
sequence: txIn.sequence,
witness: txIn.witness
}

@@ -180,9 +245,2 @@ })

var ONE = new Buffer('0000000000000000000000000000000000000000000000000000000000000001', 'hex')
var VALUE_UINT64_MAX = new Buffer('ffffffffffffffff', 'hex')
var BLANK_OUTPUT = {
script: EMPTY_SCRIPT,
valueBuffer: VALUE_UINT64_MAX
}
/**

@@ -234,4 +292,4 @@ * Hash transaction for signing a specific input.

// ignore sequence numbers (except at inIndex)
txTmp.ins.forEach(function (input, i) {
if (i === inIndex) return
txTmp.ins.forEach(function (input, y) {
if (y === inIndex) return

@@ -255,5 +313,5 @@ input.sequence = 0

// serialize and hash
var buffer = new Buffer(txTmp.byteLength() + 4)
var buffer = new Buffer(txTmp.__byteLength(false) + 4)
buffer.writeInt32LE(hashType, buffer.length - 4)
txTmp.toBuffer(buffer, 0)
txTmp.__toBuffer(buffer, 0, false)

@@ -263,4 +321,87 @@ return bcrypto.hash256(buffer)

Transaction.prototype.hashForWitnessV0 = function (inIndex, prevOutScript, value, hashType) {
typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments)
var tbuffer, toffset
function writeSlice (slice) { toffset += slice.copy(tbuffer, toffset) }
function writeUInt32 (i) { toffset = tbuffer.writeUInt32LE(i, toffset) }
function writeUInt64 (i) { toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset) }
function writeVarInt (i) { toffset += bufferutils.writeVarInt(tbuffer, i, toffset) }
function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) }
var hashOutputs = ZERO
var hashPrevouts = ZERO
var hashSequence = ZERO
if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) {
tbuffer = new Buffer(36 * this.ins.length)
toffset = 0
this.ins.forEach(function (txIn) {
writeSlice(txIn.hash)
writeUInt32(txIn.index)
})
hashPrevouts = bcrypto.hash256(tbuffer)
}
if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) &&
(hashType & 0x1f) !== Transaction.SIGHASH_SINGLE &&
(hashType & 0x1f) !== Transaction.SIGHASH_NONE) {
tbuffer = new Buffer(4 * this.ins.length)
toffset = 0
this.ins.forEach(function (txIn) {
writeUInt32(txIn.sequence)
})
hashSequence = bcrypto.hash256(tbuffer)
}
if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE &&
(hashType & 0x1f) !== Transaction.SIGHASH_NONE) {
var txOutsSize = this.outs.reduce(function (sum, output) {
return sum + 8 + varSliceSize(output.script)
}, 0)
tbuffer = new Buffer(txOutsSize)
toffset = 0
this.outs.forEach(function (out) {
writeUInt64(out.value)
writeVarSlice(out.script)
})
hashOutputs = bcrypto.hash256(tbuffer)
} else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) {
var output = this.outs[inIndex]
tbuffer = new Buffer(8 + varSliceSize(output.script))
toffset = 0
writeUInt64(output.value)
writeVarSlice(output.script)
hashOutputs = bcrypto.hash256(tbuffer)
}
tbuffer = new Buffer(156 + varSliceSize(prevOutScript))
toffset = 0
var input = this.ins[inIndex]
writeUInt32(this.version)
writeSlice(hashPrevouts)
writeSlice(hashSequence)
writeSlice(input.hash)
writeUInt32(input.index)
writeVarSlice(prevOutScript)
writeUInt64(value)
writeUInt32(input.sequence)
writeSlice(hashOutputs)
writeUInt32(this.locktime)
writeUInt32(hashType)
return bcrypto.hash256(tbuffer)
}
Transaction.prototype.getHash = function () {
return bcrypto.hash256(this.toBuffer())
return bcrypto.hash256(this.__toBuffer(undefined, undefined, false))
}

@@ -270,30 +411,31 @@

// transaction hash's are displayed in reverse order
return bufferReverse(this.getHash()).toString('hex')
return this.getHash().reverse().toString('hex')
}
Transaction.prototype.toBuffer = function (buffer, initialOffset) {
if (!buffer) buffer = new Buffer(this.byteLength())
return this.__toBuffer(buffer, initialOffset, true)
}
Transaction.prototype.__toBuffer = function (buffer, initialOffset, __allowWitness) {
if (!buffer) buffer = new Buffer(this.__byteLength(__allowWitness))
var offset = initialOffset || 0
function writeSlice (slice) {
slice.copy(buffer, offset)
offset += slice.length
}
function writeSlice (slice) { offset += slice.copy(buffer, offset) }
function writeUInt8 (i) { offset = buffer.writeUInt8(i, offset) }
function writeUInt32 (i) { offset = buffer.writeUInt32LE(i, offset) }
function writeInt32 (i) { offset = buffer.writeInt32LE(i, offset) }
function writeUInt64 (i) { offset = bufferutils.writeUInt64LE(buffer, i, offset) }
function writeVarInt (i) { offset += bufferutils.writeVarInt(buffer, i, offset) }
function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) }
function writeVector (vector) { writeVarInt(vector.length); vector.forEach(writeVarSlice) }
function writeUInt32 (i) {
buffer.writeUInt32LE(i, offset)
offset += 4
}
writeInt32(this.version)
function writeUInt64 (i) {
bufferutils.writeUInt64LE(buffer, i, offset)
offset += 8
}
var hasWitnesses = __allowWitness && this.hasWitnesses()
function writeVarInt (i) {
var n = bufferutils.writeVarInt(buffer, i, offset)
offset += n
if (hasWitnesses) {
writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER)
writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG)
}
writeUInt32(this.version)
writeVarInt(this.ins.length)

@@ -304,4 +446,3 @@

writeUInt32(txIn.index)
writeVarInt(txIn.script.length)
writeSlice(txIn.script)
writeVarSlice(txIn.script)
writeUInt32(txIn.sequence)

@@ -318,6 +459,11 @@ })

writeVarInt(txOut.script.length)
writeSlice(txOut.script)
writeVarSlice(txOut.script)
})
if (hasWitnesses) {
this.ins.forEach(function (input) {
writeVector(input.witness)
})
}
writeUInt32(this.locktime)

@@ -327,3 +473,2 @@

if (initialOffset !== undefined) return buffer.slice(initialOffset, offset)
return buffer

@@ -342,2 +487,8 @@ }

Transaction.prototype.setWitness = function (index, witness) {
typeforce(types.tuple(types.Number, [types.Buffer]), arguments)
this.ins[index].witness = witness
}
module.exports = Transaction
var typeforce = require('typeforce')
function nBuffer (value, n) {
typeforce(types.Buffer, value)
if (value.length !== n) throw new typeforce.TfTypeError('Expected ' + (n * 8) + '-bit Buffer, got ' + (value.length * 8) + '-bit Buffer')
return true
}
function Hash160bit (value) { return nBuffer(value, 20) }
function Hash256bit (value) { return nBuffer(value, 32) }
function Buffer256bit (value) { return nBuffer(value, 32) }
var UINT53_MAX = Math.pow(2, 53) - 1
var UINT31_MAX = Math.pow(2, 31) - 1
function UInt2 (value) { return (value & 3) === value }
function UInt8 (value) { return (value & 0xff) === value }
function UInt32 (value) { return (value >>> 0) === value }
function UInt31 (value) {
return UInt32(value) && value <= UINT31_MAX
return typeforce.UInt32(value) && value <= UINT31_MAX
}
function UInt53 (value) {
return typeforce.Number(value) &&
value >= 0 &&
value <= UINT53_MAX &&
Math.floor(value) === value
function BIP32Path (value) {
return typeforce.String(value) && value.match(/^(m\/)?(\d+'?\/)*\d+'?$/)
}
BIP32Path.toJSON = function () { return 'BIP32 derivation path' }
function Bip32Path (value) {
return typeforce.String(value) &&
value.match(/^(m\/)?(\d+'?\/)*\d+'?$/)
var SATOSHI_MAX = 21 * 1e14
function Satoshi (value) {
return typeforce.UInt53(value) && value <= SATOSHI_MAX
}

@@ -43,9 +27,8 @@

bip32: {
public: UInt32,
private: UInt32
public: typeforce.UInt32,
private: typeforce.UInt32
},
pubKeyHash: UInt8,
scriptHash: UInt8,
wif: UInt8,
dustThreshold: UInt53
pubKeyHash: typeforce.UInt8,
scriptHash: typeforce.UInt8,
wif: typeforce.UInt8
})

@@ -56,14 +39,11 @@

BigInt: BigInt,
Buffer256bit: Buffer256bit,
BIP32Path: BIP32Path,
Buffer256bit: typeforce.BufferN(32),
ECPoint: ECPoint,
ECSignature: ECSignature,
Hash160bit: Hash160bit,
Hash256bit: Hash256bit,
Hash160bit: typeforce.BufferN(20),
Hash256bit: typeforce.BufferN(32),
Network: Network,
UInt2: UInt2,
UInt8: UInt8,
UInt31: UInt31,
UInt32: UInt32,
UInt53: UInt53,
Bip32Path: Bip32Path
Satoshi: Satoshi,
UInt31: UInt31
}

@@ -70,0 +50,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc