lighthouse/crypto/bls/src/impls/blst.rs
realbigsean 303deb9969 Rust 1.54.0 lints (#2483)
## Issue Addressed

N/A

## Proposed Changes

- Removing a bunch of unnecessary references
- Updated `Error::VariantError` to `Error::Variant`
- There were additional enum variant lints that I ignored, because I thought our variant names were fine
- removed `MonitoredValidator`'s `pubkey` field, because I couldn't find it used anywhere. It looks like we just use the string version of the pubkey (the `id` field) if there is no index

## Additional Info



Co-authored-by: realbigsean <seananderson33@gmail.com>
2021-07-30 01:11:47 +00:00

284 lines
9.5 KiB
Rust

use crate::{
generic_aggregate_public_key::TAggregatePublicKey,
generic_aggregate_signature::TAggregateSignature,
generic_public_key::{GenericPublicKey, TPublicKey, PUBLIC_KEY_BYTES_LEN},
generic_secret_key::TSecretKey,
generic_signature::{TSignature, SIGNATURE_BYTES_LEN},
Error, Hash256, ZeroizeHash, INFINITY_SIGNATURE,
};
pub use blst::min_pk as blst_core;
use blst::{blst_scalar, BLST_ERROR};
use rand::Rng;
use std::iter::ExactSizeIterator;
pub const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
pub const RAND_BITS: usize = 64;
/// Provides the externally-facing, core BLS types.
pub mod types {
pub use super::blst_core::PublicKey;
pub use super::blst_core::SecretKey;
pub use super::blst_core::Signature;
pub use super::verify_signature_sets;
pub use super::BlstAggregatePublicKey as AggregatePublicKey;
pub use super::BlstAggregateSignature as AggregateSignature;
pub use super::SignatureSet;
}
pub type SignatureSet<'a> = crate::generic_signature_set::GenericSignatureSet<
'a,
blst_core::PublicKey,
BlstAggregatePublicKey,
blst_core::Signature,
BlstAggregateSignature,
>;
pub fn verify_signature_sets<'a>(
signature_sets: impl ExactSizeIterator<Item = &'a SignatureSet<'a>>,
) -> bool {
let sets = signature_sets.collect::<Vec<_>>();
if sets.is_empty() {
return false;
}
let rng = &mut rand::thread_rng();
let mut rands: Vec<blst_scalar> = Vec::with_capacity(sets.len());
let mut msgs_refs = Vec::with_capacity(sets.len());
let mut sigs = Vec::with_capacity(sets.len());
let mut pks = Vec::with_capacity(sets.len());
for set in &sets {
// Generate random scalars.
let mut vals = [0u64; 4];
while vals[0] == 0 {
// Do not use zero
vals[0] = rng.gen();
}
let mut rand_i = std::mem::MaybeUninit::<blst_scalar>::uninit();
// TODO: remove this `unsafe` code-block once we get a safe option from `blst`.
//
// https://github.com/sigp/lighthouse/issues/1720
unsafe {
blst::blst_scalar_from_uint64(rand_i.as_mut_ptr(), vals.as_ptr());
rands.push(rand_i.assume_init());
}
// Grab a slice of the message, to satisfy the blst API.
msgs_refs.push(set.message.as_bytes());
if let Some(point) = set.signature.point() {
// Subgroup check the signature
if !point.0.subgroup_check() {
return false;
}
// Convert the aggregate signature into a signature.
sigs.push(point.0.to_signature())
} else {
// Any "empty" signature should cause a signature failure.
return false;
}
// Sanity check.
if set.signing_keys.is_empty() {
// A signature that has no signing keys is invalid.
return false;
}
// Collect all the public keys into a point, to satisfy the blst API.
//
// Note: we could potentially have the `SignatureSet` take a pubkey point instead of a
// `GenericPublicKey` and avoid this allocation.
let signing_keys = set
.signing_keys
.iter()
.map(|pk| pk.point())
.collect::<Vec<_>>();
// Aggregate all the public keys.
// Public keys have already been checked for subgroup and infinity
let agg_pk = match blst_core::AggregatePublicKey::aggregate(&signing_keys, false) {
Ok(agg_pk) => agg_pk,
Err(_) => return false,
};
pks.push(agg_pk.to_public_key());
}
let (sig_refs, pks_refs): (Vec<_>, Vec<_>) = sigs.iter().zip(pks.iter()).unzip();
// Public keys have already been checked for subgroup and infinity
// Signatures have already been checked for subgroup
// Signature checks above could be done here for convienence as well
let err = blst_core::Signature::verify_multiple_aggregate_signatures(
&msgs_refs, DST, &pks_refs, false, &sig_refs, false, &rands, RAND_BITS,
);
err == blst::BLST_ERROR::BLST_SUCCESS
}
impl TPublicKey for blst_core::PublicKey {
fn serialize(&self) -> [u8; PUBLIC_KEY_BYTES_LEN] {
self.compress()
}
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
// key_validate accepts uncompressed bytes too so enforce byte length here.
// It also does subgroup checks, noting infinity check is done in `generic_public_key.rs`.
if bytes.len() != PUBLIC_KEY_BYTES_LEN {
return Err(Error::InvalidByteLength {
got: bytes.len(),
expected: PUBLIC_KEY_BYTES_LEN,
});
}
Self::key_validate(bytes).map_err(Into::into)
}
}
/// A wrapper that allows for `PartialEq` and `Clone` impls.
pub struct BlstAggregatePublicKey(blst_core::AggregatePublicKey);
impl Clone for BlstAggregatePublicKey {
fn clone(&self) -> Self {
Self(blst_core::AggregatePublicKey::from_public_key(
&self.0.to_public_key(),
))
}
}
impl PartialEq for BlstAggregatePublicKey {
fn eq(&self, other: &Self) -> bool {
self.0.to_public_key() == other.0.to_public_key()
}
}
impl TAggregatePublicKey<blst_core::PublicKey> for BlstAggregatePublicKey {
fn to_public_key(&self) -> GenericPublicKey<blst_core::PublicKey> {
GenericPublicKey::from_point(self.0.to_public_key())
}
fn aggregate(pubkeys: &[GenericPublicKey<blst_core::PublicKey>]) -> Result<Self, Error> {
let pubkey_refs = pubkeys.iter().map(|pk| pk.point()).collect::<Vec<_>>();
// Public keys have already been checked for subgroup and infinity
let agg_pub = blst_core::AggregatePublicKey::aggregate(&pubkey_refs, false)?;
Ok(BlstAggregatePublicKey(agg_pub))
}
}
impl TSignature<blst_core::PublicKey> for blst_core::Signature {
fn serialize(&self) -> [u8; SIGNATURE_BYTES_LEN] {
self.to_bytes()
}
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
Self::from_bytes(bytes).map_err(Into::into)
}
fn verify(&self, pubkey: &blst_core::PublicKey, msg: Hash256) -> bool {
// Public keys have already been checked for subgroup and infinity
// Check Signature inside function for subgroup
self.verify(true, msg.as_bytes(), DST, &[], pubkey, false) == BLST_ERROR::BLST_SUCCESS
}
}
/// A wrapper that allows for `PartialEq` and `Clone` impls.
pub struct BlstAggregateSignature(blst_core::AggregateSignature);
impl Clone for BlstAggregateSignature {
fn clone(&self) -> Self {
Self(blst_core::AggregateSignature::from_signature(
&self.0.to_signature(),
))
}
}
impl PartialEq for BlstAggregateSignature {
fn eq(&self, other: &Self) -> bool {
self.0.to_signature() == other.0.to_signature()
}
}
impl TAggregateSignature<blst_core::PublicKey, BlstAggregatePublicKey, blst_core::Signature>
for BlstAggregateSignature
{
fn infinity() -> Self {
blst_core::Signature::from_bytes(&INFINITY_SIGNATURE)
.map(|sig| blst_core::AggregateSignature::from_signature(&sig))
.map(Self)
.expect("should decode infinity signature")
}
fn add_assign(&mut self, other: &blst_core::Signature) {
// Add signature into aggregate, signature has already been subgroup checked
let _ = self.0.add_signature(other, false);
}
fn add_assign_aggregate(&mut self, other: &Self) {
self.0.add_aggregate(&other.0)
}
fn serialize(&self) -> [u8; SIGNATURE_BYTES_LEN] {
self.0.to_signature().to_bytes()
}
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
blst_core::Signature::from_bytes(bytes)
.map_err(Into::into)
.map(|sig| blst_core::AggregateSignature::from_signature(&sig))
.map(Self)
}
fn fast_aggregate_verify(
&self,
msg: Hash256,
pubkeys: &[&GenericPublicKey<blst_core::PublicKey>],
) -> bool {
let pubkeys = pubkeys.iter().map(|pk| pk.point()).collect::<Vec<_>>();
let signature = self.0.clone().to_signature();
// Public keys are already valid due to PoP
// Check Signature inside function for subgroup
signature.fast_aggregate_verify(true, msg.as_bytes(), DST, &pubkeys)
== BLST_ERROR::BLST_SUCCESS
}
fn aggregate_verify(
&self,
msgs: &[Hash256],
pubkeys: &[&GenericPublicKey<blst_core::PublicKey>],
) -> bool {
let pubkeys = pubkeys.iter().map(|pk| pk.point()).collect::<Vec<_>>();
let msgs = msgs.iter().map(|hash| hash.as_bytes()).collect::<Vec<_>>();
let signature = self.0.clone().to_signature();
// Public keys have already been checked for subgroup and infinity
// Check Signature inside function for subgroup
signature.aggregate_verify(true, &msgs, DST, &pubkeys, false) == BLST_ERROR::BLST_SUCCESS
}
}
impl TSecretKey<blst_core::Signature, blst_core::PublicKey> for blst_core::SecretKey {
fn random() -> Self {
let rng = &mut rand::thread_rng();
let ikm: [u8; 32] = rng.gen();
Self::key_gen(&ikm, &[]).unwrap()
}
fn public_key(&self) -> blst_core::PublicKey {
self.sk_to_pk()
}
fn sign(&self, msg: Hash256) -> blst_core::Signature {
self.sign(msg.as_bytes(), DST, &[])
}
fn serialize(&self) -> ZeroizeHash {
self.to_bytes().into()
}
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
Self::from_bytes(bytes).map_err(Into::into)
}
}