Reed: anonymous, end-to-end encrypted messaging over relays, radio and mesh. One Rust core for Android, web and iOS. Unaudited pre-release.
  • Rust 58.9%
  • Kotlin 17.1%
  • TypeScript 6.5%
  • Shell 6.4%
  • Swift 5.9%
  • Other 5.1%
Find a file
2026-09-08 19:33:53 +02:00
.cargo cargo: cap build jobs at 6 on the shared Mac 2026-09-06 00:56:20 +02:00
.forgejo/workflows WP-M2-16 assurance (Fable): ProVerif models with expected verdicts and the proofs gate, fuzz targets for every M2 decoder with fuzz-ci, dudect bench, Kani harnesses, Miri script, wasm-surface baseline, AUDIT-RFP, KNOWN-ISSUES, TESTING; verified by lead 2026-09-06 19:43:56 +02:00
apps FIX-SWIFT-PAIRING: a pending acceptance re-fetches its invitation blob (2 s doubling to the fetch interval, wall clock with a tick floor) and arms the Retry wake for it; an invitee whose FETCH raced the inviter's POST at the relay was stuck until the invitation expired, with no error and no retry. Found through ReedKit's relay-pairing tests, which accept in the same millisecond as the POST 2026-09-08 07:26:39 +02:00
bindings FIX-EMU-FOLLOWUP: Command::SetLinkPsm carries the BLE acceptor's L2CAP PSM to the core (HELLO_ACK field, CoC upgrade asserted by the emulated BLE leg), the CLI's direct-peer probe leaves the link driver's socket namespace (lan.sh step 8 over the link with the relay stopped), lora.sh step 7 drives the debug companion hook against the MeshCore and Meshtastic firmware, and the narrow path posts the frames Narrow::schedule returns (they were dropped since WP-M2-22) 2026-09-08 03:10:21 +02:00
build-status build-status: bench passes 2 and 3 provenance, TODO rows 42 and 43, REPORT-M2 section 7 rows and the real-device paragraph, lead notes on the relay's per-address cap 2026-09-08 19:33:53 +02:00
core FIX-SWIFT-PAIRING: a pending acceptance re-fetches its invitation blob (2 s doubling to the fetch interval, wall clock with a tick floor) and arms the Retry wake for it; an invitee whose FETCH raced the inviter's POST at the relay was stuck until the invitation expired, with no error and no retry. Found through ReedKit's relay-pairing tests, which accept in the same millisecond as the POST 2026-09-08 07:26:39 +02:00
design build-status: bench passes 2 and 3 provenance, TODO rows 42 and 43, REPORT-M2 section 7 rows and the real-device paragraph, lead notes on the relay's per-address cap 2026-09-08 19:33:53 +02:00
docs build-status: bench passes 2 and 3 provenance, TODO rows 42 and 43, REPORT-M2 section 7 rows and the real-device paragraph, lead notes on the relay's per-address cap 2026-09-08 19:33:53 +02:00
fuzz FIX-CORE-M2B: SimpleX link host grammar with a parse/render round-trip invariant (smp_link fuzz finding), link driver test pins PING and a cell due on the same tick (the receipt loss was the core test harness dropping SendBytes), interop scripts for SimpleX, Nostr and chatmail run under bash and zsh 2026-09-07 22:30:01 +02:00
host WP-M2-07 Chatmail family (Fable): Family facade over a pipe, embedded deltachat engine with its own lockfile (ADR-50), host binary and Android cdylib, :interop bridge and chatmail screens, harness with an online relay leg; verified by lead 2026-09-06 17:03:43 +02:00
proofs FIX-OPK-COLLISION: two acceptors of one reusable address no longer lose a contact when they select the same one-time prekey; the initiator retries with a fresh InitCell and an untried prekey, then the DH4-less path (PROTOCOL.md 2.3 client rule, no wire change); the one-time prekey index derives from EK_A 2026-09-07 22:34:53 +02:00
research M2 research: brand pass (Fable); all eleven M2 research briefs complete, all pure Fable 2026-09-05 20:43:38 +02:00
services/reed-relay WP-M2-22 closing wiring behind the frozen accessors: session keeps SK, ncap plumbing, links and narrow seeded from the pair key, relay pool, prekeys and device revocation on the CLI, relay registration log and scripted clock, Android chatmail persistence through the core, iOS Keep; cli-lan step 5, cli-onion 8c and 8d, push through Core; deny.toml allows NCSA for the fuzz-only libfuzzer-sys 2026-09-07 21:06:03 +02:00
tests FIX-DEVICE-BENCH-2 and FIX-DEVICE-BENCH-3: the real-device bench on a phone. The runner provides the APK to every leg, sets the phone's relay to the adb-reversed loopback through Settings (the debug default is the emulator's host alias), waits for a device that drops off USB, holds one lock (the nested lockf stalled the Tor leg); the shell leg clears and reads back the relay field, scrolls from a neutral point, keeps its screenshots; the Tor leg reaches the switch and names the node it misses; the push leg reads the phone's relay before it asks for an endpoint; ui.py gains set-text, clear-field and a neutral scroll point with unit tests 2026-09-08 19:33:52 +02:00
tools FIX-EMU-FOLLOWUP: Command::SetLinkPsm carries the BLE acceptor's L2CAP PSM to the core (HELLO_ACK field, CoC upgrade asserted by the emulated BLE leg), the CLI's direct-peer probe leaves the link driver's socket namespace (lan.sh step 8 over the link with the relay stopped), lora.sh step 7 drives the debug companion hook against the MeshCore and Meshtastic firmware, and the narrow path posts the frames Narrow::schedule returns (they were dropped since WP-M2-22) 2026-09-08 03:10:21 +02:00
vectors WP-M2-17 conformance and vectors (Fable, the WP-16 re-author): six new vector families (120 cases, 36 rejections), M1 hash list, Node, Kotlin and Swift runners, reed-conformance rewritten; verified by lead 2026-09-06 18:25:38 +02:00
.gitignore gitignore: the bench runner's tests/device/out/ directory 2026-09-08 06:42:03 +02:00
.gitlab-ci.yml WP-M2-15 release engineering (Fable, the WP-15 re-author): Forgejo and GitLab pipelines, toolchain image recipe, vendor and reproduce, signing and cosign flow, WEBCAT manifest, SBOMs and audit, F-Droid recipe, RELEASE.md and STORE.md, xtask check with 22 steps; verified by lead (PARTIAL by design of this Mac) 2026-09-06 19:21:26 +02:00
Cargo.lock WP-M2-20 integration and M2 demo (Fable), with FIX-LORA-COPY and FIX-WEB-ROUTE-SPECS: Core drives families, links, push wake and Tor mode; store format version with Reset and Keep on every surface (ADR-51); bearer copy on the three shells; xtask check with freshness, fmt and copy gates; fuzz wrappers on reed_property::targets; wasm round-trip kinds; demo --m2 and --show; REPORT-M2, RUNBOOK-M2, KNOWN-ISSUES; verified by lead 2026-09-07 14:04:38 +02:00
Cargo.toml M2 wave 0 (Fable): interface freeze, new crate and module stubs, INTERNAL-M2, registries, UI-COPY 2.0 seed, xtask dispatch; deny.toml lead decisions 2026-09-06 05:24:46 +02:00
deny.toml WP-M2-22 closing wiring behind the frozen accessors: session keeps SK, ncap plumbing, links and narrow seeded from the pair key, relay pool, prekeys and device revocation on the CLI, relay registration log and scripted clock, Android chatmail persistence through the core, iOS Keep; cli-lan step 5, cli-onion 8c and 8d, push through Core; deny.toml allows NCSA for the fuzz-only libfuzzer-sys 2026-09-07 21:06:03 +02:00
HANDOFF.md HANDOFF: name confirmed (Reed), M2 start; provenance of the M2 research wave 2026-09-05 20:44:14 +02:00
LICENSE WP-00: interface freeze, workspace skeleton, reed-api and reed-proto (Fable); wave-0 gate verified 2026-09-05 05:10:43 +02:00
README.md WP-M2-19 documentation, copy, website, brand record (Fable): UI-COPY 2.x with the M2 namespaces, string tables regenerated on three surfaces, copy checker with bearer-map and Disabled-reason rules, RUNBOOK-M2 skeleton, README and SECURITY, site pages; verified by lead 2026-09-06 19:13:35 +02:00
rust-toolchain.toml WP-00: interface freeze, workspace skeleton, reed-api and reed-proto (Fable); wave-0 gate verified 2026-09-05 05:10:43 +02:00
SECURITY.md WP-M2-19 documentation, copy, website, brand record (Fable): UI-COPY 2.x with the M2 namespaces, string tables regenerated on three surfaces, copy checker with bearer-map and Disabled-reason rules, RUNBOOK-M2 skeleton, README and SECURITY, site pages; verified by lead 2026-09-06 19:13:35 +02:00

Reed

Reed is a messenger with no phone number, email or account. Messages are end-to-end encrypted with forward secrecy and travel as fixed-size cells through relays that store ciphertext they cannot read, over Tor when the user turns it on, directly between two nearby phones over Wi-Fi or Bluetooth, through a LoRa companion radio, and to people on other networks (Briar, SimpleX, Nostr, Delta Chat, Meshtastic, MeshCore) with those networks' own encryption. One Rust core runs on Android, in the browser as an installable web app, on iOS and on the command line.

Reed is an unaudited pre-release. Do not rely on it if your safety depends on it.

Historical codename: sotto (the repository directory keeps that name; nothing else does). Store display name: Reed Messenger (docs/DECISIONS.md ADR-47).

What this repository contains

Path Content
core/ The sans-IO Rust core: reed-api (shared types), reed-proto (byte layouts), reed-crypto (primitive facade), reed-session (first contact, Double Ratchet, period layer, prekeys), reed-store and reed-store-sqlite (encrypted records), reed-bearer (relay driver, link driver, socket pool, simulators), reed-bearer-lora (Meshtastic and MeshCore companions, band check, narrow codec), reed-core (the state machine: sockets, links, narrow, groups, MLS adapter, notify, families), reed-interop, reed-bramble (Briar), reed-simplex, reed-nostr, reed-mesh-client
host/ Host-side crates that need an OS: reed-tor (arti client leg, onion hosting), reed-smptls (SimpleX transport), reed-chatmail (the Delta Chat engine behind a pipe, its own lockfile per ADR-50)
services/reed-relay/ The blind mailbox relay: binary, library, group-log and notifier roles, deployment files, operator README
bindings/ reed-ffi (UniFFI, Kotlin and Swift; the network host object) and reed-wasm (wasm-bindgen)
apps/android/ The Android app (Jetpack Compose, applicationId fr.ekaii.reed, flavours foss and play)
apps/web/ The web client (Svelte 5, Vite 8, a Web Worker owns the core, Web Push)
apps/ios/ ReedKit (Swift package over the UniFFI XCFramework) and the SwiftUI app with its notification service extension
apps/site/ The static website
tools/ reed-cli (headless client and integration gate), xtask (build and check tasks), release/ (toolchain container, reproduce, sign, publish, F-Droid), oracles/ (the real Briar, SimpleX, Nostr, Meshtastic and MeshCore software the interop tests run against)
tests/ End-to-end scripts (cli-e2e.sh, cli-onion.sh, cli-lan.sh, cli-group.sh), the demo runner, interop and simulator harnesses, device scripts, the independent ratchet reference, conformance, property, constant-time and Kani tests
proofs/, fuzz/ ProVerif models with their expected verdicts; cargo-fuzz targets on the pinned nightly
vectors/ Frozen test vectors, M1 and the 1.3 families
docs/ Architecture (M1 and the M2 addendum), protocol (1.3, plus the Bramble and SimpleX transcriptions), threat model, decisions, roadmap, build plans, UI copy, runbooks, release and store procedures, toolchain, review packet
design/, research/ Frozen inputs from the research and design phases, including the M2 research reports under research/m2/

Documents

Read in this order: docs/ARCHITECTURE.md and docs/ARCHITECTURE-M2.md (shape, crates, hosts, build commands), docs/PROTOCOL.md (the byte-level contract, version 1.3), docs/THREAT-MODEL.md (assets, adversaries, ceilings per bearer and per foreign network, the claims policy in section 10), docs/DECISIONS.md (ADRs), docs/ROADMAP.md (M1 to M4), docs/BUILD-PLAN-M2.md (work packages), docs/TOOLCHAIN.md (verified local build facts), docs/UI-COPY.md (every user-facing security sentence), docs/RUNBOOK-M2.md (the demo, step by step), docs/RELEASE.md and docs/STORE.md (releases and store submissions), SECURITY.md (reporting, disclosure, the legal record).

Build quickstart (M2)

Verified on macOS with Rust 1.97.1 (the pinned toolchain, the only one with the iOS targets), JDK 21, Gradle 9.6.0 (wrapper), Node 24.14 and pnpm 11.5, Xcode with the iOS 26.5 simulators. Details and the reasons behind each pin are in docs/TOOLCHAIN.md; the full command table is docs/ARCHITECTURE-M2.md section 12 (additions to docs/ARCHITECTURE.md section 10). Always build from the repository so the pinned toolchain is used; nightly (nightly-2026-08-25) only inside fuzz/ and for Miri.

Environment for every shell:

export ANDROID_HOME=/opt/homebrew/share/android-commandlinetools
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/27.2.12479018
export JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home
export CARGO_TARGET_DIR=/tmp/reed-target/local    # any directory; scripts never assume target/
export IPHONEOS_DEPLOYMENT_TARGET=17.0 MACOSX_DEPLOYMENT_TARGET=14.0   # iOS builds

Core, tests and checks on the host:

cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo deny check                       # licences, bans, advisories, sources (deny.toml is frozen, ADR-18, ADR-40)
cargo xtask vectors --check            # vectors/*.json unchanged
cargo xtask copy                       # every governed sentence on Android, web, site and iOS comes from docs/UI-COPY.md;
                                       # one transport.name id per bearer kind; Disabled reasons resolved (UI-COPY.md section 5);
                                       # the family fixture holds
cargo xtask copy --self-test           # the fixture under docs/ui-copy-fixture/ fails exactly as listed
cargo xtask check                      # the whole local CI equivalent

Web core must stay pure Rust (no C toolchain variables, no ring, no rusqlite, and none of the host crates):

cargo build -p reed-core -p reed-nostr --target wasm32-unknown-unknown
cargo tree -p reed-core --target wasm32-unknown-unknown -e normal | grep -c -E 'rusqlite|ring v|cc v|tokio|arti|rustls|deltachat'   # prints 0

Tor host, relay and the command-line gates:

cargo build -p reed-tor --release
cargo build --release -p reed-relay -p reed-cli
tests/e2e/cli-e2e.sh                   # the M1 gate: two CLIs through the real relay
tests/e2e/cli-onion.sh                 # relay on loopback, local tor hosting the onion, two `reed-cli --tor`
tests/e2e/cli-lan.sh                   # two CLIs over lan+tcp with mDNS
tests/e2e/cli-group.sh                 # eight CLIs: create, add, remove, rotate, late fetch

Interop against the real oracles (tools/oracles; each script says what it needs and skips what is absent):

tests/interop/briar/run.sh             # briar-headless 1.5.19 over Tor
tests/interop/simplex/run.sh           # smp-server, xftp-server (Docker) and the SimpleX CLI 7.1.0.4
tests/interop/nostr/run.sh             # nostr-rs-relay with NIP-42
tests/interop/chatmail/run.sh          # the deltachat test context; ONLINE=1 for a live chatmail relay
tests/interop/mesh/run.sh              # meshtasticd --sim 2.7.26 and the MeshCore simulator
tests/sim/lora/meshtastic.sh; tests/sim/lora/meshcore.sh     # the LoRa bearer on the firmware simulators

Android native library, Kotlin bindings and APKs (two flavours; the emulator is a singleton under lockf, the Pixel 9a is reached with adb -s 53261JEBF04604):

cargo xtask android --abis arm64-v8a,armeabi-v7a,x86_64          # debug; --release-repro for the release build
cd apps/android && ./gradlew assembleFossDebug assemblePlayDebug testFossDebugUnitTest

iOS (unsigned, simulator):

cargo xtask ios                                    # three static archives, Swift bindings, apps/ios/ReedKit/ReedFFI.xcframework
cd apps/ios/ReedKit && swift test
cd apps/ios/Reed && xcodegen generate && xcodebuild test -project Reed.xcodeproj -scheme Reed \
  -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.5' CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO

Web client and website:

cargo xtask wasm                                       # release wasm build, wasm-bindgen 0.2.127, integrity hash
cd apps/web  && pnpm install --frozen-lockfile && pnpm build && pnpm preview --port 4173 --strictPort   # REED_CSP_DEV=0 for the production CSP
cd apps/site && pnpm install --frozen-lockfile && pnpm build && pnpm test:e2e && pnpm preview --port 4174 --strictPort

Assurance:

proofs/install-proverif.sh && cargo xtask proofs      # every ProVerif model against proofs/proverif/expected.txt
cargo xtask fuzz-ci --minutes 10                       # seeded fuzz run of every target
cargo run --release -p reed-ct-bench                   # dudect timing classes
MIRIFLAGS=-Zmiri-disable-isolation cargo +nightly-2026-08-25 miri test -p reed-proto -p reed-crypto -p reed-session
cargo xtask sbom

Release (Mac, owner present; keys come only from the vault, never from CI): tools/release/reproduce.sh vX.Y.Z, then tools/release/sign.sh, then tools/release/publish.sh; tools/release/fdroid-rebuild.sh verifies from outside. Procedure and rules in docs/RELEASE.md.

Demo: tests/demo/run.sh --m2 --pixel 53261JEBF04604 --ios 'iPhone 17' --tor --lan --ble --pcap (described in docs/RUNBOOK-M2.md; a device that is absent marks its legs SKIPPED with the reason, never FAIL).

Status

Milestone M2 (docs/ROADMAP.md 2.0): the M1 relay exchange between Android, browser, iOS simulator and command-line clients, plus the Tor client leg and onion mirror, Wi-Fi and Bluetooth links between two Android phones, LoRa through Meshtastic and MeshCore companions on the firmware simulators (untested on hardware), groups of up to 64 members, content-free wake-ups (UnifiedPush, Web Push, FCM, APNs), rotating prekeys and device lists, and conversations with Briar, SimpleX, Nostr, Delta Chat, Meshtastic and MeshCore users through their own protocols, tested against the real software. Reproducible builds, three signature systems and an F-Droid recipe are in place; no release has been published yet. Attachments, disappearing messages, multi-device linking, the File bearer and XMPP or Matrix are M3 (ADR-49).

Security

Vulnerability reports, the disclosure policy, the audit status, the abuse address and the export-control record are in SECURITY.md. The protected and unprotected properties per bearer are in docs/THREAT-MODEL.md section 4, per foreign network in 4.7; what the UI may claim is section 10 of the same document, and docs/UI-COPY.md holds every sentence.

Licence

Code (core crates, host crates, bindings, relay, apps, tools, tests) is licensed under the Mozilla Public License 2.0 (LICENSE). Documentation under docs/ is licensed under CC BY 4.0. Third-party dependencies are limited by deny.toml (docs/DECISIONS.md ADR-18, ADR-40); the embedded Delta Chat engine has its own tree and lockfile (ADR-50). Briar and SimpleX are implemented from their specifications; no GPL or AGPL code is linked, copied or translated.