Skip to main content

Module control_and_dataflow

Module control_and_dataflow 

Source
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]A intermediates;
  • 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 Ed25519Result

This 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 -> RESULT

A 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
-> RESULT

A 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
-> RESULT

The 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

  1. Add the state encoding in rhdl_ed25519_controller_types.
  2. Add its incoming and outgoing edges in rhdl_ed25519_transition.
  3. Generate child requests in rhdl_ed25519_commands.
  4. Capture or clear data in rhdl_ed25519_registers.
  5. Map errors/output in rhdl_ed25519_result.
  6. Wire new child data in rhdl_ed25519_top.
  7. Add a state-transition unit test and an end-to-end simulation.
  8. Inspect a waveform with backpressure, not only the no-stall case.