diff --git a/crypto/ed25519/bench_test.go b/crypto/ed25519/bench_test.go new file mode 100644 index 000000000..47897cde6 --- /dev/null +++ b/crypto/ed25519/bench_test.go @@ -0,0 +1,26 @@ +package ed25519 + +import ( + "io" + "testing" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/internal/benchmarking" +) + +func BenchmarkKeyGeneration(b *testing.B) { + benchmarkKeygenWrapper := func(reader io.Reader) crypto.PrivKey { + return genPrivKey(reader) + } + benchmarking.BenchmarkKeyGeneration(b, benchmarkKeygenWrapper) +} + +func BenchmarkSigning(b *testing.B) { + priv := GenPrivKey() + benchmarking.BenchmarkSigning(b, priv) +} + +func BenchmarkVerification(b *testing.B) { + priv := GenPrivKey() + benchmarking.BenchmarkVerification(b, priv) +} diff --git a/crypto/ed25519/ed25519.go b/crypto/ed25519/ed25519.go index 8b7bd42bd..3dd4d2b31 100644 --- a/crypto/ed25519/ed25519.go +++ b/crypto/ed25519/ed25519.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/subtle" "fmt" + "io" "github.com/tendermint/ed25519" "github.com/tendermint/ed25519/extra25519" @@ -102,8 +103,16 @@ func (privKey PrivKeyEd25519) ToCurve25519() *[PubKeyEd25519Size]byte { // It uses OS randomness in conjunction with the current global random seed // in tendermint/libs/common to generate the private key. func GenPrivKey() PrivKeyEd25519 { + return genPrivKey(crypto.CReader()) +} + +// genPrivKey generates a new ed25519 private key using the provided reader. +func genPrivKey(rand io.Reader) PrivKeyEd25519 { privKey := new([64]byte) - copy(privKey[:32], crypto.CRandBytes(32)) + _, err := io.ReadFull(rand, privKey[:32]) + if err != nil { + panic(err) + } // ed25519.MakePublicKey(privKey) alters the last 32 bytes of privKey. // It places the pubkey in the last 32 bytes of privKey, and returns the // public key. diff --git a/crypto/internal/benchmarking/bench.go b/crypto/internal/benchmarking/bench.go new file mode 100644 index 000000000..c988de48e --- /dev/null +++ b/crypto/internal/benchmarking/bench.go @@ -0,0 +1,88 @@ +package benchmarking + +import ( + "io" + "testing" + + "github.com/tendermint/tendermint/crypto" +) + +// The code in this file is adapted from agl/ed25519. +// As such it is under the following license. +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found at the bottom of this file. + +type zeroReader struct{} + +func (zeroReader) Read(buf []byte) (int, error) { + for i := range buf { + buf[i] = 0 + } + return len(buf), nil +} + +// BenchmarkKeyGeneration benchmarks the given key generation algorithm using +// a dummy reader. +func BenchmarkKeyGeneration(b *testing.B, GenerateKey func(reader io.Reader) crypto.PrivKey) { + var zero zeroReader + for i := 0; i < b.N; i++ { + GenerateKey(zero) + } +} + +// BenchmarkSigning benchmarks the given signing algorithm using +// the provided privkey. +func BenchmarkSigning(b *testing.B, priv crypto.PrivKey) { + message := []byte("Hello, world!") + b.ResetTimer() + for i := 0; i < b.N; i++ { + priv.Sign(message) + } +} + +// BenchmarkVerification benchmarks the given verification algorithm using +// the provided privkey on a constant message. +func BenchmarkVerification(b *testing.B, priv crypto.PrivKey) { + pub := priv.PubKey() + // use a short message, so this time doesn't get dominated by hashing. + message := []byte("Hello, world!") + signature, err := priv.Sign(message) + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + pub.VerifyBytes(message, signature) + } +} + +// Below is the aforementioned license. + +// Copyright (c) 2012 The Go Authors. All rights reserved. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: + +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. + +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/crypto/secp256k1/bench_test.go b/crypto/secp256k1/bench_test.go new file mode 100644 index 000000000..4f651b762 --- /dev/null +++ b/crypto/secp256k1/bench_test.go @@ -0,0 +1,26 @@ +package secp256k1 + +import ( + "io" + "testing" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/internal/benchmarking" +) + +func BenchmarkKeyGeneration(b *testing.B) { + benchmarkKeygenWrapper := func(reader io.Reader) crypto.PrivKey { + return genPrivKey(reader) + } + benchmarking.BenchmarkKeyGeneration(b, benchmarkKeygenWrapper) +} + +func BenchmarkSigning(b *testing.B) { + priv := GenPrivKey() + benchmarking.BenchmarkSigning(b, priv) +} + +func BenchmarkVerification(b *testing.B) { + priv := GenPrivKey() + benchmarking.BenchmarkVerification(b, priv) +} diff --git a/crypto/secp256k1/secp256k1.go b/crypto/secp256k1/secp256k1.go index 4b210dc7f..03d5614ab 100644 --- a/crypto/secp256k1/secp256k1.go +++ b/crypto/secp256k1/secp256k1.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "crypto/subtle" "fmt" + "io" secp256k1 "github.com/btcsuite/btcd/btcec" amino "github.com/tendermint/go-amino" @@ -80,8 +81,16 @@ func (privKey PrivKeySecp256k1) Equals(other crypto.PrivKey) bool { // It uses OS randomness in conjunction with the current global random seed // in tendermint/libs/common to generate the private key. func GenPrivKey() PrivKeySecp256k1 { + return genPrivKey(crypto.CReader()) +} + +// genPrivKey generates a new secp256k1 private key using the provided reader. +func genPrivKey(rand io.Reader) PrivKeySecp256k1 { privKeyBytes := [32]byte{} - copy(privKeyBytes[:], crypto.CRandBytes(32)) + _, err := io.ReadFull(rand, privKeyBytes[:]) + if err != nil { + panic(err) + } // crypto.CRandBytes is guaranteed to be 32 bytes long, so it can be // casted to PrivKeySecp256k1. return PrivKeySecp256k1(privKeyBytes)