#![forbid(unsafe_code)]
use ciborium::{de, ser};
use serde::{Deserialize, Serialize};
use serde_bytes::ByteBuf;
use serde_tuple::{Deserialize_tuple, Serialize_tuple};
use std::io;
use sha2::{Digest, Sha256};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("CBOR encode error: {0}")]
Encode(String),
#[error("CBOR decode error: {0}")]
Decode(String),
#[error("I/O error: {0}")]
Io(#[from] io::Error),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Signer {
pub kid: String,
#[serde(with = "serde_bytes")]
#[serde(default)]
pub claims: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Transparency {
#[serde(with = "serde_bytes")]
pub root: Vec<u8>,
#[serde(with = "serde_bytes")]
pub proof: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
pub struct QSig {
pub version: u8,
pub alg: String,
#[serde(with = "serde_bytes")]
pub digest: Vec<u8>,
#[serde(with = "serde_bytes")]
pub sig: Vec<u8>,
pub co_sig: Vec<ByteBuf>,
pub tst: Option<ByteBuf>,
pub tlog: Option<Transparency>,
pub signer: Signer,
pub time_unix: i64,
pub domain_sep: String,
#[serde(default)]
pub meta: Option<ByteBuf>,
}
impl QSig {
pub fn encode_to_vec(&self) -> Result<Vec<u8>, Error> {
let mut buf = Vec::new();
ser::into_writer(self, &mut buf).map_err(|e| Error::Encode(e.to_string()))?;
Ok(buf)
}
pub fn decode(bytes: &[u8]) -> Result<Self, Error> {
de::from_reader(bytes).map_err(|e| Error::Decode(e.to_string()))
}
#[allow(clippy::too_many_arguments)]
pub fn new(
version: u8,
alg: String,
digest: Vec<u8>,
sig: Vec<u8>,
co_sig: Vec<Vec<u8>>,
tst: Option<Vec<u8>>,
tlog: Option<Transparency>,
signer: Signer,
time_unix: i64,
domain_sep: String,
meta: Option<Vec<u8>>,
) -> Self {
Self {
version,
alg,
digest,
sig,
co_sig: co_sig.into_iter().map(ByteBuf::from).collect(),
tst: tst.map(ByteBuf::from),
tlog,
signer,
time_unix,
domain_sep,
meta: meta.map(ByteBuf::from),
}
}
pub fn timestamp(&self) -> Option<&[u8]> {
self.tst.as_ref().map(ByteBuf::as_ref)
}
pub fn co_signatures(&self) -> impl Iterator<Item = &[u8]> {
self.co_sig.iter().map(ByteBuf::as_ref)
}
pub fn encode_core_view(&self) -> Result<Vec<u8>, Error> {
let mut core = self.clone();
core.tst = None;
core.tlog = None;
core.encode_to_vec()
}
pub fn core_leaf_hash_sha256(&self) -> Result<[u8; 32], Error> {
let core = self.encode_core_view()?;
let mut h = Sha256::new();
h.update(&core);
let digest = h.finalize();
let mut out = [0u8; 32];
out.copy_from_slice(&digest);
Ok(out)
}
}