mirror of
https://github.com/block/buzz.git
synced 2026-10-30 14:01:37 +00:00
Mobile signs every Nostr event (sends, relay AUTH, media auth headers, preference writes) in pure Dart on the UI isolate. On an iPhone SE (2nd gen, Profile build) one BIP-340 signature costs about 10.7 ms and deriving the public key another 5.6 ms, so a burst of signed writes drops frames. This adds `mobile/packages/buzz_secp256k1`, a small FFI package that builds vendored bitcoin-core/libsecp256k1 v0.8.0 (ecdh, extrakeys, schnorrsig modules) through a Dart build hook, so the same C and the same Dart API ship on iOS and Android with no platform bridge code. All 13 `nostr.Event.from` signing sites now go through `signNostrEvent`, which keeps the `nostr` package's event-id serialization and moves only key derivation and signing to native code. Calls stay synchronous. The package also exposes `schnorrVerify` and `ecdhX`; follow-up PRs move verification and the NIP-44 conversation key over. Incoming relay events are still not verified, unchanged by this PR. Safety: the signing context is randomized once per isolate, secret keys and keypairs are wiped from the native scratch buffer after each call, aux randomness comes from `Random.secure()`, and the static verify context runs libsecp256k1's self test before first use. ### Validation - Added tests: BIP-340 official vectors and native-vs-pure-Dart differential tests in the package; `event_signing_test.dart` signs with 64 random keys and checks pubkey, event id and signature against the existing `nostr` builder and verifier, plus malformed-key rejection. - Full mobile analyze and test suite pass locally. - Builds: iOS release (framework ~1.3 MB) and Android debug APK with the library for arm64-v8a, armeabi-v7a and x86_64 (~1.2–1.3 MB each). - On-device (iPhone SE 2nd gen, Profile, median per op): sign 10,736 µs → 41 µs, derive pubkey 5,580 µs → 16.5 µs, full signed event 10,744 µs → 65 µs. Event-id JSON and SHA-256 are 23 µs, so they stay in Dart. - Device, iOS (iPhone SE 2nd gen, Profile): `buzz_secp256k1.framework` embedded; the signed-in app authenticated to a real community relay, loaded channels and history, and paged older messages. No native-asset or secp256k1 errors in the console. - Device, Android (emulator, debug): APK contains `libbuzz_secp256k1.so` and loads it. Against a local mock relay that verifies with the pure-Dart `nostr` package, the app's NIP-42 AUTH, NIP-98 `POST /query` headers, and kind 20001/30078 events all verified. - Blossom GET auth, iOS: the dev relay returns 401 for unauthenticated `/media/` GETs. From inside the running app, the production `MediaGetAuthService.headersFor()` header for a nonexistent hash got 404 (accepted, file missing), compared with 401 without it. The community has no relay-hosted image, so none was rendered. buzz-review-completed (agent review, Codex and security review clean; device validation above; human app test not applicable under the mobile testing exception) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Tom Brow <tomb@block.xyz> Co-authored-by: george <973be878edd6d4f79692a3827f20a6f7fe0ed0362f269ff6b6ba8867033d7d8e@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Native packages
Local Dart packages that wrap a native C library through dart:ffi. Each one
compiles its library from vendored source with a Dart build hook
(hook/build.dart), so Flutter's native assets support builds it for every
target (iOS, Android, and the host for flutter test). No CocoaPods, Gradle,
or CMake plugin wiring is involved.
Layout
packages/<name>/
pubspec.yaml # depends on hooks, code_assets, native_toolchain_c, ffi
hook/build.dart # CBuilder.library over the vendored sources
third_party/<lib>/ # pinned upstream subset + VENDORED.md (tag, sha256)
src/*.c # optional shims when the upstream API needs adapting
lib/src/bindings.dart # @Native leaf bindings, @DefaultAsset = the hook's assetName
lib/<name>.dart # small typed Dart API that owns memory and validation
test/ # upstream test vectors where they exist
Adding a library
- Vendor the smallest source subset from a tagged upstream release and record
the tag and tarball sha256 in
third_party/<lib>/VENDORED.md. Do not edit vendored files. - Mirror the upstream build system's compile definitions in
hook/build.dart. - Bind only the symbols the app needs. Mark calls
isLeaf: trueunless they call back into Dart, and keep callbacks in C shims so the bindings work in any isolate. - Add the package to
mobile/pubspec.yamlas apath:dependency.
Packages
buzz_secp256k1: bitcoin-core/libsecp256k1 (BIP-340 Schnorr, ECDH).