Skip to main content

Module engine

Module engine 

Source
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:

  1. How does the host talk to it? Through a register file on AXI4-Lite that follows the Vitis ap_ctrl_hs convention (“handshake” control: the host sets ap_start, the kernel reports ap_idle, ap_done, ap_ready). That lets ordinary XRT host code start the kernel and pass arguments without a custom driver.
  2. 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.
  3. 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:

  1. The host writes the arguments (addresses, counts, namespace, secrets) into the registers, then sets ap_start.
  2. MessageReader fetches messages from HBM and deals message n to slice n mod SLICES.
  3. Each Slice has been making one-time keys since start. It builds its subtree root for each batch and hands the root to the CertUnit, which joins all slice roots into the batch root and signs it with Ed25519. The certificate comes back to every slice.
  4. 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.

OffsetNameAccess
0x000AP_CTRL: bit 0 ap_start, 1 ap_done (clear on read), 2 ap_idle, 3 ap_readyRW
0x004GIE global interrupt enableRW
0x008IER bit 0 = done interruptRW
0x00cISR bit 0 = done (write 1 to toggle)RW
0x010arg messages: message buffer address (u64)W
0x018 + 8sarg frames{s}: slice s frame buffer address (u64)W
0x058arg count: messages to sign (u32)W
0x05carg batches: batches to make (u32)W
0x060arg epoch (u64)W
0x068arg first_batch (u64)W
0x070 + 4wargs cv0..cv7: derive-key prefix CV (secret)W
0x090 + 4wargs seed0..seed7: Ed25519 seed (secret)W
0x200MAGIC = 0x33475344 (“DSG3”)R
0x204ABI = ABI_VERSIONR
0x208SHAPE: slices in bits 0..8, table mask in bits 8..24R
0x20cFAULT bits: 0 writer, 1 reader, 2 cert, 3 sliceR
0x210/0x214TICKS lo (snapshots hi) / hiR
0x218/0x21cSTART_TICK lo/hiR
0x220/0x224DONE_TICK lo/hiR
0x228CERTIFIED batchesR
0x22cDEALT messagesR
0x230/0x234CERT_BUSY cycles lo/hiR
0x240 + 4sFRAMES[s] acknowledged per sliceR
0x260 + 4sKEYS[s] started per sliceR
0x280 + 4wPUBLIC_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::lease is 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) and seed0..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 (see crate::slice_model::prefix_cv).
  • Arguments freeze at start. Writes to argument offsets are dropped while running or done.

§Neighbours

ChildModuleRole here
readercrate::msg_readerHBM messages → per-slice buffers
slicescrate::slicekey factory, cache, subtree, signer
certcrate::cert_unitMerkle top + Ed25519 certificate per batch
writerscrate::hbm_writerframes → HBM, one port per slice
beatscrate::relayrelay pipes: frame beats flow at up to one per clock
messages, certificatescrate::relaytoggle links: at most one message per hash round trip and one certificate per 128 signatures need no relay stations
to_slice, from_slicecrate::relaydelay lines for configuration, roots, credit and status
(types)crate::axi4the 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.
EngineControl
Resettable control state.
EngineInput
Kernel inputs: every signal that enters the kernel from outside.
EngineOutput
Kernel outputs: every signal that leaves the kernel.
Registers
Host-written configuration: the kernel’s arguments.
SliceControl
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).
SliceReport
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
MAGIC register 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.