commit: 977cdf1ba863e599abcf2cc80cbd719cb3b0f67e
Author: Kerin Millar <kfm <AT> plushkava <DOT> net>
AuthorDate: Mon Aug 12 10:19:10 2024 +0000
Commit: Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sat Aug 17 16:16:36 2024 +0000
URL:
https://gitweb.gentoo.org/proj/gentoo-functions.git/commit/?id=977cdf1b
Use an entropy pool for the mksh-targeting srandom() implementation
The slowest of the the three srandom() implementations is presently
selected for shells that overflow numbers at the 2^31 mark. A prominent
shell which does so is mksh (even for LP64 architectures).
Recently, one of the other srandom() implementations was accelerated by
having the shell maintain its own entropy pool of up to 512 hex digits
in size. Make it so that the mksh-targeting implementation employs a
similar technique. Consider the following benchmark.
i=0; while [ $((i += 1)) -le 30000 ]; do srandom; done >/dev/null
As conducted with mksh 59c on a system with a 2nd generation Intel Xeon,
I obtained the following figures.
BEFORE
real 0m56.414s
user 0m47.043s
sys 0m24.751s
AFTER
real 0m28.900s
user 0m22.795s
sys 0m6.802s
Note that the performance increase cannot be applied in all situations.
For further details regarding the constraints, refer to commit 866af9c.
Signed-off-by: Kerin Millar <kfm <AT> plushkava.net>
functions.sh | 71 ++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 45 insertions(+), 26 deletions(-)
diff --git a/functions.sh b/functions.sh
index 406fe7f..454c62d 100644
--- a/functions.sh
+++ b/functions.sh
@@ -581,30 +581,43 @@ srandom()
printf '%d\n' "$(( SRANDOM >> 1 ))"
}
elif [ -c /dev/urandom ] && [ "$(( 1 << 31 == -2147483648 ))" -eq 1 ];
then
- # The shell implements integers as signed int rather than signed
- # long, contrary to the specification. Therefore, bit shifting
- # cannot be a viable strategy. Instead, use awk to generate a
- # number that is immediately within range.
+ # The shell implements integers as signed int rather than
+ # signed long, contrary to the specification. Therefore, bit
+ # shifting cannot be a viable strategy. Instead, try to discern
+ # a suitably constrained sequence of 8 hex digits.
+
+
genfun_int32_pat='[0-7][[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]]'
+ unset -v genfun_entropy
+
srandom()
{
- local hex
+ local hex i slice
- hex=$(
- export LC_ALL=C
- od -vAn -N256 -tx1 /dev/urandom | awk '
- {
- gsub(/[[:space:]]/, "")
- hex = hex $0
- }
- END {
- if (match(hex,
/[0-7][[:xdigit:]]{7}/)) {
- print substr(hex,
RSTART, RLENGTH)
- } else {
- exit 1
- }
- }
- '
- ) &&
+ # If the shell is understood to have potentially forked
+ # itself then collect fresh entropy from the outset.
+ if ! _update_pid || [ "$$" != "${genfun_pid}" ]; then
+ _collect_entropy
+ fi
+
+ for i in 1 2; do
+ # shellcheck disable=2295
+ slice=${genfun_entropy%${genfun_int32_pat}*}
+ if [ "${#slice}" -ne "${#genfun_entropy}" ];
then
+ hex=${genfun_entropy#"$slice"}
+ genfun_entropy=${genfun_entropy%"$hex"}
+ while [ "${#hex}" -gt 8 ]; do
+ hex=${hex%?}
+ done
+ break
+ elif [ "$i" -eq 1 ]; then
+ # The pool is too small to contain a
+ # suitable sequence. Refill then try
+ # again.
+ _collect_entropy
+ else
+ false
+ fi
+ done &&
printf '%d\n' "0x${hex}"
}
elif [ -c /dev/urandom ]; then
@@ -614,8 +627,8 @@ srandom()
{
local hex
- # If the shell has forked itself, collect 4 bytes worth
- # of entropy.
+ # If the shell is understood to have potentially forked
+ # itself then collect 4 bytes worth of entropy.
if ! _update_pid || [ "$$" != "${genfun_pid}" ]; then
hex=$(LC_ALL=C od -vAn -N4 -tx1 /dev/urandom |
tr -d '[:space:]')
test "${#hex}" -eq 8 && printf '%d\n' "$((
0x${hex} >> 1 ))"
@@ -626,9 +639,7 @@ srandom()
# maintains an entropy pool of up to 512 hex digits in
# size.
if [ "${#genfun_entropy}" -lt 8 ]; then
- genfun_entropy=$(
- LC_ALL=C od -vAn -N256 -tx1
/dev/urandom | tr -d '[:space:]'
- )
+ _collect_entropy
fi
if [ "${#genfun_entropy}" -lt 8 ]; then
false
@@ -787,6 +798,14 @@ whenceforth()
#------------------------------------------------------------------------------#
+#
+# Collects 256 bytes worth of entropy from /dev/urandom and assigns it to the
+# genfun_entropy variable in the form of 512 hex digits.
+#
+_collect_entropy() {
+ genfun_entropy=$(LC_ALL=C od -vAn -N256 -tx1 /dev/urandom | tr -d
'[:space:]')
+}
+
#
# Determines whether the terminal is a dumb one.
#