From 8a43590970baea88c8e8017e1ba80278221c5b83 Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Fri, 30 Dec 2022 14:34:07 +0100 Subject: [PATCH 1/7] Adapt code to last version of KES --- Cargo.lock | 3 ++- mithril-common/Cargo.toml | 2 +- .../src/crypto_helper/cardano/key_certification.rs | 11 ++++------- mithril-common/src/crypto_helper/cardano/opcert.rs | 2 +- mithril-signer/src/single_signer.rs | 7 ++++--- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4dfd00a5302..fffe5885e50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1802,7 +1802,8 @@ dependencies = [ [[package]] name = "kes-summed-ed25519" version = "0.1.0" -source = "git+https://github.com/input-output-hk/kes?rev=1418efa#1418efaacaca52ba48bdee0bab56bea1bb1d1ce4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bd03f6fbbd46e0197115047ace8236ae5a8d434c12083f782db9c4eeefa900" dependencies = [ "blake2 0.9.2", "ed25519-dalek", diff --git a/mithril-common/Cargo.toml b/mithril-common/Cargo.toml index 4a22d2ec2f8..6828a522665 100644 --- a/mithril-common/Cargo.toml +++ b/mithril-common/Cargo.toml @@ -27,7 +27,7 @@ glob = "0.3" hex = "0.4.3" http = "0.2.6" jsonschema = "0.16.0" -kes-summed-ed25519 = { git = "https://github.com/input-output-hk/kes", rev = "1418efa", features = ["serde_enabled"] } +kes-summed-ed25519 = { version = "0.1.0", features = ["serde_enabled"] } mockall = "0.11.0" nom = "7.1" rand-chacha-dalek-compat = { package = "rand_chacha", version = "0.2" } diff --git a/mithril-common/src/crypto_helper/cardano/key_certification.rs b/mithril-common/src/crypto_helper/cardano/key_certification.rs index 01b57fe0a33..e32d6447031 100644 --- a/mithril-common/src/crypto_helper/cardano/key_certification.rs +++ b/mithril-common/src/crypto_helper/cardano/key_certification.rs @@ -29,7 +29,7 @@ use thiserror::Error; type D = Blake2b; /// The KES period that is used to check if the KES keys is expired -pub type KESPeriod = usize; +pub type KESPeriod = u32; /// New registration error #[derive(Error, Debug, PartialEq, Eq)] @@ -53,7 +53,7 @@ pub enum ProtocolRegistrationErrorWrapper { /// Error raised when a KES Signature verification fails #[error("KES signature verification error: CurrentKesPeriod={0}, StartKesPeriod={1}")] - KesSignatureInvalid(usize, u64), + KesSignatureInvalid(u32, u64), /// Error raised when a KES Signature is needed but not provided #[error("missing KES signature")] @@ -122,14 +122,11 @@ impl StmInitializerWrapper { // We need to perform the evolutions, as the key is stored in evolution 0 in `kes.skey` for period in 0..kes_period.unwrap_or_default() { kes_sk - .update(period) + .update() .map_err(|_| ProtocolInitializerErrorWrapper::KesUpdate(period))?; } - Some(kes_sk.sign( - kes_period.unwrap_or_default(), - &stm_initializer.verification_key().to_bytes(), - )) + Some(kes_sk.sign(&stm_initializer.verification_key().to_bytes())) } else { println!("WARNING: Non certified signer registration by providing only a Pool Id is decommissionned and must be used for tests only!"); None diff --git a/mithril-common/src/crypto_helper/cardano/opcert.rs b/mithril-common/src/crypto_helper/cardano/opcert.rs index 8ae8987da45..6c97516b159 100644 --- a/mithril-common/src/crypto_helper/cardano/opcert.rs +++ b/mithril-common/src/crypto_helper/cardano/opcert.rs @@ -9,7 +9,7 @@ use blake2::{digest::consts::U28, Blake2b, Digest}; #[cfg(any(test, feature = "test_only"))] use ed25519_dalek::{Keypair as EdKeypair, Signer}; use ed25519_dalek::{PublicKey as EdPublicKey, Signature as EdSignature, Verifier}; -use kes_summed_ed25519::common::PublicKey as KesPublicKey; +use kes_summed_ed25519::PublicKey as KesPublicKey; use serde::de::Error; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use sha2::Sha256; diff --git a/mithril-signer/src/single_signer.rs b/mithril-signer/src/single_signer.rs index df9e57a4cc5..0b25c518f57 100644 --- a/mithril-signer/src/single_signer.rs +++ b/mithril-signer/src/single_signer.rs @@ -4,8 +4,9 @@ use std::path::PathBuf; use thiserror::Error; use mithril_common::crypto_helper::{ - key_decode_hex, key_encode_hex, ProtocolClerk, ProtocolInitializer, ProtocolKeyRegistration, - ProtocolPartyId, ProtocolRegistrationError, ProtocolSigner, ProtocolStakeDistribution, + key_decode_hex, key_encode_hex, KESPeriod, ProtocolClerk, ProtocolInitializer, + ProtocolKeyRegistration, ProtocolPartyId, ProtocolRegistrationError, ProtocolSigner, + ProtocolStakeDistribution, }; use mithril_common::entities::{ PartyId, ProtocolMessage, ProtocolParameters, SignerWithStake, SingleSignatures, Stake, @@ -38,7 +39,7 @@ impl MithrilProtocolInitializerBuilder { stake: &Stake, protocol_parameters: &ProtocolParameters, kes_secret_key_path: Option, - kes_period: Option, + kes_period: Option, ) -> Result { let mut rng = rand_core::OsRng; let protocol_initializer = ProtocolInitializer::setup( From bee48a76f36cef5092c7b8c23f5ab18d634c1285 Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Tue, 3 Jan 2023 12:16:19 +0100 Subject: [PATCH 2/7] Add hardcoded tests for compatibility with haskell implementation. --- .../src/crypto_helper/cardano/codec.rs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/mithril-common/src/crypto_helper/cardano/codec.rs b/mithril-common/src/crypto_helper/cardano/codec.rs index 8a8630719ff..aac68674cac 100644 --- a/mithril-common/src/crypto_helper/cardano/codec.rs +++ b/mithril-common/src/crypto_helper/cardano/codec.rs @@ -87,3 +87,33 @@ impl SerDeShelleyFileFormat for Sum6Kes { const TYPE: &'static str = "KesSigningKey_ed25519_kes_2^6"; const DESCRIPTION: &'static str = "KES Signing Key"; } + +#[cfg(all(test))] +mod test { + use super::*; + + #[test] + fn compat_with_shelly_format() { + let temp_dir = std::env::temp_dir().join("testing"); + fs::create_dir_all(&temp_dir).expect("temp dir creation should not fail"); + let sk_dir = temp_dir.join("dummy.skey"); + let cbor_string = "590260fe77acdfa56281e4b05198f5136018057a65f425411f0990cac4aca0f2917aa00a3d51e191f6f425d870aca3c6a2a41833621f5729d7bc0e3dfc3ae77d057e5e1253b71def7a54157b9f98973ca3c49edd9f311e5f4b23ac268b56a6ac040c14c6d2217925492e42f00dc89a2a01ff363571df0ca0db5ba37001cee56790cc01cd69c6aa760fca55a65a110305ea3c11da0a27be345a589329a584ebfc499c43c55e8c6db5d9c0b014692533ee78abd7ac1e79f7ec9335c7551d31668369b4d5111db78072f010043e35e5ca7f11acc3c05b26b9c7fe56f02aa41544f00cb7685e87f34c73b617260ade3c7b8d8c4df46693694998f85ad80d2cbab0b575b6ccd65d90574e84368169578bff57f751bc94f7eec5c0d7055ec88891a69545eedbfbd3c5f1b1c1fe09c14099f6b052aa215efdc5cb6cdc84aa810db41dbe8cb7d28f7c4beb75cc53915d3ac75fc9d0bf1c734a46e401e15150c147d013a938b7e07cc4f25a582b914e94783d15896530409b8acbe31ef471de8a1988ac78dfb7510729eff008084885f07df870b65e4f382ca15908e1dcda77384b5c724350de90cec22b1dcbb1cdaed88da08bb4772a82266ec154f5887f89860d0920dba705c45957ef6d93e42f6c9509c966277d368dd0eefa67c8147aa15d40a222f7953a4f34616500b310d00aa1b5b73eb237dc4f76c0c16813d321b2fc5ac97039be25b22509d1201d61f4ccc11cd4ff40fffe39f0e937b4722074d8e073a775d7283b715d46f79ce128e3f1362f35615fa72364d20b6db841193d96e58d9d8e86b516bbd1f05e45b39823a93f6e9f29d9e01acf2c12c072d1c64e0afbbabf6903ef542e".to_string(); + + let file_format = ShelleyFileFormat { + file_type: Sum6Kes::TYPE.to_string(), + description: Sum6Kes::DESCRIPTION.to_string(), + cbor_hex: cbor_string, + }; + + let mut file = + fs::File::create(sk_dir.clone()).expect("Unexpected error with file creation."); + let json_str = + serde_json::to_string(&file_format).expect("Unexpected error with serialisation."); + + write!(file, "{}", json_str).expect("Unexpected error writing to file."); + + let kes_sk = Sum6Kes::from_file(&sk_dir); + + assert!(kes_sk.is_ok(), "Failure parsing Shelley file format."); + } +} From 867c2fb0974dae6582e8348ae2c60ea471e90fb2 Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Tue, 3 Jan 2023 12:16:38 +0100 Subject: [PATCH 3/7] Modify from_file function for KES sk --- .../src/crypto_helper/cardano/codec.rs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/mithril-common/src/crypto_helper/cardano/codec.rs b/mithril-common/src/crypto_helper/cardano/codec.rs index aac68674cac..abee41f8f7f 100644 --- a/mithril-common/src/crypto_helper/cardano/codec.rs +++ b/mithril-common/src/crypto_helper/cardano/codec.rs @@ -55,7 +55,8 @@ pub trait SerDeShelleyFileFormat: Serialize + DeserializeOwned { /// The description of the Cardano key const DESCRIPTION: &'static str; - /// Deserialize a Cardano key from file + /// Deserialize a type `T: Serialize + DeserializeOwned` from file following Cardano + /// Shelley file format. fn from_file>(path: P) -> Result { let data = fs::read_to_string(path)?; let file: ShelleyFileFormat = serde_json::from_str(&data)?; @@ -65,7 +66,8 @@ pub trait SerDeShelleyFileFormat: Serialize + DeserializeOwned { Ok(a) } - /// Serialize a Cardano Key to file + /// Serialize a type `T: Serialize + DeserializeOwned` to file following Cardano + /// Shelley file format. fn to_file>(&self, path: P) -> Result<(), ParseError> { let cbor_string = hex::encode(serde_cbor::to_vec(&self)?); @@ -86,6 +88,26 @@ pub trait SerDeShelleyFileFormat: Serialize + DeserializeOwned { impl SerDeShelleyFileFormat for Sum6Kes { const TYPE: &'static str = "KesSigningKey_ed25519_kes_2^6"; const DESCRIPTION: &'static str = "KES Signing Key"; + + /// Deserialize a Cardano key from file. Cardano KES key Shelley format does not + /// contain the period (it is always zero). Therefore we need to include it in the + /// deserialisation. + fn from_file>(path: P) -> Result { + let data = fs::read_to_string(path)?; + let file: ShelleyFileFormat = serde_json::from_str(&data)?; + let mut hex_vector = Vec::from_hex(file.cbor_hex)?; + + // We check whether the serialisation was performed by the haskell library or the rust library + if (hex_vector[2] & 4u8) == 0 { + // First we need to change the cbor format to notify about the extra 4 bytes: + hex_vector[2] |= 4u8; + // Then we append the bytes representing the period = 0 + hex_vector.extend_from_slice(&[0u8; 4]); + } + + let a: Self = serde_cbor::from_slice(&hex_vector)?; + Ok(a) + } } #[cfg(all(test))] From b81122b4ca0da141c3c7877ea58af87b288914f0 Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Tue, 3 Jan 2023 12:19:07 +0100 Subject: [PATCH 4/7] KES signature implements copy --- mithril-common/src/crypto_helper/cardano/key_certification.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mithril-common/src/crypto_helper/cardano/key_certification.rs b/mithril-common/src/crypto_helper/cardano/key_certification.rs index e32d6447031..5382aa9d7c2 100644 --- a/mithril-common/src/crypto_helper/cardano/key_certification.rs +++ b/mithril-common/src/crypto_helper/cardano/key_certification.rs @@ -145,7 +145,7 @@ impl StmInitializerWrapper { /// Extract the verification key signature. pub fn verification_key_signature(&self) -> Option { - self.kes_signature.clone() + self.kes_signature } /// Extract the stake of the party From e6bde77e5e1f3ae43e33124f410fd0df6ce4a842 Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Wed, 4 Jan 2023 10:12:15 +0100 Subject: [PATCH 5/7] Update KES key until provided period --- Cargo.lock | 4 +-- mithril-common/Cargo.toml | 2 +- .../cardano/key_certification.rs | 27 ++++++++++++++----- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fffe5885e50..1d9280ee3a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1801,9 +1801,9 @@ dependencies = [ [[package]] name = "kes-summed-ed25519" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bd03f6fbbd46e0197115047ace8236ae5a8d434c12083f782db9c4eeefa900" +checksum = "ff5ba36dcf3798c53cfe222f22038ac63b1a3ef676a68af50a990d2775280cfb" dependencies = [ "blake2 0.9.2", "ed25519-dalek", diff --git a/mithril-common/Cargo.toml b/mithril-common/Cargo.toml index 6828a522665..daabcb02ef2 100644 --- a/mithril-common/Cargo.toml +++ b/mithril-common/Cargo.toml @@ -27,7 +27,7 @@ glob = "0.3" hex = "0.4.3" http = "0.2.6" jsonschema = "0.16.0" -kes-summed-ed25519 = { version = "0.1.0", features = ["serde_enabled"] } +kes-summed-ed25519 = { version = "0.1.1", features = ["serde_enabled"] } mockall = "0.11.0" nom = "7.1" rand-chacha-dalek-compat = { package = "rand_chacha", version = "0.2" } diff --git a/mithril-common/src/crypto_helper/cardano/key_certification.rs b/mithril-common/src/crypto_helper/cardano/key_certification.rs index 5382aa9d7c2..21c96bef5b3 100644 --- a/mithril-common/src/crypto_helper/cardano/key_certification.rs +++ b/mithril-common/src/crypto_helper/cardano/key_certification.rs @@ -82,6 +82,10 @@ pub enum ProtocolInitializerErrorWrapper { /// Error raised when a KES update error occurs #[error("KES key cannot be updated for period {0}")] KesUpdate(KESPeriod), + + /// Period of key file does not match with period provided by user + #[error("Period of key file, {0}, does not match with period provided by user, {1}")] + KesMismatch(KESPeriod, KESPeriod), } /// Wrapper structure for [MithrilStm:StmInitializer](mithril_stm::stm::StmInitializer). /// It now obtains a KES signature over the Mithril key. This allows the signers prove @@ -119,14 +123,23 @@ impl StmInitializerWrapper { let kes_signature = if let Some(kes_sk_path) = kes_sk_path { let mut kes_sk: Sum6Kes = Sum6Kes::from_file(kes_sk_path)?; - // We need to perform the evolutions, as the key is stored in evolution 0 in `kes.skey` - for period in 0..kes_period.unwrap_or_default() { - kes_sk - .update() - .map_err(|_| ProtocolInitializerErrorWrapper::KesUpdate(period))?; - } + let kes_sk_period = kes_sk.get_period(); + let provided_period = kes_period.unwrap_or_default(); + if kes_sk_period <= provided_period { + // We need to perform the evolutions + for period in kes_sk_period..provided_period { + kes_sk + .update() + .map_err(|_| ProtocolInitializerErrorWrapper::KesUpdate(period))?; + } - Some(kes_sk.sign(&stm_initializer.verification_key().to_bytes())) + Some(kes_sk.sign(&stm_initializer.verification_key().to_bytes())) + } else { + return Err(ProtocolInitializerErrorWrapper::KesMismatch( + kes_sk_period, + provided_period, + )); + } } else { println!("WARNING: Non certified signer registration by providing only a Pool Id is decommissionned and must be used for tests only!"); None From 6dbbb6932fee58b83fd51b6b9e83465434233284 Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Wed, 4 Jan 2023 11:06:46 +0100 Subject: [PATCH 6/7] First check if Key period is higher than provided --- .../cardano/key_certification.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mithril-common/src/crypto_helper/cardano/key_certification.rs b/mithril-common/src/crypto_helper/cardano/key_certification.rs index 21c96bef5b3..abab5e57dc4 100644 --- a/mithril-common/src/crypto_helper/cardano/key_certification.rs +++ b/mithril-common/src/crypto_helper/cardano/key_certification.rs @@ -125,21 +125,21 @@ impl StmInitializerWrapper { let kes_sk_period = kes_sk.get_period(); let provided_period = kes_period.unwrap_or_default(); - if kes_sk_period <= provided_period { - // We need to perform the evolutions - for period in kes_sk_period..provided_period { - kes_sk - .update() - .map_err(|_| ProtocolInitializerErrorWrapper::KesUpdate(period))?; - } - - Some(kes_sk.sign(&stm_initializer.verification_key().to_bytes())) - } else { + if kes_sk_period > provided_period { return Err(ProtocolInitializerErrorWrapper::KesMismatch( kes_sk_period, provided_period, )); } + + // We need to perform the evolutions + for period in kes_sk_period..provided_period { + kes_sk + .update() + .map_err(|_| ProtocolInitializerErrorWrapper::KesUpdate(period))?; + } + + Some(kes_sk.sign(&stm_initializer.verification_key().to_bytes())) } else { println!("WARNING: Non certified signer registration by providing only a Pool Id is decommissionned and must be used for tests only!"); None From b592b2270707ca8aac7b478f0d959d73cd0ff044 Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Wed, 4 Jan 2023 14:21:30 +0100 Subject: [PATCH 7/7] Version 0.2.1 --- Cargo.lock | 2 +- mithril-common/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d9280ee3a3..1e5d794f696 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2060,7 +2060,7 @@ dependencies = [ [[package]] name = "mithril-common" -version = "0.2.0" +version = "0.2.1" dependencies = [ "async-trait", "bech32", diff --git a/mithril-common/Cargo.toml b/mithril-common/Cargo.toml index daabcb02ef2..de125155a24 100644 --- a/mithril-common/Cargo.toml +++ b/mithril-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-common" -version = "0.2.0" +version = "0.2.1" authors = { workspace = true } edition = { workspace = true } documentation = { workspace = true }