structured_cades/evidence/
coverage.rs1use super::record::{Checked, Verified};
3use crate::{
4 Cades, Error, ISSUER,
5 material::Index,
6 source::{DocumentId, Node},
7 timestamp,
8};
9use structured_asn1::{
10 Reader, Span,
11 memory::{Memory, OwnedVec, SortError, Work},
12};
13use structured_ltv::{
14 material::{Coverage, IndexError},
15 source::{Scope, Source as _},
16};
17const FIELD: &str = "cades.evidence.coverage";
18type Items<'m, 'd> = Coverage<Node, DocumentId<'m, 'd>, (), Memory, Cades>;
19
20#[derive(Debug)]
22pub enum CoverageError {
23 Processing(Error),
25 Index(IndexError<Node>),
27 Foreign {
29 property: Node,
31 },
32}
33pub struct Archive<'view, 'prepared, 'm, 'd, 'path> {
37 report: &'view Checked<'prepared, 'm, 'd, 'path>,
38 timestamp: &'view timestamp::Checked<'m, 'd, 'path>,
39 coverage: Items<'m, 'd>,
40}
41impl<'m, 'd, 'path> Archive<'_, '_, 'm, 'd, 'path> {
42 #[must_use]
44 pub fn timestamp(&self) -> ×tamp::Checked<'m, 'd, 'path> {
45 self.timestamp
46 }
47 #[must_use]
49 pub fn coverage(&self) -> &Items<'m, 'd> {
50 &self.coverage
51 }
52 pub fn requirements(
54 &self,
55 operation: &Reader<'d>,
56 ) -> Result<
57 structured_ltv::timestamp::TimestampRequirements<Node, DocumentId<'m, 'd>, (), Cades>,
58 timestamp::ArchiveScopeError,
59 > {
60 timestamp::requirements::derive(
61 self.timestamp,
62 &self.coverage,
63 self.report.prepared,
64 operation,
65 )
66 }
67}
68impl<'prepared, 'm, 'd, 'path> Verified<'_, 'prepared, 'm, 'd, 'path> {
69 pub fn archive<'view, W: Work>(
73 &'view self,
74 ordinal: usize,
75 index: &Index<'_, 'm, 'd, W>,
76 operation: &Reader<'d>,
77 ) -> Result<Archive<'view, 'prepared, 'm, 'd, 'path>, CoverageError> {
78 let report = self.report();
79 let prepared = report.prepared;
80 let property = report.required.property;
81 let resource =
82 |cause| CoverageError::Processing(Error::resource(cause, FIELD, property.span().start));
83 prepared
84 .document()
85 .message()
86 .require_session(operation, FIELD)
87 .map_err(|cause| CoverageError::Processing(Error::Cms(cause)))?;
88 let work = operation.execution();
89 work.charge_work(3).map_err(resource)?;
90 if !report.timestamps.contains(&ordinal)
91 || index.snapshot() != prepared.document().snapshot()
92 || index.signature() != Node::of(prepared.signer().span())
93 {
94 return Err(CoverageError::Foreign { property });
95 }
96 let entry = prepared
97 .parsed
98 .proofs
99 .entries
100 .get(report.proof)
101 .ok_or(CoverageError::Foreign { property })?;
102 if entry.required.property != property {
103 return Err(CoverageError::Foreign { property });
104 }
105 let relative = ordinal - report.timestamps.start;
106 let timestamp = &report.checks[report.checks.len() - 1 - relative];
107 let actor = timestamp
108 .actor()
109 .ok_or(CoverageError::Foreign { property })?;
110 let mut spans = work.vector();
111 let base = report
112 .covered
113 .as_ref()
114 .ok_or(CoverageError::Foreign { property })?;
115 spans.try_extend_from_slice(base).map_err(resource)?;
116 for previous in report.timestamps.start..ordinal {
117 work.charge_work(1).map_err(resource)?;
118 let value = prepared.timestamps()[previous]
119 .value()
120 .ok_or(CoverageError::Foreign { property })?;
121 spans.try_push(value.span()).map_err(resource)?;
122 }
123 normalize(&mut spans, &work).map_err(resource)?;
124 let document = prepared.document();
125 let query = Scope::new(document, document.snapshot(), &work);
126 let mut items = work.map();
127 for occurrence in index
128 .all_occurrences(&query)
129 .map_err(CoverageError::Index)?
130 {
131 let occurrence = occurrence.map_err(CoverageError::Index)?;
132 let node = occurrence.location().node;
133 if selects(&spans, node.span(), &work).map_err(resource)? {
134 items.try_insert(node, true).map_err(resource)?;
135 }
136 }
137 for counter in prepared
138 .counters()
139 .iter()
140 .chain(prepared.parallel_counters())
141 {
142 work.charge_work(1).map_err(resource)?;
143 if selects(&spans, counter.node().span(), &work).map_err(resource)? {
144 items.try_insert(counter.node(), true).map_err(resource)?;
145 }
146 }
147 for entry in prepared.timestamps() {
148 work.charge_work(1).map_err(resource)?;
149 let node = entry
150 .value()
151 .map_or(entry.property(), |value| Node::of(value.span()));
152 if node == actor.verified().token().node {
153 continue;
154 }
155 if selects(&spans, node.span(), &work).map_err(resource)? {
156 items.try_insert(node, true).map_err(resource)?;
157 }
158 if selects(&spans, entry.property().span(), &work).map_err(resource)? {
159 items.try_insert(entry.property(), true).map_err(resource)?;
160 }
161 }
162 let coverage = Coverage::for_token(
163 ISSUER,
164 document.snapshot(),
165 report.required.signature,
166 property,
167 actor.verified().token().node,
168 structured_ltv::timestamp::Purpose::Archive,
169 items.into_owned(),
170 );
171 Ok(Archive {
172 report,
173 timestamp,
174 coverage,
175 })
176 }
177}
178pub(super) fn normalize_owned<W: Work>(
179 spans: OwnedVec<Span>,
180 work: &W,
181 at: u64,
182) -> Result<OwnedVec<Span>, Error> {
183 let mut spans = spans
184 .with_execution(work)
185 .map_err(|_| Error::Foreign { at })?;
186 normalize(&mut spans, work).map_err(|cause| Error::resource(cause, FIELD, at))?;
187 Ok(spans.into_owned())
188}
189fn normalize<W: Work>(
190 spans: &mut OwnedVec<Span, W>,
191 work: &W,
192) -> Result<(), structured_asn1::memory::MemoryError> {
193 spans
194 .try_sort_unstable_by(|a, b| {
195 work.charge_work(3)?;
196 Ok::<_, structured_asn1::memory::MemoryError>(
197 a.start.cmp(&b.start).then_with(|| b.length.cmp(&a.length)),
198 )
199 })
200 .map_err(|cause| match cause {
201 SortError::Resource(cause) | SortError::Comparison(cause) => cause,
202 })?;
203 let mut written = 0;
204 for read in 0..spans.len() {
205 work.charge_work(3)?;
206 let current = spans[read];
207 if written != 0 && current.start <= spans[written - 1].end() {
208 let previous = &mut spans[written - 1];
209 if current.end() > previous.end() {
210 previous.length = current.end() - previous.start;
211 }
212 } else {
213 spans[written] = current;
214 written += 1;
215 }
216 }
217 while spans.len() > written {
218 work.charge_work(1)?;
219 spans.pop();
220 }
221 Ok(())
222}
223pub(super) fn selects<W: Work>(
224 spans: &[Span],
225 node: Span,
226 work: &W,
227) -> Result<bool, structured_asn1::memory::MemoryError> {
228 let mut low = 0;
229 let mut high = spans.len();
230 while low < high {
231 work.charge_work(2)?;
232 let middle = low + (high - low) / 2;
233 if spans[middle].start <= node.start {
234 low = middle + 1;
235 } else {
236 high = middle;
237 }
238 }
239 if low == 0 {
240 return Ok(false);
241 }
242 work.charge_work(1)?;
243 Ok(spans[low - 1].end() >= node.end())
244}