Expand description
The sustained-signing RTL kernel: eight slices, one certificate unit, HBM.
(Eight in the default build; SLICES is 2, 4 or 8, chosen by the
DSIG_SLICES build variable. The diagrams below draw the 8-slice case.)
§The problem
Everything else in this crate is a block: a key factory, a signer, a certificate unit. A card needs one top-level RTL kernel that Vitis can link: a box with a host control port and some HBM ports. This module is that box. It answers three questions:
- How does the host talk to it? Through a register file on
AXI4-Lite that follows the Vitis
ap_ctrl_hsconvention (“handshake” control: the host setsap_start, the kernel reportsap_idle,ap_done,ap_ready). That lets ordinary XRT host code start the kernel and pass arguments without a custom driver. - How do messages get in and frames get out? One HBM read master
(
crate::msg_reader) for messages and one HBM write master per slice (crate::hbm_writer) for frames. - How do we measure it honestly? With a free-running cycle counter that is latched at start and again when the last frame is acknowledged by memory.
§The pieces and how data flows
AXI-Lite (host) HBM
│ ▲ ▲ … ▲
┌─────────────▼───────────────────────────────────┼──┼───┼──┐
│ registers ── config/start ──┐ writer0 … writer7 │
│ ▲ counters, ticks ▼ ▲ ▲ │
│ │ MessageReader ──msg n──▶ slice (n mod 8) │
│ │ ▲ HBM │ roots / certs │
│ └────────────── CertUnit ◀───────────────┘ │
└──────────────────────────────────────────────────────────────┘Follow one message through the kernel:
- The host writes the arguments (addresses, counts, namespace, secrets)
into the registers, then sets
ap_start. MessageReaderfetches messages from HBM and deals messagento slicen mod SLICES.- Each
Slicehas been making one-time keys since start. It builds its subtree root for each batch and hands the root to theCertUnit, which joins all slice roots into the batch root and signs it with Ed25519. The certificate comes back to every slice. - The slice signs the message with a fresh key and streams the
26-beat frame to its own
HbmWriter, which writes it to HBM.
Every signal between a slice and a shared block passes through registers
(crate::relay): handshakes through relay pipes, the rest through
two-register delay lines. The slices sit in their own SLRs, up to two die
crossings from the shared blocks next to the HBM, and build v9 showed
that an unregistered link across that distance cannot run at 205 MHz.
5. When the writers’ acknowledged-frame counts add up to count, the
kernel stops, latches DONE_TICK and raises ap_done.
§The run lifecycle
reset ──▶ IDLE ──host writes args──▶ IDLE ──AP_CTRL bit0=1──▶ RUNNING
│ (args writable, │
│ no read path for secrets) frames_total == count
│ ▼
└────────── only a reset leaves ◀──────────────── DONE
(start_tick, done_tick
latched; ap_done set)running and done in EngineControl encode the states: IDLE is
neither, RUNNING is running, DONE is done. A start request is ignored
unless both are clear, and argument writes are ignored unless both are
clear, so nothing about a run can change after it starts.
§How a run is measured
The host programs the configuration registers, then writes CTRL.start.
The kernel latches the free-running tick counter at start, makes every key
from scratch, and latches the counter again when the last frame’s HBM write
response arrives. (done_tick − start_tick) cycles at the clock frequency
the host measures through the same counter
(reading the low word snapshots the high word) is
the denominator of the reported rate. The numerator is the number of frames
the host reads back and verifies.
One run per kernel reset: the kernel never restarts on its own, and the host must allocate a fresh namespace (epoch, batch range, master seed) for every run, because keys made but not spent are still burned.
§Register map (32-bit words)
The control block follows the Vitis ap_ctrl_hs convention, so the host
drives the kernel with ordinary xrt::kernel / xrt::run calls and
arguments; every argument below is declared in kernel.xml at its offset.
| Offset | Name | Access |
|---|---|---|
0x000 | AP_CTRL: bit 0 ap_start, 1 ap_done (clear on read), 2 ap_idle, 3 ap_ready | RW |
0x004 | GIE global interrupt enable | RW |
0x008 | IER bit 0 = done interrupt | RW |
0x00c | ISR bit 0 = done (write 1 to toggle) | RW |
0x010 | arg messages: message buffer address (u64) | W |
0x018 + 8s | arg frames{s}: slice s frame buffer address (u64) | W |
0x058 | arg count: messages to sign (u32) | W |
0x05c | arg batches: batches to make (u32) | W |
0x060 | arg epoch (u64) | W |
0x068 | arg first_batch (u64) | W |
0x070 + 4w | args cv0..cv7: derive-key prefix CV (secret) | W |
0x090 + 4w | args seed0..seed7: Ed25519 seed (secret) | W |
0x200 | MAGIC = 0x33475344 (“DSG3”) | R |
0x204 | ABI = ABI_VERSION | R |
0x208 | SHAPE: slices in bits 0..8, table mask in bits 8..24 | R |
0x20c | FAULT bits: 0 writer, 1 reader, 2 cert, 3 slice | R |
0x210/0x214 | TICKS lo (snapshots hi) / hi | R |
0x218/0x21c | START_TICK lo/hi | R |
0x220/0x224 | DONE_TICK lo/hi | R |
0x228 | CERTIFIED batches | R |
0x22c | DEALT messages | R |
0x230/0x234 | CERT_BUSY cycles lo/hi | R |
0x240 + 4s | FRAMES[s] acknowledged per slice | R |
0x260 + 4s | KEYS[s] started per slice | R |
0x280 + 4w | PUBLIC_KEY words (8 × u32) | R |
Arguments are accepted only while the kernel is idle and have no read path, so secrets cannot be read back. A completed kernel stays done until the next reset: one run per reset, each with a fresh namespace.
§Why the rules are so strict
A W-OTS+ one-time key that signs two different messages leaks enough of its chains to forge. So the kernel is built so that a key can never be reused, even by accident:
- A one-time key is never reused after admission, timeout, reset or
uncertain launch. The kernel has no “resume”: after a reset it starts
from nothing, and the host must give it a fresh namespace (epoch, batch
range, master seed).
crate::leaseis the host-side guard that never hands out the same run directory, namespace or batch range twice. - Secrets are write-only.
cv0..cv7(the derive-key prefix chaining value) andseed0..seed7(the Ed25519 seed) have no read path in the register file. The master seed itself is never stored on the card; the host passes only the derived prefix CV (seecrate::slice_model::prefix_cv). - Arguments freeze at start. Writes to argument offsets are dropped while running or done.
§Neighbours
| Child | Module | Role here |
|---|---|---|
reader | crate::msg_reader | HBM messages → per-slice buffers |
slices | crate::slice | key factory, cache, subtree, signer |
cert | crate::cert_unit | Merkle top + Ed25519 certificate per batch |
writers | crate::hbm_writer | frames → HBM, one port per slice |
beats | crate::relay | relay pipes: frame beats flow at up to one per clock |
messages, certificates | crate::relay | toggle links: at most one message per hash round trip and one certificate per 128 signatures need no relay stations |
to_slice, from_slice | crate::relay | delay lines for configuration, roots, credit and status |
| (types) | crate::axi4 | the AXI4 / AXI4-Lite signal structs |
The Verilog for this kernel is produced by the dsig_engine_export
binary, and the host program that drives it is dsig_engine_host.
Structs§
- Engine
- The kernel.
- Engine
Control - Resettable control state.
- Engine
Input - Kernel inputs: every signal that enters the kernel from outside.
- Engine
Output - Kernel outputs: every signal that leaves the kernel.
- Registers
- Host-written configuration: the kernel’s arguments.
- Slice
Control - What the engine sends a slice that tolerates latency: run configuration
(static during a run),
run, and the root credit (a late credit only makes the slice wait longer). - Slice
Report - What a slice reports that tolerates latency: the one-clock subtree-root pulse (the cert unit queues roots, and credit covers the delay), the status counters the host reads, and the fault bit.
Constants§
- ABI_
VERSION - Register-map version.
- MAGIC
MAGICregister value (“DSG3”).
Functions§
- engine_
kernel - The kernel’s wiring and register file.
- set_
half_ kernel - Replace the low or high half of a 64-bit register.