Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.15.0 dev improve random upstream cherry picks #3487

Draft
wants to merge 9 commits into
base: 1.15.0-dev
Choose a base branch
from

Conversation

chromatic
Copy link
Member

This is a work in progress to cherry-pick some upstream randomization improvements (see #3229 for context).

sipa and others added 9 commits March 23, 2024 16:21
These are available in sandboxes without access to files or
devices. Also [they are safer and more straightforward](https://en.wikipedia.org/wiki/Entropy-supplying_system_calls)
to use than `/dev/urandom` as reading from a file has quite a few edge
cases:

- Linux: `getrandom(buf, buflen, 0)`. [getrandom(2)](http://man7.org/linux/man-pages/man2/getrandom.2.html)
  was introduced in version 3.17 of the Linux kernel.
- OpenBSD: `getentropy(buf, buflen)`. The [getentropy(2)](http://man.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2)
  function appeared in OpenBSD 5.6.
- FreeBSD and NetBSD: `sysctl(KERN_ARND)`. Not sure when this was added
  but it has existed for quite a while.

Alternatives:

- Linux has sysctl `CTL_KERN` / `KERN_RANDOM` / `RANDOM_UUID`
  which gives 16 bytes of randomness. This may be available
  on older kernels, however [sysctl is deprecated on Linux](https://lwn.net/Articles/605392/)
  and even removed in some distros so we shouldn't use it.

Add tests for `GetOSRand()`:

- Test that no error happens (otherwise `RandFailure()` which aborts)
- Test that all 32 bytes are overwritten (initialize with zeros, try multiple times)

Discussion:

- When to use these? Currently they are always used when available.
  Another option would be to use them only when `/dev/urandom` is not
  available. But this would mean these code paths receive less testing,
  and I'm not sure there is any reason to prefer `/dev/urandom`.

Closes: #9676
Move the OS random test to a sanity check function that is called every
time bitcoind is initialized.

Keep `src/test/random_tests.cpp` for the case that later random tests
are added, and keep a rudimentary test that just calls the sanity check.
If the code was compiled with newer (>=3.17) kernel headers but executed
on a system without the system call, every use of random would crash the
program. Add a fallback for that case.
@chromatic chromatic changed the base branch from master to 1.15.0-dev March 24, 2024 01:21
@patricklodder
Copy link
Member

I benched this on both an x86_64 Intel I7 and an arm64 Apple M1. Results:

On i7-970

Current FastRandomContext (at 8d4e0bd)

#Benchmark,count,min,max,average,min_cycles,max_cycles,average_cycles
FastRandom_1bit,640,0.001588508486748,0.001606859266758,0.001596468687057,5144478,5203874,5170219
FastRandom_32bit,640,0.001587942242622,0.001599781215191,0.001593051850796,5142448,5180947,5159149

New FastRandomContext (at 9c33a27)

#Benchmark,count,min,max,average,min_cycles,max_cycles,average_cycles
FastRandom_1bit,576,0.001762509346008,0.001951079815626,0.001785520878103,5707967,6318597,5782466
FastRandom_32bit,88,0.011499375104904,0.011546224355698,0.011518229137767,37241032,37393131,37302139

On Apple M1

Current FastRandomContext

#Benchmark,count,min,max,average,min_cycles,max_cycles,average_cycles
FastRandom_1bit,416,0.002500720322132,0.002539746463299,0.002514704488791,0,0,0
FastRandom_32bit,416,0.002498909831047,0.002532906830311,0.002507672860072,0,0,0

New FastRandomContext

#Benchmark,count,min,max,average,min_cycles,max_cycles,average_cycles
FastRandom_1bit,1280,0.000798149034381,0.000805476680398,0.000799535214901,0,0,0
FastRandom_32bit,160,0.006616741418839,0.006684437394142,0.006653493642807,0,0,0

@patricklodder
Copy link
Member

patricklodder commented Mar 25, 2024

I picked the following on top for a ~10% performance increase on the 32-bit FastRandomContext call:

There are probably more enhancements that are worth picking, but this (on the same i7-970 as above) at least consistently gave me:

#Benchmark,count,min,max,average,min_cycles,max_cycles,average_cycles
FastRandom_1bit,576,0.001733902841806,0.002175435423851,0.001750805725654,5615303,7045181,5670042
FastRandom_32bit,96,0.010480642318726,0.010773122310638,0.010528010626634,33942116,34889024,34095342

@xanimo
Copy link
Member

xanimo commented Mar 26, 2024

Everything is looking good so far. Tested successfully on x86_64-pc-linux-gnu jammy.

FastRandom_1bit,768,0.001310061663389,0.001355305314064,0.001322269439697,3270081,3383005,3300558
FastRandom_32bit,120,0.008004248142242,0.010467499494553,0.008429358402888,19979437,26128340,21040796

@chromatic
Copy link
Member Author

I can't seem to reproduce a clean cherry-pick like you mention, @patricklodder . Did you reproduce from 9c33a2 or is there another commit? I get conflicts around noexcept for FastRandomContext::FastRandomContext().

@xanimo
Copy link
Member

xanimo commented Apr 4, 2024

Everything is looking good so far. Tested successfully on x86_64-pc-linux-gnu jammy.

FastRandom_1bit,768,0.001310061663389,0.001355305314064,0.001322269439697,3270081,3383005,3300558
FastRandom_32bit,120,0.008004248142242,0.010467499494553,0.008429358402888,19979437,26128340,21040796

@chromatic This one is a bit further down the road but in comparison here are my results with those cherry-picks @patricklodder mentioned:

FastRandom_1bit,832,0.001286000013351,0.001319061964750,0.001300879969047,3209897,3292369,3247008
FastRandom_32bit,128,0.007689073681831,0.008537530899048,0.008067343384027,19191829,21310164,20136173

@xanimo
Copy link
Member

xanimo commented Apr 4, 2024

Running on a i5-10300H*

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants