Skip to content
liqdmetalPublic

About

Spore — a no-relay, nobody-but-us private messenger. Short whispers ride the tx payload; long bodies are encrypted, held by the sender, and fetched peer-to-peer; then keys rot. Part of the Mycelium stack.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

451 Commits

Folders and files

Repository files navigation

Spore — m³ · Multi-chain Private Messenger

In one line: an E2E-encrypted, forward-private, compostable messenger that rides any of seven chains — you talk wallet-to-wallet, money and message in the same atomic transaction, and everything rots on your schedule. No central server. No VC. No token.

Want to send your first message? → docs/ONBOARDING.md Two commands: spore init then spore msg send-e2 …. (spore demo runs with no chain and no wallet if you just want to see it work.)

Install (checksum-verified, spore + spore-peer, all of linux/macOS/Windows, amd64 + arm64):

curl -fsSL https://raw.githubusercontent.com/liqdmetal/spore/main/scripts/install.sh | sh   # linux/macOS/WSL
irm https://raw.githubusercontent.com/liqdmetal/spore/main/scripts/install.ps1 | iex        # Windows

Then spore demo — the full send → receive → burn lifecycle, no wallet, no setup. Releases also carry SLSA keyless provenance (multiple.intoto.jsonl) verifiable with slsa-verifier.

Releases

Version Date Highlights
v0.8.0 2026-09-27 The EVM carrier readied for the wire: local EIP-155 signing, the loopback spore evm-proxy in front of read-only public RPCs, the per-chain evm_mailbox config seam, and a durable settlement notice outbox pinned by crash-window tests — plus the relay work-order prepare/identity boundary, DEL-escaping canonical JSON, and a reaper-watchdog staleness fix. Pointing the carrier at a real chain moves to v0.9.0.
v0.7.0 2026-09-23 First release shipping the full stack: spore (Go) for all six targets (linux/macOS/Windows × amd64/arm64) plus the Rust spore-peer transport for five of them, per-asset .sha256 checksums, and SLSA keyless provenance for every binary. Installers verify before they swap anything into place.

Pin the install with SPORE_RELEASE=v0.8.0, and verify a downloaded binary the way CI does with slsa-verifier … --source-tag v0.8.0 — full recipe in docs/ONBOARDING.md. One honest caveat: spore-peer for Windows arm64 is not shipped yet (the Rust cross-linker for that target isn't trustworthy); Go spore for arm64 is.


What makes Spore different

Signal Session Telegram+TON Spore
Forward secrecy (Double Ratchet) ✓ ✓ partial ✓
Post-compromise healing ✓ ✓ ✗ ✓
No central server ✗ ✓ (onion) ✗ ✓ (chain + your own node)
Money moves WITH the message, same atomic tx ✗ ✗ custodial bots ✓ native (DERO/EVM)
Messages compost (bodies expire, mailbox burns, local panic-wipe) ✗ ✗ ✗ ✓
Single-use prekeys served without exposing your identity key — — — ✓

Settlement-native, compostable, self-hosted private messaging is an empty category. Spore is the messaging fruiting body on the Relay/Sap settlement rail — money and words become the same atomic object, and both rot.

The mycorrhizal model (m³)

In a forest, trees look separate — underground they are joined by a shared mycorrhizal network exchanging nutrients and warnings. That is Spore:

  • Trees = endpoints. Each an independent wallet + node on its own chain.
  • Spore = the substrate underneath. A no-relay transport letting any tree signal another — quietly, point-to-point.
  • m³ = the network that emerges: trees on different chains, joined through one underground fabric.

Architecture (the honest model)

Spore carries only an opaque 74-byte pointer on-chain. The ratcheted ciphertext, the handshake, and the message body stay off-chain in a TTL-bound store and are reaped after expiry. A permanent chain can't forget a transaction — so Spore never pretends to. What it guarantees:

The message body composts. The permanent carrier retains only an opaque, non-decryptable pointer scrap.

  • X3DH + Double Ratchet (internal/ratchet, internal/ratchetwire): every new conversation is 0xE2, forward-private, post-compromise healing. The legacy 0xE1 envelope, DERO-native whispers, and one-shot long-body path remain compatibility-only and are documented as not forward-private.
  • Off-chain bodies (internal/store): content-addressed, TTL-evicted, crash-safe (the expiry record is written before the body, so a crash can never leave an un-reapable ciphertext).
  • Single-use prekeys (internal/mailbox): GET /prekey pops one pre-signed public bundle per sender — two senders never get the same OPK. The mailbox never touches your identity/SPK private keys; bundles are signed offline (spore prekeybatch).
  • Durable local state: ratchet sessions are endpoint-local, encrypted at rest, anti-rollback (append-only sequence log survives restart), and inactivity-expiring.
  • No downgrade: an unsupported carrier refuses rather than silently falling back to a legacy plaintext-forever path.

Chain / carrier status

Carrier Backend Pointer transport Compost Status
DERO internal/dero native encrypted tx payload carrying opaque E2 pointer body TTL live, mainnet
EVM internal/evm mailbox contract / calldata burn(to,seq) after delivery live-verified (local Anvil); deployment pending
Solana internal/solana inbox PDA (program v2) burn(idx) after delivery live, mainnet; self-messaging verified
Nostr internal/nostr signed event content NIP-09 delete (best-effort) carrier impl
Bitcoin internal/bitcoin OP_RETURN (≤80B) body-only (chain immutable) carrier impl, signer-injected
Cosmos SDK internal/cosmos configurable memo field chain-specific configurable seam
TON internal/ton configurable comment no universal burn configurable seam
Monero (XMR) internal/xmr 8-byte payment id off-chain rendezvous mock-verified; too small for E2 pointer — refused, not downgraded

Full carrier matrix, invariants, and deployment order: docs/CARRIER_MATRIX.md.

Payments (settlement-native)

Money rides the same transaction as the pointer on DERO and EVM-calldata — atomically, trustlessly, no custody. Spore never holds your funds; your wallet signs.

  • spore msg send-e2 -amount 5.5dero … — pay with the message.
  • spore msg invoice -amount 25dero … — request payment in-thread.
  • spore msg pay -invoice <id> … — settle: money + proof ride one atomic tx.

Bitcoin/TON value carriage is refused today (their backends discard the amount hint) rather than silently sending an unpaid message as if paid.

CLI (everything after spore init picks up config defaults)

spore init                     # one-shot onboarding: identity kit + config.json
spore demo                     # see it work — no chain, no wallet

# Forward-private E2 (the real messenger):
spore msg send-e2   -to ADDR (-bundle F | -bundle-url URL) -pinned-sig HEX [-ringsize 8|16] [-amount 5.5dero] [-msg-file F|-]
spore msg recv-e2   [-auto-ack] [-maildb F] [-out-dir D] [-ntfy URL]
spore msg reply-e2  -to ADDR -session HEX      # continue a thread
spore msg forward-e2 -to ADDR -file F …        # new session, same body
spore msg sessions                             # list thread/session ids
spore msg invoice|pay -session HEX -amount N   # in-thread settlement
spore msg compose | flush                      # offline send queue (HMAC-sealed)
spore msg mail add|list|block|threads|search|purge   # local contacts + search

# Prekey discovery (single-use):
spore prekeybatch gen|push|status

# Infra:
spore mailbox host|list|get    # hosted ciphertext/prekey service
spore msg recv-e2               # client-side E2 receive/decrypt
spore relay run                # store-and-forward hop (auth + backoff)
spore status | doctor          # health HUD + preflight

# Serverless (no home node): bodies live on a public Nostr relay commons.
#   -store nostr://relay.damus.io,nos.lol  -store-key ~/.spore/store.key
#   (any E2 command; dedicated key required — see docs/CARRIER_MATRIX.md)

# Compostability as a user feature:
spore panic [-home ~/.spore] [-confirm]   # verifiable local wipe of keys/state/maildb/spool

# Explicit continuity vault (no automatic fund movement):
spore continuity create -owner-key FILE -recipient-pub HEX[,HEX,...] -file PAYLOAD -out VAULT
spore continuity check-in -vault VAULT -owner-key FILE
spore continuity status -vault VAULT [-at UNIX]
spore continuity release -vault VAULT -recipient-key FILE -out PAYLOAD [-at UNIX]
spore continuity verify -vault VAULT
spore continuity watch-init -vault VAULT -observer-key KEY -out WATCH_STATE
spore continuity watch -vault VAULT -observer-key KEY -state WATCH_STATE -notice NOTICE -outbox OUTBOX -webhook URL [-at UNIX] [-flush]
spore continuity recovery-create -vault VAULT [-policy POLICY] [-quorum QUORUM] [-anchor ANCHOR] [-receipt RECEIPT] [-watch WATCH_STATE] [-notice NOTICE] -out BUNDLE
spore continuity recovery-verify -bundle BUNDLE
spore continuity recovery-restore -bundle BUNDLE -dir EMPTY_DIR

# N-of-M independent observer release:
spore continuity quorum-create -vault VAULT -threshold N -attester-pub HEX[,HEX,...] -out POLICY
spore continuity attest -vault VAULT -policy POLICY -observer-key KEY -out ATTESTATION [-at UNIX]
spore continuity quorum -policy POLICY -attestations A1[,A2,...] -out QUORUM
spore continuity verify-quorum -quorum QUORUM [-vault VAULT]
spore continuity release-quorum -vault VAULT -quorum QUORUM -recipient-key KEY -out PAYLOAD [-at UNIX]

# Optional chain commitment (opaque IDs only; posting is explicit):
spore continuity anchor-create -vault VAULT -policy POLICY -out ANCHOR
spore continuity anchor-verify -anchor ANCHOR -vault VAULT -policy POLICY
spore continuity anchor-post -anchor ANCHOR -vault VAULT -policy POLICY -to DERO_ADDR [-rpc URL] [-rpc-user USER] [-ringsize 8|16] [-receipt RECEIPT]  # password is prompted securely
spore continuity anchor-check -receipt RECEIPT -anchor ANCHOR [-rpc URL] [-rpc-user USER]  # wallet-history payload readback

Plaintext is never an argv flag (shell history, ps, and crash reports read argv) — use -msg-file or stdin. Run spore with no args for full usage.

Privacy model (honest limits)

  • Forward-private + compostable on the E2 path; legacy paths are not. DERO E2 posts accept only -ringsize 8 or -ringsize 16, defaulting to 16.
  • No relay: a whisper is a real tx that P2P-fans to the recipient's node.
  • Metadata is visible: "a tx happened at ~time" is chain-wide public. DERO's ring sigs hide the sender; EVM/Solana/Bitcoin/TON expose tx metadata (content stays private via the off-chain ratchet body). ntfy sees "you got a message" + a short txid, never the body.
  • Immutable carriers keep the pointer scrap forever — deleting an off-chain body does not erase the on-chain pointer. No protocol can promise otherwise.
  • Local plaintext: maildb stores decrypted snippets for search (0600, purge-able); the spool stores queued plaintext (0600, HMAC-sealed). panic wipes both.
  • Threat model: docs/SENDER_AUTH.md · wire formats: docs/WIRE_SPEC.md · ratchet: docs/RATCHET.md.

Self-host (the privacy default)

Three deployment postures, from zero infrastructure to fully self-hosted:

Serverless Home node (encouraged) Hosted (Model B)
You run nothing chain node + spore mailbox host (+ optional spore relay run) nothing — you pay the operator
Off-chain bodies nostr:// public relay commons (-store nostr://relay1,relay2) your mailbox over TLS + token the service's mailbox (blind courier)
Prekey discovery manual bundle exchange (-bundle FILE), or your own mailbox your mailbox serves GET /prekey the service's mailbox
Who's in the middle nobody you pay; relays see ciphertext-by-CID nobody the service sees traffic + timing, never content
Trade-off 256 KiB body cap, deletion is best-effort (the ratchet is the real erasure) needs an always-on box you trust the operator with metadata

The serverless posture is the no-servers endgame: point -store at sporepeer:// (the two endpoints run everything — see the store table above) or at nostr:// relays, exchange bundles out-of-band, and no one operates anything for you. Bodies are content-addressed ciphertext on a public commons; deletion is best-effort, so the ratchet's erased keys are what actually makes old messages unreadable — see docs/CARRIER_MATRIX.md for the honest limits.

→ docs/HOME_NODE.md (copy-paste) · docs/MODEL_B_SERVICE.md · docs/MODEL_B_RUNBOOK.md

Build & test

go build ./...   # builds clean
go vet ./...     # clean
go test ./...    # all packages green
go test -race ./internal/ratchetwire ./internal/mailbox ./internal/relay   # race-clean

Go 1.23.1+. No CGO.

One command runs the whole pre-push suite — gofmt/vet/tests, the doc-refs pin checker, and (when a spore-peer checkout is present next to this one) its cargo build/fmt/clippy/test gates plus the -race cross-binary interop run against the freshly built Rust binary:

scripts/gates.sh           # the full suite
scripts/gates.sh --quick   # inner loop: skips the Rust gates and -race/interop

A lefthook pre-push hook runs the full suite automatically on every git push (escape hatches: LEFTHOOK=0 git push … or --no-verify). The global hooks setup is backed up in this repo: scripts/install-global-hooks.sh recreates it on a new machine and self-verifies; scripts/verify-hooks.sh detects drift on any machine against the committed scripts/hooks-manifest.sha256.

Sustainability (FOSS, grassroots — no VC, no token)

Spore is BSD-3 free software. It stays free. The operator (not the protocol) can earn from optional convenience — see docs/BUSINESS.md: hosted Model-B mailboxes, settlement rake on in-chat escrow/swaps (sap/relay-dex), and an optional business tier. None of it is required to use Spore privately and forever-free.

Roadmap

See ROADMAP.md. Shipped recently: E2 (0xE2) forward-private transport, 4 new carriers, pay-with-message + in-thread invoices, local maildb (contacts/threads/search), offline compose queue, single-use prekey batches, one-shot onboarding, panic wipe, multi-device state sync via e2-device, and serverless bodies over spore-peer (sporepeer:// store backend, spore serve daemon, cross-binary Go↔Rust interop tests). Next: tokenized search, in-chat settlement (escrow/swap), and real-chain EVM deployment.

License

BSD 3-Clause. Spore is clean-room Go; it imports no derohe source. derohe-rs (the Rust port used for L1) and spore-peer are separately BSD-3-Clause.

About

Spore — a no-relay, nobody-but-us private messenger. Short whispers ride the tx payload; long bodies are encrypted, held by the sender, and fetched peer-to-peer; then keys rot. Part of the Mycelium stack.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages