Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
LABS
Guides

Launching a Proof-of-Reserves Implementation for Custody

A technical guide for developers on implementing a cryptographically verifiable proof-of-reserves system to demonstrate full asset backing for custodial services.
Chainscore © 2026
introduction
IMPLEMENTATION GUIDE

Introduction to Proof-of-Reserves for Custodians

A technical guide for custodians on implementing a transparent, cryptographically verifiable proof-of-reserves system to demonstrate full asset backing.

A proof-of-reserves (PoR) is an independent, cryptographic audit that verifies a custodian holds sufficient assets to cover all client liabilities. Unlike traditional audits, a PoR leverages public blockchains and zero-knowledge proofs to provide real-time, verifiable transparency without exposing sensitive client data. For custodians, implementing a PoR is a critical step in building trust, mitigating counterparty risk, and differentiating services in a competitive market. It directly addresses the core question of solvency that emerged after events like the FTX collapse.

The technical implementation revolves around three core components: the liability proof, the asset proof, and the cryptographic commitment. The liability proof is a cryptographically signed statement of total client holdings, often represented as a Merkle tree root where each leaf is a hashed client balance. The asset proof consists of on-chain attestations, such as signed messages from custodial addresses or attestations from institutional partners like Coinbase Custody or BitGo. The system proves that the sum of verifiable assets is greater than or equal to the sum of committed liabilities.

A robust PoR system must protect client privacy. Simply publishing a list of client balances is not acceptable. Instead, custodians use a Merkle tree structure. Each client's account ID and balance are hashed together to create a leaf. The Merkle root is published, representing the total liabilities. Individual clients can then receive a Merkle proof—a path of hashes from their leaf to the root—allowing them to verify their inclusion in the total without revealing other clients' data. This is a foundational privacy-preserving technique.

Proving asset ownership requires securely attesting to control of on-chain addresses. The standard method involves the custodian cryptographically signing a message (e.g., "Custodian X controls address 0x... for PoR audit on 2024-01-01") from each custodial wallet. These signatures are published alongside the corresponding addresses. Anyone can then verify that the custodian controls the funds in those wallets at the time of the attestation. For off-chain or cross-chain assets, attestations from trusted, audited entities or the use of bridged attestation protocols are necessary.

The final step is the solvency proof, which cryptographically links assets and liabilities. This often involves generating a zk-SNARK or similar zero-knowledge proof. This proof demonstrates, in a verifiable and privacy-preserving manner, that the sum of the committed assets is greater than or equal to the Merkle root of liabilities. Tools like Circom or snarkjs can be used to construct these circuits. The output is a small proof that can be verified by anyone with the public verification key, providing strong cryptographic assurance of solvency.

For a production implementation, custodians should follow a recurring workflow: 1) Snapshot client balances at a specific block height, 2) Generate the liability Merkle tree and publish the root, 3) Attest to on-chain assets with signed messages, 4) Generate and publish the zk-SNARK solvency proof, and 5) Provide a public verification portal. Regular, frequent audits (e.g., monthly) are essential. Open-source frameworks like those from Chainscore or Succinct Labs can accelerate development, but the security of the signing key management and data pipeline is paramount.

prerequisites
FOUNDATION

Prerequisites and System Requirements

Before deploying a Proof-of-Reserves (PoR) system for digital asset custody, establishing a robust technical and operational foundation is critical. This section outlines the essential components, from infrastructure to cryptographic libraries, required for a secure and verifiable implementation.

A production-grade PoR system requires a dedicated, secure infrastructure environment. This typically involves deploying to a virtual private cloud (VPC) or an air-gapped system for the most sensitive components, such as the key management service. You will need a reliable server (e.g., AWS EC2, GCP Compute Engine) with sufficient CPU and memory to handle periodic Merkle tree generation for large asset sets. A managed database like PostgreSQL is recommended for storing audit trails, user balances, and the Merkle tree data structure. All components must be containerized using Docker for consistency and deployed via an orchestration tool like Kubernetes for high availability.

The core of your PoR relies on cryptographic primitives. Your development stack must include a mature cryptographic library. For Rust implementations, use the arkworks suite for pairing-based cryptography or rust-crypto for standard hashing. In TypeScript/JavaScript, the @noble libraries (@noble/curves, @noble/hashes) are industry-standard for their security and audit history. You will specifically need functionality for the SHA-256 hash function (for Merkle trees) and digital signatures (like EdDSA with Ed25519 or ECDSA with secp256k1) to sign the final proof. Never roll your own cryptographic functions.

Your architecture must clearly separate the prover (the custodian's system that generates the proof) from the verifier (the public smart contract or client). The prover requires secure access to the total custodial wallet addresses and their balances. This is often facilitated by integrating with your internal accounting or ledger system via a secure API. The verifier, typically a smart contract on a blockchain like Ethereum, needs to be written in a language such as Solidity or Vyper. It must implement functions to verify the provided Merkle root and cryptographic signature against a known custodian public key.

Operational security prerequisites are non-negotiable. Implement a Hardware Security Module (HSM) or a cloud KMS (e.g., AWS KMS, GCP Cloud HSM) to manage the custodian's signing key. The private key used to sign the Merkle root must never be exposed to application memory in plaintext. Establish strict access controls and audit logging for any system that handles balance data or the signing process. Furthermore, define a scheduled audit cycle (e.g., daily or weekly) that triggers the proof generation and publication automatically, ensuring consistency and removing manual intervention points.

Finally, prepare the data pipeline. You need a reliable method to snapshot user balances at a specific block height. This often requires a indexer or database that can provide a consistent view of all custodial holdings. The data must be formatted into a structured input for your proof generation script, which will create the leaf nodes (e.g., hash(address, balance)) and compute the Merkle root. The output—the root, the signature, and often the total aggregate value—must be published to a persistent, publicly accessible location, such as a decentralized storage network (IPFS/Arweave) and/or directly to the verification contract.

key-concepts-text
CORE CRYPTOGRAPHIC CONCEPTS

Launching a Proof-of-Reserves Implementation for Custody

A technical guide to implementing a cryptographic proof-of-reserves system for digital asset custodians, ensuring verifiable solvency without compromising client privacy.

A proof-of-reserves (PoR) system cryptographically demonstrates that a custodian holds assets equal to or greater than its total client liabilities. Unlike a simple balance sheet, a PoR uses Merkle trees and digital signatures to provide verifiable, privacy-preserving evidence of solvency. The core cryptographic flow involves: - The custodian generating a Merkle root from hashed client balances. - Publishing this root and a total reserve value (e.g., from on-chain attestations or exchange statements). - Allowing individual users to verify their inclusion in the tree via a Merkle proof. This shifts trust from blind faith to cryptographic verification, a critical requirement for institutional custody.

The implementation begins with constructing the Merkle tree. Each leaf node is a hash of a client's unique identifier (like a user ID) and their balance, often formatted as H(user_id | balance). Using a cryptographically secure hash function like SHA-256 or Keccak-256, the leaves are hashed in pairs to create parent nodes until a single Merkle root remains. This root is the commitment to the entire set of client balances at a specific point in time. Crucially, the tree structure reveals no individual balances or relationships between users, preserving privacy while enabling aggregate verification.

For a user to verify their funds are included, the custodian provides a Merkle proof. This proof consists of the sibling hashes along the path from the user's leaf to the root. The user can recompute the root hash using their own (user_id, balance) and the provided proof hashes. If the computed root matches the publicly published root, the verification succeeds. This process is efficient, requiring only O(log n) hashes for a tree with n users. Public tools like the MerkleTree.js library or Solidity's MerkleProof library can handle this logic.

The reserve attestation must be independently verifiable. For on-chain assets like ETH or ERC-20 tokens, the custodian can sign a message from its publicly known custody wallets, summing their balances to a total reserve value. For off-chain or cross-chain assets, a trusted auditor or oracle network (like Chainlink Proof of Reserve) may provide signed attestations. The published total reserve must be greater than or equal to the sum of all client balances committed in the Merkle tree. A discrepancy where liabilities exceed reserves indicates insolvency.

A production implementation requires automating the audit cycle and handling edge cases. Key steps include: 1. Scheduled Snapshotting: Regularly generating new Merkle trees (e.g., daily) from the custody database. 2. Secure Root Publication: Publishing the new root and reserve total to an immutable public ledger (like Ethereum or IPFS) with a timestamp. 3. Proof Generation API: Creating an authenticated endpoint where users can fetch their specific Merkle proof. 4. Handling Data Changes: Managing balance updates between snapshots to ensure proofs remain valid for the stated audit period. Open-source frameworks from firms like Coinbase or Binance provide reference architectures.

Advanced implementations incorporate zero-knowledge proofs (ZKPs) for enhanced privacy and functionality. A zk-SNARK can prove that the sum of all balances in the Merkle tree is less than the total reserves without revealing any individual balances, even to the verifier. Protocols like zk-STARKs can also prove the correct computation of the entire Merkle tree. While more computationally intensive, ZK-based PoR represents the next evolution, enabling fully private, real-time solvency proofs. For most custodians, starting with a transparent Merkle tree system provides a strong, auditable foundation for trust.

step-1-data-aggregation
DATA PREPARATION

Step 1: Aggregate and Hash Client Balances

The foundation of a trustworthy Proof-of-Reserves (PoR) system is the creation of an immutable, privacy-preserving snapshot of all client holdings at a specific point in time.

The first operational step is to aggregate the total balance for every client account at a precisely defined timestamp, known as the snapshot block height. This involves querying your internal custody database to sum all assets—such as Bitcoin, Ethereum, and ERC-20 tokens—held by each unique user identifier. The output is a structured dataset, often a JSON file or database table, containing entries like { "client_id": "abc123", "total_btc": 1.5, "total_eth": 25.0 }. Accuracy here is paramount, as this dataset represents the liabilities you are committing to prove you hold.

To protect client privacy and prepare the data for cryptographic proof, you must then hash each client's entry. A common and secure method is to create a Merkle tree. For each client, you generate a leaf node by hashing a concatenated string of their client_id and balance data. Using a library like merkletreejs in Node.js, the process looks like this:

javascript
const { MerkleTree } = require('merkletreejs');
const SHA256 = require('crypto-js/sha256');

const leaves = clientData.map(c => SHA256(c.clientId + c.totalBtc + c.totalEth));
const tree = new MerkleTree(leaves, SHA256);
const rootHash = tree.getRoot().toString('hex'); // This is your commitment

The resulting Merkle root is a single, compact hash that uniquely represents the entire set of client balances without revealing any individual's information.

This Merkle root becomes your public commitment. You publish this hash on-chain (e.g., by storing it in a bytes32 variable in an Ethereum smart contract) or in a verifiable public log. This act cryptographically binds you to the specific dataset you hashed. Later, you can provide any client with a Merkle proof—a small set of hashes—that allows them to independently verify their balance was included in the original calculation that produced the published root. This process ensures data integrity from the moment of the snapshot.

step-2-merkle-tree-construction
DATA STRUCTURE

Step 2: Construct the Merkle Tree

This step involves organizing your verified user balance data into a cryptographic tree structure, which is the core component enabling efficient and verifiable proof generation.

With your validated user balance dataset prepared, you now need to build a Merkle tree (specifically, a Merkle Patricia Trie in many implementations). This data structure cryptographically commits to every user's balance and identifier. Each leaf node in the tree is a hash of a user's data, typically formatted as keccak256(address + balance). The tree is constructed by repeatedly hashing pairs of child nodes to create parent nodes, culminating in a single root hash. This root is your system's fingerprint; any change to a single user's balance will produce a completely different root.

The construction must be deterministic. Users must be sorted, usually by their Ethereum address in hexadecimal order, before hashing into leaves. This ensures anyone can independently rebuild the tree from the same dataset and arrive at the identical root hash. For implementation, libraries like OpenZeppelin's MerkleProof.sol provide the necessary verification logic, while off-chain tools in JavaScript (ethers.js, merkletreejs) or Python (merkletools) handle tree generation. The process is algorithmic: hash the sorted data, build the tree layers, and output the root.

Here is a simplified JavaScript example using merkletreejs and keccak256:

javascript
const { MerkleTree } = require('merkletreejs');
const keccak256 = require('keccak256');
// leaves = sorted array of keccak256(address + balance)
const tree = new MerkleTree(leaves, keccak256, { sortPairs: true });
const root = tree.getRoot().toString('hex');
console.log('Merkle Root:', root);

This root hash is the critical piece of data that will be published on-chain or in your attestation. For each user, you must also generate and store their Merkle proof—the minimal set of sibling hashes needed to verify their leaf's inclusion in the published root.

In a production Proof-of-Reserves system, you often implement an incremental tree or use a standardized structure like the IETF RFC 9162 Merkle Tree for Security Event Logging. This allows for efficient updates when balances change between attestations without rebuilding the entire tree. The final output of this step is two-fold: the immutable root hash representing the state of all liabilities, and a set of cryptographic proofs mappable to each user, enabling the trust-minimized verification in the next step.

step-3-on-chain-publication
EXECUTION

Step 3: Publish the Commitment On-Chain

This step finalizes the Proof-of-Reserves process by submitting the cryptographic commitment to a public blockchain, creating a permanent, verifiable record of the attestation.

With the Merkle root and timestamp prepared, the next action is to publish this data to a smart contract on a public blockchain, typically Ethereum. This on-chain transaction serves as the definitive, tamper-proof proof that the attestation was performed at a specific block height. The core function call is usually publishRoot(bytes32 root, uint256 timestamp). The root is the 32-byte Merkle root hash from Step 2, and the timestamp is the Unix epoch time when the attestation data was finalized. This transaction must be signed by the custodian's administrative wallet.

The smart contract that receives this data is a critical component. It must be a simple, audited, and immutable contract whose sole purpose is to store a history of published roots. A common pattern is for the contract to maintain a mapping, such as mapping(uint256 => bytes32) public publishedRoots, where the key is an incrementing index or the block number. This allows anyone to query the contract to retrieve all historical commitments. The contract should emit an event, like RootPublished(bytes32 indexed root, uint256 timestamp, address publisher), enabling easy off-chain indexing and monitoring by users and auditors.

Choosing the right network and managing gas costs are practical considerations. While Ethereum mainnet offers the highest security and decentralization, layer-2 solutions like Arbitrum or Optimism provide significantly lower transaction fees for frequent (e.g., daily) publications. The contract address must be publicly listed on the custodian's transparency page. After a successful transaction, you should verify the publication by checking the transaction hash on a block explorer like Etherscan, confirming the RootPublished event log contains the correct Merkle root and timestamp.

This on-chain footprint enables the final user verification step. A user can now independently verify their inclusion in the reserve proof. They would visit the custodian's verification portal, connect their wallet, and the portal's backend would: 1) fetch the latest published root from the blockchain, 2) use the user's provided Merkle proof (generated in Step 2) to recalculate the root from the user's leaf, and 3) confirm a match. This process proves the user's funds were part of the attested total reserves without revealing other users' balances.

step-4-auditor-verification
TRANSPARENCY AND VERIFICATION

Step 4: Facilitate Third-Party Audits

The final, critical step in a Proof-of-Reserves implementation is enabling independent verification by third-party auditors. This transforms your cryptographic proofs from a self-reported claim into a trusted, verifiable attestation of solvency.

Third-party audits are essential for establishing E-E-A-T (Experience, Expertise, Authoritativeness, Trustworthiness) with users and the broader market. An auditor's role is to independently verify that the cryptographic commitments you've published accurately reflect your on-chain holdings and that the proof generation process is sound. This involves the auditor reviewing your Merkle tree construction, verifying the inclusion of all custodial addresses, and validating the digital signatures on the attestation. A successful audit results in a public report, often called an attestation report, that details the scope, methodology, and findings.

To facilitate an efficient audit, you must provide auditors with comprehensive access and documentation. This includes:

  • The complete dataset: The raw list of user balances and corresponding Merkle leaf hashes.
  • The Merkle root generation script: The exact code used to build the tree and calculate the root.
  • Access to the attestation signing process: Details on how the root was signed, including the public key of the attestor.
  • The list of custody addresses: All blockchain addresses under the custodian's control that were included in the reserve calculation. Auditors will independently sum the balances of these addresses and compare the total to the aggregated user liabilities from your Merkle tree.

A common practice is to use a zero-knowledge proof system like zk-SNARKs to allow users to cryptographically verify their inclusion in the Merkle tree without revealing other users' balances. For an auditor, verifying this system is more complex. They must check that the zk-SNARK circuit logic correctly enforces the Merkle proof verification and that the trusted setup (if required) was performed securely. Auditors like ChainSecurity, Trail of Bits, or OpenZeppelin specialize in reviewing such cryptographic implementations.

The output of this step is a publicly published audit report. Leading custodians like Coinbase and Kraken publish these reports on their transparency pages. The report should clearly state the audit date, the total auditable assets, the total user liabilities, and the reserve ratio. It should also disclose any limitations, such as assets held off-chain or in non-custodial DeFi protocols that were not included. This transparency about scope is crucial for maintaining trust.

Ultimately, facilitating third-party audits closes the loop on Proof-of-Reserves. It moves the system from a technical implementation to a trust-minimized assurance model. Regular audits, conducted quarterly or following significant changes to the custody system, provide ongoing proof of solvency. This continuous verification is what gives users and regulators confidence in the custodian's financial health and operational integrity.

ARCHITECTURE COMPARISON

Proof-of-Reserves Implementation Options

A comparison of the primary technical approaches for implementing a Proof-of-Reserves system for a custody service.

Implementation FeatureSelf-Hosted Merkle TreeThird-Party AttestationOn-Chain Verification

Audit Frequency

Real-time / On-demand

Quarterly / Monthly

Continuous

Technical Overhead

High

Low

Medium

Client Verification

Self-service portal

Published PDF report

Public blockchain explorer

Data Privacy

High (client data private)

Medium (shared with auditor)

Low (fully public)

Setup & Integration Cost

$50k-200k+

$10k-50k per audit

$20k-100k+ (gas costs vary)

Settlement Finality

Delayed (snapshot-based)

Delayed (report date)

Immediate (block confirmation)

Primary Use Case

Large exchanges, bespoke custody

Regulatory compliance, traditional finance

DeFi-native protocols, transparency focus

PROOF-OF-RESERVES IMPLEMENTATION

Frequently Asked Questions

Common technical questions and troubleshooting for developers building a Proof-of-Reserves (PoR) system for digital asset custody.

The core cryptographic proof is a Merkle proof that links a user's balance to the total custodial reserves. The system works by:

  1. Generating a Merkle Tree: Each leaf node is a hash of a client's identifier (like client_id) and their balance.
  2. Publishing the Root: The Merkle root is published on-chain (e.g., Ethereum) or to a public transparency page. This root commits to all client balances at a specific block height.
  3. Generating Inclusion Proofs: For verification, the custodian provides a user with a Merkle proof—a path of sibling hashes from their leaf to the published root.

This allows any user to cryptographically verify their funds are included in the total claimed liabilities without revealing other clients' private data.

conclusion
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have now explored the core components for launching a Proof-of-Reserves (PoR) system for a crypto custody service. This final section summarizes the key steps and outlines how to evolve your implementation.

A robust PoR implementation is built on three pillars: data integrity, transparent verification, and user accessibility. The process begins with securely generating a Merkle root from user balances, which is then anchored on-chain, typically via a smart contract on a transparent ledger like Ethereum or Arbitrum. The accompanying attestation report, signed by the custodian's private key, must cryptographically link to this on-chain commitment and be publicly hosted. Tools like TLSNotary or DECO can provide cryptographic proof that the attested data matches the live state of the custodian's systems without revealing sensitive information.

For ongoing operations, establish a regular attestation schedule (e.g., weekly or monthly) and automate the entire pipeline. Use scripts to fetch balances, generate the Merkle tree, publish the root, and sign the report. Consider integrating with oracle networks like Chainlink to automate the on-chain publication. Monitor the smart contract for verification attempts and failed proofs, which can be early indicators of issues. Your public-facing verification portal should be intuitive, allowing users to input their account ID to receive their Merkle proof and verify their inclusion independently against the published root.

The next evolution is moving from a single-asset model to a multi-asset PoR. This requires aggregating liabilities across different blockchains (e.g., Bitcoin, Ethereum, Solana) and potentially off-chain assets. The challenge is creating a unified proof. One approach is to generate separate Merkle trees for each asset type and then create a final "root of roots." Alternatively, protocols like zkProofs can be used to create a succinct proof that validates all assets simultaneously without revealing individual holdings, enhancing privacy and scalability.

To build greater trust, transition from a self-attested model to one with external oversight. Engage a reputable third-party auditor to review your procedures and cryptographically sign the attestation report. Explore real-time verification systems where the reserve status is continuously proven, moving beyond periodic snapshots. This can be achieved with cryptographic accumulators or by leveraging validiums and zk-rollups that provide constant state commitments. Staying current with emerging standards from bodies like the Proof of Reserves Alliance is also crucial.

Finally, treat your PoR system as a core product feature. Document the entire process transparently for users and developers. Provide open-source verifier libraries in multiple languages (JavaScript, Python, Go) to lower the barrier for independent checks. By implementing these steps, you move beyond marketing to providing a verifiable, trust-minimized foundation for your custody service, aligning with the core principles of self-sovereignty and transparency in the Web3 ecosystem.