You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: signature_program.go
    path of file: ./repos/bytom/blockchain/txbuilder
    
    the code of the file until where you have to start completion: package txbuilder

import (
	"github.com/bytom/bytom/protocol/vm"
	"github.com/bytom/bytom/protocol/vm/vmutil"
)

// Signature programs constrain how the signed inputs of a transaction
// in a template may be used, especially if the transaction is not yet
// complete.
//
// For example, suppose Alice wants to send Bob 80 EUR but only if Bob
// pays her 100 USD, and only if payment is made before next
// Tuesday. Alice constructs a partial transaction that includes her
// 80 EUR as one input, a payment to
    
func buildSigProgram(tpl *Template, index uint32) ([]byte, error) {
	if !tpl.AllowAdditional {
		h := tpl.Hash(index)
		builder := vmutil.NewBuilder()
		builder.AddData(h.Bytes())
		builder.AddOp(vm.OP_TXSIGHASH).AddOp(vm.OP_EQUAL)

		return builder.Build()
	}
	constraints := make([]constraint, 0, 3+len(tpl.Transaction.Outputs))
	id := tpl.Transaction.Tx.InputIDs[index]
	if sp, err := tpl.Transaction.Tx.Spend(id); err == nil {
		constraints = append(constraints, outputIDConstraint(*sp.SpentOutputId))
	}

	for i, out := range tpl.Transaction.Outputs {
		c := &payConstraint{
			Index:       i,
			AssetAmount: out.AssetAmount,
			Program:     out.ControlProgram,
		}
		constraints = append(constraints, c)
	}
	var program []byte
	for i, c := range constraints {
		program = append(program, c.code()...)
		if i < len(constraints)-1 { // leave the final bool on top of the stack
			program = append(program, byte(vm.OP_VERIFY))
		}
	}
	return program, nil
}