From 003926ddfa21137c5f58f4d7d03c90b13a87c8a5 Mon Sep 17 00:00:00 2001 From: librelois <elois@ifee.fr> Date: Sun, 1 Mar 2020 23:58:44 +0100 Subject: [PATCH] [fix] base58: handle leading zero --- src/bases/b58.rs | 72 +++++++++++++++++++++++++++++++++++++-------- src/keys/ed25519.rs | 66 +++++++++++------------------------------ src/keys/mod.rs | 23 +++++++-------- src/seeds.rs | 2 +- 4 files changed, 87 insertions(+), 76 deletions(-) diff --git a/src/bases/b58.rs b/src/bases/b58.rs index 52ba871..8dec3ab 100644 --- a/src/bases/b58.rs +++ b/src/bases/b58.rs @@ -26,25 +26,23 @@ pub trait ToBase58 { /// Create an array of 32 bytes from a Base58 string. pub fn str_base58_to_32bytes(base58_data: &str) -> Result<([u8; 32], usize), BaseConvertionError> { let mut source = base58_data; + let mut count_leading_1 = 0; while !source.is_empty() && &source[0..1] == "1" { source = &source[1..]; + count_leading_1 += 1; } match bs58::decode(source).into_vec() { Ok(result) => { - let len = result.len(); - if len <= 32 { - let mut u8_array = [0; 32]; + let mut len = result.len(); + if len > 32 { + len = 32; + } + let mut u8_array = [0; 32]; - u8_array[..len].clone_from_slice(&result[..len]); + u8_array[(32 - len)..].clone_from_slice(&result[..len]); - Ok((u8_array, len)) - } else { - Err(BaseConvertionError::InvalidLength { - expected: 32, - found: len, - }) - } + Ok((u8_array, count_leading_1)) } Err(bs58::decode::Error::InvalidCharacter { character, index }) => { Err(BaseConvertionError::InvalidCharacter { @@ -60,8 +58,56 @@ pub fn str_base58_to_32bytes(base58_data: &str) -> Result<([u8; 32], usize), Bas } /// Create a Base58 string from a slice of bytes. -pub fn bytes_to_str_base58(bytes: &[u8]) -> String { - bs58::encode(bytes).into_string() +pub fn bytes_to_str_base58(bytes: &[u8], mut count_leading_1: usize) -> String { + let mut str_base58 = String::new(); + let bytes = &bytes[count_leading_1..]; + + let bytes = if count_leading_1 == 0 && !bytes.is_empty() && bytes[0] == 0 { + &bytes[1..] + } else { + while count_leading_1 > 0 { + count_leading_1 -= 1; + str_base58.push('1'); + } + &bytes[count_leading_1..] + }; + + str_base58.push_str(&bs58::encode(bytes).into_string()); + + str_base58 +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_base_58_str_with_leading_1() -> Result<(), BaseConvertionError> { + let base58str = "1V27SH9TiVEDs8TWFPydpRKxhvZari7wjGwQnPxMnkr"; + + let (bytes, count_leading_1) = str_base58_to_32bytes(base58str)?; + + println!("{:?}", bytes); + + assert_eq!(base58str, &bytes_to_str_base58(&bytes[..], count_leading_1),); + + Ok(()) + } + + #[test] + fn test_base_58_str_with_43_char() -> Result<(), BaseConvertionError> { + let base58str = "2nV7Dv4nhTJ9dZUvRJpL34vFP9b2BkDjKWv9iBW2JaR"; + + let (bytes, count_leading_1) = str_base58_to_32bytes(base58str)?; + + println!("{}", count_leading_1); + println!("{:?}", bytes); + + assert_eq!(base58str, &bytes_to_str_base58(&bytes[..], count_leading_1),); + + Ok(()) + } } /*/// Create an array of 64bytes from a Base58 string. diff --git a/src/keys/ed25519.rs b/src/keys/ed25519.rs index 3074ea9..c8ee4a3 100644 --- a/src/keys/ed25519.rs +++ b/src/keys/ed25519.rs @@ -159,21 +159,21 @@ impl Eq for Signature {} #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct PublicKey { datas: [u8; 32], - len: usize, + count_leading_zero: usize, } impl Default for PublicKey { fn default() -> Self { PublicKey { datas: [0u8; 32], - len: 0, + count_leading_zero: 32, } } } impl AsRef<[u8]> for PublicKey { fn as_ref(&self) -> &[u8] { - &self.datas[..self.len] + &self.datas[..] } } @@ -187,11 +187,11 @@ impl TryFrom<&[u8]> for PublicKey { found: bytes.len(), }) } else { - let mut u8_array = [0; 32]; - u8_array[..bytes.len()].copy_from_slice(&bytes); + let mut u8_array = [0; PUBKEY_SIZE_IN_BYTES]; + u8_array[(PUBKEY_SIZE_IN_BYTES - bytes.len())..].copy_from_slice(&bytes); Ok(PublicKey { datas: u8_array, - len: bytes.len(), + count_leading_zero: 0, }) } } @@ -199,13 +199,17 @@ impl TryFrom<&[u8]> for PublicKey { impl ToBase58 for PublicKey { fn to_base58(&self) -> String { - bytes_to_str_base58(self.as_ref()) + bytes_to_str_base58(self.as_ref(), self.count_leading_zero) } } impl Display for PublicKey { fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { - write!(f, "{}", bytes_to_str_base58(self.as_ref())) + write!( + f, + "{}", + bytes_to_str_base58(self.as_ref(), self.count_leading_zero) + ) } } @@ -221,8 +225,11 @@ impl super::PublicKey for PublicKey { #[inline] fn from_base58(base58_data: &str) -> Result<Self, BaseConvertionError> { - let (datas, len) = b58::str_base58_to_32bytes(base58_data)?; - Ok(PublicKey { datas, len }) + let (datas, count_leading_zero) = b58::str_base58_to_32bytes(base58_data)?; + Ok(PublicKey { + datas, + count_leading_zero, + }) } fn to_bytes_vector(&self) -> Vec<u8> { @@ -447,13 +454,6 @@ mod tests { assert!(!seed.eq(&other_seed)); // Test seed parsing - assert_eq!( - Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLVgth",).unwrap_err(), - BaseConvertionError::InvalidLength { - found: 35, - expected: 32 - } - ); /*assert_eq!( Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd",).unwrap_err(), BaseConvertionError::InvalidLength { @@ -468,22 +468,6 @@ mod tests { offset: 42 } ); - assert_eq!( - Seed32::from_base58( - "\ - DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ - DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ - DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ - DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ - DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ - " - ) - .unwrap_err(), - BaseConvertionError::InvalidLength { - expected: 32, - found: 161 - } - ); } #[test] @@ -527,22 +511,6 @@ mod tests { offset: 42 } ); - assert_eq!( - super::PublicKey::from_base58( - "\ - DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ - DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ - DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ - DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ - DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ - " - ) - .unwrap_err(), - BaseConvertionError::InvalidLength { - expected: 32, - found: 161 - } - ); } #[test] diff --git a/src/keys/mod.rs b/src/keys/mod.rs index 6acfdcd..53ece26 100644 --- a/src/keys/mod.rs +++ b/src/keys/mod.rs @@ -507,10 +507,11 @@ mod tests { #[test] fn pubkey() { - let pubkey_default = PubKey::default(); - let pubkey_bytes = []; - let pubkey = PubKey::Ed25519(unwrap!(ed25519::PublicKey::try_from(&pubkey_bytes[..]))); - assert_eq!(pubkey_default, pubkey); + let ed25519_pubkey_default = ed25519::PublicKey::default(); + let pubkey_default = PubKey::Ed25519(ed25519_pubkey_default); + let pubkey = PubKey::Ed25519(unwrap!(ed25519::PublicKey::try_from( + ed25519_pubkey_default.as_ref() + ))); let pubkey_str_b58 = "11111111111111111111111111111111".to_owned(); assert_eq!( @@ -519,14 +520,14 @@ mod tests { ); assert_eq!(pubkey.size_in_bytes(), ed25519::PUBKEY_SIZE_IN_BYTES + 3); - assert_eq!("", &format!("{}", pubkey)); + assert_eq!("1111111111111111111111111111111", &format!("{}", pubkey)); assert_eq!(KeysAlgo::Ed25519, pubkey.algo()); assert_eq!(KeysAlgo::Schnorr, PubKey::Schnorr().algo()); - assert_eq!(pubkey_bytes.to_vec(), pubkey.to_bytes_vector()); + assert_eq!([0u8; 32].to_vec(), pubkey.to_bytes_vector()); - assert_eq!("", &pubkey.to_base58()); + assert_eq!("1111111111111111111111111111111", &pubkey.to_base58()); assert_eq!( Err(SigError::InvalidSig), @@ -548,7 +549,7 @@ mod tests { 0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; - let seed_str_b58 = "11111111111111111111111111111111".to_owned(); + let seed_str_b58 = "1111111111111111111111111111111".to_owned(); let seed = Seed32::new(seed_bytes); assert_eq!(seed_default, seed); @@ -557,7 +558,7 @@ mod tests { Seed32::from_base58(&seed_str_b58).expect("Fail to parse seed !") ); - assert_eq!(seed_str_b58, format!("{}", seed)); + assert_eq!("1111111111111111111111111111111", format!("{}", seed)); assert_eq!(seed_str_b58, seed.to_base58()); } @@ -725,9 +726,5 @@ mod tests { 23, 24, 25, 26, 27, 28, 29, 30, 31, 31 ]), ); - assert_eq!( - Ok(PubKey::Ed25519(ed25519::PublicKey::default())), - PubKey::from_bytes(&[]), - ); } } diff --git a/src/seeds.rs b/src/seeds.rs index c94b9ca..c5f5563 100644 --- a/src/seeds.rs +++ b/src/seeds.rs @@ -38,7 +38,7 @@ impl AsRef<[u8]> for Seed32 { impl ToBase58 for Seed32 { fn to_base58(&self) -> String { - bytes_to_str_base58(&self.0[..]) + bytes_to_str_base58(&self.0[..], 0) } } -- GitLab