Skip to content

Commit b6eccdb

Browse files
authored
Merge pull request #1224 from input-output-hk/jpraynaud/798-cardano-crypto-helper-refactor
Use anyhow in `common/crypto_helper`
2 parents ed098f1 + a2efcc6 commit b6eccdb

File tree

10 files changed

+116
-91
lines changed

10 files changed

+116
-91
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mithril-common/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-common"
3-
version = "0.2.113"
3+
version = "0.2.114"
44
authors = { workspace = true }
55
edition = { workspace = true }
66
documentation = { workspace = true }

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

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//! The trait `SerDeShelleyFileFormat` can be implemented for any structure that implements
1212
//! `Serialize` and `Deserialize`.
1313
14+
use anyhow::{anyhow, Context};
1415
use hex::FromHex;
1516
use kes_summed_ed25519::kes::Sum6Kes;
1617
use kes_summed_ed25519::traits::KesSk;
@@ -22,6 +23,8 @@ use std::io::Write;
2223
use std::path::Path;
2324
use thiserror::Error;
2425

26+
use crate::StdError;
27+
2528
/// We need to create this struct because the design of Sum6Kes takes
2629
/// a reference to a mutable pointer. It is therefore not possible to
2730
/// implement Ser/Deser using serde.
@@ -33,22 +36,8 @@ pub struct Sum6KesBytes(#[serde(with = "As::<Bytes>")] pub [u8; 612]);
3336

3437
/// Parse error
3538
#[derive(Error, Debug)]
36-
pub enum ParseError {
37-
#[error("io error: `{0}`")]
38-
IO(#[from] std::io::Error),
39-
40-
#[error("JSON parse error: `{0}`")]
41-
JsonFormat(#[from] serde_json::Error),
42-
43-
#[error("CBOR hex codec error: `{0}`")]
44-
CborHex(#[from] hex::FromHexError),
45-
46-
#[error("CBOR parse error: `{0}`")]
47-
CborFormat(#[from] serde_cbor::Error),
48-
49-
#[error("Invalid KES format")]
50-
KesFormat,
51-
}
39+
#[error("Codec parse error: `{0:?}`")]
40+
pub struct CodecParseError(StdError);
5241

5342
/// Fields for a shelley formatted file (holds for vkeys, skeys or certs)
5443
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
@@ -71,30 +60,48 @@ pub trait SerDeShelleyFileFormat: Serialize + DeserializeOwned {
7160

7261
/// Deserialize a type `T: Serialize + DeserializeOwned` from file following Cardano
7362
/// Shelley file format.
74-
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, ParseError> {
75-
let data = fs::read_to_string(path)?;
76-
let file: ShelleyFileFormat = serde_json::from_str(&data)?;
77-
let hex_vector = Vec::from_hex(file.cbor_hex)?;
63+
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, CodecParseError> {
64+
let data = fs::read_to_string(path)
65+
.with_context(|| "SerDeShelleyFileFormat can not read data from file {}")
66+
.map_err(|e| CodecParseError(anyhow!(e)))?;
67+
let file: ShelleyFileFormat = serde_json::from_str(&data)
68+
.with_context(|| "SerDeShelleyFileFormat can not unserialize json data")
69+
.map_err(|e| CodecParseError(anyhow!(e)))?;
70+
let hex_vector = Vec::from_hex(file.cbor_hex)
71+
.with_context(|| "SerDeShelleyFileFormat can not unserialize hex data")
72+
.map_err(|e| CodecParseError(anyhow!(e)))?;
73+
let a: Self = serde_cbor::from_slice(&hex_vector)
74+
.with_context(|| "SerDeShelleyFileFormat can not unserialize cbor data")
75+
.map_err(|e| CodecParseError(anyhow!(e)))?;
7876

79-
let a: Self = serde_cbor::from_slice(&hex_vector)?;
8077
Ok(a)
8178
}
8279

8380
/// Serialize a type `T: Serialize + DeserializeOwned` to file following Cardano
8481
/// Shelley file format.
85-
fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), ParseError> {
86-
let cbor_string = hex::encode(serde_cbor::to_vec(&self)?);
82+
fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), CodecParseError> {
83+
let cbor_string = hex::encode(
84+
serde_cbor::to_vec(&self)
85+
.with_context(|| "SerDeShelleyFileFormat can not serialize data to cbor")
86+
.map_err(|e| CodecParseError(anyhow!(e)))?,
87+
);
8788

8889
let file_format = ShelleyFileFormat {
8990
file_type: Self::TYPE.to_string(),
9091
description: Self::DESCRIPTION.to_string(),
9192
cbor_hex: cbor_string,
9293
};
9394

94-
let mut file = fs::File::create(path)?;
95-
let json_str = serde_json::to_string(&file_format)?;
95+
let mut file = fs::File::create(path)
96+
.with_context(|| "SerDeShelleyFileFormat can not create file")
97+
.map_err(|e| CodecParseError(anyhow!(e)))?;
98+
let json_str = serde_json::to_string(&file_format)
99+
.with_context(|| "SerDeShelleyFileFormat can not serialize data to json")
100+
.map_err(|e| CodecParseError(anyhow!(e)))?;
96101

97-
write!(file, "{json_str}")?;
102+
write!(file, "{json_str}")
103+
.with_context(|| "SerDeShelleyFileFormat can not write data to file")
104+
.map_err(|e| CodecParseError(anyhow!(e)))?;
98105
Ok(())
99106
}
100107
}
@@ -106,10 +113,16 @@ impl SerDeShelleyFileFormat for Sum6KesBytes {
106113
/// Deserialize a Cardano key from file. Cardano KES key Shelley format does not
107114
/// contain the period (it is always zero). Therefore we need to include it in the
108115
/// deserialisation.
109-
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, ParseError> {
110-
let data = fs::read_to_string(path)?;
111-
let file: ShelleyFileFormat = serde_json::from_str(&data)?;
112-
let mut hex_vector = Vec::from_hex(file.cbor_hex)?;
116+
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, CodecParseError> {
117+
let data = fs::read_to_string(path)
118+
.with_context(|| "Sum6KesBytes can not read data from file")
119+
.map_err(|e| CodecParseError(anyhow!(e)))?;
120+
let file: ShelleyFileFormat = serde_json::from_str(&data)
121+
.with_context(|| "Sum6KesBytes can not unserialize json data")
122+
.map_err(|e| CodecParseError(anyhow!(e)))?;
123+
let mut hex_vector = Vec::from_hex(file.cbor_hex)
124+
.with_context(|| "Sum6KesBytes can not unserialize hex data")
125+
.map_err(|e| CodecParseError(anyhow!(e)))?;
113126

114127
// We check whether the serialisation was performed by the haskell library or the rust library
115128
if (hex_vector[2] & 4u8) == 0 {
@@ -119,16 +132,18 @@ impl SerDeShelleyFileFormat for Sum6KesBytes {
119132
hex_vector.extend_from_slice(&[0u8; 4]);
120133
}
121134

122-
let a: Self = serde_cbor::from_slice(&hex_vector)?;
135+
let a: Self = serde_cbor::from_slice(&hex_vector)
136+
.with_context(|| "Sum6KesBytes can not unserialize cbor data")
137+
.map_err(|e| CodecParseError(anyhow!(e)))?;
123138
Ok(a)
124139
}
125140
}
126141

127142
impl<'a> TryFrom<&'a mut Sum6KesBytes> for Sum6Kes<'a> {
128-
type Error = ParseError;
143+
type Error = CodecParseError;
129144

130145
fn try_from(value: &'a mut Sum6KesBytes) -> Result<Self, Self::Error> {
131-
Self::from_bytes(&mut value.0).map_err(|_| ParseError::KesFormat)
146+
Self::from_bytes(&mut value.0).map_err(|e| CodecParseError(anyhow!(format!("{e:?}"))))
132147
}
133148
}
134149

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

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,24 @@
33
//! These wrappers allows keeping mithril-stm agnostic to Cardano, while providing some
44
//! guarantees that mithril-stm will not be misused in the context of Cardano.
55
6-
use crate::crypto_helper::{
7-
cardano::{ParseError, SerDeShelleyFileFormat},
8-
types::{
9-
ProtocolParameters, ProtocolPartyId, ProtocolSignerVerificationKey,
10-
ProtocolSignerVerificationKeySignature, ProtocolStakeDistribution,
6+
use crate::{
7+
crypto_helper::{
8+
cardano::SerDeShelleyFileFormat,
9+
types::{
10+
ProtocolParameters, ProtocolPartyId, ProtocolSignerVerificationKey,
11+
ProtocolSignerVerificationKeySignature, ProtocolStakeDistribution,
12+
},
13+
ProtocolOpCert,
1114
},
12-
ProtocolOpCert,
15+
StdError, StdResult,
1316
};
1417

1518
use mithril_stm::key_reg::{ClosedKeyReg, KeyReg};
1619
use mithril_stm::stm::{Stake, StmInitializer, StmParameters, StmSigner, StmVerificationKeyPoP};
1720
use mithril_stm::RegisterError;
1821

1922
use crate::crypto_helper::cardano::Sum6KesBytes;
23+
use anyhow::{anyhow, Context};
2024
use blake2::{
2125
digest::{consts::U32, FixedOutput},
2226
Blake2b, Digest,
@@ -36,7 +40,7 @@ type D = Blake2b<U32>;
3640
pub type KESPeriod = u32;
3741

3842
/// New registration error
39-
#[derive(Error, Debug, PartialEq, Eq)]
43+
#[derive(Error, Debug)]
4044
pub enum ProtocolRegistrationErrorWrapper {
4145
/// Error raised when a party id is needed but not provided
4246
// TODO: Should be removed once the signer certification is fully deployed
@@ -72,16 +76,16 @@ pub enum ProtocolRegistrationErrorWrapper {
7276
PoolAddressEncoding,
7377

7478
/// Error raised when a core registration error occurs
75-
#[error("core registration error: '{0}'")]
76-
CoreRegister(#[from] RegisterError),
79+
#[error("core registration error: '{0:?}'")]
80+
CoreRegister(StdError),
7781
}
7882

7983
/// New initializer error
8084
#[derive(Error, Debug)]
8185
pub enum ProtocolInitializerErrorWrapper {
82-
/// Error raised when a codec parse error occurs
83-
#[error("codec parse error: '{0}'")]
84-
Codec(#[from] ParseError),
86+
/// Error raised when the underlying protocol initializer fails
87+
#[error("protocol initializer error {0:?}")]
88+
ProtocolInitializer(StdError),
8589

8690
/// Error raised when a KES update error occurs
8791
#[error("KES key cannot be updated for period {0}")]
@@ -122,19 +126,22 @@ impl StmInitializerWrapper {
122126
kes_period: Option<KESPeriod>,
123127
stake: Stake,
124128
rng: &mut R,
125-
) -> Result<Self, ProtocolInitializerErrorWrapper> {
129+
) -> StdResult<Self> {
126130
let stm_initializer = StmInitializer::setup(params, stake, rng);
127131
let kes_signature = if let Some(kes_sk_path) = kes_sk_path {
128-
let mut kes_sk_bytes = Sum6KesBytes::from_file(kes_sk_path)?;
132+
let mut kes_sk_bytes = Sum6KesBytes::from_file(kes_sk_path)
133+
.map_err(|e| anyhow!(e))
134+
.with_context(|| "StmInitializerWrapper can not read KES secret key from file")?;
129135
let mut kes_sk = Sum6Kes::try_from(&mut kes_sk_bytes)
130-
.map_err(ProtocolInitializerErrorWrapper::Codec)?;
136+
.map_err(|e| ProtocolInitializerErrorWrapper::ProtocolInitializer(anyhow!(e)))
137+
.with_context(|| "StmInitializerWrapper can not use KES secret key")?;
131138
let kes_sk_period = kes_sk.get_period();
132139
let provided_period = kes_period.unwrap_or_default();
133140
if kes_sk_period > provided_period {
134-
return Err(ProtocolInitializerErrorWrapper::KesMismatch(
141+
return Err(anyhow!(ProtocolInitializerErrorWrapper::KesMismatch(
135142
kes_sk_period,
136143
provided_period,
137-
));
144+
)));
138145
}
139146

140147
// We need to perform the evolutions
@@ -192,7 +199,10 @@ impl StmInitializerWrapper {
192199
self,
193200
closed_reg: ClosedKeyReg<D>,
194201
) -> Result<StmSigner<D>, ProtocolRegistrationErrorWrapper> {
195-
Ok(self.stm_initializer.new_signer(closed_reg)?)
202+
self.stm_initializer
203+
.new_signer(closed_reg)
204+
.with_context(|| "StmInitializerWrapper can not create a new signer")
205+
.map_err(|e| ProtocolRegistrationErrorWrapper::CoreRegister(anyhow!(e)))
196206
}
197207

198208
/// Convert to bytes
@@ -279,7 +289,8 @@ impl KeyRegWrapper {
279289
if let Some(&stake) = self.stake_distribution.get(&pool_id_bech32) {
280290
self.stm_key_reg
281291
.register(stake, pk.into())
282-
.map_err(ProtocolRegistrationErrorWrapper::CoreRegister)?;
292+
.with_context(|| format!("KeyRegWrapper can not register pool {pool_id_bech32}"))
293+
.map_err(|e| ProtocolRegistrationErrorWrapper::CoreRegister(anyhow!(e)))?;
283294
return Ok(pool_id_bech32);
284295
}
285296
Err(ProtocolRegistrationErrorWrapper::PartyIdNonExisting)

mithril-common/src/crypto_helper/era.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
use ed25519_dalek::{SignatureError, Signer, SigningKey};
1+
use ed25519_dalek::{Signer, SigningKey};
22
use rand_chacha::rand_core::{self, CryptoRng, RngCore, SeedableRng};
33
use rand_chacha::ChaCha20Rng;
44
use serde::{Deserialize, Serialize};
55
use thiserror::Error;
66

7+
use crate::{StdError, StdResult};
8+
79
use super::ProtocolKey;
810

911
/// Wrapper of [Ed25519:PublicKey](https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.VerifyingKey.html).
@@ -20,7 +22,7 @@ pub type EraMarkersVerifierSignature = ProtocolKey<ed25519_dalek::Signature>;
2022
pub enum EraMarkersVerifierError {
2123
/// Error raised when a Signature verification fail
2224
#[error("era markers signature verification error: '{0}'")]
23-
SignatureVerification(#[from] SignatureError),
25+
SignatureVerification(StdError),
2426
}
2527

2628
/// A cryptographic signer that is responsible for signing the EraMarkers
@@ -85,11 +87,7 @@ impl EraMarkersVerifier {
8587
}
8688

8789
/// Verifies the signature of a message
88-
pub fn verify(
89-
&self,
90-
message: &[u8],
91-
signature: &EraMarkersVerifierSignature,
92-
) -> Result<(), EraMarkersVerifierError> {
90+
pub fn verify(&self, message: &[u8], signature: &EraMarkersVerifierSignature) -> StdResult<()> {
9391
Ok(self.verification_key.verify_strict(message, signature)?)
9492
}
9593
}

mithril-common/src/crypto_helper/genesis.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use crate::StdResult;
2-
use ed25519_dalek::{SignatureError, Signer, SigningKey};
1+
use crate::{StdError, StdResult};
2+
use anyhow::anyhow;
3+
use ed25519_dalek::{Signer, SigningKey};
34
use rand_chacha::rand_core::{self, CryptoRng, RngCore, SeedableRng};
45
use rand_chacha::ChaCha20Rng;
56
use serde::{Deserialize, Serialize};
@@ -10,11 +11,8 @@ use super::{ProtocolGenesisSecretKey, ProtocolGenesisSignature, ProtocolGenesisV
1011

1112
#[derive(Error, Debug)]
1213
/// [ProtocolGenesisSigner] and [ProtocolGenesisVerifier] related errors.
13-
pub enum ProtocolGenesisError {
14-
/// Error raised when a Genesis Signature verification fail
15-
#[error("genesis signature verification error: '{0}'")]
16-
SignatureVerification(#[from] SignatureError),
17-
}
14+
#[error("genesis signature verification error: '{0}'")]
15+
pub struct ProtocolGenesisError(StdError);
1816

1917
/// A protocol Genesis Signer that is responsible for signing the
2018
/// [Genesis Certificate](https://mithril.network/doc/mithril/mithril-protocol/certificates#the-certificate-chain-design)
@@ -90,12 +88,11 @@ impl ProtocolGenesisVerifier {
9088
}
9189

9290
/// Verifies the signature of a message
93-
pub fn verify(
94-
&self,
95-
message: &[u8],
96-
signature: &ProtocolGenesisSignature,
97-
) -> Result<(), ProtocolGenesisError> {
98-
Ok(self.verification_key.verify_strict(message, signature)?)
91+
pub fn verify(&self, message: &[u8], signature: &ProtocolGenesisSignature) -> StdResult<()> {
92+
Ok(self
93+
.verification_key
94+
.verify_strict(message, signature)
95+
.map_err(|e| ProtocolGenesisError(anyhow!(e)))?)
9996
}
10097
}
10198

mithril-common/src/era/adapters/cardano_chain.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
era::{EraMarker, EraReaderAdapter},
88
StdError, StdResult,
99
};
10-
use anyhow::anyhow;
10+
use anyhow::{anyhow, Context};
1111
use async_trait::async_trait;
1212
use serde::{Deserialize, Serialize};
1313
use std::sync::Arc;
@@ -80,7 +80,8 @@ impl EraMarkersPayload {
8080

8181
markers_verifier
8282
.verify(&self.message_to_bytes()?, &signature)
83-
.map_err(|e| EraMarkersPayloadError::VerifySignature(e.into()))
83+
.with_context(|| "era markers payload could not verify signature")
84+
.map_err(EraMarkersPayloadError::VerifySignature)
8485
}
8586

8687
/// Sign an era markers payload

mithril-signer/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-signer"
3-
version = "0.2.79"
3+
version = "0.2.80"
44
description = "A Mithril Signer"
55
authors = { workspace = true }
66
edition = { workspace = true }

0 commit comments

Comments
 (0)