holos_tda/distributed/store/
verification.rs1use crate::{CertificateLimits, RelativeInterfaceCertificate};
2
3use super::super::compose::{
4 check_fold_id, combined_vertices, compose_certificates, decode_certificate, encode_certificate,
5 require_compatible, require_separator,
6};
7use super::super::model::{
8 ArtifactId, DistributedInterfaceError, DistributedInterfaceManifest, DurableInterfaceStore,
9};
10
11impl DurableInterfaceStore {
12 pub fn verify_manifest(
17 &self,
18 manifest: &DistributedInterfaceManifest,
19 limits: CertificateLimits,
20 ) -> Result<RelativeInterfaceCertificate, DistributedInterfaceError> {
21 let mut accumulator = self.load_manifest_start(manifest, limits)?;
22 self.replay_manifest_folds(manifest, limits, &mut accumulator)?;
23 if accumulator.protected_vertices() != manifest.output_protected_vertices {
24 accumulator =
25 compose_certificates(&[&accumulator], &manifest.output_protected_vertices, limits)?;
26 }
27 self.check_manifest_result(manifest, &accumulator, limits)?;
28 Ok(accumulator)
29 }
30
31 fn load_manifest_start(
32 &self,
33 manifest: &DistributedInterfaceManifest,
34 limits: CertificateLimits,
35 ) -> Result<RelativeInterfaceCertificate, DistributedInterfaceError> {
36 let bytes = self.get(manifest.shards[0], limits.max_bytes)?;
37 let accumulator = decode_certificate(&bytes, limits)?;
38 require_separator(&accumulator, &manifest.separator_vertices)?;
39 check_fold_id(&bytes, manifest.folds[0])?;
40 Ok(accumulator)
41 }
42
43 fn replay_manifest_folds(
44 &self,
45 manifest: &DistributedInterfaceManifest,
46 limits: CertificateLimits,
47 accumulator: &mut RelativeInterfaceCertificate,
48 ) -> Result<(), DistributedInterfaceError> {
49 let intermediate = combined_vertices(
50 &manifest.separator_vertices,
51 &manifest.output_protected_vertices,
52 );
53 for (position, shard) in manifest.shards.iter().enumerate().skip(1) {
54 self.replay_manifest_fold(
55 manifest,
56 limits,
57 &intermediate,
58 accumulator,
59 position,
60 *shard,
61 )?;
62 }
63 Ok(())
64 }
65
66 fn replay_manifest_fold(
67 &self,
68 manifest: &DistributedInterfaceManifest,
69 limits: CertificateLimits,
70 intermediate: &[usize],
71 accumulator: &mut RelativeInterfaceCertificate,
72 position: usize,
73 shard: ArtifactId,
74 ) -> Result<(), DistributedInterfaceError> {
75 let bytes = self.get(shard, limits.max_bytes)?;
76 let child = decode_certificate(&bytes, limits)?;
77 require_compatible(accumulator, &child)?;
78 require_separator(&child, &manifest.separator_vertices)?;
79 *accumulator = compose_certificates(&[accumulator, &child], intermediate, limits)?;
80 check_fold_id(
81 &encode_certificate(accumulator, limits)?,
82 manifest.folds[position],
83 )
84 }
85
86 fn check_manifest_result(
87 &self,
88 manifest: &DistributedInterfaceManifest,
89 accumulator: &RelativeInterfaceCertificate,
90 limits: CertificateLimits,
91 ) -> Result<(), DistributedInterfaceError> {
92 let encoded = encode_certificate(accumulator, limits)?;
93 if ArtifactId::for_bytes(&encoded) != manifest.result {
94 return Err(DistributedInterfaceError::new(
95 "manifest result differs from recomputation",
96 ));
97 }
98 let stored = self.get(manifest.result, limits.max_bytes)?;
99 if stored != encoded {
100 return Err(DistributedInterfaceError::new(
101 "stored result differs from recomputed result",
102 ));
103 }
104 Ok(())
105 }
106}