bench_test.go raw
1 // Copyright 2013-2016 The btcsuite developers
2 // Copyright (c) 2015-2022 The Decred developers
3 // Use of this source code is governed by an ISC
4 // license that can be found in the LICENSE file.
5
6 package ecdsa
7
8 import (
9 "testing"
10
11 "next.orly.dev/pkg/nostr/crypto/ec/secp256k1"
12 "next.orly.dev/pkg/nostr/encoders/hex"
13 )
14
15 // hexToModNScalar converts the passed hex string into a ModNScalar and will
16 // panic if there is an error. This is only provided for the hard-coded
17 // constants so errors in the source code can be detected. It will only (and
18 // must only) be called with hard-coded values.
19 func hexToModNScalar(s string) *secp256k1.ModNScalar {
20 b, err := hex.Dec(s)
21 if err != nil {
22 panic("invalid hex in source file: " + s)
23 }
24 var scalar secp256k1.ModNScalar
25 if overflow := scalar.SetByteSlice(b); overflow {
26 panic("hex in source file overflows mod N scalar: " + s)
27 }
28 return &scalar
29 }
30
31 // hexToFieldVal converts the passed hex string into a FieldVal and will panic
32 // if there is an error. This is only provided for the hard-coded constants so
33 // errors in the source code can be detected. It will only (and must only) be
34 // called with hard-coded values.
35 func hexToFieldVal(s string) *secp256k1.FieldVal {
36 b, err := hex.Dec(s)
37 if err != nil {
38 panic("invalid hex in source file: " + s)
39 }
40 var f secp256k1.FieldVal
41 if overflow := f.SetByteSlice(b); overflow {
42 panic("hex in source file overflows mod P: " + s)
43 }
44 return &f
45 }
46
47 // BenchmarkSigVerify benchmarks how long it takes the secp256k1 curve to
48 // verify signatures.
49 func BenchmarkSigVerify(b *testing.B) {
50 // Randomly generated keypair.
51 // Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
52 pubKey := secp256k1.NewPublicKey(
53 hexToFieldVal("d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab"),
54 hexToFieldVal("ab65528eefbb8057aa85d597258a3fbd481a24633bc9b47a9aa045c91371de52"),
55 )
56 // Double sha256 of by{0x01, 0x02, 0x03, 0x04}
57 msgHash := hexToBytes("8de472e2399610baaa7f84840547cd409434e31f5d3bd71e4d947f283874f9c0")
58 sig := NewSignature(
59 hexToModNScalar("fef45d2892953aa5bbcdb057b5e98b208f1617a7498af7eb765574e29b5d9c2c"),
60 hexToModNScalar("d47563f52aac6b04b55de236b7c515eb9311757db01e02cff079c3ca6efb063f"),
61 )
62 if !sig.Verify(msgHash, pubKey) {
63 b.Errorf("Signature failed to verify")
64 return
65 }
66 b.ReportAllocs()
67 b.ResetTimer()
68 for i := 0; i < b.N; i++ {
69 sig.Verify(msgHash, pubKey)
70 }
71 }
72
73 // BenchmarkSign benchmarks how long it takes to sign a message.
74 func BenchmarkSign(b *testing.B) {
75 // Randomly generated keypair.
76 d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d")
77 secKey := secp256k1.NewSecretKey(d)
78 // blake256 of by{0x01, 0x02, 0x03, 0x04}.
79 msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7")
80 b.ReportAllocs()
81 b.ResetTimer()
82 for i := 0; i < b.N; i++ {
83 signRFC6979(secKey, msgHash)
84 }
85 }
86
87 // BenchmarkSigSerialize benchmarks how long it takes to serialize a typical
88 // signature with the strict DER encoding.
89 func BenchmarkSigSerialize(b *testing.B) {
90 // Randomly generated keypair.
91 // Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
92 // Signature for double sha256 of by{0x01, 0x02, 0x03, 0x04}.
93 sig := NewSignature(
94 hexToModNScalar("fef45d2892953aa5bbcdb057b5e98b208f1617a7498af7eb765574e29b5d9c2c"),
95 hexToModNScalar("d47563f52aac6b04b55de236b7c515eb9311757db01e02cff079c3ca6efb063f"),
96 )
97 b.ReportAllocs()
98 b.ResetTimer()
99 for i := 0; i < b.N; i++ {
100 sig.Serialize()
101 }
102 }
103
104 // BenchmarkNonceRFC6979 benchmarks how long it takes to generate a
105 // deterministic nonce according to RFC6979.
106 func BenchmarkNonceRFC6979(b *testing.B) {
107 // Randomly generated keypair.
108 // Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
109 // X: d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab
110 // Y: ab65528eefbb8057aa85d597258a3fbd481a24633bc9b47a9aa045c91371de52
111 secKeyStr := "9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d"
112 secKey := hexToBytes(secKeyStr)
113 // BLAKE-256 of by{0x01, 0x02, 0x03, 0x04}.
114 msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7")
115 b.ReportAllocs()
116 b.ResetTimer()
117 var noElideNonce *secp256k1.ModNScalar
118 for i := 0; i < b.N; i++ {
119 noElideNonce = secp256k1.NonceRFC6979(secKey, msgHash, nil, nil, 0)
120 }
121 _ = noElideNonce
122 }
123
124 // BenchmarkSignCompact benchmarks how long it takes to produce a compact
125 // signature for a message.
126 func BenchmarkSignCompact(b *testing.B) {
127 d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d")
128 secKey := secp256k1.NewSecretKey(d)
129 // blake256 of by{0x01, 0x02, 0x03, 0x04}.
130 msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7")
131 b.ReportAllocs()
132 b.ResetTimer()
133 for i := 0; i < b.N; i++ {
134 _ = SignCompact(secKey, msgHash, true)
135 }
136 }
137
138 // BenchmarkRecoverCompact benchmarks how long it takes to recover a public key
139 // given a compact signature and message.
140 func BenchmarkRecoverCompact(b *testing.B) {
141 // Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
142 wantPubKey := secp256k1.NewPublicKey(
143 hexToFieldVal("d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab"),
144 hexToFieldVal("ab65528eefbb8057aa85d597258a3fbd481a24633bc9b47a9aa045c91371de52"),
145 )
146 compactSig := hexToBytes(
147 "205978b7896bc71676ba2e459882a8f52e1299449596c4f" +
148 "93c59bf1fbfa2f9d3b76ecd0c99406f61a6de2bb5a8937c061c176ecf381d0231e0d" +
149 "af73b922c8952c7",
150 )
151 // blake256 of by{0x01, 0x02, 0x03, 0x04}.
152 msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7")
153 // Ensure a valid compact signature is being benchmarked.
154 pubKey, wasCompressed, err := RecoverCompact(compactSig, msgHash)
155 if err != nil {
156 b.Fatalf("unexpected err: %v", err)
157 }
158 if !wasCompressed {
159 b.Fatal("recover claims uncompressed pubkey")
160 }
161 if !pubKey.IsEqual(wantPubKey) {
162 b.Fatal("recover returned unexpected pubkey")
163 }
164 b.ReportAllocs()
165 b.ResetTimer()
166 for i := 0; i < b.N; i++ {
167 _, _, _ = RecoverCompact(compactSig, msgHash)
168 }
169 }
170