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 txscript
6
7import (
8	"testing"
9
10	"github.com/btcsuite/btcd/chaincfg/chainhash"
11	"github.com/btcsuite/btcd/wire"
12)
13
14// TestBadPC sets the pc to a deliberately bad result then confirms that Step()
15// and Disasm fail correctly.
16func TestBadPC(t *testing.T) {
17	t.Parallel()
18
19	tests := []struct {
20		script, off int
21	}{
22		{script: 2, off: 0},
23		{script: 0, off: 2},
24	}
25
26	// tx with almost empty scripts.
27	tx := &wire.MsgTx{
28		Version: 1,
29		TxIn: []*wire.TxIn{
30			{
31				PreviousOutPoint: wire.OutPoint{
32					Hash: chainhash.Hash([32]byte{
33						0xc9, 0x97, 0xa5, 0xe5,
34						0x6e, 0x10, 0x41, 0x02,
35						0xfa, 0x20, 0x9c, 0x6a,
36						0x85, 0x2d, 0xd9, 0x06,
37						0x60, 0xa2, 0x0b, 0x2d,
38						0x9c, 0x35, 0x24, 0x23,
39						0xed, 0xce, 0x25, 0x85,
40						0x7f, 0xcd, 0x37, 0x04,
41					}),
42					Index: 0,
43				},
44				SignatureScript: mustParseShortForm("NOP"),
45				Sequence:        4294967295,
46			},
47		},
48		TxOut: []*wire.TxOut{{
49			Value:    1000000000,
50			PkScript: nil,
51		}},
52		LockTime: 0,
53	}
54	pkScript := mustParseShortForm("NOP")
55
56	for _, test := range tests {
57		vm, err := NewEngine(pkScript, tx, 0, 0, nil, nil, -1)
58		if err != nil {
59			t.Errorf("Failed to create script: %v", err)
60		}
61
62		// set to after all scripts
63		vm.scriptIdx = test.script
64		vm.scriptOff = test.off
65
66		_, err = vm.Step()
67		if err == nil {
68			t.Errorf("Step with invalid pc (%v) succeeds!", test)
69			continue
70		}
71
72		_, err = vm.DisasmPC()
73		if err == nil {
74			t.Errorf("DisasmPC with invalid pc (%v) succeeds!",
75				test)
76		}
77	}
78}
79
80// TestCheckErrorCondition tests the execute early test in CheckErrorCondition()
81// since most code paths are tested elsewhere.
82func TestCheckErrorCondition(t *testing.T) {
83	t.Parallel()
84
85	// tx with almost empty scripts.
86	tx := &wire.MsgTx{
87		Version: 1,
88		TxIn: []*wire.TxIn{{
89			PreviousOutPoint: wire.OutPoint{
90				Hash: chainhash.Hash([32]byte{
91					0xc9, 0x97, 0xa5, 0xe5,
92					0x6e, 0x10, 0x41, 0x02,
93					0xfa, 0x20, 0x9c, 0x6a,
94					0x85, 0x2d, 0xd9, 0x06,
95					0x60, 0xa2, 0x0b, 0x2d,
96					0x9c, 0x35, 0x24, 0x23,
97					0xed, 0xce, 0x25, 0x85,
98					0x7f, 0xcd, 0x37, 0x04,
99				}),
100				Index: 0,
101			},
102			SignatureScript: nil,
103			Sequence:        4294967295,
104		}},
105		TxOut: []*wire.TxOut{{
106			Value:    1000000000,
107			PkScript: nil,
108		}},
109		LockTime: 0,
110	}
111	pkScript := mustParseShortForm("NOP NOP NOP NOP NOP NOP NOP NOP NOP" +
112		" NOP TRUE")
113
114	vm, err := NewEngine(pkScript, tx, 0, 0, nil, nil, 0)
115	if err != nil {
116		t.Errorf("failed to create script: %v", err)
117	}
118
119	for i := 0; i < len(pkScript)-1; i++ {
120		done, err := vm.Step()
121		if err != nil {
122			t.Fatalf("failed to step %dth time: %v", i, err)
123		}
124		if done {
125			t.Fatalf("finshed early on %dth time", i)
126		}
127
128		err = vm.CheckErrorCondition(false)
129		if !IsErrorCode(err, ErrScriptUnfinished) {
130			t.Fatalf("got unexepected error %v on %dth iteration",
131				err, i)
132		}
133	}
134	done, err := vm.Step()
135	if err != nil {
136		t.Fatalf("final step failed %v", err)
137	}
138	if !done {
139		t.Fatalf("final step isn't done!")
140	}
141
142	err = vm.CheckErrorCondition(false)
143	if err != nil {
144		t.Errorf("unexpected error %v on final check", err)
145	}
146}
147
148// TestInvalidFlagCombinations ensures the script engine returns the expected
149// error when disallowed flag combinations are specified.
150func TestInvalidFlagCombinations(t *testing.T) {
151	t.Parallel()
152
153	tests := []ScriptFlags{
154		ScriptVerifyCleanStack,
155	}
156
157	// tx with almost empty scripts.
158	tx := &wire.MsgTx{
159		Version: 1,
160		TxIn: []*wire.TxIn{
161			{
162				PreviousOutPoint: wire.OutPoint{
163					Hash: chainhash.Hash([32]byte{
164						0xc9, 0x97, 0xa5, 0xe5,
165						0x6e, 0x10, 0x41, 0x02,
166						0xfa, 0x20, 0x9c, 0x6a,
167						0x85, 0x2d, 0xd9, 0x06,
168						0x60, 0xa2, 0x0b, 0x2d,
169						0x9c, 0x35, 0x24, 0x23,
170						0xed, 0xce, 0x25, 0x85,
171						0x7f, 0xcd, 0x37, 0x04,
172					}),
173					Index: 0,
174				},
175				SignatureScript: []uint8{OP_NOP},
176				Sequence:        4294967295,
177			},
178		},
179		TxOut: []*wire.TxOut{
180			{
181				Value:    1000000000,
182				PkScript: nil,
183			},
184		},
185		LockTime: 0,
186	}
187	pkScript := []byte{OP_NOP}
188
189	for i, test := range tests {
190		_, err := NewEngine(pkScript, tx, 0, test, nil, nil, -1)
191		if !IsErrorCode(err, ErrInvalidFlags) {
192			t.Fatalf("TestInvalidFlagCombinations #%d unexpected "+
193				"error: %v", i, err)
194		}
195	}
196}
197
198// TestCheckPubKeyEncoding ensures the internal checkPubKeyEncoding function
199// works as expected.
200func TestCheckPubKeyEncoding(t *testing.T) {
201	t.Parallel()
202
203	tests := []struct {
204		name    string
205		key     []byte
206		isValid bool
207	}{
208		{
209			name: "uncompressed ok",
210			key: hexToBytes("0411db93e1dcdb8a016b49840f8c53bc1eb68" +
211				"a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf" +
212				"9744464f82e160bfa9b8b64f9d4c03f999b8643f656b" +
213				"412a3"),
214			isValid: true,
215		},
216		{
217			name: "compressed ok",
218			key: hexToBytes("02ce0b14fb842b1ba549fdd675c98075f12e9" +
219				"c510f8ef52bd021a9a1f4809d3b4d"),
220			isValid: true,
221		},
222		{
223			name: "compressed ok",
224			key: hexToBytes("032689c7c2dab13309fb143e0e8fe39634252" +
225				"1887e976690b6b47f5b2a4b7d448e"),
226			isValid: true,
227		},
228		{
229			name: "hybrid",
230			key: hexToBytes("0679be667ef9dcbbac55a06295ce870b07029" +
231				"bfcdb2dce28d959f2815b16f81798483ada7726a3c46" +
232				"55da4fbfc0e1108a8fd17b448a68554199c47d08ffb1" +
233				"0d4b8"),
234			isValid: false,
235		},
236		{
237			name:    "empty",
238			key:     nil,
239			isValid: false,
240		},
241	}
242
243	vm := Engine{flags: ScriptVerifyStrictEncoding}
244	for _, test := range tests {
245		err := vm.checkPubKeyEncoding(test.key)
246		if err != nil && test.isValid {
247			t.Errorf("checkSignatureEncoding test '%s' failed "+
248				"when it should have succeeded: %v", test.name,
249				err)
250		} else if err == nil && !test.isValid {
251			t.Errorf("checkSignatureEncooding test '%s' succeeded "+
252				"when it should have failed", test.name)
253		}
254	}
255
256}
257
258// TestCheckSignatureEncoding ensures the internal checkSignatureEncoding
259// function works as expected.
260func TestCheckSignatureEncoding(t *testing.T) {
261	t.Parallel()
262
263	tests := []struct {
264		name    string
265		sig     []byte
266		isValid bool
267	}{
268		{
269			name: "valid signature",
270			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
271				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
272				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
273				"82221a8768d1d09"),
274			isValid: true,
275		},
276		{
277			name:    "empty.",
278			sig:     nil,
279			isValid: false,
280		},
281		{
282			name: "bad magic",
283			sig: hexToBytes("314402204e45e16932b8af514961a1d3a1a25" +
284				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
285				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
286				"82221a8768d1d09"),
287			isValid: false,
288		},
289		{
290			name: "bad 1st int marker magic",
291			sig: hexToBytes("304403204e45e16932b8af514961a1d3a1a25" +
292				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
293				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
294				"82221a8768d1d09"),
295			isValid: false,
296		},
297		{
298			name: "bad 2nd int marker",
299			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
300				"fdf3f4f7732e9d624c6c61548ab5fb8cd41032018152" +
301				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
302				"82221a8768d1d09"),
303			isValid: false,
304		},
305		{
306			name: "short len",
307			sig: hexToBytes("304302204e45e16932b8af514961a1d3a1a25" +
308				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
309				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
310				"82221a8768d1d09"),
311			isValid: false,
312		},
313		{
314			name: "long len",
315			sig: hexToBytes("304502204e45e16932b8af514961a1d3a1a25" +
316				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
317				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
318				"82221a8768d1d09"),
319			isValid: false,
320		},
321		{
322			name: "long X",
323			sig: hexToBytes("304402424e45e16932b8af514961a1d3a1a25" +
324				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
325				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
326				"82221a8768d1d09"),
327			isValid: false,
328		},
329		{
330			name: "long Y",
331			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
332				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022118152" +
333				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
334				"82221a8768d1d09"),
335			isValid: false,
336		},
337		{
338			name: "short Y",
339			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
340				"fdf3f4f7732e9d624c6c61548ab5fb8cd41021918152" +
341				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
342				"82221a8768d1d09"),
343			isValid: false,
344		},
345		{
346			name: "trailing crap",
347			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
348				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
349				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
350				"82221a8768d1d0901"),
351			isValid: false,
352		},
353		{
354			name: "X == N ",
355			sig: hexToBytes("30440220fffffffffffffffffffffffffffff" +
356				"ffebaaedce6af48a03bbfd25e8cd0364141022018152" +
357				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
358				"82221a8768d1d09"),
359			isValid: false,
360		},
361		{
362			name: "X == N ",
363			sig: hexToBytes("30440220fffffffffffffffffffffffffffff" +
364				"ffebaaedce6af48a03bbfd25e8cd0364142022018152" +
365				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
366				"82221a8768d1d09"),
367			isValid: false,
368		},
369		{
370			name: "Y == N",
371			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
372				"fdf3f4f7732e9d624c6c61548ab5fb8cd410220fffff" +
373				"ffffffffffffffffffffffffffebaaedce6af48a03bb" +
374				"fd25e8cd0364141"),
375			isValid: false,
376		},
377		{
378			name: "Y > N",
379			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
380				"fdf3f4f7732e9d624c6c61548ab5fb8cd410220fffff" +
381				"ffffffffffffffffffffffffffebaaedce6af48a03bb" +
382				"fd25e8cd0364142"),
383			isValid: false,
384		},
385		{
386			name: "0 len X",
387			sig: hexToBytes("302402000220181522ec8eca07de4860a4acd" +
388				"d12909d831cc56cbbac4622082221a8768d1d09"),
389			isValid: false,
390		},
391		{
392			name: "0 len Y",
393			sig: hexToBytes("302402204e45e16932b8af514961a1d3a1a25" +
394				"fdf3f4f7732e9d624c6c61548ab5fb8cd410200"),
395			isValid: false,
396		},
397		{
398			name: "extra R padding",
399			sig: hexToBytes("30450221004e45e16932b8af514961a1d3a1a" +
400				"25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181" +
401				"522ec8eca07de4860a4acdd12909d831cc56cbbac462" +
402				"2082221a8768d1d09"),
403			isValid: false,
404		},
405		{
406			name: "extra S padding",
407			sig: hexToBytes("304502204e45e16932b8af514961a1d3a1a25" +
408				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022100181" +
409				"522ec8eca07de4860a4acdd12909d831cc56cbbac462" +
410				"2082221a8768d1d09"),
411			isValid: false,
412		},
413	}
414
415	vm := Engine{flags: ScriptVerifyStrictEncoding}
416	for _, test := range tests {
417		err := vm.checkSignatureEncoding(test.sig)
418		if err != nil && test.isValid {
419			t.Errorf("checkSignatureEncoding test '%s' failed "+
420				"when it should have succeeded: %v", test.name,
421				err)
422		} else if err == nil && !test.isValid {
423			t.Errorf("checkSignatureEncooding test '%s' succeeded "+
424				"when it should have failed", test.name)
425		}
426	}
427}
428