macula_rust/station_link/report.rs
1//! A caller's seal report (macula's DESIGN_E2E_SEAL_REPORT): whether the
2//! exchange that produced a result was sealed, and to which key. It states
3//! that sealing ran on that exchange, nothing more: not that the provider
4//! keeps the payload secret, not that the key is uncompromised.
5
6use std::fmt;
7
8use crate::seal::KEY_ID_SIZE;
9
10use super::Stream;
11
12/// A caller's seal report on one exchange, with the three fields every SDK
13/// names alike (macula's `sealed`, `provider`, `seal_key_id`). `sealed` is 1
14/// when the request that produced the result was sealed and its answer opened
15/// under the same key, whose id `seal_key_id` names, and 0, with no key id,
16/// for a clear exchange. `provider` is the node the request was addressed
17/// to: for a sealed result also the one whose answer opened, for a clear one
18/// the target and no claim about who answered.
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct Report {
21 pub sealed: u8,
22 pub provider: [u8; 32],
23 pub seal_key_id: Option<[u8; KEY_ID_SIZE]>,
24}
25
26impl Report {
27 /// The report on an exchange with `provider`: sealed to `key_id`, or
28 /// clear when it is `None`.
29 pub(crate) fn of(provider: [u8; 32], key_id: Option<[u8; KEY_ID_SIZE]>) -> Report {
30 Report {
31 sealed: u8::from(key_id.is_some()),
32 provider,
33 seal_key_id: key_id,
34 }
35 }
36}
37
38/// Why a stream has no seal report.
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum ReportError {
41 /// The provider has sent no data or reply opened under the stream's key
42 /// (on a clear stream, no data, reply or end), or the stream ended
43 /// first, an error included.
44 NotSettled,
45 /// A served stream: the report is the caller's evidence, and the
46 /// provider side has none.
47 NotACaller,
48}
49
50impl ReportError {
51 /// The error as macula and libmacula name it.
52 pub fn name(self) -> &'static str {
53 match self {
54 ReportError::NotSettled => "not_settled",
55 ReportError::NotACaller => "not_a_caller",
56 }
57 }
58}
59
60impl fmt::Display for ReportError {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 f.write_str(self.name())
63 }
64}
65
66impl std::error::Error for ReportError {}
67
68impl Stream {
69 /// This caller stream's seal report. It settles on the provider's first
70 /// STREAM_DATA or STREAM_REPLY opened under the stream's key; on a clear
71 /// stream, on its first STREAM_DATA, STREAM_REPLY or STREAM_END. A sealed
72 /// stream's STREAM_END travels clear and settles nothing, and no error
73 /// settles a stream. Before it settles, and on a stream that ended
74 /// first, it is [`ReportError::NotSettled`]; on a served stream,
75 /// [`ReportError::NotACaller`]. A stream that settled and then ended, an
76 /// error included, keeps its report.
77 pub fn report(&self) -> Result<Report, ReportError> {
78 if !self.inner.caller {
79 return Err(ReportError::NotACaller);
80 }
81 if !self.inner.side().settled {
82 return Err(ReportError::NotSettled);
83 }
84 let key_id = self.inner.sealing.as_ref().map(|s| s.key_id());
85 Ok(Report::of(self.inner.open.target, key_id))
86 }
87}