bip39, bip32, bitcoinjs-libでモナコインアドレスを作った。

ブツ

実行

git clone https://github.com/ytyaru/Node.js.bip39.bip32.CreateAddress.20220930162500
node index.js

結果

----- ランダムにニーモニックを作成しそこから鍵やアドレスを作る -----
Mnemonic: together anchor sun horse escape that adjust liquid fog push public decide
address:  MTV5aGR2iUtpwZk8eF5iMZ2RoCdGLzZ1G5
WIF:      TAw58AXrzKPfiEqQnrdgEAjuJWN6QB2z6XmMWckxghbybHacknJG
Public:   0258554521e5adbd84bec56d4d48af9efd8a63a21f2ba733f19066622e526a39a0
Private:  eb25983847d3e896dbb0ca87bbf597c2747fc4904683e68b74988974e2bef8d6
----- ニーモニックから鍵やアカウントを作成する -----
Mnemonic: together anchor sun horse escape that adjust liquid fog push public decide
address:  MTV5aGR2iUtpwZk8eF5iMZ2RoCdGLzZ1G5
WIF:      TAw58AXrzKPfiEqQnrdgEAjuJWN6QB2z6XmMWckxghbybHacknJG
Public:   0258554521e5adbd84bec56d4d48af9efd8a63a21f2ba733f19066622e526a39a0
Private:  eb25983847d3e896dbb0ca87bbf597c2747fc4904683e68b74988974e2bef8d6

WIFは前回ecpairとwifを相互変換してみた通りで、WIFがあれば秘密鍵も復元できる。ニーモニックもWIFと同じく鍵やWIFも復元できるが、さらに英単語など人間にとって覚えやすい文字列になっている。Mpurseでもアドレスを作成するとき保存しろと言われたやつだと思う。12単語なら128、24単語なら256エントロピー。この数値はwif.encodeの第一引数に渡すやつだと思う。

情報源

BIP39は以下のようなものらしい。

人間がわかる単語を紙と鉛筆でメモを取ることでバックアップができるような仕組み

プロジェクト作成

NAME=bip39-address
mkdir $NAME
cd $NAME
npm init -y
npm i bitcoinjs-lib coininfo wif ecpair tiny-secp256k1 bip32 bip39
touch index.js

bip39, bip32パッケージを使うのがポイント。

コード作成

index.js

const bitcoin = require('bitcoinjs-lib');
const coininfo = require('coininfo');
const wif = require('wif');
const ecpair = require('ecpair');
const tinysecp = require('tiny-secp256k1');
const bip39 = require('bip39');
const bip32 = require('bip32').default(tinysecp);

const network = coininfo('MONA').toBitcoinJS();
network.messagePrefix = '';

const path = `m/49'/0'/0'/0` // テストネットなら m/49'/1'/0'/0 
const mnemonic = bip39.generateMnemonic();
const seed = bip39.mnemonicToSeedSync(mnemonic);
const root = bip32.fromSeed(seed, network);

const account = root.derivePath(path);
const node = account.derive(0).derive(0);
const address = bitcoin.payments.p2pkh({ pubkey: node.publicKey, network: network }).address;

console.log(`----- ランダムにニーモニックを作成しそこから鍵やアドレスを作る -----
Mnemonic: ${mnemonic}
address:  ${address}
WIF:      ${node.toWIF()}
Public:   ${node.publicKey.toString('hex')}
Private:  ${node.privateKey.toString('hex')}`);

makeFromMnemonic(mnemonic)
function makeFromMnemonic(mnemonic) {
    console.log('----- ニーモニックから鍵やアカウントを作成する -----')
    const seed = bip39.mnemonicToSeedSync(mnemonic);
    const root = bip32.fromSeed(seed, network);
    const account = root.derivePath(path);
    const node = account.derive(0).derive(0);
    const address = bitcoin.payments.p2pkh({ pubkey: node.publicKey, network: network }).address;
    console.log(`Mnemonic: ${mnemonic}
address:  ${address}
WIF:      ${node.toWIF()}
Public:   ${node.publicKey.toString('hex')}
Private:  ${node.privateKey.toString('hex')}`);
}

アドレスやニーモニックだけでなくWIFや秘密鍵、公開鍵も取得できた。

bitcoinjs-lib、bip32、bip39を使ってビットコインアドレスを生成するを参考にしたが、そこにあったように以下のようなコードにしたらエラーになった。どうやらbip32パッケージのインタフェースが変更されたようだ。

const bip32 = require('bip32');
const root = bip32.fromSeed(seed, network);
TypeError: bip32.fromSeed is not a function

そこでbip32のREADMEを参考にして以下のように修正した。

const tinysecp = require('tiny-secp256k1');
const bip32 = require('bip32').default(tinysecp);
...
const root = bip32.fromSeed(seed, network);

所感

これだけやれば鍵やアドレスまわりのことは何とかなるだろう。次はこの鍵を使って署名したい。