Files
lighthouse/crypto/bls/src/generic_signature.rs
realbigsean 50321c6671 Updates to make crates publishable (#2472)
## Issue Addressed

Related to: #2259

Made an attempt at all the necessary updates here to publish the crates to crates.io. I incremented the minor versions on all the crates that have been previously published. We still might run into some issues as we try to publish because I'm not able to test this out but I think it's a good starting point.

## Proposed Changes

- Add description and license to `ssz_types` and `serde_util`
- rename `serde_util` to `eth2_serde_util`
- increment minor versions
- remove path dependencies
- remove patch dependencies 

## Additional Info
Crates published: 

- [x] `tree_hash` -- need to publish `tree_hash_derive` and `eth2_hashing` first
- [x] `eth2_ssz_types` -- need to publish `eth2_serde_util` first
- [x] `tree_hash_derive`
- [x] `eth2_ssz`
- [x] `eth2_ssz_derive`
- [x] `eth2_serde_util`
- [x] `eth2_hashing`


Co-authored-by: realbigsean <seananderson33@gmail.com>
2021-09-03 01:10:25 +00:00

174 lines
5.3 KiB
Rust

use crate::{
generic_public_key::{GenericPublicKey, TPublicKey},
Error, Hash256,
};
use eth2_serde_utils::hex::encode as hex_encode;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use ssz::{Decode, Encode};
use std::fmt;
use std::marker::PhantomData;
use tree_hash::TreeHash;
/// The byte-length of a BLS signature when serialized in compressed form.
pub const SIGNATURE_BYTES_LEN: usize = 96;
/// Represents the signature at infinity.
pub const INFINITY_SIGNATURE: [u8; SIGNATURE_BYTES_LEN] = [
0xc0, 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, 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,
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, 0,
0,
];
/// The compressed bytes used to represent `GenericSignature::empty()`.
pub const NONE_SIGNATURE: [u8; SIGNATURE_BYTES_LEN] = [0; SIGNATURE_BYTES_LEN];
/// Implemented on some struct from a BLS library so it may be used as the `point` in an
/// `GenericSignature`.
pub trait TSignature<GenericPublicKey>: Sized + Clone {
/// Serialize `self` as compressed bytes.
fn serialize(&self) -> [u8; SIGNATURE_BYTES_LEN];
/// Deserialize `self` from compressed bytes.
fn deserialize(bytes: &[u8]) -> Result<Self, Error>;
/// Returns `true` if `self` is a signature across `msg` by `pubkey`.
fn verify(&self, pubkey: &GenericPublicKey, msg: Hash256) -> bool;
}
/// A BLS signature that is generic across:
///
/// - `Pub`: A BLS public key.
/// - `Sig`: A BLS signature.
///
/// Provides generic functionality whilst deferring all serious cryptographic operations to the
/// generics.
#[derive(Clone, PartialEq, Eq)]
pub struct GenericSignature<Pub, Sig> {
/// The underlying point which performs *actual* cryptographic operations.
point: Option<Sig>,
/// True if this point is equal to the `INFINITY_SIGNATURE`.
pub(crate) is_infinity: bool,
_phantom: PhantomData<Pub>,
}
impl<Pub, Sig> GenericSignature<Pub, Sig>
where
Sig: TSignature<Pub>,
{
/// Initialize self to the "empty" value. This value is serialized as all-zeros.
///
/// ## Notes
///
/// This function is not necessarily useful from a BLS cryptography perspective, it mostly
/// exists to satisfy the Eth2 specification which expects the all-zeros serialization to be
/// meaningful.
pub fn empty() -> Self {
Self {
point: None,
is_infinity: false,
_phantom: PhantomData,
}
}
/// Returns `true` if `self` is equal to the "empty" value.
///
/// E.g., `Self::empty().is_empty() == true`
pub fn is_empty(&self) -> bool {
self.point.is_none()
}
/// Returns a reference to the underlying BLS point.
pub(crate) fn point(&self) -> Option<&Sig> {
self.point.as_ref()
}
/// Instantiates `Self` from a `point`.
pub(crate) fn from_point(point: Sig, is_infinity: bool) -> Self {
Self {
point: Some(point),
is_infinity,
_phantom: PhantomData,
}
}
/// Serialize `self` as compressed bytes.
pub fn serialize(&self) -> [u8; SIGNATURE_BYTES_LEN] {
if let Some(point) = &self.point {
point.serialize()
} else {
NONE_SIGNATURE
}
}
/// Deserialize `self` from compressed bytes.
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
let point = if bytes == &NONE_SIGNATURE[..] {
None
} else {
Some(Sig::deserialize(bytes)?)
};
Ok(Self {
point,
is_infinity: bytes == &INFINITY_SIGNATURE[..],
_phantom: PhantomData,
})
}
}
impl<Pub, Sig> GenericSignature<Pub, Sig>
where
Sig: TSignature<Pub>,
Pub: TPublicKey + Clone,
{
/// Returns `true` if `self` is a signature across `msg` by `pubkey`.
pub fn verify(&self, pubkey: &GenericPublicKey<Pub>, msg: Hash256) -> bool {
if let Some(point) = &self.point {
point.verify(pubkey.point(), msg)
} else {
false
}
}
}
impl<PublicKey, T: TSignature<PublicKey>> Encode for GenericSignature<PublicKey, T> {
impl_ssz_encode!(SIGNATURE_BYTES_LEN);
}
impl<PublicKey, T: TSignature<PublicKey>> Decode for GenericSignature<PublicKey, T> {
impl_ssz_decode!(SIGNATURE_BYTES_LEN);
}
impl<PublicKey, T: TSignature<PublicKey>> TreeHash for GenericSignature<PublicKey, T> {
impl_tree_hash!(SIGNATURE_BYTES_LEN);
}
impl<PublicKey, T: TSignature<PublicKey>> fmt::Display for GenericSignature<PublicKey, T> {
impl_display!();
}
impl<PublicKey, T: TSignature<PublicKey>> std::str::FromStr for GenericSignature<PublicKey, T> {
impl_from_str!();
}
impl<PublicKey, T: TSignature<PublicKey>> Serialize for GenericSignature<PublicKey, T> {
impl_serde_serialize!();
}
impl<'de, PublicKey, T: TSignature<PublicKey>> Deserialize<'de> for GenericSignature<PublicKey, T> {
impl_serde_deserialize!();
}
impl<PublicKey, T: TSignature<PublicKey>> fmt::Debug for GenericSignature<PublicKey, T> {
impl_debug!();
}
#[cfg(feature = "arbitrary")]
impl<PublicKey: 'static, T: TSignature<PublicKey> + 'static> arbitrary::Arbitrary
for GenericSignature<PublicKey, T>
{
impl_arbitrary!(SIGNATURE_BYTES_LEN);
}