Skip to main content

wots_rhdl/
lib.rs

1//! Profile-specific `HashSigsRS` WOTS+ schedulers and synthesizable RHDL tops.
2//!
3//! This crate is the hardware protocol layer of the workspace. It turns one
4//! already-hashed 32-byte message and one one-time private seed into a canonical
5//! fused signature/public-key stream, and it provides a separate public-data
6//! verifier for the SHA-256 profile. Hash primitives live in `keccak-rhdl` and
7//! `sha256-rhdl`; profile-safe host values and the independent software oracle
8//! live in `hashsigs-types` and `hashsigs-reference`.
9//!
10//! # Start with the security boundary
11//!
12//! `HashSigsRS` uses `n = 32`, `w = 16`, and 67 hash chains. Its inputs and
13//! encodings have several non-negotiable properties:
14//!
15//! - **Every private seed and derived private key is one-time.** Reusing either
16//!   value to sign another message can expose enough chain positions to permit a
17//!   forgery. The RHDL interfaces consume bytes, but they cannot know whether a
18//!   caller has submitted those bytes before. Durable one-time-use enforcement
19//!   is a system responsibility.
20//! - The message input is already a 32-byte digest. The caller owns application
21//!   prehashing, collision resistance, and domain separation.
22//! - Serialized keys, signatures, and 512-bit frames contain no profile tag. A
23//!   protocol must authenticate the selected build profile out of band.
24//! - The custom shared-mask/address construction is not XMSS, SLH-DSA, FIPS
25//!   205, or a many-time signature system. This crate does not claim the proof
26//!   of a standardized parameter set or an independent cryptographic audit.
27//! - Resetless secret/data registers are meaningful only while separately reset
28//!   ownership bits say so. Architectural overwrite is not physical
29//!   zeroization, remanence resistance, or side-channel evidence.
30//!
31//! # Profiles and implemented operations
32//!
33//! Profiles are different Rust types and different hardware build targets;
34//! there is no runtime hash-profile mux.
35//!
36//! | Profile | Compatibility | RHDL signing | RHDL verification |
37//! |---|---|---|---|
38//! | `LEGACY_KECCAK` | Byte-compatible with pinned `HashSigsRS`; legacy Keccak-256 `0x01` padding, not SHA3-256 | [`legacy::LegacyFusedPrivateSeedEngine`] and [`legacy::LegacyFusedPrivateKeyEngine`] | Not implemented; use the software oracle for legacy verification |
39//! | `HASHSIGS_SHA256_GENERIC_V1` | Deliberately incompatible with legacy keys and signatures | [`top::Sha256SignerTop`] | [`verify::top::Sha256VerifierTop`] |
40//!
41//! The private-key legacy ingress exists for pinned upstream vectors. The
42//! production SHA signer accepts a private seed. The SHA verifier consumes only
43//! public material. No legacy Keccak verifier top exists in this crate.
44//!
45//! All cryptographic datapaths are authored in Rust/RHDL. The modular signer
46//! and verifier aliases use a typed unresolved compression-lane leaf so the
47//! exact separately generated RHDL lane can be linked by an external HDL tool;
48//! they are not invitations to replace the lane with handwritten cryptographic
49//! RTL. Tcl, XDC, testbenches, and a future board shell remain outside this
50//! crate's cryptographic implementation boundary.
51//!
52//! # Signing work and selected topology
53//!
54//! Fused private-seed signing always advances every chain through all fifteen
55//! transitions. A signature segment is captured when the chain reaches the
56//! message/checksum digit, while the final value becomes a public-key endpoint:
57//!
58//! ```text
59//! private seed -> private key
60//!                       +-> public seed -> 16 masks
61//!                       +-> 67 secret PRFs
62//!                             -> 67 secret hashes
63//!                             -> 67 x 15 chain hashes
64//!                                  +-> capture 67 signature segments
65//!                                  +-> hash 67 endpoints into the public key
66//! ```
67//!
68//! Under `HASHSIGS_SHA256_GENERIC_V1`, this graph contains exactly 1,258
69//! SHA-256 compression tasks. [`engine::SingleContextWorkEngine`] represents one
70//! dependency-tracked job. Four contexts share one exact-latency compression
71//! lane inside [`cluster::LaneLocalCluster`], and the production top replicates
72//! that complete cluster three times:
73//!
74//! ```text
75//! top::Sha256SignerTop
76//!   +-- cluster 0: 4 contexts + 1 SHA-256 lane
77//!   +-- cluster 1: 4 contexts + 1 SHA-256 lane
78//!   +-- cluster 2: 4 contexts + 1 SHA-256 lane
79//!   +-- registered, frame-locked 3-to-1 data merge
80//!   +-- independent registered error merge
81//! ```
82//!
83//! The twelve contexts overlap independent dependency graphs; each context can
84//! issue at most once every two cycles because request construction includes a
85//! synchronous-memory prefetch. Complete tags carry local context, task class,
86//! task coordinates, and generation through the lane. Job IDs remain outside
87//! cryptographic state.
88//!
89//! [`sequencer::SingleContextSequencer`] and [`fabric::ShaTransportFabric`] are
90//! retained foundations from an earlier serial/central nine-context
91//! architecture. They are useful focused control oracles, but neither is
92//! instantiated by the selected three-cluster production signer.
93//!
94//! # Signer interface and output frame
95//!
96//! [`top::SignerTopInput`] and [`top::SignerTopOutput`] are the production SHA
97//! signer contract:
98//!
99//! | Signal group | Contract |
100//! |---|---|
101//! | `start_valid`, `start_ready`, `private_seed`, `message`, `job_id` | Accept one new one-time job when valid and ready are both true |
102//! | `output_valid`, `output_ready`, `output` | Transfer one registered 512-bit result beat when valid and ready are both true |
103//! | `error_valid`, `error_ready`, `error` | Transfer one independent identified error completion |
104//! | `fault` | Sticky structural/transport failure; shared reset is required before accepting more trusted work |
105//!
106//! Once admitted, a job owns a context until either its final successful beat is
107//! captured or its identified error is released. Output backpressure is a
108//! correctness contract: a stalled beat and its metadata remain stable. Frames
109//! never interleave. The successful stream is 2,208 bytes in 35 beats:
110//!
111//! | Beat | Low 32 bytes | High 32 bytes | `keep` / `last` |
112//! |---:|---|---|---|
113//! | 0 through 32 | Signature segment `2b` | Signature segment `2b + 1` | All bytes valid; not last |
114//! | 33 | Signature segment 66 | Public seed | All bytes valid; not last |
115//! | 34 | Public-key endpoint hash | Zero padding | Low half valid; last |
116//!
117//! [`framing::pack_fused_output`] and [`framing::unpack_fused_output`] are the
118//! independent host framing oracles. [`cluster::LaneLocalResultFramer`] reserves
119//! output capacity before exposing a result and releases local context credit
120//! only after ownership has moved safely to the next registered stage.
121//!
122//! Shared reset flushes all valid, allocation, request, result, and ownership
123//! state and suppresses transfers on the reset edge. Resetless wide data is
124//! ignored while its resettable valid bit is clear. A signer transport fault
125//! invalidates immediately preceding and outstanding work until shared reset;
126//! consumers must not treat a coincident data/error payload as trusted merely
127//! because its bytes are present.
128//!
129//! # SHA-256 verification
130//!
131//! Verification receives `signature`, `public_seed`, `public_key_hash`, and the
132//! 32-byte message digest as one exact 2,240-byte frame. It advances each
133//! signature segment only from its message digit to chain position fifteen,
134//! hashes all endpoints, and compares all 256 bits of the resulting public-key
135//! hash.
136//!
137//! Let `S` be the sum of `15 - digit` across the 64 message digits and let
138//! `h(S)` be the sum of the three hexadecimal checksum digits. Real verifier
139//! chain work is `S + 45 - h(S)`, ranging from 45 to 990 hashes. Including 16
140//! masks and 34 endpoint-stream blocks, a SHA verifier job emits between 95 and
141//! 1,040 compression tasks. Bypassed positions are idle state preservation, not
142//! hidden hash work.
143//!
144//! The selected verifier mirrors the signer hierarchy: four
145//! [`verify::sha::VerifySingleContextSha`] contexts share one lane inside
146//! [`verify::cluster::VerifierCluster`], and
147//! [`verify::top::Sha256VerifierTop`] replicates three clusters. The ingress
148//! frame contains exactly 35 full-valid beats:
149//!
150//! | Beats | Bytes |
151//! |---:|---|
152//! | 0 through 32 | Signature segments 0 through 65 |
153//! | 33 | Signature segment 66 followed by the public seed |
154//! | 34 | Public-key endpoint hash followed by the message digest |
155//!
156//! [`verify::top::VerifierTopInput`] uses a ready/valid stream and an independent
157//! `result_ready`. [`verify::top::VerifierTopOutput`] returns one registered
158//! [`verify::cluster::VerifyResult`] containing the opaque job ID, a `verified`
159//! decision, and an error code. Nonzero framing, transport, or audit errors
160//! always force `verified` false.
161//!
162//! Verifier transport is fail closed. A 64-entry expected-tag delay line checks
163//! the lane's exact 64-cycle return contract. Missing, extra, mistimed, swapped,
164//! malformed, unowned, or rejected tokens poison the owning cluster. The top
165//! registers that fault, aborts peers without a combinational sibling loop, and
166//! drains every already-accepted identity as a nonzero error. New admission and
167//! lane launch remain blocked until shared reset.
168//!
169//! # Evidence vocabulary and current status
170//!
171//! Evidence from one level never implies the next:
172//!
173//! | Tier | What it establishes | What it does not establish |
174//! |---:|---|---|
175//! | 1. Rust/RHDL source simulation | Source behavior and modeled cycle contracts | Generated RTL, mapping, timing, route, or hardware |
176//! | 2. Generated-Verilog simulation | Lowering equivalence for exercised traces | Formal equivalence, synthesis, timing, route, or card behavior |
177//! | 3. U280 synthesis | Mapping and utilization estimates | Routed timing or hardware throughput |
178//! | 4. U280 placement and routing | Routed utilization and achieved timing for the constrained design | Card/runtime behavior |
179//! | 5. Reserved-card execution | Measured behavior for the loaded artifact and workload | Other commits, constraints, or workloads |
180//!
181//! Current production-signer evidence reaches tier 2. A sustained
182//! generated-Verilog trace measured one 23,121-cycle aggregate interval spanning
183//! 48 results, or 481.6875 cycles/result. Normalizing that simulated aggregate
184//! interval at 250 MHz gives 519,008.693 signatures/second. This is arithmetic
185//! normalization, not evidence that the RTL synthesizes, fits, routes, meets 250
186//! or 300 MHz, or
187//! executes at that rate on a U280. The exact trace assumes an always-ready
188//! output; arbitrary stalls remain a correctness property, not a throughput
189//! guarantee.
190//!
191//! The production SHA verifier reaches tier 1. Its complete three-cluster source
192//! simulation admits twelve worst-case jobs, accepts and routes exactly 12,480
193//! SHA tasks, checks all results under stalls, and reaches quiescence. Its
194//! modular descriptor also has a bounded unresolved-skeleton check. It does not
195//! yet have linked generated-Verilog simulation, synthesis, timing, route, or
196//! card evidence.
197//!
198//! Legacy engines match the pinned upstream vectors in source/RHDL tests. That
199//! compatibility result does not establish synthesis, physical zeroization,
200//! side-channel behavior, timing, or card execution. No U280 utilization,
201//! timing-closure, routed, or hardware-throughput claim is made by this crate.
202//!
203//! # Newcomer reading order
204//!
205//! Follow the active path from protocol bytes to composed hardware:
206//!
207//! 1. [`crate::framing`] and [`crate::verify::framing`] define the exact output
208//!    and verification-input bytes before control logic is introduced.
209//! 2. [`crate::digits`] explains message/checksum digits; [`crate::blocks`]
210//!    defines every fixed SHA-256 preimage and byte-order boundary; and
211//!    [`crate::tag`] defines the sole 32-bit lane-tag encoding.
212//! 3. [`crate::engine`] is one active SHA signer context. Read its dependency,
213//!    reset, request-prefetch, response-validation, and secret-ownership
214//!    contracts before changing scheduling.
215//! 4. [`crate::cluster`] composes four contexts, one compression lane, and the
216//!    local result framer. [`crate::top`] composes exactly three such clusters
217//!    and owns only narrow global admission/data/error merges.
218//! 5. For verification, read [`crate::verify`] and then its `framing`, `tasks`,
219//!    `sha`, `transport`, `cluster`, and `top` modules in that order.
220//! 6. For byte-compatible signing, read [`crate::legacy`] after `keccak-rhdl`.
221//!    It is a separate serial engine, not a SHA signer mode.
222//! 7. Read [`crate::tasks`], [`crate::sequencer`], and [`crate::fabric`] when
223//!    auditing the serial task oracle or historical central-fabric experiments;
224//!    do not infer the production topology from them.
225//!
226//! # Source, test, and evidence map
227//!
228//! | Concern | Source | Focused tests / evidence |
229//! |---|---|---|
230//! | Profile-safe bytes and software semantics | `hashsigs-types`, `hashsigs-reference` | Upstream compatibility vectors and randomized differential tests |
231//! | Legacy signer | [`crate::legacy`] | `tests/legacy.rs` |
232//! | SHA block/digit/tag semantics | [`crate::blocks`], [`crate::digits`], [`crate::tag`] | `tests/tag_and_blocks.rs`, `tests/digits.rs` |
233//! | One SHA signer context | [`crate::engine`] | `tests/engine.rs` |
234//! | Active signer cluster and top | [`crate::cluster`], [`crate::top`] | `tests/cluster.rs`, `tests/top.rs`, `tests/top_full.rs` |
235//! | SHA verifier | [`crate::verify`] | `tests/verify_framing.rs` through `tests/verify_top_full.rs` |
236//! | Generated RTL and immutable manifests | `rhdl-gen` | `crates/rhdl-gen/tests/cli.rs` and date-stamped files under `evidence/rtl` |
237//! | U280 boundary | `fpga/u280` | Staged source manifest plus Vivado reports; none may be inferred from simulation |
238//!
239//! # Contributor workflow
240//!
241//! Start at the smallest owning layer and preserve its public contracts:
242//!
243//! 1. Add or update an independent host oracle before changing a cryptographic
244//!    kernel, framing rule, task count, or tag encoding.
245//! 2. Run the focused leaf test, then its context, cluster, and top tests. A
246//!    change is not integrated merely because its final digest matches; exact
247//!    task cardinality, identity, latency, reset flushing, fault behavior, and
248//!    backpressure also matter.
249//! 3. Keep `LEGACY_KECCAK` and `HASHSIGS_SHA256_GENERIC_V1` as distinct types and
250//!    build targets. Never introduce a runtime profile mux or silently reinterpret
251//!    serialized bytes.
252//! 4. Generate Verilog through `rhdl-gen`; do not patch generated cryptographic
253//!    RTL. Any unresolved modular skeleton must be linked with the exact
254//!    separately generated RHDL lane before an external parse or simulation.
255//! 5. Record negative results and promote claims only with matching source/RTL
256//!    provenance. A logical storage count is not mapped area, an output interval
257//!    is not clock closure, and synthesis is not a routed or card result.
258//!
259//! On memory-constrained hosts, use one Cargo job and one test thread. Expensive
260//! ignored gates document their own memory limits and evidence boundaries; they
261//! should never be folded into an ordinary quick test run.
262#![forbid(unsafe_code)]
263
264pub mod benchmark;
265pub mod blocks;
266pub mod cluster;
267pub mod digits;
268pub mod engine;
269pub mod fabric;
270pub mod framing;
271pub mod legacy;
272pub mod sequencer;
273pub mod tag;
274pub mod tasks;
275pub mod top;
276pub mod verify;
277
278pub use benchmark::{
279    AXI_RESP_OKAY, AXI_RESP_SLVERR, AxiLiteBenchmarkConfig, AxiLiteBenchmarkControl,
280    AxiLiteBenchmarkInput, AxiLiteBenchmarkKernel, AxiLiteBenchmarkOutput, BENCHMARK_ABI_VERSION,
281    BENCHMARK_AXI_ADDR_BITS, BENCHMARK_AXI_RANGE_BYTES, BENCHMARK_CHECKSUM_WORDS,
282    BENCHMARK_FAULT_ADMISSION, BENCHMARK_FAULT_COUNTER, BENCHMARK_FAULT_ERROR,
283    BENCHMARK_FAULT_FRAME, BENCHMARK_FAULT_NONE, BENCHMARK_FAULT_SIGNER, BENCHMARK_LIVE_JOB_SLOTS,
284    BENCHMARK_NONCE_WORDS, BENCHMARK_REJECT_INDEX_OVERFLOW, BENCHMARK_REJECT_NONE,
285    BENCHMARK_REJECT_ZERO_BATCH, BenchmarkChecksumInput, BenchmarkCounterAuditInput,
286    BenchmarkCounterAuditOutput, BenchmarkEngine, BenchmarkEngineControl, BenchmarkEngineData,
287    BenchmarkEngineInput, BenchmarkEngineOutput, BenchmarkFrameValidationInput,
288    BenchmarkJobMaterial, BenchmarkLaunchValidationInput, BenchmarkLaunchValidationOutput,
289    BenchmarkLiveJob, BenchmarkReadDecodeInput, BenchmarkReadDecodeOutput,
290    BenchmarkScoreboardAdmissionInput, BenchmarkScoreboardAdmissionOutput,
291    BenchmarkScoreboardAuditInput, BenchmarkScoreboardAuditOutput, BenchmarkScoreboardLookupInput,
292    BenchmarkScoreboardLookupOutput, ModularWotsSha256AxiLiteBenchmarkKernel,
293    ModularWotsSha256BenchmarkEngine, REG_ABI_VERSION, REG_ACCEPTED_LO, REG_AP_CTRL, REG_BASE_HI,
294    REG_BASE_LO, REG_BATCH, REG_BEATS_LO, REG_CHECKSUM_0, REG_CODES, REG_COMPLETED_LO,
295    REG_COMPLETION_SPAN_LO, REG_ELAPSED_LO, REG_ERRORS_LO, REG_FIRST_COMPLETION_LO, REG_GIE,
296    REG_IER, REG_ISR, REG_LAST_COMPLETION_LO, REG_NONCE_0, REG_PAYLOAD_CYCLES_LO, REG_RUN_BASE_HI,
297    REG_RUN_BASE_LO, REG_STATUS, WotsSha256AxiLiteBenchmarkKernel, WotsSha256BenchmarkEngine,
298    axi_lite_benchmark_kernel, benchmark_checksum_kernel, benchmark_counter_audit_kernel,
299    benchmark_engine_kernel, benchmark_frame_is_canonical_kernel, benchmark_job_material_kernel,
300    benchmark_launch_validation_kernel, benchmark_merge_write_kernel, benchmark_read_decode_kernel,
301    benchmark_scoreboard_admission_kernel, benchmark_scoreboard_audit_kernel,
302    benchmark_scoreboard_lookup_kernel,
303};
304pub use blocks::{
305    ChainBlockInput, EndpointPairInput, HashBytes, HashWords, PrfBlockInput, SecretDataInput,
306    ShaBlock, chain_block_kernel, endpoint_final_block_kernel, endpoint_pair_block_kernel,
307    hash_words_to_bytes_kernel, initial_state_words_kernel, prf_block_kernel,
308    private_seed_block_kernel, secret_data_block_kernel, secret_padding_block_kernel,
309    sha256_32_byte_block_kernel,
310};
311pub use cluster::{
312    AssembleLaneLocalBeatInput, CompressionLaneComponent, LANE_LOCAL_BEAT_BUFFER_DEPTH,
313    LANE_LOCAL_CONTEXTS, LANE_LOCAL_OUTPUT_BEATS, LaneFramerContextInput, LaneIssueControlInput,
314    LaneIssueControlOutput, LaneIssueInput, LaneIssueOutput, LaneLocalBeat, LaneLocalCluster,
315    LaneLocalClusterControl, LaneLocalClusterInput, LaneLocalClusterOutput, LaneLocalFramerControl,
316    LaneLocalResultFramer, LaneLocalResultFramerInput, LaneLocalResultFramerOutput,
317    LaneResponseRouteOutput, LaneResultSelection, LaneStartSelection,
318    ModularSha256LaneLocalCluster, Sha256LaneLocalCluster, assemble_lane_local_beat_kernel,
319    issue_lane_request_kernel, lane_issue_control_kernel, lane_local_cluster_kernel,
320    lane_local_result_framer_kernel, route_lane_response_kernel, select_lane_result_kernel,
321    select_lane_start_kernel,
322};
323
324pub use digits::{
325    MessageBytes, MessageDigitArray, SignatureCaptureInput, message_digits_kernel,
326    signature_capture_kernel,
327};
328pub use engine::{
329    CONTEXT_LOGICAL_RAM_BITS, ContextEngineInput, ContextEngineOutput, ENGINE_SEGMENTS,
330    EngineControl, MASK_STORAGE_BITS, PRIVATE_KEY_CONSUMERS, PUBLIC_KEY_FOCUS_BLOCKS,
331    PrepareRequestInput, SEGMENT_GROUPS, SEGMENT_STAGE_CHAIN_FIRST, SEGMENT_STAGE_CHAIN_LAST,
332    SEGMENT_STAGE_ENDPOINT, SEGMENT_STAGE_PRF, SEGMENT_STAGE_SECRET_DATA,
333    SEGMENT_STAGE_SECRET_PADDING, SIGNATURE_STORAGE_BITS, STATE_STORAGE_BITS, SegmentGroups,
334    SegmentSelection, SegmentStages, SignatureBanks, SignatureBanksInput, SignatureBanksOutput,
335    SingleContextWorkEngine, exclude_segment_groups_kernel, increment_segment_group_kernel,
336    prepare_request_kernel, public_key_endpoints_ready_kernel, segment_bit_kernel,
337    segment_required_mask_kernel, segment_task_fields_kernel,
338    select_public_key_focus_segment_kernel, select_ready_segment_kernel, set_segment_bit_kernel,
339    signature_banks_kernel, single_context_work_engine_kernel, state_pair_exclusion_kernel,
340    union_segment_groups_kernel, wake_segments_for_mask_kernel,
341};
342pub use fabric::{
343    CONTEXT_COUNT, IssueControlInput, IssueControlOutput, IssueInput, IssueOutput, LANE_COUNT,
344    ResponseControlInput, ResponseControlOutput, ResponseRouterInput, ResponseRouterOutput,
345    ShaTransportFabric, TransportInput, TransportOutput, host_issue_oracle,
346    host_response_router_oracle, issue_control_kernel, issue_requests_kernel,
347    response_control_kernel, route_responses_kernel, sha_transport_fabric_kernel,
348};
349pub use framing::{
350    FUSED_OUTPUT_BEATS, FusedBeat, FusedFrame, OUTPUT_BEAT_BYTES, OutputFrameError,
351    pack_fused_output, unpack_fused_output,
352};
353pub use legacy::{
354    LEGACY_CHAIN_STEPS, LEGACY_ENDPOINT_BLOCKS, LEGACY_FUSED_OUTPUT_BEATS,
355    LEGACY_FUSED_PERMUTATIONS, LEGACY_FUSED_PRIVATE_KEY_PERMUTATIONS, LEGACY_HASH_BYTES,
356    LEGACY_MASK_COUNT, LegacyBeatBytes, LegacyChainStateInput, LegacyEndpointBlockInput,
357    LegacyFusedBeat, LegacyFusedInput, LegacyFusedOutput, LegacyFusedPrivateKeyEngine,
358    LegacyFusedPrivateKeyInput, LegacyFusedPrivateSeedEngine, LegacyHashLanes, LegacyMaskStore,
359    LegacyOutputBeatInput, LegacyPrfStateInput, LegacyPrivateSeedBytes, LegacySecretStateInput,
360    LegacySegmentStore, legacy_bytes_to_lanes_kernel, legacy_chain_state_kernel,
361    legacy_digest_lanes_kernel, legacy_endpoint_block_state_kernel,
362    legacy_fused_private_key_kernel, legacy_fused_private_seed_kernel, legacy_hash32_state_kernel,
363    legacy_output_beat_kernel, legacy_prf_state_kernel, legacy_secret_state_kernel,
364};
365pub use sequencer::{
366    HardwareTaskCounts, SequencerInput, SequencerOutput, SingleContextSequencer,
367    decode_hardware_counts_kernel, encode_hardware_counts_kernel, single_context_sequencer_kernel,
368};
369pub use tag::{
370    DecodedTaskTag, TagFields, TaskKind, TaskTagError, decode_tag_kernel, decode_task_tag,
371    encode_tag_kernel, tag_is_well_formed_kernel,
372};
373pub use tasks::{TaskAudit, TaskCounts, TaskTraceError, audit_task_trace, canonical_task_trace};
374pub use top::{
375    GlobalBeatValidationInput, GlobalErrorMerge, GlobalErrorMergeControl, GlobalErrorMergeInput,
376    GlobalErrorMergeOutput, GlobalErrorSource, GlobalFrameMerge, GlobalFrameMergeControl,
377    GlobalFrameMergeInput, GlobalFrameMergeOutput, GlobalFrameSource, GlobalLaneSelection,
378    ModularSha256SignerTop, SIGNER_CLUSTER_COUNT, SIGNER_FRAME_BEATS, Sha256SignerTop,
379    SignerErrorCompletion, SignerOutputBeat, SignerTop, SignerTopControl, SignerTopInput,
380    SignerTopOutput, global_beat_is_canonical_kernel, global_error_merge_kernel,
381    global_frame_merge_kernel, select_global_lane_kernel, signer_top_kernel,
382};
383pub use verify::*;
384
385/// Maximum average simulated cycles per fused private-seed result in the sustained gate.
386///
387/// The gate measures one aggregate interval spanning 48 completed results; it
388/// does not assert that every individual inter-completion interval is at most
389/// this value. At the 250 MHz normalization frequency, an average of 500
390/// simulated cycles per result corresponds to 500,000 results per second. This
391/// is a generated-RTL simulation acceptance threshold, not evidence of an
392/// achievable clock, synthesis timing, route timing, or hardware throughput.
393pub const MAX_AVERAGE_CYCLES_PER_RESULT: usize = 500;