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,
};
#[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 {
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())),
}
}
}
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()
}
}
impl Serialize for AttachedSignaturePrefix {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_str())
}
}
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)
}
}