Instead of computing on-tap, all 9 tones are precomputed in parallel
after a 1-second debounce when the user stops typing. Tone chips only
appear once results are ready. Tapping a chip instantly shows the
precomputed result. Text changes cancel and restart the computation.
https://claude.ai/code/session_01RbCYGrbbapRMike8WQy41F
When selecting a relay from the top nav filter, the home feed now
filters in-place (New Threads, Conversations, Live) showing only
posts from that relay, with subscriptions scoped to it.
https://claude.ai/code/session_01PZLLjE7MWh7PPz1woVqmxM
Replace the sparkle toggle button in the compose toolbar with a
persistent setting in UI/Application Preferences. The new "Propose AI
text improvements" setting (Always/Never) controls whether the tone
chip row appears in the compose screen.
When enabled and the device supports on-device AI, the tone chips show
automatically below the text field. Removes the per-session toggle
button from BottomRowActions.
https://claude.ai/code/session_01RbCYGrbbapRMike8WQy41F
These options are better suited as settings entries rather than top-level
drawer items. They are now in the Account Settings section, placed after
Relay Setup for logical grouping.
https://claude.ai/code/session_017bgasTSsMRR9aepmAsKEzR
Temporary MockWritingAssistant that returns fake transformed text after
a short delay. Enabled via useMockAi flag in ShortNotePostViewModel.
Allows testing the AI writing help UI on devices without Gemini Nano.
TODO: Set useMockAi = false before shipping.
https://claude.ai/code/session_01RbCYGrbbapRMike8WQy41F
Use ML Kit language identification to detect the post's language before
transforming. Maps detected BCP-47 tags to the 7 supported languages
(English, Japanese, Korean, German, French, Italian, Spanish). Falls
back to English for unsupported languages. Rewriter and proofreader
clients are cached per language+outputType combination.
https://claude.ai/code/session_01RbCYGrbbapRMike8WQy41F
processCommit now detects ExternalInit proposals and allows the sender
leaf index to equal tree.leafCount (the new joiner's slot), matching
RFC 9420 Section 12.4.3.2 external commit semantics.
MlsKeyPackage.decodeTls no longer rejects non-0x0001 ciphersuites so
that interop test vectors with other suites round-trip correctly.
https://claude.ai/code/session_01LpR6qsF6nep1RnXA9KbXGs
Replace TODO stubs with pure Kotlin implementations of Ed25519 (RFC 8032) and
X25519 (RFC 7748) for native targets, completing Marmot MLS support on iOS.
Shared field arithmetic over GF(2^255-19) is extracted to nativeMain. Also
fixes MarmotSubscriptionManagerTest assertions to account for the ownKeyPackageFilter
added to buildFilters().
https://claude.ai/code/session_01LpR6qsF6nep1RnXA9KbXGs
Add on-device AI writing assistance using ML Kit GenAI APIs (Rewriting,
Proofreading) powered by Gemini Nano via Android AICore. Users can tap
the sparkle button in the compose toolbar to access tone chips (Correct,
Rephrase, Shorter, Elaborate, Friendly, Professional, More Direct,
Punchy, + Emoji) that transform their post text. Results appear in a
card with Use/Dismiss actions.
- Play flavor: MLKitWritingAssistant using on-device Gemini Nano
- F-Droid flavor: NoOpWritingAssistant stub (returns unavailable)
- WritingAssistant interface for future DVM/NIP90 integration
- AI button hidden on unsupported devices
Also fixes pre-existing exhaustive when expression in
DecryptAndIndexProcessor for GroupEventResult.Duplicate.
https://claude.ai/code/session_01RbCYGrbbapRMike8WQy41F
DisplayAllAccounts collects from accountsFlow() which is a
MutableStateFlow initialized to null. The accounts are lazily loaded
from encrypted storage only when allSavedAccounts() is called, but
nothing in the account switcher triggers that load.
Add a LaunchedEffect that calls allSavedAccounts() when the flow
is still null, ensuring the account list is populated when the
bottom sheet opens.
With 256 slots and ~1000 followed users, the direct-mapped caches had
~75% collision rate (multiple pubkeys mapping to the same slot, causing
constant eviction and recomputation). Increasing to 1024 slots covers
most follow lists with minimal collisions.
Memory impact:
pubkeyCache: 1024 × ~96 bytes = ~96KB (was ~24KB)
pTableCache: 1024 × ~1KB = ~1MB (was ~256KB)
Total ~1.1MB — acceptable for mobile.
https://claude.ai/code/session_017UbWduFi1sLUsgVUMUH2nx
Add verifySchnorrBatch(pub, signatures, messages) that verifies n
signatures from the same public key using scalar and point summation
instead of n individual mulDoubleG calls.
The batch equation exploits linearity of Schnorr signatures:
(Σ sᵢ)·G = (Σ Rᵢ) + (Σ eᵢ)·P
This combines n verifications into:
- n scalar additions for S = Σsᵢ and E = Σeᵢ (trivial)
- n liftX + (n-1) addMixed for R_sum = ΣRᵢ (cheap point additions)
- ONE mulDoubleG(S, P, -E) (the expensive EC operation, done once)
- Check result - R_sum = O (no toAffine needed)
JVM benchmark results (same pubkey, 1000 iterations, 500 warmup):
batch( 4): 4.1x faster than individual (40,121 events/s)
batch( 8): 5.3x faster (49,637 events/s)
batch(16): 5.5x faster (49,815 events/s)
batch(32): 5.9x faster (51,272 events/s)
This fits the Nostr pattern perfectly: when loading a profile or
connecting to a relay, many events from the same followed author
arrive together and can be batch-verified.
If the batch fails (returns false), the caller falls back to
individual verification to identify which signature(s) are invalid.
Security: by linearity, individual errors cannot cancel without
solving the discrete log. For extra hardening, duplicate events
from multiple relays can be verified individually as cross-checks.
https://claude.ai/code/session_017UbWduFi1sLUsgVUMUH2nx
Inline the P = [P0, -1, -1, -1] constant into sub and neg instead
of going through generic U256.addTo/subTo + P array reads.
For sub (add-back P on borrow): when carry from limb 0 is 1, adding
P[1..3]=-1 with carry is identity (no-op). When carry is 0, just
subtract 1 with borrow propagation through limbs 1-3. Replaces a
full 4-limb generic addition with a conditional decrement.
For neg (P - a): uses bitwise NOT for limbs 1-3 (since P[i]=-1,
P[i]-a[i] = ~a[i]) with simple borrow propagation from limb 0.
Replaces a full 4-limb generic subtraction with P array reads.
These are called ~500 times per verify. On JVM/HotSpot the gain is
marginal (inlining already handles this), but on Android ART the
reduced function call depth and eliminated array loads should help.
https://claude.ai/code/session_017UbWduFi1sLUsgVUMUH2nx
Pool toAffine/toAffineX temp LongArrays (zInv, zInv2, zInv3) into
PointScratch. Add scratch-aware overloads that hot paths now use,
keeping allocating convenience overloads for one-time init paths
(buildCombTable).
Consolidate verify/sign/pubCreate/ECDH scratch into shared entry*
fields in PointScratch (entryPx, entryPy, entryPoint, entryResult,
entryTmp, entryTmp2). This replaces the old verify-specific fields
(verifyPx/Py/R/S/E/Rx/Ry/PPoint/Result) with fewer, shared buffers.
Update all Secp256k1 entry points (pubkeyCreate, signSchnorr,
signSchnorrInternal, verifySchnorr, pubKeyTweakMul, ecdhXOnly)
to use scratch instead of per-call allocations.
Add KeyCodec.liftX overload accepting a temp buffer to avoid 1
LongArray allocation per call.
Eliminate 2 longArrayOf allocations in ScalarN.reduceWideTo by
reusing the output array as temporary storage for hi limbs.
https://claude.ai/code/session_017UbWduFi1sLUsgVUMUH2nx
Extract MutablePoint, AffinePoint, and PointScratch from Point.kt into
PointTypes.kt (140 lines). Rename Point.kt to ECPoint.kt (897 lines)
to match the single top-level declaration (ktlint convention).
Remove dead code:
- addWnafJacobian: private function never called (replaced by
addWnafMixedPP with effective-affine tables)
Remove 5 KeyCodec wrapper functions from ECPoint that just delegated
(liftX, hasEvenY, parsePublicKey, serializeUncompressed,
serializeCompressed). Callers in Secp256k1.kt and PointTest.kt now
use KeyCodec directly, making ownership clear: KeyCodec owns key
encoding/decoding, ECPoint owns point arithmetic.
Update Secp256k1.kt header documentation with current benchmark
numbers (verify 1.7x, sign 0.9x faster than native, etc.) and
a concise list of optimizations.
No functional or performance changes — all 170 tests pass, benchmark
numbers unchanged.
https://claude.ai/code/session_017UbWduFi1sLUsgVUMUH2nx
Replace the manual KeyPackage publish button with a LaunchedEffect
that auto-publishes if no key package exists yet. The subscription
already correctly downloads our own kind:30443 via
ownKeyPackageFilter() on home relays, and rotation is handled
reactively when Welcome messages are processed.
https://claude.ai/code/session_01LhfCp8DHqNVx6mSiYfpQny