mithril_common/crypto_helper/cardano/kes/
signer_with_key.rs1use std::path::PathBuf;
2
3use anyhow::{Context, anyhow};
4use kes_summed_ed25519::{
5 kes::{Sum6Kes, Sum6KesSig},
6 traits::KesSk,
7};
8
9use crate::{
10 StdResult,
11 crypto_helper::{
12 KesPeriod, OpCert, SerDeShelleyFileFormat, Sum6KesBytes,
13 cardano::{KesSignError, KesSigner},
14 },
15};
16
17pub struct KesSignerStandard {
19 kes_sk_path: PathBuf,
20 operational_certificate_path: PathBuf,
21}
22
23impl KesSignerStandard {
24 pub fn new(kes_sk_path: PathBuf, operational_certificate_path: PathBuf) -> Self {
26 Self {
27 kes_sk_path,
28 operational_certificate_path,
29 }
30 }
31}
32
33impl KesSigner for KesSignerStandard {
34 fn sign(
35 &self,
36 message: &[u8],
37 current_kes_period: KesPeriod,
38 ) -> StdResult<(Sum6KesSig, OpCert)> {
39 let mut kes_sk_bytes = Sum6KesBytes::from_file(&self.kes_sk_path)
40 .with_context(|| "StandardKesSigner can not read KES secret key from file")?;
41 let mut kes_sk = Sum6Kes::try_from(&mut kes_sk_bytes)
42 .with_context(|| "StandardKesSigner can not use KES secret key")?;
43 let operational_certificate = OpCert::from_file(&self.operational_certificate_path)
44 .with_context(|| "StandardKesSigner can not read operational certificate from file")?;
45 let kes_period_start = operational_certificate.get_start_kes_period() as u32;
46 if kes_period_start > current_kes_period {
47 return Err(anyhow!(KesSignError::PeriodMismatch(
48 kes_period_start,
49 current_kes_period
50 )));
51 }
52 let kes_evolutions = current_kes_period.saturating_sub(kes_period_start);
53
54 for evolution in 0..kes_evolutions {
56 kes_sk.update().map_err(|_| KesSignError::UpdateKey(evolution))?;
57 }
58
59 Ok((kes_sk.sign(message), operational_certificate))
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 use crate::crypto_helper::cardano::kes::{KesVerifier, KesVerifierStandard};
68 use crate::current_function;
69 use crate::test::crypto_helper::{
70 KesCryptographicMaterialForTest, KesPartyIndexForTest, create_kes_cryptographic_material,
71 };
72
73 #[test]
74 fn create_valid_signature_for_message() {
75 let start_kes_period = 10 as KesPeriod;
76 let kes_evolutions = 32;
77 let signing_kes_period = start_kes_period + kes_evolutions;
78 let KesCryptographicMaterialForTest {
79 party_id: _,
80 operational_certificate_file,
81 kes_secret_key_file,
82 } = create_kes_cryptographic_material(
83 1 as KesPartyIndexForTest,
84 start_kes_period,
85 current_function!(),
86 );
87 let message = b"Test message for KES signing";
88 let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
89
90 let (signature, op_cert) = kes_signer
91 .sign(message, signing_kes_period)
92 .expect("Signing should not fail");
93
94 KesVerifierStandard
95 .verify(message, &signature, &op_cert, kes_evolutions)
96 .expect("Signature verification should not fail");
97 }
98
99 #[test]
100 fn create_invalid_signature_for_different_message() {
101 let start_kes_period = 10 as KesPeriod;
102 let kes_evolutions = 32;
103 let signing_kes_period = start_kes_period + kes_evolutions;
104 let KesCryptographicMaterialForTest {
105 party_id: _,
106 operational_certificate_file,
107 kes_secret_key_file,
108 } = create_kes_cryptographic_material(
109 1 as KesPartyIndexForTest,
110 start_kes_period,
111 current_function!(),
112 );
113 let message = b"Test message for KES signing";
114 let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
115
116 let (signature, op_cert) = kes_signer
117 .sign(message, signing_kes_period)
118 .expect("Signing should not fail");
119
120 KesVerifierStandard
121 .verify(b"Different message", &signature, &op_cert, kes_evolutions)
122 .expect_err("Signature verification should fail");
123 }
124
125 #[test]
126 fn create_invalid_signature_for_invalid_current_kes_period() {
127 let start_kes_period = 10 as KesPeriod;
128 let signing_kes_period = 5;
129 let KesCryptographicMaterialForTest {
130 party_id: _,
131 operational_certificate_file,
132 kes_secret_key_file,
133 } = create_kes_cryptographic_material(
134 1 as KesPartyIndexForTest,
135 start_kes_period,
136 current_function!(),
137 );
138 let message = b"Test message for KES signing";
139 let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
140
141 let res = kes_signer
142 .sign(message, signing_kes_period)
143 .expect_err("Signing should fail");
144 assert_eq!(
145 res.downcast_ref::<KesSignError>(),
146 Some(&KesSignError::PeriodMismatch(
147 start_kes_period,
148 signing_kes_period
149 ))
150 );
151 }
152
153 #[test]
154 fn create_invalid_signature_for_invalid_kes_evolutions() {
155 const MAX_KES_EVOLUTIONS: KesPeriod = 63;
156 let start_kes_period = 10 as KesPeriod;
157 let signing_kes_period = start_kes_period + MAX_KES_EVOLUTIONS + 1;
158 let KesCryptographicMaterialForTest {
159 party_id: _,
160 operational_certificate_file,
161 kes_secret_key_file,
162 } = create_kes_cryptographic_material(
163 1 as KesPartyIndexForTest,
164 start_kes_period,
165 current_function!(),
166 );
167 let message = b"Test message for KES signing";
168 let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
169
170 let res = kes_signer
171 .sign(message, signing_kes_period)
172 .expect_err("Signing should fail");
173 assert_eq!(
174 res.downcast_ref::<KesSignError>(),
175 Some(&KesSignError::UpdateKey(MAX_KES_EVOLUTIONS))
176 );
177 }
178}