nanowalletに学ぶ、JavaScriptだけでBIP32準拠のNEMアカウントを生成する方法

[前回](http://qiita.com/nem_takanobu/items/298a79385e267804be82)はランダムにNEMアカウントを生成する方法を学びました。
今回はnanowallet にログイン中のアカウント情報を利用して、そこから芋づる式にアカウントを生成する方法を紹介します。

まずこちらをご参考ください。

[ビットコインウォレットのパスフレーズの互換性の話（簡単なHDウォレットの仕組み）](http://www.jpbitcoinblog.info/entry/20160522/1463905035)
[HDウォレット（BIP-32）](http://techmedia-think.hatenablog.com/entry/2017/01/07/142406)

BIP32はHDウォレットの基本規格として位置づけられているようです。
細かな語句の説明は上記URLに説明されているので省略します。

ランダムに生成したアカウントは紛失すれば決して再現できなかったのに対し、BIP32で生成したアカウントはマスターキーさえなくさなければいつでも復元可能です。クライアントが秘密鍵を失くした！と騒ぎたてても、取引所がHDウォレットで生成していればいつでも再発行可能なわけですね。暗号通貨は鍵の管理が難しいと想像されがちですが、エンドユーザには鍵の存在をあまり意識させずに運用することも可能なのかもしれません。

それではソースコードの方を読み解いていきます。
依存するライブラリは以下の通りです。

```html:library
    <script src="vendors/cryptoJS/core-min.js"></script>
    <script src="vendors/cryptoJS/x64-core-min.js"></script>
    <script src="vendors/cryptoJS/ripemd160-min.js"></script>
    <script src="vendors/cryptoJS/sha3-min.js"></script>
    <script src="vendors/cryptoJS/hmac-min.js"></script>
    <script src="vendors/sha256.js"></script>
    <script src="vendors/bitcoinjs-min.js"></script>
```

少し多めです。bitcoinjs-min.js などを使っているところが興味深いですね。
まずはハッシュ値の生成

```js:hash生成

var pk_SHA3_25000 = void 0;
for (var i = 0; i < 25000; ++i) {
    pk_SHA3_25000 = CryptoJS.SHA3("マスターアカウントの秘密鍵", {
        outputLength: 256
    });
}
var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA3, "nanowalletのパスワード");
hmac.update(pk_SHA3_25000);
var hash = hmac.finalize();

var il = Crypto.util.hexToBytes(hash.toString().slice(0, 64));
var ir = Crypto.util.hexToBytes(hash.toString().slice(64, 128));

```

マスターアカウントの秘密鍵とログイン中のnanowalletパスワードの秘密鍵を用いてハッシュ値を出力します。
その値を il とirの半分で割ったところで準備完了です。
次にBIP32の処理を行います。

```js:BIP32
// Create BIP32 object
var gen_bip32 = new BIP32();

gen_bip32.eckey = new Bitcoin.ECKey(il);
gen_bip32.eckey.pub = gen_bip32.eckey.getPubPoint();
gen_bip32.eckey.setCompressed(true);
gen_bip32.eckey.pubKeyHash = Bitcoin.Util.sha256ripe160(gen_bip32.eckey.pub.getEncoded(true));
gen_bip32.has_private_key = true;

gen_bip32.chain_code = ir;
gen_bip32.child_index = 0;
gen_bip32.parent_fingerprint = Bitcoin.Util.hexToBytes("00000000");

gen_bip32.version = 0x68000000;
gen_bip32.depth = 99;

gen_bip32.build_extended_public_key();
gen_bip32.build_extended_private_key();

var result = void 0;
result = gen_bip32.derive("m/0");
var privkeyBytes = result.eckey.priv.toByteArrayUnsigned();
while (privkeyBytes.length < 32) {
    privkeyBytes.unshift(0);
};

```

先ほど生成したハッシュ値から、アカウントに必要な秘密鍵を生成しています。ところどころで追加パラメータが必要になります。今回は"m/0" という場所固定でアカウントを作成しました。

```js:generate
var hexPriv = Crypto.util.bytesToHex(result.eckey.priv.toByteArrayUnsigned());
var account = new KeyPair(hexPriv);
var address = toAddress(account.publicKey.toString(), 104);

```

最後は前回同様、秘密鍵から公開鍵とアドレスを生成します。

どうでしょうか？複雑にはなりますが、こちらで生成するメリットもたくさんありそうです。興味深いところは秘密鍵とnanowalletのパスワード2つを使用している点ですね。もちろん、必ずそうする必要はありません。例えばtwitterやfacebookなどのユニークなアカウント名を入れれば、サービス外からそのアカウントに対してお財布の機能を持たせる、なんてことも可能になります。あ、どこかの取引所がやってましたね。

デジタル空間のまったく新たなところに財布を作り出す方法、そして既存のユニークなものに対して財布を付与させる方法、この２つを使い分ければインターネットであらたな価値の流通が創造できそうですね！

動くページはこちらです
[demo](https://s3-ap-northeast-1.amazonaws.com/nemtest/account_generate_hd.html)

何故、JavaScriptにこだわるのか？それはアプリが広まらないと流通しない通貨はハードルが高すぎると思うからです。そして、NEMはこれから紹介する送金処理やその他の処理がほぼすべてJavaScriptで実現できてしまいます。Node.jsもAzureも必要ありません。もちろん最後にはセキュリティが課題になってくるとは思いますが、とりあえず暗号通貨の面白さを世界一敷居の低い言語で感じてもらえたらと思います。

それでは！

----
以下のNEMアドレスは、全てNEM上でエンジニアが活動できるための資金に使用します。
これから私が書く記事に共感していただけましたら、ご寄附いただけると助かります。
NEM ADDRESS: NBZNQL-2JDWTG-UAW237-PXV4SS-XSPORY-43GUSW-GSB7