1 // Copyright 2013-2016 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
4 5 package btcec
6 7 import (
8 "math/big"
9 "testing"
10 11 "next.orly.dev/pkg/nostr/crypto/ec/secp256k1"
12 "next.orly.dev/pkg/nostr/encoders/hex"
13 )
14 15 // setHex decodes the passed big-endian hex string into the internal field value
16 // representation. Only the first 32-bytes are used.
17 //
18 // This is NOT constant time.
19 //
20 // The field value is returned to support chaining. This enables syntax like:
21 // f := new(FieldVal).SetHex("0abc").Add(1) so that f = 0x0abc + 1
22 func setHex(hexString string) *FieldVal {
23 if len(hexString)%2 != 0 {
24 hexString = "0" + hexString
25 }
26 bytes, _ := hex.Dec(hexString)
27 var f FieldVal
28 f.SetByteSlice(bytes)
29 return &f
30 }
31 32 // hexToFieldVal converts the passed hex string into a FieldVal and will panic
33 // if there is an error. This is only provided for the hard-coded constants so
34 // errors in the source code can be detected. It will only (and must only) be
35 // called with hard-coded values.
36 func hexToFieldVal(s string) *FieldVal {
37 b, err := hex.Dec(s)
38 if err != nil {
39 panic("invalid hex in source file: " + s)
40 }
41 var f FieldVal
42 if overflow := f.SetByteSlice(b); overflow {
43 panic("hex in source file overflows mod P: " + s)
44 }
45 return &f
46 }
47 48 // fromHex converts the passed hex string into a big integer pointer and will
49 // panic is there is an error. This is only provided for the hard-coded
50 // constants so errors in the source code can bet detected. It will only (and
51 // must only) be called for initialization purposes.
52 func fromHex(s string) *big.Int {
53 if s == "" {
54 return big.NewInt(0)
55 }
56 r, ok := new(big.Int).SetString(s, 16)
57 if !ok {
58 panic("invalid hex in source file: " + s)
59 }
60 return r
61 }
62 63 // jacobianPointFromHex decodes the passed big-endian hex strings into a
64 // Jacobian point with its internal fields set to the resulting values. Only
65 // the first 32-bytes are used.
66 func jacobianPointFromHex(x, y, z string) JacobianPoint {
67 var p JacobianPoint
68 p.X = *setHex(x)
69 p.Y = *setHex(y)
70 p.Z = *setHex(z)
71 return p
72 }
73 74 // BenchmarkAddNonConst benchmarks the secp256k1 curve AddNonConst function with
75 // Z values of 1 so that the associated optimizations are used.
76 func BenchmarkAddJacobian(b *testing.B) {
77 p1 := jacobianPointFromHex(
78 "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6",
79 "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232",
80 "1",
81 )
82 p2 := jacobianPointFromHex(
83 "34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6",
84 "0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232",
85 "1",
86 )
87 b.ReportAllocs()
88 b.ResetTimer()
89 var result JacobianPoint
90 for i := 0; i < b.N; i++ {
91 secp256k1.AddNonConst(&p1, &p2, &result)
92 }
93 }
94 95 // BenchmarkAddNonConstNotZOne benchmarks the secp256k1 curve AddNonConst
96 // function with Z values other than one so the optimizations associated with
97 // Z=1 aren't used.
98 func BenchmarkAddJacobianNotZOne(b *testing.B) {
99 x1 := setHex("d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718")
100 y1 := setHex("5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190")
101 z1 := setHex("2")
102 x2 := setHex("91abba6a34b7481d922a4bd6a04899d5a686f6cf6da4e66a0cb427fb25c04bd4")
103 y2 := setHex("03fede65e30b4e7576a2abefc963ddbf9fdccbf791b77c29beadefe49951f7d1")
104 z2 := setHex("3")
105 p1 := MakeJacobianPoint(x1, y1, z1)
106 p2 := MakeJacobianPoint(x2, y2, z2)
107 b.ReportAllocs()
108 b.ResetTimer()
109 var result JacobianPoint
110 for i := 0; i < b.N; i++ {
111 AddNonConst(&p1, &p2, &result)
112 }
113 }
114 115 // BenchmarkScalarBaseMult benchmarks the secp256k1 curve ScalarBaseMult
116 // function.
117 func BenchmarkScalarBaseMult(b *testing.B) {
118 k := fromHex("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575")
119 curve := S256()
120 for i := 0; i < b.N; i++ {
121 curve.ScalarBaseMult(k.Bytes())
122 }
123 }
124 125 // BenchmarkScalarBaseMultLarge benchmarks the secp256k1 curve ScalarBaseMult
126 // function with abnormally large k values.
127 func BenchmarkScalarBaseMultLarge(b *testing.B) {
128 k := fromHex("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c005751111111011111110")
129 curve := S256()
130 for i := 0; i < b.N; i++ {
131 curve.ScalarBaseMult(k.Bytes())
132 }
133 }
134 135 // BenchmarkScalarMult benchmarks the secp256k1 curve ScalarMult function.
136 func BenchmarkScalarMult(b *testing.B) {
137 x := fromHex("34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6")
138 y := fromHex("0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232")
139 k := fromHex("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575")
140 curve := S256()
141 for i := 0; i < b.N; i++ {
142 curve.ScalarMult(x, y, k.Bytes())
143 }
144 }
145 146 // hexToModNScalar converts the passed hex string into a ModNScalar and will
147 // panic if there is an error. This is only provided for the hard-coded
148 // constants so errors in the source code can be detected. It will only (and
149 // must only) be called with hard-coded values.
150 func hexToModNScalar(s string) *ModNScalar {
151 b, err := hex.Dec(s)
152 if err != nil {
153 panic("invalid hex in source file: " + s)
154 }
155 var scalar ModNScalar
156 if overflow := scalar.SetByteSlice(b); overflow {
157 panic("hex in source file overflows mod N scalar: " + s)
158 }
159 return &scalar
160 }
161 162 // BenchmarkFieldNormalize benchmarks how long it takes the internal field
163 // to perform normalization (which includes modular reduction).
164 func BenchmarkFieldNormalize(b *testing.B) {
165 // The normalize function is constant time so default value is fine.
166 var f FieldVal
167 for i := 0; i < b.N; i++ {
168 f.Normalize()
169 }
170 }
171 172 // BenchmarkParseCompressedPubKey benchmarks how long it takes to decompress and
173 // validate a compressed public key from a byte array.
174 func BenchmarkParseCompressedPubKey(b *testing.B) {
175 rawPk, _ := hex.Dec("0234f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6")
176 177 var (
178 pk *PublicKey
179 err error
180 )
181 b.ReportAllocs()
182 b.ResetTimer()
183 for i := 0; i < b.N; i++ {
184 pk, err = ParsePubKey(rawPk)
185 }
186 _ = pk
187 _ = err
188 }
189