read.go raw
1 package psbt
2
3 import (
4 "bytes"
5 "encoding/binary"
6 "errors"
7 "fmt"
8 )
9
10 // Errors the reader refuses.
11 var (
12 // ErrNotPSBT is a blob that is not a BIP174 file.
13 ErrNotPSBT = errors.New("psbt: not a psbt")
14 // ErrTruncated is a record whose length runs past the end of the file.
15 ErrTruncated = errors.New("psbt: truncated")
16 )
17
18 // Preimage is one SHA-256 preimage record: the hash it opens and the preimage.
19 type Preimage struct {
20 // SecretHash is the hash the record is keyed by.
21 SecretHash [32]byte
22 // Preimage is the preimage.
23 Preimage []byte
24 }
25
26 // Input is what a reader got out of one input map.
27 type Input struct {
28 // Amount and ScriptPubKey come from the witness UTXO record, if it is there.
29 Amount uint64
30 ScriptPubKey []byte
31 // WitnessScript is the P2WSH script, if the map carries one.
32 WitnessScript []byte
33 // Preimages are the preimage records.
34 Preimages []Preimage
35 }
36
37 // File is a parsed PSBT.
38 type File struct {
39 // Unsigned is the global unsigned transaction, as serialised.
40 Unsigned []byte
41 // Inputs are the input maps, in order.
42 Inputs []Input
43 // Outputs is how many output maps were present.
44 Outputs int
45 }
46
47 // Read parses a PSBT.
48 //
49 // It is the other direction of Write, and it checks what it can check: magic, that every length
50 // fits, and that a preimage record's key really is the hash of its value. A record whose
51 // meaning it does not know is skipped rather than guessed at — a PSBT that carries something
52 // this wallet did not write is not an error, it is another signer's business.
53 func Read(raw []byte) (*File, error) {
54 if !bytes.HasPrefix(raw, magic) {
55 return nil, ErrNotPSBT
56 }
57
58 reader := &cursor{raw: raw, at: len(magic)}
59 file := &File{}
60
61 // The global map.
62 for {
63 key, value, err := reader.record()
64
65 if err != nil {
66 return nil, err
67 }
68
69 if key == nil {
70 break
71 }
72
73 switch key[0] {
74 case globalUnsignedTx:
75 file.Unsigned = value
76 }
77 }
78
79 // BIP174 does not count the maps, so the unsigned transaction does: it says how many input
80 // maps and how many output maps follow.
81 inputs, outputs, err := counts(file.Unsigned)
82
83 if err != nil {
84 return nil, err
85 }
86
87 for index := 0; index < inputs; index++ {
88 input := Input{}
89 emptied := false
90
91 for {
92 if !reader.more() {
93 return nil, fmt.Errorf("%w: an unclosed input map", ErrTruncated)
94 }
95
96 key, value, err := reader.record()
97
98 if err != nil {
99 return nil, err
100 }
101
102 if key == nil {
103 emptied = true
104
105 break
106 }
107
108 switch key[0] {
109 case inputWitnessUTXO:
110 if len(value) < 9 {
111 return nil, fmt.Errorf("%w: a witness utxo of %d bytes", ErrTruncated, len(value))
112 }
113
114 input.Amount = binary.LittleEndian.Uint64(value[0:8])
115
116 length := int(value[8])
117
118 if len(value) < 9+length {
119 return nil, fmt.Errorf("%w: a witness utxo script", ErrTruncated)
120 }
121
122 input.ScriptPubKey = value[9 : 9+length]
123 case inputWitnessScript:
124 input.WitnessScript = value
125 case inputSHA256Preimage:
126 if len(key) != 33 {
127 return nil, fmt.Errorf("%w: a preimage key of %d bytes", ErrTruncated, len(key))
128 }
129
130 record := Preimage{Preimage: value}
131 copy(record.SecretHash[:], key[1:])
132
133 if !bytes.Equal(sha256Of(value), record.SecretHash[:]) {
134 return nil, fmt.Errorf("%w: a preimage does not open %x", ErrTruncated, record.SecretHash)
135 }
136
137 input.Preimages = append(input.Preimages, record)
138 }
139 }
140
141 if !emptied {
142 break
143 }
144
145 file.Inputs = append(file.Inputs, input)
146 }
147
148 for index := 0; index < outputs; index++ {
149 for {
150 if !reader.more() {
151 return nil, fmt.Errorf("%w: an unclosed output map", ErrTruncated)
152 }
153
154 key, _, err := reader.record()
155
156 if err != nil {
157 return nil, err
158 }
159
160 if key == nil {
161 file.Outputs++
162
163 break
164 }
165 }
166 }
167
168 if reader.more() {
169 return nil, fmt.Errorf("%w: %d trailing bytes", ErrTruncated, len(reader.raw)-reader.at)
170 }
171
172 return file, nil
173 }
174
175 // cursor walks the file.
176 type cursor struct {
177 raw []byte
178 at int
179 }
180
181 // more reports whether there are bytes left.
182 func (c *cursor) more() bool { return c.at < len(c.raw) }
183
184 // record reads one key and value, or a nil key at a map's end.
185 func (c *cursor) record() ([]byte, []byte, error) {
186 if !c.more() {
187 return nil, nil, nil
188 }
189
190 if c.raw[c.at] == 0x00 {
191 c.at++
192
193 return nil, nil, nil
194 }
195
196 length, err := c.size()
197
198 if err != nil {
199 return nil, nil, err
200 }
201
202 key, err := c.take(length)
203
204 if err != nil {
205 return nil, nil, err
206 }
207
208 length, err = c.size()
209
210 if err != nil {
211 return nil, nil, err
212 }
213
214 value, err := c.take(length)
215
216 if err != nil {
217 return nil, nil, err
218 }
219
220 return key, value, nil
221 }
222
223 // size reads a compact size.
224 func (c *cursor) size() (int, error) {
225 if !c.more() {
226 return 0, ErrTruncated
227 }
228
229 first := c.raw[c.at]
230 c.at++
231
232 switch first {
233 case 0xfd:
234 raw, err := c.take(2)
235
236 if err != nil {
237 return 0, err
238 }
239
240 return int(binary.LittleEndian.Uint16(raw)), nil
241 case 0xfe:
242 raw, err := c.take(4)
243
244 if err != nil {
245 return 0, err
246 }
247
248 return int(binary.LittleEndian.Uint32(raw)), nil
249 }
250
251 return int(first), nil
252 }
253
254 // take reads n bytes.
255 func (c *cursor) take(n int) ([]byte, error) {
256 if n < 0 || c.at+n > len(c.raw) {
257 return nil, fmt.Errorf("%w: %d bytes at %d", ErrTruncated, n, c.at)
258 }
259
260 out := c.raw[c.at : c.at+n]
261 c.at += n
262
263 return out, nil
264 }
265
266 // counts walks the unsigned transaction and reports how many inputs and outputs it has, which
267 // is how many maps must follow.
268 func counts(unsigned []byte) (int, int, error) {
269 cursor := &cursor{raw: unsigned}
270
271 if _, err := cursor.take(4); err != nil {
272 return 0, 0, err
273 }
274
275 inputs, err := cursor.size()
276
277 if err != nil {
278 return 0, 0, err
279 }
280
281 for index := 0; index < inputs; index++ {
282 if _, err := cursor.take(36); err != nil { // outpoint
283 return 0, 0, err
284 }
285
286 length, err := cursor.size()
287
288 if err != nil {
289 return 0, 0, err
290 }
291
292 if _, err := cursor.take(length); err != nil { // scriptSig
293 return 0, 0, err
294 }
295
296 if _, err := cursor.take(4); err != nil { // sequence
297 return 0, 0, err
298 }
299 }
300
301 outputs, err := cursor.size()
302
303 if err != nil {
304 return 0, 0, err
305 }
306
307 for index := 0; index < outputs; index++ {
308 if _, err := cursor.take(8); err != nil { // value
309 return 0, 0, err
310 }
311
312 length, err := cursor.size()
313
314 if err != nil {
315 return 0, 0, err
316 }
317
318 if _, err := cursor.take(length); err != nil { // script
319 return 0, 0, err
320 }
321 }
322
323 return inputs, outputs, nil
324 }
325