Skip to main content
This page is a placeholder. All examples on this page are currently AI-generated and are not correct. This documentation will be completed in the future with accurate, tested examples.

Overview

Address: 0x0000000000000000000000000000000000000009 Introduced: Istanbul (EIP-152) EIP: EIP-152 The Blake2f precompile implements the Blake2b compression function F, the core building block of the Blake2b cryptographic hash function. Unlike other hash precompiles that compute complete hashes, Blake2f exposes the low-level compression step, giving smart contracts fine-grained control over Blake2b hashing. This enables efficient verification of Zcash Equihash proofs and cross-chain bridges to Blake2-based blockchains. Blake2 is a modern cryptographic hash function that’s faster than MD5, SHA-1, SHA-2, and SHA-3 while maintaining strong security guarantees. It’s widely used in Zcash, Monero, IPFS, and Wireguard. The “b” variant (Blake2b) operates on 64-bit words and produces up to 512-bit (64-byte) hashes. By exposing the compression function directly, this precompile allows contracts to implement custom Blake2b variants (different initialization vectors, personalization strings, or tree hashing) without requiring new precompiles for each variant.

Gas Cost

Formula: rounds (1 gas per round) The number of rounds is specified in the input (first 4 bytes). Common values:
  • Blake2b standard: 12 rounds
  • Reduced round versions: 1-12 rounds
  • Maximum: 2^32 - 1 rounds (4,294,967,295 gas)
Examples:
  • 0 rounds: 0 gas
  • 12 rounds: 12 gas
  • 1000 rounds: 1000 gas

Input Format

Exactly 213 bytes required:
Offset | Length | Description
-------|--------|-------------
0      | 4      | rounds (big-endian u32)
4      | 64     | h (state vector, 8x u64 little-endian)
68     | 128    | m (message block, 16x u64 little-endian)
196    | 16     | t (offset counters, 2x u64 little-endian)
212    | 1      | f (final block flag, 0x00 or 0x01)
Total input length: Exactly 213 bytes (no padding, no truncation) All multi-byte integers except rounds are little-endian.

Output Format

Offset | Length | Description
-------|--------|-------------
0      | 64     | h (new state vector, 8x u64 little-endian)
Total output length: 64 bytes Output is the updated Blake2b state after applying the compression function.

Usage Example

import { execute, PrecompileAddress } from '@tevm/voltaire/precompiles';
import { Hardfork } from '@tevm/voltaire/primitives/Hardfork';
import * as Hex from '@tevm/voltaire/Hex';

// Blake2b compression with 12 rounds (standard)
const input = new Uint8Array(213);

// Set rounds (big-endian)
const view = new DataView(input.buffer);
view.setUint32(0, 12, false); // 12 rounds, big-endian

// Set state vector h - Blake2b-512 IV (8 x u64, little-endian)
const iv = [
  0x6a09e667f3bcc908n, 0xbb67ae8584caa73bn, 0x3c6ef372fe94f82bn, 0xa54ff53a5f1d36f1n,
  0x510e527fade682d1n, 0x9b05688c2b3e6c1fn, 0x1f83d9abfb41bd6bn, 0x5be0cd19137e2179n
];
iv.forEach((val, i) => view.setBigUint64(4 + i * 8, val, true));

// Set message block m (128 bytes, example data)
const message = Hex('0x48656c6c6f20426c616b6532622100' + '00'.repeat(115));
input.set(message, 68);

// Set offset counters t (little-endian u64s)
view.setBigUint64(196, 128n, true); // t0 = 128 (processed bytes)
view.setBigUint64(204, 0n, true);   // t1 = 0

// Set final flag f
input[212] = 0x00; // Not final block

const result = execute(
  PrecompileAddress.BLAKE2F,
  input,
  20n, // Need at least 12 gas for 12 rounds
  Hardfork.CANCUN
);

if (result.success) {
  console.log('New state:', result.output);
  console.log('Gas used:', result.gasUsed); // 12
} else {
  console.error('Error:', result.error);
}

Error Conditions

  • Input length ≠ 213 bytes (exact length required)
  • Out of gas (gasLimit < rounds)
  • Invalid final flag (not 0x00 or 0x01)

Use Cases

Production Applications:
  • Zcash Bridge: Verify Zcash Equihash proofs on Ethereum to enable trustless ZEC/ETH swaps. Equihash is a memory-hard proof-of-work algorithm based on Blake2b. The bridge contract uses Blake2f to verify Zcash block headers.
  • Cross-chain Bridges: Validate headers from blockchains using Blake2b:
    • Filecoin: Uses Blake2b for hashing (bridge to Ethereum)
    • Sia/Siacoin: Blake2b-based storage network
    • Decred: Uses Blake256 (related to Blake2)
  • Efficient Hashing in Contracts: Blake2b is ~10x cheaper than SHA256 per byte:
    • Large data structure hashing (Merkle trees)
    • Content-addressed storage systems
    • Efficient MACs and authenticated encryption
  • Custom Blake2 Variants:
    • Personalized hashing: Domain separation for different protocols
    • Tree hashing: BLAKE2bp parallel variant
    • Keyed hashing: HMAC-like authentication
Real-World Example: A Zcash-Ethereum bridge uses Blake2f to verify ~100 Zcash blocks (~10,000 Blake2f calls) for ~120,000 gas total, versus millions of gas if implemented in pure Solidity.

Implementation Details

  • Zig: Uses Blake2 crypto module implementing RFC 7693
  • TypeScript: Wrapper around Blake2 compression function
  • Integration: Standalone Blake2b F function
  • Algorithm: Blake2b compression as specified in RFC 7693
  • Rounds: Configurable (standard Blake2b uses 12)

Blake2b Algorithm Overview

What is Blake2b? Blake2b is a cryptographic hash function designed to be faster than MD5, SHA-1, SHA-2, and SHA-3 while maintaining strong security. It’s the 64-bit variant of Blake2 (Blake2s is the 32-bit variant). Key Features:
  • Performance: Up to 2x faster than SHA-3, comparable to MD5
  • Security: No known cryptographic weaknesses (finalist in SHA-3 competition)
  • Flexibility: Configurable output length, keyed hashing, salting, personalization
  • Simplicity: Simpler than SHA-3, easier to implement and audit
Standard Blake2b Parameters:
  • Rounds: 12 rounds per 128-byte block (can be reduced for performance/security tradeoff)
  • Output: Up to 512 bits (64 bytes), configurable
  • Block size: 128 bytes (1024 bits)
  • Word size: 64-bit (unlike Blake2s which uses 32-bit)
  • State: 8 x 64-bit words (512 bits total)
Compression Function F: The compression function F is the core of Blake2b. It takes:
  • Current state h (8 x 64-bit words)
  • Message block m (16 x 64-bit words = 128 bytes)
  • Offset counters t (2 x 64-bit words, tracks bytes processed)
  • Final block flag f (1 byte, marks last block)
And produces a new state h' by mixing the message into the state over multiple rounds.

Complete Blake2b Hashing

To hash a message completely using Blake2f:
  1. Initialize state h with Blake2b IV
  2. Process each 128-byte block:
    • Call Blake2f with current state
    • Update offset counter t
  3. Final block: set f=0x01
  4. State h is the hash output
// Simplified Blake2b using Blake2f precompile
function blake2b(message: Uint8Array): Uint8Array {
  let h = blake2bIV(); // Initial state
  let t = 0n;

  const blocks = Math.ceil(message.length / 128);
  for (let i = 0; i < blocks; i++) {
    const block = message.slice(i * 128, (i + 1) * 128);
    const input = encodeBlake2fInput({
      rounds: 12,
      h: h,
      m: padTo128(block),
      t: [t + BigInt(block.length), 0n],
      f: i === blocks - 1 ? 1 : 0
    });

    const result = executeBlake2f(input);
    h = result.output;
    t += BigInt(block.length);
  }

  return h; // 64-byte hash
}

Gas Cost Efficiency

Blake2f is extremely gas-efficient:
  • 12 rounds = 12 gas
  • Processes 128 bytes per compression
  • ~0.09 gas/byte (cheaper than all other hash functions)
Comparison (per 128 bytes):
  • Blake2f: ~12 gas
  • SHA256: ~108 gas (60 + 12*4)
  • Keccak256: ~66 gas (30 + 6*4)

Test Vectors

From RFC 7693 and EIP-152 official test suite:
import { execute, PrecompileAddress } from '@tevm/voltaire/precompiles';
import { Hardfork } from '@tevm/voltaire/primitives/Hardfork';
import * as Hex from '@tevm/voltaire/Hex';

// Vector 1: Empty message hash
// Hash of empty string with Blake2b should produce specific known output
const input1 = Hex(
  '0x0000000c' + // rounds = 12
  '6a09e667f2bcc948bb67ae8584caa73b3c6ef372fe94f82ba54ff53a5f1d36f1' + // h (IV XOR params)
  '510e527fade682d19b05688c2b3e6c1f1f83d9abfb41bd6b5be0cd19137e2179' +
  '00'.repeat(128) + // m (empty message)
  '0000000000000000' + '0000000000000000' + // t = [0, 0]
  '01' // f = final
);

const result1 = execute(PrecompileAddress.BLAKE2F, input1, 20n, Hardfork.CANCUN);
// result1.gasUsed === 12
// result1.output should match known Blake2b("") hash

// Vector 2: "abc" message hash
// Standard test vector - hash of "abc"
const input2 = Hex(
  '0x0000000c' + // rounds = 12
  '6a09e667f2bcc948bb67ae8584caa73b3c6ef372fe94f82ba54ff53a5f1d36f1' + // h (IV XOR params)
  '510e527fade682d19b05688c2b3e6c1f1f83d9abfb41bd6b5be0cd19137e2179' +
  '616263' + '00'.repeat(125) + // m = "abc" padded to 128 bytes
  '0300000000000000' + '0000000000000000' + // t = [3, 0]
  '01' // f = final
);

const result2 = execute(PrecompileAddress.BLAKE2F, input2, 20n, Hardfork.CANCUN);
// result2.gasUsed === 12
// Expected output (Blake2b("abc")):
// 0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1
//   7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923

// Vector 3: Variable rounds (1 round only)
// Tests gas calculation - should cost 1 gas
const input3 = Hex(
  '0x00000001' + // rounds = 1
  '6a09e667f2bcc948bb67ae8584caa73b3c6ef372fe94f82ba54ff53a5f1d36f1' + // h
  '510e527fade682d19b05688c2b3e6c1f1f83d9abfb41bd6b5be0cd19137e2179' +
  '00'.repeat(128) + // m
  '0000000000000000' + '0000000000000000' + // t
  '01' // f
);

const result3 = execute(PrecompileAddress.BLAKE2F, input3, 10n, Hardfork.CANCUN);
// result3.gasUsed === 1

// Vector 4: Maximum rounds
// Tests high round counts (Zcash uses higher round counts)
const input4 = Hex(
  '0x00002710' + // rounds = 10000
  '6a09e667f2bcc948bb67ae8584caa73b3c6ef372fe94f82ba54ff53a5f1d36f1' + // h
  '510e527fade682d19b05688c2b3e6c1f1f83d9abfb41bd6b5be0cd19137e2179' +
  '00'.repeat(128) + // m
  '0000000000000000' + '0000000000000000' + // t
  '01' // f
);

const result4 = execute(PrecompileAddress.BLAKE2F, input4, 15000n, Hardfork.CANCUN);
// result4.gasUsed === 10000

Byte Order Warning

Blake2f uses little-endian for h, m, t (unlike most Ethereum precompiles). Only rounds is big-endian. This matches Blake2b specification but differs from Ethereum convention.