//! 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
return {
api: this.api,
debug: this.debug,
- difficulty: bigintToHex(this.difficulty, 16),
+ difficulty: bigHex(this.difficulty, 16),
effort: this.effort
}
}
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
}
//! 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'
}
return {
- hash: bigintToHex(hash, 64),
- work: bigintToHex(work, 16),
+ hash: bigHex(hash, 64),
+ work: bigHex(work, 16),
difficulty: result
}
}
//! 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'
// 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))
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)
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)
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])
}
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)
}
}
//! 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'
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)
}
/**
-* 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
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
}
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)
}
}
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) {
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 ?? '')) }
//! 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()
}
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)
}
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')
}
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'
//! 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':
}
}
-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