sva_formula/
content_hash.rs1use crate::hash::Hash;
4
5#[derive(Clone, Copy, PartialEq, Eq, Debug)]
6pub enum HashDomain {
7 WrittenClosedForm,
8 ClosedFormInFrequency,
9 ReadTime,
10 NodeIdentity,
11 CacheAddress,
12 GainBoundKey,
13 ProfileName,
14}
15
16impl HashDomain {
17 fn key(self) -> (u64, u64) {
18 (DOMAIN_KEY, self as u64)
19 }
20}
21
22const DOMAIN_KEY: u64 = 0x7264_6461_2061_7673;
23
24#[derive(Clone)]
27pub struct ContentHasher {
28 v: [u64; 4],
29 words: u64,
30}
31
32impl ContentHasher {
33 pub fn new(domain: HashDomain) -> ContentHasher {
34 let (k0, k1) = domain.key();
35 ContentHasher {
36 v: [
37 k0 ^ 0x736f_6d65_7073_6575,
38 k1 ^ 0x646f_7261_6e64_6f6d ^ 0xee,
39 k0 ^ 0x6c79_6765_6e65_7261,
40 k1 ^ 0x7465_6462_7974_6573,
41 ],
42 words: 0,
43 }
44 }
45
46 pub fn word(&mut self, word: u64) {
47 self.compress(word);
48 self.words += 1;
49 }
50
51 pub fn hash(&mut self, held: Hash) {
52 self.word(held.0);
53 self.word(held.1);
54 }
55
56 pub fn text(&mut self, text: &str) {
57 self.word(text.len() as u64);
58 for chunk in text.as_bytes().chunks(8) {
59 let mut bytes = [0; 8];
60 bytes[..chunk.len()].copy_from_slice(chunk);
61 self.word(u64::from_le_bytes(bytes));
62 }
63 }
64
65 pub fn finish(mut self) -> Hash {
66 let length = (self.words.wrapping_mul(8) & 0xff) << 56;
67 self.compress(length);
68 self.v[2] ^= 0xee;
69 self.rounds(3);
70 let low = self.v.iter().fold(0, |held, v| held ^ v);
71 self.v[1] ^= 0xdd;
72 self.rounds(3);
73 let high = self.v.iter().fold(0, |held, v| held ^ v);
74 Hash(low, high)
75 }
76
77 fn compress(&mut self, m: u64) {
78 self.v[3] ^= m;
79 self.rounds(1);
80 self.v[0] ^= m;
81 }
82
83 fn rounds(&mut self, n: usize) {
84 let [v0, v1, v2, v3] = &mut self.v;
85 for _ in 0..n {
86 *v0 = v0.wrapping_add(*v1);
87 *v1 = v1.rotate_left(13) ^ *v0;
88 *v0 = v0.rotate_left(32);
89 *v2 = v2.wrapping_add(*v3);
90 *v3 = v3.rotate_left(16) ^ *v2;
91 *v0 = v0.wrapping_add(*v3);
92 *v3 = v3.rotate_left(21) ^ *v0;
93 *v2 = v2.wrapping_add(*v1);
94 *v1 = v1.rotate_left(17) ^ *v2;
95 *v2 = v2.rotate_left(32);
96 }
97 }
98}