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        KesPeriod, 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: KesPeriod,
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                    kes_evolutions_try,
36                    &operational_certificate.get_kes_verification_key(),
37                    message,
38                )
39                .is_ok()
40            {
41                return Ok(());
42            }
43        }
44
45        Err(KesVerifyError::SignatureInvalid(
46            kes_evolutions,
47            operational_certificate.get_start_kes_period() as u32,
48        )
49        .into())
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use crate::crypto_helper::cardano::kes::{KesSigner, KesSignerStandard};
56    use crate::current_function;
57    use crate::test::crypto_helper::{
58        KesCryptographicMaterialForTest, KesPartyIndexForTest, create_kes_cryptographic_material,
59    };
60
61    use super::*;
62
63    #[test]
64    fn verify_valid_signature_succeeds() {
65        let start_kes_period = 10 as KesPeriod;
66        let kes_evolutions = 1;
67        let signing_kes_period = start_kes_period + kes_evolutions;
68        let KesCryptographicMaterialForTest {
69            party_id: _,
70            operational_certificate_file,
71            kes_secret_key_file,
72        } = create_kes_cryptographic_material(
73            1 as KesPartyIndexForTest,
74            start_kes_period,
75            current_function!(),
76        );
77        let message = b"Test message for KES signing";
78        let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
79
80        let (signature, op_cert) = kes_signer
81            .sign(message, signing_kes_period)
82            .expect("Signing should not fail");
83
84        KesVerifierStandard
85            .verify(message, &signature, &op_cert, kes_evolutions)
86            .expect("Signature verification should not fail");
87    }
88
89    #[test]
90    fn verify_invalid_signature_fails() {
91        let start_kes_period = 10 as KesPeriod;
92        let kes_evolutions = 1;
93        let signing_kes_period = start_kes_period + kes_evolutions;
94        let KesCryptographicMaterialForTest {
95            party_id: _,
96            operational_certificate_file,
97            kes_secret_key_file,
98        } = create_kes_cryptographic_material(
99            1 as KesPartyIndexForTest,
100            start_kes_period,
101            current_function!(),
102        );
103        let message = b"Test message for KES signing";
104        let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
105        let (signature, op_cert) = kes_signer
106            .sign(message, signing_kes_period)
107            .expect("Signing should not fail");
108
109        KesVerifierStandard
110            .verify(b"Different message", &signature, &op_cert, kes_evolutions)
111            .expect_err("Signature verification should fail");
112    }
113
114    #[test]
115    fn verify_valid_signature_invalid_kes_evolutions_fails() {
116        let start_kes_period = 10 as KesPeriod;
117        let kes_evolutions = 5;
118        let signing_kes_period = start_kes_period + kes_evolutions;
119        let KesCryptographicMaterialForTest {
120            party_id: _,
121            operational_certificate_file,
122            kes_secret_key_file,
123        } = create_kes_cryptographic_material(
124            1 as KesPartyIndexForTest,
125            start_kes_period,
126            current_function!(),
127        );
128        let message = b"Test message for KES signing";
129        let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
130
131        let (signature, op_cert) = kes_signer
132            .sign(message, signing_kes_period)
133            .expect("Signing should not fail");
134
135        KesVerifierStandard
136            .verify(message, &signature, &op_cert, kes_evolutions - 2)
137            .expect_err("Signature verification should fail");
138
139        KesVerifierStandard
140            .verify(message, &signature, &op_cert, kes_evolutions - 1)
141            .expect("Signature verification should not fail");
142
143        KesVerifierStandard
144            .verify(message, &signature, &op_cert, kes_evolutions)
145            .expect("Signature verification should not fail");
146
147        KesVerifierStandard
148            .verify(message, &signature, &op_cert, kes_evolutions + 1)
149            .expect("Signature verification should not fail");
150
151        KesVerifierStandard
152            .verify(message, &signature, &op_cert, kes_evolutions + 2)
153            .expect_err("Signature verification should fail");
154    }
155}