diff --git a/eng/_util/cmd/updatecryptodocs/docs.go b/eng/_util/cmd/updatecryptodocs/docs.go
index 65ff3207e3f..a5364711f09 100644
--- a/eng/_util/cmd/updatecryptodocs/docs.go
+++ b/eng/_util/cmd/updatecryptodocs/docs.go
@@ -266,7 +266,7 @@ var doc = Document{
},
{
Title: "Asymmetric encryption",
- Packages: []string{"RSA", "ECDSA", "ECDH", "Ed25519", "DSA"},
+ Packages: []string{"RSA", "ECDSA", "ECDH", "Ed25519", "ML-DSA", "DSA"},
Description: "",
Subsections: []Section{
{
@@ -486,6 +486,39 @@ var doc = Document{
},
},
},
+ {
+ Title: "ML-DSA",
+ ColumnHeader: "Parameters",
+ Packages: []string{"crypto/mldsa"},
+ MinGoVersion: "1.27",
+ Description: "Operations that require random numbers (rand io.Reader) only support [rand.Reader](https://pkg.go.dev/crypto/rand#Reader). Deterministic signing is always performed by the Go cryptographic module. External-mu signing falls back to the Go cryptographic module on platforms whose backend does not implement it (currently macOS).",
+ Items: []Item{
+ {
+ Name: "44",
+ Platforms: Platforms{
+ Windows: PlatformStatus{MinVersion: "11 (24H2)"},
+ Linux: PlatformStatus{MinVersion: "3.5.0"},
+ MacOS: PlatformStatus{Supported: NotSupported},
+ },
+ },
+ {
+ Name: "65",
+ Platforms: Platforms{
+ Windows: PlatformStatus{MinVersion: "11 (24H2)"},
+ Linux: PlatformStatus{MinVersion: "3.5.0"},
+ MacOS: PlatformStatus{MinVersion: "26"},
+ },
+ },
+ {
+ Name: "87",
+ Platforms: Platforms{
+ Windows: PlatformStatus{MinVersion: "11 (24H2)"},
+ Linux: PlatformStatus{MinVersion: "3.5.0"},
+ MacOS: PlatformStatus{MinVersion: "26"},
+ },
+ },
+ },
+ },
{
Title: "DSA",
ColumnHeader: "Parameters",
diff --git a/eng/doc/CrossPlatformCryptography.md b/eng/doc/CrossPlatformCryptography.md
index 095c0ef7429..5cc611a494a 100644
--- a/eng/doc/CrossPlatformCryptography.md
+++ b/eng/doc/CrossPlatformCryptography.md
@@ -136,6 +136,7 @@ This section includes the following subsections:
- [ECDSA](#ecdsa)
- [ECDH](#ecdh)
- [Ed25519](#ed25519)
+- [ML-DSA](#ml-dsa)
- [DSA](#dsa)
### RSA
@@ -234,6 +235,28 @@ Operations that require random numbers (rand io.Reader) only support [rand.Reade
| Ed25519ctx | ❌️ | ❌️ | ❌️ |
| Ed25519ph | ❌️ | ❌️ | ❌️ |
+### ML-DSA
+
+This section includes the following packages:
+
+- [crypto/mldsa](https://pkg.go.dev/crypto/mldsa)
+
+ML-DSA is available starting from the Microsoft build of Go 1.27.
+
+Operations that require random numbers (rand io.Reader) only support [rand.Reader](https://pkg.go.dev/crypto/rand#Reader). Deterministic signing is always performed by the Go cryptographic module. External-mu signing falls back to the Go cryptographic module on platforms whose backend does not implement it (currently macOS).
+
+| Parameters | Windows | Linux | macOS |
+| ---------- | -------------- | -------------- | -------------- |
+| 44 | ✔️1 | ✔️2 | ❌️ |
+| 65 | ✔️1 | ✔️2 | ✔️3 |
+| 87 | ✔️1 | ✔️2 | ✔️3 |
+
+1Requires Windows 11 (24H2) or later.
+
+2Requires OpenSSL 3.5.0 or later.
+
+3Requires macOS 26 or later.
+
### DSA
| Parameters | Windows | Linux | macOS |
diff --git a/patches/0001-Vendor-external-dependencies.patch b/patches/0001-Vendor-external-dependencies.patch
index 58d2cf993e9..60a42cf88b4 100644
--- a/patches/0001-Vendor-external-dependencies.patch
+++ b/patches/0001-Vendor-external-dependencies.patch
@@ -34,7 +34,7 @@ Use a 'go' that was recently built by the current branch to ensure stable result
.../microsoft/go-infra/telemetry/telemetry.go | 168 ++
src/cmd/vendor/modules.txt | 11 +
src/crypto/internal/backend/deps_ignore.go | 22 +
- src/go.mod | 6 +
+ src/go.mod | 11 +-
src/go.sum | 6 +
src/go/build/deps_test.go | 55 +-
src/go/build/vendor_test.go | 4 +
@@ -59,32 +59,32 @@ Use a 'go' that was recently built by the current branch to ensure stable result
.../internal/cryptokit/zcryptokit.c | 317 +++
.../internal/cryptokit/zcryptokit.h | 77 +
.../internal/cryptokit/zcryptokit.s | 400 +++
- .../internal/cryptokit/zcryptokit_cgo.go | 386 +++
- .../internal/cryptokit/zcryptokit_nocgo.go | 441 +++
+ .../internal/cryptokit/zcryptokit_cgo.go | 401 +++
+ .../internal/cryptokit/zcryptokit_nocgo.go | 456 +++
.../cryptokit/zcryptokit_swift_amd64.go | 307 ++
.../cryptokit/zcryptokit_swift_arm64.go | 306 ++
- .../internal/fakecgo/abi_amd64.h | 99 +
- .../internal/fakecgo/abi_arm64.h | 39 +
- .../internal/fakecgo/asm_amd64.s | 39 +
- .../internal/fakecgo/asm_arm64.s | 36 +
- .../internal/fakecgo/callbacks.go | 93 +
- .../internal/fakecgo/fakecgo.go | 14 +
+ .../internal/fakecgo/abi_amd64.h | 101 +
+ .../internal/fakecgo/abi_arm64.h | 41 +
+ .../internal/fakecgo/asm_amd64.s | 41 +
+ .../internal/fakecgo/asm_arm64.s | 37 +
+ .../internal/fakecgo/callbacks.go | 95 +
+ .../internal/fakecgo/fakecgo.go | 16 +
.../internal/fakecgo/fakecgo.lock | 3 +
.../internal/fakecgo/generate.go | 6 +
- .../internal/fakecgo/go_darwin.go | 88 +
- .../internal/fakecgo/go_libinit.go | 72 +
- .../internal/fakecgo/go_setenv.go | 18 +
- .../internal/fakecgo/go_util.go | 38 +
- .../internal/fakecgo/iscgo.go | 19 +
- .../internal/fakecgo/libcgo.go | 39 +
- .../internal/fakecgo/libcgo_darwin.go | 26 +
- .../internal/fakecgo/setenv.go | 19 +
- .../internal/fakecgo/trampolines_amd64.s | 107 +
- .../internal/fakecgo/trampolines_arm64.s | 81 +
- .../internal/fakecgo/zsymbols.go | 165 ++
- .../internal/fakecgo/zsymbols_darwin.go | 59 +
- .../internal/fakecgo/ztrampolines_darwin.s | 19 +
- .../internal/fakecgo/ztrampolines_stubs.s | 55 +
+ .../internal/fakecgo/go_darwin.go | 90 +
+ .../internal/fakecgo/go_libinit.go | 74 +
+ .../internal/fakecgo/go_setenv.go | 20 +
+ .../internal/fakecgo/go_util.go | 40 +
+ .../internal/fakecgo/iscgo.go | 21 +
+ .../internal/fakecgo/libcgo.go | 41 +
+ .../internal/fakecgo/libcgo_darwin.go | 28 +
+ .../internal/fakecgo/setenv.go | 21 +
+ .../internal/fakecgo/trampolines_amd64.s | 109 +
+ .../internal/fakecgo/trampolines_arm64.s | 83 +
+ .../internal/fakecgo/zsymbols.go | 167 ++
+ .../internal/fakecgo/zsymbols_darwin.go | 61 +
+ .../internal/fakecgo/ztrampolines_darwin.s | 21 +
+ .../internal/fakecgo/ztrampolines_stubs.s | 57 +
.../internal/security/security.go | 9 +
.../internal/security/shims.h | 107 +
.../internal/security/syscall_nocgo.go | 15 +
@@ -93,7 +93,7 @@ Use a 'go' that was recently built by the current branch to ensure stable result
.../internal/security/zsecurity.h | 98 +
.../internal/security/zsecurity.s | 172 ++
.../internal/security/zsecurity_cgo.go | 388 +++
- .../internal/security/zsecurity_nocgo.go | 466 ++++
+ .../internal/security/zsecurity_nocgo.go | 466 +++
.../internal/xsyscall/asm_amd64.s | 120 +
.../internal/xsyscall/asm_arm64.s | 97 +
.../internal/xsyscall/syscall_nocgo.go | 72 +
@@ -110,10 +110,10 @@ Use a 'go' that was recently built by the current branch to ensure stable result
.../go-crypto-darwin/xcrypto/ed25519.go | 124 +
.../microsoft/go-crypto-darwin/xcrypto/evp.go | 339 +++
.../microsoft/go-crypto-darwin/xcrypto/gcm.go | 218 ++
- .../go-crypto-darwin/xcrypto/hash.go | 337 +++
+ .../go-crypto-darwin/xcrypto/hash.go | 335 +++
.../go-crypto-darwin/xcrypto/hkdf.go | 103 +
- .../go-crypto-darwin/xcrypto/hmac.go | 119 +
- .../go-crypto-darwin/xcrypto/mldsa.go | 222 ++
+ .../go-crypto-darwin/xcrypto/hmac.go | 106 +
+ .../go-crypto-darwin/xcrypto/mldsa.go | 241 ++
.../go-crypto-darwin/xcrypto/mlkem.go | 261 ++
.../go-crypto-darwin/xcrypto/pbkdf2.go | 76 +
.../go-crypto-darwin/xcrypto/rand.go | 28 +
@@ -121,61 +121,61 @@ Use a 'go' that was recently built by the current branch to ensure stable result
.../microsoft/go-crypto-darwin/xcrypto/rsa.go | 208 ++
.../microsoft/go-crypto-openssl/LICENSE | 21 +
.../microsoft/go-crypto-openssl/bbig/big.go | 40 +
- .../internal/fakecgo/abi_amd64.h | 99 +
- .../internal/fakecgo/abi_arm64.h | 39 +
- .../internal/fakecgo/abi_loong64.h | 60 +
- .../internal/fakecgo/abi_ppc64x.h | 195 ++
- .../internal/fakecgo/abi_riscv64.h | 72 +
- .../internal/fakecgo/asm_386.s | 29 +
- .../internal/fakecgo/asm_amd64.s | 39 +
+ .../internal/fakecgo/abi_amd64.h | 101 +
+ .../internal/fakecgo/abi_arm64.h | 41 +
+ .../internal/fakecgo/abi_loong64.h | 62 +
+ .../internal/fakecgo/abi_ppc64x.h | 197 ++
+ .../internal/fakecgo/abi_riscv64.h | 74 +
+ .../internal/fakecgo/asm_386.s | 31 +
+ .../internal/fakecgo/asm_amd64.s | 41 +
.../internal/fakecgo/asm_arm.s | 52 +
- .../internal/fakecgo/asm_arm64.s | 36 +
+ .../internal/fakecgo/asm_arm64.s | 37 +
.../internal/fakecgo/asm_loong64.s | 40 +
- .../internal/fakecgo/asm_ppc64le.s | 82 +
- .../internal/fakecgo/asm_riscv64.s | 37 +
- .../internal/fakecgo/asm_s390x.s | 55 +
- .../internal/fakecgo/callbacks.go | 93 +
- .../internal/fakecgo/fakecgo.go | 14 +
+ .../internal/fakecgo/asm_ppc64le.s | 81 +
+ .../internal/fakecgo/asm_riscv64.s | 38 +
+ .../internal/fakecgo/asm_s390x.s | 54 +
+ .../internal/fakecgo/callbacks.go | 95 +
+ .../internal/fakecgo/fakecgo.go | 16 +
.../internal/fakecgo/fakecgo.lock | 3 +
- .../internal/fakecgo/freebsd.go | 27 +
+ .../internal/fakecgo/freebsd.go | 29 +
.../internal/fakecgo/generate.go | 6 +
- .../internal/fakecgo/go_darwin.go | 88 +
- .../internal/fakecgo/go_freebsd.go | 79 +
- .../internal/fakecgo/go_libinit.go | 72 +
- .../internal/fakecgo/go_linux.go | 79 +
- .../internal/fakecgo/go_setenv.go | 18 +
- .../internal/fakecgo/go_util.go | 38 +
- .../internal/fakecgo/iscgo.go | 19 +
- .../internal/fakecgo/libcgo.go | 39 +
- .../internal/fakecgo/libcgo_darwin.go | 26 +
- .../internal/fakecgo/libcgo_freebsd.go | 20 +
- .../internal/fakecgo/libcgo_linux.go | 20 +
- .../internal/fakecgo/linux.go | 184 ++
- .../internal/fakecgo/setenv.go | 19 +
- .../internal/fakecgo/trampolines_386.s | 121 +
- .../internal/fakecgo/trampolines_amd64.s | 107 +
- .../internal/fakecgo/trampolines_arm.s | 122 +
- .../internal/fakecgo/trampolines_arm64.s | 81 +
- .../internal/fakecgo/trampolines_linux_386.s | 78 +
- .../fakecgo/trampolines_linux_amd64.s | 69 +
- .../internal/fakecgo/trampolines_linux_arm.s | 69 +
- .../fakecgo/trampolines_linux_arm64.s | 60 +
- .../fakecgo/trampolines_linux_loong64.s | 60 +
- .../fakecgo/trampolines_linux_ppc64le.s | 69 +
- .../fakecgo/trampolines_linux_riscv64.s | 60 +
+ .../internal/fakecgo/go_darwin.go | 90 +
+ .../internal/fakecgo/go_freebsd.go | 81 +
+ .../internal/fakecgo/go_libinit.go | 74 +
+ .../internal/fakecgo/go_linux.go | 81 +
+ .../internal/fakecgo/go_setenv.go | 20 +
+ .../internal/fakecgo/go_util.go | 40 +
+ .../internal/fakecgo/iscgo.go | 21 +
+ .../internal/fakecgo/libcgo.go | 41 +
+ .../internal/fakecgo/libcgo_darwin.go | 28 +
+ .../internal/fakecgo/libcgo_freebsd.go | 22 +
+ .../internal/fakecgo/libcgo_linux.go | 22 +
+ .../internal/fakecgo/linux.go | 186 ++
+ .../internal/fakecgo/setenv.go | 21 +
+ .../internal/fakecgo/trampolines_386.s | 123 +
+ .../internal/fakecgo/trampolines_amd64.s | 109 +
+ .../internal/fakecgo/trampolines_arm.s | 124 +
+ .../internal/fakecgo/trampolines_arm64.s | 83 +
+ .../internal/fakecgo/trampolines_linux_386.s | 80 +
+ .../fakecgo/trampolines_linux_amd64.s | 71 +
+ .../internal/fakecgo/trampolines_linux_arm.s | 71 +
+ .../fakecgo/trampolines_linux_arm64.s | 62 +
+ .../fakecgo/trampolines_linux_loong64.s | 62 +
+ .../fakecgo/trampolines_linux_ppc64le.s | 71 +
+ .../fakecgo/trampolines_linux_riscv64.s | 62 +
.../fakecgo/trampolines_linux_s390x.s | 53 +
- .../internal/fakecgo/trampolines_loong64.s | 78 +
- .../internal/fakecgo/trampolines_ppc64le.s | 128 +
- .../internal/fakecgo/trampolines_riscv64.s | 76 +
- .../internal/fakecgo/trampolines_s390x.s | 154 +
- .../internal/fakecgo/zsymbols.go | 165 ++
- .../internal/fakecgo/zsymbols_darwin.go | 59 +
- .../internal/fakecgo/zsymbols_freebsd.go | 48 +
- .../internal/fakecgo/zsymbols_linux.go | 158 ++
- .../internal/fakecgo/ztrampolines_darwin.s | 19 +
- .../internal/fakecgo/ztrampolines_freebsd.s | 16 +
- .../internal/fakecgo/ztrampolines_linux.s | 46 +
- .../internal/fakecgo/ztrampolines_stubs.s | 55 +
+ .../internal/fakecgo/trampolines_loong64.s | 80 +
+ .../internal/fakecgo/trampolines_ppc64le.s | 134 +
+ .../internal/fakecgo/trampolines_riscv64.s | 78 +
+ .../internal/fakecgo/trampolines_s390x.s | 158 ++
+ .../internal/fakecgo/zsymbols.go | 167 ++
+ .../internal/fakecgo/zsymbols_darwin.go | 61 +
+ .../internal/fakecgo/zsymbols_freebsd.go | 50 +
+ .../internal/fakecgo/zsymbols_linux.go | 160 ++
+ .../internal/fakecgo/ztrampolines_darwin.s | 21 +
+ .../internal/fakecgo/ztrampolines_freebsd.s | 18 +
+ .../internal/fakecgo/ztrampolines_linux.s | 48 +
+ .../internal/fakecgo/ztrampolines_stubs.s | 57 +
.../go-crypto-openssl/internal/ossl/asm_386.s | 101 +
.../internal/ossl/asm_amd64.s | 123 +
.../go-crypto-openssl/internal/ossl/asm_arm.s | 107 +
@@ -190,7 +190,7 @@ Use a 'go' that was recently built by the current branch to ensure stable result
.../internal/ossl/errors_cgo.go | 33 +
.../internal/ossl/errors_nocgo.go | 19 +
.../go-crypto-openssl/internal/ossl/ossl.go | 62 +
- .../go-crypto-openssl/internal/ossl/shims.h | 446 +++
+ .../go-crypto-openssl/internal/ossl/shims.h | 448 +++
.../internal/ossl/syscall_nocgo.go | 87 +
.../internal/ossl/syscall_nocgo_darwin.go | 8 +
.../internal/ossl/syscall_nocgo_freebsd.go | 8 +
@@ -199,16 +199,16 @@ Use a 'go' that was recently built by the current branch to ensure stable result
.../internal/ossl/syscall_nocgo_windows.go | 25 +
.../go-crypto-openssl/internal/ossl/zdl.s | 58 +
.../internal/ossl/zdl_nocgo.go | 61 +
- .../go-crypto-openssl/internal/ossl/zossl.c | 2083 ++++++++++++++
+ .../go-crypto-openssl/internal/ossl/zossl.c | 2101 ++++++++++++++
.../go-crypto-openssl/internal/ossl/zossl.go | 76 +
- .../go-crypto-openssl/internal/ossl/zossl.h | 375 +++
- .../internal/ossl/zossl_cgo.go | 1513 ++++++++++
- .../internal/ossl/zossl_nocgo.go | 2481 +++++++++++++++++
+ .../go-crypto-openssl/internal/ossl/zossl.h | 377 +++
+ .../internal/ossl/zossl_cgo.go | 1527 ++++++++++
+ .../internal/ossl/zossl_nocgo.go | 2501 +++++++++++++++++
.../go-crypto-openssl/openssl/aes.go | 158 ++
.../go-crypto-openssl/openssl/big.go | 14 +
.../openssl/chacha20poly1305.go | 152 +
- .../go-crypto-openssl/openssl/cipher.go | 665 +++++
- .../go-crypto-openssl/openssl/const.go | 109 +
+ .../go-crypto-openssl/openssl/cipher.go | 690 +++++
+ .../go-crypto-openssl/openssl/const.go | 115 +
.../go-crypto-openssl/openssl/cshake.go | 256 ++
.../go-crypto-openssl/openssl/des.go | 121 +
.../go-crypto-openssl/openssl/dsa.go | 296 ++
@@ -216,11 +216,11 @@ Use a 'go' that was recently built by the current branch to ensure stable result
.../go-crypto-openssl/openssl/ecdh.go | 331 +++
.../go-crypto-openssl/openssl/ecdsa.go | 212 ++
.../go-crypto-openssl/openssl/ed25519.go | 209 ++
- .../go-crypto-openssl/openssl/evp.go | 616 ++++
- .../go-crypto-openssl/openssl/hash.go | 521 ++++
- .../go-crypto-openssl/openssl/hkdf.go | 312 +++
+ .../go-crypto-openssl/openssl/evp.go | 634 +++++
+ .../go-crypto-openssl/openssl/hash.go | 518 ++++
+ .../go-crypto-openssl/openssl/hkdf.go | 312 ++
.../go-crypto-openssl/openssl/hmac.go | 269 ++
- .../go-crypto-openssl/openssl/mldsa.go | 449 +++
+ .../go-crypto-openssl/openssl/mldsa.go | 499 ++++
.../go-crypto-openssl/openssl/mlkem.go | 369 +++
.../go-crypto-openssl/openssl/openssl.go | 182 ++
.../go-crypto-openssl/openssl/openssl_cgo.go | 17 +
@@ -232,7 +232,7 @@ Use a 'go' that was recently built by the current branch to ensure stable result
.../go-crypto-openssl/openssl/rand.go | 37 +
.../go-crypto-openssl/openssl/rc4.go | 76 +
.../go-crypto-openssl/openssl/rsa.go | 706 +++++
- .../go-crypto-openssl/openssl/tls1prf.go | 147 +
+ .../go-crypto-openssl/openssl/tls1prf.go | 149 +
.../go-crypto-openssl/openssl/zaes.go | 87 +
.../go-crypto-openssl/osslsetup/fips.go | 115 +
.../go-crypto-openssl/osslsetup/init.go | 170 ++
@@ -253,25 +253,25 @@ Use a 'go' that was recently built by the current branch to ensure stable result
.../microsoft/go-crypto-winnative/cng/dsa.go | 465 +++
.../microsoft/go-crypto-winnative/cng/ecdh.go | 255 ++
.../go-crypto-winnative/cng/ecdsa.go | 169 ++
- .../microsoft/go-crypto-winnative/cng/hash.go | 344 +++
+ .../microsoft/go-crypto-winnative/cng/hash.go | 342 +++
.../microsoft/go-crypto-winnative/cng/hkdf.go | 133 +
.../microsoft/go-crypto-winnative/cng/hmac.go | 70 +
.../microsoft/go-crypto-winnative/cng/keys.go | 220 ++
- .../go-crypto-winnative/cng/mldsa.go | 425 +++
+ .../go-crypto-winnative/cng/mldsa.go | 444 +++
.../go-crypto-winnative/cng/mlkem.go | 405 +++
.../go-crypto-winnative/cng/pbkdf2.go | 70 +
.../microsoft/go-crypto-winnative/cng/rand.go | 28 +
.../microsoft/go-crypto-winnative/cng/rc4.go | 65 +
.../microsoft/go-crypto-winnative/cng/rsa.go | 404 +++
.../microsoft/go-crypto-winnative/cng/sha3.go | 203 ++
- .../go-crypto-winnative/cng/tls1prf.go | 89 +
+ .../go-crypto-winnative/cng/tls1prf.go | 91 +
.../internal/bcrypt/bcrypt_windows.go | 434 +++
.../internal/bcrypt/ntstatus_windows.go | 45 +
.../internal/bcrypt/zsyscall_windows.go | 438 +++
.../internal/subtle/aliasing.go | 32 +
.../internal/sysdll/sys_windows.go | 55 +
src/vendor/modules.txt | 23 +
- 263 files changed, 35759 insertions(+), 7 deletions(-)
+ 263 files changed, 36104 insertions(+), 11 deletions(-)
create mode 100644 src/cmd/internal/telemetry/counter/deps_ignore.go
create mode 100644 src/cmd/vendor/github.com/microsoft/go-infra/telemetry/LICENSE
create mode 100644 src/cmd/vendor/github.com/microsoft/go-infra/telemetry/README.md
@@ -529,7 +529,7 @@ Use a 'go' that was recently built by the current branch to ensure stable result
create mode 100644 src/vendor/github.com/microsoft/go-crypto-winnative/internal/sysdll/sys_windows.go
diff --git a/src/cmd/go.mod b/src/cmd/go.mod
-index 82ceadb04a273a..b7fe75a52e69f8 100644
+index 82ceadb04a273a..14a2aa30728fc6 100644
--- a/src/cmd/go.mod
+++ b/src/cmd/go.mod
@@ -4,6 +4,8 @@ go 1.27
@@ -542,7 +542,7 @@ index 82ceadb04a273a..b7fe75a52e69f8 100644
golang.org/x/build v0.0.0-20260522210304-d55d0041b921
golang.org/x/mod v0.36.1-0.20260520130633-087f6515dd3b
diff --git a/src/cmd/go.sum b/src/cmd/go.sum
-index 929e1c34dcbec1..e5b03ca050f661 100644
+index d9e3e3992ebb61..579fc05cbd0e33 100644
--- a/src/cmd/go.sum
+++ b/src/cmd/go.sum
@@ -4,6 +4,10 @@ github.com/google/pprof v0.0.0-20260507013755-92041b743c96 h1:YDDnaZ9afWajDboPMt
@@ -2368,7 +2368,7 @@ index 00000000000000..016de9bdd95956
+ return filtered
+}
diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt
-index 4774f1a02e905f..3c77716f1fe9b0 100644
+index 4774f1a02e905f..a8e955dc37675e 100644
--- a/src/cmd/vendor/modules.txt
+++ b/src/cmd/vendor/modules.txt
@@ -16,6 +16,17 @@ github.com/google/pprof/third_party/svgpan
@@ -2418,35 +2418,44 @@ index 00000000000000..f5dc9afe4b0ead
+// that are used by the backend package. This allows to track
+// their versions in a single patch file.
diff --git a/src/go.mod b/src/go.mod
-index bb6abc93792f39..46d8c6ad6bd22d 100644
+index bb6abc93792f39..fe4f728b478280 100644
--- a/src/go.mod
+++ b/src/go.mod
-@@ -11,3 +11,9 @@ require (
- golang.org/x/sys v0.45.0 // indirect
- golang.org/x/text v0.37.0 // indirect
+@@ -3,11 +3,14 @@ module std
+ go 1.27
+
+ require (
+- golang.org/x/crypto v0.52.1-0.20260526024921-9beb694f9766
+- golang.org/x/net v0.55.1-0.20260526154343-657eb1317b5d
++ golang.org/x/sys v0.45.0 // indirect
++ golang.org/x/text v0.37.0 // indirect
+ )
+
+ require (
+- golang.org/x/sys v0.45.0 // indirect
+- golang.org/x/text v0.37.0 // indirect
++ github.com/microsoft/go-crypto-darwin v0.0.3-0.20260605073440-7505334b131b
++ github.com/microsoft/go-crypto-openssl v0.0.0-20260605082236-c86f934c8ba7
++ github.com/microsoft/go-crypto-winnative v0.0.0-20260605073512-713d2add0825
++ golang.org/x/crypto v0.52.1-0.20260526024921-9beb694f9766
++ golang.org/x/net v0.55.1-0.20260526154343-657eb1317b5d
)
-+
-+require (
-+ github.com/microsoft/go-crypto-darwin v0.0.3-0.20260512212935-d0ce8397e44b
-+ github.com/microsoft/go-crypto-openssl v0.0.0-20260526094617-f3ee9e48499e
-+ github.com/microsoft/go-crypto-winnative v0.0.0-20260512074019-00d811a4aefe
-+)
diff --git a/src/go.sum b/src/go.sum
-index ab34844da17757..060e1a1e1ae6fc 100644
+index ab34844da17757..76c16dd97f3fbd 100644
--- a/src/go.sum
+++ b/src/go.sum
@@ -1,3 +1,9 @@
-+github.com/microsoft/go-crypto-darwin v0.0.3-0.20260512212935-d0ce8397e44b h1:HADuteQytnLec1jmAOGPGCukWIxObrAm/CBYtVzuo5o=
-+github.com/microsoft/go-crypto-darwin v0.0.3-0.20260512212935-d0ce8397e44b/go.mod h1:QahyqOoEDhEJ08aC1WtiWq691LyNgXq3qrjI4QmdPzM=
-+github.com/microsoft/go-crypto-openssl v0.0.0-20260526094617-f3ee9e48499e h1:969cC0h4W/zAzgFu09YW/6MwRkEDTAVlDB1CKiGG+Qs=
-+github.com/microsoft/go-crypto-openssl v0.0.0-20260526094617-f3ee9e48499e/go.mod h1:gJrjX+yWGi9pkbfPVDDh+ZbgjtQoRSXHjb/ZyjwKk34=
-+github.com/microsoft/go-crypto-winnative v0.0.0-20260512074019-00d811a4aefe h1:WDbUuTTKY8VElMRA3JJ8Quvj9xK9GqEcTiBZ3BF+7mI=
-+github.com/microsoft/go-crypto-winnative v0.0.0-20260512074019-00d811a4aefe/go.mod h1:a1Z07CJIuWa8WT/pzFIGNTTKS96s8o1B1TPOziAHUxw=
++github.com/microsoft/go-crypto-darwin v0.0.3-0.20260605073440-7505334b131b h1:uoj3rW1U1TrlBAv7O3SyFzmYEzO7XWtQFE9WozP8TGc=
++github.com/microsoft/go-crypto-darwin v0.0.3-0.20260605073440-7505334b131b/go.mod h1:QahyqOoEDhEJ08aC1WtiWq691LyNgXq3qrjI4QmdPzM=
++github.com/microsoft/go-crypto-openssl v0.0.0-20260605082236-c86f934c8ba7 h1:5iOYJ5Z1aYu/RRlznK4llvmQnudH6eAC0SG009wjMUM=
++github.com/microsoft/go-crypto-openssl v0.0.0-20260605082236-c86f934c8ba7/go.mod h1:gJrjX+yWGi9pkbfPVDDh+ZbgjtQoRSXHjb/ZyjwKk34=
++github.com/microsoft/go-crypto-winnative v0.0.0-20260605073512-713d2add0825 h1:nmQ1K/L5GISW8UwbUwE376h3WXREEpREFdc3fNklcXc=
++github.com/microsoft/go-crypto-winnative v0.0.0-20260605073512-713d2add0825/go.mod h1:a1Z07CJIuWa8WT/pzFIGNTTKS96s8o1B1TPOziAHUxw=
golang.org/x/crypto v0.52.1-0.20260526024921-9beb694f9766 h1:ABD+jVg0H4Hwu2sGcUtKeb3T8mlS+jS3uWrkTAPcXjs=
golang.org/x/crypto v0.52.1-0.20260526024921-9beb694f9766/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
golang.org/x/net v0.55.1-0.20260526154343-657eb1317b5d h1:G6GZDsxGyGK2SxMEqnPJfBWRKGCNpWheup5btZYkYpw=
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
-index 25cb06182cae3d..920e72e5cdbb9d 100644
+index f65e709a72f6af..a71759adcb7363 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -153,6 +153,13 @@ var depsRules = `
@@ -2463,7 +2472,7 @@ index 25cb06182cae3d..920e72e5cdbb9d 100644
# TIME is SYSCALL plus the core packages about time, including context.
SYSCALL
< time/tzdata
-@@ -536,16 +543,46 @@ var depsRules = `
+@@ -540,16 +547,46 @@ var depsRules = `
NONE < crypto/internal/boring/sig, crypto/internal/boring/syso;
sync/atomic < crypto/internal/boring/bcache;
@@ -2515,7 +2524,7 @@ index 25cb06182cae3d..920e72e5cdbb9d 100644
< crypto/internal/boring
< crypto/boring
< crypto/internal/rand
-@@ -571,6 +608,10 @@ var depsRules = `
+@@ -575,6 +612,10 @@ var depsRules = `
# CRYPTO-MATH is crypto that exposes math/big APIs - no cgo, net; fmt now ok.
@@ -2526,7 +2535,7 @@ index 25cb06182cae3d..920e72e5cdbb9d 100644
CRYPTO, FMT, math/big, internal/saferio
< crypto/internal/boring/bbig
< crypto/internal/fips140cache
-@@ -947,7 +988,7 @@ var buildIgnore = []byte("\n//go:build ignore")
+@@ -951,7 +992,7 @@ var buildIgnore = []byte("\n//go:build ignore")
func findImports(pkg string) ([]string, error) {
vpkg := pkg
@@ -2535,7 +2544,7 @@ index 25cb06182cae3d..920e72e5cdbb9d 100644
vpkg = "vendor/" + pkg
}
dir := filepath.Join(Default.GOROOT, "src", vpkg)
-@@ -957,7 +998,7 @@ func findImports(pkg string) ([]string, error) {
+@@ -961,7 +1002,7 @@ func findImports(pkg string) ([]string, error) {
}
var imports []string
var haveImport = map[string]bool{}
@@ -5288,7 +5297,7 @@ index 00000000000000..e134697ed96de7
+import "C"
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/cryptokit/shims.h b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/cryptokit/shims.h
new file mode 100644
-index 00000000000000..dc98c702b3d50f
+index 00000000000000..7025a366a1513b
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/cryptokit/shims.h
@@ -0,0 +1,127 @@
@@ -5335,11 +5344,11 @@ index 00000000000000..dc98c702b3d50f
+
+// AES GCM encryption and decryption
+long go_encryptAESGCM(const uint8_t *key, size_t keyLength, const uint8_t *data, size_t dataLength, const uint8_t *nonce, size_t nonceLength, const uint8_t *aad, size_t aadLength, uint8_t *cipherText, size_t cipherTextLength, uint8_t *tag) __attribute__((noescape, nocallback, static, slice(key, keyLength), slice(data, dataLength), slice(nonce, nonceLength), slice(aad, aadLength), slice(cipherText, cipherTextLength), slice(tag)));
-+long go_decryptAESGCM(const uint8_t *key, size_t keyLength, const uint8_t *data, size_t dataLength, const uint8_t *nonce, size_t nonceLength, const uint8_t *aad, size_t aadLength, const uint8_t *tag, size_t tagLength, uint8_t *out, size_t *outLength) __attribute__((noescape, nocallback, static, slice(key, keyLength), slice(data, dataLength), slice(nonce, nonceLength), slice(aad, aadLength), slice(tag, tagLength), slice(out)));
++long go_decryptAESGCM(const uint8_t *key, size_t keyLength, const uint8_t *data, size_t dataLength, const uint8_t *nonce, size_t nonceLength, const uint8_t *aad, size_t aadLength, const uint8_t *tag, size_t tagLength, uint8_t *out, size_t *outLength) __attribute__((noescape, nocallback, static, slice(key, keyLength), slice(data, dataLength), slice(nonce, nonceLength), slice(aad, aadLength), slice(tag, tagLength), slice(out, outLength)));
+
+// ChaChaPoly encryption and decryption
+long go_encryptChaChaPoly(const uint8_t *key, size_t keyLength, const uint8_t *data, size_t dataLength, const uint8_t *nonce, size_t nonceLength, const uint8_t *aad, size_t aadLength, uint8_t *cipherText, size_t cipherTextLength, uint8_t *tag) __attribute__((noescape, nocallback, static, slice(key, keyLength), slice(data, dataLength), slice(nonce, nonceLength), slice(aad, aadLength), slice(cipherText, cipherTextLength), slice(tag)));
-+long go_decryptChaChaPoly(const uint8_t *key, size_t keyLength, const uint8_t *data, size_t dataLength, const uint8_t *nonce, size_t nonceLength, const uint8_t *aad, size_t aadLength, const uint8_t *tag, size_t tagLength, uint8_t *out, size_t *outLength) __attribute__((noescape, nocallback, static, slice(key, keyLength), slice(data, dataLength), slice(nonce, nonceLength), slice(aad, aadLength), slice(tag, tagLength), slice(out)));
++long go_decryptChaChaPoly(const uint8_t *key, size_t keyLength, const uint8_t *data, size_t dataLength, const uint8_t *nonce, size_t nonceLength, const uint8_t *aad, size_t aadLength, const uint8_t *tag, size_t tagLength, uint8_t *out, size_t *outLength) __attribute__((noescape, nocallback, static, slice(key, keyLength), slice(data, dataLength), slice(nonce, nonceLength), slice(aad, aadLength), slice(tag, tagLength), slice(out, outLength)));
+
+// Generates an Ed25519 keypair.
+// The private key is 64 bytes (first 32 bytes are the seed, next 32 bytes are the public key). The public key is 32 bytes.
@@ -5395,8 +5404,8 @@ index 00000000000000..dc98c702b3d50f
+long go_generateKeyMLDSA87(uint8_t *seed, long seedLen) __attribute__((noescape, nocallback, static, slice(seed, seedLen)));
+long go_derivePublicKeyMLDSA65(const uint8_t *seed, long seedLen, uint8_t *publicKey, long publicKeyLen) __attribute__((noescape, nocallback, static, slice(seed, seedLen), slice(publicKey, publicKeyLen)));
+long go_derivePublicKeyMLDSA87(const uint8_t *seed, long seedLen, uint8_t *publicKey, long publicKeyLen) __attribute__((noescape, nocallback, static, slice(seed, seedLen), slice(publicKey, publicKeyLen)));
-+long go_signMLDSA65(const uint8_t *seed, long seedLen, const uint8_t *message, long messageLen, const uint8_t *context, long contextLen, uint8_t *signature, long *signatureLen) __attribute__((noescape, nocallback, static, slice(seed, seedLen), slice(message, messageLen), slice(context, contextLen), slice(signature)));
-+long go_signMLDSA87(const uint8_t *seed, long seedLen, const uint8_t *message, long messageLen, const uint8_t *context, long contextLen, uint8_t *signature, long *signatureLen) __attribute__((noescape, nocallback, static, slice(seed, seedLen), slice(message, messageLen), slice(context, contextLen), slice(signature)));
++long go_signMLDSA65(const uint8_t *seed, long seedLen, const uint8_t *message, long messageLen, const uint8_t *context, long contextLen, uint8_t *signature, long *signatureLen) __attribute__((noescape, nocallback, static, slice(seed, seedLen), slice(message, messageLen), slice(context, contextLen), slice(signature, signatureLen)));
++long go_signMLDSA87(const uint8_t *seed, long seedLen, const uint8_t *message, long messageLen, const uint8_t *context, long contextLen, uint8_t *signature, long *signatureLen) __attribute__((noescape, nocallback, static, slice(seed, seedLen), slice(message, messageLen), slice(context, contextLen), slice(signature, signatureLen)));
+long go_verifyMLDSA65(const uint8_t *publicKey, long publicKeyLen, const uint8_t *message, long messageLen, const uint8_t *context, long contextLen, const uint8_t *signature, long signatureLen) __attribute__((noescape, nocallback, static, slice(publicKey, publicKeyLen), slice(message, messageLen), slice(context, contextLen), slice(signature, signatureLen)));
+long go_verifyMLDSA87(const uint8_t *publicKey, long publicKeyLen, const uint8_t *message, long messageLen, const uint8_t *context, long contextLen, const uint8_t *signature, long signatureLen) __attribute__((noescape, nocallback, static, slice(publicKey, publicKeyLen), slice(message, messageLen), slice(context, contextLen), slice(signature, signatureLen)));
+long go_validatePublicKeyMLDSA65(const uint8_t *publicKey, long publicKeyLen) __attribute__((noescape, nocallback, static, slice(publicKey, publicKeyLen)));
@@ -5411,7 +5420,7 @@ index 00000000000000..dc98c702b3d50f
+
+// ECDSA
+long go_generateKeyECDSA(int32_t curveID, uint8_t *x, long xLen, uint8_t *y, long yLen, uint8_t *d, long dLen) __attribute__((noescape, nocallback, static, slice(x, xLen), slice(y, yLen), slice(d, dLen)));
-+long go_ecdsaSign(int32_t curveID, const uint8_t *d, long dLen, const uint8_t *message, long messageLen, uint8_t *signature, long *signatureLen) __attribute__((noescape, nocallback, static, slice(d, dLen), slice(message, messageLen), slice(signature)));
++long go_ecdsaSign(int32_t curveID, const uint8_t *d, long dLen, const uint8_t *message, long messageLen, uint8_t *signature, long *signatureLen) __attribute__((noescape, nocallback, static, slice(d, dLen), slice(message, messageLen), slice(signature, signatureLen)));
+long go_ecdsaVerify(int32_t curveID, const uint8_t *x, long xLen, const uint8_t *y, long yLen, const uint8_t *message, long messageLen, const uint8_t *signature, long signatureLen) __attribute__((noescape, nocallback, static, slice(x, xLen), slice(y, yLen), slice(message, messageLen), slice(signature, signatureLen)));
+
+#ifdef __clang__
@@ -6262,10 +6271,10 @@ index 00000000000000..5be36f4b35dedb
+
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/cryptokit/zcryptokit_cgo.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/cryptokit/zcryptokit_cgo.go
new file mode 100644
-index 00000000000000..c05dd1acf80954
+index 00000000000000..5bd022affd7811
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/cryptokit/zcryptokit_cgo.go
-@@ -0,0 +1,386 @@
+@@ -0,0 +1,401 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -6454,10 +6463,16 @@ index 00000000000000..c05dd1acf80954
+}
+
+func DecryptAESGCM(key []uint8, data []uint8, nonce []uint8, aad []uint8, tag []uint8, out []uint8, outLength *int) int64 {
++ if outLength != nil && int(*outLength) > len(out) {
++ panic("DecryptAESGCM: *outLength exceeds len(out)")
++ }
+ return int64(C._mkcgo_go_decryptAESGCM((*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(key))), C.size_t(len(key)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(data))), C.size_t(len(data)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(nonce))), C.size_t(len(nonce)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(aad))), C.size_t(len(aad)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(tag))), C.size_t(len(tag)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(out))), (*C.size_t)(unsafe.Pointer(outLength))))
+}
+
+func DecryptChaChaPoly(key []uint8, data []uint8, nonce []uint8, aad []uint8, tag []uint8, out []uint8, outLength *int) int64 {
++ if outLength != nil && int(*outLength) > len(out) {
++ panic("DecryptChaChaPoly: *outLength exceeds len(out)")
++ }
+ return int64(C._mkcgo_go_decryptChaChaPoly((*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(key))), C.size_t(len(key)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(data))), C.size_t(len(data)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(nonce))), C.size_t(len(nonce)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(aad))), C.size_t(len(aad)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(tag))), C.size_t(len(tag)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(out))), (*C.size_t)(unsafe.Pointer(outLength))))
+}
+
@@ -6482,6 +6497,9 @@ index 00000000000000..c05dd1acf80954
+}
+
+func EcdsaSign(curveID int32, d []uint8, message []uint8, signature []uint8, signatureLen *int64) int64 {
++ if signatureLen != nil && int(*signatureLen) > len(signature) {
++ panic("EcdsaSign: *signatureLen exceeds len(signature)")
++ }
+ return int64(C._mkcgo_go_ecdsaSign(C.int32_t(curveID), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(d))), C.long(len(d)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(message))), C.long(len(message)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(signature))), (*C.long)(unsafe.Pointer(signatureLen))))
+}
+
@@ -6602,10 +6620,16 @@ index 00000000000000..c05dd1acf80954
+}
+
+func SignMLDSA65(seed []uint8, message []uint8, context []uint8, signature []uint8, signatureLen *int64) int64 {
++ if signatureLen != nil && int(*signatureLen) > len(signature) {
++ panic("SignMLDSA65: *signatureLen exceeds len(signature)")
++ }
+ return int64(C._mkcgo_go_signMLDSA65((*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(seed))), C.long(len(seed)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(message))), C.long(len(message)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(context))), C.long(len(context)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(signature))), (*C.long)(unsafe.Pointer(signatureLen))))
+}
+
+func SignMLDSA87(seed []uint8, message []uint8, context []uint8, signature []uint8, signatureLen *int64) int64 {
++ if signatureLen != nil && int(*signatureLen) > len(signature) {
++ panic("SignMLDSA87: *signatureLen exceeds len(signature)")
++ }
+ return int64(C._mkcgo_go_signMLDSA87((*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(seed))), C.long(len(seed)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(message))), C.long(len(message)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(context))), C.long(len(context)), (*C.uint8_t)(unsafe.Pointer(unsafe.SliceData(signature))), (*C.long)(unsafe.Pointer(signatureLen))))
+}
+
@@ -6654,10 +6678,10 @@ index 00000000000000..c05dd1acf80954
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/cryptokit/zcryptokit_nocgo.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/cryptokit/zcryptokit_nocgo.go
new file mode 100644
-index 00000000000000..222ece4bb14349
+index 00000000000000..81adf32bc70763
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/cryptokit/zcryptokit_nocgo.go
-@@ -0,0 +1,441 @@
+@@ -0,0 +1,456 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -6859,11 +6883,17 @@ index 00000000000000..222ece4bb14349
+}
+
+func DecryptAESGCM(key []uint8, data []uint8, nonce []uint8, aad []uint8, tag []uint8, out []uint8, outLength *int) int64 {
++ if outLength != nil && int(*outLength) > len(out) {
++ panic("DecryptAESGCM: *outLength exceeds len(out)")
++ }
+ r0, _ := syscallN(0, uintptr(unsafe.Pointer(&go_decryptAESGCM)), uintptr(unsafe.Pointer(unsafe.SliceData(key))), uintptr(len(key)), uintptr(unsafe.Pointer(unsafe.SliceData(data))), uintptr(len(data)), uintptr(unsafe.Pointer(unsafe.SliceData(nonce))), uintptr(len(nonce)), uintptr(unsafe.Pointer(unsafe.SliceData(aad))), uintptr(len(aad)), uintptr(unsafe.Pointer(unsafe.SliceData(tag))), uintptr(len(tag)), uintptr(unsafe.Pointer(unsafe.SliceData(out))), uintptr(unsafe.Pointer(outLength)))
+ return int64(r0)
+}
+
+func DecryptChaChaPoly(key []uint8, data []uint8, nonce []uint8, aad []uint8, tag []uint8, out []uint8, outLength *int) int64 {
++ if outLength != nil && int(*outLength) > len(out) {
++ panic("DecryptChaChaPoly: *outLength exceeds len(out)")
++ }
+ r0, _ := syscallN(0, uintptr(unsafe.Pointer(&go_decryptChaChaPoly)), uintptr(unsafe.Pointer(unsafe.SliceData(key))), uintptr(len(key)), uintptr(unsafe.Pointer(unsafe.SliceData(data))), uintptr(len(data)), uintptr(unsafe.Pointer(unsafe.SliceData(nonce))), uintptr(len(nonce)), uintptr(unsafe.Pointer(unsafe.SliceData(aad))), uintptr(len(aad)), uintptr(unsafe.Pointer(unsafe.SliceData(tag))), uintptr(len(tag)), uintptr(unsafe.Pointer(unsafe.SliceData(out))), uintptr(unsafe.Pointer(outLength)))
+ return int64(r0)
+}
@@ -6894,6 +6924,9 @@ index 00000000000000..222ece4bb14349
+}
+
+func EcdsaSign(curveID int32, d []uint8, message []uint8, signature []uint8, signatureLen *int64) int64 {
++ if signatureLen != nil && int(*signatureLen) > len(signature) {
++ panic("EcdsaSign: *signatureLen exceeds len(signature)")
++ }
+ r0, _ := syscallN(0, uintptr(unsafe.Pointer(&go_ecdsaSign)), uintptr(curveID), uintptr(unsafe.Pointer(unsafe.SliceData(d))), uintptr(len(d)), uintptr(unsafe.Pointer(unsafe.SliceData(message))), uintptr(len(message)), uintptr(unsafe.Pointer(unsafe.SliceData(signature))), uintptr(unsafe.Pointer(signatureLen)))
+ return int64(r0)
+}
@@ -7037,11 +7070,17 @@ index 00000000000000..222ece4bb14349
+}
+
+func SignMLDSA65(seed []uint8, message []uint8, context []uint8, signature []uint8, signatureLen *int64) int64 {
++ if signatureLen != nil && int(*signatureLen) > len(signature) {
++ panic("SignMLDSA65: *signatureLen exceeds len(signature)")
++ }
+ r0, _ := syscallN(0, uintptr(unsafe.Pointer(&go_signMLDSA65)), uintptr(unsafe.Pointer(unsafe.SliceData(seed))), uintptr(len(seed)), uintptr(unsafe.Pointer(unsafe.SliceData(message))), uintptr(len(message)), uintptr(unsafe.Pointer(unsafe.SliceData(context))), uintptr(len(context)), uintptr(unsafe.Pointer(unsafe.SliceData(signature))), uintptr(unsafe.Pointer(signatureLen)))
+ return int64(r0)
+}
+
+func SignMLDSA87(seed []uint8, message []uint8, context []uint8, signature []uint8, signatureLen *int64) int64 {
++ if signatureLen != nil && int(*signatureLen) > len(signature) {
++ panic("SignMLDSA87: *signatureLen exceeds len(signature)")
++ }
+ r0, _ := syscallN(0, uintptr(unsafe.Pointer(&go_signMLDSA87)), uintptr(unsafe.Pointer(unsafe.SliceData(seed))), uintptr(len(seed)), uintptr(unsafe.Pointer(unsafe.SliceData(message))), uintptr(len(message)), uintptr(unsafe.Pointer(unsafe.SliceData(context))), uintptr(len(context)), uintptr(unsafe.Pointer(unsafe.SliceData(signature))), uintptr(unsafe.Pointer(signatureLen)))
+ return int64(r0)
+}
@@ -7726,10 +7765,12 @@ index 00000000000000..ce5806b1910da9
+//go:cgo_import_dynamic swift_unexpectedError swift_unexpectedError ""
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/abi_amd64.h b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/abi_amd64.h
new file mode 100644
-index 00000000000000..9949435fe9e0ae
+index 00000000000000..6bb31c929849a8
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/abi_amd64.h
-@@ -0,0 +1,99 @@
+@@ -0,0 +1,101 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2021 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.
@@ -7831,10 +7872,12 @@ index 00000000000000..9949435fe9e0ae
+#endif
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/abi_arm64.h b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/abi_arm64.h
new file mode 100644
-index 00000000000000..5d5061ec1dbf8c
+index 00000000000000..4957e129eae27e
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/abi_arm64.h
-@@ -0,0 +1,39 @@
+@@ -0,0 +1,41 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2021 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.
@@ -7876,10 +7919,12 @@ index 00000000000000..5d5061ec1dbf8c
+ FLDPD ((offset)+6*8)(RSP), (F14, F15)
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/asm_amd64.s b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/asm_amd64.s
new file mode 100644
-index 00000000000000..2b7eb57f8ae783
+index 00000000000000..623852da4937cb
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/asm_amd64.s
-@@ -0,0 +1,39 @@
+@@ -0,0 +1,41 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2009 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.
@@ -7921,10 +7966,12 @@ index 00000000000000..2b7eb57f8ae783
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/asm_arm64.s b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/asm_arm64.s
new file mode 100644
-index 00000000000000..50e5261d922c56
+index 00000000000000..ff58b16c050af6
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/asm_arm64.s
-@@ -0,0 +1,36 @@
+@@ -0,0 +1,37 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2015 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.
@@ -7952,7 +7999,6 @@ index 00000000000000..50e5261d922c56
+ STP (R29, R30), (8*22)(RSP)
+
+ // Initialize Go ABI environment
-+ BL runtime·load_g(SB)
+ BL runtime·cgocallback(SB)
+
+ RESTORE_R19_TO_R28(8*4)
@@ -7963,10 +8009,12 @@ index 00000000000000..50e5261d922c56
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/callbacks.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/callbacks.go
new file mode 100644
-index 00000000000000..e48722128a09d7
+index 00000000000000..ff5d7f336c9a2a
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/callbacks.go
-@@ -0,0 +1,93 @@
+@@ -0,0 +1,95 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2011 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.
@@ -8062,10 +8110,12 @@ index 00000000000000..e48722128a09d7
+)
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/fakecgo.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/fakecgo.go
new file mode 100644
-index 00000000000000..b631396bd2ffe7
+index 00000000000000..45ffff7707b65e
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/fakecgo.go
-@@ -0,0 +1,14 @@
+@@ -0,0 +1,16 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
@@ -8082,12 +8132,12 @@ index 00000000000000..b631396bd2ffe7
+func call5(fn, a1, a2, a3, a4, a5 uintptr) uintptr
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/fakecgo.lock b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/fakecgo.lock
new file mode 100644
-index 00000000000000..9b0650d53777bd
+index 00000000000000..3a842170f1f5e8
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/fakecgo.lock
@@ -0,0 +1,3 @@
+{
-+ "commit_hash": "5110604b3385278be6887d0feead513a1bfe7a82"
++ "commit_hash": "1512f327e9958354283654ee4497800e33a7b838"
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/generate.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/generate.go
new file mode 100644
@@ -8103,10 +8153,12 @@ index 00000000000000..88c4cdf9ec04cc
+//go:generate go run update_tool.go
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_darwin.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_darwin.go
new file mode 100644
-index 00000000000000..d0868f0f790351
+index 00000000000000..e49117058f381e
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_darwin.go
-@@ -0,0 +1,88 @@
+@@ -0,0 +1,90 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2011 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.
@@ -8197,10 +8249,12 @@ index 00000000000000..d0868f0f790351
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_libinit.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_libinit.go
new file mode 100644
-index 00000000000000..f6fa2328af41bc
+index 00000000000000..b8bfc86edc973a
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_libinit.go
-@@ -0,0 +1,72 @@
+@@ -0,0 +1,74 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -8275,10 +8329,12 @@ index 00000000000000..f6fa2328af41bc
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_setenv.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_setenv.go
new file mode 100644
-index 00000000000000..a79441edffbcb9
+index 00000000000000..ac0ca35aa25dc0
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_setenv.go
-@@ -0,0 +1,18 @@
+@@ -0,0 +1,20 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -8299,10 +8355,12 @@ index 00000000000000..a79441edffbcb9
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_util.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_util.go
new file mode 100644
-index 00000000000000..1d59e7f6b628d1
+index 00000000000000..0e316cc82c12f6
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/go_util.go
-@@ -0,0 +1,38 @@
+@@ -0,0 +1,40 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -8343,10 +8401,12 @@ index 00000000000000..1d59e7f6b628d1
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/iscgo.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/iscgo.go
new file mode 100644
-index 00000000000000..76f7ef6dc58c7c
+index 00000000000000..7c0b38637a85da
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/iscgo.go
-@@ -0,0 +1,19 @@
+@@ -0,0 +1,21 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2010 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.
@@ -8368,10 +8428,12 @@ index 00000000000000..76f7ef6dc58c7c
+var _iscgo bool = true
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/libcgo.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/libcgo.go
new file mode 100644
-index 00000000000000..001b698842a36c
+index 00000000000000..666398d611c7e6
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/libcgo.go
-@@ -0,0 +1,39 @@
+@@ -0,0 +1,41 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -8413,10 +8475,12 @@ index 00000000000000..001b698842a36c
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/libcgo_darwin.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/libcgo_darwin.go
new file mode 100644
-index 00000000000000..ecdcb2e7852560
+index 00000000000000..2f7a973b34a3a3
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/libcgo_darwin.go
-@@ -0,0 +1,26 @@
+@@ -0,0 +1,28 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -8445,10 +8509,12 @@ index 00000000000000..ecdcb2e7852560
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/setenv.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/setenv.go
new file mode 100644
-index 00000000000000..e761fecfb89280
+index 00000000000000..3579d5e7dd1bad
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/setenv.go
-@@ -0,0 +1,19 @@
+@@ -0,0 +1,21 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2011 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.
@@ -8470,10 +8536,12 @@ index 00000000000000..e761fecfb89280
+var _cgo_unsetenv = &x_cgo_unsetenv_trampoline
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/trampolines_amd64.s b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/trampolines_amd64.s
new file mode 100644
-index 00000000000000..098f56ce5e6b77
+index 00000000000000..0ec577fa374ed6
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/trampolines_amd64.s
-@@ -0,0 +1,107 @@
+@@ -0,0 +1,109 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -8583,10 +8651,12 @@ index 00000000000000..098f56ce5e6b77
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/trampolines_arm64.s b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/trampolines_arm64.s
new file mode 100644
-index 00000000000000..970f3fd9a1ef0d
+index 00000000000000..a9c6f3d0d59e21
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/trampolines_arm64.s
-@@ -0,0 +1,81 @@
+@@ -0,0 +1,83 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -8670,10 +8740,12 @@ index 00000000000000..970f3fd9a1ef0d
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/zsymbols.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/zsymbols.go
new file mode 100644
-index 00000000000000..3f720df236e392
+index 00000000000000..e0394bb59562a2
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/zsymbols.go
-@@ -0,0 +1,165 @@
+@@ -0,0 +1,167 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -8841,10 +8913,12 @@ index 00000000000000..3f720df236e392
+var pthread_setspecificABI0 = uintptr(unsafe.Pointer(&_pthread_setspecific))
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/zsymbols_darwin.go b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/zsymbols_darwin.go
new file mode 100644
-index 00000000000000..960f8168eb88d7
+index 00000000000000..a7a0d9e69d4d8b
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/zsymbols_darwin.go
-@@ -0,0 +1,59 @@
+@@ -0,0 +1,61 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -8906,10 +8980,12 @@ index 00000000000000..960f8168eb88d7
+var pthread_attr_setstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_setstacksize))
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/ztrampolines_darwin.s b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/ztrampolines_darwin.s
new file mode 100644
-index 00000000000000..35ef7ac11cb955
+index 00000000000000..9038f8394965e8
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/ztrampolines_darwin.s
-@@ -0,0 +1,19 @@
+@@ -0,0 +1,21 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -8931,10 +9007,12 @@ index 00000000000000..35ef7ac11cb955
+ JMP purego_pthread_attr_setstacksize(SB)
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/ztrampolines_stubs.s b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/ztrampolines_stubs.s
new file mode 100644
-index 00000000000000..c59e0dce68c449
+index 00000000000000..5e6229a8a9bca5
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/internal/fakecgo/ztrampolines_stubs.s
-@@ -0,0 +1,55 @@
+@@ -0,0 +1,57 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -12359,10 +12437,10 @@ index 00000000000000..82a961d974f129
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/hash.go b/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/hash.go
new file mode 100644
-index 00000000000000..016827afea2eee
+index 00000000000000..3a3f76b9fd0453
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/hash.go
-@@ -0,0 +1,337 @@
+@@ -0,0 +1,335 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -12399,8 +12477,6 @@ index 00000000000000..016827afea2eee
+ blockSize int
+}
+
-+type HashCloner = hash.Cloner
-+
+var cacheHash sync.Map // map[crypto.Hash]*hashAlgorithm
+
+// supportsSHA3 returns true if SHA-3 is available on this macOS version.
@@ -12513,7 +12589,7 @@ index 00000000000000..016827afea2eee
+ }
+}
+
-+func (h *Hash) Clone() (HashCloner, error) {
++func (h *Hash) Clone() (hash.Cloner, error) {
+ if h.ptr == nil {
+ panic("cryptokit: hash already finalized")
+ }
@@ -12618,7 +12694,7 @@ index 00000000000000..016827afea2eee
+}
+
+var _ hash.Hash = (*Hash)(nil)
-+var _ HashCloner = (*Hash)(nil)
++var _ hash.Cloner = (*Hash)(nil)
+
+func MD5(p []byte) (sum [16]byte) {
+ cryptokit.MD5(p, sum[:])
@@ -12661,28 +12737,28 @@ index 00000000000000..016827afea2eee
+}
+
+// NewMD5 initializes a new MD5 hasher.
-+func NewMD5() hash.Hash {
++func NewMD5() *Hash {
+ return newHash(crypto.MD5)
+
+}
+
+// NewSHA1 initializes a new SHA1 hasher.
-+func NewSHA1() hash.Hash {
++func NewSHA1() *Hash {
+ return newHash(crypto.SHA1)
+}
+
+// NewSHA256 initializes a new SHA256 hasher.
-+func NewSHA256() hash.Hash {
++func NewSHA256() *Hash {
+ return newHash(crypto.SHA256)
+}
+
+// NewSHA384 initializes a new SHA384 hasher.
-+func NewSHA384() hash.Hash {
++func NewSHA384() *Hash {
+ return newHash(crypto.SHA384)
+}
+
+// NewSHA512 initializes a new SHA512 hasher.
-+func NewSHA512() hash.Hash {
++func NewSHA512() *Hash {
+ return newHash(crypto.SHA512)
+}
+
@@ -12702,7 +12778,7 @@ index 00000000000000..016827afea2eee
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/hkdf.go b/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/hkdf.go
new file mode 100644
-index 00000000000000..f6183de583d9ac
+index 00000000000000..a49b6f2ab41e3c
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/hkdf.go
@@ -0,0 +1,103 @@
@@ -12722,7 +12798,7 @@ index 00000000000000..f6183de583d9ac
+)
+
+// ExtractHKDF performs the extract step of HKDF using the specified hash function.
-+func ExtractHKDF(h func() hash.Hash, secret, salt []byte) ([]byte, error) {
++func ExtractHKDF[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) {
+ // Handle empty secret
+ if len(secret) == 0 {
+ return nil, errors.New("secret cannot be empty")
@@ -12755,7 +12831,7 @@ index 00000000000000..f6183de583d9ac
+}
+
+// ExpandHKDF performs the expand step of HKDF using the specified hash function.
-+func ExpandHKDF(h func() hash.Hash, pseudorandomKey, info []byte, keyLength int) ([]byte, error) {
++func ExpandHKDF[H hash.Hash](h func() H, pseudorandomKey, info []byte, keyLength int) ([]byte, error) {
+ // Handle empty secret
+ if len(pseudorandomKey) == 0 {
+ return nil, errors.New("pseudorandom key cannot be empty")
@@ -12811,10 +12887,10 @@ index 00000000000000..f6183de583d9ac
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/hmac.go b/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/hmac.go
new file mode 100644
-index 00000000000000..80a951f8ea1a2a
+index 00000000000000..5f73e60f5465cf
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/hmac.go
-@@ -0,0 +1,119 @@
+@@ -0,0 +1,106 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -12832,7 +12908,7 @@ index 00000000000000..80a951f8ea1a2a
+)
+
+var _ hash.Hash = (*cryptoKitHMAC)(nil)
-+var _ HashCloner = (*cryptoKitHMAC)(nil)
++var _ hash.Cloner = (*cryptoKitHMAC)(nil)
+
+type cryptoKitHMAC struct {
+ ptr unsafe.Pointer
@@ -12845,30 +12921,26 @@ index 00000000000000..80a951f8ea1a2a
+}
+
+// NewHMAC returns a new HMAC using xcrypto.
-+// The function h must return a hash implemented by
-+// CommonCrypto (for example, h could be xcrypto.NewSHA256).
-+// If h is not recognized, NewHMAC returns nil.
-+func NewHMAC(fh func() hash.Hash, key []byte) hash.Hash {
-+ h := fh()
-+ if h == nil {
++// The function fh must return a hash implemented by
++// CommonCrypto (for example, [NewSHA256]).
++// If fh is not recognized, NewHMAC returns nil.
++func NewHMAC[H hash.Hash](fh func() H, key []byte) hash.Hash {
++ h, ok := any(fh()).(*Hash)
++ if !ok || h == nil {
+ return nil
+ }
+
+ // copying the key here to ensure that it is not modified
+ // while this algorithm is using it.
+ key = slices.Clone(key)
-+ kind := hashToHMACEnum(h)
-+ if kind == 0 {
-+ // The hash function is not supported by the HMAC implementation.
-+ return nil
-+ }
++ kind := h.alg.id
+
+ hmac := &cryptoKitHMAC{
+ ptr: cryptokit.InitHMAC(kind, key),
+ kind: kind,
+ key: key,
-+ blockSize: h.BlockSize(),
-+ size: h.Size(),
++ blockSize: h.alg.blockSize,
++ size: h.alg.size,
+ }
+
+ runtime.SetFinalizer(hmac, func(h *cryptoKitHMAC) {
@@ -12895,7 +12967,7 @@ index 00000000000000..80a951f8ea1a2a
+ return b
+}
+
-+func (h *cryptoKitHMAC) Clone() (HashCloner, error) {
++func (h *cryptoKitHMAC) Clone() (hash.Cloner, error) {
+ if h.ptr == nil {
+ panic("cryptokit: hash already finalized")
+ }
@@ -12925,21 +12997,12 @@ index 00000000000000..80a951f8ea1a2a
+func (h *cryptoKitHMAC) BlockSize() int {
+ return h.blockSize
+}
-+
-+func hashToHMACEnum(h hash.Hash) int32 {
-+ switch h := h.(type) {
-+ case *Hash:
-+ return h.alg.id
-+ default:
-+ return 0
-+ }
-+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/mldsa.go b/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/mldsa.go
new file mode 100644
-index 00000000000000..136d81fe3c152e
+index 00000000000000..7bc762de80ff3d
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/mldsa.go
-@@ -0,0 +1,222 @@
+@@ -0,0 +1,241 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -12948,6 +13011,7 @@ index 00000000000000..136d81fe3c152e
+package xcrypto
+
+import (
++ "crypto/subtle"
+ "errors"
+
+ "github.com/microsoft/go-crypto-darwin/internal/cryptokit"
@@ -13073,6 +13137,15 @@ index 00000000000000..136d81fe3c152e
+ return key.seed[:]
+}
+
++// Equal reports whether key and other represent the same private key.
++func (key *PrivateKeyMLDSA) Equal(other *PrivateKeyMLDSA) bool {
++ if other == nil {
++ return false
++ }
++ return key.params.name == other.params.name &&
++ subtle.ConstantTimeCompare(key.seed[:], other.seed[:]) == 1
++}
++
+// Parameters returns the parameters associated with this private key.
+func (key *PrivateKeyMLDSA) Parameters() MLDSAParameters { return key.params }
+
@@ -13134,6 +13207,15 @@ index 00000000000000..136d81fe3c152e
+ return key.bytes[:key.params.publicKeySize]
+}
+
++// Equal reports whether key and other represent the same public key.
++func (key *PublicKeyMLDSA) Equal(other *PublicKeyMLDSA) bool {
++ if other == nil {
++ return false
++ }
++ return key.params.name == other.params.name &&
++ subtle.ConstantTimeCompare(key.bytes[:key.params.publicKeySize], other.bytes[:other.params.publicKeySize]) == 1
++}
++
+// Parameters returns the parameters associated with this public key.
+func (key *PublicKeyMLDSA) Parameters() MLDSAParameters { return key.params }
+
@@ -13431,7 +13513,7 @@ index 00000000000000..b5131703afdbcc
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/pbkdf2.go b/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/pbkdf2.go
new file mode 100644
-index 00000000000000..b50fc17d0f8d66
+index 00000000000000..ce9bf09c010354
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-darwin/xcrypto/pbkdf2.go
@@ -0,0 +1,76 @@
@@ -13451,7 +13533,7 @@ index 00000000000000..b50fc17d0f8d66
+ "github.com/microsoft/go-crypto-darwin/internal/commoncrypto"
+)
+
-+func PBKDF2(password, salt []byte, iter, keyLen int, fh func() hash.Hash) ([]byte, error) {
++func PBKDF2[H hash.Hash](password, salt []byte, iter, keyLen int, fh func() H) ([]byte, error) {
+ // CommonCrypto's CCKeyDerivationPBKDF takes an unsigned 32-bit iteration
+ // count, so reject values that would overflow or wrap. In practice the
+ // recommended iteration count is around 300,000.
@@ -13921,10 +14003,12 @@ index 00000000000000..32ce383bd966c2
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_amd64.h b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_amd64.h
new file mode 100644
-index 00000000000000..9949435fe9e0ae
+index 00000000000000..6bb31c929849a8
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_amd64.h
-@@ -0,0 +1,99 @@
+@@ -0,0 +1,101 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2021 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.
@@ -14026,10 +14110,12 @@ index 00000000000000..9949435fe9e0ae
+#endif
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_arm64.h b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_arm64.h
new file mode 100644
-index 00000000000000..5d5061ec1dbf8c
+index 00000000000000..4957e129eae27e
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_arm64.h
-@@ -0,0 +1,39 @@
+@@ -0,0 +1,41 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2021 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.
@@ -14071,10 +14157,12 @@ index 00000000000000..5d5061ec1dbf8c
+ FLDPD ((offset)+6*8)(RSP), (F14, F15)
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_loong64.h b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_loong64.h
new file mode 100644
-index 00000000000000..b10d83732f1c6e
+index 00000000000000..3752c54045960b
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_loong64.h
-@@ -0,0 +1,60 @@
+@@ -0,0 +1,62 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// 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.
@@ -14137,10 +14225,12 @@ index 00000000000000..b10d83732f1c6e
+ MOVD ((offset)+(7*8))(R3), F31
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_ppc64x.h b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_ppc64x.h
new file mode 100644
-index 00000000000000..245a5266f6e9fa
+index 00000000000000..4a6086502ee07b
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_ppc64x.h
-@@ -0,0 +1,195 @@
+@@ -0,0 +1,197 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2023 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.
@@ -14338,10 +14428,12 @@ index 00000000000000..245a5266f6e9fa
+ MOVW R0, CR
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_riscv64.h b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_riscv64.h
new file mode 100644
-index 00000000000000..b9322e0c53e2ac
+index 00000000000000..f728bd3300cf18
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/abi_riscv64.h
-@@ -0,0 +1,72 @@
+@@ -0,0 +1,74 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// 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.
@@ -14416,10 +14508,12 @@ index 00000000000000..b9322e0c53e2ac
+ MOVD ((offset)+11*8)(X2), F27
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_386.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_386.s
new file mode 100644
-index 00000000000000..7475ec8a0b21fc
+index 00000000000000..350233acccc89b
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_386.s
-@@ -0,0 +1,29 @@
+@@ -0,0 +1,31 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2009 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.
@@ -14451,10 +14545,12 @@ index 00000000000000..7475ec8a0b21fc
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_amd64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_amd64.s
new file mode 100644
-index 00000000000000..2b7eb57f8ae783
+index 00000000000000..623852da4937cb
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_amd64.s
-@@ -0,0 +1,39 @@
+@@ -0,0 +1,41 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2009 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.
@@ -14496,10 +14592,12 @@ index 00000000000000..2b7eb57f8ae783
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_arm.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_arm.s
new file mode 100644
-index 00000000000000..68034e6035aa44
+index 00000000000000..2a24150b337120
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_arm.s
@@ -0,0 +1,52 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2012 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.
@@ -14534,8 +14632,6 @@ index 00000000000000..68034e6035aa44
+ MOVD F14, (13*4+8*7)(R13)
+ MOVD F15, (13*4+8*8)(R13)
+
-+ BL runtime·load_g(SB)
-+
+ // We set up the arguments to cgocallback when saving registers above.
+ BL runtime·cgocallback(SB)
+
@@ -14554,10 +14650,12 @@ index 00000000000000..68034e6035aa44
+ MOVW R14, R15
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_arm64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_arm64.s
new file mode 100644
-index 00000000000000..50e5261d922c56
+index 00000000000000..ff58b16c050af6
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_arm64.s
-@@ -0,0 +1,36 @@
+@@ -0,0 +1,37 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2015 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.
@@ -14585,7 +14683,6 @@ index 00000000000000..50e5261d922c56
+ STP (R29, R30), (8*22)(RSP)
+
+ // Initialize Go ABI environment
-+ BL runtime·load_g(SB)
+ BL runtime·cgocallback(SB)
+
+ RESTORE_R19_TO_R28(8*4)
@@ -14596,10 +14693,12 @@ index 00000000000000..50e5261d922c56
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_loong64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_loong64.s
new file mode 100644
-index 00000000000000..e81df86a56e4ad
+index 00000000000000..e3c8afb0d7f7de
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_loong64.s
@@ -0,0 +1,40 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// 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.
@@ -14629,8 +14728,6 @@ index 00000000000000..e81df86a56e4ad
+ MOVV R1, (22*8)(R3)
+
+ // Initialize Go ABI environment
-+ JAL runtime·load_g(SB)
-+
+ JAL runtime·cgocallback(SB)
+
+ RESTORE_R22_TO_R31((4*8))
@@ -14642,10 +14739,12 @@ index 00000000000000..e81df86a56e4ad
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_ppc64le.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_ppc64le.s
new file mode 100644
-index 00000000000000..6d1938cd8d8bcd
+index 00000000000000..98fa0d54133219
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_ppc64le.s
-@@ -0,0 +1,82 @@
+@@ -0,0 +1,81 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2014 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.
@@ -14698,9 +14797,6 @@ index 00000000000000..6d1938cd8d8bcd
+ // Initialize R0 to 0 as expected by Go
+ MOVD $0, R0
+
-+ // Load the current g.
-+ BL runtime·load_g(SB)
-+
+ // Set up arguments for cgocallback
+ MOVD R3, FIXED_FRAME+0(R1) // fn unsafe.Pointer
+ MOVD R4, FIXED_FRAME+8(R1) // a unsafe.Pointer
@@ -14730,10 +14826,12 @@ index 00000000000000..6d1938cd8d8bcd
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_riscv64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_riscv64.s
new file mode 100644
-index 00000000000000..d34699e5a84d2a
+index 00000000000000..4bb9b1d3a0a2ad
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_riscv64.s
-@@ -0,0 +1,37 @@
+@@ -0,0 +1,38 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2020 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.
@@ -14761,7 +14859,6 @@ index 00000000000000..d34699e5a84d2a
+ SAVE_FPR((8*17))
+
+ // Initialize Go ABI environment
-+ CALL runtime·load_g(SB)
+ CALL runtime·cgocallback(SB)
+
+ RESTORE_GPR((8*4))
@@ -14773,10 +14870,12 @@ index 00000000000000..d34699e5a84d2a
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_s390x.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_s390x.s
new file mode 100644
-index 00000000000000..b64466501dee38
+index 00000000000000..fb393d4c534a8b
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/asm_s390x.s
-@@ -0,0 +1,55 @@
+@@ -0,0 +1,54 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2016 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.
@@ -14806,9 +14905,6 @@ index 00000000000000..b64466501dee38
+ FMOVD F14, 80(R15)
+ FMOVD F15, 88(R15)
+
-+ // Initialize Go ABI environment.
-+ BL runtime·load_g(SB)
-+
+ MOVD R2, 8(R15) // fn unsafe.Pointer
+ MOVD R3, 16(R15) // a unsafe.Pointer
+
@@ -14834,10 +14930,12 @@ index 00000000000000..b64466501dee38
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/callbacks.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/callbacks.go
new file mode 100644
-index 00000000000000..f29e690cc15b3a
+index 00000000000000..b6ef14af7ef4f8
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/callbacks.go
-@@ -0,0 +1,93 @@
+@@ -0,0 +1,95 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2011 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.
@@ -14933,10 +15031,12 @@ index 00000000000000..f29e690cc15b3a
+)
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/fakecgo.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/fakecgo.go
new file mode 100644
-index 00000000000000..58b95e1f4157f2
+index 00000000000000..17c6f83475ce5e
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/fakecgo.go
-@@ -0,0 +1,14 @@
+@@ -0,0 +1,16 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
@@ -14953,19 +15053,21 @@ index 00000000000000..58b95e1f4157f2
+func call5(fn, a1, a2, a3, a4, a5 uintptr) uintptr
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/fakecgo.lock b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/fakecgo.lock
new file mode 100644
-index 00000000000000..9b0650d53777bd
+index 00000000000000..3a842170f1f5e8
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/fakecgo.lock
@@ -0,0 +1,3 @@
+{
-+ "commit_hash": "5110604b3385278be6887d0feead513a1bfe7a82"
++ "commit_hash": "1512f327e9958354283654ee4497800e33a7b838"
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/freebsd.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/freebsd.go
new file mode 100644
-index 00000000000000..bb73a709e69188
+index 00000000000000..fd301098885920
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/freebsd.go
-@@ -0,0 +1,27 @@
+@@ -0,0 +1,29 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2010 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.
@@ -15007,10 +15109,12 @@ index 00000000000000..88c4cdf9ec04cc
+//go:generate go run update_tool.go
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_darwin.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_darwin.go
new file mode 100644
-index 00000000000000..d0868f0f790351
+index 00000000000000..e49117058f381e
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_darwin.go
-@@ -0,0 +1,88 @@
+@@ -0,0 +1,90 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2011 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.
@@ -15101,10 +15205,12 @@ index 00000000000000..d0868f0f790351
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_freebsd.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_freebsd.go
new file mode 100644
-index 00000000000000..55ff71e2672086
+index 00000000000000..928c5245c84d29
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_freebsd.go
-@@ -0,0 +1,79 @@
+@@ -0,0 +1,81 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2011 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.
@@ -15186,10 +15292,12 @@ index 00000000000000..55ff71e2672086
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_libinit.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_libinit.go
new file mode 100644
-index 00000000000000..e5a66f39d4f3f5
+index 00000000000000..38ba01bb4f273d
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_libinit.go
-@@ -0,0 +1,72 @@
+@@ -0,0 +1,74 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -15264,10 +15372,12 @@ index 00000000000000..e5a66f39d4f3f5
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_linux.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_linux.go
new file mode 100644
-index 00000000000000..089d9fe489407b
+index 00000000000000..2018c6dc2e1b85
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_linux.go
-@@ -0,0 +1,79 @@
+@@ -0,0 +1,81 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2011 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.
@@ -15349,10 +15459,12 @@ index 00000000000000..089d9fe489407b
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_setenv.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_setenv.go
new file mode 100644
-index 00000000000000..e42d84f0b75ea6
+index 00000000000000..4d24dae4e11cc4
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_setenv.go
-@@ -0,0 +1,18 @@
+@@ -0,0 +1,20 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -15373,10 +15485,12 @@ index 00000000000000..e42d84f0b75ea6
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_util.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_util.go
new file mode 100644
-index 00000000000000..ff190007e8b6c0
+index 00000000000000..6a1731e3bee8e5
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/go_util.go
-@@ -0,0 +1,38 @@
+@@ -0,0 +1,40 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -15417,10 +15531,12 @@ index 00000000000000..ff190007e8b6c0
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/iscgo.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/iscgo.go
new file mode 100644
-index 00000000000000..28af41cc640724
+index 00000000000000..eb8ec0e7f94b99
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/iscgo.go
-@@ -0,0 +1,19 @@
+@@ -0,0 +1,21 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2010 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.
@@ -15442,10 +15558,12 @@ index 00000000000000..28af41cc640724
+var _iscgo bool = true
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo.go
new file mode 100644
-index 00000000000000..38f94419397d8d
+index 00000000000000..418a3951bfc621
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo.go
-@@ -0,0 +1,39 @@
+@@ -0,0 +1,41 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -15487,10 +15605,12 @@ index 00000000000000..38f94419397d8d
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo_darwin.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo_darwin.go
new file mode 100644
-index 00000000000000..ecdcb2e7852560
+index 00000000000000..2f7a973b34a3a3
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo_darwin.go
-@@ -0,0 +1,26 @@
+@@ -0,0 +1,28 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -15519,10 +15639,12 @@ index 00000000000000..ecdcb2e7852560
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo_freebsd.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo_freebsd.go
new file mode 100644
-index 00000000000000..4bfb70c3d5ee9a
+index 00000000000000..d7cc9f31a98255
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo_freebsd.go
-@@ -0,0 +1,20 @@
+@@ -0,0 +1,22 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -15545,10 +15667,12 @@ index 00000000000000..4bfb70c3d5ee9a
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo_linux.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo_linux.go
new file mode 100644
-index 00000000000000..b08a44a1001bc0
+index 00000000000000..ace87e2201bfba
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/libcgo_linux.go
-@@ -0,0 +1,20 @@
+@@ -0,0 +1,22 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -15571,10 +15695,12 @@ index 00000000000000..b08a44a1001bc0
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/linux.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/linux.go
new file mode 100644
-index 00000000000000..f98e272e42720e
+index 00000000000000..0fbf6bcac87f2b
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/linux.go
-@@ -0,0 +1,184 @@
+@@ -0,0 +1,186 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2016 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.
@@ -15761,10 +15887,12 @@ index 00000000000000..f98e272e42720e
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/setenv.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/setenv.go
new file mode 100644
-index 00000000000000..f30af0e1515699
+index 00000000000000..30b9e8eb88c83d
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/setenv.go
-@@ -0,0 +1,19 @@
+@@ -0,0 +1,21 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Copyright 2011 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.
@@ -15786,10 +15914,12 @@ index 00000000000000..f30af0e1515699
+var _cgo_unsetenv = &x_cgo_unsetenv_trampoline
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_386.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_386.s
new file mode 100644
-index 00000000000000..cf56a6c71575eb
+index 00000000000000..5067c5533d14ae
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_386.s
-@@ -0,0 +1,121 @@
+@@ -0,0 +1,123 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -15913,10 +16043,12 @@ index 00000000000000..cf56a6c71575eb
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_amd64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_amd64.s
new file mode 100644
-index 00000000000000..a4ca5ea98214fd
+index 00000000000000..049e2bbb1e7f44
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_amd64.s
-@@ -0,0 +1,107 @@
+@@ -0,0 +1,109 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -16026,10 +16158,12 @@ index 00000000000000..a4ca5ea98214fd
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_arm.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_arm.s
new file mode 100644
-index 00000000000000..c17925d60d6787
+index 00000000000000..3c0e1d00bd90f6
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_arm.s
-@@ -0,0 +1,122 @@
+@@ -0,0 +1,124 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -16154,10 +16288,12 @@ index 00000000000000..c17925d60d6787
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_arm64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_arm64.s
new file mode 100644
-index 00000000000000..1deb2747ad3245
+index 00000000000000..1a072538b12e3e
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_arm64.s
-@@ -0,0 +1,81 @@
+@@ -0,0 +1,83 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
@@ -16241,10 +16377,12 @@ index 00000000000000..1deb2747ad3245
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_386.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_386.s
new file mode 100644
-index 00000000000000..eea96638fa9a9b
+index 00000000000000..a917675cc5862a
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_386.s
-@@ -0,0 +1,78 @@
+@@ -0,0 +1,80 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -16325,10 +16463,12 @@ index 00000000000000..eea96638fa9a9b
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_amd64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_amd64.s
new file mode 100644
-index 00000000000000..424ebc1e7cbb42
+index 00000000000000..fc2e4476c4813c
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_amd64.s
-@@ -0,0 +1,69 @@
+@@ -0,0 +1,71 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -16400,10 +16540,12 @@ index 00000000000000..424ebc1e7cbb42
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_arm.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_arm.s
new file mode 100644
-index 00000000000000..284fe5d0e3a87a
+index 00000000000000..4b84a54da30cc7
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_arm.s
-@@ -0,0 +1,69 @@
+@@ -0,0 +1,71 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -16475,10 +16617,12 @@ index 00000000000000..284fe5d0e3a87a
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_arm64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_arm64.s
new file mode 100644
-index 00000000000000..771910817b7686
+index 00000000000000..1d895b9dea7a87
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_arm64.s
-@@ -0,0 +1,60 @@
+@@ -0,0 +1,62 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -16541,10 +16685,12 @@ index 00000000000000..771910817b7686
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_loong64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_loong64.s
new file mode 100644
-index 00000000000000..ebcc1176c0a0a6
+index 00000000000000..d390a5f1da0af5
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_loong64.s
-@@ -0,0 +1,60 @@
+@@ -0,0 +1,62 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -16607,10 +16753,12 @@ index 00000000000000..ebcc1176c0a0a6
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_ppc64le.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_ppc64le.s
new file mode 100644
-index 00000000000000..59a95a929fb5c2
+index 00000000000000..1abccdc7a0ebdd
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_ppc64le.s
-@@ -0,0 +1,69 @@
+@@ -0,0 +1,71 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -16682,10 +16830,12 @@ index 00000000000000..59a95a929fb5c2
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_riscv64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_riscv64.s
new file mode 100644
-index 00000000000000..9e892dbd2daf71
+index 00000000000000..c78f98e8c89c09
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_linux_riscv64.s
-@@ -0,0 +1,60 @@
+@@ -0,0 +1,62 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -16807,10 +16957,12 @@ index 00000000000000..ce4247c989f4c1
+ BR R1
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_loong64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_loong64.s
new file mode 100644
-index 00000000000000..b93b5da90a8333
+index 00000000000000..512a8dddf0be56
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_loong64.s
-@@ -0,0 +1,78 @@
+@@ -0,0 +1,80 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
@@ -16891,10 +17043,12 @@ index 00000000000000..b93b5da90a8333
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_ppc64le.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_ppc64le.s
new file mode 100644
-index 00000000000000..444529d8ae820b
+index 00000000000000..55f88c03cd4795
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_ppc64le.s
-@@ -0,0 +1,128 @@
+@@ -0,0 +1,134 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -16944,15 +17098,19 @@ index 00000000000000..444529d8ae820b
+
+// func setg_trampoline(setg uintptr, g uintptr)
+TEXT ·setg_trampoline(SB), NOSPLIT, $16-16
-+ MOVD R31, 8(R1) // save R31 (load_g clobbers it)
++ MOVD R31, 8(R1) // save R31
+
+ MOVD setg+0(FP), R12
+ MOVD newg+8(FP), R3
+
++ MOVD R3, 16(R1) // save newg before call
++
+ MOVD R12, CTR
+ CALL CTR
+
-+ CALL runtime·load_g(SB)
++ // Assign g directly instead of calling runtime·load_g
++ // setg_gcc has already stored newg into TLS; put it in the g register too.
++ MOVD 16(R1), g
+
+ MOVD 8(R1), R31
+ XOR R0, R0, R0
@@ -17025,10 +17183,12 @@ index 00000000000000..444529d8ae820b
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_riscv64.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_riscv64.s
new file mode 100644
-index 00000000000000..b162fdde234629
+index 00000000000000..2e4f60db002a44
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_riscv64.s
-@@ -0,0 +1,76 @@
+@@ -0,0 +1,78 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -17107,10 +17267,10 @@ index 00000000000000..b162fdde234629
+ RET
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_s390x.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_s390x.s
new file mode 100644
-index 00000000000000..2b68d438e4ec1d
+index 00000000000000..258c4a33c368e4
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/trampolines_s390x.s
-@@ -0,0 +1,154 @@
+@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
@@ -17198,9 +17358,13 @@ index 00000000000000..2b68d438e4ec1d
+ SUB $160, R15
+ MOVD R3, 0(R15)
+ MOVD R0, 112(R15)
++ MOVD R2, 120(R15) // save newg before call
++
++ BL R1 // call setg_gcc
+
-+ BL R1 // call setg_gcc
-+ BL runtime·load_g(SB)
++ // Assign g directly instead of calling runtime·load_g
++ // setg_gcc has already stored newg into TLS; put it in the g register too.
++ MOVD 120(R15), g
+
+ MOVD 112(R15), R14
+ ADD $160, R15
@@ -17267,10 +17431,12 @@ index 00000000000000..2b68d438e4ec1d
+ BR R14
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols.go
new file mode 100644
-index 00000000000000..e1339193b9764d
+index 00000000000000..eb26fa04fee744
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols.go
-@@ -0,0 +1,165 @@
+@@ -0,0 +1,167 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -17438,10 +17604,12 @@ index 00000000000000..e1339193b9764d
+var pthread_setspecificABI0 = uintptr(unsafe.Pointer(&_pthread_setspecific))
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols_darwin.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols_darwin.go
new file mode 100644
-index 00000000000000..960f8168eb88d7
+index 00000000000000..a7a0d9e69d4d8b
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols_darwin.go
-@@ -0,0 +1,59 @@
+@@ -0,0 +1,61 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -17503,10 +17671,12 @@ index 00000000000000..960f8168eb88d7
+var pthread_attr_setstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_setstacksize))
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols_freebsd.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols_freebsd.go
new file mode 100644
-index 00000000000000..d69775596fddf3
+index 00000000000000..d5a24b1cde00a7
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols_freebsd.go
-@@ -0,0 +1,48 @@
+@@ -0,0 +1,50 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -17557,10 +17727,12 @@ index 00000000000000..d69775596fddf3
+var pthread_attr_destroyABI0 = uintptr(unsafe.Pointer(&_pthread_attr_destroy))
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols_linux.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols_linux.go
new file mode 100644
-index 00000000000000..cbb120431ab6bb
+index 00000000000000..ab4e0d77cf70d0
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/zsymbols_linux.go
-@@ -0,0 +1,158 @@
+@@ -0,0 +1,160 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -17721,10 +17893,12 @@ index 00000000000000..cbb120431ab6bb
+var pthread_attr_destroyABI0 = uintptr(unsafe.Pointer(&_pthread_attr_destroy))
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_darwin.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_darwin.s
new file mode 100644
-index 00000000000000..35ef7ac11cb955
+index 00000000000000..9038f8394965e8
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_darwin.s
-@@ -0,0 +1,19 @@
+@@ -0,0 +1,21 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -17746,10 +17920,12 @@ index 00000000000000..35ef7ac11cb955
+ JMP purego_pthread_attr_setstacksize(SB)
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_freebsd.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_freebsd.s
new file mode 100644
-index 00000000000000..da07005c0bc988
+index 00000000000000..0e0dbfaaed15dd
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_freebsd.s
-@@ -0,0 +1,16 @@
+@@ -0,0 +1,18 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -17768,10 +17944,12 @@ index 00000000000000..da07005c0bc988
+ JMP purego_pthread_attr_destroy(SB)
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_linux.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_linux.s
new file mode 100644
-index 00000000000000..ba2cb38918d538
+index 00000000000000..561f4af7545d4e
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_linux.s
-@@ -0,0 +1,46 @@
+@@ -0,0 +1,48 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -17820,10 +17998,12 @@ index 00000000000000..ba2cb38918d538
+ JMP purego_pthread_attr_destroy(SB)
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_stubs.s b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_stubs.s
new file mode 100644
-index 00000000000000..067583d68517a9
+index 00000000000000..6adce1818015af
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/fakecgo/ztrampolines_stubs.s
-@@ -0,0 +1,55 @@
+@@ -0,0 +1,57 @@
++// Code generated by update_tool.go from ebitengine/purego; DO NOT EDIT.
++
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
@@ -19067,10 +19247,10 @@ index 00000000000000..9acac55865dc17
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/shims.h b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/shims.h
new file mode 100644
-index 00000000000000..9a47c5bf820472
+index 00000000000000..f5f4918ac54163
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/shims.h
-@@ -0,0 +1,446 @@
+@@ -0,0 +1,448 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -19353,6 +19533,7 @@ index 00000000000000..9a47c5bf820472
+void EVP_CIPHER_CTX_free(_EVP_CIPHER_CTX_PTR arg0);
+int EVP_CIPHER_CTX_ctrl(_EVP_CIPHER_CTX_PTR ctx, int type, int arg, void *ptr);
+int EVP_CipherInit_ex(_EVP_CIPHER_CTX_PTR ctx, const _EVP_CIPHER_PTR type, _ENGINE_PTR impl, const unsigned char *key, const unsigned char *iv, int enc);
++int EVP_CipherInit_ex2(_EVP_CIPHER_CTX_PTR ctx, const _EVP_CIPHER_PTR type, const unsigned char *key, const unsigned char *iv, int enc, const _OSSL_PARAM_PTR params) __attribute__((tag("3")));
+int EVP_CipherUpdate(_EVP_CIPHER_CTX_PTR ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) __attribute__((noescape,nocallback,slice("out","outl"),slice("in","inl")));
+int EVP_EncryptInit_ex(_EVP_CIPHER_CTX_PTR ctx, const _EVP_CIPHER_PTR type, _ENGINE_PTR impl, const unsigned char *key, const unsigned char *iv);
+int EVP_EncryptUpdate(_EVP_CIPHER_CTX_PTR ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) __attribute__((noescape,nocallback,slice("out","outl"),slice("in","inl")));
@@ -19376,6 +19557,7 @@ index 00000000000000..9a47c5bf820472
+size_t EVP_PKEY_get1_encoded_public_key(_EVP_PKEY_PTR pkey, unsigned char **ppub) __attribute__((tag("3")));
+int EVP_PKEY_get_bn_param(const _EVP_PKEY_PTR pkey, const char *key_name, _BIGNUM_PTR *bn) __attribute__((tag("3"),noescape,nocallback));
+int EVP_PKEY_get_octet_string_param(const _EVP_PKEY_PTR pkey, const char *key_name, unsigned char *buf, size_t buf_len, size_t *out_len) __attribute__((tag("3"),slice("buf","buf_len")));
++int EVP_PKEY_eq(const _EVP_PKEY_PTR a, const _EVP_PKEY_PTR b) __attribute__((tag("3"),noescape,nocallback));
+int EVP_PKEY_up_ref(_EVP_PKEY_PTR key);
+int EVP_PKEY_set1_EC_KEY(_EVP_PKEY_PTR pkey, _EC_KEY_PTR key) __attribute__((tag("legacy_1")));
+int EVP_PKEY_CTX_set0_rsa_oaep_label(_EVP_PKEY_CTX_PTR ctx, void *label, int labellen) __attribute__((tag("3"),slice("label","labellen")));
@@ -19845,10 +20027,10 @@ index 00000000000000..7d382b9a5c288c
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl.c b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl.c
new file mode 100644
-index 00000000000000..8abb6430c2a6e7
+index 00000000000000..18c2978e636dc8
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl.c
-@@ -0,0 +1,2083 @@
+@@ -0,0 +1,2101 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -19918,6 +20100,7 @@ index 00000000000000..8abb6430c2a6e7
+const char* (*_g_EVP_CIPHER_get0_name)(const _EVP_CIPHER_PTR);
+int (*_g_EVP_CIPHER_get_block_size)(const _EVP_CIPHER_PTR);
+int (*_g_EVP_CipherInit_ex)(_EVP_CIPHER_CTX_PTR, const _EVP_CIPHER_PTR, _ENGINE_PTR, const unsigned char*, const unsigned char*, int);
++int (*_g_EVP_CipherInit_ex2)(_EVP_CIPHER_CTX_PTR, const _EVP_CIPHER_PTR, const unsigned char*, const unsigned char*, int, const _OSSL_PARAM_PTR);
+int (*_g_EVP_CipherUpdate)(_EVP_CIPHER_CTX_PTR, unsigned char*, int*, const unsigned char*, int);
+int (*_g_EVP_DecryptFinal_ex)(_EVP_CIPHER_CTX_PTR, unsigned char*, int*);
+int (*_g_EVP_DecryptInit_ex)(_EVP_CIPHER_CTX_PTR, const _EVP_CIPHER_PTR, _ENGINE_PTR, const unsigned char*, const unsigned char*);
@@ -19995,6 +20178,7 @@ index 00000000000000..8abb6430c2a6e7
+int (*_g_EVP_PKEY_encapsulate_init)(_EVP_PKEY_CTX_PTR, const _OSSL_PARAM_PTR);
+int (*_g_EVP_PKEY_encrypt)(_EVP_PKEY_CTX_PTR, unsigned char*, size_t*, const unsigned char*, size_t);
+int (*_g_EVP_PKEY_encrypt_init)(_EVP_PKEY_CTX_PTR);
++int (*_g_EVP_PKEY_eq)(const _EVP_PKEY_PTR, const _EVP_PKEY_PTR);
+void (*_g_EVP_PKEY_free)(_EVP_PKEY_PTR);
+int (*_g_EVP_PKEY_fromdata)(_EVP_PKEY_CTX_PTR, _EVP_PKEY_PTR*, int, _OSSL_PARAM_PTR);
+int (*_g_EVP_PKEY_fromdata_init)(_EVP_PKEY_CTX_PTR);
@@ -20353,6 +20537,7 @@ index 00000000000000..8abb6430c2a6e7
+ __mkcgo__dlsym(EVP_CIPHER_fetch)
+ __mkcgo__dlsym(EVP_CIPHER_get0_name)
+ __mkcgo__dlsym(EVP_CIPHER_get_block_size)
++ __mkcgo__dlsym(EVP_CipherInit_ex2)
+ __mkcgo__dlsym(EVP_KDF_CTX_free)
+ __mkcgo__dlsym(EVP_KDF_CTX_get_kdf_size)
+ __mkcgo__dlsym(EVP_KDF_CTX_new)
@@ -20394,6 +20579,7 @@ index 00000000000000..8abb6430c2a6e7
+ __mkcgo__dlsym(EVP_PKEY_decapsulate_init)
+ __mkcgo__dlsym(EVP_PKEY_encapsulate)
+ __mkcgo__dlsym(EVP_PKEY_encapsulate_init)
++ __mkcgo__dlsym(EVP_PKEY_eq)
+ __mkcgo__dlsym(EVP_PKEY_fromdata)
+ __mkcgo__dlsym(EVP_PKEY_fromdata_init)
+ __mkcgo__dlsym(EVP_PKEY_get1_encoded_public_key)
@@ -20428,6 +20614,7 @@ index 00000000000000..8abb6430c2a6e7
+ _g_EVP_CIPHER_fetch = NULL;
+ _g_EVP_CIPHER_get0_name = NULL;
+ _g_EVP_CIPHER_get_block_size = NULL;
++ _g_EVP_CipherInit_ex2 = NULL;
+ _g_EVP_KDF_CTX_free = NULL;
+ _g_EVP_KDF_CTX_get_kdf_size = NULL;
+ _g_EVP_KDF_CTX_new = NULL;
@@ -20469,6 +20656,7 @@ index 00000000000000..8abb6430c2a6e7
+ _g_EVP_PKEY_decapsulate_init = NULL;
+ _g_EVP_PKEY_encapsulate = NULL;
+ _g_EVP_PKEY_encapsulate_init = NULL;
++ _g_EVP_PKEY_eq = NULL;
+ _g_EVP_PKEY_fromdata = NULL;
+ _g_EVP_PKEY_fromdata_init = NULL;
+ _g_EVP_PKEY_get1_encoded_public_key = NULL;
@@ -20914,6 +21102,12 @@ index 00000000000000..8abb6430c2a6e7
+ return _ret;
+}
+
++int _mkcgo_EVP_CipherInit_ex2(_EVP_CIPHER_CTX_PTR _arg0, const _EVP_CIPHER_PTR _arg1, const unsigned char* _arg2, const unsigned char* _arg3, int _arg4, const _OSSL_PARAM_PTR _arg5, uintptr_t *_err_state) {
++ int _ret = _g_EVP_CipherInit_ex2(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
++ if (_ret <= 0) *_err_state = mkcgo_err_retrieve();
++ return _ret;
++}
++
+int _mkcgo_EVP_CipherUpdate(_EVP_CIPHER_CTX_PTR _arg0, unsigned char* _arg1, int* _arg2, const unsigned char* _arg3, int _arg4, uintptr_t *_err_state) {
+ int _ret = _g_EVP_CipherUpdate(_arg0, _arg1, _arg2, _arg3, _arg4);
+ if (_ret <= 0) *_err_state = mkcgo_err_retrieve();
@@ -21390,6 +21584,12 @@ index 00000000000000..8abb6430c2a6e7
+ return _ret;
+}
+
++int _mkcgo_EVP_PKEY_eq(const _EVP_PKEY_PTR _arg0, const _EVP_PKEY_PTR _arg1, uintptr_t *_err_state) {
++ int _ret = _g_EVP_PKEY_eq(_arg0, _arg1);
++ if (_ret <= 0) *_err_state = mkcgo_err_retrieve();
++ return _ret;
++}
++
+void _mkcgo_EVP_PKEY_free(_EVP_PKEY_PTR _arg0) {
+ _g_EVP_PKEY_free(_arg0);
+}
@@ -22016,10 +22216,10 @@ index 00000000000000..a73b6a785f0265
+)
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl.h b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl.h
new file mode 100644
-index 00000000000000..152e26e99367e9
+index 00000000000000..95ba94df4e1c49
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl.h
-@@ -0,0 +1,375 @@
+@@ -0,0 +1,377 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -22206,6 +22406,7 @@ index 00000000000000..152e26e99367e9
+const char* _mkcgo_EVP_CIPHER_get0_name(const _EVP_CIPHER_PTR);
+int _mkcgo_EVP_CIPHER_get_block_size(const _EVP_CIPHER_PTR);
+int _mkcgo_EVP_CipherInit_ex(_EVP_CIPHER_CTX_PTR, const _EVP_CIPHER_PTR, _ENGINE_PTR, const unsigned char*, const unsigned char*, int, uintptr_t *);
++int _mkcgo_EVP_CipherInit_ex2(_EVP_CIPHER_CTX_PTR, const _EVP_CIPHER_PTR, const unsigned char*, const unsigned char*, int, const _OSSL_PARAM_PTR, uintptr_t *);
+int _mkcgo_EVP_CipherUpdate(_EVP_CIPHER_CTX_PTR, unsigned char*, int*, const unsigned char*, int, uintptr_t *);
+int _mkcgo_EVP_DecryptFinal_ex(_EVP_CIPHER_CTX_PTR, unsigned char*, int*, uintptr_t *);
+int _mkcgo_EVP_DecryptInit_ex(_EVP_CIPHER_CTX_PTR, const _EVP_CIPHER_PTR, _ENGINE_PTR, const unsigned char*, const unsigned char*, uintptr_t *);
@@ -22288,6 +22489,7 @@ index 00000000000000..152e26e99367e9
+int _mkcgo_EVP_PKEY_encapsulate_init(_EVP_PKEY_CTX_PTR, const _OSSL_PARAM_PTR, uintptr_t *);
+int _mkcgo_EVP_PKEY_encrypt(_EVP_PKEY_CTX_PTR, unsigned char*, size_t*, const unsigned char*, size_t, uintptr_t *);
+int _mkcgo_EVP_PKEY_encrypt_init(_EVP_PKEY_CTX_PTR, uintptr_t *);
++int _mkcgo_EVP_PKEY_eq(const _EVP_PKEY_PTR, const _EVP_PKEY_PTR, uintptr_t *);
+void _mkcgo_EVP_PKEY_free(_EVP_PKEY_PTR);
+int _mkcgo_EVP_PKEY_fromdata(_EVP_PKEY_CTX_PTR, _EVP_PKEY_PTR*, int, _OSSL_PARAM_PTR, uintptr_t *);
+int _mkcgo_EVP_PKEY_fromdata_init(_EVP_PKEY_CTX_PTR, uintptr_t *);
@@ -22397,10 +22599,10 @@ index 00000000000000..152e26e99367e9
+#endif // MKCGO_H
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl_cgo.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl_cgo.go
new file mode 100644
-index 00000000000000..2eb57068990277
+index 00000000000000..c774468b970dce
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl_cgo.go
-@@ -0,0 +1,1513 @@
+@@ -0,0 +1,1527 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -22469,6 +22671,8 @@ index 00000000000000..2eb57068990277
+#cgo nocallback _mkcgo_EVP_PKEY_Q_keygen_X25519
+#cgo noescape _mkcgo_EVP_PKEY_derive
+#cgo nocallback _mkcgo_EVP_PKEY_derive
++#cgo noescape _mkcgo_EVP_PKEY_eq
++#cgo nocallback _mkcgo_EVP_PKEY_eq
+#cgo noescape _mkcgo_EVP_PKEY_get_bn_param
+#cgo nocallback _mkcgo_EVP_PKEY_get_bn_param
+#cgo noescape _mkcgo_EVP_PKEY_get_raw_private_key
@@ -22849,6 +23053,12 @@ index 00000000000000..2eb57068990277
+ return int32(_ret), newMkcgoErr("EVP_CipherInit_ex", uintptr(_err))
+}
+
++func EVP_CipherInit_ex2(ctx EVP_CIPHER_CTX_PTR, __type EVP_CIPHER_PTR, key *byte, iv *byte, enc int32, params OSSL_PARAM_PTR) (int32, error) {
++ var _err C.uintptr_t
++ _ret := C._mkcgo_EVP_CipherInit_ex2(ctx, __type, (*C.uchar)(unsafe.Pointer(key)), (*C.uchar)(unsafe.Pointer(iv)), C.int(enc), params, mkcgoNoEscape(&_err))
++ return int32(_ret), newMkcgoErr("EVP_CipherInit_ex2", uintptr(_err))
++}
++
+func EVP_CipherUpdate(ctx EVP_CIPHER_CTX_PTR, out []byte, outl *int32, in []byte) (int32, error) {
+ if outl != nil && int(*outl) > len(out) {
+ panic("EVP_CipherUpdate: *outl exceeds len(out)")
@@ -23361,6 +23571,12 @@ index 00000000000000..2eb57068990277
+ return int32(_ret), newMkcgoErr("EVP_PKEY_encrypt_init", uintptr(_err))
+}
+
++func EVP_PKEY_eq(a EVP_PKEY_PTR, b EVP_PKEY_PTR) (int32, error) {
++ var _err C.uintptr_t
++ _ret := C._mkcgo_EVP_PKEY_eq(a, b, mkcgoNoEscape(&_err))
++ return int32(_ret), newMkcgoErr("EVP_PKEY_eq", uintptr(_err))
++}
++
+func EVP_PKEY_free(arg0 EVP_PKEY_PTR) {
+ C._mkcgo_EVP_PKEY_free(arg0)
+}
@@ -23916,10 +24132,10 @@ index 00000000000000..2eb57068990277
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl_nocgo.go b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl_nocgo.go
new file mode 100644
-index 00000000000000..4323bdad14f62f
+index 00000000000000..a81137ddaf02f7
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/internal/ossl/zossl_nocgo.go
-@@ -0,0 +1,2481 @@
+@@ -0,0 +1,2501 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -24353,6 +24569,14 @@ index 00000000000000..4323bdad14f62f
+ return int32(r0), newMkcgoErr("EVP_CipherInit_ex", _err)
+}
+
++var _mkcgo_EVP_CipherInit_ex2 uintptr
++
++func EVP_CipherInit_ex2(ctx EVP_CIPHER_CTX_PTR, __type EVP_CIPHER_PTR, key *byte, iv *byte, enc int32, params OSSL_PARAM_PTR) (int32, error) {
++ var _err uintptr
++ r0, _ := syscallN(3, _mkcgo_EVP_CipherInit_ex2, uintptr(ctx), uintptr(__type), uintptr(mkcgoEscapePtrOssl(unsafe.Pointer(key))), uintptr(mkcgoEscapePtrOssl(unsafe.Pointer(iv))), uintptr(enc), uintptr(params), uintptr(unsafe.Pointer(&_err)))
++ return int32(r0), newMkcgoErr("EVP_CipherInit_ex2", _err)
++}
++
+var _mkcgo_EVP_CipherUpdate uintptr
+
+func EVP_CipherUpdate(ctx EVP_CIPHER_CTX_PTR, out []byte, outl *int32, in []byte) (int32, error) {
@@ -25034,6 +25258,14 @@ index 00000000000000..4323bdad14f62f
+ return int32(r0), newMkcgoErr("EVP_PKEY_encrypt_init", _err)
+}
+
++var _mkcgo_EVP_PKEY_eq uintptr
++
++func EVP_PKEY_eq(a EVP_PKEY_PTR, b EVP_PKEY_PTR) (int32, error) {
++ var _err uintptr
++ r0, _ := syscallN(3, _mkcgo_EVP_PKEY_eq, uintptr(a), uintptr(b), uintptr(unsafe.Pointer(&_err)))
++ return int32(r0), newMkcgoErr("EVP_PKEY_eq", _err)
++}
++
+var _mkcgo_EVP_PKEY_free uintptr
+
+func EVP_PKEY_free(arg0 EVP_PKEY_PTR) {
@@ -26103,6 +26335,7 @@ index 00000000000000..4323bdad14f62f
+ _mkcgo_EVP_CIPHER_fetch = dlsym(handle, "EVP_CIPHER_fetch\x00", false)
+ _mkcgo_EVP_CIPHER_get0_name = dlsym(handle, "EVP_CIPHER_get0_name\x00", false)
+ _mkcgo_EVP_CIPHER_get_block_size = dlsym(handle, "EVP_CIPHER_get_block_size\x00", false)
++ _mkcgo_EVP_CipherInit_ex2 = dlsym(handle, "EVP_CipherInit_ex2\x00", false)
+ _mkcgo_EVP_KDF_CTX_free = dlsym(handle, "EVP_KDF_CTX_free\x00", false)
+ _mkcgo_EVP_KDF_CTX_get_kdf_size = dlsym(handle, "EVP_KDF_CTX_get_kdf_size\x00", false)
+ _mkcgo_EVP_KDF_CTX_new = dlsym(handle, "EVP_KDF_CTX_new\x00", false)
@@ -26144,6 +26377,7 @@ index 00000000000000..4323bdad14f62f
+ _mkcgo_EVP_PKEY_decapsulate_init = dlsym(handle, "EVP_PKEY_decapsulate_init\x00", false)
+ _mkcgo_EVP_PKEY_encapsulate = dlsym(handle, "EVP_PKEY_encapsulate\x00", false)
+ _mkcgo_EVP_PKEY_encapsulate_init = dlsym(handle, "EVP_PKEY_encapsulate_init\x00", false)
++ _mkcgo_EVP_PKEY_eq = dlsym(handle, "EVP_PKEY_eq\x00", false)
+ _mkcgo_EVP_PKEY_fromdata = dlsym(handle, "EVP_PKEY_fromdata\x00", false)
+ _mkcgo_EVP_PKEY_fromdata_init = dlsym(handle, "EVP_PKEY_fromdata_init\x00", false)
+ _mkcgo_EVP_PKEY_get1_encoded_public_key = dlsym(handle, "EVP_PKEY_get1_encoded_public_key\x00", false)
@@ -26178,6 +26412,7 @@ index 00000000000000..4323bdad14f62f
+ _mkcgo_EVP_CIPHER_fetch = 0
+ _mkcgo_EVP_CIPHER_get0_name = 0
+ _mkcgo_EVP_CIPHER_get_block_size = 0
++ _mkcgo_EVP_CipherInit_ex2 = 0
+ _mkcgo_EVP_KDF_CTX_free = 0
+ _mkcgo_EVP_KDF_CTX_get_kdf_size = 0
+ _mkcgo_EVP_KDF_CTX_new = 0
@@ -26219,6 +26454,7 @@ index 00000000000000..4323bdad14f62f
+ _mkcgo_EVP_PKEY_decapsulate_init = 0
+ _mkcgo_EVP_PKEY_encapsulate = 0
+ _mkcgo_EVP_PKEY_encapsulate_init = 0
++ _mkcgo_EVP_PKEY_eq = 0
+ _mkcgo_EVP_PKEY_fromdata = 0
+ _mkcgo_EVP_PKEY_fromdata_init = 0
+ _mkcgo_EVP_PKEY_get1_encoded_public_key = 0
@@ -26745,10 +26981,10 @@ index 00000000000000..410829738931c7
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/cipher.go b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/cipher.go
new file mode 100644
-index 00000000000000..10f932a02d0b36
+index 00000000000000..e69e0bcfe332df
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/cipher.go
-@@ -0,0 +1,665 @@
+@@ -0,0 +1,690 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -27372,6 +27608,10 @@ index 00000000000000..10f932a02d0b36
+ if cipher == nil {
+ panic("crypto/cipher: unsupported cipher: " + kind.String())
+ }
++ params, err := cipherInitParams(encrypt)
++ if err != nil {
++ return nil, err
++ }
+ ctx, err := ossl.EVP_CIPHER_CTX_new()
+ if err != nil {
+ return nil, err
@@ -27394,12 +27634,33 @@ index 00000000000000..10f932a02d0b36
+ // Pass nil to the next call to EVP_CipherInit_ex to avoid resetting ctx's cipher.
+ cipher = nil
+ }
-+ if _, err := ossl.EVP_CipherInit_ex(ctx, cipher, nil, base(key), base(iv), int32(encrypt)); err != nil {
++ if params != nil {
++ _, err = ossl.EVP_CipherInit_ex2(ctx, cipher, base(key), base(iv), int32(encrypt), params)
++ } else {
++ _, err = ossl.EVP_CipherInit_ex(ctx, cipher, nil, base(key), base(iv), int32(encrypt))
++ }
++ if err != nil {
+ return nil, err
+ }
+ return ctx, nil
+}
+
++var cipherEncryptCheckParams = sync.OnceValues(func() (ossl.OSSL_PARAM_PTR, error) {
++ bld := newParamBuilder()
++ bld.addInt32(_OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK, 0)
++ return bld.build()
++})
++
++func cipherInitParams(encrypt cipherOp) (ossl.OSSL_PARAM_PTR, error) {
++ if encrypt != cipherOpEncrypt || major() == 1 {
++ return nil, nil
++ }
++ // The returned params are cached for the lifetime of the process and must not be freed by callers.
++ // Setting the FIPS encrypt check to 0 allows encryption to proceed even if the key is not approved for use in FIPS mode.
++ // This check is done at the Go crypto level.
++ return cipherEncryptCheckParams()
++}
++
+// The following two functions are a mirror of golang.org/x/crypto/internal/subtle.
+
+func anyOverlap(x, y []byte) bool {
@@ -27416,10 +27677,10 @@ index 00000000000000..10f932a02d0b36
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/const.go b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/const.go
new file mode 100644
-index 00000000000000..7817e37ffdc40f
+index 00000000000000..c84521b3aa7d34
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/const.go
-@@ -0,0 +1,109 @@
+@@ -0,0 +1,115 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -27491,7 +27752,8 @@ index 00000000000000..7817e37ffdc40f
+ _OSSL_KDF_PARAM_MODE cString = "mode\x00"
+
+ // KDF FIPS parameters
-+ _OSSL_KDF_PARAM_FIPS_KEY_CHECK cString = "key-check\x00"
++ _OSSL_KDF_PARAM_FIPS_KEY_CHECK cString = "key-check\x00"
++ _OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK cString = "encrypt-check\x00"
+
+ // TLS3-KDF parameters
+ _OSSL_KDF_PARAM_PREFIX cString = "prefix\x00"
@@ -27522,8 +27784,13 @@ index 00000000000000..7817e37ffdc40f
+ _OSSL_PKEY_PARAM_ML_DSA_SEED cString = "seed\x00"
+
+ // Signature parameters
-+ _OSSL_SIGNATURE_PARAM_CONTEXT_STRING cString = "context-string\x00"
-+ _OSSL_SIGNATURE_PARAM_MU cString = "mu\x00"
++ _OSSL_SIGNATURE_PARAM_DIGEST cString = "digest\x00"
++ _OSSL_SIGNATURE_PARAM_PAD_MODE cString = "pad-mode\x00"
++ _OSSL_SIGNATURE_PARAM_PSS_SALTLEN cString = "saltlen\x00"
++ _OSSL_SIGNATURE_PARAM_CONTEXT_STRING cString = "context-string\x00"
++ _OSSL_SIGNATURE_PARAM_MU cString = "mu\x00"
++ _OSSL_SIGNATURE_PARAM_FIPS_RSA_PSS_SALTLEN_CHECK cString = "rsa-pss-saltlen-check\x00"
++ _OSSL_PKEY_RSA_PAD_MODE_PSS cString = "pss\x00"
+
+ // MAC parameters
+ _OSSL_MAC_PARAM_DIGEST cString = "digest\x00"
@@ -29130,10 +29397,10 @@ index 00000000000000..69565f949d4ac5
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/evp.go b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/evp.go
new file mode 100644
-index 00000000000000..3752d3ce4d18bd
+index 00000000000000..86e10fc0059754
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/evp.go
-@@ -0,0 +1,616 @@
+@@ -0,0 +1,634 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -29158,7 +29425,7 @@ index 00000000000000..3752d3ce4d18bd
+// This is used to avoid aborting the program when calling
+// an unsupported hash function. It is the caller's responsibility
+// to check the returned value.
-+func hashFuncHash(fn func() hash.Hash) (h hash.Hash, err error) {
++func hashFuncHash[H hash.Hash](fn func() H) (h hash.Hash, err error) {
+ defer func() {
+ r := recover()
+ if r == nil {
@@ -29195,7 +29462,7 @@ index 00000000000000..3752d3ce4d18bd
+
+// hashFuncToMD converts a hash.Hash function to a GOossl.EVP_MD_PTR.
+// See [hashFuncHash] for details on error handling.
-+func hashFuncToMD(fn func() hash.Hash) (ossl.EVP_MD_PTR, error) {
++func hashFuncToMD[H hash.Hash](fn func() H) (ossl.EVP_MD_PTR, error) {
+ h, err := hashFuncHash(fn)
+ if err != nil {
+ return nil, err
@@ -29456,19 +29723,37 @@ index 00000000000000..3752d3ce4d18bd
+ if alg == nil {
+ return errors.New("crypto/rsa: unsupported hash function")
+ }
-+ if _, err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_MD, 0, unsafe.Pointer(alg.md)); err != nil {
-+ return err
-+ }
-+ // setPadding must happen after setting EVP_PKEY_CTRL_MD.
-+ if _, err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_RSA_PADDING, ossl.RSA_PKCS1_PSS_PADDING, nil); err != nil {
-+ return err
-+ }
-+ if saltLen != 0 {
-+ if _, err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_RSA_PSS_SALTLEN, saltLen, nil); err != nil {
++ switch major() {
++ case 1:
++ if _, err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_MD, 0, unsafe.Pointer(alg.md)); err != nil {
++ return err
++ }
++ // setPadding must happen after setting EVP_PKEY_CTRL_MD.
++ if _, err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_RSA_PADDING, ossl.RSA_PKCS1_PSS_PADDING, nil); err != nil {
+ return err
+ }
++ if saltLen != 0 {
++ if _, err := ossl.EVP_PKEY_CTX_ctrl(ctx, ossl.EVP_PKEY_RSA, -1, ossl.EVP_PKEY_CTRL_RSA_PSS_SALTLEN, saltLen, nil); err != nil {
++ return err
++ }
++ }
++ return nil
++ default:
++ bld := newParamBuilder()
++ bld.addUTF8String(_OSSL_SIGNATURE_PARAM_DIGEST, ossl.EVP_MD_get0_name(alg.md), 0)
++ bld.addUTF8String(_OSSL_SIGNATURE_PARAM_PAD_MODE, _OSSL_PKEY_RSA_PAD_MODE_PSS.ptr(), 0)
++ if saltLen != 0 {
++ bld.addInt32(_OSSL_SIGNATURE_PARAM_PSS_SALTLEN, saltLen)
++ }
++ bld.addInt32(_OSSL_SIGNATURE_PARAM_FIPS_RSA_PSS_SALTLEN_CHECK, 0)
++ params, err := bld.build()
++ if err != nil {
++ return err
++ }
++ defer ossl.OSSL_PARAM_free(params)
++ _, err = ossl.EVP_PKEY_CTX_set_params(ctx, params)
++ return err
+ }
-+ return nil
+}
+
+func setPKCS1Padding(ctx ossl.EVP_PKEY_CTX_PTR, ch crypto.Hash) error {
@@ -29752,10 +30037,10 @@ index 00000000000000..3752d3ce4d18bd
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/hash.go b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/hash.go
new file mode 100644
-index 00000000000000..020323eb7be25e
+index 00000000000000..1f3d87d10da04f
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/hash.go
-@@ -0,0 +1,521 @@
+@@ -0,0 +1,518 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -29792,8 +30077,6 @@ index 00000000000000..020323eb7be25e
+// maxHashSize is the size of SHA52 and SHA3_512, the largest hashes we support.
+const maxHashSize = 64
+
-+type HashCloner = hash.Cloner
-+
+func hashOneShot(ch crypto.Hash, p []byte, sum []byte) bool {
+ _, err := ossl.EVP_Digest(p, sum, nil, loadHash(ch, true).md, nil)
+ return err == nil
@@ -29917,49 +30200,48 @@ index 00000000000000..020323eb7be25e
+}
+
+// NewMD4 returns a new MD4 hash.
-+// The returned hash doesn't implement encoding.BinaryMarshaler and
-+// encoding.BinaryUnmarshaler.
-+func NewMD4() hash.Hash {
++// State marshaling and unmarshaling return errors.ErrUnsupported.
++func NewMD4() *Hash {
+ return newHash(crypto.MD4)
+}
+
+// NewMD5 returns a new MD5 hash.
-+func NewMD5() hash.Hash {
++func NewMD5() *Hash {
+ return newHash(crypto.MD5)
+}
+
+// NewSHA1 returns a new SHA1 hash.
-+func NewSHA1() hash.Hash {
++func NewSHA1() *Hash {
+ return newHash(crypto.SHA1)
+}
+
+// NewSHA224 returns a new SHA224 hash.
-+func NewSHA224() hash.Hash {
++func NewSHA224() *Hash {
+ return newHash(crypto.SHA224)
+}
+
+// NewSHA256 returns a new SHA256 hash.
-+func NewSHA256() hash.Hash {
++func NewSHA256() *Hash {
+ return newHash(crypto.SHA256)
+}
+
+// NewSHA384 returns a new SHA384 hash.
-+func NewSHA384() hash.Hash {
++func NewSHA384() *Hash {
+ return newHash(crypto.SHA384)
+}
+
+// NewSHA512 returns a new SHA512 hash.
-+func NewSHA512() hash.Hash {
++func NewSHA512() *Hash {
+ return newHash(crypto.SHA512)
+}
+
+// NewSHA512_224 returns a new SHA512_224 hash.
-+func NewSHA512_224() hash.Hash {
++func NewSHA512_224() *Hash {
+ return newHash(crypto.SHA512_224)
+}
+
+// NewSHA512_256 returns a new SHA512_256 hash.
-+func NewSHA512_256() hash.Hash {
++func NewSHA512_256() *Hash {
+ return newHash(crypto.SHA512_256)
+}
+
@@ -29984,7 +30266,7 @@ index 00000000000000..020323eb7be25e
+}
+
+var _ hash.Hash = (*Hash)(nil)
-+var _ HashCloner = (*Hash)(nil)
++var _ hash.Cloner = (*Hash)(nil)
+
+// FIPSApprovedHash reports whether this hash algorithm is FIPS 140-3 approved.
+func FIPSApprovedHash(h hash.Hash) bool {
@@ -30029,7 +30311,7 @@ index 00000000000000..020323eb7be25e
+ // Don't call init() yet, it would be wasteful
+ // if the caller only wants to know the hash type. This
+ // is a common pattern in this package, as some functions
-+ // accept a `func() hash.Hash` parameter and call it just
++ // accept a hash constructor parameter and call it just
+ // to know the hash type.
+ return &Hash{alg: loadHash(ch, true)}
+}
@@ -30164,7 +30446,7 @@ index 00000000000000..020323eb7be25e
+// Clone returns a new Hash object that is a deep clone of itself.
+// The duplicate object contains all state and data contained in the
+// original object at the point of duplication.
-+func (h *Hash) Clone() (HashCloner, error) {
++func (h *Hash) Clone() (hash.Cloner, error) {
+ h2 := &Hash{alg: h.alg, nbuf: h.nbuf}
+ copy(h2.buf[:h.nbuf], h.buf[:h.nbuf])
+ if h.ctx != nil {
@@ -30279,7 +30561,7 @@ index 00000000000000..020323eb7be25e
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/hkdf.go b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/hkdf.go
new file mode 100644
-index 00000000000000..6ae76c729a7aa0
+index 00000000000000..ac6771f2babe5b
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/hkdf.go
@@ -0,0 +1,312 @@
@@ -30365,10 +30647,10 @@ index 00000000000000..6ae76c729a7aa0
+// used with HKDF.
+var hkdfAllZerosSalt [64]byte
+
-+// ExtractHDKF implements the HDKF extract step.
++// ExtractHKDF implements the HKDF extract step.
+// If salt is nil, then this function replaces it internally with a buffer of
+// zeros whose length equals the output length of the specified hash algorithm.
-+func ExtractHKDF(h func() hash.Hash, secret, salt []byte) ([]byte, error) {
++func ExtractHKDF[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) {
+ if !SupportsHKDF() {
+ return nil, errUnsupportedVersion()
+ }
@@ -30427,7 +30709,7 @@ index 00000000000000..6ae76c729a7aa0
+}
+
+// ExpandHKDF derives a key from the given hash, key, and optional context info.
-+func ExpandHKDF(h func() hash.Hash, pseudorandomKey, info []byte, keyLength int) ([]byte, error) {
++func ExpandHKDF[H hash.Hash](h func() H, pseudorandomKey, info []byte, keyLength int) ([]byte, error) {
+ if !SupportsHKDF() {
+ return nil, errUnsupportedVersion()
+ }
@@ -30476,7 +30758,7 @@ index 00000000000000..6ae76c729a7aa0
+
+// ExpandTLS13KDF derives a key from the given hash, key, label and context. It will use
+// "TLS13-KDF" algorithm to do so.
-+func ExpandTLS13KDF(h func() hash.Hash, pseudorandomKey, label, context []byte, keyLength int) ([]byte, error) {
++func ExpandTLS13KDF[H hash.Hash](h func() H, pseudorandomKey, label, context []byte, keyLength int) ([]byte, error) {
+ if !SupportsTLS13KDF() {
+ return nil, errUnsupportedVersion()
+ }
@@ -30597,7 +30879,7 @@ index 00000000000000..6ae76c729a7aa0
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/hmac.go b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/hmac.go
new file mode 100644
-index 00000000000000..6402a9b3d0f30a
+index 00000000000000..16d59d713d77c5
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/hmac.go
@@ -0,0 +1,269 @@
@@ -30616,10 +30898,10 @@ index 00000000000000..6402a9b3d0f30a
+)
+
+// NewHMAC returns a new HMAC using OpenSSL.
-+// The function h must return a hash implemented by
-+// OpenSSL (for example, h could be openssl.NewSHA256).
-+// If h is not recognized, NewHMAC returns nil.
-+func NewHMAC(fh func() hash.Hash, key []byte) hash.Hash {
++// The function fh must return a hash implemented by
++// OpenSSL (for example, [NewSHA256]).
++// If fh is not recognized, NewHMAC returns nil.
++func NewHMAC[H hash.Hash](fh func() H, key []byte) hash.Hash {
+ h, _ := hashFuncHash(fh)
+ md := hashToMD(h)
+ if md == nil {
@@ -30836,7 +31118,7 @@ index 00000000000000..6402a9b3d0f30a
+ return append(in, h.sum[:h.size]...)
+}
+
-+func (h *opensslHMAC) Clone() (HashCloner, error) {
++func (h *opensslHMAC) Clone() (hash.Cloner, error) {
+ switch major() {
+ case 1:
+ ctx2, err := ossl.HMAC_CTX_new()
@@ -30872,10 +31154,10 @@ index 00000000000000..6402a9b3d0f30a
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/mldsa.go b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/mldsa.go
new file mode 100644
-index 00000000000000..49481d99023c12
+index 00000000000000..97fc7406f75353
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/mldsa.go
-@@ -0,0 +1,449 @@
+@@ -0,0 +1,499 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -31055,6 +31337,31 @@ index 00000000000000..49481d99023c12
+ return key.seed[:]
+}
+
++// Equal reports whether key and other represent the same private key.
++func (key *PrivateKeyMLDSA) Equal(other *PrivateKeyMLDSA) bool {
++ if other == nil {
++ return false
++ }
++ a, err := newMLDSAPrivatePkey(key.params.keyType, key.seed[:])
++ if err != nil {
++ return false
++ }
++ defer ossl.EVP_PKEY_free(a)
++ b, err := newMLDSAPrivatePkey(other.params.keyType, other.seed[:])
++ if err != nil {
++ return false
++ }
++ defer ossl.EVP_PKEY_free(b)
++ // EVP_PKEY_eq returns 1 if inputs match, 0 if they don't match, -1 if the
++ // key types are different, and -2 if the operation is not supported. We
++ // don't care about the reason, only if they match or aren't confirmed to
++ // match. The error return drains the OpenSSL error queue when the
++ // comparison fails (e.g. on cross-parameter-set inputs), so we keep it
++ // here rather than tagging the binding noerror.
++ ret, _ := ossl.EVP_PKEY_eq(a, b)
++ return ret == 1
++}
++
+// Parameters returns the parameters associated with this private key.
+func (key *PrivateKeyMLDSA) Parameters() MLDSAParameters { return key.params }
+
@@ -31097,7 +31404,7 @@ index 00000000000000..49481d99023c12
+ return nil, errors.New("mldsa: invalid public key size")
+ }
+ // Validate by attempting a key import.
-+ pkey, err := createMLDSAPublicKey(params.keyType, publicKey)
++ pkey, err := newMLDSAPublicPkey(params.keyType, publicKey)
+ if err != nil {
+ return nil, err
+ }
@@ -31112,6 +31419,31 @@ index 00000000000000..49481d99023c12
+ return key.bytes[:key.params.publicKeySize]
+}
+
++// Equal reports whether key and other represent the same public key.
++func (key *PublicKeyMLDSA) Equal(other *PublicKeyMLDSA) bool {
++ if other == nil {
++ return false
++ }
++ a, err := newMLDSAPublicPkey(key.params.keyType, key.bytes[:key.params.publicKeySize])
++ if err != nil {
++ return false
++ }
++ defer ossl.EVP_PKEY_free(a)
++ b, err := newMLDSAPublicPkey(other.params.keyType, other.bytes[:other.params.publicKeySize])
++ if err != nil {
++ return false
++ }
++ defer ossl.EVP_PKEY_free(b)
++ // EVP_PKEY_eq returns 1 if inputs match, 0 if they don't match, -1 if the
++ // key types are different, and -2 if the operation is not supported. We
++ // don't care about the reason, only if they match or aren't confirmed to
++ // match. The error return drains the OpenSSL error queue when the
++ // comparison fails (e.g. on cross-parameter-set inputs), so we keep it
++ // here rather than tagging the binding noerror.
++ ret, _ := ossl.EVP_PKEY_eq(a, b)
++ return ret == 1
++}
++
+// Parameters returns the parameters associated with this public key.
+func (key *PublicKeyMLDSA) Parameters() MLDSAParameters { return key.params }
+
@@ -31143,8 +31475,8 @@ index 00000000000000..49481d99023c12
+ return err
+}
+
-+// createMLDSAPrivateKey creates an ML-DSA EVP_PKEY from a 32-byte seed.
-+func createMLDSAPrivateKey(id int32, seed []byte) (ossl.EVP_PKEY_PTR, error) {
++// newMLDSAPrivatePkey creates an ML-DSA EVP_PKEY from a 32-byte seed.
++func newMLDSAPrivatePkey(id int32, seed []byte) (ossl.EVP_PKEY_PTR, error) {
+ if len(seed) != privateKeySizeMLDSA {
+ return nil, errors.New("mldsa: invalid seed size")
+ }
@@ -31163,8 +31495,8 @@ index 00000000000000..49481d99023c12
+ return newEvpFromParams(id, ossl.EVP_PKEY_KEYPAIR, params)
+}
+
-+// createMLDSAPublicKey creates an ML-DSA EVP_PKEY from encoded public key bytes.
-+func createMLDSAPublicKey(id int32, pubKeyBytes []byte) (ossl.EVP_PKEY_PTR, error) {
++// newMLDSAPublicPkey creates an ML-DSA EVP_PKEY from encoded public key bytes.
++func newMLDSAPublicPkey(id int32, pubKeyBytes []byte) (ossl.EVP_PKEY_PTR, error) {
+ bld := newParamBuilder()
+ defer bld.finalize()
+
@@ -31182,7 +31514,7 @@ index 00000000000000..49481d99023c12
+// mldsaExtractPublicKey derives and copies the encoded public key bytes from
+// a private key seed.
+func mldsaExtractPublicKey(params MLDSAParameters, seed, dst []byte) error {
-+ pkey, err := createMLDSAPrivateKey(params.keyType, seed)
++ pkey, err := newMLDSAPrivatePkey(params.keyType, seed)
+ if err != nil {
+ return err
+ }
@@ -31220,7 +31552,7 @@ index 00000000000000..49481d99023c12
+}
+
+func mldsaSign(params MLDSAParameters, seed, message []byte, context string) ([]byte, error) {
-+ pkey, err := createMLDSAPrivateKey(params.keyType, seed)
++ pkey, err := newMLDSAPrivatePkey(params.keyType, seed)
+ if err != nil {
+ return nil, err
+ }
@@ -31230,7 +31562,7 @@ index 00000000000000..49481d99023c12
+}
+
+func mldsaSignExternalMu(params MLDSAParameters, seed, mu []byte) ([]byte, error) {
-+ pkey, err := createMLDSAPrivateKey(params.keyType, seed)
++ pkey, err := newMLDSAPrivatePkey(params.keyType, seed)
+ if err != nil {
+ return nil, err
+ }
@@ -31276,7 +31608,7 @@ index 00000000000000..49481d99023c12
+ if len(signature) != params.signatureSize {
+ return errors.New("mldsa: invalid signature length")
+ }
-+ pkey, err := createMLDSAPublicKey(params.keyType, publicKey)
++ pkey, err := newMLDSAPublicPkey(params.keyType, publicKey)
+ if err != nil {
+ return err
+ }
@@ -31289,7 +31621,7 @@ index 00000000000000..49481d99023c12
+ if len(signature) != params.signatureSize {
+ return errors.New("mldsa: invalid signature length")
+ }
-+ pkey, err := createMLDSAPublicKey(params.keyType, publicKey)
++ pkey, err := newMLDSAPublicPkey(params.keyType, publicKey)
+ if err != nil {
+ return err
+ }
@@ -32151,7 +32483,7 @@ index 00000000000000..8bd651d6493707
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/pbkdf2.go b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/pbkdf2.go
new file mode 100644
-index 00000000000000..6cba126ef9dee4
+index 00000000000000..9cc532155314d6
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/pbkdf2.go
@@ -0,0 +1,82 @@
@@ -32190,7 +32522,7 @@ index 00000000000000..6cba126ef9dee4
+ return kdf, nil
+})
+
-+func PBKDF2(password, salt []byte, iter, keyLen int, fh func() hash.Hash) ([]byte, error) {
++func PBKDF2[H hash.Hash](password, salt []byte, iter, keyLen int, fh func() H) ([]byte, error) {
+ h, err := hashFuncHash(fh)
+ if err != nil {
+ return nil, err
@@ -33676,10 +34008,10 @@ index 00000000000000..a59ac6f76a1298
+})
diff --git a/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/tls1prf.go b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/tls1prf.go
new file mode 100644
-index 00000000000000..d53f18c9fbc24c
+index 00000000000000..67e4cc7919fe08
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-openssl/openssl/tls1prf.go
-@@ -0,0 +1,147 @@
+@@ -0,0 +1,149 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -33705,14 +34037,16 @@ index 00000000000000..d53f18c9fbc24c
+ }
+}
+
-+// TLS1PRF implements the TLS 1.0/1.1 pseudo-random function if h is nil,
++// TLS1PRF implements the TLS 1.0/1.1 pseudo-random function if fh is nil,
+// else it implements the TLS 1.2 pseudo-random function.
++// To use TLS 1.0/1.1 mode with nil fh, specify the type parameter explicitly,
++// for example TLS1PRF[hash.Hash](result, secret, label, seed, nil).
+// The pseudo-random number will be written to result and will be of length len(result).
-+func TLS1PRF(result, secret, label, seed []byte, fh func() hash.Hash) error {
++func TLS1PRF[H hash.Hash](result, secret, label, seed []byte, fh func() H) error {
+ var md ossl.EVP_MD_PTR
+ if fh == nil {
+ // TLS 1.0/1.1 PRF doesn't allow to specify the hash function,
-+ // it always uses MD5SHA1. If h is nil, then assume
++ // it always uses MD5SHA1. If fh is nil, then assume
+ // that the caller wants to use TLS 1.0/1.1 PRF.
+ // OpenSSL detects this case by checking if the hash
+ // function is MD5SHA1.
@@ -36409,10 +36743,10 @@ index 00000000000000..586e9ae2ebb0c9
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-winnative/cng/hash.go b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/hash.go
new file mode 100644
-index 00000000000000..13c39fea4f64fb
+index 00000000000000..88fd1969de9735
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/hash.go
-@@ -0,0 +1,344 @@
+@@ -0,0 +1,342 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -36435,8 +36769,6 @@ index 00000000000000..13c39fea4f64fb
+// maxHashSize is the size of SHA512 and SHA3_512, the largest hashes we support.
+const maxHashSize = 64
+
-+type HashCloner = hash.Cloner
-+
+// SupportsHash returns true if a hash.Hash implementation is supported for h.
+func SupportsHash(h crypto.Hash) bool {
+ switch h {
@@ -36506,32 +36838,32 @@ index 00000000000000..13c39fea4f64fb
+}
+
+// NewMD4 returns a new MD4 hash.
-+func NewMD4() hash.Hash {
++func NewMD4() *Hash {
+ return newHash(bcrypt.MD4_ALGORITHM)
+}
+
+// NewMD5 returns a new MD5 hash.
-+func NewMD5() hash.Hash {
++func NewMD5() *Hash {
+ return newHash(bcrypt.MD5_ALGORITHM)
+}
+
+// NewSHA1 returns a new SHA1 hash.
-+func NewSHA1() hash.Hash {
++func NewSHA1() *Hash {
+ return newHash(bcrypt.SHA1_ALGORITHM)
+}
+
+// NewSHA256 returns a new SHA256 hash.
-+func NewSHA256() hash.Hash {
++func NewSHA256() *Hash {
+ return newHash(bcrypt.SHA256_ALGORITHM)
+}
+
+// NewSHA384 returns a new SHA384 hash.
-+func NewSHA384() hash.Hash {
++func NewSHA384() *Hash {
+ return newHash(bcrypt.SHA384_ALGORITHM)
+}
+
+// NewSHA512 returns a new SHA512 hash.
-+func NewSHA512() hash.Hash {
++func NewSHA512() *Hash {
+ return newHash(bcrypt.SHA512_ALGORITHM)
+}
+
@@ -36575,7 +36907,7 @@ index 00000000000000..13c39fea4f64fb
+}
+
+var _ hash.Hash = (*Hash)(nil)
-+var _ HashCloner = (*Hash)(nil)
++var _ hash.Cloner = (*Hash)(nil)
+
+// FIPSApprovedHash reports whether this hash algorithm is FIPS 140-3 approved.
+func FIPSApprovedHash(h hash.Hash) bool {
@@ -36604,7 +36936,7 @@ index 00000000000000..13c39fea4f64fb
+ // Don't call bcrypt.CreateHash yet, it would be wasteful
+ // if the caller only wants to know the hash type. This
+ // is a common pattern in this package, as some functions
-+ // accept a `func() hash.Hash` parameter and call it just
++ // accept a hash constructor parameter and call it just
+ // to know the hash type.
+ return &Hash{alg: mustLoadHash(id, bcrypt.ALG_NONE_FLAG)}
+}
@@ -36625,7 +36957,7 @@ index 00000000000000..13c39fea4f64fb
+ runtime.SetFinalizer(h, (*Hash).finalize)
+}
+
-+func (h *Hash) Clone() (HashCloner, error) {
++func (h *Hash) Clone() (hash.Cloner, error) {
+ defer runtime.KeepAlive(h)
+ h2 := &Hash{alg: h.alg, key: bytes.Clone(h.key)}
+ if h.ctx != 0 {
@@ -36759,7 +37091,7 @@ index 00000000000000..13c39fea4f64fb
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-winnative/cng/hkdf.go b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/hkdf.go
new file mode 100644
-index 00000000000000..aa48b084d708da
+index 00000000000000..59da3c3eeb30cb
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/hkdf.go
@@ -0,0 +1,133 @@
@@ -36791,7 +37123,7 @@ index 00000000000000..aa48b084d708da
+ })
+}
+
-+func newHKDF(h func() hash.Hash, secret, salt []byte) (bcrypt.KEY_HANDLE, error) {
++func newHKDF[H hash.Hash](h func() H, secret, salt []byte) (bcrypt.KEY_HANDLE, error) {
+ ch := h()
+ hashID := hashToID(ch)
+ if hashID == "" {
@@ -36823,7 +37155,7 @@ index 00000000000000..aa48b084d708da
+ return kh, nil
+}
+
-+func ExtractHKDF(h func() hash.Hash, secret, salt []byte) ([]byte, error) {
++func ExtractHKDF[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) {
+ if salt == nil {
+ // Replicate x/crypto/hkdf behavior.
+ salt = make([]byte, h().Size())
@@ -36857,7 +37189,7 @@ index 00000000000000..aa48b084d708da
+}
+
+// ExpandHKDF derives a key from the given hash, key, and optional context info.
-+func ExpandHKDF(h func() hash.Hash, pseudorandomKey, info []byte, keyLength int) ([]byte, error) {
++func ExpandHKDF[H hash.Hash](h func() H, pseudorandomKey, info []byte, keyLength int) ([]byte, error) {
+ kh, err := newHKDF(h, pseudorandomKey, nil)
+ if err != nil {
+ return nil, err
@@ -36898,7 +37230,7 @@ index 00000000000000..aa48b084d708da
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-winnative/cng/hmac.go b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/hmac.go
new file mode 100644
-index 00000000000000..18067ce5abf434
+index 00000000000000..b7d5688f005781
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/hmac.go
@@ -0,0 +1,70 @@
@@ -36918,11 +37250,11 @@ index 00000000000000..18067ce5abf434
+)
+
+// NewHMAC returns a new HMAC using BCrypt.
-+// The function h must return a hash implemented by
-+// CNG (for example, h could be cng.NewSHA256).
-+// If h is not recognized, NewHMAC returns nil.
-+func NewHMAC(h func() hash.Hash, key []byte) hash.Hash {
-+ ch := h()
++// The function fh must return a hash implemented by
++// CNG (for example, [NewSHA256]).
++// If fh is not recognized, NewHMAC returns nil.
++func NewHMAC[H hash.Hash](fh func() H, key []byte) hash.Hash {
++ ch := fh()
+ id := hashToID(ch)
+ if id == "" {
+ return nil
@@ -36965,7 +37297,7 @@ index 00000000000000..18067ce5abf434
+ return h.hashX.BlockSize()
+}
+
-+func (h hmacWrapper) Clone() (HashCloner, error) {
++func (h hmacWrapper) Clone() (hash.Cloner, error) {
+ clone, err := h.hashX.Clone()
+ if err != nil {
+ return nil, err
@@ -37200,10 +37532,10 @@ index 00000000000000..bc150a7bd39272
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-winnative/cng/mldsa.go b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/mldsa.go
new file mode 100644
-index 00000000000000..673fdcd3b3e9e5
+index 00000000000000..92df2fac2ca6da
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/mldsa.go
-@@ -0,0 +1,425 @@
+@@ -0,0 +1,444 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -37213,6 +37545,7 @@ index 00000000000000..673fdcd3b3e9e5
+package cng
+
+import (
++ "crypto/subtle"
+ "errors"
+ "runtime"
+ "unsafe"
@@ -37566,6 +37899,15 @@ index 00000000000000..673fdcd3b3e9e5
+ return key.seed[:]
+}
+
++// Equal reports whether key and other represent the same private key.
++func (key *PrivateKeyMLDSA) Equal(other *PrivateKeyMLDSA) bool {
++ if other == nil {
++ return false
++ }
++ return key.params.name == other.params.name &&
++ subtle.ConstantTimeCompare(key.seed[:], other.seed[:]) == 1
++}
++
+// Parameters returns the parameters associated with this private key.
+func (key *PrivateKeyMLDSA) Parameters() MLDSAParameters { return key.params }
+
@@ -37617,6 +37959,15 @@ index 00000000000000..673fdcd3b3e9e5
+ return key.bytes[:key.params.publicKeySize]
+}
+
++// Equal reports whether key and other represent the same public key.
++func (key *PublicKeyMLDSA) Equal(other *PublicKeyMLDSA) bool {
++ if other == nil {
++ return false
++ }
++ return key.params.name == other.params.name &&
++ subtle.ConstantTimeCompare(key.bytes[:key.params.publicKeySize], other.bytes[:other.params.publicKeySize]) == 1
++}
++
+// Parameters returns the parameters associated with this public key.
+func (key *PublicKeyMLDSA) Parameters() MLDSAParameters { return key.params }
+
@@ -38042,7 +38393,7 @@ index 00000000000000..f220e1d9d29794
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-winnative/cng/pbkdf2.go b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/pbkdf2.go
new file mode 100644
-index 00000000000000..5466b180e60e5a
+index 00000000000000..cb9dba21416c6d
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/pbkdf2.go
@@ -0,0 +1,70 @@
@@ -38068,8 +38419,8 @@ index 00000000000000..5466b180e60e5a
+ })
+}
+
-+func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) ([]byte, error) {
-+ ch := h()
++func PBKDF2[H hash.Hash](password, salt []byte, iter, keyLen int, fh func() H) ([]byte, error) {
++ ch := fh()
+ hashID := hashToID(ch)
+ if hashID == "" {
+ return nil, errors.New("cng: unsupported hash function")
@@ -38842,10 +39193,10 @@ index 00000000000000..c26c4bcf0d1afe
+}
diff --git a/src/vendor/github.com/microsoft/go-crypto-winnative/cng/tls1prf.go b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/tls1prf.go
new file mode 100644
-index 00000000000000..56131a6bc93d3f
+index 00000000000000..3418bf62f22d4d
--- /dev/null
+++ b/src/vendor/github.com/microsoft/go-crypto-winnative/cng/tls1prf.go
-@@ -0,0 +1,89 @@
+@@ -0,0 +1,91 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
@@ -38868,17 +39219,19 @@ index 00000000000000..56131a6bc93d3f
+ })
+}
+
-+// TLS1PRF implements the TLS 1.0/1.1 pseudo-random function if h is nil,
++// TLS1PRF implements the TLS 1.0/1.1 pseudo-random function if fh is nil,
+// else it implements the TLS 1.2 pseudo-random function.
++// To use TLS 1.0/1.1 mode with nil fh, specify the type parameter explicitly,
++// for example TLS1PRF[hash.Hash](result, secret, label, seed, nil).
+// The pseudo-random number will be written to result and will be of length len(result).
-+func TLS1PRF(result, secret, label, seed []byte, h func() hash.Hash) error {
++func TLS1PRF[H hash.Hash](result, secret, label, seed []byte, fh func() H) error {
+ // TLS 1.0/1.1 PRF uses MD5SHA1.
+ algID := bcrypt.TLS1_1_KDF_ALGORITHM
+ var hashID string
-+ if h != nil {
-+ // If h is specified, assume the caller wants to use TLS 1.2 PRF.
++ if fh != nil {
++ // If fh is specified, assume the caller wants to use TLS 1.2 PRF.
+ // TLS 1.0/1.1 PRF doesn't allow specifying the hash function.
-+ if hashID = hashToID(h()); hashID == "" {
++ if hashID = hashToID(fh()); hashID == "" {
+ return errors.New("cng: unsupported hash function")
+ }
+ algID = bcrypt.TLS1_2_KDF_ALGORITHM
@@ -39970,11 +40323,11 @@ index 00000000000000..1722410e5af193
+ return getSystemDirectory() + "\\" + dll
+}
diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt
-index 54fcbab6a221c0..07fcd41c1e259f 100644
+index 54fcbab6a221c0..02c944e4640127 100644
--- a/src/vendor/modules.txt
+++ b/src/vendor/modules.txt
@@ -1,3 +1,26 @@
-+# github.com/microsoft/go-crypto-darwin v0.0.3-0.20260512212935-d0ce8397e44b
++# github.com/microsoft/go-crypto-darwin v0.0.3-0.20260605073440-7505334b131b
+## explicit; go 1.25
+github.com/microsoft/go-crypto-darwin/bbig
+github.com/microsoft/go-crypto-darwin/internal/commoncrypto
@@ -39983,14 +40336,14 @@ index 54fcbab6a221c0..07fcd41c1e259f 100644
+github.com/microsoft/go-crypto-darwin/internal/security
+github.com/microsoft/go-crypto-darwin/internal/xsyscall
+github.com/microsoft/go-crypto-darwin/xcrypto
-+# github.com/microsoft/go-crypto-openssl v0.0.0-20260526094617-f3ee9e48499e
++# github.com/microsoft/go-crypto-openssl v0.0.0-20260605082236-c86f934c8ba7
+## explicit; go 1.25
+github.com/microsoft/go-crypto-openssl/bbig
+github.com/microsoft/go-crypto-openssl/internal/fakecgo
+github.com/microsoft/go-crypto-openssl/internal/ossl
+github.com/microsoft/go-crypto-openssl/openssl
+github.com/microsoft/go-crypto-openssl/osslsetup
-+# github.com/microsoft/go-crypto-winnative v0.0.0-20260512074019-00d811a4aefe
++# github.com/microsoft/go-crypto-winnative v0.0.0-20260605073512-713d2add0825
+## explicit; go 1.25
+github.com/microsoft/go-crypto-winnative/cng
+github.com/microsoft/go-crypto-winnative/cng/bbig
diff --git a/patches/0002-Add-crypto-backends.patch b/patches/0002-Add-crypto-backends.patch
index 1a3b072ef98..408bfe922e0 100644
--- a/patches/0002-Add-crypto-backends.patch
+++ b/patches/0002-Add-crypto-backends.patch
@@ -22,7 +22,7 @@ Subject: [PATCH] Add crypto backends
src/cmd/go/internal/tool/tool.go | 9 +-
.../verylongtest/testdata/script/README | 2 +
src/cmd/go/script_test.go | 3 +
- src/cmd/go/systemcrypto_test.go | 272 +++++++++++
+ src/cmd/go/systemcrypto_test.go | 272 ++++++++++
src/cmd/go/testdata/script/README | 2 +
src/cmd/go/testdata/script/darwin_no_cgo.txt | 1 +
src/cmd/go/testdata/script/env_changed.txt | 3 +
@@ -68,10 +68,10 @@ Subject: [PATCH] Add crypto backends
src/crypto/hmac/hmac.go | 16 +-
src/crypto/hmac/hmac_test.go | 2 +-
src/crypto/hpke/aead.go | 14 +-
- src/crypto/internal/backend/backend_darwin.go | 441 ++++++++++++++++++
- src/crypto/internal/backend/backend_linux.go | 434 +++++++++++++++++
+ src/crypto/internal/backend/backend_darwin.go | 474 ++++++++++++++++++
+ src/crypto/internal/backend/backend_linux.go | 463 +++++++++++++++++
src/crypto/internal/backend/backend_test.go | 56 +++
- .../internal/backend/backend_windows.go | 441 ++++++++++++++++++
+ .../internal/backend/backend_windows.go | 474 ++++++++++++++++++
src/crypto/internal/backend/bbig/big.go | 17 +
.../internal/backend/bbig/big_darwin.go | 12 +
src/crypto/internal/backend/bbig/big_linux.go | 12 +
@@ -92,7 +92,7 @@ Subject: [PATCH] Add crypto backends
.../opensslsetup/opensslsetup_linux.go | 68 +++
.../opensslsetup/opensslsetup_linux_test.go | 92 ++++
.../backend/internal/opensslsetup/stub.go | 8 +
- src/crypto/internal/backend/nobackend.go | 375 +++++++++++++++
+ src/crypto/internal/backend/nobackend.go | 460 +++++++++++++++++
src/crypto/internal/backend/stub.s | 10 +
src/crypto/internal/cryptotest/allocations.go | 6 -
src/crypto/internal/cryptotest/fips140.go | 8 +
@@ -107,6 +107,8 @@ Subject: [PATCH] Add crypto backends
src/crypto/internal/rand/rand.go | 2 +-
src/crypto/md5/md5.go | 10 +
src/crypto/md5/md5_test.go | 18 +-
+ src/crypto/mldsa/mldsa_fips140v1.26.go | 175 ++++++-
+ src/crypto/mldsa/mldsa_test.go | 65 ++-
src/crypto/mlkem/mlkem.go | 118 ++++-
src/crypto/mlkem/mlkem_test.go | 8 +
src/crypto/pbkdf2/pbkdf2.go | 7 +
@@ -117,7 +119,7 @@ Subject: [PATCH] Add crypto backends
src/crypto/rc4/rc4.go | 18 +
src/crypto/rsa/boring.go | 12 +-
src/crypto/rsa/boring_test.go | 2 +-
- src/crypto/rsa/fips.go | 156 +++----
+ src/crypto/rsa/fips.go | 156 +++---
src/crypto/rsa/notboring.go | 4 +-
src/crypto/rsa/pkcs1v15.go | 10 +-
src/crypto/rsa/pkcs1v15_test.go | 5 +
@@ -142,7 +144,7 @@ Subject: [PATCH] Add crypto backends
src/crypto/tls/handshake_server.go | 15 +-
src/crypto/tls/handshake_server_tls13.go | 5 +-
src/crypto/tls/internal/tls13/doc.go | 18 +
- src/crypto/tls/internal/tls13/tls13.go | 195 ++++++++
+ src/crypto/tls/internal/tls13/tls13.go | 195 +++++++
src/crypto/tls/key_schedule.go | 2 +-
src/crypto/tls/prf.go | 24 +
src/crypto/tls/prf_test.go | 9 +
@@ -165,7 +167,7 @@ Subject: [PATCH] Add crypto backends
src/net/lookup_test.go | 3 +
src/os/exec/exec_test.go | 9 +
src/runtime/runtime_boring.go | 5 +
- 161 files changed, 4879 insertions(+), 312 deletions(-)
+ 163 files changed, 5292 insertions(+), 319 deletions(-)
create mode 100644 src/cmd/go/internal/modindex/build_test.go
create mode 100644 src/cmd/go/systemcrypto_test.go
create mode 100644 src/crypto/dsa/boring.go
@@ -2769,10 +2771,10 @@ index fb55c97ddf20c9..fb036863cde2dd 100644
func (a *aead) ID() uint16 {
diff --git a/src/crypto/internal/backend/backend_darwin.go b/src/crypto/internal/backend/backend_darwin.go
new file mode 100644
-index 00000000000000..f3d79d6b318d8a
+index 00000000000000..111181f963d7c3
--- /dev/null
+++ b/src/crypto/internal/backend/backend_darwin.go
-@@ -0,0 +1,441 @@
+@@ -0,0 +1,474 @@
+// Copyright 2017 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.
@@ -3204,6 +3206,39 @@ index 00000000000000..f3d79d6b318d8a
+ return xcrypto.NewEncapsulationKeyMLKEM1024(encapsulationKey)
+}
+
++type MLDSAParameters = xcrypto.MLDSAParameters
++
++// MLDSA44 returns an unsupported parameter set: CryptoKit does not implement
++// ML-DSA-44. The zero value is reported as unsupported by [SupportsMLDSA], so
++// callers fall back to the standard library implementation.
++func MLDSA44() MLDSAParameters { return MLDSAParameters{} }
++func MLDSA65() MLDSAParameters { return xcrypto.MLDSA65() }
++func MLDSA87() MLDSAParameters { return xcrypto.MLDSA87() }
++
++func SupportsMLDSA(params MLDSAParameters) bool {
++ return xcrypto.SupportsMLDSA(params)
++}
++
++// SupportsMLDSAExternalMu reports whether the backend can sign a pre-hashed mu
++// message representative directly. CryptoKit does not implement external-mu
++// signing, so callers fall back to the standard library implementation.
++func SupportsMLDSAExternalMu() bool { return false }
++
++type PrivateKeyMLDSA = xcrypto.PrivateKeyMLDSA
++type PublicKeyMLDSA = xcrypto.PublicKeyMLDSA
++
++func GenerateKeyMLDSA(params MLDSAParameters) (*PrivateKeyMLDSA, error) {
++ return xcrypto.GenerateKeyMLDSA(params)
++}
++
++func NewPrivateKeyMLDSA(params MLDSAParameters, seed []byte) (*PrivateKeyMLDSA, error) {
++ return xcrypto.NewPrivateKeyMLDSA(params, seed)
++}
++
++func NewPublicKeyMLDSA(params MLDSAParameters, publicKey []byte) (*PublicKeyMLDSA, error) {
++ return xcrypto.NewPublicKeyMLDSA(params, publicKey)
++}
++
+func SupportsChaCha20Poly1305() bool {
+ return true
+}
@@ -3216,10 +3251,10 @@ index 00000000000000..f3d79d6b318d8a
+}
diff --git a/src/crypto/internal/backend/backend_linux.go b/src/crypto/internal/backend/backend_linux.go
new file mode 100644
-index 00000000000000..c8c07a4beeecde
+index 00000000000000..a129793175b7aa
--- /dev/null
+++ b/src/crypto/internal/backend/backend_linux.go
-@@ -0,0 +1,434 @@
+@@ -0,0 +1,463 @@
+// Copyright 2017 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.
@@ -3644,6 +3679,35 @@ index 00000000000000..c8c07a4beeecde
+ return openssl.NewEncapsulationKeyMLKEM1024(encapsulationKey)
+}
+
++type MLDSAParameters = openssl.MLDSAParameters
++
++func MLDSA44() MLDSAParameters { return openssl.MLDSA44() }
++func MLDSA65() MLDSAParameters { return openssl.MLDSA65() }
++func MLDSA87() MLDSAParameters { return openssl.MLDSA87() }
++
++func SupportsMLDSA(params MLDSAParameters) bool {
++ return openssl.SupportsMLDSA(params)
++}
++
++// SupportsMLDSAExternalMu reports whether the backend can sign a pre-hashed mu
++// message representative directly. OpenSSL implements external-mu signing.
++func SupportsMLDSAExternalMu() bool { return true }
++
++type PrivateKeyMLDSA = openssl.PrivateKeyMLDSA
++type PublicKeyMLDSA = openssl.PublicKeyMLDSA
++
++func GenerateKeyMLDSA(params MLDSAParameters) (*PrivateKeyMLDSA, error) {
++ return openssl.GenerateKeyMLDSA(params)
++}
++
++func NewPrivateKeyMLDSA(params MLDSAParameters, seed []byte) (*PrivateKeyMLDSA, error) {
++ return openssl.NewPrivateKeyMLDSA(params, seed)
++}
++
++func NewPublicKeyMLDSA(params MLDSAParameters, publicKey []byte) (*PublicKeyMLDSA, error) {
++ return openssl.NewPublicKeyMLDSA(params, publicKey)
++}
++
+func SupportsChaCha20Poly1305() bool {
+ return openssl.SupportsChaCha20Poly1305()
+}
@@ -3718,10 +3782,10 @@ index 00000000000000..093acd82556330
+}
diff --git a/src/crypto/internal/backend/backend_windows.go b/src/crypto/internal/backend/backend_windows.go
new file mode 100644
-index 00000000000000..8013f189808e31
+index 00000000000000..30ac33f8b58103
--- /dev/null
+++ b/src/crypto/internal/backend/backend_windows.go
-@@ -0,0 +1,441 @@
+@@ -0,0 +1,474 @@
+// Copyright 2017 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.
@@ -4153,6 +4217,39 @@ index 00000000000000..8013f189808e31
+ return cng.NewEncapsulationKeyMLKEM1024(encapsulationKey)
+}
+
++type MLDSAParameters = cng.MLDSAParameters
++
++func MLDSA44() MLDSAParameters { return cng.MLDSA44() }
++func MLDSA65() MLDSAParameters { return cng.MLDSA65() }
++func MLDSA87() MLDSAParameters { return cng.MLDSA87() }
++
++// SupportsMLDSA reports whether the backend supports ML-DSA. The params
++// argument is ignored because CNG support is all-or-nothing: it implements
++// ML-DSA-44, -65, and -87 uniformly, unlike the parameter-aware OpenSSL and
++// CryptoKit backends.
++func SupportsMLDSA(params MLDSAParameters) bool {
++ return cng.SupportsMLDSA()
++}
++
++// SupportsMLDSAExternalMu reports whether the backend can sign a pre-hashed mu
++// message representative directly. CNG implements external-mu signing.
++func SupportsMLDSAExternalMu() bool { return true }
++
++type PrivateKeyMLDSA = cng.PrivateKeyMLDSA
++type PublicKeyMLDSA = cng.PublicKeyMLDSA
++
++func GenerateKeyMLDSA(params MLDSAParameters) (*PrivateKeyMLDSA, error) {
++ return cng.GenerateKeyMLDSA(params)
++}
++
++func NewPrivateKeyMLDSA(params MLDSAParameters, seed []byte) (*PrivateKeyMLDSA, error) {
++ return cng.NewPrivateKeyMLDSA(params, seed)
++}
++
++func NewPublicKeyMLDSA(params MLDSAParameters, publicKey []byte) (*PublicKeyMLDSA, error) {
++ return cng.NewPublicKeyMLDSA(params, publicKey)
++}
++
+func SupportsChaCha20Poly1305() bool {
+ return cng.SupportsChaCha20Poly1305()
+}
@@ -4901,10 +4998,10 @@ index 00000000000000..19fd29e19e7b96
+package opensslsetup
diff --git a/src/crypto/internal/backend/nobackend.go b/src/crypto/internal/backend/nobackend.go
new file mode 100644
-index 00000000000000..84a73fc5c2d523
+index 00000000000000..e0d0dfd91dfd32
--- /dev/null
+++ b/src/crypto/internal/backend/nobackend.go
-@@ -0,0 +1,375 @@
+@@ -0,0 +1,460 @@
+// Copyright 2017 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.
@@ -5273,6 +5370,91 @@ index 00000000000000..84a73fc5c2d523
+ panic("cryptobackend: not available")
+}
+
++type MLDSAParameters struct{}
++
++func MLDSA44() MLDSAParameters {
++ panic("cryptobackend: not available")
++}
++
++func MLDSA65() MLDSAParameters {
++ panic("cryptobackend: not available")
++}
++
++func MLDSA87() MLDSAParameters {
++ panic("cryptobackend: not available")
++}
++
++func (params MLDSAParameters) String() string {
++ panic("cryptobackend: not available")
++}
++
++func SupportsMLDSA(params MLDSAParameters) bool {
++ panic("cryptobackend: not available")
++}
++
++func SupportsMLDSAExternalMu() bool {
++ panic("cryptobackend: not available")
++}
++
++type PrivateKeyMLDSA struct{}
++type PublicKeyMLDSA struct{}
++
++func GenerateKeyMLDSA(params MLDSAParameters) (*PrivateKeyMLDSA, error) {
++ panic("cryptobackend: not available")
++}
++
++func NewPrivateKeyMLDSA(params MLDSAParameters, seed []byte) (*PrivateKeyMLDSA, error) {
++ panic("cryptobackend: not available")
++}
++
++func NewPublicKeyMLDSA(params MLDSAParameters, publicKey []byte) (*PublicKeyMLDSA, error) {
++ panic("cryptobackend: not available")
++}
++
++func (key *PrivateKeyMLDSA) Bytes() []byte {
++ panic("cryptobackend: not available")
++}
++
++func (key *PrivateKeyMLDSA) Equal(other *PrivateKeyMLDSA) bool {
++ panic("cryptobackend: not available")
++}
++
++func (key *PrivateKeyMLDSA) Parameters() MLDSAParameters {
++ panic("cryptobackend: not available")
++}
++
++func (key *PrivateKeyMLDSA) PublicKey() *PublicKeyMLDSA {
++ panic("cryptobackend: not available")
++}
++
++func (key *PrivateKeyMLDSA) Sign(message []byte, context string) ([]byte, error) {
++ panic("cryptobackend: not available")
++}
++
++func (key *PrivateKeyMLDSA) SignExternalMu(mu []byte) ([]byte, error) {
++ panic("cryptobackend: not available")
++}
++
++func (key *PublicKeyMLDSA) Bytes() []byte {
++ panic("cryptobackend: not available")
++}
++
++func (key *PublicKeyMLDSA) Equal(other *PublicKeyMLDSA) bool {
++ panic("cryptobackend: not available")
++}
++
++func (key *PublicKeyMLDSA) Parameters() MLDSAParameters {
++ panic("cryptobackend: not available")
++}
++
++func (key *PublicKeyMLDSA) Verify(message, signature []byte, context string) error {
++ panic("cryptobackend: not available")
++}
++
++func (key *PublicKeyMLDSA) VerifyExternalMu(mu, signature []byte) error {
++ panic("cryptobackend: not available")
++}
++
+func SupportsChaCha20Poly1305() bool {
+ return false
+}
@@ -5681,6 +5863,408 @@ index 403ff2881f4b68..5417556a86700e 100644
}
func maybeCloner(h hash.Hash) any {
+diff --git a/src/crypto/mldsa/mldsa_fips140v1.26.go b/src/crypto/mldsa/mldsa_fips140v1.26.go
+index 2c36fe191e9149..1eb974c8e351a5 100644
+--- a/src/crypto/mldsa/mldsa_fips140v1.26.go
++++ b/src/crypto/mldsa/mldsa_fips140v1.26.go
+@@ -8,9 +8,12 @@ package mldsa
+
+ import (
+ "crypto"
++ boring "crypto/internal/backend"
+ "crypto/internal/fips140/mldsa"
++ "crypto/internal/rand"
+ "errors"
+ "io"
++ "sync"
+ )
+
+ // PrivateKey is an in-memory ML-DSA private key. It implements [crypto.Signer]
+@@ -19,12 +22,63 @@ import (
+ // A PrivateKey is safe for concurrent use.
+ type PrivateKey struct {
+ k mldsa.PrivateKey
++
++ // boring holds the crypto backend key, or nil if this key is implemented by
++ // the Go module. It is a pointer because the backend key structs are large,
++ // and storing one by value would make PrivateKey too big to keep on the stack
++ // even on the Go path. For backend-backed keys, k is lazily reconstructed from
++ // the seed by goKey (guarded by goKeyOnce) for the operations the backend does
++ // not implement on every platform.
++ boring *boring.PrivateKeyMLDSA
++ goKeyOnce sync.Once
++ goKeyErr error
+ }
+
+ var errInvalidParameters = errors.New("mldsa: invalid parameters")
+
++// boringMLDSAParameters maps a [Parameters] value to the equivalent crypto
++// backend parameter set. ok is false if params is not a recognized standard
++// parameter set. A true result only means params is a valid standard parameter
++// set, not that the backend supports it: callers must still check
++// [boring.SupportsMLDSA], since e.g. the returned set may be the zero value on
++// platforms whose backend does not implement that parameter set.
++//
++// It must only be called when [boring.Enabled] is true.
++func boringMLDSAParameters(params Parameters) (bparams boring.MLDSAParameters, ok bool) {
++ switch params {
++ case MLDSA44():
++ return boring.MLDSA44(), true
++ case MLDSA65():
++ return boring.MLDSA65(), true
++ case MLDSA87():
++ return boring.MLDSA87(), true
++ default:
++ return boring.MLDSAParameters{}, false
++ }
++}
++
++// useBoringMLDSA reports whether the crypto backend should be used for the
++// given parameter set, and returns the corresponding backend parameter set.
++func useBoringMLDSA(params Parameters) (bparams boring.MLDSAParameters, ok bool) {
++ if !boring.Enabled || !rand.IsDefaultReader(rand.Reader) {
++ return boring.MLDSAParameters{}, false
++ }
++ bparams, ok = boringMLDSAParameters(params)
++ if !ok || !boring.SupportsMLDSA(bparams) {
++ return boring.MLDSAParameters{}, false
++ }
++ return bparams, true
++}
++
+ // GenerateKey generates a new random ML-DSA private key.
+ func GenerateKey(params Parameters) (*PrivateKey, error) {
++ if bparams, ok := useBoringMLDSA(params); ok {
++ key, err := boring.GenerateKeyMLDSA(bparams)
++ if err != nil {
++ return nil, err
++ }
++ return &PrivateKey{boring: key}, nil
++ }
+ switch params {
+ case MLDSA44():
+ return &PrivateKey{k: *mldsa.GenerateKey44()}, nil
+@@ -41,6 +95,13 @@ func GenerateKey(params Parameters) (*PrivateKey, error) {
+ //
+ // The seed must be exactly [PrivateKeySize] bytes long.
+ func NewPrivateKey(params Parameters, seed []byte) (*PrivateKey, error) {
++ if bparams, ok := useBoringMLDSA(params); ok {
++ key, err := boring.NewPrivateKeyMLDSA(bparams, seed)
++ if err != nil {
++ return nil, err
++ }
++ return &PrivateKey{boring: key}, nil
++ }
+ var err error
+ var k *mldsa.PrivateKey
+ switch params {
+@@ -75,11 +136,23 @@ func (sk *PrivateKey) Equal(x crypto.PrivateKey) bool {
+ if !ok || other == nil {
+ return false
+ }
++ // Two keys of the same parameter set are either both backed by the crypto
++ // backend or both standard library keys, so a differing backing implies
++ // differing parameter sets, and hence different keys.
++ if (sk.boring == nil) != (other.boring == nil) {
++ return false
++ }
++ if sk.boring != nil {
++ return sk.boring.Equal(other.boring)
++ }
+ return sk.k.Equal(&other.k)
+ }
+
+ // PublicKey returns the corresponding [PublicKey] for this private key.
+ func (sk *PrivateKey) PublicKey() *PublicKey {
++ if sk.boring != nil {
++ return &PublicKey{boring: sk.boring.PublicKey()}
++ }
+ // Making a copy severs the pointer relationship between the private and
+ // public keys, so that keeping the public key around doesn't keep the
+ // private key alive. This costs a copy and an allocation.
+@@ -88,9 +161,49 @@ func (sk *PrivateKey) PublicKey() *PublicKey {
+
+ // Bytes returns the private key seed.
+ func (sk *PrivateKey) Bytes() []byte {
++ if sk.boring != nil {
++ return sk.boring.Bytes()
++ }
+ return sk.k.Bytes()
+ }
+
++// goKey returns a standard library private key equivalent to sk. If sk is
++// backed by the crypto backend, the key is reconstructed from its seed the
++// first time it is needed and cached in sk.k. It is used for operations the
++// backend does not implement on every platform, such as deterministic and
++// external-mu signing, which then run through the FIPS 140-3 Go Cryptographic
++// Module.
++func (sk *PrivateKey) goKey() (*mldsa.PrivateKey, error) {
++ if sk.boring == nil {
++ return &sk.k, nil
++ }
++ sk.goKeyOnce.Do(func() {
++ seed := sk.boring.Bytes()
++ var k *mldsa.PrivateKey
++ // Dispatch on the parameter set's string name rather than comparing
++ // backend [boring.MLDSAParameters] values directly: on some platforms an
++ // unsupported set is represented by the zero value, so value comparison
++ // would be ambiguous.
++ switch sk.boring.Parameters().String() {
++ case "ML-DSA-44":
++ k, sk.goKeyErr = mldsa.NewPrivateKey44(seed)
++ case "ML-DSA-65":
++ k, sk.goKeyErr = mldsa.NewPrivateKey65(seed)
++ case "ML-DSA-87":
++ k, sk.goKeyErr = mldsa.NewPrivateKey87(seed)
++ default:
++ sk.goKeyErr = errInvalidParameters
++ }
++ if sk.goKeyErr == nil {
++ sk.k = *k
++ }
++ })
++ if sk.goKeyErr != nil {
++ return nil, sk.goKeyErr
++ }
++ return &sk.k, nil
++}
++
+ var errInvalidSignerOpts = errors.New("mldsa: invalid SignerOpts")
+
+ // Sign returns a signature of the given message using this private key.
+@@ -112,9 +225,21 @@ func (sk *PrivateKey) Sign(_ io.Reader, message []byte, opts crypto.SignerOpts)
+ if opts, ok := opts.(*Options); ok {
+ context = opts.Context
+ }
++ if sk.boring != nil {
++ return sk.boring.Sign(message, context)
++ }
+ return mldsa.Sign(&sk.k, message, context)
+ case crypto.MLDSAMu:
+- return mldsa.SignExternalMu(&sk.k, message)
++ if sk.boring != nil && boring.SupportsMLDSAExternalMu() {
++ return sk.boring.SignExternalMu(message)
++ }
++ // The backend does not implement external-mu signing on this platform,
++ // so fall back to the standard library implementation.
++ k, err := sk.goKey()
++ if err != nil {
++ return nil, err
++ }
++ return mldsa.SignExternalMu(k, message)
+ default:
+ return nil, errInvalidSignerOpts
+ }
+@@ -126,15 +251,21 @@ func (sk *PrivateKey) SignDeterministic(message []byte, opts crypto.SignerOpts)
+ if opts == nil {
+ opts = &Options{}
+ }
++ // Deterministic signing is not supported by the crypto backend, so use the
++ // standard library implementation.
++ k, err := sk.goKey()
++ if err != nil {
++ return nil, err
++ }
+ switch opts.HashFunc() {
+ case 0:
+ var context string
+ if opts, ok := opts.(*Options); ok {
+ context = opts.Context
+ }
+- return mldsa.SignDeterministic(&sk.k, message, context)
++ return mldsa.SignDeterministic(k, message, context)
+ case crypto.MLDSAMu:
+- return mldsa.SignExternalMuDeterministic(&sk.k, message)
++ return mldsa.SignExternalMuDeterministic(k, message)
+ default:
+ return nil, errInvalidSignerOpts
+ }
+@@ -146,6 +277,12 @@ func (sk *PrivateKey) SignDeterministic(message []byte, opts crypto.SignerOpts)
+ // A PublicKey is safe for concurrent use.
+ type PublicKey struct {
+ p mldsa.PublicKey
++
++ // boring holds the crypto backend key, or nil if this key is implemented by
++ // the Go module. It is a pointer because [boring.PublicKeyMLDSA] is large (it
++ // embeds a full-size public key buffer), and storing one by value would make
++ // PublicKey too big to keep on the stack even on the Go path.
++ boring *boring.PublicKeyMLDSA
+ }
+
+ // NewPublicKey creates a new ML-DSA public key from the given encoding.
+@@ -154,6 +291,14 @@ func NewPublicKey(params Parameters, encoding []byte) (*PublicKey, error) {
+ }
+
+ func newPublicKey(pub *PublicKey, params Parameters, encoding []byte) (*PublicKey, error) {
++ if bparams, ok := useBoringMLDSA(params); ok {
++ key, err := boring.NewPublicKeyMLDSA(bparams, encoding)
++ if err != nil {
++ return nil, err
++ }
++ pub.boring = key
++ return pub, nil
++ }
+ var err error
+ var pk *mldsa.PublicKey
+ switch params {
+@@ -175,6 +320,9 @@ func newPublicKey(pub *PublicKey, params Parameters, encoding []byte) (*PublicKe
+
+ // Bytes returns the public key encoding.
+ func (pk *PublicKey) Bytes() []byte {
++ if pk.boring != nil {
++ return pk.boring.Bytes()
++ }
+ return pk.p.Bytes()
+ }
+
+@@ -187,11 +335,29 @@ func (pk *PublicKey) Equal(x crypto.PublicKey) bool {
+ if !ok || other == nil {
+ return false
+ }
++ if (pk.boring == nil) != (other.boring == nil) {
++ return false
++ }
++ if pk.boring != nil {
++ return pk.boring.Equal(other.boring)
++ }
+ return pk.p.Equal(&other.p)
+ }
+
+ // Parameters returns the parameters associated with this public key.
+ func (pk *PublicKey) Parameters() Parameters {
++ if pk.boring != nil {
++ switch pk.boring.Parameters().String() {
++ case "ML-DSA-44":
++ return MLDSA44()
++ case "ML-DSA-65":
++ return MLDSA65()
++ case "ML-DSA-87":
++ return MLDSA87()
++ default:
++ panic("mldsa: invalid parameters in public key")
++ }
++ }
+ switch pk.p.Parameters() {
+ case "ML-DSA-44":
+ return MLDSA44()
+@@ -213,5 +379,8 @@ func Verify(pk *PublicKey, message []byte, signature []byte, opts *Options) erro
+ if opts == nil {
+ opts = &Options{}
+ }
++ if pk.boring != nil {
++ return pk.boring.Verify(message, signature, opts.Context)
++ }
+ return mldsa.Verify(&pk.p, message, signature, opts.Context)
+ }
+diff --git a/src/crypto/mldsa/mldsa_test.go b/src/crypto/mldsa/mldsa_test.go
+index 375333a70cf686..32ce2066b0ae9d 100644
+--- a/src/crypto/mldsa/mldsa_test.go
++++ b/src/crypto/mldsa/mldsa_test.go
+@@ -9,6 +9,7 @@ package mldsa_test
+ import (
+ "bytes"
+ "crypto"
++ boring "crypto/internal/backend"
+ "crypto/fips140"
+ "crypto/internal/cryptotest"
+ . "crypto/mldsa"
+@@ -105,7 +106,7 @@ func testAccumulated(t *testing.T, params Parameters, n int, expected string) {
+ if err != nil {
+ t.Fatalf("NewPublicKey: %v", err)
+ }
+- if *pub != *dk.PublicKey() {
++ if !pub.Equal(dk.PublicKey()) {
+ t.Fatalf("public key mismatch")
+ }
+ if err := Verify(dk.PublicKey(), msg, sig, nil); err != nil {
+@@ -154,6 +155,41 @@ func testGenerateKey(t *testing.T, params Parameters) {
+ }
+ }
+
++// TestEqualDistinguishesParameters checks that two keys derived from the same
++// seed but with different parameter sets are not reported as equal. The private
++// key seed is the same length for all parameter sets, so a seed-only comparison
++// would incorrectly report them as equal.
++func TestEqualDistinguishesParameters(t *testing.T) {
++ seed := make([]byte, PrivateKeySize)
++ for i := range seed {
++ seed[i] = byte(i)
++ }
++ allParams := []Parameters{MLDSA44(), MLDSA65(), MLDSA87()}
++ keys := make([]*PrivateKey, len(allParams))
++ for i, params := range allParams {
++ sk, err := NewPrivateKey(params, seed)
++ if err != nil {
++ t.Fatalf("NewPrivateKey(%v): %v", params, err)
++ }
++ keys[i] = sk
++ }
++ for i := range keys {
++ for j := range keys {
++ got := keys[i].Equal(keys[j])
++ want := i == j
++ if got != want {
++ t.Errorf("PrivateKey(%v).Equal(PrivateKey(%v)) = %v, want %v",
++ allParams[i], allParams[j], got, want)
++ }
++ gotPub := keys[i].PublicKey().Equal(keys[j].PublicKey())
++ if gotPub != want {
++ t.Errorf("PublicKey(%v).Equal(PublicKey(%v)) = %v, want %v",
++ allParams[i], allParams[j], gotPub, want)
++ }
++ }
++ }
++}
++
+ func TestAllocations(t *testing.T) {
+ // We allocate
+ //
+@@ -178,13 +214,34 @@ func TestAllocations(t *testing.T) {
+ expected += 3
+ }
+ cryptotest.SkipTestAllocations(t)
++ params := MLDSA65()
++ switch {
++ case boring.Enabled && boring.SupportsMLDSA(boring.MLDSA65()):
++ // The crypto backend implements ML-DSA-65 on this host, so key
++ // generation, parsing, signing, and verification route through it rather
++ // than the Go module. The backend's allocation count is
++ // implementation-defined, so it replaces the Go expectation above. This
++ // count was measured with the darwin/CryptoKit backend; the OpenSSL and
++ // CNG backends are only reachable where the system cryptography library
++ // implements ML-DSA, which no CI runner currently provides, so they share
++ // this expectation until they can be measured.
++ expected = 12
++ case boring.Enabled:
++ // The crypto backend is built in but does not implement ML-DSA on this
++ // host (for example an OpenSSL, Windows, or macOS release that predates
++ // ML-DSA support), so the operations fall back to the Go module. The
++ // wrapper key structs hold a pointer to the backend key rather than
++ // embedding it, so they are only one word larger than upstream, which
++ // costs at most one extra allocation.
++ expected += 1
++ }
+ if allocs := testing.AllocsPerRun(100, func() {
+- k, err := GenerateKey(MLDSA44())
++ k, err := GenerateKey(params)
+ if err != nil {
+ t.Fatalf("GenerateKey: %v", err)
+ }
+ seed := k.Bytes()
+- kk, err := NewPrivateKey(MLDSA44(), seed)
++ kk, err := NewPrivateKey(params, seed)
+ if err != nil {
+ t.Fatalf("NewPrivateKey: %v", err)
+ }
+@@ -192,7 +249,7 @@ func TestAllocations(t *testing.T) {
+ t.Fatalf("keys not equal")
+ }
+ pkBytes := k.PublicKey().Bytes()
+- pk, err := NewPublicKey(MLDSA44(), pkBytes)
++ pk, err := NewPublicKey(params, pkBytes)
+ if err != nil {
+ t.Fatalf("NewPublicKey: %v", err)
+ }
diff --git a/src/crypto/mlkem/mlkem.go b/src/crypto/mlkem/mlkem.go
index f0fd6a4993a8e6..53600fdf265062 100644
--- a/src/crypto/mlkem/mlkem.go