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