Feed environment data into RNG initializers #17270

pull sipa wants to merge 11 commits into bitcoin:master from sipa:201910_seedrandom changing 11 files +611 −108
  1. sipa commented at 1:26 am on October 27, 2019: member

    This introduces a new randomenv module that queries varies non-cryptographic (and non-RNG) sources of entropy available on the system; things like user IDs, system configuration, time, statistics, CPUID data.

    The idea is that these provide a fallback in scenarios where system entropy is somehow broken (note that if system entropy fails we will abort regardless; this is only meant to function as a last resort against undetected failure). It includes some data sources OpenSSL currently uses, and more.

    The separation between random and randomenv is a bit arbitrary, but I felt that all this “non-essential” functionality deserved to be separated from the core random module.

  2. DrahtBot added the label Build system on Oct 27, 2019
  3. meshcollider removed the label Build system on Oct 27, 2019
  4. meshcollider added the label Utils/log/libs on Oct 27, 2019
  5. sipa force-pushed on Oct 27, 2019
  6. sipa force-pushed on Oct 27, 2019
  7. sipa force-pushed on Oct 27, 2019
  8. sipa force-pushed on Oct 27, 2019
  9. DrahtBot commented at 2:24 am on October 27, 2019: member

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #12557 ([WIP] 64 bit iOS device support by Sjors)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  10. in src/randomenv.cpp:361 in 0c6d5cb1f7 outdated
    213+    hasher << x;
    214+#endif
    215+
    216+#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
    217+    AddCPUID(hasher);
    218+#endif
    


    laanwj commented at 9:39 am on October 27, 2019:
    To also have CPU features bits for other architectures (on Linux) you could include getauxval(AT_HWCAP) and getauxval(AT_HWCAP2). (maybe some other getauxval are relevant too, e.g. AT_RANDOM has 16 bytes of random data)

    sipa commented at 8:05 pm on October 27, 2019:
    Good idea, added!
  11. laanwj commented at 10:19 am on October 27, 2019: member

    Errors on MacOSX (looks like it doesn’t have environ and CLOCK_MONOTONIC):

     0andomenv.cpp:177:19: error: use of undeclared identifier 'CLOCK_MONOTONIC'
     1    clock_gettime(CLOCK_MONOTONIC, &ts);
     2randomenv.cpp:222:64: error: use of undeclared identifier 'environ'
     3    hasher << &x << &RandAddStaticEnv << &malloc << &errno << &environ << addr;                                                
     4randomenv.cpp:282:9: error: use of undeclared identifier 'environ'
     5    if (environ) {
     6randomenv.cpp:283:28: error: use of undeclared identifier 'environ'
     7        for (size_t i = 0; environ[i]; ++i) {
     8randomenv.cpp:284:48: error: use of undeclared identifier 'environ'; did you mean 'union'?
     9            hasher.Write((const unsigned char*)environ[i], strlen(environ[i]));
    10                                               ^~~~~~~
    11                                               union
    12randomenv.cpp:284:48: error: expected expression
    13randomenv.cpp:284:67: error: use of undeclared identifier 'environ'
    14            hasher.Write((const unsigned char*)environ[i], strlen(environ[i]));
    15                                                                 ^
    167 errors generated.
    
  12. sipa force-pushed on Oct 27, 2019
  13. sipa force-pushed on Oct 27, 2019
  14. practicalswift commented at 8:30 pm on October 27, 2019: contributor
    Concept ACK: good idea
  15. sipa force-pushed on Oct 27, 2019
  16. sipa force-pushed on Oct 27, 2019
  17. sipa commented at 9:34 pm on October 27, 2019: member
    I think I’ve addressed a compatibility/build issues. Can someone try this on OSX, and perhaps some BSD flavor?
  18. RandyMcMillan commented at 10:56 pm on October 27, 2019: contributor
  19. promag commented at 8:37 am on October 28, 2019: member
    Concept ACK, nice commit sequence.
  20. fanquake commented at 2:13 pm on October 28, 2019: member

    Can someone try this on OSX, and perhaps some BSD flavor?

    I get the following error when building eed8cfec452a538d644844fb96606e6bc24f47c8 on OpenBSD 6.6:

     0  CXX      libbitcoin_util_a-randomenv.o
     1In file included from randomenv.cpp:37:
     2/usr/include/netinet/ip.h:67:19: error: field has incomplete type 'struct in_addr'
     3        struct    in_addr ip_src, ip_dst; /* source and dest address */
     4                          ^
     5/usr/include/netinet/ip.h:67:11: note: forward declaration of 'in_addr'
     6        struct    in_addr ip_src, ip_dst; /* source and dest address */
     7                  ^
     8/usr/include/netinet/ip.h:67:27: error: field has incomplete type 'struct in_addr'
     9        struct    in_addr ip_src, ip_dst; /* source and dest address */
    10                                  ^
    11/usr/include/netinet/ip.h:67:11: note: forward declaration of 'in_addr'
    12        struct    in_addr ip_src, ip_dst; /* source and dest address */
    13                  ^
    14/usr/include/netinet/ip.h:181:19: error: field has incomplete type 'struct in_addr'
    15                        struct in_addr ipt_addr;
    16                                       ^
    17/usr/include/netinet/ip.h:67:11: note: forward declaration of 'in_addr'
    18        struct    in_addr ip_src, ip_dst; /* source and dest address */
    19                  ^
    20randomenv.cpp:101:57: error: unknown type name 'sockaddr_in'; did you mean 'sockaddr'?
    21        hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in));
    22                                                        ^~~~~~~~~~~
    23                                                        sockaddr
    24/usr/include/sys/socket.h:207:8: note: 'sockaddr' declared here
    25struct sockaddr {
    26       ^
    27randomenv.cpp:104:57: error: unknown type name 'sockaddr_in6'; did you mean 'sockaddr'?
    28        hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in6));
    29                                                        ^~~~~~~~~~~~
    30                                                        sockaddr
    31/usr/include/sys/socket.h:207:8: note: 'sockaddr' declared here
    32struct sockaddr {
    33       ^
    345 errors generated.
    
  21. laanwj commented at 3:37 pm on October 28, 2019: member

    Log on FreeBSD 12.0-RELEASE-p10 (same complaint, about sockaddr)

     0Making all in src
     1gmake[1]: Entering directory '/usr/home/user/src/bitcoin/src'
     2gmake[2]: Entering directory '/usr/home/user/src/bitcoin/src'
     3  CXX      libbitcoin_util_a-randomenv.o
     4In file included from randomenv.cpp:37:
     5/usr/include/netinet/ip.h:71:17: error: field has incomplete type 'struct in_addr'
     6        struct  in_addr ip_src,ip_dst;  /* source and dest address */
     7                        ^
     8/usr/include/netinet/ip.h:71:9: note: forward declaration of 'in_addr'
     9        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    10                ^
    11/usr/include/netinet/ip.h:71:24: error: field has incomplete type 'struct in_addr'
    12        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    13                               ^
    14/usr/include/netinet/ip.h:71:9: note: forward declaration of 'in_addr'
    15        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    16                ^
    17/usr/include/netinet/ip.h:188:19: error: field has incomplete type 'struct in_addr'
    18                        struct in_addr ipt_addr;
    19                                       ^
    20/usr/include/netinet/ip.h:71:9: note: forward declaration of 'in_addr'
    21        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    22                ^
    23/usr/include/netinet/ip.h:223:17: error: field has incomplete type 'struct in_addr'
    24        struct  in_addr ippseudo_src;   /* source internet address */
    25                        ^
    26/usr/include/netinet/ip.h:71:9: note: forward declaration of 'in_addr'
    27        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    28                ^
    29/usr/include/netinet/ip.h:224:17: error: field has incomplete type 'struct in_addr'
    30        struct  in_addr ippseudo_dst;   /* destination internet address */
    31                        ^
    32/usr/include/netinet/ip.h:71:9: note: forward declaration of 'in_addr'
    33        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    34                ^
    35randomenv.cpp:101:57: error: unknown type name 'sockaddr_in'; did you mean 'sockaddr'?
    36        hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in));
    37                                                        ^~~~~~~~~~~
    38                                                        sockaddr
    39/usr/include/sys/socket.h:328:8: note: 'sockaddr' declared here
    40struct sockaddr {
    41       ^
    42randomenv.cpp:104:57: error: unknown type name 'sockaddr_in6'; did you mean 'sockaddr'?
    43        hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in6));
    44                                                        ^~~~~~~~~~~~
    45                                                        sockaddr
    46/usr/include/sys/socket.h:328:8: note: 'sockaddr' declared here
    47struct sockaddr {
    48       ^
    497 errors generated.
    50gmake[2]: *** [Makefile:8866: libbitcoin_util_a-randomenv.o] Error 1
    51gmake[2]: Leaving directory '/usr/home/user/src/bitcoin/src'
    52gmake[1]: *** [Makefile:14135: all-recursive] Error 1
    53gmake[1]: Leaving directory '/usr/home/user/src/bitcoin/src'
    54gmake: *** [Makefile:774: all-recursive] Error 1
    
  22. MarcoFalke commented at 3:37 pm on October 28, 2019: member
  23. MarcoFalke commented at 3:50 pm on October 28, 2019: member
    Does the comment in random.h need to be updated?
  24. fanquake commented at 3:58 pm on October 28, 2019: member

    Does the comment in random.h need to be updated?

    If that is updated, you could also cherry-pick https://github.com/bitcoin/bitcoin/pull/17265/commits/770cd9640e8b38d3456527bdf3d84b589cbd3418 out of #17265 which contains some related corrections.

  25. sipa force-pushed on Oct 28, 2019
  26. sipa force-pushed on Oct 28, 2019
  27. sipa force-pushed on Oct 28, 2019
  28. sipa force-pushed on Oct 28, 2019
  29. MarcoFalke commented at 6:41 pm on October 28, 2019: member
  30. MarcoFalke commented at 7:28 pm on October 28, 2019: member

    New freeBSD build failure: https://cirrus-ci.com/task/4712584309112832?command=make#L761

     0/usr/local/bin/ccache c++ -std=c++11 -DHAVE_CONFIG_H -I. -I../src/config   -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -I. -I/tmp/cirrus-ci-build/db4/include -DBOOST_SP_USE_STD_ATOMIC -DBOOST_AC_USE_STD_ATOMIC -pthread -I/usr/local/include -I./leveldb/include -I./leveldb/helpers/memenv -I/usr/local/include  -I./secp256k1/include -I./univalue/include -Qunused-arguments  -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS  -Wstack-protector -fstack-protector-all -Wall -Wextra -Wformat -Wvla -Wswitch -Wformat-security -Wthread-safety-analysis -Wrange-loop-analysis -Wredundant-decls -Wno-unused-parameter -Wno-self-assign -Wno-unused-local-typedef -Wno-deprecated-register -Wno-implicit-fallthrough    -fPIE -g -O2 -c -o libbitcoin_util_a-randomenv.o `test -f 'randomenv.cpp' || echo './'`randomenv.cpp
     1In file included from randomenv.cpp:29:
     2/usr/include/netinet/ip.h:53:2: error: unknown type name 'u_char'; did you mean 'char'?
     3        u_char  ip_hl:4,                /* header length */
     4        ^
     5/usr/include/netinet/ip.h:60:2: error: unknown type name 'u_char'; did you mean 'char'?
     6        u_char  ip_tos;                 /* type of service */
     7        ^
     8/usr/include/netinet/ip.h:61:2: error: unknown type name 'u_short'; did you mean 'short'?
     9        u_short ip_len;                 /* total length */
    10        ^
    11/usr/include/netinet/ip.h:62:2: error: unknown type name 'u_short'; did you mean 'short'?
    12        u_short ip_id;                  /* identification */
    13        ^
    14/usr/include/netinet/ip.h:63:2: error: unknown type name 'u_short'; did you mean 'short'?
    15        u_short ip_off;                 /* fragment offset field */
    16        ^
    17/usr/include/netinet/ip.h:68:2: error: unknown type name 'u_char'; did you mean 'char'?
    18        u_char  ip_ttl;                 /* time to live */
    19        ^
    20/usr/include/netinet/ip.h:69:2: error: unknown type name 'u_char'; did you mean 'char'?
    21        u_char  ip_p;                   /* protocol */
    22        ^
    23/usr/include/netinet/ip.h:70:2: error: unknown type name 'u_short'; did you mean 'short'?
    24        u_short ip_sum;                 /* checksum */
    25        ^
    26/usr/include/netinet/ip.h:71:17: error: field has incomplete type 'struct in_addr'
    27        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    28                        ^
    29/usr/include/netinet/ip.h:71:9: note: forward declaration of 'in_addr'
    30        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    31                ^
    32/usr/include/netinet/ip.h:71:24: error: field has incomplete type 'struct in_addr'
    33        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    34                               ^
    35/usr/include/netinet/ip.h:71:9: note: forward declaration of 'in_addr'
    36        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    37                ^
    38/usr/include/netinet/ip.h:174:2: error: unknown type name 'u_char'; did you mean 'char'?
    39        u_char  ipt_code;               /* IPOPT_TS */
    40        ^
    41/usr/include/netinet/ip.h:175:2: error: unknown type name 'u_char'; did you mean 'char'?
    42        u_char  ipt_len;                /* size of structure (variable) */
    43        ^
    44/usr/include/netinet/ip.h:176:2: error: unknown type name 'u_char'; did you mean 'char'?
    45        u_char  ipt_ptr;                /* index of current entry */
    46        ^
    47/usr/include/netinet/ip.h:178:2: error: unknown type name 'u_char'; did you mean 'char'?
    48        u_char  ipt_flg:4,              /* flags, see below */
    49        ^
    50/usr/include/netinet/ip.h:188:19: error: field has incomplete type 'struct in_addr'
    51                        struct in_addr ipt_addr;
    52                                       ^
    53/usr/include/netinet/ip.h:71:9: note: forward declaration of 'in_addr'
    54        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    55                ^
    56/usr/include/netinet/ip.h:223:17: error: field has incomplete type 'struct in_addr'
    57        struct  in_addr ippseudo_src;   /* source internet address */
    58                        ^
    59/usr/include/netinet/ip.h:71:9: note: forward declaration of 'in_addr'
    60        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    61                ^
    62/usr/include/netinet/ip.h:224:17: error: field has incomplete type 'struct in_addr'
    63        struct  in_addr ippseudo_dst;   /* destination internet address */
    64                        ^
    65/usr/include/netinet/ip.h:71:9: note: forward declaration of 'in_addr'
    66        struct  in_addr ip_src,ip_dst;  /* source and dest address */
    67                ^
    68/usr/include/netinet/ip.h:225:2: error: unknown type name 'u_char'; did you mean 'char'?
    69        u_char          ippseudo_pad;   /* pad, must be zero */
    70        ^
    71/usr/include/netinet/ip.h:226:2: error: unknown type name 'u_char'; did you mean 'char'?
    72        u_char          ippseudo_p;     /* protocol */
    73        ^
    74fatal error: too many errors emitted, stopping now [-ferror-limit=]
    7520 errors generated.
    76gmake[2]: *** [Makefile:8866: libbitcoin_util_a-randomenv.o] Error 1
    77gmake[2]: Leaving directory '/tmp/cirrus-ci-build/src'
    78gmake[1]: *** [Makefile:14135: install-recursive] Error 1
    79gmake[1]: Leaving directory '/tmp/cirrus-ci-build/src'
    80gmake: *** [Makefile:774: install-recursive] Error 1
    81Exit status: 2
    
  31. sipa force-pushed on Oct 28, 2019
  32. MarcoFalke commented at 8:49 pm on October 28, 2019: member
  33. sipa commented at 9:09 pm on October 28, 2019: member
    @MarcoFalke Hmm, “checking whether sysctlbyname is declared… no”. Does FreeBSD not have sysctlbyname?
  34. fanquake commented at 10:19 pm on October 28, 2019: member

    MarcoFalke Hmm, “checking whether sysctlbyname is declared… no”. Does FreeBSD not have sysctlbyname?

    It does, looks like you’ll just need to include sys/types.h as well. See the sysctlbyname docs.

    After including sys/types.hI’ve tested using 12.0-RELEASE-p6 and see sysctlbyname is declared... yes.

  35. sipa force-pushed on Oct 28, 2019
  36. MarcoFalke commented at 1:40 pm on October 29, 2019: member
  37. jamesob commented at 4:02 pm on October 29, 2019: member
    Concept ACK. I have to review more closely, but how do we detect situations “where system entropy is somehow broken”? Are these sources now unconditionally rolled into our seeding process?
  38. sipa commented at 4:05 pm on October 29, 2019: member

    @jamesob They’re undetectable in general.

    To clarify: I mean situations where system entropy is broken, for example because /dev/urandum is initialized to just 2^32 possible states and nothing new is fed into it. An attacker who knows this could predict the random numbers you’re going to generate, by simply looping over all 2^32 possibilities and comparing them with your output.

    This is generally not detectable, unless it’s a very extreme case (with no entropy whatsoever, say, and all reads from /dev/urandom or similar produce the same output). There is also not anything we can do to fix it; it’s a terrible bug if it happens, but fixing it requires discovering and fixing the root cause.

    What this PR does is add in a bunch of environment data (e.g. interrupt statistics, resource usage statistics, pids, …) that would make the situation slightly less bad in such a case - perhaps enough to make it non-attackable. But it’s not a fix.

  39. in src/crypto/sha256.cpp:12 in 35cfbf7587 outdated
     7@@ -8,15 +8,14 @@
     8 #include <assert.h>
     9 #include <string.h>
    10 
    11+#include <compat/cpuid.h>
    12+
    13 #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
    14-#if defined(USE_ASM)
    


    Sjors commented at 4:51 pm on October 29, 2019:
    Are you sure you don’t need to keep if defined(USE_ASM) around for void Transform(?

    sipa commented at 6:14 pm on October 29, 2019:
    Fixed.
  40. MarcoFalke commented at 5:27 pm on October 29, 2019: member
    For obviously broken cases (e.g. the random number generator returns a constant) it is possible to detect it with automated tools that apply heuristics such as those described in https://web.archive.org/web/20110602194701/http://users.eecs.northwestern.edu/~nickle/310/2010/headRuns.pdf . However, these tools can only hint at potential problems and never certify correctness. See https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-22r1a.pdf for an example of such a tool. That tool only works for long sequences, so it doesn’t seem applicable to the sources added here… Not to mention the randomness sources added in this pull request are non-cryptographic, so any slightly sane tool would immediately yell at them.
  41. Sjors commented at 5:29 pm on October 29, 2019: member

    Code review ACK on the move-only stuff up to 35cfbf7 Move cpuid code from random & sha256 to compat/cpuid. Concept ACK on the followup commits that add more sources (5a078e2); looks sane, but not sure how to review.

    I’m able to run the test suite on macOS 10.15 (using MACOSX_DEPLOYMENT_TARGET=10.14 to avoid https://github.com/bitcoin-core/secp256k1/issues/674).

  42. sipa force-pushed on Oct 29, 2019
  43. sipa commented at 7:42 pm on October 29, 2019: member

    A bunch of updates over the past days:

    • Cherry-picked https://github.com/bitcoin/bitcoin/commit/770cd9640e8b38d3456527bdf3d84b589cbd3418
    • Added a moveonly commit to merge the cpuid code in random and crypto/sha256, making it reusable for randomenv.
    • Added a commit to use getauxval on Linux.
    • Added a commit to use sysctlbyname on BSD/MacOS.
    • Added a commit to make sure dynamic env seeders do not run more than once per minute, and added a scheduled task to make sure they do get run occasionally.
    • Added a commit to fix a bug in the perfmon seeder (now that it can be called from multiple threads, it may need an atomic to track the previous run time).
  44. gmaxwell commented at 8:40 pm on October 29, 2019: contributor

    A reminder that this sort of thing is important: Some ryzen cpus rng returns a constant (and success), and in default configs linux relies on it for many purposes (I think, /dev/random in current default kernel configs mostly manages to dodge the over-reliance, but many other things do– so it’s a narrow miss.)

    https://arstechnica.com/gadgets/2019/10/how-a-months-old-amd-microcode-bug-destroyed-my-weekend/

  45. laanwj commented at 1:26 pm on October 30, 2019: member

    Travis error on mingw:

    0randomenv.cpp: In function void {anonymous}::RandAddSeedPerfmon(CSHA512&):
    1randomenv.cpp:63:33: error: variable std::atomic<long long int> last_perfmon has initializer but incomplete type
    2     static std::atomic<int64_t> last_perfmon{0};
    3                                 ^~~~~~~~~~~~
    
  46. sipa force-pushed on Oct 30, 2019
  47. in src/randomenv.cpp:66 in ad09ad707e outdated
    65-    if (GetTime() < nLastPerfmon + 10 * 60)
    66-        return;
    67-    nLastPerfmon = GetTime();
    68+    static std::atomic<int64_t> last_perfmon{0};
    69+    int64_t last_time = last_perfmon.load();
    70+    int64_t current_time = GetTime();
    


    MarcoFalke commented at 8:15 pm on October 30, 2019:

    in commit ad09ad707e0ed6e3a537e1a204843792e5d06108:

    GetTime is deprecated (see https://dev.visucore.com/bitcoin/doxygen/time_8cpp.html#a350f99e2a13df31f2afbd7f80ab21a5e). I guess you wanted to use GetSystemTimeInSeconds


    MarcoFalke commented at 8:16 pm on October 30, 2019:
    GetTime<std::chrono::seconds>() can’t hurt here either, as far as I can tell

    sipa commented at 11:03 pm on October 30, 2019:
    Fixed. Also done elsewhere in the previous commit.
  48. sipa force-pushed on Oct 30, 2019
  49. in src/randomenv.cpp:276 in 8a27be0fb0 outdated
    218+    }
    219+
    220+#ifdef __linux__
    221+    AddFile(hasher, "/proc/diskstats");
    222+    AddFile(hasher, "/proc/vmstat");
    223+    AddFile(hasher, "/proc/schedstat");
    


    fanquake commented at 3:02 pm on October 31, 2019:
    I think this should be /proc/self/schedstat

    sipa commented at 6:34 pm on October 31, 2019:
    It seems both exist.
  50. in src/randomenv.cpp:278 in 8a27be0fb0 outdated
    228+    AddFile(hasher, "/proc/self/status");
    229+#endif
    230+#endif
    231+
    232+    AddSysctl(hasher, "vm.loadavg");
    233+    AddSysctl(hasher, "vm.swapusage");
    


    fanquake commented at 3:18 pm on October 31, 2019:
    Note vm.swapusage seems to be macOS only. I can’t find it on OpenBSD or FreeBSD.

    sipa commented at 6:35 pm on October 31, 2019:
    That’s ok; I combined lists of sysctls listed for various platforms. Not all will exist on each.
  51. in src/randomenv.cpp:343 in 8a27be0fb0 outdated
    338+    AddFile(hasher, "/etc/group");
    339+    AddFile(hasher, "/etc/hosts");
    340+    AddFile(hasher, "/etc/resolv.conf");
    341+    AddFile(hasher, "/etc/timezone");
    342+    AddFile(hasher, "/etc/localtime");
    343+    AddFile(hasher, "/etc/hostconfig");
    


    fanquake commented at 3:23 pm on October 31, 2019:
    I couldn’t find /etc/hostconfig on any of the platforms I tested (macOS, *BSD, Linux). Seems it used to exist on at least macOS, but was removed in 10.10.

    sipa commented at 6:36 pm on October 31, 2019:
    Ok, removing.
  52. in src/randomenv.cpp:273 in 8a27be0fb0 outdated
    268+#  endif
    269+#  ifdef AT_HWCAP2
    270+    hasher << getauxval(AT_HWCAP2);
    271+#  endif
    272+#  ifdef AT_RANDOM
    273+    hasher << getauxval(AT_RANDOM);
    


    laanwj commented at 3:24 pm on October 31, 2019:
    getauxval(AT_RANDOM), if present, returns a pointer to 16 bytes of random data; it’s not itself random data

    sipa commented at 6:49 pm on October 31, 2019:
    Fixed.
  53. in src/randomenv.cpp:234 in 8a27be0fb0 outdated
    200+#else
    201+#  ifdef __MACH__
    202+    hasher << mach_absolute_time();
    203+#  else
    204+    struct timespec ts;
    205+    clock_gettime(CLOCK_MONOTONIC, &ts);
    


    fanquake commented at 3:45 pm on October 31, 2019:
    It looks like upstream OpenSSL uses CLOCK_REALTIME when generating a timestamp. Could you explain why CLOCK_MONOTONIC is the better choice for us? I assume it’s TODO with it being less manipulable and kernel compatibility?

    sipa commented at 6:36 pm on October 31, 2019:
    I’m expanding this piece of code to just use all clocks available.
  54. in src/randomenv.cpp:202 in 8a27be0fb0 outdated
    197+    FILETIME ftime;
    198+    GetSystemTimeAsFileTime(&ftime);
    199+    hasher << ftime;
    200+#else
    201+#  ifdef __MACH__
    202+    hasher << mach_absolute_time();
    


    fanquake commented at 3:47 pm on October 31, 2019:
    There’s not a heap of documentation on mach_absolute_time and I can’t find any calls to it in recent OpenSSL, however looks like it’s available for macOS versions > 10.9. /usr/include/mach/mach_time.h.

    sipa commented at 6:37 pm on October 31, 2019:
    Yeah, I tried to find an equivalent to CLOCK_MONOTONIC on MacOS, and found this. It doesn’t exactly match what OpenSSL did.
  55. fanquake commented at 3:48 pm on October 31, 2019: member

    Concept ACK

    sysctlbyname isn’t being picked up on OpenBSD (works on macOS and FreeBSD). Will investigate.

    I’ve pushed some WIP review notes up to https://github.com/fanquake/bitcoin/tree/17270_annotated.

  56. fanquake commented at 6:38 pm on October 31, 2019: member

    sysctlbyname isn’t being picked up on OpenBSD (works on macOS and FreeBSD). Will investigate.

    Looks like it doesn’t actually exist on OpenBSD. It only has sysctl. On OpenBSD 6.6:

    0bazinga# cat sysctl.h | grep sysctlbyname
    1bazinga# cat sysctl.h | grep "sysctl("
    2 * pairs to be used by sysctl(1) in manipulating the subsystem.
    3 * aggregated into an array in debug_sysctl(), so that it can
    4int kern_sysctl(int *, u_int, void *, size_t *, void *, size_t,
    5int hw_sysctl(int *, u_int, void *, size_t *, void *, size_t,
    6< trimmed >
    7int mpls_sysctl(int *, u_int, void *, size_t *, void *, size_t);
    8int	sysctl(const int *, u_int, void *, size_t *, void *, size_t);
    
  57. sipa force-pushed on Oct 31, 2019
  58. sipa commented at 6:48 pm on October 31, 2019: member

    Addressed the comments above (AT_RANDOM gives a pointer, removed /etc/hostconfig, added a comment that not all sysctls are available on every system).

    Also added:

    • Added more clocks (they’re gathered once a minute, some redundancy won’t hurt).
    • Improved the CPUID code (also adds extended leaves now)
    • Added compiler version string (__VERSION__).
    • Added Bitcoin Core version information (CLIENT_VERSION, CLIENT_NAME, CLIENT_BUILD).
  59. sipa commented at 6:49 pm on October 31, 2019: member
    @fanquake Ok, annoying. Perhaps that means we should use sysctl instead of sysctlbyname.
  60. laanwj commented at 10:59 am on November 1, 2019: member
    Changes now look good to me. Tested on Linux RISC-V 64 bit w/ no issues.
  61. sipa force-pushed on Nov 1, 2019
  62. sipa commented at 10:51 pm on November 1, 2019: member
    Replaced the use of sysctlbyname by sysctl; it’s less extensive and needs more code, but likely supports more systems.
  63. sipa force-pushed on Nov 1, 2019
  64. sipa force-pushed on Nov 1, 2019
  65. sipa force-pushed on Nov 2, 2019
  66. sipa force-pushed on Nov 2, 2019
  67. sipa force-pushed on Nov 2, 2019
  68. sipa force-pushed on Nov 2, 2019
  69. sipa force-pushed on Nov 2, 2019
  70. in src/randomenv.cpp:174 in d78a49906f outdated
    169+#endif
    170+
    171+template<int... S>
    172+void AddSysctl(CSHA512& hasher)
    173+{
    174+#if HAVE_DECL_SYSCTL
    


    laanwj commented at 9:26 am on November 5, 2019:
    Shouldn’t this ifdef be outside the function instead of outside it? I mean, I don’t think it should be possible to call AddSysctl on systems without sysctl?

    sipa commented at 11:10 pm on November 5, 2019:
    Fixed.
  71. in src/randomenv.cpp:251 in d78a49906f outdated
    246+    // and clock_get_time for CALENDAR_CLOCK as a replacement for CLOCK_REALTIME.
    247+    hasher << mach_absolute_time();
    248+    // From https://gist.github.com/jbenet/1087739
    249+    clock_serv_t cclock;
    250+    mach_timespec_t mts;
    251+    host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
    


    laanwj commented at 9:27 am on November 5, 2019:
    could creating the service fail? is there a return value to handle here?

    sipa commented at 11:09 pm on November 5, 2019:
    Fixed.
  72. laanwj commented at 9:32 am on November 5, 2019: member
    it’s pretty hard to verify that this is doing anything, at runtime; it would be too much hassle to keep track of everything that is hashed, but it would be nice to have (optionally enabled. category RAND?) summarizing debug log messages like; N bytes of static environment data added to random state N bytes of dynamic environment data added to random state
  73. sipa force-pushed on Nov 5, 2019
  74. in src/randomenv.cpp:138 in 95f1642930 outdated
    133+        }
    134+        do {
    135+            n = read(f, fbuf, sizeof(fbuf));
    136+            if (n > 0) hasher.Write(fbuf, n);
    137+            /* not bothering with EINTR handling. */
    138+        } while (n == sizeof(fbuf));
    


    narula commented at 11:10 pm on November 5, 2019:
    Might you consider only reading up to a certain number of bytes? I’m not sure you’re guaranteed that some of these files won’t be enormous.

    sipa commented at 11:18 pm on November 5, 2019:
    Done.
  75. sipa force-pushed on Nov 5, 2019
  76. sipa commented at 11:19 pm on November 5, 2019: member
    @laanwj I’ve added a commit that logs the number of bytes gathered.
  77. in src/randomenv.cpp:112 in f14cd41976 outdated
    107+}
    108+
    109+/** Helper to easily feed data into a CSHA512.
    110+ *
    111+ * Note that this does not serialize the passed object (like stream.h's << operators do).
    112+ * Its raw memory representation is used directly.
    


    madars commented at 11:49 pm on November 5, 2019:
    Should we make this comment explicitly enforced, e.g. having static_assert(!std::is_same<T, char*>::value, "calling hasher.operator<< on char* probably won't do what you want"); or similar?

    laanwj commented at 11:54 pm on November 5, 2019:
    it’s only defined in this cpp file, where the hasher is only used for one thing, so the scope for potential accidental misuse is very little (and who knows, maybe you’d want to hash a pointer here, if it’s random enough due to ASLR)

    sipa commented at 0:01 am on November 6, 2019:
    There are plenty of internal pointers being fed to the RNG here (stack locations, standard library locations, …).

    madars commented at 0:08 am on November 6, 2019:
    They don’t appear to be char* pointers (e.g. environ is char**, result of a temp malloc below is void*, etc) but potential for misuse is a judgement call.

    sipa commented at 0:10 am on November 6, 2019:
    Ah, good point. Let’s see if that compiles.

    sipa commented at 0:16 am on November 6, 2019:
    Done. I added std::decay<T> so that it also catches const char* and char arrays.
  78. sipa force-pushed on Nov 6, 2019
  79. sipa force-pushed on Nov 6, 2019
  80. sipa force-pushed on Nov 6, 2019
  81. sipa force-pushed on Nov 7, 2019
  82. sipa force-pushed on Nov 7, 2019
  83. laanwj added this to the "Blockers" column in a project

  84. laanwj commented at 4:52 pm on November 10, 2019: member

    Tested on a few different platforms;

    FreeBSD x86_64:

    02019-11-10T13:02:15Z Feeding 66012 of dynamic environment data into RNG
    12019-11-10T13:02:15Z Feeding 10350 bytes of static environment data into RNG
    

    Linux x86_64 VM:

    02019-11-10T15:33:02Z Feeding 16094 of dynamic environment data into RNG
    12019-11-10T15:33:02Z Feeding 14944 bytes of static environment data into RNG
    

    Linux aarch64:

    02019-11-10T16:18:13Z Feeding 11043 of dynamic environment data into RNG
    12019-11-10T16:18:13Z Feeding 7073 bytes of static environment data into RNG
    

    Linux arm32:

    02019-11-10T15:52:06Z Feeding 10921 of dynamic environment data into RNG
    12019-11-10T15:52:06Z Feeding 8906 bytes of static environment data into RNG
    

    Linux riscv64:

    02019-11-10T16:50:38Z Feeding 10389 of dynamic environment data into RNG
    12019-11-10T16:50:38Z Feeding 6833 bytes of static environment data into RNG
    

    New compile warning (gcc Linux):

    0In file included from randomenv.cpp:50:
    1/usr/include/sys/sysctl.h:21:2: warning: #warning "The <sys/sysctl.h> header is deprecated and will be removed." [-Wcpp]
    2   21 | #warning "The <sys/sysctl.h> header is deprecated and will be removed."
    3      |  ^~~~~~~
    

    Looks this was a recent libc/kernel change (http://patches-tcwg.linaro.org/patch/19443/). I don’t think the intent is to use sysctl on Linux (it already reads /proc directly, which is what they suggest instead), so we might want to prevent its detection there somehow.

    (omeone might want to check on a musl-libc based system, all of these Linux is glibc based)

  85. sipa commented at 7:29 pm on November 10, 2019: member
    Added a commit to always avoids sysctl on Linux.
  86. in src/randomenv.cpp:49 in 1d1200f6b2 outdated
    45@@ -46,6 +46,7 @@
    46 #if HAVE_DECL_GETIFADDRS
    47 #include <ifaddrs.h>
    48 #endif
    49+#ifndef __linux__
    


    laanwj commented at 10:58 am on November 12, 2019:
    Thanks! Though, I’d slightly prefer to handle this in the build system, so that the symbol HAVE_DECL_SYSCTL doesn’t get set in the first place in Linux. This avoids having to handle it on a case by case basis on all caller sites.

    sipa commented at 10:51 pm on November 12, 2019:
    Good point, fixed.
  87. in src/randomenv.cpp:142 in 1d1200f6b2 outdated
    138+    }
    139+}
    140+
    141+void AddStat(CSHA512& hasher, const struct stat& sb)
    142+{
    143+    hasher << sb.st_dev << sb.st_ino << sb.st_mode << sb.st_nlink << sb.st_uid << sb.st_gid << sb.st_size << sb.st_blksize << sb.st_blocks << sb.st_atime << sb.st_mtime << sb.st_ctime;
    


    TheBlueMatt commented at 5:23 pm on November 12, 2019:
    Hmm, we here write a struct timeval directly into the hasher, but in other places we avoid it by writing the fields. I presume the avoiding it cases are to avoid writing padding bytes into the hasher (otherwise why both)?

    sipa commented at 10:56 pm on November 12, 2019:
    One reason to writing the fields directly is because these structures may have implementation-defined other fields, which are perhaps left uninitialized. Feeding them into the hasher would then trip up valgrind & co. Perhaps this is not a real concern and we should just feed the struct in until someone notices a problem?

    sipa commented at 11:43 pm on November 12, 2019:
    Ok, fixed: I’m zero initializing all the structs, and then just feeding them directly into the hasher.

    TheBlueMatt commented at 1:42 am on November 13, 2019:
    I can’t say I feel strongly. I see reasons to do it both ways, and as long as valgrind doesn’t complain and we hash in the higher-entropy bits, it doesn’t matter either way. Just figured I’d flag it since you appeared to be very careful about it in all places but here.
  88. in src/random.cpp:577 in 2f4aaf1327 outdated
    602@@ -585,6 +603,9 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level)
    603     case RNGLevel::SLEEP:
    604         SeedSleep(hasher, rng);
    605         break;
    606+    case RNGLevel::PERIODIC:
    


    TheBlueMatt commented at 6:34 pm on November 12, 2019:

    I don’t get the point of this commit. You’re avoiding doing something that sleeps 1ms but runs in a tight loop for 10ms. The real meat of the function gets called on a timer every minute, but also my be called at other times, but only runs if its been 10 minutes since the last run.

    Maybe we should just skip the SeedInfrequent call in SeedSleep and then we can drop all the once-per-minute checking in this file wholesale and use the scheduler?


    sipa commented at 10:58 pm on November 12, 2019:
    I think you’re right, there is fairly little advantage to having both RandAddSeedSleep and RandAddPeriodic. I’ve redone this PR to instead just have a RandAddPeriodic, which indeed simplifies a bunch of things including not keeping track of when the last run of the expensive stuff was (there is a still a counter in the perfmon data for windows, which only runs once every 10 minutes instead of every minute).
  89. TheBlueMatt commented at 6:34 pm on November 12, 2019: member
    Awesome work! One real comment, but otherwise looks good.
  90. doc: minor corrections in random.cpp
    This should have been part of #17151.
    b51bae1a5a
  91. [MOVEONLY] Move perfmon data gathering to new randomenv module cea3902015
  92. [MOVEONLY] Move cpuid code from random & sha256 to compat/cpuid 723c796667
  93. Seed randomness with process id / thread id / various clocks
    This sort of data is also used by OpenSSL.
    c2a262a78c
  94. sipa force-pushed on Nov 12, 2019
  95. Gather additional entropy from the environment
    This based on code by Gregory Maxwell.
    2554c1b81b
  96. Use sysctl for seeding on MacOS/BSD a81c494b4c
  97. Feed CPUID data into RNG 11793ea22e
  98. Add information gathered through getauxval()
    Suggested by Wladimir van der Laan.
    483b94292e
  99. Run background seeding periodically instead of unpredictably
    * Instead of calling RandAddSeedSleep anytime the scheduler goes
      idle, call its replacement (RandAddSeedPeriodic) just once per
      minute. This has better guarantees of actually being run, and
      helps limit how frequently the dynamic env data is gathered.
    * Since this code runs once per minute regardless now, we no
      longer need to keep track of the last time strengthening was
      run; just do it always.
    * Make strengthening time context dependent (100 ms at startup,
      10 ms once per minute afterwards).
    d61f2bb076
  100. Use thread-safe atomic in perfmon seeder
    Also switch to chrono based types.
    64e1e022ce
  101. Report amount of data gathered from environment d1c02775aa
  102. sipa force-pushed on Nov 12, 2019
  103. TheBlueMatt commented at 1:44 am on November 13, 2019: member
    utACK d1c02775aa74a0610809ac54bb241ddad61d2d8c. Certainly no longer measuring the time elapsed between a 1ms sleep (which got removed in the latest change) is a fair tradeoff for adding about 2 million other actually-higher-entropy bits :).
  104. fanquake commented at 1:10 am on November 14, 2019: member

    I’ve been testing d1c02775aa74a0610809ac54bb241ddad61d2d8c across various operating systems. Few logs for anyone who’s interested. Will post a final review shortly.

    macOS 10.14.6

    02019-11-13T18:24:03Z Feeding 1066350 bytes of environment data into RNG
    12019-11-13T18:25:03Z Feeding 216 bytes of dynamic environment data into RNG
    22019-11-13T18:26:03Z Feeding 216 bytes of dynamic environment data into RNG
    

    OpenBSD 6.6

    02019-11-13T19:21:17Z Feeding 9334 bytes of environment data into RNG
    12019-11-13T19:22:18Z Feeding 504 bytes of dynamic environment data into RNG
    22019-11-13T19:23:18Z Feeding 504 bytes of dynamic environment data into RNG
    

    FreeBSD 12

    02019-11-13T21:04:50Z Feeding 74253 bytes of environment data into RNG
    12019-11-13T21:05:51Z Feeding 66068 bytes of dynamic environment data into RNG
    22019-11-13T21:06:51Z Feeding 66068 bytes of dynamic environment data into RNG
    

    Windows 10 WSL

    02019-11-13T23:05:00Z Feeding 435111 bytes of environment data into RNG
    12019-11-13T23:06:00Z Feeding 48 bytes of dynamic environment data into RNG
    22019-11-13T23:07:00Z Feeding 48 bytes of dynamic environment data into RNG
    

    Windows 10 MSVC

    02019-11-13T23:16:08Z Feeding 378764 bytes of environment data into RNG
    12019-11-13T23:17:08Z Feeding 48 bytes of dynamic environment data into RNG
    22019-11-13T23:18:08Z Feeding 48 bytes of dynamic environment data into RNG
    

    NetBSD 8.1

    02019-11-13T23:50:05Z Feeding 35503 bytes of environment data into RNG
    12019-11-13T23:51:05Z Feeding 28268 bytes of dynamic environment data into RNG
    22019-11-13T23:52:05Z Feeding 28268 bytes of dynamic environment data into RNG
    

    Alpine

    02019-11-14T00:45:33Z Feeding 23631 bytes of environment data into RNG
    12019-11-14T00:46:33Z Feeding 14196 bytes of dynamic environment data into RNG
    22019-11-14T00:47:33Z Feeding 14206 bytes of dynamic environment data into RNG
    32019-11-14T00:48:33Z Feeding 14208 bytes of dynamic environment data into RNG
    42019-11-14T00:49:33Z Feeding 14211 bytes of dynamic environment data into RNG
    

    Debian 10

    02019-11-14T00:21:13Z Feeding 23714 bytes of environment data into RNG
    12019-11-14T00:22:13Z Feeding 13980 bytes of dynamic environment data into RNG
    22019-11-14T00:23:13Z Feeding 13983 bytes of dynamic environment data into RNG
    32019-11-14T00:24:13Z Feeding 13991 bytes of dynamic environment data into RNG
    42019-11-14T00:25:13Z Feeding 13988 bytes of dynamic environment data into RNG
    52019-11-14T00:26:13Z Feeding 13993 bytes of dynamic environment data into RNG
    62019-11-14T00:27:13Z Feeding 14024 bytes of dynamic environment data into RNG
    
  105. in src/randomenv.cpp:230 in d1c02775aa
    225+#ifdef WIN32
    226+    FILETIME ftime;
    227+    GetSystemTimeAsFileTime(&ftime);
    228+    hasher << ftime;
    229+#else
    230+#  ifndef __MACH__
    


    fanquake commented at 1:30 am on November 14, 2019:
    Using __MACH__ here and above is unusual for a our codebase, we use MAC_OSX throughout. Also __MACH__ by itself isn’t necessarily macOS, looks like if you were to use it you’d want to couple it with __APPLE__.
  106. in src/randomenv.cpp:246 in d1c02775aa
    241+#    ifdef CLOCK_BOOTTIME
    242+    clock_gettime(CLOCK_BOOTTIME, &ts);
    243+    hasher << ts;
    244+#    endif
    245+#  else
    246+    // On MacOS use mach_absolute_time (number of CPU ticks since boot) as a replacement for CLOCK_MONOTONIC,
    


    fanquake commented at 1:39 am on November 14, 2019:
    After #16392 (bumping our SDK and minimum required macOS to 10.12), clock_gettime, CLOCK_REALTIME and CLOCK_MONOTONIC will be available to use on macOS. Not necessarily anything that needs to change here now, but the potential to simplify this later.
  107. fanquake commented at 1:58 am on November 14, 2019: member
    I think the changes here should be sufficient that we can remove our OpenSSL usage (#17265). This is now likely doing above and beyond what (depends) OpenSSL was doing. I prefer the recent refactor to RandAddPeriodic and removing the RandAdd call from scheduler.cpp. I’ve done some sanity checking across various operating systems.
  108. laanwj commented at 12:21 pm on November 18, 2019: member

    ACK d1c02775aa74a0610809ac54bb241ddad61d2d8c

    I agree with @fanquake. I think this is good for merge. It has been tested on a wide range of platforms, and unarguably works.

    Additional bits of entropy for specific arch and OS can be added later.

  109. laanwj referenced this in commit 0bb37e437e on Nov 18, 2019
  110. laanwj merged this on Nov 18, 2019
  111. laanwj closed this on Nov 18, 2019

  112. fanquake removed this from the "Blockers" column in a project

  113. fanquake referenced this in commit 461e547877 on Nov 18, 2019
  114. fanquake referenced this in commit 55b2cb199c on Nov 18, 2019
  115. sidhujag referenced this in commit 436bc5c466 on Nov 18, 2019
  116. laanwj referenced this in commit f6e42256fe on Nov 23, 2019
  117. laanwj referenced this in commit 2eeacdfe44 on Nov 24, 2019
  118. sidhujag referenced this in commit 7f69c42e6f on Nov 24, 2019
  119. MarcoFalke referenced this in commit e6f167bfdf on Nov 25, 2019
  120. sidhujag referenced this in commit 912a39b439 on Nov 25, 2019
  121. laanwj referenced this in commit 6fff333c9f on Dec 5, 2019
  122. sidhujag referenced this in commit 9189c75128 on Dec 6, 2019
  123. luke-jr referenced this in commit 52a65504b1 on Feb 18, 2020
  124. luke-jr referenced this in commit bdcfaa3318 on Feb 18, 2020
  125. laanwj referenced this in commit 1a51cd1ac5 on Feb 28, 2020
  126. sidhujag referenced this in commit 639537df89 on Feb 29, 2020
  127. HashUnlimited referenced this in commit 7f9303bb8f on Apr 17, 2020
  128. HashUnlimited referenced this in commit ece4c4901e on Apr 17, 2020
  129. HashUnlimited referenced this in commit f46cd87683 on Apr 17, 2020
  130. deadalnix referenced this in commit 48bfb8cc7a on May 20, 2020
  131. deadalnix referenced this in commit 8726d6cac1 on May 21, 2020
  132. deadalnix referenced this in commit 180f05083c on May 21, 2020
  133. deadalnix referenced this in commit df747e1aa4 on May 21, 2020
  134. deadalnix referenced this in commit 9cb83a17b9 on May 21, 2020
  135. deadalnix referenced this in commit d977136bf4 on May 21, 2020
  136. deadalnix referenced this in commit 192d4bb47c on May 22, 2020
  137. deadalnix referenced this in commit 05debbcdd0 on May 22, 2020
  138. deadalnix referenced this in commit 88aae1e037 on May 22, 2020
  139. deadalnix referenced this in commit 5ff89a0754 on May 22, 2020
  140. deadalnix referenced this in commit fcd7977a3e on May 22, 2020
  141. ftrader referenced this in commit 088155a5d6 on Aug 17, 2020
  142. sidhujag referenced this in commit 1b77769612 on Nov 10, 2020
  143. sidhujag referenced this in commit c14e5d9cf9 on Nov 10, 2020
  144. sidhujag referenced this in commit f569979667 on Nov 10, 2020
  145. sidhujag referenced this in commit 23b2206654 on Nov 10, 2020
  146. sidhujag referenced this in commit 45b75873ec on Nov 10, 2020
  147. backpacker69 referenced this in commit 7e08ff49c1 on Mar 28, 2021
  148. backpacker69 referenced this in commit 9787f54aef on Mar 28, 2021
  149. backpacker69 referenced this in commit 94a4e59524 on Mar 28, 2021
  150. Fuzzbawls referenced this in commit f70e0c8437 on Mar 31, 2021
  151. Fuzzbawls referenced this in commit 60cb1599e4 on Mar 31, 2021
  152. Fuzzbawls referenced this in commit 78d66f8399 on Mar 31, 2021
  153. Fuzzbawls referenced this in commit 2b754ac493 on Mar 31, 2021
  154. Fuzzbawls referenced this in commit bd59763482 on Mar 31, 2021
  155. Fuzzbawls referenced this in commit 09fbf93cc9 on Mar 31, 2021
  156. Fuzzbawls referenced this in commit 81d382fc5b on Apr 14, 2021
  157. Fuzzbawls referenced this in commit 88c2ae5f6e on Apr 14, 2021
  158. random-zebra referenced this in commit 93f43f0f81 on Apr 14, 2021
  159. furszy referenced this in commit 826ecb479a on May 1, 2021
  160. furszy referenced this in commit 1b5c73d66e on May 1, 2021
  161. furszy referenced this in commit 32473aab90 on May 1, 2021
  162. furszy referenced this in commit f0b48a848f on May 1, 2021
  163. furszy referenced this in commit 8d798981fa on May 1, 2021
  164. furszy referenced this in commit b8d4c8ed61 on May 1, 2021
  165. furszy referenced this in commit 1c91570ed7 on May 3, 2021
  166. Fabcien referenced this in commit c85ed4043d on Aug 27, 2021
  167. PastaPastaPasta referenced this in commit b184989b4d on Sep 17, 2021
  168. thelazier referenced this in commit 45c6fd5823 on Sep 25, 2021
  169. MarcoFalke locked this on Dec 16, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-07-03 10:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me