Browse Source

Merge pull request #1070 from bitcoinjs/tinyec

rm ecdsa, switch out ECPair secp256k1 impl.
addLowRGrinding
Daniel Cousens 7 years ago
committed by GitHub
parent
commit
d7eb6c8e77
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      package.json
  2. 163
      src/ecdsa.js
  3. 142
      src/ecpair.js
  4. 4
      src/transaction_builder.js
  5. 4
      src/types.js
  6. 2
      test/bitcoin.core.js
  7. 135
      test/ecdsa.js
  8. 176
      test/ecpair.js
  9. 41
      test/fixtures/ecpair.json
  10. 2
      test/integration/_regtest.js
  11. 10
      test/integration/addresses.js
  12. 4
      test/integration/cltv.js
  13. 2
      test/integration/crypto.js
  14. 4
      test/integration/csv.js
  15. 80
      test/integration/stealth.js
  16. 13
      test/integration/transactions.js
  17. 5
      test/transaction_builder.js
  18. 12
      test/types.js

2
package.json

@ -31,14 +31,12 @@
],
"dependencies": {
"bech32": "^1.1.2",
"bigi": "^1.4.0",
"bip32": "^0.1.0",
"bip66": "^1.1.0",
"bitcoin-ops": "^1.4.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",

163
src/ecdsa.js

@ -1,163 +0,0 @@
var Buffer = require('safe-buffer').Buffer
var createHmac = require('create-hmac')
var typeforce = require('typeforce')
var types = require('./types')
var BigInteger = require('bigi')
var ZERO = Buffer.alloc(1, 0)
var ONE = Buffer.alloc(1, 1)
var ecurve = require('ecurve')
var secp256k1 = ecurve.getCurveByName('secp256k1')
// https://tools.ietf.org/html/rfc6979#section-3.2
function deterministicGenerateK (hash, x, checkSig) {
typeforce(types.tuple(
types.Hash256bit,
types.Buffer256bit,
types.Function
), arguments)
// Step A, ignored as hash already provided
// Step B
// Step C
var k = Buffer.alloc(32, 0)
var v = Buffer.alloc(32, 1)
// Step D
k = createHmac('sha256', k)
.update(v)
.update(ZERO)
.update(x)
.update(hash)
.digest()
// Step E
v = createHmac('sha256', k).update(v).digest()
// Step F
k = createHmac('sha256', k)
.update(v)
.update(ONE)
.update(x)
.update(hash)
.digest()
// Step G
v = createHmac('sha256', k).update(v).digest()
// Step H1/H2a, ignored as tlen === qlen (256 bit)
// Step H2b
v = createHmac('sha256', k).update(v).digest()
var T = BigInteger.fromBuffer(v)
// Step H3, repeat until T is within the interval [1, n - 1] and is suitable for ECDSA
while (T.signum() <= 0 || T.compareTo(secp256k1.n) >= 0 || !checkSig(T)) {
k = createHmac('sha256', k)
.update(v)
.update(ZERO)
.digest()
v = createHmac('sha256', k).update(v).digest()
// Step H1/H2a, again, ignored as tlen === qlen (256 bit)
// Step H2b again
v = createHmac('sha256', k).update(v).digest()
T = BigInteger.fromBuffer(v)
}
return T
}
var N_OVER_TWO = secp256k1.n.shiftRight(1)
function sign (hash, d) {
typeforce(types.tuple(types.Hash256bit, types.BigInt), arguments)
var x = d.toBuffer(32)
var e = BigInteger.fromBuffer(hash)
var n = secp256k1.n
var G = secp256k1.G
var r, s
deterministicGenerateK(hash, x, function (k) {
var Q = G.multiply(k)
if (secp256k1.isInfinity(Q)) return false
r = Q.affineX.mod(n)
if (r.signum() === 0) return false
s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n)
if (s.signum() === 0) return false
return true
})
// enforce low S values, see bip62: 'low s values in signatures'
if (s.compareTo(N_OVER_TWO) > 0) {
s = n.subtract(s)
}
return {
r: r,
s: s
}
}
function verify (hash, signature, Q) {
typeforce(types.tuple(
types.Hash256bit,
types.ECSignature,
types.ECPoint
), arguments)
var n = secp256k1.n
var G = secp256k1.G
var r = signature.r
var s = signature.s
// 1.4.1 Enforce r and s are both integers in the interval [1, n − 1]
if (r.signum() <= 0 || r.compareTo(n) >= 0) return false
if (s.signum() <= 0 || s.compareTo(n) >= 0) return false
// 1.4.2 H = Hash(M), already done by the user
// 1.4.3 e = H
var e = BigInteger.fromBuffer(hash)
// Compute s^-1
var sInv = s.modInverse(n)
// 1.4.4 Compute u1 = es^−1 mod n
// u2 = rs^−1 mod n
var u1 = e.multiply(sInv).mod(n)
var u2 = r.multiply(sInv).mod(n)
// 1.4.5 Compute R = (xR, yR)
// R = u1G + u2Q
var R = G.multiplyTwo(u1, Q, u2)
// 1.4.5 (cont.) Enforce R is not at infinity
if (secp256k1.isInfinity(R)) return false
// 1.4.6 Convert the field element R.x to an integer
var xR = R.affineX
// 1.4.7 Set v = xR mod n
var v = xR.mod(n)
// 1.4.8 If v = r, output "valid", and if v != r, output "invalid"
return v.equals(r)
}
module.exports = {
deterministicGenerateK: deterministicGenerateK,
sign: sign,
verify: verify,
// TODO: remove
__curve: secp256k1
}

142
src/ecpair.js

@ -1,63 +1,70 @@
let ecdsa = require('./ecdsa')
let ecc = require('tiny-secp256k1')
let randomBytes = require('randombytes')
let typeforce = require('typeforce')
let types = require('./types')
let wif = require('wif')
let NETWORKS = require('./networks')
let BigInteger = require('bigi')
let ecurve = require('ecurve')
let secp256k1 = ecdsa.__curve
// TODO: why is the function name toJSON weird?
function isPoint (x) { return ecc.isPoint(x) }
let isOptions = typeforce.maybe(typeforce.compile({
compressed: types.maybe(types.Boolean),
network: types.maybe(types.Network)
}))
function ECPair (d, Q, options) {
if (options) {
typeforce({
compressed: types.maybe(types.Boolean),
network: types.maybe(types.Network)
}, options)
}
options = options || {}
if (d) {
if (d.signum() <= 0) throw new Error('Private key must be greater than 0')
if (d.compareTo(secp256k1.n) >= 0) throw new Error('Private key must be less than the curve order')
if (Q) throw new TypeError('Unexpected publicKey parameter')
this.compressed = options.compressed === undefined ? true : options.compressed
this.network = options.network || NETWORKS.bitcoin
this.d = d
} else {
typeforce(types.ECPoint, Q)
this.__d = d || null
this.__Q = null
if (Q) this.__Q = ecc.pointCompress(Q, this.compressed)
}
this.__Q = Q
}
Object.defineProperty(ECPair.prototype, 'privateKey', {
enumerable: false,
get: function () { return this.__d }
})
this.compressed = options.compressed === undefined ? true : options.compressed
this.network = options.network || NETWORKS.bitcoin
Object.defineProperty(ECPair.prototype, 'publicKey', { get: function () {
if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__d, this.compressed)
return this.__Q
}})
ECPair.prototype.toWIF = function () {
if (!this.__d) throw new Error('Missing private key')
return wif.encode(this.network.wif, this.__d, this.compressed)
}
Object.defineProperty(ECPair.prototype, 'Q', {
get: function () {
if (!this.__Q && this.d) {
this.__Q = secp256k1.G.multiply(this.d)
}
ECPair.prototype.sign = function (hash) {
if (!this.__d) throw new Error('Missing private key')
return ecc.sign(hash, this.__d)
}
return this.__Q
}
})
ECPair.prototype.verify = function (hash, signature) {
return ecc.verify(hash, this.publicKey, signature)
}
ECPair.fromPublicKeyBuffer = function (buffer, network) {
var Q = ecurve.Point.decodeFrom(secp256k1, buffer)
function fromPrivateKey (buffer, options) {
typeforce(types.Buffer256bit, buffer)
if (!ecc.isPrivate(buffer)) throw new TypeError('Private key not in range [1, n)')
typeforce(isOptions, options)
return new ECPair(null, Q, {
compressed: Q.compressed,
network: network
})
return new ECPair(buffer, null, options)
}
ECPair.fromWIF = function (string, network) {
var decoded = wif.decode(string)
var version = decoded.version
function fromPublicKey (buffer, options) {
typeforce(isPoint, buffer)
typeforce(isOptions, options)
return new ECPair(null, buffer, options)
}
function fromWIF (string, network) {
let decoded = wif.decode(string)
let version = decoded.version
// list of networks?
if (types.Array(network)) {
@ -74,58 +81,29 @@ ECPair.fromWIF = function (string, network) {
if (version !== network.wif) throw new Error('Invalid network version')
}
var d = BigInteger.fromBuffer(decoded.privateKey)
return new ECPair(d, null, {
return fromPrivateKey(decoded.privateKey, {
compressed: decoded.compressed,
network: network
})
}
ECPair.makeRandom = function (options) {
function makeRandom (options) {
typeforce(isOptions, options)
options = options || {}
let rng = options.rng || randomBytes
var rng = options.rng || randomBytes
var d
let d
do {
var buffer = rng(32)
typeforce(types.Buffer256bit, buffer)
d = BigInteger.fromBuffer(buffer)
} while (d.signum() <= 0 || d.compareTo(secp256k1.n) >= 0)
return new ECPair(d, null, options)
}
ECPair.prototype.getNetwork = function () {
return this.network
}
ECPair.prototype.getPublicKeyBuffer = function () {
return this.Q.getEncoded(this.compressed)
}
d = rng(32)
typeforce(types.Buffer256bit, d)
} while (!ecc.isPrivate(d))
ECPair.prototype.sign = function (hash) {
if (!this.d) throw new Error('Missing private key')
let signature = ecdsa.sign(hash, this.d)
return Buffer.concat([signature.r.toBuffer(32), signature.s.toBuffer(32)], 64)
}
ECPair.prototype.toWIF = function () {
if (!this.d) throw new Error('Missing private key')
return wif.encode(this.network.wif, this.d.toBuffer(32), this.compressed)
return fromPrivateKey(d, options)
}
ECPair.prototype.verify = function (hash, signature) {
signature = {
r: BigInteger.fromBuffer(signature.slice(0, 32)),
s: BigInteger.fromBuffer(signature.slice(32, 64))
}
return ecdsa.verify(hash, signature, this.Q)
module.exports = {
makeRandom,
fromPrivateKey,
fromPublicKey,
fromWIF
}
module.exports = ECPair

4
src/transaction_builder.js

@ -180,7 +180,7 @@ function fixMultisigOrder (input, transaction, vin) {
var unmatched = input.signatures.concat()
input.signatures = input.pubKeys.map(function (pubKey) {
var keyPair = ECPair.fromPublicKeyBuffer(pubKey)
var keyPair = ECPair.fromPublicKey(pubKey)
var match
// check for a signature
@ -686,7 +686,7 @@ TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashTy
throw new Error('Inconsistent redeemScript')
}
var kpPubKey = keyPair.publicKey || keyPair.getPublicKeyBuffer()
var kpPubKey = keyPair.publicKey || keyPair.getPublicKey()
if (!canSign(input)) {
if (witnessValue !== undefined) {
if (input.value !== undefined && input.value !== witnessValue) throw new Error('Input didn\'t match witnessValue')

4
src/types.js

@ -16,11 +16,9 @@ function Satoshi (value) {
}
// external dependent types
var BigInt = typeforce.quacksLike('BigInteger')
var ECPoint = typeforce.quacksLike('Point')
// exposed, external API
var ECSignature = typeforce.compile({ r: BigInt, s: BigInt })
var Network = typeforce.compile({
messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String),
bip32: {
@ -34,11 +32,9 @@ var Network = typeforce.compile({
// extend typeforce types with ours
var types = {
BigInt: BigInt,
BIP32Path: BIP32Path,
Buffer256bit: typeforce.BufferN(32),
ECPoint: ECPoint,
ECSignature: ECSignature,
Hash160bit: typeforce.BufferN(20),
Hash256bit: typeforce.BufferN(32),
Network: Network,

2
test/bitcoin.core.js

@ -94,7 +94,7 @@ describe('Bitcoin-core', function () {
var keyPair = bitcoin.ECPair.fromWIF(string, network)
it('fromWIF imports ' + string, function () {
assert.strictEqual(keyPair.d.toHex(), hex)
assert.strictEqual(keyPair.privateKey.toString('hex'), hex)
assert.strictEqual(keyPair.compressed, params.isCompressed)
})

135
test/ecdsa.js

@ -1,135 +0,0 @@
/* global describe, it */
var assert = require('assert')
var bcrypto = require('../src/crypto')
var ecdsa = require('../src/ecdsa')
var hoodwink = require('hoodwink')
var BigInteger = require('bigi')
var curve = ecdsa.__curve
var fixtures = require('./fixtures/ecdsa.json')
describe('ecdsa', function () {
function fromRaw (signature) {
return {
r: new BigInteger(signature.r, 16),
s: new BigInteger(signature.s, 16)
}
}
function toRaw (signature) {
return {
r: signature.r.toHex(),
s: signature.s.toHex()
}
}
describe('deterministicGenerateK', function () {
function checkSig () {
return true
}
fixtures.valid.ecdsa.forEach(function (f) {
it('for "' + f.message + '"', function () {
var x = BigInteger.fromHex(f.d).toBuffer(32)
var h1 = bcrypto.sha256(f.message)
var k = ecdsa.deterministicGenerateK(h1, x, checkSig)
assert.strictEqual(k.toHex(), f.k)
})
})
it('loops until an appropriate k value is found', hoodwink(function () {
this.mock(BigInteger, 'fromBuffer', function f (b) {
assert.strictEqual(b.length, 32)
if (f.calls === 0) return BigInteger.ZERO // < 1
if (f.calls === 1) return curve.n // > n - 1
if (f.calls === 2) return new BigInteger('42') // valid
}, 3)
var x = new BigInteger('1').toBuffer(32)
var h1 = Buffer.alloc(32)
var k = ecdsa.deterministicGenerateK(h1, x, checkSig)
assert.strictEqual(k.toString(), '42')
}))
it('loops until a suitable signature is found', hoodwink(function () {
var checkSigStub = this.stub(function f () {
if (f.calls === 0) return false // bad signature
if (f.calls === 1) return true // good signature
}, 2)
var x = BigInteger.ONE.toBuffer(32)
var h1 = Buffer.alloc(32)
var k = ecdsa.deterministicGenerateK(h1, x, checkSigStub)
assert.strictEqual(k.toHex(), 'a9b1a1a84a4c2f96b6158ed7a81404c50cb74373c22e8d9e02d0411d719acae2')
}))
fixtures.valid.rfc6979.forEach(function (f) {
it('produces the expected k values for ' + f.message + " if k wasn't suitable", function () {
var x = BigInteger.fromHex(f.d).toBuffer(32)
var h1 = bcrypto.sha256(f.message)
var results = []
ecdsa.deterministicGenerateK(h1, x, function (k) {
results.push(k)
return results.length === 16
})
assert.strictEqual(results[0].toHex(), f.k0)
assert.strictEqual(results[1].toHex(), f.k1)
assert.strictEqual(results[15].toHex(), f.k15)
})
})
})
describe('sign', function () {
fixtures.valid.ecdsa.forEach(function (f) {
it('produces a deterministic signature for "' + f.message + '"', function () {
var d = BigInteger.fromHex(f.d)
var hash = bcrypto.sha256(f.message)
var signature = ecdsa.sign(hash, d)
assert.deepEqual(toRaw(signature), f.signature)
})
})
it('should sign with low S value', function () {
var hash = bcrypto.sha256('Vires in numeris')
var sig = ecdsa.sign(hash, BigInteger.ONE)
// See BIP62 for more information
var N_OVER_TWO = curve.n.shiftRight(1)
assert(sig.s.compareTo(N_OVER_TWO) <= 0)
})
})
describe('verify', function () {
fixtures.valid.ecdsa.forEach(function (f) {
it('verifies a valid signature for "' + f.message + '"', function () {
var d = BigInteger.fromHex(f.d)
var H = bcrypto.sha256(f.message)
var signature = fromRaw(f.signature)
var Q = curve.G.multiply(d)
assert(ecdsa.verify(H, signature, Q))
})
})
fixtures.invalid.verify.forEach(function (f) {
it('fails to verify with ' + f.description, function () {
var H = bcrypto.sha256(f.message)
var d = BigInteger.fromHex(f.d)
var signature = fromRaw(f.signature)
var Q = curve.G.multiply(d)
assert.strictEqual(ecdsa.verify(H, signature, Q), false)
})
})
})
})

176
test/ecpair.js

@ -1,34 +1,36 @@
/* global describe, it, beforeEach */
/* eslint-disable no-new */
var assert = require('assert')
var ecdsa = require('../src/ecdsa')
var ecurve = require('ecurve')
var proxyquire = require('proxyquire')
var hoodwink = require('hoodwink')
let assert = require('assert')
let proxyquire = require('proxyquire')
let hoodwink = require('hoodwink')
var BigInteger = require('bigi')
var ECPair = require('../src/ecpair')
let ECPair = require('../src/ecpair')
let tinysecp = require('tiny-secp256k1')
var fixtures = require('./fixtures/ecpair.json')
var curve = ecdsa.__curve
let fixtures = require('./fixtures/ecpair.json')
var NETWORKS = require('../src/networks')
var NETWORKS_LIST = [] // Object.values(NETWORKS)
for (var networkName in NETWORKS) {
let NETWORKS = require('../src/networks')
let NETWORKS_LIST = [] // Object.values(NETWORKS)
for (let networkName in NETWORKS) {
NETWORKS_LIST.push(NETWORKS[networkName])
}
let ZERO = Buffer.alloc(32, 0)
let ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex')
let GROUP_ORDER = Buffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 'hex')
let GROUP_ORDER_LESS_1 = Buffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140', 'hex')
describe('ECPair', function () {
describe('constructor', function () {
it('defaults to compressed', function () {
var keyPair = new ECPair(BigInteger.ONE)
let keyPair = ECPair.fromPrivateKey(ONE)
assert.strictEqual(keyPair.compressed, true)
})
it('supports the uncompressed option', function () {
var keyPair = new ECPair(BigInteger.ONE, null, {
let keyPair = ECPair.fromPrivateKey(ONE, {
compressed: false
})
@ -36,7 +38,7 @@ describe('ECPair', function () {
})
it('supports the network option', function () {
var keyPair = new ECPair(BigInteger.ONE, null, {
let keyPair = ECPair.fromPrivateKey(ONE, {
compressed: false,
network: NETWORKS.testnet
})
@ -45,51 +47,58 @@ describe('ECPair', function () {
})
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, {
it('derives public key for ' + f.WIF, function () {
let d = Buffer.from(f.d, 'hex')
console.log(d)
let keyPair = ECPair.fromPrivateKey(d, {
compressed: f.compressed
})
assert.strictEqual(keyPair.getPublicKeyBuffer().toString('hex'), f.Q)
assert.strictEqual(keyPair.publicKey.toString('hex'), f.Q)
})
})
fixtures.invalid.constructor.forEach(function (f) {
it('throws ' + f.exception, function () {
var d = f.d && new BigInteger(f.d)
var Q = f.Q && ecurve.Point.decodeFrom(curve, Buffer.from(f.Q, 'hex'))
assert.throws(function () {
new ECPair(d, Q, f.options)
}, new RegExp(f.exception))
if (f.d) {
let d = Buffer.from(f.d, 'hex')
assert.throws(function () {
ECPair.fromPrivateKey(d, f.options)
}, new RegExp(f.exception))
} else {
let Q = Buffer.from(f.Q, 'hex')
assert.throws(function () {
ECPair.fromPublicKey(Q, f.options)
}, new RegExp(f.exception))
}
})
})
})
describe('getPublicKeyBuffer', function () {
var keyPair
describe('getPublicKey', function () {
let keyPair
beforeEach(function () {
keyPair = new ECPair(BigInteger.ONE)
keyPair = ECPair.fromPrivateKey(ONE)
})
it('wraps Q.getEncoded', hoodwink(function () {
this.mock(keyPair.Q, 'getEncoded', function (compressed) {
assert.strictEqual(compressed, keyPair.compressed)
}, 1)
it('calls pointFromScalar lazily', hoodwink(function () {
assert.strictEqual(keyPair.__Q, null)
keyPair.getPublicKeyBuffer()
// .publicKey forces the memoization
assert.strictEqual(keyPair.publicKey.toString('hex'), '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798')
assert.strictEqual(keyPair.__Q.toString('hex'), '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798')
}))
})
describe('fromWIF', function () {
fixtures.valid.forEach(function (f) {
it('imports ' + f.WIF + ' (' + f.network + ')', function () {
var network = NETWORKS[f.network]
var keyPair = ECPair.fromWIF(f.WIF, network)
let network = NETWORKS[f.network]
let keyPair = ECPair.fromWIF(f.WIF, network)
assert.strictEqual(keyPair.d.toString(), f.d)
assert.strictEqual(keyPair.privateKey.toString('hex'), f.d)
assert.strictEqual(keyPair.compressed, f.compressed)
assert.strictEqual(keyPair.network, network)
})
@ -97,9 +106,9 @@ describe('ECPair', function () {
fixtures.valid.forEach(function (f) {
it('imports ' + f.WIF + ' (via list of networks)', function () {
var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
let keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
assert.strictEqual(keyPair.d.toString(), f.d)
assert.strictEqual(keyPair.privateKey.toString('hex'), f.d)
assert.strictEqual(keyPair.compressed, f.compressed)
assert.strictEqual(keyPair.network, NETWORKS[f.network])
})
@ -108,7 +117,7 @@ describe('ECPair', function () {
fixtures.invalid.fromWIF.forEach(function (f) {
it('throws on ' + f.WIF, function () {
assert.throws(function () {
var networks = f.network ? NETWORKS[f.network] : NETWORKS_LIST
let networks = f.network ? NETWORKS[f.network] : NETWORKS_LIST
ECPair.fromWIF(f.WIF, networks)
}, new RegExp(f.exception))
@ -119,30 +128,29 @@ describe('ECPair', function () {
describe('toWIF', function () {
fixtures.valid.forEach(function (f) {
it('exports ' + f.WIF, function () {
var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
var result = keyPair.toWIF()
let keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
let result = keyPair.toWIF()
assert.strictEqual(result, f.WIF)
})
})
})
describe('makeRandom', function () {
var d = Buffer.from('0404040404040404040404040404040404040404040404040404040404040404', 'hex')
var exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv'
let d = Buffer.alloc(32, 4)
let exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv'
describe('uses randombytes RNG', function () {
it('generates a ECPair', function () {
var stub = { randombytes: function () { return d } }
var ProxiedECPair = proxyquire('../src/ecpair', stub)
let stub = { randombytes: function () { return d } }
let ProxiedECPair = proxyquire('../src/ecpair', stub)
var keyPair = ProxiedECPair.makeRandom()
let keyPair = ProxiedECPair.makeRandom()
assert.strictEqual(keyPair.toWIF(), exWIF)
})
})
it('allows a custom RNG to be used', function () {
var keyPair = ECPair.makeRandom({
let keyPair = ECPair.makeRandom({
rng: function (size) { return d.slice(0, size) }
})
@ -150,14 +158,14 @@ describe('ECPair', function () {
})
it('retains the same defaults as ECPair constructor', function () {
var keyPair = ECPair.makeRandom()
let keyPair = ECPair.makeRandom()
assert.strictEqual(keyPair.compressed, true)
assert.strictEqual(keyPair.network, NETWORKS.bitcoin)
})
it('supports the options parameter', function () {
var keyPair = ECPair.makeRandom({
let keyPair = ECPair.makeRandom({
compressed: false,
network: NETWORKS.testnet
})
@ -168,7 +176,7 @@ describe('ECPair', function () {
it('throws if d is bad length', function () {
function rng () {
return BigInteger.ZERO.toBuffer(28)
return Buffer.alloc(28)
}
assert.throws(function () {
@ -176,58 +184,59 @@ describe('ECPair', function () {
}, /Expected Buffer\(Length: 32\), got Buffer\(Length: 28\)/)
})
it('loops until d is within interval [1, n - 1] : 1', hoodwink(function () {
var rng = this.stub(function f () {
if (f.calls === 0) return BigInteger.ZERO.toBuffer(32) // 0
return BigInteger.ONE.toBuffer(32) // >0
it('loops until d is within interval [1, n) : 1', hoodwink(function () {
let rng = this.stub(function f () {
if (f.calls === 0) return ZERO // 0
return ONE // >0
}, 2)
ECPair.makeRandom({ rng: rng })
}))
it('loops until d is within interval [1, n - 1] : n - 1', hoodwink(function () {
var rng = this.stub(function f () {
if (f.calls === 0) return BigInteger.ZERO.toBuffer(32) // <1
if (f.calls === 1) return curve.n.toBuffer(32) // >n-1
return curve.n.subtract(BigInteger.ONE).toBuffer(32) // n-1
it('loops until d is within interval [1, n) : n - 1', hoodwink(function () {
let rng = this.stub(function f () {
if (f.calls === 0) return ZERO // <1
if (f.calls === 1) return GROUP_ORDER // >n-1
return GROUP_ORDER_LESS_1 // n-1
}, 3)
ECPair.makeRandom({ rng: rng })
}))
})
describe('getNetwork', function () {
describe('.network', function () {
fixtures.valid.forEach(function (f) {
it('returns ' + f.network + ' for ' + f.WIF, function () {
var network = NETWORKS[f.network]
var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
let network = NETWORKS[f.network]
let keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
assert.strictEqual(keyPair.getNetwork(), network)
assert.strictEqual(keyPair.network, network)
})
})
})
describe('ecdsa wrappers', function () {
var keyPair, hash
describe('tinysecp wrappers', function () {
let keyPair, hash, signature
beforeEach(function () {
keyPair = ECPair.makeRandom()
hash = Buffer.alloc(32)
hash = ZERO
signature = Buffer.alloc(64, 1)
})
describe('signing', function () {
it('wraps ecdsa.sign', hoodwink(function () {
this.mock(ecdsa, 'sign', function (h, d) {
it('wraps tinysecp.sign', hoodwink(function () {
this.mock(tinysecp, 'sign', function (h, d) {
assert.strictEqual(h, hash)
assert.strictEqual(d, keyPair.d)
return { r: BigInteger.ONE, s: BigInteger.ONE }
assert.strictEqual(d, keyPair.privateKey)
return signature
}, 1)
keyPair.sign(hash)
assert.strictEqual(keyPair.sign(hash), signature)
}))
it('throws if no private key is found', function () {
keyPair.d = null
delete keyPair.__d
assert.throws(function () {
keyPair.sign(hash)
@ -236,24 +245,15 @@ describe('ECPair', function () {
})
describe('verify', function () {
var signature
beforeEach(function () {
signature = keyPair.sign(hash)
})
it('wraps ecdsa.verify', hoodwink(function () {
this.mock(ecdsa, 'verify', function (h, s, q) {
it('wraps tinysecp.verify', hoodwink(function () {
this.mock(tinysecp, 'verify', function (h, q, s) {
assert.strictEqual(h, hash)
// assert.strictEqual(s, signature)
assert.deepEqual(s, {
r: BigInteger.fromBuffer(signature.slice(0, 32)),
s: BigInteger.fromBuffer(signature.slice(32, 64))
})
assert.strictEqual(q, keyPair.Q)
assert.strictEqual(q, keyPair.publicKey)
assert.strictEqual(s, signature)
return true
}, 1)
keyPair.verify(hash, signature)
assert.strictEqual(keyPair.verify(hash, signature), true)
}))
})
})

41
test/fixtures/ecpair.json

@ -1,7 +1,7 @@
{
"valid": [
{
"d": "1",
"d": "0000000000000000000000000000000000000000000000000000000000000001",
"Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"compressed": true,
"network": "bitcoin",
@ -9,7 +9,7 @@
"WIF": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
},
{
"d": "1",
"d": "0000000000000000000000000000000000000000000000000000000000000001",
"Q": "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
"compressed": false,
"network": "bitcoin",
@ -17,7 +17,7 @@
"WIF": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf"
},
{
"d": "19898843618908353587043383062236220484949425084007183071220218307100305431102",
"d": "2bfe58ab6d9fd575bdc3a624e4825dd2b375d64ac033fbc46ea79dbab4f69a3e",
"Q": "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
"compressed": true,
"network": "bitcoin",
@ -25,7 +25,7 @@
"WIF": "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9o"
},
{
"d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
"d": "6c4313b03f2e7324d75e642f0ab81b734b724e13fec930f309e222470236d66b",
"Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34",
"compressed": true,
"network": "bitcoin",
@ -33,7 +33,7 @@
"WIF": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx"
},
{
"d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
"d": "6c4313b03f2e7324d75e642f0ab81b734b724e13fec930f309e222470236d66b",
"Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6",
"compressed": false,
"network": "bitcoin",
@ -41,7 +41,7 @@
"WIF": "5JdxzLtFPHNe7CAL8EBC6krdFv9pwPoRo4e3syMZEQT9srmK8hh"
},
{
"d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
"d": "6c4313b03f2e7324d75e642f0ab81b734b724e13fec930f309e222470236d66b",
"Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34",
"compressed": true,
"network": "testnet",
@ -49,7 +49,7 @@
"WIF": "cRD9b1m3vQxmwmjSoJy7Mj56f4uNFXjcWMCzpQCEmHASS4edEwXv"
},
{
"d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
"d": "6c4313b03f2e7324d75e642f0ab81b734b724e13fec930f309e222470236d66b",
"Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6",
"compressed": false,
"network": "testnet",
@ -57,7 +57,7 @@
"WIF": "92Qba5hnyWSn5Ffcka56yMQauaWY6ZLd91Vzxbi4a9CCetaHtYj"
},
{
"d": "115792089237316195423570985008687907852837564279074904382605163141518161494336",
"d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
"Q": "0379be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"compressed": true,
"network": "bitcoin",
@ -68,36 +68,27 @@
"invalid": {
"constructor": [
{
"exception": "Private key must be greater than 0",
"d": "-1"
"exception": "Private key not in range \\[1, n\\)",
"d": "0000000000000000000000000000000000000000000000000000000000000000"
},
{
"exception": "Private key must be greater than 0",
"d": "0"
"exception": "Private key not in range \\[1, n\\)",
"d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
},
{
"exception": "Private key must be less than the curve order",
"d": "115792089237316195423570985008687907852837564279074904382605163141518161494337"
},
{
"exception": "Private key must be less than the curve order",
"d": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
"exception": "Private key not in range \\[1, n\\)",
"d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142"
},
{
"exception": "Expected property \"compressed\" of type \\?Boolean, got Number 2",
"d": "1",
"d": "0000000000000000000000000000000000000000000000000000000000000001",
"options": {
"compressed": 2
}
},
{
"exception": "Unexpected publicKey parameter",
"d": "1",
"Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
},
{
"exception": "Expected property \"network.messagePrefix\" of type Buffer|String, got undefined",
"d": "1",
"d": "0000000000000000000000000000000000000000000000000000000000000001",
"options": {
"network": {}
}

2
test/integration/_regtest.js

@ -72,7 +72,7 @@ let baddress = bitcoin.address
let bcrypto = bitcoin.crypto
function getAddress (node, network) {
network = network || bitcoin.networks.bitcoin
return baddress.toBase58Check(bcrypto.hash160(node.getPublicKeyBuffer()), network.pubKeyHash)
return baddress.toBase58Check(bcrypto.hash160(node.publicKey), network.pubKeyHash)
}
function randomAddress () {

10
test/integration/addresses.js

@ -12,7 +12,7 @@ let baddress = bitcoin.address
let bcrypto = bitcoin.crypto
function getAddress (node, network) {
network = network || bitcoin.networks.bitcoin
return baddress.toBase58Check(bcrypto.hash160(node.getPublicKeyBuffer()), network.pubKeyHash)
return baddress.toBase58Check(bcrypto.hash160(node.publicKey), network.pubKeyHash)
}
describe('bitcoinjs-lib (addresses)', function () {
@ -26,7 +26,7 @@ describe('bitcoinjs-lib (addresses)', function () {
it('can generate an address from a SHA256 hash', function () {
var hash = bitcoin.crypto.sha256(Buffer.from('correct horse battery staple'))
var keyPair = bitcoin.ECPair.makeRandom({ rng: () => hash })
var keyPair = bitcoin.ECPair.fromPrivateKey(hash)
var address = getAddress(keyPair)
// Generating addresses from SHA256 hashes is not secure if the input to the hash function is predictable
@ -57,9 +57,8 @@ describe('bitcoinjs-lib (addresses)', function () {
it('can generate a SegWit address', function () {
var keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
var pubKey = keyPair.getPublicKeyBuffer()
var scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(pubKey))
var scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(keyPair.publicKey))
var address = bitcoin.address.fromOutputScript(scriptPubKey)
assert.strictEqual(address, 'bc1qt97wqg464zrhnx23upykca5annqvwkwujjglky')
@ -67,9 +66,8 @@ describe('bitcoinjs-lib (addresses)', function () {
it('can generate a SegWit address (via P2SH)', function () {
var keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
var pubKey = keyPair.getPublicKeyBuffer()
var redeemScript = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(pubKey))
var redeemScript = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(keyPair.publicKey))
var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript))
var address = bitcoin.address.fromOutputScript(scriptPubKey)

4
test/integration/cltv.js

@ -25,11 +25,11 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
bitcoin.opcodes.OP_DROP,
bitcoin.opcodes.OP_ELSE,
bQ.getPublicKeyBuffer(),
bQ.publicKey,
bitcoin.opcodes.OP_CHECKSIGVERIFY,
bitcoin.opcodes.OP_ENDIF,
aQ.getPublicKeyBuffer(),
aQ.publicKey,
bitcoin.opcodes.OP_CHECKSIG
])
}

2
test/integration/crypto.js

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

4
test/integration/csv.js

@ -26,11 +26,11 @@ describe('bitcoinjs-lib (transactions w/ CSV)', function () {
bitcoin.opcodes.OP_DROP,
bitcoin.opcodes.OP_ELSE,
bQ.getPublicKeyBuffer(),
bQ.publicKey,
bitcoin.opcodes.OP_CHECKSIGVERIFY,
bitcoin.opcodes.OP_ENDIF,
aQ.getPublicKeyBuffer(),
aQ.publicKey,
bitcoin.opcodes.OP_CHECKSIG
])
}

80
test/integration/stealth.js

@ -1,74 +1,72 @@
/* global describe, it */
let assert = require('assert')
let bigi = require('bigi')
let bitcoin = require('../../')
let ecurve = require('ecurve')
let secp256k1 = ecurve.getCurveByName('secp256k1')
let G = secp256k1.G
let n = secp256k1.n
let ecc = require('tiny-secp256k1')
// TODO: remove
let baddress = bitcoin.address
let bcrypto = bitcoin.crypto
function getAddress (node) {
return baddress.toBase58Check(bcrypto.hash160(node.getPublicKeyBuffer()), bitcoin.networks.bitcoin.pubKeyHash)
return baddress.toBase58Check(bcrypto.hash160(node.publicKey), bitcoin.networks.bitcoin.pubKeyHash)
}
// vG = (dG \+ sha256(e * dG)G)
function stealthSend (e, Q) {
var eQ = Q.multiply(e) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var cG = G.multiply(c)
var vG = new bitcoin.ECPair(null, Q.add(cG))
var eQ = ecc.pointMultiply(Q, e, true) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var Qc = ecc.pointAddScalar(Q, c)
var vG = bitcoin.ECPair.fromPublicKey(Qc)
return vG
}
// v = (d + sha256(eG * d))
function stealthReceive (d, eG) {
var eQ = eG.multiply(d) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var v = new bitcoin.ECPair(d.add(c).mod(n))
var eQ = ecc.pointMultiply(eG, d) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var dc = ecc.privateAdd(d, c)
var v = bitcoin.ECPair.fromPrivateKey(dc)
return v
}
// d = (v - sha256(e * dG))
function stealthRecoverLeaked (v, e, Q) {
var eQ = Q.multiply(e) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var d = new bitcoin.ECPair(v.subtract(c).mod(n))
var eQ = ecc.pointMultiply(Q, e) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var vc = ecc.privateSub(v, c)
var d = bitcoin.ECPair.fromPrivateKey(vc)
return d
}
// vG = (rG \+ sha256(e * dG)G)
function stealthDualSend (e, R, Q) {
var eQ = Q.multiply(e) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var cG = G.multiply(c)
var vG = new bitcoin.ECPair(null, R.add(cG))
var eQ = ecc.pointMultiply(Q, e) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var Rc = ecc.pointAddScalar(R, c)
var vG = bitcoin.ECPair.fromPublicKey(Rc)
return vG
}
// vG = (rG \+ sha256(eG * d)G)
function stealthDualScan (d, R, eG) {
var eQ = eG.multiply(d) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var cG = G.multiply(c)
var vG = new bitcoin.ECPair(null, R.add(cG))
var eQ = ecc.pointMultiply(eG, d) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var Rc = ecc.pointAddScalar(R, c)
var vG = bitcoin.ECPair.fromPublicKey(Rc)
return vG
}
// v = (r + sha256(eG * d))
function stealthDualReceive (d, r, eG) {
var eQ = eG.multiply(d) // shared secret
var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
var v = new bitcoin.ECPair(r.add(c).mod(n))
var eQ = ecc.pointMultiply(eG, d) // shared secret
var c = bitcoin.crypto.sha256(eQ)
var rc = ecc.privateAdd(r, c)
var v = bitcoin.ECPair.fromPrivateKey(rc)
return v
}
@ -80,12 +78,12 @@ describe('bitcoinjs-lib (crypto)', function () {
var nonce = bitcoin.ECPair.fromWIF('KxVqB96pxbw1pokzQrZkQbLfVBjjHFfp2mFfEp8wuEyGenLFJhM9') // private to sender
// ... recipient reveals public key (recipient.Q) to sender
var forSender = stealthSend(nonce.d, recipient.Q)
var forSender = stealthSend(nonce.privateKey, recipient.publicKey)
assert.equal(getAddress(forSender), '1CcZWwCpACJL3AxqoDbwEt4JgDFuTHUspE')
assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/)
// ... sender reveals nonce public key (nonce.Q) to recipient
var forRecipient = stealthReceive(recipient.d, nonce.Q)
var forRecipient = stealthReceive(recipient.privateKey, nonce.publicKey)
assert.equal(getAddress(forRecipient), '1CcZWwCpACJL3AxqoDbwEt4JgDFuTHUspE')
assert.equal(forRecipient.toWIF(), 'L1yjUN3oYyCXV3LcsBrmxCNTa62bZKWCybxVJMvqjMmmfDE8yk7n')
@ -98,11 +96,11 @@ describe('bitcoinjs-lib (crypto)', function () {
var nonce = bitcoin.ECPair.makeRandom() // private to sender
// ... recipient reveals public key (recipient.Q) to sender
var forSender = stealthSend(nonce.d, recipient.Q)
var forSender = stealthSend(nonce.privateKey, recipient.publicKey)
assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/)
// ... sender reveals nonce public key (nonce.Q) to recipient
var forRecipient = stealthReceive(recipient.d, nonce.Q)
var forRecipient = stealthReceive(recipient.privateKey, nonce.publicKey)
assert.doesNotThrow(function () { forRecipient.toWIF() })
// sender and recipient, both derived same address
@ -114,15 +112,15 @@ describe('bitcoinjs-lib (crypto)', function () {
var nonce = bitcoin.ECPair.makeRandom() // private to sender
// ... recipient reveals public key (recipient.Q) to sender
var forSender = stealthSend(nonce.d, recipient.Q)
var forSender = stealthSend(nonce.privateKey, recipient.publicKey)
assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/)
// ... sender reveals nonce public key (nonce.Q) to recipient
var forRecipient = stealthReceive(recipient.d, nonce.Q)
var forRecipient = stealthReceive(recipient.privateKey, nonce.publicKey)
assert.doesNotThrow(function () { forRecipient.toWIF() })
// ... recipient accidentally leaks forRecipient.d on the blockchain
var leaked = stealthRecoverLeaked(forRecipient.d, nonce.d, recipient.Q)
var leaked = stealthRecoverLeaked(forRecipient.privateKey, nonce.privateKey, recipient.publicKey)
assert.equal(leaked.toWIF(), recipient.toWIF())
})
@ -133,15 +131,15 @@ describe('bitcoinjs-lib (crypto)', function () {
var nonce = bitcoin.ECPair.fromWIF('KxVqB96pxbw1pokzQrZkQbLfVBjjHFfp2mFfEp8wuEyGenLFJhM9') // private to sender
// ... recipient reveals public key(s) (recipient.Q, scan.Q) to sender
var forSender = stealthDualSend(nonce.d, recipient.Q, scan.Q)
var forSender = stealthDualSend(nonce.privateKey, recipient.publicKey, scan.publicKey)
assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/)
// ... sender reveals nonce public key (nonce.Q) to scanner
var forScanner = stealthDualScan(scan.d, recipient.Q, nonce.Q)
var forScanner = stealthDualScan(scan.privateKey, recipient.publicKey, nonce.publicKey)
assert.throws(function () { forScanner.toWIF() }, /Error: Missing private key/)
// ... scanner reveals relevant transaction + nonce public key (nonce.Q) to recipient
var forRecipient = stealthDualReceive(scan.d, recipient.d, nonce.Q)
var forRecipient = stealthDualReceive(scan.privateKey, recipient.privateKey, nonce.publicKey)
assert.doesNotThrow(function () { forRecipient.toWIF() })
// scanner, sender and recipient, all derived same address
@ -155,15 +153,15 @@ describe('bitcoinjs-lib (crypto)', function () {
var nonce = bitcoin.ECPair.makeRandom() // private to sender
// ... recipient reveals public key(s) (recipient.Q, scan.Q) to sender
var forSender = stealthDualSend(nonce.d, recipient.Q, scan.Q)
var forSender = stealthDualSend(nonce.privateKey, recipient.publicKey, scan.publicKey)
assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/)
// ... sender reveals nonce public key (nonce.Q) to scanner
var forScanner = stealthDualScan(scan.d, recipient.Q, nonce.Q)
var forScanner = stealthDualScan(scan.privateKey, recipient.publicKey, nonce.publicKey)
assert.throws(function () { forScanner.toWIF() }, /Error: Missing private key/)
// ... scanner reveals relevant transaction + nonce public key (nonce.Q) to recipient
var forRecipient = stealthDualReceive(scan.d, recipient.d, nonce.Q)
var forRecipient = stealthDualReceive(scan.privateKey, recipient.privateKey, nonce.publicKey)
assert.doesNotThrow(function () { forRecipient.toWIF() })
// scanner, sender and recipient, all derived same address

13
test/integration/transactions.js

@ -10,7 +10,7 @@ let baddress = bitcoin.address
let bcrypto = bitcoin.crypto
function getAddress (node, network) {
network = network || bitcoin.networks.bitcoin
return baddress.toBase58Check(bcrypto.hash160(node.getPublicKeyBuffer()), network.pubKeyHash)
return baddress.toBase58Check(bcrypto.hash160(node.publicKey), network.pubKeyHash)
}
function rng () {
@ -115,7 +115,7 @@ describe('bitcoinjs-lib (transactions)', function () {
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe',
'91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx9rcrL7'
].map(function (wif) { return bitcoin.ECPair.fromWIF(wif, regtest) })
var pubKeys = keyPairs.map(function (x) { return x.getPublicKeyBuffer() })
var pubKeys = keyPairs.map(function (x) { return x.publicKey })
var redeemScript = bitcoin.script.multisig.output.encode(2, pubKeys)
var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript))
@ -150,8 +150,7 @@ describe('bitcoinjs-lib (transactions)', function () {
this.timeout(30000)
var keyPair = bitcoin.ECPair.fromWIF('cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87JcbXMTcA', regtest)
var pubKey = keyPair.getPublicKeyBuffer()
var pubKeyHash = bitcoin.crypto.hash160(pubKey)
var pubKeyHash = bitcoin.crypto.hash160(keyPair.publicKey)
var redeemScript = bitcoin.script.witnessPubKeyHash.output.encode(pubKeyHash)
var redeemScriptHash = bitcoin.crypto.hash160(redeemScript)
@ -191,7 +190,7 @@ describe('bitcoinjs-lib (transactions)', function () {
'cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87KcLPVfXz',
'cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87L7FgDCKE'
].map(function (wif) { return bitcoin.ECPair.fromWIF(wif, regtest) })
var pubKeys = keyPairs.map(function (x) { return x.getPublicKeyBuffer() })
var pubKeys = keyPairs.map(function (x) { return x.publicKey })
var witnessScript = bitcoin.script.multisig.output.encode(3, pubKeys)
var redeemScript = bitcoin.script.witnessScriptHash.output.encode(bitcoin.crypto.sha256(witnessScript))
@ -230,7 +229,7 @@ describe('bitcoinjs-lib (transactions)', function () {
'032b4c06c06c3ec0b7fa29519dfa5aae193ee2cc35ca127f29f14ec605d62fb63d',
'0216c92abe433106491bdeb4a261226f20f5a4ac86220cc6e37655aac6bf3c1f2a',
'039e05da8b8ea4f9868ecebb25998c7701542986233f4401799551fbecf316b18f'
].map(function (q) { return bitcoin.ECPair.fromPublicKeyBuffer(Buffer.from(q, 'hex')) })
].map(function (q) { return bitcoin.ECPair.fromPublicKey(Buffer.from(q, 'hex')) })
var tx = bitcoin.Transaction.fromHex(txHex)
@ -241,7 +240,7 @@ describe('bitcoinjs-lib (transactions)', function () {
var ss = bitcoin.script.signature.decode(scriptSig.signature)
var hash = tx.hashForSignature(i, prevOutScript, ss.hashType)
assert.strictEqual(scriptSig.pubKey.toString('hex'), keyPair.getPublicKeyBuffer().toString('hex'))
assert.strictEqual(scriptSig.pubKey.toString('hex'), keyPair.publicKey.toString('hex'))
assert.strictEqual(keyPair.verify(hash, ss.signature), true)
})
})

5
test/transaction_builder.js

@ -7,7 +7,6 @@ let bscript = require('../src/script')
let btemplates = require('../src/templates')
let ops = require('bitcoin-ops')
let BigInteger = require('bigi')
let ECPair = require('../src/ecpair')
let Transaction = require('../src/transaction')
let TransactionBuilder = require('../src/transaction_builder')
@ -17,7 +16,7 @@ let fixtures = require('./fixtures/transaction_builder')
// TODO: remove
function getAddress (node) {
return baddress.toBase58Check(bcrypto.hash160(node.getPublicKeyBuffer()), NETWORKS.bitcoin.pubKeyHash)
return baddress.toBase58Check(bcrypto.hash160(node.publicKey), NETWORKS.bitcoin.pubKeyHash)
}
function construct (f, dontSign) {
@ -89,7 +88,7 @@ function construct (f, dontSign) {
describe('TransactionBuilder', function () {
// constants
var keyPair = new ECPair(BigInteger.ONE)
var keyPair = ECPair.fromPrivateKey(Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex'))
var scripts = [
'1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH',
'1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP'

12
test/types.js

@ -5,18 +5,6 @@ var types = require('../src/types')
var typeforce = require('typeforce')
describe('types', function () {
describe('BigInt/ECPoint', function () {
it('return true for duck types', function () {
assert(types.BigInt(new function BigInteger () {}()))
assert(types.ECPoint(new function Point () {}()))
})
it('return false for bad types', function () {
assert(!types.BigInt(new function NotABigInteger () {}()))
assert(!types.ECPoint(new function NotAPoint () {}()))
})
})
describe('Buffer Hash160/Hash256', function () {
var buffer20byte = Buffer.alloc(20)
var buffer32byte = Buffer.alloc(32)

Loading…
Cancel
Save