]> git.codecow.com Git - nano-pow.git/commitdiff
Refactor bigint conversion helpers. next/refactoring
authorChris Duncan <chris@codecow.com>
Mon, 22 Jun 2026 22:37:14 +0000 (15:37 -0700)
committerChris Duncan <chris@codecow.com>
Mon, 22 Jun 2026 22:37:14 +0000 (15:37 -0700)
src/lib/config/index.ts
src/lib/generate/wasm/index.ts
src/lib/generate/webgl/index.ts
src/lib/generate/webgpu/index.ts
src/lib/index.ts
src/lib/validate/index.ts
src/utils/bigint.ts

index 8a9d07bfc81f7624580f81efc77aae07043459e0..3ffd796f980041dfd119aedca72070e3cc85748c 100644 (file)
@@ -1,7 +1,7 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { ApiSupport, SEND, bigintFrom, bigintToHex } from '#utils'
+import { ApiSupport, big, bigHex, SEND } from '#utils'
 
 type ApiSupportedTypes = keyof typeof ApiSupport
 
@@ -33,7 +33,7 @@ class NanoPowConfigConstructor implements NanoPowOptions {
                return {
                        api: this.api,
                        debug: this.debug,
-                       difficulty: bigintToHex(this.difficulty, 16),
+                       difficulty: bigHex(this.difficulty, 16),
                        effort: this.effort
                }
        }
@@ -117,14 +117,14 @@ class NanoPowConfigConstructor implements NanoPowOptions {
                if (input != null && input.difficulty != null) {
                        if (typeof input.difficulty === 'string') {
                                try {
-                                       input.difficulty = bigintFrom(input.difficulty, 'hex')
+                                       input.difficulty = big(input.difficulty)
                                } catch { }
                        }
                        if (typeof input.difficulty !== 'bigint') {
-                               throw new Error(`Invalid difficulty (${typeof input.difficulty})${input.difficulty}`)
+                               throw new Error(`Invalid difficulty ${input.difficulty}`)
                        }
-                       if (input.difficulty < 0x0n || input.difficulty > SEND) {
-                               throw new Error(`Invalid difficulty ${bigintToHex(input.difficulty, 16)}`)
+                       if (input.difficulty < 0n || input.difficulty > SEND) {
+                               throw new Error(`Invalid difficulty ${bigHex(input.difficulty, 16)}`)
                        }
                        return input.difficulty
                }
index 46cbdbd2d1b30910df218f3a74df5f04df31663f..d0e07b9f3943503ad4f69c3d789ee2e2e74318f6 100644 (file)
@@ -2,7 +2,7 @@
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
 import { NanoPowValidate } from '#lib/validate'
-import { Logger, bigintToHex } from '#utils'
+import { bigHex, Logger } from '#utils'
 import { WorkGenerateResponse } from 'nano-pow'
 import { NanoPowWasmWorker } from './worker.js'
 
@@ -159,8 +159,8 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number
        }
 
        return {
-               hash: bigintToHex(hash, 64),
-               work: bigintToHex(work, 16),
+               hash: bigHex(hash, 64),
+               work: bigHex(work, 16),
                difficulty: result
        }
 }
index 5800dcb8d8e8df4962fbf09daafa72cdc3fefe7f..0c36071b522a5da95543bd8a1457d392cf72dcfe 100644 (file)
@@ -2,7 +2,7 @@
 //! SPDX-FileContributor: Ben Green <ben@latenightsketches.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later AND MIT
 
-import { Logger, bigintToHex, bigintToU32 } from '#utils'
+import { bigHex, bigToU32, Logger } from '#utils'
 import { WorkGenerateResponse } from 'nano-pow'
 import { downsampleSource, drawSource, quadSource } from './shaders'
 
@@ -295,7 +295,7 @@ function init (hash: Uint32Array, difficulty: bigint): void {
 
        // Set up INPUT which must be 16 bytes per 32-bit value due to array alignment
        for (let i = 0; i < 8; i++) {
-               inputHashView.setUint32(i * 16, hash[i])
+               inputHashView.setUint32(i * 16, hash[i], true)
        }
        inputDifficultyView.setBigUint64(0, difficulty, true)
        LOG: logger.log('INPUT', inputArray.buffer.slice(0))
@@ -311,7 +311,7 @@ function draw (seed: bigint, drawFbo: FBO, query: WebGLQuery): void {
        if (gl == null) throw new Error('WebGL 2 is required to draw')
        if (drawFbo == null) throw new Error('FBO is required to draw')
        if (query == null) throw new Error('Query is required to draw')
-       LOG: logger.log(bigintToHex(seed, 16))
+       LOG: logger.log(bigHex(seed, 16))
 
        // Upload work seed buffer
        inputSeedView.setBigUint64(0, seed, true)
@@ -414,7 +414,7 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number
                LOG: logger.log('timed out')
        }, 60_000)
        LOG: logger.groupStart('NanoPow WebGL work_generate')
-       LOG: logger.log(`generate('${hash.toString(16)}', '${difficulty.toString(16)}', ${effort}, ${debug})`)
+       LOG: logger.log(`generate('${bigHex(hash, 16)}', '${bigHex(difficulty, 16)}', ${effort}, ${debug})`)
 
        // Start drawing to calculate one nonce per pixel
        const seed = new BigUint64Array(4)
@@ -427,7 +427,7 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number
                                if (isReady === false || effort !== drawEffort || isFirstRetry) {
                                        setup(effort)
                                }
-                               init(bigintToU32(hash, 8), difficulty)
+                               init(bigToU32(hash, 8), difficulty)
                                crypto.getRandomValues(seed)
                                LOG: logger.log('drawing frame 0')
                                draw(seed[0], drawFbos[0], queries[0])
@@ -460,8 +460,8 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number
        }
 
        return {
-               hash: bigintToHex(hash, 64),
-               work: bigintToHex(result.work, 16),
-               difficulty: bigintToHex(result.difficulty, 16)
+               hash: bigHex(hash, 64),
+               work: bigHex(result.work, 16),
+               difficulty: bigHex(result.difficulty, 16)
        }
 }
index caa6a9a7766d3d09150ddaa6a829456bf2c94ff3..0eafc868202620be935ce01e8b34220c754d975b 100644 (file)
@@ -1,7 +1,7 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { Logger, Queue, bigintToHex, bigintToU64 } from '#utils'
+import { bigHex, bigToU64, Logger, Queue } from '#utils'
 import { WorkGenerateResponse } from 'nano-pow'
 import { default as NanoPowGpuComputeShader } from './shaders/compute.wgsl'
 
@@ -205,7 +205,7 @@ async function init (hash: BigUint64Array, difficulty: bigint): Promise<void> {
 async function dispatch (dispatchIndex: number, seed: bigint, effort: number): Promise<void> {
        LOG: logger.log('dispatching compute pass')
        try {
-               LOG: logger.log('seed', bigintToHex(seed, 16))
+               LOG: logger.log('seed', bigHex(seed, 16))
 
                // Copy seed into INPUT buffer
                inputDataView.setBigUint64(40, seed, true)
@@ -268,8 +268,8 @@ function read (dispatchIndex: number): { work: bigint, difficulty: bigint } {
 }
 
 /**
-* Nano proof-of-work using WebGPU.
-*/
+ * Nano proof-of-work using WebGPU.
+ */
 export async function generate (hash: bigint, difficulty: bigint, effort: number, debug: boolean): Promise<WorkGenerateResponse> {
        logger.isEnabled = debug
        // Set up 60s timeout to prevent long-running calls
@@ -294,7 +294,7 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number
                                                throw new Error('failed to start')
                                        }
                                }
-                               await q.add(init, bigintToU64(hash, 4), difficulty)
+                               await q.add(init, bigToU64(hash, 4), difficulty)
                                // Dispatch initial workgroups and set index
                                await dispatch(0, crypto.getRandomValues(seed)[0], effort)
                                let dispatchIndex = 1
@@ -328,8 +328,8 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number
        }
 
        return {
-               hash: bigintToHex(hash, 64),
-               work: bigintToHex(result.work, 16),
-               difficulty: bigintToHex(result.difficulty, 16)
+               hash: bigHex(hash, 64),
+               work: bigHex(result.work, 16),
+               difficulty: bigHex(result.difficulty, 16)
        }
 }
index 0757d8b416d09e9617ae7ac7bf93a50f022be82b..660ee59734d55e77cb2d11ff8de060397c8416b9 100644 (file)
@@ -4,44 +4,43 @@
 import { NanoPowConfig } from '#lib/config'
 import { NanoPowCpu, NanoPowWasm, NanoPowWebgl, NanoPowWebgpu } from '#lib/generate'
 import { NanoPowValidate } from '#lib/validate'
-import { Cache, Logger, Queue, bigintFrom } from '#utils'
+import { big, Cache, Logger, Queue } from '#utils'
 import { WorkErrorResponse, WorkGenerateResponse, WorkValidateResponse } from 'nano-pow'
 
 const logger = new Logger()
 const q = new Queue()
 
 export async function generate (hash: unknown, options?: unknown): Promise<WorkGenerateResponse | WorkErrorResponse> {
+       const { api, debug, difficulty, effort } = await NanoPowConfig(options)
+       LOG: logger.isEnabled = debug
+       const cached = Cache.search(hash, difficulty)
+       if (cached) {
+               LOG: logger.log('found work in cache')
+               const { valid } = NanoPowValidate(big(cached.work), big(cached.hash), difficulty, debug)
+               if (valid === '1') {
+                       return cached
+               } else {
+                       try {
+                               Cache.delete(hash)
+                       } catch (err) {
+                               LOG: logger.log('error deleting invalid work from cache, continuing with generate', err)
+                       }
+               }
+       }
        return q.add(async (): Promise<WorkGenerateResponse | WorkErrorResponse> => {
                try {
-                       const { api, debug, difficulty, effort } = await NanoPowConfig(options)
-                       LOG: logger.isEnabled = debug
-                       const bigintHash = bigintFrom(hash, 'hex')
-                       const cached = Cache.search(bigintHash, difficulty)
-                       if (cached) {
-                               LOG: logger.log('found work in cache')
-                               const { valid } = NanoPowValidate(bigintFrom(cached.work, 'hex'), bigintFrom(cached.hash, 'hex'), bigintFrom(cached.difficulty, 'hex'), debug)
-                               if (valid === '1') {
-                                       return cached
-                               } else {
-                                       try {
-                                               Cache.delete(bigintHash)
-                                       } catch (err) {
-                                               LOG: logger.log('error deleting invalid work from cache, continuing with generate', err)
-                                       }
-                               }
-                       }
                        switch (api) {
                                case 'webgpu': {
-                                       return Cache.store(await NanoPowWebgpu(bigintHash, difficulty, effort, debug))
+                                       return Cache.store(await NanoPowWebgpu(big(hash), difficulty, effort, debug))
                                }
                                case 'webgl': {
-                                       return Cache.store(await NanoPowWebgl(bigintHash, difficulty, effort, debug))
+                                       return Cache.store(await NanoPowWebgl(big(hash), difficulty, effort, debug))
                                }
                                case 'wasm': {
-                                       return Cache.store(await NanoPowWasm(bigintHash, difficulty, effort, debug))
+                                       return Cache.store(await NanoPowWasm(big(hash), difficulty, effort, debug))
                                }
                                default: {
-                                       return Cache.store(await NanoPowCpu(bigintHash, difficulty, debug))
+                                       return Cache.store(await NanoPowCpu(big(hash), difficulty, debug))
                                }
                        }
                } catch (e: any) {
@@ -52,10 +51,8 @@ export async function generate (hash: unknown, options?: unknown): Promise<WorkG
 
 export async function validate (work: unknown, hash: unknown, options?: unknown): Promise<WorkValidateResponse | WorkErrorResponse> {
        try {
-               const bigintHash = bigintFrom(hash, 'hex')
-               const bigintWork = bigintFrom(work, 'hex')
                const { debug, difficulty } = await NanoPowConfig(options)
-               const result = await NanoPowValidate(bigintWork, bigintHash, difficulty, debug)
+               const result = await NanoPowValidate(big(work), big(hash), difficulty, debug)
                return result
        } catch (e: any) {
                return { error: (typeof e === 'string' ? e : (e?.message ?? '')) }
index 1eb90b9d7b60219038a17214837890a9171c04e6..cf99606902cca07e23b10625d20d533171f97278 100644 (file)
@@ -1,7 +1,7 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { Logger, RECEIVE, SEND, bigintToHex, bigintToU64 } from '#utils'
+import { Logger, RECEIVE, SEND, bigHex, bigToU64 } from '#utils'
 import { WorkValidateResponse } from 'nano-pow'
 
 const logger = new Logger()
@@ -86,7 +86,7 @@ function init (seed: bigint, hash: BigUint64Array): void {
 }
 
 function blake2b (work: bigint, hash: bigint): void {
-       init(work, bigintToU64(hash, 4))
+       init(work, bigToU64(hash, 4))
        for (let i = 0; i < 12; i++) {
                ROUND(i)
        }
@@ -95,10 +95,10 @@ function blake2b (work: bigint, hash: bigint): void {
 
 function log (work: bigint, hash: bigint, difficulty: bigint): void {
        LOG: logger.groupStart('NanoPow CPU work_validate')
-       LOG: logger.log('NanoPow CPU work_validate', 'work', bigintToHex(work, 16))
-       LOG: logger.log('NanoPow CPU work_validate', 'hash', bigintToHex(hash, 64))
-       LOG: logger.log('NanoPow CPU work_validate', 'difficulty', bigintToHex(difficulty, 16))
-       LOG: logger.log('NanoPow CPU work_validate', 'result', bigintToHex(result, 16))
+       LOG: logger.log('NanoPow CPU work_validate', 'work', bigHex(work, 16))
+       LOG: logger.log('NanoPow CPU work_validate', 'hash', bigHex(hash, 64))
+       LOG: logger.log('NanoPow CPU work_validate', 'difficulty', bigHex(difficulty, 16))
+       LOG: logger.log('NanoPow CPU work_validate', 'result', bigHex(result, 16))
        LOG: logger.groupEnd('NanoPow CPU work_validate')
 }
 
@@ -107,9 +107,9 @@ function validate (work: bigint, hash: bigint, difficulty: bigint, debug: boolea
        blake2b(work, hash)
        log(work, hash, difficulty)
        return {
-               hash: bigintToHex(hash, 64),
-               work: bigintToHex(work, 16),
-               difficulty: bigintToHex(result, 16),
+               hash: bigHex(hash, 64),
+               work: bigHex(work, 16),
+               difficulty: bigHex(result, 16),
                valid: (result >= difficulty) ? '1' : '0',
                valid_all: (result >= SEND) ? '1' : '0',
                valid_receive: (result >= RECEIVE) ? '1' : '0'
index 3b19e7e9ba10f23a2df8cb0d5e1c52f3c2e53d84..cc7dd4ed0b48788e22854e7798abe9231a265d0a 100644 (file)
@@ -1,7 +1,7 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-export function bigintFrom (value: bigint | boolean | number | string | unknown): bigint {
+export function big (value: bigint | boolean | number | string | unknown): bigint {
        switch (typeof value) {
                case 'bigint':
                case 'boolean':
@@ -18,20 +18,17 @@ export function bigintFrom (value: bigint | boolean | number | string | unknown)
        }
 }
 
-export function bigintToHex (int: bigint, length: unknown = 0): string {
-       if (typeof length !== 'number') {
-               throw new TypeError('invalid length')
-       }
+export function bigHex (int: bigint, length: number = 0): string {
        return int.toString(16).padStart(length, '0')
 }
 
-export function bigintToU32 (int: bigint, length: number): Uint32Array<ArrayBuffer> {
+export function bigToU32 (int: bigint, length: number): Uint32Array<ArrayBuffer> {
        const u32 = new Uint32Array(length)
        bigintToUintArray(u32, int)
        return u32
 }
 
-export function bigintToU64 (int: bigint, length: number): BigUint64Array<ArrayBuffer> {
+export function bigToU64 (int: bigint, length: number): BigUint64Array<ArrayBuffer> {
        const u64 = new BigUint64Array(length)
        bigintToUintArray(u64, int)
        return u64