signature_test.go raw
1 // Copyright (c) 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 // TODO: change this test to use sha256 (tests are still valid only the
7 // generated hash differs, of course)
8
9 package ecdsa
10
11 import (
12 "errors"
13 "math/rand"
14 "testing"
15 "time"
16
17 "next.orly.dev/pkg/nostr/crypto/ec/secp256k1"
18 "next.orly.dev/pkg/nostr/encoders/hex"
19 "next.orly.dev/pkg/nostr/utils"
20 "next.orly.dev/pkg/lol/chk"
21 )
22
23 // hexToBytes converts the passed hex string into bytes and will panic if there
24 // is an error. This is only provided for the hard-coded constants so errors in
25 // the source code can be detected. It will only (and must only) be called with
26 // hard-coded values.
27 func hexToBytes(s string) []byte {
28 b, err := hex.Dec(s)
29 if err != nil {
30 panic("invalid hex in source file: " + s)
31 }
32 return b
33 }
34
35 // TestSignatureParsing ensures that signatures are properly parsed according
36 // to DER rules. The error paths are tested as well.
37 func TestSignatureParsing(t *testing.T) {
38 tests := []struct {
39 name string
40 sig []byte
41 err error
42 }{
43 {
44 // signature from Decred blockchain tx
45 // 76634e947f49dfc6228c3e8a09cd3e9e15893439fc06df7df0fc6f08d659856c:0
46 name: "valid signature 1",
47 sig: hexToBytes(
48 "3045022100cd496f2ab4fe124f977ffe3caa09f7576d8a34156" +
49 "b4e55d326b4dffc0399a094022013500a0510b5094bff220c74656879b8ca03" +
50 "69d3da78004004c970790862fc03",
51 ),
52 err: nil,
53 }, {
54 // signature from Decred blockchain tx
55 // 76634e947f49dfc6228c3e8a09cd3e9e15893439fc06df7df0fc6f08d659856c:1
56 name: "valid signature 2",
57 sig: hexToBytes(
58 "3044022036334e598e51879d10bf9ce3171666bc2d1bbba6164" +
59 "cf46dd1d882896ba35d5d022056c39af9ea265c1b6d7eab5bc977f06f81e35c" +
60 "dcac16f3ec0fd218e30f2bad2a",
61 ),
62 err: nil,
63 }, {
64 name: "empty",
65 sig: nil,
66 err: ErrSigTooShort,
67 }, {
68 name: "too short",
69 sig: hexToBytes("30050201000200"),
70 err: ErrSigTooShort,
71 }, {
72 name: "too long",
73 sig: hexToBytes(
74 "3045022100f5353150d31a63f4a0d06d1f5a01ac65f7267a719e" +
75 "49f2a1ac584fd546bef074022030e09575e7a1541aa018876a4003cefe1b061a" +
76 "90556b5140c63e0ef8481352480101",
77 ),
78 err: ErrSigTooLong,
79 }, {
80 name: "bad ASN.1 sequence id",
81 sig: hexToBytes(
82 "3145022100f5353150d31a63f4a0d06d1f5a01ac65f7267a719e" +
83 "49f2a1ac584fd546bef074022030e09575e7a1541aa018876a4003cefe1b061a" +
84 "90556b5140c63e0ef848135248",
85 ),
86 err: ErrSigInvalidSeqID,
87 }, {
88 name: "mismatched data length (short one byte)",
89 sig: hexToBytes(
90 "3044022100f5353150d31a63f4a0d06d1f5a01ac65f7267a719e" +
91 "49f2a1ac584fd546bef074022030e09575e7a1541aa018876a4003cefe1b061a" +
92 "90556b5140c63e0ef848135248",
93 ),
94 err: ErrSigInvalidDataLen,
95 }, {
96 name: "mismatched data length (long one byte)",
97 sig: hexToBytes(
98 "3046022100f5353150d31a63f4a0d06d1f5a01ac65f7267a719e" +
99 "49f2a1ac584fd546bef074022030e09575e7a1541aa018876a4003cefe1b061a" +
100 "90556b5140c63e0ef848135248",
101 ),
102 err: ErrSigInvalidDataLen,
103 }, {
104 name: "bad R ASN.1 int marker",
105 sig: hexToBytes(
106 "304403204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d6" +
107 "24c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56c" +
108 "bbac4622082221a8768d1d09",
109 ),
110 err: ErrSigInvalidRIntID,
111 }, {
112 name: "zero R length",
113 sig: hexToBytes(
114 "30240200022030e09575e7a1541aa018876a4003cefe1b061a90" +
115 "556b5140c63e0ef848135248",
116 ),
117 err: ErrSigZeroRLen,
118 }, {
119 name: "negative R (too little padding)",
120 sig: hexToBytes(
121 "30440220b2ec8d34d473c3aa2ab5eb7cc4a0783977e5db8c8daf" +
122 "777e0b6d7bfa6b6623f302207df6f09af2c40460da2c2c5778f636d3b2e27e20" +
123 "d10d90f5a5afb45231454700",
124 ),
125 err: ErrSigNegativeR,
126 }, {
127 name: "too much R padding",
128 sig: hexToBytes(
129 "304402200077f6e93de5ed43cf1dfddaa79fca4b766e1a8fc879" +
130 "b0333d377f62538d7eb5022054fed940d227ed06d6ef08f320976503848ed1f5" +
131 "2d0dd6d17f80c9c160b01d86",
132 ),
133 err: ErrSigTooMuchRPadding,
134 }, {
135 name: "bad S ASN.1 int marker",
136 sig: hexToBytes(
137 "3045022100f5353150d31a63f4a0d06d1f5a01ac65f7267a719e" +
138 "49f2a1ac584fd546bef074032030e09575e7a1541aa018876a4003cefe1b061a" +
139 "90556b5140c63e0ef848135248",
140 ),
141 err: ErrSigInvalidSIntID,
142 }, {
143 name: "missing S ASN.1 int marker",
144 sig: hexToBytes(
145 "3023022100f5353150d31a63f4a0d06d1f5a01ac65f7267a719e" +
146 "49f2a1ac584fd546bef074",
147 ),
148 err: ErrSigMissingSTypeID,
149 }, {
150 name: "S length missing",
151 sig: hexToBytes(
152 "3024022100f5353150d31a63f4a0d06d1f5a01ac65f7267a719e" +
153 "49f2a1ac584fd546bef07402",
154 ),
155 err: ErrSigMissingSLen,
156 }, {
157 name: "invalid S length (short one byte)",
158 sig: hexToBytes(
159 "3045022100f5353150d31a63f4a0d06d1f5a01ac65f7267a719e" +
160 "49f2a1ac584fd546bef074021f30e09575e7a1541aa018876a4003cefe1b061a" +
161 "90556b5140c63e0ef848135248",
162 ),
163 err: ErrSigInvalidSLen,
164 }, {
165 name: "invalid S length (long one byte)",
166 sig: hexToBytes(
167 "3045022100f5353150d31a63f4a0d06d1f5a01ac65f7267a719e" +
168 "49f2a1ac584fd546bef074022130e09575e7a1541aa018876a4003cefe1b061a" +
169 "90556b5140c63e0ef848135248",
170 ),
171 err: ErrSigInvalidSLen,
172 }, {
173 name: "zero S length",
174 sig: hexToBytes(
175 "3025022100f5353150d31a63f4a0d06d1f5a01ac65f7267a719e" +
176 "49f2a1ac584fd546bef0740200",
177 ),
178 err: ErrSigZeroSLen,
179 }, {
180 name: "negative S (too little padding)",
181 sig: hexToBytes(
182 "304402204fc10344934662ca0a93a84d14d650d8a21cf2ab91f6" +
183 "08e8783d2999c955443202208441aacd6b17038ff3f6700b042934f9a6fea0ce" +
184 "c2051b51dc709e52a5bb7d61",
185 ),
186 err: ErrSigNegativeS,
187 }, {
188 name: "too much S padding",
189 sig: hexToBytes(
190 "304402206ad2fdaf8caba0f2cb2484e61b81ced77474b4c2aa06" +
191 "9c852df1351b3314fe20022000695ad175b09a4a41cd9433f6b2e8e83253d6a7" +
192 "402096ba313a7be1f086dde5",
193 ),
194 err: ErrSigTooMuchSPadding,
195 }, {
196 name: "R == 0",
197 sig: hexToBytes(
198 "30250201000220181522ec8eca07de4860a4acdd12909d831cc5" +
199 "6cbbac4622082221a8768d1d09",
200 ),
201 err: ErrSigRIsZero,
202 }, {
203 name: "R == N",
204 sig: hexToBytes(
205 "3045022100fffffffffffffffffffffffffffffffebaaedce6af" +
206 "48a03bbfd25e8cd03641410220181522ec8eca07de4860a4acdd12909d831cc5" +
207 "6cbbac4622082221a8768d1d09",
208 ),
209 err: ErrSigRTooBig,
210 }, {
211 name: "R > N (>32 bytes)",
212 sig: hexToBytes(
213 "3045022101cd496f2ab4fe124f977ffe3caa09f756283910fc1a" +
214 "96f60ee6873e88d3cfe1d50220181522ec8eca07de4860a4acdd12909d831cc5" +
215 "6cbbac4622082221a8768d1d09",
216 ),
217 err: ErrSigRTooBig,
218 }, {
219 name: "R > N",
220 sig: hexToBytes(
221 "3045022100fffffffffffffffffffffffffffffffebaaedce6af" +
222 "48a03bbfd25e8cd03641420220181522ec8eca07de4860a4acdd12909d831cc5" +
223 "6cbbac4622082221a8768d1d09",
224 ),
225 err: ErrSigRTooBig,
226 }, {
227 name: "S == 0",
228 sig: hexToBytes(
229 "302502204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d6" +
230 "24c6c61548ab5fb8cd41020100",
231 ),
232 err: ErrSigSIsZero,
233 }, {
234 name: "S == N",
235 sig: hexToBytes(
236 "304502204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d6" +
237 "24c6c61548ab5fb8cd41022100fffffffffffffffffffffffffffffffebaaedc" +
238 "e6af48a03bbfd25e8cd0364141",
239 ),
240 err: ErrSigSTooBig,
241 }, {
242 name: "S > N (>32 bytes)",
243 sig: hexToBytes(
244 "304502204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d6" +
245 "24c6c61548ab5fb8cd4102210113500a0510b5094bff220c74656879b784b246" +
246 "ba89c0a07bc49bcf05d8993d44",
247 ),
248 err: ErrSigSTooBig,
249 }, {
250 name: "S > N",
251 sig: hexToBytes(
252 "304502204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d6" +
253 "24c6c61548ab5fb8cd41022100fffffffffffffffffffffffffffffffebaaedc" +
254 "e6af48a03bbfd25e8cd0364142",
255 ),
256 err: ErrSigSTooBig,
257 },
258 }
259 for _, test := range tests {
260 _, err := ParseDERSignature(test.sig)
261 if !errors.Is(err, test.err) {
262 t.Errorf(
263 "%s mismatched err -- got %v, want %v", test.name, err,
264 test.err,
265 )
266 continue
267 }
268 }
269 }
270
271 // TestSignatureSerialize ensures that serializing signatures works as expected.
272 func TestSignatureSerialize(t *testing.T) {
273 tests := []struct {
274 name string
275 ecsig *Signature
276 expected []byte
277 }{
278 {
279 // signature from bitcoin blockchain tx
280 // 0437cd7f8525ceed2324359c2d0ba26006d92d85
281 "valid 1 - r and s most significant bits are zero",
282 &Signature{
283 r: *hexToModNScalar("4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41"),
284 s: *hexToModNScalar("181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09"),
285 },
286 hexToBytes(
287 "304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d62" +
288 "4c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc" +
289 "56cbbac4622082221a8768d1d09",
290 ),
291 }, {
292 // signature from bitcoin blockchain tx
293 // cb00f8a0573b18faa8c4f467b049f5d202bf1101d9ef2633bc611be70376a4b4
294 "valid 2 - r most significant bit is one",
295 &Signature{
296 r: *hexToModNScalar("82235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c30a23b0afbb8d178abcf3"),
297 s: *hexToModNScalar("24bf68e256c534ddfaf966bf908deb944305596f7bdcc38d69acad7f9c868724"),
298 },
299 hexToBytes(
300 "304502210082235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c" +
301 "30a23b0afbb8d178abcf3022024bf68e256c534ddfaf966bf908deb94430" +
302 "5596f7bdcc38d69acad7f9c868724",
303 ),
304 }, {
305 // signature from bitcoin blockchain tx
306 // fda204502a3345e08afd6af27377c052e77f1fefeaeb31bdd45f1e1237ca5470
307 //
308 // Note that signatures with an S component that is > half the group
309 // order are neither allowed nor produced in Decred, so this has been
310 // modified to expect the equally valid low S signature variant.
311 "valid 3 - s most significant bit is one",
312 &Signature{
313 r: *hexToModNScalar("1cadddc2838598fee7dc35a12b340c6bde8b389f7bfd19a1252a17c4b5ed2d71"),
314 s: *hexToModNScalar("c1a251bbecb14b058a8bd77f65de87e51c47e95904f4c0e9d52eddc21c1415ac"),
315 },
316 hexToBytes(
317 "304402201cadddc2838598fee7dc35a12b340c6bde8b389f7bfd1" +
318 "9a1252a17c4b5ed2d7102203e5dae44134eb4fa757428809a2178199e66f" +
319 "38daa53df51eaa380cab4222b95",
320 ),
321 }, {
322 "zero signature",
323 &Signature{
324 r: *new(secp256k1.ModNScalar).SetInt(0),
325 s: *new(secp256k1.ModNScalar).SetInt(0),
326 },
327 hexToBytes("3006020100020100"),
328 },
329 }
330 for i, test := range tests {
331 result := test.ecsig.Serialize()
332 if !utils.FastEqual(result, test.expected) {
333 t.Errorf(
334 "Serialize #%d (%s) unexpected result:\n"+
335 "got: %x\nwant: %x", i, test.name, result,
336 test.expected,
337 )
338 }
339 }
340 }
341
342 // signTest describes tests for producing and verifying ECDSA signatures for a
343 // selected set of secret keys, messages, and nonces that have been verified
344 // independently with the Sage computer algebra system. It is defined
345 // separately since it is intended for use in both normal and compact signature
346 // tests.
347 type signTest struct {
348 name string // test description
349 key string // hex encoded secret key
350 msg string // hex encoded message to sign before hashing
351 hash string // hex encoded hash of the message to sign
352 nonce string // hex encoded nonce to use in the signature calculation
353 rfc6979 bool // whether the nonce is an RFC6979 nonce
354 wantSigR string // hex encoded expected signature R
355 wantSigS string // hex encoded expected signature S
356 wantCode byte // expected public key recovery code
357 }
358
359 // // signTests returns several tests for ECDSA signatures that use a selected set
360 // // of secret keys, messages, and nonces that have been verified independently
361 // // with the Sage computer algebra system. It is defined here versus inside a
362 // // specific test function scope so it can be shared for both normal and compact
363 // // signature tests.
364 // func signTests(t *testing.T) []signTest {
365 // t.Helper()
366 //
367 // tests := []signTest{{
368 // name: "key 0x1, blake256(0x01020304), rfc6979 nonce",
369 // key: "0000000000000000000000000000000000000000000000000000000000000001",
370 // msg: "01020304",
371 // hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
372 // nonce: "4154324ecd4158938f1df8b5b659aeb639c7fbc36005934096e514af7d64bcc2",
373 // rfc6979: true,
374 // wantSigR: "c6c4137b0e5fbfc88ae3f293d7e80c8566c43ae20340075d44f75b009c943d09",
375 // wantSigS: "00ba213513572e35943d5acdd17215561b03f11663192a7252196cc8b2a99560",
376 // wantCode: 0,
377 // }, {
378 // name: "key 0x1, blake256(0x01020304), random nonce",
379 // key: "0000000000000000000000000000000000000000000000000000000000000001",
380 // msg: "01020304",
381 // hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
382 // nonce: "a6df66500afeb7711d4c8e2220960855d940a5ed57260d2c98fbf6066cca283e",
383 // rfc6979: false,
384 // wantSigR: "b073759a96a835b09b79e7b93c37fdbe48fb82b000c4a0e1404ba5d1fbc15d0a",
385 // wantSigS: "7e34928a3e3832ec21e7711644d9388f7deb6340ead661d7056b0665974b87f3",
386 // wantCode: pubKeyRecoveryCodeOddnessBit,
387 // }, {
388 // name: "key 0x2, blake256(0x01020304), rfc6979 nonce",
389 // key: "0000000000000000000000000000000000000000000000000000000000000002",
390 // msg: "01020304",
391 // hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
392 // nonce: "55f96f24cf7531f527edfe3b9222eca12d575367c32a7f593a828dc3651acf49",
393 // rfc6979: true,
394 // wantSigR: "e6f137b52377250760cc702e19b7aee3c63b0e7d95a91939b14ab3b5c4771e59",
395 // wantSigS: "44b9bc4620afa158b7efdfea5234ff2d5f2f78b42886f02cf581827ee55318ea",
396 // wantCode: pubKeyRecoveryCodeOddnessBit,
397 // }, {
398 // name: "key 0x2, blake256(0x01020304), random nonce",
399 // key: "0000000000000000000000000000000000000000000000000000000000000002",
400 // msg: "01020304",
401 // hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
402 // nonce: "679a6d36e7fe6c02d7668af86d78186e8f9ccc04371ac1c8c37939d1f5cae07a",
403 // rfc6979: false,
404 // wantSigR: "4a090d82f48ca12d9e7aa24b5dcc187ee0db2920496f671d63e86036aaa7997e",
405 // wantSigS: "261ffe8ba45007fc5fbbba6b4c6ed41beafb48b09fa8af1d6a3fbc6ccefbad",
406 // wantCode: 0,
407 // }, {
408 // name: "key 0x1, blake256(0x0102030405), rfc6979 nonce",
409 // key: "0000000000000000000000000000000000000000000000000000000000000001",
410 // msg: "0102030405",
411 // hash: "dc063eba3c8d52a159e725c1a161506f6cb6b53478ad5ef3f08d534efa871d9f",
412 // nonce: "aa87a543c68f2568bb107c9946afa5233bf94fb6a7a063544505282621021629",
413 // rfc6979: true,
414 // wantSigR: "dda8308cdbda2edf51ccf598b42b42b19597e102eb2ed4a04a16dd57084d3b40",
415 // wantSigS: "0b6d67bab4929624e28f690407a15efc551354544fdc179970ff401eec2e5dc9",
416 // wantCode: pubKeyRecoveryCodeOddnessBit,
417 // }, {
418 // name: "key 0x1, blake256(0x0102030405), random nonce",
419 // key: "0000000000000000000000000000000000000000000000000000000000000001",
420 // msg: "0102030405",
421 // hash: "dc063eba3c8d52a159e725c1a161506f6cb6b53478ad5ef3f08d534efa871d9f",
422 // nonce: "65f880c892fdb6e7f74f76b18c7c942cfd037ef9cf97c39c36e08bbc36b41616",
423 // rfc6979: false,
424 // wantSigR: "72e5666f4e9d1099447b825cf737ee32112f17a67e2ca7017ae098da31dfbb8b",
425 // wantSigS: "1a7326da661a62f66358dcf53300afdc8e8407939dae1192b5b0899b0254311b",
426 // wantCode: pubKeyRecoveryCodeOddnessBit,
427 // }, {
428 // name: "key 0x2, blake256(0x0102030405), rfc6979 nonce",
429 // key: "0000000000000000000000000000000000000000000000000000000000000002",
430 // msg: "0102030405",
431 // hash: "dc063eba3c8d52a159e725c1a161506f6cb6b53478ad5ef3f08d534efa871d9f",
432 // nonce: "a13d652abd54b6e862548e5d12716df14dc192d93f3fa13536fdf4e56c54f233",
433 // rfc6979: true,
434 // wantSigR: "122663fd29e41a132d3c8329cf05d61ebcca9351074cc277dcd868faba58d87d",
435 // wantSigS: "353a44f2d949c04981e4e4d9c1f93a9e0644e63a5eaa188288c5ad68fd288d40",
436 // wantCode: 0,
437 // }, {
438 // name: "key 0x2, blake256(0x0102030405), random nonce",
439 // key: "0000000000000000000000000000000000000000000000000000000000000002",
440 // msg: "0102030405",
441 // hash: "dc063eba3c8d52a159e725c1a161506f6cb6b53478ad5ef3f08d534efa871d9f",
442 // nonce: "026ece4cfb704733dd5eef7898e44c33bd5a0d749eb043f48705e40fa9e9afa0",
443 // rfc6979: false,
444 // wantSigR: "3c4c5a2f217ea758113fd4e89eb756314dfad101a300f48e5bd764d3b6e0f8bf",
445 // wantSigS: "6513e82442f133cb892514926ed9158328ead488ff1b027a31827603a65009df",
446 // wantCode: pubKeyRecoveryCodeOddnessBit,
447 // }, {
448 // name: "random key 1, blake256(0x01), rfc6979 nonce",
449 // key: "a1becef2069444a9dc6331c3247e113c3ee142edda683db8643f9cb0af7cbe33",
450 // msg: "01",
451 // hash: "4a6c419a1e25c85327115c4ace586decddfe2990ed8f3d4d801871158338501d",
452 // nonce: "edb3a01063a0c6ccfc0d77295077cbd322cf364bfa64b7eeea3b20305135d444",
453 // rfc6979: true,
454 // wantSigR: "ef392791d87afca8256c4c9c68d981248ee34a09069f50fa8dfc19ae34cd92ce",
455 // wantSigS: "0a2b9cb69fd794f7f204c272293b8585a294916a21a11fd94ec04acae2dc6d21",
456 // wantCode: 0,
457 // }, {
458 // name: "random key 2, blake256(0x02), rfc6979 nonce",
459 // key: "59930b76d4b15767ec0e8c8e5812aa2e57db30c6af7963e2a6295ba02af5416b",
460 // msg: "02",
461 // hash: "49af37ab5270015fe25276ea5a3bb159d852943df23919522a202205fb7d175c",
462 // nonce: "af2a59085976494567ef0fc2ecede587b2d1d8e9898cc46e72d7f3e33156e057",
463 // rfc6979: true,
464 // wantSigR: "886c9cccb356b3e1deafef2c276a4f8717ab73c1244c3f673cfbff5897de0e06",
465 // wantSigS: "609394185495f978ae84b69be90c69947e5dd8dcb4726da604fcbd139d81fc55",
466 // wantCode: 0,
467 // }, {
468 // name: "random key 3, blake256(0x03), rfc6979 nonce",
469 // key: "c5b205c36bb7497d242e96ec19a2a4f086d8daa919135cf490d2b7c0230f0e91",
470 // msg: "03",
471 // hash: "b706d561742ad3671703c247eb927ee8a386369c79644131cdeb2c5c26bf6c5d",
472 // nonce: "82d82b696a386d6d7a111c4cb943bfd39de8e5f6195e7eed9d3edb40fe1419fa",
473 // rfc6979: true,
474 // wantSigR: "6589d5950cec1fe2e7e20593b5ffa3556de20c176720a1796aa77a0cec1ec5a7",
475 // wantSigS: "2a26deba3241de852e786f5b4e2b98d3efb958d91fe9773b331dbcca9e8be800",
476 // wantCode: 0,
477 // }, {
478 // name: "random key 4, blake256(0x04), rfc6979 nonce",
479 // key: "65b46d4eb001c649a86309286aaf94b18386effe62c2e1586d9b1898ccf0099b",
480 // msg: "04",
481 // hash: "4c6eb9e38415034f4c93d3304d10bef38bf0ad420eefd0f72f940f11c5857786",
482 // nonce: "7afd696a9e770961d2b2eaec77ab7c22c734886fa57bc4a50a9f1946168cd06f",
483 // rfc6979: true,
484 // wantSigR: "81db1d6dca08819ad936d3284a359091e57c036648d477b96af9d8326965a7d1",
485 // wantSigS: "1bdf719c4be69351ba7617a187ac246912101aea4b5a7d6dfc234478622b43c6",
486 // wantCode: pubKeyRecoveryCodeOddnessBit,
487 // }, {
488 // name: "random key 5, blake256(0x05), rfc6979 nonce",
489 // key: "915cb9ba4675de06a182088b182abcf79fa8ac989328212c6b866fa3ec2338f9",
490 // msg: "05",
491 // hash: "bdd15db13448905791a70b68137445e607cca06cc71c7a58b9b2e84a06c54d08",
492 // nonce: "2a6ae70ea5cf1b932331901d640ece54551f5f33bf9484d5f95c676b5612b527",
493 // rfc6979: true,
494 // wantSigR: "47fd51aecbc743477cb59aa29d18d11d75fb206ae1cdd044216e4f294e33d5b6",
495 // wantSigS: "3d50edc03066584d50b8d19d681865a23960b37502ede5bf452bdca56744334a",
496 // wantCode: pubKeyRecoveryCodeOddnessBit,
497 // }, {
498 // name: "random key 6, blake256(0x06), rfc6979 nonce",
499 // key: "93e9d81d818f08ba1f850c6dfb82256b035b42f7d43c1fe090804fb009aca441",
500 // msg: "06",
501 // hash: "19b7506ad9c189a9f8b063d2aee15953d335f5c88480f8515d7d848e7771c4ae",
502 // nonce: "0b847a0ae0cbe84dfca66621f04f04b0f2ec190dce10d43ba8c3915c0fcd90ed",
503 // rfc6979: true,
504 // wantSigR: "c99800bc7ac7ea11afe5d7a264f4c26edd63ae9c7ecd6d0d19992980bcda1d34",
505 // wantSigS: "2844d4c9020ddf9e96b86c1a04788e0f371bd562291fd17ee017db46259d04fb",
506 // wantCode: pubKeyRecoveryCodeOddnessBit,
507 // }, {
508 // name: "random key 7, blake256(0x07), rfc6979 nonce",
509 // key: "c249bbd5f533672b7dcd514eb1256854783531c2b85fe60bf4ce6ea1f26afc2b",
510 // msg: "07",
511 // hash: "53d661e71e47a0a7e416591200175122d83f8af31be6a70af7417ad6f54d0038",
512 // nonce: "0f8e20694fe766d7b79e5ac141e3542f2f3c3d2cc6d0f60e0ec263a46dbe6d49",
513 // rfc6979: true,
514 // wantSigR: "7a57a5222fb7d615eaa0041193f682262cebfa9b448f9c519d3644d0a3348521",
515 // wantSigS: "574923b7b5aec66b62f1589002db29342c9f5ed56d5e80f5361c0307ff1561fa",
516 // wantCode: 0,
517 // }, {
518 // name: "random key 8, blake256(0x08), rfc6979 nonce",
519 // key: "ec0be92fcec66cf1f97b5c39f83dfd4ddcad0dad468d3685b5eec556c6290bcc",
520 // msg: "08",
521 // hash: "9bff7982eab6f7883322edf7bdc86a23c87ca1c07906fbb1584f57b197dc6253",
522 // nonce: "ab7df49257d18f5f1b730cc7448f46bd82eb43e6e220f521fa7d23802310e24d",
523 // rfc6979: true,
524 // wantSigR: "64f90b09c8b1763a3eeefd156e5d312f80a98c24017811c0163b1c0b01323668",
525 // wantSigS: "7d7bf4ff295ecfc9578eadc8378b0eea0c0362ad083b0fd1c9b3c06f4537f6ff",
526 // wantCode: pubKeyRecoveryCodeOddnessBit,
527 // }, {
528 // name: "random key 9, blake256(0x09), rfc6979 nonce",
529 // key: "6847b071a7cba6a85099b26a9c3e57a964e4990620e1e1c346fecc4472c4d834",
530 // msg: "09",
531 // hash: "4c2231813064f8500edae05b40195416bd543fd3e76c16d6efb10c816d92e8b6",
532 // nonce: "48ea6c907e1cda596048d812439ccf416eece9a7de400c8a0e40bd48eb7e613a",
533 // rfc6979: true,
534 // wantSigR: "81fc600775d3cdcaa14f8629537299b8226a0c8bfce9320ce64a8d14e3f95bae",
535 // wantSigS: "3607997d36b48bce957ae9b3d450e0969f6269554312a82bf9499efc8280ea6d",
536 // wantCode: 0,
537 // }, {
538 // name: "random key 10, blake256(0x0a), rfc6979 nonce",
539 // key: "b7548540f52fe20c161a0d623097f827608c56023f50442cc00cc50ad674f6b5",
540 // msg: "0a",
541 // hash: "e81db4f0d76e02805155441f50c861a8f86374f3ae34c7a3ff4111d3a634ecb1",
542 // nonce: "95c07e315cd5457e84270ca01019563c8eeaffb18ab4f23e88a44a0ff01c5f6f",
543 // rfc6979: true,
544 // wantSigR: "0d4cbf2da84f7448b083fce9b9c4e1834b5e2e98defcec7ec87e87c739f5fe78",
545 // wantSigS: "0997db60683e12b4494702347fc7ae7f599e5a95c629c146e0fc615a1a2acac5",
546 // wantCode: pubKeyRecoveryCodeOddnessBit,
547 // }}
548 //
549 // // Ensure the test data is sane by comparing the provided hashed message and
550 // // nonce, in the case RFC6979 was used, to their calculated values. These
551 // // values could just be calculated instead of specified in the test data,
552 // // but it's nice to have all of the calculated values available in the test
553 // // data for cross implementation testing and verification.
554 // for _, test := range tests {
555 // msg := hexToBytes(test.msg)
556 // hash := hexToBytes(test.hash)
557 //
558 // calcHash := blake256.Sum256(msg)
559 // if !equals(calcHash[:], hash) {
560 // t.Errorf("%s: mismatched test hash -- expected: %x, given: %x",
561 // test.name, calcHash[:], hash)
562 // continue
563 // }
564 // if test.rfc6979 {
565 // secKeyBytes := hexToBytes(test.key)
566 // nonceBytes := hexToBytes(test.nonce)
567 // calcNonce := secp256k1.NonceRFC6979(secKeyBytes, hash, nil, nil, 0)
568 // calcNonceBytes := calcNonce.Bytes()
569 // if !equals(calcNonceBytes[:], nonceBytes) {
570 // t.Errorf("%s: mismatched test nonce -- expected: %x, given: %x",
571 // test.name, calcNonceBytes, nonceBytes)
572 // continue
573 // }
574 // }
575 // }
576 //
577 // return tests
578 // }
579
580 // // TestSignAndVerify ensures the ECDSA signing function produces the expected
581 // // signatures for a selected set of secret keys, messages, and nonces that have
582 // // been verified independently with the Sage computer algebra system. It also
583 // // ensures verifying the signature works as expected.
584 // func TestSignAndVerify(t *testing.T) {
585 // t.Parallel()
586 //
587 // tests := signTests(t)
588 // for _, test := range tests {
589 // secKey := secp256k1.NewSecretKey(hexToModNScalar(test.key))
590 // hash := hexToBytes(test.hash)
591 // nonce := hexToModNScalar(test.nonce)
592 // wantSigR := hexToModNScalar(test.wantSigR)
593 // wantSigS := hexToModNScalar(test.wantSigS)
594 // wantSig := NewSignature(wantSigR, wantSigS).Serialize()
595 //
596 // // Sign the hash of the message with the given secret key and nonce.
597 // gotSig, recoveryCode, success := sign(&secKey.Key, nonce, hash)
598 // if !success {
599 // t.Errorf("%s: unexpected error when signing", test.name)
600 // continue
601 // }
602 //
603 // // Ensure the generated signature is the expected value.
604 // gotSigBytes := gotSig.Serialize()
605 // if !equals(gotSigBytes, wantSig) {
606 // t.Errorf("%s: unexpected signature -- got %x, want %x", test.name,
607 // gotSigBytes, wantSig)
608 // continue
609 // }
610 //
611 // // Ensure the generated public key recovery code is the expected value.
612 // if recoveryCode != test.wantCode {
613 // t.Errorf("%s: unexpected recovery code -- got %x, want %x",
614 // test.name, recoveryCode, test.wantCode)
615 // continue
616 // }
617 //
618 // // Ensure the produced signature verifies.
619 // pubKey := secKey.Pubkey()
620 // if !gotSig.Verify(hash, pubKey) {
621 // t.Errorf("%s: signature failed to verify", test.name)
622 // continue
623 // }
624 //
625 // // Ensure the signature generated by the exported method is the expected
626 // // value as well in the case RFC6979 was used.
627 // if test.rfc6979 {
628 // gotSig = Sign(secKey, hash)
629 // gotSigBytes := gotSig.Serialize()
630 // if !equals(gotSigBytes, wantSig) {
631 // t.Errorf("%s: unexpected signature -- got %x, want %x",
632 // test.name, gotSigBytes, wantSig)
633 // continue
634 // }
635 // }
636 // }
637 // }
638
639 // TestSignAndVerifyRandom ensures ECDSA signing and verification work as
640 // expected for randomly-generated secret keys and messages. It also ensures
641 // invalid signatures are not improperly verified by mutating the valid
642 // signature and changing the message the signature covers.
643 func TestSignAndVerifyRandom(t *testing.T) {
644 t.Parallel()
645
646 // Use a unique random seed each test instance and log it if the tests fail.
647 seed := time.Now().Unix()
648 rng := rand.New(rand.NewSource(seed))
649 defer func(t *testing.T, seed int64) {
650 if t.Failed() {
651 t.Logf("random seed: %d", seed)
652 }
653 }(t, seed)
654 for i := 0; i < 100; i++ {
655 // Generate a random secret key.
656 var buf [32]byte
657 if _, err := rng.Read(buf[:]); chk.T(err) {
658 t.Fatalf("failed to read random secret key: %v", err)
659 }
660 var secKeyScalar secp256k1.ModNScalar
661 secKeyScalar.SetBytes(&buf)
662 secKey := secp256k1.NewSecretKey(&secKeyScalar)
663 // Generate a random hash to sign.
664 var hash [32]byte
665 if _, err := rng.Read(hash[:]); chk.T(err) {
666 t.Fatalf("failed to read random hash: %v", err)
667 }
668 // Sign the hash with the secret key and then ensure the produced
669 // signature is valid for the hash and public key associated with the
670 // secret key.
671 sig := Sign(secKey, hash[:])
672 pubKey := secKey.PubKey()
673 if !sig.Verify(hash[:], pubKey) {
674 t.Fatalf(
675 "failed to verify signature\nsig: %x\nhash: %x\n"+
676 "secret key: %x\npublic key: %x", sig.Serialize(), hash,
677 secKey.Serialize(), pubKey.SerializeCompressed(),
678 )
679 }
680 // Change a random bit in the signature and ensure the bad signature
681 // fails to verify the original message.
682 badSig := *sig
683 randByte := rng.Intn(32)
684 randBit := rng.Intn(7)
685 if randComponent := rng.Intn(2); randComponent == 0 {
686 badSigBytes := badSig.r.Bytes()
687 badSigBytes[randByte] ^= 1 << randBit
688 badSig.r.SetBytes(&badSigBytes)
689 } else {
690 badSigBytes := badSig.s.Bytes()
691 badSigBytes[randByte] ^= 1 << randBit
692 badSig.s.SetBytes(&badSigBytes)
693 }
694 if badSig.Verify(hash[:], pubKey) {
695 t.Fatalf(
696 "verified bad signature\nsig: %x\nhash: %x\n"+
697 "secret key: %x\npublic key: %x", badSig.Serialize(), hash,
698 secKey.Serialize(), pubKey.SerializeCompressed(),
699 )
700 }
701 // Change a random bit in the hash that was originally signed and ensure
702 // the original good signature fails to verify the new bad message.
703 badHash := make([]byte, len(hash))
704 copy(badHash, hash[:])
705 randByte = rng.Intn(len(badHash))
706 randBit = rng.Intn(7)
707 badHash[randByte] ^= 1 << randBit
708 if sig.Verify(badHash[:], pubKey) {
709 t.Fatalf(
710 "verified signature for bad hash\nsig: %x\nhash: %x\n"+
711 "pubkey: %x", sig.Serialize(), badHash,
712 pubKey.SerializeCompressed(),
713 )
714 }
715 }
716 }
717
718 // TestSignFailures ensures the internal ECDSA signing function returns an
719 // unsuccessful result when particular combinations of values are unable to
720 // produce a valid signature.
721 func TestSignFailures(t *testing.T) {
722 t.Parallel()
723 tests := []struct {
724 name string // test description
725 key string // hex encoded secret key
726 hash string // hex encoded hash of the message to sign
727 nonce string // hex encoded nonce to use in the signature calculation
728 }{
729 {
730 name: "zero R is invalid (forced by using zero nonce)",
731 key: "0000000000000000000000000000000000000000000000000000000000000001",
732 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
733 nonce: "0000000000000000000000000000000000000000000000000000000000000000",
734 }, {
735 name: "zero S is invalid (forced by key/hash/nonce choice)",
736 key: "0000000000000000000000000000000000000000000000000000000000000001",
737 hash: "393bec84f1a04037751c0d6c2817f37953eaa204ac0898de7adb038c33a20438",
738 nonce: "4154324ecd4158938f1df8b5b659aeb639c7fbc36005934096e514af7d64bcc2",
739 },
740 }
741 for _, test := range tests {
742 secKey := hexToModNScalar(test.key)
743 hash := hexToBytes(test.hash)
744 nonce := hexToModNScalar(test.nonce)
745 // Ensure the signing is NOT successful.
746 sig, _, success := sign(secKey, nonce, hash[:])
747 if success {
748 t.Errorf(
749 "%s: unexpected success -- got sig %x", test.name,
750 sig.Serialize(),
751 )
752 continue
753 }
754 }
755 }
756
757 // TestVerifyFailures ensures the ECDSA verification function returns an
758 // unsuccessful result for edge conditions.
759 func TestVerifyFailures(t *testing.T) {
760 t.Parallel()
761
762 tests := []struct {
763 name string // test description
764 key string // hex encoded secret key
765 hash string // hex encoded hash of the message to sign
766 r, s string // hex encoded r and s components of signature to verify
767 }{
768 {
769 name: "signature R is 0",
770 key: "0000000000000000000000000000000000000000000000000000000000000001",
771 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
772 r: "0000000000000000000000000000000000000000000000000000000000000000",
773 s: "00ba213513572e35943d5acdd17215561b03f11663192a7252196cc8b2a99560",
774 }, {
775 name: "signature S is 0",
776 key: "0000000000000000000000000000000000000000000000000000000000000001",
777 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
778 r: "c6c4137b0e5fbfc88ae3f293d7e80c8566c43ae20340075d44f75b009c943d09",
779 s: "0000000000000000000000000000000000000000000000000000000000000000",
780 }, {
781 name: "u1G + u2Q is the point at infinity",
782 key: "0000000000000000000000000000000000000000000000000000000000000001",
783 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
784 r: "3cfe45621a29fac355260a14b9adc0fe43ac2f13e918fc9ddfa117e964b61a8a",
785 s: "00ba213513572e35943d5acdd17215561b03f11663192a7252196cc8b2a99560",
786 }, {
787 name: "signature R < P-N, but invalid",
788 key: "0000000000000000000000000000000000000000000000000000000000000001",
789 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
790 r: "000000000000000000000000000000014551231950b75fc4402da1722fc9baed",
791 s: "00ba213513572e35943d5acdd17215561b03f11663192a7252196cc8b2a99560",
792 },
793 }
794 for _, test := range tests {
795 secKey := hexToModNScalar(test.key)
796 hash := hexToBytes(test.hash)
797 r := hexToModNScalar(test.r)
798 s := hexToModNScalar(test.s)
799 sig := NewSignature(r, s)
800 // Ensure the verification is NOT successful.
801 pubKey := secp256k1.NewSecretKey(secKey).PubKey()
802 if sig.Verify(hash, pubKey) {
803 t.Errorf(
804 "%s: unexpected success for invalid signature: %x",
805 test.name, sig.Serialize(),
806 )
807 continue
808 }
809 }
810 }
811
812 // TestSignatureIsEqual ensures that equality testing between two signatures
813 // works as expected.
814 func TestSignatureIsEqual(t *testing.T) {
815 sig1 := &Signature{
816 r: *hexToModNScalar("82235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c30a23b0afbb8d178abcf3"),
817 s: *hexToModNScalar("24bf68e256c534ddfaf966bf908deb944305596f7bdcc38d69acad7f9c868724"),
818 }
819 sig1Copy := &Signature{
820 r: *hexToModNScalar("82235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c30a23b0afbb8d178abcf3"),
821 s: *hexToModNScalar("24bf68e256c534ddfaf966bf908deb944305596f7bdcc38d69acad7f9c868724"),
822 }
823 sig2 := &Signature{
824 r: *hexToModNScalar("4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41"),
825 s: *hexToModNScalar("181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09"),
826 }
827 if !sig1.IsEqual(sig1) {
828 t.Fatalf("bad self signature equality check: %v == %v", sig1, sig1Copy)
829 }
830 if !sig1.IsEqual(sig1Copy) {
831 t.Fatalf("bad signature equality check: %v == %v", sig1, sig1Copy)
832 }
833
834 if sig1.IsEqual(sig2) {
835 t.Fatalf("bad signature equality check: %v != %v", sig1, sig2)
836 }
837 }
838
839 // // TestSignAndRecoverCompact ensures compact (recoverable public key) ECDSA
840 // // signing and public key recovery works as expected for a selected set of
841 // // secret keys, messages, and nonces that have been verified independently with
842 // // the Sage computer algebra system.
843 // func TestSignAndRecoverCompact(t *testing.T) {
844 // t.Parallel()
845 //
846 // tests := signTests(t)
847 // for _, test := range tests {
848 // // Skip tests using nonces that are not RFC6979.
849 // if !test.rfc6979 {
850 // continue
851 // }
852 //
853 // // Parse test data.
854 // secKey := secp256k1.NewSecretKey(hexToModNScalar(test.key))
855 // pubKey := secKey.Pubkey()
856 // hash := hexToBytes(test.hash)
857 // wantSig := hexToBytes("00" + test.wantSigR + test.wantSigS)
858 //
859 // // Test compact signatures for both the compressed and uncompressed
860 // // versions of the public key.
861 // for _, compressed := range []bool{true, false} {
862 // // Populate the expected compact signature recovery code.
863 // wantRecoveryCode := compactSigMagicOffset + test.wantCode
864 // if compressed {
865 // wantRecoveryCode += compactSigCompPubKey
866 // }
867 // wantSig[0] = wantRecoveryCode
868 //
869 // // Sign the hash of the message with the given secret key and
870 // // ensure the generated signature is the expected value per the
871 // // specified compressed flag.
872 // gotSig := SignCompact(secKey, hash, compressed)
873 // if !equals(gotSig, wantSig) {
874 // t.Errorf("%s: unexpected signature -- got %x, want %x",
875 // test.name, gotSig, wantSig)
876 // continue
877 // }
878 //
879 // // Ensure the recovered public key and flag that indicates whether
880 // // or not the signature was for a compressed public key are the
881 // // expected values.
882 // gotPubKey, gotCompressed, err := RecoverCompact(gotSig, hash)
883 // if err != nil {
884 // t.Errorf("%s: unexpected error when recovering: %v", test.name,
885 // err)
886 // continue
887 // }
888 // if gotCompressed != compressed {
889 // t.Errorf("%s: unexpected compressed flag -- got %v, want %v",
890 // test.name, gotCompressed, compressed)
891 // continue
892 // }
893 // if !gotPubKey.IsEqual(pubKey) {
894 // t.Errorf("%s: unexpected public key -- got %x, want %x",
895 // test.name, gotPubKey.SerializeUncompressed(),
896 // pubKey.SerializeUncompressed())
897 // continue
898 // }
899 // }
900 // }
901 // }
902
903 // TestRecoverCompactErrors ensures several error paths in compact signature recovery are
904 // detected as expected. When possible, the signatures are otherwise valid, except the specific
905 // failure to ensure it's robust against things like fault attacks.
906 func TestRecoverCompactErrors(t *testing.T) {
907 t.Parallel()
908
909 tests := []struct {
910 name string // test description
911 sig string // hex encoded signature to recover pubkey from
912 hash string // hex encoded hash of message
913 err error // expected error
914 }{
915 {
916 name: "empty signature",
917 sig: "",
918 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
919 err: ErrSigInvalidLen,
920 }, {
921 // Signature created from secret key 0x02, blake256(0x01020304).
922 name: "no compact sig recovery code (otherwise valid sig)",
923 sig: "e6f137b52377250760cc702e19b7aee3c63b0e7d95a91939b14ab3b5c4771e59" +
924 "44b9bc4620afa158b7efdfea5234ff2d5f2f78b42886f02cf581827ee55318ea",
925 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
926 err: ErrSigInvalidLen,
927 }, {
928 // Signature created from secret key 0x02, blake256(0x01020304).
929 name: "signature one byte too long (S padded with leading zero)",
930 sig: "1f" +
931 "e6f137b52377250760cc702e19b7aee3c63b0e7d95a91939b14ab3b5c4771e59" +
932 "0044b9bc4620afa158b7efdfea5234ff2d5f2f78b42886f02cf581827ee55318ea",
933 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
934 err: ErrSigInvalidLen,
935 }, {
936 // Signature created from secret key 0x02, blake256(0x01020304).
937 name: "compact sig recovery code too low (otherwise valid sig)",
938 sig: "1a" +
939 "e6f137b52377250760cc702e19b7aee3c63b0e7d95a91939b14ab3b5c4771e59" +
940 "44b9bc4620afa158b7efdfea5234ff2d5f2f78b42886f02cf581827ee55318ea",
941 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
942 err: ErrSigInvalidRecoveryCode,
943 }, {
944 // Signature created from secret key 0x02, blake256(0x01020304).
945 name: "compact sig recovery code too high (otherwise valid sig)",
946 sig: "23" +
947 "e6f137b52377250760cc702e19b7aee3c63b0e7d95a91939b14ab3b5c4771e59" +
948 "44b9bc4620afa158b7efdfea5234ff2d5f2f78b42886f02cf581827ee55318ea",
949 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
950 err: ErrSigInvalidRecoveryCode,
951 }, {
952 // Signature invented since finding a signature with an r value that is
953 // exactly the group order prior to the modular reduction is not
954 // calculable without breaking the underlying crypto.
955 name: "R == group order",
956 sig: "1f" +
957 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" +
958 "44b9bc4620afa158b7efdfea5234ff2d5f2f78b42886f02cf581827ee55318ea",
959 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
960 err: ErrSigRTooBig,
961 }, {
962 // Signature invented since finding a signature with an r value that
963 // would be valid modulo the group order and is still 32 bytes is not
964 // calculable without breaking the underlying crypto.
965 name: "R > group order and still 32 bytes (order + 1)",
966 sig: "1f" +
967 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142" +
968 "44b9bc4620afa158b7efdfea5234ff2d5f2f78b42886f02cf581827ee55318ea",
969 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
970 err: ErrSigRTooBig,
971 }, {
972 // Signature invented since the only way a signature could have an r
973 // value of zero is if the nonce were zero which is invalid.
974 name: "R == 0",
975 sig: "1f" +
976 "0000000000000000000000000000000000000000000000000000000000000000" +
977 "44b9bc4620afa158b7efdfea5234ff2d5f2f78b42886f02cf581827ee55318ea",
978 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
979 err: ErrSigRIsZero,
980 }, {
981 // Signature invented since finding a signature with an s value that is
982 // exactly the group order prior to the modular reduction is not
983 // calculable without breaking the underlying crypto.
984 name: "S == group order",
985 sig: "1f" +
986 "e6f137b52377250760cc702e19b7aee3c63b0e7d95a91939b14ab3b5c4771e59" +
987 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
988 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
989 err: ErrSigSTooBig,
990 }, {
991 // Signature invented since finding a signature with an s value that
992 // would be valid modulo the group order and is still 32 bytes is not
993 // calculable without breaking the underlying crypto.
994 name: "S > group order and still 32 bytes (order + 1)",
995 sig: "1f" +
996 "e6f137b52377250760cc702e19b7aee3c63b0e7d95a91939b14ab3b5c4771e59" +
997 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
998 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
999 err: ErrSigSTooBig,
1000 }, {
1001 // Signature created by forcing the key/hash/nonce choices such that s
1002 // is zero and is therefore invalid. The signing code will not produce
1003 // such a signature in practice.
1004 name: "S == 0",
1005 sig: "1f" +
1006 "e6f137b52377250760cc702e19b7aee3c63b0e7d95a91939b14ab3b5c4771e59" +
1007 "0000000000000000000000000000000000000000000000000000000000000000",
1008 hash: "393bec84f1a04037751c0d6c2817f37953eaa204ac0898de7adb038c33a20438",
1009 err: ErrSigSIsZero,
1010 }, {
1011 // Signature invented since finding a secret key needed to create a
1012 // valid signature with an r value that is >= group order prior to the
1013 // modular reduction is not possible without breaking the underlying
1014 // crypto.
1015 name: "R >= field prime minus group order with overflow bit",
1016 sig: "21" +
1017 "000000000000000000000000000000014551231950b75fc4402da1722fc9baee" +
1018 "44b9bc4620afa158b7efdfea5234ff2d5f2f78b42886f02cf581827ee55318ea",
1019 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
1020 err: ErrSigOverflowsPrime,
1021 }, {
1022 // Signature created from secret key 0x01, blake256(0x0102030407) over
1023 // the secp256r1 curve (note the r1 instead of k1).
1024 name: "pubkey not on the curve, signature valid for secp256r1 instead",
1025 sig: "1f" +
1026 "2a81d1b3facc22185267d3f8832c5104902591bc471253f1cfc5eb25f4f740f2" +
1027 "72e65d019f9b09d769149e2be0b55de9b0224d34095bddc6a5dba90bfda33c45",
1028 hash: "9165e957708bc95cf62d020769c150b2d7b08e7ab7981860815b1eaabd41d695",
1029 err: ErrPointNotOnCurve,
1030 }, {
1031 // Signature created from secret key 0x01, blake256(0x01020304) and
1032 // manually setting s = -e*k^-1.
1033 name: "calculated pubkey point at infinity",
1034 sig: "1f" +
1035 "c6c4137b0e5fbfc88ae3f293d7e80c8566c43ae20340075d44f75b009c943d09" +
1036 "1281d8d90a5774045abd57b453c7eadbc830dbadec89ae8dd7639b9cc55641d0",
1037 hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
1038 err: ErrPointNotOnCurve,
1039 },
1040 }
1041 for _, test := range tests {
1042 // Parse test data.
1043 hash := hexToBytes(test.hash)
1044 sig := hexToBytes(test.sig)
1045 // Ensure the expected error is hit.
1046 _, _, err := RecoverCompact(sig, hash)
1047 if !errors.Is(err, test.err) {
1048 t.Errorf(
1049 "%s: mismatched err -- got %v, want %v", test.name, err,
1050 test.err,
1051 )
1052 continue
1053 }
1054 }
1055 }
1056
1057 // TestSignAndRecoverCompactRandom ensures compact (recoverable public key)
1058 // ECDSA signing and recovery work as expected for randomly-generated secret
1059 // keys and messages. It also ensures mutated signatures and messages do not
1060 // improperly recover the original public key.
1061 func TestSignAndRecoverCompactRandom(t *testing.T) {
1062 t.Parallel()
1063 // Use a unique random seed each test instance and log it if the tests fail.
1064 seed := time.Now().Unix()
1065 rng := rand.New(rand.NewSource(seed))
1066 defer func(t *testing.T, seed int64) {
1067 if t.Failed() {
1068 t.Logf("random seed: %d", seed)
1069 }
1070 }(t, seed)
1071 for i := 0; i < 100; i++ {
1072 // Generate a random secret key.
1073 var buf [32]byte
1074 if _, err := rng.Read(buf[:]); chk.T(err) {
1075 t.Fatalf("failed to read random secret key: %v", err)
1076 }
1077 var secKeyScalar secp256k1.ModNScalar
1078 secKeyScalar.SetBytes(&buf)
1079 secKey := secp256k1.NewSecretKey(&secKeyScalar)
1080 wantPubKey := secKey.PubKey()
1081 // Generate a random hash to sign.
1082 var hash [32]byte
1083 if _, err := rng.Read(hash[:]); chk.T(err) {
1084 t.Fatalf("failed to read random hash: %v", err)
1085 }
1086 // Test compact signatures for both the compressed and uncompressed
1087 // versions of the public key.
1088 for _, compressed := range []bool{true, false} {
1089 // Sign the hash with the secret key and then ensure the original
1090 // public key and compressed flag is recovered from the produced
1091 // signature.
1092 gotSig := SignCompact(secKey, hash[:], compressed)
1093
1094 gotPubKey, gotCompressed, err := RecoverCompact(gotSig, hash[:])
1095 if err != nil {
1096 t.Fatalf(
1097 "unexpected err: %v\nsig: %x\nhash: %x\nsecret key: %x",
1098 err, gotSig, hash, secKey.Serialize(),
1099 )
1100 }
1101 if gotCompressed != compressed {
1102 t.Fatalf(
1103 "unexpected compressed flag: %v\nsig: %x\nhash: %x\n"+
1104 "secret key: %x", gotCompressed, gotSig, hash,
1105 secKey.Serialize(),
1106 )
1107 }
1108 if !gotPubKey.IsEqual(wantPubKey) {
1109 t.Fatalf(
1110 "unexpected recovered public key: %x\nsig: %x\nhash: "+
1111 "%x\nsecret key: %x", gotPubKey.SerializeUncompressed(),
1112 gotSig, hash, secKey.Serialize(),
1113 )
1114 }
1115 // Change a random bit in the signature and ensure the bad signature
1116 // fails to recover the original public key.
1117 badSig := make([]byte, len(gotSig))
1118 copy(badSig, gotSig)
1119 randByte := rng.Intn(len(badSig)-1) + 1
1120 randBit := rng.Intn(7)
1121 badSig[randByte] ^= 1 << randBit
1122 badPubKey, _, err := RecoverCompact(badSig, hash[:])
1123 if err == nil && badPubKey.IsEqual(wantPubKey) {
1124 t.Fatalf(
1125 "recovered public key for bad sig: %x\nhash: %x\n"+
1126 "secret key: %x", badSig, hash, secKey.Serialize(),
1127 )
1128 }
1129 // Change a random bit in the hash that was originally signed and
1130 // ensure the original good signature fails to recover the original
1131 // public key.
1132 badHash := make([]byte, len(hash))
1133 copy(badHash, hash[:])
1134 randByte = rng.Intn(len(badHash))
1135 randBit = rng.Intn(7)
1136 badHash[randByte] ^= 1 << randBit
1137 badPubKey, _, err = RecoverCompact(gotSig, badHash[:])
1138 if err == nil && badPubKey.IsEqual(wantPubKey) {
1139 t.Fatalf(
1140 "recovered public key for bad hash: %x\nsig: %x\n"+
1141 "secret key: %x", badHash, gotSig, secKey.Serialize(),
1142 )
1143 }
1144 }
1145 }
1146 }
1147