package crypto

import (
	"crypto/rand"
	"errors"

	"golang.org/x/crypto/curve25519"
)

// KeyExchange manages the exchange of keys
type curve25519KEX struct {
	secret [32]byte
	public [32]byte
}

var _ KeyExchange = &curve25519KEX{}

// NewCurve25519KEX creates a new KeyExchange using Curve25519, see https://cr.yp.to/ecdh.html
func NewCurve25519KEX() (KeyExchange, error) {
	c := &curve25519KEX{}
	if _, err := rand.Read(c.secret[:]); err != nil {
		return nil, errors.New("Curve25519: could not create private key")
	}
	// See https://cr.yp.to/ecdh.html
	c.secret[0] &= 248
	c.secret[31] &= 127
	c.secret[31] |= 64
	curve25519.ScalarBaseMult(&c.public, &c.secret)
	return c, nil
}

func (c *curve25519KEX) PublicKey() []byte {
	return c.public[:]
}

func (c *curve25519KEX) CalculateSharedKey(otherPublic []byte) ([]byte, error) {
	if len(otherPublic) != 32 {
		return nil, errors.New("Curve25519: expected public key of 32 byte")
	}
	var res [32]byte
	var otherPublicArray [32]byte
	copy(otherPublicArray[:], otherPublic)
	curve25519.ScalarMult(&res, &c.secret, &otherPublicArray)
	return res[:], nil
}