use serde::{Deserialize, Serialize};
pub const SUITE_V1: &str = "Kyber1024+XChaCha20P1305+MlDsa65";
pub const DILITHIUM3_SIG_LEN: usize = 3309;
pub const DILITHIUM3_PK_LEN: usize = 1952;
pub const MLKEM1024_PK_LEN: usize = 1568;
const CBOR_SELF_DESCRIBE_TAG: [u8; 3] = [0xd9, 0xd9, 0xf7];
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct SenderPub {
pub sid: String,
#[serde(with = "serde_bytes")]
pub pk_dilithium: Vec<u8>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct RecipientPub {
pub kid: String,
#[serde(with = "serde_bytes")]
pub pk_kyber: Vec<u8>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct Header {
pub v: u32,
pub suite: String,
pub sender: String,
pub recipients: Vec<String>,
pub msg_id: String,
pub timestamp_unix: u64,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct RecipientEnvelope {
pub kid: String,
#[serde(with = "serde_bytes")]
pub kem_ct: Vec<u8>,
#[serde(with = "serde_bytes")]
pub wrap_nonce: Vec<u8>,
#[serde(with = "serde_bytes")]
pub wrapped_cek: Vec<u8>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct BundleUnsigned {
pub header: Header,
#[serde(with = "serde_bytes")]
pub pay_nonce: Vec<u8>,
#[serde(with = "serde_bytes")]
pub ciphertext: Vec<u8>,
pub recipients: Vec<RecipientEnvelope>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct BundleSigned {
#[serde(with = "serde_bytes")]
pub inner: Vec<u8>,
#[serde(with = "serde_bytes")]
pub sig_dilithium: Vec<u8>,
}
pub(crate) fn to_cbor<T: serde::Serialize>(v: &T) -> Result<Vec<u8>, crate::TholosError> {
let mut buf = CBOR_SELF_DESCRIBE_TAG.to_vec();
ciborium::ser::into_writer(v, &mut buf).map_err(|e| crate::TholosError::Ser(e.to_string()))?;
Ok(buf)
}
pub(crate) fn from_cbor<T: serde::de::DeserializeOwned>(
data: &[u8],
) -> Result<T, crate::TholosError> {
let payload = strip_self_describe_prefix(data);
ciborium::de::from_reader(payload).map_err(|e| crate::TholosError::Ser(e.to_string()))
}
pub(crate) fn strip_self_describe_prefix(data: &[u8]) -> &[u8] {
if data.len() >= CBOR_SELF_DESCRIBE_TAG.len()
&& data[..CBOR_SELF_DESCRIBE_TAG.len()] == CBOR_SELF_DESCRIBE_TAG
{
&data[CBOR_SELF_DESCRIBE_TAG.len()..]
} else {
data
}
}
pub(crate) fn has_self_describe_tag(data: &[u8]) -> bool {
data.len() >= CBOR_SELF_DESCRIBE_TAG.len()
&& data[..CBOR_SELF_DESCRIBE_TAG.len()] == CBOR_SELF_DESCRIBE_TAG
}