reverse_resonance_id 0.1.0

Self-checking symmetric tokens based on reversing squared user identifiers.
Documentation
![Baseline token example](1089-9801.png)

# reverse_resonance_id

Self-checking symmetric tokens based on reversing `n²` and pairing it with fast integrity tags. The crate ships a zero-allocation core API, an optional CLI, and Criterion benches so you can validate throughput before rollout.

## Highlights
- Three schemes: baseline (CRC32 + Blake2s), HMAC (Blake2s) and salt+iter (slow hash w/ configurable work factor).
- Safe, pure-Rust implementation (Rust 1.70+ MSRV) with no `unsafe`.
- Strong test coverage including property and tamper tests, plus a 100k-token smoke test (opt-in).
- Optional features for CLI (`cli`), salted hashing (`salt-iter`), HMAC (`hmac`), serde integration, and in-memory key zeroisation (`zeroize`).

## Installation

```toml
[dependencies]
reverse_resonance_id = { version = "0.1.0", features = ["hmac", "salt-iter"] }
```

Feature flags:

| Feature | Default | Purpose |
|---------|---------|---------|
| `baseline` || Core CRC32 + Blake2s flow. |
| `hmac` || Enables HMAC-Blake2s generation/verification. |
| `salt-iter` || Enables salt+iter flow with secure randomness. |
| `cli` || Builds the `rrid` binary (`cargo install --features cli`). |
| `serde` || Derives `serde::Serialize/Deserialize` for structs that need it (used by CLI). |
| `zeroize` || Zeroizes stored secrets (Scheme enum, HMAC helper) when dropped. |

## Quick Start (Rust)

```rust
use reverse_resonance_id::{make_token_baseline, validate_token_baseline};
#[cfg(feature = "hmac")]
use reverse_resonance_id::{make_token_hmac, validate_token_hmac};
#[cfg(feature = "salt-iter")]
use reverse_resonance_id::{make_token_salt_iter, validate_token_salt_iter};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Baseline: CRC32 + truncated Blake2s (8 hex chars)
    let baseline = make_token_baseline(33)?;
    assert!(validate_token_baseline(baseline.as_str()));

    // HMAC (Blake2s) with 64-bit tag (16 hex chars)
    #[cfg(feature = "hmac")]
    {
        let key = hex::decode("00112233445566778899aabbccddeeff")?;
        let hmac = make_token_hmac(33, &key, 16)?;
        assert!(validate_token_hmac(hmac.as_str(), &key, 16));
    }

    // Salted iterative hash (default salt=4 bytes, iters=2048)
    #[cfg(feature = "salt-iter")]
    {
        let slow = make_token_salt_iter(33, 4, 2_048)?;
        assert!(validate_token_salt_iter(slow.as_str()));
    }

    Ok(())
}
```

Scheme formats:

| Scheme | Format |
|--------|--------|
| Baseline | `<n2>-<rev>-<crc32hex8>-<blake2s8hex>` |
| HMAC | `<n2>-<rev>-<hmac_blake2s_hex>` |
| Salt+Iter | `<n2>-<rev>-<salt_hex>-<iters>-<tag8hex>` |

Where `n2 = n * n` as decimal string, `rev` is that string reversed, and the payload hashed is `"{n2}|{rev}"`.

## CLI

Enable the `cli` feature to build the `rrid` binary:

```sh
cargo install --path . --features cli
```

### Generate

```sh
$ rrid make --scheme baseline 33
{"token":"1089-9801-f7961616-283a12c9","scheme":"baseline","gen_time_ms":0.088709}

$ rrid make --scheme hmac --key 00112233445566778899aabbccddeeff --tag-len 16 33
{"token":"1089-9801-6d779ec117c17c71","scheme":"hmac","gen_time_ms":0.10254100000000001}

$ rrid make --scheme salt-iter --salt-len 4 --iters 2048 33
{"token":"1089-9801-b453dac8-2048-8cebd230","scheme":"salt-iter","gen_time_ms":12.504375}
```

### Verify

```sh
$ rrid verify --scheme baseline 1089-9801-f7961616-283a12c9
{"token":"1089-9801-f7961616-283a12c9","scheme":"baseline","gen_time_ms":0.088917}
```

The command exits with code `0` when validation succeeds and `1` otherwise. JSON always contains `token`, `scheme`, and the measured runtime in milliseconds.

## Errors

Token generation returns `Result<Token, RRIDError>`. Validation helpers return `bool` (`false` on any error). `RRIDError` variants cover invalid user IDs, format/parse problems, reversed-string mismatches, tag mismatches, and cryptographic errors. Convert or display them directly for logging/auditing.

## Security Notes

- **Baseline**: Fast and deterministic, but only a 32-bit CRC + 32-bit Blake2s tag. Best for human-readable, low-risk use-cases.
- **HMAC**: Requires a server-side secret. Default tag length is 16 hex chars (64 bits). Increase `tag_len` for harder brute force. Enable the `zeroize` feature to erase in-memory keys on drop.
- **Salt+Iter**: Keyless, time-hardening defence against brute force. Defaults to 2048 iterations; adjust upward for higher security (but note the slower throughput and DoS trade-offs).
- All hex digests are lowercase. Always compare using the provided helpers to avoid subtle mistakes.
- For long-term, high-assurance deployments, consider layering stronger authentication (e.g., Ed25519 signatures) on top—this crate documents the core rev(n²) idea.

## Benchmarks

Measured with `cargo bench` on Rust `1.88.0` (release build) on the developer machine. Throughput counts complete generate+validate pairs.

| Scheme | Workload | Throughput |
|--------|----------|------------|
| Baseline | 100k tokens / batch | ~595k tokens/sec |
| HMAC (tag 16) | 50k tokens / batch | ~506k tokens/sec |
| Salt+Iter (512 iters) | 5k tokens / batch | ~7.9k tokens/sec |
| Salt+Iter (1024 iters) | 5k tokens / batch | ~3.9k tokens/sec |
| Salt+Iter (2048 iters) | 5k tokens / batch | ~2.0k tokens/sec |
| Salt+Iter (4096 iters) | 5k tokens / batch | ~0.93k tokens/sec |

Use the benches to evaluate your own hardware (`cargo bench`). Plots are stored under `target/criterion/`.

## Testing & QA

```sh
cargo fmt
cargo clippy --all-targets --all-features
cargo test
cargo bench             # runs Criterion suites
cargo test -- --ignored # runs the 100k-token smoke test
```

The test suite includes:

- Round-trip, tamper, and uniqueness checks for every scheme.
- Property tests with Proptest.
- Deterministic RNG tests for salt generation.
- A long-running `#[ignore]` bulk test covering 100k tokens and salt iter smoke coverage.

## Actix Web Integration Snippet

```rust,ignore
use actix_web::{dev::Payload, error::ErrorUnauthorized, FromRequest, HttpRequest};
use futures_util::future::{ready, Ready};
use reverse_resonance_id::validate_token_hmac;

pub struct RridToken(String);

impl FromRequest for RridToken {
    type Error = actix_web::Error;
    type Future = Ready<Result<Self, Self::Error>>;

    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        const KEY: &[u8] = b"0123456789abcdef0123456789abcdef";
        let header = req
            .headers()
            .get("x-rrid-token")
            .and_then(|v| v.to_str().ok());

        match header {
            Some(token) if validate_token_hmac(token, KEY, 16) => {
                ready(Ok(RridToken(token.to_owned())))
            }
            _ => ready(Err(ErrorUnauthorized("invalid rrid token"))),
        }
    }
}
```

## License

Dual-licensed under MIT or Apache-2.0. See `LICENSE-MIT` and `LICENSE-APACHE` for details.