Kraken Proof-of-Reserves Audit Process
This document provides background and guidance regarding Kraken’s audit process.
Kraken 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, Kraken 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.
The impetus for this initiative is Greg Maxwell's proposal for exchanges/wallets to prove their Bitcoin reserves. 
To date, audits produced by the Bitcoin industry have been opaque, superficial and without publicly viewable and independently verifiable cryptographic verification. Kraken 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 Kraken 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.
Phase 1 - Auditor checks the funds of Kraken’s entire wallet
Kraken 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 Payward, 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. 
Phase 2 - Auditor checks that the balances of Kraken users match with the funds of the Kraken wallet
Kraken 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 Kraken 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. Kraken released C++ code for this phase under the MIT License: https://github.com/payward/krakendb
Phase 3 - Users independently verify that their account balances were included in the data used by the auditor
Kraken 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.
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, Kraken 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.
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.
How to verify your individual Kraken account balance in the Kraken audit
See also: Kraken Proof-of-Reserves Audit Process.
These instructions explain how to cryptographically verify your Kraken account balance and its inclusion in the audit.
This verification will reflect your account's Bitcoin (XBT) balance at the time of the audit.
If you haven't already logged in, log into your Kraken account.
Go to https://www.kraken.com/ and ensure that your browser’s address bar shows "https://www.kraken.com/"
Click "Funding" tab -> "Audit" subtab -> "Bitcoin (XBT)" on the left.Figure 1. Kraken Bitcoin Audit page.
View the information about your account verified by the auditor
- The Time of the audit, which is the timestamp used by the auditor.
- The Submission code, which is a 64 bit salt.
- 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.
- 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.
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.
Submission code: 379377cd8190f9bf
import hashlib; print(hashlib.sha256(hashlib.sha256(b'379377cd8190f9bf:1500000').digest()).hexdigest());
echo hash('sha256', hash('sha256', '379377cd8190f9bf:1500000', true));
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.
306daae528dc137c9053554c45e90a631ef859490a3ede651d488135602500a3* c3fb1f931c681f4a7b779fb19e107bba156cae78c3a928707c42b395b056541b* 5e01ee0fee85641dd5cd4e3005792f973a2a1362180783041eb1719163b1d21c
import hashlib; print(hashlib.sha256(b'c3fb1f931c681f4a7b779fb19e107bba156cae78c3a928707c42b395b056541b5e01ee0fee85641dd5cd4e3005792f973a2a1362180783041eb1719163b1d21c'.decode('hex'))).hexdigest();
echo hash('sha256', hex2bin('c3fb1f931c681f4a7b779fb19e107bba156cae78c3a928707c42b395b056541b5e01ee0fee85641dd5cd4e3005792f973a2a1362180783041eb1719163b1d21c'));