github.com/platonnetwork/platon-go@v0.7.6/cases/tool/win/bls_win/include/cybozu/random_generator.hpp (about)

     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  #include <winsock2.h>
    15  #include <windows.h>
    16  #include <wincrypt.h>
    17  #ifdef _MSC_VER
    18  #pragma comment (lib, "advapi32.lib")
    19  #endif
    20  #include <cybozu/critical_section.hpp>
    21  #else
    22  #include <sys/types.h>
    23  #include <fcntl.h>
    24  #endif
    25  
    26  namespace cybozu {
    27  
    28  class RandomGenerator {
    29  	RandomGenerator(const RandomGenerator&);
    30  	void operator=(const RandomGenerator&);
    31  public:
    32  #ifdef _WIN32
    33  	RandomGenerator()
    34  		: prov_(0)
    35  		, pos_(bufSize)
    36  	{
    37  		DWORD flagTbl[] = { 0, CRYPT_NEWKEYSET };
    38  		for (int i = 0; i < 2; i++) {
    39  			if (CryptAcquireContext(&prov_, NULL, NULL, PROV_RSA_FULL, flagTbl[i]) != 0) return;
    40  		}
    41  #ifdef CYBOZU_DONT_USE_EXCEPTION
    42  		prov_ = 0;
    43  #else
    44  		throw cybozu::Exception("randomgenerator");
    45  #endif
    46  	}
    47  	bool read_inner(void *buf, size_t byteSize)
    48  	{
    49  		if (prov_ == 0) return false;
    50  		return CryptGenRandom(prov_, static_cast<DWORD>(byteSize), static_cast<BYTE*>(buf)) != 0;
    51  	}
    52  	~RandomGenerator()
    53  	{
    54  		if (prov_) {
    55  			CryptReleaseContext(prov_, 0);
    56  		}
    57  	}
    58  	/*
    59  		fill buf[0..bufNum-1] with random data
    60  		@note bufNum is not byte size
    61  	*/
    62  	template<class T>
    63  	void read(bool *pb, T *buf, size_t bufNum)
    64  	{
    65  		cybozu::AutoLockCs al(cs_);
    66  		const size_t byteSize = sizeof(T) * bufNum;
    67  		if (byteSize > bufSize) {
    68  			if (!read_inner(buf, byteSize)) {
    69  				*pb = false;
    70  				return;
    71  			}
    72  		} else {
    73  			if (pos_ + byteSize > bufSize) {
    74  				read_inner(buf_, bufSize);
    75  				pos_ = 0;
    76  			}
    77  			memcpy(buf, buf_ + pos_, byteSize);
    78  			pos_ += byteSize;
    79  		}
    80  		*pb = true;
    81  	}
    82  private:
    83  	HCRYPTPROV prov_;
    84  	static const size_t bufSize = 1024;
    85  	char buf_[bufSize];
    86  	size_t pos_;
    87  	cybozu::CriticalSection cs_;
    88  #else
    89  	RandomGenerator()
    90  		: fp_(::fopen("/dev/urandom", "rb"))
    91  	{
    92  #ifndef CYBOZU_DONT_USE_EXCEPTION
    93  		if (!fp_) throw cybozu::Exception("randomgenerator");
    94  #endif
    95  	}
    96  	~RandomGenerator()
    97  	{
    98  		if (fp_) ::fclose(fp_);
    99  	}
   100  	/*
   101  		fill buf[0..bufNum-1] with random data
   102  		@note bufNum is not byte size
   103  	*/
   104  	template<class T>
   105  	void read(bool *pb, T *buf, size_t bufNum)
   106  	{
   107  		if (fp_ == 0) {
   108  			*pb = false;
   109  			return;
   110  		}
   111  		const size_t byteSize = sizeof(T) * bufNum;
   112  		*pb = ::fread(buf, 1, (int)byteSize, fp_) == byteSize;
   113  	}
   114  private:
   115  	FILE *fp_;
   116  #endif
   117  #ifndef CYBOZU_DONT_USE_EXCEPTION
   118  public:
   119  	template<class T>
   120  	void read(T *buf, size_t bufNum)
   121  	{
   122  		bool b;
   123  		read(&b, buf, bufNum);
   124  		if (!b) throw cybozu::Exception("RandomGenerator:read") << bufNum;
   125  	}
   126  	uint32_t get32()
   127  	{
   128  		uint32_t ret;
   129  		read(&ret, 1);
   130  		return ret;
   131  	}
   132  	uint64_t get64()
   133  	{
   134  		uint64_t ret;
   135  		read(&ret, 1);
   136  		return ret;
   137  	}
   138  	uint32_t operator()()
   139  	{
   140  		return get32();
   141  	}
   142  #endif
   143  };
   144  
   145  template<class T, class RG>
   146  void shuffle(T* v, size_t n, RG& rg)
   147  {
   148  	if (n <= 1) return;
   149  	for (size_t i = 0; i < n - 1; i++) {
   150  		size_t r = i + size_t(rg.get64() % (n - i));
   151  		using namespace std;
   152  		swap(v[i], v[r]);
   153  	}
   154  }
   155  
   156  template<class V, class RG>
   157  void shuffle(V& v, RG& rg)
   158  {
   159  	shuffle(v.data(), v.size(), rg);
   160  }
   161  
   162  } // cybozu