1// Copyright (c) 2018 The btcsuite developers
2// Use of this source code is governed by an ISC
3// license that can be found in the LICENSE file.
4
5package psbt
6
7// The Updater requires provision of a single PSBT and is able to add data to
8// both input and output sections.  It can be called repeatedly to add more
9// data.  It also allows addition of signatures via the addPartialSignature
10// function; this is called internally to the package in the Sign() function of
11// Updater, located in signer.go
12
13import (
14	"bytes"
15	"crypto/sha256"
16
17	"github.com/btcsuite/btcd/txscript"
18	"github.com/btcsuite/btcd/wire"
19	"github.com/btcsuite/btcutil"
20)
21
22// Updater encapsulates the role 'Updater' as specified in BIP174; it accepts
23// Psbt structs and has methods to add fields to the inputs and outputs.
24type Updater struct {
25	Upsbt *Packet
26}
27
28// NewUpdater returns a new instance of Updater, if the passed Psbt struct is
29// in a valid form, else an error.
30func NewUpdater(p *Packet) (*Updater, error) {
31	if err := p.SanityCheck(); err != nil {
32		return nil, err
33	}
34
35	return &Updater{Upsbt: p}, nil
36
37}
38
39// AddInNonWitnessUtxo adds the utxo information for an input which is
40// non-witness. This requires provision of a full transaction (which is the
41// source of the corresponding prevOut), and the input index. If addition of
42// this key-value pair to the Psbt fails, an error is returned.
43func (p *Updater) AddInNonWitnessUtxo(tx *wire.MsgTx, inIndex int) error {
44	if inIndex > len(p.Upsbt.Inputs)-1 {
45		return ErrInvalidPrevOutNonWitnessTransaction
46	}
47
48	p.Upsbt.Inputs[inIndex].NonWitnessUtxo = tx
49
50	if err := p.Upsbt.SanityCheck(); err != nil {
51		return ErrInvalidPsbtFormat
52	}
53
54	return nil
55}
56
57// AddInWitnessUtxo adds the utxo information for an input which is witness.
58// This requires provision of a full transaction *output* (which is the source
59// of the corresponding prevOut); not the full transaction because BIP143 means
60// the output information is sufficient, and the input index. If addition of
61// this key-value pair to the Psbt fails, an error is returned.
62func (p *Updater) AddInWitnessUtxo(txout *wire.TxOut, inIndex int) error {
63	if inIndex > len(p.Upsbt.Inputs)-1 {
64		return ErrInvalidPsbtFormat
65	}
66
67	p.Upsbt.Inputs[inIndex].WitnessUtxo = txout
68
69	if err := p.Upsbt.SanityCheck(); err != nil {
70		return ErrInvalidPsbtFormat
71	}
72
73	return nil
74}
75
76// addPartialSignature allows the Updater role to insert fields of type partial
77// signature into a Psbt, consisting of both the pubkey (as keydata) and the
78// ECDSA signature (as value).  Note that the Signer role is encapsulated in
79// this function; signatures are only allowed to be added that follow the
80// sanity-check on signing rules explained in the BIP under `Signer`; if the
81// rules are not satisfied, an ErrInvalidSignatureForInput is returned.
82//
83// NOTE: This function does *not* validate the ECDSA signature itself.
84func (p *Updater) addPartialSignature(inIndex int, sig []byte,
85	pubkey []byte) error {
86
87	partialSig := PartialSig{
88		PubKey: pubkey, Signature: sig,
89	}
90
91	// First validate the passed (sig, pub).
92	if !partialSig.checkValid() {
93		return ErrInvalidPsbtFormat
94	}
95
96	pInput := p.Upsbt.Inputs[inIndex]
97
98	// First check; don't add duplicates.
99	for _, x := range pInput.PartialSigs {
100		if bytes.Equal(x.PubKey, partialSig.PubKey) {
101			return ErrDuplicateKey
102		}
103	}
104
105	// Next, we perform a series of additional sanity checks.
106	if pInput.NonWitnessUtxo != nil {
107		if len(p.Upsbt.UnsignedTx.TxIn) < inIndex+1 {
108			return ErrInvalidPrevOutNonWitnessTransaction
109		}
110
111		if pInput.NonWitnessUtxo.TxHash() !=
112			p.Upsbt.UnsignedTx.TxIn[inIndex].PreviousOutPoint.Hash {
113			return ErrInvalidSignatureForInput
114		}
115
116		// To validate that the redeem script matches, we must pull out
117		// the scriptPubKey of the corresponding output and compare
118		// that with the P2SH scriptPubKey that is generated by
119		// redeemScript.
120		if pInput.RedeemScript != nil {
121			outIndex := p.Upsbt.UnsignedTx.TxIn[inIndex].PreviousOutPoint.Index
122			scriptPubKey := pInput.NonWitnessUtxo.TxOut[outIndex].PkScript
123			scriptHash := btcutil.Hash160(pInput.RedeemScript)
124
125			scriptHashScript, err := txscript.NewScriptBuilder().
126				AddOp(txscript.OP_HASH160).
127				AddData(scriptHash).
128				AddOp(txscript.OP_EQUAL).
129				Script()
130			if err != nil {
131				return err
132			}
133
134			if !bytes.Equal(scriptHashScript, scriptPubKey) {
135				return ErrInvalidSignatureForInput
136			}
137		}
138
139	} else if pInput.WitnessUtxo != nil {
140		scriptPubKey := pInput.WitnessUtxo.PkScript
141
142		var script []byte
143		if pInput.RedeemScript != nil {
144			scriptHash := btcutil.Hash160(pInput.RedeemScript)
145			scriptHashScript, err := txscript.NewScriptBuilder().
146				AddOp(txscript.OP_HASH160).
147				AddData(scriptHash).
148				AddOp(txscript.OP_EQUAL).
149				Script()
150			if err != nil {
151				return err
152			}
153
154			if !bytes.Equal(scriptHashScript, scriptPubKey) {
155				return ErrInvalidSignatureForInput
156			}
157
158			script = pInput.RedeemScript
159		} else {
160			script = scriptPubKey
161		}
162
163		// If a witnessScript field is present, this is a P2WSH,
164		// whether nested or not (that is handled by the assignment to
165		// `script` above); in that case, sanity check that `script` is
166		// the p2wsh of witnessScript. Contrariwise, if no
167		// witnessScript field is present, this will be signed as
168		// p2wkh.
169		if pInput.WitnessScript != nil {
170			witnessScriptHash := sha256.Sum256(pInput.WitnessScript)
171			witnessScriptHashScript, err := txscript.NewScriptBuilder().
172				AddOp(txscript.OP_0).
173				AddData(witnessScriptHash[:]).
174				Script()
175			if err != nil {
176				return err
177			}
178
179			if !bytes.Equal(script, witnessScriptHashScript[:]) {
180				return ErrInvalidSignatureForInput
181			}
182		} else {
183			// Otherwise, this is a p2wkh input.
184			pubkeyHash := btcutil.Hash160(pubkey)
185			pubkeyHashScript, err := txscript.NewScriptBuilder().
186				AddOp(txscript.OP_0).
187				AddData(pubkeyHash).
188				Script()
189			if err != nil {
190				return err
191			}
192
193			// Validate that we're able to properly reconstruct the
194			// witness program.
195			if !bytes.Equal(pubkeyHashScript, script) {
196				return ErrInvalidSignatureForInput
197			}
198		}
199	} else {
200
201		// Attaching signature without utxo field is not allowed.
202		return ErrInvalidPsbtFormat
203	}
204
205	p.Upsbt.Inputs[inIndex].PartialSigs = append(
206		p.Upsbt.Inputs[inIndex].PartialSigs, &partialSig,
207	)
208
209	if err := p.Upsbt.SanityCheck(); err != nil {
210		return err
211	}
212
213	// Addition of a non-duplicate-key partial signature cannot violate
214	// sanity-check rules.
215	return nil
216}
217
218// AddInSighashType adds the sighash type information for an input.  The
219// sighash type is passed as a 32 bit unsigned integer, along with the index
220// for the input. An error is returned if addition of this key-value pair to
221// the Psbt fails.
222func (p *Updater) AddInSighashType(sighashType txscript.SigHashType,
223	inIndex int) error {
224
225	p.Upsbt.Inputs[inIndex].SighashType = sighashType
226
227	if err := p.Upsbt.SanityCheck(); err != nil {
228		return err
229	}
230	return nil
231}
232
233// AddInRedeemScript adds the redeem script information for an input.  The
234// redeem script is passed serialized, as a byte slice, along with the index of
235// the input. An error is returned if addition of this key-value pair to the
236// Psbt fails.
237func (p *Updater) AddInRedeemScript(redeemScript []byte,
238	inIndex int) error {
239
240	p.Upsbt.Inputs[inIndex].RedeemScript = redeemScript
241
242	if err := p.Upsbt.SanityCheck(); err != nil {
243		return ErrInvalidPsbtFormat
244	}
245
246	return nil
247}
248
249// AddInWitnessScript adds the witness script information for an input.  The
250// witness script is passed serialized, as a byte slice, along with the index
251// of the input. An error is returned if addition of this key-value pair to the
252// Psbt fails.
253func (p *Updater) AddInWitnessScript(witnessScript []byte,
254	inIndex int) error {
255
256	p.Upsbt.Inputs[inIndex].WitnessScript = witnessScript
257
258	if err := p.Upsbt.SanityCheck(); err != nil {
259		return err
260	}
261
262	return nil
263}
264
265// AddInBip32Derivation takes a master key fingerprint as defined in BIP32, a
266// BIP32 path as a slice of uint32 values, and a serialized pubkey as a byte
267// slice, along with the integer index of the input, and inserts this data into
268// that input.
269//
270// NOTE: This can be called multiple times for the same input.  An error is
271// returned if addition of this key-value pair to the Psbt fails.
272func (p *Updater) AddInBip32Derivation(masterKeyFingerprint uint32,
273	bip32Path []uint32, pubKeyData []byte, inIndex int) error {
274
275	bip32Derivation := Bip32Derivation{
276		PubKey:               pubKeyData,
277		MasterKeyFingerprint: masterKeyFingerprint,
278		Bip32Path:            bip32Path,
279	}
280
281	if !bip32Derivation.checkValid() {
282		return ErrInvalidPsbtFormat
283	}
284
285	// Don't allow duplicate keys
286	for _, x := range p.Upsbt.Inputs[inIndex].Bip32Derivation {
287		if bytes.Equal(x.PubKey, bip32Derivation.PubKey) {
288			return ErrDuplicateKey
289		}
290	}
291
292	p.Upsbt.Inputs[inIndex].Bip32Derivation = append(
293		p.Upsbt.Inputs[inIndex].Bip32Derivation, &bip32Derivation,
294	)
295
296	if err := p.Upsbt.SanityCheck(); err != nil {
297		return err
298	}
299
300	return nil
301}
302
303// AddOutBip32Derivation takes a master key fingerprint as defined in BIP32, a
304// BIP32 path as a slice of uint32 values, and a serialized pubkey as a byte
305// slice, along with the integer index of the output, and inserts this data
306// into that output.
307//
308// NOTE: That this can be called multiple times for the same output.  An error
309// is returned if addition of this key-value pair to the Psbt fails.
310func (p *Updater) AddOutBip32Derivation(masterKeyFingerprint uint32,
311	bip32Path []uint32, pubKeyData []byte, outIndex int) error {
312
313	bip32Derivation := Bip32Derivation{
314		PubKey:               pubKeyData,
315		MasterKeyFingerprint: masterKeyFingerprint,
316		Bip32Path:            bip32Path,
317	}
318
319	if !bip32Derivation.checkValid() {
320		return ErrInvalidPsbtFormat
321	}
322
323	// Don't allow duplicate keys
324	for _, x := range p.Upsbt.Outputs[outIndex].Bip32Derivation {
325		if bytes.Equal(x.PubKey, bip32Derivation.PubKey) {
326			return ErrDuplicateKey
327		}
328	}
329
330	p.Upsbt.Outputs[outIndex].Bip32Derivation = append(
331		p.Upsbt.Outputs[outIndex].Bip32Derivation, &bip32Derivation,
332	)
333
334	if err := p.Upsbt.SanityCheck(); err != nil {
335		return err
336	}
337
338	return nil
339}
340
341// AddOutRedeemScript takes a redeem script as a byte slice and appends it to
342// the output at index outIndex.
343func (p *Updater) AddOutRedeemScript(redeemScript []byte,
344	outIndex int) error {
345
346	p.Upsbt.Outputs[outIndex].RedeemScript = redeemScript
347
348	if err := p.Upsbt.SanityCheck(); err != nil {
349		return ErrInvalidPsbtFormat
350	}
351
352	return nil
353}
354
355// AddOutWitnessScript takes a witness script as a byte slice and appends it to
356// the output at index outIndex.
357func (p *Updater) AddOutWitnessScript(witnessScript []byte,
358	outIndex int) error {
359
360	p.Upsbt.Outputs[outIndex].WitnessScript = witnessScript
361
362	if err := p.Upsbt.SanityCheck(); err != nil {
363		return err
364	}
365
366	return nil
367}
368