mithril_common/crypto_helper/cardano/kes/
verifier_standard.rs

1use kes_summed_ed25519::{kes::Sum6KesSig, traits::KesSig};
2
3use crate::{
4    StdResult,
5    crypto_helper::{
6        KesEvolutions, OpCert,
7        cardano::{KesVerifier, KesVerifyError},
8    },
9};
10
11/// A standard KES signature verifier.
12#[derive(Debug)]
13pub struct KesVerifierStandard;
14
15impl KesVerifier for KesVerifierStandard {
16    /// Verify the signed message and return the original message.
17    fn verify(
18        &self,
19        message: &[u8],
20        signature: &Sum6KesSig,
21        operational_certificate: &OpCert,
22        kes_evolutions: KesEvolutions,
23    ) -> StdResult<()> {
24        operational_certificate
25            .validate()
26            .map_err(|_| KesVerifyError::OpCertInvalid)?;
27
28        // Check if the signature verifies for the provided KES evolutions value +/- 1 KES period.
29        // This is needed to account for clock skew between signer and verifier.
30        let kes_evolutions_try_min = std::cmp::max(0, kes_evolutions.saturating_sub(1));
31        let kes_evolutions_try_max = std::cmp::min(64, kes_evolutions.saturating_add(1));
32        for kes_evolutions_try in kes_evolutions_try_min..=kes_evolutions_try_max {
33            if signature
34                .verify(
35                    u32::try_from(kes_evolutions_try)
36                        .map_err(|_| KesVerifyError::InvalidKesEvolutions(kes_evolutions))?,
37                    &operational_certificate.get_kes_verification_key(),
38                    message,
39                )
40                .is_ok()
41            {
42                return Ok(());
43            }
44        }
45
46        Err(KesVerifyError::SignatureInvalid(
47            kes_evolutions,
48            operational_certificate.get_start_kes_period(),
49        )
50        .into())
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use crate::crypto_helper::KesPeriod;
57    use crate::crypto_helper::cardano::kes::{KesSigner, KesSignerStandard};
58    use crate::current_function;
59    use crate::test::crypto_helper::{
60        KesCryptographicMaterialForTest, KesPartyIndexForTest, create_kes_cryptographic_material,
61    };
62
63    use super::*;
64
65    #[test]
66    fn verify_valid_signature_succeeds() {
67        let start_kes_period = KesPeriod(10);
68        let kes_evolutions = KesEvolutions(1);
69        let signing_kes_period = start_kes_period + kes_evolutions;
70        let KesCryptographicMaterialForTest {
71            party_id: _,
72            operational_certificate_file,
73            kes_secret_key_file,
74        } = create_kes_cryptographic_material(
75            1 as KesPartyIndexForTest,
76            start_kes_period,
77            current_function!(),
78        );
79        let message = b"Test message for KES signing";
80        let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
81
82        let (signature, op_cert) = kes_signer
83            .sign(message, signing_kes_period)
84            .expect("Signing should not fail");
85
86        KesVerifierStandard
87            .verify(message, &signature, &op_cert, kes_evolutions)
88            .expect("Signature verification should not fail");
89    }
90
91    #[test]
92    fn verify_invalid_signature_fails() {
93        let start_kes_period = KesPeriod(10);
94        let kes_evolutions = KesEvolutions(1);
95        let signing_kes_period = start_kes_period + kes_evolutions;
96        let KesCryptographicMaterialForTest {
97            party_id: _,
98            operational_certificate_file,
99            kes_secret_key_file,
100        } = create_kes_cryptographic_material(
101            1 as KesPartyIndexForTest,
102            start_kes_period,
103            current_function!(),
104        );
105        let message = b"Test message for KES signing";
106        let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
107        let (signature, op_cert) = kes_signer
108            .sign(message, signing_kes_period)
109            .expect("Signing should not fail");
110
111        KesVerifierStandard
112            .verify(b"Different message", &signature, &op_cert, kes_evolutions)
113            .expect_err("Signature verification should fail");
114    }
115
116    #[test]
117    fn verify_valid_signature_invalid_kes_evolutions_fails() {
118        let start_kes_period = KesPeriod(10);
119        let kes_evolutions = KesEvolutions(5);
120        let signing_kes_period = start_kes_period + kes_evolutions;
121        let KesCryptographicMaterialForTest {
122            party_id: _,
123            operational_certificate_file,
124            kes_secret_key_file,
125        } = create_kes_cryptographic_material(
126            1 as KesPartyIndexForTest,
127            start_kes_period,
128            current_function!(),
129        );
130        let message = b"Test message for KES signing";
131        let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
132
133        let (signature, op_cert) = kes_signer
134            .sign(message, signing_kes_period)
135            .expect("Signing should not fail");
136
137        KesVerifierStandard
138            .verify(message, &signature, &op_cert, kes_evolutions - 2)
139            .expect_err("Signature verification should fail");
140
141        KesVerifierStandard
142            .verify(message, &signature, &op_cert, kes_evolutions - 1)
143            .expect("Signature verification should not fail");
144
145        KesVerifierStandard
146            .verify(message, &signature, &op_cert, kes_evolutions)
147            .expect("Signature verification should not fail");
148
149        KesVerifierStandard
150            .verify(message, &signature, &op_cert, kes_evolutions + 1)
151            .expect("Signature verification should not fail");
152
153        KesVerifierStandard
154            .verify(message, &signature, &op_cert, kes_evolutions + 2)
155            .expect_err("Signature verification should fail");
156
157        KesVerifierStandard
158            .verify(message, &signature, &op_cert, KesEvolutions(u64::MAX))
159            .expect_err("Signature verification should fail");
160    }
161}