// 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) {
	 := make([]byte, x25519PrivateKeySize)
	randutil.MaybeReadByte()
	if ,  := io.ReadFull(, );  != nil {
		return nil, 
	}
	return .NewPrivateKey()
}

func ( *x25519Curve) ( []byte) (*PrivateKey, error) {
	if len() != x25519PrivateKeySize {
		return nil, errors.New("crypto/ecdh: invalid private key size")
	}
	return &PrivateKey{
		curve:      ,
		privateKey: append([]byte{}, ...),
	}, nil
}

func ( *x25519Curve) ( *PrivateKey) *PublicKey {
	if .curve !=  {
		panic("crypto/ecdh: internal error: converting the wrong key type")
	}
	 := &PublicKey{
		curve:     .curve,
		publicKey: make([]byte, x25519PublicKeySize),
	}
	 := [32]byte{9}
	x25519ScalarMult(.publicKey, .privateKey, [:])
	return 
}

func ( *x25519Curve) ( []byte) (*PublicKey, error) {
	if len() != x25519PublicKeySize {
		return nil, errors.New("crypto/ecdh: invalid public key")
	}
	return &PublicKey{
		curve:     ,
		publicKey: append([]byte{}, ...),
	}, 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())
}