// txidPrefix is prepended to a transaction when computing its txid
var txidPrefix = []byte("TX")
// RawTransactionBytesToSign returns the byte form of the tx that we actually sign
// and compute txID from.
func RawTransactionBytesToSign(tx types.Transaction) []byte {
// Encode the transaction as msgpack
encodedTx := msgpack.Encode(tx)
// Prepend the hashable prefix
msgParts := [][]byte{txidPrefix, encodedTx}
return bytes.Join(msgParts, nil)
}
// VerifySignature verifies a simple signature (not a multisig or logicsig)
func VerifySignature(tx types.Transaction, pk ed25519.PublicKey, sig types.Signature) bool {
toBeSigned := RawTransactionBytesToSign(tx)
return ed25519.Verify(pk, toBeSigned, sig[:])
}
// AddrToED25519PublicKey copies an address to pk
func AddrToED25519PublicKey(a types.Address) (pk ed25519.PublicKey) {
pk = make([]byte, len(a))
copy(pk, a[:])
return
}
// CheckSignature verifies that stx is either a single signature
func CheckSignature(stx types.SignedTxn) error {
if (stx.Sig != types.Signature{}) { // contains a regular signature
// Single signature
// Check msig is empty
if len(stx.Msig.Subsigs) != 0 || stx.Msig.Version != 0 || stx.Msig.Threshold != 0 {
return errors.New("tx has both a sig and msig")
}
// Check lsig is empty
if !stx.Lsig.Blank() {
return errors.New("tx has both a sig and lsig")
}
pk := AddrToED25519PublicKey(stx.Txn.Sender)
if (stx.Sig == types.Signature{}) && !requireSigned {
return nil
}
if !VerifySignature(stx.Txn, pk, stx.Sig) {
return errors.New("signature does not verify")
}
}
return errors.New("msig/lsig not supported")
}