zcashd/src/random.h

165 lines
4.2 KiB
C
Raw Normal View History

// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
2014-12-12 20:09:33 -08:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
#ifndef BITCOIN_RANDOM_H
#define BITCOIN_RANDOM_H
#include "crypto/chacha20.h"
#include "crypto/common.h"
#include "uint256.h"
#include <functional>
#include <limits>
#include <stdint.h>
/**
* Functions to gather random data via the rand_core OsRng
*/
void GetRandBytes(unsigned char* buf, size_t num);
uint64_t GetRand(uint64_t nMax);
int GetRandInt(int nMax);
uint256 GetRandHash();
/**
* Implementation of a C++ Uniform Random Number Generator, backed by GetRandBytes.
*/
class ZcashRandomEngine
{
public:
typedef uint64_t result_type;
explicit ZcashRandomEngine() {}
static constexpr result_type min() {
return std::numeric_limits<result_type>::min();
}
static constexpr result_type max() {
return std::numeric_limits<result_type>::max();
}
result_type operator()() {
result_type nRand = 0;
GetRandBytes((unsigned char*)&nRand, sizeof(nRand));
return nRand;
}
double entropy() const noexcept {
return 0;
}
};
/**
* Identity function for MappedShuffle, so that elements retain their original order.
*/
int GenIdentity(int n);
/**
* Rearranges the elements in the range [first,first+len) randomly, assuming
* that gen is a uniform random number generator. Follows the same algorithm as
* std::shuffle in C++11 (a Durstenfeld shuffle).
*
* The elements in the range [mapFirst,mapFirst+len) are rearranged according to
* the same permutation, enabling the permutation to be tracked by the caller.
*
* gen takes an integer n and produces a uniform random output in [0,n).
*/
template <typename RandomAccessIterator, typename MapRandomAccessIterator>
void MappedShuffle(RandomAccessIterator first,
MapRandomAccessIterator mapFirst,
size_t len,
std::function<int(int)> gen)
{
for (size_t i = len-1; i > 0; --i) {
auto r = gen(i+1);
assert(r >= 0);
assert(r <= i);
std::swap(first[i], first[r]);
std::swap(mapFirst[i], mapFirst[r]);
}
}
/**
Kill insecure_random and associated global state There are only a few uses of `insecure_random` outside the tests. This PR replaces uses of insecure_random (and its accompanying global state) in the core code with an FastRandomContext that is automatically seeded on creation. This is meant to be used for inner loops. The FastRandomContext can be in the outer scope, or the class itself, then rand32() is used inside the loop. Useful e.g. for pushing addresses in CNode or the fee rounding, or randomization for coin selection. As a context is created per purpose, thus it gets rid of cross-thread unprotected shared usage of a single set of globals, this should also get rid of the potential race conditions. - I'd say TxMempool::check is not called enough to warrant using a special fast random context, this is switched to GetRand() (open for discussion...) - The use of `insecure_rand` in ConnectThroughProxy has been replaced by an atomic integer counter. The only goal here is to have a different credentials pair for each connection to go on a different Tor circuit, it does not need to be random nor unpredictable. - To avoid having a FastRandomContext on every CNode, the context is passed into PushAddress as appropriate. There remains an insecure_random for test usage in `test_random.h`. Zcash: Resolved conflicts with the following files src/addrman.cpp src/main.cpp src/net.cpp src/net.h src/policy/fees.cpp src/policy/fees.h src/random.cpp src/test/merkle_tests.cpp src/test/net_tests.cpp src/test/prevector_tests.cpp src/test/sighash_tests.cpp src/test/skiplist_tests.cpp src/test/test_bitcoin.cpp src/test/versionbits_tests.cpp src/wallet/test/crypto_tests.cpp
2016-10-13 07:19:20 -07:00
* Fast randomness source. This is seeded once with secure random data, but
* is completely deterministic and insecure after that.
* This class is not thread-safe.
*/
Kill insecure_random and associated global state There are only a few uses of `insecure_random` outside the tests. This PR replaces uses of insecure_random (and its accompanying global state) in the core code with an FastRandomContext that is automatically seeded on creation. This is meant to be used for inner loops. The FastRandomContext can be in the outer scope, or the class itself, then rand32() is used inside the loop. Useful e.g. for pushing addresses in CNode or the fee rounding, or randomization for coin selection. As a context is created per purpose, thus it gets rid of cross-thread unprotected shared usage of a single set of globals, this should also get rid of the potential race conditions. - I'd say TxMempool::check is not called enough to warrant using a special fast random context, this is switched to GetRand() (open for discussion...) - The use of `insecure_rand` in ConnectThroughProxy has been replaced by an atomic integer counter. The only goal here is to have a different credentials pair for each connection to go on a different Tor circuit, it does not need to be random nor unpredictable. - To avoid having a FastRandomContext on every CNode, the context is passed into PushAddress as appropriate. There remains an insecure_random for test usage in `test_random.h`. Zcash: Resolved conflicts with the following files src/addrman.cpp src/main.cpp src/net.cpp src/net.h src/policy/fees.cpp src/policy/fees.h src/random.cpp src/test/merkle_tests.cpp src/test/net_tests.cpp src/test/prevector_tests.cpp src/test/sighash_tests.cpp src/test/skiplist_tests.cpp src/test/test_bitcoin.cpp src/test/versionbits_tests.cpp src/wallet/test/crypto_tests.cpp
2016-10-13 07:19:20 -07:00
class FastRandomContext {
private:
bool requires_seed;
ChaCha20 rng;
unsigned char bytebuf[64];
int bytebuf_size;
uint64_t bitbuf;
int bitbuf_size;
void RandomSeed();
void FillByteBuffer()
{
if (requires_seed) {
RandomSeed();
}
rng.Output(bytebuf, sizeof(bytebuf));
bytebuf_size = sizeof(bytebuf);
}
void FillBitBuffer()
{
bitbuf = rand64();
bitbuf_size = 64;
Kill insecure_random and associated global state There are only a few uses of `insecure_random` outside the tests. This PR replaces uses of insecure_random (and its accompanying global state) in the core code with an FastRandomContext that is automatically seeded on creation. This is meant to be used for inner loops. The FastRandomContext can be in the outer scope, or the class itself, then rand32() is used inside the loop. Useful e.g. for pushing addresses in CNode or the fee rounding, or randomization for coin selection. As a context is created per purpose, thus it gets rid of cross-thread unprotected shared usage of a single set of globals, this should also get rid of the potential race conditions. - I'd say TxMempool::check is not called enough to warrant using a special fast random context, this is switched to GetRand() (open for discussion...) - The use of `insecure_rand` in ConnectThroughProxy has been replaced by an atomic integer counter. The only goal here is to have a different credentials pair for each connection to go on a different Tor circuit, it does not need to be random nor unpredictable. - To avoid having a FastRandomContext on every CNode, the context is passed into PushAddress as appropriate. There remains an insecure_random for test usage in `test_random.h`. Zcash: Resolved conflicts with the following files src/addrman.cpp src/main.cpp src/net.cpp src/net.h src/policy/fees.cpp src/policy/fees.h src/random.cpp src/test/merkle_tests.cpp src/test/net_tests.cpp src/test/prevector_tests.cpp src/test/sighash_tests.cpp src/test/skiplist_tests.cpp src/test/test_bitcoin.cpp src/test/versionbits_tests.cpp src/wallet/test/crypto_tests.cpp
2016-10-13 07:19:20 -07:00
}
public:
explicit FastRandomContext(bool fDeterministic = false);
/** Initialize with explicit seed (only for testing) */
explicit FastRandomContext(const uint256& seed);
/** Generate a random 64-bit integer. */
uint64_t rand64()
{
if (bytebuf_size < 8) FillByteBuffer();
uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size);
bytebuf_size -= 8;
return ret;
}
/** Generate a random (bits)-bit integer. */
uint64_t randbits(int bits) {
if (bits == 0) {
return 0;
} else if (bits > 32) {
return rand64() >> (64 - bits);
} else {
if (bitbuf_size < bits) FillBitBuffer();
uint64_t ret = bitbuf & (~(uint64_t)0 >> (64 - bits));
bitbuf >>= bits;
bitbuf_size -= bits;
return ret;
}
}
/** Generate a random integer in the range [0..range). */
uint64_t randrange(uint64_t range)
{
--range;
int bits = CountBits(range);
while (true) {
uint64_t ret = randbits(bits);
if (ret <= range) return ret;
}
}
/** Generate a random 32-bit integer. */
uint32_t rand32() { return randbits(32); }
/** Generate a random boolean. */
bool randbool() { return randbits(1); }
Kill insecure_random and associated global state There are only a few uses of `insecure_random` outside the tests. This PR replaces uses of insecure_random (and its accompanying global state) in the core code with an FastRandomContext that is automatically seeded on creation. This is meant to be used for inner loops. The FastRandomContext can be in the outer scope, or the class itself, then rand32() is used inside the loop. Useful e.g. for pushing addresses in CNode or the fee rounding, or randomization for coin selection. As a context is created per purpose, thus it gets rid of cross-thread unprotected shared usage of a single set of globals, this should also get rid of the potential race conditions. - I'd say TxMempool::check is not called enough to warrant using a special fast random context, this is switched to GetRand() (open for discussion...) - The use of `insecure_rand` in ConnectThroughProxy has been replaced by an atomic integer counter. The only goal here is to have a different credentials pair for each connection to go on a different Tor circuit, it does not need to be random nor unpredictable. - To avoid having a FastRandomContext on every CNode, the context is passed into PushAddress as appropriate. There remains an insecure_random for test usage in `test_random.h`. Zcash: Resolved conflicts with the following files src/addrman.cpp src/main.cpp src/net.cpp src/net.h src/policy/fees.cpp src/policy/fees.h src/random.cpp src/test/merkle_tests.cpp src/test/net_tests.cpp src/test/prevector_tests.cpp src/test/sighash_tests.cpp src/test/skiplist_tests.cpp src/test/test_bitcoin.cpp src/test/versionbits_tests.cpp src/wallet/test/crypto_tests.cpp
2016-10-13 07:19:20 -07:00
};
#endif // BITCOIN_RANDOM_H