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