この記事は株式会社Gincoのテックブログとして書いています。
この記事では、Klaytnにおけるマルチシグアカウントの作成方法を紹介します。弊社プロダクトのGinco Enterprise WalletでもKlaytnを取り扱っています。
Klaytnの概要
Klaytnは、韓国の大手インターネット企業であるカカオが開発したブロックチェーンプラットフォームです。Klaytnは分散型アプリケーション(dApps)の開発や運用に適したプラットフォームを提供し、使いやすさやスケーラビリティに重点を置いています。
KlaytnはEthereum Virtual Machine(EVM)に基づいており、既存のEVMアプリケーションを移行することができます。これにより、既存のEthereumやPolygonなどのEVMチェーンで開発されたアプリケーションを簡単にKlaytnに移行することが可能です。
他のEVMチェーンとの違いは、EthereumやPolygonのようなチェーンではマルチシグ実装にスマートコントラクトを利用する必要があるのに対し、Klaytnではプロトコルレベルでマルチシグに対応している点です。
マルチシグとは
マルチシグ(Multisignature)とは、トランザクションの承認に必要な電子署名のプロセスに、複数の秘密鍵を利用する仕組みのことです。マルチシグは、セキュリティ面で高い信頼性を持つことができるため、ウォレットや取引所などで広く利用されています。
例えば、3人の署名者がいるウォレットで、トランザクションを実行するには2人以上の署名が必要とする2-of-3のマルチシグ構成を考えてみましょう。
この場合、たとえ攻撃者が3つのうちの秘密鍵の1つを窃取できたとしても、残りの秘密鍵のどちらかをさらに窃取しないかぎり、ウォレット内の資産を移動させることはできません。そのため、不正流出のリスクを低減することが可能となります。
次に、Klaytnでのマルチシグアカウントの構成方法について解説していきます。
KlaytnのEOAアカウントの構成
KlaytnにはEOA(Externally Owned Account)アカウントとスマートコントラクトアカウントの2つのアカウントタイプがあります。EOAアカウントは以下のパラメータで構成されています。
パラメータ名 | 概要 |
AccountType | アカウントの種類。EOAアカウントでは”0x1”、スマートコントラクトアカウントでは”0x2”。 |
nonce | トランザクションの順序を決定し、トランザクションの重複処理を防止するために使用される数値。 |
Balance | アカウントが所有している残高。 |
HumanReadable | アカウントのアドレスを任意に変更する機能(Human-Readable Address)。開発中のためnil。 |
Account Key | 署名のために使うキー。EOAアカウントを作成すると、AccountKeyLegacyになっている。 |
Account Keyは、アカウントがトランザクションに署名するために使われるキーで、KlaytnではデフォルトでAccountKeyLegacyとなっています。AccountKeyLegacyは、一つの秘密鍵による署名を許可するシンプルな形式のアカウントキーです。しかし、マルチシグアカウントを作成するには、Account KeyをAccountKeyWeightedMultiSigに変更する必要があります。次のセクションでは、マルチシグアカウントの作成方法について説明します。
参考文献:Klaytn公式ドキュメント - Accounts
マルチシグアカウントの作成方法
Klaytnでは、EOAアカウントからAccountKeyを更新するためのAccountUpdateTxを送信し、Account KeyのタイプをデフォルトのAccountKeyLegacyからAccountKeyWeightedMultiSigに変更することができます。
AccountKeyWeightedMultiSigは、署名に必要なしきい値と重み付けされた公開鍵が保持されているKey Typeです。AccountKeyWeightedMultiSigに追加する公開鍵は、最初に作成したAccountKeyLegacyのものとは異なるものである必要があります。
例えば、2-of-3のマルチシグアカウントを作成する場合、以下の手順に従います
- 秘密鍵1から導出した公開鍵でAccountKeyLegacyのEOAを作成する。 秘密鍵1から導出した公開鍵でAccountKeyLegacyのEOAを作成する。
- 作成したEOAに、AccountUpdateTxに必要な手数料分のKLAYを送金する。
- 秘密鍵2、秘密鍵3、秘密鍵4から新たに導出した公開鍵3つでAccountKeyWeightedMultiSigを作成する(しきい値: 2、それぞれの鍵の重み付け: 1)。
- AccountUpdateTxにAccountKeyWeightedMultiSigを入れる。
- 署名し、RawTxをノードに送信する。 AccountKeyWeightedMultiSigを作成し、AccountUpdateTxをノードに送信する。
手順に従い、golangでの実装例を以下に示します。
package main
import (
"fmt"
"github.com/klaytn/klaytn/accounts/abi/bind"
"github.com/klaytn/klaytn/blockchain/types"
"github.com/klaytn/klaytn/blockchain/types/accountkey"
"github.com/klaytn/klaytn/client"
"github.com/klaytn/klaytn/crypto"
"github.com/klaytn/klaytn/params"
)
func main() {
// 1. 秘密鍵1から導出した公開鍵でAccountKeyLegacyのEOAを作成する。
priKey1, _ := crypto.GenerateKey()
crypto.PubkeyToAddress(*priKey1.PublicKey).String() // "0xabcdefghijk..."
// 2. prvKey1から導出したpubKeyからできたアドレスにAccountUpdateTxを送信するに足りるKLAYを送金する。
// 省略
// 3. 秘密鍵2、秘密鍵3、秘密鍵4から新たに導出した公開鍵3つでAccountKeyWeightedMultiSigを作成する。
priKey2, _ := crypto.GenerateKey()
priKey3, _ := crypto.GenerateKey()
priKey4, _ := crypto.GenerateKey()
weightedKeys := make(accountkey.WeightedPublicKeys, 0, 3) // 2-of-3なので登録するpubKeyの数は3つです。
weightedKeys = append(weightedKeys, accountkey.NewWeightedPublicKey(1, (*accountkey.PublicKeySerializable)(&priKey2.PublicKey))) // 鍵の重み付け: 1
weightedKeys = append(weightedKeys, accountkey.NewWeightedPublicKey(1, (*accountkey.PublicKeySerializable)(&priKey3.PublicKey))) // 鍵の重み付け: 1
weightedKeys = append(weightedKeys, accountkey.NewWeightedPublicKey(1, (*accountkey.PublicKeySerializable)(&priKey4.PublicKey))) // 鍵の重み付け: 1
// 4. AccountUpdateTxにAccountKeyWeightedMultiSigを入れる。
newAccount := &Account{
Address: "0xabcdefghijk...",
AccountKey: accountkey.NewAccountKeyWeightedMultiSigWithValues(uint(2), weightedKeys), // 2人が署名すればOKなので2を設定します。
}
values := map[types.TxValueKeyType]interface{}{
types.TxValueKeyFrom: newAccount.Address,
types.TxValueKeyGasLimit: {GasLimitの値},
types.TxValueKeyGasPrice: {GasPriceの値},
types.TxValueKeyAccountKey: newAccount.AccountKey,
types.TxValueKeyNonce: {Nonceの値},
}
unsignedTx, _ := types.NewTransactionWithMap(types.TxTypeAccountUpdate, values)
// 5. 署名し、RawTxをノードに送信する。
signedRawTx, _ := types.SignTx(unsignedTx, types.NewEIP155Signer(params.MainnetChainConfig.ChainID), priKey1)
client, err := client.Dial("{node url}")
txHash, _ := client.SendTransaction(context.Background(), signedRawTx)
fmt.Printf("Transaction hash: %s\\\\n", txHash.Hex())
}
// Account ...
type Account struct {
Address common.Address
AccountKey accountkey.AccountKey
}
Account KeyのタイプがAccountKeyWeightedMultiSigに更新された後、他のアカウントに送金するには、ValueTransferTxを作成し、登録された公開鍵に対応する秘密鍵(秘密鍵2、秘密鍵3、および秘密鍵4)のうち2つを使って署名を行う必要があります。これにより、送金トランザクションが正常に完了します。
まとめ
本記事では、Klaytnでのマルチシグアカウントの作成方法について紹介しました。マルチシグアカウントは、複数の署名を必要とすることでセキュリティを向上させる重要な機能です。KlaytnはEVMベースのブロックチェーンであり、他のEVMチェーンとの違いを理解することが重要です。
Gincoでは、顧客の資金を管理する上でよりセキュアな方法があるかプロトコルの調査を慎重に行っております。ウォレットについて詳しくなりたい方やブロックチェーンに興味がある方を募集しています。