Coverage Report

Created: 2023-12-08 07:00

/src/mcl/include/cybozu/random_generator.hpp
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
/**
3
  @file
4
  @brief pseudrandom generator
5
  @author MITSUNARI Shigeo(@herumi)
6
  @license modified new BSD license
7
  http://opensource.org/licenses/BSD-3-Clause
8
*/
9
10
#ifndef CYBOZU_DONT_USE_EXCEPTION
11
#include <cybozu/exception.hpp>
12
#endif
13
#ifdef _WIN32
14
#ifndef WIN32_LEAN_AND_MEAN
15
  #define WIN32_LEAN_AND_MEAN
16
#endif
17
#include <windows.h>
18
#include <wincrypt.h>
19
#ifdef _MSC_VER
20
#pragma comment (lib, "advapi32.lib")
21
#endif
22
#else
23
#include <stdio.h>
24
#include <sys/types.h>
25
#include <fcntl.h>
26
#endif
27
28
namespace cybozu {
29
30
class RandomGenerator {
31
  RandomGenerator(const RandomGenerator&);
32
  void operator=(const RandomGenerator&);
33
public:
34
#ifdef _WIN32
35
  RandomGenerator()
36
    : prov_(0)
37
  {
38
    DWORD flagTbl[] = { CRYPT_VERIFYCONTEXT | CRYPT_SILENT, 0, CRYPT_MACHINE_KEYSET };
39
    for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(flagTbl); i++) {
40
      if (CryptAcquireContext(&prov_, NULL, NULL, PROV_RSA_FULL, flagTbl[i]) != 0) return;
41
    }
42
#ifdef CYBOZU_DONT_USE_EXCEPTION
43
    prov_ = 0;
44
#else
45
    throw cybozu::Exception("randomgenerator");
46
#endif
47
  }
48
  bool read_inner(void *buf, size_t byteSize)
49
  {
50
    if (prov_ == 0) return false;
51
    return CryptGenRandom(prov_, static_cast<DWORD>(byteSize), static_cast<BYTE*>(buf)) != 0;
52
  }
53
  ~RandomGenerator()
54
  {
55
    if (prov_) {
56
      CryptReleaseContext(prov_, 0);
57
    }
58
  }
59
  /*
60
    fill buf[0..bufNum-1] with random data
61
    @note bufNum is not byte size
62
  */
63
  template<class T>
64
  void read(bool *pb, T *buf, size_t bufNum)
65
  {
66
    const size_t byteSize = sizeof(T) * bufNum;
67
    *pb = read_inner(buf, byteSize);
68
  }
69
private:
70
  HCRYPTPROV prov_;
71
#else
72
  RandomGenerator()
73
    : fp_(::fopen("/dev/urandom", "rb"))
74
0
  {
75
0
#ifndef CYBOZU_DONT_USE_EXCEPTION
76
0
    if (!fp_) throw cybozu::Exception("randomgenerator");
77
0
#endif
78
0
  }
79
  ~RandomGenerator()
80
0
  {
81
0
    if (fp_) ::fclose(fp_);
82
0
  }
83
  /*
84
    fill buf[0..bufNum-1] with random data
85
    @note bufNum is not byte size
86
  */
87
  template<class T>
88
  void read(bool *pb, T *buf, size_t bufNum)
89
0
  {
90
0
    if (fp_ == 0) {
91
0
      *pb = false;
92
0
      return;
93
0
    }
94
0
    const size_t byteSize = sizeof(T) * bufNum;
95
0
    *pb = ::fread(buf, 1, (int)byteSize, fp_) == byteSize;
96
0
  }
Unexecuted instantiation: void cybozu::RandomGenerator::read<unsigned int>(bool*, unsigned int*, unsigned long)
Unexecuted instantiation: void cybozu::RandomGenerator::read<unsigned long>(bool*, unsigned long*, unsigned long)
Unexecuted instantiation: void cybozu::RandomGenerator::read<unsigned char>(bool*, unsigned char*, unsigned long)
97
private:
98
  FILE *fp_;
99
#endif
100
#ifndef CYBOZU_DONT_USE_EXCEPTION
101
public:
102
  template<class T>
103
  void read(T *buf, size_t bufNum)
104
0
  {
105
0
    bool b;
106
0
    read(&b, buf, bufNum);
107
0
    if (!b) throw cybozu::Exception("RandomGenerator:read") << bufNum;
108
0
  }
Unexecuted instantiation: void cybozu::RandomGenerator::read<unsigned int>(unsigned int*, unsigned long)
Unexecuted instantiation: void cybozu::RandomGenerator::read<unsigned long>(unsigned long*, unsigned long)
109
  uint32_t get32()
110
0
  {
111
0
    uint32_t ret;
112
0
    read(&ret, 1);
113
0
    return ret;
114
0
  }
115
  uint64_t get64()
116
0
  {
117
0
    uint64_t ret;
118
0
    read(&ret, 1);
119
0
    return ret;
120
0
  }
121
  uint32_t operator()()
122
0
  {
123
0
    return get32();
124
0
  }
125
#endif
126
};
127
128
template<class T, class RG>
129
void shuffle(T* v, size_t n, RG& rg)
130
{
131
  if (n <= 1) return;
132
  for (size_t i = 0; i < n - 1; i++) {
133
    size_t r = i + size_t(rg.get64() % (n - i));
134
    using namespace std;
135
    swap(v[i], v[r]);
136
  }
137
}
138
139
template<class V, class RG>
140
void shuffle(V& v, RG& rg)
141
{
142
  shuffle(v.data(), v.size(), rg);
143
}
144
145
} // cybozu