github.com/ethereum/go-ethereum@v1.14.3/beacon/types/committee.go (about)

     1  // Copyright 2023 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package types
    18  
    19  import (
    20  	"crypto/sha256"
    21  	"encoding/json"
    22  	"fmt"
    23  	"math/bits"
    24  
    25  	"github.com/ethereum/go-ethereum/beacon/params"
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/common/hexutil"
    28  	bls "github.com/protolambda/bls12-381-util"
    29  )
    30  
    31  // SerializedSyncCommitteeSize is the size of the sync committee plus the
    32  // aggregate public key.
    33  const SerializedSyncCommitteeSize = (params.SyncCommitteeSize + 1) * params.BLSPubkeySize
    34  
    35  // SerializedSyncCommittee is the serialized version of a sync committee
    36  // plus the aggregate public key.
    37  type SerializedSyncCommittee [SerializedSyncCommitteeSize]byte
    38  
    39  // jsonSyncCommittee is the JSON representation of a sync committee.
    40  //
    41  // See data structure definition here:
    42  // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate
    43  type jsonSyncCommittee struct {
    44  	Pubkeys   []hexutil.Bytes `json:"pubkeys"`
    45  	Aggregate hexutil.Bytes   `json:"aggregate_pubkey"`
    46  }
    47  
    48  // MarshalJSON implements json.Marshaler.
    49  func (s *SerializedSyncCommittee) MarshalJSON() ([]byte, error) {
    50  	sc := jsonSyncCommittee{Pubkeys: make([]hexutil.Bytes, params.SyncCommitteeSize)}
    51  	for i := range sc.Pubkeys {
    52  		sc.Pubkeys[i] = make(hexutil.Bytes, params.BLSPubkeySize)
    53  		copy(sc.Pubkeys[i][:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize])
    54  	}
    55  	sc.Aggregate = make(hexutil.Bytes, params.BLSPubkeySize)
    56  	copy(sc.Aggregate[:], s[params.SyncCommitteeSize*params.BLSPubkeySize:])
    57  	return json.Marshal(&sc)
    58  }
    59  
    60  // UnmarshalJSON implements json.Marshaler.
    61  func (s *SerializedSyncCommittee) UnmarshalJSON(input []byte) error {
    62  	var sc jsonSyncCommittee
    63  	if err := json.Unmarshal(input, &sc); err != nil {
    64  		return err
    65  	}
    66  	if len(sc.Pubkeys) != params.SyncCommitteeSize {
    67  		return fmt.Errorf("invalid number of pubkeys %d", len(sc.Pubkeys))
    68  	}
    69  	for i, key := range sc.Pubkeys {
    70  		if len(key) != params.BLSPubkeySize {
    71  			return fmt.Errorf("pubkey %d has invalid size %d", i, len(key))
    72  		}
    73  		copy(s[i*params.BLSPubkeySize:], key[:])
    74  	}
    75  	if len(sc.Aggregate) != params.BLSPubkeySize {
    76  		return fmt.Errorf("invalid aggregate pubkey size %d", len(sc.Aggregate))
    77  	}
    78  	copy(s[params.SyncCommitteeSize*params.BLSPubkeySize:], sc.Aggregate[:])
    79  	return nil
    80  }
    81  
    82  // Root calculates the root hash of the binary tree representation of a sync
    83  // committee provided in serialized format.
    84  //
    85  // TODO(zsfelfoldi): Get rid of this when SSZ encoding lands.
    86  func (s *SerializedSyncCommittee) Root() common.Hash {
    87  	var (
    88  		hasher  = sha256.New()
    89  		padding [64 - params.BLSPubkeySize]byte
    90  		data    [params.SyncCommitteeSize]common.Hash
    91  		l       = params.SyncCommitteeSize
    92  	)
    93  	for i := range data {
    94  		hasher.Reset()
    95  		hasher.Write(s[i*params.BLSPubkeySize : (i+1)*params.BLSPubkeySize])
    96  		hasher.Write(padding[:])
    97  		hasher.Sum(data[i][:0])
    98  	}
    99  	for l > 1 {
   100  		for i := 0; i < l/2; i++ {
   101  			hasher.Reset()
   102  			hasher.Write(data[i*2][:])
   103  			hasher.Write(data[i*2+1][:])
   104  			hasher.Sum(data[i][:0])
   105  		}
   106  		l /= 2
   107  	}
   108  	hasher.Reset()
   109  	hasher.Write(s[SerializedSyncCommitteeSize-params.BLSPubkeySize : SerializedSyncCommitteeSize])
   110  	hasher.Write(padding[:])
   111  	hasher.Sum(data[1][:0])
   112  	hasher.Reset()
   113  	hasher.Write(data[0][:])
   114  	hasher.Write(data[1][:])
   115  	hasher.Sum(data[0][:0])
   116  	return data[0]
   117  }
   118  
   119  // Deserialize splits open the pubkeys into proper BLS key types.
   120  func (s *SerializedSyncCommittee) Deserialize() (*SyncCommittee, error) {
   121  	sc := new(SyncCommittee)
   122  	for i := 0; i <= params.SyncCommitteeSize; i++ {
   123  		key := new(bls.Pubkey)
   124  
   125  		var bytes [params.BLSPubkeySize]byte
   126  		copy(bytes[:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize])
   127  
   128  		if err := key.Deserialize(&bytes); err != nil {
   129  			return nil, err
   130  		}
   131  		if i < params.SyncCommitteeSize {
   132  			sc.keys[i] = key
   133  		} else {
   134  			sc.aggregate = key
   135  		}
   136  	}
   137  	return sc, nil
   138  }
   139  
   140  // SyncCommittee is a set of sync committee signer pubkeys and the aggregate key.
   141  //
   142  // See data structure definition here:
   143  // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate
   144  type SyncCommittee struct {
   145  	keys      [params.SyncCommitteeSize]*bls.Pubkey
   146  	aggregate *bls.Pubkey
   147  }
   148  
   149  // VerifySignature returns true if the given sync aggregate is a valid signature
   150  // or the given hash.
   151  func (sc *SyncCommittee) VerifySignature(signingRoot common.Hash, signature *SyncAggregate) bool {
   152  	var (
   153  		sig  bls.Signature
   154  		keys = make([]*bls.Pubkey, 0, params.SyncCommitteeSize)
   155  	)
   156  	if err := sig.Deserialize(&signature.Signature); err != nil {
   157  		return false
   158  	}
   159  	for i, key := range sc.keys {
   160  		if signature.Signers[i/8]&(byte(1)<<(i%8)) != 0 {
   161  			keys = append(keys, key)
   162  		}
   163  	}
   164  	return bls.FastAggregateVerify(keys, signingRoot[:], &sig)
   165  }
   166  
   167  //go:generate go run github.com/fjl/gencodec -type SyncAggregate -field-override syncAggregateMarshaling -out gen_syncaggregate_json.go
   168  
   169  // SyncAggregate represents an aggregated BLS signature with Signers referring
   170  // to a subset of the corresponding sync committee.
   171  //
   172  // See data structure definition here:
   173  // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate
   174  type SyncAggregate struct {
   175  	Signers   [params.SyncCommitteeBitmaskSize]byte `gencodec:"required" json:"sync_committee_bits"`
   176  	Signature [params.BLSSignatureSize]byte         `gencodec:"required" json:"sync_committee_signature"`
   177  }
   178  
   179  type syncAggregateMarshaling struct {
   180  	Signers   hexutil.Bytes
   181  	Signature hexutil.Bytes
   182  }
   183  
   184  // SignerCount returns the number of signers in the aggregate signature.
   185  func (s *SyncAggregate) SignerCount() int {
   186  	var count int
   187  	for _, v := range s.Signers {
   188  		count += bits.OnesCount8(v)
   189  	}
   190  	return count
   191  }