Skip to content

Commit 172c5da

Browse files
committed
signpsbt: implement Taproot keyspend signing
1 parent f478242 commit 172c5da

File tree

2 files changed

+63
-7
lines changed

2 files changed

+63
-7
lines changed

cmd/chantools/signpsbt.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -172,24 +172,37 @@ func signPsbt(rootKey *hdkeychain.ExtendedKey,
172172
}
173173
utxo := pIn.WitnessUtxo
174174

175+
localPrivateKey, err := localKey.ECPrivKey()
176+
if err != nil {
177+
return fmt.Errorf("error getting private key: %w", err)
178+
}
179+
175180
// The signing is a bit different for P2WPKH, we need to specify
176181
// the pk script as the witness script.
177182
var witnessScript []byte
178-
if txscript.IsPayToWitnessPubKeyHash(utxo.PkScript) {
183+
switch {
184+
case txscript.IsPayToWitnessPubKeyHash(utxo.PkScript):
179185
witnessScript = utxo.PkScript
180-
} else {
186+
187+
case txscript.IsPayToTaproot(utxo.PkScript):
188+
err := signer.AddTaprootSignature(
189+
packet, inputIndex, utxo, localPrivateKey,
190+
)
191+
if err != nil {
192+
return fmt.Errorf("error adding taproot "+
193+
"signature: %w", err)
194+
}
195+
196+
continue
197+
198+
default:
181199
if len(pIn.WitnessScript) == 0 {
182200
return fmt.Errorf("invalid PSBT, input %d is "+
183201
"missing witness script", inputIndex)
184202
}
185203
witnessScript = pIn.WitnessScript
186204
}
187205

188-
localPrivateKey, err := localKey.ECPrivKey()
189-
if err != nil {
190-
return fmt.Errorf("error getting private key: %w", err)
191-
}
192-
193206
// Do we already have a partial signature for our key?
194207
localPubKey := localPrivateKey.PubKey().SerializeCompressed()
195208
haveSig := false

lnd/signer.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package lnd
22

33
import (
4+
"bytes"
45
"crypto/sha256"
56
"errors"
67
"fmt"
@@ -234,6 +235,48 @@ func (s *Signer) AddPartialSignatureForPrivateKey(packet *psbt.Packet,
234235
return nil
235236
}
236237

238+
func (s *Signer) AddTaprootSignature(packet *psbt.Packet, inputIndex int,
239+
utxo *wire.TxOut, privateKey *btcec.PrivateKey) error {
240+
241+
pIn := &packet.Inputs[inputIndex]
242+
243+
// Now we add our partial signature.
244+
prevOutFetcher := wallet.PsbtPrevOutputFetcher(packet)
245+
signDesc := &input.SignDescriptor{
246+
Output: utxo,
247+
InputIndex: inputIndex,
248+
HashType: txscript.SigHashDefault,
249+
PrevOutputFetcher: prevOutFetcher,
250+
SigHashes: txscript.NewTxSigHashes(
251+
packet.UnsignedTx, prevOutFetcher,
252+
),
253+
SignMethod: input.TaprootKeySpendBIP0086SignMethod,
254+
}
255+
256+
if len(pIn.TaprootMerkleRoot) > 0 {
257+
signDesc.SignMethod = input.TaprootKeySpendSignMethod
258+
signDesc.TapTweak = pIn.TaprootMerkleRoot
259+
}
260+
261+
ourSigRaw, err := s.SignOutputRawWithPrivateKey(
262+
packet.UnsignedTx, signDesc, privateKey,
263+
)
264+
if err != nil {
265+
return fmt.Errorf("error signing with our key: %w", err)
266+
}
267+
268+
witness := wire.TxWitness{ourSigRaw.Serialize()}
269+
var witnessBuf bytes.Buffer
270+
err = psbt.WriteTxWitness(&witnessBuf, witness)
271+
if err != nil {
272+
return fmt.Errorf("error serializing witness: %w", err)
273+
}
274+
275+
pIn.FinalScriptWitness = witnessBuf.Bytes()
276+
277+
return nil
278+
}
279+
237280
// maybeTweakPrivKey examines the single tweak parameters on the passed sign
238281
// descriptor and may perform a mapping on the passed private key in order to
239282
// utilize the tweaks, if populated.

0 commit comments

Comments
 (0)