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}