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