// 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 ecdhimport ()typenistCurve[ nistPoint[]] struct {namestringnewPointfunc() scalarOrder []byte}// nistPoint is a generic constraint for the nistec Point types.typenistPoint[ any] interface {Bytes() []byteBytesX() ([]byte, error)SetBytes([]byte) (, error)ScalarMult(, []byte) (, error)ScalarBaseMult([]byte) (, error)}func ( *nistCurve[]) () string {return .name}varerrInvalidPrivateKey = errors.New("crypto/ecdh: invalid private key")func ( *nistCurve[]) ( io.Reader) (*PrivateKey, error) {ifboring.Enabled && == boring.RandReader { , , := boring.GenerateKeyECDH(.name)if != nil {returnnil, }returnnewBoringPrivateKey(, , ) } := make([]byte, len(.scalarOrder))randutil.MaybeReadByte()for {if , := io.ReadFull(, ); != nil {returnnil, }// 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 &.scalarOrder[0] == &p521Order[0] { [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. [1] ^= 0x42 , := .NewPrivateKey()if == errInvalidPrivateKey {continue }return , }}func ( *nistCurve[]) ( []byte) (*PrivateKey, error) {iflen() != len(.scalarOrder) {returnnil, errors.New("crypto/ecdh: invalid private key size") }ifisZero() || !isLess(, .scalarOrder) {returnnil, errInvalidPrivateKey }ifboring.Enabled { , := boring.NewPrivateKeyECDH(.name, )if != nil {returnnil, }returnnewBoringPrivateKey(, , ) } := &PrivateKey{curve: ,privateKey: append([]byte{}, ...), }return , nil}func ( Curve, *boring.PrivateKeyECDH, []byte) (*PrivateKey, error) { := &PrivateKey{curve: ,boring: ,privateKey: append([]byte(nil), ...), }return , nil}func ( *nistCurve[]) ( *PrivateKey) *PublicKey {boring.Unreachable()if .curve != {panic("crypto/ecdh: internal error: converting the wrong key type") } , := .newPoint().ScalarBaseMult(.privateKey)if != 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") } := .Bytes()iflen() == 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: .curve,publicKey: , }}// isZero returns whether a is all zeroes in constant time.func ( []byte) bool {varbytefor , := range { |= }return == 0}// isLess returns whether a < b, where a and b are big-endian buffers of the// same length and shorter than 72 bytes.func (, []byte) bool {iflen() != len() {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.iflen() > 72 {panic("crypto/ecdh: internal error: isLess input too large") } , := make([]byte, 72), make([]byte, 72)for := range { [], [] = [len()--1], [len()--1] }// Perform a subtraction with borrow.varuint64for := 0; < len(); += 8 { , := binary.LittleEndian.Uint64([:]), binary.LittleEndian.Uint64([:]) _, = bits.Sub64(, , ) }// If there is a borrow at the end of the operation, then a < b.return == 1}func ( *nistCurve[]) ( []byte) (*PublicKey, error) {// Reject the point at infinity and compressed encodings.iflen() == 0 || [0] != 4 {returnnil, errors.New("crypto/ecdh: invalid public key") } := &PublicKey{curve: ,publicKey: append([]byte{}, ...), }ifboring.Enabled { , := boring.NewPublicKeyECDH(.name, .publicKey)if != nil {returnnil, } .boring = } else {// SetBytes also checks that the point is on the curve.if , := .newPoint().SetBytes(); != nil {returnnil, } }return , nil}func ( *nistCurve[]) ( *PrivateKey, *PublicKey) ([]byte, error) {// Note that this function can't return an error, as NewPublicKey rejects // invalid points and the point at infinity, and NewPrivateKey rejects // invalid scalars and the zero value. BytesX returns an error for the point // at infinity, but in a prime order group such as the NIST curves that can // only be the result of a scalar multiplication if one of the inputs is the // zero scalar or the point at infinity.ifboring.Enabled {returnboring.ECDH(.boring, .boring) }boring.Unreachable() , := .newPoint().SetBytes(.publicKey)if != nil {returnnil, }if , := .ScalarMult(, .privateKey); != nil {returnnil, }return .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, which can// be used for equality checks and switch statements.func () Curve { returnp256 }varp256 = &nistCurve[*nistec.P256Point]{name: "P-256",newPoint: nistec.NewP256Point,scalarOrder: p256Order,}varp256Order = []byte{0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,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, which can// be used for equality checks and switch statements.func () Curve { returnp384 }varp384 = &nistCurve[*nistec.P384Point]{name: "P-384",newPoint: nistec.NewP384Point,scalarOrder: p384Order,}varp384Order = []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, 0x0d, 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, which can// be used for equality checks and switch statements.func () Curve { returnp521 }varp521 = &nistCurve[*nistec.P521Point]{name: "P-521",newPoint: nistec.NewP521Point,scalarOrder: p521Order,}varp521Order = []byte{0x01, 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, 0x01, 0x48, 0xf7, 0x09, 0xa5, 0xd0,0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c, 0x47, 0xae,0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38, 0x64, 0x09}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.