1 // Copyright 2013-2022 The btcsuite developers
2 3 package musig2
4 5 import (
6 "bytes"
7 "crypto/rand"
8 "encoding/binary"
9 "errors"
10 "io"
11 12 "next.orly.dev/pkg/nostr/crypto/ec"
13 "next.orly.dev/pkg/nostr/crypto/ec/chainhash"
14 "next.orly.dev/pkg/nostr/crypto/ec/schnorr"
15 "next.orly.dev/pkg/lol/chk"
16 )
17 18 const (
19 // PubNonceSize is the size of the public nonces. Each public nonce is
20 // serialized the full compressed encoding, which uses 32 bytes for each
21 // nonce.
22 PubNonceSize = 66
23 // SecNonceSize is the size of the secret nonces for musig2. The secret
24 // nonces are the corresponding secret keys to the public nonce points.
25 SecNonceSize = 97
26 )
27 28 var (
29 // NonceAuxTag is the tag used to optionally mix in the secret key with
30 // the set of aux randomness.
31 NonceAuxTag = []byte("MuSig/aux")
32 // NonceGenTag is used to generate the value (from a set of required an
33 // optional field) that will be used as the part of the secret nonce.
34 NonceGenTag = []byte("MuSig/nonce")
35 byteOrder = binary.BigEndian
36 // ErrPubkeyInvalid is returned when the pubkey of the WithPublicKey
37 // option is not passed or of invalid length.
38 ErrPubkeyInvalid = errors.New("nonce generation requires a valid pubkey")
39 )
40 41 // zeroSecNonce is a secret nonce that's all zeroes. This is used to check that
42 // we're not attempting to re-use a nonce, and also protect callers from it.
43 var zeroSecNonce [SecNonceSize]byte
44 45 // Nonces holds the public and secret nonces required for musig2.
46 //
47 // TODO(roasbeef): methods on this to help w/ parsing, etc?
48 type Nonces struct {
49 // PubNonce holds the two 33-byte compressed encoded points that serve
50 // as the public set of nonces.
51 PubNonce [PubNonceSize]byte
52 // SecNonce holds the two 32-byte scalar values that are the secret
53 // keys to the two public nonces.
54 SecNonce [SecNonceSize]byte
55 }
56 57 // secNonceToPubNonce takes our two secrete nonces, and produces their two
58 // corresponding EC points, serialized in compressed format.
59 func secNonceToPubNonce(secNonce [SecNonceSize]byte) [PubNonceSize]byte {
60 var k1Mod, k2Mod btcec.ModNScalar
61 k1Mod.SetByteSlice(secNonce[:btcec.SecKeyBytesLen])
62 k2Mod.SetByteSlice(secNonce[btcec.SecKeyBytesLen:])
63 var r1, r2 btcec.JacobianPoint
64 btcec.ScalarBaseMultNonConst(&k1Mod, &r1)
65 btcec.ScalarBaseMultNonConst(&k2Mod, &r2)
66 // Next, we'll convert the key in jacobian format to a normal public
67 // key expressed in affine coordinates.
68 r1.ToAffine()
69 r2.ToAffine()
70 r1Pub := btcec.NewPublicKey(&r1.X, &r1.Y)
71 r2Pub := btcec.NewPublicKey(&r2.X, &r2.Y)
72 var pubNonce [PubNonceSize]byte
73 // The public nonces are serialized as: R1 || R2, where both keys are
74 // serialized in compressed format.
75 copy(pubNonce[:], r1Pub.SerializeCompressed())
76 copy(
77 pubNonce[btcec.PubKeyBytesLenCompressed:],
78 r2Pub.SerializeCompressed(),
79 )
80 return pubNonce
81 }
82 83 // NonceGenOption is a function option that allows callers to modify how nonce
84 // generation happens.
85 type NonceGenOption func(*nonceGenOpts)
86 87 // nonceGenOpts is the set of options that control how nonce generation
88 // happens.
89 type nonceGenOpts struct {
90 // randReader is what we'll use to generate a set of random bytes. If
91 // unspecified, then the normal crypto/rand rand.Read method will be
92 // used in place.
93 randReader io.Reader
94 // publicKey is the mandatory public key that will be mixed into the nonce
95 // generation.
96 publicKey []byte
97 // secretKey is an optional argument that's used to further augment the
98 // generated nonce by xor'ing it with this secret key.
99 secretKey []byte
100 // combinedKey is an optional argument that if specified, will be
101 // combined along with the nonce generation.
102 combinedKey []byte
103 // msg is an optional argument that will be mixed into the nonce
104 // derivation algorithm.
105 msg []byte
106 // auxInput is an optional argument that will be mixed into the nonce
107 // derivation algorithm.
108 auxInput []byte
109 }
110 111 // cryptoRandAdapter is an adapter struct that allows us to pass in the package
112 // level Read function from crypto/rand into a context that accepts an
113 // io.Reader.
114 type cryptoRandAdapter struct{}
115 116 // Read implements the io.Reader interface for the crypto/rand package. By
117 // default, we always use the crypto/rand reader, but the caller is able to
118 // specify their own generation, which can be useful for deterministic tests.
119 func (c *cryptoRandAdapter) Read(p []byte) (n int, err error) {
120 return rand.Read(p)
121 }
122 123 // defaultNonceGenOpts returns the default set of nonce generation options.
124 func defaultNonceGenOpts() *nonceGenOpts {
125 return &nonceGenOpts{randReader: &cryptoRandAdapter{}}
126 }
127 128 // WithCustomRand allows a caller to use a custom random number generator in
129 // place for crypto/rand. This should only really be used to generate
130 // determinstic tests.
131 func WithCustomRand(r io.Reader) NonceGenOption {
132 return func(o *nonceGenOpts) { o.randReader = r }
133 }
134 135 // WithPublicKey is the mandatory public key that will be mixed into the nonce
136 // generation.
137 func WithPublicKey(pubKey *btcec.PublicKey) NonceGenOption {
138 return func(o *nonceGenOpts) {
139 o.publicKey = pubKey.SerializeCompressed()
140 }
141 }
142 143 // WithNonceSecretKeyAux allows a caller to optionally specify a secret key
144 // that should be used to augment the randomness used to generate the nonces.
145 func WithNonceSecretKeyAux(secKey *btcec.SecretKey) NonceGenOption {
146 return func(o *nonceGenOpts) { o.secretKey = secKey.Serialize() }
147 }
148 149 var WithNoncePrivateKeyAux = WithNonceSecretKeyAux
150 151 // WithNonceCombinedKeyAux allows a caller to optionally specify the combined
152 // key used in this signing session to further augment the randomness used to
153 // generate nonces.
154 func WithNonceCombinedKeyAux(combinedKey *btcec.PublicKey) NonceGenOption {
155 return func(o *nonceGenOpts) {
156 o.combinedKey = schnorr.SerializePubKey(combinedKey)
157 }
158 }
159 160 // WithNonceMessageAux allows a caller to optionally specify a message to be
161 // mixed into the randomness generated to create the nonce.
162 func WithNonceMessageAux(msg [32]byte) NonceGenOption {
163 return func(o *nonceGenOpts) { o.msg = msg[:] }
164 }
165 166 // WithNonceAuxInput is a set of auxiliary randomness, similar to BIP 340 that
167 // can be used to further augment the nonce generation process.
168 func WithNonceAuxInput(aux []byte) NonceGenOption {
169 return func(o *nonceGenOpts) { o.auxInput = aux }
170 }
171 172 // withCustomOptions allows a caller to pass a complete set of custom
173 // nonceGenOpts, without needing to create custom and checked structs such as
174 // *btcec.SecretKey. This is mainly used to match the testcases provided by
175 // the MuSig2 BIP.
176 func withCustomOptions(customOpts nonceGenOpts) NonceGenOption {
177 return func(o *nonceGenOpts) {
178 o.randReader = customOpts.randReader
179 o.secretKey = customOpts.secretKey
180 o.combinedKey = customOpts.combinedKey
181 o.auxInput = customOpts.auxInput
182 o.msg = customOpts.msg
183 o.publicKey = customOpts.publicKey
184 }
185 }
186 187 // lengthWriter is a function closure that allows a caller to control how the
188 // length prefix of a byte slice is written.
189 //
190 // TODO(roasbeef): use type params once we bump repo version
191 type lengthWriter func(w io.Writer, b []byte) error
192 193 // uint8Writer is an implementation of lengthWriter that writes the length of
194 // the byte slice using 1 byte.
195 func uint8Writer(w io.Writer, b []byte) error {
196 return binary.Write(w, byteOrder, uint8(len(b)))
197 }
198 199 // uint32Writer is an implementation of lengthWriter that writes the length of
200 // the byte slice using 4 bytes.
201 func uint32Writer(w io.Writer, b []byte) error {
202 return binary.Write(w, byteOrder, uint32(len(b)))
203 }
204 205 // uint32Writer is an implementation of lengthWriter that writes the length of
206 // the byte slice using 8 bytes.
207 func uint64Writer(w io.Writer, b []byte) error {
208 return binary.Write(w, byteOrder, uint64(len(b)))
209 }
210 211 // writeBytesPrefix is used to write out: len(b) || b, to the passed io.Writer.
212 // The lengthWriter function closure is used to allow the caller to specify the
213 // precise byte packing of the length.
214 func writeBytesPrefix(w io.Writer, b []byte, lenWriter lengthWriter) error {
215 // Write out the length of the byte first, followed by the set of bytes
216 // itself.
217 if err := lenWriter(w, b); chk.T(err) {
218 return err
219 }
220 if _, err := w.Write(b); chk.T(err) {
221 return err
222 }
223 return nil
224 }
225 226 // genNonceAuxBytes writes out the full byte string used to derive a secret
227 // nonce based on some initial randomness as well as the series of optional
228 // fields. The byte string used for derivation is:
229 // - tagged_hash("MuSig/nonce", rand || len(pk) || pk ||
230 // len(aggpk) || aggpk || m_prefixed || len(in) || in || i).
231 //
232 // where i is the ith secret nonce being generated and m_prefixed is:
233 // - bytes(1, 0) if the message is blank
234 // - bytes(1, 1) || bytes(8, len(m)) || m if the message is present.
235 func genNonceAuxBytes(
236 rand []byte, pubkey []byte, i int,
237 opts *nonceGenOpts,
238 ) (*chainhash.Hash, error) {
239 240 var w bytes.Buffer
241 // First, write out the randomness generated in the prior step.
242 if _, err := w.Write(rand); chk.T(err) {
243 return nil, err
244 }
245 // Next, we'll write out: len(pk) || pk
246 err := writeBytesPrefix(&w, pubkey, uint8Writer)
247 if err != nil {
248 return nil, err
249 }
250 // Next, we'll write out: len(aggpk) || aggpk.
251 err = writeBytesPrefix(&w, opts.combinedKey, uint8Writer)
252 if err != nil {
253 return nil, err
254 }
255 switch {
256 // If the message isn't present, then we'll just write out a single
257 // uint8 of a zero byte: m_prefixed = bytes(1, 0).
258 case opts.msg == nil:
259 if _, err := w.Write([]byte{0x00}); chk.T(err) {
260 return nil, err
261 }
262 // Otherwise, we'll write a single byte of 0x01 with a 1 byte length
263 // prefix, followed by the message itself with an 8 byte length prefix:
264 // m_prefixed = bytes(1, 1) || bytes(8, len(m)) || m.
265 case len(opts.msg) == 0:
266 fallthrough
267 default:
268 if _, err := w.Write([]byte{0x01}); chk.T(err) {
269 return nil, err
270 }
271 err = writeBytesPrefix(&w, opts.msg, uint64Writer)
272 if err != nil {
273 return nil, err
274 }
275 }
276 // Finally we'll write out the auxiliary input.
277 err = writeBytesPrefix(&w, opts.auxInput, uint32Writer)
278 if err != nil {
279 return nil, err
280 }
281 // Next we'll write out the interaction/index number which will
282 // uniquely generate two nonces given the rest of the possibly static
283 // parameters.
284 if err := binary.Write(&w, byteOrder, uint8(i)); chk.T(err) {
285 return nil, err
286 }
287 // With the message buffer complete, we'll now derive the tagged hash
288 // using our set of params.
289 return chainhash.TaggedHash(NonceGenTag, w.Bytes()), nil
290 }
291 292 // GenNonces generates the secret nonces, as well as the public nonces which
293 // correspond to an EC point generated using the secret nonce as a secret key.
294 func GenNonces(options ...NonceGenOption) (*Nonces, error) {
295 opts := defaultNonceGenOpts()
296 for _, opt := range options {
297 opt(opts)
298 }
299 // We require the pubkey option.
300 if opts.publicKey == nil || len(opts.publicKey) != 33 {
301 return nil, ErrPubkeyInvalid
302 }
303 // First, we'll start out by generating 32 random bytes drawn from our
304 // CSPRNG.
305 var randBytes [32]byte
306 if _, err := opts.randReader.Read(randBytes[:]); chk.T(err) {
307 return nil, err
308 }
309 // If the options contain a secret key, we XOR it with with the tagged
310 // random bytes.
311 if len(opts.secretKey) == 32 {
312 taggedHash := chainhash.TaggedHash(NonceAuxTag, randBytes[:])
313 314 for i := 0; i < chainhash.HashSize; i++ {
315 randBytes[i] = opts.secretKey[i] ^ taggedHash[i]
316 }
317 }
318 // Using our randomness, pubkey and the set of optional params, generate our
319 // two secret nonces: k1 and k2.
320 k1, err := genNonceAuxBytes(randBytes[:], opts.publicKey, 0, opts)
321 if err != nil {
322 return nil, err
323 }
324 k2, err := genNonceAuxBytes(randBytes[:], opts.publicKey, 1, opts)
325 if err != nil {
326 return nil, err
327 }
328 var k1Mod, k2Mod btcec.ModNScalar
329 k1Mod.SetBytes((*[32]byte)(k1))
330 k2Mod.SetBytes((*[32]byte)(k2))
331 // The secret nonces are serialized as the concatenation of the two 32
332 // byte secret nonce values and the pubkey.
333 var nonces Nonces
334 k1Mod.PutBytesUnchecked(nonces.SecNonce[:])
335 k2Mod.PutBytesUnchecked(nonces.SecNonce[btcec.SecKeyBytesLen:])
336 copy(nonces.SecNonce[btcec.SecKeyBytesLen*2:], opts.publicKey)
337 // Next, we'll generate R_1 = k_1*G and R_2 = k_2*G. Along the way we
338 // need to map our nonce values into mod n scalars so we can work with
339 // the btcec API.
340 nonces.PubNonce = secNonceToPubNonce(nonces.SecNonce)
341 return &nonces, nil
342 }
343 344 // AggregateNonces aggregates the set of a pair of public nonces for each party
345 // into a single aggregated nonces to be used for multi-signing.
346 func AggregateNonces(pubNonces [][PubNonceSize]byte) (
347 [PubNonceSize]byte,
348 error,
349 ) {
350 351 // combineNonces is a helper function that aggregates (adds) up a
352 // series of nonces encoded in compressed format. It uses a slicing
353 // function to extra 33 bytes at a time from the packed 2x public
354 // nonces.
355 type nonceSlicer func([PubNonceSize]byte) []byte
356 combineNonces := func(slicer nonceSlicer) (btcec.JacobianPoint, error) {
357 // Convert the set of nonces into jacobian coordinates we can
358 // use to accumulate them all into each other.
359 pubNonceJs := make([]*btcec.JacobianPoint, len(pubNonces))
360 for i, pubNonceBytes := range pubNonces {
361 // Using the slicer, extract just the bytes we need to
362 // decode.
363 var nonceJ btcec.JacobianPoint
364 nonceJ, err := btcec.ParseJacobian(slicer(pubNonceBytes))
365 if err != nil {
366 return btcec.JacobianPoint{}, err
367 }
368 pubNonceJs[i] = &nonceJ
369 }
370 // Now that we have the set of complete nonces, we'll aggregate
371 // them: R = R_i + R_i+1 + ... + R_i+n.
372 var aggregateNonce btcec.JacobianPoint
373 for _, pubNonceJ := range pubNonceJs {
374 btcec.AddNonConst(
375 &aggregateNonce, pubNonceJ, &aggregateNonce,
376 )
377 }
378 aggregateNonce.ToAffine()
379 return aggregateNonce, nil
380 }
381 // The final nonce public nonce is actually two nonces, one that
382 // aggregate the first nonce of all the parties, and the other that
383 // aggregates the second nonce of all the parties.
384 var finalNonce [PubNonceSize]byte
385 combinedNonce1, err := combineNonces(
386 func(n [PubNonceSize]byte) []byte {
387 return n[:btcec.PubKeyBytesLenCompressed]
388 },
389 )
390 if err != nil {
391 return finalNonce, err
392 }
393 combinedNonce2, err := combineNonces(
394 func(n [PubNonceSize]byte) []byte {
395 return n[btcec.PubKeyBytesLenCompressed:]
396 },
397 )
398 if err != nil {
399 return finalNonce, err
400 }
401 copy(finalNonce[:], btcec.JacobianToByteSlice(combinedNonce1))
402 copy(
403 finalNonce[btcec.PubKeyBytesLenCompressed:],
404 btcec.JacobianToByteSlice(combinedNonce2),
405 )
406 return finalNonce, nil
407 }
408