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