Skip to content

Commit 4bbe8fd

Browse files
committed
feat: add new 'genesis generate-keypair' command to aggregator
1 parent 0a7fb9f commit 4bbe8fd

File tree

3 files changed

+97
-14
lines changed

3 files changed

+97
-14
lines changed

mithril-aggregator/src/commands/genesis_command.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ pub enum GenesisSubCommand {
4545

4646
/// Genesis certificate bootstrap command.
4747
Bootstrap(BootstrapGenesisSubCommand),
48+
49+
/// Genesis certificate keypair generation command.
50+
GenerateKeypair(GenerateKeypairGenesisSubCommand),
4851
}
4952

5053
impl GenesisSubCommand {
@@ -58,6 +61,7 @@ impl GenesisSubCommand {
5861
Self::Export(cmd) => cmd.execute(root_logger, config_builder).await,
5962
Self::Import(cmd) => cmd.execute(root_logger, config_builder).await,
6063
Self::Sign(cmd) => cmd.execute(root_logger, config_builder).await,
64+
Self::GenerateKeypair(cmd) => cmd.execute(root_logger, config_builder).await,
6165
}
6266
}
6367
}
@@ -229,3 +233,30 @@ impl BootstrapGenesisSubCommand {
229233
Ok(())
230234
}
231235
}
236+
237+
/// Genesis certificate keypair generation command.
238+
#[derive(Parser, Debug, Clone)]
239+
pub struct GenerateKeypairGenesisSubCommand {
240+
/// Target Path for the generated keypair
241+
#[clap(long)]
242+
target_path: PathBuf,
243+
}
244+
245+
impl GenerateKeypairGenesisSubCommand {
246+
pub async fn execute(
247+
&self,
248+
root_logger: Logger,
249+
_config_builder: ConfigBuilder<DefaultState>,
250+
) -> StdResult<()> {
251+
debug!(root_logger, "GENERATE KEYPAIR GENESIS command");
252+
println!(
253+
"Generating genesis keypair to {}",
254+
self.target_path.to_string_lossy()
255+
);
256+
257+
GenesisTools::create_and_save_genesis_keypair(&self.target_path)
258+
.with_context(|| "genesis-tools: keypair generation error")?;
259+
260+
Ok(())
261+
}
262+
}

mithril-aggregator/src/tools/genesis.rs

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
use anyhow::{anyhow, Context};
2-
use std::{fs::File, io::prelude::*, io::Write, path::Path, sync::Arc};
2+
use std::{
3+
fs::File,
4+
io::{prelude::*, Write},
5+
path::{Path, PathBuf},
6+
sync::Arc,
7+
};
38

49
use mithril_common::{
510
certificate_chain::{CertificateGenesisProducer, CertificateVerifier},
@@ -201,16 +206,25 @@ impl GenesisTools {
201206
})?;
202207
Ok(())
203208
}
209+
210+
/// Export the genesis keypair to a folder and returns the paths to the files (secret key, verification_key)
211+
pub fn create_and_save_genesis_keypair(keypair_path: &Path) -> StdResult<(PathBuf, PathBuf)> {
212+
let genesis_signer = ProtocolGenesisSigner::create_non_deterministic_genesis_signer();
213+
214+
genesis_signer.export_keypair_to_files(keypair_path)
215+
}
204216
}
205217

206218
#[cfg(test)]
207219
mod tests {
208220
use mithril_common::{
209221
certificate_chain::MithrilCertificateVerifier,
210-
crypto_helper::ProtocolGenesisSigner,
222+
crypto_helper::{
223+
ProtocolGenesisSecretKey, ProtocolGenesisSigner, ProtocolGenesisVerificationKey,
224+
},
211225
test_utils::{fake_data, MithrilFixtureBuilder, TempDir},
212226
};
213-
use std::path::PathBuf;
227+
use std::{fs::read_to_string, path::PathBuf};
214228

215229
use crate::database::test_helper::main_db_connection;
216230
use crate::test_tools::TestLogger;
@@ -266,14 +280,13 @@ mod tests {
266280
let test_dir = get_temp_dir("export_payload_to_sign");
267281
let payload_path = test_dir.join("payload.txt");
268282
let signed_payload_path = test_dir.join("payload-signed.txt");
269-
let genesis_secret_key_path = test_dir.join("genesis.sk");
270283
let genesis_signer = ProtocolGenesisSigner::create_deterministic_genesis_signer();
271284
let (genesis_tools, certificate_store, genesis_verifier, certificate_verifier) =
272285
build_tools(&genesis_signer);
273286

274-
genesis_signer
275-
.export_to_file(&genesis_secret_key_path)
276-
.expect("exporting the secret key should not fail");
287+
let (genesis_secret_key_path, _) = genesis_signer
288+
.export_keypair_to_files(&test_dir)
289+
.expect("exporting the keypair should not fail");
277290
genesis_tools
278291
.export_payload_to_sign(&payload_path)
279292
.expect("export_payload_to_sign should not fail");
@@ -327,4 +340,27 @@ mod tests {
327340
"verify_genesis_certificate should successfully validate the genesis certificate",
328341
);
329342
}
343+
344+
#[test]
345+
fn test_create_and_save_genesis_keypair() {
346+
let temp_dir = get_temp_dir("test_create_and_save_genesis_keypair");
347+
let (genesis_secret_key_path, genesis_verification_key_path) =
348+
GenesisTools::create_and_save_genesis_keypair(&temp_dir)
349+
.expect("Failed to create and save genesis keypair");
350+
let genesis_secret_key = ProtocolGenesisSecretKey::from_json_hex(
351+
&read_to_string(&genesis_secret_key_path)
352+
.expect("Failed to read genesis secret key file"),
353+
)
354+
.expect("Failed to parse genesis secret key");
355+
let genesis_verification_key = ProtocolGenesisVerificationKey::from_json_hex(
356+
&read_to_string(&genesis_verification_key_path)
357+
.expect("Failed to read genesis verification key file"),
358+
)
359+
.expect("Failed to parse genesis verification key");
360+
let genesis_verifier =
361+
ProtocolGenesisSigner::from_secret_key(genesis_secret_key).create_genesis_verifier();
362+
363+
let expected_genesis_verification_key = genesis_verifier.to_verification_key();
364+
assert_eq!(expected_genesis_verification_key, genesis_verification_key);
365+
}
330366
}

mithril-common/src/crypto_helper/genesis.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ use rand_chacha::rand_core;
66
use rand_chacha::rand_core::{CryptoRng, RngCore, SeedableRng};
77
use rand_chacha::ChaCha20Rng;
88
use serde::{Deserialize, Serialize};
9-
use std::{fs::File, io::Write, path::Path};
9+
use std::{
10+
fs::File,
11+
io::Write,
12+
path::{Path, PathBuf},
13+
};
1014
use thiserror::Error;
1115

1216
use super::{ProtocolGenesisSecretKey, ProtocolGenesisSignature, ProtocolGenesisVerificationKey};
@@ -63,13 +67,25 @@ impl ProtocolGenesisSigner {
6367
self.secret_key.sign(message).into()
6468
}
6569

66-
/// Export the secret key from the genesis verifier to a file. TEST ONLY
67-
#[doc(hidden)]
68-
pub fn export_to_file(&self, secret_key_path: &Path) -> StdResult<()> {
69-
let mut genesis_secret_key_file = File::create(secret_key_path)?;
70-
genesis_secret_key_file.write_all(self.secret_key.to_json_hex().unwrap().as_bytes())?;
70+
/// Export the keypair from the genesis verifier to files
71+
pub fn export_keypair_to_files(&self, keypair_path: &Path) -> StdResult<(PathBuf, PathBuf)> {
72+
let genesis_secret_key_path = keypair_path.join("genesis.sk");
73+
{
74+
let genesis_secret_key_payload = self.secret_key.to_json_hex().unwrap();
75+
let mut genesis_secret_key_file = File::create(&genesis_secret_key_path)?;
76+
genesis_secret_key_file.write_all(genesis_secret_key_payload.as_bytes())?;
77+
}
78+
79+
let genesis_verification_key_path = keypair_path.join("genesis.vk");
80+
{
81+
let genesis_verification_key: ProtocolGenesisVerificationKey =
82+
self.secret_key.verifying_key().into();
83+
let genesis_verification_key_payload = genesis_verification_key.to_json_hex().unwrap();
84+
let mut genesis_verification_key_file = File::create(&genesis_verification_key_path)?;
85+
genesis_verification_key_file.write_all(genesis_verification_key_payload.as_bytes())?;
86+
}
7187

72-
Ok(())
88+
Ok((genesis_secret_key_path, genesis_verification_key_path))
7389
}
7490
}
7591

0 commit comments

Comments
 (0)