diff --git a/src/commands/cesium.rs b/src/commands/cesium.rs index dee9515d5cb0dc7b188db195d1da8e589257a513..f302e4c15c0c30cb70649caeae04a42288bfdbbc 100644 --- a/src/commands/cesium.rs +++ b/src/commands/cesium.rs @@ -1,6 +1,11 @@ -use crate::*; +use crate::data::Data; +use crate::keys; +use crate::keys::KeyPair; +use crate::runtime_config::AccountId; +use crate::utils::GcliError; use bs58; -use sp_core::ed25519; +use sp_core::{ed25519, Pair}; +use std::str::FromStr; /// define cesium subcommands #[derive(Clone, Default, Debug, clap::Parser)] @@ -34,10 +39,10 @@ pub async fn handle_command(_data: Data, command: Subcommand) -> Result<(), Gcli println!("Address (SS58): {}", address); } Subcommand::Prompt => { - let pair = prompt_secret_cesium(); + let pair = keys::prompt_secret_cesium(); println!( "Pubkey: {}", - compute_g1v1_public_key_from_ed25519_pair(&pair)? + compute_g1v1_public_key_from_ed25519_pair(&pair) ); let address: AccountId = pair.public().into(); println!("Address: {}", address); @@ -52,13 +57,91 @@ pub fn compute_g1v1_public_key(key_pair: &KeyPair) -> Result<String, GcliError> KeyPair::Sr25519(_) => Err(GcliError::Logic( "key pair is not of type ed25519".to_string(), )), - KeyPair::Ed25519(key_pair) => Ok(compute_g1v1_public_key_from_ed25519_pair(key_pair)?), + KeyPair::Ed25519(key_pair) => Ok(compute_g1v1_public_key_from_ed25519_pair(key_pair)), } } /// Computes G1v1 public key from an ed25519 Pair -pub fn compute_g1v1_public_key_from_ed25519_pair( - ed25519_key_pair: &ed25519::Pair, +pub fn compute_g1v1_public_key_from_ed25519_pair(ed25519_key_pair: &ed25519::Pair) -> String { + compute_g1v1_public_key_from_ed25519_public(&ed25519_key_pair.public()) +} + +/// Computes G1v1 public key from an ed25519 Public +pub fn compute_g1v1_public_key_from_ed25519_public(ed25519_public: &ed25519::Public) -> String { + bs58::encode(ed25519_public).into_string() +} + +/// Computes G1v1 public key from an ed25519 AccountId +pub fn compute_g1v1_public_key_from_ed25519_account_id(ed25519_account_id: &AccountId) -> String { + let ed25519_public: ed25519::Public = ed25519::Public::from(ed25519_account_id.0); + bs58::encode(ed25519_public).into_string() +} + +/// Computes G1v1 public key from an ed25519 SS58 Address +#[allow(unused)] +pub fn compute_g1v1_public_key_from_ed25519_ss58_address( + ed25519_ss58_address: &str, ) -> Result<String, GcliError> { - Ok(bs58::encode(ed25519_key_pair.public()).into_string()) + Ok(compute_g1v1_public_key_from_ed25519_account_id( + &AccountId::from_str(ed25519_ss58_address).map_err(|e| GcliError::Input(e.to_string()))?, + )) +} + +// Unit tests +#[cfg(test)] +mod tests { + use super::*; + + /// Test data: + /// cesium_id = "test_cesium_id" + /// cesium_pwd = "test_cesium_pwd" + /// + /// G1v1 base58 public key: 86pW1doyJPVH3jeDPZNQa1UZFBo5zcdvHERcaeE758W7 + /// + /// ``` + /// subkey inspect --scheme ed25519 + /// URI: + /// Secret Key URI `0x2101d2bc68de9ad149c06293bfe489c8608de576c88927aa5439a81be17aae84` is account: + /// Network ID: substrate + /// Secret seed: 0x2101d2bc68de9ad149c06293bfe489c8608de576c88927aa5439a81be17aae84 + /// Public key (hex): 0x697f6bd16ddebf142384e503fd3f3efc39fe5c7be7c693bd98d982403bb6eb74 + /// Account ID: 0x697f6bd16ddebf142384e503fd3f3efc39fe5c7be7c693bd98d982403bb6eb74 + /// Public key (SS58): 5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4 + /// SS58 Address: 5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4 + /// ``` + #[test] + fn test_compute_g1v1_public_key() { + let expected_base58_public_key = "86pW1doyJPVH3jeDPZNQa1UZFBo5zcdvHERcaeE758W7"; + let ss58_address = "5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4"; + + assert_eq!( + expected_base58_public_key, + compute_g1v1_public_key_from_ed25519_ss58_address(ss58_address).unwrap() + ); + + let account_id = AccountId::from_str(ss58_address).unwrap(); + + assert_eq!( + expected_base58_public_key, + compute_g1v1_public_key_from_ed25519_account_id(&account_id) + ); + + let ed25519_public = ed25519::Public::from(account_id.0); + + assert_eq!( + expected_base58_public_key, + compute_g1v1_public_key_from_ed25519_public(&ed25519_public) + ); + + let cesium_id = "test_cesium_id".to_string(); + let cesium_pwd = "test_cesium_pwd".to_string(); + + let seed = keys::seed_from_cesium(&cesium_id, &cesium_pwd); + let ed25519_pair_from_seed = ed25519::Pair::from_seed(&seed); + + assert_eq!( + expected_base58_public_key, + compute_g1v1_public_key_from_ed25519_pair(&ed25519_pair_from_seed) + ); + } } diff --git a/src/commands/vault.rs b/src/commands/vault.rs index 534091f4aafdf7b3df14e823f8f4166cb8e29817..f046df212e51d0a26483fa03d362744846065d62 100644 --- a/src/commands/vault.rs +++ b/src/commands/vault.rs @@ -38,7 +38,7 @@ pub enum Subcommand { in the substrate uri value." )] Import { - /// Secret key format (substrate, seed, cesium) + /// Secret key format (substrate, seed, g1v1) #[clap(short = 'S', long, required = false, default_value = SecretFormat::Substrate)] secret_format: SecretFormat, }, @@ -219,8 +219,8 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE let vault_data_for_import = prompt_secret_and_compute_vault_data_to_import(secret_format)?; - //Extra check for SecretFormat::Cesium / G1v1Seed - showing the G1v1 cesium public key for confirmation - if secret_format == SecretFormat::Cesium { + //Extra check for SecretFormat::G1v1 (old cesium) - showing the G1v1 cesium public key for confirmation + if secret_format == SecretFormat::G1v1 { println!( "The G1v1 public key for the provided secret is: '{}'", compute_g1v1_public_key(&vault_data_for_import.key_pair)? @@ -545,7 +545,7 @@ fn map_secret_format_to_crypto_scheme(secret_format: SecretFormat) -> CryptoSche SecretFormat::Seed => CryptoScheme::Sr25519, SecretFormat::Substrate => CryptoScheme::Sr25519, SecretFormat::Predefined => CryptoScheme::Sr25519, - SecretFormat::Cesium => CryptoScheme::Ed25519, + SecretFormat::G1v1 => CryptoScheme::Ed25519, } } @@ -701,7 +701,7 @@ fn prompt_secret_and_compute_vault_data_to_import( SecretFormat::Seed => { create_vault_data_to_import(secret_format, prompt_seed_and_compute_keypair) } - SecretFormat::Cesium => { + SecretFormat::G1v1 => { create_vault_data_to_import(secret_format, prompt_secret_cesium_and_compute_keypair) } SecretFormat::Predefined => { diff --git a/src/commands/vault/display.rs b/src/commands/vault/display.rs index f7bab79eb5d136fd84e3260946464061aa984a2a..8dd84c23420c8452c538c769a240ab4a5a344073 100644 --- a/src/commands/vault/display.rs +++ b/src/commands/vault/display.rs @@ -1,10 +1,12 @@ +use crate::commands::cesium; use crate::entities::vault_account; use crate::entities::vault_account::AccountTreeNode; -use crate::keys::{CryptoScheme, SecretFormat}; +use crate::keys::CryptoScheme; use crate::utils::GcliError; use comfy_table::{Cell, Table}; use std::cell::RefCell; use std::rc::Rc; +use std::str; #[deprecated( note = "Should be removed in a future version when db persistence of vault is present for a while" @@ -26,10 +28,15 @@ pub fn compute_vault_accounts_table( ) -> Result<Table, GcliError> { let mut table = Table::new(); table.load_preset(comfy_table::presets::UTF8_BORDERS_ONLY); - table.set_header(vec!["SS58 Address", "Format", "Account/Path", "Name"]); + table.set_header(vec![ + "SS58 Address/G1v1 public key", + "Crypto", + "Path", + "Name", + ]); for account_tree_node in account_tree_nodes { - add_account_tree_node_to_table(&mut table, account_tree_node); + let _ = add_account_tree_node_to_table(&mut table, account_tree_node); } Ok(table) @@ -38,16 +45,25 @@ pub fn compute_vault_accounts_table( fn add_account_tree_node_to_table( table: &mut Table, account_tree_node: &Rc<RefCell<AccountTreeNode>>, -) { - let row = compute_vault_accounts_row(account_tree_node); - table.add_row(row); +) -> Result<(), GcliError> { + let rows = compute_vault_accounts_row(account_tree_node)?; + rows.iter().for_each(|row| { + table.add_row(row.clone()); + }); for child in &account_tree_node.borrow().children { - add_account_tree_node_to_table(table, child); + let _ = add_account_tree_node_to_table(table, child); } + + Ok(()) } -pub fn compute_vault_accounts_row(account_tree_node: &Rc<RefCell<AccountTreeNode>>) -> Vec<Cell> { +/// Computes one or more row of the table for selected account_tree_node +/// +/// For ed25519 keys, will display over 2 rows to also show the base 58 G1v1 public key +pub fn compute_vault_accounts_row( + account_tree_node: &Rc<RefCell<AccountTreeNode>>, +) -> Result<Vec<Vec<Cell>>, GcliError> { let empty_string = "".to_string(); let depth_account_tree_node = vault_account::count_depth_account_tree_node(account_tree_node); @@ -71,33 +87,51 @@ pub fn compute_vault_accounts_row(account_tree_node: &Rc<RefCell<AccountTreeNode account_tree_node.account.address.to_string() }; - let (path, format) = if let Some(path) = account_tree_node.account.path.clone() { + let mut rows: Vec<Vec<Cell>> = vec![]; + + let (path, crypto) = if let Some(path) = account_tree_node.account.path.clone() { (path, empty_string.clone()) } else { - let secret_format = match account_tree_node.account.crypto_scheme.unwrap().into() { - CryptoScheme::Sr25519 => SecretFormat::Substrate, - CryptoScheme::Ed25519 => SecretFormat::Cesium, - }; - let secret_format_str: &str = secret_format.into(); + let crypto_scheme = CryptoScheme::from(account_tree_node.account.crypto_scheme.unwrap()); + + // Adding 2nd row for G1v1 public key + if CryptoScheme::Ed25519 == crypto_scheme { + rows.push(vec![Cell::new(format!( + "â”” G1v1: {}", + cesium::compute_g1v1_public_key_from_ed25519_account_id( + &account_tree_node.account.address.0 + ) + ))]); + } + + let crypto_scheme_str: &str = crypto_scheme.into(); ( format!("<{}>", account_tree_node.account.account_type()), - secret_format_str.to_string(), + crypto_scheme_str.to_string(), ) }; - vec![ - Cell::new(&address), - Cell::new(format), - Cell::new(&path), - Cell::new(&name), - ] + // Adding 1st row + rows.insert( + 0, + vec![ + Cell::new(&address), + Cell::new(crypto), + Cell::new(&path), + Cell::new(&name), + ], + ); + + Ok(rows) } #[cfg(test)] mod tests { mod vault_accounts_table_tests { use crate::commands::vault::display::compute_vault_accounts_table; - use crate::entities::vault_account::tests::account_tree_node_tests::mother_account_tree_node; + use crate::entities::vault_account::tests::account_tree_node_tests::{ + mother_account_tree_node, mother_g1v1_account_tree_node, + }; use indoc::indoc; #[test] @@ -105,10 +139,10 @@ mod tests { let table = compute_vault_accounts_table(&[]).unwrap(); let expected_table = indoc! {r#" - ┌─────────────────────────────────────────────┠- │ SS58 Address Format Account/Path Name │ - ╞â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡ - └─────────────────────────────────────────────┘"# + ┌─────────────────────────────────────────────────────┠+ │ SS58 Address/G1v1 public key Crypto Path Name │ + ╞â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡ + └─────────────────────────────────────────────────────┘"# }; assert_eq!(table.to_string(), expected_table); @@ -117,19 +151,23 @@ mod tests { #[test] fn test_compute_vault_accounts_table() { let account_tree_node = mother_account_tree_node(); + let g1v1_account_tree_node = mother_g1v1_account_tree_node(); - let table = compute_vault_accounts_table(&[account_tree_node]).unwrap(); + let table = + compute_vault_accounts_table(&[account_tree_node, g1v1_account_tree_node]).unwrap(); let expected_table = indoc! {r#" - ┌──────────────────────────────────────────────────────────────────────────────────────────────────┠- │ SS58 Address Format Account/Path Name │ - ╞â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡ - │ 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV substrate <Base> Mother │ - │ ├─5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH //0 Child 1 │ - │ │ ├─5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │ - │ ├─5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o //1 <Mother//1> │ - │ │ ├─5CvdJuB9HLXSi5FS9LW57cyHF13iCv5HDimo2C45KxnxriCT //1 <Mother//1//1> │ - └──────────────────────────────────────────────────────────────────────────────────────────────────┘"# + ┌──────────────────────────────────────────────────────────────────────────────────────────┠+ │ SS58 Address/G1v1 public key Crypto Path Name │ + ╞â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡ + │ 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV sr25519 <Base> Mother │ + │ ├─5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH //0 Child 1 │ + │ │ ├─5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │ + │ ├─5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o //1 <Mother//1> │ + │ │ ├─5CvdJuB9HLXSi5FS9LW57cyHF13iCv5HDimo2C45KxnxriCT //1 <Mother//1//1> │ + │ 5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4 ed25519 <Base> MotherG1v1 │ + │ â”” G1v1: 86pW1doyJPVH3jeDPZNQa1UZFBo5zcdvHERcaeE758W7 │ + └──────────────────────────────────────────────────────────────────────────────────────────┘"# }; assert_eq!(table.to_string(), expected_table); @@ -143,12 +181,12 @@ mod tests { let table = compute_vault_accounts_table(&[child1]).unwrap(); let expected_table = indoc! {r#" - ┌─────────────────────────────────────────────────────────────────────────────────────────────┠- │ SS58 Address Format Account/Path Name │ - ╞â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡ - │ ├─5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH //0 Child 1 │ - │ │ ├─5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │ - └─────────────────────────────────────────────────────────────────────────────────────────────┘"# + ┌─────────────────────────────────────────────────────────────────────────────────────┠+ │ SS58 Address/G1v1 public key Crypto Path Name │ + ╞â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡ + │ ├─5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH //0 Child 1 │ + │ │ ├─5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │ + └─────────────────────────────────────────────────────────────────────────────────────┘"# }; assert_eq!(table.to_string(), expected_table); diff --git a/src/entities/vault_account.rs b/src/entities/vault_account.rs index 1a31f4af9fe55e5305f9d220074741a8edb20e48..760582da15ef7ffc4446773c50636ff99f00b52f 100644 --- a/src/entities/vault_account.rs +++ b/src/entities/vault_account.rs @@ -1,4 +1,5 @@ -use crate::commands::vault; +use crate::commands::{cesium, vault}; +use crate::runtime_config::AccountId; use crate::utils::GcliError; use anyhow::anyhow; use sea_orm::prelude::async_trait::async_trait; @@ -20,7 +21,6 @@ use std::future::Future; use std::pin::Pin; use std::rc::Rc; use std::str::FromStr; -use subxt::utils::AccountId32; #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] #[sea_orm(table_name = "vault_account")] @@ -63,14 +63,33 @@ impl Model { impl Display for Model { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.is_base_account() { - write!( - f, - "{}[address:{}, name:{:?}, crypto_scheme:{:?}]", - self.account_type(), - self.address, - self.name, - self.crypto_scheme - ) + match self.crypto_scheme { + None => { + unreachable!() + } + Some(DbCryptoScheme::Ed25519) => { + // Also showing G1v1 public key for Ed25519 (base) accounts + write!( + f, + "{}[address:{}, g1v1_pub_key:{}, name:{:?}, crypto_scheme:{:?}]", + self.account_type(), + self.address, + cesium::compute_g1v1_public_key_from_ed25519_account_id(&self.address.0), + self.name, + self.crypto_scheme + ) + } + Some(DbCryptoScheme::Sr25519) => { + write!( + f, + "{}[address:{}, name:{:?}, crypto_scheme:{:?}]", + self.account_type(), + self.address, + self.name, + self.crypto_scheme + ) + } + } } else { fn get_parent_name(parent: &Option<DbAccountId>) -> String { if let Some(parent) = parent { @@ -95,15 +114,15 @@ impl Display for Model { /// Necessary to create a wrapper over AccountId32 to implement sea-orm traits #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, FromJsonQueryResult)] -pub struct DbAccountId(pub AccountId32); +pub struct DbAccountId(pub AccountId); impl FromStr for DbAccountId { type Err = GcliError; fn from_str(s: &str) -> Result<Self, Self::Err> { - AccountId32::from_str(s) + AccountId::from_str(s) .map(DbAccountId) - .map_err(|_| GcliError::Input("Invalid AccountId32 format".to_string())) + .map_err(|_| GcliError::Input("Invalid AccountId format".to_string())) } } @@ -113,13 +132,13 @@ impl Display for DbAccountId { } } -impl From<AccountId32> for DbAccountId { - fn from(account_id32: AccountId32) -> Self { - DbAccountId(account_id32) +impl From<AccountId> for DbAccountId { + fn from(account_id: AccountId) -> Self { + DbAccountId(account_id) } } -impl From<DbAccountId> for AccountId32 { +impl From<DbAccountId> for AccountId { fn from(db_account_id: DbAccountId) -> Self { db_account_id.0 } @@ -127,7 +146,7 @@ impl From<DbAccountId> for AccountId32 { impl From<String> for DbAccountId { fn from(s: String) -> Self { - DbAccountId(AccountId32::from_str(&s).expect("Invalid AccountId32 format")) + DbAccountId(AccountId::from_str(&s).expect("Invalid AccountId format")) } } @@ -888,6 +907,7 @@ pub mod tests { pub mod account_tree_node_tests { use super::*; use crate::commands::vault; + use crate::keys; use crate::keys::SUBSTRATE_MNEMONIC; pub fn mother_account_tree_node() -> Rc<RefCell<AccountTreeNode>> { @@ -980,6 +1000,34 @@ pub mod tests { mother } + pub fn mother_g1v1_account_tree_node() -> Rc<RefCell<AccountTreeNode>> { + let mother_address = + DbAccountId::from_str("5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4").unwrap(); + + let cesium_id = "test_cesium_id".to_string(); + let cesium_pwd = "test_cesium_pwd".to_string(); + + let seed = keys::seed_from_cesium(&cesium_id, &cesium_pwd); + let secret_suri = format!("0x{}", hex::encode(seed)); + + let mother_g1v1 = Rc::new(RefCell::new(AccountTreeNode { + account: Model { + address: mother_address.clone(), + name: Some("MotherG1v1".to_string()), + path: None, + crypto_scheme: Some(DbCryptoScheme::Ed25519), + encrypted_suri: Some( + vault::encrypt(secret_suri.as_bytes(), "".to_string()).unwrap(), + ), + parent: None, + }, + children: vec![], + parent: None, + })); + + mother_g1v1 + } + #[test] fn test_count_depth_account_tree_node() { let mother = mother_account_tree_node(); diff --git a/src/keys.rs b/src/keys.rs index ad03260a9a5b2a16be9d14873b2eca323fef3843..515814ca971cc5c0de94ab2f1039b9cc866d03ec 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -16,8 +16,8 @@ pub enum SecretFormat { Substrate, /// Predefined (Alice, Bob, ...) Predefined, - /// Cesium (scrypt + nacl) - Cesium, + /// G1v1 id+secret using (scrypt + ed25519) + G1v1, } impl FromStr for SecretFormat { @@ -28,7 +28,9 @@ impl FromStr for SecretFormat { "seed" => Ok(SecretFormat::Seed), "substrate" => Ok(SecretFormat::Substrate), "predefined" => Ok(SecretFormat::Predefined), - "cesium" => Ok(SecretFormat::Cesium), + "g1v1" => Ok(SecretFormat::G1v1), + //Still support "cesium" input as well for backward compatibility + "cesium" => Ok(SecretFormat::G1v1), _ => Err(std::io::Error::from(std::io::ErrorKind::InvalidInput)), } } @@ -39,7 +41,7 @@ impl From<SecretFormat> for &'static str { SecretFormat::Seed => "seed", SecretFormat::Substrate => "substrate", SecretFormat::Predefined => "predefined", - SecretFormat::Cesium => "cesium", + SecretFormat::G1v1 => "g1v1", } } } @@ -60,18 +62,38 @@ pub enum CryptoScheme { Sr25519, } +impl FromStr for CryptoScheme { + type Err = std::io::Error; + + fn from_str(s: &str) -> std::io::Result<Self> { + match s { + "ed25519" => Ok(CryptoScheme::Ed25519), + "sr25519" => Ok(CryptoScheme::Sr25519), + _ => Err(std::io::Error::from(std::io::ErrorKind::InvalidInput)), + } + } +} +impl From<CryptoScheme> for &'static str { + fn from(val: CryptoScheme) -> &'static str { + match val { + CryptoScheme::Ed25519 => "ed25519", + CryptoScheme::Sr25519 => "sr25519", + } + } +} +impl From<CryptoScheme> for OsStr { + fn from(val: CryptoScheme) -> OsStr { + OsStr::from(Into::<&str>::into(val)) + } +} + /// wrapper type for keys + signature //FIXME check if it's ok to keep large enum variant // Sr25519 second-largest variant contains at least 256 bytes // Ed25519 largest variant contains at least 480 bytes //FIXME -// Replace by CryptoScheme from sc_cli?? or CryptoType from sp-core ? -// sc_cli::arg_enums::CryptoScheme (enum) -// CryptoScheme::Ed25519 -// CryptoScheme::Sr25519 -// CryptoScheme::Ecdsa +// Replace by CryptoType from sp-core ? // sp_core::crypto::CryptoType (trait) -// /home/valpha/.cargo/git/checkouts/duniter-polkadot-sdk-0889f590ced4a269/bcc60f3/substrate/primitives/core/src/crypto.rs:1012 #[allow(clippy::large_enum_variant)] pub enum KeyPair { Sr25519(sr25519::Pair), @@ -132,8 +154,8 @@ pub fn pair_from_secret( SecretFormat::Substrate => pair_from_sr25519_str(secret), SecretFormat::Predefined => pair_from_sr25519_str(secret), /* if predefined, secret arg is replaced in config */ SecretFormat::Seed => pair_from_sr25519_seed(secret), - SecretFormat::Cesium => Err(GcliError::Logic( - "cesium format incompatible with single secret".to_string(), + SecretFormat::G1v1 => Err(GcliError::Logic( + "G1v1 format incompatible with single secret".to_string(), )), } } @@ -183,7 +205,7 @@ pub fn pair_from_predefined(deriv: &str) -> Result<sr25519::Pair, GcliError> { } /// get seed from Cesium id/pwd -fn seed_from_cesium(id: &str, pwd: &str) -> [u8; 32] { +pub fn seed_from_cesium(id: &str, pwd: &str) -> [u8; 32] { let params = scrypt::Params::new(12u8, 16u32, 1u32, 32).unwrap(); let mut seed = [0u8; 32]; scrypt::scrypt(pwd.as_bytes(), id.as_bytes(), ¶ms, &mut seed).unwrap(); @@ -262,7 +284,7 @@ pub fn prompt_predefined_and_compute_keypair() -> (String, sr25519::Pair) { pub fn prompt_secret(secret_format: SecretFormat) -> KeyPair { match secret_format { SecretFormat::Substrate => prompt_secret_substrate().into(), - SecretFormat::Cesium => prompt_secret_cesium().into(), + SecretFormat::G1v1 => prompt_secret_cesium().into(), SecretFormat::Seed => prompt_seed().into(), SecretFormat::Predefined => prompt_predefined().into(), } @@ -388,7 +410,7 @@ mod tests { /// formats public key as hex fn format_public_key<P: sp_core::Pair>(public_key: PublicFor<P>) -> String { - format!("0x{}", hex::encode((&public_key.as_ref()))) + format!("0x{}", hex::encode(&public_key.as_ref())) } /// formats public key as accountId as hex diff --git a/src/main.rs b/src/main.rs index 0435feae6b13bf10a4d8173deb3b7918a9e61dda..116552d6c3228bf19d8f5c0451555925b856298d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,7 +50,7 @@ pub struct Args { /// (eventually followed by derivation path) #[clap(short, long)] secret: Option<String>, - /// Secret key format (seed, substrate, cesium) + /// Secret key format (seed, substrate, g1v1) #[clap(short = 'S', long)] secret_format: Option<SecretFormat>, /// SS58 Address