[beast: 1/20] SFI: add randomhash.hh, randomhash.cc from Rapicorn



commit 6521240f8dce3adbef7b1aac87c0e787fa67fb93
Author: Tim Janik <timj gnu org>
Date:   Sun Sep 17 01:50:20 2017 +0200

    SFI: add randomhash.hh, randomhash.cc from Rapicorn
    
    Import is based on Rapicorn commit id:
        bf228016cba3f6d252ee2cc38e1ed32607f37bf0
    
    Signed-off-by: Tim Janik <timj gnu org>

 sfi/randomhash.cc |  687 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 sfi/randomhash.hh |  559 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1246 insertions(+), 0 deletions(-)
---
diff --git a/sfi/randomhash.cc b/sfi/randomhash.cc
new file mode 100644
index 0000000..5cffe16
--- /dev/null
+++ b/sfi/randomhash.cc
@@ -0,0 +1,687 @@
+// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
+// Author: 2014, Tim Janik, see http://testbit.org/keccak
+#include "randomhash.hh"
+#include "entropy.hh"
+
+namespace Bse {
+
+// == Lib::KeccakF1600 ==
+Lib::KeccakF1600::KeccakF1600()
+{
+  reset();
+}
+
+void
+Lib::KeccakF1600::reset ()
+{
+  memset4 ((uint32*) bytes, 0, sizeof (bytes) / 4);
+}
+
+static constexpr const uint8_t KECCAK_RHO_OFFSETS[25] = { 0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43,
+                                                          25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14 };
+static constexpr const uint64_t KECCAK_ROUND_CONSTANTS[255] = {
+  1, 32898, 0x800000000000808a, 0x8000000080008000, 32907, 0x80000001, 0x8000000080008081, 
0x8000000000008009, 138, 136, 0x80008009,
+  0x8000000a, 0x8000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, 0x8000000000008002, 
0x8000000000000080, 32778,
+  0x800000008000000a, 0x8000000080008081, 0x8000000000008080, 0x80000001, 0x8000000080008008, 
0x8000000080008082, 0x800000008000800a,
+  0x8000000000000003, 0x8000000080000009, 0x8000000000008082, 32777, 0x8000000000000080, 32899, 
0x8000000000000081, 1, 32779,
+  0x8000000080008001, 128, 0x8000000000008000, 0x8000000080008001, 9, 0x800000008000808b, 129, 
0x8000000000000082, 0x8000008b,
+  0x8000000080008009, 0x8000000080000000, 0x80000080, 0x80008003, 0x8000000080008082, 0x8000000080008083, 
0x8000000080000088, 32905,
+  32777, 0x8000000000000009, 0x80008008, 0x80008001, 0x800000000000008a, 0x800000000000000b, 137, 
0x80000002, 0x800000000000800b,
+  0x8000800b, 32907, 0x80000088, 0x800000000000800a, 0x80000089, 0x8000000000000001, 0x8000000000008088, 
0x8000000000000081, 136,
+  0x80008080, 129, 0x800000000000000b, 0, 137, 0x8000008b, 0x8000000080008080, 0x800000000000008b, 
0x8000000000008000,
+  0x8000000080008088, 0x80000082, 11, 0x800000000000000a, 32898, 0x8000000000008003, 0x800000000000808b, 
0x800000008000000b,
+  0x800000008000008a, 0x80000081, 0x80000081, 0x80000008, 131, 0x8000000080008003, 0x80008088, 
0x8000000080000088, 32768, 0x80008082,
+  0x80008089, 0x8000000080008083, 0x8000000080000001, 0x80008002, 0x8000000080000089, 130, 
0x8000000080000008, 0x8000000000000089,
+  0x8000000080000008, 0x8000000000000000, 0x8000000000000083, 0x80008080, 8, 0x8000000080000080, 
0x8000000080008080,
+  0x8000000000000002, 0x800000008000808b, 8, 0x8000000080000009, 0x800000000000800b, 0x80008082, 0x80008000, 
0x8000000000008008, 32897,
+  0x8000000080008089, 0x80008089, 0x800000008000800a, 0x800000000000008a, 0x8000000000000082, 0x80000002, 
0x8000000000008082, 32896,
+  0x800000008000000b, 0x8000000080000003, 10, 0x8000000000008001, 0x8000000080000083, 0x8000000000008083, 
139, 32778,
+  0x8000000080000083, 0x800000000000800a, 0x80000000, 0x800000008000008a, 0x80000008, 10, 
0x8000000000008088, 0x8000000000000008,
+  0x80000003, 0x8000000000000000, 0x800000000000000a, 32779, 0x8000000080008088, 0x8000000b, 0x80000080, 
0x8000808a,
+  0x8000000000008009, 3, 0x80000003, 0x8000000000000089, 0x8000000080000081, 0x800000008000008b, 0x80008003, 
0x800000008000800b,
+  0x8000000000008008, 32776, 0x8000000000008002, 0x8000000000000009, 0x80008081, 32906, 0x8000800a, 128, 
0x8000000000008089,
+  0x800000000000808a, 0x8000000080008089, 0x80008000, 0x8000000000008081, 0x8000800a, 9, 0x8000000080008002, 
0x8000000a, 0x80008002,
+  0x8000000080000000, 0x80000009, 32904, 2, 0x80008008, 0x80008088, 0x8000000080000001, 0x8000808b, 
0x8000000000000002,
+  0x8000000080008002, 0x80000083, 32905, 32896, 0x8000000080000082, 0x8000000000000088, 0x800000008000808a, 
32906, 0x80008083,
+  0x8000000b, 0x80000009, 32769, 0x80000089, 0x8000000000000088, 0x8000000080008003, 0x80008001, 
0x8000000000000003,
+  0x8000000080000080, 0x8000000080008009, 0x8000000080000089, 11, 0x8000000000000083, 0x80008009, 
0x80000083, 32768, 0x8000800b, 32770,
+  3, 0x8000008a, 0x8000000080000002, 32769, 0x80000000, 0x8000000080000003, 131, 0x800000008000808a, 32771, 
32776, 0x800000000000808b,
+  0x8000000080000082, 0x8000000000000001, 0x8000000000008001, 0x800000008000000a, 0x8000000080008008, 
0x800000008000800b,
+  0x8000000000008081, 0x80008083, 0x80000082, 130, 0x8000000080000081, 0x8000000080000002, 32904, 139, 
32899, 0x8000000000000008,
+  0x8000008a, 0x800000008000008b, 0x8000808a, 0x8000000000008080, 0x80000088, 0x8000000000008083, 2, 
0x80008081, 32771, 32897,
+  0x8000000080008000, 32770, 138,
+};
+
+/// Rotate left for uint64_t.
+static inline constexpr uint64_t
+bit_rotate64 (uint64_t bits, unsigned int offset)
+{
+  // bitwise rotate-left pattern recognized by gcc & clang iff 64==sizeof (bits)
+  return (bits << offset) | (bits >> (64 - offset));
+}
+
+/// The Keccak-f[1600] permutation for up to 254 rounds, see Keccak11 @cite Keccak11 .
+void
+Lib::KeccakF1600::permute (const uint32_t n_rounds)
+{
+  BSE_ASSERT_RETURN (n_rounds < 255); // adjust the KECCAK_ROUND_CONSTANTS access to lift this assertion
+  // Keccak forward rounds
+  for (size_t round_index = 0; round_index < n_rounds; round_index++)
+    {
+      // theta
+      uint64_t C[5];
+      for (size_t x = 0; x < 5; x++)
+        {
+          C[x] = A[x];
+          for (size_t y = 1; y < 5; y++)
+            C[x] ^= A[x + 5 * y];
+        }
+      for (size_t x = 0; x < 5; x++)
+        {
+          const uint64_t D = C[(5 + x - 1) % 5] ^ bit_rotate64 (C[(x + 1) % 5], 1);
+          for (size_t y = 0; y < 5; y++)
+            A[x + 5 * y] ^= D;
+        }
+      // rho
+      for (size_t y = 0; y < 25; y += 5)
+        {
+          uint64_t *const plane = &A[y];
+          for (size_t x = 0; x < 5; x++)
+            plane[x] = bit_rotate64 (plane[x], KECCAK_RHO_OFFSETS[x + y]);
+        }
+      // pi
+      const uint64_t a[25] = { A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[8], A[9], A[10], A[11], 
A[12],
+                               A[13], A[14], A[15], A[16], A[17], A[18], A[19], A[20], A[21], A[22], A[23], 
A[24] };
+      for (size_t y = 0; y < 5; y++)
+        for (size_t x = 0; x < 5; x++)
+          {
+            const size_t X = (0 * x + 1 * y) % 5;
+            const size_t Y = (2 * x + 3 * y) % 5;
+            A[X + 5 * Y] = a[x + 5 * y];
+          }
+      // chi
+      for (size_t y = 0; y < 25; y += 5)
+        {
+          uint64_t *const plane = &A[y];
+          for (size_t x = 0; x < 5; x++)
+            C[x] = plane[x] ^ (~plane[(x + 1) % 5] & plane[(x + 2) % 5]);
+          for (size_t x = 0; x < 5; x++)
+            plane[x] = C[x];
+        }
+      // iota
+      A[0 + 5 * 0] ^= KECCAK_ROUND_CONSTANTS[round_index]; // round_index needs %255 for n_rounds>=255
+    }
+}
+
+// == KeccakRng ==
+/// Keccak permutation for 1600 bits, see Keccak11 @cite Keccak11 .
+void
+KeccakRng::permute1600()
+{
+  state_.permute (n_rounds_);
+  opos_ = 0;    // fresh outputs available
+}
+
+/** Discard 2^256 bits of the current generator state.
+ * This makes it practically infeasible to guess previous generator states or
+ * deduce generated values from the past.
+ * Use this for forward security @cite Security03 of generated security tokens like session keys.
+ */
+void
+KeccakRng::forget()
+{
+  std::fill (&state_[0], &state_[256 / 64], 0);
+  permute1600();
+}
+
+/** Discard @a count consecutive random values.
+ * This function is slightly faster than calling operator()() exactly @a count times.
+ */
+void
+KeccakRng::discard (unsigned long long count)
+{
+  while (count)
+    {
+      if (opos_ >= n_nums())
+        permute1600();
+      const unsigned long long ull = std::min ((unsigned long long) n_nums() - opos_, count);
+      opos_ += ull;
+      count -= ull;
+    }
+}
+
+/** Incorporate @a seed_values into the current generator state.
+ * A block permutation to advance the generator state is carried out per n_nums() seed values.
+ * After calling this function, generating the next n_nums() random values will not need to
+ * block for a new permutation.
+ */
+void
+KeccakRng::xor_seed (const uint64_t *seeds, size_t n_seeds)
+{
+  // printerr ("xor_seed(%p): %s\n", this, String ((const char*) seeds, n_seeds * 8));
+  size_t i = 0;
+  while (n_seeds)
+    {
+      if (i > 0)        // not first seed block
+        permute1600();  // prepare for next seed block
+      const size_t count = std::min (n_nums(), n_seeds);
+      for (i = 0; i < count; i++)
+        state_[i] ^= seeds[i];
+      seeds += count;
+      n_seeds -= count;
+    }
+  if (i < 25)           // apply Simple padding: pad10*
+    state_[i] ^= 0x1;   // 1: payload boundary bit for Keccak Sponge compliant padding
+  permute1600();        // integrate seed
+}
+
+void
+KeccakRng::auto_seed()
+{
+  AutoSeeder seeder;
+  seed (seeder);
+}
+
+/// The destructor resets the generator state to avoid leaving memory trails.
+KeccakRng::~KeccakRng()
+{
+  // forget all state and leave no trails
+  std::fill (&state_[0], &state_[25], 0xaffeaffeaffeaffe);
+  forget();
+  opos_ = n_nums();
+}
+
+// == SHAKE_Base - primitive for SHA3 hashing ==
+template<size_t HASHBITS, uint8_t DOMAINBITS>
+class SHAKE_Base {
+  Lib::KeccakF1600      state_;
+  const size_t          rate_;
+  size_t                iopos_;
+  bool                  feeding_mode_;
+protected:
+  /// Add stream data up to block size into Keccak state via XOR.
+  size_t
+  xor_state (size_t offset, const uint8_t *input, size_t n_in)
+  {
+    BSE_ASSERT_RETURN (offset + n_in <= byte_rate(), 0);
+    size_t i;
+    for (i = offset; i < offset + n_in; i++)
+      state_.byte (i) ^= input[i - offset];
+    return i - offset;
+  }
+  /** Pad stream from offset to block boundary into Keccak state via XOR.
+   * The @a trail argument must contain the termination bit, optionally preceeded by
+   * additional (LSB) bits for domain separation. A permutation is carried out if the
+   * trailing padding bits do not fit into the remaining block length.
+   */
+  void
+  absorb_padding (size_t offset, uint8_t trail = 0x01)
+  {
+    BSE_ASSERT_RETURN (offset < byte_rate());   // offset is first byte following payload
+    BSE_ASSERT_RETURN (trail != 0x00);
+    // MultiRatePadding
+    state_.byte (offset) ^= trail;              // 1: payload boundary bit for MultiRatePadding (and 
SimplePadding)
+    // state_.bits[i..last] ^= 0x0;             // 0*: bitrate filler for MultiRatePadding (and 
SimplePadding)
+    const size_t lastbyte = byte_rate() - 1;    // last bitrate byte, may coincide with offset
+    if (offset == lastbyte && trail >= 0x80)
+      state_.permute (24);                      // prepare new block to append last bit
+    state_.byte (lastbyte) ^= 0x80;             // 1: last bitrate bit; required by MultiRatePadding
+  }
+  SHAKE_Base (size_t rate) :
+    rate_ (rate), iopos_ (0), feeding_mode_ (true)
+  {}
+public:
+  size_t
+  byte_rate() const
+  {
+    return rate_ / 8;
+  }
+  void
+  reset()
+  {
+    state_.reset();
+    iopos_ = 0;
+    feeding_mode_ = true;
+  }
+  void
+  update (const uint8_t *data, size_t length)
+  {
+    BSE_ASSERT_RETURN (feeding_mode_ == true);
+    while (length)
+      {
+        const size_t count = std::min (byte_rate() - iopos_, length);
+        xor_state (iopos_, data, count);
+        iopos_ += count;
+        data += count;
+        length -= count;
+        if (iopos_ >= byte_rate())
+          {
+            state_.permute (24);
+            iopos_ = 0;
+          }
+      }
+  }
+  /// Switch from absorbing into squeezing mode and return digest.
+  size_t
+  get_hash (uint8_t hashvalue[HASHBITS / 8])
+  {
+    if (feeding_mode_)
+      {
+        const uint8_t shake_delimiter = DOMAINBITS;
+        absorb_padding (iopos_, shake_delimiter);
+        feeding_mode_ = false;
+        state_.permute (24);
+        iopos_ = 0;
+      }
+    const size_t count = HASHBITS / 8;
+    for (size_t i = 0; i < count; i++)
+      hashvalue[i] = state_.byte (i);
+    return count;
+  }
+  /// Read out the current Keccak state and permute as needed.
+  void
+  squeeze_digest (uint8_t *output, size_t n_out)
+  {
+    BSE_ASSERT_RETURN (HASHBITS == 0);
+    get_hash (output);                  // absorb_padding and leave feeding_mode_
+    BSE_ASSERT_RETURN (feeding_mode_ == false);
+    while (n_out)
+      {
+        const size_t count = std::min (n_out, byte_rate() - iopos_);
+        for (size_t i = 0; i < count; i++)
+          output[i] = state_.byte (iopos_ + i);
+        iopos_ += count;
+        output += count;
+        n_out -= count;
+        if (iopos_ >= byte_rate())
+          {
+            state_.permute (24);
+            iopos_ = 0;
+          }
+      }
+  }
+};
+
+// == SHA3_224 ==
+struct SHA3_224::State : SHAKE_Base<224, 0x06> {
+  State() : SHAKE_Base (1152) {}
+};
+
+SHA3_224::SHA3_224 () :
+  state_ (new (&mem_) State())
+{
+  static_assert (sizeof (mem_) >= sizeof (*state_), "");
+}
+
+SHA3_224::~SHA3_224 ()
+{
+  state_->~State();
+}
+
+void
+SHA3_224::update (const uint8_t *data, size_t length)
+{
+  state_->update (data, length);
+}
+
+void
+SHA3_224::digest (uint8_t hashvalue[28])
+{
+  state_->get_hash (hashvalue);
+}
+
+void
+SHA3_224::reset ()
+{
+  state_->reset();
+}
+
+void
+sha3_224_hash (const void *data, size_t data_length, uint8_t hashvalue[28])
+{
+  SHA3_224 context;
+  context.update ((const uint8_t*) data, data_length);
+  context.digest (hashvalue);
+}
+
+// == SHA3_256 ==
+struct SHA3_256::State : SHAKE_Base<256, 0x06> {
+  State() : SHAKE_Base (1088) {}
+};
+
+SHA3_256::SHA3_256 () :
+  state_ (new (&mem_) State())
+{
+  static_assert (sizeof (mem_) >= sizeof (*state_), "");
+}
+
+SHA3_256::~SHA3_256 ()
+{
+  state_->~State();
+}
+
+void
+SHA3_256::update (const uint8_t *data, size_t length)
+{
+  state_->update (data, length);
+}
+
+void
+SHA3_256::digest (uint8_t hashvalue[32])
+{
+  state_->get_hash (hashvalue);
+}
+
+void
+SHA3_256::reset ()
+{
+  state_->reset();
+}
+
+void
+sha3_256_hash (const void *data, size_t data_length, uint8_t hashvalue[32])
+{
+  SHA3_256 context;
+  context.update ((const uint8_t*) data, data_length);
+  context.digest (hashvalue);
+}
+
+// == SHA3_384 ==
+struct SHA3_384::State : SHAKE_Base<384, 0x06> {
+  State() : SHAKE_Base (832) {}
+};
+
+SHA3_384::SHA3_384 () :
+  state_ (new (&mem_) State())
+{
+  static_assert (sizeof (mem_) >= sizeof (*state_), "");
+}
+
+SHA3_384::~SHA3_384 ()
+{
+  state_->~State();
+}
+
+void
+SHA3_384::update (const uint8_t *data, size_t length)
+{
+  state_->update (data, length);
+}
+
+void
+SHA3_384::digest (uint8_t hashvalue[48])
+{
+  state_->get_hash (hashvalue);
+}
+
+void
+SHA3_384::reset ()
+{
+  state_->reset();
+}
+
+void
+sha3_384_hash (const void *data, size_t data_length, uint8_t hashvalue[48])
+{
+  SHA3_384 context;
+  context.update ((const uint8_t*) data, data_length);
+  context.digest (hashvalue);
+}
+
+// == SHA3_512 ==
+struct SHA3_512::State : SHAKE_Base<512, 0x06> {
+  State() : SHAKE_Base (576) {}
+};
+
+SHA3_512::SHA3_512 () :
+  state_ (new (&mem_) State())
+{
+  static_assert (sizeof (mem_) >= sizeof (*state_), "");
+}
+
+SHA3_512::~SHA3_512 ()
+{
+  state_->~State();
+}
+
+void
+SHA3_512::update (const uint8_t *data, size_t length)
+{
+  state_->update (data, length);
+}
+
+void
+SHA3_512::digest (uint8_t hashvalue[64])
+{
+  state_->get_hash (hashvalue);
+}
+
+void
+SHA3_512::reset ()
+{
+  state_->reset();
+}
+
+void
+sha3_512_hash (const void *data, size_t data_length, uint8_t hashvalue[64])
+{
+  SHA3_512 context;
+  context.update ((const uint8_t*) data, data_length);
+  context.digest (hashvalue);
+}
+
+// == SHAKE128 ==
+struct SHAKE128::State : SHAKE_Base<0, 0x1f> {
+  State() : SHAKE_Base (1344) {}
+};
+
+SHAKE128::SHAKE128 () :
+  state_ (new (&mem_) State())
+{
+  static_assert (sizeof (mem_) >= sizeof (*state_), "");
+}
+
+SHAKE128::~SHAKE128 ()
+{
+  state_->~State();
+}
+
+void
+SHAKE128::update (const uint8_t *data, size_t length)
+{
+  state_->update (data, length);
+}
+
+void
+SHAKE128::squeeze_digest (uint8_t *hashvalues, size_t n)
+{
+  state_->squeeze_digest (hashvalues, n);
+}
+
+void
+SHAKE128::reset ()
+{
+  state_->reset();
+}
+
+void
+shake128_hash (const void *data, size_t data_length, uint8_t *hashvalues, size_t n)
+{
+  SHAKE128 context;
+  context.update ((const uint8_t*) data, data_length);
+  context.squeeze_digest (hashvalues, n);
+}
+
+// == SHAKE256 ==
+struct SHAKE256::State : SHAKE_Base<0, 0x1f> {
+  State() : SHAKE_Base (1088) {}
+};
+
+SHAKE256::SHAKE256 () :
+  state_ (new (&mem_) State())
+{
+  static_assert (sizeof (mem_) >= sizeof (*state_), "");
+}
+
+SHAKE256::~SHAKE256 ()
+{
+  state_->~State();
+}
+
+void
+SHAKE256::update (const uint8_t *data, size_t length)
+{
+  state_->update (data, length);
+}
+
+void
+SHAKE256::squeeze_digest (uint8_t *hashvalues, size_t n)
+{
+  state_->squeeze_digest (hashvalues, n);
+}
+
+void
+SHAKE256::reset ()
+{
+  state_->reset();
+}
+
+void
+shake256_hash (const void *data, size_t data_length, uint8_t *hashvalues, size_t n)
+{
+  SHAKE256 context;
+  context.update ((const uint8_t*) data, data_length);
+  context.squeeze_digest (hashvalues, n);
+}
+
+// == Pcg32Rng ==
+Pcg32Rng::Pcg32Rng () :
+  increment_ (0), accu_ (0)
+{
+  auto_seed();
+}
+
+Pcg32Rng::Pcg32Rng (uint64_t offset, uint64_t sequence) :
+  increment_ (0), accu_ (0)
+{
+  seed (offset, sequence);
+}
+
+void
+Pcg32Rng::auto_seed ()
+{
+  AutoSeeder seeder;
+  seed (seeder);
+}
+
+void
+Pcg32Rng::seed (uint64_t offset, uint64_t sequence)
+{
+  accu_ = sequence;
+  increment_ = (sequence << 1) | 1;    // force increment_ to be odd
+  accu_ += offset;
+  accu_ = A * accu_ + increment_;
+}
+
+// == Random Numbers ==
+static uint64_t
+global_random64()
+{
+  static KeccakRng *global_rng = NULL;
+  static std::mutex mtx;
+  std::unique_lock<std::mutex> lock (mtx);
+  if (UNLIKELY (!global_rng))
+    {
+      uint64 entropy[32];
+      collect_runtime_entropy (entropy, ARRAY_SIZE (entropy));
+      static std::aligned_storage<sizeof (KeccakRng), alignof (KeccakRng)>::type mem;
+      // 8 rounds provide good statistical shuffling, and
+      // 256 hidden bits make the generator state unguessable
+      global_rng = new (&mem) KeccakRng (256, 8);
+      global_rng->seed (entropy, ARRAY_SIZE (entropy));
+    }
+  return global_rng->random();
+}
+
+/** Generate a non-deterministic, uniformly distributed 64 bit pseudo-random number.
+ * This function generates pseudo-random numbers using the system state as entropy
+ * and class KeccakRng for the mixing. No seeding is required.
+ */
+uint64_t
+random_int64 ()
+{
+  return global_random64();
+}
+
+/** Generate uniformly distributed pseudo-random integer within range.
+ * This function generates a pseudo-random number like random_int64(),
+ * constrained to the range: @a begin <= number < @a end.
+ */
+int64_t
+random_irange (int64_t begin, int64_t end)
+{
+  return_unless (begin < end, begin);
+  const uint64_t range    = end - begin;
+  const uint64_t quotient = 0xffffffffffffffffULL / range;
+  const uint64_t bound    = quotient * range;
+  uint64_t r = global_random64();
+  while (BSE_UNLIKELY (r >= bound))        // repeats with <50% probability
+    r = global_random64();
+  return begin + r / quotient;
+}
+
+/** Generate uniformly distributed pseudo-random floating point number.
+ * This function generates a pseudo-random number like random_int64(),
+ * constrained to the range: 0.0 <= number < 1.0.
+ */
+double
+random_float ()
+{
+  double r01;
+  do
+    r01 = global_random64() * 5.42101086242752217003726400434970855712890625e-20; // 1.0 / 2^64
+  while (BSE_UNLIKELY (r01 >= 1.0));       // retry if arithmetic exceeds boundary
+  return r01;
+}
+
+/** Generate uniformly distributed pseudo-random floating point number within a range.
+ * This function generates a pseudo-random number like random_float(),
+ * constrained to the range: @a begin <= number < @a end.
+ */
+double
+random_frange (double begin, double end)
+{
+  return_unless (begin < end, begin + 0 * end); // catch and propagate NaNs
+  const double r01 = global_random64() * 5.42101086242752217003726400434970855712890625e-20; // 1.0 / 2^64
+  return end * r01 + (1.0 - r01) * begin;
+}
+
+/// Provide a unique 64 bit identifier that is not 0, see also random_int64().
+uint64_t
+random_nonce ()
+{
+  static uint64_t cached_nonce = 0;
+  if (BSE_UNLIKELY (cached_nonce == 0))
+    random_secret (&cached_nonce);
+  return cached_nonce;
+}
+
+/// Generate a secret non-zero nonce in secret_var, unless it has already been assigned.
+void
+random_secret (uint64_t *secret_var)
+{
+  static std::mutex mtx;
+  std::unique_lock<std::mutex> lock (mtx);
+  if (!*secret_var)
+    {
+      uint64_t d;
+      do
+        d = global_random64();
+      while (d == 0); // very unlikely
+      *secret_var = d;
+    }
+}
+
+uint64_t cached_hash_secret = 0;
+
+} // Bse
diff --git a/sfi/randomhash.hh b/sfi/randomhash.hh
new file mode 100644
index 0000000..0877f69
--- /dev/null
+++ b/sfi/randomhash.hh
@@ -0,0 +1,559 @@
+// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
+// Author: 2014, Tim Janik, see http://testbit.org/keccak
+#ifndef __BSE_RANDOMHASH_HH__
+#define __BSE_RANDOMHASH_HH__
+
+#include <sfi/bcore.hh>
+
+namespace Bse {
+
+/** Helper to provide memory for placement new
+ * AlignedPOD<SIZE> is aligned like max_align_t or like malloc()-ed memory and
+ * provides SIZE bytes. Idiomatic use is:
+ * \code{.cc}
+ *   static AlignedPOD<sizeof (std::string)> pod_mem;
+ *   std::string *str = new (&pod_mem) std::string();
+ * \endcode
+ */
+template<size_t SIZE>
+struct alignas (16) AlignedPOD {
+  typename std::aligned_storage<SIZE, 16>::type mem;
+  /* malloc() aligns to 2 * sizeof (size_t), i.e. 16 on 64bit, max_align_t is
+   * usually aligned to long double, i.e. 16, and most SIMD code also needs at
+   * least 16 byte alignment.
+   */
+};
+
+// == Random Numbers ==
+uint64_t        random_nonce    ();
+uint64_t        random_int64    ();
+int64_t         random_irange   (int64_t begin, int64_t end);
+double          random_float    ();
+double          random_frange   (double begin, double end);
+void            random_secret   (uint64_t *secret_var);
+
+
+// == Hashing ==
+/** SHA3_224 - 224 Bit digest generation.
+ * This class implements the SHA3 hash funtion to create 224 Bit digests, see FIPS 202 @cite Fips202 .
+ */
+struct SHA3_224 {
+  /*dtor*/ ~SHA3_224    ();
+  /*ctor*/  SHA3_224    ();         ///< Create context to calculate a 224 bit SHA3 hash digest.
+  void      reset       ();         ///< Reset state to feed and retrieve a new hash value.
+  void      update      (const uint8_t *data, size_t length);   ///< Feed data to be hashed.
+  void      digest      (uint8_t hashvalue[28]);                ///< Retrieve the resulting hash value.
+private:
+  AlignedPOD<232> mem_;
+  class     State;
+  State    *state_;
+};
+/// Calculate 224 bit SHA3 digest from @a data, see also class SHA3_224.
+void    sha3_224_hash   (const void *data, size_t data_length, uint8_t hashvalue[28]);
+
+/** SHA3_256 - 256 Bit digest generation.
+ * This class implements the SHA3 hash funtion to create 256 Bit digests, see FIPS 202 @cite Fips202 .
+ */
+struct SHA3_256 {
+  /*dtor*/ ~SHA3_256    ();
+  /*ctor*/  SHA3_256    ();         ///< Create context to calculate a 256 bit SHA3 hash digest.
+  void      reset       ();         ///< Reset state to feed and retrieve a new hash value.
+  void      update      (const uint8_t *data, size_t length);   ///< Feed data to be hashed.
+  void      digest      (uint8_t hashvalue[32]);                ///< Retrieve the resulting hash value.
+private:
+  AlignedPOD<232> mem_;
+  class     State;
+  State    *state_;
+};
+/// Calculate 256 bit SHA3 digest from @a data, see also class SHA3_256.
+void    sha3_256_hash   (const void *data, size_t data_length, uint8_t hashvalue[32]);
+
+/** SHA3_384 - 384 Bit digest generation.
+ * This class implements the SHA3 hash funtion to create 384 Bit digests, see FIPS 202 @cite Fips202 .
+ */
+struct SHA3_384 {
+  /*dtor*/ ~SHA3_384    ();
+  /*ctor*/  SHA3_384    ();         ///< Create context to calculate a 384 bit SHA3 hash digest.
+  void      reset       ();         ///< Reset state to feed and retrieve a new hash value.
+  void      update      (const uint8_t *data, size_t length);   ///< Feed data to be hashed.
+  void      digest      (uint8_t hashvalue[48]);                ///< Retrieve the resulting hash value.
+private:
+  AlignedPOD<232> mem_;
+  class     State;
+  State    *state_;
+};
+/// Calculate 384 bit SHA3 digest from @a data, see also class SHA3_384.
+void    sha3_384_hash   (const void *data, size_t data_length, uint8_t hashvalue[48]);
+
+/** SHA3_512 - 512 Bit digest generation.
+ * This class implements the SHA3 hash funtion to create 512 Bit digests, see FIPS 202 @cite Fips202 .
+ */
+struct SHA3_512 {
+  /*dtor*/ ~SHA3_512    ();
+  /*ctor*/  SHA3_512    ();         ///< Create context to calculate a 512 bit SHA3 hash digest.
+  void      reset       ();         ///< Reset state to feed and retrieve a new hash value.
+  void      update      (const uint8_t *data, size_t length);   ///< Feed data to be hashed.
+  void      digest      (uint8_t hashvalue[64]);                ///< Retrieve the resulting hash value.
+private:
+  AlignedPOD<232> mem_;
+  class     State;
+  State    *state_;
+};
+/// Calculate 512 bit SHA3 digest from @a data, see also class SHA3_512.
+void    sha3_512_hash   (const void *data, size_t data_length, uint8_t hashvalue[64]);
+
+/** SHAKE128 - 128 Bit extendable output digest generation.
+ * This class implements the SHA3 extendable output hash funtion with 128 bit security strength, see FIPS 
202 @cite Fips202 .
+ */
+struct SHAKE128 {
+  /*dtor*/ ~SHAKE128        ();
+  /*ctor*/  SHAKE128        ();         ///< Create context to calculate an unbounded SHAKE128 hash digest.
+  void      reset           ();         ///< Reset state to feed and retrieve a new hash value.
+  void      update          (const uint8_t *data, size_t length);   ///< Feed data to be hashed.
+  void      squeeze_digest  (uint8_t *hashvalues, size_t n);        ///< Retrieve an arbitrary number of 
hash value bytes.
+private:
+  AlignedPOD<232> mem_;
+  class     State;
+  State    *state_;
+};
+/// Calculate SHA3 extendable output digest for 128 bit security strength, see also class SHAKE128.
+void    shake128_hash   (const void *data, size_t data_length, uint8_t *hashvalues, size_t n);
+
+/** SHAKE256 - 256 Bit extendable output digest generation.
+ * This class implements the SHA3 extendable output hash funtion with 256 bit security strength, see FIPS 
202 @cite Fips202 .
+ */
+struct SHAKE256 {
+  /*dtor*/ ~SHAKE256        ();
+  /*ctor*/  SHAKE256        ();         ///< Create context to calculate an unbounded SHAKE256 hash digest.
+  void      reset           ();         ///< Reset state to feed and retrieve a new hash value.
+  void      update          (const uint8_t *data, size_t length);   ///< Feed data to be hashed.
+  void      squeeze_digest  (uint8_t *hashvalues, size_t n);        ///< Retrieve an arbitrary number of 
hash value bytes.
+private:
+  AlignedPOD<232> mem_;
+  class     State;
+  State    *state_;
+};
+/// Calculate SHA3 extendable output digest for 256 bit security strength, see also class SHAKE256.
+void    shake256_hash   (const void *data, size_t data_length, uint8_t *hashvalues, size_t n);
+
+namespace Lib { // Namespace for implementation internals
+
+/// The Keccak-f[1600] Permutation, see the Keccak specification @cite Keccak11 .
+class KeccakF1600 {
+  union alignas (2 * sizeof (uint64_t))
+  {
+    uint64_t            A[25];
+    uint8_t             bytes[200];
+    // __MMX__: __m64   V[25];
+  };
+public:
+  explicit      KeccakF1600 ();                         ///< Zero the state.
+  void          reset       ();                         ///< Zero the state.
+  uint64_t&     operator[]  (int      index)       { return A[index]; }
+  uint64_t      operator[]  (int      index) const { return A[index]; }
+  void          permute     (uint32_t n_rounds);        ///< Apply Keccak permutation with @a n_rounds.
+  inline uint8_t&
+  byte (size_t state_index)                             ///< Access byte 0..199 of the state.
+  {
+#if   __BYTE_ORDER == __LITTLE_ENDIAN
+    return bytes[(state_index / 8) * 8 + (state_index % 8)];            // 8 == sizeof (uint64_t)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+    return bytes[(state_index / 8) * 8 + (8 - 1 - (state_index % 8))];  // 8 == sizeof (uint64_t)
+#else
+#   error "Unknown __BYTE_ORDER"
+#endif
+  }
+};
+
+} // Lib
+
+/// AutoSeeder provides non-deterministic seeding entropy.
+class AutoSeeder {
+public:
+  /// Generate non-deterministic 64bit random value.
+  static uint64   random     ()       { return random_int64(); }
+  /// Generate non-deterministic 64bit random value.
+  uint64          operator() () const { return this->random(); }
+  /// Fill the range [begin, end) with random unsigned integer values.
+  template<typename RandomAccessIterator> void
+  generate (RandomAccessIterator begin, RandomAccessIterator end)
+  {
+    typedef typename std::iterator_traits<RandomAccessIterator>::value_type Value;
+    while (begin != end)
+      {
+        const uint64_t rbits = operator()();
+        *begin++ = Value (rbits);
+        if (sizeof (Value) <= 4 && begin != end)
+          *begin++ = Value (rbits >> 32);
+      }
+  }
+};
+
+/** KeccakRng - A KeccakF1600 based pseudo-random number generator.
+ * The permutation steps are derived from the Keccak specification @cite Keccak11 .
+ * For further details about this implementation, see also: http://testbit.org/keccak
+ * This class is primarily used to implement more fine tuned generators, such as:
+ * KeccakCryptoRng, KeccakGoodRng and KeccakFastRng.
+ */
+class KeccakRng {
+  const uint16_t      bit_rate_, n_rounds_;
+  uint32_t            opos_;
+  Lib::KeccakF1600    state_;
+  void                permute1600();
+public:
+  /// Integral type of the KeccakRng generator results.
+  typedef uint64_t    result_type;
+  /// Amount of 64 bit random numbers per generated block.
+  inline size_t       n_nums() const            { return bit_rate_ / 64; }
+  /// Amount of bits used to store hidden random number generator state.
+  inline size_t       bit_capacity() const      { return 1600 - bit_rate_; }
+  /*dtor*/           ~KeccakRng  ();
+  /// Create an unseeded Keccak PRNG with specific capacity and number of rounds, for experts only.
+  explicit
+  KeccakRng (uint16_t hidden_state_capacity, uint16_t n_rounds) :
+    bit_rate_ (1600 - hidden_state_capacity), n_rounds_ (n_rounds), opos_ (n_nums())
+  {
+    BSE_ASSERT_RETURN (hidden_state_capacity > 0 && hidden_state_capacity <= 1600 - 64);
+    BSE_ASSERT_RETURN (64 * (hidden_state_capacity / 64) == hidden_state_capacity); // capacity must be 
64bit aligned
+    BSE_ASSERT_RETURN (n_rounds > 0 && n_rounds < 255);                             // see 
KECCAK_ROUND_CONSTANTS access
+  }
+  void forget   ();
+  void discard  (unsigned long long count);
+  void xor_seed (const uint64_t *seeds, size_t n_seeds);
+  /// Reinitialize the generator state using a 64 bit @a seed_value.
+  void seed     (uint64_t seed_value = 1)               { seed (&seed_value, 1); }
+  /// Reinitialize the generator state using a nuber of 64 bit @a seeds.
+  void
+  seed (const uint64_t *seeds, size_t n_seeds)
+  {
+    state_.reset();
+    xor_seed (seeds, n_seeds);
+  }
+  /// Seed the generator state from a @a seed_sequence.
+  template<class SeedSeq> void
+  seed (SeedSeq &seed_sequence)
+  {
+    uint32_t u32[50];                   // fill 50 * 32 = 1600 state bits
+    seed_sequence.generate (&u32[0], &u32[50]);
+    uint64_t u64[25];
+    for (size_t i = 0; i < 25; i++)     // Keccak bit order: 1) LSB 2) MSB
+      u64[i] = u32[i * 2] | (uint64_t (u32[i * 2 + 1]) << 32);
+    seed (u64, 25);
+  }
+  /// Seed the generator from a system specific nondeterministic random source.
+  void auto_seed ();
+  /// Generate uniformly distributed 64 bit pseudo random number.
+  /// A new block permutation is carried out every n_nums() calls, see also xor_seed().
+  uint64_t
+  random ()
+  {
+    if (opos_ >= n_nums())
+      permute1600();
+    return state_[opos_++];
+  }
+  /// Generate uniformly distributed 32 bit pseudo random number.
+  result_type   operator() ()   { return random(); }
+  /// Fill the range [begin, end) with random unsigned integer values.
+  template<typename RandomAccessIterator> void
+  generate (RandomAccessIterator begin, RandomAccessIterator end)
+  {
+    typedef typename std::iterator_traits<RandomAccessIterator>::value_type Value;
+    while (begin != end)
+      {
+        const uint64_t rbits = operator()();
+        *begin++ = Value (rbits);
+        if (sizeof (Value) <= 4 && begin != end)
+          *begin++ = Value (rbits >> 32);
+      }
+  }
+  /// Compare two generators for state equality.
+  friend bool
+  operator== (const KeccakRng &lhs, const KeccakRng &rhs)
+  {
+    for (size_t i = 0; i < 25; i++)
+      if (lhs.state_[i] != rhs.state_[i])
+        return false;
+    return lhs.opos_ == rhs.opos_ && lhs.bit_rate_ == rhs.bit_rate_;
+  }
+  /// Compare two generators for state inequality.
+  friend bool
+  operator!= (const KeccakRng &lhs, const KeccakRng &rhs)
+  {
+    return !(lhs == rhs);
+  }
+  /// Minimum of the result type, for uint64_t that is 0.
+  result_type
+  min() const
+  {
+    return std::numeric_limits<result_type>::min(); // 0
+  }
+  /// Maximum of the result type, for uint64_t that is 18446744073709551615.
+  result_type
+  max() const
+  {
+    return std::numeric_limits<result_type>::max(); // 18446744073709551615
+  }
+  /// Serialize generator state into an OStream.
+  template<typename CharT, typename Traits>
+  friend std::basic_ostream<CharT, Traits>&
+  operator<< (std::basic_ostream<CharT, Traits> &os, const KeccakRng &self)
+  {
+    typedef typename std::basic_ostream<CharT, Traits>::ios_base IOS;
+    const typename IOS::fmtflags saved_flags = os.flags();
+    os.flags (IOS::dec | IOS::fixed | IOS::left);
+    const CharT space = os.widen (' ');
+    const CharT saved_fill = os.fill();
+    os.fill (space);
+    os << self.opos_;
+    for (size_t i = 0; i < 25; i++)
+      os << space << self.state_[i];
+    os.flags (saved_flags);
+    os.fill (saved_fill);
+    return os;
+  }
+  /// Deserialize generator state from an IStream.
+  template<typename CharT, typename Traits>
+  friend std::basic_istream<CharT, Traits>&
+  operator>> (std::basic_istream<CharT, Traits> &is, KeccakRng &self)
+  {
+    typedef typename std::basic_istream<CharT, Traits>::ios_base IOS;
+    const typename IOS::fmtflags saved_flags = is.flags();
+    is.flags (IOS::dec | IOS::skipws);
+    is >> self.opos_;
+    self.opos_ = std::min (self.n_nums(), size_t (self.opos_));
+    for (size_t i = 0; i < 25; i++)
+      is >> self.state_[i];
+    is.flags (saved_flags);
+    return is;
+  }
+};
+
+/** KeccakCryptoRng - A KeccakF1600 based cryptographic quality pseudo-random number generator.
+ * The quality of the generated pseudo random numbers is comaparable to the hash output of SHAKE128.
+ */
+class KeccakCryptoRng : public KeccakRng {
+public:
+  /// Initialize and seed the generator from a system specific nondeterministic random source.
+  explicit      KeccakCryptoRng ()                       : KeccakRng (256, 24)   { auto_seed(); }
+  /// Initialize and seed the generator from @a seed_sequence.
+  template<class SeedSeq>
+  explicit      KeccakCryptoRng (SeedSeq &seed_sequence) : KeccakRng (256, 24)   { seed (seed_sequence); }
+};
+
+/** KeccakGoodRng - A KeccakF1600 based good quality pseudo-random number generator.
+ * This class provides very good random numbers, using the KeccakF1600 algorithm without
+ * the extra security margins applied for SHA3 hash generation. This improves performance
+ * significantly without noticably trading random number quality.
+ * For cryptography grade number generation KeccakCryptoRng should be used instead.
+ */
+class KeccakGoodRng : public KeccakRng {
+public:
+  /// Initialize and seed the generator from a system specific nondeterministic random source.
+  explicit      KeccakGoodRng   ()                       : KeccakRng (192, 13)   { auto_seed(); }
+  /// Initialize and seed the generator from @a seed_sequence.
+  template<class SeedSeq>
+  explicit      KeccakGoodRng   (SeedSeq &seed_sequence) : KeccakRng (192, 13)   { seed (seed_sequence); }
+};
+
+/** KeccakFastRng - A KeccakF1600 based fast pseudo-random number generator.
+ * This class tunes the KeccakF1600 algorithm for best performance in pseudo random
+ * number generation. Performance is improved while still retaining quality random
+ * number generation, according to the findings in seciton "4.1.1 Statistical tests"
+ * from http://keccak.noekeon.org/Keccak-reference-3.0.pdf.
+ */
+class KeccakFastRng : public KeccakRng {
+public:
+  /// Initialize and seed the generator from a system specific nondeterministic random source.
+  explicit      KeccakFastRng   ()                       : KeccakRng (128, 8)    { auto_seed(); }
+  /// Initialize and seed the generator from @a seed_sequence.
+  template<class SeedSeq>
+  explicit      KeccakFastRng   (SeedSeq &seed_sequence) : KeccakRng (128, 8)    { seed (seed_sequence); }
+};
+
+/** Pcg32Rng is a permutating linear congruential PRNG.
+ * At the core, this pseudo random number generator uses the well known
+ * linear congruential generator:
+ * 6364136223846793005 * accumulator + 1442695040888963407 mod 2^64.
+ * See also TAOCP by D. E. Knuth, section 3.3.4, table 1, line 26.
+ * For good statistical performance, the output function of the permuted congruential
+ * generator family is used as described on http://www.pcg-random.org/.
+ * Period length for this generator is 2^64, the specified seed @a offset
+ * chooses the position of the genrator and the seed @a sequence parameter
+ * can be used to choose from 2^63 distinct random sequences.
+ */
+class Pcg32Rng {
+  uint64_t increment_;          // must be odd, allows for 2^63 distinct random sequences
+  uint64_t accu_;               // can contain all 2^64 possible values
+  static constexpr const uint64_t A = 6364136223846793005ULL; // from C. E. Hayness, see TAOCP by D. E. 
Knuth, 3.3.4, table 1, line 26.
+  static inline constexpr uint32_t
+  ror32 (const uint32_t bits, const uint32_t offset)
+  {
+    // bitwise rotate-right pattern recognized by gcc & clang iff 32==sizeof (bits)
+    return (bits >> offset) | (bits << (32 - offset));
+  }
+  static inline constexpr uint32_t
+  pcg_xsh_rr (const uint64_t input)
+  {
+    // Section 6.3.1. 32-bit Output, 64-bit State: PCG-XSH-RR
+    // http://www.pcg-random.org/pdf/toms-oneill-pcg-family-v1.02.pdf
+    return ror32 ((input ^ (input >> 18)) >> 27, input >> 59);
+  }
+public:
+  /// Initialize and seed from @a seed_sequence.
+  template<class SeedSeq>
+  explicit Pcg32Rng  (SeedSeq &seed_sequence) : increment_ (0), accu_ (0) { seed (seed_sequence); }
+  /// Initialize and seed by seeking to position @a offset within stream @a sequence.
+  explicit Pcg32Rng  (uint64_t offset, uint64_t sequence);
+  /// Initialize and seed the generator from a system specific nondeterministic random source.
+  explicit Pcg32Rng  ();
+  /// Seed the generator from a system specific nondeterministic random source.
+  void     auto_seed ();
+  /// Seed by seeking to position @a offset within stream @a sequence.
+  void     seed      (uint64_t offset, uint64_t sequence);
+  /// Seed the generator state from a @a seed_sequence.
+  template<class SeedSeq> void
+  seed (SeedSeq &seed_sequence)
+  {
+    uint64_t seeds[2];
+    seed_sequence.generate (&seeds[0], &seeds[2]);
+    seed (seeds[0], seeds[1]);
+  }
+  /// Generate uniformly distributed 32 bit pseudo random number.
+  uint32_t
+  random ()
+  {
+    const uint64_t lcgout = accu_;      // using the *last* state as ouput helps with CPU pipelining
+    accu_ = A * accu_ + increment_;
+    return pcg_xsh_rr (lcgout);         // PCG XOR-shift + random rotation
+  }
+};
+
+// == Hashing ==
+/** Simple, very fast and well known hash function as constexpr with good dispersion.
+ * This is the 64bit version of the well known
+ * [FNV-1a](https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function)
+ * hash function, implemented as a C++11 constexpr for zero-terminated
+ * strings, so the hashes can be used e.g. as case labels in switch statements.
+ */
+template<class Num> static inline constexpr uint64_t
+fnv1a_consthash64 (const Num *const ztdata, uint64_t hash = 0xcbf29ce484222325)
+{
+  static_assert (sizeof (Num) <= 1, "");
+  return BSE_ISLIKELY (ztdata[0] != 0) ? fnv1a_consthash64 (ztdata + 1, 0x100000001b3 * (hash ^ uint8_t 
(ztdata[0]))) : hash;
+}
+
+/** Hash function based on the PCG family of random number generators (RNG).
+ * This function is based on the paper [PCG: A Family of Simple Fast
+ * Space-Efficient Statistically Good Algorithms for Random Number
+ * Generation](http://www.pcg-random.org/paper.html),
+ * because of its excellent avalange and distribution properties.
+ * The hash data is integrated as octets in the inner LCG RNG loop.
+ * Hash generation is very fast, because the inner loop consists only of a
+ * multiplication and subtraction, while the ouput bit mixing consists of
+ * just 5 simple operations (xor, shift and rotation).
+ */
+template<class Num> static BSE_CONST inline uint32_t
+pcg_hash32 (const Num *data, size_t length, uint64_t seed)
+{
+  static_assert (sizeof (Num) <= 1, "");
+  uint64_t h = seed;
+  // Knuth LCG
+  h ^= 0x14057b7ef767814fULL;
+  for (size_t i = 0; BSE_ISLIKELY (i < length); i++)
+    {
+      h -= uint8_t (data[i]);
+      h *= 6364136223846793005ULL;
+    }
+  // based on pcg_detail::xsh_rr_mixin
+  const size_t   rsh = h >> 59;
+  const uint32_t xsh = (h ^ (h >> 18)) >> 27;
+  const uint32_t rot = (xsh >> rsh) | (xsh << (32 - rsh));
+  return rot;
+}
+
+/** Hash function based on the PCG family of random number generators (RNG).
+ * This function is similar to pcg_hash32() at its core, but because the
+ * output is 64bit, the accumulated 64bit LCG state does not need to be
+ * bit reduced. A fast but statistially good mixing function with
+ * 5 xor/shifts and one multiplication is applied as output stage.
+ * This function is allmost as fast as fnv1a_consthash64 due to the similar
+ * structures of the inner loops, but it tends to score much better in
+ * [Avalanche effect](https://en.wikipedia.org/wiki/Avalanche_effect)
+ * tests, usch as [SMHasher](https://code.google.com/p/smhasher/).
+ */
+template<class Num> static BSE_CONST inline uint64_t
+pcg_hash64 (const Num *data, size_t length, uint64_t seed)
+{
+  static_assert (sizeof (Num) <= 1, "");
+  uint64_t h = seed;
+  // Knuth LCG
+  h ^= 0x14057b7ef767814fULL;
+  for (size_t i = 0; BSE_ISLIKELY (i < length); i++)
+    {
+      h -= uint8_t (data[i]);
+      h *= 6364136223846793005ULL;
+    }
+  // based on pcg_detail::rxs_m_xs_mixin
+  const size_t   rsh = h >> 59;
+  const uint64_t rxs = h ^ (h >> (5 + rsh));
+  const uint64_t m = rxs * 12605985483714917081ULL;
+  const uint64_t xs = m ^ (m >> 43);
+  return xs;
+}
+
+/// pcg_hash64() variant for zero-terminated strings.
+static BSE_CONST inline uint64_t
+pcg_hash64 (const char *ztdata, uint64_t seed)
+{
+  uint64_t h = seed;
+  // Knuth LCG
+  h ^= 0x14057b7ef767814fULL;
+  for (size_t i = 0; BSE_ISLIKELY (ztdata[i] != 0); i++)
+    {
+      h -= uint8_t (ztdata[i]);
+      h *= 6364136223846793005ULL;
+    }
+  // based on pcg_detail::rxs_m_xs_mixin
+  const size_t   rsh = h >> 59;
+  const uint64_t rxs = h ^ (h >> (5 + rsh));
+  const uint64_t m = rxs * 12605985483714917081ULL;
+  const uint64_t xs = m ^ (m >> 43);
+  return xs;
+}
+
+extern uint64_t cached_hash_secret; ///< Use hash_secret() for access.
+
+/// Provide hashing nonce for reseeding hashes at program start to avoid collision attacks.
+static BSE_PURE inline uint64_t
+hash_secret ()
+{
+  if (BSE_UNLIKELY (cached_hash_secret == 0))
+    random_secret (&cached_hash_secret);
+  return cached_hash_secret;
+}
+
+/// Fast byte hashing with good dispersion and runtime randomization.
+template<class Num> static BSE_CONST inline uint64_t
+byte_hash64 (const Num *data, size_t length)
+{
+  static_assert (sizeof (Num) <= 1, "");
+  return pcg_hash64 (data, length, hash_secret());
+}
+
+/// Fast string hashing with good dispersion for std::string and runtime randomization.
+static BSE_CONST inline uint64_t
+string_hash64 (const std::string &string)
+{
+  return pcg_hash64 (string.data(), string.size(), hash_secret());
+}
+
+/// pcg_hash64() variant for zero-terminated strings.
+static BSE_CONST inline uint64_t
+string_hash64 (const char *ztdata)
+{
+  return pcg_hash64 (ztdata, hash_secret());
+}
+
+} // Bse
+
+#endif // __BSE_RANDOMHASH_HH__



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]