134 lines
2.6 KiB
Go
134 lines
2.6 KiB
Go
// 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
|
|
}
|