rngQQID: rngQQID

Description Usage Arguments Details Value qQQIDs vs. rngQQIDs 128 vs. 122 bit random Random seeds Warning - parallelization Disclaimer and caution Author(s) See Also Examples

View source: R/rngQQID.R


rngQQID uses R's random number generator to generate a vector of pseudo-random QQIDs.


rngQQID(n = 1, method = "q", RFC4122compliant = TRUE)



(integer) The number of pseudo-random QQIDs to return. Default is 1.


(character) Which random seed method to use. Default is "q", a true random number seed. Other options are "R" (R's inbuilt RNG initialization), "n" (no initialization, a reproducible random seed can be set prior to this call if one clearly understands the risks), "t" (test of error handling).


(logical) whether to base the QQID on version-stamped 128-bit numbers with 122 random bits, compliant with RFC 4122 (default), or to return QQIDs based on 128 random bits.


The function rngQQID generates a vector of n pseudo-random QQIDs using R's inbuilt random number generator. Internally, the QQIDs are constructed from randomly sampled individual bits, thus the resulting QQIDs do not suffer from distributional issues that arise from mapping large floating point numbers to a continuous range of integers. The function takes care not to change the global state of the RNG in .Random.seed.


(character) a vector of n QQIDs

qQQIDs vs. rngQQIDs

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 (method "q", the default option for rngQQID).

128 vs. 122 bit random

By default, QQIDs produced with rngQQID() can be converted to RFC 4122 compliant UUIDs. These use 6 bits to identify the method of UUID generation and thus contain only 122 random bits. It is possible to obtain 128-bit random QQIDs from rngQQID(), by setting the parameter RFC4122compliant to FALSE. This increases the number space from 2^122 =~ 5.3e+36 to 2^128 =~ 3.4e+38 at the cost of no longer being compliant with the UUID standard.

Random seeds

The function supports three methods to seed R's RNG. The default method is "q" and uses a true random seed retrieved from the ANU quantum random number server. An alternative method is "r", which uses R's inbuilt random initialization (cf. the behaviour of set.seed(NULL) in the set.seed() documentation). Finally, the function can be run without a random seed with "n", which allows either to define one's own sane RNG initialization, or use a specific seed for reproducible randomization - assuming that the risks are clearly understood. In all cases, the current state of R's RNG is saved and restored upon exit, even if the function exits with an error. For testing purposes, saving the RNG state can be demonstrated with method "t" which does not change the global random seed, creates exactly one random 128-bit number internally, and then throws an error to exit the function which should restore .Random.seed.

Warning - parallelization

If you are executing code in parallel on separate processors, you must make sure that every task uses its own, separately initialized state of the global variable .Random.seed and not a copy of a single instance of the global environment - such copies will produce exactly identical QQIDs unless reinitialized after the task is deployed.

Disclaimer and caution

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).

See Also

qQQIDfactory() to create a closure that returns cached, true random QQIDs.


## Not run: 

# initialize the RNG with a true random number and return 5 QQIDs
# note the latency incurred by retrieving the seed from the ANU server

# return 10,000 QQIDs and transform them into UUIDs (takes less than two
# seconds); we assume that the RNG is in a sane state since we have just
previously initialized it with a true random number
x <- qq2uu(rngQQID(1e4, method = "n"))

## End(Not run)

qqid documentation built on May 2, 2019, 12:19 p.m.