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