diff --git a/src/bases/b58.rs b/src/bases/b58.rs index 94980af9e607c1a72ac4b3b9dad6d71dc580e86c..0b2ce255f51fe87ed6dd9b9907fbaac66b93d479 100644 --- a/src/bases/b58.rs +++ b/src/bases/b58.rs @@ -24,7 +24,7 @@ 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> { +pub fn str_base58_to_32bytes(base58_data: &str) -> Result<([u8; 32], u8), BaseConvertionError> { let mut source = base58_data; let mut count_leading_1 = 0; while !source.is_empty() && &source[0..1] == "1" { @@ -58,7 +58,7 @@ 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], count_leading_1: usize) -> String { +pub fn bytes_to_str_base58(bytes: &[u8], count_leading_1: u8) -> String { let mut str_base58 = String::new(); let mut remaining_leading_1 = count_leading_1; while remaining_leading_1 > 0 { @@ -72,7 +72,7 @@ pub fn bytes_to_str_base58(bytes: &[u8], count_leading_1: usize) -> String { let bytes = if count_leading_1 == 0 && !bytes.is_empty() && bytes[0] == 0 { &bytes[1..] } else { - &bytes[count_leading_1..] + &bytes[count_leading_1 as usize..] }; str_base58.push_str(&bs58::encode(bytes).into_string()); diff --git a/src/keys/ed25519.rs b/src/keys/ed25519.rs index 62be4377565862f20a1975141df196027ed4667c..cf89b5419d3b0bea69c4879c2725b378c7c2e9bc 100644 --- a/src/keys/ed25519.rs +++ b/src/keys/ed25519.rs @@ -42,8 +42,9 @@ use std::marker::PhantomData; use unwrap::unwrap; use zeroize::Zeroize; -/// Maximal size of a public key in bytes -pub const PUBKEY_SIZE_IN_BYTES: usize = 32; +/// Size of a public key in bytes +pub const PUBKEY_SIZE_IN_BYTES: usize = 33; +const PUBKEY_INTERNAL_SIZE_IN_BYTES: usize = 32; /// constf a signature in bytes pub const SIG_SIZE_IN_BYTES: usize = 64; @@ -157,8 +158,8 @@ impl Eq for Signature {} #[cfg_attr(feature = "ser", derive(Deserialize, Serialize))] #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct PublicKey { - datas: [u8; 32], - count_leading_zero: usize, + pub(crate) datas: [u8; 32], + count_leading_zero: u8, } impl Default for PublicKey { @@ -172,7 +173,7 @@ impl Default for PublicKey { impl AsRef<[u8]> for PublicKey { fn as_ref(&self) -> &[u8] { - &self.datas[..] + unsafe { std::slice::from_raw_parts(self.datas.as_ptr(), PUBKEY_SIZE_IN_BYTES) } } } @@ -186,11 +187,17 @@ impl TryFrom<&[u8]> for PublicKey { found: bytes.len(), }) } else { - let mut u8_array = [0; PUBKEY_SIZE_IN_BYTES]; - u8_array[(PUBKEY_SIZE_IN_BYTES - bytes.len())..].copy_from_slice(&bytes); + let mut u8_array = [0; PUBKEY_INTERNAL_SIZE_IN_BYTES]; + let count_leading_zero = if bytes.len() <= PUBKEY_INTERNAL_SIZE_IN_BYTES { + u8_array[(PUBKEY_INTERNAL_SIZE_IN_BYTES - bytes.len())..].copy_from_slice(&bytes); + 0 + } else { + u8_array.copy_from_slice(&bytes[..PUBKEY_INTERNAL_SIZE_IN_BYTES]); + bytes[PUBKEY_INTERNAL_SIZE_IN_BYTES] + }; Ok(PublicKey { datas: u8_array, - count_leading_zero: 0, + count_leading_zero, }) } } @@ -198,7 +205,7 @@ impl TryFrom<&[u8]> for PublicKey { impl ToBase58 for PublicKey { fn to_base58(&self) -> String { - bytes_to_str_base58(self.as_ref(), self.count_leading_zero) + bytes_to_str_base58(self.datas.as_ref(), self.count_leading_zero) } } @@ -207,7 +214,7 @@ impl Display for PublicKey { write!( f, "{}", - bytes_to_str_base58(self.as_ref(), self.count_leading_zero) + bytes_to_str_base58(self.datas.as_ref(), self.count_leading_zero) ) } } @@ -236,7 +243,7 @@ impl super::PublicKey for PublicKey { } fn verify(&self, message: &[u8], signature: &Self::Signature) -> Result<(), SigError> { - Ok(UnparsedPublicKey::new(&ED25519, self.as_ref()) + Ok(UnparsedPublicKey::new(&ED25519, self.datas.as_ref()) .verify(message, &signature.0) .map_err(|_| SigError::InvalidSig)?) } @@ -292,7 +299,7 @@ impl super::KeyPair for Ed25519KeyPair { fn generate_signator(&self) -> Result<Self::Signator, super::SignError> { Ok(Signator( - RingKeyPair::from_seed_and_public_key(self.seed.as_ref(), self.pubkey.as_ref()) + RingKeyPair::from_seed_and_public_key(self.seed.as_ref(), self.pubkey.datas.as_ref()) .map_err(|_| super::SignError::CorruptedKeyPair)?, )) } @@ -448,13 +455,6 @@ mod tests { assert!(!seed.eq(&other_seed)); // Test seed parsing - /*assert_eq!( - Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd",).unwrap_err(), - BaseConvertionError::InvalidLength { - found: 31, - expected: 32 - } - );*/ assert_eq!( Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd<<").unwrap_err(), BaseConvertionError::InvalidCharacter { @@ -465,24 +465,67 @@ mod tests { } #[test] - fn test_pubkey_111_from_base58() { + fn test_pubkey_111_from_base58() -> Result<(), bincode::Error> { let public58 = "11111111111111111111111111111111111111111111"; - let _ = unwrap!(super::PublicKey::from_base58(public58)); + let public_key = unwrap!(super::PublicKey::from_base58(public58)); + assert_eq!( + &[ + 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, 44 + ][..], + public_key.as_ref(), + ); + assert_eq!( + bincode::serialize(&public_key)?, + public_key.to_bytes_vector(), + ); + Ok(()) + } + + #[test] + fn test_pubkey_with_leading_1() -> Result<(), bincode::Error> { + let public58 = "13fn6X3XWVgshHTgS8beZMo9XiyScx6MB6yPsBB5ZBia"; + let public_key = unwrap!(super::PublicKey::from_base58(public58)); + assert_eq!( + bincode::serialize(&public_key)?, + public_key.to_bytes_vector(), + ); + Ok(()) + } + + #[test] + fn test_other_pubkey_with_leading_1() -> Result<(), bincode::Error> { + let public58 = "1V27SH9TiVEDs8TWFPydpRKxhvZari7wjGwQnPxMnkr"; + let public_key = unwrap!(super::PublicKey::from_base58(public58)); + assert_eq!( + bincode::serialize(&public_key)?, + public_key.to_bytes_vector(), + ); + Ok(()) } #[test] - fn base58_public_key() { + fn base58_public_key() -> Result<(), bincode::Error> { let public58 = "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"; let public_key = unwrap!(super::PublicKey::from_base58(public58)); // Test base58 encoding/decoding (loop for every bytes) assert_eq!(public_key.to_base58(), public58); let public_raw = unwrap!(b58::str_base58_to_32bytes(public58)); - assert_eq!(public_raw.0.to_vec(), public_key.to_bytes_vector()); - for (key, raw) in public_key.as_ref().iter().zip(public_raw.0.iter()) { + assert_eq!( + public_raw.0.to_vec(), + &public_key.to_bytes_vector()[..PUBKEY_INTERNAL_SIZE_IN_BYTES] + ); + for (key, raw) in public_key.datas.as_ref().iter().zip(public_raw.0.iter()) { assert_eq!(key, raw); } + // Test binary encoding/decoding + assert_eq!( + bincode::serialize(&public_key)?, + public_key.to_bytes_vector(), + ); + // Test pubkey debug assert_eq!( "PublicKey { DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV }".to_owned(), @@ -490,8 +533,8 @@ mod tests { ); // Test pubkey with 43 characters - let pubkey43 = - super::PublicKey::from_base58("2nV7Dv4nhTJ9dZUvRJpL34vFP9b2BkDjKWv9iBW2JaR").unwrap(); + let pubkey43 = super::PublicKey::from_base58("2nV7Dv4nhTJ9dZUvRJpL34vFP9b2BkDjKWv9iBW2JaR") + .expect("invalid pubkey"); println!("pubkey43={:?}", pubkey43.as_ref()); assert_eq!( format!("{:?}", pubkey43), @@ -505,6 +548,7 @@ mod tests { offset: 42 } ); + Ok(()) } #[test] @@ -536,7 +580,7 @@ mod tests { signature.hash(&mut hasher); let hash1 = hasher.finish(); let mut hasher = DefaultHasher::new(); - let signature_copy = signature.clone(); + let signature_copy = signature; signature_copy.hash(&mut hasher); let hash2 = hasher.finish(); assert_eq!(hash1, hash2); diff --git a/src/keys/mod.rs b/src/keys/mod.rs index 77084f26742e68bb92bdb5a1bf71c2bb68b0d79a..2d9ecce59fb6116644c71d0e430a335010344894 100644 --- a/src/keys/mod.rs +++ b/src/keys/mod.rs @@ -506,7 +506,7 @@ mod tests { } #[test] - fn pubkey() { + fn public_key() { let ed25519_pubkey_default = ed25519::PublicKey::default(); let pubkey_default = PubKey::Ed25519(ed25519_pubkey_default); let pubkey = PubKey::Ed25519(unwrap!(ed25519::PublicKey::try_from( @@ -520,14 +520,16 @@ mod tests { ); assert_eq!(pubkey.size_in_bytes(), ed25519::PUBKEY_SIZE_IN_BYTES + 3); - assert_eq!("1111111111111111111111111111111", &format!("{}", pubkey)); + assert_eq!("11111111111111111111111111111111", &format!("{}", pubkey)); assert_eq!(KeysAlgo::Ed25519, pubkey.algo()); assert_eq!(KeysAlgo::Schnorr, PubKey::Schnorr().algo()); - assert_eq!([0u8; 32].to_vec(), pubkey.to_bytes_vector()); + let mut expected_vec = [0u8; 32].to_vec(); + expected_vec.push(32); + assert_eq!(expected_vec, pubkey.to_bytes_vector()); - assert_eq!("1111111111111111111111111111111", &pubkey.to_base58()); + assert_eq!("11111111111111111111111111111111", &pubkey.to_base58()); assert_eq!( Err(SigError::InvalidSig), @@ -720,11 +722,11 @@ mod tests { assert_eq!( Err(PubkeyFromBytesError::InvalidBytesLen { expected: ed25519::PUBKEY_SIZE_IN_BYTES, - found: 33, + found: 34, }), PubKey::from_bytes(&[ 0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 31 + 23, 24, 25, 26, 27, 28, 29, 30, 31, 31, 17 ]), ); } diff --git a/src/lib.rs b/src/lib.rs index 4c36431b691ce4533866f4d9716c21a975d0adc1..60f0aabc5b145ccb0380d5c7be285060b4d5ad0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,6 @@ missing_copy_implementations, trivial_casts, trivial_numeric_casts, - unsafe_code, unstable_features, unused_import_braces, unused_qualifications