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