Skip to content

Commit

Permalink
move keypair generate to core cli
Browse files Browse the repository at this point in the history
  • Loading branch information
KaoImin committed Dec 11, 2023
1 parent 632507a commit 206e08b
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 1 deletion.
3 changes: 3 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions core/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0"
clap = { version = "4.4", features = ["cargo", "string", "derive"] }
semver = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tempfile = "3.6"
tentacle-secio = "0.6"
thiserror = "1.0"

common-config-parser = { path = "../../common/config-parser" }
common-crypto ={ path = "../../common/crypto" }
common-logger = { path = "../../common/logger" }
common-version = { path = "../../common/version" }
core-run = { path = "../../core/run" }
Expand Down
File renamed without changes.
124 changes: 124 additions & 0 deletions core/cli/src/args/generate_keypair.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use std::{fs::File, io::Write, path::PathBuf};

use clap::Parser;
use serde::Serialize;

use common_crypto::{BlsPrivateKey, PrivateKey, PublicKey, Secp256k1PrivateKey, ToBlsPublicKey};
use protocol::rand::rngs::OsRng;
use protocol::types::{Address, Bytes, Hex};
use tentacle_secio::SecioKeyPair;

use crate::error::{Error, Result};

#[derive(Parser, Debug)]
#[command(about = "Initialize new axon data directory")]
pub struct GenerateKeypairArgs {
#[arg(
short = 'n',
long = "number",
value_name = "NUMBER",
help = "The number of keypairs to generate.",
default_value = "1"
)]
pub num: usize,
#[arg(
short = 'p',
long = "path",
value_name = "PRIVATE_KEY_PATH",
help = "The path to store the generated private key binary.",
default_value = "free-space"
)]
pub path: String,
}

impl GenerateKeypairArgs {
pub(crate) fn execute(self) -> Result<()> {
let Self { num, path } = self;
let mut keypairs = Vec::with_capacity(num);
let path = PathBuf::from(path);

for i in 0..num {
let key_pair = Keypair::generate(i)?;
write_private_keys(
&path,
key_pair.net_private_key.as_bytes(),
key_pair.bls_private_key.as_bytes(),
i,
)?;
keypairs.push(Keypair::generate(i)?);
}

println!(
"{}",
serde_json::to_string_pretty(&Output { keypairs }).unwrap()
);

Ok(())
}
}

#[derive(Serialize, Clone, Debug)]
pub struct Keypair {
pub index: usize,
pub net_private_key: Hex,
pub public_key: Hex,
pub address: Address,
pub peer_id: Hex,
pub bls_private_key: Hex,
pub bls_public_key: Hex,
}

impl Keypair {
pub(crate) fn generate(i: usize) -> Result<Self> {
let bls_seckey = BlsPrivateKey::generate(&mut OsRng).to_bytes();
let net_seckey = Secp256k1PrivateKey::generate(&mut OsRng).to_bytes();
Self::from_private_keys(net_seckey, bls_seckey, i)
}

pub(crate) fn from_private_keys(
net_seckey: Bytes,
bls_seckey: Bytes,
i: usize,
) -> Result<Keypair> {
let secio_keypair = SecioKeyPair::secp256k1_raw_key(&net_seckey)
.map_err(|e| Error::Crypto(e.to_string()))?;
let pubkey = secio_keypair.public_key().inner();

let bls_priv_key = BlsPrivateKey::try_from(bls_seckey.as_ref())
.map_err(|e| Error::Crypto(e.to_string()))?;
let bls_pub_key = bls_priv_key.pub_key(&String::new());

Ok(Keypair {
index: i,
net_private_key: Hex::encode(&net_seckey),
public_key: Hex::encode(&pubkey),
address: Address::from_pubkey_bytes(pubkey).map_err(Error::Running)?,
peer_id: Hex::encode(secio_keypair.public_key().peer_id().to_base58()),
bls_private_key: Hex::encode(bls_seckey.to_vec()),
bls_public_key: Hex::encode(bls_pub_key.to_bytes()),
})
}
}

#[derive(Serialize, Clone, Debug)]
struct Output {
keypairs: Vec<Keypair>,
}

fn write_private_keys(path: &PathBuf, net_key: Bytes, bls_key: Bytes, index: usize) -> Result<()> {
let write = |path: PathBuf, data: Bytes| -> Result<()> {
let mut file = File::create(path).map_err(Error::WritingPrivateKey)?;
file.write_all(&data).map_err(Error::WritingPrivateKey)?;

Ok(())
};

let mut bls_key_path = path.clone();
bls_key_path.push(format!("bls_{}.key", index));
let mut net_key_path = path.clone();
net_key_path.push(format!("net_{}.key", index));

write(bls_key_path, bls_key)?;
write(net_key_path, net_key)?;
Ok(())
}
2 changes: 2 additions & 0 deletions core/cli/src/args/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub(crate) mod generate_keypair;
pub(crate) mod hardfork;
pub(crate) mod init;
pub(crate) mod recover_keypair;
pub(crate) mod run;
51 changes: 51 additions & 0 deletions core/cli/src/args/recover_keypair.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use std::{fs::File, io::Read, path::PathBuf};

use clap::Parser;

use protocol::types::Bytes;

use crate::args::generate_keypair::Keypair;
use crate::error::{Error, Result};

#[derive(Parser, Debug)]
#[command(about = "Initialize new axon data directory")]
pub struct RecoverKeypairArgs {
#[arg(
short = 'n',
long = "net_path",
value_name = "NET_PRIVATE_KEY_PATH",
help = "The path to store the net private key binary."
)]
pub net_private_key_path: String,
#[arg(
short = 'b',
long = "bls_path",
value_name = "BLS_PRIVATE_KEY_PATH",
help = "The path to store the bls private key binary."
)]
pub bls_private_key_path: String,
}

impl RecoverKeypairArgs {
pub(crate) fn execute(self) -> Result<()> {
let Self {
net_private_key_path,
bls_private_key_path,
} = self;
let net_private_key = read_private_key(&PathBuf::from(net_private_key_path))?;
let bls_private_key = read_private_key(&PathBuf::from(bls_private_key_path))?;

let output = Keypair::from_private_keys(net_private_key, bls_private_key, 0)?;
println!("{}", serde_json::to_string_pretty(&output).unwrap());

Ok(())
}
}

fn read_private_key(path: &PathBuf) -> Result<Bytes> {
let mut file = File::open(path).map_err(Error::ReadingPrivateKey)?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)
.map_err(Error::ReadingPrivateKey)?;
Ok(buf.into())
}
9 changes: 9 additions & 0 deletions core/cli/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,23 @@ pub enum Error {
// Boxing so the error type isn't too large (clippy::result-large-err).
#[error(transparent)]
CheckingVersion(Box<CheckingVersionError>),

#[error("reading data version: {0}")]
ReadingVersion(#[source] io::Error),
#[error("writing data version: {0}")]
WritingVersion(#[source] io::Error),

#[error("reading private key: {0}")]
ReadingPrivateKey(#[source] io::Error),
#[error("writing private key: {0}")]
WritingPrivateKey(#[source] io::Error),

#[error(transparent)]
Running(ProtocolError),

#[error("crypto error: {0}")]
Crypto(String),

#[error("internal error: {0}")]
Internal(String),
}
Expand Down
9 changes: 8 additions & 1 deletion core/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ mod args;
mod error;
pub(crate) mod utils;

pub use args::{hardfork::HardforkArgs, init::InitArgs, run::RunArgs};
pub use args::{
generate_keypair::GenerateKeypairArgs, hardfork::HardforkArgs, init::InitArgs,
recover_keypair::RecoverKeypairArgs, run::RunArgs,
};
pub use error::{CheckingVersionError, Error, Result};

use clap::{CommandFactory as _, FromArgMatches as _, Parser, Subcommand};
Expand All @@ -22,6 +25,8 @@ enum Commands {
Init(InitArgs),
Run(RunArgs),
Hardfork(HardforkArgs),
GenerateKeypair(GenerateKeypairArgs),
RecoverKeypair(RecoverKeypairArgs),
}

pub struct AxonCli {
Expand Down Expand Up @@ -62,6 +67,8 @@ impl AxonCli {
Commands::Init(args) => args.execute(kernel_version),
Commands::Run(args) => args.execute(application_version, kernel_version, key_provider),
Commands::Hardfork(args) => args.execute(),
Commands::GenerateKeypair(args) => args.execute(),
Commands::RecoverKeypair(args) => args.execute(),
}
}
}

0 comments on commit 206e08b

Please sign in to comment.