Appendix of Don't trust, verify the proof of reserves

by Martin Monperrus

tldr; very very few exchanges do proper proof-of-reserve, OkX and BitMEX stand out.

OKx (verifiable)

OKx supports proof-of-reserves. * the official documentation is at https://www.okx.com/help/zero-knowledge-proofs-what-are-zk-starks-and-how-do-they-work (warning: the page is not actively maintained, it contains a few outdated links) * the verification code is available on Github at https://github.com/okx/proof-of-reserves (the code is mix of Go and Python) * the proofs can be downloaded at https://www.okx.com/proof-of-reserves/download * TONCOIN-NEW, BCHN, ETH, UNI, FIL, USDC, EOS, DOT, ETC, RIPPLE, ELF, PEOPLE, SOL, TRX, APTOS, USDT, OKB, BTC, LTC, DOGE, OKT, LINK are supported * the proofs are computed monthly * The OKex team was supportive on Github (see #33 and #34).

Running the verification for OKx

Reserves The reserve data is a big CSV file of 211MB.

The tool to verify reserves is written in Go (cmd/verifyaddress/main.go). It is called as follows:

./build/VerifyAddress  --por_csv_filename okx_por_2024041301.csv/okx_por_2024041301.csv

The verification works as expected.

Liabilities The liabilities data contains many JSON files in a folder sum_proof_data, for 2.2GB. The user data is under “PoR Reports” in the web menu once connected. One copies to clipboard some json data to be put in a local file inclusion_proof.json.

Then, the tool to verify liabilities is a Python script called zk_STARK_Validator.py.

# it expects sum_proof_data and inclusion_proof.json in the current folder
python zk_STARK_Validator.py

It works. However, the documentation is scarce and the tool is not fool proof.

Limitations the private keys only sign a message “I am an OKX address”. This only proves that the key was once in control of OKx, but it may have been lost since then, putting the reserve at risk. It would be better that the message to be signed contains a unique, time-based piece of information, such as a blockhash. Then, the signature would prove that the account was in control of this key as of the creation of this block.

Recommendation: * OKx should sign a message containing a time-based information. * The command line interface of zk_STARK_Validator.py is untuitive, with hard-coded paths, it can be significantly improved.

Bitmex (verifiable)

Bitmex supports proof-of-reserves.

Running the verification for Bitmex

Reserves The proof of assets are in YAML, they can be downloaded on S3 (eg link) The reserves data is a 205kb YAML file, containing bitcoin addresses. Verifying the assets requires a bitcoind node to run. The user is responsible to validate that the public keys belong to BitMEX.

$ python3 validate_reserves.py --proof 20240418-reserves-839754-20240418D100000596047000.yaml --bitcoin mainnet://username:password@localhost:8332

I set up a Bitcoin full node and was able to run the verification. The verification is done against a full node, it is verified that the sum of all utxos matching the Bitcoin descriptors actually contain the claimed balances.

Liabilities The proof of liabilities is in a CSV file of 278 MB. The liability chunks are as the leaves of a merkle sum proof, as a modified version of the Maxwell Proof of Liabilities scheme.

The user inclusion data can be downloaded on BitMex’ “My Account” page, with disclaimer: Proof of Reserves and Liabilities. Your account balance is automatically and pseudonymously incorporated into our Proof of Liabilities dataset. Your Account Nonce is your unique individual identifier within the Proof of Liabilities dataset, which allows you to independently audit that your wallet balance is backed by on-chain assets controlled by exchange private keys. Your Account Nonce cannot be changed and provides the ability to view your past and future account balances as each snapshot is published to anyone who knows the Nonce, so act with caution in sharing this information. You can find more information on our Proof of Reserves & Liabilities dataset here. Reveal Account Nonce and Snapshot

The script to check for liabilities is a short (174 loc) Python program called validate_liabilities.py

python3 validate_liabilities.py --proof liabilities.csv --account 2 --account_nonce b88860add96111d84d38a500266df715158f91375d9aaa98aa58356f9a872412
Number of leaf nodes to scan 8
Hash match for leaf 3 claims 1,294 sats
Hash match for leaf 5 claims 1,706 sats
Validated 3,000 sats for account 2
Total liabilities 4,000,004,000 sats, root hash 85b0a83970a74a6ad0ee5d4bec5d3afe0048d18b8342e31e2d3a45e0f17879c7

It works, I was able to check that my liability is present in the Merkle tree.

The BitMEX team answered my question on Github, see https://github.com/BitMEX/proof-of-reserves-liabilities/issues/18

Recommendation: - The documentation of the proof-of-reserves is scarce, it could be improved. - Bitmex should do proofs of reverves for all crypto they offer, not only Bitcoin.

Kraken (not verifiable)

Kraken claims to provide a proof of reserves, see https://www.kraken.com/proof-of-reserves, and provides a user facing page However, one cannot download the full proof data and the code to verify the proofs is absent. The only file that can be downloaded is a CSV file containing a single path in the Merkle tree for your account, eg Kraken_Audit_PR30NOV23_Merkle_Tree_Path.csv.

One can only click here and there and at some point see a “Success, Found your account details in the merkle tree” or “Your Merkle Leaf ID has been found at Level 25, Position 156114” That’s not a verification. That’s more proof-of-reserve theater.

However, a good idea in the Kraken design is to provide links to third-party auditors. They would be able run the verification for mainstream users (most users don’t understand what is a proof-of-reserve is and do not have the skills to verify it).

Notes: - Kraken does proo-of-reserves for crypto: ADA, BTC, DOT, ETH, USDC, USDT, XRP. - Periodicity: 6 months

Recommendation:

Other cryptoexchanges

Deribit (theater)

Deribit claims to support proof-of-reserves. The official information is available at https://insights.deribit.com/exchange-updates/proof-of-reserves-deribit/. Some data can be downloaded at https://www.deribit.com/statistics/BTC/proof-of-reserves. There is no Github repositories.

Overall, there is no code available to verify the proof of reserves and liabilities, only pseudocode. Like Kraken, this is more a proof-of-reserve theater than a verifiable proof-of-reserves.

gate.io

gate.io has https://github.com/gateio/proof-of-reserves, I have not tested it. Please reach out if you have tested their proof-of-reserves

Discussion

Proof of reserve periodicity

With hot wallets, proofs of reserves can be made very regularly. For example, BitMex does it biweekly.

With cold wallets, signing the proof requires going to cold storage which has a real cost [1]. Then, it’s normal to be done less often. Maybe that’s the reason for which Kraken does a proof of reserve only every 6 months.

Note that Nic Carter’s list claims that some other exchanges, incl. Kraken have proofs-of-reserves. I believe that it is innacurate, for example Kraken provide some “proof of reserve feature” but this is not verifiable.

References

[1] Having a safe CEX: proof of solvency and beyond (2022), Vitalik Buterin, https://vitalik.eth.limo/general/2022/11/19/proof_of_solvency.html
[2] Proof of reserves, Nic Carter, https://niccarter.info/proof-of-reserves/
[3] What Are Proof Of Reserves In Crypto? - Milkroad https://milkroad.com/exchanges/proof-of-reserves/