Page MenuHomePhabricator

D490.diff
No OneTemporary

D490.diff

diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -606,6 +606,8 @@
#include <byteswap.h>
#endif])
+AC_CHECK_DECLS([__builtin_clz, __builtin_clzl, __builtin_clzll])
+
dnl Check for MSG_NOSIGNAL
AC_MSG_CHECKING(for MSG_NOSIGNAL)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],
diff --git a/src/Makefile.am b/src/Makefile.am
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -250,6 +250,8 @@
crypto_libbitcoin_crypto_a_SOURCES = \
crypto/aes.cpp \
crypto/aes.h \
+ crypto/chacha20.h \
+ crypto/chacha20.cpp \
crypto/common.h \
crypto/hmac_sha256.cpp \
crypto/hmac_sha256.h \
diff --git a/src/addrman.h b/src/addrman.h
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -143,13 +143,13 @@
*/
//! total number of buckets for tried addresses
-#define ADDRMAN_TRIED_BUCKET_COUNT 256
+#define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8
//! total number of buckets for new addresses
-#define ADDRMAN_NEW_BUCKET_COUNT 1024
+#define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10
//! maximum allowed number of entries in buckets for new and tried addresses
-#define ADDRMAN_BUCKET_SIZE 64
+#define ADDRMAN_BUCKET_SIZE_LOG2 6
//! over how many buckets entries with tried addresses from a single group (/16
//! for IPv4) are spread
@@ -181,6 +181,11 @@
//! the maximum number of nodes to return in a getaddr call
#define ADDRMAN_GETADDR_MAX 2500
+//! Convenience
+#define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2)
+#define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2)
+#define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2)
+
/**
* Stochastical (IP) address manager
*/
diff --git a/src/addrman.cpp b/src/addrman.cpp
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -349,17 +349,22 @@
int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT);
int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
while (vvTried[nKBucket][nKBucketPos] == -1) {
- nKBucket = (nKBucket + insecure_rand.rand32()) %
- ADDRMAN_TRIED_BUCKET_COUNT;
- nKBucketPos = (nKBucketPos + insecure_rand.rand32()) %
- ADDRMAN_BUCKET_SIZE;
+ nKBucket =
+ (nKBucket +
+ insecure_rand.randbits(ADDRMAN_TRIED_BUCKET_COUNT_LOG2)) %
+ ADDRMAN_TRIED_BUCKET_COUNT;
+ nKBucketPos =
+ (nKBucketPos +
+ insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) %
+ ADDRMAN_BUCKET_SIZE;
}
int nId = vvTried[nKBucket][nKBucketPos];
assert(mapInfo.count(nId) == 1);
CAddrInfo &info = mapInfo[nId];
if (RandomInt(1 << 30) <
- fChanceFactor * info.GetChance() * (1 << 30))
+ fChanceFactor * info.GetChance() * (1 << 30)) {
return info;
+ }
fChanceFactor *= 1.2;
}
} else {
@@ -369,10 +374,14 @@
int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
while (vvNew[nUBucket][nUBucketPos] == -1) {
- nUBucket = (nUBucket + insecure_rand.rand32()) %
- ADDRMAN_NEW_BUCKET_COUNT;
- nUBucketPos = (nUBucketPos + insecure_rand.rand32()) %
- ADDRMAN_BUCKET_SIZE;
+ nUBucket =
+ (nUBucket +
+ insecure_rand.randbits(ADDRMAN_NEW_BUCKET_COUNT_LOG2)) %
+ ADDRMAN_NEW_BUCKET_COUNT;
+ nUBucketPos =
+ (nUBucketPos +
+ insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) %
+ ADDRMAN_BUCKET_SIZE;
}
int nId = vvNew[nUBucket][nUBucketPos];
assert(mapInfo.count(nId) == 1);
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -62,7 +62,7 @@
prevector<PREVECTOR_SIZE, uint8_t> p;
PrevectorJob() {}
PrevectorJob(FastRandomContext &insecure_rand) {
- p.resize(insecure_rand.rand32() % (PREVECTOR_SIZE * 2));
+ p.resize(insecure_rand.randrange(PREVECTOR_SIZE * 2));
}
bool operator()() { return true; }
void swap(PrevectorJob &x) { p.swap(x.p); };
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -11,6 +11,7 @@
#include "crypto/sha256.h"
#include "crypto/sha512.h"
#include "hash.h"
+#include "random.h"
#include "uint256.h"
#include "utiltime.h"
@@ -63,6 +64,26 @@
}
}
+static void FastRandom_32bit(benchmark::State &state) {
+ FastRandomContext rng(true);
+ uint32_t x;
+ while (state.KeepRunning()) {
+ for (int i = 0; i < 1000000; i++) {
+ x += rng.rand32();
+ }
+ }
+}
+
+static void FastRandom_1bit(benchmark::State &state) {
+ FastRandomContext rng(true);
+ uint32_t x;
+ while (state.KeepRunning()) {
+ for (int i = 0; i < 1000000; i++) {
+ x += rng.randbool();
+ }
+ }
+}
+
BENCHMARK(RIPEMD160);
BENCHMARK(SHA1);
BENCHMARK(SHA256);
@@ -70,3 +91,5 @@
BENCHMARK(SHA256_32b);
BENCHMARK(SipHash_32b);
+BENCHMARK(FastRandom_32bit);
+BENCHMARK(FastRandom_1bit);
diff --git a/src/crypto/chacha20.h b/src/crypto/chacha20.h
new file mode 100644
--- /dev/null
+++ b/src/crypto/chacha20.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_CRYPTO_CHACHA20_H
+#define BITCOIN_CRYPTO_CHACHA20_H
+
+#include <cstdint>
+#include <cstdlib>
+
+/** A PRNG class for ChaCha20. */
+class ChaCha20 {
+private:
+ uint32_t input[16];
+
+public:
+ ChaCha20();
+ ChaCha20(const uint8_t *key, size_t keylen);
+ void SetKey(const uint8_t *key, size_t keylen);
+ void SetIV(uint64_t iv);
+ void Seek(uint64_t pos);
+ void Output(uint8_t *output, size_t bytes);
+};
+
+#endif // BITCOIN_CRYPTO_CHACHA20_H
diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp
new file mode 100644
--- /dev/null
+++ b/src/crypto/chacha20.cpp
@@ -0,0 +1,190 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+// Based on the public domain implementation 'merged' by D. J. Bernstein
+// See https://cr.yp.to/chacha.html.
+
+#include "crypto/chacha20.h"
+#include "crypto/common.h"
+
+#include <cstring>
+
+constexpr static inline uint32_t rotl32(uint32_t v, int c) {
+ return (v << c) | (v >> (32 - c));
+}
+
+#define QUARTERROUND(a, b, c, d) \
+ a += b; \
+ d = rotl32(d ^ a, 16); \
+ c += d; \
+ b = rotl32(b ^ c, 12); \
+ a += b; \
+ d = rotl32(d ^ a, 8); \
+ c += d; \
+ b = rotl32(b ^ c, 7);
+
+static const uint8_t sigma[] = "expand 32-byte k";
+static const uint8_t tau[] = "expand 16-byte k";
+
+void ChaCha20::SetKey(const uint8_t *k, size_t keylen) {
+ const uint8_t *constants;
+
+ input[4] = ReadLE32(k + 0);
+ input[5] = ReadLE32(k + 4);
+ input[6] = ReadLE32(k + 8);
+ input[7] = ReadLE32(k + 12);
+ if (keylen == 32) {
+ // recommended
+ k += 16;
+ constants = sigma;
+ } else {
+ // keylen == 16
+ constants = tau;
+ }
+ input[8] = ReadLE32(k + 0);
+ input[9] = ReadLE32(k + 4);
+ input[10] = ReadLE32(k + 8);
+ input[11] = ReadLE32(k + 12);
+ input[0] = ReadLE32(constants + 0);
+ input[1] = ReadLE32(constants + 4);
+ input[2] = ReadLE32(constants + 8);
+ input[3] = ReadLE32(constants + 12);
+ input[12] = 0;
+ input[13] = 0;
+ input[14] = 0;
+ input[15] = 0;
+}
+
+ChaCha20::ChaCha20() {
+ memset(input, 0, sizeof(input));
+}
+
+ChaCha20::ChaCha20(const uint8_t *k, size_t keylen) {
+ SetKey(k, keylen);
+}
+
+void ChaCha20::SetIV(uint64_t iv) {
+ input[14] = iv;
+ input[15] = iv >> 32;
+}
+
+void ChaCha20::Seek(uint64_t pos) {
+ input[12] = pos;
+ input[13] = pos >> 32;
+}
+
+void ChaCha20::Output(uint8_t *c, size_t bytes) {
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14,
+ x15;
+ uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14,
+ j15;
+ uint8_t *ctarget = nullptr;
+ uint8_t tmp[64];
+ unsigned int i;
+
+ if (!bytes) {
+ return;
+ }
+
+ j0 = input[0];
+ j1 = input[1];
+ j2 = input[2];
+ j3 = input[3];
+ j4 = input[4];
+ j5 = input[5];
+ j6 = input[6];
+ j7 = input[7];
+ j8 = input[8];
+ j9 = input[9];
+ j10 = input[10];
+ j11 = input[11];
+ j12 = input[12];
+ j13 = input[13];
+ j14 = input[14];
+ j15 = input[15];
+
+ for (;;) {
+ if (bytes < 64) {
+ ctarget = c;
+ c = tmp;
+ }
+ x0 = j0;
+ x1 = j1;
+ x2 = j2;
+ x3 = j3;
+ x4 = j4;
+ x5 = j5;
+ x6 = j6;
+ x7 = j7;
+ x8 = j8;
+ x9 = j9;
+ x10 = j10;
+ x11 = j11;
+ x12 = j12;
+ x13 = j13;
+ x14 = j14;
+ x15 = j15;
+ for (i = 20; i > 0; i -= 2) {
+ QUARTERROUND(x0, x4, x8, x12)
+ QUARTERROUND(x1, x5, x9, x13)
+ QUARTERROUND(x2, x6, x10, x14)
+ QUARTERROUND(x3, x7, x11, x15)
+ QUARTERROUND(x0, x5, x10, x15)
+ QUARTERROUND(x1, x6, x11, x12)
+ QUARTERROUND(x2, x7, x8, x13)
+ QUARTERROUND(x3, x4, x9, x14)
+ }
+ x0 += j0;
+ x1 += j1;
+ x2 += j2;
+ x3 += j3;
+ x4 += j4;
+ x5 += j5;
+ x6 += j6;
+ x7 += j7;
+ x8 += j8;
+ x9 += j9;
+ x10 += j10;
+ x11 += j11;
+ x12 += j12;
+ x13 += j13;
+ x14 += j14;
+ x15 += j15;
+
+ ++j12;
+ if (!j12) {
+ ++j13;
+ }
+
+ WriteLE32(c + 0, x0);
+ WriteLE32(c + 4, x1);
+ WriteLE32(c + 8, x2);
+ WriteLE32(c + 12, x3);
+ WriteLE32(c + 16, x4);
+ WriteLE32(c + 20, x5);
+ WriteLE32(c + 24, x6);
+ WriteLE32(c + 28, x7);
+ WriteLE32(c + 32, x8);
+ WriteLE32(c + 36, x9);
+ WriteLE32(c + 40, x10);
+ WriteLE32(c + 44, x11);
+ WriteLE32(c + 48, x12);
+ WriteLE32(c + 52, x13);
+ WriteLE32(c + 56, x14);
+ WriteLE32(c + 60, x15);
+
+ if (bytes <= 64) {
+ if (bytes < 64) {
+ for (i = 0; i < bytes; ++i) {
+ ctarget[i] = c[i];
+ }
+ }
+ input[12] = j12;
+ input[13] = j13;
+ return;
+ }
+ bytes -= 64;
+ c += 64;
+ }
+}
diff --git a/src/crypto/common.h b/src/crypto/common.h
--- a/src/crypto/common.h
+++ b/src/crypto/common.h
@@ -69,4 +69,27 @@
memcpy(ptr, (char *)&v, 8);
}
+/**
+ * Return the smallest number n such that (x >> n) == 0 (or 64 if the highest
+ * bit in x is set.
+ */
+uint64_t static inline CountBits(uint64_t x) {
+#ifdef HAVE_DECL___BUILTIN_CLZL
+ if (sizeof(unsigned long) >= sizeof(uint64_t)) {
+ return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
+ }
+#endif
+#ifdef HAVE_DECL___BUILTIN_CLZLL
+ if (sizeof(unsigned long long) >= sizeof(uint64_t)) {
+ return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;
+ }
+#endif
+ int ret = 0;
+ while (x) {
+ x >>= 1;
+ ++ret;
+ }
+ return ret;
+}
+
#endif // BITCOIN_CRYPTO_COMMON_H
diff --git a/src/net.h b/src/net.h
--- a/src/net.h
+++ b/src/net.h
@@ -778,7 +778,7 @@
// after addresses were pushed.
if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) {
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
- vAddrToSend[insecure_rand.rand32() % vAddrToSend.size()] =
+ vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] =
_addr;
} else {
vAddrToSend.push_back(_addr);
diff --git a/src/random.h b/src/random.h
--- a/src/random.h
+++ b/src/random.h
@@ -6,6 +6,8 @@
#ifndef BITCOIN_RANDOM_H
#define BITCOIN_RANDOM_H
+#include "crypto/chacha20.h"
+#include "crypto/common.h"
#include "uint256.h"
#include <cstdint>
@@ -33,17 +35,81 @@
* This class is not thread-safe.
*/
class FastRandomContext {
+private:
+ bool requires_seed;
+ ChaCha20 rng;
+
+ uint8_t 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;
+ }
+
public:
explicit FastRandomContext(bool fDeterministic = false);
- uint32_t rand32() {
- Rz = 36969 * (Rz & 65535) + (Rz >> 16);
- Rw = 18000 * (Rw & 65535) + (Rw >> 16);
- return (Rw << 16) + Rz;
+ /** 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;
+ }
}
- uint32_t Rz;
- uint32_t Rw;
+ /** 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); }
};
/**
diff --git a/src/random.cpp b/src/random.cpp
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -239,21 +239,15 @@
return hash;
}
-FastRandomContext::FastRandomContext(bool fDeterministic) {
- // The seed values have some unlikely fixed points which we avoid.
- if (fDeterministic) {
- Rz = Rw = 11;
- } else {
- uint32_t tmp;
- do {
- GetRandBytes((uint8_t *)&tmp, 4);
- } while (tmp == 0 || tmp == 0x9068ffffU);
- Rz = tmp;
- do {
- GetRandBytes((uint8_t *)&tmp, 4);
- } while (tmp == 0 || tmp == 0x464fffffU);
- Rw = tmp;
- }
+void FastRandomContext::RandomSeed() {
+ uint256 seed = GetRandHash();
+ rng.SetKey(seed.begin(), 32);
+ requires_seed = false;
+}
+
+FastRandomContext::FastRandomContext(const uint256 &seed)
+ : requires_seed(false), bytebuf_size(0), bitbuf_size(0) {
+ rng.SetKey(seed.begin(), 32);
}
bool Random_SanityCheck() {
@@ -288,3 +282,12 @@
/* If this failed, bailed out after too many tries */
return (num_overwritten == NUM_OS_RANDOM_BYTES);
}
+
+FastRandomContext::FastRandomContext(bool fDeterministic)
+ : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0) {
+ if (!fDeterministic) {
+ return;
+ }
+ uint256 seed;
+ rng.SetKey(seed.begin(), 32);
+}
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -185,10 +185,11 @@
BOOST_CHECK(addrman.size() == 7);
// Test 12: Select pulls from new and tried regardless of port number.
- BOOST_CHECK(addrman.Select().ToString() == "250.4.6.6:8333");
- BOOST_CHECK(addrman.Select().ToString() == "250.3.2.2:9999");
- BOOST_CHECK(addrman.Select().ToString() == "250.3.3.3:9999");
- BOOST_CHECK(addrman.Select().ToString() == "250.4.4.4:8333");
+ std::set<uint16_t> ports;
+ for (int i = 0; i < 20; ++i) {
+ ports.insert(addrman.Select().GetPort());
+ }
+ BOOST_CHECK_EQUAL(ports.size(), 3);
}
BOOST_AUTO_TEST_CASE(addrman_new_collisions) {
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -3,12 +3,14 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "crypto/aes.h"
+#include "crypto/chacha20.h"
#include "crypto/hmac_sha256.h"
#include "crypto/hmac_sha512.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
#include "crypto/sha512.h"
+#include "random.h"
#include "test/test_bitcoin.h"
#include "test/test_random.h"
#include "utilstrencodings.h"
@@ -210,6 +212,19 @@
}
}
+void TestChaCha20(const std::string &hexkey, uint64_t nonce, uint64_t seek,
+ const std::string &hexout) {
+ std::vector<uint8_t> key = ParseHex(hexkey);
+ ChaCha20 rng(key.data(), key.size());
+ rng.SetIV(nonce);
+ rng.Seek(seek);
+ std::vector<uint8_t> out = ParseHex(hexout);
+ std::vector<uint8_t> outres;
+ outres.resize(out.size());
+ rng.Output(outres.data(), outres.size());
+ BOOST_CHECK(out == outres);
+}
+
std::string LongTestString(void) {
std::string ret;
for (int i = 0; i < 200000; i++) {
@@ -550,4 +565,67 @@
"b2eb05e2c39be9fcda6c19078c6a9d1b3f461796d6b0d6b2e0c2a72b4d80e644");
}
+BOOST_AUTO_TEST_CASE(chacha20_testvector) {
+ // Test vector from RFC 7539
+ TestChaCha20(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ 0x4a000000UL, 1, "224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fc"
+ "aec9ef3cf788a3b0aa372600a92b57974cded2b9334794cba40c6"
+ "3e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47"
+ "e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a832c89c167"
+ "eacd901d7e2bf363");
+
+ // Test vectors from
+ // https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7
+ TestChaCha20(
+ "0000000000000000000000000000000000000000000000000000000000000000", 0,
+ 0, "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da4"
+ "1597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586");
+ TestChaCha20(
+ "0000000000000000000000000000000000000000000000000000000000000001", 0,
+ 0, "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe"
+ "2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea817e9ad275ae546963");
+ TestChaCha20(
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ 0x0100000000000000ULL, 0, "de9cba7bf3d69ef5e786dc63973f653a0b49e015adbf"
+ "f7134fcb7df137821031e85a050278a7084527214f73"
+ "efc7fa5b5277062eb7a0433e445f41e3");
+ TestChaCha20(
+ "0000000000000000000000000000000000000000000000000000000000000000", 1,
+ 0, "ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111"
+ "e4caf237ee53ca8ad6426194a88545ddc497a0b466e7d6bbdb0041b2f586b");
+ TestChaCha20(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ 0x0706050403020100ULL, 0,
+ "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a454"
+ "7b733b46413042c9440049176905d3be59ea1c53f15916155c2be8241a38008b9a26bc"
+ "35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc118be563e"
+ "b9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a4750"
+ "32b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c507b138db853e3d"
+ "6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5360c3317166a1c89"
+ "4c94a371876a94df7628fe4eaaf2ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d"
+ "38407a6deb3ab78fab78c9");
+}
+
+BOOST_AUTO_TEST_CASE(countbits_tests) {
+ FastRandomContext ctx;
+ for (int i = 0; i <= 64; ++i) {
+ if (i == 0) {
+ // Check handling of zero.
+ BOOST_CHECK_EQUAL(CountBits(0), 0);
+ } else if (i < 10) {
+ for (uint64_t j = 1 << (i - 1); (j >> i) == 0; ++j) {
+ // Exhaustively test up to 10 bits
+ BOOST_CHECK_EQUAL(CountBits(j), i);
+ }
+ } else {
+ for (int k = 0; k < 1000; k++) {
+ // Randomly test 1000 samples of each length above 10 bits.
+ uint64_t j = uint64_t(1) << (i - 1) | ctx.randbits(i - 1);
+ BOOST_CHECK_EQUAL(CountBits(j), i);
+ }
+ }
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp
--- a/src/test/prevector_tests.cpp
+++ b/src/test/prevector_tests.cpp
@@ -28,6 +28,7 @@
typedef typename pretype::size_type Size;
bool passed = true;
FastRandomContext rand_cache;
+ uint256 rand_seed;
template <typename A, typename B> void local_check_equal(A a, B b) {
local_check(a == b);
@@ -178,13 +179,12 @@
}
~prevector_tester() {
- BOOST_CHECK_MESSAGE(passed,
- "insecure_rand_Rz: " << rand_cache.Rz
- << ", insecure_rand_Rw: "
- << rand_cache.Rw);
+ BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString());
}
+
prevector_tester() {
seed_insecure_rand();
+ rand_seed = insecure_rand_seed;
rand_cache = insecure_rand_ctx;
}
};
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
--- a/src/test/random_tests.cpp
+++ b/src/test/random_tests.cpp
@@ -14,4 +14,38 @@
BOOST_CHECK(Random_SanityCheck());
}
+BOOST_AUTO_TEST_CASE(fastrandom_tests) {
+ // Check that deterministic FastRandomContexts are deterministic
+ FastRandomContext ctx1(true);
+ FastRandomContext ctx2(true);
+
+ BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
+ BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
+ BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64());
+ BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
+ BOOST_CHECK_EQUAL(ctx1.randbits(7), ctx2.randbits(7));
+ BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
+ BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
+
+ // Check that a nondeterministic ones are not
+ FastRandomContext ctx3;
+ FastRandomContext ctx4;
+ // extremely unlikely to be equal
+ BOOST_CHECK(ctx3.rand64() != ctx4.rand64());
+}
+
+BOOST_AUTO_TEST_CASE(fastrandom_randbits) {
+ FastRandomContext ctx1;
+ FastRandomContext ctx2;
+ for (int bits = 0; bits < 63; ++bits) {
+ for (int j = 0; j < 1000; ++j) {
+ uint64_t rangebits = ctx1.randbits(bits);
+ BOOST_CHECK_EQUAL(rangebits >> bits, 0);
+ uint64_t range = uint64_t(1) << bits | rangebits;
+ uint64_t rand = ctx2.randrange(range);
+ BOOST_CHECK(rand < range);
+ }
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -32,7 +32,8 @@
#include <boost/thread.hpp>
std::unique_ptr<CConnman> g_connman;
-FastRandomContext insecure_rand_ctx(true);
+uint256 insecure_rand_seed = GetRandHash();
+FastRandomContext insecure_rand_ctx(insecure_rand_seed);
extern bool fPrintToConsole;
extern void noui_connect();
diff --git a/src/test/test_random.h b/src/test/test_random.h
--- a/src/test/test_random.h
+++ b/src/test/test_random.h
@@ -8,10 +8,16 @@
#include "random.h"
+extern uint256 insecure_rand_seed;
extern FastRandomContext insecure_rand_ctx;
static inline void seed_insecure_rand(bool fDeterministic = false) {
- insecure_rand_ctx = FastRandomContext(fDeterministic);
+ if (fDeterministic) {
+ insecure_rand_seed = uint256();
+ } else {
+ insecure_rand_seed = GetRandHash();
+ }
+ insecure_rand_ctx = FastRandomContext(insecure_rand_seed);
}
static inline uint32_t insecure_rand(void) {
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2320,7 +2320,7 @@
// degenerate behavior and it is important that the rng is fast.
// We do not use a constant random sequence, because there may
// be some privacy improvement by making the selection random.
- if (nPass == 0 ? insecure_rand.rand32() & 1 : !vfIncluded[i]) {
+ if (nPass == 0 ? insecure_rand.randbool() : !vfIncluded[i]) {
nTotal += vValue[i].first;
vfIncluded[i] = true;
if (nTotal >= nTargetValue) {

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 1, 10:11 (7 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5183032
Default Alt Text
D490.diff (25 KB)

Event Timeline