//! Ed25519 signature primitives.
//!
//! `PublicKey` and `Sig` are byte-array newtypes that serialise portably
//! through CBOR; conversion to/from ed25519-dalek types happens at the
//! cryptographic boundary (`verify`, `from_signing_key`).

use std::fmt;

use ed25519_dalek::{Signature as EdSignature, Verifier, VerifyingKey};
use serde::de::{Error as DeError, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};

/// Errors produced by signature verification.
#[derive(Debug, thiserror::Error)]
pub enum SignatureError {
    /// The 32 public-key bytes do not decode to a valid Ed25519 point.
    #[error("invalid public key")]
    InvalidPublicKey,
    /// Signature verification failed.
    #[error("bad signature")]
    BadSignature,
}

/// 32-byte Ed25519 public key.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct PublicKey(pub [u8; 32]);

impl PublicKey {
    /// Derive the public key from a signing key.
    pub fn from_signing_key(key: &ed25519_dalek::SigningKey) -> Self {
        Self(key.verifying_key().to_bytes())
    }

    /// Verify `sig` against `msg` under this public key.
    pub fn verify(&self, msg: &[u8], sig: &Sig) -> Result<(), SignatureError> {
        let vk = VerifyingKey::from_bytes(&self.0).map_err(|_| SignatureError::InvalidPublicKey)?;
        let ed = EdSignature::from_bytes(&sig.0);
        vk.verify(msg, &ed)
            .map_err(|_| SignatureError::BadSignature)
    }
}

impl fmt::Debug for PublicKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "PublicKey(")?;
        for byte in self.0.iter().take(4) {
            write!(f, "{byte:02x}")?;
        }
        write!(f, "..)")
    }
}

/// 64-byte Ed25519 signature.
///
/// Serde default array impls cap at length 32; this newtype provides
/// hand-rolled impls that round-trip through CBOR as a byte string (major type
/// 2) for canonical, compact encoding.
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Sig(pub [u8; 64]);

impl fmt::Debug for Sig {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Sig(")?;
        for byte in self.0.iter().take(4) {
            write!(f, "{byte:02x}")?;
        }
        write!(f, "..)")
    }
}

impl Serialize for Sig {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_bytes(&self.0)
    }
}

struct SigVisitor;

impl<'de> Visitor<'de> for SigVisitor {
    type Value = Sig;

    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("a 64-byte Ed25519 signature")
    }

    fn visit_bytes<E: DeError>(self, value: &[u8]) -> Result<Sig, E> {
        if value.len() != 64 {
            return Err(E::invalid_length(value.len(), &self));
        }
        let mut bytes = [0u8; 64];
        bytes.copy_from_slice(value);
        Ok(Sig(bytes))
    }

    fn visit_byte_buf<E: DeError>(self, value: Vec<u8>) -> Result<Sig, E> {
        self.visit_bytes(&value)
    }

    fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Sig, A::Error> {
        let mut bytes = [0u8; 64];
        for (idx, slot) in bytes.iter_mut().enumerate() {
            *slot = seq
                .next_element()?
                .ok_or_else(|| <A::Error as DeError>::invalid_length(idx, &"64"))?;
        }
        Ok(Sig(bytes))
    }
}

impl<'de> Deserialize<'de> for Sig {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_bytes(SigVisitor)
    }
}
