function signOne(hash, addrStr, keys) { var keyObj = keys[addrStr]; var rawPrivKey = new Buffer(keyObj.priv, 'hex'); var key = new KeyModule.Key(); key.private = rawPrivKey; var signature = key.signSync(hash); return signature; } function signTxIn(nIn, tx, txInputs, network, keys, scripts) { // locate TX input needing a signature var txin = tx.ins[nIn]; var scriptSig = txin.getScript(); // locate TX output, within txInputs var txoutHash = txin.getOutpointHash(); if (!(txoutHash in txInputs)) throw new Error("signTxIn missing input hash"); var txFrom = txInputs[txoutHash]; var txoutIndex = txin.getOutpointIndex(); if (txFrom.outs.length >= txoutIndex) throw new Error("signTxIn missing input index"); var txout = txFrom.outs[txoutIndex]; var scriptPubKey = txout.getScript(); // detect type of transaction, and extract useful elements var txType = scriptPubKey.classify(); if (txType == TX_UNKNOWN) throw new Error("unknown TX type"); var scriptData = scriptPubKey.capture(); // if P2SH, lookup the script var subscriptRaw = undefined; var subscript = undefined; var subType = undefined; var subData = undefined; if (txType == TX_SCRIPTHASH) { var addr = new Address(network.P2SHVersion, scriptData[0]); var addrStr = addr.toString(); if (!(addrStr in scripts)) throw new Error("unknown script hash address"); subscriptRaw = new Buffer(scripts[addrStr], 'hex'); subscript = new Script(subscriptRaw); subType = subscript.classify(); if (subType == TX_UNKNOWN) throw new Error("unknown subscript TX type"); subData = subscript.capture(); } var hash = tx.hashForSignature(scriptPubKey, i, 0); switch (txType) { case TX_PUBKEY: // already signed if (scriptSig.chunks.length > 0) return; var pubkeyhash = util.sha256ripe160(scriptData[0]); var addr = new Address(network.addressVersion, pubkeyhash); var addrStr = addr.toString(); if (!(addrStr in keys)) throw new Error("unknown pubkey"); var signature = signOne(hash, addrStr, keys); scriptSig.writeBytes(signature); break; case TX_PUBKEYHASH: // already signed if (scriptSig.chunks.length > 0) return; var addr = new Address(network.addressVersion, scriptData[0]); var addrStr = addr.toString(); if (!(addrStr in keys)) throw new Error("unknown pubkey hash address"); var signature = signOne(hash, addrStr, keys); scriptSig.writeBytes(signature); scriptSig.writeBytes(key.public); break; case TX_SCRIPTHASH: // already signed if (scriptSig.chunks.length > 0) return; var addr = new Address(network.addressVersion, subData[0]); var addrStr = addr.toString(); if (!(addrStr in keys)) throw new Error("unknown script(pubkey hash) address"); var signature = signOne(hash, addrStr, keys); scriptSig.writeBytes(signature); scriptSig.writeBytes(key.public); break; case TX_MULTISIG: while (scriptSig.chunks.length < scriptData.length) { scriptSig.writeBytes(util.EMPTY_BUFFER); } for (var i = 0; i < scriptData.length; i++) { // skip already signed if (scriptSig.chunks[i].length > 0) continue; var pubkeyhash = util.sha256ripe160(scriptSig.chunks[i]); var addr = new Address(network.addressVersion, pubkeyhash); var addrStr = addr.toString(); if (!(addrStr in keys)) continue; var signature = signOne(hash, addrStr, keys); scriptSig.chunks[i] = signature; } break; } if (txtype == TX_SCRIPTHASH) scriptSig.writeBytes(subscriptRaw); } exports.Transaction = function Transaction(tx, txInputs, network, keys, scripts) { for (var i = 0; i < tx.ins.length; i++) signTxIn(i, tx, txInputs, network, keys, scripts); };