Skip to main content

rns_core/resource/
assembly.rs

1//! Owned, authenticated Resource data that can be verified away from its receiver.
2use super::{
3    parts::extract_metadata_owned,
4    proof::{build_proof_data, data_hash_state, finish_with},
5    ResourceAction, ResourceError,
6};
7use crate::{
8    buffer::types::{Compressor, DecompressError},
9    constants::RESOURCE_RANDOM_HASH_SIZE,
10};
11use alloc::{boxed::Box, sync::Arc, vec, vec::Vec};
12use rns_crypto::sha256::Sha256;
13
14/// Identity of one assembly attempt. Equality compares attempts, not Resource hashes.
15#[derive(Clone, Debug)]
16pub struct AssemblyId(Arc<()>);
17impl AssemblyId {
18    pub(super) fn new() -> Self {
19        Self(Arc::new(()))
20    }
21}
22impl PartialEq for AssemblyId {
23    fn eq(&self, other: &Self) -> bool {
24        Arc::ptr_eq(&self.0, &other.0)
25    }
26}
27impl Eq for AssemblyId {}
28
29/// A consuming handoff. Authentication has already succeeded when encryption is used.
30/// No protocol actions are published until the receiver accepts the returned result.
31pub struct ResourceAssembly {
32    pub(super) id: AssemblyId,
33    pub(super) data: AssemblyData,
34}
35/// A completed attempt, bound to its original receiver. Contents are deliberately private.
36pub struct AssemblyResult {
37    pub(super) id: AssemblyId,
38    pub(super) result: Result<Vec<ResourceAction>, ResourceError>,
39}
40fn decompress_error(error: DecompressError) -> ResourceError {
41    match error {
42        DecompressError::TooLarge => ResourceError::TooLarge,
43        DecompressError::InvalidData => ResourceError::DecompressionFailed,
44    }
45}
46
47impl ResourceAssembly {
48    pub fn id(&self) -> &AssemblyId {
49        &self.id
50    }
51    /// Whether the data is compressed and must be decompressed to assemble.
52    pub fn is_compressed(&self) -> bool {
53        self.data.compressed
54    }
55    /// Take the authenticated data still to be decompressed, for a caller
56    /// that decompresses it in pieces and then calls
57    /// [`Self::finish_decompressed`] or [`Self::decompression_failed`].
58    pub fn take_compressed_data(&mut self) -> Vec<u8> {
59        core::mem::take(&mut self.data.plaintext)
60    }
61    /// [`Self::run`] for data the caller decompressed itself, within
62    /// [`Self::max_output_size`]; `data_state`, when given, is SHA-256 over
63    /// `decompressed`.
64    pub fn finish_decompressed(
65        self,
66        decompressed: Vec<u8>,
67        data_state: Option<Sha256>,
68    ) -> AssemblyResult {
69        AssemblyResult {
70            id: self.id,
71            result: self.data.finish(decompressed, data_state),
72        }
73    }
74    /// The result of an assembly whose decompression failed: `too_large`
75    /// when the output exceeded [`Self::max_output_size`].
76    pub fn decompression_failed(self, too_large: bool) -> AssemblyResult {
77        AssemblyResult {
78            id: self.id,
79            result: Err(decompress_error(if too_large {
80                DecompressError::TooLarge
81            } else {
82                DecompressError::InvalidData
83            })),
84        }
85    }
86    /// Owned plaintext capacity retained while the attempt is queued.
87    pub fn input_capacity(&self) -> usize {
88        self.data.plaintext.capacity()
89    }
90    /// Decoder output bound, independent of the advertised data size.
91    pub fn max_output_size(&self) -> usize {
92        self.data.limit
93    }
94    pub fn run(self, compressor: &dyn Compressor) -> AssemblyResult {
95        AssemblyResult {
96            id: self.id,
97            result: self.data.run(compressor),
98        }
99    }
100}
101
102pub(super) struct AssemblyData {
103    pub plaintext: Vec<u8>,
104    /// SHA-256 over `plaintext`, when it was hashed as it was decrypted.
105    pub data_state: Option<Box<Sha256>>,
106    pub random_hash: [u8; RESOURCE_RANDOM_HASH_SIZE],
107    pub resource_hash: [u8; 32],
108    pub compressed: bool,
109    pub metadata: bool,
110    pub app_flag: bool,
111    pub limit: usize,
112}
113impl AssemblyData {
114    pub fn run(
115        mut self,
116        compressor: &dyn Compressor,
117    ) -> Result<Vec<ResourceAction>, ResourceError> {
118        // The receiver already dropped the random prefix.
119        let plaintext = core::mem::take(&mut self.plaintext);
120        let (decompressed, data_state) = if self.compressed {
121            let decompressed = compressor
122                .decompress_bounded(&plaintext, self.limit)
123                .map_err(decompress_error)?;
124            (decompressed, None)
125        } else {
126            (plaintext, self.data_state.take().map(|state| *state))
127        };
128        self.finish(decompressed, data_state)
129    }
130
131    /// Check `decompressed` against the resource hash and build the proof and
132    /// delivery. `data_state`, when given, is SHA-256 over `decompressed`.
133    fn finish(
134        self,
135        decompressed: Vec<u8>,
136        data_state: Option<Sha256>,
137    ) -> Result<Vec<ResourceAction>, ResourceError> {
138        let data_state = data_state.unwrap_or_else(|| data_hash_state(&decompressed));
139        let hash = finish_with(&data_state, &self.random_hash);
140        if hash != self.resource_hash {
141            return Err(ResourceError::HashMismatch);
142        }
143        // Proof covers the complete data, including its metadata prefix.
144        let proof = build_proof_data(&hash, &finish_with(&data_state, &hash));
145        let (data, metadata) = if self.metadata {
146            let (metadata, data) =
147                extract_metadata_owned(decompressed).ok_or(ResourceError::InvalidPart)?;
148            (data, Some(metadata))
149        } else {
150            (decompressed, None)
151        };
152        Ok(vec![
153            ResourceAction::SendProof(proof),
154            ResourceAction::DataReceived {
155                data,
156                metadata,
157                app_flag: self.app_flag,
158            },
159            ResourceAction::Completed,
160        ])
161    }
162}