2020
2121#include < array>
2222#include < cstddef>
23- #include < memory>
2423#include < stdexcept>
2524#include < string>
2625#include < vector>
2726
2827#include < emmintrin.h>
2928
30- /* *
31- * @brief 64 bit nonce which is prepended to the counter in the PRG.
32- */
33- #ifndef PRG_NONCE
34- #define PRG_NONCE 0x0123456789ABCDEF
35- #endif
36-
37- /* *
38- * @brief The initial value of the PRG counter.
39- */
40- #ifndef PRG_INITIAL_COUNTER
41- #define PRG_INITIAL_COUNTER 0
42- #endif
43-
4429namespace scl {
4530
4631/* *
47- * @brief Pseudorandom generator based on AES-CTR.
32+ * @brief Pseudorandom generator.
33+ *
34+ * @code
35+ * auto prg = PRG::create();
4836 *
49- * The <code>PRG</code> class implements a pseudorandom generator based on
50- * AES-CTR where the n'th block of output is generated by encrypting a
51- * counter. A block of random data is generated by computing
37+ * std::array<unsigned char, 10> buffer;
38+ * prg.next(buffer); // buffer is filled with random bytes
5239 *
53- * <code>block := AES(seed, counter)</code>
40+ * std::vector<unsigned char> rands = prg.next(42);
41+ * assert(rands.size() == 42);
5442 *
55- * where <code>seed</code> is either all 0s or a user supplied value, and
56- * <code>counter</code> is a 128-bit counter initialized to be
43+ * auto prg1 = PRG::create("seed1");
44+ * auto prg2 = PRG::create("seed2");
5745 *
58- * <code>counter_init := PRG_NONCE || 0 ... 0</code>
46+ * assert(prg1.next(42) != prg2.next(42));
47+ * @endcode
5948 *
60- * where each half is 64 bits. The value of PRG_NONCE can be set by defining it
61- * as a macro. It defaults to <code>0x0123456789ABCDEF</code>.
49+ * The underlying implementation of PRG is based on AES128 in counter mode.
50+ * When supplying an explicit seed, only the first PRG::seedSize() bytes are
51+ * used. For the current implementation this means only the first 16 bytes are
52+ * counted.
53+ *
54+ * @code
55+ * auto prg1 = PRG::create("abcdef0123456789abc");
56+ * auto prg2 = PRG::create("abcdef0123456789xyz");
57+ *
58+ * assert(prg1.next(42) == prg2.next(42));
59+ * @endcode
6260 */
6361class PRG {
6462 private:
@@ -80,60 +78,41 @@ class PRG {
8078
8179 /* *
8280 * @brief Create a new PRG with a provided seed.
83- * @param seed the seed.
84- * @param seed_len length of the seed
8581 */
8682 static PRG create (const unsigned char * seed, std::size_t seed_len);
8783
8884 /* *
8985 * @brief Create a new PRG from a provided seed.
90- * @param seed the seed.
9186 */
9287 static PRG create (const std::string& seed);
9388
9489 /* *
9590 * @brief Reset the PRG.
96- *
97- * This method allows resetting a PRG object to its initial state.
9891 */
9992 void reset ();
10093
10194 /* *
10295 * @brief Generate random data and store it in a supplied buffer.
103- * @param buffer the buffer
104- * @param n how many bytes of random data to generate
10596 */
10697 void next (unsigned char * buffer, std::size_t n);
10798
10899 /* *
109100 * @brief Generate random data and store it in a supplied buffer.
110- * @param buffer the buffer with space pre-allocated
111- *
112- * How many bytes of random data to generate is decided based on the output of
113- * <code>buffer.size()</code>.
114101 */
115102 void next (std::vector<unsigned char >& buffer) {
116103 next (buffer.data (), buffer.size ());
117104 }
118105
119106 /* *
120107 * @brief Generate random data and store it in a supplied buffer.
121- * @param buffer the buffer.
122108 */
123109 template <std::size_t N>
124110 void next (std::array<unsigned char , N>& buffer) {
125- Next (buffer.data (), N);
111+ next (buffer.data (), N);
126112 }
127113
128114 /* *
129115 * @brief Generate random data and store in in a supplied buffer.
130- * @param buffer the buffer
131- * @param n how many random bytes to generate
132- * @throws std::invalid_argument if \p n is greater than
133- * <code>buffer.size()</code>.
134- *
135- * The capacity of \p buffer is not affected in any way by this method and it
136- * requires that it has room for at least \p n elements.
137116 */
138117 void next (std::vector<unsigned char >& buffer, std::size_t n) {
139118 if (buffer.size () < n) {
@@ -144,13 +123,12 @@ class PRG {
144123
145124 /* *
146125 * @brief Generate and return random data.
147- * @param n the number of random bytes to generate
148- * @return the random bytes.
149126 */
150127 std::vector<unsigned char > next (std::size_t n) {
151- auto buffer = std::make_unique<unsigned char []>(n);
152- next (buffer.get (), n);
153- return std::vector<unsigned char >(buffer.get (), buffer.get () + n);
128+ std::vector<unsigned char > buffer;
129+ buffer.reserve (n);
130+ next (buffer);
131+ return buffer;
154132 }
155133
156134 /* *
@@ -161,12 +139,12 @@ class PRG {
161139 }
162140
163141 private:
164- PRG (std::array<unsigned char , BLOCK_SIZE> seed) : m_seed(seed) {};
165-
166142 std::array<unsigned char , BLOCK_SIZE> m_seed = {0 };
167- long m_counter = PRG_INITIAL_COUNTER ;
143+ long m_counter = 0 ;
168144 BlockType m_state[11 ];
169145
146+ PRG (std::array<unsigned char , BLOCK_SIZE> seed) : m_seed(seed) {};
147+
170148 void update ();
171149 void init ();
172150};
0 commit comments