From abebda601ccc5f0717c15d9a916bab3591f1d31c Mon Sep 17 00:00:00 2001 From: Daniel Liu Date: Thu, 26 Sep 2024 13:34:52 +0800 Subject: [PATCH] common/math, tests/fuzzers: use big.Int clone (#26006) --- common/math/modexp.go | 82 --------------------------- common/math/modexp_test.go | 53 +++++++++++++++++ go.mod | 1 + go.sum | 2 + tests/fuzzers/modexp/debug/main.go | 40 +++++++++++++ tests/fuzzers/modexp/modexp-fuzzer.go | 19 ++++--- 6 files changed, 107 insertions(+), 90 deletions(-) delete mode 100644 common/math/modexp.go create mode 100644 common/math/modexp_test.go create mode 100644 tests/fuzzers/modexp/debug/main.go diff --git a/common/math/modexp.go b/common/math/modexp.go deleted file mode 100644 index 02ef755574..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/XinFinOrg/XDPoSChain/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 b7baee7256..7e9a4f481d 100644 --- a/go.mod +++ b/go.mod @@ -61,6 +61,7 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/maruel/panicparse v0.0.0-20160720141634-ad661195ed0e // indirect diff --git a/go.sum b/go.sum index 98d3a63aed..36c3740a1f 100644 --- a/go.sum +++ b/go.sum @@ -141,6 +141,8 @@ github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1 github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/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/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= diff --git a/tests/fuzzers/modexp/debug/main.go b/tests/fuzzers/modexp/debug/main.go new file mode 100644 index 0000000000..008e46b192 --- /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/XinFinOrg/XDPoSChain/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 38e8487d1b..bdbfd86e30 100644 --- a/tests/fuzzers/modexp/modexp-fuzzer.go +++ b/tests/fuzzers/modexp/modexp-fuzzer.go @@ -21,8 +21,8 @@ import ( "math/big" "github.com/XinFinOrg/XDPoSChain/common" - "github.com/XinFinOrg/XDPoSChain/common/math" "github.com/XinFinOrg/XDPoSChain/core/vm" + big2 "github.com/holiman/big" ) // The function must return @@ -55,18 +55,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 }