diff --git a/dcrec/secp256k1/field_bench_test.go b/dcrec/secp256k1/field_bench_test.go index eb9e684b15..f89c420b72 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,40 +25,119 @@ 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) { +// 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) + + } +} + +// 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).Normalize() + f := new(FieldVal).SetHex(valHex) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { var result FieldVal - _ = result.SquareRootVal(f) + _ = result.NegateVal(f, 1) } } -// BenchmarkBigSqrt 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) +// 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) } +} + +// 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++ { - _ = new(big.Int).ModSqrt(val, curveParams.P) + var sum FieldVal + sum.Add2(f1, f2) } } -// 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) { +// 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) + } +} + +// 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) { + v1Hex := "16fb970147a9acc73654d4be233cc48b875ce20a2122d24f073d29bd28805aca" + v1 := fromHex(v1Hex) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = new(big.Int).ModSqrt(v1, curveParams.P) + } +} + +// BenchmarkFieldSqrt benchmarks calculating the square root of an unsigned +// 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" f := new(FieldVal).SetHex(valHex).Normalize() @@ -66,31 +145,57 @@ func BenchmarkFieldInverse(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - f.Inverse() + var result FieldVal + _ = result.SquareRootVal(f) } } -// 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) +// 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) } +} + +// 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++ { - _ = new(big.Int).ModInverse(val, curveParams.P) + var sq FieldVal + sq.SquareVal(f) } } -// 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) { +// 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(v1, curveParams.P) + } +} + +// BenchmarkFieldInverse calculating the multiplicative inverse of an unsigned +// 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" f := new(FieldVal).SetHex(valHex).Normalize() @@ -98,20 +203,17 @@ func BenchmarkFieldIsGtOrEqPrimeMinusOrder(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - _ = f.IsGtOrEqPrimeMinusOrder() + f.Inverse() } } -// 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 +222,21 @@ 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 + } +} + +// 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() } }