1use xso::{AsXml, FromXml};
8
9use crate::data_forms::DataForm;
10use crate::disco::{DiscoInfoQuery, DiscoInfoResult, Identity};
11use crate::hashes::{Algo, Hash};
12use crate::ns;
13use crate::presence::PresencePayload;
14use base64::{engine::general_purpose::STANDARD as Base64, Engine};
15use blake2::{
16 digest::{Update, VariableOutput},
17 Blake2bVar,
18};
19use digest::Digest;
20use sha2::{Sha256, Sha512};
21use sha3::{Sha3_256, Sha3_512};
22use xso::error::Error;
23
24#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
28#[xml(namespace = ns::ECAPS2, name = "c")]
29pub struct ECaps2 {
30 #[xml(child(n = ..))]
32 pub hashes: Vec<Hash>,
33}
34
35impl PresencePayload for ECaps2 {}
36
37impl ECaps2 {
38 pub fn new(hashes: Vec<Hash>) -> ECaps2 {
40 ECaps2 { hashes }
41 }
42}
43
44fn compute_item(field: &str) -> Vec<u8> {
45 let mut bytes = field.as_bytes().to_vec();
46 bytes.push(0x1f);
47 bytes
48}
49
50fn compute_items<'x, T: 'x, I: IntoIterator<Item = &'x T>, F: Fn(&'x T) -> Vec<u8>>(
51 things: I,
52 separator: u8,
53 encode: F,
54) -> Vec<u8> {
55 let mut string: Vec<u8> = vec![];
56 let mut accumulator: Vec<Vec<u8>> = vec![];
57 for thing in things.into_iter() {
58 let bytes = encode(thing);
59 accumulator.push(bytes);
60 }
61 accumulator.sort();
63 for mut bytes in accumulator {
64 string.append(&mut bytes);
65 }
66 string.push(separator);
67 string
68}
69
70fn compute_features(features: &[String]) -> Vec<u8> {
71 compute_items(features, 0x1c, |feature| compute_item(&feature))
72}
73
74fn compute_identities(identities: &[Identity]) -> Vec<u8> {
75 compute_items(identities, 0x1c, |identity| {
76 let mut bytes = compute_item(&identity.category);
77 bytes.append(&mut compute_item(&identity.type_));
78 bytes.append(&mut compute_item(
79 identity.lang.as_deref().unwrap_or_default(),
80 ));
81 bytes.append(&mut compute_item(
82 identity.name.as_deref().unwrap_or_default(),
83 ));
84 bytes.push(0x1e);
85 bytes
86 })
87}
88
89fn compute_extensions(extensions: &[DataForm]) -> Result<Vec<u8>, Error> {
90 for extension in extensions {
91 if extension.form_type().is_none() {
92 return Err(Error::Other("Missing FORM_TYPE in extension."));
93 }
94 }
95 Ok(compute_items(extensions, 0x1c, |extension| {
96 let mut bytes = compute_item("FORM_TYPE");
97 bytes.append(&mut compute_item(
98 if let Some(form_type) = extension.form_type() {
99 form_type
100 } else {
101 unreachable!()
102 },
103 ));
104 bytes.push(0x1e);
105 bytes.append(&mut compute_items(
106 extension
107 .fields
108 .iter()
109 .filter(|field| field.var.as_deref().unwrap_or("") != "FORM_TYPE"),
110 0x1d,
111 |field| {
112 let mut bytes = vec![];
113 if let Some(var) = &field.var {
114 bytes.append(&mut compute_item(var));
115 }
116 bytes.append(&mut compute_items(&field.values, 0x1e, |value| {
117 compute_item(value)
118 }));
119 bytes
120 },
121 ));
122 bytes
123 }))
124}
125
126pub fn compute_disco(disco: &DiscoInfoResult) -> Result<Vec<u8>, Error> {
130 let features: Vec<_> = disco.features.iter().cloned().collect();
132
133 let features_string = compute_features(&features);
134 let identities_string = compute_identities(&disco.identities);
135 let extensions_string = compute_extensions(&disco.extensions)?;
136
137 let mut final_string = vec![];
138 final_string.extend(features_string);
139 final_string.extend(identities_string);
140 final_string.extend(extensions_string);
141 Ok(final_string)
142}
143
144pub fn hash_ecaps2(data: &[u8], algo: Algo) -> Result<Hash, Error> {
147 Ok(Hash {
148 hash: match algo {
149 Algo::Sha_256 => {
150 let hash = Sha256::digest(data);
151 hash.to_vec()
152 }
153 Algo::Sha_512 => {
154 let hash = Sha512::digest(data);
155 hash.to_vec()
156 }
157 Algo::Sha3_256 => {
158 let hash = Sha3_256::digest(data);
159 hash.to_vec()
160 }
161 Algo::Sha3_512 => {
162 let hash = Sha3_512::digest(data);
163 hash.to_vec()
164 }
165 Algo::Blake2b_256 => {
166 let mut hasher = Blake2bVar::new(32).unwrap();
167 hasher.update(data);
168 let mut vec = vec![0u8; 32];
169 hasher.finalize_variable(&mut vec).unwrap();
170 vec
171 }
172 Algo::Blake2b_512 => {
173 let mut hasher = Blake2bVar::new(64).unwrap();
174 hasher.update(data);
175 let mut vec = vec![0u8; 64];
176 hasher.finalize_variable(&mut vec).unwrap();
177 vec
178 }
179 Algo::Sha_1 => return Err(Error::Other("Disabled algorithm sha-1: unsafe.")),
180 Algo::Unknown(_algo) => return Err(Error::Other("Unknown algorithm in ecaps2.")),
181 },
182 algo,
183 })
184}
185
186pub fn query_ecaps2(hash: Hash) -> DiscoInfoQuery {
189 DiscoInfoQuery {
190 node: Some(format!(
191 "{}#{}.{}",
192 ns::ECAPS2,
193 String::from(hash.algo),
194 Base64.encode(&hash.hash)
195 )),
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202 use minidom::Element;
203 use xso::error::FromElementError;
204
205 #[cfg(target_pointer_width = "32")]
206 #[test]
207 fn test_size() {
208 assert_size!(ECaps2, 12);
209 }
210
211 #[cfg(target_pointer_width = "64")]
212 #[test]
213 fn test_size() {
214 assert_size!(ECaps2, 24);
215 }
216
217 #[test]
218 fn test_parse() {
219 let elem: Element = "<c xmlns='urn:xmpp:caps'><hash xmlns='urn:xmpp:hashes:2' algo='sha-256'>K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4=</hash><hash xmlns='urn:xmpp:hashes:2' algo='sha3-256'>+sDTQqBmX6iG/X3zjt06fjZMBBqL/723knFIyRf0sg8=</hash></c>".parse().unwrap();
220 let ecaps2 = ECaps2::try_from(elem).unwrap();
221 assert_eq!(ecaps2.hashes.len(), 2);
222 assert_eq!(ecaps2.hashes[0].algo, Algo::Sha_256);
223 assert_eq!(
224 ecaps2.hashes[0].hash,
225 Base64
226 .decode("K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4=")
227 .unwrap()
228 );
229 assert_eq!(ecaps2.hashes[1].algo, Algo::Sha3_256);
230 assert_eq!(
231 ecaps2.hashes[1].hash,
232 Base64
233 .decode("+sDTQqBmX6iG/X3zjt06fjZMBBqL/723knFIyRf0sg8=")
234 .unwrap()
235 );
236 }
237
238 #[test]
239 #[cfg_attr(not(feature = "pedantic"), should_panic = "Result::unwrap_err")]
240 fn test_invalid_child() {
241 let elem: Element = "<c xmlns='urn:xmpp:caps'><hash xmlns='urn:xmpp:hashes:2' algo='sha-256'>K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4=</hash><hash xmlns='urn:xmpp:hashes:1' algo='sha3-256'>+sDTQqBmX6iG/X3zjt06fjZMBBqL/723knFIyRf0sg8=</hash></c>".parse().unwrap();
242 let error = ECaps2::try_from(elem).unwrap_err();
243 let message = match error {
244 FromElementError::Invalid(Error::Other(string)) => string,
245 _ => panic!(),
246 };
247 assert_eq!(message, "Unknown child in ECaps2 element.");
248 }
249
250 #[test]
251 fn test_simple() {
252 let elem: Element = "<query xmlns='http://jabber.org/protocol/disco#info'><identity category='client' type='pc'/><feature var='http://jabber.org/protocol/disco#info'/></query>".parse().unwrap();
253 let disco = DiscoInfoResult::try_from(elem).unwrap();
254 let ecaps2 = compute_disco(&disco).unwrap();
255 assert_eq!(ecaps2.len(), 54);
256 }
257
258 #[test]
259 fn test_xep_ex1() {
260 let elem: Element = r#"<query xmlns="http://jabber.org/protocol/disco#info">
261 <identity category="client" name="BombusMod" type="mobile"/>
262 <feature var="http://jabber.org/protocol/si"/>
263 <feature var="http://jabber.org/protocol/bytestreams"/>
264 <feature var="http://jabber.org/protocol/chatstates"/>
265 <feature var="http://jabber.org/protocol/disco#info"/>
266 <feature var="http://jabber.org/protocol/disco#items"/>
267 <feature var="urn:xmpp:ping"/>
268 <feature var="jabber:iq:time"/>
269 <feature var="jabber:iq:privacy"/>
270 <feature var="jabber:iq:version"/>
271 <feature var="http://jabber.org/protocol/rosterx"/>
272 <feature var="urn:xmpp:time"/>
273 <feature var="jabber:x:oob"/>
274 <feature var="http://jabber.org/protocol/ibb"/>
275 <feature var="http://jabber.org/protocol/si/profile/file-transfer"/>
276 <feature var="urn:xmpp:receipts"/>
277 <feature var="jabber:iq:roster"/>
278 <feature var="jabber:iq:last"/>
279</query>
280"#
281 .parse()
282 .unwrap();
283 let expected = vec![
284 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112,
285 114, 111, 116, 111, 99, 111, 108, 47, 98, 121, 116, 101, 115, 116, 114, 101, 97, 109,
286 115, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103,
287 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 99, 104, 97, 116, 115, 116, 97, 116,
288 101, 115, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114,
289 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 100, 105, 115, 99, 111, 35, 105,
290 110, 102, 111, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111,
291 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 100, 105, 115, 99, 111, 35,
292 105, 116, 101, 109, 115, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114,
293 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 105, 98, 98, 31, 104,
294 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114,
295 111, 116, 111, 99, 111, 108, 47, 114, 111, 115, 116, 101, 114, 120, 31, 104, 116, 116,
296 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116,
297 111, 99, 111, 108, 47, 115, 105, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98,
298 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 115, 105,
299 47, 112, 114, 111, 102, 105, 108, 101, 47, 102, 105, 108, 101, 45, 116, 114, 97, 110,
300 115, 102, 101, 114, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58, 108, 97, 115, 116,
301 31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58, 112, 114, 105, 118, 97, 99, 121, 31,
302 106, 97, 98, 98, 101, 114, 58, 105, 113, 58, 114, 111, 115, 116, 101, 114, 31, 106, 97,
303 98, 98, 101, 114, 58, 105, 113, 58, 116, 105, 109, 101, 31, 106, 97, 98, 98, 101, 114,
304 58, 105, 113, 58, 118, 101, 114, 115, 105, 111, 110, 31, 106, 97, 98, 98, 101, 114, 58,
305 120, 58, 111, 111, 98, 31, 117, 114, 110, 58, 120, 109, 112, 112, 58, 112, 105, 110,
306 103, 31, 117, 114, 110, 58, 120, 109, 112, 112, 58, 114, 101, 99, 101, 105, 112, 116,
307 115, 31, 117, 114, 110, 58, 120, 109, 112, 112, 58, 116, 105, 109, 101, 31, 28, 99,
308 108, 105, 101, 110, 116, 31, 109, 111, 98, 105, 108, 101, 31, 31, 66, 111, 109, 98,
309 117, 115, 77, 111, 100, 31, 30, 28, 28,
310 ];
311 let disco = DiscoInfoResult::try_from(elem).unwrap();
312 let ecaps2 = compute_disco(&disco).unwrap();
313 assert_eq!(ecaps2.len(), 0x1d9);
314 assert_eq!(ecaps2, expected);
315
316 let sha_256 = hash_ecaps2(&ecaps2, Algo::Sha_256).unwrap();
317 assert_eq!(
318 sha_256.hash,
319 Base64
320 .decode("kzBZbkqJ3ADrj7v08reD1qcWUwNGHaidNUgD7nHpiw8=")
321 .unwrap()
322 );
323 let sha3_256 = hash_ecaps2(&ecaps2, Algo::Sha3_256).unwrap();
324 assert_eq!(
325 sha3_256.hash,
326 Base64
327 .decode("79mdYAfU9rEdTOcWDO7UEAt6E56SUzk/g6TnqUeuD9Q=")
328 .unwrap()
329 );
330 }
331
332 #[test]
333 fn test_xep_ex2() {
334 let elem: Element = r#"<query xmlns="http://jabber.org/protocol/disco#info">
335 <identity category="client" name="Tkabber" type="pc" xml:lang="en"/>
336 <identity category="client" name="Ткаббер" type="pc" xml:lang="ru"/>
337 <feature var="games:board"/>
338 <feature var="http://jabber.org/protocol/activity"/>
339 <feature var="http://jabber.org/protocol/activity+notify"/>
340 <feature var="http://jabber.org/protocol/bytestreams"/>
341 <feature var="http://jabber.org/protocol/chatstates"/>
342 <feature var="http://jabber.org/protocol/commands"/>
343 <feature var="http://jabber.org/protocol/disco#info"/>
344 <feature var="http://jabber.org/protocol/disco#items"/>
345 <feature var="http://jabber.org/protocol/evil"/>
346 <feature var="http://jabber.org/protocol/feature-neg"/>
347 <feature var="http://jabber.org/protocol/geoloc"/>
348 <feature var="http://jabber.org/protocol/geoloc+notify"/>
349 <feature var="http://jabber.org/protocol/ibb"/>
350 <feature var="http://jabber.org/protocol/iqibb"/>
351 <feature var="http://jabber.org/protocol/mood"/>
352 <feature var="http://jabber.org/protocol/mood+notify"/>
353 <feature var="http://jabber.org/protocol/rosterx"/>
354 <feature var="http://jabber.org/protocol/si"/>
355 <feature var="http://jabber.org/protocol/si/profile/file-transfer"/>
356 <feature var="http://jabber.org/protocol/tune"/>
357 <feature var="http://www.facebook.com/xmpp/messages"/>
358 <feature var="http://www.xmpp.org/extensions/xep-0084.html#ns-metadata+notify"/>
359 <feature var="jabber:iq:avatar"/>
360 <feature var="jabber:iq:browse"/>
361 <feature var="jabber:iq:dtcp"/>
362 <feature var="jabber:iq:filexfer"/>
363 <feature var="jabber:iq:ibb"/>
364 <feature var="jabber:iq:inband"/>
365 <feature var="jabber:iq:jidlink"/>
366 <feature var="jabber:iq:last"/>
367 <feature var="jabber:iq:oob"/>
368 <feature var="jabber:iq:privacy"/>
369 <feature var="jabber:iq:roster"/>
370 <feature var="jabber:iq:time"/>
371 <feature var="jabber:iq:version"/>
372 <feature var="jabber:x:data"/>
373 <feature var="jabber:x:event"/>
374 <feature var="jabber:x:oob"/>
375 <feature var="urn:xmpp:avatar:metadata+notify"/>
376 <feature var="urn:xmpp:ping"/>
377 <feature var="urn:xmpp:receipts"/>
378 <feature var="urn:xmpp:time"/>
379 <x xmlns="jabber:x:data" type="result">
380 <field type="hidden" var="FORM_TYPE">
381 <value>urn:xmpp:dataforms:softwareinfo</value>
382 </field>
383 <field var="software">
384 <value>Tkabber</value>
385 </field>
386 <field var="software_version">
387 <value>0.11.1-svn-20111216-mod (Tcl/Tk 8.6b2)</value>
388 </field>
389 <field var="os">
390 <value>Windows</value>
391 </field>
392 <field var="os_version">
393 <value>XP</value>
394 </field>
395 </x>
396</query>
397"#
398 .parse()
399 .unwrap();
400 let expected = vec![
401 103, 97, 109, 101, 115, 58, 98, 111, 97, 114, 100, 31, 104, 116, 116, 112, 58, 47, 47,
402 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111,
403 108, 47, 97, 99, 116, 105, 118, 105, 116, 121, 31, 104, 116, 116, 112, 58, 47, 47, 106,
404 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47,
405 97, 99, 116, 105, 118, 105, 116, 121, 43, 110, 111, 116, 105, 102, 121, 31, 104, 116,
406 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111,
407 116, 111, 99, 111, 108, 47, 98, 121, 116, 101, 115, 116, 114, 101, 97, 109, 115, 31,
408 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112,
409 114, 111, 116, 111, 99, 111, 108, 47, 99, 104, 97, 116, 115, 116, 97, 116, 101, 115,
410 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47,
411 112, 114, 111, 116, 111, 99, 111, 108, 47, 99, 111, 109, 109, 97, 110, 100, 115, 31,
412 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112,
413 114, 111, 116, 111, 99, 111, 108, 47, 100, 105, 115, 99, 111, 35, 105, 110, 102, 111,
414 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47,
415 112, 114, 111, 116, 111, 99, 111, 108, 47, 100, 105, 115, 99, 111, 35, 105, 116, 101,
416 109, 115, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114,
417 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 101, 118, 105, 108, 31, 104, 116,
418 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111,
419 116, 111, 99, 111, 108, 47, 102, 101, 97, 116, 117, 114, 101, 45, 110, 101, 103, 31,
420 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112,
421 114, 111, 116, 111, 99, 111, 108, 47, 103, 101, 111, 108, 111, 99, 31, 104, 116, 116,
422 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116,
423 111, 99, 111, 108, 47, 103, 101, 111, 108, 111, 99, 43, 110, 111, 116, 105, 102, 121,
424 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47,
425 112, 114, 111, 116, 111, 99, 111, 108, 47, 105, 98, 98, 31, 104, 116, 116, 112, 58, 47,
426 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111,
427 108, 47, 105, 113, 105, 98, 98, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98,
428 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 109, 111,
429 111, 100, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114,
430 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 109, 111, 111, 100, 43, 110, 111,
431 116, 105, 102, 121, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46,
432 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 114, 111, 115, 116, 101,
433 114, 120, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114,
434 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 115, 105, 31, 104, 116, 116, 112,
435 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116, 111,
436 99, 111, 108, 47, 115, 105, 47, 112, 114, 111, 102, 105, 108, 101, 47, 102, 105, 108,
437 101, 45, 116, 114, 97, 110, 115, 102, 101, 114, 31, 104, 116, 116, 112, 58, 47, 47,
438 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111,
439 108, 47, 116, 117, 110, 101, 31, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46,
440 102, 97, 99, 101, 98, 111, 111, 107, 46, 99, 111, 109, 47, 120, 109, 112, 112, 47, 109,
441 101, 115, 115, 97, 103, 101, 115, 31, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119,
442 46, 120, 109, 112, 112, 46, 111, 114, 103, 47, 101, 120, 116, 101, 110, 115, 105, 111,
443 110, 115, 47, 120, 101, 112, 45, 48, 48, 56, 52, 46, 104, 116, 109, 108, 35, 110, 115,
444 45, 109, 101, 116, 97, 100, 97, 116, 97, 43, 110, 111, 116, 105, 102, 121, 31, 106, 97,
445 98, 98, 101, 114, 58, 105, 113, 58, 97, 118, 97, 116, 97, 114, 31, 106, 97, 98, 98,
446 101, 114, 58, 105, 113, 58, 98, 114, 111, 119, 115, 101, 31, 106, 97, 98, 98, 101, 114,
447 58, 105, 113, 58, 100, 116, 99, 112, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58,
448 102, 105, 108, 101, 120, 102, 101, 114, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113,
449 58, 105, 98, 98, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58, 105, 110, 98, 97,
450 110, 100, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58, 106, 105, 100, 108, 105,
451 110, 107, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58, 108, 97, 115, 116, 31, 106,
452 97, 98, 98, 101, 114, 58, 105, 113, 58, 111, 111, 98, 31, 106, 97, 98, 98, 101, 114,
453 58, 105, 113, 58, 112, 114, 105, 118, 97, 99, 121, 31, 106, 97, 98, 98, 101, 114, 58,
454 105, 113, 58, 114, 111, 115, 116, 101, 114, 31, 106, 97, 98, 98, 101, 114, 58, 105,
455 113, 58, 116, 105, 109, 101, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58, 118, 101,
456 114, 115, 105, 111, 110, 31, 106, 97, 98, 98, 101, 114, 58, 120, 58, 100, 97, 116, 97,
457 31, 106, 97, 98, 98, 101, 114, 58, 120, 58, 101, 118, 101, 110, 116, 31, 106, 97, 98,
458 98, 101, 114, 58, 120, 58, 111, 111, 98, 31, 117, 114, 110, 58, 120, 109, 112, 112, 58,
459 97, 118, 97, 116, 97, 114, 58, 109, 101, 116, 97, 100, 97, 116, 97, 43, 110, 111, 116,
460 105, 102, 121, 31, 117, 114, 110, 58, 120, 109, 112, 112, 58, 112, 105, 110, 103, 31,
461 117, 114, 110, 58, 120, 109, 112, 112, 58, 114, 101, 99, 101, 105, 112, 116, 115, 31,
462 117, 114, 110, 58, 120, 109, 112, 112, 58, 116, 105, 109, 101, 31, 28, 99, 108, 105,
463 101, 110, 116, 31, 112, 99, 31, 101, 110, 31, 84, 107, 97, 98, 98, 101, 114, 31, 30,
464 99, 108, 105, 101, 110, 116, 31, 112, 99, 31, 114, 117, 31, 208, 162, 208, 186, 208,
465 176, 208, 177, 208, 177, 208, 181, 209, 128, 31, 30, 28, 70, 79, 82, 77, 95, 84, 89,
466 80, 69, 31, 117, 114, 110, 58, 120, 109, 112, 112, 58, 100, 97, 116, 97, 102, 111, 114,
467 109, 115, 58, 115, 111, 102, 116, 119, 97, 114, 101, 105, 110, 102, 111, 31, 30, 111,
468 115, 31, 87, 105, 110, 100, 111, 119, 115, 31, 30, 111, 115, 95, 118, 101, 114, 115,
469 105, 111, 110, 31, 88, 80, 31, 30, 115, 111, 102, 116, 119, 97, 114, 101, 31, 84, 107,
470 97, 98, 98, 101, 114, 31, 30, 115, 111, 102, 116, 119, 97, 114, 101, 95, 118, 101, 114,
471 115, 105, 111, 110, 31, 48, 46, 49, 49, 46, 49, 45, 115, 118, 110, 45, 50, 48, 49, 49,
472 49, 50, 49, 54, 45, 109, 111, 100, 32, 40, 84, 99, 108, 47, 84, 107, 32, 56, 46, 54,
473 98, 50, 41, 31, 30, 29, 28,
474 ];
475 let disco = DiscoInfoResult::try_from(elem).unwrap();
476 let ecaps2 = compute_disco(&disco).unwrap();
477 assert_eq!(ecaps2.len(), 0x543);
478 assert_eq!(ecaps2, expected);
479
480 let sha_256 = hash_ecaps2(&ecaps2, Algo::Sha_256).unwrap();
481 assert_eq!(
482 sha_256.hash,
483 Base64
484 .decode("u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=")
485 .unwrap()
486 );
487 let sha3_256 = hash_ecaps2(&ecaps2, Algo::Sha3_256).unwrap();
488 assert_eq!(
489 sha3_256.hash,
490 Base64
491 .decode("XpUJzLAc93258sMECZ3FJpebkzuyNXDzRNwQog8eycg=")
492 .unwrap()
493 );
494 }
495
496 #[test]
497 fn test_blake2b_512() {
498 let hash = hash_ecaps2("abc".as_bytes(), Algo::Blake2b_512).unwrap();
499 let known_hash: Vec<u8> = vec![
500 0xBA, 0x80, 0xA5, 0x3F, 0x98, 0x1C, 0x4D, 0x0D, 0x6A, 0x27, 0x97, 0xB6, 0x9F, 0x12,
501 0xF6, 0xE9, 0x4C, 0x21, 0x2F, 0x14, 0x68, 0x5A, 0xC4, 0xB7, 0x4B, 0x12, 0xBB, 0x6F,
502 0xDB, 0xFF, 0xA2, 0xD1, 0x7D, 0x87, 0xC5, 0x39, 0x2A, 0xAB, 0x79, 0x2D, 0xC2, 0x52,
503 0xD5, 0xDE, 0x45, 0x33, 0xCC, 0x95, 0x18, 0xD3, 0x8A, 0xA8, 0xDB, 0xF1, 0x92, 0x5A,
504 0xB9, 0x23, 0x86, 0xED, 0xD4, 0x00, 0x99, 0x23,
505 ];
506 assert_eq!(hash.hash, known_hash);
507 }
508}