自分の資産がMerkle Treeに登録されているか調べる方法
Merkle Treeとは
Merkle Treeはハッシュ木とも呼ばれ、データ構造の一つで通常は2分木であり、葉ノードから最上位の根ノードまで特定の方法でハッシュ値を層ごとに計算するものです。
CoinEx Merkle Treeの定義
ノード情報
各ツリーノードに格納されている情報は以下の通りです。1. ノードのハッシュ値 2. ユーザー資産のスナップショットによってカバーされるコインの数(例として、BTC、ETH、USDTなど)。
ハッシュ値{"BTC":"BTC残高","ETH":"ETH残高","USDT":"USDT残高"}
3d101072de66342c711e369e1e98f48c89c412e7246918ae6466a5c72e73003d{"BTC":"1.023","ETH":"0.56","USDT":"20.2343322"}
3d101072de66342c711e369e1e98f48c89c412e7246918ae6466a5c72e73003d{"BTC":"1.023","ETH":"0.56","USDT":"20.2343322"}
ハッシュルール
葉ノード
hash = SHA256(nonce + balances)
例:
hash = SHA256('79b0319c0003e6b5f149525a6677f1bcb7851e9bd7bf05c7089576d38dd95efa{"BTC":"1.023","ETH":"0.56","USDT":"20.2343322"}')
このうち、CoinExは各ユーザーに固有のナンス(nonce)を割り当て、監査データで照会できるようにします。一方「残高」は、ユーザーの資産スナップショットがカバーするコイン数からなるjson文字列で、次のようなものです。{BTC": "1.023", "ETH": "0", "USDT": "20.2343322"} 。以下のルールに従った形で指定します。
1. json文字列は、改行や空白のないコンパクトな形式です。
2. コイン数量の末尾にある無効な0を削除し、8桁の精度を保持します。
3. コイン名はアルファベット順にソートされています。
1. json文字列は、改行や空白のないコンパクトな形式です。
2. コイン数量の末尾にある無効な0を削除し、8桁の精度を保持します。
3. コイン名はアルファベット順にソートされています。
親ノード
hash = SHA256(h1 + h2 + balances)
· h1: 左側の子ノードのハッシュ値
· h2: 右側の子ノードのハッシュ値
· balances: 左側の子のbalances+右側の子のbalances、同じ資産の残高を足し合わせたもの
· h2: 右側の子ノードのハッシュ値
· balances: 左側の子のbalances+右側の子のbalances、同じ資産の残高を足し合わせたもの
例:
左側の子ノード
3d101072de66342c711e369e1e98f48c89c412e7246918ae6466a5c72e73003d{"BTC":"1.023","ETH":"0.56","USDT":"20.2343322"} 右側の子ノード:
e9fcf13c9cdae1dfab4c2ea60d8acb62603b5f8430e265bf4b3f901fc4e45fe9{"BTC":"0.48","USDT":"100.24534"} 親ノードのハッシュ:
hash = SHA256(3d101072de66342c711e369e1e98f48c89c412e7246918ae6466a5c72e73003d3d101072de66342c711e369e1e98f48c89c412e7246918ae6466a5c72e73003d{"BTC":"1.023","ETH":"0.56","USDT":"20.2343322"})
パディングノードのルール
完全なMerkle Tree(フルバイナリ)を構築するには2^n個の葉ノードのデータが必要ですが、実際のデータ数は十分でない場合や偶数の場合があります。この場合ノードkが兄弟ノードを持たない場合、paddingは自動的に兄弟ノードk'を生成し、この兄弟ノードhash(k')=hash(k)、ノードk'のコイン枚数は全て0となるように設定します。
例:ノードK
3d101072de66342c711e369e1e98f48c89c412e7246918ae6466a5c72e73003d{"BTC":"1.023","ETH":"0.56","USDT":"20.2343322"}
親ノードのハッシュ:
hash = SHA256(3d101072de66342c711e369e1e98f48c89c412e7246918ae6466a5c72e73003d3d101072de66342c711e369e1e98f48c89c412e7246918ae6466a5c72e73003d{"BTC":"1.023","ETH":"0.56","USDT":"20.2343322"})
検証ルール
1. 検証の原理 Merkle Treeの定義によれば、ユーザ自身の葉ノードから親ノードのハッシュ値を計算しルートノードのハッシュ値が得られるまで、ルートノードのハッシュ値を比較します。両者が等しい場合は検証を承認し、等しくない場合は検証を失敗とします。
2. 例えば以下のjsonテキストでは、まず自己のデータを元に葉ノードのハッシュを計算し、次にパス上の各兄弟ノードと親ノードのハッシュを計算し、結果のノードハッシュはルートノードのハッシュと等しいバランスになるはずです。(兄弟ノードが空白を表示する場合は兄弟ノードが存在せず、パディングノードのルールに従って親ノードのハッシュが計算されることに注意してください)
2. 例えば以下のjsonテキストでは、まず自己のデータを元に葉ノードのハッシュを計算し、次にパス上の各兄弟ノードと親ノードのハッシュを計算し、結果のノードハッシュはルートノードのハッシュと等しいバランスになるはずです。(兄弟ノードが空白を表示する場合は兄弟ノードが存在せず、パディングノードのルールに従って親ノードのハッシュが計算されることに注意してください)
Merkle Treeのパスデータ(json text):
{
"root": {
"balances": {
"CET": "14373493.24153457",
"ETH": "104543541.61407674",
"USDC": "2419089.97192761",
"USDT": "4836955256.81519091"
},
"hash": "c01a6c3b0fedde2a066f8a38968e40420c0b0742bb4ccda571a4349fb1c64f18"
},
"self": {
"balances": {
"USDT": "3990000"
},
"nonce": "9885b5df557ba3cec41a74347719a8a37d5792a1cf7f0e216510d60dd1b1fc95"
},
"path": [
{
"balances": {
"CET": "10000.01994324",
"USDC": "40000",
"USDT": "1004.13066254"
},
"hash": "01f94322a74bee4431b809406997cee575bed3b85ef36b4ba3b2ff9dd140f99a",
"pos": "left"
},
{
"balances": {
"CET": "1000",
"ETH": "0.90765244",
"USDT": "143151.30772787"
},
"hash": "c99051749a3a83e60d1338454382044f9d7236928cfdc4b7fca1a7cc7450c7a6",
"pos": "left"
},
{
"balances": {
"CET": "548800.95984406",
"ETH": "50000.00001068",
"USDC": "9986.281143",
"USDT": "62752.29303779"
},
"hash": "173a9a7ef562f1b537def5d58167d7402c8e268b1423c5f8e1d806cd0c524344",
"pos": "left"
},
{
"balances": {
"CET": "10023.01105146",
"ETH": "9900.74253772",
"USDT": "22516389.78119662"
},
"hash": "d79bd6c7a1536db199747061c119f98f86d99f9c7a8350fe63c6314ef3e8a24c",
"pos": "right"
},
{
"balances": {
"CET": "5393361.46905487",
"ETH": "23711.51394236",
"USDC": "201404.61667184",
"USDT": "230211961.3159725"
},
"hash": "115551fd3f85328d32858cc6d1bea9c1274984b0f8abba8140752f9d55e48277",
"pos": "left"
},
{
"balances": {
"CET": "1554146.8440552",
"ETH": "100.0040003",
"USDC": "160006.6",
"USDT": "11201397.46983634"
},
"hash": "7b92897456af56f473b75d5e009be090726ad64694fd27971dc46f2631db51d8",
"pos": "right"
},
{
"balances": {
"CET": "4712634.46013087",
"ETH": "91469.27009748",
"USDC": "1002463.00913027",
"USDT": "830313049.62523756"
},
"hash": "0905786187f2c582902b84175813b063c31755a2930b25dee7ba005f7c8a7cf9",
"pos": "right"
},
{
"balances": {
"CET": "2143526.47745487",
"ETH": "104368359.17583576",
"USDC": "1005229.4649825",
"USDT": "3738515550.89151969"
},
"hash": "41dc5da7477fab3ac6fe233a1bf1bec0d26d0f5dea679b5d91f2f09c488fcb2f",
"pos": "right"
}
]
}認証ステップ
1. CoinExアカウントにログインし「Proof of Reserve」をクリックします。ページに入り「私の監査をコピーする」をクリックします。
2. コピーした監査データを merkle_proof_file.json などのテキストファイルに貼り付けます。
3. CoinExが提供する[オープンソース検証ツール]をダウンロードする。
4. 検証ツールを解凍し、解凍したファイルと merkle_proof_file.json を ~/Downloads/proof-of-reserves などの同じフォルダに入れます。
5. ターミナル(MacOS: Terminal App; Windows: Terminal or PowerShell)を開き、cd ~/Downloads/proof-of-reserves と入力し、上記のディレクトリに移動します。
6. 以下のコマンドを入力し、データの検証を行います。MacOS / Linux:
./proof-of-reserves -f merkle_proof_file.json
Windows:
./proof-of-reserves.exe -f merkle_proof_file.json
7. 検証が承認されると、プロンプトに Merkle tree path validation passed と表示されます。
また、このドキュメントに記載されている手順や[オープンソース検証ツールのソースコード]を参考に、独自の検証ツールを作成することも可能です