Decentralized, end-to-end encrypted messaging with no accounts and no home servers. Identity is an Ed25519 keypair; messages route over plain HTTP through any relay in an open federated mesh. A relay only ever sees the recipient's public key and an opaque blob — the sender's identity and signature live inside the AEAD ciphertext, so a server never learns who sent a message.
See PROTOCOL.md for the full specification.
| Path | What it is |
|---|---|
core/ |
The shared core (Rust, Crux). All business logic: identity, crypto, auth, the long-poll loop, the outbox, contacts, profiles, message ingest. |
apple/ |
The iOS client (Swift + SwiftUI, iOS 17+). A thin shell: it executes HTTP/key-value/timer effects and renders the view model. No business logic. |
server.knot |
The relay server, written in Knot and compiled to a native binary. |
servers.json |
A public relay list. A static suggestion, not a directory. |
Crypto is X25519 + XChaCha20-Poly1305 with HKDF-SHA256, signed with Ed25519 — see core/src/crypto.rs, which is written to be auditable against the spec.
One-time setup:
rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios
cargo install boltffi_cli
brew install xcodegenThen (just alone runs test):
just test # run the core test suite
just generate # regenerate Swift types, xcframework, and the Xcode project
just build SIM_ID=<udid> # build for a booted simulator
just run SIM_ID=<udid> # install + launch on that simulatorRun just generate after any change to the core's Event, ViewModel, or Effect types — otherwise the Swift side compiles against stale generated types.
To install one on a Linux host, with a systemd service and Caddy as a reverse proxy with automatic TLS:
curl -fsSL https://raw.githubusercontent.com/ilyakooo0/skrepka/master/install.sh | sudo DOMAIN=skrepka.example.com shRe-running the same command updates the binary and restarts the service.
Every top-level constant in server.knot is overridable at startup as --name=value (--serverHost=, --federationEnabled=False, --trustForwardedFor=False, …); run the binary with --help for the full list. --serverHost must be the public hostname clients use to reach the relay: it is the federation identity, and clients bind their auth signature to it.
To run a relay locally you need a prebuilt ./server binary (knot build server.knot, or grab a release asset); then just server resets the disposable database and starts it.