Commit 3454f62f authored by Geoff Simmons's avatar Geoff Simmons

Add the random_real() function.

parent e237e453
Pipeline #234 skipped
......@@ -39,6 +39,7 @@ import gcrypt [from "path"] ;
BLOB gcrypt.random([ENUM quality] [, BYTES n])
INT gcrypt.random_int(ENUM quality [, INT bound])
REAL gcrypt.random_real(ENUM)
gcrypt.wipe(BLOB)
......@@ -167,6 +168,7 @@ CONTENTS
* BLOB fileread(PRIV_TASK, STRING)
* BLOB random(PRIV_TASK, ENUM {STRONG,VERY_STRONG,NONCE}, BYTES)
* INT random_int(ENUM {STRONG,NONCE}, INT)
* REAL random_real(ENUM {STRONG,NONCE})
* VOID wipe(BLOB)
* STRING version()
* STRING gcrypt_version()
......@@ -712,12 +714,42 @@ If ``bound`` is greater than 0, then the return value lies between 0
values ``min`` and ``max`` inclusive with the ``NONCE`` generator, use
this formula::
random_int(NONCE, (max - min) + 1) + min
gcrypt.random_int(NONCE, (max - min) + 1) + min
Example::
# Assign a random group number from 0 to 99 to a request.
set req.http.X-Group = random_int(NONCE, 100);
set req.http.X-Group = gcrypt.random_int(NONCE, 100);
.. _func_random_real:
random_real
-----------
::
REAL random_real(ENUM {STRONG,NONCE})
Returns a random REAL that is greater than or equal to 0.0 and less
than 1.0, using the random number generator with the specified quality
level. The permitted levels are ``NONCE`` and ``STRONG`` as described
above.
To get a random REAL in the range from ``min`` to ``max`` inclusive
with the ``STRONG`` generator, use this formula::
gcrypt.random_real(STRONG) * (max - min) + min
Note that when a REAL is converted to a STRING, for example when it is
assigned to a header, the representation may be rounded up to
``"1.0"`` if the REAL's value is very close to 1.0. So it may appear
as if the range of ``random_real()`` includes 1.0, but this is just an
artifact of string conversion.
Example::
# Assign an unpredictable REAL from -1.0 to 1.0 to a request.
set req.http.X-Real = gcrypt.random_real(STRONG) * 2 - 1;
.. _func_wipe:
......
......@@ -121,3 +121,28 @@ varnish v1 -errvcl {vmod gcrypt error: in gcrypt.random(): quality ENUM is NULL}
key=gcrypt.random(n=16B));
}
}
varnish v1 -vcl {
import blobcode;
import gcrypt from "${vmod_topbuild}/src/.libs/libvmod_gcrypt.so";
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.nonce = gcrypt.random_real(NONCE);
set resp.http.strong = gcrypt.random_real(STRONG);
return(deliver);
}
}
client c1 -repeat 20 {
txreq
rxresp
expect resp.status == 200
expect resp.http.nonce ~ "^1.0+|0.[[:digit:]]+$"
expect resp.http.strong ~ "^1.0+|0.[[:digit:]]+$"
} -run
......@@ -39,6 +39,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <float.h>
#include "vcl.h"
#include "cache/cache.h"
......@@ -725,6 +726,8 @@ vmod_random(VRT_CTX, struct vmod_priv *rnd_task, VCL_ENUM qualitys, VCL_BYTES n)
return rnd_blob;
}
/* Function random_int */
VCL_INT
vmod_random_int(VRT_CTX, VCL_ENUM qualitys, VCL_INT bound)
{
......@@ -761,6 +764,48 @@ vmod_random_int(VRT_CTX, VCL_ENUM qualitys, VCL_INT bound)
return r;
}
/* Function random_real */
/*
* This makes use of knowledge that VRT_REAL is typedef double, and that
* doubles have 53 bit mantissas on most platforms, including all of those
* supported by Varnish.
*
* It probably won't work if VRT_REAL ever becomes long double, which is
* likely to be extended precision, and won't work if the conditions
* described in the #errors below are not satisfied. For that, we'll have
* to make use of libm.
*/
#if FLT_RADIX != 2
#error "random_real() implementation requires FLT_RADIX == 2"
#endif
#if DBL_MANT_DIG > 63
#error "random_real() implementation requires DBL_MANT_DIG < 64"
#endif
#define DBL_BYTES ((DBL_MANT_DIG + 7) / 8)
#define DBL_INV (1./((uint64_t)1 << DBL_MANT_DIG))
#define DBL_MASK (0xffffffffffffffff >> (64 - DBL_MANT_DIG))
VCL_REAL
vmod_random_real(VRT_CTX, VCL_ENUM qualitys)
{
VCL_REAL r;
uint64_t u = 0;
(void) ctx;
AN(qualitys);
assert(qualitys[0] != 'V');
get_rnd(qualitys, &u, DBL_BYTES);
u &= DBL_MASK;
r = u * DBL_INV;
assert(r >= 0. && r < 1.);
return r;
}
/* Function wipe */
static inline void
......
......@@ -22,6 +22,7 @@ $Module gcrypt 3 access the libgcrypt cryptographic library
BLOB gcrypt.random([ENUM quality] [, BYTES n])
INT gcrypt.random_int(ENUM quality [, INT bound])
REAL gcrypt.random_real(ENUM)
gcrypt.wipe(BLOB)
......@@ -638,12 +639,35 @@ If ``bound`` is greater than 0, then the return value lies between 0
values ``min`` and ``max`` inclusive with the ``NONCE`` generator, use
this formula::
random_int(NONCE, (max - min) + 1) + min
gcrypt.random_int(NONCE, (max - min) + 1) + min
Example::
# Assign a random group number from 0 to 99 to a request.
set req.http.X-Group = random_int(NONCE, 100);
set req.http.X-Group = gcrypt.random_int(NONCE, 100);
$Function REAL random_real(ENUM {STRONG, NONCE})
Returns a random REAL that is greater than or equal to 0.0 and less
than 1.0, using the random number generator with the specified quality
level. The permitted levels are ``NONCE`` and ``STRONG`` as described
above.
To get a random REAL in the range from ``min`` to ``max`` inclusive
with the ``STRONG`` generator, use this formula::
gcrypt.random_real(STRONG) * (max - min) + min
Note that when a REAL is converted to a STRING, for example when it is
assigned to a header, the representation may be rounded up to
``"1.0"`` if the REAL's value is very close to 1.0. So it may appear
as if the range of ``random_real()`` includes 1.0, but this is just an
artifact of string conversion.
Example::
# Assign an unpredictable REAL from -1.0 to 1.0 to a request.
set req.http.X-Real = gcrypt.random_real(STRONG) * 2 - 1;
$Function VOID wipe(BLOB)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment