xmpp_parsers/
ecaps2.rs

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