From 1926d1d95d32af30f0b70d35c5c439c9a2d31378 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 20 May 2026 11:51:35 -0700 Subject: [PATCH 01/18] cmd/compile: clarify relativity of a simple file name in a line directive Per comment on (now abandoned) CL 780104. Change-Id: Ic9ccfdbb6d3755c2f0589fbe5bffab096a8c508e Reviewed-on: https://go-review.googlesource.com/c/go/+/780106 Reviewed-by: Robert Griesemer TryBot-Bypass: Robert Griesemer Reviewed-by: Alan Donovan Auto-Submit: Robert Griesemer Reviewed-by: Michael Podtserkovskii --- src/cmd/compile/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/doc.go b/src/cmd/compile/doc.go index 502f658e985fca..dee509218965f8 100644 --- a/src/cmd/compile/doc.go +++ b/src/cmd/compile/doc.go @@ -205,7 +205,7 @@ all other compiler directives are of the form // // Examples: // -// //line foo.go:10 the filename is foo.go, and the line number is 10 for the next line +// //line foo.go:10 the (relative) filename is foo.go, and the line number is 10 for the next line // //line ../foo.go:10 relative filenames are resolved against the directive's source directory // //line C:foo.go:10 colons are permitted in filenames, here the filename is C:foo.go, and the line is 10 // //line a:100 :10 blanks are permitted in filenames, here the filename is " a:100 " (excluding quotes) From a00bbab762905527684cf59b9db7a8532cae0929 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Tue, 24 Mar 2026 22:43:50 -0700 Subject: [PATCH 02/18] crypto/internal/fips140/edwards25519/field: speed up add chains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Repeated squaring forms the bulk of these add chains. Doing it in a dedicated routine with local variables is faster. Introduce SquareN for this, and switch to an add chain geared towards maximizing runs of repeated squares. Unrolling the SquareN loop 5x gains a few percentage points more; this could be done as desired in a follow-up. A planned follow-up will use this newfound speed to delete amd64 asm. Microbenchmarks: goos: darwin goarch: arm64 pkg: crypto/internal/fips140/edwards25519 cpu: Apple M3 Max │ a │ b │ │ sec/op │ sec/op vs base │ EncodingDecoding-16 5.842µ ± 0% 4.703µ ± 0% -19.51% (n=100) ScalarBaseMult-16 9.157µ ± 0% 9.178µ ± 0% +0.23% (p=0.000 n=100) ScalarMult-16 29.28µ ± 0% 29.25µ ± 0% -0.09% (n=100) VarTimeDoubleScalarBaseMult-16 27.46µ ± 0% 27.46µ ± 0% -0.02% (p=0.002 n=100) geomean 14.40µ 13.64µ -5.25% pkg: crypto/internal/fips140/edwards25519/field │ a │ b │ │ sec/op │ sec/op vs base │ Add-16 3.364n ± 0% 3.350n ± 0% -0.43% (p=0.000 n=100) Multiply-16 14.15n ± 0% 14.15n ± 0% 0.00% (p=0.000 n=100) Square-16 10.32n ± 0% 10.25n ± 0% -0.68% (n=100) Invert-16 2.734µ ± 0% 2.331µ ± 0% -14.74% (n=100) Mult32-16 5.067n ± 0% 4.926n ± 0% -2.78% (n=100) Bytes-16 4.595n ± 0% 4.580n ± 0% ~ (p=0.052 n=100) geomean 17.75n 17.16n -3.31% Macrobenchmarks: goos: darwin goarch: arm64 pkg: crypto/ed25519 cpu: Apple M3 Max │ before │ after │ │ sec/op │ sec/op vs base │ KeyGeneration-16 13.84µ ± 2% 12.92µ ± 1% -6.65% (p=0.000 n=30) NewKeyFromSeed-16 13.60µ ± 3% 12.91µ ± 1% -5.09% (p=0.000 n=30) Signing-16 16.14µ ± 3% 15.75µ ± 1% -2.45% (p=0.000 n=30) Verification-16 35.47µ ± 2% 34.84µ ± 0% -1.79% (p=0.001 n=30) geomean 18.12µ 17.39µ -4.02% Change-Id: I30d09b8d15fa9d1d64863a21d26c1c9ce4d8e9cc Reviewed-on: https://go-review.googlesource.com/c/go/+/760760 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: David Chase Reviewed-by: Filippo Valsorda Reviewed-by: Dmitri Shuralyov --- .../internal/fips140/edwards25519/field/fe.go | 161 +++++++----------- .../edwards25519/field/fe_alias_test.go | 6 + .../edwards25519/field/fe_amd64_noasm.go | 2 + .../fips140/edwards25519/field/fe_generic.go | 56 ++++++ .../edwards25519/field/fe_squaren_amd64.go | 14 ++ .../fips140/edwards25519/field/fe_test.go | 50 ++++++ 6 files changed, 192 insertions(+), 97 deletions(-) create mode 100644 src/crypto/internal/fips140/edwards25519/field/fe_squaren_amd64.go diff --git a/src/crypto/internal/fips140/edwards25519/field/fe.go b/src/crypto/internal/fips140/edwards25519/field/fe.go index 5c5c22c637378c..45ec5c8dd4c4a2 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe.go +++ b/src/crypto/internal/fips140/edwards25519/field/fe.go @@ -115,65 +115,40 @@ func (v *Element) Negate(a *Element) *Element { // // If z == 0, Invert returns v = 0. func (v *Element) Invert(z *Element) *Element { - // Inversion is implemented as exponentiation with exponent p − 2. It uses the - // same sequence of 254 squarings and 11 multiplications as [Curve25519]. - var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element - - z2.Square(z) // 2 - t.Square(&z2) // 4 - t.Square(&t) // 8 - z9.Multiply(&t, z) // 9 - z11.Multiply(&z9, &z2) // 11 - t.Square(&z11) // 22 - z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0 - - t.Square(&z2_5_0) // 2^6 - 2^1 - for i := 0; i < 4; i++ { - t.Square(&t) // 2^10 - 2^5 - } - z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0 + // Inversion is implemented as exponentiation with exponent p − 2. + // It uses 254 squarings and 11 multiplications, grouping squarings to use SquareN. + var z11, t0, t1, t2, t Element - t.Square(&z2_10_0) // 2^11 - 2^1 - for i := 0; i < 9; i++ { - t.Square(&t) // 2^20 - 2^10 - } - z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0 + t1.Square(z) // 2 + t.Square(&t1) // 4 + t.Square(&t) // 8 + t2.Multiply(&t, z) // 9 + z11.Multiply(&t2, &t1) // 11 + t.Square(&z11) // 22 + t0.Multiply(&t, &t2) // 31 = 2^5 - 2^0 - t.Square(&z2_20_0) // 2^21 - 2^1 - for i := 0; i < 19; i++ { - t.Square(&t) // 2^40 - 2^20 - } - t.Multiply(&t, &z2_20_0) // 2^40 - 2^0 + t.SquareN(&t0, 5) // 2^10 - 2^5 + t2.Multiply(&t, &t0) // 2^10 - 1 - t.Square(&t) // 2^41 - 2^1 - for i := 0; i < 9; i++ { - t.Square(&t) // 2^50 - 2^10 - } - z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0 + t.SquareN(&t2, 5) // 2^15 - 2^5 + t0.Multiply(&t, &t0) // 2^15 - 1 - t.Square(&z2_50_0) // 2^51 - 2^1 - for i := 0; i < 49; i++ { - t.Square(&t) // 2^100 - 2^50 - } - z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0 + t.SquareN(&t0, 15) // 2^30 - 2^15 + t1.Multiply(&t, &t0) // 2^30 - 1 - t.Square(&z2_100_0) // 2^101 - 2^1 - for i := 0; i < 99; i++ { - t.Square(&t) // 2^200 - 2^100 - } - t.Multiply(&t, &z2_100_0) // 2^200 - 2^0 + t.SquareN(&t1, 30) // 2^60 - 2^30 + t0.Multiply(&t, &t1) // 2^60 - 1 - t.Square(&t) // 2^201 - 2^1 - for i := 0; i < 49; i++ { - t.Square(&t) // 2^250 - 2^50 - } - t.Multiply(&t, &z2_50_0) // 2^250 - 2^0 + t.SquareN(&t0, 60) // 2^120 - 2^60 + t1.Multiply(&t, &t0) // 2^120 - 1 - t.Square(&t) // 2^251 - 2^1 - t.Square(&t) // 2^252 - 2^2 - t.Square(&t) // 2^253 - 2^3 - t.Square(&t) // 2^254 - 2^4 - t.Square(&t) // 2^255 - 2^5 + t.SquareN(&t1, 120) // 2^240 - 2^120 + t.Multiply(&t, &t1) // 2^240 - 1 + + t.SquareN(&t, 10) // 2^250 - 2^10 + t.Multiply(&t, &t2) // 2^250 - 1 + + t.SquareN(&t, 5) // 2^255 - 2^5 return v.Multiply(&t, &z11) // 2^255 - 21 } @@ -311,6 +286,12 @@ func (v *Element) Square(x *Element) *Element { return v } +// SquareN sets v = x^(2^n), and returns v. n must be positive. +func (v *Element) SquareN(x *Element, n int) *Element { + feSquareN(v, x, n) + return v +} + // Mult32 sets v = x * y, and returns v. func (v *Element) Mult32(x *Element, y uint32) *Element { x0lo, x0hi := mul51(x.l0, y) @@ -340,51 +321,37 @@ func mul51(a uint64, b uint32) (lo uint64, hi uint64) { func (v *Element) Pow22523(x *Element) *Element { var t0, t1, t2 Element - t0.Square(x) // x^2 - t1.Square(&t0) // x^4 - t1.Square(&t1) // x^8 - t1.Multiply(x, &t1) // x^9 - t0.Multiply(&t0, &t1) // x^11 - t0.Square(&t0) // x^22 - t0.Multiply(&t1, &t0) // x^31 - t1.Square(&t0) // x^62 - for i := 1; i < 5; i++ { // x^992 - t1.Square(&t1) - } - t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1 - t1.Square(&t0) // 2^11 - 2 - for i := 1; i < 10; i++ { // 2^20 - 2^10 - t1.Square(&t1) - } - t1.Multiply(&t1, &t0) // 2^20 - 1 - t2.Square(&t1) // 2^21 - 2 - for i := 1; i < 20; i++ { // 2^40 - 2^20 - t2.Square(&t2) - } - t1.Multiply(&t2, &t1) // 2^40 - 1 - t1.Square(&t1) // 2^41 - 2 - for i := 1; i < 10; i++ { // 2^50 - 2^10 - t1.Square(&t1) - } - t0.Multiply(&t1, &t0) // 2^50 - 1 - t1.Square(&t0) // 2^51 - 2 - for i := 1; i < 50; i++ { // 2^100 - 2^50 - t1.Square(&t1) - } - t1.Multiply(&t1, &t0) // 2^100 - 1 - t2.Square(&t1) // 2^101 - 2 - for i := 1; i < 100; i++ { // 2^200 - 2^100 - t2.Square(&t2) - } - t1.Multiply(&t2, &t1) // 2^200 - 1 - t1.Square(&t1) // 2^201 - 2 - for i := 1; i < 50; i++ { // 2^250 - 2^50 - t1.Square(&t1) - } - t0.Multiply(&t1, &t0) // 2^250 - 1 - t0.Square(&t0) // 2^251 - 2 - t0.Square(&t0) // 2^252 - 4 - return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3) + t0.Square(x) // x^2 + t1.Multiply(x, &t0) // x^3 + t0.Square(&t1) // x^6 + t0.Square(&t0) // x^12 + t0.Multiply(&t1, &t0) // x^15 + t0.Square(&t0) // x^30 + t0.Multiply(x, &t0) // x^31 = 2^5 - 1 + + t1.SquareN(&t0, 5) // 2^10 - 2^5 + t1.Multiply(&t1, &t0) // 2^10 - 1 + + t2.SquareN(&t1, 5) // 2^15 - 2^5 + t0.Multiply(&t2, &t0) // 2^15 - 1 + + t2.SquareN(&t0, 15) // 2^30 - 2^15 + t2.Multiply(&t2, &t0) // 2^30 - 1 + + t0.SquareN(&t2, 30) // 2^60 - 2^30 + t0.Multiply(&t0, &t2) // 2^60 - 1 + + t2.SquareN(&t0, 60) // 2^120 - 2^60 + t2.Multiply(&t2, &t0) // 2^120 - 1 + + t0.SquareN(&t2, 120) // 2^240 - 2^120 + t0.Multiply(&t0, &t2) // 2^240 - 1 + + t0.SquareN(&t0, 10) // 2^250 - 2^10 + t0.Multiply(&t0, &t1) // 2^250 - 1 + + t0.SquareN(&t0, 2) // 2^252 - 4 + return v.Multiply(&t0, x) // 2^252 - 3 } // sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion. diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_alias_test.go b/src/crypto/internal/fips140/edwards25519/field/fe_alias_test.go index 0c81239458d04a..3473e53a80e6c8 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe_alias_test.go +++ b/src/crypto/internal/fips140/edwards25519/field/fe_alias_test.go @@ -96,6 +96,12 @@ func TestAliasing(t *testing.T) { {name: "Negate", oneArgF: (*Element).Negate}, {name: "Set", oneArgF: (*Element).Set}, {name: "Square", oneArgF: (*Element).Square}, + { + name: "SquareN", + oneArgF: func(v, x *Element) *Element { + return v.SquareN(x, 10) + }, + }, {name: "Pow22523", oneArgF: (*Element).Pow22523}, { name: "Mult32", diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_amd64_noasm.go b/src/crypto/internal/fips140/edwards25519/field/fe_amd64_noasm.go index 4b81f25d1d0f53..792b84f152360c 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe_amd64_noasm.go +++ b/src/crypto/internal/fips140/edwards25519/field/fe_amd64_noasm.go @@ -9,3 +9,5 @@ package field func feMul(v, x, y *Element) { feMulGeneric(v, x, y) } func feSquare(v, x *Element) { feSquareGeneric(v, x) } + +func feSquareN(v, a *Element, n int) { feSquareNGeneric(v, a, n) } diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_generic.go b/src/crypto/internal/fips140/edwards25519/field/fe_generic.go index ef1f15a5dc0598..dd9a0fb61f1851 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe_generic.go +++ b/src/crypto/internal/fips140/edwards25519/field/fe_generic.go @@ -256,6 +256,62 @@ func feSquareGeneric(v, a *Element) { v.l4 = rr4&maskLow51Bits + rr3>>51 } +// feSquareNGeneric squares a n times and writes the result to v. +// It uses local variables to keep limbs in registers. +func feSquareNGeneric(v, a *Element, n int) { + l0 := a.l0 + l1 := a.l1 + l2 := a.l2 + l3 := a.l3 + l4 := a.l4 + + for range n { + r0 := mul(l0, l0) + r0 = addMul38(r0, l1, l4) + r0 = addMul38(r0, l2, l3) + + r1 := mul(l0*2, l1) + r1 = addMul38(r1, l2, l4) + r1 = addMul19(r1, l3, l3) + + r2 := mul(l0*2, l2) + r2 = addMul(r2, l1, l1) + r2 = addMul38(r2, l3, l4) + + r3 := mul(l0*2, l3) + r3 = addMul(r3, l1*2, l2) + r3 = addMul19(r3, l4, l4) + + r4 := mul(l0*2, l4) + r4 = addMul(r4, l1*2, l3) + r4 = addMul(r4, l2, l2) + + c0 := shiftRightBy51(r0) + c1 := shiftRightBy51(r1) + c2 := shiftRightBy51(r2) + c3 := shiftRightBy51(r3) + c4 := shiftRightBy51(r4) + + rr0 := r0.lo&maskLow51Bits + mul19(c4) + rr1 := r1.lo&maskLow51Bits + c0 + rr2 := r2.lo&maskLow51Bits + c1 + rr3 := r3.lo&maskLow51Bits + c2 + rr4 := r4.lo&maskLow51Bits + c3 + + l0 = rr0&maskLow51Bits + mul19(rr4>>51) + l1 = rr1&maskLow51Bits + rr0>>51 + l2 = rr2&maskLow51Bits + rr1>>51 + l3 = rr3&maskLow51Bits + rr2>>51 + l4 = rr4&maskLow51Bits + rr3>>51 + } + + v.l0 = l0 + v.l1 = l1 + v.l2 = l2 + v.l3 = l3 + v.l4 = l4 +} + // carryPropagate brings the limbs below 52 bits by applying the reduction // identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry. func (v *Element) carryPropagate() *Element { diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_squaren_amd64.go b/src/crypto/internal/fips140/edwards25519/field/fe_squaren_amd64.go new file mode 100644 index 00000000000000..021899b6e46bbe --- /dev/null +++ b/src/crypto/internal/fips140/edwards25519/field/fe_squaren_amd64.go @@ -0,0 +1,14 @@ +// Copyright (c) 2026 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. + +//go:build amd64 && !purego + +package field + +func feSquareN(v, a *Element, n int) { + feSquare(v, a) + for range n - 1 { + feSquare(v, v) + } +} diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_test.go b/src/crypto/internal/fips140/edwards25519/field/fe_test.go index b268878912197b..424074f7500520 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe_test.go +++ b/src/crypto/internal/fips140/edwards25519/field/fe_test.go @@ -489,6 +489,56 @@ func TestSqrtRatio(t *testing.T) { } } +func TestSquareN(t *testing.T) { + squareNMatchesRepeatSquare := func(x Element) bool { + for _, n := range []int{1, 2, 5, 10, 15, 50, 120} { + got := new(Element).SquareN(&x, n) + want := new(Element).Set(&x) + for range n { + want.Square(want) + } + if got.Equal(want) != 1 { + t.Logf("SquareN(%d) mismatch", n) + return false + } + if !isInBounds(got) { + t.Logf("SquareN(%d) out of bounds", n) + return false + } + } + return true + } + + if err := quick.Check(squareNMatchesRepeatSquare, quickCheckConfig(1024)); err != nil { + t.Error(err) + } +} + +func TestFeSquareN(t *testing.T) { + asmLikeGeneric := func(a Element) bool { + for _, n := range []int{1, 2, 5, 10, 15, 50, 120} { + t1 := a + t2 := a + + feSquareNGeneric(&t1, &t1, n) + feSquareN(&t2, &t2, n) + + if t1 != t2 { + t.Logf("n=%d: got %#v, expected %#v", n, t2, t1) + return false + } + if !isInBounds(&t2) { + return false + } + } + return true + } + + if err := quick.Check(asmLikeGeneric, quickCheckConfig(1024)); err != nil { + t.Error(err) + } +} + func TestFeSquare(t *testing.T) { asmLikeGeneric := func(a Element) bool { t1 := a From acced3df0352b1a859ddfd9cde6cdc48b9abd3aa Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 14 May 2026 10:06:04 -0700 Subject: [PATCH 03/18] crypto/internal/fips140/edwards25519/field: delete Square amd64 assembly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The preceding commit made the compiler-generated code faster than the assembly. Since the generic/assembly split is gone, use nicer function names. The fact that they are functions instead of methods is itself a vestige of their assembly roots. But unwinding that makes for a large diff. goos: linux goarch: amd64 cpu: AMD Ryzen Threadripper PRO 7975WX 32-Cores pkg: crypto/ed25519 │ before │ after │ │ sec/op │ sec/op vs base │ KeyGeneration-64 12.70µ ± 1% 12.38µ ± 2% -2.53% (p=0.000 n=30) NewKeyFromSeed-64 12.52µ ± 0% 12.27µ ± 1% -2.00% (p=0.000 n=30) Signing-64 15.42µ ± 0% 14.81µ ± 0% -3.97% (p=0.000 n=30) Verification-64 34.84µ ± 0% 34.68µ ± 0% -0.44% (p=0.006 n=30) geomean 17.10µ 16.71µ -2.24% pkg: crypto/internal/fips140/edwards25519 │ before │ after │ │ sec/op │ sec/op vs base │ EncodingDecoding-64 5.159µ ± 0% 4.589µ ± 1% -11.05% (p=0.000 n=30) ScalarBaseMult-64 9.761µ ± 0% 9.780µ ± 1% ~ (p=0.965 n=30) ScalarMult-64 31.99µ ± 0% 32.46µ ± 0% +1.47% (p=0.000 n=30) VarTimeDoubleScalarBaseMult-64 29.82µ ± 0% 30.16µ ± 0% +1.14% (p=0.000 n=30) geomean 14.80µ 14.48µ -2.20% pkg: crypto/internal/fips140/edwards25519/field │ before │ after │ │ sec/op │ sec/op vs base │ Add-64 2.571n ± 2% 2.573n ± 1% ~ (p=0.460 n=30) Multiply-64 10.67n ± 0% 10.62n ± 0% -0.47% (p=0.001 n=30) Square-64 8.849n ± 0% 8.412n ± 0% -4.94% (p=0.000 n=30) Invert-64 2.401µ ± 0% 2.156µ ± 2% -10.20% (p=0.000 n=30) Mult32-64 3.226n ± 0% 3.240n ± 0% +0.47% (p=0.004 n=30) Bytes-64 7.974n ± 1% 7.905n ± 1% -0.87% (p=0.015 n=30) geomean 15.70n 15.27n -2.74% Change-Id: I995209e72e202e7ca4e436615424120ef09e8b37 Reviewed-on: https://go-review.googlesource.com/c/go/+/778500 Reviewed-by: David Chase LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Filippo Valsorda Reviewed-by: Dmitri Shuralyov --- .../edwards25519/field/_asm/fe_amd64_asm.go | 90 ---------- .../fips140/edwards25519/field/fe_amd64.go | 5 - .../fips140/edwards25519/field/fe_amd64.s | 167 ------------------ .../edwards25519/field/fe_amd64_noasm.go | 4 - .../fips140/edwards25519/field/fe_generic.go | 6 +- .../edwards25519/field/fe_squaren_amd64.go | 14 -- .../fips140/edwards25519/field/fe_test.go | 45 ----- 7 files changed, 3 insertions(+), 328 deletions(-) delete mode 100644 src/crypto/internal/fips140/edwards25519/field/fe_squaren_amd64.go diff --git a/src/crypto/internal/fips140/edwards25519/field/_asm/fe_amd64_asm.go b/src/crypto/internal/fips140/edwards25519/field/_asm/fe_amd64_asm.go index ecb713b3c42a68..e2fcf0b2462661 100644 --- a/src/crypto/internal/fips140/edwards25519/field/_asm/fe_amd64_asm.go +++ b/src/crypto/internal/fips140/edwards25519/field/_asm/fe_amd64_asm.go @@ -19,7 +19,6 @@ func main() { Package("crypto/internal/fips140/edwards25519/field") ConstraintExpr("!purego") feMul() - feSquare() Generate() } @@ -37,95 +36,6 @@ type uint128 struct { func (c uint128) String() string { return c.name } -func feSquare() { - TEXT("feSquare", NOSPLIT, "func(out, a *Element)") - Doc("feSquare sets out = a * a. It works like feSquareGeneric.") - Pragma("noescape") - - a := Dereference(Param("a")) - l0 := namedComponent{a.Field("l0"), "l0"} - l1 := namedComponent{a.Field("l1"), "l1"} - l2 := namedComponent{a.Field("l2"), "l2"} - l3 := namedComponent{a.Field("l3"), "l3"} - l4 := namedComponent{a.Field("l4"), "l4"} - - // r0 = l0×l0 + 19×2×(l1×l4 + l2×l3) - r0 := uint128{"r0", GP64(), GP64()} - mul64(r0, 1, l0, l0) - addMul64(r0, 38, l1, l4) - addMul64(r0, 38, l2, l3) - - // r1 = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3 - r1 := uint128{"r1", GP64(), GP64()} - mul64(r1, 2, l0, l1) - addMul64(r1, 38, l2, l4) - addMul64(r1, 19, l3, l3) - - // r2 = = 2×l0×l2 + l1×l1 + 19×2×l3×l4 - r2 := uint128{"r2", GP64(), GP64()} - mul64(r2, 2, l0, l2) - addMul64(r2, 1, l1, l1) - addMul64(r2, 38, l3, l4) - - // r3 = = 2×l0×l3 + 2×l1×l2 + 19×l4×l4 - r3 := uint128{"r3", GP64(), GP64()} - mul64(r3, 2, l0, l3) - addMul64(r3, 2, l1, l2) - addMul64(r3, 19, l4, l4) - - // r4 = = 2×l0×l4 + 2×l1×l3 + l2×l2 - r4 := uint128{"r4", GP64(), GP64()} - mul64(r4, 2, l0, l4) - addMul64(r4, 2, l1, l3) - addMul64(r4, 1, l2, l2) - - Comment("First reduction chain") - maskLow51Bits := GP64() - MOVQ(Imm((1<<51)-1), maskLow51Bits) - c0, r0lo := shiftRightBy51(&r0) - c1, r1lo := shiftRightBy51(&r1) - c2, r2lo := shiftRightBy51(&r2) - c3, r3lo := shiftRightBy51(&r3) - c4, r4lo := shiftRightBy51(&r4) - maskAndAdd(r0lo, maskLow51Bits, c4, 19) - maskAndAdd(r1lo, maskLow51Bits, c0, 1) - maskAndAdd(r2lo, maskLow51Bits, c1, 1) - maskAndAdd(r3lo, maskLow51Bits, c2, 1) - maskAndAdd(r4lo, maskLow51Bits, c3, 1) - - Comment("Second reduction chain (carryPropagate)") - // c0 = r0 >> 51 - MOVQ(r0lo, c0) - SHRQ(Imm(51), c0) - // c1 = r1 >> 51 - MOVQ(r1lo, c1) - SHRQ(Imm(51), c1) - // c2 = r2 >> 51 - MOVQ(r2lo, c2) - SHRQ(Imm(51), c2) - // c3 = r3 >> 51 - MOVQ(r3lo, c3) - SHRQ(Imm(51), c3) - // c4 = r4 >> 51 - MOVQ(r4lo, c4) - SHRQ(Imm(51), c4) - maskAndAdd(r0lo, maskLow51Bits, c4, 19) - maskAndAdd(r1lo, maskLow51Bits, c0, 1) - maskAndAdd(r2lo, maskLow51Bits, c1, 1) - maskAndAdd(r3lo, maskLow51Bits, c2, 1) - maskAndAdd(r4lo, maskLow51Bits, c3, 1) - - Comment("Store output") - out := Dereference(Param("out")) - Store(r0lo, out.Field("l0")) - Store(r1lo, out.Field("l1")) - Store(r2lo, out.Field("l2")) - Store(r3lo, out.Field("l3")) - Store(r4lo, out.Field("l4")) - - RET() -} - func feMul() { TEXT("feMul", NOSPLIT, "func(out, a, b *Element)") Doc("feMul sets out = a * b. It works like feMulGeneric.") diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_amd64.go b/src/crypto/internal/fips140/edwards25519/field/fe_amd64.go index 00bf8f4479225b..1f3ce861c4dfea 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe_amd64.go +++ b/src/crypto/internal/fips140/edwards25519/field/fe_amd64.go @@ -8,8 +8,3 @@ package field // //go:noescape func feMul(out *Element, a *Element, b *Element) - -// feSquare sets out = a * a. It works like feSquareGeneric. -// -//go:noescape -func feSquare(out *Element, a *Element) diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_amd64.s b/src/crypto/internal/fips140/edwards25519/field/fe_amd64.s index 5e06e242ed8e92..a24a2410391bff 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe_amd64.s +++ b/src/crypto/internal/fips140/edwards25519/field/fe_amd64.s @@ -229,170 +229,3 @@ TEXT ·feMul(SB), NOSPLIT, $0-24 MOVQ R13, 24(AX) MOVQ R15, 32(AX) RET - -// func feSquare(out *Element, a *Element) -TEXT ·feSquare(SB), NOSPLIT, $0-16 - MOVQ a+8(FP), CX - - // r0 = l0×l0 - MOVQ (CX), AX - MULQ (CX) - MOVQ AX, SI - MOVQ DX, BX - - // r0 += 38×l1×l4 - MOVQ 8(CX), DX - LEAQ (DX)(DX*8), AX - LEAQ (DX)(AX*2), AX - SHLQ $0x01, AX - MULQ 32(CX) - ADDQ AX, SI - ADCQ DX, BX - - // r0 += 38×l2×l3 - MOVQ 16(CX), DX - LEAQ (DX)(DX*8), AX - LEAQ (DX)(AX*2), AX - SHLQ $0x01, AX - MULQ 24(CX) - ADDQ AX, SI - ADCQ DX, BX - - // r1 = 2×l0×l1 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 8(CX) - MOVQ AX, R8 - MOVQ DX, DI - - // r1 += 38×l2×l4 - MOVQ 16(CX), DX - LEAQ (DX)(DX*8), AX - LEAQ (DX)(AX*2), AX - SHLQ $0x01, AX - MULQ 32(CX) - ADDQ AX, R8 - ADCQ DX, DI - - // r1 += 19×l3×l3 - MOVQ 24(CX), DX - LEAQ (DX)(DX*8), AX - LEAQ (DX)(AX*2), AX - MULQ 24(CX) - ADDQ AX, R8 - ADCQ DX, DI - - // r2 = 2×l0×l2 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 16(CX) - MOVQ AX, R10 - MOVQ DX, R9 - - // r2 += l1×l1 - MOVQ 8(CX), AX - MULQ 8(CX) - ADDQ AX, R10 - ADCQ DX, R9 - - // r2 += 38×l3×l4 - MOVQ 24(CX), DX - LEAQ (DX)(DX*8), AX - LEAQ (DX)(AX*2), AX - SHLQ $0x01, AX - MULQ 32(CX) - ADDQ AX, R10 - ADCQ DX, R9 - - // r3 = 2×l0×l3 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 24(CX) - MOVQ AX, R12 - MOVQ DX, R11 - - // r3 += 2×l1×l2 - MOVQ 8(CX), AX - SHLQ $0x01, AX - MULQ 16(CX) - ADDQ AX, R12 - ADCQ DX, R11 - - // r3 += 19×l4×l4 - MOVQ 32(CX), DX - LEAQ (DX)(DX*8), AX - LEAQ (DX)(AX*2), AX - MULQ 32(CX) - ADDQ AX, R12 - ADCQ DX, R11 - - // r4 = 2×l0×l4 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 32(CX) - MOVQ AX, R14 - MOVQ DX, R13 - - // r4 += 2×l1×l3 - MOVQ 8(CX), AX - SHLQ $0x01, AX - MULQ 24(CX) - ADDQ AX, R14 - ADCQ DX, R13 - - // r4 += l2×l2 - MOVQ 16(CX), AX - MULQ 16(CX) - ADDQ AX, R14 - ADCQ DX, R13 - - // First reduction chain - MOVQ $0x0007ffffffffffff, AX - SHLQ $0x0d, SI, BX - SHLQ $0x0d, R8, DI - SHLQ $0x0d, R10, R9 - SHLQ $0x0d, R12, R11 - SHLQ $0x0d, R14, R13 - ANDQ AX, SI - IMUL3Q $0x13, R13, R13 - ADDQ R13, SI - ANDQ AX, R8 - ADDQ BX, R8 - ANDQ AX, R10 - ADDQ DI, R10 - ANDQ AX, R12 - ADDQ R9, R12 - ANDQ AX, R14 - ADDQ R11, R14 - - // Second reduction chain (carryPropagate) - MOVQ SI, BX - SHRQ $0x33, BX - MOVQ R8, DI - SHRQ $0x33, DI - MOVQ R10, R9 - SHRQ $0x33, R9 - MOVQ R12, R11 - SHRQ $0x33, R11 - MOVQ R14, R13 - SHRQ $0x33, R13 - ANDQ AX, SI - IMUL3Q $0x13, R13, R13 - ADDQ R13, SI - ANDQ AX, R8 - ADDQ BX, R8 - ANDQ AX, R10 - ADDQ DI, R10 - ANDQ AX, R12 - ADDQ R9, R12 - ANDQ AX, R14 - ADDQ R11, R14 - - // Store output - MOVQ out+0(FP), AX - MOVQ SI, (AX) - MOVQ R8, 8(AX) - MOVQ R10, 16(AX) - MOVQ R12, 24(AX) - MOVQ R14, 32(AX) - RET diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_amd64_noasm.go b/src/crypto/internal/fips140/edwards25519/field/fe_amd64_noasm.go index 792b84f152360c..a85eb109bbd3fd 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe_amd64_noasm.go +++ b/src/crypto/internal/fips140/edwards25519/field/fe_amd64_noasm.go @@ -7,7 +7,3 @@ package field func feMul(v, x, y *Element) { feMulGeneric(v, x, y) } - -func feSquare(v, x *Element) { feSquareGeneric(v, x) } - -func feSquareN(v, a *Element, n int) { feSquareNGeneric(v, a, n) } diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_generic.go b/src/crypto/internal/fips140/edwards25519/field/fe_generic.go index dd9a0fb61f1851..579eab6122f036 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe_generic.go +++ b/src/crypto/internal/fips140/edwards25519/field/fe_generic.go @@ -183,7 +183,7 @@ func feMulGeneric(v, a, b *Element) { v.l4 = rr4&maskLow51Bits + rr3>>51 } -func feSquareGeneric(v, a *Element) { +func feSquare(v, a *Element) { l0 := a.l0 l1 := a.l1 l2 := a.l2 @@ -256,9 +256,9 @@ func feSquareGeneric(v, a *Element) { v.l4 = rr4&maskLow51Bits + rr3>>51 } -// feSquareNGeneric squares a n times and writes the result to v. +// feSquareN squares a n times and writes the result to v. // It uses local variables to keep limbs in registers. -func feSquareNGeneric(v, a *Element, n int) { +func feSquareN(v, a *Element, n int) { l0 := a.l0 l1 := a.l1 l2 := a.l2 diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_squaren_amd64.go b/src/crypto/internal/fips140/edwards25519/field/fe_squaren_amd64.go deleted file mode 100644 index 021899b6e46bbe..00000000000000 --- a/src/crypto/internal/fips140/edwards25519/field/fe_squaren_amd64.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2026 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. - -//go:build amd64 && !purego - -package field - -func feSquareN(v, a *Element, n int) { - feSquare(v, a) - for range n - 1 { - feSquare(v, v) - } -} diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_test.go b/src/crypto/internal/fips140/edwards25519/field/fe_test.go index 424074f7500520..a98c152b631477 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe_test.go +++ b/src/crypto/internal/fips140/edwards25519/field/fe_test.go @@ -514,51 +514,6 @@ func TestSquareN(t *testing.T) { } } -func TestFeSquareN(t *testing.T) { - asmLikeGeneric := func(a Element) bool { - for _, n := range []int{1, 2, 5, 10, 15, 50, 120} { - t1 := a - t2 := a - - feSquareNGeneric(&t1, &t1, n) - feSquareN(&t2, &t2, n) - - if t1 != t2 { - t.Logf("n=%d: got %#v, expected %#v", n, t2, t1) - return false - } - if !isInBounds(&t2) { - return false - } - } - return true - } - - if err := quick.Check(asmLikeGeneric, quickCheckConfig(1024)); err != nil { - t.Error(err) - } -} - -func TestFeSquare(t *testing.T) { - asmLikeGeneric := func(a Element) bool { - t1 := a - t2 := a - - feSquareGeneric(&t1, &t1) - feSquare(&t2, &t2) - - if t1 != t2 { - t.Logf("got: %#v,\nexpected: %#v", t1, t2) - } - - return t1 == t2 && isInBounds(&t2) - } - - if err := quick.Check(asmLikeGeneric, quickCheckConfig(1024)); err != nil { - t.Error(err) - } -} - func TestFeMul(t *testing.T) { asmLikeGeneric := func(a, b Element) bool { a1 := a From c0bd270406befbc373ad96f73e121dd447c31737 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 19 May 2026 21:22:43 +0200 Subject: [PATCH 04/18] net/netip: update godoc comments Streamline the godoc comments across Addr, AddrPort and Prefix in terms of wording and godoc links. Add more and correct godoc links. Change-Id: Id806ddcfafc9a99af483a9a6c94c6288d1ee4939 Reviewed-on: https://go-review.googlesource.com/c/go/+/779640 Reviewed-by: Michael Pratt Auto-Submit: Tobias Klauser LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Sean Liao Reviewed-by: Florian Lehner Reviewed-by: Dmitri Shuralyov --- src/net/netip/netip.go | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/net/netip/netip.go b/src/net/netip/netip.go index 75042bf165bf4f..57b8c6f70a3698 100644 --- a/src/net/netip/netip.go +++ b/src/net/netip/netip.go @@ -97,7 +97,7 @@ func AddrFrom4(addr [4]byte) Addr { // AddrFrom16 returns the IPv6 address given by the bytes in addr. // An IPv4-mapped IPv6 address is left as an IPv6 address. -// (Use Unmap to convert them if needed.) +// (Use [Addr.Unmap] to convert them if needed.) func AddrFrom16(addr [16]byte) Addr { return Addr{ addr: uint128{ @@ -957,13 +957,13 @@ func (ip Addr) StringExpanded() string { return string(ret) } -// AppendText implements the [encoding.TextAppender] interface, -// It is the same as [Addr.AppendTo]. +// AppendText implements the [encoding.TextAppender] interface. +// The encoding is the same as returned by [Addr.AppendTo]. func (ip Addr) AppendText(b []byte) ([]byte, error) { return ip.AppendTo(b), nil } -// MarshalText implements the [encoding.TextMarshaler] interface, +// MarshalText implements the [encoding.TextMarshaler] interface. // The encoding is the same as returned by [Addr.String], with one exception: // If ip is the zero [Addr], the encoding is the empty string. func (ip Addr) MarshalText() ([]byte, error) { @@ -985,7 +985,7 @@ func (ip Addr) MarshalText() ([]byte, error) { return ip.AppendText(buf) } -// UnmarshalText implements the encoding.TextUnmarshaler interface. +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. // The IP address is expected in a form accepted by [ParseAddr]. // // If text is empty, UnmarshalText sets *ip to the zero [Addr] and @@ -1034,7 +1034,7 @@ func (ip Addr) MarshalBinary() ([]byte, error) { } // UnmarshalBinary implements the [encoding.BinaryUnmarshaler] interface. -// It expects data in the form generated by MarshalBinary. +// It expects data in the form generated by [Addr.MarshalBinary]. func (ip *Addr) UnmarshalBinary(b []byte) error { n := len(b) switch { @@ -1201,15 +1201,15 @@ func (p AddrPort) AppendTo(b []byte) []byte { return b } -// AppendText implements the [encoding.TextAppender] interface. The -// encoding is the same as returned by [AddrPort.AppendTo]. +// AppendText implements the [encoding.TextAppender] interface. +// The encoding is the same as returned by [AddrPort.AppendTo]. func (p AddrPort) AppendText(b []byte) ([]byte, error) { return p.AppendTo(b), nil } -// MarshalText implements the [encoding.TextMarshaler] interface. The -// encoding is the same as returned by [AddrPort.String], with one exception: if -// p.Addr() is the zero [Addr], the encoding is the empty string. +// MarshalText implements the [encoding.TextMarshaler] interface. +// The encoding is the same as returned by [AddrPort.String], with one exception: +// If p.Addr() is the zero [Addr], the encoding is the empty string. func (p AddrPort) MarshalText() ([]byte, error) { buf := []byte{} switch p.ip.z { @@ -1224,9 +1224,9 @@ func (p AddrPort) MarshalText() ([]byte, error) { return p.AppendText(buf) } -// UnmarshalText implements the encoding.TextUnmarshaler -// interface. The [AddrPort] is expected in a form -// generated by [AddrPort.MarshalText] or accepted by [ParseAddrPort]. +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. +// The [AddrPort] is expected in a form generated by [AddrPort.MarshalText] or +// accepted by [ParseAddrPort]. func (p *AddrPort) UnmarshalText(text []byte) error { if len(text) == 0 { *p = AddrPort{} @@ -1512,9 +1512,9 @@ func (p Prefix) AppendText(b []byte) ([]byte, error) { return p.AppendTo(b), nil } -// MarshalText implements the [encoding.TextMarshaler] interface, +// MarshalText implements the [encoding.TextMarshaler] interface. // The encoding is the same as returned by [Prefix.String], with one exception: -// If p is the zero value, the encoding is the empty string. +// If p is the zero [Prefix], the encoding is the empty string. func (p Prefix) MarshalText() ([]byte, error) { buf := []byte{} switch p.ip.z { @@ -1529,7 +1529,7 @@ func (p Prefix) MarshalText() ([]byte, error) { return p.AppendText(buf) } -// UnmarshalText implements the encoding.TextUnmarshaler interface. +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. // The IP address is expected in a form accepted by [ParsePrefix] // or generated by [Prefix.MarshalText]. func (p *Prefix) UnmarshalText(text []byte) error { @@ -1542,7 +1542,7 @@ func (p *Prefix) UnmarshalText(text []byte) error { return err } -// AppendBinary implements the [encoding.AppendMarshaler] interface. +// AppendBinary implements the [encoding.BinaryAppender] interface. // It returns [Addr.AppendBinary] with an additional byte appended // containing the prefix bits. func (p Prefix) AppendBinary(b []byte) ([]byte, error) { From 05ab7b8da58811a50a90146d7405296fab82376f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 20 May 2026 11:29:39 -0700 Subject: [PATCH 05/18] cmd/compile/internal/syntax: refactor/reword new line directives tests - added a handfull of test cases to TestLineDirectives that were removed and added to TestLineDirectivesPaths in CL 706795 - rewrote TestLineDirectivesWithDir into a simpler, more readable form - removed TestLineDirectivesPaths and moved its cases into the existing TestLineDirectives function This cleanup now leaves one dedicated, simple test function that tests the new directory-relative line-directive behavior. Follow-up on CL 706795. Change-Id: I1025a54ba9de034235bceaaa0cc416b7acb5cb73 Reviewed-on: https://go-review.googlesource.com/c/go/+/780660 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Robert Griesemer Auto-Submit: Robert Griesemer Reviewed-by: Alan Donovan Reviewed-by: Michael Podtserkovskii --- .../compile/internal/syntax/parser_test.go | 126 +++++------------- 1 file changed, 36 insertions(+), 90 deletions(-) diff --git a/src/cmd/compile/internal/syntax/parser_test.go b/src/cmd/compile/internal/syntax/parser_test.go index e086f56f4ca6f2..1f5d44caa9ded3 100644 --- a/src/cmd/compile/internal/syntax/parser_test.go +++ b/src/cmd/compile/internal/syntax/parser_test.go @@ -232,7 +232,7 @@ func TestParseFile(t *testing.T) { var tooLarge int = PosMax + 1 func TestLineDirectives(t *testing.T) { - // valid line directives lead to a syntax error after them + // valid line directives lead to this syntax error after them const valid = "syntax error: package statement must be first" const filename = "directives.go" @@ -271,8 +271,8 @@ func TestLineDirectives(t *testing.T) { {fmt.Sprintf("//line foo:10:%d\n", tooLarge), fmt.Sprintf("invalid column number: %d", tooLarge), filename, 1, 15}, // effect of valid //line directives on lines - {"//line foo:123\n foo", valid, "foo", 123, 0}, - {"//line foo:123\n foo", valid, " foo", 123, 0}, + {"//line foo:123\n", valid, "foo", 123, 0}, + {"//line foo:123\n", valid, " foo", 123, 0}, {"//line foo:123\n//line bar:345\nfoo", valid, "bar", 345, 0}, {"//line :x:1\n", valid, ":x", 1, 0}, {"//line foo ::1\n", valid, "foo :", 1, 0}, @@ -322,7 +322,7 @@ func TestLineDirectives(t *testing.T) { {fmt.Sprintf("/*line foo:10:%d*/", tooLarge), fmt.Sprintf("invalid column number: %d", tooLarge), filename, 1, 15}, // effect of valid /*line directives on lines - {"/*line foo:123*/ foo", valid, "foo", 123, 0}, + {"/*line foo:123*/", valid, "foo", 123, 0}, {"/*line foo:123*/\n//line bar:345\nfoo", valid, "bar", 345, 0}, {"/*line :x:1*/", valid, ":x", 1, 0}, {"/*line foo ::1*/", valid, "foo :", 1, 0}, @@ -342,6 +342,14 @@ func TestLineDirectives(t *testing.T) { {"/*line :10:20*/", valid, filename, 10, 20}, {"//line bar:1\n/*line :10*/", valid, "", 10, 0}, {"//line bar:1\n/*line :10:20*/", valid, "bar", 10, 20}, + + // effect of cleaning filenames + {"//line C:foo:123\n", valid, filepath.Clean("C:foo"), 123, 0}, + {"//line /src/a/a.go:123\n", valid, filepath.Clean("/src/a/a.go"), 123, 0}, + {"//line foo/../bar:1\n", valid, filepath.Clean("foo/../bar"), 1, 0}, + {"/*line C:foo:123*/", valid, filepath.Clean("C:foo"), 123, 0}, + {"/*line /src/a/a.go:123*/", valid, filepath.Clean("/src/a/a.go"), 123, 0}, + {"/*line foo/../bar:1*/", valid, filepath.Clean("foo/../bar"), 1, 0}, } { base := NewFileBase(filename) _, err := Parse(base, strings.NewReader(test.src), nil, nil, 0) @@ -372,102 +380,40 @@ func TestLineDirectives(t *testing.T) { } func TestLineDirectivesWithDir(t *testing.T) { - const valid = "syntax error: package statement must be first" - srcFile := filepath.Join("dir", "directives.go") - - check := func(src, want string) { - t.Helper() - base := NewFileBase(srcFile) - _, err := Parse(base, strings.NewReader(src), nil, nil, 0) - if err == nil { - t.Errorf("%s: no error reported", src) - return - } - perr, ok := err.(Error) - if !ok { - t.Errorf("%s: got %v; want parser error", src, err) - return - } - if perr.Msg != valid { - t.Errorf("%s: got msg = %q; want %q", src, perr.Msg, valid) - return - } - if got := perr.Pos.RelFilename(); got != want { - t.Errorf("%s: got filename = %q; want %q", src, got, want) - } + const dir = "dir" + filename := filepath.Join(dir, "directives.go") + + type test struct{ src, filename string } + relPaths := []test{ + {"//line foo:1\n", filepath.Join(dir, "foo")}, + {"//line ./foo:1\n", filepath.Join(dir, "foo")}, + {"//line ../foo:1\n", "foo"}, + {"//line sub/foo:1\n", filepath.Join(dir, "sub", "foo")}, + {"/*line foo:1*/", filepath.Join(dir, "foo")}, + {"//line bar:1\n//line :2:1\n", filepath.Join(dir, "bar")}, } - for _, test := range []struct { - src string - filename string - }{ - {"//line foo:1\n x", filepath.Join("dir", "foo")}, - {"//line ./foo:1\n x", filepath.Join("dir", "foo")}, - {"//line ../foo:1\n x", "foo"}, - {"//line sub/foo:1\n x", filepath.Join("dir", "sub", "foo")}, - {"/*line foo:1*/ x", filepath.Join("dir", "foo")}, - {"//line bar:1\n//line :2:1\n x", filepath.Join("dir", "bar")}, - } { - check(test.src, test.filename) - } - - var absCases []struct { - src, filename string - } + var absPaths []test if runtime.GOOS == "windows" { - absCases = append(absCases, struct{ src, filename string }{ - "//line c:\\bar:1\n x", "c:\\bar", - }) + absPaths = []test{ + {"//line c:\\bar:1\n", "c:\\bar"}, + } } else { - absCases = append(absCases, - struct{ src, filename string }{"//line /abs/foo:1\n x", "/abs/foo"}, - struct{ src, filename string }{"//line /src/a/a.go:1\n x", "/src/a/a.go"}, - ) - } - for _, test := range absCases { - check(test.src, test.filename) + absPaths = []test{ + {"//line /abs/foo:1\n", "/abs/foo"}, + {"//line /src/a/a.go:1\n", "/src/a/a.go"}, + } } -} -func TestLineDirectivesPaths(t *testing.T) { - const valid = "syntax error: package statement must be first" - const filename = "directives.go" - - type tc struct { - src string - filename string - line uint - } - var cases []tc - cases = []tc{ - {"//line C:foo:123\n", "C:foo", 123}, - {"//line /src/a/a.go:123\n foo", filepath.Clean("/src/a/a.go"), 123}, - {"/*line C:foo:123*/", "C:foo", 123}, - {"/*line /src/a/a.go:123*/ foo", filepath.Clean("/src/a/a.go"), 123}, - {"//line foo/../bar:1\n x", "bar", 1}, - } - for _, test := range cases { + for _, test := range append(relPaths, absPaths...) { base := NewFileBase(filename) - _, err := Parse(base, strings.NewReader(test.src), nil, nil, 0) - if err == nil { - t.Errorf("%s: no error reported", test.src) - continue - } - perr, ok := err.(Error) - if !ok { - t.Errorf("%s: got %v; want parser error", test.src, err) - continue - } - if perr.Msg != valid { - t.Errorf("%s: got msg = %q; want %q", test.src, perr.Msg, valid) - continue + pkg, err := Parse(base, strings.NewReader(test.src+"package p"), nil, nil, 0) + if err != nil { + t.Error(err) } - if got := perr.Pos.RelFilename(); got != test.filename { + if got := pkg.Pos().RelFilename(); got != test.filename { t.Errorf("%s: got filename = %q; want %q", test.src, got, test.filename) } - if got := perr.Pos.RelLine(); got != test.line { - t.Errorf("%s: got line = %d; want %d", test.src, got, test.line) - } } } From 3652f299a89ee45caaa6ee0f36c1a45da7909504 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 20 May 2026 16:00:13 -0400 Subject: [PATCH 06/18] cmd/link: skip TestAbstractOriginSanity CL 743860 broke -l=4 builds by introducing an allocation in runtime.printfloat64. Since -l=4 is very rarely used, skip the one test using it until it is fixed. Updates #79547 Change-Id: Id180cfc66a76c70fa980b3efeb1440156a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/780760 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Junyang Shao Auto-Submit: Michael Pratt --- src/cmd/link/internal/ld/dwarf_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index 8c2ac0d46a8e1c..ab7cbe92210538 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -828,6 +828,9 @@ func TestAbstractOriginSanity(t *testing.T) { t.Skip("skipping test in short mode.") } + // TODO(go.dev/issue/79547): -l=4 builds are temporarily broken. + t.Skip("-l=4 builds are currently broken because they introduce an allocation in runtime.printfloat64") + mustHaveDWARF(t) abstractOriginSanity(t, "testdata/httptest", OptAllInl4) } From 694604e524ebdb44aff60e3057152f8d5f406c09 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Wed, 20 May 2026 00:34:10 -0400 Subject: [PATCH 07/18] runtime: further reduce number of size classes We now will only generate size specialized functions for size clases less than or equal to 7. This brings down the size of the generated functions from around 21k to around 16k. For #79286 Change-Id: I1adafd3674004069ed6461ef63228bfc6a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/780300 Reviewed-by: Michael Matloob LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Michael Pratt --- src/cmd/compile/internal/ir/symtab.go | 4 +- src/cmd/compile/internal/ssagen/ssa.go | 2 +- src/runtime/_mkmalloc/constants.go | 2 +- src/runtime/_mkmalloc/mkmalloc.go | 6 +- src/runtime/malloc_generated.go | 883 +++---------------------- src/runtime/malloc_tables_generated.go | 101 +-- 6 files changed, 86 insertions(+), 912 deletions(-) diff --git a/src/cmd/compile/internal/ir/symtab.go b/src/cmd/compile/internal/ir/symtab.go index 320836c8c4f449..57cde66fb5601c 100644 --- a/src/cmd/compile/internal/ir/symtab.go +++ b/src/cmd/compile/internal/ir/symtab.go @@ -39,8 +39,8 @@ type symsStruct struct { InterfaceSwitch *obj.LSym MallocGC *obj.LSym MallocGCTiny *obj.LSym - MallocGCSmallNoScan [11]*obj.LSym - MallocGCSmallScanNoHeader [11]*obj.LSym + MallocGCSmallNoScan [8]*obj.LSym + MallocGCSmallScanNoHeader [8]*obj.LSym Memmove *obj.LSym Memequal *obj.LSym Msanread *obj.LSym diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 9fb79bc97758a9..9a4970a579085d 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -806,7 +806,7 @@ func (s *state) specializedMallocSym(size int64, hasPointers bool) *obj.LSym { if !s.sizeSpecializedMallocEnabled() { return nil } - const specializedMallocMax = 128 // This must match the constant in mkmalloc. + const specializedMallocMax = 80 // This must match the constant in mkmalloc. if size > specializedMallocMax { return nil } diff --git a/src/runtime/_mkmalloc/constants.go b/src/runtime/_mkmalloc/constants.go index 7c7424eb6189f9..57fa8a7b46bb4e 100644 --- a/src/runtime/_mkmalloc/constants.go +++ b/src/runtime/_mkmalloc/constants.go @@ -27,5 +27,5 @@ const ( // size classes, and with the wrapper they are sometimes slower // than the non-specialized functions. // This must match the constant in the compiler. - specializedMallocMax = 128 + specializedMallocMax = 80 ) diff --git a/src/runtime/_mkmalloc/mkmalloc.go b/src/runtime/_mkmalloc/mkmalloc.go index f777349d9cbda6..892cfdcc8e97ae 100644 --- a/src/runtime/_mkmalloc/mkmalloc.go +++ b/src/runtime/_mkmalloc/mkmalloc.go @@ -888,16 +888,16 @@ package runtime import "unsafe" -var mallocScanTable = [129]func(size uintptr, typ *_type, needzero bool) unsafe.Pointer{`) +var mallocScanTable = [%d]func(size uintptr, typ *_type, needzero bool) unsafe.Pointer{`, specializedMallocMax+1) for i := range uintptr(specializedMallocMax + 1) { fmt.Fprintf(&b, "%s,\n", smallScanNoHeaderSCFuncName(sizeToSizeClass[i], scMax)) } - fmt.Fprintln(&b, ` + fmt.Fprintf(&b, ` } -var mallocNoScanTable = [129]func(size uintptr, typ *_type, needzero bool) unsafe.Pointer{`) +var mallocNoScanTable = [%d]func(size uintptr, typ *_type, needzero bool) unsafe.Pointer{`, specializedMallocMax+1) for i := range uintptr(specializedMallocMax + 1) { if i < 16 { fmt.Fprintf(&b, "%s,\n", "mallocPanic") diff --git a/src/runtime/malloc_generated.go b/src/runtime/malloc_generated.go index 0c2c115e7db2f1..2cced2341696a2 100644 --- a/src/runtime/malloc_generated.go +++ b/src/runtime/malloc_generated.go @@ -1053,663 +1053,17 @@ func mallocgcSmallScanNoHeaderSC7(size uintptr, typ *_type, needzero bool) unsaf return x } -func mallocgcSmallScanNoHeaderSC8(size uintptr, typ *_type, needzero bool) unsafe.Pointer { - - forceSlowPath := debug.malloc || gcBlackenEnabled != 0 || (goexperiment.RuntimeSecret && getg().secret > 0) - - if forceSlowPath { - - const spc = spanClass(8<<1) | spanClass(0) - const elemsize = uintptr(96) - return mallocgcSmallScanSlowPath(size, typ, needzero, spc, elemsize) - } - - if doubleCheckMalloc { - if gcphase == _GCmarktermination { - throw("mallocgc called with gcphase == _GCmarktermination") - } - } - - lockRankMayQueueFinalizer() - - const sizeclass = 8 - const elemsize = 96 - - mp := acquirem() - if doubleCheckMalloc { - - doubleCheckSmallScanNoHeader(size, typ, mp) - - } - mp.mallocing = 1 - - checkGCTrigger := false - c := getMCache(mp) - const spc = spanClass(sizeclass<<1) | spanClass(0) - span := c.alloc[spc] - - var v gclinkptr - var x unsafe.Pointer - - { - - var nextFreeFastResult gclinkptr - if span.allocCache != 0 { - theBit := sys.TrailingZeros64(span.allocCache) - result := span.freeindex + uint16(theBit) - if result < span.nelems { - freeidx := result + 1 - if !(freeidx%64 == 0 && freeidx != span.nelems) { - span.allocCache >>= uint(theBit + 1) - span.freeindex = freeidx - span.allocCount++ - nextFreeFastResult = gclinkptr(uintptr(result)*elemsize + span.base()) - } - } - } - v = nextFreeFastResult - if v == 0 { - v, span, checkGCTrigger = c.nextFree(spc) - } - x = unsafe.Pointer(v) - } - - if span.needzero != 0 { - memclrNoHeapPointers(x, elemsize) - } - if goarch.PtrSize == 8 && elemsize == 8 { - - c.scanAlloc += 8 - } else { - dataSize := size - x := uintptr(x) - - if doubleCheckHeapSetType && (!heapBitsInSpan(dataSize) || !heapBitsInSpan(96)) { - throw("tried to write heap bits, but no heap bits in span") - } - - src0 := readUintptr(getGCMask(typ)) - - const elemsize = 96 - - var scanSize uintptr - src := src0 - if typ.Size_ == goarch.PtrSize { - src = (1 << (dataSize / goarch.PtrSize)) - 1 - - scanSize = dataSize - } else { - - if doubleCheckHeapSetType && !asanenabled && dataSize%typ.Size_ != 0 { - throw("runtime: (*mspan).writeHeapBitsSmall: dataSize is not a multiple of typ.Size_") - } - scanSize = typ.PtrBytes - for i := typ.Size_; i < dataSize; i += typ.Size_ { - src |= src0 << (i / goarch.PtrSize) - scanSize += typ.Size_ - } - } - - dstBase, _ := spanHeapBitsRange(span.base(), pageSize, elemsize) - dst := unsafe.Pointer(dstBase) - o := (x - span.base()) / goarch.PtrSize - i := o / ptrBits - j := o % ptrBits - var bits uintptr = elemsize / goarch.PtrSize - - var bitsIsPowerOfTwo = bits&(bits-1) == 0 - if bits > ptrBits || (!bitsIsPowerOfTwo && j+bits > ptrBits) { - - bits0 := ptrBits - j - bits1 := bits - bits0 - dst0 := (*uintptr)(add(dst, (i+0)*goarch.PtrSize)) - dst1 := (*uintptr)(add(dst, (i+1)*goarch.PtrSize)) - *dst0 = (*dst0)&(^uintptr(0)>>bits0) | (src << j) - *dst1 = (*dst1)&^((1<> bits0) - } else { - - dst := (*uintptr)(add(dst, i*goarch.PtrSize)) - *dst = (*dst)&^(((1<<(min(bits, ptrBits)))-1)< 0) - - if forceSlowPath { - - const spc = spanClass(9<<1) | spanClass(0) - const elemsize = uintptr(112) - return mallocgcSmallScanSlowPath(size, typ, needzero, spc, elemsize) - } - - if doubleCheckMalloc { - if gcphase == _GCmarktermination { - throw("mallocgc called with gcphase == _GCmarktermination") - } - } - - lockRankMayQueueFinalizer() - - const sizeclass = 9 - const elemsize = 112 - - mp := acquirem() - if doubleCheckMalloc { - - doubleCheckSmallScanNoHeader(size, typ, mp) - - } - mp.mallocing = 1 - - checkGCTrigger := false - c := getMCache(mp) - const spc = spanClass(sizeclass<<1) | spanClass(0) - span := c.alloc[spc] - - var v gclinkptr - var x unsafe.Pointer - - { - - var nextFreeFastResult gclinkptr - if span.allocCache != 0 { - theBit := sys.TrailingZeros64(span.allocCache) - result := span.freeindex + uint16(theBit) - if result < span.nelems { - freeidx := result + 1 - if !(freeidx%64 == 0 && freeidx != span.nelems) { - span.allocCache >>= uint(theBit + 1) - span.freeindex = freeidx - span.allocCount++ - nextFreeFastResult = gclinkptr(uintptr(result)*elemsize + span.base()) - } - } - } - v = nextFreeFastResult - if v == 0 { - v, span, checkGCTrigger = c.nextFree(spc) - } - x = unsafe.Pointer(v) - } - - if span.needzero != 0 { - memclrNoHeapPointers(x, elemsize) - } - if goarch.PtrSize == 8 && elemsize == 8 { - - c.scanAlloc += 8 - } else { - dataSize := size - x := uintptr(x) - - if doubleCheckHeapSetType && (!heapBitsInSpan(dataSize) || !heapBitsInSpan(112)) { - throw("tried to write heap bits, but no heap bits in span") - } - - src0 := readUintptr(getGCMask(typ)) - - const elemsize = 112 - - var scanSize uintptr - src := src0 - if typ.Size_ == goarch.PtrSize { - src = (1 << (dataSize / goarch.PtrSize)) - 1 - - scanSize = dataSize - } else { - - if doubleCheckHeapSetType && !asanenabled && dataSize%typ.Size_ != 0 { - throw("runtime: (*mspan).writeHeapBitsSmall: dataSize is not a multiple of typ.Size_") - } - scanSize = typ.PtrBytes - for i := typ.Size_; i < dataSize; i += typ.Size_ { - src |= src0 << (i / goarch.PtrSize) - scanSize += typ.Size_ - } - } - - dstBase, _ := spanHeapBitsRange(span.base(), pageSize, elemsize) - dst := unsafe.Pointer(dstBase) - o := (x - span.base()) / goarch.PtrSize - i := o / ptrBits - j := o % ptrBits - var bits uintptr = elemsize / goarch.PtrSize - - var bitsIsPowerOfTwo = bits&(bits-1) == 0 - if bits > ptrBits || (!bitsIsPowerOfTwo && j+bits > ptrBits) { - - bits0 := ptrBits - j - bits1 := bits - bits0 - dst0 := (*uintptr)(add(dst, (i+0)*goarch.PtrSize)) - dst1 := (*uintptr)(add(dst, (i+1)*goarch.PtrSize)) - *dst0 = (*dst0)&(^uintptr(0)>>bits0) | (src << j) - *dst1 = (*dst1)&^((1<> bits0) - } else { - - dst := (*uintptr)(add(dst, i*goarch.PtrSize)) - *dst = (*dst)&^(((1<<(min(bits, ptrBits)))-1)< 0) - - if forceSlowPath { - - const spc = spanClass(10<<1) | spanClass(0) - const elemsize = uintptr(128) - return mallocgcSmallScanSlowPath(size, typ, needzero, spc, elemsize) - } - - if doubleCheckMalloc { - if gcphase == _GCmarktermination { - throw("mallocgc called with gcphase == _GCmarktermination") - } - } - - lockRankMayQueueFinalizer() - - const sizeclass = 10 - const elemsize = 128 - - mp := acquirem() - if doubleCheckMalloc { - - doubleCheckSmallScanNoHeader(size, typ, mp) - - } - mp.mallocing = 1 - - checkGCTrigger := false - c := getMCache(mp) - const spc = spanClass(sizeclass<<1) | spanClass(0) - span := c.alloc[spc] - - var v gclinkptr - var x unsafe.Pointer - - { - - var nextFreeFastResult gclinkptr - if span.allocCache != 0 { - theBit := sys.TrailingZeros64(span.allocCache) - result := span.freeindex + uint16(theBit) - if result < span.nelems { - freeidx := result + 1 - if !(freeidx%64 == 0 && freeidx != span.nelems) { - span.allocCache >>= uint(theBit + 1) - span.freeindex = freeidx - span.allocCount++ - nextFreeFastResult = gclinkptr(uintptr(result)*elemsize + span.base()) - } - } - } - v = nextFreeFastResult - if v == 0 { - v, span, checkGCTrigger = c.nextFree(spc) - } - x = unsafe.Pointer(v) - } - - if span.needzero != 0 { - memclrNoHeapPointers(x, elemsize) - } - if goarch.PtrSize == 8 && elemsize == 8 { - - c.scanAlloc += 8 - } else { - dataSize := size - x := uintptr(x) - - if doubleCheckHeapSetType && (!heapBitsInSpan(dataSize) || !heapBitsInSpan(128)) { - throw("tried to write heap bits, but no heap bits in span") - } - - src0 := readUintptr(getGCMask(typ)) - - const elemsize = 128 - - var scanSize uintptr - src := src0 - if typ.Size_ == goarch.PtrSize { - src = (1 << (dataSize / goarch.PtrSize)) - 1 - - scanSize = dataSize - } else { - - if doubleCheckHeapSetType && !asanenabled && dataSize%typ.Size_ != 0 { - throw("runtime: (*mspan).writeHeapBitsSmall: dataSize is not a multiple of typ.Size_") - } - scanSize = typ.PtrBytes - for i := typ.Size_; i < dataSize; i += typ.Size_ { - src |= src0 << (i / goarch.PtrSize) - scanSize += typ.Size_ - } - } - - dstBase, _ := spanHeapBitsRange(span.base(), pageSize, elemsize) - dst := unsafe.Pointer(dstBase) - o := (x - span.base()) / goarch.PtrSize - i := o / ptrBits - j := o % ptrBits - var bits uintptr = elemsize / goarch.PtrSize - - var bitsIsPowerOfTwo = bits&(bits-1) == 0 - if bits > ptrBits || (!bitsIsPowerOfTwo && j+bits > ptrBits) { - - bits0 := ptrBits - j - bits1 := bits - bits0 - dst0 := (*uintptr)(add(dst, (i+0)*goarch.PtrSize)) - dst1 := (*uintptr)(add(dst, (i+1)*goarch.PtrSize)) - *dst0 = (*dst0)&(^uintptr(0)>>bits0) | (src << j) - *dst1 = (*dst1)&^((1<> bits0) - } else { - - dst := (*uintptr)(add(dst, i*goarch.PtrSize)) - *dst = (*dst)&^(((1<<(min(bits, ptrBits)))-1)< 0) - - if forceSlowPath { - - return mallocgcTinySlowPath(size, typ, needzero) - - const spc = spanClass(2<<1) | spanClass(1) - const elemsize = uintptr(16) - return mallocgcSlowPathStub(size, typ, needzero, spc, elemsize) - } - - if doubleCheckMalloc { - if gcphase == _GCmarktermination { - throw("mallocgc called with gcphase == _GCmarktermination") - } - } - - lockRankMayQueueFinalizer() - - const elemsize = 16 - - mp := acquirem() - if doubleCheckMalloc { - doubleCheckTiny(size, typ, mp) - } - mp.mallocing = 1 - - c := getMCache(mp) - off := c.tinyoffset - - if size&7 == 0 { - off = alignUp(off, 8) - } else if goarch.PtrSize == 4 && size == 12 { - - off = alignUp(off, 8) - } else if size&3 == 0 { - off = alignUp(off, 4) - } else if size&1 == 0 { - off = alignUp(off, 2) - } - if off+size <= maxTinySize && c.tiny != 0 { - - x := unsafe.Pointer(c.tiny + off) - c.tinyoffset = off + size - c.tinyAllocs++ - mp.mallocing = 0 - releasem(mp) - const elemsize = 0 - - return x - } - - checkGCTrigger := false - span := c.alloc[tinySpanClass] - - const nbytes = 8192 - const nelems = uint16((nbytes - unsafe.Sizeof(spanInlineMarkBits{})) / 16) - var nextFreeFastResult gclinkptr - if span.allocCache != 0 { - theBit := sys.TrailingZeros64(span.allocCache) - result := span.freeindex + uint16(theBit) - if result < nelems { - freeidx := result + 1 - if !(freeidx%64 == 0 && freeidx != nelems) { - span.allocCache >>= uint(theBit + 1) - span.freeindex = freeidx - span.allocCount++ - nextFreeFastResult = gclinkptr(uintptr(result)*16 + span.base()) - } - } - } - v := nextFreeFastResult - if v == 0 { - v, span, checkGCTrigger = c.nextFree(tinySpanClass) - } - x := unsafe.Pointer(v) - (*[2]uint64)(x)[0] = 0 - (*[2]uint64)(x)[1] = 0 - - if !raceenabled && (size < c.tinyoffset || c.tiny == 0) { - - c.tiny = uintptr(x) - c.tinyoffset = size - } - - publicationBarrier() - - span.freeIndexForScan = span.freeindex - - c.nextSample -= int64(elemsize) - if c.nextSample < 0 || MemProfileRate != c.memProfRate { - profilealloc(mp, x, elemsize) - } - mp.mallocing = 0 - releasem(mp) - - if checkGCTrigger { - if t := (gcTrigger{kind: gcTriggerHeap}); t.test() { - gcStart(t) - } - } - - return x -} - -func mallocgcSmallNoScanSC2(size uintptr, typ *_type, needzero bool) unsafe.Pointer { - - forceSlowPath := debug.malloc || gcBlackenEnabled != 0 || (goexperiment.RuntimeSecret && getg().secret > 0) - - if forceSlowPath { - - const spc = spanClass(2<<1) | spanClass(1) - const elemsize = uintptr(16) - return mallocgcSmallNoScanSlowPath(size, typ, needzero, spc, elemsize) - } - - if doubleCheckMalloc { - if gcphase == _GCmarktermination { - throw("mallocgc called with gcphase == _GCmarktermination") - } - } - - lockRankMayQueueFinalizer() - - const sizeclass = 2 - const elemsize = 16 - - mp := acquirem() - if doubleCheckMalloc { - - doubleCheckSmallNoScan(typ, mp) - - } - mp.mallocing = 1 - - checkGCTrigger := false - c := getMCache(mp) - const spc = spanClass(sizeclass<<1) | spanClass(1) - span := c.alloc[spc] - - var v gclinkptr - var x unsafe.Pointer - - if runtimeFreegcEnabled && c.hasReusableNoscan(spc) { - - x = mallocgcSmallNoscanReuse(c, span, spc, elemsize, needzero) - mp.mallocing = 0 - releasem(mp) - - return x - } - - { - - var nextFreeFastResult gclinkptr - if span.allocCache != 0 { - theBit := sys.TrailingZeros64(span.allocCache) - result := span.freeindex + uint16(theBit) - if result < span.nelems { - freeidx := result + 1 - if !(freeidx%64 == 0 && freeidx != span.nelems) { - span.allocCache >>= uint(theBit + 1) - span.freeindex = freeidx - span.allocCount++ - nextFreeFastResult = gclinkptr(uintptr(result)*elemsize + span.base()) - } - } - } - v = nextFreeFastResult - if v == 0 { - v, span, checkGCTrigger = c.nextFree(spc) - } - x = unsafe.Pointer(v) - } - - if needzero && span.needzero != 0 { - memclrNoHeapPointers(x, elemsize) - } - - publicationBarrier() - - span.freeIndexForScan = span.freeindex - - c.nextSample -= int64(elemsize) - if c.nextSample < 0 || MemProfileRate != c.memProfRate { - profilealloc(mp, x, elemsize) - } - mp.mallocing = 0 - releasem(mp) - - if checkGCTrigger { - if t := (gcTrigger{kind: gcTriggerHeap}); t.test() { - gcStart(t) - } - } - - return x -} - -func mallocgcSmallNoScanSC3(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcTinySC2(size uintptr, typ *_type, needzero bool) unsafe.Pointer { forceSlowPath := debug.malloc || gcBlackenEnabled != 0 || (goexperiment.RuntimeSecret && getg().secret > 0) if forceSlowPath { - const spc = spanClass(3<<1) | spanClass(1) - const elemsize = uintptr(24) - return mallocgcSmallNoScanSlowPath(size, typ, needzero, spc, elemsize) + return mallocgcTinySlowPath(size, typ, needzero) + + const spc = spanClass(2<<1) | spanClass(1) + const elemsize = uintptr(16) + return mallocgcSlowPathStub(size, typ, needzero, spc, elemsize) } if doubleCheckMalloc { @@ -1720,153 +1074,70 @@ func mallocgcSmallNoScanSC3(size uintptr, typ *_type, needzero bool) unsafe.Poin lockRankMayQueueFinalizer() - const sizeclass = 3 - const elemsize = 24 + const elemsize = 16 mp := acquirem() if doubleCheckMalloc { - - doubleCheckSmallNoScan(typ, mp) - + doubleCheckTiny(size, typ, mp) } mp.mallocing = 1 - checkGCTrigger := false c := getMCache(mp) - const spc = spanClass(sizeclass<<1) | spanClass(1) - span := c.alloc[spc] + off := c.tinyoffset - var v gclinkptr - var x unsafe.Pointer + if size&7 == 0 { + off = alignUp(off, 8) + } else if goarch.PtrSize == 4 && size == 12 { - if runtimeFreegcEnabled && c.hasReusableNoscan(spc) { + off = alignUp(off, 8) + } else if size&3 == 0 { + off = alignUp(off, 4) + } else if size&1 == 0 { + off = alignUp(off, 2) + } + if off+size <= maxTinySize && c.tiny != 0 { - x = mallocgcSmallNoscanReuse(c, span, spc, elemsize, needzero) + x := unsafe.Pointer(c.tiny + off) + c.tinyoffset = off + size + c.tinyAllocs++ mp.mallocing = 0 releasem(mp) + const elemsize = 0 return x } - { + checkGCTrigger := false + span := c.alloc[tinySpanClass] - var nextFreeFastResult gclinkptr - if span.allocCache != 0 { - theBit := sys.TrailingZeros64(span.allocCache) - result := span.freeindex + uint16(theBit) - if result < span.nelems { - freeidx := result + 1 - if !(freeidx%64 == 0 && freeidx != span.nelems) { - span.allocCache >>= uint(theBit + 1) - span.freeindex = freeidx - span.allocCount++ - nextFreeFastResult = gclinkptr(uintptr(result)*elemsize + span.base()) - } + const nbytes = 8192 + const nelems = uint16((nbytes - unsafe.Sizeof(spanInlineMarkBits{})) / 16) + var nextFreeFastResult gclinkptr + if span.allocCache != 0 { + theBit := sys.TrailingZeros64(span.allocCache) + result := span.freeindex + uint16(theBit) + if result < nelems { + freeidx := result + 1 + if !(freeidx%64 == 0 && freeidx != nelems) { + span.allocCache >>= uint(theBit + 1) + span.freeindex = freeidx + span.allocCount++ + nextFreeFastResult = gclinkptr(uintptr(result)*16 + span.base()) } } - v = nextFreeFastResult - if v == 0 { - v, span, checkGCTrigger = c.nextFree(spc) - } - x = unsafe.Pointer(v) - } - - if needzero && span.needzero != 0 { - memclrNoHeapPointers(x, elemsize) - } - - publicationBarrier() - - span.freeIndexForScan = span.freeindex - - c.nextSample -= int64(elemsize) - if c.nextSample < 0 || MemProfileRate != c.memProfRate { - profilealloc(mp, x, elemsize) - } - mp.mallocing = 0 - releasem(mp) - - if checkGCTrigger { - if t := (gcTrigger{kind: gcTriggerHeap}); t.test() { - gcStart(t) - } - } - - return x -} - -func mallocgcSmallNoScanSC4(size uintptr, typ *_type, needzero bool) unsafe.Pointer { - - forceSlowPath := debug.malloc || gcBlackenEnabled != 0 || (goexperiment.RuntimeSecret && getg().secret > 0) - - if forceSlowPath { - - const spc = spanClass(4<<1) | spanClass(1) - const elemsize = uintptr(32) - return mallocgcSmallNoScanSlowPath(size, typ, needzero, spc, elemsize) - } - - if doubleCheckMalloc { - if gcphase == _GCmarktermination { - throw("mallocgc called with gcphase == _GCmarktermination") - } - } - - lockRankMayQueueFinalizer() - - const sizeclass = 4 - const elemsize = 32 - - mp := acquirem() - if doubleCheckMalloc { - - doubleCheckSmallNoScan(typ, mp) - } - mp.mallocing = 1 - - checkGCTrigger := false - c := getMCache(mp) - const spc = spanClass(sizeclass<<1) | spanClass(1) - span := c.alloc[spc] - - var v gclinkptr - var x unsafe.Pointer - - if runtimeFreegcEnabled && c.hasReusableNoscan(spc) { - - x = mallocgcSmallNoscanReuse(c, span, spc, elemsize, needzero) - mp.mallocing = 0 - releasem(mp) - - return x + v := nextFreeFastResult + if v == 0 { + v, span, checkGCTrigger = c.nextFree(tinySpanClass) } + x := unsafe.Pointer(v) + (*[2]uint64)(x)[0] = 0 + (*[2]uint64)(x)[1] = 0 - { - - var nextFreeFastResult gclinkptr - if span.allocCache != 0 { - theBit := sys.TrailingZeros64(span.allocCache) - result := span.freeindex + uint16(theBit) - if result < span.nelems { - freeidx := result + 1 - if !(freeidx%64 == 0 && freeidx != span.nelems) { - span.allocCache >>= uint(theBit + 1) - span.freeindex = freeidx - span.allocCount++ - nextFreeFastResult = gclinkptr(uintptr(result)*elemsize + span.base()) - } - } - } - v = nextFreeFastResult - if v == 0 { - v, span, checkGCTrigger = c.nextFree(spc) - } - x = unsafe.Pointer(v) - } + if !raceenabled && (size < c.tinyoffset || c.tiny == 0) { - if needzero && span.needzero != 0 { - memclrNoHeapPointers(x, elemsize) + c.tiny = uintptr(x) + c.tinyoffset = size } publicationBarrier() @@ -1889,14 +1160,14 @@ func mallocgcSmallNoScanSC4(size uintptr, typ *_type, needzero bool) unsafe.Poin return x } -func mallocgcSmallNoScanSC5(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcSmallNoScanSC2(size uintptr, typ *_type, needzero bool) unsafe.Pointer { forceSlowPath := debug.malloc || gcBlackenEnabled != 0 || (goexperiment.RuntimeSecret && getg().secret > 0) if forceSlowPath { - const spc = spanClass(5<<1) | spanClass(1) - const elemsize = uintptr(48) + const spc = spanClass(2<<1) | spanClass(1) + const elemsize = uintptr(16) return mallocgcSmallNoScanSlowPath(size, typ, needzero, spc, elemsize) } @@ -1908,8 +1179,8 @@ func mallocgcSmallNoScanSC5(size uintptr, typ *_type, needzero bool) unsafe.Poin lockRankMayQueueFinalizer() - const sizeclass = 5 - const elemsize = 48 + const sizeclass = 2 + const elemsize = 16 mp := acquirem() if doubleCheckMalloc { @@ -1983,14 +1254,14 @@ func mallocgcSmallNoScanSC5(size uintptr, typ *_type, needzero bool) unsafe.Poin return x } -func mallocgcSmallNoScanSC6(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcSmallNoScanSC3(size uintptr, typ *_type, needzero bool) unsafe.Pointer { forceSlowPath := debug.malloc || gcBlackenEnabled != 0 || (goexperiment.RuntimeSecret && getg().secret > 0) if forceSlowPath { - const spc = spanClass(6<<1) | spanClass(1) - const elemsize = uintptr(64) + const spc = spanClass(3<<1) | spanClass(1) + const elemsize = uintptr(24) return mallocgcSmallNoScanSlowPath(size, typ, needzero, spc, elemsize) } @@ -2002,8 +1273,8 @@ func mallocgcSmallNoScanSC6(size uintptr, typ *_type, needzero bool) unsafe.Poin lockRankMayQueueFinalizer() - const sizeclass = 6 - const elemsize = 64 + const sizeclass = 3 + const elemsize = 24 mp := acquirem() if doubleCheckMalloc { @@ -2077,14 +1348,14 @@ func mallocgcSmallNoScanSC6(size uintptr, typ *_type, needzero bool) unsafe.Poin return x } -func mallocgcSmallNoScanSC7(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcSmallNoScanSC4(size uintptr, typ *_type, needzero bool) unsafe.Pointer { forceSlowPath := debug.malloc || gcBlackenEnabled != 0 || (goexperiment.RuntimeSecret && getg().secret > 0) if forceSlowPath { - const spc = spanClass(7<<1) | spanClass(1) - const elemsize = uintptr(80) + const spc = spanClass(4<<1) | spanClass(1) + const elemsize = uintptr(32) return mallocgcSmallNoScanSlowPath(size, typ, needzero, spc, elemsize) } @@ -2096,8 +1367,8 @@ func mallocgcSmallNoScanSC7(size uintptr, typ *_type, needzero bool) unsafe.Poin lockRankMayQueueFinalizer() - const sizeclass = 7 - const elemsize = 80 + const sizeclass = 4 + const elemsize = 32 mp := acquirem() if doubleCheckMalloc { @@ -2171,14 +1442,14 @@ func mallocgcSmallNoScanSC7(size uintptr, typ *_type, needzero bool) unsafe.Poin return x } -func mallocgcSmallNoScanSC8(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcSmallNoScanSC5(size uintptr, typ *_type, needzero bool) unsafe.Pointer { forceSlowPath := debug.malloc || gcBlackenEnabled != 0 || (goexperiment.RuntimeSecret && getg().secret > 0) if forceSlowPath { - const spc = spanClass(8<<1) | spanClass(1) - const elemsize = uintptr(96) + const spc = spanClass(5<<1) | spanClass(1) + const elemsize = uintptr(48) return mallocgcSmallNoScanSlowPath(size, typ, needzero, spc, elemsize) } @@ -2190,8 +1461,8 @@ func mallocgcSmallNoScanSC8(size uintptr, typ *_type, needzero bool) unsafe.Poin lockRankMayQueueFinalizer() - const sizeclass = 8 - const elemsize = 96 + const sizeclass = 5 + const elemsize = 48 mp := acquirem() if doubleCheckMalloc { @@ -2265,14 +1536,14 @@ func mallocgcSmallNoScanSC8(size uintptr, typ *_type, needzero bool) unsafe.Poin return x } -func mallocgcSmallNoScanSC9(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcSmallNoScanSC6(size uintptr, typ *_type, needzero bool) unsafe.Pointer { forceSlowPath := debug.malloc || gcBlackenEnabled != 0 || (goexperiment.RuntimeSecret && getg().secret > 0) if forceSlowPath { - const spc = spanClass(9<<1) | spanClass(1) - const elemsize = uintptr(112) + const spc = spanClass(6<<1) | spanClass(1) + const elemsize = uintptr(64) return mallocgcSmallNoScanSlowPath(size, typ, needzero, spc, elemsize) } @@ -2284,8 +1555,8 @@ func mallocgcSmallNoScanSC9(size uintptr, typ *_type, needzero bool) unsafe.Poin lockRankMayQueueFinalizer() - const sizeclass = 9 - const elemsize = 112 + const sizeclass = 6 + const elemsize = 64 mp := acquirem() if doubleCheckMalloc { @@ -2359,14 +1630,14 @@ func mallocgcSmallNoScanSC9(size uintptr, typ *_type, needzero bool) unsafe.Poin return x } -func mallocgcSmallNoScanSC10(size uintptr, typ *_type, needzero bool) unsafe.Pointer { +func mallocgcSmallNoScanSC7(size uintptr, typ *_type, needzero bool) unsafe.Pointer { forceSlowPath := debug.malloc || gcBlackenEnabled != 0 || (goexperiment.RuntimeSecret && getg().secret > 0) if forceSlowPath { - const spc = spanClass(10<<1) | spanClass(1) - const elemsize = uintptr(128) + const spc = spanClass(7<<1) | spanClass(1) + const elemsize = uintptr(80) return mallocgcSmallNoScanSlowPath(size, typ, needzero, spc, elemsize) } @@ -2378,8 +1649,8 @@ func mallocgcSmallNoScanSC10(size uintptr, typ *_type, needzero bool) unsafe.Poi lockRankMayQueueFinalizer() - const sizeclass = 10 - const elemsize = 128 + const sizeclass = 7 + const elemsize = 80 mp := acquirem() if doubleCheckMalloc { diff --git a/src/runtime/malloc_tables_generated.go b/src/runtime/malloc_tables_generated.go index fbba92e1ca1982..32f4317d699eec 100644 --- a/src/runtime/malloc_tables_generated.go +++ b/src/runtime/malloc_tables_generated.go @@ -5,7 +5,7 @@ package runtime import "unsafe" -var mallocScanTable = [129]func(size uintptr, typ *_type, needzero bool) unsafe.Pointer{mallocPanic, +var mallocScanTable = [81]func(size uintptr, typ *_type, needzero bool) unsafe.Pointer{mallocPanic, mallocgcSmallScanNoHeaderSC1, mallocgcSmallScanNoHeaderSC1, mallocgcSmallScanNoHeaderSC1, @@ -86,58 +86,9 @@ var mallocScanTable = [129]func(size uintptr, typ *_type, needzero bool) unsafe. mallocgcSmallScanNoHeaderSC7, mallocgcSmallScanNoHeaderSC7, mallocgcSmallScanNoHeaderSC7, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC8, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC9, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, - mallocgcSmallScanNoHeaderSC10, } -var mallocNoScanTable = [129]func(size uintptr, typ *_type, needzero bool) unsafe.Pointer{ - mallocPanic, +var mallocNoScanTable = [81]func(size uintptr, typ *_type, needzero bool) unsafe.Pointer{mallocPanic, mallocPanic, mallocPanic, mallocPanic, @@ -218,52 +169,4 @@ var mallocNoScanTable = [129]func(size uintptr, typ *_type, needzero bool) unsaf mallocgcSmallNoScanSC7, mallocgcSmallNoScanSC7, mallocgcSmallNoScanSC7, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC8, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC9, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, - mallocgcSmallNoScanSC10, } From 6a002d147445dd468bd07922a298f2fb61164ee2 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 20 May 2026 15:05:58 -0400 Subject: [PATCH 08/18] cmd/dist: pass -std to assembler Like CL 761200, pass the -std flag to the assembler during bootstrap. Change-Id: I37931c21ed33bbaefebfe3e66cc8bd7a503b5185 Reviewed-on: https://go-review.googlesource.com/c/go/+/780402 Reviewed-by: Michael Pratt LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/cmd/dist/build.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index de2c7be2e833f9..78d55bec559987 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -924,6 +924,7 @@ func runInstall(pkg string, ch chan struct{}) { "-D", "GOARCH_" + goarch, "-D", "GOOS_GOARCH_" + goos + "_" + goarch, "-p", pkg, + "-std", } if goarch == "mips" || goarch == "mipsle" { // Define GOMIPS_value from gomips. From 4dde0f6c368fb041517d97f2e6bfcf9fcaee9d7e Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 20 May 2026 14:38:47 -0400 Subject: [PATCH 09/18] all: use linknamestd for new linknames For linknames within the standard library, we can use the new linknamestd pragma. Apply it to linknames added in 1.27 cycle, as they cannot be accessed externally. Change-Id: I97f78ddcb6ca27718337dcfc8d3c581a5acd2b73 Reviewed-on: https://go-review.googlesource.com/c/go/+/780680 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Michael Pratt --- src/internal/cpu/cpu_windows.go | 2 +- src/internal/runtime/atomic/linkname.go | 48 ++++++++++++------------- src/internal/runtime/maps/runtime.go | 2 +- src/reflect/type.go | 4 ++- src/runtime/os_windows.go | 2 +- src/runtime/runtime1.go | 4 +-- 6 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/internal/cpu/cpu_windows.go b/src/internal/cpu/cpu_windows.go index e921a9566ea767..3587c0dbbbad07 100644 --- a/src/internal/cpu/cpu_windows.go +++ b/src/internal/cpu/cpu_windows.go @@ -16,5 +16,5 @@ const ( // isProcessorFeaturePresent calls windows IsProcessorFeaturePresent API. // -//go:linkname isProcessorFeaturePresent +//go:linknamestd isProcessorFeaturePresent func isProcessorFeaturePresent(processorFeature uint32) bool // Implemented in runtime package. diff --git a/src/internal/runtime/atomic/linkname.go b/src/internal/runtime/atomic/linkname.go index e5ddcf76e0dd96..72636465fb87d7 100644 --- a/src/internal/runtime/atomic/linkname.go +++ b/src/internal/runtime/atomic/linkname.go @@ -8,27 +8,27 @@ import _ "unsafe" // for linkname // Export some functions via linkname to assembly in sync/atomic. // -//go:linkname Load -//go:linkname Loadp -//go:linkname Load64 -//go:linkname Loaduintptr -//go:linkname Xadd -//go:linkname Xadd64 -//go:linkname Xadduintptr -//go:linkname Xchg -//go:linkname Xchg64 -//go:linkname Xchguintptr -//go:linkname Cas -//go:linkname Cas64 -//go:linkname Casint32 -//go:linkname Casint64 -//go:linkname Casuintptr -//go:linkname Store -//go:linkname Store64 -//go:linkname Storeuintptr -//go:linkname And32 -//go:linkname And64 -//go:linkname Anduintptr -//go:linkname Or32 -//go:linkname Or64 -//go:linkname Oruintptr +//go:linknamestd Load +//go:linknamestd Loadp +//go:linknamestd Load64 +//go:linknamestd Loaduintptr +//go:linknamestd Xadd +//go:linknamestd Xadd64 +//go:linknamestd Xadduintptr +//go:linknamestd Xchg +//go:linknamestd Xchg64 +//go:linknamestd Xchguintptr +//go:linknamestd Cas +//go:linknamestd Cas64 +//go:linknamestd Casint32 +//go:linknamestd Casint64 +//go:linknamestd Casuintptr +//go:linknamestd Store +//go:linknamestd Store64 +//go:linknamestd Storeuintptr +//go:linknamestd And32 +//go:linknamestd And64 +//go:linknamestd Anduintptr +//go:linknamestd Or32 +//go:linknamestd Or64 +//go:linknamestd Oruintptr diff --git a/src/internal/runtime/maps/runtime.go b/src/internal/runtime/maps/runtime.go index 39017c6fa88b65..4b6051d73ee84c 100644 --- a/src/internal/runtime/maps/runtime.go +++ b/src/internal/runtime/maps/runtime.go @@ -19,7 +19,7 @@ import ( //go:linkname fatal func fatal(s string) -//go:linkname bootstrapRand runtime.bootstrapRand +//go:linknamestd bootstrapRand runtime.bootstrapRand func bootstrapRand() uint64 //go:linkname rand diff --git a/src/reflect/type.go b/src/reflect/type.go index f03bc322fec8fd..cb040037b771b1 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1719,6 +1719,8 @@ func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool { // there can be more than one with a given string. // Only types we might want to look up are included: // pointers, channels, maps, slices, and arrays. +// +//go:linknamestd compiledTypelinks func compiledTypelinks() ([]*abi.Type, [][]*abi.Type) // rtypeOff should be an internal detail, @@ -2775,7 +2777,7 @@ func adjustAIXGCData(addr *byte) *byte { // adjustAIXGCDataForRuntime adjusts the GCData field pointer // as the runtime requires for AIX. See runtime.getGCMaskOnDemand. // -//go:linkname adjustAIXGCDataForRuntime +//go:linknamestd adjustAIXGCDataForRuntime //go:noescape func adjustAIXGCDataForRuntime(*byte) *byte diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index 5af1b037886479..42af4200547b64 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -263,7 +263,7 @@ func windows_QueryPerformanceFrequency() int64 { return frequency } -//go:linkname cpu_isProcessorFeaturePresent internal/cpu.isProcessorFeaturePresent +//go:linknamestd cpu_isProcessorFeaturePresent internal/cpu.isProcessorFeaturePresent func cpu_isProcessorFeaturePresent(processorFeature uint32) bool { ret := stdcall(_IsProcessorFeaturePresent, uintptr(processorFeature)) return ret != 0 diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index 835aa8ecedb484..97f3d8e8878b64 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -655,7 +655,7 @@ func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { // slice for the main module, and a slice of slices, normally nil, // for other modules. // -//go:linkname reflect_compiledTypelinks reflect.compiledTypelinks +//go:linknamestd reflect_compiledTypelinks reflect.compiledTypelinks func reflect_compiledTypelinks() ([]*abi.Type, [][]*abi.Type) { modules := activeModules() firstTypes := moduleTypelinks(modules[0]) @@ -753,7 +753,7 @@ func reflect_addReflectOff(ptr unsafe.Pointer) int32 { // the new address to use. This is only called on AIX. // See getGCMaskOnDemand. // -//go:linkname reflect_adjustAIXGCDataForRuntime reflect.adjustAIXGCDataForRuntime +//go:linknamestd reflect_adjustAIXGCDataForRuntime reflect.adjustAIXGCDataForRuntime func reflect_adjustAIXGCDataForRuntime(addr *byte) *byte { return (*byte)(add(unsafe.Pointer(addr), aixStaticDataBase-firstmoduledata.data)) } From 4a38094e42de833f859fba85d1de7f6a32204abe Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Tue, 24 Mar 2026 09:41:49 -0700 Subject: [PATCH 10/18] database/sql: add RowsColumnScanner, expose ConvertAssign Add a new optional interface for driver.Rows which permits the driver to scan directly into the user-provided []any. Export the convertAssign function, to permit drivers to fall back to the old assignment path. Using the prior Rows interface, a driver provides values with a function like: func (rows *Rows) Next(dest []Value) error { dest[0] = "some value" return nil } Using the new RowsColumnScanner interface, the equivalent is: func (rows *Rows) ScanColumn(scanCtx driver.ScanContext, index int, dest any) error { return sql.ConvertAssign(scanCtx, dest, "some value") } Fixes #67546 Change-Id: I421f5639a12c78c76d377534b5a82f846a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/777961 Reviewed-by: Austin Clements Reviewed-by: Alan Donovan LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- api/next/67546.txt | 8 + .../6-stdlib/99-minor/database/sql/67546.md | 2 + .../99-minor/database/sql/driver/67546.md | 2 + src/database/sql/convert.go | 24 ++- src/database/sql/convert_test.go | 11 + src/database/sql/driver/driver.go | 23 +++ src/database/sql/fakedb_test.go | 12 ++ src/database/sql/internal/sql.go | 22 ++ src/database/sql/sql.go | 49 ++++- src/database/sql/sql_test.go | 190 +++++++++++++++++- 10 files changed, 328 insertions(+), 15 deletions(-) create mode 100644 api/next/67546.txt create mode 100644 doc/next/6-stdlib/99-minor/database/sql/67546.md create mode 100644 doc/next/6-stdlib/99-minor/database/sql/driver/67546.md create mode 100644 src/database/sql/internal/sql.go diff --git a/api/next/67546.txt b/api/next/67546.txt new file mode 100644 index 00000000000000..1ef3bcaa08e178 --- /dev/null +++ b/api/next/67546.txt @@ -0,0 +1,8 @@ +pkg database/sql, func ConvertAssign(driver.ScanContext, interface{}, driver.Value) error #67546 +pkg database/sql/driver, type RowsColumnScanner interface { Close, Columns, Next, NextRow, ScanColumn } #67546 +pkg database/sql/driver, type RowsColumnScanner interface, Close() error #67546 +pkg database/sql/driver, type RowsColumnScanner interface, Columns() []string #67546 +pkg database/sql/driver, type RowsColumnScanner interface, Next([]Value) error #67546 +pkg database/sql/driver, type RowsColumnScanner interface, NextRow() error #67546 +pkg database/sql/driver, type RowsColumnScanner interface, ScanColumn(ScanContext, int, interface{}) error #67546 +pkg database/sql/driver, type ScanContext struct #67546 diff --git a/doc/next/6-stdlib/99-minor/database/sql/67546.md b/doc/next/6-stdlib/99-minor/database/sql/67546.md new file mode 100644 index 00000000000000..53bf69eb5fcbdb --- /dev/null +++ b/doc/next/6-stdlib/99-minor/database/sql/67546.md @@ -0,0 +1,2 @@ +The new [ConvertAssign] function gives database drivers access +to the type conversions performed by [Rows.Scan]. diff --git a/doc/next/6-stdlib/99-minor/database/sql/driver/67546.md b/doc/next/6-stdlib/99-minor/database/sql/driver/67546.md new file mode 100644 index 00000000000000..f618ede8bfee92 --- /dev/null +++ b/doc/next/6-stdlib/99-minor/database/sql/driver/67546.md @@ -0,0 +1,2 @@ +Drivers may implement the new [RowsColumnScanner] interface +to scan directly into user-provided destinations. diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go index 25bf433edc2b64..e965d09b45654c 100644 --- a/src/database/sql/convert.go +++ b/src/database/sql/convert.go @@ -9,6 +9,7 @@ package sql import ( "bytes" "database/sql/driver" + "database/sql/internal" "errors" "fmt" "reflect" @@ -219,10 +220,25 @@ func driverArgsConnLocked(ci driver.Conn, ds *driverStmt, args []any) ([]driver. // See go.dev/issue/67401. // //go:linkname convertAssign -func convertAssign(dest, src any) error { +func convertAssign(dest any, src any) error { return convertAssignRows(dest, src, nil) } +// ConvertAssign copies the value in src to the value pointed at by dest. +// See the documentation on [Rows.Scan] for details on conversions. +// dest must be a pointer or must implement [Scanner]. +// +// Implementations of [driver.RowsColumnScanner] should pass through +// their [driver.ScanContext] parameter. +// In other cases, pass driver.ScanContext{} as the context. +// +// ConvertAssign is intended for use by driver implementations. +// Most users should not need to use it directly. +func ConvertAssign(scanCtx driver.ScanContext, dest any, src driver.Value) error { + rows, _ := internal.ScanContextValue(internal.ScanContext(scanCtx)).(*Rows) + return convertAssignRows(dest, src, rows) +} + // convertAssignRows copies to dest the value in src, converting it if possible. // An error is returned if the copy would result in loss of information. // dest should be a pointer type. If rows is passed in, the rows will @@ -353,8 +369,8 @@ func convertAssignRows(dest, src any, rows *Rows) error { } // The driver is returning a cursor the client may iterate over. case driver.Rows: - switch d := dest.(type) { - case *Rows: + d, ok := dest.(*Rows) + if ok { if d == nil { return errNilPtr } @@ -387,7 +403,7 @@ func convertAssignRows(dest, src any, rows *Rows) error { parentCancel := rows.cancel rows.cancel = func() { // When Rows.cancel is called, the closemu will be locked as well. - // So we can access rs.lasterr. + // So we can access rows.lasterr. d.close(rows.lasterr) if parentCancel != nil { parentCancel() diff --git a/src/database/sql/convert_test.go b/src/database/sql/convert_test.go index 1294d51d8308db..10ae9acbd81f04 100644 --- a/src/database/sql/convert_test.go +++ b/src/database/sql/convert_test.go @@ -624,3 +624,14 @@ func TestDecimal(t *testing.T) { }) } } + +func TestConvertAssignNoContext(t *testing.T) { + const want = 42 + var got int64 + if err := ConvertAssign(driver.ScanContext{}, &got, want); err != nil { + t.Fatalf("ConvertAssign: %v", err) + } + if got != int64(want) { + t.Errorf("after ConvertAssign: got %v, want %v", got, want) + } +} diff --git a/src/database/sql/driver/driver.go b/src/database/sql/driver/driver.go index d0892e80fc28d5..264fd67b8c236d 100644 --- a/src/database/sql/driver/driver.go +++ b/src/database/sql/driver/driver.go @@ -40,6 +40,7 @@ package driver import ( "context" + "database/sql/internal" "errors" "reflect" ) @@ -443,6 +444,28 @@ type Rows interface { Next(dest []Value) error } +// ScanContext carries state related to the current query +// through a [RowsColumnScanner.ScanColumn] function to [database/sql.ConvertAssign]. +type ScanContext internal.ScanContext + +// RowsColumnScanner extends the [Rows] interface by providing a way for the driver +// to scan directly into the user-provided destination. +// +// RowsColumnScanner supersedes the [Rows.Next] method. +type RowsColumnScanner interface { + Rows + + // NextRow advances to the next row of data. + // It should return io.EOF when there are no more rows. + NextRow() error + + // ScanColumn copies the column at the given index in the current row + // into the value pointed to by dest. + // + // The driver may assign a driver.Value to dest using [database/sql.ConvertAssign]. + ScanColumn(scanCtx ScanContext, index int, dest any) error +} + // RowsNextResultSet extends the [Rows] interface by providing a way to signal // the driver to advance to the next result set. type RowsNextResultSet interface { diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go index 23715e221f2149..d59275aa2c75f5 100644 --- a/src/database/sql/fakedb_test.go +++ b/src/database/sql/fakedb_test.go @@ -79,6 +79,16 @@ func (c *fakeConn) getFakeConn() *fakeConn { return c } +func getRowsCursor(rs *Rows) *rowsCursor { + return rs.rowsi.(interface { + getRowsCursor() *rowsCursor + }).getRowsCursor() +} + +func (rc *rowsCursor) getRowsCursor() *rowsCursor { + return rc +} + func (c *fakeConnector) Driver() driver.Driver { return fdriver } @@ -1242,6 +1252,8 @@ func converterForType(typ string) driver.ValueConverter { return driver.NotNull{Converter: driver.DefaultParameterConverter} case "nulluuid": return driver.Null{Converter: driver.DefaultParameterConverter} + case "nulltable": + return driver.Null{Converter: driver.DefaultParameterConverter} case "any": return anyTypeConverter{} } diff --git a/src/database/sql/internal/sql.go b/src/database/sql/internal/sql.go new file mode 100644 index 00000000000000..7b7769a0556a67 --- /dev/null +++ b/src/database/sql/internal/sql.go @@ -0,0 +1,22 @@ +// Copyright 2026 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 internal contains internal symbols shared between +// database/sql and database/sql/driver. +package internal + +// ScanContext is database/sql/driver.ScanContext. +// We define it here so driver.ScanContext can be opaque to users but +// visible to database/sql. +type ScanContext struct { + v any +} + +func NewScanContext(v any) ScanContext { + return ScanContext{v} +} + +func ScanContextValue(c ScanContext) any { + return c.v +} diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index 6b7d073359ead3..a7dc70b281b3e1 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -18,6 +18,7 @@ package sql import ( "context" "database/sql/driver" + "database/sql/internal" "errors" "fmt" "io" @@ -2963,10 +2964,16 @@ type Rows struct { // expected not to be called concurrently. hitEOF bool + // nextCalled is set by the first call to Next. + nextCalled bool + // lastcols is only used in Scan, Next, and NextResultSet which are expected // not to be called concurrently. lastcols []driver.Value + // numCols is the number of columns, and is initialized by the first Next call. + numCols int + // raw is a buffer for RawBytes that persists between Scan calls. // This is used when the driver returns a mismatched type that requires // a cloning allocation. For example, if the driver returns a *string and @@ -3065,11 +3072,20 @@ func (rs *Rows) nextLocked() (doClose, ok bool) { rs.dc.Lock() defer rs.dc.Unlock() - if rs.lastcols == nil { - rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns())) + if !rs.nextCalled { + rs.numCols = len(rs.rowsi.Columns()) + rs.nextCalled = true + } + + if rscan, ok := rs.rowsi.(driver.RowsColumnScanner); ok { + rs.lasterr = rscan.NextRow() + } else { + if rs.lastcols == nil { + rs.lastcols = make([]driver.Value, rs.numCols) + } + rs.lasterr = rs.rowsi.Next(rs.lastcols) } - rs.lasterr = rs.rowsi.Next(rs.lastcols) if rs.lasterr != nil { // Close the connection if there is a driver error. if rs.lasterr != io.EOF { @@ -3117,6 +3133,7 @@ func (rs *Rows) NextResultSet() bool { return false } + rs.nextCalled = false rs.lastcols = nil nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet) if !ok { @@ -3386,6 +3403,11 @@ func (rs *Rows) Scan(dest ...any) error { return err } +// rowsScanContext is used to pass a *Rows through ScanColumn into ConvertAssign. +type rowsScanContext struct { + rs *Rows +} + func (rs *Rows) scanLocked(dest ...any) error { if rs.lasterr != nil && rs.lasterr != io.EOF { return rs.lasterr @@ -3394,11 +3416,26 @@ func (rs *Rows) scanLocked(dest ...any) error { return rs.lasterrOrErrLocked(errRowsClosed) } - if rs.lastcols == nil { + if !rs.nextCalled { return errors.New("sql: Scan called without calling Next") } - if len(dest) != len(rs.lastcols) { - return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest)) + if len(dest) != rs.numCols { + return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", rs.numCols, len(dest)) + } + + if rscan, ok := rs.rowsi.(driver.RowsColumnScanner); ok { + // Lock the driver connection before calling the driver interface + // rowsi to prevent a Tx from rolling back the connection at the same time. + rs.dc.Lock() + defer rs.dc.Unlock() + + for i, d := range dest { + scanCtx := driver.ScanContext(internal.NewScanContext(rs)) + if err := rscan.ScanColumn(scanCtx, i, d); err != nil { + return fmt.Errorf(`sql: Scan error on column index %d, name %q: %w`, i, rs.rowsi.Columns()[i], err) + } + } + return nil } for i, sv := range rs.lastcols { diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go index e202213a4b4f02..1763b3bd3ab24e 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -70,6 +70,16 @@ Test: "Validator", }, }, + { + name: "scancols", + connector: &rowsColumnScannerConnector{name: fakeDBName}, + features: []string{ + "ConnBeginTx", + "NamedValue", + "Validator", + "ScanColumn", + }, + }, } { for _, req := range require { if !slices.Contains(test.features, req) { @@ -1671,6 +1681,68 @@ func testCursorFake(t *testing.T, db *DB) { } } +func TestCursorDoubleRowsPointer(t *testing.T) { + testDatabase(t, testCursorDoubleRowsPointer) +} +func testCursorDoubleRowsPointer(t *testing.T, db *DB) { + exec(t, db, "CREATE|table1|col=string") + exec(t, db, "INSERT|table1|col=value") + exec(t, db, "CREATE|cursor|list=table") + exec(t, db, "INSERT|cursor|list=table1!col") + + rows, err := db.QueryContext(t.Context(), `SELECT|cursor|list|`) + if err != nil { + t.Fatal(err) + } + defer rows.Close() + + if !rows.Next() { + t.Fatal("no rows") + } + var cursor *Rows + if err := rows.Scan(&cursor); err != nil { + t.Fatal(err) + } + defer cursor.Close() + + if !cursor.Next() { + t.Fatal("no child rows") + } + var col string + if err := cursor.Scan(&col); err != nil { + t.Fatal(err) + } + if got, want := col, "value"; got != want { + t.Errorf("read col=%q, want %q", got, want) + } +} + +func TestCursorNull(t *testing.T) { + testDatabase(t, testCursorNull) +} +func testCursorNull(t *testing.T, db *DB) { + exec(t, db, "CREATE|cursor|list=nulltable") + exec(t, db, "INSERT|cursor|list=?", nil) + + rows, err := db.QueryContext(t.Context(), `SELECT|cursor|list|`) + if err != nil { + t.Fatal(err) + } + defer rows.Close() + + if !rows.Next() { + t.Fatal("no rows") + } + + var cursor *Rows + if err := rows.Scan(&cursor); err != nil { + t.Fatal(err) + } + if cursor != nil { + t.Errorf("Scan returned cursor, expected nil") + } +} + // TestCursorCancel exercises calling Rows.Close at various places, // including canceling a cursor (child Rows). func TestCursorCancel(t *testing.T) { @@ -2949,7 +3021,7 @@ func testRowsImplicitClose(t *testing.T, db *DB) { } want, fail := 2, errors.New("fail") - r := rows.rowsi.(*rowsCursor) + r := getRowsCursor(rows) r.errPos, r.err = want, fail got := 0 @@ -2982,10 +3054,7 @@ func testRowsCloseError(t *testing.T, db *DB) { } got := []row{} - rc, ok := rows.rowsi.(*rowsCursor) - if !ok { - t.Fatal("not using *rowsCursor") - } + rc := getRowsCursor(rows) rc.closeErr = errors.New("rowsCursor: failed to close") for rows.Next() { @@ -5594,3 +5663,114 @@ func TestNullTypeScanNil(t *testing.T) { }) } } + +type testStringType struct { + s string +} + +func TestQueryRowsScanner(t *testing.T) { + testDatabase(t, testQueryRowsScanner, requireFeature("ScanColumn")) +} +func testQueryRowsScanner(t *testing.T, db *DB) { + populate(t, db, "people") + rows, err := db.Query("SELECT|people|age,name|") + if err != nil { + t.Fatalf("Query: %v", err) + } + defer rows.Close() + type row struct { + age int + name testStringType + } + got := []row{} + for rows.Next() { + var r row + err = rows.Scan(&r.age, &r.name) + if err != nil { + t.Fatalf("Scan: %v", err) + } + got = append(got, r) + } + err = rows.Err() + if err != nil { + t.Fatalf("Err: %v", err) + } + want := []row{ + {age: 1, name: testStringType{"Alice"}}, + {age: 2, name: testStringType{"Bob"}}, + {age: 3, name: testStringType{"Chris"}}, + } + if !slices.Equal(got, want) { + t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want) + } +} + +type rowsColumnScannerConnector struct { + fakeConnector +} + +func (c *rowsColumnScannerConnector) Connect(ctx context.Context) (driver.Conn, error) { + conn, err := c.fakeConnector.Connect(ctx) + fc := getFakeConn(conn) + return &rowsColumnScannerConn{fc}, err +} + +// rowsColumnScannerConn is a Conn with rows that implement RowsColumnScanner. +type rowsColumnScannerConn struct { + *fakeConn +} + +func (s *rowsColumnScannerConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + stmt, err := s.fakeConn.PrepareContext(ctx, query) + if err != nil { + return nil, err + } + return &rowsColumnScannerStmt{stmt.(*fakeStmt)}, nil +} + +type rowsColumnScannerStmt struct { + *fakeStmt +} + +func (s *rowsColumnScannerStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + rows, err := s.fakeStmt.QueryContext(ctx, args) + if err != nil { + return nil, err + } + return &rowsColumnScannerRows{rowsCursor: rows.(*rowsCursor)}, nil +} + +type rowsColumnScannerRows struct { + *rowsCursor + row []driver.Value +} + +func (c *rowsColumnScannerRows) NextRow() error { + if c.row == nil { + c.row = make([]driver.Value, len(c.rowsCursor.Columns())) + } + return c.rowsCursor.Next(c.row) +} + +func (c *rowsColumnScannerRows) NextResultSet() error { + c.row = nil + return c.rowsCursor.NextResultSet() +} + +func (c *rowsColumnScannerRows) ScanColumn(ctx driver.ScanContext, index int, dest any) error { + if index < 0 || index >= len(c.row) { + return fmt.Errorf("index %v out of range", index) + } + switch d := dest.(type) { + case *testStringType: + switch s := c.row[index].(type) { + case string: + d.s = s + return nil + case []byte: + d.s = string(s) + return nil + } + } + return ConvertAssign(ctx, dest, c.row[index]) +} From c700213f6c5938838bc8c198617fb6cf27152a13 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Tue, 19 May 2026 11:53:19 -0700 Subject: [PATCH 11/18] encoding/json/jsontext: expand Decoder.UnreadBuffer documentation Expand the documentation on Decoder.UnreadBuffer regarding what exactly it returns, what guarantees are provided, and how to properly use it for the most common use-case of obtaining everything else after the last parsed token. Also update documentation in v1 json.Decoder.Buffered method, which is trivially implemented under the hood using Decoder.UnreadBuffer. Updates #79498 Change-Id: I9c4a9350e97b74d77d4a74dd191fba6097ae332a Reviewed-on: https://go-review.googlesource.com/c/go/+/779981 Reviewed-by: Damien Neil LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Michael Pratt Auto-Submit: Damien Neil --- src/encoding/json/jsontext/decode.go | 11 +++++++++++ src/encoding/json/stream.go | 16 ++++++++++++++-- src/encoding/json/v2_stream.go | 16 ++++++++++++++-- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/encoding/json/jsontext/decode.go b/src/encoding/json/jsontext/decode.go index fead9ae657d7bf..282011f1079aa2 100644 --- a/src/encoding/json/jsontext/decode.go +++ b/src/encoding/json/jsontext/decode.go @@ -1134,6 +1134,17 @@ func (d *Decoder) InputOffset() int64 { // UnreadBuffer returns the data remaining in the unread buffer, // which may contain zero or more bytes. +// This is the data already consumed from the input [io.Reader], +// but not yet read by a [Decoder.ReadToken] or [Decoder.ReadValue] call. +// It may contain bytes that do not form valid JSON as it has not yet +// been validated according to the JSON grammar. +// The exact amount of buffered data is an implementation detail +// of the Decoder and may change over time. +// +// It is the caller's responsibility to concatenate this buffer with +// the remainder of the input Reader to obtain the full sequence +// of bytes after the last read JSON token or value. +// // The returned buffer must not be mutated while Decoder continues to be used. // The buffer contents are valid until the next Peek, Read, or Skip call. func (d *Decoder) UnreadBuffer() []byte { diff --git a/src/encoding/json/stream.go b/src/encoding/json/stream.go index fc480c994651d2..eb3907c39a0bc6 100644 --- a/src/encoding/json/stream.go +++ b/src/encoding/json/stream.go @@ -80,8 +80,20 @@ func (dec *Decoder) Decode(v any) error { return err } -// Buffered returns a reader of the data remaining in the Decoder's -// buffer. The reader is valid until the next call to [Decoder.Decode]. +// Buffered returns a reader of the data remaining in the unread buffer, +// which may contain zero or more bytes. +// This is the data already consumed from the input [io.Reader], +// but not yet read by a [Decoder.Decode] or [Decoder.Token] call. +// It may contain bytes that do not form valid JSON as it has not yet +// been validated according to the JSON grammar. +// The exact amount of buffered data is an implementation detail +// of the Decoder and may change over time. +// +// It is the caller's responsibility to concatenate this buffer with +// the remainder of the input Reader to obtain the full sequence +// of bytes after the last decoded JSON value. +// +// The reader is valid until the next call to [Decoder.Decode] or [Decoder.Token]. func (dec *Decoder) Buffered() io.Reader { return bytes.NewReader(dec.buf[dec.scanp:]) } diff --git a/src/encoding/json/v2_stream.go b/src/encoding/json/v2_stream.go index 68cc2591104e79..11656d94bd8dac 100644 --- a/src/encoding/json/v2_stream.go +++ b/src/encoding/json/v2_stream.go @@ -85,8 +85,20 @@ func (dec *Decoder) Decode(v any) error { return jsonv2.Unmarshal(b, v, dec.opts) } -// Buffered returns a reader of the data remaining in the Decoder's -// buffer. The reader is valid until the next call to [Decoder.Decode]. +// Buffered returns a reader of the data remaining in the unread buffer, +// which may contain zero or more bytes. +// This is the data already consumed from the input [io.Reader], +// but not yet read by a [Decoder.Decode] or [Decoder.Token] call. +// It may contain bytes that do not form valid JSON as it has not yet +// been validated according to the JSON grammar. +// The exact amount of buffered data is an implementation detail +// of the Decoder and may change over time. +// +// It is the caller's responsibility to concatenate this buffer with +// the remainder of the input Reader to obtain the full sequence +// of bytes after the last decoded JSON value. +// +// The reader is valid until the next call to [Decoder.Decode] or [Decoder.Token]. func (dec *Decoder) Buffered() io.Reader { return bytes.NewReader(dec.dec.UnreadBuffer()) } From f571fc93b05e8bd53240271a0cf5c52bd10f6a66 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Wed, 20 May 2026 12:12:37 -0700 Subject: [PATCH 12/18] encoding/json: clarify that v1 Unmarshal calls UnmarshalerFrom methods This is the equivalent of CL 775180 for Unmarshal. Also, since the jsonv2 package is imported with a specific name, the hot-link can reference the local package name directly, instead of relying on a full-qualified package import path. Change-Id: I1223eeaac2d2aed53cfc681b5582e697813f2a36 Reviewed-on: https://go-review.googlesource.com/c/go/+/780107 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Auto-Submit: Damien Neil Reviewed-by: Damien Neil Reviewed-by: Michael Pratt --- src/encoding/json/v2_decode.go | 22 ++++++++++++++++------ src/encoding/json/v2_encode.go | 2 +- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/encoding/json/v2_decode.go b/src/encoding/json/v2_decode.go index 959b31d78a970e..4a96d3d92562d2 100644 --- a/src/encoding/json/v2_decode.go +++ b/src/encoding/json/v2_decode.go @@ -35,12 +35,22 @@ import ( // the value pointed at by the pointer. If the pointer is nil, Unmarshal // allocates a new value for it to point to. // -// To unmarshal JSON into a value implementing [Unmarshaler], -// Unmarshal calls that value's [Unmarshaler.UnmarshalJSON] method, including -// when the input is a JSON null. -// Otherwise, if the value implements [encoding.TextUnmarshaler] -// and the input is a JSON quoted string, Unmarshal calls -// [encoding.TextUnmarshaler.UnmarshalText] with the unquoted form of the string. +// The JSON input is decoded according the following rules: +// +// - If the value type implements [jsonv2.UnmarshalerFrom], +// then the UnmarshalJSONFrom method is called to decode the JSON value. +// If the method returns [errors.ErrUnsupported], +// then the input is decoded according to subsequent rules. +// +// - If the value type implements [Unmarshaler], +// then the UnmarshalJSON method is called to decode the JSON value, +// including when the input is a JSON null. +// +// - If the value implements [encoding.TextUnmarshaler] and +// the input is a JSON string, then the UnmarshalText method +// is called with the unquoted form of the string. +// +// Otherwise, Unmarshal uses the following type-dependent default decodings: // // To unmarshal JSON into a struct, Unmarshal matches incoming object // keys to the keys used by [Marshal] (either the struct field name or its tag), diff --git a/src/encoding/json/v2_encode.go b/src/encoding/json/v2_encode.go index b5d27c3b34802d..a704e2ad22e66d 100644 --- a/src/encoding/json/v2_encode.go +++ b/src/encoding/json/v2_encode.go @@ -33,7 +33,7 @@ import ( // // The input value is encoded as JSON according the following rules: // -// - If the value type implements [encoding/json/v2.MarshalerTo], +// - If the value type implements [jsonv2.MarshalerTo], // then the MarshalJSONTo method is called to encode the value. // If the method returns [errors.ErrUnsupported], // then the input is encoded according to subsequent rules. From bbf60f3bbd3010783a6e7d4f793a673a004a2ce0 Mon Sep 17 00:00:00 2001 From: Mark Freeman Date: Wed, 20 May 2026 17:05:26 -0400 Subject: [PATCH 13/18] all: update to x/tools@b38156a7 This rolls up to include CL 780780, preparing us for the freeze. Change-Id: I69561591332e377fddac20af99d85cf92f8bc2cf Reviewed-on: https://go-review.googlesource.com/c/go/+/780801 TryBot-Bypass: Mark Freeman Reviewed-by: Neal Patel --- src/cmd/go.mod | 4 +- src/cmd/go.sum | 8 +- .../go/analysis/passes/composite/composite.go | 142 ++--- .../go/analysis/passes/errorsas/errorsas.go | 11 +- .../x/tools/go/analysis/passes/inline/doc.go | 6 + .../tools/go/analysis/passes/inline/inline.go | 30 +- .../analysis/passes/modernize/atomictypes.go | 8 +- .../tools/go/analysis/passes/modernize/doc.go | 41 ++ .../go/analysis/passes/modernize/embedlit.go | 406 +++++++++++++ .../analysis/passes/modernize/errorsastype.go | 132 ++-- .../go/analysis/passes/modernize/minmax.go | 35 +- .../go/analysis/passes/modernize/modernize.go | 24 +- .../go/analysis/passes/modernize/plusbuild.go | 8 +- .../go/analysis/passes/modernize/rangeint.go | 11 +- .../go/analysis/passes/modernize/reflect.go | 4 +- .../passes/modernize/slicesbackward.go | 102 +++- .../passes/modernize/slicescontains.go | 14 +- .../analysis/passes/modernize/stditerators.go | 8 +- .../passes/modernize/stringsbuilder.go | 53 +- .../analysis/passes/modernize/stringscut.go | 157 ++++- .../tools/go/analysis/passes/printf/printf.go | 2 +- .../golang.org/x/tools/go/ast/edge/edge.go | 24 +- .../x/tools/go/types/objectpath/objectpath.go | 563 +++++++++++------- .../x/tools/internal/astutil/comment.go | 22 +- .../x/tools/internal/astutil/cursor.go | 38 ++ .../x/tools/internal/astutil/purge.go | 43 +- .../x/tools/internal/astutil/util.go | 5 + .../x/tools/internal/goplsexport/export.go | 13 +- .../x/tools/internal/moreiters/iters.go | 8 + .../x/tools/internal/refactor/delete.go | 2 +- .../tools/internal/refactor/inline/callee.go | 15 +- .../tools/internal/refactor/inline/inline.go | 2 +- .../typesinternal/typeindex/typeindex.go | 25 +- src/cmd/vendor/modules.txt | 4 +- 34 files changed, 1406 insertions(+), 564 deletions(-) create mode 100644 src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/embedlit.go create mode 100644 src/cmd/vendor/golang.org/x/tools/internal/astutil/cursor.go diff --git a/src/cmd/go.mod b/src/cmd/go.mod index a5bbc6b69013a6..df4fba11865b84 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -9,9 +9,9 @@ require ( golang.org/x/mod v0.36.1-0.20260513122029-343ee60345a1 golang.org/x/sync v0.20.0 golang.org/x/sys v0.44.0 - golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa + golang.org/x/telemetry v0.0.0-20260508192327-42602be52be6 golang.org/x/term v0.39.0 - golang.org/x/tools v0.44.1-0.20260414062052-55fb96ff894f + golang.org/x/tools v0.45.1-0.20260520205638-b38156a7a9f5 ) require ( diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 6eb3c889306465..b8531a556a60ab 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -16,13 +16,13 @@ golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa h1:efT73AJZfAAUV7SOip6pWGkwJDzIGiKBZGVzHYa+ve4= -golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa/go.mod h1:kHjTxDEnAu6/Nl9lDkzjWpR+bmKfxeiRuSDlsMb70gE= +golang.org/x/telemetry v0.0.0-20260508192327-42602be52be6 h1:HjU6IWBiAgRIdAJ9/y1rwCn+UELEmwV+VsTLzj/W4sE= +golang.org/x/telemetry v0.0.0-20260508192327-42602be52be6/go.mod h1:Eqhaxk/wZsWEH8CRxLwj6xzEJbz7k1EFGqx7nyCoabE= golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= -golang.org/x/tools v0.44.1-0.20260414062052-55fb96ff894f h1:OsDhJTPRMdqueEUhZ6K1sdC07K6rj9i4RYTQGF6zSHA= -golang.org/x/tools v0.44.1-0.20260414062052-55fb96ff894f/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +golang.org/x/tools v0.45.1-0.20260520205638-b38156a7a9f5 h1:jqdNq3qAaJT9zQL5Cbq/TRYEdoLZmystI2hoCyAsAuw= +golang.org/x/tools v0.45.1-0.20260520205638-b38156a7a9f5/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef h1:mqLYrXCXYEZOop9/Dbo6RPX11539nwiCNBb1icVPmw8= rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef/go.mod h1:8xcPgWmwlZONN1D9bjxtHEjrUtSEa3fakVF8iaewYKQ= diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go index ed2284e6306a99..f80e393adbba00 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go @@ -10,6 +10,7 @@ import ( "fmt" "go/ast" "go/types" + "slices" "strings" "golang.org/x/tools/go/analysis" @@ -49,108 +50,88 @@ func init() { Analyzer.Flags.BoolVar(&whitelist, "whitelist", whitelist, "use composite white list; for testing only") } -// runUnkeyedLiteral checks if a composite literal is a struct literal with -// unkeyed fields. func run(pass *analysis.Pass) (any, error) { inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - nodeFilter := []ast.Node{ - (*ast.CompositeLit)(nil), - } - inspect.Preorder(nodeFilter, func(n ast.Node) { - cl := n.(*ast.CompositeLit) + for curLit := range inspect.Root().Preorder((*ast.CompositeLit)(nil)) { + complit := curLit.Node().(*ast.CompositeLit) + + // Skip empty or partly/fully keyed literals. + if len(complit.Elts) == 0 || + slices.ContainsFunc(complit.Elts, func(e ast.Expr) bool { return is[*ast.KeyValueExpr](e) }) { + continue + } - typ := pass.TypesInfo.Types[cl].Type + // Find struct type. + // (For a type parameter, choose an arbitrary term.) + typ := pass.TypesInfo.Types[complit].Type if typ == nil { - // cannot determine composite literals' type, skip it - return + continue // no type info } - typeName := typ.String() - if whitelist && unkeyedLiteral[typeName] { - // skip whitelisted types - return + terms, err := typeparams.NormalTerms(typ) + if err != nil || len(terms) == 0 { + continue // invalid or empty type } - var structuralTypes []types.Type - switch typ := types.Unalias(typ).(type) { - case *types.TypeParam: - terms, err := typeparams.StructuralTerms(typ) - if err != nil { - return // invalid type - } - for _, term := range terms { - structuralTypes = append(structuralTypes, term.Type()) - } - default: - structuralTypes = append(structuralTypes, typ) + t := terms[0].Type() + strct, ok := typeparams.Deref(t).Underlying().(*types.Struct) + if !ok { + continue // not a struct literal + } + if isSamePackageType(pass, t) { + continue // allow unkeyed literals for structs in same package } - for _, typ := range structuralTypes { - strct, ok := typeparams.Deref(typ).Underlying().(*types.Struct) - if !ok { - // skip non-struct composite literals - continue - } - if isLocalType(pass, typ) { - // allow unkeyed locally defined composite literal - continue - } + // Allow whitelisted types. + typeName := typ.String() + if whitelist && unkeyedLiteral[typeName] { + continue + } - // check if the struct contains an unkeyed field - allKeyValue := true - var suggestedFixAvailable = len(cl.Elts) == strct.NumFields() - var missingKeys []analysis.TextEdit - for i, e := range cl.Elts { - if _, ok := e.(*ast.KeyValueExpr); !ok { - allKeyValue = false - if i >= strct.NumFields() { - break - } - field := strct.Field(i) - if !field.Exported() { - // Adding unexported field names for structs not defined - // locally will not work. - suggestedFixAvailable = false - break - } - missingKeys = append(missingKeys, analysis.TextEdit{ - Pos: e.Pos(), - End: e.Pos(), - NewText: fmt.Appendf(nil, "%s: ", field.Name()), - }) + // If there is one value per field, + // offer to fill in the field names. + var fixes []analysis.SuggestedFix + if len(complit.Elts) == strct.NumFields() { + var edits []analysis.TextEdit + for i, elt := range complit.Elts { + field := strct.Field(i) + // We cannot fill in the name of an + // exported field from another package. + if !field.Exported() { + edits = nil + break } + edits = append(edits, analysis.TextEdit{ + Pos: elt.Pos(), + End: elt.Pos(), + NewText: fmt.Appendf(nil, "%s: ", field.Name()), + }) } - if allKeyValue { - // all the struct fields are keyed - continue - } - - diag := analysis.Diagnostic{ - Pos: cl.Pos(), - End: cl.End(), - Message: fmt.Sprintf("%s struct literal uses unkeyed fields", typeName), - } - if suggestedFixAvailable { - diag.SuggestedFixes = []analysis.SuggestedFix{{ + if edits != nil { + fixes = []analysis.SuggestedFix{{ Message: "Add field names to struct literal", - TextEdits: missingKeys, + TextEdits: edits, }} } - pass.Report(diag) - return } - }) + + pass.Report(analysis.Diagnostic{ + Pos: complit.Pos(), + End: complit.End(), + Message: fmt.Sprintf("%s struct literal uses unkeyed fields", typeName), + SuggestedFixes: fixes, + }) + } return nil, nil } -// isLocalType reports whether typ belongs to the same package as pass. -// TODO(adonovan): local means "internal to a function"; rename to isSamePackageType. -func isLocalType(pass *analysis.Pass, typ types.Type) bool { +// isSamePackageType reports whether typ belongs to the same package as pass. +func isSamePackageType(pass *analysis.Pass, typ types.Type) bool { switch x := types.Unalias(typ).(type) { case *types.Struct: // struct literals are local types return true case *types.Pointer: - return isLocalType(pass, x.Elem()) + return isSamePackageType(pass, x.Elem()) case interface{ Obj() *types.TypeName }: // *Named or *TypeParam (aliases were removed already) // names in package foo are local to foo_test too return x.Obj().Pkg() != nil && @@ -158,3 +139,8 @@ func isLocalType(pass *analysis.Pass, typ types.Type) bool { } return false } + +func is[T any](x any) bool { + _, ok := x.(T) + return ok +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go index f1465f73434fed..eb4373dafea1a3 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The errorsas package defines an Analyzer that checks that the second argument to -// errors.As is a pointer to a type implementing error. +// Package errorsas defines an Analyzer that checks that the second argument to +// [errors.As] is a pointer to a type implementing error. package errorsas import ( @@ -19,7 +19,12 @@ import ( const Doc = `report passing non-pointer or non-error values to errors.As The errorsas analyzer reports calls to errors.As where the type -of the second argument is not a pointer to a type implementing error.` +of the second argument is not a pointer to a type implementing error. +For example: + + var unwrappedErr net.DNSError + errors.As(err, unwrappedErr) // should use &unwrappedErr, DNSError.Error has a pointer receiver +` var Analyzer = &analysis.Analyzer{ Name: "errorsas", diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/doc.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/doc.go index a3e98cb6572c7c..8b817a702900ba 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/doc.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/doc.go @@ -61,6 +61,12 @@ inliner machinery is capable of replacing f by a function literal, func(){...}(). However, the inline analyzer discards all such "literalizations" unconditionally, again on grounds of style.) +A call to a function F from its dedicated test (TestF) is not inlined, +since the purpose of the test is to exercise F itself, even when +it's a deprecated function to which other calls should be inlined. +This is not true for type aliases; see https://go.dev/issue/79271. +See further discussion in https://go.dev/issue/79272. + ## Constants Given a constant that is marked for inlining, like this one: diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go index efa2dcaf89ddb9..890f4adf6ed5f2 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inline/inline.go @@ -339,23 +339,19 @@ func (a *analyzer) inlineAlias(tn *types.TypeName, curId inspector.Cursor) { expr = curId.Node().(*ast.IndexListExpr) } - fieldType := curId - if fieldType.ParentEdgeKind() == edge.StarExpr_X { - fieldType = fieldType.Parent() - } - if fieldType.ParentEdgeKind() == edge.Field_Type { - field := fieldType.Parent().Node().(*ast.Field) - if len(field.Names) == 0 { - identicalName := false - if rhs, ok := alias.Rhs().(*types.Named); ok { - identicalName = alias.Obj().Name() == rhs.Obj().Name() - } - if !identicalName { - // Type is embedded, inlining the alias will cause - // the field name to be changed, which might break - // programs in terms of backwards compatibility. - return - } + // Reject inlining of a type alias used to declare an embedded + // struct field if doing so would change the field's name. + if v, ok := a.pass.TypesInfo.Defs[id].(*types.Var); ok && v.Embedded() { + identicalName := false + // TODO(adonovan): should we allow a pointer (type A = *pkg.A)? + if rhs, ok := alias.Rhs().(*types.Named); ok { + identicalName = alias.Obj().Name() == rhs.Obj().Name() + } + if !identicalName { + // Type is embedded, inlining the alias will cause + // the field name to be changed, which might break + // programs in terms of backwards compatibility. + return } } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/atomictypes.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/atomictypes.go index ec0044b3074705..9df39fb23a7a96 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/atomictypes.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/atomictypes.go @@ -19,14 +19,13 @@ import ( "golang.org/x/tools/internal/analysis/analyzerutil" typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex" "golang.org/x/tools/internal/astutil" - "golang.org/x/tools/internal/goplsexport" "golang.org/x/tools/internal/refactor" "golang.org/x/tools/internal/typesinternal" "golang.org/x/tools/internal/typesinternal/typeindex" "golang.org/x/tools/internal/versions" ) -var atomicTypesAnalyzer = &analysis.Analyzer{ +var AtomicTypesAnalyzer = &analysis.Analyzer{ Name: "atomictypes", Doc: analyzerutil.MustExtractDoc(doc, "atomictypes"), Requires: []*analysis.Analyzer{ @@ -37,11 +36,6 @@ var atomicTypesAnalyzer = &analysis.Analyzer{ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#atomictypes", } -func init() { - // Export to gopls until this is a published modernizer. - goplsexport.AtomicTypesModernizer = atomicTypesAnalyzer -} - // TODO(mkalil): support the Pointer variants. // Consider the following function signatures for pointer loading: // func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer) diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go index e9a3a0d985c695..260dd50908c2e7 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go @@ -111,6 +111,31 @@ The any analyzer suggests replacing uses of the empty interface type, `interface{}`, with the `any` alias, which was introduced in Go 1.18. This is a purely stylistic change that makes code more readable. +# Analyzer embedlit + +embedlit: simplify references to embedded fields in composite literals + +The embedlit analyzer suggests removing redundant embedded field type specifiers +from composite literals. Go1.27 introduced the ability to directly initialize +fields promoted from embedded struct types without a nested literal. For +example, given the following structs: + + type T struct { + U + } + + type U struct { + x int + } + +A composite literal such as + + t := T{U: U{x: 1}} + +would become + + t := T{x: 1} + # Analyzer errorsastype errorsastype: replace errors.As with errors.AsType[T] @@ -142,6 +167,9 @@ The fmtappendf analyzer suggests replacing `[]byte(fmt.Sprintf(...))` with by Sprintf, making the code more efficient. The suggestion also applies to fmt.Sprint and fmt.Sprintln. +Since its fix is not a Pareto improvement, fmtappendf is disabled by default in +the `go fix` analyzer suite; see golang/go#77581. + # Analyzer forvar forvar: remove redundant re-declaration of loop variables @@ -424,6 +452,16 @@ It also handles variants using [strings.IndexByte] instead of Index, or the byte Fixes are offered only in cases in which there are no potential modifications of the idx, s, or substr expressions between their definition and use. +It also replaces [strings.SplitN](s, sep, 2)[0] and [strings.Split](s, sep)[0] with the "before" result of strings.Cut, when sep is a non-empty string constant: + + x := strings.SplitN(s, sep, 2)[0] + +is replaced by: + + x, _, _ := strings.Cut(s, sep) + +The fix is only offered when sep is a non-empty string literal. When sep is a variable or the empty string, the semantics differ (strings.Split(s, "")[0] returns the first character of s, but strings.Cut(s, "").before is ""), so no fix is suggested. + # Analyzer stringscutprefix stringscutprefix: replace HasPrefix/TrimPrefix with CutPrefix @@ -506,6 +544,9 @@ is replaced by: This avoids quadratic memory allocation and improves performance. +No diagnostics are issued in tests, where data sizes are often +small and asymptotic performance is not a security concern. + The analyzer requires that all references to s before the final uses are += operations. To avoid warning about trivial cases, at least one must appear within a loop. The variable s must be a local diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/embedlit.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/embedlit.go new file mode 100644 index 00000000000000..7d0b7e3b683f01 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/embedlit.go @@ -0,0 +1,406 @@ +// Copyright 2026 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 modernize + +import ( + "bytes" + "fmt" + "go/ast" + "go/token" + "go/types" + "slices" + "strings" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/edge" + "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/analysis/analyzerutil" + typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex" + "golang.org/x/tools/internal/astutil" + "golang.org/x/tools/internal/moreiters" + "golang.org/x/tools/internal/typesinternal/typeindex" + "golang.org/x/tools/internal/versions" +) + +var EmbedLitAnalyzer = &analysis.Analyzer{ + Name: "embedlit", + Doc: analyzerutil.MustExtractDoc(doc, "embedlit"), + Requires: []*analysis.Analyzer{ + inspect.Analyzer, + typeindexanalyzer.Analyzer, + }, + Run: runEmbedLit, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#embedlit", +} + +// Go1.27 introduced the ability to directly access embedded struct fields. +// The embedlit modernizer suggests two types of fixes that use this feature: +// 1. Removing redundant field type specifiers in embedded struct fields. +// 2. Moving embedded struct field assignments inside of the struct literal +// initialization. +func runEmbedLit(pass *analysis.Pass) (any, error) { + var ( + inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index) + info = pass.TypesInfo + ) + for curLit := range inspect.Root().Preorder((*ast.CompositeLit)(nil)) { + if curLit.ParentEdgeKind() != edge.KeyValueExpr_Value { // non-nested comp lit + // TODO(mkalil): Figure out how to handle addition/removal of commas in + // the comp lit when we observe code where both patterns apply. (This will + // likely require a significant amount of work). For now, only apply edits + // from one pattern at a time. + if !embedlitUnnest(pass, info, curLit) { + err := embedlitCombine(pass, index, info, curLit) // calls pass.ReadFile + if err != nil { + return nil, err + } + } + } + } + return nil, nil +} + +// Pattern A: removing unneeded embedded field type specifier from the struct +// literal. +// T{U: U{f: v, ...}} => T{f: v, ...} +// It returns true if it reported a diagnostic with edits. +func embedlitUnnest(pass *analysis.Pass, info *types.Info, curLit inspector.Cursor) bool { + var ( + edits []analysis.TextEdit + names []string // names of the embedded field types that can be removed + lit = curLit.Node().(*ast.CompositeLit) + compLitType = info.TypeOf(lit) + ) + + // checkLit determines whether any of the fields in the given struct literal can + // be promoted, and calculates the corresponding edits. + var checkLit func(lit *ast.CompositeLit) + checkLit = func(lit *ast.CompositeLit) { + for _, elt := range lit.Elts { + // Can't promote an unkeyed field; would result in a syntax error. + if kv, ok := elt.(*ast.KeyValueExpr); ok { + if innerLit := isEmbeddedFieldLit(info, compLitType, kv); innerLit != nil { + // Emit edits to delete the unnecessary embedded field type specifier + // and its closing brace. + closingPos := innerLit.Rbrace + if len(innerLit.Elts) > 0 { + // Delete any inner trailing commas or white space. Extra trailing commas + // would result in invalid code. + closingPos = innerLit.Elts[len(innerLit.Elts)-1].End() + } + file := astutil.EnclosingFile(curLit) + // Enable modernizer only for Go1.27. + if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_27) { + return + } + // If any comments overlap with the range to delete, don't suggest a fix. + if !moreiters.Empty(astutil.Comments(file, kv.Pos(), innerLit.Lbrace+1)) || + !moreiters.Empty(astutil.Comments(file, closingPos, innerLit.Rbrace+1)) { + continue + } + edits = append(edits, []analysis.TextEdit{ + // T{U: U{f: v, ...}} + // ----- - + { + // Delete the key and the opening brace of the inner struct literal. + Pos: kv.Pos(), + End: innerLit.Lbrace + 1, + }, + { + // Delete the corresponding closing brace, including preceding + // white space or commas. Failing to delete trailing commas may + // result in invalid code. + Pos: closingPos, + End: innerLit.Rbrace + 1, + }, + }...) + names = append(names, kv.Key.(*ast.Ident).Name) + checkLit(innerLit) + } + } + } + } + checkLit(lit) + if len(edits) > 0 { + pass.Report(analysis.Diagnostic{ + Pos: curLit.Node().Pos(), + End: curLit.Node().End(), + Message: "embedded field type can be removed from struct literal", + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: fmt.Sprintf("Remove embedded field type%s %s", cond(len(names) == 1, "", "s"), strings.Join(names, ", ")), + TextEdits: edits, + }, + }, + }) + return true + } + return false +} + +// Pattern B: moving embedded field assignments inside the struct literal +// initialization. +// t := T{...}; t.x = x => t := T{..., x: x} +// (or var t = ...) +func embedlitCombine(pass *analysis.Pass, index *typeindex.Index, info *types.Info, curLit inspector.Cursor) error { + compLit := curLit.Node().(*ast.CompositeLit) + if !moreiters.Every(slices.Values(compLit.Elts), func(e ast.Expr) bool { + return is[*ast.KeyValueExpr](e) + }) { + // Promoting additional embedded fields would result in mixing keyed and + // unkeyed fields, which isn't allowed. + return nil + } + var ( + // Ident for "t" in the assignment. + lhs *ast.Ident + // The cursor representing the statement that initializes the comp lit "t". + // We use its siblings to search for field assignments and verify that there + // are no intervening statements, in case those statements observe "t". + curStmt inspector.Cursor + ) + switch curLit.ParentEdgeKind() { + case edge.AssignStmt_Rhs: + assign := curLit.Parent().Node().(*ast.AssignStmt) + // TODO(mkalil): Handle lhs forms that aren't idents, i.e. x.y[i] = T{...}. + if id, ok := assign.Lhs[curLit.ParentEdgeIndex()].(*ast.Ident); ok { + lhs = id + curStmt = curLit.Parent() + } + case edge.ValueSpec_Values: + spec := curLit.Parent().Node().(*ast.ValueSpec) + lhs = spec.Names[curLit.ParentEdgeIndex()] + if decl, ok := moreiters.First(curLit.Enclosing((*ast.DeclStmt)(nil))); ok { + curStmt = decl + } + default: + return nil + } + + if lhs == nil || !curStmt.Valid() { + return nil + } + + var ( + tObj = info.ObjectOf(lhs) + // Marks the contiguous block of embedded field assign statements that will + // be moved into the struct initialization. + firstStmt, lastStmt inspector.Cursor + ) +stmtloop: + for { + var ok bool + curStmt, ok = curStmt.NextSibling() + if !ok { + break // end of (e.g.) block + } + // All embedded field value assignments must immediately follow the struct + // initialization. + assign, ok := curStmt.Node().(*ast.AssignStmt) + if !ok || len(assign.Lhs) != 1 || !(assign.Tok == token.ASSIGN || assign.Tok == token.DEFINE) { + // TODO(mkalil): handle multi-assignments like t.x, t.y = 1, 2 + break + } + expr := assign.Lhs[0] + sel, ok := expr.(*ast.SelectorExpr) + if !ok { + break + } + // Verify that sel.X refers to the same object as "t" + selXId, ok := sel.X.(*ast.Ident) + if !ok { + // TODO(mkalil): handle deeply nested expressions like t.B.x + break + } + obj := info.ObjectOf(selXId) + if obj != tObj { + break + } + rhsCur := curStmt.ChildAt(edge.AssignStmt_Rhs, 0) + if uses(index, rhsCur, tObj) { + break + } + for c := range rhsCur.Preorder((*ast.Ident)(nil)) { + id := c.Node().(*ast.Ident) + // If the rhs uses a value of t (e.g. t.x = t.y), don't suggest a fix because + // we can't evaluate t.y when constructing the new literal. + if info.ObjectOf(id) == tObj { + break stmtloop + } + // Note: we don't need to worry about expressions with side effects + // changing the behavior when moved inside the comp lit. The order of + // effects will be preserved because we preserve the order of the key + // value pairs inside the comp lit. + } + if !firstStmt.Valid() { + firstStmt = curStmt + } + lastStmt = curStmt + } + + if !firstStmt.Valid() { + return nil + } + + file := astutil.EnclosingFile(curLit) + // Enable modernizer only for Go1.27. + if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_27) { + return nil + } + + // Read file content to determine if the struct lit has a trailing comma + // after its last element. + tokFile := pass.Fset.File(compLit.Rbrace) + filename := tokFile.Name() + src, err := pass.ReadFile(filename) + if err != nil { + return err + } + + hasTrailingComma := false + if len(compLit.Elts) > 0 { + lastElt := compLit.Elts[len(compLit.Elts)-1] + lastEltOffset := tokFile.Offset(lastElt.End()) + rbraceOffset := tokFile.Offset(compLit.Rbrace) + hasTrailingComma = bytes.Contains(src[lastEltOffset:rbraceOffset], []byte(",")) + } + var edits []analysis.TextEdit + // Emit edits to move the field assignment into the struct lit while + // removing it from its current place. + // t := T{...}; t.x = v + // ----- --- - + // t := T{..., x: v} + + // Add a trailing comma before the closing brace of compLit if one doesn't + // exist, and delete the closing brace itself. + // t := T{...}; t.x = v + // - + // t := T{..., t.x = v + if len(compLit.Elts) > 0 && !hasTrailingComma { + edits = append(edits, analysis.TextEdit{ + Pos: compLit.Rbrace, + End: compLit.Rbrace + 1, + NewText: []byte(","), + }) + } else { + edits = append(edits, analysis.TextEdit{ + Pos: compLit.Rbrace, + End: compLit.Rbrace + 1, + }) + } + + // For each assignment: + // t.x = v + // -- --- + // x : v + curStmt = firstStmt + var prevStmt inspector.Cursor + for { + assign := curStmt.Node().(*ast.AssignStmt) + expr := assign.Lhs[0] + sel := expr.(*ast.SelectorExpr) + // Delete "t." + edits = append(edits, analysis.TextEdit{ + Pos: assign.Pos(), + End: sel.Sel.Pos(), + }) + // Replace "=" with ":" + edits = append(edits, analysis.TextEdit{ + Pos: expr.End(), + End: assign.TokPos + 1, + NewText: []byte(":"), + }) + + // Add a comma after the previous assignment if this is not the first one. + if prevStmt.Valid() { + edits = append(edits, analysis.TextEdit{ + Pos: prevStmt.Node().End(), + NewText: []byte(","), + }) + } + + // For the last assignment, add the closing brace of the struct lit. + if curStmt == lastStmt { + edits = append(edits, analysis.TextEdit{ + Pos: assign.End(), + NewText: []byte("}"), + }) + break + } + prevStmt = curStmt + curStmt, _ = curStmt.NextSibling() // can't fail because we break out of the loop when we hit lastStmt + } + + pass.Report(analysis.Diagnostic{ + Pos: curLit.Node().Pos(), + End: curLit.Node().End(), + Message: "embedded field assignment can be moved to struct literal", + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "Move embedded field assignment to struct literal", + TextEdits: edits, + }, + }, + }) + return nil +} + +// isEmbeddedFieldLit determines whether elt is a KeyValueExpr "T: T{...}" for +// an embedded field for which we can safely remove its type. +// If so, it returns the corresponding CompositeLit. +// If elt contains an unkeyed field or ambiguous type, it returns nil. +func isEmbeddedFieldLit(info *types.Info, topLevelType types.Type, kv *ast.KeyValueExpr) *ast.CompositeLit { + obj := keyedField(info, kv) + if obj == nil || !obj.Embedded() { + return nil + } + lit, ok := kv.Value.(*ast.CompositeLit) + if !ok || len(lit.Elts) == 0 { + // Skip if the struct literal is empty. + return nil + } + // We cannot remove this type if any of its nested composite elements have + // unkeyed fields or are ambiguous, so we check for those conditions before + // returning. + for _, elt := range lit.Elts { + kv, ok := elt.(*ast.KeyValueExpr) + if !ok { + return nil + } + obj := keyedField(info, kv) + if obj == nil { + return nil + } + k := kv.Key.(*ast.Ident) // can't fail + // Cannot promote an ambiguous type, for example: + // type T struct { A; B } + // type A struct { x int } + // type B struct { x int } + // _ = T{A: A{x: 1}} + // cannot be simplified to T{x: 1} because T has two different embedded fields called "x". + // We also reject composite literals with slice elements, as parentObj will be nil. + parentObj, _, _ := types.LookupFieldOrMethod(topLevelType, true, obj.Pkg(), k.Name) + if parentObj != obj { + return nil + } + } + return lit +} + +// keyedField reports whether the key of kv is an embedded field type. If so, it +// returns the type of the embedded field, otherwise it returns nil. +func keyedField(info *types.Info, kv *ast.KeyValueExpr) *types.Var { + k, ok := kv.Key.(*ast.Ident) + if !ok { + return nil + } + obj, ok := info.ObjectOf(k).(*types.Var) + if !ok || !obj.IsField() { + return nil + } + return obj +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go index 8603d54712125b..f52f202e22def9 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go @@ -17,14 +17,14 @@ import ( "golang.org/x/tools/internal/analysis/analyzerutil" typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex" "golang.org/x/tools/internal/astutil" - "golang.org/x/tools/internal/goplsexport" + "golang.org/x/tools/internal/moreiters" "golang.org/x/tools/internal/refactor" "golang.org/x/tools/internal/typesinternal" "golang.org/x/tools/internal/typesinternal/typeindex" "golang.org/x/tools/internal/versions" ) -var errorsastypeAnalyzer = &analysis.Analyzer{ +var ErrorsAsTypeAnalyzer = &analysis.Analyzer{ Name: "errorsastype", Doc: analyzerutil.MustExtractDoc(doc, "errorsastype"), URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#errorsastype", @@ -32,11 +32,6 @@ var errorsastypeAnalyzer = &analysis.Analyzer{ Run: errorsastype, } -func init() { - // Export to gopls until this is a published modernizer. - goplsexport.ErrorsAsTypeModernizer = errorsastypeAnalyzer -} - // errorsastype offers a fix to replace error.As with the newer // errors.AsType[T] following this pattern: // @@ -60,22 +55,15 @@ func init() { // // because the transformation in that case would be ungainly. // +// For the negated case (!errors.As), we use !ok instead. +// // Note that the cmd/vet suite includes the "errorsas" analyzer, which // detects actual mistakes in the use of errors.As. This logic does // not belong in errorsas because the problems it fixes are merely // stylistic. // // TODO(adonovan): support more cases: -// -// - Negative cases -// var myerr E -// if !errors.As(err, &myerr) { ... } -// => -// myerr, ok := errors.AsType[E](err) -// if !ok { ... } -// // - if myerr := new(E); errors.As(err, myerr); { ... } -// // - if errors.As(err, myerr) && othercond { ... } func errorsastype(pass *analysis.Pass) (any, error) { var ( @@ -89,7 +77,7 @@ func errorsastype(pass *analysis.Pass) (any, error) { continue // spread call: errors.As(pair()) } - v, curDeclStmt := canUseErrorsAsType(info, index, curCall) + v, curDeclStmt, curIfStmt := canUseErrorsAsType(info, index, curCall) if v == nil { continue } @@ -127,64 +115,82 @@ func errorsastype(pass *analysis.Pass) (any, error) { // Choose a name for the "ok" variable. // We generate a new name only if 'ok' is already declared at // curCall and it also used within the if-statement. - curIf := curCall.Parent() - ifScope := info.Scopes[curIf.Node().(*ast.IfStmt)] - okName := freshName(info, index, ifScope, v.Pos(), curCall, curIf, token.NoPos, "ok") + ifScope := info.Scopes[curIfStmt.Node().(*ast.IfStmt)] + negated := curCall.ParentEdgeKind() == edge.UnaryExpr_X // bool => Tok==NOT + okName := freshName(info, index, ifScope, v.Pos(), curCall, curIfStmt, token.NoPos, "ok") + // Because we reject any use of v outside the if statement, any use besides + // the argument in errors.As must lie inside the if statement. + usesV := moreiters.Len(index.Uses(v)) > 1 + + edits := append( + // delete "var myerr *MyErr" + refactor.DeleteStmt(pass.Fset.File(call.Fun.Pos()), curDeclStmt), + // if errors.As (err, &myerr) { ... } + // ------------- -------------- -------- ---- + // if myerr, ok := errors.AsType[*MyErr](err ); ok { ... } + analysis.TextEdit{ + // Insert "myerr, ok := " if myerr is used inside the if statement. + // Otherwise insert "_, ok := ". + Pos: call.Pos(), + End: call.Pos(), + NewText: fmt.Appendf(nil, "%s, %s := ", cond(usesV, v.Name(), "_"), okName), + }, + analysis.TextEdit{ + // replace As with AsType[T] + Pos: asIdent.Pos(), + End: asIdent.End(), + NewText: fmt.Appendf(nil, "AsType[%s]", errtype), + }, + analysis.TextEdit{ + // delete ", &myerr" + Pos: call.Args[0].End(), + End: call.Args[1].End(), + }, + analysis.TextEdit{ + // insert "; ok" for errors.AsType or "; !ok" for !errors.AsType + Pos: call.End(), + End: call.End(), + NewText: fmt.Appendf(nil, "; %s%s", cond(negated, "!", ""), okName), + }, + ) + if negated { + unaryExpr := curCall.Parent().Node().(*ast.UnaryExpr) + // delete "!" + edits = append(edits, analysis.TextEdit{ + Pos: unaryExpr.OpPos, + End: unaryExpr.X.Pos(), + }) + } pass.Report(analysis.Diagnostic{ Pos: call.Fun.Pos(), End: call.Fun.End(), Message: fmt.Sprintf("errors.As can be simplified using AsType[%s]", errtype), SuggestedFixes: []analysis.SuggestedFix{{ - Message: fmt.Sprintf("Replace errors.As with AsType[%s]", errtype), - TextEdits: append( - // delete "var myerr *MyErr" - refactor.DeleteStmt(pass.Fset.File(call.Fun.Pos()), curDeclStmt), - // if errors.As (err, &myerr) { ... } - // ------------- -------------- -------- ---- - // if myerr, ok := errors.AsType[*MyErr](err ); ok { ... } - analysis.TextEdit{ - // insert "myerr, ok := " - Pos: call.Pos(), - End: call.Pos(), - NewText: fmt.Appendf(nil, "%s, %s := ", v.Name(), okName), - }, - analysis.TextEdit{ - // replace As with AsType[T] - Pos: asIdent.Pos(), - End: asIdent.End(), - NewText: fmt.Appendf(nil, "AsType[%s]", errtype), - }, - analysis.TextEdit{ - // delete ", &myerr" - Pos: call.Args[0].End(), - End: call.Args[1].End(), - }, - analysis.TextEdit{ - // insert "; ok" - Pos: call.End(), - End: call.End(), - NewText: fmt.Appendf(nil, "; %s", okName), - }, - ), + Message: fmt.Sprintf("Replace errors.As with AsType[%s]", errtype), + TextEdits: edits, }}, }) } return nil, nil } -// canUseErrorsAsType reports whether curCall is a call to -// errors.As beneath an if statement, preceded by a -// declaration of the typed error var. The var must not be -// used outside the if statement. -func canUseErrorsAsType(info *types.Info, index *typeindex.Index, curCall inspector.Cursor) (_ *types.Var, _ inspector.Cursor) { - if curCall.ParentEdgeKind() != edge.IfStmt_Cond { - return // not beneath if statement +// canUseErrorsAsType reports whether curCall is a call to errors.As beneath an +// if statement, preceded by a declaration of the typed error var. The var must +// not be used outside the if statement. +// If the conditions are met, it returns the error var, the cursor for its +// DeclStmt, and the cursor for the IfStmt that contains the call to errors.As. +// Otherwise it returns a nil error var. +func canUseErrorsAsType(info *types.Info, index *typeindex.Index, curCall inspector.Cursor) (_ *types.Var, curDeclStmt, curIfStmt inspector.Cursor) { + curCond := curCall + if curCond.ParentEdgeKind() == edge.UnaryExpr_X { // if !errors.As(err, &v) + curCond = curCond.Parent() } - var ( - curIfStmt = curCall.Parent() - ifStmt = curIfStmt.Node().(*ast.IfStmt) - ) + if curCond.ParentEdgeKind() != edge.IfStmt_Cond { + return // not beneath if or unaryexpr + } + curIfStmt = curCond.Parent() + ifStmt := curIfStmt.Node().(*ast.IfStmt) if ifStmt.Init != nil { return // if statement already has an init part } @@ -228,5 +234,5 @@ func canUseErrorsAsType(info *types.Info, index *typeindex.Index, curCall inspec // ... // if errors.As(err, &v) { ... } // with no uses of v outside the IfStmt. - return v, curDecl.Parent() // DeclStmt + return v, curDecl.Parent(), curIfStmt // curDecl.Parent() is a DeclStmt } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go index 93aadf04a13fb5..9fd8657581ddd0 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go @@ -19,6 +19,7 @@ import ( typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex" "golang.org/x/tools/internal/astutil" "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/internal/typesinternal" "golang.org/x/tools/internal/typesinternal/typeindex" "golang.org/x/tools/internal/versions" ) @@ -230,6 +231,7 @@ func minmax(pass *analysis.Pass) (any, error) { if compare, ok := ifStmt.Cond.(*ast.BinaryExpr); ok && ifStmt.Init == nil && isInequality(compare.Op) != 0 && + typesinternal.NoEffects(info, compare) && isAssignBlock(ifStmt.Body) { // a blank var has no type. if tLHS := info.TypeOf(ifStmt.Body.List[0].(*ast.AssignStmt).Lhs[0]); tLHS != nil && !maybeNaN(tLHS) { @@ -361,18 +363,18 @@ func canUseBuiltinMinMax(fn *types.Func, body *ast.BlockStmt) bool { return false } - return hasMinMaxLogic(body, fn.Name()) + return hasMinMaxLogic(body, fn.Name(), sig.Params().At(0).Name(), sig.Params().At(1).Name()) } // hasMinMaxLogic checks if the function body implements simple min/max logic. -func hasMinMaxLogic(body *ast.BlockStmt, funcName string) bool { +func hasMinMaxLogic(body *ast.BlockStmt, funcName, param0, param1 string) bool { // Pattern 1: Single if/else statement if len(body.List) == 1 { if ifStmt, ok := body.List[0].(*ast.IfStmt); ok { // Get the "false" result from the else block if elseBlock, ok := ifStmt.Else.(*ast.BlockStmt); ok && len(elseBlock.List) == 1 { if elseRet, ok := elseBlock.List[0].(*ast.ReturnStmt); ok && len(elseRet.Results) == 1 { - return checkMinMaxPattern(ifStmt, elseRet.Results[0], funcName) + return checkMinMaxPattern(ifStmt, elseRet.Results[0], funcName, param0, param1) } } } @@ -382,7 +384,7 @@ func hasMinMaxLogic(body *ast.BlockStmt, funcName string) bool { if len(body.List) == 2 { if ifStmt, ok := body.List[0].(*ast.IfStmt); ok && ifStmt.Else == nil { if retStmt, ok := body.List[1].(*ast.ReturnStmt); ok && len(retStmt.Results) == 1 { - return checkMinMaxPattern(ifStmt, retStmt.Results[0], funcName) + return checkMinMaxPattern(ifStmt, retStmt.Results[0], funcName, param0, param1) } } } @@ -394,7 +396,8 @@ func hasMinMaxLogic(body *ast.BlockStmt, funcName string) bool { // ifStmt: the if statement to check // falseResult: the expression returned when the condition is false // funcName: "min" or "max" -func checkMinMaxPattern(ifStmt *ast.IfStmt, falseResult ast.Expr, funcName string) bool { +// param0, param1: the two parameter names for the function. +func checkMinMaxPattern(ifStmt *ast.IfStmt, falseResult ast.Expr, funcName, param0, param1 string) bool { // Must have condition with comparison cmp, ok := ifStmt.Cond.(*ast.BinaryExpr) if !ok { @@ -417,10 +420,24 @@ func checkMinMaxPattern(ifStmt *ast.IfStmt, falseResult ast.Expr, funcName strin return false // Not a comparison operator } - t := thenRet.Results[0] // "true" result - f := falseResult // "false" result - x := cmp.X // left operand - y := cmp.Y // right operand + t := thenRet.Results[0] // "true" result + f := falseResult // "false" result + x, ok := cmp.X.(*ast.Ident) // left operand + if !ok { + return false // Not a basic min/max comparison + } + y, ok := cmp.Y.(*ast.Ident) // right operand + if !ok { + return false // Not a basic min/max comparison + } + + // Check that the min max algorithm uses the function's params + // Which param corresponds to which part of the operation doesn't matter, + // so we have to try both. + if !(param0 == x.Name && param1 == y.Name || + param0 == y.Name && param1 == x.Name) { + return false + } // Check operand order and adjust sign accordingly if astutil.EqualSyntax(t, x) && astutil.EqualSyntax(f, y) { diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go index db3b86fbf4c8a8..80491273b5d5f9 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go @@ -17,7 +17,6 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" - "golang.org/x/tools/go/ast/edge" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/internal/analysis/analyzerutil" "golang.org/x/tools/internal/refactor" @@ -35,24 +34,26 @@ var doc string // Suite lists all modernize analyzers. var Suite = []*analysis.Analyzer{ AnyAnalyzer, - atomicTypesAnalyzer, + AtomicTypesAnalyzer, // AppendClippedAnalyzer, // not nil-preserving! // BLoopAnalyzer, // may skew benchmark results, see golang/go#74967 - FmtAppendfAnalyzer, + EmbedLitAnalyzer, + ErrorsAsTypeAnalyzer, + // FmtAppendfAnalyzer, // makes code less clear, see golang/go#77581 ForVarAnalyzer, MapsLoopAnalyzer, MinMaxAnalyzer, NewExprAnalyzer, OmitZeroAnalyzer, - plusBuildAnalyzer, + PlusBuildAnalyzer, RangeIntAnalyzer, ReflectTypeForAnalyzer, - slicesbackwardAnalyzer, + slicesBackwardAnalyzer, SlicesContainsAnalyzer, // SlicesDeleteAnalyzer, // not nil-preserving! SlicesSortAnalyzer, - stditeratorsAnalyzer, - stringscutAnalyzer, + StdIteratorsAnalyzer, + StringsCutAnalyzer, StringsCutPrefixAnalyzer, StringsSeqAnalyzer, StringsBuilderAnalyzer, @@ -121,15 +122,6 @@ func within(pass *analysis.Pass, pkgs ...string) bool { moreiters.Contains(stdlib.Dependencies(pkgs...), path) } -// unparenEnclosing removes enclosing parens from cur in -// preparation for a call to [Cursor.ParentEdge]. -func unparenEnclosing(cur inspector.Cursor) inspector.Cursor { - for cur.ParentEdgeKind() == edge.ParenExpr_X { - cur = cur.Parent() - } - return cur -} - var ( builtinAny = types.Universe.Lookup("any") builtinAppend = types.Universe.Lookup("append") diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go index ff6c90551e9b91..574ce0a899051b 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go @@ -11,22 +11,16 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/internal/analysis/analyzerutil" - "golang.org/x/tools/internal/goplsexport" "golang.org/x/tools/internal/versions" ) -var plusBuildAnalyzer = &analysis.Analyzer{ +var PlusBuildAnalyzer = &analysis.Analyzer{ Name: "plusbuild", Doc: analyzerutil.MustExtractDoc(doc, "plusbuild"), URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#plusbuild", Run: plusbuild, } -func init() { - // Export to gopls until this is a published modernizer. - goplsexport.PlusBuildModernizer = plusBuildAnalyzer -} - func plusbuild(pass *analysis.Pass) (any, error) { check := func(f *ast.File) { // "//go:build" directives were added in go1.17, but diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go index 7c529c97da97d8..f7cb965f366aea 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go @@ -356,16 +356,9 @@ func isScalarLvalue(info *types.Info, curId inspector.Cursor) bool { // as it is always true for a variable even when that variable is // used only as an r-value. So we must inspect enclosing syntax. - cur := curId + cur := astutil.UnparenEnclosingCursor(curId) - // Strip enclosing parens. - ek := cur.ParentEdgeKind() - for ek == edge.ParenExpr_X { - cur = cur.Parent() - ek = cur.ParentEdgeKind() - } - - switch ek { + switch cur.ParentEdgeKind() { case edge.AssignStmt_Lhs: assign := cur.Parent().Node().(*ast.AssignStmt) if assign.Tok != token.DEFINE { diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go index fb1f2e2efca591..959939b5a2a4c6 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go @@ -65,9 +65,9 @@ func reflecttypefor(pass *analysis.Pass) (any, error) { // Special cases for TypeOf((*T)(nil)).Elem(), and // TypeOf([]T(nil)).Elem(), needed when T is an interface type. if curCall.ParentEdgeKind() == edge.SelectorExpr_X { - curSel := unparenEnclosing(curCall).Parent() + curSel := astutil.UnparenEnclosingCursor(curCall).Parent() if curSel.ParentEdgeKind() == edge.CallExpr_Fun { - call2 := unparenEnclosing(curSel).Parent().Node().(*ast.CallExpr) // potentially .Elem() + call2 := astutil.UnparenEnclosingCursor(curSel).Parent().Node().(*ast.CallExpr) // potentially .Elem() obj := typeutil.Callee(info, call2) if typesinternal.IsMethodNamed(obj, "reflect", "Type", "Elem") { // reflect.TypeOf(expr).Elem() diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesbackward.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesbackward.go index 293a7c0c3fbd4e..305b5e5b149141 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesbackward.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesbackward.go @@ -9,6 +9,7 @@ import ( "go/ast" "go/token" "go/types" + "strings" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" @@ -23,7 +24,7 @@ import ( "golang.org/x/tools/internal/versions" ) -var slicesbackwardAnalyzer = &analysis.Analyzer{ +var slicesBackwardAnalyzer = &analysis.Analyzer{ Name: "slicesbackward", Doc: analyzerutil.MustExtractDoc(doc, "slicesbackward"), Requires: []*analysis.Analyzer{ @@ -36,7 +37,7 @@ var slicesbackwardAnalyzer = &analysis.Analyzer{ func init() { // Export to gopls until this is a published modernizer. - goplsexport.SlicesBackwardModernizer = slicesbackwardAnalyzer + goplsexport.SlicesBackwardModernizer = slicesBackwardAnalyzer } // slicesbackward offers a fix to replace a manually-written backward loop: @@ -147,18 +148,47 @@ func slicesbackward(pass *analysis.Pass) (any, error) { // s[i] — pure element accesses that can be replaced by the value var // other — index used for non-indexing purposes var ( - sliceIndexes []*ast.IndexExpr - otherUses int + // First assignment in the loop body of the form "name := s[i]"; or nil. + firstSliceIdxAssign *ast.AssignStmt + // List of s[i] expressions to replace by the value var (excludes firstSliceIdxAssign, which will be entirely removed). + sliceIdxsReplace []*ast.IndexExpr + // Total count of s[i] usages. + sliceIdxs int + // Non-indexing uses of i. + otherUses int ) for curUse := range index.Uses(indexObj) { if !bodyCur.Contains(curUse) { continue } // Is i in the Index position of an s[i] expression? + // If so, we also need to check whether s[i] is an lvalue. If we're + // mutating the slice or taking an element's address, a fix will not + // be offered. if curUse.ParentEdgeKind() == edge.IndexExpr_Index { - idxExpr := curUse.Parent().Node().(*ast.IndexExpr) + if isScalarLvalue(pass.TypesInfo, curUse.Parent()) { + continue nextLoop + } + idxCur := curUse.Parent() + idxExpr := idxCur.Node().(*ast.IndexExpr) if astutil.EqualSyntax(idxExpr.X, sliceExpr) { - sliceIndexes = append(sliceIndexes, idxExpr) + sliceIdxs++ + // If the current statement is the first in the body of the form + // "name := s[i]", save it so we can use "name" as the value + // variable in slices.Backward. We can also remove the entire assign + // statement. + if firstSliceIdxAssign == nil && idxCur.ParentEdgeKind() == edge.AssignStmt_Rhs { + assignStmt := idxCur.Parent().Node().(*ast.AssignStmt) + if len(assignStmt.Lhs) == 1 && assignStmt.Tok == token.DEFINE { + // The condition above implies that assignStmt.Lhs[0] is a valid + // identifier. + firstSliceIdxAssign = assignStmt + // We don't need to replace the index expr with the value variable + // name if we are going to remove the entire assignment. + continue + } + } + sliceIdxsReplace = append(sliceIdxsReplace, idxExpr) continue } } @@ -167,15 +197,18 @@ func slicesbackward(pass *analysis.Pass) (any, error) { // Build the suggested fix. // - // for i := len(s) - 1; i >= 0; i-- { ... s[i] ... } - // ---------------------------- ---- - // _, v := range slices.Backward(s) v + // for i := len(s) - 1; i >= 0; i-- { ... s[i] ... } + // -------------------------------- ---- + // for _, v := range slices.Backward(s) { ... v ... } sliceStr := astutil.Format(pass.Fset, sliceExpr) prefix, edits := refactor.AddImport(info, file, "slices", "slices", "Backward", loop.Pos()) - elemName := freshName(info, index, info.Scopes[loop], loop.Pos(), bodyCur, bodyCur, token.NoPos, "v") + elemName := chooseValueName(firstSliceIdxAssign, sliceStr) + elemName = freshName(info, index, info.Scopes[loop], loop.Pos(), bodyCur, bodyCur, token.NoPos, elemName) - // Replace each s[i] with elemName. - for _, sx := range sliceIndexes { + // Replace each s[i] with elemName (except for in the statement of the + // form "name := s[i]" where we might have gotten elemName from - we will + // delete this entire statement instead). + for _, sx := range sliceIdxsReplace { edits = append(edits, analysis.TextEdit{ Pos: sx.Pos(), End: sx.End(), @@ -183,17 +216,27 @@ func slicesbackward(pass *analysis.Pass) (any, error) { }) } - // Replace the loop header with a range over slices.Backward. - var header string - if otherUses == 0 && len(sliceIndexes) > 0 { + if firstSliceIdxAssign != nil { + edits = append(edits, analysis.TextEdit{ + Pos: firstSliceIdxAssign.Pos(), + End: firstSliceIdxAssign.End(), + }) + } + + // Replace the loop header with a range over slices.Backward. In + // well-typed code, at least one of the index or value variables must be + // referenced inside the loop body (otherUses + sliceIndexes > 0). + var vars string + if otherUses == 0 { // sliceIdxs > 0 // All uses of i are s[i]; drop the index variable. - header = fmt.Sprintf("_, %s := range %sBackward(%s)", - elemName, prefix, sliceStr) - } else { - // i is used for other purposes; keep both index and value. - header = fmt.Sprintf("%s, %s := range %sBackward(%s)", - indexIdent.Name, elemName, prefix, sliceStr) + vars = fmt.Sprintf("_, %s", elemName) + } else if sliceIdxs == 0 { // otherUses > 0 + // Index i is not used in any s[i] expressions; drop the value variable. + vars = indexIdent.Name + } else { // otherUses > 0 && sliceIdxs > 0, keep both variables. + vars = fmt.Sprintf("%s, %s", indexIdent.Name, elemName) } + header := fmt.Sprintf("%s := range %sBackward(%s)", vars, prefix, sliceStr) edits = append(edits, analysis.TextEdit{ Pos: loop.Init.Pos(), End: loop.Post.End(), @@ -213,3 +256,20 @@ func slicesbackward(pass *analysis.Pass) (any, error) { } return nil, nil } + +// chooseValueName uses a heuristic to generate a name for the value variable in +// the call to slices.Backward. +func chooseValueName(assign *ast.AssignStmt, sliceStr string) string { + if assign != nil { + return assign.Lhs[0].(*ast.Ident).Name + } + // Heuristic: remove plural s suffix from slice var + // if present, otherwise use first letter. + if token.IsIdentifier(sliceStr) && len(sliceStr) > 1 { + if single, ok := strings.CutSuffix(sliceStr, "s"); ok { + return single + } + return sliceStr[:1] // first letter (assuming ASCII) + } + return "v" +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go index c1d42188f61dae..ed75e05e9a92b3 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go @@ -19,6 +19,7 @@ import ( "golang.org/x/tools/internal/astutil" "golang.org/x/tools/internal/refactor" "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/internal/typesinternal" "golang.org/x/tools/internal/typesinternal/typeindex" "golang.org/x/tools/internal/versions" ) @@ -58,12 +59,8 @@ var SlicesContainsAnalyzer = &analysis.Analyzer{ // statement is "found = false" (or vice versa), the // loop becomes "found = [!]slices.Contains(...)". // -// It may change cardinality of effects of the "needle" expression. -// (Mostly this appears to be a desirable optimization, avoiding -// redundantly repeated evaluation.) -// -// TODO(adonovan): Add a check that needle/predicate expression from -// if-statement has no effects. Now the program behavior may change. +// It rejects candidates whose needle/predicate expression from the if-statement +// has side effects to avoid changes in program behavior. func slicescontains(pass *analysis.Pass) (any, error) { // Skip the analyzer in packages where its // fixes would create an import cycle. @@ -174,6 +171,11 @@ func slicescontains(pass *analysis.Pass) (any, error) { return } + // Reject if needle/predicate expression has side effects. + if !typesinternal.NoEffects(info, arg2) { + return + } + // Reject if the body, needle or predicate references either range variable. usesRangeVar := func(n ast.Node) bool { cur, ok := curRange.FindNode(n) diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go index 86e1c8fd421b6e..19532686387f71 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go @@ -17,12 +17,11 @@ import ( "golang.org/x/tools/internal/analysis/analyzerutil" typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex" "golang.org/x/tools/internal/astutil" - "golang.org/x/tools/internal/goplsexport" "golang.org/x/tools/internal/stdlib" "golang.org/x/tools/internal/typesinternal/typeindex" ) -var stditeratorsAnalyzer = &analysis.Analyzer{ +var StdIteratorsAnalyzer = &analysis.Analyzer{ Name: "stditerators", Doc: analyzerutil.MustExtractDoc(doc, "stditerators"), Requires: []*analysis.Analyzer{ @@ -32,11 +31,6 @@ var stditeratorsAnalyzer = &analysis.Analyzer{ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#stditerators", } -func init() { - // Export to gopls until this is a published modernizer. - goplsexport.StdIteratorsModernizer = stditeratorsAnalyzer -} - // stditeratorsTable records std types that have legacy T.{Len,At} // iteration methods as well as a newer T.All method that returns an // iter.Seq. diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go index e89baa9b0e90a3..6aa9c881a32c4b 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go @@ -13,6 +13,7 @@ import ( "go/types" "maps" "slices" + "strings" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" @@ -47,6 +48,7 @@ func stringsbuilder(pass *analysis.Pass) (any, error) { var ( inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index) + info = pass.TypesInfo ) // Gather all local string variables that appear on the @@ -55,7 +57,7 @@ func stringsbuilder(pass *analysis.Pass) (any, error) { for curAssign := range inspect.Root().Preorder((*ast.AssignStmt)(nil)) { assign := curAssign.Node().(*ast.AssignStmt) if assign.Tok == token.ADD_ASSIGN && is[*ast.Ident](assign.Lhs[0]) { - if v, ok := pass.TypesInfo.Uses[assign.Lhs[0].(*ast.Ident)].(*types.Var); ok && + if v, ok := info.Uses[assign.Lhs[0].(*ast.Ident)].(*types.Var); ok && v.Kind() == types.LocalVar && types.Identical(v.Type(), builtinString.Type()) { candidates[v] = true @@ -75,7 +77,7 @@ func stringsbuilder(pass *analysis.Pass) (any, error) { // Now check each candidate variable's decl and uses. nextcand: for _, v := range slices.SortedFunc(maps.Keys(candidates), lexicalOrder) { - var edits []analysis.TextEdit + var edits, postEdits []analysis.TextEdit // postEdits are emitted last // Check declaration of s has one of these forms: // @@ -100,6 +102,13 @@ nextcand: if file == lastEditFile && v.Pos() < lastEditEnd { continue } + filename := pass.Fset.File(file.FileStart).Name() + // Suppress diagnostics in test files, where suggested fixes may increase + // verbosity, and performance doesn't matter as much. + // See https://go.dev/issue/78613 + if strings.HasSuffix(filename, "_test.go") { + continue + } ek := def.ParentEdgeKind() if ek == edge.AssignStmt_Lhs && @@ -121,10 +130,10 @@ nextcand: // Add strings import. prefix, importEdits := refactor.AddImport( - pass.TypesInfo, astutil.EnclosingFile(def), "strings", "strings", "Builder", v.Pos()) + info, astutil.EnclosingFile(def), "strings", "strings", "Builder", v.Pos()) edits = append(edits, importEdits...) - if isEmptyString(pass.TypesInfo, assign.Rhs[0]) { + if isEmptyString(info, assign.Rhs[0]) { // s := "" // --------------------- // var s strings.Builder @@ -171,7 +180,7 @@ nextcand: // Add strings import. prefix, importEdits := refactor.AddImport( - pass.TypesInfo, astutil.EnclosingFile(def), "strings", "strings", "Builder", v.Pos()) + info, astutil.EnclosingFile(def), "strings", "strings", "Builder", v.Pos()) edits = append(edits, importEdits...) spec := def.Parent().Node().(*ast.ValueSpec) @@ -193,7 +202,7 @@ nextcand: NewText: fmt.Appendf(nil, " %sBuilder", prefix), }) - if len(spec.Values) > 0 && !isEmptyString(pass.TypesInfo, spec.Values[0]) { + if len(spec.Values) > 0 && !isEmptyString(info, spec.Values[0]) { if decl.Rparen.IsValid() { // var decl with explicit parens: // @@ -273,11 +282,8 @@ nextcand: ) for curUse := range index.Uses(v) { // Strip enclosing parens around Ident. + curUse = astutil.UnparenEnclosingCursor(curUse) ek := curUse.ParentEdgeKind() - for ek == edge.ParenExpr_X { - curUse = curUse.Parent() - ek = curUse.ParentEdgeKind() - } // intervening reports whether cur has an ancestor of // one of the given types that is within the scope of v. @@ -315,20 +321,21 @@ nextcand: // s += expr // ------------- - // s.WriteString(expr) - edits = append(edits, []analysis.TextEdit{ + edits = append(edits, analysis.TextEdit{ // replace " += " with ".WriteString(" - { - Pos: assign.Lhs[0].End(), - End: assign.Rhs[0].Pos(), - NewText: []byte(".WriteString("), - }, + Pos: assign.Lhs[0].End(), + End: assign.Rhs[0].Pos(), + NewText: []byte(".WriteString("), + }) + + // Delay inserting the closing parenthesis, in case it overlaps with a + // .String() edit, since it would need to come after. + postEdits = append(postEdits, analysis.TextEdit{ // insert ")" - { - Pos: assign.End(), - End: assign.End(), - NewText: []byte(")"), - }, - }...) + Pos: assign.End(), + End: assign.End(), + NewText: []byte(")"), + }) } else if ek == edge.UnaryExpr_X && curUse.Parent().Node().(*ast.UnaryExpr).Op == token.AND { @@ -357,6 +364,8 @@ nextcand: continue nextcand // no += in a loop; reject } + edits = append(edits, postEdits...) + lastEditFile = file lastEditEnd = edits[len(edits)-1].End diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go index 6192c56fa34041..ae93d4d3f26b9b 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go @@ -21,14 +21,13 @@ import ( "golang.org/x/tools/internal/analysis/analyzerutil" typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex" "golang.org/x/tools/internal/astutil" - "golang.org/x/tools/internal/goplsexport" "golang.org/x/tools/internal/moreiters" "golang.org/x/tools/internal/typesinternal" "golang.org/x/tools/internal/typesinternal/typeindex" "golang.org/x/tools/internal/versions" ) -var stringscutAnalyzer = &analysis.Analyzer{ +var StringsCutAnalyzer = &analysis.Analyzer{ Name: "stringscut", Doc: analyzerutil.MustExtractDoc(doc, "stringscut"), Requires: []*analysis.Analyzer{ @@ -39,11 +38,6 @@ var stringscutAnalyzer = &analysis.Analyzer{ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#stringscut", } -func init() { - // Export to gopls until this is a published modernizer. - goplsexport.StringsCutModernizer = stringscutAnalyzer -} - // stringscut offers a fix to replace an occurrence of strings.Index{,Byte} with // strings.{Cut,Contains}, and similar fixes for functions in the bytes package. // Consider some candidate for replacement i := strings.Index(s, substr). @@ -92,7 +86,7 @@ func init() { // } // // If the condition involving `i` is equivalent to i >= 0, then we replace it with -// `if ok“. +// `if ok`. // If the condition is negated (e.g. equivalent to `i < 0`), we use `if !ok` instead. // If the slices of `s` match `s[:i]` or `s[i+len(substr):]` or their variants listed above, // then we replace them with before and after. @@ -124,6 +118,8 @@ func stringscut(pass *analysis.Pass) (any, error) { bytesIndexByte = index.Object("bytes", "IndexByte") ) + stringsplitCut(pass, index) + scopeFixCount := make(map[*types.Scope]int) // the number of times we have offered a fix within a given scope in the current pass for _, obj := range []types.Object{ @@ -149,11 +145,20 @@ func stringscut(pass *analysis.Pass) (any, error) { switch ek, idx := curCall.ParentEdge(); ek { case edge.ValueSpec_Values: // Have: var i = strings.Index(...) + // If the call occurs in a multi-value declaration or assignment, don't suggest a fix because it would produce invalid code (See golang/go#78643). + spec := curCall.Parent().Node().(*ast.ValueSpec) + if len(spec.Names) != 1 { + continue + } curName := curCall.Parent().ChildAt(edge.ValueSpec_Names, idx) iIdent = curName.Node().(*ast.Ident) case edge.AssignStmt_Rhs: // Have: i := strings.Index(...) // (Must be i's definition.) + assign := curCall.Parent().Node().(*ast.AssignStmt) + if len(assign.Lhs) != 1 { + continue + } curLhs := curCall.Parent().ChildAt(edge.AssignStmt_Lhs, idx) iIdent, _ = curLhs.Node().(*ast.Ident) // may be nil } @@ -367,6 +372,129 @@ func stringscut(pass *analysis.Pass) (any, error) { return nil, nil } +// stringsplitCut reports patterns where strings.Split or strings.SplitN with +// n=2 is immediately indexed at [0], which can be simplified to strings.Cut, +// when sep is a non-empty string constant. The transformation is +// semantics-preserving only for non-empty sep: strings.Split(s, "")[0] +// returns the first character of s, but strings.Cut(s, "").before is "". +// For variable sep the value is unknown at analysis time, so we conservatively +// skip those cases too. +// +// For example: +// +// x := strings.SplitN(s, ",", 2)[0] +// ------ -- +// x, _, _ := strings.Cut(s, ",") +// +// Requires Go 1.18 (when strings.Cut was added). +func stringsplitCut(pass *analysis.Pass, index *typeindex.Index) { + info := pass.TypesInfo + + stringsSplit := index.Object("strings", "Split") + stringsSplitN := index.Object("strings", "SplitN") + + for _, obj := range []types.Object{stringsSplit, stringsSplitN} { + for curCall := range index.Calls(obj) { + callExpr := curCall.Node().(*ast.CallExpr) + + // For SplitN, the third argument must be the integer constant 2. + if obj.Name() == "SplitN" && !isIntLiteral(info, callExpr.Args[2], 2) { + continue + } + + // Sep must be a non-empty constant string. + // strings.Split(s, "")[0] returns the first character of s, but + // strings.Cut(s, "").before is "", so the semantics differ for + // an empty sep. For a variable sep we cannot rule out "" at + // analysis time, so we conservatively skip those cases too. + sepTV := info.Types[callExpr.Args[1]] + if sepTV.Value == nil || constant.StringVal(sepTV.Value) == "" { + continue + } + + // The call must be the X of an IndexExpr. + if curCall.ParentEdgeKind() != edge.IndexExpr_X { + continue + } + parent := curCall.Parent() + indexExpr := parent.Node().(*ast.IndexExpr) + + // The index must be the integer constant 0. + if !isZeroIntConst(info, indexExpr.Index) { + continue + } + + // The IndexExpr must be the sole RHS of an assignment statement. + if parent.ParentEdgeKind() != edge.AssignStmt_Rhs { + continue + } + assign := parent.Parent().Node().(*ast.AssignStmt) + if assign.Tok != token.DEFINE || len(assign.Lhs) != 1 { + continue + } + + // The LHS must be a single non-blank identifier. + lhsIdent, ok := assign.Lhs[0].(*ast.Ident) + if !ok || lhsIdent.Name == "_" { + continue + } + + // strings.Cut requires Go 1.18. + if !analyzerutil.FileUsesGoVersion(pass, astutil.EnclosingFile(curCall), versions.Go1_18) { + continue + } + + // Build the fix. + // + // x := strings.SplitN(s, sep, 2)[0] + // --- ------ --- + // x, _, _ := strings.Cut(s, sep) + callFunIdent := typesinternal.UsedIdent(info, callExpr.Fun) + + var edits []analysis.TextEdit + + // LHS: insert ", _, _" after x + edits = append(edits, analysis.TextEdit{ + Pos: lhsIdent.End(), + End: lhsIdent.End(), + NewText: []byte(", _, _"), + }) + + // Function name: Split/SplitN → Cut + edits = append(edits, analysis.TextEdit{ + Pos: callFunIdent.Pos(), + End: callFunIdent.End(), + NewText: []byte("Cut"), + }) + + // For SplitN: remove the ", 2" third argument. + if obj.Name() == "SplitN" { + edits = append(edits, analysis.TextEdit{ + Pos: callExpr.Args[1].End(), // after sep + End: callExpr.Rparen, // before ) + }) + } + + // Remove the "[0]" index expression. + edits = append(edits, analysis.TextEdit{ + Pos: indexExpr.Lbrack, + End: indexExpr.End(), + }) + + pass.Report(analysis.Diagnostic{ + Pos: callExpr.Fun.Pos(), + End: callExpr.Fun.End(), + Message: fmt.Sprintf("strings.%s call can be simplified using strings.Cut", obj.Name()), + Category: "stringscut", + SuggestedFixes: []analysis.SuggestedFix{{ + Message: fmt.Sprintf("Simplify strings.%s call using strings.Cut", obj.Name()), + TextEdits: edits, + }}, + }) + } + } +} + // indexArgValid reports whether expr is a valid strings.Index(_, _) arg // for the transformation. An arg is valid iff it is: // - constant; @@ -387,10 +515,10 @@ func indexArgValid(info *types.Info, index *typeindex.Index, expr ast.Expr, afte case *ast.Ident: sObj := info.Uses[expr] sUses := index.Uses(sObj) - return !hasModifyingUses(info, sUses, afterPos) + return !hasModifyingUses(sUses, afterPos) default: // For now, skip instances where s or substr are not - // identifers, basic lits, or call expressions of the form + // identifiers, basic lits, or call expressions of the form // []byte(s). // TODO(mkalil): Handle s and substr being expressions like ptr.field[i]. // From adonovan: We'd need to analyze s and substr to see @@ -487,18 +615,15 @@ func checkIdxUses(info *types.Info, uses iter.Seq[inspector.Cursor], s, substr a // hasModifyingUses reports whether any of the uses involve potential // modifications. Uses involving assignments before the "afterPos" won't be // considered. -func hasModifyingUses(info *types.Info, uses iter.Seq[inspector.Cursor], afterPos token.Pos) bool { +func hasModifyingUses(uses iter.Seq[inspector.Cursor], afterPos token.Pos) bool { for curUse := range uses { ek := curUse.ParentEdgeKind() if ek == edge.AssignStmt_Lhs { if curUse.Node().Pos() <= afterPos { continue } - assign := curUse.Parent().Node().(*ast.AssignStmt) - if sameObject(info, assign.Lhs[0], curUse.Node().(*ast.Ident)) { - // Modifying use because we are reassigning the value of the object. - return true - } + // Any use on the LHS is a modifying use. + return true } else if ek == edge.UnaryExpr_X && curUse.Parent().Node().(*ast.UnaryExpr).Op == token.AND { // Modifying use because we might be passing the object by reference (an explicit &). diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go index 13065312732cdb..79859a536d03f0 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go @@ -416,7 +416,7 @@ func match(info *types.Info, arg ast.Expr, param *types.Var) bool { } // propagate propagates changes in wrapper (non-None) kind information backwards -// through through the wrapper.callers graph of well-formed forwarding calls. +// through the wrapper.callers graph of well-formed forwarding calls. func propagate(pass *analysis.Pass, w *wrapper, call *ast.CallExpr, kind Kind, res *Result) { // Check correct call forwarding. // diff --git a/src/cmd/vendor/golang.org/x/tools/go/ast/edge/edge.go b/src/cmd/vendor/golang.org/x/tools/go/ast/edge/edge.go index 4f6ccfd6e5e293..8dc4dd1502baa3 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/ast/edge/edge.go +++ b/src/cmd/vendor/golang.org/x/tools/go/ast/edge/edge.go @@ -12,7 +12,7 @@ import ( "reflect" ) -// A Kind describes a field of an ast.Node struct. +// A Kind describes a field of an [ast.Node] struct. type Kind uint8 // String returns a description of the edge kind. @@ -41,21 +41,25 @@ func (k Kind) Get(n ast.Node, idx int) ast.Node { panic(fmt.Sprintf("%v.Get(%T): invalid node type", k, n)) } v := reflect.ValueOf(n).Elem().Field(fieldInfos[k].index) - if idx != -1 { - v = v.Index(idx) // asserts valid index - } else { - // (The type assertion below asserts that v is not a slice.) + + if v.Kind() == reflect.Slice { + v = v.Index(idx) // asserts valid idx + } else if idx != -1 { + panic(fmt.Sprintf("%v, Get(%T, %d): cannot index non-slice", v, n, idx)) } - return v.Interface().(ast.Node) // may be nil + + out, _ := v.Interface().(ast.Node) // may be nil + return out } +// Each [Kind] is named Type_Field, where Type is the +// [ast.Node] struct type and Field is the name of the field const ( Invalid Kind = iota // for nodes at the root of the traversal - // Kinds are sorted alphabetically. - // Numbering is not stable. - // Each is named Type_Field, where Type is the - // ast.Node struct type and Field is the name of the field + // As of Go1.26 these kinds are sorted alphabetically, but + // numbering must be stable, so any new addition of const should + // use a new value (be added at the end of the list). ArrayType_Elt ArrayType_Len diff --git a/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go b/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go index 77aad553d5b93f..0d6d0bced0fae9 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go +++ b/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go @@ -24,8 +24,10 @@ package objectpath import ( + "encoding/binary" "fmt" "go/types" + "slices" "strconv" "strings" @@ -124,7 +126,66 @@ func For(obj types.Object) (Path, error) { // An Encoder amortizes the cost of encoding the paths of multiple objects. // The zero value of an Encoder is ready to use. type Encoder struct { - scopeMemo map[*types.Scope][]types.Object // memoization of scopeObjects + pkgIndex map[*types.Package]*pkgIndex +} + +// A traversal encapsulates the state of a single traversal of the object/type graph. +type traversal struct { + pkg *types.Package + ix *pkgIndex // non-nil if we are building the index + + target types.Object // the sought symbol (if ix == nil) + found Path // the found path (if ix == nil) + + // These maps are used to short circuit cycles through + // interface methods, such as occur in the following example: + // + // type I interface { f() interface{I} } + // + // See golang/go#68046 for details. + seenTParamNames map[*types.TypeName]bool // global cycle breaking through type parameters + seenMethods map[*types.Func]bool // global cycle breaking through recursive interfaces +} + +// A pkgIndex holds a compressed index of objectpaths of all symbols +// (fields, methods, params) requiring search for an entire package. +// +// The first time a search for a given package is requested, we simply +// traverse the type graph for the target object, maintaining the +// current object path as a stack. If we find the target object, we +// save the path and terminate the main loop (but it's not worth +// breaking out of the current recursion). +// +// On the second search (a pkgIndex exists but its data is nil), we +// build an index of the traversal, which we use for all subsequent +// searches. +// +// The traversal index is encoded in the data field as a list of records, +// one per node, in preorder. Records are of two types: +// +// - A record for a package-level object consists of a pair +// (parent, nameIndex uvarint), where parent is zero and +// nameIndex is the index of the object's name in the sorted +// pkg.Scope().Names() slice. +// +// - A record for a nested node (a segment of an object path) +// consists of (parent uvarint, op byte, index uvarint), where +// parent is the index of the record for the parent node, +// op is the destructuring operator, and index (if op = [AFMTr]) +// is its integer operand. +// +// Since data[0] = 0 all nodes have positive offsets. In effect the +// encoding is a trie in which each node stores one path segment +// and points to the node for its prefix. +// +// TODO(adonovan): opt: evaluate an only 2-level tree with nodes for +// package-level objects and the-rest-of-the-path. One calculation +// suggested that it might be similar speed but 30% more compact. +type pkgIndex struct { + pkg *types.Package + data []byte // encoding of traversal; nil if not yet constructed + scopeNames []string // memo of pkg.Scope().Names() to avoid O(n) alloc/sort at lookup + offsets map[types.Object]uint32 // each object's node offset within encoded traversal data } // For returns the path to an object relative to its package, @@ -211,10 +272,9 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { if pkg == nil { return "", fmt.Errorf("predeclared %s has no path", obj) } - scope := pkg.Scope() // 2. package-level object? - if scope.Lookup(obj.Name()) == obj { + if pkg.Scope().Lookup(obj.Name()) == obj { // Only exported objects (and non-exported types) have a path. // Non-exported types may be referenced by other objects. if _, ok := obj.(*types.TypeName); !ok && !obj.Exported() { @@ -232,19 +292,18 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { // have a path. return "", fmt.Errorf("no path for %v", obj) } + case *types.Const, // Only package-level constants have a path. *types.Label, // Labels are function-local. *types.PkgName: // PkgNames are file-local. return "", fmt.Errorf("no path for %v", obj) case *types.Var: - // Could be: - // - a field (obj.IsField()) - // - a func parameter or result - // - a local var. - // Sadly there is no way to distinguish - // a param/result from a local - // so we must proceed to the find. + // A var, if not package-level, must be a + // parameter (incl. receiver) or result, or a struct field. + if obj.Kind() == types.LocalVar { + return "", fmt.Errorf("no path for local %v", obj) + } case *types.Func: // A func, if not package-level, must be a method. @@ -261,89 +320,311 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { panic(obj) } - // 4. Search the API for the path to the var (field/param/result) or method. + // 4. Search the object/type graph for the path to + // the var (field/param/result) or method. + ix, ok := enc.pkgIndex[pkg] + if !ok { + // First search: don't build an index, just traverse. + // This avoids allocation in [For], whose Encoder + // lives for a single call. + ix = &pkgIndex{pkg: pkg} + + if enc.pkgIndex == nil { + enc.pkgIndex = make(map[*types.Package]*pkgIndex) + } + enc.pkgIndex[pkg] = ix // build the index next time + + f := traversal{pkg: pkg, target: obj} + f.traverse() + + if f.found != "" { + return f.found, nil + } + } else { + // Second search: build an index while traversing. + if ix.data == nil { + ix.offsets = make(map[types.Object]uint32) + ix.data = []byte{0} // offset 0 is sentinel + (&traversal{pkg: pkg, ix: ix}).traverse() + } + + // Second and later searches: consult the index. + if offset, ok := ix.offsets[obj]; ok { + return ix.path(offset), nil + } + } + + return "", fmt.Errorf("can't find path for %v in %s", obj, pkg.Path()) +} + +// traverse performs a complete traversal of all symbols reachable from the package. +func (tr *traversal) traverse() { + scope := tr.pkg.Scope() + names := scope.Names() + if tr.ix != nil { + tr.ix.scopeNames = names + } + + empty := make([]byte, 0, 48) // initial space for stack (ix == nil) - // First inspect package-level named types. + // First inspect package-level type names. // In the presence of path aliases, these give // the best paths because non-types may // refer to types, but not the reverse. - empty := make([]byte, 0, 48) // initial space - objs := enc.scopeObjects(scope) - for _, o := range objs { - tname, ok := o.(*types.TypeName) - if !ok { - continue // handle non-types in second pass + for i, name := range names { + if tr.found != "" { + return // found (ix == nil) } - path := append(empty, o.Name()...) - path = append(path, opType) - - T := o.Type() - if alias, ok := T.(*types.Alias); ok { - if r := findTypeParam(obj, alias.TypeParams(), path, opTypeParam); r != nil { - return Path(r), nil - } - if r := find(obj, alias.Rhs(), append(path, opRhs)); r != nil { - return Path(r), nil - } + obj := scope.Lookup(name) + if _, ok := obj.(*types.TypeName); !ok { + continue // handle non-types in second pass + } - } else if tname.IsAlias() { - // legacy alias - if r := find(obj, T, path); r != nil { - return Path(r), nil - } + // emit (name, opType) + var path []byte + var offset uint32 + if tr.ix == nil { + path = append(empty, name...) + path = append(path, opType) + } else { + offset = tr.ix.emitPackageLevel(i) + tr.ix.offsets[obj] = offset + offset = tr.ix.emitPathSegment(offset, opType, -1) + } - } else if named, ok := T.(*types.Named); ok { - // defined (named) type - if r := findTypeParam(obj, named.TypeParams(), path, opTypeParam); r != nil { - return Path(r), nil - } - if r := find(obj, named.Underlying(), append(path, opUnderlying)); r != nil { - return Path(r), nil - } + // A TypeName (for Named or Alias) may have type parameters. + switch t := obj.Type().(type) { + case *types.Alias: + tr.tparams(t.TypeParams(), path, offset, opTypeParam) + tr.typ(path, offset, opRhs, -1, t.Rhs()) + case *types.Named: + tr.tparams(t.TypeParams(), path, offset, opTypeParam) + tr.typ(path, offset, opUnderlying, -1, t.Underlying()) } } // Then inspect everything else: - // non-types, and declared methods of defined types. - for _, o := range objs { - path := append(empty, o.Name()...) - if _, ok := o.(*types.TypeName); !ok { - if o.Exported() { + // exported non-types, and declared methods of defined types. + for i, name := range names { + if tr.found != "" { + return // found (ix == nil) + } + + obj := scope.Lookup(name) + + if tname, ok := obj.(*types.TypeName); !ok { + if obj.Exported() { // exported non-type (const, var, func) - if r := find(obj, o.Type(), append(path, opType)); r != nil { - return Path(r), nil + var path []byte + var offset uint32 + if tr.ix == nil { + path = append(empty, name...) + } else { + offset = tr.ix.emitPackageLevel(i) + tr.ix.offsets[obj] = offset } + tr.typ(path, offset, opType, -1, obj.Type()) } - continue - } - // Inspect declared methods of defined types. - if T, ok := types.Unalias(o.Type()).(*types.Named); ok { - path = append(path, opType) + } else if T, ok := types.Unalias(tname.Type()).(*types.Named); ok { + // defined type + var path []byte + var offset uint32 + if tr.ix == nil { + path = append(empty, name...) + path = append(path, opType) + } else { + // Inv: map entry for obj was populated in first pass. + offset = tr.ix.emitPathSegment(tr.ix.offsets[obj], opType, -1) + } + + // Inspect declared methods of defined types. + // // The method index here is always with respect // to the underlying go/types data structures, // which ultimately derives from source order // and must be preserved by export data. for i := 0; i < T.NumMethods(); i++ { m := T.Method(i) - path2 := appendOpArg(path, opMethod, i) - if m == obj { - return Path(path2), nil // found declared method - } - if r := find(obj, m.Type(), append(path2, opType)); r != nil { - return Path(r), nil + tr.object(path, offset, opMethod, i, m) + } + } + } +} + +func (tr *traversal) visitType(path []byte, offset uint32, T types.Type) { + switch T := T.(type) { + case *types.Alias: + tr.typ(path, offset, opRhs, -1, T.Rhs()) + + case *types.Basic, *types.Named: + // Named types belonging to pkg were handled already, + // so T must belong to another package. No path. + return + + case *types.Pointer, *types.Slice, *types.Array, *types.Chan: + type hasElem interface{ Elem() types.Type } // note: includes Map + tr.typ(path, offset, opElem, -1, T.(hasElem).Elem()) + + case *types.Map: + tr.typ(path, offset, opKey, -1, T.Key()) + tr.typ(path, offset, opElem, -1, T.Elem()) + + case *types.Signature: + tr.tparams(T.RecvTypeParams(), path, offset, opRecvTypeParam) + tr.tparams(T.TypeParams(), path, offset, opTypeParam) + tr.typ(path, offset, opParams, -1, T.Params()) + tr.typ(path, offset, opResults, -1, T.Results()) + + case *types.Struct: + for i := 0; i < T.NumFields(); i++ { + tr.object(path, offset, opField, i, T.Field(i)) + } + + case *types.Tuple: + for i := 0; i < T.Len(); i++ { + tr.object(path, offset, opAt, i, T.At(i)) + } + + case *types.Interface: + for i := 0; i < T.NumMethods(); i++ { + m := T.Method(i) + if m.Pkg() != nil && m.Pkg() != tr.pkg { + continue // embedded method from another package + } + if !tr.seenMethods[m] { + if tr.seenMethods == nil { + tr.seenMethods = make(map[*types.Func]bool) } + tr.seenMethods[m] = true + tr.object(path, offset, opMethod, i, m) } } + + case *types.TypeParam: + tname := T.Obj() + if tname.Pkg() != nil && tname.Pkg() != tr.pkg { + return // type parameter from another package + } + if !tr.seenTParamNames[tname] { + if tr.seenTParamNames == nil { + tr.seenTParamNames = make(map[*types.TypeName]bool) + } + tr.seenTParamNames[tname] = true + tr.object(path, offset, opObj, -1, tname) + tr.typ(path, offset, opConstraint, -1, T.Constraint()) + } } +} - return "", fmt.Errorf("can't find path for %v in %s", obj, pkg.Path()) +func (tr *traversal) tparams(list *types.TypeParamList, path []byte, offset uint32, op byte) { + for i := 0; i < list.Len(); i++ { + tr.typ(path, offset, op, i, list.At(i)) + } +} + +// typ descends the type graph edge (op, index), then proceeds to traverse type t. +func (tr *traversal) typ(path []byte, offset uint32, op byte, index int, t types.Type) { + if tr.ix == nil { + path = appendOpArg(path, op, index) + } else { + offset = tr.ix.emitPathSegment(offset, op, index) + } + tr.visitType(path, offset, t) +} + +// object descends the type graph edge (op, index), records object +// obj, then proceeds to traverse its type. +func (tr *traversal) object(path []byte, offset uint32, op byte, index int, obj types.Object) { + if tr.ix == nil { + path = appendOpArg(path, op, index) + if obj == tr.target && tr.found == "" { + tr.found = Path(path) + } + path = append(path, opType) + } else { + offset = tr.ix.emitPathSegment(offset, op, index) + if _, ok := tr.ix.offsets[obj]; !ok { + tr.ix.offsets[obj] = offset + } + offset = tr.ix.emitPathSegment(offset, opType, -1) + } + tr.visitType(path, offset, obj.Type()) +} + +// emitPackageLevel encodes a record for a package-level symbol, +// identified by its index in ix.scopeNames. +func (p *pkgIndex) emitPackageLevel(index int) uint32 { + off := uint32(len(p.data)) + p.data = append(p.data, 0) // zero varint => no parent + p.data = binary.AppendUvarint(p.data, uint64(index)) + return off +} + +// emitPathSegment emits a record for a non-initial object path segment. +func (p *pkgIndex) emitPathSegment(parent uint32, op byte, index int) uint32 { + off := uint32(len(p.data)) + p.data = binary.AppendUvarint(p.data, uint64(parent)) + p.data = append(p.data, op) + switch op { + case opAt, opField, opMethod, opTypeParam, opRecvTypeParam: + p.data = binary.AppendUvarint(p.data, uint64(index)) + } + return off +} + +// path returns the Path for the encoded node at the specified offset. +func (p *pkgIndex) path(offset uint32) Path { + var elems []string // path elements in reverse + for { + // Read parent index. + parent, n := binary.Uvarint(p.data[offset:]) + offset += uint32(n) + + if parent == 0 { + break // root (end of path) + } + + op := p.data[offset] + offset++ + + // The [AFMTr] operators have a numeric operand. + switch op { + case opAt, opField, opMethod, opTypeParam, opRecvTypeParam: + val, n := binary.Uvarint(p.data[offset:]) + offset += uint32(n) + elems = append(elems, strconv.Itoa(int(val))) + } + + elems = append(elems, string([]byte{op})) + + offset = uint32(parent) + } + idx, _ := binary.Uvarint(p.data[offset:]) + + // Convert index to Path string. + name := p.scopeNames[idx] + sz := len(name) + for _, elem := range elems { + sz += len(elem) + } + var buf strings.Builder + buf.Grow(sz) + buf.WriteString(name) + for _, elem := range slices.Backward(elems) { + buf.WriteString(elem) + } + return Path(buf.String()) } -func appendOpArg(path []byte, op byte, arg int) []byte { +// appendOpArg appends (op, index) to the object path. +// A negative index is ignored. +func appendOpArg(path []byte, op byte, index int) []byte { path = append(path, op) - path = strconv.AppendInt(path, int64(arg), 10) + if index >= 0 { + path = strconv.AppendInt(path, int64(index), 10) + } return path } @@ -442,138 +723,6 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) { // panic(fmt.Sprintf("couldn't find method %s on type %s; methods: %#v", meth, named, enc.namedMethods(named))) } -// find finds obj within type T, returning the path to it, or nil if not found. -// -// The seen map is used to short circuit cycles through type parameters. If -// nil, it will be allocated as necessary. -// -// The seenMethods map is used internally to short circuit cycles through -// interface methods, such as occur in the following example: -// -// type I interface { f() interface{I} } -// -// See golang/go#68046 for details. -func find(obj types.Object, T types.Type, path []byte) []byte { - return (&finder{obj: obj}).find(T, path) -} - -// finder closes over search state for a call to find. -type finder struct { - obj types.Object // the sought object - seenTParamNames map[*types.TypeName]bool // for cycle breaking through type parameters - seenMethods map[*types.Func]bool // for cycle breaking through recursive interfaces -} - -func (f *finder) find(T types.Type, path []byte) []byte { - switch T := T.(type) { - case *types.Alias: - return f.find(types.Unalias(T), path) - case *types.Basic, *types.Named: - // Named types belonging to pkg were handled already, - // so T must belong to another package. No path. - return nil - case *types.Pointer: - return f.find(T.Elem(), append(path, opElem)) - case *types.Slice: - return f.find(T.Elem(), append(path, opElem)) - case *types.Array: - return f.find(T.Elem(), append(path, opElem)) - case *types.Chan: - return f.find(T.Elem(), append(path, opElem)) - case *types.Map: - if r := f.find(T.Key(), append(path, opKey)); r != nil { - return r - } - return f.find(T.Elem(), append(path, opElem)) - case *types.Signature: - if r := f.findTypeParam(T.RecvTypeParams(), path, opRecvTypeParam); r != nil { - return r - } - if r := f.findTypeParam(T.TypeParams(), path, opTypeParam); r != nil { - return r - } - if r := f.find(T.Params(), append(path, opParams)); r != nil { - return r - } - return f.find(T.Results(), append(path, opResults)) - case *types.Struct: - for i := 0; i < T.NumFields(); i++ { - fld := T.Field(i) - path2 := appendOpArg(path, opField, i) - if fld == f.obj { - return path2 // found field var - } - if r := f.find(fld.Type(), append(path2, opType)); r != nil { - return r - } - } - return nil - case *types.Tuple: - for i := 0; i < T.Len(); i++ { - v := T.At(i) - path2 := appendOpArg(path, opAt, i) - if v == f.obj { - return path2 // found param/result var - } - if r := f.find(v.Type(), append(path2, opType)); r != nil { - return r - } - } - return nil - case *types.Interface: - for i := 0; i < T.NumMethods(); i++ { - m := T.Method(i) - if f.seenMethods[m] { - continue // break cycles (see TestIssue70418) - } - path2 := appendOpArg(path, opMethod, i) - if m == f.obj { - return path2 // found interface method - } - if f.seenMethods == nil { - f.seenMethods = make(map[*types.Func]bool) - } - f.seenMethods[m] = true - if r := f.find(m.Type(), append(path2, opType)); r != nil { - return r - } - } - return nil - case *types.TypeParam: - name := T.Obj() - if f.seenTParamNames[name] { - return nil - } - if name == f.obj { - return append(path, opObj) - } - if f.seenTParamNames == nil { - f.seenTParamNames = make(map[*types.TypeName]bool) - } - f.seenTParamNames[name] = true - if r := f.find(T.Constraint(), append(path, opConstraint)); r != nil { - return r - } - return nil - } - panic(T) -} - -func findTypeParam(obj types.Object, list *types.TypeParamList, path []byte, op byte) []byte { - return (&finder{obj: obj}).findTypeParam(list, path, op) -} - -func (f *finder) findTypeParam(list *types.TypeParamList, path []byte, op byte) []byte { - for i := 0; i < list.Len(); i++ { - tparam := list.At(i) - path2 := appendOpArg(path, op, i) - if r := f.find(tparam, path2); r != nil { - return r - } - } - return nil -} - // Object returns the object denoted by path p within the package pkg. func Object(pkg *types.Package, p Path) (types.Object, error) { pathstr := string(p) @@ -708,7 +857,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { } tparams := hasTypeParams.TypeParams() if n := tparams.Len(); index >= n { - return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n) + return nil, fmt.Errorf("type parameter index %d out of range [0-%d)", index, n) } t = tparams.At(index) @@ -719,7 +868,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { } rtparams := sig.RecvTypeParams() if n := rtparams.Len(); index >= n { - return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n) + return nil, fmt.Errorf("receiver type parameter index %d out of range [0-%d)", index, n) } t = rtparams.At(index) @@ -794,23 +943,3 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { return obj, nil // success } - -// scopeObjects is a memoization of scope objects. -// Callers must not modify the result. -func (enc *Encoder) scopeObjects(scope *types.Scope) []types.Object { - m := enc.scopeMemo - if m == nil { - m = make(map[*types.Scope][]types.Object) - enc.scopeMemo = m - } - objs, ok := m[scope] - if !ok { - names := scope.Names() // allocates and sorts - objs = make([]types.Object, len(names)) - for i, name := range names { - objs[i] = scope.Lookup(name) - } - m[scope] = objs - } - return objs -} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go b/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go index 5ed4765c723d63..40a347214b5a38 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go @@ -8,6 +8,7 @@ import ( "go/ast" "go/token" "iter" + "sort" "strings" ) @@ -114,18 +115,25 @@ func Directives(g *ast.CommentGroup) (res []*Directive) { } // Comments returns an iterator over the comments overlapping the specified interval. +// Comments are sorted by position in the file, so we can use binary search. func Comments(file *ast.File, start, end token.Pos) iter.Seq[*ast.Comment] { - // TODO(adonovan): optimize use binary O(log n) instead of linear O(n) search. return func(yield func(*ast.Comment) bool) { - for _, cg := range file.Comments { - for _, co := range cg.List { + // Find the first comment group that overlaps the range. + i := sort.Search(len(file.Comments), func(i int) bool { + return file.Comments[i].End() >= start + }) + for _, cg := range file.Comments[i:] { + if cg.Pos() > end { + return + } + // Find the first comment in the group that overlaps the range. + j := sort.Search(len(cg.List), func(j int) bool { + return cg.List[j].End() >= start + }) + for _, co := range cg.List[j:] { if co.Pos() > end { return } - if co.End() < start { - continue - } - if !yield(co) { return } diff --git a/src/cmd/vendor/golang.org/x/tools/internal/astutil/cursor.go b/src/cmd/vendor/golang.org/x/tools/internal/astutil/cursor.go new file mode 100644 index 00000000000000..74e75d1458a20c --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/internal/astutil/cursor.go @@ -0,0 +1,38 @@ +// Copyright 2026 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 astutil + +import ( + "go/ast" + + "golang.org/x/tools/go/ast/edge" + "golang.org/x/tools/go/ast/inspector" +) + +// UnparenCursor returns the cursor for an expression with any +// enclosing parentheses removed, similar to [ast.Unparen]. +// It is often prudent to call this before switching on the +// type of cur.Node(). +// +// See also [UnparenEnclosingCursor]. +func UnparenCursor(cur inspector.Cursor) inspector.Cursor { + for is[*ast.ParenExpr](cur) { + cur, _ = cur.FirstChild() + } + return cur +} + +// UnparenEnclosingCursor returns the first element of +// the [Cursor.Enclosing] sequence that is not itself enclosed +// in parens. It is often prudent to call this before switching on +// cur.ParentEdge(). +// +// See also [UnparenCursor]. +func UnparenEnclosingCursor(cur inspector.Cursor) inspector.Cursor { + for cur.ParentEdgeKind() == edge.ParenExpr_X { + cur = cur.Parent() + } + return cur +} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/astutil/purge.go b/src/cmd/vendor/golang.org/x/tools/internal/astutil/purge.go index 81ac46a0c4eb78..d0a39415dcbb40 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/astutil/purge.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/astutil/purge.go @@ -12,9 +12,14 @@ import ( ) // PurgeFuncBodies returns a copy of src in which the contents of each -// outermost {...} region except struct and interface types have been -// deleted. This reduces the amount of work required to parse the -// top-level declarations. +// outermost {...} region have been deleted, except for struct and +// interface type bodies and the bodies of length-elided array +// literals ([...]T), whose element count is part of the type. It +// includes function bodies, function-literal bodies, and the bodies +// of slice, map, and explicitly-sized array composite literals (whose +// contents don't affect the type of the enclosing declaration). This +// reduces the amount of work required to parse the top-level +// declarations. // // PurgeFuncBodies does not preserve newlines or position information. // Also, if the input is invalid, parsing the output of @@ -22,11 +27,12 @@ import ( // on parser error recovery. func PurgeFuncBodies(src []byte) []byte { // Destroy the content of any {...}-bracketed regions that are - // not immediately preceded by a "struct" or "interface" - // token. That includes function bodies, composite literals, - // switch/select bodies, and all blocks of statements. - // This will lead to non-void functions that don't have return - // statements, which of course is a type error, but that's ok. + // not immediately preceded by a "struct" or "interface" token, + // and that are not the body of a length-elided array literal. + // That includes function bodies, switch/select bodies, and most + // composite literals; this will lead to non-void functions that + // don't have return statements, which of course is a type error, + // but that's ok. var out bytes.Buffer file := token.NewFileSet().AddFile("", -1, len(src)) @@ -34,7 +40,8 @@ func PurgeFuncBodies(src []byte) []byte { sc.Init(file, src, nil, 0) var prev token.Token var cursor int // last consumed src offset - var braces []token.Pos // stack of unclosed braces or -1 for struct/interface type + var braces []token.Pos // stack of unclosed braces, or -1 for a region we preserve + var ellipsis bool // saw "[...]" not yet consumed by a literal-body "{" for { pos, tok, _ := sc.Scan() if tok == token.EOF { @@ -44,9 +51,23 @@ func PurgeFuncBodies(src []byte) []byte { case token.COMMENT: // TODO(adonovan): opt: skip, to save an estimated 20% of time. + case token.SEMICOLON: + ellipsis = false + + case token.RBRACK: + // "...]" occurs only in the array-type prefix of a + // composite literal; variadic "..." is followed by + // a type or ")", never "]". + if prev == token.ELLIPSIS { + ellipsis = true + } + case token.LBRACE: if prev == token.STRUCT || prev == token.INTERFACE { - pos = -1 + pos = -1 // type body: preserve (don't consume ellipsis) + } else if ellipsis { + pos = -1 // [...]T literal body: preserve + ellipsis = false } braces = append(braces, pos) @@ -55,7 +76,7 @@ func PurgeFuncBodies(src []byte) []byte { top := braces[last] braces = braces[:last] if top < 0 { - // struct/interface type: leave alone + // preserve } else if len(braces) == 0 { // toplevel only // Delete {...} body. start := file.Offset(top) diff --git a/src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go b/src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go index b855a5600855f9..58fc8bb42718a7 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go @@ -254,3 +254,8 @@ func needsParens(parentNode ast.Node, old, new ast.Expr) bool { } return false } + +func is[T any](n any) bool { + _, ok := n.(T) + return ok +} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/goplsexport/export.go b/src/cmd/vendor/golang.org/x/tools/internal/goplsexport/export.go index 57c15c414efd2a..414c9cb03ef22e 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/goplsexport/export.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/goplsexport/export.go @@ -9,11 +9,12 @@ package goplsexport import "golang.org/x/tools/go/analysis" var ( - ErrorsAsTypeModernizer *analysis.Analyzer // = modernize.errorsastypeAnalyzer + ErrorsAsTypeModernizer *analysis.Analyzer // = modernize.errorsastypeAnalyzer SlicesBackwardModernizer *analysis.Analyzer // = modernize.slicesbackwardAnalyzer - StdIteratorsModernizer *analysis.Analyzer // = modernize.stditeratorsAnalyzer - PlusBuildModernizer *analysis.Analyzer // = modernize.plusbuildAnalyzer - StringsCutModernizer *analysis.Analyzer // = modernize.stringscutAnalyzer - UnsafeFuncsModernizer *analysis.Analyzer // = modernize.unsafeFuncsAnalyzer - AtomicTypesModernizer *analysis.Analyzer // = modernize.atomicTypesAnalyzer + StdIteratorsModernizer *analysis.Analyzer // = modernize.stditeratorsAnalyzer + PlusBuildModernizer *analysis.Analyzer // = modernize.plusbuildAnalyzer + StringsCutModernizer *analysis.Analyzer // = modernize.stringscutAnalyzer + UnsafeFuncsModernizer *analysis.Analyzer // = modernize.unsafeFuncsAnalyzer + AtomicTypesModernizer *analysis.Analyzer // = modernize.atomicTypesAnalyzer + EmbedLitModernizer *analysis.Analyzer // = modernize.embedLitAnalyzer ) diff --git a/src/cmd/vendor/golang.org/x/tools/internal/moreiters/iters.go b/src/cmd/vendor/golang.org/x/tools/internal/moreiters/iters.go index 9e4aaf94855ade..3dc81c4dbfdf77 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/moreiters/iters.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/moreiters/iters.go @@ -53,3 +53,11 @@ func Len[T any](seq iter.Seq[T]) (n int) { } return } + +// Empty reports whether the sequence contains no elements. +func Empty[T any](seq iter.Seq[T]) bool { + for range seq { + return false + } + return true +} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/refactor/delete.go b/src/cmd/vendor/golang.org/x/tools/internal/refactor/delete.go index 25547f04f0991e..b655b8a2ee3760 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/refactor/delete.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/refactor/delete.go @@ -439,7 +439,7 @@ Big: inStmtList = true case *ast.ForStmt: use(parent.For, parent.Body.Lbrace) - // special handling, as init;cond;post BlockStmt is not a statment list + // special handling, as init;cond;post BlockStmt is not a statement list if parent.Init != nil && parent.Cond != nil && stmt == parent.Init && lineOf(parent.Cond.Pos()) == lineOf(stmt.End()) { rightStmt = parent.Cond.Pos() } else if parent.Post != nil && parent.Cond != nil && stmt == parent.Post && lineOf(parent.Cond.End()) == lineOf(stmt.Pos()) { diff --git a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/callee.go b/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/callee.go index 815c8c0bba0069..68e2844794b437 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/callee.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/callee.go @@ -530,9 +530,7 @@ func analyzeTypeParams(_ logger, fset *token.FileSet, info *types.Info, decl *as // We don't care about most of the properties that matter for parameter references: // a type is immutable, cannot have its address taken, and does not undergo conversions. // TODO(jba): can we nevertheless combine this with the traversal in analyzeParams? - var stack []ast.Node - stack = append(stack, decl.Type) // for scope of function itself - ast.PreorderStack(decl.Body, stack, func(n ast.Node, stack []ast.Node) bool { + visit := func(n ast.Node, stack []ast.Node) bool { if id, ok := n.(*ast.Ident); ok { if v, ok := info.Uses[id].(*types.TypeName); ok { if pinfo, ok := paramInfos[v]; ok { @@ -543,7 +541,16 @@ func analyzeTypeParams(_ logger, fset *token.FileSet, info *types.Info, decl *as } } return true - }) + } + var stack []ast.Node + stack = append(stack, decl.Type) // for scope of function itself + if decl.Type.Params != nil { + ast.PreorderStack(decl.Type.Params, stack, visit) + } + if decl.Type.Results != nil { + ast.PreorderStack(decl.Type.Results, stack, visit) + } + ast.PreorderStack(decl.Body, stack, visit) return params } diff --git a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/inline.go b/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/inline.go index cbcf7b3ff2934b..cf4c587176e5cd 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/inline.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/refactor/inline/inline.go @@ -2050,7 +2050,7 @@ func resolveEffects(logf logger, args []*argument, effects []int, sg substGraph) } } if !sg.has(argi) { - for j := 0; j < i; j++ { + for j := range i { argj := args[j] if argj.pure { continue diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/typeindex/typeindex.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/typeindex/typeindex.go index 222ada55a2550a..e9ea0c4cdc9256 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/typeindex/typeindex.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/typeindex/typeindex.go @@ -17,6 +17,7 @@ import ( "golang.org/x/tools/go/ast/edge" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "golang.org/x/tools/internal/astutil" "golang.org/x/tools/internal/typesinternal" ) @@ -217,10 +218,9 @@ func (ix *Index) Selection(path, typename, name string) types.Object { func (ix *Index) Calls(callee types.Object) iter.Seq[inspector.Cursor] { return func(yield func(inspector.Cursor) bool) { for cur := range ix.Uses(callee) { - ek := cur.ParentEdgeKind() - // The call may be of the form f() or x.f(), // optionally with parens; ascend from f to call. + // See logic in [typesinternal.UsedIdent], to which this is dual. // // It is tempting but wrong to use the first // CallExpr ancestor: we have to make sure the @@ -229,25 +229,20 @@ func (ix *Index) Calls(callee types.Object) iter.Seq[inspector.Cursor] { // Avoiding Enclosing is also significantly faster. // inverse unparen: f -> (f) - for ek == edge.ParenExpr_X { - cur = cur.Parent() - ek = cur.ParentEdgeKind() - } + cur = astutil.UnparenEnclosingCursor(cur) - // ascend selector: f -> x.f - if ek == edge.SelectorExpr_Sel { - cur = cur.Parent() - ek = cur.ParentEdgeKind() + // ascend selector (or qualified identifier): f -> x.f + if cur.ParentEdgeKind() == edge.SelectorExpr_Sel { + cur = astutil.UnparenEnclosingCursor(cur.Parent()) } - // inverse unparen again - for ek == edge.ParenExpr_X { - cur = cur.Parent() - ek = cur.ParentEdgeKind() + // ascend typeparams: f -> f[T]; f -> f[T1, T2] + if ek := cur.ParentEdgeKind(); ek == edge.IndexExpr_X || ek == edge.IndexListExpr_X { + cur = astutil.UnparenEnclosingCursor(cur.Parent()) } // ascend from f or x.f to call - if ek == edge.CallExpr_Fun { + if cur.ParentEdgeKind() == edge.CallExpr_Fun { curCall := cur.Parent() call := curCall.Node().(*ast.CallExpr) if typeutil.Callee(ix.info, call) == callee { diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 421f557745ff4f..b8a8f795ec2475 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -48,7 +48,7 @@ golang.org/x/sync/semaphore golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa +# golang.org/x/telemetry v0.0.0-20260508192327-42602be52be6 ## explicit; go 1.25.0 golang.org/x/telemetry golang.org/x/telemetry/counter @@ -73,7 +73,7 @@ golang.org/x/text/internal/tag golang.org/x/text/language golang.org/x/text/transform golang.org/x/text/unicode/norm -# golang.org/x/tools v0.44.1-0.20260414062052-55fb96ff894f +# golang.org/x/tools v0.45.1-0.20260520205638-b38156a7a9f5 ## explicit; go 1.25.0 golang.org/x/tools/cmd/bisect golang.org/x/tools/cover From 91a81e5ae1998cb134953140be0dd565973716b4 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Wed, 20 May 2026 16:28:45 -0400 Subject: [PATCH 14/18] go/types,cmd/compile/internal/types2: add String methods This change adds String methods to the types TypeList, TypeParamList and Instance. The format is unspecified and is provided merely as a debugging aid. Fixes #79287 Change-Id: Ic283ea57bac6465b47b8b81b1fa4590641b639cb Reviewed-on: https://go-review.googlesource.com/c/go/+/780581 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Auto-Submit: Robert Griesemer Auto-Submit: Alan Donovan Reviewed-by: Robert Griesemer --- api/next/79287.txt | 3 +++ doc/next/6-stdlib/99-minor/go/types/79287.md | 1 + src/cmd/compile/internal/types2/api.go | 4 +++ src/cmd/compile/internal/types2/typelists.go | 28 ++++++++++++++++++++ src/go/types/api.go | 4 +++ src/go/types/typelists.go | 28 ++++++++++++++++++++ 6 files changed, 68 insertions(+) create mode 100644 api/next/79287.txt create mode 100644 doc/next/6-stdlib/99-minor/go/types/79287.md diff --git a/api/next/79287.txt b/api/next/79287.txt new file mode 100644 index 00000000000000..3e334d3159cb6d --- /dev/null +++ b/api/next/79287.txt @@ -0,0 +1,3 @@ +pkg go/types, method (*TypeList) String() string #79287 +pkg go/types, method (*TypeParamList) String() string #79287 +pkg go/types, method (Instance) String() string #79287 diff --git a/doc/next/6-stdlib/99-minor/go/types/79287.md b/doc/next/6-stdlib/99-minor/go/types/79287.md new file mode 100644 index 00000000000000..8ec275e7f67751 --- /dev/null +++ b/doc/next/6-stdlib/99-minor/go/types/79287.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/cmd/compile/internal/types2/api.go b/src/cmd/compile/internal/types2/api.go index 901984814ec933..e6caf676b3a4c6 100644 --- a/src/cmd/compile/internal/types2/api.go +++ b/src/cmd/compile/internal/types2/api.go @@ -437,6 +437,10 @@ type Instance struct { Type Type } +func (inst Instance) String() string { + return fmt.Sprintf("%s%s", inst.TypeArgs, inst.Type) +} + // An Initializer describes a package-level variable, or a list of variables in case // of a multi-valued initialization expression, and the corresponding initialization // expression. diff --git a/src/cmd/compile/internal/types2/typelists.go b/src/cmd/compile/internal/types2/typelists.go index a2aba4a9a553c9..b0633022ae2015 100644 --- a/src/cmd/compile/internal/types2/typelists.go +++ b/src/cmd/compile/internal/types2/typelists.go @@ -4,6 +4,8 @@ package types2 +import "bytes" + // TypeParamList holds a list of type parameters. type TypeParamList struct{ tparams []*TypeParam } @@ -24,6 +26,19 @@ func (l *TypeParamList) list() []*TypeParam { return l.tparams } +func (l *TypeParamList) String() string { + var buf bytes.Buffer + buf.WriteByte('[') + for i, tparam := range l.tparams { + if i > 0 { + buf.WriteString(", ") + } + WriteType(&buf, tparam, nil) + } + buf.WriteByte(']') + return buf.String() +} + // TypeList holds a list of types. type TypeList struct{ types []Type } @@ -52,6 +67,19 @@ func (l *TypeList) list() []Type { return l.types } +func (l *TypeList) String() string { + var buf bytes.Buffer + buf.WriteByte('[') + for i, t := range l.types { + if i > 0 { + buf.WriteString(", ") + } + WriteType(&buf, t, nil) + } + buf.WriteByte(']') + return buf.String() +} + // ---------------------------------------------------------------------------- // Implementation diff --git a/src/go/types/api.go b/src/go/types/api.go index cb6972992e6b56..3dbc35edb51f27 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -445,6 +445,10 @@ type Instance struct { Type Type } +func (inst Instance) String() string { + return fmt.Sprintf("%s%s", inst.TypeArgs, inst.Type) +} + // An Initializer describes a package-level variable, or a list of variables in case // of a multi-valued initialization expression, and the corresponding initialization // expression. diff --git a/src/go/types/typelists.go b/src/go/types/typelists.go index a857ea02a981bf..8d86f518b29d87 100644 --- a/src/go/types/typelists.go +++ b/src/go/types/typelists.go @@ -7,6 +7,8 @@ package types +import "bytes" + // TypeParamList holds a list of type parameters. type TypeParamList struct{ tparams []*TypeParam } @@ -27,6 +29,19 @@ func (l *TypeParamList) list() []*TypeParam { return l.tparams } +func (l *TypeParamList) String() string { + var buf bytes.Buffer + buf.WriteByte('[') + for i, tparam := range l.tparams { + if i > 0 { + buf.WriteString(", ") + } + WriteType(&buf, tparam, nil) + } + buf.WriteByte(']') + return buf.String() +} + // TypeList holds a list of types. type TypeList struct{ types []Type } @@ -55,6 +70,19 @@ func (l *TypeList) list() []Type { return l.types } +func (l *TypeList) String() string { + var buf bytes.Buffer + buf.WriteByte('[') + for i, t := range l.types { + if i > 0 { + buf.WriteString(", ") + } + WriteType(&buf, t, nil) + } + buf.WriteByte(']') + return buf.String() +} + // ---------------------------------------------------------------------------- // Implementation From be35de22f18a3c16e24a20490ec1fc316ea12b04 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 5 May 2025 12:09:13 +0200 Subject: [PATCH 15/18] crypto/internal/fips140/nistec: replace P-256 scalar assembly with fiat Change-Id: I6a6a4656c554e26151dc73287b68d6665a824dc3 Reviewed-on: https://go-review.googlesource.com/c/go/+/669895 Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Neal Patel Reviewed-by: Neal Patel Reviewed-by: Roland Shoemaker --- .../compile/internal/ssa/stmtlines_test.go | 3 +- src/crypto/internal/fips140/bigmod/nat.go | 8 + src/crypto/internal/fips140/ecdsa/ecdsa.go | 16 +- .../internal/fips140/nistec/_asm/go.mod | 8 +- .../internal/fips140/nistec/_asm/go.sum | 6 + .../internal/fips140/nistec/_asm/p256_asm.go | 614 +------- src/crypto/internal/fips140/nistec/p256.go | 4 +- .../internal/fips140/nistec/p256_asm.go | 13 +- .../internal/fips140/nistec/p256_asm_amd64.s | 503 ------ .../internal/fips140/nistec/p256_asm_arm64.s | 433 +----- .../internal/fips140/nistec/p256_ordinv.go | 1355 ++++++++++++++++- .../fips140/nistec/p256_ordinv_noasm.go | 13 - .../nistec_ordinv_fips140v1.0_test.go | 30 + .../nistec_ordinv_fips140v1.28_test.go | 16 + .../fips140test/nistec_ordinv_test.go | 83 +- 15 files changed, 1436 insertions(+), 1669 deletions(-) delete mode 100644 src/crypto/internal/fips140/nistec/p256_ordinv_noasm.go create mode 100644 src/crypto/internal/fips140test/nistec_ordinv_fips140v1.0_test.go create mode 100644 src/crypto/internal/fips140test/nistec_ordinv_fips140v1.28_test.go diff --git a/src/cmd/compile/internal/ssa/stmtlines_test.go b/src/cmd/compile/internal/ssa/stmtlines_test.go index 02bdfca92504e0..acab3c9cb114d0 100644 --- a/src/cmd/compile/internal/ssa/stmtlines_test.go +++ b/src/cmd/compile/internal/ssa/stmtlines_test.go @@ -103,7 +103,8 @@ func TestStmtLines(t *testing.T) { if pkgname == "runtime" { continue } - if pkgname == "crypto/internal/fips140/nistec/fiat" { + if pkgname == "crypto/internal/fips140/nistec/fiat" || + pkgname == "crypto/internal/fips140/nistec" { continue // golang.org/issue/49372 } if e.Val(dwarf.AttrStmtList) == nil { diff --git a/src/crypto/internal/fips140/bigmod/nat.go b/src/crypto/internal/fips140/bigmod/nat.go index 53f77502afa017..0233f12639c00c 100644 --- a/src/crypto/internal/fips140/bigmod/nat.go +++ b/src/crypto/internal/fips140/bigmod/nat.go @@ -142,6 +142,14 @@ func (x *Nat) Bits() []uint { return x.limbs } +// SetBits assigns x = y, where y is a slice of little-endian uint. x is resized +// to the length of y. +func (x *Nat) SetBits(y []uint) *Nat { + x.reset(len(y)) + copy(x.limbs, y) + return x +} + // Bytes returns x as a zero-extended big-endian byte slice. The size of the // slice will match the size of m. // diff --git a/src/crypto/internal/fips140/ecdsa/ecdsa.go b/src/crypto/internal/fips140/ecdsa/ecdsa.go index 5759c34c6a12bb..30f004ff6b884a 100644 --- a/src/crypto/internal/fips140/ecdsa/ecdsa.go +++ b/src/crypto/internal/fips140/ecdsa/ecdsa.go @@ -13,6 +13,7 @@ import ( "errors" "hash" "io" + "math/bits" "sync" ) @@ -54,7 +55,7 @@ const ( type Curve[P Point[P]] struct { curve curveID newPoint func() P - ordInverse func([]byte) ([]byte, error) + ordInverse func(*[4]uint64) N *bigmod.Modulus nMinus2 []byte } @@ -387,14 +388,11 @@ func signGeneric[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash // inverse sets kInv to the inverse of k modulo the order of the curve. func inverse[P Point[P]](c *Curve[P], kInv, k *bigmod.Nat) { - if c.ordInverse != nil { - kBytes, err := c.ordInverse(k.Bytes(c.N)) - // Some platforms don't implement ordInverse, and always return an error. - if err == nil { - _, err := kInv.SetBytes(kBytes, c.N) - if err != nil { - panic("ecdsa: internal error: ordInverse produced an invalid value") - } + if c.ordInverse != nil && bits.UintSize == 64 { + if kb := k.Bits(); len(kb) == 4 { + k64 := [4]uint64{uint64(kb[0]), uint64(kb[1]), uint64(kb[2]), uint64(kb[3])} + c.ordInverse(&k64) + kInv.SetBits([]uint{uint(k64[0]), uint(k64[1]), uint(k64[2]), uint(k64[3])}) return } } diff --git a/src/crypto/internal/fips140/nistec/_asm/go.mod b/src/crypto/internal/fips140/nistec/_asm/go.mod index 09daa240276170..3941288f122404 100644 --- a/src/crypto/internal/fips140/nistec/_asm/go.mod +++ b/src/crypto/internal/fips140/nistec/_asm/go.mod @@ -1,11 +1,11 @@ module crypto/internal/fips140/nistec/_asm -go 1.24 +go 1.26.0 require github.com/mmcloughlin/avo v0.6.0 require ( - golang.org/x/mod v0.20.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/tools v0.42.0 // indirect ) diff --git a/src/crypto/internal/fips140/nistec/_asm/go.sum b/src/crypto/internal/fips140/nistec/_asm/go.sum index 76af484b2eba35..fbfa9879c3a846 100644 --- a/src/crypto/internal/fips140/nistec/_asm/go.sum +++ b/src/crypto/internal/fips140/nistec/_asm/go.sum @@ -2,7 +2,13 @@ github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8= golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= diff --git a/src/crypto/internal/fips140/nistec/_asm/p256_asm.go b/src/crypto/internal/fips140/nistec/_asm/p256_asm.go index c32e7edf74a7a3..1d2e5270cb46f6 100644 --- a/src/crypto/internal/fips140/nistec/_asm/p256_asm.go +++ b/src/crypto/internal/fips140/nistec/_asm/p256_asm.go @@ -52,8 +52,6 @@ func main() { p256FromMont() p256Select() p256SelectAffine() - p256OrdMul() - p256OrdSqr() p256SubInternal() p256MulInternal() p256SqrInternal() @@ -832,583 +830,6 @@ func p256SelectAffine() { RET() } -// Implements: -// -// func p256OrdMul(res, in1, in2 *p256OrdElement) -func p256OrdMul() { - Implement("p256OrdMul") - Attributes(NOSPLIT) - - Load(Param("res"), res_ptr) - Load(Param("in1"), x_ptr) - Load(Param("in2"), y_ptr) - - Comment("x * y[0]") - MOVQ(Mem{Base: y_ptr}.Offset(8*0), t0_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*0), RAX) - MULQ(t0_v1) - MOVQ(RAX, acc0_v1) - MOVQ(RDX, acc1_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*1), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc1_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, acc2_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*2), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc2_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, acc3_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*3), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc3_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, acc4_v1) - XORQ(acc5_v1, acc5_v1) - - Comment("First reduction step") - MOVQ(acc0_v1, RAX) - p256ordK0 := p256ordK0_DATA() - MULQ(p256ordK0) - MOVQ(RAX, t0_v1) - - p256ord := p256ord_DATA() - MOVQ(p256ord.Offset(0x00), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc0_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x08), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc1_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc1_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x10), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc2_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc2_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x18), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc3_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc3_v1) - ADCQ(RDX, acc4_v1) - ADCQ(Imm(0), acc5_v1) - - Comment("x * y[1]") - MOVQ(Mem{Base: y_ptr}.Offset(8*1), t0_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*0), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc1_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*1), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc2_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc2_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*2), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc3_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc3_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*3), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc4_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc4_v1) - ADCQ(RDX, acc5_v1) - ADCQ(Imm(0), acc0_v1) - - Comment("Second reduction step") - MOVQ(acc1_v1, RAX) - MULQ(p256ordK0) - MOVQ(RAX, t0_v1) - - MOVQ(p256ord.Offset(0x00), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc1_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x08), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc2_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc2_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x10), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc3_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc3_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x18), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc4_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc4_v1) - ADCQ(RDX, acc5_v1) - ADCQ(Imm(0), acc0_v1) - - Comment("x * y[2]") - MOVQ(Mem{Base: y_ptr}.Offset(8*2), t0_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*0), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc2_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*1), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc3_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc3_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*2), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc4_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc4_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*3), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc5_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc5_v1) - ADCQ(RDX, acc0_v1) - ADCQ(Imm(0), acc1_v1) - - Comment("Third reduction step") - MOVQ(acc2_v1, RAX) - MULQ(p256ordK0) - MOVQ(RAX, t0_v1) - - MOVQ(p256ord.Offset(0x00), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc2_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x08), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc3_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc3_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x10), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc4_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc4_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x18), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc5_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc5_v1) - ADCQ(RDX, acc0_v1) - ADCQ(Imm(0), acc1_v1) - - Comment("x * y[3]") - MOVQ(Mem{Base: y_ptr}.Offset(8*3), t0_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*0), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc3_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*1), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc4_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc4_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*2), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc5_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc5_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*3), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc0_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc0_v1) - ADCQ(RDX, acc1_v1) - ADCQ(Imm(0), acc2_v1) - - Comment("Last reduction step") - MOVQ(acc3_v1, RAX) - MULQ(p256ordK0) - MOVQ(RAX, t0_v1) - - MOVQ(p256ord.Offset(0x00), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc3_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x08), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc4_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc4_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x10), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc5_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc5_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x18), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc0_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc0_v1) - ADCQ(RDX, acc1_v1) - ADCQ(Imm(0), acc2_v1) - - Comment("Copy result [255:0]") - MOVQ(acc4_v1, x_ptr) - MOVQ(acc5_v1, acc3_v1) - MOVQ(acc0_v1, t0_v1) - MOVQ(acc1_v1, t1_v1) - - Comment("Subtract p256") - SUBQ(p256ord.Offset(0x00), acc4_v1) - SBBQ(p256ord.Offset(0x08), acc5_v1) - SBBQ(p256ord.Offset(0x10), acc0_v1) - SBBQ(p256ord.Offset(0x18), acc1_v1) - SBBQ(Imm(0), acc2_v1) - - CMOVQCS(x_ptr, acc4_v1) - CMOVQCS(acc3_v1, acc5_v1) - CMOVQCS(t0_v1, acc0_v1) - CMOVQCS(t1_v1, acc1_v1) - - MOVQ(acc4_v1, Mem{Base: res_ptr}.Offset(8*0)) - MOVQ(acc5_v1, Mem{Base: res_ptr}.Offset(8*1)) - MOVQ(acc0_v1, Mem{Base: res_ptr}.Offset(8*2)) - MOVQ(acc1_v1, Mem{Base: res_ptr}.Offset(8*3)) - - RET() -} - -// Implements: -// -// func p256OrdSqr(res, in *p256OrdElement, n int) -func p256OrdSqr() { - Implement("p256OrdSqr") - Attributes(NOSPLIT) - - Load(Param("res"), res_ptr) - Load(Param("in"), x_ptr) - Load(Param("n"), RBX) - - Label("ordSqrLoop") - - Comment("y[1:] * y[0]") - MOVQ(Mem{Base: x_ptr}.Offset(8*0), t0_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*1), RAX) - MULQ(t0_v1) - MOVQ(RAX, acc1_v1) - MOVQ(RDX, acc2_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*2), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc2_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, acc3_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*3), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc3_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, acc4_v1) - - Comment("y[2:] * y[1]") - MOVQ(Mem{Base: x_ptr}.Offset(8*1), t0_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*2), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc3_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*3), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc4_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc4_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, acc5_v1) - - Comment("y[3] * y[2]") - MOVQ(Mem{Base: x_ptr}.Offset(8*2), t0_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*3), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc5_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, y_ptr) - XORQ(t1_v1, t1_v1) - - Comment("*2") - ADDQ(acc1_v1, acc1_v1) - ADCQ(acc2_v1, acc2_v1) - ADCQ(acc3_v1, acc3_v1) - ADCQ(acc4_v1, acc4_v1) - ADCQ(acc5_v1, acc5_v1) - ADCQ(y_ptr, y_ptr) - ADCQ(Imm(0), t1_v1) - - Comment("Missing products") - MOVQ(Mem{Base: x_ptr}.Offset(8*0), RAX) - MULQ(RAX) - MOVQ(RAX, acc0_v1) - MOVQ(RDX, t0_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*1), RAX) - MULQ(RAX) - ADDQ(t0_v1, acc1_v1) - ADCQ(RAX, acc2_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t0_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*2), RAX) - MULQ(RAX) - ADDQ(t0_v1, acc3_v1) - ADCQ(RAX, acc4_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t0_v1) - - MOVQ(Mem{Base: x_ptr}.Offset(8*3), RAX) - MULQ(RAX) - ADDQ(t0_v1, acc5_v1) - ADCQ(RAX, y_ptr) - ADCQ(RDX, t1_v1) - MOVQ(t1_v1, x_ptr) - - Comment("First reduction step") - MOVQ(acc0_v1, RAX) - p256ordK0 := p256ordK0_DATA() - MULQ(p256ordK0) - MOVQ(RAX, t0_v1) - - p256ord := p256ord_DATA() - MOVQ(p256ord.Offset(0x00), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc0_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x08), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc1_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc1_v1) - - MOVQ(t0_v1, t1_v1) - ADCQ(RDX, acc2_v1) - ADCQ(Imm(0), t1_v1) - SUBQ(t0_v1, acc2_v1) - SBBQ(Imm(0), t1_v1) - - MOVQ(t0_v1, RAX) - MOVQ(t0_v1, RDX) - MOVQ(t0_v1, acc0_v1) - SHLQ(Imm(32), RAX) - SHRQ(Imm(32), RDX) - - ADDQ(t1_v1, acc3_v1) - ADCQ(Imm(0), acc0_v1) - SUBQ(RAX, acc3_v1) - SBBQ(RDX, acc0_v1) - - Comment("Second reduction step") - MOVQ(acc1_v1, RAX) - MULQ(p256ordK0) - MOVQ(RAX, t0_v1) - - MOVQ(p256ord.Offset(0x00), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc1_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x08), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc2_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc2_v1) - - MOVQ(t0_v1, t1_v1) - ADCQ(RDX, acc3_v1) - ADCQ(Imm(0), t1_v1) - SUBQ(t0_v1, acc3_v1) - SBBQ(Imm(0), t1_v1) - - MOVQ(t0_v1, RAX) - MOVQ(t0_v1, RDX) - MOVQ(t0_v1, acc1_v1) - SHLQ(Imm(32), RAX) - SHRQ(Imm(32), RDX) - - ADDQ(t1_v1, acc0_v1) - ADCQ(Imm(0), acc1_v1) - SUBQ(RAX, acc0_v1) - SBBQ(RDX, acc1_v1) - - Comment("Third reduction step") - MOVQ(acc2_v1, RAX) - MULQ(p256ordK0) - MOVQ(RAX, t0_v1) - - MOVQ(p256ord.Offset(0x00), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc2_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x08), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc3_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc3_v1) - - MOVQ(t0_v1, t1_v1) - ADCQ(RDX, acc0_v1) - ADCQ(Imm(0), t1_v1) - SUBQ(t0_v1, acc0_v1) - SBBQ(Imm(0), t1_v1) - - MOVQ(t0_v1, RAX) - MOVQ(t0_v1, RDX) - MOVQ(t0_v1, acc2_v1) - SHLQ(Imm(32), RAX) - SHRQ(Imm(32), RDX) - - ADDQ(t1_v1, acc1_v1) - ADCQ(Imm(0), acc2_v1) - SUBQ(RAX, acc1_v1) - SBBQ(RDX, acc2_v1) - - Comment("Last reduction step") - MOVQ(acc3_v1, RAX) - MULQ(p256ordK0) - MOVQ(RAX, t0_v1) - - MOVQ(p256ord.Offset(0x00), RAX) - MULQ(t0_v1) - ADDQ(RAX, acc3_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(p256ord.Offset(0x08), RAX) - MULQ(t0_v1) - ADDQ(t1_v1, acc0_v1) - ADCQ(Imm(0), RDX) - ADDQ(RAX, acc0_v1) - ADCQ(Imm(0), RDX) - MOVQ(RDX, t1_v1) - - MOVQ(t0_v1, t1_v1) - ADCQ(RDX, acc1_v1) - ADCQ(Imm(0), t1_v1) - SUBQ(t0_v1, acc1_v1) - SBBQ(Imm(0), t1_v1) - - MOVQ(t0_v1, RAX) - MOVQ(t0_v1, RDX) - MOVQ(t0_v1, acc3_v1) - SHLQ(Imm(32), RAX) - SHRQ(Imm(32), RDX) - - ADDQ(t1_v1, acc2_v1) - ADCQ(Imm(0), acc3_v1) - SUBQ(RAX, acc2_v1) - SBBQ(RDX, acc3_v1) - XORQ(t0_v1, t0_v1) - - Comment("Add bits [511:256] of the sqr result") - ADCQ(acc4_v1, acc0_v1) - ADCQ(acc5_v1, acc1_v1) - ADCQ(y_ptr, acc2_v1) - ADCQ(x_ptr, acc3_v1) - ADCQ(Imm(0), t0_v1) - - MOVQ(acc0_v1, acc4_v1) - MOVQ(acc1_v1, acc5_v1) - MOVQ(acc2_v1, y_ptr) - MOVQ(acc3_v1, t1_v1) - - Comment("Subtract p256") - SUBQ(p256ord.Offset(0x00), acc0_v1) - SBBQ(p256ord.Offset(0x08), acc1_v1) - SBBQ(p256ord.Offset(0x10), acc2_v1) - SBBQ(p256ord.Offset(0x18), acc3_v1) - SBBQ(Imm(0), t0_v1) - - CMOVQCS(acc4_v1, acc0_v1) - CMOVQCS(acc5_v1, acc1_v1) - CMOVQCS(y_ptr, acc2_v1) - CMOVQCS(t1_v1, acc3_v1) - - MOVQ(acc0_v1, Mem{Base: res_ptr}.Offset(8*0)) - MOVQ(acc1_v1, Mem{Base: res_ptr}.Offset(8*1)) - MOVQ(acc2_v1, Mem{Base: res_ptr}.Offset(8*2)) - MOVQ(acc3_v1, Mem{Base: res_ptr}.Offset(8*3)) - MOVQ(res_ptr, x_ptr) - DECQ(RBX) - JNE(LabelRef("ordSqrLoop")) - - RET() -} - // These variables have been versioned as they get redfined in the reference implementation. // This is done to produce a minimal semantic diff. var ( @@ -2595,7 +2016,7 @@ func p256PointDoubleAsm() { // #----------------------------DATA SECTION-----------------------------------## // Pointers for memoizing Data section symbols -var p256const0_ptr, p256const1_ptr, p256ordK0_ptr, p256ord_ptr, p256one_ptr *Mem +var p256const0_ptr, p256const1_ptr, p256one_ptr *Mem func p256const0_DATA() Mem { if p256const0_ptr != nil { @@ -2619,39 +2040,6 @@ func p256const1_DATA() Mem { return p256const1 } -func p256ordK0_DATA() Mem { - if p256ordK0_ptr != nil { - return *p256ordK0_ptr - } - - p256ordK0 := GLOBL("p256ordK0", 8) - p256ordK0_ptr = &p256ordK0 - DATA(0, U64(0xccd1c8aaee00bc4f)) - return p256ordK0 -} - -var p256ordConstants = [4]uint64{ - 0xf3b9cac2fc632551, - 0xbce6faada7179e84, - 0xffffffffffffffff, - 0xffffffff00000000, -} - -func p256ord_DATA() Mem { - if p256ord_ptr != nil { - return *p256ord_ptr - } - - p256ord := GLOBL("p256ord", 8) - p256ord_ptr = &p256ord - - for i, k := range p256ordConstants { - DATA(i*8, U64(k)) - } - - return p256ord -} - var p256oneConstants = [4]uint64{ 0x0000000000000001, 0xffffffff00000000, diff --git a/src/crypto/internal/fips140/nistec/p256.go b/src/crypto/internal/fips140/nistec/p256.go index 650bde4e73e0a7..25ecdad2a0051f 100644 --- a/src/crypto/internal/fips140/nistec/p256.go +++ b/src/crypto/internal/fips140/nistec/p256.go @@ -392,8 +392,8 @@ func (q *P256Point) Select(p1, p2 *P256Point, cond int) *P256Point { return q } -// p256OrdElement is a P-256 scalar field element in [0, ord(G)-1] in the -// Montgomery domain (with R 2²⁵⁶) as four uint64 limbs in little-endian order. +// p256OrdElement is a P-256 scalar field element in [0, ord(G)-1] +// as four uint64 limbs in little-endian order. type p256OrdElement [4]uint64 // SetBytes sets s to the big-endian value of x, reducing it as necessary. diff --git a/src/crypto/internal/fips140/nistec/p256_asm.go b/src/crypto/internal/fips140/nistec/p256_asm.go index f00e70d99d1d8c..22fc8c06f789ad 100644 --- a/src/crypto/internal/fips140/nistec/p256_asm.go +++ b/src/crypto/internal/fips140/nistec/p256_asm.go @@ -76,9 +76,10 @@ const p256CompressedLength = 1 + p256ElementLength // the curve, it returns nil and an error, and the receiver is unchanged. // Otherwise, it returns p. func (p *P256Point) SetBytes(b []byte) (*P256Point, error) { - // p256Mul operates in the Montgomery domain with R = 2²⁵⁶ mod p. Thus rr - // here is R in the Montgomery domain, or R×R mod p. See comment in - // P256OrdInverse about how this is used. + // This implementation operates in the Montgomery domain with R = 2²⁵⁶ mod + // p. Elements in the Montgomery domain take the form a×R and p256Mul + // calculates (a × b × R⁻¹) mod p. rr is R in the domain, or R×R mod p, thus + // p256Mul(e, RR) gives e×R, i.e. converts e into the Montgomery domain. rr := p256Element{0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe, 0x00000004fffffffd} @@ -282,7 +283,7 @@ func p256Mul(res, in1, in2 *p256Element) //go:noescape func p256Sqr(res, in *p256Element, n int) -// Montgomery multiplication by R⁻¹, or 1 outside the domain. +// Montgomery multiplication by R⁻¹, or 1 outside the domain, as R⁻¹×R = 1. // Sets res = in * R⁻¹, bringing res out of the Montgomery domain. // //go:noescape @@ -365,8 +366,8 @@ func p256PointAddAsm(res, in1, in2 *P256Point) int //go:noescape func p256PointDoubleAsm(res, in *P256Point) -// p256OrdElement is a P-256 scalar field element in [0, ord(G)-1] in the -// Montgomery domain (with R 2²⁵⁶) as four uint64 limbs in little-endian order. +// p256OrdElement is a P-256 scalar field element in [0, ord(G)-1] +// as four uint64 limbs in little-endian order. type p256OrdElement [4]uint64 // p256OrdReduce ensures s is in the range [0, ord(G)-1]. diff --git a/src/crypto/internal/fips140/nistec/p256_asm_amd64.s b/src/crypto/internal/fips140/nistec/p256_asm_amd64.s index 64894891e98037..86053049c68bd6 100644 --- a/src/crypto/internal/fips140/nistec/p256_asm_amd64.s +++ b/src/crypto/internal/fips140/nistec/p256_asm_amd64.s @@ -640,509 +640,6 @@ loop_select_base: MOVOU X3, 48(DX) RET -// func p256OrdMul(res *p256OrdElement, in1 *p256OrdElement, in2 *p256OrdElement) -// Requires: CMOV -TEXT ·p256OrdMul(SB), NOSPLIT, $0-24 - MOVQ res+0(FP), DI - MOVQ in1+8(FP), SI - MOVQ in2+16(FP), CX - - // x * y[0] - MOVQ (CX), R14 - MOVQ (SI), AX - MULQ R14 - MOVQ AX, R8 - MOVQ DX, R9 - MOVQ 8(SI), AX - MULQ R14 - ADDQ AX, R9 - ADCQ $0x00, DX - MOVQ DX, R10 - MOVQ 16(SI), AX - MULQ R14 - ADDQ AX, R10 - ADCQ $0x00, DX - MOVQ DX, R11 - MOVQ 24(SI), AX - MULQ R14 - ADDQ AX, R11 - ADCQ $0x00, DX - MOVQ DX, R12 - XORQ R13, R13 - - // First reduction step - MOVQ R8, AX - MULQ p256ordK0<>+0(SB) - MOVQ AX, R14 - MOVQ p256ord<>+0(SB), AX - MULQ R14 - ADDQ AX, R8 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+8(SB), AX - MULQ R14 - ADDQ R15, R9 - ADCQ $0x00, DX - ADDQ AX, R9 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+16(SB), AX - MULQ R14 - ADDQ R15, R10 - ADCQ $0x00, DX - ADDQ AX, R10 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+24(SB), AX - MULQ R14 - ADDQ R15, R11 - ADCQ $0x00, DX - ADDQ AX, R11 - ADCQ DX, R12 - ADCQ $0x00, R13 - - // x * y[1] - MOVQ 8(CX), R14 - MOVQ (SI), AX - MULQ R14 - ADDQ AX, R9 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ 8(SI), AX - MULQ R14 - ADDQ R15, R10 - ADCQ $0x00, DX - ADDQ AX, R10 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ 16(SI), AX - MULQ R14 - ADDQ R15, R11 - ADCQ $0x00, DX - ADDQ AX, R11 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ 24(SI), AX - MULQ R14 - ADDQ R15, R12 - ADCQ $0x00, DX - ADDQ AX, R12 - ADCQ DX, R13 - ADCQ $0x00, R8 - - // Second reduction step - MOVQ R9, AX - MULQ p256ordK0<>+0(SB) - MOVQ AX, R14 - MOVQ p256ord<>+0(SB), AX - MULQ R14 - ADDQ AX, R9 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+8(SB), AX - MULQ R14 - ADDQ R15, R10 - ADCQ $0x00, DX - ADDQ AX, R10 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+16(SB), AX - MULQ R14 - ADDQ R15, R11 - ADCQ $0x00, DX - ADDQ AX, R11 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+24(SB), AX - MULQ R14 - ADDQ R15, R12 - ADCQ $0x00, DX - ADDQ AX, R12 - ADCQ DX, R13 - ADCQ $0x00, R8 - - // x * y[2] - MOVQ 16(CX), R14 - MOVQ (SI), AX - MULQ R14 - ADDQ AX, R10 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ 8(SI), AX - MULQ R14 - ADDQ R15, R11 - ADCQ $0x00, DX - ADDQ AX, R11 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ 16(SI), AX - MULQ R14 - ADDQ R15, R12 - ADCQ $0x00, DX - ADDQ AX, R12 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ 24(SI), AX - MULQ R14 - ADDQ R15, R13 - ADCQ $0x00, DX - ADDQ AX, R13 - ADCQ DX, R8 - ADCQ $0x00, R9 - - // Third reduction step - MOVQ R10, AX - MULQ p256ordK0<>+0(SB) - MOVQ AX, R14 - MOVQ p256ord<>+0(SB), AX - MULQ R14 - ADDQ AX, R10 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+8(SB), AX - MULQ R14 - ADDQ R15, R11 - ADCQ $0x00, DX - ADDQ AX, R11 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+16(SB), AX - MULQ R14 - ADDQ R15, R12 - ADCQ $0x00, DX - ADDQ AX, R12 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+24(SB), AX - MULQ R14 - ADDQ R15, R13 - ADCQ $0x00, DX - ADDQ AX, R13 - ADCQ DX, R8 - ADCQ $0x00, R9 - - // x * y[3] - MOVQ 24(CX), R14 - MOVQ (SI), AX - MULQ R14 - ADDQ AX, R11 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ 8(SI), AX - MULQ R14 - ADDQ R15, R12 - ADCQ $0x00, DX - ADDQ AX, R12 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ 16(SI), AX - MULQ R14 - ADDQ R15, R13 - ADCQ $0x00, DX - ADDQ AX, R13 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ 24(SI), AX - MULQ R14 - ADDQ R15, R8 - ADCQ $0x00, DX - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0x00, R10 - - // Last reduction step - MOVQ R11, AX - MULQ p256ordK0<>+0(SB) - MOVQ AX, R14 - MOVQ p256ord<>+0(SB), AX - MULQ R14 - ADDQ AX, R11 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+8(SB), AX - MULQ R14 - ADDQ R15, R12 - ADCQ $0x00, DX - ADDQ AX, R12 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+16(SB), AX - MULQ R14 - ADDQ R15, R13 - ADCQ $0x00, DX - ADDQ AX, R13 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+24(SB), AX - MULQ R14 - ADDQ R15, R8 - ADCQ $0x00, DX - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0x00, R10 - - // Copy result [255:0] - MOVQ R12, SI - MOVQ R13, R11 - MOVQ R8, R14 - MOVQ R9, R15 - - // Subtract p256 - SUBQ p256ord<>+0(SB), R12 - SBBQ p256ord<>+8(SB), R13 - SBBQ p256ord<>+16(SB), R8 - SBBQ p256ord<>+24(SB), R9 - SBBQ $0x00, R10 - CMOVQCS SI, R12 - CMOVQCS R11, R13 - CMOVQCS R14, R8 - CMOVQCS R15, R9 - MOVQ R12, (DI) - MOVQ R13, 8(DI) - MOVQ R8, 16(DI) - MOVQ R9, 24(DI) - RET - -DATA p256ordK0<>+0(SB)/8, $0xccd1c8aaee00bc4f -GLOBL p256ordK0<>(SB), RODATA, $8 - -DATA p256ord<>+0(SB)/8, $0xf3b9cac2fc632551 -DATA p256ord<>+8(SB)/8, $0xbce6faada7179e84 -DATA p256ord<>+16(SB)/8, $0xffffffffffffffff -DATA p256ord<>+24(SB)/8, $0xffffffff00000000 -GLOBL p256ord<>(SB), RODATA, $32 - -// func p256OrdSqr(res *p256OrdElement, in *p256OrdElement, n int) -// Requires: CMOV -TEXT ·p256OrdSqr(SB), NOSPLIT, $0-24 - MOVQ res+0(FP), DI - MOVQ in+8(FP), SI - MOVQ n+16(FP), BX - -ordSqrLoop: - // y[1:] * y[0] - MOVQ (SI), R14 - MOVQ 8(SI), AX - MULQ R14 - MOVQ AX, R9 - MOVQ DX, R10 - MOVQ 16(SI), AX - MULQ R14 - ADDQ AX, R10 - ADCQ $0x00, DX - MOVQ DX, R11 - MOVQ 24(SI), AX - MULQ R14 - ADDQ AX, R11 - ADCQ $0x00, DX - MOVQ DX, R12 - - // y[2:] * y[1] - MOVQ 8(SI), R14 - MOVQ 16(SI), AX - MULQ R14 - ADDQ AX, R11 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ 24(SI), AX - MULQ R14 - ADDQ R15, R12 - ADCQ $0x00, DX - ADDQ AX, R12 - ADCQ $0x00, DX - MOVQ DX, R13 - - // y[3] * y[2] - MOVQ 16(SI), R14 - MOVQ 24(SI), AX - MULQ R14 - ADDQ AX, R13 - ADCQ $0x00, DX - MOVQ DX, CX - XORQ R15, R15 - - // *2 - ADDQ R9, R9 - ADCQ R10, R10 - ADCQ R11, R11 - ADCQ R12, R12 - ADCQ R13, R13 - ADCQ CX, CX - ADCQ $0x00, R15 - - // Missing products - MOVQ (SI), AX - MULQ AX - MOVQ AX, R8 - MOVQ DX, R14 - MOVQ 8(SI), AX - MULQ AX - ADDQ R14, R9 - ADCQ AX, R10 - ADCQ $0x00, DX - MOVQ DX, R14 - MOVQ 16(SI), AX - MULQ AX - ADDQ R14, R11 - ADCQ AX, R12 - ADCQ $0x00, DX - MOVQ DX, R14 - MOVQ 24(SI), AX - MULQ AX - ADDQ R14, R13 - ADCQ AX, CX - ADCQ DX, R15 - MOVQ R15, SI - - // First reduction step - MOVQ R8, AX - MULQ p256ordK0<>+0(SB) - MOVQ AX, R14 - MOVQ p256ord<>+0(SB), AX - MULQ R14 - ADDQ AX, R8 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+8(SB), AX - MULQ R14 - ADDQ R15, R9 - ADCQ $0x00, DX - ADDQ AX, R9 - MOVQ R14, R15 - ADCQ DX, R10 - ADCQ $0x00, R15 - SUBQ R14, R10 - SBBQ $0x00, R15 - MOVQ R14, AX - MOVQ R14, DX - MOVQ R14, R8 - SHLQ $0x20, AX - SHRQ $0x20, DX - ADDQ R15, R11 - ADCQ $0x00, R8 - SUBQ AX, R11 - SBBQ DX, R8 - - // Second reduction step - MOVQ R9, AX - MULQ p256ordK0<>+0(SB) - MOVQ AX, R14 - MOVQ p256ord<>+0(SB), AX - MULQ R14 - ADDQ AX, R9 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+8(SB), AX - MULQ R14 - ADDQ R15, R10 - ADCQ $0x00, DX - ADDQ AX, R10 - MOVQ R14, R15 - ADCQ DX, R11 - ADCQ $0x00, R15 - SUBQ R14, R11 - SBBQ $0x00, R15 - MOVQ R14, AX - MOVQ R14, DX - MOVQ R14, R9 - SHLQ $0x20, AX - SHRQ $0x20, DX - ADDQ R15, R8 - ADCQ $0x00, R9 - SUBQ AX, R8 - SBBQ DX, R9 - - // Third reduction step - MOVQ R10, AX - MULQ p256ordK0<>+0(SB) - MOVQ AX, R14 - MOVQ p256ord<>+0(SB), AX - MULQ R14 - ADDQ AX, R10 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+8(SB), AX - MULQ R14 - ADDQ R15, R11 - ADCQ $0x00, DX - ADDQ AX, R11 - MOVQ R14, R15 - ADCQ DX, R8 - ADCQ $0x00, R15 - SUBQ R14, R8 - SBBQ $0x00, R15 - MOVQ R14, AX - MOVQ R14, DX - MOVQ R14, R10 - SHLQ $0x20, AX - SHRQ $0x20, DX - ADDQ R15, R9 - ADCQ $0x00, R10 - SUBQ AX, R9 - SBBQ DX, R10 - - // Last reduction step - MOVQ R11, AX - MULQ p256ordK0<>+0(SB) - MOVQ AX, R14 - MOVQ p256ord<>+0(SB), AX - MULQ R14 - ADDQ AX, R11 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ p256ord<>+8(SB), AX - MULQ R14 - ADDQ R15, R8 - ADCQ $0x00, DX - ADDQ AX, R8 - ADCQ $0x00, DX - MOVQ DX, R15 - MOVQ R14, R15 - ADCQ DX, R9 - ADCQ $0x00, R15 - SUBQ R14, R9 - SBBQ $0x00, R15 - MOVQ R14, AX - MOVQ R14, DX - MOVQ R14, R11 - SHLQ $0x20, AX - SHRQ $0x20, DX - ADDQ R15, R10 - ADCQ $0x00, R11 - SUBQ AX, R10 - SBBQ DX, R11 - XORQ R14, R14 - - // Add bits [511:256] of the sqr result - ADCQ R12, R8 - ADCQ R13, R9 - ADCQ CX, R10 - ADCQ SI, R11 - ADCQ $0x00, R14 - MOVQ R8, R12 - MOVQ R9, R13 - MOVQ R10, CX - MOVQ R11, R15 - - // Subtract p256 - SUBQ p256ord<>+0(SB), R8 - SBBQ p256ord<>+8(SB), R9 - SBBQ p256ord<>+16(SB), R10 - SBBQ p256ord<>+24(SB), R11 - SBBQ $0x00, R14 - CMOVQCS R12, R8 - CMOVQCS R13, R9 - CMOVQCS CX, R10 - CMOVQCS R15, R11 - MOVQ R8, (DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - MOVQ R11, 24(DI) - MOVQ DI, SI - DECQ BX - JNE ordSqrLoop - RET - // func p256SubInternal() // Requires: CMOV TEXT p256SubInternal(SB), NOSPLIT, $0 diff --git a/src/crypto/internal/fips140/nistec/p256_asm_arm64.s b/src/crypto/internal/fips140/nistec/p256_asm_arm64.s index 33da24508e2655..23bfe049f425a0 100644 --- a/src/crypto/internal/fips140/nistec/p256_asm_arm64.s +++ b/src/crypto/internal/fips140/nistec/p256_asm_arm64.s @@ -45,24 +45,14 @@ #define y2 R25 #define y3 R26 -#define const2 t2 -#define const3 t3 - DATA p256const0<>+0x00(SB)/8, $0x00000000ffffffff DATA p256const1<>+0x00(SB)/8, $0xffffffff00000001 -DATA p256ordK0<>+0x00(SB)/8, $0xccd1c8aaee00bc4f -DATA p256ord<>+0x00(SB)/8, $0xf3b9cac2fc632551 -DATA p256ord<>+0x08(SB)/8, $0xbce6faada7179e84 -DATA p256ord<>+0x10(SB)/8, $0xffffffffffffffff -DATA p256ord<>+0x18(SB)/8, $0xffffffff00000000 DATA p256one<>+0x00(SB)/8, $0x0000000000000001 DATA p256one<>+0x08(SB)/8, $0xffffffff00000000 DATA p256one<>+0x10(SB)/8, $0xffffffffffffffff DATA p256one<>+0x18(SB)/8, $0x00000000fffffffe GLOBL p256const0<>(SB), 8, $8 GLOBL p256const1<>(SB), 8, $8 -GLOBL p256ordK0<>(SB), 8, $8 -GLOBL p256ord<>(SB), 8, $32 GLOBL p256one<>(SB), 8, $32 /* ---------------------------------------*/ @@ -343,425 +333,10 @@ loop_select: STP (y2, y3), 3*16(res_ptr) RET /* ---------------------------------------*/ -// func p256OrdSqr(res, in *p256OrdElement, n int) -TEXT ·p256OrdSqr(SB),NOSPLIT,$0 - MOVD in+8(FP), a_ptr - MOVD n+16(FP), b_ptr - - MOVD p256ordK0<>(SB), hlp1 - LDP p256ord<>+0x00(SB), (const0, const1) - LDP p256ord<>+0x10(SB), (const2, const3) - - LDP 0*16(a_ptr), (x0, x1) - LDP 1*16(a_ptr), (x2, x3) - -ordSqrLoop: - SUB $1, b_ptr - - // x[1:] * x[0] - MUL x0, x1, acc1 - UMULH x0, x1, acc2 - - MUL x0, x2, t0 - ADDS t0, acc2, acc2 - UMULH x0, x2, acc3 - - MUL x0, x3, t0 - ADCS t0, acc3, acc3 - UMULH x0, x3, acc4 - ADC $0, acc4, acc4 - // x[2:] * x[1] - MUL x1, x2, t0 - ADDS t0, acc3 - UMULH x1, x2, t1 - ADCS t1, acc4 - ADC $0, ZR, acc5 - - MUL x1, x3, t0 - ADDS t0, acc4 - UMULH x1, x3, t1 - ADC t1, acc5 - // x[3] * x[2] - MUL x2, x3, t0 - ADDS t0, acc5 - UMULH x2, x3, acc6 - ADC $0, acc6 - - MOVD $0, acc7 - // *2 - ADDS acc1, acc1 - ADCS acc2, acc2 - ADCS acc3, acc3 - ADCS acc4, acc4 - ADCS acc5, acc5 - ADCS acc6, acc6 - ADC $0, acc7 - // Missing products - MUL x0, x0, acc0 - UMULH x0, x0, t0 - ADDS t0, acc1, acc1 - - MUL x1, x1, t0 - ADCS t0, acc2, acc2 - UMULH x1, x1, t1 - ADCS t1, acc3, acc3 - - MUL x2, x2, t0 - ADCS t0, acc4, acc4 - UMULH x2, x2, t1 - ADCS t1, acc5, acc5 - - MUL x3, x3, t0 - ADCS t0, acc6, acc6 - UMULH x3, x3, t1 - ADC t1, acc7, acc7 - // First reduction step - MUL acc0, hlp1, hlp0 - - MUL const0, hlp1, t0 - ADDS t0, acc0, acc0 - UMULH const0, hlp0, t1 - - MUL const1, hlp0, t0 - ADCS t0, acc1, acc1 - UMULH const1, hlp0, y0 - - MUL const2, hlp0, t0 - ADCS t0, acc2, acc2 - UMULH const2, hlp0, acc0 - - MUL const3, hlp0, t0 - ADCS t0, acc3, acc3 - - UMULH const3, hlp0, hlp0 - ADC $0, hlp0 - - ADDS t1, acc1, acc1 - ADCS y0, acc2, acc2 - ADCS acc0, acc3, acc3 - ADC $0, hlp0, acc0 - // Second reduction step - MUL acc1, hlp1, hlp0 - - MUL const0, hlp1, t0 - ADDS t0, acc1, acc1 - UMULH const0, hlp0, t1 - - MUL const1, hlp0, t0 - ADCS t0, acc2, acc2 - UMULH const1, hlp0, y0 - - MUL const2, hlp0, t0 - ADCS t0, acc3, acc3 - UMULH const2, hlp0, acc1 - - MUL const3, hlp0, t0 - ADCS t0, acc0, acc0 - - UMULH const3, hlp0, hlp0 - ADC $0, hlp0 - - ADDS t1, acc2, acc2 - ADCS y0, acc3, acc3 - ADCS acc1, acc0, acc0 - ADC $0, hlp0, acc1 - // Third reduction step - MUL acc2, hlp1, hlp0 - - MUL const0, hlp1, t0 - ADDS t0, acc2, acc2 - UMULH const0, hlp0, t1 - - MUL const1, hlp0, t0 - ADCS t0, acc3, acc3 - UMULH const1, hlp0, y0 - - MUL const2, hlp0, t0 - ADCS t0, acc0, acc0 - UMULH const2, hlp0, acc2 - - MUL const3, hlp0, t0 - ADCS t0, acc1, acc1 - - UMULH const3, hlp0, hlp0 - ADC $0, hlp0 - - ADDS t1, acc3, acc3 - ADCS y0, acc0, acc0 - ADCS acc2, acc1, acc1 - ADC $0, hlp0, acc2 - - // Last reduction step - MUL acc3, hlp1, hlp0 - - MUL const0, hlp1, t0 - ADDS t0, acc3, acc3 - UMULH const0, hlp0, t1 - - MUL const1, hlp0, t0 - ADCS t0, acc0, acc0 - UMULH const1, hlp0, y0 - - MUL const2, hlp0, t0 - ADCS t0, acc1, acc1 - UMULH const2, hlp0, acc3 - - MUL const3, hlp0, t0 - ADCS t0, acc2, acc2 - - UMULH const3, hlp0, hlp0 - ADC $0, acc7 - - ADDS t1, acc0, acc0 - ADCS y0, acc1, acc1 - ADCS acc3, acc2, acc2 - ADC $0, hlp0, acc3 - - ADDS acc4, acc0, acc0 - ADCS acc5, acc1, acc1 - ADCS acc6, acc2, acc2 - ADCS acc7, acc3, acc3 - ADC $0, ZR, acc4 - - SUBS const0, acc0, y0 - SBCS const1, acc1, y1 - SBCS const2, acc2, y2 - SBCS const3, acc3, y3 - SBCS $0, acc4, acc4 - - CSEL CS, y0, acc0, x0 - CSEL CS, y1, acc1, x1 - CSEL CS, y2, acc2, x2 - CSEL CS, y3, acc3, x3 - - CBNZ b_ptr, ordSqrLoop - - MOVD res+0(FP), res_ptr - STP (x0, x1), 0*16(res_ptr) - STP (x2, x3), 1*16(res_ptr) - - RET -/* ---------------------------------------*/ -// func p256OrdMul(res, in1, in2 *p256OrdElement) -TEXT ·p256OrdMul(SB),NOSPLIT,$0 - MOVD in1+8(FP), a_ptr - MOVD in2+16(FP), b_ptr - - MOVD p256ordK0<>(SB), hlp1 - LDP p256ord<>+0x00(SB), (const0, const1) - LDP p256ord<>+0x10(SB), (const2, const3) - - LDP 0*16(a_ptr), (x0, x1) - LDP 1*16(a_ptr), (x2, x3) - LDP 0*16(b_ptr), (y0, y1) - LDP 1*16(b_ptr), (y2, y3) - - // y[0] * x - MUL y0, x0, acc0 - UMULH y0, x0, acc1 - - MUL y0, x1, t0 - ADDS t0, acc1 - UMULH y0, x1, acc2 - - MUL y0, x2, t0 - ADCS t0, acc2 - UMULH y0, x2, acc3 - - MUL y0, x3, t0 - ADCS t0, acc3 - UMULH y0, x3, acc4 - ADC $0, acc4 - // First reduction step - MUL acc0, hlp1, hlp0 - - MUL const0, hlp1, t0 - ADDS t0, acc0, acc0 - UMULH const0, hlp0, t1 - - MUL const1, hlp0, t0 - ADCS t0, acc1, acc1 - UMULH const1, hlp0, y0 - - MUL const2, hlp0, t0 - ADCS t0, acc2, acc2 - UMULH const2, hlp0, acc0 - - MUL const3, hlp0, t0 - ADCS t0, acc3, acc3 - - UMULH const3, hlp0, hlp0 - ADC $0, acc4 - - ADDS t1, acc1, acc1 - ADCS y0, acc2, acc2 - ADCS acc0, acc3, acc3 - ADC $0, hlp0, acc0 - // y[1] * x - MUL y1, x0, t0 - ADDS t0, acc1 - UMULH y1, x0, t1 - - MUL y1, x1, t0 - ADCS t0, acc2 - UMULH y1, x1, hlp0 - - MUL y1, x2, t0 - ADCS t0, acc3 - UMULH y1, x2, y0 - - MUL y1, x3, t0 - ADCS t0, acc4 - UMULH y1, x3, y1 - ADC $0, ZR, acc5 - - ADDS t1, acc2 - ADCS hlp0, acc3 - ADCS y0, acc4 - ADC y1, acc5 - // Second reduction step - MUL acc1, hlp1, hlp0 - - MUL const0, hlp1, t0 - ADDS t0, acc1, acc1 - UMULH const0, hlp0, t1 - - MUL const1, hlp0, t0 - ADCS t0, acc2, acc2 - UMULH const1, hlp0, y0 - - MUL const2, hlp0, t0 - ADCS t0, acc3, acc3 - UMULH const2, hlp0, acc1 - - MUL const3, hlp0, t0 - ADCS t0, acc0, acc0 - - UMULH const3, hlp0, hlp0 - ADC $0, acc5 - - ADDS t1, acc2, acc2 - ADCS y0, acc3, acc3 - ADCS acc1, acc0, acc0 - ADC $0, hlp0, acc1 - // y[2] * x - MUL y2, x0, t0 - ADDS t0, acc2 - UMULH y2, x0, t1 - - MUL y2, x1, t0 - ADCS t0, acc3 - UMULH y2, x1, hlp0 - - MUL y2, x2, t0 - ADCS t0, acc4 - UMULH y2, x2, y0 - - MUL y2, x3, t0 - ADCS t0, acc5 - UMULH y2, x3, y1 - ADC $0, ZR, acc6 - - ADDS t1, acc3 - ADCS hlp0, acc4 - ADCS y0, acc5 - ADC y1, acc6 - // Third reduction step - MUL acc2, hlp1, hlp0 - - MUL const0, hlp1, t0 - ADDS t0, acc2, acc2 - UMULH const0, hlp0, t1 - - MUL const1, hlp0, t0 - ADCS t0, acc3, acc3 - UMULH const1, hlp0, y0 - - MUL const2, hlp0, t0 - ADCS t0, acc0, acc0 - UMULH const2, hlp0, acc2 - - MUL const3, hlp0, t0 - ADCS t0, acc1, acc1 - - UMULH const3, hlp0, hlp0 - ADC $0, acc6 - - ADDS t1, acc3, acc3 - ADCS y0, acc0, acc0 - ADCS acc2, acc1, acc1 - ADC $0, hlp0, acc2 - // y[3] * x - MUL y3, x0, t0 - ADDS t0, acc3 - UMULH y3, x0, t1 - - MUL y3, x1, t0 - ADCS t0, acc4 - UMULH y3, x1, hlp0 - - MUL y3, x2, t0 - ADCS t0, acc5 - UMULH y3, x2, y0 - - MUL y3, x3, t0 - ADCS t0, acc6 - UMULH y3, x3, y1 - ADC $0, ZR, acc7 - - ADDS t1, acc4 - ADCS hlp0, acc5 - ADCS y0, acc6 - ADC y1, acc7 - // Last reduction step - MUL acc3, hlp1, hlp0 - - MUL const0, hlp1, t0 - ADDS t0, acc3, acc3 - UMULH const0, hlp0, t1 - - MUL const1, hlp0, t0 - ADCS t0, acc0, acc0 - UMULH const1, hlp0, y0 - - MUL const2, hlp0, t0 - ADCS t0, acc1, acc1 - UMULH const2, hlp0, acc3 - - MUL const3, hlp0, t0 - ADCS t0, acc2, acc2 - - UMULH const3, hlp0, hlp0 - ADC $0, acc7 - - ADDS t1, acc0, acc0 - ADCS y0, acc1, acc1 - ADCS acc3, acc2, acc2 - ADC $0, hlp0, acc3 - - ADDS acc4, acc0, acc0 - ADCS acc5, acc1, acc1 - ADCS acc6, acc2, acc2 - ADCS acc7, acc3, acc3 - ADC $0, ZR, acc4 - - SUBS const0, acc0, t0 - SBCS const1, acc1, t1 - SBCS const2, acc2, t2 - SBCS const3, acc3, t3 - SBCS $0, acc4, acc4 - - CSEL CS, t0, acc0, acc0 - CSEL CS, t1, acc1, acc1 - CSEL CS, t2, acc2, acc2 - CSEL CS, t3, acc3, acc3 - - MOVD res+0(FP), res_ptr - STP (acc0, acc1), 0*16(res_ptr) - STP (acc2, acc3), 1*16(res_ptr) - - RET -/* ---------------------------------------*/ +// input: x0-x3, y0-y3 +// output: x0-x3 +// uses: const0, const1 +// clobbers: y0-y3, hlp0 TEXT p256SubInternal<>(SB),NOSPLIT,$0 SUBS x0, y0, acc0 SBCS x1, y1, acc1 diff --git a/src/crypto/internal/fips140/nistec/p256_ordinv.go b/src/crypto/internal/fips140/nistec/p256_ordinv.go index 156a873188c3ae..6404e0bac62215 100644 --- a/src/crypto/internal/fips140/nistec/p256_ordinv.go +++ b/src/crypto/internal/fips140/nistec/p256_ordinv.go @@ -2,53 +2,30 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (amd64 || arm64) && !purego - package nistec -import "errors" - -// Montgomery multiplication modulo org(G). Sets res = in1 * in2 * R⁻¹. -// -//go:noescape -func p256OrdMul(res, in1, in2 *p256OrdElement) - -// Montgomery square modulo org(G), repeated n times (n >= 1). -// -//go:noescape -func p256OrdSqr(res, in *p256OrdElement, n int) - -func P256OrdInverse(k []byte) ([]byte, error) { - if len(k) != 32 { - return nil, errors.New("invalid scalar length") - } - - x := new(p256OrdElement) - p256OrdBigToLittle(x, (*[32]byte)(k)) - p256OrdReduce(x) +import "math/bits" +// P256OrdInverse sets k to the inverse of k modulo ord(G). k is encoded as four +// uint64 limbs in little-endian order, and must be reduced. If k is zero, the +// result is zero. +func P256OrdInverse(k *[4]uint64) { // Inversion is implemented as exponentiation by n - 2, per Fermat's little theorem. // // The sequence of 38 multiplications and 254 squarings is derived from // https://briansmith.org/ecc-inversion-addition-chains-01#p256_scalar_inversion - _1 := new(p256OrdElement) - _11 := new(p256OrdElement) - _101 := new(p256OrdElement) - _111 := new(p256OrdElement) - _1111 := new(p256OrdElement) - _10101 := new(p256OrdElement) - _101111 := new(p256OrdElement) - t := new(p256OrdElement) - - // This code operates in the Montgomery domain where R = 2²⁵⁶ mod n and n is - // the order of the scalar field. Elements in the Montgomery domain take the - // form a×R and p256OrdMul calculates (a × b × R⁻¹) mod n. RR is R in the - // domain, or R×R mod n, thus p256OrdMul(x, RR) gives x×R, i.e. converts x - // into the Montgomery domain. - RR := &p256OrdElement{0x83244c95be79eea2, 0x4699799c49bd6fa6, - 0x2845b2392b6bec59, 0x66e12d94f3d95620} - - p256OrdMul(_1, x, RR) // _1 + _1 := new(p256OrdMontgomeryDomainFieldElement) + _11 := new(p256OrdMontgomeryDomainFieldElement) + _101 := new(p256OrdMontgomeryDomainFieldElement) + _111 := new(p256OrdMontgomeryDomainFieldElement) + _1111 := new(p256OrdMontgomeryDomainFieldElement) + _10101 := new(p256OrdMontgomeryDomainFieldElement) + _101111 := new(p256OrdMontgomeryDomainFieldElement) + x := new(p256OrdMontgomeryDomainFieldElement) + t := new(p256OrdMontgomeryDomainFieldElement) + + j := (*p256OrdNonMontgomeryDomainFieldElement)(k) + p256OrdToMontgomery(_1, j) // _1 p256OrdSqr(x, _1, 1) // _10 p256OrdMul(_11, x, _1) // _11 p256OrdMul(_101, x, _11) // _101 @@ -79,7 +56,7 @@ func P256OrdInverse(k []byte) ([]byte, error) { 6, 2, 5, 6, 5, 4, 5, 5, 3, 10, 2, 5, 5, 3, 7, 6} - muls := []*p256OrdElement{ + muls := []*p256OrdMontgomeryDomainFieldElement{ _101111, _111, _11, _1111, _10101, _101, _101, _101, _111, _101111, _1111, _1, _1, _1111, _111, @@ -91,12 +68,1294 @@ func P256OrdInverse(k []byte) ([]byte, error) { p256OrdMul(x, x, muls[i]) } - // Montgomery multiplication by R⁻¹, or 1 outside the domain as R⁻¹×R = 1, - // converts a Montgomery value out of the domain. - one := &p256OrdElement{1} - p256OrdMul(x, x, one) + p256OrdFromMontgomery(j, x) +} + +func p256OrdSqr(out1, arg1 *p256OrdMontgomeryDomainFieldElement, n int) { + p256OrdSquare(out1, arg1) + for range n - 1 { + p256OrdSquare(out1, out1) + } +} + +// The code below was generated by Fiat Cryptography v0.1.6-63-g92ee794c2. +// +// word-by-word-montgomery --lang Go --no-wide-int +// --relax-primitive-carry-to-bitwidth 32,64 --cmovznz-by-mul --static +// --package-case flatcase --private-function-case camelCase --private-type-case +// camelCase --no-prefix-fiat --package-name nistec p256Ord 64 +// 2^256-2^224+2^192-89188191075325690597107910205041859247 +// mul square from_montgomery to_montgomery +// +// https://mit-plv.github.io/fiat-crypto/ +// +// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, +// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +// Autogenerated: fiat_crypto.js word-by-word-montgomery --lang Go --no-wide-int --relax-primitive-carry-to-bitwidth 32,64 --cmovznz-by-mul --static --package-case flatcase --private-function-case camelCase --private-type-case camelCase --no-prefix-fiat --package-name nistec p256Ord 64 2^256-2^224+2^192-89188191075325690597107910205041859247 mul square from_montgomery to_montgomery +// +// curve description: p256Ord +// +// machine_wordsize = 64 (from "64") +// +// requested operations: mul, square, from_montgomery, to_montgomery +// +// m = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 (from "2^256-2^224+2^192-89188191075325690597107910205041859247") +// +// +// +// NOTE: In addition to the bounds specified above each function, all +// +// functions synthesized for this Montgomery arithmetic require the +// +// input to be strictly less than the prime modulus (m), and also +// +// require the input to be in the unique saturated representation. +// +// All functions also ensure that these two properties are true of +// +// return values. +// +// +// +// Computed values: +// +// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) +// +// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) +// +// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in +// +// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 + +type p256OrdUint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 +type p256OrdInt1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 + +// The type p256OrdMontgomeryDomainFieldElement is a field element in the Montgomery domain. +// +// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type p256OrdMontgomeryDomainFieldElement [4]uint64 + +// The type p256OrdNonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain. +// +// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type p256OrdNonMontgomeryDomainFieldElement [4]uint64 + +// The function p256OrdMul multiplies two field elements in the Montgomery domain. +// +// Preconditions: +// +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// +// Postconditions: +// +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +func p256OrdMul(out1 *p256OrdMontgomeryDomainFieldElement, arg1 *p256OrdMontgomeryDomainFieldElement, arg2 *p256OrdMontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg2[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg2[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg2[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg2[0]) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(p256OrdUint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(p256OrdUint1(x16))) + x19 := (uint64(p256OrdUint1(x18)) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0xccd1c8aaee00bc4f) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0xffffffff00000000) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0xffffffffffffffff) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0xbce6faada7179e84) + var x28 uint64 + var x29 uint64 + x29, x28 = bits.Mul64(x20, 0xf3b9cac2fc632551) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x29, x26, uint64(0x0)) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x27, x24, uint64(p256OrdUint1(x31))) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x25, x22, uint64(p256OrdUint1(x33))) + x36 := (uint64(p256OrdUint1(x35)) + x23) + var x38 uint64 + _, x38 = bits.Add64(x11, x28, uint64(0x0)) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x13, x30, uint64(p256OrdUint1(x38))) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x15, x32, uint64(p256OrdUint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64(x17, x34, uint64(p256OrdUint1(x42))) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Add64(x19, x36, uint64(p256OrdUint1(x44))) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg2[3]) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x1, arg2[2]) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x1, arg2[1]) + var x53 uint64 + var x54 uint64 + x54, x53 = bits.Mul64(x1, arg2[0]) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x54, x51, uint64(0x0)) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x52, x49, uint64(p256OrdUint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x50, x47, uint64(p256OrdUint1(x58))) + x61 := (uint64(p256OrdUint1(x60)) + x48) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x39, x53, uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x41, x55, uint64(p256OrdUint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x43, x57, uint64(p256OrdUint1(x65))) + var x68 uint64 + var x69 uint64 + x68, x69 = bits.Add64(x45, x59, uint64(p256OrdUint1(x67))) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(uint64(p256OrdUint1(x46)), x61, uint64(p256OrdUint1(x69))) + var x72 uint64 + _, x72 = bits.Mul64(x62, 0xccd1c8aaee00bc4f) + var x74 uint64 + var x75 uint64 + x75, x74 = bits.Mul64(x72, 0xffffffff00000000) + var x76 uint64 + var x77 uint64 + x77, x76 = bits.Mul64(x72, 0xffffffffffffffff) + var x78 uint64 + var x79 uint64 + x79, x78 = bits.Mul64(x72, 0xbce6faada7179e84) + var x80 uint64 + var x81 uint64 + x81, x80 = bits.Mul64(x72, 0xf3b9cac2fc632551) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x81, x78, uint64(0x0)) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x79, x76, uint64(p256OrdUint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x77, x74, uint64(p256OrdUint1(x85))) + x88 := (uint64(p256OrdUint1(x87)) + x75) + var x90 uint64 + _, x90 = bits.Add64(x62, x80, uint64(0x0)) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(x64, x82, uint64(p256OrdUint1(x90))) + var x93 uint64 + var x94 uint64 + x93, x94 = bits.Add64(x66, x84, uint64(p256OrdUint1(x92))) + var x95 uint64 + var x96 uint64 + x95, x96 = bits.Add64(x68, x86, uint64(p256OrdUint1(x94))) + var x97 uint64 + var x98 uint64 + x97, x98 = bits.Add64(x70, x88, uint64(p256OrdUint1(x96))) + x99 := (uint64(p256OrdUint1(x98)) + uint64(p256OrdUint1(x71))) + var x100 uint64 + var x101 uint64 + x101, x100 = bits.Mul64(x2, arg2[3]) + var x102 uint64 + var x103 uint64 + x103, x102 = bits.Mul64(x2, arg2[2]) + var x104 uint64 + var x105 uint64 + x105, x104 = bits.Mul64(x2, arg2[1]) + var x106 uint64 + var x107 uint64 + x107, x106 = bits.Mul64(x2, arg2[0]) + var x108 uint64 + var x109 uint64 + x108, x109 = bits.Add64(x107, x104, uint64(0x0)) + var x110 uint64 + var x111 uint64 + x110, x111 = bits.Add64(x105, x102, uint64(p256OrdUint1(x109))) + var x112 uint64 + var x113 uint64 + x112, x113 = bits.Add64(x103, x100, uint64(p256OrdUint1(x111))) + x114 := (uint64(p256OrdUint1(x113)) + x101) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x91, x106, uint64(0x0)) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Add64(x93, x108, uint64(p256OrdUint1(x116))) + var x119 uint64 + var x120 uint64 + x119, x120 = bits.Add64(x95, x110, uint64(p256OrdUint1(x118))) + var x121 uint64 + var x122 uint64 + x121, x122 = bits.Add64(x97, x112, uint64(p256OrdUint1(x120))) + var x123 uint64 + var x124 uint64 + x123, x124 = bits.Add64(x99, x114, uint64(p256OrdUint1(x122))) + var x125 uint64 + _, x125 = bits.Mul64(x115, 0xccd1c8aaee00bc4f) + var x127 uint64 + var x128 uint64 + x128, x127 = bits.Mul64(x125, 0xffffffff00000000) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(x125, 0xffffffffffffffff) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(x125, 0xbce6faada7179e84) + var x133 uint64 + var x134 uint64 + x134, x133 = bits.Mul64(x125, 0xf3b9cac2fc632551) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x134, x131, uint64(0x0)) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x132, x129, uint64(p256OrdUint1(x136))) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(x130, x127, uint64(p256OrdUint1(x138))) + x141 := (uint64(p256OrdUint1(x140)) + x128) + var x143 uint64 + _, x143 = bits.Add64(x115, x133, uint64(0x0)) + var x144 uint64 + var x145 uint64 + x144, x145 = bits.Add64(x117, x135, uint64(p256OrdUint1(x143))) + var x146 uint64 + var x147 uint64 + x146, x147 = bits.Add64(x119, x137, uint64(p256OrdUint1(x145))) + var x148 uint64 + var x149 uint64 + x148, x149 = bits.Add64(x121, x139, uint64(p256OrdUint1(x147))) + var x150 uint64 + var x151 uint64 + x150, x151 = bits.Add64(x123, x141, uint64(p256OrdUint1(x149))) + x152 := (uint64(p256OrdUint1(x151)) + uint64(p256OrdUint1(x124))) + var x153 uint64 + var x154 uint64 + x154, x153 = bits.Mul64(x3, arg2[3]) + var x155 uint64 + var x156 uint64 + x156, x155 = bits.Mul64(x3, arg2[2]) + var x157 uint64 + var x158 uint64 + x158, x157 = bits.Mul64(x3, arg2[1]) + var x159 uint64 + var x160 uint64 + x160, x159 = bits.Mul64(x3, arg2[0]) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Add64(x160, x157, uint64(0x0)) + var x163 uint64 + var x164 uint64 + x163, x164 = bits.Add64(x158, x155, uint64(p256OrdUint1(x162))) + var x165 uint64 + var x166 uint64 + x165, x166 = bits.Add64(x156, x153, uint64(p256OrdUint1(x164))) + x167 := (uint64(p256OrdUint1(x166)) + x154) + var x168 uint64 + var x169 uint64 + x168, x169 = bits.Add64(x144, x159, uint64(0x0)) + var x170 uint64 + var x171 uint64 + x170, x171 = bits.Add64(x146, x161, uint64(p256OrdUint1(x169))) + var x172 uint64 + var x173 uint64 + x172, x173 = bits.Add64(x148, x163, uint64(p256OrdUint1(x171))) + var x174 uint64 + var x175 uint64 + x174, x175 = bits.Add64(x150, x165, uint64(p256OrdUint1(x173))) + var x176 uint64 + var x177 uint64 + x176, x177 = bits.Add64(x152, x167, uint64(p256OrdUint1(x175))) + var x178 uint64 + _, x178 = bits.Mul64(x168, 0xccd1c8aaee00bc4f) + var x180 uint64 + var x181 uint64 + x181, x180 = bits.Mul64(x178, 0xffffffff00000000) + var x182 uint64 + var x183 uint64 + x183, x182 = bits.Mul64(x178, 0xffffffffffffffff) + var x184 uint64 + var x185 uint64 + x185, x184 = bits.Mul64(x178, 0xbce6faada7179e84) + var x186 uint64 + var x187 uint64 + x187, x186 = bits.Mul64(x178, 0xf3b9cac2fc632551) + var x188 uint64 + var x189 uint64 + x188, x189 = bits.Add64(x187, x184, uint64(0x0)) + var x190 uint64 + var x191 uint64 + x190, x191 = bits.Add64(x185, x182, uint64(p256OrdUint1(x189))) + var x192 uint64 + var x193 uint64 + x192, x193 = bits.Add64(x183, x180, uint64(p256OrdUint1(x191))) + x194 := (uint64(p256OrdUint1(x193)) + x181) + var x196 uint64 + _, x196 = bits.Add64(x168, x186, uint64(0x0)) + var x197 uint64 + var x198 uint64 + x197, x198 = bits.Add64(x170, x188, uint64(p256OrdUint1(x196))) + var x199 uint64 + var x200 uint64 + x199, x200 = bits.Add64(x172, x190, uint64(p256OrdUint1(x198))) + var x201 uint64 + var x202 uint64 + x201, x202 = bits.Add64(x174, x192, uint64(p256OrdUint1(x200))) + var x203 uint64 + var x204 uint64 + x203, x204 = bits.Add64(x176, x194, uint64(p256OrdUint1(x202))) + x205 := (uint64(p256OrdUint1(x204)) + uint64(p256OrdUint1(x177))) + var x206 uint64 + var x207 uint64 + x206, x207 = bits.Sub64(x197, 0xf3b9cac2fc632551, uint64(0x0)) + var x208 uint64 + var x209 uint64 + x208, x209 = bits.Sub64(x199, 0xbce6faada7179e84, uint64(p256OrdUint1(x207))) + var x210 uint64 + var x211 uint64 + x210, x211 = bits.Sub64(x201, 0xffffffffffffffff, uint64(p256OrdUint1(x209))) + var x212 uint64 + var x213 uint64 + x212, x213 = bits.Sub64(x203, 0xffffffff00000000, uint64(p256OrdUint1(x211))) + var x215 uint64 + _, x215 = bits.Sub64(x205, uint64(0x0), uint64(p256OrdUint1(x213))) + var x216 uint64 + p256OrdCmovznzU64(&x216, p256OrdUint1(x215), x206, x197) + var x217 uint64 + p256OrdCmovznzU64(&x217, p256OrdUint1(x215), x208, x199) + var x218 uint64 + p256OrdCmovznzU64(&x218, p256OrdUint1(x215), x210, x201) + var x219 uint64 + p256OrdCmovznzU64(&x219, p256OrdUint1(x215), x212, x203) + out1[0] = x216 + out1[1] = x217 + out1[2] = x218 + out1[3] = x219 +} + +// The function p256OrdSquare squares a field element in the Montgomery domain. +// +// Preconditions: +// +// 0 ≤ eval arg1 < m +// +// Postconditions: +// +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m +// 0 ≤ eval out1 < m +func p256OrdSquare(out1 *p256OrdMontgomeryDomainFieldElement, arg1 *p256OrdMontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg1[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg1[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg1[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg1[0]) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(p256OrdUint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(p256OrdUint1(x16))) + x19 := (uint64(p256OrdUint1(x18)) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0xccd1c8aaee00bc4f) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0xffffffff00000000) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0xffffffffffffffff) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0xbce6faada7179e84) + var x28 uint64 + var x29 uint64 + x29, x28 = bits.Mul64(x20, 0xf3b9cac2fc632551) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x29, x26, uint64(0x0)) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x27, x24, uint64(p256OrdUint1(x31))) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x25, x22, uint64(p256OrdUint1(x33))) + x36 := (uint64(p256OrdUint1(x35)) + x23) + var x38 uint64 + _, x38 = bits.Add64(x11, x28, uint64(0x0)) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x13, x30, uint64(p256OrdUint1(x38))) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x15, x32, uint64(p256OrdUint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64(x17, x34, uint64(p256OrdUint1(x42))) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Add64(x19, x36, uint64(p256OrdUint1(x44))) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg1[3]) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x1, arg1[2]) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x1, arg1[1]) + var x53 uint64 + var x54 uint64 + x54, x53 = bits.Mul64(x1, arg1[0]) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x54, x51, uint64(0x0)) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x52, x49, uint64(p256OrdUint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x50, x47, uint64(p256OrdUint1(x58))) + x61 := (uint64(p256OrdUint1(x60)) + x48) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x39, x53, uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x41, x55, uint64(p256OrdUint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x43, x57, uint64(p256OrdUint1(x65))) + var x68 uint64 + var x69 uint64 + x68, x69 = bits.Add64(x45, x59, uint64(p256OrdUint1(x67))) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(uint64(p256OrdUint1(x46)), x61, uint64(p256OrdUint1(x69))) + var x72 uint64 + _, x72 = bits.Mul64(x62, 0xccd1c8aaee00bc4f) + var x74 uint64 + var x75 uint64 + x75, x74 = bits.Mul64(x72, 0xffffffff00000000) + var x76 uint64 + var x77 uint64 + x77, x76 = bits.Mul64(x72, 0xffffffffffffffff) + var x78 uint64 + var x79 uint64 + x79, x78 = bits.Mul64(x72, 0xbce6faada7179e84) + var x80 uint64 + var x81 uint64 + x81, x80 = bits.Mul64(x72, 0xf3b9cac2fc632551) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x81, x78, uint64(0x0)) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x79, x76, uint64(p256OrdUint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x77, x74, uint64(p256OrdUint1(x85))) + x88 := (uint64(p256OrdUint1(x87)) + x75) + var x90 uint64 + _, x90 = bits.Add64(x62, x80, uint64(0x0)) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(x64, x82, uint64(p256OrdUint1(x90))) + var x93 uint64 + var x94 uint64 + x93, x94 = bits.Add64(x66, x84, uint64(p256OrdUint1(x92))) + var x95 uint64 + var x96 uint64 + x95, x96 = bits.Add64(x68, x86, uint64(p256OrdUint1(x94))) + var x97 uint64 + var x98 uint64 + x97, x98 = bits.Add64(x70, x88, uint64(p256OrdUint1(x96))) + x99 := (uint64(p256OrdUint1(x98)) + uint64(p256OrdUint1(x71))) + var x100 uint64 + var x101 uint64 + x101, x100 = bits.Mul64(x2, arg1[3]) + var x102 uint64 + var x103 uint64 + x103, x102 = bits.Mul64(x2, arg1[2]) + var x104 uint64 + var x105 uint64 + x105, x104 = bits.Mul64(x2, arg1[1]) + var x106 uint64 + var x107 uint64 + x107, x106 = bits.Mul64(x2, arg1[0]) + var x108 uint64 + var x109 uint64 + x108, x109 = bits.Add64(x107, x104, uint64(0x0)) + var x110 uint64 + var x111 uint64 + x110, x111 = bits.Add64(x105, x102, uint64(p256OrdUint1(x109))) + var x112 uint64 + var x113 uint64 + x112, x113 = bits.Add64(x103, x100, uint64(p256OrdUint1(x111))) + x114 := (uint64(p256OrdUint1(x113)) + x101) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x91, x106, uint64(0x0)) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Add64(x93, x108, uint64(p256OrdUint1(x116))) + var x119 uint64 + var x120 uint64 + x119, x120 = bits.Add64(x95, x110, uint64(p256OrdUint1(x118))) + var x121 uint64 + var x122 uint64 + x121, x122 = bits.Add64(x97, x112, uint64(p256OrdUint1(x120))) + var x123 uint64 + var x124 uint64 + x123, x124 = bits.Add64(x99, x114, uint64(p256OrdUint1(x122))) + var x125 uint64 + _, x125 = bits.Mul64(x115, 0xccd1c8aaee00bc4f) + var x127 uint64 + var x128 uint64 + x128, x127 = bits.Mul64(x125, 0xffffffff00000000) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(x125, 0xffffffffffffffff) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(x125, 0xbce6faada7179e84) + var x133 uint64 + var x134 uint64 + x134, x133 = bits.Mul64(x125, 0xf3b9cac2fc632551) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x134, x131, uint64(0x0)) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x132, x129, uint64(p256OrdUint1(x136))) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(x130, x127, uint64(p256OrdUint1(x138))) + x141 := (uint64(p256OrdUint1(x140)) + x128) + var x143 uint64 + _, x143 = bits.Add64(x115, x133, uint64(0x0)) + var x144 uint64 + var x145 uint64 + x144, x145 = bits.Add64(x117, x135, uint64(p256OrdUint1(x143))) + var x146 uint64 + var x147 uint64 + x146, x147 = bits.Add64(x119, x137, uint64(p256OrdUint1(x145))) + var x148 uint64 + var x149 uint64 + x148, x149 = bits.Add64(x121, x139, uint64(p256OrdUint1(x147))) + var x150 uint64 + var x151 uint64 + x150, x151 = bits.Add64(x123, x141, uint64(p256OrdUint1(x149))) + x152 := (uint64(p256OrdUint1(x151)) + uint64(p256OrdUint1(x124))) + var x153 uint64 + var x154 uint64 + x154, x153 = bits.Mul64(x3, arg1[3]) + var x155 uint64 + var x156 uint64 + x156, x155 = bits.Mul64(x3, arg1[2]) + var x157 uint64 + var x158 uint64 + x158, x157 = bits.Mul64(x3, arg1[1]) + var x159 uint64 + var x160 uint64 + x160, x159 = bits.Mul64(x3, arg1[0]) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Add64(x160, x157, uint64(0x0)) + var x163 uint64 + var x164 uint64 + x163, x164 = bits.Add64(x158, x155, uint64(p256OrdUint1(x162))) + var x165 uint64 + var x166 uint64 + x165, x166 = bits.Add64(x156, x153, uint64(p256OrdUint1(x164))) + x167 := (uint64(p256OrdUint1(x166)) + x154) + var x168 uint64 + var x169 uint64 + x168, x169 = bits.Add64(x144, x159, uint64(0x0)) + var x170 uint64 + var x171 uint64 + x170, x171 = bits.Add64(x146, x161, uint64(p256OrdUint1(x169))) + var x172 uint64 + var x173 uint64 + x172, x173 = bits.Add64(x148, x163, uint64(p256OrdUint1(x171))) + var x174 uint64 + var x175 uint64 + x174, x175 = bits.Add64(x150, x165, uint64(p256OrdUint1(x173))) + var x176 uint64 + var x177 uint64 + x176, x177 = bits.Add64(x152, x167, uint64(p256OrdUint1(x175))) + var x178 uint64 + _, x178 = bits.Mul64(x168, 0xccd1c8aaee00bc4f) + var x180 uint64 + var x181 uint64 + x181, x180 = bits.Mul64(x178, 0xffffffff00000000) + var x182 uint64 + var x183 uint64 + x183, x182 = bits.Mul64(x178, 0xffffffffffffffff) + var x184 uint64 + var x185 uint64 + x185, x184 = bits.Mul64(x178, 0xbce6faada7179e84) + var x186 uint64 + var x187 uint64 + x187, x186 = bits.Mul64(x178, 0xf3b9cac2fc632551) + var x188 uint64 + var x189 uint64 + x188, x189 = bits.Add64(x187, x184, uint64(0x0)) + var x190 uint64 + var x191 uint64 + x190, x191 = bits.Add64(x185, x182, uint64(p256OrdUint1(x189))) + var x192 uint64 + var x193 uint64 + x192, x193 = bits.Add64(x183, x180, uint64(p256OrdUint1(x191))) + x194 := (uint64(p256OrdUint1(x193)) + x181) + var x196 uint64 + _, x196 = bits.Add64(x168, x186, uint64(0x0)) + var x197 uint64 + var x198 uint64 + x197, x198 = bits.Add64(x170, x188, uint64(p256OrdUint1(x196))) + var x199 uint64 + var x200 uint64 + x199, x200 = bits.Add64(x172, x190, uint64(p256OrdUint1(x198))) + var x201 uint64 + var x202 uint64 + x201, x202 = bits.Add64(x174, x192, uint64(p256OrdUint1(x200))) + var x203 uint64 + var x204 uint64 + x203, x204 = bits.Add64(x176, x194, uint64(p256OrdUint1(x202))) + x205 := (uint64(p256OrdUint1(x204)) + uint64(p256OrdUint1(x177))) + var x206 uint64 + var x207 uint64 + x206, x207 = bits.Sub64(x197, 0xf3b9cac2fc632551, uint64(0x0)) + var x208 uint64 + var x209 uint64 + x208, x209 = bits.Sub64(x199, 0xbce6faada7179e84, uint64(p256OrdUint1(x207))) + var x210 uint64 + var x211 uint64 + x210, x211 = bits.Sub64(x201, 0xffffffffffffffff, uint64(p256OrdUint1(x209))) + var x212 uint64 + var x213 uint64 + x212, x213 = bits.Sub64(x203, 0xffffffff00000000, uint64(p256OrdUint1(x211))) + var x215 uint64 + _, x215 = bits.Sub64(x205, uint64(0x0), uint64(p256OrdUint1(x213))) + var x216 uint64 + p256OrdCmovznzU64(&x216, p256OrdUint1(x215), x206, x197) + var x217 uint64 + p256OrdCmovznzU64(&x217, p256OrdUint1(x215), x208, x199) + var x218 uint64 + p256OrdCmovznzU64(&x218, p256OrdUint1(x215), x210, x201) + var x219 uint64 + p256OrdCmovznzU64(&x219, p256OrdUint1(x215), x212, x203) + out1[0] = x216 + out1[1] = x217 + out1[2] = x218 + out1[3] = x219 +} + +// The function p256OrdFromMontgomery translates a field element out of the Montgomery domain. +// +// Preconditions: +// +// 0 ≤ eval arg1 < m +// +// Postconditions: +// +// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m +// 0 ≤ eval out1 < m +func p256OrdFromMontgomery(out1 *p256OrdNonMontgomeryDomainFieldElement, arg1 *p256OrdMontgomeryDomainFieldElement) { + x1 := arg1[0] + var x2 uint64 + _, x2 = bits.Mul64(x1, 0xccd1c8aaee00bc4f) + var x4 uint64 + var x5 uint64 + x5, x4 = bits.Mul64(x2, 0xffffffff00000000) + var x6 uint64 + var x7 uint64 + x7, x6 = bits.Mul64(x2, 0xffffffffffffffff) + var x8 uint64 + var x9 uint64 + x9, x8 = bits.Mul64(x2, 0xbce6faada7179e84) + var x10 uint64 + var x11 uint64 + x11, x10 = bits.Mul64(x2, 0xf3b9cac2fc632551) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x11, x8, uint64(0x0)) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x9, x6, uint64(p256OrdUint1(x13))) + var x16 uint64 + var x17 uint64 + x16, x17 = bits.Add64(x7, x4, uint64(p256OrdUint1(x15))) + var x19 uint64 + _, x19 = bits.Add64(x1, x10, uint64(0x0)) + var x20 uint64 + var x21 uint64 + x20, x21 = bits.Add64(uint64(0x0), x12, uint64(p256OrdUint1(x19))) + var x22 uint64 + var x23 uint64 + x22, x23 = bits.Add64(uint64(0x0), x14, uint64(p256OrdUint1(x21))) + var x24 uint64 + var x25 uint64 + x24, x25 = bits.Add64(uint64(0x0), x16, uint64(p256OrdUint1(x23))) + var x26 uint64 + var x27 uint64 + x26, x27 = bits.Add64(x20, arg1[1], uint64(0x0)) + var x28 uint64 + var x29 uint64 + x28, x29 = bits.Add64(x22, uint64(0x0), uint64(p256OrdUint1(x27))) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x24, uint64(0x0), uint64(p256OrdUint1(x29))) + var x32 uint64 + _, x32 = bits.Mul64(x26, 0xccd1c8aaee00bc4f) + var x34 uint64 + var x35 uint64 + x35, x34 = bits.Mul64(x32, 0xffffffff00000000) + var x36 uint64 + var x37 uint64 + x37, x36 = bits.Mul64(x32, 0xffffffffffffffff) + var x38 uint64 + var x39 uint64 + x39, x38 = bits.Mul64(x32, 0xbce6faada7179e84) + var x40 uint64 + var x41 uint64 + x41, x40 = bits.Mul64(x32, 0xf3b9cac2fc632551) + var x42 uint64 + var x43 uint64 + x42, x43 = bits.Add64(x41, x38, uint64(0x0)) + var x44 uint64 + var x45 uint64 + x44, x45 = bits.Add64(x39, x36, uint64(p256OrdUint1(x43))) + var x46 uint64 + var x47 uint64 + x46, x47 = bits.Add64(x37, x34, uint64(p256OrdUint1(x45))) + var x49 uint64 + _, x49 = bits.Add64(x26, x40, uint64(0x0)) + var x50 uint64 + var x51 uint64 + x50, x51 = bits.Add64(x28, x42, uint64(p256OrdUint1(x49))) + var x52 uint64 + var x53 uint64 + x52, x53 = bits.Add64(x30, x44, uint64(p256OrdUint1(x51))) + var x54 uint64 + var x55 uint64 + x54, x55 = bits.Add64((uint64(p256OrdUint1(x31)) + (uint64(p256OrdUint1(x25)) + (uint64(p256OrdUint1(x17)) + x5))), x46, uint64(p256OrdUint1(x53))) + var x56 uint64 + var x57 uint64 + x56, x57 = bits.Add64(x50, arg1[2], uint64(0x0)) + var x58 uint64 + var x59 uint64 + x58, x59 = bits.Add64(x52, uint64(0x0), uint64(p256OrdUint1(x57))) + var x60 uint64 + var x61 uint64 + x60, x61 = bits.Add64(x54, uint64(0x0), uint64(p256OrdUint1(x59))) + var x62 uint64 + _, x62 = bits.Mul64(x56, 0xccd1c8aaee00bc4f) + var x64 uint64 + var x65 uint64 + x65, x64 = bits.Mul64(x62, 0xffffffff00000000) + var x66 uint64 + var x67 uint64 + x67, x66 = bits.Mul64(x62, 0xffffffffffffffff) + var x68 uint64 + var x69 uint64 + x69, x68 = bits.Mul64(x62, 0xbce6faada7179e84) + var x70 uint64 + var x71 uint64 + x71, x70 = bits.Mul64(x62, 0xf3b9cac2fc632551) + var x72 uint64 + var x73 uint64 + x72, x73 = bits.Add64(x71, x68, uint64(0x0)) + var x74 uint64 + var x75 uint64 + x74, x75 = bits.Add64(x69, x66, uint64(p256OrdUint1(x73))) + var x76 uint64 + var x77 uint64 + x76, x77 = bits.Add64(x67, x64, uint64(p256OrdUint1(x75))) + var x79 uint64 + _, x79 = bits.Add64(x56, x70, uint64(0x0)) + var x80 uint64 + var x81 uint64 + x80, x81 = bits.Add64(x58, x72, uint64(p256OrdUint1(x79))) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x60, x74, uint64(p256OrdUint1(x81))) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64((uint64(p256OrdUint1(x61)) + (uint64(p256OrdUint1(x55)) + (uint64(p256OrdUint1(x47)) + x35))), x76, uint64(p256OrdUint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x80, arg1[3], uint64(0x0)) + var x88 uint64 + var x89 uint64 + x88, x89 = bits.Add64(x82, uint64(0x0), uint64(p256OrdUint1(x87))) + var x90 uint64 + var x91 uint64 + x90, x91 = bits.Add64(x84, uint64(0x0), uint64(p256OrdUint1(x89))) + var x92 uint64 + _, x92 = bits.Mul64(x86, 0xccd1c8aaee00bc4f) + var x94 uint64 + var x95 uint64 + x95, x94 = bits.Mul64(x92, 0xffffffff00000000) + var x96 uint64 + var x97 uint64 + x97, x96 = bits.Mul64(x92, 0xffffffffffffffff) + var x98 uint64 + var x99 uint64 + x99, x98 = bits.Mul64(x92, 0xbce6faada7179e84) + var x100 uint64 + var x101 uint64 + x101, x100 = bits.Mul64(x92, 0xf3b9cac2fc632551) + var x102 uint64 + var x103 uint64 + x102, x103 = bits.Add64(x101, x98, uint64(0x0)) + var x104 uint64 + var x105 uint64 + x104, x105 = bits.Add64(x99, x96, uint64(p256OrdUint1(x103))) + var x106 uint64 + var x107 uint64 + x106, x107 = bits.Add64(x97, x94, uint64(p256OrdUint1(x105))) + var x109 uint64 + _, x109 = bits.Add64(x86, x100, uint64(0x0)) + var x110 uint64 + var x111 uint64 + x110, x111 = bits.Add64(x88, x102, uint64(p256OrdUint1(x109))) + var x112 uint64 + var x113 uint64 + x112, x113 = bits.Add64(x90, x104, uint64(p256OrdUint1(x111))) + var x114 uint64 + var x115 uint64 + x114, x115 = bits.Add64((uint64(p256OrdUint1(x91)) + (uint64(p256OrdUint1(x85)) + (uint64(p256OrdUint1(x77)) + x65))), x106, uint64(p256OrdUint1(x113))) + x116 := (uint64(p256OrdUint1(x115)) + (uint64(p256OrdUint1(x107)) + x95)) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Sub64(x110, 0xf3b9cac2fc632551, uint64(0x0)) + var x119 uint64 + var x120 uint64 + x119, x120 = bits.Sub64(x112, 0xbce6faada7179e84, uint64(p256OrdUint1(x118))) + var x121 uint64 + var x122 uint64 + x121, x122 = bits.Sub64(x114, 0xffffffffffffffff, uint64(p256OrdUint1(x120))) + var x123 uint64 + var x124 uint64 + x123, x124 = bits.Sub64(x116, 0xffffffff00000000, uint64(p256OrdUint1(x122))) + var x126 uint64 + _, x126 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(p256OrdUint1(x124))) + var x127 uint64 + p256OrdCmovznzU64(&x127, p256OrdUint1(x126), x117, x110) + var x128 uint64 + p256OrdCmovznzU64(&x128, p256OrdUint1(x126), x119, x112) + var x129 uint64 + p256OrdCmovznzU64(&x129, p256OrdUint1(x126), x121, x114) + var x130 uint64 + p256OrdCmovznzU64(&x130, p256OrdUint1(x126), x123, x116) + out1[0] = x127 + out1[1] = x128 + out1[2] = x129 + out1[3] = x130 +} - var xOut [32]byte - p256OrdLittleToBig(&xOut, x) - return xOut[:], nil +// The function p256OrdToMontgomery translates a field element into the Montgomery domain. +// +// Preconditions: +// +// 0 ≤ eval arg1 < m +// +// Postconditions: +// +// eval (from_montgomery out1) mod m = eval arg1 mod m +// 0 ≤ eval out1 < m +func p256OrdToMontgomery(out1 *p256OrdMontgomeryDomainFieldElement, arg1 *p256OrdNonMontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, 0x66e12d94f3d95620) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, 0x2845b2392b6bec59) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, 0x4699799c49bd6fa6) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, 0x83244c95be79eea2) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(p256OrdUint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(p256OrdUint1(x16))) + var x19 uint64 + _, x19 = bits.Mul64(x11, 0xccd1c8aaee00bc4f) + var x21 uint64 + var x22 uint64 + x22, x21 = bits.Mul64(x19, 0xffffffff00000000) + var x23 uint64 + var x24 uint64 + x24, x23 = bits.Mul64(x19, 0xffffffffffffffff) + var x25 uint64 + var x26 uint64 + x26, x25 = bits.Mul64(x19, 0xbce6faada7179e84) + var x27 uint64 + var x28 uint64 + x28, x27 = bits.Mul64(x19, 0xf3b9cac2fc632551) + var x29 uint64 + var x30 uint64 + x29, x30 = bits.Add64(x28, x25, uint64(0x0)) + var x31 uint64 + var x32 uint64 + x31, x32 = bits.Add64(x26, x23, uint64(p256OrdUint1(x30))) + var x33 uint64 + var x34 uint64 + x33, x34 = bits.Add64(x24, x21, uint64(p256OrdUint1(x32))) + var x36 uint64 + _, x36 = bits.Add64(x11, x27, uint64(0x0)) + var x37 uint64 + var x38 uint64 + x37, x38 = bits.Add64(x13, x29, uint64(p256OrdUint1(x36))) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x15, x31, uint64(p256OrdUint1(x38))) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x17, x33, uint64(p256OrdUint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64((uint64(p256OrdUint1(x18)) + x6), (uint64(p256OrdUint1(x34)) + x22), uint64(p256OrdUint1(x42))) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(x1, 0x66e12d94f3d95620) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, 0x2845b2392b6bec59) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x1, 0x4699799c49bd6fa6) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x1, 0x83244c95be79eea2) + var x53 uint64 + var x54 uint64 + x53, x54 = bits.Add64(x52, x49, uint64(0x0)) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x50, x47, uint64(p256OrdUint1(x54))) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x48, x45, uint64(p256OrdUint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x37, x51, uint64(0x0)) + var x61 uint64 + var x62 uint64 + x61, x62 = bits.Add64(x39, x53, uint64(p256OrdUint1(x60))) + var x63 uint64 + var x64 uint64 + x63, x64 = bits.Add64(x41, x55, uint64(p256OrdUint1(x62))) + var x65 uint64 + var x66 uint64 + x65, x66 = bits.Add64(x43, x57, uint64(p256OrdUint1(x64))) + var x67 uint64 + _, x67 = bits.Mul64(x59, 0xccd1c8aaee00bc4f) + var x69 uint64 + var x70 uint64 + x70, x69 = bits.Mul64(x67, 0xffffffff00000000) + var x71 uint64 + var x72 uint64 + x72, x71 = bits.Mul64(x67, 0xffffffffffffffff) + var x73 uint64 + var x74 uint64 + x74, x73 = bits.Mul64(x67, 0xbce6faada7179e84) + var x75 uint64 + var x76 uint64 + x76, x75 = bits.Mul64(x67, 0xf3b9cac2fc632551) + var x77 uint64 + var x78 uint64 + x77, x78 = bits.Add64(x76, x73, uint64(0x0)) + var x79 uint64 + var x80 uint64 + x79, x80 = bits.Add64(x74, x71, uint64(p256OrdUint1(x78))) + var x81 uint64 + var x82 uint64 + x81, x82 = bits.Add64(x72, x69, uint64(p256OrdUint1(x80))) + var x84 uint64 + _, x84 = bits.Add64(x59, x75, uint64(0x0)) + var x85 uint64 + var x86 uint64 + x85, x86 = bits.Add64(x61, x77, uint64(p256OrdUint1(x84))) + var x87 uint64 + var x88 uint64 + x87, x88 = bits.Add64(x63, x79, uint64(p256OrdUint1(x86))) + var x89 uint64 + var x90 uint64 + x89, x90 = bits.Add64(x65, x81, uint64(p256OrdUint1(x88))) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(((uint64(p256OrdUint1(x66)) + uint64(p256OrdUint1(x44))) + (uint64(p256OrdUint1(x58)) + x46)), (uint64(p256OrdUint1(x82)) + x70), uint64(p256OrdUint1(x90))) + var x93 uint64 + var x94 uint64 + x94, x93 = bits.Mul64(x2, 0x66e12d94f3d95620) + var x95 uint64 + var x96 uint64 + x96, x95 = bits.Mul64(x2, 0x2845b2392b6bec59) + var x97 uint64 + var x98 uint64 + x98, x97 = bits.Mul64(x2, 0x4699799c49bd6fa6) + var x99 uint64 + var x100 uint64 + x100, x99 = bits.Mul64(x2, 0x83244c95be79eea2) + var x101 uint64 + var x102 uint64 + x101, x102 = bits.Add64(x100, x97, uint64(0x0)) + var x103 uint64 + var x104 uint64 + x103, x104 = bits.Add64(x98, x95, uint64(p256OrdUint1(x102))) + var x105 uint64 + var x106 uint64 + x105, x106 = bits.Add64(x96, x93, uint64(p256OrdUint1(x104))) + var x107 uint64 + var x108 uint64 + x107, x108 = bits.Add64(x85, x99, uint64(0x0)) + var x109 uint64 + var x110 uint64 + x109, x110 = bits.Add64(x87, x101, uint64(p256OrdUint1(x108))) + var x111 uint64 + var x112 uint64 + x111, x112 = bits.Add64(x89, x103, uint64(p256OrdUint1(x110))) + var x113 uint64 + var x114 uint64 + x113, x114 = bits.Add64(x91, x105, uint64(p256OrdUint1(x112))) + var x115 uint64 + _, x115 = bits.Mul64(x107, 0xccd1c8aaee00bc4f) + var x117 uint64 + var x118 uint64 + x118, x117 = bits.Mul64(x115, 0xffffffff00000000) + var x119 uint64 + var x120 uint64 + x120, x119 = bits.Mul64(x115, 0xffffffffffffffff) + var x121 uint64 + var x122 uint64 + x122, x121 = bits.Mul64(x115, 0xbce6faada7179e84) + var x123 uint64 + var x124 uint64 + x124, x123 = bits.Mul64(x115, 0xf3b9cac2fc632551) + var x125 uint64 + var x126 uint64 + x125, x126 = bits.Add64(x124, x121, uint64(0x0)) + var x127 uint64 + var x128 uint64 + x127, x128 = bits.Add64(x122, x119, uint64(p256OrdUint1(x126))) + var x129 uint64 + var x130 uint64 + x129, x130 = bits.Add64(x120, x117, uint64(p256OrdUint1(x128))) + var x132 uint64 + _, x132 = bits.Add64(x107, x123, uint64(0x0)) + var x133 uint64 + var x134 uint64 + x133, x134 = bits.Add64(x109, x125, uint64(p256OrdUint1(x132))) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x111, x127, uint64(p256OrdUint1(x134))) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x113, x129, uint64(p256OrdUint1(x136))) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(((uint64(p256OrdUint1(x114)) + uint64(p256OrdUint1(x92))) + (uint64(p256OrdUint1(x106)) + x94)), (uint64(p256OrdUint1(x130)) + x118), uint64(p256OrdUint1(x138))) + var x141 uint64 + var x142 uint64 + x142, x141 = bits.Mul64(x3, 0x66e12d94f3d95620) + var x143 uint64 + var x144 uint64 + x144, x143 = bits.Mul64(x3, 0x2845b2392b6bec59) + var x145 uint64 + var x146 uint64 + x146, x145 = bits.Mul64(x3, 0x4699799c49bd6fa6) + var x147 uint64 + var x148 uint64 + x148, x147 = bits.Mul64(x3, 0x83244c95be79eea2) + var x149 uint64 + var x150 uint64 + x149, x150 = bits.Add64(x148, x145, uint64(0x0)) + var x151 uint64 + var x152 uint64 + x151, x152 = bits.Add64(x146, x143, uint64(p256OrdUint1(x150))) + var x153 uint64 + var x154 uint64 + x153, x154 = bits.Add64(x144, x141, uint64(p256OrdUint1(x152))) + var x155 uint64 + var x156 uint64 + x155, x156 = bits.Add64(x133, x147, uint64(0x0)) + var x157 uint64 + var x158 uint64 + x157, x158 = bits.Add64(x135, x149, uint64(p256OrdUint1(x156))) + var x159 uint64 + var x160 uint64 + x159, x160 = bits.Add64(x137, x151, uint64(p256OrdUint1(x158))) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Add64(x139, x153, uint64(p256OrdUint1(x160))) + var x163 uint64 + _, x163 = bits.Mul64(x155, 0xccd1c8aaee00bc4f) + var x165 uint64 + var x166 uint64 + x166, x165 = bits.Mul64(x163, 0xffffffff00000000) + var x167 uint64 + var x168 uint64 + x168, x167 = bits.Mul64(x163, 0xffffffffffffffff) + var x169 uint64 + var x170 uint64 + x170, x169 = bits.Mul64(x163, 0xbce6faada7179e84) + var x171 uint64 + var x172 uint64 + x172, x171 = bits.Mul64(x163, 0xf3b9cac2fc632551) + var x173 uint64 + var x174 uint64 + x173, x174 = bits.Add64(x172, x169, uint64(0x0)) + var x175 uint64 + var x176 uint64 + x175, x176 = bits.Add64(x170, x167, uint64(p256OrdUint1(x174))) + var x177 uint64 + var x178 uint64 + x177, x178 = bits.Add64(x168, x165, uint64(p256OrdUint1(x176))) + var x180 uint64 + _, x180 = bits.Add64(x155, x171, uint64(0x0)) + var x181 uint64 + var x182 uint64 + x181, x182 = bits.Add64(x157, x173, uint64(p256OrdUint1(x180))) + var x183 uint64 + var x184 uint64 + x183, x184 = bits.Add64(x159, x175, uint64(p256OrdUint1(x182))) + var x185 uint64 + var x186 uint64 + x185, x186 = bits.Add64(x161, x177, uint64(p256OrdUint1(x184))) + var x187 uint64 + var x188 uint64 + x187, x188 = bits.Add64(((uint64(p256OrdUint1(x162)) + uint64(p256OrdUint1(x140))) + (uint64(p256OrdUint1(x154)) + x142)), (uint64(p256OrdUint1(x178)) + x166), uint64(p256OrdUint1(x186))) + var x189 uint64 + var x190 uint64 + x189, x190 = bits.Sub64(x181, 0xf3b9cac2fc632551, uint64(0x0)) + var x191 uint64 + var x192 uint64 + x191, x192 = bits.Sub64(x183, 0xbce6faada7179e84, uint64(p256OrdUint1(x190))) + var x193 uint64 + var x194 uint64 + x193, x194 = bits.Sub64(x185, 0xffffffffffffffff, uint64(p256OrdUint1(x192))) + var x195 uint64 + var x196 uint64 + x195, x196 = bits.Sub64(x187, 0xffffffff00000000, uint64(p256OrdUint1(x194))) + var x198 uint64 + _, x198 = bits.Sub64(uint64(p256OrdUint1(x188)), uint64(0x0), uint64(p256OrdUint1(x196))) + var x199 uint64 + p256OrdCmovznzU64(&x199, p256OrdUint1(x198), x189, x181) + var x200 uint64 + p256OrdCmovznzU64(&x200, p256OrdUint1(x198), x191, x183) + var x201 uint64 + p256OrdCmovznzU64(&x201, p256OrdUint1(x198), x193, x185) + var x202 uint64 + p256OrdCmovznzU64(&x202, p256OrdUint1(x198), x195, x187) + out1[0] = x199 + out1[1] = x200 + out1[2] = x201 + out1[3] = x202 +} + +// The function p256OrdCmovznzU64 is a single-word conditional move. +// +// Postconditions: +// +// out1 = (if arg1 = 0 then arg2 else arg3) +// +// Input Bounds: +// +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0xffffffffffffffff] +// arg3: [0x0 ~> 0xffffffffffffffff] +// +// Output Bounds: +// +// out1: [0x0 ~> 0xffffffffffffffff] +func p256OrdCmovznzU64(out1 *uint64, arg1 p256OrdUint1, arg2 uint64, arg3 uint64) { + x1 := (uint64(arg1) * 0xffffffffffffffff) + x2 := ((x1 & arg3) | ((^x1) & arg2)) + *out1 = x2 } diff --git a/src/crypto/internal/fips140/nistec/p256_ordinv_noasm.go b/src/crypto/internal/fips140/nistec/p256_ordinv_noasm.go deleted file mode 100644 index 9cbb1a89dbaf18..00000000000000 --- a/src/crypto/internal/fips140/nistec/p256_ordinv_noasm.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2022 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. - -//go:build (!amd64 && !arm64) || purego - -package nistec - -import "errors" - -func P256OrdInverse(k []byte) ([]byte, error) { - return nil, errors.New("unimplemented") -} diff --git a/src/crypto/internal/fips140test/nistec_ordinv_fips140v1.0_test.go b/src/crypto/internal/fips140test/nistec_ordinv_fips140v1.0_test.go new file mode 100644 index 00000000000000..06d057bdb84a32 --- /dev/null +++ b/src/crypto/internal/fips140test/nistec_ordinv_fips140v1.0_test.go @@ -0,0 +1,30 @@ +// Copyright 2026 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. + +//go:build fips140v1.0 || fips140v1.26 + +package fipstest + +import ( + "crypto/internal/fips140/nistec" + "internal/goarch" + "testing" +) + +// package nistec +// func P256OrdInverse(k []byte) ([]byte, error) + +func p256OrdInverse(t *testing.T, k *[4]uint64) { + input := limbsToBytes(*k) + out, err := nistec.P256OrdInverse(input) + if err != nil { + switch goarch.GOARCH { + case "amd64", "arm64": + t.Fatal(err) + default: + t.Skip("this GOARCH didn't have P256OrdInverse in v1.0/v1.26") + } + } + *k = bytesToLimbs(out) +} diff --git a/src/crypto/internal/fips140test/nistec_ordinv_fips140v1.28_test.go b/src/crypto/internal/fips140test/nistec_ordinv_fips140v1.28_test.go new file mode 100644 index 00000000000000..51e99fa6525e8e --- /dev/null +++ b/src/crypto/internal/fips140test/nistec_ordinv_fips140v1.28_test.go @@ -0,0 +1,16 @@ +// Copyright 2026 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. + +//go:build !(fips140v1.0 || fips140v1.26) + +package fipstest + +import ( + "crypto/internal/fips140/nistec" + "testing" +) + +func p256OrdInverse(t *testing.T, k *[4]uint64) { + nistec.P256OrdInverse(k) +} diff --git a/src/crypto/internal/fips140test/nistec_ordinv_test.go b/src/crypto/internal/fips140test/nistec_ordinv_test.go index 5eeb3d25268efb..b3eeeb324413e2 100644 --- a/src/crypto/internal/fips140test/nistec_ordinv_test.go +++ b/src/crypto/internal/fips140test/nistec_ordinv_test.go @@ -2,80 +2,83 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (amd64 || arm64) && !purego - package fipstest import ( "bytes" "crypto/elliptic" - "crypto/internal/fips140/nistec" + "internal/byteorder" "math/big" "testing" ) +func bytesToLimbs(b []byte) [4]uint64 { + var l [4]uint64 + l[0] = byteorder.BEUint64(b[24:]) + l[1] = byteorder.BEUint64(b[16:]) + l[2] = byteorder.BEUint64(b[8:]) + l[3] = byteorder.BEUint64(b[:]) + return l +} + +func limbsToBytes(l [4]uint64) []byte { + b := make([]byte, 32) + byteorder.BEPutUint64(b[24:], l[0]) + byteorder.BEPutUint64(b[16:], l[1]) + byteorder.BEPutUint64(b[8:], l[2]) + byteorder.BEPutUint64(b[:], l[3]) + return b +} + func TestP256OrdInverse(t *testing.T) { N := elliptic.P256().Params().N // inv(0) is expected to be 0. zero := make([]byte, 32) - out, err := nistec.P256OrdInverse(zero) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(out, zero) { + k := bytesToLimbs(zero) + p256OrdInverse(t, &k) + if !bytes.Equal(limbsToBytes(k), zero) { t.Error("unexpected output for inv(0)") } // inv(N) is also 0 mod N. input := make([]byte, 32) N.FillBytes(input) - out, err = nistec.P256OrdInverse(input) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(out, zero) { + k = bytesToLimbs(input) + p256OrdInverse(t, &k) + if !bytes.Equal(limbsToBytes(k), zero) { t.Error("unexpected output for inv(N)") } - if !bytes.Equal(input, N.Bytes()) { - t.Error("input was modified") - } // Check inv(1) and inv(N+1) against math/big exp := new(big.Int).ModInverse(big.NewInt(1), N).FillBytes(make([]byte, 32)) big.NewInt(1).FillBytes(input) - out, err = nistec.P256OrdInverse(input) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(out, exp) { + k = bytesToLimbs(input) + p256OrdInverse(t, &k) + if !bytes.Equal(limbsToBytes(k), exp) { t.Error("unexpected output for inv(1)") } + new(big.Int).Add(N, big.NewInt(1)).FillBytes(input) - out, err = nistec.P256OrdInverse(input) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(out, exp) { + k = bytesToLimbs(input) + p256OrdInverse(t, &k) + if !bytes.Equal(limbsToBytes(k), exp) { t.Error("unexpected output for inv(N+1)") } // Check inv(20) and inv(N+20) against math/big exp = new(big.Int).ModInverse(big.NewInt(20), N).FillBytes(make([]byte, 32)) big.NewInt(20).FillBytes(input) - out, err = nistec.P256OrdInverse(input) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(out, exp) { + k = bytesToLimbs(input) + p256OrdInverse(t, &k) + if !bytes.Equal(limbsToBytes(k), exp) { t.Error("unexpected output for inv(20)") } + new(big.Int).Add(N, big.NewInt(20)).FillBytes(input) - out, err = nistec.P256OrdInverse(input) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(out, exp) { + k = bytesToLimbs(input) + p256OrdInverse(t, &k) + if !bytes.Equal(limbsToBytes(k), exp) { t.Error("unexpected output for inv(N+20)") } @@ -84,11 +87,9 @@ func TestP256OrdInverse(t *testing.T) { bigInput.Sub(bigInput, big.NewInt(1)) exp = new(big.Int).ModInverse(bigInput, N).FillBytes(make([]byte, 32)) bigInput.FillBytes(input) - out, err = nistec.P256OrdInverse(input) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(out, exp) { + k = bytesToLimbs(input) + p256OrdInverse(t, &k) + if !bytes.Equal(limbsToBytes(k), exp) { t.Error("unexpected output for inv(2^256-1)") } } From e4e6887ceefdd516fae86aa43b3410a2a0398394 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 25 Feb 2026 14:02:16 +0100 Subject: [PATCH 16/18] crypto/internal/fips140/nistec: mechanically improve P-256 scalar fiat code Made the following changes: * gofmt -r "(a) -> a" * "type p256OrdUint1 = uint64" * go run github.com/mdempsky/unconvert@latest -apply * gofmt -r "uint64(0x0) -> 0" * sed -E '/^\tvar x[0-9]+ uint64$/d; s/^\t(_|x[0-9]+)(, x[0-9]+)? = /\t\1\2 := /' * renamed p256OrdMontgomeryDomainFieldElement to p256OrdMontElement * replaced p256OrdNonMontgomeryDomainFieldElement with p256OrdElement Change-Id: I996f76aa429e0c4ca049ee76a506e09d6a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/749140 Auto-Submit: Filippo Valsorda Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Neal Patel Reviewed-by: Neal Patel --- .../internal/fips140/nistec/p256_ordinv.go | 1528 +++++------------ 1 file changed, 420 insertions(+), 1108 deletions(-) diff --git a/src/crypto/internal/fips140/nistec/p256_ordinv.go b/src/crypto/internal/fips140/nistec/p256_ordinv.go index 6404e0bac62215..d1e58b202be003 100644 --- a/src/crypto/internal/fips140/nistec/p256_ordinv.go +++ b/src/crypto/internal/fips140/nistec/p256_ordinv.go @@ -14,17 +14,17 @@ func P256OrdInverse(k *[4]uint64) { // // The sequence of 38 multiplications and 254 squarings is derived from // https://briansmith.org/ecc-inversion-addition-chains-01#p256_scalar_inversion - _1 := new(p256OrdMontgomeryDomainFieldElement) - _11 := new(p256OrdMontgomeryDomainFieldElement) - _101 := new(p256OrdMontgomeryDomainFieldElement) - _111 := new(p256OrdMontgomeryDomainFieldElement) - _1111 := new(p256OrdMontgomeryDomainFieldElement) - _10101 := new(p256OrdMontgomeryDomainFieldElement) - _101111 := new(p256OrdMontgomeryDomainFieldElement) - x := new(p256OrdMontgomeryDomainFieldElement) - t := new(p256OrdMontgomeryDomainFieldElement) + _1 := new(p256OrdMontElement) + _11 := new(p256OrdMontElement) + _101 := new(p256OrdMontElement) + _111 := new(p256OrdMontElement) + _1111 := new(p256OrdMontElement) + _10101 := new(p256OrdMontElement) + _101111 := new(p256OrdMontElement) + x := new(p256OrdMontElement) + t := new(p256OrdMontElement) - j := (*p256OrdNonMontgomeryDomainFieldElement)(k) + j := (*p256OrdElement)(k) p256OrdToMontgomery(_1, j) // _1 p256OrdSqr(x, _1, 1) // _10 p256OrdMul(_11, x, _1) // _11 @@ -56,7 +56,7 @@ func P256OrdInverse(k *[4]uint64) { 6, 2, 5, 6, 5, 4, 5, 5, 3, 10, 2, 5, 5, 3, 7, 6} - muls := []*p256OrdMontgomeryDomainFieldElement{ + muls := []*p256OrdMontElement{ _101111, _111, _11, _1111, _10101, _101, _101, _101, _111, _101111, _1111, _1, _1, _1111, _111, @@ -71,7 +71,7 @@ func P256OrdInverse(k *[4]uint64) { p256OrdFromMontgomery(j, x) } -func p256OrdSqr(out1, arg1 *p256OrdMontgomeryDomainFieldElement, n int) { +func p256OrdSqr(out1, arg1 *p256OrdMontElement, n int) { p256OrdSquare(out1, arg1) for range n - 1 { p256OrdSquare(out1, out1) @@ -148,18 +148,12 @@ func p256OrdSqr(out1, arg1 *p256OrdMontgomeryDomainFieldElement, n int) { // // if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 -type p256OrdUint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 -type p256OrdInt1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 +type p256OrdUint1 = uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 -// The type p256OrdMontgomeryDomainFieldElement is a field element in the Montgomery domain. +// The type p256OrdMontElement is a field element in the Montgomery domain. // // Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -type p256OrdMontgomeryDomainFieldElement [4]uint64 - -// The type p256OrdNonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain. -// -// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -type p256OrdNonMontgomeryDomainFieldElement [4]uint64 +type p256OrdMontElement [4]uint64 // The function p256OrdMul multiplies two field elements in the Montgomery domain. // @@ -172,321 +166,130 @@ type p256OrdNonMontgomeryDomainFieldElement [4]uint64 // // eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m // 0 ≤ eval out1 < m -func p256OrdMul(out1 *p256OrdMontgomeryDomainFieldElement, arg1 *p256OrdMontgomeryDomainFieldElement, arg2 *p256OrdMontgomeryDomainFieldElement) { +func p256OrdMul(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, arg2 *p256OrdMontElement) { x1 := arg1[1] x2 := arg1[2] x3 := arg1[3] x4 := arg1[0] - var x5 uint64 - var x6 uint64 - x6, x5 = bits.Mul64(x4, arg2[3]) - var x7 uint64 - var x8 uint64 - x8, x7 = bits.Mul64(x4, arg2[2]) - var x9 uint64 - var x10 uint64 - x10, x9 = bits.Mul64(x4, arg2[1]) - var x11 uint64 - var x12 uint64 - x12, x11 = bits.Mul64(x4, arg2[0]) - var x13 uint64 - var x14 uint64 - x13, x14 = bits.Add64(x12, x9, uint64(0x0)) - var x15 uint64 - var x16 uint64 - x15, x16 = bits.Add64(x10, x7, uint64(p256OrdUint1(x14))) - var x17 uint64 - var x18 uint64 - x17, x18 = bits.Add64(x8, x5, uint64(p256OrdUint1(x16))) - x19 := (uint64(p256OrdUint1(x18)) + x6) - var x20 uint64 - _, x20 = bits.Mul64(x11, 0xccd1c8aaee00bc4f) - var x22 uint64 - var x23 uint64 - x23, x22 = bits.Mul64(x20, 0xffffffff00000000) - var x24 uint64 - var x25 uint64 - x25, x24 = bits.Mul64(x20, 0xffffffffffffffff) - var x26 uint64 - var x27 uint64 - x27, x26 = bits.Mul64(x20, 0xbce6faada7179e84) - var x28 uint64 - var x29 uint64 - x29, x28 = bits.Mul64(x20, 0xf3b9cac2fc632551) - var x30 uint64 - var x31 uint64 - x30, x31 = bits.Add64(x29, x26, uint64(0x0)) - var x32 uint64 - var x33 uint64 - x32, x33 = bits.Add64(x27, x24, uint64(p256OrdUint1(x31))) - var x34 uint64 - var x35 uint64 - x34, x35 = bits.Add64(x25, x22, uint64(p256OrdUint1(x33))) - x36 := (uint64(p256OrdUint1(x35)) + x23) - var x38 uint64 - _, x38 = bits.Add64(x11, x28, uint64(0x0)) - var x39 uint64 - var x40 uint64 - x39, x40 = bits.Add64(x13, x30, uint64(p256OrdUint1(x38))) - var x41 uint64 - var x42 uint64 - x41, x42 = bits.Add64(x15, x32, uint64(p256OrdUint1(x40))) - var x43 uint64 - var x44 uint64 - x43, x44 = bits.Add64(x17, x34, uint64(p256OrdUint1(x42))) - var x45 uint64 - var x46 uint64 - x45, x46 = bits.Add64(x19, x36, uint64(p256OrdUint1(x44))) - var x47 uint64 - var x48 uint64 - x48, x47 = bits.Mul64(x1, arg2[3]) - var x49 uint64 - var x50 uint64 - x50, x49 = bits.Mul64(x1, arg2[2]) - var x51 uint64 - var x52 uint64 - x52, x51 = bits.Mul64(x1, arg2[1]) - var x53 uint64 - var x54 uint64 - x54, x53 = bits.Mul64(x1, arg2[0]) - var x55 uint64 - var x56 uint64 - x55, x56 = bits.Add64(x54, x51, uint64(0x0)) - var x57 uint64 - var x58 uint64 - x57, x58 = bits.Add64(x52, x49, uint64(p256OrdUint1(x56))) - var x59 uint64 - var x60 uint64 - x59, x60 = bits.Add64(x50, x47, uint64(p256OrdUint1(x58))) - x61 := (uint64(p256OrdUint1(x60)) + x48) - var x62 uint64 - var x63 uint64 - x62, x63 = bits.Add64(x39, x53, uint64(0x0)) - var x64 uint64 - var x65 uint64 - x64, x65 = bits.Add64(x41, x55, uint64(p256OrdUint1(x63))) - var x66 uint64 - var x67 uint64 - x66, x67 = bits.Add64(x43, x57, uint64(p256OrdUint1(x65))) - var x68 uint64 - var x69 uint64 - x68, x69 = bits.Add64(x45, x59, uint64(p256OrdUint1(x67))) - var x70 uint64 - var x71 uint64 - x70, x71 = bits.Add64(uint64(p256OrdUint1(x46)), x61, uint64(p256OrdUint1(x69))) - var x72 uint64 - _, x72 = bits.Mul64(x62, 0xccd1c8aaee00bc4f) - var x74 uint64 - var x75 uint64 - x75, x74 = bits.Mul64(x72, 0xffffffff00000000) - var x76 uint64 - var x77 uint64 - x77, x76 = bits.Mul64(x72, 0xffffffffffffffff) - var x78 uint64 - var x79 uint64 - x79, x78 = bits.Mul64(x72, 0xbce6faada7179e84) - var x80 uint64 - var x81 uint64 - x81, x80 = bits.Mul64(x72, 0xf3b9cac2fc632551) - var x82 uint64 - var x83 uint64 - x82, x83 = bits.Add64(x81, x78, uint64(0x0)) - var x84 uint64 - var x85 uint64 - x84, x85 = bits.Add64(x79, x76, uint64(p256OrdUint1(x83))) - var x86 uint64 - var x87 uint64 - x86, x87 = bits.Add64(x77, x74, uint64(p256OrdUint1(x85))) - x88 := (uint64(p256OrdUint1(x87)) + x75) - var x90 uint64 - _, x90 = bits.Add64(x62, x80, uint64(0x0)) - var x91 uint64 - var x92 uint64 - x91, x92 = bits.Add64(x64, x82, uint64(p256OrdUint1(x90))) - var x93 uint64 - var x94 uint64 - x93, x94 = bits.Add64(x66, x84, uint64(p256OrdUint1(x92))) - var x95 uint64 - var x96 uint64 - x95, x96 = bits.Add64(x68, x86, uint64(p256OrdUint1(x94))) - var x97 uint64 - var x98 uint64 - x97, x98 = bits.Add64(x70, x88, uint64(p256OrdUint1(x96))) - x99 := (uint64(p256OrdUint1(x98)) + uint64(p256OrdUint1(x71))) - var x100 uint64 - var x101 uint64 - x101, x100 = bits.Mul64(x2, arg2[3]) - var x102 uint64 - var x103 uint64 - x103, x102 = bits.Mul64(x2, arg2[2]) - var x104 uint64 - var x105 uint64 - x105, x104 = bits.Mul64(x2, arg2[1]) - var x106 uint64 - var x107 uint64 - x107, x106 = bits.Mul64(x2, arg2[0]) - var x108 uint64 - var x109 uint64 - x108, x109 = bits.Add64(x107, x104, uint64(0x0)) - var x110 uint64 - var x111 uint64 - x110, x111 = bits.Add64(x105, x102, uint64(p256OrdUint1(x109))) - var x112 uint64 - var x113 uint64 - x112, x113 = bits.Add64(x103, x100, uint64(p256OrdUint1(x111))) - x114 := (uint64(p256OrdUint1(x113)) + x101) - var x115 uint64 - var x116 uint64 - x115, x116 = bits.Add64(x91, x106, uint64(0x0)) - var x117 uint64 - var x118 uint64 - x117, x118 = bits.Add64(x93, x108, uint64(p256OrdUint1(x116))) - var x119 uint64 - var x120 uint64 - x119, x120 = bits.Add64(x95, x110, uint64(p256OrdUint1(x118))) - var x121 uint64 - var x122 uint64 - x121, x122 = bits.Add64(x97, x112, uint64(p256OrdUint1(x120))) - var x123 uint64 - var x124 uint64 - x123, x124 = bits.Add64(x99, x114, uint64(p256OrdUint1(x122))) - var x125 uint64 - _, x125 = bits.Mul64(x115, 0xccd1c8aaee00bc4f) - var x127 uint64 - var x128 uint64 - x128, x127 = bits.Mul64(x125, 0xffffffff00000000) - var x129 uint64 - var x130 uint64 - x130, x129 = bits.Mul64(x125, 0xffffffffffffffff) - var x131 uint64 - var x132 uint64 - x132, x131 = bits.Mul64(x125, 0xbce6faada7179e84) - var x133 uint64 - var x134 uint64 - x134, x133 = bits.Mul64(x125, 0xf3b9cac2fc632551) - var x135 uint64 - var x136 uint64 - x135, x136 = bits.Add64(x134, x131, uint64(0x0)) - var x137 uint64 - var x138 uint64 - x137, x138 = bits.Add64(x132, x129, uint64(p256OrdUint1(x136))) - var x139 uint64 - var x140 uint64 - x139, x140 = bits.Add64(x130, x127, uint64(p256OrdUint1(x138))) - x141 := (uint64(p256OrdUint1(x140)) + x128) - var x143 uint64 - _, x143 = bits.Add64(x115, x133, uint64(0x0)) - var x144 uint64 - var x145 uint64 - x144, x145 = bits.Add64(x117, x135, uint64(p256OrdUint1(x143))) - var x146 uint64 - var x147 uint64 - x146, x147 = bits.Add64(x119, x137, uint64(p256OrdUint1(x145))) - var x148 uint64 - var x149 uint64 - x148, x149 = bits.Add64(x121, x139, uint64(p256OrdUint1(x147))) - var x150 uint64 - var x151 uint64 - x150, x151 = bits.Add64(x123, x141, uint64(p256OrdUint1(x149))) - x152 := (uint64(p256OrdUint1(x151)) + uint64(p256OrdUint1(x124))) - var x153 uint64 - var x154 uint64 - x154, x153 = bits.Mul64(x3, arg2[3]) - var x155 uint64 - var x156 uint64 - x156, x155 = bits.Mul64(x3, arg2[2]) - var x157 uint64 - var x158 uint64 - x158, x157 = bits.Mul64(x3, arg2[1]) - var x159 uint64 - var x160 uint64 - x160, x159 = bits.Mul64(x3, arg2[0]) - var x161 uint64 - var x162 uint64 - x161, x162 = bits.Add64(x160, x157, uint64(0x0)) - var x163 uint64 - var x164 uint64 - x163, x164 = bits.Add64(x158, x155, uint64(p256OrdUint1(x162))) - var x165 uint64 - var x166 uint64 - x165, x166 = bits.Add64(x156, x153, uint64(p256OrdUint1(x164))) - x167 := (uint64(p256OrdUint1(x166)) + x154) - var x168 uint64 - var x169 uint64 - x168, x169 = bits.Add64(x144, x159, uint64(0x0)) - var x170 uint64 - var x171 uint64 - x170, x171 = bits.Add64(x146, x161, uint64(p256OrdUint1(x169))) - var x172 uint64 - var x173 uint64 - x172, x173 = bits.Add64(x148, x163, uint64(p256OrdUint1(x171))) - var x174 uint64 - var x175 uint64 - x174, x175 = bits.Add64(x150, x165, uint64(p256OrdUint1(x173))) - var x176 uint64 - var x177 uint64 - x176, x177 = bits.Add64(x152, x167, uint64(p256OrdUint1(x175))) - var x178 uint64 - _, x178 = bits.Mul64(x168, 0xccd1c8aaee00bc4f) - var x180 uint64 - var x181 uint64 - x181, x180 = bits.Mul64(x178, 0xffffffff00000000) - var x182 uint64 - var x183 uint64 - x183, x182 = bits.Mul64(x178, 0xffffffffffffffff) - var x184 uint64 - var x185 uint64 - x185, x184 = bits.Mul64(x178, 0xbce6faada7179e84) - var x186 uint64 - var x187 uint64 - x187, x186 = bits.Mul64(x178, 0xf3b9cac2fc632551) - var x188 uint64 - var x189 uint64 - x188, x189 = bits.Add64(x187, x184, uint64(0x0)) - var x190 uint64 - var x191 uint64 - x190, x191 = bits.Add64(x185, x182, uint64(p256OrdUint1(x189))) - var x192 uint64 - var x193 uint64 - x192, x193 = bits.Add64(x183, x180, uint64(p256OrdUint1(x191))) - x194 := (uint64(p256OrdUint1(x193)) + x181) - var x196 uint64 - _, x196 = bits.Add64(x168, x186, uint64(0x0)) - var x197 uint64 - var x198 uint64 - x197, x198 = bits.Add64(x170, x188, uint64(p256OrdUint1(x196))) - var x199 uint64 - var x200 uint64 - x199, x200 = bits.Add64(x172, x190, uint64(p256OrdUint1(x198))) - var x201 uint64 - var x202 uint64 - x201, x202 = bits.Add64(x174, x192, uint64(p256OrdUint1(x200))) - var x203 uint64 - var x204 uint64 - x203, x204 = bits.Add64(x176, x194, uint64(p256OrdUint1(x202))) - x205 := (uint64(p256OrdUint1(x204)) + uint64(p256OrdUint1(x177))) - var x206 uint64 - var x207 uint64 - x206, x207 = bits.Sub64(x197, 0xf3b9cac2fc632551, uint64(0x0)) - var x208 uint64 - var x209 uint64 - x208, x209 = bits.Sub64(x199, 0xbce6faada7179e84, uint64(p256OrdUint1(x207))) - var x210 uint64 - var x211 uint64 - x210, x211 = bits.Sub64(x201, 0xffffffffffffffff, uint64(p256OrdUint1(x209))) - var x212 uint64 - var x213 uint64 - x212, x213 = bits.Sub64(x203, 0xffffffff00000000, uint64(p256OrdUint1(x211))) - var x215 uint64 - _, x215 = bits.Sub64(x205, uint64(0x0), uint64(p256OrdUint1(x213))) + x6, x5 := bits.Mul64(x4, arg2[3]) + x8, x7 := bits.Mul64(x4, arg2[2]) + x10, x9 := bits.Mul64(x4, arg2[1]) + x12, x11 := bits.Mul64(x4, arg2[0]) + x13, x14 := bits.Add64(x12, x9, 0) + x15, x16 := bits.Add64(x10, x7, x14) + x17, x18 := bits.Add64(x8, x5, x16) + x19 := x18 + x6 + _, x20 := bits.Mul64(x11, 0xccd1c8aaee00bc4f) + x23, x22 := bits.Mul64(x20, 0xffffffff00000000) + x25, x24 := bits.Mul64(x20, 0xffffffffffffffff) + x27, x26 := bits.Mul64(x20, 0xbce6faada7179e84) + x29, x28 := bits.Mul64(x20, 0xf3b9cac2fc632551) + x30, x31 := bits.Add64(x29, x26, 0) + x32, x33 := bits.Add64(x27, x24, x31) + x34, x35 := bits.Add64(x25, x22, x33) + x36 := x35 + x23 + _, x38 := bits.Add64(x11, x28, 0) + x39, x40 := bits.Add64(x13, x30, x38) + x41, x42 := bits.Add64(x15, x32, x40) + x43, x44 := bits.Add64(x17, x34, x42) + x45, x46 := bits.Add64(x19, x36, x44) + x48, x47 := bits.Mul64(x1, arg2[3]) + x50, x49 := bits.Mul64(x1, arg2[2]) + x52, x51 := bits.Mul64(x1, arg2[1]) + x54, x53 := bits.Mul64(x1, arg2[0]) + x55, x56 := bits.Add64(x54, x51, 0) + x57, x58 := bits.Add64(x52, x49, x56) + x59, x60 := bits.Add64(x50, x47, x58) + x61 := x60 + x48 + x62, x63 := bits.Add64(x39, x53, 0) + x64, x65 := bits.Add64(x41, x55, x63) + x66, x67 := bits.Add64(x43, x57, x65) + x68, x69 := bits.Add64(x45, x59, x67) + x70, x71 := bits.Add64(x46, x61, x69) + _, x72 := bits.Mul64(x62, 0xccd1c8aaee00bc4f) + x75, x74 := bits.Mul64(x72, 0xffffffff00000000) + x77, x76 := bits.Mul64(x72, 0xffffffffffffffff) + x79, x78 := bits.Mul64(x72, 0xbce6faada7179e84) + x81, x80 := bits.Mul64(x72, 0xf3b9cac2fc632551) + x82, x83 := bits.Add64(x81, x78, 0) + x84, x85 := bits.Add64(x79, x76, x83) + x86, x87 := bits.Add64(x77, x74, x85) + x88 := x87 + x75 + _, x90 := bits.Add64(x62, x80, 0) + x91, x92 := bits.Add64(x64, x82, x90) + x93, x94 := bits.Add64(x66, x84, x92) + x95, x96 := bits.Add64(x68, x86, x94) + x97, x98 := bits.Add64(x70, x88, x96) + x99 := x98 + x71 + x101, x100 := bits.Mul64(x2, arg2[3]) + x103, x102 := bits.Mul64(x2, arg2[2]) + x105, x104 := bits.Mul64(x2, arg2[1]) + x107, x106 := bits.Mul64(x2, arg2[0]) + x108, x109 := bits.Add64(x107, x104, 0) + x110, x111 := bits.Add64(x105, x102, x109) + x112, x113 := bits.Add64(x103, x100, x111) + x114 := x113 + x101 + x115, x116 := bits.Add64(x91, x106, 0) + x117, x118 := bits.Add64(x93, x108, x116) + x119, x120 := bits.Add64(x95, x110, x118) + x121, x122 := bits.Add64(x97, x112, x120) + x123, x124 := bits.Add64(x99, x114, x122) + _, x125 := bits.Mul64(x115, 0xccd1c8aaee00bc4f) + x128, x127 := bits.Mul64(x125, 0xffffffff00000000) + x130, x129 := bits.Mul64(x125, 0xffffffffffffffff) + x132, x131 := bits.Mul64(x125, 0xbce6faada7179e84) + x134, x133 := bits.Mul64(x125, 0xf3b9cac2fc632551) + x135, x136 := bits.Add64(x134, x131, 0) + x137, x138 := bits.Add64(x132, x129, x136) + x139, x140 := bits.Add64(x130, x127, x138) + x141 := x140 + x128 + _, x143 := bits.Add64(x115, x133, 0) + x144, x145 := bits.Add64(x117, x135, x143) + x146, x147 := bits.Add64(x119, x137, x145) + x148, x149 := bits.Add64(x121, x139, x147) + x150, x151 := bits.Add64(x123, x141, x149) + x152 := x151 + x124 + x154, x153 := bits.Mul64(x3, arg2[3]) + x156, x155 := bits.Mul64(x3, arg2[2]) + x158, x157 := bits.Mul64(x3, arg2[1]) + x160, x159 := bits.Mul64(x3, arg2[0]) + x161, x162 := bits.Add64(x160, x157, 0) + x163, x164 := bits.Add64(x158, x155, x162) + x165, x166 := bits.Add64(x156, x153, x164) + x167 := x166 + x154 + x168, x169 := bits.Add64(x144, x159, 0) + x170, x171 := bits.Add64(x146, x161, x169) + x172, x173 := bits.Add64(x148, x163, x171) + x174, x175 := bits.Add64(x150, x165, x173) + x176, x177 := bits.Add64(x152, x167, x175) + _, x178 := bits.Mul64(x168, 0xccd1c8aaee00bc4f) + x181, x180 := bits.Mul64(x178, 0xffffffff00000000) + x183, x182 := bits.Mul64(x178, 0xffffffffffffffff) + x185, x184 := bits.Mul64(x178, 0xbce6faada7179e84) + x187, x186 := bits.Mul64(x178, 0xf3b9cac2fc632551) + x188, x189 := bits.Add64(x187, x184, 0) + x190, x191 := bits.Add64(x185, x182, x189) + x192, x193 := bits.Add64(x183, x180, x191) + x194 := x193 + x181 + _, x196 := bits.Add64(x168, x186, 0) + x197, x198 := bits.Add64(x170, x188, x196) + x199, x200 := bits.Add64(x172, x190, x198) + x201, x202 := bits.Add64(x174, x192, x200) + x203, x204 := bits.Add64(x176, x194, x202) + x205 := x204 + x177 + x206, x207 := bits.Sub64(x197, 0xf3b9cac2fc632551, 0) + x208, x209 := bits.Sub64(x199, 0xbce6faada7179e84, x207) + x210, x211 := bits.Sub64(x201, 0xffffffffffffffff, x209) + x212, x213 := bits.Sub64(x203, 0xffffffff00000000, x211) + _, x215 := bits.Sub64(x205, 0, x213) var x216 uint64 - p256OrdCmovznzU64(&x216, p256OrdUint1(x215), x206, x197) + p256OrdCmovznzU64(&x216, x215, x206, x197) var x217 uint64 - p256OrdCmovznzU64(&x217, p256OrdUint1(x215), x208, x199) + p256OrdCmovznzU64(&x217, x215, x208, x199) var x218 uint64 - p256OrdCmovznzU64(&x218, p256OrdUint1(x215), x210, x201) + p256OrdCmovznzU64(&x218, x215, x210, x201) var x219 uint64 - p256OrdCmovznzU64(&x219, p256OrdUint1(x215), x212, x203) + p256OrdCmovznzU64(&x219, x215, x212, x203) out1[0] = x216 out1[1] = x217 out1[2] = x218 @@ -503,321 +306,130 @@ func p256OrdMul(out1 *p256OrdMontgomeryDomainFieldElement, arg1 *p256OrdMontgome // // eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m // 0 ≤ eval out1 < m -func p256OrdSquare(out1 *p256OrdMontgomeryDomainFieldElement, arg1 *p256OrdMontgomeryDomainFieldElement) { +func p256OrdSquare(out1 *p256OrdMontElement, arg1 *p256OrdMontElement) { x1 := arg1[1] x2 := arg1[2] x3 := arg1[3] x4 := arg1[0] - var x5 uint64 - var x6 uint64 - x6, x5 = bits.Mul64(x4, arg1[3]) - var x7 uint64 - var x8 uint64 - x8, x7 = bits.Mul64(x4, arg1[2]) - var x9 uint64 - var x10 uint64 - x10, x9 = bits.Mul64(x4, arg1[1]) - var x11 uint64 - var x12 uint64 - x12, x11 = bits.Mul64(x4, arg1[0]) - var x13 uint64 - var x14 uint64 - x13, x14 = bits.Add64(x12, x9, uint64(0x0)) - var x15 uint64 - var x16 uint64 - x15, x16 = bits.Add64(x10, x7, uint64(p256OrdUint1(x14))) - var x17 uint64 - var x18 uint64 - x17, x18 = bits.Add64(x8, x5, uint64(p256OrdUint1(x16))) - x19 := (uint64(p256OrdUint1(x18)) + x6) - var x20 uint64 - _, x20 = bits.Mul64(x11, 0xccd1c8aaee00bc4f) - var x22 uint64 - var x23 uint64 - x23, x22 = bits.Mul64(x20, 0xffffffff00000000) - var x24 uint64 - var x25 uint64 - x25, x24 = bits.Mul64(x20, 0xffffffffffffffff) - var x26 uint64 - var x27 uint64 - x27, x26 = bits.Mul64(x20, 0xbce6faada7179e84) - var x28 uint64 - var x29 uint64 - x29, x28 = bits.Mul64(x20, 0xf3b9cac2fc632551) - var x30 uint64 - var x31 uint64 - x30, x31 = bits.Add64(x29, x26, uint64(0x0)) - var x32 uint64 - var x33 uint64 - x32, x33 = bits.Add64(x27, x24, uint64(p256OrdUint1(x31))) - var x34 uint64 - var x35 uint64 - x34, x35 = bits.Add64(x25, x22, uint64(p256OrdUint1(x33))) - x36 := (uint64(p256OrdUint1(x35)) + x23) - var x38 uint64 - _, x38 = bits.Add64(x11, x28, uint64(0x0)) - var x39 uint64 - var x40 uint64 - x39, x40 = bits.Add64(x13, x30, uint64(p256OrdUint1(x38))) - var x41 uint64 - var x42 uint64 - x41, x42 = bits.Add64(x15, x32, uint64(p256OrdUint1(x40))) - var x43 uint64 - var x44 uint64 - x43, x44 = bits.Add64(x17, x34, uint64(p256OrdUint1(x42))) - var x45 uint64 - var x46 uint64 - x45, x46 = bits.Add64(x19, x36, uint64(p256OrdUint1(x44))) - var x47 uint64 - var x48 uint64 - x48, x47 = bits.Mul64(x1, arg1[3]) - var x49 uint64 - var x50 uint64 - x50, x49 = bits.Mul64(x1, arg1[2]) - var x51 uint64 - var x52 uint64 - x52, x51 = bits.Mul64(x1, arg1[1]) - var x53 uint64 - var x54 uint64 - x54, x53 = bits.Mul64(x1, arg1[0]) - var x55 uint64 - var x56 uint64 - x55, x56 = bits.Add64(x54, x51, uint64(0x0)) - var x57 uint64 - var x58 uint64 - x57, x58 = bits.Add64(x52, x49, uint64(p256OrdUint1(x56))) - var x59 uint64 - var x60 uint64 - x59, x60 = bits.Add64(x50, x47, uint64(p256OrdUint1(x58))) - x61 := (uint64(p256OrdUint1(x60)) + x48) - var x62 uint64 - var x63 uint64 - x62, x63 = bits.Add64(x39, x53, uint64(0x0)) - var x64 uint64 - var x65 uint64 - x64, x65 = bits.Add64(x41, x55, uint64(p256OrdUint1(x63))) - var x66 uint64 - var x67 uint64 - x66, x67 = bits.Add64(x43, x57, uint64(p256OrdUint1(x65))) - var x68 uint64 - var x69 uint64 - x68, x69 = bits.Add64(x45, x59, uint64(p256OrdUint1(x67))) - var x70 uint64 - var x71 uint64 - x70, x71 = bits.Add64(uint64(p256OrdUint1(x46)), x61, uint64(p256OrdUint1(x69))) - var x72 uint64 - _, x72 = bits.Mul64(x62, 0xccd1c8aaee00bc4f) - var x74 uint64 - var x75 uint64 - x75, x74 = bits.Mul64(x72, 0xffffffff00000000) - var x76 uint64 - var x77 uint64 - x77, x76 = bits.Mul64(x72, 0xffffffffffffffff) - var x78 uint64 - var x79 uint64 - x79, x78 = bits.Mul64(x72, 0xbce6faada7179e84) - var x80 uint64 - var x81 uint64 - x81, x80 = bits.Mul64(x72, 0xf3b9cac2fc632551) - var x82 uint64 - var x83 uint64 - x82, x83 = bits.Add64(x81, x78, uint64(0x0)) - var x84 uint64 - var x85 uint64 - x84, x85 = bits.Add64(x79, x76, uint64(p256OrdUint1(x83))) - var x86 uint64 - var x87 uint64 - x86, x87 = bits.Add64(x77, x74, uint64(p256OrdUint1(x85))) - x88 := (uint64(p256OrdUint1(x87)) + x75) - var x90 uint64 - _, x90 = bits.Add64(x62, x80, uint64(0x0)) - var x91 uint64 - var x92 uint64 - x91, x92 = bits.Add64(x64, x82, uint64(p256OrdUint1(x90))) - var x93 uint64 - var x94 uint64 - x93, x94 = bits.Add64(x66, x84, uint64(p256OrdUint1(x92))) - var x95 uint64 - var x96 uint64 - x95, x96 = bits.Add64(x68, x86, uint64(p256OrdUint1(x94))) - var x97 uint64 - var x98 uint64 - x97, x98 = bits.Add64(x70, x88, uint64(p256OrdUint1(x96))) - x99 := (uint64(p256OrdUint1(x98)) + uint64(p256OrdUint1(x71))) - var x100 uint64 - var x101 uint64 - x101, x100 = bits.Mul64(x2, arg1[3]) - var x102 uint64 - var x103 uint64 - x103, x102 = bits.Mul64(x2, arg1[2]) - var x104 uint64 - var x105 uint64 - x105, x104 = bits.Mul64(x2, arg1[1]) - var x106 uint64 - var x107 uint64 - x107, x106 = bits.Mul64(x2, arg1[0]) - var x108 uint64 - var x109 uint64 - x108, x109 = bits.Add64(x107, x104, uint64(0x0)) - var x110 uint64 - var x111 uint64 - x110, x111 = bits.Add64(x105, x102, uint64(p256OrdUint1(x109))) - var x112 uint64 - var x113 uint64 - x112, x113 = bits.Add64(x103, x100, uint64(p256OrdUint1(x111))) - x114 := (uint64(p256OrdUint1(x113)) + x101) - var x115 uint64 - var x116 uint64 - x115, x116 = bits.Add64(x91, x106, uint64(0x0)) - var x117 uint64 - var x118 uint64 - x117, x118 = bits.Add64(x93, x108, uint64(p256OrdUint1(x116))) - var x119 uint64 - var x120 uint64 - x119, x120 = bits.Add64(x95, x110, uint64(p256OrdUint1(x118))) - var x121 uint64 - var x122 uint64 - x121, x122 = bits.Add64(x97, x112, uint64(p256OrdUint1(x120))) - var x123 uint64 - var x124 uint64 - x123, x124 = bits.Add64(x99, x114, uint64(p256OrdUint1(x122))) - var x125 uint64 - _, x125 = bits.Mul64(x115, 0xccd1c8aaee00bc4f) - var x127 uint64 - var x128 uint64 - x128, x127 = bits.Mul64(x125, 0xffffffff00000000) - var x129 uint64 - var x130 uint64 - x130, x129 = bits.Mul64(x125, 0xffffffffffffffff) - var x131 uint64 - var x132 uint64 - x132, x131 = bits.Mul64(x125, 0xbce6faada7179e84) - var x133 uint64 - var x134 uint64 - x134, x133 = bits.Mul64(x125, 0xf3b9cac2fc632551) - var x135 uint64 - var x136 uint64 - x135, x136 = bits.Add64(x134, x131, uint64(0x0)) - var x137 uint64 - var x138 uint64 - x137, x138 = bits.Add64(x132, x129, uint64(p256OrdUint1(x136))) - var x139 uint64 - var x140 uint64 - x139, x140 = bits.Add64(x130, x127, uint64(p256OrdUint1(x138))) - x141 := (uint64(p256OrdUint1(x140)) + x128) - var x143 uint64 - _, x143 = bits.Add64(x115, x133, uint64(0x0)) - var x144 uint64 - var x145 uint64 - x144, x145 = bits.Add64(x117, x135, uint64(p256OrdUint1(x143))) - var x146 uint64 - var x147 uint64 - x146, x147 = bits.Add64(x119, x137, uint64(p256OrdUint1(x145))) - var x148 uint64 - var x149 uint64 - x148, x149 = bits.Add64(x121, x139, uint64(p256OrdUint1(x147))) - var x150 uint64 - var x151 uint64 - x150, x151 = bits.Add64(x123, x141, uint64(p256OrdUint1(x149))) - x152 := (uint64(p256OrdUint1(x151)) + uint64(p256OrdUint1(x124))) - var x153 uint64 - var x154 uint64 - x154, x153 = bits.Mul64(x3, arg1[3]) - var x155 uint64 - var x156 uint64 - x156, x155 = bits.Mul64(x3, arg1[2]) - var x157 uint64 - var x158 uint64 - x158, x157 = bits.Mul64(x3, arg1[1]) - var x159 uint64 - var x160 uint64 - x160, x159 = bits.Mul64(x3, arg1[0]) - var x161 uint64 - var x162 uint64 - x161, x162 = bits.Add64(x160, x157, uint64(0x0)) - var x163 uint64 - var x164 uint64 - x163, x164 = bits.Add64(x158, x155, uint64(p256OrdUint1(x162))) - var x165 uint64 - var x166 uint64 - x165, x166 = bits.Add64(x156, x153, uint64(p256OrdUint1(x164))) - x167 := (uint64(p256OrdUint1(x166)) + x154) - var x168 uint64 - var x169 uint64 - x168, x169 = bits.Add64(x144, x159, uint64(0x0)) - var x170 uint64 - var x171 uint64 - x170, x171 = bits.Add64(x146, x161, uint64(p256OrdUint1(x169))) - var x172 uint64 - var x173 uint64 - x172, x173 = bits.Add64(x148, x163, uint64(p256OrdUint1(x171))) - var x174 uint64 - var x175 uint64 - x174, x175 = bits.Add64(x150, x165, uint64(p256OrdUint1(x173))) - var x176 uint64 - var x177 uint64 - x176, x177 = bits.Add64(x152, x167, uint64(p256OrdUint1(x175))) - var x178 uint64 - _, x178 = bits.Mul64(x168, 0xccd1c8aaee00bc4f) - var x180 uint64 - var x181 uint64 - x181, x180 = bits.Mul64(x178, 0xffffffff00000000) - var x182 uint64 - var x183 uint64 - x183, x182 = bits.Mul64(x178, 0xffffffffffffffff) - var x184 uint64 - var x185 uint64 - x185, x184 = bits.Mul64(x178, 0xbce6faada7179e84) - var x186 uint64 - var x187 uint64 - x187, x186 = bits.Mul64(x178, 0xf3b9cac2fc632551) - var x188 uint64 - var x189 uint64 - x188, x189 = bits.Add64(x187, x184, uint64(0x0)) - var x190 uint64 - var x191 uint64 - x190, x191 = bits.Add64(x185, x182, uint64(p256OrdUint1(x189))) - var x192 uint64 - var x193 uint64 - x192, x193 = bits.Add64(x183, x180, uint64(p256OrdUint1(x191))) - x194 := (uint64(p256OrdUint1(x193)) + x181) - var x196 uint64 - _, x196 = bits.Add64(x168, x186, uint64(0x0)) - var x197 uint64 - var x198 uint64 - x197, x198 = bits.Add64(x170, x188, uint64(p256OrdUint1(x196))) - var x199 uint64 - var x200 uint64 - x199, x200 = bits.Add64(x172, x190, uint64(p256OrdUint1(x198))) - var x201 uint64 - var x202 uint64 - x201, x202 = bits.Add64(x174, x192, uint64(p256OrdUint1(x200))) - var x203 uint64 - var x204 uint64 - x203, x204 = bits.Add64(x176, x194, uint64(p256OrdUint1(x202))) - x205 := (uint64(p256OrdUint1(x204)) + uint64(p256OrdUint1(x177))) - var x206 uint64 - var x207 uint64 - x206, x207 = bits.Sub64(x197, 0xf3b9cac2fc632551, uint64(0x0)) - var x208 uint64 - var x209 uint64 - x208, x209 = bits.Sub64(x199, 0xbce6faada7179e84, uint64(p256OrdUint1(x207))) - var x210 uint64 - var x211 uint64 - x210, x211 = bits.Sub64(x201, 0xffffffffffffffff, uint64(p256OrdUint1(x209))) - var x212 uint64 - var x213 uint64 - x212, x213 = bits.Sub64(x203, 0xffffffff00000000, uint64(p256OrdUint1(x211))) - var x215 uint64 - _, x215 = bits.Sub64(x205, uint64(0x0), uint64(p256OrdUint1(x213))) + x6, x5 := bits.Mul64(x4, arg1[3]) + x8, x7 := bits.Mul64(x4, arg1[2]) + x10, x9 := bits.Mul64(x4, arg1[1]) + x12, x11 := bits.Mul64(x4, arg1[0]) + x13, x14 := bits.Add64(x12, x9, 0) + x15, x16 := bits.Add64(x10, x7, x14) + x17, x18 := bits.Add64(x8, x5, x16) + x19 := x18 + x6 + _, x20 := bits.Mul64(x11, 0xccd1c8aaee00bc4f) + x23, x22 := bits.Mul64(x20, 0xffffffff00000000) + x25, x24 := bits.Mul64(x20, 0xffffffffffffffff) + x27, x26 := bits.Mul64(x20, 0xbce6faada7179e84) + x29, x28 := bits.Mul64(x20, 0xf3b9cac2fc632551) + x30, x31 := bits.Add64(x29, x26, 0) + x32, x33 := bits.Add64(x27, x24, x31) + x34, x35 := bits.Add64(x25, x22, x33) + x36 := x35 + x23 + _, x38 := bits.Add64(x11, x28, 0) + x39, x40 := bits.Add64(x13, x30, x38) + x41, x42 := bits.Add64(x15, x32, x40) + x43, x44 := bits.Add64(x17, x34, x42) + x45, x46 := bits.Add64(x19, x36, x44) + x48, x47 := bits.Mul64(x1, arg1[3]) + x50, x49 := bits.Mul64(x1, arg1[2]) + x52, x51 := bits.Mul64(x1, arg1[1]) + x54, x53 := bits.Mul64(x1, arg1[0]) + x55, x56 := bits.Add64(x54, x51, 0) + x57, x58 := bits.Add64(x52, x49, x56) + x59, x60 := bits.Add64(x50, x47, x58) + x61 := x60 + x48 + x62, x63 := bits.Add64(x39, x53, 0) + x64, x65 := bits.Add64(x41, x55, x63) + x66, x67 := bits.Add64(x43, x57, x65) + x68, x69 := bits.Add64(x45, x59, x67) + x70, x71 := bits.Add64(x46, x61, x69) + _, x72 := bits.Mul64(x62, 0xccd1c8aaee00bc4f) + x75, x74 := bits.Mul64(x72, 0xffffffff00000000) + x77, x76 := bits.Mul64(x72, 0xffffffffffffffff) + x79, x78 := bits.Mul64(x72, 0xbce6faada7179e84) + x81, x80 := bits.Mul64(x72, 0xf3b9cac2fc632551) + x82, x83 := bits.Add64(x81, x78, 0) + x84, x85 := bits.Add64(x79, x76, x83) + x86, x87 := bits.Add64(x77, x74, x85) + x88 := x87 + x75 + _, x90 := bits.Add64(x62, x80, 0) + x91, x92 := bits.Add64(x64, x82, x90) + x93, x94 := bits.Add64(x66, x84, x92) + x95, x96 := bits.Add64(x68, x86, x94) + x97, x98 := bits.Add64(x70, x88, x96) + x99 := x98 + x71 + x101, x100 := bits.Mul64(x2, arg1[3]) + x103, x102 := bits.Mul64(x2, arg1[2]) + x105, x104 := bits.Mul64(x2, arg1[1]) + x107, x106 := bits.Mul64(x2, arg1[0]) + x108, x109 := bits.Add64(x107, x104, 0) + x110, x111 := bits.Add64(x105, x102, x109) + x112, x113 := bits.Add64(x103, x100, x111) + x114 := x113 + x101 + x115, x116 := bits.Add64(x91, x106, 0) + x117, x118 := bits.Add64(x93, x108, x116) + x119, x120 := bits.Add64(x95, x110, x118) + x121, x122 := bits.Add64(x97, x112, x120) + x123, x124 := bits.Add64(x99, x114, x122) + _, x125 := bits.Mul64(x115, 0xccd1c8aaee00bc4f) + x128, x127 := bits.Mul64(x125, 0xffffffff00000000) + x130, x129 := bits.Mul64(x125, 0xffffffffffffffff) + x132, x131 := bits.Mul64(x125, 0xbce6faada7179e84) + x134, x133 := bits.Mul64(x125, 0xf3b9cac2fc632551) + x135, x136 := bits.Add64(x134, x131, 0) + x137, x138 := bits.Add64(x132, x129, x136) + x139, x140 := bits.Add64(x130, x127, x138) + x141 := x140 + x128 + _, x143 := bits.Add64(x115, x133, 0) + x144, x145 := bits.Add64(x117, x135, x143) + x146, x147 := bits.Add64(x119, x137, x145) + x148, x149 := bits.Add64(x121, x139, x147) + x150, x151 := bits.Add64(x123, x141, x149) + x152 := x151 + x124 + x154, x153 := bits.Mul64(x3, arg1[3]) + x156, x155 := bits.Mul64(x3, arg1[2]) + x158, x157 := bits.Mul64(x3, arg1[1]) + x160, x159 := bits.Mul64(x3, arg1[0]) + x161, x162 := bits.Add64(x160, x157, 0) + x163, x164 := bits.Add64(x158, x155, x162) + x165, x166 := bits.Add64(x156, x153, x164) + x167 := x166 + x154 + x168, x169 := bits.Add64(x144, x159, 0) + x170, x171 := bits.Add64(x146, x161, x169) + x172, x173 := bits.Add64(x148, x163, x171) + x174, x175 := bits.Add64(x150, x165, x173) + x176, x177 := bits.Add64(x152, x167, x175) + _, x178 := bits.Mul64(x168, 0xccd1c8aaee00bc4f) + x181, x180 := bits.Mul64(x178, 0xffffffff00000000) + x183, x182 := bits.Mul64(x178, 0xffffffffffffffff) + x185, x184 := bits.Mul64(x178, 0xbce6faada7179e84) + x187, x186 := bits.Mul64(x178, 0xf3b9cac2fc632551) + x188, x189 := bits.Add64(x187, x184, 0) + x190, x191 := bits.Add64(x185, x182, x189) + x192, x193 := bits.Add64(x183, x180, x191) + x194 := x193 + x181 + _, x196 := bits.Add64(x168, x186, 0) + x197, x198 := bits.Add64(x170, x188, x196) + x199, x200 := bits.Add64(x172, x190, x198) + x201, x202 := bits.Add64(x174, x192, x200) + x203, x204 := bits.Add64(x176, x194, x202) + x205 := x204 + x177 + x206, x207 := bits.Sub64(x197, 0xf3b9cac2fc632551, 0) + x208, x209 := bits.Sub64(x199, 0xbce6faada7179e84, x207) + x210, x211 := bits.Sub64(x201, 0xffffffffffffffff, x209) + x212, x213 := bits.Sub64(x203, 0xffffffff00000000, x211) + _, x215 := bits.Sub64(x205, 0, x213) var x216 uint64 - p256OrdCmovznzU64(&x216, p256OrdUint1(x215), x206, x197) + p256OrdCmovznzU64(&x216, x215, x206, x197) var x217 uint64 - p256OrdCmovznzU64(&x217, p256OrdUint1(x215), x208, x199) + p256OrdCmovznzU64(&x217, x215, x208, x199) var x218 uint64 - p256OrdCmovznzU64(&x218, p256OrdUint1(x215), x210, x201) + p256OrdCmovznzU64(&x218, x215, x210, x201) var x219 uint64 - p256OrdCmovznzU64(&x219, p256OrdUint1(x215), x212, x203) + p256OrdCmovznzU64(&x219, x215, x212, x203) out1[0] = x216 out1[1] = x217 out1[2] = x218 @@ -834,194 +446,79 @@ func p256OrdSquare(out1 *p256OrdMontgomeryDomainFieldElement, arg1 *p256OrdMontg // // eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m // 0 ≤ eval out1 < m -func p256OrdFromMontgomery(out1 *p256OrdNonMontgomeryDomainFieldElement, arg1 *p256OrdMontgomeryDomainFieldElement) { +func p256OrdFromMontgomery(out1 *p256OrdElement, arg1 *p256OrdMontElement) { x1 := arg1[0] - var x2 uint64 - _, x2 = bits.Mul64(x1, 0xccd1c8aaee00bc4f) - var x4 uint64 - var x5 uint64 - x5, x4 = bits.Mul64(x2, 0xffffffff00000000) - var x6 uint64 - var x7 uint64 - x7, x6 = bits.Mul64(x2, 0xffffffffffffffff) - var x8 uint64 - var x9 uint64 - x9, x8 = bits.Mul64(x2, 0xbce6faada7179e84) - var x10 uint64 - var x11 uint64 - x11, x10 = bits.Mul64(x2, 0xf3b9cac2fc632551) - var x12 uint64 - var x13 uint64 - x12, x13 = bits.Add64(x11, x8, uint64(0x0)) - var x14 uint64 - var x15 uint64 - x14, x15 = bits.Add64(x9, x6, uint64(p256OrdUint1(x13))) - var x16 uint64 - var x17 uint64 - x16, x17 = bits.Add64(x7, x4, uint64(p256OrdUint1(x15))) - var x19 uint64 - _, x19 = bits.Add64(x1, x10, uint64(0x0)) - var x20 uint64 - var x21 uint64 - x20, x21 = bits.Add64(uint64(0x0), x12, uint64(p256OrdUint1(x19))) - var x22 uint64 - var x23 uint64 - x22, x23 = bits.Add64(uint64(0x0), x14, uint64(p256OrdUint1(x21))) - var x24 uint64 - var x25 uint64 - x24, x25 = bits.Add64(uint64(0x0), x16, uint64(p256OrdUint1(x23))) - var x26 uint64 - var x27 uint64 - x26, x27 = bits.Add64(x20, arg1[1], uint64(0x0)) - var x28 uint64 - var x29 uint64 - x28, x29 = bits.Add64(x22, uint64(0x0), uint64(p256OrdUint1(x27))) - var x30 uint64 - var x31 uint64 - x30, x31 = bits.Add64(x24, uint64(0x0), uint64(p256OrdUint1(x29))) - var x32 uint64 - _, x32 = bits.Mul64(x26, 0xccd1c8aaee00bc4f) - var x34 uint64 - var x35 uint64 - x35, x34 = bits.Mul64(x32, 0xffffffff00000000) - var x36 uint64 - var x37 uint64 - x37, x36 = bits.Mul64(x32, 0xffffffffffffffff) - var x38 uint64 - var x39 uint64 - x39, x38 = bits.Mul64(x32, 0xbce6faada7179e84) - var x40 uint64 - var x41 uint64 - x41, x40 = bits.Mul64(x32, 0xf3b9cac2fc632551) - var x42 uint64 - var x43 uint64 - x42, x43 = bits.Add64(x41, x38, uint64(0x0)) - var x44 uint64 - var x45 uint64 - x44, x45 = bits.Add64(x39, x36, uint64(p256OrdUint1(x43))) - var x46 uint64 - var x47 uint64 - x46, x47 = bits.Add64(x37, x34, uint64(p256OrdUint1(x45))) - var x49 uint64 - _, x49 = bits.Add64(x26, x40, uint64(0x0)) - var x50 uint64 - var x51 uint64 - x50, x51 = bits.Add64(x28, x42, uint64(p256OrdUint1(x49))) - var x52 uint64 - var x53 uint64 - x52, x53 = bits.Add64(x30, x44, uint64(p256OrdUint1(x51))) - var x54 uint64 - var x55 uint64 - x54, x55 = bits.Add64((uint64(p256OrdUint1(x31)) + (uint64(p256OrdUint1(x25)) + (uint64(p256OrdUint1(x17)) + x5))), x46, uint64(p256OrdUint1(x53))) - var x56 uint64 - var x57 uint64 - x56, x57 = bits.Add64(x50, arg1[2], uint64(0x0)) - var x58 uint64 - var x59 uint64 - x58, x59 = bits.Add64(x52, uint64(0x0), uint64(p256OrdUint1(x57))) - var x60 uint64 - var x61 uint64 - x60, x61 = bits.Add64(x54, uint64(0x0), uint64(p256OrdUint1(x59))) - var x62 uint64 - _, x62 = bits.Mul64(x56, 0xccd1c8aaee00bc4f) - var x64 uint64 - var x65 uint64 - x65, x64 = bits.Mul64(x62, 0xffffffff00000000) - var x66 uint64 - var x67 uint64 - x67, x66 = bits.Mul64(x62, 0xffffffffffffffff) - var x68 uint64 - var x69 uint64 - x69, x68 = bits.Mul64(x62, 0xbce6faada7179e84) - var x70 uint64 - var x71 uint64 - x71, x70 = bits.Mul64(x62, 0xf3b9cac2fc632551) - var x72 uint64 - var x73 uint64 - x72, x73 = bits.Add64(x71, x68, uint64(0x0)) - var x74 uint64 - var x75 uint64 - x74, x75 = bits.Add64(x69, x66, uint64(p256OrdUint1(x73))) - var x76 uint64 - var x77 uint64 - x76, x77 = bits.Add64(x67, x64, uint64(p256OrdUint1(x75))) - var x79 uint64 - _, x79 = bits.Add64(x56, x70, uint64(0x0)) - var x80 uint64 - var x81 uint64 - x80, x81 = bits.Add64(x58, x72, uint64(p256OrdUint1(x79))) - var x82 uint64 - var x83 uint64 - x82, x83 = bits.Add64(x60, x74, uint64(p256OrdUint1(x81))) - var x84 uint64 - var x85 uint64 - x84, x85 = bits.Add64((uint64(p256OrdUint1(x61)) + (uint64(p256OrdUint1(x55)) + (uint64(p256OrdUint1(x47)) + x35))), x76, uint64(p256OrdUint1(x83))) - var x86 uint64 - var x87 uint64 - x86, x87 = bits.Add64(x80, arg1[3], uint64(0x0)) - var x88 uint64 - var x89 uint64 - x88, x89 = bits.Add64(x82, uint64(0x0), uint64(p256OrdUint1(x87))) - var x90 uint64 - var x91 uint64 - x90, x91 = bits.Add64(x84, uint64(0x0), uint64(p256OrdUint1(x89))) - var x92 uint64 - _, x92 = bits.Mul64(x86, 0xccd1c8aaee00bc4f) - var x94 uint64 - var x95 uint64 - x95, x94 = bits.Mul64(x92, 0xffffffff00000000) - var x96 uint64 - var x97 uint64 - x97, x96 = bits.Mul64(x92, 0xffffffffffffffff) - var x98 uint64 - var x99 uint64 - x99, x98 = bits.Mul64(x92, 0xbce6faada7179e84) - var x100 uint64 - var x101 uint64 - x101, x100 = bits.Mul64(x92, 0xf3b9cac2fc632551) - var x102 uint64 - var x103 uint64 - x102, x103 = bits.Add64(x101, x98, uint64(0x0)) - var x104 uint64 - var x105 uint64 - x104, x105 = bits.Add64(x99, x96, uint64(p256OrdUint1(x103))) - var x106 uint64 - var x107 uint64 - x106, x107 = bits.Add64(x97, x94, uint64(p256OrdUint1(x105))) - var x109 uint64 - _, x109 = bits.Add64(x86, x100, uint64(0x0)) - var x110 uint64 - var x111 uint64 - x110, x111 = bits.Add64(x88, x102, uint64(p256OrdUint1(x109))) - var x112 uint64 - var x113 uint64 - x112, x113 = bits.Add64(x90, x104, uint64(p256OrdUint1(x111))) - var x114 uint64 - var x115 uint64 - x114, x115 = bits.Add64((uint64(p256OrdUint1(x91)) + (uint64(p256OrdUint1(x85)) + (uint64(p256OrdUint1(x77)) + x65))), x106, uint64(p256OrdUint1(x113))) - x116 := (uint64(p256OrdUint1(x115)) + (uint64(p256OrdUint1(x107)) + x95)) - var x117 uint64 - var x118 uint64 - x117, x118 = bits.Sub64(x110, 0xf3b9cac2fc632551, uint64(0x0)) - var x119 uint64 - var x120 uint64 - x119, x120 = bits.Sub64(x112, 0xbce6faada7179e84, uint64(p256OrdUint1(x118))) - var x121 uint64 - var x122 uint64 - x121, x122 = bits.Sub64(x114, 0xffffffffffffffff, uint64(p256OrdUint1(x120))) - var x123 uint64 - var x124 uint64 - x123, x124 = bits.Sub64(x116, 0xffffffff00000000, uint64(p256OrdUint1(x122))) - var x126 uint64 - _, x126 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(p256OrdUint1(x124))) + _, x2 := bits.Mul64(x1, 0xccd1c8aaee00bc4f) + x5, x4 := bits.Mul64(x2, 0xffffffff00000000) + x7, x6 := bits.Mul64(x2, 0xffffffffffffffff) + x9, x8 := bits.Mul64(x2, 0xbce6faada7179e84) + x11, x10 := bits.Mul64(x2, 0xf3b9cac2fc632551) + x12, x13 := bits.Add64(x11, x8, 0) + x14, x15 := bits.Add64(x9, x6, x13) + x16, x17 := bits.Add64(x7, x4, x15) + _, x19 := bits.Add64(x1, x10, 0) + x20, x21 := bits.Add64(0, x12, x19) + x22, x23 := bits.Add64(0, x14, x21) + x24, x25 := bits.Add64(0, x16, x23) + x26, x27 := bits.Add64(x20, arg1[1], 0) + x28, x29 := bits.Add64(x22, 0, x27) + x30, x31 := bits.Add64(x24, 0, x29) + _, x32 := bits.Mul64(x26, 0xccd1c8aaee00bc4f) + x35, x34 := bits.Mul64(x32, 0xffffffff00000000) + x37, x36 := bits.Mul64(x32, 0xffffffffffffffff) + x39, x38 := bits.Mul64(x32, 0xbce6faada7179e84) + x41, x40 := bits.Mul64(x32, 0xf3b9cac2fc632551) + x42, x43 := bits.Add64(x41, x38, 0) + x44, x45 := bits.Add64(x39, x36, x43) + x46, x47 := bits.Add64(x37, x34, x45) + _, x49 := bits.Add64(x26, x40, 0) + x50, x51 := bits.Add64(x28, x42, x49) + x52, x53 := bits.Add64(x30, x44, x51) + x54, x55 := bits.Add64(x31+(x25+(x17+x5)), x46, x53) + x56, x57 := bits.Add64(x50, arg1[2], 0) + x58, x59 := bits.Add64(x52, 0, x57) + x60, x61 := bits.Add64(x54, 0, x59) + _, x62 := bits.Mul64(x56, 0xccd1c8aaee00bc4f) + x65, x64 := bits.Mul64(x62, 0xffffffff00000000) + x67, x66 := bits.Mul64(x62, 0xffffffffffffffff) + x69, x68 := bits.Mul64(x62, 0xbce6faada7179e84) + x71, x70 := bits.Mul64(x62, 0xf3b9cac2fc632551) + x72, x73 := bits.Add64(x71, x68, 0) + x74, x75 := bits.Add64(x69, x66, x73) + x76, x77 := bits.Add64(x67, x64, x75) + _, x79 := bits.Add64(x56, x70, 0) + x80, x81 := bits.Add64(x58, x72, x79) + x82, x83 := bits.Add64(x60, x74, x81) + x84, x85 := bits.Add64(x61+(x55+(x47+x35)), x76, x83) + x86, x87 := bits.Add64(x80, arg1[3], 0) + x88, x89 := bits.Add64(x82, 0, x87) + x90, x91 := bits.Add64(x84, 0, x89) + _, x92 := bits.Mul64(x86, 0xccd1c8aaee00bc4f) + x95, x94 := bits.Mul64(x92, 0xffffffff00000000) + x97, x96 := bits.Mul64(x92, 0xffffffffffffffff) + x99, x98 := bits.Mul64(x92, 0xbce6faada7179e84) + x101, x100 := bits.Mul64(x92, 0xf3b9cac2fc632551) + x102, x103 := bits.Add64(x101, x98, 0) + x104, x105 := bits.Add64(x99, x96, x103) + x106, x107 := bits.Add64(x97, x94, x105) + _, x109 := bits.Add64(x86, x100, 0) + x110, x111 := bits.Add64(x88, x102, x109) + x112, x113 := bits.Add64(x90, x104, x111) + x114, x115 := bits.Add64(x91+(x85+(x77+x65)), x106, x113) + x116 := x115 + (x107 + x95) + x117, x118 := bits.Sub64(x110, 0xf3b9cac2fc632551, 0) + x119, x120 := bits.Sub64(x112, 0xbce6faada7179e84, x118) + x121, x122 := bits.Sub64(x114, 0xffffffffffffffff, x120) + x123, x124 := bits.Sub64(x116, 0xffffffff00000000, x122) + _, x126 := bits.Sub64(0, 0, x124) var x127 uint64 - p256OrdCmovznzU64(&x127, p256OrdUint1(x126), x117, x110) + p256OrdCmovznzU64(&x127, x126, x117, x110) var x128 uint64 - p256OrdCmovznzU64(&x128, p256OrdUint1(x126), x119, x112) + p256OrdCmovznzU64(&x128, x126, x119, x112) var x129 uint64 - p256OrdCmovznzU64(&x129, p256OrdUint1(x126), x121, x114) + p256OrdCmovznzU64(&x129, x126, x121, x114) var x130 uint64 - p256OrdCmovznzU64(&x130, p256OrdUint1(x126), x123, x116) + p256OrdCmovznzU64(&x130, x126, x123, x116) out1[0] = x127 out1[1] = x128 out1[2] = x129 @@ -1038,301 +535,116 @@ func p256OrdFromMontgomery(out1 *p256OrdNonMontgomeryDomainFieldElement, arg1 *p // // eval (from_montgomery out1) mod m = eval arg1 mod m // 0 ≤ eval out1 < m -func p256OrdToMontgomery(out1 *p256OrdMontgomeryDomainFieldElement, arg1 *p256OrdNonMontgomeryDomainFieldElement) { +func p256OrdToMontgomery(out1 *p256OrdMontElement, arg1 *p256OrdElement) { x1 := arg1[1] x2 := arg1[2] x3 := arg1[3] x4 := arg1[0] - var x5 uint64 - var x6 uint64 - x6, x5 = bits.Mul64(x4, 0x66e12d94f3d95620) - var x7 uint64 - var x8 uint64 - x8, x7 = bits.Mul64(x4, 0x2845b2392b6bec59) - var x9 uint64 - var x10 uint64 - x10, x9 = bits.Mul64(x4, 0x4699799c49bd6fa6) - var x11 uint64 - var x12 uint64 - x12, x11 = bits.Mul64(x4, 0x83244c95be79eea2) - var x13 uint64 - var x14 uint64 - x13, x14 = bits.Add64(x12, x9, uint64(0x0)) - var x15 uint64 - var x16 uint64 - x15, x16 = bits.Add64(x10, x7, uint64(p256OrdUint1(x14))) - var x17 uint64 - var x18 uint64 - x17, x18 = bits.Add64(x8, x5, uint64(p256OrdUint1(x16))) - var x19 uint64 - _, x19 = bits.Mul64(x11, 0xccd1c8aaee00bc4f) - var x21 uint64 - var x22 uint64 - x22, x21 = bits.Mul64(x19, 0xffffffff00000000) - var x23 uint64 - var x24 uint64 - x24, x23 = bits.Mul64(x19, 0xffffffffffffffff) - var x25 uint64 - var x26 uint64 - x26, x25 = bits.Mul64(x19, 0xbce6faada7179e84) - var x27 uint64 - var x28 uint64 - x28, x27 = bits.Mul64(x19, 0xf3b9cac2fc632551) - var x29 uint64 - var x30 uint64 - x29, x30 = bits.Add64(x28, x25, uint64(0x0)) - var x31 uint64 - var x32 uint64 - x31, x32 = bits.Add64(x26, x23, uint64(p256OrdUint1(x30))) - var x33 uint64 - var x34 uint64 - x33, x34 = bits.Add64(x24, x21, uint64(p256OrdUint1(x32))) - var x36 uint64 - _, x36 = bits.Add64(x11, x27, uint64(0x0)) - var x37 uint64 - var x38 uint64 - x37, x38 = bits.Add64(x13, x29, uint64(p256OrdUint1(x36))) - var x39 uint64 - var x40 uint64 - x39, x40 = bits.Add64(x15, x31, uint64(p256OrdUint1(x38))) - var x41 uint64 - var x42 uint64 - x41, x42 = bits.Add64(x17, x33, uint64(p256OrdUint1(x40))) - var x43 uint64 - var x44 uint64 - x43, x44 = bits.Add64((uint64(p256OrdUint1(x18)) + x6), (uint64(p256OrdUint1(x34)) + x22), uint64(p256OrdUint1(x42))) - var x45 uint64 - var x46 uint64 - x46, x45 = bits.Mul64(x1, 0x66e12d94f3d95620) - var x47 uint64 - var x48 uint64 - x48, x47 = bits.Mul64(x1, 0x2845b2392b6bec59) - var x49 uint64 - var x50 uint64 - x50, x49 = bits.Mul64(x1, 0x4699799c49bd6fa6) - var x51 uint64 - var x52 uint64 - x52, x51 = bits.Mul64(x1, 0x83244c95be79eea2) - var x53 uint64 - var x54 uint64 - x53, x54 = bits.Add64(x52, x49, uint64(0x0)) - var x55 uint64 - var x56 uint64 - x55, x56 = bits.Add64(x50, x47, uint64(p256OrdUint1(x54))) - var x57 uint64 - var x58 uint64 - x57, x58 = bits.Add64(x48, x45, uint64(p256OrdUint1(x56))) - var x59 uint64 - var x60 uint64 - x59, x60 = bits.Add64(x37, x51, uint64(0x0)) - var x61 uint64 - var x62 uint64 - x61, x62 = bits.Add64(x39, x53, uint64(p256OrdUint1(x60))) - var x63 uint64 - var x64 uint64 - x63, x64 = bits.Add64(x41, x55, uint64(p256OrdUint1(x62))) - var x65 uint64 - var x66 uint64 - x65, x66 = bits.Add64(x43, x57, uint64(p256OrdUint1(x64))) - var x67 uint64 - _, x67 = bits.Mul64(x59, 0xccd1c8aaee00bc4f) - var x69 uint64 - var x70 uint64 - x70, x69 = bits.Mul64(x67, 0xffffffff00000000) - var x71 uint64 - var x72 uint64 - x72, x71 = bits.Mul64(x67, 0xffffffffffffffff) - var x73 uint64 - var x74 uint64 - x74, x73 = bits.Mul64(x67, 0xbce6faada7179e84) - var x75 uint64 - var x76 uint64 - x76, x75 = bits.Mul64(x67, 0xf3b9cac2fc632551) - var x77 uint64 - var x78 uint64 - x77, x78 = bits.Add64(x76, x73, uint64(0x0)) - var x79 uint64 - var x80 uint64 - x79, x80 = bits.Add64(x74, x71, uint64(p256OrdUint1(x78))) - var x81 uint64 - var x82 uint64 - x81, x82 = bits.Add64(x72, x69, uint64(p256OrdUint1(x80))) - var x84 uint64 - _, x84 = bits.Add64(x59, x75, uint64(0x0)) - var x85 uint64 - var x86 uint64 - x85, x86 = bits.Add64(x61, x77, uint64(p256OrdUint1(x84))) - var x87 uint64 - var x88 uint64 - x87, x88 = bits.Add64(x63, x79, uint64(p256OrdUint1(x86))) - var x89 uint64 - var x90 uint64 - x89, x90 = bits.Add64(x65, x81, uint64(p256OrdUint1(x88))) - var x91 uint64 - var x92 uint64 - x91, x92 = bits.Add64(((uint64(p256OrdUint1(x66)) + uint64(p256OrdUint1(x44))) + (uint64(p256OrdUint1(x58)) + x46)), (uint64(p256OrdUint1(x82)) + x70), uint64(p256OrdUint1(x90))) - var x93 uint64 - var x94 uint64 - x94, x93 = bits.Mul64(x2, 0x66e12d94f3d95620) - var x95 uint64 - var x96 uint64 - x96, x95 = bits.Mul64(x2, 0x2845b2392b6bec59) - var x97 uint64 - var x98 uint64 - x98, x97 = bits.Mul64(x2, 0x4699799c49bd6fa6) - var x99 uint64 - var x100 uint64 - x100, x99 = bits.Mul64(x2, 0x83244c95be79eea2) - var x101 uint64 - var x102 uint64 - x101, x102 = bits.Add64(x100, x97, uint64(0x0)) - var x103 uint64 - var x104 uint64 - x103, x104 = bits.Add64(x98, x95, uint64(p256OrdUint1(x102))) - var x105 uint64 - var x106 uint64 - x105, x106 = bits.Add64(x96, x93, uint64(p256OrdUint1(x104))) - var x107 uint64 - var x108 uint64 - x107, x108 = bits.Add64(x85, x99, uint64(0x0)) - var x109 uint64 - var x110 uint64 - x109, x110 = bits.Add64(x87, x101, uint64(p256OrdUint1(x108))) - var x111 uint64 - var x112 uint64 - x111, x112 = bits.Add64(x89, x103, uint64(p256OrdUint1(x110))) - var x113 uint64 - var x114 uint64 - x113, x114 = bits.Add64(x91, x105, uint64(p256OrdUint1(x112))) - var x115 uint64 - _, x115 = bits.Mul64(x107, 0xccd1c8aaee00bc4f) - var x117 uint64 - var x118 uint64 - x118, x117 = bits.Mul64(x115, 0xffffffff00000000) - var x119 uint64 - var x120 uint64 - x120, x119 = bits.Mul64(x115, 0xffffffffffffffff) - var x121 uint64 - var x122 uint64 - x122, x121 = bits.Mul64(x115, 0xbce6faada7179e84) - var x123 uint64 - var x124 uint64 - x124, x123 = bits.Mul64(x115, 0xf3b9cac2fc632551) - var x125 uint64 - var x126 uint64 - x125, x126 = bits.Add64(x124, x121, uint64(0x0)) - var x127 uint64 - var x128 uint64 - x127, x128 = bits.Add64(x122, x119, uint64(p256OrdUint1(x126))) - var x129 uint64 - var x130 uint64 - x129, x130 = bits.Add64(x120, x117, uint64(p256OrdUint1(x128))) - var x132 uint64 - _, x132 = bits.Add64(x107, x123, uint64(0x0)) - var x133 uint64 - var x134 uint64 - x133, x134 = bits.Add64(x109, x125, uint64(p256OrdUint1(x132))) - var x135 uint64 - var x136 uint64 - x135, x136 = bits.Add64(x111, x127, uint64(p256OrdUint1(x134))) - var x137 uint64 - var x138 uint64 - x137, x138 = bits.Add64(x113, x129, uint64(p256OrdUint1(x136))) - var x139 uint64 - var x140 uint64 - x139, x140 = bits.Add64(((uint64(p256OrdUint1(x114)) + uint64(p256OrdUint1(x92))) + (uint64(p256OrdUint1(x106)) + x94)), (uint64(p256OrdUint1(x130)) + x118), uint64(p256OrdUint1(x138))) - var x141 uint64 - var x142 uint64 - x142, x141 = bits.Mul64(x3, 0x66e12d94f3d95620) - var x143 uint64 - var x144 uint64 - x144, x143 = bits.Mul64(x3, 0x2845b2392b6bec59) - var x145 uint64 - var x146 uint64 - x146, x145 = bits.Mul64(x3, 0x4699799c49bd6fa6) - var x147 uint64 - var x148 uint64 - x148, x147 = bits.Mul64(x3, 0x83244c95be79eea2) - var x149 uint64 - var x150 uint64 - x149, x150 = bits.Add64(x148, x145, uint64(0x0)) - var x151 uint64 - var x152 uint64 - x151, x152 = bits.Add64(x146, x143, uint64(p256OrdUint1(x150))) - var x153 uint64 - var x154 uint64 - x153, x154 = bits.Add64(x144, x141, uint64(p256OrdUint1(x152))) - var x155 uint64 - var x156 uint64 - x155, x156 = bits.Add64(x133, x147, uint64(0x0)) - var x157 uint64 - var x158 uint64 - x157, x158 = bits.Add64(x135, x149, uint64(p256OrdUint1(x156))) - var x159 uint64 - var x160 uint64 - x159, x160 = bits.Add64(x137, x151, uint64(p256OrdUint1(x158))) - var x161 uint64 - var x162 uint64 - x161, x162 = bits.Add64(x139, x153, uint64(p256OrdUint1(x160))) - var x163 uint64 - _, x163 = bits.Mul64(x155, 0xccd1c8aaee00bc4f) - var x165 uint64 - var x166 uint64 - x166, x165 = bits.Mul64(x163, 0xffffffff00000000) - var x167 uint64 - var x168 uint64 - x168, x167 = bits.Mul64(x163, 0xffffffffffffffff) - var x169 uint64 - var x170 uint64 - x170, x169 = bits.Mul64(x163, 0xbce6faada7179e84) - var x171 uint64 - var x172 uint64 - x172, x171 = bits.Mul64(x163, 0xf3b9cac2fc632551) - var x173 uint64 - var x174 uint64 - x173, x174 = bits.Add64(x172, x169, uint64(0x0)) - var x175 uint64 - var x176 uint64 - x175, x176 = bits.Add64(x170, x167, uint64(p256OrdUint1(x174))) - var x177 uint64 - var x178 uint64 - x177, x178 = bits.Add64(x168, x165, uint64(p256OrdUint1(x176))) - var x180 uint64 - _, x180 = bits.Add64(x155, x171, uint64(0x0)) - var x181 uint64 - var x182 uint64 - x181, x182 = bits.Add64(x157, x173, uint64(p256OrdUint1(x180))) - var x183 uint64 - var x184 uint64 - x183, x184 = bits.Add64(x159, x175, uint64(p256OrdUint1(x182))) - var x185 uint64 - var x186 uint64 - x185, x186 = bits.Add64(x161, x177, uint64(p256OrdUint1(x184))) - var x187 uint64 - var x188 uint64 - x187, x188 = bits.Add64(((uint64(p256OrdUint1(x162)) + uint64(p256OrdUint1(x140))) + (uint64(p256OrdUint1(x154)) + x142)), (uint64(p256OrdUint1(x178)) + x166), uint64(p256OrdUint1(x186))) - var x189 uint64 - var x190 uint64 - x189, x190 = bits.Sub64(x181, 0xf3b9cac2fc632551, uint64(0x0)) - var x191 uint64 - var x192 uint64 - x191, x192 = bits.Sub64(x183, 0xbce6faada7179e84, uint64(p256OrdUint1(x190))) - var x193 uint64 - var x194 uint64 - x193, x194 = bits.Sub64(x185, 0xffffffffffffffff, uint64(p256OrdUint1(x192))) - var x195 uint64 - var x196 uint64 - x195, x196 = bits.Sub64(x187, 0xffffffff00000000, uint64(p256OrdUint1(x194))) - var x198 uint64 - _, x198 = bits.Sub64(uint64(p256OrdUint1(x188)), uint64(0x0), uint64(p256OrdUint1(x196))) + x6, x5 := bits.Mul64(x4, 0x66e12d94f3d95620) + x8, x7 := bits.Mul64(x4, 0x2845b2392b6bec59) + x10, x9 := bits.Mul64(x4, 0x4699799c49bd6fa6) + x12, x11 := bits.Mul64(x4, 0x83244c95be79eea2) + x13, x14 := bits.Add64(x12, x9, 0) + x15, x16 := bits.Add64(x10, x7, x14) + x17, x18 := bits.Add64(x8, x5, x16) + _, x19 := bits.Mul64(x11, 0xccd1c8aaee00bc4f) + x22, x21 := bits.Mul64(x19, 0xffffffff00000000) + x24, x23 := bits.Mul64(x19, 0xffffffffffffffff) + x26, x25 := bits.Mul64(x19, 0xbce6faada7179e84) + x28, x27 := bits.Mul64(x19, 0xf3b9cac2fc632551) + x29, x30 := bits.Add64(x28, x25, 0) + x31, x32 := bits.Add64(x26, x23, x30) + x33, x34 := bits.Add64(x24, x21, x32) + _, x36 := bits.Add64(x11, x27, 0) + x37, x38 := bits.Add64(x13, x29, x36) + x39, x40 := bits.Add64(x15, x31, x38) + x41, x42 := bits.Add64(x17, x33, x40) + x43, x44 := bits.Add64(x18+x6, x34+x22, x42) + x46, x45 := bits.Mul64(x1, 0x66e12d94f3d95620) + x48, x47 := bits.Mul64(x1, 0x2845b2392b6bec59) + x50, x49 := bits.Mul64(x1, 0x4699799c49bd6fa6) + x52, x51 := bits.Mul64(x1, 0x83244c95be79eea2) + x53, x54 := bits.Add64(x52, x49, 0) + x55, x56 := bits.Add64(x50, x47, x54) + x57, x58 := bits.Add64(x48, x45, x56) + x59, x60 := bits.Add64(x37, x51, 0) + x61, x62 := bits.Add64(x39, x53, x60) + x63, x64 := bits.Add64(x41, x55, x62) + x65, x66 := bits.Add64(x43, x57, x64) + _, x67 := bits.Mul64(x59, 0xccd1c8aaee00bc4f) + x70, x69 := bits.Mul64(x67, 0xffffffff00000000) + x72, x71 := bits.Mul64(x67, 0xffffffffffffffff) + x74, x73 := bits.Mul64(x67, 0xbce6faada7179e84) + x76, x75 := bits.Mul64(x67, 0xf3b9cac2fc632551) + x77, x78 := bits.Add64(x76, x73, 0) + x79, x80 := bits.Add64(x74, x71, x78) + x81, x82 := bits.Add64(x72, x69, x80) + _, x84 := bits.Add64(x59, x75, 0) + x85, x86 := bits.Add64(x61, x77, x84) + x87, x88 := bits.Add64(x63, x79, x86) + x89, x90 := bits.Add64(x65, x81, x88) + x91, x92 := bits.Add64(x66+x44+(x58+x46), x82+x70, x90) + x94, x93 := bits.Mul64(x2, 0x66e12d94f3d95620) + x96, x95 := bits.Mul64(x2, 0x2845b2392b6bec59) + x98, x97 := bits.Mul64(x2, 0x4699799c49bd6fa6) + x100, x99 := bits.Mul64(x2, 0x83244c95be79eea2) + x101, x102 := bits.Add64(x100, x97, 0) + x103, x104 := bits.Add64(x98, x95, x102) + x105, x106 := bits.Add64(x96, x93, x104) + x107, x108 := bits.Add64(x85, x99, 0) + x109, x110 := bits.Add64(x87, x101, x108) + x111, x112 := bits.Add64(x89, x103, x110) + x113, x114 := bits.Add64(x91, x105, x112) + _, x115 := bits.Mul64(x107, 0xccd1c8aaee00bc4f) + x118, x117 := bits.Mul64(x115, 0xffffffff00000000) + x120, x119 := bits.Mul64(x115, 0xffffffffffffffff) + x122, x121 := bits.Mul64(x115, 0xbce6faada7179e84) + x124, x123 := bits.Mul64(x115, 0xf3b9cac2fc632551) + x125, x126 := bits.Add64(x124, x121, 0) + x127, x128 := bits.Add64(x122, x119, x126) + x129, x130 := bits.Add64(x120, x117, x128) + _, x132 := bits.Add64(x107, x123, 0) + x133, x134 := bits.Add64(x109, x125, x132) + x135, x136 := bits.Add64(x111, x127, x134) + x137, x138 := bits.Add64(x113, x129, x136) + x139, x140 := bits.Add64(x114+x92+(x106+x94), x130+x118, x138) + x142, x141 := bits.Mul64(x3, 0x66e12d94f3d95620) + x144, x143 := bits.Mul64(x3, 0x2845b2392b6bec59) + x146, x145 := bits.Mul64(x3, 0x4699799c49bd6fa6) + x148, x147 := bits.Mul64(x3, 0x83244c95be79eea2) + x149, x150 := bits.Add64(x148, x145, 0) + x151, x152 := bits.Add64(x146, x143, x150) + x153, x154 := bits.Add64(x144, x141, x152) + x155, x156 := bits.Add64(x133, x147, 0) + x157, x158 := bits.Add64(x135, x149, x156) + x159, x160 := bits.Add64(x137, x151, x158) + x161, x162 := bits.Add64(x139, x153, x160) + _, x163 := bits.Mul64(x155, 0xccd1c8aaee00bc4f) + x166, x165 := bits.Mul64(x163, 0xffffffff00000000) + x168, x167 := bits.Mul64(x163, 0xffffffffffffffff) + x170, x169 := bits.Mul64(x163, 0xbce6faada7179e84) + x172, x171 := bits.Mul64(x163, 0xf3b9cac2fc632551) + x173, x174 := bits.Add64(x172, x169, 0) + x175, x176 := bits.Add64(x170, x167, x174) + x177, x178 := bits.Add64(x168, x165, x176) + _, x180 := bits.Add64(x155, x171, 0) + x181, x182 := bits.Add64(x157, x173, x180) + x183, x184 := bits.Add64(x159, x175, x182) + x185, x186 := bits.Add64(x161, x177, x184) + x187, x188 := bits.Add64(x162+x140+(x154+x142), x178+x166, x186) + x189, x190 := bits.Sub64(x181, 0xf3b9cac2fc632551, 0) + x191, x192 := bits.Sub64(x183, 0xbce6faada7179e84, x190) + x193, x194 := bits.Sub64(x185, 0xffffffffffffffff, x192) + x195, x196 := bits.Sub64(x187, 0xffffffff00000000, x194) + _, x198 := bits.Sub64(x188, 0, x196) var x199 uint64 - p256OrdCmovznzU64(&x199, p256OrdUint1(x198), x189, x181) + p256OrdCmovznzU64(&x199, x198, x189, x181) var x200 uint64 - p256OrdCmovznzU64(&x200, p256OrdUint1(x198), x191, x183) + p256OrdCmovznzU64(&x200, x198, x191, x183) var x201 uint64 - p256OrdCmovznzU64(&x201, p256OrdUint1(x198), x193, x185) + p256OrdCmovznzU64(&x201, x198, x193, x185) var x202 uint64 - p256OrdCmovznzU64(&x202, p256OrdUint1(x198), x195, x187) + p256OrdCmovznzU64(&x202, x198, x195, x187) out1[0] = x199 out1[1] = x200 out1[2] = x201 @@ -1354,8 +666,8 @@ func p256OrdToMontgomery(out1 *p256OrdMontgomeryDomainFieldElement, arg1 *p256Or // Output Bounds: // // out1: [0x0 ~> 0xffffffffffffffff] -func p256OrdCmovznzU64(out1 *uint64, arg1 p256OrdUint1, arg2 uint64, arg3 uint64) { - x1 := (uint64(arg1) * 0xffffffffffffffff) - x2 := ((x1 & arg3) | ((^x1) & arg2)) +func p256OrdCmovznzU64(out1 *uint64, arg1 uint64, arg2 uint64, arg3 uint64) { + x1 := arg1 * 0xffffffffffffffff + x2 := x1&arg3 | ^x1&arg2 *out1 = x2 } From 2c659bb4db1ff06c819f8b4cd6decc71e4d5b36e Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 25 Feb 2026 14:12:15 +0100 Subject: [PATCH 17/18] crypto/internal/fips140/nistec: optimize P-256 scalar fiat implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reduces the regression of CL 669895 by about half on arm64. host: linux-amd64_c2s16 3227c963a3c 12743b9f2c8 ccb659cd879 9a11e9167c3 sec/op vs base vs base vs base Sign/P256-16 33.38µ +5.23% +5.04% +5.41% Verify/P256-16 74.11µ +2.54% +2.49% +2.69% GenerateKey/P256-16 14.61µ ~ ~ ~ geomean 33.06µ +2.50% +2.41% +2.63% B/op vs base vs base vs base Sign/P256-16 5.922Ki -0.53% -0.53% -0.53% Verify/P256-16 576.0 -5.56% -5.56% -5.56% GenerateKey/P256-16 984.0 ~ ~ ~ geomean 1.474Ki -2.06% -2.06% -2.06% allocs/op vs base vs base vs base Sign/P256-16 59.00 -1.69% -1.69% -1.69% Verify/P256-16 10.00 -10.00% -10.00% -10.00% GenerateKey/P256-16 16.00 ~ ~ ~ geomean 21.13 -4.00% -4.00% -4.00% host: linux-arm64_c4as16 3227c963a3c 12743b9f2c8 ccb659cd879 9a11e9167c3 sec/op vs base vs base vs base Sign/P256-16 29.29µ +8.88% +8.94% +5.41% Verify/P256-16 69.25µ +3.52% +3.48% +2.21% GenerateKey/P256-16 15.17µ ~ ~ ~ geomean 31.34µ +4.05% +3.97% +2.51% B/op vs base vs base vs base Sign/P256-16 5.922Ki -0.53% -0.53% -0.53% Verify/P256-16 576.0 -5.56% -5.56% -5.56% GenerateKey/P256-16 984.0 ~ ~ ~ geomean 1.474Ki -2.06% -2.06% -2.06% allocs/op vs base vs base vs base Sign/P256-16 59.00 -1.69% -1.69% -1.69% Verify/P256-16 10.00 -10.00% -10.00% -10.00% GenerateKey/P256-16 16.00 ~ ~ ~ geomean 21.13 -4.00% -4.00% -4.00% Change-Id: I69adc8175acf0082dca7c8a13d5f62046a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/749141 Auto-Submit: Filippo Valsorda Reviewed-by: Neal Patel Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Neal Patel --- .../internal/fips140/nistec/p256_ordinv.go | 419 ++++++------------ 1 file changed, 147 insertions(+), 272 deletions(-) diff --git a/src/crypto/internal/fips140/nistec/p256_ordinv.go b/src/crypto/internal/fips140/nistec/p256_ordinv.go index d1e58b202be003..a65f27c8142629 100644 --- a/src/crypto/internal/fips140/nistec/p256_ordinv.go +++ b/src/crypto/internal/fips140/nistec/p256_ordinv.go @@ -71,14 +71,8 @@ func P256OrdInverse(k *[4]uint64) { p256OrdFromMontgomery(j, x) } -func p256OrdSqr(out1, arg1 *p256OrdMontElement, n int) { - p256OrdSquare(out1, arg1) - for range n - 1 { - p256OrdSquare(out1, out1) - } -} - -// The code below was generated by Fiat Cryptography v0.1.6-63-g92ee794c2. +// The code below was generated by Fiat Cryptography v0.1.6-63-g92ee794c2, and +// then manually formatted and optimized. // // word-by-word-montgomery --lang Go --no-wide-int // --relax-primitive-carry-to-bitwidth 32,64 --cmovznz-by-mul --static @@ -112,60 +106,12 @@ func p256OrdSqr(out1, arg1 *p256OrdMontElement, n int) { // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Autogenerated: fiat_crypto.js word-by-word-montgomery --lang Go --no-wide-int --relax-primitive-carry-to-bitwidth 32,64 --cmovznz-by-mul --static --package-case flatcase --private-function-case camelCase --private-type-case camelCase --no-prefix-fiat --package-name nistec p256Ord 64 2^256-2^224+2^192-89188191075325690597107910205041859247 mul square from_montgomery to_montgomery -// -// curve description: p256Ord -// -// machine_wordsize = 64 (from "64") -// -// requested operations: mul, square, from_montgomery, to_montgomery -// -// m = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 (from "2^256-2^224+2^192-89188191075325690597107910205041859247") -// -// -// -// NOTE: In addition to the bounds specified above each function, all -// -// functions synthesized for this Montgomery arithmetic require the -// -// input to be strictly less than the prime modulus (m), and also -// -// require the input to be in the unique saturated representation. -// -// All functions also ensure that these two properties are true of -// -// return values. -// -// -// -// Computed values: -// -// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) -// -// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) -// -// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in -// -// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 - -type p256OrdUint1 = uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 - -// The type p256OrdMontElement is a field element in the Montgomery domain. -// -// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// p256OrdMontElement is a scalar field element in the Montgomery domain, as +// four uint64 limbs in little-endian order. It must be strictly less than +// ord(G) and in Montgomery form (with R 2²⁵⁶). type p256OrdMontElement [4]uint64 -// The function p256OrdMul multiplies two field elements in the Montgomery domain. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// 0 ≤ eval arg2 < m -// -// Postconditions: -// -// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m -// 0 ≤ eval out1 < m +// p256OrdMul multiplies two field elements in the Montgomery domain. func p256OrdMul(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, arg2 *p256OrdMontElement) { x1 := arg1[1] x2 := arg1[2] @@ -282,170 +228,144 @@ func p256OrdMul(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, arg2 *p256Or x210, x211 := bits.Sub64(x201, 0xffffffffffffffff, x209) x212, x213 := bits.Sub64(x203, 0xffffffff00000000, x211) _, x215 := bits.Sub64(x205, 0, x213) - var x216 uint64 - p256OrdCmovznzU64(&x216, x215, x206, x197) - var x217 uint64 - p256OrdCmovznzU64(&x217, x215, x208, x199) - var x218 uint64 - p256OrdCmovznzU64(&x218, x215, x210, x201) - var x219 uint64 - p256OrdCmovznzU64(&x219, x215, x212, x203) - out1[0] = x216 - out1[1] = x217 - out1[2] = x218 - out1[3] = x219 + mask, _ := bits.Sub64(0, 0, x215) + out1[0] = x206&^mask | x197&mask + out1[1] = x208&^mask | x199&mask + out1[2] = x210&^mask | x201&mask + out1[3] = x212&^mask | x203&mask } -// The function p256OrdSquare squares a field element in the Montgomery domain. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// -// Postconditions: -// -// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m -// 0 ≤ eval out1 < m -func p256OrdSquare(out1 *p256OrdMontElement, arg1 *p256OrdMontElement) { +// p256OrdSqr squares n times a field element in the Montgomery domain. +func p256OrdSqr(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, n int) { x1 := arg1[1] x2 := arg1[2] x3 := arg1[3] x4 := arg1[0] - x6, x5 := bits.Mul64(x4, arg1[3]) - x8, x7 := bits.Mul64(x4, arg1[2]) - x10, x9 := bits.Mul64(x4, arg1[1]) - x12, x11 := bits.Mul64(x4, arg1[0]) - x13, x14 := bits.Add64(x12, x9, 0) - x15, x16 := bits.Add64(x10, x7, x14) - x17, x18 := bits.Add64(x8, x5, x16) - x19 := x18 + x6 - _, x20 := bits.Mul64(x11, 0xccd1c8aaee00bc4f) - x23, x22 := bits.Mul64(x20, 0xffffffff00000000) - x25, x24 := bits.Mul64(x20, 0xffffffffffffffff) - x27, x26 := bits.Mul64(x20, 0xbce6faada7179e84) - x29, x28 := bits.Mul64(x20, 0xf3b9cac2fc632551) - x30, x31 := bits.Add64(x29, x26, 0) - x32, x33 := bits.Add64(x27, x24, x31) - x34, x35 := bits.Add64(x25, x22, x33) - x36 := x35 + x23 - _, x38 := bits.Add64(x11, x28, 0) - x39, x40 := bits.Add64(x13, x30, x38) - x41, x42 := bits.Add64(x15, x32, x40) - x43, x44 := bits.Add64(x17, x34, x42) - x45, x46 := bits.Add64(x19, x36, x44) - x48, x47 := bits.Mul64(x1, arg1[3]) - x50, x49 := bits.Mul64(x1, arg1[2]) - x52, x51 := bits.Mul64(x1, arg1[1]) - x54, x53 := bits.Mul64(x1, arg1[0]) - x55, x56 := bits.Add64(x54, x51, 0) - x57, x58 := bits.Add64(x52, x49, x56) - x59, x60 := bits.Add64(x50, x47, x58) - x61 := x60 + x48 - x62, x63 := bits.Add64(x39, x53, 0) - x64, x65 := bits.Add64(x41, x55, x63) - x66, x67 := bits.Add64(x43, x57, x65) - x68, x69 := bits.Add64(x45, x59, x67) - x70, x71 := bits.Add64(x46, x61, x69) - _, x72 := bits.Mul64(x62, 0xccd1c8aaee00bc4f) - x75, x74 := bits.Mul64(x72, 0xffffffff00000000) - x77, x76 := bits.Mul64(x72, 0xffffffffffffffff) - x79, x78 := bits.Mul64(x72, 0xbce6faada7179e84) - x81, x80 := bits.Mul64(x72, 0xf3b9cac2fc632551) - x82, x83 := bits.Add64(x81, x78, 0) - x84, x85 := bits.Add64(x79, x76, x83) - x86, x87 := bits.Add64(x77, x74, x85) - x88 := x87 + x75 - _, x90 := bits.Add64(x62, x80, 0) - x91, x92 := bits.Add64(x64, x82, x90) - x93, x94 := bits.Add64(x66, x84, x92) - x95, x96 := bits.Add64(x68, x86, x94) - x97, x98 := bits.Add64(x70, x88, x96) - x99 := x98 + x71 - x101, x100 := bits.Mul64(x2, arg1[3]) - x103, x102 := bits.Mul64(x2, arg1[2]) - x105, x104 := bits.Mul64(x2, arg1[1]) - x107, x106 := bits.Mul64(x2, arg1[0]) - x108, x109 := bits.Add64(x107, x104, 0) - x110, x111 := bits.Add64(x105, x102, x109) - x112, x113 := bits.Add64(x103, x100, x111) - x114 := x113 + x101 - x115, x116 := bits.Add64(x91, x106, 0) - x117, x118 := bits.Add64(x93, x108, x116) - x119, x120 := bits.Add64(x95, x110, x118) - x121, x122 := bits.Add64(x97, x112, x120) - x123, x124 := bits.Add64(x99, x114, x122) - _, x125 := bits.Mul64(x115, 0xccd1c8aaee00bc4f) - x128, x127 := bits.Mul64(x125, 0xffffffff00000000) - x130, x129 := bits.Mul64(x125, 0xffffffffffffffff) - x132, x131 := bits.Mul64(x125, 0xbce6faada7179e84) - x134, x133 := bits.Mul64(x125, 0xf3b9cac2fc632551) - x135, x136 := bits.Add64(x134, x131, 0) - x137, x138 := bits.Add64(x132, x129, x136) - x139, x140 := bits.Add64(x130, x127, x138) - x141 := x140 + x128 - _, x143 := bits.Add64(x115, x133, 0) - x144, x145 := bits.Add64(x117, x135, x143) - x146, x147 := bits.Add64(x119, x137, x145) - x148, x149 := bits.Add64(x121, x139, x147) - x150, x151 := bits.Add64(x123, x141, x149) - x152 := x151 + x124 - x154, x153 := bits.Mul64(x3, arg1[3]) - x156, x155 := bits.Mul64(x3, arg1[2]) - x158, x157 := bits.Mul64(x3, arg1[1]) - x160, x159 := bits.Mul64(x3, arg1[0]) - x161, x162 := bits.Add64(x160, x157, 0) - x163, x164 := bits.Add64(x158, x155, x162) - x165, x166 := bits.Add64(x156, x153, x164) - x167 := x166 + x154 - x168, x169 := bits.Add64(x144, x159, 0) - x170, x171 := bits.Add64(x146, x161, x169) - x172, x173 := bits.Add64(x148, x163, x171) - x174, x175 := bits.Add64(x150, x165, x173) - x176, x177 := bits.Add64(x152, x167, x175) - _, x178 := bits.Mul64(x168, 0xccd1c8aaee00bc4f) - x181, x180 := bits.Mul64(x178, 0xffffffff00000000) - x183, x182 := bits.Mul64(x178, 0xffffffffffffffff) - x185, x184 := bits.Mul64(x178, 0xbce6faada7179e84) - x187, x186 := bits.Mul64(x178, 0xf3b9cac2fc632551) - x188, x189 := bits.Add64(x187, x184, 0) - x190, x191 := bits.Add64(x185, x182, x189) - x192, x193 := bits.Add64(x183, x180, x191) - x194 := x193 + x181 - _, x196 := bits.Add64(x168, x186, 0) - x197, x198 := bits.Add64(x170, x188, x196) - x199, x200 := bits.Add64(x172, x190, x198) - x201, x202 := bits.Add64(x174, x192, x200) - x203, x204 := bits.Add64(x176, x194, x202) - x205 := x204 + x177 - x206, x207 := bits.Sub64(x197, 0xf3b9cac2fc632551, 0) - x208, x209 := bits.Sub64(x199, 0xbce6faada7179e84, x207) - x210, x211 := bits.Sub64(x201, 0xffffffffffffffff, x209) - x212, x213 := bits.Sub64(x203, 0xffffffff00000000, x211) - _, x215 := bits.Sub64(x205, 0, x213) - var x216 uint64 - p256OrdCmovznzU64(&x216, x215, x206, x197) - var x217 uint64 - p256OrdCmovznzU64(&x217, x215, x208, x199) - var x218 uint64 - p256OrdCmovznzU64(&x218, x215, x210, x201) - var x219 uint64 - p256OrdCmovznzU64(&x219, x215, x212, x203) - out1[0] = x216 - out1[1] = x217 - out1[2] = x218 - out1[3] = x219 + for range n { + x6, x5 := bits.Mul64(x4, x3) + x8, x7 := bits.Mul64(x4, x2) + x10, x9 := bits.Mul64(x4, x1) + x12, x11 := bits.Mul64(x4, x4) + x13, x14 := bits.Add64(x12, x9, 0) + x15, x16 := bits.Add64(x10, x7, x14) + x17, x18 := bits.Add64(x8, x5, x16) + x19 := x18 + x6 + _, x20 := bits.Mul64(x11, 0xccd1c8aaee00bc4f) + x23, x22 := bits.Mul64(x20, 0xffffffff00000000) + x25, x24 := bits.Mul64(x20, 0xffffffffffffffff) + x27, x26 := bits.Mul64(x20, 0xbce6faada7179e84) + x29, x28 := bits.Mul64(x20, 0xf3b9cac2fc632551) + x30, x31 := bits.Add64(x29, x26, 0) + x32, x33 := bits.Add64(x27, x24, x31) + x34, x35 := bits.Add64(x25, x22, x33) + x36 := x35 + x23 + _, x38 := bits.Add64(x11, x28, 0) + x39, x40 := bits.Add64(x13, x30, x38) + x41, x42 := bits.Add64(x15, x32, x40) + x43, x44 := bits.Add64(x17, x34, x42) + x45, x46 := bits.Add64(x19, x36, x44) + x48, x47 := bits.Mul64(x1, x3) + x50, x49 := bits.Mul64(x1, x2) + x52, x51 := bits.Mul64(x1, x1) + x54, x53 := bits.Mul64(x1, x4) + x55, x56 := bits.Add64(x54, x51, 0) + x57, x58 := bits.Add64(x52, x49, x56) + x59, x60 := bits.Add64(x50, x47, x58) + x61 := x60 + x48 + x62, x63 := bits.Add64(x39, x53, 0) + x64, x65 := bits.Add64(x41, x55, x63) + x66, x67 := bits.Add64(x43, x57, x65) + x68, x69 := bits.Add64(x45, x59, x67) + x70, x71 := bits.Add64(x46, x61, x69) + _, x72 := bits.Mul64(x62, 0xccd1c8aaee00bc4f) + x75, x74 := bits.Mul64(x72, 0xffffffff00000000) + x77, x76 := bits.Mul64(x72, 0xffffffffffffffff) + x79, x78 := bits.Mul64(x72, 0xbce6faada7179e84) + x81, x80 := bits.Mul64(x72, 0xf3b9cac2fc632551) + x82, x83 := bits.Add64(x81, x78, 0) + x84, x85 := bits.Add64(x79, x76, x83) + x86, x87 := bits.Add64(x77, x74, x85) + x88 := x87 + x75 + _, x90 := bits.Add64(x62, x80, 0) + x91, x92 := bits.Add64(x64, x82, x90) + x93, x94 := bits.Add64(x66, x84, x92) + x95, x96 := bits.Add64(x68, x86, x94) + x97, x98 := bits.Add64(x70, x88, x96) + x99 := x98 + x71 + x101, x100 := bits.Mul64(x2, x3) + x103, x102 := bits.Mul64(x2, x2) + x105, x104 := bits.Mul64(x2, x1) + x107, x106 := bits.Mul64(x2, x4) + x108, x109 := bits.Add64(x107, x104, 0) + x110, x111 := bits.Add64(x105, x102, x109) + x112, x113 := bits.Add64(x103, x100, x111) + x114 := x113 + x101 + x115, x116 := bits.Add64(x91, x106, 0) + x117, x118 := bits.Add64(x93, x108, x116) + x119, x120 := bits.Add64(x95, x110, x118) + x121, x122 := bits.Add64(x97, x112, x120) + x123, x124 := bits.Add64(x99, x114, x122) + _, x125 := bits.Mul64(x115, 0xccd1c8aaee00bc4f) + x128, x127 := bits.Mul64(x125, 0xffffffff00000000) + x130, x129 := bits.Mul64(x125, 0xffffffffffffffff) + x132, x131 := bits.Mul64(x125, 0xbce6faada7179e84) + x134, x133 := bits.Mul64(x125, 0xf3b9cac2fc632551) + x135, x136 := bits.Add64(x134, x131, 0) + x137, x138 := bits.Add64(x132, x129, x136) + x139, x140 := bits.Add64(x130, x127, x138) + x141 := x140 + x128 + _, x143 := bits.Add64(x115, x133, 0) + x144, x145 := bits.Add64(x117, x135, x143) + x146, x147 := bits.Add64(x119, x137, x145) + x148, x149 := bits.Add64(x121, x139, x147) + x150, x151 := bits.Add64(x123, x141, x149) + x152 := x151 + x124 + x154, x153 := bits.Mul64(x3, x3) + x156, x155 := bits.Mul64(x3, x2) + x158, x157 := bits.Mul64(x3, x1) + x160, x159 := bits.Mul64(x3, x4) + x161, x162 := bits.Add64(x160, x157, 0) + x163, x164 := bits.Add64(x158, x155, x162) + x165, x166 := bits.Add64(x156, x153, x164) + x167 := x166 + x154 + x168, x169 := bits.Add64(x144, x159, 0) + x170, x171 := bits.Add64(x146, x161, x169) + x172, x173 := bits.Add64(x148, x163, x171) + x174, x175 := bits.Add64(x150, x165, x173) + x176, x177 := bits.Add64(x152, x167, x175) + _, x178 := bits.Mul64(x168, 0xccd1c8aaee00bc4f) + x181, x180 := bits.Mul64(x178, 0xffffffff00000000) + x183, x182 := bits.Mul64(x178, 0xffffffffffffffff) + x185, x184 := bits.Mul64(x178, 0xbce6faada7179e84) + x187, x186 := bits.Mul64(x178, 0xf3b9cac2fc632551) + x188, x189 := bits.Add64(x187, x184, 0) + x190, x191 := bits.Add64(x185, x182, x189) + x192, x193 := bits.Add64(x183, x180, x191) + x194 := x193 + x181 + _, x196 := bits.Add64(x168, x186, 0) + x197, x198 := bits.Add64(x170, x188, x196) + x199, x200 := bits.Add64(x172, x190, x198) + x201, x202 := bits.Add64(x174, x192, x200) + x203, x204 := bits.Add64(x176, x194, x202) + x205 := x204 + x177 + x206, x207 := bits.Sub64(x197, 0xf3b9cac2fc632551, 0) + x208, x209 := bits.Sub64(x199, 0xbce6faada7179e84, x207) + x210, x211 := bits.Sub64(x201, 0xffffffffffffffff, x209) + x212, x213 := bits.Sub64(x203, 0xffffffff00000000, x211) + _, x215 := bits.Sub64(x205, 0, x213) + mask, _ := bits.Sub64(0, 0, x215) + x4 = x206&^mask | x197&mask + x1 = x208&^mask | x199&mask + x2 = x210&^mask | x201&mask + x3 = x212&^mask | x203&mask + } + out1[0] = x4 + out1[1] = x1 + out1[2] = x2 + out1[3] = x3 } -// The function p256OrdFromMontgomery translates a field element out of the Montgomery domain. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// -// Postconditions: -// -// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m -// 0 ≤ eval out1 < m +// p256OrdFromMontgomery translates a field element out of the Montgomery domain. func p256OrdFromMontgomery(out1 *p256OrdElement, arg1 *p256OrdMontElement) { x1 := arg1[0] _, x2 := bits.Mul64(x1, 0xccd1c8aaee00bc4f) @@ -510,31 +430,14 @@ func p256OrdFromMontgomery(out1 *p256OrdElement, arg1 *p256OrdMontElement) { x119, x120 := bits.Sub64(x112, 0xbce6faada7179e84, x118) x121, x122 := bits.Sub64(x114, 0xffffffffffffffff, x120) x123, x124 := bits.Sub64(x116, 0xffffffff00000000, x122) - _, x126 := bits.Sub64(0, 0, x124) - var x127 uint64 - p256OrdCmovznzU64(&x127, x126, x117, x110) - var x128 uint64 - p256OrdCmovznzU64(&x128, x126, x119, x112) - var x129 uint64 - p256OrdCmovznzU64(&x129, x126, x121, x114) - var x130 uint64 - p256OrdCmovznzU64(&x130, x126, x123, x116) - out1[0] = x127 - out1[1] = x128 - out1[2] = x129 - out1[3] = x130 + mask, _ := bits.Sub64(0, 0, x124) + out1[0] = x117&^mask | x110&mask + out1[1] = x119&^mask | x112&mask + out1[2] = x121&^mask | x114&mask + out1[3] = x123&^mask | x116&mask } -// The function p256OrdToMontgomery translates a field element into the Montgomery domain. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// -// Postconditions: -// -// eval (from_montgomery out1) mod m = eval arg1 mod m -// 0 ≤ eval out1 < m +// p256OrdToMontgomery translates a field element into the Montgomery domain. func p256OrdToMontgomery(out1 *p256OrdMontElement, arg1 *p256OrdElement) { x1 := arg1[1] x2 := arg1[2] @@ -637,37 +540,9 @@ func p256OrdToMontgomery(out1 *p256OrdMontElement, arg1 *p256OrdElement) { x193, x194 := bits.Sub64(x185, 0xffffffffffffffff, x192) x195, x196 := bits.Sub64(x187, 0xffffffff00000000, x194) _, x198 := bits.Sub64(x188, 0, x196) - var x199 uint64 - p256OrdCmovznzU64(&x199, x198, x189, x181) - var x200 uint64 - p256OrdCmovznzU64(&x200, x198, x191, x183) - var x201 uint64 - p256OrdCmovznzU64(&x201, x198, x193, x185) - var x202 uint64 - p256OrdCmovznzU64(&x202, x198, x195, x187) - out1[0] = x199 - out1[1] = x200 - out1[2] = x201 - out1[3] = x202 -} - -// The function p256OrdCmovznzU64 is a single-word conditional move. -// -// Postconditions: -// -// out1 = (if arg1 = 0 then arg2 else arg3) -// -// Input Bounds: -// -// arg1: [0x0 ~> 0x1] -// arg2: [0x0 ~> 0xffffffffffffffff] -// arg3: [0x0 ~> 0xffffffffffffffff] -// -// Output Bounds: -// -// out1: [0x0 ~> 0xffffffffffffffff] -func p256OrdCmovznzU64(out1 *uint64, arg1 uint64, arg2 uint64, arg3 uint64) { - x1 := arg1 * 0xffffffffffffffff - x2 := x1&arg3 | ^x1&arg2 - *out1 = x2 + mask, _ := bits.Sub64(0, 0, x198) + out1[0] = x189&^mask | x181&mask + out1[1] = x191&^mask | x183&mask + out1[2] = x193&^mask | x185&mask + out1[3] = x195&^mask | x187&mask } From 244c8ae4c885fd0db8988a5734ac644f4f52eb51 Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Wed, 20 May 2026 19:55:10 +0300 Subject: [PATCH 18/18] crypto/internal/fips140/nistec: avoid some mul64 in p256 calculations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit x * 0xffffffff00000000 = x * (2^64 - 2^32) x * 0xffffffffffffffff = x * (2^64 - 1) Comparing to parent commit: goos: darwin goarch: arm64 pkg: crypto/ecdsa cpu: Apple M4 Max │ OLD │ NEW │ │ sec/op │ sec/op vs base │ Sign/P256-16 15.83µ ± 1% 15.18µ ± 1% -4.06% (p=0.002 n=6) Sign/P384-16 108.0µ ± 0% 107.6µ ± 1% -0.36% (p=0.041 n=6) Sign/P521-16 264.5µ ± 0% 262.9µ ± 0% -0.61% (p=0.002 n=6) Verify/P256-16 35.89µ ± 0% 35.23µ ± 0% -1.84% (p=0.002 n=6) Verify/P384-16 322.4µ ± 0% 321.6µ ± 0% -0.28% (p=0.041 n=6) Verify/P521-16 850.3µ ± 0% 847.4µ ± 0% -0.35% (p=0.002 n=6) GenerateKey/P256-16 7.241µ ± 0% 7.125µ ± 1% -1.60% (p=0.002 n=6) GenerateKey/P384-16 71.03µ ± 0% 70.94µ ± 0% -0.13% (p=0.041 n=6) GenerateKey/P521-16 180.6µ ± 0% 180.1µ ± 0% -0.31% (p=0.002 n=6) geomean 90.65µ 89.68µ -1.07% Change-Id: If8d659a76624dce1c53e23e6ed201189476e3f6b Reviewed-on: https://go-review.googlesource.com/c/go/+/780640 Reviewed-by: Filippo Valsorda Auto-Submit: Filippo Valsorda Reviewed-by: Michael Pratt Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- .../internal/fips140/nistec/p256_ordinv.go | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/crypto/internal/fips140/nistec/p256_ordinv.go b/src/crypto/internal/fips140/nistec/p256_ordinv.go index a65f27c8142629..b8a51dedd09349 100644 --- a/src/crypto/internal/fips140/nistec/p256_ordinv.go +++ b/src/crypto/internal/fips140/nistec/p256_ordinv.go @@ -126,8 +126,12 @@ func p256OrdMul(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, arg2 *p256Or x17, x18 := bits.Add64(x8, x5, x16) x19 := x18 + x6 _, x20 := bits.Mul64(x11, 0xccd1c8aaee00bc4f) - x23, x22 := bits.Mul64(x20, 0xffffffff00000000) - x25, x24 := bits.Mul64(x20, 0xffffffffffffffff) + // x20 * 0xffffffff00000000 = x20 * (2^64 - 2^32) + x22, b22 := bits.Sub64(0, x20<<32, 0) + x23 := x20 - (x20 >> 32) - b22 + // x20 * 0xffffffffffffffff = x20 * (2^64 - 1) + x24, b24 := bits.Sub64(0, x20, 0) + x25 := x20 - b24 x27, x26 := bits.Mul64(x20, 0xbce6faada7179e84) x29, x28 := bits.Mul64(x20, 0xf3b9cac2fc632551) x30, x31 := bits.Add64(x29, x26, 0) @@ -153,8 +157,10 @@ func p256OrdMul(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, arg2 *p256Or x68, x69 := bits.Add64(x45, x59, x67) x70, x71 := bits.Add64(x46, x61, x69) _, x72 := bits.Mul64(x62, 0xccd1c8aaee00bc4f) - x75, x74 := bits.Mul64(x72, 0xffffffff00000000) - x77, x76 := bits.Mul64(x72, 0xffffffffffffffff) + x74, b74 := bits.Sub64(0, x72<<32, 0) + x75 := x72 - (x72 >> 32) - b74 + x76, b76 := bits.Sub64(0, x72, 0) + x77 := x72 - b76 x79, x78 := bits.Mul64(x72, 0xbce6faada7179e84) x81, x80 := bits.Mul64(x72, 0xf3b9cac2fc632551) x82, x83 := bits.Add64(x81, x78, 0) @@ -181,8 +187,10 @@ func p256OrdMul(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, arg2 *p256Or x121, x122 := bits.Add64(x97, x112, x120) x123, x124 := bits.Add64(x99, x114, x122) _, x125 := bits.Mul64(x115, 0xccd1c8aaee00bc4f) - x128, x127 := bits.Mul64(x125, 0xffffffff00000000) - x130, x129 := bits.Mul64(x125, 0xffffffffffffffff) + x127, b127 := bits.Sub64(0, x125<<32, 0) + x128 := x125 - (x125 >> 32) - b127 + x129, b129 := bits.Sub64(0, x125, 0) + x130 := x125 - b129 x132, x131 := bits.Mul64(x125, 0xbce6faada7179e84) x134, x133 := bits.Mul64(x125, 0xf3b9cac2fc632551) x135, x136 := bits.Add64(x134, x131, 0) @@ -209,8 +217,10 @@ func p256OrdMul(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, arg2 *p256Or x174, x175 := bits.Add64(x150, x165, x173) x176, x177 := bits.Add64(x152, x167, x175) _, x178 := bits.Mul64(x168, 0xccd1c8aaee00bc4f) - x181, x180 := bits.Mul64(x178, 0xffffffff00000000) - x183, x182 := bits.Mul64(x178, 0xffffffffffffffff) + x180, b180 := bits.Sub64(0, x178<<32, 0) + x181 := x178 - (x178 >> 32) - b180 + x182, b182 := bits.Sub64(0, x178, 0) + x183 := x178 - b182 x185, x184 := bits.Mul64(x178, 0xbce6faada7179e84) x187, x186 := bits.Mul64(x178, 0xf3b9cac2fc632551) x188, x189 := bits.Add64(x187, x184, 0) @@ -251,8 +261,10 @@ func p256OrdSqr(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, n int) { x17, x18 := bits.Add64(x8, x5, x16) x19 := x18 + x6 _, x20 := bits.Mul64(x11, 0xccd1c8aaee00bc4f) - x23, x22 := bits.Mul64(x20, 0xffffffff00000000) - x25, x24 := bits.Mul64(x20, 0xffffffffffffffff) + x22, b22 := bits.Sub64(0, x20<<32, 0) + x23 := x20 - (x20 >> 32) - b22 + x24, b24 := bits.Sub64(0, x20, 0) + x25 := x20 - b24 x27, x26 := bits.Mul64(x20, 0xbce6faada7179e84) x29, x28 := bits.Mul64(x20, 0xf3b9cac2fc632551) x30, x31 := bits.Add64(x29, x26, 0) @@ -278,8 +290,10 @@ func p256OrdSqr(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, n int) { x68, x69 := bits.Add64(x45, x59, x67) x70, x71 := bits.Add64(x46, x61, x69) _, x72 := bits.Mul64(x62, 0xccd1c8aaee00bc4f) - x75, x74 := bits.Mul64(x72, 0xffffffff00000000) - x77, x76 := bits.Mul64(x72, 0xffffffffffffffff) + x74, b74 := bits.Sub64(0, x72<<32, 0) + x75 := x72 - (x72 >> 32) - b74 + x76, b76 := bits.Sub64(0, x72, 0) + x77 := x72 - b76 x79, x78 := bits.Mul64(x72, 0xbce6faada7179e84) x81, x80 := bits.Mul64(x72, 0xf3b9cac2fc632551) x82, x83 := bits.Add64(x81, x78, 0) @@ -306,8 +320,10 @@ func p256OrdSqr(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, n int) { x121, x122 := bits.Add64(x97, x112, x120) x123, x124 := bits.Add64(x99, x114, x122) _, x125 := bits.Mul64(x115, 0xccd1c8aaee00bc4f) - x128, x127 := bits.Mul64(x125, 0xffffffff00000000) - x130, x129 := bits.Mul64(x125, 0xffffffffffffffff) + x127, b127 := bits.Sub64(0, x125<<32, 0) + x128 := x125 - (x125 >> 32) - b127 + x129, b129 := bits.Sub64(0, x125, 0) + x130 := x125 - b129 x132, x131 := bits.Mul64(x125, 0xbce6faada7179e84) x134, x133 := bits.Mul64(x125, 0xf3b9cac2fc632551) x135, x136 := bits.Add64(x134, x131, 0) @@ -334,8 +350,10 @@ func p256OrdSqr(out1 *p256OrdMontElement, arg1 *p256OrdMontElement, n int) { x174, x175 := bits.Add64(x150, x165, x173) x176, x177 := bits.Add64(x152, x167, x175) _, x178 := bits.Mul64(x168, 0xccd1c8aaee00bc4f) - x181, x180 := bits.Mul64(x178, 0xffffffff00000000) - x183, x182 := bits.Mul64(x178, 0xffffffffffffffff) + x180, b180 := bits.Sub64(0, x178<<32, 0) + x181 := x178 - (x178 >> 32) - b180 + x182, b182 := bits.Sub64(0, x178, 0) + x183 := x178 - b182 x185, x184 := bits.Mul64(x178, 0xbce6faada7179e84) x187, x186 := bits.Mul64(x178, 0xf3b9cac2fc632551) x188, x189 := bits.Add64(x187, x184, 0)