package crypto

import (
	
	
	
	
	
	
	
	
	

	pb 
	
)

// ECDSAPrivateKey is an implementation of an ECDSA private key
type ECDSAPrivateKey struct {
	priv *ecdsa.PrivateKey
}

// ECDSAPublicKey is an implementation of an ECDSA public key
type ECDSAPublicKey struct {
	pub *ecdsa.PublicKey
}

// ECDSASig holds the r and s values of an ECDSA signature
type ECDSASig struct {
	R, S *big.Int
}

var (
	// ErrNotECDSAPubKey is returned when the public key passed is not an ecdsa public key
	ErrNotECDSAPubKey = errors.New("not an ecdsa public key")
	// ErrNilSig is returned when the signature is nil
	ErrNilSig = errors.New("sig is nil")
	// ErrNilPrivateKey is returned when a nil private key is provided
	ErrNilPrivateKey = errors.New("private key is nil")
	// ErrNilPublicKey is returned when a nil public key is provided
	ErrNilPublicKey = errors.New("public key is nil")
	// ECDSACurve is the default ecdsa curve used
	ECDSACurve = elliptic.P256()
)

// GenerateECDSAKeyPair generates a new ecdsa private and public key
func ( io.Reader) (PrivKey, PubKey, error) {
	return GenerateECDSAKeyPairWithCurve(ECDSACurve, )
}

// GenerateECDSAKeyPairWithCurve generates a new ecdsa private and public key with a specified curve
func ( elliptic.Curve,  io.Reader) (PrivKey, PubKey, error) {
	,  := ecdsa.GenerateKey(, )
	if  != nil {
		return nil, nil, 
	}

	return &ECDSAPrivateKey{}, &ECDSAPublicKey{&.PublicKey}, nil
}

// ECDSAKeyPairFromKey generates a new ecdsa private and public key from an input private key
func ( *ecdsa.PrivateKey) (PrivKey, PubKey, error) {
	if  == nil {
		return nil, nil, ErrNilPrivateKey
	}

	return &ECDSAPrivateKey{}, &ECDSAPublicKey{&.PublicKey}, nil
}

// ECDSAPublicKeyFromPubKey generates a new ecdsa public key from an input public key
func ( ecdsa.PublicKey) (PubKey, error) {
	return &ECDSAPublicKey{pub: &}, nil
}

// MarshalECDSAPrivateKey returns x509 bytes from a private key
func ( ECDSAPrivateKey) ( []byte,  error) {
	defer func() { catch.HandlePanic(recover(), &, "ECDSA private-key marshal") }()
	return x509.MarshalECPrivateKey(.priv)
}

// MarshalECDSAPublicKey returns x509 bytes from a public key
func ( ECDSAPublicKey) ( []byte,  error) {
	defer func() { catch.HandlePanic(recover(), &, "ECDSA public-key marshal") }()
	return x509.MarshalPKIXPublicKey(.pub)
}

// UnmarshalECDSAPrivateKey returns a private key from x509 bytes
func ( []byte) ( PrivKey,  error) {
	defer func() { catch.HandlePanic(recover(), &, "ECDSA private-key unmarshal") }()

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

	return &ECDSAPrivateKey{}, nil
}

// UnmarshalECDSAPublicKey returns the public key from x509 bytes
func ( []byte) ( PubKey,  error) {
	defer func() { catch.HandlePanic(recover(), &, "ECDSA public-key unmarshal") }()

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

	,  := .(*ecdsa.PublicKey)
	if ! {
		return nil, ErrNotECDSAPubKey
	}

	return &ECDSAPublicKey{}, nil
}

// Type returns the key type
func ( *ECDSAPrivateKey) () pb.KeyType {
	return pb.KeyType_ECDSA
}

// Raw returns x509 bytes from a private key
func ( *ECDSAPrivateKey) () ( []byte,  error) {
	defer func() { catch.HandlePanic(recover(), &, "ECDSA private-key marshal") }()
	return x509.MarshalECPrivateKey(.priv)
}

// Equals compares two private keys
func ( *ECDSAPrivateKey) ( Key) bool {
	return basicEquals(, )
}

// Sign returns the signature of the input data
func ( *ECDSAPrivateKey) ( []byte) ( []byte,  error) {
	defer func() { catch.HandlePanic(recover(), &, "ECDSA signing") }()
	 := sha256.Sum256()
	, ,  := ecdsa.Sign(rand.Reader, .priv, [:])
	if  != nil {
		return nil, 
	}

	return asn1.Marshal(ECDSASig{
		R: ,
		S: ,
	})
}

// GetPublic returns a public key
func ( *ECDSAPrivateKey) () PubKey {
	return &ECDSAPublicKey{&.priv.PublicKey}
}

// Type returns the key type
func ( *ECDSAPublicKey) () pb.KeyType {
	return pb.KeyType_ECDSA
}

// Raw returns x509 bytes from a public key
func ( *ECDSAPublicKey) () ([]byte, error) {
	return x509.MarshalPKIXPublicKey(.pub)
}

// Equals compares to public keys
func ( *ECDSAPublicKey) ( Key) bool {
	return basicEquals(, )
}

// Verify compares data to a signature
func ( *ECDSAPublicKey) (,  []byte) ( bool,  error) {
	defer func() {
		catch.HandlePanic(recover(), &, "ECDSA signature verification")

		// Just to be extra paranoid.
		if  != nil {
			 = false
		}
	}()

	 := new(ECDSASig)
	if ,  := asn1.Unmarshal(, );  != nil {
		return false, 
	}

	 := sha256.Sum256()

	return ecdsa.Verify(.pub, [:], .R, .S), nil
}