Skip to content

ML-DSA AArch64/32: assembly implementation - #11188

Open
SparkiDev wants to merge 1 commit into
wolfSSL:masterfrom
SparkiDev:mldsa_aarch64
Open

ML-DSA AArch64/32: assembly implementation#11188
SparkiDev wants to merge 1 commit into
wolfSSL:masterfrom
SparkiDev:mldsa_aarch64

Conversation

@SparkiDev

Copy link
Copy Markdown
Contributor

Description

Add optimized AArch64 NEON assembly implementation
Add optimized AArch32 NEON assembly implementation

Testing

Regression tested for C/x64/AArch64/AArch32 assembly code.

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

Copy link
Copy Markdown
Contributor Author

Code generated by PR:
https://github.com/wolfSSL/scripts/pull/658

@SparkiDev

Copy link
Copy Markdown
Contributor Author

Jenkins: retest this please

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11188

Scan targets checked: wolfcrypt-bugs, wolfcrypt-port-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src
Findings: 5

High (3)

AArch64 inline asm writes the return value to raw x0 instead of an operand in mldsa_make_hint_neon

File: wolfcrypt/src/port/arm/armv8-mldsa-asm_c.c:20543
Function: mldsa_make_hint_neon
Category: Copy-paste errors across platforms

The block copies the .S epilogue verbatim: it deposits the result in x0, which is neither an operand nor a clobber, while the function returns [s] — a "+r" operand the asm only advances by 1024 bytes. Correct only if the compiler happens to allocate s to x0; otherwise mldsa_make_hint() gets a pointer as the hint count and x0 is corrupted behind the compiler's back.

Recommendation: Write the result into the returned operand (mov %x[s], %x[idx] / movn %x[s], #0) as armv8-mlkem-asm_c.c does.

Referenced code: wolfcrypt/src/port/arm/armv8-mldsa-asm_c.c:20543-20548 (6 lines)


AArch64 inline asm writes the return value to raw x0 instead of an operand in mldsa_vec_check_low_neon

File: wolfcrypt/src/port/arm/armv8-mldsa-asm_c.c:26961
Function: mldsa_vec_check_low_neon
Category: Copy-paste errors across platforms

mov x0, x4 targets a register that is neither an operand nor a clobber, while the function returns [a], a "+r" operand the asm only advances past the input. Unless the compiler happens to place a in x0, the caller receives a non-zero pointer and the range check in mldsa_vec_check_low() always reports "low".

Recommendation: Emit the result into the returned operand, e.g. cset %w[a], eq, and drop the mov x0 copy.

Referenced code: wolfcrypt/src/port/arm/armv8-mldsa-asm_c.c:26961-26964 (4 lines)


AArch64 inline asm writes the return value to raw x0 instead of an operand in mldsa_rej_uniform_neon

File: wolfcrypt/src/port/arm/armv8-mldsa-asm_c.c:27645
Function: mldsa_rej_uniform_neon
Category: Copy-paste errors across platforms

mov x0, x14 writes a register that is neither an operand nor a clobber, while the function returns [p], a "+r" operand the asm advances as it stores samples. Unless the compiler places p in x0, the sample count returned to mldsa_rej_ntt_poly() is a pointer value.

Recommendation: Replace with mov %x[p], x14 to match the idiom used by mlkem_rej_uniform_neon.

Referenced code: wolfcrypt/src/port/arm/armv8-mldsa-asm_c.c:27645-27648 (4 lines)


Medium (1)

New MLDSA_SHAKE_DIRECT hash256 padding overwrites the 0x1f domain byte when the input exactly fills rate-1

File: wolfcrypt/src/wc_mldsa.c:917
Function: mldsa_hash256
Category: Logic errors

The short-input branch of the new MLDSA_SHAKE_DIRECT path assigns rather than ORs the final padding bit. When data1Len + data2Len == 135 (e.g. tr of 64 bytes plus a 71-byte message), state8[135] is set to 0x1f at line 915 and then clobbered to 0x80, dropping the SHAKE domain separator and producing a non-FIPS-204 mu. The sibling helpers mldsa_shake256 (line 695) and mldsa_squeeze256 (line 1231) use ^= here.

Related known finding #10014 (similar but distinct): Both are ML-DSA hash-input/FIPS-204 conformance defects in wc_mldsa.c, but this fault is SHAKE padding-byte clobbering in the MLDSA_SHAKE_DIRECT hash operation, while #10014 omits external message-prefix formatting in selectable no-context sign/verify paths. Their root causes and required patches differ.

Recommendation: Change the assignment to state8[WC_SHA3_256_COUNT * 8 - 1] ^= 0x80; to match the sibling SHAKE helpers.

Referenced code: wolfcrypt/src/wc_mldsa.c:917-921 (5 lines)


Low (1)

Batched-Keccak declarations moved outside the extern "C" block in sha3.h

File: wolfssl/wolfcrypt/sha3.h:465
Function: sha3_blocksx3_neon
Category: API contract violations

The relocated sha3_blocksx3_* / sha3_*_blocksx3_seed_* declarations sit after the closing } /* extern "C" */ at line 455, so a C++ translation unit including sha3.h declares them with C++ linkage while the assembly defines them with C linkage.

Recommendation: Move the #ifdef __cplusplus } #endif closer to the end of the file so the new block sits inside extern "C".

Referenced code: wolfssl/wolfcrypt/sha3.h:465-469 (5 lines)


This review was generated automatically by Fenrir. Blocking findings require changes before merge.

Add optimized AArch64 NEON assembly implementation
Add optimized AArch32 NEON assembly implementation
@SparkiDev

Copy link
Copy Markdown
Contributor Author

All Fenrir issues fixed

@SparkiDev

Copy link
Copy Markdown
Contributor Author

Jenkins: retest this please

FIPS

@SparkiDev SparkiDev assigned wolfSSL-Bot and unassigned SparkiDev Aug 20, 2026
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