github.com/haliliceylan/bsc@v1.1.10-0.20220501224556-eb78d644ebcb/tests/fuzzers/rangeproof/rangeproof-fuzzer.go (about) 1 // Copyright 2020 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package rangeproof 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "io" 24 "sort" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/ethdb/memorydb" 28 "github.com/ethereum/go-ethereum/trie" 29 ) 30 31 type kv struct { 32 k, v []byte 33 t bool 34 } 35 36 type entrySlice []*kv 37 38 func (p entrySlice) Len() int { return len(p) } 39 func (p entrySlice) Less(i, j int) bool { return bytes.Compare(p[i].k, p[j].k) < 0 } 40 func (p entrySlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 41 42 type fuzzer struct { 43 input io.Reader 44 exhausted bool 45 } 46 47 func (f *fuzzer) randBytes(n int) []byte { 48 r := make([]byte, n) 49 if _, err := f.input.Read(r); err != nil { 50 f.exhausted = true 51 } 52 return r 53 } 54 55 func (f *fuzzer) readInt() uint64 { 56 var x uint64 57 if err := binary.Read(f.input, binary.LittleEndian, &x); err != nil { 58 f.exhausted = true 59 } 60 return x 61 } 62 63 func (f *fuzzer) randomTrie(n int) (*trie.Trie, map[string]*kv) { 64 65 trie := new(trie.Trie) 66 vals := make(map[string]*kv) 67 size := f.readInt() 68 // Fill it with some fluff 69 for i := byte(0); i < byte(size); i++ { 70 value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} 71 value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false} 72 trie.Update(value.k, value.v) 73 trie.Update(value2.k, value2.v) 74 vals[string(value.k)] = value 75 vals[string(value2.k)] = value2 76 } 77 if f.exhausted { 78 return nil, nil 79 } 80 // And now fill with some random 81 for i := 0; i < n; i++ { 82 k := f.randBytes(32) 83 v := f.randBytes(20) 84 value := &kv{k, v, false} 85 trie.Update(k, v) 86 vals[string(k)] = value 87 if f.exhausted { 88 return nil, nil 89 } 90 } 91 return trie, vals 92 } 93 94 func (f *fuzzer) fuzz() int { 95 maxSize := 200 96 tr, vals := f.randomTrie(1 + int(f.readInt())%maxSize) 97 if f.exhausted { 98 return 0 // input too short 99 } 100 var entries entrySlice 101 for _, kv := range vals { 102 entries = append(entries, kv) 103 } 104 if len(entries) <= 1 { 105 return 0 106 } 107 sort.Sort(entries) 108 109 var ok = 0 110 for { 111 start := int(f.readInt() % uint64(len(entries))) 112 end := 1 + int(f.readInt()%uint64(len(entries)-1)) 113 testcase := int(f.readInt() % uint64(6)) 114 index := int(f.readInt() & 0xFFFFFFFF) 115 index2 := int(f.readInt() & 0xFFFFFFFF) 116 if f.exhausted { 117 break 118 } 119 proof := memorydb.New() 120 if err := tr.Prove(entries[start].k, 0, proof); err != nil { 121 panic(fmt.Sprintf("Failed to prove the first node %v", err)) 122 } 123 if err := tr.Prove(entries[end-1].k, 0, proof); err != nil { 124 panic(fmt.Sprintf("Failed to prove the last node %v", err)) 125 } 126 var keys [][]byte 127 var vals [][]byte 128 for i := start; i < end; i++ { 129 keys = append(keys, entries[i].k) 130 vals = append(vals, entries[i].v) 131 } 132 if len(keys) == 0 { 133 return 0 134 } 135 var first, last = keys[0], keys[len(keys)-1] 136 testcase %= 6 137 switch testcase { 138 case 0: 139 // Modified key 140 keys[index%len(keys)] = f.randBytes(32) // In theory it can't be same 141 case 1: 142 // Modified val 143 vals[index%len(vals)] = f.randBytes(20) // In theory it can't be same 144 case 2: 145 // Gapped entry slice 146 index = index % len(keys) 147 keys = append(keys[:index], keys[index+1:]...) 148 vals = append(vals[:index], vals[index+1:]...) 149 case 3: 150 // Out of order 151 index1 := index % len(keys) 152 index2 := index2 % len(keys) 153 keys[index1], keys[index2] = keys[index2], keys[index1] 154 vals[index1], vals[index2] = vals[index2], vals[index1] 155 case 4: 156 // Set random key to nil, do nothing 157 keys[index%len(keys)] = nil 158 case 5: 159 // Set random value to nil, deletion 160 vals[index%len(vals)] = nil 161 162 // Other cases: 163 // Modify something in the proof db 164 // add stuff to proof db 165 // drop stuff from proof db 166 167 } 168 if f.exhausted { 169 break 170 } 171 ok = 1 172 //nodes, subtrie 173 hasMore, err := trie.VerifyRangeProof(tr.Hash(), first, last, keys, vals, proof) 174 if err != nil { 175 if hasMore { 176 panic("err != nil && hasMore == true") 177 } 178 } 179 } 180 return ok 181 } 182 183 // The function must return 184 // 1 if the fuzzer should increase priority of the 185 // given input during subsequent fuzzing (for example, the input is lexically 186 // correct and was parsed successfully); 187 // -1 if the input must not be added to corpus even if gives new coverage; and 188 // 0 otherwise; other values are reserved for future use. 189 func Fuzz(input []byte) int { 190 if len(input) < 100 { 191 return 0 192 } 193 r := bytes.NewReader(input) 194 f := fuzzer{ 195 input: r, 196 exhausted: false, 197 } 198 return f.fuzz() 199 }