From: Chris Duncan Date: Mon, 25 May 2026 09:10:44 +0000 (-0700) Subject: Reduce RNG calls by generating up front into larger typed array. X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=499ddc418776b70a9ab1811a35f3755d2d783b85;p=nano-pow.git Reduce RNG calls by generating up front into larger typed array. --- diff --git a/src/lib/generate/wasm/index.ts b/src/lib/generate/wasm/index.ts index 87eae92..d8e0bf2 100644 --- a/src/lib/generate/wasm/index.ts +++ b/src/lib/generate/wasm/index.ts @@ -2,7 +2,7 @@ //! SPDX-License-Identifier: GPL-3.0-or-later import { NanoPowValidate } from '#lib/validate' -import { BytesToHex, Logger, bigintRandom, isBytes } from '#utils' +import { BytesToHex, Logger, isBytes } from '#utils' import { WorkGenerateResponse } from 'nano-pow' import { NanoPowWasmWorker } from './worker.js' @@ -73,8 +73,10 @@ async function workersStarted () { async function dispatch (): Promise { return new Promise(next => { const attempts = [] - for (const w of workers) { - data.seed = bigintRandom() & ~((1n << 24n) - 1n) + const seed = crypto.getRandomValues(new BigUint64Array(workers.length)) + for (let i = 0; i < workers.length; i++) { + data.seed = seed[i] & ~((1n << 24n) - 1n) + const w = workers[i] const attempt = new Promise((resolve, reject) => { w.onerror = reject w.onmessage = (msg) => resolve(msg.data) diff --git a/src/lib/generate/webgl/index.ts b/src/lib/generate/webgl/index.ts index 1169c63..a86f2d7 100644 --- a/src/lib/generate/webgl/index.ts +++ b/src/lib/generate/webgl/index.ts @@ -2,7 +2,7 @@ //! SPDX-FileContributor: Ben Green //! SPDX-License-Identifier: GPL-3.0-or-later AND MIT -import { BytesToHex, Logger, bigintRandom, bigintToHex } from '#utils' +import { BytesToHex, Logger, bigintToHex } from '#utils' import { WorkGenerateResponse } from 'nano-pow' import { downsampleSource, drawSource, quadSource } from './shaders' @@ -417,6 +417,7 @@ export async function generate (hash: Bytes, difficulty: bigint, effort: number, LOG: logger.log(`generate('${BytesToHex(hash.buffer)}', '${difficulty.toString(16)}', ${effort}, ${debug})`) // Start drawing to calculate one nonce per pixel + const seed = new BigUint64Array(4) let found = false let result: Record = {} let isFirstRetry = false @@ -427,13 +428,15 @@ export async function generate (hash: Bytes, difficulty: bigint, effort: number, setup(effort) } init(new Uint32Array(hash.buffer), difficulty) + crypto.getRandomValues(seed) LOG: logger.log('drawing frame 0') - draw(bigintRandom(), drawFbos[0], queries[0]) - draw(bigintRandom(), drawFbos[1], queries[1]) - draw(bigintRandom(), drawFbos[2], queries[2]) + draw(seed[0], drawFbos[0], queries[0]) + draw(seed[1], drawFbos[1], queries[1]) + draw(seed[2], drawFbos[2], queries[2]) let drawIndex = 3 do { - draw(bigintRandom(), drawFbos[drawIndex], queries[drawIndex]) + if (drawIndex === 0) crypto.getRandomValues(seed) + draw(seed[drawIndex], drawFbos[drawIndex], queries[drawIndex]) drawIndex = (drawIndex + 1) % 4 found = await check(queries[drawIndex]) } while (!found && !timeout) diff --git a/src/lib/generate/webgpu/index.ts b/src/lib/generate/webgpu/index.ts index 081b0eb..50a5efe 100644 --- a/src/lib/generate/webgpu/index.ts +++ b/src/lib/generate/webgpu/index.ts @@ -1,7 +1,7 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { BytesToHex, Logger, Queue, bigintRandom, bigintToHex } from '#utils' +import { BytesToHex, Logger, Queue, bigintToHex } from '#utils' import { WorkGenerateResponse } from 'nano-pow' import { default as NanoPowGpuComputeShader } from './shaders/compute.wgsl' @@ -205,7 +205,7 @@ async function init (hash: Bytes, difficulty: bigint): Promise { async function dispatch (dispatchIndex: number, seed: bigint, effort: number): Promise { LOG: logger.log('dispatching compute pass') try { - LOG: logger.log('seed', bigintToHex(seed, 16)) + LOG: logger.log('seed', seed.toString(16).padStart(16, '0')) // Copy seed into INPUT buffer inputDataView.setBigUint64(40, seed, true) @@ -280,6 +280,7 @@ export async function generate (hash: Bytes, difficulty: bigint, effort: number, }, 60_000) LOG: logger.groupStart('NanoPow WebGPU work_generate') LOG: logger.log('generating') + const seed = new BigUint64Array(2) let found = false let result: Record = {} let isFirstRetry = false @@ -295,11 +296,12 @@ export async function generate (hash: Bytes, difficulty: bigint, effort: number, } await q.add(init, hash, difficulty) // Dispatch initial workgroups and set index - await dispatch(0, bigintRandom(), effort) + await dispatch(0, crypto.getRandomValues(seed)[0], effort) let dispatchIndex = 1 // Loop attempts until valid work found do { - await dispatch(dispatchIndex, bigintRandom(), effort) + if (dispatchIndex === 0) crypto.getRandomValues(seed) + await dispatch(dispatchIndex, seed[dispatchIndex], effort) dispatchIndex ^= 1 found = await check(dispatchIndex) } while (!found && !timeout) diff --git a/src/utils/bigint.ts b/src/utils/bigint.ts index 85b26ac..4bc3a30 100644 --- a/src/utils/bigint.ts +++ b/src/utils/bigint.ts @@ -1,41 +1,6 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -export function bigintBitLength (int: bigint): bigint { - let bitLength = 1n - while (int > 1n || int < -1n) { - bitLength++ - int >>= 1n - } - return bitLength -} - -export function bigintByteLength (int: bigint): number { - let byteLength = 0 - while (int > 0n || int < -1n) { - byteLength++ - int >>= 8n - } - return byteLength -} - -export function bigintRandom (): bigint { - const mask = 0xFFFFFFFFFFFFFFFFn - const randomUint8Array = new Uint8Array(8) - let output = 0n - do { - output = 0n - crypto.getRandomValues(randomUint8Array) - output = BigInt(randomUint8Array[0]) - for (let i = 1; i < randomUint8Array.length; i++) { - output <<= 8n - output += BigInt(randomUint8Array[i]) - } - output &= mask - } while (output > mask) - return output -} - export function bigintToHex (int: bigint, length: unknown = 0): string { if (typeof length !== 'number') { throw new TypeError('invalid length')