package crypto

import (
	
	
	
	
	
	

	pb 
	
)

// Ed25519PrivateKey is an ed25519 private key.
type Ed25519PrivateKey struct {
	k ed25519.PrivateKey
}

// Ed25519PublicKey is an ed25519 public key.
type Ed25519PublicKey struct {
	k ed25519.PublicKey
}

// GenerateEd25519Key generates a new ed25519 private and public key pair.
func ( io.Reader) (PrivKey, PubKey, error) {
	, ,  := ed25519.GenerateKey()
	if  != nil {
		return nil, nil, 
	}

	return &Ed25519PrivateKey{
			k: ,
		},
		&Ed25519PublicKey{
			k: ,
		},
		nil
}

// Type of the private key (Ed25519).
func ( *Ed25519PrivateKey) () pb.KeyType {
	return pb.KeyType_Ed25519
}

// Raw private key bytes.
func ( *Ed25519PrivateKey) () ([]byte, error) {
	// The Ed25519 private key contains two 32-bytes curve points, the private
	// key and the public key.
	// It makes it more efficient to get the public key without re-computing an
	// elliptic curve multiplication.
	 := make([]byte, len(.k))
	copy(, .k)

	return , nil
}

func ( *Ed25519PrivateKey) () []byte {
	return .k[ed25519.PrivateKeySize-ed25519.PublicKeySize:]
}

// Equals compares two ed25519 private keys.
func ( *Ed25519PrivateKey) ( Key) bool {
	,  := .(*Ed25519PrivateKey)
	if ! {
		return basicEquals(, )
	}

	return subtle.ConstantTimeCompare(.k, .k) == 1
}

// GetPublic returns an ed25519 public key from a private key.
func ( *Ed25519PrivateKey) () PubKey {
	return &Ed25519PublicKey{k: .pubKeyBytes()}
}

// Sign returns a signature from an input message.
func ( *Ed25519PrivateKey) ( []byte) ( []byte,  error) {
	defer func() { catch.HandlePanic(recover(), &, "ed15519 signing") }()

	return ed25519.Sign(.k, ), nil
}

// Type of the public key (Ed25519).
func ( *Ed25519PublicKey) () pb.KeyType {
	return pb.KeyType_Ed25519
}

// Raw public key bytes.
func ( *Ed25519PublicKey) () ([]byte, error) {
	return .k, nil
}

// Equals compares two ed25519 public keys.
func ( *Ed25519PublicKey) ( Key) bool {
	,  := .(*Ed25519PublicKey)
	if ! {
		return basicEquals(, )
	}

	return bytes.Equal(.k, .k)
}

// Verify checks a signature against the input data.
func ( *Ed25519PublicKey) ( []byte,  []byte) ( bool,  error) {
	defer func() {
		catch.HandlePanic(recover(), &, "ed15519 signature verification")

		// To be safe.
		if  != nil {
			 = false
		}
	}()
	return ed25519.Verify(.k, , ), nil
}

// UnmarshalEd25519PublicKey returns a public key from input bytes.
func ( []byte) (PubKey, error) {
	if len() != 32 {
		return nil, errors.New("expect ed25519 public key data size to be 32")
	}

	return &Ed25519PublicKey{
		k: ed25519.PublicKey(),
	}, nil
}

// UnmarshalEd25519PrivateKey returns a private key from input bytes.
func ( []byte) (PrivKey, error) {
	switch len() {
	case ed25519.PrivateKeySize + ed25519.PublicKeySize:
		// Remove the redundant public key. See issue #36.
		 := [ed25519.PrivateKeySize:]
		 := [ed25519.PrivateKeySize-ed25519.PublicKeySize : ed25519.PrivateKeySize]
		if subtle.ConstantTimeCompare(, ) == 0 {
			return nil, errors.New("expected redundant ed25519 public key to be redundant")
		}

		// No point in storing the extra data.
		 := make([]byte, ed25519.PrivateKeySize)
		copy(, [:ed25519.PrivateKeySize])
		 = 
	case ed25519.PrivateKeySize:
	default:
		return nil, fmt.Errorf(
			"expected ed25519 data size to be %d or %d, got %d",
			ed25519.PrivateKeySize,
			ed25519.PrivateKeySize+ed25519.PublicKeySize,
			len(),
		)
	}

	return &Ed25519PrivateKey{
		k: ed25519.PrivateKey(),
	}, nil
}