use std::{fs, path::Path};
use casper_types::{AsymmetricType, PublicKey, SecretKey};
use crate::Error;
pub const SECRET_KEY_PEM: &str = "secret_key.pem";
pub const PUBLIC_KEY_HEX: &str = "public_key_hex";
pub const PUBLIC_KEY_PEM: &str = "public_key.pem";
pub const FILES: [&str; 3] = [SECRET_KEY_PEM, PUBLIC_KEY_PEM, PUBLIC_KEY_HEX];
pub const ED25519: &str = "Ed25519";
pub const SECP256K1: &str = "secp256k1";
pub fn generate_files(output_dir: &str, algorithm: &str, force: bool) -> Result<(), Error> {
if output_dir.is_empty() {
return Err(Error::EmptyKeygenPath);
}
fs::create_dir_all(output_dir).map_err(move |error| Error::IoError {
context: format!("unable to create directory at '{}'", output_dir),
error,
})?;
let output_dir = Path::new(output_dir)
.canonicalize()
.map_err(|error| Error::IoError {
context: format!("unable get canonical path at '{}'", output_dir),
error,
})?;
if !force {
for file in FILES.iter().map(|filename| output_dir.join(filename)) {
if file.exists() {
return Err(Error::FileAlreadyExists(file));
}
}
}
let secret_key = if algorithm.eq_ignore_ascii_case(ED25519) {
SecretKey::generate_ed25519().unwrap()
} else if algorithm.eq_ignore_ascii_case(SECP256K1) {
SecretKey::generate_secp256k1().unwrap()
} else {
return Err(Error::UnsupportedAlgorithm(algorithm.to_string()));
};
let public_key = PublicKey::from(&secret_key);
let public_key_hex_path = output_dir.join(PUBLIC_KEY_HEX);
fs::write(public_key_hex_path, public_key.to_hex()).map_err(|error| Error::IoError {
context: format!(
"unable to write public key hex file at {:?}",
output_dir.join(PUBLIC_KEY_HEX)
),
error,
})?;
let secret_key_path = output_dir.join(SECRET_KEY_PEM);
secret_key
.to_file(secret_key_path)
.map_err(|error| Error::CryptoError {
context: "secret_key",
error,
})?;
let public_key_path = output_dir.join(PUBLIC_KEY_PEM);
public_key
.to_file(public_key_path)
.map_err(|error| Error::CryptoError {
context: "public_key",
error,
})?;
Ok(())
}