Skip to main content

Crate rhdl_sha512_pipelined

Crate rhdl_sha512_pipelined 

Source
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 + T1

Five 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 roundround_kernel, then Stage
see how rounds become a pipelineRoundGroup, Sha512Pipeline
change the line’s size in the plannerplanner (feature planner)
share the core between clientsthe Ed25519 crate’s sha_client (arbiter)
hash DSig chain steps with itrhdl_dsig_scalable_core::chain_lane
build a line smaller than one block per clockfolded: rings of 2–40 stages, 1/40 to 1/2 block per clock
reach above one block per clockopen problem: a fixed-length single-block variant, DSP adders

Modules§

folded
A folded SHA-512 core: S round stages in a ring, S / 80 blocks per clock, for lines smaller than one full pipeline.
planner
The shared SHA-512 line as a component of the chip planner/TUI.

Structs§

RoundGroup
Ten consecutive rounds, 10·G .. 10·G + 10.
RoundIn
A round stage’s input: the state and the next round’s constant.
RoundStage
One registered round.
Sha512Pipeline
The whole core: input stage, 80 rounds, final addition.
ShaCoreOut
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 zero K_80 so 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-ahead p for the next round (whose constant is k_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).