mirror of
https://github.com/golang/go
synced 2024-11-26 06:17:57 -07:00
crypto/ecdh: new package
We use crypto/internal/edwards25519/field to implement X25519 directly, so that golang.org/x/crypto/curve25519 can be dropped from the src module dependencies, and eventually replaced with a crypto/ecdh wrapper, removing the need to keep golang.org/x/crypto/curve25519/internal/field in sync with crypto/internal/edwards25519/field. In crypto/internal/nistec, we add BytesX to serialize only the x coordinate, which we'll need for the horrible ECDSA x-coord-to-scalar operation, too. In crypto/tls, we replace the ECDHE implementation with crypto/ecdh, dropping the X25519 special cases and related scaffolding. Finally, FINALLY, we deprecate the ~white whale~ big.Int-based APIs of the crypto/elliptic package. •_•) ( •_•)>⌐■-■ (⌐■_■) Fixes #52182 Fixes #34648 Fixes #52221 Change-Id: Iccdda210319cc892e96bb28a0e7b7123551982c7 Reviewed-on: https://go-review.googlesource.com/c/go/+/398914 Reviewed-by: Fernando Lobato Meeser <felobato@google.com> Reviewed-by: Roland Shoemaker <roland@golang.org> Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
0b79abc27e
commit
d88d91e32e
19
api/next/52221.txt
Normal file
19
api/next/52221.txt
Normal file
@ -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
|
149
src/crypto/ecdh/ecdh.go
Normal file
149
src/crypto/ecdh/ecdh.go
Normal file
@ -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()
|
||||
}
|
255
src/crypto/ecdh/ecdh_test.go
Normal file
255
src/crypto/ecdh/ecdh_test.go
Normal file
@ -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{}
|
211
src/crypto/ecdh/nist.go
Normal file
211
src/crypto/ecdh/nist.go
Normal file
@ -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}
|
136
src/crypto/ecdh/x25519.go
Normal file
136
src/crypto/ecdh/x25519.go
Normal file
@ -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())
|
||||
}
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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()}},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
146
src/vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
146
src/vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
@ -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
|
||||
}
|
7
src/vendor/golang.org/x/crypto/curve25519/internal/field/README
generated
vendored
7
src/vendor/golang.org/x/crypto/curve25519/internal/field/README
generated
vendored
@ -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.
|
416
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go
generated
vendored
416
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go
generated
vendored
@ -1,416 +0,0 @@
|
||||
// Copyright (c) 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package field implements fast arithmetic modulo 2^255-19.
|
||||
package field
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// Element represents an element of the field GF(2^255-19). Note that this
|
||||
// is not a cryptographically secure group, and should only be used to interact
|
||||
// with edwards25519.Point coordinates.
|
||||
//
|
||||
// This type works similarly to math/big.Int, and all arguments and receivers
|
||||
// are allowed to alias.
|
||||
//
|
||||
// The zero value is a valid zero element.
|
||||
type Element struct {
|
||||
// An element t represents the integer
|
||||
// t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
|
||||
//
|
||||
// Between operations, all limbs are expected to be lower than 2^52.
|
||||
l0 uint64
|
||||
l1 uint64
|
||||
l2 uint64
|
||||
l3 uint64
|
||||
l4 uint64
|
||||
}
|
||||
|
||||
const maskLow51Bits uint64 = (1 << 51) - 1
|
||||
|
||||
var feZero = &Element{0, 0, 0, 0, 0}
|
||||
|
||||
// Zero sets v = 0, and returns v.
|
||||
func (v *Element) Zero() *Element {
|
||||
*v = *feZero
|
||||
return v
|
||||
}
|
||||
|
||||
var feOne = &Element{1, 0, 0, 0, 0}
|
||||
|
||||
// One sets v = 1, and returns v.
|
||||
func (v *Element) One() *Element {
|
||||
*v = *feOne
|
||||
return v
|
||||
}
|
||||
|
||||
// reduce reduces v modulo 2^255 - 19 and returns it.
|
||||
func (v *Element) reduce() *Element {
|
||||
v.carryPropagate()
|
||||
|
||||
// After the light reduction we now have a field element representation
|
||||
// v < 2^255 + 2^13 * 19, but need v < 2^255 - 19.
|
||||
|
||||
// If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
|
||||
// generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
|
||||
c := (v.l0 + 19) >> 51
|
||||
c = (v.l1 + c) >> 51
|
||||
c = (v.l2 + c) >> 51
|
||||
c = (v.l3 + c) >> 51
|
||||
c = (v.l4 + c) >> 51
|
||||
|
||||
// If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
|
||||
// effectively applying the reduction identity to the carry.
|
||||
v.l0 += 19 * c
|
||||
|
||||
v.l1 += v.l0 >> 51
|
||||
v.l0 = v.l0 & maskLow51Bits
|
||||
v.l2 += v.l1 >> 51
|
||||
v.l1 = v.l1 & maskLow51Bits
|
||||
v.l3 += v.l2 >> 51
|
||||
v.l2 = v.l2 & maskLow51Bits
|
||||
v.l4 += v.l3 >> 51
|
||||
v.l3 = v.l3 & maskLow51Bits
|
||||
// no additional carry
|
||||
v.l4 = v.l4 & maskLow51Bits
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// Add sets v = a + b, and returns v.
|
||||
func (v *Element) Add(a, b *Element) *Element {
|
||||
v.l0 = a.l0 + b.l0
|
||||
v.l1 = a.l1 + b.l1
|
||||
v.l2 = a.l2 + b.l2
|
||||
v.l3 = a.l3 + b.l3
|
||||
v.l4 = a.l4 + b.l4
|
||||
// Using the generic implementation here is actually faster than the
|
||||
// assembly. Probably because the body of this function is so simple that
|
||||
// the compiler can figure out better optimizations by inlining the carry
|
||||
// propagation. TODO
|
||||
return v.carryPropagateGeneric()
|
||||
}
|
||||
|
||||
// Subtract sets v = a - b, and returns v.
|
||||
func (v *Element) Subtract(a, b *Element) *Element {
|
||||
// We first add 2 * p, to guarantee the subtraction won't underflow, and
|
||||
// then subtract b (which can be up to 2^255 + 2^13 * 19).
|
||||
v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
|
||||
v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
|
||||
v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
|
||||
v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
|
||||
v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
|
||||
return v.carryPropagate()
|
||||
}
|
||||
|
||||
// Negate sets v = -a, and returns v.
|
||||
func (v *Element) Negate(a *Element) *Element {
|
||||
return v.Subtract(feZero, a)
|
||||
}
|
||||
|
||||
// Invert sets v = 1/z mod p, and returns v.
|
||||
//
|
||||
// If z == 0, Invert returns v = 0.
|
||||
func (v *Element) Invert(z *Element) *Element {
|
||||
// Inversion is implemented as exponentiation with exponent p − 2. It uses the
|
||||
// same sequence of 255 squarings and 11 multiplications as [Curve25519].
|
||||
var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element
|
||||
|
||||
z2.Square(z) // 2
|
||||
t.Square(&z2) // 4
|
||||
t.Square(&t) // 8
|
||||
z9.Multiply(&t, z) // 9
|
||||
z11.Multiply(&z9, &z2) // 11
|
||||
t.Square(&z11) // 22
|
||||
z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0
|
||||
|
||||
t.Square(&z2_5_0) // 2^6 - 2^1
|
||||
for i := 0; i < 4; i++ {
|
||||
t.Square(&t) // 2^10 - 2^5
|
||||
}
|
||||
z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0
|
||||
|
||||
t.Square(&z2_10_0) // 2^11 - 2^1
|
||||
for i := 0; i < 9; i++ {
|
||||
t.Square(&t) // 2^20 - 2^10
|
||||
}
|
||||
z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0
|
||||
|
||||
t.Square(&z2_20_0) // 2^21 - 2^1
|
||||
for i := 0; i < 19; i++ {
|
||||
t.Square(&t) // 2^40 - 2^20
|
||||
}
|
||||
t.Multiply(&t, &z2_20_0) // 2^40 - 2^0
|
||||
|
||||
t.Square(&t) // 2^41 - 2^1
|
||||
for i := 0; i < 9; i++ {
|
||||
t.Square(&t) // 2^50 - 2^10
|
||||
}
|
||||
z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0
|
||||
|
||||
t.Square(&z2_50_0) // 2^51 - 2^1
|
||||
for i := 0; i < 49; i++ {
|
||||
t.Square(&t) // 2^100 - 2^50
|
||||
}
|
||||
z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0
|
||||
|
||||
t.Square(&z2_100_0) // 2^101 - 2^1
|
||||
for i := 0; i < 99; i++ {
|
||||
t.Square(&t) // 2^200 - 2^100
|
||||
}
|
||||
t.Multiply(&t, &z2_100_0) // 2^200 - 2^0
|
||||
|
||||
t.Square(&t) // 2^201 - 2^1
|
||||
for i := 0; i < 49; i++ {
|
||||
t.Square(&t) // 2^250 - 2^50
|
||||
}
|
||||
t.Multiply(&t, &z2_50_0) // 2^250 - 2^0
|
||||
|
||||
t.Square(&t) // 2^251 - 2^1
|
||||
t.Square(&t) // 2^252 - 2^2
|
||||
t.Square(&t) // 2^253 - 2^3
|
||||
t.Square(&t) // 2^254 - 2^4
|
||||
t.Square(&t) // 2^255 - 2^5
|
||||
|
||||
return v.Multiply(&t, &z11) // 2^255 - 21
|
||||
}
|
||||
|
||||
// Set sets v = a, and returns v.
|
||||
func (v *Element) Set(a *Element) *Element {
|
||||
*v = *a
|
||||
return v
|
||||
}
|
||||
|
||||
// SetBytes sets v to x, which must be a 32-byte little-endian encoding.
|
||||
//
|
||||
// Consistent with RFC 7748, the most significant bit (the high bit of the
|
||||
// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1)
|
||||
// are accepted. Note that this is laxer than specified by RFC 8032.
|
||||
func (v *Element) SetBytes(x []byte) *Element {
|
||||
if len(x) != 32 {
|
||||
panic("edwards25519: invalid field element input size")
|
||||
}
|
||||
|
||||
// Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
|
||||
v.l0 = binary.LittleEndian.Uint64(x[0:8])
|
||||
v.l0 &= maskLow51Bits
|
||||
// Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
|
||||
v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
|
||||
v.l1 &= maskLow51Bits
|
||||
// Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
|
||||
v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
|
||||
v.l2 &= maskLow51Bits
|
||||
// Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
|
||||
v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1
|
||||
v.l3 &= maskLow51Bits
|
||||
// Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51).
|
||||
// Note: not bytes 25:33, shift 4, to avoid overread.
|
||||
v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12
|
||||
v.l4 &= maskLow51Bits
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// Bytes returns the canonical 32-byte little-endian encoding of v.
|
||||
func (v *Element) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [32]byte
|
||||
return v.bytes(&out)
|
||||
}
|
||||
|
||||
func (v *Element) bytes(out *[32]byte) []byte {
|
||||
t := *v
|
||||
t.reduce()
|
||||
|
||||
var buf [8]byte
|
||||
for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
|
||||
bitsOffset := i * 51
|
||||
binary.LittleEndian.PutUint64(buf[:], l<<uint(bitsOffset%8))
|
||||
for i, bb := range buf {
|
||||
off := bitsOffset/8 + i
|
||||
if off >= len(out) {
|
||||
break
|
||||
}
|
||||
out[off] |= bb
|
||||
}
|
||||
}
|
||||
|
||||
return out[:]
|
||||
}
|
||||
|
||||
// Equal returns 1 if v and u are equal, and 0 otherwise.
|
||||
func (v *Element) Equal(u *Element) int {
|
||||
sa, sv := u.Bytes(), v.Bytes()
|
||||
return subtle.ConstantTimeCompare(sa, sv)
|
||||
}
|
||||
|
||||
// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise.
|
||||
func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
|
||||
|
||||
// Select sets v to a if cond == 1, and to b if cond == 0.
|
||||
func (v *Element) Select(a, b *Element, cond int) *Element {
|
||||
m := mask64Bits(cond)
|
||||
v.l0 = (m & a.l0) | (^m & b.l0)
|
||||
v.l1 = (m & a.l1) | (^m & b.l1)
|
||||
v.l2 = (m & a.l2) | (^m & b.l2)
|
||||
v.l3 = (m & a.l3) | (^m & b.l3)
|
||||
v.l4 = (m & a.l4) | (^m & b.l4)
|
||||
return v
|
||||
}
|
||||
|
||||
// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v.
|
||||
func (v *Element) Swap(u *Element, cond int) {
|
||||
m := mask64Bits(cond)
|
||||
t := m & (v.l0 ^ u.l0)
|
||||
v.l0 ^= t
|
||||
u.l0 ^= t
|
||||
t = m & (v.l1 ^ u.l1)
|
||||
v.l1 ^= t
|
||||
u.l1 ^= t
|
||||
t = m & (v.l2 ^ u.l2)
|
||||
v.l2 ^= t
|
||||
u.l2 ^= t
|
||||
t = m & (v.l3 ^ u.l3)
|
||||
v.l3 ^= t
|
||||
u.l3 ^= t
|
||||
t = m & (v.l4 ^ u.l4)
|
||||
v.l4 ^= t
|
||||
u.l4 ^= t
|
||||
}
|
||||
|
||||
// IsNegative returns 1 if v is negative, and 0 otherwise.
|
||||
func (v *Element) IsNegative() int {
|
||||
return int(v.Bytes()[0] & 1)
|
||||
}
|
||||
|
||||
// Absolute sets v to |u|, and returns v.
|
||||
func (v *Element) Absolute(u *Element) *Element {
|
||||
return v.Select(new(Element).Negate(u), u, u.IsNegative())
|
||||
}
|
||||
|
||||
// Multiply sets v = x * y, and returns v.
|
||||
func (v *Element) Multiply(x, y *Element) *Element {
|
||||
feMul(v, x, y)
|
||||
return v
|
||||
}
|
||||
|
||||
// Square sets v = x * x, and returns v.
|
||||
func (v *Element) Square(x *Element) *Element {
|
||||
feSquare(v, x)
|
||||
return v
|
||||
}
|
||||
|
||||
// Mult32 sets v = x * y, and returns v.
|
||||
func (v *Element) Mult32(x *Element, y uint32) *Element {
|
||||
x0lo, x0hi := mul51(x.l0, y)
|
||||
x1lo, x1hi := mul51(x.l1, y)
|
||||
x2lo, x2hi := mul51(x.l2, y)
|
||||
x3lo, x3hi := mul51(x.l3, y)
|
||||
x4lo, x4hi := mul51(x.l4, y)
|
||||
v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
|
||||
v.l1 = x1lo + x0hi
|
||||
v.l2 = x2lo + x1hi
|
||||
v.l3 = x3lo + x2hi
|
||||
v.l4 = x4lo + x3hi
|
||||
// The hi portions are going to be only 32 bits, plus any previous excess,
|
||||
// so we can skip the carry propagation.
|
||||
return v
|
||||
}
|
||||
|
||||
// mul51 returns lo + hi * 2⁵¹ = a * b.
|
||||
func mul51(a uint64, b uint32) (lo uint64, hi uint64) {
|
||||
mh, ml := bits.Mul64(a, uint64(b))
|
||||
lo = ml & maskLow51Bits
|
||||
hi = (mh << 13) | (ml >> 51)
|
||||
return
|
||||
}
|
||||
|
||||
// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3.
|
||||
func (v *Element) Pow22523(x *Element) *Element {
|
||||
var t0, t1, t2 Element
|
||||
|
||||
t0.Square(x) // x^2
|
||||
t1.Square(&t0) // x^4
|
||||
t1.Square(&t1) // x^8
|
||||
t1.Multiply(x, &t1) // x^9
|
||||
t0.Multiply(&t0, &t1) // x^11
|
||||
t0.Square(&t0) // x^22
|
||||
t0.Multiply(&t1, &t0) // x^31
|
||||
t1.Square(&t0) // x^62
|
||||
for i := 1; i < 5; i++ { // x^992
|
||||
t1.Square(&t1)
|
||||
}
|
||||
t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1
|
||||
t1.Square(&t0) // 2^11 - 2
|
||||
for i := 1; i < 10; i++ { // 2^20 - 2^10
|
||||
t1.Square(&t1)
|
||||
}
|
||||
t1.Multiply(&t1, &t0) // 2^20 - 1
|
||||
t2.Square(&t1) // 2^21 - 2
|
||||
for i := 1; i < 20; i++ { // 2^40 - 2^20
|
||||
t2.Square(&t2)
|
||||
}
|
||||
t1.Multiply(&t2, &t1) // 2^40 - 1
|
||||
t1.Square(&t1) // 2^41 - 2
|
||||
for i := 1; i < 10; i++ { // 2^50 - 2^10
|
||||
t1.Square(&t1)
|
||||
}
|
||||
t0.Multiply(&t1, &t0) // 2^50 - 1
|
||||
t1.Square(&t0) // 2^51 - 2
|
||||
for i := 1; i < 50; i++ { // 2^100 - 2^50
|
||||
t1.Square(&t1)
|
||||
}
|
||||
t1.Multiply(&t1, &t0) // 2^100 - 1
|
||||
t2.Square(&t1) // 2^101 - 2
|
||||
for i := 1; i < 100; i++ { // 2^200 - 2^100
|
||||
t2.Square(&t2)
|
||||
}
|
||||
t1.Multiply(&t2, &t1) // 2^200 - 1
|
||||
t1.Square(&t1) // 2^201 - 2
|
||||
for i := 1; i < 50; i++ { // 2^250 - 2^50
|
||||
t1.Square(&t1)
|
||||
}
|
||||
t0.Multiply(&t1, &t0) // 2^250 - 1
|
||||
t0.Square(&t0) // 2^251 - 2
|
||||
t0.Square(&t0) // 2^252 - 4
|
||||
return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3)
|
||||
}
|
||||
|
||||
// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion.
|
||||
var sqrtM1 = &Element{1718705420411056, 234908883556509,
|
||||
2233514472574048, 2117202627021982, 765476049583133}
|
||||
|
||||
// SqrtRatio sets r to the non-negative square root of the ratio of u and v.
|
||||
//
|
||||
// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio
|
||||
// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
|
||||
// and returns r and 0.
|
||||
func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) {
|
||||
var a, b Element
|
||||
|
||||
// r = (u * v3) * (u * v7)^((p-5)/8)
|
||||
v2 := a.Square(v)
|
||||
uv3 := b.Multiply(u, b.Multiply(v2, v))
|
||||
uv7 := a.Multiply(uv3, a.Square(v2))
|
||||
r.Multiply(uv3, r.Pow22523(uv7))
|
||||
|
||||
check := a.Multiply(v, a.Square(r)) // check = v * r^2
|
||||
|
||||
uNeg := b.Negate(u)
|
||||
correctSignSqrt := check.Equal(u)
|
||||
flippedSignSqrt := check.Equal(uNeg)
|
||||
flippedSignSqrtI := check.Equal(uNeg.Multiply(uNeg, sqrtM1))
|
||||
|
||||
rPrime := b.Multiply(r, sqrtM1) // r_prime = SQRT_M1 * r
|
||||
// r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
|
||||
r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI)
|
||||
|
||||
r.Absolute(r) // Choose the nonnegative square root.
|
||||
return r, correctSignSqrt | flippedSignSqrt
|
||||
}
|
16
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go
generated
vendored
16
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go
generated
vendored
@ -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)
|
379
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s
generated
vendored
379
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s
generated
vendored
@ -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
|
12
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go
generated
vendored
12
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go
generated
vendored
@ -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) }
|
16
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go
generated
vendored
16
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go
generated
vendored
@ -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
|
||||
}
|
43
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s
generated
vendored
43
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s
generated
vendored
@ -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
|
12
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go
generated
vendored
12
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go
generated
vendored
@ -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()
|
||||
}
|
264
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go
generated
vendored
264
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go
generated
vendored
@ -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
|
||||
}
|
1
src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint
generated
vendored
1
src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint
generated
vendored
@ -1 +0,0 @@
|
||||
b0c49ae9f59d233526f8934262c5bbbe14d4358d
|
19
src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh
generated
vendored
19
src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh
generated
vendored
@ -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
|
2
src/vendor/modules.txt
vendored
2
src/vendor/modules.txt
vendored
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user