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

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
Draft
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 @@ -161,7 +161,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
18 changes: 14 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,23 +134,33 @@ jobs:
runs-on: ${{ matrix.target.runner }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: build + test
- name: build + test (no-opt)
uses: ./.github/actions/multi-functest
with:
nix-shell: ${{ matrix.target.nix_shell }}
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 != 'riscv32' && matrix.target.arch != 'aarch64_be') && 'all' || 'no_opt' }}
- name: build + test (+debug+memsan+ubsan)
opt: 'no_opt'
- name: build + test (+debug+memsan+ubsan, native)
uses: ./.github/actions/multi-functest
if: ${{ matrix.target.mode == 'native' }}
with:
gh_token: ${{ secrets.GITHUB_TOKEN }}
compile_mode: native
cflags: "-DMLKEM_DEBUG -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all"
check_namespace: 'false'
- name: build + test (+debug, cross, opt)
uses: ./.github/actions/multi-functest
# There is no native code yet on PPC64LE, riscv32 or AArch64_be, so no point running opt tests
if: ${{ matrix.target.mode != 'native' && (matrix.target.arch != 'ppc64le' && matrix.target.arch != 'riscv32' && matrix.target.arch != 'aarch64_be') }}
with:
nix-shell: ${{ matrix.target.nix_shell }}
nix-cache: ${{ matrix.target.mode == 'native' && 'false' || 'true' }}
gh_token: ${{ secrets.GITHUB_TOKEN }}
compile_mode: ${{ matrix.target.mode }}
cflags: "-DMLKEM_DEBUG"
opt: 'opt'
backend_tests:
name: AArch64 FIPS202 backends (${{ matrix.backend }})
strategy:
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 @@ -72,6 +72,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 riscv32, $(CROSS_PREFIX)),)
CFLAGS += -DMLK_FORCE_RISCV32
Expand Down
35 changes: 35 additions & 0 deletions examples/monolithic_build_native/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,41 @@ LIB1024=libmlkem1024.a

MLK_OBJS=$(BUILD_DIR)/mlkem_native.c.o $(BUILD_DIR)/mlkem_native.S.o

# Automatically detect system architecture and set preprocessor etc accordingly
HOST_PLATFORM := $(shell uname -s)-$(shell uname -m)

# linux x86_64
ifeq ($(HOST_PLATFORM),Linux-x86_64)
CFLAGS += -z noexecstack
endif

# Native compilation
ifeq ($(CROSS_PREFIX),)
ifeq ($(HOST_PLATFORM),Linux-x86_64)
CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes
CFLAGS += -DMLK_FORCE_X86_64
else ifeq ($(HOST_PLATFORM),Linux-aarch64)
CFLAGS += -DMLK_FORCE_AARCH64
else ifeq ($(HOST_PLATFORM),Darwin-arm64)
CFLAGS += -DMLK_FORCE_AARCH64
endif
# Cross compilation
else ifneq ($(findstring x86_64, $(CROSS_PREFIX)),)
CFLAGS += -mavx2 -mbmi2 -mpopcnt -maes
CFLAGS += -DMLK_FORCE_X86_64
else ifneq ($(findstring aarch64_be, $(CROSS_PREFIX)),)
CFLAGS += -DMLK_FORCE_AARCH64_EB
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 riscv32, $(CROSS_PREFIX)),)
CFLAGS += -DMLK_FORCE_RISCV32
else ifneq ($(findstring powerpc64le, $(CROSS_PREFIX)),)
CFLAGS += -DMLK_FORCE_PPC64LE
endif

CFLAGS := \
-Wall \
-Wextra \
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 riscv32, $(CROSS_PREFIX)),)
CFLAGS += -DMLK_FORCE_RISCV32
Expand Down
44 changes: 44 additions & 0 deletions mlkem/mlkem_native.S
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@
#include "mlkem/src/native/x86_64/src/reduce.S"
#include "mlkem/src/native/x86_64/src/tomont.S"
#endif /* MLK_SYS_X86_64 */
#if defined(MLK_SYS_RISCV64)
#endif
#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_ARITH */

#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202)
Expand Down Expand Up @@ -271,6 +273,7 @@
#undef MLK_SYS_PPC64LE
#undef MLK_SYS_RISCV32
#undef MLK_SYS_RISCV64
#undef MLK_SYS_RISCV64_V256
#undef MLK_SYS_WINDOWS
#undef MLK_SYS_X86_64
#undef MLK_SYS_X86_64_AVX2
Expand Down Expand Up @@ -555,5 +558,46 @@
#undef MLK_NATIVE_X86_64_SRC_CONSTS_H
#undef mlk_qdata
#endif /* MLK_SYS_X86_64 */
#if defined(MLK_SYS_RISCV64)
/*
* Undefine macros from native code (Arith, RISC-V 64)
*/
/* mlkem/src/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/src/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/src/native/riscv64/src/rv64v_settings.h */
#undef MLK_NATIVE_RISCV64_SRC_RV64V_SETTINGS_H
#undef MLK_RVV_E16M1_VL
#undef MLK_RVV_MONT_NR
#undef MLK_RVV_MONT_R1
#undef MLK_RVV_MONT_R2
#undef MLK_RVV_QI
#undef MLK_RVV_VLEN
#undef mlk_assert_abs_bound_int16m1
#undef mlk_assert_abs_bound_int16m2
#undef mlk_assert_bound_int16m1
#undef mlk_assert_bound_int16m2
#undef mlk_debug_check_bounds_int16m1
#undef mlk_debug_check_bounds_int16m2
#endif /* MLK_SYS_RISCV64 */
#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_ARITH */
#endif /* !MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */
46 changes: 46 additions & 0 deletions mlkem/mlkem_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@
#include "src/native/x86_64/src/rej_uniform_avx2.c"
#include "src/native/x86_64/src/rej_uniform_table.c"
#endif /* MLK_SYS_X86_64 */
#if defined(MLK_SYS_RISCV64)
#include "src/native/riscv64/src/rv64v_debug.c"
#include "src/native/riscv64/src/rv64v_poly.c"
#endif
#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_ARITH */

#if defined(MLK_CONFIG_USE_NATIVE_BACKEND_FIPS202)
Expand Down Expand Up @@ -260,6 +264,7 @@
#undef MLK_SYS_PPC64LE
#undef MLK_SYS_RISCV32
#undef MLK_SYS_RISCV64
#undef MLK_SYS_RISCV64_V256
#undef MLK_SYS_WINDOWS
#undef MLK_SYS_X86_64
#undef MLK_SYS_X86_64_AVX2
Expand Down Expand Up @@ -544,5 +549,46 @@
#undef MLK_NATIVE_X86_64_SRC_CONSTS_H
#undef mlk_qdata
#endif /* MLK_SYS_X86_64 */
#if defined(MLK_SYS_RISCV64)
/*
* Undefine macros from native code (Arith, RISC-V 64)
*/
/* mlkem/src/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/src/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/src/native/riscv64/src/rv64v_settings.h */
#undef MLK_NATIVE_RISCV64_SRC_RV64V_SETTINGS_H
#undef MLK_RVV_E16M1_VL
#undef MLK_RVV_MONT_NR
#undef MLK_RVV_MONT_R1
#undef MLK_RVV_MONT_R2
#undef MLK_RVV_QI
#undef MLK_RVV_VLEN
#undef mlk_assert_abs_bound_int16m1
#undef mlk_assert_abs_bound_int16m2
#undef mlk_assert_bound_int16m1
#undef mlk_assert_bound_int16m2
#undef mlk_debug_check_bounds_int16m1
#undef mlk_debug_check_bounds_int16m2
#endif /* MLK_SYS_RISCV64 */
#endif /* MLK_CONFIG_USE_NATIVE_BACKEND_ARITH */
#endif /* !MLK_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */
4 changes: 4 additions & 0 deletions mlkem/src/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

#if defined(MLK_SYS_RISCV64_V256)
#include "riscv64/meta.h"
#endif

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

# RISC-V Vector Extension Backend

Notes on RISC-V Vector support.

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

## Implementation Status

This implementation is inferior to the AArch64 and AVX2 backends in the following ways:

- **Verification**: No formal verification has been performed on this backend
- **Testing**: Uses the same functional tests as AVX2 and AArch64 backends, but lacks extensive real-hardware testing
- **Audit**: This is new code that has not yet received thorough review or widespread use in production environments

## Requirements

- RISC-V 64-bit architecture
- Vector extension (RVV) version 1.0
- Minimum vector length (VLEN) of 256 bits
- Standard "gc" extensions (integer and compressed instructions)

88 changes: 88 additions & 0 deletions mlkem/src/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 */
Loading
Loading