vrf-wasm 0.9.1

VRF for WASM environments
Documentation
pub mod ristretto255_tests;
pub mod vrf_tests;
pub mod test_helpers;

#[cfg(test)]
mod conditional_compilation_tests {
    use crate::rng;
    use rand_core::RngCore;

    #[test]
    fn test_rng_implementation_selection() {
        let implementation = rng::get_rng_implementation();

        // Test the priority system:
        // 1. browser feature takes priority when both are enabled (or is default)
        // 2. near feature is used only when browser is explicitly disabled

        #[cfg(all(feature = "browser", feature = "near"))]
        assert_eq!(implementation, "browser", "Browser should take priority when both features are enabled");

        #[cfg(all(feature = "browser", not(feature = "near")))]
        assert_eq!(implementation, "browser", "Browser should be used when only browser feature is enabled");

        #[cfg(all(feature = "near", not(feature = "browser")))]
        assert_eq!(implementation, "near", "NEAR should be used when only near feature is enabled");

        println!("Using RNG implementation: {}", implementation);
    }

    #[test]
    fn test_rng_functionality() {

        // Create RNG instance based on the implementation
        #[cfg(feature = "browser")]
        let mut rng = rng::WasmRng;

        // NOTE: defaults to browser based RNG for tests even when near feature is enabled
        // We don't have near_workspace dependency added, so near testes would fail annyway
        #[cfg(feature = "near")]
        let mut rng = rng::WasmRng::default();

        // Test that we can generate different values
        let val1 = rng.next_u32();
        let val2 = rng.next_u32();

        // Very unlikely to be equal (though theoretically possible)
        // This is just a basic smoke test
        println!("Generated values: {} and {}", val1, val2);

        // Test fill_bytes
        let mut buffer = [0u8; 16];
        rng.fill_bytes(&mut buffer);

        // Should not be all zeros (extremely unlikely)
        assert_ne!(buffer, [0u8; 16]);
        println!("Generated bytes: {:?}", buffer);
    }

    #[test]
    fn test_seeded_rng() {
        use rand_core::SeedableRng;

        let seed = [42u8; 32];
        let mut rng1 = rng::WasmRngFromSeed::from_seed(seed);
        let mut rng2 = rng::WasmRngFromSeed::from_seed(seed);

        // Same seed should produce same values
        assert_eq!(rng1.next_u32(), rng2.next_u32());
        assert_eq!(rng1.next_u64(), rng2.next_u64());

        println!("Seeded RNG test passed for implementation: {}", rng::get_rng_implementation());
    }
}

#[cfg(test)]
mod vrf_component_tests {
    use crate::vrf::ecvrf::{ECVRFKeyPair, ECVRFProof};
    use crate::vrf::{VRFKeyPair, VRFProof};
    use crate::serde_helpers::ToFromByteArray;
    use crate::rng;

    #[test]
    fn test_component_extraction() {

        // Create RNG instance based on the implementation
        #[cfg(feature = "browser")]
        let mut rng = rng::WasmRng;

        // NOTE: defaults to browser based RNG for tests even when near feature is enabled
        // We don't have near_workspace dependency added, so near testes would fail annyway
        #[cfg(feature = "near")]
        let mut rng = rng::WasmRng::default();

        // Generate a keypair and proof
        let keypair = ECVRFKeyPair::generate(&mut rng);
        let input = b"test input for component extraction";
        let proof = keypair.prove(input);

        // Extract components using new methods
        let gamma_bytes = proof.gamma_bytes();
        let challenge_bytes = proof.challenge_bytes();
        let scalar_bytes = proof.scalar_bytes();

        // Extract all components at once
        let (gamma_all, challenge_all, scalar_all) = proof.to_components();

        // Verify individual extractions match bulk extraction
        assert_eq!(gamma_bytes, gamma_all);
        assert_eq!(challenge_bytes, challenge_all);
        assert_eq!(scalar_bytes, scalar_all);

        // Verify expected lengths
        assert_eq!(gamma_bytes.len(), 32);
        assert_eq!(challenge_bytes.len(), 16);
        assert_eq!(scalar_bytes.len(), 32);

        println!("✓ Component extraction works correctly");
        println!("  Gamma: {} bytes", gamma_bytes.len());
        println!("  Challenge: {} bytes", challenge_bytes.len());
        println!("  Scalar: {} bytes", scalar_bytes.len());
    }

    #[test]
    fn test_proof_reconstruction() {

        // Create RNG instance based on the implementation
        #[cfg(feature = "browser")]
        let mut rng = rng::WasmRng;

        // NOTE: defaults to browser based RNG for tests even when near feature is enabled
        // We don't have near_workspace dependency added, so near testes would fail annyway
        #[cfg(feature = "near")]
        let mut rng = rng::WasmRng::default();

        // Generate a keypair and proof
        let keypair = ECVRFKeyPair::generate(&mut rng);
        let input = b"test input for proof reconstruction";
        let original_proof = keypair.prove(input);

        // Extract components
        let (gamma_bytes, challenge_bytes, scalar_bytes) = original_proof.to_components();

        // Reconstruct proof from components
        let reconstructed_proof = ECVRFProof::from_components(
            &gamma_bytes,
            &challenge_bytes,
            &scalar_bytes,
        ).expect("Failed to reconstruct proof from components");

        // Verify reconstructed proof works
        assert!(reconstructed_proof.verify(input, &keypair.pk).is_ok());

        // Verify proofs are equivalent
        assert_eq!(original_proof.gamma_bytes(), reconstructed_proof.gamma_bytes());
        assert_eq!(original_proof.challenge_bytes(), reconstructed_proof.challenge_bytes());
        assert_eq!(original_proof.scalar_bytes(), reconstructed_proof.scalar_bytes());

        // Verify they produce the same hash
        assert_eq!(original_proof.to_hash(), reconstructed_proof.to_hash());

        println!("✓ Proof reconstruction from components works correctly");
        println!("  Original and reconstructed proofs are functionally identical");
    }

    #[test]
    fn test_direct_field_access() {
        // Create RNG instance based on the implementation
        #[cfg(feature = "browser")]
        let mut rng_instance = rng::WasmRng;

        #[cfg(feature = "near")]
        let mut rng_instance = rng::WasmRng::default();

        // Generate a keypair and proof
        let keypair = ECVRFKeyPair::generate(&mut rng_instance);
        let input = b"test input for direct field access";
        let proof = keypair.prove(input);

        // Test that we can directly access the public fields
        let _gamma = proof.gamma;
        let _challenge = proof.c;
        let _scalar = proof.s;

        // Test that direct access gives same results as helper methods
        assert_eq!(proof.gamma.compress(), proof.gamma_bytes());
        assert_eq!(proof.c.0, proof.challenge_bytes());
        assert_eq!(proof.s.to_byte_array(), proof.scalar_bytes());

        println!("✓ Direct field access works correctly");
        println!("  Public fields are accessible and consistent with helper methods");
    }
}