- Rust 96.4%
- Nix 3.6%
| .woodpecker | Fix Nix deprecation warning | |
| design | First version | |
| src | First version | |
| tests | First version | |
| .gitignore | First version | |
| _typos.toml | Improve CI | |
| Cargo.lock | First version | |
| Cargo.toml | First version | |
| deny.toml | First version | |
| flake.lock | First version | |
| flake.nix | Fix Nix deprecation warning | |
| HACKING.md | First version | |
| LICENSE-APACHE | First version | |
| LICENSE-MIT | First version | |
| README.md | Add CI badge | |
evidence
Type-level tags for cryptographic primitives.
evidence wraps cryptographic output (hashes, signatures, ciphertext) with phantom type parameters that track what was processed, which algorithm was used, and how the input was serialized — all at zero runtime cost.
The Problem
Cryptographic code often looks like this:
fn verify_user(user_hash: [u8;32],post_hash: [u8;32]){// Oops! Easy to swap these by accident
ifuser_hash==post_hash{/* ... */}}These are just byte arrays — the compiler can't help you distinguish a hash of a User from a hash of a Post, or a SHA-256 digest from a Blake3 digest.
The Solution
With evidence, the type system tracks what was hashed/signed and how:
useevidence::digest::{Digest,sha2::Sha256};useevidence::codec::Identity;// These are incompatible types — can't be mixed up
letuser_hash: Digest<User,Sha256,Identity>=Digest::hash(&user);letpost_hash: Digest<Post,Sha256,Identity>=Digest::hash(&post);// Compile error: expected `Digest<User, ...>`, found `Digest<Post, ...>`
// verify_user(post_hash);
This prevents:
- Mixing up digests of different types
- Comparing hashes from different algorithms
- Accessing signed payloads before verification
- Confusing encodings (a CBOR hash != a JSON hash of the same value)
The supported types can be extended without changing this library. That said, contributions of common primitives are always welcome.
Usage
useevidence::{codec::Encode,digest::{Digest,sha2::Sha256}};// Define your codec (or use the built-in Cbor / Json codecs)
enum MyCbor{}impl<T: minicbor::Encode<()>>Encode<T>forMyCbor{type Error=minicbor::encode::Error<core::convert::Infallible>;fn encode(value: &T)-> Result<Vec<u8>,Self::Error>{minicbor::to_vec(value)}}// Now you can hash values
letdigest: Digest<MyData,Sha256,MyCbor>=Digest::hash(&my_data);// Access the raw bytes when needed
letbytes: &[u8]=digest.as_bytes();Primitives
Hash
| Primitive | Feature | Output Size |
|---|---|---|
Sha256 |
sha2 |
32 bytes |
Sha384 |
sha2 |
48 bytes |
Sha512 |
sha2 |
64 bytes |
Sha3_224 |
sha3 |
28 bytes |
Sha3_256 |
sha3 |
32 bytes |
Sha3_384 |
sha3 |
48 bytes |
Sha3_512 |
sha3 |
64 bytes |
Keccak256 |
sha3 |
32 bytes |
Keccak512 |
sha3 |
64 bytes |
Blake3 |
blake3 |
32 bytes |
Signature
| Primitive | Feature |
|---|---|
Ed25519 |
ed25519 |
Encryption (AEAD)
| Primitive | Feature | Key Size | Nonce Size |
|---|---|---|---|
ChaCha20Poly1305 |
chacha20poly1305 |
32 bytes | 12 bytes |
Aes128Gcm |
aes-gcm |
16 bytes | 12 bytes |
Aes256Gcm |
aes-gcm |
32 bytes | 12 bytes |
MAC
| Primitive | Feature | Tag Size |
|---|---|---|
HmacSha256 |
hmac |
32 bytes |
HmacSha384 |
hmac |
48 bytes |
HmacSha512 |
hmac |
64 bytes |
Features
| Feature | Description |
|---|---|
sha2 |
SHA-256, SHA-384, SHA-512 |
sha3 |
SHA3-224/256/384/512, Keccak256/512 |
blake3 |
Blake3 |
ed25519 |
Ed25519 signatures |
hmac |
HMAC-SHA256/384/512 |
chacha20poly1305 |
ChaCha20-Poly1305 AEAD |
aes-gcm |
AES-128-GCM, AES-256-GCM |
minicbor |
Cbor codec Encode/Decode impls |
serde_json |
Json codec Encode/Decode impls (requires std) |
serde |
Serialize/Deserialize impls |
rkyv |
Zero-copy Archive/Serialize/Deserialize |
arbitrary |
Fuzzing support (arbitrary) |
bolero |
Fuzzing support (bolero) |
proptest |
Property testing (requires std) |
No features are enabled by default.
Cargo.toml
[dependencies]
evidence = { version = "0.1", features = ["sha2"] }
# With signatures
evidence = { version = "0.1", features = ["sha2", "ed25519"] }
# With encryption
evidence = { version = "0.1", features = ["sha2", "chacha20poly1305"] }
MSRV
The minimum supported Rust version is 1.90.
no_std
This crate is #![no_std] compatible. It requires alloc for encoding.
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.