const MAX_LEN: usize = 120;
#[derive(Clone, PartialEq)]
pub struct Signature {
data: [u8; MAX_LEN],
len: u8,
}
impl std::fmt::Display for Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_hex_str(f)
}
}
impl std::fmt::Debug for Signature {
fn fmt(&self, mut f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Signature(")?;
self.as_hex_str(&mut f)?;
write!(f, ")")
}
}
impl Signature {
pub fn as_hex_str<W>(&self, mut buf: W) -> Result<(), std::fmt::Error>
where
W: std::fmt::Write,
{
for b in self.as_ref() {
write!(&mut buf, "{b:02x}")?;
}
Ok(())
}
}
impl From<aws_lc_rs::signature::Signature> for Signature {
fn from(value: aws_lc_rs::signature::Signature) -> Self {
let sig = value.as_ref();
Self::try_from(sig).unwrap()
}
}
impl TryFrom<&[u8]> for Signature {
type Error = &'static str;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() > MAX_LEN {
return Err("invalid signature: too long");
}
let mut data = [0; MAX_LEN];
let sig = value;
let dst = &mut data[..sig.len()];
dst.clone_from_slice(sig);
let len = u8::try_from(sig.len()).expect("signature is too large");
Ok(Self { data, len })
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
&self.data[..self.len as usize]
}
}
#[cfg(test)]
mod tests {
use crate::{keys::PrivateKey, signer::Signer};
use proptest::prelude::*;
proptest! {
#[test]
fn prop_repr(
payload in prop::collection::vec(any::<u8>(), 64),
) {
let key = PrivateKey::new();
let sig = key.sign(&payload);
let mut hex = String::new();
sig.as_hex_str(&mut hex).unwrap();
let got = format!("{sig:?}");
assert_eq!(got, format!("Signature({hex})"));
assert_eq!(sig.to_string(), hex);
}
}
}