radio/iroh-willow/src/proto/wgps/challenge.rs

use iroh_blobs::Hash;
use rand::Rng;
use rand_core::CryptoRngCore;
use serde::{Deserialize, Serialize};

use crate::proto::data_model::DIGEST_LENGTH;

pub const CHALLENGE_LENGTH: usize = 32;
pub const CHALLENGE_HASH_LENGTH: usize = DIGEST_LENGTH;

#[derive(derive_more::Debug, Copy, Clone, Eq, PartialEq)]
pub struct ChallengeHash(
    #[debug("{}..", data_encoding::HEXLOWER.encode(&self.0))] [u8; CHALLENGE_HASH_LENGTH],
);

impl Serialize for ChallengeHash {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        use serde::ser::SerializeTuple;
        let mut seq = serializer.serialize_tuple(32)?;
        for byte in &self.0 {
            seq.serialize_element(byte)?;
        }
        seq.end()
    }
}

impl<'de> Deserialize<'de> for ChallengeHash {
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        struct Visitor;
        impl<'de> serde::de::Visitor<'de> for Visitor {
            type Value = ChallengeHash;
            fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(f, "32 bytes")
            }
            fn visit_seq<A: serde::de::SeqAccess<'de>>(self, mut seq: A) -> Result<ChallengeHash, A::Error> {
                let mut bytes = [0u8; 32];
                for (i, byte) in bytes.iter_mut().enumerate() {
                    *byte = seq.next_element()?.ok_or_else(|| serde::de::Error::invalid_length(i, &self))?;
                }
                Ok(ChallengeHash(bytes))
            }
        }
        deserializer.deserialize_tuple(32, Visitor)
    }
}

impl ChallengeHash {
    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }

    pub fn from_bytes(bytes: [u8; CHALLENGE_HASH_LENGTH]) -> Self {
        Self(bytes)
    }
}

#[derive(derive_more::Debug, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub struct AccessChallenge(
    #[debug("{}..", data_encoding::HEXLOWER.encode(&self.0))] AccessChallengeBytes,
);

pub type AccessChallengeBytes = [u8; CHALLENGE_LENGTH];

impl Default for AccessChallenge {
    fn default() -> Self {
        Self::generate()
    }
}

impl AccessChallenge {
    pub fn generate() -> Self {
        Self(rand::random())
    }

    pub fn generate_with_rng(rng: &mut impl CryptoRngCore) -> Self {
        Self(rng.gen())
    }

    pub fn as_bytes(&self) -> &[u8] {
        &self.0
    }

    pub fn to_bytes(&self) -> [u8; 32] {
        self.0
    }

    pub fn hash(&self) -> ChallengeHash {
        ChallengeHash(*Hash::new(self.0).as_bytes())
    }
}

Synonyms

radio/iroh-willow/src/session/challenge.rs

Neighbours