btcec/schnorr/musig2: update musig2 impl to version 0.7.0

The two _concrete_ changes between version 0.4.0 (where we are before
this commit), and version 0.7.0 are:

  1. Variable length messages are now allowed, this comes with a new 8
     byte prefix for the messages.

     * Our implementation was already using a `[]byte` for the
       message/hash, so no extra API changes are needed here.

  2. The serialization for a blank message and a normal message (for
     nonce gen) is now distinct. A single byte is added (either 0 or 1)
     to indicate if a message was passed into nonce generation.
This commit is contained in:
Olaoluwa Osuntokun 2022-10-05 20:05:29 -07:00
parent e563459b72
commit a34e777916
No known key found for this signature in database
GPG key ID: 3BBD59E99B280306
2 changed files with 36 additions and 10 deletions

View file

@ -1367,9 +1367,9 @@ func TestMusig2NonceGenTestVectors(t *testing.T) {
auxInput: extra_in[:],
msg: msg[:],
},
expectedNonce: "E8F2E103D86800F19A4E97338D371CB885DB2" +
"F19D08C0BD205BBA9B906C971D0D786A17718AAFAD6D" +
"E025DDDD99DC823E2DFC1AE1DDFE920888AD53FFF423FC4",
expectedNonce: "BC6C683EBBCC39DCB3C29B3D010D2AAA7C86C" +
"FB562FC41ED9A460EE061013E75FB4AD2F0B81671326" +
"9800D018803906D5481E00A940EAB4F4AC49B4A372EB0F4",
},
{
opts: nonceGenOpts{

View file

@ -191,6 +191,8 @@ func withCustomOptions(customOpts nonceGenOpts) NonceGenOption {
// lengthWriter is a function closure that allows a caller to control how the
// length prefix of a byte slice is written.
//
// TODO(roasbeef): use type params once we bump repo version
type lengthWriter func(w io.Writer, b []byte) error
// uint8Writer is an implementation of lengthWriter that writes the length of
@ -205,6 +207,12 @@ func uint32Writer(w io.Writer, b []byte) error {
return binary.Write(w, byteOrder, uint32(len(b)))
}
// uint32Writer is an implementation of lengthWriter that writes the length of
// the byte slice using 8 bytes.
func uint64Writer(w io.Writer, b []byte) error {
return binary.Write(w, byteOrder, uint64(len(b)))
}
// writeBytesPrefix is used to write out: len(b) || b, to the passed io.Writer.
// The lengthWriter function closure is used to allow the caller to specify the
// precise byte packing of the length.
@ -225,10 +233,12 @@ func writeBytesPrefix(w io.Writer, b []byte, lenWriter lengthWriter) error {
// genNonceAuxBytes writes out the full byte string used to derive a secret
// nonce based on some initial randomness as well as the series of optional
// fields. The byte string used for derivation is:
// * tagged_hash("MuSig/nonce", rand || len(aggpk) || aggpk || len(m)
// || m || len(in) || in || i).
// - tagged_hash("MuSig/nonce", rand || len(aggpk) || aggpk || m_prefixed
// || len(in) || in || i).
//
// where i is the ith secret nonce being generated.
// where i is the ith secret nonce being generated and m_prefixed is:
// - bytes(1, 0) if the message is blank
// - bytes(1, 1) || bytes(8, len(m)) || m if the message is present.
func genNonceAuxBytes(rand []byte, i int,
opts *nonceGenOpts) (*chainhash.Hash, error) {
@ -245,10 +255,26 @@ func genNonceAuxBytes(rand []byte, i int,
return nil, err
}
// Next, we'll write out the length prefixed message.
err = writeBytesPrefix(&w, opts.msg, uint8Writer)
if err != nil {
return nil, err
switch len(opts.msg) {
// If the message isn't present, then we'll just write out a single
// uint8 of a zero byte: m_prefixed = bytes(1, 0).
case 0:
if _, err := w.Write([]byte{0x00}); err != nil {
return nil, err
}
// Otherwise, we'll write a single byte of 0x01 with a 1 byte length
// prefix, followed by the message itself with an 8 byte length prefix:
// m_prefixed = bytes(1, 1) || bytes(8, len(m)) || m.
default:
if _, err := w.Write([]byte{0x01}); err != nil {
return nil, err
}
err = writeBytesPrefix(&w, opts.msg, uint64Writer)
if err != nil {
return nil, err
}
}
// Finally we'll write out the auxiliary input.