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 Finalizer requires provision of a single PSBT input
8// in which all necessary signatures are encoded, and
9// uses it to construct valid final sigScript and scriptWitness
10// fields.
11// NOTE that p2sh (legacy) and p2wsh currently support only
12// multisig and no other custom script.
13
14import (
15	"github.com/btcsuite/btcd/txscript"
16)
17
18// isFinalized considers this input finalized if it contains at least one of
19// the FinalScriptSig or FinalScriptWitness are filled (which only occurs in a
20// successful call to Finalize*).
21func isFinalized(p *Packet, inIndex int) bool {
22	input := p.Inputs[inIndex]
23	return input.FinalScriptSig != nil || input.FinalScriptWitness != nil
24}
25
26// isFinalizableWitnessInput returns true if the target input is a witness UTXO
27// that can be finalized.
28func isFinalizableWitnessInput(pInput *PInput) bool {
29	pkScript := pInput.WitnessUtxo.PkScript
30
31	switch {
32	// If this is a native witness output, then we require both
33	// the witness script, but not a redeem script.
34	case txscript.IsWitnessProgram(pkScript):
35		if txscript.IsPayToWitnessScriptHash(pkScript) {
36			if pInput.WitnessScript == nil ||
37				pInput.RedeemScript != nil {
38				return false
39			}
40		} else {
41			// A P2WKH output on the other hand doesn't need
42			// neither a witnessScript or redeemScript.
43			if pInput.WitnessScript != nil ||
44				pInput.RedeemScript != nil {
45				return false
46			}
47		}
48
49	// For nested P2SH inputs, we verify that a witness script is known.
50	case txscript.IsPayToScriptHash(pkScript):
51		if pInput.RedeemScript == nil {
52			return false
53		}
54
55		// If this is a nested P2SH input, then it must also have a
56		// witness script, while we don't need one for P2WKH.
57		if txscript.IsPayToWitnessScriptHash(pInput.RedeemScript) {
58			if pInput.WitnessScript == nil {
59				return false
60			}
61		} else if txscript.IsPayToWitnessPubKeyHash(pInput.RedeemScript) {
62			if pInput.WitnessScript != nil {
63				return false
64			}
65		} else {
66			// unrecognized type
67			return false
68		}
69
70	// If this isn't a nested nested P2SH output or a native witness
71	// output, then we can't finalize this input as we don't understand it.
72	default:
73		return false
74	}
75
76	return true
77}
78
79// isFinalizableLegacyInput returns true of the passed input a legacy input
80// (non-witness) that can be finalized.
81func isFinalizableLegacyInput(p *Packet, pInput *PInput, inIndex int) bool {
82	// If the input has a witness, then it's invalid.
83	if pInput.WitnessScript != nil {
84		return false
85	}
86
87	// Otherwise, we'll verify that we only have a RedeemScript if the prev
88	// output script is P2SH.
89	outIndex := p.UnsignedTx.TxIn[inIndex].PreviousOutPoint.Index
90	if txscript.IsPayToScriptHash(pInput.NonWitnessUtxo.TxOut[outIndex].PkScript) {
91		if pInput.RedeemScript == nil {
92			return false
93		}
94	} else {
95		if pInput.RedeemScript != nil {
96			return false
97		}
98	}
99
100	return true
101}
102
103// isFinalizable checks whether the structure of the entry for the input of the
104// psbt.Packet at index inIndex contains sufficient information to finalize
105// this input.
106func isFinalizable(p *Packet, inIndex int) bool {
107	pInput := p.Inputs[inIndex]
108
109	// The input cannot be finalized without any signatures
110	if pInput.PartialSigs == nil {
111		return false
112	}
113
114	// For an input to be finalized, we'll one of two possible top-level
115	// UTXOs present. Each UTXO type has a distinct set of requirements to
116	// be considered finalized.
117	switch {
118
119	// A witness input must be either native P2WSH or nested P2SH with all
120	// relevant sigScript or witness data populated.
121	case pInput.WitnessUtxo != nil:
122		if !isFinalizableWitnessInput(&pInput) {
123			return false
124		}
125
126	case pInput.NonWitnessUtxo != nil:
127		if !isFinalizableLegacyInput(p, &pInput, inIndex) {
128			return false
129		}
130
131	// If neither a known UTXO type isn't present at all, then we'll
132	// return false as we need one of them.
133	default:
134		return false
135	}
136
137	return true
138}
139
140// MaybeFinalize attempts to finalize the input at index inIndex in the PSBT p,
141// returning true with no error if it succeeds, OR if the input has already
142// been finalized.
143func MaybeFinalize(p *Packet, inIndex int) (bool, error) {
144	if isFinalized(p, inIndex) {
145		return true, nil
146	}
147
148	if !isFinalizable(p, inIndex) {
149		return false, ErrNotFinalizable
150	}
151
152	if err := Finalize(p, inIndex); err != nil {
153		return false, err
154	}
155
156	return true, nil
157}
158
159// MaybeFinalizeAll attempts to finalize all inputs of the psbt.Packet that are
160// not already finalized, and returns an error if it fails to do so.
161func MaybeFinalizeAll(p *Packet) error {
162
163	for i := range p.UnsignedTx.TxIn {
164		success, err := MaybeFinalize(p, i)
165		if err != nil || !success {
166			return err
167		}
168	}
169
170	return nil
171}
172
173// Finalize assumes that the provided psbt.Packet struct has all partial
174// signatures and redeem scripts/witness scripts already prepared for the
175// specified input, and so removes all temporary data and replaces them with
176// completed sigScript and witness fields, which are stored in key-types 07 and
177// 08. The witness/non-witness utxo fields in the inputs (key-types 00 and 01)
178// are left intact as they may be needed for validation (?).  If there is any
179// invalid or incomplete data, an error is returned.
180func Finalize(p *Packet, inIndex int) error {
181	pInput := p.Inputs[inIndex]
182
183	// Depending on the UTXO type, we either attempt to finalize it as a
184	// witness or legacy UTXO.
185	switch {
186	case pInput.WitnessUtxo != nil:
187		if err := finalizeWitnessInput(p, inIndex); err != nil {
188			return err
189		}
190
191	case pInput.NonWitnessUtxo != nil:
192		if err := finalizeNonWitnessInput(p, inIndex); err != nil {
193			return err
194		}
195
196	default:
197		return ErrInvalidPsbtFormat
198	}
199
200	// Before returning we sanity check the PSBT to ensure we don't extract
201	// an invalid transaction or produce an invalid intermediate state.
202	if err := p.SanityCheck(); err != nil {
203		return err
204	}
205
206	return nil
207}
208
209// checkFinalScriptSigWitness checks whether a given input in the psbt.Packet
210// struct already has the fields 07 (FinalInScriptSig) or 08 (FinalInWitness).
211// If so, it returns true. It does not modify the Psbt.
212func checkFinalScriptSigWitness(p *Packet, inIndex int) bool {
213	pInput := p.Inputs[inIndex]
214
215	if pInput.FinalScriptSig != nil {
216		return true
217	}
218
219	if pInput.FinalScriptWitness != nil {
220		return true
221	}
222
223	return false
224}
225
226// finalizeNonWitnessInput attempts to create a PsbtInFinalScriptSig field for
227// the input at index inIndex, and removes all other fields except for the UTXO
228// field, for an input of type non-witness, or returns an error.
229func finalizeNonWitnessInput(p *Packet, inIndex int) error {
230	// If this input has already been finalized, then we'll return an error
231	// as we can't proceed.
232	if checkFinalScriptSigWitness(p, inIndex) {
233		return ErrInputAlreadyFinalized
234	}
235
236	// Our goal here is to construct a sigScript given the pubkey,
237	// signature (keytype 02), of which there might be multiple, and the
238	// redeem script field (keytype 04) if present (note, it is not present
239	// for p2pkh type inputs).
240	var sigScript []byte
241
242	pInput := p.Inputs[inIndex]
243	containsRedeemScript := pInput.RedeemScript != nil
244
245	var (
246		pubKeys [][]byte
247		sigs    [][]byte
248	)
249	for _, ps := range pInput.PartialSigs {
250		pubKeys = append(pubKeys, ps.PubKey)
251
252		sigOK := checkSigHashFlags(ps.Signature, &pInput)
253		if !sigOK {
254			return ErrInvalidSigHashFlags
255		}
256
257		sigs = append(sigs, ps.Signature)
258	}
259
260	// We have failed to identify at least 1 (sig, pub) pair in the PSBT,
261	// which indicates it was not ready to be finalized. As a result, we
262	// can't proceed.
263	if len(sigs) < 1 || len(pubKeys) < 1 {
264		return ErrNotFinalizable
265	}
266
267	// If this input doesn't need a redeem script (P2PKH), then we'll
268	// construct a simple sigScript that's just the signature then the
269	// pubkey (OP_CHECKSIG).
270	var err error
271	if !containsRedeemScript {
272		// At this point, we should only have a single signature and
273		// pubkey.
274		if len(sigs) != 1 || len(pubKeys) != 1 {
275			return ErrNotFinalizable
276		}
277
278		// In this case, our sigScript is just: <sig> <pubkey>.
279		builder := txscript.NewScriptBuilder()
280		builder.AddData(sigs[0]).AddData(pubKeys[0])
281		sigScript, err = builder.Script()
282		if err != nil {
283			return err
284		}
285	} else {
286		// This is assumed p2sh multisig Given redeemScript and pubKeys
287		// we can decide in what order signatures must be appended.
288		orderedSigs, err := extractKeyOrderFromScript(
289			pInput.RedeemScript, pubKeys, sigs,
290		)
291		if err != nil {
292			return err
293		}
294
295		// At this point, we assume that this is a mult-sig input, so
296		// we construct our sigScript which looks something like this
297		// (mind the extra element for the extra multi-sig pop):
298		//  * <nil> <sigs...> <redeemScript>
299		//
300		// TODO(waxwing): the below is specific to the multisig case.
301		builder := txscript.NewScriptBuilder()
302		builder.AddOp(txscript.OP_FALSE)
303		for _, os := range orderedSigs {
304			builder.AddData(os)
305		}
306		builder.AddData(pInput.RedeemScript)
307		sigScript, err = builder.Script()
308		if err != nil {
309			return err
310		}
311	}
312
313	// At this point, a sigScript has been constructed.  Remove all fields
314	// other than non-witness utxo (00) and finaliscriptsig (07)
315	newInput := NewPsbtInput(pInput.NonWitnessUtxo, nil)
316	newInput.FinalScriptSig = sigScript
317
318	// Overwrite the entry in the input list at the correct index. Note
319	// that this removes all the other entries in the list for this input
320	// index.
321	p.Inputs[inIndex] = *newInput
322
323	return nil
324}
325
326// finalizeWitnessInput attempts to create PsbtInFinalScriptSig field and
327// PsbtInFinalScriptWitness field for input at index inIndex, and removes all
328// other fields except for the utxo field, for an input of type witness, or
329// returns an error.
330func finalizeWitnessInput(p *Packet, inIndex int) error {
331	// If this input has already been finalized, then we'll return an error
332	// as we can't proceed.
333	if checkFinalScriptSigWitness(p, inIndex) {
334		return ErrInputAlreadyFinalized
335	}
336
337	// Depending on the actual output type, we'll either populate a
338	// serializedWitness or a witness as well asa sigScript.
339	var (
340		sigScript         []byte
341		serializedWitness []byte
342	)
343
344	pInput := p.Inputs[inIndex]
345
346	// First we'll validate and collect the pubkey+sig pairs from the set
347	// of partial signatures.
348	var (
349		pubKeys [][]byte
350		sigs    [][]byte
351	)
352	for _, ps := range pInput.PartialSigs {
353		pubKeys = append(pubKeys, ps.PubKey)
354
355		sigOK := checkSigHashFlags(ps.Signature, &pInput)
356		if !sigOK {
357			return ErrInvalidSigHashFlags
358
359		}
360
361		sigs = append(sigs, ps.Signature)
362	}
363
364	// If at this point, we don't have any pubkey+sig pairs, then we bail
365	// as we can't proceed.
366	if len(sigs) == 0 || len(pubKeys) == 0 {
367		return ErrNotFinalizable
368	}
369
370	containsRedeemScript := pInput.RedeemScript != nil
371	cointainsWitnessScript := pInput.WitnessScript != nil
372
373	// If there's no redeem script, then we assume that this is native
374	// segwit input.
375	var err error
376	if !containsRedeemScript {
377		// If we have only a sigley pubkey+sig pair, and no witness
378		// script, then we assume this is a P2WKH input.
379		if len(pubKeys) == 1 && len(sigs) == 1 &&
380			!cointainsWitnessScript {
381
382			serializedWitness, err = writePKHWitness(
383				sigs[0], pubKeys[0],
384			)
385			if err != nil {
386				return err
387			}
388		} else {
389			// Otherwise, we must have a witnessScript field, so
390			// we'll generate a valid multi-sig witness.
391			//
392			// NOTE: We tacitly assume multisig.
393			//
394			// TODO(roasbeef): need to add custom finalize for
395			// non-multisig P2WSH outputs (HTLCs, delay outputs,
396			// etc).
397			if !cointainsWitnessScript {
398				return ErrNotFinalizable
399			}
400
401			serializedWitness, err = getMultisigScriptWitness(
402				pInput.WitnessScript, pubKeys, sigs,
403			)
404			if err != nil {
405				return err
406			}
407		}
408	} else {
409		// Otherwise, we assume that this is a p2wsh multi-sig output,
410		// which is nested in a p2sh, or a p2wkh nested in a p2sh.
411		//
412		// In this case, we'll take the redeem script (the witness
413		// program in this case), and push it on the stack within the
414		// sigScript.
415		builder := txscript.NewScriptBuilder()
416		builder.AddData(pInput.RedeemScript)
417		sigScript, err = builder.Script()
418		if err != nil {
419			return err
420		}
421
422		// If don't have a witness script, then we assume this is a
423		// nested p2wkh output.
424		if !cointainsWitnessScript {
425			// Assumed p2sh-p2wkh Here the witness is just (sig,
426			// pub) as for p2pkh case
427			if len(sigs) != 1 || len(pubKeys) != 1 {
428				return ErrNotFinalizable
429			}
430
431			serializedWitness, err = writePKHWitness(sigs[0], pubKeys[0])
432			if err != nil {
433				return err
434			}
435
436		} else {
437			// Otherwise, we assume that this is a p2wsh multi-sig,
438			// so we generate the proper witness.
439			serializedWitness, err = getMultisigScriptWitness(
440				pInput.WitnessScript, pubKeys, sigs,
441			)
442			if err != nil {
443				return err
444			}
445		}
446	}
447
448	// At this point, a witness has been constructed, and a sigScript (if
449	// nested; else it's []). Remove all fields other than witness utxo
450	// (01) and finalscriptsig (07), finalscriptwitness (08).
451	newInput := NewPsbtInput(nil, pInput.WitnessUtxo)
452	if len(sigScript) > 0 {
453		newInput.FinalScriptSig = sigScript
454	}
455
456	newInput.FinalScriptWitness = serializedWitness
457
458	// Finally, we overwrite the entry in the input list at the correct
459	// index.
460	p.Inputs[inIndex] = *newInput
461	return nil
462}
463