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