Commit Graph
119 Commits
Author SHA1 Message Date
Claude a3e239d33f feat(store): cost-based FS driver pick, runtime index materialization, new relayBench shapes
Acts on the measured gaps from TagAuthorIndexBenchmark and
FsDriverSelectionBenchmark:

- FsQueryPlanner: replace the fixed tags -> kinds -> authors driver
  order with a cost-based pick. Every legal driver (each tagsAll value,
  each tags key's value union, the kind set, the author set) opens a
  lazy directory iterator; all are drained in lockstep and the first to
  exhaust (the smallest listing) drives, so a giant idx/kind tree is
  never read past ~the smallest candidate's size. Fixes the 149 ms vs
  3.4 ms (~44x at 30k events) authors+kinds+limit regression.

- EventIndexesModule.ensureOptionalIndexes + SQLiteEventStore: flag-
  gated indexes are runtime config, not schema. An idempotent
  CREATE INDEX IF NOT EXISTS pass now runs on every open, so flipping
  an IndexingStrategy flag on an existing DB builds the index without
  a user_version bump.

- Desktop LocalRelayStore: enable indexEventsByPubkeyAlone. Shared
  ViewModels (Nip65RelayList, PrivateOutboxRelayList, VanishRequests)
  replay authors-only filters that full-scanned without
  (pubkey, created_at); existing DBs pick the index up on next open.

- relayBench Scenarios: add "conversation" (tag ∩ author ∩ kind, the
  DM-room shape, 65 client assembler call sites) and "reactions-watch"
  (kind 7 + #e IN 150 hottest notes) so the uncovered archetypes get
  head-to-head numbers vs strfry.

- quartz build: forward tagBenchScale/fsBenchScale to the test JVM.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RzkoN3SJHCZWRAiadXXG4w
2026-07-21 14:54:48 +00:00
davotoulaandClaude Opus 4.8 d7e163111a build: remove Kover coverage plugin
Reverts the Kover coverage aggregation (introduced in dca345212b) from every
module, the root aggregation block, the Sonar coverage import, the version
catalog, and BUILDING.md. With the plugin present the 16 GB CI runner OOM-killed
during the Android test+build job even with Kover opt-in disabled; removing it
entirely clears the OOM. No other CI changes — the diff versus main is exactly
the inverse of dca345212b.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 16:52:29 +01:00
davotoula dca345212b build: aggregate Kover coverage for SonarQube import
- Apply Kover (Apache-2.0, build-time only) to the KMP/JVM modules and aggregate at the root
- include amethyst playDebug in the aggregated Kover coverage
2026-07-11 15:37:40 +01:00
Claude f29196f0fc test(store): measure follow-feed read/write/size tradeoff — keep current plan
follow-feed (kinds=[1,6] × 150 authors, ORDER BY created_at DESC LIMIT 500)
was geode's 5.5× loss (97.7ms vs strfry 17.6ms). Investigated whether any
change is worth it, across read + write + size.

Read (FollowFeedReadBenchmark, in-memory, scale 5 ≈ 1.05M events):
                  prolific-recent   sparse-old
  current            5.7 ms          1.9 ms
  scan (strfry)      1.0 ms       1601.9 ms
  union            316.9 ms         20.0 ms

- scan (created_at index + early LIMIT) wins for active follows but is
  catastrophic for sparse/inactive follows AND grows with corpus size
  (234ms→1601ms from scale 1→5) — following rarely-posting accounts is
  common, so it'd be a severe regression.
- union (300 per-branch subqueries) is dominated by branch overhead.
- current is the only robust option — flat across scale, bounded by the
  followed set, never catastrophic. The 97.7ms is a worst case (the 150
  MOST prolific authors, disk-bound reading all their matching rows).

No safe SQL-level swap exists; each alternative trades geode's worst case
for a worse one on a common workload. The only universal improvement is
strfry's app-level k-way merge (O(LIMIT+streams)) — a real new executor,
not a SQL tweak.

Write & size: neutral for every candidate — all reuse existing indexes
(query_by_kind_pubkey_created / query_by_created_at_id), none adds a
CREATE INDEX, so ingest throughput and storage are untouched regardless of
choice. A new index was considered and rejected (taxes every write, helps
one shape, reverts under ANALYZE).

Decision: keep the current composite plan. Full write-up in
quartz/plans/2026-07-04-follow-feed-read-tradeoff.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EZeWww5TJnzBZKPoc6mvU
2026-07-04 16:04:20 +00:00
Claude 8a607b08b9 perf(negentropy): profile NIP-77 reconcile, verify prefix-sum fingerprint fix
The 1M relayBench run had geode losing the negentropy phase to strfry
(initial reconcile 6066ms/27r vs 1270ms/14r; identical-set 1947ms vs
557ms). Three layered benchmarks pin where the time actually goes:

- NegentropyReconcileBenchmark (quartz): the kmp-negentropy server loop
  in isolation is ~200ms for the full 14-round exchange — the reconcile
  ALGORITHM is not the bottleneck. (An early version showed 22s/139r;
  that was a benchmark bug — index slices over randomly-sorted ids
  scatter the diff. Real relayBench slices are contiguous time ranges;
  monotonic created_at fixes it and matches strfry's round count.)
- NegentropyServerReconcileBenchmark (geode): the real in-process geode
  server over loopback is 3214ms — 15x the library loop. JFR of the
  server call-trees: ~40% hex/UTF-8/JSON serialization of the payloads,
  ~26% actual reconcile, rest allocation. The gap is the JVM
  constant-factor tax on hex-in-JSON, which strfry pays in C++, not a
  single hotspot.
- NegentropyPrefixFingerprintTest (quartz): the one algorithmic lever.
  Negentropy's fingerprint is an additive sum mod 2^256, so a prefix-sum
  table answers any range in O(1). Proven bit-for-bit identical to the
  library over 2000 random ranges, and 460x faster per call — the fix
  for the ~26% reconcile slice (dominant in the identical-set case).

Not yet wired: the library instantiates FingerprintCalculator
internally, so shipping prefix-sum needs a kmp-negentropy change (or a
quartz-side fast server). Full write-up + artifacts in
quartz/plans/2026-07-04-negentropy-reconcile-profiling.md.

Benchmarks are CI-safe (small defaults / opt-in gates); JFR via
-PnegProfile, scale via -DnegBenchN, geode server bench via
-DnegServerBench=1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EZeWww5TJnzBZKPoc6mvU
2026-07-04 05:22:20 +00:00
Claude 4b8cca0d59 feat: add production benchmark for the NostrClient receive path
Gated JVM test (-PprodRelayBench=1) that connects to live relays with
realistic filters and measures per-relay queue delay, processing time,
consumer busy fraction, EOSE latency and duplicate rates, comparing the
current inline verification against a parallel verify stage, plus
offline single-thread parse/verify ceilings on captured frames.

Findings from a first run are written up in
quartz/plans/2026-07-02-nostrclient-receiver-perf.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018saXqYfAa3RvSJoDXK591R
2026-07-02 22:49:42 +00:00
Claude 6a65680e61 refactor(cashu): move v4 (cashuB) token codec to quartz
The NUT-00 v4 `cashuB` wire-format encoder + CBOR models lived in
`amethyst/service/cashu/v4`, even though they are pure protocol code with
no app/UI dependencies. quartz had the proof/mint primitives but no
`cashuB` string codec at all, so this was a layering gap rather than a
duplicate.

Move `V4Encoder` and the `V4Token`/`V4T`/`V4Proof`/`V4DleqProof` wire
models into `quartz/nip60Cashu/token`, rewriting the JVM-only
`java.util.Base64` to the multiplatform `kotlin.io.encoding.Base64.UrlSafe`
so the codec lives in commonMain. This unblocks sharing CashuWalletOps /
CashuWalletState into commons (V4Encoder was one of the Android-only ties).

- add kotlinx-serialization-cbor (Apache-2.0) to quartz commonMain
- repoint CashuWalletOps (encoder) and V4Parser (V4Token) imports to quartz
- add V4EncoderTest round-trip coverage in quartz commonTest

amethyst's V4Parser stays put: it returns UI types (GenericLoadable +
commons CashuToken) and now just reuses the relocated quartz V4Token.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013UMNKix4qEfiAPP9s2a4gB
2026-06-19 14:48:40 +00:00
Vitor PamplonaandClaude Opus 4.8 270d229d0a build: drive all module versions from the catalog
Make every module read its release version from gradle/libs.versions.toml
instead of carrying its own literal, so a release bump is a single-file edit.

- Move the Android versionCode out of amethyst/build.gradle.kts into the
  catalog as `appCode`; amethyst reads it via libs.versions.appCode.get().
- quartz publishes with version = libs.versions.app.get().
- geode generates a BuildConfig.VERSION from the catalog (new
  generateVersionFile task) and RelayInfo.VERSION reads it, so the NIP-11
  software version tracks releases.
- Update the root build comment to point at the appCode entry.

Version-neutral: everything still resolves to the current 1.12.0 / 448.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 11:19:52 -04:00
Vitor Pamplona 0572b0091c v1.12.0 2026-06-16 14:38:13 -04:00
Claude d1749c314f fix: audit findings on iOS-readiness migration
Address bugs and gaps surfaced by an audit of the prior 14 commits.
JVM tests passed because of typealias / platform-type lenience that
won't hold on Native; these are real iOS compile / behavior issues.

BUG fixes (iOS compile failures):

- commons/.../Note.kt:899 — Iterable.sumOf { -> BigDecimal } is a
  JVM-stdlib-only overload. Common stdlib ships sumOf only for
  Int/Long/Double/Float/UInt/ULong. Replaced with fold(BigDecimal(0)).
- commons/.../Note.kt:889 — BigDecimal(it.event?.content): the quartz
  expect-class constructor takes String non-null; JVM accepted nullable
  via platform-type lenience and threw NPE caught downstream. Switched
  to ?.let { content -> BigDecimal(content) }.
- commons/.../Note.kt:838 — `catch (e: java.lang.Exception)` -> `Exception`.
- commons/.../feeds/custom/FeedDefinitionBuilder.kt + FeedBuilderState.kt:
  inline FQN `java.util.UUID.randomUUID().toString()` -> kotlin.uuid.Uuid.
  random().toString() (Kotlin 2.0+, @OptIn ExperimentalUuidApi).
  inline `System.currentTimeMillis() / 1000` -> TimeUtils.now() (already
  used elsewhere in the codebase).
- commons/.../viewmodels/NestViewModelTest.kt: moved from commonTest to
  jvmTest. The test imports NestViewModel + nestsclient, both of which
  the prior PR moved to jvmAndroid. commonTest depends on commonMain
  only, so the test would fail to compile for iosSimulatorArm64Test.

SUBTLE fixes:

- commons/.../UserRelaysCache.kt: the flow field used double-checked
  locking on a non-volatile var. JMM hazard on Native (ARM weak memory
  model) — outer fast-path could observe a partially-published
  WeakReference. Added @kotlin.concurrent.Volatile.
- commons/.../util/UrlValidation.ios.kt: NSURL.URLWithString("http:")
  returns non-null with scheme="http" and no host; JVM's URI.toURL()
  rejects with MalformedURLException. Reject scheme-only network URLs
  (http/https/ws/wss/ftp without a host) to match JVM behavior.
- commons/.../util/KmpLock.kt commonMain doc: corrected "NSLock" ->
  "NSRecursiveLock" to match the actual iOS implementation.

verifyKmpPurity gate extended (commons + quartz):

- Adds patterns: System.currentTimeMillis, Thread.sleep, java.util.UUID,
  kotlin.jvm.Synchronized, kotlin.jvm.Volatile.
- Each pattern paired with a hint pointing at the canonical KMP
  replacement; the error message surfaces both.
- Skips lines that start with //, *, or /* to avoid false positives on
  KDoc / migration notes.
2026-05-25 02:17:32 +00:00
Claude e0c3b18731 ci: add iOS test job for quartz + commonMain purity gate
Phase 1 of the iOS support plan (amethyst/plans/2026-05-24-ios-support.md).
Two independent guards so JVM-only imports can't silently appear in
quartz's iOS-bound source sets:

- :quartz:verifyKmpPurity (Linux, ~1s): scans commonMain + apple/native
  source sets for com.fasterxml.jackson / okhttp3 references and fails
  the build with a clear pointer to the offending file:line. Wired into
  the existing lint job so it runs on every PR.

- test-quartz-ios (macos-latest): runs :quartz:iosSimulatorArm64Test on
  the simulator (NIP-04, NIP-17, NIP-19, NIP-49 vectors + AES-GCM and
  chatroom-key tests already in quartz/src/iosTest) and additionally
  compileTestKotlinIosArm64 to catch device-variant compile drift.
2026-05-24 16:12:34 +00:00
Vitor Pamplona e0abc4a224 v1.11.0 2026-05-20 18:59:05 -04:00
Vitor Pamplona 280f21159f v1.10.0 2026-05-16 16:53:00 -04:00
Vitor Pamplona 8a498695a9 v1.09.2 2026-05-16 12:06:32 -04:00
Vitor Pamplona 5a30b10a77 v1.09.1 2026-05-15 18:25:17 -04:00
Vitor Pamplona 74c0d6906e v1.09.0 2026-05-15 15:43:47 -04:00
Claude c19bd4e92e refactor(geode): test fixtures + collectUntilEose helper, move to testFixtures sourceSet
The in-process relay was usable but every consumer test paid a 10–15
line tax for scope/client setup, manual cleanup inside the test body
(leaks on assertion failure), hardcoded "ws://127.0.0.1:7770/" magic
strings, and an inline collectUntilEose pattern reinvented per file.

Net: ~250 LOC removed, every test gets correct @After cleanup, and
the synthetic event builders no longer ship in geode's production jar.

- Move geode.fixtures (synthetic event builders) and the new
  geode.testing package from src/main to a new src/testFixtures
  source set via the java-test-fixtures plugin. Production geode jar
  no longer includes them; consumers wire them with
  testImplementation(testFixtures(project(":geode"))).
- Add geode.testing.RelayClientTest open class — owns hub, scope,
  client, defaultRelay, defaultRelayUrl with @After-driven cleanup.
- Add geode.testing.collectUntilEose / collectUntilEoseMulti
  NostrClient extensions with a shared subId counter and timeout knob.
  Replaces hand-rolled subscriber loops in 4+ files.
- Add RelayHub.DEFAULT_URL constant so tests stop typing
  "ws://127.0.0.1:7770/" inline.
- Migrate the 8 quartz NostrClient*Test files + geode's
  Nip01ComplianceTest to extend RelayClientTest and (where REQ/EOSE
  is the pattern) call collectUntilEose. Delete the redundant
  BaseNostrClientTest wrapper.
2026-05-07 13:42:20 +00:00
Claude c2f24a5213 refactor: rename quartz-relay module to geode
The relay implementation now stands as its own module. Fitting brand
for a Nostr relay shipped alongside the Quartz library — a geode is a
rock that holds quartz inside.

- Rename module directory quartz-relay/ -> geode/.
- Rename Gradle module path :quartz-relay -> :geode (settings.gradle).
- Rename Kotlin package com.vitorpamplona.quartz.relay -> com.vitorpamplona.geode.
- Rename application name + main class binding to match.
- Update the relay's NIP-11 advertised name to "geode" and the
  software URL to /tree/main/geode. Test asserting the doc updated.
- Refresh comments / Main.kt usage line / config.example.toml header.
- Update consumers: quartz/build.gradle.kts dependency path, and
  quartz NostrClient tests that import the in-process RelayHub.
2026-05-07 13:12:34 +00:00
Claude eb80dbcd15 feat(quartz-relay): rename + promote to a real Nostr relay
Renames :quartz-test-relay to :quartz-relay and promotes it from a
test-only fixture to a real, runnable Nostr relay that just happens
to also be used in tests.

Two transports now share the same `Relay` core:

- `RelayHub` + `InProcessWebSocket` — no socket, fastest path; ideal
  for unit tests inside one JVM.
- `LocalRelayServer` — Ktor `embeddedServer` (CIO engine) listening
  on a real `ws://` port. Use for `cli` interop tests, Android
  instrumented tests, or running the relay standalone.

NIPs implemented (all driven through production `NostrClient` in the
new `LocalRelayServerTest`):

- NIP-01 wire protocol (REQ/EVENT/EOSE/CLOSE) over real WebSockets
- NIP-09 deletion (via existing `DeletionRequestModule`)
- NIP-11 relay info doc — `RelayInfo` wraps the existing
  `Nip11RelayInformation` model and is served on HTTP GET when
  `Accept: application/nostr+json` is requested. Loadable from a
  JSON config file via `RelayInfo.fromFile(...)`.
- NIP-40 expiration (existing `ExpirationModule`)
- NIP-42 AUTH (existing `FullAuthPolicy`, opted-in via the
  `--auth` flag in the standalone runner)
- NIP-45 COUNT
- NIP-50 search via the existing FTS index
- NIP-62 right-to-vanish (existing module)

Adds a standalone runner: `./gradlew :quartz-relay:run --args="--port 7447 --verify"`
binds the relay to a real port. Flags: --host, --port, --path,
--info <file>, --db <file>, --auth, --verify.

Test-only event generators moved to a clearly-named
`com.vitorpamplona.quartz.relay.fixtures` package so they're still
shareable with consumer tests without polluting the production API.

Adds `LocalRelayServerTest` covering NIP-01/11/42/45/50 over a real
loopback WebSocket. Existing 11-test `Nip01ComplianceTest` (in-process
transport) continues to pass.
2026-05-07 00:56:57 +00:00
Claude aefecf71d8 test(quartz): add :quartz-test-relay for in-process Nostr relay testing
Replaces production-relay (wss://nos.lol, wss://nostr.bitcoiner.social)
dependencies in 10 quartz JVM relay tests with a deterministic
in-process Nostr relay built on top of the existing NostrServer +
EventStore, plus a NIP-01 compliance suite that exercises the bridge
end-to-end through NostrClient.

The new :quartz-test-relay module exposes:
- TestRelay / TestRelayHub: NostrServer + in-memory EventStore per URL,
  registry implements WebsocketBuilder so tests can drop it into
  NostrClient in place of BasicOkHttpWebSocket.Builder.
- InProcessWebSocket: bridges the WebSocket abstraction to RelaySession
  with a single-coroutine drain to preserve message ordering.
- SyntheticEvents / RelayFixtures: deterministic event generators and a
  loader for the existing nostr_vitor_*.json corpora.

Found and fixed three NIP-01/NIP-45 wire-format bugs in the relay
serializers that prevented round-trip through the in-tree NostrClient:
- OkMessage wrote success as a JSON string instead of a boolean,
  causing publishAndConfirm to hang.
- CountMessage dropped the queryId, breaking COUNT response routing.
- CountResult used the field name "pubkey" instead of "approximate".

Both Jackson and kotlinx-serialization paths were affected; both fixed
to match NIP-01/NIP-45 wire formats.
2026-05-07 00:41:02 +00:00
Claude 2ad1a48123 refactor(quartz): migrate in-tree C secp256k1 to libschnorr256k1-kmp
The custom C secp256k1 implementation under quartz/src/main/c/ was never
wired into Gradle (no externalNativeBuild block) and only existed for the
3-way benchmark + cross-validation test against ACINQ on JVM/Android.
The C library has been split out to vitorpamplona/libschnorr256k1{,-kmp},
so the in-repo copy is dead weight.

This change replaces it with the published Maven Central artifact
`com.vitorpamplona:schnorr256k1-kmp:1.0.0`, scoped to test/benchmark
configurations only — production crypto continues to use ACINQ
secp256k1-kmp on JVM/Android and the pure-Kotlin Secp256k1 on native.

The Android AAR ships libschnorr256k1_jni.so for arm64-v8a and x86_64,
so the Android benchmark now exercises the C row automatically (no more
manual build_android.sh). On JVM the .so still has to be installed by the
developer; the cross-validation test and triple-benchmark gracefully skip
the C row when System.loadLibrary fails, matching prior behavior.

Verified on JVM: all 13 secp256k1 jvmTest classes pass (188 tests), and
ACINQ vs pure-Kotlin benchmark numbers match the documented baseline
within sandbox noise (verifySchnorr ~15k ops/s, signSchnorr cached
~33k ops/s, pubkeyCreate+Compress ~36k ops/s).

Removes ~5,100 LOC: quartz/src/main/c/ (4,500), Secp256k1InstanceC.*
expect/actual shim (560), Secp256k1C JNI declaration object.

https://claude.ai/code/session_01KnvpK2amcVZKfFiZJvHjVe
2026-04-28 15:36:25 +00:00
Vitor Pamplona a566c663ec Better way to control the optimization level 2026-04-21 14:39:41 -04:00
Vitor Pamplona 036323fa53 This was added by the secp rewrite, but we moved them out to another repo, so now it can be removed. 2026-04-20 10:43:54 -04:00
Vitor Pamplona db18954d91 Fixes key creation for groups. 2026-04-15 12:04:38 -04:00
Claude fa0da7fae3 feat: upgrade negentropy-kmp to v1.0.2, enable macosArm64 target
negentropy-kmp v1.0.2 now publishes a macosArm64 artifact, unblocking
the macOS native target. Wired macosMain/macosTest source sets through
appleMain/appleTest and updated run_all.sh to run the K/Native
benchmark on both Linux (linuxX64) and macOS (macosArm64).

https://claude.ai/code/session_01WSNE6QKiYM2ZutQD2UihCW
2026-04-11 00:44:33 +00:00
Claude 731e32eb61 fix: revert macosArm64 target (blocked by negentropy-kmp), add K/N toolchain to session hook
macosArm64 target cannot be enabled until negentropy-kmp publishes a
macosArm64 artifact — commented out with explanation. Reverted run_all.sh
back to Linux-only for K/Native benchmark.

Added Kotlin/Native toolchain dependencies (GCC sysroot, LLDB, LLVM,
libffi) to session-start.sh so K/N compilation works in Claude Code
remote environments where Gradle's own downloader fails through the
proxy.

https://claude.ai/code/session_01WSNE6QKiYM2ZutQD2UihCW
2026-04-11 00:44:33 +00:00
Claude ce199f42df fix: drop deprecated macosX64 target, keep only macosArm64
macosX64 (Intel) has been removed from Kotlin's native target tiers.
Only macosArm64 (Apple Silicon) is supported.

https://claude.ai/code/session_01WSNE6QKiYM2ZutQD2UihCW
2026-04-11 00:44:33 +00:00
Claude 09001bbe98 feat: add macOS native targets (macosX64, macosArm64) to quartz
- Declare macosX64() and macosArm64() KMP targets in build.gradle.kts
- Wire macosMain/macosTest source sets through appleMain/appleTest
- Move Secp256k1NativeBenchmark from linuxX64Test to nativeTest so it
  runs on all native targets (Linux, macOS, iOS)
- Use platform() for dynamic labels instead of hardcoded "linuxX64"
- Update run_all.sh to pick the correct native target per OS/arch

https://claude.ai/code/session_01WSNE6QKiYM2ZutQD2UihCW
2026-04-11 00:44:33 +00:00
Claude 715e6e598c perf: add -Xno-param/call/receiver-assertions to remove null checks
Kotlin generates Intrinsics.checkNotNullParameter at the entry of every
function taking non-null reference types. Bytecode audit showed:
  Before: 128 checkNotNullParameter calls across secp256k1 classes
  After:  8 (only expression-value checks in non-hot paths)

Per Schnorr verify, this eliminates ~4,000+ invokestatic calls.
On ART (~2-3ns each): saves ~8-12μs per verify.
On HotSpot: neutral (C2 already optimizes null checks to fast branches).

These flags are safe for this module: all internal secp256k1 functions
use non-null LongArray/MutablePoint parameters that are never null.
Applied at the module level (compilerOptions) so all targets benefit.

https://claude.ai/code/session_01EMY5RnXb9rnsyU2KbXrSaY
2026-04-09 01:29:20 +00:00
Claude 9334994ce3 feat: add Kotlin/Native benchmark for secp256k1 on linuxX64
Mirrors the JVM benchmark (Secp256k1Benchmark.kt) for cross-platform
comparison of the same Kotlin code across runtimes:

  K/Native LLVM AOT (-opt) on x86-64:
    verifySchnorr:  101,406 ns  (9,861 ops/s)
    signSchnorr:     80,424 ns  (12,434 ops/s)
    FieldP.mul:          43 ns  (22.8M ops/s)

  JVM HotSpot C2 on same machine:
    verifySchnorr:   53,600 ns  (18,640 ops/s)
    signSchnorr:     42,400 ns  (23,518 ops/s)

  K/N vs JVM: ~1.9× slower (vs C: ~2.9×)
  K/N vs C native: ~2.9× slower

Includes field-level micro-benchmarks (FieldP.mul/sqr/add/sub/inv,
unsignedMultiplyHigh, uLt) for isolating LLVM codegen quality.

Also adds -opt to native test compilations for benchmark accuracy
(without it, debug mode is ~12× slower).

Run: ./gradlew :quartz:linuxX64Test --tests "*.Secp256k1NativeBenchmark"

https://claude.ai/code/session_01EMY5RnXb9rnsyU2KbXrSaY
2026-04-09 01:29:20 +00:00
Vitor Pamplona 9587026abc v1.08.0 2026-04-01 15:45:46 -04:00
Vitor Pamplona cd11503b1e v1.07.5 2026-03-31 20:18:34 -04:00
Vitor Pamplona 5cd83bbaa4 v1.07.4 2026-03-31 19:19:24 -04:00
Vitor Pamplona 69099728b2 v1.07.3 2026-03-31 17:32:23 -04:00
Vitor Pamplona 8e4ee7a618 v1.07.2 2026-03-30 16:46:01 -04:00
Vitor Pamplona 640c47e29f v1.07.1 2026-03-30 13:53:25 -04:00
Vitor Pamplona 0c4e5be1ea v1.07.0 2026-03-30 12:29:41 -04:00
Claude 5fc7526076 feat: add linuxX64 KMP target and restructure native source sets
Restructure quartz module's Kotlin/Native source set hierarchy for
proper multiplatform coverage. Adds linuxX64 target with complete
actual implementations for all expect declarations.

Source set hierarchy:
  commonMain
  ├── jvmAndroid → jvmMain, androidMain
  └── nativeMain (shared pure Kotlin)
      ├── appleMain (Apple APIs) → iosMain
      └── linuxMain (POSIX/OpenSSL) → linuxX64Main

nativeMain: Address, OptimizedJsonMapper, EventHasherSerializer,
  ChessEngine, Secp256k1Instance, BitSet, StringExt, io/ utilities

appleMain: Log (NSLog), SecureRandom (SecRandomCopyBytes),
  UriParser (NSURLComponents), BigDecimal (NSDecimalNumber),
  GZip (zlib), Sha256 (CC_SHA256), crypto (Apple provider),
  LargeCache (CacheMap), UrlEncoder, UnicodeNormalizer

linuxMain: Log (println), SecureRandom (/dev/urandom),
  UriParser (pure Kotlin), BigDecimal (pure Kotlin),
  GZip (zlib cinterop), Sha256 (OpenSSL), crypto (OpenSSL),
  LargeCache (AtomicReference<LinkedHashMap>), UrlEncoder

macOS targets deferred pending negentropy-kmp macOS artifacts.
macosMain/Platform.kt retained as scaffold for future activation.

https://claude.ai/code/session_01M9CAuPUV3TfPB2xShnsBhw
2026-03-28 02:55:20 +00:00
Vitor PamplonaandGitHub 009b5655f9 Merge branch 'main' into claude/add-negentropy-support-PcTpR 2026-03-27 08:15:24 -04:00
Vitor Pamplona 75a8e461ad 20x Faster Rfc3986Normalizer and way less objects being created. 2026-03-26 19:04:18 -04:00
Claude 70baf55e1c feat: add NIP-77 negentropy sync support
Add support for NIP-77 (Negentropy Syncing) protocol messages using
the negentropy-kmp library for efficient set reconciliation between
client and relay.

New files:
- NegOpenCmd, NegMsgCmd, NegCloseCmd: Client-to-relay commands
- NegMsgMessage, NegErrMessage: Relay-to-client messages
- NegentropySession: Client-side reconciliation orchestrator
- NegentropyServerSession: Server-side reconciliation handler
- NegentropyManager: High-level sync manager with listener callbacks

Updated serializers:
- Jackson MessageSerializer/Deserializer for NEG-MSG, NEG-ERR
- Jackson CommandSerializer/Deserializer for NEG-OPEN, NEG-MSG, NEG-CLOSE
- Kotlin MessageKSerializer/CommandKSerializer for all NIP-77 types

Compatible with strfry relay's negentropy implementation via the
negentropy-kmp library which implements the same Protocol V1 spec.

https://claude.ai/code/session_01Dc6W1G1jURAAR9kzyVvk6g
2026-03-26 04:23:32 +00:00
Vitor PamplonaandGitHub d84d146981 Merge branch 'main' into claude/remove-libsodium-dependency-DjtWa 2026-03-25 11:24:55 -04:00
Vitor Pamplona f42881a48e v1.06.3 2026-03-24 20:55:04 -04:00
Vitor Pamplona 1f2e24bc1f v1.06.2 2026-03-24 19:36:30 -04:00
KotlinGeekDev 349781d9be Use uri-reference-kmp in commonMain. Remove platform-specific implementations. 2026-03-24 16:34:13 +01:00
KotlinGeekDevandGitHub 4c14554263 Merge branch 'vitorpamplona:main' into kmp-completeness 2026-03-24 13:27:40 +01:00
Vitor Pamplona 7874893938 v1.06.1 2026-03-23 18:19:42 -04:00
KotlinGeekDev bddff36e6b androidLibrary {} -> android {} 2026-03-23 19:55:35 +01:00
KotlinGeekDev cfecfe2130 Move uri-reference-kmp to version catalog. Remove swift bridge(was a nice run). 2026-03-23 19:49:24 +01:00
KotlinGeekDev a9c41e1d55 Introduce uri-reference-kmp and replace uriBridge usages with it. 2026-03-23 19:31:58 +01:00