Expand description
Detailed hardware boundaries, scheduling, representation, and integration.
§Architecture Guide
This document is the map from the public request interface to the arithmetic pipelines. It assumes basic synchronous-logic knowledge but no prior FPGA cryptography experience.
Start with the visual guide for the signature recipe, annotated parallel paths, pipeline timing, and resource map.
§Design boundary
Fast64Core is a synchronous RHDL component. It has three independent input
operations: load/clear the cached signing key, submit a cached-key signing
request, and submit a strict-verification request. Signing and verification
share only the result arbiter; their cryptographic pipelines run concurrently.
The module deliberately excludes AXI, PCIe, clocks, and reset synchronization. An integration shell should register the wide request boundary, convert its transport to ready/valid, and keep transport counters outside the cryptographic core. This separation makes the core reusable and keeps protocol timing out of the arithmetic placement region.
§RHDL conventions
Every stateful block implements SynchronousIO and has a #[kernel] next-state
function. In a kernel:
iis the current cycle’s external input;qis registered state and child-module output;dis the next state and child-module input;- the returned output is combinationally derived from
iandq; - child outputs observed in
qcorrespond to earlier child inputs assigned tod.
RHDL’s DFF and SyncBRAM primitives are used instead of handwritten HDL.
Array sizes are compile-time constants because they become physical storage.
Types such as b51 and b16 are exact-width hardware integers, not Rust host
integers.
§Signing pipeline
CachedSignCore stores one expanded seed, nonce prefix, and public key. Key
load hashes the 32-byte seed with hardware SHA-512, clamps the lower half, and
computes the public key with fixed-base multiplication.
Each accepted signing request occupies one of 128 contexts:
- Hash
prefix || messageusing one SHA-512 block (96 bytes plus padding). - Reduce the digest modulo the Ed25519 group order to obtain nonce
r. - Compute
[r]Bwith the 24-context signed multi-comb engine. - Pair point-compression requests so two projective points share one inversion.
- Hash
R || A || messageusing two SHA-512 blocks. - Reduce the challenge digest to scalar
k. - Compute canonical
S = r + k*a mod lin the scalar multiply-add pipeline. - Retire
R || Swith the original tag.
Messages and per-request scalars are in inferred BRAM. The default wide-sign
profile uses eight SHA lanes, two multi-comb engines, and two pair compressors.
--no-default-features selects four SHA lanes and one of each point engine.
Credit-bounded BRAM mergers preserve results when parallel lanes finish together.
§Strict-verification pipeline
Each accepted verification request occupies one of 64 contexts. The scheduler launches independent work as soon as operands are available:
- Check
S < lwithout reducing noncanonical input. - Decode public key
Aand signature pointRin two parallel decoder lanes. - Reject noncanonical encodings, points not on the curve, and low-order points.
- Hash
R || A || messagein hardware and reduce the digest tok. - Compute
[S]Bin the fixed-base multi-comb engine. - Compute
[k]Ain one of two variable-base lanes. - Check
[S]B = R + [k]Awith projective cross-products. - Retire the decision, stable error code, and original tag.
The point decoders use the fixed exponent (p-5)/8. Every request executes the
same exponentiation schedule. Variable-base multiplication executes both a
doubling and an addition for each of 256 bits, then selects the correct point.
This is deliberately more regular than a secret-indexed window table.
§Arithmetic representation
Field elements modulo p = 2^255 - 19 use five 51-bit limbs. A field
multiplication decomposes each 51-by-51 limb product into six registered
26-by-17 partial products. The complete five-by-five product matrix therefore
contains 150 small 26 x 17 multiplies. The decomposition is chosen to encourage DSP
mapping and to put registers between adder levels.
Scalars modulo
l = 2^252 + 27742317777372353535851937790883648493 use four 64-bit words at
module boundaries and radix-2^16 internally. Reduction folds high limbs with
the small constant l - 2^252; multiply-add uses spatial coefficient banks and
registered normalization stages.
Edwards points use extended projective (X:Y:Z:T) coordinates. Verification
compares projective points directly, avoiding a final inversion. Compression
uses batched inversion only where the encoded R or public key is required.
§Fixed-base table
The signed 4-block, 8-tooth, spacing-8 multi-comb table has four logical banks and 128 entries per bank. One logical entry is 765 bits. Eight physical read replicas scan public address groups in parallel, making the initialized payload 3,133,440 bits before implementation packing. Secret bits select only among already registered candidates and never address RAM.
The table is generated at Rust build time from checked .mem assets. The
generated values are ordinary RHDL SyncBRAM initialization; no Verilog table
source exists in the crate.
§Throughput reasoning
Throughput is set by initiation interval, not single-request latency. Context rotation hides multiplier latency while an operation from a different request issues each cycle.
- Fixed-base multiplication has 24 contexts and four field multipliers.
- Point decoding has 20 contexts per lane and one field multiplier.
- Variable-base multiplication has 20 contexts per lane and four field multipliers. One lane issues 1,024 four-product rounds per scalar; the strict verifier has two lanes.
- The equation stage has 20 contexts and four field multipliers.
- Signing has 128 top-level contexts; verification has 64.
These counts are architectural inputs, not performance claims. RHDL simulation
must measure sustained accepted/completed request spacing, and the U280 build
must supply post-route frequency. Operations per second are calculated only as
post_route_hz / measured_steady_state_interval.
§Memory traffic
There is no external-memory port in Fast64Core. For each operation the shell
delivers exactly one 64-byte message. A sign result is 64 bytes; a verify result
is a tag, decision, and error code. Public keys and signatures are part of the
request payload. All repeated access is to registers, distributed RAM, or
inferred BRAM inside the module.
Consequently, cryptographic DRAM/HBM scratch traffic is zero. System-level benchmarks must still count request and result transport bytes, PCIe traffic, and any buffers owned by the integration shell; those are not silently called zero.
§Safe modification checklist
- Preserve ready/valid acceptance and tags at module boundaries.
- Keep secret-dependent addresses and loop bounds out of arithmetic changes.
- Add a Dalek differential test before changing a representation or formula.
- Test back-to-back requests, not only isolated latency.
- Compile the changed module with RHDL before compiling the full top.
- Regenerate the single top-level netlist; never patch generated Verilog.
- Re-run synthesis after changing array size, pipeline depth, or context count.
- Treat simulated interval and post-route frequency as separate measurements.
§Integration checklist
Register the wide input and output bundles at the shell boundary. Do not insert
combinational transport logic into the arithmetic Pblock. Reset the core
synchronously according to the generated RHDL wrapper, wait for readiness, and
honor every ready/valid transfer exactly once. Before loading a new tenant’s
key, stop accepting signs, drain all accepted signs, and wait for any key
expansion to finish. Keep request-valid inputs low while asserting clear_key,
then observe key_loaded == false. This clears the cached key, not necessarily
every intermediate pipeline register; it is not a complete physical-remanence
or side-channel guarantee.