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 computed::{AsyncComputedInput, AsyncRawInput};
26pub use token::{AsyncInfoVisitor, InfoError, Token};
27mod timeliness;
28pub use timeliness::{RequestWindow, Timeliness, timeliness};
29mod request;
30pub use request::Request;
31pub mod response;
32pub use response::Response;
33mod request_extensions;
34mod request_fields;
35pub use request_fields::{RequestFieldError, RequestFields};
36mod authority;
37mod carried;
38mod signature;
39pub use authority::{AuthorityError, AuthorityFacts, AuthoritySource, TsaIdentity, TsaUsage};
40pub use signature::{SignatureError, TokenSignature};
41mod check;
42mod profile;
43pub use check::{
44 CheckContext, CheckError, CheckedTimestamp, Evidence, EvidenceCopyError, InfoCheckError,
45 MappedCheckError, Requested,
46};
47pub use profile::{
48 MappedProfileCheckError, ProfileCheckError, ProfileFailure, ProfileInput, ProfileSource,
49};
50mod retained;
51pub use retained::{RetainedFacts, RetainedImprint};
52
53pub(crate) fn record<W: structured_asn1::memory::Work>(
54 faults: &mut structured_asn1::memory::OwnedVec<crate::Error, W>,
55 error: crate::Error,
56) -> crate::Result<()> {
57 if error.is_terminal() {
58 return Err(error);
59 }
60 let at = error.offset();
61 let field = error.field();
62 faults
63 .try_push(error)
64 .map_err(|reason| crate::Error::resource(reason, field, at))
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub struct Accuracy {
76 seconds: u64,
77 millis: u64,
78 micros: u64,
79}
80
81impl Accuracy {
82 #[must_use]
84 pub const fn new(seconds: u64, millis: u64, micros: u64) -> Self {
85 Self {
86 seconds,
87 millis,
88 micros,
89 }
90 }
91 #[must_use]
93 pub const fn seconds(self) -> u64 {
94 self.seconds
95 }
96 #[must_use]
98 pub const fn millis(self) -> u64 {
99 self.millis
100 }
101 #[must_use]
103 pub const fn micros(self) -> u64 {
104 self.micros
105 }
106 #[must_use]
108 pub fn nanos(self) -> u128 {
109 u128::from(self.seconds) * 1_000_000_000
111 + u128::from(self.millis) * 1_000_000
112 + u128::from(self.micros) * 1_000
113 }
114}
115
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub enum BoundUncertainty {
119 AccuracyUnstated,
121 Utc(Uncertainty),
123}
124
125pub use structured_pkix::temporal::CompareError as GenerationOrderError;
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
130pub struct GenerationInterval {
131 pub earliest: Instant,
133 pub latest: Instant,
135}
136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
138pub enum IntervalError {
139 Resource(structured_asn1::memory::MemoryError),
141 Uncertain(BoundUncertainty),
143}
144pub fn interval_in<W: structured_asn1::memory::Work>(
147 reading: Reading,
148 accuracy: Option<Accuracy>,
149 utc: &LeapTable<'_>,
150 work: &W,
151) -> core::result::Result<GenerationInterval, IntervalError> {
152 let bits = usize::BITS - utc.transitions().len().leading_zeros();
153 work.charge_work(48 + 9 * (u64::from(bits) + 1))
154 .map_err(IntervalError::Resource)?;
155 Ok(GenerationInterval {
156 earliest: earliest(reading, accuracy, utc).map_err(IntervalError::Uncertain)?,
157 latest: latest(reading, accuracy, utc).map_err(IntervalError::Uncertain)?,
158 })
159}
160
161pub fn earliest(
164 reading: Reading,
165 accuracy: Option<Accuracy>,
166 utc: &LeapTable<'_>,
167) -> Result<Instant, BoundUncertainty> {
168 let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
169 shift(reading.start(), accuracy, true, utc)
170}
171
172pub fn latest(
175 reading: Reading,
176 accuracy: Option<Accuracy>,
177 utc: &LeapTable<'_>,
178) -> Result<Instant, BoundUncertainty> {
179 let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
184 let upper = reading.upper_bound(utc).map_err(BoundUncertainty::Utc)?;
185 shift(upper, accuracy, false, utc)
186}
187
188fn shift(
189 at: Instant,
190 accuracy: Accuracy,
191 earlier: bool,
192 utc: &LeapTable<'_>,
193) -> Result<Instant, BoundUncertainty> {
194 let nanos = i128::try_from(accuracy.nanos())
195 .map_err(|_| BoundUncertainty::Utc(Uncertainty::OutOfRange))?;
196 utc.shift(at, if earlier { -nanos } else { nanos })
197 .map_err(BoundUncertainty::Utc)
198}