A client library for accessing reeeductio Spaces API
Project description
reeeductio Python SDK
A clean, modern Python SDK for the reeeductio Spaces API - an end-to-end encrypted messaging system with capability-based authorization.
Features
- End-to-end encryption: Zero-knowledge server design
- Blockchain-like message chains: Cryptographic integrity verification
- Capability-based authorization: Granular, signed permissions
- Multiple storage types:
- Messages: Append-only topic streams
- State: Event-sourced key-value store
- Data: Simple signed key-value store
- Blobs: Content-addressed binary storage
- Real-time streaming: WebSocket support (coming soon)
- Async support: Built on httpx for both sync and async usage
- Type-safe: Full type hints and dataclass models
Installation
pip install reeeductio
Or install from source:
cd python-sdk
pip install -e .
Quick Start
from reeeductio import Space, generate_keypair
import os
# Generate a key pair
keypair = generate_keypair()
member_id = keypair.to_user_id() # 44-char typed user identifier starting with 'U'
# Generate or retrieve the space's symmetric root key (32 bytes)
symmetric_root = os.urandom(32) # In practice, derive from space key or shared secret
# Connect to a space
# The Space client automatically derives encryption keys on init:
# - message_key (for encrypting messages)
# - state_key (for encrypting state)
# - data_key (for encrypting KV data)
with Space(
space_id="Sabc123...", # 44-char space ID
member_id=member_id, # typed user/tool identifier
private_key=keypair.private_key, # raw 32-byte Ed25519 private key
symmetric_root=symmetric_root, # 256-bit root key for encryption
base_url="http://localhost:8000"
) as space:
# Keys are available as space.message_key, space.state_key, space.data_key
# Post a message
result = space.post_message(
topic_id="general",
msg_type="chat",
data=b"Hello, world!" # Should be encrypted before passing
)
print(f"Posted message: {result.message_hash}")
# Get messages
messages = space.get_messages("general", limit=10)
for msg in messages:
print(f"{msg.sender}: {msg.data}")
# Upload an encrypted blob
blob = space.encrypt_and_upload_blob(b"file contents")
print(f"Uploaded blob: {blob.blob_id}")
# Set state
space.set_state("profiles/alice", b'{"name": "Alice"}')
# Get state
state_msg = space.get_state("profiles/alice")
print(f"State: {state_msg.data}")
Architecture
Components
- Space: High-level client for interacting with a space
- Topics: Blockchain-style append-only message streams
- State: Event-sourced key-value store (stored as messages in the special
statetopic) - Data: Simple signed key-value store
- Blobs: Content-addressed encrypted file storage
- Auth: Challenge-response authentication with Ed25519 signatures
Cryptography
All identifiers use typed base64 encoding with a header byte:
- User IDs start with
U(e.g.,Uabc123...) - Space IDs start with
S(e.g.,Sabc123...) - Message IDs start with
M(e.g.,Mabc123...) - Blob IDs start with
B(e.g.,Babc123...) - Tool IDs start with
T(e.g.,Tabc123...)
Message Chains
Messages form blockchain-like chains with hash pointers:
Message 1 → Message 2 → Message 3
(M_abc) (M_def) (M_ghi)
↑ ↑
prev_hash prev_hash
Each message hash is computed over: topic_id|type|prev_hash|data|sender
Key Derivation
The Space client uses HKDF-SHA256 to derive encryption keys from the symmetric_root:
space = Space(space_id, keypair, symmetric_root)
# Automatically derived on initialization (scoped to space_id):
space.message_key # HKDF(symmetric_root, info="message key | {space_id}") → 32 bytes
space.data_key # HKDF(symmetric_root, info="data key | {space_id}") → 32 bytes
space.state_key # HKDF(message_key, info="topic key | state") → 32 bytes
Security Benefits:
- Single shared secret (
symmetric_root) per space - Cryptographically independent keys for each data type
- Domain separation: Keys are scoped to
space_idto prevent cross-space key reuse - Deterministic: same root + same space always produces same keys
- Forward-compatible for key rotation
Usage:
from reeeductio import derive_key
# Manual key derivation if needed
custom_key = derive_key(symmetric_root, "custom context", length=32)
API Reference
Space Client
class Space:
def __init__(
self,
space_id: str,
member_id: str, # typed user/tool identifier (e.g. keypair.to_user_id())
private_key: bytes, # raw 32-byte Ed25519 private key
symmetric_root: bytes, # 256-bit (32-byte) root key for HKDF
base_url: str = "http://localhost:8000",
auto_authenticate: bool = True,
local_store: LocalMessageStore | None = None,
user_symmetric_key: bytes | None = None, # optional user-private key
)
# Authentication
def authenticate(self) -> str
# Messages
def post_message(self, topic_id: str, msg_type: str, data: bytes, prev_hash: str | None = None) -> MessageCreated
def get_messages(self, topic_id: str, from_timestamp: int | None = None, to_timestamp: int | None = None, limit: int = 100, use_cache: bool = True, validate_chain: bool = True) -> list[Message]
def get_message(self, topic_id: str, message_hash: str, use_cache: bool = True) -> Message
# State
def get_state(self, path: str) -> Message
def set_state(self, path: str, data: bytes, prev_hash: str | None = None) -> MessageCreated
def get_state_history(self, from_timestamp: int | None = None, to_timestamp: int | None = None, limit: int = 100) -> list[Message]
# Data (KV)
def get_data(self, path: str) -> DataEntry
def set_data(self, path: str, data: bytes) -> int
# Blobs
def upload_plaintext_blob(self, data: bytes) -> BlobCreated
def encrypt_and_upload_blob(self, data: bytes) -> EncryptedBlobCreated
def download_plaintext_blob(self, blob_id: str) -> bytes
def download_and_decrypt_blob(self, blob_id: str, key: bytes) -> bytes
def delete_blob(self, blob_id: str) -> None
Crypto Utilities
from reeeductio import generate_keypair, sign_data, compute_hash
# Generate keys
keypair = generate_keypair()
user_id = keypair.to_user_id()
space_id = keypair.to_space_id()
# Sign data
signature = sign_data(b"data to sign", keypair.private_key)
# Hash data
hash_bytes = compute_hash(b"data to hash")
Development Status
Implemented
- ✅ Core models (Message, Capability, etc.)
- ✅ Cryptography (Ed25519 signing, HKDF key derivation, AES-GCM encryption)
- ✅ Authentication (challenge-response)
- ✅ Message posting and retrieval
- ✅ State management
- ✅ Data (KV) storage
- ✅ Blob upload/download (plaintext and encrypted)
- ✅ Sync API (
Space) using httpx - ✅ Async API (
AsyncSpace) with WebSocket streaming - ✅ Local message cache (
LocalMessageStore) - ✅ Comprehensive test suite (pytest)
Coming Soon
- ⏳ Additional examples
Testing
Run the test suite:
# Install dev dependencies
uv pip install -e ".[dev]"
# Run all tests (19 tests total)
uv run pytest
# Run with verbose output
uv run pytest -v
# Run specific test file
uv run pytest tests/test_key_derivation.py # 18 key derivation tests
uv run pytest tests/test_smoke.py # 1 comprehensive API smoke test
The test suite includes:
- test_smoke.py: Comprehensive smoke test validating the entire public API surface
- test_key_derivation.py: 18 tests covering HKDF key derivation, domain separation, and security properties
See tests/README.md for more details.
License
Licensed under either of Apache License, Version 2.0 or MIT License at your option.
Contributing
Contributions welcome! Please open an issue or PR.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file reeeductio-0.1.1.tar.gz.
File metadata
- Download URL: reeeductio-0.1.1.tar.gz
- Upload date:
- Size: 74.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
21c5bd27f6008c43faae9ba5fc71594fc3520f0cd0c84d7ce7963af8c291e785
|
|
| MD5 |
940bf5424831a33ef544206960488bad
|
|
| BLAKE2b-256 |
cf9f15f497f3b85abb9d33890ea8ed0ae58ecfcb3d70ce1d58d6bb15f11265f5
|
File details
Details for the file reeeductio-0.1.1-py3-none-any.whl.
File metadata
- Download URL: reeeductio-0.1.1-py3-none-any.whl
- Upload date:
- Size: 67.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8bea653e83035fd599fe7dcb70e3a228f90a993eebd7d96cf9bf981db634dba7
|
|
| MD5 |
65b8c1f51b2639a0e8307ef7b16bb2ed
|
|
| BLAKE2b-256 |
9edac50e261b95996123f349cb2b66d2cf28d7ff6ac743be3e913d2b090011f2
|