Skip to content

Commit a17fcfb

Browse files
Valeh2012holiman
andauthored
optimize Exp for even bases (#189)
--------- Co-authored-by: Martin Holst Swende <martin@swende.se>
1 parent 439fbd4 commit a17fcfb

2 files changed

Lines changed: 53 additions & 54 deletions

File tree

benchmarks_test.go

Lines changed: 39 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -572,10 +572,7 @@ func bigExp(result, base, exponent *big.Int) *big.Int {
572572
return result
573573
}
574574

575-
func benchmark_Exp_Big(bench *testing.B) {
576-
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
577-
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
578-
575+
func benchmark_Exp_Big(bench *testing.B, x, y string) {
579576
orig := big.NewInt(0).SetBytes(hex2Bytes(x))
580577
base := big.NewInt(0).SetBytes(hex2Bytes(x))
581578
exp := big.NewInt(0).SetBytes(hex2Bytes(y))
@@ -587,62 +584,55 @@ func benchmark_Exp_Big(bench *testing.B) {
587584
base.Set(orig)
588585
}
589586
}
590-
func benchmark_Exp_Bit(bench *testing.B) {
591-
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
592-
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
593-
594-
base := big.NewInt(0).SetBytes(hex2Bytes(x))
595-
exp := big.NewInt(0).SetBytes(hex2Bytes(y))
596587

597-
f_base, _ := FromBig(base)
598-
f_orig, _ := FromBig(base)
599-
f_exp, _ := FromBig(exp)
600-
f_res := Int{}
588+
func benchmark_Exp_U256(bench *testing.B, x, y string) {
589+
var (
590+
base = big.NewInt(0).SetBytes(hex2Bytes(x))
591+
exp = big.NewInt(0).SetBytes(hex2Bytes(y))
601592

593+
f_base, _ = FromBig(base)
594+
f_orig, _ = FromBig(base)
595+
f_exp, _ = FromBig(exp)
596+
f_res Int
597+
)
602598
bench.ResetTimer()
603599
for i := 0; i < bench.N; i++ {
604600
f_res.Exp(f_base, f_exp)
605601
f_base.Set(f_orig)
606602
}
607603
}
608-
func benchmark_ExpSmall_Big(bench *testing.B) {
609-
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
610-
y := "8abcdef"
611604

612-
orig := big.NewInt(0).SetBytes(hex2Bytes(x))
613-
base := big.NewInt(0).SetBytes(hex2Bytes(x))
614-
exp := big.NewInt(0).SetBytes(hex2Bytes(y))
615-
616-
result := new(big.Int)
617-
bench.ResetTimer()
618-
for i := 0; i < bench.N; i++ {
619-
bigExp(result, base, exp)
620-
base.Set(orig)
605+
func BenchmarkExp(bench *testing.B) {
606+
{ // Large values
607+
base := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
608+
exp := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
609+
bench.Run("large/big", func(b *testing.B) {
610+
benchmark_Exp_Big(b, base, exp)
611+
})
612+
bench.Run("large/uint256", func(b *testing.B) {
613+
benchmark_Exp_U256(b, base, exp)
614+
})
621615
}
622-
}
623-
func benchmark_ExpSmall_Bit(bench *testing.B) {
624-
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
625-
y := "8abcdef"
626-
627-
base := big.NewInt(0).SetBytes(hex2Bytes(x))
628-
exp := big.NewInt(0).SetBytes(hex2Bytes(y))
629-
630-
f_base, _ := FromBig(base)
631-
f_orig, _ := FromBig(base)
632-
f_exp, _ := FromBig(exp)
633-
f_res := Int{}
634-
635-
bench.ResetTimer()
636-
for i := 0; i < bench.N; i++ {
637-
f_res.Exp(f_base, f_exp)
638-
f_base.Set(f_orig)
616+
{ // Smaller exponent
617+
base := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
618+
exp := "8abcdef"
619+
bench.Run("small/big", func(b *testing.B) {
620+
benchmark_Exp_Big(b, base, exp)
621+
})
622+
bench.Run("small/uint256", func(b *testing.B) {
623+
benchmark_Exp_U256(b, base, exp)
624+
})
625+
}
626+
{ // Even base (and very small exponent)
627+
base := "ABCDEF090807060504030201fffffffffffffffffffffffffffffffffffffffe"
628+
exp := "ff"
629+
bench.Run("even/big", func(b *testing.B) {
630+
benchmark_Exp_Big(b, base, exp)
631+
})
632+
bench.Run("even/uint256", func(b *testing.B) {
633+
benchmark_Exp_U256(b, base, exp)
634+
})
639635
}
640-
}
641-
func BenchmarkExp(bench *testing.B) {
642-
bench.Run("large/big", benchmark_Exp_Big)
643-
bench.Run("large/uint256", benchmark_Exp_Bit)
644-
bench.Run("small/big", benchmark_ExpSmall_Big)
645-
bench.Run("small/uint256", benchmark_ExpSmall_Bit)
646636
}
647637

648638
func BenchmarkDiv(b *testing.B) {

uint256.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,19 +1199,28 @@ func (z *Int) Byte(n *Int) *Int {
11991199

12001200
// Exp sets z = base**exponent mod 2**256, and returns z.
12011201
func (z *Int) Exp(base, exponent *Int) *Int {
1202-
res := Int{1, 0, 0, 0}
1203-
multiplier := *base
1204-
expBitLen := exponent.BitLen()
1202+
var (
1203+
res = Int{1, 0, 0, 0}
1204+
multiplier = *base
1205+
expBitLen = exponent.BitLen()
1206+
curBit = 0
1207+
word = exponent[0]
1208+
even = base[0]&1 == 0
1209+
)
1210+
if even && expBitLen > 8 {
1211+
return z.Clear()
1212+
}
12051213

1206-
curBit := 0
1207-
word := exponent[0]
12081214
for ; curBit < expBitLen && curBit < 64; curBit++ {
12091215
if word&1 == 1 {
12101216
res.Mul(&res, &multiplier)
12111217
}
12121218
multiplier.squared()
12131219
word >>= 1
12141220
}
1221+
if even { // If the base was even, we are finished now
1222+
return z.Set(&res)
1223+
}
12151224

12161225
word = exponent[1]
12171226
for ; curBit < expBitLen && curBit < 128; curBit++ {

0 commit comments

Comments
 (0)