Implement attestation signature validation and test
This commit is contained in:
parent
69c97745d2
commit
be09fd4f29
@ -4,10 +4,15 @@ use super::attestation_parent_hashes::{
|
||||
ParentHashesError,
|
||||
};
|
||||
use super::db::ClientDB;
|
||||
use super::db::stores::BlockStore;
|
||||
use super::db::stores::{
|
||||
BlockStore,
|
||||
ValidatorStore,
|
||||
StoreError,
|
||||
};
|
||||
use super::ssz::SszStream;
|
||||
use super::bls::{
|
||||
AggregateSignature,
|
||||
AggregatePublicKey,
|
||||
PublicKey,
|
||||
};
|
||||
use super::utils::hash::canonical_hash;
|
||||
|
@ -15,4 +15,5 @@ use super::transition::attestation_parent_hashes;
|
||||
use super::utils;
|
||||
|
||||
mod attestation_validation;
|
||||
mod signatures;
|
||||
mod ssz_block;
|
||||
|
126
lighthouse/state/validation/signatures.rs
Normal file
126
lighthouse/state/validation/signatures.rs
Normal file
@ -0,0 +1,126 @@
|
||||
use std::collections::HashSet;
|
||||
use super::bls::{
|
||||
AggregateSignature,
|
||||
AggregatePublicKey,
|
||||
};
|
||||
use super::db::ClientDB;
|
||||
use super::db::stores::{
|
||||
ValidatorStore,
|
||||
StoreError,
|
||||
};
|
||||
use super::utils::types::Bitfield;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SignatureVerificationError {
|
||||
BadValidatorIndex,
|
||||
PublicKeyCorrupt,
|
||||
NoPublicKeyForValidator,
|
||||
DBError(String),
|
||||
}
|
||||
|
||||
fn verify_aggregate_signature_for_indices<T>(message: &[u8],
|
||||
agg_sig: &AggregateSignature,
|
||||
attestation_indices: &[usize],
|
||||
bitfield: &Bitfield,
|
||||
validator_store: &ValidatorStore<T>)
|
||||
-> Result<(bool, HashSet<usize>), SignatureVerificationError>
|
||||
where T: ClientDB + Sized
|
||||
{
|
||||
let mut voters = HashSet::new();
|
||||
let mut agg_pub_key = AggregatePublicKey::new();
|
||||
|
||||
for i in 0..attestation_indices.len() {
|
||||
let voted = bitfield.get_bit(i);
|
||||
if voted {
|
||||
let validator = attestation_indices[i];
|
||||
let pub_key = validator_store.get_public_key_by_index(i)?
|
||||
.ok_or(SignatureVerificationError::NoPublicKeyForValidator)?;
|
||||
agg_pub_key.add(&pub_key);
|
||||
voters.insert(validator);
|
||||
}
|
||||
}
|
||||
Ok((agg_sig.verify(&message, &agg_pub_key),
|
||||
voters))
|
||||
}
|
||||
|
||||
impl From<StoreError> for SignatureVerificationError {
|
||||
fn from(error: StoreError) -> Self {
|
||||
match error {
|
||||
StoreError::DBError(s) =>
|
||||
SignatureVerificationError::DBError(s),
|
||||
StoreError::DecodeError =>
|
||||
SignatureVerificationError::PublicKeyCorrupt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::super::bls::{
|
||||
Keypair,
|
||||
Signature,
|
||||
};
|
||||
use super::super::db::MemoryDB;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
fn test_signature_verification() {
|
||||
let message = "cats".as_bytes();
|
||||
let signing_keypairs = vec![
|
||||
Keypair::random(),
|
||||
Keypair::random(),
|
||||
Keypair::random(),
|
||||
Keypair::random(),
|
||||
Keypair::random(),
|
||||
Keypair::random(),
|
||||
];
|
||||
let non_signing_keypairs = vec![
|
||||
Keypair::random(),
|
||||
Keypair::random(),
|
||||
Keypair::random(),
|
||||
Keypair::random(),
|
||||
Keypair::random(),
|
||||
Keypair::random(),
|
||||
];
|
||||
/*
|
||||
* Signing keypairs first, then non-signing
|
||||
*/
|
||||
let mut all_keypairs = signing_keypairs.clone();
|
||||
all_keypairs.append(&mut non_signing_keypairs.clone());
|
||||
|
||||
let attestation_indices: Vec<usize> = (0..all_keypairs.len())
|
||||
.collect();
|
||||
let mut bitfield = Bitfield::new();
|
||||
for i in 0..signing_keypairs.len() {
|
||||
bitfield.set_bit(i, true);
|
||||
}
|
||||
|
||||
let db = Arc::new(MemoryDB::open());
|
||||
let store = ValidatorStore::new(db);
|
||||
|
||||
for (i, keypair) in all_keypairs.iter().enumerate() {
|
||||
store.put_public_key_by_index(i, &keypair.pk).unwrap();
|
||||
}
|
||||
|
||||
let mut agg_sig = AggregateSignature::new();
|
||||
for keypair in &signing_keypairs {
|
||||
let sig = Signature::new(&message, &keypair.sk);
|
||||
agg_sig.add(&sig);
|
||||
}
|
||||
|
||||
let (is_valid, voters) = verify_aggregate_signature_for_indices(
|
||||
&message,
|
||||
&agg_sig,
|
||||
&attestation_indices,
|
||||
&bitfield,
|
||||
&store).unwrap();
|
||||
|
||||
assert_eq!(is_valid, true);
|
||||
(0..signing_keypairs.len())
|
||||
.for_each(|i| assert!(voters.contains(&i)));
|
||||
(signing_keypairs.len()..non_signing_keypairs.len())
|
||||
.for_each(|i| assert!(!voters.contains(&i)));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user