/// <summary> /// Check if ``indexed_attestation`` has valid indices and signature. /// </summary> public bool IsValidIndexedAttestation(BeaconState state, IndexedAttestation indexedAttestation, Domain domain) { MiscellaneousParameters miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue; IList <ValidatorIndex> bit0Indices = indexedAttestation.CustodyBit0Indices; IList <ValidatorIndex> bit1Indices = indexedAttestation.CustodyBit1Indices; // Verify no index has custody bit equal to 1 [to be removed in phase 1] if (bit1Indices.Count != 0) // [to be removed in phase 1] { if (_logger.IsWarn()) { _logger.LogWarning(Event.InvalidIndexedAttestation, "Invalid indexed attestion from committee {CommitteeIndex} for slot {Slot}, because it has {BitIndicesCount} bit 1 indices.", indexedAttestation.Data.Index, indexedAttestation.Data.Slot, bit1Indices.Count()); } return(false); //[to be removed in phase 1] } // Verify max number of indices int totalIndices = bit0Indices.Count + bit1Indices.Count; if ((ulong)totalIndices > miscellaneousParameters.MaximumValidatorsPerCommittee) { if (_logger.IsWarn()) { _logger.LogWarning(Event.InvalidIndexedAttestation, "Invalid indexed attestion from committee {CommitteeIndex} for slot {Slot}, because it has total indices {TotalIndices}, more than the maximum validators per committe {MaximumValidatorsPerCommittee}.", indexedAttestation.Data.Index, indexedAttestation.Data.Slot, totalIndices, miscellaneousParameters.MaximumValidatorsPerCommittee); } return(false); } // Verify index sets are disjoint IEnumerable <ValidatorIndex> intersect = bit0Indices.Intersect(bit1Indices); if (intersect.Count() != 0) { if (_logger.IsWarn()) { _logger.LogWarning(Event.InvalidIndexedAttestation, "Invalid indexed attestion from committee {CommitteeIndex} for slot {Slot}, because it has {IntersectingValidatorCount} validator indexes in common between custody bit 0 and custody bit 1.", indexedAttestation.Data.Index, indexedAttestation.Data.Slot, intersect.Count()); } return(false); } // Verify indices are sorted if (bit0Indices.Count() > 1) { for (int index = 0; index < bit0Indices.Count() - 1; index++) { if (!(bit0Indices[index] < bit0Indices[index + 1])) { if (_logger.IsWarn()) { _logger.LogWarning(Event.InvalidIndexedAttestation, "Invalid indexed attestion from committee {CommitteeIndex} for slot {Slot}, because custody bit 0 index {IndexNumber} is not sorted.", indexedAttestation.Data.Index, indexedAttestation.Data.Slot, index); } return(false); } } } if (bit1Indices.Count() > 1) { for (int index = 0; index < bit1Indices.Count() - 1; index++) { if (!(bit1Indices[index] < bit1Indices[index + 1])) { if (_logger.IsWarn()) { _logger.LogWarning(Event.InvalidIndexedAttestation, "Invalid indexed attestion from committee {CommitteeIndex} for slot {Slot}, because custody bit 1 index {IndexNumber} is not sorted.", indexedAttestation.Data.Index, indexedAttestation.Data.Slot, index); } return(false); } } } // Verify aggregate signature IEnumerable <BlsPublicKey> bit0PublicKeys = bit0Indices.Select(x => state.Validators[(int)(ulong)x].PublicKey); BlsPublicKey bit0AggregatePublicKey = _cryptographyService.BlsAggregatePublicKeys(bit0PublicKeys); IEnumerable <BlsPublicKey> bit1PublicKeys = bit1Indices.Select(x => state.Validators[(int)(ulong)x].PublicKey); BlsPublicKey bit1AggregatePublicKey = _cryptographyService.BlsAggregatePublicKeys(bit1PublicKeys); BlsPublicKey[] publicKeys = new[] { bit0AggregatePublicKey, bit1AggregatePublicKey }; AttestationDataAndCustodyBit attestationDataAndCustodyBit0 = new AttestationDataAndCustodyBit(indexedAttestation.Data, false); Hash32 messageHashBit0 = attestationDataAndCustodyBit0.HashTreeRoot(); AttestationDataAndCustodyBit attestationDataAndCustodyBit1 = new AttestationDataAndCustodyBit(indexedAttestation.Data, true); Hash32 messageHashBit1 = attestationDataAndCustodyBit1.HashTreeRoot(); Hash32[] messageHashes = new[] { messageHashBit0, messageHashBit1 }; BlsSignature signature = indexedAttestation.Signature; bool isValid = _cryptographyService.BlsVerifyMultiple(publicKeys, messageHashes, signature, domain); if (!isValid) { if (_logger.IsWarn()) { _logger.LogWarning(Event.InvalidIndexedAttestation, "Invalid indexed attestion from committee {CommitteeIndex} for slot {Slot}, because the aggregate signature does not match.", indexedAttestation.Data.Index, indexedAttestation.Data.Slot); } return(false); } return(true); }