Skip to content

Commit c08dc59

Browse files
zsfelfoldikaralabe
andauthored
beacon/types: add beacon chain data types (#27292)
* beacon/types: add beacon chain data types * beacon/merkle: added comments * go.mod: cleanups --------- Co-authored-by: Péter Szilágyi <[email protected]>
1 parent 41fafa4 commit c08dc59

File tree

10 files changed

+836
-0
lines changed

10 files changed

+836
-0
lines changed

beacon/merkle/merkle.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2022 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 merkle implements proof verifications in binary merkle trees.
18+
package merkle
19+
20+
import (
21+
"crypto/sha256"
22+
"errors"
23+
"reflect"
24+
25+
"github.com/ethereum/go-ethereum/common"
26+
"github.com/ethereum/go-ethereum/common/hexutil"
27+
)
28+
29+
// Value represents either a 32 byte leaf value or hash node in a binary merkle tree/partial proof.
30+
type Value [32]byte
31+
32+
// Values represent a series of merkle tree leaves/nodes.
33+
type Values []Value
34+
35+
var valueT = reflect.TypeOf(Value{})
36+
37+
// UnmarshalJSON parses a merkle value in hex syntax.
38+
func (m *Value) UnmarshalJSON(input []byte) error {
39+
return hexutil.UnmarshalFixedJSON(valueT, input, m[:])
40+
}
41+
42+
// VerifyProof verifies a Merkle proof branch for a single value in a
43+
// binary Merkle tree (index is a generalized tree index).
44+
func VerifyProof(root common.Hash, index uint64, branch Values, value Value) error {
45+
hasher := sha256.New()
46+
for _, sibling := range branch {
47+
hasher.Reset()
48+
if index&1 == 0 {
49+
hasher.Write(value[:])
50+
hasher.Write(sibling[:])
51+
} else {
52+
hasher.Write(sibling[:])
53+
hasher.Write(value[:])
54+
}
55+
hasher.Sum(value[:0])
56+
if index >>= 1; index == 0 {
57+
return errors.New("branch has extra items")
58+
}
59+
}
60+
if index != 1 {
61+
return errors.New("branch is missing items")
62+
}
63+
if common.Hash(value) != root {
64+
return errors.New("root mismatch")
65+
}
66+
return nil
67+
}

beacon/params/params.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2022 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 params
18+
19+
const (
20+
EpochLength = 32
21+
SyncPeriodLength = 8192
22+
23+
BLSSignatureSize = 96
24+
BLSPubkeySize = 48
25+
26+
SyncCommitteeSize = 512
27+
SyncCommitteeBitmaskSize = SyncCommitteeSize / 8
28+
SyncCommitteeSupermajority = (SyncCommitteeSize*2 + 2) / 3
29+
)
30+
31+
const (
32+
StateIndexGenesisTime = 32
33+
StateIndexGenesisValidators = 33
34+
StateIndexForkVersion = 141
35+
StateIndexLatestHeader = 36
36+
StateIndexBlockRoots = 37
37+
StateIndexStateRoots = 38
38+
StateIndexHistoricRoots = 39
39+
StateIndexFinalBlock = 105
40+
StateIndexSyncCommittee = 54
41+
StateIndexNextSyncCommittee = 55
42+
StateIndexExecPayload = 56
43+
StateIndexExecHead = 908
44+
)

beacon/types/committee.go

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
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+
// SyncAggregate represents an aggregated BLS signature with Signers referring
168+
// to a subset of the corresponding sync committee.
169+
//
170+
// See data structure definition here:
171+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate
172+
type SyncAggregate struct {
173+
Signers [params.SyncCommitteeBitmaskSize]byte
174+
Signature [params.BLSSignatureSize]byte
175+
}
176+
177+
type jsonSyncAggregate struct {
178+
Signers hexutil.Bytes `json:"sync_committee_bits"`
179+
Signature hexutil.Bytes `json:"sync_committee_signature"`
180+
}
181+
182+
// MarshalJSON implements json.Marshaler.
183+
func (s *SyncAggregate) MarshalJSON() ([]byte, error) {
184+
return json.Marshal(&jsonSyncAggregate{
185+
Signers: s.Signers[:],
186+
Signature: s.Signature[:],
187+
})
188+
}
189+
190+
// UnmarshalJSON implements json.Marshaler.
191+
func (s *SyncAggregate) UnmarshalJSON(input []byte) error {
192+
var sc jsonSyncAggregate
193+
if err := json.Unmarshal(input, &sc); err != nil {
194+
return err
195+
}
196+
if len(sc.Signers) != params.SyncCommitteeBitmaskSize {
197+
return fmt.Errorf("invalid signature bitmask size %d", len(sc.Signers))
198+
}
199+
if len(sc.Signature) != params.BLSSignatureSize {
200+
return fmt.Errorf("invalid signature size %d", len(sc.Signature))
201+
}
202+
copy(s.Signers[:], sc.Signers)
203+
copy(s.Signature[:], sc.Signature)
204+
return nil
205+
}
206+
207+
// SignerCount returns the number of signers in the aggregate signature.
208+
func (s *SyncAggregate) SignerCount() int {
209+
var count int
210+
for _, v := range s.Signers {
211+
count += bits.OnesCount8(v)
212+
}
213+
return count
214+
}

0 commit comments

Comments
 (0)