International Association for Cryptologic Research

International Association
for Cryptologic Research

Transactions on Cryptographic Hardware and Embedded Systems 2026

Additive FFTs for HQC on ARM Cortex-M4, Revisited


README

The TCHES paper is available at https://eprint.iacr.org/2026/739 .

HQC on Arm Cortex-M4

This repository contains implementations of HQC for Arm Cortex-M4 microcontrollers. Code can be tested using QEMU emulation or deployed on a STM32L4R5 Nucleo-144 board for performance benchmarking.

benchmark results

Multiplication

hqc-1 hqc-3 hqc-5
1753860 4836147 9290004

The table is part of table 4 in the paper.

New codec

operation hqc-1 hqc-3 hqc-5
Encode 7945 14878 26752
Decode 909832 1348110 2337350

The table is part of table 5 in the paper.

HQC component

operation hqc-1 hqc-3 hqc-5
Keygen 2928092 8054559 12701974
Encap 5187762 14427435 21890093
Decap 8748583 22876873 34771718

The table is part of table 6 in the paper.

Prerequisites

Linux (recommended: Ubuntu) or MacOS is required to use this project. If you are using Windows, we highly recommend using an Ubuntu virtual machine, e.g., using Virtual Box. WSL2 also works for building and QEMU; flashing a board from WSL2 additionally requires USB passthrough via usbipd-win, which is why we suggest VirtualBox for the full hardware flow.

Arm GCC Toolchain:

QEMU with Arm support:

For stlink:

For serial output:

Quick Start

We use qemu and pqm4(https://github.com/mupq/pqm4) to test and benchmark our projects:

Compiler versions and warnings

The results in the paper were produced with arm-none-eabi-gcc 10.3.1, which we recommend for reproduction. The code builds with newer toolchains as well, but GCC 14 and later promote -Wincompatible-pointer-types from a warning to an error by default, so those versions require:

make CFLAGS="-Wno-error=incompatible-pointer-types"

The build also emits a number of warnings (-Wincompatible-pointer-types, -Wshift-count-overflow and others). These originate from the deliberate type punning used throughout the arithmetic layer, where the same buffers are addressed as byte, word and 64-bit arrays depending on the kernel, and from shift amounts that are unreachable for the parameter sets actually instantiated. The correctness is verified with QEMU and pam4. We have left the code as measured for the paper rather than restructuring it, so that the published cycle counts correspond exactly to the source in this artifact.

Building and Running

Navigate to any project directory and use these commands:

QEMU (Emulation):

cd hqc-1/                    # or any project directory
make PLATFORM=qemu            # Build
make run-qemu PLATFORM=qemu   # Build and run

Test multiplications

cd hqc-1/                    # or any project directory
make PLATFORM=qemu            # Build
make MODE=MUL run-qemu PLATFORM=qemu   # Build and run

Test All Projects

./run-all-tests.sh            # Run tests for all projects

Output Files

Each build generates platform-specific binaries:

Hardware Setup

Connecting the STM32L4R5 Nucleo-144 board

Follow instructions in pqm4

Use the script to clone pqm4 and copy files to the directory:

./pqm4.sh
cd pqm4

Config and serial output

To view output from the board, make file and connect via serial terminal, use HQC-1 as an example:

# make files
make -j4 PLATFORM=nucleo-l4r5zi IMPLEMENTATION_PATH=crypto_kem/hqc-1/m4f

# flash the board
st-flash write bin/crypto_kem_hqc-1_m4f_speed.bin 0x8000000
# connect to serial terminal:
pyserial-miniterm /dev/tty.usbmodem* 38400
# or for linux
pyserial-miniterm /dev/ttyACM* 38400

Note on benchmarks.py. pqm4's speed test benchmarks the KEM API only — keypair, encaps, decaps — and pqm4 offers no facility for timing individual components, so Tables 4 and 5 of the paper cannot be obtained through it. pqm4.sh therefore replaces mupq/crypto_kem/speed.c with a version that additionally times the polynomial multiplication and the encoder/decoder.

This replacement targets HQC only: it references symbols that exist in our implementations, so other schemes in the pqm4 tree will no longer build against it. Please use the commands above rather than benchmarks.py, and do not build other schemes in this working copy. To restore the original behaviour, run git -C pqm4/mupq checkout crypto_kem/speed.c.

The stack usage in Table 6 is obtained by flashing bin/crypto_kem_hqc-1_m4f_stack.bin instead. Repeat with IMPLEMENTATION_PATH=crypto_kem/hqc-3/m4f and hqc-5/m4f for the remaining columns.

Development

Common Infrastructure