Skip to content

Use AES hardware support on Apple arm64 and with GCC on aarch64 - #1

Closed
mtrossbach wants to merge 1 commit into
mainfrom
fix/aes-hw-detection
Closed

mtrossbach wants to merge 1 commit into
mainfrom
fix/aes-hw-detection

Conversation

@mtrossbach

@mtrossbach mtrossbach commented Sep 11, 2026

Copy link
Copy Markdown
Member

Hi Ulrich,

first of all, thank you for SQLite3 Multiple Ciphers! It's a great piece of work, and the modular cipher design made it easy to find my way around the code.

While measuring AES performance on Apple Silicon, I noticed two gaps in src/aes_hardware.c:

  • The existing ARMv8 AES code is compiled on Apple devices but never used.
  • GCC builds on aarch64 don't include it at all.

This small PR closes both. The encryption output doesn't change in any way; the only difference is that the much faster hardware path is now picked wherever it's available.

What changes (only src/aes_hardware.c, +23 lines)

  • Apple arm64 (macOS, iOS, iPadOS, tvOS, watchOS, visionOS): aesHardwareAvailableOnPlatform() had no Apple branch and fell through to return 0. As a result, aes128cbc, aes256cbc and sqlcipher used the table-based software AES. All 64-bit ARM processors Apple uses (A7 and later, M1 and later) implement the ARMv8 cryptographic extensions, so the new branch simply returns 1. OpenSSL and Botan make the same assumption, and the bundled libaegis already relies on it (src/aegis/common/cpu.c).
  • GCC on aarch64: the compiler detection only covered GCC on x86, so without -march=...+crypto no hardware path was compiled. For GCC ≥ 6, the NEON code path is now enabled with the function attribute target("+crypto"), just like the existing clang handling. The runtime check (getauxval(AT_HWCAP) & HWCAP_AES) was already in place.
  • Everything else is untouched: x86, MSVC, clang, Windows on ARM, and the CBC functions themselves.

A nice side effect: the existing CI jobs on macos-latest and ubuntu-24.04-arm (gcc) will now really exercise the hardware code paths. At the moment they quietly test the software fallback.

Performance (Apple M4 Max)

  • AES-256-CBC, 4 KiB blocks: encrypt 314 → 2145 MB/s, decrypt 386 → 16392 MB/s.
  • aes256cbc database, 100,000 rows × 1,000 bytes:
    • Write: 0.59 s → 0.30 s.
    • Read: 0.31 s → 0.06 s.
    • On Linux aarch64 with GCC 13, read time goes from 0.33 s → 0.08 s.
How I tested it
  • macOS (Apple M4 Max, Apple clang 21):
    • The CI test scripts (test1test4, sqlciphertest) produce identical output before and after the change.
    • The NIST SP 800-38A F.2.5/F.2.6 CBC-AES256 vector passes through the hardware path.
    • Databases written with the previous build open with the new one and vice versa, for aes128cbc, aes256cbc and sqlcipher.
  • iOS simulator (iPhone 17, iOS 26.5, arm64): aesHardwareAvailable() goes from 0 to 1, and the known-answer test passes.
  • Apple SDKs (Xcode 26.5):
    • On arm64 iOS, tvOS, watchOS (arm64_32 and arm64) and visionOS, the platform check now returns 1.
    • The x86_64 simulator and 32-bit armv7k watchOS are unchanged.
    • The amalgamation compiles for all of them without new warnings.
  • Linux aarch64 (Ubuntu 24.04 container, CI recipe autoreconf; ./configure; make):
    • GCC 13.3: previously no hardware path, now active. The known-answer test passes, CI output is identical, and databases are cross-compatible.
    • clang 18.1 (as a control): unchanged.
  • GCC version gate:
    • GCC 6.5, 7.5 and 8.5: hardware path active, known-answer test passes, and the amalgamation compiles without warnings.
    • GCC 5.5: stays on the software path and compiles cleanly.
  • Android (NDK 28.2):
    • arm64-v8a already used the hardware path and is unchanged. A static arm64 binary passes the known-answer test.
    • x86_64 and armeabi-v7a are unchanged.

ARM64 machines aren't always at hand, so I tried to test as broadly as I could. I'm happy to run anything else you'd like to see. If you prefer a different approach, I'll gladly adjust it. One example would be a sysctlbyname()-based check on Apple instead of the constant.

While digging into the AES code, I came across a few more small things around AES and random number generation. I'd like to propose them separately, each as its own small PR or issue, so they stay easy to review.

Thanks a lot for taking a look!

Best regards,
Markus

On 64-bit Apple ARM platforms the NEON AES code was compiled, but the
runtime check always reported that no hardware support is available, so
the table-based software implementation was used. With GCC on aarch64 no
hardware code path was compiled at all, unless the crypto extension was
enabled via compiler flags.

- Report AES hardware support on 64-bit Apple ARM platforms (macOS, iOS,
  iPadOS, tvOS, watchOS, visionOS)
- Enable the NEON AES code path for GCC >= 6 on aarch64 via a function
  target attribute, analogous to the existing clang handling
@mtrossbach mtrossbach closed this Sep 11, 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.

1 participant