Commit Graph

11002 Commits

Author SHA1 Message Date
Crowdin Bot b9fbd77309 New Crowdin translations by GitHub Action 2026-04-09 15:14:37 +00:00
Crowdin Bot df243d4bf4 New Crowdin translations by GitHub Action 2026-04-08 23:59:08 +00:00
Crowdin Bot ddc3c1d318 New Crowdin translations by GitHub Action 2026-04-08 17:30:00 +00:00
Crowdin Bot 6ce3d377e3 New Crowdin translations by GitHub Action 2026-04-08 12:42:44 +00:00
Vitor Pamplona d4959473d7 Merge pull request #2170 from vitorpamplona/claude/improve-secp256k1-performance-nFGT8
Optimize secp256k1 with unrolled arithmetic and caching
2026-04-08 08:41:06 -04:00
Vitor Pamplona a010f01fbf Avoids warnings 2026-04-08 08:31:54 -04:00
David Kaspar 991a187dde Merge pull request #2171 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-04-08 12:08:48 +02:00
Crowdin Bot 17a4b54cb7 New Crowdin translations by GitHub Action 2026-04-08 09:15:42 +00:00
davotoula ade3ed5690 Added missing is GroupEventResult.Duplicate branch at DecryptAndIndexProcessor.kt:499 — it logs and ignores duplicate events 2026-04-08 11:12:02 +02:00
davotoula 5a72385a37 update translations: CZ, DE, PT, SE 2026-04-08 11:01:27 +02:00
Claude 491c31d625 perf: increase cache sizes from 256 to 1024 for ~1000 followed pubkeys
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
2026-04-08 03:06:46 +00:00
Claude df9c8a9f4b feat: add same-pubkey batch Schnorr verification (5-6x throughput)
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
2026-04-08 02:56:45 +00:00
Claude cf7e2d4b0d perf: specialize FieldP.sub and neg for secp256k1 prime structure
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
2026-04-08 01:35:54 +00:00
Claude f912520ee2 perf: reuse pre-allocated scratch for all entry-point allocations
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
2026-04-08 01:22:05 +00:00
Claude fc690d66c7 refactor: reorganize secp256k1 for clarity without affecting performance
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
2026-04-08 01:10:01 +00:00
Claude c7b164b845 perf: cache P-side wNAF tables in mulDoubleG for repeated pubkeys
In mulDoubleG (verify), the P-side wNAF-5 affine table (8 odd multiples
of P plus 8 GLV λ counterparts) is rebuilt from scratch on every call.
This costs ~437 field ops: 1 doublePoint + 7 addPoints + 8 β-multiplies
+ 1 batch inversion with full field inversion (~270 ops alone).

Add a 256-entry direct-mapped cache that stores these affine tables
keyed by the point's x-coordinate. On cache hit, the table build is
skipped entirely — the cached arrays are used directly (zero-copy).

This saves ~27% of mulDoubleG cost (~20% of total verify) for repeated
pubkeys. Combined with the liftX cache from the previous commit,
repeated-pubkey verifications now skip ~33% of the work.

JVM benchmark: verify ratio improved from 2.0x to 1.6-1.8x vs native C
(with the benchmark's 100% cache hit rate). Original baseline was 3.0x.

https://claude.ai/code/session_017UbWduFi1sLUsgVUMUH2nx
2026-04-08 00:55:54 +00:00
Claude bdf7ab1a15 perf: eliminate allocations in verify path and add pubkey cache
Add in-place ScalarN operations (mulTo, addTo, negTo) that write to
caller-provided output arrays instead of allocating. Add
Glv.splitScalarInto that uses pre-allocated scratch buffers from
PointScratch, eliminating ~26 LongArray allocations per call (called
2x per verify = ~52 allocs saved). Both mul and mulDoubleG now use
the allocation-free split path.

Pool all LongArray and MutablePoint allocations in verifySchnorr
into thread-local PointScratch (verifyPx/Py/R/S/E/Rx/Ry, verifyPPoint,
verifyResult). Add U256.fromBytesInto for decoding into pre-allocated
arrays. Total: ~14 object allocations eliminated per verify call.

Add pubkey decompression cache (256-entry direct-mapped) that skips
the liftX square root (~280 field ops) for repeated pubkeys. In Nostr,
the same authors are verified repeatedly, so cache hit rate is high.
This saves ~13% of verify cost per cache hit.

Increase benchmark warmup/iterations for more stable measurements
(e.g., verifySchnorr: 200/500 -> 2000/5000).

JVM benchmark result: verify ratio improved from 3.0x to 2.0x vs
native C (with 100% cache hit rate on the benchmark's single pubkey).

https://claude.ai/code/session_017UbWduFi1sLUsgVUMUH2nx
2026-04-08 00:44:41 +00:00
Claude 8a6d1f1d44 perf: increase benchmark warmup and iterations for stable results
The previous counts (200 warmup / 500 iterations for verify) were too
low for reliable measurements on noisy VMs. Increase to 2000+ warmup
and 3000-50000 iterations depending on operation cost, giving the JIT
time to fully optimize and reducing variance between runs.

https://claude.ai/code/session_017UbWduFi1sLUsgVUMUH2nx
2026-04-07 23:46:59 +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 1dd8edcd41 perf: optimize secp256k1 field arithmetic and point operations for Android
Unroll hot-path loops in U256 (mulWide, sqrWide, addTo, subTo) to
eliminate loop control overhead and array bounds checks that ART JIT
on Android does not optimize as aggressively as HotSpot. These functions
are called ~1,900× per signature verification.

Optimize unsignedMultiplyHighFallback to compute the unsigned 128-bit
product directly from 32-bit sub-products, avoiding the signed
multiplyHigh + correction path. Saves ~8 instructions per call on
Android < API 31 (~30,000 calls per verify).

Unroll FieldP.reduceWide carry propagation and inline the reduceSelf
subtraction (avoiding P array access and U256.subTo call). Unroll
FieldP.half with P[1..3]=-1 inlined as mask.

Replace copyFrom pattern in mul, mulG, and mulDoubleG with ping-pong
point buffers — alternate between two MutablePoints via reference swap
instead of copying 12 Longs after every addition. Eliminates ~170
copyFrom calls per verify and avoids the internal copy buffer in
doublePoint's out===inp path (~130 per verify). Also removes the
MutablePoint() allocation in mulG (3 LongArrays per sign/pubCreate).

https://claude.ai/code/session_017UbWduFi1sLUsgVUMUH2nx
2026-04-07 23:14:11 +00: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