Commit 52b68e01a0e for nodejs
commit 52b68e01a0e49110811e42dc7f96ef3f76139952
Author: Mert Can Altin <mertgold60@gmail.com>
Date: Sat Oct 3 11:32:22 2026 +0300
crypto: improve random synchronous number generation performance
Instead of creating a RandomBytesJob object, it calls CSPRNG()
directly now.
Assisted-by: Claude Code
Signed-off-by: Mert Can Altin <mertgold60@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66348
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
diff --git a/lib/internal/crypto/random.js b/lib/internal/crypto/random.js
index 10bd2627b0b..c53494aed84 100644
--- a/lib/internal/crypto/random.js
+++ b/lib/internal/crypto/random.js
@@ -34,6 +34,7 @@ const {
CheckPrimeJob,
kCryptoJobAsync,
kCryptoJobSync,
+ randomFillSync: randomFillSyncImpl,
secureBuffer,
} = internalBinding('crypto');
@@ -175,16 +176,7 @@ function randomFillSync(buf, offset = 0, size) {
if (size === 0)
return buf;
- const job = new RandomBytesJob(
- kCryptoJobSync,
- buf,
- offset,
- size);
-
- const err = job.run()[0];
- if (err)
- throw err;
-
+ randomFillSyncImpl(buf, offset, size);
return buf;
}
diff --git a/src/crypto/crypto_random.cc b/src/crypto/crypto_random.cc
index 0318d9157b9..c80eb2c800a 100644
--- a/src/crypto/crypto_random.cc
+++ b/src/crypto/crypto_random.cc
@@ -214,13 +214,47 @@ MaybeLocal<Value> CheckPrimeTraits::EncodeOutput(Environment* env,
}
namespace Random {
+static void RandomFillSync(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ CHECK(IsAnyBufferSource(args[0])); // Buffer to fill
+ CHECK(args[1]->IsUint32()); // Offset
+ CHECK(args[2]->IsUint32()); // Size
+
+ ArrayBufferOrViewContents<unsigned char> in(args[0]);
+
+ const uint32_t byte_offset = args[1].As<Uint32>()->Value();
+ const uint32_t size = args[2].As<Uint32>()->Value();
+ CHECK_GE(byte_offset + size, byte_offset); // Overflow check.
+ CHECK_LE(byte_offset + size, in.size()); // Bounds check.
+
+ env->PrintSyncTrace();
+ if (ERR_peek_error() != 0) ERR_clear_error();
+ if (ncrypto::CSPRNG(in.data() + byte_offset, size)) {
+ if (ERR_peek_error() != 0) ERR_clear_error();
+ return;
+ }
+
+ CryptoErrorStore errors;
+ errors.Capture();
+ if (errors.Empty()) {
+ errors.Insert(NodeCryptoError::DERIVING_BITS_FAILED);
+ errors.SetNodeErrorCode("ERR_CRYPTO_OPERATION_FAILED");
+ }
+ Local<Value> exception;
+ if (errors.ToException(env).ToLocal(&exception)) {
+ env->isolate()->ThrowException(exception);
+ }
+}
+
void Initialize(Environment* env, Local<Object> target) {
+ SetMethod(env->context(), target, "randomFillSync", RandomFillSync);
RandomBytesJob::Initialize(env, target);
RandomPrimeJob::Initialize(env, target);
CheckPrimeJob::Initialize(env, target);
}
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
+ registry->Register(RandomFillSync);
RandomBytesJob::RegisterExternalReferences(registry);
RandomPrimeJob::RegisterExternalReferences(registry);
CheckPrimeJob::RegisterExternalReferences(registry);
diff --git a/test/parallel/test-crypto-randomfillsync-trace-sync-io.js b/test/parallel/test-crypto-randomfillsync-trace-sync-io.js
new file mode 100644
index 00000000000..8f9461f19f3
--- /dev/null
+++ b/test/parallel/test-crypto-randomfillsync-trace-sync-io.js
@@ -0,0 +1,23 @@
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const { spawnSync } = require('child_process');
+
+// randomFillSync() should be reported by --trace-sync-io when it runs after
+// the first event loop turn.
+
+if (process.argv[2] === 'child') {
+ setImmediate(() => {
+ require('crypto').randomFillSync(Buffer.alloc(16));
+ });
+ return;
+}
+
+const { stderr, status } = spawnSync(process.execPath,
+ ['--trace-sync-io', __filename, 'child'],
+ { encoding: 'utf8' });
+assert.strictEqual(status, 0);
+assert.match(stderr, /WARNING: Detected use of sync API[\s\S]*randomFillSync/);
diff --git a/typings/internalBinding/crypto.d.ts b/typings/internalBinding/crypto.d.ts
index e12016ec916..22ee303f599 100644
--- a/typings/internalBinding/crypto.d.ts
+++ b/typings/internalBinding/crypto.d.ts
@@ -1002,6 +1002,7 @@ export interface CryptoBinding {
privateEncrypt: InternalCryptoBinding.PublicKeyCipher;
publicDecrypt: InternalCryptoBinding.PublicKeyCipher;
publicEncrypt: InternalCryptoBinding.PublicKeyCipher;
+ randomFillSync(buf: ArrayBufferLike | ArrayBufferView, offset: number, size: number): void;
resetRootCertStore(): void;
secureBuffer(length: number): Uint8Array | undefined;
secureHeapUsed(): bigint | undefined;