devela/data/codec/hash/
pengy.rs
1use crate::{ConstDefault, Hasher};
7
8#[doc = crate::doc_!(vendor: "pengyhash")]
11pub struct HasherPengy {
12 state: [u64; 4],
13 seed: u64,
14}
15
16impl ConstDefault for HasherPengy {
17 const DEFAULT: Self = Self { state: [0; 4], seed: 0 };
18}
19impl Default for HasherPengy {
20 fn default() -> Self {
21 Self::DEFAULT
22 }
23}
24
25impl HasherPengy {
26 pub const fn new() -> Self {
28 Self::DEFAULT
29 }
30
31 pub const fn with_seed(seed: u64) -> Self {
33 Self { state: [0; 4], seed }
34 }
35
36 pub const fn is_empty(&self) -> bool {
38 let [a, b, c, d] = self.state;
39 a + b + c + d == 0
40 }
41
42 pub const fn reset(&mut self) {
44 self.state = [0; 4];
45 }
46
47 pub const fn clear(&mut self) {
49 self.state = [0; 4];
50 self.seed = 0;
51 }
52
53 pub const fn process(&mut self, data: &[u8]) {
55 let mut b: [u64; 4] = [0; 4];
56 let mut s: [u64; 4] = [0, 0, 0, data.len() as u64];
57 let mut remaining = data;
58
59 while remaining.len() >= 32 {
61 let mut i = 0;
62 while i < 4 {
63 let (_, rest) = remaining.split_at(i * 8);
64 let (chunk, _) = rest.split_at(8);
65 b[i] = u64::from_le_bytes(Self::make_byte_array(chunk));
66
67 i += 1;
68 }
69 let (_left, right) = remaining.split_at(32);
70 remaining = right;
71
72 s[0] = s[0].wrapping_add(s[1]).wrapping_add(b[3]);
73 s[1] = s[0].wrapping_add(s[1].wrapping_shl(14) | s[1].wrapping_shr(50));
74 s[2] = s[2].wrapping_add(s[3]).wrapping_add(b[2]);
75 s[3] = s[2].wrapping_add(s[3].wrapping_shl(23) | s[3].wrapping_shr(41));
76 s[0] = s[0].wrapping_add(s[3]).wrapping_add(b[1]);
77 s[3] = s[0] ^ (s[3].wrapping_shl(16) | s[3].wrapping_shr(48));
78 s[2] = s[2].wrapping_add(s[1]).wrapping_add(b[0]);
79 s[1] = s[2] ^ (s[1].wrapping_shl(40) | s[1].wrapping_shr(24));
80 }
81
82 let mut tmp = [0u8; 32];
83 let mut i = 0;
84 while i < remaining.len() {
85 if i < tmp.len() {
86 tmp[i] = remaining[i];
87 }
88 i += 1;
89 }
90
91 let mut i = 0;
92 while i < 4 {
93 let (_, rest) = tmp.split_at(i * 8);
94 let (chunk, _) = rest.split_at(8);
95 b[i] = u64::from_le_bytes(Self::make_byte_array(chunk));
96 i += 1;
97 }
98
99 let mut _i = 0;
101 while _i < 6 {
102 s[0] = s[0].wrapping_add(s[1]).wrapping_add(b[3]);
103 s[1] = s[0]
104 .wrapping_add(s[1].wrapping_shl(14) | s[1].wrapping_shr(50))
105 .wrapping_add(self.seed);
106 s[2] = s[2].wrapping_add(s[3]).wrapping_add(b[2]);
107 s[3] = s[2].wrapping_add(s[3].wrapping_shl(23) | s[3].wrapping_shr(41));
108 s[0] = s[0].wrapping_add(s[3]).wrapping_add(b[1]);
109 s[3] = s[0] ^ (s[3].wrapping_shl(16) | s[3].wrapping_shr(48));
110 s[2] = s[2].wrapping_add(s[1]).wrapping_add(b[0]);
111 s[1] = s[2] ^ (s[1].wrapping_shl(40) | s[1].wrapping_shr(24));
112 _i += 1;
113 }
114
115 self.state[0] = s[0];
116 self.state[1] = s[1];
117 self.state[2] = s[2];
118 self.state[3] = s[3];
119 }
120
121 const fn make_byte_array(chunk: &[u8]) -> [u8; 8] {
122 let mut byte_array = [0; 8];
123 let mut j = 0;
124 while j < chunk.len() {
125 byte_array[j] = chunk[j];
126 j += 1;
127 }
128 byte_array
129 }
130
131 pub const fn digest(&self) -> u64 {
133 self.state[0]
134 .wrapping_add(self.state[1])
135 .wrapping_add(self.state[2])
136 .wrapping_add(self.state[3])
137 }
138}
139
140impl Hasher for HasherPengy {
141 fn write(&mut self, data: &[u8]) {
142 self.process(data);
143 }
144 fn finish(&self) -> u64 {
145 self.digest()
146 }
147}