1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
pub use tiny_keccak::{Hasher, Shake};

/// Key Derivation Function (KDF).
///
/// Derives the given inputs to the desired length using SHAKE128, which should
/// then be imported where this macro is used.
///
/// # Security
///
/// The input length needs to be at least 256 bits to give 128 bits of security.
///
/// [source](https://en.wikipedia.org/wiki/SHA-3#Instances)
///
/// For smaller inputs like passwords, the Argon2 algorithm should be used.
///
/// # Example
///
/// ```
/// #[macro_use]
/// use cosmian_crypto_core::kdf128;
///
/// const KEY_LENGTH: usize = 16;
///
/// const IKM: &str = "asdf34@!dsa@grq5e$2ASGy5";
///
/// // derive a 32-bytes key
/// let mut key = [0; KEY_LENGTH];
/// kdf128!(&mut key, IKM.as_bytes());
///
/// assert_eq!(KEY_LENGTH, key.len());
///
/// let mut key2 = [0; KEY_LENGTH];
/// kdf128!(&mut key2, IKM.as_bytes());
/// assert_eq!(key, key2);
/// ```
///
/// # Parameters
///
/// - `res`     : output to be updated in-place
/// - `bytes`   : KDF input
#[macro_export]
macro_rules! kdf128 {
    ($res: expr, $($bytes: expr),+) => {
        {
            let mut hasher = $crate::kdf::Shake::v128();
            $(
                <$crate::kdf::Shake as $crate::kdf::Hasher>::update(&mut hasher, $bytes);
            )*
            <$crate::kdf::Shake as $crate::kdf::Hasher>::finalize(hasher, $res);
        }
    };
}

/// Key Derivation Function (KDF).
///
/// Derives the given inputs to the desired length using SHAKE256, which should
/// then be imported where this macro is used.
///
/// # Security
///
/// The input length needs to be at least 512 bits to give 256 bits of security.
///
/// [source](https://en.wikipedia.org/wiki/SHA-3#Instances)
///
/// For smaller inputs like passwords, the Argon2 algorithm should be used.
///
/// # Example
///
/// ```
/// #[macro_use]
/// use cosmian_crypto_core::kdf256;
///
/// const KEY_LENGTH: usize = 32;
///
/// const ikm: &str = "asdf34@!dsa@grq5e$2ASGy5";
///
/// // derive a 32-bytes key
/// let mut key = [0; KEY_LENGTH];
/// kdf256!(&mut key, ikm.as_bytes());
///
/// assert_eq!(KEY_LENGTH, key.len());
///
/// let mut key2 = [0; KEY_LENGTH];
/// kdf256!(&mut key2, ikm.as_bytes());
/// assert_eq!(key, key2);
/// ```
///
/// # Parameters
///
/// - `res`     : output to be updated in-place
/// - `bytes`   : KDF input
#[macro_export]
macro_rules! kdf256 {
    ($res: expr, $($bytes: expr),+) => {
        {
            let mut hasher = $crate::kdf::Shake::v256();
            $(
                <$crate::kdf::Shake as $crate::kdf::Hasher>::update(&mut hasher, $bytes);
            )*
            <$crate::kdf::Shake as $crate::kdf::Hasher>::finalize(hasher, $res);
        }
    };
}