Contents

Using the RISC-V Scalar Cryptography extensions

Compile and emulate RISC-V scalar cryptography extensions with GCC and Qemu.

Introduction

RISC-V is an instruction set provided under a open source license which is more and more used in the embedded device world but not only. Linux kernel and Android support RISC-V processors. The instruction set has a modular design divided between a base part and extensions which allow to integrate to a CPU only the instructions of interest. Each extension is named with a single or several letters. For example, saying that a CPU has instructions set RV64IMC means that has a 64-bit address space with instructions for integer multiplication and division ( the letter M ) and Compressed instructions ( the letter C ).

Among those extensions, the RISC-V Scalar Cryptography extensions accelerate some operations interesting for Symmetric Cryptography. They include instructions to accelerate AES, SM4, SHA-256, SHA-512, SM3 and some bit manipulation instructions available for 32 and 64 bit architectures. It is similar to the AES-NI instructions done by Intel for the x86 architecture. This post focus here on 64 bit architecture but is also applicable for 32-bit CPUs. Scalar Cryptography extensions are ratified since 2021 thus those extensions are stable and will not change in the future. They can be found under the following denominations:

  • Zkn: NIST Algorithm Suite, AES and SHA2
  • Zks: ShangMi Algorithm Suite, SM3 and SM4
  • Zkt: Data independent execution latency extension.

Code

For example, to code an AES encryption in assembly, the two instructions aes64ks1i and aes64ks2 can be used for the key schedule. If the secret key is in the registers t0 and t1 the first round of the key schedule can be implemented with the following:

1
2
3
4
5
aes64ks1i t2, t1, 0
aes64ks2  t0, t2, t0
aes64ks2  t1, t0, t1
sd  t0, 16(a1)
sd  t1, 24(a1)

Then for the encryption, the instruction aes64esm is used to implement the middle round operations without the add round key operation. As well, the instruction aes64es is used for the final round. A full AES implementation and Makefile is provided in my repository.

Compilation

The Cryptography extensions are supported by GCC since version 12. It should be available in your package manager if you have a recent distribution. LLVM seems to also support those instructions since version 14.0.

To allow GCC to use the Cryptography extensions, the architecture of the target CPU have to be given in a compilation flag. The flag march should include zkn to use the AES instructions. The code can be compiled with the following command:

1
$ riscv64-linux-gnu-gcc aes.c aes.S -o aes -march=rv64idzkn -static

And it produces a valid ELF executable file:

1
2
$file aes
aes: ELF 64-bit LSB executable, UCB RISC-V, RVC, double-float ABI, version 1 (SYSV), statically linked, BuildID[sha1]=7a5ee4f0f70a7b56ab07c30f46832da88151ed08, for GNU/Linux 4.15.0, with debug_info, not stripped

It is then possible to disassemble the binary with the objdump tool:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ riscv64-linux-gnu-objdump --disassemble=aes_expand_key aes

aes:     file format elf64-littleriscv


Disassembly of section .text:

0000000000010810 <aes_expand_key>:
   10810:	00053283          	ld	t0,0(a0)
   10814:	00853303          	ld	t1,8(a0)
   10818:	0055b023          	sd	t0,0(a1)
   1081c:	0065b423          	sd	t1,8(a1)
   10820:	31031393          	aes64ks1i	t2,t1,0x0
   10824:	7e5382b3          	aes64ks2	t0,t2,t0
   10828:	7e628333          	aes64ks2	t1,t0,t1
   1082c:	0055b823          	sd	t0,16(a1)
   10830:	0065bc23          	sd	t1,24(a1)

Emulation

The Scalar Cryptography extensions are new and there are not a lot of hardware designs available. Some proof-of-concept designs may be found on the RISC-V pages. However, they are supported by Qemu since version 7.1.0 and it allows to emulate the execution of those instructions. Qemu is able to emulate several RISC-V CPUs:

1
2
3
4
5
6
7
$ qemu-riscv64 -cpu  help
any
rv64
shakti-c
sifive-e51
sifive-u54
x-rv128

Here we are interested by the 64-bit architecture but in addition we have to pass the extension option zkn:

1
2
$ qemu-riscv64 -cpu rv64,zkn=true aes 2b7e151628aed2a6abf7158809cf4f3c 6bc1bee22e409f96e93d7e117393172a
3ad77bb40d7a3660a89ecaf32466ef97

It gives an emulated execution of our AES encryption implementation.

I found difficult to find how to play with the RISC-V extensions and those instructions even though they are already into standard tool like GCC or Qemu. I hope it will helps people who want to experiment that.