cardano-crypto 1.0.8

Pure Rust implementation of Cardano cryptographic primitives (VRF, KES, DSIGN, Hash) with 100% compatibility with cardano-node
Documentation
//! Test vectors for KES algorithms
//!
//! These test vectors validate compatibility with Cardano's KES implementation.
//! Vectors are derived from the cardano-base test suite and IETF specifications.
//!
//! # Example
//!
//! ```rust
//! use cardano_crypto::kes::{Sum6Kes, KesAlgorithm};
//!
//! // Test basic KES properties
//! let seed = [0u8; 32];
//! let signing_key = Sum6Kes::gen_key_kes_from_seed_bytes(&seed).unwrap();
//! let verification_key = Sum6Kes::derive_verification_key(&signing_key).unwrap();
//!
//! // Sum6Kes supports 64 periods (2^6)
//! assert_eq!(Sum6Kes::total_periods(), 64);
//!
//! // Sign at period 0
//! let message = b"test";
//! let signature = Sum6Kes::sign_kes(&(), 0, message, &signing_key).unwrap();
//! Sum6Kes::verify_kes(&(), &verification_key, 0, message, &signature).unwrap();
//! ```

#[cfg(test)]
mod tests {
    use crate::common::Result;
    use crate::dsign::Ed25519;
    use crate::kes::{KesAlgorithm, SingleKes, Sum2Kes, Sum6Kes};

    /// Test vector for SingleKES with Ed25519
    #[test]
    fn test_single_kes_deterministic() -> Result<()> {
        type TestKes = SingleKes<Ed25519>;

        // Known seed
        let seed = [42u8; 32];

        // Generate key from seed
        let sk1 = TestKes::gen_key_kes_from_seed_bytes(&seed)?;
        let vk1 = TestKes::derive_verification_key(&sk1)?;

        // Regenerate from same seed
        let sk2 = TestKes::gen_key_kes_from_seed_bytes(&seed)?;
        let vk2 = TestKes::derive_verification_key(&sk2)?;

        // Verification keys should match (Ed25519 VK has as_bytes())
        assert_eq!(vk1.as_bytes(), vk2.as_bytes());

        // Sign same message with both keys
        let message = b"test message";
        let sig1 = TestKes::sign_kes(&(), 0, message, &sk1)?;
        let sig2 = TestKes::sign_kes(&(), 0, message, &sk2)?;

        // Signatures should be deterministic (Ed25519 Sig has as_bytes())
        assert_eq!(sig1.as_bytes(), sig2.as_bytes());

        // Both signatures should verify
        TestKes::verify_kes(&(), &vk1, 0, message, &sig1)?;
        TestKes::verify_kes(&(), &vk2, 0, message, &sig2)?;

        Ok(())
    }

    /// Test vector for Sum2KES key evolution
    #[test]
    fn test_sum2_kes_evolution() -> Result<()> {
        type TestKes = Sum2Kes;

        let seed = [99u8; 32];
        let mut sk = TestKes::gen_key_kes_from_seed_bytes(&seed)?;
        let vk = TestKes::derive_verification_key(&sk)?;

        // Test all 4 periods
        for period in 0..4 {
            let message = format!("period_{}", period);

            // Sign at current period
            let sig = TestKes::sign_kes(&(), period, message.as_bytes(), &sk)?;

            // Verify signature
            TestKes::verify_kes(&(), &vk, period, message.as_bytes(), &sig)?;

            // Signature should fail for wrong period
            if period > 0 {
                let wrong_result =
                    TestKes::verify_kes(&(), &vk, period - 1, message.as_bytes(), &sig);
                assert!(wrong_result.is_err());
            }

            // Update key for next period (if not last)
            if period < 3 {
                sk = TestKes::update_kes(&(), sk, period)?
                    .expect("Key should not expire before period 3");
            }
        }

        // Key should expire after period 3
        let expired = TestKes::update_kes(&(), sk, 3)?;
        assert!(expired.is_none());

        Ok(())
    }

    /// Test vector for Sum6KES (Cardano standard)
    #[test]
    fn test_sum6_kes_cardano_standard() -> Result<()> {
        type TestKes = Sum6Kes;

        // Cardano-style seed
        let seed = [0x5F; 32];

        let sk = TestKes::gen_key_kes_from_seed_bytes(&seed)?;
        let vk = TestKes::derive_verification_key(&sk)?;

        // Test specific periods relevant to Cardano
        let test_periods = [0, 1, 31, 32, 63];

        for &period in &test_periods {
            // Create a deterministic message for this period
            let message = format!("Cardano block slot {}", period * 1000);

            // Note: We would need to update the key to the right period
            // For now, just test period 0
            if period == 0 {
                let sig = TestKes::sign_kes(&(), period, message.as_bytes(), &sk)?;
                TestKes::verify_kes(&(), &vk, period, message.as_bytes(), &sig)?;
            }
        }

        Ok(())
    }

    /// Test that verification keys remain constant across key evolution
    #[test]
    fn test_verification_key_stability() -> Result<()> {
        type TestKes = Sum2Kes;

        let seed = [7u8; 32];
        let mut sk = TestKes::gen_key_kes_from_seed_bytes(&seed)?;
        let vk_initial = TestKes::derive_verification_key(&sk)?;

        // Evolve key through all periods
        for period in 0..3 {
            let vk_current = TestKes::derive_verification_key(&sk)?;

            // Verification key should never change (both are Vec<u8> for Sum2Kes)
            assert_eq!(vk_initial, vk_current);

            sk = TestKes::update_kes(&(), sk, period)?.expect("Key should not expire");
        }

        // Check one final time at last period
        let vk_final = TestKes::derive_verification_key(&sk)?;
        assert_eq!(vk_initial, vk_final);

        Ok(())
    }

    /// Test cross-period signature validation fails correctly
    #[test]
    fn test_cross_period_validation_failure() -> Result<()> {
        type TestKes = Sum2Kes;

        let seed = [3u8; 32];
        let sk = TestKes::gen_key_kes_from_seed_bytes(&seed)?;
        let vk = TestKes::derive_verification_key(&sk)?;

        let message = b"cross period test";

        // Sign at period 0
        let sig_p0 = TestKes::sign_kes(&(), 0, message, &sk)?;

        // Verify at period 0 (should succeed)
        TestKes::verify_kes(&(), &vk, 0, message, &sig_p0)?;

        // Verify at period 1 (should fail)
        let result_p1 = TestKes::verify_kes(&(), &vk, 1, message, &sig_p0);
        assert!(result_p1.is_err());

        // Verify at period 2 (should fail)
        let result_p2 = TestKes::verify_kes(&(), &vk, 2, message, &sig_p0);
        assert!(result_p2.is_err());

        Ok(())
    }

    /// Test that wrong messages fail verification
    #[test]
    fn test_wrong_message_fails() -> Result<()> {
        type TestKes = SingleKes<Ed25519>;

        let seed = [11u8; 32];
        let sk = TestKes::gen_key_kes_from_seed_bytes(&seed)?;
        let vk = TestKes::derive_verification_key(&sk)?;

        let message1 = b"original message";
        let message2 = b"different message";

        // Sign first message
        let sig = TestKes::sign_kes(&(), 0, message1, &sk)?;

        // Verify with correct message (should succeed)
        TestKes::verify_kes(&(), &vk, 0, message1, &sig)?;

        // Verify with wrong message (should fail)
        let wrong_result = TestKes::verify_kes(&(), &vk, 0, message2, &sig);
        assert!(wrong_result.is_err());

        Ok(())
    }

    /// Test KES sizes match expected values
    #[test]
    fn test_kes_size_constants() {
        type TestSingleKes = SingleKes<Ed25519>;
        type TestSum2Kes = Sum2Kes;
        type TestSum6Kes = Sum6Kes;

        // SingleKES
        assert_eq!(TestSingleKes::SEED_SIZE, 32);
        assert_eq!(TestSingleKes::VERIFICATION_KEY_SIZE, 32);
        assert_eq!(TestSingleKes::SIGNATURE_SIZE, 64);
        assert_eq!(TestSingleKes::total_periods(), 1);

        // Sum2KES (2^2 = 4 periods)
        assert_eq!(TestSum2Kes::SEED_SIZE, 32);
        assert_eq!(TestSum2Kes::VERIFICATION_KEY_SIZE, 32); // Blake2b-256 hash
        assert_eq!(TestSum2Kes::total_periods(), 4);

        // Sum6KES (2^6 = 64 periods) - Cardano standard
        assert_eq!(TestSum6Kes::SEED_SIZE, 32);
        assert_eq!(TestSum6Kes::VERIFICATION_KEY_SIZE, 32);
        assert_eq!(TestSum6Kes::total_periods(), 64);
    }
}