From d9654671d42d200e1e87fad27c1ad008bd14b0ee Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Jun 2026 03:31:18 -0500 Subject: [PATCH 01/11] secp256k1: Rename big int mod p benchmarks. This renames the various benchmarks for big ints mod P to be consistent with the big int mod N benchmarks. --- dcrec/secp256k1/field_bench_test.go | 43 ++++++++++++----------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index eb9e684b15..b320c86e2c 100644 --- a/dcrec/secp256k1/field_bench_test.go +++ b/dcrec/secp256k1/field_bench_test.go @@ -40,19 +40,16 @@ func BenchmarkFieldSqrt(b *testing.B) { } } -// BenchmarkBigSqrt benchmarks calculating the square root of an unsigned +// BenchmarkBigIntSqrtModP benchmarks calculating the square root of an unsigned // 256-bit big-endian integer modulo the field prime with stdlib big integers. -func BenchmarkBigSqrt(b *testing.B) { - valHex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" - val, ok := new(big.Int).SetString(valHex, 16) - if !ok { - b.Fatalf("failed to parse hex %s", valHex) - } +func BenchmarkBigIntSqrtModP(b *testing.B) { + v1Hex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + v1 := fromHex(v1Hex) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - _ = new(big.Int).ModSqrt(val, curveParams.P) + _ = new(big.Int).ModSqrt(v1, curveParams.P) } } @@ -70,20 +67,17 @@ func BenchmarkFieldInverse(b *testing.B) { } } -// BenchmarkBigInverse benchmarks calculating the multiplicative inverse of an -// unsigned 256-bit big-endian integer modulo the field prime with stdlib big -// integers. -func BenchmarkBigInverse(b *testing.B) { - valHex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" - val, ok := new(big.Int).SetString(valHex, 16) - if !ok { - b.Fatalf("failed to parse hex %s", valHex) - } +// BenchmarkBigIntInverseModP benchmarks calculating the multiplicative inverse +// of an unsigned 256-bit big-endian integer modulo the field prime with stdlib +// big integers. +func BenchmarkBigIntInverseModP(b *testing.B) { + v1Hex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + v1 := fromHex(v1Hex) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - _ = new(big.Int).ModInverse(val, curveParams.P) + _ = new(big.Int).ModInverse(v1, curveParams.P) } } @@ -102,16 +96,13 @@ func BenchmarkFieldIsGtOrEqPrimeMinusOrder(b *testing.B) { } } -// BenchmarkBigIsGtOrEqPrimeMinusOrder benchmarks determining whether a value +// BenchmarkBigIntIsGtOrEqPrimeMinusOrder benchmarks determining whether a value // is greater than or equal to the field prime minus the group order with stdlib // big integers. -func BenchmarkBigIsGtOrEqPrimeMinusOrder(b *testing.B) { +func BenchmarkBigIntIsGtOrEqPrimeMinusOrder(b *testing.B) { // Same value used in field val version. - valHex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" - val, ok := new(big.Int).SetString(valHex, 16) - if !ok { - b.Fatalf("failed to parse hex %s", valHex) - } + v1Hex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + v1 := fromHex(v1Hex) bigPMinusN := new(big.Int).Sub(curveParams.P, curveParams.N) b.ReportAllocs() @@ -120,6 +111,6 @@ func BenchmarkBigIsGtOrEqPrimeMinusOrder(b *testing.B) { // In practice, the internal value to compare would have to be converted // to a big integer from bytes, so it's a fair comparison to allocate a // new big int here and set all bytes. - _ = new(big.Int).SetBytes(val.Bytes()).Cmp(bigPMinusN) >= 0 + _ = new(big.Int).SetBytes(v1.Bytes()).Cmp(bigPMinusN) >= 0 } } From 3080a90e7626f5dd6ffd515b14314ea1d7d6bc58 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Jun 2026 03:44:30 -0500 Subject: [PATCH 02/11] secp256k1: Reorder big int mod p benchmarks. This moves the big int mod p benchmarks before their respective field benchmarks for consistency with the big int mod n code. --- dcrec/secp256k1/field_bench_test.go | 46 ++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index b320c86e2c..b11f02adca 100644 --- a/dcrec/secp256k1/field_bench_test.go +++ b/dcrec/secp256k1/field_bench_test.go @@ -25,21 +25,6 @@ func BenchmarkFieldNormalize(b *testing.B) { } } -// BenchmarkFieldSqrt benchmarks calculating the square root of an unsigned -// 256-bit big-endian integer modulo the field prime with the specialized type. -func BenchmarkFieldSqrt(b *testing.B) { - // The function is constant time so any value is fine. - valHex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" - f := new(FieldVal).SetHex(valHex).Normalize() - - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - var result FieldVal - _ = result.SquareRootVal(f) - } -} - // BenchmarkBigIntSqrtModP benchmarks calculating the square root of an unsigned // 256-bit big-endian integer modulo the field prime with stdlib big integers. func BenchmarkBigIntSqrtModP(b *testing.B) { @@ -53,9 +38,9 @@ func BenchmarkBigIntSqrtModP(b *testing.B) { } } -// BenchmarkFieldInverse calculating the multiplicative inverse of an unsigned +// BenchmarkFieldSqrt benchmarks calculating the square root of an unsigned // 256-bit big-endian integer modulo the field prime with the specialized type. -func BenchmarkFieldInverse(b *testing.B) { +func BenchmarkFieldSqrt(b *testing.B) { // The function is constant time so any value is fine. valHex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" f := new(FieldVal).SetHex(valHex).Normalize() @@ -63,7 +48,8 @@ func BenchmarkFieldInverse(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - f.Inverse() + var result FieldVal + _ = result.SquareRootVal(f) } } @@ -81,10 +67,9 @@ func BenchmarkBigIntInverseModP(b *testing.B) { } } -// BenchmarkFieldIsGtOrEqPrimeMinusOrder benchmarks determining whether a value -// is greater than or equal to the field prime minus the group order with the -// specialized type. -func BenchmarkFieldIsGtOrEqPrimeMinusOrder(b *testing.B) { +// BenchmarkFieldInverse calculating the multiplicative inverse of an unsigned +// 256-bit big-endian integer modulo the field prime with the specialized type. +func BenchmarkFieldInverse(b *testing.B) { // The function is constant time so any value is fine. valHex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" f := new(FieldVal).SetHex(valHex).Normalize() @@ -92,7 +77,7 @@ func BenchmarkFieldIsGtOrEqPrimeMinusOrder(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - _ = f.IsGtOrEqPrimeMinusOrder() + f.Inverse() } } @@ -114,3 +99,18 @@ func BenchmarkBigIntIsGtOrEqPrimeMinusOrder(b *testing.B) { _ = new(big.Int).SetBytes(v1.Bytes()).Cmp(bigPMinusN) >= 0 } } + +// BenchmarkFieldIsGtOrEqPrimeMinusOrder benchmarks determining whether a value +// is greater than or equal to the field prime minus the group order with the +// specialized type. +func BenchmarkFieldIsGtOrEqPrimeMinusOrder(b *testing.B) { + // The function is constant time so any value is fine. + valHex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + f := new(FieldVal).SetHex(valHex).Normalize() + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = f.IsGtOrEqPrimeMinusOrder() + } +} From eb6311192863cef8f19d841228e87789e891c84f Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Jun 2026 03:23:50 -0500 Subject: [PATCH 03/11] secp256k1: Add big int negate mod p benchmark. --- dcrec/secp256k1/field_bench_test.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index b11f02adca..0b38900c1c 100644 --- a/dcrec/secp256k1/field_bench_test.go +++ b/dcrec/secp256k1/field_bench_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2024 The Decred developers +// Copyright (c) 2020-2026 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -25,6 +25,22 @@ func BenchmarkFieldNormalize(b *testing.B) { } } +// BenchmarkBigIntNegateModP benchmarks calculating the additive inverse of an +// unsigned 256-bit big-endian integer modulo the field prime with stdlib big +// integers. +func BenchmarkBigIntNegateModP(b *testing.B) { + v1Hex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + v1 := fromHex(v1Hex) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + result := new(big.Int).Neg(v1) + result.Mod(result, curveParams.P) + + } +} + // BenchmarkBigIntSqrtModP benchmarks calculating the square root of an unsigned // 256-bit big-endian integer modulo the field prime with stdlib big integers. func BenchmarkBigIntSqrtModP(b *testing.B) { From 6068b8ea60def80513e0154f311606450e4da028 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Jun 2026 03:24:37 -0500 Subject: [PATCH 04/11] secp256k1: Add field negate benchmark. --- dcrec/secp256k1/field_bench_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index 0b38900c1c..1d0dbf542d 100644 --- a/dcrec/secp256k1/field_bench_test.go +++ b/dcrec/secp256k1/field_bench_test.go @@ -41,6 +41,21 @@ func BenchmarkBigIntNegateModP(b *testing.B) { } } +// BenchmarkFieldNegate benchmarks calculating the additive inverse of an +// unsigned 256-bit big-endian integer modulo the field prime with [FieldVal]. +func BenchmarkFieldNegate(b *testing.B) { + // The function is constant time so any value is fine. + valHex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + f := new(FieldVal).SetHex(valHex) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var result FieldVal + _ = result.NegateVal(f, 1) + } +} + // BenchmarkBigIntSqrtModP benchmarks calculating the square root of an unsigned // 256-bit big-endian integer modulo the field prime with stdlib big integers. func BenchmarkBigIntSqrtModP(b *testing.B) { From bc7eb91437b8e07092e08849dda93f139b3c2bad Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Jun 2026 03:35:46 -0500 Subject: [PATCH 05/11] secp256k1: Add big int add mod p benchmark. --- dcrec/secp256k1/field_bench_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index 1d0dbf542d..234b44c73d 100644 --- a/dcrec/secp256k1/field_bench_test.go +++ b/dcrec/secp256k1/field_bench_test.go @@ -56,6 +56,22 @@ func BenchmarkFieldNegate(b *testing.B) { } } +// BenchmarkBigIntAddModP benchmarks adding two unsigned 256-bit big-endian +// integers modulo the field prime with stdlib big integers. +func BenchmarkBigIntAddModP(b *testing.B) { + v1Hex := "d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab" + v2Hex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + v1 := fromHex(v1Hex) + v2 := fromHex(v2Hex) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + result := new(big.Int).Add(v1, v2) + result.Mod(result, curveParams.N) + } +} + // BenchmarkBigIntSqrtModP benchmarks calculating the square root of an unsigned // 256-bit big-endian integer modulo the field prime with stdlib big integers. func BenchmarkBigIntSqrtModP(b *testing.B) { From a80d60ca6067eb9b5eff293579570c285fabed74 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Jun 2026 03:37:14 -0500 Subject: [PATCH 06/11] secp256k1: Add field add benchmark. --- dcrec/secp256k1/field_bench_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index 234b44c73d..7c31e90070 100644 --- a/dcrec/secp256k1/field_bench_test.go +++ b/dcrec/secp256k1/field_bench_test.go @@ -72,6 +72,23 @@ func BenchmarkBigIntAddModP(b *testing.B) { } } +// BenchmarkFieldAdd benchmarks adding two unsigned 256-bit big-endian integers +// modulo the field prime with [FieldVal]. +func BenchmarkFieldAdd(b *testing.B) { + // The function is constant time so any values are fine. + f1Hex := "d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab" + f2Hex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + f1 := new(FieldVal).SetHex(f1Hex) + f2 := new(FieldVal).SetHex(f2Hex) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var sum FieldVal + sum.Add2(f1, f2) + } +} + // BenchmarkBigIntSqrtModP benchmarks calculating the square root of an unsigned // 256-bit big-endian integer modulo the field prime with stdlib big integers. func BenchmarkBigIntSqrtModP(b *testing.B) { From fb1dd6fbdd3443728c2c53db7be976d749c05888 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Jun 2026 03:39:02 -0500 Subject: [PATCH 07/11] secp256k1: Add big int multiply mod p benchmark. --- dcrec/secp256k1/field_bench_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index 7c31e90070..3118ed9a91 100644 --- a/dcrec/secp256k1/field_bench_test.go +++ b/dcrec/secp256k1/field_bench_test.go @@ -89,6 +89,22 @@ func BenchmarkFieldAdd(b *testing.B) { } } +// BenchmarkBigIntMulModP benchmarks multiplying two unsigned 256-bit big-endian +// integers modulo the field prime with stdlib big integers. +func BenchmarkBigIntMulModP(b *testing.B) { + v1Hex := "d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab" + v2Hex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + v1 := fromHex(v1Hex) + v2 := fromHex(v2Hex) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + result := new(big.Int).Mul(v1, v2) + result.Mod(result, curveParams.P) + } +} + // BenchmarkBigIntSqrtModP benchmarks calculating the square root of an unsigned // 256-bit big-endian integer modulo the field prime with stdlib big integers. func BenchmarkBigIntSqrtModP(b *testing.B) { From 305dba71092198c697320c2d26fc2690f4c70572 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Jun 2026 03:39:31 -0500 Subject: [PATCH 08/11] secp256k1: Add field mul benchmark. --- dcrec/secp256k1/field_bench_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index 3118ed9a91..63e9838190 100644 --- a/dcrec/secp256k1/field_bench_test.go +++ b/dcrec/secp256k1/field_bench_test.go @@ -105,6 +105,23 @@ func BenchmarkBigIntMulModP(b *testing.B) { } } +// BenchmarkFieldMul benchmarks multiplying two unsigned 256-bit big-endian +// integers modulo the field prime with [FieldVal]. +func BenchmarkFieldMul(b *testing.B) { + // The function is constant time so any values are fine. + f1Hex := "d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab" + f2Hex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + f1 := new(FieldVal).SetHex(f1Hex) + f2 := new(FieldVal).SetHex(f2Hex) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var prod FieldVal + prod.Mul2(f1, f2) + } +} + // BenchmarkBigIntSqrtModP benchmarks calculating the square root of an unsigned // 256-bit big-endian integer modulo the field prime with stdlib big integers. func BenchmarkBigIntSqrtModP(b *testing.B) { From aa3fe9ad959a8060e8f00ddf0d46b37d4a904e54 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Jun 2026 03:51:28 -0500 Subject: [PATCH 09/11] secp256k1: Add big int square mod p benchmark. --- dcrec/secp256k1/field_bench_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index 63e9838190..fb8ebb97e2 100644 --- a/dcrec/secp256k1/field_bench_test.go +++ b/dcrec/secp256k1/field_bench_test.go @@ -150,6 +150,20 @@ func BenchmarkFieldSqrt(b *testing.B) { } } +// BenchmarkBigIntSquareModP benchmarks squaring an unsigned 256-bit big-endian +// integer modulo the field prime with stdlib big integers. +func BenchmarkBigIntSquareModP(b *testing.B) { + v1Hex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + v1 := fromHex(v1Hex) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + result := new(big.Int).Mul(v1, v1) + result.Mod(result, curveParams.P) + } +} + // BenchmarkBigIntInverseModP benchmarks calculating the multiplicative inverse // of an unsigned 256-bit big-endian integer modulo the field prime with stdlib // big integers. From 5e33d9f3315507893f4d47fa4cced02179d0aaaa Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Jun 2026 03:52:05 -0500 Subject: [PATCH 10/11] secp256k1: Add field square benchmark. --- dcrec/secp256k1/field_bench_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index fb8ebb97e2..d899faf41d 100644 --- a/dcrec/secp256k1/field_bench_test.go +++ b/dcrec/secp256k1/field_bench_test.go @@ -164,6 +164,21 @@ func BenchmarkBigIntSquareModP(b *testing.B) { } } +// BenchmarkFieldSquare benchmarks squaring a 256-bit big-endian integer modulo +// the field prime with [FieldVal]. +func BenchmarkFieldSquare(b *testing.B) { + // The function is constant time so any values are fine. + fHex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + f := new(FieldVal).SetHex(fHex) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var sq FieldVal + sq.SquareVal(f) + } +} + // BenchmarkBigIntInverseModP benchmarks calculating the multiplicative inverse // of an unsigned 256-bit big-endian integer modulo the field prime with stdlib // big integers. From 2a6defda43e24ed4798031558e1a502cc30f508b Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 23 Jun 2026 07:16:48 -0500 Subject: [PATCH 11/11] secp256k1: Consistent type refs in field benches. --- dcrec/secp256k1/field_bench_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index d899faf41d..f89c420b72 100644 --- a/dcrec/secp256k1/field_bench_test.go +++ b/dcrec/secp256k1/field_bench_test.go @@ -136,7 +136,7 @@ func BenchmarkBigIntSqrtModP(b *testing.B) { } // BenchmarkFieldSqrt benchmarks calculating the square root of an unsigned -// 256-bit big-endian integer modulo the field prime with the specialized type. +// 256-bit big-endian integer modulo the field prime with [FieldVal]. func BenchmarkFieldSqrt(b *testing.B) { // The function is constant time so any value is fine. valHex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" @@ -194,7 +194,7 @@ func BenchmarkBigIntInverseModP(b *testing.B) { } // BenchmarkFieldInverse calculating the multiplicative inverse of an unsigned -// 256-bit big-endian integer modulo the field prime with the specialized type. +// 256-bit big-endian integer modulo the field prime with [FieldVal]. func BenchmarkFieldInverse(b *testing.B) { // The function is constant time so any value is fine. valHex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca"