manifold/common/util/random.ts
Jonas Wagner c9f3644988
Better random (#213)
* randomString: generate a securely random string.

Also, support lengths > 12 in case that's ever needed.

This is used in at least one case (creating device tokens for users)
where it seems important that the output is unpredictable.

* Try harder to create unique usernames.

The previous version added 16 bits of entropy to the username, which
isn't all that much. Due to the birthday paradox, it would be enough to
create ~256 users with the same prefix to get a collision.

Trying that would probably fail later on, and not create security
issues... but it just seems better to be on the safe side here.
2022-05-15 13:13:07 -07:00

52 lines
1.4 KiB
TypeScript

// Returns a cryptographically random hexadecimal string of length `length`
// (thus containing 4*`length` bits of entropy).
export const randomString = (length = 12) => {
const bytes = new Uint8Array(Math.ceil(length / 2))
crypto.getRandomValues(bytes)
const hex = bytes.reduce((s, b) => s + ('0' + b.toString(16)).slice(-2), '')
return hex.substring(0, length)
}
export function genHash(str: string) {
// xmur3
for (var i = 0, h = 1779033703 ^ str.length; i < str.length; i++) {
h = Math.imul(h ^ str.charCodeAt(i), 3432918353)
h = (h << 13) | (h >>> 19)
}
return function () {
h = Math.imul(h ^ (h >>> 16), 2246822507)
h = Math.imul(h ^ (h >>> 13), 3266489909)
return (h ^= h >>> 16) >>> 0
}
}
export function createRNG(seed: string) {
// https://stackoverflow.com/a/47593316/1592933
const gen = genHash(seed)
let [a, b, c, d] = [gen(), gen(), gen(), gen()]
// sfc32
return function () {
a >>>= 0
b >>>= 0
c >>>= 0
d >>>= 0
var t = (a + b) | 0
a = b ^ (b >>> 9)
b = (c + (c << 3)) | 0
c = (c << 21) | (c >>> 11)
d = (d + 1) | 0
t = (t + d) | 0
c = (c + t) | 0
return (t >>> 0) / 4294967296
}
}
export const shuffle = (array: any[], rand: () => number) => {
for (let i = 0; i < array.length; i++) {
const swapIndex = Math.floor(rand() * (array.length - i))
;[array[i], array[swapIndex]] = [array[swapIndex], array[i]]
}
}