crypto/ascon/
ascon_xof128.rs1use super::*;
2use crate::Xof;
3
4const IV: u64 = 0x0000_0800_00cc_0003;
6
7#[derive(Clone)]
35#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
36pub struct AsconXof128 {
37 state: State,
38 buf: [u8; 8],
39 buf_len: usize,
40 squeezing: bool,
41 squeeze_pos: usize,
42 current_block: [u8; 8],
43}
44
45impl AsconXof128 {
46 #[inline]
47 pub fn new() -> Self {
48 let mut state = State::init_hash(IV);
49 p12(&mut state);
50 AsconXof128 {
51 state,
52 buf: [0u8; 8],
53 buf_len: 0,
54 squeezing: false,
55 squeeze_pos: 0,
56 current_block: [0u8; 8],
57 }
58 }
59
60 #[inline]
61 pub fn hash(data: &[u8], output: &mut [u8]) {
62 let mut xof = Self::new();
63 xof.absorb(data);
64 xof.squeeze(output);
65 }
66}
67
68impl Xof for AsconXof128 {
69 fn absorb(&mut self, mut data: &[u8]) {
70 assert!(!self.squeezing, "absorb cannot be called after squeeze");
71
72 if self.buf_len > 0 {
73 let to_fill = (8 - self.buf_len).min(data.len());
74 self.buf[self.buf_len..self.buf_len + to_fill].copy_from_slice(&data[..to_fill]);
75 self.buf_len += to_fill;
76 data = &data[to_fill..];
77
78 if self.buf_len == 8 {
79 self.state.absorb_block(&self.buf);
80 p12(&mut self.state);
81 self.buf_len = 0;
82 }
83 }
84
85 let mut chunks = data.chunks_exact(8);
86 for chunk in &mut chunks {
87 self.state.absorb_block(chunk);
88 p12(&mut self.state);
89 }
90
91 let remainder = chunks.remainder();
92 if !remainder.is_empty() {
93 self.buf[..remainder.len()].copy_from_slice(remainder);
94 self.buf_len = remainder.len();
95 }
96 }
97
98 fn squeeze(&mut self, out: &mut [u8]) {
99 if !self.squeezing {
100 let mut padded = [0u8; 8];
101 padded[..self.buf_len].copy_from_slice(&self.buf[..self.buf_len]);
102 padded[self.buf_len] = 0x01;
103 self.state.absorb_block(&padded);
104 p12(&mut self.state);
105 self.squeezing = true;
106 }
107
108 let mut remaining = out;
109 while !remaining.is_empty() {
110 if self.squeeze_pos == 0 {
111 self.current_block = self.state.squeeze_byte();
112 }
113 let n = remaining.len().min(8 - self.squeeze_pos);
114 remaining[..n].copy_from_slice(&self.current_block[self.squeeze_pos..self.squeeze_pos + n]);
115 self.squeeze_pos += n;
116 remaining = &mut remaining[n..];
117
118 if self.squeeze_pos == 8 && !remaining.is_empty() {
119 self.squeeze_pos = 0;
120 p12(&mut self.state);
121 }
122 }
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use crate::Xof;
130
131 #[test]
132 fn empty_xof() {
133 let mut out = [0u8; 64];
134 AsconXof128::hash(b"", &mut out);
135 let expected = hex::decode("473D5E6164F58B39DFD84AACDB8AE42EC2D91FED33388EE0D960D9B3993295C6AD77855A5D3B13FE6AD9E6098988373AF7D0956D05A8F1665D2C67D1A3AD10FF").unwrap();
136 assert_eq!(out.as_slice(), expected.as_slice());
137 }
138
139 #[test]
140 fn one_byte_xof() {
141 let mut out = [0u8; 64];
142 AsconXof128::hash(b"\x00", &mut out);
143 let expected = hex::decode("51430E0438ECDF642B393630D977625F5F337656BA58AB1E960784AC32A16E0D446405551F5469384F8EA283CF12E64FA72C426BFEBAEA3AA1529E2C4AB23A2F").unwrap();
144 assert_eq!(out.as_slice(), expected.as_slice());
145 }
146
147 #[test]
148 fn incremental_xof() {
149 let mut one_shot = [0u8; 64];
150 AsconXof128::hash(b"", &mut one_shot);
151
152 let mut xof = AsconXof128::new();
153 xof.absorb(b"");
154 let mut first = [0u8; 32];
155 let mut second = [0u8; 32];
156 xof.squeeze(&mut first);
157 xof.squeeze(&mut second);
158
159 assert_eq!(first.as_slice(), &one_shot[..32]);
160 assert_eq!(second.as_slice(), &one_shot[32..]);
161 }
162
163 #[test]
164 fn prefix_property() {
165 let mut out64 = [0u8; 64];
166 AsconXof128::hash(b"data", &mut out64);
167
168 let mut out32 = [0u8; 32];
169 AsconXof128::hash(b"data", &mut out32);
170
171 assert_eq!(out32.as_slice(), &out64[..32]);
172 }
173
174 #[test]
175 fn kat_vectors() {
176 let data = include_str!("../../testdata/ascon/LWC_XOF_KAT_128_512.txt");
177 let mut count = 0u64;
178 let mut msg_hex = String::new();
179
180 for line in data.lines() {
181 let line = line.trim();
182 if line.is_empty() {
183 continue;
184 }
185 if line.starts_with("Count = ") {
186 count = line["Count = ".len()..].parse().unwrap();
187 msg_hex.clear();
188 continue;
189 }
190 if line.starts_with("Msg = ") {
191 msg_hex = line[6..].to_string();
192 continue;
193 }
194 if line.starts_with("MD = ") {
195 let expected_md: &str = &line[5..];
196 let msg = hex::decode(&msg_hex).unwrap();
197 let expected = hex::decode(expected_md).unwrap();
198 let mut out = vec![0u8; expected.len()];
199 AsconXof128::hash(&msg, &mut out);
200 assert_eq!(out.as_slice(), expected.as_slice(), "KAT XOF Count={count} mismatch");
201
202 let mut xof = AsconXof128::new();
204 xof.absorb(&msg);
205 let mut out_inc = vec![0u8; expected.len()];
206 xof.squeeze(&mut out_inc);
207 assert_eq!(
208 out_inc.as_slice(),
209 expected.as_slice(),
210 "KAT XOF Count={count} incremental mismatch"
211 );
212 msg_hex.clear();
213 continue;
214 }
215 }
216 }
217}