diff --git a/tezos-core/src/error.rs b/tezos-core/src/error.rs index ee5180b..89a1c10 100644 --- a/tezos-core/src/error.rs +++ b/tezos-core/src/error.rs @@ -40,6 +40,12 @@ pub enum Error { TryFromBigUInt { source: num_bigint::TryFromBigIntError, }, + Blake2InvalidOutputSize { + source: blake2::digest::InvalidOutputSize, + }, + Blake2InvalidBufferSize { + source: blake2::digest::InvalidBufferSize, + }, InvalidSecretKeyBytes, InvalidPublicKeyBytes, InvalidSignatureBytes, diff --git a/tezos-core/src/internal/crypto.rs b/tezos-core/src/internal/crypto.rs index fa7f82d..46cacbe 100644 --- a/tezos-core/src/internal/crypto.rs +++ b/tezos-core/src/internal/crypto.rs @@ -21,16 +21,7 @@ impl Crypto { } pub fn blake2b(&self, message: &[u8], size: usize) -> Result> { - use blake2::{ - digest::{Update, VariableOutput}, - Blake2bVar, - }; - let mut hasher = Blake2bVar::new(size).unwrap(); - hasher.update(message); - let mut buf = Vec::::new(); - buf.resize(size, 0); - hasher.finalize_variable(&mut buf).unwrap(); - Ok(buf) + blake2b(message, size) } pub fn sign_ed25519(&self, message: &[u8], secret: &[u8]) -> Result> { @@ -85,3 +76,16 @@ impl Crypto { .verify(message, signature, public_key) } } + +pub fn blake2b(message: &[u8], size: usize) -> Result> { + use blake2::{ + digest::{Update, VariableOutput}, + Blake2bVar, + }; + let mut hasher = Blake2bVar::new(size)?; + hasher.update(message); + let mut buf = Vec::::new(); + buf.resize(size, 0); + hasher.finalize_variable(&mut buf)?; + Ok(buf) +} diff --git a/tezos-core/src/types/encoded/key.rs b/tezos-core/src/types/encoded/key.rs index 2721869..d3c016a 100644 --- a/tezos-core/src/types/encoded/key.rs +++ b/tezos-core/src/types/encoded/key.rs @@ -2,10 +2,14 @@ use serde::{Deserialize, Serialize}; use crate::{ - internal::coder::{EncodedBytesCoder, PublicKeyBytesCoder}, + internal::{ + coder::{EncodedBytesCoder, PublicKeyBytesCoder}, + crypto::blake2b, + }, types::encoded::{ - Ed25519PublicKey, Ed25519SecretKey, Encoded, MetaEncoded, P256PublicKey, P256SecretKey, - Secp256K1PublicKey, Secp256K1SecretKey, + Ed25519PublicKey, Ed25519PublicKeyHash, Ed25519SecretKey, Encoded, ImplicitAddress, + MetaEncoded, P256PublicKey, P256PublicKeyHash, P256SecretKey, Secp256K1PublicKey, + Secp256K1PublicKeyHash, Secp256K1SecretKey, }, Error, Result, }; @@ -280,6 +284,31 @@ impl PublicKey { || Secp256K1PublicKey::is_valid_bytes(value) || P256PublicKey::is_valid_bytes(value) } + + /// Base58 encoded address + pub fn bs58_address(&self) -> Result { + self.address().map(|address| address.into_string()) + } + + fn address(&self) -> Result { + fn address_of(v: &[u8]) -> Result { + blake2b(v, 20).map(|hash| T::from_bytes(hash.as_slice()))? + } + + let address = match self { + Self::Ed25519(value) => { + ImplicitAddress::from(address_of::(&value.to_bytes()?)?) + } + Self::Secp256K1(value) => { + ImplicitAddress::from(address_of::(&value.to_bytes()?)?) + } + Self::P256(value) => { + ImplicitAddress::from(address_of::(&value.to_bytes()?)?) + } + }; + + Ok(address) + } } impl Encoded for PublicKey { @@ -418,6 +447,15 @@ mod test { Err(Error::InvalidConversion) } + #[test] + fn test_edpk_to_tz1() { + let key: PublicKey = "edpkuF5y5V7NNH5xKMCKHHqVDzq6YuUXiPT3FFjA9CGnht6xCgziTe" + .try_into() + .unwrap(); + let address = key.bs58_address().unwrap(); + assert_eq!(address, "tz1VZFmv9dJj7QFs8nv5JTjJiYJxVQXqmDMv".to_string()) + } + #[test] fn test_edpk_secret_key() -> Result<()> { let key: SecretKey = "edskRhKTQkgxb7CNTr31rzy3xdkyKaYX9hySAnZYJTPmUzPB7WU4NL7C8pmtQDgRqQ4jDw4Ugh6Y1UW5nvo7UYrRbyhVYK1YuR".try_into()?; @@ -471,6 +509,15 @@ mod test { Err(Error::InvalidConversion) } + #[test] + fn test_sppk_to_tz2() { + let key: PublicKey = "sppkDN74FpFyXiHUe7MZS7rwDzzwb2esc21355LEcSExN67KdNnAfqA" + .try_into() + .unwrap(); + let address = key.bs58_address().unwrap(); + assert_eq!(address, "tz2WHHyhmspQDmKzAZmDmUyqkhcS3BA5EiuU".to_string()) + } + #[test] fn test_secp_256_k1_secret_key() -> Result<()> { let key: SecretKey = "spsk2WUw2TFXQq2CsrNhB7EfFzdhMyNvGoYgD4uGQ6e17MgoRDv1co".try_into()?; @@ -524,6 +571,15 @@ mod test { Err(Error::InvalidConversion) } + #[test] + fn test_p2pk_to_tz2() { + let key: PublicKey = "p2pkDkL6thzTwyPjpmMotSqeKy1MAftLrseqTALwBhHwUtXRmFV983f" + .try_into() + .unwrap(); + let address = key.bs58_address().unwrap(); + assert_eq!(address, "tz3c6Z7Vaz3jDfpKLof6PSJsHsUDYjBbQpbn".to_string()) + } + #[test] fn test_p256_secret_key() -> Result<()> { let key: SecretKey = "p2sk2Xoduh8dx6B3smV81NMV25cYpZJj7yYWMRARedzyJae8SB9auw".try_into()?;