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, Pair}; use std::str::FromStr; /// define cesium subcommands #[derive(Clone, Default, Debug, clap::Parser)] pub enum Subcommand { // Nothing #[default] #[clap(hide = true)] Nothing, /// Analyse a base58 pubkey and gives it in all its form Pubkey { pubkey: String }, /// Prompt for cesium input Prompt, } /// handle blockchain commands pub async fn handle_command(_data: Data, command: Subcommand) -> Result<(), GcliError> { match command { Subcommand::Nothing => {} Subcommand::Pubkey { pubkey } => { let raw_pubkey = bs58::decode(pubkey).into_vec().unwrap(); let raw_pubkey: [u8; 32] = if raw_pubkey.len() > 32 { return Err(GcliError::Input("invalid pubkey size".to_string())); } else { [vec![0; 32 - raw_pubkey.len()], raw_pubkey] .concat() .try_into() .unwrap() }; println!("Pubkey (hex): 0x{}", hex::encode(raw_pubkey)); let address: AccountId = sp_core::ed25519::Public::from_raw(raw_pubkey).into(); println!("Address (SS58): {}", address); } Subcommand::Prompt => { let pair = keys::prompt_secret_cesium(); println!( "Pubkey: {}", compute_g1v1_public_key_from_ed25519_pair(&pair) ); let address: AccountId = pair.public().into(); println!("Address: {}", address); } } Ok(()) } /// Computes G1v1 public key from a KeyPair of type sp_core::ed25519::Pair - fails otherwise pub fn compute_g1v1_public_key(key_pair: &KeyPair) -> Result<String, GcliError> { match key_pair { 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)), } } /// Computes G1v1 public key from an 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(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) ); } }