Commit Graph

10988 Commits

Author SHA1 Message Date
Claude 6f6e876158 feat: precompute all AI tone results in parallel
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
2026-04-08 16:33:06 +00:00
Claude 60d817b0c0 feat: move AI writing help to Application Preferences
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
2026-04-08 16:24:48 +00:00
Claude e674141054 feat: add mock writing assistant for UI testing
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
2026-04-08 15:52:18 +00:00
Claude 5ed66fd699 feat: auto-detect language for AI writing help
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
2026-04-08 14:42:03 +00:00
Claude 7ae536e80d feat: add AI writing help to new post screen
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
2026-04-08 12:47:23 +00:00
Vitor Pamplona 5e93ff0532 Merge pull request #2169 from vitorpamplona/claude/review-marmot-mls-C5whm
Add thread safety and robustness improvements to Marmot MLS implementation
2026-04-07 19:27:23 -04:00
Vitor Pamplona 61887f97b0 Merge pull request #2167 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-04-07 19:26:43 -04:00
Claude 894042f056 style: spotlessApply formatting fix for MarmotManager
https://claude.ai/code/session_018gVkmmYgMFtBH7G31pCk9N
2026-04-07 23:06:16 +00:00
Claude 4edfb816d2 feat: add removeMemberFromGroup and updateGroupMetadata to AccountViewModel
- Wire removeMember through AccountViewModel for UI access
- Add updateGroupMetadata to MlsGroupManager with Mutex protection

https://claude.ai/code/session_018gVkmmYgMFtBH7G31pCk9N
2026-04-07 23:05:59 +00:00
Claude 11412b8873 feat: add remove member, edit group metadata, and formatting fixes
- Add removeMember() to MarmotManager and AccountViewModel
- Add updateGroupMetadata() to MarmotManager for MIP-01 name/description
- Add MarmotGroupData.toExtension() for encoding metadata as MLS extension
- Add proposeGroupContextExtensions() to MlsGroup
- Apply spotlessApply formatting fixes
- SecretTree: prune consumed generations below current minimum

https://claude.ai/code/session_018gVkmmYgMFtBH7G31pCk9N
2026-04-07 23:05:44 +00:00
Claude 7d8937ca48 fix: SecretTree skipped keys, sentKeys cleanup, markAsRead, key zeroing
- H11: Cache skipped message keys in SecretTree for out-of-order decryption
- L1: Prune sentKeys map when exceeding 10000 entries
- L2: Prune consumed generations below current minimum
- H17: Call markAsRead when chat view is opened
- Key zeroing: Zero old private keys in KeyPackageRotationManager

https://claude.ai/code/session_018gVkmmYgMFtBH7G31pCk9N
2026-04-07 23:04:49 +00:00
Claude 6e3ad1f86e fix: remaining HIGH/MEDIUM bugs - outer epoch fallback, atomic writes, unread UI
- H10: Add outer decryption epoch fallback using retained exporter secrets
- H17: Display unread count badge in MarmotGroupListScreen
- M24: Log corrupted state before deletion in restoreAll
- M25: Atomic write-to-temp-then-rename in AndroidMlsGroupStateStore
- Thread safety: Add Mutex to KeyPackageRotationManager

https://claude.ai/code/session_018gVkmmYgMFtBH7G31pCk9N
2026-04-07 23:04:29 +00:00
Claude 4526beb4be fix: MEDIUM/LOW bugs - validation, unread tracking, TLS bounds, KeyPackage checks
- H17: Add unread count tracking to MarmotGroupChatroom
- M8: Add MAX_OPAQUE_SIZE bounds check to TLS deserialization
- M13: Add version/ciphersuite validation on KeyPackage deserialization
- M24: Add logging before deleting corrupted group state in restoreAll
- L1: Add size limit to sentKeys map in MlsGroup
- Additional UI fixes: leave group cleanup, error handling improvements
- Fix MarmotSubscriptionManagerTest for updated API

https://claude.ai/code/session_018gVkmmYgMFtBH7G31pCk9N
2026-04-07 23:04:09 +00:00
Claude 8c8ab4bb2c fix: HIGH/MEDIUM Marmot bugs - thread safety, dedup, UI error handling
- H8: Add Mutex to MarmotSubscriptionManager for thread safety
- H10: Add retained exporter secret to MlsGroupState/RetainedEpochSecrets
  for outer decryption of out-of-order messages
- H14: Add error handling to CreateGroupScreen and MarmotGroupChatView
- H15: Add removeGroup() to MarmotGroupList, clean up after leave
- M3: Use SecureRandom for nostrGroupId generation
- M5: Add event deduplication to MarmotInboundProcessor
- M6: Add KeyPackage credential validation in MarmotManager.addMember()
- M7: Validate nostrGroupId matches WelcomeEvent h-tag

https://claude.ai/code/session_018gVkmmYgMFtBH7G31pCk9N
2026-04-07 23:03:27 +00:00
Claude 29d1610d1a fix: critical Marmot/MLS bugs - crashes, crypto, protocol compliance
- C1: Fix leaveGroup() crash (used group state after deletion)
- C2: Fix X25519.bigIntegerToBytes ArrayIndexOutOfBoundsException
- C3: Add all-zeros DH check to prevent small-subgroup attacks
- C4: Fix path secret derivation off-by-one (RFC 9420 Section 7.4)
- C5: Use constant-time comparison for confirmation/membership tags
- C6: Stage signing keys in proposeSigningKeyRotation, promote on commit
- C7: Make commit conflict tracker per-(group,epoch) not just per-epoch
- C8: Fix tree deserialization leafCount for trimmed trees
- H8: Add Mutex-based thread safety to MlsGroupManager
- H9: Fix extractPrivateKeyBytes little-endian padding
- H12: Blank direct path on addLeaf (RFC 9420 Section 7.7)
- M14: Track actual leaf index from addLeaf for Welcome generation

https://claude.ai/code/session_018gVkmmYgMFtBH7G31pCk9N
2026-04-07 23:02:09 +00:00
Crowdin Bot f5d2b9116f New Crowdin translations by GitHub Action 2026-04-07 22:52:03 +00:00
Vitor Pamplona 46e50b880e avoids registering with an empty token 2026-04-07 18:50:00 -04:00
Vitor Pamplona fc07090121 Finishes the wakeUp event implementation 2026-04-07 18:36:55 -04:00
Vitor Pamplona 975ca3cb43 Force upload even if the ntfy token hasn't changed. 2026-04-07 18:36:39 -04:00
Vitor Pamplona c4b0270a51 Runs notification init in the background 2026-04-07 18:35:55 -04:00
Vitor Pamplona c40ac1870d Activates Relay services after starting okhttp for images/videos 2026-04-07 18:35:17 -04:00
Vitor Pamplona d64f018bc2 adds support for the Wake notification event 2026-04-07 18:15:13 -04:00
Vitor Pamplona 93c4164955 Fixes relay ui spacing after the drag and drop feature was added. 2026-04-07 11:11:15 -04:00
Vitor Pamplona 7799793c29 Merge pull request #2165 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-04-06 19:46:01 -04:00
Crowdin Bot 4595613fa4 New Crowdin translations by GitHub Action 2026-04-06 23:44:58 +00:00
Vitor Pamplona 4b2e53e0d7 Merge pull request #2166 from vitorpamplona/claude/port-secp256k1-kotlin-Ir8yz
Add pure Kotlin secp256k1 implementation for Nostr operations
2026-04-06 19:43:31 -04:00
Vitor Pamplona 292f8a3850 Migrates the SHA256 hasher out of the threadpool 2026-04-06 19:22:24 -04:00
Vitor Pamplona 9b4d6247f0 Adds an android benchmark comparison for the new Secp 2026-04-06 18:00:46 -04:00
Vitor Pamplona fe5f07da3f Moves the hex operations to our own functions 2026-04-06 17:55:54 -04:00
Vitor Pamplona 094586ff41 Fixes the sign issue in the fallback function 2026-04-06 17:55:17 -04:00
Vitor Pamplona 7a8b7a5e9f Merge branch 'claude/port-secp256k1-kotlin-Ir8yz' of https://github.com/vitorpamplona/amethyst into claude/port-secp256k1-kotlin-Ir8yz 2026-04-06 17:13:21 -04:00
Vitor Pamplona 57eb0ef803 Merge branch 'main' into claude/port-secp256k1-kotlin-Ir8yz 2026-04-06 17:13:01 -04:00
Vitor Pamplona 8a914d3130 removes some warnings 2026-04-06 17:12:00 -04:00
Claude 034c1ab2d1 fix: replace ThreadLocal with KMP-compatible ScratchLocal expect/actual
ThreadLocal.withInitial is a JVM-only API that doesn't compile on
Kotlin/Native or iOS targets. Replace all usages in commonMain
(FieldP.kt, Point.kt) with a new ScratchLocal expect/actual:

- jvmMain/androidMain: delegates to java.lang.ThreadLocal (same behavior)
- nativeMain: holds value directly (Kotlin/Native coroutines are
  cooperative, scratch buffers don't need thread isolation)

https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
2026-04-06 21:06:44 +00:00
Vitor Pamplona b60a0bcae8 Reverts the use of our own Secp256K1 until faster than native 2026-04-06 16:31:38 -04:00
Crowdin Bot ae142a39cd New Crowdin translations by GitHub Action 2026-04-06 20:23:10 +00:00
Vitor Pamplona d17203a632 Merge pull request #2162 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-04-06 16:21:49 -04:00
Vitor Pamplona 7e991fd4d8 Merge pull request #2164 from vitorpamplona/claude/fix-old-call-ringing-nM8y5
Prevent stale call offers from retriggering after app restart
2026-04-06 16:21:36 -04:00
Claude 5731275362 fix: prevent old call events from triggering ringing after app restart
When the app restarts and reconnects to relays, old call offer events
from completed calls could be replayed, causing the phone to ring for
calls that already ended. This was especially noticeable when the user
killed and restarted the app shortly after a call.

Three protections added to CallManager:

1. Track completed call IDs: hangup/reject events mark their call-id as
   completed. Subsequent offer events for the same call-id are ignored.

2. Init timestamp guard: events created before the CallManager was
   initialized (minus a grace period) are rejected, preventing stale
   events from a previous app session from triggering ringing.

3. Completed call IDs survive reset(): the set is intentionally not
   cleared when the call state machine resets to Idle, ensuring that
   stale offers remain blocked for the lifetime of the CallManager.

https://claude.ai/code/session_0145VKiG8yZMqcMsaBEjNPxv
2026-04-06 20:15:26 +00:00
Claude e0fc42e955 perf: Android API-level-gated unsignedMultiplyHigh + eliminate per-call branch
Three Android-specific optimizations:

1. Use Math.unsignedMultiplyHigh on API 35+ (Android 15): single UMULH
   instruction, eliminates the 4-insn signed→unsigned correction that
   the fallback path requires. Same optimization as our JVM 18+ path.

2. Use Math.multiplyHigh + correction on API 31-34 (Android 12-14):
   avoids the pure-Kotlin 4×32-bit sub-product fallback entirely.

3. Resolve API level check ONCE at class load via static final fields
   (HAS_MULTIPLY_HIGH, HAS_UNSIGNED_MULTIPLY_HIGH) instead of checking
   Build.VERSION.SDK_INT on every call. These functions are called 16×
   per field multiply (~12,000× per signature verify), so eliminating
   the per-call branch matters.

Performance tiers on Android:
  API 35+ (Android 15):  ~same as JVM 18+ (UMULH intrinsic)
  API 31-34 (Android 12-14): SMULH + 3 correction insns per product
  API 26-30 (Android 8-11): pure-Kotlin fallback (4 sub-products)

https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
2026-04-06 20:14:45 +00:00
Claude 2bf911379f docs: update Secp256k1.kt with instruction-level C comparison
Add precise per-operation cost analysis from comparing our Kotlin
implementation with bitcoin-core/secp256k1's C source:

- doublePoint: 1,516 insns (Kotlin) vs 530 insns (C) = 2.9×
  - mul/sqr accounts for 76% of gap (UMULH+MUL+carry vs single MUL)
  - add/neg/half accounts for 24% (reduceSelf vs lazy magnitude tracking)
- Update performance numbers to Java 21 results (verify 3.4×, sign 1.1×)
- Document all optimizations implemented during this session
- Note that lazy reduction penalty (4.2× on cheap ops) is the main
  remaining algorithmic opportunity, but requires 5×52-bit limb change

https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
2026-04-06 19:58:51 +00:00
Claude f9ec821107 docs+cleanup: inline hot-path functions, fix stale comments
- Add `inline` to hot-path tiny functions: U256.isZero, U256.testBit,
  FieldP.reduceSelf, FieldP.neg, MutablePoint.isInfinity. These are
  called thousands of times per EC operation; inline eliminates virtual
  call overhead (mostly helps Kotlin/Native; JVM JIT already inlines).
- Fix stale comment: G_TABLE_SIZE is 1024 for w=12 (was "64 for w=8")

https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
2026-04-06 19:42:47 +00:00
Crowdin Bot ad5bb87a1a New Crowdin translations by GitHub Action 2026-04-06 19:32:22 +00:00
Vitor Pamplona 96fd58dfcd Merge pull request #2163 from vitorpamplona/claude/fix-webrtc-ringing-bug-pNe68
Fix audio cleanup and call state handling on Activity destroy
2026-04-06 15:30:45 -04:00
Claude 6486a0a995 fix: stop ringing immediately when caller cancels WebRTC call
Move transitionToEnded() before the signing + relay publish in hangup()
so the UI stops ringing/ringback immediately, matching the pattern
already used by rejectCall(). Add onDestroy safety net in CallActivity
to hang up if the Activity is destroyed while a call is active. Wrap
audio stop methods in try-catch to prevent one failure from blocking
the others.

https://claude.ai/code/session_01Rip2HPCbF48PPFDiB2X5ik
2026-04-06 19:29:36 +00:00
Claude 494ca22bdf perf: pre-allocate inv/sqrt addition chain scratch via ThreadLocal
inv() and sqrt() each allocated 11 LongArray(4) (plus 2 for sqrt
verification) on every call. These are now served from a thread-local
Array(11) { LongArray(4) } cache, eliminating 22-24 allocations per
ECDH operation (inv called in toAffine, sqrt called in liftX).

Also reuses chain scratch slots for sqrt's verification step instead
of allocating separate check/ar arrays.

https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
2026-04-06 19:28:48 +00:00
Claude 20bab17440 perf: pre-allocate P-side tables and batch inversion temps in PointScratch
Eliminates ~80 LongArray allocations per mul/mulDoubleG call by
pre-allocating the P-side Jacobian and affine tables, the doubling
temp, and the batch inversion scratch buffers in PointScratch
(thread-local, allocated once per thread, reused across calls).

Before: mul() allocated 8 MutablePoint (24 LongArray) + 8 MutablePoint
(24 LongArray) + 16 AffinePoint (32 LongArray) + batch temps = ~92
LongArray per call. After: 0 allocations in the table construction path.

Also fixes minor allocation in addMixed degenerate case (use t[5]
scratch instead of new LongArray(4)).

https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
2026-04-06 19:22:38 +00:00
Vitor Pamplona 121eabd51f Merge pull request #2161 from vitorpamplona/claude/add-relay-drag-drop-uFrmj
Add drag-to-reorder functionality for relay lists
2026-04-06 15:10:28 -04:00
Vitor Pamplona 2b200538f0 Adjusting elevation borders 2026-04-06 15:07:08 -04:00
Claude 09427fe6cf perf: direct Math.unsignedMultiplyHigh call — eliminate MethodHandle boxing
The JVM target is Java 21, so Math.unsignedMultiplyHigh (Java 18+) can
be called directly without MethodHandle reflection. The previous approach
used MethodHandle.invokeExact which Kotlin compiles with Object return
type, causing Long boxing on every call (3 box/unbox per invocation ×
16 calls per field multiply = 48 boxed objects per mul).

Direct call compiles to a single UMULH instruction with zero overhead.
This is the most performance-critical function: called ~12,000× per
signature verification.

https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
2026-04-06 19:01:38 +00:00