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