1use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9pub enum Version {
10 V1_0,
12 V1_1,
14 V2_0,
16}
17
18impl Version {
19 pub fn as_str(&self) -> &'static str {
20 match self {
21 Version::V1_0 => "WAR/1.0",
22 Version::V1_1 => "WAR/1.1",
23 Version::V2_0 => "WAR/2.0",
24 }
25 }
26
27 pub fn parse(s: &str) -> Option<Self> {
28 match s {
29 "WAR/1.0" => Some(Version::V1_0),
30 "WAR/1.1" => Some(Version::V1_1),
31 "WAR/2.0" => Some(Version::V2_0),
32 _ => None,
33 }
34 }
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct Block {
40 pub version: Version,
41 pub author: String,
43 pub document_id: [u8; 32],
45 pub timestamp: DateTime<Utc>,
46 pub statement: String,
47 pub seal: Seal,
48 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
50 pub signed: bool,
51 #[serde(default, skip_serializing_if = "Option::is_none")]
53 pub verifier_nonce: Option<[u8; 32]>,
54 #[serde(default, skip_serializing_if = "Option::is_none")]
56 pub ear: Option<super::ear::EarToken>,
57}
58
59#[derive(Debug, Clone)]
61pub struct Seal {
62 pub h1: [u8; 32],
64 pub h2: [u8; 32],
66 pub h3: [u8; 32],
68 pub signature: [u8; 64],
70 pub public_key: [u8; 32],
71}
72
73impl Serialize for Seal {
74 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75 where
76 S: serde::Serializer,
77 {
78 use serde::ser::SerializeStruct;
79 let mut state = serializer.serialize_struct("Seal", 5)?;
80 state.serialize_field("h1", &hex::encode(self.h1))?;
81 state.serialize_field("h2", &hex::encode(self.h2))?;
82 state.serialize_field("h3", &hex::encode(self.h3))?;
83 state.serialize_field("signature", &hex::encode(self.signature))?;
84 state.serialize_field("public_key", &hex::encode(self.public_key))?;
85 state.end()
86 }
87}
88
89impl<'de> Deserialize<'de> for Seal {
90 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
91 where
92 D: serde::Deserializer<'de>,
93 {
94 #[derive(Deserialize)]
95 struct SealHelper {
96 h1: String,
97 h2: String,
98 h3: String,
99 signature: String,
100 public_key: String,
101 }
102
103 let helper = SealHelper::deserialize(deserializer)?;
104
105 let h1 = hex::decode(&helper.h1).map_err(serde::de::Error::custom)?;
106 let h2 = hex::decode(&helper.h2).map_err(serde::de::Error::custom)?;
107 let h3 = hex::decode(&helper.h3).map_err(serde::de::Error::custom)?;
108 let signature = hex::decode(&helper.signature).map_err(serde::de::Error::custom)?;
109 let public_key = hex::decode(&helper.public_key).map_err(serde::de::Error::custom)?;
110
111 if h1.len() != 32 || h2.len() != 32 || h3.len() != 32 {
112 return Err(serde::de::Error::custom("hash must be 32 bytes"));
113 }
114 if signature.len() != 64 {
115 return Err(serde::de::Error::custom("signature must be 64 bytes"));
116 }
117 if public_key.len() != 32 {
118 return Err(serde::de::Error::custom("public key must be 32 bytes"));
119 }
120
121 let mut seal = Seal {
122 h1: [0u8; 32],
123 h2: [0u8; 32],
124 h3: [0u8; 32],
125 signature: [0u8; 64],
126 public_key: [0u8; 32],
127 };
128 seal.h1.copy_from_slice(&h1);
129 seal.h2.copy_from_slice(&h2);
130 seal.h3.copy_from_slice(&h3);
131 seal.signature.copy_from_slice(&signature);
132 seal.public_key.copy_from_slice(&public_key);
133 Ok(seal)
134 }
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct VerificationReport {
140 pub valid: bool,
141 pub checks: Vec<CheckResult>,
142 pub summary: String,
143 pub details: ForensicDetails,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct CheckResult {
149 pub name: String,
151 pub passed: bool,
152 pub message: String,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct ForensicDetails {
158 pub version: String,
159 pub author: String,
160 pub document_id: String,
161 pub timestamp: DateTime<Utc>,
162 pub components: Vec<String>,
163 pub elapsed_time_secs: Option<f64>,
165 pub checkpoint_count: Option<usize>,
166 pub keystroke_count: Option<u64>,
167 pub has_jitter_seal: bool,
168 pub has_hardware_attestation: bool,
169 pub has_verifier_nonce: bool,
170 #[serde(skip_serializing_if = "Option::is_none")]
172 pub verifier_nonce: Option<String>,
173}