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

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 () Curve { return x25519 }

var x25519 = &x25519Curve{}

type x25519Curve struct{}

func ( *x25519Curve) () string {
	return "X25519"
}

func ( *x25519Curve) ( io.Reader) (*PrivateKey, error) {
	if fips140only.Enabled {
		return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
	}
	 := make([]byte, x25519PrivateKeySize)
	randutil.MaybeReadByte()
	if ,  := io.ReadFull(, );  != nil {
		return nil, 
	}
	return .NewPrivateKey()
}

func ( *x25519Curve) ( []byte) (*PrivateKey, error) {
	if fips140only.Enabled {
		return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
	}
	if len() != x25519PrivateKeySize {
		return nil, errors.New("crypto/ecdh: invalid private key size")
	}
	 := make([]byte, x25519PublicKeySize)
	 := [32]byte{9}
	x25519ScalarMult(, , [:])
	// We don't check for the all-zero public key here because the scalar is
	// never zero because of clamping, and the basepoint is not the identity in
	// the prime-order subgroup(s).
	return &PrivateKey{
		curve:      ,
		privateKey: bytes.Clone(),
		publicKey:  &PublicKey{curve: , publicKey: },
	}, nil
}

func ( *x25519Curve) ( []byte) (*PublicKey, error) {
	if fips140only.Enabled {
		return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
	}
	if len() != x25519PublicKeySize {
		return nil, errors.New("crypto/ecdh: invalid public key")
	}
	return &PublicKey{
		curve:     ,
		publicKey: bytes.Clone(),
	}, nil
}

func ( *x25519Curve) ( *PrivateKey,  *PublicKey) ([]byte, error) {
	 := make([]byte, x25519SharedSecretSize)
	x25519ScalarMult(, .privateKey, .publicKey)
	if isZero() {
		return nil, errors.New("crypto/ecdh: bad X25519 remote ECDH input: low order point")
	}
	return , nil
}

func x25519ScalarMult(, ,  []byte) {
	var  [32]byte

	copy([:], [:])
	[0] &= 248
	[31] &= 127
	[31] |= 64

	var , , , , , ,  field.Element
	.SetBytes([:])
	.One()
	.Set(&)
	.One()

	 := 0
	for  := 254;  >= 0; -- {
		 := [/8] >> uint(&7)
		 &= 1
		 ^= int()
		.Swap(&, )
		.Swap(&, )
		 = int()

		.Subtract(&, &)
		.Subtract(&, &)
		.Add(&, &)
		.Add(&, &)
		.Multiply(&, &)
		.Multiply(&, &)
		.Square(&)
		.Square(&)
		.Add(&, &)
		.Subtract(&, &)
		.Multiply(&, &)
		.Subtract(&, &)
		.Square(&)

		.Mult32(&, 121666)
		.Square(&)
		.Add(&, &)
		.Multiply(&, &)
		.Multiply(&, &)
	}

	.Swap(&, )
	.Swap(&, )

	.Invert(&)
	.Multiply(&, &)
	copy([:], .Bytes())
}

// isZero reports whether x is all zeroes in constant time.
func isZero( []byte) bool {
	var  byte
	for ,  := range  {
		 |= 
	}
	return  == 0
}