0

I've written a funtion to prouduce random bytes in a uint8_t type array, unless I seed this with a random_device object it works fine but when I seed there are some compiler errors.

code:

#include <algorithm>
#include <random>
#include <functional>
#include <stdint>

void generateInitVector(uint8_t IV_buff[16])
{
    using bytes_randomizer = std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>;
    std::random_device rd;
    bytes_randomizer bytes(rd);

    std::generate(std::begin(IV_buff), std::end(IV_buff), std::ref(bytes));
}

compiler errors:

1. error: no matching function for call to 'begin(uint8_t*&)'|

2. error: request for member 'begin' in '__cont', which is of non-class type 'unsigned char*'|

3. error: request for member 'begin' in '__cont', which is of non-class type 'unsigned char* const'|

4. error: no matching function for call to 'end(uint8_t*&)'|

5. error: request for member 'begin' in '__cont', which is of non-class type 'unsigned char*'|

6. error: request for member 'end' in '__cont', which is of non-class type 'unsigned char* const'|

7. error: 'class std::random_device' has no member named 'generate'|

There's catch that if I define a uint8_t type array within th function

uint8_t data[16];
std::generate(std::begin(data), std::end(data), std::ref(bytes));  //and pass this array in `generate()`.

then only error 7 remains. Any solutions to this?

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Nilesh Kumar
  • 343
  • 1
  • 5
  • 18
  • 2
    Possible duplicate of [What is array decaying?](https://stackoverflow.com/questions/1461432/what-is-array-decaying) – UnholySheep May 31 '18 at 12:07
  • 2
    Use `std::array`. – Hatted Rooster May 31 '18 at 12:09
  • @SombreroChicken can you please elaborate. – Nilesh Kumar May 31 '18 at 12:11
  • @UnholySheep can you demonstrate how can I implement the solution to which you redirected me. – Nilesh Kumar May 31 '18 at 12:12
  • You cannot use `uint8_t` here anyway. Only `short`, `int`, `long`, `long long` or their unsigned counterparts, depending on the situations, are allowed as template parameters in ``. Even `int64_t` and the like are potentially UB, although that is a purely theoretical concern. – Baum mit Augen May 31 '18 at 12:27
  • @Nilesh, UnholySheep posted a rod, not a fish. What you are trying to do is incorrect, because passing array makes it decay to a bare pointer. You would have to pass size as another argument (and it still won't allow you to use iterators on it). `std::array` or `std::vector` is better solution here, as it won't decay and is generally better than C arrays. – Yksisarvinen May 31 '18 at 12:39
  • @Yksisarvinen `std::array` doesn't gain the OP anything. They just need to pass the array by reference. – NathanOliver May 31 '18 at 12:42
  • `std::generate(IV_buff, IV_buff + 16, ...)` – Igor Tandetnik May 31 '18 at 12:43
  • can you please suggest anything on error 7 also – Nilesh Kumar May 31 '18 at 12:49
  • None of the constructors of `std::independent_bits_engine` take `std::random_device` as a parameter. There's a templated constructor taking a `SeedSequence`, but `std::random_device` does not satisfy the requirements of `SeedSequence` (in particular, it doesn't have a method named `generate`, hence the last error). It's not clear to me what you were trying to do there. – Igor Tandetnik May 31 '18 at 12:49

1 Answers1

3

The issue here is that even though your function looks like

void generateInitVector(uint8_t IV_buff[16])

What it really is, thanks to the array decaying into a pointer is

void generateInitVector(uint8_t * IV_buff)

So, because you have a pointer, you cannot use std::begin and std::end. What you need to do is pass the array by reference to keep it an array. That looks like

void generateInitVector(uint8_t (&IV_buff)[16])

and now you can use std::begin and std::end and you maintain the size information of the array. You can even make it generic for the size using a template like

template<std::size_t N>
void generateInitVector(uint8_t (&IV_buff)[N])
{
    using bytes_randomizer = std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>;
    std::random_device rd;
    bytes_randomizer bytes(rd);

    std::generate(std::begin(IV_buff), std::end(IV_buff), std::ref(bytes));
}

You also have an issue with

bytes_randomizer bytes(rd);

std::independent_bits_engine expects a PRNG of the type of the first template parameter. You used std::default_random_engine which is not the same as std::random_device. You will need to change one of them to match the other in order for it to compile. For example:

template<std::size_t N>
void generateInitVector(uint8_t (&IV_buff)[N])
{
    using bytes_randomizer = std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>;
    std::default_random_engine rd;
    bytes_randomizer bytes(rd);

    std::generate(std::begin(IV_buff), std::end(IV_buff), std::ref(bytes));
}

int main()
{
    uint8_t data[16];
    generateInitVector(data);
}

Compiles just fine

NathanOliver
  • 171,901
  • 28
  • 288
  • 402