Skip to content

SP RISC-V 64-bit: new implementation - #11135

Merged
dgarske merged 1 commit into
wolfSSL:masterfrom
SparkiDev:sp_riscv_64
Aug 14, 2026
Merged

SP RISC-V 64-bit: new implementation#11135
dgarske merged 1 commit into
wolfSSL:masterfrom
SparkiDev:sp_riscv_64

Conversation

@SparkiDev

Copy link
Copy Markdown
Contributor

Description

Implementation of all SP algorithms/parameters for RISC-V 64-bit CPU.

Testing

Tested all algorithms including SAKKE and SM2 for SP ASM for RISC-V 64-bit.

@SparkiDev SparkiDev self-assigned this Aug 11, 2026
@SparkiDev

Copy link
Copy Markdown
Contributor Author

Code generated with PR:
https://github.com/wolfSSL/scripts/pull/653

@SparkiDev

Copy link
Copy Markdown
Contributor Author

SM2 code:
wolfSSL/wolfsm#33

@SparkiDev SparkiDev assigned wolfSSL-Bot and unassigned SparkiDev Aug 11, 2026
@dgarske
dgarske self-requested a review August 11, 2026 23:45
@dgarske dgarske self-assigned this Aug 12, 2026

@dgarske dgarske left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review findings - wolfSSL PR 11135 and wolfsm PR 33 (RISC-V 64-bit SP)

Testing performed on 2026-08-13 against wolfssl-alt2 pr11135 (commit 124b5c0d7) and wolfsm pr33 (commit 4b1f214), cross-compiled with the Microchip PolarFire SoC Yocto toolchain (GCC 13.3.0, riscv64-mchp-linux, default rv64imafdc/lp64d) and executed under qemu-riscv64 8.2.2.

What passes

The implementation itself is in good shape. With --enable-all --enable-sp-asm --enable-riscv-asm:

  • sp_riscv64.c is correctly selected as the only SP backend (no sp_c64.o in the build).
  • testwolfcrypt passes completely - RSA, DH, ECC P-256/384/521, SAKKE, ML-KEM, and the full OpenSSL-compat suite.
  • -O1, -Os, -O2 and -Ofast all build and pass.
  • wolfsm PR 33's sp_sm2_riscv64.c compiles and is the only SM2 backend selected; SM2P256V1 key generation, ECDHE, ECDSA sign and verify all execute, and SM3/SM4-CBC/SM4-GCM benchmark clean.
  • The code is base RV64IM only (no Zb*, Zk*, or V), so it runs on cores without any ISA extensions. Verified by compiling clean at -march=rv64imac -mabi=lp64 (PolarFire SoC E51) as well as rv64gc/lp64d (U54), with GCC 8.3.0 and GCC 15.1.0 in addition to 13.3.0.

1. sp_riscv64.c fails to build at -O0, or with -fno-omit-frame-pointer at any level

Severity: high. This is the one finding that should block merge.

wolfcrypt/src/sp_riscv64.c: In function 'sp_2048_sqr_16':
wolfcrypt/src/sp_riscv64.c:5989:1: error: s0 cannot be used in 'asm' here

s0 is the frame pointer (fp) on RISC-V. Three assembly blocks list it in their clobber list, so any build in which GCC must keep a frame pointer is rejected.

Reproduced matrix (same compiler, same defines, only the flags differ):

Flags Result
-O0 FAIL
-O0 -fPIC FAIL
-O2 -fno-omit-frame-pointer FAIL
-O1 / -Os / -O2 / -Ofast ok

Affected sites, all in fully-unrolled 16-limb squaring routines:

Line of clobber list Function
wolfcrypt/src/sp_riscv64.c:5987 sp_2048_sqr_16 (definition at 4223)
wolfcrypt/src/sp_riscv64.c:11293 sp_2048_sqr_16 (definition at 9529)
wolfcrypt/src/sp_riscv64.c:72039 sp_1024_sqr_16 (definition at 70275)

This is not a simple register rename. The clobber list is t0-t6, a2-a7, s1-s11, plus s0 - 25 registers - and the two "+r" operands take 2 more, for 27. RISC-V has 32 GPRs of which zero, ra, sp, gp and tp are unusable, leaving 27 only when s0 is not reserved as a frame pointer. So the routine currently fits exactly, and only when the frame pointer is omitted. Freeing a register (spilling one value to the stack) in the generator looks like the real fix.

Worth noting for context: -fno-omit-frame-pointer is not exotic - Ubuntu and Fedora both build with frame pointers enabled by default now for profiling, and -O0 is a normal debug build.

For comparison, neither sp_arm64.c nor sp_x86_64.c ever clobbers its platform's frame-pointer register (x29 / rbp) - zero occurrences in each. wolfsm's sp_sm2_riscv64.c is also clean (zero s0 clobbers), so this is confined to sp_riscv64.c.

2. CI never compiles the new file

.github/configs/multi-arch.json has five riscv64 jobs and none of them passes --enable-sp-asm:

Job --enable-sp-asm --enable-riscv-asm CFLAGS
riscv64-o0 no yes -O0
riscv64-o1-no-fp-ecc no yes -O1 -UFP_ECC
riscv64-os no yes -Os
riscv64-o2 no yes -O2
riscv64-ofast no yes -Ofast

So 83,000 lines of new assembly land with no CI coverage at all. Adding --enable-sp-asm to at least one riscv64 entry would fix that - and note that adding it to riscv64-o0 would immediately surface finding 1, which is a good argument for doing exactly that once the s0 issue is resolved.

The explanatory comment at .github/workflows/multi-arch.yml:58-63 ("riscv64's --enable-riscv-asm (unlike the other arches' --enable-sp-asm) does not bring it in") is now stale and should be updated alongside.

3. WOLFSSL_SP_RISCV64_ASM is documented nowhere

grep -rn WOLFSSL_SP_RISCV64_ASM doc/ examples/ returns zero hits. Three specific places are now wrong or incomplete:

  • doc/ASM_AND_MATH_DEFINES.md:541-542 states the opposite of what is now true: "RISC-V has no specialised SP assembly, so use WOLFSSL_SP_RISCV64 for the inline tier."
  • doc/ASM_AND_MATH_DEFINES.md:100 - the per-CPU table row for RISC-V 64 reads add WOLFSSL_SP_RISCV64, WOLFSSL_RISCV_ASM (+ extension defines), with no mention of the new macro. Compare the Aarch64 row directly above it, which does list WOLFSSL_SP_ARM64_ASM.
  • doc/ASM_AND_MATH_DEFINES.md:222 - the word-size table lists WOLFSSL_SP_RISCV64 / WOLFSSL_SP_RISCV32 but not the _ASM variant.

The near-miss naming makes this more than a cosmetic gap: WOLFSSL_SP_RISCV64 and WOLFSSL_SP_RISCV64_ASM differ by a suffix and select completely different implementations, so a reader who follows the current documentation silently gets the slow inline tier.

4. user_settings_embedded.h cannot select the new backend

examples/configs/user_settings_embedded.h:848-851:

#elif WC_CFG_CPU_RISCV64
    #if WC_CFG_ASM_SP
        #define WOLFSSL_SP_RISCV64
    #endif

WC_CFG_ASM_SP is the switch that means "give me big-number assembly", so on RISC-V 64 it should now emit WOLFSSL_SP_RISCV64_ASM. As written, anyone configuring an embedded build through this template gets the inline tier and none of the new code, with no indication anything is missing.

The per-CPU source-file list in the same file's header comment (lines 58-68) also needs wolfcrypt/src/sp_riscv64.c adding, next to the existing sp_arm64.c / sp_x86_64.c entries.

5. No HAVE___UINT128_T fallback on the RISC-V 64 SP path

wolfssl/wolfcrypt/sp_int.h:254 sets SP_WORD_SIZE 64 unconditionally for WOLFSSL_SP_RISCV64_ASM and WOLFSSL_SP_RISCV64, but the sp_int_word / sp_int_sword typedefs at lines 326-330 are only emitted when WOLFSSL_UINT128_T_DEFINED is set, which in turn requires HAVE___UINT128_T. A user_settings.h build that does not define it therefore fails deep inside sp_int.c with:

wolfcrypt/src/sp_int.c:6666:5: error: unknown type name 'sp_int_word'

The x86_64 path two dozen lines above handles this - sp_int.h:217-218 degrades to SP_WORD_SIZE 32 when HAVE___UINT128_T is absent. The RISC-V path has no equivalent.

This pre-dates the PR for the WOLFSSL_SP_RISCV64 spelling, but the PR extends the same condition to WOLFSSL_SP_RISCV64_ASM, so it now affects the new code path too. Autotools masks it because configure probes for the type and passes -DHAVE___UINT128_T=1; only hand-written builds hit it. Either mirror the x86_64 fallback, or auto-define from __SIZEOF_INT128__, or at minimum document the requirement.

6. wolfsm install.sh does not copy the new MSVC assembly file

Severity: low. wolfsm PR 33 adds sp_sm2_x86_64_asm.asm (the masm/MSVC counterpart to the existing GNU-as .S), but install.sh copies only the .S:

31: cp sp_sm2_x86_64.c $WOLFSSL_DIR/wolfcrypt/src/
32: cp sp_sm2_x86_64_asm.S $WOLFSSL_DIR/wolfcrypt/src/

So the new file never reaches a wolfSSL tree and cannot be used by a Visual Studio build. The RISC-V addition on line 33 is correct - this is only about the x86_64 masm file that came along in the same commit.

Suggested minimum before merge

  1. Fix the s0 clobber in the three squaring routines (finding 1).
  2. Add --enable-sp-asm to at least one riscv64 CI job so the file is compiled at all (finding 2), ideally riscv64-o0 once finding 1 is fixed.
  3. Document WOLFSSL_SP_RISCV64_ASM and correct the three stale statements in doc/ASM_AND_MATH_DEFINES.md (finding 3).
  4. Emit the new macro from user_settings_embedded.h (finding 4).

Findings 5 and 6 are fine to handle separately.

@dgarske dgarske assigned SparkiDev and unassigned dgarske Aug 14, 2026
Implementation of all SP algorithms/parameters for RISC-V 64-bit CPU.
@SparkiDev

Copy link
Copy Markdown
Contributor Author

fixed review issues

@dgarske dgarske self-assigned this Aug 14, 2026
@dgarske
dgarske self-requested a review August 14, 2026 15:06
@dgarske

dgarske commented Aug 14, 2026

Copy link
Copy Markdown
Member

testwolfcrypt passes completely with the assembly backend: zero failures, return code 0, 1m48s for the full --enable-all suite on the U54.

Both builds below are --enable-all --enable-sp --enable-riscv-asm CFLAGS=-O2, differing only by --enable-sp-asm, so WOLFSSL_HAVE_SP_RSA/DH/ECC is set identically in both and this isolates sp_c64.c against sp_riscv64.c.

Operation sp_c64.c (C) sp_riscv64.c (asm) Speedup
RSA 2048 public 923.8 ops/s 1472.7 ops/s 1.59x
RSA 2048 private 18.34 ops/s 38.03 ops/s 2.07x
DH 2048 key gen 47.57 ops/s 80.46 ops/s 1.69x
DH 2048 agree 47.66 ops/s 80.60 ops/s 1.69x
ECDHE P-256 agree 670.6 ops/s 973.2 ops/s 1.45x
ECDSA P-256 sign 504.5 ops/s 767.1 ops/s 1.52x
ECDSA P-256 verify 639.0 ops/s 1007.7 ops/s 1.58x
ECDHE BrainpoolP256R1 agree 369.7 ops/s 367.3 ops/s 0.99x
ECDSA BrainpoolP256R1 sign 347.6 ops/s 345.6 ops/s 0.99x
ECDSA BrainpoolP256R1 verify 274.9 ops/s 271.0 ops/s 0.99x
AES-128-CBC encrypt 8.125 MiB/s 8.137 MiB/s 1.00x
SHA-256 9.294 MiB/s 9.276 MiB/s 1.00x

1.45x to 2.07x on everything the backend covers, with RSA private-key operations gaining most. The flat rows are the expected ones: Brainpool P-256 falls through to the generic path in both builds, and AES/SHA-256 are governed by --enable-riscv-asm, which this PR does not touch. No regressions.

@dgarske
dgarske merged commit 17821e2 into wolfSSL:master Aug 14, 2026
391 of 393 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants