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