Merge pull request #385 from bitcoinjs/ecpair

ECPair
This commit is contained in:
Daniel Cousens 2015-04-09 14:41:28 +10:00
commit 12dbe571a4
23 changed files with 753 additions and 670 deletions

151
src/ecpair.js Normal file
View file

@ -0,0 +1,151 @@
var assert = require('assert')
var base58check = require('bs58check')
var bcrypto = require('./crypto')
var ecdsa = require('./ecdsa')
var ecurve = require('ecurve')
var networks = require('./networks')
var randomBytes = require('randombytes')
var typeForce = require('typeforce')
var Address = require('./address')
var BigInteger = require('bigi')
function findNetworkByWIFVersion (version) {
for (var networkName in networks) {
var network = networks[networkName]
if (network.wif === version) return network
}
assert(false, 'Unknown network')
}
function ECPair (d, Q, options) {
options = options || {}
var compressed = options.compressed === undefined ? true : options.compressed
var network = options.network === undefined ? networks.bitcoin : options.network
typeForce('Boolean', compressed)
assert('pubKeyHash' in network, 'Unknown pubKeyHash constants for network')
if (d) {
assert(d.signum() > 0, 'Private key must be greater than 0')
assert(d.compareTo(ECPair.curve.n) < 0, 'Private key must be less than the curve order')
assert(!Q, 'Unexpected publicKey parameter')
this.d = d
// enforce Q is a public key if no private key given
} else {
typeForce('Point', Q)
this.__Q = Q
}
this.compressed = compressed
this.network = network
}
Object.defineProperty(ECPair.prototype, 'Q', {
get: function () {
if (!this.__Q && this.d) {
this.__Q = ECPair.curve.G.multiply(this.d)
}
return this.__Q
}
})
// Public access to secp256k1 curve
ECPair.curve = ecurve.getCurveByName('secp256k1')
ECPair.fromPublicKeyBuffer = function (buffer, network) {
var Q = ecurve.Point.decodeFrom(ECPair.curve, buffer)
return new ECPair(null, Q, {
compressed: Q.compressed,
network: network
})
}
ECPair.fromWIF = function (string) {
var payload = base58check.decode(string)
var version = payload.readUInt8(0)
var compressed
if (payload.length === 34) {
assert.strictEqual(payload[33], 0x01, 'Invalid compression flag')
// truncate the version/compression bytes
payload = payload.slice(1, -1)
compressed = true
// no compression flag
} else {
assert.equal(payload.length, 33, 'Invalid WIF payload length')
// Truncate the version byte
payload = payload.slice(1)
compressed = false
}
var network = findNetworkByWIFVersion(version)
var d = BigInteger.fromBuffer(payload)
return new ECPair(d, null, {
compressed: compressed,
network: network
})
}
ECPair.makeRandom = function (options) {
options = options || {}
var rng = options.rng || randomBytes
var buffer = rng(32)
typeForce('Buffer', buffer)
assert.equal(buffer.length, 32, 'Expected 256-bit Buffer from RNG')
var d = BigInteger.fromBuffer(buffer)
d = d.mod(ECPair.curve.n)
return new ECPair(d, null, options)
}
ECPair.prototype.toWIF = function () {
assert(this.d, 'Missing private key')
var bufferLen = this.compressed ? 34 : 33
var buffer = new Buffer(bufferLen)
buffer.writeUInt8(this.network.wif, 0)
this.d.toBuffer(32).copy(buffer, 1)
if (this.compressed) {
buffer.writeUInt8(0x01, 33)
}
return base58check.encode(buffer)
}
ECPair.prototype.getAddress = function () {
var pubKey = this.getPublicKeyBuffer()
return new Address(bcrypto.hash160(pubKey), this.network.pubKeyHash)
}
ECPair.prototype.getPublicKeyBuffer = function () {
return this.Q.getEncoded(this.compressed)
}
ECPair.prototype.sign = function (hash) {
assert(this.d, 'Missing private key')
return ecdsa.sign(ECPair.curve, hash, this.d)
}
ECPair.prototype.verify = function (hash, signature) {
return ecdsa.verify(ECPair.curve, hash, signature, this.Q)
}
module.exports = ECPair

View file

@ -6,8 +6,7 @@ var typeForce = require('typeforce')
var networks = require('./networks')
var BigInteger = require('bigi')
var ECKey = require('./eckey')
var ECPubKey = require('./ecpubkey')
var ECPair = require('./ecpair')
var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')
@ -24,32 +23,19 @@ function findBIP32NetworkByVersion (version) {
assert(false, 'Could not find network for ' + version.toString(16))
}
function HDNode (K, chainCode, network) {
network = network || networks.bitcoin
function HDNode (keyPair, chainCode) {
typeForce('ECPair', keyPair)
typeForce('Buffer', chainCode)
assert.equal(chainCode.length, 32, 'Expected chainCode length of 32, got ' + chainCode.length)
assert(network.bip32, 'Unknown BIP32 constants for network')
assert('bip32' in keyPair.network, 'Unknown BIP32 constants for network')
assert.equal(keyPair.compressed, true, 'BIP32 only allows compressed keyPairs')
this.keyPair = keyPair
this.chainCode = chainCode
this.depth = 0
this.index = 0
this.parentFingerprint = 0x00000000
this.network = network
if (K instanceof BigInteger) {
this.privKey = new ECKey(K, true)
this.pubKey = this.privKey.pub
} else if (K instanceof ECKey) {
assert(K.pub.compressed, 'ECKey must be compressed')
this.privKey = K
} else if (K instanceof ECPubKey) {
assert(K.compressed, 'ECPubKey must be compressed')
this.pubKey = K
} else {
this.pubKey = new ECPubKey(K, true)
}
}
HDNode.MASTER_SECRET = new Buffer('Bitcoin seed')
@ -67,10 +53,13 @@ HDNode.fromSeedBuffer = function (seed, network) {
var IR = I.slice(32)
// In case IL is 0 or >= n, the master key is invalid
// This is handled by `new ECKey` in the HDNode constructor
// This is handled by the ECPair constructor
var pIL = BigInteger.fromBuffer(IL)
var keyPair = new ECPair(pIL, null, {
network: network
})
return new HDNode(pIL, IR, network)
return new HDNode(keyPair, IR)
}
HDNode.fromSeedHex = function (hex, network) {
@ -108,14 +97,17 @@ HDNode.fromBase58 = function (string, network) {
// 32 bytes: the chain code
var chainCode = buffer.slice(13, 45)
var data, hd
var data, keyPair
// 33 bytes: private key data (0x00 + k)
if (version === network.bip32.private) {
assert.strictEqual(buffer.readUInt8(45), 0x00, 'Invalid private key')
data = buffer.slice(46, 78)
var d = BigInteger.fromBuffer(data)
hd = new HDNode(d, chainCode, network)
keyPair = new ECPair(d, null, {
network: network
})
// 33 bytes: public key data (0x02 + X or 0x03 + X)
} else {
@ -127,9 +119,12 @@ HDNode.fromBase58 = function (string, network) {
// If not, the extended public key is invalid.
curve.validate(Q)
hd = new HDNode(Q, chainCode, network)
keyPair = new ECPair(null, Q, {
network: network
})
}
var hd = new HDNode(keyPair, chainCode)
hd.depth = depth
hd.index = index
hd.parentFingerprint = parentFingerprint
@ -138,7 +133,7 @@ HDNode.fromBase58 = function (string, network) {
}
HDNode.prototype.getIdentifier = function () {
return bcrypto.hash160(this.pubKey.toBuffer())
return bcrypto.hash160(this.keyPair.getPublicKeyBuffer())
}
HDNode.prototype.getFingerprint = function () {
@ -146,11 +141,15 @@ HDNode.prototype.getFingerprint = function () {
}
HDNode.prototype.getAddress = function () {
return this.pubKey.getAddress(this.network)
return this.keyPair.getAddress()
}
HDNode.prototype.neutered = function () {
var neutered = new HDNode(this.pubKey.Q, this.chainCode, this.network)
var neuteredKeyPair = new ECPair(null, this.keyPair.Q, {
network: this.keyPair.network
})
var neutered = new HDNode(neuteredKeyPair, this.chainCode)
neutered.depth = this.depth
neutered.index = this.index
neutered.parentFingerprint = this.parentFingerprint
@ -162,7 +161,8 @@ HDNode.prototype.toBase58 = function (__isPrivate) {
assert.strictEqual(__isPrivate, undefined, 'Unsupported argument in 2.0.0')
// Version
var version = this.privKey ? this.network.bip32.private : this.network.bip32.public
var network = this.keyPair.network
var version = this.keyPair.d ? network.bip32.private : network.bip32.public
var buffer = new Buffer(HDNode.LENGTH)
// 4 bytes: version bytes
@ -182,16 +182,16 @@ HDNode.prototype.toBase58 = function (__isPrivate) {
// 32 bytes: the chain code
this.chainCode.copy(buffer, 13)
// 33 bytes: the private key, or
if (this.privKey) {
// 33 bytes: the public key or private key data
if (this.keyPair.d) {
// 0x00 + k for private keys
buffer.writeUInt8(0, 45)
this.privKey.d.toBuffer(32).copy(buffer, 46)
this.keyPair.d.toBuffer(32).copy(buffer, 46)
// 33 bytes: the public key
} else {
// X9.62 encoding for public keys
this.pubKey.toBuffer().copy(buffer, 45)
this.keyPair.getPublicKeyBuffer().copy(buffer, 45)
}
return base58check.encode(buffer)
@ -207,11 +207,11 @@ HDNode.prototype.derive = function (index) {
// Hardened child
if (isHardened) {
assert(this.privKey, 'Could not derive hardened child key')
assert(this.keyPair.d, 'Could not derive hardened child key')
// data = 0x00 || ser256(kpar) || ser32(index)
data = Buffer.concat([
this.privKey.d.toBuffer(33),
this.keyPair.d.toBuffer(33),
indexBuffer
])
@ -220,7 +220,7 @@ HDNode.prototype.derive = function (index) {
// data = serP(point(kpar)) || ser32(index)
// = serP(Kpar) || ser32(index)
data = Buffer.concat([
this.pubKey.toBuffer(),
this.keyPair.getPublicKeyBuffer(),
indexBuffer
])
}
@ -237,32 +237,37 @@ HDNode.prototype.derive = function (index) {
}
// Private parent key -> private child key
var hd
if (this.privKey) {
var derivedKeyPair
if (this.keyPair.d) {
// ki = parse256(IL) + kpar (mod n)
var ki = pIL.add(this.privKey.d).mod(curve.n)
var ki = pIL.add(this.keyPair.d).mod(curve.n)
// In case ki == 0, proceed with the next value for i
if (ki.signum() === 0) {
return this.derive(index + 1)
}
hd = new HDNode(ki, IR, this.network)
derivedKeyPair = new ECPair(ki, null, {
network: this.keyPair.network
})
// Public parent key -> public child key
} else {
// Ki = point(parse256(IL)) + Kpar
// = G*IL + Kpar
var Ki = curve.G.multiply(pIL).add(this.pubKey.Q)
var Ki = curve.G.multiply(pIL).add(this.keyPair.Q)
// In case Ki is the point at infinity, proceed with the next value for i
if (curve.isInfinity(Ki)) {
return this.derive(index + 1)
}
hd = new HDNode(Ki, IR, this.network)
derivedKeyPair = new ECPair(null, Ki, {
network: this.keyPair.network
})
}
var hd = new HDNode(derivedKeyPair, IR)
hd.depth = this.depth + 1
hd.index = index
hd.parentFingerprint = this.getFingerprint().readUInt32BE(0)

View file

@ -4,8 +4,7 @@ module.exports = {
bufferutils: require('./bufferutils'),
crypto: require('./crypto'),
ecdsa: require('./ecdsa'),
ECKey: require('./eckey'),
ECPubKey: require('./ecpubkey'),
ECPair: require('./ecpair'),
ECSignature: require('./ecsignature'),
message: require('./message'),
opcodes: require('./opcodes'),

View file

@ -4,7 +4,7 @@ var ecdsa = require('./ecdsa')
var networks = require('./networks')
var BigInteger = require('bigi')
var ECPubKey = require('./ecpubkey')
var ECPair = require('./ecpair')
var ECSignature = require('./ecsignature')
var ecurve = require('ecurve')
@ -19,15 +19,15 @@ function magicHash (message, network) {
return crypto.hash256(buffer)
}
function sign (privKey, message, network) {
function sign (keyPair, message, network) {
network = network || networks.bitcoin
var hash = magicHash(message, network)
var signature = privKey.sign(hash)
var signature = keyPair.sign(hash)
var e = BigInteger.fromBuffer(hash)
var i = ecdsa.calcPubKeyRecoveryParam(ecparams, e, signature, privKey.pub.Q)
var i = ecdsa.calcPubKeyRecoveryParam(ecparams, e, signature, keyPair.Q)
return signature.toCompact(i, privKey.pub.compressed)
return signature.toCompact(i, keyPair.compressed)
}
// TODO: network could be implied from address
@ -42,9 +42,12 @@ function verify (address, signature, message, network) {
var parsed = ECSignature.parseCompact(signature)
var e = BigInteger.fromBuffer(hash)
var Q = ecdsa.recoverPubKey(ecparams, e, parsed.signature, parsed.i)
var keyPair = new ECPair(null, Q, {
compressed: parsed.compressed,
network: network
})
var pubKey = new ECPubKey(Q, parsed.compressed)
return pubKey.getAddress(network).toString() === address.toString()
return keyPair.getAddress().toString() === address.toString()
}
module.exports = {

View file

@ -170,7 +170,7 @@ function classifyInput (script, allowIncomplete) {
// {pubKey} OP_CHECKSIG
function pubKeyOutput (pubKey) {
return Script.fromChunks([
pubKey.toBuffer(),
pubKey,
ops.OP_CHECKSIG
])
}
@ -201,18 +201,14 @@ function scriptHashOutput (hash) {
// m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput (m, pubKeys) {
typeForce(['ECPubKey'], pubKeys)
typeForce(['Buffer'], pubKeys)
assert(pubKeys.length >= m, 'Not enough pubKeys provided')
var pubKeyBuffers = pubKeys.map(function (pubKey) {
return pubKey.toBuffer()
})
var n = pubKeys.length
assert(n >= m, 'Not enough pubKeys provided')
return Script.fromChunks([].concat(
(ops.OP_1 - 1) + m,
pubKeyBuffers,
pubKeys,
(ops.OP_1 - 1) + n,
ops.OP_CHECKMULTISIG
))
@ -228,8 +224,9 @@ function pubKeyInput (signature) {
// {signature} {pubKey}
function pubKeyHashInput (signature, pubKey) {
typeForce('Buffer', signature)
typeForce('Buffer', pubKey)
return Script.fromChunks([signature, pubKey.toBuffer()])
return Script.fromChunks([signature, pubKey])
}
// <scriptSig> {serialized scriptPubKey script}

View file

@ -1,9 +1,10 @@
var assert = require('assert')
var bufferutils = require('./bufferutils')
var ops = require('./opcodes')
var scripts = require('./scripts')
var Address = require('./address')
var ECPubKey = require('./ecpubkey')
var ECPair = require('./ecpair')
var ECSignature = require('./ecsignature')
var Script = require('./script')
var Transaction = require('./transaction')
@ -33,9 +34,9 @@ function extractInput (txIn) {
case 'pubkeyhash': {
parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
hashType = parsed.hashType
pubKeys = [ECPubKey.fromBuffer(scriptSig.chunks[1])]
pubKeys = scriptSig.chunks.slice(1)
signatures = [parsed.signature]
prevOutScript = pubKeys[0].getAddress().toOutputScript()
prevOutScript = ECPair.fromPublicKeyBuffer(pubKeys[0]).getAddress().toOutputScript()
break
}
@ -46,7 +47,7 @@ function extractInput (txIn) {
signatures = [parsed.signature]
if (redeemScript) {
pubKeys = [ECPubKey.fromBuffer(redeemScript.chunks[0])]
pubKeys = redeemScript.chunks.slice(0, 1)
}
break
@ -63,7 +64,7 @@ function extractInput (txIn) {
})
if (redeemScript) {
pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
pubKeys = redeemScript.chunks.slice(1, -2)
}
break
@ -141,12 +142,12 @@ TransactionBuilder.prototype.addInput = function (txHash, vout, sequence, prevOu
// if we can, extract pubKey information
switch (prevOutType) {
case 'multisig': {
input.pubKeys = prevOutScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
input.pubKeys = prevOutScript.chunks.slice(1, -2)
break
}
case 'pubkey': {
input.pubKeys = prevOutScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer)
input.pubKeys = prevOutScript.chunks.slice(0, 1)
break
}
}
@ -280,7 +281,7 @@ TransactionBuilder.prototype.__build = function (allowIncomplete) {
return tx
}
TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hashType) {
TransactionBuilder.prototype.sign = function (index, keyPair, redeemScript, hashType) {
assert(index in this.inputs, 'No input at index: ' + index)
hashType = hashType || Transaction.SIGHASH_ALL
@ -292,6 +293,8 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash
input.scriptType &&
input.signatures
var kpPubKey = keyPair.getPublicKeyBuffer()
// are we almost ready to sign?
if (canSign) {
// if redeemScript was provided, enforce consistency
@ -319,21 +322,21 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash
var pubKeys = []
switch (scriptType) {
case 'multisig': {
pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
pubKeys = redeemScript.chunks.slice(1, -2)
break
}
case 'pubkeyhash': {
var pkh1 = redeemScript.chunks[2]
var pkh2 = privKey.pub.getAddress().hash
var pkh2 = keyPair.getAddress().hash
assert.deepEqual(pkh1, pkh2, 'privateKey cannot sign for this input')
pubKeys = [privKey.pub]
pubKeys = [kpPubKey]
break
}
case 'pubkey': {
pubKeys = redeemScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer)
pubKeys = redeemScript.chunks.slice(0, 1)
break
}
}
@ -357,9 +360,9 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash
// we know nothin' Jon Snow, assume pubKeyHash
} else {
input.prevOutScript = privKey.pub.getAddress().toOutputScript()
input.prevOutScript = keyPair.getAddress().toOutputScript()
input.prevOutType = 'pubkeyhash'
input.pubKeys = [privKey.pub]
input.pubKeys = [kpPubKey]
input.scriptType = input.prevOutType
}
}
@ -378,10 +381,11 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash
input.signatures = input.pubKeys.map(function (pubKey) {
var match
var keyPair2 = ECPair.fromPublicKeyBuffer(pubKey)
// check for any matching signatures
unmatched.some(function (signature, i) {
if (!pubKey.verify(signatureHash, signature)) return false
if (!keyPair2.verify(signatureHash, signature)) return false
match = signature
// remove matched signature from unmatched
@ -396,14 +400,15 @@ TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hash
// enforce in order signing of public keys
assert(input.pubKeys.some(function (pubKey, i) {
if (!privKey.pub.Q.equals(pubKey.Q)) return false
if (!bufferutils.equal(kpPubKey, pubKey)) return false
assert(!input.signatures[i], 'Signature already exists')
var signature = privKey.sign(signatureHash)
var signature = keyPair.sign(signatureHash)
input.signatures[i] = signature
return true
}, this), 'privateKey cannot sign for this input')
}, this), 'key pair cannot sign for this input')
}
module.exports = TransactionBuilder

View file

@ -2,12 +2,11 @@
var assert = require('assert')
var base58 = require('bs58')
var base58check = require('bs58check')
var Bitcoin = require('../')
var Address = Bitcoin.Address
var Block = Bitcoin.Block
var ECKey = Bitcoin.ECKey
var ECPair = Bitcoin.ECPair
var ECSignature = Bitcoin.ECSignature
var Transaction = Bitcoin.Transaction
var Script = Bitcoin.Script
@ -95,32 +94,31 @@ describe('Bitcoin-core', function () {
})
// base58_keys_valid
describe('ECKey', function () {
describe('ECPair', function () {
base58_keys_valid.forEach(function (f) {
var string = f[0]
var hex = f[1]
var params = f[2]
var network = params.isTestnet ? networks.testnet : networks.bitcoin
if (!params.isPrivkey) return
var privKey = ECKey.fromWIF(string)
var keyPair = ECPair.fromWIF(string)
it('imports ' + string + ' correctly', function () {
assert.equal(privKey.d.toHex(), hex)
assert.equal(privKey.pub.compressed, params.isCompressed)
assert.equal(keyPair.d.toHex(), hex)
assert.equal(keyPair.compressed, params.isCompressed)
})
it('exports ' + hex + ' to ' + string, function () {
assert.equal(privKey.toWIF(network), string)
assert.equal(keyPair.toWIF(), string)
})
})
})
// base58_keys_invalid
describe('ECKey', function () {
describe('ECPair', function () {
var allowedNetworks = [
networks.bitcoin.wif,
networks.testnet.wif
networks.bitcoin,
networks.testnet
]
base58_keys_invalid.forEach(function (f) {
@ -128,11 +126,10 @@ describe('Bitcoin-core', function () {
it('throws on ' + string, function () {
assert.throws(function () {
ECKey.fromWIF(string)
var version = base58check.decode(string).readUInt8(0)
var keyPair = ECPair.fromWIF(string)
assert.notEqual(allowedNetworks.indexOf(version), -1, 'Invalid network')
}, /Invalid (checksum|compression flag|network|WIF payload)/)
assert(allowedNetworks.indexOf(keyPair.network) > -1, 'Invalid network')
}, /(Invalid|Unknown) (checksum|compression flag|network|WIF payload)/)
})
})
})

View file

@ -1,143 +0,0 @@
/* global describe, it */
/* eslint-disable no-new */
var assert = require('assert')
var ecurve = require('ecurve')
var networks = require('../src/networks')
var proxyquire = require('proxyquire')
var randomBytes = require('randombytes')
var BigInteger = require('bigi')
var ECKey = require('../src/eckey')
var fixtures = require('./fixtures/eckey.json')
describe('ECKey', function () {
describe('constructor', function () {
it('defaults to compressed', function () {
var privKey = new ECKey(BigInteger.ONE)
assert.equal(privKey.pub.compressed, true)
})
it('supports the uncompressed flag', function () {
var privKey = new ECKey(BigInteger.ONE, false)
assert.equal(privKey.pub.compressed, false)
})
fixtures.valid.forEach(function (f) {
it('calculates the matching pubKey for ' + f.d, function () {
var d = new BigInteger(f.d)
var privKey = new ECKey(d)
assert.equal(privKey.pub.Q.toString(), f.Q)
})
})
fixtures.invalid.constructor.forEach(function (f) {
it('throws on ' + f.d, function () {
var d = new BigInteger(f.d)
assert.throws(function () {
new ECKey(d)
}, new RegExp(f.exception))
})
})
})
it('uses the secp256k1 curve by default', function () {
var secp256k1 = ecurve.getCurveByName('secp256k1')
for (var property in secp256k1) {
// FIXME: circular structures in ecurve
if (property === 'G') continue
if (property === 'infinity') continue
var actual = ECKey.curve[property]
var expected = secp256k1[property]
assert.deepEqual(actual, expected)
}
})
describe('fromWIF', function () {
fixtures.valid.forEach(function (f) {
f.WIFs.forEach(function (wif) {
it('imports ' + wif.string + ' correctly', function () {
var privKey = ECKey.fromWIF(wif.string)
assert.equal(privKey.d.toString(), f.d)
assert.equal(privKey.pub.compressed, wif.compressed)
})
})
})
fixtures.invalid.WIF.forEach(function (f) {
it('throws on ' + f.string, function () {
assert.throws(function () {
ECKey.fromWIF(f.string)
}, new RegExp(f.exception))
})
})
})
describe('toWIF', function () {
fixtures.valid.forEach(function (f) {
f.WIFs.forEach(function (wif) {
it('exports ' + wif.string + ' correctly', function () {
var privKey = ECKey.fromWIF(wif.string)
var network = networks[wif.network]
var result = privKey.toWIF(network)
assert.equal(result, wif.string)
})
})
})
})
describe('makeRandom', function () {
var exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv'
var exPrivKey = ECKey.fromWIF(exWIF)
var exBuffer = exPrivKey.d.toBuffer(32)
it("uses the RNG provided by the 'randombytes' module by default", function () {
var stub = { randombytes: function () { return exBuffer } }
var ProxiedECKey = proxyquire('../src/eckey', stub)
var privKey = ProxiedECKey.makeRandom()
assert.equal(privKey.toWIF(), exWIF)
})
it('allows a custom RNG to be used', function () {
function rng (size) {
return exBuffer.slice(0, size)
}
var privKey = ECKey.makeRandom(undefined, rng)
assert.equal(privKey.toWIF(), exWIF)
})
it('supports compression', function () {
assert.equal(ECKey.makeRandom(true).pub.compressed, true)
assert.equal(ECKey.makeRandom(false).pub.compressed, false)
})
})
describe('signing', function () {
var hash = randomBytes(32)
var priv = ECKey.makeRandom()
var signature = priv.sign(hash)
it('should verify against the public key', function () {
assert(priv.pub.verify(hash, signature))
})
it('should not verify against the wrong public key', function () {
var priv2 = ECKey.makeRandom()
assert(!priv2.pub.verify(hash, signature))
})
})
})

234
test/ecpair.js Normal file
View file

@ -0,0 +1,234 @@
/* global describe, it, beforeEach */
/* eslint-disable no-new */
var assert = require('assert')
var ecdsa = require('../src/ecdsa')
var ecurve = require('ecurve')
var networks = require('../src/networks')
var proxyquire = require('proxyquire')
var sinon = require('sinon')
var BigInteger = require('bigi')
var ECPair = require('../src/ecpair')
var fixtures = require('./fixtures/ecpair.json')
describe('ECPair', function () {
describe('constructor', function () {
it('defaults to compressed', function () {
var keyPair = new ECPair(BigInteger.ONE)
assert.equal(keyPair.compressed, true)
})
it('supports the uncompressed option', function () {
var keyPair = new ECPair(BigInteger.ONE, null, {
compressed: false
})
assert.equal(keyPair.compressed, false)
})
it('supports the network option', function () {
var keyPair = new ECPair(BigInteger.ONE, null, {
compressed: false,
network: networks.testnet
})
assert.equal(keyPair.network, networks.testnet)
})
it('throws if compressed option is not a bool', function () {
assert.throws(function () {
new ECPair(null, null, {
compressed: 2
}, /Expected Boolean, got 2/)
})
})
it('throws if public and private key given', function () {
var qBuffer = new Buffer('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 'hex')
var Q = ecurve.Point.decodeFrom(ECPair.curve, qBuffer)
assert.throws(function () {
new ECPair(BigInteger.ONE, Q)
}, /Unexpected publicKey parameter/)
})
it('throws if network is missing pubKeyHash constants', function () {
assert.throws(function () {
new ECPair(null, null, {
network: {}
}, /Unknown pubKeyHash constants for network/)
})
})
fixtures.valid.forEach(function (f) {
it('calculates the public point for ' + f.WIF, function () {
var d = new BigInteger(f.d)
var keyPair = new ECPair(d, null, {
compressed: f.compressed
})
assert.equal(keyPair.getPublicKeyBuffer().toString('hex'), f.Q)
})
})
fixtures.invalid.constructor.forEach(function (f) {
it('throws on ' + f.d, function () {
var d = new BigInteger(f.d)
assert.throws(function () {
new ECPair(d)
}, new RegExp(f.exception))
})
})
})
describe('getPublicKeyBuffer', function () {
var keyPair
beforeEach(function () {
keyPair = new ECPair(BigInteger.ONE)
})
it('wraps Q.getEncoded', sinon.test(function () {
this.mock(keyPair.Q).expects('getEncoded')
.once().calledWith(keyPair.compressed)
keyPair.getPublicKeyBuffer()
}))
})
describe('fromWIF', function () {
fixtures.valid.forEach(function (f) {
it('imports ' + f.WIF + ' correctly', function () {
var keyPair = ECPair.fromWIF(f.WIF)
assert.equal(keyPair.d.toString(), f.d)
assert.equal(keyPair.compressed, f.compressed)
assert.equal(keyPair.network, networks[f.network])
})
})
fixtures.invalid.fromWIF.forEach(function (f) {
it('throws on ' + f.string, function () {
assert.throws(function () {
ECPair.fromWIF(f.string)
}, new RegExp(f.exception))
})
})
})
describe('toWIF', function () {
fixtures.valid.forEach(function (f) {
it('exports ' + f.WIF + ' correctly', function () {
var keyPair = ECPair.fromWIF(f.WIF)
var result = keyPair.toWIF()
assert.equal(result, f.WIF)
})
})
})
describe('makeRandom', function () {
var d = new Buffer('0404040404040404040404040404040404040404040404040404040404040404', 'hex')
var exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv'
describe('uses randombytes RNG', function () {
it('generates a ECPair', function () {
var stub = { randombytes: function () { return d } }
var ProxiedECPair = proxyquire('../src/ecpair', stub)
var keyPair = ProxiedECPair.makeRandom()
assert.equal(keyPair.toWIF(), exWIF)
})
it('passes the options param', sinon.test(function () {
var options = {
compressed: true
}
// FIXME: waiting on https://github.com/cjohansen/Sinon.JS/issues/613
// this.mock(ECPair).expects('constructor')
// .once().calledWith(options)
ECPair.makeRandom(options)
}))
})
it('allows a custom RNG to be used', function () {
var keyPair = ECPair.makeRandom({
rng: function (size) { return d.slice(0, size) }
})
assert.equal(keyPair.toWIF(), exWIF)
})
})
describe('getAddress', function () {
fixtures.valid.forEach(function (f) {
it('returns ' + f.address + ' for ' + f.WIF, function () {
var keyPair = ECPair.fromWIF(f.WIF)
assert.equal(keyPair.getAddress().toString(), f.address)
})
})
})
describe('ecdsa wrappers', function () {
var keyPair, hash
beforeEach(function () {
keyPair = ECPair.makeRandom()
hash = new Buffer(32)
})
it('uses the secp256k1 curve by default', function () {
var secp256k1 = ecurve.getCurveByName('secp256k1')
for (var property in secp256k1) {
// FIXME: circular structures in ecurve
if (property === 'G') continue
if (property === 'infinity') continue
var actual = ECPair.curve[property]
var expected = secp256k1[property]
assert.deepEqual(actual, expected)
}
})
describe('signing', function () {
it('wraps ecdsa.sign', sinon.test(function () {
this.mock(ecdsa).expects('sign')
.once().calledWith(ECPair.curve, hash, keyPair.d)
keyPair.sign(hash)
}))
it('throws if no private key is found', function () {
keyPair.d = null
assert.throws(function () {
keyPair.sign(hash)
}, /Missing private key/)
})
})
describe('verify', function () {
var signature
beforeEach(function () {
signature = keyPair.sign(hash)
})
it('wraps ecdsa.verify', sinon.test(function () {
this.mock(ecdsa).expects('verify')
.once().calledWith(ECPair.curve, hash, signature, keyPair.Q)
keyPair.verify(hash, signature)
}))
})
})
})

View file

@ -1,120 +0,0 @@
/* global describe, it, beforeEach */
var assert = require('assert')
var crypto = require('../src/crypto')
var networks = require('../src/networks')
var BigInteger = require('bigi')
var ECPubKey = require('../src/ecpubkey')
var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')
var fixtures = require('./fixtures/ecpubkey.json')
describe('ECPubKey', function () {
var Q
beforeEach(function () {
Q = ecurve.Point.fromAffine(
curve,
new BigInteger(fixtures.Q.x),
new BigInteger(fixtures.Q.y)
)
})
describe('constructor', function () {
it('defaults to compressed', function () {
var pubKey = new ECPubKey(Q)
assert.equal(pubKey.compressed, true)
})
it('supports the uncompressed flag', function () {
var pubKey = new ECPubKey(Q, false)
assert.equal(pubKey.compressed, false)
})
})
it('uses the secp256k1 curve by default', function () {
var secp256k1 = ecurve.getCurveByName('secp256k1')
for (var property in secp256k1) {
// FIXME: circular structures in ecurve
if (property === 'G') continue
if (property === 'infinity') continue
var actual = ECPubKey.curve[property]
var expected = secp256k1[property]
assert.deepEqual(actual, expected)
}
})
describe('fromHex/toHex', function () {
it('supports compressed points', function () {
var pubKey = ECPubKey.fromHex(fixtures.compressed.hex)
assert(pubKey.Q.equals(Q))
assert.equal(pubKey.toHex(), fixtures.compressed.hex)
assert.equal(pubKey.compressed, true)
})
it('supports uncompressed points', function () {
var pubKey = ECPubKey.fromHex(fixtures.uncompressed.hex)
assert(pubKey.Q.equals(Q))
assert.equal(pubKey.toHex(), fixtures.uncompressed.hex)
assert.equal(pubKey.compressed, false)
})
})
describe('getAddress', function () {
it('calculates the expected hash (compressed)', function () {
var pubKey = new ECPubKey(Q, true)
var address = pubKey.getAddress()
assert.equal(address.hash.toString('hex'), fixtures.compressed.hash160)
})
it('calculates the expected hash (uncompressed)', function () {
var pubKey = new ECPubKey(Q, false)
var address = pubKey.getAddress()
assert.equal(address.hash.toString('hex'), fixtures.uncompressed.hash160)
})
it('supports alternative networks', function () {
var pubKey = new ECPubKey(Q)
var address = pubKey.getAddress(networks.testnet)
assert.equal(address.version, networks.testnet.pubKeyHash)
assert.equal(address.hash.toString('hex'), fixtures.compressed.hash160)
})
})
describe('verify', function () {
var pubKey, signature
beforeEach(function () {
pubKey = new ECPubKey(Q)
signature = {
r: new BigInteger(fixtures.signature.r),
s: new BigInteger(fixtures.signature.s)
}
})
it('verifies a valid signature', function () {
var hash = crypto.sha256(fixtures.message)
assert(pubKey.verify(hash, signature))
})
it("doesn't verify the wrong signature", function () {
var hash = crypto.sha256('mushrooms')
assert(!pubKey.verify(hash, signature))
})
})
})

View file

@ -1,102 +0,0 @@
{
"valid": [
{
"d": "1",
"Q": "(55066263022277343669578718895168534326250603453777594175500187360389116729240,32670510020758816978083085130507043184471273380659243275938904335757337482424)",
"WIFs": [
{
"network": "bitcoin",
"string": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"compressed": true
},
{
"network": "bitcoin",
"string": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf",
"compressed": false
}
]
},
{
"d": "19898843618908353587043383062236220484949425084007183071220218307100305431102",
"Q": "(83225686012142088543596389522774768397204444195709443235253141114409346958144,23739058578904784236915560265041168694780215705543362357495033621678991351768)",
"WIFs": [
{
"network": "bitcoin",
"string": "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9o",
"compressed": true
}
]
},
{
"d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
"Q": "(30095590000961171681152428142595206241714764354580127609094760797518133922356,93521207164355458151597931319591130635754976513751247168472016818884561919702)",
"WIFs": [
{
"network": "bitcoin",
"string": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx",
"compressed": true
},
{
"network": "bitcoin",
"string": "5JdxzLtFPHNe7CAL8EBC6krdFv9pwPoRo4e3syMZEQT9srmK8hh",
"compressed": false
},
{
"network": "testnet",
"string": "cRD9b1m3vQxmwmjSoJy7Mj56f4uNFXjcWMCzpQCEmHASS4edEwXv",
"compressed": true
},
{
"network": "testnet",
"string": "92Qba5hnyWSn5Ffcka56yMQauaWY6ZLd91Vzxbi4a9CCetaHtYj",
"compressed": false
}
]
},
{
"d": "115792089237316195423570985008687907852837564279074904382605163141518161494336",
"Q": "(55066263022277343669578718895168534326250603453777594175500187360389116729240,83121579216557378445487899878180864668798711284981320763518679672151497189239)",
"WIFs": [
{
"network": "bitcoin",
"string": "L5oLkpV3aqBjhki6LmvChTCV6odsp4SXM6FfU2Gppt5kFLaHLuZ9",
"compressed": true
}
]
}
],
"invalid": {
"constructor": [
{
"exception": "Private key must be greater than 0",
"d": "-1"
},
{
"exception": "Private key must be greater than 0",
"d": "0"
},
{
"exception": "Private key must be less than the curve order",
"d": "115792089237316195423570985008687907852837564279074904382605163141518161494337"
},
{
"exception": "Private key must be less than the curve order",
"d": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
}
],
"WIF": [
{
"exception": "Invalid compression flag",
"string": "ju9rooVsmagsb4qmNyTysUSFB1GB6MdpD7eoGjUTPmZRAApJxRz"
},
{
"exception": "Invalid WIF payload length",
"string": "7ZEtRQLhCsDQrd6ZKfmcESdXgas8ggZPN24ByEi5ey6VJW"
},
{
"exception": "Invalid WIF payload length",
"string": "5qibUKwsnMo1qDiNp3prGaQkD2JfVJa8F8Na87H2CkMHvuVg6uKhw67Rh"
}
]
}
}

102
test/fixtures/ecpair.json vendored Normal file
View file

@ -0,0 +1,102 @@
{
"valid": [
{
"d": "1",
"Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"compressed": true,
"network": "bitcoin",
"address": "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH",
"WIF": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
},
{
"d": "1",
"Q": "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
"compressed": false,
"network": "bitcoin",
"address": "1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm",
"WIF": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf"
},
{
"d": "19898843618908353587043383062236220484949425084007183071220218307100305431102",
"Q": "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
"compressed": true,
"network": "bitcoin",
"address": "1MasfEKgSiaSeri2C6kgznaqBNtyrZPhNq",
"WIF": "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9o"
},
{
"d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
"Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34",
"compressed": true,
"network": "bitcoin",
"address": "1LwwMWdSEMHJ2dMhSvAHZ3g95tG2UBv9jg",
"WIF": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx"
},
{
"d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
"Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6",
"compressed": false,
"network": "bitcoin",
"address": "1zXcfvKCLgsFdJDYPuqpu1sF3q92tnnUM",
"WIF": "5JdxzLtFPHNe7CAL8EBC6krdFv9pwPoRo4e3syMZEQT9srmK8hh"
},
{
"d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
"Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34",
"compressed": true,
"network": "testnet",
"address": "n1TteZiR3NiYojqKAV8fNxtTwsrjM7kVdj",
"WIF": "cRD9b1m3vQxmwmjSoJy7Mj56f4uNFXjcWMCzpQCEmHASS4edEwXv"
},
{
"d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
"Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6",
"compressed": false,
"network": "testnet",
"address": "mgWUuj1J1N882jmqFxtDepEC73Rr22E9GU",
"WIF": "92Qba5hnyWSn5Ffcka56yMQauaWY6ZLd91Vzxbi4a9CCetaHtYj"
},
{
"d": "115792089237316195423570985008687907852837564279074904382605163141518161494336",
"Q": "0379be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"compressed": true,
"network": "bitcoin",
"address": "1GrLCmVQXoyJXaPJQdqssNqwxvha1eUo2E",
"WIF": "L5oLkpV3aqBjhki6LmvChTCV6odsp4SXM6FfU2Gppt5kFLaHLuZ9"
}
],
"invalid": {
"constructor": [
{
"exception": "Private key must be greater than 0",
"d": "-1"
},
{
"exception": "Private key must be greater than 0",
"d": "0"
},
{
"exception": "Private key must be less than the curve order",
"d": "115792089237316195423570985008687907852837564279074904382605163141518161494337"
},
{
"exception": "Private key must be less than the curve order",
"d": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
}
],
"fromWIF": [
{
"exception": "Invalid compression flag",
"string": "ju9rooVsmagsb4qmNyTysUSFB1GB6MdpD7eoGjUTPmZRAApJxRz"
},
{
"exception": "Invalid WIF payload length",
"string": "7ZEtRQLhCsDQrd6ZKfmcESdXgas8ggZPN24ByEi5ey6VJW"
},
{
"exception": "Invalid WIF payload length",
"string": "5qibUKwsnMo1qDiNp3prGaQkD2JfVJa8F8Na87H2CkMHvuVg6uKhw67Rh"
}
]
}
}

View file

@ -1,19 +0,0 @@
{
"Q": {
"x": "55066263022277343669578718895168534326250603453777594175500187360389116729240",
"y": "32670510020758816978083085130507043184471273380659243275938904335757337482424"
},
"compressed": {
"hex": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"hash160": "751e76e8199196d454941c45d1b3a323f1433bd6"
},
"uncompressed": {
"hex": "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
"hash160": "91b24bf9f5288532960ac687abb035127b1d28a5"
},
"message": "vires in numeris",
"signature": {
"r": "68972263025625296948424563184904289678530916807200550828762374724416876919710",
"s": "43478152510424186005054433052302509227777805602212468112169549534899266476898"
}
}

View file

@ -10,7 +10,7 @@
"vout": 0,
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
}
]
}
@ -32,7 +32,7 @@
"prevTxScript": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 OP_CHECKSIG",
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
}
]
}
@ -53,7 +53,7 @@
"vout": 0,
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"redeemScript": "OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG"
}
]
@ -75,11 +75,11 @@
"vout": 0,
"signs": [
{
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG"
},
{
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
}
]
}
@ -101,10 +101,10 @@
"prevTxScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
"signs": [
{
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx"
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx"
},
{
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
}
]
}
@ -126,10 +126,10 @@
"prevTxScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
"signs": [
{
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
},
{
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx"
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx"
}
]
}
@ -150,11 +150,11 @@
"vout": 0,
"signs": [
{
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG"
},
{
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe"
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe"
}
]
}
@ -176,7 +176,7 @@
"prevTxScript": "OP_HASH160 e89677d91455e541630d62c63718bef738b478b1 OP_EQUAL",
"signs": [
{
"privKey": "KxLDMPtVM7sLSu2v5n1LybDibw6P9FFbL4pUwJ51UDm7rp5AmXWW",
"keyPair": "KxLDMPtVM7sLSu2v5n1LybDibw6P9FFbL4pUwJ51UDm7rp5AmXWW",
"redeemScript": "033e29aea1168a835d5e386c292082db7b7807172a10ec634ad34226f36d79e70f OP_CHECKSIG"
}
]
@ -198,7 +198,7 @@
"vout": 1,
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
}
]
}
@ -222,7 +222,7 @@
"sequence": 2147001,
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
}
]
}
@ -246,12 +246,12 @@
"signs": [
{
"pubKeyIndex": 0,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
},
{
"pubKeyIndex": 1,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
}
]
@ -275,12 +275,12 @@
"signs": [
{
"pubKeyIndex": 1,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"scriptSig": "OP_0 OP_0 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
},
{
"pubKeyIndex": 0,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
}
]
@ -304,12 +304,12 @@
"signs": [
{
"pubKeyIndex": 0,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
},
{
"pubKeyIndex": 1,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
}
]
@ -333,12 +333,12 @@
"signs": [
{
"pubKeyIndex": 0,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
},
{
"pubKeyIndex": 1,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 3045022100ae06d8269b79b5cfa0297d1d88261b0061e52fc2814948c3aa05fa78ee76894302206e0c79a5c90569d8c72a542ef9a06471cbbcd2c651b312339983dfba4f8ff46301 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
}
]
@ -362,12 +362,12 @@
"signs": [
{
"pubKeyIndex": 0,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
},
{
"pubKeyIndex": 2,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
"scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
}
]
@ -391,12 +391,12 @@
"signs": [
{
"pubKeyIndex": 2,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
"scriptSig": "OP_0 OP_0 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
},
{
"pubKeyIndex": 0,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
}
]
@ -420,12 +420,12 @@
"signs": [
{
"pubKeyIndex": 0,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
},
{
"pubKeyIndex": 2,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
"scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
}
]
@ -449,13 +449,13 @@
"signs": [
{
"pubKeyIndex": 2,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
"scriptSig": "OP_0 OP_0 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
},
{
"filterOP_0": true,
"pubKeyIndex": 0,
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae",
"scriptSigFiltered": "OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
}
@ -522,7 +522,7 @@
"vout": 0,
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
}
]
},
@ -556,10 +556,10 @@
"vout": 1,
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
},
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"throws": true
}
]
@ -580,7 +580,7 @@
"vout": 1,
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"redeemScript": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474",
"throws": true
}
@ -603,7 +603,7 @@
"prevTxScript": "OP_HASH160 7f67f0521934a57d3039f77f9f32cf313f3ac74b OP_EQUAL",
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"throws": true
}
]
@ -625,11 +625,11 @@
"signs": [
{
"redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx"
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx"
},
{
"redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"throws": true
}
]
@ -651,11 +651,11 @@
"signs": [
{
"redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
"hashType": 4
},
{
"privKey": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
"hashType": 2,
"throws": true
}
@ -677,7 +677,7 @@
"vout": 1,
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"redeemScript": "OP_HASH160 7f67f0521934a57d3039f77f9f32cf313f3ac74b OP_EQUAL",
"throws": true
}
@ -700,7 +700,7 @@
"prevTxScript": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_1 OP_CHECKMULTISIG",
"throws": true
}
@ -723,11 +723,11 @@
"vout": 1,
"signs": [
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"keyPair": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf",
"redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_1 OP_CHECKMULTISIG"
},
{
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
"keyPair": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf",
"throws": true
}
]
@ -741,15 +741,15 @@
]
},
{
"description": "Wrong private key for multisig redeemScript",
"exception": "privateKey cannot sign for this input",
"description": "Wrong key pair for multisig redeemScript",
"exception": "key pair cannot sign for this input",
"inputs": [
{
"txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"vout": 1,
"signs": [
{
"privKey": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx",
"keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx",
"redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_1 OP_CHECKMULTISIG",
"throws": true
}
@ -772,7 +772,7 @@
"prevTxScript": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474",
"signs": [
{
"privKey": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx",
"keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx",
"throws": true
}
]

View file

@ -1,98 +1,54 @@
/* global describe, it */
/* global describe, it, beforeEach */
/* eslint-disable no-new */
var assert = require('assert')
var networks = require('../src/networks')
var sinon = require('sinon')
var BigInteger = require('bigi')
var ECKey = require('../src/eckey')
var ECPubKey = require('../src/ecpubkey')
var ECPair = require('../src/ecpair')
var HDNode = require('../src/hdnode')
var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')
var fixtures = require('./fixtures/hdnode.json')
describe('HDNode', function () {
describe('Constructor', function () {
var d = BigInteger.ONE
var Q = curve.G.multiply(d)
var chainCode = new Buffer(32)
chainCode.fill(1)
var keyPair, chainCode
it('calculates the publicKey from a BigInteger', function () {
var hd = new HDNode(d, chainCode)
beforeEach(function () {
var d = BigInteger.ONE
assert(hd.pubKey.Q.equals(Q))
})
it('allows initialization directly from an ECKey', function () {
var ek = new ECKey(d)
var hd = new HDNode(ek, chainCode)
assert.equal(hd.privKey, ek)
})
it('allows initialization directly from an ECPubKey', function () {
var ek = new ECPubKey(Q)
var hd = new HDNode(ek, chainCode)
assert.equal(hd.pubKey, ek)
})
it('throws if ECKey is not compressed', function () {
var ek = new ECKey(d, false)
assert.throws(function () {
new HDNode(ek, chainCode)
}, /ECKey must be compressed/)
})
it('throws if ECPubKey is not compressed', function () {
var ek = new ECPubKey(Q, false)
assert.throws(function () {
new HDNode(ek, chainCode)
}, /ECPubKey must be compressed/)
})
it('only uses compressed points', function () {
var hd = new HDNode(Q, chainCode)
var hdP = new HDNode(d, chainCode)
assert.strictEqual(hd.pubKey.compressed, true)
assert.strictEqual(hdP.pubKey.compressed, true)
keyPair = new ECPair(d, null)
chainCode = new Buffer(32)
chainCode.fill(1)
})
it('has a default depth/index of 0', function () {
var hd = new HDNode(Q, chainCode)
var hd = new HDNode(keyPair, chainCode)
assert.strictEqual(hd.depth, 0)
assert.strictEqual(hd.index, 0)
})
it('defaults to the bitcoin network', function () {
var hd = new HDNode(Q, chainCode)
it('throws on uncompressed keyPair', function () {
keyPair.compressed = false
assert.equal(hd.network, networks.bitcoin)
})
it('supports alternative networks', function () {
var hd = new HDNode(Q, chainCode, networks.testnet)
assert.equal(hd.network, networks.testnet)
assert.throws(function () {
new HDNode(keyPair, chainCode)
}, /BIP32 only allows compressed keyPairs/)
})
it('throws when an invalid length chain code is given', function () {
assert.throws(function () {
new HDNode(d, chainCode.slice(0, 20), networks.testnet)
new HDNode(keyPair, chainCode.slice(0, 20))
}, /Expected chainCode length of 32, got 20/)
})
it('throws when an unknown network is given', function () {
keyPair.network = {}
assert.throws(function () {
new HDNode(d, chainCode, {})
new HDNode(keyPair, chainCode)
}, /Unknown BIP32 constants for network/)
})
})
@ -103,7 +59,7 @@ describe('HDNode', function () {
var network = networks[f.network]
var hd = HDNode.fromSeedHex(f.master.seed, network)
assert.equal(hd.privKey.toWIF(network), f.master.wif)
assert.equal(hd.keyPair.toWIF(), f.master.wif)
assert.equal(hd.chainCode.toString('hex'), f.master.chainCode)
})
})
@ -148,7 +104,7 @@ describe('HDNode', function () {
var hd = HDNode.fromBase58(f.master.base58)
assert.equal(hd.toBase58(), f.master.base58)
assert.equal(hd.network, network)
assert.equal(hd.keyPair.network, network)
})
})
@ -158,7 +114,7 @@ describe('HDNode', function () {
var hd = HDNode.fromBase58(f.master.base58Priv, network)
assert.equal(hd.toBase58(), f.master.base58Priv)
assert.equal(hd.network, network)
assert.equal(hd.keyPair.network, network)
})
})
@ -194,13 +150,20 @@ describe('HDNode', function () {
})
describe('getAddress', function () {
fixtures.valid.forEach(function (f) {
it('returns ' + f.master.address + ' for ' + f.master.fingerprint, function () {
var hd = HDNode.fromBase58(f.master.base58)
var hd
assert.equal(hd.getAddress().toString(), f.master.address)
})
beforeEach(function () {
var f = fixtures.valid[0]
hd = HDNode.fromBase58(f.master.base58)
})
it('wraps ECPair.getAddress', sinon.test(function () {
this.mock(hd.keyPair).expects('getAddress')
.once().returns('foobar')
assert.equal(hd.getAddress(), 'foobar')
}))
})
describe('neutered', function () {
@ -210,8 +173,8 @@ describe('HDNode', function () {
var hd = HDNode.fromBase58(f.master.base58)
var hdn = hd.neutered()
assert.equal(hdn.privKey, undefined)
assert.equal(hdn.pubKey.toHex(), hd.pubKey.toHex())
assert.equal(hdn.keyPair.d, null)
assert.equal(hdn.keyPair.Q, hd.keyPair.Q)
assert.equal(hdn.chainCode, hd.chainCode)
assert.equal(hdn.depth, hd.depth)
assert.equal(hdn.index, hd.index)
@ -219,9 +182,9 @@ describe('HDNode', function () {
})
describe('derive', function () {
function verifyVector (hd, network, v, depth) {
assert.equal(hd.privKey.toWIF(network), v.wif)
assert.equal(hd.pubKey.toHex(), v.pubKey)
function verifyVector (hd, v, depth) {
assert.equal(hd.keyPair.toWIF(), v.wif)
assert.equal(hd.keyPair.getPublicKeyBuffer().toString('hex'), v.pubKey)
assert.equal(hd.chainCode.toString('hex'), v.chainCode)
assert.equal(hd.depth, depth || 0)
@ -245,7 +208,7 @@ describe('HDNode', function () {
hd = hd.derive(c.m)
}
verifyVector(hd, network, c, i + 1)
verifyVector(hd, c, i + 1)
})
})
})

View file

@ -6,10 +6,10 @@ var blockchain = new (require('cb-helloblock'))('testnet')
describe('bitcoinjs-lib (advanced)', function () {
it('can sign a Bitcoin message', function () {
var key = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
var keyPair = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
var message = 'This is an example of a signed message.'
var signature = bitcoin.message.sign(key, message)
var signature = bitcoin.message.sign(keyPair, message)
assert.equal(signature.toString('base64'), 'G9L5yLFjti0QTHhPyFrZCT1V/MMnBtXKmoiKDZ78NDBjERki6ZTQZdSMCtkgoNmp17By9ItJr8o7ChX0XxY91nk=')
})
@ -24,8 +24,10 @@ describe('bitcoinjs-lib (advanced)', function () {
it('can create an OP_RETURN transaction', function (done) {
this.timeout(20000)
var key = bitcoin.ECKey.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy')
var address = key.pub.getAddress(bitcoin.networks.testnet).toString()
var keyPair = bitcoin.ECPair.makeRandom({
network: bitcoin.networks.testnet
})
var address = keyPair.getAddress().toString()
blockchain.addresses.__faucetWithdraw(address, 2e4, function (err) {
if (err) return done(err)
@ -41,7 +43,7 @@ describe('bitcoinjs-lib (advanced)', function () {
tx.addInput(unspent.txId, unspent.vout)
tx.addOutput(dataScript, 1000)
tx.sign(0, key)
tx.sign(0, keyPair)
var txBuilt = tx.build()

View file

@ -9,9 +9,9 @@ describe('bitcoinjs-lib (basic)', function () {
// for testing only
function rng () { return new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') }
// generate random key (custom rng for testing only)
var key = bitcoin.ECKey.makeRandom(undefined, rng)
var address = key.pub.getAddress().toString()
// generate random keyPair
var keyPair = bitcoin.ECPair.makeRandom({ rng: rng })
var address = keyPair.getAddress().toString()
assert.equal(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64')
})
@ -20,25 +20,26 @@ describe('bitcoinjs-lib (basic)', function () {
var hash = bitcoin.crypto.sha256('correct horse battery staple')
var d = bigi.fromBuffer(hash)
var key = new bitcoin.ECKey(d)
var keyPair = new bitcoin.ECPair(d)
var address = keyPair.getAddress().toString()
assert.equal(key.pub.getAddress().toString(), '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8')
assert.equal(address, '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8')
})
it('can import an address via WIF', function () {
var key = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
var address = key.pub.getAddress().toString()
var keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
var address = keyPair.getAddress().toString()
assert.equal(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31')
})
it('can create a Transaction', function () {
var key = bitcoin.ECKey.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy')
var keyPair = bitcoin.ECPair.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy')
var tx = new bitcoin.TransactionBuilder()
tx.addInput('aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31', 0)
tx.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000)
tx.sign(0, key)
tx.sign(0, keyPair)
assert.equal(tx.build().toHex(), '0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa000000006b483045022100aefbcf847900b01dd3e3debe054d3b6d03d715d50aea8525f5ea3396f168a1fb022013d181d05b15b90111808b22ef4f9ebe701caf2ab48db269691fdf4e9048f4f60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01983a0000000000001976a914ad618cf4333b3b248f9744e8e81db2964d0ae39788ac00000000')
})

View file

@ -9,17 +9,17 @@ var crypto = require('crypto')
describe('bitcoinjs-lib (crypto)', function () {
it('can generate a single-key stealth address', function () {
var receiver = bitcoin.ECKey.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
var receiver = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')
// XXX: ephemeral, must be random (and secret to sender) to preserve privacy
var sender = bitcoin.ECKey.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
var sender = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
var G = bitcoin.ECKey.curve.G
var G = bitcoin.ECPair.curve.G
var d = receiver.d // secret (receiver only)
var Q = receiver.pub.Q // shared
var Q = receiver.Q // shared
var e = sender.d // secret (sender only)
var P = sender.pub.Q // shared
var P = sender.Q // shared
// derived shared secret
var eQ = Q.multiply(e) // sender
@ -35,7 +35,7 @@ describe('bitcoinjs-lib (crypto)', function () {
assert.deepEqual(QprimeR.getEncoded(), QprimeS.getEncoded())
// derived shared-secret address
var address = new bitcoin.ECPubKey(QprimeS).getAddress().toString()
var address = new bitcoin.ECPair(null, QprimeS).getAddress().toString()
assert.equal(address, '1EwCNJNZM5q58YPPTnjR1H5BvYRNeyZi47')
})
@ -45,13 +45,14 @@ describe('bitcoinjs-lib (crypto)', function () {
it("can recover a parent private key from the parent's public key and a derived non-hardened child private key", function () {
function recoverParent (master, child) {
assert(!master.privKey, 'You already have the parent private key')
assert(child.privKey, 'Missing child private key')
assert(!master.keyPair.d, 'You already have the parent private key')
assert(child.keyPair.d, 'Missing child private key')
var curve = bitcoin.ECKey.curve
var QP = master.pubKey.toBuffer()
var QP64 = QP.toString('base64')
var d1 = child.privKey.d
var curve = bitcoin.ECPair.curve
var QP = master.keyPair.Q
var serQP = master.keyPair.getPublicKeyBuffer()
var d1 = child.keyPair.d
var d2
var indexBuffer = new Buffer(4)
@ -60,7 +61,7 @@ describe('bitcoinjs-lib (crypto)', function () {
indexBuffer.writeUInt32BE(i, 0)
// calculate I
var data = Buffer.concat([QP, indexBuffer])
var data = Buffer.concat([serQP, indexBuffer])
var I = crypto.createHmac('sha512', master.chainCode).update(data).digest()
var IL = I.slice(0, 32)
var pIL = bigi.fromBuffer(IL)
@ -68,11 +69,11 @@ describe('bitcoinjs-lib (crypto)', function () {
// See hdnode.js:273 to understand
d2 = d1.subtract(pIL).mod(curve.n)
var Qp = new bitcoin.ECKey(d2, true).pub.toBuffer()
if (Qp.toString('base64') === QP64) break
var Qp = new bitcoin.ECPair(d2).Q
if (Qp.equals(QP)) break
}
var node = new bitcoin.HDNode(d2, master.chainCode, master.network)
var node = new bitcoin.HDNode(new bitcoin.ECPair(d2), master.chainCode, master.network)
node.depth = master.depth
node.index = master.index
node.masterFingerprint = master.masterFingerprint
@ -133,7 +134,7 @@ describe('bitcoinjs-lib (crypto)', function () {
var prevOutScript = prevOut.outs[prevVout].script
var scriptSignature = bitcoin.ECSignature.parseScriptSignature(script.chunks[0])
var publicKey = bitcoin.ECPubKey.fromBuffer(script.chunks[1])
var publicKey = bitcoin.ECPair.fromPublicKeyBuffer(script.chunks[1])
var m = transaction.hashForSignature(input.vout, prevOutScript, scriptSignature.hashType)
assert(publicKey.verify(m, scriptSignature.signature), 'Invalid m')
@ -151,7 +152,8 @@ describe('bitcoinjs-lib (crypto)', function () {
async.parallel(tasks, function (err) {
if (err)
throw err
var n = bitcoin.ECKey.curve.n
var n = bitcoin.ECPair.curve.n
for (var i = 0; i < inputs.length; ++i) {
for (var j = i + 1; j < inputs.length; ++j) {

View file

@ -10,11 +10,13 @@ describe('bitcoinjs-lib (multisig)', function () {
'026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
'02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
'03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9'
].map(bitcoin.ECPubKey.fromHex)
].map(function (hex) {
return new Buffer(hex, 'hex')
})
var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 3
var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
var address = bitcoin.Address.fromOutputScript(scriptPubKey).toString()
var address = bitcoin.Address.fromOutputScript(scriptPubKey)
assert.equal(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7')
})
@ -22,15 +24,13 @@ describe('bitcoinjs-lib (multisig)', function () {
it('can spend from a 2-of-4 multsig P2SH address', function (done) {
this.timeout(20000)
var privKeys = [
var keyPairs = [
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx',
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT',
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe',
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx9rcrL7'
].map(bitcoin.ECKey.fromWIF)
var pubKeys = privKeys.map(function (x) {
return x.pub
})
].map(bitcoin.ECPair.fromWIF)
var pubKeys = keyPairs.map(function (x) { return x.getPublicKeyBuffer() })
var redeemScript = bitcoin.scripts.multisigOutput(2, pubKeys) // 2 of 4
var scriptPubKey = bitcoin.scripts.scriptHashOutput(redeemScript.getHash())
@ -44,7 +44,7 @@ describe('bitcoinjs-lib (multisig)', function () {
blockchain.addresses.unspents(address, function (err, unspents) {
if (err) return done(err)
// filter small unspents
// filter small unspents
unspents = unspents.filter(function (unspent) {
return unspent.value > 1e4
})
@ -53,15 +53,17 @@ describe('bitcoinjs-lib (multisig)', function () {
var unspent = unspents.pop()
// make a random destination address
var targetAddress = bitcoin.ECKey.makeRandom().pub.getAddress(bitcoin.networks.testnet).toString()
var targetAddress = bitcoin.ECPair.makeRandom({
network: bitcoin.networks.testnet
}).getAddress().toString()
var txb = new bitcoin.TransactionBuilder()
txb.addInput(unspent.txId, unspent.vout)
txb.addOutput(targetAddress, 1e4)
// sign with 1st and 3rd key
txb.sign(0, privKeys[0], redeemScript)
txb.sign(0, privKeys[2], redeemScript)
txb.sign(0, keyPairs[0], redeemScript)
txb.sign(0, keyPairs[2], redeemScript)
// broadcast our transaction
blockchain.transactions.propagate(txb.build().toHex(), function (err) {

View file

@ -6,7 +6,7 @@ var networks = require('../src/networks')
var Address = require('../src/address')
var BigInteger = require('bigi')
var ECKey = require('../src/eckey')
var ECPair = require('../src/ecpair')
var fixtures = require('./fixtures/message.json')
@ -55,12 +55,14 @@ describe('message', function () {
it(f.description, function () {
var network = networks[f.network]
var privKey = new ECKey(new BigInteger(f.d), false)
var signature = message.sign(privKey, f.message, network)
var keyPair = new ECPair(new BigInteger(f.d), null, {
compressed: false
})
var signature = message.sign(keyPair, f.message, network)
assert.equal(signature.toString('base64'), f.signature)
if (f.compressed) {
var compressedPrivKey = new ECKey(new BigInteger(f.d))
var compressedPrivKey = new ECPair(new BigInteger(f.d))
var compressedSignature = message.sign(compressedPrivKey, f.message)
assert.equal(compressedSignature.toString('base64'), f.compressed.signature)

View file

@ -15,7 +15,7 @@ describe('networks', function () {
var extb58 = f.bip32[name]
it(extb58 + ' auto-detects ' + f.network, function () {
assert.equal(HDNode.fromBase58(extb58).network, network)
assert.equal(HDNode.fromBase58(extb58).keyPair.network, network)
})
})
})

View file

@ -4,7 +4,7 @@ var assert = require('assert')
var ops = require('../src/opcodes')
var scripts = require('../src/scripts')
var ECPubKey = require('../src/ecpubkey')
var ECPair = require('../src/ecpair')
var Script = require('../src/script')
var fixtures = require('./fixtures/scripts.json')
@ -150,8 +150,7 @@ describe('Scripts', function () {
if (f.type !== 'pubkey') return
it('returns ' + f.scriptPubKey, function () {
var pubKey = ECPubKey.fromHex(f.pubKey)
var pubKey = new Buffer(f.pubKey, 'hex')
var scriptPubKey = scripts.pubKeyOutput(pubKey)
assert.equal(scriptPubKey.toASM(), f.scriptPubKey)
})
@ -162,7 +161,7 @@ describe('Scripts', function () {
fixtures.valid.forEach(function (f) {
if (f.type !== 'pubkeyhash') return
var pubKey = ECPubKey.fromHex(f.pubKey)
var pubKey = new Buffer(f.pubKey, 'hex')
it('returns ' + f.scriptSig, function () {
var signature = new Buffer(f.signature, 'hex')
@ -177,8 +176,8 @@ describe('Scripts', function () {
fixtures.valid.forEach(function (f) {
if (f.type !== 'pubkeyhash') return
var pubKey = ECPubKey.fromHex(f.pubKey)
var address = pubKey.getAddress()
var pubKey = new Buffer(f.pubKey, 'hex')
var address = ECPair.fromPublicKeyBuffer(pubKey).getAddress()
it('returns ' + f.scriptPubKey, function () {
var scriptPubKey = scripts.pubKeyHashOutput(address.hash)
@ -220,7 +219,7 @@ describe('Scripts', function () {
fixtures.valid.forEach(function (f) {
if (f.type !== 'multisig') return
var pubKeys = f.pubKeys.map(ECPubKey.fromHex)
var pubKeys = f.pubKeys.map(function (p) { return new Buffer(p, 'hex') })
var scriptPubKey = scripts.multisigOutput(pubKeys.length, pubKeys)
it('returns ' + f.scriptPubKey, function () {
@ -229,7 +228,9 @@ describe('Scripts', function () {
})
fixtures.invalid.multisigOutput.forEach(function (f) {
var pubKeys = f.pubKeys.map(ECPubKey.fromHex)
var pubKeys = f.pubKeys.map(function (p) {
return new Buffer(p, 'hex')
})
it('throws on ' + f.exception, function () {
assert.throws(function () {

View file

@ -6,7 +6,7 @@ var scripts = require('../src/scripts')
var Address = require('../src/address')
var BigInteger = require('bigi')
var ECKey = require('../src/eckey')
var ECPair = require('../src/ecpair')
var Script = require('../src/script')
var Transaction = require('../src/transaction')
var TransactionBuilder = require('../src/transaction_builder')
@ -33,14 +33,14 @@ function construct (txb, f, sign) {
if (sign === undefined || sign) {
f.inputs.forEach(function (input, index) {
input.signs.forEach(function (sign) {
var privKey = ECKey.fromWIF(sign.privKey)
var keyPair = ECPair.fromWIF(sign.keyPair)
var redeemScript
if (sign.redeemScript) {
redeemScript = Script.fromASM(sign.redeemScript)
}
txb.sign(index, privKey, redeemScript, sign.hashType)
txb.sign(index, keyPair, redeemScript, sign.hashType)
})
})
}
@ -58,7 +58,7 @@ function construct (txb, f, sign) {
describe('TransactionBuilder', function () {
var privAddress, privScript
var prevTx, prevTxHash
var privKey
var keyPair
var txb
beforeEach(function () {
@ -69,8 +69,8 @@ describe('TransactionBuilder', function () {
prevTx.addOutput(Address.fromBase58Check('1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP').toOutputScript(), 1)
prevTxHash = prevTx.getHash()
privKey = new ECKey(BigInteger.ONE, false)
privAddress = privKey.pub.getAddress()
keyPair = new ECPair(BigInteger.ONE)
privAddress = keyPair.getAddress()
privScript = privAddress.toOutputScript()
})
@ -115,7 +115,7 @@ describe('TransactionBuilder', function () {
it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () {
txb.addInput(prevTxHash, 0)
txb.sign(0, privKey)
txb.sign(0, keyPair)
assert.throws(function () {
txb.addInput(prevTxHash, 0)
@ -154,7 +154,7 @@ describe('TransactionBuilder', function () {
it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () {
txb.addInput(prevTxHash, 0)
txb.addOutput(privScript, 2000)
txb.sign(0, privKey)
txb.sign(0, keyPair)
assert.throws(function () {
txb.addOutput(privScript, 9000)
@ -169,7 +169,7 @@ describe('TransactionBuilder', function () {
f.inputs.forEach(function (input, index) {
input.signs.forEach(function (sign) {
var privKey = ECKey.fromWIF(sign.privKey)
var keyPair = ECPair.fromWIF(sign.keyPair)
var redeemScript
if (sign.redeemScript) {
@ -177,10 +177,11 @@ describe('TransactionBuilder', function () {
}
if (!sign.throws) {
txb.sign(index, privKey, redeemScript, sign.hashType)
txb.sign(index, keyPair, redeemScript, sign.hashType)
} else {
assert.throws(function () {
txb.sign(index, privKey, redeemScript, sign.hashType)
txb.sign(index, keyPair, redeemScript, sign.hashType)
}, new RegExp(f.exception))
}
})
@ -256,8 +257,8 @@ describe('TransactionBuilder', function () {
txb = TransactionBuilder.fromTransaction(tx)
}
var privKey = ECKey.fromWIF(sign.privKey)
txb.sign(i, privKey, redeemScript, sign.hashType)
var keyPair = ECPair.fromWIF(sign.keyPair)
txb.sign(i, keyPair, redeemScript, sign.hashType)
// update the tx
tx = txb.buildIncomplete()