Skip to content

Commit 1e9be5f

Browse files
committed
refactor(common): add support for operational certificate without cold verification key
1 parent e89e93f commit 1e9be5f

File tree

5 files changed

+159
-37
lines changed

5 files changed

+159
-37
lines changed

mithril-common/src/crypto_helper/cardano/kes/verifier_standard.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ impl KesVerifier for KesVerifierStandard {
3030
let kes_period_try_max = std::cmp::min(64, kes_period.saturating_add(1));
3131
for kes_period_try in kes_period_try_min..kes_period_try_max {
3232
if signature
33-
.verify(kes_period_try, &operational_certificate.kes_vk, message)
33+
.verify(
34+
kes_period_try,
35+
&operational_certificate.get_kes_verification_key(),
36+
message,
37+
)
3438
.is_ok()
3539
{
3640
return Ok(());
@@ -39,7 +43,7 @@ impl KesVerifier for KesVerifierStandard {
3943

4044
Err(KesVerifyError::SignatureInvalid(
4145
kes_period,
42-
operational_certificate.start_kes_period as u32,
46+
operational_certificate.get_start_kes_period() as u32,
4347
)
4448
.into())
4549
}

mithril-common/src/crypto_helper/cardano/key_certification.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ impl KeyRegWrapper {
266266
} else {
267267
return Err(ProtocolRegistrationErrorWrapper::KesSignatureInvalid(
268268
kes_period,
269-
opcert.start_kes_period,
269+
opcert.get_start_kes_period(),
270270
));
271271
}
272272
} else {

mithril-common/src/crypto_helper/cardano/opcert.rs

Lines changed: 137 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub enum OpCertError {
2626

2727
/// Raw Fields of the operational certificates (without including the cold VK)
2828
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
29-
struct RawFields(
29+
struct RawOpCertWithoutColdVerificationKey(
3030
#[serde(with = "serde_bytes")] Vec<u8>,
3131
u64,
3232
u64,
@@ -35,16 +35,72 @@ struct RawFields(
3535

3636
/// Raw Operational Certificate
3737
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
38-
struct RawOpCert(RawFields, EdVerificationKey);
38+
struct RawOpCert(RawOpCertWithoutColdVerificationKey, EdVerificationKey);
3939

40-
/// Parsed Operational Certificate
40+
/// Parsed Operational Certificate without cold verification key
4141
#[derive(Clone, Debug, PartialEq, Eq)]
42-
pub struct OpCert {
42+
pub struct OpCertWithoutColdVerificationKey {
4343
pub(crate) kes_vk: KesPublicKey,
4444
pub(crate) issue_number: u64,
4545
/// KES period at which KES key is initalized
4646
pub start_kes_period: u64,
4747
pub(crate) cert_sig: EdSignature,
48+
}
49+
50+
impl SerDeShelleyFileFormat for OpCertWithoutColdVerificationKey {
51+
const TYPE: &'static str = "NodeOperationalCertificateWithoutColdVerificationKey";
52+
const DESCRIPTION: &'static str = "";
53+
}
54+
55+
impl Serialize for OpCertWithoutColdVerificationKey {
56+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
57+
where
58+
S: Serializer,
59+
{
60+
let raw_cert = RawOpCertWithoutColdVerificationKey(
61+
self.kes_vk.as_bytes().to_vec(),
62+
self.issue_number,
63+
self.start_kes_period,
64+
self.cert_sig.to_bytes().to_vec(),
65+
);
66+
67+
raw_cert.serialize(serializer)
68+
}
69+
}
70+
71+
impl<'de> Deserialize<'de> for OpCertWithoutColdVerificationKey {
72+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
73+
where
74+
D: Deserializer<'de>,
75+
{
76+
let raw_cert = RawOpCertWithoutColdVerificationKey::deserialize(deserializer)?;
77+
78+
Ok(Self {
79+
kes_vk: KesPublicKey::from_bytes(&raw_cert.0)
80+
.map_err(|_| Error::custom("KES vk serialisation error"))?,
81+
issue_number: raw_cert.1,
82+
start_kes_period: raw_cert.2,
83+
cert_sig: EdSignature::from_slice(&raw_cert.3)
84+
.map_err(|_| Error::custom("ed25519 signature serialisation error"))?,
85+
})
86+
}
87+
}
88+
89+
impl From<&OpCertWithoutColdVerificationKey> for RawOpCertWithoutColdVerificationKey {
90+
fn from(opcert: &OpCertWithoutColdVerificationKey) -> Self {
91+
RawOpCertWithoutColdVerificationKey(
92+
opcert.kes_vk.as_bytes().to_vec(),
93+
opcert.issue_number,
94+
opcert.start_kes_period,
95+
opcert.cert_sig.to_bytes().to_vec(),
96+
)
97+
}
98+
}
99+
100+
/// Parsed Operational Certificate
101+
#[derive(Clone, Debug, PartialEq, Eq)]
102+
pub struct OpCert {
103+
pub(crate) opcert_without_vk: OpCertWithoutColdVerificationKey,
48104
pub(crate) cold_vk: EdVerificationKey,
49105
}
50106

@@ -69,14 +125,46 @@ impl OpCert {
69125
));
70126

71127
Self {
72-
kes_vk,
73-
issue_number,
74-
start_kes_period,
75-
cert_sig,
128+
opcert_without_vk: OpCertWithoutColdVerificationKey {
129+
kes_vk,
130+
issue_number,
131+
start_kes_period,
132+
cert_sig,
133+
},
76134
cold_vk,
77135
}
78136
}
79137

138+
/// Get the KES verification key
139+
pub fn get_kes_verification_key(&self) -> KesPublicKey {
140+
self.opcert_without_vk.kes_vk
141+
}
142+
143+
/// Get the issue number
144+
pub fn get_issue_number(&self) -> u64 {
145+
self.opcert_without_vk.issue_number
146+
}
147+
148+
/// Get the start KES period
149+
pub fn get_start_kes_period(&self) -> u64 {
150+
self.opcert_without_vk.start_kes_period
151+
}
152+
153+
/// Get the certificate signature
154+
pub fn get_certificate_signature(&self) -> EdSignature {
155+
self.opcert_without_vk.cert_sig
156+
}
157+
158+
/// Get the OpCert without cold verification key
159+
pub fn get_opcert_without_cold_verification_key(&self) -> OpCertWithoutColdVerificationKey {
160+
self.opcert_without_vk.clone()
161+
}
162+
163+
/// Get the cold verification key
164+
pub fn get_cold_verification_key(&self) -> EdVerificationKey {
165+
self.cold_vk
166+
}
167+
80168
/// Compute message to sign
81169
pub(crate) fn compute_message_to_sign(
82170
kes_vk: &KesPublicKey,
@@ -96,11 +184,11 @@ impl OpCert {
96184
.cold_vk
97185
.verify(
98186
&Self::compute_message_to_sign(
99-
&self.kes_vk,
100-
self.issue_number,
101-
self.start_kes_period,
187+
&self.opcert_without_vk.kes_vk,
188+
self.opcert_without_vk.issue_number,
189+
self.opcert_without_vk.start_kes_period,
102190
),
103-
&self.cert_sig,
191+
&self.opcert_without_vk.cert_sig,
104192
)
105193
.is_ok()
106194
{
@@ -129,10 +217,10 @@ impl OpCert {
129217
/// Compute the hash of an OpCert
130218
pub fn compute_hash(&self) -> String {
131219
let mut hasher = Sha256::new();
132-
hasher.update(self.kes_vk.as_bytes());
133-
hasher.update(self.issue_number.to_be_bytes());
134-
hasher.update(self.start_kes_period.to_be_bytes());
135-
hasher.update(self.cert_sig.to_bytes());
220+
hasher.update(self.opcert_without_vk.kes_vk.as_bytes());
221+
hasher.update(self.opcert_without_vk.issue_number.to_be_bytes());
222+
hasher.update(self.opcert_without_vk.start_kes_period.to_be_bytes());
223+
hasher.update(self.opcert_without_vk.cert_sig.to_bytes());
136224
hasher.update(self.cold_vk.as_bytes());
137225
hex::encode(hasher.finalize())
138226
}
@@ -143,15 +231,9 @@ impl Serialize for OpCert {
143231
where
144232
S: Serializer,
145233
{
146-
let raw_cert = RawOpCert(
147-
RawFields(
148-
self.kes_vk.as_bytes().to_vec(),
149-
self.issue_number,
150-
self.start_kes_period,
151-
self.cert_sig.to_bytes().to_vec(),
152-
),
153-
self.cold_vk,
154-
);
234+
let raw_opcert_without_vk: RawOpCertWithoutColdVerificationKey =
235+
(&self.opcert_without_vk).into();
236+
let raw_cert = RawOpCert(raw_opcert_without_vk, self.cold_vk);
155237

156238
raw_cert.serialize(serializer)
157239
}
@@ -163,18 +245,33 @@ impl<'de> Deserialize<'de> for OpCert {
163245
D: Deserializer<'de>,
164246
{
165247
let raw_cert = RawOpCert::deserialize(deserializer)?;
248+
let raw_opcert_without_vk = &raw_cert.0;
249+
166250
Ok(Self {
167-
kes_vk: KesPublicKey::from_bytes(&raw_cert.0.0)
168-
.map_err(|_| Error::custom("KES vk serialisation error"))?,
169-
issue_number: raw_cert.0.1,
170-
start_kes_period: raw_cert.0.2,
171-
cert_sig: EdSignature::from_slice(&raw_cert.0.3)
172-
.map_err(|_| Error::custom("ed25519 signature serialisation error"))?,
251+
opcert_without_vk: OpCertWithoutColdVerificationKey {
252+
kes_vk: KesPublicKey::from_bytes(&raw_opcert_without_vk.0)
253+
.map_err(|_| Error::custom("KES vk serialisation error"))?,
254+
issue_number: raw_opcert_without_vk.1,
255+
start_kes_period: raw_opcert_without_vk.2,
256+
cert_sig: EdSignature::from_slice(&raw_opcert_without_vk.3)
257+
.map_err(|_| Error::custom("ed25519 signature serialisation error"))?,
258+
},
173259
cold_vk: raw_cert.1,
174260
})
175261
}
176262
}
177263

264+
impl From<(OpCertWithoutColdVerificationKey, EdVerificationKey)> for OpCert {
265+
fn from(
266+
(opcert_without_vk, cold_vk): (OpCertWithoutColdVerificationKey, EdVerificationKey),
267+
) -> Self {
268+
Self {
269+
opcert_without_vk,
270+
cold_vk,
271+
}
272+
}
273+
}
274+
178275
#[cfg(test)]
179276
mod tests {
180277
use super::*;
@@ -220,5 +317,14 @@ mod tests {
220317
"d9899c574fd7a710732391706b59e878bfd416214c49d2b3841c5c8b".to_string(),
221318
party_id_as_hash
222319
);
320+
321+
let operational_certificate_bytes_without_cold_vk = operational_certificate
322+
.get_opcert_without_cold_verification_key()
323+
.to_cbor_bytes()
324+
.expect("compute CBOR bytes should not fail");
325+
assert_eq!(
326+
"845820e650d7531509bb6cffd7998c28c68e4ec8fa621a0952206ea11eb03fcd7dcb2900005840d4abce27da05ff03c1342cc6ab53135072e1babf9cc05492f59f1ff009f70457aaa862c7158b13be0cfb41d7a91a562589bc110eb2cdaf5d2756048abbea5f05",
327+
hex::encode(operational_certificate_bytes_without_cold_vk)
328+
);
223329
}
224330
}

mithril-common/src/crypto_helper/codec/binary.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ mod binary_kes_sig {
210210
}
211211

212212
mod binary_opcert {
213-
use crate::crypto_helper::{OpCert, SerDeShelleyFileFormat};
213+
use crate::crypto_helper::{OpCert, OpCertWithoutColdVerificationKey, SerDeShelleyFileFormat};
214214
use anyhow::anyhow;
215215

216216
use super::*;
@@ -226,6 +226,18 @@ mod binary_opcert {
226226
Self::from_cbor_bytes(bytes).map_err(|e| anyhow!(format!("{e:?}")))
227227
}
228228
}
229+
230+
impl TryToBytes for OpCertWithoutColdVerificationKey {
231+
fn to_bytes_vec(&self) -> StdResult<Vec<u8>> {
232+
self.to_cbor_bytes().map_err(|e| anyhow!(format!("{e:?}")))
233+
}
234+
}
235+
236+
impl TryFromBytes for OpCertWithoutColdVerificationKey {
237+
fn try_from_bytes(bytes: &[u8]) -> StdResult<Self> {
238+
Self::from_cbor_bytes(bytes).map_err(|e| anyhow!(format!("{e:?}")))
239+
}
240+
}
229241
}
230242

231243
mod binary_mk_proof {

mithril-common/src/crypto_helper/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ pub use cardano::ColdKeyGenerator;
1313

1414
pub use cardano::{
1515
KesPeriod, KesSigner, KesSignerStandard, KesVerifier, KesVerifierStandard, KesVerifyError,
16-
OpCert, ProtocolInitializerErrorWrapper, ProtocolRegistrationErrorWrapper,
17-
SerDeShelleyFileFormat, Sum6KesBytes,
16+
OpCert, OpCertWithoutColdVerificationKey, ProtocolInitializerErrorWrapper,
17+
ProtocolRegistrationErrorWrapper, SerDeShelleyFileFormat, Sum6KesBytes,
1818
};
1919
pub use codec::*;
2020
pub use ed25519_alias::{era::*, genesis::*, manifest::*};

0 commit comments

Comments
 (0)