# Assembly Ownership Ledger

Last audited: 2026-07-02

rscrypto should own its assembly. Namespacing a third-party symbol is useful, but
it is not ownership. This ledger tracks every known assembly lineage so we can
replace vendored kernels deliberately instead of carrying inherited code by
accident.

## Ownership Criteria

An assembly file is rscrypto-owned when all of these are true:

- The algorithm, schedule, ABI, register allocation, and tail behavior were
  written for rscrypto or regenerated from rscrypto-owned source.
- The file has an SPDX header and provenance comment.
- The Rust wrapper documents the ABI, CPU-feature gate, aliasing rules, and
  secret/public timing boundary.
- Tests compare the assembly backend against the portable implementation or a
  published test-vector oracle.
- Any generated tables or generated assembly have a checked-in generator or a
  reproducible derivation note.

Code adapted from another project stays in the "external" bucket until it is
rewritten or regenerated from rscrypto-owned source. License compatibility is
necessary, not sufficient.

## Performance Target

The default goal is to write or generate rscrypto-owned assembly that is faster
than the vendored kernel it replaces. Ownership without speed is not enough for
hot crypto paths.

Deletion is acceptable only when an owned Rust intrinsic path already wins or is
effectively flat on the user-facing benchmark rows. If an owned assembly or
intrinsic candidate loses, the next step is profiling and tuning, not declaring
the slower path complete.

## Current Inventory

- 63 `.s` / `.S` files under `src/`.
- 63 Rust files use `asm!`, `core::arch::asm!`, or `global_asm!`.
- 48 tracked assembly files are explicitly external-derived today.
- 15 assembly files are explicitly marked `rscrypto-owned`.
- 0 tracked assembly files are first-party candidates awaiting headers.

## External-Derived Assembly To Replace

### s2n-bignum

These 36 files are adapted from s2n-bignum. They are namespaced for rscrypto,
but they are not rscrypto-owned yet.

2026-06-26 closed x86_64 P-384 signing slice: the worst P-384 signing loss is
closed on Linux x86_64. The arbitrary scalar-mul file, two dead point-helper
files, and x86_64 P-384 order-reduction file were deleted, and targeted run
[#28245803704](https://github.com/loadingalias/rscrypto/actions/runs/28245803704)
kept all 16 measured x86_64 P-384 signing rows ahead of AWS-LC: W/T/L 16/0/0,
geomean 1.34x, median 1.35x, worst row 1.21x. Do not restore these vendored
helpers. Remaining P-384 field, inversion, scalar-inversion, and aarch64 point
helpers listed below are separate ownership targets.

2026-06-26 status: `rscrypto_p384_montjscalarmul_alt_x86_64_unknown_linux.S`
was deleted and Linux x86_64 P-384 signing now uses the owned fixed-base comb
path. The first targeted quick bench improved the affected x86_64 P-384
signing geomean from 0.53x to 0.70x against the fastest external
implementation; the later fixed-base specialization moved those rows to a
1.38x geomean and 16/0/0 against AWS-LC. Do not restore vendored
arbitrary-point scalar multiplication.

2026-06-26 cleanup: the dead x86_64 P-384 point double/mixed-add assembly files
were also deleted after the x86_64 P-384 signing path stopped including those
wrappers. The aarch64 point helpers remain live and are intentionally still
listed below.

2026-06-26 tuning: deterministic P-384 signing now uses an r-only basepoint
path on supported platforms, avoiding affine `y` computation when signing only
needs `x mod n`. This is a safe owned-code shortcut, not the final x86_64 win;
the follow-up fixed-base comb specialization is what made x86_64 beat AWS-LC on
Zen4, Zen5, Ice Lake, and Sapphire Rapids.

2026-06-26 x86_64 fixed-base tuning: Linux x86_64 P-384 signing now uses a
P-384-specific owned comb loop that removes generic field-dispatch overhead and
the generic mixed-add exceptional double. The incomplete mixed-add is confined
to the fixed-base signing comb and is justified by the comb bit layout: nonzero
selected row coefficients and doubled accumulator coefficients occupy disjoint
bit positions and cannot be equal or opposite modulo the P-384 order. Run
[#28216163852](https://github.com/loadingalias/rscrypto/actions/runs/28216163852)
confirmed that this is enough to beat AWS-LC on the targeted x86_64 signing
rows. Future s2n-bignum work should treat the remaining live helpers as
separate tasks and preserve the signing margin.

2026-06-26 bench result: targeted x86_64 P-384 signing on run
[#28216163852](https://github.com/loadingalias/rscrypto/actions/runs/28216163852)
now beats AWS-LC on all 16 measured sign rows: W/T/L 16/0/0, geomean 1.38x,
median 1.40x. After that win, the x86_64 P-384 wide-order reduction assembly
`rscrypto_bignum_mod_n384_x86_64_unknown_linux.S` was deleted and x86_64 falls
through to the owned constant-time Montgomery reducer for 96-byte P-384 nonce
reduction. P-256 and aarch64 reduction assembly remain unchanged.

2026-06-26 reduction-cleanup bench result: targeted x86_64 P-384 signing on
run [#28245803704](https://github.com/loadingalias/rscrypto/actions/runs/28245803704)
still beats AWS-LC on all 16 measured sign rows after deleting
`rscrypto_bignum_mod_n384_x86_64_unknown_linux.S`: W/T/L 16/0/0, geomean
1.34x, median 1.35x, worst row 1.21x. The owned reducer roughly doubles the
small-message nonce-reduction internal time, but the signing margin remains
large enough to keep the deletion.

- `src/auth/asm/rscrypto_bignum_mod_n256_aarch64_apple_darwin.s`
- `src/auth/asm/rscrypto_bignum_mod_n256_aarch64_unknown_linux.s`
- `src/auth/asm/rscrypto_bignum_mod_n256_x86_64_unknown_linux.S`
- `src/auth/asm/rscrypto_bignum_mod_n384_aarch64_apple_darwin.s`
- `src/auth/asm/rscrypto_bignum_mod_n384_aarch64_unknown_linux.s`
- `src/auth/asm/rscrypto_bignum_modinv_aarch64_apple_darwin.s`
- `src/auth/asm/rscrypto_bignum_modinv_aarch64_unknown_linux.s`
- `src/auth/asm/rscrypto_bignum_modinv_x86_64_unknown_linux.S`
- `src/auth/asm/rscrypto_bignum_montinv_p384_aarch64_apple_darwin.s`
- `src/auth/asm/rscrypto_bignum_montinv_p384_aarch64_unknown_linux.s`
- `src/auth/asm/rscrypto_bignum_montinv_p384_x86_64_unknown_linux.S`
- `src/auth/asm/rscrypto_bignum_montmul_p384_aarch64_apple_darwin.s`
- `src/auth/asm/rscrypto_bignum_montmul_p384_aarch64_unknown_linux.s`
- `src/auth/asm/rscrypto_bignum_montmul_p384_alt_x86_64_unknown_linux.S`
- `src/auth/asm/rscrypto_bignum_montmul_p384_x86_64_unknown_linux.S`
- `src/auth/asm/rscrypto_bignum_montsqr_p384_aarch64_apple_darwin.s`
- `src/auth/asm/rscrypto_bignum_montsqr_p384_aarch64_unknown_linux.s`
- `src/auth/asm/rscrypto_bignum_montsqr_p384_alt_x86_64_unknown_linux.S`
- `src/auth/asm/rscrypto_bignum_montsqr_p384_x86_64_unknown_linux.S`
- `src/auth/asm/rscrypto_p256_scalarmulbase_alt_aarch64_apple_darwin.s`
- `src/auth/asm/rscrypto_p256_scalarmulbase_alt_aarch64_unknown_linux.s`
- `src/auth/asm/rscrypto_p256_scalarmulbase_alt_x86_64_unknown_linux.S`
- `src/auth/asm/rscrypto_p256_scalarmulbase_x86_64_unknown_linux.S`
- `src/auth/asm/rscrypto_p384_montjdouble_alt_aarch64_apple_darwin.s`
- `src/auth/asm/rscrypto_p384_montjdouble_alt_aarch64_unknown_linux.s`
- `src/auth/asm/rscrypto_p384_montjmixadd_alt_aarch64_apple_darwin.s`
- `src/auth/asm/rscrypto_p384_montjmixadd_alt_aarch64_unknown_linux.s`
- `src/auth/ed25519/asm/rscrypto_ed25519_aarch64_apple_darwin.s`
- `src/auth/ed25519/asm/rscrypto_ed25519_aarch64_unknown_linux.s`
- `src/auth/ed25519/asm/rscrypto_ed25519_scalarmulbase_aarch64_apple_darwin.s`
- `src/auth/ed25519/asm/rscrypto_ed25519_scalarmulbase_aarch64_unknown_linux.s`
- `src/auth/ed25519/asm/rscrypto_ed25519_scalarmulbase_alt_x86_64_unknown_linux.s`
- `src/auth/ed25519/asm/rscrypto_ed25519_scalarmulbase_x86_64_unknown_linux.s`
- `src/auth/x25519/asm/rscrypto_x25519_aarch64_apple_darwin.s`
- `src/auth/x25519/asm/rscrypto_x25519_aarch64_unknown_linux.s`
- `src/auth/x25519/asm/rscrypto_x25519_x86_64_linux.s`

Replacement target: rewrite fixed-base, field, scalar, and bignum kernels from
rscrypto's scalar field code and ABI needs. Do not bulk-port another bignum
project. If we keep any s2n-derived file temporarily, keep the SPDX and upstream
source path in the header.

### AWS-LC / BoringSSL / OpenSSL / Cloudflare

This section currently tracks 6 generated AWS-LC, BoringSSL, OpenSSL, or
Cloudflare-derived files that remain live:

- `src/aead/chacha20poly1305/asm/rscrypto_chacha20_poly1305_aarch64_apple_darwin.s`
- `src/aead/chacha20poly1305/asm/rscrypto_chacha20_poly1305_aarch64_linux.s`
- `src/aead/chacha20poly1305/asm/rscrypto_chacha20_poly1305_x86_64_linux.s`
- `src/auth/asm/rscrypto_rsa_bignum_mont_aarch64_elf.s`
- `src/auth/asm/rscrypto_rsa_bignum_mont_apple.s`
- `src/auth/asm/rscrypto_rsa_x86_64_elf.S`

SHA-2 Darwin AArch64 status: complete. The imported SHA-256 and SHA-512
assembly paths were deleted after the owned Rust intrinsic kernels measured
faster or flat on Apple Silicon.

ChaCha20-Poly1305 AArch64 status: active, but no current owned replacement is
ready for paid Graviton benches. Keep the vendored integrated files. Earlier
owned composition, direct-NEON/chunk, Rust/NEON fused, and hand-written fused
diagnostic attempts all lost to the imported integrated assembly on Apple M1
Pro large rows. The latest hand-written fused8 ASM candidate was correct, and a
live-accumulator revision improved it slightly, but it still lost to production
and to the composed owned par4 diagnostic path: 1 KiB 882.66 ns production vs
961.57 ns fused8, 4 KiB 2.8408 us vs 3.2667 us, 64 KiB 43.329 us vs 49.540 us,
and 1 MiB 694.18 us vs 796.08 us. A deeper register-fed four-block Poly1305
variant was also correct after fixes, but regressed much harder. Both fused ASM
diagnostic shapes were deleted. Do not run paid G3/G4 benches for this
ChaCha20-Poly1305 owned fused approach. The next viable attempt must be a new
generated or hand-scheduled production kernel, not incremental glue around the
current owned ChaCha XOR and par4 Poly1305 helpers.

Carry-through note: the owned Poly1305 par4 accumulator is an AEAD
authentication primitive and can be reused by XChaCha20-Poly1305 after HChaCha
derives the subkey and 96-bit ChaCha nonce. The current end-to-end diagnostic
wrapper is ChaCha20-Poly1305 only. This work does not speed raw ChaCha20 or
HChaCha by itself; those paths benefit only from the separate owned eight-block
ChaCha XOR kernel.

RSA Montgomery status: measured, keep for now. The imported fixed-width
Montgomery assembly is still materially faster than the owned portable CIOS path
at 2048, 3072, 4096, and 8192-bit public-operation widths on Apple Silicon and
Sapphire Rapids. The production threshold was widened so non-standard 65..127
limb public moduli use the faster owned portable CIOS path instead of product
Montgomery; shared/private Montgomery helpers keep the old threshold pending a
separate private-operation pass.

Published snapshot: commit `222e62f216691d706343b51fe5dca6ca69120890` was
pushed to `main`. Quick Bench run
[`28157440400`](https://github.com/loadingalias/rscrypto/actions/runs/28157440400)
was triggered with `targets=all`, `platforms=all`, and `quick=true`; it
completed successfully, but artifacts have not been extracted into
`benchmark_results/` yet.

Remaining replacement target: write or generate direct rscrypto kernels for RSA
Montgomery and ChaCha20-Poly1305 that beat the imported assembly on the measured
hot rows. If a candidate loses, keep the vendored path temporarily and tune the
owned implementation until it is faster or a measured intrinsic path makes the
assembly unnecessary.

Active notebook: `docs/tasks/aws-lc-boringssl-openssl-cloudflare-notebook.md`.

### Upstream BLAKE3 x86_64

These 6 files are derived from upstream BLAKE3 x86_64 assembly with symbols
renamed and preprocessor conditionals removed.

- `src/hashes/crypto/blake3/x86_64/asm/rscrypto_blake3_avx2_x86-64_apple_darwin.s`
- `src/hashes/crypto/blake3/x86_64/asm/rscrypto_blake3_avx2_x86-64_unix_linux.s`
- `src/hashes/crypto/blake3/x86_64/asm/rscrypto_blake3_avx2_x86-64_windows_msvc.s`
- `src/hashes/crypto/blake3/x86_64/asm/rscrypto_blake3_avx512_x86-64_apple_darwin.s`
- `src/hashes/crypto/blake3/x86_64/asm/rscrypto_blake3_avx512_x86-64_unix_linux.s`
- `src/hashes/crypto/blake3/x86_64/asm/rscrypto_blake3_avx512_x86-64_windows_msvc.s`

Replacement target: either write rscrypto-owned x86_64 assembly, or delete
these files and rely on the Rust intrinsic backends. Keeping both upstream ASM
and intrinsic fallbacks is a maintenance tax unless benchmarks prove the ASM
path still earns its place.

Each file now carries the upstream BLAKE3 1.8.5 source path and license
expression in its header. That freezes provenance but does not make these files
rscrypto-owned.

Phase 1 status: complete. We replaced the vendored/upstream-derived BLAKE3 ASM
paths where an rscrypto-owned Rust intrinsic path was faster or neutral, removed
dead x86 exports, and kept the remaining upstream-derived x86 AVX2/AVX-512 ASM
only where benchmarks showed it still wins. That means BLAKE3 is closed for the
first ownership pass, not fully rscrypto-owned.

Remaining BLAKE3 x86 ASM is intentional for now: AVX2 4-lane tails, AVX-512
full `hash_many`, AVX-512 `compress_in_place`, and AVX-512 `xof_many` are still
faster than the owned candidates measured in phase 1. Track any future rewrite
in `docs/tasks/blake3-notebook.md`.

### mlkem-native / NeonNTT / SLOTHY

Closed 2026-06-26: the two external-derived AArch64 ML-KEM forward NTT assembly
files were deleted. Production AArch64 forward NTT now uses the rscrypto-owned
Rust NEON kernel, with scalar-oracle tests covering canonical output, 1024
seeded polynomials, and fixed FIPS keygen-noise inputs. Keep future ML-KEM
forward NTT work in `docs/tasks/mlkem-ntt-notebook.md`; the remaining ML-KEM
assembly files are already tracked in the owned bucket below.

During verification, the no-longer-needed AArch64 ML-KEM inverse-NTT assembly
pair was also deleted and production inverse NTT now uses the same owned Rust
NEON path on macOS and Linux. Those files were rscrypto-owned, not vendored, so
this does not change the external-derived count.

## Explicitly rscrypto-owned Assembly

These 15 files are currently marked `rscrypto-owned`.

- `src/aead/chacha20/asm/rscrypto_chacha20_xor_aarch64_apple_darwin.s`
- `src/aead/chacha20/asm/rscrypto_chacha20_xor_aarch64_linux.s`
- `src/aead/poly1305/asm/rscrypto_poly1305_par4_aarch64_apple_darwin.s`
- `src/aead/poly1305/asm/rscrypto_poly1305_par4_aarch64_linux.s`
- `src/aead/aes/aarch64/asm/rscrypto_aes_gcm_aarch64_apple_darwin.s`
- `src/aead/aes/x86_64/asm/rscrypto_aes_gcm_x86_64_linux.s`
- `src/auth/asm/rscrypto_rsa_aarch64_apple_darwin.s`
- `src/auth/asm/rscrypto_rsa_aarch64_linux_elf.s`
- `src/auth/mlkem/asm/rscrypto_mlkem_basemul_aarch64_apple_darwin.s`
- `src/auth/mlkem/asm/rscrypto_mlkem_basemul_aarch64_linux.s`
- `src/auth/mlkem/asm/rscrypto_mlkem_rej_uniform_aarch64_apple_darwin.s`
- `src/auth/mlkem/asm/rscrypto_mlkem_rej_uniform_aarch64_linux.s`
- `src/hashes/crypto/blake3/aarch64/asm/rscrypto_blake3_hash1_chunk_aarch64_apple_darwin.s`
- `src/hashes/crypto/blake3/aarch64/asm/rscrypto_blake3_hash1_chunk_aarch64_unix_linux.s`
- `src/hashes/crypto/keccak/aarch64_sve2_sha3.S`

Keep these on the owned path by preserving ABI comments, constant-time boundary
notes, backend equivalence tests, and diagnostic digests.

ML-KEM `rej_uniform` currently covers the owned one-block parser, bounded
one-block tail parser, and the diagnostic initial-three-block capped parser for
public matrix SampleNTT. The rejected 2026-07-02 direct triple-XOF sampler
candidate reused these owned parsers from Keccak state memory, but it did not
move Graviton keygen and does not change the assembly inventory.

ML-KEM `basemul` currently covers owned full-polynomial accumulation, K=2/K=3/K=4
dot-product accumulation, and the Linux AArch64 variable-count chunk loop used
by the fused SampleNTT product diagnostic path.

## First-party Candidates Awaiting Headers

No tracked assembly files are currently in this bucket.

Header target for future first-party assembly:

```text
// Copyright (c) 2026 rscrypto contributors
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// rscrypto-owned ...
```

Only use that header after confirming no external source was copied or adapted.
If any file was adapted, keep it in the external bucket and record the source.

## Adjacent Non-ASM Provenance

These are not tracked assembly files, but they matter for the same ownership
goal because they carry external algorithm or table lineage.

- `src/aead/aes_round.rs`: Hamburg vperm AES tables sourced from OpenSSL
  `vpaes-x86_64.pl`.
- `src/checksum/crc32/aarch64.rs`: EOR3 CRC32C and ISO-HDLC kernels ported from
  `fast-crc32`.
- `src/checksum/crc64/aarch64.rs`, `src/checksum/crc64/x86_64.rs`,
  `src/checksum/crc64/power.rs`, `src/checksum/crc64/s390x.rs`: CRC64 folding
  algorithm derived from Intel/TiKV folding.

Treat these as separate ownership work. Rewriting assembly while leaving
externally sourced tables or schedules undocumented does not solve provenance.

## Work Plan

1. Keep the assembly ledger guard green.
   Verify with `scripts/check/asm-ledger.sh` or `just check`.

2. Keep BLAKE3 phase 1 closed.
   Verify the ledger stays green and revisit BLAKE3 only when a new owned
   AVX2/AVX-512 design can beat the retained upstream-derived ASM paths.

3. Replace or delete the AWS-LC / BoringSSL / OpenSSL / Cloudflare-derived
   assembly.
   Verify SHA-2, RSA Montgomery, and ChaCha20-Poly1305 tests pass against
   portable/oracle paths after each replacement.

4. Replace the s2n-bignum public-key assembly.
   Verify ECDSA, Ed25519, X25519, and RSA tests pass against portable/oracle
   paths after each replacement.

5. Keep the ML-KEM forward NTT ownership slice closed.
   Verify the owned AArch64 NEON forward NTT remains scalar-equivalent and
   revisit only if Graviton benches show the deleted assembly must be replaced
   by a faster owned generated kernel.

6. Close adjacent non-ASM provenance.
   Verify AES tables and CRC-derived algorithms are either owned, regenerated,
   or explicitly documented.

7. Keep this ledger current.
   Verify any new `.s` / `.S` file appears in exactly one section before merge.
