hbkr-rs 0.3.2

Hashblock Key Rotation
Documentation
use base64::{decode_config, encode_config};
use core::str::FromStr;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use crate::{
    derivation::DerivationCode, errors::KrError, self_signing_pre::SelfSigningPrefix,
    self_signinig::SelfSigning, Prefix,
};

/// Attached Signature Derivation Codes
///
/// A self signing prefix derivation outputs a signature as its derivative (2.3.5)
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct AttachedSignatureCode {
    pub index: u16,
    pub code: SelfSigning,
}

impl AttachedSignatureCode {
    pub fn new(code: SelfSigning, index: u16) -> Self {
        Self { index, code }
    }
}

impl DerivationCode for AttachedSignatureCode {
    // TODO, this will only work with indicies up to 63
    fn to_str(&self) -> String {
        [
            match self.code {
                SelfSigning::Ed25519Sha512 => "A",
                SelfSigning::ECDSAsecp256k1Sha256 => "B",
                SelfSigning::Ed448 => "0AA",
            },
            &num_to_b64(self.index),
        ]
        .join("")
    }

    fn code_len(&self) -> usize {
        match self.code {
            SelfSigning::Ed25519Sha512 | SelfSigning::ECDSAsecp256k1Sha256 => 2,
            SelfSigning::Ed448 => 4,
        }
    }

    fn derivative_b64_len(&self) -> usize {
        match self.code {
            SelfSigning::Ed25519Sha512 | SelfSigning::ECDSAsecp256k1Sha256 => 86,
            SelfSigning::Ed448 => 152,
        }
    }
}

impl FromStr for AttachedSignatureCode {
    type Err = KrError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match &s[..1] {
            "A" => Ok(Self::new(
                SelfSigning::Ed25519Sha512,
                b64_to_num(&s.as_bytes()[1..2])?,
            )),
            "B" => Ok(Self::new(
                SelfSigning::ECDSAsecp256k1Sha256,
                b64_to_num(&s.as_bytes()[1..2])?,
            )),
            "0" => match &s[1..3] {
                "AA" => Ok(Self::new(
                    SelfSigning::Ed448,
                    b64_to_num(&s.as_bytes()[3..4])?,
                )),
                _ => Err(KrError::DeserializeError("Unknows signature code".into())),
            },
            _ => Err(KrError::DeserializeError("Unknown attachment code".into())),
        }
    }
}

// returns the u16 from the lowest 2 bytes of the b64 string
// currently only works for strings 4 chars or less
pub fn b64_to_num(b64: &[u8]) -> Result<u16, KrError> {
    let slice = decode_config(
        match b64.len() {
            1 => [r"AAA".as_bytes(), b64].concat(),
            2 => [r"AA".as_bytes(), b64].concat(),
            _ => b64.to_owned(),
        },
        base64::URL_SAFE,
    )
    .map_err(|e| KrError::Base64DecodingError { source: e })?;
    let len = slice.len();

    Ok(u16::from_be_bytes(match len {
        0 => [0u8; 2],
        1 => [0, slice[0]],
        _ => [slice[len - 2], slice[len - 1]],
    }))
}

pub fn num_to_b64(num: u16) -> String {
    match num {
        n if n < 63 => {
            encode_config([num.to_be_bytes()[1] << 2], base64::URL_SAFE_NO_PAD)[..1].to_string()
        }
        n if n < 4095 => encode_config(num.to_be_bytes(), base64::URL_SAFE_NO_PAD)[..2].to_string(),
        _ => encode_config(num.to_be_bytes(), base64::URL_SAFE_NO_PAD),
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct AttachedSignaturePrefix {
    pub index: u16,
    pub signature: SelfSigningPrefix,
}

impl AttachedSignaturePrefix {
    pub fn new(code: SelfSigning, signature: Vec<u8>, index: u16) -> Self {
        Self {
            signature: SelfSigningPrefix::new(code, signature),
            index,
        }
    }
}

impl FromStr for AttachedSignaturePrefix {
    type Err = KrError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let code = AttachedSignatureCode::from_str(s)?;

        if (s.len()) == code.prefix_b64_len() {
            Ok(Self::new(
                code.code,
                decode_config(&s[code.code_len()..code.prefix_b64_len()], base64::URL_SAFE)?,
                code.index,
            ))
        } else {
            Err(KrError::SemanticError(format!(
                "Incorrect Prefix Length: {}",
                s
            )))
        }
    }
}

impl Prefix for AttachedSignaturePrefix {
    fn derivative(&self) -> Vec<u8> {
        self.signature.signature.to_vec()
    }
    fn derivation_code(&self) -> String {
        AttachedSignatureCode::new(self.signature.derivation, self.index).to_str()
    }
}

/// Serde compatible Serialize
impl Serialize for AttachedSignaturePrefix {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&self.to_str())
    }
}

/// Serde compatible Deserialize
impl<'de> Deserialize<'de> for AttachedSignaturePrefix {
    fn deserialize<D>(deserializer: D) -> Result<AttachedSignaturePrefix, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;

        AttachedSignaturePrefix::from_str(&s).map_err(serde::de::Error::custom)
    }
}

// #[cfg(test)]
// mod tests {
//     use super::*;
//     use crate::derivation::self_signing::SelfSigning;

//     #[test]
//     fn deserialize() -> Result<(), Error> {
//         let attached_ed_1 = "ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
//         let attached_secp_2 = "BCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
//         let attached_448_3 = "0AADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";

//         let pref_ed_1 = AttachedSignaturePrefix::from_str(attached_ed_1)?;
//         let pref_secp_2 = AttachedSignaturePrefix::from_str(attached_secp_2)?;
//         let pref_448_3 = AttachedSignaturePrefix::from_str(attached_448_3)?;

//         assert_eq!(1, pref_ed_1.index);
//         assert_eq!(2, pref_secp_2.index);
//         assert_eq!(3, pref_448_3.index);

//         assert_eq!(SelfSigning::Ed25519Sha512, pref_ed_1.signature.derivation);
//         assert_eq!(
//             SelfSigning::ECDSAsecp256k1Sha256,
//             pref_secp_2.signature.derivation
//         );
//         assert_eq!(SelfSigning::Ed448, pref_448_3.signature.derivation);
//         Ok(())
//     }

//     #[test]
//     fn serialize() -> Result<(), Error> {
//         let pref_ed_2 = AttachedSignaturePrefix::new(SelfSigning::Ed25519Sha512, vec![0u8; 64], 2);
//         let pref_secp_6 =
//             AttachedSignaturePrefix::new(SelfSigning::ECDSAsecp256k1Sha256, vec![0u8; 64], 6);
//         let pref_448_4 = AttachedSignaturePrefix::new(SelfSigning::Ed448, vec![0u8; 114], 4);

//         assert_eq!(88, pref_ed_2.to_str().len());
//         assert_eq!(88, pref_secp_6.to_str().len());
//         assert_eq!(156, pref_448_4.to_str().len());

//         assert_eq!("ACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", pref_ed_2.to_str());
//         assert_eq!("BGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", pref_secp_6.to_str());
//         assert_eq!("0AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", pref_448_4.to_str());
//         Ok(())
//     }
// }