evidence 0.1.0

Type-level tags for cryptographic primitives
Documentation
[![crates.io](https://img.shields.io/crates/v/evidence.svg)](https://crates.io/crates/evidence)
[![docs.rs](https://docs.rs/evidence/badge.svg)](https://docs.rs/evidence)
[![license](https://img.shields.io/crates/l/evidence.svg)](LICENSE-MIT)

# 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:

```rust
fn verify_user(user_hash: [u8; 32], post_hash: [u8; 32]) {
    // Oops! Easy to swap these by accident
    if user_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:

```rust
use evidence::digest::{Digest, sha2::Sha256};
use evidence::codec::Identity;

// These are incompatible types — can't be mixed up
let user_hash: Digest<User, Sha256, Identity> = Digest::hash(&user);
let post_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

```rust
use evidence::{
  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> for MyCbor {
    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
let digest: Digest<MyData, Sha256, MyCbor> = Digest::hash(&my_data);

// Access the raw bytes when needed
let bytes: &[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

```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](LICENSE-APACHE) or [MIT license](LICENSE-MIT) at your option.