func (t *Transaction) validSignatures(currentHeight BlockHeight) error {
	err := t.validCoveredFields()
	if err != nil {
		return err
	}
	sigMap := make(map[crypto.Hash]*inputSignatures)
	for i, input := range t.SiacoinInputs {
		id := crypto.Hash(input.ParentID)
		_, exists := sigMap[id]
		if exists {
			return ErrDoubleSpend
		}
		sigMap[id] = &inputSignatures{
			remainingSignatures: input.UnlockConditions.SignaturesRequired,
			possibleKeys:        input.UnlockConditions.PublicKeys,
			usedKeys:            make(map[uint64]struct{}),
			index:               i,
		}
	}
	for i, revision := range t.FileContractRevisions {
		id := crypto.Hash(revision.ParentID)
		_, exists := sigMap[id]
		if exists {
			return ErrDoubleSpend
		}
		sigMap[id] = &inputSignatures{
			remainingSignatures: revision.UnlockConditions.SignaturesRequired,
			possibleKeys:        revision.UnlockConditions.PublicKeys,
			usedKeys:            make(map[uint64]struct{}),
			index:               i,
		}
	}
	for i, input := range t.SiafundInputs {
		id := crypto.Hash(input.ParentID)
		_, exists := sigMap[id]
		if exists {
			return ErrDoubleSpend
		}
		sigMap[id] = &inputSignatures{
			remainingSignatures: input.UnlockConditions.SignaturesRequired,
			possibleKeys:        input.UnlockConditions.PublicKeys,
			usedKeys:            make(map[uint64]struct{}),
			index:               i,
		}
	}
	for i, sig := range t.TransactionSignatures {
		inSig, exists := sigMap[crypto.Hash(sig.ParentID)]
		if !exists || inSig.remainingSignatures == 0 {
			return ErrFrivolousSignature
		}
		_, exists = inSig.usedKeys[sig.PublicKeyIndex]
		if exists {
			return ErrPublicKeyOveruse
		}
		if sig.PublicKeyIndex >= uint64(len(inSig.possibleKeys)) {
			return ErrInvalidPubKeyIndex
		}
		if sig.Timelock > currentHeight {
			return ErrPrematureSignature
		}
		publicKey := inSig.possibleKeys[sig.PublicKeyIndex]
		switch publicKey.Algorithm {
		case SignatureEntropy:
			return ErrEntropyKey
		case SignatureEd25519:
			var edPK crypto.PublicKey
			err := encoding.Unmarshal([]byte(publicKey.Key), &edPK)
			if err != nil {
				return err
			}
			var edSig [crypto.SignatureSize]byte
			err = encoding.Unmarshal([]byte(sig.Signature), &edSig)
			if err != nil {
				return err
			}
			cryptoSig := crypto.Signature(edSig)
			sigHash := t.SigHash(i)
			err = crypto.VerifyHash(sigHash, edPK, cryptoSig)
			if err != nil {
				return err
			}
		default:
		}
		inSig.usedKeys[sig.PublicKeyIndex] = struct{}{}
		inSig.remainingSignatures--
	}
	for _, reqSigs := range sigMap {
		if reqSigs.remainingSignatures != 0 {
			return ErrMissingSignatures
		}
	}
	return nil
}
validSignatures checks the validaty of all signatures in a transaction.
package types
import (
	"bytes"
	"errors"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
)
var (
	ErrEntropyKey = errors.New("transaction tries to sign an entropy public key")
	ErrFrivolousSignature = errors.New("transaction contains a frivolous signature")
	ErrInvalidPubKeyIndex = errors.New("transaction contains a signature that points to a nonexistent public key")
	ErrInvalidUnlockHashChecksum = errors.New("provided unlock hash has an invalid checksum")
	ErrMissingSignatures = errors.New("transaction has inputs with missing signatures")
	ErrPrematureSignature = errors.New("timelock on signature has not expired")
	ErrPublicKeyOveruse = errors.New("public key was used multiple times while signing transaction")
	ErrSortedUniqueViolation = errors.New("sorted unique violation")
	ErrUnlockHashWrongLen = errors.New("marshalled unlock hash is the wrong length")
	ErrWholeTransactionViolation = errors.New("covered fields violation")
	FullCoveredFields = CoveredFields{WholeTransaction: true}
	SignatureEd25519 = Specifier{'e', 'd', '2', '5', '5', '1', '9'}
	SignatureEntropy = Specifier{'e', 'n', 't', 'r', 'o', 'p', 'y'}
)
type (
	CoveredFields struct {
		WholeTransaction      bool     `json:"wholetransaction"`
		SiacoinInputs         []uint64 `json:"siacoininputs"`
		SiacoinOutputs        []uint64 `json:"siacoinoutputs"`
		FileContracts         []uint64 `json:"filecontracts"`
		FileContractRevisions []uint64 `json:"filecontractrevisions"`
		StorageProofs         []uint64 `json:"storageproofs"`
		SiafundInputs         []uint64 `json:"siafundinputs"`
		SiafundOutputs        []uint64 `json:"siafundoutputs"`
		MinerFees             []uint64 `json:"minerfees"`
		ArbitraryData         []uint64 `json:"arbitrarydata"`
		TransactionSignatures []uint64 `json:"transactionsignatures"`
	}
	SiaPublicKey struct {
		Algorithm Specifier `json:"algorithm"`
		Key       []byte    `json:"key"`
	}
	TransactionSignature struct {
		ParentID       crypto.Hash   `json:"parentid"`
		PublicKeyIndex uint64        `json:"publickeyindex"`
		Timelock       BlockHeight   `json:"timelock"`
		CoveredFields  CoveredFields `json:"coveredfields"`
		Signature      []byte        `json:"signature"`
	}
	UnlockConditions struct {
		Timelock           BlockHeight    `json:"timelock"`
		PublicKeys         []SiaPublicKey `json:"publickeys"`
		SignaturesRequired uint64         `json:"signaturesrequired"`
	}
	inputSignatures struct {
		remainingSignatures uint64
		possibleKeys        []SiaPublicKey
		usedKeys            map[uint64]struct{}
		index               int
	}
)
func Ed25519PublicKey(pk crypto.PublicKey) SiaPublicKey {
	return SiaPublicKey{
		Algorithm: SignatureEd25519,
		Key:       pk[:],
	}
}
func (uc UnlockConditions) UnlockHash() UnlockHash {
	var buf bytes.Buffer
	e := encoding.NewEncoder(&buf)
	tree := crypto.NewTree()
	e.WriteUint64(uint64(uc.Timelock))
	tree.Push(buf.Bytes())
	buf.Reset()
	for _, key := range uc.PublicKeys {
		key.MarshalSia(e)
		tree.Push(buf.Bytes())
		buf.Reset()
	}
	e.WriteUint64(uc.SignaturesRequired)
	tree.Push(buf.Bytes())
	return UnlockHash(tree.Root())
}
func (t Transaction) SigHash(i int) (hash crypto.Hash) {
	cf := t.TransactionSignatures[i].CoveredFields
	h := crypto.NewHash()
	if cf.WholeTransaction {
		t.marshalSiaNoSignatures(h)
		h.Write(t.TransactionSignatures[i].ParentID[:])
		encoding.WriteUint64(h, t.TransactionSignatures[i].PublicKeyIndex)
		encoding.WriteUint64(h, uint64(t.TransactionSignatures[i].Timelock))
	} else {
		for _, input := range cf.SiacoinInputs {
			t.SiacoinInputs[input].MarshalSia(h)
		}
		for _, output := range cf.SiacoinOutputs {
			t.SiacoinOutputs[output].MarshalSia(h)
		}
		for _, contract := range cf.FileContracts {
			t.FileContracts[contract].MarshalSia(h)
		}
		for _, revision := range cf.FileContractRevisions {
			t.FileContractRevisions[revision].MarshalSia(h)
		}
		for _, storageProof := range cf.StorageProofs {
			t.StorageProofs[storageProof].MarshalSia(h)
		}
		for _, siafundInput := range cf.SiafundInputs {
			t.SiafundInputs[siafundInput].MarshalSia(h)
		}
		for _, siafundOutput := range cf.SiafundOutputs {
			t.SiafundOutputs[siafundOutput].MarshalSia(h)
		}
		for _, minerFee := range cf.MinerFees {
			t.MinerFees[minerFee].MarshalSia(h)
		}
		for _, arbData := range cf.ArbitraryData {
			encoding.WritePrefixedBytes(h, t.ArbitraryData[arbData])
		}
	}
	for _, sig := range cf.TransactionSignatures {
		t.TransactionSignatures[sig].MarshalSia(h)
	}
	h.Sum(hash[:0])
	return
}
func sortedUnique(elems []uint64, max int) bool {
	if len(elems) == 0 {
		return true
	}
	biggest := elems[0]
	for _, elem := range elems[1:] {
		if elem <= biggest {
			return false
		}
		biggest = elem
	}
	if biggest >= uint64(max) {
		return false
	}
	return true
}
func (t Transaction) validCoveredFields() error {
	for _, sig := range t.TransactionSignatures {
		cf := sig.CoveredFields
		fieldMaxs := []struct {
			field []uint64
			max   int
		}{
			{cf.SiacoinInputs, len(t.SiacoinInputs)},
			{cf.SiacoinOutputs, len(t.SiacoinOutputs)},
			{cf.FileContracts, len(t.FileContracts)},
			{cf.FileContractRevisions, len(t.FileContractRevisions)},
			{cf.StorageProofs, len(t.StorageProofs)},
			{cf.SiafundInputs, len(t.SiafundInputs)},
			{cf.SiafundOutputs, len(t.SiafundOutputs)},
			{cf.MinerFees, len(t.MinerFees)},
			{cf.ArbitraryData, len(t.ArbitraryData)},
			{cf.TransactionSignatures, len(t.TransactionSignatures)},
		}
		if cf.WholeTransaction {
			for _, fieldMax := range fieldMaxs[:len(fieldMaxs)-1] {
				if len(fieldMax.field) != 0 {
					return ErrWholeTransactionViolation
				}
			}
		}
		for _, fieldMax := range fieldMaxs {
			if !sortedUnique(fieldMax.field, fieldMax.max) {
				return ErrSortedUniqueViolation
			}
		}
	}
	return nil
}