// 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 struct {
	name          string
	generate      func(io.Reader) (*ecdh.PrivateKey, error)
	newPrivateKey func([]byte) (*ecdh.PrivateKey, error)
	newPublicKey  func(publicKey []byte) (*ecdh.PublicKey, error)
	sharedSecret  func(*ecdh.PrivateKey, *ecdh.PublicKey) (sharedSecret []byte, err error)
}

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

func ( *nistCurve) ( io.Reader) (*PrivateKey, error) {
	if boring.Enabled &&  == boring.RandReader {
		, ,  := boring.GenerateKeyECDH(.name)
		if  != nil {
			return nil, 
		}
		,  := .PublicKey()
		if  != nil {
			return nil, 
		}
		 := &PrivateKey{
			curve:      ,
			privateKey: ,
			publicKey:  &PublicKey{curve: , publicKey: .Bytes(), boring: },
			boring:     ,
		}
		return , nil
	}

	if fips140only.Enabled && !fips140only.ApprovedRandomReader() {
		return nil, errors.New("crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-only mode")
	}

	,  := .generate()
	if  != nil {
		return nil, 
	}

	 := &PrivateKey{
		curve:      ,
		privateKey: .Bytes(),
		fips:       ,
		publicKey: &PublicKey{
			curve:     ,
			publicKey: .PublicKey().Bytes(),
			fips:      .PublicKey(),
		},
	}
	if boring.Enabled {
		,  := boring.NewPrivateKeyECDH(.name, .privateKey)
		if  != nil {
			return nil, 
		}
		,  := .PublicKey()
		if  != nil {
			return nil, 
		}
		.boring = 
		.publicKey.boring = 
	}
	return , nil
}

func ( *nistCurve) ( []byte) (*PrivateKey, error) {
	if boring.Enabled {
		,  := boring.NewPrivateKeyECDH(.name, )
		if  != nil {
			return nil, errors.New("crypto/ecdh: invalid private key")
		}
		,  := .PublicKey()
		if  != nil {
			return nil, errors.New("crypto/ecdh: invalid private key")
		}
		 := &PrivateKey{
			curve:      ,
			privateKey: bytes.Clone(),
			publicKey:  &PublicKey{curve: , publicKey: .Bytes(), boring: },
			boring:     ,
		}
		return , nil
	}

	,  := .newPrivateKey()
	if  != nil {
		return nil, 
	}
	 := &PrivateKey{
		curve:      ,
		privateKey: bytes.Clone(),
		fips:       ,
		publicKey: &PublicKey{
			curve:     ,
			publicKey: .PublicKey().Bytes(),
			fips:      .PublicKey(),
		},
	}
	return , nil
}

func ( *nistCurve) ( []byte) (*PublicKey, error) {
	// Reject the point at infinity and compressed encodings.
	// Note that boring.NewPublicKeyECDH would accept them.
	if len() == 0 || [0] != 4 {
		return nil, errors.New("crypto/ecdh: invalid public key")
	}
	 := &PublicKey{
		curve:     ,
		publicKey: bytes.Clone(),
	}
	if boring.Enabled {
		,  := boring.NewPublicKeyECDH(.name, .publicKey)
		if  != nil {
			return nil, errors.New("crypto/ecdh: invalid public key")
		}
		.boring = 
	} else {
		,  := .newPublicKey()
		if  != nil {
			return nil, 
		}
		.fips = 
	}
	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)
	}
	return .sharedSecret(.fips, .fips)
}

// 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{
	name: "P-256",
	generate: func( io.Reader) (*ecdh.PrivateKey, error) {
		return ecdh.GenerateKey(ecdh.P256(), )
	},
	newPrivateKey: func( []byte) (*ecdh.PrivateKey, error) {
		return ecdh.NewPrivateKey(ecdh.P256(), )
	},
	newPublicKey: func( []byte) (*ecdh.PublicKey, error) {
		return ecdh.NewPublicKey(ecdh.P256(), )
	},
	sharedSecret: func( *ecdh.PrivateKey,  *ecdh.PublicKey) ( []byte,  error) {
		return ecdh.ECDH(ecdh.P256(), , )
	},
}

// 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{
	name: "P-384",
	generate: func( io.Reader) (*ecdh.PrivateKey, error) {
		return ecdh.GenerateKey(ecdh.P384(), )
	},
	newPrivateKey: func( []byte) (*ecdh.PrivateKey, error) {
		return ecdh.NewPrivateKey(ecdh.P384(), )
	},
	newPublicKey: func( []byte) (*ecdh.PublicKey, error) {
		return ecdh.NewPublicKey(ecdh.P384(), )
	},
	sharedSecret: func( *ecdh.PrivateKey,  *ecdh.PublicKey) ( []byte,  error) {
		return ecdh.ECDH(ecdh.P384(), , )
	},
}

// 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{
	name: "P-521",
	generate: func( io.Reader) (*ecdh.PrivateKey, error) {
		return ecdh.GenerateKey(ecdh.P521(), )
	},
	newPrivateKey: func( []byte) (*ecdh.PrivateKey, error) {
		return ecdh.NewPrivateKey(ecdh.P521(), )
	},
	newPublicKey: func( []byte) (*ecdh.PublicKey, error) {
		return ecdh.NewPublicKey(ecdh.P521(), )
	},
	sharedSecret: func( *ecdh.PrivateKey,  *ecdh.PublicKey) ( []byte,  error) {
		return ecdh.ECDH(ecdh.P521(), , )
	},
}