diff --git a/eth2/utils/bls/src/aggregate_signature.rs b/eth2/utils/bls/src/aggregate_signature.rs index e6c6cff9a..00afe19d6 100644 --- a/eth2/utils/bls/src/aggregate_signature.rs +++ b/eth2/utils/bls/src/aggregate_signature.rs @@ -1,4 +1,4 @@ -use super::{AggregatePublicKey, Signature, BLS_AGG_SIG_BYTE_SIZE}; +use super::*; use bls_aggregates::{ AggregatePublicKey as RawAggregatePublicKey, AggregateSignature as RawAggregateSignature, }; @@ -6,7 +6,7 @@ use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::{encode as hex_encode, HexVisitor}; -use ssz::{decode, Decodable, DecodeError, Encodable, SszStream}; +use ssz::{Decodable, DecodeError}; use tree_hash::tree_hash_ssz_encoding_as_vector; /// A BLS aggregate signature. @@ -99,8 +99,12 @@ impl AggregateSignature { pub fn from_bytes(bytes: &[u8]) -> Result { for byte in bytes { if *byte != 0 { - let sig = - RawAggregateSignature::from_bytes(&bytes).map_err(|_| DecodeError::Invalid)?; + let sig = RawAggregateSignature::from_bytes(&bytes).map_err(|_| { + DecodeError::BytesInvalid( + format!("Invalid AggregateSignature bytes: {:?}", bytes).to_string(), + ) + })?; + return Ok(Self { aggregate_signature: sig, is_empty: false, @@ -127,22 +131,11 @@ impl AggregateSignature { } } -impl Encodable for AggregateSignature { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.as_bytes()); - } -} - -impl Decodable for AggregateSignature { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_AGG_SIG_BYTE_SIZE { - return Err(DecodeError::TooShort); - } - let agg_sig = AggregateSignature::from_bytes(&bytes[i..(i + BLS_AGG_SIG_BYTE_SIZE)]) - .map_err(|_| DecodeError::Invalid)?; - Ok((agg_sig, i + BLS_AGG_SIG_BYTE_SIZE)) - } -} +impl_ssz!( + AggregateSignature, + BLS_AGG_SIG_BYTE_SIZE, + "AggregateSignature" +); impl Serialize for AggregateSignature { /// Serde serialization is compliant the Ethereum YAML test format. @@ -161,8 +154,9 @@ impl<'de> Deserialize<'de> for AggregateSignature { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let agg_sig = decode(&bytes[..]) + let agg_sig = AggregateSignature::from_ssz_bytes(&bytes) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; + Ok(agg_sig) } } @@ -174,7 +168,7 @@ cached_tree_hash_ssz_encoding_as_vector!(AggregateSignature, 96); mod tests { use super::super::{Keypair, Signature}; use super::*; - use ssz::{decode, ssz_encode}; + use ssz::Encodable; #[test] pub fn test_ssz_round_trip() { @@ -183,8 +177,8 @@ mod tests { let mut original = AggregateSignature::new(); original.add(&Signature::new(&[42, 42], 0, &keypair.sk)); - let bytes = ssz_encode(&original); - let decoded = decode::(&bytes).unwrap(); + let bytes = original.as_ssz_bytes(); + let decoded = AggregateSignature::from_ssz_bytes(&bytes).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/bls/src/fake_aggregate_signature.rs b/eth2/utils/bls/src/fake_aggregate_signature.rs index aeb89507d..829a280e1 100644 --- a/eth2/utils/bls/src/fake_aggregate_signature.rs +++ b/eth2/utils/bls/src/fake_aggregate_signature.rs @@ -59,25 +59,11 @@ impl FakeAggregateSignature { } } -impl Encodable for FakeAggregateSignature { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.bytes); - } -} - -impl Decodable for FakeAggregateSignature { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_AGG_SIG_BYTE_SIZE { - return Err(DecodeError::TooShort); - } - Ok(( - FakeAggregateSignature { - bytes: bytes[i..(i + BLS_AGG_SIG_BYTE_SIZE)].to_vec(), - }, - i + BLS_AGG_SIG_BYTE_SIZE, - )) - } -} +impl_ssz!( + FakeAggregateSignature, + BLS_AGG_SIG_BYTE_SIZE, + "FakeAggregateSignature" +); impl Serialize for FakeAggregateSignature { fn serialize(&self, serializer: S) -> Result diff --git a/eth2/utils/bls/src/fake_signature.rs b/eth2/utils/bls/src/fake_signature.rs index 8a333b9c0..a10e40323 100644 --- a/eth2/utils/bls/src/fake_signature.rs +++ b/eth2/utils/bls/src/fake_signature.rs @@ -55,25 +55,7 @@ impl FakeSignature { } } -impl Encodable for FakeSignature { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.bytes); - } -} - -impl Decodable for FakeSignature { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_SIG_BYTE_SIZE { - return Err(DecodeError::TooShort); - } - Ok(( - FakeSignature { - bytes: bytes[i..(i + BLS_SIG_BYTE_SIZE)].to_vec(), - }, - i + BLS_SIG_BYTE_SIZE, - )) - } -} +impl_ssz!(FakeSignature, BLS_SIG_BYTE_SIZE, "FakeSignature"); tree_hash_ssz_encoding_as_vector!(FakeSignature); cached_tree_hash_ssz_encoding_as_vector!(FakeSignature, 96); diff --git a/eth2/utils/bls/src/lib.rs b/eth2/utils/bls/src/lib.rs index fae41aeed..afe655939 100644 --- a/eth2/utils/bls/src/lib.rs +++ b/eth2/utils/bls/src/lib.rs @@ -1,6 +1,8 @@ extern crate bls_aggregates; extern crate ssz; +#[macro_use] +mod macros; mod aggregate_public_key; mod keypair; mod public_key; diff --git a/eth2/utils/bls/src/macros.rs b/eth2/utils/bls/src/macros.rs new file mode 100644 index 000000000..b5c9f8e33 --- /dev/null +++ b/eth2/utils/bls/src/macros.rs @@ -0,0 +1,38 @@ +macro_rules! impl_ssz { + ($type: ident, $byte_size: expr, $item_str: expr) => { + impl ssz::Encodable for $type { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + $byte_size + } + + fn ssz_append(&self, buf: &mut Vec) { + buf.append(&mut self.as_bytes()) + } + } + + impl ssz::Decodable for $type { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + $byte_size + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let len = bytes.len(); + let expected = ::ssz_fixed_len(); + + if len != expected { + Err(ssz::DecodeError::InvalidByteLength { len, expected }) + } else { + $type::from_bytes(bytes) + } + } + } + }; +} diff --git a/eth2/utils/bls/src/public_key.rs b/eth2/utils/bls/src/public_key.rs index 41b87d383..565755b37 100644 --- a/eth2/utils/bls/src/public_key.rs +++ b/eth2/utils/bls/src/public_key.rs @@ -4,7 +4,7 @@ use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::{encode as hex_encode, HexVisitor}; -use ssz::{decode, ssz_encode, Decodable, DecodeError, Encodable, SszStream}; +use ssz::{ssz_encode, Decodable, DecodeError}; use std::default; use std::fmt; use std::hash::{Hash, Hasher}; @@ -27,9 +27,19 @@ impl PublicKey { &self.0 } + /// Returns the underlying point as compressed bytes. + /// + /// Identical to `self.as_uncompressed_bytes()`. + fn as_bytes(&self) -> Vec { + self.as_raw().as_bytes() + } + /// Converts compressed bytes to PublicKey pub fn from_bytes(bytes: &[u8]) -> Result { - let pubkey = RawPublicKey::from_bytes(&bytes).map_err(|_| DecodeError::Invalid)?; + let pubkey = RawPublicKey::from_bytes(&bytes).map_err(|_| { + DecodeError::BytesInvalid(format!("Invalid PublicKey bytes: {:?}", bytes).to_string()) + })?; + Ok(PublicKey(pubkey)) } @@ -40,8 +50,9 @@ impl PublicKey { /// Converts (x, y) bytes to PublicKey pub fn from_uncompressed_bytes(bytes: &[u8]) -> Result { - let pubkey = - RawPublicKey::from_uncompressed_bytes(&bytes).map_err(|_| DecodeError::Invalid)?; + let pubkey = RawPublicKey::from_uncompressed_bytes(&bytes).map_err(|_| { + DecodeError::BytesInvalid("Invalid PublicKey uncompressed bytes.".to_string()) + })?; Ok(PublicKey(pubkey)) } @@ -68,22 +79,7 @@ impl default::Default for PublicKey { } } -impl Encodable for PublicKey { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.0.as_bytes()); - } -} - -impl Decodable for PublicKey { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_PUBLIC_KEY_BYTE_SIZE { - return Err(DecodeError::TooShort); - } - let raw_sig = RawPublicKey::from_bytes(&bytes[i..(i + BLS_PUBLIC_KEY_BYTE_SIZE)]) - .map_err(|_| DecodeError::TooShort)?; - Ok((PublicKey(raw_sig), i + BLS_PUBLIC_KEY_BYTE_SIZE)) - } -} +impl_ssz!(PublicKey, BLS_PUBLIC_KEY_BYTE_SIZE, "PublicKey"); impl Serialize for PublicKey { fn serialize(&self, serializer: S) -> Result @@ -100,7 +96,7 @@ impl<'de> Deserialize<'de> for PublicKey { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let pubkey = decode(&bytes[..]) + let pubkey = Self::from_ssz_bytes(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid pubkey ({:?})", e)))?; Ok(pubkey) } @@ -139,7 +135,7 @@ mod tests { let original = PublicKey::from_secret_key(&sk); let bytes = ssz_encode(&original); - let (decoded, _) = PublicKey::ssz_decode(&bytes, 0).unwrap(); + let decoded = PublicKey::from_ssz_bytes(&bytes).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/bls/src/secret_key.rs b/eth2/utils/bls/src/secret_key.rs index d1aaa96da..39b4422a1 100644 --- a/eth2/utils/bls/src/secret_key.rs +++ b/eth2/utils/bls/src/secret_key.rs @@ -1,10 +1,10 @@ use super::BLS_SECRET_KEY_BYTE_SIZE; -use bls_aggregates::{DecodeError as BlsDecodeError, SecretKey as RawSecretKey}; +use bls_aggregates::SecretKey as RawSecretKey; use hex::encode as hex_encode; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::HexVisitor; -use ssz::{decode, ssz_encode, Decodable, DecodeError, Encodable, SszStream}; +use ssz::{ssz_encode, Decodable, DecodeError}; use tree_hash::tree_hash_ssz_encoding_as_vector; /// A single BLS signature. @@ -19,11 +19,21 @@ impl SecretKey { SecretKey(RawSecretKey::random()) } + /// Returns the underlying point as compressed bytes. + fn as_bytes(&self) -> Vec { + self.as_raw().as_bytes() + } + /// Instantiate a SecretKey from existing bytes. /// /// Note: this is _not_ SSZ decoding. - pub fn from_bytes(bytes: &[u8]) -> Result { - Ok(SecretKey(RawSecretKey::from_bytes(bytes)?)) + pub fn from_bytes(bytes: &[u8]) -> Result { + Ok(SecretKey(RawSecretKey::from_bytes(bytes).map_err(|e| { + DecodeError::BytesInvalid(format!( + "Invalid SecretKey bytes: {:?} Error: {:?}", + bytes, e + )) + })?)) } /// Returns the underlying secret key. @@ -32,22 +42,7 @@ impl SecretKey { } } -impl Encodable for SecretKey { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.0.as_bytes()); - } -} - -impl Decodable for SecretKey { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_SECRET_KEY_BYTE_SIZE { - return Err(DecodeError::TooShort); - } - let raw_sig = RawSecretKey::from_bytes(&bytes[i..(i + BLS_SECRET_KEY_BYTE_SIZE)]) - .map_err(|_| DecodeError::TooShort)?; - Ok((SecretKey(raw_sig), i + BLS_SECRET_KEY_BYTE_SIZE)) - } -} +impl_ssz!(SecretKey, BLS_SECRET_KEY_BYTE_SIZE, "SecretKey"); impl Serialize for SecretKey { fn serialize(&self, serializer: S) -> Result @@ -64,7 +59,7 @@ impl<'de> Deserialize<'de> for SecretKey { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let secret_key = decode::(&bytes[..]) + let secret_key = SecretKey::from_ssz_bytes(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; Ok(secret_key) } @@ -84,7 +79,7 @@ mod tests { .unwrap(); let bytes = ssz_encode(&original); - let (decoded, _) = SecretKey::ssz_decode(&bytes, 0).unwrap(); + let decoded = SecretKey::from_ssz_bytes(&bytes).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/bls/src/signature.rs b/eth2/utils/bls/src/signature.rs index e2dbd9c27..e8dd80e7f 100644 --- a/eth2/utils/bls/src/signature.rs +++ b/eth2/utils/bls/src/signature.rs @@ -5,7 +5,7 @@ use hex::encode as hex_encode; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::HexVisitor; -use ssz::{decode, ssz_encode, Decodable, DecodeError, Encodable, SszStream}; +use ssz::{ssz_encode, Decodable, DecodeError}; use tree_hash::tree_hash_ssz_encoding_as_vector; /// A single BLS signature. @@ -83,8 +83,11 @@ impl Signature { pub fn from_bytes(bytes: &[u8]) -> Result { for byte in bytes { if *byte != 0 { - let raw_signature = - RawSignature::from_bytes(&bytes).map_err(|_| DecodeError::Invalid)?; + let raw_signature = RawSignature::from_bytes(&bytes).map_err(|_| { + DecodeError::BytesInvalid( + format!("Invalid Signature bytes: {:?}", bytes).to_string(), + ) + })?; return Ok(Signature { signature: raw_signature, is_empty: false, @@ -100,21 +103,7 @@ impl Signature { } } -impl Encodable for Signature { - fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_raw(&self.as_bytes()); - } -} - -impl Decodable for Signature { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() - i < BLS_SIG_BYTE_SIZE { - return Err(DecodeError::TooShort); - } - let signature = Signature::from_bytes(&bytes[i..(i + BLS_SIG_BYTE_SIZE)])?; - Ok((signature, i + BLS_SIG_BYTE_SIZE)) - } -} +impl_ssz!(Signature, BLS_SIG_BYTE_SIZE, "Signature"); tree_hash_ssz_encoding_as_vector!(Signature); cached_tree_hash_ssz_encoding_as_vector!(Signature, 96); @@ -136,7 +125,7 @@ impl<'de> Deserialize<'de> for Signature { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let signature = decode(&bytes[..]) + let signature = Self::from_ssz_bytes(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; Ok(signature) } @@ -156,7 +145,7 @@ mod tests { let original = Signature::new(&[42, 42], 0, &keypair.sk); let bytes = ssz_encode(&original); - let decoded = decode::(&bytes).unwrap(); + let decoded = Signature::from_ssz_bytes(&bytes).unwrap(); assert_eq!(original, decoded); }