github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/helpers/signing_root.go (about) 1 package helpers 2 3 import ( 4 fssz "github.com/ferranbt/fastssz" 5 "github.com/pkg/errors" 6 types "github.com/prysmaticlabs/eth2-types" 7 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 8 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 9 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 10 "github.com/prysmaticlabs/prysm/shared/bls" 11 "github.com/prysmaticlabs/prysm/shared/bytesutil" 12 "github.com/prysmaticlabs/prysm/shared/params" 13 ) 14 15 // ForkVersionByteLength length of fork version byte array. 16 const ForkVersionByteLength = 4 17 18 // DomainByteLength length of domain byte array. 19 const DomainByteLength = 4 20 21 // ErrSigFailedToVerify returns when a signature of a block object(ie attestation, slashing, exit... etc) 22 // failed to verify. 23 var ErrSigFailedToVerify = errors.New("signature did not verify") 24 25 // ComputeDomainAndSign computes the domain and signing root and sign it using the passed in private key. 26 func ComputeDomainAndSign(st iface.ReadOnlyBeaconState, epoch types.Epoch, obj fssz.HashRoot, domain [4]byte, key bls.SecretKey) ([]byte, error) { 27 d, err := Domain(st.Fork(), epoch, domain, st.GenesisValidatorRoot()) 28 if err != nil { 29 return nil, err 30 } 31 sr, err := ComputeSigningRoot(obj, d) 32 if err != nil { 33 return nil, err 34 } 35 return key.Sign(sr[:]).Marshal(), nil 36 } 37 38 // ComputeSigningRoot computes the root of the object by calculating the hash tree root of the signing data with the given domain. 39 // 40 // Spec pseudocode definition: 41 // def compute_signing_root(ssz_object: SSZObject, domain: Domain) -> Root: 42 // """ 43 // Return the signing root for the corresponding signing data. 44 // """ 45 // return hash_tree_root(SigningData( 46 // object_root=hash_tree_root(ssz_object), 47 // domain=domain, 48 // )) 49 func ComputeSigningRoot(object fssz.HashRoot, domain []byte) ([32]byte, error) { 50 return signingData(object.HashTreeRoot, domain) 51 } 52 53 // Computes the signing data by utilising the provided root function and then 54 // returning the signing data of the container object. 55 func signingData(rootFunc func() ([32]byte, error), domain []byte) ([32]byte, error) { 56 objRoot, err := rootFunc() 57 if err != nil { 58 return [32]byte{}, err 59 } 60 container := &pb.SigningData{ 61 ObjectRoot: objRoot[:], 62 Domain: domain, 63 } 64 return container.HashTreeRoot() 65 } 66 67 // ComputeDomainVerifySigningRoot computes domain and verifies signing root of an object given the beacon state, validator index and signature. 68 func ComputeDomainVerifySigningRoot(st iface.BeaconState, index types.ValidatorIndex, epoch types.Epoch, obj fssz.HashRoot, domain [4]byte, sig []byte) error { 69 v, err := st.ValidatorAtIndex(index) 70 if err != nil { 71 return err 72 } 73 d, err := Domain(st.Fork(), epoch, domain, st.GenesisValidatorRoot()) 74 if err != nil { 75 return err 76 } 77 return VerifySigningRoot(obj, v.PublicKey, sig, d) 78 } 79 80 // VerifySigningRoot verifies the signing root of an object given it's public key, signature and domain. 81 func VerifySigningRoot(obj fssz.HashRoot, pub, signature, domain []byte) error { 82 publicKey, err := bls.PublicKeyFromBytes(pub) 83 if err != nil { 84 return errors.Wrap(err, "could not convert bytes to public key") 85 } 86 sig, err := bls.SignatureFromBytes(signature) 87 if err != nil { 88 return errors.Wrap(err, "could not convert bytes to signature") 89 } 90 root, err := ComputeSigningRoot(obj, domain) 91 if err != nil { 92 return errors.Wrap(err, "could not compute signing root") 93 } 94 if !sig.Verify(publicKey, root[:]) { 95 return ErrSigFailedToVerify 96 } 97 return nil 98 } 99 100 // VerifyBlockSigningRoot verifies the signing root of a block given it's public key, signature and domain. 101 func VerifyBlockSigningRoot(pub, signature, domain []byte, rootFunc func() ([32]byte, error)) error { 102 set, err := BlockSignatureSet(pub, signature, domain, rootFunc) 103 if err != nil { 104 return err 105 } 106 // We assume only one signature set is returned here. 107 sig := set.Signatures[0] 108 publicKey := set.PublicKeys[0] 109 root := set.Messages[0] 110 111 rSig, err := bls.SignatureFromBytes(sig) 112 if err != nil { 113 return err 114 } 115 if !rSig.Verify(publicKey, root[:]) { 116 return ErrSigFailedToVerify 117 } 118 return nil 119 } 120 121 // BlockSignatureSet retrieves the relevant signature, message and pubkey data from a block and collating it 122 // into a signature set object. 123 func BlockSignatureSet(pub, signature, domain []byte, rootFunc func() ([32]byte, error)) (*bls.SignatureSet, error) { 124 publicKey, err := bls.PublicKeyFromBytes(pub) 125 if err != nil { 126 return nil, errors.Wrap(err, "could not convert bytes to public key") 127 } 128 // utilize custom block hashing function 129 root, err := signingData(rootFunc, domain) 130 if err != nil { 131 return nil, errors.Wrap(err, "could not compute signing root") 132 } 133 return &bls.SignatureSet{ 134 Signatures: [][]byte{signature}, 135 PublicKeys: []bls.PublicKey{publicKey}, 136 Messages: [][32]byte{root}, 137 }, nil 138 } 139 140 // VerifyBlockHeaderSigningRoot verifies the signing root of a block header given it's public key, signature and domain. 141 func VerifyBlockHeaderSigningRoot(blkHdr *ethpb.BeaconBlockHeader, pub, signature, domain []byte) error { 142 publicKey, err := bls.PublicKeyFromBytes(pub) 143 if err != nil { 144 return errors.Wrap(err, "could not convert bytes to public key") 145 } 146 sig, err := bls.SignatureFromBytes(signature) 147 if err != nil { 148 return errors.Wrap(err, "could not convert bytes to signature") 149 } 150 root, err := signingData(blkHdr.HashTreeRoot, domain) 151 if err != nil { 152 return errors.Wrap(err, "could not compute signing root") 153 } 154 if !sig.Verify(publicKey, root[:]) { 155 return ErrSigFailedToVerify 156 } 157 return nil 158 } 159 160 // ComputeDomain returns the domain version for BLS private key to sign and verify with a zeroed 4-byte 161 // array as the fork version. 162 // 163 // def compute_domain(domain_type: DomainType, fork_version: Version=None, genesis_validators_root: Root=None) -> Domain: 164 // """ 165 // Return the domain for the ``domain_type`` and ``fork_version``. 166 // """ 167 // if fork_version is None: 168 // fork_version = GENESIS_FORK_VERSION 169 // if genesis_validators_root is None: 170 // genesis_validators_root = Root() # all bytes zero by default 171 // fork_data_root = compute_fork_data_root(fork_version, genesis_validators_root) 172 // return Domain(domain_type + fork_data_root[:28]) 173 func ComputeDomain(domainType [DomainByteLength]byte, forkVersion, genesisValidatorsRoot []byte) ([]byte, error) { 174 if forkVersion == nil { 175 forkVersion = params.BeaconConfig().GenesisForkVersion 176 } 177 if genesisValidatorsRoot == nil { 178 genesisValidatorsRoot = params.BeaconConfig().ZeroHash[:] 179 } 180 forkBytes := [ForkVersionByteLength]byte{} 181 copy(forkBytes[:], forkVersion) 182 183 forkDataRoot, err := computeForkDataRoot(forkBytes[:], genesisValidatorsRoot) 184 if err != nil { 185 return nil, err 186 } 187 188 return domain(domainType, forkDataRoot[:]), nil 189 } 190 191 // This returns the bls domain given by the domain type and fork data root. 192 func domain(domainType [DomainByteLength]byte, forkDataRoot []byte) []byte { 193 var b []byte 194 b = append(b, domainType[:4]...) 195 b = append(b, forkDataRoot[:28]...) 196 return b 197 } 198 199 // this returns the 32byte fork data root for the ``current_version`` and ``genesis_validators_root``. 200 // This is used primarily in signature domains to avoid collisions across forks/chains. 201 // 202 // Spec pseudocode definition: 203 // def compute_fork_data_root(current_version: Version, genesis_validators_root: Root) -> Root: 204 // """ 205 // Return the 32-byte fork data root for the ``current_version`` and ``genesis_validators_root``. 206 // This is used primarily in signature domains to avoid collisions across forks/chains. 207 // """ 208 // return hash_tree_root(ForkData( 209 // current_version=current_version, 210 // genesis_validators_root=genesis_validators_root, 211 // )) 212 func computeForkDataRoot(version, root []byte) ([32]byte, error) { 213 r, err := (&pb.ForkData{ 214 CurrentVersion: version, 215 GenesisValidatorsRoot: root, 216 }).HashTreeRoot() 217 if err != nil { 218 return [32]byte{}, err 219 } 220 return r, nil 221 } 222 223 // ComputeForkDigest returns the fork for the current version and genesis validator root 224 // 225 // Spec pseudocode definition: 226 // def compute_fork_digest(current_version: Version, genesis_validators_root: Root) -> ForkDigest: 227 // """ 228 // Return the 4-byte fork digest for the ``current_version`` and ``genesis_validators_root``. 229 // This is a digest primarily used for domain separation on the p2p layer. 230 // 4-bytes suffices for practical separation of forks/chains. 231 // """ 232 // return ForkDigest(compute_fork_data_root(current_version, genesis_validators_root)[:4]) 233 func ComputeForkDigest(version, genesisValidatorsRoot []byte) ([4]byte, error) { 234 dataRoot, err := computeForkDataRoot(version, genesisValidatorsRoot) 235 if err != nil { 236 return [4]byte{}, err 237 } 238 return bytesutil.ToBytes4(dataRoot[:]), nil 239 }