Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimised modular arithmetic targeting elliptic curve operations #86

Merged
merged 50 commits into from
Oct 25, 2021
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
be6f2c0
Adds faster 256-bit modular addition and multiplication
daosvik Aug 13, 2021
2e57fec
Fix problems identified by CI
daosvik Aug 13, 2021
d805bd1
Use AddOverflow and SubOverflow instead of add256 and sub256
daosvik Aug 19, 2021
d94fb68
Remove unnecessary assignment and replace use of SubOverflow with Sub
daosvik Aug 19, 2021
ab5ffc1
Use explicit returns
daosvik Aug 19, 2021
b66fd9f
Add comment about iteration count in AddMod
daosvik Aug 23, 2021
4b6e116
Fix mistake in calculation of reciprocal for (64n+1)-bit moduli
daosvik Aug 26, 2021
9f29343
Change expression according to readability preference
daosvik Aug 23, 2021
1c62378
Remove unnecessary case safeguards (CI: SCC-S1023, RVV-A0010)
daosvik Aug 26, 2021
caf83a0
Omit unnecessary break at end of case clause (CI: RVV-A0010)
daosvik Aug 26, 2021
4c61f84
Remove new shift function, use Lsh instead
daosvik Aug 26, 2021
63920a0
Use unsigned shift count
daosvik Aug 26, 2021
442ac08
Fix AddMod
daosvik Aug 26, 2021
5ef5e07
Replace unnecessary use of SubOverflow with Sub
daosvik Aug 26, 2021
7254745
create reciprocalCache type
holiman Aug 27, 2021
184a854
mod: modularize cache
holiman Aug 27, 2021
7fa8a78
Pass cache by reference
daosvik Aug 30, 2021
d22990c
Reduce overhead to a single pair of hit/miss counters for the recipro…
daosvik Aug 30, 2021
418bcc6
Add some more explicit returns
daosvik Aug 30, 2021
5fe32cc
Improve explanation of cache size parameters
daosvik Aug 30, 2021
5ff673d
gofmt benchmarks_test.go
daosvik Aug 30, 2021
0108e7f
Add MulMod tests with one operand a power of 2
daosvik Sep 2, 2021
890573b
Add MulMod tests with one operand a power of 2 plus/minus 1
daosvik Sep 2, 2021
ff7a115
test: Add AddMod test cases for unoptimized case with overflow
chfast Sep 2, 2021
5a55274
test: Add tests for leadingZeros()
chfast Sep 2, 2021
faefd57
Add tests with one operand being 2^256 minus a power of 2 (only one 0…
daosvik Sep 3, 2021
991905f
Disable the cache if configured to 0-way cache sets
daosvik Sep 3, 2021
27eb820
Add fixed modulus and precalculation of its reciprocal
daosvik Sep 3, 2021
0322ef0
tests: more ternary ops cases, more coverage
holiman Sep 6, 2021
90b4dd4
squashmelater: commit to trigger codecov
holiman Sep 6, 2021
5339bcb
mod: remove global cache
holiman Sep 8, 2021
a38198f
move reciprocal cache to separate file, un-export
holiman Sep 8, 2021
6e9bba4
make fixed modulus non-global
holiman Sep 8, 2021
58aab4a
lint fix
holiman Sep 8, 2021
6ee98f7
Remove automatic cache
daosvik Sep 20, 2021
6c954e8
Pass modulus and reciprocal by reference instead of value
daosvik Sep 20, 2021
3002c1b
Make reciprocal() specialized for m[3] != 0 (modulus >= 2^193)
daosvik Sep 20, 2021
7fdcd68
Add two corner case tests for reciprocal
daosvik Sep 20, 2021
74b3e8b
Remove unreachable safeguard code in reciprocal
daosvik Sep 20, 2021
54cdbb6
Merge branch 'holiman:master' into opt_modarith
daosvik Sep 20, 2021
15758be
Comment out unused onesCount
daosvik Sep 20, 2021
0c7b623
Make leadingZeros faster
daosvik Sep 21, 2021
154f050
Simplify detection of whether a modulus is a power of 2
daosvik Sep 28, 2021
b15b515
Speed up the end of reciprocal
daosvik Sep 28, 2021
0c7b52c
Add MulModWithReciprocal, export Reciprocal
daosvik Oct 1, 2021
17235df
Pass reciprocal as pointer parameter to MulModWithReciprocal
daosvik Oct 1, 2021
81c7df1
Remove unused func onesCount
daosvik Oct 22, 2021
a8c1be9
Add testing of MulModWithReciprocal
daosvik Oct 22, 2021
baf4cd6
Adjust comments and tests to reflect that Reciprocal now only support…
daosvik Oct 24, 2021
295482d
Also test MulModWithReciprocal on regular test cases
chfast Oct 24, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 52 additions & 32 deletions benchmarks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func initSamples() bool {
l := newRandInt(1)
g := newRandInt(1)
if g.Lt(&l) {
g,l = l,g
g, l = l, g
}
if g[0] == 0 {
g[0]++
Expand All @@ -77,7 +77,7 @@ func initSamples() bool {
l = newRandInt(2)
g = newRandInt(2)
if g.Lt(&l) {
g,l = l,g
g, l = l, g
}
if g[1] == 0 {
g[1]++
Expand All @@ -90,7 +90,7 @@ func initSamples() bool {
l = newRandInt(3)
g = newRandInt(3)
if g.Lt(&l) {
g,l = l,g
g, l = l, g
}
if g[2] == 0 {
g[2]++
Expand All @@ -103,7 +103,7 @@ func initSamples() bool {
l = newRandInt(4)
g = newRandInt(4)
if g.Lt(&l) {
g,l = l,g
g, l = l, g
}
if g[3] == 0 {
g[3]++
Expand Down Expand Up @@ -599,14 +599,14 @@ func BenchmarkDiv(b *testing.B) {
}

b.Run("small/uint256", func(b *testing.B) { benchmarkDivUint256(b, &int32Samples, &int32SamplesLt) })
b.Run("small/big", func(b *testing.B) { benchmarkDivBig(b, &big32Samples, &big32SamplesLt) })
b.Run("mod64/uint256", func(b *testing.B) { benchmarkDivUint256(b, &int256Samples, &int64Samples) })
b.Run("mod64/big", func(b *testing.B) { benchmarkDivBig(b, &big256Samples, &big64Samples) })
b.Run("mod128/uint256", func(b *testing.B) { benchmarkDivUint256(b, &int256Samples, &int128Samples) })
b.Run("mod128/big", func(b *testing.B) { benchmarkDivBig(b, &big256Samples, &big128Samples) })
b.Run("mod192/uint256", func(b *testing.B) { benchmarkDivUint256(b, &int256Samples, &int192Samples) })
b.Run("mod192/big", func(b *testing.B) { benchmarkDivBig(b, &big256Samples, &big192Samples) })
b.Run("mod256/uint256", func(b *testing.B) { benchmarkDivUint256(b, &int256Samples, &int256SamplesLt) })
b.Run("small/big", func(b *testing.B) { benchmarkDivBig(b, &big32Samples, &big32SamplesLt) })
b.Run("mod64/big", func(b *testing.B) { benchmarkDivBig(b, &big256Samples, &big64Samples) })
b.Run("mod128/big", func(b *testing.B) { benchmarkDivBig(b, &big256Samples, &big128Samples) })
b.Run("mod192/big", func(b *testing.B) { benchmarkDivBig(b, &big256Samples, &big192Samples) })
b.Run("mod256/big", func(b *testing.B) { benchmarkDivBig(b, &big256Samples, &big256SamplesLt) })
}

Expand All @@ -629,14 +629,14 @@ func BenchmarkMod(b *testing.B) {
}

b.Run("small/uint256", func(b *testing.B) { benchmarkModUint256(b, &int32Samples, &int32SamplesLt) })
b.Run("small/big", func(b *testing.B) { benchmarkModBig(b, &big32Samples, &big32SamplesLt) })
b.Run("mod64/uint256", func(b *testing.B) { benchmarkModUint256(b, &int256Samples, &int64Samples) })
b.Run("mod64/big", func(b *testing.B) { benchmarkModBig(b, &big256Samples, &big64Samples) })
b.Run("mod128/uint256", func(b *testing.B) { benchmarkModUint256(b, &int256Samples, &int128Samples) })
b.Run("mod128/big", func(b *testing.B) { benchmarkModBig(b, &big256Samples, &big128Samples) })
b.Run("mod192/uint256", func(b *testing.B) { benchmarkModUint256(b, &int256Samples, &int192Samples) })
b.Run("mod192/big", func(b *testing.B) { benchmarkModBig(b, &big256Samples, &big192Samples) })
b.Run("mod256/uint256", func(b *testing.B) { benchmarkModUint256(b, &int256Samples, &int256SamplesLt) })
b.Run("small/big", func(b *testing.B) { benchmarkModBig(b, &big32Samples, &big32SamplesLt) })
b.Run("mod64/big", func(b *testing.B) { benchmarkModBig(b, &big256Samples, &big64Samples) })
b.Run("mod128/big", func(b *testing.B) { benchmarkModBig(b, &big256Samples, &big128Samples) })
b.Run("mod192/big", func(b *testing.B) { benchmarkModBig(b, &big256Samples, &big192Samples) })
b.Run("mod256/big", func(b *testing.B) { benchmarkModBig(b, &big256Samples, &big256SamplesLt) })
}

Expand Down Expand Up @@ -667,19 +667,38 @@ func BenchmarkAddMod(b *testing.B) {
}
}

b.Run("small/uint256", func(b *testing.B) { benchmarkAddModUint256 (b, &int32SamplesLt, &int32Samples) })
b.Run("small/big", func(b *testing.B) { benchmarkAddModBig (b, &big32SamplesLt, &big32Samples) })
b.Run("mod64/uint256", func(b *testing.B) { benchmarkAddModUint256 (b, &int64SamplesLt, &int64Samples) })
b.Run("mod64/big", func(b *testing.B) { benchmarkAddModBig (b, &big64SamplesLt, &big64Samples) })
b.Run("mod128/uint256", func(b *testing.B) { benchmarkAddModUint256 (b, &int128SamplesLt, &int128Samples) })
b.Run("mod128/big", func(b *testing.B) { benchmarkAddModBig (b, &big128SamplesLt, &big128Samples) })
b.Run("mod192/uint256", func(b *testing.B) { benchmarkAddModUint256 (b, &int192SamplesLt, &int192Samples) })
b.Run("mod192/big", func(b *testing.B) { benchmarkAddModBig (b, &big192SamplesLt, &big192Samples) })
b.Run("mod256/uint256", func(b *testing.B) { benchmarkAddModUint256 (b, &int256SamplesLt, &int256Samples) })
b.Run("mod256/big", func(b *testing.B) { benchmarkAddModBig (b, &big256SamplesLt, &big256Samples) })
b.Run("small/uint256", func(b *testing.B) { benchmarkAddModUint256(b, &int32SamplesLt, &int32Samples) })
b.Run("mod64/uint256", func(b *testing.B) { benchmarkAddModUint256(b, &int64SamplesLt, &int64Samples) })
b.Run("mod128/uint256", func(b *testing.B) { benchmarkAddModUint256(b, &int128SamplesLt, &int128Samples) })
b.Run("mod192/uint256", func(b *testing.B) { benchmarkAddModUint256(b, &int192SamplesLt, &int192Samples) })
b.Run("mod256/uint256", func(b *testing.B) { benchmarkAddModUint256(b, &int256SamplesLt, &int256Samples) })
b.Run("small/big", func(b *testing.B) { benchmarkAddModBig(b, &big32SamplesLt, &big32Samples) })
b.Run("mod64/big", func(b *testing.B) { benchmarkAddModBig(b, &big64SamplesLt, &big64Samples) })
b.Run("mod128/big", func(b *testing.B) { benchmarkAddModBig(b, &big128SamplesLt, &big128Samples) })
b.Run("mod192/big", func(b *testing.B) { benchmarkAddModBig(b, &big192SamplesLt, &big192Samples) })
b.Run("mod256/big", func(b *testing.B) { benchmarkAddModBig(b, &big256SamplesLt, &big256Samples) })
}

func BenchmarkMulMod(b *testing.B) {
benchmarkMulModUint256R := func(b *testing.B, factorsSamples, modSamples *[numSamples]Int) {
iter := (b.N + numSamples - 1) / numSamples

var mu [numSamples][5]uint64

for i := 0; i < numSamples; i++ {
mu[i] = Reciprocal(&modSamples[i])
}

b.ResetTimer()

for j := 0; j < numSamples; j++ {
x := factorsSamples[j]

for i := 0; i < iter; i++ {
x.MulModWithReciprocal(&x, &factorsSamples[j], &modSamples[j], &mu[j])
}
}
}
benchmarkMulModUint256 := func(b *testing.B, factorsSamples, modSamples *[numSamples]Int) {
iter := (b.N + numSamples - 1) / numSamples

Expand All @@ -704,16 +723,17 @@ func BenchmarkMulMod(b *testing.B) {
}
}

b.Run("small/uint256", func(b *testing.B) { benchmarkMulModUint256 (b, &int32SamplesLt, &int32Samples) })
b.Run("small/big", func(b *testing.B) { benchmarkMulModBig (b, &big32SamplesLt, &big32Samples) })
b.Run("mod64/uint256", func(b *testing.B) { benchmarkMulModUint256 (b, &int64SamplesLt, &int64Samples) })
b.Run("mod64/big", func(b *testing.B) { benchmarkMulModBig (b, &big64SamplesLt, &big64Samples) })
b.Run("mod128/uint256", func(b *testing.B) { benchmarkMulModUint256 (b, &int128SamplesLt, &int128Samples) })
b.Run("mod128/big", func(b *testing.B) { benchmarkMulModBig (b, &big128SamplesLt, &big128Samples) })
b.Run("mod192/uint256", func(b *testing.B) { benchmarkMulModUint256 (b, &int192SamplesLt, &int192Samples) })
b.Run("mod192/big", func(b *testing.B) { benchmarkMulModBig (b, &big192SamplesLt, &big192Samples) })
b.Run("mod256/uint256", func(b *testing.B) { benchmarkMulModUint256 (b, &int256SamplesLt, &int256Samples) })
b.Run("mod256/big", func(b *testing.B) { benchmarkMulModBig (b, &big256SamplesLt, &big256Samples) })
b.Run("small/uint256", func(b *testing.B) { benchmarkMulModUint256(b, &int32SamplesLt, &int32Samples) })
b.Run("mod64/uint256", func(b *testing.B) { benchmarkMulModUint256(b, &int64SamplesLt, &int64Samples) })
b.Run("mod128/uint256", func(b *testing.B) { benchmarkMulModUint256(b, &int128SamplesLt, &int128Samples) })
b.Run("mod192/uint256", func(b *testing.B) { benchmarkMulModUint256(b, &int192SamplesLt, &int192Samples) })
b.Run("mod256/uint256", func(b *testing.B) { benchmarkMulModUint256(b, &int256SamplesLt, &int256Samples) })
b.Run("mod256/uint256r", func(b *testing.B) { benchmarkMulModUint256R(b, &int256SamplesLt, &int256Samples) })
b.Run("small/big", func(b *testing.B) { benchmarkMulModBig(b, &big32SamplesLt, &big32Samples) })
b.Run("mod64/big", func(b *testing.B) { benchmarkMulModBig(b, &big64SamplesLt, &big64Samples) })
b.Run("mod128/big", func(b *testing.B) { benchmarkMulModBig(b, &big128SamplesLt, &big128Samples) })
b.Run("mod192/big", func(b *testing.B) { benchmarkMulModBig(b, &big192SamplesLt, &big192Samples) })
b.Run("mod256/big", func(b *testing.B) { benchmarkMulModBig(b, &big256SamplesLt, &big256Samples) })
}

func benchmark_SdivLarge_Big(bench *testing.B) {
Expand Down
Loading