sighash.go raw

   1  package tx
   2  
   3  import (
   4  	"crypto/sha256"
   5  	"encoding/binary"
   6  	"errors"
   7  )
   8  
   9  // Errors the sighash refuses.
  10  var (
  11  	// ErrSighashType is a signature hash type this wallet does not produce. Only SIGHASH_ALL
  12  	// is implemented: a swap that could be re-signed with a different type would change what
  13  	// it commits to, and nothing here needs that.
  14  	ErrSighashType = errors.New("tx: only SIGHASH_ALL is supported")
  15  	// ErrInputIndex is an input that is not in the transaction.
  16  	ErrInputIndex = errors.New("tx: no such input")
  17  )
  18  
  19  // SighashAll is the only signature hash type the wallet signs.
  20  const SighashAll uint32 = 1
  21  
  22  // P2WPKHScriptCode is the scriptCode BIP143 uses for a P2WPKH input: the pay-to-pubkey-hash
  23  // script the witness program stands for, not the program itself. It is the bare 25-byte
  24  // script — the length prefix in the preimage is the codec's, not part of this.
  25  func P2WPKHScriptCode(program [20]byte) []byte {
  26  	out := []byte{0x76, 0xa9, 0x14}
  27  	out = append(out, program[:]...)
  28  
  29  	return append(out, 0x88, 0xac)
  30  }
  31  
  32  // SighashV0 is the BIP143 digest for input `index` of a segwit spend.
  33  //
  34  //	version | hashPrevouts | hashSequence | outpoint | scriptCode | amount |
  35  //	sequence | hashOutputs | locktime | sighashType
  36  //
  37  // The digest commits to every input's outpoint and sequence and to every output, which is what
  38  // makes it safe to sign without the other inputs' scripts — the property that lets a wallet
  39  // sign an input it did not build. `amount` is the value being spent, and it is in the digest
  40  // because BIP143 added it: a signature that did not commit to the amount would let a
  41  // counterparty claim a different value.
  42  func (t *Tx) SighashV0(index int, scriptCode []byte, amount uint64, sighashType uint32) ([32]byte, error) {
  43  	if sighashType != SighashAll {
  44  		return [32]byte{}, ErrSighashType
  45  	}
  46  
  47  	if index < 0 || index >= len(t.Inputs) {
  48  		return [32]byte{}, ErrInputIndex
  49  	}
  50  
  51  	prevouts, err := t.hashPrevouts()
  52  
  53  	if err != nil {
  54  		return [32]byte{}, err
  55  	}
  56  
  57  	sequences, err := t.hashSequences()
  58  
  59  	if err != nil {
  60  		return [32]byte{}, err
  61  	}
  62  
  63  	outputs, err := t.hashOutputs()
  64  
  65  	if err != nil {
  66  		return [32]byte{}, err
  67  	}
  68  
  69  	input := t.Inputs[index]
  70  
  71  	preimage := make([]byte, 0, 156+len(scriptCode))
  72  	preimage = binary.LittleEndian.AppendUint32(preimage, t.Version)
  73  	preimage = append(preimage, prevouts[:]...)
  74  	preimage = append(preimage, sequences[:]...)
  75  	preimage = append(preimage, input.Hash[:]...)
  76  	preimage = binary.LittleEndian.AppendUint32(preimage, input.Index)
  77  	preimage = appendCompactSize(preimage, len(scriptCode))
  78  	preimage = append(preimage, scriptCode...)
  79  	preimage = binary.LittleEndian.AppendUint64(preimage, amount)
  80  	preimage = binary.LittleEndian.AppendUint32(preimage, input.Sequence)
  81  	preimage = append(preimage, outputs[:]...)
  82  	preimage = binary.LittleEndian.AppendUint32(preimage, t.LockTime)
  83  	preimage = binary.LittleEndian.AppendUint32(preimage, sighashType)
  84  
  85  	return doubleSHA256(preimage), nil
  86  }
  87  
  88  // hashPrevouts is the double SHA-256 of every input's outpoint.
  89  func (t *Tx) hashPrevouts() ([32]byte, error) {
  90  	if len(t.Inputs) == 0 {
  91  		return [32]byte{}, ErrNoInputs
  92  	}
  93  
  94  	raw := make([]byte, 0, 36*len(t.Inputs))
  95  
  96  	for _, input := range t.Inputs {
  97  		raw = append(raw, input.Hash[:]...)
  98  		raw = binary.LittleEndian.AppendUint32(raw, input.Index)
  99  	}
 100  
 101  	return doubleSHA256(raw), nil
 102  }
 103  
 104  // hashSequences is the double SHA-256 of every input's sequence.
 105  func (t *Tx) hashSequences() ([32]byte, error) {
 106  	if len(t.Inputs) == 0 {
 107  		return [32]byte{}, ErrNoInputs
 108  	}
 109  
 110  	raw := make([]byte, 0, 4*len(t.Inputs))
 111  
 112  	for _, input := range t.Inputs {
 113  		raw = binary.LittleEndian.AppendUint32(raw, input.Sequence)
 114  	}
 115  
 116  	return doubleSHA256(raw), nil
 117  }
 118  
 119  // hashOutputs is the double SHA-256 of every output, serialised as the transaction does.
 120  func (t *Tx) hashOutputs() ([32]byte, error) {
 121  	if len(t.Outputs) == 0 {
 122  		return [32]byte{}, ErrNoOutputs
 123  	}
 124  
 125  	raw := make([]byte, 0, 34*len(t.Outputs))
 126  
 127  	for _, output := range t.Outputs {
 128  		raw = binary.LittleEndian.AppendUint64(raw, output.Value)
 129  		raw = appendCompactSize(raw, len(output.Script))
 130  		raw = append(raw, output.Script...)
 131  	}
 132  
 133  	return doubleSHA256(raw), nil
 134  }
 135  
 136  // doubleSHA256 is Bitcoin's hash.
 137  func doubleSHA256(raw []byte) [32]byte {
 138  	first := sha256.Sum256(raw)
 139  
 140  	return sha256.Sum256(first[:])
 141  }
 142