Expand description
A slice’s signer: one complete 1,642-byte signature every 68 cycles.
§Where this fits
By the time a message reaches the signer, almost all the work of signing it is already done. The key factory made the one-time key in advance and wrote its chain nodes to the key cache. The subtree builder hashed the key into its batch’s Merkle tree. The shared cert unit signed the batch root with Ed25519. What is left is to pick a key, hash the message, look up the right nodes, and write it all out in the wire format. That is this module.
The slice_factory fills the cache with keys; this
block spends them. For every message it:
- burns the slice’s next certified key (before anything else, so a
lost frame can never lead to key reuse) and asks the factory’s message
slot for
BLAKE3(pk_hash ‖ nonce ‖ message); - turns the 64-byte XOF into 68 base-4 digits (64 message digits and
a 4-digit complement checksum, as in
reference::digits_from_xof); - prepares the frame: reads four Merkle siblings, writes the six header beats, and computes the 34 header bytes that share a beat with the first node;
- streams the frame: one cached node per cycle, each read from the cache bank its digit selects, packed into beats.
Preparation of frame n + 1 overlaps the streaming of frame n, so in
steady state a slice finishes one frame every 68 cycles: exactly one key per
KEY_PERIOD, matching the factory.
message ─▶ [burn+hash] ─▶ factory slot ─▶ [digits] ─▶ [prep] ─▶ [stream] ─▶ frame buffer ─▶ writer
│ │ │ (4 frames)
key metadata RAM ◀── key_done proof port cache banks
certificate FIFO ◀── shared top(The “four Merkle siblings” are the 8-slice count, SUBTREE_LEVELS; the
other TOP_LEVELS siblings arrive inside the certificate.)
§Why the stages overlap
Streaming is the only stage that has to take 68 cycles (one node per
chain, one cache read per cycle). Everything else is shorter, so it is
done for the next frame while the current one streams. A work item moves
through a chain of holding registers in SignerControl:
queue[0..2] ──▶ prep ──▶ ready ──▶ stream ──▶ cache reads ──▶ packer ──▶ frame buffer ──▶ drain
(burned, (siblings, (prepared, (68 node (token rides (beats (4 slots of (26 beats
digits soon) header) waiting) addresses) with data) 6..25) 32 beats) to HBM)
time ─▶ |──── frame n streams (68) ────|──── frame n+1 streams (68) ────|
|hash n+1|prep n+1| (waits) |hash n+2|prep n+2| (waits)A new stream may begin addressing on the cycle right after the previous stream addressed chain 67, so streams run back to back with no gap.
§Frame layout (26 × 64-byte beats = 1,664 bytes)
Bytes 0..1642 are exactly
DsigSignature::to_bytes:
| Bytes | Field |
|---|---|
| 0..64 | certificate commitment (DSIGFP01 envelope) |
| 64..128 | Ed25519 signature |
| 128..130 | key index within the batch, LE16 |
| 130..162 | pk_hash |
| 162..178 | pk_nonce |
| 178..194 | private nonce |
| 194..418 | seven 32-byte Merkle siblings, bottom-up |
| 418..1642 | 68 revealed 18-byte nodes |
Bytes 1642..1650 carry the message index (LE64) so the host can match a
frame to its message; the remaining padding is zero.
The same layout seen as beats, and who writes each one:
beat 0 commitment ← preparation (from certificate)
beat 1 Ed25519 signature ← preparation (from certificate)
beats 2..5 frame bytes 128..384 (index, pk_hash, …) ← preparation (header_tail_kernel)
beat 6 bytes 384..418 (34 B) │ node 0 │ node 1 … ← packer (34 B are its prefix)
beats 7..24 nodes ← packer
beat 25 … node 67 │ msg index (B 42..50) │ zeros ← packer + index patch
beats 26..31 unused (each frame slot is 32 beats)§Ordering rules
- Keys are spent in cache-slot order, which is the order the factory made
them, so “key
kis finished” is the counter testdone > consumed. - A key is eligible only once its batch certificate is present.
- A certificate is retired after the last frame that needs it (this slice’s
j = 15key of that batch) has been prepared.
§The key-reuse rule
A one-time key must never sign twice. The signer increments consumed (the
burn) in the same cycle the factory accepts the message hash, before any
node is read. consumed only moves forward and the factory may not
overwrite a slot until its key is burned (see crate::slice). So even if
a frame is later lost, delayed or the run is reset, the key it used is
gone for good.
Structs§
- Certificate
- One batch certificate as delivered by the shared top.
- Frame
Beat - One frame beat for the HBM writer.
- KeyMeta
- Per-key metadata held until the key is spent.
- Message
- A message to sign.
- Node
Read - Everything needed to use one cache read when its data arrives.
- Signer
Control - Resettable control.
- Signer
Data - Resetless datapath registers.
- Signer
Input - Signer inputs.
- Signer
Output - Signer outputs.
- Slice
Signer - The slice signer.
- Work
- A burned key travelling through digits, preparation and streaming.
Constants§
- FRAME_
BEATS - Beats per frame.
- FRAME_
SLOTS - Frame slots in the frame buffer.
- HEADER_
BEATS - Header beats written by preparation.
Functions§
- cleared_
work - Kernel-side
idle_work: clears every field except the don’t-caremeta, which it keeps fromstale(kernels cannot calldont_care()). - digits_
kernel - 68 digits from the 64-byte message XOF (low two bits, then checksum).
- frame_
address_ kernel - Frame-buffer address of beat
beatin frame slotframe. - header_
tail_ kernel - The 290 header bytes after the signature (frame bytes 128..418).
- sibling_
address_ kernel - Subtree sibling address for
levelof keyjin batch ringring: the node next toj’s ancestor at that level. - slice_
signer_ kernel - The signer’s wiring.