Drop in BTCZJS refinements
This commit is contained in:
parent
70bed2f5e3
commit
0185517d67
|
@ -1,15 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
var bs58check = require('bs58check');
|
||||
var secp256k1 = require('secp256k1');
|
||||
var zbufferutils = require('./bufferutils');
|
||||
var bigi = require('bigi');
|
||||
var zcrypto = require('./crypto');
|
||||
var zopcodes = require('./opcodes');
|
||||
var zconfig = require('./config');
|
||||
|
||||
/*
|
||||
* Makes a private key
|
||||
* @param {String phrase (Password phrase)
|
||||
* @param {String} phrase (Password phrase)
|
||||
* @return {Sting} Private key
|
||||
*/
|
||||
function mkPrivKey(phrase) {
|
||||
|
@ -20,12 +17,12 @@ function mkPrivKey(phrase) {
|
|||
* Converts a private key to WIF format
|
||||
* @param {String} privKey (private key)
|
||||
* @param {boolean} toCompressed (Convert to WIF compressed key or nah)
|
||||
* @param {String} wif (wif hashing bytes (default: 0x80))
|
||||
* @param {string} wif (wif hashing bytes (default: 0x80))
|
||||
* @return {Sting} WIF format (uncompressed)
|
||||
*/
|
||||
function privKeyToWIF(privKey) {
|
||||
var toCompressed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
var wif = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : zconfig.mainnet.wif;
|
||||
function privKeyToWIF(privKey, toCompressed, wif) {
|
||||
toCompressed = toCompressed || false;
|
||||
wif = wif || zconfig.mainnet.wif;
|
||||
|
||||
if (toCompressed) privKey = privKey + '01';
|
||||
|
||||
|
@ -38,10 +35,10 @@ function privKeyToWIF(privKey) {
|
|||
* @param {boolean} toCompressed (Convert to public key compressed key or nah)
|
||||
* @return {Sting} Public Key (default: uncompressed)
|
||||
*/
|
||||
function privKeyToPubKey(privKey) {
|
||||
var toCompressed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
function privKeyToPubKey(privKey, toCompressed) {
|
||||
toCompressed = toCompressed || false;
|
||||
|
||||
var pkBuffer = Buffer.from(privKey, 'hex');
|
||||
const pkBuffer = Buffer.from(privKey, 'hex');
|
||||
var publicKey = secp256k1.publicKeyCreate(pkBuffer, toCompressed);
|
||||
return publicKey.toString('hex');
|
||||
}
|
||||
|
@ -64,19 +61,20 @@ function WIFToPrivKey(wifPk) {
|
|||
}
|
||||
|
||||
/*
|
||||
* Converts public key to zencash address
|
||||
* Converts public key to btcp address
|
||||
* @param {String} pubKey (public key)
|
||||
* @param {String} pubKeyHash (public key hash (optional, else use defaul))
|
||||
* @return {String} zencash address
|
||||
* @return {Sting} btcp address
|
||||
*/
|
||||
function pubKeyToAddr(pubKey) {
|
||||
var pubKeyHash = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : zconfig.mainnet.pubKeyHash;
|
||||
function pubKeyToAddr(pubKey, pubKeyHash) {
|
||||
pubKeyHash = pubKeyHash || zconfig.mainnet.pubKeyHash;
|
||||
|
||||
var hash160 = zcrypto.hash160(Buffer.from(pubKey, 'hex'));
|
||||
const hash160 = zcrypto.hash160(Buffer.from(pubKey, 'hex'));
|
||||
return bs58check.encode(Buffer.from(pubKeyHash + hash160, 'hex')).toString('hex');
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
/* (Not in use)
|
||||
* Given a list of public keys, create a M-of-N redeemscript
|
||||
* @param {[String]} pubKey (array of public keys, NOT ADDRESS)
|
||||
* @param {Int} M [2 or 3] in M-of-N multisig
|
||||
|
@ -91,11 +89,11 @@ function mkMultiSigRedeemScript(pubKeys, M, N) {
|
|||
var OP_END = (OP_1.readInt8(0) + (N - 1)).toString(16);
|
||||
|
||||
return OP_START + pubKeys.map(function (x) {
|
||||
return zbufferutils.getPushDataLength(x) + x;
|
||||
return zbufferutils.getStringBufferLength(x) + x;
|
||||
}).join('') + OP_END + zopcodes.OP_CHECKMULTISIG;
|
||||
}
|
||||
|
||||
/*
|
||||
/* (Not in use)
|
||||
* Reference: http://www.soroushjp.com/2014/12/20/bitcoin-multisig-the-hard-way-understanding-raw-multisignature-bitcoin-transactions/
|
||||
* Given the multi sig redeem script, return the corresponding address
|
||||
* @param {String} RedeemScript (redeem script)
|
||||
|
@ -118,4 +116,4 @@ module.exports = {
|
|||
WIFToPrivKey: WIFToPrivKey,
|
||||
mkMultiSigRedeemScript: mkMultiSigRedeemScript,
|
||||
multiSigRSToAddress: multiSigRSToAddress
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
var varuint = require('varuint-bitcoin');
|
||||
|
||||
// https://github.com/bitcoinjs/bitcoinjs-lib/issues/14
|
||||
function numToBytes(num, bytes) {
|
||||
if (bytes === 0) return [];else return [num % 256].concat(numToBytes(Math.floor(num / 256), bytes - 1));
|
||||
if (bytes == 0) return [];else return [num % 256].concat(numToBytes(Math.floor(num / 256), bytes - 1));
|
||||
}
|
||||
|
||||
function numToVarInt(num) {
|
||||
return varuint.encode(num).toString('hex');
|
||||
var b;
|
||||
if (num < 253) b = [num];else if (num < 65536) b = [253].concat(numToBytes(num, 2));else if (num < 4294967296) b = [254].concat(numToBytes(num, 4));else b = [253].concat(numToBytes(num, 8));
|
||||
return Buffer.from(b).toString('hex');
|
||||
}
|
||||
|
||||
// https://github.com/feross/buffer/blob/master/index.js#L1127
|
||||
|
@ -50,16 +48,15 @@ function writeUInt64LE(buffer, value, offset) {
|
|||
* @param {String} hexStr
|
||||
* return {String} Length of hexStr in bytes
|
||||
*/
|
||||
function getPushDataLength(s) {
|
||||
// https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
|
||||
var hexLength = Buffer.from(s, 'hex').length;
|
||||
return numToVarInt(hexLength);
|
||||
function getStringBufferLength(hexStr) {
|
||||
const _tmpBuf = Buffer.from(hexStr, 'hex').length;
|
||||
return Buffer.from([_tmpBuf]).toString('hex');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
readUInt64LE: readUInt64LE,
|
||||
writeUInt64LE: writeUInt64LE,
|
||||
getPushDataLength: getPushDataLength,
|
||||
getStringBufferLength: getStringBufferLength,
|
||||
numToVarInt: numToVarInt,
|
||||
numToBytes: numToBytes
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
var bs58check = require('bs58check');
|
||||
|
||||
var elliptic = require('elliptic');
|
||||
var secp256k1 = new elliptic.ec('secp256k1'); /* eslint new-cap: ["error", { "newIsCap": false }] */
|
||||
var secp256k1 = require('secp256k1');
|
||||
var int64buffer = require('int64-buffer');
|
||||
var varuint = require('varuint-bitcoin');
|
||||
var zconfig = require('./config');
|
||||
var zbufferutils = require('./bufferutils');
|
||||
|
@ -11,38 +8,39 @@ var zcrypto = require('./crypto');
|
|||
var zconstants = require('./constants');
|
||||
var zaddress = require('./address');
|
||||
var zopcodes = require('./opcodes');
|
||||
var zbufferutils = require('./bufferutils');
|
||||
|
||||
/*
|
||||
* Given an address, generates a pubkeyhash replay type script needed for the transaction
|
||||
/*
|
||||
* Given an address, generates a pubkeyhash script needed for the transaction
|
||||
* @param {String} address
|
||||
* @param {String} pubKeyHash (optional)
|
||||
* return {String} pubKeyScript
|
||||
*/
|
||||
function mkPubkeyHashReplayScript(address) {
|
||||
// Prefix
|
||||
var pubKeyHash = zconfig.mainnet.pubKeyHash;
|
||||
function mkPubkeyHashReplayScript(address, pubKeyHash) {
|
||||
pubKeyHash = pubKeyHash || zconfig.mainnet.pubKeyHash;
|
||||
|
||||
var addrHex = bs58check.decode(address).toString('hex');
|
||||
|
||||
// Cut out pubKeyHash
|
||||
// '14' is the length of the subAddrHex (in bytes)
|
||||
var subAddrHex = addrHex.substring(pubKeyHash.length, addrHex.length);
|
||||
|
||||
return zopcodes.OP_DUP + zopcodes.OP_HASH160 + zbufferutils.getPushDataLength(subAddrHex) + subAddrHex + zopcodes.OP_EQUALVERIFY + zopcodes.OP_CHECKSIG;
|
||||
// Minimal encoding
|
||||
// '14' is the length of the subAddrHex (in bytes)
|
||||
return zopcodes.OP_DUP + zopcodes.OP_HASH160 + zbufferutils.getStringBufferLength(subAddrHex) + subAddrHex + zopcodes.OP_EQUALVERIFY + zopcodes.OP_CHECKSIG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given an address, generates a script hash replay type script needed for the transaction
|
||||
* Given an address, generates a script hash script needed for the transaction
|
||||
* @param {String} address
|
||||
* return {String} scriptHash script
|
||||
*/
|
||||
function mkScriptHashReplayScript(address) {
|
||||
|
||||
var addrHex = bs58check.decode(address).toString('hex');
|
||||
var subAddrHex = addrHex.substring(4, addrHex.length); // Cut out the '00' (we also only want 14 bytes instead of 16)
|
||||
|
||||
// Cut out the '00' (we also only want 14 bytes instead of 16)
|
||||
var subAddrHex = addrHex.substring(4, addrHex.length);
|
||||
// '14' is the length of the subAddrHex (in bytes)
|
||||
return zopcodes.OP_DUP + zopcodes.OP_HASH160 + zbufferutils.getStringBufferLength(subAddrHex) + subAddrHex + zopcodes.OP_EQUAL;
|
||||
|
||||
return zopcodes.OP_HASH160 + zbufferutils.getPushDataLength(subAddrHex) + subAddrHex + zopcodes.OP_EQUAL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -51,12 +49,10 @@ function mkScriptHashReplayScript(address) {
|
|||
* return {String} output script
|
||||
*/
|
||||
function addressToScript(address) {
|
||||
// P2SH (with replay protection)
|
||||
if (address[1] === 'x') {
|
||||
return mkScriptHashReplayScript(address);
|
||||
}
|
||||
|
||||
// P2PKH (with replay protection)
|
||||
return mkPubkeyHashReplayScript(address);
|
||||
}
|
||||
|
||||
|
@ -69,34 +65,30 @@ function addressToScript(address) {
|
|||
* return {String} output script
|
||||
*/
|
||||
function signatureForm(txObj, i, script, hashcode) {
|
||||
console.log('Hashcode', hashcode);
|
||||
|
||||
console.log('signatureForm');
|
||||
console.log(hashcode);
|
||||
console.log(script);
|
||||
// Copy object so we don't rewrite it
|
||||
var newTx = JSON.parse(JSON.stringify(txObj));
|
||||
|
||||
// Only sign the specified index
|
||||
for (var j = 0; j < newTx.ins.length; j++) {
|
||||
newTx.ins[j].script = '';
|
||||
}
|
||||
|
||||
newTx.ins[i].script = script;
|
||||
|
||||
/*
|
||||
if (hashcode === zconstants.SIGHASH_NONE) {
|
||||
newTx.outs = [];
|
||||
} else if (hashcode === zconstants.SIGHASH_SINGLE) {
|
||||
newTx.outs = newTx.outs.slice(0, newTx.ins.length);
|
||||
for (var _j = 0; _j < newTx.ins.length - 1; ++_j) {
|
||||
newTx.outs[_j].satoshis = Math.pow(2, 64) - 1;
|
||||
newTx.outs[_j].script = '';
|
||||
for (var j = 0; j < newTx.ins.length - 1; ++j) {
|
||||
newTx.outs[j].satoshis = Math.pow(2, 64) - 1;
|
||||
newTx.outs[j].script = '';
|
||||
}
|
||||
} else if (hashcode === zconstants.SIGHASH_ANYONECANPAY) {
|
||||
newTx.ins = [newTx.ins[i]];
|
||||
} else { //TODO temp
|
||||
newTx.ins = [newTx.ins[i]];
|
||||
}
|
||||
TODO these | SIGHASH_FORKID
|
||||
*/
|
||||
|
||||
newTx.ins = [newTx.ins[i]];
|
||||
|
||||
return newTx;
|
||||
}
|
||||
|
@ -107,13 +99,13 @@ function signatureForm(txObj, i, script, hashcode) {
|
|||
* @return {Object} txOBJ
|
||||
*/
|
||||
function deserializeTx(hexStr) {
|
||||
var buf = Buffer.from(hexStr, 'hex');
|
||||
const buf = Buffer.from(hexStr, 'hex');
|
||||
var offset = 0;
|
||||
|
||||
// Out txobj
|
||||
var txObj = { version: 0, locktime: 0, ins: [], outs: []
|
||||
|
||||
// Version
|
||||
// Version
|
||||
};txObj.version = buf.readUInt32LE(offset);
|
||||
offset += 4;
|
||||
|
||||
|
@ -121,20 +113,19 @@ function deserializeTx(hexStr) {
|
|||
var vinLen = varuint.decode(buf, offset);
|
||||
offset += varuint.decode.bytes;
|
||||
for (var i = 0; i < vinLen; i++) {
|
||||
// Else its
|
||||
var hash = buf.slice(offset, offset + 32);
|
||||
const hash = buf.slice(offset, offset + 32);
|
||||
offset += 32;
|
||||
|
||||
var vout = buf.readUInt32LE(offset);
|
||||
const vout = buf.readUInt32LE(offset);
|
||||
offset += 4;
|
||||
|
||||
var scriptLen = varuint.decode(buf, offset);
|
||||
const scriptLen = varuint.decode(buf, offset);
|
||||
offset += varuint.decode.bytes;
|
||||
|
||||
var script = buf.slice(offset, offset + scriptLen);
|
||||
const script = buf.slice(offset, offset + scriptLen);
|
||||
offset += scriptLen;
|
||||
|
||||
var sequence = buf.slice(offset, offset + 4).toString('hex');
|
||||
const sequence = buf.slice(offset, offset + 4).toString('hex');
|
||||
offset += 4;
|
||||
|
||||
txObj.ins.push({
|
||||
|
@ -148,19 +139,19 @@ function deserializeTx(hexStr) {
|
|||
// Vouts
|
||||
var voutLen = varuint.decode(buf, offset);
|
||||
offset += varuint.decode.bytes;
|
||||
for (var _i = 0; _i < voutLen; _i++) {
|
||||
var satoshis = zbufferutils.readUInt64LE(buf, offset);
|
||||
for (var i = 0; i < voutLen; i++) {
|
||||
const satoshis = zbufferutils.readUInt64LE(buf, offset);
|
||||
offset += 8;
|
||||
|
||||
var _scriptLen = varuint.decode(buf, offset);
|
||||
const scriptLen = varuint.decode(buf, offset);
|
||||
offset += varuint.decode.bytes;
|
||||
|
||||
var _script = buf.slice(offset, offset + _scriptLen);
|
||||
offset += _scriptLen;
|
||||
const script = buf.slice(offset, offset + scriptLen);
|
||||
offset += scriptLen;
|
||||
|
||||
txObj.outs.push({
|
||||
satoshis: satoshis,
|
||||
script: _script.toString('hex')
|
||||
script: script.toString('hex')
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -192,9 +183,8 @@ function serializeTx(txObj) {
|
|||
serializedTx += Buffer.from(i.output.hash, 'hex').reverse().toString('hex');
|
||||
serializedTx += _buf16.toString('hex');
|
||||
|
||||
// Script Signature
|
||||
// Doesn't work for length > 253 ....
|
||||
serializedTx += zbufferutils.getPushDataLength(i.script);
|
||||
// Script
|
||||
serializedTx += zbufferutils.getStringBufferLength(i.script);
|
||||
serializedTx += i.script;
|
||||
|
||||
// Sequence
|
||||
|
@ -209,13 +199,11 @@ function serializeTx(txObj) {
|
|||
// https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/bufferutils.js#L25
|
||||
var _buf32 = Buffer.alloc(8);
|
||||
|
||||
// Satoshis
|
||||
_buf32.writeInt32LE(o.satoshis & -1, 0);
|
||||
_buf32.writeUInt32LE(Math.floor(o.satoshis / 0x100000000), 4);
|
||||
|
||||
// ScriptPubKey
|
||||
serializedTx += _buf32.toString('hex');
|
||||
serializedTx += zbufferutils.getPushDataLength(o.script);
|
||||
serializedTx += zbufferutils.getStringBufferLength(o.script);
|
||||
serializedTx += o.script;
|
||||
});
|
||||
|
||||
|
@ -230,7 +218,8 @@ function serializeTx(txObj) {
|
|||
* Creates a raw transaction
|
||||
* @param {[HISTORY]} history type, array of transaction history
|
||||
* @param {[RECIPIENTS]} recipient type, array of address on where to send coins to
|
||||
* @return {TXOBJ} Transaction Object (see TXOBJ type for info about structure)
|
||||
* @param {Number} blockHeight (latest - 300)
|
||||
* @return {TXOBJ} Transction Object (see TXOBJ type for info about structure)
|
||||
*/
|
||||
function createRawTx(history, recipients) {
|
||||
var txObj = { locktime: 0, version: 1, ins: [], outs: [] };
|
||||
|
@ -253,132 +242,53 @@ function createRawTx(history, recipients) {
|
|||
return txObj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets signature for the vin script
|
||||
* @params {string} privKey private key
|
||||
* @params {TXOBJ} signingTx a txobj whereby all the vin script's field are empty except for the one that needs to be signed
|
||||
* @params {number} hashcode
|
||||
*/
|
||||
function getScriptSignature(privKey, signingTx, hashcode) {
|
||||
|
||||
const BTCP_FORKID = 42;
|
||||
|
||||
// Buffers
|
||||
var _buf16H = Buffer.alloc(4);
|
||||
_buf16H.writeUInt16LE(hashcode | (BTCP_FORKID << 8), 0);
|
||||
|
||||
var signingTxHex = serializeTx(signingTx);
|
||||
var signingTxWithHashcode = signingTxHex + _buf16H.toString('hex');
|
||||
|
||||
// Sha256 it twice, according to spec
|
||||
var msg = zcrypto.sha256x2(Buffer.from(signingTxWithHashcode, 'hex'));
|
||||
|
||||
// Signing it
|
||||
var rawsig = secp256k1.sign(Buffer.from(msg, 'hex'), Buffer.from(privKey, 'hex'), { canonical: true });
|
||||
|
||||
// SCRIPT_VERIFY_DERSIG is always enforced
|
||||
// Convert it to DER format
|
||||
// Appending 41 to it
|
||||
// Would normally be 01, but OR'd against FORKID
|
||||
// ScriptSig = <varint of total sig length> <SIG from code, including appended 01 SIGNHASH> <length of pubkey (0x21 or 0x41)> <pubkey>
|
||||
// https://bitcoin.stackexchange.com/a/36481
|
||||
var signatureDER = Buffer.from(rawsig.toDER()).toString('hex') + '41';
|
||||
|
||||
return signatureDER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signs the raw transaction
|
||||
* @param {String} rawTx raw transaction
|
||||
* @param {Int} i
|
||||
* @param {privKey} privKey (not WIF format)
|
||||
* @param {compressPubKey} compress public key before appending to scriptSig? (default false)
|
||||
* @param {hashcode} hashtype (default SIGHASH_ALL|SIGHASH_FORKID)
|
||||
* @param {hashcode} hashcode (default SIGHASH_ALL)
|
||||
* return {String} signed transaction
|
||||
*/
|
||||
function signTx(_txObj, i, privKey) {
|
||||
var compressPubKey = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
||||
var hashcode = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : zconstants.SIGHASH_ALL | zconstants.SIGHASH_FORKID;
|
||||
function signTx(_txObj, i, privKey, compressPubKey, hashcode) {
|
||||
hashcode = hashcode || (zconstants.SIGHASH_ALL | zconstants.SIGHASH_FORKID);
|
||||
compressPubKey = compressPubKey || false;
|
||||
|
||||
// Make a copy
|
||||
var txObj = JSON.parse(JSON.stringify(_txObj));
|
||||
|
||||
var forkHashcode = hashcode | (42 << 8); // BTCP_FORKID = 42
|
||||
|
||||
// Buffer
|
||||
var _buf16 = Buffer.alloc(4);
|
||||
_buf16.writeUInt16LE(forkHashcode, 0);
|
||||
|
||||
// Prepare signing
|
||||
const script = txObj.ins[i].prevScriptPubKey;
|
||||
|
||||
// Prepare our signature
|
||||
// Get script from the current tx input
|
||||
var script = txObj.ins[i].prevScriptPubKey;
|
||||
const signingTx = signatureForm(txObj, i, script, forkHashcode);
|
||||
const signingTxHex = serializeTx(signingTx);
|
||||
const signingTxWithHashcode = signingTxHex + _buf16.toString('hex');
|
||||
|
||||
// Populate current tx in with the prevScriptPubKey
|
||||
var signingTx = signatureForm(txObj, i, script, hashcode);
|
||||
// Sha256 it twice, according to spec
|
||||
const msg = zcrypto.sha256x2(Buffer.from(signingTxWithHashcode, 'hex'));
|
||||
|
||||
// Get script signature
|
||||
var scriptSig = getScriptSignature(privKey, signingTx, hashcode);
|
||||
// Signing it
|
||||
const rawsig = secp256k1.sign(Buffer.from(msg, 'hex'), Buffer.from(privKey, 'hex')).signature;
|
||||
|
||||
// Convert it to DER format
|
||||
// Appending 41 (instead of 01)
|
||||
// ScriptSig = <varint of total sig length> <SIG from code, including appended 01 SIGNHASH> <length of pubkey (0x21 or 0x41)> <pubkey>
|
||||
// https://bitcoin.stackexchange.com/a/36481
|
||||
const signatureDER = secp256k1.signatureExport(rawsig).toString('hex') + '41';
|
||||
|
||||
// Chuck it back into txObj and add pubkey
|
||||
// Protocol:
|
||||
// PUSHDATA
|
||||
// signature data and SIGHASH_ALL|SIGHASH_FORKID
|
||||
// PUSHDATA
|
||||
// public key data
|
||||
var compress = false; //TODO does this need to be true?
|
||||
var pubKey = zaddress.privKeyToPubKey(privKey, compress);
|
||||
// WHAT? If it fails, uncompress/compress it and it should work...
|
||||
const pubKey = zaddress.privKeyToPubKey(privKey, compressPubKey);
|
||||
|
||||
txObj.ins[i].script = zbufferutils.getPushDataLength(scriptSig) + scriptSig + zbufferutils.getPushDataLength(pubKey) + pubKey;
|
||||
|
||||
return txObj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets signatures needed for multi-sign tx
|
||||
* @param {String} _txObj transaction object you wanna sign
|
||||
* @param {Int} index fof tx.in to sign
|
||||
* @param {privKey} An M private key (NOT WIF format!!!)
|
||||
* @param {string} redeemScript (redeemScript of the multi-sig)
|
||||
* @param {string} hashcode (SIGHASH_ALL, SIGHASH_NONE, etc | SIGHASH_FORKID)
|
||||
* return {String} signature
|
||||
*/
|
||||
function multiSign(_txObj, i, privKey, redeemScript) {
|
||||
var hashcode = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : zconstants.SIGHASH_ALL | zconstants.SIGHASH_FORKID;
|
||||
|
||||
// Make a copy
|
||||
var txObj = JSON.parse(JSON.stringify(_txObj));
|
||||
|
||||
// Populate current tx.ins[i] with the redeemScript
|
||||
var signingTx = signatureForm(txObj, i, redeemScript, hashcode);
|
||||
|
||||
return getScriptSignature(privKey, signingTx, hashcode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Applies the signatures to the transaction object
|
||||
* NOTE: You NEED to supply the signatures in order.
|
||||
* E.g. You made sigAddr1 with priv1, priv3, priv2
|
||||
* You can provide signatures of (priv1, priv2) (priv3, priv2) ...
|
||||
* But not (priv2, priv1)
|
||||
* @param {String} _txObj transaction object you wanna sign
|
||||
* @param {Int} index fof tx.in to sign
|
||||
* @param {[string]} signatures obtained from multiSign
|
||||
* @param {string} redeemScript (redeemScript of the multi-sig)
|
||||
* @param {string} hashcode (SIGHASH_ALL, SIGHASH_NONE, etc)
|
||||
* return {String} signature
|
||||
*/
|
||||
function applyMultiSignatures(_txObj, i, signatures, redeemScript) {
|
||||
// Make a copy
|
||||
var txObj = JSON.parse(JSON.stringify(_txObj));
|
||||
|
||||
var redeemScriptPushDataLength = zbufferutils.getPushDataLength(redeemScript);
|
||||
|
||||
// Lmao no idea, just following the source code
|
||||
if (redeemScriptPushDataLength.length > 2) {
|
||||
if (redeemScriptPushDataLength.length === 6) {
|
||||
redeemScriptPushDataLength = redeemScriptPushDataLength.slice(2, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// http://www.soroushjp.com/2014/12/20/bitcoin-multisig-the-hard-way-understanding-raw-multisignature-bitcoin-transactions/
|
||||
txObj.ins[i].script = zopcodes.OP_0 + signatures.map(function (x) {
|
||||
return zbufferutils.getPushDataLength(x) + x;
|
||||
}).join('') + zopcodes.OP_PUSHDATA1 + redeemScriptPushDataLength + redeemScript;
|
||||
txObj.ins[i].script = zbufferutils.getStringBufferLength(signatureDER) + signatureDER + zbufferutils.getStringBufferLength(pubKey) + pubKey;
|
||||
|
||||
return txObj;
|
||||
}
|
||||
|
@ -391,8 +301,5 @@ module.exports = {
|
|||
signatureForm: signatureForm,
|
||||
serializeTx: serializeTx,
|
||||
deserializeTx: deserializeTx,
|
||||
signTx: signTx,
|
||||
multiSign: multiSign,
|
||||
applyMultiSignatures: applyMultiSignatures,
|
||||
getScriptSignature: getScriptSignature
|
||||
signTx: signTx
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue