lms_signature/ots/
public.rsuse crate::constants::ID_LEN;
use crate::error::LmsDeserializeError;
use crate::ots::modes::LmsOtsMode;
use crate::ots::signature::Signature;
use crate::types::Identifier;
use digest::{Output, OutputSizeUser};
use generic_array::{ArrayLength, GenericArray};
use signature::{Error, Verifier};
use std::cmp::Ordering;
use std::ops::Add;
use typenum::{Sum, U2, U24};
#[derive(Debug)]
pub struct VerifyingKey<Mode: LmsOtsMode> {
pub(crate) q: u32,
pub(crate) id: Identifier,
pub(crate) k: Output<Mode::Hasher>,
}
impl<Mode: LmsOtsMode> Clone for VerifyingKey<Mode> {
fn clone(&self) -> Self {
Self {
q: self.q,
id: self.id,
k: self.k.clone(),
}
}
}
impl<Mode: LmsOtsMode> PartialEq for VerifyingKey<Mode> {
fn eq(&self, other: &Self) -> bool {
self.q == other.q && self.id == other.id && self.k == other.k
}
}
impl<Mode: LmsOtsMode> Verifier<Signature<Mode>> for VerifyingKey<Mode>
where
<Mode::Hasher as OutputSizeUser>::OutputSize: Add<U2>,
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U2>: ArrayLength<u8>,
{
fn verify(&self, msg: &[u8], signature: &Signature<Mode>) -> Result<(), Error> {
let kc = signature.recover_pubkey(self.id, self.q, msg);
if self.k == kc.k {
Ok(())
} else {
Err(Error::new())
}
}
}
impl<Mode: LmsOtsMode> From<VerifyingKey<Mode>>
for GenericArray<u8, Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>>
where
<Mode::Hasher as OutputSizeUser>::OutputSize: Add<U24>,
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>: ArrayLength<u8>,
{
fn from(pk: VerifyingKey<Mode>) -> Self {
GenericArray::from_exact_iter(
std::iter::empty()
.chain(Mode::TYPECODE.to_be_bytes())
.chain(pk.id)
.chain(pk.q.to_be_bytes())
.chain(pk.k),
)
.expect("ok")
}
}
impl<'a, Mode: LmsOtsMode> TryFrom<&'a [u8]> for VerifyingKey<Mode> {
type Error = LmsDeserializeError;
fn try_from(pk: &'a [u8]) -> Result<Self, Self::Error> {
if pk.len() < 4 {
return Err(LmsDeserializeError::NoAlgorithm);
}
let (alg, pk) = pk.split_at(4);
let expected = Mode::N + ID_LEN + 4;
if u32::from_be_bytes(alg.try_into().unwrap()) != Mode::TYPECODE {
return Err(LmsDeserializeError::WrongAlgorithm);
}
match pk.len().cmp(&expected) {
Ordering::Less => Err(LmsDeserializeError::TooShort),
Ordering::Greater => Err(LmsDeserializeError::TooLong),
Ordering::Equal => {
let (i, qk) = pk.split_at(ID_LEN);
let (q, k) = qk.split_at(4);
Ok(Self {
q: u32::from_be_bytes(q.try_into().expect("ok")),
id: i.try_into().expect("ok"),
k: GenericArray::clone_from_slice(k),
})
}
}
}
}
#[cfg(test)]
mod tests {
use crate::constants::ID_LEN;
use crate::error::LmsDeserializeError;
use crate::ots::modes::{LmsOtsSha256N32W4, LmsOtsSha256N32W8};
use crate::ots::private::SigningKey;
use crate::ots::public::VerifyingKey;
use generic_array::GenericArray;
use rand::thread_rng;
#[test]
fn test_serde() {
let pk =
SigningKey::<LmsOtsSha256N32W8>::new(0, [0xbb; ID_LEN], &mut thread_rng()).public();
let pk_serialized: GenericArray<u8, _> = pk.clone().into();
let bytes = pk_serialized.as_slice();
let pk_deserialized = VerifyingKey::<LmsOtsSha256N32W8>::try_from(bytes);
assert!(pk_deserialized.is_ok());
let pk_deserialized = pk_deserialized.unwrap();
assert_eq!(pk, pk_deserialized);
let pk_wrongalgo = VerifyingKey::<LmsOtsSha256N32W4>::try_from(bytes);
let pk_short = VerifyingKey::<LmsOtsSha256N32W8>::try_from(&bytes[0..(bytes.len() - 1)]);
let mut long_bytes = pk_serialized.into_iter().collect::<Vec<_>>();
long_bytes.push(0);
let pk_long = VerifyingKey::<LmsOtsSha256N32W8>::try_from(long_bytes.as_slice());
assert_eq!(pk_wrongalgo, Err(LmsDeserializeError::WrongAlgorithm));
assert_eq!(pk_short, Err(LmsDeserializeError::TooShort));
assert_eq!(pk_long, Err(LmsDeserializeError::TooLong));
}
}