Expand description
BLAKE3 compression and a fully pipelined Rust/RHDL implementation.
§Why this module exists
Haraka does the chain steps, but everything else a DSig key needs is
BLAKE3, in every profile: deriving the one-time seed, expanding it into
the 68 chain secrets and the nonces (BLAKE3’s extendable output, “XOF”),
committing to the 68 chain ends, building the Merkle tree, and hashing the
message. That is about 47 BLAKE3 compressions per signature
(sustained).
BLAKE3 hashes any input by cutting it into 64-byte blocks and running a compression function on each one. A tree-hashing controller decides the order, the counters and the flags; the compression function does the actual mixing. This module is only the compression function. The callers that drive it:
| Caller | What it hashes |
|---|---|
crate::slice_factory | seeds, XOF blocks, chain-end commitment, subtree, message digest, on a fixed 68-cycle timetable (crate::slice_schedule) |
crate::cert_unit | the Merkle levels shared by all slices |
crate::chain_lane | the chain step itself in the DSIG_CHAIN=blake3 profile |
crate::slice_model | the same work in plain Rust, using compress |
Because one BLAKE3 lane per slice serves all of that work, the lane must accept a new block every clock. So this file builds a fully pipelined compression: 28 register stages, one block in and one block out per clock.
§What one compression does
The state is 16 words of 32 bits, viewed as a 4 × 4 matrix. It starts as
the 8-word chaining value, 4 words of IV, the 64-bit counter, the block
length and the flags. Seven rounds then mix in the 16 message words:
state (16 × 32-bit words) one round = 8 G functions
┌─────┬─────┬─────┬─────┐
│ v0 │ v1 │ v2 │ v3 │ column step: G(v0,v4,v8,v12) G(v1,v5,v9,v13)
├─────┼─────┼─────┼─────┤ G(v2,v6,v10,v14) G(v3,v7,v11,v15)
│ v4 │ v5 │ v6 │ v7 │
├─────┼─────┼─────┼─────┤ diagonal step: G(v0,v5,v10,v15) G(v1,v6,v11,v12)
│ v8 │ v9 │ v10 │ v11 │ G(v2,v7,v8,v13) G(v3,v4,v9,v14)
├─────┼─────┼─────┼─────┤
│ v12 │ v13 │ v14 │ v15 │ then permute the 16 message words
└─────┴─────┴─────┴─────┘ (MESSAGE_PERMUTATION) for the next round
G(a, b, c, d) with message words x, y:
first half: a += b + x; d = (d ⊕ a) ⋙ 16; c += d; b = (b ⊕ c) ⋙ 12
second half: a += b + y; d = (d ⊕ a) ⋙ 8; c += d; b = (b ⊕ c) ⋙ 7(⋙ is a rotate right; + wraps at 2^32.) After seven rounds a
feed-forward XORs the two halves of the state together and the original
chaining value into the upper half, giving 16 output words.
§From the picture to a pipeline
The four G functions of a step are independent, so they run side by side. Each G is cut in half, so one round is four register stages:
CompressionInput ─▶ initialize ─▶ ┌ phase 0: column G, first half ┐ ─reg─▶
│ phase 1: column G, second half │ ─reg─▶ × 7 rounds
│ phase 2: diagonal G, first half │ ─reg─▶ = 28 stages
└ phase 3: diagonal G, second half┘ ─reg─▶
+ message permutation
─▶ feed_forward ─▶ CompressionOutputWhy half a G per stage: each half has two additions in series. A whole G
per stage would put four in series between two registers and lower the
clock the stage can reach. The out-of-context measurement of one BLAKE3
lane (~325 MHz alone, see sustained) is the evidence
that the 205 MHz target has margin; nothing in this file measures it.
§Reading order
- Constants:
ROUNDS,PIPELINE_STAGES, the flags,IV. - The software model:
compress,salted_digest_16. - Ports:
CompressionInput,CompressionOutput. - Kernels:
g_first_kernel,g_second_kernel,quarter_stage_kernel,feed_forward_kernel. - The pipeline:
RoundPipeline,round_pipeline_kernel,CompressionPipeline,InlineCompressionPipeline.
§Summary of the contract
CompressionPipeline implements all seven BLAKE3 rounds, with four
register transfers per round. Each stage executes one half of four parallel
G functions. Inputs are accepted every cycle; a corresponding output is
visible after exactly PIPELINE_STAGES registered transfers. There is no
backpressure. The caller must provision downstream capacity before sending
a valid token.
Message and chaining words use BLAKE3’s little-endian encoding. This is a
compression primitive, not a general-purpose tree-hashing controller. Its
caller owns block padding, chunk counters, flag selection, and chaining.
salted_digest_16 is the complete fixed-size online message operation:
the first 64 XOF bytes of BLAKE3(pk_hash || nonce || message), with a 32-byte
public-key hash, 16-byte nonce, and exactly 16 message bytes.
The round state, original chaining value, message schedule, and tag reside
in resetless registers. Only the valid bits reset. Data is unspecified when
valid is false, and reset discards every in-flight token. No resource,
routed-frequency, or board-throughput claim follows from this architecture.
Structs§
- Compression
Input - One compression request; all fields except
validare ignored in bubbles. - Compression
Output - Compression result;
wordsandtagare meaningful only when valid. - GState
- Four words manipulated by one BLAKE3 G function.
- Inline
Compression Pipeline - Copyable, zero-sized adapter for embedding the complete pipeline in a parent.
- Round
Pipeline - Registered prefix of the BLAKE3 compression pipeline.
- Round
State - Resetless token carried between the quarter-round stages.
Constants§
- BLOCK_
BYTES - Number of input bytes in a BLAKE3 compression block.
- CHUNK_
END - Marks the final block of a chunk.
- CHUNK_
START - Marks the first block of a chunk.
- DERIVE_
KEY_ CONTEXT - Selects the context-hashing step of BLAKE3 key derivation.
- DERIVE_
KEY_ MATERIAL - Selects the material-hashing step of BLAKE3 key derivation.
- IV
- BLAKE3 initialization vector, as specified by the BLAKE3 team.
- KEYED_
HASH - Selects BLAKE3’s keyed-hash mode.
- MESSAGE_
PERMUTATION - Word permutation applied after each complete round.
- MESSAGE_
SCHEDULE - Official seven-round message schedule, used by the independent Rust model.
- OUTPUT_
BYTES - Number of bytes returned by one BLAKE3 XOF output block.
- PARENT
- Marks a tree-parent block made from two child chaining values.
- PIPELINE_
STAGES - Number of registered G-half stages in a complete compression.
- ROOT
- Selects root/XOF output rather than an intermediate chaining value.
- ROUNDS
- Number of BLAKE3 compression rounds.
- SINGLE_
BLOCK_ ROOT - Flags for one complete, unkeyed, single-block root hash.
Functions§
- compress
- Compresses a single BLAKE3 block, returning all sixteen feed-forward words.
- compression_
pipeline_ unchecked_ verilog - Renders the complete pipeline without invoking RHDL’s external syntax check.
- compression_
pipeline_ verilog - Emits the complete checked 28-stage BLAKE3 compression hierarchy.
- decode_
block - Decodes a complete 64-byte block as sixteen little-endian words.
- encode_
words - Encodes sixteen compression-output words as 64 little-endian XOF bytes.
- feed_
forward_ kernel - Applies BLAKE3’s final XORs, without any additional registered transfer.
- g_
first_ kernel - Synthesizable first half of G: rotations by 16 and 12 bits.
- g_
second_ kernel - Synthesizable second half of G: rotations by 8 and 7 bits.
- initialize_
kernel - Constructs the round-zero working state without modifying input words.
- quarter_
stage_ kernel - Executes one quarter-round with compile-time phase selection in the pipeline.
- round_
pipeline_ kernel - Connects fixed-phase stages and aligns resettable validity with data/tag.
- round_
pipeline_ verilog - Emits a checked BLAKE3 pipeline or small test prefix as Verilog.
- salted_
block_ 16 - Constructs the exact single block
pk_hash || nonce || message. - salted_
digest_ 16 - Returns 64 BLAKE3 XOF bytes for the fixed 16-byte online-message profile.
- salted_
input_ kernel - Builds the fixed 16-byte-message input directly from RHDL word arrays.
Type Aliases§
- Compression
Pipeline - All seven BLAKE3 rounds, 28-cycle latency, and one input per clock.