Thin client libraries for sending and receiving messages via the Katzenpost mix network.
This repository contains the Rust and
Python thin client libraries for
Katzenpost, together with
pigeonhole-cp, a small command-line utility for sending and
receiving files over Pigeonhole channels.
A mix network is a type of anonymous communications network. The
Katzenpost stack is split between a local daemon, kpclientd, and
the application that uses it. The daemon performs all cryptographic
and network operations: PQ Noise transport, Sphinx packet
construction, courier discovery, and ARQ retransmission. A thin
client is the small library on the application side: it speaks a
CBOR-framed protocol over a local socket to the daemon, and exposes
a friendly API in its host language. Several applications on the
same device may share a single daemon concurrently by way of their
respective thin clients.
The reference Go implementation lives in
katzenpost/client/thin
within the Katzenpost monorepo. The Rust and Python ports are
maintained here.
Beyond simple request-response services, Katzenpost provides a storage layer called Pigeonhole. Applications communicate through encrypted, append-only streams composed of fixed-size, padded Boxes, which are sharded across storage replicas via consistent hashing (two replicas per Box). Access is governed by cryptographic capabilities: a write capability can append messages or place tombstones, whilst a separate read capability decrypts and verifies without conferring any ability to write. Streams are single-writer and multi-reader, and unlinkable in the sense that storage servers cannot tell which messages belong to the same stream. Storage is ephemeral: Boxes are garbage-collected after roughly two weeks, so Pigeonhole is not intended for long-term archival storage.
Clients never speak to replicas directly. Each Pigeonhole operation is carried as a Sphinx round-trip through the mix layers to a courier service, which then forwards the request to the appropriate replicas on fixed-throughput connections so that traffic patterns reveal nothing to an outside observer. Many higher-level protocols (group chat, file transfer, request-response services) compose readily on top of these streams by sharing read capabilities out-of-band.
For a developer-oriented introduction see Understanding Pigeonhole. For the wire-level details see the Pigeonhole specification and §§4-5 of the Echomix paper.
- Project website
- Thin Client How-to Guide, task-oriented examples in Go, Rust, and Python.
- Thin Client API Reference, the unified API reference for all three languages.
- Build from source, the canonical record of pinned versions for the whole stack.
- Docker test network, instructions for running a local mixnet for development.
- Python thin client, distributed via PyPI as
katzenpost_thinclient. - Rust thin client, distributed via crates.io as
katzenpost_thin_client.
pigeonhole-cp is a small command-line utility, written in Rust,
for sending and receiving files to and from Pigeonhole channels.
It is a thin wrapper over the persistent Pigeonhole API and serves
both as a utility in its own right and as a worked example for
application authors. Build it with the cli feature:
cargo build --release --features cli --bin pigeonhole-cpThe source lives at src/bin/pigeonhole_cp.rs.
thin_client/
├── src/ Rust thin client (crates.io: katzenpost_thin_client)
│ ├── lib.rs Crate root; re-exports the public API.
│ ├── core.rs ThinClient struct: connection, events, message send.
│ ├── pigeonhole.rs Low-level Pigeonhole API (manual cap and index handling).
│ ├── persistent/ High-level Pigeonhole API with SQLite-backed state.
│ │ ├── mod.rs PigeonholeClient and ChannelHandle.
│ │ ├── channel.rs Channel state machine and box send/receive.
│ │ ├── db.rs SQLite persistence for caps, indices, and messages.
│ │ ├── models.rs Channel, capability, and message records.
│ │ └── error.rs Errors specific to the persistent layer.
│ ├── transport/ Pluggable daemon transports.
│ │ ├── mod.rs Dialer trait and DialConfig discriminated union.
│ │ ├── unix.rs Abstract Unix domain socket transport.
│ │ └── tcp.rs TCP transport (used by the docker mixnet).
│ ├── helpers.rs PKI document utilities (find_services, pretty print).
│ ├── error.rs Error types and error code translation.
│ └── bin/
│ └── pigeonhole_cp.rs pigeonhole-cp file send/receive utility.
├── katzenpost_thinclient/ Python thin client (PyPI: katzenpost_thinclient)
│ ├── __init__.py Public API and module docstring.
│ ├── core.py ThinClient and Config; replica error types.
│ ├── pigeonhole.py Capability-based Pigeonhole API.
│ └── transport/ Daemon transports (TCP and Unix).
├── tests/ Integration tests (Rust and Python).
│ ├── conftest.py Pytest fixtures; expects the daemon on 127.0.0.1:64331.
│ ├── high_level_api_test.rs Persistent Pigeonhole API tests.
│ ├── channel_api_test.rs Channel API tests.
│ ├── smoke_pigeonhole_cp.rs pigeonhole-cp smoke test.
│ └── test_*.py Python integration tests.
├── testdata/
│ └── thinclient.toml Fixture config (TCP dial, Sphinx and Pigeonhole geometry).
├── Cargo.toml Rust crate manifest.
├── pyproject.toml Python package manifest.
├── requirements.txt Python runtime dependencies.
├── pydoc-markdown.yml Pydoc generation config for the Python API reference.
├── README.md This file (rendered on GitHub).
├── README_python.md Bundled with the PyPI package.
└── README_rust.md Bundled with the crates.io package.
Both libraries track the Katzenpost stack at the tag listed in
Build from source;
that page is the canonical record of pinned versions for kpclientd,
the Go reference thin client, the Rust and Python thin clients, and
katzenqt. The reference daemon is built from the
katzenpost monorepo at
that same tag.
Pull requests are welcome at https://github.com/katzenpost/thin_client. The CI pipeline runs the integration suite against a docker mixnet pinned to a specific commit of the katzenpost monorepo; protocol-level changes should be coordinated with that pin in mind.
AGPLv3.