schnorr_test.go raw
1 //go:build !js && !wasm && !tinygo && !wasm32
2
3 package p256k1
4
5 import (
6 "testing"
7 )
8
9 func TestSchnorrSignVerify(t *testing.T) {
10 // Generate keypair
11 kp, err := KeyPairGenerate()
12 if err != nil {
13 t.Fatalf("failed to generate keypair: %v", err)
14 }
15 defer kp.Clear()
16
17 // Get x-only pubkey
18 xonly, err := kp.XOnlyPubkey()
19 if err != nil {
20 t.Fatalf("failed to get x-only pubkey: %v", err)
21 }
22
23 // Create message
24 msg := make([]byte, 32)
25 for i := range msg {
26 msg[i] = byte(i)
27 }
28
29 // Sign
30 var sig [64]byte
31 if err := SchnorrSign(sig[:], msg, kp, nil); err != nil {
32 t.Fatalf("failed to sign: %v", err)
33 }
34
35 // Verify
36 if !SchnorrVerify(sig[:], msg, xonly) {
37 t.Error("signature verification failed")
38 }
39
40 // Test with wrong message
41 wrongMsg := make([]byte, 32)
42 copy(wrongMsg, msg)
43 wrongMsg[0] ^= 1
44 if SchnorrVerify(sig[:], wrongMsg, xonly) {
45 t.Error("signature verification should fail with wrong message")
46 }
47 }
48
49 func TestSchnorrSignWithAuxRand(t *testing.T) {
50 // Generate keypair
51 kp, err := KeyPairGenerate()
52 if err != nil {
53 t.Fatalf("failed to generate keypair: %v", err)
54 }
55 defer kp.Clear()
56
57 // Get x-only pubkey
58 xonly, err := kp.XOnlyPubkey()
59 if err != nil {
60 t.Fatalf("failed to get x-only pubkey: %v", err)
61 }
62
63 // Create message
64 msg := make([]byte, 32)
65 for i := range msg {
66 msg[i] = byte(i)
67 }
68
69 // Auxiliary randomness
70 auxRand := make([]byte, 32)
71 for i := range auxRand {
72 auxRand[i] = byte(i + 100)
73 }
74
75 // Sign
76 var sig [64]byte
77 if err := SchnorrSign(sig[:], msg, kp, auxRand); err != nil {
78 t.Fatalf("failed to sign: %v", err)
79 }
80
81 // Verify
82 if !SchnorrVerify(sig[:], msg, xonly) {
83 t.Error("signature verification failed")
84 }
85 }
86
87 func TestSchnorrVerifyInvalid(t *testing.T) {
88 // Generate keypair
89 kp, err := KeyPairGenerate()
90 if err != nil {
91 t.Fatalf("failed to generate keypair: %v", err)
92 }
93 defer kp.Clear()
94
95 // Get x-only pubkey
96 xonly, err := kp.XOnlyPubkey()
97 if err != nil {
98 t.Fatalf("failed to get x-only pubkey: %v", err)
99 }
100
101 msg := make([]byte, 32)
102
103 // Test with invalid signature length
104 if SchnorrVerify([]byte{1}, msg, xonly) {
105 t.Error("should fail with invalid signature length")
106 }
107
108 // Test with invalid message length
109 var sig [64]byte
110 if SchnorrVerify(sig[:], []byte{1}, xonly) {
111 t.Error("should fail with invalid message length")
112 }
113
114 // Test with nil pubkey
115 if SchnorrVerify(sig[:], msg, nil) {
116 t.Error("should fail with nil pubkey")
117 }
118 }
119
120 func TestNonceFunctionBIP340(t *testing.T) {
121 key32 := make([]byte, 32)
122 xonlyPk32 := make([]byte, 32)
123 msg := make([]byte, 32) // BIP-340 requires 32-byte message hash
124 auxRand32 := make([]byte, 32)
125
126 // Initialize test data
127 for i := range key32 {
128 key32[i] = byte(i)
129 }
130 for i := range xonlyPk32 {
131 xonlyPk32[i] = byte(i + 10)
132 }
133 for i := range auxRand32 {
134 auxRand32[i] = byte(i + 20)
135 }
136
137 // Test with aux random
138 var nonce1 [32]byte
139 if err := NonceFunctionBIP340(nonce1[:], msg, key32, xonlyPk32, auxRand32); err != nil {
140 t.Fatalf("nonce generation failed: %v", err)
141 }
142
143 // Test without aux random
144 var nonce2 [32]byte
145 if err := NonceFunctionBIP340(nonce2[:], msg, key32, xonlyPk32, nil); err != nil {
146 t.Fatalf("nonce generation failed: %v", err)
147 }
148
149 // Nonces should be different
150 allSame := true
151 for i := 0; i < 32; i++ {
152 if nonce1[i] != nonce2[i] {
153 allSame = false
154 break
155 }
156 }
157 if allSame {
158 t.Error("nonces should differ with different aux random")
159 }
160 }
161
162 func TestSchnorrMultipleSignatures(t *testing.T) {
163 // Test that multiple signatures with same keypair are different when using different aux_rand
164 kp, err := KeyPairGenerate()
165 if err != nil {
166 t.Fatalf("failed to generate keypair: %v", err)
167 }
168 defer kp.Clear()
169
170 xonly, err := kp.XOnlyPubkey()
171 if err != nil {
172 t.Fatalf("failed to get x-only pubkey: %v", err)
173 }
174
175 msg := make([]byte, 32)
176
177 // Sign without aux_rand (deterministic - should be same)
178 var sig1, sig2 [64]byte
179 if err := SchnorrSign(sig1[:], msg, kp, nil); err != nil {
180 t.Fatalf("failed to sign: %v", err)
181 }
182 if err := SchnorrSign(sig2[:], msg, kp, nil); err != nil {
183 t.Fatalf("failed to sign: %v", err)
184 }
185
186 // Both should verify
187 if !SchnorrVerify(sig1[:], msg, xonly) {
188 t.Error("signature 1 verification failed")
189 }
190 if !SchnorrVerify(sig2[:], msg, xonly) {
191 t.Error("signature 2 verification failed")
192 }
193
194 // Without aux_rand, signatures should be deterministic (same)
195 allSame := true
196 for i := 0; i < 64; i++ {
197 if sig1[i] != sig2[i] {
198 allSame = false
199 break
200 }
201 }
202 if !allSame {
203 t.Error("without aux_rand, signatures should be deterministic (same)")
204 }
205
206 // Sign with different aux_rand (should be different)
207 auxRand1 := make([]byte, 32)
208 auxRand2 := make([]byte, 32)
209 for i := range auxRand1 {
210 auxRand1[i] = byte(i)
211 auxRand2[i] = byte(i + 1)
212 }
213
214 if err := SchnorrSign(sig1[:], msg, kp, auxRand1); err != nil {
215 t.Fatalf("failed to sign: %v", err)
216 }
217 if err := SchnorrSign(sig2[:], msg, kp, auxRand2); err != nil {
218 t.Fatalf("failed to sign: %v", err)
219 }
220
221 // Both should verify
222 if !SchnorrVerify(sig1[:], msg, xonly) {
223 t.Error("signature 1 verification failed")
224 }
225 if !SchnorrVerify(sig2[:], msg, xonly) {
226 t.Error("signature 2 verification failed")
227 }
228
229 // With different aux_rand, signatures should differ
230 allSame = true
231 for i := 0; i < 64; i++ {
232 if sig1[i] != sig2[i] {
233 allSame = false
234 break
235 }
236 }
237 if allSame {
238 t.Error("with different aux_rand, signatures should differ")
239 }
240 }
241
242 func BenchmarkSchnorrVerify(b *testing.B) {
243 // Generate test data once outside the benchmark loop
244 kp, err := KeyPairGenerate()
245 if err != nil {
246 b.Fatalf("failed to generate keypair: %v", err)
247 }
248 defer kp.Clear()
249
250 xonly, err := kp.XOnlyPubkey()
251 if err != nil {
252 b.Fatalf("failed to get x-only pubkey: %v", err)
253 }
254
255 msg := make([]byte, 32)
256 for i := range msg {
257 msg[i] = byte(i)
258 }
259
260 sig := make([]byte, 64)
261 if err := SchnorrSign(sig, msg, kp, nil); err != nil {
262 b.Fatalf("failed to sign: %v", err)
263 }
264
265 // Convert to internal types once
266 var secpXonly secp256k1_xonly_pubkey
267 copy(secpXonly.data[:], xonly.data[:])
268
269 // Benchmark verification with pre-computed values
270 b.ResetTimer()
271 b.ReportAllocs()
272
273 ctx := getSchnorrVerifyContext()
274 for i := 0; i < b.N; i++ {
275 result := secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &secpXonly)
276 if result == 0 {
277 b.Fatal("verification failed")
278 }
279 }
280 }
281