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  }