status-go/vendor/github.com/holiman/uint256/fuzz.go

134 lines
2.6 KiB
Go
Raw Permalink Normal View History

// uint256: Fixed size 256-bit math library
// Copyright 2020 uint256 Authors
// SPDX-License-Identifier: BSD-3-Clause
// +build gofuzz
package uint256
import (
"fmt"
"math/big"
"reflect"
"runtime"
)
const (
opUdivrem = 0
opMul = 1
opLsh = 2
opAdd = 4
opSub = 5
)
type opFunc func(*Int, *Int, *Int) *Int
type bigFunc func(*big.Int, *big.Int, *big.Int) *big.Int
func crash(op opFunc, x, y Int, msg string) {
fn := runtime.FuncForPC(reflect.ValueOf(op).Pointer())
fnName := fn.Name()
fnFile, fnLine := fn.FileLine(fn.Entry())
panic(fmt.Sprintf("%s\nfor %s (%s:%d)\nx: %x\ny: %x", msg, fnName, fnFile, fnLine, &x, &y))
}
func checkOp(op opFunc, bigOp bigFunc, x, y Int) {
origX := x
origY := y
var result Int
ret := op(&result, &x, &y)
if ret != &result {
crash(op, x, y, "returned not the pointer receiver")
}
if x != origX {
crash(op, x, y, "first argument modified")
}
if y != origY {
crash(op, x, y, "second argument modified")
}
expected, _ := FromBig(bigOp(new(big.Int), x.ToBig(), y.ToBig()))
if result != *expected {
crash(op, x, y, "unexpected result")
}
// Test again when the receiver is not zero.
var garbage Int
garbage.Xor(&x, &y)
ret = op(&garbage, &x, &y)
if ret != &garbage {
crash(op, x, y, "returned not the pointer receiver")
}
if garbage != *expected {
crash(op, x, y, "unexpected result")
}
if x != origX {
crash(op, x, y, "first argument modified")
}
if y != origY {
crash(op, x, y, "second argument modified")
}
// Test again with the receiver aliasing arguments.
ret = op(&x, &x, &y)
if ret != &x {
crash(op, x, y, "returned not the pointer receiver")
}
if x != *expected {
crash(op, x, y, "unexpected result")
}
ret = op(&y, &origX, &y)
if ret != &y {
crash(op, x, y, "returned not the pointer receiver")
}
if y != *expected {
crash(op, x, y, "unexpected result")
}
}
func Fuzz(data []byte) int {
if len(data) != 65 {
return 0
}
op := data[0]
var x, y Int
x.SetBytes(data[1:33])
y.SetBytes(data[33:])
switch op {
case opUdivrem:
if y.IsZero() {
return 0
}
checkOp((*Int).Div, (*big.Int).Div, x, y)
checkOp((*Int).Mod, (*big.Int).Mod, x, y)
case opMul:
checkOp((*Int).Mul, (*big.Int).Mul, x, y)
case opLsh:
lsh := func(z, x, y *Int) *Int {
return z.Lsh(x, uint(y[0]))
}
bigLsh := func(z, x, y *big.Int) *big.Int {
n := uint(y.Uint64())
if n > 256 {
n = 256
}
return z.Lsh(x, n)
}
checkOp(lsh, bigLsh, x, y)
case opAdd:
checkOp((*Int).Add, (*big.Int).Add, x, y)
case opSub:
checkOp((*Int).Sub, (*big.Int).Sub, x, y)
}
return 0
}