-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
btcec/schnorr: add benchmarks for sign/verify
Benchmarks run w/o fast sign (always verify after you generate a sig): ``` goos: darwin goarch: amd64 pkg: github.com/btcsuite/btcd/btcec/v2/schnorr cpu: VirtualApple @ 2.50GHz BenchmarkSigVerify-8 8000 152468 ns/op 960 B/op 16 allocs/op BenchmarkSign-8 4939 215489 ns/op 1408 B/op 27 allocs/op BenchmarkSignRfc6979-8 5106 217416 ns/op 2129 B/op 37 allocs/op PASS ok github.com/btcsuite/btcd/btcec/v2/schnorr 4.629s ``` Benchmarks w/ fast sign: ``` goos: darwin goarch: amd64 pkg: github.com/btcsuite/btcd/btcec/v2/schnorr cpu: VirtualApple @ 2.50GHz BenchmarkSigVerify-8 7982 142826 ns/op 960 B/op 16 allocs/op BenchmarkSign-8 18210 65908 ns/op 496 B/op 12 allocs/op BenchmarkSignRfc6979-8 16537 78161 ns/op 1216 B/op 22 allocs/op PASS ok github.com/btcsuite/btcd/btcec/v2/schnorr 5.418s ```
- Loading branch information
Showing
1 changed file
with
169 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
// Copyright 2013-2016 The btcsuite developers | ||
// Copyright (c) 2015-2021 The Decred developers | ||
// Use of this source code is governed by an ISC | ||
// license that can be found in the LICENSE file. | ||
|
||
package schnorr | ||
|
||
import ( | ||
"crypto/sha256" | ||
"encoding/hex" | ||
"math/big" | ||
"testing" | ||
|
||
"github.com/btcsuite/btcd/btcec/v2" | ||
"github.com/decred/dcrd/dcrec/secp256k1/v4" | ||
) | ||
|
||
// hexToBytes converts the passed hex string into bytes and will panic if there | ||
// is an error. This is only provided for the hard-coded constants so errors in | ||
// the source code can be detected. It will only (and must only) be called with | ||
// hard-coded values. | ||
func hexToBytes(s string) []byte { | ||
b, err := hex.DecodeString(s) | ||
if err != nil { | ||
panic("invalid hex in source file: " + s) | ||
} | ||
return b | ||
} | ||
|
||
// hexToModNScalar converts the passed hex string into a ModNScalar and will | ||
// panic if there is an error. This is only provided for the hard-coded | ||
// constants so errors in the source code can be detected. It will only (and | ||
// must only) be called with hard-coded values. | ||
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 | ||
} | ||
|
||
// hexToFieldVal converts the passed hex string into a FieldVal and will panic | ||
// if there is an error. This is only provided for the hard-coded constants so | ||
// errors in the source code can be detected. It will only (and must only) be | ||
// called with hard-coded values. | ||
func hexToFieldVal(s string) *btcec.FieldVal { | ||
b, err := hex.DecodeString(s) | ||
if err != nil { | ||
panic("invalid hex in source file: " + s) | ||
} | ||
var f btcec.FieldVal | ||
if overflow := f.SetByteSlice(b); overflow { | ||
panic("hex in source file overflows mod P: " + s) | ||
} | ||
return &f | ||
} | ||
|
||
// fromHex converts the passed hex string into a big integer pointer and will | ||
// panic is there is an error. This is only provided for the hard-coded | ||
// constants so errors in the source code can bet detected. It will only (and | ||
// must only) be called for initialization purposes. | ||
func fromHex(s string) *big.Int { | ||
if s == "" { | ||
return big.NewInt(0) | ||
} | ||
r, ok := new(big.Int).SetString(s, 16) | ||
if !ok { | ||
panic("invalid hex in source file: " + s) | ||
} | ||
return r | ||
} | ||
|
||
var testOk bool | ||
|
||
// BenchmarkSigVerify benchmarks how long it takes the secp256k1 curve to | ||
// verify signatures. | ||
func BenchmarkSigVerify(b *testing.B) { | ||
// Randomly generated keypair. | ||
d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d") | ||
|
||
privKey := secp256k1.NewPrivateKey(d) | ||
pubKey := privKey.PubKey() | ||
|
||
// Double sha256 of []byte{0x01, 0x02, 0x03, 0x04} | ||
msgHash := sha256.Sum256([]byte("benchmark")) | ||
sig, err := Sign(privKey, msgHash[:]) | ||
if err != nil { | ||
b.Fatalf("unable to sign: %v", err) | ||
} | ||
|
||
if !sig.Verify(msgHash[:], pubKey) { | ||
b.Errorf("Signature failed to verify") | ||
return | ||
} | ||
|
||
var ok bool | ||
|
||
b.ReportAllocs() | ||
b.ResetTimer() | ||
for i := 0; i < b.N; i++ { | ||
ok = sig.Verify(msgHash[:], pubKey) | ||
} | ||
|
||
testOk = ok | ||
} | ||
|
||
// Used to ensure the compiler doesn't optimize away the benchmark. | ||
var ( | ||
testSig *Signature | ||
testErr error | ||
) | ||
|
||
// BenchmarkSign benchmarks how long it takes to sign a message. | ||
func BenchmarkSign(b *testing.B) { | ||
// Randomly generated keypair. | ||
d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d") | ||
privKey := secp256k1.NewPrivateKey(d) | ||
|
||
// blake256 of []byte{0x01, 0x02, 0x03, 0x04}. | ||
msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7") | ||
|
||
var auxBytes [32]byte | ||
copy(auxBytes[:], msgHash) | ||
auxBytes[0] ^= 1 | ||
|
||
var ( | ||
sig *Signature | ||
err error | ||
) | ||
|
||
b.ReportAllocs() | ||
b.ResetTimer() | ||
for i := 0; i < b.N; i++ { | ||
sig, err = Sign( | ||
privKey, msgHash, CustomNonce(auxBytes), FastSign(), | ||
) | ||
} | ||
|
||
testSig = sig | ||
testErr = err | ||
} | ||
|
||
// BenchmarkSignRfc6979 benchmarks how long it takes to sign a message. | ||
func BenchmarkSignRfc6979(b *testing.B) { | ||
// Randomly generated keypair. | ||
d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d") | ||
privKey := secp256k1.NewPrivateKey(d) | ||
|
||
// blake256 of []byte{0x01, 0x02, 0x03, 0x04}. | ||
msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7") | ||
|
||
var ( | ||
sig *Signature | ||
err error | ||
) | ||
|
||
b.ReportAllocs() | ||
b.ResetTimer() | ||
for i := 0; i < b.N; i++ { | ||
sig, err = Sign(privKey, msgHash, FastSign()) | ||
} | ||
|
||
testSig = sig | ||
testErr = err | ||
} |