by Wolfgang Corcoran-Mathe
This SRFI is currently in draft status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-271@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.
This SRFI proposes a pattern of libraries for binary input ports that produce random bytes. Libraries are divided into “cryptographic” and “repeatable” categories to address different uses of random data. The design leaves the details of random number generation to the implementer and the transformation of bytes to other types (floats, etc.) to higher-level libraries. A mechanism for saving random-port states as bytevectors and for propagating those states to new ports is also provided.
None at present.
As a foundation for random-number generation, the well-known (and excellent) SRFI 27 includes both too little and too much. On the one hand, it makes no distinction between sources of cryptographic-quality pseudorandom data and sources of the deterministic pseudorandom data sometimes needed for testing and other purposes. On the other, it includes forms for defining new random sources and for parameterizing library procedures over them, thus adding avoidable complexity to the specification.
In this SRFI I take a different tack and try to describe a framework for random-byte generation that adds as little as necessary to the language. This SRFI:
Uses binary input ports, rather than a novel type, for random sources.
Uses the Scheme library system — and only the Scheme library system — to distinguish between cryptographic-quality sources and repeatable sources, as well as between different kinds of cryptographic and repeatable sources.
Specifies no procedures for drawing random data. The
random-byte-seeking user is pointed in the direction of
read-u8 and read-bytevector; those
in search of other kinds of random data will find a profusion
of options in
SRFI 194.
(But see the compatibility
notes.)
Everyone agrees that it is sometimes useful to generate
the same random sequence several times, e.g. on each run of
a test suite. Whether to allow random number generators to
be “seeded”, and what forms those seeds should take, is
controversial. Initializing one
kind of source may require more “seed” data than another
would, so we can’t take the one-size-fits-all approach of
srand(3) (C23
section 7.24.3.2) and other obsolete systems.
SRFI 27 allows random-source states to be manipulated as opaque objects, which does most of the job — you can save the sate of a SRFI 27 source and restore it later, although the SRFI doesn’t guarantee that states support an equivalence relation or have datum representations. These properties are essential for allowing random states to be written to disk and read back in during a later session.
In this SRFI I go a step further and propose
bytevectors as a common representation of random-port states.
While this may pose a challenge to adoption (current random
source implementations use a wide range of state representations),
it has many benefits. Bytevectors can be written, read, and
compared for equality, which makes them a good vehicle for
saving and restoring states. We also gain the ability to seed
one random port from the output of another, obviating the
need for procedures like SRFI 27’s
random-source-randomize!. (To create a source
with a hard-to-predict initial state, simply seed it with a
cryptographic-quality port.)
Input ports have been in the Scheme Reports since the early
days (the R2RS); thus they fit easily into existing programs,
and they come with a wealth of standard inspection
procedures (u8-ready?, etc.). In contrast, an
opaque type like SRFI 27's random-source needs a fair amount of
wheel-reinvention — procedures like the utterly elementary
read-u8 have to be specified anew.
SRFI 194's generator-based
interface is another option.
SRFI 158
generators, however, are ill-defined,
being no more than nullary Scheme procedures. There is no portable
way to distinguish a
generator from any other procedure.
They mimic input ports in several ways, but there are important
port operations that they cannot support in current Scheme.
For example, it isn’t possible to write peek or
ready? procedures for generators. Some have
suggested adding general language features to address these
weaknesses. We can look forward to a future Scheme in which
ports and generators have all of the same features and compete,
pointlessly, for control of every I/O domain.
Back to the point. Some of the standard port operations that
are not available for SRFI 158 generators are useful for random
ports. For example, in some cases it may be necessary for a random
source to block, e.g. until sufficient entropy is available. With
random ports, applying u8-ready? should be enough to
alert you of this situation.
The words “must”, “may”, etc., though not upper-cased in this SRFI, should be interpreted according to RFC 2119.
A cryptographic-quality random-number source produces data from either a hopefully-secure external source (e.g. the operating system’s entropy pool or a hardware random-number generator) or from a deterministic generation algorithm which has been seeded from such a source. The sequence produced by a cryptographic-quality source should be unpredictable, even by an adversary who can read past outputs and simulate generation of outputs on demand.
The above definition is an attempt; the details are many and complicated. Exactly what counts as “cryptographic quality” depends on your intentions and adversaries. When in doubt, consult your friendly neighborhood cryptologist.
A repeatable random-number source uses a fully deterministic generation algorithm and can be made to produce a known sequence of pseudorandom numbers by being seeded with an appropriate state value.
A Scheme implementation conforming to this specification provides at least the following R7RS libraries (R7RS section 5.6):
(srfi 271 random)(srfi 271 random crypto)(srfi 271 random repeatable)The usual library-name-format variants for these libraries may also be provided:
(srfi :271 random crypto), etc.(srfi srfi-271 random crypto), etc.(srfi 271 random) is simply an alias for
(srfi 271 random crypto). (Rationale:
Rushed or incautious programmers who just want random numbers
get the best available.)
The (srfi 271 random crypto) library and any
libraries with the (srfi 271 random crypto)
prefix should provide ports that produce cryptographic-quality
random data.
Both the crypto and repeatable
libraries must export the make-random-port constructor.
repeatable libraries must provide an
additional interface for
creating random ports with predetermined initial
states.
Implementations are encouraged to provide additional libraries
(e.g. for different pseudorandom generation algorithms) under the
(srfi 271 random repeatable) “namespace”. If they do, they must ensure
that each library follows the protocol detailed above.
A list of example
library names is provided below.
This section is informational.
Each library is tied to a specific generation mechanism; import the library that provides the one you want. There is no other mechanism in this specification for choosing between random-number-generation algorithms.
No means is provided here for getting floats, arbitrary integers, or other data out of random ports. This is left to a higher-level library, similar to SRFI 194, which can transform the binary output of a random port into values of other types.
If this proposal is incorporated into the R7RS, I suggest
that aliases under the library prefix (scheme random)
(e.g. (scheme random crypto),
(scheme random repeatable), etc.) be provided.
A make-random-port procedure is exported by each
library with the (srfi 271 random) prefix.
(make-random-port [initializer]) →
binary-input-port
Returns a random port, a binary input port which
produces random data. Reading
from a random port should not produce an end-of-file object.
If the source represented by a random port would
block (e.g. due to low system entropy), u8-ready?
must return #f when invoked on the port.
The optional initializer argument is used only
by repeatable libraries (see below).
repeatable librariesThe following procedures are exported by all libraries with
the (srfi 271 random repeatable) prefix.
(make-random-port [initializer]) →
binary-input-port
As above, but the optional initializer argument is used as follows:
If initializer is a bytevector
then the initial state of the random port returned by
make-random-port is derived from this value.
An error is
signaled if initializer does not contain enough
data to initialize the port.
Rationale: In tandem with random-port-state,
this provides a way to put a random port into a known state.
If initializer is a binary input port, then
make-random-port reads data from this port
until it has enough to initialize a new port. An error is
signaled if enough data cannot be obtained.
Calling make-random-port without an
initializer is equivalent to
(call-with-port (crypto:make-random-port)
make-random-port)
where crypto:make-random-port denotes the
make-random-port procedure exported by
(srfi 271 random crypto).
(random-port-state random-port) →
bytevector
Returns a bytevector representing the current state
of random-port. If a new port is created with
(make-random-port state), where
state is the value of (random-port-state
old-port) (or is equal to that value
in the sense of equal?), then the new port
must produce the same random sequence as old-port.
repeatable library namesThis section is informational.
Names are based on Sebastiano Vigna’s PRNG page and Wikipedia.
(srfi 271 random repeatable xorshift)
Library using some kind of xorshift generator.
(srfi 271 random repeatable xoshiro256++)
(srfi 271 random repeatable xoshiro256**)
xoshiro libraries.
(srfi 271 random repeatable mwc256)Library for a 256-bit multiply-with-carry source.
SRFI 27’s random sources are very much like random ports, but they support a few operations that cannot be directly implemented in terms of SRFI 271 forms:
random-source?Why not: Random ports are input ports, but SRFI 27 requires that random sources be of a disjoint type.
random-source-state-set!random-source-randomize!random-source-pseudo-randomize!Why not: SRFI 271 does not provide operations for directly changing the state of an existing random port.
The state-mutation procedures, while rather ugly, pose no real difficulty and could be added as an extension of SRFI 271. There is, however, no way to satisfy SRFI 27’s type-disjointness requirement.
Since SRFI 194 is built on SRFI 27’s random sources, it is
not directly compatible with SRFI 271, but could be adapted to
random ports without substantial changes. The missing pieces are,
as far as I can tell, the default-random-source
parameter (easily added), and procedures for drawing arbitrary
integers or floating-point numbers from random ports.
Implementing these procedures isn't trivial — getting a uniform
distribution of floats from a random byte sequence is
particularly tricky — but they will be a practical necessity,
in any case, for all users of SRFI 271. (In view of this,
a revision of SRFI 194 based on random-byte sources might be
a Good Thing.)
A portable implementation of random ports is currently impossible. A sample implementation of SRFI 271 developed for Gauche (running on POSIX systems) is available in the SRFI repository.
Thanks to John W. Cowan for helping to chip away everything in this SRFI that did not look like an elephant.
Thanks to Taylor Campbell and Alaric Snell-Pym for suggestions and elucidations. In particular, the definition of a cryptographic-quality source was adapted from Alaric’s description of the desirable properties of such a source; any inaccuracies in the SRFI’s version are my own doing.
Thanks to Peter McGoron and the other members of the R7RS Second Working Group for advice and discussion.
Thanks to those who provided feedback via the SRFI mailing list or on the #scheme IRC channel.
Of course, none of this should be taken to suggest that any of the people mentioned above endorse this SRFI.
S. Bradner, Key words for use in RFCs to Indicate Requirement Levels (RFC 2119), 1997. https://datatracker.ietf.org/doc/html/rfc2119
Hal Abelson et al, Revised Revised Report on Scheme (R2RS), August 1985.
Alex Shinn, John Cowan, & Arthur A. Gleckler, eds., Revised7 Report on the Algorithmic Language Scheme (R7RS Small), 2013. https://small.r7rs.org
Sebastiano Vigna, A PRNG shootout, (no publication date given). https://prng.di.unimi.it
ISO/IEC 9899:2024. Programming languages — C (C23). ISO/IEC, 2024.
Alaric Snell-Pym. Some thoughts on random number generation. Communication to the R7RS WG2 mailing list, March 2026.
Sebastian Egner. SRFI 27: Sources of random bits. https://srfi.schemers.org/srfi-27/, 2002.
Shiro Kawai, John Cowan, and Thomas Gilray. SRFI 158: Generators and Accumulators. https://srfi.schemers.org/srfi-158/, 2017.
Shiro Kawai, Arvydas Silanskas, Linas Vepštas, and John Cowan. SRFI 194: Random data generators. https://srfi.schemers.org/srfi-194/, 2020.
Taylor Campbell. Personal communication, 2025. Available on the R7RS issue tracker.
© 2026 Wolfgang Corcoran-Mathe.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.