271: Random port libraries

by Wolfgang Corcoran-Mathe

Status

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.

Abstract

This SRFI proposes a pattern of libraries for binary input ports that produce random bytes. Libraries are divided into “randomized” and “determinized” 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.

Contents

  1. Issues
  2. Rationale
  3. Specification
    1. Terminology
    2. Libraries
      1. Library protocol
      2. Additional libraries
      3. Discussion
    3. Interface
      1. All libraries
      2. determinized libraries
    4. Example determinized library names
  4. Implementation
  5. Usage and compatibility
  6. Acknowledgements
  7. References
  8. Copyright

Issues

A random port from a determinized library can be initialized from a bytevector (or binary port). The initialization data drawn from this object may be:

  1. a state, valid in length and form, extracted by random-port-state from a port with the same backing algorithm, or
  2. arbitrary data.

There are thus two conceptually distinct initialization modes, and it might be ambiguous which one make-random-port should apply. What if the state representation for a given library changes slightly between versions, e.g. if the length of the state remains the same but the order of values changes? In such a case, make-random-port would either mis-parse the data or fall back to treating it as arbitrary. The result would be a port which — horror of horrors — does not produce the expected sequence.

Therefore, should make-random-port accept a Boolean flag requiring it to parse its initialization data strictly, i.e. as a random state representation, and to signal an error if parsing fails?

Rationale

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-number generation that adds as little as necessary to the language. This SRFI:

*: Throughout this SRFI, I use the term “randomized” to denote sources that should produce “cryptographic-quality” random data. See the Terminology section for a precise — or at least longer — definition.

Random port states

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, so we can’t take the one-size-fits-all approach of C’s srand (C23 section 7.24.3.2) and other obsolete systems.

SRFI 27 allows random-source states to be manipulated as semi-opaque objects (i.e. unspecified, but having external representations), which does most of the job: you can save the state of a SRFI 27 source and restore it later. But this is a fragile design. Lacking a common format for random states, there is no reliable way to seed a SRFI 27 source with anything other than a saved state from the exact same source.

First of all, this SRFI does not allow the state of a randomized random port to be extracted — such a state would usually have no meaning. With regard to determinized random-port states, it goes two steps beyond SRFI 27:

While these changes may pose a challenge to adoption (current random source implementations use a wide range of state representations and generally can't be initialized from arbitrary bytes), there are benefits. We 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 randomized port.)

Why ports?

Input ports have been in the Scheme Reports since the early days (the RRRS); 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, some random sources (traditionally, though unfortunately) may block until sufficient entropy is available. With random ports, applying u8-ready? should be enough to alert you of this situation.

Specification

Terminology

The words “must”, “may”, etc., though not upper-cased in this SRFI, should be interpreted according to RFC 2119.

A random port is a binary input port which produces random data. Reading from a random port should not produce an end-of-file object.

An randomized random port should produce data from either a high-entropy 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 randomized source should be unpredictable, even by an adversary who can read past outputs and simulate generation of outputs on demand.

A determinized random port must produce data generated by a fully deterministic generation algorithm. Two determinized random ports with the same states must produce the same sequence of pseudorandom numbers.

Libraries

A Scheme implementation conforming to this specification provides at least the following R7RS libraries (R7RS section 5.6):

The usual library-name-format variants for these libraries may also be provided:

(srfi 271) is simply an alias for (srfi 271 randomized). (Rationale: Rushed or incautious programmers who just want random numbers get the best available.)

Library protocol

The (srfi 271 randomized) library and any libraries with the (srfi 271 randomized) prefix provide randomized random-number ports.

Both the randomized and determinized libraries must export the make-random-port constructor. determinized libraries must provide an additional interface for creating random ports with predetermined initial states.

Additional libraries

Implementations are encouraged to provide additional libraries (e.g. for different pseudorandom generation algorithms) under the (srfi 271 determinized) “namespace”. If they do, they must ensure that each library follows the protocol detailed above. A list of example library names is provided below.

Discussion

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 randomized), (scheme random determinized), etc.) be provided.

Interface

All libraries

A make-random-port procedure is exported by each library with the (srfi 271) prefix.

(make-random-port) → binary-input-port

Returns a new random port.

determinized libraries

The following procedures are exported by all libraries with the (srfi 271 determinized) prefix.

(make-random-port [initializer]) → binary-input-port

As above, but the optional initializer argument is used as follows:

Rationale: In tandem with random-port-state, this provides a way to put a random port into a known state.

There is no requirement that the data contained in or read from an initializer be a state representation extracted with random-port-state: make-random-port must support initializing a port from arbitrary data.

Calling make-random-port without an initializer is equivalent to

(call-with-port (randomized:make-random-port)
                make-random-port)

where randomized:make-random-port denotes the make-random-port procedure exported by (srfi 271 randomized).

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

(random-port-initialization-error? obj) → boolean

Returns #t if obj is an object signaled by make-random-port in the circumstances described above, and #f otherwise.

Example determinized library names

This section is informational.

Names are based on Sebastiano Vigna’s PRNG page and Wikipedia.

(srfi 271 determinized xorshift)

Library using some kind of xorshift generator. These are often very fast, but the simplest xorshift implementations may not be very reliable. It might be appropriate to use such a library for toy or educational programs.

(srfi 271 determinized xoshiro256++)
(srfi 271 determinized xoshiro256**)

xoshiro libraries. The authors of the xoshiro generators claim they are faster and more reliable than xorshift generators.

(srfi 271 determinized xoshiro-kawai)

Reserved for use by the Gauche Scheme implementation.

(srfi 271 determinized mwc256)

Library for a 256-bit multiply-with-carry (MWC) source. MWC generators tend to have extremely long periods, ranging from around 260 to 22,000,000.

Usage and compatibility

This section is informational.

A higher-level interface

Since the libraries specified by this SRFI do not provide procedures for getting generally useful data types (integers within arbitrary ranges, reals, etc.) out of random ports, a higher-level interface will be needed to make random-port programming congenial. The multi-library design of this SRFI leads to one important consideration in choosing such an interface: it should work with random ports from any library. Because Scheme lacks a means of parameterizing one library over the exports of another, we need an interface to random ports in general, not just to the ports from, say, (srfi 271 randomized), if we wish to avoid multiplying libraries unnecessarily.

For several reasons, detailed below, SRFI 27 would make a poor high-level interface to random ports. SRFI 194, while specified in terms of SRFI 27, is a better fit, and it provides more kinds of random-data generators than most programmers will ever need. By wrapping random ports in SRFI 158 generators, however, several useful properties of ports would be lost (see the Rationale for details). My preference (which may be reified in a future SRFI) is for a library of bland port-reading procedures, e.g. read-random-integer, read-random-real, etc., which would do the (sometimes prickly) job of extracting good-quality random values without hiding the ports providing the raw data.

That being said, SRFI 27 remains the best-known random-number interface in Scheme, and it may be desirable to provide both SRFI 27 and 271 interfaces. A discussion of SRFI 27 / 271 compatibility issues follows.

SRFI 27

SRFI 27’s random sources are similar to random ports, but they support a few operations that cannot be directly implemented in terms of this SRFI’s 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: This SRFI does not provide operations for directly changing the state of an existing random port.

SRFI 27’s type-disjointness requirement could be satisfied by wrapping a random port in a record type. State mutation could then be implemented by replacing the port within the random-source wrapper with a newly-created port (since this SRFI only allows states to be set during port creation).

Implementation

A portable implementation of random ports is currently impossible. A sample implementation of this SRFI developed for Gauche (running on POSIX systems) is available in the SRFI repository.

Acknowledgements

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 randomized port 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.

References

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 (RRRS), MIT Artificial Intelligence Memo No. 848, 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.


Editor: Arthur A. Gleckler