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