Filippo Valsorda uploaded patch set #9 to this change.
crypto/ecdh: new package
We use crypto/internal/edwards25519/field to implement X25519 directly,
so that golang.org/x/crypto/curve25519 can be dropped from the src
module dependencies, and eventually replaced with a crypto/ecdh wrapper,
removing the need to keep golang.org/x/crypto/curve25519/internal/field
in sync with crypto/internal/edwards25519/field.
In crypto/internal/nistec, we add BytesX to serialize only the x
coordinate, which we'll need for the horrible ECDSA x-coord-to-scalar
operation, too.
In crypto/tls, we replace the ECDHE implementation with crypto/ecdh,
dropping the X25519 special cases and related scaffolding.
For #52182
Fixes #52221
Change-Id: Iccdda210319cc892e96bb28a0e7b7123551982c7
---
A api/next/52221.txt
A src/crypto/ecdh/ecdh.go
A src/crypto/ecdh/ecdh_test.go
A src/crypto/ecdh/nist.go
A src/crypto/ecdh/x25519.go
M src/crypto/internal/nistec/generate.go
M src/crypto/internal/nistec/p224.go
M src/crypto/internal/nistec/p256.go
M src/crypto/internal/nistec/p256_asm.go
M src/crypto/internal/nistec/p384.go
M src/crypto/internal/nistec/p521.go
M src/crypto/tls/handshake_client.go
M src/crypto/tls/handshake_client_tls13.go
M src/crypto/tls/handshake_server_test.go
M src/crypto/tls/handshake_server_tls13.go
M src/crypto/tls/key_agreement.go
M src/crypto/tls/key_schedule.go
M src/go/build/deps_test.go
D src/vendor/golang.org/x/crypto/curve25519/curve25519.go
D src/vendor/golang.org/x/crypto/curve25519/internal/field/README
D src/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go
D src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go
D src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s
D src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go
D src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go
D src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s
D src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go
D src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go
D src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint
D src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh
M src/vendor/modules.txt
31 files changed, 864 insertions(+), 1,454 deletions(-)
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda.
Filippo Valsorda uploaded patch set #10 to this change.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda.
4 comments:
File src/crypto/ecdh/nist.go:
Patch Set #9, Line 34: make([]byte, 66)[:len(c.scalarOrder)]
could this just be: `make([]byte, len(c. […]
Using a fixed size makes it possible to allocate on the stack, however NewPrivateKey doesn't get devirtualized because it's a method of a generic function, so key escapes anyway. Dropped the trick. Can always put it back if the generics optimizations get better.
Patch Set #9, Line 62: var errInvalidPrivateKey = errors.New("crypto/ecdh: invalid private key")
(nit): this could be before GenerateKey function.
Done
File src/crypto/ecdh/x25519.go:
Patch Set #9, Line 31: func (x25519Curve) private() {}
// private implements the Curve interface.
Done
(nit): remove newline
Done
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Filippo Valsorda.
Patch set 9:Code-Review +1
8 comments:
Patchset:
I might take another look at the TLS change, but on first round it LGTM, great work.
File src/crypto/ecdh/ecdh.go:
Patch Set #9, Line 37: X25519, this only checks the scalar length
IIUC, `x25519ScalarMult` does performs the clamping of the first 3 bytes, should this be somewhat mentioned as part of what's validated?
Or maybe just mention it follows RFC 7748 Section 5?
Patch Set #9, Line 44: Compressed
Since compressed encodings are supported further down the chain, is the plan to support this eventually?
File src/crypto/ecdh/ecdh_test.go:
Patch Set #9, Line 23: &ecdh.PublicKey{}
(feel free to ignore) (*ecdh.PublicKey)(nil)
File src/crypto/ecdh/nist.go:
Patch Set #9, Line 34: make([]byte, 66)[:len(c.scalarOrder)]
could this just be: `make([]byte, len(c.scalarOrder))`? Does it need the additional capacity?
Patch Set #9, Line 62: var errInvalidPrivateKey = errors.New("crypto/ecdh: invalid private key")
(nit): this could be before GenerateKey function.
File src/crypto/ecdh/x25519.go:
Patch Set #9, Line 31: func (x25519Curve) private() {}
// private implements the Curve interface.
(nit): remove newline
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda.
Filippo Valsorda uploaded patch set #11 to this change.
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda.
Filippo Valsorda uploaded patch set #12 to this change.
crypto/ecdh: new package
We use crypto/internal/edwards25519/field to implement X25519 directly,
so that golang.org/x/crypto/curve25519 can be dropped from the src
module dependencies, and eventually replaced with a crypto/ecdh wrapper,
removing the need to keep golang.org/x/crypto/curve25519/internal/field
in sync with crypto/internal/edwards25519/field.
In crypto/internal/nistec, we add BytesX to serialize only the x
coordinate, which we'll need for the horrible ECDSA x-coord-to-scalar
operation, too.
In crypto/tls, we replace the ECDHE implementation with crypto/ecdh,
dropping the X25519 special cases and related scaffolding.
For #52182
Fixes #52221
Change-Id: Iccdda210319cc892e96bb28a0e7b7123551982c7
---
A api/next/52221.txt
A src/crypto/ecdh/ecdh.go
A src/crypto/ecdh/ecdh_test.go
A src/crypto/ecdh/nist.go
A src/crypto/ecdh/x25519.go
M src/crypto/internal/nistec/fiat/generate.go
32 files changed, 901 insertions(+), 1,480 deletions(-)
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda.
2 comments:
File src/crypto/ecdh/ecdh.go:
Patch Set #9, Line 37: X25519, this only checks the scalar length
IIUC, `x25519ScalarMult` does performs the clamping of the first 3 bytes, should this be somewhat me […]
The clamping is defined as part of the ECDH operation, not as part of loading the key. The comment on the ECDH method references RFC 7748, Section 6.1.
Patch Set #9, Line 44: Compressed
Since compressed encodings are supported further down the chain, is the plan to support this eventua […]
Yeah! I will add this proposed API https://github.com/golang/go/issues/52221#issuecomment-1111153164 in a follow-up CL.
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda.
Filippo Valsorda uploaded patch set #13 to this change.
crypto/ecdh: new package
We use crypto/internal/edwards25519/field to implement X25519 directly,
so that golang.org/x/crypto/curve25519 can be dropped from the src
module dependencies, and eventually replaced with a crypto/ecdh wrapper,
removing the need to keep golang.org/x/crypto/curve25519/internal/field
in sync with crypto/internal/edwards25519/field.
In crypto/internal/nistec, we add BytesX to serialize only the x
coordinate, which we'll need for the horrible ECDSA x-coord-to-scalar
operation, too.
In crypto/tls, we replace the ECDHE implementation with crypto/ecdh,
dropping the X25519 special cases and related scaffolding.
For #52182
Fixes #52221
Change-Id: Iccdda210319cc892e96bb28a0e7b7123551982c7
---
A api/next/52221.txt
A src/crypto/ecdh/ecdh.go
A src/crypto/ecdh/ecdh_test.go
A src/crypto/ecdh/nist.go
A src/crypto/ecdh/x25519.go
31 files changed, 899 insertions(+), 1,454 deletions(-)
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda.
Patch set 13:Code-Review +2
3 comments:
File src/crypto/ecdh/ecdh.go:
Patch Set #12, Line 80: func (k *PublicKey) Equal(x crypto.PublicKey) bool {
Document this is constant time?
Patch Set #12, Line 113: func (k *PrivateKey) Equal(x crypto.PrivateKey) bool {
Same as above, 🤷.
File src/crypto/ecdh/ecdh_test.go:
Patch Set #12, Line 1: // Copyright 2022 The Go Authors. All rights reserved.
Test vectors for ECDH for each of the curves would be nice.
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda, Roland Shoemaker.
2 comments:
File src/crypto/ecdh/ecdh.go:
Patch Set #12, Line 80: func (k *PublicKey) Equal(x crypto.PublicKey) bool {
Document this is constant time?
Done
Patch Set #12, Line 113: func (k *PrivateKey) Equal(x crypto.PrivateKey) bool {
Same as above, 🤷.
Done
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda, Roland Shoemaker.
Filippo Valsorda uploaded patch set #14 to this change.
31 files changed, 911 insertions(+), 1,454 deletions(-)
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda, Roland Shoemaker.
1 comment:
Patchset:
Almost forgot to add the deprecation notices to crypto/elliptic! \o/
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda, Roland Shoemaker.
Filippo Valsorda uploaded patch set #15 to this change.
crypto/ecdh: new package
We use crypto/internal/edwards25519/field to implement X25519 directly,
so that golang.org/x/crypto/curve25519 can be dropped from the src
module dependencies, and eventually replaced with a crypto/ecdh wrapper,
removing the need to keep golang.org/x/crypto/curve25519/internal/field
in sync with crypto/internal/edwards25519/field.
In crypto/internal/nistec, we add BytesX to serialize only the x
coordinate, which we'll need for the horrible ECDSA x-coord-to-scalar
operation, too.
In crypto/tls, we replace the ECDHE implementation with crypto/ecdh,
dropping the X25519 special cases and related scaffolding.
Finally, FINALLY, we deprecate the ~white whale~ big.Int-based APIs of
the crypto/elliptic package. •_•) ( •_•)>⌐■-■ (⌐■_■)
For #52182
Fixes #34648
Fixes #52221
Change-Id: Iccdda210319cc892e96bb28a0e7b7123551982c7
---
A api/next/52221.txt
A src/crypto/ecdh/ecdh.go
A src/crypto/ecdh/ecdh_test.go
A src/crypto/ecdh/nist.go
A src/crypto/ecdh/x25519.go
M src/crypto/elliptic/elliptic.go
M src/crypto/elliptic/params.go
33 files changed, 1,064 insertions(+), 1,457 deletions(-)
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda, Roland Shoemaker.
3 comments:
Patchset:
Almost forgot to add the deprecation notices to crypto/elliptic! \o/
Done
Patchset:
Roland, PTAL at the deprecation messages? I used the "Deprecated:" marking only on those methods and functions that don't have a legitimate ECDSA purpose.
RELNOTE=yes
File src/crypto/ecdh/ecdh_test.go:
Patch Set #12, Line 1: // Copyright 2022 The Go Authors. All rights reserved.
Test vectors for ECDH for each of the curves would be nice.
Done
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda, Roland Shoemaker.
Filippo Valsorda uploaded patch set #16 to this change.
crypto/ecdh: new package
We use crypto/internal/edwards25519/field to implement X25519 directly,
so that golang.org/x/crypto/curve25519 can be dropped from the src
module dependencies, and eventually replaced with a crypto/ecdh wrapper,
removing the need to keep golang.org/x/crypto/curve25519/internal/field
in sync with crypto/internal/edwards25519/field.
In crypto/internal/nistec, we add BytesX to serialize only the x
coordinate, which we'll need for the horrible ECDSA x-coord-to-scalar
operation, too.
In crypto/tls, we replace the ECDHE implementation with crypto/ecdh,
dropping the X25519 special cases and related scaffolding.
Finally, FINALLY, we deprecate the ~white whale~ big.Int-based APIs of
the crypto/elliptic package. •_•) ( •_•)>⌐■-■ (⌐■_■)
Fixes #52182
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda, Roland Shoemaker.
1 comment:
Patchset:
What is the status of this CL? Do we want this for 1.19?
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Fernando Lobato Meeser, Filippo Valsorda, Roland Shoemaker.
Filippo Valsorda uploaded patch set #17 to this change.
The following approvals got outdated and were removed: Run-TryBot+1 by Filippo Valsorda, TryBot-Result+1 by Gopher Robot
33 files changed, 1,086 insertions(+), 1,462 deletions(-)
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.
Filippo Valsorda submitted this change.
13 is the latest approved patch-set.
The change was submitted with unreviewed changes in the following files:
```
The name of the file: src/go/build/deps_test.go
Insertions: 5, Deletions: 3.
The diff is too large to show. Please review the diff.
```
```
The name of the file: src/crypto/ecdh/ecdh_test.go
Insertions: 85, Deletions: 0.
The diff is too large to show. Please review the diff.
```
```
The name of the file: src/crypto/ecdh/x25519.go
Insertions: 4, Deletions: 0.
The diff is too large to show. Please review the diff.
```
```
The name of the file: src/crypto/elliptic/params.go
Insertions: 34, Deletions: 0.
The diff is too large to show. Please review the diff.
```
```
The name of the file: src/crypto/ecdh/nist.go
Insertions: 8, Deletions: 0.
The diff is too large to show. Please review the diff.
```
```
The name of the file: src/crypto/elliptic/elliptic.go
Insertions: 40, Deletions: 3.
The diff is too large to show. Please review the diff.
```
```
The name of the file: src/crypto/ecdh/ecdh.go
Insertions: 16, Deletions: 4.
The diff is too large to show. Please review the diff.
```
crypto/ecdh: new package
We use crypto/internal/edwards25519/field to implement X25519 directly,
so that golang.org/x/crypto/curve25519 can be dropped from the src
module dependencies, and eventually replaced with a crypto/ecdh wrapper,
removing the need to keep golang.org/x/crypto/curve25519/internal/field
in sync with crypto/internal/edwards25519/field.
In crypto/internal/nistec, we add BytesX to serialize only the x
coordinate, which we'll need for the horrible ECDSA x-coord-to-scalar
operation, too.
In crypto/tls, we replace the ECDHE implementation with crypto/ecdh,
dropping the X25519 special cases and related scaffolding.
Finally, FINALLY, we deprecate the ~white whale~ big.Int-based APIs of
the crypto/elliptic package. •_•) ( •_•)>⌐■-■ (⌐■_■)
Fixes #52182
Fixes #34648
Fixes #52221
Change-Id: Iccdda210319cc892e96bb28a0e7b7123551982c7
Reviewed-on: https://go-review.googlesource.com/c/go/+/398914
Reviewed-by: Fernando Lobato Meeser <felo...@google.com>
Reviewed-by: Roland Shoemaker <rol...@golang.org>
Run-TryBot: Filippo Valsorda <fil...@golang.org>
TryBot-Result: Gopher Robot <go...@golang.org>
33 files changed, 1,091 insertions(+), 1,462 deletions(-)
diff --git a/api/next/52221.txt b/api/next/52221.txt
new file mode 100644
index 0000000..c288e46
--- /dev/null
+++ b/api/next/52221.txt
@@ -0,0 +1,19 @@
+pkg crypto/ecdh, func P256() Curve #52221
+pkg crypto/ecdh, func P384() Curve #52221
+pkg crypto/ecdh, func P521() Curve #52221
+pkg crypto/ecdh, func X25519() Curve #52221
+pkg crypto/ecdh, method (*PrivateKey) Bytes() []uint8 #52221
+pkg crypto/ecdh, method (*PrivateKey) Curve() Curve #52221
+pkg crypto/ecdh, method (*PrivateKey) Equal(crypto.PrivateKey) bool #52221
+pkg crypto/ecdh, method (*PrivateKey) Public() crypto.PublicKey #52221
+pkg crypto/ecdh, method (*PrivateKey) PublicKey() *PublicKey #52221
+pkg crypto/ecdh, method (*PublicKey) Bytes() []uint8 #52221
+pkg crypto/ecdh, method (*PublicKey) Curve() Curve #52221
+pkg crypto/ecdh, method (*PublicKey) Equal(crypto.PublicKey) bool #52221
+pkg crypto/ecdh, type Curve interface, ECDH(*PrivateKey, *PublicKey) ([]uint8, error) #52221
+pkg crypto/ecdh, type Curve interface, GenerateKey(io.Reader) (*PrivateKey, error) #52221
+pkg crypto/ecdh, type Curve interface, NewPrivateKey([]uint8) (*PrivateKey, error) #52221
+pkg crypto/ecdh, type Curve interface, NewPublicKey([]uint8) (*PublicKey, error) #52221
+pkg crypto/ecdh, type Curve interface, unexported methods #52221
+pkg crypto/ecdh, type PrivateKey struct #52221
+pkg crypto/ecdh, type PublicKey struct #52221
diff --git a/src/crypto/ecdh/ecdh.go b/src/crypto/ecdh/ecdh.go
new file mode 100644
index 0000000..d835b04
--- /dev/null
+++ b/src/crypto/ecdh/ecdh.go
@@ -0,0 +1,149 @@
+// 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.
+
+// Package ecdh implements Elliptic Curve Diffie-Hellman over
+// NIST curves and Curve25519.
+package ecdh
+
+import (
+ "crypto"
+ "crypto/subtle"
+ "io"
+ "sync"
+)
+
+type Curve interface {
+ // ECDH performs a ECDH exchange and returns the shared secret.
+ //
+ // For NIST curves, this performs ECDH as specified in SEC 1, Version 2.0,
+ // Section 3.3.1, and returns the x-coordinate encoded according to SEC 1,
+ // Version 2.0, Section 2.3.5. In particular, if the result is the point at
+ // infinity, ECDH returns an error. (Note that for NIST curves, that's only
+ // possible if the private key is the all-zero value.)
+ //
+ // For X25519, this performs ECDH as specified in RFC 7748, Section 6.1. If
+ // the result is the all-zero value, ECDH returns an error.
+ ECDH(local *PrivateKey, remote *PublicKey) ([]byte, error)
+
+ // GenerateKey generates a new PrivateKey from rand.
+ GenerateKey(rand io.Reader) (*PrivateKey, error)
+
+ // NewPrivateKey checks that key is valid and returns a PrivateKey.
+ //
+ // For NIST curves, this follows SEC 1, Version 2.0, Section 2.3.6, which
+ // amounts to decoding the bytes as a fixed length big endian integer and
+ // checking that the result is lower than the order of the curve. The zero
+ // private key is also rejected, as the encoding of the corresponding public
+ // key would be irregular.
+ //
+ // For X25519, this only checks the scalar length. Adversarially selected
+ // private keys can cause ECDH to return an error.
+ NewPrivateKey(key []byte) (*PrivateKey, error)
+
+ // NewPublicKey checks that key is valid and returns a PublicKey.
+ //
+ // For NIST curves, this decodes an uncompressed point according to SEC 1,
+ // Version 2.0, Section 2.3.4. Compressed encodings and the point at
+ // infinity are rejected.
+ //
+ // For X25519, this only checks the u-coordinate length. Adversarially
+ // selected public keys can cause ECDH to return an error.
+ NewPublicKey(key []byte) (*PublicKey, error)
+
+ // privateKeyToPublicKey converts a PrivateKey to a PublicKey. It's exposed
+ // as the PrivateKey.PublicKey method.
+ //
+ // This method always succeeds: for X25519, it might output the all-zeroes
+ // value (unlike the ECDH method); for NIST curves, it would only fail for
+ // the zero private key, which is rejected by NewPrivateKey.
+ //
+ // The private method also allow us to expand the ECDH interface with more
+ // methods in the future without breaking backwards compatibility.
+ privateKeyToPublicKey(*PrivateKey) *PublicKey
+}
+
+// PublicKey is an ECDH public key, usually a peer's ECDH share sent over the wire.
+type PublicKey struct {
+ curve Curve
+ publicKey []byte
+}
+
+// Bytes returns a copy of the encoding of the public key.
+func (k *PublicKey) Bytes() []byte {
+ // Copy the public key to a fixed size buffer that can get allocated on the
+ // caller's stack after inlining.
+ var buf [133]byte
+ return append(buf[:0], k.publicKey...)
+}
+
+// Equal returns whether x represents the same public key as k.
+//
+// Note that there can be equivalent public keys with different encodings which
+// would return false from this check but behave the same way as inputs to ECDH.
+//
+// This check is performed in constant time as long as the key types and their
+// curve match.
+func (k *PublicKey) Equal(x crypto.PublicKey) bool {
+ xx, ok := x.(*PublicKey)
+ if !ok {
+ return false
+ }
+ return k.curve == xx.curve &&
+ subtle.ConstantTimeCompare(k.publicKey, xx.publicKey) == 1
+}
+
+func (k *PublicKey) Curve() Curve {
+ return k.curve
+}
+
+// PrivateKey is an ECDH private key, usually kept secret.
+type PrivateKey struct {
+ curve Curve
+ privateKey []byte
+ // publicKey is set under publicKeyOnce, to allow loading private keys with
+ // NewPrivateKey without having to perform a scalar multiplication.
+ publicKey *PublicKey
+ publicKeyOnce sync.Once
+}
+
+// Bytes returns a copy of the encoding of the private key.
+func (k *PrivateKey) Bytes() []byte {
+ // Copy the private key to a fixed size buffer that can get allocated on the
+ // caller's stack after inlining.
+ var buf [66]byte
+ return append(buf[:0], k.privateKey...)
+}
+
+// Equal returns whether x represents the same private key as k.
+//
+// Note that there can be equivalent private keys with different encodings which
+// would return false from this check but behave the same way as inputs to ECDH.
+//
+// This check is performed in constant time as long as the key types and their
+// curve match.
+func (k *PrivateKey) Equal(x crypto.PrivateKey) bool {
+ xx, ok := x.(*PrivateKey)
+ if !ok {
+ return false
+ }
+ return k.curve == xx.curve &&
+ subtle.ConstantTimeCompare(k.privateKey, xx.privateKey) == 1
+}
+
+func (k *PrivateKey) Curve() Curve {
+ return k.curve
+}
+
+func (k *PrivateKey) PublicKey() *PublicKey {
+ k.publicKeyOnce.Do(func() {
+ k.publicKey = k.curve.privateKeyToPublicKey(k)
+ })
+ return k.publicKey
+}
+
+// Public implements the implicit interface of all standard library private
+// keys. See the docs of crypto.PrivateKey.
+func (k *PrivateKey) Public() crypto.PublicKey {
+ return k.PublicKey()
+}
diff --git a/src/crypto/ecdh/ecdh_test.go b/src/crypto/ecdh/ecdh_test.go
new file mode 100644
index 0000000..b27d6c9
--- /dev/null
+++ b/src/crypto/ecdh/ecdh_test.go
@@ -0,0 +1,255 @@
+// 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.
+
+package ecdh_test
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/cipher"
+ "crypto/ecdh"
+ "crypto/rand"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "testing"
+
+ "golang.org/x/crypto/chacha20"
+)
+
+// Check that PublicKey and PrivateKey implement the interfaces documented in
+// crypto.PublicKey and crypto.PrivateKey.
+var _ interface {
+ Equal(x crypto.PublicKey) bool
+} = &ecdh.PublicKey{}
+var _ interface {
+ Public() crypto.PublicKey
+ Equal(x crypto.PrivateKey) bool
+} = &ecdh.PrivateKey{}
+
+func TestECDH(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve ecdh.Curve) {
+ aliceKey, err := curve.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ bobKey, err := curve.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ alicePubKey, err := curve.NewPublicKey(aliceKey.PublicKey().Bytes())
+ if err != nil {
+ t.Error(err)
+ }
+ if !bytes.Equal(aliceKey.PublicKey().Bytes(), alicePubKey.Bytes()) {
+ t.Error("encoded and decoded public keys are different")
+ }
+ if !aliceKey.PublicKey().Equal(alicePubKey) {
+ t.Error("encoded and decoded public keys are different")
+ }
+
+ alicePrivKey, err := curve.NewPrivateKey(aliceKey.Bytes())
+ if err != nil {
+ t.Error(err)
+ }
+ if !bytes.Equal(aliceKey.Bytes(), alicePrivKey.Bytes()) {
+ t.Error("encoded and decoded private keys are different")
+ }
+ if !aliceKey.Equal(alicePrivKey) {
+ t.Error("encoded and decoded private keys are different")
+ }
+
+ bobSecret, err := curve.ECDH(bobKey, aliceKey.PublicKey())
+ if err != nil {
+ t.Fatal(err)
+ }
+ aliceSecret, err := curve.ECDH(aliceKey, bobKey.PublicKey())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Equal(bobSecret, aliceSecret) {
+ t.Error("two ECDH computations came out different")
+ }
+ })
+}
+
+type countingReader struct {
+ r io.Reader
+ n int
+}
+
+func (r *countingReader) Read(p []byte) (int, error) {
+ n, err := r.r.Read(p)
+ r.n += n
+ return n, err
+}
+
+func TestGenerateKey(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve ecdh.Curve) {
+ r := &countingReader{r: rand.Reader}
+ k, err := curve.GenerateKey(r)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // GenerateKey does rejection sampling. If the masking works correctly,
+ // the probability of a rejection is 1-ord(G)/2^ceil(log2(ord(G))),
+ // which for all curves is small enough (at most 2^-32, for P-256) that
+ // a bit flip is more likely to make this test fail than bad luck.
+ // Account for the extra MaybeReadByte byte, too.
+ if got, expected := r.n, len(k.Bytes())+1; got > expected {
+ t.Errorf("expected GenerateKey to consume at most %v bytes, got %v", expected, got)
+ }
+ })
+}
+
+var vectors = map[ecdh.Curve]struct {
+ PrivateKey, PublicKey string
+ PeerPublicKey string
+ SharedSecret string
+}{
+ // NIST vectors from CAVS 14.1, ECC CDH Primitive (SP800-56A).
+ ecdh.P256(): {
+ PrivateKey: "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534",
+ PublicKey: "04ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230" +
+ "28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141",
+ PeerPublicKey: "04700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" +
+ "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
+ SharedSecret: "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b",
+ },
+ ecdh.P384(): {
+ PrivateKey: "3cc3122a68f0d95027ad38c067916ba0eb8c38894d22e1b15618b6818a661774ad463b205da88cf699ab4d43c9cf98a1",
+ PublicKey: "049803807f2f6d2fd966cdd0290bd410c0190352fbec7ff6247de1302df86f25d34fe4a97bef60cff548355c015dbb3e5f" +
+ "ba26ca69ec2f5b5d9dad20cc9da711383a9dbe34ea3fa5a2af75b46502629ad54dd8b7d73a8abb06a3a3be47d650cc99",
+ PeerPublicKey: "04a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e764592efda27fe7513272734466b400091adbf2d68c58e0c50066" +
+ "ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b661efedf243451915ed0905a32b060992b468c64766fc8437a",
+ SharedSecret: "5f9d29dc5e31a163060356213669c8ce132e22f57c9a04f40ba7fcead493b457e5621e766c40a2e3d4d6a04b25e533f1",
+ },
+ // For some reason all field elements in the test vector (both scalars and
+ // base field elements), but not the shared secret output, have two extra
+ // leading zero bytes (which in big-endian are irrelevant). Removed here.
+ ecdh.P521(): {
+ PrivateKey: "017eecc07ab4b329068fba65e56a1f8890aa935e57134ae0ffcce802735151f4eac6564f6ee9974c5e6887a1fefee5743ae2241bfeb95d5ce31ddcb6f9edb4d6fc47",
+ PublicKey: "0400602f9d0cf9e526b29e22381c203c48a886c2b0673033366314f1ffbcba240ba42f4ef38a76174635f91e6b4ed34275eb01c8467d05ca80315bf1a7bbd945f550a5" +
+ "01b7c85f26f5d4b2d7355cf6b02117659943762b6d1db5ab4f1dbc44ce7b2946eb6c7de342962893fd387d1b73d7a8672d1f236961170b7eb3579953ee5cdc88cd2d",
+ PeerPublicKey: "0400685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a9490340854334b1e1b87fa395464c60626124a4e70d0f785601d37c09870ebf176666877a2046d" +
+ "01ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b739884a83bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302f676",
+ SharedSecret: "005fc70477c3e63bc3954bd0df3ea0d1f41ee21746ed95fc5e1fdf90930d5e136672d72cc770742d1711c3c3a4c334a0ad9759436a4d3c5bf6e74b9578fac148c831",
+ },
+ // X25519 test vector from RFC 7748, Section 6.1.
+ ecdh.X25519(): {
+ PrivateKey: "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a",
+ PublicKey: "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a",
+ PeerPublicKey: "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f",
+ SharedSecret: "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742",
+ },
+}
+
+func TestVectors(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve ecdh.Curve) {
+ v := vectors[curve]
+ key, err := curve.NewPrivateKey(hexDecode(t, v.PrivateKey))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(key.PublicKey().Bytes(), hexDecode(t, v.PublicKey)) {
+ t.Error("public key derived from the private key does not match")
+ }
+ peer, err := curve.NewPublicKey(hexDecode(t, v.PeerPublicKey))
+ if err != nil {
+ t.Fatal(err)
+ }
+ secret, err := curve.ECDH(key, peer)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(secret, hexDecode(t, v.SharedSecret)) {
+ t.Error("shared secret does not match")
+ }
+ })
+}
+
+func hexDecode(t *testing.T, s string) []byte {
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ t.Fatal("invalid hex string:", s)
+ }
+ return b
+}
+
+func TestString(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve ecdh.Curve) {
+ s := fmt.Sprintf("%s", curve)
+ if s[:1] != "P" && s[:1] != "X" {
+ t.Errorf("unexpected Curve string encoding: %q", s)
+ }
+ })
+}
+
+func testAllCurves(t *testing.T, f func(t *testing.T, curve ecdh.Curve)) {
+ t.Run("P256", func(t *testing.T) { f(t, ecdh.P256()) })
+ t.Run("P384", func(t *testing.T) { f(t, ecdh.P384()) })
+ t.Run("P521", func(t *testing.T) { f(t, ecdh.P521()) })
+ t.Run("X25519", func(t *testing.T) { f(t, ecdh.X25519()) })
+}
+
+func BenchmarkECDH(b *testing.B) {
+ benchmarkAllCurves(b, func(b *testing.B, curve ecdh.Curve) {
+ c, err := chacha20.NewUnauthenticatedCipher(make([]byte, 32), make([]byte, 12))
+ if err != nil {
+ b.Fatal(err)
+ }
+ rand := cipher.StreamReader{
+ S: c, R: zeroReader,
+ }
+
+ peerKey, err := curve.GenerateKey(rand)
+ if err != nil {
+ b.Fatal(err)
+ }
+ peerShare := peerKey.PublicKey().Bytes()
+ b.ResetTimer()
+ b.ReportAllocs()
+
+ var allocationsSink byte
+
+ for i := 0; i < b.N; i++ {
+ key, err := curve.GenerateKey(rand)
+ if err != nil {
+ b.Fatal(err)
+ }
+ share := key.PublicKey().Bytes()
+ peerPubKey, err := curve.NewPublicKey(peerShare)
+ if err != nil {
+ b.Fatal(err)
+ }
+ secret, err := curve.ECDH(key, peerPubKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ allocationsSink ^= secret[0] ^ share[0]
+ }
+ })
+}
+
+func benchmarkAllCurves(b *testing.B, f func(b *testing.B, curve ecdh.Curve)) {
+ b.Run("P256", func(b *testing.B) { f(b, ecdh.P256()) })
+ b.Run("P384", func(b *testing.B) { f(b, ecdh.P384()) })
+ b.Run("P521", func(b *testing.B) { f(b, ecdh.P521()) })
+ b.Run("X25519", func(b *testing.B) { f(b, ecdh.X25519()) })
+}
+
+type zr struct{}
+
+// Read replaces the contents of dst with zeros. It is safe for concurrent use.
+func (zr) Read(dst []byte) (n int, err error) {
+ for i := range dst {
+ dst[i] = 0
+ }
+ return len(dst), nil
+}
+
+var zeroReader = zr{}
diff --git a/src/crypto/ecdh/nist.go b/src/crypto/ecdh/nist.go
new file mode 100644
index 0000000..091d6ae
--- /dev/null
+++ b/src/crypto/ecdh/nist.go
@@ -0,0 +1,211 @@
+// 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.
+
+package ecdh
+
+import (
+ "crypto/internal/nistec"
+ "crypto/internal/randutil"
+ "encoding/binary"
+ "errors"
+ "io"
+ "math/bits"
+)
+
+type nistCurve[Point nistPoint[Point]] struct {
+ name string
+ newPoint func() Point
+ scalarOrder []byte
+}
+
+// nistPoint is a generic constraint for the nistec Point types.
+type nistPoint[T any] interface {
+ Bytes() []byte
+ BytesX() ([]byte, error)
+ SetBytes([]byte) (T, error)
+ ScalarMult(T, []byte) (T, error)
+ ScalarBaseMult([]byte) (T, error)
+}
+
+func (c *nistCurve[Point]) String() string {
+ return c.name
+}
+
+var errInvalidPrivateKey = errors.New("crypto/ecdh: invalid private key")
+
+func (c *nistCurve[Point]) GenerateKey(rand io.Reader) (*PrivateKey, error) {
+ key := make([]byte, len(c.scalarOrder))
+ randutil.MaybeReadByte(rand)
+ for {
+ if _, err := io.ReadFull(rand, key); err != nil {
+ return nil, err
+ }
+
+ // Mask off any excess bits if the size of the underlying field is not a
+ // whole number of bytes, which is only the case for P-521. We use a
+ // pointer to the scalarOrder field because comparing generic and
+ // instantiated types is not supported.
+ if &c.scalarOrder[0] == &p521Order[0] {
+ key[0] &= 0b0000_0001
+ }
+
+ // In tests, rand will return all zeros and NewPrivateKey will reject
+ // the zero key as it generates the identity as a public key. This also
+ // makes this function consistent with crypto/elliptic.GenerateKey.
+ key[1] ^= 0x42
+
+ k, err := c.NewPrivateKey(key)
+ if err == errInvalidPrivateKey {
+ continue
+ }
+ return k, err
+ }
+}
+
+func (c *nistCurve[Point]) NewPrivateKey(key []byte) (*PrivateKey, error) {
+ if len(key) != len(c.scalarOrder) {
+ return nil, errors.New("crypto/ecdh: invalid private key size")
+ }
+ if isZero(key) || !isLess(key, c.scalarOrder) {
+ return nil, errInvalidPrivateKey
+ }
+ return &PrivateKey{
+ curve: c,
+ privateKey: append([]byte{}, key...),
+ }, nil
+}
+
+func (c *nistCurve[Point]) privateKeyToPublicKey(key *PrivateKey) *PublicKey {
+ if key.curve != c {
+ panic("crypto/ecdh: internal error: converting the wrong key type")
+ }
+ p, err := c.newPoint().ScalarBaseMult(key.privateKey)
+ if err != nil {
+ // This is unreachable because the only error condition of
+ // ScalarBaseMult is if the input is not the right size.
+ panic("crypto/ecdh: internal error: nistec ScalarBaseMult failed for a fixed-size input")
+ }
+ publicKey := p.Bytes()
+ if len(publicKey) == 1 {
+ // The encoding of the identity is a single 0x00 byte. This is
+ // unreachable because the only scalar that generates the identity is
+ // zero, which is rejected by NewPrivateKey.
+ panic("crypto/ecdh: internal error: nistec ScalarBaseMult returned the identity")
+ }
+ return &PublicKey{
+ curve: key.curve,
+ publicKey: publicKey,
+ }
+}
+
+// isZero returns whether a is all zeroes in constant time.
+func isZero(a []byte) bool {
+ var acc byte
+ for _, b := range a {
+ acc |= b
+ }
+ return acc == 0
+}
+
+// isLess returns whether a < b, where a and b are big-endian buffers of the
+// same length and shorter than 72 bytes.
+func isLess(a, b []byte) bool {
+ if len(a) != len(b) {
+ panic("crypto/ecdh: internal error: mismatched isLess inputs")
+ }
+
+ // Copy the values into a fixed-size preallocated little-endian buffer.
+ // 72 bytes is enough for every scalar in this package, and having a fixed
+ // size lets us avoid heap allocations.
+ if len(a) > 72 {
+ panic("crypto/ecdh: internal error: isLess input too large")
+ }
+ bufA, bufB := make([]byte, 72), make([]byte, 72)
+ for i := range a {
+ bufA[i], bufB[i] = a[len(a)-i-1], b[len(b)-i-1]
+ }
+
+ // Perform a subtraction with borrow.
+ var borrow uint64
+ for i := 0; i < len(bufA); i += 8 {
+ limbA, limbB := binary.LittleEndian.Uint64(bufA[i:]), binary.LittleEndian.Uint64(bufB[i:])
+ _, borrow = bits.Sub64(limbA, limbB, borrow)
+ }
+
+ // If there is a borrow at the end of the operation, then a < b.
+ return borrow == 1
+}
+
+func (c *nistCurve[Point]) NewPublicKey(key []byte) (*PublicKey, error) {
+ // Reject the point at infinity and compressed encodings.
+ if len(key) == 0 || key[0] != 4 {
+ return nil, errors.New("crypto/ecdh: invalid public key")
+ }
+ // SetBytes also checks that the point is on the curve.
+ if _, err := c.newPoint().SetBytes(key); err != nil {
+ return nil, err
+ }
+
+ return &PublicKey{
+ curve: c,
+ publicKey: append([]byte{}, key...),
+ }, nil
+}
+
+func (c *nistCurve[Point]) ECDH(local *PrivateKey, remote *PublicKey) ([]byte, error) {
+ p, err := c.newPoint().SetBytes(remote.publicKey)
+ if err != nil {
+ return nil, err
+ }
+ if _, err := p.ScalarMult(p, local.privateKey); err != nil {
+ return nil, err
+ }
+ // BytesX will return an error if p is the point at infinity.
+ return p.BytesX()
+}
+
+// P256 returns a Curve which implements NIST P-256 (FIPS 186-3, section D.2.3),
+// also known as secp256r1 or prime256v1.
+//
+// Multiple invocations of this function will return the same value, so it can
+// be used for equality checks and switch statements.
+func P256() Curve { return p256 }
+
+var p256 = &nistCurve[*nistec.P256Point]{
+ name: "P-256",
+ newPoint: nistec.NewP256Point,
+ scalarOrder: p256Order,
+}
+
+var p256Order = []byte{0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51}
+
+// P384 returns a Curve which implements NIST P-384 (FIPS 186-3, section D.2.4),
+// also known as secp384r1.
+//
+// Multiple invocations of this function will return the same value, so it can
+// be used for equality checks and switch statements.
+func P384() Curve { return p384 }
+
+var p384 = &nistCurve[*nistec.P384Point]{
+ name: "P-384",
+ newPoint: nistec.NewP384Point,
+ scalarOrder: p384Order,
+}
+
+var p384Order = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, 0x58, 0x1a, 0xd, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73}
+
+// P521 returns a Curve which implements NIST P-521 (FIPS 186-3, section D.2.5),
+// also known as secp521r1.
+//
+// Multiple invocations of this function will return the same value, so it can
+// be used for equality checks and switch statements.
+func P521() Curve { return p521 }
+
+var p521 = &nistCurve[*nistec.P521Point]{
+ name: "P-521",
+ newPoint: nistec.NewP521Point,
+ scalarOrder: p521Order,
+}
+
+var p521Order = []byte{0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f, 0x96, 0x6b, 0x7f, 0xcc, 0x1, 0x48, 0xf7, 0x9, 0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c, 0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38, 0x64, 0x9}
diff --git a/src/crypto/ecdh/x25519.go b/src/crypto/ecdh/x25519.go
new file mode 100644
index 0000000..21127ff
--- /dev/null
+++ b/src/crypto/ecdh/x25519.go
@@ -0,0 +1,136 @@
+// 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.
+
+package ecdh
+
+import (
+ "crypto/internal/edwards25519/field"
+ "crypto/internal/randutil"
+ "errors"
+ "io"
+)
+
+var (
+ x25519PublicKeySize = 32
+ x25519PrivateKeySize = 32
+ x25519SharedSecretSize = 32
+)
+
+// X25519 returns a Curve which implements the X25519 function over Curve25519
+// (RFC 7748, Section 5).
+//
+// Multiple invocations of this function will return the same value, so it can
+// be used for equality checks and switch statements.
+func X25519() Curve { return x25519 }
+
+var x25519 = &x25519Curve{}
+
+type x25519Curve struct{}
+
+func (c *x25519Curve) String() string {
+ return "X25519"
+}
+
+func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
+ key := make([]byte, x25519PrivateKeySize)
+ randutil.MaybeReadByte(rand)
+ if _, err := io.ReadFull(rand, key); err != nil {
+ return nil, err
+ }
+ return c.NewPrivateKey(key)
+}
+
+func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
+ if len(key) != x25519PrivateKeySize {
+ return nil, errors.New("crypto/ecdh: invalid private key size")
+ }
+ return &PrivateKey{
+ curve: c,
+ privateKey: append([]byte{}, key...),
+ }, nil
+}
+
+func (c *x25519Curve) privateKeyToPublicKey(key *PrivateKey) *PublicKey {
+ if key.curve != c {
+ panic("crypto/ecdh: internal error: converting the wrong key type")
+ }
+ k := &PublicKey{
+ curve: key.curve,
+ publicKey: make([]byte, x25519PublicKeySize),
+ }
+ x25519Basepoint := [32]byte{9}
+ x25519ScalarMult(k.publicKey, key.privateKey, x25519Basepoint[:])
+ return k
+}
+
+func (c *x25519Curve) NewPublicKey(key []byte) (*PublicKey, error) {
+ if len(key) != x25519PublicKeySize {
+ return nil, errors.New("crypto/ecdh: invalid public key")
+ }
+ return &PublicKey{
+ curve: c,
+ publicKey: append([]byte{}, key...),
+ }, nil
+}
+
+func (c *x25519Curve) ECDH(local *PrivateKey, remote *PublicKey) ([]byte, error) {
+ out := make([]byte, x25519SharedSecretSize)
+ x25519ScalarMult(out, local.privateKey, remote.publicKey)
+ if isZero(out) {
+ return nil, errors.New("crypto/ecdh: bad X25519 remote ECDH input: low order point")
+ }
+ return out, nil
+}
+
+func x25519ScalarMult(dst, scalar, point []byte) {
+ var e [32]byte
+
+ copy(e[:], scalar[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element
+ x1.SetBytes(point[:])
+ x2.One()
+ x3.Set(&x1)
+ z3.One()
+
+ swap := 0
+ for pos := 254; pos >= 0; pos-- {
+ b := e[pos/8] >> uint(pos&7)
+ b &= 1
+ swap ^= int(b)
+ x2.Swap(&x3, swap)
+ z2.Swap(&z3, swap)
+ swap = int(b)
+
+ tmp0.Subtract(&x3, &z3)
+ tmp1.Subtract(&x2, &z2)
+ x2.Add(&x2, &z2)
+ z2.Add(&x3, &z3)
+ z3.Multiply(&tmp0, &x2)
+ z2.Multiply(&z2, &tmp1)
+ tmp0.Square(&tmp1)
+ tmp1.Square(&x2)
+ x3.Add(&z3, &z2)
+ z2.Subtract(&z3, &z2)
+ x2.Multiply(&tmp1, &tmp0)
+ tmp1.Subtract(&tmp1, &tmp0)
+ z2.Square(&z2)
+
+ z3.Mult32(&tmp1, 121666)
+ x3.Square(&x3)
+ tmp0.Add(&tmp0, &z3)
+ z3.Multiply(&x1, &z2)
+ z2.Multiply(&tmp1, &tmp0)
+ }
+
+ x2.Swap(&x3, swap)
+ z2.Swap(&z3, swap)
+
+ z2.Invert(&z2)
+ x2.Multiply(&x2, &z2)
+ copy(dst[:], x2.Bytes())
+}
diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go
index 8c0b60b..ababde4 100644
--- a/src/crypto/elliptic/elliptic.go
+++ b/src/crypto/elliptic/elliptic.go
@@ -4,6 +4,10 @@
// Package elliptic implements the standard NIST P-224, P-256, P-384, and P-521
// elliptic curves over prime fields.
+//
+// Direct use of this package is deprecated, beyond the P224(), P256(), P384(),
+// and P521() values necessary to use the crypto/ecdsa package. Most other uses
+// should migrate to the more efficient and safer crypto/ecdh package.
package elliptic
import (
@@ -20,19 +24,43 @@
// Note that the conventional point at infinity (0, 0) is not considered on the
// curve, although it can be returned by Add, Double, ScalarMult, or
// ScalarBaseMult (but not the Unmarshal or UnmarshalCompressed functions).
+//
+// Using Curve implementations besides those returned by P224(), P256(), P384(),
+// and P521() is deprecated.
type Curve interface {
// Params returns the parameters for the curve.
Params() *CurveParams
+
// IsOnCurve reports whether the given (x,y) lies on the curve.
+ //
+ // Deprecated: this is a low-level unsafe API. For ECDH, use the crypto/ecdh
+ // package. The NewPublicKey methods of NIST curves in crypto/ecdh accept
+ // the same encoding as the Unmarshal function, and perform on-curve checks.
IsOnCurve(x, y *big.Int) bool
- // Add returns the sum of (x1,y1) and (x2,y2)
+
+ // Add returns the sum of (x1,y1) and (x2,y2).
+ //
+ // Deprecated: this is a low-level unsafe API.
Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int)
- // Double returns 2*(x,y)
+
+ // Double returns 2*(x,y).
+ //
+ // Deprecated: this is a low-level unsafe API.
Double(x1, y1 *big.Int) (x, y *big.Int)
- // ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
+
+ // ScalarMult returns k*(x,y) where k is an integer in big-endian form.
+ //
+ // Deprecated: this is a low-level unsafe API. For ECDH, use the crypto/ecdh
+ // package. Most uses of ScalarMult can be replaced by a call to the ECDH
+ // methods of NIST curves in crypto/ecdh.
ScalarMult(x1, y1 *big.Int, k []byte) (x, y *big.Int)
+
// ScalarBaseMult returns k*G, where G is the base point of the group
// and k is an integer in big-endian form.
+ //
+ // Deprecated: this is a low-level unsafe API. For ECDH, use the crypto/ecdh
+ // package. Most uses of ScalarBaseMult can be replaced by a call to the
+ // PrivateKey.PublicKey method in crypto/ecdh.
ScalarBaseMult(k []byte) (x, y *big.Int)
}
@@ -40,6 +68,9 @@
// GenerateKey returns a public/private key pair. The private key is
// generated using the given reader, which must return random data.
+//
+// Deprecated: for ECDH, use the GenerateKey methods of the crypto/ecdh package;
+// for ECDSA, use the GenerateKey function of the crypto/ecdsa package.
func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err error) {
N := curve.Params().N
bitSize := N.BitLen()
@@ -71,6 +102,9 @@
// Marshal converts a point on the curve into the uncompressed form specified in
// SEC 1, Version 2.0, Section 2.3.3. If the point is not on the curve (or is
// the conventional point at infinity), the behavior is undefined.
+//
+// Deprecated: for ECDH, use the crypto/ecdh package. This function returns an
+// encoding equivalent to that of PublicKey.Bytes in crypto/ecdh.
func Marshal(curve Curve, x, y *big.Int) []byte {
panicIfNotOnCurve(curve, x, y)
@@ -112,6 +146,9 @@
// Unmarshal converts a point, serialized by Marshal, into an x, y pair. It is
// an error if the point is not in uncompressed form, is not on the curve, or is
// the point at infinity. On error, x = nil.
+//
+// Deprecated: for ECDH, use the crypto/ecdh package. This function accepts an
+// encoding equivalent to that of the NewPublicKey methods in crypto/ecdh.
func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
if c, ok := curve.(unmarshaler); ok {
return c.Unmarshal(data)
diff --git a/src/crypto/elliptic/params.go b/src/crypto/elliptic/params.go
index 0ed929d..1ae57fa 100644
--- a/src/crypto/elliptic/params.go
+++ b/src/crypto/elliptic/params.go
@@ -8,6 +8,10 @@
// CurveParams contains the parameters of an elliptic curve and also provides
// a generic, non-constant time implementation of Curve.
+//
+// The generic Curve implementation is deprecated, and using custom curves
+// (those not returned by P224(), P256(), P384(), and P521()) is not guaranteed
+// to provide any security property.
type CurveParams struct {
P *big.Int // the order of the underlying field
N *big.Int // the order of the base point
@@ -43,6 +47,12 @@
return x3
}
+// IsOnCurve implements Curve.IsOnCurve.
+//
+// Deprecated: the CurveParams methods are deprecated and are not guaranteed to
+// provide any security property. For ECDH, use the crypto/ecdh package.
+// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
+// from P224(), P256(), P384(), or P521().
func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
@@ -91,6 +101,12 @@
return
}
+// Add implements Curve.Add.
+//
+// Deprecated: the CurveParams methods are deprecated and are not guaranteed to
+// provide any security property. For ECDH, use the crypto/ecdh package.
+// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
+// from P224(), P256(), P384(), or P521().
func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
@@ -183,6 +199,12 @@
return x3, y3, z3
}
+// Double implements Curve.Double.
+//
+// Deprecated: the CurveParams methods are deprecated and are not guaranteed to
+// provide any security property. For ECDH, use the crypto/ecdh package.
+// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
+// from P224(), P256(), P384(), or P521().
func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
@@ -256,6 +278,12 @@
return x3, y3, z3
}
+// ScalarMult implements Curve.ScalarMult.
+//
+// Deprecated: the CurveParams methods are deprecated and are not guaranteed to
+// provide any security property. For ECDH, use the crypto/ecdh package.
+// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
+// from P224(), P256(), P384(), or P521().
func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
@@ -280,6 +308,12 @@
return curve.affineFromJacobian(x, y, z)
}
+// ScalarBaseMult implements Curve.ScalarBaseMult.
+//
+// Deprecated: the CurveParams methods are deprecated and are not guaranteed to
+// provide any security property. For ECDH, use the crypto/ecdh package.
+// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
+// from P224(), P256(), P384(), or P521().
func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
diff --git a/src/crypto/internal/nistec/generate.go b/src/crypto/internal/nistec/generate.go
index 9e82693..2c42eb9 100644
--- a/src/crypto/internal/nistec/generate.go
+++ b/src/crypto/internal/nistec/generate.go
@@ -303,6 +303,26 @@
return buf
}
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *{{.P}}Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [{{.p}}ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *{{.P}}Point) bytesX(out *[{{.p}}ElementLength]byte) ([]byte, error) {
+ if p.z.IsZero() == 1 {
+ return nil, errors.New("{{.P}} point is the point at infinity")
+ }
+
+ zinv := new({{.Element}}).Invert(p.z)
+ x := new({{.Element}}).Mul(p.x, zinv)
+
+ return append(out[:0], x.Bytes()...), nil
+}
+
// BytesCompressed returns the compressed or infinity encoding of p, as
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
// point at infinity is shorter than all other encodings.
diff --git a/src/crypto/internal/nistec/p224.go b/src/crypto/internal/nistec/p224.go
index 8d236b3..18b43ea 100644
--- a/src/crypto/internal/nistec/p224.go
+++ b/src/crypto/internal/nistec/p224.go
@@ -159,6 +159,26 @@
return buf
}
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *P224Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p224ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *P224Point) bytesX(out *[p224ElementLength]byte) ([]byte, error) {
+ if p.z.IsZero() == 1 {
+ return nil, errors.New("P224 point is the point at infinity")
+ }
+
+ zinv := new(fiat.P224Element).Invert(p.z)
+ x := new(fiat.P224Element).Mul(p.x, zinv)
+
+ return append(out[:0], x.Bytes()...), nil
+}
+
// BytesCompressed returns the compressed or infinity encoding of p, as
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
// point at infinity is shorter than all other encodings.
diff --git a/src/crypto/internal/nistec/p256.go b/src/crypto/internal/nistec/p256.go
index 353b428..c836c2a 100644
--- a/src/crypto/internal/nistec/p256.go
+++ b/src/crypto/internal/nistec/p256.go
@@ -161,6 +161,26 @@
return buf
}
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *P256Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p256ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *P256Point) bytesX(out *[p256ElementLength]byte) ([]byte, error) {
+ if p.z.IsZero() == 1 {
+ return nil, errors.New("P256 point is the point at infinity")
+ }
+
+ zinv := new(fiat.P256Element).Invert(p.z)
+ x := new(fiat.P256Element).Mul(p.x, zinv)
+
+ return append(out[:0], x.Bytes()...), nil
+}
+
// BytesCompressed returns the compressed or infinity encoding of p, as
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
// point at infinity is shorter than all other encodings.
diff --git a/src/crypto/internal/nistec/p256_asm.go b/src/crypto/internal/nistec/p256_asm.go
index bc443ba..90f0279 100644
--- a/src/crypto/internal/nistec/p256_asm.go
+++ b/src/crypto/internal/nistec/p256_asm.go
@@ -479,6 +479,30 @@
p256FromMont(y, y)
}
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *P256Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p256ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *P256Point) bytesX(out *[p256ElementLength]byte) ([]byte, error) {
+ if p.isInfinity() == 1 {
+ return nil, errors.New("P256 point is the point at infinity")
+ }
+
+ x := new(p256Element)
+ p256Inverse(x, &p.z)
+ p256Sqr(x, x, 1)
+ p256Mul(x, &p.x, x)
+ p256FromMont(x, x)
+ p256LittleToBig((*[32]byte)(out[:]), x)
+
+ return out[:], nil
+}
+
// BytesCompressed returns the compressed or infinity encoding of p, as
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
// point at infinity is shorter than all other encodings.
diff --git a/src/crypto/internal/nistec/p384.go b/src/crypto/internal/nistec/p384.go
index 1a855cb..40bff73 100644
--- a/src/crypto/internal/nistec/p384.go
+++ b/src/crypto/internal/nistec/p384.go
@@ -159,6 +159,26 @@
return buf
}
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *P384Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p384ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *P384Point) bytesX(out *[p384ElementLength]byte) ([]byte, error) {
+ if p.z.IsZero() == 1 {
+ return nil, errors.New("P384 point is the point at infinity")
+ }
+
+ zinv := new(fiat.P384Element).Invert(p.z)
+ x := new(fiat.P384Element).Mul(p.x, zinv)
+
+ return append(out[:0], x.Bytes()...), nil
+}
+
// BytesCompressed returns the compressed or infinity encoding of p, as
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
// point at infinity is shorter than all other encodings.
diff --git a/src/crypto/internal/nistec/p521.go b/src/crypto/internal/nistec/p521.go
index f285d575..b137d27 100644
--- a/src/crypto/internal/nistec/p521.go
+++ b/src/crypto/internal/nistec/p521.go
@@ -159,6 +159,26 @@
return buf
}
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *P521Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p521ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *P521Point) bytesX(out *[p521ElementLength]byte) ([]byte, error) {
+ if p.z.IsZero() == 1 {
+ return nil, errors.New("P521 point is the point at infinity")
+ }
+
+ zinv := new(fiat.P521Element).Invert(p.z)
+ x := new(fiat.P521Element).Mul(p.x, zinv)
+
+ return append(out[:0], x.Bytes()...), nil
+}
+
// BytesCompressed returns the compressed or infinity encoding of p, as
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
// point at infinity is shorter than all other encodings.
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index e07cf79..f5e24cb 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -8,6 +8,7 @@
"bytes"
"context"
"crypto"
+ "crypto/ecdh"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
@@ -35,7 +36,7 @@
var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme
-func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
+func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) {
config := c.config
if len(config.ServerName) == 0 && !config.InsecureSkipVerify {
return nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
@@ -124,7 +125,7 @@
hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
}
- var params ecdheParameters
+ var key *ecdh.PrivateKey
if hello.supportedVersions[0] == VersionTLS13 {
if hasAESGCMHardwareSupport {
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
@@ -133,17 +134,17 @@
}
curveID := config.curvePreferences()[0]
- if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
+ if _, ok := curveForCurveID(curveID); !ok {
return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve")
}
- params, err = generateECDHEParameters(config.rand(), curveID)
+ key, err = generateECDHEKey(config.rand(), curveID)
if err != nil {
return nil, nil, err
}
- hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}}
+ hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}}
}
- return hello, params, nil
+ return hello, key, nil
}
func (c *Conn) clientHandshake(ctx context.Context) (err error) {
@@ -155,7 +156,7 @@
// need to be reset.
c.didResume = false
- hello, ecdheParams, err := c.makeClientHello()
+ hello, ecdheKey, err := c.makeClientHello()
if err != nil {
return err
}
@@ -213,7 +214,7 @@
ctx: ctx,
serverHello: serverHello,
hello: hello,
- ecdheParams: ecdheParams,
+ ecdheKey: ecdheKey,
session: session,
earlySecret: earlySecret,
binderKey: binderKey,
diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go
index ac783af..12ff3a4 100644
--- a/src/crypto/tls/handshake_client_tls13.go
+++ b/src/crypto/tls/handshake_client_tls13.go
@@ -8,6 +8,7 @@
"bytes"
"context"
"crypto"
+ "crypto/ecdh"
"crypto/hmac"
"crypto/rsa"
"errors"
@@ -20,7 +21,7 @@
ctx context.Context
serverHello *serverHelloMsg
hello *clientHelloMsg
- ecdheParams ecdheParameters
+ ecdheKey *ecdh.PrivateKey
session *ClientSessionState
earlySecret []byte
@@ -35,7 +36,7 @@
trafficSecret []byte // client_application_traffic_secret_0
}
-// handshake requires hs.c, hs.hello, hs.serverHello, hs.ecdheParams, and,
+// handshake requires hs.c, hs.hello, hs.serverHello, hs.ecdheKey, and,
// optionally, hs.session, hs.earlySecret and hs.binderKey to be set.
func (hs *clientHandshakeStateTLS13) handshake() error {
c := hs.c
@@ -52,7 +53,7 @@
}
// Consistency check on the presence of a keyShare and its parameters.
- if hs.ecdheParams == nil || len(hs.hello.keyShares) != 1 {
+ if hs.ecdheKey == nil || len(hs.hello.keyShares) != 1 {
return c.sendAlert(alertInternalError)
}
@@ -221,21 +222,21 @@
c.sendAlert(alertIllegalParameter)
return errors.New("tls: server selected unsupported group")
}
- if hs.ecdheParams.CurveID() == curveID {
+ if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); sentID == curveID {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
}
- if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
+ if _, ok := curveForCurveID(curveID); !ok {
c.sendAlert(alertInternalError)
return errors.New("tls: CurvePreferences includes unsupported curve")
}
- params, err := generateECDHEParameters(c.config.rand(), curveID)
+ key, err := generateECDHEKey(c.config.rand(), curveID)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
- hs.ecdheParams = params
- hs.hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}}
+ hs.ecdheKey = key
+ hs.hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}}
}
hs.hello.raw = nil
@@ -309,7 +310,7 @@
c.sendAlert(alertIllegalParameter)
return errors.New("tls: server did not send a key share")
}
- if hs.serverHello.serverShare.group != hs.ecdheParams.CurveID() {
+ if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); hs.serverHello.serverShare.group != sentID {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: server selected unsupported group")
}
@@ -347,8 +348,13 @@
func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
c := hs.c
- sharedKey := hs.ecdheParams.SharedKey(hs.serverHello.serverShare.data)
- if sharedKey == nil {
+ peerKey, err := hs.ecdheKey.Curve().NewPublicKey(hs.serverHello.serverShare.data)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid server key share")
+ }
+ sharedKey, err := hs.ecdheKey.Curve().ECDH(hs.ecdheKey, peerKey)
+ if err != nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid server key share")
}
@@ -367,7 +373,7 @@
serverHandshakeTrafficLabel, hs.transcript)
c.in.setTrafficSecret(hs.suite, serverSecret)
- err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret)
+ err = c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret)
if err != nil {
c.sendAlert(alertInternalError)
return err
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
index 5ff5270..863cb20 100644
--- a/src/crypto/tls/handshake_server_test.go
+++ b/src/crypto/tls/handshake_server_test.go
@@ -8,7 +8,9 @@
"bytes"
"context"
"crypto"
+ "crypto/ecdh"
"crypto/elliptic"
+ "crypto/rand"
"crypto/x509"
"encoding/pem"
"errors"
@@ -22,8 +24,6 @@
"strings"
"testing"
"time"
-
- "golang.org/x/crypto/curve25519"
)
func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
@@ -1909,6 +1909,7 @@
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
hasAESGCMHardwareSupport = tc.serverHasAESGCM
+ pk, _ := ecdh.X25519().GenerateKey(rand.Reader)
hs := &serverHandshakeStateTLS13{
c: &Conn{
config: &Config{},
@@ -1918,7 +1919,7 @@
cipherSuites: tc.clientCiphers,
supportedVersions: []uint16{VersionTLS13},
compressionMethods: []uint8{compressionNone},
- keyShares: []keyShare{{group: X25519, data: curve25519.Basepoint}},
+ keyShares: []keyShare{{group: X25519, data: pk.PublicKey().Bytes()}},
},
}
diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go
index 712f358..9b7356a 100644
--- a/src/crypto/tls/handshake_server_tls13.go
+++ b/src/crypto/tls/handshake_server_tls13.go
@@ -205,18 +205,23 @@
clientKeyShare = &hs.clientHello.keyShares[0]
}
- if _, ok := curveForCurveID(selectedGroup); selectedGroup != X25519 && !ok {
+ if _, ok := curveForCurveID(selectedGroup); !ok {
c.sendAlert(alertInternalError)
return errors.New("tls: CurvePreferences includes unsupported curve")
}
- params, err := generateECDHEParameters(c.config.rand(), selectedGroup)
+ key, err := generateECDHEKey(c.config.rand(), selectedGroup)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
- hs.hello.serverShare = keyShare{group: selectedGroup, data: params.PublicKey()}
- hs.sharedKey = params.SharedKey(clientKeyShare.data)
- if hs.sharedKey == nil {
+ hs.hello.serverShare = keyShare{group: selectedGroup, data: key.PublicKey().Bytes()}
+ peerKey, err := key.Curve().NewPublicKey(clientKeyShare.data)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid client key share")
+ }
+ hs.sharedKey, err = key.Curve().ECDH(key, peerKey)
+ if err != nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid client key share")
}
diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go
index c28a64f..027060d 100644
--- a/src/crypto/tls/key_agreement.go
+++ b/src/crypto/tls/key_agreement.go
@@ -6,6 +6,7 @@
import (
"crypto"
+ "crypto/ecdh"
"crypto/md5"
"crypto/rsa"
"crypto/sha1"
@@ -157,7 +158,7 @@
type ecdheKeyAgreement struct {
version uint16
isRSA bool
- params ecdheParameters
+ key *ecdh.PrivateKey
// ckx and preMasterSecret are generated in processServerKeyExchange
// and returned in generateClientKeyExchange.
@@ -177,18 +178,18 @@
if curveID == 0 {
return nil, errors.New("tls: no supported elliptic curves offered")
}
- if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
+ if _, ok := curveForCurveID(curveID); !ok {
return nil, errors.New("tls: CurvePreferences includes unsupported curve")
}
- params, err := generateECDHEParameters(config.rand(), curveID)
+ key, err := generateECDHEKey(config.rand(), curveID)
if err != nil {
return nil, err
}
- ka.params = params
+ ka.key = key
// See RFC 4492, Section 5.4.
- ecdhePublic := params.PublicKey()
+ ecdhePublic := key.PublicKey().Bytes()
serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic))
serverECDHEParams[0] = 3 // named curve
serverECDHEParams[1] = byte(curveID >> 8)
@@ -259,8 +260,12 @@
return nil, errClientKeyExchange
}
- preMasterSecret := ka.params.SharedKey(ckx.ciphertext[1:])
- if preMasterSecret == nil {
+ peerKey, err := ka.key.Curve().NewPublicKey(ckx.ciphertext[1:])
+ if err != nil {
+ return nil, errClientKeyExchange
+ }
+ preMasterSecret, err := ka.key.Curve().ECDH(ka.key, peerKey)
+ if err != nil {
return nil, errClientKeyExchange
}
@@ -288,22 +293,26 @@
return errServerKeyExchange
}
- if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
+ if _, ok := curveForCurveID(curveID); !ok {
return errors.New("tls: server selected unsupported curve")
}
- params, err := generateECDHEParameters(config.rand(), curveID)
+ key, err := generateECDHEKey(config.rand(), curveID)
if err != nil {
return err
}
- ka.params = params
+ ka.key = key
- ka.preMasterSecret = params.SharedKey(publicKey)
- if ka.preMasterSecret == nil {
+ peerKey, err := key.Curve().NewPublicKey(publicKey)
+ if err != nil {
+ return errServerKeyExchange
+ }
+ ka.preMasterSecret, err = key.Curve().ECDH(key, peerKey)
+ if err != nil {
return errServerKeyExchange
}
- ourPublicKey := params.PublicKey()
+ ourPublicKey := key.PublicKey().Bytes()
ka.ckx = new(clientKeyExchangeMsg)
ka.ckx.ciphertext = make([]byte, 1+len(ourPublicKey))
ka.ckx.ciphertext[0] = byte(len(ourPublicKey))
diff --git a/src/crypto/tls/key_schedule.go b/src/crypto/tls/key_schedule.go
index 3140169..af1f2bd 100644
--- a/src/crypto/tls/key_schedule.go
+++ b/src/crypto/tls/key_schedule.go
@@ -5,15 +5,13 @@
package tls
import (
- "crypto/elliptic"
+ "crypto/ecdh"
"crypto/hmac"
"errors"
"hash"
"io"
- "math/big"
"golang.org/x/crypto/cryptobyte"
- "golang.org/x/crypto/curve25519"
"golang.org/x/crypto/hkdf"
)
@@ -101,99 +99,43 @@
}
}
-// ecdheParameters implements Diffie-Hellman with either NIST curves or X25519,
+// generateECDHEParameters returns a PrivateKey that implements Diffie-Hellman
// according to RFC 8446, Section 4.2.8.2.
-type ecdheParameters interface {
- CurveID() CurveID
- PublicKey() []byte
- SharedKey(peerPublicKey []byte) []byte
-}
-
-func generateECDHEParameters(rand io.Reader, curveID CurveID) (ecdheParameters, error) {
- if curveID == X25519 {
- privateKey := make([]byte, curve25519.ScalarSize)
- if _, err := io.ReadFull(rand, privateKey); err != nil {
- return nil, err
- }
- publicKey, err := curve25519.X25519(privateKey, curve25519.Basepoint)
- if err != nil {
- return nil, err
- }
- return &x25519Parameters{privateKey: privateKey, publicKey: publicKey}, nil
- }
-
+func generateECDHEKey(rand io.Reader, curveID CurveID) (*ecdh.PrivateKey, error) {
curve, ok := curveForCurveID(curveID)
if !ok {
return nil, errors.New("tls: internal error: unsupported curve")
}
- p := &nistParameters{curveID: curveID}
- var err error
- p.privateKey, p.x, p.y, err = elliptic.GenerateKey(curve, rand)
- if err != nil {
- return nil, err
- }
- return p, nil
+ return curve.GenerateKey(rand)
}
-func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
+func curveForCurveID(id CurveID) (ecdh.Curve, bool) {
switch id {
+ case X25519:
+ return ecdh.X25519(), true
case CurveP256:
- return elliptic.P256(), true
+ return ecdh.P256(), true
case CurveP384:
- return elliptic.P384(), true
+ return ecdh.P384(), true
case CurveP521:
- return elliptic.P521(), true
+ return ecdh.P521(), true
default:
return nil, false
}
}
-type nistParameters struct {
- privateKey []byte
- x, y *big.Int // public key
- curveID CurveID
-}
-
-func (p *nistParameters) CurveID() CurveID {
- return p.curveID
-}
-
-func (p *nistParameters) PublicKey() []byte {
- curve, _ := curveForCurveID(p.curveID)
- return elliptic.Marshal(curve, p.x, p.y)
-}
-
-func (p *nistParameters) SharedKey(peerPublicKey []byte) []byte {
- curve, _ := curveForCurveID(p.curveID)
- // Unmarshal also checks whether the given point is on the curve.
- x, y := elliptic.Unmarshal(curve, peerPublicKey)
- if x == nil {
- return nil
+func curveIDForCurve(curve ecdh.Curve) (CurveID, bool) {
+ switch curve {
+ case ecdh.X25519():
+ return X25519, true
+ case ecdh.P256():
+ return CurveP256, true
+ case ecdh.P384():
+ return CurveP384, true
+ case ecdh.P521():
+ return CurveP521, true
+ default:
+ return 0, false
}
-
- xShared, _ := curve.ScalarMult(x, y, p.privateKey)
- sharedKey := make([]byte, (curve.Params().BitSize+7)/8)
- return xShared.FillBytes(sharedKey)
-}
-
-type x25519Parameters struct {
- privateKey []byte
- publicKey []byte
-}
-
-func (p *x25519Parameters) CurveID() CurveID {
- return X25519
-}
-
-func (p *x25519Parameters) PublicKey() []byte {
- return p.publicKey[:]
-}
-
-func (p *x25519Parameters) SharedKey(peerPublicKey []byte) []byte {
- sharedKey, err := curve25519.X25519(p.privateKey, peerPublicKey)
- if err != nil {
- return nil
- }
- return sharedKey
}
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 496771b..e911f2f 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -382,10 +382,11 @@
< crypto
< crypto/subtle
< crypto/internal/subtle
+ < crypto/internal/randutil
< crypto/internal/nistec/fiat
< crypto/internal/nistec
- < crypto/internal/edwards25519/field, golang.org/x/crypto/curve25519/internal/field
- < crypto/internal/edwards25519
+ < crypto/internal/edwards25519/field
+ < crypto/internal/edwards25519, crypto/ecdh
< crypto/cipher;
crypto/cipher,
@@ -399,15 +400,13 @@
CGO, fmt, net !< CRYPTO;
# CRYPTO-MATH is core bignum-based crypto - no cgo, net; fmt now ok.
- CRYPTO, FMT, math/big, embed
+ CRYPTO, FMT, math/big
< crypto/internal/boring/bbig
- < crypto/internal/randutil
< crypto/rand
< crypto/ed25519
< encoding/asn1
< golang.org/x/crypto/cryptobyte/asn1
< golang.org/x/crypto/cryptobyte
- < golang.org/x/crypto/curve25519
< crypto/dsa, crypto/elliptic, crypto/rsa
< crypto/ecdsa
< CRYPTO-MATH;
diff --git a/src/vendor/golang.org/x/crypto/curve25519/curve25519.go b/src/vendor/golang.org/x/crypto/curve25519/curve25519.go
deleted file mode 100644
index bc62161..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/curve25519.go
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package curve25519 provides an implementation of the X25519 function, which
-// performs scalar multiplication on the elliptic curve known as Curve25519.
-// See RFC 7748.
-package curve25519 // import "golang.org/x/crypto/curve25519"
-
-import (
- "crypto/subtle"
- "errors"
- "strconv"
-
- "golang.org/x/crypto/curve25519/internal/field"
-)
-
-// ScalarMult sets dst to the product scalar * point.
-//
-// Deprecated: when provided a low-order point, ScalarMult will set dst to all
-// zeroes, irrespective of the scalar. Instead, use the X25519 function, which
-// will return an error.
-func ScalarMult(dst, scalar, point *[32]byte) {
- var e [32]byte
-
- copy(e[:], scalar[:])
- e[0] &= 248
- e[31] &= 127
- e[31] |= 64
-
- var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element
- x1.SetBytes(point[:])
- x2.One()
- x3.Set(&x1)
- z3.One()
-
- swap := 0
- for pos := 254; pos >= 0; pos-- {
- b := e[pos/8] >> uint(pos&7)
- b &= 1
- swap ^= int(b)
- x2.Swap(&x3, swap)
- z2.Swap(&z3, swap)
- swap = int(b)
-
- tmp0.Subtract(&x3, &z3)
- tmp1.Subtract(&x2, &z2)
- x2.Add(&x2, &z2)
- z2.Add(&x3, &z3)
- z3.Multiply(&tmp0, &x2)
- z2.Multiply(&z2, &tmp1)
- tmp0.Square(&tmp1)
- tmp1.Square(&x2)
- x3.Add(&z3, &z2)
- z2.Subtract(&z3, &z2)
- x2.Multiply(&tmp1, &tmp0)
- tmp1.Subtract(&tmp1, &tmp0)
- z2.Square(&z2)
-
- z3.Mult32(&tmp1, 121666)
- x3.Square(&x3)
- tmp0.Add(&tmp0, &z3)
- z3.Multiply(&x1, &z2)
- z2.Multiply(&tmp1, &tmp0)
- }
-
- x2.Swap(&x3, swap)
- z2.Swap(&z3, swap)
-
- z2.Invert(&z2)
- x2.Multiply(&x2, &z2)
- copy(dst[:], x2.Bytes())
-}
-
-// ScalarBaseMult sets dst to the product scalar * base where base is the
-// standard generator.
-//
-// It is recommended to use the X25519 function with Basepoint instead, as
-// copying into fixed size arrays can lead to unexpected bugs.
-func ScalarBaseMult(dst, scalar *[32]byte) {
- ScalarMult(dst, scalar, &basePoint)
-}
-
-const (
- // ScalarSize is the size of the scalar input to X25519.
- ScalarSize = 32
- // PointSize is the size of the point input to X25519.
- PointSize = 32
-)
-
-// Basepoint is the canonical Curve25519 generator.
-var Basepoint []byte
-
-var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-
-func init() { Basepoint = basePoint[:] }
-
-func checkBasepoint() {
- if subtle.ConstantTimeCompare(Basepoint, []byte{
- 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- }) != 1 {
- panic("curve25519: global Basepoint value was modified")
- }
-}
-
-// X25519 returns the result of the scalar multiplication (scalar * point),
-// according to RFC 7748, Section 5. scalar, point and the return value are
-// slices of 32 bytes.
-//
-// scalar can be generated at random, for example with crypto/rand. point should
-// be either Basepoint or the output of another X25519 call.
-//
-// If point is Basepoint (but not if it's a different slice with the same
-// contents) a precomputed implementation might be used for performance.
-func X25519(scalar, point []byte) ([]byte, error) {
- // Outline the body of function, to let the allocation be inlined in the
- // caller, and possibly avoid escaping to the heap.
- var dst [32]byte
- return x25519(&dst, scalar, point)
-}
-
-func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
- var in [32]byte
- if l := len(scalar); l != 32 {
- return nil, errors.New("bad scalar length: " + strconv.Itoa(l) + ", expected 32")
- }
- if l := len(point); l != 32 {
- return nil, errors.New("bad point length: " + strconv.Itoa(l) + ", expected 32")
- }
- copy(in[:], scalar)
- if &point[0] == &Basepoint[0] {
- checkBasepoint()
- ScalarBaseMult(dst, &in)
- } else {
- var base, zero [32]byte
- copy(base[:], point)
- ScalarMult(dst, &in, &base)
- if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 {
- return nil, errors.New("bad input point: low order point")
- }
- }
- return dst[:], nil
-}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/README b/src/vendor/golang.org/x/crypto/curve25519/internal/field/README
deleted file mode 100644
index e25bca7..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/internal/field/README
+++ /dev/null
@@ -1,7 +0,0 @@
-This package is kept in sync with crypto/ed25519/internal/edwards25519/field in
-the standard library.
-
-If there are any changes in the standard library that need to be synced to this
-package, run sync.sh. It will not overwrite any local changes made since the
-previous sync, so it's ok to land changes in this package first, and then sync
-to the standard library later.
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go
deleted file mode 100644
index ca841ad..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go
+++ /dev/null
@@ -1,416 +0,0 @@
-// Copyright (c) 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.
-
-// Package field implements fast arithmetic modulo 2^255-19.
-package field
-
-import (
- "crypto/subtle"
- "encoding/binary"
- "math/bits"
-)
-
-// Element represents an element of the field GF(2^255-19). Note that this
-// is not a cryptographically secure group, and should only be used to interact
-// with edwards25519.Point coordinates.
-//
-// This type works similarly to math/big.Int, and all arguments and receivers
-// are allowed to alias.
-//
-// The zero value is a valid zero element.
-type Element struct {
- // An element t represents the integer
- // t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
- //
- // Between operations, all limbs are expected to be lower than 2^52.
- l0 uint64
- l1 uint64
- l2 uint64
- l3 uint64
- l4 uint64
-}
-
-const maskLow51Bits uint64 = (1 << 51) - 1
-
-var feZero = &Element{0, 0, 0, 0, 0}
-
-// Zero sets v = 0, and returns v.
-func (v *Element) Zero() *Element {
- *v = *feZero
- return v
-}
-
-var feOne = &Element{1, 0, 0, 0, 0}
-
-// One sets v = 1, and returns v.
-func (v *Element) One() *Element {
- *v = *feOne
- return v
-}
-
-// reduce reduces v modulo 2^255 - 19 and returns it.
-func (v *Element) reduce() *Element {
- v.carryPropagate()
-
- // After the light reduction we now have a field element representation
- // v < 2^255 + 2^13 * 19, but need v < 2^255 - 19.
-
- // If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
- // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
- c := (v.l0 + 19) >> 51
- c = (v.l1 + c) >> 51
- c = (v.l2 + c) >> 51
- c = (v.l3 + c) >> 51
- c = (v.l4 + c) >> 51
-
- // If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
- // effectively applying the reduction identity to the carry.
- v.l0 += 19 * c
-
- v.l1 += v.l0 >> 51
- v.l0 = v.l0 & maskLow51Bits
- v.l2 += v.l1 >> 51
- v.l1 = v.l1 & maskLow51Bits
- v.l3 += v.l2 >> 51
- v.l2 = v.l2 & maskLow51Bits
- v.l4 += v.l3 >> 51
- v.l3 = v.l3 & maskLow51Bits
- // no additional carry
- v.l4 = v.l4 & maskLow51Bits
-
- return v
-}
-
-// Add sets v = a + b, and returns v.
-func (v *Element) Add(a, b *Element) *Element {
- v.l0 = a.l0 + b.l0
- v.l1 = a.l1 + b.l1
- v.l2 = a.l2 + b.l2
- v.l3 = a.l3 + b.l3
- v.l4 = a.l4 + b.l4
- // Using the generic implementation here is actually faster than the
- // assembly. Probably because the body of this function is so simple that
- // the compiler can figure out better optimizations by inlining the carry
- // propagation. TODO
- return v.carryPropagateGeneric()
-}
-
-// Subtract sets v = a - b, and returns v.
-func (v *Element) Subtract(a, b *Element) *Element {
- // We first add 2 * p, to guarantee the subtraction won't underflow, and
- // then subtract b (which can be up to 2^255 + 2^13 * 19).
- v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
- v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
- v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
- v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
- v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
- return v.carryPropagate()
-}
-
-// Negate sets v = -a, and returns v.
-func (v *Element) Negate(a *Element) *Element {
- return v.Subtract(feZero, a)
-}
-
-// Invert sets v = 1/z mod p, and returns v.
-//
-// If z == 0, Invert returns v = 0.
-func (v *Element) Invert(z *Element) *Element {
- // Inversion is implemented as exponentiation with exponent p − 2. It uses the
- // same sequence of 255 squarings and 11 multiplications as [Curve25519].
- var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element
-
- z2.Square(z) // 2
- t.Square(&z2) // 4
- t.Square(&t) // 8
- z9.Multiply(&t, z) // 9
- z11.Multiply(&z9, &z2) // 11
- t.Square(&z11) // 22
- z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0
-
- t.Square(&z2_5_0) // 2^6 - 2^1
- for i := 0; i < 4; i++ {
- t.Square(&t) // 2^10 - 2^5
- }
- z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0
-
- t.Square(&z2_10_0) // 2^11 - 2^1
- for i := 0; i < 9; i++ {
- t.Square(&t) // 2^20 - 2^10
- }
- z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0
-
- t.Square(&z2_20_0) // 2^21 - 2^1
- for i := 0; i < 19; i++ {
- t.Square(&t) // 2^40 - 2^20
- }
- t.Multiply(&t, &z2_20_0) // 2^40 - 2^0
-
- t.Square(&t) // 2^41 - 2^1
- for i := 0; i < 9; i++ {
- t.Square(&t) // 2^50 - 2^10
- }
- z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0
-
- t.Square(&z2_50_0) // 2^51 - 2^1
- for i := 0; i < 49; i++ {
- t.Square(&t) // 2^100 - 2^50
- }
- z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0
-
- t.Square(&z2_100_0) // 2^101 - 2^1
- for i := 0; i < 99; i++ {
- t.Square(&t) // 2^200 - 2^100
- }
- t.Multiply(&t, &z2_100_0) // 2^200 - 2^0
-
- t.Square(&t) // 2^201 - 2^1
- for i := 0; i < 49; i++ {
- t.Square(&t) // 2^250 - 2^50
- }
- t.Multiply(&t, &z2_50_0) // 2^250 - 2^0
-
- t.Square(&t) // 2^251 - 2^1
- t.Square(&t) // 2^252 - 2^2
- t.Square(&t) // 2^253 - 2^3
- t.Square(&t) // 2^254 - 2^4
- t.Square(&t) // 2^255 - 2^5
-
- return v.Multiply(&t, &z11) // 2^255 - 21
-}
-
-// Set sets v = a, and returns v.
-func (v *Element) Set(a *Element) *Element {
- *v = *a
- return v
-}
-
-// SetBytes sets v to x, which must be a 32-byte little-endian encoding.
-//
-// Consistent with RFC 7748, the most significant bit (the high bit of the
-// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1)
-// are accepted. Note that this is laxer than specified by RFC 8032.
-func (v *Element) SetBytes(x []byte) *Element {
- if len(x) != 32 {
- panic("edwards25519: invalid field element input size")
- }
-
- // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
- v.l0 = binary.LittleEndian.Uint64(x[0:8])
- v.l0 &= maskLow51Bits
- // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
- v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
- v.l1 &= maskLow51Bits
- // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
- v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
- v.l2 &= maskLow51Bits
- // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
- v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1
- v.l3 &= maskLow51Bits
- // Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51).
- // Note: not bytes 25:33, shift 4, to avoid overread.
- v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12
- v.l4 &= maskLow51Bits
-
- return v
-}
-
-// Bytes returns the canonical 32-byte little-endian encoding of v.
-func (v *Element) Bytes() []byte {
- // This function is outlined to make the allocations inline in the caller
- // rather than happen on the heap.
- var out [32]byte
- return v.bytes(&out)
-}
-
-func (v *Element) bytes(out *[32]byte) []byte {
- t := *v
- t.reduce()
-
- var buf [8]byte
- for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
- bitsOffset := i * 51
- binary.LittleEndian.PutUint64(buf[:], l<<uint(bitsOffset%8))
- for i, bb := range buf {
- off := bitsOffset/8 + i
- if off >= len(out) {
- break
- }
- out[off] |= bb
- }
- }
-
- return out[:]
-}
-
-// Equal returns 1 if v and u are equal, and 0 otherwise.
-func (v *Element) Equal(u *Element) int {
- sa, sv := u.Bytes(), v.Bytes()
- return subtle.ConstantTimeCompare(sa, sv)
-}
-
-// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise.
-func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
-
-// Select sets v to a if cond == 1, and to b if cond == 0.
-func (v *Element) Select(a, b *Element, cond int) *Element {
- m := mask64Bits(cond)
- v.l0 = (m & a.l0) | (^m & b.l0)
- v.l1 = (m & a.l1) | (^m & b.l1)
- v.l2 = (m & a.l2) | (^m & b.l2)
- v.l3 = (m & a.l3) | (^m & b.l3)
- v.l4 = (m & a.l4) | (^m & b.l4)
- return v
-}
-
-// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v.
-func (v *Element) Swap(u *Element, cond int) {
- m := mask64Bits(cond)
- t := m & (v.l0 ^ u.l0)
- v.l0 ^= t
- u.l0 ^= t
- t = m & (v.l1 ^ u.l1)
- v.l1 ^= t
- u.l1 ^= t
- t = m & (v.l2 ^ u.l2)
- v.l2 ^= t
- u.l2 ^= t
- t = m & (v.l3 ^ u.l3)
- v.l3 ^= t
- u.l3 ^= t
- t = m & (v.l4 ^ u.l4)
- v.l4 ^= t
- u.l4 ^= t
-}
-
-// IsNegative returns 1 if v is negative, and 0 otherwise.
-func (v *Element) IsNegative() int {
- return int(v.Bytes()[0] & 1)
-}
-
-// Absolute sets v to |u|, and returns v.
-func (v *Element) Absolute(u *Element) *Element {
- return v.Select(new(Element).Negate(u), u, u.IsNegative())
-}
-
-// Multiply sets v = x * y, and returns v.
-func (v *Element) Multiply(x, y *Element) *Element {
- feMul(v, x, y)
- return v
-}
-
-// Square sets v = x * x, and returns v.
-func (v *Element) Square(x *Element) *Element {
- feSquare(v, x)
- return v
-}
-
-// Mult32 sets v = x * y, and returns v.
-func (v *Element) Mult32(x *Element, y uint32) *Element {
- x0lo, x0hi := mul51(x.l0, y)
- x1lo, x1hi := mul51(x.l1, y)
- x2lo, x2hi := mul51(x.l2, y)
- x3lo, x3hi := mul51(x.l3, y)
- x4lo, x4hi := mul51(x.l4, y)
- v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
- v.l1 = x1lo + x0hi
- v.l2 = x2lo + x1hi
- v.l3 = x3lo + x2hi
- v.l4 = x4lo + x3hi
- // The hi portions are going to be only 32 bits, plus any previous excess,
- // so we can skip the carry propagation.
- return v
-}
-
-// mul51 returns lo + hi * 2⁵¹ = a * b.
-func mul51(a uint64, b uint32) (lo uint64, hi uint64) {
- mh, ml := bits.Mul64(a, uint64(b))
- lo = ml & maskLow51Bits
- hi = (mh << 13) | (ml >> 51)
- return
-}
-
-// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3.
-func (v *Element) Pow22523(x *Element) *Element {
- var t0, t1, t2 Element
-
- t0.Square(x) // x^2
- t1.Square(&t0) // x^4
- t1.Square(&t1) // x^8
- t1.Multiply(x, &t1) // x^9
- t0.Multiply(&t0, &t1) // x^11
- t0.Square(&t0) // x^22
- t0.Multiply(&t1, &t0) // x^31
- t1.Square(&t0) // x^62
- for i := 1; i < 5; i++ { // x^992
- t1.Square(&t1)
- }
- t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1
- t1.Square(&t0) // 2^11 - 2
- for i := 1; i < 10; i++ { // 2^20 - 2^10
- t1.Square(&t1)
- }
- t1.Multiply(&t1, &t0) // 2^20 - 1
- t2.Square(&t1) // 2^21 - 2
- for i := 1; i < 20; i++ { // 2^40 - 2^20
- t2.Square(&t2)
- }
- t1.Multiply(&t2, &t1) // 2^40 - 1
- t1.Square(&t1) // 2^41 - 2
- for i := 1; i < 10; i++ { // 2^50 - 2^10
- t1.Square(&t1)
- }
- t0.Multiply(&t1, &t0) // 2^50 - 1
- t1.Square(&t0) // 2^51 - 2
- for i := 1; i < 50; i++ { // 2^100 - 2^50
- t1.Square(&t1)
- }
- t1.Multiply(&t1, &t0) // 2^100 - 1
- t2.Square(&t1) // 2^101 - 2
- for i := 1; i < 100; i++ { // 2^200 - 2^100
- t2.Square(&t2)
- }
- t1.Multiply(&t2, &t1) // 2^200 - 1
- t1.Square(&t1) // 2^201 - 2
- for i := 1; i < 50; i++ { // 2^250 - 2^50
- t1.Square(&t1)
- }
- t0.Multiply(&t1, &t0) // 2^250 - 1
- t0.Square(&t0) // 2^251 - 2
- t0.Square(&t0) // 2^252 - 4
- return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3)
-}
-
-// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion.
-var sqrtM1 = &Element{1718705420411056, 234908883556509,
- 2233514472574048, 2117202627021982, 765476049583133}
-
-// SqrtRatio sets r to the non-negative square root of the ratio of u and v.
-//
-// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio
-// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
-// and returns r and 0.
-func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) {
- var a, b Element
-
- // r = (u * v3) * (u * v7)^((p-5)/8)
- v2 := a.Square(v)
- uv3 := b.Multiply(u, b.Multiply(v2, v))
- uv7 := a.Multiply(uv3, a.Square(v2))
- r.Multiply(uv3, r.Pow22523(uv7))
-
- check := a.Multiply(v, a.Square(r)) // check = v * r^2
-
- uNeg := b.Negate(u)
- correctSignSqrt := check.Equal(u)
- flippedSignSqrt := check.Equal(uNeg)
- flippedSignSqrtI := check.Equal(uNeg.Multiply(uNeg, sqrtM1))
-
- rPrime := b.Multiply(r, sqrtM1) // r_prime = SQRT_M1 * r
- // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
- r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI)
-
- r.Absolute(r) // Choose the nonnegative square root.
- return r, correctSignSqrt | flippedSignSqrt
-}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go
deleted file mode 100644
index edcf163..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
-
-//go:build amd64 && gc && !purego
-// +build amd64,gc,!purego
-
-package field
-
-// feMul sets out = a * b. It works like feMulGeneric.
-//
-//go:noescape
-func feMul(out *Element, a *Element, b *Element)
-
-// feSquare sets out = a * a. It works like feSquareGeneric.
-//
-//go:noescape
-func feSquare(out *Element, a *Element)
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s
deleted file mode 100644
index 293f013..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s
+++ /dev/null
@@ -1,379 +0,0 @@
-// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
-
-//go:build amd64 && gc && !purego
-// +build amd64,gc,!purego
-
-#include "textflag.h"
-
-// func feMul(out *Element, a *Element, b *Element)
-TEXT ·feMul(SB), NOSPLIT, $0-24
- MOVQ a+8(FP), CX
- MOVQ b+16(FP), BX
-
- // r0 = a0×b0
- MOVQ (CX), AX
- MULQ (BX)
- MOVQ AX, DI
- MOVQ DX, SI
-
- // r0 += 19×a1×b4
- MOVQ 8(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 32(BX)
- ADDQ AX, DI
- ADCQ DX, SI
-
- // r0 += 19×a2×b3
- MOVQ 16(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 24(BX)
- ADDQ AX, DI
- ADCQ DX, SI
-
- // r0 += 19×a3×b2
- MOVQ 24(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 16(BX)
- ADDQ AX, DI
- ADCQ DX, SI
-
- // r0 += 19×a4×b1
- MOVQ 32(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 8(BX)
- ADDQ AX, DI
- ADCQ DX, SI
-
- // r1 = a0×b1
- MOVQ (CX), AX
- MULQ 8(BX)
- MOVQ AX, R9
- MOVQ DX, R8
-
- // r1 += a1×b0
- MOVQ 8(CX), AX
- MULQ (BX)
- ADDQ AX, R9
- ADCQ DX, R8
-
- // r1 += 19×a2×b4
- MOVQ 16(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 32(BX)
- ADDQ AX, R9
- ADCQ DX, R8
-
- // r1 += 19×a3×b3
- MOVQ 24(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 24(BX)
- ADDQ AX, R9
- ADCQ DX, R8
-
- // r1 += 19×a4×b2
- MOVQ 32(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 16(BX)
- ADDQ AX, R9
- ADCQ DX, R8
-
- // r2 = a0×b2
- MOVQ (CX), AX
- MULQ 16(BX)
- MOVQ AX, R11
- MOVQ DX, R10
-
- // r2 += a1×b1
- MOVQ 8(CX), AX
- MULQ 8(BX)
- ADDQ AX, R11
- ADCQ DX, R10
-
- // r2 += a2×b0
- MOVQ 16(CX), AX
- MULQ (BX)
- ADDQ AX, R11
- ADCQ DX, R10
-
- // r2 += 19×a3×b4
- MOVQ 24(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 32(BX)
- ADDQ AX, R11
- ADCQ DX, R10
-
- // r2 += 19×a4×b3
- MOVQ 32(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 24(BX)
- ADDQ AX, R11
- ADCQ DX, R10
-
- // r3 = a0×b3
- MOVQ (CX), AX
- MULQ 24(BX)
- MOVQ AX, R13
- MOVQ DX, R12
-
- // r3 += a1×b2
- MOVQ 8(CX), AX
- MULQ 16(BX)
- ADDQ AX, R13
- ADCQ DX, R12
-
- // r3 += a2×b1
- MOVQ 16(CX), AX
- MULQ 8(BX)
- ADDQ AX, R13
- ADCQ DX, R12
-
- // r3 += a3×b0
- MOVQ 24(CX), AX
- MULQ (BX)
- ADDQ AX, R13
- ADCQ DX, R12
-
- // r3 += 19×a4×b4
- MOVQ 32(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 32(BX)
- ADDQ AX, R13
- ADCQ DX, R12
-
- // r4 = a0×b4
- MOVQ (CX), AX
- MULQ 32(BX)
- MOVQ AX, R15
- MOVQ DX, R14
-
- // r4 += a1×b3
- MOVQ 8(CX), AX
- MULQ 24(BX)
- ADDQ AX, R15
- ADCQ DX, R14
-
- // r4 += a2×b2
- MOVQ 16(CX), AX
- MULQ 16(BX)
- ADDQ AX, R15
- ADCQ DX, R14
-
- // r4 += a3×b1
- MOVQ 24(CX), AX
- MULQ 8(BX)
- ADDQ AX, R15
- ADCQ DX, R14
-
- // r4 += a4×b0
- MOVQ 32(CX), AX
- MULQ (BX)
- ADDQ AX, R15
- ADCQ DX, R14
-
- // First reduction chain
- MOVQ $0x0007ffffffffffff, AX
- SHLQ $0x0d, DI, SI
- SHLQ $0x0d, R9, R8
- SHLQ $0x0d, R11, R10
- SHLQ $0x0d, R13, R12
- SHLQ $0x0d, R15, R14
- ANDQ AX, DI
- IMUL3Q $0x13, R14, R14
- ADDQ R14, DI
- ANDQ AX, R9
- ADDQ SI, R9
- ANDQ AX, R11
- ADDQ R8, R11
- ANDQ AX, R13
- ADDQ R10, R13
- ANDQ AX, R15
- ADDQ R12, R15
-
- // Second reduction chain (carryPropagate)
- MOVQ DI, SI
- SHRQ $0x33, SI
- MOVQ R9, R8
- SHRQ $0x33, R8
- MOVQ R11, R10
- SHRQ $0x33, R10
- MOVQ R13, R12
- SHRQ $0x33, R12
- MOVQ R15, R14
- SHRQ $0x33, R14
- ANDQ AX, DI
- IMUL3Q $0x13, R14, R14
- ADDQ R14, DI
- ANDQ AX, R9
- ADDQ SI, R9
- ANDQ AX, R11
- ADDQ R8, R11
- ANDQ AX, R13
- ADDQ R10, R13
- ANDQ AX, R15
- ADDQ R12, R15
-
- // Store output
- MOVQ out+0(FP), AX
- MOVQ DI, (AX)
- MOVQ R9, 8(AX)
- MOVQ R11, 16(AX)
- MOVQ R13, 24(AX)
- MOVQ R15, 32(AX)
- RET
-
-// func feSquare(out *Element, a *Element)
-TEXT ·feSquare(SB), NOSPLIT, $0-16
- MOVQ a+8(FP), CX
-
- // r0 = l0×l0
- MOVQ (CX), AX
- MULQ (CX)
- MOVQ AX, SI
- MOVQ DX, BX
-
- // r0 += 38×l1×l4
- MOVQ 8(CX), AX
- IMUL3Q $0x26, AX, AX
- MULQ 32(CX)
- ADDQ AX, SI
- ADCQ DX, BX
-
- // r0 += 38×l2×l3
- MOVQ 16(CX), AX
- IMUL3Q $0x26, AX, AX
- MULQ 24(CX)
- ADDQ AX, SI
- ADCQ DX, BX
-
- // r1 = 2×l0×l1
- MOVQ (CX), AX
- SHLQ $0x01, AX
- MULQ 8(CX)
- MOVQ AX, R8
- MOVQ DX, DI
-
- // r1 += 38×l2×l4
- MOVQ 16(CX), AX
- IMUL3Q $0x26, AX, AX
- MULQ 32(CX)
- ADDQ AX, R8
- ADCQ DX, DI
-
- // r1 += 19×l3×l3
- MOVQ 24(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 24(CX)
- ADDQ AX, R8
- ADCQ DX, DI
-
- // r2 = 2×l0×l2
- MOVQ (CX), AX
- SHLQ $0x01, AX
- MULQ 16(CX)
- MOVQ AX, R10
- MOVQ DX, R9
-
- // r2 += l1×l1
- MOVQ 8(CX), AX
- MULQ 8(CX)
- ADDQ AX, R10
- ADCQ DX, R9
-
- // r2 += 38×l3×l4
- MOVQ 24(CX), AX
- IMUL3Q $0x26, AX, AX
- MULQ 32(CX)
- ADDQ AX, R10
- ADCQ DX, R9
-
- // r3 = 2×l0×l3
- MOVQ (CX), AX
- SHLQ $0x01, AX
- MULQ 24(CX)
- MOVQ AX, R12
- MOVQ DX, R11
-
- // r3 += 2×l1×l2
- MOVQ 8(CX), AX
- IMUL3Q $0x02, AX, AX
- MULQ 16(CX)
- ADDQ AX, R12
- ADCQ DX, R11
-
- // r3 += 19×l4×l4
- MOVQ 32(CX), AX
- IMUL3Q $0x13, AX, AX
- MULQ 32(CX)
- ADDQ AX, R12
- ADCQ DX, R11
-
- // r4 = 2×l0×l4
- MOVQ (CX), AX
- SHLQ $0x01, AX
- MULQ 32(CX)
- MOVQ AX, R14
- MOVQ DX, R13
-
- // r4 += 2×l1×l3
- MOVQ 8(CX), AX
- IMUL3Q $0x02, AX, AX
- MULQ 24(CX)
- ADDQ AX, R14
- ADCQ DX, R13
-
- // r4 += l2×l2
- MOVQ 16(CX), AX
- MULQ 16(CX)
- ADDQ AX, R14
- ADCQ DX, R13
-
- // First reduction chain
- MOVQ $0x0007ffffffffffff, AX
- SHLQ $0x0d, SI, BX
- SHLQ $0x0d, R8, DI
- SHLQ $0x0d, R10, R9
- SHLQ $0x0d, R12, R11
- SHLQ $0x0d, R14, R13
- ANDQ AX, SI
- IMUL3Q $0x13, R13, R13
- ADDQ R13, SI
- ANDQ AX, R8
- ADDQ BX, R8
- ANDQ AX, R10
- ADDQ DI, R10
- ANDQ AX, R12
- ADDQ R9, R12
- ANDQ AX, R14
- ADDQ R11, R14
-
- // Second reduction chain (carryPropagate)
- MOVQ SI, BX
- SHRQ $0x33, BX
- MOVQ R8, DI
- SHRQ $0x33, DI
- MOVQ R10, R9
- SHRQ $0x33, R9
- MOVQ R12, R11
- SHRQ $0x33, R11
- MOVQ R14, R13
- SHRQ $0x33, R13
- ANDQ AX, SI
- IMUL3Q $0x13, R13, R13
- ADDQ R13, SI
- ANDQ AX, R8
- ADDQ BX, R8
- ANDQ AX, R10
- ADDQ DI, R10
- ANDQ AX, R12
- ADDQ R9, R12
- ANDQ AX, R14
- ADDQ R11, R14
-
- // Store output
- MOVQ out+0(FP), AX
- MOVQ SI, (AX)
- MOVQ R8, 8(AX)
- MOVQ R10, 16(AX)
- MOVQ R12, 24(AX)
- MOVQ R14, 32(AX)
- RET
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go
deleted file mode 100644
index ddb6c9b..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !amd64 || !gc || purego
-// +build !amd64 !gc purego
-
-package field
-
-func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
-
-func feSquare(v, x *Element) { feSquareGeneric(v, x) }
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go
deleted file mode 100644
index af459ef..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 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.
-
-//go:build arm64 && gc && !purego
-// +build arm64,gc,!purego
-
-package field
-
-//go:noescape
-func carryPropagate(v *Element)
-
-func (v *Element) carryPropagate() *Element {
- carryPropagate(v)
- return v
-}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s
deleted file mode 100644
index 5c91e45..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 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.
-
-//go:build arm64 && gc && !purego
-// +build arm64,gc,!purego
-
-#include "textflag.h"
-
-// carryPropagate works exactly like carryPropagateGeneric and uses the
-// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but
-// avoids loading R0-R4 twice and uses LDP and STP.
-//
-// See https://golang.org/issues/43145 for the main compiler issue.
-//
-// func carryPropagate(v *Element)
-TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8
- MOVD v+0(FP), R20
-
- LDP 0(R20), (R0, R1)
- LDP 16(R20), (R2, R3)
- MOVD 32(R20), R4
-
- AND $0x7ffffffffffff, R0, R10
- AND $0x7ffffffffffff, R1, R11
- AND $0x7ffffffffffff, R2, R12
- AND $0x7ffffffffffff, R3, R13
- AND $0x7ffffffffffff, R4, R14
-
- ADD R0>>51, R11, R11
- ADD R1>>51, R12, R12
- ADD R2>>51, R13, R13
- ADD R3>>51, R14, R14
- // R4>>51 * 19 + R10 -> R10
- LSR $51, R4, R21
- MOVD $19, R22
- MADD R22, R10, R21, R10
-
- STP (R10, R11), 0(R20)
- STP (R12, R13), 16(R20)
- MOVD R14, 32(R20)
-
- RET
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go
deleted file mode 100644
index 234a5b2..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 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.
-
-//go:build !arm64 || !gc || purego
-// +build !arm64 !gc purego
-
-package field
-
-func (v *Element) carryPropagate() *Element {
- return v.carryPropagateGeneric()
-}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go
deleted file mode 100644
index 7b5b78c..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go
+++ /dev/null
@@ -1,264 +0,0 @@
-// Copyright (c) 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.
-
-package field
-
-import "math/bits"
-
-// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
-// bits.Mul64 and bits.Add64 intrinsics.
-type uint128 struct {
- lo, hi uint64
-}
-
-// mul64 returns a * b.
-func mul64(a, b uint64) uint128 {
- hi, lo := bits.Mul64(a, b)
- return uint128{lo, hi}
-}
-
-// addMul64 returns v + a * b.
-func addMul64(v uint128, a, b uint64) uint128 {
- hi, lo := bits.Mul64(a, b)
- lo, c := bits.Add64(lo, v.lo, 0)
- hi, _ = bits.Add64(hi, v.hi, c)
- return uint128{lo, hi}
-}
-
-// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits.
-func shiftRightBy51(a uint128) uint64 {
- return (a.hi << (64 - 51)) | (a.lo >> 51)
-}
-
-func feMulGeneric(v, a, b *Element) {
- a0 := a.l0
- a1 := a.l1
- a2 := a.l2
- a3 := a.l3
- a4 := a.l4
-
- b0 := b.l0
- b1 := b.l1
- b2 := b.l2
- b3 := b.l3
- b4 := b.l4
-
- // Limb multiplication works like pen-and-paper columnar multiplication, but
- // with 51-bit limbs instead of digits.
- //
- // a4 a3 a2 a1 a0 x
- // b4 b3 b2 b1 b0 =
- // ------------------------
- // a4b0 a3b0 a2b0 a1b0 a0b0 +
- // a4b1 a3b1 a2b1 a1b1 a0b1 +
- // a4b2 a3b2 a2b2 a1b2 a0b2 +
- // a4b3 a3b3 a2b3 a1b3 a0b3 +
- // a4b4 a3b4 a2b4 a1b4 a0b4 =
- // ----------------------------------------------
- // r8 r7 r6 r5 r4 r3 r2 r1 r0
- //
- // We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to
- // reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5,
- // r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc.
- //
- // Reduction can be carried out simultaneously to multiplication. For
- // example, we do not compute r5: whenever the result of a multiplication
- // belongs to r5, like a1b4, we multiply it by 19 and add the result to r0.
- //
- // a4b0 a3b0 a2b0 a1b0 a0b0 +
- // a3b1 a2b1 a1b1 a0b1 19×a4b1 +
- // a2b2 a1b2 a0b2 19×a4b2 19×a3b2 +
- // a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 +
- // a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 =
- // --------------------------------------
- // r4 r3 r2 r1 r0
- //
- // Finally we add up the columns into wide, overlapping limbs.
-
- a1_19 := a1 * 19
- a2_19 := a2 * 19
- a3_19 := a3 * 19
- a4_19 := a4 * 19
-
- // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
- r0 := mul64(a0, b0)
- r0 = addMul64(r0, a1_19, b4)
- r0 = addMul64(r0, a2_19, b3)
- r0 = addMul64(r0, a3_19, b2)
- r0 = addMul64(r0, a4_19, b1)
-
- // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
- r1 := mul64(a0, b1)
- r1 = addMul64(r1, a1, b0)
- r1 = addMul64(r1, a2_19, b4)
- r1 = addMul64(r1, a3_19, b3)
- r1 = addMul64(r1, a4_19, b2)
-
- // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
- r2 := mul64(a0, b2)
- r2 = addMul64(r2, a1, b1)
- r2 = addMul64(r2, a2, b0)
- r2 = addMul64(r2, a3_19, b4)
- r2 = addMul64(r2, a4_19, b3)
-
- // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
- r3 := mul64(a0, b3)
- r3 = addMul64(r3, a1, b2)
- r3 = addMul64(r3, a2, b1)
- r3 = addMul64(r3, a3, b0)
- r3 = addMul64(r3, a4_19, b4)
-
- // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
- r4 := mul64(a0, b4)
- r4 = addMul64(r4, a1, b3)
- r4 = addMul64(r4, a2, b2)
- r4 = addMul64(r4, a3, b1)
- r4 = addMul64(r4, a4, b0)
-
- // After the multiplication, we need to reduce (carry) the five coefficients
- // to obtain a result with limbs that are at most slightly larger than 2⁵¹,
- // to respect the Element invariant.
- //
- // Overall, the reduction works the same as carryPropagate, except with
- // wider inputs: we take the carry for each coefficient by shifting it right
- // by 51, and add it to the limb above it. The top carry is multiplied by 19
- // according to the reduction identity and added to the lowest limb.
- //
- // The largest coefficient (r0) will be at most 111 bits, which guarantees
- // that all carries are at most 111 - 51 = 60 bits, which fits in a uint64.
- //
- // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
- // r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²)
- // r0 < (1 + 19 × 4) × 2⁵² × 2⁵²
- // r0 < 2⁷ × 2⁵² × 2⁵²
- // r0 < 2¹¹¹
- //
- // Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most
- // 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and
- // allows us to easily apply the reduction identity.
- //
- // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
- // r4 < 5 × 2⁵² × 2⁵²
- // r4 < 2¹⁰⁷
- //
-
- c0 := shiftRightBy51(r0)
- c1 := shiftRightBy51(r1)
- c2 := shiftRightBy51(r2)
- c3 := shiftRightBy51(r3)
- c4 := shiftRightBy51(r4)
-
- rr0 := r0.lo&maskLow51Bits + c4*19
- rr1 := r1.lo&maskLow51Bits + c0
- rr2 := r2.lo&maskLow51Bits + c1
- rr3 := r3.lo&maskLow51Bits + c2
- rr4 := r4.lo&maskLow51Bits + c3
-
- // Now all coefficients fit into 64-bit registers but are still too large to
- // be passed around as a Element. We therefore do one last carry chain,
- // where the carries will be small enough to fit in the wiggle room above 2⁵¹.
- *v = Element{rr0, rr1, rr2, rr3, rr4}
- v.carryPropagate()
-}
-
-func feSquareGeneric(v, a *Element) {
- l0 := a.l0
- l1 := a.l1
- l2 := a.l2
- l3 := a.l3
- l4 := a.l4
-
- // Squaring works precisely like multiplication above, but thanks to its
- // symmetry we get to group a few terms together.
- //
- // l4 l3 l2 l1 l0 x
- // l4 l3 l2 l1 l0 =
- // ------------------------
- // l4l0 l3l0 l2l0 l1l0 l0l0 +
- // l4l1 l3l1 l2l1 l1l1 l0l1 +
- // l4l2 l3l2 l2l2 l1l2 l0l2 +
- // l4l3 l3l3 l2l3 l1l3 l0l3 +
- // l4l4 l3l4 l2l4 l1l4 l0l4 =
- // ----------------------------------------------
- // r8 r7 r6 r5 r4 r3 r2 r1 r0
- //
- // l4l0 l3l0 l2l0 l1l0 l0l0 +
- // l3l1 l2l1 l1l1 l0l1 19×l4l1 +
- // l2l2 l1l2 l0l2 19×l4l2 19×l3l2 +
- // l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 +
- // l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 =
- // --------------------------------------
- // r4 r3 r2 r1 r0
- //
- // With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with
- // only three Mul64 and four Add64, instead of five and eight.
-
- l0_2 := l0 * 2
- l1_2 := l1 * 2
-
- l1_38 := l1 * 38
- l2_38 := l2 * 38
- l3_38 := l3 * 38
-
- l3_19 := l3 * 19
- l4_19 := l4 * 19
-
- // r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3)
- r0 := mul64(l0, l0)
- r0 = addMul64(r0, l1_38, l4)
- r0 = addMul64(r0, l2_38, l3)
-
- // r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
- r1 := mul64(l0_2, l1)
- r1 = addMul64(r1, l2_38, l4)
- r1 = addMul64(r1, l3_19, l3)
-
- // r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4
- r2 := mul64(l0_2, l2)
- r2 = addMul64(r2, l1, l1)
- r2 = addMul64(r2, l3_38, l4)
-
- // r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
- r3 := mul64(l0_2, l3)
- r3 = addMul64(r3, l1_2, l2)
- r3 = addMul64(r3, l4_19, l4)
-
- // r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2
- r4 := mul64(l0_2, l4)
- r4 = addMul64(r4, l1_2, l3)
- r4 = addMul64(r4, l2, l2)
-
- c0 := shiftRightBy51(r0)
- c1 := shiftRightBy51(r1)
- c2 := shiftRightBy51(r2)
- c3 := shiftRightBy51(r3)
- c4 := shiftRightBy51(r4)
-
- rr0 := r0.lo&maskLow51Bits + c4*19
- rr1 := r1.lo&maskLow51Bits + c0
- rr2 := r2.lo&maskLow51Bits + c1
- rr3 := r3.lo&maskLow51Bits + c2
- rr4 := r4.lo&maskLow51Bits + c3
-
- *v = Element{rr0, rr1, rr2, rr3, rr4}
- v.carryPropagate()
-}
-
-// carryPropagate brings the limbs below 52 bits by applying the reduction
-// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry. TODO inline
-func (v *Element) carryPropagateGeneric() *Element {
- c0 := v.l0 >> 51
- c1 := v.l1 >> 51
- c2 := v.l2 >> 51
- c3 := v.l3 >> 51
- c4 := v.l4 >> 51
-
- v.l0 = v.l0&maskLow51Bits + c4*19
- v.l1 = v.l1&maskLow51Bits + c0
- v.l2 = v.l2&maskLow51Bits + c1
- v.l3 = v.l3&maskLow51Bits + c2
- v.l4 = v.l4&maskLow51Bits + c3
-
- return v
-}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint b/src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint
deleted file mode 100644
index e3685f9..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint
+++ /dev/null
@@ -1 +0,0 @@
-b0c49ae9f59d233526f8934262c5bbbe14d4358d
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh b/src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh
deleted file mode 100644
index 1ba22a8..0000000
--- a/src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#! /bin/bash
-set -euo pipefail
-
-cd "$(git rev-parse --show-toplevel)"
-
-STD_PATH=src/crypto/ed25519/internal/edwards25519/field
-LOCAL_PATH=curve25519/internal/field
-LAST_SYNC_REF=$(cat $LOCAL_PATH/sync.checkpoint)
-
-git fetch https://go.googlesource.com/go master
-
-if git diff --quiet $LAST_SYNC_REF:$STD_PATH FETCH_HEAD:$STD_PATH; then
- echo "No changes."
-else
- NEW_REF=$(git rev-parse FETCH_HEAD | tee $LOCAL_PATH/sync.checkpoint)
- echo "Applying changes from $LAST_SYNC_REF to $NEW_REF..."
- git diff $LAST_SYNC_REF:$STD_PATH FETCH_HEAD:$STD_PATH | \
- git apply -3 --directory=$LOCAL_PATH
-fi
diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt
index a81495a..60c53b2 100644
--- a/src/vendor/modules.txt
+++ b/src/vendor/modules.txt
@@ -4,8 +4,6 @@
golang.org/x/crypto/chacha20poly1305
golang.org/x/crypto/cryptobyte
golang.org/x/crypto/cryptobyte/asn1
-golang.org/x/crypto/curve25519
-golang.org/x/crypto/curve25519/internal/field
golang.org/x/crypto/hkdf
golang.org/x/crypto/internal/poly1305
golang.org/x/crypto/internal/subtle
To view, visit change 398914. To unsubscribe, or for help writing mail filters, visit settings.