package key

import (
	
	
	
	
	
	
	

	
)

const (
	// PublicKeySize is the size of an Ed25519 public key, in bytes.
	PublicKeySize = ed25519.PublicKeySize
	// PrivateKeySize is the size of an Ed25519 private key, in bytes.
	PrivateKeySize = ed25519.PrivateKeySize
	// SeedSize is the size of an Ed25519 private key seed, in bytes.
	SeedSize = ed25519.SeedSize
	// SignatureSize is the size of an Ed25519 signature, in bytes.
	SignatureSize = ed25519.SignatureSize
)

// zBase32 is the z-base-32 encoding used by pkarr (https://pkarr.org) for
// endpoint-id domain names. Its alphabet differs from RFC 4648 base32.
const zBase32Alphabet = "ybndrfg8ejkmcpqxot1uwisza345h769"

// Errors returned when parsing keys.
var (
	// ErrInvalidKeyData is returned when bytes do not represent a valid
	// Ed25519 curve point.
	ErrInvalidKeyData = errors.New("data is not a valid public key")
	// ErrInvalidKeyLength is returned when key bytes have the wrong length.
	ErrInvalidKeyLength = errors.New("invalid length")
	// ErrDecodeHex is returned when a string cannot be decoded as hex.
	ErrDecodeHex = errors.New("failed to decode hex string")
	// ErrDecodeBase32 is returned when a string cannot be decoded as base32.
	ErrDecodeBase32 = errors.New("failed to decode base32 string")
)

// PublicKey is a public Ed25519 key. It is verified to be a valid curve point
// when created.
//
// The zero value is not usable; construct a PublicKey with [NewPublicKey],
// [ParsePublicKey], or [SecretKey.Public].
type PublicKey struct {
	bytes [PublicKeySize]byte
}

// EndpointID is a network-facing identifier for an endpoint.
//
// Use EndpointID in network-facing APIs and [PublicKey] when performing
// cryptographic operations.
type EndpointID PublicKey

// NewPublicKey constructs a PublicKey from a 32-byte array. It returns
// [ErrInvalidKeyData] if the bytes do not decompress to a valid Ed25519 curve
// point. It never fails for bytes returned from [PublicKey.Bytes].
func ( [PublicKeySize]byte) (PublicKey, error) {
	if ,  := new(edwards25519.Point).SetBytes([:]);  != nil {
		return PublicKey{}, ErrInvalidKeyData
	}
	return PublicKey{bytes: }, nil
}

// NewEndpointID constructs an EndpointID from a 32-byte array.
func ( [PublicKeySize]byte) (EndpointID, error) {
	,  := NewPublicKey()
	if  != nil {
		return EndpointID{}, 
	}
	return .EndpointID(), nil
}

// PublicKeyFromEd25519 constructs a PublicKey from a crypto/ed25519 public key.
func ( ed25519.PublicKey) (PublicKey, error) {
	return PublicKeyFromSlice()
}

// PublicKeyFromSlice constructs a PublicKey from a byte slice. It returns
// [ErrInvalidKeyLength] if the slice is not 32 bytes and [ErrInvalidKeyData] if
// the bytes are not a valid curve point.
func ( []byte) (PublicKey, error) {
	if len() != PublicKeySize {
		return PublicKey{}, ErrInvalidKeyLength
	}
	var  [PublicKeySize]byte
	copy([:], )
	return NewPublicKey()
}

// EndpointIDFromSlice constructs an EndpointID from a byte slice.
func ( []byte) (EndpointID, error) {
	,  := PublicKeyFromSlice()
	if  != nil {
		return EndpointID{}, 
	}
	return .EndpointID(), nil
}

// EndpointID returns the endpoint identifier for k.
func ( PublicKey) () EndpointID { return EndpointID() }

// Bytes returns the public key as a 32-byte array.
func ( PublicKey) () [PublicKeySize]byte { return .bytes }

// Ed25519 returns the key as a crypto/ed25519 public key. The returned slice is
// a copy and may be modified by the caller.
func ( PublicKey) () ed25519.PublicKey {
	 := make(ed25519.PublicKey, PublicKeySize)
	copy(, .bytes[:])
	return 
}

// Verify reports whether sig is a valid signature of message by k. It returns
// nil on success and [ErrInvalidSignature] otherwise.
//
// Verification uses crypto/ed25519 (cofactored, RFC 8032). The Rust reference
// uses ed25519-dalek's verify_strict (cofactorless). The two agree for every
// signature an honest iroh peer produces; they differ only for adversarially
// malleable signatures, which iroh drops anyway. This divergence is benign for
// iroh's drop-on-failure model (relay handshake, TLS raw-key, and pkarr packet
// verification all reject on failure).
func ( PublicKey) ( []byte,  Signature) error {
	return .verify(, )
}

// IsZero reports whether k is the unusable zero value.
func ( PublicKey) () bool { return  == PublicKey{} }

// Equal reports whether k and other are the same key.
func ( PublicKey) ( PublicKey) bool { return .bytes == .bytes }

// Compare returns -1, 0, or +1 comparing k and other by their raw bytes. It
// gives PublicKey a total order suitable for sorting and map-free ordered use.
func ( PublicKey) ( PublicKey) int {
	return bytes.Compare(.bytes[:], .bytes[:])
}

// String returns the lowercase-hex encoding of the key. It is the canonical
// human-readable form and round-trips through [ParsePublicKey].
func ( PublicKey) () string {
	return hex.EncodeToString(.bytes[:])
}

// Short returns a short, friendly hex string of the first 5 bytes of the key,
// for logging. It is not a complete or parseable representation.
func ( PublicKey) () string {
	return hex.EncodeToString(.bytes[:5])
}

// PublicKey returns id as a public key for cryptographic operations.
func ( EndpointID) () PublicKey { return PublicKey() }

// Bytes returns the endpoint id as a 32-byte array.
func ( EndpointID) () [PublicKeySize]byte { return .PublicKey().Bytes() }

// IsZero reports whether id is the unusable zero value.
func ( EndpointID) () bool { return  == EndpointID{} }

// Equal reports whether id and other are the same endpoint id.
func ( EndpointID) ( EndpointID) bool {
	return .PublicKey().Equal(.PublicKey())
}

// Compare returns -1, 0, or +1 comparing id and other by their raw bytes. It
// gives EndpointID a total order suitable for sorting and map-free ordered use.
func ( EndpointID) ( EndpointID) int {
	return .PublicKey().Compare(.PublicKey())
}

// String returns the lowercase-hex encoding of the endpoint id. It is the
// canonical human-readable form and round-trips through [ParseEndpointID].
func ( EndpointID) () string { return .PublicKey().String() }

// Short returns a short, friendly hex string of the first 5 bytes of the
// endpoint id, for logging. It is not a complete or parseable representation.
func ( EndpointID) () string { return .PublicKey().Short() }

// Z32 encodes the endpoint id in z-base-32, the encoding used by pkarr domain
// names.
func ( EndpointID) () string {
	 := .PublicKey()
	return encodeZBase32(.bytes[:])
}

// ParseEndpointIDZ32 parses an endpoint id from its z-base-32 encoding.
func ( string) (EndpointID, error) {
	,  := decodeZBase32()
	if  != nil {
		return EndpointID{}, ErrDecodeBase32
	}
	return EndpointIDFromSlice()
}

// ParsePublicKey parses a PublicKey from its hex or base32 string form. A string
// of exactly 64 characters is decoded as lowercase hex; otherwise it is decoded
// as RFC 4648 base32 (no padding, case-insensitive). [PublicKey.String] always
// produces the hex form.
func ( string) (PublicKey, error) {
	,  := decodeBase32OrHex()
	if  != nil {
		return PublicKey{}, 
	}
	return NewPublicKey()
}

// ParseEndpointID parses an EndpointID from its hex or base32 string form.
func ( string) (EndpointID, error) {
	,  := ParsePublicKey()
	if  != nil {
		return EndpointID{}, 
	}
	return .EndpointID(), nil
}

// MarshalText implements encoding.TextMarshaler, producing the hex form.
func ( PublicKey) () ([]byte, error) {
	return []byte(.String()), nil
}

// UnmarshalText implements encoding.TextUnmarshaler, parsing the hex or base32
// form.
func ( *PublicKey) ( []byte) error {
	,  := ParsePublicKey(string())
	if  != nil {
		return 
	}
	* = 
	return nil
}

// MarshalText implements encoding.TextMarshaler, producing the hex form.
func ( EndpointID) () ([]byte, error) {
	return []byte(.String()), nil
}

// UnmarshalText implements encoding.TextUnmarshaler, parsing the hex or base32
// form.
func ( *EndpointID) ( []byte) error {
	,  := ParseEndpointID(string())
	if  != nil {
		return 
	}
	* = 
	return nil
}

// MarshalBinary implements encoding.BinaryMarshaler, producing the 32 raw bytes.
func ( PublicKey) () ([]byte, error) {
	 := .bytes
	return [:], nil
}

// UnmarshalBinary implements encoding.BinaryUnmarshaler from 32 raw bytes.
func ( *PublicKey) ( []byte) error {
	,  := PublicKeyFromSlice()
	if  != nil {
		return 
	}
	* = 
	return nil
}

// MarshalBinary implements encoding.BinaryMarshaler, producing the 32 raw bytes.
func ( EndpointID) () ([]byte, error) {
	return .PublicKey().MarshalBinary()
}

// UnmarshalBinary implements encoding.BinaryUnmarshaler from 32 raw bytes.
func ( *EndpointID) ( []byte) error {
	,  := EndpointIDFromSlice()
	if  != nil {
		return 
	}
	* = 
	return nil
}

// SecretKey is a secret endpoint identity key. Its public part can always be
// recovered.
//
// Go has no destructors, so unlike the Rust original this type is not cleared
// automatically. Call [SecretKey.Clear] to overwrite the key material when a
// long-lived secret is no longer needed.
//
// The zero value is not usable; construct with [GenerateSecretKey],
// [NewSecretKey], or [ParseSecretKey].
type SecretKey struct {
	signing ed25519.PrivateKey // 64 bytes: seed||public
}

// GenerateSecretKey generates a new SecretKey using crypto/ed25519.
func () (SecretKey, error) {
	, ,  := ed25519.GenerateKey(rand.Reader)
	if  != nil {
		return SecretKey{}, fmt.Errorf("generate secret key: %w", )
	}
	return SecretKey{signing: }, nil
}

// NewSecretKey constructs a SecretKey from its 32-byte seed.
func ( [SeedSize]byte) SecretKey {
	return SecretKey{signing: ed25519.NewKeyFromSeed([:])}
}

// SecretKeyFromEd25519 constructs a SecretKey from a crypto/ed25519 private key.
// The private key is copied.
func ( ed25519.PrivateKey) (SecretKey, error) {
	if len() != PrivateKeySize {
		return SecretKey{}, ErrInvalidKeyLength
	}
	return SecretKey{signing: append(ed25519.PrivateKey(nil), ...)}, nil
}

// SecretKeyFromSlice constructs a SecretKey from a 32-byte seed slice. It
// returns [ErrInvalidKeyLength] if the slice is not 32 bytes.
func ( []byte) (SecretKey, error) {
	if len() != SeedSize {
		return SecretKey{}, ErrInvalidKeyLength
	}
	var  [SeedSize]byte
	copy([:], )
	return NewSecretKey(), nil
}

// ParseSecretKey parses a SecretKey from its hex or base32 string form, matching
// the rules of [ParsePublicKey].
func ( string) (SecretKey, error) {
	,  := decodeBase32OrHex()
	if  != nil {
		return SecretKey{}, 
	}
	return NewSecretKey(), nil
}

// Public returns the public key of this secret key.
func ( SecretKey) () PublicKey {
	,  := PublicKeyFromEd25519(.signing.Public().(ed25519.PublicKey))
	return 
}

// Sign signs msg and returns the signature.
func ( SecretKey) ( []byte) Signature {
	return .sign()
}

// Ed25519 returns the key as a crypto/ed25519 private key. The returned key is
// a copy and satisfies crypto.Signer.
func ( SecretKey) () ed25519.PrivateKey {
	return append(ed25519.PrivateKey(nil), .signing...)
}

// Bytes returns the 32-byte seed of the secret key. The public part can be
// recovered from it.
func ( SecretKey) () [SeedSize]byte {
	var  [SeedSize]byte
	copy([:], .signing.Seed())
	return 
}

// Clear overwrites k's key material and resets k to the zero value. It does not
// clear copies already made by value or by [SecretKey.Bytes], [SecretKey.Ed25519],
// or [SecretKey.MarshalBinary].
func ( *SecretKey) () {
	if  == nil {
		return
	}
	clear(.signing)
	.signing = nil
}

// IsZero reports whether k is the unusable zero value.
func ( SecretKey) () bool { return .signing == nil }

// MarshalBinary implements encoding.BinaryMarshaler, producing the 32-byte seed.
func ( SecretKey) () ([]byte, error) {
	 := .Bytes()
	return [:], nil
}

// UnmarshalBinary implements encoding.BinaryUnmarshaler from a 32-byte seed.
func ( *SecretKey) ( []byte) error {
	,  := SecretKeyFromSlice()
	if  != nil {
		return 
	}
	* = 
	return nil
}

// Signature is a signature produced by a [SecretKey].
type Signature struct {
	bytes [SignatureSize]byte
}

// NewSignature constructs a Signature from its 64 raw bytes.
func ( [SignatureSize]byte) Signature {
	return Signature{bytes: }
}

// SignatureFromEd25519 constructs a Signature from a crypto/ed25519 signature.
func ( []byte) (Signature, error) {
	return SignatureFromSlice()
}

// SignatureFromSlice constructs a Signature from a byte slice. It returns
// [ErrInvalidSignatureParse] if the slice is not 64 bytes.
func ( []byte) (Signature, error) {
	if len() != SignatureSize {
		return Signature{}, ErrInvalidSignatureParse
	}
	var  [SignatureSize]byte
	copy([:], )
	return Signature{bytes: }, nil
}

// Bytes returns the signature as a 64-byte array.
func ( Signature) () [SignatureSize]byte { return .bytes }

// Ed25519 returns the signature bytes used by crypto/ed25519. The returned
// slice is a copy and may be modified by the caller.
func ( Signature) () []byte {
	 := make([]byte, SignatureSize)
	copy(, .bytes[:])
	return 
}

// String returns the lowercase-hex encoding of the signature.
func ( Signature) () string { return hex.EncodeToString(.bytes[:]) }

// MarshalText implements encoding.TextMarshaler, producing the hex form.
func ( Signature) () ([]byte, error) {
	return []byte(.String()), nil
}

// UnmarshalText implements encoding.TextUnmarshaler, parsing the hex form.
func ( *Signature) ( []byte) error {
	,  := hex.DecodeString(string())
	if  != nil {
		return ErrDecodeHex
	}
	,  := SignatureFromSlice()
	if  != nil {
		return 
	}
	* = 
	return nil
}

// MarshalBinary implements encoding.BinaryMarshaler, producing the 64 raw
// signature bytes.
func ( Signature) () ([]byte, error) {
	 := .bytes
	return [:], nil
}

// UnmarshalBinary implements encoding.BinaryUnmarshaler from 64 raw bytes.
func ( *Signature) ( []byte) error {
	,  := SignatureFromSlice()
	if  != nil {
		return 
	}
	* = 
	return nil
}

// Equal reports whether s and other are the same signature.
func ( Signature) ( Signature) bool { return .bytes == .bytes }

// Signature parsing and verification errors.
var (
	// ErrInvalidSignatureParse is returned when bytes cannot be parsed as an
	// Ed25519 signature.
	ErrInvalidSignatureParse = errors.New("could not parse ed25519 signature")
	// ErrInvalidSignature is returned when signature verification fails.
	ErrInvalidSignature = errors.New("invalid signature")
)

// decodeBase32OrHex decodes a 32-byte value from a key's string form: 64-char
// strings are lowercase hex, others are RFC 4648 base32 (no padding).
func decodeBase32OrHex( string) ([32]byte, error) {
	var  [32]byte
	if len() == PublicKeySize*2 {
		,  := hex.DecodeString()
		if  != nil {
			return , ErrDecodeHex
		}
		copy([:], )
		return , nil
	}
	,  := decodeStdBase32NoPad(strings.ToUpper())
	if  != nil {
		return , ErrDecodeBase32
	}
	if len() != PublicKeySize {
		return , ErrInvalidKeyLength
	}
	copy([:], )
	return , nil
}