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 KesEvolutions, 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();
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 - kes_period_start;
53
54 for evolution in 0..*kes_evolutions {
56 kes_sk
57 .update()
58 .map_err(|_| KesSignError::UpdateKey(KesEvolutions(evolution)))?;
59 }
60
61 Ok((kes_sk.sign(message), operational_certificate))
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 use crate::crypto_helper::KesEvolutions;
70 use crate::crypto_helper::cardano::kes::{KesVerifier, KesVerifierStandard};
71 use crate::current_function;
72 use crate::test::crypto_helper::{
73 KesCryptographicMaterialForTest, KesPartyIndexForTest, create_kes_cryptographic_material,
74 };
75
76 #[test]
77 fn create_valid_signature_for_message() {
78 let start_kes_period = KesPeriod(10);
79 let kes_evolutions = KesEvolutions(32);
80 let signing_kes_period = start_kes_period + kes_evolutions;
81 let KesCryptographicMaterialForTest {
82 party_id: _,
83 operational_certificate_file,
84 kes_secret_key_file,
85 } = create_kes_cryptographic_material(
86 1 as KesPartyIndexForTest,
87 start_kes_period,
88 current_function!(),
89 );
90 let message = b"Test message for KES signing";
91 let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
92
93 let (signature, op_cert) = kes_signer
94 .sign(message, signing_kes_period)
95 .expect("Signing should not fail");
96
97 KesVerifierStandard
98 .verify(message, &signature, &op_cert, kes_evolutions)
99 .expect("Signature verification should not fail");
100 }
101
102 #[test]
103 fn create_invalid_signature_for_different_message() {
104 let start_kes_period = KesPeriod(10);
105 let kes_evolutions = KesEvolutions(32);
106 let signing_kes_period = start_kes_period + kes_evolutions;
107 let KesCryptographicMaterialForTest {
108 party_id: _,
109 operational_certificate_file,
110 kes_secret_key_file,
111 } = create_kes_cryptographic_material(
112 1 as KesPartyIndexForTest,
113 start_kes_period,
114 current_function!(),
115 );
116 let message = b"Test message for KES signing";
117 let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
118
119 let (signature, op_cert) = kes_signer
120 .sign(message, signing_kes_period)
121 .expect("Signing should not fail");
122
123 KesVerifierStandard
124 .verify(b"Different message", &signature, &op_cert, kes_evolutions)
125 .expect_err("Signature verification should fail");
126 }
127
128 #[test]
129 fn create_invalid_signature_for_invalid_current_kes_period() {
130 let start_kes_period = KesPeriod(10);
131 let signing_kes_period = KesPeriod(5);
132 let KesCryptographicMaterialForTest {
133 party_id: _,
134 operational_certificate_file,
135 kes_secret_key_file,
136 } = create_kes_cryptographic_material(
137 1 as KesPartyIndexForTest,
138 start_kes_period,
139 current_function!(),
140 );
141 let message = b"Test message for KES signing";
142 let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
143
144 let res = kes_signer
145 .sign(message, signing_kes_period)
146 .expect_err("Signing should fail");
147 assert_eq!(
148 res.downcast_ref::<KesSignError>(),
149 Some(&KesSignError::PeriodMismatch(
150 start_kes_period,
151 signing_kes_period
152 ))
153 );
154 }
155
156 #[test]
157 fn create_invalid_signature_for_invalid_kes_evolutions() {
158 const MAX_KES_EVOLUTIONS: KesEvolutions = KesEvolutions(63);
159 let start_kes_period = KesPeriod(10);
160 let signing_kes_period = start_kes_period + MAX_KES_EVOLUTIONS + 1;
161 let KesCryptographicMaterialForTest {
162 party_id: _,
163 operational_certificate_file,
164 kes_secret_key_file,
165 } = create_kes_cryptographic_material(
166 1 as KesPartyIndexForTest,
167 start_kes_period,
168 current_function!(),
169 );
170 let message = b"Test message for KES signing";
171 let kes_signer = KesSignerStandard::new(kes_secret_key_file, operational_certificate_file);
172
173 let res = kes_signer
174 .sign(message, signing_kes_period)
175 .expect_err("Signing should fail");
176 assert_eq!(
177 res.downcast_ref::<KesSignError>(),
178 Some(&KesSignError::UpdateKey(MAX_KES_EVOLUTIONS))
179 );
180 }
181}