Great just isn't good enough.

毎日が楽しいなんて、毎日楽しくないのと同じ

nemのアプリケーション作成 Part2

以前の記事で、nemのウォレットを作成することにすると宣言しました。 seika0pom.hatenablog.com 第2回では、ウォレットの作成で欠かせない秘密鍵と公開鍵の生成についてNanoWalletを調べてみることにします。 NanoWalletを参照するには、GitHubからソースを落としてくる必要があります。 その方法はここでは割愛します。 対象のリポジトリは以下となります。 github.com

まずはウォレット生成時に呼び出されるであろう関数を確認します。 以下の関数では、ランダムの数値から秘密鍵を作成し、そこから公開鍵を作成していることがわかります。

[walletBuilder.service.js]

createWallet(walletName, walletPassword, network) {
        return new Promise((resolve, reject) => {
            if (!walletName || !walletPassword || !network) {
                return reject("Missing parameter");
            }
            // Create private key from random bytes
            //  [nekokoコメント]ua2hexという関数がconvert.jsに定義されておりそれを呼び出しています。こんな感じでどんどん追って行くといいです。
            let r = convert.ua2hex(nacl.randomBytes(32));
            // Create KeyPair from above key
            let k = KeyPair.create(r);
            // Create address from public key
            //  [nekokoコメント]オリジナルコメント通りですが、公開鍵を元にアドレスを生成しています。
            let addr = Address.toAddress(k.publicKey.toString(), network);
            // Encrypt private key using password
            let encrypted = CryptoHelpers.encodePrivKey(r, walletPassword);
            // Create bip32 remote amount using generated private key
            return resolve(CryptoHelpers.generateBIP32Data(r, walletPassword, 0, network).then((data) => {
                    // Construct the wallet object
                    let wallet = this.buildWallet(walletName, addr, true, "pass:bip32", encrypted, network, data.publicKey);
                    return wallet;
            },
            (err) => {
                this._$timeout(() => {
                    this._Alert.createWalletFailed(err);
                    return 0;
                }, 0)
            }));
    });
}

上記のソースを順に追っていくと、アドレス生成までたどり着くかと思います。 アドレスは公開鍵を元に生成しているのが以下を参照すれば確認できました。

[Address.js]

let toAddress = function(publicKey, networkId) {
    let binPubKey = CryptoJS.enc.Hex.parse(publicKey);
    let hash = CryptoJS.SHA3(binPubKey, {
        outputLength: 256
    });
    let hash2 = CryptoJS.RIPEMD160(hash);
    // 98 is for testnet
    let networkPrefix = Network.id2Prefix(networkId);
    let versionPrefixedRipemd160Hash = networkPrefix + CryptoJS.enc.Hex.stringify(hash2);
    let tempHash = CryptoJS.SHA3(CryptoJS.enc.Hex.parse(versionPrefixedRipemd160Hash), {
        outputLength: 256
    });
    let stepThreeChecksum = CryptoJS.enc.Hex.stringify(tempHash).substr(0, 8);
    let concatStepThreeAndStepSix = convert.hex2a(versionPrefixedRipemd160Hash + stepThreeChecksum);
    let ret = b32encode(concatStepThreeAndStepSix);
    return ret;
};

上記のソースでは、以下の処理を行っているのがわかります。

(1)256-bit sha3を公開鍵に適用

let binPubKey = CryptoJS.enc.Hex.parse(publicKey);
    let hash = CryptoJS.SHA3(binPubKey, {
        outputLength: 256
    });

(2)160bit Ripemdハッシュを適用

let hash2 = CryptoJS.RIPEMD160(hash);

(3)バージョン番号のバイトを先頭に付加(0x68または0x98)

let networkPrefix = Network.id2Prefix(networkId);

(4)256-bit sha3をもう一度適用し、先頭4バイトをチェックサムとする

let versionPrefixedRipemd160Hash = networkPrefix + CryptoJS.enc.Hex.stringify(hash2);
    let tempHash = CryptoJS.SHA3(CryptoJS.enc.Hex.parse(versionPrefixedRipemd160Hash), {
        outputLength: 256
    });
    let stepThreeChecksum = CryptoJS.enc.Hex.stringify(tempHash).substr(0, 8);

(5)(3)の結果とステップ4のチェックサムを結合

let concatStepThreeAndStepSix = convert.hex2a(versionPrefixedRipemd160Hash + stepThreeChecksum);

(6)最終結果をbase32でエンコード

let ret = b32encode(concatStepThreeAndStepSix);

この流れでアドレスの生成を行っています。 暗号理論とかは難しく理解するのに時間がかかるので、そこは後回しでアドレスを生成するには (1)〜(6)の手順を行えば良いということがわかります。 この生成方法を真似て他のアプリ作成もできるかと。

このソースコードを参考にするには、もう少し細かく他のメソッド等も確認する必要がありますが 大まかな流れは掴めたので、オリジナルウォレット作成に向けて一つ前進できたかと思います。

以上。次回は簡単なUIを作成してそこから鍵の作成を行えるようにしてみます。

では!

広告を非表示にする
日本で一番簡単にビットコインが買える取引所 coincheck bitcoin