# Katzenpost thin client libraries
*Thin client libraries for sending and receiving messages via the
Katzenpost mix network.*
This repository contains the [Rust](README_rust.md) and
[Python](README_python.md) thin client libraries for
[Katzenpost](https://katzenpost.network/), together with
`pigeonhole-cp`, a small command-line utility for sending and
receiving files over Pigeonhole channels.
## What is a thin client?
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`](https://github.com/katzenpost/katzenpost/tree/main/client/thin)
within the Katzenpost monorepo. The Rust and Python ports are
maintained here.
## Pigeonhole, in brief
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](https://katzenpost.network/docs/pigeonhole_explained/).
For the wire-level details see the
[Pigeonhole specification](https://katzenpost.network/docs/specs/pigeonhole/)
and §§4-5 of the [Echomix paper](https://arxiv.org/abs/2501.02933).
## Documentation
- [Project website](https://katzenpost.network/)
- [Thin Client How-to Guide](https://katzenpost.network/docs/thin_client_howto/), task-oriented examples in Go, Rust, and Python.
- [Thin Client API Reference](https://katzenpost.network/docs/thin_client_api_reference/), the unified API reference for all three languages.
- [Build from source](https://katzenpost.network/docs/build_from_source/), the canonical record of pinned versions for the whole stack.
- [Docker test network](https://katzenpost.network/docs/admin_guide/docker.html), instructions for running a local mixnet for development.
## Per-language READMEs
- [Python thin client](README_python.md), distributed via PyPI as [`katzenpost_thinclient`](https://pypi.org/project/katzenpost_thinclient/).
- [Rust thin client](README_rust.md), distributed via crates.io as [`katzenpost_thin_client`](https://crates.io/crates/katzenpost_thin_client).
## pigeonhole-cp
`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:
```bash
cargo build --release --features cli --bin pigeonhole-cp
```
The source lives at [`src/bin/pigeonhole_cp.rs`](src/bin/pigeonhole_cp.rs).
## Directory layout
```
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.
```
## Compatibility
Both libraries track the Katzenpost stack at the tag listed in
[Build from source](https://katzenpost.network/docs/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](https://github.com/katzenpost/katzenpost) at
that same tag.
## Contributions
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](https://github.com/katzenpost/katzenpost);
protocol-level changes should be coordinated with that pin in mind.
## License
AGPLv3.