Fix bug in attestation verification

We were ensuring that a validator was present on the aggregation
bitfield before adding their signature to the agg pub
This commit is contained in:
Paul Hauner 2019-03-09 20:09:17 +11:00
parent 62ab782ee2
commit 6250c81bb9
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
2 changed files with 47 additions and 27 deletions

View File

@ -147,6 +147,8 @@ pub enum AttestationInvalid {
///
/// (attestation_data_shard, attestation_data_slot)
NoCommitteeForShard(u64, Slot),
/// The validator index was unknown.
UnknownValidator(u64),
/// The attestation signature verification failed.
BadSignature,
/// The shard block root was not set to zero. This is a phase 0 requirement.

View File

@ -159,18 +159,16 @@ fn validate_attestation_signature_optional(
if verify_signature {
let attestation_epoch = attestation.data.slot.epoch(spec.slots_per_epoch);
verify!(
verify_attestation_signature(
state,
committee,
attestation_epoch,
&attestation.custody_bitfield,
&attestation.data,
&attestation.aggregate_signature,
spec
),
Invalid::BadSignature
);
verify_attestation_signature(
state,
committee,
attestation_epoch,
&attestation.aggregation_bitfield,
&attestation.custody_bitfield,
&attestation.data,
&attestation.aggregate_signature,
spec,
)?;
}
// [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.crosslink_data_root == ZERO_HASH`.
@ -195,30 +193,45 @@ fn verify_attestation_signature(
state: &BeaconState,
committee: &[usize],
attestation_epoch: Epoch,
aggregation_bitfield: &Bitfield,
custody_bitfield: &Bitfield,
attestation_data: &AttestationData,
aggregate_signature: &AggregateSignature,
spec: &ChainSpec,
) -> bool {
) -> Result<(), Error> {
let mut aggregate_pubs = vec![AggregatePublicKey::new(); 2];
let mut message_exists = vec![false; 2];
for (i, v) in committee.iter().enumerate() {
let custody_bit = match custody_bitfield.get(i) {
Ok(bit) => bit,
// Invalidate signature if custody_bitfield.len() < committee
Err(_) => return false,
};
let validator_signed = aggregation_bitfield.get(i).map_err(|_| {
Error::Invalid(Invalid::BadAggregationBitfieldLength(
committee.len(),
aggregation_bitfield.len(),
))
})?;
message_exists[custody_bit as usize] = true;
if validator_signed {
let custody_bit: bool = match custody_bitfield.get(i) {
Ok(bit) => bit,
// Invalidate signature if custody_bitfield.len() < committee
Err(_) => {
return Err(Error::Invalid(Invalid::BadCustodyBitfieldLength(
committee.len(),
custody_bitfield.len(),
)));
}
};
match state.validator_registry.get(*v as usize) {
Some(validator) => {
aggregate_pubs[custody_bit as usize].add(&validator.pubkey);
}
// Invalidate signature if validator index is unknown.
None => return false,
};
message_exists[custody_bit as usize] = true;
match state.validator_registry.get(*v as usize) {
Some(validator) => {
aggregate_pubs[custody_bit as usize].add(&validator.pubkey);
}
// Return error if validator index is unknown.
None => return Err(Error::BeaconStateError(BeaconStateError::UnknownValidator)),
};
}
}
// Message when custody bitfield is `false`
@ -251,5 +264,10 @@ fn verify_attestation_signature(
let domain = spec.get_domain(attestation_epoch, Domain::Attestation, &state.fork);
aggregate_signature.verify_multiple(&messages[..], domain, &keys[..])
verify!(
aggregate_signature.verify_multiple(&messages[..], domain, &keys[..]),
Invalid::BadSignature
);
Ok(())
}