Expand description
Ed25519 as the signature service of a uBFT replica (feature ubft).
§The problem
uBFT runs consensus entirely
on an Alveo U280. On its slow path every replica signs a 64-bit summary
of the slot, sends the signature to every peer, and verifies the shares
it receives until it holds 2f + 1. It calls the Vitis Security
Library’s Ed25519 inline, so the whole state machine stops for every
signature and every verification. That signer is the routed design’s
worst path (−2.866 ns), which pulls the kernel clock from 300 MHz down
to 161.3 MHz. It also hashes only one byte of the summary: the calls pass
a length of 1.
§The idea
UbftEd25519 is a service that sits next to uBFT on the chip. It takes
one request at a time on a stream and answers in microseconds, with the
same streams and header layout as DSig’s service (rhdl_dsig_scalable_core
ubft), so uBFT picks a scheme at compile time with the same HLS stream
calls. Inside are this crate’s cached-key signer and known-key verifier.
uBFT ──sign request──▶ ┌────────────── UbftEd25519 ──────────────┐
◀──R‖S, tag────── │ Ed25519SignCore (cached key) │
uBFT ──verify request─▶│ KnownKeyVerifyCore, 16 trusted key slots│
◀──verdict word── └──── AXI4-Lite: seed, keys, counters ────┘- Signing. A request is one 64-byte beat: an 8-byte tag, then a
48-byte message (layout v2,
ABI_VERSION2). The signed message is those 48 bytes zero-extended to 64 bytes, an ordinary RFC 8032 signature that any Ed25519 library checks. rhdl_ubft puts a domain magic, a role, a session id and its(view, slot, k, m)there, so a share from another run or another role does not verify. (v1 signed bytes 0..16 and carried the tag at 16..24.) The answer is two beats:R‖S(the 64 bytes uBFT mails to its peers), then the tag. - Verifying. A request is three beats: a header (the signer’s key
slot and a 32-bit tag), the 64-byte message as it was signed, and
R‖S. The verdict word comes back with the slot and the tag. - Peers. One key per replica, so the verifier trusts up to
KEY_SLOTS= 16 keys (N ≤ 17replicas; uBFT hasN ≤ 12). - Order. Answers can come back out of order. Match them by tag.
§Streams
| Port | Direction | Beat | Content |
|---|---|---|---|
s_axis_sign | in | 512 bits | bytes 0..8 tag (LE64), 8..56 message |
m_axis_sig | out | 512 bits, tlast on beat 1 | beat 0: R‖S; beat 1: bytes 0..8 tag |
s_axis_verify | in | 512 bits, tlast on beat 2 | beat 0: byte 0 bits 0..4 key slot, bytes 4..8 tag (LE32); beat 1: message; beat 2: R‖S |
m_axis_verdict | out | 64 bits | bits 0..8 verdict, 8..12 key slot, 32..64 tag |
A verdict of 0x80 means valid. Otherwise it is 0x80 | code, with a
VERIFY_* code of crate::verify_core: 7 means the slot’s key is not
loaded, 6 that the equation failed.
§Register map (32-bit words)
| Offset | Name | Access |
|---|---|---|
0x000 | AP_CTRL: bit 0 ap_start, 1 ap_done (clear on read), 2 ap_idle, 3 ap_ready | RW |
0x004/0x008/0x00c | GIE / IER / ISR | RW |
0x010 | arg sign_count: signatures this session | W |
0x014 | arg verify_count: verifications this session | W |
0x050 + 4w | args seed0..seed7: the signer’s Ed25519 seed (secret) | W |
0x070 | arg key_mask: trusted key slots in use (bits 0..16) | W |
0x200 | MAGIC = MAGIC (“ESU1”) | R |
0x204 | ABI = ABI_VERSION | R |
0x208 | SHAPE: fixed-base machines bits 0..8, verify machines 8..16, key slots 24..29 | R |
0x20c | FAULT: bit 0 signer, 2 verify core, 3 a trusted key rejected, 4 verify stream framing | R |
0x210/0x214 | TICKS lo (snapshots hi) / hi | R |
0x218/0x21c | START_TICK lo/hi | R |
0x220/0x224 | DONE_TICK lo/hi | R |
0x228/0x22c | KEY_TICK lo/hi: the signer’s key and the trusted keys are loaded | R |
0x230 | SIGNED: signatures sent | R |
0x234 | SIGN_TAKEN: sign requests accepted | R |
0x238 | VERIFIED: verdicts sent | R |
0x23c | VALID: verdicts that were 0x80 | R |
0x250 + 4i | sign latency: N, LAST, MIN, MAX, SUM lo, SUM hi | R |
0x270 + 4i | verify latency: same six words | R |
0x2a0 + 4w | PUBLIC_KEY: the signer’s Ed25519 public key (8 × u32) | R |
0x400 + 0x20·s + 4w | args key{s}_{w}: slot s’s public key, bytes 4w..4w+4 LE | W |
The words up to 0x2c0 sit where DSig’s service has them. The trusted
keys moved to 0x400: 16 slots at DSig’s 0x080 would run into the
status words at 0x200.
§How latency is measured
As in DSig’s service: the kernel times isolated requests on its own clock, from the request’s first handshake to the answer’s last, when no other request of the same kind is in flight. Loaded latency is not measured here.
§Session rules
The host writes the seed, the keys, key_mask and the counts, then sets
ap_start. The signer expands its seed and the loader puts each masked
key into the verifier, about 105,000 cycles each. The sign stream opens
once the signer’s key is cached and the verify stream once every masked
slot has settled. The session is done when sign_count signatures and
verify_count verdicts have left. The seed has no read path.
Structs§
- AxiLite
In - AXI4-Lite requests from the host (the layout of DSig’s
AxiLiteIn, so both services use one Verilog wrapper). - AxiLite
Out - AXI4-Lite responses, every one from a register (the layout of DSig’s
AxiLiteOut). - Axis64
- One 64-bit stream beat (the verdict stream).
- Axis512
- One 512-bit stream beat (
tvalid,tdata,tlast;treadytravels the other way as a plainbool). The layout of DSig’sAxis512. - Latency
- Isolated-request latency statistics, in cycles.
- Ubft
Ed25519 - The uBFT Ed25519 service kernel: a signer with
NFBfixed-base machines and a verifier withNVverify machines (one SHA-512 ring and one scalar ring each). uBFT signs once per consensus slot and verifies at mostN − 1shares, soUbftEd25519<1, 1>is the usual build. - UbftIn
- Kernel inputs.
- UbftOut
- Kernel outputs.
Constants§
- ABI_
VERSION - Register-map version.
- ARG_
KEYS key0_0; slots, wordwat+ 0x20·s + 4w.- ARG_
KEY_ MASK key_mask.- ARG_
SEED seed0.- ARG_
SIGN_ COUNT sign_count.- ARG_
VERIFY_ COUNT verify_count.- IN_
FLIGHT - Requests of each kind the service holds at once (in a core or waiting on an output stream): the tag tables’ size.
- MAGIC
MAGICregister value (“ESU1” in little-endian ASCII).- REG_ABI
ABI.- REG_
DONE_ TICK DONE_TICKlo.- REG_
FAULT FAULT.- REG_
KEY_ TICK KEY_TICKlo.- REG_
MAGIC MAGIC.- REG_
PUBLIC_ KEY PUBLIC_KEYwords.- REG_
SHAPE SHAPE.- REG_
SIGNED SIGNED.- REG_
SIGN_ LATENCY - Sign latency block (six words).
- REG_
SIGN_ TAKEN SIGN_TAKEN.- REG_
START_ TICK START_TICKlo.- REG_
TICKS TICKSlo.- REG_
VALID VALID.- REG_
VERIFIED VERIFIED.- REG_
VERIFY_ LATENCY - Verify latency block (six words).
Functions§
- beat_
words - A beat’s bytes as eight little-endian words.
- latency_
kernel - Opens or closes a latency measurement (DSig’s rule):
beginwhen a request is taken with none in flight,endwhen an answer’s last beat leaves with one in flight,abandonwhen a second request arrives. - latency_
word - One register word of a latency block (
i= 0N, 1LAST, 2MIN, 3MAX, 4SUMlo, 5SUMhi). - lowest_
free - The lowest set bit of a tag table’s free mask (index 0 if none is set).
- sign_
message - The message a sign beat asks for, layout v2 (ABI 2): bytes 8..56 of the beat (words 1..7), zero-extended to 64 bytes. Bytes 0..8 are the tag and are not signed. The service signs exactly this; tests call it to get the same bytes.
- ubft_
ed25519_ kernel - The kernel’s logic.
- words_
beat - Eight little-endian words as a beat’s bytes.