diff --git a/src/address.js b/src/address.js index 669b6d57a..d6924b328 100644 --- a/src/address.js +++ b/src/address.js @@ -9,7 +9,7 @@ function fromBase58Check (address) { if (payload.length < 21) throw new TypeError(address + ' is too short') if (payload.length > 21) throw new TypeError(address + ' is too long') - var version = payload.readUInt8(0) + var version = payload[0] var hash = payload.slice(1) return { hash: hash, version: version } @@ -38,15 +38,9 @@ function toBase58Check (hash, version) { function toOutputScript (address, network) { network = network || networks.bitcoin - var payload = bs58check.decode(address) - if (payload.length < 21) throw new TypeError(address + ' is too short') - if (payload.length > 21) throw new TypeError(address + ' is too long') - - var version = payload.readUInt8(0) - var hash = payload.slice(1) - - if (version === network.pubKeyHash) return bscript.pubKeyHashOutput(hash) - if (version === network.scriptHash) return bscript.scriptHashOutput(hash) + var decode = fromBase58Check(address) + if (decode.version === network.pubKeyHash) return bscript.pubKeyHashOutput(decode.hash) + if (decode.version === network.scriptHash) return bscript.scriptHashOutput(decode.hash) throw new Error(address + ' has no matching Script') } diff --git a/src/ecdsa.js b/src/ecdsa.js index a5190b769..103095dbd 100644 --- a/src/ecdsa.js +++ b/src/ecdsa.js @@ -8,16 +8,17 @@ var ECSignature = require('./ecsignature') var ZERO = new Buffer([0]) var ONE = new Buffer([1]) +var ecurve = require('ecurve') +var secp256k1 = ecurve.getCurveByName('secp256k1') + // https://tools.ietf.org/html/rfc6979#section-3.2 -function deterministicGenerateK (curve, hash, d, checkSig) { +function deterministicGenerateK (hash, x, checkSig) { typeforce(types.tuple( - types.ECCurve, types.Hash256bit, - types.BigInt, + types.Buffer256bit, types.Function ), arguments) - var x = d.toBuffer(32) var k = new Buffer(32) var v = new Buffer(32) @@ -57,7 +58,7 @@ function deterministicGenerateK (curve, hash, d, checkSig) { 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(curve.n) >= 0) || !checkSig(T)) { + while (T.signum() <= 0 || T.compareTo(secp256k1.n) >= 0 || !checkSig(T)) { k = createHmac('sha256', k) .update(v) .update(ZERO) @@ -74,18 +75,21 @@ function deterministicGenerateK (curve, hash, d, checkSig) { return T } -function sign (curve, hash, d) { - typeforce(types.tuple(types.ECCurve, types.Hash256bit, types.BigInt), arguments) +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 = curve.n - var G = curve.G + var n = secp256k1.n + var G = secp256k1.G var r, s - deterministicGenerateK(curve, hash, d, function (k) { + deterministicGenerateK(hash, x, function (k) { var Q = G.multiply(k) - if (curve.isInfinity(Q)) return false + if (secp256k1.isInfinity(Q)) return false r = Q.affineX.mod(n) if (r.signum() === 0) return false @@ -96,8 +100,6 @@ function sign (curve, hash, d) { return true }) - var N_OVER_TWO = n.shiftRight(1) - // enforce low S values, see bip62: 'low s values in signatures' if (s.compareTo(N_OVER_TWO) > 0) { s = n.subtract(s) @@ -106,16 +108,15 @@ function sign (curve, hash, d) { return new ECSignature(r, s) } -function verify (curve, hash, signature, Q) { +function verify (hash, signature, Q) { typeforce(types.tuple( - types.ECCurve, types.Hash256bit, types.ECSignature, types.ECPoint ), arguments) - var n = curve.n - var G = curve.G + var n = secp256k1.n + var G = secp256k1.G var r = signature.r var s = signature.s @@ -141,7 +142,7 @@ function verify (curve, hash, signature, Q) { var R = G.multiplyTwo(u1, Q, u2) // 1.4.5 (cont.) Enforce R is not at infinity - if (curve.isInfinity(R)) return false + if (secp256k1.isInfinity(R)) return false // 1.4.6 Convert the field element R.x to an integer var xR = R.affineX @@ -161,16 +162,15 @@ function verify (curve, hash, signature, Q) { * * http://www.secg.org/download/aid-780/sec1-v2.pdf */ -function recoverPubKey (curve, e, signature, i) { +function recoverPubKey (e, signature, i) { typeforce(types.tuple( - types.ECCurve, types.BigInt, types.ECSignature, types.UInt2 ), arguments) - var n = curve.n - var G = curve.G + var n = secp256k1.n + var G = secp256k1.G var r = signature.r var s = signature.s @@ -186,11 +186,11 @@ function recoverPubKey (curve, e, signature, i) { // 1.1 Let x = r + jn var x = isSecondKey ? r.add(n) : r - var R = curve.pointFromX(isYOdd, x) + var R = secp256k1.pointFromX(isYOdd, x) // 1.4 Check that nR is at infinity var nR = R.multiply(n) - if (!curve.isInfinity(nR)) throw new Error('nR is not a valid curve point') + if (!secp256k1.isInfinity(nR)) throw new Error('nR is not a valid curve point') // Compute r^-1 var rInv = r.modInverse(n) @@ -202,7 +202,7 @@ function recoverPubKey (curve, e, signature, i) { // Q = r^-1 (sR + -eG) var Q = R.multiplyTwo(s, G, eNeg).multiply(rInv) - curve.validate(Q) + secp256k1.validate(Q) return Q } @@ -218,16 +218,15 @@ function recoverPubKey (curve, e, signature, i) { * This function simply tries all four cases and returns the value * that resulted in a successful pubkey recovery. */ -function calcPubKeyRecoveryParam (curve, e, signature, Q) { +function calcPubKeyRecoveryParam (e, signature, Q) { typeforce(types.tuple( - types.ECCurve, types.BigInt, types.ECSignature, types.ECPoint ), arguments) for (var i = 0; i < 4; i++) { - var Qprime = recoverPubKey(curve, e, signature, i) + var Qprime = recoverPubKey(e, signature, i) // 1.6.2 Verify Q if (Qprime.equals(Q)) { @@ -243,5 +242,8 @@ module.exports = { deterministicGenerateK: deterministicGenerateK, recoverPubKey: recoverPubKey, sign: sign, - verify: verify + verify: verify, + + // TODO: remove + __curve: secp256k1 } diff --git a/src/ecpair.js b/src/ecpair.js index 9e8698be0..e469638f4 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -1,7 +1,6 @@ var bcrypto = require('./crypto') var bs58check = require('bs58check') var ecdsa = require('./ecdsa') -var ecurve = require('ecurve') var randomBytes = require('randombytes') var typeforce = require('typeforce') var types = require('./types') @@ -10,7 +9,8 @@ var wif = require('wif') var NETWORKS = require('./networks') var BigInteger = require('bigi') -var secp256k1 = ecurve.getCurveByName('secp256k1') +var ecurve = require('ecurve') +var secp256k1 = ecdsa.__curve function ECPair (d, Q, options) { if (options) { @@ -112,7 +112,7 @@ ECPair.prototype.getPublicKeyBuffer = function () { ECPair.prototype.sign = function (hash) { if (!this.d) throw new Error('Missing private key') - return ecdsa.sign(secp256k1, hash, this.d) + return ecdsa.sign(hash, this.d) } ECPair.prototype.toWIF = function () { @@ -122,7 +122,7 @@ ECPair.prototype.toWIF = function () { } ECPair.prototype.verify = function (hash, signature) { - return ecdsa.verify(secp256k1, hash, signature, this.Q) + return ecdsa.verify(hash, signature, this.Q) } module.exports = ECPair diff --git a/src/hdnode.js b/src/hdnode.js index 4cb117f43..22ccecf96 100644 --- a/src/hdnode.js +++ b/src/hdnode.js @@ -11,6 +11,9 @@ var ECPair = require('./ecpair') var ecurve = require('ecurve') var curve = ecurve.getCurveByName('secp256k1') +var MASTER_SECRET = new Buffer('Bitcoin seed') +var HIGHEST_BIT = 0x80000000 + function HDNode (keyPair, chainCode) { typeforce(types.tuple('ECPair', types.Buffer256bit), arguments) @@ -23,17 +26,13 @@ function HDNode (keyPair, chainCode) { this.parentFingerprint = 0x00000000 } -HDNode.MASTER_SECRET = new Buffer('Bitcoin seed') -HDNode.HIGHEST_BIT = 0x80000000 -HDNode.LENGTH = 78 - HDNode.fromSeedBuffer = function (seed, network) { typeforce(types.tuple(types.Buffer, types.maybe(types.Network)), arguments) if (seed.length < 16) throw new TypeError('Seed should be at least 128 bits') if (seed.length > 64) throw new TypeError('Seed should be at most 512 bits') - var I = createHmac('sha512', HDNode.MASTER_SECRET).update(seed).digest() + var I = createHmac('sha512', MASTER_SECRET).update(seed).digest() var IL = I.slice(0, 32) var IR = I.slice(32) @@ -53,9 +52,9 @@ HDNode.fromSeedHex = function (hex, network) { HDNode.fromBase58 = function (string, networks) { var buffer = base58check.decode(string) - if (buffer.length !== HDNode.LENGTH) throw new Error('Invalid buffer length') + if (buffer.length !== 78) throw new Error('Invalid buffer length') - // 4 byte: version bytes + // 4 bytes: version bytes var version = buffer.readUInt32BE(0) var network @@ -75,7 +74,7 @@ HDNode.fromBase58 = function (string, networks) { version !== network.bip32.public) throw new Error('Invalid network') // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ... - var depth = buffer.readUInt8(4) + var depth = buffer[4] // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key) var parentFingerprint = buffer.readUInt32BE(5) @@ -155,12 +154,11 @@ HDNode.prototype.toBase58 = function (__isPrivate) { // Version var network = this.keyPair.network var version = this.keyPair.d ? network.bip32.private : network.bip32.public - var buffer = new Buffer(HDNode.LENGTH) + var buffer = new Buffer(78) // 4 bytes: version bytes buffer.writeUInt32BE(version, 0) - // Depth // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, .... buffer.writeUInt8(this.depth, 4) @@ -191,7 +189,7 @@ HDNode.prototype.toBase58 = function (__isPrivate) { // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#child-key-derivation-ckd-functions HDNode.prototype.derive = function (index) { - var isHardened = index >= HDNode.HIGHEST_BIT + var isHardened = index >= HIGHEST_BIT var data = new Buffer(37) // Hardened child @@ -263,7 +261,7 @@ HDNode.prototype.derive = function (index) { HDNode.prototype.deriveHardened = function (index) { // Only derives hardened private keys by default - return this.derive(index + HDNode.HIGHEST_BIT) + return this.derive(index + HIGHEST_BIT) } HDNode.prototype.toString = HDNode.prototype.toBase58 diff --git a/src/message.js b/src/message.js index 16fc1fee9..29fe7dc8b 100644 --- a/src/message.js +++ b/src/message.js @@ -7,9 +7,6 @@ var BigInteger = require('bigi') var ECPair = require('./ecpair') var ECSignature = require('./ecsignature') -var ecurve = require('ecurve') -var ecparams = ecurve.getCurveByName('secp256k1') - function magicHash (message, network) { var messagePrefix = new Buffer(network.messagePrefix) var messageBuffer = new Buffer(message) @@ -25,7 +22,7 @@ function sign (keyPair, message, network) { var hash = magicHash(message, network) var signature = keyPair.sign(hash) var e = BigInteger.fromBuffer(hash) - var i = ecdsa.calcPubKeyRecoveryParam(ecparams, e, signature, keyPair.Q) + var i = ecdsa.calcPubKeyRecoveryParam(e, signature, keyPair.Q) return signature.toCompact(i, keyPair.compressed) } @@ -40,7 +37,7 @@ function verify (address, signature, message, network) { var hash = magicHash(message, network) var parsed = ECSignature.parseCompact(signature) var e = BigInteger.fromBuffer(hash) - var Q = ecdsa.recoverPubKey(ecparams, e, parsed.signature, parsed.i) + var Q = ecdsa.recoverPubKey(e, parsed.signature, parsed.i) var keyPair = new ECPair(null, Q, { compressed: parsed.compressed, diff --git a/src/script.js b/src/script.js index b91997f9a..56c75e98d 100644 --- a/src/script.js +++ b/src/script.js @@ -84,7 +84,7 @@ function decompile (buffer) { var i = 0 while (i < buffer.length) { - var opcode = buffer.readUInt8(i) + var opcode = buffer[i] // data chunk if ((opcode > OPS.OP_0) && (opcode <= OPS.OP_PUSHDATA4)) { diff --git a/src/transaction.js b/src/transaction.js index d71784234..3ddf84b4c 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -52,23 +52,12 @@ Transaction.fromBuffer = function (buffer, __noStrict) { var vinLen = readVarInt() for (var i = 0; i < vinLen; ++i) { - var hash = readSlice(32) - - if (Transaction.isCoinbaseHash(hash)) { - tx.ins.push({ - hash: hash, - index: readUInt32(), - script: readScript(), - sequence: readUInt32() - }) - } else { - tx.ins.push({ - hash: hash, - index: readUInt32(), - script: readScript(), - sequence: readUInt32() - }) - } + tx.ins.push({ + hash: readSlice(32), + index: readUInt32(), + script: readScript(), + sequence: readUInt32() + }) } var voutLen = readVarInt() diff --git a/test/ecdsa.js b/test/ecdsa.js index be8345537..db7c8b36d 100644 --- a/test/ecdsa.js +++ b/test/ecdsa.js @@ -10,8 +10,7 @@ var sinon = require('sinon') var BigInteger = require('bigi') var ECSignature = require('../src/ecsignature') -var ecurve = require('ecurve') -var curve = ecurve.getCurveByName('secp256k1') +var curve = ecdsa.__curve var fixtures = require('./fixtures/ecdsa.json') @@ -23,10 +22,10 @@ describe('ecdsa', function () { fixtures.valid.ecdsa.forEach(function (f) { it('for "' + f.message + '"', function () { - var d = BigInteger.fromHex(f.d) + var x = BigInteger.fromHex(f.d).toBuffer(32) var h1 = bcrypto.sha256(f.message) - var k = ecdsa.deterministicGenerateK(curve, h1, d, checkSig) + var k = ecdsa.deterministicGenerateK(h1, x, checkSig) assert.strictEqual(k.toHex(), f.k) }) }) @@ -38,9 +37,9 @@ describe('ecdsa', function () { .onCall(1).returns(curve.n) // > n-1 .onCall(2).returns(new BigInteger('42')) // valid - var d = new BigInteger('1') + var x = new BigInteger('1').toBuffer(32) var h1 = new Buffer(32) - var k = ecdsa.deterministicGenerateK(curve, h1, d, checkSig) + var k = ecdsa.deterministicGenerateK(h1, x, checkSig) assert.strictEqual(k.toString(), '42') })) @@ -58,20 +57,20 @@ describe('ecdsa', function () { checkSig.onCall(0).returns(false) // bad signature checkSig.onCall(1).returns(true) // good signature - var d = new BigInteger('1') + var x = new BigInteger('1').toBuffer(32) var h1 = new Buffer(32) - var k = ecdsa.deterministicGenerateK(curve, h1, d, checkSig) + var k = ecdsa.deterministicGenerateK(h1, x, checkSig) assert.strictEqual(k.toString(), '53') })) fixtures.valid.rfc6979.forEach(function (f) { it('produces the expected k values for ' + f.message + " if k wasn't suitable", function () { - var d = BigInteger.fromHex(f.d) + var x = BigInteger.fromHex(f.d).toBuffer(32) var h1 = bcrypto.sha256(f.message) var results = [] - ecdsa.deterministicGenerateK(curve, h1, d, function (k) { + ecdsa.deterministicGenerateK(h1, x, function (k) { results.push(k) return results.length === 16 @@ -92,7 +91,7 @@ describe('ecdsa', function () { var signature = ECSignature.fromDER(new Buffer(f.signature, 'hex')) var h1 = bcrypto.sha256(f.message) var e = BigInteger.fromBuffer(h1) - var Qprime = ecdsa.recoverPubKey(curve, e, signature, f.i) + var Qprime = ecdsa.recoverPubKey(e, signature, f.i) assert(Qprime.equals(Q)) }) @@ -113,7 +112,7 @@ describe('ecdsa', function () { points.forEach(function (expectedHex, i) { it('recovers an expected point for i of ' + i, function () { - var Qprime = ecdsa.recoverPubKey(curve, e, signature, i) + var Qprime = ecdsa.recoverPubKey(e, signature, i) var QprimeHex = Qprime.getEncoded().toString('hex') assert.strictEqual(QprimeHex, expectedHex) @@ -127,7 +126,7 @@ describe('ecdsa', function () { var signature = new ECSignature(new BigInteger(f.signatureRaw.r, 16), new BigInteger(f.signatureRaw.s, 16)) assert.throws(function () { - ecdsa.recoverPubKey(curve, e, signature, f.i) + ecdsa.recoverPubKey(e, signature, f.i) }, new RegExp(f.exception)) }) }) @@ -138,7 +137,7 @@ describe('ecdsa', function () { 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(curve, hash, d).toDER() + var signature = ecdsa.sign(hash, d).toDER() assert.strictEqual(signature.toString('hex'), f.signature) }) @@ -146,7 +145,7 @@ describe('ecdsa', function () { it('should sign with low S value', function () { var hash = bcrypto.sha256('Vires in numeris') - var sig = ecdsa.sign(curve, hash, BigInteger.ONE) + var sig = ecdsa.sign(hash, BigInteger.ONE) // See BIP62 for more information var N_OVER_TWO = curve.n.shiftRight(1) @@ -162,7 +161,7 @@ describe('ecdsa', function () { var signature = ECSignature.fromDER(new Buffer(f.signature, 'hex')) var Q = curve.G.multiply(d) - assert(ecdsa.verify(curve, H, signature, Q)) + assert(ecdsa.verify(H, signature, Q)) }) }) @@ -180,7 +179,7 @@ describe('ecdsa', function () { var Q = curve.G.multiply(d) - assert.strictEqual(ecdsa.verify(curve, H, signature, Q), false) + assert.strictEqual(ecdsa.verify(H, signature, Q), false) }) }) }) diff --git a/test/hdnode.js b/test/hdnode.js index 3bfed8d24..a14d89fc8 100644 --- a/test/hdnode.js +++ b/test/hdnode.js @@ -193,7 +193,7 @@ describe('HDNode', function () { assert.strictEqual(hd.depth, depth || 0) if (v.hardened) { - assert.strictEqual(hd.index, v.m + HDNode.HIGHEST_BIT) + assert.strictEqual(hd.index, v.m + 0x80000000) } else { assert.strictEqual(hd.index, v.m) }