cesrox 2.0.0-beta.6

Implementation of Composable Event Streaming Representation (CESR)
Documentation
use std::str::FromStr;

use crate::{
    conversion::{adjust_with_num, b64_to_num},
    derivation_code::DerivationCode,
    error::Error,
};

#[derive(Debug, PartialEq, Eq)]
pub enum GroupCode {
    IndexedControllerSignatures(u16),
    IndexedWitnessSignatures(u16),
    NontransferableReceiptCouples(u16),
    FirstSeenReplyCouples(u16),
    // Composed Base64 couple, snu+dig of given delegators or issuers event
    SealSourceCouples(u16),
    AnchoringEventSeals(u16),
    /// CESR 2.0 `-Y` "Trans Last Est Evt Indexed Signature Group(s)".
    /// Each entry: identifier prefix + nested `IndexedControllerSignatures` group.
    /// Used to bind a transferable signer's AID to indexed signatures when the
    /// signature is verified against the signer's *current* establishment keys
    /// (queries, replies, mailbox traffic).
    TransLastIdxSigGroups(u16),
    #[cfg(feature = "cesr-proof")]
    PathedMaterialQuadruple(u16),
    TSPPayload(u16),
}

impl DerivationCode for GroupCode {
    fn value_size(&self) -> usize {
        0
    }

    fn soft_size(&self) -> usize {
        2
    }

    fn hard_size(&self) -> usize {
        2
    }

    fn to_str(&self) -> String {
        let (code, count) = match self {
            GroupCode::IndexedControllerSignatures(count) => ("-K", count),
            GroupCode::IndexedWitnessSignatures(count) => ("-L", count),
            GroupCode::NontransferableReceiptCouples(count) => ("-M", count),
            GroupCode::FirstSeenReplyCouples(count) => ("-O", count),
            GroupCode::SealSourceCouples(count) => ("-S", count),
            GroupCode::AnchoringEventSeals(count) => ("-T", count),
            GroupCode::TransLastIdxSigGroups(count) => ("-Y", count),
            #[cfg(feature = "cesr-proof")]
            GroupCode::PathedMaterialQuadruple(len) => ("-P", len),
            GroupCode::TSPPayload(len) => ("-Z", len),
        };
        [code, &adjust_with_num(count.to_owned(), self.soft_size())].join("")
    }
}

impl FromStr for GroupCode {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let code = s.get(..2).ok_or(Error::EmptyCodeError)?;
        let count_part = s.get(2..4).ok_or(Error::EmptyCodeError)?;
        let count = b64_to_num(count_part)?;
        match code {
            "-K" => Ok(Self::IndexedControllerSignatures(count)),
            "-L" => Ok(Self::IndexedWitnessSignatures(count)),
            "-M" => Ok(Self::NontransferableReceiptCouples(count)),
            "-N" => todo!(),
            "-O" => Ok(Self::FirstSeenReplyCouples(count)),
            #[cfg(feature = "cesr-proof")]
            "-P" => Ok(Self::PathedMaterialQuadruple(count)),
            "-R" => todo!(),
            "-S" => Ok(Self::SealSourceCouples(count)),
            "-T" => Ok(Self::AnchoringEventSeals(count)),
            "-U" => todo!(),
            "-V" => todo!(),
            "-W" => todo!(),
            "-X" => todo!(),
            "-Y" => Ok(Self::TransLastIdxSigGroups(count)),
            "-Z" => Ok(Self::TSPPayload(count)),
            _ => Err(Error::UnknownCodeError),
        }
    }
}

#[test]
pub fn test_group_codes_to_str() -> Result<(), Error> {
    assert_eq!(GroupCode::IndexedControllerSignatures(3).to_str(), "-KAD");
    assert_eq!(GroupCode::IndexedWitnessSignatures(30).to_str(), "-LAe");
    assert_eq!(
        GroupCode::NontransferableReceiptCouples(100).to_str(),
        "-MBk"
    );
    assert_eq!(GroupCode::FirstSeenReplyCouples(127).to_str(), "-OB_");
    assert_eq!(GroupCode::SealSourceCouples(0).to_str(), "-SAA");
    assert_eq!(GroupCode::AnchoringEventSeals(4095).to_str(), "-T__");
    Ok(())
}

#[test]
pub fn test_group_codes_from_str() -> Result<(), Error> {
    assert_eq!(GroupCode::IndexedControllerSignatures(3), "-KAD".parse()?);
    assert_eq!(GroupCode::IndexedWitnessSignatures(30), "-LAe".parse()?);
    assert_eq!(
        GroupCode::NontransferableReceiptCouples(100),
        "-MBk".parse()?
    );
    assert_eq!(GroupCode::SealSourceCouples(0), "-SAA".parse()?);
    assert_eq!(GroupCode::FirstSeenReplyCouples(127), "-OB_".parse()?);
    assert_eq!(GroupCode::AnchoringEventSeals(4095), "-T__".parse()?);
    Ok(())
}