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) /// (attestation_data_shard, attestation_data_slot)
NoCommitteeForShard(u64, Slot), NoCommitteeForShard(u64, Slot),
/// The validator index was unknown.
UnknownValidator(u64),
/// The attestation signature verification failed. /// The attestation signature verification failed.
BadSignature, BadSignature,
/// The shard block root was not set to zero. This is a phase 0 requirement. /// 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 { if verify_signature {
let attestation_epoch = attestation.data.slot.epoch(spec.slots_per_epoch); let attestation_epoch = attestation.data.slot.epoch(spec.slots_per_epoch);
verify!( verify_attestation_signature(
verify_attestation_signature( state,
state, committee,
committee, attestation_epoch,
attestation_epoch, &attestation.aggregation_bitfield,
&attestation.custody_bitfield, &attestation.custody_bitfield,
&attestation.data, &attestation.data,
&attestation.aggregate_signature, &attestation.aggregate_signature,
spec spec,
), )?;
Invalid::BadSignature
);
} }
// [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.crosslink_data_root == ZERO_HASH`. // [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, state: &BeaconState,
committee: &[usize], committee: &[usize],
attestation_epoch: Epoch, attestation_epoch: Epoch,
aggregation_bitfield: &Bitfield,
custody_bitfield: &Bitfield, custody_bitfield: &Bitfield,
attestation_data: &AttestationData, attestation_data: &AttestationData,
aggregate_signature: &AggregateSignature, aggregate_signature: &AggregateSignature,
spec: &ChainSpec, spec: &ChainSpec,
) -> bool { ) -> Result<(), Error> {
let mut aggregate_pubs = vec![AggregatePublicKey::new(); 2]; let mut aggregate_pubs = vec![AggregatePublicKey::new(); 2];
let mut message_exists = vec![false; 2]; let mut message_exists = vec![false; 2];
for (i, v) in committee.iter().enumerate() { for (i, v) in committee.iter().enumerate() {
let custody_bit = match custody_bitfield.get(i) { let validator_signed = aggregation_bitfield.get(i).map_err(|_| {
Ok(bit) => bit, Error::Invalid(Invalid::BadAggregationBitfieldLength(
// Invalidate signature if custody_bitfield.len() < committee committee.len(),
Err(_) => return false, 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) { message_exists[custody_bit as usize] = true;
Some(validator) => {
aggregate_pubs[custody_bit as usize].add(&validator.pubkey); match state.validator_registry.get(*v as usize) {
} Some(validator) => {
// Invalidate signature if validator index is unknown. aggregate_pubs[custody_bit as usize].add(&validator.pubkey);
None => return false, }
}; // Return error if validator index is unknown.
None => return Err(Error::BeaconStateError(BeaconStateError::UnknownValidator)),
};
}
} }
// Message when custody bitfield is `false` // 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); 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(())
} }