Skip to content

Commit

Permalink
Merge pull request #1082 from input-output-hk/jpraynaud/1081-add-sign…
Browse files Browse the repository at this point in the history
…-genesis-sub-command

Add `sign` sub-command in aggregator `genesis` command
  • Loading branch information
jpraynaud authored Jul 26, 2023
2 parents 456a5ae + b3c67e4 commit 147c49d
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 35 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

38 changes: 25 additions & 13 deletions docs/root/manual/developer-docs/nodes/mithril-aggregator.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ SUBCOMMANDS:
import Import payload signed with genesis secret key and create & import a genesis certificate
```

### bootstrap sub-command (test-only)

Run 'genesis bootstrap' command in release with default configuration, **only in test mode**.
This allows the Mithril Aggregator node to bootstrap a `Genesis Certificate`. After this operation, the Mithril Aggregator will be able to produce new snapshots and certificates.

Expand All @@ -203,27 +205,28 @@ Or with a specific `Genesis Secret Key`, **only in test mode**.
./mithril-aggregator genesis bootstrap --genesis-secret-key **YOUR_SECRET_KEY*
```

Run 'genesis export' command in release with default configuration.
This allows the Mithril Aggregator node to export the `Genesis Payload` that needs to be signed (and later reimported) of the `Genesis Certificate`. The signature of the `Genesis Payload` must be done manually with the owner of the `Genesis Secret Key`.

```bash
./mithril-aggregator genesis export
```
### export sub-command

Or with a custom export path (to override the default value `./mithril-genesis-payload.txt`)
Run 'genesis export' command in release.
This allows the Mithril Aggregator node to export the `Genesis Payload` that needs to be signed (and later reimported) of the `Genesis Certificate`. The signature of the `Genesis Payload` must be done manually with the owner of the `Genesis Secret Key`.

```bash
./mithril-aggregator genesis export --target-path **YOUR_TARGET_PATH**
```

Run 'genesis import' command in release with default configuration.
This allows the Mithril Aggregator node to import the signed payload of the `Genesis Certificate` and create it in the store. After this operation, the Mithril Aggregator will be able to produce new snapshots and certificates.
### sign sub-command

Run 'genesis sign' command in release.
This allows the Mithril Aggregator node to sign the `Genesis Payload` that needs to be reimported. The signature of the `Genesis Payload` must be done manually by the owner of the `Genesis Secret Key`.

```bash
./mithril-aggregator genesis import
./mithril-aggregator genesis sign --to-sign-payload-path **TO_SIGN_PAYLOAD_PATH** --target-signed-payload-path **TARGET_SIGNED_PAYLOAD_PATH** --genesis-secret-key-path **GENESIS_SECRET_KEY_PATH**
```

Or with a custom export path (to override the default value `./mithril-genesis-signed-payload.txt`)
### import sub-command

Run 'genesis import' command in release.
This allows the Mithril Aggregator node to import the signed payload of the `Genesis Certificate` and create it in the store. After this operation, the Mithril Aggregator will be able to produce new snapshots and certificates.

```bash
./mithril-aggregator genesis import --signed-payload-path **YOUR_SIGNED_PAYLOAD_PATH**
Expand Down Expand Up @@ -397,6 +400,7 @@ Here are the subcommands available:
| **serve** | Aggregator runs its HTTP server in nominal mode and orchestrates multi signatures production |
| **help** | Print this message or the help of the given subcommand(s) |
| **genesis export** | Export genesis payload to sign with genesis secret key |
| **genesis sign** | Sign genesis payload with genesis secret key |
| **genesis import** | Import genesis signature (payload signed with genesis secret key) and create & import a genesis certificate in the store |
| **genesis bootstrap** | Bootstrap a genesis certificate (test only usage) |
| **era list** | List the supported eras |
Expand Down Expand Up @@ -450,17 +454,25 @@ General parameters:
|-----------|---------------------|:---------------------:|----------------------|-------------|---------------|---------|:---------:|
| `genesis_secret_key` | - | - | `GENESIS_SECRET_KEY` | Genesis secret key, :warning: for test only | - | - | - |

`genesis export` command:

| Parameter | Command Line (long) | Command Line (short) | Environment Variable | Description | Default Value | Example | Mandatory |
|-----------|---------------------|:---------------------:|----------------------|-------------|---------------|---------|:---------:|
| `target_path` | `--target-path` | - | - | Path of the file to export the payload to. | - | - | - | - |

`genesis import` command:

| Parameter | Command Line (long) | Command Line (short) | Environment Variable | Description | Default Value | Example | Mandatory |
|-----------|---------------------|:---------------------:|----------------------|-------------|---------------|---------|:---------:|
| `signed_payload_path` | `--signed-payload-path` | - | - | Path of the payload to import. | - | - | - | - |

`genesis export` command:
`genesis sign` command:

| Parameter | Command Line (long) | Command Line (short) | Environment Variable | Description | Default Value | Example | Mandatory |
|-----------|---------------------|:---------------------:|----------------------|-------------|---------------|---------|:---------:|
| `target_path` | `--target-path` | - | - | Path of the file to export the payload to. | - | - | - | - |
| `to_sign_payload_path` | `--to-sign-payload-path` | - | - | Path of the payload to sign. | - | - | - | - |
| `target_signed_payload_path` | `--target-signed-payload-path` | - | - | Path of the signed payload to export. | - | - | - | - |
| `genesis_secret_key_path` | `--genesis-secret-key-path` | - | - | Path of the Genesis secret key. | - | - | - |

`era list` command:

Expand Down
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.3.57"
version = "0.3.58"
description = "A Mithril Aggregator server"
authors = { workspace = true }
edition = { workspace = true }
Expand Down
42 changes: 42 additions & 0 deletions mithril-aggregator/src/commands/genesis_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ pub enum GenesisSubCommand {
/// Genesis certificate import command.
Import(ImportGenesisSubCommand),

/// Genesis certificate sign command.
Sign(SignGenesisSubCommand),

/// Genesis certificate bootstrap command.
Bootstrap(BootstrapGenesisSubCommand),
}
Expand All @@ -48,6 +51,7 @@ impl GenesisSubCommand {
Self::Bootstrap(cmd) => cmd.execute(config_builder).await,
Self::Export(cmd) => cmd.execute(config_builder).await,
Self::Import(cmd) => cmd.execute(config_builder).await,
Self::Sign(cmd) => cmd.execute(config_builder).await,
}
}
}
Expand Down Expand Up @@ -124,6 +128,44 @@ impl ImportGenesisSubCommand {
}
}

#[derive(Parser, Debug, Clone)]
pub struct SignGenesisSubCommand {
/// To Sign Payload Path
#[clap(long)]
to_sign_payload_path: PathBuf,

/// Target Signed Payload Path
#[clap(long)]
target_signed_payload_path: PathBuf,

/// Genesis Secret Key Path
#[clap(long)]
genesis_secret_key_path: PathBuf,
}

impl SignGenesisSubCommand {
pub async fn execute(
&self,
_config_builder: ConfigBuilder<DefaultState>,
) -> Result<(), Box<dyn Error>> {
debug!("SIGN GENESIS command");
println!(
"Genesis sign payload from {} to {}",
self.to_sign_payload_path.to_string_lossy(),
self.target_signed_payload_path.to_string_lossy()
);

GenesisTools::sign_genesis_certificate(
&self.to_sign_payload_path,
&self.target_signed_payload_path,
&self.genesis_secret_key_path,
)
.await
.map_err(|err| format!("genesis-tools: sign error: {err}"))?;

Ok(())
}
}
#[derive(Parser, Debug, Clone)]
pub struct BootstrapGenesisSubCommand {
/// Genesis Secret Key (test only)
Expand Down
62 changes: 43 additions & 19 deletions mithril-aggregator/src/tools/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,32 @@ impl GenesisTools {
.await
}

/// Sign the genesis certificate
pub async fn sign_genesis_certificate(
to_sign_payload_path: &Path,
target_signed_payload_path: &Path,
genesis_secret_key_path: &Path,
) -> StdResult<()> {
let mut genesis_secret_key_file = File::open(genesis_secret_key_path).unwrap();
let mut genesis_secret_key_serialized = String::new();
genesis_secret_key_file.read_to_string(&mut genesis_secret_key_serialized)?;

let genesis_secret_key = key_decode_hex(&genesis_secret_key_serialized.trim().to_string())?;
let genesis_signer = ProtocolGenesisSigner::from_secret_key(genesis_secret_key);

let mut to_sign_payload_file = File::open(to_sign_payload_path).unwrap();
let mut to_sign_payload_buffer = Vec::new();
to_sign_payload_file.read_to_end(&mut to_sign_payload_buffer)?;

let genesis_signature = genesis_signer.sign(&to_sign_payload_buffer);
let signed_payload = genesis_signature.to_bytes();

let mut target_signed_payload_file = File::create(target_signed_payload_path)?;
target_signed_payload_file.write_all(&signed_payload)?;

Ok(())
}

async fn create_and_save_genesis_certificate(
&self,
genesis_signature: ProtocolGenesisSignature,
Expand Down Expand Up @@ -162,7 +188,10 @@ mod tests {
use super::*;

fn get_temp_dir(dir_name: &str) -> PathBuf {
let dir = std::env::temp_dir().join("mithril_test").join(dir_name);
let dir = std::env::temp_dir()
.join("mithril_test")
.join("genesis")
.join(dir_name);

if dir.exists() {
let _ = fs::remove_dir_all(&dir);
Expand All @@ -180,20 +209,6 @@ mod tests {
clerk.compute_avk()
}

fn sign_avk_payload(
payload_path: &Path,
target_path: &Path,
genesis_signer: &ProtocolGenesisSigner,
) -> StdResult<()> {
let mut payload_file = File::open(payload_path).unwrap();
let mut payload_buffer = Vec::new();
payload_file.read_to_end(&mut payload_buffer)?;
let payload_signed = genesis_signer.sign(&payload_buffer).to_bytes();
let mut target_file = File::create(target_path)?;
target_file.write_all(&payload_signed)?;
Ok(())
}

fn build_tools(
genesis_signer: &ProtocolGenesisSigner,
) -> (
Expand Down Expand Up @@ -229,17 +244,26 @@ mod tests {
#[tokio::test]
async fn export_sign_then_import_genesis_payload() {
let test_dir = get_temp_dir("export_payload_to_sign");
let path = test_dir.join("payload.txt");
let payload_path = test_dir.join("payload.txt");
let signed_payload_path = test_dir.join("payload-signed.txt");
let genesis_secret_key_path = test_dir.join("genesis.sk");
let genesis_signer = ProtocolGenesisSigner::create_deterministic_genesis_signer();
let (genesis_tools, certificate_store, genesis_verifier, certificate_verifier) =
build_tools(&genesis_signer);

genesis_signer
.export_to_file(&genesis_secret_key_path)
.expect("exporting the secret key should not fail");
genesis_tools
.export_payload_to_sign(&path)
.export_payload_to_sign(&payload_path)
.expect("export_payload_to_sign should not fail");
sign_avk_payload(&path, &signed_payload_path, &genesis_signer)
.expect("sign avk payload should not fail");
GenesisTools::sign_genesis_certificate(
&payload_path,
&signed_payload_path,
&genesis_secret_key_path,
)
.await
.expect("sign_genesis_certificate should not fail");
genesis_tools
.import_payload_signature(&signed_payload_path)
.await
Expand Down
21 changes: 20 additions & 1 deletion mithril-common/src/crypto_helper/genesis.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use crate::StdResult;
use ed25519_dalek::{ExpandedSecretKey, SignatureError};
use rand_chacha_dalek_compat::rand_core::{self, CryptoRng, RngCore, SeedableRng};
use rand_chacha_dalek_compat::ChaCha20Rng;
use serde::{Deserialize, Serialize};
use std::{fs::File, io::Write, path::Path};
use thiserror::Error;

use super::{ProtocolGenesisSecretKey, ProtocolGenesisSignature, ProtocolGenesisVerificationKey};
use super::{
key_encode_hex, ProtocolGenesisSecretKey, ProtocolGenesisSignature,
ProtocolGenesisVerificationKey,
};

#[derive(Error, Debug)]
/// [ProtocolGenesisSigner] and [ProtocolGenesisVerifier] related errors.
Expand All @@ -18,6 +23,7 @@ pub enum ProtocolGenesisError {
/// [Genesis Certificate](https://mithril.network/doc/mithril/mithril-protocol/certificates#the-certificate-chain-design)
#[derive(Debug, Serialize, Deserialize)]
pub struct ProtocolGenesisSigner {
/// Protocol Genesis secret key
pub(crate) secret_key: ProtocolGenesisSecretKey,
}

Expand Down Expand Up @@ -75,6 +81,19 @@ impl ProtocolGenesisSigner {
let verification_key = self.create_verification_key(&expanded_secret_key);
expanded_secret_key.sign(message, &verification_key)
}

/// Export the secret key from the genesis verifier to a file. TEST ONLY
#[doc(hidden)]
pub fn export_to_file(&self, secret_key_path: &Path) -> StdResult<()> {
let mut genesis_secret_key_file = File::create(secret_key_path)?;
genesis_secret_key_file.write_all(
key_encode_hex(self.secret_key.as_bytes())
.unwrap()
.as_bytes(),
)?;

Ok(())
}
}

/// A protocol Genesis Verifier that is responsible for verifying the
Expand Down

0 comments on commit 147c49d

Please sign in to comment.