diff --git a/api/next/52221.txt b/api/next/52221.txt new file mode 100644 index 00000000000..c288e4660b3 --- /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 00000000000..d835b045736 --- /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 00000000000..b27d6c91eae --- /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 00000000000..091d6aec9f7 --- /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 00000000000..21127ffb957 --- /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 8c0b60b8892..ababde4646d 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 @@ import ( // 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 @@ var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f} // 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 @@ func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err e // 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 @@ var _ = []unmarshaler{p224, p256, p384, p521} // 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 0ed929d61f9..1ae57fae9ea 100644 --- a/src/crypto/elliptic/params.go +++ b/src/crypto/elliptic/params.go @@ -8,6 +8,10 @@ import "math/big" // 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 @@ func (curve *CurveParams) polynomial(x *big.Int) *big.Int { 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 @@ func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big. 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 @@ func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int 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 @@ func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, 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 @@ func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big. 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 9e82693b1c1..2c42eb9bb95 100644 --- a/src/crypto/internal/nistec/generate.go +++ b/src/crypto/internal/nistec/generate.go @@ -303,6 +303,26 @@ func (p *{{.P}}Point) bytes(out *[1+2*{{.p}}ElementLength]byte) []byte { 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 8d236b33d73..18b43eaef62 100644 --- a/src/crypto/internal/nistec/p224.go +++ b/src/crypto/internal/nistec/p224.go @@ -159,6 +159,26 @@ func (p *P224Point) bytes(out *[1 + 2*p224ElementLength]byte) []byte { 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 353b428c1d9..c836c2a0c83 100644 --- a/src/crypto/internal/nistec/p256.go +++ b/src/crypto/internal/nistec/p256.go @@ -161,6 +161,26 @@ func (p *P256Point) bytes(out *[1 + 2*p256ElementLength]byte) []byte { 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 bc443ba323a..90f027945da 100644 --- a/src/crypto/internal/nistec/p256_asm.go +++ b/src/crypto/internal/nistec/p256_asm.go @@ -479,6 +479,30 @@ func (p *P256Point) affineFromMont(x, y *p256Element) { 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 1a855cb7133..40bff73c5a8 100644 --- a/src/crypto/internal/nistec/p384.go +++ b/src/crypto/internal/nistec/p384.go @@ -159,6 +159,26 @@ func (p *P384Point) bytes(out *[1 + 2*p384ElementLength]byte) []byte { 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 f285d575763..b137d27aedd 100644 --- a/src/crypto/internal/nistec/p521.go +++ b/src/crypto/internal/nistec/p521.go @@ -159,6 +159,26 @@ func (p *P521Point) bytes(out *[1 + 2*p521ElementLength]byte) []byte { 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 e07cf79629a..f5e24cbc6d5 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -8,6 +8,7 @@ import ( "bytes" "context" "crypto" + "crypto/ecdh" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" @@ -35,7 +36,7 @@ type clientHandshakeState struct { 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 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) { 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 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) { } 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 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { // 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 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { 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 ac783afdfca..12ff3a4a4ff 100644 --- a/src/crypto/tls/handshake_client_tls13.go +++ b/src/crypto/tls/handshake_client_tls13.go @@ -8,6 +8,7 @@ import ( "bytes" "context" "crypto" + "crypto/ecdh" "crypto/hmac" "crypto/rsa" "errors" @@ -20,7 +21,7 @@ type clientHandshakeStateTLS13 struct { ctx context.Context serverHello *serverHelloMsg hello *clientHelloMsg - ecdheParams ecdheParameters + ecdheKey *ecdh.PrivateKey session *ClientSessionState earlySecret []byte @@ -35,7 +36,7 @@ type clientHandshakeStateTLS13 struct { 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 @@ func (hs *clientHandshakeStateTLS13) handshake() error { } // 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 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { 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 @@ func (hs *clientHandshakeStateTLS13) processServerHello() error { 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) processServerHello() error { 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 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { 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 5ff5270a7c1..863cb20600c 100644 --- a/src/crypto/tls/handshake_server_test.go +++ b/src/crypto/tls/handshake_server_test.go @@ -8,7 +8,9 @@ import ( "bytes" "context" "crypto" + "crypto/ecdh" "crypto/elliptic" + "crypto/rand" "crypto/x509" "encoding/pem" "errors" @@ -22,8 +24,6 @@ import ( "strings" "testing" "time" - - "golang.org/x/crypto/curve25519" ) func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) { @@ -1909,6 +1909,7 @@ func TestAESCipherReorderingTLS13(t *testing.T) { 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 @@ func TestAESCipherReorderingTLS13(t *testing.T) { 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 712f3589b3f..9b7356a32b4 100644 --- a/src/crypto/tls/handshake_server_tls13.go +++ b/src/crypto/tls/handshake_server_tls13.go @@ -205,18 +205,23 @@ GroupSelection: 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 c28a64f3a8b..027060d090e 100644 --- a/src/crypto/tls/key_agreement.go +++ b/src/crypto/tls/key_agreement.go @@ -6,6 +6,7 @@ package tls import ( "crypto" + "crypto/ecdh" "crypto/md5" "crypto/rsa" "crypto/sha1" @@ -157,7 +158,7 @@ func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint1 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 @@ func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Cer 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 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert 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 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell 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 314016979af..af1f2bd0a85 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 @@ func (c *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript } } -// 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 496771b5175..e911f2f3411 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -382,10 +382,11 @@ var depsRules = ` < 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 @@ var depsRules = ` 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 bc62161d6e4..00000000000 --- 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 e25bca7dc80..00000000000 --- 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 ca841ad99e3..00000000000 --- 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<= 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 edcf163c4ed..00000000000 --- 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 293f013c94a..00000000000 --- 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 ddb6c9b8f7f..00000000000 --- 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 af459ef5154..00000000000 --- 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 5c91e458923..00000000000 --- 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 234a5b2e5d1..00000000000 --- 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 7b5b78cbd6d..00000000000 --- 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 e3685f95cab..00000000000 --- 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 1ba22a8b4c9..00000000000 --- 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 a81495aeb5f..60c53b2dcd6 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -4,8 +4,6 @@ golang.org/x/crypto/chacha20 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