Skip to content
This repository was archived by the owner on Sep 16, 2026. It is now read-only.

Aarch64 feature detection - #83

Closed
thomwiggers wants to merge 1 commit into
mainfrom
aarch64-feature-detection
Closed

thomwiggers wants to merge 1 commit into
mainfrom
aarch64-feature-detection

Conversation

@thomwiggers

Copy link
Copy Markdown
Member

Should fix #82

@icota

icota commented Mar 16, 2025

Copy link
Copy Markdown

I can confirm that

[patch.crates-io]
pqcrypto-traits = { git = "https://github.com/rustpq/pqcrypto", branch = "aarch64-feature-detection" }
pqcrypto-mldsa = { git = "https://github.com/rustpq/pqcrypto", branch = "aarch64-feature-detection" }
pqcrypto-mlkem = { git = "https://github.com/rustpq/pqcrypto", branch = "aarch64-feature-detection" }

fixes Fatal signal 4 (SIGILL), code 1 (ILL_ILLOPC) on Android Pixel 7 for me.

@icota

icota commented Mar 16, 2025

Copy link
Copy Markdown

On second glance it only fixes ml-dsa. If I try to get an ml-kem keypair I still encounter:

signal 4 (SIGILL), code 1 (ILL_ILLOPC), fault addr 0x000000744d312fb4
    x0  0000007451950550  x1  000000744cdd9828  x2  00000074519503d0  x3  0000000000000018
    x4  00000074519503d0  x5  000000000000001f  x6  0000000000000010  x7  7f7f7f7f7f7f7f7f
    x8  0000000000000003  x9  0000000000000014  x10 000000000000001f  x11 f41107a453e2076c
    x12 0000000000021003  x13 000000007fffffff  x14 0000000000000000  x15 0000027433a5a687
    x16 000000744d5e4480  x17 0000007830d67940  x18 0000007443da0000  x19 b4000076f9369c70
    x20 b400007599339900  x21 000000744d5af710  x22 0000000000005232  x23 00000000000051dc
    x24 00000074519606c0  x25 00000074519606c0  x26 0000007451960a28  x27 0000007451960a80
    x28 0000000000206000  x29 0000007451950160
    lr  000000744d312f6c  sp  0000007451950110  pc  000000744d312fb4  pst 0000000020001000

@icota

icota commented Mar 16, 2025

Copy link
Copy Markdown

I can fix the above by having ml-dsa check for sha3 instead of merely neon. But I'm not sure if that's a proper fix.
I'll make a PR to this branch regardless.

@icota icota 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.

#84

@thomwiggers
thomwiggers force-pushed the aarch64-feature-detection branch 2 times, most recently from 4c07016 to bb67ba9 Compare March 17, 2025 04:13
Enable AArch64 feature detection

Bump versions

Update changelog

Include ml-kem, bump versions

Falcon should not be bumped

Should be a semantic bump
@thomwiggers
thomwiggers force-pushed the aarch64-feature-detection branch from bb67ba9 to 097a7b4 Compare March 17, 2025 04:26
@thomwiggers

Copy link
Copy Markdown
Member Author

Would be great if you could test this again

@icota

icota commented Mar 17, 2025

Copy link
Copy Markdown

@thomwiggers it crashes on 097a7b4

@thomwiggers

Copy link
Copy Markdown
Member Author

Can you elaborate? There are no differences with #84 in how the code is called (though I'm suspicious that the cfg guards in #84 are broken which leads to the code not getting included).

@hfunke

hfunke commented Mar 17, 2025

Copy link
Copy Markdown

From my perspective your fix works: ML-DSA runs on a RasPi now. Thanks a lot for your support!

@1Birdo

1Birdo commented Sep 16, 2026

Copy link
Copy Markdown

Field data for this issue from an Android VPN client (BirdoVPN, pqcrypto-mlkem 0.1.1 + pqcrypto-internals 0.2.11, aarch64-linux-android via cargo-ndk), in case it helps prioritise:

What happened. With pqcrypto-mlkem's default features (neon on), Google Play reported SIGILL crashes on seven phone models — Redmi Note 8 (Snapdragon 665), Galaxy A70/A71 (SD675/730), Xiaomi 11T Pro (Snapdragon 888 — all eight cores), TCL 50 SE (Helio G88), Infinix NOTE 30 (Helio G99), vivo Y11 5G — across Android 11/14/16. Stack: nativeGenerateKeypair → PQCLEAN_MLKEM1024_AARCH64_crypto_kem_keypair → …_indcpa_keypair_derand → …_gen_matrix → keccakx2_squeezeblocks.

Disassembly of the shipped .so (llvm-objdump --triple=aarch64-linux-android --mattr=+all): 64 FEAT_SHA3 instructions — eor3 10, rax1 5, xar 24, bcax 25 — all inside f1600x2 (pqclean/common/keccak2x/feat.S), and no runtime feature check anywhere on the path (no getauxval import). The first SHA3 opcode executed is the first instruction of the Keccak permutation, which is why crash reporters attribute it to keccakx2_squeezeblocks (f1600x2/loop have ELF size 0).

Why it is unconditional, as far as I can tell from the sources:

  • pqcrypto-internals/build.rs compiles keccak2x/fips202x2.c + feat.S with -march=armv8.2-a+sha3 on every aarch64 target except msvc (main today: lines 67–74). That flag defines __ARM_FEATURE_SHA3, which feat.S and KeccakF1600_StatePermutex2 key on.
  • pqcrypto-mlkem/src/mlkem1024.rs (and 512/768) selects the AArch64 implementation under #[cfg(all(enable_aarch64_neon, feature = "neon"))] with a literal if true { … } (lines 150–158 on main) — the comment says is_aarch64_feature_detected!("neon") needed nightly, but the feature that actually matters is sha3, which is optional in ARMv8.2-A and absent on Cortex-A53/A55/A57/A72/A73/A75/A76/A77/A78/X1-class cores. The x86 path, by contrast, is gated with is_x86_feature_detected!("avx2") and never crashed for us.

Reproduction without hardware (QEMU user-mode, static harness of the vendored PQClean sources): the AArch64 build exits 132 (SIGILL) under qemu-aarch64 -cpu cortex-a53 / a55 / a57 / a72 / a76 / neoverse-n1, and runs under cortex-a710 / neoverse-v1 / max; the CLEAN build runs on all of them and produces bit-identical keys from the same derand coins.

What we did: pqcrypto-mlkem = { version = "0.1", default-features = false, features = ["std"] } (CLEAN only), plus a CI gate that disassembles the packaged .so and fails on any FEAT_SHA3/SHA512/SM3/SM4/DotProd/FP16/LSE/SVE mnemonic outside runtime-dispatched code. Note the fix relies on the linker dropping libkeccak2x.a as a dead member — pqcrypto-internals still assembles feat.S with +sha3 regardless of the neon feature.

Suggestions: (1) gate keccak2x's +sha3 build behind a cargo feature (or compile it twice and pick at runtime); (2) on stable Rust, std::arch::is_aarch64_feature_detected!("sha3") is available (stable since 1.60) — the AArch64 KEM/DSA paths could dispatch on it and fall back to clean, matching what the x86 path already does; (3) until then, neon as a default feature is unsafe for aarch64-linux-android and Raspberry-Pi-class targets, so a README warning would save the next project a production crash.

Happy to provide the harness sources / objdump summaries if useful.

@thomwiggers

Copy link
Copy Markdown
Member Author

See #97

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Runtime feature detection fails for ML-DSA on Aarch64

4 participants