Skip to content

Commit

Permalink
Merge pull request #1950 from input-output-hk/jpraynaud/sign-protocol…
Browse files Browse the repository at this point in the history
…-parameters-genesis-certificate

Feat: sign protocol parameters in Genesis certificate
  • Loading branch information
jpraynaud authored Sep 24, 2024
2 parents 04bd838 + 9c62875 commit 17b94ba
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 38 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ As a minor extension, we have adopted a slightly different versioning convention

- Support for new `Pythagoras` Mithril era.

- Support for signing the protocol parameters in the Genesis certificate.

- Crates versions:

| Crate | Version |
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion mithril-aggregator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-aggregator"
version = "0.5.66"
version = "0.5.67"
description = "A Mithril Aggregator server"
authors = { workspace = true }
edition = { workspace = true }
Expand Down
46 changes: 19 additions & 27 deletions mithril-aggregator/src/tools/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,30 +39,30 @@ pub struct GenesisToolsDependency {
}

pub struct GenesisTools {
protocol_parameters: ProtocolParameters,
network: CardanoNetwork,
time_point: TimePoint,
genesis_avk: ProtocolAggregateVerificationKey,
genesis_protocol_parameters: ProtocolParameters,
genesis_verifier: Arc<ProtocolGenesisVerifier>,
certificate_verifier: Arc<dyn CertificateVerifier>,
certificate_repository: Arc<CertificateRepository>,
}

impl GenesisTools {
pub fn new(
protocol_parameters: ProtocolParameters,
network: CardanoNetwork,
time_point: TimePoint,
genesis_avk: ProtocolAggregateVerificationKey,
genesis_protocol_parameters: ProtocolParameters,
genesis_verifier: Arc<ProtocolGenesisVerifier>,
certificate_verifier: Arc<dyn CertificateVerifier>,
certificate_repository: Arc<CertificateRepository>,
) -> Self {
Self {
protocol_parameters,
network,
time_point,
genesis_avk,
genesis_protocol_parameters,
genesis_verifier,
certificate_verifier,
certificate_repository,
Expand All @@ -72,22 +72,12 @@ impl GenesisTools {
pub async fn from_dependencies(dependencies: GenesisToolsDependency) -> StdResult<Self> {
let ticker_service = dependencies.ticker_service.clone();
let time_point = ticker_service.get_current_time_point().await?;

let genesis_verifier = dependencies.genesis_verifier.clone();
let certificate_verifier = dependencies.certificate_verifier.clone();
let certificate_repository = dependencies.certificate_repository.clone();
let epoch_settings_storer = dependencies.epoch_settings_storer.clone();

let protocol_params_epoch = time_point.epoch.offset_to_signer_retrieval_epoch()?;
let protocol_parameters = epoch_settings_storer
.get_protocol_parameters(protocol_params_epoch)
.await?
.ok_or_else(|| {
anyhow!("Missing protocol parameters for epoch {protocol_params_epoch}")
})?;

let genesis_avk_epoch = time_point.epoch.offset_to_next_signer_retrieval_epoch();
let genesis_avk_protocol_parameters = epoch_settings_storer
let genesis_protocol_parameters = epoch_settings_storer
.get_protocol_parameters(time_point.epoch.offset_to_signer_retrieval_epoch()?)
.await?
.ok_or_else(|| anyhow!("Missing protocol parameters for epoch {genesis_avk_epoch}"))?;
Expand All @@ -98,17 +88,16 @@ impl GenesisTools {
.ok_or_else(|| anyhow!("Missing signers for epoch {genesis_avk_epoch}"))?;

let protocol_multi_signer =
SignerBuilder::new(&genesis_signers, &genesis_avk_protocol_parameters)
SignerBuilder::new(&genesis_signers, &genesis_protocol_parameters)
.with_context(|| "Could not build a multi signer to compute the genesis avk")?
.build_multi_signer();

let genesis_avk = protocol_multi_signer.compute_aggregate_verification_key();

Ok(Self::new(
protocol_parameters,
dependencies.network,
time_point,
genesis_avk,
genesis_protocol_parameters,
genesis_verifier,
certificate_verifier,
certificate_repository,
Expand All @@ -118,8 +107,10 @@ impl GenesisTools {
/// Export AVK of the genesis stake distribution to a payload file
pub fn export_payload_to_sign(&self, target_path: &Path) -> StdResult<()> {
let mut target_file = File::create(target_path)?;
let protocol_message =
CertificateGenesisProducer::create_genesis_protocol_message(&self.genesis_avk)?;
let protocol_message = CertificateGenesisProducer::create_genesis_protocol_message(
&self.genesis_protocol_parameters,
&self.genesis_avk,
)?;
target_file.write_all(protocol_message.compute_hash().as_bytes())?;
Ok(())
}
Expand All @@ -141,8 +132,10 @@ impl GenesisTools {
genesis_signer: ProtocolGenesisSigner,
) -> StdResult<()> {
let genesis_producer = CertificateGenesisProducer::new(Some(Arc::new(genesis_signer)));
let genesis_protocol_message =
CertificateGenesisProducer::create_genesis_protocol_message(&self.genesis_avk)?;
let genesis_protocol_message = CertificateGenesisProducer::create_genesis_protocol_message(
&self.genesis_protocol_parameters,
&self.genesis_avk,
)?;
let genesis_signature =
genesis_producer.sign_genesis_protocol_message(genesis_protocol_message)?;
self.create_and_save_genesis_certificate(genesis_signature)
Expand Down Expand Up @@ -183,7 +176,7 @@ impl GenesisTools {
genesis_signature: ProtocolGenesisSignature,
) -> StdResult<()> {
let genesis_certificate = CertificateGenesisProducer::create_genesis_certificate(
self.protocol_parameters.clone(),
self.genesis_protocol_parameters.clone(),
self.network.to_string(),
self.time_point.epoch,
self.time_point.immutable_file_number,
Expand Down Expand Up @@ -214,7 +207,7 @@ mod tests {
use crate::database::test_helper::main_db_connection;
use mithril_common::{
certificate_chain::MithrilCertificateVerifier,
crypto_helper::{ProtocolClerk, ProtocolGenesisSigner},
crypto_helper::ProtocolGenesisSigner,
test_utils::{fake_data, MithrilFixtureBuilder, TempDir},
};
use std::path::PathBuf;
Expand All @@ -227,9 +220,8 @@ mod tests {

fn create_fake_genesis_avk() -> ProtocolAggregateVerificationKey {
let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
let first_signer = fixture.signers_fixture()[0].clone().protocol_signer;
let clerk = ProtocolClerk::from_signer(&first_signer);
clerk.compute_avk().into()

fixture.compute_avk()
}

fn build_tools(
Expand All @@ -249,10 +241,10 @@ mod tests {
let genesis_avk = create_fake_genesis_avk();
let genesis_verifier = Arc::new(genesis_signer.create_genesis_verifier());
let genesis_tools = GenesisTools::new(
fake_data::protocol_parameters(),
fake_data::network(),
TimePoint::dummy(),
genesis_avk,
fake_data::protocol_parameters(),
genesis_verifier.clone(),
certificate_verifier.clone(),
certificate_store.clone(),
Expand Down
2 changes: 1 addition & 1 deletion mithril-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-common"
version = "0.4.56"
version = "0.4.57"
description = "Common types, interfaces, and utilities for Mithril nodes."
authors = { workspace = true }
edition = { workspace = true }
Expand Down
42 changes: 40 additions & 2 deletions mithril-common/src/certificate_chain/certificate_genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ impl CertificateGenesisProducer {

/// Create the Genesis protocol message
pub fn create_genesis_protocol_message(
genesis_protocol_parameters: &ProtocolParameters,
genesis_avk: &ProtocolAggregateVerificationKey,
) -> StdResult<ProtocolMessage> {
let genesis_avk = genesis_avk.to_json_hex()?;
Expand All @@ -49,6 +50,10 @@ impl CertificateGenesisProducer {
ProtocolMessagePartKey::NextAggregateVerificationKey,
genesis_avk,
);
protocol_message.set_message_part(
ProtocolMessagePartKey::NextProtocolParameters,
genesis_protocol_parameters.compute_hash(),
);
Ok(protocol_message)
}

Expand Down Expand Up @@ -82,13 +87,14 @@ impl CertificateGenesisProducer {
network,
immutable_file_number,
protocol_version,
protocol_parameters,
protocol_parameters.clone(),
initiated_at,
sealed_at,
signers,
);
let previous_hash = "".to_string();
let genesis_protocol_message = Self::create_genesis_protocol_message(&genesis_avk)?;
let genesis_protocol_message =
Self::create_genesis_protocol_message(&protocol_parameters, &genesis_avk)?;
Ok(Certificate::new(
previous_hash,
epoch,
Expand All @@ -99,3 +105,35 @@ impl CertificateGenesisProducer {
))
}
}

#[cfg(test)]
mod tests {
use super::*;

use crate::{entities::ProtocolMessagePartKey, test_utils::MithrilFixtureBuilder};

#[test]
fn test_create_genesis_protocol_message_has_expected_keys_and_values() {
let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
let genesis_protocol_parameters = fixture.protocol_parameters();
let genesis_avk = fixture.compute_avk();
let protocol_message = CertificateGenesisProducer::create_genesis_protocol_message(
&genesis_protocol_parameters,
&genesis_avk,
)
.unwrap();

let expected_genesis_avk_value = fixture.compute_and_encode_avk();
assert_eq!(
protocol_message
.get_message_part(&ProtocolMessagePartKey::NextAggregateVerificationKey),
Some(&expected_genesis_avk_value)
);

let expected_genesis_protocol_parameters_value = genesis_protocol_parameters.compute_hash();
assert_eq!(
protocol_message.get_message_part(&ProtocolMessagePartKey::NextProtocolParameters),
Some(&expected_genesis_protocol_parameters_value)
);
}
}
9 changes: 6 additions & 3 deletions mithril-common/src/crypto_helper/tests_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ pub fn setup_certificate_chain(
let next_fixture = fixture_per_epoch.get(&(epoch + 1)).unwrap();
let avk = avk_for_signers(&fixture.signers_fixture());
let next_avk = avk_for_signers(&next_fixture.signers_fixture());
let next_protocol_parameters = &next_fixture.protocol_parameters();
let mut fake_certificate = {
let mut base_certificate = fake_data::certificate(certificate_hash);
base_certificate
Expand All @@ -228,7 +229,6 @@ pub fn setup_certificate_chain(
ProtocolMessagePartKey::NextAggregateVerificationKey,
next_avk.to_json_hex().unwrap(),
);

Certificate {
epoch,
aggregate_verification_key: avk,
Expand All @@ -247,8 +247,11 @@ pub fn setup_certificate_chain(
match i {
0 => {
let genesis_protocol_message =
CertificateGenesisProducer::create_genesis_protocol_message(&next_avk)
.unwrap();
CertificateGenesisProducer::create_genesis_protocol_message(
next_protocol_parameters,
&next_avk,
)
.unwrap();
let genesis_signature = genesis_producer
.sign_genesis_protocol_message(genesis_protocol_message)
.unwrap();
Expand Down
27 changes: 27 additions & 0 deletions mithril-common/src/entities/protocol_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,19 @@ pub enum ProtocolMessagePartKey {
CardanoTransactionsMerkleRoot,

/// The ProtocolMessage part key associated to the Next epoch aggregate verification key
///
/// The AVK that will be allowed to be used to sign during the next epoch
/// aka AVK(n-1)
#[serde(rename = "next_aggregate_verification_key")]
NextAggregateVerificationKey,

/// The ProtocolMessage part key associated to the Next epoch protocol parameters
///
/// The protocol parameters that will be allowed to be used to sign during the next epoch
/// aka PPARAMS(n-1)
#[serde(rename = "next_protocol_parameters")]
NextProtocolParameters,

/// The ProtocolMessage part key associated to the latest block number signed
#[serde(rename = "latest_block_number")]
LatestBlockNumber,
Expand All @@ -39,6 +47,7 @@ impl Display for ProtocolMessagePartKey {
match *self {
Self::SnapshotDigest => write!(f, "snapshot_digest"),
Self::NextAggregateVerificationKey => write!(f, "next_aggregate_verification_key"),
Self::NextProtocolParameters => write!(f, "next_protocol_parameters"),
Self::CardanoTransactionsMerkleRoot => write!(f, "cardano_transactions_merkle_root"),
Self::LatestBlockNumber => write!(f, "latest_block_number"),
Self::CardanoStakeDistributionEpoch => write!(f, "cardano_stake_distribution_epoch"),
Expand Down Expand Up @@ -191,6 +200,20 @@ mod tests {
assert_ne!(hash_expected, protocol_message_modified.compute_hash());
}

#[test]
fn test_protocol_message_compute_hash_include_next_protocol_parameters() {
let protocol_message = build_protocol_message_reference();
let hash_expected = protocol_message.compute_hash();

let mut protocol_message_modified = protocol_message.clone();
protocol_message_modified.set_message_part(
ProtocolMessagePartKey::NextProtocolParameters,
"latest-protocol-parameters-456".to_string(),
);

assert_ne!(hash_expected, protocol_message_modified.compute_hash());
}

#[test]
fn test_protocol_message_compute_hash_the_same_hash_with_same_protocol_message() {
assert_eq!(
Expand All @@ -209,6 +232,10 @@ mod tests {
ProtocolMessagePartKey::NextAggregateVerificationKey,
"next-avk-123".to_string(),
);
protocol_message.set_message_part(
ProtocolMessagePartKey::NextProtocolParameters,
"next-protocol-parameters-123".to_string(),
);
protocol_message.set_message_part(
ProtocolMessagePartKey::CardanoTransactionsMerkleRoot,
"ctx-merkle-root-123".to_string(),
Expand Down
7 changes: 5 additions & 2 deletions mithril-common/src/test_utils/mithril_fixture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,11 @@ impl MithrilFixture {
let genesis_avk = self.compute_avk();
let genesis_signer = ProtocolGenesisSigner::create_deterministic_genesis_signer();
let genesis_producer = CertificateGenesisProducer::new(Some(Arc::new(genesis_signer)));
let genesis_protocol_message =
CertificateGenesisProducer::create_genesis_protocol_message(&genesis_avk).unwrap();
let genesis_protocol_message = CertificateGenesisProducer::create_genesis_protocol_message(
&self.protocol_parameters,
&genesis_avk,
)
.unwrap();
let genesis_signature = genesis_producer
.sign_genesis_protocol_message(genesis_protocol_message)
.unwrap();
Expand Down

0 comments on commit 17b94ba

Please sign in to comment.