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