Installation
[]
= "1"
Or:
MSRV: Rust 1.85 (edition 2024). Older toolchains will not build.
Quick start
AEAD round-trip
use Crypt;
let key = ; // your 256-bit key
let crypt = new; // ChaCha20-Poly1305 by default
let ciphertext = crypt.encrypt?;
let recovered = crypt.decrypt?;
assert_eq!;
# Ok::
AES-256-GCM (when you want hardware acceleration)
use Crypt;
let key = ;
let crypt = aes_256_gcm; // requires `aead-aes-gcm` (default-on)
let ciphertext = crypt.encrypt?;
let recovered = crypt.decrypt?;
# Ok::
Hashing
use hash;
let digest = blake3; // [u8; 32]
let sha256 = sha256; // [u8; 32]
let sha512 = sha512; // [u8; 64]
let xof = blake3_long; // Vec<u8>, 128 bytes
MAC with constant-time verify
use mac;
let key = b"shared secret";
let data = b"message to authenticate";
let tag = hmac_sha256?;
assert!;
// Never `tag == expected_tag` against a secret — use the `*_verify` path.
# Ok::
BLAKE3 keyed mode — typed key, infallible:
use mac;
let key = ;
let tag = blake3_keyed;
assert!;
Streaming (large or chunked inputs)
use Blake3Hasher;
let mut h = new;
h.update;
h.update;
let digest = h.finalize;
Key derivation
Deriving a subkey from a master:
use kdf;
let master = ;
let session_key = hkdf_sha256?;
assert_eq!;
# Ok::
Hashing a password (Argon2id, OWASP-recommended defaults):
use kdf;
let phc = argon2_hash?;
assert!;
# Ok::
Encrypt a file
use Algorithm;
use stream;
let key = ;
encrypt_file?;
decrypt_file?;
# Ok::
Chunked AEAD with the STREAM construction — works for files of any size, detects tampering / truncation / reordering. For in-memory streaming (network sockets, buffered I/O), use StreamEncryptor / StreamDecryptor directly.
See docs/API.md for the full reference.
Design philosophy
crypt-io is intentionally focused:
- One job: symmetric crypto. Done well.
- No reinvention. Primitives come from RustCrypto and BLAKE3 (battle-tested, widely audited).
- Simple API. Encrypt in two lines. Hash in one. The easy path is the secure path.
- Algorithm agility. ChaCha20-Poly1305 by default, AES-256-GCM when you want hardware acceleration. Same
CryptAPI either way. - Constant-time discipline. MAC verification uses upstream constant-time comparators, never
==. Documented in module overviews. - Hash ≠ MAC.
Blake3Hasherhas nowith_key. The only way to produce a keyed tag is through themacmodule. This separation is deliberate. - Redaction-clean errors. No variant of
Errorever contains key material, plaintext, ciphertext, nonces, or tag bytes. - REPS-disciplined. Every commit passes
cargo fmt --check,cargo clippy --all-targets --all-features -- -D warnings,cargo test --all-features, andcargo docwith-D warnings.
What we explicitly do NOT do:
- Implement crypto primitives from scratch (use battle-tested upstreams)
- Asymmetric crypto (RSA, ECDSA, Ed25519) — different problem, separate crate
- PGP/GPG (use
sequoia-openpgp) - TLS (use
rustls) - Random number generation (use
mod-rand) - UUID generation (use
id-forge) - Key storage (use
key-vault)
When to use crypt-io
Good fit:
- Encrypting data for storage (databases, file systems, caches)
- Encrypting API tokens or session data
- Authenticating messages, audit logs, signed records
- Hashing for integrity checks, fingerprinting, content-addressed storage
- HMAC signatures for outgoing requests (AWS SigV4, JWT HS256/HS512, webhooks)
- Composing with
key-vaultfor in-memory key handling
Wrong fit:
- TLS connections — use
rustls - OpenPGP interop — use
sequoia-openpgp - Digital signatures — use
ed25519-dalek - Key exchange — use
x25519-dalek - Random number generation — use
mod-rand
Performance
Measured on a reference machine (AMD Ryzen 9 9950X3D, AES-NI + SHA-NI + AVX-512, WSL2 Ubuntu, Rust 1.85.0). Full methodology + per-suite tables in docs/PERFORMANCE.md.
| Operation | Target | Measured | Status |
|---|---|---|---|
| ChaCha20-Poly1305 encrypt, 1 KiB | < 2 µs | 1.72 µs | ✅ |
| AES-256-GCM encrypt, 1 KiB (HW accel) | < 1 µs | 944 ns | ✅ |
| BLAKE3 hash, 1 KiB | < 500 ns | 1.07 µs | ⚠️ revised |
| BLAKE3 hash, 64 KiB | — | 11.24 GiB/s | ✅ |
| SHA-256 hash, 1 KiB (SHA-NI) | < 2 µs | 426 ns | ✅ |
| HMAC-SHA256, 1 KiB | < 3 µs | 565 ns | ✅ |
| HKDF-SHA256, 32-byte output | < 5 µs | 304 ns | ✅ |
| Argon2id, default params | ~100 ms | ~9 ms (Zen 5 too fast — tune t_cost) |
⚠️ |
| Stream encrypt, 1 MiB plaintext | > 1 GiB/s | 932-999 MiB/s | ⚠️ marginal |
Reproduce: cargo bench --all-features (numbers vary by hardware — see PERFORMANCE.md for the portable analysis).
Documentation
docs/API.md— complete public-API reference.docs/STABILITY-1.0.md— what the 1.0 contract freezes, the MSRV policy, what can change in 1.x vs 2.0.docs/SECURITY.md— threat model, algorithm rationale, vulnerability reporting.docs/ARCHITECTURE.md— module layout, algorithm dispatch, dependency rationale.docs/PLATFORM-NOTES.md— hardware acceleration per platform + cross-compile guide.docs/PERFORMANCE.md— measured throughput, contract-check matrix, parameter-choice guidance.docs/FILE_FORMAT.md— stream wire format spec (frozen for the 1.x series).CHANGELOG.md— per-version Added / Changed / Security entries.docs/release/— per-release notes (v0.2.0.md,v0.3.0.md, …,v1.0.0.md)..dev/ROADMAP.md— milestone plan through 1.0 and beyond.
Standards
- REPS (Rust Efficiency & Performance Standards) governs every decision. See
REPS.md. - MSRV: Rust 1.85.
- Edition: 2024.
- Cross-platform: Linux, macOS, Windows (CI matrix on stable + MSRV).
License
Dual-licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.