1use crate::attributes::{self, AttributeXml};
4use crate::binary::{self, BinaryXml, Location};
5use crate::certificate::{self, CheckedPathCertificate};
6use crate::hashes::ParticipantHashes;
7use crate::header;
8use crate::pki::CounterPaths;
9use crate::prepare::Fields;
10use crate::scalar::ScalarXml;
11use crate::xml::{Access, AccessError, Xml};
12use structured_asn1::{
13 Reader,
14 memory::{MemoryError, OwnedVec, Work},
15};
16use structured_ltv::baseline::BasicStage;
17
18#[path = "hints.rs"]
19mod hints;
20
21#[derive(Clone, Copy)]
25pub struct BasicInput<'receipt, 'prepared, 'path, 'document, N, D, G> {
26 pub fields: &'receipt Fields<'prepared, N, D, G>,
28 pub hashes: &'receipt ParticipantHashes<N, D, G>,
30 pub certificate: &'receipt CheckedPathCertificate<'path, 'document, N, D, G>,
32 pub counters: &'receipt CounterPaths<'path, 'document, N, D, G>,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum HintSource {
39 Protected(usize),
41 ValidationReference {
43 property: usize,
45 entry: usize,
47 },
48}
49
50pub struct Hint<N, D, G> {
54 location: Location<N, D, G>,
55 faults: OwnedVec<structured_cms::Error>,
56 source: HintSource,
57}
58impl<N: Copy, D: Copy, G: Copy> Hint<N, D, G> {
59 #[must_use]
61 pub fn source(&self) -> HintSource {
62 self.source
63 }
64 #[must_use]
66 pub fn location(&self) -> Location<N, D, G> {
67 self.location
68 }
69 #[must_use]
72 pub fn faults(&self) -> &[structured_cms::Error] {
73 &self.faults
74 }
75}
76
77pub struct Basic<'receipt, 'prepared, 'path, 'document, N, D, G> {
82 input: BasicInput<'receipt, 'prepared, 'path, 'document, N, D, G>,
83 included: Option<Location<N, D, G>>,
84 hints: OwnedVec<Hint<N, D, G>>,
85 hint_encodings_conform: bool,
86}
87
88impl<'r, 'p, 'v, 'd, N: Copy, D: Copy, G: Copy> Basic<'r, 'p, 'v, 'd, N, D, G> {
89 #[must_use]
91 pub fn inputs(&self) -> &BasicInput<'r, 'p, 'v, 'd, N, D, G> {
92 &self.input
93 }
94 #[must_use]
96 pub fn included(&self) -> Option<Location<N, D, G>> {
97 self.included
98 }
99 #[must_use]
103 pub fn hints(&self) -> &[Hint<N, D, G>] {
104 &self.hints
105 }
106 #[must_use]
111 pub fn all_root_requirements_met(&self) -> bool {
112 self.input.certificate.is_bound() && self.included.is_some() && self.hint_encodings_conform
113 }
114}
115
116impl<'v, 'd, N: Copy, D: Copy, G: Copy> BasicStage<'v, 'd> for Basic<'_, '_, 'v, 'd, N, D, G> {
117 type Id = N;
118 type Document = D;
119 type Generation = G;
120 type Signer = CheckedPathCertificate<'v, 'd, N, D, G>;
121 type Counters = CounterPaths<'v, 'd, N, D, G>;
122
123 fn signer(&self) -> &Self::Signer {
124 self.input.certificate
125 }
126 fn counters(&self) -> &Self::Counters {
127 self.input.counters
128 }
129 fn all_requirements_met(&self) -> bool {
130 self.all_root_requirements_met()
131 }
132}
133
134#[derive(Debug)]
137pub enum BasicError<E, N, D, G> {
138 Foreign {
140 signature: N,
142 },
143 Access(AccessError<E, N>),
145 Attributes(attributes::Error<E, N>),
147 Inclusion(binary::Error<E, header::InclusionError, N, D, G>),
149 Hint(binary::Error<E, certificate::IssuerError<core::convert::Infallible>, N, D, G>),
151 Resource {
153 node: N,
155 cause: MemoryError,
157 },
158}
159
160pub type BasicResult<'receipt, 'prepared, 'path, 'document, X> = Result<
162 Basic<
163 'receipt,
164 'prepared,
165 'path,
166 'document,
167 <X as Xml>::Id,
168 <X as Xml>::Document,
169 <X as Xml>::Generation,
170 >,
171 BasicError<<X as Xml>::Error, <X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>,
172>;
173type InputFor<'r, 'p, 'v, 'd, X> =
174 BasicInput<'r, 'p, 'v, 'd, <X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
175type ProcessingResult<T, X> = Result<
176 T,
177 BasicError<<X as Xml>::Error, <X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>,
178>;
179
180pub fn basic<'r, 'p, 'v, 'd, X: BinaryXml + AttributeXml + ScalarXml>(
189 input: InputFor<'r, 'p, 'v, 'd, X>,
190 xml: &X,
191 operation: &Reader<'_>,
192) -> BasicResult<'r, 'p, 'v, 'd, X> {
193 let prepared = input.fields.prepared();
194 let layout = prepared.bound().containers();
195 let signature = layout.signature();
196 let work = operation.execution();
197 let access = Access::new(xml, layout.snapshot(), &work);
198 require_sources(&input, &access)?;
199 attributes::check_counters(prepared, input.counters, &access)
200 .map_err(BasicError::Attributes)?;
201 let included = header::included(
202 xml,
203 prepared.header(),
204 input.certificate.selected().certificate(),
205 &work,
206 )
207 .map_err(BasicError::Inclusion)?;
208 let hints = hints::check_encodings(prepared, xml, operation)?;
209 access
210 .query(signature, |_, _, _| Ok(()))
211 .map_err(BasicError::Access)?;
212 Ok(Basic {
213 input,
214 included,
215 hints: hints.items,
216 hint_encodings_conform: hints.all_conformant,
217 })
218}
219
220fn require_sources<X: Xml, W: Work>(
221 input: &InputFor<'_, '_, '_, '_, X>,
222 access: &Access<'_, X, W>,
223) -> ProcessingResult<(), X> {
224 let prepared = input.fields.prepared();
225 let layout = prepared.bound().containers();
226 let signature = layout.signature();
227 let foreign = || BasicError::Foreign { signature };
228 if input.hashes.snapshot() != access.snapshot()
229 || input.counters.snapshot() != access.snapshot()
230 || !core::ptr::eq(
231 input.certificate.selected().reference(),
232 prepared.certificates(),
233 )
234 {
235 return Err(foreign());
236 }
237 access
238 .query(signature, |_, _, _| Ok(()))
239 .map_err(BasicError::Access)?;
240 let resource = |cause| BasicError::Resource {
241 node: signature,
242 cause,
243 };
244 if !access
245 .equal_id(signature, input.hashes.signature())
246 .map_err(resource)?
247 || !access
248 .equal_id(signature, input.counters.signature())
249 .map_err(resource)?
250 || input.hashes.counters().len() != input.counters.actors().len()
251 {
252 return Err(foreign());
253 }
254 for (hash, actor) in input.hashes.counters().iter().zip(input.counters.actors()) {
255 if !access
256 .equal_id(
257 hash.signature(),
258 actor.signer().counter().original().child(),
259 )
260 .map_err(resource)?
261 {
262 return Err(foreign());
263 }
264 }
265 Ok(())
266}