Skip to content

Initial riscv64 vector support (uses standard vector instrinsics for rvv 1.0. Presently VLEN=256 only.) #1037

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/multi-functest/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ runs:
custom_shell: ${{ inputs.custom_shell }}
cflags: "${{ inputs.cflags }} -DMLK_FORCE_RISCV64"
cross_prefix: riscv64-unknown-linux-gnu-
exec_wrapper: qemu-riscv64
exec_wrapper: "qemu-riscv64 -cpu rv64,v=true,vlen=256" # This needs to be changed once we test other VLs
opt: ${{ inputs.opt }}
func: ${{ inputs.func }}
kat: ${{ inputs.kat }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ jobs:
nix-cache: ${{ matrix.target.mode == 'native' && 'false' || 'true' }}
gh_token: ${{ secrets.GITHUB_TOKEN }}
compile_mode: ${{ matrix.target.mode }}
# There is no native code yet on PPC64LE, R-V or AArch64_be, so no point running opt tests
opt: ${{ (matrix.target.arch != 'ppc64le' && matrix.target.arch != 'riscv64' && matrix.target.arch != 'aarch64_be') && 'all' || 'no_opt' }}
# There is no native code yet on PPC64LE or or AArch64_be, so no point running opt tests
opt: ${{ (matrix.target.arch != 'ppc64le' && matrix.target.arch != 'aarch64_be') && 'all' || 'no_opt' }}
- name: build + test (+debug+memsan+ubsan)
uses: ./.github/actions/multi-functest
if: ${{ matrix.target.mode == 'native' }}
Expand Down
34 changes: 34 additions & 0 deletions examples/monolithic_build/mlkem_native_monobuild.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@
#include "mlkem/native/x86_64/src/rej_uniform_avx2.c"
#include "mlkem/native/x86_64/src/rej_uniform_table.c"
#endif /* MLK_SYS_X86_64 */
#if defined(MLK_SYS_RISCV64)
#include "mlkem/native/riscv64/src/rv64v_poly.c"
#endif
#endif /* MLK_CONFIG_MONOBUILD_WITH_NATIVE_ARITH */

#if defined(MLK_CONFIG_MONOBUILD_WITH_NATIVE_FIPS202)
Expand Down Expand Up @@ -455,6 +458,37 @@
#undef MLK_NTT_BOUND
/* mlkem/native/meta.h */
#undef MLK_NATIVE_META_H
/* mlkem/native/riscv64/meta.h */
#undef MLK_ARITH_BACKEND_RISCV64
#undef MLK_NATIVE_RISCV64_META_H
#undef MLK_USE_NATIVE_INTT
#undef MLK_USE_NATIVE_NTT
#undef MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED
#undef MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE
#undef MLK_USE_NATIVE_POLY_REDUCE
#undef MLK_USE_NATIVE_POLY_TOMONT
#undef MLK_USE_NATIVE_REJ_UNIFORM
/* mlkem/native/riscv64/src/arith_native_riscv64.h */
#undef MLK_NATIVE_RISCV64_SRC_ARITH_NATIVE_RISCV64_H
#undef mlk_rv64v_poly_add
#undef mlk_rv64v_poly_basemul_mont_add_k2
#undef mlk_rv64v_poly_basemul_mont_add_k3
#undef mlk_rv64v_poly_basemul_mont_add_k4
#undef mlk_rv64v_poly_invntt_tomont
#undef mlk_rv64v_poly_ntt
#undef mlk_rv64v_poly_reduce
#undef mlk_rv64v_poly_sub
#undef mlk_rv64v_poly_tomont
#undef mlk_rv64v_rej_uniform
/* mlkem/native/riscv64/src/rv64v_settings.h */
#undef MLKEM_QI
#undef MLK_MONT_NR
#undef MLK_MONT_R1
#undef MLK_MONT_R2
#undef MLK_NATIVE_RISCV64_SRC_RV64V_SETTINGS_H
#undef MLK_RVV_E16M1_VL
#undef MLK_RVV_VLEN
#undef MLK_RVV_WIDENING_MUL
/* mlkem/native/x86_64/meta.h */
#undef MLK_ARITH_BACKEND_X86_64_DEFAULT
#undef MLK_NATIVE_X86_64_META_H
Expand Down
1 change: 1 addition & 0 deletions examples/monolithic_build_multilevel_native/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),)
else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),)
CFLAGS += -DMLK_FORCE_AARCH64
else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),)
CFLAGS += -march=rv64gcv_zvl256b
CFLAGS += -DMLK_FORCE_RISCV64
else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),)
CFLAGS += -DMLK_FORCE_PPC64LE
Expand Down
1 change: 1 addition & 0 deletions examples/multilevel_build_native/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),)
else ifneq ($(findstring aarch64, $(CROSS_PREFIX)),)
CFLAGS += -DMLK_FORCE_AARCH64
else ifneq ($(findstring riscv64, $(CROSS_PREFIX)),)
CFLAGS += -march=rv64gcv_zvl256b
CFLAGS += -DMLK_FORCE_RISCV64
else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),)
CFLAGS += -DMLK_FORCE_PPC64LE
Expand Down
4 changes: 4 additions & 0 deletions mlkem/native/meta.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@
#include "x86_64/meta.h"
#endif

#ifdef MLK_SYS_RISCV64
#include "riscv64/meta.h"
#endif

#endif /* !MLK_NATIVE_META_H */
88 changes: 88 additions & 0 deletions mlkem/native/riscv64/meta.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) The mlkem-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/

#ifndef MLK_NATIVE_RISCV64_META_H
#define MLK_NATIVE_RISCV64_META_H

/* Identifier for this backend so that source and assembly files
* in the build can be appropriately guarded. */
#define MLK_ARITH_BACKEND_RISCV64

/* Set of primitives that this backend replaces */
#define MLK_USE_NATIVE_NTT
#define MLK_USE_NATIVE_INTT
#define MLK_USE_NATIVE_POLY_TOMONT
#define MLK_USE_NATIVE_REJ_UNIFORM
#define MLK_USE_NATIVE_POLY_REDUCE
#define MLK_USE_NATIVE_POLY_MULCACHE_COMPUTE
#define MLK_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED

#include "../../common.h"

#if !defined(__ASSEMBLER__)

#include "src/arith_native_riscv64.h"

static MLK_INLINE void mlk_ntt_native(int16_t data[MLKEM_N])
{
mlk_rv64v_poly_ntt(data);
}

static MLK_INLINE void mlk_intt_native(int16_t data[MLKEM_N])
{
mlk_rv64v_poly_invntt_tomont(data);
}

static MLK_INLINE void mlk_poly_tomont_native(int16_t data[MLKEM_N])
{
mlk_rv64v_poly_tomont(data);
}

static MLK_INLINE int mlk_rej_uniform_native(int16_t *r, unsigned len,
const uint8_t *buf,
unsigned buflen)
{
return mlk_rv64v_rej_uniform(r, len, buf, buflen);
}

static MLK_INLINE void mlk_poly_reduce_native(int16_t data[MLKEM_N])
{
mlk_rv64v_poly_reduce(data);
}

static MLK_INLINE void mlk_poly_mulcache_compute_native(
int16_t x[MLKEM_N / 2], const int16_t y[MLKEM_N])
{
(void)x; /* not using the cache atm */
(void)y;
}

static MLK_INLINE void mlk_polyvec_basemul_acc_montgomery_cached_k2_native(
int16_t r[MLKEM_N], const int16_t a[2 * MLKEM_N],
const int16_t b[2 * MLKEM_N], const int16_t b_cache[2 * (MLKEM_N / 2)])
{
(void)b_cache;
mlk_rv64v_poly_basemul_mont_add_k2(r, a, b);
}

static MLK_INLINE void mlk_polyvec_basemul_acc_montgomery_cached_k3_native(
int16_t r[MLKEM_N], const int16_t a[3 * MLKEM_N],
const int16_t b[3 * MLKEM_N], const int16_t b_cache[3 * (MLKEM_N / 2)])
{
(void)b_cache;
mlk_rv64v_poly_basemul_mont_add_k3(r, a, b);
}

static MLK_INLINE void mlk_polyvec_basemul_acc_montgomery_cached_k4_native(
int16_t r[MLKEM_N], const int16_t a[4 * MLKEM_N],
const int16_t b[4 * MLKEM_N], const int16_t b_cache[4 * (MLKEM_N / 2)])
{
(void)b_cache;
mlk_rv64v_poly_basemul_mont_add_k4(r, a, b);
}

#endif /* !__ASSEMBLER__ */

#endif /* !MLK_NATIVE_RISCV64_META_H */
84 changes: 84 additions & 0 deletions mlkem/native/riscv64/riscv64-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
[//]: # (SPDX-License-Identifier: CC-BY-4.0)

# rv64v-notes.md

Notes on RISC-V Vector support.

**WARNING** This is highly experimental. Currently vlen=256 only.

### Some preprequisites for cross compiling

Here's a collection of prerequisites (may contain extras/duplicates:
```
sudo apt install \
asciidoctor autoconf automake autotools-dev bc bison build-essential ccache \
clang clang-format cmake curl device-tree-compiler flex g++ gawk gdb git \
gperf graphviz help2man libeigen3-dev libexpat1-dev libffi-dev libfl2 \
libfl-dev libglib2.0-dev libgmp-dev libgoogle-perftools-dev libmpc-dev \
libmpfr-dev libreadline-dev libtool ninja-build patchutils perl pkg-config \
python3 python3-dev python3-pip slirp tcl-dev texinfo tio xdot zlib1g \
zlib1g-dev libboost-all-dev libboost-system-dev libboost-python-dev \
libboost-filesystem-dev libboost-thread-dev libboost-program-options-dev \
libftdi-dev libusb-1.0-0-dev libftdi1-dev
```

### Set up local tool directories

I have the following lines at the end of In `~/.bashrc` so that toolchains
can be installed without sude:
```
export RVSRC="$HOME/rv/src"
export RISCV="$HOME/rv/riscv"
export PATH="$RISCV/bin:$PATH"
```

Just create the directories (as a regular user):
```
mkdir -p $RVSRC $RISCV
```

### Build regular cross-compiler toolchains

Builds `riscv64-unknown-linux-gnu-*` toolchains, both gcc and clang:
```
cd $RVSRC
git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
./configure --prefix=$RISCV --enable-llvm --enable-linux --with-arch=rv64gcv
time make
```
This installs the tools locally locally (no `make install`.)


### An experimental spike emulator with a RISC-V Keccak instruction:

The patch provides a single vector instruction for "full Keccak" used by
`mlkem/fips202/native/riscv64/keccak_inst.h` when
`MLK_SYS_RISCV64_KECCAK_INST` is set.
The corresponding ISA extension flag (that needs to be passed to spike)
is `_zvkk`.

```
cd $RVSRC
git clone https://github.com/mjosaarinen/riscv-isa-sim.git
cd riscv-isa-sim
git checkout dev-keccak
mkdir build
cd build
../configure --prefix=$RISCV --with-target=riscv64-unknown-linux-gnu
time make
make install
```

### You'll also need pk
```
cd $RVSRC
git clone https://github.com/riscv-software-src/riscv-pk.git
cd riscv-pk
mkdir build
cd build
../configure --prefix=$RISCV --host=riscv64-unknown-linux-gnu CC=clang-19
make
make install
```

45 changes: 45 additions & 0 deletions mlkem/native/riscv64/src/arith_native_riscv64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) The mlkem-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLK_NATIVE_RISCV64_SRC_ARITH_NATIVE_RISCV64_H
#define MLK_NATIVE_RISCV64_SRC_ARITH_NATIVE_RISCV64_H

#include <stdint.h>
#include "../../../common.h"

#define mlk_rv64v_poly_ntt MLK_NAMESPACE(ntt_riscv64)
void mlk_rv64v_poly_ntt(int16_t *);

#define mlk_rv64v_poly_invntt_tomont MLK_NAMESPACE(intt_riscv64)
void mlk_rv64v_poly_invntt_tomont(int16_t *r);

#define mlk_rv64v_poly_basemul_mont_add_k2 MLK_NAMESPACE(basemul_add_k2_riscv64)
void mlk_rv64v_poly_basemul_mont_add_k2(int16_t *r, const int16_t *a,
const int16_t *b);

#define mlk_rv64v_poly_basemul_mont_add_k3 MLK_NAMESPACE(basemul_add_k3_riscv64)
void mlk_rv64v_poly_basemul_mont_add_k3(int16_t *r, const int16_t *a,
const int16_t *b);

#define mlk_rv64v_poly_basemul_mont_add_k4 MLK_NAMESPACE(basemul_add_k4_riscv64)
void mlk_rv64v_poly_basemul_mont_add_k4(int16_t *r, const int16_t *a,
const int16_t *b);

#define mlk_rv64v_poly_tomont MLK_NAMESPACE(tomont_riscv64)
void mlk_rv64v_poly_tomont(int16_t *r);

#define mlk_rv64v_poly_reduce MLK_NAMESPACE(reduce_riscv64)
void mlk_rv64v_poly_reduce(int16_t *r);

#define mlk_rv64v_poly_add MLK_NAMESPACE(poly_add_riscv64)
void mlk_rv64v_poly_add(int16_t *r, const int16_t *a, const int16_t *b);

#define mlk_rv64v_poly_sub MLK_NAMESPACE(poly_sub_riscv64)
void mlk_rv64v_poly_sub(int16_t *r, const int16_t *a, const int16_t *b);

#define mlk_rv64v_rej_uniform MLK_NAMESPACE(rj_uniform_riscv64)
unsigned int mlk_rv64v_rej_uniform(int16_t *r, unsigned int len,
const uint8_t *buf, unsigned int buflen);

#endif /* !MLK_NATIVE_RISCV64_SRC_ARITH_NATIVE_RISCV64_H */
Loading
Loading