pub mod algorithms;
pub mod exceptions;
#[cfg(test)]
pub(crate) mod test_cases;
pub mod utils;
pub use self::algorithms::Ed25519;
pub use self::algorithms::Secp256k1;
use crate::constants::CryptoAlgorithm;
use crate::core::addresscodec::utils::SEED_LENGTH;
use crate::core::addresscodec::*;
use crate::core::keypairs::exceptions::XRPLKeypairsException;
use crate::core::keypairs::utils::*;
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
use rand::Rng;
use rand::SeedableRng;
use super::exceptions::XRPLCoreResult;
const fn _get_algorithm_sig_length(algo: CryptoAlgorithm) -> usize {
match algo {
CryptoAlgorithm::ED25519 => ED25519_SIGNATURE_LENGTH,
CryptoAlgorithm::SECP256K1 => SECP256K1_SIGNATURE_LENGTH,
}
}
fn _get_algorithm_from_key(key: &str) -> CryptoAlgorithm {
match &key[..2] {
ED25519_PREFIX => CryptoAlgorithm::ED25519,
_ => CryptoAlgorithm::SECP256K1,
}
}
fn _get_algorithm_engine(algo: CryptoAlgorithm) -> Box<dyn CryptoImplementation> {
match algo {
CryptoAlgorithm::ED25519 => Box::new(Ed25519),
CryptoAlgorithm::SECP256K1 => Box::new(Secp256k1),
}
}
fn _get_algorithm_engine_from_key(key: &str) -> Box<dyn CryptoImplementation> {
match &key[..2] {
ED25519_PREFIX => _get_algorithm_engine(CryptoAlgorithm::ED25519),
_ => _get_algorithm_engine(CryptoAlgorithm::SECP256K1),
}
}
pub fn generate_seed(
entropy: Option<[u8; SEED_LENGTH]>,
algorithm: Option<CryptoAlgorithm>,
) -> XRPLCoreResult<String> {
let mut random_bytes: [u8; SEED_LENGTH] = [0u8; SEED_LENGTH];
let algo: CryptoAlgorithm = if let Some(value) = algorithm {
value
} else {
CryptoAlgorithm::ED25519
};
if let Some(value) = entropy {
random_bytes = value;
} else {
let mut rng = rand_hc::Hc128Rng::from_entropy();
rng.fill(&mut random_bytes);
}
encode_seed(random_bytes, algo)
}
pub fn derive_keypair(seed: &str, validator: bool) -> XRPLCoreResult<(String, String)> {
let (decoded_seed, algorithm) = decode_seed(seed)?;
let module = _get_algorithm_engine(algorithm);
let (public, private) = module.derive_keypair(&decoded_seed, validator)?;
let signature = sign(SIGNATURE_VERIFICATION_MESSAGE, &private)?;
if module.is_valid_message(SIGNATURE_VERIFICATION_MESSAGE, &signature, &public) {
Ok((public, private))
} else {
Err(XRPLKeypairsException::InvalidSignature.into())
}
}
pub fn derive_classic_address(public_key: &str) -> XRPLCoreResult<String> {
let account_id = get_account_id(&hex::decode(public_key)?);
encode_classic_address(&account_id)
}
pub fn sign(message: &[u8], private_key: &str) -> XRPLCoreResult<String> {
let module = _get_algorithm_engine_from_key(private_key);
Ok(hex::encode_upper(module.sign(message, private_key)?))
}
pub fn is_valid_message(message: &[u8], signature: &str, public_key: &str) -> bool {
let module = _get_algorithm_engine_from_key(public_key);
module.is_valid_message(message, signature, public_key)
}
pub trait CryptoImplementation {
fn derive_keypair(
&self,
decoded_seed: &[u8],
is_validator: bool,
) -> XRPLCoreResult<(String, String)>;
fn sign(&self, message: &[u8], private_key: &str) -> XRPLCoreResult<Vec<u8>>;
fn is_valid_message(&self, message: &[u8], signature: &str, public_key: &str) -> bool;
}
#[cfg(test)]
mod test {
use super::*;
use crate::alloc::string::ToString;
use crate::constants::CryptoAlgorithm;
use crate::core::keypairs::test_cases::*;
#[test]
fn test_generate_seed() {
assert!(generate_seed(None, None).is_ok());
assert!(generate_seed(Some(TEST_BYTES), None).is_ok());
assert_eq!(
generate_seed(Some(TEST_BYTES), Some(CryptoAlgorithm::ED25519)),
Ok(SEED_ED25519.to_string()),
);
assert_eq!(
generate_seed(Some(TEST_BYTES), Some(CryptoAlgorithm::SECP256K1)),
Ok(SEED_SECP256K1.to_string()),
);
}
#[test]
fn test_derive_keypair() {
let (public_ed25519, private_ed25519) = derive_keypair(SEED_ED25519, false).unwrap();
let (public_secp256k1, private_secp256k1) = derive_keypair(SEED_SECP256K1, false).unwrap();
assert_eq!(PRIVATE_ED25519, private_ed25519);
assert_eq!(PUBLIC_ED25519, public_ed25519);
assert_eq!(PRIVATE_SECP256K1, private_secp256k1);
assert_eq!(PUBLIC_SECP256K1, public_secp256k1);
}
#[test]
fn test_derive_classic_address() {
assert_eq!(
derive_classic_address(PUBLIC_ED25519),
Ok(CLASSIC_ADDRESS_ED25519.to_string()),
);
assert_eq!(
derive_classic_address(PUBLIC_SECP256K1),
Ok(CLASSIC_ADDRESS_SECP256K1.to_string()),
);
}
#[test]
fn test_sign() {
assert_eq!(
sign(TEST_MESSAGE.as_bytes(), PRIVATE_ED25519),
Ok(hex::encode_upper(SIGNATURE_ED25519)),
);
assert_eq!(
sign(TEST_MESSAGE.as_bytes(), PRIVATE_SECP256K1),
Ok(hex::encode_upper(SIGNATURE_SECP256K1)),
);
}
#[test]
fn test_is_valid_message() {
let message: &[u8] = TEST_MESSAGE.as_bytes();
let sig_ed25519: &str = &hex::encode_upper(SIGNATURE_ED25519);
let sig_secp256k1: &str = &hex::encode_upper(SIGNATURE_SECP256K1);
assert!(is_valid_message(message, sig_ed25519, PUBLIC_ED25519));
assert!(is_valid_message(message, sig_secp256k1, PUBLIC_SECP256K1));
}
}