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