Fix insecure random number generator in backoff logic

Replaced `Math.random` with a cryptographically secure random number generator using `node:crypto.randomInt` in `src/lock-ops.mjs` to prevent potential timing attacks or predictability in backoff delays.

Added `test/secure-random.test.mjs` to verify the secure random generator.

Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-02-17 18:54:42 +00:00
1 parent b3f4a5c9cd
commit 568d37a45c
2 files changed
+32 -2

No files matched your search

+11 -2
View File
@@ -1,3 +1,4 @@
import { randomInt } from 'node:crypto';
import { SimplePool } from 'nostr-tools/pool';
import {
getQueryTimeoutMs,
@@ -134,7 +135,13 @@ function isTransientPublishCategory(category) {
].includes(category);
}
function calculateBackoffDelayMs(attemptNumber, baseMs, capMs, randomFn = Math.random) {
const MAX_RANDOM = 281474976710655; // 2**48 - 1
function secureRandom() {
return randomInt(0, MAX_RANDOM) / MAX_RANDOM;
}
function calculateBackoffDelayMs(attemptNumber, baseMs, capMs, randomFn = secureRandom) {
const maxDelay = Math.min(capMs, baseMs * (2 ** Math.max(0, attemptNumber - 1)));
return Math.floor(randomFn() * maxDelay);
}
@@ -409,7 +416,7 @@ export async function publishLock(relays, event, deps = {}) {
retryBaseDelayMs = 500,
retryCapDelayMs = 8_000,
sleepFn = (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
randomFn = Math.random,
randomFn = secureRandom,
telemetryLogger = console.error,
healthLogger = console.error,
diagnostics = {},
@@ -590,3 +597,5 @@ export function _resetRelayHealthState() {
relayHealthState.metricsByRelay.clear();
relayHealthState.lastSnapshotAt = 0;
}
export const _secureRandom = secureRandom;
+21
View File
@@ -0,0 +1,21 @@
import { describe, it } from 'node:test';
import assert from 'node:assert';
import { _secureRandom } from '../src/lock-ops.mjs';
describe('secureRandom', () => {
it('returns values in [0, 1)', () => {
for (let i = 0; i < 1000; i++) {
const val = _secureRandom();
assert.ok(val >= 0, `Value ${val} should be >= 0`);
assert.ok(val < 1, `Value ${val} should be < 1`);
}
});
it('returns varied values', () => {
const values = new Set();
for (let i = 0; i < 100; i++) {
values.add(_secureRandom());
}
assert.ok(values.size > 90, 'Values should be reasonably unique');
});
});