Skip to content

Commit f5d98a2

Browse files
committed
hyperloop: add hyperloop script
1 parent 374fb41 commit f5d98a2

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

hyperloop/script.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package hyperloop
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/btcsuite/btcd/btcec/v2"
7+
"github.com/btcsuite/btcd/btcec/v2/schnorr"
8+
"github.com/btcsuite/btcd/txscript"
9+
"github.com/lightningnetwork/lnd/input"
10+
)
11+
12+
const (
13+
14+
// TaprootMultiSigWitnessSize evaluates to 66 bytes:
15+
// - num_witness_elements: 1 byte
16+
// - sig_varint_len: 1 byte
17+
// - <sig>: 64 bytes
18+
TaprootMultiSigWitnessSize = 1 + 1 + 64
19+
20+
// TaprootExpiryScriptSize evaluates to 39 bytes:
21+
// - OP_DATA: 1 byte (trader_key length)
22+
// - <trader_key>: 32 bytes
23+
// - OP_CHECKSIGVERIFY: 1 byte
24+
// - <reservation_expiry>: 4 bytes
25+
// - OP_CHECKLOCKTIMEVERIFY: 1 byte
26+
TaprootExpiryScriptSize = 1 + 32 + 1 + 4 + 1
27+
28+
// TaprootExpiryWitnessSize evaluates to 140 bytes:
29+
// - num_witness_elements: 1 byte
30+
// - trader_sig_varint_len: 1 byte (trader_sig length)
31+
// - <trader_sig>: 64 bytes
32+
// - witness_script_varint_len: 1 byte (script length)
33+
// - <witness_script>: 39 bytes
34+
// - control_block_varint_len: 1 byte (control block length)
35+
// - <control_block>: 33 bytes
36+
TaprootExpiryWitnessSize = 1 + 1 + 64 + 1 + TaprootExpiryScriptSize + 1 + 33
37+
)
38+
39+
func HyperLoopScript(expiry uint32, serverKey *btcec.PublicKey,
40+
clientKeys []*btcec.PublicKey) ([]byte, error) {
41+
42+
taprootKey, _, _, err := TaprootKey(expiry, serverKey, clientKeys)
43+
if err != nil {
44+
return nil, err
45+
}
46+
return PayToWitnessTaprootScript(taprootKey)
47+
}
48+
49+
// TaprootKey returns the aggregated MuSig2 combined internal key and the
50+
// tweaked Taproot key of an hyperloop output, as well as the expiry script tap
51+
// leaf.
52+
func TaprootKey(expiry uint32, serverKey *btcec.PublicKey,
53+
clientKeys []*btcec.PublicKey) (*btcec.PublicKey, *btcec.PublicKey,
54+
*txscript.TapLeaf, error) {
55+
56+
expiryLeaf, err := TaprootExpiryScript(expiry, serverKey)
57+
if err != nil {
58+
return nil, nil, nil, err
59+
}
60+
61+
rootHash := expiryLeaf.TapHash()
62+
63+
aggregateKey, err := input.MuSig2CombineKeys(
64+
input.MuSig2Version100RC2,
65+
clientKeys,
66+
true,
67+
&input.MuSig2Tweaks{
68+
TaprootTweak: rootHash[:],
69+
},
70+
)
71+
if err != nil {
72+
return nil, nil, nil, fmt.Errorf("error combining keys: %v", err)
73+
}
74+
75+
return aggregateKey.FinalKey, aggregateKey.PreTweakedKey, expiryLeaf, nil
76+
}
77+
78+
// PayToWitnessTaprootScript creates a new script to pay to a version 1
79+
// (taproot) witness program. The passed hash is expected to be valid.
80+
func PayToWitnessTaprootScript(taprootKey *btcec.PublicKey) ([]byte, error) {
81+
builder := txscript.NewScriptBuilder()
82+
83+
builder.AddOp(txscript.OP_1)
84+
builder.AddData(schnorr.SerializePubKey(taprootKey))
85+
86+
return builder.Script()
87+
}
88+
89+
// TaprootExpiryScript returns the leaf script of the expiry script path.
90+
//
91+
// <server_key> OP_CHECKSIGVERIFY <hyperloop_expiry> OP_CHECKSEQUENCEVERIFY.
92+
func TaprootExpiryScript(expiry uint32,
93+
serverKey *btcec.PublicKey) (*txscript.TapLeaf, error) {
94+
95+
builder := txscript.NewScriptBuilder()
96+
97+
builder.AddData(schnorr.SerializePubKey(serverKey))
98+
builder.AddOp(txscript.OP_CHECKSIGVERIFY)
99+
100+
builder.AddInt64(int64(expiry))
101+
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
102+
103+
script, err := builder.Script()
104+
if err != nil {
105+
return nil, err
106+
}
107+
108+
leaf := txscript.NewBaseTapLeaf(script)
109+
return &leaf, nil
110+
}
111+
112+
func ExpirySpendWeight() int64 {
113+
var weightEstimator input.TxWeightEstimator
114+
weightEstimator.AddWitnessInput(TaprootExpiryWitnessSize)
115+
116+
weightEstimator.AddP2TROutput()
117+
118+
return int64(weightEstimator.Weight())
119+
}

0 commit comments

Comments
 (0)