Skip to content

simd: U64x8::mul_lo32 — widening lo32×lo32→u64 on every backend (argon2 BlaMka) - #331

Merged
AdaWorldAPI merged 2 commits into
masterfrom
claude/u64x8-mul-lo32
Sep 24, 2026
Merged

AdaWorldAPI merged 2 commits into
masterfrom
claude/u64x8-mul-lo32

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

What this adds

U64x8::mul_lo32(self, rhs) computes, lane by lane, lo32(self) × lo32(rhs) as an exact u64.

  • Semantics: the high 32 bits of each input lane are ignored, and the product can't overflow because (2³²−1)² < 2⁶⁴.
  • Why: it's the multiply inside argon2's BlaMka function, a + b + 2·lo32(a)·lo32(b), which runs on a live path: ogar-encryption for a2ui session keys, and ogar-auth for logins. It's also the limb multiply that radix-2²⁶ Poly1305 and curve25519 arithmetic need.
backend body
AVX-512 _mm512_mul_epu32 (VPMULUDQ zmm)
AVX2 _mm256_mul_epu32 on each 256-bit half
NEON vmovn_u64 + vmull_u32 (UMULL) per quad
wasm i32x4_shuffle::<0,2,0,2> + u64x2_extmul_low_u32x4 per v128
scalar per-lane reference loop
nightly (a & 0xFFFF_FFFF) * (b & 0xFFFF_FFFF) on core::simd::u64x8

AVX-512 and NEON name the intrinsic rather than relying on portable source. A codegen probe showed that inside BlaMka's add chain, LLVM lowered the portable form to VPMULLQ (the full 64-bit multiply) on x86-64-v4, and left it as a scalar madd on aarch64.

Tests

  • simd::tests::u64x8_mul_lo32_matches_scalar:
    • checks every lane against the scalar definition;
    • every operand lane has non-zero high bits and is chosen so a full 64-bit multiply gives a different answer, and the test asserts that;
    • five lanes have products wider than 32 bits, so a truncating 32-bit multiply fails too;
    • also checks commutativity, and argon2's fBlaMka (RFC 9106 §3.5) built from mul_lo32.
  • neon-simd-parity (qemu) and wasm-simd-parity (node) gain the same check, as return code 0x30F.

Run locally, all green:

  • the new test on native AVX-512 and on pinned x86-64-v3;
  • scripts/neon-parity.sh and scripts/wasm-parity.sh;
  • full cargo test --lib on native: 2478 passed;
  • clippy -D warnings on native and on v3.

Disable runs, each one red:

  • AVX-512 changed to _mm512_mullo_epi64 → the lane 0 assertion fails;
  • NEON changed to multiply the high halves via vshrn → rc 783 (0x30F);
  • wasm shuffle changed to <1,3,1,3> → rc 783.

Not run locally: the nightly-simd arm; there's no nightly toolchain here, and CI's nightly rows cover it.

Note for reviewers

cargo --config X clippy does not apply X. clippy is an external subcommand, and cargo doesn't forward a --config given before it: rustc ran with target-cpu=native only. Use cargo clippy --config X. This is recorded on the blackboard.

🤖 Generated with Claude Code

https://claude.ai/code/session_019HnekoM1EidTwQLS3oFVFm


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added lane-wise multiplication of the low 32 bits of each pair of 64-bit values, returning exact 64-bit products across supported SIMD implementations.
  • Tests
    • Added checks against scalar results, including commutativity and wrapping-arithmetic cases. NEON and WebAssembly parity checks now cover the operation.

@coderabbitai

coderabbitai Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Essentials

Run ID: a4b7dafb-fd63-45dd-b7e0-5bb1487d1019

📥 Commits

Reviewing files that changed from the base of the PR and between a1ad0bc and 2cd4246.

📒 Files selected for processing (10)
  • .claude/blackboard.md
  • crates/neon-simd-parity/src/main.rs
  • crates/wasm-simd-parity/src/lib.rs
  • src/simd.rs
  • src/simd_avx2.rs
  • src/simd_avx512.rs
  • src/simd_neon.rs
  • src/simd_nightly/u_word_types.rs
  • src/simd_scalar.rs
  • src/simd_wasm.rs

Included review availability: 2 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 3 reviews per hour.


📝 Walkthrough

Walkthrough

U64x8::mul_lo32 is added to six SIMD implementations. It multiplies the low 32 bits of each pair of lanes and returns an exact 64-bit product. Tests and NEON and WebAssembly parity checks compare its results with scalar multiplication.

Changes

U64x8 multiplication

Layer / File(s) Summary
Implement lane-wise multiplication
src/simd_scalar.rs, src/simd_nightly/u_word_types.rs, src/simd_avx2.rs, src/simd_avx512.rs, src/simd_neon.rs, src/simd_wasm.rs
Adds U64x8::mul_lo32 to six SIMD implementations. Each implementation ignores the upper 32 bits and returns the exact 32×32-bit product in each 64-bit lane.
Validate multiplication results
src/simd.rs, crates/neon-simd-parity/src/main.rs, crates/wasm-simd-parity/src/lib.rs, .claude/blackboard.md
Adds scalar comparison, commutativity, and BlaMka arithmetic tests. Adds lane-wise parity checks for NEON and WebAssembly. The blackboard records implementation and test details, a Cargo Clippy configuration caveat, and a proposed Argon2 follow-up.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Suggested reviewers: claude

Merge Risk: ⚪ Minimal · up to 2cd42

No identified defect blocks merging after normal checks.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding widening low-32-bit multiplication for U64x8 across all SIMD backends, with its Argon2 BlaMka use case.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 18 functions across 9 files. (1 skipped: 1…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR

A rabbit checks each lane with care,
Low bits meet, and products pair.
Six paths return the same result,
Tests confirm each value built.
Then off I hop through fields of clover.

Comment @coderabbitai help to get the list of available commands.

@cursor

cursor Bot commented Sep 24, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_2c1487f0-a405-4bb4-95c3-72ea456c61e9)

@AdaWorldAPI
AdaWorldAPI marked this pull request as ready for review September 24, 2026 23:00
…n2 BlaMka)

Lane-wise lo32(self) x lo32(rhs) as an exact u64; the high 32 bits of each
input lane are ignored and the product cannot overflow. This is the multiply
in argon2's BlaMka G function (a + b + 2*lo32(a)*lo32(b)) and the limb
multiply of radix-2^26 Poly1305 / curve25519 arithmetic.

  AVX-512  _mm512_mul_epu32 (VPMULUDQ zmm). Intrinsic, not portable source:
           in BlaMka's add chain LLVM lowered the portable form to VPMULLQ.
  AVX2     _mm256_mul_epu32 on each 256-bit half.
  NEON     vmovn_u64 + vmull_u32 (UMULL) per quad; LLVM left the portable
           form scalar inside BlaMka on aarch64.
  wasm     i32x4_shuffle::<0,2,0,2> + u64x2_extmul_low_u32x4 per v128.
  scalar   the per-lane reference loop.
  nightly  (a & 0xFFFFFFFF) * (b & 0xFFFFFFFF) on core::simd::u64x8.

Tests: simd::tests::u64x8_mul_lo32_matches_scalar checks every lane against
the scalar definition with operands whose high halves are all non-zero and
chosen so a full 64-bit multiply differs in every lane (asserted), plus
commutativity and argon2's fBlaMka (RFC 9106 3.5) built from mul_lo32. The
NEON (qemu) and wasm (node) parity harnesses gain the same check as 0x30F.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HnekoM1EidTwQLS3oFVFm
@AdaWorldAPI
AdaWorldAPI merged commit 90cc821 into master Sep 24, 2026
26 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.

2 participants