crypto/ascon/
ascon_hash256.rs1use super::*;
2use crate::{Bytes, Hash, Hasher};
3
4const IV: u64 = 0x0000_0801_00cc_0002;
6
7#[derive(Clone)]
32#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
33pub struct AsconHash256 {
34 state: State,
35 buf: [u8; 8],
36 buf_len: usize,
37}
38
39impl AsconHash256 {
40 #[inline]
41 pub fn new() -> Self {
42 let mut state = State::init_hash(IV);
43 p12(&mut state);
44 AsconHash256 {
45 state,
46 buf: [0u8; 8],
47 buf_len: 0,
48 }
49 }
50
51 fn process_buffer(&mut self) {
52 debug_assert_eq!(self.buf_len, 8);
53 self.state.absorb_block(&self.buf);
54 p12(&mut self.state);
55 self.buf_len = 0;
56 }
57
58 fn pad_and_finalize(&mut self) {
59 let mut padded = [0u8; 8];
60 padded[..self.buf_len].copy_from_slice(&self.buf[..self.buf_len]);
61 padded[self.buf_len] = 0x01;
62 self.state.absorb_block(&padded);
63 p12(&mut self.state);
64 }
65}
66
67impl Hasher for AsconHash256 {
68 const BLOCK_SIZE: usize = 8;
69 const OUTPUT_SIZE: usize = 32;
70
71 #[inline]
72 fn new() -> Self {
73 AsconHash256::new()
74 }
75
76 fn update(&mut self, mut data: &[u8]) {
77 if self.buf_len > 0 {
78 let to_fill = (8 - self.buf_len).min(data.len());
79 self.buf[self.buf_len..self.buf_len + to_fill].copy_from_slice(&data[..to_fill]);
80 self.buf_len += to_fill;
81 data = &data[to_fill..];
82
83 if self.buf_len == 8 {
84 self.process_buffer();
85 }
86 }
87
88 let (chunks, remainder) = data.as_chunks::<8>();
89 for chunk in chunks {
90 self.state.absorb_block(chunk);
91 p12(&mut self.state);
92 }
93
94 if !remainder.is_empty() {
95 self.buf[..remainder.len()].copy_from_slice(remainder);
96 self.buf_len = remainder.len();
97 }
98 }
99
100 fn sum(mut self) -> Hash {
101 self.pad_and_finalize();
102
103 let mut hash = Bytes::<64>::with_length(32);
104 let out = hash.as_mut();
105 out[0..8].copy_from_slice(&self.state.squeeze_rate_u64().to_le_bytes());
107 p12(&mut self.state);
108 out[8..16].copy_from_slice(&self.state.squeeze_rate_u64().to_le_bytes());
109 p12(&mut self.state);
110 out[16..24].copy_from_slice(&self.state.squeeze_rate_u64().to_le_bytes());
111 p12(&mut self.state);
112 out[24..32].copy_from_slice(&self.state.squeeze_rate_u64().to_le_bytes());
113
114 Hash(hash)
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use crate::Hasher;
122
123 #[test]
124 fn empty_input() {
125 let h = AsconHash256::hash(b"");
126 let expected = hex::decode("0B3BE5850F2F6B98CAF29F8FDEA89B64A1FA70AA249B8F839BD53BAA304D92B2").unwrap();
127 assert_eq!(h.as_ref(), expected.as_slice());
128 }
129
130 #[test]
131 fn one_byte() {
132 let h = AsconHash256::hash(b"\x00");
133 let expected = hex::decode("0728621035AF3ED2BCA03BF6FDE900F9456F5330E4B5EE23E7F6A1E70291BC80").unwrap();
134 assert_eq!(h.as_ref(), expected.as_slice());
135 }
136
137 #[test]
138 fn two_bytes() {
139 let h = AsconHash256::hash(b"\x00\x01");
140 let expected = hex::decode("6115E7C9C4081C2797FC8FE1BC57A836AFA1C5381E556DD583860CA2DFB48DD2").unwrap();
141 assert_eq!(h.as_ref(), expected.as_slice());
142 }
143
144 #[test]
145 fn exactly_one_block() {
146 let h = AsconHash256::hash(b"\x00\x01\x02\x03\x04\x05\x06\x07");
147 let expected = hex::decode("B88E497AE8E6FB641B87EF622EB8F2FCA0ED95383F7FFEBE167ACF1099BA764F").unwrap();
148 assert_eq!(h.as_ref(), expected.as_slice());
149 }
150
151 #[test]
152 fn incremental() {
153 let msg = b"hello world";
154 let one_shot = AsconHash256::hash(msg);
155 let mut h = AsconHash256::new();
156 for byte in msg {
157 h.update(&[*byte]);
158 }
159 assert_eq!(one_shot.as_ref(), h.sum().as_ref());
160 }
161
162 #[test]
163 fn block_boundaries() {
164 for len in [1usize, 7, 8, 9, 15, 16, 17, 63, 64, 65] {
165 let input = vec![b'a'; len];
166 let one_shot = AsconHash256::hash(&input);
167 let mut h = AsconHash256::new();
168 for chunk in input.chunks(3) {
169 h.update(chunk);
170 }
171 assert_eq!(one_shot.as_ref(), h.sum().as_ref(), "len={len}");
172 }
173 }
174
175 #[test]
176 fn kat_vectors() {
177 let data = include_str!("../../testdata/ascon/LWC_HASH_KAT_128_256.txt");
178 let mut count = 0u64;
179 let mut msg_hex = String::new();
180
181 for line in data.lines() {
182 let line = line.trim();
183 if line.is_empty() {
184 continue;
185 }
186 if line.starts_with("Count = ") {
187 count = line["Count = ".len()..].parse().unwrap();
188 msg_hex.clear();
189 continue;
190 }
191 if line.starts_with("Msg = ") {
192 msg_hex = line[6..].to_string();
193 continue;
194 }
195 if line.starts_with("MD = ") {
196 let expected_md: &str = &line[5..];
197 let msg = hex::decode(&msg_hex).unwrap();
198 let expected = hex::decode(expected_md).unwrap();
199 let hash = AsconHash256::hash(&msg);
200 assert_eq!(hash.as_ref(), expected.as_slice(), "KAT Hash Count={count} mismatch");
201 let mut h = AsconHash256::new();
202 for chunk in msg.chunks(3) {
203 h.update(chunk);
204 }
205 assert_eq!(
206 h.sum().as_ref(),
207 expected.as_slice(),
208 "KAT Hash Count={count} incremental mismatch"
209 );
210 msg_hex.clear();
211 continue;
212 }
213 }
214 }
215}