use rand_core::{CryptoRng, RngCore};
use sha2::{Digest, Sha256};
pub use super::Error;
const H_TCK_DOMAIN_SEP: &[u8; 5] = b"H_TCK";
const H_TCN_DOMAIN_SEP: &[u8; 5] = b"H_TCN";
#[derive(Copy, Clone, Debug)]
pub struct ReportAuthorizationKey {
pub(crate) rak: ed25519_zebra::SecretKey,
}
impl ReportAuthorizationKey {
pub fn new<R: RngCore + CryptoRng>(rng: R) -> ReportAuthorizationKey {
ReportAuthorizationKey {
rak: ed25519_zebra::SecretKey::new(rng),
}
}
pub fn initial_temporary_contact_key(&self) -> TemporaryContactKey {
self.tck_0().ratchet().expect("0 < u16::MAX")
}
pub(crate) fn tck_0(&self) -> TemporaryContactKey {
let rvk = ed25519_zebra::PublicKeyBytes::from(&self.rak);
let tck_bytes = {
let mut bytes = [0; 32];
bytes.copy_from_slice(
&Sha256::default()
.chain(H_TCK_DOMAIN_SEP)
.chain(&self.rak)
.result()[..],
);
bytes
};
TemporaryContactKey {
index: 0,
rvk,
tck_bytes,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct TemporaryContactNumber(pub [u8; 16]);
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct TemporaryContactKey {
pub(crate) index: u16,
pub(crate) rvk: ed25519_zebra::PublicKeyBytes,
pub(crate) tck_bytes: [u8; 32],
}
impl TemporaryContactKey {
pub fn index(&self) -> u16 {
self.index
}
pub fn temporary_contact_number(&self) -> TemporaryContactNumber {
let mut bytes = [0; 16];
bytes.copy_from_slice(
&Sha256::default()
.chain(H_TCN_DOMAIN_SEP)
.chain(&self.index.to_le_bytes()[..])
.chain(&self.tck_bytes)
.result()[..16],
);
TemporaryContactNumber(bytes)
}
pub fn ratchet(self) -> Option<TemporaryContactKey> {
let TemporaryContactKey {
index,
rvk,
tck_bytes,
} = self;
if let Some(next_index) = index.checked_add(1) {
let next_tck_bytes = {
let mut bytes = [0; 32];
bytes.copy_from_slice(
&Sha256::default()
.chain(H_TCK_DOMAIN_SEP)
.chain(&rvk)
.chain(&tck_bytes)
.result()[..],
);
bytes
};
Some(TemporaryContactKey {
rvk,
index: next_index,
tck_bytes: next_tck_bytes,
})
} else {
None
}
}
}