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.
54 lines
1.4 KiB
TypeScript
54 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))
|
|
const temp = array[i]
|
|
array[i] = array[swapIndex]
|
|
array[swapIndex] = temp
|
|
}
|
|
}
|