X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=bip39-standalone.html;h=09634b882b150ab98c796adc8b8901b0ab00186b;hb=81f35b5e6643d9ac046ee8f4a5c3b4308ea03ceb;hp=c04272faf14bbac06e5cf683577fb2defb5cf729;hpb=a3baa26e61a357b96c7b76f50689ff9cd0f75a02;p=perso%2FImmae%2FProjets%2FCryptomonnaies%2FBIP39.git diff --git a/bip39-standalone.html b/bip39-standalone.html index c04272f..09634b8 100644 --- a/bip39-standalone.html +++ b/bip39-standalone.html @@ -11,7 +11,8 @@ - + + @@ -55,36 +118,140 @@

Mnemonic

-
-
-

You can enter an existing BIP39 mnemonic, or generate a new random one. Typing your own twelve words will probably not work how you expect, since the words require a particular structure (the last word is a checksum)

-

For more info see the BIP39 spec

-
- +
- +

You can enter an existing BIP39 mnemonic, or generate a new random one. Typing your own twelve words will probably not work how you expect, since the words require a particular structure (the last word is a checksum).

+

+ For more info see the + BIP39 spec. +

-
- +
+
-
- - - - +
+
+ Generate a random mnemonic, or enter your own below: + + + words +
+
+
+
+ +
+
+
+ +
+
+
- + +
+ +
+
+
+
- + +
+ +
+
+
+
+
@@ -120,11 +287,14 @@
-

For more info see the BIP44 spec

+

+ For more info see the + BIP44 spec. +

@@ -132,7 +302,7 @@
@@ -140,7 +310,7 @@
@@ -148,14 +318,44 @@
- + +
+

The account extended keys can be used for importing to most BIP44 compatible wallets, such as mycelium or electrum.

+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+

The BIP32 derivation path and extended keys are the basis for the derived addresses.

+
+
+
+
@@ -167,29 +367,67 @@
-

For more info see the BIP32 spec

+

+ For more info see the + BIP32 spec +

+
+
+ +
+ +
- +
- +
+ +
+
+ +
+

+ Use path m/0'/0' with hardened addresses. +

+

+ For more info see the + Bitcoin Core BIP32 implementation +

+
+
+
+

- Use path m/0'/0. - For more info see the Hive Wallet homepage + Use path m/0'/0. +

+

+ For more info see + MultiBit HD

- +

- Use path m/44'/0'/0'/0. - For more info see the Mycelium Wallet homepage + Use path m/44'/0'/0'. + Only enter the xpub extended key into block explorer search fields, never the xprv key. +

+

+ Can be used with: + blockchain.info

@@ -198,15 +436,15 @@
- +
- +
- +
- +
@@ -218,71 +456,119 @@

Derived Addresses

-

Note these addreses are derived from the BIP32 Extended Key

+

Note these addreses are derived from the BIP32 Extended Key

+ - - - - - - + + + + + +
- Index   - + Path   + +
+
+
+ Address   +
- Address   - + Public Key   +
- Private Key   - + Private Key   +
   
   
   
   
   
    
    
    
    
    
- Show next + Show more rows: - +
-

More info

-

BIP39 Mnemonic code for generating deterministic keys

-

+

More info

+

BIP39 Mnemonic code for generating deterministic keys

+

Read more at the official BIP39 spec

-

BIP32 Hierarchical Deterministic Wallets

-

+

BIP32 Hierarchical Deterministic Wallets

+

Read more at the official BIP32 spec - and see the demo at +

+

+ See the demo at bip32.org

-

BIP44 Multi-Account Hierarchy for Deterministic Wallets

-

+

BIP44 Multi-Account Hierarchy for Deterministic Wallets

+

Read more at the official BIP44 spec

-

Private Keys

+

Private Keys

+

+ + Use private keys at + brainwallet.org. + + Be careful - it can be easy to make mistakes if you don't know what you're doing. +

+

Entropy

+

+ + Entropy values must be sourced from a + strong source of randomness. + + This means flipping a fair coin, rolling a fair dice, noise measurements etc. + + Do NOT use phrases from books, lyrics from songs, your birthday or steet address, + keyboard mashing, or anything you think is random, because chances are overwhelming it isn't + random enough for the needs of this tool. + +

+

+ Do not store entropy. +

+

+ Storing entropy (such as keeping a deck of cards in a specific shuffled order) is unreliable compared to storing a mnemonic. + Instead of storing entropy, store the mnemonic generated from the entropy. + Steganography may be beneficial when storing the mnemonic. +

+

+ + The random mnemonic generator on this page uses a + cryptographically secure random number generator. + + The built in random generator can generally be trusted more than your own intuition about randomness. + If cryptographic randomness isn't available in your browser, this page will show a warning and the generate button will not work. + In that case you might choose to use your own source of entropy. +

+

+ You are not a good source of entropy. +

+

License

- Use private keys at - brainwallet.org, - but be careful - it can be easy to make mistakes if you - don't know what you're doing + Please refer to the software license for more detail. +

+

The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.

@@ -291,24 +577,24 @@
-

Offline Usage

+

Offline Usage

-

+

You can use this tool without having to be online.

-

+

In your browser, select file save-as, and save this page as a file.

-

+

Double-click that file to open it in a browser on any offline computer.

- Alternatively, download it from - - https://github.com/dcpos/bip39 - + Alternatively, download the file from the repository + - + https://github.com/iancoleman/bip39 +

@@ -318,16 +604,17 @@
-

This project is 100% open-source code

+

This project is 100% open-source code

- Get the source code at - - - https://github.com/dcpos/bip39 + Get the source code from the repository + - + + https://github.com/iancoleman/bip39

-

Libraries

+

Libraries

BitcoinJS - @@ -369,6 +656,15 @@

+ + @@ -376,2340 +672,4210 @@ - - - + + + + + + + - - +// https://tools.ietf.org/html/rfc6979#section-3.2 +function deterministicGenerateK (curve, hash, d, checkSig) { + typeForce('Buffer', hash) + typeForce('BigInteger', d) + + // FIXME: remove/uncomment for 2.0.0 + // typeForce('Function', checkSig) + + if (typeof checkSig !== 'function') { + console.warn('deterministicGenerateK requires a checkSig callback in 2.0.0, see #337 for more information') + + checkSig = function (k) { + var G = curve.G + var n = curve.n + var e = BigInteger.fromBuffer(hash) + + var Q = G.multiply(k) + + if (curve.isInfinity(Q)) + return false + + var r = Q.affineX.mod(n) + if (r.signum() === 0) + return false + + var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n) + if (s.signum() === 0) + return false + + return true + } + } + + // sanity check + assert.equal(hash.length, 32, 'Hash must be 256 bit') + + var x = d.toBuffer(32) + var k = new Buffer(32) + var v = new Buffer(32) + + // Step A, ignored as hash already provided + // Step B + v.fill(1) + + // Step C + k.fill(0) + + // 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(curve.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 +} + +function sign (curve, hash, d) { + var r, s + + var e = BigInteger.fromBuffer(hash) + var n = curve.n + var G = curve.G + + deterministicGenerateK(curve, hash, d, function (k) { + var Q = G.multiply(k) + + if (curve.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 + }) + + 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) + } + + return new ECSignature(r, s) +} + +function verifyRaw (curve, e, signature, Q) { + var n = curve.n + var G = curve.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 + + // c = s^-1 mod n + var c = s.modInverse(n) + + // 1.4.4 Compute u1 = es^−1 mod n + // u2 = rs^−1 mod n + var u1 = e.multiply(c).mod(n) + var u2 = r.multiply(c).mod(n) + + // 1.4.5 Compute R = (xR, yR) = u1G + u2Q + var R = G.multiplyTwo(u1, Q, u2) + var v = R.affineX.mod(n) + + // 1.4.5 (cont.) Enforce R is not at infinity + if (curve.isInfinity(R)) return false + + // 1.4.8 If v = r, output "valid", and if v != r, output "invalid" + return v.equals(r) +} + +function verify (curve, hash, signature, Q) { + // 1.4.2 H = Hash(M), already done by the user + // 1.4.3 e = H + var e = BigInteger.fromBuffer(hash) + + return verifyRaw(curve, e, signature, Q) +} + +/** + * Recover a public key from a signature. + * + * See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public + * Key Recovery Operation". + * + * http://www.secg.org/download/aid-780/sec1-v2.pdf + */ +function recoverPubKey (curve, e, signature, i) { + assert.strictEqual(i & 3, i, 'Recovery param is more than two bits') + + var n = curve.n + var G = curve.G + + var r = signature.r + var s = signature.s + + assert(r.signum() > 0 && r.compareTo(n) < 0, 'Invalid r value') + assert(s.signum() > 0 && s.compareTo(n) < 0, 'Invalid s value') + + // A set LSB signifies that the y-coordinate is odd + var isYOdd = i & 1 + + // The more significant bit specifies whether we should use the + // first or second candidate key. + var isSecondKey = i >> 1 + + // 1.1 Let x = r + jn + var x = isSecondKey ? r.add(n) : r + var R = curve.pointFromX(isYOdd, x) + + // 1.4 Check that nR is at infinity + var nR = R.multiply(n) + assert(curve.isInfinity(nR), 'nR is not a valid curve point') + + // Compute -e from e + var eNeg = e.negate().mod(n) + + // 1.6.1 Compute Q = r^-1 (sR - eG) + // Q = r^-1 (sR + -eG) + var rInv = r.modInverse(n) + + var Q = R.multiplyTwo(s, G, eNeg).multiply(rInv) + curve.validate(Q) + + return Q +} + +/** + * Calculate pubkey extraction parameter. + * + * When extracting a pubkey from a signature, we have to + * distinguish four different cases. Rather than putting this + * burden on the verifier, Bitcoin includes a 2-bit value with the + * signature. + * + * This function simply tries all four cases and returns the value + * that resulted in a successful pubkey recovery. + */ +function calcPubKeyRecoveryParam (curve, e, signature, Q) { + for (var i = 0; i < 4; i++) { + var Qprime = recoverPubKey(curve, e, signature, i) + + // 1.6.2 Verify Q + if (Qprime.equals(Q)) { + return i + } + } + + throw new Error('Unable to find valid recovery factor') +} + +module.exports = { + calcPubKeyRecoveryParam: calcPubKeyRecoveryParam, + deterministicGenerateK: deterministicGenerateK, + recoverPubKey: recoverPubKey, + sign: sign, + verify: verify, + verifyRaw: verifyRaw +} + +}).call(this,require("buffer").Buffer) +},{"./ecsignature":62,"assert":5,"bigi":3,"buffer":7,"create-hmac":45,"typeforce":53}],60:[function(require,module,exports){ +(function (Buffer){ +var assert = require('assert') +var base58check = require('bs58check') +var ecdsa = require('./ecdsa') +var networks = require('./networks') +var randomBytes = require('randombytes') +var typeForce = require('typeforce') + +var BigInteger = require('bigi') +var ECPubKey = require('./ecpubkey') + +var ecurve = require('ecurve') +var secp256k1 = ecurve.getCurveByName('secp256k1') + +function ECKey (d, compressed) { + assert(d.signum() > 0, 'Private key must be greater than 0') + assert(d.compareTo(ECKey.curve.n) < 0, 'Private key must be less than the curve order') + + var Q = ECKey.curve.G.multiply(d) + + this.d = d + this.pub = new ECPubKey(Q, compressed) +} + +// Constants +ECKey.curve = secp256k1 + +// Static constructors +ECKey.fromWIF = function (string) { + var payload = base58check.decode(string) + var compressed = false + + // Ignore the version byte + payload = payload.slice(1) + + if (payload.length === 33) { + assert.strictEqual(payload[32], 0x01, 'Invalid compression flag') + + // Truncate the compression flag + payload = payload.slice(0, -1) + compressed = true + } + + assert.equal(payload.length, 32, 'Invalid WIF payload length') + + var d = BigInteger.fromBuffer(payload) + return new ECKey(d, compressed) +} + +ECKey.makeRandom = function (compressed, rng) { + rng = 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(ECKey.curve.n) + + return new ECKey(d, compressed) +} + +// Export functions +ECKey.prototype.toWIF = function (network) { + network = network || networks.bitcoin + + var bufferLen = this.pub.compressed ? 34 : 33 + var buffer = new Buffer(bufferLen) + + buffer.writeUInt8(network.wif, 0) + this.d.toBuffer(32).copy(buffer, 1) + + if (this.pub.compressed) { + buffer.writeUInt8(0x01, 33) + } + + return base58check.encode(buffer) +} + +// Operations +ECKey.prototype.sign = function (hash) { + return ecdsa.sign(ECKey.curve, hash, this.d) +} + +module.exports = ECKey + +}).call(this,require("buffer").Buffer) +},{"./ecdsa":59,"./ecpubkey":61,"./networks":66,"assert":5,"bigi":3,"bs58check":31,"buffer":7,"ecurve":49,"randombytes":52,"typeforce":53}],61:[function(require,module,exports){ +(function (Buffer){ +var crypto = require('./crypto') +var ecdsa = require('./ecdsa') +var typeForce = require('typeforce') +var networks = require('./networks') + +var Address = require('./address') + +var ecurve = require('ecurve') +var secp256k1 = ecurve.getCurveByName('secp256k1') + +function ECPubKey (Q, compressed) { + if (compressed === undefined) { + compressed = true + } + + typeForce('Point', Q) + typeForce('Boolean', compressed) + + this.compressed = compressed + this.Q = Q +} + +// Constants +ECPubKey.curve = secp256k1 + +// Static constructors +ECPubKey.fromBuffer = function (buffer) { + var Q = ecurve.Point.decodeFrom(ECPubKey.curve, buffer) + return new ECPubKey(Q, Q.compressed) +} + +ECPubKey.fromHex = function (hex) { + return ECPubKey.fromBuffer(new Buffer(hex, 'hex')) +} + +// Operations +ECPubKey.prototype.getAddress = function (network) { + network = network || networks.bitcoin + + return new Address(crypto.hash160(this.toBuffer()), network.pubKeyHash) +} + +ECPubKey.prototype.verify = function (hash, signature) { + return ecdsa.verify(ECPubKey.curve, hash, signature, this.Q) +} + +// Export functions +ECPubKey.prototype.toBuffer = function () { + return this.Q.getEncoded(this.compressed) +} + +ECPubKey.prototype.toHex = function () { + return this.toBuffer().toString('hex') +} + +module.exports = ECPubKey + +}).call(this,require("buffer").Buffer) +},{"./address":54,"./crypto":58,"./ecdsa":59,"./networks":66,"buffer":7,"ecurve":49,"typeforce":53}],62:[function(require,module,exports){ +(function (Buffer){ +var assert = require('assert') +var typeForce = require('typeforce') + +var BigInteger = require('bigi') + +function ECSignature (r, s) { + typeForce('BigInteger', r) + typeForce('BigInteger', s) + + this.r = r + this.s = s +} + +ECSignature.parseCompact = function (buffer) { + assert.equal(buffer.length, 65, 'Invalid signature length') + var i = buffer.readUInt8(0) - 27 + + // At most 3 bits + assert.equal(i, i & 7, 'Invalid signature parameter') + var compressed = !!(i & 4) + + // Recovery param only + i = i & 3 + + var r = BigInteger.fromBuffer(buffer.slice(1, 33)) + var s = BigInteger.fromBuffer(buffer.slice(33)) + + return { + compressed: compressed, + i: i, + signature: new ECSignature(r, s) + } +} + +ECSignature.fromDER = function (buffer) { + assert.equal(buffer.readUInt8(0), 0x30, 'Not a DER sequence') + assert.equal(buffer.readUInt8(1), buffer.length - 2, 'Invalid sequence length') + assert.equal(buffer.readUInt8(2), 0x02, 'Expected a DER integer') + + var rLen = buffer.readUInt8(3) + assert(rLen > 0, 'R length is zero') + + var offset = 4 + rLen + assert.equal(buffer.readUInt8(offset), 0x02, 'Expected a DER integer (2)') + + var sLen = buffer.readUInt8(offset + 1) + assert(sLen > 0, 'S length is zero') + + var rB = buffer.slice(4, offset) + var sB = buffer.slice(offset + 2) + offset += 2 + sLen + + if (rLen > 1 && rB.readUInt8(0) === 0x00) { + assert(rB.readUInt8(1) & 0x80, 'R value excessively padded') + } + + if (sLen > 1 && sB.readUInt8(0) === 0x00) { + assert(sB.readUInt8(1) & 0x80, 'S value excessively padded') + } + + assert.equal(offset, buffer.length, 'Invalid DER encoding') + var r = BigInteger.fromDERInteger(rB) + var s = BigInteger.fromDERInteger(sB) + + assert(r.signum() >= 0, 'R value is negative') + assert(s.signum() >= 0, 'S value is negative') + + return new ECSignature(r, s) +} + +// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) +ECSignature.parseScriptSignature = function (buffer) { + var hashType = buffer.readUInt8(buffer.length - 1) + var hashTypeMod = hashType & ~0x80 + + assert(hashTypeMod > 0x00 && hashTypeMod < 0x04, 'Invalid hashType ' + hashType) + + return { + signature: ECSignature.fromDER(buffer.slice(0, -1)), + hashType: hashType + } +} + +ECSignature.prototype.toCompact = function (i, compressed) { + if (compressed) { + i += 4 + } + + i += 27 + + var buffer = new Buffer(65) + buffer.writeUInt8(i, 0) + + this.r.toBuffer(32).copy(buffer, 1) + this.s.toBuffer(32).copy(buffer, 33) + + return buffer +} + +ECSignature.prototype.toDER = function () { + var rBa = this.r.toDERInteger() + var sBa = this.s.toDERInteger() + + var sequence = [] + + // INTEGER + sequence.push(0x02, rBa.length) + sequence = sequence.concat(rBa) + + // INTEGER + sequence.push(0x02, sBa.length) + sequence = sequence.concat(sBa) + + // SEQUENCE + sequence.unshift(0x30, sequence.length) + + return new Buffer(sequence) +} + +ECSignature.prototype.toScriptSignature = function (hashType) { + var hashTypeMod = hashType & ~0x80 + assert(hashTypeMod > 0x00 && hashTypeMod < 0x04, 'Invalid hashType ' + hashType) + + var hashTypeBuffer = new Buffer(1) + hashTypeBuffer.writeUInt8(hashType, 0) + + return Buffer.concat([this.toDER(), hashTypeBuffer]) +} + +module.exports = ECSignature + +}).call(this,require("buffer").Buffer) +},{"assert":5,"bigi":3,"buffer":7,"typeforce":53}],63:[function(require,module,exports){ +(function (Buffer){ +var assert = require('assert') +var base58check = require('bs58check') +var bcrypto = require('./crypto') +var createHmac = require('create-hmac') +var typeForce = require('typeforce') +var networks = require('./networks') + +var BigInteger = require('bigi') +var ECKey = require('./eckey') +var ECPubKey = require('./ecpubkey') + +var ecurve = require('ecurve') +var curve = ecurve.getCurveByName('secp256k1') + +function findBIP32NetworkByVersion (version) { + for (var name in networks) { + var network = networks[name] + + if (version === network.bip32.private || version === network.bip32.public) { + return network + } + } + + assert(false, 'Could not find network for ' + version.toString(16)) +} + +function HDNode (K, chainCode, network) { + network = network || networks.bitcoin + + typeForce('Buffer', chainCode) + + assert.equal(chainCode.length, 32, 'Expected chainCode length of 32, got ' + chainCode.length) + assert(network.bip32, 'Unknown BIP32 constants for network') + + 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 + this.pubKey = K.pub + } 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') +HDNode.HIGHEST_BIT = 0x80000000 +HDNode.LENGTH = 78 + +HDNode.fromSeedBuffer = function (seed, network) { + typeForce('Buffer', seed) + + assert(seed.length >= 16, 'Seed should be at least 128 bits') + assert(seed.length <= 64, 'Seed should be at most 512 bits') + + var I = createHmac('sha512', HDNode.MASTER_SECRET).update(seed).digest() + var IL = I.slice(0, 32) + 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 + var pIL = BigInteger.fromBuffer(IL) + + return new HDNode(pIL, IR, network) +} + +HDNode.fromSeedHex = function (hex, network) { + return HDNode.fromSeedBuffer(new Buffer(hex, 'hex'), network) +} + +HDNode.fromBase58 = function (string, network) { + return HDNode.fromBuffer(base58check.decode(string), network, true) +} + +// FIXME: remove in 2.x.y +HDNode.fromBuffer = function (buffer, network, __ignoreDeprecation) { + if (!__ignoreDeprecation) { + console.warn('HDNode.fromBuffer() is deprecated for removal in 2.x.y, use fromBase58 instead') + } + + assert.strictEqual(buffer.length, HDNode.LENGTH, 'Invalid buffer length') + + // 4 byte: version bytes + var version = buffer.readUInt32BE(0) + + if (network) { + assert(version === network.bip32.private || version === network.bip32.public, "Network doesn't match") + + // auto-detect + } else { + network = findBIP32NetworkByVersion(version) + } + + // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ... + var depth = buffer.readUInt8(4) + + // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key) + var parentFingerprint = buffer.readUInt32BE(5) + if (depth === 0) { + assert.strictEqual(parentFingerprint, 0x00000000, 'Invalid parent fingerprint') + } + + // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized. + // This is encoded in MSB order. (0x00000000 if master key) + var index = buffer.readUInt32BE(9) + assert(depth > 0 || index === 0, 'Invalid index') + + // 32 bytes: the chain code + var chainCode = buffer.slice(13, 45) + var data, hd + + // 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) + + // 33 bytes: public key data (0x02 + X or 0x03 + X) + } else { + data = buffer.slice(45, 78) + var Q = ecurve.Point.decodeFrom(curve, data) + assert.equal(Q.compressed, true, 'Invalid public key') + + // Verify that the X coordinate in the public point corresponds to a point on the curve. + // If not, the extended public key is invalid. + curve.validate(Q) + + hd = new HDNode(Q, chainCode, network) + } + + hd.depth = depth + hd.index = index + hd.parentFingerprint = parentFingerprint + + return hd +} + +// FIXME: remove in 2.x.y +HDNode.fromHex = function (hex, network) { + return HDNode.fromBuffer(new Buffer(hex, 'hex'), network) +} + +HDNode.prototype.getIdentifier = function () { + return bcrypto.hash160(this.pubKey.toBuffer()) +} + +HDNode.prototype.getFingerprint = function () { + return this.getIdentifier().slice(0, 4) +} + +HDNode.prototype.getAddress = function () { + return this.pubKey.getAddress(this.network) +} + +HDNode.prototype.neutered = function () { + var neutered = new HDNode(this.pubKey.Q, this.chainCode, this.network) + neutered.depth = this.depth + neutered.index = this.index + neutered.parentFingerprint = this.parentFingerprint + + return neutered +} + +HDNode.prototype.toBase58 = function (isPrivate) { + return base58check.encode(this.toBuffer(isPrivate, true)) +} + +// FIXME: remove in 2.x.y +HDNode.prototype.toBuffer = function (isPrivate, __ignoreDeprecation) { + if (isPrivate === undefined) { + isPrivate = !!this.privKey + + // FIXME: remove in 2.x.y + } else { + console.warn('isPrivate flag is deprecated, please use the .neutered() method instead') + } + + if (!__ignoreDeprecation) { + console.warn('HDNode.toBuffer() is deprecated for removal in 2.x.y, use toBase58 instead') + } + + // Version + var version = isPrivate ? this.network.bip32.private : this.network.bip32.public + var buffer = new Buffer(HDNode.LENGTH) + + // 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) + + // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key) + buffer.writeUInt32BE(this.parentFingerprint, 5) + + // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized. + // This is encoded in Big endian. (0x00000000 if master key) + buffer.writeUInt32BE(this.index, 9) + + // 32 bytes: the chain code + this.chainCode.copy(buffer, 13) + + // 33 bytes: the public key or private key data + if (isPrivate) { + // FIXME: remove in 2.x.y + assert(this.privKey, 'Missing private key') + + // 0x00 + k for private keys + buffer.writeUInt8(0, 45) + this.privKey.d.toBuffer(32).copy(buffer, 46) + } else { + // X9.62 encoding for public keys + this.pubKey.toBuffer().copy(buffer, 45) + } + + return buffer +} + +// FIXME: remove in 2.x.y +HDNode.prototype.toHex = function (isPrivate) { + return this.toBuffer(isPrivate).toString('hex') +} + +// 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 indexBuffer = new Buffer(4) + indexBuffer.writeUInt32BE(index, 0) + + var data + + // Hardened child + if (isHardened) { + assert(this.privKey, 'Could not derive hardened child key') + + // data = 0x00 || ser256(kpar) || ser32(index) + data = Buffer.concat([ + this.privKey.d.toBuffer(33), + indexBuffer + ]) + + // Normal child + } else { + // data = serP(point(kpar)) || ser32(index) + // = serP(Kpar) || ser32(index) + data = Buffer.concat([ + this.pubKey.toBuffer(), + indexBuffer + ]) + } + + var I = createHmac('sha512', this.chainCode).update(data).digest() + var IL = I.slice(0, 32) + var IR = I.slice(32) + + var pIL = BigInteger.fromBuffer(IL) + + // In case parse256(IL) >= n, proceed with the next value for i + if (pIL.compareTo(curve.n) >= 0) { + return this.derive(index + 1) + } + + // Private parent key -> private child key + var hd + if (this.privKey) { + // ki = parse256(IL) + kpar (mod n) + var ki = pIL.add(this.privKey.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) + + // 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) + + // 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) + } + + hd.depth = this.depth + 1 + hd.index = index + hd.parentFingerprint = this.getFingerprint().readUInt32BE(0) + + return hd +} + +HDNode.prototype.deriveHardened = function (index) { + // Only derives hardened private keys by default + return this.derive(index + HDNode.HIGHEST_BIT) +} + +HDNode.prototype.toString = HDNode.prototype.toBase58 + +module.exports = HDNode + +}).call(this,require("buffer").Buffer) +},{"./crypto":58,"./eckey":60,"./ecpubkey":61,"./networks":66,"assert":5,"bigi":3,"bs58check":31,"buffer":7,"create-hmac":45,"ecurve":49,"typeforce":53}],64:[function(require,module,exports){ +module.exports = { + Address: require('./address'), + base58check: require('./base58check'), + Block: require('./block'), + bufferutils: require('./bufferutils'), + crypto: require('./crypto'), + ecdsa: require('./ecdsa'), + ECKey: require('./eckey'), + ECPubKey: require('./ecpubkey'), + ECSignature: require('./ecsignature'), + Message: require('./message'), + opcodes: require('./opcodes'), + HDNode: require('./hdnode'), + Script: require('./script'), + scripts: require('./scripts'), + Transaction: require('./transaction'), + TransactionBuilder: require('./transaction_builder'), + networks: require('./networks'), + Wallet: require('./wallet') +} + +},{"./address":54,"./base58check":55,"./block":56,"./bufferutils":57,"./crypto":58,"./ecdsa":59,"./eckey":60,"./ecpubkey":61,"./ecsignature":62,"./hdnode":63,"./message":65,"./networks":66,"./opcodes":67,"./script":68,"./scripts":69,"./transaction":70,"./transaction_builder":71,"./wallet":72}],65:[function(require,module,exports){ +(function (Buffer){ +var bufferutils = require('./bufferutils') +var crypto = require('./crypto') +var ecdsa = require('./ecdsa') +var networks = require('./networks') + +var BigInteger = require('bigi') +var ECPubKey = require('./ecpubkey') +var ECSignature = require('./ecsignature') + +var ecurve = require('ecurve') +var ecparams = ecurve.getCurveByName('secp256k1') + +function magicHash (message, network) { + var magicPrefix = new Buffer(network.magicPrefix) + var messageBuffer = new Buffer(message) + var lengthBuffer = bufferutils.varIntBuffer(messageBuffer.length) + + var buffer = Buffer.concat([magicPrefix, lengthBuffer, messageBuffer]) + return crypto.hash256(buffer) +} + +function sign (privKey, message, network) { + network = network || networks.bitcoin + + var hash = magicHash(message, network) + var signature = privKey.sign(hash) + var e = BigInteger.fromBuffer(hash) + var i = ecdsa.calcPubKeyRecoveryParam(ecparams, e, signature, privKey.pub.Q) + + return signature.toCompact(i, privKey.pub.compressed) +} + +// TODO: network could be implied from address +function verify (address, signature, message, network) { + if (!Buffer.isBuffer(signature)) { + signature = new Buffer(signature, 'base64') + } + + network = network || networks.bitcoin + + 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 pubKey = new ECPubKey(Q, parsed.compressed) + return pubKey.getAddress(network).toString() === address.toString() +} + +module.exports = { + magicHash: magicHash, + sign: sign, + verify: verify +} + +}).call(this,require("buffer").Buffer) +},{"./bufferutils":57,"./crypto":58,"./ecdsa":59,"./ecpubkey":61,"./ecsignature":62,"./networks":66,"bigi":3,"buffer":7,"ecurve":49}],66:[function(require,module,exports){ +// https://en.bitcoin.it/wiki/List_of_address_prefixes +// Dogecoin BIP32 is a proposed standard: https://bitcointalk.org/index.php?topic=409731 + +var networks = { + bitcoin: { + magicPrefix: '\x18Bitcoin Signed Message:\n', + bip32: { + public: 0x0488b21e, + private: 0x0488ade4 + }, + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80, + dustThreshold: 546, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162 + feePerKb: 10000, // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/main.cpp#L53 + estimateFee: estimateFee('bitcoin') + }, + testnet: { + magicPrefix: '\x18Bitcoin Signed Message:\n', + bip32: { + public: 0x043587cf, + private: 0x04358394 + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef, + dustThreshold: 546, + feePerKb: 10000, + estimateFee: estimateFee('testnet') + }, + litecoin: { + magicPrefix: '\x19Litecoin Signed Message:\n', + bip32: { + public: 0x019da462, + private: 0x019d9cfe + }, + pubKeyHash: 0x30, + scriptHash: 0x05, + wif: 0xb0, + dustThreshold: 0, // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L360-L365 + dustSoftThreshold: 100000, // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.h#L53 + feePerKb: 100000, // https://github.com/litecoin-project/litecoin/blob/v0.8.7.2/src/main.cpp#L56 + estimateFee: estimateFee('litecoin') + }, + dogecoin: { + magicPrefix: '\x19Dogecoin Signed Message:\n', + bip32: { + public: 0x02facafd, + private: 0x02fac398 + }, + pubKeyHash: 0x1e, + scriptHash: 0x16, + wif: 0x9e, + dustThreshold: 0, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/core.h#L155-L160 + dustSoftThreshold: 100000000, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.h#L62 + feePerKb: 100000000, // https://github.com/dogecoin/dogecoin/blob/v1.7.1/src/main.cpp#L58 + estimateFee: estimateFee('dogecoin') + }, + viacoin: { + magicPrefix: '\x18Viacoin Signed Message:\n', + bip32: { + public: 0x0488b21e, + private: 0x0488ade4 + }, + pubKeyHash: 0x47, + scriptHash: 0x21, + wif: 0xc7, + dustThreshold: 560, + dustSoftThreshold: 100000, + feePerKb: 100000, // + estimateFee: estimateFee('viacoin') + }, + viacointestnet: { + magicPrefix: '\x18Viacoin Signed Message:\n', + bip32: { + public: 0x043587cf, + private: 0x04358394 + }, + pubKeyHash: 0x7f, + scriptHash: 0xc4, + wif: 0xff, + dustThreshold: 560, + dustSoftThreshold: 100000, + feePerKb: 100000, + estimateFee: estimateFee('viacointestnet') + }, + gamerscoin: { + magicPrefix: '\x19Gamerscoin Signed Message:\n', + bip32: { + public: 0x019da462, + private: 0x019d9cfe + }, + pubKeyHash: 0x26, + scriptHash: 0x05, + wif: 0xA6, + dustThreshold: 0, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L358-L363 + dustSoftThreshold: 100000, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L51 + feePerKb: 100000, // https://github.com/gamers-coin/gamers-coinv3/blob/master/src/main.cpp#L54 + estimateFee: estimateFee('gamerscoin') + }, + jumbucks: { + magicPrefix: '\x19Jumbucks Signed Message:\n', + bip32: { + public: 0x037a689a, + private: 0x037a6460 + }, + pubKeyHash: 0x2b, + scriptHash: 0x05, + wif: 0xab, + dustThreshold: 0, + dustSoftThreshold: 10000, + feePerKb: 10000, + estimateFee: estimateFee('jumbucks') + }, + zetacoin: { + magicPrefix: '\x18Zetacoin Signed Message:\n', + bip32: { + public: 0x0488b21e, + private: 0x0488ade4 + }, + pubKeyHash: 0x50, + scriptHash: 0x09, + wif: 0xe0, + dustThreshold: 546, // https://github.com/zetacoin/zetacoin/blob/master/src/core.h#L159 + feePerKb: 10000, // https://github.com/zetacoin/zetacoin/blob/master/src/main.cpp#L54 + estimateFee: estimateFee('zetacoin') + } +} + +function estimateFee (type) { + return function (tx) { + var network = networks[type] + var baseFee = network.feePerKb + var byteSize = tx.toBuffer().length + + var fee = baseFee * Math.ceil(byteSize / 1000) + if (network.dustSoftThreshold === undefined) return fee + + tx.outs.forEach(function (e) { + if (e.value < network.dustSoftThreshold) { + fee += baseFee + } + }) + + return fee + } +} + +module.exports = networks + +},{}],67:[function(require,module,exports){ +module.exports = { + // push value + OP_FALSE: 0, + OP_0: 0, + OP_PUSHDATA1: 76, + OP_PUSHDATA2: 77, + OP_PUSHDATA4: 78, + OP_1NEGATE: 79, + OP_RESERVED: 80, + OP_1: 81, + OP_TRUE: 81, + OP_2: 82, + OP_3: 83, + OP_4: 84, + OP_5: 85, + OP_6: 86, + OP_7: 87, + OP_8: 88, + OP_9: 89, + OP_10: 90, + OP_11: 91, + OP_12: 92, + OP_13: 93, + OP_14: 94, + OP_15: 95, + OP_16: 96, + + // control + OP_NOP: 97, + OP_VER: 98, + OP_IF: 99, + OP_NOTIF: 100, + OP_VERIF: 101, + OP_VERNOTIF: 102, + OP_ELSE: 103, + OP_ENDIF: 104, + OP_VERIFY: 105, + OP_RETURN: 106, + + // stack ops + OP_TOALTSTACK: 107, + OP_FROMALTSTACK: 108, + OP_2DROP: 109, + OP_2DUP: 110, + OP_3DUP: 111, + OP_2OVER: 112, + OP_2ROT: 113, + OP_2SWAP: 114, + OP_IFDUP: 115, + OP_DEPTH: 116, + OP_DROP: 117, + OP_DUP: 118, + OP_NIP: 119, + OP_OVER: 120, + OP_PICK: 121, + OP_ROLL: 122, + OP_ROT: 123, + OP_SWAP: 124, + OP_TUCK: 125, + + // splice ops + OP_CAT: 126, + OP_SUBSTR: 127, + OP_LEFT: 128, + OP_RIGHT: 129, + OP_SIZE: 130, + + // bit logic + OP_INVERT: 131, + OP_AND: 132, + OP_OR: 133, + OP_XOR: 134, + OP_EQUAL: 135, + OP_EQUALVERIFY: 136, + OP_RESERVED1: 137, + OP_RESERVED2: 138, + + // numeric + OP_1ADD: 139, + OP_1SUB: 140, + OP_2MUL: 141, + OP_2DIV: 142, + OP_NEGATE: 143, + OP_ABS: 144, + OP_NOT: 145, + OP_0NOTEQUAL: 146, + + OP_ADD: 147, + OP_SUB: 148, + OP_MUL: 149, + OP_DIV: 150, + OP_MOD: 151, + OP_LSHIFT: 152, + OP_RSHIFT: 153, + + OP_BOOLAND: 154, + OP_BOOLOR: 155, + OP_NUMEQUAL: 156, + OP_NUMEQUALVERIFY: 157, + OP_NUMNOTEQUAL: 158, + OP_LESSTHAN: 159, + OP_GREATERTHAN: 160, + OP_LESSTHANOREQUAL: 161, + OP_GREATERTHANOREQUAL: 162, + OP_MIN: 163, + OP_MAX: 164, + + OP_WITHIN: 165, + + // crypto + OP_RIPEMD160: 166, + OP_SHA1: 167, + OP_SHA256: 168, + OP_HASH160: 169, + OP_HASH256: 170, + OP_CODESEPARATOR: 171, + OP_CHECKSIG: 172, + OP_CHECKSIGVERIFY: 173, + OP_CHECKMULTISIG: 174, + OP_CHECKMULTISIGVERIFY: 175, + + // expansion + OP_NOP1: 176, + OP_NOP2: 177, + OP_NOP3: 178, + OP_NOP4: 179, + OP_NOP5: 180, + OP_NOP6: 181, + OP_NOP7: 182, + OP_NOP8: 183, + OP_NOP9: 184, + OP_NOP10: 185, + + // template matching params + OP_PUBKEYHASH: 253, + OP_PUBKEY: 254, + OP_INVALIDOPCODE: 255 +} + +},{}],68:[function(require,module,exports){ +(function (Buffer){ +var assert = require('assert') +var bufferutils = require('./bufferutils') +var crypto = require('./crypto') +var typeForce = require('typeforce') +var opcodes = require('./opcodes') + +function Script (buffer, chunks) { + typeForce('Buffer', buffer) + typeForce('Array', chunks) + + this.buffer = buffer + this.chunks = chunks +} + +Script.fromASM = function (asm) { + var strChunks = asm.split(' ') + var chunks = strChunks.map(function (strChunk) { + // opcode + if (strChunk in opcodes) { + return opcodes[strChunk] + + // data chunk + } else { + return new Buffer(strChunk, 'hex') + } + }) + + return Script.fromChunks(chunks) +} + +Script.fromBuffer = function (buffer) { + var chunks = [] + var i = 0 + + while (i < buffer.length) { + var opcode = buffer.readUInt8(i) + + // data chunk + if ((opcode > opcodes.OP_0) && (opcode <= opcodes.OP_PUSHDATA4)) { + var d = bufferutils.readPushDataInt(buffer, i) + + // did reading a pushDataInt fail? return non-chunked script + if (d === null) return new Script(buffer, []) + i += d.size + + // attempt to read too much data? + if (i + d.number > buffer.length) return new Script(buffer, []) + + var data = buffer.slice(i, i + d.number) + i += d.number + + chunks.push(data) + + // opcode + } else { + chunks.push(opcode) + + i += 1 + } + } + + return new Script(buffer, chunks) +} + +Script.fromChunks = function (chunks) { + typeForce('Array', chunks) + + var bufferSize = chunks.reduce(function (accum, chunk) { + // data chunk + if (Buffer.isBuffer(chunk)) { + return accum + bufferutils.pushDataSize(chunk.length) + chunk.length + } + + // opcode + return accum + 1 + }, 0.0) + + var buffer = new Buffer(bufferSize) + var offset = 0 + + chunks.forEach(function (chunk) { + // data chunk + if (Buffer.isBuffer(chunk)) { + offset += bufferutils.writePushDataInt(buffer, chunk.length, offset) + + chunk.copy(buffer, offset) + offset += chunk.length + + // opcode + } else { + buffer.writeUInt8(chunk, offset) + offset += 1 + } + }) + + assert.equal(offset, buffer.length, 'Could not decode chunks') + return new Script(buffer, chunks) +} + +Script.fromHex = function (hex) { + return Script.fromBuffer(new Buffer(hex, 'hex')) +} + +Script.EMPTY = Script.fromChunks([]) + +Script.prototype.getHash = function () { + return crypto.hash160(this.buffer) +} + +// FIXME: doesn't work for data chunks, maybe time to use buffertools.compare... +Script.prototype.without = function (needle) { + return Script.fromChunks(this.chunks.filter(function (op) { + return op !== needle + })) +} + +var reverseOps = [] +for (var op in opcodes) { + var code = opcodes[op] + reverseOps[code] = op +} + +Script.prototype.toASM = function () { + return this.chunks.map(function (chunk) { + // data chunk + if (Buffer.isBuffer(chunk)) { + return chunk.toString('hex') + + // opcode + } else { + return reverseOps[chunk] + } + }).join(' ') +} + +Script.prototype.toBuffer = function () { + return this.buffer +} + +Script.prototype.toHex = function () { + return this.toBuffer().toString('hex') +} + +module.exports = Script + +}).call(this,require("buffer").Buffer) +},{"./bufferutils":57,"./crypto":58,"./opcodes":67,"assert":5,"buffer":7,"typeforce":53}],69:[function(require,module,exports){ +(function (Buffer){ +var assert = require('assert') +var ops = require('./opcodes') +var typeForce = require('typeforce') + +var ecurve = require('ecurve') +var curve = ecurve.getCurveByName('secp256k1') + +var ECSignature = require('./ecsignature') +var Script = require('./script') + +function isCanonicalPubKey (buffer) { + if (!Buffer.isBuffer(buffer)) return false + + try { + ecurve.Point.decodeFrom(curve, buffer) + } catch (e) { + if (!(e.message.match(/Invalid sequence (length|tag)/))) + throw e + + return false + } + + return true +} + +function isCanonicalSignature (buffer) { + if (!Buffer.isBuffer(buffer)) return false + + try { + ECSignature.parseScriptSignature(buffer) + } catch (e) { + if (!(e.message.match(/Not a DER sequence|Invalid sequence length|Expected a DER integer|R length is zero|S length is zero|R value excessively padded|S value excessively padded|R value is negative|S value is negative|Invalid hashType/))) { + throw e + } + + return false + } + + return true +} + +function isPubKeyHashInput (script) { + return script.chunks.length === 2 && + isCanonicalSignature(script.chunks[0]) && + isCanonicalPubKey(script.chunks[1]) +} + +function isPubKeyHashOutput (script) { + return script.chunks.length === 5 && + script.chunks[0] === ops.OP_DUP && + script.chunks[1] === ops.OP_HASH160 && + Buffer.isBuffer(script.chunks[2]) && + script.chunks[2].length === 20 && + script.chunks[3] === ops.OP_EQUALVERIFY && + script.chunks[4] === ops.OP_CHECKSIG +} + +function isPubKeyInput (script) { + return script.chunks.length === 1 && + isCanonicalSignature(script.chunks[0]) +} + +function isPubKeyOutput (script) { + return script.chunks.length === 2 && + isCanonicalPubKey(script.chunks[0]) && + script.chunks[1] === ops.OP_CHECKSIG +} + +function isScriptHashInput (script, allowIncomplete) { + if (script.chunks.length < 2) return false + + var lastChunk = script.chunks[script.chunks.length - 1] + if (!Buffer.isBuffer(lastChunk)) return false + + var scriptSig = Script.fromChunks(script.chunks.slice(0, -1)) + var redeemScript = Script.fromBuffer(lastChunk) + + // is redeemScript a valid script? + if (redeemScript.chunks.length === 0) return false + + return classifyInput(scriptSig, allowIncomplete) === classifyOutput(redeemScript) +} + +function isScriptHashOutput (script) { + return script.chunks.length === 3 && + script.chunks[0] === ops.OP_HASH160 && + Buffer.isBuffer(script.chunks[1]) && + script.chunks[1].length === 20 && + script.chunks[2] === ops.OP_EQUAL +} + +// allowIncomplete is to account for combining signatures +// See https://github.com/bitcoin/bitcoin/blob/f425050546644a36b0b8e0eb2f6934a3e0f6f80f/src/script/sign.cpp#L195-L197 +function isMultisigInput (script, allowIncomplete) { + if (script.chunks.length < 2) return false + if (script.chunks[0] !== ops.OP_0) return false + + if (allowIncomplete) { + return script.chunks.slice(1).every(function (chunk) { + return chunk === ops.OP_0 || isCanonicalSignature(chunk) + }) + } + + return script.chunks.slice(1).every(isCanonicalSignature) +} + +function isMultisigOutput (script) { + if (script.chunks.length < 4) return false + if (script.chunks[script.chunks.length - 1] !== ops.OP_CHECKMULTISIG) return false + + var mOp = script.chunks[0] + if (mOp === ops.OP_0) return false + if (mOp < ops.OP_1) return false + if (mOp > ops.OP_16) return false + + var nOp = script.chunks[script.chunks.length - 2] + if (nOp === ops.OP_0) return false + if (nOp < ops.OP_1) return false + if (nOp > ops.OP_16) return false + + var m = mOp - (ops.OP_1 - 1) + var n = nOp - (ops.OP_1 - 1) + if (n < m) return false + + var pubKeys = script.chunks.slice(1, -2) + if (n < pubKeys.length) return false + + return pubKeys.every(isCanonicalPubKey) +} + +function isNullDataOutput (script) { + return script.chunks[0] === ops.OP_RETURN +} + +function classifyOutput (script) { + typeForce('Script', script) + + if (isPubKeyHashOutput(script)) { + return 'pubkeyhash' + } else if (isScriptHashOutput(script)) { + return 'scripthash' + } else if (isMultisigOutput(script)) { + return 'multisig' + } else if (isPubKeyOutput(script)) { + return 'pubkey' + } else if (isNullDataOutput(script)) { + return 'nulldata' + } + + return 'nonstandard' +} + +function classifyInput (script, allowIncomplete) { + typeForce('Script', script) + + if (isPubKeyHashInput(script)) { + return 'pubkeyhash' + } else if (isMultisigInput(script, allowIncomplete)) { + return 'multisig' + } else if (isScriptHashInput(script, allowIncomplete)) { + return 'scripthash' + } else if (isPubKeyInput(script)) { + return 'pubkey' + } + + return 'nonstandard' +} + +// Standard Script Templates +// {pubKey} OP_CHECKSIG +function pubKeyOutput (pubKey) { + return Script.fromChunks([ + pubKey.toBuffer(), + ops.OP_CHECKSIG + ]) +} + +// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG +function pubKeyHashOutput (hash) { + typeForce('Buffer', hash) + + return Script.fromChunks([ + ops.OP_DUP, + ops.OP_HASH160, + hash, + ops.OP_EQUALVERIFY, + ops.OP_CHECKSIG + ]) +} + +// OP_HASH160 {scriptHash} OP_EQUAL +function scriptHashOutput (hash) { + typeForce('Buffer', hash) + + return Script.fromChunks([ + ops.OP_HASH160, + hash, + ops.OP_EQUAL + ]) +} + +// m [pubKeys ...] n OP_CHECKMULTISIG +function multisigOutput (m, pubKeys) { + typeForce(['ECPubKey'], pubKeys) + + assert(pubKeys.length >= m, 'Not enough pubKeys provided') + + var pubKeyBuffers = pubKeys.map(function (pubKey) { + return pubKey.toBuffer() + }) + var n = pubKeys.length + + return Script.fromChunks([].concat( + (ops.OP_1 - 1) + m, + pubKeyBuffers, + (ops.OP_1 - 1) + n, + ops.OP_CHECKMULTISIG + )) +} + +// {signature} +function pubKeyInput (signature) { + typeForce('Buffer', signature) + + return Script.fromChunks([signature]) +} + +// {signature} {pubKey} +function pubKeyHashInput (signature, pubKey) { + typeForce('Buffer', signature) + + return Script.fromChunks([signature, pubKey.toBuffer()]) +} + +// {serialized scriptPubKey script} +function scriptHashInput (scriptSig, scriptPubKey) { + return Script.fromChunks([].concat( + scriptSig.chunks, + scriptPubKey.toBuffer() + )) +} + +// OP_0 [signatures ...] +function multisigInput (signatures, scriptPubKey) { + if (scriptPubKey) { + assert(isMultisigOutput(scriptPubKey)) + + var mOp = scriptPubKey.chunks[0] + var nOp = scriptPubKey.chunks[scriptPubKey.chunks.length - 2] + var m = mOp - (ops.OP_1 - 1) + var n = nOp - (ops.OP_1 - 1) + + assert(signatures.length >= m, 'Not enough signatures provided') + assert(signatures.length <= n, 'Too many signatures provided') + } + + return Script.fromChunks([].concat(ops.OP_0, signatures)) +} + +function nullDataOutput (data) { + return Script.fromChunks([ops.OP_RETURN, data]) +} + +module.exports = { + isCanonicalPubKey: isCanonicalPubKey, + isCanonicalSignature: isCanonicalSignature, + isPubKeyHashInput: isPubKeyHashInput, + isPubKeyHashOutput: isPubKeyHashOutput, + isPubKeyInput: isPubKeyInput, + isPubKeyOutput: isPubKeyOutput, + isScriptHashInput: isScriptHashInput, + isScriptHashOutput: isScriptHashOutput, + isMultisigInput: isMultisigInput, + isMultisigOutput: isMultisigOutput, + isNullDataOutput: isNullDataOutput, + classifyOutput: classifyOutput, + classifyInput: classifyInput, + pubKeyOutput: pubKeyOutput, + pubKeyHashOutput: pubKeyHashOutput, + scriptHashOutput: scriptHashOutput, + multisigOutput: multisigOutput, + pubKeyInput: pubKeyInput, + pubKeyHashInput: pubKeyHashInput, + scriptHashInput: scriptHashInput, + multisigInput: multisigInput, + dataOutput: function (data) { + console.warn('dataOutput is deprecated, use nullDataOutput by 2.0.0') + return nullDataOutput(data) + }, + nullDataOutput: nullDataOutput +} + +}).call(this,require("buffer").Buffer) +},{"./ecsignature":62,"./opcodes":67,"./script":68,"assert":5,"buffer":7,"ecurve":49,"typeforce":53}],70:[function(require,module,exports){ +(function (Buffer){ +var assert = require('assert') +var bufferutils = require('./bufferutils') +var crypto = require('./crypto') +var typeForce = require('typeforce') +var opcodes = require('./opcodes') +var scripts = require('./scripts') + +var Address = require('./address') +var ECSignature = require('./ecsignature') +var Script = require('./script') + +function Transaction () { + this.version = 1 + this.locktime = 0 + this.ins = [] + this.outs = [] +} + +Transaction.DEFAULT_SEQUENCE = 0xffffffff +Transaction.SIGHASH_ALL = 0x01 +Transaction.SIGHASH_NONE = 0x02 +Transaction.SIGHASH_SINGLE = 0x03 +Transaction.SIGHASH_ANYONECANPAY = 0x80 + +Transaction.fromBuffer = function (buffer, __disableAssert) { + var offset = 0 + function readSlice (n) { + offset += n + return buffer.slice(offset - n, offset) + } + + function readUInt32 () { + var i = buffer.readUInt32LE(offset) + offset += 4 + return i + } + + function readUInt64 () { + var i = bufferutils.readUInt64LE(buffer, offset) + offset += 8 + return i + } + + function readVarInt () { + var vi = bufferutils.readVarInt(buffer, offset) + offset += vi.size + return vi.number + } + + function readScript () { + return Script.fromBuffer(readSlice(readVarInt())) + } + + function readGenerationScript () { + return new Script(readSlice(readVarInt()), []) + } + + var tx = new Transaction() + tx.version = readUInt32() + + 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: readGenerationScript(), + sequence: readUInt32() + }) + } else { + tx.ins.push({ + hash: hash, + index: readUInt32(), + script: readScript(), + sequence: readUInt32() + }) + } + } + + var voutLen = readVarInt() + for (i = 0; i < voutLen; ++i) { + tx.outs.push({ + value: readUInt64(), + script: readScript() + }) + } + + tx.locktime = readUInt32() + + if (!__disableAssert) { + assert.equal(offset, buffer.length, 'Transaction has unexpected data') + } + + return tx +} + +Transaction.fromHex = function (hex) { + return Transaction.fromBuffer(new Buffer(hex, 'hex')) +} + +Transaction.isCoinbaseHash = function (buffer) { + return Array.prototype.every.call(buffer, function (x) { + return x === 0 + }) +} + +/** + * Create a new txIn. + * + * Can be called with any of: + * + * - A transaction and an index + * - A transaction hash and an index + * + * Note that this method does not sign the created input. + */ +Transaction.prototype.addInput = function (hash, index, sequence, script) { + if (sequence === undefined || sequence === null) { + sequence = Transaction.DEFAULT_SEQUENCE + } + + script = script || Script.EMPTY + + if (typeof hash === 'string') { + // TxId hex is big-endian, we need little-endian + hash = bufferutils.reverse(new Buffer(hash, 'hex')) + } else if (hash instanceof Transaction) { + hash = hash.getHash() + } + + typeForce('Buffer', hash) + typeForce('Number', index) + typeForce('Number', sequence) + typeForce('Script', script) + + assert.equal(hash.length, 32, 'Expected hash length of 32, got ' + hash.length) + + // Add the input and return the input's index + return (this.ins.push({ + hash: hash, + index: index, + script: script, + sequence: sequence + }) - 1) +} + +/** + * Create a new txOut. + * + * Can be called with: + * + * - A base58 address string and a value + * - An Address object and a value + * - A scriptPubKey Script and a value + */ +Transaction.prototype.addOutput = function (scriptPubKey, value) { + // Attempt to get a valid address if it's a base58 address string + if (typeof scriptPubKey === 'string') { + scriptPubKey = Address.fromBase58Check(scriptPubKey) + } + + // Attempt to get a valid script if it's an Address object + if (scriptPubKey instanceof Address) { + scriptPubKey = scriptPubKey.toOutputScript() + } + + typeForce('Script', scriptPubKey) + typeForce('Number', value) + + // Add the output and return the output's index + return (this.outs.push({ + script: scriptPubKey, + value: value + }) - 1) +} + +Transaction.prototype.clone = function () { + var newTx = new Transaction() + newTx.version = this.version + newTx.locktime = this.locktime + + newTx.ins = this.ins.map(function (txIn) { + return { + hash: txIn.hash, + index: txIn.index, + script: txIn.script, + sequence: txIn.sequence + } + }) + + newTx.outs = this.outs.map(function (txOut) { + return { + script: txOut.script, + value: txOut.value + } + }) + + return newTx +} + +/** + * Hash transaction for signing a specific input. + * + * Bitcoin uses a different hash for each signed transaction input. This + * method copies the transaction, makes the necessary changes based on the + * hashType, serializes and finally hashes the result. This hash can then be + * used to sign the transaction input in question. + */ +Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashType) { + // FIXME: remove in 2.x.y + if (arguments[0] instanceof Script) { + console.warn('hashForSignature(prevOutScript, inIndex, ...) has been deprecated. Use hashForSignature(inIndex, prevOutScript, ...)') + + // swap the arguments (must be stored in tmp, arguments is special) + var tmp = arguments[0] + inIndex = arguments[1] + prevOutScript = tmp + } + + typeForce('Number', inIndex) + typeForce('Script', prevOutScript) + typeForce('Number', hashType) + + assert(inIndex >= 0, 'Invalid vin index') + assert(inIndex < this.ins.length, 'Invalid vin index') + + var txTmp = this.clone() + var hashScript = prevOutScript.without(opcodes.OP_CODESEPARATOR) + + // Blank out other inputs' signatures + txTmp.ins.forEach(function (txIn) { + txIn.script = Script.EMPTY + }) + txTmp.ins[inIndex].script = hashScript + + var hashTypeModifier = hashType & 0x1f + + if (hashTypeModifier === Transaction.SIGHASH_NONE) { + assert(false, 'SIGHASH_NONE not yet supported') + } else if (hashTypeModifier === Transaction.SIGHASH_SINGLE) { + assert(false, 'SIGHASH_SINGLE not yet supported') + } + + if (hashType & Transaction.SIGHASH_ANYONECANPAY) { + assert(false, 'SIGHASH_ANYONECANPAY not yet supported') + } + + var hashTypeBuffer = new Buffer(4) + hashTypeBuffer.writeInt32LE(hashType, 0) + + var buffer = Buffer.concat([txTmp.toBuffer(), hashTypeBuffer]) + return crypto.hash256(buffer) +} + +Transaction.prototype.getHash = function () { + return crypto.hash256(this.toBuffer()) +} + +Transaction.prototype.getId = function () { + // TxHash is little-endian, we need big-endian + return bufferutils.reverse(this.getHash()).toString('hex') +} + +Transaction.prototype.toBuffer = function () { + function scriptSize (script) { + var length = script.buffer.length + + return bufferutils.varIntSize(length) + length + } + + var buffer = new Buffer( + 8 + + bufferutils.varIntSize(this.ins.length) + + bufferutils.varIntSize(this.outs.length) + + this.ins.reduce(function (sum, input) { return sum + 40 + scriptSize(input.script) }, 0) + + this.outs.reduce(function (sum, output) { return sum + 8 + scriptSize(output.script) }, 0) + ) + + var offset = 0 + function writeSlice (slice) { + slice.copy(buffer, offset) + offset += slice.length + } + + function writeUInt32 (i) { + buffer.writeUInt32LE(i, offset) + offset += 4 + } + + function writeUInt64 (i) { + bufferutils.writeUInt64LE(buffer, i, offset) + offset += 8 + } + + function writeVarInt (i) { + var n = bufferutils.writeVarInt(buffer, i, offset) + offset += n + } + + writeUInt32(this.version) + writeVarInt(this.ins.length) + + this.ins.forEach(function (txIn) { + writeSlice(txIn.hash) + writeUInt32(txIn.index) + writeVarInt(txIn.script.buffer.length) + writeSlice(txIn.script.buffer) + writeUInt32(txIn.sequence) + }) + + writeVarInt(this.outs.length) + this.outs.forEach(function (txOut) { + writeUInt64(txOut.value) + writeVarInt(txOut.script.buffer.length) + writeSlice(txOut.script.buffer) + }) + + writeUInt32(this.locktime) + + return buffer +} + +Transaction.prototype.toHex = function () { + return this.toBuffer().toString('hex') +} + +Transaction.prototype.setInputScript = function (index, script) { + typeForce('Number', index) + typeForce('Script', script) + + this.ins[index].script = script +} + +// FIXME: remove in 2.x.y +Transaction.prototype.sign = function (index, privKey, hashType) { + console.warn('Transaction.prototype.sign is deprecated. Use TransactionBuilder instead.') + + var prevOutScript = privKey.pub.getAddress().toOutputScript() + var signature = this.signInput(index, prevOutScript, privKey, hashType) + + var scriptSig = scripts.pubKeyHashInput(signature, privKey.pub) + this.setInputScript(index, scriptSig) +} + +// FIXME: remove in 2.x.y +Transaction.prototype.signInput = function (index, prevOutScript, privKey, hashType) { + console.warn('Transaction.prototype.signInput is deprecated. Use TransactionBuilder instead.') + + hashType = hashType || Transaction.SIGHASH_ALL + + var hash = this.hashForSignature(index, prevOutScript, hashType) + var signature = privKey.sign(hash) + + return signature.toScriptSignature(hashType) +} + +// FIXME: remove in 2.x.y +Transaction.prototype.validateInput = function (index, prevOutScript, pubKey, buffer) { + console.warn('Transaction.prototype.validateInput is deprecated. Use TransactionBuilder instead.') + + var parsed = ECSignature.parseScriptSignature(buffer) + var hash = this.hashForSignature(index, prevOutScript, parsed.hashType) + + return pubKey.verify(hash, parsed.signature) +} + +module.exports = Transaction + +}).call(this,require("buffer").Buffer) +},{"./address":54,"./bufferutils":57,"./crypto":58,"./ecsignature":62,"./opcodes":67,"./script":68,"./scripts":69,"assert":5,"buffer":7,"typeforce":53}],71:[function(require,module,exports){ +(function (Buffer){ +var assert = require('assert') +var ops = require('./opcodes') +var scripts = require('./scripts') + +var ECPubKey = require('./ecpubkey') +var ECSignature = require('./ecsignature') +var Script = require('./script') +var Transaction = require('./transaction') + +function extractInput (txIn) { + var redeemScript + var scriptSig = txIn.script + var prevOutScript + var prevOutType = scripts.classifyInput(scriptSig, true) + var scriptType + + // Re-classify if scriptHash + if (prevOutType === 'scripthash') { + redeemScript = Script.fromBuffer(scriptSig.chunks.slice(-1)[0]) + prevOutScript = scripts.scriptHashOutput(redeemScript.getHash()) + + scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1)) + scriptType = scripts.classifyInput(scriptSig, true) + } else { + scriptType = prevOutType + } + + // Extract hashType, pubKeys and signatures + var hashType, parsed, pubKeys, signatures + + switch (scriptType) { + case 'pubkeyhash': { + parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0]) + hashType = parsed.hashType + pubKeys = [ECPubKey.fromBuffer(scriptSig.chunks[1])] + signatures = [parsed.signature] + prevOutScript = pubKeys[0].getAddress().toOutputScript() + + break + } + + case 'pubkey': { + parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0]) + hashType = parsed.hashType + signatures = [parsed.signature] + + if (redeemScript) { + pubKeys = [ECPubKey.fromBuffer(redeemScript.chunks[0])] + } + + break + } + + case 'multisig': { + signatures = scriptSig.chunks.slice(1).map(function (chunk) { + if (chunk === ops.OP_0) return chunk + + var parsed = ECSignature.parseScriptSignature(chunk) + hashType = parsed.hashType + + return parsed.signature + }) + + if (redeemScript) { + pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer) + } + + break + } + } + + return { + hashType: hashType, + prevOutScript: prevOutScript, + prevOutType: prevOutType, + pubKeys: pubKeys, + redeemScript: redeemScript, + scriptType: scriptType, + signatures: signatures + } +} + +function TransactionBuilder () { + this.prevTxMap = {} + this.prevOutScripts = {} + this.prevOutTypes = {} + + this.inputs = [] + this.tx = new Transaction() +} + +TransactionBuilder.fromTransaction = function (transaction) { + var txb = new TransactionBuilder() + + // Copy other transaction fields + txb.tx.version = transaction.version + txb.tx.locktime = transaction.locktime + + // Extract/add inputs + transaction.ins.forEach(function (txIn) { + txb.addInput(txIn.hash, txIn.index, txIn.sequence) + }) + + // Extract/add outputs + transaction.outs.forEach(function (txOut) { + txb.addOutput(txOut.script, txOut.value) + }) + + // Extract/add signatures + txb.inputs = transaction.ins.map(function (txIn) { + // TODO: remove me after testcase added + assert(!Transaction.isCoinbaseHash(txIn.hash), 'coinbase inputs not supported') + + // Ignore empty scripts + if (txIn.script.buffer.length === 0) return {} + + return extractInput(txIn) + }) + + return txb +} + +TransactionBuilder.prototype.addInput = function (prevTx, index, sequence, prevOutScript) { + var prevOutHash + + // txId + if (typeof prevTx === 'string') { + prevOutHash = new Buffer(prevTx, 'hex') + + // TxId hex is big-endian, we want little-endian hash + Array.prototype.reverse.call(prevOutHash) + + // Transaction + } else if (prevTx instanceof Transaction) { + prevOutHash = prevTx.getHash() + prevOutScript = prevTx.outs[index].script + + // txHash + } else { + prevOutHash = prevTx + } + + var input = {} + if (prevOutScript) { + var prevOutType = scripts.classifyOutput(prevOutScript) + + // if we can, extract pubKey information + switch (prevOutType) { + case 'multisig': { + input.pubKeys = prevOutScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer) + break + } + + case 'pubkey': { + input.pubKeys = prevOutScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer) + break + } + } + + if (prevOutType !== 'scripthash') { + input.scriptType = prevOutType + } + + input.prevOutScript = prevOutScript + input.prevOutType = prevOutType + } + + assert(this.inputs.every(function (input2) { + if (input2.hashType === undefined) return true + + return input2.hashType & Transaction.SIGHASH_ANYONECANPAY + }), 'No, this would invalidate signatures') + + var prevOut = prevOutHash.toString('hex') + ':' + index + assert(!(prevOut in this.prevTxMap), 'Transaction is already an input') + + var vin = this.tx.addInput(prevOutHash, index, sequence) + this.inputs[vin] = input + this.prevTxMap[prevOut] = vin + + return vin +} + +TransactionBuilder.prototype.addOutput = function (scriptPubKey, value) { + assert(this.inputs.every(function (input) { + if (input.hashType === undefined) return true + + return (input.hashType & 0x1f) === Transaction.SIGHASH_SINGLE + }), 'No, this would invalidate signatures') + + return this.tx.addOutput(scriptPubKey, value) +} + +TransactionBuilder.prototype.build = function () { + return this.__build(false) +} +TransactionBuilder.prototype.buildIncomplete = function () { + return this.__build(true) +} + +var canSignTypes = { + 'pubkeyhash': true, + 'multisig': true, + 'pubkey': true +} + +TransactionBuilder.prototype.__build = function (allowIncomplete) { + if (!allowIncomplete) { + assert(this.tx.ins.length > 0, 'Transaction has no inputs') + assert(this.tx.outs.length > 0, 'Transaction has no outputs') + } + + var tx = this.tx.clone() + + // Create script signatures from signature meta-data + this.inputs.forEach(function (input, index) { + var scriptType = input.scriptType + var scriptSig + + if (!allowIncomplete) { + assert(!!scriptType, 'Transaction is not complete') + assert(scriptType in canSignTypes, scriptType + ' not supported') + assert(input.signatures, 'Transaction is missing signatures') + } + + if (input.signatures) { + switch (scriptType) { + case 'pubkeyhash': { + var pkhSignature = input.signatures[0].toScriptSignature(input.hashType) + scriptSig = scripts.pubKeyHashInput(pkhSignature, input.pubKeys[0]) + break + } + + case 'multisig': { + // Array.prototype.map is sparse-compatible + var msSignatures = input.signatures.map(function (signature) { + return signature && signature.toScriptSignature(input.hashType) + }) + + // fill in blanks with OP_0 + if (allowIncomplete) { + for (var i = 0; i < msSignatures.length; ++i) { + if (msSignatures[i]) continue + + msSignatures[i] = ops.OP_0 + } + } else { + // Array.prototype.filter returns non-sparse array + msSignatures = msSignatures.filter(function (x) { return x }) + } + + var redeemScript = allowIncomplete ? undefined : input.redeemScript + scriptSig = scripts.multisigInput(msSignatures, redeemScript) + break + } + + case 'pubkey': { + var pkSignature = input.signatures[0].toScriptSignature(input.hashType) + scriptSig = scripts.pubKeyInput(pkSignature) + break + } + } + } + + // did we build a scriptSig? + if (scriptSig) { + // wrap as scriptHash if necessary + if (input.prevOutType === 'scripthash') { + scriptSig = scripts.scriptHashInput(scriptSig, input.redeemScript) + } + + tx.setInputScript(index, scriptSig) + } + }) + + return tx +} + +TransactionBuilder.prototype.sign = function (index, privKey, redeemScript, hashType) { + assert(index in this.inputs, 'No input at index: ' + index) + hashType = hashType || Transaction.SIGHASH_ALL + + var input = this.inputs[index] + var canSign = input.hashType && + input.prevOutScript && + input.prevOutType && + input.pubKeys && + input.scriptType && + input.signatures + + // are we almost ready to sign? + if (canSign) { + // if redeemScript was provided, enforce consistency + if (redeemScript) { + assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript') + } + + assert.equal(input.hashType, hashType, 'Inconsistent hashType') + + // no? prepare + } else { + // must be pay-to-scriptHash? + if (redeemScript) { + // if we have a prevOutScript, enforce scriptHash equality to the redeemScript + if (input.prevOutScript) { + assert.equal(input.prevOutType, 'scripthash', 'PrevOutScript must be P2SH') + + var scriptHash = input.prevOutScript.chunks[1] + assert.deepEqual(scriptHash, redeemScript.getHash(), 'RedeemScript does not match ' + scriptHash.toString('hex')) + } + + var scriptType = scripts.classifyOutput(redeemScript) + assert(scriptType in canSignTypes, 'RedeemScript not supported (' + scriptType + ')') + + var pubKeys = [] + switch (scriptType) { + case 'multisig': { + pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer) + break + } + + case 'pubkeyhash': { + var pkh1 = redeemScript.chunks[2] + var pkh2 = privKey.pub.getAddress().hash + + assert.deepEqual(pkh1, pkh2, 'privateKey cannot sign for this input') + pubKeys = [privKey.pub] + break + } + + case 'pubkey': { + pubKeys = redeemScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer) + break + } + } + + if (!input.prevOutScript) { + input.prevOutScript = scripts.scriptHashOutput(redeemScript.getHash()) + input.prevOutType = 'scripthash' + } + + input.pubKeys = pubKeys + input.redeemScript = redeemScript + input.scriptType = scriptType + + // cannot be pay-to-scriptHash + } else { + assert.notEqual(input.prevOutType, 'scripthash', 'PrevOutScript is P2SH, missing redeemScript') + + // can we otherwise sign this? + if (input.scriptType) { + assert(input.pubKeys, input.scriptType + ' not supported') + + // we know nothin' Jon Snow, assume pubKeyHash + } else { + input.prevOutScript = privKey.pub.getAddress().toOutputScript() + input.prevOutType = 'pubkeyhash' + input.pubKeys = [privKey.pub] + input.scriptType = input.prevOutType + } + } + + input.hashType = hashType + input.signatures = input.signatures || [] + } + + var signatureScript = input.redeemScript || input.prevOutScript + var signatureHash = this.tx.hashForSignature(index, signatureScript, hashType) + + // enforce signature order matches public keys + if (input.scriptType === 'multisig' && input.redeemScript && input.signatures.length !== input.pubKeys.length) { + // maintain a local copy of unmatched signatures + var unmatched = input.signatures.slice() + + input.signatures = input.pubKeys.map(function (pubKey) { + var match + + // check for any matching signatures + unmatched.some(function (signature, i) { + if (!pubKey.verify(signatureHash, signature)) return false + match = signature + + // remove matched signature from unmatched + unmatched.splice(i, 1) + + return true + }) + + return match || undefined + }) + } + + // enforce in order signing of public keys + assert(input.pubKeys.some(function (pubKey, i) { + if (!privKey.pub.Q.equals(pubKey.Q)) return false + + assert(!input.signatures[i], 'Signature already exists') + var signature = privKey.sign(signatureHash) + input.signatures[i] = signature + + return true + }, this), 'privateKey cannot sign for this input') +} + +module.exports = TransactionBuilder + +}).call(this,require("buffer").Buffer) +},{"./ecpubkey":61,"./ecsignature":62,"./opcodes":67,"./script":68,"./scripts":69,"./transaction":70,"assert":5,"buffer":7}],72:[function(require,module,exports){ +(function (Buffer){ +var assert = require('assert') +var bufferutils = require('./bufferutils') +var typeForce = require('typeforce') +var networks = require('./networks') +var randomBytes = require('randombytes') + +var Address = require('./address') +var HDNode = require('./hdnode') +var TransactionBuilder = require('./transaction_builder') +var Script = require('./script') + +function Wallet (seed, network) { + console.warn('Wallet is deprecated and will be removed in 2.0.0, see #296') + + seed = seed || randomBytes(32) + network = network || networks.bitcoin + + // Stored in a closure to make accidental serialization less likely + var masterKey = HDNode.fromSeedBuffer(seed, network) + + // HD first-level child derivation method should be hardened + // See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254 + var accountZero = masterKey.deriveHardened(0) + var externalAccount = accountZero.derive(0) + var internalAccount = accountZero.derive(1) + + this.addresses = [] + this.changeAddresses = [] + this.network = network + this.unspents = [] + + // FIXME: remove in 2.0.0 + this.unspentMap = {} + + // FIXME: remove in 2.0.0 + var me = this + this.newMasterKey = function (seed) { + console.warn('newMasterKey is deprecated, please make a new Wallet instance instead') + + seed = seed || randomBytes(32) + masterKey = HDNode.fromSeedBuffer(seed, network) + + accountZero = masterKey.deriveHardened(0) + externalAccount = accountZero.derive(0) + internalAccount = accountZero.derive(1) + + me.addresses = [] + me.changeAddresses = [] + + me.unspents = [] + me.unspentMap = {} + } + + this.getMasterKey = function () { + return masterKey + } + this.getAccountZero = function () { + return accountZero + } + this.getExternalAccount = function () { + return externalAccount + } + this.getInternalAccount = function () { + return internalAccount + } +} + +Wallet.prototype.createTransaction = function (to, value, options) { + // FIXME: remove in 2.0.0 + if (typeof options !== 'object') { + if (options !== undefined) { + console.warn('Non options object parameters are deprecated, use options object instead') + + options = { + fixedFee: arguments[2], + changeAddress: arguments[3] + } + } + } + + options = options || {} + + assert(value > this.network.dustThreshold, value + ' must be above dust threshold (' + this.network.dustThreshold + ' Satoshis)') + + var changeAddress = options.changeAddress + var fixedFee = options.fixedFee + var minConf = options.minConf === undefined ? 0 : options.minConf // FIXME: change minConf:1 by default in 2.0.0 + + // filter by minConf, then pending and sort by descending value + var unspents = this.unspents.filter(function (unspent) { + return unspent.confirmations >= minConf + }).filter(function (unspent) { + return !unspent.pending + }).sort(function (o1, o2) { + return o2.value - o1.value + }) + + var accum = 0 + var addresses = [] + var subTotal = value + + var txb = new TransactionBuilder() + txb.addOutput(to, value) + + for (var i = 0; i < unspents.length; ++i) { + var unspent = unspents[i] + addresses.push(unspent.address) + + txb.addInput(unspent.txHash, unspent.index) + + var fee = fixedFee === undefined ? estimatePaddedFee(txb.buildIncomplete(), this.network) : fixedFee + + accum += unspent.value + subTotal = value + fee + + if (accum >= subTotal) { + var change = accum - subTotal + + if (change > this.network.dustThreshold) { + txb.addOutput(changeAddress || this.getChangeAddress(), change) + } + + break + } + } + + assert(accum >= subTotal, 'Not enough funds (incl. fee): ' + accum + ' < ' + subTotal) + + return this.signWith(txb, addresses).build() +} + +// FIXME: remove in 2.0.0 +Wallet.prototype.processPendingTx = function (tx) { + this.__processTx(tx, true) +} + +// FIXME: remove in 2.0.0 +Wallet.prototype.processConfirmedTx = function (tx) { + this.__processTx(tx, false) +} + +// FIXME: remove in 2.0.0 +Wallet.prototype.__processTx = function (tx, isPending) { + console.warn('processTransaction is considered harmful, see issue #260 for more information') + + var txId = tx.getId() + var txHash = tx.getHash() + + tx.outs.forEach(function (txOut, i) { + var address + + try { + address = Address.fromOutputScript(txOut.script, this.network).toString() + } catch (e) { + if (!(e.message.match(/has no matching Address/))) + throw e + } + + var myAddresses = this.addresses.concat(this.changeAddresses) + if (myAddresses.indexOf(address) > -1) { + var lookup = txId + ':' + i + if (lookup in this.unspentMap) return + + // its unique, add it + var unspent = { + address: address, + confirmations: 0, // no way to determine this without more information + index: i, + txHash: txHash, + txId: txId, + value: txOut.value, + pending: isPending + } + + this.unspentMap[lookup] = unspent + this.unspents.push(unspent) + } + }, this) + + tx.ins.forEach(function (txIn) { + // copy and convert to big-endian hex + var txInId = bufferutils.reverse(txIn.hash).toString('hex') + + var lookup = txInId + ':' + txIn.index + if (!(lookup in this.unspentMap)) return + + var unspent = this.unspentMap[lookup] + + if (isPending) { + unspent.pending = true + unspent.spent = true + } else { + delete this.unspentMap[lookup] + + this.unspents = this.unspents.filter(function (unspent2) { + return unspent !== unspent2 + }) + } + }, this) +} + +Wallet.prototype.generateAddress = function () { + var k = this.addresses.length + var address = this.getExternalAccount().derive(k).getAddress() + + this.addresses.push(address.toString()) + + return this.getReceiveAddress() +} + +Wallet.prototype.generateChangeAddress = function () { + var k = this.changeAddresses.length + var address = this.getInternalAccount().derive(k).getAddress() + + this.changeAddresses.push(address.toString()) + + return this.getChangeAddress() +} + +Wallet.prototype.getAddress = function () { + if (this.addresses.length === 0) { + this.generateAddress() + } + + return this.addresses[this.addresses.length - 1] +} + +Wallet.prototype.getBalance = function (minConf) { + minConf = minConf || 0 + + return this.unspents.filter(function (unspent) { + return unspent.confirmations >= minConf + + // FIXME: remove spent filter in 2.0.0 + }).filter(function (unspent) { + return !unspent.spent + }).reduce(function (accum, unspent) { + return accum + unspent.value + }, 0) +} + +Wallet.prototype.getChangeAddress = function () { + if (this.changeAddresses.length === 0) { + this.generateChangeAddress() + } + + return this.changeAddresses[this.changeAddresses.length - 1] +} + +Wallet.prototype.getInternalPrivateKey = function (index) { + return this.getInternalAccount().derive(index).privKey +} + +Wallet.prototype.getPrivateKey = function (index) { + return this.getExternalAccount().derive(index).privKey +} + +Wallet.prototype.getPrivateKeyForAddress = function (address) { + var index + + if ((index = this.addresses.indexOf(address)) > -1) { + return this.getPrivateKey(index) + } + + if ((index = this.changeAddresses.indexOf(address)) > -1) { + return this.getInternalPrivateKey(index) + } + + assert(false, 'Unknown address. Make sure the address is from the keychain and has been generated') +} + +Wallet.prototype.getUnspentOutputs = function (minConf) { + minConf = minConf || 0 + + return this.unspents.filter(function (unspent) { + return unspent.confirmations >= minConf + + // FIXME: remove spent filter in 2.0.0 + }).filter(function (unspent) { + return !unspent.spent + }).map(function (unspent) { + return { + address: unspent.address, + confirmations: unspent.confirmations, + index: unspent.index, + txId: unspent.txId, + value: unspent.value, + + // FIXME: remove in 2.0.0 + hash: unspent.txId, + pending: unspent.pending + } + }) +} + +Wallet.prototype.setUnspentOutputs = function (unspents) { + this.unspentMap = {} + this.unspents = unspents.map(function (unspent) { + // FIXME: remove unspent.hash in 2.0.0 + var txId = unspent.txId || unspent.hash + var index = unspent.index + + // FIXME: remove in 2.0.0 + if (unspent.hash !== undefined) { + console.warn('unspent.hash is deprecated, use unspent.txId instead') + } + + // FIXME: remove in 2.0.0 + if (index === undefined) { + console.warn('unspent.outputIndex is deprecated, use unspent.index instead') + index = unspent.outputIndex + } + + typeForce('String', txId) + typeForce('Number', index) + typeForce('Number', unspent.value) + + assert.equal(txId.length, 64, 'Expected valid txId, got ' + txId) + assert.doesNotThrow(function () { + Address.fromBase58Check(unspent.address) + }, 'Expected Base58 Address, got ' + unspent.address) + assert(isFinite(index), 'Expected finite index, got ' + index) + + // FIXME: remove branch in 2.0.0 + if (unspent.confirmations !== undefined) { + typeForce('Number', unspent.confirmations) + } + + var txHash = bufferutils.reverse(new Buffer(txId, 'hex')) + + unspent = { + address: unspent.address, + confirmations: unspent.confirmations || 0, + index: index, + txHash: txHash, + txId: txId, + value: unspent.value, + + // FIXME: remove in 2.0.0 + pending: unspent.pending || false + } + + // FIXME: remove in 2.0.0 + this.unspentMap[txId + ':' + index] = unspent + + return unspent + }, this) +} + +Wallet.prototype.signWith = function (tx, addresses) { + addresses.forEach(function (address, i) { + var privKey = this.getPrivateKeyForAddress(address) + + tx.sign(i, privKey) + }, this) + + return tx +} + +function estimatePaddedFee (tx, network) { + var tmpTx = tx.clone() + tmpTx.addOutput(Script.EMPTY, network.dustSoftThreshold || 0) + + return network.estimateFee(tmpTx) +} + +// FIXME: 1.0.0 shims, remove in 2.0.0 +Wallet.prototype.getReceiveAddress = Wallet.prototype.getAddress +Wallet.prototype.createTx = Wallet.prototype.createTransaction + +module.exports = Wallet + +}).call(this,require("buffer").Buffer) +},{"./address":54,"./bufferutils":57,"./hdnode":63,"./networks":66,"./script":68,"./transaction_builder":71,"assert":5,"buffer":7,"randombytes":52,"typeforce":53}]},{},[64])(64) +}); + + + + + + + + + + + + + + +