// bslh_seedgenerator.h -*-C++-*- #ifndef INCLUDED_BSLH_SEEDGENERATOR #define INCLUDED_BSLH_SEEDGENERATOR #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a class to generate arbitrary length seeds for algorithms. // //@CLASSES: // bslh::SeedGenerator: generator for arbitrary length seeds // //@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 { // // This class is a functor that implements a hashing algorithm seeded // // with 32 bits. // // public: // typedef unsigned result_type; // Type of the hash returned // enum { k_SEED_LENGTH = 4 }; // Seed length in bytes // // private: // const char *d_seed; // Seed used in the generation of hashes // // public: // explicit Seeded32BitHashingAlgorithm(const char *seed); // // Construct a 'Seeded32BitHashingAlgorithm' that will use the // // first 4 bytes of the specified 'seed' to seed the algorithm. // // result_type operator()(const char *data, size_t length); // // Return a hash of the specified 'length' bytes of 'data'. // }; //.. // Then, we define another hashing algorithm, which accepts a 64-bit seed and // returns a 32-bit unsigned int //.. // class Seeded64BitHashingAlgorithm { // // This class is a functor that implements a hashing algorithm seeded // // with 64 bits. // // public: // typedef unsigned result_type; // Type of the hash returned // enum { k_SEED_LENGTH = 8 }; // Seed length in bytes // // private: // const char *d_seed; // Seed used in the generation of hashes // // public: // explicit Seeded64BitHashingAlgorithm(const char *seed); // // Construct a 'Seeded64BitHashingAlgorithm' that will use the // // first 8 bytes of the specified 'seed' to seed the algorithm. // // result_type operator()(const char *data, size_t length); // // Return a hash of the specified 'length' bytes of 'data'. // }; //.. // Next, we define a final hashing algorithm, which accepts a 1024-bit seed and // returns a 32-bit unsigned int //.. // class Seeded1024BitHashingAlgorithm { // // This class is a functor that implements a hashing algorithm seeded // // with 1024 bits. // // public: // typedef unsigned result_type; // Type of the hash returned // enum { k_SEED_LENGTH = 128 }; // Seed length in bytes // // private: // const char *d_seed; // Seed used in the generation of hashes // // public: // explicit Seeded1024BitHashingAlgorithm(const char *seed); // // Construct a 'Seeded1024BitHashingAlgorithm' that will use the // // first 128 bytes of the specified 'seed' to seed the algorithm. // // result_type operator()(const char *data, size_t length); // // Return a hash of the specified 'length' bytes of 'data'. // }; //.. // 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 { // // This class template implements an interface similar to 'std::hash', // // which will used the (template parameter) type 'SEED_GENERATOR' and // // 'HASH_ALGORITHM' to compute hashes. // // public: // typedef typename HASH_ALGORITHM::result_type result_type; // // Type of the hash that will be returned. // // private: // char seed[HASH_ALGORITHM::k_SEED_LENGTH]; // // Stores the seed that will be used to run the (template // // parameter) type 'HASH_ALGORITHM' // // public: // template<class SEED_GENERATOR> // SeededHash(SEED_GENERATOR seedGenerator); // //Create a 'SeededHash' and generate a seed using the specified // //'seedGenerator'. // // result_type operator()(const char *data, size_t length) const; // // Returns a hash generated by the (template parameter) type // // 'HASH_ALGORITHM' for the specified 'length' bytes of 'data'. // // }; //.. // 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); // } //.. #include <bslscm_version.h> #include <bsls_assert.h> #include <string.h> // for 'memcpy' #include <stddef.h> // for 'size_t' namespace BloombergLP { namespace bslh { // ========================= // class bslh::SeedGenerator // ========================= template<class RANDOM_NUM_GEN> class SeedGenerator : private RANDOM_NUM_GEN { // This class template implements a seed generator which takes a user // supplied random number generator and uses it to generate an arbitrary // length seed. Note that this type inherits from the (template parameter) // type 'RANDOM_NUM_GEN' to take advantage of the empty-base optimization. private: // PRIVATE TYPES typedef typename RANDOM_NUM_GEN::result_type result_type; // 'result_type' is an alias for the value returned by a call to // 'operator()' on the (template parameter) type 'RNG'. // DATA enum { k_RNGOUTPUTSIZE = sizeof(typename RANDOM_NUM_GEN::result_type)}; // Size in bytes of the rng's output. public: // CREATORS SeedGenerator(); // Create a 'bslh::SeedGenerator' that will default construct the // parameterized 'RNG' and use it to generate its seeds. explicit SeedGenerator(const RANDOM_NUM_GEN &randomNumberGenerator); // Create a 'bslh::SeedGenerator' that will use the specified // 'randomNumberGenerator' to generate its seeds. //! SeedGenerator(const SeedGenerator& original) = default; // Create a 'bslh::SeedGenerator' object with a copy of the random // number generator used by the specified 'original'. //! ~SeedGenerator() = default; // Destroy this object. // MANIPULATORS //! SeedGenerator& operator=(const SeedGenerator& rhs) = default; // Assign to this object the value of the specified 'rhs' object, and // return a reference providing modifiable access to this object. void generateSeed(char *seedLocation, size_t seedLength); // Generate a seed of the specified 'seedLength' bytes and store it at // the specified 'seedLocation'. The seed will be generated with bytes // from the random number generator supplied at construction. All of // the returned bytes will come from the RNG, meaning if the requested // seed is larger than the return type of the RNG, the RNG will be // called multiple times. The behaviour is undefined unless the memory // at 'seedLocation' can store 'seedLength' bytes. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // CREATORS template<class RANDOM_NUM_GEN> inline SeedGenerator<RANDOM_NUM_GEN>::SeedGenerator() : RANDOM_NUM_GEN() { } template<class RANDOM_NUM_GEN> inline SeedGenerator<RANDOM_NUM_GEN>::SeedGenerator( const RANDOM_NUM_GEN &randomNumberGenerator) : RANDOM_NUM_GEN(randomNumberGenerator) { } // MANIPULATORS template<class RANDOM_NUM_GEN> inline void SeedGenerator<RANDOM_NUM_GEN>::generateSeed(char *seedLocation, size_t seedLength) { BSLS_ASSERT(seedLocation || !seedLength); size_t numChunks = seedLength / k_RNGOUTPUTSIZE; size_t remainder = seedLength % k_RNGOUTPUTSIZE; for (size_t i = 0; i != numChunks; ++i) { result_type rand = RANDOM_NUM_GEN::operator()(); memcpy(seedLocation + i * sizeof(rand), &rand, sizeof(rand)); } if (remainder) { result_type rand = RANDOM_NUM_GEN::operator()(); memcpy(seedLocation + numChunks * sizeof(rand), &rand, remainder); } } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2014 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------