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