hash.rs 4.7 KB

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