I've first encountered this when using expo (react-native) where I have to polyfill the globalThis.crypto with the following code right at the very beginning of my App.js:
import { getRandomValues as expoCryptoGetRandomValues } from 'expo-crypto';
class Crypto {
getRandomValues = expoCryptoGetRandomValues;
}
const webCrypto = typeof crypto !== 'undefined' ? crypto : new Crypto();
export function polyfillWebCrypto() {
if (typeof crypto === 'undefined') {
Object.defineProperty(globalThis, 'crypto', {
configurable: true,
enumerable: true,
get: () => webCrypto,
});
}
}
Even though the polyfill is applied you still end up getting the Because there is no global crypto property in this context, cryptographically unsafe Math.random() is used message in the logs. I think the reason for this is that the randomWordArray function is declared in such a way that it will only evaluated once during the initialization, but I wasn't able to find a order of operations during which the polyfill is already applied before this.
It's probably a bit less efficient, but you could get around this issue if you would define randomWordArray in core.js instead in the following way:
const randomWordArray = (nBytes) => {
const crypto =
(typeof globalThis != 'undefined' ? globalThis : void 0)?.crypto ||
(typeof global != 'undefined' ? global : void 0)?.crypto ||
(typeof window != 'undefined' ? window : void 0)?.crypto ||
(typeof self != 'undefined' ? self : void 0)?.crypto ||
(typeof frames != 'undefined' ? frames : void 0)?.[0]?.crypto;
if (crypto) {
const words = [];
for (let i = 0; i < nBytes; i += 4) {
words.push(crypto.getRandomValues(new Uint32Array(1))[0]);
}
return new WordArray(words, nBytes);
}
console.warn('Because there is no global crypto property in this context, cryptographically unsafe Math.random() is used');
const words = [];
const r = (m_w) => {
let _m_w = m_w;
let _m_z = 0x3ade68b1;
const mask = 0xffffffff;
return () => {
_m_z = (0x9069 * (_m_z & 0xFFFF) + (_m_z >> 0x10)) & mask;
_m_w = (0x4650 * (_m_w & 0xFFFF) + (_m_w >> 0x10)) & mask;
let result = ((_m_z << 0x10) + _m_w) & mask;
result /= 0x100000000;
result += 0.5;
return result * (Math.random() > 0.5 ? 1 : -1);
};
};
for (let i = 0, rcache; i < nBytes; i += 4) {
const _r = r((rcache || Math.random()) * 0x100000000);
rcache = _r() * 0x3ade67b7;
words.push((_r() * 0x100000000) | 0);
}
return new WordArray(words, nBytes);
}
Is this anything you would consider changing?
I've first encountered this when using expo (react-native) where I have to polyfill the
globalThis.cryptowith the following code right at the very beginning of myApp.js:Even though the polyfill is applied you still end up getting the
Because there is no global crypto property in this context, cryptographically unsafe Math.random() is usedmessage in the logs. I think the reason for this is that therandomWordArrayfunction is declared in such a way that it will only evaluated once during the initialization, but I wasn't able to find a order of operations during which the polyfill is already applied before this.It's probably a bit less efficient, but you could get around this issue if you would define
randomWordArrayincore.jsinstead in the following way:Is this anything you would consider changing?