input: add exhaustive unit tests for new taproot scripts

This commit is contained in:
Olaoluwa Osuntokun
2023-02-04 15:09:32 +02:00
parent b8d1596428
commit 5e921376c4
4 changed files with 2283 additions and 78 deletions

View File

@@ -554,19 +554,24 @@ func SenderHTLCTapLeafSuccess(receiverHtlcKey *btcec.PublicKey,
return txscript.NewBaseTapLeaf(successLeafScript), nil return txscript.NewBaseTapLeaf(successLeafScript), nil
} }
// HtlcScriptTree... // HtlcScriptTree holds the taproot output key, as well as the two script path
// leaves that every taproot HTLC script depends on.
type HtlcScriptTree struct { type HtlcScriptTree struct {
// TaprootKey... // TaprootKey is the key that will be used to generate the taproot output.
TaprootKey *btcec.PublicKey TaprootKey *btcec.PublicKey
// SuccessTapLeaf... // SuccessTapLeaf is the tapleaf for the redemption path.
SuccessTapLeaf txscript.TapLeaf SuccessTapLeaf txscript.TapLeaf
// TimeoutTapLeaf... // TimeoutTapLeaf is the tapleaf for the timeout path.
TimeoutTapLeaf txscript.TapLeaf TimeoutTapLeaf txscript.TapLeaf
// TapscriptTree... // TapscriptTree is the full tapscript tree that also includes the
// control block needed to spend each of the leaves.
TapscriptTree *txscript.IndexedTapScriptTree TapscriptTree *txscript.IndexedTapScriptTree
// TapscriptTreeRoot is the root hash of the tapscript tree.
TapscriptRoot []byte
} }
// senderHtlcTapScriptTree builds the tapscript tree which is used to anchor // senderHtlcTapScriptTree builds the tapscript tree which is used to anchor
@@ -608,6 +613,7 @@ func senderHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
SuccessTapLeaf: successTapLeaf, SuccessTapLeaf: successTapLeaf,
TimeoutTapLeaf: timeoutTapLeaf, TimeoutTapLeaf: timeoutTapLeaf,
TapscriptTree: tapscriptTree, TapscriptTree: tapscriptTree,
TapscriptRoot: tapScriptRoot[:],
}, nil }, nil
} }
@@ -654,7 +660,7 @@ func SenderHTLCScriptTaproot(senderHtlcKey, receiverHtlcKey,
// the sighash type isn't sighash default. // the sighash type isn't sighash default.
func maybeAppendSighash(sig Signature, sigHash txscript.SigHashType) []byte { func maybeAppendSighash(sig Signature, sigHash txscript.SigHashType) []byte {
sigBytes := sig.Serialize() sigBytes := sig.Serialize()
if sigHash != txscript.SigHashDefault { if sigHash == txscript.SigHashDefault {
return sigBytes return sigBytes
} }
@@ -1066,8 +1072,8 @@ func ReceiverHtlcTapLeafTimeout(senderHtlcKey *btcec.PublicKey,
// //
// OP_SIZE 32 OP_EQUALVERIFY OP_HASH160 // OP_SIZE 32 OP_EQUALVERIFY OP_HASH160
// <RIPEMD160(payment_hash)> OP_EQUALVERIFY // <RIPEMD160(payment_hash)> OP_EQUALVERIFY
// <local_htlcpubkey> OP_CHECKSIGVERIFY // <receiver_htlcpubkey> OP_CHECKSIGVERIFY
// <remote_htlcpubkey> OP_CHECKSIG // <sender_htlcpubkey> OP_CHECKSIG
func ReceiverHtlcTapLeafSuccess(receiverHtlcKey *btcec.PublicKey, func ReceiverHtlcTapLeafSuccess(receiverHtlcKey *btcec.PublicKey,
senderHtlcKey *btcec.PublicKey, senderHtlcKey *btcec.PublicKey,
paymentHash []byte) (txscript.TapLeaf, error) { paymentHash []byte) (txscript.TapLeaf, error) {
@@ -1115,7 +1121,7 @@ func receiverHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
return nil, err return nil, err
} }
timeoutTapLeaf, err := ReceiverHtlcTapLeafTimeout( timeoutTapLeaf, err := ReceiverHtlcTapLeafTimeout(
receiverHtlcKey, cltvExpiry, senderHtlcKey, cltvExpiry,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1140,6 +1146,7 @@ func receiverHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
SuccessTapLeaf: successTapLeaf, SuccessTapLeaf: successTapLeaf,
TimeoutTapLeaf: timeoutTapLeaf, TimeoutTapLeaf: timeoutTapLeaf,
TapscriptTree: tapscriptTree, TapscriptTree: tapscriptTree,
TapscriptRoot: tapScriptRoot[:],
}, nil }, nil
} }
@@ -1213,8 +1220,8 @@ func ReceiverHTLCScriptTaprootRedeem(senderSig Signature,
// The final witness stack is: // The final witness stack is:
// * <sender sig> <receiver sig> <preimage> <success_script> <control_block> // * <sender sig> <receiver sig> <preimage> <success_script> <control_block>
witnessStack := wire.TxWitness(make([][]byte, 5)) witnessStack := wire.TxWitness(make([][]byte, 5))
witnessStack[0] = append(senderSig.Serialize(), byte(senderSigHash)) witnessStack[0] = maybeAppendSighash(senderSig, senderSigHash)
witnessStack[1] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[1] = maybeAppendSighash(sweepSig, signDesc.HashType)
witnessStack[2] = paymentPreimage witnessStack[2] = paymentPreimage
witnessStack[3] = signDesc.WitnessScript witnessStack[3] = signDesc.WitnessScript
witnessStack[4], err = successControlBlock.ToBytes() witnessStack[4], err = successControlBlock.ToBytes()
@@ -1266,7 +1273,7 @@ func ReceiverHTLCScriptTaprootTimeout(signer Signer, signDesc *SignDescriptor,
// The final witness is pretty simple, we just need to present a valid // The final witness is pretty simple, we just need to present a valid
// signature for the script, and then provide the control block. // signature for the script, and then provide the control block.
witnessStack := make(wire.TxWitness, 3) witnessStack := make(wire.TxWitness, 3)
witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[0] = maybeAppendSighash(sweepSig, signDesc.HashType)
witnessStack[1] = signDesc.WitnessScript witnessStack[1] = signDesc.WitnessScript
witnessStack[2], err = timeoutControlBlock.ToBytes() witnessStack[2], err = timeoutControlBlock.ToBytes()
if err != nil { if err != nil {
@@ -1276,6 +1283,25 @@ func ReceiverHTLCScriptTaprootTimeout(signer Signer, signDesc *SignDescriptor,
return witnessStack, nil return witnessStack, nil
} }
// ReceiverHTLCScriptTaprootRevoke creates a valid witness needed to spend the
// revocation path of the HTLC from the PoV of the sender (offerer) of the
// HTLC. This uses a plain keyspend using the specified revocation key.
func ReceiverHTLCScriptTaprootRevoke(signer Signer, signDesc *SignDescriptor,
sweepTx *wire.MsgTx) (wire.TxWitness, error) {
sweepSig, err := signer.SignOutputRaw(sweepTx, signDesc)
if err != nil {
return nil, err
}
// The witness stack in this case is pretty simple: we only need to
// specify the signature generated.
witnessStack := make(wire.TxWitness, 1)
witnessStack[0] = maybeAppendSighash(sweepSig, signDesc.HashType)
return witnessStack, nil
}
// SecondLevelHtlcScript is the uniform script that's used as the output for // SecondLevelHtlcScript is the uniform script that's used as the output for
// the second-level HTLC transactions. The second level transaction act as a // the second-level HTLC transactions. The second level transaction act as a
// sort of covenant, ensuring that a 2-of-2 multi-sig output can only be // sort of covenant, ensuring that a 2-of-2 multi-sig output can only be
@@ -1457,7 +1483,7 @@ func TaprootHtlcSpendRevoke(signer Signer, signDesc *SignDescriptor,
// The witness stack in this case is pretty simple: we only need to // The witness stack in this case is pretty simple: we only need to
// specify the signature generated. // specify the signature generated.
witnessStack := make(wire.TxWitness, 1) witnessStack := make(wire.TxWitness, 1)
witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[0] = maybeAppendSighash(sweepSig, signDesc.HashType)
return witnessStack, nil return witnessStack, nil
} }
@@ -1494,7 +1520,7 @@ func TaprootHtlcSpendSuccess(signer Signer, signDesc *SignDescriptor,
// //
// <success sig> <success script> <control_block> // <success sig> <success script> <control_block>
witnessStack := make(wire.TxWitness, 3) witnessStack := make(wire.TxWitness, 3)
witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[0] = maybeAppendSighash(sweepSig, signDesc.HashType)
witnessStack[1] = signDesc.WitnessScript witnessStack[1] = signDesc.WitnessScript
witnessStack[2], err = redeemControlBlock.ToBytes() witnessStack[2], err = redeemControlBlock.ToBytes()
if err != nil { if err != nil {
@@ -1748,30 +1774,29 @@ func CommitScriptToSelf(csvTimeout uint32, selfKey, revokeKey *btcec.PublicKey)
return builder.Script() return builder.Script()
} }
// TaprootCommitScriptToSelf creates the taproot witness program that commits // CommitScript holds the taproot output key (in this case the revocation key,
// to the revocation (keyspend) and delay path (script path) in a single // or a NUMs point for the remote output) along with the tapscript leaf that
// taproot output key. // can spend the output after a delay.
// type CommitScriptTree struct {
// For the delay path we have the following tapscript leaf script: // TaprootKey is the key that will be used to generate the taproot
// // output.
// <local_delayedpubkey> OP_CHECKSIG TaprootKey *btcec.PublicKey
// <to_self_delay> OP_CHECKSEQUENCEVERIFY OP_DROP
// // SettleLeaf is the leaf used to settle the output after the delay.
// This can then be spent with just: SettleLeaf txscript.TapLeaf
//
// <local_delayedsig> <to_delay_script> <delay_control_block> // TapscriptTree is the full tapscript tree that also includes the
// // control block needed to spend each of the leaves.
// Where the to_delay_script is listed above, and the delay_control_block TapscriptTree *txscript.IndexedTapScriptTree
// computed as:
// // TapscriptTreeRoot is the root hash of the tapscript tree.
// delay_control_block = (output_key_y_parity | 0xc0) || revocationpubkey TapscriptRoot []byte
// }
// The revocation key spend path will simply present a valid signature with the
// witness being just: // NewLocalCommitScriptTree returns a new CommitScript tree that can be used to
// // create and spend the commitment output for the local party.
// <revocation_sig> func NewLocalCommitScriptTree(csvTimeout uint32,
func TaprootCommitScriptToSelf(csvTimeout uint32, selfKey, revokeKey *btcec.PublicKey) (*CommitScriptTree, error) {
selfKey, revokeKey *btcec.PublicKey) (*btcec.PublicKey, error) {
// First, we'll need to construct the tapLeaf that'll be our delay CSV // First, we'll need to construct the tapLeaf that'll be our delay CSV
// clause. // clause.
@@ -1801,7 +1826,104 @@ func TaprootCommitScriptToSelf(csvTimeout uint32,
revokeKey, tapScriptRoot[:], revokeKey, tapScriptRoot[:],
) )
return toLocalOutputKey, nil return &CommitScriptTree{
SettleLeaf: tapLeaf,
TaprootKey: toLocalOutputKey,
TapscriptTree: tapScriptTree,
TapscriptRoot: tapScriptRoot[:],
}, nil
}
// TaprootCommitScriptToSelf creates the taproot witness program that commits
// to the revocation (keyspend) and delay path (script path) in a single
// taproot output key.
//
// For the delay path we have the following tapscript leaf script:
//
// <local_delayedpubkey> OP_CHECKSIG
// <to_self_delay> OP_CHECKSEQUENCEVERIFY OP_DROP
//
// This can then be spent with just:
//
// <local_delayedsig> <to_delay_script> <delay_control_block>
//
// Where the to_delay_script is listed above, and the delay_control_block
// computed as:
//
// delay_control_block = (output_key_y_parity | 0xc0) || revocationpubkey
//
// The revocation key spend path will simply present a valid signature with the
// witness being just:
//
// <revocation_sig>
func TaprootCommitScriptToSelf(csvTimeout uint32,
selfKey, revokeKey *btcec.PublicKey) (*btcec.PublicKey, error) {
commitScriptTree, err := NewLocalCommitScriptTree(
csvTimeout, selfKey, revokeKey,
)
if err != nil {
return nil, err
}
return commitScriptTree.TaprootKey, nil
}
// TaprootCommitSpendSuccess constructs a valid witness allowing a node to
// sweep the settled taproot output after the delay has passed for a force
// close.
func TaprootCommitSpendSuccess(signer Signer, signDesc *SignDescriptor,
sweepTx *wire.MsgTx, revokeKey *btcec.PublicKey,
scriptTree *txscript.IndexedTapScriptTree) (wire.TxWitness, error) {
// First, we'll need to construct a valid control block to execute the
// leaf script for sweep settlement.
settleTapleafHash := txscript.NewBaseTapLeaf(
signDesc.WitnessScript,
).TapHash()
settleIdx := scriptTree.LeafProofIndex[settleTapleafHash]
settleMerkleProof := scriptTree.LeafMerkleProofs[settleIdx]
settleControlBlock := settleMerkleProof.ToControlBlock(revokeKey)
// With the control block created, we'll now generate the signature we
// need to authorize the spend.
sweepSig, err := signer.SignOutputRaw(sweepTx, signDesc)
if err != nil {
return nil, err
}
// The final witness stack will be:
//
// <sweep sig> <sweep script> <control block>
witnessStack := make(wire.TxWitness, 3)
witnessStack[0] = maybeAppendSighash(sweepSig, signDesc.HashType)
witnessStack[1] = signDesc.WitnessScript
witnessStack[2], err = settleControlBlock.ToBytes()
if err != nil {
return nil, err
}
return witnessStack, nil
}
// TaprootCommitSpendRevoke constructs a valid witness allowing a node to sweep
// the revoked taproot output of a malicious peer.
func TaprootCommitSpendRevoke(signer Signer, signDesc *SignDescriptor,
revokeTx *wire.MsgTx) (wire.TxWitness, error) {
// For this spend type, we only need a single signature which'll be a
// keyspend using the revoke private key.
sweepSig, err := signer.SignOutputRaw(revokeTx, signDesc)
if err != nil {
return nil, err
}
// The witness stack in this case is pretty simple: we only need to
// specify the signature generated.
witnessStack := make(wire.TxWitness, 1)
witnessStack[0] = maybeAppendSighash(sweepSig, signDesc.HashType)
return witnessStack, nil
} }
// LeaseCommitScriptToSelf constructs the public key script for the output on the // LeaseCommitScriptToSelf constructs the public key script for the output on the
@@ -2018,26 +2140,10 @@ func CommitScriptToRemoteConfirmed(key *btcec.PublicKey) ([]byte, error) {
return builder.Script() return builder.Script()
} }
// TaprootCommitScriptToRemote constructs a taproot witness program for the // NewRemoteCommitScriptTree constructs a new script tree for the remote party
// output on the commitment transaction for the remote party. For the top level // to sweep their funds after a hard coded 1 block delay.
// key spend, we'll use the combined funding key (musig2.KeyAgg(k1, k2)), as a func NewRemoteCommitScriptTree(numsKey,
// sort of practical NUMs point (the local party would never sign for this). We remoteKey *btcec.PublicKey) (*CommitScriptTree, error) {
// then commit to a single tapscript leaf that holds the normal CSV 1 delay
// script.
//
// Our single tapleaf will use the following script:
//
// <remotepubkey> OP_CHECKSIG
// OP_CHECKSEQUENCEVERIFY
//
// The CSV clause is a bit subtle, but OP_CHECKSIG will return true if it
// succeeds, which then enforces our 1 CSV. The true will remain on the stack,
// causing the script to pass. If the CHECKSIG fails, then a 0 will remain on
// the stack.
//
// TODO(roasbeef): double check here can't pass additional stack elements?
func TaprootCommitScriptToRemote(combinedFundingKey,
remoteKey *btcec.PublicKey) (*btcec.PublicKey, error) {
// First, construct the remote party's tapscript they'll use to sweep their // First, construct the remote party's tapscript they'll use to sweep their
// outputs. // outputs.
@@ -2060,10 +2166,82 @@ func TaprootCommitScriptToRemote(combinedFundingKey,
// Now that we have our root, we can arrive at the final output script // Now that we have our root, we can arrive at the final output script
// by tweaking the internal key with this root. // by tweaking the internal key with this root.
toRemoteOutputKey := txscript.ComputeTaprootOutputKey( toRemoteOutputKey := txscript.ComputeTaprootOutputKey(
combinedFundingKey, tapScriptRoot[:], numsKey, tapScriptRoot[:],
) )
return toRemoteOutputKey, nil return &CommitScriptTree{
TaprootKey: toRemoteOutputKey,
SettleLeaf: tapLeaf,
TapscriptTree: tapScriptTree,
TapscriptRoot: tapScriptRoot[:],
}, nil
}
// TaprootCommitScriptToRemote constructs a taproot witness program for the
// output on the commitment transaction for the remote party. For the top level
// key spend, we'll use the combined funding key (musig2.KeyAgg(k1, k2)), as a
// sort of practical NUMs point (the local party would never sign for this). We
// then commit to a single tapscript leaf that holds the normal CSV 1 delay
// script.
//
// Our single tapleaf will use the following script:
//
// <remotepubkey> OP_CHECKSIG
// OP_CHECKSEQUENCEVERIFY
//
// The CSV clause is a bit subtle, but OP_CHECKSIG will return true if it
// succeeds, which then enforces our 1 CSV. The true will remain on the stack,
// causing the script to pass. If the CHECKSIG fails, then a 0 will remain on
// the stack.
//
// TODO(roasbeef): double check here can't pass additional stack elements?
func TaprootCommitScriptToRemote(combinedFundingKey,
remoteKey *btcec.PublicKey) (*btcec.PublicKey, error) {
commitScriptTree, err := NewRemoteCommitScriptTree(
combinedFundingKey, remoteKey,
)
if err != nil {
return nil, err
}
return commitScriptTree.TaprootKey, nil
}
// TaprootCommitRemoteSpend allows the remote party to sweep their output into
// their wallet after an enforced 1 block delay.
func TaprootCommitRemoteSpend(signer Signer, signDesc *SignDescriptor,
sweepTx *wire.MsgTx, numsKey *btcec.PublicKey,
scriptTree *txscript.IndexedTapScriptTree) (wire.TxWitness, error) {
// First, we'll need to construct a valid control block to execute the
// leaf script for sweep settlement.
settleTapleafHash := txscript.NewBaseTapLeaf(
signDesc.WitnessScript,
).TapHash()
settleIdx := scriptTree.LeafProofIndex[settleTapleafHash]
settleMerkleProof := scriptTree.LeafMerkleProofs[settleIdx]
settleControlBlock := settleMerkleProof.ToControlBlock(numsKey)
// With the control block created, we'll now generate the signature we
// need to authorize the spend.
sweepSig, err := signer.SignOutputRaw(sweepTx, signDesc)
if err != nil {
return nil, err
}
// The final witness stack will be:
//
// <sweep sig> <sweep script> <control block>
witnessStack := make(wire.TxWitness, 3)
witnessStack[0] = maybeAppendSighash(sweepSig, signDesc.HashType)
witnessStack[1] = signDesc.WitnessScript
witnessStack[2], err = settleControlBlock.ToBytes()
if err != nil {
return nil, err
}
return witnessStack, nil
} }
// LeaseCommitScriptToRemoteConfirmed constructs the script for the output on // LeaseCommitScriptToRemoteConfirmed constructs the script for the output on
@@ -2164,15 +2342,29 @@ func CommitScriptAnchor(key *btcec.PublicKey) ([]byte, error) {
return builder.Script() return builder.Script()
} }
// TaprootOutputKeyAnchor returns the segwit v1 (taproot) witness program that // AnchorScriptTree holds all the contents needed to to sweep a taproot anchor
// encodes the anchor output spending conditions: the passed key can be used // output on chain.
// for keyspend, with the OP_CSV 16 clause living within an internal tapscript
// leaf.
// //
// Spend paths: // TODO(roasbeef): refactor trees to reduce dedup
// - Key spend: <key_signature> type AnchorScriptTree struct {
// - Script spend: OP_16 CSV <control_block> // TaprootKey is the key that will be used to generate the taproot
func TaprootOutputKeyAnchor(key *btcec.PublicKey) (*btcec.PublicKey, error) { // output.
TaprootKey *btcec.PublicKey
// SweepLeaf is the leaf used to settle the output after the delay.
SweepLeaf txscript.TapLeaf
// TapscriptTree is the full tapscript tree that also includes the
// control block needed to spend each of the leaves.
TapscriptTree *txscript.IndexedTapScriptTree
// TapscriptTreeRoot is the root hash of the tapscript tree.
TapscriptRoot []byte
}
// NewAnchorScriptTree makes a new script tree for an anchor output with the
// passed anchor key.
func NewAnchorScriptTree(anchorKey *btcec.PublicKey) (*AnchorScriptTree, error) {
// The main script used is just a OP_16 CSV (anyone can sweep after 16 // The main script used is just a OP_16 CSV (anyone can sweep after 16
// blocks). // blocks).
builder := txscript.NewScriptBuilder() builder := txscript.NewScriptBuilder()
@@ -2192,11 +2384,83 @@ func TaprootOutputKeyAnchor(key *btcec.PublicKey) (*btcec.PublicKey, error) {
// Now that we have our root, we can arrive at the final output script // Now that we have our root, we can arrive at the final output script
// by tweaking the internal key with this root. // by tweaking the internal key with this root.
anchorKey := txscript.ComputeTaprootOutputKey( anchorOutputKey := txscript.ComputeTaprootOutputKey(
key, tapScriptRoot[:], anchorKey, tapScriptRoot[:],
) )
return anchorKey, nil return &AnchorScriptTree{
TaprootKey: anchorOutputKey,
SweepLeaf: tapLeaf,
TapscriptTree: tapScriptTree,
TapscriptRoot: tapScriptRoot[:],
}, nil
}
// TaprootOutputKeyAnchor returns the segwit v1 (taproot) witness program that
// encodes the anchor output spending conditions: the passed key can be used
// for keyspend, with the OP_CSV 16 clause living within an internal tapscript
// leaf.
//
// Spend paths:
// - Key spend: <key_signature>
// - Script spend: OP_16 CSV <control_block>
func TaprootOutputKeyAnchor(key *btcec.PublicKey) (*btcec.PublicKey, error) {
anchorScriptTree, err := NewAnchorScriptTree(key)
if err != nil {
return nil, err
}
return anchorScriptTree.TaprootKey, nil
}
// TaprootAnchorSpend constructs a valid witness allowing a node to sweep their
// anchor output.
func TaprootAnchorSpend(signer Signer, signDesc *SignDescriptor,
revokeTx *wire.MsgTx) (wire.TxWitness, error) {
// For this spend type, we only need a single signature which'll be a
// keyspend using the revoke private key.
sweepSig, err := signer.SignOutputRaw(revokeTx, signDesc)
if err != nil {
return nil, err
}
// The witness stack in this case is pretty simple: we only need to
// specify the signature generated.
witnessStack := make(wire.TxWitness, 1)
witnessStack[0] = maybeAppendSighash(sweepSig, signDesc.HashType)
return witnessStack, nil
}
// TaprootAnchorSpendAny constructs a valid witness allowing anyone to sweep
// the anchor output after 16 blocks.
func TaprootAnchorSpendAny(anchorKey *btcec.PublicKey) (wire.TxWitness, error) {
anchorScriptTree, err := NewAnchorScriptTree(anchorKey)
if err != nil {
return nil, err
}
// For this spend, the only thing we need to do is create a valid
// control block. Other than that, there're no restrictions to how the
// output can be spent.
scriptTree := anchorScriptTree.TapscriptTree
sweepLeaf := anchorScriptTree.SweepLeaf
sweepIdx := scriptTree.LeafProofIndex[sweepLeaf.TapHash()]
sweepMerkleProof := scriptTree.LeafMerkleProofs[sweepIdx]
sweepControlBlock := sweepMerkleProof.ToControlBlock(anchorKey)
// The final witness stack will be:
//
// <sweep script> <control block>
witnessStack := make(wire.TxWitness, 2)
witnessStack[0] = sweepLeaf.Script
witnessStack[1], err = sweepControlBlock.ToBytes()
if err != nil {
return nil, err
}
return witnessStack, nil
} }
// CommitSpendAnchor constructs a valid witness allowing a node to spend their // CommitSpendAnchor constructs a valid witness allowing a node to spend their

View File

@@ -52,7 +52,7 @@ func assertEngineExecution(t *testing.T, testNum int, valid bool,
if err != nil { if err != nil {
t.Fatalf("stepping (%v)\n", err) t.Fatalf("stepping (%v)\n", err)
} }
debugBuf.WriteString(fmt.Sprintf("stepping %v\n", dis)) debugBuf.WriteString(fmt.Sprintf("Stepping %v\n", dis))
done, err = vm.Step() done, err = vm.Step()
if err != nil && valid { if err != nil && valid {
@@ -65,8 +65,11 @@ func assertEngineExecution(t *testing.T, testNum int, valid bool,
"should be invalid: %v", testNum, err) "should be invalid: %v", testNum, err)
} }
debugBuf.WriteString(fmt.Sprintf("Stack: %v", vm.GetStack())) debugBuf.WriteString(fmt.Sprintf("Stack: %v\n",
debugBuf.WriteString(fmt.Sprintf("AltStack: %v", vm.GetAltStack())) vm.GetStack()))
debugBuf.WriteString(fmt.Sprintf("AltStack: %v\n",
vm.GetAltStack()))
debugBuf.WriteString("-----\n")
} }
// If we get to this point the unexpected case was not reached // If we get to this point the unexpected case was not reached

1877
input/taproot_test.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -72,9 +72,70 @@ func (m *MockSigner) SignOutputRaw(tx *wire.MsgTx,
return nil, fmt.Errorf("mock signer does not have key") return nil, fmt.Errorf("mock signer does not have key")
} }
sig, err := txscript.RawTxInWitnessSignature(tx, signDesc.SigHashes, // In case of a taproot output any signature is always a Schnorr
signDesc.InputIndex, signDesc.Output.Value, signDesc.WitnessScript, // signature, based on the new tapscript sighash algorithm.
signDesc.HashType, privKey) //
// TODO(roasbeef): should conslidate with btcwallet/signer.go
if txscript.IsPayToTaproot(signDesc.Output.PkScript) {
sigHashes := txscript.NewTxSigHashes(
tx, signDesc.PrevOutputFetcher,
)
witnessScript := signDesc.WitnessScript
// Are we spending a script path or the key path? The API is
// slightly different, so we need to account for that to get the
// raw signature.
var (
rawSig []byte
err error
)
switch signDesc.SignMethod {
case TaprootKeySpendBIP0086SignMethod,
TaprootKeySpendSignMethod:
// This function tweaks the private key using the tap
// root key supplied as the tweak.
rawSig, err = txscript.RawTxInTaprootSignature(
tx, sigHashes, signDesc.InputIndex,
signDesc.Output.Value, signDesc.Output.PkScript,
signDesc.TapTweak, signDesc.HashType,
privKey,
)
if err != nil {
return nil, err
}
case TaprootScriptSpendSignMethod:
leaf := txscript.TapLeaf{
LeafVersion: txscript.BaseLeafVersion,
Script: witnessScript,
}
rawSig, err = txscript.RawTxInTapscriptSignature(
tx, sigHashes, signDesc.InputIndex,
signDesc.Output.Value, signDesc.Output.PkScript,
leaf, signDesc.HashType, privKey,
)
if err != nil {
return nil, err
}
}
sig, err := schnorr.ParseSignature(
rawSig[:schnorr.SignatureSize],
)
if err != nil {
return nil, err
}
return sig, nil
}
sig, err := txscript.RawTxInWitnessSignature(
tx, signDesc.SigHashes, signDesc.InputIndex,
signDesc.Output.Value, signDesc.WitnessScript,
signDesc.HashType, privKey,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }