1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use crate::prelude::*;
use blake3::{Hasher, OutputReader};
use leb128::write::unsigned as write_varint;
use std::convert::TryInto as _;
use std::num::NonZeroUsize;

#[derive(Clone)]
pub struct Blake3SeqNo {
    hasher: Hasher,
    // This has to be NonZero in order to be injective, since the payload marker writes 0
    // See also 91e48829-7bea-4426-971a-f092856269a5
    child: NonZeroUsize,
}

impl SequenceNumber for Blake3SeqNo {
    fn root() -> Self {
        profile_method!(root);

        Self {
            hasher: Hasher::new(),
            child: NonZeroUsize::new(1).unwrap(),
        }
    }
    fn next_child(&mut self) -> Self {
        profile_method!(next_child);

        let child = self.child;
        let mut hasher = self.hasher.clone();
        // Better to panic than overflow.
        self.child = NonZeroUsize::new(child.get() + 1).unwrap();
        // Include the child node
        write_varint(&mut hasher, child.get().try_into().unwrap()).unwrap();
        Self {
            hasher,
            child: NonZeroUsize::new(1).unwrap(),
        }
    }
    #[inline]
    fn skip(&mut self, count: usize) {
        profile_method!(skip);

        self.child = NonZeroUsize::new(self.child.get() + count).unwrap();
    }
}

impl Blake3SeqNo {
    pub(crate) fn finish(self, payload: &[u8]) -> OutputReader {
        profile_method!(finish);

        let Self { mut hasher, .. } = self;

        // To debug all the payloads in a hash to find a diff, this can be useful.
        /*
        #[derive(Debug)]
        struct Update {
            payload: String,
            seq_no: String,
        }
        let update = Update {
            seq_no: hex::encode(hasher.finalize().as_bytes()),
            payload: hex::encode(payload),
        };
        dbg!(update);
        */

        // See also 91e48829-7bea-4426-971a-f092856269a5
        hasher.update(&[0]);
        hasher.update(payload);
        hasher.finalize_xof()
    }
}