Skip to main content

origin_crypto_sdk/
test_utils.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Test utilities for downstream users.
4//!
5//! This module provides deterministic seeds, mock key generation, and
6//! proptest strategies so users can write tests against the SDK without
7//! touching real cryptographic randomness.
8//!
9//! **Feature-gated** — only available with `features = ["test-utils"]`.
10//!
11//! # Example
12//!
13//! ```ignore
14//! use origin_crypto_sdk::test_utils::deterministic_seed;
15//!
16//! let seed = deterministic_seed(42);
17//! // Use seed for key derivation, signing, etc.
18//! ```
19
20use crate::types::Seed;
21
22/// A deterministic 32-byte seed for testing.
23///
24/// Generated from a simple PRNG seeded with the given index.
25/// NOT cryptographically secure — for tests only.
26pub fn deterministic_seed(index: u64) -> Seed {
27    let mut state = index.wrapping_add(0x9E3779B97F4A7C15);
28    let mut bytes = [0u8; 32];
29    for i in 0..32 {
30        // xorshift64
31        state ^= state << 13;
32        state ^= state >> 7;
33        state ^= state << 17;
34        bytes[i] = state as u8;
35    }
36    Seed::from(bytes)
37}
38
39/// Generate a deterministic Ed25519 signing key for testing.
40///
41/// The key is derived from a deterministic seed indexed by `index`.
42/// NOT for production use.
43pub fn deterministic_ed25519_key(index: u64) -> ed25519_dalek::SigningKey {
44    let seed = deterministic_seed(index);
45    ed25519_dalek::SigningKey::from_bytes(seed.as_bytes())
46}
47
48/// Generate a deterministic 32-byte key for testing AEAD operations.
49pub fn deterministic_key(index: u64) -> [u8; 32] {
50    *deterministic_seed(index).as_bytes()
51}
52
53/// Generate a deterministic 24-byte nonce for testing.
54pub fn deterministic_nonce_24(index: u64) -> [u8; 24] {
55    let seed = deterministic_seed(index);
56    let mut nonce = [0u8; 24];
57    nonce[..24].copy_from_slice(&seed.as_bytes()[..24]);
58    nonce
59}
60
61/// Generate a deterministic 12-byte nonce for testing.
62pub fn deterministic_nonce_12(index: u64) -> [u8; 12] {
63    let seed = deterministic_seed(index);
64    let mut nonce = [0u8; 12];
65    nonce.copy_from_slice(&seed.as_bytes()[..12]);
66    nonce
67}
68
69/// Generate a deterministic random-ish byte vector of the given length.
70pub fn deterministic_bytes(index: u64, len: usize) -> Vec<u8> {
71    let mut state = index.wrapping_add(0xCAFEBABE_DEADC0DE);
72    let mut out = Vec::with_capacity(len);
73    for _ in 0..len {
74        state ^= state << 13;
75        state ^= state >> 7;
76        state ^= state << 17;
77        out.push(state as u8);
78    }
79    out
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn test_deterministic_seed_reproducible() {
88        let s1 = deterministic_seed(42);
89        let s2 = deterministic_seed(42);
90        assert_eq!(s1.as_bytes(), s2.as_bytes());
91    }
92
93    #[test]
94    fn test_different_indices_different_seeds() {
95        let s1 = deterministic_seed(1);
96        let s2 = deterministic_seed(2);
97        assert_ne!(s1.as_bytes(), s2.as_bytes());
98    }
99
100    #[test]
101    fn test_deterministic_key_32_bytes() {
102        let key = deterministic_key(99);
103        assert_eq!(key.len(), 32);
104    }
105
106    #[test]
107    fn test_deterministic_nonce_24() {
108        let nonce = deterministic_nonce_24(7);
109        assert_eq!(nonce.len(), 24);
110    }
111
112    #[test]
113    fn test_deterministic_nonce_12() {
114        let nonce = deterministic_nonce_12(7);
115        assert_eq!(nonce.len(), 12);
116    }
117
118    #[test]
119    fn test_deterministic_bytes_length() {
120        let bytes = deterministic_bytes(0, 100);
121        assert_eq!(bytes.len(), 100);
122        assert_ne!(bytes, vec![0u8; 100]);
123    }
124}