mirror of https://github.com/aria2/aria2
				
				
				
			Revise getRandom facilities
Use one of the following to provide random bytes: - Windows CryptGenRandom - Linux getrandom (syscall interface to urandom, without nasty corner cases such as file descriptor exhaustion or re-linked /dev/urandom) - std::device_random (C++ random device, which usually will be urandom) This also equalizes util::getRandom and SimpleRandomizer (the former will now use the latter) instead of having essentially two different PRNG interfaces with potentially different quality. Closes GH-320pull/320/merge
							parent
							
								
									747131a06c
								
							
						
					
					
						commit
						81bdd5f61a
					
				
							
								
								
									
										14
									
								
								configure.ac
								
								
								
								
							
							
						
						
									
										14
									
								
								configure.ac
								
								
								
								
							| 
						 | 
				
			
			@ -720,6 +720,7 @@ AC_CHECK_FUNCS([__argz_count \
 | 
			
		|||
                gethostbyname \
 | 
			
		||||
		getifaddrs \
 | 
			
		||||
                getpagesize \
 | 
			
		||||
                getrandom \
 | 
			
		||||
                memchr \
 | 
			
		||||
                memmove \
 | 
			
		||||
                mempcpy \
 | 
			
		||||
| 
						 | 
				
			
			@ -755,6 +756,19 @@ AC_CHECK_FUNCS([__argz_count \
 | 
			
		|||
		utime \
 | 
			
		||||
		utimes])
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING([for getrandom linux syscall interface])
 | 
			
		||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
 | 
			
		||||
#include <linux/random.h>
 | 
			
		||||
]],
 | 
			
		||||
[[
 | 
			
		||||
int x = GRND_NONBLOCK;
 | 
			
		||||
]])],
 | 
			
		||||
  [have_getrandom_interface=yes
 | 
			
		||||
   AC_DEFINE([HAVE_GETRANDOM_INTERFACE], [1], [Define to 1 if getrandom linux syscall interface is available.])],
 | 
			
		||||
  [have_getrandom_interface=no])
 | 
			
		||||
AC_MSG_RESULT([$have_getrandom_interface])
 | 
			
		||||
AM_CONDITIONAL([HAVE_GETRANDOM_INTERFACE], [test "x$have_getrandom_interface" = "xyes"])
 | 
			
		||||
 | 
			
		||||
dnl Put tcmalloc/jemalloc checks after the posix_memalign check.
 | 
			
		||||
dnl These libraries may implement posix_memalign, while the usual CRT may not
 | 
			
		||||
dnl (e.g. mingw). Since we aren't including the corresponding library headers
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -163,7 +163,6 @@ Context::Context(bool standalone,
 | 
			
		|||
      throw DL_ABORT_EX("Option processing failed");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  SimpleRandomizer::getInstance()->init();
 | 
			
		||||
#ifdef ENABLE_BITTORRENT
 | 
			
		||||
  bittorrent::generateStaticPeerId(op->get(PREF_PEER_ID_PREFIX));
 | 
			
		||||
#endif // ENABLE_BITTORRENT
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -687,6 +687,10 @@ if HAVE_KQUEUE
 | 
			
		|||
SRCS += KqueueEventPoll.cc KqueueEventPoll.h
 | 
			
		||||
endif # HAVE_KQUEUE
 | 
			
		||||
 | 
			
		||||
if HAVE_GETRANDOM_INTERFACE
 | 
			
		||||
SRCS += getrandom_linux.c getrandom_linux.h
 | 
			
		||||
endif # HAVE_GETRANDOM_INTERFACE
 | 
			
		||||
 | 
			
		||||
if HAVE_LIBUV
 | 
			
		||||
SRCS += LibuvEventPoll.cc LibuvEventPoll.h
 | 
			
		||||
endif # HAVE_LIBUV
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,6 +43,10 @@
 | 
			
		|||
#include "a2time.h"
 | 
			
		||||
#include "a2functional.h"
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_GETRANDOM_INTERFACE
 | 
			
		||||
#  include "getrandom_linux.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace aria2 {
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<SimpleRandomizer> SimpleRandomizer::randomizer_;
 | 
			
		||||
| 
						 | 
				
			
			@ -55,75 +59,49 @@ const std::unique_ptr<SimpleRandomizer>& SimpleRandomizer::getInstance()
 | 
			
		|||
  return randomizer_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SimpleRandomizer::init()
 | 
			
		||||
{
 | 
			
		||||
#ifndef __MINGW32__
 | 
			
		||||
  // Just in case std::random_device() is fixed, add time and pid too.
 | 
			
		||||
  eng_.seed(std::random_device()()^time(nullptr)^getpid());
 | 
			
		||||
#endif // !__MINGW32__
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SimpleRandomizer::SimpleRandomizer()
 | 
			
		||||
{
 | 
			
		||||
#ifdef __MINGW32__
 | 
			
		||||
  BOOL r = CryptAcquireContext(&cryProvider_, 0, 0, PROV_RSA_FULL,
 | 
			
		||||
                               CRYPT_VERIFYCONTEXT|CRYPT_SILENT);
 | 
			
		||||
  BOOL r = ::CryptAcquireContext(
 | 
			
		||||
      &provider_,
 | 
			
		||||
      0, 0, PROV_RSA_FULL,
 | 
			
		||||
      CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
 | 
			
		||||
  assert(r);
 | 
			
		||||
#endif // __MINGW32__
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SimpleRandomizer::~SimpleRandomizer()
 | 
			
		||||
{
 | 
			
		||||
#ifdef __MINGW32__
 | 
			
		||||
  CryptReleaseContext(cryProvider_, 0);
 | 
			
		||||
#endif // __MINGW32__
 | 
			
		||||
  CryptReleaseContext(provider_, 0);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
long int SimpleRandomizer::getRandomNumber(long int to)
 | 
			
		||||
{
 | 
			
		||||
  assert(to > 0);
 | 
			
		||||
  return std::uniform_int_distribution<long int>(0, to - 1)(*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SimpleRandomizer::getRandomBytes(unsigned char* buf, size_t len)
 | 
			
		||||
{
 | 
			
		||||
#ifdef __MINGW32__
 | 
			
		||||
  int32_t val;
 | 
			
		||||
  BOOL r = CryptGenRandom(cryProvider_, sizeof(val),
 | 
			
		||||
                          reinterpret_cast<BYTE*>(&val));
 | 
			
		||||
  BOOL r = CryptGenRandom(provider_, len, reinterpret_cast<BYTE*>(buf));
 | 
			
		||||
  assert(r);
 | 
			
		||||
  if(val == INT32_MIN) {
 | 
			
		||||
    val = INT32_MAX;
 | 
			
		||||
  } else if(val < 0) {
 | 
			
		||||
    val = -val;
 | 
			
		||||
#elif defined(HAVE_GETRANDOM_INTERFACE)
 | 
			
		||||
  auto rv = getrandom_linux(buf, len);
 | 
			
		||||
  assert(rv >= 0 && (size_t)rv == len);
 | 
			
		||||
#else // ! __MINGW32__
 | 
			
		||||
  auto ubuf = reinterpret_cast<result_type*>(buf);
 | 
			
		||||
  size_t q = len / sizeof(result_type);
 | 
			
		||||
  auto gen = std::uniform_int_distribution<result_type>();
 | 
			
		||||
  for(; q > 0; --q, ++ubuf) {
 | 
			
		||||
    *ubuf = gen(dev_);
 | 
			
		||||
  }
 | 
			
		||||
  return val % to;
 | 
			
		||||
#else // !__MINGW32__
 | 
			
		||||
  return std::uniform_int_distribution<long int>(0, to - 1)(eng_);
 | 
			
		||||
#endif // !__MINGW32__
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
long int SimpleRandomizer::operator()(long int to)
 | 
			
		||||
{
 | 
			
		||||
  return getRandomNumber(to);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SimpleRandomizer::getRandomBytes(unsigned char *buf, size_t len)
 | 
			
		||||
{
 | 
			
		||||
#ifdef __MINGW32__
 | 
			
		||||
  if (!CryptGenRandom(cryProvider_, len, (PBYTE)buf)) {
 | 
			
		||||
    throw std::bad_alloc();
 | 
			
		||||
  }
 | 
			
		||||
#else
 | 
			
		||||
  uint32_t val;
 | 
			
		||||
  size_t q = len / sizeof(val);
 | 
			
		||||
  size_t r = len % sizeof(val);
 | 
			
		||||
  auto gen = std::bind(std::uniform_int_distribution<uint32_t>
 | 
			
		||||
                       (0, std::numeric_limits<uint32_t>::max()),
 | 
			
		||||
                       eng_);
 | 
			
		||||
  for(; q > 0; --q) {
 | 
			
		||||
    val = gen();
 | 
			
		||||
    memcpy(buf, &val, sizeof(val));
 | 
			
		||||
    buf += sizeof(val);
 | 
			
		||||
  }
 | 
			
		||||
  val = gen();
 | 
			
		||||
  memcpy(buf, &val, r);
 | 
			
		||||
#endif
 | 
			
		||||
  const size_t r = len % sizeof(result_type);
 | 
			
		||||
  auto last = gen(dev_);
 | 
			
		||||
  memcpy(ubuf, &last, r);
 | 
			
		||||
#endif // ! __MINGW32__
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace aria2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,30 +41,32 @@
 | 
			
		|||
#include <random>
 | 
			
		||||
 | 
			
		||||
#ifdef __MINGW32__
 | 
			
		||||
# include <wincrypt.h>
 | 
			
		||||
#endif // __MINGW32__
 | 
			
		||||
#  include <wincrypt.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace aria2 {
 | 
			
		||||
 | 
			
		||||
class SimpleRandomizer : public Randomizer {
 | 
			
		||||
private:
 | 
			
		||||
  static std::unique_ptr<SimpleRandomizer> randomizer_;
 | 
			
		||||
 | 
			
		||||
#ifdef __MINGW32__
 | 
			
		||||
  HCRYPTPROV cryProvider_;
 | 
			
		||||
#else // !__MINGW32__
 | 
			
		||||
  std::minstd_rand eng_;
 | 
			
		||||
#endif //!__MINGW32__
 | 
			
		||||
 | 
			
		||||
  SimpleRandomizer();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
#ifdef __MINGW32__
 | 
			
		||||
  HCRYPTPROV provider_;
 | 
			
		||||
#elif defined(HAVE_GETRANDOM_INTERFACE)
 | 
			
		||||
  // Nothing special needed
 | 
			
		||||
#else
 | 
			
		||||
  std::random_device dev_;
 | 
			
		||||
#endif // ! __MINGW32__
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  typedef std::random_device::result_type result_type;
 | 
			
		||||
 | 
			
		||||
  static const std::unique_ptr<SimpleRandomizer>& getInstance();
 | 
			
		||||
 | 
			
		||||
  virtual ~SimpleRandomizer();
 | 
			
		||||
 | 
			
		||||
  void init();
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns random number in [0, to).
 | 
			
		||||
   */
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +74,32 @@ public:
 | 
			
		|||
 | 
			
		||||
  void getRandomBytes(unsigned char *buf, size_t len);
 | 
			
		||||
 | 
			
		||||
  long int operator()(long int to);
 | 
			
		||||
  long int operator()(long int to)
 | 
			
		||||
  {
 | 
			
		||||
    return getRandomNumber(to);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  result_type operator()()
 | 
			
		||||
  {
 | 
			
		||||
    result_type rv;
 | 
			
		||||
    getRandomBytes(reinterpret_cast<unsigned char*>(&rv), sizeof(rv));
 | 
			
		||||
    return rv;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static constexpr result_type min()
 | 
			
		||||
  {
 | 
			
		||||
    return std::numeric_limits<result_type>::min();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static constexpr result_type max()
 | 
			
		||||
  {
 | 
			
		||||
    return std::numeric_limits<result_type>::max();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static double entropy()
 | 
			
		||||
  {
 | 
			
		||||
    return 0.0;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace aria2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
/* <!-- copyright */
 | 
			
		||||
/*
 | 
			
		||||
 * aria2 - The high speed download utility
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2014 Nils Maier
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 *
 | 
			
		||||
 * In addition, as a special exception, the copyright holders give
 | 
			
		||||
 * permission to link the code of portions of this program with the
 | 
			
		||||
 * OpenSSL library under certain conditions as described in each
 | 
			
		||||
 * individual source file, and distribute linked combinations
 | 
			
		||||
 * including the two.
 | 
			
		||||
 * You must obey the GNU General Public License in all respects
 | 
			
		||||
 * for all of the code used other than OpenSSL.  If you modify
 | 
			
		||||
 * file(s) with this exception, you may extend this exception to your
 | 
			
		||||
 * version of the file(s), but you are not obligated to do so.  If you
 | 
			
		||||
 * do not wish to do so, delete this exception statement from your
 | 
			
		||||
 * version.  If you delete this exception statement from all source
 | 
			
		||||
 * files in the program, then also delete it here.
 | 
			
		||||
 */
 | 
			
		||||
/* copyright --> */
 | 
			
		||||
 | 
			
		||||
#define _GNUSOURCE
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/syscall.h>
 | 
			
		||||
#include <linux/random.h>
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "getrandom_linux.h"
 | 
			
		||||
 | 
			
		||||
int getrandom_linux(void *buf, size_t buflen) {
 | 
			
		||||
#ifdef HAVE_GETRANDOM
 | 
			
		||||
  return getrandom(buf, buflen, 0);
 | 
			
		||||
#else // HAVE_GETRANDOM
 | 
			
		||||
  return syscall(SYS_getrandom, buf, buflen, 0);
 | 
			
		||||
#endif // HAVE_GETRANDOM
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,49 @@
 | 
			
		|||
/* <!-- copyright */
 | 
			
		||||
/*
 | 
			
		||||
 * aria2 - The high speed download utility
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2014 Nils Maier
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 *
 | 
			
		||||
 * In addition, as a special exception, the copyright holders give
 | 
			
		||||
 * permission to link the code of portions of this program with the
 | 
			
		||||
 * OpenSSL library under certain conditions as described in each
 | 
			
		||||
 * individual source file, and distribute linked combinations
 | 
			
		||||
 * including the two.
 | 
			
		||||
 * You must obey the GNU General Public License in all respects
 | 
			
		||||
 * for all of the code used other than OpenSSL.  If you modify
 | 
			
		||||
 * file(s) with this exception, you may extend this exception to your
 | 
			
		||||
 * version of the file(s), but you are not obligated to do so.  If you
 | 
			
		||||
 * do not wish to do so, delete this exception statement from your
 | 
			
		||||
 * version.  If you delete this exception statement from all source
 | 
			
		||||
 * files in the program, then also delete it here.
 | 
			
		||||
 */
 | 
			
		||||
/* copyright --> */
 | 
			
		||||
 | 
			
		||||
#ifndef D_GETRANDOM_LINUX_H
 | 
			
		||||
#define D_GETRANDOM_LINUX_H
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int getrandom_linux(void *buf, size_t buflen);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* D_GETRANDOM_LINUX_H */
 | 
			
		||||
							
								
								
									
										39
									
								
								src/util.cc
								
								
								
								
							
							
						
						
									
										39
									
								
								src/util.cc
								
								
								
								
							| 
						 | 
				
			
			@ -1545,45 +1545,10 @@ std::vector<std::pair<size_t, std::string> > createIndexPaths(std::istream& i)
 | 
			
		|||
  return indexPaths;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
void generateRandomDataRandom(unsigned char* data, size_t length)
 | 
			
		||||
{
 | 
			
		||||
  const auto& rd = SimpleRandomizer::getInstance();
 | 
			
		||||
  rd->getRandomBytes(data, length);
 | 
			
		||||
}
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
#ifndef __MINGW32__
 | 
			
		||||
namespace {
 | 
			
		||||
void generateRandomDataUrandom
 | 
			
		||||
(unsigned char* data, size_t length, std::ifstream& devUrand)
 | 
			
		||||
{
 | 
			
		||||
  devUrand.read(reinterpret_cast<char*>(data), length);
 | 
			
		||||
}
 | 
			
		||||
} // namespace
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void generateRandomData(unsigned char* data, size_t length)
 | 
			
		||||
{
 | 
			
		||||
#ifdef __MINGW32__
 | 
			
		||||
  generateRandomDataRandom(data, length);
 | 
			
		||||
#else // !__MINGW32__
 | 
			
		||||
  static int method = -1;
 | 
			
		||||
  static std::ifstream devUrand;
 | 
			
		||||
  if(method == 0) {
 | 
			
		||||
    generateRandomDataUrandom(data, length, devUrand);
 | 
			
		||||
  } else if(method == 1) {
 | 
			
		||||
    generateRandomDataRandom(data, length);
 | 
			
		||||
  } else {
 | 
			
		||||
    devUrand.open("/dev/urandom");
 | 
			
		||||
    if(devUrand) {
 | 
			
		||||
      method = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
      method = 1;
 | 
			
		||||
    }
 | 
			
		||||
    generateRandomData(data, length);
 | 
			
		||||
  }
 | 
			
		||||
#endif // !__MINGW32__
 | 
			
		||||
  const auto& rd = SimpleRandomizer::getInstance();
 | 
			
		||||
  return rd->getRandomBytes(data, length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool saveAs
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
| 
						 | 
				
			
			@ -1954,11 +1955,54 @@ void UtilTest::testCreateIndexPaths()
 | 
			
		|||
 | 
			
		||||
void UtilTest::testGenerateRandomData()
 | 
			
		||||
{
 | 
			
		||||
  unsigned char data1[20];
 | 
			
		||||
  using namespace std;
 | 
			
		||||
 | 
			
		||||
  // Simple sanity check
 | 
			
		||||
  unsigned char data1[25];
 | 
			
		||||
  memset(data1, 0, sizeof(data1));
 | 
			
		||||
  util::generateRandomData(data1, sizeof(data1));
 | 
			
		||||
  unsigned char data2[20];
 | 
			
		||||
 | 
			
		||||
  unsigned char data2[25];
 | 
			
		||||
  memset(data2, 0, sizeof(data2));
 | 
			
		||||
  util::generateRandomData(data2, sizeof(data2));
 | 
			
		||||
 | 
			
		||||
  CPPUNIT_ASSERT(memcmp(data1, data2, sizeof(data1)) != 0);
 | 
			
		||||
 | 
			
		||||
  // Simple stddev/mean tests
 | 
			
		||||
  map<uint8_t, size_t> counts;
 | 
			
		||||
  uint8_t bytes[1 << 20];
 | 
			
		||||
  for (auto i = 0; i < 10; ++i) {
 | 
			
		||||
    util::generateRandomData(bytes, sizeof(bytes));
 | 
			
		||||
    for (auto b : bytes) {
 | 
			
		||||
      counts[b]++;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  CPPUNIT_ASSERT_MESSAGE("Should see all kinds of bytes", counts.size() == 256);
 | 
			
		||||
  if (counts.size() != 256) {
 | 
			
		||||
    throw std::domain_error(
 | 
			
		||||
        "Would have expected to see at one of each possible byte value!");
 | 
			
		||||
  }
 | 
			
		||||
  double sum = accumulate(
 | 
			
		||||
    counts.begin(),
 | 
			
		||||
    counts.end(),
 | 
			
		||||
    0.0,
 | 
			
		||||
    [](double total, const decltype(counts)::value_type & elem) {
 | 
			
		||||
      return total + elem.second;
 | 
			
		||||
    });
 | 
			
		||||
  double mean = sum / counts.size();
 | 
			
		||||
  vector<double> diff(counts.size());
 | 
			
		||||
  transform(
 | 
			
		||||
    counts.begin(),
 | 
			
		||||
    counts.end(),
 | 
			
		||||
    diff.begin(),
 | 
			
		||||
    [&](const decltype(counts)::value_type & elem) -> double {
 | 
			
		||||
      return (double)elem.second - mean;
 | 
			
		||||
    });
 | 
			
		||||
  double sq_sum = inner_product(diff.begin(), diff.end(), diff.begin(), 0.0);
 | 
			
		||||
  double stddev = sqrt(sq_sum / counts.size());
 | 
			
		||||
  cout << "stddev: " << fixed << stddev << endl;
 | 
			
		||||
  CPPUNIT_ASSERT_MESSAGE("stddev makes sense (lower)", stddev <= 320);
 | 
			
		||||
  CPPUNIT_ASSERT_MESSAGE("stddev makes sense (upper)", stddev >= 100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UtilTest::testFromHex()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue