diff --git a/common/math/modexp.go b/common/math/modexp.go deleted file mode 100644 index b0a32e8c27..0000000000 --- a/common/math/modexp.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -import ( - "math/big" - "math/bits" - - "github.com/ethereum/go-ethereum/common" -) - -// FastExp is semantically equivalent to x.Exp(x,y, m), but is faster for even -// modulus. -func FastExp(x, y, m *big.Int) *big.Int { - // Split m = m1 × m2 where m1 = 2ⁿ - n := m.TrailingZeroBits() - m1 := new(big.Int).Lsh(common.Big1, n) - mask := new(big.Int).Sub(m1, common.Big1) - m2 := new(big.Int).Rsh(m, n) - - // We want z = x**y mod m. - // z1 = x**y mod m1 = (x**y mod m) mod m1 = z mod m1 - // z2 = x**y mod m2 = (x**y mod m) mod m2 = z mod m2 - z1 := fastExpPow2(x, y, mask) - z2 := new(big.Int).Exp(x, y, m2) - - // Reconstruct z from z1, z2 using CRT, using algorithm from paper, - // which uses only a single modInverse. - // p = (z1 - z2) * m2⁻¹ (mod m1) - // z = z2 + p * m2 - z := new(big.Int).Set(z2) - - // Compute (z1 - z2) mod m1 [m1 == 2**n] into z1. - z1 = z1.And(z1, mask) - z2 = z2.And(z2, mask) - z1 = z1.Sub(z1, z2) - if z1.Sign() < 0 { - z1 = z1.Add(z1, m1) - } - - // Reuse z2 for p = z1 * m2inv. - m2inv := new(big.Int).ModInverse(m2, m1) - z2 = z2.Mul(z1, m2inv) - z2 = z2.And(z2, mask) - - // Reuse z1 for m2 * p. - z = z.Add(z, z1.Mul(z2, m2)) - z = z.Rem(z, m) - - return z -} - -func fastExpPow2(x, y *big.Int, mask *big.Int) *big.Int { - z := big.NewInt(1) - if y.Sign() == 0 { - return z - } - p := new(big.Int).Set(x) - p = p.And(p, mask) - if p.Cmp(z) <= 0 { // p <= 1 - return p - } - if y.Cmp(mask) > 0 { - y = new(big.Int).And(y, mask) - } - t := new(big.Int) - - for _, b := range y.Bits() { - for i := 0; i < bits.UintSize; i++ { - if b&1 != 0 { - z, t = t.Mul(z, p), z - z = z.And(z, mask) - } - p, t = t.Mul(p, p), p - p = p.And(p, mask) - b >>= 1 - } - } - return z -} diff --git a/common/math/modexp_test.go b/common/math/modexp_test.go new file mode 100644 index 0000000000..bd90076f84 --- /dev/null +++ b/common/math/modexp_test.go @@ -0,0 +1,53 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package math + +import ( + "math/big" + "testing" + + big2 "github.com/holiman/big" +) + +// TestFastModexp tests some cases found during fuzzing. +func TestFastModexp(t *testing.T) { + for i, tc := range []struct { + base string + exp string + mod string + }{ + {"0xeffffff900002f00", "0x40000000000000", "0x200"}, + {"0xf000", "0x4f900b400080000", "0x400000d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9ffffff005aeffd310000000000000000000000000000000000009f9f9f9f0000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000befffa5a5a5fff900002f000040000000000000000000000000000000029d9d9d000000000000009f9f9f00000000000000009f9f9f000000f3a080ab00000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f0000000000002900009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000cf000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000befffff0000c0800000000800000000000000000000000000000002000000000000009f9f9f0000000000000000008000ff000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000befffa5a5a5fff900002f000040000000000000000000000000000000029d9d9d000000000000009f9f9f00000000000000009f9f9f000000f3a080ab00000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f0000000000002900009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000beffffff900002f0000400000c100000000000000000000000000000000000000006160600000000000000000008000ff0000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f0000"}, + {"5", "1435700818", "72"}, + {"0xffff", "0x300030003000300030003000300030003000302a3000300030003000300030003000300030003000300030003000300030003030623066307f3030783062303430383064303630343036", "0x300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, + {"0x3133", "0x667f00000000000000000000000000ff002a000000000000000000000000000000000000000000000000000000000000667fff30783362773057ee756a6c266134643831646230313630", "0x3030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, + } { + var ( + base, _ = new(big.Int).SetString(tc.base, 0) + exp, _ = new(big.Int).SetString(tc.exp, 0) + mod, _ = new(big.Int).SetString(tc.mod, 0) + base2, _ = new(big2.Int).SetString(tc.base, 0) + exp2, _ = new(big2.Int).SetString(tc.exp, 0) + mod2, _ = new(big2.Int).SetString(tc.mod, 0) + ) + var a = new(big2.Int).Exp(base2, exp2, mod2).String() + var b = new(big.Int).Exp(base, exp, mod).String() + if a != b { + t.Errorf("test %d: %#x ^ %#x mod %#x \n have %x\n want %x", i, base, exp, mod, a, b) + } + } +} diff --git a/go.mod b/go.mod index 1f88ef7c6f..eda8e663c6 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/go-bexpr v0.1.10 github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d + github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e github.com/holiman/bloomfilter/v2 v2.0.3 github.com/holiman/uint256 v1.2.0 github.com/huin/goupnp v1.0.3 @@ -60,7 +61,7 @@ require ( golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a + golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 golang.org/x/text v0.3.7 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba diff --git a/go.sum b/go.sum index 3b1b58a121..50c27386cb 100644 --- a/go.sum +++ b/go.sum @@ -223,6 +223,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw= +github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= @@ -552,8 +554,9 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4= +golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= diff --git a/tests/fuzzers/modexp/debug/main.go b/tests/fuzzers/modexp/debug/main.go new file mode 100644 index 0000000000..22002bd3f8 --- /dev/null +++ b/tests/fuzzers/modexp/debug/main.go @@ -0,0 +1,40 @@ +// Copyright 2020 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package main + +import ( + "fmt" + "os" + + "github.com/ethereum/go-ethereum/tests/fuzzers/modexp" +) + +func main() { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "Usage: debug \n") + fmt.Fprintf(os.Stderr, "Example\n") + fmt.Fprintf(os.Stderr, " $ debug ../crashers/4bbef6857c733a87ecf6fd8b9e7238f65eb9862a\n") + os.Exit(1) + } + crasher := os.Args[1] + data, err := os.ReadFile(crasher) + if err != nil { + fmt.Fprintf(os.Stderr, "error loading crasher %v: %v", crasher, err) + os.Exit(1) + } + modexp.Fuzz(data) +} diff --git a/tests/fuzzers/modexp/modexp-fuzzer.go b/tests/fuzzers/modexp/modexp-fuzzer.go index a288404942..086d9e1153 100644 --- a/tests/fuzzers/modexp/modexp-fuzzer.go +++ b/tests/fuzzers/modexp/modexp-fuzzer.go @@ -21,8 +21,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/vm" + big2 "github.com/holiman/big" ) // Fuzz is the fuzzing entry-point. @@ -56,18 +56,21 @@ func Fuzz(input []byte) int { input = input[96:] // Retrieve the operands and execute the exponentiation var ( - base = new(big.Int).SetBytes(getData(input, 0, baseLen)) - exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) - mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + base = new(big.Int).SetBytes(getData(input, 0, baseLen)) + exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) + mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + base2 = new(big2.Int).SetBytes(getData(input, 0, baseLen)) + exp2 = new(big2.Int).SetBytes(getData(input, baseLen, expLen)) + mod2 = new(big2.Int).SetBytes(getData(input, baseLen+expLen, modLen)) ) if mod.BitLen() == 0 { // Modulo 0 is undefined, return zero return -1 } - var a = math.FastExp(new(big.Int).Set(base), new(big.Int).Set(exp), new(big.Int).Set(mod)) - var b = base.Exp(base, exp, mod) - if a.Cmp(b) != 0 { - panic(fmt.Sprintf("Inequality %x != %x", a, b)) + var a = new(big2.Int).Exp(base2, exp2, mod2).String() + var b = new(big.Int).Exp(base, exp, mod).String() + if a != b { + panic(fmt.Sprintf("Inequality %#x ^ %#x mod %#x \n have %s\n want %s", base, exp, mod, a, b)) } return 1 }