qualia_client_core/
vision_10d_rights.rs1use qualia_core_db::container_10d::{
8 header::Container10dHeader,
9 integrity::verify_whole_file_crc32c,
10 parse_section_table,
11 provenance_section::{decode_provenance_section, validate_provenance},
12 section::SectionType,
13};
14use serde::Serialize;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
18pub enum Vision10dAccess {
19 BrowseAllowUnattested,
21 CitableRequireProvenance,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
27pub enum Vision10dBarrier {
28 Permit,
29 Deny { reason: &'static str },
30}
31
32pub fn evaluate_vision_10d_barrier(bytes: &[u8], access: Vision10dAccess) -> Vision10dBarrier {
34 let mut bytes_mut = bytes.to_vec();
35 if verify_whole_file_crc32c(&mut bytes_mut).is_err() {
36 return Vision10dBarrier::Deny {
37 reason: "crc_failed",
38 };
39 }
40 let Ok(header) = Container10dHeader::parse(&bytes_mut) else {
41 return Vision10dBarrier::Deny {
42 reason: "bad_header",
43 };
44 };
45 let Ok(descs) = parse_section_table(&bytes_mut, &header) else {
46 return Vision10dBarrier::Deny {
47 reason: "bad_section_table",
48 };
49 };
50
51 let mut has_mesh = false;
52 let mut prov_payload: Option<&[u8]> = None;
53 for d in descs.iter() {
54 match d.typ() {
55 Some(SectionType::QuantizedMesh) => has_mesh = true,
56 Some(SectionType::ProvenanceSidecar) => {
57 let start = d.byte_offset as usize;
58 let end = start.saturating_add(d.byte_length as usize);
59 prov_payload = bytes_mut.get(start..end);
60 }
61 _ => {}
62 }
63 }
64 if !has_mesh {
65 return Vision10dBarrier::Deny {
66 reason: "no_mesh_section",
67 };
68 }
69
70 match access {
71 Vision10dAccess::BrowseAllowUnattested => Vision10dBarrier::Permit,
72 Vision10dAccess::CitableRequireProvenance => match prov_payload {
73 None => Vision10dBarrier::Deny {
74 reason: "missing_provenance",
75 },
76 Some(payload) => match decode_provenance_section(payload) {
77 Err(_) => Vision10dBarrier::Deny {
78 reason: "provenance_decode_failed",
79 },
80 Ok(view) => match validate_provenance(&view) {
81 Ok(()) => Vision10dBarrier::Permit,
82 Err(_) => Vision10dBarrier::Deny {
83 reason: "provenance_invalid",
84 },
85 },
86 },
87 },
88 }
89}
90
91pub fn vision_10d_may_load(bytes: &[u8], access: Vision10dAccess) -> bool {
93 matches!(
94 evaluate_vision_10d_barrier(bytes, access),
95 Vision10dBarrier::Permit
96 )
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use qualia_core_db::container_10d::provenance_section::ProvenanceSidecar;
103 use qualia_core_db::render::assets::Mesh;
104 use qualia_core_db::render::compile_10d::{
105 compile_mesh_to_10d_vision, compile_mesh_to_10d_vision_with_provenance,
106 };
107 use qualia_core_db::tensor::Tensor10D;
108
109 fn tri_mesh() -> Mesh {
110 Mesh {
111 positions: vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
112 triangles: vec![[0, 1, 2]],
113 min: [0.0, 0.0, 0.0],
114 max: [1.0, 1.0, 0.0],
115 }
116 }
117
118 #[test]
119 fn unattested_denied_for_citable() {
120 let nodes = [Tensor10D::default()];
121 let bytes = compile_mesh_to_10d_vision(&tri_mesh(), &nodes).unwrap();
122 assert!(matches!(
123 evaluate_vision_10d_barrier(&bytes, Vision10dAccess::CitableRequireProvenance),
124 Vision10dBarrier::Deny {
125 reason: "missing_provenance"
126 }
127 ));
128 assert!(matches!(
129 evaluate_vision_10d_barrier(&bytes, Vision10dAccess::BrowseAllowUnattested),
130 Vision10dBarrier::Permit
131 ));
132 }
133
134 #[test]
135 fn attested_permits_citable() {
136 let nodes = [Tensor10D::default()];
137 let prov = ProvenanceSidecar::new(b"source-rgb-stub".to_vec(), "image/rgb8", "CC0");
138 let bytes = compile_mesh_to_10d_vision_with_provenance(&tri_mesh(), &nodes, &prov).unwrap();
139 assert!(matches!(
140 evaluate_vision_10d_barrier(&bytes, Vision10dAccess::CitableRequireProvenance),
141 Vision10dBarrier::Permit
142 ));
143 }
144}