xs_random.h 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /* copyright (c) 2022 - 2024 grunfink et al. / MIT license */
  2. #ifndef _XS_RANDOM_H
  3. #define _XS_RANDOM_H
  4. unsigned int xs_rnd_int32_d(unsigned int *seed);
  5. void *xs_rnd_buf(void *buf, int size);
  6. #ifdef XS_IMPLEMENTATION
  7. #include <stdio.h>
  8. #include <sys/time.h>
  9. #include <unistd.h>
  10. #include <stdlib.h>
  11. unsigned int xs_rnd_int32_d(unsigned int *seed)
  12. /* returns a deterministic random integer. If seed is NULL, uses a static one */
  13. {
  14. static unsigned int s = 0;
  15. if (seed == NULL)
  16. seed = &s;
  17. if (*seed == 0) {
  18. struct timeval tv;
  19. gettimeofday(&tv, NULL);
  20. *seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
  21. }
  22. /* Linear congruential generator by Numerical Recipes */
  23. *seed = (*seed * 1664525) + 1013904223;
  24. return *seed;
  25. }
  26. void *xs_rnd_buf(void *buf, int size)
  27. /* fills buf with random data */
  28. {
  29. #ifdef __OpenBSD__
  30. /* available since OpenBSD 2.2 */
  31. arc4random_buf(buf, size);
  32. #else
  33. FILE *f;
  34. int done = 0;
  35. if ((f = fopen("/dev/urandom", "r")) != NULL) {
  36. /* fill with great random data from the system */
  37. if (fread(buf, size, 1, f) == 1)
  38. done = 1;
  39. fclose(f);
  40. }
  41. if (!done) {
  42. /* fill the buffer with poor quality, deterministic data */
  43. unsigned int s = 0;
  44. unsigned char *p = (unsigned char *)buf;
  45. int n = size / sizeof(s);
  46. /* fill with full integers */
  47. while (n--) {
  48. xs_rnd_int32_d(&s);
  49. memcpy(p, &s, sizeof(s));
  50. p += sizeof(s);
  51. }
  52. if ((n = size % sizeof(s))) {
  53. /* fill the remaining */
  54. xs_rnd_int32_d(&s);
  55. memcpy(p, &s, n);
  56. }
  57. }
  58. #endif /* __OpenBSD__ */
  59. return buf;
  60. }
  61. #endif /* XS_IMPLEMENTATION */
  62. #endif /* XS_RANDOM_H */