• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2017, Google Inc.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15//go:build ignore
16
17package main
18
19import (
20	"bufio"
21	"crypto/sha1"
22	"encoding/hex"
23	"errors"
24	"fmt"
25	"io"
26	"math/big"
27	"os"
28	"path/filepath"
29	"strings"
30)
31
32type test struct {
33	LineNumber int
34	Type       string
35	Values     map[string]*big.Int
36}
37
38type testScanner struct {
39	scanner *bufio.Scanner
40	lineNo  int
41	err     error
42	test    test
43}
44
45func newTestScanner(r io.Reader) *testScanner {
46	return &testScanner{scanner: bufio.NewScanner(r)}
47}
48
49func (s *testScanner) scanLine() bool {
50	if !s.scanner.Scan() {
51		return false
52	}
53	s.lineNo++
54	return true
55}
56
57func (s *testScanner) addAttribute(line string) (key string, ok bool) {
58	fields := strings.SplitN(line, "=", 2)
59	if len(fields) != 2 {
60		s.setError(errors.New("invalid syntax"))
61		return "", false
62	}
63
64	key = strings.TrimSpace(fields[0])
65	value := strings.TrimSpace(fields[1])
66
67	valueInt, ok := new(big.Int).SetString(value, 16)
68	if !ok {
69		s.setError(fmt.Errorf("could not parse %q", value))
70		return "", false
71	}
72	if _, dup := s.test.Values[key]; dup {
73		s.setError(fmt.Errorf("duplicate key %q", key))
74		return "", false
75	}
76	s.test.Values[key] = valueInt
77	return key, true
78}
79
80func (s *testScanner) Scan() bool {
81	s.test = test{
82		Values: make(map[string]*big.Int),
83	}
84
85	// Scan until the first attribute.
86	for {
87		if !s.scanLine() {
88			return false
89		}
90		if len(s.scanner.Text()) != 0 && s.scanner.Text()[0] != '#' {
91			break
92		}
93	}
94
95	var ok bool
96	s.test.Type, ok = s.addAttribute(s.scanner.Text())
97	if !ok {
98		return false
99	}
100	s.test.LineNumber = s.lineNo
101
102	for s.scanLine() {
103		if len(s.scanner.Text()) == 0 {
104			break
105		}
106
107		if s.scanner.Text()[0] == '#' {
108			continue
109		}
110
111		if _, ok := s.addAttribute(s.scanner.Text()); !ok {
112			return false
113		}
114	}
115	return s.scanner.Err() == nil
116}
117
118func (s *testScanner) Test() test {
119	return s.test
120}
121
122func (s *testScanner) Err() error {
123	if s.err != nil {
124		return s.err
125	}
126	return s.scanner.Err()
127}
128
129func (s *testScanner) setError(err error) {
130	s.err = fmt.Errorf("line %d: %s", s.lineNo, err)
131}
132
133func checkKeys(t test, keys ...string) bool {
134	var foundErrors bool
135
136	for _, k := range keys {
137		if _, ok := t.Values[k]; !ok {
138			fmt.Fprintf(os.Stderr, "Line %d: missing key %q.\n", t.LineNumber, k)
139			foundErrors = true
140		}
141	}
142
143	for k := range t.Values {
144		var found bool
145		for _, k2 := range keys {
146			if k == k2 {
147				found = true
148				break
149			}
150		}
151		if !found {
152			fmt.Fprintf(os.Stderr, "Line %d: unexpected key %q.\n", t.LineNumber, k)
153			foundErrors = true
154		}
155	}
156
157	return !foundErrors
158}
159
160func appendLengthPrefixed(ret, b []byte) []byte {
161	ret = append(ret, byte(len(b)>>8), byte(len(b)))
162	ret = append(ret, b...)
163	return ret
164}
165
166func appendUnsigned(ret []byte, n *big.Int) []byte {
167	b := n.Bytes()
168	if n.Sign() == 0 {
169		b = []byte{0}
170	}
171	return appendLengthPrefixed(ret, b)
172}
173
174func appendSigned(ret []byte, n *big.Int) []byte {
175	var sign byte
176	if n.Sign() < 0 {
177		sign = 1
178	}
179	b := []byte{sign}
180	b = append(b, n.Bytes()...)
181	if n.Sign() == 0 {
182		b = append(b, 0)
183	}
184	return appendLengthPrefixed(ret, b)
185}
186
187func main() {
188	if len(os.Args) != 3 {
189		fmt.Fprintf(os.Stderr, "Usage: %s TESTS FUZZ_DIR\n", os.Args[0])
190		os.Exit(1)
191	}
192
193	in, err := os.Open(os.Args[1])
194	if err != nil {
195		fmt.Fprintf(os.Stderr, "Error opening %s: %s.\n", os.Args[0], err)
196		os.Exit(1)
197	}
198	defer in.Close()
199
200	fuzzerDir := os.Args[2]
201
202	scanner := newTestScanner(in)
203	for scanner.Scan() {
204		var fuzzer string
205		var b []byte
206		test := scanner.Test()
207		switch test.Type {
208		case "Quotient":
209			if checkKeys(test, "A", "B", "Quotient", "Remainder") {
210				fuzzer = "bn_div"
211				b = appendSigned(b, test.Values["A"])
212				b = appendSigned(b, test.Values["B"])
213			}
214		case "ModExp":
215			if checkKeys(test, "A", "E", "M", "ModExp") {
216				fuzzer = "bn_mod_exp"
217				b = appendSigned(b, test.Values["A"])
218				b = appendUnsigned(b, test.Values["E"])
219				b = appendUnsigned(b, test.Values["M"])
220			}
221		}
222
223		if len(fuzzer) != 0 {
224			hash := sha1.Sum(b)
225			path := filepath.Join(fuzzerDir, fuzzer+"_corpus", hex.EncodeToString(hash[:]))
226			if err := os.WriteFile(path, b, 0666); err != nil {
227				fmt.Fprintf(os.Stderr, "Error writing to %s: %s.\n", path, err)
228				os.Exit(1)
229			}
230		}
231	}
232	if scanner.Err() != nil {
233		fmt.Fprintf(os.Stderr, "Error reading tests: %s.\n", scanner.Err())
234	}
235}
236