1use structured_pkix::temporal::{Instant, LeapTable, Reading, Uncertainty};
4
5mod accuracy;
6pub use accuracy::{AccuracyReading, Component, ComponentReading, DeviationError, DeviationReason};
7mod imprint;
8pub use imprint::{HashAlgorithmReading, MessageImprint};
9mod imprint_check;
10pub use imprint_check::{ImprintAgreement, ImprintError};
11mod computed;
12pub use computed::{
13 ComputedInput, ImprintContext, ImprintDigest, ImprintProof, ImprintState, InputFailure,
14 RawInput,
15};
16mod requested;
17pub use requested::{ImprintOperand, RequestAgreement, RequestImprintError, RequestedContentError};
18mod extension;
19pub use extension::{RecognitionError, TokenExtension, TokenExtensions};
20mod info;
21pub use info::{IntegerField, TokenInfo};
22mod tsa;
23pub use tsa::TsaReading;
24mod token;
25pub use token::{InfoError, Token};
26mod timeliness;
27pub use timeliness::{RequestWindow, Timeliness, timeliness};
28mod request;
29pub use request::Request;
30pub mod response;
31pub use response::Response;
32mod request_extensions;
33mod request_fields;
34pub use request_fields::{RequestFieldError, RequestFields};
35mod authority;
36mod carried;
37mod signature;
38pub use authority::{AuthorityError, AuthorityFacts, AuthoritySource, TsaIdentity, TsaUsage};
39pub use signature::{SignatureError, TokenSignature};
40mod check;
41mod profile;
42pub use check::{
43 CheckContext, CheckError, CheckedTimestamp, Evidence, EvidenceCopyError, InfoCheckError,
44 MappedCheckError, Requested,
45};
46pub use profile::{
47 MappedProfileCheckError, ProfileCheckError, ProfileFailure, ProfileInput, ProfileSource,
48};
49mod retained;
50pub use retained::{RetainedFacts, RetainedImprint};
51
52pub(crate) fn record<W: structured_asn1::memory::Work>(
53 faults: &mut structured_asn1::memory::OwnedVec<crate::Error, W>,
54 error: crate::Error,
55) -> crate::Result<()> {
56 if error.is_terminal() {
57 return Err(error);
58 }
59 let at = error.offset();
60 let field = error.field();
61 faults
62 .try_push(error)
63 .map_err(|reason| crate::Error::resource(reason, field, at))
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub struct Accuracy {
75 seconds: u64,
76 millis: u64,
77 micros: u64,
78}
79
80impl Accuracy {
81 #[must_use]
83 pub const fn new(seconds: u64, millis: u64, micros: u64) -> Self {
84 Self {
85 seconds,
86 millis,
87 micros,
88 }
89 }
90 #[must_use]
92 pub const fn seconds(self) -> u64 {
93 self.seconds
94 }
95 #[must_use]
97 pub const fn millis(self) -> u64 {
98 self.millis
99 }
100 #[must_use]
102 pub const fn micros(self) -> u64 {
103 self.micros
104 }
105 #[must_use]
107 pub fn nanos(self) -> u128 {
108 u128::from(self.seconds) * 1_000_000_000
110 + u128::from(self.millis) * 1_000_000
111 + u128::from(self.micros) * 1_000
112 }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum BoundUncertainty {
118 AccuracyUnstated,
120 Utc(Uncertainty),
122}
123
124pub use structured_pkix::temporal::CompareError as GenerationOrderError;
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub struct GenerationInterval {
130 pub earliest: Instant,
132 pub latest: Instant,
134}
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137pub enum IntervalError {
138 Resource(structured_asn1::memory::MemoryError),
140 Uncertain(BoundUncertainty),
142}
143pub fn interval_in<W: structured_asn1::memory::Work>(
146 reading: Reading,
147 accuracy: Option<Accuracy>,
148 utc: &LeapTable<'_>,
149 work: &W,
150) -> core::result::Result<GenerationInterval, IntervalError> {
151 let bits = usize::BITS - utc.transitions().len().leading_zeros();
152 work.charge_work(48 + 9 * (u64::from(bits) + 1))
153 .map_err(IntervalError::Resource)?;
154 Ok(GenerationInterval {
155 earliest: earliest(reading, accuracy, utc).map_err(IntervalError::Uncertain)?,
156 latest: latest(reading, accuracy, utc).map_err(IntervalError::Uncertain)?,
157 })
158}
159
160pub fn earliest(
163 reading: Reading,
164 accuracy: Option<Accuracy>,
165 utc: &LeapTable<'_>,
166) -> Result<Instant, BoundUncertainty> {
167 let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
168 shift(reading.start(), accuracy, true, utc)
169}
170
171pub fn latest(
174 reading: Reading,
175 accuracy: Option<Accuracy>,
176 utc: &LeapTable<'_>,
177) -> Result<Instant, BoundUncertainty> {
178 let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
183 let upper = reading.upper_bound(utc).map_err(BoundUncertainty::Utc)?;
184 shift(upper, accuracy, false, utc)
185}
186
187fn shift(
188 at: Instant,
189 accuracy: Accuracy,
190 earlier: bool,
191 utc: &LeapTable<'_>,
192) -> Result<Instant, BoundUncertainty> {
193 let nanos = i128::try_from(accuracy.nanos())
194 .map_err(|_| BoundUncertainty::Utc(Uncertainty::OutOfRange))?;
195 utc.shift(at, if earlier { -nanos } else { nanos })
196 .map_err(BoundUncertainty::Utc)
197}