1 // Copyright 2013-2016 The btcsuite developers
2 // Copyright (c) 2015-2021 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 schnorr
7 8 import (
9 "math/big"
10 "testing"
11 12 "next.orly.dev/pkg/nostr/crypto/ec"
13 "next.orly.dev/pkg/nostr/crypto/ec/secp256k1"
14 "next.orly.dev/pkg/nostr/encoders/hex"
15 "github.com/minio/sha256-simd"
16 )
17 18 // hexToBytes converts the passed hex string into bytes and will panic if there
19 // is an error. This is only provided for the hard-coded constants, so errors in
20 // the source code can be detected. It will only (and must only) be called with
21 // hard-coded values.
22 func hexToBytes(s string) []byte {
23 b, err := hex.Dec(s)
24 if err != nil {
25 panic("invalid hex in source file: " + s)
26 }
27 return b
28 }
29 30 // hexToModNScalar converts the passed hex string into a ModNScalar and will
31 // panic if there is an error. This is only provided for the hard-coded
32 //
33 // constants, so errors in the source code can be detected. It will only (and
34 //
35 // must only) be called with hard-coded values.
36 func hexToModNScalar(s string) *btcec.ModNScalar {
37 b, err := hex.Dec(s)
38 if err != nil {
39 panic("invalid hex in source file: " + s)
40 }
41 var scalar btcec.ModNScalar
42 if overflow := scalar.SetByteSlice(b); overflow {
43 panic("hex in source file overflows mod N scalar: " + s)
44 }
45 return &scalar
46 }
47 48 // hexToFieldVal converts the passed hex string into a FieldVal and will panic
49 // if there is an error. This is only provided for the hard-coded constants, so
50 // errors in the source code can be detected. It will only (and must only) be
51 // called with hard-coded values.
52 func hexToFieldVal(s string) *btcec.FieldVal {
53 b, err := hex.Dec(s)
54 if err != nil {
55 panic("invalid hex in source file: " + s)
56 }
57 var f btcec.FieldVal
58 if overflow := f.SetByteSlice(b); overflow {
59 panic("hex in source file overflows mod P: " + s)
60 }
61 return &f
62 }
63 64 // fromHex converts the passed hex string into a big integer pointer and will
65 // panic if there is an error. This is only provided for the hard-coded
66 // constants, so errors in the source code can be detected. It will only (and
67 // must only) be called for initialization purposes.
68 func fromHex(s string) *big.Int {
69 if s == "" {
70 return big.NewInt(0)
71 }
72 r, ok := new(big.Int).SetString(s, 16)
73 if !ok {
74 panic("invalid hex in source file: " + s)
75 }
76 return r
77 }
78 79 var testOk bool
80 81 // BenchmarkSign benchmarks how long it takes to sign a message.
82 func BenchmarkSign(b *testing.B) {
83 // Randomly generated keypair.
84 d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d")
85 privKey := secp256k1.NewSecretKey(d)
86 // blake256 of by{0x01, 0x02, 0x03, 0x04}.
87 msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7")
88 var auxBytes [32]byte
89 copy(auxBytes[:], msgHash)
90 auxBytes[0] ^= 1
91 var (
92 sig *Signature
93 err error
94 )
95 b.ReportAllocs()
96 b.ResetTimer()
97 for i := 0; i < b.N; i++ {
98 sig, err = Sign(
99 privKey, msgHash, CustomNonce(auxBytes), FastSign(),
100 )
101 }
102 testSig = sig
103 testErr = err
104 }
105 106 // BenchmarkSigVerify benchmarks how long it takes the secp256k1 curve to
107 // verify signatures.
108 func BenchmarkSigVerify(b *testing.B) {
109 // Randomly generated keypair.
110 d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d")
111 privKey := secp256k1.NewSecretKey(d)
112 pubKey := privKey.PubKey()
113 // Double sha256 of by{0x01, 0x02, 0x03, 0x04}
114 msgHash := sha256.Sum256([]byte("benchmark"))
115 sig, err := Sign(privKey, msgHash[:])
116 if err != nil {
117 b.Fatalf("unable to sign: %v", err)
118 }
119 if !sig.Verify(msgHash[:], pubKey) {
120 b.Errorf("Signature failed to verify")
121 return
122 }
123 var ok bool
124 b.ReportAllocs()
125 b.ResetTimer()
126 for i := 0; i < b.N; i++ {
127 ok = sig.Verify(msgHash[:], pubKey)
128 }
129 testOk = ok
130 }
131 132 // Used to ensure the compiler doesn't optimize away the benchmark.
133 var (
134 testSig *Signature
135 testErr error
136 )
137 138 // BenchmarkSignRfc6979 benchmarks how long it takes to sign a message.
139 func BenchmarkSignRfc6979(b *testing.B) {
140 // Randomly generated keypair.
141 d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d")
142 privKey := secp256k1.NewSecretKey(d)
143 // blake256 of by{0x01, 0x02, 0x03, 0x04}.
144 msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7")
145 var (
146 sig *Signature
147 err error
148 )
149 b.ReportAllocs()
150 b.ResetTimer()
151 for i := 0; i < b.N; i++ {
152 sig, err = Sign(privKey, msgHash, FastSign())
153 }
154 testSig = sig
155 testErr = err
156 }
157 158 // BenchmarkSigSerialize benchmarks how long it takes to serialize Schnorr
159 // signatures.
160 func BenchmarkSigSerialize(b *testing.B) {
161 // From randomly generated keypair.
162 d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d")
163 secKey := secp256k1.NewSecretKey(d)
164 // blake256 of by{0x01, 0x02, 0x03, 0x04}.
165 msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7")
166 // Generate the signature.
167 sig, _ := Sign(secKey, msgHash)
168 b.ReportAllocs()
169 b.ResetTimer()
170 for i := 0; i < b.N; i++ {
171 sig.Serialize()
172 }
173 }
174