Skip to main content

hopr_crypto_sphinx/
derivation.rs

1use hopr_types::crypto::prelude::*;
2
3// Module-specific constants
4const HASH_KEY_PACKET_TAG: &str = "HASH_KEY_PACKET_TAG";
5
6pub(crate) fn create_kdf_instance<S: AsRef<[u8]>>(
7    secret: &S,
8    context: &str,
9    salt: Option<&[u8]>,
10) -> hopr_types::crypto::errors::Result<Blake3Output> {
11    let key_material = secret.as_ref();
12    if key_material.len() < 16 {
13        return Err(CryptoError::InvalidInputValue("secret must have at least 128-bits"));
14    }
15
16    if let Some(salt) = salt {
17        Ok(Blake3::new_derive_key(context)
18            .update_reader(salt)
19            .map_err(|_| CryptoError::InvalidInputValue("salt"))?
20            .update_reader(key_material)
21            .map_err(|_| CryptoError::InvalidInputValue("key"))?
22            .finalize_xof())
23    } else {
24        Ok(Blake3::new_derive_key(context)
25            .update_reader(key_material)
26            .map_err(|_| CryptoError::InvalidInputValue("key"))?
27            .finalize_xof())
28    }
29}
30
31/// Derives the packet tag used during packet construction by expanding the given secret.
32pub fn derive_packet_tag(secret: &SecretKey) -> hopr_types::crypto::errors::Result<PacketTag> {
33    let mut packet_tag: PacketTag = [0u8; PACKET_TAG_LENGTH];
34
35    let mut output = create_kdf_instance(secret, HASH_KEY_PACKET_TAG, None)?;
36    output.fill(&mut packet_tag);
37    Ok(packet_tag)
38}
39
40/// Internal convenience function to generate key and IV from the given secret,
41/// that is cryptographically strong.
42///
43/// The `secret` must be at least 16 bytes long.
44/// The function internally uses Blake2s256 based HKDF (see RFC 5869).
45///
46/// For `extract_with_salt` is given, the HKDF uses `Extract` with the given salt first
47/// and then calls `Expand` to derive the key and IV.
48///
49/// Otherwise, only `Expand` is used to derive key and IV using the given `info`, but
50/// the secret size must be exactly 32 bytes.
51pub(crate) fn generate_key<T: crypto_traits::KeyInit, S: AsRef<[u8]>>(
52    secret: &S,
53    context: &str,
54    with_salt: Option<&[u8]>,
55) -> hopr_types::crypto::errors::Result<T> {
56    let mut out = crypto_traits::Key::<T>::default();
57
58    let mut output = create_kdf_instance(secret, context, with_salt)?;
59    output.fill(&mut out);
60
61    Ok(T::new(&out))
62}
63
64/// Internal convenience function to generate key and IV from the given secret,
65/// that is cryptographically strong.
66///
67/// See [`generate_key`] for details.
68pub(crate) fn generate_key_iv<T: crypto_traits::KeyIvInit, S: AsRef<[u8]>>(
69    secret: &S,
70    context: &str,
71    with_salt: Option<&[u8]>,
72) -> hopr_types::crypto::errors::Result<T> {
73    let mut output = create_kdf_instance(secret, context, with_salt)?;
74
75    let mut key = crypto_traits::Key::<T>::default();
76    let mut iv = crypto_traits::Iv::<T>::default();
77
78    let mut out = vec![0u8; key.len() + iv.len()];
79    output.fill(&mut out);
80
81    let (v_iv, v_key) = out.split_at(iv.len());
82    iv.copy_from_slice(v_iv);
83    key.copy_from_slice(v_key);
84
85    Ok(T::new(&key, &iv))
86}