blob: 1aeca1aa33eabb64d8bb39bb65db1bdd9950d1ca [file] [log] [blame]
Alexander Afanasyev75088672014-07-14 11:58:30 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento74daf742018-11-23 18:14:13 -05002/*
Davide Pesavento8db61522019-01-11 16:44:50 -05003 * Copyright (c) 2013-2019 Regents of the University of California.
Alexander Afanasyev75088672014-07-14 11:58:30 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
Davide Pesavento7e780642018-11-24 15:51:34 -050022#include "ndn-cxx/util/random.hpp"
Junxiao Shi24c5a002018-12-12 04:47:15 +000023#include "ndn-cxx/security/impl/openssl.hpp"
Alexander Afanasyev75088672014-07-14 11:58:30 -070024
Davide Pesavento7e780642018-11-24 15:51:34 -050025#include "tests/boost-test.hpp"
Davide Pesavento74daf742018-11-23 18:14:13 -050026
Davide Pesavento8db61522019-01-11 16:44:50 -050027#include <array>
Alexander Afanasyev75088672014-07-14 11:58:30 -070028#include <cmath>
Davide Pesavento8db61522019-01-11 16:44:50 -050029#include <thread>
30
31#include <boost/mpl/vector.hpp>
Alexander Afanasyev75088672014-07-14 11:58:30 -070032
33namespace ndn {
Spyridon Mastorakis429634f2015-02-19 17:35:33 -080034namespace tests {
Alexander Afanasyev75088672014-07-14 11:58:30 -070035
Yingdi Yu0b537b92015-08-27 14:39:34 -070036BOOST_AUTO_TEST_SUITE(Util)
37BOOST_AUTO_TEST_SUITE(TestRandom)
Alexander Afanasyev75088672014-07-14 11:58:30 -070038
Davide Pesavento8db61522019-01-11 16:44:50 -050039BOOST_AUTO_TEST_CASE(ThreadLocalRng)
40{
41 random::RandomNumberEngine* r1 = &random::getRandomNumberEngine();
42 random::RandomNumberEngine* r2 = nullptr;
43 std::thread t([&r2] { r2 = &random::getRandomNumberEngine(); });
44 t.join();
45 random::RandomNumberEngine* r3 = &random::getRandomNumberEngine();
46
47 BOOST_CHECK(r2 != nullptr);
48 BOOST_CHECK_NE(r1, r2);
49 BOOST_CHECK_EQUAL(r1, r3);
50}
51
Alexander Afanasyev75088672014-07-14 11:58:30 -070052class PseudoRandomWord32
53{
54public:
55 static uint32_t
56 generate()
57 {
58 return random::generateWord32();
59 }
60};
61
62class PseudoRandomWord64
63{
64public:
65 static uint64_t
66 generate()
67 {
68 return random::generateWord64();
69 }
70};
71
72class SecureRandomWord32
73{
74public:
75 static uint32_t
76 generate()
77 {
78 return random::generateSecureWord32();
79 }
80};
81
82class SecureRandomWord64
83{
84public:
85 static uint64_t
86 generate()
87 {
88 return random::generateSecureWord64();
89 }
90};
91
Davide Pesavento8db61522019-01-11 16:44:50 -050092using RandomGenerators = boost::mpl::vector<PseudoRandomWord32,
93 PseudoRandomWord64,
94 SecureRandomWord32,
95 SecureRandomWord64>;
Yingdi Yu0b537b92015-08-27 14:39:34 -070096
97static double
98getDeviation(const std::vector<uint32_t>& counts, size_t size)
Alexander Afanasyev75088672014-07-14 11:58:30 -070099{
100 // Kolmogorov-Smirnov Goodness-of-Fit Test
101 // http://www.itl.nist.gov/div898/handbook/eda/section3/eda35g.htm
102
Yingdi Yu0b537b92015-08-27 14:39:34 -0700103 std::vector<double> edf(counts.size(), 0.0);
104 double probability = 0.0;
105 for (size_t i = 0; i < counts.size(); i++) {
106 probability += 1.0 * counts[i] / size;
107 edf[i] = probability;
108 }
109
110 double t = 0.0;
111 for (size_t i = 0; i < counts.size(); i++) {
112 t = std::max(t, std::abs(edf[i] - (i * 1.0 / counts.size())));
113 }
114
115 return t;
116}
117
Yingdi Yu0b537b92015-08-27 14:39:34 -0700118BOOST_AUTO_TEST_CASE_TEMPLATE(GoodnessOfFit, RandomGenerator, RandomGenerators)
119{
Alexander Afanasyev75088672014-07-14 11:58:30 -0700120 const size_t MAX_BINS = 32;
121 const uint32_t MAX_ITERATIONS = 35;
122
123 std::vector<uint32_t> counts(MAX_BINS, 0);
Alexander Afanasyev75088672014-07-14 11:58:30 -0700124 for (uint32_t i = 0; i < MAX_ITERATIONS; i++) {
125 counts[RandomGenerator::generate() % MAX_BINS]++;
126 }
127
Yingdi Yu0b537b92015-08-27 14:39:34 -0700128 // Check if it is uniform distribution with confidence 0.95
129 // http://dlc.erieri.com/onlinetextbook/index.cfm?fuseaction=textbook.appendix&FileName=Table7
Davide Pesavento8db61522019-01-11 16:44:50 -0500130 BOOST_CHECK_LE(getDeviation(counts, MAX_ITERATIONS), 0.230);
Yingdi Yu0b537b92015-08-27 14:39:34 -0700131}
Alexander Afanasyev75088672014-07-14 11:58:30 -0700132
Davide Pesavento8db61522019-01-11 16:44:50 -0500133BOOST_AUTO_TEST_CASE(GenerateSecureBytes)
Yingdi Yu0b537b92015-08-27 14:39:34 -0700134{
135 // Kolmogorov-Smirnov Goodness-of-Fit Test
136 // http://www.itl.nist.gov/div898/handbook/eda/section3/eda35g.htm
137
Davide Pesavento8db61522019-01-11 16:44:50 -0500138 std::array<uint8_t, 1024> buf;
139 random::generateSecureBytes(buf.data(), buf.size());
Yingdi Yu0b537b92015-08-27 14:39:34 -0700140
141 std::vector<uint32_t> counts(256, 0);
Davide Pesavento8db61522019-01-11 16:44:50 -0500142 for (size_t i = 0; i < buf.size(); i++) {
Yingdi Yu0b537b92015-08-27 14:39:34 -0700143 counts[buf[i]]++;
Alexander Afanasyev75088672014-07-14 11:58:30 -0700144 }
145
146 // Check if it is uniform distribution with confidence 0.95
147 // http://dlc.erieri.com/onlinetextbook/index.cfm?fuseaction=textbook.appendix&FileName=Table7
Davide Pesavento8db61522019-01-11 16:44:50 -0500148 BOOST_CHECK_LE(getDeviation(counts, buf.size()), 0.230);
Alexander Afanasyev75088672014-07-14 11:58:30 -0700149}
150
Yingdi Yu0b537b92015-08-27 14:39:34 -0700151// This fixture uses OpenSSL routines to set a dummy random generator that always fails
152class FailRandMethodFixture
153{
154public:
155 FailRandMethodFixture()
156 : m_dummyRandMethod{&FailRandMethodFixture::seed,
157 &FailRandMethodFixture::bytes,
158 &FailRandMethodFixture::cleanup,
159 &FailRandMethodFixture::add,
160 &FailRandMethodFixture::pseudorand,
161 &FailRandMethodFixture::status}
162 {
163 m_origRandMethod = RAND_get_rand_method();
164 RAND_set_rand_method(&m_dummyRandMethod);
165 }
166
167 ~FailRandMethodFixture()
168 {
169 RAND_set_rand_method(m_origRandMethod);
170 }
171
172private: // RAND_METHOD callbacks
Alexander Afanasyev02948ec2016-09-12 18:04:50 -0700173#if OPENSSL_VERSION_NUMBER < 0x1010000fL
Yingdi Yu0b537b92015-08-27 14:39:34 -0700174 static void
175 seed(const void* buf, int num)
176 {
177 }
Alexander Afanasyev02948ec2016-09-12 18:04:50 -0700178#else
179 static int
180 seed(const void* buf, int num)
181 {
182 return 0;
183 }
184#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
Yingdi Yu0b537b92015-08-27 14:39:34 -0700185
186 static int
Davide Pesavento74daf742018-11-23 18:14:13 -0500187 bytes(unsigned char* buf, int num)
Yingdi Yu0b537b92015-08-27 14:39:34 -0700188 {
189 return 0;
190 }
191
192 static void
193 cleanup()
194 {
195 }
196
Alexander Afanasyev02948ec2016-09-12 18:04:50 -0700197#if OPENSSL_VERSION_NUMBER < 0x1010000fL
Yingdi Yu0b537b92015-08-27 14:39:34 -0700198 static void
Davide Pesavento74daf742018-11-23 18:14:13 -0500199 add(const void* buf, int num, double entropy)
Yingdi Yu0b537b92015-08-27 14:39:34 -0700200 {
201 }
Alexander Afanasyev02948ec2016-09-12 18:04:50 -0700202#else
203 static int
Davide Pesavento74daf742018-11-23 18:14:13 -0500204 add(const void* buf, int num, double entropy)
Alexander Afanasyev02948ec2016-09-12 18:04:50 -0700205 {
206 return 0;
207 }
208#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
Yingdi Yu0b537b92015-08-27 14:39:34 -0700209
210 static int
Davide Pesavento74daf742018-11-23 18:14:13 -0500211 pseudorand(unsigned char* buf, int num)
Yingdi Yu0b537b92015-08-27 14:39:34 -0700212 {
213 return 0;
214 }
215
216 static int
217 status()
218 {
219 return 0;
220 }
221
222private:
223 const RAND_METHOD* m_origRandMethod;
224 RAND_METHOD m_dummyRandMethod;
225};
226
227BOOST_FIXTURE_TEST_CASE(Error, FailRandMethodFixture)
228{
Davide Pesavento8db61522019-01-11 16:44:50 -0500229 std::array<uint8_t, 1024> buf;
230 BOOST_CHECK_THROW(random::generateSecureBytes(buf.data(), buf.size()), std::runtime_error);
Yingdi Yu0b537b92015-08-27 14:39:34 -0700231}
232
233BOOST_AUTO_TEST_SUITE_END() // TestRandom
234BOOST_AUTO_TEST_SUITE_END() // Util
Alexander Afanasyev75088672014-07-14 11:58:30 -0700235
Spyridon Mastorakis429634f2015-02-19 17:35:33 -0800236} // namespace tests
Alexander Afanasyev75088672014-07-14 11:58:30 -0700237} // namespace ndn