NEMの子アカウントを作ろう

NEMの子アカウントを作ろう:

子アカウントとはなんでしょうか?

前回までは何も無いところからアカウントを生成しました。

今回は親アカウントの情報を頼りに子アカウントを生成してみます。

以前にも説明したのですが、今回は後日完成するだろうXEMBook-sdkの設計思想を考慮して解説していきます。

まずはいつも通りの雛形です。

index.html
<!DOCTYPE html> 
<html> 
  <head> 
    <meta charset="utf-8"> 
  </head> 
  <body> 
 
    <!-- Crypto --> 
    <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script> 
    <script src="nacl-fast.js"></script> 
    <script src="keyPair.js"></script> 
    <!-- Utils --> 
    <script src="sha256.js"></script> 
    <script src="bitcoinjs-min.js"></script> 
 
    <!-- app --> 
    <script> 
 
//ここにロジックを挿入していきます。 
 
 
window.document.write("NEMアカウントを生成しました。<br>Private Key:" + privateKey + "<br>Public Key:" + account.publicKey.toString() + "<br>ADDRESS:" + address ); 
 
console.log(privateKey); 
console.log(account.publicKey.toString()); 
console.log(address); 
 
</script> 
  </body> 
</html> 
今回は新たに

sha256.jsとbitcoinjs-min.js

というライブラリを使用します。そうです、あのビットコインのライブラリを使用します。つまりビットコインで定められたルール(BIP)と同じ方法で子アカウントを生成するので、その手法が今後がらりと変わることは考えにくいということです。ビットコインはもはや暗号資産界の歴史の一部となりつつあるようです。

ここに挿入するのは以下のようなロジックです。

挿入
var MASTER_KEY = "NXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; 
 
var networkId = 0x68000000; //MAIN_NET 
var masterHash = getMasterHash(MASTER_KEY,"login_password"); 
var privateKeyBytes = getChildKeyBytes(masterHash,networkId,"m/0"); 
 
var privateKey = Crypto.util.bytesToHex(privateKeyBytes.toByteArrayUnsigned()); 
var account = new KeyPair(privateKey); 
var address = toAddress(account.publicKey.toString(), networkId); 
 
まず、親となる秘密鍵をMASTER_KEYに指定します。

今回はソースコードベタ打ちですが、本来ならばマルチシグでセキュア設定されたものを使用すべきです。

NEMではここで秘密鍵とNEM Walletのログインパスワードを組み合わせてハッシュ値を生み出します。具体的には以下のように2万5千回ぐちゃぐちゃにした後にHMACと呼ばれる手法でNEM Walletのパスワード情報から新しいハッシュ値を生み出しています。

hash
var pk_SHA3_25000 = void 0; 
for (var i = 0; i < 25000; ++i) { 
    pk_SHA3_25000 = CryptoJS.SHA3(MASTER_KEY, { 
        outputLength: 256 
    }); 
} 
 
var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA3, "login_password"); 
hmac.update(pk_SHA3_25000); 
var hash = hmac.finalize(); 
 
前回も説明した通り戻せないようにぐちゃぐちゃにするのですが、今回は親には何回でも同じものを再現できるように手がかりを残しつつぐちゃぐちゃにします。つまりエントロピー等は使用しません。代わりに使用するのがネットワークIDと階層の指定です。

ここでは、親と同じネットワーク(MAIN_NET)と親からの直下という意味で(m/0)という場所に子アカウントを作成します。

ちなみにNEM Walletで(m/0)の場所に作成されるアカウントは委任ハーベストに使用され、m/1 からが子アカウントとなっているようです。

以下のようにhash値を変換していきます。

var il = Crypto.util.hexToBytes(hash.toString().slice(0, 64)); 
var ir = Crypto.util.hexToBytes(hash.toString().slice(64, 128)); 
 
// Create BIP32 object 
var gen_bip32 = new BIP32(); 
// Set BIP32 object properties 
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"); 
// BIP32 version by wallet network 
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); 
}; 
 
ちょっと難しくなってきましたね。

先ほどのハッシュ値の128バイト分をさらに左と右に2分割します。

BIP32に必要なデータをセットしていきます。

ネットワークIDや階層ですね。そのほかはデフォルトといった感じです。

最後に全体を32バイトになるように0埋めして完成です。

生成された子アカウントの秘密鍵はバイト値の配列として出力され、

これからいつも通りの秘密鍵、公開鍵、アドレスに変換することが可能です。

今回、privateKeyではなくprivkeyBytesのバイト配列として秘密鍵を取り出しました。ここにXEMBookの一つの想いがあります。

JavaScriptソースコードの至るところにprivateKeyという変数が放置されるのは、望ましく無い事態が発生するように思います。

マルウェアに感染したPCがメモリダンプされれば、秘密鍵をむき出しにしたソースコードは送金額を書き換えられたり送金先を変更されたり様々な危険性が出てきます。もちろんマルウェアにやられる方も悪いし、秘密鍵をバイト配列で保有してもやられる時はやられます。

マルチシグ運用が最強ではありますが、使う側がまだその段階ではありません。

その可能性を少しでも低くする努力を続けることがサービス提供者としては必要なことだと思います。

XEMBook-sdkはソースコード中の秘密鍵露出を出来るだけ減らし、かつ直感的にどんなソースコードにも組み込みやすいライブラリを目指します。

コメント

このブログの人気の投稿

投稿時間:2021-06-17 22:08:45 RSSフィード2021-06-17 22:00 分まとめ(2089件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)