Skip to content

Convert BLAKE2s circuit to BLAKE2b#3

Merged
czarcas7ic merged 2 commits into
blake2b-orchardfrom
adam/blake2b-conversion
Feb 5, 2026
Merged

Convert BLAKE2s circuit to BLAKE2b#3
czarcas7ic merged 2 commits into
blake2b-orchardfrom
adam/blake2b-conversion

Conversation

@czarcas7ic
Copy link
Copy Markdown

@czarcas7ic czarcas7ic commented Feb 5, 2026

Summary

This PR converts the BLAKE2s Halo2 circuit to BLAKE2b for use in Orchard nullifier proofs.

BLAKE2s → BLAKE2b Changes

Feature BLAKE2s BLAKE2b
Word size 32 bits 64 bits
Rounds 10 12
Block size 64 bytes 128 bytes
Rotations (16, 12, 8, 7) (32, 24, 16, 63)
IV constants 32-bit 64-bit
Counter 64-bit 128-bit
Personalization 8 bytes 16 bytes
Output 32 bytes 64 bytes

Implementation Details

All changes are marked with // BLAKE2B-MOD: comments for easy review.

Constants:

  • 64-bit IV values
  • Rotation constants (32, 24, 16, 63)
  • 12 rounds (SIGMA cycles with i % 10)

Structs:

  • Blake2bWord with 64 bits (was 32)
  • Blake2bByte unchanged (8 bits)

Gates:

  • s_word_decompose: Updated for 8 bytes (was 4)
  • s_word_add: Uses F::from_u128(1u128 << 64) for carry
  • s_result_encode: Encodes 2×64-bit words per field (was 4×32-bit)
  • s_word_combine: NEW - Constrains 64-bit word = two 32-bit words combined

Architecture Decision - 32-bit Words for Field Decomposition:

The field decomposition and canonicality check retain 32-bit word granularity because:

  1. The Pallas modulus structure requires 32-bit precision for the canonicality check
  2. Minimizes changes to security-critical code
  3. The new s_word_combine gate soundly constrains: word_64 = word_32_lo + word_32_hi * 2^32

Soundness Fix (Critical):

The field_decompose function now properly constrains the 64-bit words via s_word_combine.
Previously, the 64-bit words were assigned via assign_free_advice without constraint,
allowing a malicious prover to manipulate hash inputs while passing verification.

Chip Methods:

  • add_mod_u64: Checks byte 8 for overflow
  • word_combine: Constrains 64-bit words to 32-bit pairs
  • word_decompose_32: Kept for field/canonicality (4 bytes)
  • word_decompose: Updated for BLAKE2b operations (8 bytes)
  • word_xor: Updated for 64 bits
  • word_rotate: Updated for 64 bits

Process/Compress:

  • 128-byte blocks (inputs.chunks(4))
  • 128-bit counter (t: u128)
  • 16-byte personalization

Test plan

  • test_blake2b_circuit: Basic constraint satisfaction
  • test_blake2b_empty_input: Empty input handling
  • test_blake2b_against_reference: Output matches reference implementation
  • test_blake2b_zeros_against_reference: Zero input test
  • MockProver verifies all constraints (k=17)

Security Considerations

  1. Canonicality check preserved: The critical soundness fix from Phase 1 is unchanged
  2. Boolean constraints: All bit decompositions properly constrain bits to {0,1}
  3. Copy constraints: All witness values connected via copy_advice
  4. Word combining: New s_word_combine gate ensures 64-bit words match 32-bit decomposition

Base

Built on top of blake2b-orchard branch (includes Phase 1 BLAKE2s soundness fixes).

@czarcas7ic czarcas7ic changed the base branch from main to adam/blake2b-orchard February 5, 2026 10:31
BLAKE2B-MOD changes:
- 64-bit words (was 32-bit)
- 12 rounds (was 10)
- Rotations: (32, 24, 16, 63) (was (16, 12, 8, 7))
- 64-bit IV constants
- 128-byte blocks (16 x 64-bit words)
- 128-bit counter
- 16-byte personalization (was 8 bytes)
- 64-byte output (was 32 bytes)

Circuit changes:
- Blake2bWord now contains 64 bits
- Added word_decompose_32 for field decomposition (canonicality check)
- word_decompose now handles 8 bytes for 64-bit words
- Updated s_word_decompose gate for 8 bytes
- Updated s_word_add gate for 64-bit arithmetic
- Updated s_result_encode for 64-bit word pairs
- field_decompose returns 4 x 64-bit words per field
- process() chunks inputs by 4 fields per 128-byte block
- compress() uses 128-bit counter

Note: Circuit requires k=17 due to increased size from 64-bit operations.
@czarcas7ic czarcas7ic changed the base branch from adam/blake2b-orchard to blake2b-orchard February 5, 2026 10:44
SOUNDNESS FIX:
- Add s_word_combine gate to constrain 64-bit words
- The gate enforces: word_64 = word_32_lo + word_32_hi * 2^32
- Previously, 64-bit words were assigned via assign_free_advice without
  any constraint tying them to the 32-bit words from field decomposition
- A malicious prover could set arbitrary 64-bit values while the bits
  remained correctly constrained, breaking hash integrity

TEST FIX:
- Reference function now uses 128-byte blocks (was incorrectly using 64)
- Counter calculation matches circuit: (block_idx + 1) * 128 for
  intermediate blocks, total_bytes.max(128) for final block

All 4 tests now pass:
- test_blake2b_circuit
- test_blake2b_empty_input
- test_blake2b_against_reference
- test_blake2b_zeros_against_reference
@czarcas7ic czarcas7ic marked this pull request as ready for review February 5, 2026 11:08
@czarcas7ic czarcas7ic merged commit 2f1f4a7 into blake2b-orchard Feb 5, 2026
czarcas7ic pushed a commit that referenced this pull request Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant