//! Challenge nonces — single-use, receiver-issued, sender-echoed.
//!
//! Spec reference: `draft-vandemeent-iddrop-00` §7.3 (`challenge_nonce`).

use rand::RngCore;
use serde::{Deserialize, Serialize};

/// A 16-byte challenge nonce. The receiver issues it; the sender echoes
/// it unchanged in the sealed response. Mismatch on the receiver side =
/// `IddropError::NonceMismatch`.
///
/// JSON wire format: lowercase hex string, 32 chars.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ChallengeNonce(#[serde(with = "hex_bytes")] pub [u8; 16]);

impl ChallengeNonce {
    /// Generate a fresh cryptographic challenge nonce.
    pub fn new() -> Self {
        let mut b = [0u8; 16];
        rand::thread_rng().fill_bytes(&mut b);
        Self(b)
    }

    /// Render as lowercase hex.
    pub fn to_hex(&self) -> String {
        hex::encode(self.0)
    }
}

impl Default for ChallengeNonce {
    fn default() -> Self {
        Self::new()
    }
}

mod hex_bytes {
    use serde::{Deserialize, Deserializer, Serializer};

    pub fn serialize<S: Serializer>(bytes: &[u8; 16], s: S) -> Result<S::Ok, S::Error> {
        s.serialize_str(&hex::encode(bytes))
    }

    pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<[u8; 16], D::Error> {
        let s = String::deserialize(d)?;
        let v = hex::decode(&s).map_err(serde::de::Error::custom)?;
        if v.len() != 16 {
            return Err(serde::de::Error::custom("nonce must be 16 bytes"));
        }
        let mut out = [0u8; 16];
        out.copy_from_slice(&v);
        Ok(out)
    }
}
