taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 20b26fc38297ada6c630a5aa9dc826cd618af9a8
parent e383c41f4efcf58bdffc8635750955d8f2963f6c
Author: Florian Dold <dold@taler.net>
Date:   Mon, 20 Jul 2026 20:48:32 +0200

util: test that the browser PRNG is never a constant source

Diffstat:
Apackages/taler-util/src/prng-browser.test.ts | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+), 0 deletions(-)

diff --git a/packages/taler-util/src/prng-browser.test.ts b/packages/taler-util/src/prng-browser.test.ts @@ -0,0 +1,60 @@ +/* + This file is part of GNU Taler + (C) 2026 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { test } from "node:test"; +import assert from "node:assert"; +import { loadBrowserPrng } from "./prng-browser.js"; +import { randomBytes, setPRNG } from "./nacl-fast.js"; + +/** + * The browser entry point installs this PRNG unconditionally. Where no + * CSPRNG exists it must leave nacl's throwing default in place: a constant + * source yields publicly known private keys. + */ +test("browser PRNG never silently produces constant bytes", (t) => { + // Reinstate nacl's default "no PRNG" behaviour, so this test is independent + // of whatever another test file may have installed. + setPRNG(() => { + throw new Error("no PRNG"); + }); + + assert.strictEqual( + typeof (globalThis as any).self, + "undefined", + "precondition: this test must run without a `self` global", + ); + + loadBrowserPrng(); + + let first: Uint8Array | undefined; + try { + first = randomBytes(32); + } catch (e) { + // Correct behaviour: no CSPRNG available, so randomBytes refuses. + return; + } + + // If a PRNG was installed at all, it must not be a constant source. + assert.ok( + first.some((b) => b !== 0), + "randomBytes returned all zero bytes", + ); + assert.notDeepStrictEqual( + Array.from(first), + Array.from(randomBytes(32)), + "two consecutive randomBytes calls returned identical output", + ); +});