Skip to main content

ironshield_core/
lib.rs

1//! # Core functionality for the IronShield proof-of-work system.
2//!
3//! This module contains shared code that can be used in both
4//! the server-side (Cloudflare Workers) and client-side (WASM) implementations
5
6pub use ironshield_types::*; // Re-export types from ironshield-types
7
8mod solve;
9mod verify;
10
11#[cfg(any(feature = "wasm", rust_analyzer))]
12pub mod js;
13
14// Re-export public functions from modules
15pub use solve::PoWConfig;
16pub use solve::find_solution;
17pub use solve::execute_proof_of_work;
18pub use verify::verify_ironshield_solution;
19
20#[cfg(any(feature = "wasm", rust_analyzer))]
21pub use js::*;
22
23#[cfg(test)]
24mod tests {
25    use super::*;
26
27    #[test]
28    fn test_ironshield_challenge_creation() {
29        let dummy_key = SigningKey::from_bytes(&[0u8; 32]);
30        let challenge = IronShieldChallenge::new(
31            "test_website".to_string(),
32            1, // Very high threshold - should be easy to find solution
33            dummy_key,
34            [0x00; 32],
35        );
36        assert_eq!(challenge.website_id, "test_website");
37        assert_ne!(challenge.challenge_param, [0u8; 32]);
38    }
39
40    #[test]
41    fn test_serde_serialization() {
42        let dummy_key = SigningKey::from_bytes(&[0u8; 32]);
43        let challenge: IronShieldChallenge = IronShieldChallenge::new(
44            "test_website".to_string(),
45            1000,
46            dummy_key,
47            [0x34; 32],
48        );
49
50        // Test serialization
51        let serialized = serde_json::to_string(&challenge).unwrap();
52        assert!(!serialized.is_empty());
53
54        // Test deserialization
55        let deserialized: IronShieldChallenge = serde_json::from_str(&serialized).unwrap();
56        assert_eq!(deserialized.challenge_param, challenge.challenge_param);
57        assert_eq!(deserialized.public_key, challenge.public_key);
58        assert_eq!(deserialized.challenge_signature, challenge.challenge_signature);
59    }
60
61    #[test]
62    fn test_recommended_attempts() {
63        // Test the new recommended_attempts function
64        assert_eq!(IronShieldChallenge::recommended_attempts(1000), 2000);
65        assert_eq!(IronShieldChallenge::recommended_attempts(50000), 100000);
66        assert_eq!(IronShieldChallenge::recommended_attempts(0), 0);
67
68        // Test overflow protection
69        assert_eq!(IronShieldChallenge::recommended_attempts(u64::MAX), u64::MAX);
70    }
71
72    #[test]
73    fn test_difficulty_to_challenge_param() {
74        // Test that our difficulty conversion works correctly
75
76        // Very easy case
77        let challenge_param = IronShieldChallenge::difficulty_to_challenge_param(1);
78        assert_eq!(challenge_param, [0xFF; 32]);
79
80        // Test zero difficulty panics
81        let result = std::panic::catch_unwind(|| {
82            IronShieldChallenge::difficulty_to_challenge_param(0);
83        });
84        assert!(result.is_err(), "Zero difficulty should panic");
85
86        // Test some practical values produce valid outputs
87        let challenge_param_256 = IronShieldChallenge::difficulty_to_challenge_param(256);
88        assert_ne!(challenge_param_256, [0; 32]);
89        assert_ne!(challenge_param_256, [0xFF; 32]);
90
91        let challenge_param_1024 = IronShieldChallenge::difficulty_to_challenge_param(1024);
92        assert_ne!(challenge_param_1024, [0; 32]);
93        assert_ne!(challenge_param_1024, [0xFF; 32]);
94
95        // Test very high difficulty - this produces a very small target, not all zeros
96        let challenge_param_max = IronShieldChallenge::difficulty_to_challenge_param(u64::MAX);
97        // For max difficulty, the target should be very small but not necessarily all zeros
98        // since the function uses bit manipulation logic
99        assert_ne!(challenge_param_max, [0xFF; 32], "Maximum difficulty should not produce all FFs");
100
101        // Test that the function produces consistent results
102        let challenge_param_test = IronShieldChallenge::difficulty_to_challenge_param(1000);
103        let challenge_param_test2 = IronShieldChallenge::difficulty_to_challenge_param(1000);
104        assert_eq!(challenge_param_test, challenge_param_test2, "Function should be deterministic");
105    }
106
107    // Integration test that verifies the solve and verify modules work together
108    #[test]
109    fn test_solve_verify_integration() {
110        let dummy_key = SigningKey::from_bytes(&[0u8; 32]);
111        let challenge = IronShieldChallenge::new(
112            "test_website".to_string(),
113            1, // Easy difficulty
114            dummy_key,
115            [0x00; 32],
116        );
117
118        // Solve the challenge
119        let result = find_solution(&challenge, None, None, None, None);
120        assert!(result.is_ok(), "Should find solution for integration test");
121
122        let response = result.unwrap();
123
124        // Verify the solution using the IronShield verification
125        assert!(verify_ironshield_solution(&response),
126                "IronShield verification should confirm the solution is valid");
127
128        // Verify response structure
129        assert_eq!(response.solved_challenge.challenge_signature, challenge.challenge_signature);
130        assert!(response.solution >= 0, "Solution should be non-negative");
131    }
132
133    // Integration test for the new IronShield algorithm
134    #[test]
135    fn test_ironshield_solve_verify_integration() {
136        let dummy_key = SigningKey::from_bytes(&[0u8; 32]);
137        // Use the same parameters as the working test in solve.rs
138        let challenge = IronShieldChallenge::new(
139            "test_website".to_string(),
140            1, // Very easy difficulty - should find solution quickly
141            dummy_key,
142            [0x00; 32],
143        );
144
145        // Solve the challenge
146        let result = find_solution(&challenge, None, None, None, None);
147        assert!(result.is_ok(), "Should find solution for IronShield integration test");
148
149        let response = result.unwrap();
150
151        // Verify the solution
152        assert!(verify_ironshield_solution(&response),
153                "IronShield verification should confirm the solution is valid");
154
155        // Verify response structure
156        assert_eq!(response.solved_challenge.challenge_signature, challenge.challenge_signature);
157        assert!(response.solution >= 0, "Solution should be non-negative");
158    }
159
160    // Integration test for the multi-threaded IronShield algorithm
161    #[test]
162
163    fn test_ironshield_multi_threaded_solve_verify_integration() {
164        let dummy_key = SigningKey::from_bytes(&[0u8; 32]);
165        // Use the same parameters as the working test in solve.rs
166        let challenge = IronShieldChallenge::new(
167            "test_website".to_string(),
168            1, // Very easy difficulty - should find solution quickly
169            dummy_key,
170            [0x00; 32],
171        );
172
173        // Solve the challenge using multi-threaded version
174        let result = find_solution(&challenge, None, None, None, None);
175        assert!(result.is_ok(), "Should find solution for IronShield multi-threaded integration test");
176
177        let response = result.unwrap();
178
179        // Verify the solution
180        assert!(verify_ironshield_solution(&response),
181                "IronShield multi-threaded verification should confirm the solution is valid");
182
183        // Verify response structure
184        assert_eq!(response.solved_challenge.challenge_signature, challenge.challenge_signature);
185        assert!(response.solution >= 0, "Solution should be non-negative");
186    }
187}