Advertisement
Guest User

determine signers in a 2-of-3 Dogecoin multisig transaction

a guest
Jan 16th, 2022
204
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /// determine signers in a 2-of-3 Dogecoin multisig transaction
  2. /// uses sochain
  3. /// requirements:
  4. /// node.js and npm
  5. /// npm install bitcoinjs-lib ecpair tiny-secp256k1
  6.  
  7. const https = require('https');
  8.  
  9. const { script, Transaction } = require('bitcoinjs-lib');
  10. const { ECPairFactory } = require('ecpair');
  11. const tinysecp = require('tiny-secp256k1');
  12.  
  13. const ECPair = ECPairFactory(tinysecp);
  14.  
  15. //////////////////////////////////////////
  16. ///// functions to fetch tx from chain.so
  17. /////////////////////////////////////////
  18.  
  19. const HTTPS_OPTIONS = {
  20.   hostname: 'chain.so',
  21.   port: 443,
  22.   method: 'GET'
  23. };
  24.  
  25. function options(path) {
  26.   const out = {};
  27.   Object.keys(HTTPS_OPTIONS).forEach(k => {
  28.     out[k] = HTTPS_OPTIONS[k];
  29.   });
  30.   out["path"] = path;
  31.   return out;
  32. };
  33.  
  34. function fetch(path) {
  35.   return new Promise(function (r,f) {
  36.       opts = options(path);
  37.       const req = https.request(opts, res => {
  38.         const chunks = [];
  39.         if (res.statusCode != 200) {
  40.           return f(new Error("Server returned status " + res.statusCode));
  41.         }
  42.         res.on('data', d => chunks.push(d));
  43.         res.on('end', () => r(Buffer.concat(chunks)));
  44.       });
  45.       req.on('error', e => f(e));
  46.       req.end();
  47.   });
  48. }
  49.  
  50. async function fetchJSON(path) {
  51.   let data = await fetch(path);
  52.   return JSON.parse(data.toString('utf8'));
  53. }
  54.  
  55. async function getTx(txid) {
  56.   return await fetchJSON('/api/v2/get_tx/DOGE/' + txid);
  57. }
  58.  
  59. //////////////////////////////////////////
  60. ///// script parsing functions
  61. /////////////////////////////////////////
  62.  
  63. function getSignaturePosition(tx, index, key) {
  64.   const iptScript = script.decompile(tx.ins[index].script)
  65.   const hash = tx.hashForSignature(index, iptScript[3], 0x01);
  66.   return [1,2].reduce((a,b) => {
  67.     const sig = script.signature.decode(iptScript[b]);
  68.     return key.verify(hash, sig.signature) ? b : a;
  69.   }, 0);
  70. }
  71.  
  72. function extractAllECKeys(tx) {
  73.   const sigScripts = tx.ins.map(ipt => script.decompile(ipt.script));
  74.  
  75.   const uniqueRS = {};
  76.   sigScripts.forEach(s => {
  77.     if (s[0] != 0) return;
  78.     uniqueRS[s[s.length - 1].toString('hex')] = true;
  79.   });
  80.  
  81.   const uniqueRSKeys = {};
  82.   Object.keys(uniqueRS).forEach(rs => {
  83.     let chunks = script.decompile(Buffer.from(rs, 'hex'));
  84.     chunks.slice(1,4).forEach(key => uniqueRSKeys[key.toString('hex')] = true);
  85.   });
  86.  
  87.   return Object.keys(uniqueRSKeys).map(k => ECPair.fromPublicKey(Buffer.from(k, 'hex')));
  88.  
  89. }
  90.  
  91. //////////////////////////////////////////
  92. ///// main loop to analyze a tx
  93. /////////////////////////////////////////
  94.  
  95. async function main() {
  96.   const txid = process.argv[2];
  97.  
  98.   let txdata = await getTx(txid);
  99.   const tx = Transaction.fromHex(txdata.data.tx_hex);
  100.   const keys = extractAllECKeys(tx);
  101.  
  102.   console.log("tx:        " + txid);
  103.   console.log("inputs:    " + tx.ins.length);
  104.   console.log("keys:      " + keys.length);
  105.   keys.forEach((k, i) => {
  106.     console.log("Key " + (i + 1) + ":     " + k.publicKey.toString('hex'));
  107.   });
  108.   console.log("============================");
  109.  
  110.   tx.ins.forEach((ipt, idx) => {
  111.     keys.forEach((key, n) => {
  112.       sigPos = getSignaturePosition(tx, idx, key);
  113.       if (sigPos)
  114.         console.log("Key " + (n + 1) + " signed input " + idx + ", sig " + sigPos);
  115.     });
  116.   });
  117.  
  118. }
  119.  
  120. main().catch(console.log);
  121.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement