1// Copyright (c) 2013-2017 The btcsuite developers
2// Use of this source code is governed by an ISC
3// license that can be found in the LICENSE file.
4
5package btcec
6
7import (
8	"bytes"
9	"crypto/rand"
10	"crypto/sha256"
11	"encoding/hex"
12	"fmt"
13	"math/big"
14	"reflect"
15	"testing"
16)
17
18type signatureTest struct {
19	name    string
20	sig     []byte
21	der     bool
22	isValid bool
23}
24
25// decodeHex decodes the passed hex string and returns the resulting bytes.  It
26// panics if an error occurs.  This is only used in the tests as a helper since
27// the only way it can fail is if there is an error in the test source code.
28func decodeHex(hexStr string) []byte {
29	b, err := hex.DecodeString(hexStr)
30	if err != nil {
31		panic("invalid hex string in test source: err " + err.Error() +
32			", hex: " + hexStr)
33	}
34
35	return b
36}
37
38var signatureTests = []signatureTest{
39	// signatures from bitcoin blockchain tx
40	// 0437cd7f8525ceed2324359c2d0ba26006d92d85
41	{
42		name: "valid signature.",
43		sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
44			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
45			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
46			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
47			0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
48			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
49			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
50			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
51		},
52		der:     true,
53		isValid: true,
54	},
55	{
56		name:    "empty.",
57		sig:     []byte{},
58		isValid: false,
59	},
60	{
61		name: "bad magic.",
62		sig: []byte{0x31, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
63			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
64			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
65			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
66			0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
67			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
68			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
69			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
70		},
71		der:     true,
72		isValid: false,
73	},
74	{
75		name: "bad 1st int marker magic.",
76		sig: []byte{0x30, 0x44, 0x03, 0x20, 0x4e, 0x45, 0xe1, 0x69,
77			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
78			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
79			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
80			0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
81			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
82			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
83			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
84		},
85		der:     true,
86		isValid: false,
87	},
88	{
89		name: "bad 2nd int marker.",
90		sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
91			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
92			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
93			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
94			0x41, 0x03, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
95			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
96			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
97			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
98		},
99		der:     true,
100		isValid: false,
101	},
102	{
103		name: "short len",
104		sig: []byte{0x30, 0x43, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
105			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
106			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
107			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
108			0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
109			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
110			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
111			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
112		},
113		der:     true,
114		isValid: false,
115	},
116	{
117		name:    "invalid message length",
118		sig:     []byte{0x30, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00},
119		der:     false,
120		isValid: false,
121	},
122	{
123		name: "long len",
124		sig: []byte{0x30, 0x45, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
125			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
126			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
127			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
128			0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
129			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
130			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
131			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
132		},
133		der:     true,
134		isValid: false,
135	},
136	{
137		name: "long X",
138		sig: []byte{0x30, 0x44, 0x02, 0x42, 0x4e, 0x45, 0xe1, 0x69,
139			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
140			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
141			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
142			0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
143			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
144			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
145			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
146		},
147		der:     true,
148		isValid: false,
149	},
150	{
151		name: "long Y",
152		sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
153			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
154			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
155			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
156			0x41, 0x02, 0x21, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
157			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
158			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
159			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
160		},
161		der:     true,
162		isValid: false,
163	},
164	{
165		name: "short Y",
166		sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
167			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
168			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
169			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
170			0x41, 0x02, 0x19, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
171			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
172			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
173			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
174		},
175		der:     true,
176		isValid: false,
177	},
178	{
179		name: "trailing crap.",
180		sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
181			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
182			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
183			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
184			0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
185			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
186			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
187			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 0x01,
188		},
189		der: true,
190
191		// This test is now passing (used to be failing) because there
192		// are signatures in the blockchain that have trailing zero
193		// bytes before the hashtype. So ParseSignature was fixed to
194		// permit buffers with trailing nonsense after the actual
195		// signature.
196		isValid: true,
197	},
198	{
199		name: "X == N ",
200		sig: []byte{0x30, 0x44, 0x02, 0x20, 0xFF, 0xFF, 0xFF, 0xFF,
201			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
202			0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48,
203			0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41,
204			0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
205			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
206			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
207			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
208		},
209		der:     true,
210		isValid: false,
211	},
212	{
213		name: "X == N ",
214		sig: []byte{0x30, 0x44, 0x02, 0x20, 0xFF, 0xFF, 0xFF, 0xFF,
215			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
216			0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48,
217			0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41,
218			0x42, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
219			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
220			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
221			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
222		},
223		der:     false,
224		isValid: false,
225	},
226	{
227		name: "Y == N",
228		sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
229			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
230			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
231			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
232			0x41, 0x02, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
233			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
234			0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
235			0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41,
236		},
237		der:     true,
238		isValid: false,
239	},
240	{
241		name: "Y > N",
242		sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
243			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
244			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
245			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
246			0x41, 0x02, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
247			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
248			0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
249			0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x42,
250		},
251		der:     false,
252		isValid: false,
253	},
254	{
255		name: "0 len X.",
256		sig: []byte{0x30, 0x24, 0x02, 0x00, 0x02, 0x20, 0x18, 0x15,
257			0x22, 0xec, 0x8e, 0xca, 0x07, 0xde, 0x48, 0x60, 0xa4,
258			0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c, 0xc5, 0x6c,
259			0xbb, 0xac, 0x46, 0x22, 0x08, 0x22, 0x21, 0xa8, 0x76,
260			0x8d, 0x1d, 0x09,
261		},
262		der:     true,
263		isValid: false,
264	},
265	{
266		name: "0 len Y.",
267		sig: []byte{0x30, 0x24, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
268			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
269			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
270			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
271			0x41, 0x02, 0x00,
272		},
273		der:     true,
274		isValid: false,
275	},
276	{
277		name: "extra R padding.",
278		sig: []byte{0x30, 0x45, 0x02, 0x21, 0x00, 0x4e, 0x45, 0xe1, 0x69,
279			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
280			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
281			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
282			0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
283			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
284			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
285			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
286		},
287		der:     true,
288		isValid: false,
289	},
290	{
291		name: "extra S padding.",
292		sig: []byte{0x30, 0x45, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
293			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
294			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
295			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
296			0x41, 0x02, 0x21, 0x00, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca,
297			0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90,
298			0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22,
299			0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
300		},
301		der:     true,
302		isValid: false,
303	},
304	// Standard checks (in BER format, without checking for 'canonical' DER
305	// signatures) don't test for negative numbers here because there isn't
306	// a way that is the same between openssl and go that will mark a number
307	// as negative. The Go ASN.1 parser marks numbers as negative when
308	// openssl does not (it doesn't handle negative numbers that I can tell
309	// at all. When not parsing DER signatures, which is done by by bitcoind
310	// when accepting transactions into its mempool, we otherwise only check
311	// for the coordinates being zero.
312	{
313		name: "X == 0",
314		sig: []byte{0x30, 0x25, 0x02, 0x01, 0x00, 0x02, 0x20, 0x18,
315			0x15, 0x22, 0xec, 0x8e, 0xca, 0x07, 0xde, 0x48, 0x60,
316			0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c, 0xc5,
317			0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22, 0x21, 0xa8,
318			0x76, 0x8d, 0x1d, 0x09,
319		},
320		der:     false,
321		isValid: false,
322	},
323	{
324		name: "Y == 0.",
325		sig: []byte{0x30, 0x25, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
326			0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1,
327			0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6,
328			0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd,
329			0x41, 0x02, 0x01, 0x00,
330		},
331		der:     false,
332		isValid: false,
333	},
334}
335
336func TestSignatures(t *testing.T) {
337	for _, test := range signatureTests {
338		var err error
339		if test.der {
340			_, err = ParseDERSignature(test.sig, S256())
341		} else {
342			_, err = ParseSignature(test.sig, S256())
343		}
344		if err != nil {
345			if test.isValid {
346				t.Errorf("%s signature failed when shouldn't %v",
347					test.name, err)
348			} /* else {
349				t.Errorf("%s got error %v", test.name, err)
350			} */
351			continue
352		}
353		if !test.isValid {
354			t.Errorf("%s counted as valid when it should fail",
355				test.name)
356		}
357	}
358}
359
360// TestSignatureSerialize ensures that serializing signatures works as expected.
361func TestSignatureSerialize(t *testing.T) {
362	tests := []struct {
363		name     string
364		ecsig    *Signature
365		expected []byte
366	}{
367		// signature from bitcoin blockchain tx
368		// 0437cd7f8525ceed2324359c2d0ba26006d92d85
369		{
370			"valid 1 - r and s most significant bits are zero",
371			&Signature{
372				R: fromHex("4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41"),
373				S: fromHex("181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09"),
374			},
375			[]byte{
376				0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
377				0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3,
378				0xa1, 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32,
379				0xe9, 0xd6, 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab,
380				0x5f, 0xb8, 0xcd, 0x41, 0x02, 0x20, 0x18, 0x15,
381				0x22, 0xec, 0x8e, 0xca, 0x07, 0xde, 0x48, 0x60,
382				0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c,
383				0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22,
384				0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
385			},
386		},
387		// signature from bitcoin blockchain tx
388		// cb00f8a0573b18faa8c4f467b049f5d202bf1101d9ef2633bc611be70376a4b4
389		{
390			"valid 2 - r most significant bit is one",
391			&Signature{
392				R: fromHex("0082235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c30a23b0afbb8d178abcf3"),
393				S: fromHex("24bf68e256c534ddfaf966bf908deb944305596f7bdcc38d69acad7f9c868724"),
394			},
395			[]byte{
396				0x30, 0x45, 0x02, 0x21, 0x00, 0x82, 0x23, 0x5e,
397				0x21, 0xa2, 0x30, 0x00, 0x22, 0x73, 0x8d, 0xab,
398				0xb8, 0xe1, 0xbb, 0xd9, 0xd1, 0x9c, 0xfb, 0x1e,
399				0x7a, 0xb8, 0xc3, 0x0a, 0x23, 0xb0, 0xaf, 0xbb,
400				0x8d, 0x17, 0x8a, 0xbc, 0xf3, 0x02, 0x20, 0x24,
401				0xbf, 0x68, 0xe2, 0x56, 0xc5, 0x34, 0xdd, 0xfa,
402				0xf9, 0x66, 0xbf, 0x90, 0x8d, 0xeb, 0x94, 0x43,
403				0x05, 0x59, 0x6f, 0x7b, 0xdc, 0xc3, 0x8d, 0x69,
404				0xac, 0xad, 0x7f, 0x9c, 0x86, 0x87, 0x24,
405			},
406		},
407		// signature from bitcoin blockchain tx
408		// fda204502a3345e08afd6af27377c052e77f1fefeaeb31bdd45f1e1237ca5470
409		{
410			"valid 3 - s most significant bit is one",
411			&Signature{
412				R: fromHex("1cadddc2838598fee7dc35a12b340c6bde8b389f7bfd19a1252a17c4b5ed2d71"),
413				S: new(big.Int).Add(fromHex("00c1a251bbecb14b058a8bd77f65de87e51c47e95904f4c0e9d52eddc21c1415ac"), S256().N),
414			},
415			[]byte{
416				0x30, 0x45, 0x02, 0x20, 0x1c, 0xad, 0xdd, 0xc2,
417				0x83, 0x85, 0x98, 0xfe, 0xe7, 0xdc, 0x35, 0xa1,
418				0x2b, 0x34, 0x0c, 0x6b, 0xde, 0x8b, 0x38, 0x9f,
419				0x7b, 0xfd, 0x19, 0xa1, 0x25, 0x2a, 0x17, 0xc4,
420				0xb5, 0xed, 0x2d, 0x71, 0x02, 0x21, 0x00, 0xc1,
421				0xa2, 0x51, 0xbb, 0xec, 0xb1, 0x4b, 0x05, 0x8a,
422				0x8b, 0xd7, 0x7f, 0x65, 0xde, 0x87, 0xe5, 0x1c,
423				0x47, 0xe9, 0x59, 0x04, 0xf4, 0xc0, 0xe9, 0xd5,
424				0x2e, 0xdd, 0xc2, 0x1c, 0x14, 0x15, 0xac,
425			},
426		},
427		{
428			"valid 4 - s is bigger than half order",
429			&Signature{
430				R: fromHex("a196ed0e7ebcbe7b63fe1d8eecbdbde03a67ceba4fc8f6482bdcb9606a911404"),
431				S: fromHex("971729c7fa944b465b35250c6570a2f31acbb14b13d1565fab7330dcb2b3dfb1"),
432			},
433			[]byte{
434				0x30, 0x45, 0x02, 0x21, 0x00, 0xa1, 0x96, 0xed,
435				0x0e, 0x7e, 0xbc, 0xbe, 0x7b, 0x63, 0xfe, 0x1d,
436				0x8e, 0xec, 0xbd, 0xbd, 0xe0, 0x3a, 0x67, 0xce,
437				0xba, 0x4f, 0xc8, 0xf6, 0x48, 0x2b, 0xdc, 0xb9,
438				0x60, 0x6a, 0x91, 0x14, 0x04, 0x02, 0x20, 0x68,
439				0xe8, 0xd6, 0x38, 0x05, 0x6b, 0xb4, 0xb9, 0xa4,
440				0xca, 0xda, 0xf3, 0x9a, 0x8f, 0x5d, 0x0b, 0x9f,
441				0xe3, 0x2b, 0x9b, 0x9b, 0x77, 0x49, 0xdc, 0x14,
442				0x5f, 0x2d, 0xb0, 0x1d, 0x82, 0x61, 0x90,
443			},
444		},
445		{
446			"zero signature",
447			&Signature{
448				R: big.NewInt(0),
449				S: big.NewInt(0),
450			},
451			[]byte{0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00},
452		},
453	}
454
455	for i, test := range tests {
456		result := test.ecsig.Serialize()
457		if !bytes.Equal(result, test.expected) {
458			t.Errorf("Serialize #%d (%s) unexpected result:\n"+
459				"got:  %x\nwant: %x", i, test.name, result,
460				test.expected)
461		}
462	}
463}
464
465func testSignCompact(t *testing.T, tag string, curve *KoblitzCurve,
466	data []byte, isCompressed bool) {
467	tmp, _ := NewPrivateKey(curve)
468	priv := (*PrivateKey)(tmp)
469
470	hashed := []byte("testing")
471	sig, err := SignCompact(curve, priv, hashed, isCompressed)
472	if err != nil {
473		t.Errorf("%s: error signing: %s", tag, err)
474		return
475	}
476
477	pk, wasCompressed, err := RecoverCompact(curve, sig, hashed)
478	if err != nil {
479		t.Errorf("%s: error recovering: %s", tag, err)
480		return
481	}
482	if pk.X.Cmp(priv.X) != 0 || pk.Y.Cmp(priv.Y) != 0 {
483		t.Errorf("%s: recovered pubkey doesn't match original "+
484			"(%v,%v) vs (%v,%v) ", tag, pk.X, pk.Y, priv.X, priv.Y)
485		return
486	}
487	if wasCompressed != isCompressed {
488		t.Errorf("%s: recovered pubkey doesn't match compressed state "+
489			"(%v vs %v)", tag, isCompressed, wasCompressed)
490		return
491	}
492
493	// If we change the compressed bit we should get the same key back,
494	// but the compressed flag should be reversed.
495	if isCompressed {
496		sig[0] -= 4
497	} else {
498		sig[0] += 4
499	}
500
501	pk, wasCompressed, err = RecoverCompact(curve, sig, hashed)
502	if err != nil {
503		t.Errorf("%s: error recovering (2): %s", tag, err)
504		return
505	}
506	if pk.X.Cmp(priv.X) != 0 || pk.Y.Cmp(priv.Y) != 0 {
507		t.Errorf("%s: recovered pubkey (2) doesn't match original "+
508			"(%v,%v) vs (%v,%v) ", tag, pk.X, pk.Y, priv.X, priv.Y)
509		return
510	}
511	if wasCompressed == isCompressed {
512		t.Errorf("%s: recovered pubkey doesn't match reversed "+
513			"compressed state (%v vs %v)", tag, isCompressed,
514			wasCompressed)
515		return
516	}
517}
518
519func TestSignCompact(t *testing.T) {
520	for i := 0; i < 256; i++ {
521		name := fmt.Sprintf("test %d", i)
522		data := make([]byte, 32)
523		_, err := rand.Read(data)
524		if err != nil {
525			t.Errorf("failed to read random data for %s", name)
526			continue
527		}
528		compressed := i%2 != 0
529		testSignCompact(t, name, S256(), data, compressed)
530	}
531}
532
533// recoveryTests assert basic tests for public key recovery from signatures.
534// The cases are borrowed from github.com/fjl/btcec-issue.
535var recoveryTests = []struct {
536	msg string
537	sig string
538	pub string
539	err error
540}{
541	{
542		// Valid curve point recovered.
543		msg: "ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008",
544		sig: "0190f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc93",
545		pub: "04E32DF42865E97135ACFB65F3BAE71BDC86F4D49150AD6A440B6F15878109880A0A2B2667F7E725CEEA70C673093BF67663E0312623C8E091B13CF2C0F11EF652",
546	},
547	{
548		// Invalid curve point recovered.
549		msg: "00c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c",
550		sig: "0100b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
551		err: fmt.Errorf("invalid square root"),
552	},
553	{
554		// Low R and S values.
555		msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f",
556		sig: "00000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000004",
557		pub: "04A7640409AA2083FDAD38B2D8DE1263B2251799591D840653FB02DBBA503D7745FCB83D80E08A1E02896BE691EA6AFFB8A35939A646F1FC79052A744B1C82EDC3",
558	},
559}
560
561func TestRecoverCompact(t *testing.T) {
562	for i, test := range recoveryTests {
563		msg := decodeHex(test.msg)
564		sig := decodeHex(test.sig)
565
566		// Magic DER constant.
567		sig[0] += 27
568
569		pub, _, err := RecoverCompact(S256(), sig, msg)
570
571		// Verify that returned error matches as expected.
572		if !reflect.DeepEqual(test.err, err) {
573			t.Errorf("unexpected error returned from pubkey "+
574				"recovery #%d: wanted %v, got %v",
575				i, test.err, err)
576			continue
577		}
578
579		// If check succeeded because a proper error was returned, we
580		// ignore the returned pubkey.
581		if err != nil {
582			continue
583		}
584
585		// Otherwise, ensure the correct public key was recovered.
586		exPub, _ := ParsePubKey(decodeHex(test.pub), S256())
587		if !exPub.IsEqual(pub) {
588			t.Errorf("unexpected recovered public key #%d: "+
589				"want %v, got %v", i, exPub, pub)
590		}
591	}
592}
593
594func TestRFC6979(t *testing.T) {
595	// Test vectors matching Trezor and CoreBitcoin implementations.
596	// - https://github.com/trezor/trezor-crypto/blob/9fea8f8ab377dc514e40c6fd1f7c89a74c1d8dc6/tests.c#L432-L453
597	// - https://github.com/oleganza/CoreBitcoin/blob/e93dd71207861b5bf044415db5fa72405e7d8fbc/CoreBitcoin/BTCKey%2BTests.m#L23-L49
598	tests := []struct {
599		key       string
600		msg       string
601		nonce     string
602		signature string
603	}{
604		{
605			"cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50",
606			"sample",
607			"2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3",
608			"3045022100af340daf02cc15c8d5d08d7735dfe6b98a474ed373bdb5fbecf7571be52b384202205009fb27f37034a9b24b707b7c6b79ca23ddef9e25f7282e8a797efe53a8f124",
609		},
610		{
611			// This signature hits the case when S is higher than halforder.
612			// If S is not canonicalized (lowered by halforder), this test will fail.
613			"0000000000000000000000000000000000000000000000000000000000000001",
614			"Satoshi Nakamoto",
615			"8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15",
616			"3045022100934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d802202442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5",
617		},
618		{
619			"fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
620			"Satoshi Nakamoto",
621			"33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90",
622			"3045022100fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d002206b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5",
623		},
624		{
625			"f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181",
626			"Alan Turing",
627			"525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1",
628			"304402207063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c022058dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea",
629		},
630		{
631			"0000000000000000000000000000000000000000000000000000000000000001",
632			"All those moments will be lost in time, like tears in rain. Time to die...",
633			"38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3",
634			"30450221008600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b0220547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21",
635		},
636		{
637			"e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2",
638			"There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!",
639			"1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d",
640			"3045022100b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b0220279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6",
641		},
642	}
643
644	for i, test := range tests {
645		privKey, _ := PrivKeyFromBytes(S256(), decodeHex(test.key))
646		hash := sha256.Sum256([]byte(test.msg))
647
648		// Ensure deterministically generated nonce is the expected value.
649		gotNonce := nonceRFC6979(privKey.D, hash[:]).Bytes()
650		wantNonce := decodeHex(test.nonce)
651		if !bytes.Equal(gotNonce, wantNonce) {
652			t.Errorf("NonceRFC6979 #%d (%s): Nonce is incorrect: "+
653				"%x (expected %x)", i, test.msg, gotNonce,
654				wantNonce)
655			continue
656		}
657
658		// Ensure deterministically generated signature is the expected value.
659		gotSig, err := privKey.Sign(hash[:])
660		if err != nil {
661			t.Errorf("Sign #%d (%s): unexpected error: %v", i,
662				test.msg, err)
663			continue
664		}
665		gotSigBytes := gotSig.Serialize()
666		wantSigBytes := decodeHex(test.signature)
667		if !bytes.Equal(gotSigBytes, wantSigBytes) {
668			t.Errorf("Sign #%d (%s): mismatched signature: %x "+
669				"(expected %x)", i, test.msg, gotSigBytes,
670				wantSigBytes)
671			continue
672		}
673	}
674}
675
676func TestSignatureIsEqual(t *testing.T) {
677	sig1 := &Signature{
678		R: fromHex("0082235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c30a23b0afbb8d178abcf3"),
679		S: fromHex("24bf68e256c534ddfaf966bf908deb944305596f7bdcc38d69acad7f9c868724"),
680	}
681	sig2 := &Signature{
682		R: fromHex("4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41"),
683		S: fromHex("181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09"),
684	}
685
686	if !sig1.IsEqual(sig1) {
687		t.Fatalf("value of IsEqual is incorrect, %v is "+
688			"equal to %v", sig1, sig1)
689	}
690
691	if sig1.IsEqual(sig2) {
692		t.Fatalf("value of IsEqual is incorrect, %v is not "+
693			"equal to %v", sig1, sig2)
694	}
695}
696