Skip to content

Commit

Permalink
[autorelease] Use xoroshiro128** for random/getRandomBytes.
Browse files Browse the repository at this point in the history
This provides full determinism, and also avoids the use of `crypto`
API that requires `require` on Node v18 (used in VSCode).
  • Loading branch information
whitequark committed Dec 22, 2023
1 parent 3d4e95a commit a3d5671
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 20 deletions.
10 changes: 0 additions & 10 deletions lib/api-browser.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
import { setRandomBytesImpl } from './wasi-virt.js';

setRandomBytesImpl(function(length) {
const QUOTA = 65536; // QuotaExceededError thrown when requesting more
const bytes = new Uint8Array(length);
for (var offset = 0; offset < length; offset += QUOTA)
crypto.getRandomValues(bytes.slice(offset, offset + QUOTA));
return bytes;
});

import { BaseApplication } from './api-base.js';

export class Application extends BaseApplication {
Expand Down
5 changes: 0 additions & 5 deletions lib/api-node.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
import { randomBytes } from 'crypto';
import { setRandomBytesImpl } from './wasi-virt.js';

setRandomBytesImpl(randomBytes);

import { readFile } from 'fs/promises';
import { BaseApplication } from './api-base.js';

Expand Down
31 changes: 26 additions & 5 deletions lib/wasi-virt.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,30 @@ function wallClockNow() {
return { seconds, nanoseconds };
}

let randomBytesImpl = function() { throw 'not implemented'; };
export function setRandomBytesImpl(impl) { randomBytesImpl = impl; }
class Xoroshiro128StarStar {
constructor(seed) {
if (BigInt(seed) === 0n) {
throw new Error("xoroshiro128** must be seeded with a non-zero state")

Check failure on line 22 in lib/wasi-virt.js

View workflow job for this annotation

GitHub Actions / test

Missing semicolon
}
this.s = [BigInt(seed) & 0xffffffffffffffffn, (BigInt(seed) >> 64n) & 0xffffffffffffffffn];
}

export function getRandomBytes(len) {
return randomBytesImpl(Number(len));
next() {
function trunc64(x) { return x & 0xffffffffffffffffn; }
function rotl(x, k) { return (x << k) | (x >> (64n - k)); }

let [s0, s1] = this.s;
const r = trunc64(rotl(s0 * 5n, 7n) * 9n);
s1 ^= s0;
s0 = trunc64(rotl(s0, 24n) ^ s1 ^ (s1 << 16n));
s1 = trunc64(rotl(s1, 37n));
this.s = [s0, s1];
return r;
}

getBytes(length) {
return Uint8Array.from({ length }, () => Number(BigInt.asUintN(8, this.next() >> 32n)));
}
}

class IoError extends Error {}
Expand Down Expand Up @@ -335,6 +354,8 @@ export class Environment {
root = new Directory({});

constructor() {
this.prng = new Xoroshiro128StarStar(1n);

this.terminalInputStream = new InputStream();
this.terminalOutputStream = new TerminalOutputStream();

Expand All @@ -350,7 +371,7 @@ export class Environment {
now: wallClockNow
},
random: {
getRandomBytes,
getRandomBytes(length) { return $this.prng.getBytes(Number(length)); }
},
io: {
Error: IoError,
Expand Down

0 comments on commit a3d5671

Please sign in to comment.