Rebuild Arti from audited source with enforced provenance

Vendored arti.xcframework rebuilt from source (Rust 1.96.0, normalized
archive metadata for reproducible hashes). New ARTI-BINARY-PROVENANCE.md
records toolchain, rebuild steps, and a SHA256 manifest for every file
in the xcframework. A new CI workflow turns that policy into a gate:
PRs must keep the binary matching the manifest, and binary changes must
ship with source/lockfile/build-script evidence.

Also raises TorManager.awaitReady's default timeout from 25s to 75s to
match the bootstrap monitor deadline - a shorter wait reported "not
ready" while Arti was still legitimately bootstrapping, silently
stranding queued relay work.

Privacy policy, Tor integration doc, and privacy assessment updated to
match the current implementation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jack
2026-06-10 16:22:15 +01:00
co-authored by Claude Fable 5
parent 3eb4f2bd72
commit 4093ee6733
14 changed files with 333 additions and 65 deletions
+88
View File
@@ -0,0 +1,88 @@
# Arti Binary Provenance
This repo vendors a prebuilt Arti static-library xcframework at:
`localPackages/Arti/Frameworks/arti.xcframework`
SwiftPM links it through `localPackages/Arti/Package.swift` as the binary target named `arti`. Treat changes to this artifact like dependency updates: review the Rust sources, lockfile, build script, produced headers, and artifact hashes together.
## Source Inputs
- Rust workspace: `localPackages/Arti/Cargo.toml`
- Crate: `localPackages/Arti/arti-bitchat`
- Dependency lockfile: `localPackages/Arti/Cargo.lock`
- Build script: `localPackages/Arti/build-ios.sh`
- Exported C header: `localPackages/Arti/Frameworks/include/arti.h`
The crate declares `rust-version = "1.90"` and uses `arti-client` / `tor-rtcompat` `0.38` with minimal Tokio/Rustls features. The current lockfile requires Rust 1.90 or newer. The build script currently targets:
- `aarch64-apple-ios`
- `aarch64-apple-ios-sim`
- `aarch64-apple-darwin`
It builds release static libraries with size-oriented flags (`opt-level=z`, fat LTO, one codegen unit, `panic=abort`, stripped symbols), normalizes static-archive metadata with `xcrun libtool -static -D`, then packages them with `xcodebuild -create-xcframework`.
## Regenerating The Artifact
From the repo root:
```sh
cd localPackages/Arti
rustup toolchain install 1.96.0
rustup default 1.96.0
rustup target add aarch64-apple-ios aarch64-apple-ios-sim aarch64-apple-darwin
cargo install cbindgen
./build-ios.sh
```
After rebuilding, verify that:
- `Cargo.lock` changes are intentional and reviewed.
- `Frameworks/include/arti.h` still matches the exported FFI functions used by `TorManager`.
- `Frameworks/arti.xcframework` contains iOS device, iOS simulator, and macOS arm64 slices.
- The main app still passes iOS tests and the macOS build.
## Audited Rebuild
The June 2026 artifact below was rebuilt from source on this host with:
```text
rustc 1.96.0 (ac68faa20 2026-05-25)
cargo 1.96.0 (30a34c682 2026-05-25)
rustup 1.29.0 (28d1352db 2026-03-05)
cbindgen 0.29.3
Xcode 26.5
Build version 17F42
```
Rust 1.86.0 was also checked during the audit and no longer builds this lockfile because `typed-index-collections@3.4.0` requires Rust 1.90.0 or newer.
The build script now normalizes static-archive metadata and writes a stable xcframework `Info.plist`. Two consecutive no-source-change rebuilds on this host produced the same hashes below.
## Current Artifact Hashes
Run this from the repo root to verify the checked-in artifact:
```sh
find localPackages/Arti/Frameworks/arti.xcframework -maxdepth 3 -type f -print0 | sort -z | xargs -0 shasum -a 256
```
Current hashes:
```text
2083d44eafc765db1ffa2691a5c5fabe60b4edbb82b574169ca0c6b98e245e3a localPackages/Arti/Frameworks/arti.xcframework/Info.plist
551655904834748c9dc36034fdbc9465e7533aef1e4a6514b4fcc75875b93058 localPackages/Arti/Frameworks/arti.xcframework/ios-arm64-simulator/Headers/arti.h
85febff37b751df667a3cab8222de2e1450cefe44b5b62c419adcbce48b9663f localPackages/Arti/Frameworks/arti.xcframework/ios-arm64-simulator/libarti_bitchat.a
551655904834748c9dc36034fdbc9465e7533aef1e4a6514b4fcc75875b93058 localPackages/Arti/Frameworks/arti.xcframework/ios-arm64/Headers/arti.h
fd25ee379d709a794733fc3c052746d1e6f7b25fec23e5f5234008a3434ce879 localPackages/Arti/Frameworks/arti.xcframework/ios-arm64/libarti_bitchat.a
551655904834748c9dc36034fdbc9465e7533aef1e4a6514b4fcc75875b93058 localPackages/Arti/Frameworks/arti.xcframework/macos-arm64/Headers/arti.h
8c426a41dc3eb76cc3e3e22e3356b9d11dbebdf0a0f248c5ac892e1839352c75 localPackages/Arti/Frameworks/arti.xcframework/macos-arm64/libarti_bitchat.a
```
## Review Checklist
- Record `rustc --version`, `cargo --version`, `cbindgen --version`, and `xcodebuild -version` in the PR when refreshing the binary.
- Include the hash output above after any binary change.
- If a rebuild changes only xcframework/library bytes, record the new hashes and app validation evidence in the PR.
- Keep `target/`, `.build/`, and `.swiftpm/` out of source control.
- Do not accept an xcframework-only update without matching source, lockfile, or build-script evidence explaining where it came from.
+7 -26
View File
@@ -2,7 +2,7 @@ Tor-by-default integration (scaffold)
Overview
- All network traffic is routed via a local Tor SOCKS5 proxy by default, with fail-closed behavior when Tor isnt ready. There are no user-visible settings.
- This repo now includes a minimal TorManager and TorURLSession to make dropping in an embedded Tor framework straightforward.
- This repo vendors an Arti-backed Swift package under `localPackages/Arti`, including a Rust static-library xcframework linked by SwiftPM.
Key pieces
- TorManager
@@ -12,36 +12,17 @@ Key pieces
- Provides a shared URLSession configured with a SOCKS5 proxy when Tor is enforced/ready.
- NostrRelayManager and GeoRelayDirectory now use this session and await Tor readiness before starting network activity.
Dropin steps
1) Build or obtain a small Tor framework
- Recommended: Tor C (client-only) with static linking and dead-strip.
- Configure Tor with a minimal feature set:
./configure \
--enable-static \
--disable-asciidoc --disable-unittests --disable-manpage \
--disable-zstd --disable-lzma --enable-zlib \
--disable-systemd --disable-ptrace --disable-seccomp
CFLAGS="-Os -fdata-sections -ffunction-sections" \
LDFLAGS="-Wl,-dead_strip"
- Build a tiny OpenSSL/LibreSSL (no engines, strip symbols) or reuse system crypto where permitted on macOS.
Artifact maintenance
- Binary provenance, rebuild steps, and current hashes are documented in `docs/ARTI-BINARY-PROVENANCE.md`.
- The xcframework must include iOS device, iOS simulator, and macOS arm64 slices.
- Any refresh should review the Rust source, `Cargo.lock`, generated header, build script, and new hashes together.
2) Add the framework to Xcode targets
- Drop your xcframework into `Frameworks/`. The project is prewired in `project.yml` to link/embed `Frameworks/tor-nolzma.xcframework` (rename yours to match, or update the path).
- Ensure the binary includes the slices you need (iOS device/simulator and/or macOS). If your xcframework lacks simulator slices, you can still build/run on device or macOS arm64; simulator will fail to link.
- On iOS, it will be embedded and signed automatically.
3) Wire Tor bootstrap in TorManager.startTor()
- Two paths are already implemented:
- If a module named `Tor` is present (iCepa API), it starts `TORThread` directly.
- Otherwise, it attempts a dynamic load (`dlopen`) of a bundled framework binary named `tor-nolzma.framework/tor-nolzma` (or `Tor.framework/Tor`), resolves `tor_run_main`, and launches Tor on a background thread.
- `TorManager` writes a torrc and then probes `127.0.0.1:39050` until ready.
4) Verify networking
Verification
- On app launch, TorManager.startIfNeeded() is called implicitly by awaitReady().
- NostrRelayManager.connect() awaits readiness, then creates WebSocket tasks via TorURLSession.shared.
- GeoRelayDirectory.fetchRemote() awaits readiness, then fetches via TorURLSession.shared.
5) Optional macOS optimization
Optional macOS optimization
- Detect a system Tor binary (e.g., /opt/homebrew/bin/tor) and run it as a subprocess to avoid bundling. Keep the embedded fallback for portability.
torrc template
+18 -3
View File
@@ -4,14 +4,16 @@ BitChat Privacy Assessment
Scope
- Mesh transport (BLE) behavior and metadata minimization
- Nostr-based private message fallback (gift-wrapped, end-to-end encrypted)
- Nostr-backed public geohash channels, presence heartbeats, and location notes
- Optional CoreLocation use for geohash channel discovery
- Read receipts and delivery acknowledgments
- Logging/telemetry posture and controls
Summary
- No accounts, no servers for mesh; Nostr used only for mutual favorites, with end-to-end Noise encryption encapsulated in gift wraps.
- No accounts and no project-operated servers. Mesh traffic is peer-to-peer; Nostr is used for mutual-favorite private fallback and public geohash features.
- BLE announces contain only nickname and Noise pubkey. No device name, no plaintext identity beyond what the user broadcasts.
- Discovery and flooding incorporate jitter and TTL caps to reduce linkability and propagation radius of encrypted payloads.
- UI and storage remain ephemeral; message content is not persisted to disk. Minimal state (e.g., read-receipt IDs) is stored for UX and is bounded/cleaned.
- UI and storage remain mostly ephemeral; message content is not persisted to disk by default. Minimal local state (e.g., read-receipt IDs, favorites, selected/bookmarked geohashes) is stored for UX and is bounded or user-wipeable.
- Logging defaults to conservative levels; debug verbosity is suppressed for release builds. A single env var can raise/lower threshold when needed.
BLE Privacy Considerations
@@ -35,6 +37,14 @@ Nostr Private Messaging Fallback
- Read/delivery acks: Also encapsulated in gift wraps, preserving content secrecy and minimizing metadata.
- Relay policy variance: Some relays apply “web-of-trust” policies and may reject events; BitChat tolerates partial delivery and still prefers mesh when available.
Location Channels and Geohash Public Chats
- Location permission: Optional when-in-use CoreLocation access computes local geohash channel options. Exact coordinates are held in memory only and are not included in BitChat or Nostr payloads.
- Local state: Selected channel, teleported geohashes, bookmarks, and bookmark display names are stored in `UserDefaults`; the panic action clears location presence state along with identity/session state.
- Geohash precision: User-selected channels can range from region-level to building-level. Public geohash messages and location notes expose the selected geohash tag to relays and participants.
- Presence minimization: Automatic presence heartbeats are restricted to low-precision region/province/city geohashes and use randomized timing.
- Per-geohash identities: Public geohash Nostr identities are derived from a device seed stored in the keychain, reducing cross-channel linkability compared with a single stable public key.
- Relay metadata: Relays can observe event kind, geohash tag, public key, timestamp, and network metadata. Content in public geohash channels is intentionally public to that channel.
Read Receipts and Delivery Acks
- Routing policy: Prefer mesh if Noise session established; otherwise use Nostr when mapping exists.
- Throttling: Nostr READ acks are queued and rate-limited (~3/s) to prevent relay rate limits during backlogs.
@@ -44,6 +54,9 @@ Data Retention and State
- Messages: Ephemeral in-memory only; history is bounded per chat and trimmed.
- Read-receipt IDs: Stored in `UserDefaults` for UX continuity; periodically pruned to IDs present in memory.
- Favorites: Noise and optional Nostr keys with petnames; can be wiped via panic action.
- Location channels: Exact coordinates are not persisted by BitChat. Selected/bookmarked geohashes, teleport flags, and bookmark display names persist locally until removed, panic-wiped, or the app is deleted.
- Geohash identities: Device seed is stored in the keychain and used to derive per-geohash Nostr identities deterministically.
- Relay persistence: Public geohash events, location notes, and encrypted gift wraps may be retained by relays according to each relay's policy.
- Panic: Triple-tap clears keys, sessions, cached state, and disconnects transports.
Logging and Telemetry
@@ -56,9 +69,11 @@ Residual Risks and Mitigations
- RF fingerprinting: BLE presence is observable at the RF layer; mitigated by minimal announce content and platform MAC randomization.
- Timing correlation: Announce/relay jitter reduces but does not eliminate timing analysis. Avoids synchronized bursts.
- Relay metadata: Nostr relays can see that an account posts gift wraps; content remains end-to-end encrypted. Favor mesh path when in range.
- Geohash inference: Public location-channel tags reveal approximate area. Mitigated by explicit channel selection, low-precision automatic presence, and per-geohash identities.
- Bookmark persistence: Locally stored geohash bookmarks may reveal places of interest on a seized/unlocked device. Mitigated by panic wipe and local-only storage.
Recommendations (Next)
- Add optional coalesced READ behavior for large backlogs.
- Expose a “low-visibility mode” to reduce scanning aggressiveness in sensitive contexts.
- Allow user-configurable Nostr relay set with a “private relays only” toggle.
- Add a user-facing precision warning before posting in block/building-level geohash channels.