use crate::identity::*;
use crate::types::*;
use crate::verify::ok;
use core::fmt;
#[derive(Clone, Copy)]
#[repr(C)]
pub struct Endorsement {
pub endorser: AliceId,
pub endorsed: AliceId,
pub sig: AliceSig,
pub issued_ms: u64,
pub expires_ms: u64,
}
impl fmt::Debug for Endorsement {
#[inline(always)]
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
impl Endorsement {
#[inline]
fn payload(endorsed: &AliceId, issued_ms: u64, expires_ms: u64) -> [u8; 48] {
let mut buf = [0u8; 48];
buf[0..32].copy_from_slice(endorsed.as_bytes());
buf[32..40].copy_from_slice(&issued_ms.to_le_bytes());
buf[40..48].copy_from_slice(&expires_ms.to_le_bytes());
buf
}
}
#[inline]
#[must_use]
pub fn endorse(signer: &Identity, target: &AliceId, now_ms: u64, ttl_ms: u64) -> Endorsement {
let expires_ms = now_ms + ttl_ms;
let payload = Endorsement::payload(target, now_ms, expires_ms);
Endorsement {
endorser: signer.id(),
endorsed: *target,
sig: signer.sign(&payload),
issued_ms: now_ms,
expires_ms,
}
}
#[inline]
#[must_use]
pub fn verify_endorsement(e: &Endorsement, now_ms: u64) -> bool {
if now_ms > e.expires_ms {
return false;
}
let payload = Endorsement::payload(&e.endorsed, e.issued_ms, e.expires_ms);
ok(&e.endorser, &payload, &e.sig)
}
#[must_use]
pub fn verify_chain(chain: &[Endorsement], root: &AliceId, now_ms: u64) -> bool {
if chain.is_empty() {
return false;
}
if chain[0].endorser != *root {
return false;
}
if !verify_endorsement(&chain[0], now_ms) {
return false;
}
let mut i = 1;
while i < chain.len() {
if chain[i].endorser != chain[i - 1].endorsed {
return false;
}
if !verify_endorsement(&chain[i], now_ms) {
return false;
}
i += 1;
}
true
}