Kraken

Proof of Reserves

Kraken Proof of Reserves

Our Commitment to Transparency

At Kraken, we don’t just let you trade cutting-edge digital assets, we’re working to maximally leverage the transparency of the open-source blockchains on which they operate.

Our regular Proof of Reserves audits make it easy for clients to verify the balances they hold are backed by real assets, all with just a few easy clicks in their account.

An advanced cryptographic accounting procedure conducted semi-annually by trusted auditors, Proof of Reserves lets you verify that Kraken is meeting rigorous standards for accountability and exceeding the transparency offered by legacy financial firms.

What is Proof of Reserves?

A Proof of Reserves (PoR) is an independent audit conducted by a third party which seeks to ensure that a custodian holds the assets it claims to on behalf of its clients. This auditor takes an anonymized snapshot of all balances held and aggregates them into a Merkle tree — a privacy-friendly data structure that encapsulates all client balances.

From there, the auditor obtains a Merkle root: a cryptographic fingerprint that uniquely identifies the combination of these balances at the time when the snapshot was created.

Merkle Root Hash

The auditor then collects digital signatures produced by Kraken, which prove ownership over the on-chain addresses with publicly verifiable balances. Lastly, the auditor compares and verifies that these balances exceed or match the client balances represented in the Merkle tree, and therefore that the client assets are held on a full-reserve basis.

Any client can independently verify that their balance was included in the Proof of Reserves audit by comparing select pieces of data with the Merkle root. Any changes made to the rest of the data, however small, will affect the root – making tampering obvious.

Verifying that your account was audited

Follow the steps below to cryptographically verify the inclusion of your Kraken account balance in the most recent Proof of Reserves.

Note: This verification will only reflect your account's balances in the supported assets at the time of the audit. It will not reflect any subsequent trades or transactions, nor will it reflect balances held in assets that are not covered by the audit.

1. Log in to your Kraken account and navigate to your account settings (Settings > Account).

Kraken Audits

2. Select the Audits tab. Your account will display recent audits in which your account balance was verified, the associated Audit ID, the date of the audit, the name of the firm conducting the audit, and the type of audit that was conducted. The Audit ID is the identifying string associated with a particular audit; as Kraken expects to be conducting regular Proof of Reserves audits, it’s important that each is uniquely identifiable.

Kraken audit list

3. Select the audit date you want to verify. Here, you will find confirmation of the audit type, your Record ID (specific to your account and this particular audit), the assets that were covered, and your asset balances at the time of the audit.

The Record ID enables you to independently confirm that your account balance was included, via the third-party auditor.

Kraken audit details

Verifying your record with the auditor


Simple:

The quickest way to verify your account record is by using the third-party auditor’s portal with your Record ID:

1. Copy the Record ID corresponding with your account and the specified audit (refer to the previous section to locate this).

2. Visit the website of the third-party auditor responsible for the Proof of Reserves audit.

3. Enter your Record ID in the third-party auditor’s portal. The auditor’s website will use this ID to find the record of the cryptocurrency held in your account on-chain at the time of the audit.

4. Verify your balances.

Advanced:

Tech-savvy clients may wish to independently reconstruct their particular Merkle Tree leaf node hash and look up their balances in the third-party auditor tool using this hash, rather than just the Record ID.

This allows clients to verify that their Record ID (as well as the associated balances of their account at the time of the audit) were included in the Merkle Tree structure, which resulted in the Root Hash published by the auditor:

1. The audit details on kraken.com also include an "Account Code", another code unique to your account and this particular audit, which avoids any identifying code from being reused across audits.

2. You’ll also see a Merkle Hash that you can either use directly or reconstruct (per below) using details of your account and the particular audit. The Merkle Leaf that you’ll use for lookup on the auditor tool is the first 16 characters of the SHA256 of this Merkle Hash.

3. The requisite steps, in pseudocode, to reconstruct the Record ID and Merkle Leaf from your Account Code, Kraken IIBAN, Audit ID and Balances are outlined below. Note that the results are sensitive to the particular string formatting of balances, and the order of assets audited, as displayed on the Audits page.

  • Record ID = SHA256(concatenate(Account Code, Kraken IIBAN, Audit ID))
  • Balances = ""
  • ForEach Asset:
    • Balances = concatenate(Asset, ":", AssetBalances[asset])
  • Merkle Hash = concatenate(Record ID, “,”, Balances)
  • Merkle Leaf = substring(SHA256(Merkle Hash), 0, 16)

Specific examples are also demonstrated in the code snippets below. The resulting Merkle Leaf is also visible on the audit details to help confirm you’ve reconstructed this correctly.

python

Python

import hashlib

account_code = "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
iiban = "AB12C34DEFG5KSQI"
audit_id = "PR30JUN22"
record_id = hashlib.sha256((account_code + iiban + audit_id).encode('utf-8')).hexdigest()

balances = "ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,BTC.M:1.25,DOT:50.0,DOT.S:20.5,DOT.P:0.0,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002"

print("Record ID: {}".format(record_id))
print("Merkle Hash: {}".format((record_id + "," + balances)))
hash_result = hashlib.sha256((record_id + "," + balances).encode('utf-8')).hexdigest()
print("SHA Result: {}".format(hash_result))
print("Merkle Leaf: {}".format(hash_result[0:16]))
rust

Rust

use sha2::{Digest, Sha256};

const ACCOUNT_CODE: &str = "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1";
const IIBAN: &str = "AB12C34DEFG5KSQI";
const AUDIT_ID: &str = "PR30JUN22";
const BALANCES: &str = "ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,BTC.M:1.25,DOT:50.0,DOT.S:20.5,DOT.P:0.0,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002";

fn main() {
    let mut record_hasher: Sha256 = Default::default();

    record_hasher.update(ACCOUNT_CODE);
    record_hasher.update(IIBAN);
    record_hasher.update(AUDIT_ID);

    let record_id = format!("{:x}", record_hasher.finalize());
    let merkle_hash = format!("{},{}", record_id, BALANCES);

    let mut merkle_hasher: Sha256 = Default::default();
    merkle_hasher.update(&merkle_hash);
    let merkle_result = format!("{:x}", merkle_hasher.finalize());

    println!("Record ID: {}", record_id);
    println!("Merkle Hash: {}", merkle_hash);
    println!("SHA Result: {}", merkle_result);
    println!("Merkle Leaf: {}", &merkle_result[..16]);
}
go

Go

package main

import (
	"crypto/sha256"
	"fmt"
)

func main() {

	accountCode := "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
	iiban := "AB12C34DEFG5KSQI"
	auditId := "PR30JUN22"

	secret := accountCode + iiban + auditId

	data := []byte(secret)
	hash := sha256.Sum256(data)
	recordId := string(hash[:])
	fmt.Printf("Record ID: %x\n", recordId)

	balances := "ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,BTC.M:1.25,DOT:50.0,DOT.S:20.5,DOT.P:0.0,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002"

	merkleHash := fmt.Sprintf("%x%s%s", recordId, ",", balances)
	fmt.Printf("Merkle Hash: %s\n", merkleHash)

	hashResult := sha256.Sum256([]byte(merkleHash))
	hashResultStr := string(hashResult[:])
	fmt.Printf("SHA Result: %x\n", hashResultStr)
	fmt.Printf("Merkle Leaf: %x\n", hashResultStr[0:8])

}
bash

Bash

#!/bin/bash

ACCOUNT_CODE="8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
IIBAN="AB12C34DEFG5KSQI"
AUDIT_ID="PR30JUN22"
RECORD_ID=$(echo -n "${ACCOUNT_CODE}${IIBAN}${AUDIT_ID}" | sha256sum | head -c 64)
BALANCES="ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,BTC.M:1.25,DOT:50.0,DOT.S:20.5,DOT.P:0.0,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002"
MERKLE_HASH="${RECORD_ID},${BALANCES}"
HASH_RESULT=$(echo -n ${MERKLE_HASH} | sha256sum | head -c 64)

echo "Record ID: ${RECORD_ID}"
echo "Merkle Hash: ${MERKLE_HASH}"
echo "SHA Result: ${HASH_RESULT}"
echo "Merkle Leaf: $(echo -n ${HASH_RESULT} | head -c 16)"

Shortcomings and Future Improvements

In the interest of championing transparency, we would like to share some of the shortcomings in the Proof of Reserves process that we’ve identified.

  • A Proof of Reserves involves proving control over on-chain funds at the point in time of the audit, but cannot prove exclusive possession of private keys that may have theoretically been duplicated by an attacker.
  • The procedure cannot identify any hidden encumbrances or prove that funds had not been borrowed for purposes of passing the audit. Similarly, keys may have been lost or funds stolen since the latest audit.
  • The auditor must be competent and independent to minimize the risk of duplicity on the part of the auditee, or collusion amongst the parties.

We seek to mitigate some of these shortcomings by engaging with respected, independent third party firms for our Proof of Reserves, and conducting these audits at a regular and frequent cadence.

*Note: There are no formally accepted rules of procedures that define a proof of reserves audit. For ours, we engaged an independent accounting firm to perform an attest engagement under standards set forth by the American Institute for Certified Public Accountants and to issue an Independent Accountant’s Report on Agreed Upon Procedures. These reports include specific procedures performed by that firm as well as their findings.

Proof of Reserves