Skip to content

Instantly share code, notes, and snippets.

@kernigh
Created May 9, 2016 02:35
Show Gist options
  • Save kernigh/d169895a700c6511d08511c005a28d88 to your computer and use it in GitHub Desktop.
Save kernigh/d169895a700c6511d08511c005a28d88 to your computer and use it in GitHub Desktop.
benchmark for different random number generators
# Run benchmarks:
# $ ruby benchrand.rb
# Run benchmarks in parallel with sh and xterm:
# $ for i in 1 2; do xterm -hold -e ruby benchrand.rb& done
#
# Outputs the time to generate SIZE random bytes with several
# different random number generators:
# - Random::DEFAULT from Ruby
# - /dev/urandom
# - arc4random_buf() from libc
# - RAND_bytes() from OpenSSL
# - gnutls_rnd() from GnuTLS
# - PK11_GenerateRandom() from NSS
#
# This script skips generators that it can't find. You may need to
# edit the Fiddle.dlopen() calls in this script.
require 'benchmark'
require 'fiddle'
SIZE = 256 * 1024**2
# copied from <gnutls/crypto.h>
GNUTLS_RND_NONCE = 0
GNUTLS_RND_RANDOM = 1
GNUTLS_RND_KEY = 2
# copied from <nss/seccommon.h>
SECSuccess = 0
urandom = (open('/dev/urandom', 'rb') rescue warn "Don't have urandom")
libc = (Fiddle.dlopen('libc.so') rescue nil)
libcrypto = (Fiddle.dlopen('libcrypto.so') rescue nil)
libgnutls = (Fiddle.dlopen('libgnutls.so') rescue nil)
libnss3 = (Fiddle.dlopen('libssl3.so') rescue nil)
def function(lib, name, par, ret)
if sym = (lib[name] rescue nil)
Fiddle::Function.new(sym, par, ret)
else
warn "Don't have #{name}"
end
end
int = Fiddle::TYPE_INT
size_t = Fiddle::TYPE_SIZE_T
void = Fiddle::TYPE_VOID
voidp = Fiddle::TYPE_VOIDP
arc4random_buf = function(libc, 'arc4random_buf', [voidp, size_t], void)
rand_bytes = function(libcrypto, 'RAND_bytes', [voidp, int], int)
gnutls_rnd = function(libgnutls, 'gnutls_rnd', [int, voidp, size_t], int)
pk11_GenerateRandom = function(libnss3, 'PK11_GenerateRandom',
[voidp, int], int)
if pk11_GenerateRandom
nss_NoDB_Init = function(libnss3, 'NSS_NoDB_Init', [voidp], int)
end
def with_buf
begin
yield buf = Fiddle::Pointer.malloc(SIZE)
ensure
Fiddle.free buf
end
end
Benchmark.bm(20) do |x|
x.report('Random::DEFAULT') {
Random::DEFAULT.bytes(SIZE)
}
urandom && x.report('/dev/urandom') {
str = urandom.read(SIZE)
str.length == SIZE or warn 'urandom met EOF'
}
arc4random_buf && x.report('arc4random_buf') {
with_buf {|buf| arc4random_buf.(buf, SIZE)}
}
rand_bytes && x.report('RAND_bytes') {
with_buf {|buf| rand_bytes.(buf, SIZE)}
}
if gnutls_rnd
x.report('gnutls_rnd NONCE') {
with_buf {|buf| gnutls_rnd.(GNUTLS_RND_NONCE, buf, SIZE)}
}
x.report('gnutls_rnd RANDOM') {
with_buf {|buf| gnutls_rnd.(GNUTLS_RND_RANDOM, buf, SIZE)}
}
x.report('gnutls_rnd KEY') {
with_buf {|buf| gnutls_rnd.(GNUTLS_RND_KEY, buf, SIZE)}
}
end
pk11_GenerateRandom && x.report('PK11_GenerateRandom') {
# It fails if we did not initialize it.
nss_NoDB_Init.(0) == SECSuccess or fail 'NSS_NoDB_Init failed'
with_buf {|buf|
offset = 0
while offset < SIZE
# It fails if we request more than 65536 bytes.
req = [65536, SIZE - offset].min
pk11_GenerateRandom.(buf + offset, req) == SECSuccess or
fail 'PK11_GenerateRandom failed'
offset += req
end
}
}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment