Counterwallet 12-word passphrase作成〜ビットコインアドレスの残高表示までの流れ
はじめに
Counterwalletを初めて使うときはまず12-wordのパスフレーズを作成して、そのパスフレーズを使ってログインします。
パスフレーズを元に作成したビットコインアドレスと、wallet_idと呼ばれる設定情報を保存するためのIDだけがクライアントとサーバーでやりとりされ、パスフレーズや秘密鍵はサーバーに送信されません。
今回はそのあたりについて書きます。
目次
- 12-word passphrase作成
- 12-word passphraseからwallet_idを生成
- 12-word passphraseからビットコインアドレスを生成
- サーバーとの通信
12-word passphrase作成
logon.jsのgeneratePassphraseメソッドからMnemonicメソッドが呼ばれます。Mnemonicメソッドは、mnemonic.jsで定義されています。
self.generatePassphrase = function() { var m = new Mnemonic(128); //128 bits of entropy (12 word passphrase) var words = m.toWords(); self.generatedPassphrase(words.join(' ')); //select the generated passphrase text selectText('generated'); }
mnemonic.jsの使い方は、folk元のmnemonic.jsが参考になります。
また、mnemonic.js作者の@ggozadによるこのスライドに、どうしてmnemonicパスフレーズを使用すべきか書いてあります。以下は抜粋です。
- 設定するパスワードのルールが明確。(一般の方法は、サイトによって大文字や数字を含めないといけないなど独自のルールが存在して分かりにくい)
- 覚えやすい1626通りの単語からフレーズが生成される。(記憶間違いを防げます)
- 3単語で32-bit integer、12単語の組み合わせで128-bit integerのentropyが実現可能。
12-word passphraseからwallet_idを生成
logon.jsのopenWalletメソッドでwallet_idを生成しています。
// generate the wallet ID from a double SHA256 hash of the passphrase and the network (if testnet) var hashBase = CryptoJS.SHA256(self.sanitizedEnteredPassphrase() + (USE_TESTNET ? '_testnet' : '')); // sanitizedEnteredPassphrase()は、小文字にしてtrimしています var hash = CryptoJS.SHA256(hashBase).toString(CryptoJS.enc.Base64); WALLET.identifier(hash); $.jqlog.log("My wallet ID: " + WALLET.identifier());
wallet_idはCounterwalletの設定(色の設定など)や、多重ログインの有無チェックのために利用され、MongoDB内に保存されます。Bitcoinの送信やCounterpartyのAssetに対する変更などクリティカルなところでは使用されません。
12-word passphraseからビットコインアドレスを生成
wallet_id作成後、規約画面が表示され、それに同意すると12-word passphraseからビットコインアドレスを生成します。
logon.jsのopenWalletPt2メソッド内でCWHierarchicalKeyが初期化されます。
self.openWalletPt2 = function(mustSavePreferencesToServer) { WALLET.BITCOIN_WALLET = new CWHierarchicalKey(self.enteredPassphrase()); WALLET.isOldWallet(WALLET.BITCOIN_WALLET.useOldHierarchicalKey); setTimeout(function() { self.genAddress(mustSavePreferencesToServer, PREFERENCES['num_addresses_used']) }, 1); }
CWHierarchicalKeyはutil.bitcore.jsに定義されてます。(以下メソッドはだいぶ省略してます)
CWHierarchicalKey.prototype.init = function(passphrase) { this.passphrase = passphrase; var seed = this.wordsToSeed(words); this.HierarchicalKey = this.useOldHierarchicalKey ? this.oldHierarchicalKeyFromSeed(seed) : bitcore.HierarchicalKey.seed(seed, NETWORK.name); }
logon.jsのgenAddressメソッドでビットコインアドレスが生成されます。
self.genAddress = function(mustSavePreferencesToServer, addressCount) { var moreAddresses = []; for (var i = 0; i < addressCount; i++) { var address = WALLET.addAddress('normal'); var addressHash = hashToB64(address); var len = WALLET.addresses().length; moreAddresses.push(address); ...
サーバーとの通信
クライアントとサーバー間で以下APIがやりとりされます。APIは全てcounterblockd APIです。詳細は別途書きます。
1. wallet_id取得前
- is_ready
2. wallet_id取得後
- is_wallet_online {'wallet_id': WALLET.identifier()}
- get_preferences {'wallet_id': WALLET.identifier(),'network': USE_TESTNET ? 'testnet' : 'mainnet','for_login': true}
3. ビットコインアドレス取得後
- get_num_users_online
- get_chain_address_info {addresses: ["19wcJfJR2uSw5mf6yRdHhdifnJTZAJJdRz"], with_uxtos: true, with_last_txn_hashes: 5}
- store_preferences {'wallet_id': WALLET.identifier(), 'preferences': PREFERENCES, 'network': USE_TESTNET ? 'testnet' : 'mainnet', 'referer': ORIG_REFERER }
- get_normalized_balances {addresses: ["1AG4JA3oDNunXmTYH4PmG6eAbRZRfSQd2y"]}
まとめ
次回はビットコインの送信処理の流れを見てみます。
補足
Mnemonic Code Converter @bip39ってジョナサンかな