A synthesizable AES-128 encryption accelerator written in Verilog and targeted for the Lattice iCE40 FPGA family. The project implements the complete AES encryption datapath as a finite-state machine (FSM) composed of modular AES transformation blocks and includes a complete verification flow using Cocotb, FPGA implementation using the OSS CAD Suite, and UART communication with a host PC.
- AES-128 encryption (128-bit key)
- Modular RTL implementation
- SubBytes
- ShiftRows
- MixColumns
- Key Expansion (Key Schedule)
- AddRoundKey
- Sequential controller implemented as an FSM
- UART interface for communication with a host PC
- Cocotb-based verification
- Open-source FPGA toolchain
- Yosys
- nextpnr
- icepack
- icetime
- Timing and utilization reporting
- Seed sweep support to reduce Place-and-Route randomness
.
├── src/
│ ├── aes.v
│ ├── subbytes.v
│ ├── shiftrows.v
│ ├── mixcolumns.v
│ ├── keysched.v
│ ├── top_level.v
│ └── ...
│
├── scripts/
│ └── check_aes.py
│
├── tests/
│ └── testbench.py
├── constraints/
│ └── LatticeiCE40HX8K.pcf
│
├── Makefile
└── README.md
The top-level AES engine (file aes.v) is organized as a finite-state machine controlling each AES transformation.
+-------------+
| IDLE |
+------+------+
|
v
+-------------+
| SubBytes |
+------+------+
|
v
+-------------+
| ShiftRows |
+------+------+
|
+--------+--------+
| |
| Last Round? |
| |
No Yes
| |
v |
+-------------+ |
| MixColumns | |
+------+------+
|
v
+-------------+
| KeySchedule |
+------+------+
|
v
+-------------+
| AddRoundKey |
+------+------+
|
+-------> next round
|
v
DONE
The initial AddRoundKey operation is performed immediately after reset/start, followed by ten AES rounds. The final round omits the MixColumns transformation according to the AES specification.
- Uses a single S-Box instance
- Processes one byte per clock cycle
- Entire state computed in 16 cycles
- Uses a shift-register based architecture to minimize multiplexing and area
- Fully combinational permutation
- Result registered in a single clock cycle
- Fully sequential implementation
- Processes one 32-bit column per cycle
- Requires 4 clock cycles while
enaremains asserted - Optimized for reduced hardware utilization
- Sequential round key generation
- Produces one AES round key per invocation
- Lookup table for nonlinear byte substitution
The FPGA communicates with a host PC through UART.
- Baud rate: 1.5 Mbps
- Plaintext:
- 16 bytes transmitted from host
- Ciphertext:
- 16 bytes returned from FPGA
The supplied Python script performs an end-to-end verification using the standard AES test vector from FIPS-197.
aes_module.v provides the interface between the AES implementation (aes.v) and the UART interface (uart.v)
top_level.v wires UART interface to the AES interface.
The project uses Cocotb for RTL verification.
Individual tests include:
- Full AES encryption
- SubBytes
- ShiftRows
- MixColumns
- Key Schedule
- AddRoundKey
Results from the RTL are compared against a reference AES python library, which can be installed using:
pip3 install aesRun all simulations with:
make simAfter programming the FPGA, verify the design using:
python3 scripts/check_aes.pyThe script:
- Sends the standard AES plaintext
- Receives the encrypted ciphertext
- Compares the result against the expected NIST reference vector
Expected ciphertext:
3925841d02dc09fbdc118597196a0b32
The implementation flow uses the OSS CAD Suite.
Main tools:
- Yosys (Synthesis)
- nextpnr-ice40 (Place & Route)
- icepack (Bitstream generation)
- icetime (Static timing analysis)
Execute the complete synthesis and implementation flow:
make allTypical flow includes:
- RTL synthesis (Yosys)
- Technology mapping
- Place & Route (nextpnr)
- Bitstream generation
- Timing report generation
- Resource utilization report
Since FPGA Place-and-Route results depend on the random seed, the project includes a seed sweep target.
Run:
make seed-sweepThis performs multiple P&R runs using different seeds to reduce routing noise and obtain a better estimate of achievable timing.
Plaintext
3243f6a8885a308d313198a2e0370734
Key
2b7e151628aed2a6abf7158809cf4f3c
Expected Ciphertext
3925841d02dc09fbdc118597196a0b32
A compact summary of results can be produced using:
make report-infoThe design was synthesized for the Lattice iCE40 FPGA family using the OSS CAD Suite (Yosys 0.46+135, nextpnr-0.7-131-g9c2d96f8). The final implementation occupies approximately 27% of the available logic resources on the target device.
| Metric | Value |
|---|---|
| Total Cells | 2,862 |
| ICESTORM Logic Cells (LCs) | 2,083 / 7,680 (27%) |
| LUT4s | 1,510 |
| Flip-Flops (all variants) | 1,261 |
| Carry Cells | 69 |
| Block RAMs (SB_RAM40_4K) | 2 |
| Global Buffers | 1 |
| PLLs | 1 |
A report on synthesis results and cell usage can be seen in the log files or simply using the command:
yosys -p "read_verilog src/*.v; synth_ice40 -flatten; stat"The post-place-and-route timing analysis reports the longest critical path within the UART receive logic. The path spans 7 logic levels and determines the maximum achievable clock frequency.
| Metric | Value |
|---|---|
| Critical Path Delay | 8.84 ns |
| Logic Levels | 7 |
| Critical Module | UART Receiver (uart_inst) |
| Startpoint | uart_inst.rxctr[9] |
| Endpoint | data_from_rx[2] |
The Critical Path Report can be investigated using:
icetime -d hx8k -mtr build/top_level.rpt build/top_level.asc
cat build/top_level.rptBased on the critical path delay reported by timing analysis:
| Metric | Value |
|---|---|
| Critical Path Delay | 8.84 ns |
| Maximum Operating Frequency (Fmax) | 113.14 MHz |