Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /// determine signers in a 2-of-3 Dogecoin multisig transaction
- /// uses sochain
- /// requirements:
- /// node.js and npm
- /// npm install bitcoinjs-lib ecpair tiny-secp256k1
- const https = require('https');
- const { script, Transaction } = require('bitcoinjs-lib');
- const { ECPairFactory } = require('ecpair');
- const tinysecp = require('tiny-secp256k1');
- const ECPair = ECPairFactory(tinysecp);
- //////////////////////////////////////////
- ///// functions to fetch tx from chain.so
- /////////////////////////////////////////
- const HTTPS_OPTIONS = {
- hostname: 'chain.so',
- port: 443,
- method: 'GET'
- };
- function options(path) {
- const out = {};
- Object.keys(HTTPS_OPTIONS).forEach(k => {
- out[k] = HTTPS_OPTIONS[k];
- });
- out["path"] = path;
- return out;
- };
- function fetch(path) {
- return new Promise(function (r,f) {
- opts = options(path);
- const req = https.request(opts, res => {
- const chunks = [];
- if (res.statusCode != 200) {
- return f(new Error("Server returned status " + res.statusCode));
- }
- res.on('data', d => chunks.push(d));
- res.on('end', () => r(Buffer.concat(chunks)));
- });
- req.on('error', e => f(e));
- req.end();
- });
- }
- async function fetchJSON(path) {
- let data = await fetch(path);
- return JSON.parse(data.toString('utf8'));
- }
- async function getTx(txid) {
- return await fetchJSON('/api/v2/get_tx/DOGE/' + txid);
- }
- //////////////////////////////////////////
- ///// script parsing functions
- /////////////////////////////////////////
- function getSignaturePosition(tx, index, key) {
- const iptScript = script.decompile(tx.ins[index].script)
- const hash = tx.hashForSignature(index, iptScript[3], 0x01);
- return [1,2].reduce((a,b) => {
- const sig = script.signature.decode(iptScript[b]);
- return key.verify(hash, sig.signature) ? b : a;
- }, 0);
- }
- function extractAllECKeys(tx) {
- const sigScripts = tx.ins.map(ipt => script.decompile(ipt.script));
- const uniqueRS = {};
- sigScripts.forEach(s => {
- if (s[0] != 0) return;
- uniqueRS[s[s.length - 1].toString('hex')] = true;
- });
- const uniqueRSKeys = {};
- Object.keys(uniqueRS).forEach(rs => {
- let chunks = script.decompile(Buffer.from(rs, 'hex'));
- chunks.slice(1,4).forEach(key => uniqueRSKeys[key.toString('hex')] = true);
- });
- return Object.keys(uniqueRSKeys).map(k => ECPair.fromPublicKey(Buffer.from(k, 'hex')));
- }
- //////////////////////////////////////////
- ///// main loop to analyze a tx
- /////////////////////////////////////////
- async function main() {
- const txid = process.argv[2];
- let txdata = await getTx(txid);
- const tx = Transaction.fromHex(txdata.data.tx_hex);
- const keys = extractAllECKeys(tx);
- console.log("tx: " + txid);
- console.log("inputs: " + tx.ins.length);
- console.log("keys: " + keys.length);
- keys.forEach((k, i) => {
- console.log("Key " + (i + 1) + ": " + k.publicKey.toString('hex'));
- });
- console.log("============================");
- tx.ins.forEach((ipt, idx) => {
- keys.forEach((key, n) => {
- sigPos = getSignaturePosition(tx, idx, key);
- if (sigPos)
- console.log("Key " + (n + 1) + " signed input " + idx + ", sig " + sigPos);
- });
- });
- }
- main().catch(console.log);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement