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 mut chunks = data.chunks_exact(8);
89 for chunk in &mut chunks {
90 self.state.absorb_block(chunk);
91 p12(&mut self.state);
92 }
93
94 let remainder = chunks.remainder();
95 if !remainder.is_empty() {
96 self.buf[..remainder.len()].copy_from_slice(remainder);
97 self.buf_len = remainder.len();
98 }
99 }
100
101 fn sum(mut self) -> Hash {
102 self.pad_and_finalize();
103
104 let mut hash = Bytes::<64>::with_length(32);
105 let out = hash.as_mut();
106 out[0..8].copy_from_slice(&self.state.squeeze_rate_u64().to_le_bytes());
108 p12(&mut self.state);
109 out[8..16].copy_from_slice(&self.state.squeeze_rate_u64().to_le_bytes());
110 p12(&mut self.state);
111 out[16..24].copy_from_slice(&self.state.squeeze_rate_u64().to_le_bytes());
112 p12(&mut self.state);
113 out[24..32].copy_from_slice(&self.state.squeeze_rate_u64().to_le_bytes());
114
115 Hash(hash)
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use crate::Hasher;
123
124 #[test]
125 fn empty_input() {
126 let h = AsconHash256::hash(b"");
127 let expected = hex::decode("0B3BE5850F2F6B98CAF29F8FDEA89B64A1FA70AA249B8F839BD53BAA304D92B2").unwrap();
128 assert_eq!(h.as_ref(), expected.as_slice());
129 }
130
131 #[test]
132 fn one_byte() {
133 let h = AsconHash256::hash(b"\x00");
134 let expected = hex::decode("0728621035AF3ED2BCA03BF6FDE900F9456F5330E4B5EE23E7F6A1E70291BC80").unwrap();
135 assert_eq!(h.as_ref(), expected.as_slice());
136 }
137
138 #[test]
139 fn two_bytes() {
140 let h = AsconHash256::hash(b"\x00\x01");
141 let expected = hex::decode("6115E7C9C4081C2797FC8FE1BC57A836AFA1C5381E556DD583860CA2DFB48DD2").unwrap();
142 assert_eq!(h.as_ref(), expected.as_slice());
143 }
144
145 #[test]
146 fn exactly_one_block() {
147 let h = AsconHash256::hash(b"\x00\x01\x02\x03\x04\x05\x06\x07");
148 let expected = hex::decode("B88E497AE8E6FB641B87EF622EB8F2FCA0ED95383F7FFEBE167ACF1099BA764F").unwrap();
149 assert_eq!(h.as_ref(), expected.as_slice());
150 }
151
152 #[test]
153 fn incremental() {
154 let msg = b"hello world";
155 let one_shot = AsconHash256::hash(msg);
156 let mut h = AsconHash256::new();
157 for byte in msg {
158 h.update(&[*byte]);
159 }
160 assert_eq!(one_shot.as_ref(), h.sum().as_ref());
161 }
162
163 #[test]
164 fn block_boundaries() {
165 for len in [1usize, 7, 8, 9, 15, 16, 17, 63, 64, 65] {
166 let input = vec![b'a'; len];
167 let one_shot = AsconHash256::hash(&input);
168 let mut h = AsconHash256::new();
169 for chunk in input.chunks(3) {
170 h.update(chunk);
171 }
172 assert_eq!(one_shot.as_ref(), h.sum().as_ref(), "len={len}");
173 }
174 }
175
176 #[test]
177 fn kat_vectors() {
178 let data = include_str!("../../testdata/ascon/LWC_HASH_KAT_128_256.txt");
179 let mut count = 0u64;
180 let mut msg_hex = String::new();
181
182 for line in data.lines() {
183 let line = line.trim();
184 if line.is_empty() {
185 continue;
186 }
187 if line.starts_with("Count = ") {
188 count = line["Count = ".len()..].parse().unwrap();
189 msg_hex.clear();
190 continue;
191 }
192 if line.starts_with("Msg = ") {
193 msg_hex = line[6..].to_string();
194 continue;
195 }
196 if line.starts_with("MD = ") {
197 let expected_md: &str = &line[5..];
198 let msg = hex::decode(&msg_hex).unwrap();
199 let expected = hex::decode(expected_md).unwrap();
200 let hash = AsconHash256::hash(&msg);
201 assert_eq!(hash.as_ref(), expected.as_slice(), "KAT Hash Count={count} mismatch");
202 let mut h = AsconHash256::new();
203 for chunk in msg.chunks(3) {
204 h.update(chunk);
205 }
206 assert_eq!(
207 h.sum().as_ref(),
208 expected.as_slice(),
209 "KAT Hash Count={count} incremental mismatch"
210 );
211 msg_hex.clear();
212 continue;
213 }
214 }
215 }
216}