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

How to Choose Hashes for Commitments

A technical guide for developers on selecting and implementing hash functions for cryptographic commitments in zero-knowledge proofs and blockchain systems.
Chainscore © 2026
introduction
SECURITY FOUNDATIONS

How to Choose Hash Functions for Cryptographic Commitments

A guide to selecting secure hash functions for commitment schemes, balancing security, performance, and protocol compatibility.

A cryptographic commitment allows a user to commit to a value while keeping it hidden, with the ability to later reveal it. The core component is a cryptographic hash function like SHA-256 or Keccak-256. The committer sends the hash of their secret value (the commitment) to a verifier. Later, they reveal the original value, and the verifier hashes it to check it matches the commitment. This ensures the value was not changed after the commitment was made, a property called binding, while the hiding property keeps the secret safe until reveal.

For binding and hiding to hold, the hash function must be collision-resistant and preimage-resistant. Collision resistance prevents finding two different inputs that produce the same hash, which would break the binding property. Preimage resistance prevents reversing the hash to find the original input, preserving hiding. In practice, developers should use hash functions from the SHA-2 or SHA-3 families, which are vetted by cryptographic standards bodies like NIST. Avoid deprecated functions like MD5 or SHA-1, which have known collision attacks.

The choice often depends on the blockchain ecosystem. SHA-256 is the standard for Bitcoin and its derivatives. Keccak-256 (often called SHA-3) is used by Ethereum and EVM-compatible chains. For zero-knowledge proof systems like zk-SNARKs, Poseidon or Rescue are preferred as they are arithmetization-friendly, meaning they are efficient to compute within a circuit. Using a chain's native hash simplifies interoperability with its smart contracts and existing tooling.

Performance is another key consideration. SHA-256 is highly optimized in hardware and widely supported. Keccak-256 can be faster in software for certain implementations. For applications requiring many sequential hashes, a Merkle-Damgård construction (like SHA-256) may be suitable. For parallel processing or tree hashing, a sponge construction (like Keccak) can be more efficient. Always benchmark within your specific application context.

When implementing, use audited libraries. In Solidity, use keccak256(abi.encodePacked(input)) for commitments. In JavaScript/TypeScript with ethers.js, use ethers.utils.keccak256. For a generic SHA-256 commitment in Python, use hashlib.sha256(value).hexdigest(). Never roll your own cryptographic hash function. Always include a cryptographic salt (nonce) when hashing to prevent rainbow table attacks, ensuring the commitment is H(salt || value).

Finally, consider future-proofing. Cryptographic standards evolve as computing power increases. While SHA-256 and Keccak-256 are currently secure, monitor developments from standards bodies. For long-term commitments, design systems to allow for hash function agility—the ability to upgrade the hash function through governance or versioned APIs without breaking the commitment scheme's core logic.

prerequisites
PREREQUISITES

How to Choose Hashes for Commitments

A foundational guide to selecting cryptographic hash functions for building secure and efficient commitment schemes in blockchain applications.

A cryptographic commitment scheme allows one party to commit to a value (like a secret or data) by publishing a commitment, and later reveal the original value. The core properties are hiding (the commitment reveals nothing about the value) and binding (the committer cannot change the value later). The hash function you choose directly impacts the security and performance of this scheme. Common patterns include commitment = hash(secret, salt) or using a Merkle tree root hash to commit to a set of data.

For most blockchain applications, you should select a hash function from the SHA-2 or SHA-3 family. SHA-256 is the industry standard, used in Bitcoin's Proof-of-Work and for Merkle tree commitments in Ethereum. Its 256-bit output provides 128-bit collision resistance, which is considered secure against classical and quantum attacks for the foreseeable future. For environments prioritizing speed, BLAKE2b or BLAKE3 offer performance benefits while maintaining strong security guarantees.

Avoid deprecated or broken hash functions like MD5 or SHA-1, as they are vulnerable to collision attacks, breaking the binding property of your commitment. Also, consider the random oracle model when designing your scheme: the hash should behave like a truly random function. Functions like Keccak-256 (used in Ethereum) are designed with this in mind. Always use a cryptographic salt (nonce) to prevent brute-force and rainbow table attacks against the hiding property, especially if the secret value has low entropy.

Your choice may be dictated by the blockchain ecosystem. For Ethereum or EVM-compatible chains, use keccak256. For Solana, sha256 is common. In Cosmos SDK chains, sha256 is typically used for Merkle proofs. For zero-knowledge proof systems like zk-SNARKs, Poseidon or Rescue hashes are preferred due to their efficiency in arithmetic circuits. Always verify the native hash function of the proving system or virtual machine you are integrating with.

To implement a basic commitment in Solidity, you would typically compute: bytes32 commitment = sha256(abi.encodePacked(secret, salt));. The abi.encodePacked ensures deterministic packing. For verification upon reveal, you recalculate the hash with the provided secret and salt and check for a match. Remember to store only the commitment on-chain; the salt can be revealed later or derived deterministically. This pattern is fundamental for applications like sealed-bid auctions or commit-reveal voting schemes.

key-concepts-text
CRYPTOGRAPHIC PRIMITIVES

Key Cryptographic Properties for Commitments

A commitment scheme's security depends on the underlying cryptographic hash function. This guide explains the essential properties a hash must have to be suitable for commitments.

A commitment scheme allows a prover to commit to a value v by publishing a commitment c = commit(v, r), where r is a random blinding factor. Later, they can reveal v and r, allowing a verifier to check that c was correctly generated. The core security of this scheme hinges on two properties: hiding and binding. The hiding property ensures c reveals no information about v. The binding property ensures the prover cannot later open c to a different value v'. The hash function used to compute the commitment must be cryptographically strong to guarantee these properties.

The hiding property is directly provided by the preimage resistance (one-wayness) of the hash. Given the output c, it should be computationally infeasible to find any input (v, r) that produces it. More formally, a hash function H is preimage-resistant if for a randomly chosen output y, it is hard to find any x such that H(x) = y. For commitments, we often use c = H(v || r). If an attacker could find v from c, the commitment would not be hidden. Modern hash functions like SHA-256 and Keccak-256 (used in Ethereum) are considered preimage-resistant.

The binding property relies on the collision resistance of the hash function. It must be infeasible to find two distinct inputs (v, r) and (v', r') that hash to the same output c. If a prover could find such a collision, they could commit to c, then later reveal either (v, r) or (v', r'), breaking their commitment. This is a stronger requirement than preimage resistance. While SHA-256 is also collision-resistant, developers must be aware of length extension attacks. Some hash constructions, like SHA-256, are vulnerable, allowing an attacker to compute H(v || r || extra_data) without knowing r.

To mitigate length extension attacks, use a hash function designed for message authentication or a specific commitment construction. The HMAC construction (HMAC(key, message)) is a common solution, as it is not vulnerable to these attacks. Alternatively, use a hash function like BLAKE2 or BLAKE3, which use a built-in domain separation mechanism. For example, in a Solidity smart contract, you might use keccak256(abi.encodePacked(value, salt)). Keccak-256 does not suffer from length extension attacks, making it a safe choice for Ethereum commitments.

When choosing a hash, also consider output size and performance. A 256-bit output (32 bytes) provides 128 bits of security against collisions, which is sufficient for most applications. For higher security contexts, consider SHA-384 or SHA-512. For performance-critical applications on-chain, BLAKE3 is significantly faster than SHA-256. However, always verify the hash is available and gas-efficient in your target environment. In Ethereum, keccak256 is a built-in opcode and is the standard. In other contexts, you may need to implement or link a library.

In practice, implement commitments using a cryptographically secure random salt (r). Never use a predictable or zero salt, as this can weaken the hiding property. A common pattern is bytes32 commitment = keccak256(abi.encodePacked(value, nonce));. Store only the commitment on-chain. When revealing, the prover submits the original value and nonce, and the contract verifies by recomputing the hash. By understanding these properties—preimage resistance for hiding, collision resistance for binding, and defenses against length extension—you can select and implement robust commitment schemes for applications like sealed-bid auctions, voting, or zero-knowledge proof systems.

CRYPTOGRAPHIC PROPERTIES

Hash Function Comparison for Commitments

Key characteristics of common hash functions used in cryptographic commitments.

PropertySHA-256Keccak-256Blake2bPoseidon

Output Size (bits)

256

256

256

Variable (e.g., 256)

Preimage Resistance

Collision Resistance

ZKP Friendliness

Gas Cost (EVM, avg)

~60k

~36k

~45k

Standardization

NIST FIPS 180-4

NIST FIPS 202

RFC 7693

Academic

Common Use Case

Bitcoin, TLS/SSL

Ethereum, Keccak

Filecoin, Arweave

ZK-Rollups, StarkNet

selection-framework
CRYPTOGRAPHIC PRIMITIVES

A Framework for Selecting a Hash Function

A practical guide for developers and protocol designers on evaluating hash functions for commitment schemes, covering security, performance, and compatibility trade-offs.

A commitment scheme allows a prover to commit to a value (e.g., a bid, a vote, or a secret) by publishing a cryptographic hash, the commitment, without revealing the value itself. Later, they can open the commitment by revealing the original value, allowing anyone to verify it matches the hash. The core properties are hiding (the commitment reveals nothing about the value) and binding (the prover cannot open the commitment to a different value). The choice of hash function is critical to guarantee these properties under adversarial conditions.

For most applications, a collision-resistant hash function like SHA-256 or SHA-3 (Keccak) is the default choice. Their security is well-understood, and they are widely implemented. However, for specific use cases, alternatives may be preferable. If you need to commit to structured data where preimage resistance is paramount but collision resistance is less critical, a faster function like BLAKE3 might be suitable. In zero-knowledge proof systems like zk-SNARKs, using algebraic hash functions (e.g., Poseidon, Rescue) that operate over finite fields can drastically improve prover performance, as they are more efficient for circuits than traditional bit-oriented hashes.

Evaluate hash functions against your system's threat model. For high-value, long-term commitments (e.g., on-chain timestamping), prioritize post-quantum security. SHA-256 and SHA-3 are considered quantum-secure in terms of collision resistance, but their preimage resistance is reduced by Grover's algorithm. For binding, this may be acceptable, but for hiding, you might consider a hash with a larger output (e.g., SHA-512) or a dedicated post-quantum function. Always audit the implementation: using a native library like OpenSSL's SHA-256 is safer than a custom JavaScript port for a high-stakes smart contract verifier.

Performance constraints are equally important. In a blockchain context, gas cost on EVM chains makes Keccak-256 (used by keccak256 in Solidity) the most economical choice for on-chain verification, despite SHA-256 being more common off-chain. For client-side applications in browsers, a WebAssembly-compiled version of BLAKE3 can be orders of magnitude faster than pure JavaScript SHA-256. Your framework should define acceptable latency and resource usage, then benchmark candidate functions in your target environment.

Finally, ensure compatibility and standardization. Using a NIST-standardized function (SHA-2, SHA-3) or a well-audited, widely adopted alternative (BLAKE2, BLAKE3) reduces audit complexity and interoperability issues. Avoid obscure or novel constructions. A practical checklist includes: - Security level (128-bit, 256-bit) - Resistance to length-extension attacks (SHA-3, BLAKE2 are safe; SHA-256 requires HMAC construction) - Availability of audited libraries in your stack - Performance in your deployment context. Documenting this rationale is part of responsible system design.

PRACTICAL GUIDE

Hash Selection by Use Case

On-Chain Commitments and Verification

Smart contracts require deterministic, gas-efficient hashing. keccak256 (often called SHA-3 in Ethereum) is the native and most common choice for EVM chains. It's used in CREATE2, digital signatures (ecrecover), and Merkle proofs.

Key Considerations:

  • Gas Cost: Hashing is an opcode. Simpler preimages cost less.
  • Determinism: The same input must produce the identical hash on every node.
  • Use abi.encodePacked: For consistent hashing of multiple arguments in Solidity.
solidity
// Example: Committing to a value in a smart contract
bytes32 public commitment = keccak256(abi.encodePacked(secret, msg.sender));

// Later, verifying the revealed secret
function reveal(bytes memory _secret) public {
    require(keccak256(abi.encodePacked(_secret, msg.sender)) == commitment, "Invalid reveal");
    // ... proceed
}
implementation-considerations
IMPLEMENTATION AND SECURITY

How to Choose Hashes for Commitments

Selecting the right cryptographic hash function is a foundational security decision for building commitments in protocols like Merkle trees, Verkle trees, and zk-SNARKs.

A cryptographic hash function used in a commitment scheme must satisfy specific properties. Pre-image resistance ensures the original input cannot be derived from the hash output. Second pre-image resistance guarantees that given an input, you cannot find a different input that produces the same hash. Most critically, collision resistance means it's computationally infeasible to find any two distinct inputs that hash to the same value. For long-term data integrity, such as in blockchain state roots, collision resistance is paramount. Functions like SHA-256 are the standard choice here.

Performance requirements vary by context. In a high-throughput Ethereum rollup, a zk-friendly hash like Poseidon or Rescue is essential because it creates efficient arithmetic circuits for zero-knowledge proofs, despite being slower in general-purpose computing. For on-chain verification of Merkle proofs, a Keccak-256 (as used by Ethereum) or BLAKE2b (favored by networks like Polkadot) offers a balance of speed and security. Always benchmark within your specific stack: a hash optimal for a Solidity smart contract may be inefficient in a Rust-based prover.

Consider the output size and truncation. A 256-bit hash (32 bytes) is common, but some designs use 512-bit hashes truncated for performance. Be aware that truncation, like using the first 20 bytes of a Keccak hash for an Ethereum address, reduces the security bits. The birthday problem dictates that collision risk increases with the square root of the hash space. For a 256-bit hash, collision resistance is ~128 bits; truncating to 160 bits reduces it to ~80 bits, which may be insufficient for long-term security.

Upgradability and future-proofing are crucial. Cryptographic primitives weaken over time due to advances in computing. While SHA-256 is currently secure, protocols should have a migration path. For example, a Merkle tree library could abstract the hash function, allowing a switch from SHA-256 to SHA-3-256 without changing core logic. Avoid deprecated functions like MD5 or SHA-1, which have known collision attacks. Monitor standards from bodies like NIST for post-quantum recommendations, as hash functions like SHA-256 are considered quantum-resistant but signature schemes are not.

Implementation pitfalls include incorrect padding and domain separation. Always use the function's standard initialization vectors (IV). For different use cases within the same system—like hashing leaves versus nodes—apply domain separation by prefixing inputs with a unique context byte (e.g., 0x00 for leaves, 0x01 for nodes). This prevents cross-protocol attacks where a valid hash in one context is maliciously reused in another. Libraries such as OpenSSL's libcrypto or Rust's sha2 crate handle padding correctly, but custom implementations often introduce critical vulnerabilities.

COMMITMENT HASHES

Frequently Asked Questions

Common developer questions about selecting and using cryptographic hashes for on-chain commitments, covering security, cost, and practical implementation.

A commitment hash is the cryptographic fingerprint of a piece of data, submitted to a blockchain to prove prior knowledge without revealing the data itself. It's a core primitive for privacy, randomness, and verification.

How it works:

  1. A user generates data (e.g., a secret number, a bid amount).
  2. They compute hash = keccak256(secret, salt). The salt prevents brute-force guessing.
  3. They submit only the hash (the commitment) in a transaction.
  4. Later, they reveal the original secret and salt. Anyone can verify the commitment by hashing the revealed values and checking it matches the on-chain hash.

This pattern is used in applications like sealed-bid auctions, commit-reveal voting schemes, and verifiable random functions (VRFs).

conclusion
KEY TAKEAWAYS

Conclusion and Next Steps

Selecting the right cryptographic hash function for your commitment scheme is a critical security and performance decision. This guide has outlined the core principles to inform your choice.

Your choice of hash function should be guided by the specific security properties required by your application. For binding and hiding commitments, collision resistance and preimage resistance are non-negotiable. In high-value, adversarial environments like blockchain consensus or zero-knowledge proofs, opt for battle-tested functions like SHA-256 or Keccak-256. For performance-critical applications where a trusted setup is acceptable, consider newer, SNARK-friendly hashes like Poseidon or Rescue. Always benchmark your shortlist within your specific proving system, as performance can vary drastically.

The next step is to implement your chosen hash within a commitment scheme. For a simple Pedersen commitment, you would use the hash to generate a pseudorandom generator seed or to derive a value before scalar multiplication on an elliptic curve. In a Merkle tree construction, the hash is the core function combining leaf and node data. Remember that the security of the entire commitment relies on the hash's properties; a weakness in the hash breaks the binding or hiding guarantee. Always use audited libraries from reputable sources like the ZK Crypto library or Circomlib.

To validate your design, write comprehensive tests. Test vectors should verify that: different inputs produce distinct commitments (binding), the original data cannot be deduced from the commitment (hiding), and the scheme correctly opens with valid witnesses. For blockchain applications, analyze gas costs or circuit constraints. Finally, stay informed. Cryptographic research is active; new attacks on hash functions are published, and more efficient designs emerge. Regularly review your dependencies and be prepared to migrate to more secure or performant primitives as the ecosystem evolves.