use std::convert::TryFrom;
pub use super::{Error, ReportAuthorizationKey, TemporaryContactKey, TemporaryContactNumber};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum MemoType {
CoEpiV1 = 0,
CovidWatchV1 = 1,
Reserved = 0xff,
}
#[derive(Clone, Debug)]
pub struct Report {
pub(crate) rvk: ed25519_zebra::PublicKeyBytes,
pub(crate) tck_bytes: [u8; 32],
pub(crate) j_1: u16,
pub(crate) j_2: u16,
pub(crate) memo_type: MemoType,
pub(crate) memo_data: Vec<u8>,
}
impl Report {
pub fn memo_type(&self) -> MemoType {
self.memo_type
}
pub fn memo_data(&self) -> &[u8] {
&self.memo_data
}
pub fn temporary_contact_numbers(&self) -> impl Iterator<Item = TemporaryContactNumber> {
let mut tck = TemporaryContactKey {
index: self.j_1 - 1,
rvk: self.rvk,
tck_bytes: self.tck_bytes,
};
tck = tck.ratchet().expect("j_1 - 1 < j_1 <= u16::MAX");
(self.j_1..self.j_2).map(move |_| {
let tcn = tck.temporary_contact_number();
tck = tck
.ratchet()
.expect("we do not ratchet past j_2 <= u16::MAX");
tcn
})
}
}
impl ReportAuthorizationKey {
pub fn create_report(
&self,
memo_type: MemoType,
memo_data: Vec<u8>,
j_1: u16,
j_2: u16,
) -> Result<SignedReport, Error> {
let j_1 = if j_1 == 0 { 1 } else { j_1 };
let mut tck = self.tck_0();
for _ in 0..(j_1 - 1) {
tck = tck.ratchet().expect("j_1 - 1 < u16::MAX");
}
let report = Report {
rvk: ed25519_zebra::PublicKeyBytes::from(&self.rak),
tck_bytes: tck.tck_bytes,
j_1,
j_2,
memo_type,
memo_data,
};
use std::io::Cursor;
let mut report_bytes = Vec::with_capacity(report.size_hint());
report.write(Cursor::new(&mut report_bytes))?;
let sig = self.rak.sign(&report_bytes);
Ok(SignedReport { report, sig })
}
}
#[derive(Clone, Debug)]
pub struct SignedReport {
pub(crate) report: Report,
pub(crate) sig: ed25519_zebra::Signature,
}
impl SignedReport {
pub fn verify(self) -> Result<Report, Error> {
use std::io::Cursor;
let mut report_bytes = Vec::with_capacity(self.report.size_hint());
self.report.write(Cursor::new(&mut report_bytes))?;
match ed25519_zebra::PublicKey::try_from(self.report.rvk)
.and_then(|pk| pk.verify(&self.sig, &report_bytes))
{
Ok(_) => Ok(self.report),
Err(_) => Err(Error::ReportVerificationFailed),
}
}
}