Expand description
A fully unrolled, fully pipelined SHA-512 compression function in RHDL: one 128-byte block per clock, shared by DSig and Ed25519.
§Building for Wolverine’s U280
This crate is a reusable RHDL compression pipeline, not a standalone XRT
card kernel. cargo build --locked -p rhdl_sha512_pipelined builds its Rust
library; it does not produce a .xclbin. Include the pipeline in an enclosing
kernel and generate that kernel’s RTL before packaging and linking with
Vivado/Vitis 2023.2 for the installed U280 platform.
For the existing card flows, follow the front-page instructions for Ed25519 or DSig. Resource and timing acceptance belongs to the complete routed kernel.
Run commands from the workspace root. Before compilation or RTL generation,
record ownership in PROJECT_COORDINATION.md and
/home/sahasta/Development/FPGA_COORDINATION.md, and use the applicable
nonblocking local-heavy.lock; crates/ed25519/tools/bounded.sh wraps local
Cargo commands with that lock and resource limits. Reserve Wolverine builds
in both ledgers too, then use crates/dsig/tools/with-u280-lock.sh to hold
u280.lock. Do not bypass a busy lock.
ShaIn ──▶ [input] ──▶ g0 ─▶ g1 ─▶ … ─▶ g7 ──▶ [final add] ──▶ ShaOut
p₀ = h+K₀+W₀ (8 groups × 10 round stages = 80 rounds)Every SHA-512 round has its own pipeline stage, so a new block can enter
every cycle and leaves LATENCY cycles later. There is no back-pressure:
ShaCoreOut::ready is always high and the output must be taken when it
appears (clients keep a credit counter; see the Ed25519 crate’s
CompressStage for the pattern).
§Why this crate exists
Problem. Ed25519 hashes with SHA-512: three blocks per signature and two per verification. Its first design gave each module a small private SHA ring that needs many cycles per block. Eleven such rings cost about 50k LUTs and still ran slowly.
Reasoning. SHA-512 is 80 rounds of the same simple step. Unrolling every round into its own pipeline stage costs more LUTs in one place, but then a single unit finishes a block every clock. One fast unit, shared by every client, beats many slow private ones.
Decision. One fully pipelined core, on its own SHA line whose
allowance comes out of the chip budget. Lines that need less than a
block per clock use folded cores instead (rings of 2–40 stages, 1/40
to ½ block per clock), and the planner sizes the line to what the chip
wants by default (a manual line is 65,000 LUTs and 20 DSPs by default; the 100 % budget of 485k LUTs and
4,520 DSPs is the engines’ 420k / 4,500 plus this default). Ed25519 signing and verification share it through an arbiter.
DSig’s SHA-512 chain profile (DSIG_CHAIN=sha512 in
rhdl_dsig_scalable_core) instantiates its own copies inside its slices,
because each slice needs three blocks per clock.
Status. Bit-exact against sha2 in simulation at full rate. The LUT
cost (about 43,200 for one core) is an estimate until synthesized.
§Making one round fit one clock
A round is
T1 = h + Σ1(e) + Ch(e, f, g) + K_t + W_t T2 = Σ0(a) + Maj(a, b, c)
a' = T1 + T2 e' = d + T1Five operands feed T1. Three of them, h + K_t + W_t, are known one
round early: h of round t is g of round t − 1, K_t is a constant
and W_t is already in the message window. So each stage also computes
p = g + K_{t+1} + W_{t+1} for the next stage (Stage::p), and the
critical path of a round is only p + Σ1(e) + Ch followed by one more add.
The message schedule is a 16-word window that shifts one word per round;
word t + 16 is computed in the stage that consumes word t. Constant
inputs (for example DSig’s zero-padded chain blocks) and unused late
schedule words are removed by synthesis.
§Ports
ShaIn: valid, a 16-bit tag, the block as 16 big-endian 64-bit
words, and the chaining value: the standard IV when use_iv, else chain
(so a multi-block message is resubmitted block by block). ShaOut: the
new chaining value chain + compress(chain, block) and the tag, in order.
§Validation
tests/compress.rs compares every output with sha2::compress512 on random
blocks, chained two-block messages, and a block every cycle (full rate),
and checks LATENCY.
§Where to go next
| You want to… | Start here |
|---|---|
| understand one round | round_kernel, then Stage |
| see how rounds become a pipeline | RoundGroup, Sha512Pipeline |
| change the line’s size in the planner | planner (feature planner) |
| share the core between clients | the Ed25519 crate’s sha_client (arbiter) |
| hash DSig chain steps with it | rhdl_dsig_scalable_core::chain_lane |
| build a line smaller than one block per clock | folded: rings of 2–40 stages, 1/40 to 1/2 block per clock |
| reach above one block per clock | open problem: a fixed-length single-block variant, DSP adders |
Modules§
- folded
- A folded SHA-512 core: S round stages in a ring,
S / 80blocks per clock, for lines smaller than one full pipeline. - planner
- The shared SHA-512 line as a component of the chip planner/TUI.
Structs§
- Round
Group - Ten consecutive rounds,
10·G .. 10·G + 10. - RoundIn
- A round stage’s input: the state and the next round’s constant.
- Round
Stage - One registered round.
- Sha512
Pipeline - The whole core: input stage, 80 rounds, final addition.
- ShaCore
Out - Core outputs.
- ShaIn
- One block request.
- ShaOut
- One finished block.
- Stage
- The state carried between round stages.
Constants§
- IV
- SHA-512 initial chaining value.
- K
- Round constants
K_0..K_79, plus a zeroK_80so the last stage’s look-ahead has something to read. - LATENCY
- Cycles from accepting a block to presenting its result: one input register, 80 round stages and one output register (the final addition).
Functions§
- big_
sigma0 Σ0(a) = rotr(a,28) ^ rotr(a,34) ^ rotr(a,39).- big_
sigma1 Σ1(e) = rotr(e,14) ^ rotr(e,18) ^ rotr(e,41).- round_
group_ kernel - Wire the ten rounds in series, each with its look-ahead constant.
- round_
kernel - One SHA-512 round on
s, plus the look-aheadpfor the next round (whose constant isk_next). - round_
stage_ kernel - Compute the round and register it.
- sha512_
pipeline_ kernel - Load a block, run the groups in series, add the chaining value.
- small_
sigma0 σ0(x) = rotr(x,1) ^ rotr(x,8) ^ (x >> 7).- small_
sigma1 σ1(x) = rotr(x,19) ^ rotr(x,61) ^ (x >> 6).