reservation: add reservation script

This commit adds the reservation script file.
This file contains the neccessary function to create the
reservation script and addresses from the
pubkeys and expiry.
This commit is contained in:
sputn1ck 2023-08-25 01:29:57 +02:00
parent 23b818e436
commit 3142e98726
No known key found for this signature in database
GPG key ID: 671103D881A5F0E4

View file

@ -0,0 +1,122 @@
package script
import (
"fmt"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
"github.com/btcsuite/btcd/txscript"
"github.com/lightningnetwork/lnd/input"
)
const (
// TaprootMultiSigWitnessSize evaluates to 66 bytes:
// - num_witness_elements: 1 byte
// - sig_varint_len: 1 byte
// - <sig>: 64 bytes
TaprootMultiSigWitnessSize = 1 + 1 + 64
// TaprootExpiryScriptSize evaluates to 39 bytes:
// - OP_DATA: 1 byte (trader_key length)
// - <trader_key>: 32 bytes
// - OP_CHECKSIGVERIFY: 1 byte
// - <reservation_expiry>: 4 bytes
// - OP_CHECKLOCKTIMEVERIFY: 1 byte
TaprootExpiryScriptSize = 1 + 32 + 1 + 4 + 1
// TaprootExpiryWitnessSize evaluates to 140 bytes:
// - num_witness_elements: 1 byte
// - trader_sig_varint_len: 1 byte (trader_sig length)
// - <trader_sig>: 64 bytes
// - witness_script_varint_len: 1 byte (script length)
// - <witness_script>: 39 bytes
// - control_block_varint_len: 1 byte (control block length)
// - <control_block>: 33 bytes
TaprootExpiryWitnessSize = 1 + 1 + 64 + 1 + TaprootExpiryScriptSize + 1 + 33
)
// ReservationScript returns the tapscript pkscript for the given reservation
// parameters.
func ReservationScript(expiry uint32, serverKey,
clientKey *btcec.PublicKey) ([]byte, error) {
aggregatedKey, err := TaprootKey(expiry, serverKey, clientKey)
if err != nil {
return nil, err
}
return PayToWitnessTaprootScript(aggregatedKey.FinalKey)
}
// TaprootKey returns the aggregated MuSig2 combined key.
func TaprootKey(expiry uint32, serverKey,
clientKey *btcec.PublicKey) (*musig2.AggregateKey, error) {
expiryLeaf, err := TaprootExpiryScript(expiry, serverKey)
if err != nil {
return nil, err
}
rootHash := expiryLeaf.TapHash()
aggregateKey, err := input.MuSig2CombineKeys(
input.MuSig2Version100RC2,
[]*btcec.PublicKey{
clientKey, serverKey,
}, true,
&input.MuSig2Tweaks{
TaprootTweak: rootHash[:],
},
)
if err != nil {
return nil, fmt.Errorf("error combining keys: %v", err)
}
return aggregateKey, nil
}
// PayToWitnessTaprootScript creates a new script to pay to a version 1
// (taproot) witness program.
func PayToWitnessTaprootScript(taprootKey *btcec.PublicKey) ([]byte, error) {
builder := txscript.NewScriptBuilder()
builder.AddOp(txscript.OP_1)
builder.AddData(schnorr.SerializePubKey(taprootKey))
return builder.Script()
}
// TaprootExpiryScript returns the leaf script of the expiry script path.
//
// <server_key> OP_CHECKSIGVERIFY <reservation_expiry> OP_CHECKLOCKTIMEVERIFY.
func TaprootExpiryScript(expiry uint32,
serverKey *btcec.PublicKey) (*txscript.TapLeaf, error) {
builder := txscript.NewScriptBuilder()
builder.AddData(schnorr.SerializePubKey(serverKey))
builder.AddOp(txscript.OP_CHECKSIGVERIFY)
builder.AddInt64(int64(expiry))
builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY)
script, err := builder.Script()
if err != nil {
return nil, err
}
leaf := txscript.NewBaseTapLeaf(script)
return &leaf, nil
}
// ExpirySpendWeight returns the weight of the expiry path spend.
func ExpirySpendWeight() int64 {
var weightEstimator input.TxWeightEstimator
weightEstimator.AddWitnessInput(TaprootExpiryWitnessSize)
weightEstimator.AddP2TROutput()
return int64(weightEstimator.Weight())
}