mod engine;
use super::{
ArchiveTimeStamp, EvidenceRecord, FIELD, Membership, PriorSequence, TimeStamp,
input::InputError,
};
use crate::{
Error, ErrorCode,
content_source::ContentError,
digest::PassError,
provider::SignatureProvider,
stream::{RangesError, Source},
timestamp::{
self, CheckContext, CheckedTimestamp, Evidence, InfoError, ProfileCheckError,
ProfileFailure, TokenExtension,
},
};
use core::convert::Infallible;
use structured_asn1::{
Reader,
digest::Resolution,
memory::{Execution, OwnedVec, Work},
};
use structured_pkix::{
Certificate,
algorithm::digest::{self, Algorithm},
path::WorkingKey,
temporal::{Instant, LeapTable},
};
pub struct Selection<'a> {
pub certificate: &'a Certificate<'a>,
pub certificate_parent: &'a Reader<'a>,
pub key: WorkingKey<'a>,
}
impl<'a> Selection<'a> {
fn historical_context<'s>(&'s self, utc: &'s LeapTable<'a>) -> CheckContext<'a, 's> {
CheckContext {
certificate: self.certificate,
certificate_parent: self.certificate_parent,
key: self.key,
requested: None,
utc,
reference: None,
window: None,
}
}
}
pub trait Authorities<'document> {
type Error;
fn select<'a, W: Work>(
&'a self,
index: usize,
stamp: &'a ArchiveTimeStamp<'document>,
work: &W,
) -> Result<Selection<'a>, Self::Error>
where
'document: 'a;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Decision {
Valid,
Invalid,
Unknown,
}
pub struct Historical<'a, 'token> {
pub index: usize,
pub current: &'a CheckedTimestamp<'token>,
pub selection: &'a Selection<'token>,
pub following: Option<&'a Evidence>,
pub following_chain: Option<&'a Evidence>,
pub verification_time: Instant,
}
#[derive(Debug)]
pub enum PlanError {
Processing(Error),
Information(ContentError<InfoError<AlgorithmError>>),
Nonconforming {
index: usize,
span: structured_asn1::Span,
},
UnsupportedTimestamp {
index: usize,
},
UnsupportedAlgorithm {
at: u64,
},
}
#[derive(Debug)]
pub enum AlgorithmError {
Processing(Error),
Unsupported {
at: u64,
},
}
#[derive(Debug)]
pub enum VerificationError<SE, PE, RE, AE, HE, FE = Infallible> {
Membership {
index: usize,
},
Plan(PlanError),
Processing(Error),
Acquisition(PassError<SE, PE>),
Selection {
index: usize,
cause: AE,
},
Timestamp {
index: usize,
cause: ProfileCheckError<InputError<SE, PE>, PE, RE, FE>,
},
Renewal {
index: usize,
cause: ProfileCheckError<InputError<RangesError, PE>, PE, RE, FE>,
},
Historical {
index: usize,
cause: HE,
},
}
pub type VerificationResult<'a, 'd, SE, PE, RE, AE, HE, FE = Infallible> =
Result<Report<'a, 'd>, VerificationError<SE, PE, RE, AE, HE, FE>>;
pub struct Checked<'a> {
index: usize,
common: CheckedTimestamp<'a>,
selection: Selection<'a>,
history: Decision,
}
impl<'a> Checked<'a> {
#[must_use]
pub fn index(&self) -> usize {
self.index
}
#[must_use]
pub fn timestamp(&self) -> &CheckedTimestamp<'_> {
&self.common
}
#[must_use]
pub fn selection(&self) -> &Selection<'_> {
&self.selection
}
#[must_use]
pub fn historical(&self) -> Decision {
self.history
}
pub fn into_parts(self) -> (usize, CheckedTimestamp<'a>, Selection<'a>, Decision) {
(self.index, self.common, self.selection, self.history)
}
}
pub struct Report<'a, 'document> {
record: &'a EvidenceRecord<'document>,
checks: OwnedVec<Checked<'a>>,
ordering: OwnedVec<OrderFinding>,
complete: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OrderFinding {
pub earlier: usize,
pub later: usize,
pub cause: OrderCause,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OrderCause {
Reversed,
Overlap,
Utc(structured_pkix::temporal::Uncertainty),
UnprovenTimestamp,
Bounds {
earlier: Option<timestamp::BoundUncertainty>,
later: Option<timestamp::BoundUncertainty>,
},
}
pub struct Verified<'report, 'record, 'document>(&'report Report<'record, 'document>);
impl<'a, 'd> Report<'a, 'd> {
pub fn into_parts(
self,
) -> (
&'a EvidenceRecord<'d>,
OwnedVec<Checked<'a>>,
OwnedVec<OrderFinding>,
bool,
) {
(self.record, self.checks, self.ordering, self.complete)
}
pub fn checks(&self) -> impl DoubleEndedIterator<Item = &Checked<'a>> + ExactSizeIterator {
self.checks.iter().rev()
}
#[must_use]
pub fn ordering(&self) -> &[OrderFinding] {
&self.ordering
}
#[must_use]
pub fn verified(&self) -> Option<Verified<'_, 'a, 'd>> {
if self.complete {
Some(Verified(self))
} else {
None
}
}
}
impl<'a, 'd> Verified<'_, 'a, 'd> {
#[must_use]
pub fn record(&self) -> &'a EvidenceRecord<'d> {
self.0.record
}
pub fn checks(&self) -> impl DoubleEndedIterator<Item = &Checked<'a>> + ExactSizeIterator {
self.0.checks()
}
}
pub struct InputPlan<'record, 'document> {
record: &'record EvidenceRecord<'document>,
chains: OwnedVec<Algorithm>,
}
impl<'r, 'd> InputPlan<'r, 'd> {
#[expect(
clippy::result_large_err,
reason = "a carried algorithm failure retains its original source map and cause inline, including when no diagnostic allocation can succeed"
)]
fn read(record: &'r EvidenceRecord<'d>, operation: &Reader<'_>) -> Result<Self, PlanError> {
let origin = record
.original
.reader_in(operation)
.map_err(PlanError::Processing)?;
let work = origin.execution_query(operation);
let mut declared = work.vector();
for identifier in &record.algorithms {
let value = known(identifier, &work).map_err(original_algorithm_error)?;
insert_algorithm(&mut declared, value, &work, identifier.offset())
.map_err(PlanError::Processing)?;
}
let mut chains = work.vector();
let mut chain_index = 0;
for (index, stamp) in record.timestamps.iter().enumerate() {
work.charge_work(1).map_err(|cause| {
PlanError::Processing(Error::resource(
cause,
FIELD,
stamp.original.element.span().start,
))
})?;
let TimeStamp::Rfc3161(token) = &stamp.token else {
return Err(PlanError::UnsupportedTimestamp { index });
};
if !token.faults().is_empty()
|| !token.message().faults().is_empty()
|| !token.signer().faults().is_empty()
{
return Err(PlanError::Nonconforming {
index,
span: token.message().span(),
});
}
let parent = stamp
.timestamp
.reader_in(operation)
.map_err(PlanError::Processing)?;
let timestamp_algorithm =
token_algorithm(token, &parent).map_err(PlanError::Information)?;
let value = if let Some(identifier) = stamp.algorithm {
known(&identifier, &work).map_err(original_algorithm_error)?
} else {
timestamp_algorithm
};
require_width(stamp, value.width(), &work).map_err(PlanError::Processing)?;
let chain = &record.chains[chain_index];
if index == chain.first {
chains.try_push(value).map_err(|cause| {
PlanError::Processing(Error::resource(
cause,
FIELD,
chain.original.element.span().start,
))
})?;
} else if chains[chain_index] != value {
return Err(PlanError::Processing(Error::schema(
ErrorCode::AlgorithmProtection,
FIELD,
stamp.original.element.span().start,
)));
}
if index + 1 == chain.end {
chain_index += 1;
}
}
let mut used = work.vector();
for algorithm in &chains {
insert_algorithm(
&mut used,
*algorithm,
&work,
record.original.element.span().start,
)
.map_err(PlanError::Processing)?;
}
require_union(
&declared,
&used,
&work,
record.original.element.span().start,
)
.map_err(PlanError::Processing)?;
Ok(Self {
record,
chains: chains.into_owned(),
})
}
#[must_use]
pub fn algorithms(&self) -> &[Algorithm] {
&self.chains
}
#[must_use]
pub fn record(&self) -> &'r EvidenceRecord<'d> {
self.record
}
#[expect(
clippy::too_many_arguments,
reason = "the asynchronous driver retains distinct original/provider/authority/UTC inputs and scoped format callbacks"
)]
#[expect(
clippy::result_large_err,
reason = "suspension preserves the same source-mapped and opaque failures as resident verification"
)]
pub async fn verify_async_with_profile<'a, P, PE, A, S, RE, HE, FE>(
&self,
provider: &'a P,
operation: &Reader<'a>,
authorities: &'a A,
utc: &LeapTable<'a>,
reference: Instant,
objects: S,
membership: Membership,
mut recognizes: impl FnMut(usize, &TokenExtension<'_>, &Execution<'_>) -> Result<bool, RE>,
mut historical: impl FnMut(Historical<'_, 'a>, &Execution<'_>) -> Result<Decision, HE>,
mut profile: impl for<'view, 'scope> FnMut(
usize,
timestamp::ProfileInput<'view, 'd, 'a, 'scope>,
) -> Result<(), ProfileFailure<FE>>,
) -> VerificationResult<'a, 'd, S::Error, PE, RE, A::Error, HE, FE>
where
'r: 'a,
'd: 'a,
P: for<'scope> SignatureProvider<'scope, Error = PE>,
A: Authorities<'d>,
S: super::AsyncObjects<'a, P>,
{
let record = self.record;
let plan = self;
engine::execute!(
suspending,
record,
plan,
provider,
operation,
authorities,
utc,
reference,
objects,
membership,
recognizes,
historical,
profile
)
}
fn token(&self, index: usize) -> (&'r ArchiveTimeStamp<'d>, &'r timestamp::Token<'d>) {
let record = self.record;
let stamp = &record.timestamps[index];
let TimeStamp::Rfc3161(token) = &stamp.token else {
unreachable!("the immutable input plan admitted every timestamp format")
};
(stamp, token)
}
#[expect(
clippy::too_many_arguments,
reason = "the immutable plan keeps source, provider, authority and UTC contexts independent of the three differently scoped callbacks"
)]
#[expect(
clippy::result_large_err,
reason = "the literal-source entry preserves mapped timestamp and opaque callback failures without a diagnostic allocation"
)]
pub fn verify_with_profile<'a, P, PE, A, S, RE, HE, FE>(
&self,
provider: &'a P,
operation: &Reader<'a>,
authorities: &'a A,
utc: &LeapTable<'a>,
reference: Instant,
objects: &mut [S],
membership: Membership,
recognizes: impl FnMut(usize, &TokenExtension<'_>, &Execution<'_>) -> Result<bool, RE>,
historical: impl FnMut(Historical<'_, 'a>, &Execution<'_>) -> Result<Decision, HE>,
profile: impl for<'view, 'scope> FnMut(
usize,
timestamp::ProfileInput<'view, 'd, 'a, 'scope>,
) -> Result<(), ProfileFailure<FE>>,
) -> VerificationResult<'a, 'd, S::Error, PE, RE, A::Error, HE, FE>
where
'r: 'a,
'd: 'a,
P: for<'scope> SignatureProvider<'scope, Error = PE>,
A: Authorities<'d>,
S: Source,
{
self.record.verify_plan_sources(
self,
provider,
operation,
authorities,
utc,
reference,
super::objects::Streams(objects),
membership,
recognizes,
historical,
profile,
)
}
#[expect(
clippy::too_many_arguments,
reason = "algorithm-dependent source execution has separate producing-reader, provider, authority and callback lifetimes"
)]
#[expect(
clippy::result_large_err,
reason = "request-source refusal keeps the actual mapped timestamp and caller causes inline on exhaustion"
)]
pub fn verify_requests_with_profile<'a, P, PE, A, S, RE, HE, FE>(
&self,
provider: &'a P,
operation: &Reader<'a>,
authorities: &'a A,
utc: &LeapTable<'a>,
reference: Instant,
objects: &mut [S],
membership: Membership,
recognizes: impl FnMut(usize, &TokenExtension<'_>, &Execution<'_>) -> Result<bool, RE>,
historical: impl FnMut(Historical<'_, 'a>, &Execution<'_>) -> Result<Decision, HE>,
profile: impl for<'view, 'scope> FnMut(
usize,
timestamp::ProfileInput<'view, 'd, 'a, 'scope>,
) -> Result<(), ProfileFailure<FE>>,
) -> VerificationResult<'a, 'd, S::Error, PE, RE, A::Error, HE, FE>
where
'r: 'a,
'd: 'a,
P: for<'scope> SignatureProvider<'scope, Error = PE>,
A: Authorities<'d>,
S: crate::digest::RequestSource<'a, P>,
{
self.record.verify_plan_sources(
self,
provider,
operation,
authorities,
utc,
reference,
super::objects::Requests(objects),
membership,
recognizes,
historical,
profile,
)
}
}
#[expect(
clippy::result_large_err,
reason = "the actual carried information/source-map failure must survive before provider or covered-source side effects"
)]
pub fn token_algorithm<'d>(
token: ×tamp::Token<'d>,
parent: &Reader<'d>,
) -> Result<Algorithm, ContentError<InfoError<AlgorithmError>>> {
token.with_info(parent, |info, reader, _| {
if info.has_faults() {
return Err(AlgorithmError::Processing(Error::schema(
ErrorCode::MalformedValue,
FIELD,
info.span().start,
)));
}
let timestamp::HashAlgorithmReading::Identifier(identifier) = info.imprint().algorithm()
else {
return Err(AlgorithmError::Processing(Error::schema(
ErrorCode::AlgorithmSyntax,
FIELD,
info.imprint().span().start,
)));
};
known(identifier, &reader.execution())
})
}
fn known<W: Work>(
identifier: &structured_pkix::AlgorithmIdentifier<'_>,
work: &W,
) -> Result<Algorithm, AlgorithmError> {
match digest::algorithm(identifier, work)
.map_err(|cause| AlgorithmError::Processing(Error::pkix(cause)))?
{
Resolution::Supported(value) => Ok(value),
Resolution::Unsupported => Err(AlgorithmError::Unsupported {
at: identifier.offset(),
}),
Resolution::Malformed => Err(AlgorithmError::Processing(Error::schema(
ErrorCode::AlgorithmSyntax,
FIELD,
identifier.offset(),
))),
}
}
fn original_algorithm_error(cause: AlgorithmError) -> PlanError {
match cause {
AlgorithmError::Processing(cause) => PlanError::Processing(cause),
AlgorithmError::Unsupported { at } => PlanError::UnsupportedAlgorithm { at },
}
}
fn insert_algorithm<W: Work>(
set: &mut OwnedVec<Algorithm, W>,
value: Algorithm,
work: &W,
at: u64,
) -> crate::Result<()> {
for member in &*set {
work.charge_work(1)
.map_err(|cause| Error::resource(cause, FIELD, at))?;
if *member == value {
return Ok(());
}
}
set.try_push(value)
.map_err(|cause| Error::resource(cause, FIELD, at))
}
fn require_width<W: Work>(
stamp: &ArchiveTimeStamp<'_>,
width: usize,
work: &W,
) -> crate::Result<()> {
if let Some(tree) = &stamp.tree {
for level in tree {
for hash in &level.hashes {
work.charge_work(1)
.map_err(|cause| Error::resource(cause, FIELD, hash.span().start))?;
if hash.len() != width {
return Err(Error::schema(
ErrorCode::DigestWidth,
FIELD,
hash.span().start,
));
}
}
}
}
Ok(())
}
fn require_union<W: Work>(
declared: &[Algorithm],
used: &[Algorithm],
work: &W,
at: u64,
) -> crate::Result<()> {
for (left, right) in [(declared, used), (used, declared)] {
for requested in left {
let mut found = false;
for actual in right {
work.charge_work(1)
.map_err(|cause| Error::resource(cause, FIELD, at))?;
if requested == actual {
found = true;
break;
}
}
if !found {
return Err(Error::schema(ErrorCode::AlgorithmProtection, FIELD, at));
}
}
}
Ok(())
}
impl<'document> EvidenceRecord<'document> {
#[expect(
clippy::result_large_err,
reason = "preflight returns the carried-source diagnostic even when no diagnostic allocation can succeed"
)]
pub fn input_plan(
&self,
operation: &Reader<'_>,
) -> Result<InputPlan<'_, 'document>, PlanError> {
InputPlan::read(self, operation)
}
#[expect(
clippy::too_many_arguments,
reason = "standalone verification receives explicit source/group, provider, authority, UTC and historical/recognition boundaries"
)]
#[expect(
clippy::result_large_err,
reason = "standalone verification retains original failure categories without allocating error storage on resource refusal"
)]
pub fn verify<'a, P, PE, A, S, RE, HE>(
&'a self,
provider: &'a P,
operation: &Reader<'a>,
authorities: &'a A,
utc: &LeapTable<'a>,
reference: Instant,
objects: &mut [S],
membership: Membership,
recognizes: impl FnMut(usize, &TokenExtension<'_>, &Execution<'_>) -> Result<bool, RE>,
historical: impl FnMut(Historical<'_, 'a>, &Execution<'_>) -> Result<Decision, HE>,
) -> VerificationResult<'a, 'document, S::Error, PE, RE, A::Error, HE>
where
'document: 'a,
P: for<'scope> SignatureProvider<'scope, Error = PE>,
A: Authorities<'document>,
S: Source,
{
self.verify_with_profile(
provider,
operation,
authorities,
utc,
reference,
objects,
membership,
recognizes,
historical,
|_, _| Ok::<_, ProfileFailure<Infallible>>(()),
)
}
#[expect(
clippy::too_many_arguments,
reason = "profiled standalone verification keeps original provider/key/UTC inputs and three independently scoped callbacks explicit"
)]
#[expect(
clippy::result_large_err,
reason = "the complete carried mapping and profile/caller causes survive on the nonallocating failure path"
)]
pub fn verify_with_profile<'a, P, PE, A, S, RE, HE, FE>(
&'a self,
provider: &'a P,
operation: &Reader<'a>,
authorities: &'a A,
utc: &LeapTable<'a>,
reference: Instant,
objects: &mut [S],
membership: Membership,
recognizes: impl FnMut(usize, &TokenExtension<'_>, &Execution<'_>) -> Result<bool, RE>,
historical: impl FnMut(Historical<'_, 'a>, &Execution<'_>) -> Result<Decision, HE>,
profile: impl for<'view, 'scope> FnMut(
usize,
timestamp::ProfileInput<'view, 'document, 'a, 'scope>,
) -> Result<(), ProfileFailure<FE>>,
) -> VerificationResult<'a, 'document, S::Error, PE, RE, A::Error, HE, FE>
where
'document: 'a,
P: for<'scope> SignatureProvider<'scope, Error = PE>,
A: Authorities<'document>,
S: Source,
{
self.verify_sources(
provider,
operation,
authorities,
utc,
reference,
super::objects::Streams(objects),
membership,
recognizes,
historical,
profile,
)
}
#[expect(
clippy::too_many_arguments,
reason = "schema-derived request sources retain their original authority, execution and callback boundaries without a second dispatcher"
)]
#[expect(
clippy::result_large_err,
reason = "format-source errors and mapped token/profile refusals remain distinct without allocating error storage"
)]
pub fn verify_requests_with_profile<'a, P, PE, A, S, RE, HE, FE>(
&'a self,
provider: &'a P,
operation: &Reader<'a>,
authorities: &'a A,
utc: &LeapTable<'a>,
reference: Instant,
objects: &mut [S],
membership: Membership,
recognizes: impl FnMut(usize, &TokenExtension<'_>, &Execution<'_>) -> Result<bool, RE>,
historical: impl FnMut(Historical<'_, 'a>, &Execution<'_>) -> Result<Decision, HE>,
profile: impl for<'view, 'scope> FnMut(
usize,
timestamp::ProfileInput<'view, 'document, 'a, 'scope>,
) -> Result<(), ProfileFailure<FE>>,
) -> VerificationResult<'a, 'document, S::Error, PE, RE, A::Error, HE, FE>
where
'document: 'a,
P: for<'scope> SignatureProvider<'scope, Error = PE>,
A: Authorities<'document>,
S: crate::digest::RequestSource<'a, P>,
{
self.verify_sources(
provider,
operation,
authorities,
utc,
reference,
super::objects::Requests(objects),
membership,
recognizes,
historical,
profile,
)
}
#[expect(
clippy::too_many_arguments,
reason = "one dispatch forwards the same literal/request-source verification contexts and separately scoped callbacks"
)]
#[expect(
clippy::result_large_err,
reason = "forwarding cannot replace preflight, source-map or opaque caller errors with an allocating wrapper"
)]
fn verify_sources<'a, P, PE, A, S, RE, HE, FE>(
&'a self,
provider: &'a P,
operation: &Reader<'a>,
authorities: &'a A,
utc: &LeapTable<'a>,
reference: Instant,
objects: S,
membership: Membership,
recognizes: impl FnMut(usize, &TokenExtension<'_>, &Execution<'_>) -> Result<bool, RE>,
historical: impl FnMut(Historical<'_, 'a>, &Execution<'_>) -> Result<Decision, HE>,
profile: impl for<'view, 'scope> FnMut(
usize,
timestamp::ProfileInput<'view, 'document, 'a, 'scope>,
) -> Result<(), ProfileFailure<FE>>,
) -> VerificationResult<'a, 'document, S::Error, PE, RE, A::Error, HE, FE>
where
'document: 'a,
P: for<'scope> SignatureProvider<'scope, Error = PE>,
A: Authorities<'document>,
S: super::objects::Sources<'a, P>,
{
let plan = InputPlan::read(self, operation).map_err(VerificationError::Plan)?;
self.verify_plan_sources(
&plan,
provider,
operation,
authorities,
utc,
reference,
objects,
membership,
recognizes,
historical,
profile,
)
}
#[expect(
clippy::too_many_arguments,
reason = "the single execution kernel binds the original plan and all already-admitted source/provider/callback contexts"
)]
#[expect(
clippy::result_large_err,
reason = "token, renewal, selector and source-map refusals are returned unchanged when allocation is unavailable"
)]
fn verify_plan_sources<'a, P, PE, A, S, RE, HE, FE>(
&'a self,
plan: &InputPlan<'a, 'document>,
provider: &'a P,
operation: &Reader<'a>,
authorities: &'a A,
utc: &LeapTable<'a>,
reference: Instant,
objects: S,
membership: Membership,
mut recognizes: impl FnMut(usize, &TokenExtension<'_>, &Execution<'_>) -> Result<bool, RE>,
mut historical: impl FnMut(Historical<'_, 'a>, &Execution<'_>) -> Result<Decision, HE>,
mut profile: impl for<'view, 'scope> FnMut(
usize,
timestamp::ProfileInput<'view, 'document, 'a, 'scope>,
) -> Result<(), ProfileFailure<FE>>,
) -> VerificationResult<'a, 'document, S::Error, PE, RE, A::Error, HE, FE>
where
'document: 'a,
P: for<'scope> SignatureProvider<'scope, Error = PE>,
A: Authorities<'document>,
S: super::objects::Sources<'a, P>,
{
engine::execute!(
resident,
self,
plan,
provider,
operation,
authorities,
utc,
reference,
objects,
membership,
recognizes,
historical,
profile
)
}
}
enum GroupError {
Processing(Error),
Membership(usize),
}
fn admit_membership<W: Work>(
record: &EvidenceRecord<'_>,
objects: usize,
membership: Membership,
work: &W,
) -> Result<(), GroupError> {
let at = record.original.element.span().start;
if objects == 0 || (membership == Membership::Object && objects != 1) {
return Err(GroupError::Processing(Error::schema(
ErrorCode::MissingField,
FIELD,
at,
)));
}
for chain in &record.chains {
work.charge_work(1)
.map_err(|cause| GroupError::Processing(Error::resource(cause, FIELD, at)))?;
if !super::input::membership_shape(&record.timestamps[chain.first], objects, membership) {
return Err(GroupError::Membership(chain.first));
}
}
Ok(())
}
type Prefixes<'r, 'd> = OwnedVec<Option<PriorSequence<'r, 'd>>>;
fn prior_views<'r, 'd, W: Work>(
record: &'r EvidenceRecord<'d>,
projected: &'r [crate::encoding::Projection<'d>],
operation: &Reader<'_>,
work: &W,
) -> crate::Result<Prefixes<'r, 'd>> {
let resource = |cause| Error::resource(cause, FIELD, record.original.element.span().start);
let mut prefixes = work.vector();
prefixes
.try_reserve_exact(record.chains.len())
.map_err(resource)?;
prefixes.try_push(None).map_err(resource)?;
for index in 1..record.chains.len() {
prefixes
.try_push(Some(PriorSequence::borrowed(
record, index, projected, operation,
)?))
.map_err(resource)?;
}
Ok(prefixes.into_owned())
}
fn order_findings<W: Work>(
checks: &[Checked<'_>],
utc: &LeapTable<'_>,
operation: &Reader<'_>,
work: &W,
at: u64,
) -> crate::Result<OwnedVec<OrderFinding>> {
let resource = |cause| Error::resource(cause, FIELD, at);
let mut findings = work.vector();
for pair in checks.windows(2) {
work.charge_work(1).map_err(resource)?;
if let Some(cause) = order(&pair[1], &pair[0], utc, operation)? {
findings
.try_push(OrderFinding {
earlier: pair[1].index,
later: pair[0].index,
cause,
})
.map_err(resource)?;
}
}
Ok(findings.into_owned())
}
fn history_input<'v, 'a>(
record: &EvidenceRecord<'_>,
chain: usize,
index: usize,
current: &'v CheckedTimestamp<'a>,
selection: &'v Selection<'a>,
checks: &'v [Checked<'a>],
reference: Instant,
) -> Historical<'v, 'a> {
let following = checks.last().and_then(|next| next.common.evidence());
let following_chain = record
.chains
.get(chain + 1)
.and_then(|next| checks.get(record.timestamps.len() - 1 - next.first))
.and_then(|next| next.common.evidence());
Historical {
index,
current,
selection,
following,
following_chain,
verification_time: reference,
}
}
fn order(
earlier: &Checked<'_>,
later: &Checked<'_>,
utc: &LeapTable<'_>,
operation: &Reader<'_>,
) -> crate::Result<Option<OrderCause>> {
let work = operation.execution();
let (Some(a), Some(b)) = (earlier.common.evidence(), later.common.evidence()) else {
return Ok(Some(OrderCause::UnprovenTimestamp));
};
order_evidence(
a,
earlier.selection.certificate,
b,
later.selection.certificate,
utc,
&work,
)
}
pub fn order_evidence<W: Work>(
a: &Evidence,
left: &Certificate<'_>,
b: &Evidence,
right: &Certificate<'_>,
utc: &LeapTable<'_>,
work: &W,
) -> crate::Result<Option<OrderCause>> {
let resource = |cause| Error::resource(cause, FIELD, a.source().carrier().start);
if a.facts().ordering() && b.facts().ordering() {
let first = left.execution_in(work);
let second = right.execution_in(work);
first.charge_work(1).map_err(resource)?;
second.charge_work(1).map_err(resource)?;
let same = if core::ptr::eq(left, right) {
true
} else if left.as_bytes().len() != right.as_bytes().len() {
false
} else {
first
.charge_work(left.as_bytes().len() as u64)
.map_err(resource)?;
second
.charge_work(right.as_bytes().len() as u64)
.map_err(resource)?;
left.as_bytes() == right.as_bytes()
};
if same {
return match a.facts().compare_generation(b.facts(), utc, work) {
Ok(core::cmp::Ordering::Greater) => Ok(Some(OrderCause::Reversed)),
Ok(_) => Ok(None),
Err(timestamp::GenerationOrderError::Resource(cause)) => Err(resource(cause)),
Err(timestamp::GenerationOrderError::Uncertain(cause)) => {
Ok(Some(OrderCause::Utc(cause)))
}
};
}
}
let a = match timestamp::interval_in(a.facts().gen_time(), a.facts().accuracy(), utc, work) {
Ok(value) => Ok(value),
Err(timestamp::IntervalError::Resource(cause)) => return Err(resource(cause)),
Err(timestamp::IntervalError::Uncertain(cause)) => Err(cause),
};
let b = match timestamp::interval_in(b.facts().gen_time(), b.facts().accuracy(), utc, work) {
Ok(value) => Ok(value),
Err(timestamp::IntervalError::Resource(cause)) => return Err(resource(cause)),
Err(timestamp::IntervalError::Uncertain(cause)) => Err(cause),
};
match (a, b) {
(Ok(a), Ok(b)) if a.latest <= b.earliest => Ok(None),
(Ok(a), Ok(b)) if a.earliest > b.latest => Ok(Some(OrderCause::Reversed)),
(Ok(_), Ok(_)) => Ok(Some(OrderCause::Overlap)),
(a, b) => Ok(Some(OrderCause::Bounds {
earlier: a.err(),
later: b.err(),
})),
}
}