BTC: Node.jsでsegwit対応アカウント生成
この記事は最終更新日から1年以上が経過しています。
芽萌丸プログラミング部@programming
投稿日 2021/9/16
更新日 2021/9/16 ✏

BTC: Node.jsでsegwit対応アカウント生成

bitcoinjs-libを使って segwit に対応したBTCアカウント(アドレス、秘密鍵他)を生成するサンプルコードです。

目次:

前提

ランダムなニーモニックを生成

getMnemonic.js

/*
 ランダムなニーモニックを生成

 Usage:

 $ node getMnemonic.js
 */
const bip39 = require('bip39');
const mnemonic = bip39.generateMnemonic(256);
console.log("mnemonic:");
console.log(mnemonic);

実行

## npmモジュールをインストール:
$ npm install --save bip39

## ニーモニックを生成:
$ node getMnemonic.js

mnemonic:
abandon genuine poet car gorilla try need plug arrest orient very salad ramp ...

ニーモニックからBTCアカウントを生成

getAccountsFromMnemonic.js

/*
 ニーモニックからキーペアを派生

 Usage:

 ## メインネット用アカウントを3つ生成:
 $ node getAccountsFromMnemonic.js \
 --mnemonic="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"

 ## テストネット用アカウントを5つ生成:
 $ node getAccountsFromMnemonic.js \
  --mnemonic="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
  --count=5 \
  --testnet
 */
const bitcoin = require('bitcoinjs-lib');
const bip39 = require('bip39');
const bip32 = require('bip32');

let {
  testnet,
  mnemonic,
  count,
} = require('minimist')(process.argv.slice(2));
const network = (testnet) ? bitcoin.networks.testnet : bitcoin.networks.bitcoin; // bitcoin or testnet

if (!mnemonic) {
  console.log("ERROR: --mnemonic オプションでニーモニックを指定して下さい。");
  process.exit(0);
  return;
}
if (!count) count = 3; // デフォルトは3個生成

const seed = bip39.mnemonicToSeedSync(mnemonic);
const root = bip32.fromSeed(seed, network);

for (let len = count, i = 0; i < len; i++) {
  // IMPORTANT: BIP84対応のderivation path。 
  // derivation path は将来的に変わる可能性あり:
  const derivePath = `m/84'/${testnet ? "1'" : "0'"}/0'/0/${i}`; // , "m/44'/0'/0'/0/0", "m/84'/0'/0'/0/0" (segwit)
  console.log("Generating account by derivation path:", derivePath);
  const child = root.derivePath(derivePath);
  // or:
  // const child = root.deriveHardened(84).deriveHardened(testnet ? 1 : 0).deriveHardened(0).derive(0).derive(i);
  console.log("Account #" + i);
  const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: child.publicKey, network });
  const account = {
    address: p2wpkh.address,
    witness: p2wpkh.output.toString("hex"),
    privateKey_wif: child.toWIF(),
    publicKey: child.publicKey.toString("hex"),
    privateKey: child.privateKey.toString("hex"),
    xpub: child.neutered().toBase58(),
    xpriv: child.toBase58(),
  };
  console.log(account);
  console.log("");
}

実行

## npmモジュールをインストール:
$ npm install --save bitcoinjs-lib bip39 bip32 minimist

## 指定したニーモニックでtestnet用のBTCアカウントを3つ生成:
$ node getAccountsFromMnemonic.js --mnemonic="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" --testnet --count=3

Generating account by derivation path: m/84'/1'/0'/0/0
Account #0
{
  address: 'tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl',
  witness: '0014d0c4a3ef09e997b6e99e397e518fe3e41a118ca1',
  privateKey_wif: 'cTGhosGriPpuGA586jemcuH9pE9spwUmneMBmYYzrQEbY92DJrbo',
  publicKey: '02e7ab2537b5d49e970309aae06e9e49f36ce1c9febbd44ec8e0d1cca0b4f9c319',
  privateKey: 'a9c4134b73560f43fc5c081e5c1daa7ce068adc806d80e1f37cb658e0fea4c8d',
  xpub: 'tpubDHPpQL4fzb9hrQZuxDoybkLzpFFCFf65rSGQ3Q73Wc2bfxH6PT5MKK5oHgU68iaRoikGrJiPag1nJx7J7R7uzGBRcVhphzVCZgzyexMLJVJ',
  xpriv: 'tprv8khnFv2RrDU2xwY84a9PCLgtFDjG6KuBH8fckt4k6LECqU2Km4Fm8pTw7Z3vxEKegpWMaR4rPydEzLhnvKt5WFDhFu9b6BbCPJA6ucBMtU2'
}

Generating account by derivation path: m/84'/1'/0'/0/1
Account #1
{
  address: 'tb1qd7spv5q28348xl4myc8zmh983w5jx32cjhkn97',
  witness: '00146fa016500a3c6a737ebb260e2ddca78ba9234558',
  privateKey_wif: 'cQFUndrpAyMaE3HAsjMCXiT94MzfsABCREat1x7Qe3Mtq9KihD4V',
  publicKey: '03eeed205a69022fed4a62a02457f3699b19c06bf74bf801acc6d9ae84bc16a9e1',
  privateKey: '4f9fb140e0586691de963613549631e2048ab4030d74f4d98405686dd30a9d75',
  xpub: 'tpubDHPpQL4fzb9htigiZ3BZFSRUQVVZM8bT9G7N2swUHCQULJRbA1Z7hxEqJJr9g5VhDLDHGrVWrrpGmuZcdHLuMqo7ET2zBzrT6mXBfE4jNZo',
  xpriv: 'tprv8khnFv2RrDU31FevfPWxr2mMqTydBoQYZxWakMuArvc5VpApXcjXXTcy88kMNLRw2u86g9CnLB9tieDDeqrAHH3P5jjb7dHocnkaRqiPMUS'
}

Generating account by derivation path: m/84'/1'/0'/0/2
Account #2
{
  address: 'tb1qxdyjf6h5d6qxap4n2dap97q4j5ps6ua8sll0ct',
  witness: '0014334924eaf46e806e86b3537a12f81595030d73a7',
  privateKey_wif: 'cRe5KDj3rcZJAtZVmWe3G2rdGdXyKCjVbWBVDXqSg2WHq1qq6MNe',
  publicKey: '02339193c34cd8ecb21ebd48af64ead71d78213470d61d7274f932489d6ba21bd3',
  privateKey: '7915c74bbe3a2f3e3e9ef6ba62dd01590102a2e36ad1d0fd4b0329f9f76fa986',
  xpub: 'tpubDHPpQL4fzb9hvejcBLQzx2TqtXmN9ayfRaxgNViP9gdE5oB6jfByQNukWs3MVeHehVhZVd9AKUrBVzJLgkmyMJiioTEKLMPD9gtVLixBthB',
  xpriv: 'tprv8khnFv2RrDU33BhpHgkQYcojKWFRzFnkrHMu5yg5jQpqFJvL7GNPDtHtLkd5Eg12xmFUFnsSkUxF9TrSKd5qi1JYZ2oVopdaKZaFiqX4s1V'
}

PrivateKey(WIF)からBTCアカウントを生成

getAccountFromWif.js

/*
 PrivateKey WIFからアドレスを生成

 Usage:

 メインネット用:
 $ node getAccountFromWif.js --wif=<privateKey_wif>

 テストネット用:
 $ node getAccountFromWif.js --wif=<privateKey_wif> --testnet
 */
const bitcoin = require('bitcoinjs-lib');

let {
  testnet,
  wif,
} = require('minimist')(process.argv.slice(2));
const network = (testnet) ? bitcoin.networks.testnet : bitcoin.networks.bitcoin; // bitcoin or testnet

if (!wif) {
  console.log("ERROR: --wif オプションで PrivateKey(WIF) を指定して下さい。");
  process.exit(0);
  return;
}

console.log("P2WPKH Account:\n", getAccountFromWif(wif, network));

function getAccountFromWif(wif, network) {
  const keyPair = bitcoin.ECPair.fromWIF(wif, network);
  const publicKey = keyPair.publicKey;
  const privateKey = keyPair.privateKey;
  const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: publicKey, network });
  const address = p2wpkh.address;
  const witness = p2wpkh.output;

  return {
    address,
    witness: witness.toString("hex"),
    privateKey_wif: wif,
    publicKey: publicKey.toString("hex"),
    privateKey: privateKey.toString("hex"),
  };
}

実行


## npmモジュールをインストール:
$ npm install --save bitcoinjs-lib bip39 bip32 minimist

## 指定したPrivateKey(WIF)でtestnet用BTCアカウントを取得:
$ node getAccountFromWif.js --wif="cTGhosGriPpuGA586jemcuH9pE9spwUmneMBmYYzrQEbY92DJrbo" --testnet

P2WPKH Account:
 {
  address: 'tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl',
  witness: '0014d0c4a3ef09e997b6e99e397e518fe3e41a118ca1',
  privateKey_wif: 'cTGhosGriPpuGA586jemcuH9pE9spwUmneMBmYYzrQEbY92DJrbo',
  publicKey: '02e7ab2537b5d49e970309aae06e9e49f36ce1c9febbd44ec8e0d1cca0b4f9c319',
  privateKey: 'a9c4134b73560f43fc5c081e5c1daa7ce068adc806d80e1f37cb658e0fea4c8d'
}

以上です。


芽萌丸プログラミング部
芽萌丸プログラミング部@programming
プログラミング関連アカウント。Web標準技術を中心に書いていきます。フロントエンドからサーバサイドまで JavaScript だけで済ませたい人たちの集いです。記事は主に @TanakaSoftwareLab が担当。