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