Provide a class to generate arbitrary length seeds for algorithms.
More...
Namespaces |
namespace | bslh |
Detailed Description
- Outline
-
-
- Purpose:
- Provide a class to generate arbitrary length seeds for algorithms.
-
- Classes:
-
- See also:
-
- Description:
- This component provides a class,
bslh::SeedGenerator
, which utilizes a user-supplied Random Number Generator (RNG) to generate arbitrary length seeds. The quality of the seeds will only be as good as the quality of the supplied RNG. A cryptographically secure RNG must be supplied in order for SeedGenerator
to produce seeds suitable for a cryptographically secure algorithm.
- This class satisfies the requirements for a seed generator, defined in
bslh_seededhash.h
. More information can be found in the package level documentation for bslh
(internal users can also find information here {TEAM BDE:USING MODULAR HASHING<GO>})
-
- Requirements on RNG:
- The (template parameter) type
RANDOM_NUM_GEN
shall be a class that provides a type alias result_type
and exposes an operator()
that returns a result of type result_type
. The value returned by operator()
shall be random bits, the quality of which can be defined by RANDOM_NUM_GEN
. RANDOM_NUM_GEN
shall also be default and copy constructible.
-
- Usage:
- This section illustrates intended usage of this component.
-
- Example: Seeding Hashing Algorithms Requiring Different Seed Sizes:
- Suppose we have a number of hashing algorithms that all require different length seeds. Some require 32 bits, some require 64 bits, some even require 1024 bits. We want to generate all these seeds in the same way, but we do not want to keep manually generating seeds of different sizes for these algorithms. Moreover, we want to be able to use all these algorithms through a general purpose functor. To accomplish this, we give all our algorithm the same interface and supply a seed generator, which can create any size seed that the algorithms require.
- First, we write our first hashing algorithm, which accepts a 32-bit seed and returns a 32-bit unsigned int.
class Seeded32BitHashingAlgorithm {
public:
typedef unsigned result_type;
enum { k_SEED_LENGTH = 4 };
private:
const char *d_seed;
public:
explicit Seeded32BitHashingAlgorithm(const char *seed);
result_type operator()(const char *data, size_t length);
};
Then, we define another hashing algorithm, which accepts a 64-bit seed and returns a 32-bit unsigned int class Seeded64BitHashingAlgorithm {
public:
typedef unsigned result_type;
enum { k_SEED_LENGTH = 8 };
private:
const char *d_seed;
public:
explicit Seeded64BitHashingAlgorithm(const char *seed);
result_type operator()(const char *data, size_t length);
};
Next, we define a final hashing algorithm, which accepts a 1024-bit seed and returns a 32-bit unsigned int class Seeded1024BitHashingAlgorithm {
public:
typedef unsigned result_type;
enum { k_SEED_LENGTH = 128 };
private:
const char *d_seed;
public:
explicit Seeded1024BitHashingAlgorithm(const char *seed);
result_type operator()(const char *data, size_t length);
};
Then, we declare our functor, SeededHash
, which will take a seed generator, and be able to run any of our hashing algorithms by generating the correct size seed with the seed generator. template <class HASH_ALGORITHM>
class SeededHash {
public:
typedef typename HASH_ALGORITHM::result_type result_type;
private:
char seed[HASH_ALGORITHM::k_SEED_LENGTH];
public:
template<class SEED_GENERATOR>
SeededHash(SEED_GENERATOR seedGenerator);
result_type operator()(const char *data, size_t length) const;
};
Next, we define our constructor where we actually use bslh::SeedGenerator
. bslh::SeedGenerator
allows us to create arbitrary length seeds to match the requirements of the above declared algorithms. template <class HASH_ALGORITHM>
template<class SEED_GENERATOR>
SeededHash<HASH_ALGORITHM>::SeededHash(SEED_GENERATOR seedGenerator) {
seedGenerator.generateSeed(seed, HASH_ALGORITHM::k_SEED_LENGTH);
}
template <class HASH_ALGORITHM>
typename SeededHash<HASH_ALGORITHM>::result_type
SeededHash<HASH_ALGORITHM>::operator()(const char *data,
size_t length) const {
HASH_ALGORITHM hashAlg(seed);
return hashAlg(data, length);
}
Now, we generate some data that we want to hash. const char *data[] = { "asdf",
"qwer",
"gskgf",
"ujkagad",
"rwwfwe", };
enum { NUM_STRINGS = sizeof data / sizeof *data };
Finally, we can hash the data the same way using all of the different hashing algorithms. The seed generator allows us to abstract away the different requirements each algorithm has on seed size. Each algorithm will produce different output because it has been supplied with a different seed. MockRNG rng;
SeedGenerator<MockRNG> seedGen(rng);
SeededHash<Seeded32BitHashingAlgorithm> hashAlg32BitSeed(seedGen);
SeededHash<Seeded64BitHashingAlgorithm> hashAlg64BitSeed(seedGen);
SeededHash<Seeded1024BitHashingAlgorithm> hashAlg1024BitSeed(seedGen);
for (int i = 0; i < NUM_STRINGS; ++i) {
unsigned int hash32BitSeed = hashAlg32BitSeed(data[i],
strlen(data[i]));
unsigned int hash64BitSeed = hashAlg64BitSeed(data[i],
strlen(data[i]));
unsigned int hash1024BitSeed = hashAlg1024BitSeed(data[i],
strlen(data[i]));
if (veryVerbose) printf("Asserting hashes of %s come out"
" different\n", data[i]);
ASSERT(hash32BitSeed != hash64BitSeed);
ASSERT(hash32BitSeed != hash1024BitSeed);
ASSERT(hash1024BitSeed != hash64BitSeed);
}