Skip to main content

tzap_core/
root_auth.rs

1use sha2::{Digest, Sha256};
2
3use crate::format::{
4    AeadAlgo, BlockKind, CompressionAlgo, FecAlgo, FormatError, KdfAlgo, FORMAT_VERSION,
5    ROOT_AUTH_SPEC_ID, VOLUME_FORMAT_REV,
6};
7
8const ROOT_AUTH_DESCRIPTOR_DOMAIN: &[u8] = b"tzap-root-auth-descriptor-v1\0";
9const ARCHIVE_ROOT_DOMAIN: &[u8] = b"tzap-archive-root-v43\0";
10const CRYPTO_HEADER_PRE_HMAC_DOMAIN: &[u8] = b"tzap-crypto-header-pre-hmac-v43\0";
11const MANIFEST_FOOTER_GLOBAL_PRE_HMAC_DOMAIN: &[u8] = b"tzap-manifest-footer-global-pre-hmac-v43\0";
12const CRITICAL_METADATA_DOMAIN: &[u8] = b"tzap-critical-metadata-v43\0";
13const INDEX_ROOT_DOMAIN: &[u8] = b"tzap-index-root-v43\0";
14const FEC_LAYOUT_DOMAIN: &[u8] = b"tzap-fec-layout-v43\0";
15const DATA_BLOCK_MERKLE_DOMAIN: &[u8] = b"tzap-data-block-merkle-v43\0";
16const EMPTY_MERKLE_DOMAIN: &[u8] = b"tzap-empty-merkle-tree-v1\0";
17const SIGNER_IDENTITY_DOMAIN: &[u8] = b"tzap-signer-identity-v1\0";
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct FecLayoutObjectRow {
21    pub object_class: u8,
22    pub present: bool,
23    pub object_id: u64,
24    pub first_block_index: u64,
25    pub data_block_count: u32,
26    pub parity_block_count: u32,
27    pub encrypted_size: u32,
28    pub plain_size: u32,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct DataBlockMerkleLeaf {
33    pub block_index: u64,
34    pub kind: BlockKind,
35    pub flags: u8,
36    pub payload: Vec<u8>,
37}
38
39#[derive(Debug, Clone, Copy)]
40pub struct CriticalMetadataDigestInputs<'a> {
41    pub archive_uuid: [u8; 16],
42    pub session_id: [u8; 16],
43    pub stripe_width: u32,
44    pub total_volumes: u32,
45    pub compression_algo: CompressionAlgo,
46    pub aead_algo: AeadAlgo,
47    pub fec_algo: FecAlgo,
48    pub kdf_algo: KdfAlgo,
49    pub crypto_header_pre_hmac_bytes: &'a [u8],
50    pub chunk_size: u32,
51    pub envelope_target_size: u32,
52    pub block_size: u32,
53    pub fec_data_shards: u16,
54    pub fec_parity_shards: u16,
55    pub index_fec_data_shards: u16,
56    pub index_fec_parity_shards: u16,
57    pub index_root_fec_data_shards: u16,
58    pub index_root_fec_parity_shards: u16,
59    pub volume_loss_tolerance: u8,
60    pub bit_rot_buffer_pct: u8,
61    pub has_dictionary: u8,
62    pub manifest_footer_global_pre_hmac_bytes: &'a [u8],
63    pub index_root_first_block: u64,
64    pub index_root_data_block_count: u32,
65    pub index_root_parity_block_count: u32,
66    pub index_root_encrypted_size: u32,
67    pub index_root_decompressed_size: u32,
68    pub root_auth_descriptor_digest: [u8; 32],
69}
70
71#[derive(Debug, Clone, Copy)]
72pub struct ArchiveRootInputs {
73    pub archive_uuid: [u8; 16],
74    pub session_id: [u8; 16],
75    pub format_version: u16,
76    pub volume_format_rev: u16,
77    pub compression_algo: CompressionAlgo,
78    pub aead_algo: AeadAlgo,
79    pub fec_algo: FecAlgo,
80    pub kdf_algo: KdfAlgo,
81    pub critical_metadata_digest: [u8; 32],
82    pub index_digest: [u8; 32],
83    pub fec_layout_digest: [u8; 32],
84    pub total_data_block_count: u64,
85    pub data_block_merkle_root: [u8; 32],
86    pub root_auth_descriptor_digest: [u8; 32],
87    pub signer_identity_digest: [u8; 32],
88}
89
90pub fn root_auth_descriptor_digest(
91    authenticator_id: u16,
92    signer_identity_type: u16,
93    signer_identity_bytes: &[u8],
94    authenticator_value_length: u32,
95    footer_length: u32,
96) -> Result<[u8; 32], FormatError> {
97    let signer_identity_length = u32::try_from(signer_identity_bytes.len())
98        .map_err(|_| FormatError::InvalidArchive("root-auth signer identity length overflow"))?;
99    let signer_identity_hash = sha256_bytes(signer_identity_bytes);
100    let mut bytes = Vec::new();
101    bytes.extend_from_slice(ROOT_AUTH_DESCRIPTOR_DOMAIN);
102    bytes.extend_from_slice(&ROOT_AUTH_SPEC_ID);
103    push_u16(&mut bytes, authenticator_id);
104    push_u16(&mut bytes, signer_identity_type);
105    push_u32(&mut bytes, signer_identity_length);
106    bytes.extend_from_slice(&signer_identity_hash);
107    push_u32(&mut bytes, authenticator_value_length);
108    push_u32(&mut bytes, footer_length);
109    Ok(sha256_bytes(&bytes))
110}
111
112pub fn signer_identity_digest(
113    signer_identity_type: u16,
114    signer_identity_bytes: &[u8],
115) -> Result<[u8; 32], FormatError> {
116    let signer_identity_length = u32::try_from(signer_identity_bytes.len())
117        .map_err(|_| FormatError::InvalidArchive("root-auth signer identity length overflow"))?;
118    let mut bytes = Vec::new();
119    bytes.extend_from_slice(SIGNER_IDENTITY_DOMAIN);
120    push_u16(&mut bytes, signer_identity_type);
121    push_u32(&mut bytes, signer_identity_length);
122    bytes.extend_from_slice(signer_identity_bytes);
123    Ok(sha256_bytes(&bytes))
124}
125
126pub fn critical_metadata_digest(
127    inputs: CriticalMetadataDigestInputs<'_>,
128) -> Result<[u8; 32], FormatError> {
129    let crypto_header_pre_hmac_digest = len_prefixed_digest(
130        CRYPTO_HEADER_PRE_HMAC_DOMAIN,
131        inputs.crypto_header_pre_hmac_bytes,
132    )?;
133    let manifest_footer_global_pre_hmac_digest = len_prefixed_digest(
134        MANIFEST_FOOTER_GLOBAL_PRE_HMAC_DOMAIN,
135        inputs.manifest_footer_global_pre_hmac_bytes,
136    )?;
137
138    let mut bytes = Vec::new();
139    bytes.extend_from_slice(CRITICAL_METADATA_DOMAIN);
140    bytes.extend_from_slice(&inputs.archive_uuid);
141    bytes.extend_from_slice(&inputs.session_id);
142    push_u16(&mut bytes, FORMAT_VERSION);
143    push_u16(&mut bytes, VOLUME_FORMAT_REV);
144    push_u32(&mut bytes, inputs.stripe_width);
145    push_u32(&mut bytes, inputs.total_volumes);
146    push_u16(&mut bytes, inputs.compression_algo as u16);
147    push_u16(&mut bytes, inputs.aead_algo as u16);
148    push_u16(&mut bytes, inputs.fec_algo as u16);
149    push_u16(&mut bytes, inputs.kdf_algo as u16);
150    bytes.extend_from_slice(&crypto_header_pre_hmac_digest);
151    push_u32(&mut bytes, inputs.chunk_size);
152    push_u32(&mut bytes, inputs.envelope_target_size);
153    push_u32(&mut bytes, inputs.block_size);
154    push_u16(&mut bytes, inputs.fec_data_shards);
155    push_u16(&mut bytes, inputs.fec_parity_shards);
156    push_u16(&mut bytes, inputs.index_fec_data_shards);
157    push_u16(&mut bytes, inputs.index_fec_parity_shards);
158    push_u16(&mut bytes, inputs.index_root_fec_data_shards);
159    push_u16(&mut bytes, inputs.index_root_fec_parity_shards);
160    bytes.push(inputs.volume_loss_tolerance);
161    bytes.push(inputs.bit_rot_buffer_pct);
162    bytes.push(inputs.has_dictionary);
163    bytes.extend_from_slice(&manifest_footer_global_pre_hmac_digest);
164    push_u64(&mut bytes, inputs.index_root_first_block);
165    push_u32(&mut bytes, inputs.index_root_data_block_count);
166    push_u32(&mut bytes, inputs.index_root_parity_block_count);
167    push_u32(&mut bytes, inputs.index_root_encrypted_size);
168    push_u32(&mut bytes, inputs.index_root_decompressed_size);
169    bytes.extend_from_slice(&inputs.root_auth_descriptor_digest);
170    Ok(sha256_bytes(&bytes))
171}
172
173pub fn index_digest(index_root_plaintext: &[u8]) -> [u8; 32] {
174    let mut bytes = Vec::new();
175    bytes.extend_from_slice(INDEX_ROOT_DOMAIN);
176    bytes.extend_from_slice(index_root_plaintext);
177    sha256_bytes(&bytes)
178}
179
180pub fn fec_layout_digest(rows: &[FecLayoutObjectRow]) -> Result<[u8; 32], FormatError> {
181    let row_count = u32::try_from(rows.len())
182        .map_err(|_| FormatError::InvalidArchive("root-auth FEC row count overflow"))?;
183    let mut bytes = Vec::new();
184    bytes.extend_from_slice(FEC_LAYOUT_DOMAIN);
185    push_u32(&mut bytes, row_count);
186    for row in rows {
187        bytes.push(row.object_class);
188        bytes.push(if row.present { 1 } else { 0 });
189        push_u16(&mut bytes, 0);
190        push_u64(&mut bytes, row.object_id);
191        push_u64(&mut bytes, row.first_block_index);
192        push_u32(&mut bytes, row.data_block_count);
193        push_u32(&mut bytes, row.parity_block_count);
194        push_u32(&mut bytes, row.encrypted_size);
195        push_u32(&mut bytes, row.plain_size);
196    }
197    Ok(sha256_bytes(&bytes))
198}
199
200pub fn data_block_merkle_root(leaves: &[DataBlockMerkleLeaf]) -> [u8; 32] {
201    if leaves.is_empty() {
202        return empty_data_block_merkle_root();
203    }
204
205    let leaf_hashes = leaves
206        .iter()
207        .map(|leaf| {
208            data_block_merkle_leaf_hash(leaf.block_index, leaf.kind, leaf.flags, &leaf.payload)
209        })
210        .collect::<Vec<_>>();
211    data_block_merkle_root_from_leaf_hashes(&leaf_hashes)
212}
213
214pub fn data_block_merkle_leaf_hash(
215    block_index: u64,
216    kind: BlockKind,
217    flags: u8,
218    payload: &[u8],
219) -> [u8; 32] {
220    let mut leaf_payload = Vec::with_capacity(10 + payload.len());
221    push_u64(&mut leaf_payload, block_index);
222    leaf_payload.push(kind as u8);
223    leaf_payload.push(flags);
224    leaf_payload.extend_from_slice(payload);
225
226    let mut bytes = Vec::new();
227    bytes.push(0x00);
228    bytes.extend_from_slice(DATA_BLOCK_MERKLE_DOMAIN);
229    bytes.extend_from_slice(&leaf_payload);
230    sha256_bytes(&bytes)
231}
232
233pub fn data_block_merkle_root_from_leaf_hashes(leaf_hashes: &[[u8; 32]]) -> [u8; 32] {
234    if leaf_hashes.is_empty() {
235        return empty_data_block_merkle_root();
236    }
237
238    let mut level = leaf_hashes.to_vec();
239
240    while level.len() > 1 {
241        let mut next = Vec::with_capacity(level.len().div_ceil(2));
242        let mut idx = 0usize;
243        while idx < level.len() {
244            if idx + 1 == level.len() {
245                next.push(level[idx]);
246            } else {
247                let mut bytes = Vec::new();
248                bytes.push(0x01);
249                bytes.extend_from_slice(DATA_BLOCK_MERKLE_DOMAIN);
250                bytes.extend_from_slice(&level[idx]);
251                bytes.extend_from_slice(&level[idx + 1]);
252                next.push(sha256_bytes(&bytes));
253            }
254            idx += 2;
255        }
256        level = next;
257    }
258    level[0]
259}
260
261fn empty_data_block_merkle_root() -> [u8; 32] {
262    let mut bytes = Vec::new();
263    bytes.extend_from_slice(EMPTY_MERKLE_DOMAIN);
264    bytes.extend_from_slice(DATA_BLOCK_MERKLE_DOMAIN);
265    sha256_bytes(&bytes)
266}
267
268pub fn archive_root(inputs: ArchiveRootInputs) -> [u8; 32] {
269    let mut bytes = Vec::new();
270    bytes.extend_from_slice(ARCHIVE_ROOT_DOMAIN);
271    bytes.extend_from_slice(&ROOT_AUTH_SPEC_ID);
272    bytes.extend_from_slice(&inputs.archive_uuid);
273    bytes.extend_from_slice(&inputs.session_id);
274    push_u16(&mut bytes, inputs.format_version);
275    push_u16(&mut bytes, inputs.volume_format_rev);
276    push_u16(&mut bytes, inputs.compression_algo as u16);
277    push_u16(&mut bytes, inputs.aead_algo as u16);
278    push_u16(&mut bytes, inputs.fec_algo as u16);
279    push_u16(&mut bytes, inputs.kdf_algo as u16);
280    bytes.extend_from_slice(&inputs.critical_metadata_digest);
281    bytes.extend_from_slice(&inputs.index_digest);
282    bytes.extend_from_slice(&inputs.fec_layout_digest);
283    push_u64(&mut bytes, inputs.total_data_block_count);
284    bytes.extend_from_slice(&inputs.data_block_merkle_root);
285    bytes.extend_from_slice(&inputs.root_auth_descriptor_digest);
286    bytes.extend_from_slice(&inputs.signer_identity_digest);
287    sha256_bytes(&bytes)
288}
289
290fn len_prefixed_digest(domain: &[u8], payload: &[u8]) -> Result<[u8; 32], FormatError> {
291    let length = u32::try_from(payload.len())
292        .map_err(|_| FormatError::InvalidArchive("root-auth digest input length overflow"))?;
293    let mut bytes = Vec::new();
294    bytes.extend_from_slice(domain);
295    push_u32(&mut bytes, length);
296    bytes.extend_from_slice(payload);
297    Ok(sha256_bytes(&bytes))
298}
299
300fn sha256_bytes(bytes: &[u8]) -> [u8; 32] {
301    let digest = Sha256::digest(bytes);
302    let mut out = [0u8; 32];
303    out.copy_from_slice(&digest);
304    out
305}
306
307fn push_u16(bytes: &mut Vec<u8>, value: u16) {
308    bytes.extend_from_slice(&value.to_le_bytes());
309}
310
311fn push_u32(bytes: &mut Vec<u8>, value: u32) {
312    bytes.extend_from_slice(&value.to_le_bytes());
313}
314
315fn push_u64(bytes: &mut Vec<u8>, value: u64) {
316    bytes.extend_from_slice(&value.to_le_bytes());
317}