Description Usage Arguments Details Value Usage Properties of the produced QQIDs qQQIDs vs. rngQQIDs Caching QQIDs to avoid latency Warning - parallelization Disclaimer and caution Author(s) See Also Examples
qQQIDfactory
returns a closure (a function with an associated
environment) that retrieves, caches, and returns quantum-random QQIDs.
1 | qQQIDfactory(nBatch = 1023)
|
nBatch |
(numeric) The batch size requested from the ANU server. The
default 1023 does not normally need to be changed. (Larger batches take more
time to process, smaller batches offer no speed benefit). It might be
increased e.g. for storing a large cache in case an interruption to Internet
connectivity is anticipated. Values < 1 and > 1e05 will cause an error in
|
In what follows we will call the closure that is produced by
qQQIDfactory
"qQQID()
" (even though you could assign it to a
different name). The function factory qQQIDfactory
and the
qQQID()
closure address a latency problem that arises when we retrieve
true random numbers from the ANU
Quantum Random Number Generator at the Australian National University.
qQQIDfactory
produced closures maintain a local cache of true random
QQIDs, which can be accessed without latency. In a design use case,
qQQID()
could be produced in an R session startup script. From that
point on, latency in generating true random QQIDs is only experienced
occasionally when the cache needs to be replenished.
qQQIDfactory
returns a closure that takes the following
arguments:
n
(numeric) (default: 1; in interval: (1,
1e+05)): the number of true random QQIDs to return.
inspectOnly
(logical) (default: FALSE
). If TRUE
, the requested number of
QQIDs are only printed as a side-effect, the function returns NULL
invisibly. This is useful to inspect the first n
elements of the
cache without changing the cache, while making it sufficiently hard to
accidentally assign and reuse QQIDs.
If no connection to ANU can be
established and the initial cache cannot be filled, qQQIDfactory
returns NULL
invisibly.
qQQIDfactory
produces a closure which is meant to be
assigned to a variable and called by that variable name (see examples).
While any legal variable name can be used, assigning to "qQQID
" is
recommended. Producing the closure requires an Internet connection to first
fill the closure's cache of QQID values. Once the cache is filled, no
Internet connection is required until the cache is depleted and the closure
attempts to replenish it. If replenishing the cache fails because of a
failure to open a connection to the ANU server, an informative message is
printed and the closure returns NULL
invisibly. If there are
remaining QQIDs in the cache, these can be retrieved by requesting no more
than the number that currently exist in the cache. The closure either
returns the requested number of QQIDs, or NULL, but it will never return
fewer than the requested number of QQIDs, since implicit recycling of
shorter vectors would be a critical failure mode for a function that is
expected to return unique identifiers.
Internally, qQQID
converts
true random UUIDs obtained from qrandom::qUUID
. These UUIDs are
RFC 4122 compliant and contain a
six-bit version code, and 122 random bits. Such RFC compliant QQIDs are
drawn from 2^122 =~ 5.3e+36
possibilities, whereas totally random 128-bit numbers are drawn from a
=~ 3.4e+38 number space. The 50%
collision probability of random 122-bit numbers is =~ 2.7e+18 numbers, while for 128-bit numbers it is =~ 2.2e+19.
Whether to use true random or pseudo-random
QQIDs is a tradeoff between speed and safety. The ANU quantum random number
server can have considerable latency (a problem that qQQIDfactory
addresses through caching), but pseudo-random numbers may not be
sufficiently collision-safe for use cases that depend on the uniqueness of
the resulting numbers: while the RNGs provided by R are very good, all RNGs
potentially suffer from the possibility of an initialization
collision, i.e. when two runs of the RNG are accidentally initialized with
the same seed, due to an improper and/or unrecognized use of
set.seed()
in another function, script or package, or due to the
limited randomness of time- and machine-state based seeds. This is not a
problem for long runs of key-generation on a single machine, but it may be
an issue for the decentralized generation of random unique keys, which is
the design use case of qqid
. The only way to prevent this with
certainty is to use true random keys (as provided with this function). True
random qQQIDs have a 50% collision probability in =~ 2.7e+18 keys, and this is the same at all times, regardless of
the state of the requesting machine. Thus unless throughput of keys is a
critical concern, it is advisable to use true random QQIDs from a
qQQIDfactory
closure over those returned by a
rngQQID()
process, or at least to initialize the RNG
with a true random seed (the default option for
rngQQID()
).
The ANU server produces true random
numbers from quantum fluctuations of the vacuum. The high latency of
requests for quantum random numbers from the ANU server - between 6 to 10
seconds per request - is practically independent of the size of the
request's payload. This suggests a strategy to serve keys from a local
cache. R provides an elegant way of doing this by defining functions as
closures - i.e. along with their own environment. This function environment
allows to maintain state between function calls. qQQIDfactory
retrieves 1023 qQQIDs and caches them in the environment of qQQID
.
The qQQID
closure replenishes the cache if it does not contain at
least the requested number of QQIDs, then it unshifts the QQIDs from the
cache, and returns them. The user experience is that qQQID
is
responsive, and latency arises only occasionally when the cache is
replenished.
If you are executing code in parallel on
separate processors, you must make sure that every task uses its own,
independent copy of qQQID()
and not a copy of an instance of the
closure - such copies would all contain the same cache! Given the relatively
high latency of cache replenishment, it is likely that an approach that uses
rngQQID(N, method = "q")
, is more promising.
Although this function has been written and tested with care, no suitability for any particular purpose, in particular no suitability for high-value transactions, for applications whose failure could endanger life or property, or for cryptography is claimed. The source code is published in full and it is up to the user to audit and adapt the code for their own purposes and needs.
(c) 2019 Boris Steipe,
licensed under MIT (see file LICENSE
in this package).
rngQQID()
to generate QQIDs via the inbuilt
RNG.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ## Not run:
# prepare a qQQID function and use it to retrieve three true random QQIDs
qQQID <- qQQIDfactory()
qQQID(3)
# Use the function to return 10 UUIDs from the same cache
qq2uu(qQQID(10))
# inspect the first 5 QQIDs on the cache ...
qQQID(5, inspectOnly = TRUE)
# ... retrieve four of the QQIDs (they are identical
# to the first four we just inspected) ...
qQQID(4)
# ... show that the four keys are gone from the cache which now
# begins with the fifth QQID we saw before.
qQQID(5, inspectOnly = TRUE)
## End(Not run)
|
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.