Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a 128 byte random number

Tags:

c

random

If the rand() function creates a random number that is 4 bytes in length, and I wanted to create a random number that is 1024 bits in length (128 bytes), is the easiest method to get this by concatenating the rand() function 256 times or is there an alternative method?

#include <stdio.h>
#include <string.h>

int main(void) {
  const char data[128];
  memset(&data, 0x36, 128);

  printf("%s\n", data);
  puts("");
  printf("%d\n", sizeof(data)/sizeof(data[0]));
  puts("");

  int i = 0;
  unsigned long rez = 0;

  for(i = 0; i < 20; i++) {
      unsigned int num = rand();
      rez = rez + num;
      printf("%x\n", rez);
  }

  printf("%x\n", rez);
  return 0;
}
like image 988
nice_remark Avatar asked Jan 02 '23 06:01

nice_remark


1 Answers

is the easiest method to get this by concatenating the rand() function 256 times or is there an alternative method?

Each rand() returns a value in the [0...RAND_MAX] range. RAND_MAX is limited to 32767 <= RAND_MAX <= INT_MAX.

Very commonly RAND_MAX is a Mersenne number of the form 2n − 1. Code can take advantage of this this very common implementation dependent value. Each rand() call then provides RAND_MAX_BITS and not 32 as suggested by OP for a 4-byte int. @Matteo Italia

[See far below update]

#include <stdlib.h>

#if RAND_MAX == 0x7FFF
#define RAND_MAX_BITS 15
#elif RAND_MAX == 0x7FFFFFFF
#define RAND_MAX_BITS 31
#else
#error TBD code
#endif

Call rand() ⌈size * 8 / RAND_MAX_BITS⌉ times. This eases the number of rand() calls needed from size.

void rand_byte(uint8_t *dest, size_t size) {
  int r_queue = 0;
  int r_bit_count = 0;
  for (size_t i = 0; i < size; i++) {
    int r = 0;
    //printf("%3zu %2d %8x\n", i, r_bit_count, r_queue);
    if (r_bit_count < 8) {
      int need = 8 - r_bit_count;
      r = r_queue << need;
      r_queue = rand();
      r ^= r_queue;  // OK to flip bits already saved in `r`
      r_queue >>= need;
      r_bit_count = RAND_MAX_BITS - need;
    } else {
      r = r_queue;
      r_queue >>= 8;
      r_bit_count -= 8;
    }
    dest[i] = r;
  }
}

int main(void) {
  uint8_t buf[128];
  rand_byte(buf, sizeof buf);
  ...
  return 0;
}

If you want the easiest bit less efficient code, simply call rand() for each byte as answered by @dbush


[Update 2021]

@Anonymous Question Guy posted a nifty macro that returns the bit width of a Mersenne number, more generally than the #if RAND_MAX == 0x7FFF approach above.

/* Number of bits in inttype_MAX, or in any (1<<b)-1 where 0 <= b < 3E+10 */
#define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \
              + (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3))

_Static_assert((RAND_MAX & 1 && (RAND_MAX/2 + 1) & (RAND_MAX/2)) == 0, 
    "RAND_MAX is not a Mersenne number");
#define RAND_MAX_BITS IMAX_BITS(RAND_MAX)
like image 152
chux - Reinstate Monica Avatar answered Jan 04 '23 20:01

chux - Reinstate Monica