Skip to content

Commit

Permalink
txauthor: add taproot address type
Browse files Browse the repository at this point in the history
  • Loading branch information
guggero committed Feb 16, 2022
1 parent 3ad07da commit 6e96598
Showing 1 changed file with 68 additions and 6 deletions.
74 changes: 68 additions & 6 deletions wallet/txauthor/author.go
Expand Up @@ -8,6 +8,7 @@ package txauthor
import (
"errors"

"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/txscript"
Expand Down Expand Up @@ -229,19 +230,32 @@ func AddAllInputScripts(tx *wire.MsgTx, prevPkScripts [][]byte,
// function which generates both the sigScript, and the witness
// script.
case txscript.IsPayToScriptHash(pkScript):
err := spendNestedWitnessPubKeyHash(inputs[i], pkScript,
int64(inputValues[i]), chainParams, secrets,
tx, hashCache, i)
err := spendNestedWitnessPubKeyHash(
inputs[i], pkScript, int64(inputValues[i]),
chainParams, secrets, tx, hashCache, i,
)
if err != nil {
return err
}

case txscript.IsPayToWitnessPubKeyHash(pkScript):
err := spendWitnessKeyHash(inputs[i], pkScript,
int64(inputValues[i]), chainParams, secrets,
tx, hashCache, i)
err := spendWitnessKeyHash(
inputs[i], pkScript, int64(inputValues[i]),
chainParams, secrets, tx, hashCache, i,
)
if err != nil {
return err
}

case txscript.IsPayToTaproot(pkScript):
err := spendTaprootKeyHash(
inputs[i], pkScript, int64(inputValues[i]),
chainParams, secrets, tx, hashCache, i,
)
if err != nil {
return err
}

default:
sigScript := inputs[i].SignatureScript
script, err := txscript.SignTxOutput(chainParams, tx, i,
Expand Down Expand Up @@ -309,6 +323,54 @@ func spendWitnessKeyHash(txIn *wire.TxIn, pkScript []byte,
return nil
}

// spendTaprootKey generates, and sets a valid witness for spending the passed
// pkScript with the specified input amount. The input amount *must*
// correspond to the output value of the previous pkScript, or else verification
// will fail since the new sighash digest algorithm defined in BIP0341 includes
// the input value in the sighash.
func spendTaprootKey(txIn *wire.TxIn, pkScript []byte,
inputValue int64, chainParams *chaincfg.Params, secrets SecretsSource,
tx *wire.MsgTx, hashCache *txscript.TxSigHashes, idx int) error {

// First obtain the key pair associated with this p2tr address.
_, addrs, _, err := txscript.ExtractPkScriptAddrs(pkScript, chainParams)
if err != nil {
return err
}
privKey, _, err := secrets.GetKey(addrs[0])
if err != nil {
return err
}
pubKey := privKey.PubKey()

tapKey := txscript.ComputeTaprootKeyNoScript(pubKey)
p2trAddr, err := btcutil.NewAddressTaproot(
schnorr.SerializePubKey(tapKey), chainParams,
)
if err != nil {
return err
}

// With the concrete address type, we can now generate the
// corresponding witness program to be used to generate a valid witness
// which will allow us to spend this output.
witnessProgram, err := txscript.PayToAddrScript(p2trAddr)
if err != nil {
return err
}
witnessScript, err := txscript.TaprootWitnessSignature(
tx, hashCache, idx, inputValue, witnessProgram,
txscript.SigHashDefault, privKey,
)
if err != nil {
return err
}

txIn.Witness = witnessScript

return nil
}

// spendNestedWitnessPubKey generates both a sigScript, and valid witness for
// spending the passed pkScript with the specified input amount. The generated
// sigScript is the version 0 p2wkh witness program corresponding to the queried
Expand Down

0 comments on commit 6e96598

Please sign in to comment.