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