Skip to content
forked from rsp/deno-rand

Random utilities for getting random numbers in Deno

License

Notifications You must be signed in to change notification settings

peakea/deno-rand

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Deno rand library

Build Status
(CI tests on Linux, Mac, Windows)

Random utilities for getting random numbers in Deno conveniently.

It uses the standard crypto.getRandomValues() to get cryptographically strong random data.

In Deno crypto.getRandomValues() was implemented in PR #2327 using Rust's rand::rngs::ThreadRng (see also Deno's Issue #1891: Implement webcrypto APIs and Issue #2321: Add Crypto.getRandomValues()).

This module should work in the browser and in Node.js but currently it was only tested in Deno (on Linux, Mac and Windows).

Work in progress.

Usage

import rand from './mod.ts';

// random 7-bit unsigned integer:
const x = rand.u7();

// random 5-bit signed integer:
const y = rand.s6();

Short API:

import { u7 } from './mod.ts';

const x = u7(); // random 7-bit unsigned integer

Readable API:

import { randU7 } from './mod.ts';

const x = randU7(); // random 7-bit unsigned integer

The advantage of randU7() vs rand.u7() is that you can import only what you need and avoid mistakenly writing s7 instead of u7 etc.

Math.random() replacement:

import { f64 } from './mod.ts';

Math.random = f64;

The f64() function should be a drop-in replacement for Math.random() with exactly the same range and distribution, but using cryptographically strong random data. If it is not an exact replacement then it is a bug and should be filed as an issue.

The f64() returns a random 64-bit floating point number calculated from 64 bits of random data in the same way as in ToDouble() used by V8 for Math.random(). I.e. it sets 24 of those 64 bits to a fixed exponent, leaving 40 bits of mantissa random, and subtracts 1 to get numbers in the range of 0 (inclusive) to 1 (exclusive). This ensures a uniform distribution of values but it means that we get only 40 bits of real entropy.

Supported bit widths:

s1, s2, s3, s4, s5, s6, s7, s8, s16, s32, u1, u2, u3, u4, u5, u6, u7, u8, u16, u32, f64

TODO:

  • Add optional support for Math.random()
  • Add more bit widths
  • Add support for ranges other than round binary numbers
  • Add multiple values returned at once
  • Optimize with larger prepopulated buffers
  • Test in the browser
  • Test in Node
  • Publish on npm as well

Why it was created

I started looking into ulid to port it to Deno and I saw in its index.ts that it uses a strange way to get a random 5-bit integer:

It gets an 8-bit integer, divides it by 255, then multiplies by 32 and subtracts 1 if the result is 32, instead of just shifting or masking bits, and it's not obvious whether the numbers are uniformly distributted if calculated that way (good thought excercise to prove if they are!).

This shows that simple things like getting a random number in a particular range can be hard to do without complicating it in a way that it is hard to see if the randomness was not accidentally redused in the process.

I believe that code generating cryptographically strong random numbers should be easy to understand and audit.

This module consists of multiple small functions, there are many of them but each one is very simple, like:

const u8buf = new Uint8Array(1);

const u8 = () => crypto.getRandomValues(u8buf)[0];

const u5 = () => u8() >> 3;

Issues

For any bug reports or feature requests please post an issue on GitHub.

Author

Rafał Pocztarski
Follow on GitHub Follow on Twitter
Follow on Stack Exchange

License

MIT License (Expat). See LICENSE.md for details.

About

Random utilities for getting random numbers in Deno

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages

  • TypeScript 99.5%
  • Shell 0.5%