From 3142e98726499bfccdef71fe1706f4e492b91386 Mon Sep 17 00:00:00 2001 From: sputn1ck Date: Fri, 25 Aug 2023 01:29:57 +0200 Subject: [PATCH] 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. --- instantout/reservation/script/script.go | 122 ++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 instantout/reservation/script/script.go diff --git a/instantout/reservation/script/script.go b/instantout/reservation/script/script.go new file mode 100644 index 0000000..a86504f --- /dev/null +++ b/instantout/reservation/script/script.go @@ -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 + // - : 64 bytes + TaprootMultiSigWitnessSize = 1 + 1 + 64 + + // TaprootExpiryScriptSize evaluates to 39 bytes: + // - OP_DATA: 1 byte (trader_key length) + // - : 32 bytes + // - OP_CHECKSIGVERIFY: 1 byte + // - : 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) + // - : 64 bytes + // - witness_script_varint_len: 1 byte (script length) + // - : 39 bytes + // - control_block_varint_len: 1 byte (control block length) + // - : 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. +// +// OP_CHECKSIGVERIFY 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()) +}