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 secp256k1
7
8 import (
9 "testing"
10 )
11
12 // BenchmarkAddNonConst benchmarks the secp256k1 curve AddNonConst function with
13 // Z values of 1 so that the associated optimizations are used.
14 func BenchmarkAddNonConst(b *testing.B) {
15 p1 := jacobianPointFromHex(
16 "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6",
17 "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232",
18 "1",
19 )
20 p2 := jacobianPointFromHex(
21 "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6",
22 "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232",
23 "1",
24 )
25 b.ReportAllocs()
26 b.ResetTimer()
27 var result JacobianPoint
28 for i := 0; i < b.N; i++ {
29 AddNonConst(&p1, &p2, &result)
30 }
31 }
32
33 // BenchmarkAddNonConstNotZOne benchmarks the secp256k1 curve AddNonConst
34 // function with Z values other than one so the optimizations associated with
35 // Z=1 aren't used.
36 func BenchmarkAddNonConstNotZOne(b *testing.B) {
37 x1 := new(FieldVal).SetHex("d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718")
38 y1 := new(FieldVal).SetHex("5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190")
39 z1 := new(FieldVal).SetHex("2")
40 x2 := new(FieldVal).SetHex("91abba6a34b7481d922a4bd6a04899d5a686f6cf6da4e66a0cb427fb25c04bd4")
41 y2 := new(FieldVal).SetHex("03fede65e30b4e7576a2abefc963ddbf9fdccbf791b77c29beadefe49951f7d1")
42 z2 := new(FieldVal).SetHex("3")
43 p1 := MakeJacobianPoint(x1, y1, z1)
44 p2 := MakeJacobianPoint(x2, y2, z2)
45 b.ReportAllocs()
46 b.ResetTimer()
47 var result JacobianPoint
48 for i := 0; i < b.N; i++ {
49 AddNonConst(&p1, &p2, &result)
50 }
51 }
52
53 // BenchmarkScalarBaseMultNonConst benchmarks multiplying a scalar by the base
54 // point of the curve.
55 func BenchmarkScalarBaseMultNonConst(b *testing.B) {
56 k := hexToModNScalar("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575")
57 b.ReportAllocs()
58 b.ResetTimer()
59 var result JacobianPoint
60 for i := 0; i < b.N; i++ {
61 ScalarBaseMultNonConst(k, &result)
62 }
63 }
64
65 // BenchmarkSplitK benchmarks decomposing scalars into a balanced length-two
66 // representation.
67 func BenchmarkSplitK(b *testing.B) {
68 // Values computed from the group half order and lambda such that they
69 // exercise the decomposition edge cases and maximize the bit lengths of the
70 // produced scalars.
71 h := "7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0"
72 negOne := new(ModNScalar).NegateVal(oneModN)
73 halfOrder := hexToModNScalar(h)
74 halfOrderMOne := new(ModNScalar).Add2(halfOrder, negOne)
75 halfOrderPOne := new(ModNScalar).Add2(halfOrder, oneModN)
76 lambdaMOne := new(ModNScalar).Add2(endoLambda, negOne)
77 lambdaPOne := new(ModNScalar).Add2(endoLambda, oneModN)
78 negLambda := new(ModNScalar).NegateVal(endoLambda)
79 halfOrderMOneMLambda := new(ModNScalar).Add2(halfOrderMOne, negLambda)
80 halfOrderMLambda := new(ModNScalar).Add2(halfOrder, negLambda)
81 halfOrderPOneMLambda := new(ModNScalar).Add2(halfOrderPOne, negLambda)
82 lambdaPHalfOrder := new(ModNScalar).Add2(endoLambda, halfOrder)
83 lambdaPOnePHalfOrder := new(ModNScalar).Add2(lambdaPOne, halfOrder)
84 scalars := []*ModNScalar{
85 new(ModNScalar), // zero
86 oneModN, // one
87 negOne, // group order - 1 (aka -1 mod N)
88 halfOrderMOneMLambda, // group half order - 1 - lambda
89 halfOrderMLambda, // group half order - lambda
90 halfOrderPOneMLambda, // group half order + 1 - lambda
91 halfOrderMOne, // group half order - 1
92 halfOrder, // group half order
93 halfOrderPOne, // group half order + 1
94 lambdaMOne, // lambda - 1
95 endoLambda, // lambda
96 lambdaPOne, // lambda + 1
97 lambdaPHalfOrder, // lambda + group half order
98 lambdaPOnePHalfOrder, // lambda + 1 + group half order
99 }
100 b.ReportAllocs()
101 b.ResetTimer()
102 for i := 0; i < b.N; i += len(scalars) {
103 for j := 0; j < len(scalars); j++ {
104 _, _ = splitK(scalars[j])
105 }
106 }
107 }
108
109 // BenchmarkScalarMultNonConst benchmarks multiplying a scalar by an arbitrary
110 // point on the curve.
111 func BenchmarkScalarMultNonConst(b *testing.B) {
112 k := hexToModNScalar("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575")
113 point := jacobianPointFromHex(
114 "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6",
115 "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232",
116 "1",
117 )
118 b.ReportAllocs()
119 b.ResetTimer()
120 var result JacobianPoint
121 for i := 0; i < b.N; i++ {
122 ScalarMultNonConst(k, &point, &result)
123 }
124 }
125
126 // BenchmarkNAF benchmarks conversion of a positive integer into its
127 // non-adjacent form representation.
128 func BenchmarkNAF(b *testing.B) {
129 k := fromHex("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575")
130 kBytes := k.Bytes()
131 b.ReportAllocs()
132 b.ResetTimer()
133 for i := 0; i < b.N; i++ {
134 naf(kBytes)
135 }
136 }
137
138 // BenchmarkPubKeyDecompress benchmarks how long it takes to decompress the y
139 // coordinate from a given public key x coordinate.
140 func BenchmarkPubKeyDecompress(b *testing.B) {
141 // Randomly generated keypair.
142 // Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
143 pubKeyX := new(FieldVal).SetHex("d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab")
144 b.ReportAllocs()
145 b.ResetTimer()
146 var y FieldVal
147 for i := 0; i < b.N; i++ {
148 _ = DecompressY(pubKeyX, false, &y)
149 }
150 }
151
152 // BenchmarkParsePubKeyCompressed benchmarks how long it takes to parse a
153 // compressed public key with an even y coordinate.
154 func BenchmarkParsePubKeyCompressed(b *testing.B) {
155 format := "02"
156 x := "ce0b14fb842b1ba549fdd675c98075f12e9c510f8ef52bd021a9a1f4809d3b4d"
157 pubKeyBytes := hexToBytes(format + x)
158 b.ReportAllocs()
159 b.ResetTimer()
160 for i := 0; i < b.N; i++ {
161 ParsePubKey(pubKeyBytes)
162 }
163 }
164
165 // BenchmarkParsePubKeyUncompressed benchmarks how long it takes to parse an
166 // uncompressed public key.
167 func BenchmarkParsePubKeyUncompressed(b *testing.B) {
168 format := "04"
169 x := "11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"
170 y := "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3"
171 pubKeyBytes := hexToBytes(format + x + y)
172 b.ReportAllocs()
173 b.ResetTimer()
174 for i := 0; i < b.N; i++ {
175 ParsePubKey(pubKeyBytes)
176 }
177 }
178