bramble_crypto/
primitives.rs

1//! Cryptographic primitives
2
3use crate::{Error, Result};
4use blake2::VarBlake2b;
5use rand::{CryptoRng, Rng};
6use std::fmt::{self, Debug};
7
8/// The output of a hash function
9#[derive(Copy, Clone, PartialEq, Eq)]
10pub struct Hash([u8; HASH_LEN]);
11
12impl From<[u8; HASH_LEN]> for Hash {
13    fn from(bytes: [u8; HASH_LEN]) -> Self {
14        Self(bytes)
15    }
16}
17
18impl AsRef<[u8]> for Hash {
19    fn as_ref(&self) -> &[u8] {
20        &self.0
21    }
22}
23
24impl Debug for Hash {
25    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
26        write!(fmt, "{}", hex::encode(self.0))
27    }
28}
29
30/// A message-authentication code
31#[derive(Copy, Clone)]
32pub struct Mac([u8; MAC_LEN]);
33
34impl From<[u8; MAC_LEN]> for Mac {
35    fn from(bytes: [u8; MAC_LEN]) -> Self {
36        Self(bytes)
37    }
38}
39
40impl AsRef<[u8]> for Mac {
41    fn as_ref(&self) -> &[u8] {
42        &self.0
43    }
44}
45
46impl Debug for Mac {
47    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
48        write!(fmt, "{}", hex::encode(self.0))
49    }
50}
51
52impl Mac {
53    /// Verifies that this MAC matches the given one.
54    pub fn verify(&self, other: &Mac) -> Result<()> {
55        use subtle::ConstantTimeEq;
56
57        if self.0.ct_eq(&other.0).into() {
58            Ok(())
59        } else {
60            Err(Error::InvalidMac)
61        }
62    }
63}
64
65/// An asymmetric cryptography key pair
66#[derive(Copy, Clone, Debug, PartialEq, Eq)]
67pub struct KeyPair {
68    secret: SecretKey,
69    public: PublicKey,
70}
71
72impl KeyPair {
73    /// Generates a new random key pair.
74    pub fn generate<R: Rng + CryptoRng>(rng: &mut R) -> Self {
75        let sk = SecretKey::generate(rng);
76        Self {
77            secret: sk,
78            public: sk.public_key(),
79        }
80    }
81
82    /// Gets the secret part of this key pair.
83    pub fn secret(&self) -> &SecretKey {
84        &self.secret
85    }
86
87    /// Gets the public part of this key pair.
88    pub fn public(&self) -> &PublicKey {
89        &self.public
90    }
91}
92
93impl From<SecretKey> for KeyPair {
94    fn from(sk: SecretKey) -> Self {
95        let pk = sk.public_key();
96        Self {
97            secret: sk,
98            public: pk,
99        }
100    }
101}
102
103/// An asymmetric secret key
104#[derive(Copy, Clone, PartialEq, Eq)]
105pub struct SecretKey([u8; KEY_LEN]);
106
107impl From<[u8; KEY_LEN]> for SecretKey {
108    fn from(bytes: [u8; KEY_LEN]) -> Self {
109        Self(bytes)
110    }
111}
112
113impl AsRef<[u8]> for SecretKey {
114    fn as_ref(&self) -> &[u8] {
115        &self.0
116    }
117}
118
119impl Debug for SecretKey {
120    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
121        write!(fmt, "{}", hex::encode(self.0))
122    }
123}
124
125/// An asymmetric public key
126#[derive(Copy, Clone, PartialEq, Eq)]
127pub struct PublicKey([u8; KEY_LEN]);
128
129impl From<[u8; KEY_LEN]> for PublicKey {
130    fn from(bytes: [u8; KEY_LEN]) -> Self {
131        Self(bytes)
132    }
133}
134
135impl AsRef<[u8]> for PublicKey {
136    fn as_ref(&self) -> &[u8] {
137        &self.0
138    }
139}
140
141impl Debug for PublicKey {
142    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
143        write!(fmt, "{}", hex::encode(self.0))
144    }
145}
146
147impl SecretKey {
148    fn generate<R: Rng + CryptoRng>(rng: &mut R) -> Self {
149        let mut buf = [0u8; KEY_LEN];
150        rng.fill(&mut buf);
151        Self(buf)
152    }
153
154    fn public_key(&self) -> PublicKey {
155        let pk =
156            x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::from(self.0)).to_bytes();
157        PublicKey(pk)
158    }
159}
160
161/// A symmetric cryptography key
162#[derive(Copy, Clone, PartialEq, Eq)]
163pub struct SymmetricKey([u8; KEY_LEN]);
164
165impl From<[u8; KEY_LEN]> for SymmetricKey {
166    fn from(bytes: [u8; KEY_LEN]) -> Self {
167        Self(bytes)
168    }
169}
170
171impl From<Hash> for SymmetricKey {
172    fn from(hash: Hash) -> Self {
173        Self(hash.0)
174    }
175}
176
177impl AsRef<[u8]> for SymmetricKey {
178    fn as_ref(&self) -> &[u8] {
179        &self.0
180    }
181}
182
183impl Debug for SymmetricKey {
184    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
185        write!(fmt, "{}", hex::encode(self.0))
186    }
187}
188
189impl SymmetricKey {
190    /// Generates a new random symmetric key.
191    pub fn generate<R: Rng + CryptoRng>(rng: &mut R) -> Self {
192        let mut buf = [0u8; KEY_LEN];
193        rng.fill(&mut buf);
194        Self(buf)
195    }
196}
197
198/// A nonce
199#[derive(Copy, Clone, PartialEq, Eq)]
200pub struct Nonce([u8; NONCE_LEN]);
201
202impl From<[u8; NONCE_LEN]> for Nonce {
203    fn from(bytes: [u8; NONCE_LEN]) -> Self {
204        Self(bytes)
205    }
206}
207
208impl AsRef<[u8]> for Nonce {
209    fn as_ref(&self) -> &[u8] {
210        &self.0
211    }
212}
213
214impl Debug for Nonce {
215    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
216        write!(fmt, "{}", hex::encode(self.0))
217    }
218}
219
220impl Nonce {
221    /// Generates a random nonce.
222    pub fn new<R>(rng: &mut R) -> Self
223    where
224        R: Rng + CryptoRng,
225    {
226        let mut buf = [0u8; NONCE_LEN];
227        rng.fill(&mut buf);
228        Self(buf)
229    }
230}
231
232struct TupleHasher(VarBlake2b);
233
234impl TupleHasher {
235    pub fn new(label: &'static [u8]) -> Self {
236        use blake2::digest::VariableOutput;
237
238        Self(VarBlake2b::new(HASH_LEN).unwrap()).chain(label)
239    }
240
241    pub fn new_keyed(label: &'static [u8], key: &SymmetricKey) -> Self {
242        Self(VarBlake2b::new_keyed(&key.0, HASH_LEN)).chain(label)
243    }
244
245    pub fn new_exchange(
246        label: &'static [u8],
247        our_sk: &SecretKey,
248        their_pk: &PublicKey,
249    ) -> Result<Self> {
250        let key = dh(our_sk, their_pk);
251        if key.as_ref() == [0u8; KEY_LEN] {
252            return Err(Error::FailedKeyExchange);
253        }
254        Ok(Self::new(label).chain(&key))
255    }
256
257    pub fn update(&mut self, data: impl AsRef<[u8]>) {
258        use blake2::digest::Update;
259
260        let data = data.as_ref();
261        let l = data.len() as u32;
262        self.0.update(&l.to_be_bytes());
263        self.0.update(data);
264    }
265
266    pub fn chain(mut self, data: impl AsRef<[u8]>) -> Self {
267        self.update(data);
268        self
269    }
270
271    pub fn finalize(mut self) -> [u8; HASH_LEN] {
272        use blake2::digest::VariableOutput;
273
274        let mut buf = [0u8; HASH_LEN];
275        self.0
276            .finalize_variable_reset(|res| buf.copy_from_slice(res));
277        buf
278    }
279}
280
281/// Computes a hash of the given messages with the given label as domain separator.
282pub fn hash(label: &'static [u8], messages: &[&[u8]]) -> Hash {
283    let mut hasher = TupleHasher::new(label);
284    for m in messages {
285        hasher.update(m);
286    }
287    Hash(hasher.finalize())
288}
289
290/// Derives a MAC from the given key and messages with the given label as domain separator.
291pub fn mac(label: &'static [u8], key: &SymmetricKey, messages: &[&[u8]]) -> Mac {
292    let mut hasher = TupleHasher::new_keyed(label, key);
293    for m in messages {
294        hasher.update(m);
295    }
296    Mac(hasher.finalize())
297}
298
299/// Derives a key from the given key and messages with the given label as domain separator.
300pub fn kdf(label: &'static [u8], key: &SymmetricKey, messages: &[&[u8]]) -> SymmetricKey {
301    let mut hasher = TupleHasher::new_keyed(label, key);
302    for m in messages {
303        hasher.update(m);
304    }
305    SymmetricKey(hasher.finalize())
306}
307
308/// Performs a key exchange from the given DH keys and the given messages with the given label as domain separator.
309pub fn kex(
310    label: &'static [u8],
311    our_sk: &SecretKey,
312    their_pk: &PublicKey,
313    messages: &[&[u8]],
314) -> Result<SymmetricKey> {
315    let mut hasher = TupleHasher::new_exchange(label, our_sk, their_pk)?;
316    for m in messages {
317        hasher.update(m);
318    }
319    Ok(SymmetricKey(hasher.finalize()))
320}
321
322/// Performs a Diffie-Hellman operation between the two given keys.
323pub fn dh(our_sk: &SecretKey, their_pk: &PublicKey) -> SymmetricKey {
324    use x25519_dalek::{PublicKey, StaticSecret as SecretKey};
325
326    SymmetricKey(
327        SecretKey::from(our_sk.0)
328            .diffie_hellman(&PublicKey::from(their_pk.0))
329            .to_bytes(),
330    )
331}
332
333/// Expands a key into a stream of pseudo-random bytes.
334pub fn stream(key: &SymmetricKey, buf: &mut [u8]) {
335    use salsa20::{
336        cipher::{NewCipher, StreamCipher},
337        Salsa20,
338    };
339    let mut cipher =
340        Salsa20::new_from_slices(key.as_ref(), &[0u8; 8]).expect("invalid key/nonce sizes");
341    buf.fill(0);
342    cipher.apply_keystream(buf)
343}
344
345/// A pseudo-random function.
346pub fn prf(key: &SymmetricKey, message: &[u8]) -> [u8; PRF_LEN] {
347    use blake2::digest::Update;
348    use blake2::digest::VariableOutput;
349
350    let mut buf = [0u8; HASH_LEN];
351    VarBlake2b::new_keyed(&key.0, HASH_LEN)
352        .chain(message)
353        .finalize_variable_reset(|res| buf.copy_from_slice(res));
354    buf
355}
356
357/// Encrypts a plaintext with an authenticated cipher
358pub fn enc(key: &SymmetricKey, nonce: &Nonce, buf: &mut [u8], auth: &mut [u8]) {
359    use xsalsa20poly1305::{
360        aead::{AeadInPlace, NewAead},
361        XSalsa20Poly1305,
362    };
363    assert!(auth.len() == AUTH_LEN);
364    let aead = XSalsa20Poly1305::new_from_slice(key.as_ref()).expect("invalid key size");
365    let nonce = xsalsa20poly1305::Nonce::from_slice(nonce.as_ref());
366    let tag = aead
367        .encrypt_in_place_detached(nonce, &[], buf)
368        .expect("encryption failed");
369    auth.copy_from_slice(&tag);
370}
371
372/// Decrypts an authenticated ciphertext.
373pub fn dec(key: &SymmetricKey, nonce: &Nonce, buf: &mut [u8], auth: &[u8]) -> Result<()> {
374    use xsalsa20poly1305::{
375        aead::{AeadInPlace, NewAead},
376        XSalsa20Poly1305,
377    };
378    assert!(auth.len() == AUTH_LEN);
379    let aead = XSalsa20Poly1305::new_from_slice(key.as_ref()).expect("invalid key size");
380    let nonce = xsalsa20poly1305::Nonce::from_slice(nonce.as_ref());
381    let tag = xsalsa20poly1305::Tag::from_slice(auth);
382    aead.decrypt_in_place_detached(nonce, &[], buf, tag)?;
383    Ok(())
384}
385
386/// The length of hashes
387pub const HASH_LEN: usize = 32;
388/// The length of MACs
389pub const MAC_LEN: usize = HASH_LEN;
390/// The length of keys
391pub const KEY_LEN: usize = MAC_LEN;
392/// The length of the PRF output
393pub const PRF_LEN: usize = KEY_LEN;
394/// The length of the AEAD auth tags
395pub const AUTH_LEN: usize = 16;
396/// The length of the AEAD nonces
397pub const NONCE_LEN: usize = 24;
398
399#[cfg(test)]
400mod test {
401    use super::{dh, hash, kdf, kex, Hash, PublicKey, SecretKey, SymmetricKey, KEY_LEN};
402    use hex_literal::hex;
403
404    #[test]
405    fn hash_reference_values() {
406        for (m1, m2, m3, expected1, expected2) in HASH_TEST_VECTORS {
407            let hash1 = hash(b"test1", &[&m1, &m2, &m3]);
408            let hash2 = hash(b"test2", &[&m1, &m2, &m3]);
409            assert_eq!(hash1, expected1);
410            assert_eq!(hash2, expected2);
411        }
412    }
413
414    #[test]
415    fn hash_identical_inputs_produce_identical_outputs() {
416        let label = b"test";
417        let m1 = random_bytes(123);
418        let m2 = random_bytes(123);
419        let m3 = random_bytes(123);
420        let hash1 = hash(label, &[&m1, &m2, &m3]);
421        let hash2 = hash(label, &[&m1, &m2, &m3]);
422        assert_eq!(hash1, hash2);
423    }
424
425    #[test]
426    fn hash_different_labels_produce_different_outputs() {
427        let label1 = b"test1";
428        let label2 = b"test2";
429        let m1 = random_bytes(123);
430        let m2 = random_bytes(123);
431        let m3 = random_bytes(123);
432        let hash1 = hash(label1, &[&m1, &m2, &m3]);
433        let hash2 = hash(label2, &[&m1, &m2, &m3]);
434        assert_ne!(hash1, hash2);
435    }
436
437    #[test]
438    fn hash_different_inputs_produce_different_outputs() {
439        let label = b"test";
440        let m1 = random_bytes(123);
441        let m2 = random_bytes(123);
442        let m3 = random_bytes(123);
443        let hash1 = hash(label, &[&m1, &m2, &m3]);
444        let hash2 = hash(label, &[&m3, &m2, &m1]);
445        assert_ne!(hash1, hash2);
446    }
447
448    #[test]
449    fn kdf_reference_values() {
450        for (key, m1, m2, m3, expected1, expected2) in KDF_TEST_VECTORS {
451            let mac1 = kdf(b"test1", &key, &[&m1, &m2, &m3]);
452            let mac2 = kdf(b"test2", &key, &[&m1, &m2, &m3]);
453            assert_eq!(mac1, expected1);
454            assert!(expected1 == mac1);
455            assert_eq!(mac2, expected2);
456            assert!(expected2 == mac2);
457        }
458    }
459
460    #[test]
461    fn kdf_identical_keys_and_inputs_produce_identical_outputs() {
462        let label = b"test";
463        let key = random_key();
464        let m1 = random_bytes(123);
465        let m2 = random_bytes(123);
466        let m3 = random_bytes(123);
467        let mac1 = kdf(label, &key, &[&m1, &m2, &m3]);
468        let mac2 = kdf(label, &key, &[&m1, &m2, &m3]);
469        assert_eq!(mac1, mac2);
470        assert!(mac1 == mac2);
471    }
472
473    #[test]
474    fn kdf_different_labels_produce_different_outputs() {
475        let label1 = b"test1";
476        let label2 = b"test2";
477        let key = random_key();
478        let m1 = random_bytes(123);
479        let m2 = random_bytes(123);
480        let m3 = random_bytes(123);
481        let mac1 = kdf(label1, &key, &[&m1, &m2, &m3]);
482        let mac2 = kdf(label2, &key, &[&m1, &m2, &m3]);
483        assert_ne!(mac1, mac2);
484        assert!(mac1 != mac2);
485        assert!(mac2 != mac1);
486    }
487
488    #[test]
489    fn kdf_different_keys_produce_different_outputs() {
490        let label = b"test";
491        let key1 = random_key();
492        let key2 = random_key();
493        let m1 = random_bytes(123);
494        let m2 = random_bytes(123);
495        let m3 = random_bytes(123);
496        let mac1 = kdf(label, &key1, &[&m1, &m2, &m3]);
497        let mac2 = kdf(label, &key2, &[&m1, &m2, &m3]);
498        assert_ne!(mac1, mac2);
499        assert!(mac1 != mac2);
500        assert!(mac2 != mac1);
501    }
502
503    #[test]
504    fn kdf_different_inputs_produce_different_outputs() {
505        let label = b"test";
506        let key = random_key();
507        let m1 = random_bytes(123);
508        let m2 = random_bytes(123);
509        let m3 = random_bytes(123);
510        let mac1 = kdf(label, &key, &[&m1, &m2, &m3]);
511        let mac2 = kdf(label, &key, &[&m3, &m2, &m1]);
512        assert_ne!(mac1, mac2);
513        assert!(mac1 != mac2);
514        assert!(mac2 != mac1);
515    }
516
517    #[test]
518    fn dh_reference_values() {
519        let ss1 = dh(&ALICE_PRIVATE, &BOB_PUBLIC);
520        let ss2 = dh(&BOB_PRIVATE, &ALICE_PUBLIC);
521        assert_eq!(ss1, ss2);
522        assert_eq!(ss1, SHARED_SECRET);
523        assert_eq!(ss2, SHARED_SECRET);
524    }
525
526    #[test]
527    fn dh_derives_same_shared_secret_from_equivalent_public_key() {
528        let mut equiv = ALICE_PUBLIC;
529        equiv.0[31] ^= 0x80;
530        assert_ne!(equiv, ALICE_PUBLIC);
531        let ss1 = dh(&BOB_PRIVATE, &ALICE_PUBLIC);
532        let ss2 = dh(&BOB_PRIVATE, &equiv);
533        assert_eq!(ss1, SHARED_SECRET);
534        assert_eq!(ss2, SHARED_SECRET);
535    }
536
537    #[test]
538    fn kex_derives_shared_secret() {
539        let (sk1, pk1) = random_key_pair();
540        let (sk2, pk2) = random_key_pair();
541        let m1 = random_bytes(123);
542        let m2 = random_bytes(123);
543        let m3 = random_bytes(123);
544        let ss1 = kex(b"test", &sk1, &pk2, &[&m1, &m2, &m3]);
545        let ss2 = kex(b"test", &sk2, &pk1, &[&m1, &m2, &m3]);
546        assert_eq!(ss1.unwrap(), ss2.unwrap());
547    }
548
549    #[test]
550    fn kex_rejects_invalid_public_key() {
551        let (sk1, _) = random_key_pair();
552        let invalid = PublicKey([0u8; KEY_LEN]);
553        let m1 = random_bytes(123);
554        let m2 = random_bytes(123);
555        let m3 = random_bytes(123);
556        assert!(kex(b"test", &sk1, &invalid, &[&m1, &m2, &m3]).is_err());
557    }
558
559    #[test]
560    fn kex_derive_same_shared_secret_from_equivalent_public_keys_without_hashing_in() {
561        let (_, pk1) = random_key_pair();
562        let (sk2, _) = random_key_pair();
563        let mut equiv = pk1;
564        equiv.0[31] ^= 0x80;
565        let m1 = random_bytes(123);
566        let m2 = random_bytes(123);
567        let m3 = random_bytes(123);
568        let ss1 = kex(b"test", &sk2, &pk1, &[&m1, &m2, &m3]);
569        let ss2 = kex(b"test", &sk2, &equiv, &[&m1, &m2, &m3]);
570        assert_eq!(ss1.unwrap(), ss2.unwrap());
571    }
572
573    #[test]
574    fn kex_derive_same_shared_secret_from_equivalent_public_keys_with_hashing_in() {
575        let (_, pk1) = random_key_pair();
576        let (sk2, pk2) = random_key_pair();
577        let mut equiv = pk1;
578        equiv.0[31] ^= 0x80;
579        let m1 = random_bytes(123);
580        let m2 = random_bytes(123);
581        let m3 = random_bytes(123);
582        let ss1 = kex(
583            b"test",
584            &sk2,
585            &pk1,
586            &[pk1.as_ref(), pk2.as_ref(), &m1, &m2, &m3],
587        );
588        let ss2 = kex(
589            b"test",
590            &sk2,
591            &equiv,
592            &[equiv.as_ref(), pk2.as_ref(), &m1, &m2, &m3],
593        );
594        assert_ne!(ss1.unwrap(), ss2.unwrap());
595    }
596
597    fn random_bytes(n: usize) -> Vec<u8> {
598        use rand::distributions::Standard;
599        use rand::{thread_rng, Rng};
600
601        let rng = thread_rng();
602        rng.sample_iter(Standard).take(n).collect()
603    }
604
605    fn random_key() -> SymmetricKey {
606        use rand::{thread_rng, Rng};
607
608        let mut buf = [0u8; KEY_LEN];
609        let mut rng = thread_rng();
610        rng.fill(&mut buf);
611        SymmetricKey(buf)
612    }
613
614    fn random_key_pair() -> (SecretKey, PublicKey) {
615        let sk = random_key();
616        let pk = x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::from(sk.0)).to_bytes();
617        (SecretKey(sk.0), PublicKey(pk))
618    }
619
620    const ALICE_PRIVATE: SecretKey = SecretKey(hex!(
621        "77076D0A7318A57D3C16C17251B26645DF4C2F87EBC0992AB177FBA51DB92C2A"
622    ));
623    const ALICE_PUBLIC: PublicKey = PublicKey(hex!(
624        "8520F0098930A754748B7DDCB43EF75A0DBF3A0D26381AF4EBA4A98EAA9B4E6A"
625    ));
626    const BOB_PRIVATE: SecretKey = SecretKey(hex!(
627        "5DAB087E624A8A4B79E17F8B83800EE66F3BB1292618B6FD1C2F8B27FF88E0EB"
628    ));
629    const BOB_PUBLIC: PublicKey = PublicKey(hex!(
630        "DE9EDB7D7B7DC1B4D35B61C2ECE435373F8343C85B78674DADFC7E146F882B4F"
631    ));
632    const SHARED_SECRET: SymmetricKey = SymmetricKey(hex!(
633        "4A5D9D5BA4CE2DE1728E3BF480350F25E07E21C947D19E3376F09B3C1E161742"
634    ));
635
636    const HASH_TEST_VECTORS: [([u8; 64], [u8; 64], [u8; 64], Hash, Hash); 16]= [
637        (
638            hex!("44EE2E7DCD5C33C19FE601C1B38C1C3068409D96E49BACD0E093A2091EB5C734B9D0290092E4CDB0EC9BC81F30E0489916631EA66BCAB1A4679845738BE7B580"),
639            hex!("A2E238EFDE50E694CFBE2F1C3B16148880AD49DBAD459521E09B44D24FCAED47DE5884EB984EB34839A131AFAA1BA80735314A155B9E25EC3E6925961A9C8BA7"),
640            hex!("CEFAE5AEDB84593E40D5D6A3A98410BA87B624479B4EC82BDB695D2D33E42F4DD66E2F95742795A09F8D085438A380360E51C65185F41962F28D19B7F370001A"),
641            Hash(hex!("8BB5C31F5A540872FD3E8E3874E7CB2C4B3D6C5DDA969195D7B285A4EEDF5713")),
642            Hash(hex!("5D095D88F1013E6F72BC6DED575F285B3A87323E4CB5F7D12C11BD887EED06D1"))
643        ),
644        (
645            hex!("DBFC6A076B5FA5DC82AC0AAB28B5908F6C7788827C5CE554F4065989331C11F7344F33BB69A2B7152DE0436F2C2CBD6244BBC00CFF7C5DD44BEB9E624A8D4ECE"),
646            hex!("63ED19DE0182B65080E3D28207BD8683561D71C216752545F4D20F8F3615787B6184256004F74ADFEA6322A35BB06F710D0DEDF61E745F5421A0EA9836BFA83A"),
647            hex!("2ABB8212FB0599027CC274F3A12367A7171085DD683CA1EEE4FE9AF59B64A07D40EF1F019F01EAC36D642183A34F3710E8C6D12DB80DF0BFB73DAB064ADB3F31"),
648            Hash(hex!("0257D05D007BC15A80A3EE8C9B02888BE0654484F678968D8D2E786A8C87B6B0")),
649            Hash(hex!("A11D3ED4F623AFBD9F03468E39B07DA732A9732101F7423F90263F025474412C"))
650        ),
651        (
652            hex!("EA30E266DDCFF498F7EE84DFB314E2A57EE23C72C06CDCF25EC47C3F02CA743C950AEDC47185E521306BCD877B8295697E16ED2DC68BF01A9751FC9E3ADF506A"),
653            hex!("B962AA68A422AE5A09E32283770F3A9FB91502D56D5B840DA8EAAF7A1B8D5779EB62EA39B6D68543EA37F279968E4645F6793EE33DBCED637C6996DCEF4143EC"),
654            hex!("44A6C3051ABE4EE363027C401C251147C162E210339BD287642DE47E930FA012E265F64BF5D4CADAA6D23EA420C1FFDEE9E9C4E9408CAA4D95E30074F909FD67"),
655            Hash(hex!("AF612B99B64F509183F472AFF082342A708E224F1F0A1F5E97BD61982639B33E")),
656            Hash(hex!("461918BA348D96997721FF83D5D7C4030A9F0CE7796CC8C37D3717297DDC5932"))
657        ),
658        (
659            hex!("75CFDDDE303F4E0E840E640627A52633DE48A66923861B9E1204FF9E3546124037720A6FE2CF964737950BB3FD3FFE7A1F3024741FC8813EBB3A70BAD26C2A57"),
660            hex!("DB4BE8EFAE9FDB4CE5C8E1F8F8A27D04A02D5AE67C73F00F647DE1D4BF765C401177CA08BFAE83DB7387F344D389618D064206006EDC0197376EF36ED2FB7AFA"),
661            hex!("8E0775C7F49B79D66BF9DDA31FD0156E37737F631FADE2A03E80BE3DF55C39CB8CA679125E4735727BC2E7F7BE1702FADEB0EF712B304331EAAF7EF1A5520C34"),
662            Hash(hex!("8BE489F466D789F32BC407A5DEC414EEF0606CA774F6B30237FF3B761CA17B86")),
663            Hash(hex!("B1E97A6EADA81E43E1ED9B716588E8655A82AE1B14E66B9508EA6EE3B27EDABB"))
664        ),
665        (
666            hex!("81BBCAB8241EB0155163E3C12C29C6B3116C61110A091019E54BAE3A881A6E28FECF8E4729660D4FA77E6ED7E5500E294742FBD7DB1476C289BCE8B319767C64"),
667            hex!("09D9E8C4B69AE63736C95692C8B206D1480F8BE3018453577AB47D7AF6C510CFEEC688D063D7E3E8E0D594A8DE81B29A13E70DA0DD90527F9C5E2E9E01C200A8"),
668            hex!("7E1A62E8F957F882ABA5FC9E812EA76E6B724E8143E5FD0438925D03AE600A9D8EF1F306F8CA4AD541C84735E13C8F3E574351E8FD94CBBE7A7BCB6788951DBD"),
669            Hash(hex!("B67C87EA7B93AC2780F998D4052B360E39FEA686B09C55D496B97E523F8D11FE")),
670            Hash(hex!("A77777FB5A711565218A42D8E91EAACF704776F5BFCACE2DD3D05C6AFC4F61D3"))
671        ),
672        (
673            hex!("986D1D67AE1E581EACC0B1B5BC2926C05EF7B7AA51F67CFA14ABE67E4D28F046D0AF687466E0B5608883F8EC3A5EE5155A65D6EAC10FA8F4B8BE5B752E71FFB0"),
674            hex!("0439A9F289AB98DC41A4618F7B7D9697B04731442EF925B89A63B0612BD376FD9F23F8679AB1145B33132D6A54F0ECF139E231B7A6F58038DBFD6310B04CE67B"),
675            hex!("0DC20AD1CF95C59B61E25DDC6CCA1A6D15AD1A9A28A163427E09976940E01BB93F1B1810926F5F80F255B7F9BFD06365281978052B9B271EECB2F802F08250AE"),
676            Hash(hex!("99FF047DCA092824F7E83993A25A5C748643DD2A4801999A4649644251DBEE9C")),
677            Hash(hex!("1FC2F1CFCC75F0870027C58B271CF23ECD86739D0EE46661C1BF1176B0959DAA"))
678        ),
679        (
680            hex!("47FBCF0D756529708588ED3EA74383D6517FC7AEC5B8A204BC858B4EE94D14F51557D927ED6B92B4083F5996574B51A381FF1F010B8B2F7F63B6DE1EC3DF12D0"),
681            hex!("93801D48A7F132C2EE99A24679F2C1701C265A872A0E1C8F5CB4FB9EDA60AE05C6802FFC90E8395D917FDE1B2BC6850D59F353875C60B10885BD1EFAAA6CCEA8"),
682            hex!("39503B53CCD5D4246E3BB7A4E2BBF7CF324BA5294EB2B03C1E2328D640B8D20578C3FAA73284F3A2A97E1E49E5675AA2E829A7ECA0A18FD14AD29D79BC30DD07"),
683            Hash(hex!("610C80BAE7A922BC0FBB021A5C943581CF931A513AE7F89D2B54F37C8477EE2B")),
684            Hash(hex!("12649D9C636378ACC43E0A3F6346133A5054FB870F353A4A9849A24437C16EBD"))
685        ),
686        (
687            hex!("A22E18B8578B514DF14EBF6811C5AD293991517CAABEC25E61F0F83D575C63DF3C4C068BC77CEE1BF71EE9D56D03710226443B91E7D62E3E88F117419B74CF0F"),
688            hex!("FEA19B0DC47556B94BED048C7CAF105094AB76FB8FC6C2F0BC6137B516F115BD0A5C8C2827832F22C21E9EDD2999A4B99580EC6687093E9213E9B10DCB90D3F9"),
689            hex!("855D24B67F36D6AED75020933406D0F8821F3328A6B7AD8B8BCEFABED69111A1179D7DDF8E089EE0284AC0F5B118037D742C7EFF398F40878370553FE4FFA690"),
690            Hash(hex!("B46CFAF84D30B021FBB6033AAF496E7CBCC20B7A436B2D5847D356DE2BA78451")),
691            Hash(hex!("FFFBE623632C26DEC80D8EBE8EDB43B7149EAB2CC6AA68E58850C8FE9438652B"))
692        ),
693        (
694            hex!("BDAD3373E36EB230A90DA1B3F09A9FECABD2F22B34E3E4806A9BDA94A25C8AFF36EE5234314FA18D4B8753E8FE960AE47AC3AFD8F9DA4B008C72B71F1289B1B5"),
695            hex!("94740051495B857608F8392E154EE9FE648A9954ECB772DF9783F970026BBEC09334A15C72C56FB4B4BBAD4C6A213CE4D705390E1F86A9325F61A0C3869BBACC"),
696            hex!("75B0D0BB2606670244CA793D8B45DBF007874972174787611D59586742E8E00E7FC5CA4294EE2D1454983CF8D758D6B56BE6A2594BACFF27EBDA49AAF0D1CF80"),
697            Hash(hex!("FFF6BBFAA68236E2F863F6507552371B3FE5309FCED0FC59AD7B6D681E341066")),
698            Hash(hex!("F01C5DCC21625B8314E40D54F216FF521394E81567CEEBECC6632CF4A3BA2C09"))
699        ),
700        (
701            hex!("333268EEDED5D6498BE79F87918E2148FF30BF4E10A80479A14E16666D252650FB1B606F1A3965E89B85FD9863A98A27F1094CCDD6FFBA57B45BE5C293E231B9"),
702            hex!("27CC2CACD2E18222FACDF212260101A49C357ED043A33E4431EA16C65A10477191126E093AE2E1EAF77B1615DD06C0A84A94455C151137FA28E87C5A5F084822"),
703            hex!("153517A73724753683DA56E862AC88098B589802FBE6952A8DA93794535E3322152CBE2BE52B8883B594D62ADE2AF9C8B28B29B11A4C5833B840BFE17E8EA14F"),
704            Hash(hex!("B58741E3E6A2330A38B445390E1B86D14C1D9C41AB714F65432FDDDCBE9A5E6F")),
705            Hash(hex!("185D7BF10CD25418E4B0E29BA4423314E19A8E3F089A3D45C8DF79BFE7EEBB3E"))
706        ),
707        (
708            hex!("A1D09520C0DE7752167C26A412D3F5B4D02081FFDA3E0CA0B5F437EB6D40196603ECCF44A6CB0942A51477E6452EE3DBC34F3D4C89E801B9ACEAD30421C8E28C"),
709            hex!("8DA0B8D9B036180A9A70E6036682441B900017DC8BDEC326B1092914E9C2778BB41E81477B7CD7164003F22AC6FE2D24DE614F01C9A4CE0E90FBF1626F61CDA6"),
710            hex!("72046749DA32DBC80453F7F707517E9E19E44E5DA0D71B287B0B15B4F0639C6EC3095BD7549B08B6F8B94D7DA29BC834EF2DBA646146B931856EC9F1BEF86338"),
711            Hash(hex!("204494CA7BFCAF12407F8B99684EFA6D685AD953515535FB3827998F6E9C02BE")),
712            Hash(hex!("6CBB199BA1E1C8BE18CABF326291D3457610EAE9BF5A093C2BF33B244F54E832"))
713        ),
714        (
715            hex!("2950F9CB3642D9ECEFCA1D92E7E23DDA7FED194BA66243DCBA360DE7EB1F8294CC732B50B0C48655CAEF84872577BFB26B385A5D0FFCD7D30204E3E6D167E7E7"),
716            hex!("1F45FA53661604FA8592F200E24F7097574EA05A2D8E02F7A17547DD139A2F74B349DD57E5F8BE8AE826907B3B39603BC6683EF093E4124C9F41DFDAE50445C6"),
717            hex!("1D7C0B986B987B035C4720A21FCBBB2B80025A48CAAC9EEEEA8A01AD922B0F2B7768ABD369AE6BFA6F65D790D28FA2170F3CB184CF40D853D1199B9EF7D4F40A"),
718            Hash(hex!("DD4FC490E3C5E32156262FEB6DE7F3ED8D9D303A593B040888D4AAF0F140C383")),
719            Hash(hex!("1CE8DC7A69756F681DC1FBC1DAB3BCAFB8195DCFA2FA7A2A06727BDAAE9C4497"))
720        ),
721        (
722            hex!("F291FC88A06482E560A7720758AD114DAF18C1887A01182EA6A75E2145A4A711589F880A41D035F58FF690D3D690C3AB29A21E3DDDBECA59A94E03504C8CDB3A"),
723            hex!("3BB0BF9A2E3E1B4FFCEAE4E57939CE134ED176D288AEA3AB70EC62584BC87DEFC703C5895E9F50BC6C31C7E8A91EDFF2FB1634E53CD6CE89C083BAC0813A9268"),
724            hex!("AD65C638FA5060C3C440E16E2121D6C7D53449A02EB7C2EFC1DFD7F1C6EFFBDEA3BAA713E2EE869C8EFA06BE72E1A1FDC211B9A086C8003E7EBC1C88025E3836"),
725            Hash(hex!("046A6A69C032C3472A65B155D772E04999372F6EF7CCD9EF7A2CC25DDE38D350")),
726            Hash(hex!("F179B2CBE004B5C65466C33406E741A9A424A932F46B3065D6E122161ED94A4C"))
727        ),
728        (
729            hex!("A408334992371AF6D6BB4D4DFF137EA3C7C920C7D0B5667BD37FF4136CF171BCAE18CE401C1AB9D11C208FBBFFF0CC3A828516B457FC8B4578DF46E450A2818C"),
730            hex!("C4D2579474ADDF556419BB645D3ECE0194DA2EE06FED52FEF2F2EF5E9BD0FAF32F04C7AF7D8C3C80EDB5FC9A4E5DA844B90D6DB3846B2121413AA2A61999BBD3"),
731            hex!("3C2EDEDDCC8FA59A99019458D80583C7F0D3D8C5F73DCE0E4AE9C4A5AD8861FCBC8204272E5056D66F96B2D059CD43D4FC969A179D3B357D5400B9DCCC0AB8AB"),
732            Hash(hex!("DBEF9E5AF1C30098BBA277B16BB0809ADD34F9360BA58E304FA8C194084F15FD")),
733            Hash(hex!("36733C9CC5F84229CD8F13395CE917C79F1ECB20FF001CE29517C14F094F6040"))
734        ),
735        (
736            hex!("EE3FE00355EB6B02611D8C144DB8603A754D8DF71710A95C82E8549F659445A3573FB3F434AF5469BEFEA4E29C736A81BCE4B50E58C00F2DAA74CDEB2E0ECDE3"),
737            hex!("9FFFC9CE58B71440C51867BF97BA705B8DB9AA64A753122FDCFFCE03210CB89CAC20AB660E739FB0B0F3B428BE46A185FEF0F3689CDB0C10D5A7CF2217BC356B"),
738            hex!("E72DFE29DA303541DCD8A4D5E465E9DCEC4F5FC443883AAEB4B991737D51A9AABD0A04BCF25024AB4D532248B1B02CEF75EF42939D82473B7DBA8C40D6A30545"),
739            Hash(hex!("66ED10E4935150D14BD8731BCFCEE098C62B91740501DC5D658ECD47ADEDCB23")),
740            Hash(hex!("16C5C00FB0015C7AD4E79719661061E68D75DE87CF22C664D3CD89114876344C"))
741        ),
742        (
743            hex!("0274A6756670DA3B366F46B60319D7D228A5D5FC30B0AF1654D7E913CAF85646E02FDAE732AFC08E67D321807CA8016165CBDBCCAF20E0375E417A3D4BD11E26"),
744            hex!("3663592E2EE415BA4D43664E81E4B7D8612B2EEF6CBEAD6E4B37A0A78E7F5BE504351D01932DC47A9DC9B6BC607DAA691047E3AAABCC4F7A13855609F7489494"),
745            hex!("50FF862C4FFA985BB285F1C838456D6AA97F9BEDA4B6F8AB92315D54005E637FA32BAAB187ECD216091C18A47B1682D6273A3C3F059A4F76097768ACB7A8B8B4"),
746            Hash(hex!("B878EEC15288593F91F2DE899061D26DAFD8FACEC4570D1BF70B251B5C77FA04")),
747            Hash(hex!("CEA2750E11D569DA1D5DE8C549646A5CC608207321A84D29A198324DE6E2A087"))
748        ),
749    ];
750
751    const KDF_TEST_VECTORS: [(SymmetricKey, [u8; 64], [u8; 64], [u8; 64], SymmetricKey, SymmetricKey); 16] = [
752        (
753            SymmetricKey(hex!("011591346B2B0239A076F8F66784C0571624ABB4A4F0412EFE39B9B962B6E6D0")), 
754            hex!("76F4050C3EDC2E34FF137D27966CEB31DE03A60ADB02214367689A2713ED64A0DB6531AF22292B0CB74460158DE45304B0268543D3B6BE3DAED7B8B494E160CE"), 
755            hex!("7C7883AD1B4733FD125DFDA107CF994B9C0EB5CD286AC621AF813605CA21687D4D4B1ADA006CDD19A083306BB6ADCF5296232F1A8E349C45CC927ACFD15591CC"), 
756            hex!("64DDEEFBFE9481C7B335DDFDBE0BCCB7F60BD3464996EAB56AB64B6877D269A57B6E9BFB139D636CE4DB108C38B84DEFF89462DCB476C7C2727337B6BEFB1282"), 
757            SymmetricKey(hex!("528FCBB00BD7D3EC03EC27C2290E42730A9ABEF834DC2D6BD4DC8C44AEA3757F")), 
758            SymmetricKey(hex!("356C1D3D4106ED4066FFB6550A0E77E323ECBCD336075407CC7E34FF3EC0C9D4"))
759        ),
760        (
761            SymmetricKey(hex!("6F6F5D7293A399C78C6E33D8B1D07CC23D2BE2DBBB720A74D198D8A25D77B9F3")), 
762            hex!("C3023590A7C2E8AF4C2AF802A89B92A649E35F4D607BAEFBF8B9CEA0402FD0CC1E0D4469C91512A48554002E1333B25E0312630039C4587E5CBB78250424B915"), 
763            hex!("C8D5CEDC4A104AACE10F6271DBFE3B8F37758634F0015FB3F76EC4057C0FC65D31378072CD23D489C84085765BFF25C917ECFE6EC2F8E6EEC540A57D2FD7BA8D"), 
764            hex!("6B5FD3BCC9B6FC16EC810827E5E7221BB6BF10D8015BF92148F3034AD7CE3B1CAB20C5090A6BEB06BE28A0423D09A2658C7BB51992F7A13D056C39A5E3CAD167"), 
765            SymmetricKey(hex!("9EB06394F343E046D75D94BA8D5986FF7C3A8FA8C98FB4E264BEE7E48BF7D2EC")), 
766            SymmetricKey(hex!("68C106D4FE6D9F97E46F9B0C4DB6B7F44A49D6E25CF8087BBA9DE9469509C155"))
767        ),
768        (
769            SymmetricKey(hex!("CCD12E6D30B407EAF659215B1C0CF285F555F4DE7038772F05906626F6026E05")), 
770            hex!("CBBE6C7A2EBEE9780F2E2BAAAE7B10ECB128AFC127F1225F55303B7C66C497054C293255CCA311ADC8E51F701420F05566F9E5AA597DC62D8606FEBBBDF4AD8D"), 
771            hex!("14D9AC1B26F5DE1BA42E6010E328403A1912B3673D2F54792DC1E7853C64E6A58D3C5A0E2C8E825D6B77FAEAA427FEE3B9A9817B1B0E388F6420239053F0F4C7"), 
772            hex!("4519304420BDE406A754400852DA5C5F941C4106D1E4E94A482204422A76848D6FCCFA2B1AB9B9E228F5F306DFC5C91FE0B496EB51A04256793F48E91C95EBD8"), 
773            SymmetricKey(hex!("5BB3797B7DB0B7B0F59E92AD311E8EF6C426210A50CF7FF3EBF91C90941EA891")), 
774            SymmetricKey(hex!("52FE75CEBEEAD67369F25C7BF062D08F2BC345550BC18E695440A519C5EFBD07"))
775        ),
776        (
777            SymmetricKey(hex!("601B139687683EA380A6FF61AFA01BB63403504621FEAEA29DB771BB3641C7F5")), 
778            hex!("1394CD83A677573B8869E90E1A8D33050CC79799D98A993BDCED8F45BC25657AA67D45840ABF0C6BD99674AAEE239B224867AF1FA8F0A58365D50625A5D72726"), 
779            hex!("DB5865F81BFA9AD0549323E5EC4EE977ADFA2E0CD09597C7E86D27E41AD84E9498F04E3294CD95FC9B948BA547F3F7C862E00D96268BFDD21B50AB9DFB66CC5D"), 
780            hex!("67FA8406061ED49C9575AC62286C347A75E8F52393CAFDDB364A659A5A251330F646780F54B620CFEE9ABE8C2CD594D1540CA30395C5D9AC760CB974FD870572"), 
781            SymmetricKey(hex!("ECC1364E68A666A16DB6EA3EA3C5E0FF2D35DF7FEBC300F1828B1E679302BA62")), 
782            SymmetricKey(hex!("2729F34F8D21EEEC33AED8DCA5BBEB28268775A0553D61627FFFC2859BF1D3AE"))
783        ),
784        (
785            SymmetricKey(hex!("98825A96363EE91194E72877E424FCF354B751ABBE43066B9DE5AB6DE019714B")), 
786            hex!("C38558CEB68065163BC1901A531717102E9F7DA23491F0BC708FA087B18EBF4690359ED1B502F1ECDA24363274E8FB7E7D2C73D530FDCA58380B10AB53A5C74F"), 
787            hex!("3FF4C59967E990A12CCB0DACB2DE16A2417375457FA8FA37428ED1915BDAE785B0A195FFD330E063305D4B1F6EA52DED5EBB7ABD04A400C45F7EC37596EAD432"), 
788            hex!("EA2B2BA85432DCC2AAB84D017D7783DA1E99C171345FF852657EE7878125C63A97AFFAA71A7B4B5AA0441F9DA719687EAB95C03698660533AB8A4305CF8FE985"), 
789            SymmetricKey(hex!("700C011046CA0481CEC14B55387B536B2D901D3FDE4D2DC1BE4A375E8F3C6EAC")), 
790            SymmetricKey(hex!("74555D7AD903304D604669B6311C1A59DDC0F9EC35ED26A7A6EF78491B114DC9"))
791        ),
792        (
793            SymmetricKey(hex!("8628408EAAF2B88CDD55FC6529A5BB0E9667324A4F724A5591251A57E7D54936")), 
794            hex!("29B2C67D5A513D8A71A39119342231FA53BB407F89C44362F6934B0C640E90F8155827F2D6E690F12ECBE44A6CF2591ABA8B0FFD0DD89EA2C029F2A1934C4B61"), 
795            hex!("8476E1D29EB01FCE2DE6185B690BC422880A2BA5B45EE9B058A68B01F802A813D6AAEE7F85C01993482D81993901B5AEDC189AA5EB8FB1592BA14153C935C161"), 
796            hex!("0B54B49533F3B9F89DADB340DCE04B36BA4F97B035C7F1682A062343717DF5314BA37440A4F63C4E110D8E4AC7DA13C38B9832D2A772E1644AA260200FD9E937"), 
797            SymmetricKey(hex!("195F0471A8CA586906EC9C238A926E0E9FF89AD86A8C651D0421868457E5070E")), 
798            SymmetricKey(hex!("FB335CB495AFDEF0E3B5957E42C39EC53D183177376EA27974005E6D6478398B"))
799        ),
800        (
801            SymmetricKey(hex!("5E3CA119A8A042E8CA5E5EA162BD51739B555DE26B51855F05C0DE4DF55024FB")), 
802            hex!("3466B1B3619593D0B407A2088A3F96BA9A1A23203D029919D8D3AD53296968B85FCB5D2BC73D85C1FEB20C340F1B5FD51CF51099F1E1ABAAC3383C81E7633FE6"), 
803            hex!("94CA634F270E76C49A56C9E737F7D01419450D9EEB398BC3CCFC52781C5456082E573232A01C1C80C04727A93A23D47E6D2522ADA5BE53697CBD2F29EDFF9B88"), 
804            hex!("AB692243A507A0606B5F257BC3201EBE5964FCE52C5EC4B860944DC02E9348802D001D5F7E2CBE48DA2E8D5E75FEF184000C2155A45EACDA8913AFC6EC2139B6"), 
805            SymmetricKey(hex!("8ECB6605E812672F9049F0678D4106152E208BDA35DDBCCB1BE2FB2C7DC457B1")), 
806            SymmetricKey(hex!("2C91D48E7CDCC192FEF9E582A0356503D8B0574BCAE15F56DE09459F6E901599"))
807        ),
808        (
809            SymmetricKey(hex!("F9AED0A2C62D6868114490D16482A154EB7A1B20C0CC8ED30D52BB3DE4FA489B")), 
810            hex!("FBC0D82AEEC9A02A567E195798241913860C26E34A3AD541840800D009CA92B841E87758B9018CE9B47244228ED900F7A1510F5FA1CC2B6F8BBD6A48028BC3D6"), 
811            hex!("7C7EC8A3BE8EED3C7BE0AC5EB6AC3B1AEFD85DEC369BE0524402CB61A94BE9208255847EEAA98F44BE358832F62AD0718A87F4060E5E6044D4BEAFA88DBE67A8"), 
812            hex!("CE17C64CFB214C45D323BB83259D83016D81B9AB436C2A26E48EF199719DFCFAFE38660306C2B14CD7435DBD9112B2E0F9A10130830AD6C2212E7C60CBDBFDEE"), 
813            SymmetricKey(hex!("733868886319C986D13AD1FEE05F54751EC5C8E8DBBDC30ED84E0A39C3ED107C")), 
814            SymmetricKey(hex!("A8E27921FD3A372AF337E646001B5953A9B869F9A2E6E370615920406581FAA0"))
815        ),
816        (
817            SymmetricKey(hex!("5476D58DF107805427CB5C4F7A3B2D0D7184C2B08F0903EFBDF4289546A93B65")), 
818            hex!("36E796B7F92A738CE84F346694132C187D1CCD35BDB44FC4EB63BC2B40443083AF9DBBF72E721A06819DE464895C9570ABDE922B7710AEF266C258484C9C67D3"), 
819            hex!("EBD60127F2DAB2FB1C99A4FF75E82E6DE97837E4BA68B2B6EBC8F710B2C448CDBFBB79DB7E0F40502836F97168B47B400D1BF166982FB57CBA5EBDAEEA36AB80"), 
820            hex!("1EB1D1DE5DAD5DB4D97A272FE8D252AF4D4FF9F2B62BE2991966359B25E5E184A538ACF6EFDB8210A79432986C2679BAC7629041CFF68ECDD198CE05C41C26D6"), 
821            SymmetricKey(hex!("87B782BE12D27200F64704860FAD745ECB9B3C26F163833691CCDCEE42679162")), 
822            SymmetricKey(hex!("C37666B9C23C4D82CC632D156ACD19C37B124A9040C15F73157C18E4B1F15DA1"))
823        ),
824        (
825            SymmetricKey(hex!("1061A100E832B272CBFCD7B6E2EBC76AFA5DD5C02FCC726EAF742496DE388CFF")), 
826            hex!("C2C6CD35CEF0CFC2C5AC3BB92915AA964B8D74B738A799400438EA0FBF24ECCA422411447E8118EED96236EE9873FAC682996E7FE1B12CF226EE886563AE67B3"), 
827            hex!("B8725ECDA754710F8CF6774E76B28C584A307ACC31036A26ED8BC296FFA87882749ABFC74D048E572CBDEF327F21EB96B43CC240C9AD65C7361CEC5079DFB0D2"), 
828            hex!("68B3EE2A48CB231D46FE2CB5664F13D4B4AF0269581E6E1064FC90A6EBD695AEA9D5A652C24BA58A2E78A95A4D743B70A3D8459724CA2D64DA28915C24614225"), 
829            SymmetricKey(hex!("4862F235EB4FEED6EC8CEF9D149A9CAD57373FCB817AA498C055223B36020D2D")), 
830            SymmetricKey(hex!("8DDEE6A05669559D5EEC9B385187922272C5186712F4DEE6ED2701CF69823360"))
831        ),
832        (
833            SymmetricKey(hex!("F2790E7FBDA540D47AF42F184EACEA5BBB4DC4F9882DE48A82990C3B26FFB779")), 
834            hex!("206ADDE68BDD19BE87ECD06EF601EEDD9E64A9B9701A506649AEAD88A9130A85B74120E15492FB7FF33D1760C448F44DD03ABEE3DE562582A0AB245797E5CCFE"), 
835            hex!("5B7EBBC69304F8C021EF6E3BAFC7DA03384E3D5B698B2729FD46E68F8E7272A25820104E996CB47AB803F0D29DB3F4F2A3A5501DB98144D058437FC061117F93"), 
836            hex!("1CDB634D09A158112461FF79ED79D7474189FCA90CB347BAAE1D0F7E97E4BFF5B7D5EE025A0D5DD214C3774CEEDA75E626CB787DB42601B082C9BBD7EB1CED69"), 
837            SymmetricKey(hex!("48649FC12281CB1A2D44D9EF3BBD00B44886DAC60A4BB9052F8D5251C4C3E29D")), 
838            SymmetricKey(hex!("456E268BA37FCEA40250D504FC2BB2F9C58CD94F3993D363AE9E0B03A6371706"))
839        ),
840        (
841            SymmetricKey(hex!("62FBB03B59F8B059FABF4CA165D493D5CA9F3A2397A0F989577D30B8CA0B6202")), 
842            hex!("F5DB70F4A41AF3118EDDD9370B5CDD7B8A063192AE1F0E12378F7946D805D54E6E1C865A2F85B6214BB54FA30DEA291225C2F52F86AC8C742F61CF4E6B153951"), 
843            hex!("71775164C3D70D9DF128F1B38BD3B6D53FE1F40EC277AC11D05D227C0E7D3389C34D84937AC7D6BF01A7122219756254E1D6CCB996487B01B0047AB3000ACFC6"), 
844            hex!("CEC699D545F57F4A447F0D8B402D32A4F72269244E3B9A05E7067932B3365720218123E1661443D8454799E4FE26AD76D18A9929C5CF63F59373982A4D1D853A"), 
845            SymmetricKey(hex!("9C935A745728ED8FA999EB52EE5C642218C29A7B89505B0BCC8DE3F0805FD7DE")), 
846            SymmetricKey(hex!("45E35694EED05E2D405AE3C53A0FB8DE4C17DDD1CA0384E1B8891691C921AF10"))
847        ),
848        (
849            SymmetricKey(hex!("EDD2CBE0F6600D2BD24E3DE742F4D5BFA2E12752EE4755EA54F4EB722A3A680D")), 
850            hex!("889A2FB7606690F67F24CC9471F8CC170461AE804F56D593D019819257FEB473EE9EF1A8E41535A9222A1BECE4A265157391B083811CB22230B8ABD51932631D"), 
851            hex!("3B80A9C4152DEB0E5839680F6779389FCDC2B87DB279F02DA153D1586527C6F1323890F25CEC0E6FFF571F9FBCF2FB97D8147C8922A9C6CBD59C85F365BC8888"), 
852            hex!("B92A0C30721DDFF3BA7CF2CE16212E5ABC0F47FEA930DCDA7FFD09B7F92D37245BC67E1DEA693DBF716375C79F2C592E85CC343F301F2921DB34824333BA4084"), 
853            SymmetricKey(hex!("26B31776AEE6E241BC3A904E9A6CE722B0C54B192F8BBCA1DF6A2FEB1536175E")), 
854            SymmetricKey(hex!("47690A25891F3B96F5F5A9160776DF84A2406DE32A98F11B98B9475F365AEEB0"))
855        ),
856        (
857            SymmetricKey(hex!("C5B4F5AEA501B30DCE71AF3AF29D7C46A2ADF20D339B0E772304708FDA129BF7")), 
858            hex!("499BA1825B91F32DC0AB55AEA17865D069A712F046C182AE1BEB47DDE89F71545E6B341A198958E0FCB79EE2B025FF5F91182E548DD2694786F430830C928ADC"), 
859            hex!("1D4389F6BDB20EE777F4E2E8182EE749B6325BCA42B3764BAE9241D929C54BA1C6DD375F7C18F02CED9A7AF145C5CD85D8F2B6D132B92CDDE08BCB1AD57289AD"), 
860            hex!("3994F5715D3B44EE5EF58B9499236D57DCA9057340CADC1EEDF68847DBB488167EEDE5EFBC99E0BB8BA2BB5DE7B0214C0A15AC1EE1CAB717AB47BC19B9D7DF18"), 
861            SymmetricKey(hex!("D726E36DCC8CF5E4CD1DEEEC85D92C11095CA7BC8A84957DA21071888D72B02D")), 
862            SymmetricKey(hex!("B785AB54F3524F64B92189C1269ACBBFD6142668716979C4104C14E5D76D7EA4"))
863        ),
864        (
865            SymmetricKey(hex!("3DBF3C21C88563067DEAF0AEF8FE6C128D06830A9F5C5026726B95F6237D1E91")), 
866            hex!("46DED311044C831CFF22A0A20994ED4FF69D479A97EC2561A0F56D567E8E67730B5F965BCAA9AB2C1F244D724B8595E1BA10AA33FA1113FF155CAE8266FF6660"), 
867            hex!("2166E3ADC39363E7B1CC370A62E129E1AF023D3D8F3CB982B8436EAF28604D19C3884A43704C35D5CC9664DFE7EA5462936EC7ED2FB343EDF0DC21674840BB5F"), 
868            hex!("4FBD4381A5CA12504A3C73D1E622D518851EBBFF48E21BAE2B50E6F6FD60C6C1C6DBC40F087070554C6BF5DD612393008AB4D1525BFA685E5A3A3F0AB0B782ED"), 
869            SymmetricKey(hex!("E6080B8B02C39D665F6148C06BE501759C58BD46BC8F830AA19CF1385E4FBA27")), 
870            SymmetricKey(hex!("5F87F0949E6348DDD35C6621A253B1EDA4E5DE87CC85220DF38AED9178E7CF02"))
871        ),
872        (
873            SymmetricKey(hex!("50AED6D0960F9013B58A37AFCA49A8AF094312047FDE7498733957ED8140B96A")), 
874            hex!("B6918B421F44B629AA8EAD9C8D31A0314F75C18ADB625064EE8815FDC2A0B604E7A5F9FFC516441018DD758784FE7E2A0C48FEF62FDB50C449AE9AA47A995BC1"), 
875            hex!("738E1A4881F5EE022E42A41981775687D5510D854CF940E58435F6E7E349D9FD13C3B2AB9EF99014DEF44653C8F07331A09B945697FB5E57A67D27E4EC41C32C"), 
876            hex!("1F70A2453C7E4BC961AB57FC910671104A094A498B2B827E3695BBDCB76461BC16E7412BCE06F6B0B0BF0A878A27B1261452D69034AC0119C2269A671C9B6BDF"), 
877            SymmetricKey(hex!("12864AA0913865829F8EC2DA9ABAC54D638F6A923A4F5B91B38782594486F736")), 
878            SymmetricKey(hex!("9B2256F60DD687D26739F0DC41EB809B9A063260CE107C53ED11F0C8CEF96AC8"))
879        ),
880    ];
881}
882
883// TODO check slice sizes when hashing
884// TODO ephemeral/static secret keys