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 }