LoginSignup
4
2

symbol-sdk@3.1.0でウォレット対応の暗号化メッセージを送る

Last updated at Posted at 2023-11-08

はじめに

以前、symbol-sdkのv3.0.7で、転送トランザクションを作成した際、暗号化メッセージがウォレットで復号できないことがありました。

その記事のコメント欄に、 @Toshi_ma さんからこんなコメントを頂いておりました。

sdk v2ではRawMessageやEncryptoMessageをなぜか二重に16進数にしていました

そのため、メッセージ周りについては諦めていたのですが、このたび、symbol-sdkのアップデートでそのあたりができるようになったみたいです。

symbol-sdkのv3.0.11のリリースノートを見てみます。

(Symbol-only) special handling for encrypted messages created by Symbol wallets

special handlingとは何なのかについて、コミットを追ってみてみます。

おそらくはこのコミットなのですが、tryDecodeDeprecatedencodeDeprecated が追加されているようです。

なので、この処理を使うことでウォレットでメッセージを読んだり、ウォレットで送ったメッセージが読めるようになったりするのではないかと思いました。

それでは試してみましょう。

ウォレットでメッセージを読む

symbol-sdkで暗号化メッセージを作成し、トランザクションを送信します。そのトランザクションをウォレットで開いてみます。

TypeScriptのコードを示します。symbol-sdkはv3.1.0を使用しています。

import symbolSdk from 'symbol-sdk'
import axios from 'axios'
import { TextEncoder } from 'util';

const NODE_URL = process.env.NODE_URL
const PRIVATE_KEY = process.env.PRIVATE_KEY
const PUBLIC_KEY_RECEIVER = process.env.PUBLIC_KEY_RECEIVER

const network = symbolSdk.symbol.Network.TESTNET
const deadline = network.fromDatetime(new Date(Date.now() + 60000)).timestamp

const facade = new symbolSdk.facade.SymbolFacade(network.name)

const privateKey = new symbolSdk.PrivateKey(PRIVATE_KEY)
const keyPair = new symbolSdk.symbol.KeyPair(privateKey)

const currencyMosaicId = 0x72C0212E67A08BCEn

ここから暗号化メッセージの作成に入ります。encodeDeprecatedを使用します。

const textEncoder = new TextEncoder();
const messageEncoder = new symbolSdk.symbol.MessageEncoder(keyPair);
const message = messageEncoder.encodeDeprecated(
    new symbolSdk.PublicKey(PUBLIC_KEY_RECEIVER),
    textEncoder.encode('sample message')
)

JSDocに@deprecatedがついているためでしょうか、エディター上では取り消し線がつきました。

image.png

あとはトランザクションを作って送信します。

const transaction = facade.transactionFactory.create({
    type: 'transfer_transaction_v1',
    signerPublicKey: keyPair.publicKey.toString(),
    fee: 1000000n,
    deadline,
    recipientAddress: 'TARDV42KTAIZEF64EQT4NXT7K55DHWBEFIXVJQY',
    mosaics: [{ mosaicId: currencyMosaicId, amount: 1000000n }],
    message
})

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = symbolSdk.symbol.SymbolTransactionFactory.attachSignature(transaction, signature)
const hash = facade.hashTransaction(transaction).toString();

await axios.put(`${NODE_URL}/transactions`, JSON.parse(jsonPayload));

さて、このトランザクションをウォレットで開いてみます。上記のコードで使用したアカウントをウォレットにもインポートしておきます。

メッセージ欄は、暗号化メッセージを示す******になっています。

image.png

Decryptボタンを押して復号してみます。

image.png

無事復号することができました。

ウォレットから送信したメッセージを読む

次は、ウォレットで暗号化メッセージを含んだ転送トランザクションを作成し、そのメッセージをsymbol-sdkで復号してみます。

まずはウォレットで暗号化メッセージを含んだトランザクションを作成し送信します。

image.png

次にTypeScriptのコードを示します。symbol-sdkはv3.1.0を使用しています。

import symbolSdk from 'symbol-sdk'
import axios from 'axios'

const NODE_URL = process.env.NODE_URL
const PRIVATE_KEY = process.env.PRIVATE_KEY
const PUBLIC_KEY_RECEIVER = process.env.PUBLIC_KEY_RECEIVER

const hash = 'D642F3D6394850362EC0F9C4B31F2C3F37391864C9EFC19AC987CBC405E560A5'

const transactionResponse = await axios.get(`${NODE_URL}/transactions/confirmed/${hash}`)
const encryptedMessage = transactionResponse.data.transaction.message

const privateKey = new symbolSdk.PrivateKey(PRIVATE_KEY)
const keyPair = new symbolSdk.symbol.KeyPair(privateKey)

const messageEncoder = new symbolSdk.symbol.MessageEncoder(keyPair);

const messageDecoded = messageEncoder.tryDecodeDeprecated(
    new symbolSdk.PublicKey(PUBLIC_KEY_RECEIVER),
    symbolSdk.utils.hexToUint8(encryptedMessage)
)

const textDecoder = new TextDecoder();
console.log(textDecoder.decode(messageDecoded.message));

tryDecodeDeprecatedを使用しています。こちらも取り消し線が付きました。

image.png

これを実行します。

image.png

ちゃんと復号できました。

平文メッセージは問題なし

おまけ。平文のメッセージのほうも見ていきましょう。

結論から言うと、symbol-sdkで送った平文メッセージは、special handlingをすることなくウォレットで開くことができました。

以下のように、先頭に0x00を付けることが必要です。

const textEncoder = new TextEncoder();
const message = new Uint8Array([0x00, ...textEncoder.encode('あいうえお')]);

ウォレットで開くことができます。

image.png

次に、ウォレットで送ったメッセージをsymbol-sdkで開いてみます。

ウォレットでは、このように送りました。

image.png

さて、まずは

const hash = "<your_transaction_hash>"
const transactionResponse = await axios.get(`${NODE_URL}/transactions/confirmed/${hash}`)
const plainMessageHex = transactionResponse.data.transaction.message
console.log(plainMessageHex)

このコードを実行すると、以下のようにでてきます。

00E3818BE3818DE3818FE38191E38193

先頭の1バイトの0x00は、平文メッセージを意味するヘッダーになります。「か」はUTF-8ではE3818Bであることからもわかります。

ですので、以下のように先頭バイトを取り除く必要があります。

const plainMessageUint8 = symbolSdk.utils.hexToUint8(plainMessageHex)
console.log(textDecoder.decode(plainMessageUint8.slice(1)))

これらを実行すると、

かきくけこ

と出力されました。

おわりに

以前できなかったウォレットにおける暗号化メッセージのやりとりができるようになりました。

非推奨のマークが付けられていますが、それ専用のメソッドを使うことで実現していることがわかりました。

これで新しいsymbol-sdkでも、過去のメッセージを読むことができるようになりました。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2