Expand description
§Control and dataflow
§Top-level decomposition
[rhdl_ed25519_top::Ed25519Core] contains five groups of retained registers:
- metadata: state, operation, flags, lengths, counters, and pending child inputs;
- cache: validity, expanded scalar, prefix, and public key;
- work: current expanded key, public key, signature, nonce, and challenge;
- points:
A,R,[S]B, and[k]Aintermediates; - result: held result and point-codec response.
Child engines have their own ready/busy/done protocols. The top chooses one command per child and captures completion into retained registers.
§State ownership
The control plane is intentionally factored:
CoreStatus -> next_state_kernel -> next CoreState
CoreState -> command kernels -> child requests
responses -> register kernels -> retained work/cache
all above -> result kernel -> held Ed25519ResultThis makes the transition function inspectable as a finite-state machine and keeps large data muxes out of it.
§Derivation and signing states
The public-key path is:
IDLE -> KEY_HASH -> KEY_REDUCE -> KEY_MUL -> KEY_COMPRESS -> RESULTA cold sign continues from KEY_COMPRESS into:
SIGN_NONCE_HASH
-> SIGN_NONCE_REDUCE
-> SIGN_R_MUL
-> SIGN_R_COMPRESS
-> SIGN_CHALLENGE_HASH
-> SIGN_CHALLENGE_REDUCE
-> SIGN_MUL_ADD
-> RESULTA cached-key sign starts at SIGN_NONCE_HASH only if cached state is valid.
§Verification states
Verification intentionally rejects malformed inputs before the expensive equation:
VERIFY_CANONICAL
-> VERIFY_DECODE_A -> VERIFY_SMALL_A -> VERIFY_SMALL_A_COMPRESS
-> VERIFY_DECODE_R -> VERIFY_SMALL_R -> VERIFY_SMALL_R_COMPRESS
-> VERIFY_HASH -> VERIFY_K_REDUCE
-> VERIFY_S_MUL -> VERIFY_K_MUL
-> VERIFY_TO_NIELS -> VERIFY_ADD -> VERIFY_COMPRESS
-> RESULTThe two “compress” names following small-order loops refer to completing the identity test in the shared point path; consult the actual command and point response wiring before renaming states based only on their labels.
§Shared multiplier arbitration
Point compression/decompression and ordinary point operations share the field multiplier bank. The point codec has priority when it issues a multiplication; otherwise the point controller owns the bank. Scalar multiplication is itself a controller that emits point operations, so it does not bypass this arbitration.
When adding concurrency, preserve response ownership. A multiplier result must be tagged or structurally guaranteed to return to the context that issued it. The compatibility core obtains this guarantee by allowing only one owning controller at a time.
§RHDL synchronous pattern
Most engines implement SynchronousIO and a #[kernel] next-state function:
(clock/reset, input, current Q) -> (output, next D)Q is the current registered state and D is the next registered state.
Assignments to D do not become visible until the following rising edge. Many
off-by-one bugs in RHDL simulation are actually violations of that distinction.
For BRAM, issue the read address in one state and capture Q.ram in a later
state. Do not assume an asynchronous read unless the instantiated memory
primitive explicitly provides one.
§Adding a state safely
- Add the state encoding in
rhdl_ed25519_controller_types. - Add its incoming and outgoing edges in
rhdl_ed25519_transition. - Generate child requests in
rhdl_ed25519_commands. - Capture or clear data in
rhdl_ed25519_registers. - Map errors/output in
rhdl_ed25519_result. - Wire new child data in
rhdl_ed25519_top. - Add a state-transition unit test and an end-to-end simulation.
- Inspect a waveform with backpressure, not only the no-stall case.