1use std::fmt;
26
27use crate::object::ContentHash;
28
29pub const MANIFEST_NODE_MAGIC: [u8; 4] = *b"WPMF";
31pub const MANIFEST_FORMAT_VERSION: u8 = 1;
33pub const MANIFEST_ROUTE_DOMAIN: &[u8] = b"weft-plan-manifest-key-v1";
36pub const MANIFEST_ROUTE_BITS: u8 = 5;
38pub const MANIFEST_BRANCH_WIDTH: usize = 32;
40pub const MANIFEST_ROUTE_LEVELS: u8 = 52;
44pub const MANIFEST_LEAF_MAX_ENTRIES: usize = 16;
47
48const TAG_LEAF: u8 = 0;
49const TAG_BRANCH: u8 = 1;
50
51const LEAF_HEADER_LEN: usize = 4 + 1 + 1 + 2;
52const LEAF_ENTRY_LEN: usize = 1 + 32 + 8;
53const BRANCH_HEADER_LEN: usize = 4 + 1 + 1 + 1 + 4;
54const BRANCH_CHILD_LEN: usize = 32 + 8 + 8;
55
56#[repr(u8)]
64#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
65pub enum ManifestObjectKind {
66 Blob = 0,
67 Tree = 1,
68}
69
70impl ManifestObjectKind {
71 pub fn to_byte(self) -> u8 {
72 self as u8
73 }
74
75 pub fn from_byte(byte: u8) -> Option<Self> {
76 match byte {
77 0 => Some(Self::Blob),
78 1 => Some(Self::Tree),
79 _ => None,
80 }
81 }
82}
83
84impl fmt::Display for ManifestObjectKind {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 f.write_str(match self {
87 Self::Blob => "blob",
88 Self::Tree => "tree",
89 })
90 }
91}
92
93#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
98pub struct ManifestKey {
99 pub kind: ManifestObjectKind,
100 pub hash: ContentHash,
101}
102
103impl ManifestKey {
104 pub fn new(kind: ManifestObjectKind, hash: ContentHash) -> Self {
105 Self { kind, hash }
106 }
107
108 pub fn route(&self) -> ManifestRoute {
110 let mut hasher = blake3::Hasher::new();
111 hasher.update(MANIFEST_ROUTE_DOMAIN);
112 hasher.update(&[self.kind.to_byte()]);
113 hasher.update(self.hash.as_bytes());
114 ManifestRoute(hasher.finalize().into())
115 }
116}
117
118#[derive(Clone, Copy, PartialEq, Eq)]
121pub struct ManifestRoute([u8; 32]);
122
123impl ManifestRoute {
124 pub fn as_bytes(&self) -> &[u8; 32] {
125 &self.0
126 }
127
128 pub fn group(&self, level: u8) -> u8 {
135 let start = usize::from(level) * usize::from(MANIFEST_ROUTE_BITS);
136 let mut value = 0u8;
137 for offset in 0..usize::from(MANIFEST_ROUTE_BITS) {
138 let bit_index = start + offset;
139 let bit = if bit_index >= 256 {
140 0
141 } else {
142 (self.0[bit_index / 8] >> (7 - (bit_index % 8))) & 1
143 };
144 value = (value << 1) | bit;
145 }
146 value
147 }
148}
149
150impl fmt::Debug for ManifestRoute {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 write!(f, "ManifestRoute({})", hex::encode(&self.0[..8]))
153 }
154}
155
156#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
165pub struct ManifestObject {
166 pub kind: ManifestObjectKind,
167 pub hash: ContentHash,
168 pub decoded_size: u64,
169}
170
171impl ManifestObject {
172 pub fn new(kind: ManifestObjectKind, hash: ContentHash, decoded_size: u64) -> Self {
173 Self {
174 kind,
175 hash,
176 decoded_size,
177 }
178 }
179
180 pub fn key(&self) -> ManifestKey {
181 ManifestKey::new(self.kind, self.hash)
182 }
183}
184
185#[derive(Clone, Copy, Debug, PartialEq, Eq)]
190pub struct ManifestChild {
191 pub slot: u8,
194 pub hash: ContentHash,
195 pub object_count: u64,
196 pub decoded_bytes: u64,
197}
198
199#[derive(Clone, Debug, PartialEq, Eq)]
202pub enum ManifestNode {
203 Leaf(ManifestLeaf),
204 Branch(ManifestBranch),
205}
206
207#[derive(Clone, Debug, PartialEq, Eq)]
208pub struct ManifestLeaf {
209 entries: Vec<ManifestObject>,
210}
211
212#[derive(Clone, Debug, PartialEq, Eq)]
213pub struct ManifestBranch {
214 depth: u8,
215 children: Vec<ManifestChild>,
216}
217
218impl ManifestLeaf {
219 pub fn new(mut entries: Vec<ManifestObject>) -> Result<Self, ManifestNodeError> {
225 entries.sort_by_key(ManifestObject::key);
226 if let Some(window) = entries.windows(2).find(|w| w[0].key() == w[1].key()) {
227 return Err(ManifestNodeError::DuplicateObjectKey(window[0].key()));
228 }
229 if u16::try_from(entries.len()).is_err() {
230 return Err(ManifestNodeError::LeafCountOverflow(entries.len()));
231 }
232 Ok(Self { entries })
233 }
234
235 pub fn entries(&self) -> &[ManifestObject] {
236 &self.entries
237 }
238
239 pub fn object_count(&self) -> u64 {
240 self.entries.len() as u64
241 }
242
243 pub fn decoded_bytes(&self) -> Option<u64> {
245 self.entries
246 .iter()
247 .try_fold(0u64, |acc, entry| acc.checked_add(entry.decoded_size))
248 }
249}
250
251impl ManifestBranch {
252 pub fn new(depth: u8, mut children: Vec<ManifestChild>) -> Result<Self, ManifestNodeError> {
254 children.sort_by_key(|child| child.slot);
255 if children.is_empty() {
256 return Err(ManifestNodeError::EmptyBranchBitmap);
257 }
258 if let Some(child) = children
259 .iter()
260 .find(|child| usize::from(child.slot) >= MANIFEST_BRANCH_WIDTH)
261 {
262 return Err(ManifestNodeError::SlotOutOfRange(child.slot));
263 }
264 if let Some(window) = children.windows(2).find(|w| w[0].slot == w[1].slot) {
265 return Err(ManifestNodeError::DuplicateBranchSlot(window[0].slot));
266 }
267 Ok(Self { depth, children })
268 }
269
270 pub fn depth(&self) -> u8 {
271 self.depth
272 }
273
274 pub fn children(&self) -> &[ManifestChild] {
275 &self.children
276 }
277
278 pub fn bitmap(&self) -> u32 {
279 self.children
280 .iter()
281 .fold(0u32, |acc, child| acc | (1u32 << child.slot))
282 }
283
284 pub fn child_at(&self, slot: u8) -> Option<&ManifestChild> {
285 self.children.iter().find(|child| child.slot == slot)
286 }
287}
288
289impl ManifestNode {
290 pub fn empty() -> Self {
292 Self::Leaf(ManifestLeaf {
293 entries: Vec::new(),
294 })
295 }
296
297 pub fn encode(&self) -> Vec<u8> {
299 match self {
300 Self::Leaf(leaf) => {
301 let mut out =
302 Vec::with_capacity(LEAF_HEADER_LEN + leaf.entries.len() * LEAF_ENTRY_LEN);
303 out.extend_from_slice(&MANIFEST_NODE_MAGIC);
304 out.push(MANIFEST_FORMAT_VERSION);
305 out.push(TAG_LEAF);
306 out.extend_from_slice(&(leaf.entries.len() as u16).to_be_bytes());
307 for entry in &leaf.entries {
308 out.push(entry.kind.to_byte());
309 out.extend_from_slice(entry.hash.as_bytes());
310 out.extend_from_slice(&entry.decoded_size.to_be_bytes());
311 }
312 out
313 }
314 Self::Branch(branch) => {
315 let mut out = Vec::with_capacity(
316 BRANCH_HEADER_LEN + branch.children.len() * BRANCH_CHILD_LEN,
317 );
318 out.extend_from_slice(&MANIFEST_NODE_MAGIC);
319 out.push(MANIFEST_FORMAT_VERSION);
320 out.push(TAG_BRANCH);
321 out.push(branch.depth);
322 out.extend_from_slice(&branch.bitmap().to_be_bytes());
323 for child in &branch.children {
324 out.extend_from_slice(child.hash.as_bytes());
325 out.extend_from_slice(&child.object_count.to_be_bytes());
326 out.extend_from_slice(&child.decoded_bytes.to_be_bytes());
327 }
328 out
329 }
330 }
331 }
332
333 pub fn address(&self) -> ContentHash {
335 ContentHash::compute(&self.encode())
336 }
337
338 pub fn decode(bytes: &[u8]) -> Result<Self, ManifestDecodeError> {
346 let node = Self::decode_inner(bytes)?;
347 if node.encode() != bytes {
348 return Err(ManifestDecodeError::NonCanonicalEncoding);
349 }
350 Ok(node)
351 }
352
353 pub fn decode_addressed(
355 bytes: &[u8],
356 expected: &ContentHash,
357 ) -> Result<Self, ManifestDecodeError> {
358 let node = Self::decode(bytes)?;
359 let actual = ContentHash::compute(bytes);
360 if actual != *expected {
361 return Err(ManifestDecodeError::AddressMismatch {
362 expected: *expected,
363 actual,
364 });
365 }
366 Ok(node)
367 }
368
369 fn decode_inner(bytes: &[u8]) -> Result<Self, ManifestDecodeError> {
370 let mut reader = Reader::new(bytes);
371 if reader.take(4)? != MANIFEST_NODE_MAGIC {
372 return Err(ManifestDecodeError::BadMagic);
373 }
374 let version = reader.u8()?;
375 if version != MANIFEST_FORMAT_VERSION {
376 return Err(ManifestDecodeError::UnsupportedVersion(version));
377 }
378 let tag = reader.u8()?;
379 let node = match tag {
380 TAG_LEAF => {
381 let count = usize::from(reader.u16()?);
382 let mut entries = Vec::with_capacity(count.min(1024));
383 let mut previous: Option<ManifestKey> = None;
384 for _ in 0..count {
385 let kind_byte = reader.u8()?;
386 let kind = ManifestObjectKind::from_byte(kind_byte)
387 .ok_or(ManifestDecodeError::UnknownObjectKind(kind_byte))?;
388 let hash = ContentHash::from_bytes(reader.hash()?);
389 let decoded_size = reader.u64()?;
390 let key = ManifestKey::new(kind, hash);
391 match previous {
392 Some(prev) if prev == key => {
393 return Err(ManifestDecodeError::DuplicateObjectKey(key));
394 }
395 Some(prev) if prev > key => {
396 return Err(ManifestDecodeError::EntriesOutOfOrder);
397 }
398 _ => {}
399 }
400 previous = Some(key);
401 entries.push(ManifestObject::new(kind, hash, decoded_size));
402 }
403 Self::Leaf(ManifestLeaf { entries })
404 }
405 TAG_BRANCH => {
406 let depth = reader.u8()?;
407 let bitmap = reader.u32()?;
408 if bitmap == 0 {
409 return Err(ManifestDecodeError::EmptyBranchBitmap);
410 }
411 let mut children = Vec::with_capacity(bitmap.count_ones() as usize);
412 for slot in 0..MANIFEST_BRANCH_WIDTH as u8 {
413 if bitmap & (1u32 << slot) == 0 {
414 continue;
415 }
416 let hash = ContentHash::from_bytes(reader.hash()?);
417 let object_count = reader.u64()?;
418 let decoded_bytes = reader.u64()?;
419 children.push(ManifestChild {
420 slot,
421 hash,
422 object_count,
423 decoded_bytes,
424 });
425 }
426 Self::Branch(ManifestBranch { depth, children })
427 }
428 other => return Err(ManifestDecodeError::UnknownNodeTag(other)),
429 };
430 if !reader.is_exhausted() {
431 return Err(ManifestDecodeError::TrailingBytes);
432 }
433 Ok(node)
434 }
435
436 pub fn leaf_entries(&self) -> &[ManifestObject] {
438 match self {
439 Self::Leaf(leaf) => leaf.entries(),
440 Self::Branch(_) => &[],
441 }
442 }
443}
444
445struct Reader<'a> {
448 bytes: &'a [u8],
449 pos: usize,
450}
451
452impl<'a> Reader<'a> {
453 fn new(bytes: &'a [u8]) -> Self {
454 Self { bytes, pos: 0 }
455 }
456
457 fn take(&mut self, len: usize) -> Result<&'a [u8], ManifestDecodeError> {
458 let end = self
459 .pos
460 .checked_add(len)
461 .ok_or(ManifestDecodeError::Truncated)?;
462 let slice = self
463 .bytes
464 .get(self.pos..end)
465 .ok_or(ManifestDecodeError::Truncated)?;
466 self.pos = end;
467 Ok(slice)
468 }
469
470 fn u8(&mut self) -> Result<u8, ManifestDecodeError> {
471 Ok(self.take(1)?[0])
472 }
473
474 fn u16(&mut self) -> Result<u16, ManifestDecodeError> {
475 let bytes = self.take(2)?;
476 Ok(u16::from_be_bytes([bytes[0], bytes[1]]))
477 }
478
479 fn u32(&mut self) -> Result<u32, ManifestDecodeError> {
480 let bytes = self.take(4)?;
481 Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
482 }
483
484 fn u64(&mut self) -> Result<u64, ManifestDecodeError> {
485 let bytes = self.take(8)?;
486 let mut arr = [0u8; 8];
487 arr.copy_from_slice(bytes);
488 Ok(u64::from_be_bytes(arr))
489 }
490
491 fn hash(&mut self) -> Result<[u8; 32], ManifestDecodeError> {
492 let bytes = self.take(32)?;
493 let mut arr = [0u8; 32];
494 arr.copy_from_slice(bytes);
495 Ok(arr)
496 }
497
498 fn is_exhausted(&self) -> bool {
499 self.pos == self.bytes.len()
500 }
501}
502
503#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
507pub enum ManifestNodeError {
508 #[error("duplicate manifest object key {0:?}")]
509 DuplicateObjectKey(ManifestKey),
510 #[error("leaf holds {0} entries; the canonical count field is a u16")]
511 LeafCountOverflow(usize),
512 #[error("branch bitmap is empty; the canonical empty set is the empty leaf")]
513 EmptyBranchBitmap,
514 #[error("branch slot {0} is outside 0..32")]
515 SlotOutOfRange(u8),
516 #[error("duplicate branch slot {0}")]
517 DuplicateBranchSlot(u8),
518}
519
520#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
524pub enum ManifestDecodeError {
525 #[error("node does not start with the WPMF magic")]
526 BadMagic,
527 #[error("unsupported manifest format version {0}")]
528 UnsupportedVersion(u8),
529 #[error("unknown manifest node tag {0}")]
530 UnknownNodeTag(u8),
531 #[error("unknown manifest object kind {0}")]
532 UnknownObjectKind(u8),
533 #[error("node bytes are truncated")]
534 Truncated,
535 #[error("node has trailing bytes after its declared content")]
536 TrailingBytes,
537 #[error("leaf entries are not strictly ascending by (kind, hash)")]
538 EntriesOutOfOrder,
539 #[error("leaf names object key {0:?} more than once")]
540 DuplicateObjectKey(ManifestKey),
541 #[error("branch bitmap is empty; the canonical empty set is the empty leaf")]
542 EmptyBranchBitmap,
543 #[error("node bytes are a non-canonical spelling of their own content")]
544 NonCanonicalEncoding,
545 #[error("node bytes hash to {actual} but were addressed as {expected}")]
546 AddressMismatch {
547 expected: ContentHash,
548 actual: ContentHash,
549 },
550}
551
552#[cfg(test)]
553mod tests {
554 use super::*;
555
556 fn hash(seed: u8) -> ContentHash {
557 ContentHash::from_bytes([seed; 32])
558 }
559
560 fn object(seed: u8, size: u64) -> ManifestObject {
561 ManifestObject::new(ManifestObjectKind::Blob, hash(seed), size)
562 }
563
564 #[test]
565 fn empty_leaf_is_the_canonical_empty_root() {
566 let encoded = ManifestNode::empty().encode();
567 assert_eq!(encoded, b"WPMF\x01\x00\x00\x00");
568 assert_eq!(
569 ManifestNode::decode(&encoded).unwrap(),
570 ManifestNode::empty()
571 );
572 }
573
574 #[test]
575 fn leaf_layout_is_byte_exact() {
576 let leaf = ManifestNode::Leaf(ManifestLeaf::new(vec![object(1, 0x0102)]).unwrap());
577 let encoded = leaf.encode();
578 assert_eq!(&encoded[..4], b"WPMF");
579 assert_eq!(encoded[4], MANIFEST_FORMAT_VERSION);
580 assert_eq!(encoded[5], TAG_LEAF);
581 assert_eq!(&encoded[6..8], &1u16.to_be_bytes());
582 assert_eq!(encoded[8], 0); assert_eq!(&encoded[9..41], &[1u8; 32]);
584 assert_eq!(&encoded[41..49], &0x0102u64.to_be_bytes());
585 assert_eq!(encoded.len(), LEAF_HEADER_LEN + LEAF_ENTRY_LEN);
586 }
587
588 #[test]
589 fn branch_layout_is_byte_exact() {
590 let branch = ManifestNode::Branch(
591 ManifestBranch::new(
592 3,
593 vec![
594 ManifestChild {
595 slot: 5,
596 hash: hash(9),
597 object_count: 17,
598 decoded_bytes: 40,
599 },
600 ManifestChild {
601 slot: 1,
602 hash: hash(8),
603 object_count: 2,
604 decoded_bytes: 6,
605 },
606 ],
607 )
608 .unwrap(),
609 );
610 let encoded = branch.encode();
611 assert_eq!(encoded[5], TAG_BRANCH);
612 assert_eq!(encoded[6], 3);
613 assert_eq!(&encoded[7..11], &0b100010u32.to_be_bytes());
614 assert_eq!(&encoded[11..43], &[8u8; 32]);
617 assert_eq!(encoded.len(), BRANCH_HEADER_LEN + 2 * BRANCH_CHILD_LEN);
618 assert_eq!(ManifestNode::decode(&encoded).unwrap(), branch);
619 }
620
621 #[test]
622 fn decode_rejects_each_corruption_class() {
623 let good = ManifestNode::Leaf(ManifestLeaf::new(vec![object(1, 1), object(2, 2)]).unwrap())
624 .encode();
625
626 let mut bad_magic = good.clone();
627 bad_magic[0] = b'X';
628 assert_eq!(
629 ManifestNode::decode(&bad_magic).unwrap_err(),
630 ManifestDecodeError::BadMagic
631 );
632
633 let mut bad_version = good.clone();
634 bad_version[4] = 2;
635 assert_eq!(
636 ManifestNode::decode(&bad_version).unwrap_err(),
637 ManifestDecodeError::UnsupportedVersion(2)
638 );
639
640 let mut bad_tag = good.clone();
641 bad_tag[5] = 7;
642 assert_eq!(
643 ManifestNode::decode(&bad_tag).unwrap_err(),
644 ManifestDecodeError::UnknownNodeTag(7)
645 );
646
647 let mut bad_kind = good.clone();
648 bad_kind[8] = 9;
649 assert_eq!(
650 ManifestNode::decode(&bad_kind).unwrap_err(),
651 ManifestDecodeError::UnknownObjectKind(9)
652 );
653
654 let mut trailing = good.clone();
655 trailing.push(0);
656 assert_eq!(
657 ManifestNode::decode(&trailing).unwrap_err(),
658 ManifestDecodeError::TrailingBytes
659 );
660
661 let truncated = &good[..good.len() - 1];
662 assert_eq!(
663 ManifestNode::decode(truncated).unwrap_err(),
664 ManifestDecodeError::Truncated
665 );
666
667 let mut swapped = good.clone();
669 let (a, b) = (8, 8 + LEAF_ENTRY_LEN);
670 let entry_a = good[a..a + LEAF_ENTRY_LEN].to_vec();
671 let entry_b = good[b..b + LEAF_ENTRY_LEN].to_vec();
672 swapped[a..a + LEAF_ENTRY_LEN].copy_from_slice(&entry_b);
673 swapped[b..b + LEAF_ENTRY_LEN].copy_from_slice(&entry_a);
674 assert_eq!(
675 ManifestNode::decode(&swapped).unwrap_err(),
676 ManifestDecodeError::EntriesOutOfOrder
677 );
678
679 let mut duplicated = good.clone();
681 duplicated[b..b + LEAF_ENTRY_LEN].copy_from_slice(&entry_a);
682 assert_eq!(
683 ManifestNode::decode(&duplicated).unwrap_err(),
684 ManifestDecodeError::DuplicateObjectKey(ManifestKey::new(
685 ManifestObjectKind::Blob,
686 hash(1)
687 ))
688 );
689 }
690
691 #[test]
692 fn decode_rejects_empty_branch_bitmap() {
693 let mut bytes = Vec::new();
694 bytes.extend_from_slice(&MANIFEST_NODE_MAGIC);
695 bytes.push(MANIFEST_FORMAT_VERSION);
696 bytes.push(TAG_BRANCH);
697 bytes.push(0);
698 bytes.extend_from_slice(&0u32.to_be_bytes());
699 assert_eq!(
700 ManifestNode::decode(&bytes).unwrap_err(),
701 ManifestDecodeError::EmptyBranchBitmap
702 );
703 }
704
705 #[test]
706 fn decode_addressed_rejects_a_wrong_address() {
707 let node = ManifestNode::Leaf(ManifestLeaf::new(vec![object(1, 1)]).unwrap());
708 let bytes = node.encode();
709 let err = ManifestNode::decode_addressed(&bytes, &hash(0xff)).unwrap_err();
710 assert!(matches!(err, ManifestDecodeError::AddressMismatch { .. }));
711 assert!(ManifestNode::decode_addressed(&bytes, &node.address()).is_ok());
712 }
713
714 #[test]
715 fn route_groups_read_five_bits_msb_first() {
716 let route = ManifestRoute([0b1010_1010; 32]);
717 assert_eq!(route.group(0), 0b10101);
718 assert_eq!(route.group(1), 0b01010);
719 assert_eq!(route.group(MANIFEST_ROUTE_LEVELS - 1), 0b00000);
722 assert_eq!(
725 ManifestRoute([0b1010_1011; 32]).group(MANIFEST_ROUTE_LEVELS - 1),
726 0b10000
727 );
728 assert_eq!(route.group(MANIFEST_ROUTE_LEVELS), 0);
730 }
731
732 #[test]
733 fn route_is_domain_separated_from_the_raw_hash() {
734 let key = ManifestKey::new(ManifestObjectKind::Blob, hash(3));
735 assert_ne!(key.route().as_bytes(), hash(3).as_bytes());
736 let other = ManifestKey::new(ManifestObjectKind::Tree, hash(3));
738 assert_ne!(key.route().as_bytes(), other.route().as_bytes());
739 }
740
741 #[test]
742 fn constructing_a_leaf_rejects_duplicate_keys() {
743 let err = ManifestLeaf::new(vec![object(1, 1), object(1, 1)]).unwrap_err();
744 assert!(matches!(err, ManifestNodeError::DuplicateObjectKey(_)));
745 }
746}