Skip to main content

Module sbox_placement

Module sbox_placement 

Source
Expand description

Where each AES S-box lives: LUTs, block RAM or UltraRAM.

§Why this question matters

The default chain hash, Haraka-512, is built from AES rounds. The heart of an AES round is the S-box: a fixed table that replaces each byte with another byte. Every chain lane needs hundreds of them, and a slice has three lanes (crate::slice_chain). Built from LUTs (the FPGA’s small logic cells), S-boxes eat a large share of the LUT budget. But the U280 also has on-chip RAM blocks that the design does not otherwise fill. A ROM is just a RAM that nobody writes, so an S-box can live in a RAM block instead, freeing its LUTs.

Every S-box is a 256 × 8 ROM. The same ROM costs very different things in the three places a U280 can hold it:

PlaceCost per S-boxNotes
LUT ROM~32 CLB LUTsthe default; LUTs are the binding budget
Block RAM1 BRAM18 (½ BRAM36 tile)preloaded by the bitstream
UltraRAM1 URAMcannot be preloaded: a per-lane loader writes it after reset

A lane has 494 live S-boxes (LIVE_SBOX). The build chooses, per lane, how many go to UltraRAM and how many to block RAM:

DSIG_SBOX_PLACEMENT="uram=136,bram=358" cargo build ...   # per lane

They are assigned in order of (round, position) over the live S-boxes: UltraRAM first, then block RAM, the rest stay in LUTs. ULTRA_MASK and BLOCK_MASK record the result as one 64-bit mask per AES round; the S-box stages read them as compile-time constants, so only UltraRAM boxes get a write port.

A second, coarser choice is per round. DSIG_TABLE_MASK (bit r = AES round r, only rounds 3..=8) computes whole rounds with block-RAM T-tables (TableChainStepLane): a 256 × 32 ROM that returns an S-box output already multiplied into its MixColumns column, so a table round saves the S-boxes and most of the MixColumns XORs. TABLE_MASK holds it. Table rounds have no S-box stages, so the placement above skips them: with DSIG_TABLE_MASK=0x1f8 only the 142 live S-boxes of rounds 0, 1, 2 and 9 are left to place.

config predicts what a placement costs and how fast it is. (The LUT figure in the table above is an estimate; config explains how it was derived.)

§How the pieces fit

  DSIG_SBOX_PLACEMENT ─▶ build.rs ─▶ $OUT_DIR/sbox_placement.rs
                                        URAM_PER_LANE, BRAM_PER_LANE
                                               │  include!
                                               ▼
  chain_step::LIVE_SBOX ─────────▶ masks() ─▶ ULTRA_MASK, BLOCK_MASK
                                               │
                                               ▼
                         S-box stages (crate::aes_table) pick LUT / BRAM / URAM

The decision is made when the crate is compiled, not at run time: a different placement is a different bitstream. This lets synthesis see plain constants and build only the memory each S-box needs.

Constants§

BLOCK_MASK
Which positions of each round are block-RAM S-boxes.
BRAM_PER_LANE
S-boxes per lane in block RAM (DSIG_SBOX_PLACEMENT, or sbox-bram).
LANE_NEEDS_LOAD
The lane has at least one UltraRAM S-box, so it must be loaded after reset.
TABLE_MASK
AES rounds computed by block-RAM T-tables (DSIG_TABLE_MASK).
ULTRA_MASK
Which positions of each round are UltraRAM S-boxes.
URAM_PER_LANE
S-boxes per lane in UltraRAM (DSIG_SBOX_PLACEMENT).