func (t *Tx) Confirm(confirm interface{}, pid int) error {
	t2, ok := confirm.(*Tx)
	if !ok {
		return errors.New("coinjoin: confirmation is not a *Tx")
	}
	if len(t.Tx.TxIn) != len(t2.Tx.TxIn) {
		return errors.New("coinjoin: peer added or removed inputs")
	}
	for i, inputPid := range t.inputPids {
		if pid != inputPid {
			continue
		}
		t.Tx.TxIn[i].SignatureScript = t2.Tx.TxIn[i].SignatureScript
	}
	return nil
}
Confirm extracts the signatures from peer pid in confirm and adds them the
receiver.

confirm must have type *Tx.
package coinjoin
import (
	"bytes"
	"context"
	"crypto/rand"
	"encoding/binary"
	"encoding/gob"
	"encoding/hex"
	"errors"
	"fmt"
	mathrand "math/rand"
	"strings"
	"sync"
	"time"
	"github.com/decred/dcrd/wire"
)
var shuffleRand *mathrand.Rand
var shuffleMu sync.Mutex
func init() {
	buf := make([]byte, 8)
	_, err := rand.Read(buf)
	if err != nil {
		panic(err)
	}
	seed := int64(binary.LittleEndian.Uint64(buf))
	shuffleRand = mathrand.New(mathrand.NewSource(seed))
}
func shuffle(n int, swap func(i, j int)) {
	shuffleMu.Lock()
	shuffleRand.Shuffle(n, swap)
	shuffleMu.Unlock()
}
type Caller interface {
	Call(ctx context.Context, method string, res interface{}, args ...interface{}) error
}
type Tx struct {
	Tx        wire.MsgTx
	c         Caller
	sc        ScriptClass
	inputPids []int
	mixValue  int64
	feeRate   int64
	txVersion uint16
	lockTime  uint32
	expiry    uint32
}
type ScriptClass int
const (
	P2PKHv0 ScriptClass = iota
	P2SHv0
	numScriptClasses
)
func (sc ScriptClass) Match(script []byte, vers uint16) bool {
	if vers != 0 {
		return false
	}
	var match bool
	switch sc {
	case P2PKHv0:
		match = len(script) == 25
		match = match && script[0] == 0x76   
		match = match && script[1] == 0xa9   
		match = match && script[2] == 20     
		match = match && script[23] == 0x88  
		match = match && script[24] == 0xac  
	case P2SHv0:
		match = len(script) == 23
		match = match && script[0] == 0xa9   
		match = match && script[1] == 20     
		match = match && script[22] == 0x87  
	}
	return match
}
func (sc ScriptClass) script(message []byte) []byte {
	switch sc {
	case P2PKHv0:
		s := []byte{
			0:  0x76,  
			1:  0xa9,  
			2:  20,    
			23: 0x88,  
			24: 0xac,  
		}
		copy(s[3:23], message)
		return s
	case P2SHv0:
		s := []byte{
			0:  0xa9,  
			1:  20,    
			22: 0x87,  
		}
		copy(s[2:22], message)
		return s
	default:
		panic("unreachable")
	}
}
func (sc ScriptClass) scriptSize() int {
	switch sc {
	case P2PKHv0:
		return 25
	case P2SHv0:
		return 23
	default:
		panic("unreachable")
	}
}
func (sc ScriptClass) version() uint16 { return 0 }
const descname = "coinjoin-decred"
func EncodeDesc(sc ScriptClass, amount int64, txVersion uint16, lockTime, expiry uint32) []byte {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	encode := func(value interface{}) {
		if err := enc.Encode(value); err != nil {
			panic(err)
		}
	}
	encode(descname)
	encode(int(sc))
	encode(amount)
	encode(txVersion)
	encode(lockTime)
	encode(expiry)
	return buf.Bytes()
}
func DecodeDesc(desc []byte) (sc ScriptClass, amount int64, txVersion uint16, lockTime, expiry uint32, err error) {
	buf := bytes.NewBuffer(desc)
	dec := gob.NewDecoder(buf)
	decode := func(out interface{}) {
		if err == nil {
			err = dec.Decode(out)
		}
	}
	var ty string
	decode(&ty)
	if ty != descname {
		err = errors.New("incompatible coinjoin")
		return
	}
	decode(&sc)
	decode(&amount)
	decode(&txVersion)
	decode(&lockTime)
	decode(&expiry)
	return
}
func NewTx(caller Caller, sc ScriptClass, amount, feeRate int64, txVersion uint16,
	lockTime, expiry uint32) (*Tx, error) {
	if sc >= numScriptClasses {
		return nil, errors.New("unknown script class")
	}
	tx := &Tx{
		Tx:        wire.MsgTx{Version: txVersion},
		c:         caller,
		sc:        sc,
		mixValue:  amount,
		feeRate:   feeRate,
		txVersion: txVersion,
		lockTime:  lockTime,
		expiry:    expiry,
	}
	return tx, nil
}
func (t *Tx) MarshalBinary() ([]byte, error) {
	buf := new(bytes.Buffer)
	buf.Grow(t.Tx.SerializeSize())
	err := t.Tx.Serialize(buf)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
func (t *Tx) UnmarshalBinary(b []byte) error {
	return t.Tx.Deserialize(bytes.NewReader(b))
}
func feeForSerializeSize(relayFeePerKb int64, txSerializeSize int) int64 {
	fee := relayFeePerKb * int64(txSerializeSize) / 1000
	if fee == 0 && relayFeePerKb > 0 {
		fee = relayFeePerKb
	}
	const maxAmount = 21e6 * 1e8
	if fee < 0 || fee > maxAmount {
		fee = maxAmount
	}
	return fee
}
func (t *Tx) ValidateUnmixed(unmixed []byte, mcount int) error {
	var fee int64
	other := new(wire.MsgTx)
	err := other.Deserialize(bytes.NewReader(unmixed))
	if err != nil {
		return err
	}
	if other.Version != t.txVersion {
		return errors.New("coinjoin: different tx versions")
	}
	for _, out := range other.TxOut {
		if !t.sc.Match(out.PkScript, out.Version) {
			return errors.New("coinjoin: different script class")
		}
		fee -= out.Value
	}
	for _, in := range other.TxIn {
		if err := verifyOutput(t.c, &in.PreviousOutPoint, in.ValueIn); err != nil {
			var e *blameError
			if errors.As(err, &e) {
				return errors.New(e.s)
			}
			return err
		}
		fee += in.ValueIn
	}
	fee -= int64(mcount) * t.mixValue
	bogusMixedOut := &wire.TxOut{
		Value:    t.mixValue,
		Version:  t.sc.version(),
		PkScript: make([]byte, t.sc.scriptSize()),
	}
	for i := 0; i < mcount; i++ {
		other.AddTxOut(bogusMixedOut)
	}
	requiredFee := feeForSerializeSize(t.feeRate, other.SerializeSize())
	if fee < requiredFee {
		return errors.New("coinjoin: unmixed transaction does not pay enough network fees")
	}
	return nil
}
func (t *Tx) Join(unmixed []byte, pid int) error {
	other := new(wire.MsgTx)
	err := other.Deserialize(bytes.NewReader(unmixed))
	if err != nil {
		return err
	}
	if other.Version != t.txVersion {
		return errors.New("coinjoin: different tx versions")
	}
	for _, out := range other.TxOut {
		if !t.sc.Match(out.PkScript, out.Version) {
			return errors.New("coinjoin: different script class")
		}
	}
	for _, in := range other.TxIn {
		if err := verifyOutput(t.c, &in.PreviousOutPoint, in.ValueIn); err != nil {
			var e *blameError
			if errors.As(err, &e) {
				e.b = []int{pid}
			}
			return err
		}
	}
	tx := &t.Tx
	for _, in := range other.TxIn {
		t.inputPids = append(t.inputPids, pid)
		tx.TxIn = append(tx.TxIn, in)
	}
	tx.TxOut = append(tx.TxOut, other.TxOut...)
	return nil
}
const rpcTimeout = 10 * time.Second
func verifyOutput(c Caller, outpoint *wire.OutPoint, value int64) error {
	ctx, cancel := context.WithTimeout(context.Background(), rpcTimeout)
	defer cancel()
	var res struct {
		Value float64 `json:"value"`
	}
	err := c.Call(ctx, "gettxout", &res, outpoint.Hash.String(), outpoint.Index, outpoint.Tree)
	if err != nil {
		return err
	}
	if v := atoms(res.Value); v != value {
		return &blameError{
			fmt.Sprintf("output %v has wrong value %d (expected %d)", outpoint, value, v),
			nil,
		}
	}
	return nil
}
func atoms(f float64) int64 {
	return int64(f*1e8 + 0.5)
}
func (t *Tx) Mix(m []byte) {
	t.Tx.TxOut = append(t.Tx.TxOut, &wire.TxOut{
		Value:    t.mixValue,
		Version:  t.sc.version(),
		PkScript: t.sc.script(m),
	})
}