github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/blocks/signature.go (about) 1 package blocks 2 3 import ( 4 "context" 5 "encoding/binary" 6 7 "github.com/pkg/errors" 8 types "github.com/prysmaticlabs/eth2-types" 9 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 10 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 11 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 12 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 13 "github.com/prysmaticlabs/prysm/shared/attestationutil" 14 "github.com/prysmaticlabs/prysm/shared/bls" 15 "github.com/prysmaticlabs/prysm/shared/params" 16 ) 17 18 // retrieves the signature set from the raw data, public key,signature and domain provided. 19 func signatureSet(signedData, pub, signature, domain []byte) (*bls.SignatureSet, error) { 20 publicKey, err := bls.PublicKeyFromBytes(pub) 21 if err != nil { 22 return nil, errors.Wrap(err, "could not convert bytes to public key") 23 } 24 signingData := &pb.SigningData{ 25 ObjectRoot: signedData, 26 Domain: domain, 27 } 28 root, err := signingData.HashTreeRoot() 29 if err != nil { 30 return nil, errors.Wrap(err, "could not hash container") 31 } 32 return &bls.SignatureSet{ 33 Signatures: [][]byte{signature}, 34 PublicKeys: []bls.PublicKey{publicKey}, 35 Messages: [][32]byte{root}, 36 }, nil 37 } 38 39 // verifies the signature from the raw data, public key and domain provided. 40 func verifySignature(signedData, pub, signature, domain []byte) error { 41 set, err := signatureSet(signedData, pub, signature, domain) 42 if err != nil { 43 return err 44 } 45 if len(set.Signatures) != 1 { 46 return errors.Errorf("signature set contains %d signatures instead of 1", len(set.Signatures)) 47 } 48 // We assume only one signature set is returned here. 49 sig := set.Signatures[0] 50 publicKey := set.PublicKeys[0] 51 root := set.Messages[0] 52 rSig, err := bls.SignatureFromBytes(sig) 53 if err != nil { 54 return err 55 } 56 if !rSig.Verify(publicKey, root[:]) { 57 return helpers.ErrSigFailedToVerify 58 } 59 return nil 60 } 61 62 // VerifyBlockSignature verifies the proposer signature of a beacon block. 63 func VerifyBlockSignature(beaconState iface.ReadOnlyBeaconState, 64 proposerIndex types.ValidatorIndex, 65 sig []byte, 66 rootFunc func() ([32]byte, error)) error { 67 currentEpoch := helpers.SlotToEpoch(beaconState.Slot()) 68 domain, err := helpers.Domain(beaconState.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot()) 69 if err != nil { 70 return err 71 } 72 proposer, err := beaconState.ValidatorAtIndex(proposerIndex) 73 if err != nil { 74 return err 75 } 76 proposerPubKey := proposer.PublicKey 77 return helpers.VerifyBlockSigningRoot(proposerPubKey, sig, domain, rootFunc) 78 } 79 80 // BlockSignatureSet retrieves the block signature set from the provided block and its corresponding state. 81 func BlockSignatureSet(beaconState iface.ReadOnlyBeaconState, 82 proposerIndex types.ValidatorIndex, 83 sig []byte, 84 rootFunc func() ([32]byte, error)) (*bls.SignatureSet, error) { 85 currentEpoch := helpers.SlotToEpoch(beaconState.Slot()) 86 domain, err := helpers.Domain(beaconState.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot()) 87 if err != nil { 88 return nil, err 89 } 90 proposer, err := beaconState.ValidatorAtIndex(proposerIndex) 91 if err != nil { 92 return nil, err 93 } 94 proposerPubKey := proposer.PublicKey 95 return helpers.BlockSignatureSet(proposerPubKey, sig, domain, rootFunc) 96 } 97 98 // RandaoSignatureSet retrieves the relevant randao specific signature set object 99 // from a block and its corresponding state. 100 func RandaoSignatureSet(beaconState iface.ReadOnlyBeaconState, 101 reveal []byte, 102 ) (*bls.SignatureSet, error) { 103 buf, proposerPub, domain, err := randaoSigningData(beaconState) 104 if err != nil { 105 return nil, err 106 } 107 set, err := signatureSet(buf, proposerPub, reveal, domain) 108 if err != nil { 109 return nil, err 110 } 111 return set, nil 112 } 113 114 // retrieves the randao related signing data from the state. 115 func randaoSigningData(beaconState iface.ReadOnlyBeaconState) ([]byte, []byte, []byte, error) { 116 proposerIdx, err := helpers.BeaconProposerIndex(beaconState) 117 if err != nil { 118 return nil, nil, nil, errors.Wrap(err, "could not get beacon proposer index") 119 } 120 proposerPub := beaconState.PubkeyAtIndex(proposerIdx) 121 122 currentEpoch := helpers.SlotToEpoch(beaconState.Slot()) 123 buf := make([]byte, 32) 124 binary.LittleEndian.PutUint64(buf, uint64(currentEpoch)) 125 126 domain, err := helpers.Domain(beaconState.Fork(), currentEpoch, params.BeaconConfig().DomainRandao, beaconState.GenesisValidatorRoot()) 127 if err != nil { 128 return nil, nil, nil, err 129 } 130 return buf, proposerPub[:], domain, nil 131 } 132 133 // Method to break down attestations of the same domain and collect them into a single signature set. 134 func createAttestationSignatureSet( 135 ctx context.Context, 136 beaconState iface.ReadOnlyBeaconState, 137 atts []*ethpb.Attestation, 138 domain []byte, 139 ) (*bls.SignatureSet, error) { 140 if len(atts) == 0 { 141 return nil, nil 142 } 143 144 sigs := make([][]byte, len(atts)) 145 pks := make([]bls.PublicKey, len(atts)) 146 msgs := make([][32]byte, len(atts)) 147 for i, a := range atts { 148 sigs[i] = a.Signature 149 c, err := helpers.BeaconCommitteeFromState(beaconState, a.Data.Slot, a.Data.CommitteeIndex) 150 if err != nil { 151 return nil, err 152 } 153 ia, err := attestationutil.ConvertToIndexed(ctx, a, c) 154 if err != nil { 155 return nil, err 156 } 157 if err := attestationutil.IsValidAttestationIndices(ctx, ia); err != nil { 158 return nil, err 159 } 160 indices := ia.AttestingIndices 161 pubkeys := make([][]byte, len(indices)) 162 for i := 0; i < len(indices); i++ { 163 pubkeyAtIdx := beaconState.PubkeyAtIndex(types.ValidatorIndex(indices[i])) 164 pubkeys[i] = pubkeyAtIdx[:] 165 } 166 aggP, err := bls.AggregatePublicKeys(pubkeys) 167 if err != nil { 168 return nil, err 169 } 170 pks[i] = aggP 171 172 root, err := helpers.ComputeSigningRoot(ia.Data, domain) 173 if err != nil { 174 return nil, errors.Wrap(err, "could not get signing root of object") 175 } 176 msgs[i] = root 177 } 178 return &bls.SignatureSet{ 179 Signatures: sigs, 180 PublicKeys: pks, 181 Messages: msgs, 182 }, nil 183 } 184 185 // AttestationSignatureSet retrieves all the related attestation signature data such as the relevant public keys, 186 // signatures and attestation signing data and collate it into a signature set object. 187 func AttestationSignatureSet(ctx context.Context, beaconState iface.ReadOnlyBeaconState, atts []*ethpb.Attestation) (*bls.SignatureSet, error) { 188 if len(atts) == 0 { 189 return bls.NewSet(), nil 190 } 191 192 fork := beaconState.Fork() 193 gvr := beaconState.GenesisValidatorRoot() 194 dt := params.BeaconConfig().DomainBeaconAttester 195 196 // Split attestations by fork. Note: the signature domain will differ based on the fork. 197 var preForkAtts []*ethpb.Attestation 198 var postForkAtts []*ethpb.Attestation 199 for _, a := range atts { 200 if helpers.SlotToEpoch(a.Data.Slot) < fork.Epoch { 201 preForkAtts = append(preForkAtts, a) 202 } else { 203 postForkAtts = append(postForkAtts, a) 204 } 205 } 206 set := bls.NewSet() 207 208 // Check attestations from before the fork. 209 if fork.Epoch > 0 && len(preForkAtts) > 0 { // Check to prevent underflow and there is valid attestations to create sig set. 210 prevDomain, err := helpers.Domain(fork, fork.Epoch-1, dt, gvr) 211 if err != nil { 212 return nil, err 213 } 214 aSet, err := createAttestationSignatureSet(ctx, beaconState, preForkAtts, prevDomain) 215 if err != nil { 216 return nil, err 217 } 218 if aSet != nil { 219 set.Join(aSet) 220 } 221 } else if len(preForkAtts) > 0 { 222 // This is a sanity check that preForkAtts were not ignored when fork.Epoch == 0. This 223 // condition is not possible, but it doesn't hurt to check anyway. 224 return nil, errors.New("some attestations were not verified from previous fork before genesis") 225 } 226 227 if len(postForkAtts) > 0 { 228 // Then check attestations from after the fork. 229 currDomain, err := helpers.Domain(fork, fork.Epoch, dt, gvr) 230 if err != nil { 231 return nil, err 232 } 233 234 aSet, err := createAttestationSignatureSet(ctx, beaconState, postForkAtts, currDomain) 235 if err != nil { 236 return nil, err 237 } 238 if aSet != nil { 239 return set.Join(aSet), nil 240 } 241 } 242 243 return set, nil 244 }