22// Copyright 2020 uint256 Authors
33// SPDX-License-Identifier: BSD-3-Clause
44
5+ //go:build gofuzz
56// +build gofuzz
67
78package uint256
@@ -11,105 +12,180 @@ import (
1112 "math/big"
1213 "reflect"
1314 "runtime"
15+ "strings"
1416)
1517
1618const (
17- opUdivrem = 0
18- opMul = 1
19- opLsh = 2
20- opAdd = 4
21- opSub = 5
19+ opUdivrem = iota
20+ opMul
21+ opLsh
22+ opAdd
23+ opSub
24+ opMulmod
2225)
2326
24- type opFunc func (* Int , * Int , * Int ) * Int
25- type bigFunc func (* big.Int , * big.Int , * big.Int ) * big.Int
27+ type opDualArgFunc func (* Int , * Int , * Int ) * Int
28+ type bigDualArgFunc func (* big.Int , * big.Int , * big.Int ) * big.Int
2629
27- func crash (op opFunc , x , y Int , msg string ) {
30+ type opThreeArgFunc func (* Int , * Int , * Int , * Int ) * Int
31+ type bigThreeArgFunc func (* big.Int , * big.Int , * big.Int , * big.Int ) * big.Int
32+
33+ func crash (op interface {}, msg string , args ... Int ) {
2834 fn := runtime .FuncForPC (reflect .ValueOf (op ).Pointer ())
2935 fnName := fn .Name ()
3036 fnFile , fnLine := fn .FileLine (fn .Entry ())
31- panic (fmt .Sprintf ("%s\n for %s (%s:%d)\n x: %x\n y: %x" , msg , fnName , fnFile , fnLine , & x , & y ))
37+ var strArgs []string
38+ for i , arg := range args {
39+ strArgs = append (strArgs , fmt .Sprintf ("%d: %x" , i , & arg ))
40+ }
41+ panic (fmt .Sprintf ("%s\n for %s (%s:%d)\n %v" ,
42+ msg , fnName , fnFile , fnLine , strings .Join (strArgs , "\n " )))
3243}
3344
34- func checkOp (op opFunc , bigOp bigFunc , x , y Int ) {
45+ func checkDualArgOp (op opDualArgFunc , bigOp bigDualArgFunc , x , y Int ) {
3546 origX := x
3647 origY := y
3748
3849 var result Int
3950 ret := op (& result , & x , & y )
4051 if ret != & result {
41- crash (op , x , y , "returned not the pointer receiver" )
52+ crash (op , "returned not the pointer receiver" , x , y )
4253 }
4354 if x != origX {
44- crash (op , x , y , "first argument modified" )
55+ crash (op , "first argument modified" , x , y )
4556 }
4657 if y != origY {
47- crash (op , x , y , "second argument modified" )
58+ crash (op , "second argument modified" , x , y )
4859 }
4960
5061 expected , _ := FromBig (bigOp (new (big.Int ), x .ToBig (), y .ToBig ()))
5162 if result != * expected {
52- crash (op , x , y , "unexpected result" )
63+ crash (op , "unexpected result" , x , y )
5364 }
5465
5566 // Test again when the receiver is not zero.
5667 var garbage Int
5768 garbage .Xor (& x , & y )
5869 ret = op (& garbage , & x , & y )
5970 if ret != & garbage {
60- crash (op , x , y , "returned not the pointer receiver" )
71+ crash (op , "returned not the pointer receiver" , x , y )
6172 }
6273 if garbage != * expected {
63- crash (op , x , y , "unexpected result" )
74+ crash (op , "unexpected result" , x , y )
6475 }
6576 if x != origX {
66- crash (op , x , y , "first argument modified" )
77+ crash (op , "first argument modified" , x , y )
6778 }
6879 if y != origY {
69- crash (op , x , y , "second argument modified" )
80+ crash (op , "second argument modified" , x , y )
7081 }
7182
7283 // Test again with the receiver aliasing arguments.
7384 ret = op (& x , & x , & y )
7485 if ret != & x {
75- crash (op , x , y , "returned not the pointer receiver" )
86+ crash (op , "returned not the pointer receiver" , x , y )
7687 }
7788 if x != * expected {
78- crash (op , x , y , "unexpected result" )
89+ crash (op , "unexpected result" , x , y )
7990 }
8091
8192 ret = op (& y , & origX , & y )
8293 if ret != & y {
83- crash (op , x , y , "returned not the pointer receiver" )
94+ crash (op , "returned not the pointer receiver" , x , y )
8495 }
8596 if y != * expected {
86- crash (op , x , y , "unexpected result" )
97+ crash (op , "unexpected result" , x , y )
8798 }
8899}
89100
90- func Fuzz ( data [] byte ) int {
91- if len ( data ) != 65 {
92- return 0
93- }
101+ func checkThreeArgOp ( op opThreeArgFunc , bigOp bigThreeArgFunc , x , y , z Int ) {
102+ origX := x
103+ origY := y
104+ origZ := z
94105
95- op := data [0 ]
106+ var result Int
107+ ret := op (& result , & x , & y , & z )
108+ if ret != & result {
109+ crash (op , "returned not the pointer receiver" , x , y , z )
110+ }
111+ switch {
112+ case x != origX :
113+ crash (op , "first argument modified" , x , y , z )
114+ case y != origY :
115+ crash (op , "second argument modified" , x , y , z )
116+ case z != origZ :
117+ crash (op , "third argument modified" , x , y , z )
118+ }
119+ expected , _ := FromBig (bigOp (new (big.Int ), x .ToBig (), y .ToBig (), z .ToBig ()))
120+ if have , want := result , * expected ; have != want {
121+ crash (op , fmt .Sprintf ("unexpected result: have %v want %v" , have , want ), x , y , z )
122+ }
96123
97- var x , y Int
98- x .SetBytes (data [1 :33 ])
99- y .SetBytes (data [33 :])
124+ // Test again when the receiver is not zero.
125+ var garbage Int
126+ garbage .Xor (& x , & y )
127+ ret = op (& garbage , & x , & y , & z )
128+ if ret != & garbage {
129+ crash (op , "returned not the pointer receiver" , x , y , z )
130+ }
131+ if have , want := garbage , * expected ; have != want {
132+ crash (op , fmt .Sprintf ("unexpected result: have %v want %v" , have , want ), x , y , z )
133+ }
134+ switch {
135+ case x != origX :
136+ crash (op , "first argument modified" , x , y , z )
137+ case y != origY :
138+ crash (op , "second argument modified" , x , y , z )
139+ case z != origZ :
140+ crash (op , "third argument modified" , x , y , z )
141+ }
100142
101- switch op {
102- case opUdivrem :
103- if y .IsZero () {
104- return 0
105- }
106- checkOp ((* Int ).Div , (* big .Int ).Div , x , y )
107- checkOp ((* Int ).Mod , (* big .Int ).Mod , x , y )
143+ // Test again with the receiver aliasing arguments.
144+ ret = op (& x , & x , & y , & z )
145+ if ret != & x {
146+ crash (op , "returned not the pointer receiver" , x , y , z )
147+ }
148+ if have , want := x , * expected ; have != want {
149+ crash (op , fmt .Sprintf ("unexpected result: have %v want %v" , have , want ), x , y , z )
150+ }
108151
109- case opMul :
110- checkOp ((* Int ).Mul , (* big .Int ).Mul , x , y )
152+ ret = op (& y , & origX , & y , & z )
153+ if ret != & y {
154+ crash (op , "returned not the pointer receiver" , x , y , z )
155+ }
156+ if y != * expected {
157+ crash (op , "unexpected result" , x , y , z )
158+ }
159+ ret = op (& z , & origX , & origY , & z )
160+ if ret != & z {
161+ crash (op , "returned not the pointer receiver" , x , y , z )
162+ }
163+ if z != * expected {
164+ crash (op , fmt .Sprintf ("unexpected result: have %v want %v" , z .ToBig (), expected ), x , y , z )
165+ }
166+ }
111167
112- case opLsh :
168+ func Fuzz (data []byte ) int {
169+ switch len (data ) {
170+ case 64 :
171+ return fuzzBinaryOp (data )
172+ case 96 :
173+ return fuzzTernaryOp (data )
174+ }
175+ return - 1
176+ }
177+ func fuzzBinaryOp (data []byte ) int {
178+ var x , y Int
179+ x .SetBytes (data [0 :32 ])
180+ y .SetBytes (data [32 :])
181+ if ! y .IsZero () { // uDivrem
182+ checkDualArgOp ((* Int ).Div , (* big .Int ).Div , x , y )
183+ checkDualArgOp ((* Int ).Mod , (* big .Int ).Mod , x , y )
184+ }
185+ { // opMul
186+ checkDualArgOp ((* Int ).Mul , (* big .Int ).Mul , x , y )
187+ }
188+ { // opLsh
113189 lsh := func (z , x , y * Int ) * Int {
114190 return z .Lsh (x , uint (y [0 ]))
115191 }
@@ -120,14 +196,47 @@ func Fuzz(data []byte) int {
120196 }
121197 return z .Lsh (x , n )
122198 }
123- checkOp (lsh , bigLsh , x , y )
199+ checkDualArgOp (lsh , bigLsh , x , y )
200+ }
201+ { // opAdd
202+ checkDualArgOp ((* Int ).Add , (* big .Int ).Add , x , y )
203+ }
204+ { // opSub
205+ checkDualArgOp ((* Int ).Sub , (* big .Int ).Sub , x , y )
206+ }
207+ return 1
208+ }
124209
125- case opAdd :
126- checkOp ((* Int ).Add , (* big .Int ).Add , x , y )
210+ func bigMulMod (b1 , b2 , b3 , b4 * big.Int ) * big.Int {
211+ return b1 .Mod (big .NewInt (0 ).Mul (b2 , b3 ), b4 )
212+ }
127213
128- case opSub :
129- checkOp ((* Int ).Sub , (* big .Int ).Sub , x , y )
214+ func intMulMod (f1 , f2 , f3 , f4 * Int ) * Int {
215+ return f1 .MulMod (f2 , f3 , f4 )
216+ }
217+
218+ func bigAddMod (b1 , b2 , b3 , b4 * big.Int ) * big.Int {
219+ return b1 .Mod (big .NewInt (0 ).Add (b2 , b3 ), b4 )
220+ }
221+
222+ func intAddMod (f1 , f2 , f3 , f4 * Int ) * Int {
223+ return f1 .AddMod (f2 , f3 , f4 )
224+ }
225+
226+ func fuzzTernaryOp (data []byte ) int {
227+ var x , y , z Int
228+ x .SetBytes (data [:32 ])
229+ y .SetBytes (data [32 :64 ])
230+ z .SetBytes (data [64 :])
231+ if z .IsZero () {
232+ return 0
130233 }
131234
132- return 0
235+ { // mulMod
236+ checkThreeArgOp (intMulMod , bigMulMod , x , y , z )
237+ }
238+ { // addMod
239+ checkThreeArgOp (intAddMod , bigAddMod , x , y , z )
240+ }
241+ return 1
133242}
0 commit comments