# waddling-errors-hash
> **WDP-compliant xxHash3 computation for diagnostic codes**
A standalone hash utility crate implementing **WDP (Waddling Diagnostic Protocol) Part 5 (Compact IDs)** and **Part 7 (Namespaces)** specifications. Provides deterministic xxHash3-based hash generation for compact error code identifiers. Designed for compile-time hash embedding in procedural macros with zero runtime overhead.
[](https://crates.io/crates/waddling-errors-hash)
[](https://docs.rs/waddling-errors-hash)
---
## WDP Conformance
This crate implements the **Waddling Diagnostic Protocol (WDP)** specifications:
- **[WDP Part 5: Compact IDs](https://gitlab.com/AshutoshMahala/wdp-specs/-/blob/main/5-COMPACT-IDS.md)** - Error code hash generation with xxHash3 and `"wdp-v1"` seed
- **[WDP Part 7: Namespaces](https://gitlab.com/AshutoshMahala/wdp-specs/-/blob/main/7-NAMESPACES.md)** - Namespace hash generation with xxHash3 and `"wdpns-v1"` seed
### Key WDP Requirements
Per WDP Part 5 Β§4.1:
> Implementations MUST use xxHash3 (xxh3_64) as the hashing algorithm for Compact ID generation.
Per WDP Part 5 Β§4.3:
> Alternative algorithms MUST NOT be used. This requirement ensures universal interoperability: identical error codes MUST produce identical Compact IDs across all WDP implementations.
---
## Overview
This crate converts error codes like `E.AUTH.TOKEN.001` into compact 5-character hashes using the WDP-standardized xxHash3 algorithm.
### What It Does
```rust
use waddling_errors_hash::{compute_wdp_hash, compute_wdp_namespace_hash, compute_wdp_full_id};
// Hash an error code (WDP-compliant: case-insensitive, whitespace-trimmed)
let hash = compute_wdp_hash("E.Auth.Token.001");
assert_eq!(hash.len(), 5); // e.g., "V6a0B"
// These all produce the SAME hash (normalization per WDP Part 5 Β§3):
assert_eq!(compute_wdp_hash("E.Auth.Token.001"), compute_wdp_hash("E.AUTH.TOKEN.001"));
assert_eq!(compute_wdp_hash("E.Auth.Token.001"), compute_wdp_hash("e.auth.token.001"));
// Hash a namespace (WDP Part 7)
let ns_hash = compute_wdp_namespace_hash("auth_lib");
assert_eq!(ns_hash.len(), 5); // e.g., "05o5h"
// Combined identifier: namespace_hash-code_hash (WDP Part 7 Β§5)
let full_id = compute_wdp_full_id("auth_lib", "E.Auth.Token.001");
assert_eq!(full_id.len(), 11); // "05o5h-V6a0B"
```
### Why Compact IDs?
- π¦ **Compact logging**: `[V6a0B]` vs `[E.AUTH.TOKEN.001]` (~70% size reduction)
- π **Network efficiency**: IoT devices send 5 bytes instead of 20+ bytes
- π **Quick lookups**: Fast error correlation and catalog searches
- π **Deterministic**: Same input always produces same output
- π **Cross-language**: xxHash3 available in Python, JS, Go, Java, Rust, C, C++, etc.
- π± **URL-safe**: Base62 encoding (alphanumeric only, no special characters)
### Algorithm: xxHash3 Only
This crate **exclusively implements xxHash3** as mandated by WDP Part 5. xxHash3 was chosen for:
- β‘ **Speed**: ~30 GB/s throughput
- π― **Optimized for small inputs**: Perfect for 15-30 byte error codes
- π **Universal availability**: Supported in all major programming languages
- π **Excellent distribution**: Minimal collision probability
- π **Frozen specification**: Stable since 2021, guaranteed cross-platform consistency
**Specification References:**
- [WDP Part 5: Compact IDs](https://gitlab.com/AshutoshMahala/wdp-specs/-/blob/main/5-COMPACT-IDS.md)
- [WDP Part 7: Namespaces](https://gitlab.com/AshutoshMahala/wdp-specs/-/blob/main/7-NAMESPACES.md)
**Note:** This crate is NOT cryptographically secure. xxHash3 is designed for speed and distribution quality, not security. For security-sensitive applications, use cryptographic verification at a higher protocol layer (TLS, JWT, etc.) as recommended in WDP Part 5 Β§4.4.
---
## Quick Start
### Basic Usage (WDP-Compliant)
```rust
use waddling_errors_hash::compute_wdp_hash;
let hash = compute_wdp_hash("E.AUTH.TOKEN.001");
println!("Hash: {}", hash); // e.g., "V6a0B"
// Properties:
assert_eq!(hash.len(), 5);
**Algorithm:** xxHash3 with `"wdp-v1"` seed + input normalization (uppercase, trim)
### Without Normalization
```rust
use waddling_errors_hash::compute_hash;
// No normalization - input used as-is
let hash = compute_hash("E.AUTH.TOKEN.001");
println!("Hash: {}", hash);
```
**Algorithm:** xxHash3 with `"wdp-v1"` seed (no normalization)
### Custom Seed
```rust
use waddling_errors_hash::{compute_hash_with_config, HashConfig};
// Use a custom seed for isolated hash space
let config = HashConfig::with_seed(0x1234567890ABCDEF);
let hash = compute_hash_with_config("E.AUTH.TOKEN.001", &config);
```
**Use case:** Multi-tenant isolation (different seeds produce different hashes)
---
## Use Cases
### 1. WDP-Conformant (Recommended)
```rust
use waddling_errors_hash::compute_wdp_hash;
// WDP-compliant: normalization + standard seed
let hash = compute_wdp_hash("E.AUTH.TOKEN.001");
// Normalized: uppercase, trimmed (per WDP Part 5 Β§3)
assert_eq!(
compute_wdp_hash("e.auth.token.001"),
compute_wdp_hash("E.AUTH.TOKEN.001")
);
```
**Algorithm:** xxHash3 with `"wdp-v1"` seed (0x000031762D706477)
**Normalization:** Trim + Uppercase
**Use for:** Interoperability with WDP ecosystem
### 2. General Purpose (Fast)
```rust
use waddling_errors_hash::compute_hash;
// Fast hashing without normalization
let hash = compute_hash("E.AUTH.TOKEN.001");
```
**Algorithm:** xxHash3
**Speed:** ~30 GB/s
**Use for:** Projects not requiring WDP conformance
### 3. Multi-Tenant Isolation
```rust
use waddling_errors_hash::{compute_hash_with_config, HashConfig};
// Each tenant gets unique hashes (prevents catalog sharing)
let tenant_a_config = HashConfig::with_seed(0x1111111111111111);
let tenant_b_config = HashConfig::with_seed(0x2222222222222222);
let hash_a = compute_hash_with_config("E.QUOTA.EXCEEDED.001", &tenant_a_config);
let hash_b = compute_hash_with_config("E.QUOTA.EXCEEDED.001", &tenant_b_config);
// Same error code, different hashes!
assert_ne!(hash_a, hash_b);
```
**Use for:** SaaS, multi-tenant systems where catalog isolation is needed
### 4. Namespace Hashing (WDP Part 7)
```rust
use waddling_errors_hash::{compute_wdp_namespace_hash, compute_wdp_full_id};
// Hash a namespace (library, service, or application name)
let ns_hash = compute_wdp_namespace_hash("auth_lib");
assert_eq!(ns_hash.len(), 5); // e.g., "05o5h"
// Combined identifier for global uniqueness
let full_id = compute_wdp_full_id("auth_lib", "E.Auth.Token.001");
assert_eq!(full_id.len(), 11); // e.g., "05o5h-V6a0B"
assert_eq!(&full_id[5..6], "-"); // namespace_hash-code_hash format
```
**Use for:** Multi-library applications, microservices (WDP Part 7 Β§2)
---
## Compile-Time Usage (Proc Macros)
The primary use case is **compile-time hash generation** in procedural macros:
```rust
// In waddling-errors-macros/src/diag.rs
use waddling_errors_hash::compute_hash;
// During macro expansion (compile time):
let full_code = "E.AUTH.TOKEN.001";
let hash = compute_hash(full_code);
// Generate constant in output code:
let hash_lit = syn::LitStr::new(&hash, proc_macro2::Span::call_site());
quote! {
pub const E_AUTH_TOKEN_001_HASH: &str = #hash_lit; // e.g., "V6a0B"
}
```
**Result:** Hash is computed once at compile time and embedded as a string constant in the binary. Zero runtime cost!
---
## WDP Seed Constants
For WDP conformance, use these seed values:
| Error code hashes | `"wdp-v1"` | `0x000031762D706477` | Part 5 Β§4.5 |
| Namespace hashes | `"wdpns-v1"` | `0x31762D736E706477` | Part 7 Β§4.2 |
**Seed Conversion (WDP Part 5 Β§4.5.1):**
1. Take UTF-8 bytes of seed string (6 bytes for "wdp-v1")
2. Zero-pad on the RIGHT to 8 bytes: `[0x77, 0x64, 0x70, 0x2D, 0x76, 0x31, 0x00, 0x00]`
3. Interpret as little-endian u64: `0x000031762D706477`
### Cross-Language Examples
**Rust:**
```rust
use xxhash_rust::xxh3::xxh3_64_with_seed;
const WDP_SEED: u64 = 0x000031762D706477;
let hash = xxh3_64_with_seed(input_bytes, WDP_SEED);
// Verification: compute from bytes
let seed_bytes: [u8; 8] = [0x77, 0x64, 0x70, 0x2D, 0x76, 0x31, 0x00, 0x00];
let seed = u64::from_le_bytes(seed_bytes);
assert_eq!(seed, 0x000031762D706477);
```
**Python:**
```python
import xxhash
WDP_SEED_U64 = 0x000031762D706477 # 13891256219767
hash_value = xxhash.xxh3_64(input_bytes, seed=WDP_SEED_U64)
# Verification
seed_bytes = b"wdp-v1" + b"\x00\x00" # Zero-pad to 8 bytes
seed_u64 = int.from_bytes(seed_bytes, byteorder='little')
assert seed_u64 == 0x000031762D706477
```
**TypeScript/JavaScript:**
```typescript
import { xxh3 } from 'xxhash-wasm';
const WDP_SEED = 0x000031762D706477n; // BigInt literal
const hash = xxh3.h64(inputBytes, WDP_SEED);
```
**Go:**
```go
import "github.com/zeebo/xxh3"
const WDPSeedU64 uint64 = 0x000031762D706477
hash := xxh3.HashSeed(inputBytes, WDPSeedU64)
```
**C/C++:**
```c
#include "xxhash.h"
#define WDP_SEED 0x000031762D706477ULL
XXH64_hash_t hash = XXH3_64bits_withSeed(input_bytes, input_len, WDP_SEED);
```
**Normalization (WDP Part 5 Β§3.3):**
All languages MUST apply the same normalization for WDP compliance:
1. Trim leading/trailing whitespace
2. Convert to uppercase
3. Encode as UTF-8 bytes
```python
# Python normalization
def normalize_wdp_input(code: str) -> str:
return code.strip().upper()
# Usage
normalized = normalize_wdp_input(" e.auth.token.001 ")
# Result: "E.AUTH.TOKEN.001"
```
---
## Security Considerations
### xxHash3 is NOT Cryptographically Secure
β οΈ **NOT cryptographically secure**
β οΈ Attackers can craft collisions if they control input
β
**Safe for error codes** (you control the input, not attackers)
β
**Perfect for:** Catalogs, logging, compression, lookups
**WDP Part 5 Β§4.4 states:**
> Compact IDs are designed for IDENTIFICATION purposes, not AUTHENTICATION.
### When xxHash3 is Appropriate
```rust
// This is SAFE because error codes are controlled by developers, not users
let hash = compute_hash("E.AUTH.TOKEN.001"); // xxHash3
```
### Security Layering (WDP Part 5 Β§4.4)
For security requirements, use appropriate mechanisms at the correct architectural layer:
| Transport security | HTTPS/TLS | Transport |
| Message integrity | JWT/JWS signing | Application |
| Catalog integrity | Ed25519 signature | Distribution |
| Authentication | OAuth/API keys | Application |
**Example:**
```json
{
"error": {
"code": "E.AUTH.TOKEN.001",
"hash": "V6a0B",
"message": "Token expired"
},
"signature": "eyJhbGc...JWT_signature_here..."
}
```
The Compact ID provides efficient identification while JWT provides message-level integrity.
---
## Architecture
### Why This Crate Exists
Procedural macros run in a separate compilation context and need a standalone hash implementation:
```
βββββββββββββββββββββββββββββββββββ
β waddling-errors-macros β
β (proc macro - compile time) β
β β
β Computes hash during macro β
β expansion and embeds as const β
ββββββββββββββ¬βββββββββββββββββββββ
β
β depends on
βΌ
βββββββββββββββββββββββββββββββββββ
β waddling-errors-hash ββββββββββββ
β (pure computation) β β
β β β depends on
β β’ compute_hash() β β (optional)
β β’ compute_wdp_hash() β β
β β’ compute_wdp_namespace_hash() β β
β β’ xxHash3 implementation β β
βββββββββββββββββββββββββββββββββββ β
β² β
β depends on (optional) β
β β
ββββββββββββββ΄βββββββββββββββββββββ β
β waddling-errors ββββββββββββ
β (runtime library) β
β β
β Can verify hashes at runtime β
β (if hash feature enabled) β
βββββββββββββββββββββββββββββββββββ
β²
β user depends on
β
ββββββββββββββ΄βββββββββββββββββββββ
β User's Application β
β β
β Uses error codes with embedded β
β hash constants (zero cost!) β
βββββββββββββββββββββββββββββββββββ
```
### Binary Size Impact
**Compile-time (proc macro):** xxHash3 implementation available, zero impact on user's binary
**Runtime (optional):** Only if user enables `hash` feature for verification
```
User's binary without hash feature:
ββ Hash constants: ~5 bytes per error code
ββ Hash algorithm code: 0 bytes (not included!)
User's binary WITH hash feature (runtime verification):
ββ Hash constants: ~5 bytes per error code
ββ xxHash3 implementation: ~10-15 KB
```
---
## API Reference
### WDP-Conformant Functions (Recommended)
```rust
/// Compute WDP-conformant hash (normalized: trim + uppercase)
/// Per WDP Part 5 Β§3
pub fn compute_wdp_hash(input: &str) -> String
/// Compute WDP-conformant namespace hash
/// Per WDP Part 7 Β§4
pub fn compute_wdp_namespace_hash(namespace: &str) -> String
/// Compute combined ID: "namespace_hash-code_hash"
/// Per WDP Part 7 Β§5
pub fn compute_wdp_full_id(namespace: &str, code: &str) -> String
/// Normalize input per WDP spec (trim + uppercase)
/// Per WDP Part 5 Β§3.3
pub fn normalize_wdp_input(input: &str) -> String
/// Parse full ID into (namespace_hash, code_hash)
/// Per WDP Part 7 Β§5.3
pub fn parse_wdp_full_id(full_id: &str) -> Option<(String, String)>
/// Verify WDP hash matches input
pub fn verify_wdp_hash(input: &str, hash: &str) -> bool
/// Verify WDP namespace hash matches input
pub fn verify_wdp_namespace_hash(namespace: &str, hash: &str) -> bool
```
### WDP Constants
```rust
/// WDP code hash seed: "wdp-v1" as little-endian u64
/// Per WDP Part 5 Β§4.5
pub const WDP_SEED: u64 = 0x000031762D706477;
/// WDP seed as string
pub const WDP_SEED_STR: &str = "wdp-v1";
/// WDP code seed for xxHash3
/// Per WDP Part 5 Β§4.5
pub const WDP_CODE_SEED: u64 = 0x000031762D706477;
/// WDP namespace seed: "wdpns-v1" as little-endian u64
/// Per WDP Part 7 Β§4.2
pub const WDP_NAMESPACE_SEED: u64 = 0x31762D736E706477;
```
### Core Functions
```rust
/// Compute hash with default config (xxHash3 + "wdp-v1")
pub fn compute_hash(input: &str) -> String
/// Compute hash with custom seed
pub fn compute_hash_with_config(input: &str, config: &HashConfig) -> String
/// Verify hash matches input (default config)
pub fn verify_hash(input: &str, hash: &str) -> bool
/// Verify hash matches input (custom config)
pub fn verify_hash_with_config(input: &str, hash: &str, config: &HashConfig) -> bool
```
### Configuration Types
```rust
/// Hash algorithm (currently only xxHash3 per WDP Part 5 Β§4.1)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum HashAlgorithm {
#[default]
XxHash3, // WDP-mandated algorithm
}
/// Hash configuration
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HashConfig {
pub algorithm: HashAlgorithm,
pub seed: u64,
}
impl HashConfig {
/// Create config with algorithm and seed
pub fn new(algorithm: HashAlgorithm, seed: u64) -> Self
/// Create config with custom seed (default algorithm)
pub fn with_seed(seed: u64) -> Self
/// Create WDP-conformant config
pub fn wdp_conformant() -> Self
}
impl Default for HashConfig {
// Returns: XxHash3 with WDP_SEED (0x000031762D706477)
fn default() -> Self
}
```
### Utility Functions
```rust
/// Convert bytes to 5-character base62 string
pub fn to_base62(bytes: &[u8]) -> String
/// Convert u64 to 5-character base62 string
pub fn u64_to_base62(value: u64) -> String
/// Convert seed string to u64 (for WDP compliance)
/// Zero-pads on right to 8 bytes, interprets as little-endian
pub fn seed_to_u64(seed: &str) -> u64
```
### Const (Compile-Time) Functions
```rust
/// Const version of compute_wdp_hash (for compile-time)
pub const fn const_wdp_hash(severity: &str, component: &str,
primary: &str, sequence: &str) -> &'static str
/// Const version with raw bytes input
pub const fn const_wdp_hash_bytes(bytes: &[u8]) -> &'static str
/// Const version with pre-constructed parts
pub const fn const_wdp_hash_from_parts(severity: u8, component: &[u8],
primary: &[u8], sequence: u16) -> &'static str
/// Convert u64 to base62 at compile time
pub const fn const_hash_to_base62(hash: u64) -> &'static str
/// Format sequence number at compile time
pub const fn const_format_sequence(seq: u16) -> [u8; 3]
```
---
## Configuration Loading
This crate also provides configuration loading utilities for WDP projects:
```rust
/// Load global hash configuration from Cargo.toml or environment
#[cfg(feature = "std")]
pub fn load_global_config() -> HashConfig
/// Load namespace from Cargo.toml metadata
#[cfg(feature = "std")]
pub fn load_namespace() -> Option<String>
/// Load doc generation config (formats, output directory)
#[cfg(feature = "std")]
pub fn load_doc_gen_config() -> DocGenConfig
/// Apply configuration overrides
pub fn apply_overrides(mut config: HashConfig, seed_override: Option<u64>) -> HashConfig
```
---
## Features
```toml
[features]
default = ["std"]
std = [] # Standard library support (enables config loading)
```
**Note:** xxHash3 implementation is always available. The `std` feature only affects configuration loading utilities.
---
## no_std Support
Works in `no_std` environments with `alloc`:
```toml
[dependencies]
waddling-errors-hash = { version = "0.7", default-features = false }
```
Core hashing functions work in `no_std`, but configuration loading requires `std`.
---
## FAQ
**Q: Why only xxHash3?**
A: WDP Part 5 Β§4.3 mandates a single algorithm for universal interoperability. xxHash3 was chosen for speed, distribution quality, and cross-language availability.
**Q: Can I use a different algorithm?**
A: No, if you want WDP conformance. WDP-compliant implementations MUST use xxHash3 to ensure identical Compact IDs across all systems.
**Q: Is xxHash3 secure enough?**
A: xxHash3 is NOT cryptographically secure, but that's intentional. Compact IDs are for identification, not authentication. Use cryptographic verification at the protocol layer (TLS, JWT) as recommended in WDP Part 5 Β§4.4.
**Q: Can I use custom seeds?**
A: Yes, via `compute_hash_with_config()`. This is useful for multi-tenant isolation. However, custom seeds break WDP conformanceβuse only if you don't need catalog interoperability.
**Q: Does this increase my binary size?**
A: No! Hashes are computed at compile time. Only the 5-character string constants are in your binary (~5 bytes each).
**Q: What if I need collision resistance beyond 916M?**
A: Use full structured codes (E.AUTH.TOKEN.001) in scenarios where uniqueness is critical. Compact IDs are optimized for typical projects (<5,000 error codes).
**Q: How do I verify cross-language compatibility?**
A: Use the test vectors in WDP Part 5 Β§8. All implementations should produce identical hashes for the same inputs.
---
## Contributing
Contributions welcome! Areas of interest:
- Performance optimizations
- Cross-language test vectors
- Documentation improvements
- Bug fixes
**Note:** Feature requests for alternative algorithms will be declined per WDP specification requirements.
---
## License
Licensed under either of:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
- MIT license ([LICENSE-MIT](LICENSE-MIT))
at your option.
---
## See Also
- [waddling-errors](../waddling-errors) - Core error code library
- [waddling-errors-macros](../waddling-errors-macros) - Procedural macros
- [WDP Part 5: Compact IDs](https://gitlab.com/AshutoshMahala/wdp-specs/-/blob/main/5-COMPACT-IDS.md)
- [WDP Part 7: Namespaces](https://gitlab.com/AshutoshMahala/wdp-specs/-/blob/main/7-NAMESPACES.md)
---
**Built with π¦ by the Waddling Errors team**