用Emscripten编译ed25519_randombytes为Wasm的熵源及运行机制
Ed25519_randombytes函数在Wasm环境下的熵源与运行原理
原C语言实现代码
static inline void ed25519_randombytes(unsigned char *x,unsigned long long xlen) { int i; if (ed25519_random_fd == -1) { for (;;) { ed25519_random_fd = open("/dev/urandom",O_RDONLY); if (ed25519_random_fd != -1) break; sleep(1); } } while (xlen > 0) { if (xlen < 1048576) i = xlen; else i = 1048576; i = read(ed25519_random_fd,x,i); if (i < 1) { sleep(1); continue; } x += i; xlen -= i; } }
问题背景
上述ed25519_randombytes函数原本通过读取Linux系统的/dev/urandom设备文件获取随机字节,但使用emcc编译为Wasm后,在Node.js或浏览器环境中仍能正常生成随机字节。需要明确该场景下的熵源及运行原理。
解答
核心机制:Emscripten的系统调用模拟
Emscripten(emcc是其编译工具)在将C代码转为Wasm时,会对Linux风格的系统调用(如open、read、sleep)做模拟实现,不会在非Linux环境中直接访问/dev/urandom物理设备。
1. Node.js环境
熵源
Node.js内置crypto模块提供的加密安全随机数生成器,底层依赖操作系统原生熵源:
- Linux:
getrandom系统调用 - macOS:
SecRandomCopyBytes接口 - Windows:
CryptGenRandomAPI
运行逻辑
- 当Wasm代码调用
open("/dev/urandom")时,Emscripten的模拟层会识别这个特殊路径,不会真的打开文件,仅标记后续read操作需获取随机字节。 - 执行
read调用时,Emscripten会调用Node.js的crypto.randomBytes()接口生成指定长度的随机数据,返回给Wasm缓冲区。 - 代码中的
sleep(1)会被模拟为Node.js的setTimeout,实现延迟重试逻辑。
2. 浏览器环境
熵源
浏览器Web Crypto API的crypto.getRandomValues()方法,底层依赖:
- 操作系统原生安全随机数生成器
- 部分浏览器会额外结合用户输入(鼠标移动、键盘敲击等)补充熵源
运行逻辑
- Emscripten拦截
open("/dev/urandom")调用,无需实际打开设备文件。 - 执行
read时,Emscripten调用浏览器的crypto.getRandomValues()生成随机字节,传递给Wasm中的目标缓冲区。 sleep(1)被模拟为浏览器的setTimeout,实现循环重试逻辑。
关键注意点
- Emscripten仅对
/dev/urandom做特殊适配,其他文件路径不会映射到随机数接口。 - 生成的随机数属于加密安全级别,和原生Linux环境读取
/dev/urandom的安全性一致,因为底层依赖的都是操作系统提供的正规熵源。
内容的提问来源于stack exchange,提问作者Milos Mirkovic
相关产品推荐
相关产品推荐

