github.com/jimmyx0x/go-ethereum@v1.10.28/tests/fuzzers/modexp/modexp-fuzzer.go (about) 1 // Copyright 2022 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 modexp 18 19 import ( 20 "fmt" 21 "math/big" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/core/vm" 25 big2 "github.com/holiman/big" 26 ) 27 28 // Fuzz is the fuzzing entry-point. 29 // The function must return 30 // 31 // - 1 if the fuzzer should increase priority of the 32 // given input during subsequent fuzzing (for example, the input is lexically 33 // correct and was parsed successfully); 34 // - -1 if the input must not be added to corpus even if gives new coverage; and 35 // - 0 otherwise 36 // 37 // other values are reserved for future use. 38 func Fuzz(input []byte) int { 39 if len(input) <= 96 { 40 return -1 41 } 42 // Abort on too expensive inputs 43 precomp := vm.PrecompiledContractsBerlin[common.BytesToAddress([]byte{5})] 44 if gas := precomp.RequiredGas(input); gas > 40_000_000 { 45 return 0 46 } 47 var ( 48 baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() 49 expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() 50 modLen = new(big.Int).SetBytes(getData(input, 64, 32)).Uint64() 51 ) 52 // Handle a special case when both the base and mod length is zero 53 if baseLen == 0 && modLen == 0 { 54 return -1 55 } 56 input = input[96:] 57 // Retrieve the operands and execute the exponentiation 58 var ( 59 base = new(big.Int).SetBytes(getData(input, 0, baseLen)) 60 exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) 61 mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) 62 base2 = new(big2.Int).SetBytes(getData(input, 0, baseLen)) 63 exp2 = new(big2.Int).SetBytes(getData(input, baseLen, expLen)) 64 mod2 = new(big2.Int).SetBytes(getData(input, baseLen+expLen, modLen)) 65 ) 66 if mod.BitLen() == 0 { 67 // Modulo 0 is undefined, return zero 68 return -1 69 } 70 var a = new(big2.Int).Exp(base2, exp2, mod2).String() 71 var b = new(big.Int).Exp(base, exp, mod).String() 72 if a != b { 73 panic(fmt.Sprintf("Inequality %#x ^ %#x mod %#x \n have %s\n want %s", base, exp, mod, a, b)) 74 } 75 return 1 76 } 77 78 // getData returns a slice from the data based on the start and size and pads 79 // up to size with zero's. This function is overflow safe. 80 func getData(data []byte, start uint64, size uint64) []byte { 81 length := uint64(len(data)) 82 if start > length { 83 start = length 84 } 85 end := start + size 86 if end > length { 87 end = length 88 } 89 return common.RightPadBytes(data[start:end], int(size)) 90 }