gitlab.com/SiaPrime/SiaPrime@v1.4.1/types/signatures.go (about)

     1  package types
     2  
     3  // signatures.go contains all of the types and functions related to creating
     4  // and verifying transaction signatures. There are a lot of rules surrounding
     5  // the correct use of signatures. Signatures can cover part or all of a
     6  // transaction, can be multiple different algorithms, and must satify a field
     7  // called 'UnlockConditions'.
     8  
     9  import (
    10  	"bytes"
    11  	"errors"
    12  
    13  	"gitlab.com/SiaPrime/SiaPrime/crypto"
    14  	"gitlab.com/SiaPrime/SiaPrime/encoding"
    15  )
    16  
    17  var (
    18  	// ErrEntropyKey is the error when a transaction tries to sign an entropy
    19  	// public key
    20  	ErrEntropyKey = errors.New("transaction tries to sign an entropy public key")
    21  	// ErrFrivolousSignature is the error when a transaction contains a frivolous
    22  	// signature
    23  	ErrFrivolousSignature = errors.New("transaction contains a frivolous signature")
    24  	// ErrInvalidPubKeyIndex is the error when a transaction contains a signature
    25  	// that points to a nonexistent public key
    26  	ErrInvalidPubKeyIndex = errors.New("transaction contains a signature that points to a nonexistent public key")
    27  	// ErrInvalidUnlockHashChecksum is the error when the provided unlock hash has
    28  	// an invalid checksum
    29  	ErrInvalidUnlockHashChecksum = errors.New("provided unlock hash has an invalid checksum")
    30  	// ErrMissingSignatures is the error when a transaction has inputs with missing
    31  	// signatures
    32  	ErrMissingSignatures = errors.New("transaction has inputs with missing signatures")
    33  	// ErrPrematureSignature is the error when the timelock on signature has not
    34  	// expired
    35  	ErrPrematureSignature = errors.New("timelock on signature has not expired")
    36  	// ErrPublicKeyOveruse is the error when public key was used multiple times while
    37  	// signing transaction
    38  	ErrPublicKeyOveruse = errors.New("public key was used multiple times while signing transaction")
    39  	// ErrSortedUniqueViolation is the error when a sorted unique violation occurs
    40  	ErrSortedUniqueViolation = errors.New("sorted unique violation")
    41  	// ErrUnlockHashWrongLen is the error when a marshalled unlock hash is the wrong
    42  	// length
    43  	ErrUnlockHashWrongLen = errors.New("marshalled unlock hash is the wrong length")
    44  	// ErrWholeTransactionViolation is the error when there's a covered fields violation
    45  	ErrWholeTransactionViolation = errors.New("covered fields violation")
    46  
    47  	// FullCoveredFields is a covered fileds object where the
    48  	// 'WholeTransaction' field has been set to true. The primary purpose of
    49  	// this variable is syntactic sugar.
    50  	FullCoveredFields = CoveredFields{WholeTransaction: true}
    51  
    52  	// These Specifiers enumerate the types of signatures that are recognized
    53  	// by this implementation. If a signature's type is unrecognized, the
    54  	// signature is treated as valid. Signatures using the special "entropy"
    55  	// type are always treated as invalid; see Consensus.md for more details.
    56  
    57  	// SignatureEd25519 is a specifier for Ed22519
    58  	SignatureEd25519 = Specifier{'e', 'd', '2', '5', '5', '1', '9'}
    59  	// SignatureEntropy is a specifier for entropy
    60  	SignatureEntropy = Specifier{'e', 'n', 't', 'r', 'o', 'p', 'y'}
    61  )
    62  
    63  type (
    64  	// CoveredFields indicates which fields in a transaction have been covered by
    65  	// the signature. (Note that the signature does not sign the fields
    66  	// themselves, but rather their combined hash; see SigHash.) Each slice
    67  	// corresponds to a slice in the Transaction type, indicating which indices of
    68  	// the slice have been signed. The indices must be valid, i.e. within the
    69  	// bounds of the slice. In addition, they must be sorted and unique.
    70  	//
    71  	// As a convenience, a signature of the entire transaction can be indicated by
    72  	// the 'WholeTransaction' field. If 'WholeTransaction' == true, all other
    73  	// fields must be empty (except for the Signatures field, since a signature
    74  	// cannot sign itself).
    75  	CoveredFields struct {
    76  		WholeTransaction      bool     `json:"wholetransaction"`
    77  		SiacoinInputs         []uint64 `json:"siacoininputs"`
    78  		SiacoinOutputs        []uint64 `json:"siacoinoutputs"`
    79  		FileContracts         []uint64 `json:"filecontracts"`
    80  		FileContractRevisions []uint64 `json:"filecontractrevisions"`
    81  		StorageProofs         []uint64 `json:"storageproofs"`
    82  		SiafundInputs         []uint64 `json:"siafundinputs"`
    83  		SiafundOutputs        []uint64 `json:"siafundoutputs"`
    84  		MinerFees             []uint64 `json:"minerfees"`
    85  		ArbitraryData         []uint64 `json:"arbitrarydata"`
    86  		TransactionSignatures []uint64 `json:"transactionsignatures"`
    87  	}
    88  
    89  	// A SiaPublicKey is a public key prefixed by a Specifier. The Specifier
    90  	// indicates the algorithm used for signing and verification. Unrecognized
    91  	// algorithms will always verify, which allows new algorithms to be added to
    92  	// the protocol via a soft-fork.
    93  	SiaPublicKey struct {
    94  		Algorithm Specifier `json:"algorithm"`
    95  		Key       []byte    `json:"key"`
    96  	}
    97  
    98  	// A TransactionSignature is a signature that is included in the transaction.
    99  	// The signature should correspond to a public key in one of the
   100  	// UnlockConditions of the transaction. This key is specified first by
   101  	// 'ParentID', which specifies the UnlockConditions, and then
   102  	// 'PublicKeyIndex', which indicates the key in the UnlockConditions. There
   103  	// are three types that use UnlockConditions: SiacoinInputs, SiafundInputs,
   104  	// and FileContractTerminations. Each of these types also references a
   105  	// ParentID, and this is the hash that 'ParentID' must match. The 'Timelock'
   106  	// prevents the signature from being used until a certain height.
   107  	// 'CoveredFields' indicates which parts of the transaction are being signed;
   108  	// see CoveredFields.
   109  	TransactionSignature struct {
   110  		ParentID       crypto.Hash   `json:"parentid"`
   111  		PublicKeyIndex uint64        `json:"publickeyindex"`
   112  		Timelock       BlockHeight   `json:"timelock"`
   113  		CoveredFields  CoveredFields `json:"coveredfields"`
   114  		Signature      []byte        `json:"signature"`
   115  	}
   116  
   117  	// UnlockConditions are a set of conditions which must be met to execute
   118  	// certain actions, such as spending a SiacoinOutput or terminating a
   119  	// FileContract.
   120  	//
   121  	// The simplest requirement is that the block containing the UnlockConditions
   122  	// must have a height >= 'Timelock'.
   123  	//
   124  	// 'PublicKeys' specifies the set of keys that can be used to satisfy the
   125  	// UnlockConditions; of these, at least 'SignaturesRequired' unique keys must sign
   126  	// the transaction. The keys that do not need to use the same cryptographic
   127  	// algorithm.
   128  	//
   129  	// If 'SignaturesRequired' == 0, the UnlockConditions are effectively "anyone can
   130  	// unlock." If 'SignaturesRequired' > len('PublicKeys'), then the UnlockConditions
   131  	// cannot be fulfilled under any circumstances.
   132  	UnlockConditions struct {
   133  		Timelock           BlockHeight    `json:"timelock"`
   134  		PublicKeys         []SiaPublicKey `json:"publickeys"`
   135  		SignaturesRequired uint64         `json:"signaturesrequired"`
   136  	}
   137  
   138  	// Each input has a list of public keys and a required number of signatures.
   139  	// inputSignatures keeps track of which public keys have been used and how many
   140  	// more signatures are needed.
   141  	inputSignatures struct {
   142  		remainingSignatures uint64
   143  		possibleKeys        []SiaPublicKey
   144  		usedKeys            map[uint64]struct{}
   145  		index               int
   146  	}
   147  )
   148  
   149  // Ed25519PublicKey returns pk as a SiaPublicKey, denoting its algorithm as
   150  // Ed25519.
   151  func Ed25519PublicKey(pk crypto.PublicKey) SiaPublicKey {
   152  	return SiaPublicKey{
   153  		Algorithm: SignatureEd25519,
   154  		Key:       pk[:],
   155  	}
   156  }
   157  
   158  // UnlockHash calculates the root hash of a Merkle tree of the
   159  // UnlockConditions object. The leaves of this tree are formed by taking the
   160  // hash of the timelock, the hash of the public keys (one leaf each), and the
   161  // hash of the number of signatures. The keys are put in the middle because
   162  // Timelock and SignaturesRequired are both low entropy fields; they can be
   163  // protected by having random public keys next to them.
   164  func (uc UnlockConditions) UnlockHash() UnlockHash {
   165  	var buf bytes.Buffer
   166  	e := encoding.NewEncoder(&buf)
   167  	tree := crypto.NewTree()
   168  	e.WriteUint64(uint64(uc.Timelock))
   169  	tree.Push(buf.Bytes())
   170  	buf.Reset()
   171  	for _, key := range uc.PublicKeys {
   172  		key.MarshalSia(e)
   173  		tree.Push(buf.Bytes())
   174  		buf.Reset()
   175  	}
   176  	e.WriteUint64(uc.SignaturesRequired)
   177  	tree.Push(buf.Bytes())
   178  	return UnlockHash(tree.Root())
   179  }
   180  
   181  // SigHash returns the hash of the fields in a transaction covered by a given
   182  // signature. See CoveredFields for more details.
   183  func (t Transaction) SigHash(i int, height BlockHeight) (hash crypto.Hash) {
   184  	sig := t.TransactionSignatures[i]
   185  	if sig.CoveredFields.WholeTransaction {
   186  		return t.wholeSigHash(sig, height)
   187  	}
   188  	return t.partialSigHash(sig.CoveredFields, height)
   189  }
   190  
   191  // wholeSigHash calculates the hash for a signature that specifies
   192  // WholeTransaction = true.
   193  func (t *Transaction) wholeSigHash(sig TransactionSignature, height BlockHeight) (hash crypto.Hash) {
   194  	h := crypto.NewHash()
   195  	e := encoding.NewEncoder(h)
   196  
   197  	e.WriteInt(len((t.SiacoinInputs)))
   198  	for i := range t.SiacoinInputs {
   199  		if height >= ASICHardforkHeight {
   200  			e.Write(ASICHardforkReplayProtectionPrefix)
   201  		}
   202  		t.SiacoinInputs[i].MarshalSia(e)
   203  	}
   204  	e.WriteInt(len((t.SiacoinOutputs)))
   205  	for i := range t.SiacoinOutputs {
   206  		t.SiacoinOutputs[i].MarshalSia(e)
   207  	}
   208  	e.WriteInt(len((t.FileContracts)))
   209  	for i := range t.FileContracts {
   210  		t.FileContracts[i].MarshalSia(e)
   211  	}
   212  	e.WriteInt(len((t.FileContractRevisions)))
   213  	for i := range t.FileContractRevisions {
   214  		t.FileContractRevisions[i].MarshalSia(e)
   215  	}
   216  	e.WriteInt(len((t.StorageProofs)))
   217  	for i := range t.StorageProofs {
   218  		t.StorageProofs[i].MarshalSia(e)
   219  	}
   220  	e.WriteInt(len((t.SiafundInputs)))
   221  	for i := range t.SiafundInputs {
   222  		if height >= ASICHardforkHeight {
   223  			e.Write(ASICHardforkReplayProtectionPrefix)
   224  		}
   225  		t.SiafundInputs[i].MarshalSia(e)
   226  	}
   227  	e.WriteInt(len((t.SiafundOutputs)))
   228  	for i := range t.SiafundOutputs {
   229  		t.SiafundOutputs[i].MarshalSia(e)
   230  	}
   231  	e.WriteInt(len((t.MinerFees)))
   232  	for i := range t.MinerFees {
   233  		t.MinerFees[i].MarshalSia(e)
   234  	}
   235  	e.WriteInt(len((t.ArbitraryData)))
   236  	for i := range t.ArbitraryData {
   237  		e.WritePrefixedBytes(t.ArbitraryData[i])
   238  	}
   239  
   240  	h.Write(sig.ParentID[:])
   241  	encoding.WriteUint64(h, sig.PublicKeyIndex)
   242  	encoding.WriteUint64(h, uint64(sig.Timelock))
   243  
   244  	for _, i := range sig.CoveredFields.TransactionSignatures {
   245  		t.TransactionSignatures[i].MarshalSia(h)
   246  	}
   247  
   248  	h.Sum(hash[:0])
   249  	return
   250  }
   251  
   252  // partialSigHash calculates the hash of the fields of the transaction
   253  // specified in cf.
   254  func (t *Transaction) partialSigHash(cf CoveredFields, height BlockHeight) (hash crypto.Hash) {
   255  	h := crypto.NewHash()
   256  
   257  	for _, input := range cf.SiacoinInputs {
   258  		if height >= ASICHardforkHeight {
   259  			h.Write(ASICHardforkReplayProtectionPrefix)
   260  		}
   261  		t.SiacoinInputs[input].MarshalSia(h)
   262  	}
   263  	for _, output := range cf.SiacoinOutputs {
   264  		t.SiacoinOutputs[output].MarshalSia(h)
   265  	}
   266  	for _, contract := range cf.FileContracts {
   267  		t.FileContracts[contract].MarshalSia(h)
   268  	}
   269  	for _, revision := range cf.FileContractRevisions {
   270  		t.FileContractRevisions[revision].MarshalSia(h)
   271  	}
   272  	for _, storageProof := range cf.StorageProofs {
   273  		t.StorageProofs[storageProof].MarshalSia(h)
   274  	}
   275  	for _, siafundInput := range cf.SiafundInputs {
   276  		if height >= ASICHardforkHeight {
   277  			h.Write(ASICHardforkReplayProtectionPrefix)
   278  		}
   279  		t.SiafundInputs[siafundInput].MarshalSia(h)
   280  	}
   281  	for _, siafundOutput := range cf.SiafundOutputs {
   282  		t.SiafundOutputs[siafundOutput].MarshalSia(h)
   283  	}
   284  	for _, minerFee := range cf.MinerFees {
   285  		t.MinerFees[minerFee].MarshalSia(h)
   286  	}
   287  	for _, arbData := range cf.ArbitraryData {
   288  		encoding.WritePrefixedBytes(h, t.ArbitraryData[arbData])
   289  	}
   290  	for _, sig := range cf.TransactionSignatures {
   291  		t.TransactionSignatures[sig].MarshalSia(h)
   292  	}
   293  
   294  	h.Sum(hash[:0])
   295  	return
   296  }
   297  
   298  // sortedUnique checks that 'elems' is sorted, contains no repeats, and that no
   299  // element is larger than or equal to 'max'.
   300  func sortedUnique(elems []uint64, max int) bool {
   301  	if len(elems) == 0 {
   302  		return true
   303  	}
   304  
   305  	biggest := elems[0]
   306  	for _, elem := range elems[1:] {
   307  		if elem <= biggest {
   308  			return false
   309  		}
   310  		biggest = elem
   311  	}
   312  	if biggest >= uint64(max) {
   313  		return false
   314  	}
   315  	return true
   316  }
   317  
   318  // validCoveredFields makes sure that all covered fields objects in the
   319  // signatures follow the rules. This means that if 'WholeTransaction' is set to
   320  // true, all fields except for 'Signatures' must be empty. All fields must be
   321  // sorted numerically, and there can be no repeats.
   322  func (t Transaction) validCoveredFields() error {
   323  	for _, sig := range t.TransactionSignatures {
   324  		// convenience variables
   325  		cf := sig.CoveredFields
   326  		fieldMaxs := []struct {
   327  			field []uint64
   328  			max   int
   329  		}{
   330  			{cf.SiacoinInputs, len(t.SiacoinInputs)},
   331  			{cf.SiacoinOutputs, len(t.SiacoinOutputs)},
   332  			{cf.FileContracts, len(t.FileContracts)},
   333  			{cf.FileContractRevisions, len(t.FileContractRevisions)},
   334  			{cf.StorageProofs, len(t.StorageProofs)},
   335  			{cf.SiafundInputs, len(t.SiafundInputs)},
   336  			{cf.SiafundOutputs, len(t.SiafundOutputs)},
   337  			{cf.MinerFees, len(t.MinerFees)},
   338  			{cf.ArbitraryData, len(t.ArbitraryData)},
   339  			{cf.TransactionSignatures, len(t.TransactionSignatures)},
   340  		}
   341  
   342  		if cf.WholeTransaction {
   343  			// If WholeTransaction is set, all fields must be
   344  			// empty, except TransactionSignatures.
   345  			for _, fieldMax := range fieldMaxs[:len(fieldMaxs)-1] {
   346  				if len(fieldMax.field) != 0 {
   347  					return ErrWholeTransactionViolation
   348  				}
   349  			}
   350  		} else {
   351  			// If WholeTransaction is not set, at least one field
   352  			// must be non-empty.
   353  			allEmpty := true
   354  			for _, fieldMax := range fieldMaxs {
   355  				if len(fieldMax.field) != 0 {
   356  					allEmpty = false
   357  					break
   358  				}
   359  			}
   360  			if allEmpty {
   361  				return ErrWholeTransactionViolation
   362  			}
   363  		}
   364  
   365  		// Check that all fields are sorted, and without repeat values, and
   366  		// that all elements point to objects that exists within the
   367  		// transaction. If there are repeats, it means a transaction is trying
   368  		// to sign the same object twice. This is unncecessary, and opens up a
   369  		// DoS vector where the transaction asks the verifier to verify many GB
   370  		// of data.
   371  		for _, fieldMax := range fieldMaxs {
   372  			if !sortedUnique(fieldMax.field, fieldMax.max) {
   373  				return ErrSortedUniqueViolation
   374  			}
   375  		}
   376  	}
   377  
   378  	return nil
   379  }
   380  
   381  // validSignatures checks the validaty of all signatures in a transaction.
   382  func (t *Transaction) validSignatures(currentHeight BlockHeight) error {
   383  	// Check that all covered fields objects follow the rules.
   384  	err := t.validCoveredFields()
   385  	if err != nil {
   386  		return err
   387  	}
   388  
   389  	// Create the inputSignatures object for each input.
   390  	sigMap := make(map[crypto.Hash]*inputSignatures)
   391  	for i, input := range t.SiacoinInputs {
   392  		id := crypto.Hash(input.ParentID)
   393  		_, exists := sigMap[id]
   394  		if exists {
   395  			return ErrDoubleSpend
   396  		}
   397  
   398  		sigMap[id] = &inputSignatures{
   399  			remainingSignatures: input.UnlockConditions.SignaturesRequired,
   400  			possibleKeys:        input.UnlockConditions.PublicKeys,
   401  			usedKeys:            make(map[uint64]struct{}),
   402  			index:               i,
   403  		}
   404  	}
   405  	for i, revision := range t.FileContractRevisions {
   406  		id := crypto.Hash(revision.ParentID)
   407  		_, exists := sigMap[id]
   408  		if exists {
   409  			return ErrDoubleSpend
   410  		}
   411  
   412  		sigMap[id] = &inputSignatures{
   413  			remainingSignatures: revision.UnlockConditions.SignaturesRequired,
   414  			possibleKeys:        revision.UnlockConditions.PublicKeys,
   415  			usedKeys:            make(map[uint64]struct{}),
   416  			index:               i,
   417  		}
   418  	}
   419  	for i, input := range t.SiafundInputs {
   420  		id := crypto.Hash(input.ParentID)
   421  		_, exists := sigMap[id]
   422  		if exists {
   423  			return ErrDoubleSpend
   424  		}
   425  
   426  		sigMap[id] = &inputSignatures{
   427  			remainingSignatures: input.UnlockConditions.SignaturesRequired,
   428  			possibleKeys:        input.UnlockConditions.PublicKeys,
   429  			usedKeys:            make(map[uint64]struct{}),
   430  			index:               i,
   431  		}
   432  	}
   433  
   434  	// Check all of the signatures for validity.
   435  	for i, sig := range t.TransactionSignatures {
   436  		// Check that sig corresponds to an entry in sigMap.
   437  		inSig, exists := sigMap[crypto.Hash(sig.ParentID)]
   438  		if !exists || inSig.remainingSignatures == 0 {
   439  			return ErrFrivolousSignature
   440  		}
   441  		// Check that sig's key hasn't already been used.
   442  		_, exists = inSig.usedKeys[sig.PublicKeyIndex]
   443  		if exists {
   444  			return ErrPublicKeyOveruse
   445  		}
   446  		// Check that the public key index refers to an existing public key.
   447  		if sig.PublicKeyIndex >= uint64(len(inSig.possibleKeys)) {
   448  			return ErrInvalidPubKeyIndex
   449  		}
   450  		// Check that the timelock has expired.
   451  		if sig.Timelock > currentHeight {
   452  			return ErrPrematureSignature
   453  		}
   454  
   455  		// Check that the signature verifies. Multiple signature schemes are
   456  		// supported.
   457  		publicKey := inSig.possibleKeys[sig.PublicKeyIndex]
   458  		switch publicKey.Algorithm {
   459  		case SignatureEntropy:
   460  			// Entropy cannot ever be used to sign a transaction.
   461  			return ErrEntropyKey
   462  
   463  		case SignatureEd25519:
   464  			// Decode the public key and signature.
   465  			var edPK crypto.PublicKey
   466  			copy(edPK[:], publicKey.Key)
   467  			var edSig crypto.Signature
   468  			copy(edSig[:], sig.Signature)
   469  
   470  			sigHash := t.SigHash(i, currentHeight)
   471  			err = crypto.VerifyHash(sigHash, edPK, edSig)
   472  			if err != nil {
   473  				return err
   474  			}
   475  
   476  		default:
   477  			// If the identifier is not recognized, assume that the signature
   478  			// is valid. This allows more signature types to be added via soft
   479  			// forking.
   480  		}
   481  
   482  		inSig.usedKeys[sig.PublicKeyIndex] = struct{}{}
   483  		inSig.remainingSignatures--
   484  	}
   485  
   486  	// Check that all inputs have been sufficiently signed.
   487  	for _, reqSigs := range sigMap {
   488  		if reqSigs.remainingSignatures != 0 {
   489  			return ErrMissingSignatures
   490  		}
   491  	}
   492  
   493  	return nil
   494  }