Audit Process

LEOxChange Proof-of-Reserves Audit Process

Introduction

This document provides background and guidance regarding LEOxChange’s audit process.

LEOxChange holds full reserves, and we employ an independent, cryptographically-verified audit in order to prove to third parties, including our customers, that customer funds are properly held. Transparency and independently verified audits are critical to ensure that companies hold full reserves of customer funds. A public proof-of-reserve scheme is technically possible to implement. However, there are important externalities, user privacy among them, that must be carefully considered in the specific implementation of a public proof-of-reserve scheme. We believe that exchanges and wallets must build trust through accountability and that we bear a responsibility to address the community's desire for transparency.

Over the past several weeks, LEOxChange has successfully developed and completed an industry-leading, independent, cryptographically-verified audit. We are proud to submit this overview of our process to the global digital currency community. We believe that the Bitcoin industry is capable of providing a level of assurance and accountability that surpasses the traditional financial services industry, and we aim to lead the charge toward optimal transparency.

Current Landscape

The impetus for this initiative is Greg Maxwell's proposal for exchanges/wallets to prove their Bitcoin reserves. [1]

To date, audits produced by the Bitcoin industry have been opaque, superficial and without publicly viewable and independently verifiable cryptographic verification. LEOxChange seeks to provide a proof of concept and set industry standards of greater transparency and accountability from the digital currency ecosystem that others can follow and improve upon.

Quality of Process

Maxwell’s proposal would have required bitcoin companies to reveal all of their balance-containing addresses. This method would result in the public knowledge of exchanges’ or wallet providers’ bitcoin wallets and total holdings, information that is commercially sensitive and presents potential security risks to companies and users. Worse, it would result in an impermissible breach of user privacy, in which the history and trajectory of the individual holdings and financial activity could be tracked by third parties without cause or due process.

Our process does not require us to disclose our total balance, addresses, or keys to the public. By combining and leveraging the strengths of both a trusted auditor and publicly-verifiable cryptography, the LEOxChange audit represents the ideal balance between privacy and transparency.

Since Bitcoin is the dominant cryptocurrency, our initial audit will cover only Bitcoin reserves. However, audits for other assets will be considered for future development.

Process Overview

Phase 1 - Auditor checks the funds of LEOxChange’s entire wallet

LEOxChange gives the auditor all of our public addresses and signs them. The block hash at the time of signature is part of the signed message and can be used as a timestamp for when the signature was made. The signatures of those public addresses will then be verified, and the auditor will use the bitcoin blockchain to extract the total amount available at those addresses at a certain point in time.

The code required for this phase was written by Michael Gronager, COO at LEOxChange, and may be open-sourced in the future in its entirety. However, most of the code is already open source because the code is libcoin-based. [2]

Phase 2 - Auditor checks that the balances of LEOxChange users match with the funds of the LEOxChange wallet

LEOxChange gives the auditor the BTC balances of each one of our users and generates a Merkle tree. The auditor will publish the root node hash for all to see, and affirm, if true, that the total holdings represented by the root hash closely approximates the value that he sees in our wallet from the blockchain. This flow also ensures that LEOxChange is not hiding anything in any of the nodes that lead up to the root node.

For this phase of the audit, the auditor will have access to the source code for the tree-generating program and the individual account balances data file. LEOxChange released C++ code for this phase under the MIT License: https://github.com/LEOxChange/LEOxChangedb

Phase 3 - Users independently verify that their account balances were included in the data used by the auditor

LEOxChange gives users the amount that we reported to the auditor, as well as the nodes (and adjacent nodes) from their account to the root (which matches the one published by the auditor). We also disclose the hashing method used to generate the hash for their node, so that they can verify that the node does represent the amount that we claim it does.

This will enable users to independently check for themselves that their account was included in the data verified by the auditor.

Shortcomings

In this section, we describe some of this audit’s shortcoming. Note that this is obviously not an exhaustive list of weaknesses. However, because we value transparency to our users, we are providing informal background on specific shortcomings we have thus far identified in the auditing process.

Unlike physical assets, information need not be removed from one’s possession to be taken into possession by another. Thus, LEOxChange or another company employing this auditing method cannot prove that private keys have not been duplicated by an attacker. We also cannot prove that we have exclusive possession of the audited funds. We can only prove that at the time of the audit, we were one of the possessors of the private keys.

The full audit probably cannot be performed on-demand, without prior notice. Given the required information, structure of the audit, and industry standard cold storage security practices at this time, a surprise same-day audit is not feasible. We envision a potential ‘light’ audit building upon a prior full audit, relying on previously-generated signatures, which may be performed more frequently.

The auditor must be trusted and competent. The community must believe that the auditor values her reputation and is technically capable. There are several opportunities in this audit process where a less technical or less paranoid auditor could be duped by the auditee. There are also opportunities for the auditor to intentionally or inadvertently compromise confidential company and customer information. Both auditor and auditee must consider who provides the computer, the audit space, the blockchain, the Internet connection, the router, DNS, etc. If the goal is to hide a billion-dollar fraud, one can imagine going to great lengths to compromise the audit.

The audit is not continuously renewed in real time. It is possible that keys were lost or funds were stolen since the last audit time. The full audit renews the affirmation that keys have not been lost, though it creates greater threat exposure because it is necessary to utilize the cold storage keys to conduct the audit .

The auditee may be able to borrow funds temporarily or share keys with the true funds owner in order to pass an audit.

The auditor may collude with or succumb to threats from the auditee.

Ongoing Basis

We intend to perform regular audits on an ongoing basis. Since there is no universally trusted auditor, we may use a different auditor, or multiple auditors each time. This satisfies those who may doubt the credentials of a particular individual auditor.

Future Changes and Improvements

We hope to receive feedback from the community that will help us and others to improve this process for future audits. As members of this community, we also hope to work with industry organizations such as DATA (www.datauthority.org) to help develop basic standards, scalable tools and a comprehensive manual for others in the industry to perform similar audits.

References

[1] Summary by Zak Wilcox: https://iwilcox.me.uk/2014/proving-bitcoin-reserves. We want to thank Greg Maxwell for his ideas.

[2] libcoin is the transformation of bitcoin into modular, reusable libraries: https://github.com/libcoin/libcoin

How to verify your individual LEOxChange account balance in the LEOxChange audit

See also: LEOxChange Proof-of-Reserves Audit Process.

These instructions explain how to cryptographically verify your LEOxChange account balance and its inclusion in the audit.

This verification will reflect your account's Bitcoin (XBT) balance at the time of the audit.

Step 1

If you haven't already logged in, log into your LEOxChange account.

Go to https://www.LEOxChange.com/ and ensure that your browser’s address bar shows "https://www.LEOxChange.com/"

Step 2

Click "Funding" tab -> "Audit" subtab -> "Bitcoin (XBT)" on the left.

Step 3

View the information about your account verified by the auditor

  1. The Time of the audit, which is the timestamp used by the auditor.
  2. The Submission code, which is a 64 bit salt.
  3. The Amount of Bitcoins held in your account at the time of the audit. This is the balance value for your account that we provided to the auditor.
  4. Notes include information from the auditor proving the root hash that was used for the audit. A link to a signed, detailed report is also provided.
  5. The Hashes from your node hash to the root hash, including adjacent hashes. Hash values in your direct path are shown with an asterisk (*) to differentiate them from the adjacent node hash. With these hashes, you can verify that your node was included in the root:

    The very first line should match the root hash value given by the auditor.

    If you want to verify your own node hash (the very last hash with a * on the list), do:

    sha256(sha256(<submission code> || ":" || <amount with decimal point removed and leading 0's removed>))

    That value should match the very last value given in the hashes.

    Example code

    Submission code: 379377cd8190f9bf
    Amount: 0.01500000

    Python

    import hashlib;
    print(hashlib.sha256(hashlib.sha256(b'379377cd8190f9bf:1500000').digest()).hexdigest());
    

    PHP

    echo hash('sha256', hash('sha256', '379377cd8190f9bf:1500000', true));

    Result

    66b51ba0f4a5cf8278acac6782ffdfb9a64b9f7c895bc308266b0757c7025b27

    You can fully verify your Merkle branches by doing a hash of each pair of hashes (or “tuple”). The format is:

    sha256(left-hash || right-hash)

    The result should match the preceding tuple hash (or the root hash) with a * in it. This would be done for all tuples.

    With the exception of the root hash, all hashes are given as tuples, representing the left-hash and right-hash in that order. A * is given to the hashes that represent your direct nodes.

    Example code:

    Hashes:

    306daae528dc137c9053554c45e90a631ef859490a3ede651d488135602500a3*
    
    c3fb1f931c681f4a7b779fb19e107bba156cae78c3a928707c42b395b056541b*
    5e01ee0fee85641dd5cd4e3005792f973a2a1362180783041eb1719163b1d21c

    Python

    import hashlib;
    print(hashlib.sha256(b'c3fb1f931c681f4a7b779fb19e107bba156cae78c3a928707c42b395b056541b5e01ee0fee85641dd5cd4e3005792f973a2a1362180783041eb1719163b1d21c'.decode('hex'))).hexdigest();

    PHP

    echo hash('sha256', hex2bin('c3fb1f931c681f4a7b779fb19e107bba156cae78c3a928707c42b395b056541b5e01ee0fee85641dd5cd4e3005792f973a2a1362180783041eb1719163b1d21c'));
    

    Result

    306daae528dc137c9053554c45e90a631ef859490a3ede651d488135602500a3