Skip to content

Commit 478e2bb

Browse files
committed
rpcserver+tapscript: pre-fill and use key info from vPSBT
When signing a virtual PSBT, we don't want to use the key descriptor info of the input asset's script key, as that information is not available when the input asset is created from a de-serialized asset. So previous to the change in this commit the SignVirtualPsbt RPC method could only be called on vPSBTs that were funded through FundVirtualPsbt that populated the key information. After this commit it is possible to sign a vPSBT that was created from an input proof only since the required key information is loaded from the database before signing.
1 parent c94b5b8 commit 478e2bb

File tree

2 files changed

+50
-9
lines changed

2 files changed

+50
-9
lines changed

rpcserver.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1707,7 +1707,7 @@ func (r *rpcServer) FundVirtualPsbt(ctx context.Context,
17071707

17081708
// SignVirtualPsbt signs the inputs of a virtual transaction and prepares the
17091709
// commitments of the inputs and outputs.
1710-
func (r *rpcServer) SignVirtualPsbt(_ context.Context,
1710+
func (r *rpcServer) SignVirtualPsbt(ctx context.Context,
17111711
req *wrpc.SignVirtualPsbtRequest) (*wrpc.SignVirtualPsbtResponse,
17121712
error) {
17131713

@@ -1722,6 +1722,43 @@ func (r *rpcServer) SignVirtualPsbt(_ context.Context,
17221722
return nil, fmt.Errorf("error decoding packet: %w", err)
17231723
}
17241724

1725+
// Make sure the input keys are known.
1726+
for _, input := range vPkt.Inputs {
1727+
// If we have all the derivation information, we don't need to
1728+
// do anything.
1729+
if len(input.Bip32Derivation) > 0 &&
1730+
len(input.TaprootBip32Derivation) > 0 {
1731+
1732+
continue
1733+
}
1734+
1735+
scriptKey := input.Asset().ScriptKey
1736+
1737+
// If the full tweaked script key isn't set on the asset, we
1738+
// need to look it up in the local database, to make sure we'll
1739+
// be able to sign for it.
1740+
if scriptKey.TweakedScriptKey == nil {
1741+
tweakedScriptKey, err := r.cfg.AssetWallet.FetchScriptKey(
1742+
ctx, scriptKey.PubKey,
1743+
)
1744+
if err != nil {
1745+
return nil, fmt.Errorf("error fetching "+
1746+
"script key: %w", err)
1747+
}
1748+
1749+
scriptKey.TweakedScriptKey = tweakedScriptKey
1750+
}
1751+
1752+
derivation, trDerivation := tappsbt.Bip32DerivationFromKeyDesc(
1753+
scriptKey.TweakedScriptKey.RawKey,
1754+
r.cfg.ChainParams.HDCoinType,
1755+
)
1756+
input.Bip32Derivation = []*psbt.Bip32Derivation{derivation}
1757+
input.TaprootBip32Derivation = []*psbt.TaprootBip32Derivation{
1758+
trDerivation,
1759+
}
1760+
}
1761+
17251762
signedInputs, err := r.cfg.AssetWallet.SignVirtualPacket(vPkt)
17261763
if err != nil {
17271764
return nil, fmt.Errorf("error signing packet: %w", err)

tapscript/tx.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"github.com/lightninglabs/taproot-assets/mssmt"
1818
"github.com/lightninglabs/taproot-assets/tappsbt"
1919
"github.com/lightningnetwork/lnd/input"
20-
"github.com/lightningnetwork/lnd/keychain"
2120
)
2221

2322
var (
@@ -320,7 +319,14 @@ func CreateTaprootSignature(vIn *tappsbt.VInput, virtualTx *wire.MsgTx,
320319
"one at a time")
321320
}
322321

323-
derivation := vIn.TaprootBip32Derivation[0]
322+
derivation := vIn.Bip32Derivation[0]
323+
trDerivation := vIn.TaprootBip32Derivation[0]
324+
325+
keyDesc, err := tappsbt.KeyDescFromBip32Derivation(derivation)
326+
if err != nil {
327+
return nil, fmt.Errorf("error identifying input asset key "+
328+
"descriptor from BIP-0032 derivation: %w", err)
329+
}
324330

325331
// Compute a virtual prevOut from the input asset for the signer.
326332
prevOut, err := InputAssetPrevOut(*vIn.Asset())
@@ -331,9 +337,7 @@ func CreateTaprootSignature(vIn *tappsbt.VInput, virtualTx *wire.MsgTx,
331337
// Start with a default sign descriptor and the BIP-0086 sign method
332338
// then adjust depending on the input parameters.
333339
spendDesc := lndclient.SignDescriptor{
334-
KeyDesc: keychain.KeyDescriptor{
335-
PubKey: vIn.Asset().ScriptKey.RawKey.PubKey,
336-
},
340+
KeyDesc: keyDesc,
337341
SignMethod: input.TaprootKeySpendBIP0086SignMethod,
338342
Output: prevOut,
339343
HashType: vIn.SighashType,
@@ -350,7 +354,7 @@ func CreateTaprootSignature(vIn *tappsbt.VInput, virtualTx *wire.MsgTx,
350354
// No leaf hash means we're not signing a specific script, so this is
351355
// the key spend path with a script root.
352356
case len(vIn.TaprootMerkleRoot) == sha256.Size &&
353-
len(derivation.LeafHashes) == 0:
357+
len(trDerivation.LeafHashes) == 0:
354358

355359
spendDesc.SignMethod = input.TaprootKeySpendSignMethod
356360
spendDesc.TapTweak = vIn.TaprootMerkleRoot
@@ -359,7 +363,7 @@ func CreateTaprootSignature(vIn *tappsbt.VInput, virtualTx *wire.MsgTx,
359363
// script. There can be other scripts in the tree, but we only support
360364
// creating a signature for a single one at a time.
361365
case len(vIn.TaprootMerkleRoot) == sha256.Size &&
362-
len(derivation.LeafHashes) == 1:
366+
len(trDerivation.LeafHashes) == 1:
363367

364368
// If we're supposed to be signing for a leaf hash, we also
365369
// expect the leaf script that hashes to that hash in the
@@ -376,7 +380,7 @@ func CreateTaprootSignature(vIn *tappsbt.VInput, virtualTx *wire.MsgTx,
376380
Script: leafScript.Script,
377381
}
378382
leafHash := leaf.TapHash()
379-
if !bytes.Equal(leafHash[:], derivation.LeafHashes[0]) {
383+
if !bytes.Equal(leafHash[:], trDerivation.LeafHashes[0]) {
380384
return nil, fmt.Errorf("specified leaf hash in " +
381385
"taproot BIP-0032 derivation but " +
382386
"corresponding taproot leaf script was not " +

0 commit comments

Comments
 (0)