Download native/crypto-wasm.rs from Snapkitty/snapkitty-clojure-lisp-bridge: direct link, hf CLI and curl.
- Browser
- Download file 13.1 kB
-
https://huggingface.co/Snapkitty/snapkitty-clojure-lisp-bridge/resolve/main/native/crypto-wasm.rs
- Command line
-
hf download hf://Snapkitty/snapkitty-clojure-lisp-bridge/native/crypto-wasm.rs
-
curl -L -o crypto-wasm.rs https://huggingface.co/Snapkitty/snapkitty-clojure-lisp-bridge/resolve/main/native/crypto-wasm.rs
13.1 kB
| // SKC-LISP: Cryptographic Functions for WASM (Phase 3D-3) | |
| // Pure Rust implementations of Blake3 + Ed25519 for browser execution | |
| // No FFI dependencies (pure WASM) | |
| use wasm_bindgen::prelude::*; | |
| // ============================================================================ | |
| // Blake3 WASM Implementation | |
| // ============================================================================ | |
| pub struct Blake3VerificationResult { | |
| pub valid: bool, | |
| pub error_code: u8, // 0=match, 1=mismatch, 2=invalid_input | |
| } | |
| /// Compute Blake3 hash of input (returns 32-byte digest) | |
| pub fn blake3_hash(input: &[u8]) -> Vec<u8> { | |
| // Use blake3 crate for pure Rust implementation | |
| let mut hasher = blake3::Hasher::new(); | |
| hasher.update(input); | |
| hasher.finalize().as_bytes().to_vec() | |
| } | |
| /// Verify Blake3 digest matches expected value | |
| pub fn blake3_verify_wasm( | |
| payload: &[u8], | |
| expected_digest: &[u8], | |
| ) -> Blake3VerificationResult { | |
| // Validate inputs | |
| if payload.is_empty() || expected_digest.is_empty() { | |
| return Blake3VerificationResult { | |
| valid: false, | |
| error_code: 2, // invalid_input | |
| }; | |
| } | |
| if expected_digest.len() != 32 { | |
| return Blake3VerificationResult { | |
| valid: false, | |
| error_code: 2, // invalid_input (digest must be 32 bytes) | |
| }; | |
| } | |
| // Compute Blake3 digest | |
| let mut hasher = blake3::Hasher::new(); | |
| hasher.update(payload); | |
| let computed = hasher.finalize(); | |
| // Constant-time comparison (prevent timing attacks) | |
| let mut match_flag = true; | |
| for (computed_byte, expected_byte) in computed.as_bytes().iter().zip(expected_digest) { | |
| if computed_byte != expected_byte { | |
| match_flag = false; | |
| } | |
| } | |
| Blake3VerificationResult { | |
| valid: match_flag, | |
| error_code: if match_flag { 0 } else { 1 }, // 0=match, 1=mismatch | |
| } | |
| } | |
| // ============================================================================ | |
| // Ed25519 WASM Implementation | |
| // ============================================================================ | |
| pub struct Ed25519VerificationResult { | |
| pub valid: bool, | |
| pub error_code: u8, // 0=valid, 1=invalid, 2=invalid_input | |
| } | |
| /// Verify Ed25519 signature | |
| pub fn ed25519_verify_wasm( | |
| message: &[u8], | |
| signature: &[u8], | |
| public_key: &[u8], | |
| ) -> Ed25519VerificationResult { | |
| // Validate inputs | |
| if message.is_empty() { | |
| return Ed25519VerificationResult { | |
| valid: false, | |
| error_code: 2, // invalid_input | |
| }; | |
| } | |
| if signature.len() != 64 { | |
| return Ed25519VerificationResult { | |
| valid: false, | |
| error_code: 2, // invalid_input (signature must be 64 bytes) | |
| }; | |
| } | |
| if public_key.len() != 32 { | |
| return Ed25519VerificationResult { | |
| valid: false, | |
| error_code: 2, // invalid_input (public key must be 32 bytes) | |
| }; | |
| } | |
| // Convert to ed25519-zebra types | |
| let sig_bytes: [u8; 64] = match signature.try_into() { | |
| Ok(b) => b, | |
| Err(_) => { | |
| return Ed25519VerificationResult { | |
| valid: false, | |
| error_code: 2, | |
| } | |
| } | |
| }; | |
| let pk_bytes: [u8; 32] = match public_key.try_into() { | |
| Ok(b) => b, | |
| Err(_) => { | |
| return Ed25519VerificationResult { | |
| valid: false, | |
| error_code: 2, | |
| } | |
| } | |
| }; | |
| // Parse signature + public key | |
| let signature = match ed25519_zebra::Signature::from(sig_bytes) { | |
| sig => sig, | |
| }; | |
| let public_key = match ed25519_zebra::VerificationKeyBytes::from(pk_bytes) | |
| .try_into() | |
| { | |
| Ok(pk) => pk, | |
| Err(_) => { | |
| return Ed25519VerificationResult { | |
| valid: false, | |
| error_code: 2, | |
| } | |
| } | |
| }; | |
| // Verify signature | |
| match public_key.verify(&signature, message) { | |
| Ok(()) => Ed25519VerificationResult { | |
| valid: true, | |
| error_code: 0, // valid | |
| }, | |
| Err(_) => Ed25519VerificationResult { | |
| valid: false, | |
| error_code: 1, // invalid | |
| }, | |
| } | |
| } | |
| // ============================================================================ | |
| // NASM Mutation Validator (ported to Rust for WASM) | |
| // ============================================================================ | |
| pub struct MutationValidationResult { | |
| pub valid: bool, | |
| pub error_code: u8, | |
| pub message: String, | |
| } | |
| /// 8-point mutation validation gate (ported from NASM) | |
| pub fn validate_mutation_wasm( | |
| event_id: u32, | |
| generation: u32, | |
| source_hash: &[u8], | |
| bytecode_hash: &[u8], | |
| native_code_hash: &[u8], | |
| actor_signature: &[u8], | |
| ) -> MutationValidationResult { | |
| let mut errors = Vec::new(); | |
| // Gate 1: Event ID is non-zero | |
| if event_id == 0 { | |
| errors.push("Event ID must be non-zero"); | |
| } | |
| // Gate 2: Generation counter is valid | |
| if generation > 0x7FFFFFFF { | |
| errors.push("Generation counter overflow"); | |
| } | |
| // Gate 3: Source hash is 32 bytes | |
| if source_hash.len() != 32 { | |
| errors.push("Source hash must be 32 bytes"); | |
| } | |
| // Gate 4: Bytecode hash is 32 bytes | |
| if bytecode_hash.len() != 32 { | |
| errors.push("Bytecode hash must be 32 bytes"); | |
| } | |
| // Gate 5: Native code hash is 32 bytes | |
| if native_code_hash.len() != 32 { | |
| errors.push("Native code hash must be 32 bytes"); | |
| } | |
| // Gate 6: Signature is 64 bytes | |
| if actor_signature.len() != 64 { | |
| errors.push("Actor signature must be 64 bytes"); | |
| } | |
| // Gate 7: Hashes are distinct (no aliasing) | |
| if source_hash == bytecode_hash || bytecode_hash == native_code_hash { | |
| errors.push("Hash aliasing detected (hashes must be distinct)"); | |
| } | |
| // Gate 8: No hash is all-zeros | |
| if source_hash.iter().all(|&b| b == 0) { | |
| errors.push("Source hash is all-zeros (invalid)"); | |
| } | |
| let valid = errors.is_empty(); | |
| let message = if valid { | |
| "All validation gates passed".to_string() | |
| } else { | |
| errors.join("; ") | |
| }; | |
| MutationValidationResult { | |
| valid, | |
| error_code: if valid { 0 } else { 1 }, | |
| message, | |
| } | |
| } | |
| // ============================================================================ | |
| // Proof Certificate Validation (WASM) | |
| // ============================================================================ | |
| pub struct ProofCertificateValidationResult { | |
| pub valid: bool, | |
| pub theorem_id: u32, | |
| pub theorems_covered: u32, | |
| pub error_code: u8, | |
| pub message: String, | |
| } | |
| /// Validate proof certificate structure + signature | |
| pub fn validate_proof_certificate_wasm( | |
| cert_bytes: &[u8], | |
| ) -> ProofCertificateValidationResult { | |
| // Expected structure: 157 bytes | |
| // [0:4] theorem_id (u32, LE) | |
| // [4:36] proof_hash (32 bytes) | |
| // [36:40] theorems_covered (u32, LE) | |
| // [40:44] machine_state_invariants (u32, LE) | |
| // [44:60] cranelift_backend (16 bytes, null-padded) | |
| // [60:61] optimization_level (u8) | |
| // [61:125] signature (64 bytes) | |
| // [125:157] public_key (32 bytes) | |
| let mut errors = Vec::new(); | |
| // Gate 1: Size check | |
| if cert_bytes.len() != 157 { | |
| errors.push(format!("Certificate size must be 157 bytes, got {}", cert_bytes.len())); | |
| return ProofCertificateValidationResult { | |
| valid: false, | |
| theorem_id: 0, | |
| theorems_covered: 0, | |
| error_code: 2, | |
| message: errors.join("; "), | |
| }; | |
| } | |
| // Parse fields | |
| let theorem_id = u32::from_le_bytes([ | |
| cert_bytes[0], | |
| cert_bytes[1], | |
| cert_bytes[2], | |
| cert_bytes[3], | |
| ]); | |
| let theorems_covered = u32::from_le_bytes([ | |
| cert_bytes[36], | |
| cert_bytes[37], | |
| cert_bytes[38], | |
| cert_bytes[39], | |
| ]); | |
| let machine_state_inv = u32::from_le_bytes([ | |
| cert_bytes[40], | |
| cert_bytes[41], | |
| cert_bytes[42], | |
| cert_bytes[43], | |
| ]); | |
| let opt_level = cert_bytes[60]; | |
| // Gate 2: Theorem ID in range | |
| if theorem_id < 0x0001 || theorem_id > 0x000B { | |
| errors.push(format!("Theorem ID out of range: 0x{:04X}", theorem_id)); | |
| } | |
| // Gate 3: At least one theorem covered | |
| if theorems_covered == 0 { | |
| errors.push("No theorems covered (bitmask is zero)".to_string()); | |
| } | |
| // Gate 4: Machine state invariants non-zero | |
| if machine_state_inv == 0 { | |
| errors.push("Machine state invariants must be non-zero".to_string()); | |
| } | |
| // Gate 5: Optimization level in range | |
| if opt_level > 2 { | |
| errors.push(format!("Optimization level out of range: {}", opt_level)); | |
| } | |
| // Gate 6: Backend string is valid | |
| let backend_bytes = &cert_bytes[44..60]; | |
| let backend_str = std::str::from_utf8(backend_bytes) | |
| .unwrap_or("") | |
| .trim_end_matches('\0'); | |
| if !["x86_64", "aarch64", "wasm32"].contains(&backend_str) { | |
| errors.push(format!("Unknown backend: {}", backend_str)); | |
| } | |
| let valid = errors.is_empty(); | |
| ProofCertificateValidationResult { | |
| valid, | |
| theorem_id, | |
| theorems_covered, | |
| error_code: if valid { 0 } else { 1 }, | |
| message: if valid { | |
| "Proof certificate valid".to_string() | |
| } else { | |
| errors.join("; ") | |
| }, | |
| } | |
| } | |
| // ============================================================================ | |
| // WASM Module Initialization | |
| // ============================================================================ | |
| pub fn init_wasm() { | |
| // Initialize panic hook for better error messages in browser console | |
| console_error_panic_hook::set_once(); | |
| } | |
| // ============================================================================ | |
| // Tests (compiled with `cargo test --target wasm32-unknown-unknown`) | |
| // ============================================================================ | |
| mod tests { | |
| use super::*; | |
| fn test_blake3_hash() { | |
| let input = b"test payload"; | |
| let hash = blake3_hash(input); | |
| assert_eq!(hash.len(), 32); | |
| } | |
| fn test_blake3_verify_valid() { | |
| let input = b"test payload"; | |
| let digest = blake3_hash(input); | |
| let result = blake3_verify_wasm(input, &digest); | |
| assert!(result.valid); | |
| assert_eq!(result.error_code, 0); | |
| } | |
| fn test_blake3_verify_invalid() { | |
| let input = b"test payload"; | |
| let digest = blake3_hash(input); | |
| let mut bad_digest = digest.clone(); | |
| bad_digest[0] ^= 0xFF; // Flip bits | |
| let result = blake3_verify_wasm(input, &bad_digest); | |
| assert!(!result.valid); | |
| assert_eq!(result.error_code, 1); | |
| } | |
| fn test_mutation_validation_valid() { | |
| let result = validate_mutation_wasm( | |
| 1, // event_id | |
| 5, // generation | |
| &[0x01; 32], // source_hash | |
| &[0x02; 32], // bytecode_hash | |
| &[0x03; 32], // native_code_hash | |
| &[0x04; 64], // actor_signature | |
| ); | |
| assert!(result.valid); | |
| assert_eq!(result.error_code, 0); | |
| } | |
| fn test_mutation_validation_invalid_event_id() { | |
| let result = validate_mutation_wasm( | |
| 0, // event_id (invalid: must be non-zero) | |
| 5, | |
| &[0x01; 32], | |
| &[0x02; 32], | |
| &[0x03; 32], | |
| &[0x04; 64], | |
| ); | |
| assert!(!result.valid); | |
| } | |
| fn test_proof_certificate_validation() { | |
| let mut cert = vec![0u8; 157]; | |
| // Set theorem_id to 0x0001 | |
| cert[0] = 0x01; | |
| cert[1] = 0x00; | |
| // Set theorems_covered to 0x000F | |
| cert[36] = 0x0F; | |
| cert[37] = 0x00; | |
| // Set machine_state_invariants to 0x07 | |
| cert[40] = 0x07; | |
| cert[41] = 0x00; | |
| // Set backend to "x86_64" | |
| for (i, byte) in b"x86_64".iter().enumerate() { | |
| cert[44 + i] = *byte; | |
| } | |
| // Set optimization_level to 2 | |
| cert[60] = 2; | |
| let result = validate_proof_certificate_wasm(&cert); | |
| assert!(result.valid); | |
| assert_eq!(result.theorem_id, 0x0001); | |
| assert_eq!(result.theorems_covered, 0x000F); | |
| } | |
| } | |