Example #1
0
        /// <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);
        }