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