Skip to content

refactor(meshlink): split Ed25519 fallback into field and point arithmetic units - #135

Merged
trancee merged 1 commit into
mainfrom
refactor/split-ed25519-fallback-into-field-point-signing
Jul 15, 2026
Merged

refactor(meshlink): split Ed25519 fallback into field and point arithmetic units#135
trancee merged 1 commit into
mainfrom
refactor/split-ed25519-fallback-into-field-point-signing

Conversation

@trancee

@trancee trancee commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Summary

Implements #125. Ed25519Fallback.kt (930 lines, a single class mixing
field arithmetic, point arithmetic, comb-table machinery, and the public
signing API) is split into three files:

  • Curve25519FieldArithmetic.kt (new) — LongArray-based field operations
    (add/subtract/multiply/square/invert/power2523/carry, etc.)
  • Curve25519PointArithmetic.kt (new) — Point/PointScratch operations,
    comb-table building, both the constant-time scalarBase and the
    deliberately variable-time windowedScalarMultiplyPublic paths (kept
    together since both are "point arithmetic," with their constant-time vs.
    variable-time rationale comments traveling with them)
  • Ed25519Fallback.kt (reduced, 930 → 290 lines) — the public
    sign/verify/generateKeyPair/deriveKeyPair API, composing the two
    extracted classes, retaining the ExpandedPrivateKey WeakHashMap cache
    unchanged

This is a cryptographic primitive used on real devices (the pure-Kotlin
Ed25519 fallback for platforms/OEM JCA implementations without native
Ed25519 support), so this was held to a materially higher verification bar
than the rest of this refactor series — see below.

Verification (elevated rigor given the crypto stakes)

  • Captured a full baseline of every Ed25519/Wycheproof-related test
    before any change, then confirmed byte-for-byte identical pass
    counts after: Ed25519FallbackTest 6/6, WycheproofRegressionTest 5/5
    (JVM) + 5/5 (Android host), AndroidCryptoPolicyConformanceTest 1/1,
    MeshRuntimeAndroidCryptoTest 1/1 — all unchanged.
  • ./gradlew :meshlink:allTests — 1239/1239 passing throughout (unchanged
    total count)
  • ./gradlew :meshlink:apiCheck — zero .api diff (all touched types
    internal)
  • ./gradlew :meshlink:detektAll — clean after baseline re-keying (finding
    types and counts unchanged except an expected +1 TooManyFunctions
    from the two new classes each independently tripping that rule; verified
    via a finding-type/count diff, not just a passing build)
  • ./gradlew :meshlink:ktfmtFormat — clean
  • Final verification bundle run from a clean rebuild
    (rm -rf meshlink/build) given the correctness stakes

An independent /code-review pass went further: it extracted the full
original file at main and did a character-by-character diff of every
one of the 39 original functions
against its new location, confirming
byte-for-byte identical arithmetic bodies, identical constants, and that
every constant-time/variable-time rationale comment was preserved verbatim
(not paraphrased, not dropped). No algorithmic change, no correctness bug
found in the original code during the extraction.

Residual notes (not blockers)

  • constantTimeEquals now exists as two small identical private copies
    (Ed25519Fallback.kt, Curve25519PointArithmetic.kt) — trivial, flagged
    by review as a candidate for a future tiny consolidation, not worth
    blocking this PR over.
  • The Detekt baseline regeneration also incidentally dropped 5 stale,
    unrelated L2capFrameBuffer.kt entries (that file isn't touched by this
    diff) — an unavoidable side effect of baseline regeneration, disclosed
    for reviewer awareness.
  • PureX25519.kt (explicitly out of scope per Split Ed25519Fallback.kt into field-arithmetic / point-arithmetic / signing-API files #125) was not touched.

Review

Passed /code-review (Standards + Spec axes), with the Standards pass
specifically instructed to distrust summary claims and verify the moved
arithmetic byte-for-byte given this is a cryptographic primitive. No
blockers on either axis.

Closes #125

…metic units

Implements #125 by extracting the RFC 8032/TweetNaCl radix-2^16 field
arithmetic and Edwards point arithmetic into dedicated internal classes:
- Curve25519FieldArithmetic
- Curve25519PointArithmetic (+ Point/PointScratch)

Ed25519Fallback now stays focused on signing/verification/key generation,
composing the two extracted units while preserving:
- exact constant-time vs variable-time path distinctions
- byte-for-byte signing/verification behavior
- ExpandedPrivateKey WeakHashMap cache semantics keyed by ByteArray identity

No algorithmic changes were made: arithmetic code was moved verbatim.

Regenerated detekt baseline for androidMain only. This is re-keying from
file extraction (MagicNumber/TooManyFunctions/VariableNaming/
UnsafeCallOnNullableType IDs moved from Ed25519Fallback.kt to the new files)
plus removal of stale L2capFrameBuffer baseline IDs no longer present in
current code.

Verification:
- allTests: 1239/1239 pass (unchanged)
- Ed25519/Wycheproof tests unchanged: Ed25519FallbackTest 6/6,
  WycheproofRegressionTest 5/5 on both JVM+AndroidHost,
  AndroidCryptoPolicyConformanceTest 1/1,
  MeshRuntimeAndroidCryptoTest 1/1
- apiCheck: zero .api diff
- detektAll: clean
- ktfmtFormat: clean
- clean rebuild re-check: rm -rf meshlink/build && allTests+apiCheck+detektAll pass
@trancee
trancee merged commit e3c4a13 into main Jul 15, 2026
13 checks passed
@trancee
trancee deleted the refactor/split-ed25519-fallback-into-field-point-signing branch July 15, 2026 19:06
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.

Split Ed25519Fallback.kt into field-arithmetic / point-arithmetic / signing-API files

1 participant