<commit_before>use std::collections::HashSet;
use super::bls::{
    AggregateSignature,
    AggregatePublicKey,
};
use super::db::ClientDB;
use super::db::stores::{
    ValidatorStore,
    ValidatorStoreError,
};
use super::types::Bitfield;

#[derive(Debug, PartialEq)]
pub enum SignatureVerificationError {
    BadValidatorIndex,
    PublicKeyCorrupt,
    NoPublicKeyForValidator,
    DBError(String),
}

/// Verify an aggregate signature across the supplied message.
///
/// The public keys used for verification are collected by mapping
/// each true bitfield bit to canonical ValidatorRecord index through
/// the attestation_indicies map.
///
/// Each public key is loaded from the store on-demand.
pub fn verify_aggregate_signature_for_indices<T>(
    message: &[u8],
    agg_sig: &AggregateSignature,
    attestation_indices: &[usize],
    bitfield: &Bitfield,
    validator_store: &ValidatorStore<T>)
    -> Result<Option<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 {
            /*
             * De-reference the attestation index into a canonical ValidatorRecord index.
             */
            let validator = *attestation_indices.get(i)
                .ok_or(SignatureVerificationError::BadValidatorIndex)?;
            /*
             * Load the validators public key from our store.
             */
            let pub_key = validator_store
                .get_public_key_by_index(validator)?
                .ok_or(SignatureVerificationError::NoPublicKeyForValidator)?;
            /*
             * Add the validators public key to the aggregate public key.
             */
            agg_pub_key.add(&pub_key);
            /*
             * Add to the validator to the set of voters for this attestation record.
             */
            voters.insert(validator);
        }
    }
    /*
     * Verify the aggregate public key against the aggregate signature.
     *
     * This verification will only succeed if the exact set of public keys
     * were added to the aggregate public key as those that signed the aggregate signature.
     */
    if agg_sig.verify(&message, &agg_pub_key) {
        Ok(Some(voters))
    } else {
        Ok(None)
    }
}

impl From<ValidatorStoreError> for SignatureVerificationError {
    fn from(error: ValidatorStoreError) -> Self {
        match error {
            ValidatorStoreError::DBError(s) =>
                SignatureVerificationError::DBError(s),
            ValidatorStoreError::DecodeError =>
                SignatureVerificationError::PublicKeyCorrupt,
        }
    }
}


#[cfg(test)]
mod tests {<commit_msg>Fix a type in sig. ver. comment<commit_after>use std::collections::HashSet;
use super::bls::{
    AggregateSignature,
    AggregatePublicKey,
};
use super::db::ClientDB;
use super::db::stores::{
    ValidatorStore,
    ValidatorStoreError,
};
use super::types::Bitfield;

#[derive(Debug, PartialEq)]
pub enum SignatureVerificationError {
    BadValidatorIndex,
    PublicKeyCorrupt,
    NoPublicKeyForValidator,
    DBError(String),
}

/// Verify an aggregate signature across the supplied message.
///
/// The public keys used for verification are collected by mapping
/// each true bitfield bit to canonical ValidatorRecord index through
/// the attestation_indicies map.
///
/// Each public key is loaded from the store on-demand.
pub fn verify_aggregate_signature_for_indices<T>(
    message: &[u8],
    agg_sig: &AggregateSignature,
    attestation_indices: &[usize],
    bitfield: &Bitfield,
    validator_store: &ValidatorStore<T>)
    -> Result<Option<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 {
            /*
             * De-reference the attestation index into a canonical ValidatorRecord index.
             */
            let validator = *attestation_indices.get(i)
                .ok_or(SignatureVerificationError::BadValidatorIndex)?;
            /*
             * Load the validators public key from our store.
             */
            let pub_key = validator_store
                .get_public_key_by_index(validator)?
                .ok_or(SignatureVerificationError::NoPublicKeyForValidator)?;
            /*
             * Add the validators public key to the aggregate public key.
             */
            agg_pub_key.add(&pub_key);
            /*
             * Add validator to the set of voters for this attestation record.
             */
            voters.insert(validator);
        }
    }
    /*
     * Verify the aggregate public key against the aggregate signature.
     *
     * This verification will only succeed if the exact set of public keys
     * were added to the aggregate public key as those that signed the aggregate signature.
     */
    if agg_sig.verify(&message, &agg_pub_key) {
        Ok(Some(voters))
    } else {
        Ok(None)
    }
}

impl From<ValidatorStoreError> for SignatureVerificationError {
    fn from(error: ValidatorStoreError) -> Self {
        match error {
            ValidatorStoreError::DBError(s) =>
                SignatureVerificationError::DBError(s),
            ValidatorStoreError::DecodeError =>
                SignatureVerificationError::PublicKeyCorrupt,
        }
    }
}


#[cfg(test)]
mod tests {
{'fraction_non_alphanumeric': 0.09305629550701473, 'fraction_numerical': 0.0007103534008169064, 'mean_word_length': 2.470117067159581, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5558711', 'n_tokens_mistral': 1567, 'n_tokens_neox': 1538, 'n_words': 418}