lightning/util/
hash_tables.rs

1//! Generally LDK uses `hashbrown`'s `HashMap`s with the `std` `SipHasher` and uses `getrandom` to
2//! opportunistically randomize it, if randomization is available.
3//!
4//! This module simply re-exports the `HashMap` used in LDK for public consumption.
5
6pub use hashbrown::hash_map;
7
8mod hashbrown_tables {
9	#[cfg(feature = "std")]
10	mod hasher {
11		pub use std::collections::hash_map::RandomState;
12	}
13	#[cfg(not(feature = "std"))]
14	mod hasher {
15		#![allow(deprecated)] // hash::SipHasher was deprecated in favor of something only in std.
16		use core::hash::{BuildHasher, SipHasher};
17
18		#[derive(Clone, Copy)]
19		/// A simple implementation of [`BuildHasher`] that uses `getrandom` to opportunistically
20		/// randomize, if the platform supports it.
21		pub struct RandomState {
22			k0: u64,
23			k1: u64,
24		}
25
26		impl RandomState {
27			/// Constructs a new [`RandomState`] which may or may not be random, depending on the
28			/// target platform.
29			pub fn new() -> RandomState {
30				let (k0, k1);
31				#[cfg(not(fuzzing))]
32				{
33					let mut keys = [0; 16];
34					possiblyrandom::getpossiblyrandom(&mut keys);
35
36					let mut k0_bytes = [0; 8];
37					let mut k1_bytes = [0; 8];
38					k0_bytes.copy_from_slice(&keys[..8]);
39					k1_bytes.copy_from_slice(&keys[8..]);
40					k0 = u64::from_le_bytes(k0_bytes);
41					k1 = u64::from_le_bytes(k1_bytes);
42				}
43				#[cfg(fuzzing)]
44				{
45					k0 = 0;
46					k1 = 0;
47				}
48				RandomState { k0, k1 }
49			}
50		}
51
52		impl Default for RandomState {
53			fn default() -> RandomState {
54				RandomState::new()
55			}
56		}
57
58		impl BuildHasher for RandomState {
59			type Hasher = SipHasher;
60			fn build_hasher(&self) -> SipHasher {
61				SipHasher::new_with_keys(self.k0, self.k1)
62			}
63		}
64	}
65
66	pub use hasher::*;
67
68	/// The HashMap type used in LDK.
69	pub type HashMap<K, V> = hashbrown::HashMap<K, V, RandomState>;
70	/// The HashSet type used in LDK.
71	pub type HashSet<K> = hashbrown::HashSet<K, RandomState>;
72
73	pub(crate) type OccupiedHashMapEntry<'a, K, V> =
74		hashbrown::hash_map::OccupiedEntry<'a, K, V, RandomState>;
75	pub(crate) type VacantHashMapEntry<'a, K, V> =
76		hashbrown::hash_map::VacantEntry<'a, K, V, RandomState>;
77
78	/// Builds a new [`HashMap`].
79	pub fn new_hash_map<K, V>() -> HashMap<K, V> {
80		HashMap::with_hasher(RandomState::new())
81	}
82	/// Builds a new [`HashMap`] with the given capacity.
83	pub fn hash_map_with_capacity<K, V>(cap: usize) -> HashMap<K, V> {
84		HashMap::with_capacity_and_hasher(cap, RandomState::new())
85	}
86	pub(crate) fn hash_map_from_iter<
87		K: core::hash::Hash + Eq,
88		V,
89		I: IntoIterator<Item = (K, V)>,
90	>(
91		iter: I,
92	) -> HashMap<K, V> {
93		let iter = iter.into_iter();
94		let min_size = iter.size_hint().0;
95		let mut res = HashMap::with_capacity_and_hasher(min_size, RandomState::new());
96		res.extend(iter);
97		res
98	}
99
100	/// Builds a new [`HashSet`].
101	pub fn new_hash_set<K>() -> HashSet<K> {
102		HashSet::with_hasher(RandomState::new())
103	}
104	/// Builds a new [`HashSet`] with the given capacity.
105	pub(crate) fn hash_set_with_capacity<K>(cap: usize) -> HashSet<K> {
106		HashSet::with_capacity_and_hasher(cap, RandomState::new())
107	}
108	pub(crate) fn hash_set_from_iter<K: core::hash::Hash + Eq, I: IntoIterator<Item = K>>(
109		iter: I,
110	) -> HashSet<K> {
111		let iter = iter.into_iter();
112		let min_size = iter.size_hint().0;
113		let mut res = HashSet::with_capacity_and_hasher(min_size, RandomState::new());
114		res.extend(iter);
115		res
116	}
117}
118
119pub use hashbrown_tables::*;