hash.rs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. //! Functionality for hash functions.
  2. use crate::fixed_key_aes::FixedKeyAes;
  3. use bincode;
  4. use core::fmt::Debug;
  5. use core::ops::Range;
  6. use funty::Integral;
  7. use rand::{thread_rng, Rng, SeedableRng};
  8. use rand_chacha::ChaCha12Rng;
  9. use std::marker::PhantomData;
  10. /// Defines required properties of hash function values.
  11. pub trait HashFunctionValue: Integral + TryInto<usize>
  12. where
  13. <Self as TryInto<usize>>::Error: Debug,
  14. {
  15. }
  16. impl HashFunctionValue for u16 {}
  17. impl HashFunctionValue for u32 {}
  18. impl HashFunctionValue for u64 {}
  19. /// Trait for hash functions `[u64] -> {0, ..., range_size}`.
  20. pub trait HashFunction<Value: HashFunctionValue>
  21. where
  22. <Value as TryInto<usize>>::Error: Debug,
  23. {
  24. /// Description type that can be used to pass a small description of a hash function to another
  25. /// party.
  26. type Description: Copy + Debug + PartialEq + Eq;
  27. /// Sample a random hash function.
  28. fn sample(range_size: usize) -> Self;
  29. /// Sample a hash function using a given seed.
  30. fn from_seed(range_size: usize, seed: [u8; 32]) -> Self;
  31. /// Create new hash function instance from a description.
  32. fn from_description(description: Self::Description) -> Self;
  33. /// Convert this instance into an equivalent description.
  34. fn to_description(&self) -> Self::Description;
  35. /// Return the number of elements n in the range [0, n).
  36. fn get_range_size(&self) -> usize;
  37. /// Hash a single item.
  38. fn hash_single(&self, item: u64) -> Value;
  39. /// Hash a slice of items.
  40. fn hash_slice(&self, items: &[u64]) -> Vec<Value> {
  41. items.iter().map(|x| self.hash_single(*x)).collect()
  42. }
  43. /// Hash a range [a,b) of items.
  44. fn hash_range(&self, items: Range<u64>) -> Vec<Value> {
  45. items.map(|x| self.hash_single(x)).collect()
  46. }
  47. /// Convert a hash value into a usize. Useful when hashes are used as indices.
  48. /// Might panic if Value is not convertible to usize.
  49. #[inline(always)]
  50. fn hash_value_as_usize(value: Value) -> usize
  51. where
  52. <Value as TryInto<usize>>::Error: Debug,
  53. {
  54. <Value as TryInto<usize>>::try_into(value).unwrap()
  55. }
  56. }
  57. /// Fixed-key AES hashing using a circular correlation robust hash function.
  58. #[derive(Clone, Debug)]
  59. pub struct AesHashFunction<Value> {
  60. description: AesHashFunctionDescription,
  61. /// FixedKeyAes object including expanded key.
  62. aes: FixedKeyAes,
  63. _phantom: PhantomData<Value>,
  64. }
  65. /// Description type for [`AesHashFunction`].
  66. #[derive(Clone, Copy, Debug, PartialEq, Eq, bincode::Encode, bincode::Decode)]
  67. pub struct AesHashFunctionDescription {
  68. /// Size of the range.
  69. range_size: usize,
  70. /// Raw AES key.
  71. key: [u8; 16],
  72. }
  73. impl<Value: HashFunctionValue> HashFunction<Value> for AesHashFunction<Value>
  74. where
  75. <Value as TryInto<usize>>::Error: Debug,
  76. <Value as TryFrom<u64>>::Error: Debug,
  77. {
  78. type Description = AesHashFunctionDescription;
  79. fn get_range_size(&self) -> usize {
  80. self.description.range_size
  81. }
  82. fn from_seed(range_size: usize, seed: [u8; 32]) -> Self {
  83. assert!(range_size < (1 << 24));
  84. let mut rng = ChaCha12Rng::from_seed(seed);
  85. let key = rng.gen();
  86. Self::from_description(AesHashFunctionDescription { range_size, key })
  87. }
  88. fn sample(range_size: usize) -> Self {
  89. assert!(range_size < (1 << 24));
  90. let key: [u8; 16] = thread_rng().gen();
  91. Self::from_description(AesHashFunctionDescription { range_size, key })
  92. }
  93. fn from_description(description: Self::Description) -> Self {
  94. let aes = FixedKeyAes::new(description.key);
  95. Self {
  96. description,
  97. aes,
  98. _phantom: PhantomData,
  99. }
  100. }
  101. fn to_description(&self) -> Self::Description {
  102. self.description
  103. }
  104. fn hash_single(&self, item: u64) -> Value {
  105. let h = self.aes.hash_ccr(item as u128);
  106. (h as u64 % self.description.range_size as u64)
  107. .try_into()
  108. .unwrap()
  109. }
  110. }
  111. #[cfg(test)]
  112. mod tests {
  113. use super::*;
  114. fn test_hash_function<Value: HashFunctionValue, H: HashFunction<Value>>()
  115. where
  116. <Value as TryInto<usize>>::Error: Debug,
  117. {
  118. let range_size = 42;
  119. let h = H::sample(range_size);
  120. let h2 = H::from_description(h.to_description());
  121. assert_eq!(range_size, h.get_range_size());
  122. assert_eq!(h.to_description(), h2.to_description());
  123. for _ in 0..100 {
  124. let x: u64 = thread_rng().gen();
  125. let hx = h.hash_single(x);
  126. assert!(<Value as TryInto<usize>>::try_into(hx).unwrap() < range_size);
  127. assert_eq!(hx, h2.hash_single(x));
  128. }
  129. let a = 1337;
  130. let b = 1427;
  131. let vec: Vec<u64> = (a..b).collect();
  132. let hashes_range = h.hash_range(a..b);
  133. let hashes_slice = h.hash_slice(vec.as_slice());
  134. for (i, x) in (a..b).enumerate() {
  135. assert_eq!(hashes_range[i], h.hash_single(x));
  136. }
  137. assert_eq!(hashes_range, hashes_slice);
  138. }
  139. #[test]
  140. fn test_aes_hash_function() {
  141. test_hash_function::<u32, AesHashFunction<u32>>();
  142. test_hash_function::<u64, AesHashFunction<u64>>();
  143. }
  144. }