trueseal
End-to-end encrypted sync for Swift, Kotlin and TypeScript apps, with a relay you run yourself.
- status
- Heading to the 0.6.0 developer preview
- core
- Rust, with Swift and Kotlin bindings via UniFFI
- typescript
- Node SDK via napi-rs (no browser yet)
- relay
- Go, one container, self-hosted
- transport
- Noise XX and NK over TCP
- license
- Apache-2.0
trueseal is the private sync layer an app builds on: pairing, keys, the offline outbox and delivery are already in there, so you get end-to-end encrypted sync across devices in about ten lines. There are no accounts. Your devices talk through a relay you run yourself, and the relay stores and forwards blobs it has no keys to read.
It started because I wanted a clipboard with history (that's hush-clip now), and it grew out of the sync layer inside hush. This is the project I spend most of my time on.
The Rust core is at v0.5.0 and the next release is the 0.6.0 developer preview. Nothing is on npm or Maven yet, and 0.x can still break things between releases. The threat model, the limitations and everything else live in the docs, so this page stays short.
# Decisions
Each of these has an ADR in the repos.
A delivery primitive with no conflict resolution
sync ADR-0003- chose
- trueseal delivers messages. The app owns its data model, its schema and what happens when two devices disagree, which is the same contract TCP has with its callers.
- rejected
- Resolving conflicts inside trueseal.
- cost
- Every app writes its own conflict policy. hush-clip does last-writer-wins.
Delete only after the device says it has it
relay ADR-0009- chose
- Blobs stay on the relay until the recipient sends DeliverAck.
- rejected
- Treating a successful TCP write as delivered. That only means the bytes left the relay's buffer.
- cost
- A breaking wire change, and clients have to deduplicate re-deliveries.
Rust for the client, Go for the relay
sync ADR-0008- chose
- A Rust core with UniFFI bindings for Swift and Kotlin. The relay stays in Go.
- rejected
- Go everywhere. Except it can't ship as a library inside an iOS app.
- cost
- Noise now exists twice, in Go and Rust, checked against the same official test vectors. Also the borrow checker.