forked from wakiyamap/monad
-
Notifications
You must be signed in to change notification settings - Fork 4
/
taproot.go
207 lines (172 loc) · 6.42 KB
/
taproot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package psbt
import (
"bytes"
"github.com/monasuite/monad/btcec/v2/schnorr"
"github.com/monasuite/monad/txscript"
"github.com/monasuite/monad/wire"
)
const (
// schnorrSigMinLength is the minimum length of a Schnorr signature
// which is 64 bytes.
schnorrSigMinLength = schnorr.SignatureSize
// schnorrSigMaxLength is the maximum length of a Schnorr signature
// which is 64 bytes plus one byte for the appended sighash flag.
schnorrSigMaxLength = schnorrSigMinLength + 1
)
// TaprootScriptSpendSig encapsulates an individual Schnorr signature for a
// given public key and leaf hash.
type TaprootScriptSpendSig struct {
XOnlyPubKey []byte
LeafHash []byte
Signature []byte
SigHash txscript.SigHashType
}
// checkValid checks that both the pubkey and the signature are valid.
func (s *TaprootScriptSpendSig) checkValid() bool {
return validateXOnlyPubkey(s.XOnlyPubKey) &&
validateSchnorrSignature(s.Signature)
}
// EqualKey returns true if this script spend signature's key data is the same
// as the given script spend signature.
func (s *TaprootScriptSpendSig) EqualKey(other *TaprootScriptSpendSig) bool {
return bytes.Equal(s.XOnlyPubKey, other.XOnlyPubKey) &&
bytes.Equal(s.LeafHash, other.LeafHash)
}
// SortBefore returns true if this script spend signature's key is
// lexicographically smaller than the given other script spend signature's key
// and should come first when being sorted.
func (s *TaprootScriptSpendSig) SortBefore(other *TaprootScriptSpendSig) bool {
return bytes.Compare(s.XOnlyPubKey, other.XOnlyPubKey) < 0 &&
bytes.Compare(s.LeafHash, other.LeafHash) < 0
}
// TaprootTapLeafScript represents a single taproot leaf script that is
// identified by its control block.
type TaprootTapLeafScript struct {
ControlBlock []byte
Script []byte
LeafVersion txscript.TapscriptLeafVersion
}
// checkValid checks that the control block is valid.
func (s *TaprootTapLeafScript) checkValid() bool {
return validateControlBlock(s.ControlBlock)
}
// SortBefore returns true if this leaf script's key is lexicographically
// smaller than the given other leaf script's key and should come first when
// being sorted.
func (s *TaprootTapLeafScript) SortBefore(other *TaprootTapLeafScript) bool {
return bytes.Compare(s.ControlBlock, other.ControlBlock) < 0
}
// TaprootBip32Derivation encapsulates the data for the input and output
// taproot specific BIP-32 derivation key-value fields.
type TaprootBip32Derivation struct {
// XOnlyPubKey is the raw public key serialized in the x-only BIP-340
// format.
XOnlyPubKey []byte
// LeafHashes is a list of leaf hashes that the given public key is
// involved in.
LeafHashes [][]byte
// MasterKeyFingerprint is the fingerprint of the master pubkey.
MasterKeyFingerprint uint32
// Bip32Path is the BIP 32 path with child index as a distinct integer.
Bip32Path []uint32
}
// SortBefore returns true if this derivation info's key is lexicographically
// smaller than the given other derivation info's key and should come first when
// being sorted.
func (s *TaprootBip32Derivation) SortBefore(other *TaprootBip32Derivation) bool {
return bytes.Compare(s.XOnlyPubKey, other.XOnlyPubKey) < 0
}
// ReadTaprootBip32Derivation deserializes a byte slice containing the Taproot
// BIP32 derivation info that consists of a list of leaf hashes as well as the
// normal BIP32 derivation info.
func ReadTaprootBip32Derivation(xOnlyPubKey,
value []byte) (*TaprootBip32Derivation, error) {
// The taproot key BIP 32 derivation path is defined as:
// <hashes len> <leaf hash>* <4 byte fingerprint> <32-bit uint>*
// So we get at least 5 bytes for the length and the 4 byte fingerprint.
if len(value) < 5 {
return nil, ErrInvalidPsbtFormat
}
// The first element is the number of hashes that will follow.
reader := bytes.NewReader(value)
numHashes, err := wire.ReadVarInt(reader, 0)
if err != nil {
return nil, ErrInvalidPsbtFormat
}
// A hash is 32 bytes in size, so we need at least numHashes*32 + 5
// bytes to be present.
if len(value) < (int(numHashes)*32)+5 {
return nil, ErrInvalidPsbtFormat
}
derivation := TaprootBip32Derivation{
XOnlyPubKey: xOnlyPubKey,
LeafHashes: make([][]byte, int(numHashes)),
}
for i := 0; i < int(numHashes); i++ {
derivation.LeafHashes[i] = make([]byte, 32)
n, err := reader.Read(derivation.LeafHashes[i])
if err != nil || n != 32 {
return nil, ErrInvalidPsbtFormat
}
}
// Extract the remaining bytes from the reader (we don't actually know
// how many bytes we read due to the compact size integer at the
// beginning).
var leftoverBuf bytes.Buffer
_, err = reader.WriteTo(&leftoverBuf)
if err != nil {
return nil, err
}
// Read the BIP32 derivation info.
fingerprint, path, err := ReadBip32Derivation(leftoverBuf.Bytes())
if err != nil {
return nil, err
}
derivation.MasterKeyFingerprint = fingerprint
derivation.Bip32Path = path
return &derivation, nil
}
// SerializeTaprootBip32Derivation serializes a TaprootBip32Derivation to its
// raw byte representation.
func SerializeTaprootBip32Derivation(d *TaprootBip32Derivation) ([]byte,
error) {
var buf bytes.Buffer
// The taproot key BIP 32 derivation path is defined as:
// <hashes len> <leaf hash>* <4 byte fingerprint> <32-bit uint>*
err := wire.WriteVarInt(&buf, 0, uint64(len(d.LeafHashes)))
if err != nil {
return nil, ErrInvalidPsbtFormat
}
for _, hash := range d.LeafHashes {
n, err := buf.Write(hash)
if err != nil || n != 32 {
return nil, ErrInvalidPsbtFormat
}
}
_, err = buf.Write(SerializeBIP32Derivation(
d.MasterKeyFingerprint, d.Bip32Path,
))
if err != nil {
return nil, ErrInvalidPsbtFormat
}
return buf.Bytes(), nil
}
// validateXOnlyPubkey checks if pubKey is *any* valid pubKey serialization in a
// BIP-340 context (x-only serialization).
func validateXOnlyPubkey(pubKey []byte) bool {
_, err := schnorr.ParsePubKey(pubKey)
return err == nil
}
// validateSchnorrSignature checks that the passed byte slice is a valid Schnorr
// signature, _NOT_ including the sighash flag. It does *not* of course
// validate the signature against any message or public key.
func validateSchnorrSignature(sig []byte) bool {
_, err := schnorr.ParseSignature(sig)
return err == nil
}
// validateControlBlock checks that the passed byte slice is a valid control
// block as it would appear in a BIP-341 witness stack as the last element.
func validateControlBlock(controlBlock []byte) bool {
_, err := txscript.ParseControlBlock(controlBlock)
return err == nil
}