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