速習Symbolブロックチェーン体験記「とろ速Symbol」です。
「1. はじめに」「2.環境構築」についてはほぼ目を通すだけのため、スキップしました。
本ページでは「アカウント」をやっていきます。
なお、今回はこちらのテストネットノードをお借りしました。
hoge.harvesting-sweet-potatoes.club(Symbol テストネット)
(敬称略)
もちろんメインネットのノードも運用されております。
間違っていたり、問題があったら教えてください。
本稿では「3. アカウント」の実施内容を記載します。
新規作成 – 秘密鍵と公開鍵の導出 – アドレスの導出
アカウントの新規作成を行います。
秘密鍵と公開鍵のキーペアを生成し、そこからアドレスの導出を行います。
また、アドレスの導出にはテストネット or メインネットの属性が必要なようです。
アカウント新規作成
まったく当てにならない僕の自作コードはこちら。
// 使用するホスト情報を取得する。
var availableHost = await _getNetworkHost();
try {
// 新アカウントを生成する。
var newAccount = await _generateNewAccount(availableHost);
return newAccount;
} catch (e) {
debugPrint(e.toString());
debugPrint(StackTrace.current.toString());
throw CreateNewAccountFailedException();
}
※全体像を載せられるようなコードになっていないため、一部分だけです。
色々ありましたが、実行結果としてはこんな感じです。
秘密鍵の導出はさておいて(自分で用意していない部分でもあるので)、
導出された秘密鍵を使ってSymbolSDKから、アドレスを取得しようと思います。
そうすることで秘密鍵 → 公開鍵 → 生アドレス → アドレスの導出が同一であるということの検証とします。
※なお、raw addressと記載してますが、これをraw addressと呼んでいいかはわかりません。が、とりあえずこれで進めます。
なので比較のため、SymbolSDKでも同じことを実行します。
アドレスが同一の”TCY7YADZLU6G34GK7VPGI3EUK2PMS2SDS25QMIA”となっているため、秘密鍵からアドレスの生成までは同一である、ということとしました。
アカウント情報の確認
既に(もう少し先まで)実行した関係上、データがきれいではないのですが。
実行テストを行う上で、alice、bobの秘密鍵は固定で使用していくこととします。(期間が空いた際に毎度やり直すと大変なため)
基本的にaliceのアカウントは上記で行います。
既にトランザクションを実行している関係上、変な値ですがxymは保持されています。
こちらを取得します。
当てにならないコードはこちら。
_startProcessing();
_accountWorker.getAccountAssetsFromAddress(Address("TAEKZ65QU3T4HK3JEEI2SOAHYNPYBUZ7BPC4YAA"))
.then((AccountMosaicProfile accountMosaicProfile) {
print("取得アカウント情報。");
print("address: ${accountMosaicProfile.account.address}");
print("public key: ${accountMosaicProfile.account.publicKey}");
print("所持モザイク情報。");
var account = accountMosaicProfile.account;
var mosaicMap = accountMosaicProfile.mosaicInfos;
for (var mosaic in account.mosaics){
var mosaicDTO = mosaicMap[mosaic.id];
var mosaicAmount = "";
if (mosaicDTO != null && mosaicDTO.divisibility > 0){
var amountStr = mosaic.amount.toString();
var intVal = amountStr.substring(0, amountStr.length - mosaicDTO.divisibility);
var decVal = amountStr.substring(amountStr.length - mosaicDTO.divisibility);
mosaicAmount = "$intVal.$decVal";
}
print("id: ${mosaic.id} amount: $mosaicAmount");
}
})
.whenComplete(_finishProcessing);
実行結果はこちら。
所持モザイク情報が取得できていることが確認できますね。
現場で使えるヒント
暗号化と署名
AliceとBobのみがわかるように、内容を暗号化できるみたいです。
なのでやっていきます。
当てにならないコードはこちら。
// aliceのアカウントを作成する。
var alice = await _accountWorker
.createNewAccountFromPrivateKey("379891A667CBA1C4F9B8DFEBCEE2AE393E4D04D162B9ED3BAB6CA17178*****");
// bobのアカウントを作成する。
var bob = await _accountWorker
.createNewAccountFromPrivateKey("4A570201B9E491F0B1F4BDFE4C1AEED7D75582AAAA7771374FC88DC58C*****");
var baseMessage = "super hogehoge";
var message = PlainMessage.create(baseMessage);
print("メッセージ[$message]を暗号化/復号化。");
// メッセージの暗号化。
var encryptedMessage = await alice.encryptMessage(message, bob.publicAccount);
print("encrypted: ${encryptedMessage.payload}");
// メッセージの復号化。
// 念のため、payloadから暗号化メッセージクラスを別途インスタンス化し、復号化を行う。
var newEncryptedMessage = await EncryptedMessage.create(encryptedMessage.payload, alice.publicAccount);
var decryptedMessage = await bob.decryptMessage(newEncryptedMessage);
print("decrypted: ${decryptedMessage.value}");
print("署名と検証");
// 復号化した内容にaliceが署名する。
var aliceSignature = await alice.sign(decryptedMessage.toByte());
print("aliceSignature: ${aliceSignature.value}");
print("署名を行ったのがaliceなのかを検証する。");
var isVerifiedAlice = await alice.publicAccount.verify(decryptedMessage, aliceSignature);
var isVerifiedBob = await bob.publicAccount.verify(decryptedMessage, aliceSignature);
print("alice: ${isVerifiedAlice ? "yes" : "no" }");
print("bob: ${isVerifiedBob ? "yes" : "no"}");
“super hogehoge”をaliceがbobの公開アカウントに対して暗号化。
bobがaliceの公開アカウント情報に対して復号します。
公開アカウントってなに? っていうと「公開鍵/生アドレス/アドレス」のセットです。
※使用するのは公開鍵なんですけど。
復号した内容への署名を行い、それを検証することで、署名したのがaliceである証明とします。
実行結果はこちら。
こんな感じです。
encryptedが暗号化後のメッセージ、decryptedが復号したメッセージ。
aliceSignatureがaliceの署名です。
検証結果から、aliceが署名したことをうかがえます。
ここでの作りは僕がコーディングしただけのため、実際にSDKと同じなの? ということを確認する必要があります。
が、面倒でもあるため、SDKにて復号と署名の検証のみ行います。
ということで、復号は以下。
bobがaliceの公開情報を使用して復号した結果です。
同様に署名についても証明します。
aliceが署名していることを証明できました。
また自作のコードで暗号化 -> SDKにて復号(署名)も可能であることを確認しました。
アカウントの保管
アカウント項における最後。アカウントの保管についてです。
具体的には秘密鍵は大事な情報のため、ぱっと見ではわからないように暗号化して保管しようぜ! って話です。
使用しているaliceの秘密鍵379891A667CBA1C4F9B8DFEBCEE2AE393E4D04D162B9ED3BAB6CA17178E*****を使用することとします。
ということでまずはSDKを使用して実行します。
こんな感じとなりました。
※QRコード表示はカットとします。
もちろん復号も可能です。
さて、これと同じようなものを実装しました。
※これ、厳密にはSDKに含まれているわけではない気がしますが。
そんなわけで当てにならないコードです。
var alicePrivateKey = PrivateKey("379891A667CBA1C4F9B8DFEBCEE2AE393E4D04D162B9ED3BAB6CA17178E*****");
print("秘密鍵の暗号化");
// パスフレーズ付きで暗号化。
// invest_in_kishidaはPW。
var signerQR = qr.QRCodeGenerator.createExportAccount(alicePrivateKey,
NetworkTypeEnum.testnet,
symbolTestnetGenerationHash, "invest_in_kishida");
var schema = signerQR.getSchema();
var outputObject = await schema.toObject(signerQR);
var printOutputObject = jsonEncode(outputObject);
print("暗号結果。");
print(printOutputObject);
{
print("復号する。");
var decryptedQR = await qr.QRCodeGenerator.fromJson(printOutputObject, password: "invest_in_kishida");
decryptedQR as qr.AccountQR;
print("復号結果。");
print(jsonEncode(decryptedQR.privateKey));
}
{
print("速習Symbolより。Edgeを使用して作成した暗号化メッセージpayloadをdecryptする。");
print("symbol-qr-libraryと等価であることを検証。");
var fromBrowser = '''
{"v":3,"type":2,"network_id":152,"chain_id":"49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4","data":{"ciphertext":"aed4e1b553e02e5a38946db98ebf795bMOiGKwS3VtiQZnIvzBRQ21IQgyAM662tKUMJ3MiI3k/+YYrGC/JVbrvtkN1WfjmLOaBXYIg3dJw6FqdZ0mh80YiOl******....","salt":"d8b4f954c878fb6888cbff896ac1409eb861706d2fd933f4ede030c515148396"}}
''';
var decryptedQR = await qr.QRCodeGenerator.fromJson(fromBrowser, password: "invest_in_kishida");
decryptedQR as qr.AccountQR;
print("復号結果。");
print(jsonEncode(decryptedQR.privateKey));
// 表示するQRコードの取得。
_dispAccountQR = await decryptedQR.toQrImage(null);
}
実行結果はこちら。
こんな感じとなりました。
秘密鍵の暗号化 -> 復号が可能であり、SDKで暗号化した秘密鍵の復号も可能であることから、おそらく、秘密鍵の暗号化、復号が等価である。かもしれない。というところになりました。
一応、QRを表示するのも用意したんですよ。
お見せできないんですけども。
そんなわけで第3章、アカウントについては以上です。
後半の感想編に続きます。