willow25 0.4.0

A ready-to-use implementation of the Willow specifications.
Documentation
#![allow(clippy::module_inception)]

use core::fmt;

#[cfg(feature = "dev")]
use arbitrary::Arbitrary;

use ed25519_dalek::VerifyingKey;
use signature::Verifier;
use ufotofu::codec_prelude::*;

use order_theory::{
    GreatestElement, LeastElement, LowerSemilattice, PredecessorExceptForLeast,
    SuccessorExceptForGreatest, TryPredecessor, TrySuccessor, UpperSemilattice,
};

use crate::entry::ed25519::VerifyingKeyOrDummy;
use crate::prelude::*;

/// The width of a [`NamespaceId`] in bytes: 32.
///
/// [Specification](https://macromania--macromania.deno.dev/specs/willow25/index.html#willow25_data_model)
pub const NAMESPACE_ID_WIDTH: usize = 32;

/// The type of [NamespaceIds](https://willowprotocol.org/specs/data-model/index.html#NamespaceId) used by [Willow’25](https://macromania--macromania.deno.dev/specs/willow25/index.html#willow25_data_model).
///
/// Namespaces serve to group Willow data into independent universes — entries with nonequal namespace ids cannot overwrite each other. Namespaces further anchor the system of read and write access in Willow: namespace ids are public keys of a [digital signature system](https://ed25519.cr.yp.to/), and knowledge of the corresponding secret key allow you to issue [read and write capabilities](https://willowprotocol.org/specs/meadowcap/) for the namespace.
///
/// More precisely, Willow25 provides two different kinds of namespaces: [owned namespaces](https://willowprotocol.org/specs/meadowcap/#owned_namespace) and [communal namespaces](https://willowprotocol.org/specs/meadowcap/#communal_namespace). In an owned namespace, you need the corresponding secret key to issue initial read or write capabilities, and these then give access to the full namespace. In a communal namespace, the secret key grants no special privileges: everyone can create read and write capabilities, but these are only scoped to individual [subspaces](https://willowprotocol.org/specs/data-model/index.html#subspace) for which the creator knows the [`SubspaceSecret`](crate::prelude::SubspaceSecret). See the [`meadowcap`] module for more details on how access control works and how to refine it to more granular scopes.
///
/// That all said, you can also simply think of namespace ids as glorified `[u8; 32]` arrays. That perspective should be sufficient as long as you do not need to care about cryptographic details.
///
/// You will typically obtain a namespace id either by [randomly generating a key pair](super::randomly_generate_namespace), by cloning an existing namespace id, or by creating it from raw bytes via [`NamespaceId::from_bytes`]. See the [Willow25 specification](https://willowprotocol.org/specs/willow25/index.html#willow25_crypto) if you want to work with raw bytes — while every `[u8; 32]` can be converted into a [`NamespaceId`], some of these do not correspond to canonic public key encodings and thus always fail signature verification.
///
/// ```
/// use rand::rngs::OsRng;
/// use willow25::prelude::*;
///
/// let mut csprng = OsRng; // cryptographically secure pseudo-random number generator
/// let (namespace_id, _secret) = randomly_generate_communal_namespace(&mut csprng);
/// assert!(namespace_id.is_communal());
///
/// let namespace_id2 = NamespaceId::from_bytes(&[17; NAMESPACE_ID_WIDTH]);
/// assert!(namespace_id2.is_owned()); // Least-significant bit is one.
/// assert_eq!(namespace_id2.as_bytes(), &[17; 32]);
/// ```
#[derive(Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "dev", derive(Arbitrary))]
pub struct NamespaceId(VerifyingKeyOrDummy);

/// Implemented lexicographically on the compressed Edwards y coordinate encoding.
impl PartialOrd for NamespaceId {
    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

/// Implemented lexicographically on the compressed Edwards y coordinate encoding.
impl Ord for NamespaceId {
    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
        self.0.as_bytes().cmp(other.0.as_bytes())
    }
}

impl fmt::Debug for NamespaceId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("NamespaceId")
            .field(&NamespaceIdHexFormatter(self.0.to_bytes()))
            .finish()
    }
}

impl NamespaceId {
    /// Returns whether this namespace id defines a [communal namespace](https://willowprotocol.org/specs/meadowcap/index.html#is_communal) or not.
    ///
    /// A namespace id is communal iff its least significant bit is zero.
    ///
    /// ```
    /// use willow25::prelude::*;
    ///
    /// let namespace_id1 = NamespaceId::from_bytes(&[16; NAMESPACE_ID_WIDTH]);
    /// assert!(namespace_id1.is_communal());
    ///
    /// let namespace_id2 = NamespaceId::from_bytes(&[17; NAMESPACE_ID_WIDTH]);
    /// assert!(!namespace_id2.is_communal());
    /// ```
    pub fn is_communal(&self) -> bool {
        self.as_bytes()[NAMESPACE_ID_WIDTH - 1] % 2 == 0
    }

    /// Returns whether this namespace id defines an [owned namespace](https://willowprotocol.org/specs/meadowcap/index.html#is_communal) or not.
    ///
    /// A namespace id is owned iff its least significant bit is one.
    ///
    /// ```
    /// use willow25::prelude::*;
    ///
    /// let namespace_id1 = NamespaceId::from_bytes(&[17; NAMESPACE_ID_WIDTH]);
    /// assert!(namespace_id1.is_owned());
    ///
    /// let namespace_id2 = NamespaceId::from_bytes(&[16; NAMESPACE_ID_WIDTH]);
    /// assert!(!namespace_id2.is_owned());
    /// ```
    pub fn is_owned(&self) -> bool {
        !self.is_communal()
    }

    /// Returns a new [`NamespaceId`] corresponding to the supplied bytes.
    ///
    /// ```
    /// use willow25::prelude::*;
    ///
    /// let namespace_id = NamespaceId::from_bytes(&[17; NAMESPACE_ID_WIDTH]);
    /// assert_eq!(namespace_id.as_bytes(), &[17; NAMESPACE_ID_WIDTH]);
    /// ```
    pub fn from_bytes(bytes: &[u8; NAMESPACE_ID_WIDTH]) -> Self {
        Self(VerifyingKeyOrDummy::from_bytes(bytes))
    }

    /// Returns a reference to the raw bytes that make up this namespace id.
    ///
    /// ```
    /// use willow25::prelude::*;
    ///
    /// let namespace_id = NamespaceId::from_bytes(&[17; NAMESPACE_ID_WIDTH]);
    /// assert_eq!(namespace_id.as_bytes(), &[17; NAMESPACE_ID_WIDTH]);
    /// ```
    pub fn as_bytes(&self) -> &[u8; NAMESPACE_ID_WIDTH] {
        self.0.as_bytes()
    }

    /// Returns the raw bytes that make up this namespace id.
    ///
    /// ```
    /// use willow25::prelude::*;
    ///
    /// let namespace_id = NamespaceId::from_bytes(&[17; NAMESPACE_ID_WIDTH]);
    /// assert_eq!(namespace_id.to_bytes(), [17; NAMESPACE_ID_WIDTH]);
    /// ```
    pub fn to_bytes(&self) -> [u8; NAMESPACE_ID_WIDTH] {
        self.0.to_bytes()
    }

    /// Creates a namespace id from an ed25519 verifying key.
    ///
    /// ```
    /// use willow25::prelude::*;
    ///
    /// let from_key = NamespaceId::from_ed25519_verifying_key(
    ///     ed25519_dalek::VerifyingKey::from_bytes(&[17; 32]).unwrap(),
    /// );
    /// let from_bytes = NamespaceId::from_bytes(&[17; NAMESPACE_ID_WIDTH]);
    ///
    /// assert_eq!(from_key, from_bytes);
    /// ```
    pub fn from_ed25519_verifying_key(verifying_key: VerifyingKey) -> Self {
        Self(VerifyingKeyOrDummy::Key(verifying_key))
    }
}

impl From<[u8; NAMESPACE_ID_WIDTH]> for NamespaceId {
    fn from(value: [u8; NAMESPACE_ID_WIDTH]) -> Self {
        Self::from_bytes(&value)
    }
}

impl LeastElement for NamespaceId {
    fn least() -> Self {
        Self(VerifyingKeyOrDummy::least())
    }
}

impl GreatestElement for NamespaceId {
    fn greatest() -> Self {
        Self(VerifyingKeyOrDummy::greatest())
    }
}

impl LowerSemilattice for NamespaceId {
    fn greatest_lower_bound(&self, other: &Self) -> Self {
        Self(self.0.greatest_lower_bound(&other.0))
    }
}

impl UpperSemilattice for NamespaceId {
    fn least_upper_bound(&self, other: &Self) -> Self {
        Self(self.0.least_upper_bound(&other.0))
    }
}

impl TryPredecessor for NamespaceId {
    fn try_predecessor(&self) -> Option<Self> {
        self.0.try_predecessor().map(Self)
    }
}

impl TrySuccessor for NamespaceId {
    fn try_successor(&self) -> Option<Self> {
        self.0.try_successor().map(Self)
    }
}

impl PredecessorExceptForLeast for NamespaceId {}

impl SuccessorExceptForGreatest for NamespaceId {}

struct NamespaceIdHexFormatter<const N: usize>([u8; N]);

impl<const N: usize> fmt::Debug for NamespaceIdHexFormatter<N> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // First render a `+` if the namespace is communal, and a `-` if it is not.
        if self.0[31] & 0b0000_0001 == 0 {
            f.write_str("+")?;
        } else {
            f.write_str("-")?;
        }

        // Then render the bytes as lowercase hex.
        let mut buffer = const_hex::Buffer::<N>::new();
        let printed = buffer.format(&self.0);
        f.write_str(printed)
    }
}

impl Encodable for NamespaceId {
    async fn encode<C>(&self, consumer: &mut C) -> Result<(), C::Error>
    where
        C: BulkConsumer<Item = u8> + ?Sized,
    {
        self.0.encode(consumer).await
    }
}

impl EncodableKnownLength for NamespaceId {
    fn len_of_encoding(&self) -> usize {
        self.0.len_of_encoding()
    }
}

impl Decodable for NamespaceId {
    type ErrorReason = Infallible;

    async fn decode<P>(
        producer: &mut P,
    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorReason>>
    where
        P: BulkProducer<Item = u8> + ?Sized,
        Self: Sized,
    {
        Ok(Self(VerifyingKeyOrDummy::decode(producer).await?))
    }
}

impl DecodableCanonic for NamespaceId {
    type ErrorCanonic = Infallible;

    async fn decode_canonic<P>(
        producer: &mut P,
    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorCanonic>>
    where
        P: BulkProducer<Item = u8> + ?Sized,
        Self: Sized,
    {
        Ok(Self(VerifyingKeyOrDummy::decode_canonic(producer).await?))
    }
}

impl Verifier<NamespaceSignature> for NamespaceId {
    fn verify(&self, msg: &[u8], signature: &NamespaceSignature) -> Result<(), signature::Error> {
        match self.0 {
            VerifyingKeyOrDummy::Dummy(_) => Err(signature::Error::new()),
            VerifyingKeyOrDummy::Key(sk) => sk.verify_strict(msg, signature.into()),
        }
    }
}