Move PublicKey
to store uncompressed bytes.
This is an optimisation that allows for faster hashing of a public key, however it adds a penalty to SSZ encoding because we need to go decompressed -> PublicKey -> compressed. The spec presently uses compressed bytes to store public keys, however I'm hoping it will change.
This commit is contained in:
parent
243ef2db80
commit
bfa2e71b46
@ -14,7 +14,7 @@ impl AggregatePublicKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, public_key: &PublicKey) {
|
pub fn add(&mut self, public_key: &PublicKey) {
|
||||||
self.0.add(public_key.as_raw())
|
self.0.add(&public_key.as_raw())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying signature.
|
/// Returns the underlying signature.
|
||||||
|
@ -10,39 +10,58 @@ use ssz::{
|
|||||||
use std::default;
|
use std::default;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
/// A single BLS signature.
|
/// A single BLS public key.
|
||||||
|
///
|
||||||
|
/// This struct stores an uncompressed public key as a byte vec. The reason we store bytes instead
|
||||||
|
/// of the `RawPublicKey` struct is because it allows for building a hashmap of `PublicKey` much
|
||||||
|
/// faster.
|
||||||
|
///
|
||||||
|
/// Storing as uncompressed bytes costs ~0.02% more time when adding a `PublicKey` to an
|
||||||
|
/// `AggregateKey`, however it saves ~0.5ms each time you need to add a pubkey to a hashmap.
|
||||||
///
|
///
|
||||||
/// This struct is a wrapper upon a base type and provides helper functions (e.g., SSZ
|
/// This struct is a wrapper upon a base type and provides helper functions (e.g., SSZ
|
||||||
/// serialization).
|
/// serialization).
|
||||||
#[derive(Debug, Clone, Eq)]
|
#[derive(Debug, Clone, Eq)]
|
||||||
pub struct PublicKey(RawPublicKey);
|
pub struct PublicKey {
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
impl PublicKey {
|
impl PublicKey {
|
||||||
pub fn from_secret_key(secret_key: &SecretKey) -> Self {
|
pub fn from_secret_key(secret_key: &SecretKey) -> Self {
|
||||||
PublicKey(RawPublicKey::from_secret_key(secret_key.as_raw()))
|
let mut raw_key = RawPublicKey::from_secret_key(secret_key.as_raw());
|
||||||
|
let uncompressed_bytes = raw_key.as_uncompressed_bytes();
|
||||||
|
Self {
|
||||||
|
bytes: uncompressed_bytes,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying signature.
|
/// Returns the underlying signature.
|
||||||
pub fn as_raw(&self) -> &RawPublicKey {
|
pub fn as_raw(&self) -> RawPublicKey {
|
||||||
&self.0
|
RawPublicKey::from_uncompressed_bytes(&self.bytes).expect("PublicKey in invalid state")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts compressed bytes to PublicKey
|
/// Converts compressed bytes to PublicKey
|
||||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
|
pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
|
||||||
let pubkey = RawPublicKey::from_bytes(&bytes).map_err(|_| DecodeError::Invalid)?;
|
let mut pubkey = RawPublicKey::from_bytes(&bytes).map_err(|_| DecodeError::Invalid)?;
|
||||||
Ok(PublicKey(pubkey))
|
Ok(Self {
|
||||||
|
bytes: pubkey.as_uncompressed_bytes(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the PublicKey as (x, y) bytes
|
/// Returns the PublicKey as (x, y) bytes
|
||||||
pub fn as_uncompressed_bytes(&self) -> Vec<u8> {
|
pub fn as_uncompressed_bytes(&self) -> Vec<u8> {
|
||||||
RawPublicKey::as_uncompressed_bytes(&mut self.0.clone())
|
self.bytes.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts (x, y) bytes to PublicKey
|
/// Converts (x, y) bytes to PublicKey
|
||||||
pub fn from_uncompressed_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
|
pub fn from_uncompressed_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
|
||||||
let pubkey =
|
// Do a conversion to check the bytes are valid.
|
||||||
|
let _pubkey =
|
||||||
RawPublicKey::from_uncompressed_bytes(&bytes).map_err(|_| DecodeError::Invalid)?;
|
RawPublicKey::from_uncompressed_bytes(&bytes).map_err(|_| DecodeError::Invalid)?;
|
||||||
Ok(PublicKey(pubkey))
|
|
||||||
|
Ok(Self {
|
||||||
|
bytes: bytes.to_vec(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the last 6 bytes of the SSZ encoding of the public key, as a hex string.
|
/// Returns the last 6 bytes of the SSZ encoding of the public key, as a hex string.
|
||||||
@ -64,15 +83,22 @@ impl default::Default for PublicKey {
|
|||||||
|
|
||||||
impl Encodable for PublicKey {
|
impl Encodable for PublicKey {
|
||||||
fn ssz_append(&self, s: &mut SszStream) {
|
fn ssz_append(&self, s: &mut SszStream) {
|
||||||
s.append_vec(&self.0.as_bytes());
|
s.append_vec(&self.as_raw().as_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decodable for PublicKey {
|
impl Decodable for PublicKey {
|
||||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||||
let (sig_bytes, i) = decode_ssz_list(bytes, i)?;
|
let (sig_bytes, i) = decode_ssz_list(bytes, i)?;
|
||||||
let raw_sig = RawPublicKey::from_bytes(&sig_bytes).map_err(|_| DecodeError::TooShort)?;
|
let mut raw_sig =
|
||||||
Ok((PublicKey(raw_sig), i))
|
RawPublicKey::from_bytes(&sig_bytes).map_err(|_| DecodeError::TooShort)?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
Self {
|
||||||
|
bytes: raw_sig.as_uncompressed_bytes(),
|
||||||
|
},
|
||||||
|
i,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +125,7 @@ impl<'de> Deserialize<'de> for PublicKey {
|
|||||||
|
|
||||||
impl TreeHash for PublicKey {
|
impl TreeHash for PublicKey {
|
||||||
fn hash_tree_root(&self) -> Vec<u8> {
|
fn hash_tree_root(&self) -> Vec<u8> {
|
||||||
hash(&self.0.as_bytes())
|
hash(&self.as_raw().as_bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +143,7 @@ impl Hash for PublicKey {
|
|||||||
///
|
///
|
||||||
/// Use `ssz::Encode` to obtain the bytes required for consensus hashing.
|
/// Use `ssz::Encode` to obtain the bytes required for consensus hashing.
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.as_uncompressed_bytes().hash(state)
|
self.bytes.hash(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ impl Signature {
|
|||||||
|
|
||||||
/// Verify the Signature against a PublicKey.
|
/// Verify the Signature against a PublicKey.
|
||||||
pub fn verify(&self, msg: &[u8], domain: u64, pk: &PublicKey) -> bool {
|
pub fn verify(&self, msg: &[u8], domain: u64, pk: &PublicKey) -> bool {
|
||||||
self.0.verify(msg, domain, pk.as_raw())
|
self.0.verify(msg, domain, &pk.as_raw())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify the Signature against a PublicKey, where the message has already been hashed.
|
/// Verify the Signature against a PublicKey, where the message has already been hashed.
|
||||||
@ -44,7 +44,7 @@ impl Signature {
|
|||||||
pk: &PublicKey,
|
pk: &PublicKey,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.0
|
self.0
|
||||||
.verify_hashed(x_real_hashed, x_imaginary_hashed, pk.as_raw())
|
.verify_hashed(x_real_hashed, x_imaginary_hashed, &pk.as_raw())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying signature.
|
/// Returns the underlying signature.
|
||||||
|
Loading…
Reference in New Issue
Block a user