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