-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1820 from Roasbeef/musig2
btcec/schnorr/musig2: add new musig2 implementation based on musig2 draft BIP
- Loading branch information
Showing
9 changed files
with
3,354 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0 h1:MSskdM4/xJYcFzy0altH/C/xHopifpWzHUi1JeVI34Q= | ||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= | ||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= | ||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= | ||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= | ||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= | ||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= | ||
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 h1:rxKZ2gOnYxjfmakvUUqh9Gyb6KXfrj7JWTxORTYqb0E= | ||
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,313 @@ | ||
// Copyright 2013-2022 The btcsuite developers | ||
// Use of this source code is governed by an ISC | ||
// license that can be found in the LICENSE file. | ||
|
||
package musig2 | ||
|
||
import ( | ||
"encoding/hex" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/btcsuite/btcd/btcec/v2" | ||
"github.com/btcsuite/btcd/btcec/v2/schnorr" | ||
) | ||
|
||
var ( | ||
testPrivBytes = hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d") | ||
|
||
testMsg = hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7") | ||
) | ||
|
||
func hexToBytes(s string) []byte { | ||
b, err := hex.DecodeString(s) | ||
if err != nil { | ||
panic("invalid hex in source file: " + s) | ||
} | ||
return b | ||
} | ||
|
||
func hexToModNScalar(s string) *btcec.ModNScalar { | ||
b, err := hex.DecodeString(s) | ||
if err != nil { | ||
panic("invalid hex in source file: " + s) | ||
} | ||
var scalar btcec.ModNScalar | ||
if overflow := scalar.SetByteSlice(b); overflow { | ||
panic("hex in source file overflows mod N scalar: " + s) | ||
} | ||
return &scalar | ||
} | ||
|
||
func genSigner(t *testing.B) signer { | ||
privKey, err := btcec.NewPrivateKey() | ||
if err != nil { | ||
t.Fatalf("unable to gen priv key: %v", err) | ||
} | ||
|
||
pubKey, err := schnorr.ParsePubKey( | ||
schnorr.SerializePubKey(privKey.PubKey()), | ||
) | ||
if err != nil { | ||
t.Fatalf("unable to gen key: %v", err) | ||
} | ||
|
||
nonces, err := GenNonces() | ||
if err != nil { | ||
t.Fatalf("unable to gen nonces: %v", err) | ||
} | ||
|
||
return signer{ | ||
privKey: privKey, | ||
pubKey: pubKey, | ||
nonces: nonces, | ||
} | ||
} | ||
|
||
var ( | ||
testSig *PartialSignature | ||
testErr error | ||
) | ||
|
||
// BenchmarkPartialSign benchmarks how long it takes to generate a partial | ||
// signature factoring in if the keys are sorted and also if we're in fast sign | ||
// mode. | ||
func BenchmarkPartialSign(b *testing.B) { | ||
for _, numSigners := range []int{10, 100} { | ||
for _, fastSign := range []bool{true, false} { | ||
for _, sortKeys := range []bool{true, false} { | ||
name := fmt.Sprintf("num_signers=%v/fast_sign=%v/sort=%v", | ||
numSigners, fastSign, sortKeys) | ||
|
||
signers := make(signerSet, numSigners) | ||
for i := 0; i < numSigners; i++ { | ||
signers[i] = genSigner(b) | ||
} | ||
|
||
combinedNonce, err := AggregateNonces(signers.pubNonces()) | ||
if err != nil { | ||
b.Fatalf("unable to generate combined nonce: %v", err) | ||
} | ||
|
||
var sig *PartialSignature | ||
|
||
var msg [32]byte | ||
copy(msg[:], testMsg[:]) | ||
|
||
keys := signers.keys() | ||
|
||
b.Run(name, func(b *testing.B) { | ||
var signOpts []SignOption | ||
if fastSign { | ||
signOpts = append(signOpts, WithFastSign()) | ||
} | ||
if sortKeys { | ||
signOpts = append(signOpts, WithSortedKeys()) | ||
} | ||
|
||
b.ResetTimer() | ||
b.ReportAllocs() | ||
|
||
for i := 0; i < b.N; i++ { | ||
sig, err = Sign( | ||
signers[0].nonces.SecNonce, signers[0].privKey, | ||
combinedNonce, keys, msg, signOpts..., | ||
) | ||
if err != nil { | ||
b.Fatalf("unable to generate sig: %v", err) | ||
} | ||
} | ||
|
||
testSig = sig | ||
testErr = err | ||
}) | ||
} | ||
} | ||
} | ||
} | ||
|
||
// TODO(roasbeef): add impact of sorting ^ | ||
|
||
var sigOk bool | ||
|
||
// BenchmarkPartialVerify benchmarks how long it takes to verify a partial | ||
// signature. | ||
func BenchmarkPartialVerify(b *testing.B) { | ||
for _, numSigners := range []int{10, 100} { | ||
for _, sortKeys := range []bool{true, false} { | ||
name := fmt.Sprintf("sort_keys=%v/num_signers=%v", | ||
sortKeys, numSigners) | ||
|
||
signers := make(signerSet, numSigners) | ||
for i := 0; i < numSigners; i++ { | ||
signers[i] = genSigner(b) | ||
} | ||
|
||
combinedNonce, err := AggregateNonces( | ||
signers.pubNonces(), | ||
) | ||
if err != nil { | ||
b.Fatalf("unable to generate combined "+ | ||
"nonce: %v", err) | ||
} | ||
|
||
var sig *PartialSignature | ||
|
||
var msg [32]byte | ||
copy(msg[:], testMsg[:]) | ||
|
||
b.ReportAllocs() | ||
b.ResetTimer() | ||
|
||
sig, err = Sign( | ||
signers[0].nonces.SecNonce, signers[0].privKey, | ||
combinedNonce, signers.keys(), msg, | ||
) | ||
if err != nil { | ||
b.Fatalf("unable to generate sig: %v", err) | ||
} | ||
|
||
keys := signers.keys() | ||
pubKey := signers[0].pubKey | ||
|
||
b.Run(name, func(b *testing.B) { | ||
var signOpts []SignOption | ||
if sortKeys { | ||
signOpts = append( | ||
signOpts, WithSortedKeys(), | ||
) | ||
} | ||
|
||
b.ResetTimer() | ||
b.ReportAllocs() | ||
|
||
var ok bool | ||
for i := 0; i < b.N; i++ { | ||
ok = sig.Verify( | ||
signers[0].nonces.PubNonce, combinedNonce, | ||
keys, pubKey, msg, | ||
) | ||
if !ok { | ||
b.Fatalf("generated invalid sig!") | ||
} | ||
} | ||
sigOk = ok | ||
}) | ||
|
||
} | ||
} | ||
} | ||
|
||
var finalSchnorrSig *schnorr.Signature | ||
|
||
// BenchmarkCombineSigs benchmarks how long it takes to combine a set amount of | ||
// signatures. | ||
func BenchmarkCombineSigs(b *testing.B) { | ||
|
||
for _, numSigners := range []int{10, 100} { | ||
signers := make(signerSet, numSigners) | ||
for i := 0; i < numSigners; i++ { | ||
signers[i] = genSigner(b) | ||
} | ||
|
||
combinedNonce, err := AggregateNonces(signers.pubNonces()) | ||
if err != nil { | ||
b.Fatalf("unable to generate combined nonce: %v", err) | ||
} | ||
|
||
var msg [32]byte | ||
copy(msg[:], testMsg[:]) | ||
|
||
var finalNonce *btcec.PublicKey | ||
for i := range signers { | ||
signer := signers[i] | ||
partialSig, err := Sign( | ||
signer.nonces.SecNonce, signer.privKey, | ||
combinedNonce, signers.keys(), msg, | ||
) | ||
if err != nil { | ||
b.Fatalf("unable to generate partial sig: %v", | ||
err) | ||
} | ||
|
||
signers[i].partialSig = partialSig | ||
|
||
if finalNonce == nil { | ||
finalNonce = partialSig.R | ||
} | ||
} | ||
|
||
sigs := signers.partialSigs() | ||
|
||
name := fmt.Sprintf("num_signers=%v", numSigners) | ||
b.Run(name, func(b *testing.B) { | ||
b.ResetTimer() | ||
b.ReportAllocs() | ||
|
||
finalSig := CombineSigs(finalNonce, sigs) | ||
|
||
finalSchnorrSig = finalSig | ||
}) | ||
} | ||
} | ||
|
||
var testNonce [PubNonceSize]byte | ||
|
||
// BenchmarkAggregateNonces benchmarks how long it takes to combine nonces. | ||
func BenchmarkAggregateNonces(b *testing.B) { | ||
for _, numSigners := range []int{10, 100} { | ||
signers := make(signerSet, numSigners) | ||
for i := 0; i < numSigners; i++ { | ||
signers[i] = genSigner(b) | ||
} | ||
|
||
nonces := signers.pubNonces() | ||
|
||
name := fmt.Sprintf("num_signers=%v", numSigners) | ||
b.Run(name, func(b *testing.B) { | ||
b.ResetTimer() | ||
b.ReportAllocs() | ||
|
||
pubNonce, err := AggregateNonces(nonces) | ||
if err != nil { | ||
b.Fatalf("unable to generate nonces: %v", err) | ||
} | ||
|
||
testNonce = pubNonce | ||
}) | ||
} | ||
} | ||
|
||
var testKey *btcec.PublicKey | ||
|
||
// BenchmarkAggregateKeys benchmarks how long it takes to aggregate public | ||
// keys. | ||
func BenchmarkAggregateKeys(b *testing.B) { | ||
for _, numSigners := range []int{10, 100} { | ||
for _, sortKeys := range []bool{true, false} { | ||
signers := make(signerSet, numSigners) | ||
for i := 0; i < numSigners; i++ { | ||
signers[i] = genSigner(b) | ||
} | ||
|
||
signerKeys := signers.keys() | ||
|
||
name := fmt.Sprintf("num_signers=%v/sort_keys=%v", | ||
numSigners, sortKeys) | ||
|
||
uniqueKeyIndex := secondUniqueKeyIndex(signerKeys, false) | ||
|
||
b.Run(name, func(b *testing.B) { | ||
b.ResetTimer() | ||
b.ReportAllocs() | ||
|
||
aggKey, _, _, _ := AggregateKeys( | ||
signerKeys, sortKeys, | ||
WithUniqueKeyIndex(uniqueKeyIndex), | ||
) | ||
|
||
testKey = aggKey.FinalKey | ||
}) | ||
} | ||
} | ||
} |
Oops, something went wrong.