自分の資産が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 と表示されます。
また、このドキュメントに記載されている手順や[オープンソース検証ツールのソースコード]を参考に、独自の検証ツールを作成することも可能です