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