Implement attestation signature validation and test

This commit is contained in:
Paul Hauner 2018-09-24 14:16:48 +10:00
parent 69c97745d2
commit be09fd4f29
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
3 changed files with 133 additions and 1 deletions

View File

@ -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;

View File

@ -15,4 +15,5 @@ use super::transition::attestation_parent_hashes;
use super::utils;
mod attestation_validation;
mod signatures;
mod ssz_block;

View 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)));
}
}