Status
Current version: 0.5.0 (2026-05-22). Pre-1.0 — the public API is allowed to evolve in breaking ways through the 0.x series; 1.0.0 freezes it.
| Phase | Surface | Status |
|---|---|---|
| 0.1.0 | Scaffold, REPS baseline, CI | shipped |
| 0.2.0 | AEAD foundation — ChaCha20-Poly1305 | shipped |
| 0.3.0 | AES-256-GCM + algorithm selection | shipped |
| 0.4.0 | Hashing — BLAKE3 (+ XOF), SHA-256, SHA-512 | shipped |
| 0.5.0 | MAC — HMAC-SHA256/512, BLAKE3 keyed | shipped |
| 0.6.0 | KDF — HKDF, Argon2id | next |
| 0.7.0 | Stream / file encryption | planned |
| 0.8.0 | Performance verification (criterion benches) | planned |
| 0.9.0 | Fuzz testing | planned |
| 0.10.0 | Docs + Release Candidate | planned |
| 1.0.0 | Stable Release | planned |
See .dev/ROADMAP.md for the full milestone plan and CHANGELOG.md for per-version detail. Per-release notes live under docs/release/.
What's in 0.5.0
Symmetric AEAD encryption — crypt_io::aead
Crypt::new()— ChaCha20-Poly1305 (default, post-quantum-safe at 256 bits).Crypt::aes_256_gcm()— AES-256-GCM (hardware-accelerated on AES-NI / ARMv8 crypto extensions, runtime-dispatched by upstream).- Algorithm-agile API. Same
encrypt/decryptsurface, same wire format (nonce || ciphertext || tag), same 32-byte key. Switch by picking the constructor. - Fresh nonces per call via
mod-randTier 3 (OS CSPRNG). Nonce reuse cannot happen through the public API. - AAD support via
encrypt_with_aad/decrypt_with_aad. - RFC 8439 + NIST SP 800-38D known-answer tests verifying byte-exact output against the specs.
Hashing — crypt_io::hash
- BLAKE3 —
hash::blake3(32-byte default) +hash::blake3_long(XOF, any length) + streamingBlake3Hasher. - SHA-256 / SHA-512 —
hash::sha256/hash::sha512+ streamingSha256Hasher/Sha512Hasher. - NIST FIPS 180-4 known-answer tests for SHA-2; byte-pinned KATs for BLAKE3.
- Streaming-equals-one-shot verified at multiple chunk boundaries.
- Hash-only by design. No
with_key. Keyed hashing lives inmac.
Message Authentication — crypt_io::mac
- HMAC-SHA256 / HMAC-SHA512 —
mac::hmac_sha256/mac::hmac_sha512+ streamingHmacSha256/HmacSha512. - BLAKE3 keyed mode —
mac::blake3_keyed(typed 32-byte key, infallible) + streamingBlake3Mac. - Constant-time verification by default. Every algorithm exposes a
*_verifypath that compares against an expected tag via upstream constant-time comparators. Nevertag == expectedagainst a secret. - RFC 4231 known-answer tests for HMAC; byte-pinned KAT for BLAKE3 keyed.
- Wrong-length tags are rejections, not panics.
Portfolio integration
mod-rand— Tier 3 OS-backed CSPRNG for nonces.error-forge— declared dependency (deeper integration in a later phase).log-io(optional) — operation logging.metrics-lib(optional) — performance instrumentation.key-vault— peer crate; the consumer wires them together. No direct dependency.
What's not in 0.5.0 yet
- KDF (HKDF, Argon2id) — Phase 0.6.0.
- Stream / file encryption — Phase 0.7.0.
- Benchmark suite — Phase 0.8.0. Performance targets are in the contract (see
.dev/ROADMAP.md); committed criterion-backed measurements land in 0.8. - Fuzz testing — Phase 0.9.0.
- Asymmetric crypto, PGP, TLS, RNG, UUIDs, key storage — out of scope for the lifetime of this crate. Use
mod-rand,key-vault,rustls,sequoia-openpgp, etc.
Installation
[]
= "0.5"
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;
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 targets
Verified by benchmarks in Phase 0.8.0 (criterion-backed, committed baselines). Until then these are documented targets, not measured numbers:
| Operation | Target |
|---|---|
| ChaCha20-Poly1305 encrypt, 1 KiB | < 2 µs |
| AES-256-GCM encrypt, 1 KiB (HW accel) | < 1 µs |
| BLAKE3 hash, 1 KiB | < 500 ns |
| SHA-256 hash, 1 KiB | < 2 µs |
| HMAC-SHA256, 1 KiB | < 3 µs |
| HKDF-SHA256, 32-byte output (0.6.0) | < 5 µs |
| Argon2id, default params (0.6.0) | < 100 ms (intentionally slow) |
| Stream encrypt throughput (0.7.0) | > 1 GiB/s |
Documentation
docs/API.md— complete public-API reference for the current version.CHANGELOG.md— per-version Added / Changed / Security entries.docs/release/— per-release notes (v0.2.0.md,v0.3.0.md, …)..dev/ROADMAP.md— milestone plan through 1.0.
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.