// 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 (
	
	
	
	
	
	
	
)

type nistCurve[ nistPoint[]] struct {
	name        string
	newPoint    func() 
	scalarOrder []byte
}

// nistPoint is a generic constraint for the nistec Point types.
type nistPoint[ any] interface {
	Bytes() []byte
	BytesX() ([]byte, error)
	SetBytes([]byte) (, error)
	ScalarMult(, []byte) (, error)
	ScalarBaseMult([]byte) (, error)
}

func ( *nistCurve[]) () string {
	return .name
}

var errInvalidPrivateKey = errors.New("crypto/ecdh: invalid private key")

func ( *nistCurve[]) ( io.Reader) (*PrivateKey, error) {
	if boring.Enabled &&  == boring.RandReader {
		, ,  := boring.GenerateKeyECDH(.name)
		if  != nil {
			return nil, 
		}
		return newBoringPrivateKey(, , )
	}

	 := make([]byte, len(.scalarOrder))
	randutil.MaybeReadByte()
	for {
		if ,  := io.ReadFull(, );  != nil {
			return nil, 
		}

		// 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) {
	if len() != len(.scalarOrder) {
		return nil, errors.New("crypto/ecdh: invalid private key size")
	}
	if isZero() || !isLess(, .scalarOrder) {
		return nil, errInvalidPrivateKey
	}
	if boring.Enabled {
		,  := boring.NewPrivateKeyECDH(.name, )
		if  != nil {
			return nil, 
		}
		return newBoringPrivateKey(, , )
	}
	 := &PrivateKey{
		curve:      ,
		privateKey: append([]byte{}, ...),
	}
	return , nil
}

func newBoringPrivateKey( 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()
	if len() == 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 isZero( []byte) bool {
	var  byte
	for ,  := 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 isLess(,  []byte) bool {
	if len() != 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.
	if len() > 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.
	var  uint64
	for  := 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.
	if len() == 0 || [0] != 4 {
		return nil, errors.New("crypto/ecdh: invalid public key")
	}
	 := &PublicKey{
		curve:     ,
		publicKey: append([]byte{}, ...),
	}
	if boring.Enabled {
		,  := boring.NewPublicKeyECDH(.name, .publicKey)
		if  != nil {
			return nil, 
		}
		.boring = 
	} else {
		// SetBytes also checks that the point is on the curve.
		if ,  := .newPoint().SetBytes();  != nil {
			return nil, 
		}
	}
	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.

	if boring.Enabled {
		return boring.ECDH(.boring, .boring)
	}

	boring.Unreachable()
	,  := .newPoint().SetBytes(.publicKey)
	if  != nil {
		return nil, 
	}
	if ,  := .ScalarMult(, .privateKey);  != nil {
		return nil, 
	}
	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 { return p256 }

var p256 = &nistCurve[*nistec.P256Point]{
	name:        "P-256",
	newPoint:    nistec.NewP256Point,
	scalarOrder: p256Order,
}

var p256Order = []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 { 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, 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 { return p521 }

var p521 = &nistCurve[*nistec.P521Point]{
	name:        "P-521",
	newPoint:    nistec.NewP521Point,
	scalarOrder: p521Order,
}

var p521Order = []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}