Skip to content

Commit 0e834d9

Browse files
committed
Add EraMarkers sign/verify
1 parent 13239ef commit 0e834d9

File tree

3 files changed

+281
-15
lines changed

3 files changed

+281
-15
lines changed
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
use ed25519_dalek::{ExpandedSecretKey, SignatureError};
2+
use rand_chacha_dalek_compat::rand_core::{self, CryptoRng, RngCore, SeedableRng};
3+
use rand_chacha_dalek_compat::ChaCha20Rng;
4+
use serde::{Deserialize, Serialize};
5+
use thiserror::Error;
6+
7+
/// Alias of [Ed25519:PublicKey](https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.PublicKey.html).
8+
pub type EraMarkersVerifierVerificationKey = ed25519_dalek::PublicKey;
9+
10+
/// Alias of [Ed25519:SecretKey](https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.SecretKey.html).
11+
pub type EraMarkersVerifierSecretKey = ed25519_dalek::SecretKey;
12+
13+
/// Alias of [Ed25519:Signature](https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.Signature.html).
14+
pub type EraMarkersVerifierSignature = ed25519_dalek::Signature;
15+
16+
#[derive(Error, Debug)]
17+
/// [EraMarkersSigner] and [EraMarkersVerifier] related errors.
18+
pub enum EraMarkersVerifierError {
19+
/// Error raised when a Signature verification fail
20+
#[error("era markers signature verification error: '{0}'")]
21+
SignatureVerification(#[from] SignatureError),
22+
}
23+
24+
/// A protocol Signer that is responsible for signing the
25+
/// [Certificate](https://mithril.network/doc/mithril/mithril-protocol/certificates#the-certificate-chain-design)
26+
#[derive(Debug, Serialize, Deserialize)]
27+
pub struct EraMarkersSigner {
28+
pub(crate) secret_key: EraMarkersVerifierSecretKey,
29+
}
30+
31+
impl EraMarkersSigner {
32+
/// EraMarkersSigner factory
33+
pub fn create_test_signer<R>(mut rng: R) -> Self
34+
where
35+
R: CryptoRng + RngCore,
36+
{
37+
let secret_key = EraMarkersVerifierSecretKey::generate(&mut rng);
38+
Self::from_secret_key(secret_key)
39+
}
40+
41+
/// EraMarkersSigner deterministic
42+
pub fn create_deterministic_signer() -> Self {
43+
let rng = ChaCha20Rng::from_seed([0u8; 32]);
44+
Self::create_test_signer(rng)
45+
}
46+
47+
/// EraMarkersSigner non deterministic
48+
pub fn create_non_deterministic_signer() -> Self {
49+
let rng = rand_core::OsRng;
50+
Self::create_test_signer(rng)
51+
}
52+
53+
/// EraMarkersSigner from EraMarkersVerifierSecretKey
54+
pub fn from_secret_key(secret_key: EraMarkersVerifierSecretKey) -> Self {
55+
Self { secret_key }
56+
}
57+
58+
/// Create a an expanded secret key
59+
fn create_expanded_secret_key(&self) -> ExpandedSecretKey {
60+
ExpandedSecretKey::from(&self.secret_key)
61+
}
62+
63+
/// Create a EraMarkersVerifierVerificationKey
64+
fn create_verification_key(
65+
&self,
66+
expanded_secret_key: &ExpandedSecretKey,
67+
) -> EraMarkersVerifierVerificationKey {
68+
let verification_key: EraMarkersVerifierVerificationKey = expanded_secret_key.into();
69+
verification_key
70+
}
71+
72+
/// Create a EraMarkersVerifier
73+
pub fn create_verifier(&self) -> EraMarkersVerifier {
74+
let expanded_secret_key = self.create_expanded_secret_key();
75+
let verification_key = self.create_verification_key(&expanded_secret_key);
76+
EraMarkersVerifier::from_verification_key(verification_key)
77+
}
78+
79+
/// Signs a message and returns a EraMarkersVerifierSignature
80+
pub fn sign(&self, message: &[u8]) -> EraMarkersVerifierSignature {
81+
let expanded_secret_key = self.create_expanded_secret_key();
82+
let verification_key = self.create_verification_key(&expanded_secret_key);
83+
expanded_secret_key.sign(message, &verification_key)
84+
}
85+
}
86+
87+
/// An era merkers Verifier
88+
#[derive(Debug, Serialize, Deserialize, Clone)]
89+
pub struct EraMarkersVerifier {
90+
pub(crate) verification_key: EraMarkersVerifierVerificationKey,
91+
}
92+
93+
impl EraMarkersVerifier {
94+
/// EraMarkersVerifier from EraMarkersVerifierVerificationKey
95+
pub fn from_verification_key(verification_key: EraMarkersVerifierVerificationKey) -> Self {
96+
Self { verification_key }
97+
}
98+
99+
/// EraMarkersVerifier to EraMarkersVerifierVerificationKey
100+
pub fn to_verification_key(&self) -> EraMarkersVerifierVerificationKey {
101+
self.verification_key
102+
}
103+
104+
/// Verifies the signature of a message
105+
pub fn verify(
106+
&self,
107+
message: &[u8],
108+
signature: &EraMarkersVerifierSignature,
109+
) -> Result<(), EraMarkersVerifierError> {
110+
Ok(self.verification_key.verify_strict(message, signature)?)
111+
}
112+
}
113+
114+
#[cfg(test)]
115+
mod tests {
116+
use super::super::codec::{key_decode_hex, key_encode_hex};
117+
use super::*;
118+
119+
#[test]
120+
fn test_generate_test_deterministic_keypair() {
121+
let signer = EraMarkersSigner::create_deterministic_signer();
122+
let verifier = signer.create_verifier();
123+
let signer_2 = EraMarkersSigner::create_deterministic_signer();
124+
let verifier_2 = signer.create_verifier();
125+
assert_eq!(signer.secret_key.as_bytes(), signer_2.secret_key.as_bytes());
126+
assert_eq!(
127+
verifier.verification_key.as_bytes(),
128+
verifier_2.verification_key.as_bytes()
129+
);
130+
131+
println!(
132+
"Deterministic Verification Key={}",
133+
key_encode_hex(verifier.verification_key.as_bytes()).unwrap()
134+
);
135+
println!(
136+
"Deterministic Secret Key=={}",
137+
key_encode_hex(signer.secret_key.as_bytes()).unwrap()
138+
);
139+
}
140+
141+
#[test]
142+
fn test_generate_test_non_deterministic_keypair() {
143+
let signer = EraMarkersSigner::create_non_deterministic_signer();
144+
let verifier = signer.create_verifier();
145+
146+
println!(
147+
"Non Deterministic Verification Key={}",
148+
key_encode_hex(verifier.verification_key.as_bytes()).unwrap()
149+
);
150+
println!(
151+
"Non Deterministic Secret Key=={}",
152+
key_encode_hex(signer.secret_key.as_bytes()).unwrap()
153+
);
154+
}
155+
156+
#[test]
157+
fn test_codec_keypair() {
158+
let signer = EraMarkersSigner::create_deterministic_signer();
159+
let verifier = signer.create_verifier();
160+
let secret_key_encoded = key_encode_hex(signer.secret_key.as_bytes()).unwrap();
161+
let verification_key_encoded =
162+
key_encode_hex(verifier.verification_key.as_bytes()).unwrap();
163+
let secret_key_decoded: EraMarkersVerifierSecretKey =
164+
key_decode_hex(&secret_key_encoded).unwrap();
165+
let verification_key_decoded: EraMarkersVerifierVerificationKey =
166+
key_decode_hex(&verification_key_encoded).unwrap();
167+
let signer_decoded = EraMarkersSigner::from_secret_key(secret_key_decoded);
168+
let verifier_decoded = EraMarkersVerifier::from_verification_key(verification_key_decoded);
169+
170+
let message: &[u8] = b"some message.";
171+
let signature = signer_decoded.sign(message);
172+
let verify_signature = verifier_decoded.verify(message, &signature);
173+
assert!(
174+
verify_signature.is_ok(),
175+
"signature verification should not fail"
176+
);
177+
}
178+
}

mithril-common/src/crypto_helper/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
mod cardano;
44
mod codec;
55
mod conversions;
6+
mod era;
67
mod genesis;
78
#[cfg(any(test, feature = "test_only"))]
89
pub mod tests_setup;
@@ -12,6 +13,10 @@ mod types;
1213
pub use cardano::ColdKeyGenerator;
1314
pub use cardano::{KESPeriod, OpCert, SerDeShelleyFileFormat};
1415
pub use codec::*;
16+
pub use era::{
17+
EraMarkersSigner, EraMarkersVerifier, EraMarkersVerifierError, EraMarkersVerifierSecretKey,
18+
EraMarkersVerifierSignature, EraMarkersVerifierVerificationKey,
19+
};
1520
pub use genesis::{ProtocolGenesisError, ProtocolGenesisSigner, ProtocolGenesisVerifier};
1621
pub use types::*;
1722

mithril-common/src/era/cardano_chain_adapter.rs

Lines changed: 98 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1-
use crate::chain_observer::ChainAddress;
2-
use crate::crypto_helper::key_decode_hex;
3-
use crate::{chain_observer::ChainObserver, entities::Epoch};
1+
use crate::{
2+
chain_observer::{ChainAddress, ChainObserver},
3+
crypto_helper::{
4+
key_decode_hex, EraMarkersSigner, EraMarkersVerifier, EraMarkersVerifierSignature,
5+
EraMarkersVerifierVerificationKey,
6+
},
7+
entities::Epoch,
8+
};
49
use async_trait::async_trait;
10+
use hex::{FromHex, ToHex};
511
use serde::{Deserialize, Serialize};
612
use std::error::Error as StdError;
713
use std::sync::Arc;
814
use thiserror::Error;
915

16+
type GeneralError = Box<dyn StdError + Sync + Send>;
17+
1018
// TODO: remove EraMarker & EraReaderAdapter w/ they are available
1119

1220
/// Value object that represents a tag of Era change.
@@ -31,38 +39,101 @@ impl EraMarker {
3139
#[async_trait]
3240
pub trait EraReaderAdapter: Sync + Send {
3341
/// Read era markers from the underlying adapter.
34-
async fn read(&self) -> Result<Vec<EraMarker>, Box<dyn StdError + Sync + Send>>;
42+
async fn read(&self) -> Result<Vec<EraMarker>, GeneralError>;
3543
}
3644

3745
// TODO: Keep Cardano Chain Adapter part below
3846

3947
type HexEncodeEraMarkerSignature = String;
4048

49+
/// [EraMarkersPayload] related errors.
50+
#[derive(Debug, Error)]
51+
pub enum EraMarkersPayloadError {
52+
/// Error raised when the message serialization fails
53+
#[error("could not serialize message: {0}")]
54+
SerializeMessage(GeneralError),
55+
56+
/// Error raised when the signature deserialization fails
57+
#[error("could not deserialize signature: {0}")]
58+
DeserializeSignature(GeneralError),
59+
60+
/// Error raised when the signature is invalid
61+
#[error("could not verify signature: {0}")]
62+
VerifySignature(GeneralError),
63+
64+
/// Error raised when the signing the markers
65+
#[error("could not create signature: {0}")]
66+
CreateSignature(GeneralError),
67+
}
68+
4169
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
4270
struct EraMarkersPayload {
4371
markers: Vec<EraMarker>,
4472
signature: HexEncodeEraMarkerSignature,
4573
}
4674

75+
impl EraMarkersPayload {
76+
fn message_to_sign(&self) -> Result<Vec<u8>, EraMarkersPayloadError> {
77+
serde_json::to_vec(&self.markers)
78+
.map_err(|e| EraMarkersPayloadError::SerializeMessage(e.into()))
79+
}
80+
81+
fn verify_signature(
82+
&self,
83+
verification_key: EraMarkersVerifierVerificationKey,
84+
) -> Result<(), EraMarkersPayloadError> {
85+
let signature = EraMarkersVerifierSignature::from_bytes(
86+
&Vec::from_hex(&self.signature)
87+
.map_err(|e| EraMarkersPayloadError::DeserializeSignature(e.into()))?,
88+
)
89+
.map_err(|e| EraMarkersPayloadError::DeserializeSignature(e.into()))?;
90+
let markers_verifier = EraMarkersVerifier::from_verification_key(verification_key);
91+
markers_verifier
92+
.verify(&self.message_to_sign()?, &signature)
93+
.map_err(|e| EraMarkersPayloadError::VerifySignature(e.into()))
94+
}
95+
96+
#[cfg(any(test, feature = "test_only"))]
97+
fn sign(self, signer: &EraMarkersSigner) -> Result<Self, EraMarkersPayloadError> {
98+
let signature = signer
99+
.sign(
100+
&self
101+
.message_to_sign()
102+
.map_err(|e| EraMarkersPayloadError::CreateSignature(e.into()))?,
103+
)
104+
.encode_hex::<String>();
105+
Ok(Self {
106+
markers: self.markers,
107+
signature,
108+
})
109+
}
110+
}
111+
47112
/// Cardano Chain adapter retrieves era markers on chain
48113
pub struct CardanoChainAdapter {
49114
address: ChainAddress,
50115
chain_observer: Arc<dyn ChainObserver>,
116+
verification_key: EraMarkersVerifierVerificationKey,
51117
}
52118

53119
impl CardanoChainAdapter {
54120
/// CardanoChainAdapter factory
55-
pub fn new(address: ChainAddress, chain_observer: Arc<dyn ChainObserver>) -> Self {
121+
pub fn new(
122+
address: ChainAddress,
123+
chain_observer: Arc<dyn ChainObserver>,
124+
verification_key: EraMarkersVerifierVerificationKey,
125+
) -> Self {
56126
Self {
57127
address,
58128
chain_observer,
129+
verification_key,
59130
}
60131
}
61132
}
62133

63134
#[async_trait]
64135
impl EraReaderAdapter for CardanoChainAdapter {
65-
async fn read(&self) -> Result<Vec<EraMarker>, Box<dyn StdError + Sync + Send>> {
136+
async fn read(&self) -> Result<Vec<EraMarker>, GeneralError> {
66137
let tx_datums = self
67138
.chain_observer
68139
.get_current_datums(&self.address)
@@ -72,7 +143,12 @@ impl EraReaderAdapter for CardanoChainAdapter {
72143
.filter_map(|datum| datum.get_field_raw_value("bytes", 0).ok())
73144
.filter_map(|field_value| field_value.as_str().map(|s| s.to_string()))
74145
.filter_map(|field_value_str| key_decode_hex(&field_value_str).ok())
75-
.map(|era_markers_payload: EraMarkersPayload| era_markers_payload.markers)
146+
.filter_map(|era_markers_payload: EraMarkersPayload| {
147+
era_markers_payload
148+
.verify_signature(self.verification_key)
149+
.ok()
150+
.map(|_| era_markers_payload.markers)
151+
})
76152
.collect::<Vec<Vec<EraMarker>>>();
77153
Ok(markers_list.first().unwrap_or(&Vec::new()).to_owned())
78154
}
@@ -81,7 +157,7 @@ impl EraReaderAdapter for CardanoChainAdapter {
81157
#[cfg(test)]
82158
mod test {
83159
use crate::chain_observer::{FakeObserver, TxDatum};
84-
use crate::crypto_helper::key_encode_hex;
160+
use crate::crypto_helper::{key_encode_hex, EraMarkersSigner};
85161

86162
use super::*;
87163

@@ -99,35 +175,42 @@ mod test {
99175

100176
#[tokio::test]
101177
async fn test_cardano_chain_adapter() {
178+
let era_markers_signer = EraMarkersSigner::create_deterministic_signer();
102179
let fake_address = "addr_test_123456".to_string();
103180
let era_marker_payload_1 = EraMarkersPayload {
104181
markers: vec![
105182
EraMarker::new("thales", Some(Epoch(1))),
106-
EraMarker::new("pythagors", None),
183+
EraMarker::new("pythagoras", None),
107184
],
108185
signature: "".to_string(),
109186
};
110187
let era_marker_payload_2 = EraMarkersPayload {
111188
markers: vec![
112189
EraMarker::new("thales", Some(Epoch(1))),
113-
EraMarker::new("pythagors", Some(Epoch(2))),
190+
EraMarker::new("pythagoras", Some(Epoch(2))),
114191
],
115192
signature: "".to_string(),
116193
};
117194
let mut fake_datums = dummy_tx_datums_from_markers_payload(vec![
118-
era_marker_payload_1.clone(),
119-
era_marker_payload_2,
195+
era_marker_payload_1,
196+
era_marker_payload_2
197+
.clone()
198+
.sign(&era_markers_signer)
199+
.unwrap(),
120200
]);
121201
fake_datums.push(TxDatum("not_valid_datum".to_string()));
122202
let chain_observer = FakeObserver::default();
123203
chain_observer.set_datums(fake_datums.clone()).await;
124-
let cardano_chain_adapter =
125-
CardanoChainAdapter::new(fake_address, Arc::new(chain_observer));
204+
let cardano_chain_adapter = CardanoChainAdapter::new(
205+
fake_address,
206+
Arc::new(chain_observer),
207+
era_markers_signer.create_verifier().to_verification_key(),
208+
);
126209
let markers = cardano_chain_adapter
127210
.read()
128211
.await
129212
.expect("CardanoChainAdapter read should not fail");
130-
let expected_markers = era_marker_payload_1.markers.to_owned();
213+
let expected_markers = era_marker_payload_2.markers.to_owned();
131214
assert_eq!(expected_markers, markers);
132215
}
133216
}

0 commit comments

Comments
 (0)