tholos-pq
A pure Rust implementation of post-quantum multi-recipient encryption with a stable, versioned wire format.
Overview
tholos-pq provides a complete solution for encrypting messages to multiple recipients using post-quantum cryptographic algorithms. The library uses ML-KEM-1024 (Kyber-1024) for key encapsulation, XChaCha20-Poly1305 for symmetric encryption, and Dilithium-3 for sender authentication.
Features
- Multi-recipient encryption: Encrypt once for N recipients efficiently
- Post-quantum security: All cryptographic primitives are quantum-resistant
- Sender authentication: Verify sender identity using Dilithium-3 signatures
- Stable wire format: Versioned CBOR format for interoperability
- Pure Rust: No C dependencies, safe Rust throughout
- Comprehensive testing: Unit tests, integration tests, and property-based tests
Algorithm Suite
- Key Encapsulation: ML-KEM-1024 (Kyber-1024) for per-recipient key wrapping
- Symmetric Encryption: XChaCha20-Poly1305 for payload and CEK encryption
- Digital Signatures: Dilithium-3 for sender authentication
- Wire Format: Canonical CBOR with versioning (
suite = Kyber1024+XChaCha20P1305+Dilithium3)
Installation
Add this to your Cargo.toml:
[]
= "0.1.0"
Usage
Basic Example
use *;
Multi-Recipient Encryption
use *;
let sender = gen_sender_keypair;
let = gen_recipient_keypair;
let = gen_recipient_keypair;
let = gen_recipient_keypair;
let allowed = vec!;
// Encrypt once for all three recipients
let wire = encrypt?;
// Each recipient can decrypt independently
let pt_a = decrypt?;
let pt_b = decrypt?;
let pt_c = decrypt?;
Sender Authentication
use *;
let sender1 = gen_sender_keypair;
let sender2 = gen_sender_keypair;
let = gen_recipient_keypair;
// Only allow sender1
let allowed = vec!;
// Message from sender1 succeeds
let wire1 = encrypt?;
let pt1 = decrypt?;
// Message from sender2 is rejected
let wire2 = encrypt?;
let result = decrypt;
assert!;
API Reference
Key Generation
gen_recipient_keypair(kid: &str) -> (RecipientPub, RecipientPriv): Generate a new ML-KEM-1024 keypair for a recipientgen_sender_keypair(sid: &str) -> SenderKeypair: Generate a new Dilithium-3 keypair for a sendersender_pub(sender: &SenderKeypair) -> SenderPub: Extract public key information from a sender keypair
Encryption and Decryption
encrypt(plaintext: &[u8], sender: &SenderKeypair, recipients: &[RecipientPub]) -> Result<Vec<u8>, TholosError>: Encrypt a message for multiple recipientsdecrypt(wire_cbor: &[u8], my_kid: &str, my_sk: &<MlKem1024 as KemCore>::DecapsulationKey, allowed_senders: &[(String, Vec<u8>)]) -> Result<Vec<u8>, TholosError>: Decrypt a message as a recipient
Error Types
The TholosError enum includes:
BadSignature: Signature verification failed or sender not allowedMissingEnvelope: No recipient envelope found for the specified recipient IDMalformed: A field in the wire format is malformedAead: AEAD encryption or decryption operation failedSer: CBOR serialization or deserialization error
Security Considerations
- All cryptographic operations use secure random number generation via
OsRng - Private keys should be stored securely and never exposed
- The allowed sender list must be managed carefully to prevent unauthorized access
- Wire formats should be validated before decryption
- This library provides cryptographic primitives; key management and distribution are the application's responsibility
Testing
The library includes comprehensive test coverage:
- Unit tests for individual functions
- Integration tests for round-trip encryption/decryption
- Property-based tests using
proptestfor correctness validation - Error path testing for malformed inputs
Run tests with:
Run property tests with:
Wire Format
The wire format is a versioned CBOR structure (BundleSigned) containing:
- Header: Version, suite identifier, sender ID, recipient IDs, message ID, timestamp
- Payload: Encrypted plaintext using XChaCha20-Poly1305
- Recipient Envelopes: Per-recipient ML-KEM ciphertexts and wrapped CEKs
- Signature: Dilithium-3 signature over the unsigned bundle
The format is designed for interoperability and includes versioning to support future algorithm updates.
Dependencies
ml-kem: Pure Rust ML-KEM-1024 implementationpqcrypto-dilithium: Dilithium-3 signature implementationchacha20poly1305: XChaCha20-Poly1305 AEAD encryptionserde_cbor: CBOR serializationhkdf: Key derivation
License
Licensed under the Apache License, Version 2.0.
Contributing
Contributions are welcome. Please ensure all tests pass and code follows Rust conventions.