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