github.com/klaytn/klaytn@v1.12.1/crypto/bls/blst/bench_test.go (about)

     1  // Copyright 2023 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The klaytn library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package blst
    18  
    19  import (
    20  	"crypto/rand"
    21  	"runtime"
    22  	"sync"
    23  	"testing"
    24  
    25  	"github.com/klaytn/klaytn/crypto/bls/types"
    26  )
    27  
    28  var benchAggregateLen = 100
    29  
    30  func BenchmarkPublicKeyFromBytes(b *testing.B) {
    31  	sk, _ := RandKey()
    32  	pkb := sk.PublicKey().Marshal()
    33  
    34  	fn := func() {
    35  		if _, err := PublicKeyFromBytes(pkb); err != nil {
    36  			b.Fatal(err)
    37  		}
    38  	}
    39  	runUncached(b, "Uncached", fn)
    40  	runCached(b, "Cached", fn)
    41  }
    42  
    43  func BenchmarkMultiplePublicKeysFromBytes(b *testing.B) {
    44  	L := benchAggregateLen
    45  	tc := generateBenchmarkMaterial(L)
    46  
    47  	fn := func() {
    48  		if _, err := MultiplePublicKeysFromBytes(tc.pkbs); err != nil {
    49  			b.Fatal(err)
    50  		}
    51  	}
    52  	runUncached(b, "Uncached", fn)
    53  	runCached(b, "Cached", fn)
    54  }
    55  
    56  func BenchmarkAggregatePublicKeys(b *testing.B) {
    57  	L := benchAggregateLen
    58  	tc := generateBenchmarkMaterial(L)
    59  
    60  	for i := 0; i < b.N; i++ {
    61  		if _, err := AggregatePublicKeys(tc.pks); err != nil {
    62  			b.Fatal(err)
    63  		}
    64  	}
    65  }
    66  
    67  func BenchmarkAggregatePublicKeysFromBytes(b *testing.B) {
    68  	L := benchAggregateLen
    69  	tc := generateBenchmarkMaterial(L)
    70  
    71  	fn := func() {
    72  		if _, err := AggregatePublicKeysFromBytes(tc.pkbs); err != nil {
    73  			b.Fatal(err)
    74  		}
    75  	}
    76  	runUncached(b, "Uncached", fn)
    77  	runCached(b, "Cached", fn)
    78  }
    79  
    80  func BenchmarkSignatureFromBytes(b *testing.B) {
    81  	sigb := testSignatureBytes
    82  
    83  	fn := func() {
    84  		if _, err := SignatureFromBytes(sigb); err != nil {
    85  			b.Fatal(err)
    86  		}
    87  	}
    88  	runUncached(b, "Uncached", fn)
    89  	runCached(b, "Cached", fn)
    90  }
    91  
    92  func BenchmarkMultipleSignaturesFromBytes(b *testing.B) {
    93  	L := benchAggregateLen
    94  	tc := generateBenchmarkMaterial(L)
    95  
    96  	fn := func() {
    97  		if _, err := MultipleSignaturesFromBytes(tc.sigbs); err != nil {
    98  			b.Fatal(err)
    99  		}
   100  	}
   101  	runUncached(b, "Uncached", fn)
   102  	runCached(b, "Cached", fn)
   103  }
   104  
   105  func BenchmarkAggregateSignatures(b *testing.B) {
   106  	L := benchAggregateLen
   107  	tc := generateBenchmarkMaterial(L)
   108  
   109  	for i := 0; i < b.N; i++ {
   110  		if _, err := AggregateSignatures(tc.sigs); err != nil {
   111  			b.Fatal(err)
   112  		}
   113  	}
   114  }
   115  
   116  func BenchmarkAggregateSignaturesFromBytes(b *testing.B) {
   117  	L := benchAggregateLen
   118  	tc := generateBenchmarkMaterial(L)
   119  
   120  	fn := func() {
   121  		if _, err := AggregateSignaturesFromBytes(tc.sigbs); err != nil {
   122  			b.Fatal(err)
   123  		}
   124  	}
   125  	runUncached(b, "Uncached", fn)
   126  	runCached(b, "Cached", fn)
   127  }
   128  
   129  func BenchmarkSign(b *testing.B) {
   130  	sk, _ := RandKey()
   131  	msg := []byte("test message")
   132  
   133  	for i := 0; i < b.N; i++ {
   134  		Sign(sk, msg)
   135  	}
   136  }
   137  
   138  func BenchmarkVerify(b *testing.B) {
   139  	sk, _ := RandKey()
   140  	pk := sk.PublicKey()
   141  	msg := []byte("test message")
   142  	sig := Sign(sk, msg)
   143  
   144  	for i := 0; i < b.N; i++ {
   145  		Verify(sig, msg, pk)
   146  	}
   147  }
   148  
   149  func BenchmarkParallelVerify(b *testing.B) {
   150  	L := benchAggregateLen
   151  	tc := generateBenchmarkMaterialMulti(L)
   152  
   153  	b.ResetTimer()
   154  	for i := 0; i < b.N; i++ {
   155  		threads := runtime.NumCPU()
   156  		var wg sync.WaitGroup
   157  		wg.Add(threads)
   158  
   159  		jobs := make(chan int, len(tc.sigbs))
   160  		for i := 0; i < L; i++ {
   161  			jobs <- i
   162  		}
   163  
   164  		for i := 0; i < threads; i++ {
   165  			go func() {
   166  				for i := range jobs {
   167  					sig, _ := SignatureFromBytes(tc.sigbs[i])
   168  					pk, _ := PublicKeyFromBytes(tc.pkbs[i])
   169  					Verify(sig, tc.msgs[i][:], pk)
   170  				}
   171  				wg.Done()
   172  			}()
   173  		}
   174  
   175  		close(jobs)
   176  		wg.Wait()
   177  	}
   178  }
   179  
   180  // End-to-end benchmark where all inputs are []byte
   181  // Aggregate-Then-SingleVerify
   182  func BenchmarkAggregateAndVerify(b *testing.B) {
   183  	L := benchAggregateLen
   184  	tc := generateBenchmarkMaterial(L)
   185  	asig, _ := AggregateSignatures(tc.sigs)
   186  	asigb := asig.Marshal()
   187  
   188  	fn := func() {
   189  		apk, _ := AggregatePublicKeysFromBytes(tc.pkbs)
   190  		sig, _ := SignatureFromBytes(asigb)
   191  		Verify(sig, tc.msg, apk)
   192  	}
   193  	runUncached(b, "Uncached", fn)
   194  	runCached(b, "Cached", fn)
   195  }
   196  
   197  // End-to-end benchmark where all inputs are []byte
   198  // FastAggregateVerify
   199  func BenchmarkFastAggregateVerify(b *testing.B) {
   200  	L := benchAggregateLen
   201  	tc := generateBenchmarkMaterial(L)
   202  	asig, _ := AggregateSignatures(tc.sigs)
   203  	asigb := asig.Marshal()
   204  
   205  	fn := func() {
   206  		pks, _ := MultiplePublicKeysFromBytes(tc.pkbs)
   207  		sig, _ := SignatureFromBytes(asigb)
   208  		FastAggregateVerify(sig, tc.msg, pks)
   209  	}
   210  	runUncached(b, "Uncached", fn)
   211  	runCached(b, "Cached", fn)
   212  }
   213  
   214  // End-to-end benchmark where all inputs are []byte
   215  // Distinct messages, VerifyMultipleSignatures
   216  func BenchmarkVerifyMultipleSignatures(b *testing.B) {
   217  	L := benchAggregateLen
   218  	tc := generateBenchmarkMaterialMulti(L)
   219  
   220  	fn := func() {
   221  		pks, _ := MultiplePublicKeysFromBytes(tc.pkbs)
   222  		VerifyMultipleSignatures(tc.sigbs, tc.msgs, pks)
   223  	}
   224  	runUncached(b, "Uncached", fn)
   225  	runCached(b, "Cached", fn)
   226  }
   227  
   228  // End-to-end benchmark where all inputs are []byte
   229  // Distinct messages, verify each signature one by one
   230  func BenchmarkVerifyMultipleNaive(b *testing.B) {
   231  	L := benchAggregateLen
   232  	tc := generateBenchmarkMaterialMulti(L)
   233  
   234  	fn := func() {
   235  		pks, _ := MultiplePublicKeysFromBytes(tc.pkbs)
   236  		for i := 0; i < L; i++ {
   237  			VerifySignature(tc.sigbs[i], tc.msgs[i], pks[i])
   238  		}
   239  	}
   240  	runUncached(b, "Uncached", fn)
   241  	runCached(b, "Cached", fn)
   242  }
   243  
   244  type benchmarkTestCase struct {
   245  	sks   []types.SecretKey
   246  	pks   []types.PublicKey
   247  	pkbs  [][]byte
   248  	msg   []byte
   249  	sigs  []types.Signature
   250  	sigbs [][]byte
   251  	asig  types.Signature
   252  }
   253  
   254  func generateBenchmarkMaterial(L int) *benchmarkTestCase {
   255  	tc := &benchmarkTestCase{}
   256  	tc.sks = make([]types.SecretKey, L)
   257  	tc.pks = make([]types.PublicKey, L)
   258  	tc.pkbs = make([][]byte, L)
   259  	tc.msg = make([]byte, 32)
   260  	tc.sigs = make([]types.Signature, L)
   261  	tc.sigbs = make([][]byte, L)
   262  
   263  	rand.Read(tc.msg)
   264  
   265  	for i := 0; i < L; i++ {
   266  		sk, _ := RandKey()
   267  		pk := sk.PublicKey()
   268  		sig := Sign(sk, tc.msg)
   269  		tc.sks[i] = sk
   270  		tc.pks[i] = pk
   271  		tc.pkbs[i] = pk.Marshal()
   272  		tc.sigs[i] = sig
   273  		tc.sigbs[i] = sig.Marshal()
   274  	}
   275  	return tc
   276  }
   277  
   278  type benchmarkTestCaseMulti struct {
   279  	sks   []types.SecretKey
   280  	pks   []types.PublicKey
   281  	pkbs  [][]byte
   282  	msgs  [][32]byte
   283  	sigs  []types.Signature
   284  	sigbs [][]byte
   285  	asig  types.Signature
   286  }
   287  
   288  func generateBenchmarkMaterialMulti(L int) *benchmarkTestCaseMulti {
   289  	tc := &benchmarkTestCaseMulti{}
   290  	tc.sks = make([]types.SecretKey, L)
   291  	tc.pks = make([]types.PublicKey, L)
   292  	tc.pkbs = make([][]byte, L)
   293  	tc.msgs = make([][32]byte, L)
   294  	tc.sigs = make([]types.Signature, L)
   295  	tc.sigbs = make([][]byte, L)
   296  
   297  	for i := 0; i < L; i++ {
   298  		sk, _ := RandKey()
   299  		pk := sk.PublicKey()
   300  		rand.Read(tc.msgs[i][:])
   301  		sig := Sign(sk, tc.msgs[i][:])
   302  		tc.sks[i] = sk
   303  		tc.pks[i] = pk
   304  		tc.pkbs[i] = pk.Marshal()
   305  		tc.sigs[i] = sig
   306  		tc.sigbs[i] = sig.Marshal()
   307  	}
   308  	return tc
   309  }
   310  
   311  func runUncached(b *testing.B, name string, fn func()) {
   312  	b.Run(name, func(b *testing.B) {
   313  		for i := 0; i < b.N; i++ {
   314  			b.StopTimer()
   315  			resetCache()
   316  			b.StartTimer()
   317  			fn()
   318  		}
   319  	})
   320  }
   321  
   322  func runCached(b *testing.B, name string, fn func()) {
   323  	for i := 0; i < b.N; i++ {
   324  		fn() // populate cache
   325  	}
   326  	b.Run(name, func(b *testing.B) {
   327  		for i := 0; i < b.N; i++ {
   328  			fn()
   329  		}
   330  	})
   331  }
   332  
   333  func resetCache() {
   334  	publicKeyCache.Purge()
   335  	signatureCache.Purge()
   336  }