nano-pow 1.2.2 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -668,7 +668,7 @@ try {
668
668
  }
669
669
  var NanoPow = isGpuSupported ? NanoPowGpu : isGlSupported ? NanoPowGl : null;
670
670
 
671
- // dist/global.js
671
+ // src/global.ts
672
672
  globalThis.NanoPow ??= NanoPow;
673
673
  globalThis.NanoPowGl ??= NanoPowGl;
674
674
  globalThis.NanoPowGpu ??= NanoPowGpu;
package/dist/main.min.js CHANGED
@@ -668,7 +668,7 @@ try {
668
668
  }
669
669
  var NanoPow = isGpuSupported ? NanoPowGpu : isGlSupported ? NanoPowGl : null;
670
670
 
671
- // dist/main.js
671
+ // src/main.ts
672
672
  var main_default = NanoPow;
673
673
  export {
674
674
  NanoPow,
@@ -0,0 +1,53 @@
1
+ import "@webgpu/types"
2
+
3
+ declare const NanoPow: typeof NanoPowGl | typeof NanoPowGpu | null
4
+
5
+ export declare class NanoPowGl {
6
+ #private
7
+ /** Compile */
8
+ static init (): Promise<void>
9
+ /**
10
+ * Finds a nonce that satisfies the Nano proof-of-work requirements.
11
+ *
12
+ * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
13
+ * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
14
+ */
15
+ static search (hash: string, threshold?: number): Promise<string>
16
+ /**
17
+ * Validates that a nonce satisfies Nano proof-of-work requirements.
18
+ *
19
+ * @param {string} work - Hexadecimal proof-of-work value to validate
20
+ * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
21
+ * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
22
+ */
23
+ static validate (work: string, hash: string, threshold?: number): Promise<boolean>
24
+ }
25
+
26
+ /**
27
+ * Nano proof-of-work using WebGPU.
28
+ */
29
+ export declare class NanoPowGpu {
30
+ #private
31
+ static init (): Promise<void>
32
+ static setup (): void
33
+ static reset (): void
34
+ /**
35
+ * Finds a nonce that satisfies the Nano proof-of-work requirements.
36
+ *
37
+ * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
38
+ * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
39
+ */
40
+ static search (hash: string, threshold?: number): Promise<string>
41
+ /**
42
+ * Validates that a nonce satisfies Nano proof-of-work requirements.
43
+ *
44
+ * @param {string} work - Hexadecimal proof-of-work value to validate
45
+ * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
46
+ * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
47
+ */
48
+ static validate (work: string, hash: string, threshold?: number): Promise<boolean>
49
+ }
50
+
51
+ export declare const NanoPowGlFragmentShader: string
52
+ export declare const NanoPowGlVertexShader: string
53
+ export declare const NanoPowGpuComputeShader: any
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nano-pow",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Proof-of-work generation and validation with WebGPU/WebGL for Nano cryptocurrency.",
5
5
  "keywords": [
6
6
  "nemo",
@@ -40,11 +40,7 @@
40
40
  "url": "git+https://zoso.dev/nano-pow.git"
41
41
  },
42
42
  "scripts": {
43
- "build": "rm -rf dist && tsc && node esbuild.mjs"
44
- },
45
- "imports": {
46
- "#classes": "./src/classes/index.js",
47
- "#shaders": "./src/shaders/index.js"
43
+ "build": "rm -rf types && tsc && node esbuild.mjs && cp types.d.ts dist"
48
44
  },
49
45
  "devDependencies": {
50
46
  "@types/node": "^22.10.5",
@@ -55,7 +51,10 @@
55
51
  "typescript": "^5.7.3"
56
52
  },
57
53
  "type": "module",
58
- "exports": "./dist/main.js",
59
- "types": "dist/main.d.ts",
54
+ "exports": [
55
+ "./dist/main.min.js",
56
+ "./dist/types.d.ts"
57
+ ],
58
+ "types": "dist/types.d.ts",
60
59
  "unpkg": "dist/main.min.js"
61
60
  }
@@ -1,20 +0,0 @@
1
- export declare class NanoPowGl {
2
- #private;
3
- /** Compile */
4
- static init(): Promise<void>;
5
- /**
6
- * Finds a nonce that satisfies the Nano proof-of-work requirements.
7
- *
8
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
9
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
10
- */
11
- static search(hash: string, threshold?: number): Promise<string>;
12
- /**
13
- * Validates that a nonce satisfies Nano proof-of-work requirements.
14
- *
15
- * @param {string} work - Hexadecimal proof-of-work value to validate
16
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
17
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
18
- */
19
- static validate(work: string, hash: string, threshold?: number): Promise<boolean>;
20
- }
@@ -1,232 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-FileContributor: Ben Green <ben@latenightsketches.com>
3
- // SPDX-License-Identifier: GPL-3.0-or-later AND MIT
4
- import { NanoPowGlFragmentShader, NanoPowGlVertexShader } from '#shaders';
5
- export class NanoPowGl {
6
- /** Used to set canvas size. Must be a multiple of 256. */
7
- static #WORKLOAD = 256 * Math.max(1, Math.floor(navigator.hardwareConcurrency));
8
- static #hexify(arr) {
9
- let out = '';
10
- for (let i = arr.length - 1; i >= 0; i--) {
11
- out += arr[i].toString(16).padStart(2, '0');
12
- }
13
- return out;
14
- }
15
- static #gl;
16
- static #program;
17
- static #vertexShader;
18
- static #fragmentShader;
19
- static #positionBuffer;
20
- static #uvBuffer;
21
- static #uboBuffer;
22
- static #workBuffer;
23
- static #query;
24
- static #pixels;
25
- /**Vertex Positions, 2 triangles */
26
- static #positions = new Float32Array([
27
- -1, -1, 0, -1, 1, 0, 1, 1, 0,
28
- 1, -1, 0, 1, 1, 0, -1, -1, 0
29
- ]);
30
- /** Texture Positions */
31
- static #uvPosArray = new Float32Array([
32
- 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1
33
- ]);
34
- /** Compile */
35
- static async init() {
36
- this.#gl = new OffscreenCanvas(this.#WORKLOAD, this.#WORKLOAD).getContext('webgl2');
37
- if (this.#gl == null)
38
- throw new Error('WebGL 2 is required');
39
- this.#gl.clearColor(0, 0, 0, 1);
40
- this.#program = this.#gl.createProgram();
41
- if (this.#program == null)
42
- throw new Error('Failed to create shader program');
43
- this.#vertexShader = this.#gl.createShader(this.#gl.VERTEX_SHADER);
44
- if (this.#vertexShader == null)
45
- throw new Error('Failed to create vertex shader');
46
- this.#gl.shaderSource(this.#vertexShader, NanoPowGlVertexShader);
47
- this.#gl.compileShader(this.#vertexShader);
48
- if (!this.#gl.getShaderParameter(this.#vertexShader, this.#gl.COMPILE_STATUS))
49
- throw new Error(this.#gl.getShaderInfoLog(this.#vertexShader) ?? `Failed to compile vertex shader`);
50
- this.#fragmentShader = this.#gl.createShader(this.#gl.FRAGMENT_SHADER);
51
- if (this.#fragmentShader == null)
52
- throw new Error('Failed to create fragment shader');
53
- this.#gl.shaderSource(this.#fragmentShader, NanoPowGlFragmentShader);
54
- this.#gl.compileShader(this.#fragmentShader);
55
- if (!this.#gl.getShaderParameter(this.#fragmentShader, this.#gl.COMPILE_STATUS))
56
- throw new Error(this.#gl.getShaderInfoLog(this.#fragmentShader) ?? `Failed to compile fragment shader`);
57
- this.#gl.attachShader(this.#program, this.#vertexShader);
58
- this.#gl.attachShader(this.#program, this.#fragmentShader);
59
- this.#gl.linkProgram(this.#program);
60
- if (!this.#gl.getProgramParameter(this.#program, this.#gl.LINK_STATUS))
61
- throw new Error(this.#gl.getProgramInfoLog(this.#program) ?? `Failed to link program`);
62
- /** Construct simple 2D geometry */
63
- this.#gl.useProgram(this.#program);
64
- const triangleArray = this.#gl.createVertexArray();
65
- this.#gl.bindVertexArray(triangleArray);
66
- this.#positionBuffer = this.#gl.createBuffer();
67
- this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, this.#positionBuffer);
68
- this.#gl.bufferData(this.#gl.ARRAY_BUFFER, this.#positions, this.#gl.STATIC_DRAW);
69
- this.#gl.vertexAttribPointer(0, 3, this.#gl.FLOAT, false, 0, 0);
70
- this.#gl.enableVertexAttribArray(0);
71
- this.#uvBuffer = this.#gl.createBuffer();
72
- this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, this.#uvBuffer);
73
- this.#gl.bufferData(this.#gl.ARRAY_BUFFER, this.#uvPosArray, this.#gl.STATIC_DRAW);
74
- this.#gl.vertexAttribPointer(1, 2, this.#gl.FLOAT, false, 0, 0);
75
- this.#gl.enableVertexAttribArray(1);
76
- this.#uboBuffer = this.#gl.createBuffer();
77
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, this.#uboBuffer);
78
- this.#gl.bufferData(this.#gl.UNIFORM_BUFFER, 144, this.#gl.DYNAMIC_DRAW);
79
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, null);
80
- this.#gl.bindBufferBase(this.#gl.UNIFORM_BUFFER, 0, this.#uboBuffer);
81
- this.#gl.uniformBlockBinding(this.#program, this.#gl.getUniformBlockIndex(this.#program, 'UBO'), 0);
82
- this.#workBuffer = this.#gl.createBuffer();
83
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, this.#workBuffer);
84
- this.#gl.bufferData(this.#gl.UNIFORM_BUFFER, 32, this.#gl.STREAM_DRAW);
85
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, null);
86
- this.#gl.bindBufferBase(this.#gl.UNIFORM_BUFFER, 1, this.#workBuffer);
87
- this.#gl.uniformBlockBinding(this.#program, this.#gl.getUniformBlockIndex(this.#program, 'WORK'), 1);
88
- this.#pixels = new Uint8Array(this.#gl.drawingBufferWidth * this.#gl.drawingBufferHeight * 4);
89
- this.#query = this.#gl.createQuery();
90
- }
91
- static #draw(work) {
92
- if (this.#gl == null || this.#query == null)
93
- throw new Error('WebGL 2 is required to draw and query pixels');
94
- if (this.#workBuffer == null)
95
- throw new Error('Work buffer is required to draw');
96
- this.#gl.clear(this.#gl.COLOR_BUFFER_BIT);
97
- /** Upload work buffer */
98
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, this.#workBuffer);
99
- this.#gl.bufferSubData(this.#gl.UNIFORM_BUFFER, 0, Uint32Array.from(work));
100
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, null);
101
- this.#gl.beginQuery(this.#gl.ANY_SAMPLES_PASSED_CONSERVATIVE, this.#query);
102
- this.#gl.drawArrays(this.#gl.TRIANGLES, 0, 6);
103
- this.#gl.endQuery(this.#gl.ANY_SAMPLES_PASSED_CONSERVATIVE);
104
- }
105
- static async #checkQueryResult() {
106
- if (this.#gl == null || this.#query == null)
107
- throw new Error('WebGL 2 is required to check query results');
108
- if (this.#gl.getQueryParameter(this.#query, this.#gl.QUERY_RESULT_AVAILABLE)) {
109
- return !!(this.#gl.getQueryParameter(this.#query, this.#gl.QUERY_RESULT));
110
- }
111
- /** Query result not yet available, check again in the next frame */
112
- return new Promise((resolve, reject) => {
113
- try {
114
- requestAnimationFrame(async () => {
115
- const result = await NanoPowGl.#checkQueryResult();
116
- resolve(result);
117
- });
118
- }
119
- catch (err) {
120
- reject(err);
121
- }
122
- });
123
- }
124
- /**
125
- * Reads pixels into the work buffer, checks every 4th pixel for the 'found'
126
- * byte, converts the subsequent 3 pixels with the nonce byte values to a hex
127
- * string, and returns the result.
128
- *
129
- * @param work - Buffer with the original random nonce value
130
- * @returns Nonce as an 8-byte (16-char) hexadecimal string
131
- */
132
- static #readResult(work) {
133
- if (this.#gl == null)
134
- throw new Error('WebGL 2 is required to read pixels');
135
- this.#gl.readPixels(0, 0, this.#gl.drawingBufferWidth, this.#gl.drawingBufferHeight, this.#gl.RGBA, this.#gl.UNSIGNED_BYTE, this.#pixels);
136
- for (let i = 0; i < this.#pixels.length; i += 4) {
137
- if (this.#pixels[i] !== 0) {
138
- /** Return the work value with the custom bits */
139
- const hex = this.#hexify(work.subarray(4, 8)) + this.#hexify([
140
- this.#pixels[i + 2],
141
- this.#pixels[i + 3],
142
- work[2] ^ (this.#pixels[i] - 1),
143
- work[3] ^ (this.#pixels[i + 1] - 1)
144
- ]);
145
- return hex;
146
- }
147
- }
148
- throw new Error('Query reported result but nonce value not found');
149
- }
150
- /**
151
- * Finds a nonce that satisfies the Nano proof-of-work requirements.
152
- *
153
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
154
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
155
- */
156
- static async search(hash, threshold = 0xfffffff8) {
157
- if (NanoPowGl.#gl == null)
158
- throw new Error('WebGL 2 is required');
159
- if (!/^[A-Fa-f0-9]{64}$/.test(hash))
160
- throw new Error(`Invalid hash ${hash}`);
161
- if (typeof threshold !== 'number')
162
- throw new TypeError(`Invalid threshold ${threshold}`);
163
- if (this.#gl == null)
164
- throw new Error('WebGL 2 is required');
165
- /** Set up uniform buffer object */
166
- const uboView = new DataView(new ArrayBuffer(144));
167
- for (let i = 0; i < 64; i += 8) {
168
- const uint32 = hash.slice(i, i + 8);
169
- uboView.setUint32(i * 2, parseInt(uint32, 16));
170
- }
171
- uboView.setUint32(128, threshold, true);
172
- uboView.setFloat32(132, NanoPowGl.#WORKLOAD - 1, true);
173
- NanoPowGl.#gl.bindBuffer(NanoPowGl.#gl.UNIFORM_BUFFER, NanoPowGl.#uboBuffer);
174
- NanoPowGl.#gl.bufferSubData(NanoPowGl.#gl.UNIFORM_BUFFER, 0, uboView);
175
- NanoPowGl.#gl.bindBuffer(NanoPowGl.#gl.UNIFORM_BUFFER, null);
176
- /** Start drawing to calculate one nonce per pixel */
177
- let nonce = null;
178
- const seed = new Uint8Array(8);
179
- while (nonce == null) {
180
- crypto.getRandomValues(seed);
181
- this.#draw(seed);
182
- const found = await this.#checkQueryResult();
183
- if (found) {
184
- nonce = this.#readResult(seed);
185
- }
186
- }
187
- return nonce;
188
- }
189
- /**
190
- * Validates that a nonce satisfies Nano proof-of-work requirements.
191
- *
192
- * @param {string} work - Hexadecimal proof-of-work value to validate
193
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
194
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
195
- */
196
- static async validate(work, hash, threshold = 0xfffffff8) {
197
- if (NanoPowGl.#gl == null)
198
- throw new Error('WebGL 2 is required');
199
- if (!/^[A-Fa-f0-9]{16}$/.test(work))
200
- throw new Error(`Invalid work ${work}`);
201
- if (!/^[A-Fa-f0-9]{64}$/.test(hash))
202
- throw new Error(`Invalid hash ${hash}`);
203
- if (typeof threshold !== 'number')
204
- throw new TypeError(`Invalid threshold ${threshold}`);
205
- if (this.#gl == null)
206
- throw new Error('WebGL 2 is required');
207
- /** Set up uniform buffer object */
208
- const uboView = new DataView(new ArrayBuffer(144));
209
- for (let i = 0; i < 64; i += 8) {
210
- const uint32 = hash.slice(i, i + 8);
211
- uboView.setUint32(i * 2, parseInt(uint32, 16));
212
- }
213
- uboView.setUint32(128, threshold, true);
214
- uboView.setFloat32(132, NanoPowGl.#WORKLOAD - 1, true);
215
- NanoPowGl.#gl.bindBuffer(NanoPowGl.#gl.UNIFORM_BUFFER, NanoPowGl.#uboBuffer);
216
- NanoPowGl.#gl.bufferSubData(NanoPowGl.#gl.UNIFORM_BUFFER, 0, uboView);
217
- NanoPowGl.#gl.bindBuffer(NanoPowGl.#gl.UNIFORM_BUFFER, null);
218
- /** Start drawing to calculate one nonce per pixel */
219
- let nonce = null;
220
- const data = new DataView(new ArrayBuffer(8));
221
- data.setBigUint64(0, BigInt(`0x${work}`), true);
222
- const seed = new Uint8Array(data.buffer);
223
- this.#draw(seed);
224
- const found = await this.#checkQueryResult();
225
- if (found) {
226
- nonce = this.#readResult(seed);
227
- }
228
- if (found && nonce !== work)
229
- throw new Error(`Nonce found but does not match work`);
230
- return found;
231
- }
232
- }
@@ -1,24 +0,0 @@
1
- /**
2
- * Nano proof-of-work using WebGPU.
3
- */
4
- export declare class NanoPowGpu {
5
- #private;
6
- static init(): Promise<void>;
7
- static setup(): void;
8
- static reset(): void;
9
- /**
10
- * Finds a nonce that satisfies the Nano proof-of-work requirements.
11
- *
12
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
13
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
14
- */
15
- static search(hash: string, threshold?: number): Promise<string>;
16
- /**
17
- * Validates that a nonce satisfies Nano proof-of-work requirements.
18
- *
19
- * @param {string} work - Hexadecimal proof-of-work value to validate
20
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
21
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
22
- */
23
- static validate(work: string, hash: string, threshold?: number): Promise<boolean>;
24
- }
@@ -1,236 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-License-Identifier: GPL-3.0-or-later
3
- /// <reference types="@webgpu/types" />
4
- import { NanoPowGpuComputeShader } from '#shaders';
5
- /**
6
- * Nano proof-of-work using WebGPU.
7
- */
8
- export class NanoPowGpu {
9
- // Initialize WebGPU
10
- static #busy = false;
11
- static #device = null;
12
- static #uboBuffer;
13
- static #gpuBuffer;
14
- static #cpuBuffer;
15
- static #bindGroupLayout;
16
- static #pipeline;
17
- // Initialize WebGPU
18
- static async init() {
19
- if (this.#busy)
20
- return;
21
- this.#busy = true;
22
- // Request device and adapter
23
- if (navigator.gpu == null)
24
- throw new Error('WebGPU is not supported in this browser.');
25
- try {
26
- const adapter = await navigator.gpu.requestAdapter();
27
- if (adapter == null)
28
- throw new Error('WebGPU adapter refused by browser.');
29
- const device = await adapter.requestDevice();
30
- if (!(device instanceof GPUDevice))
31
- throw new Error('WebGPU device failed to load.');
32
- device.lost.then(this.reset);
33
- this.#device = device;
34
- this.setup();
35
- }
36
- catch (err) {
37
- throw new Error(`WebGPU initialization failed. ${err}`);
38
- }
39
- finally {
40
- this.#busy = false;
41
- }
42
- }
43
- static setup() {
44
- if (this.#device == null)
45
- throw new Error(`WebGPU device failed to load.`);
46
- // Create buffers for writing GPU calculations and reading from Javascript
47
- this.#uboBuffer = this.#device.createBuffer({
48
- size: 48,
49
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
50
- });
51
- this.#gpuBuffer = this.#device.createBuffer({
52
- size: 16,
53
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC
54
- });
55
- this.#cpuBuffer = this.#device.createBuffer({
56
- size: 16,
57
- usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
58
- });
59
- // Create binding group data structure and use it later once UBO is known
60
- this.#bindGroupLayout = this.#device.createBindGroupLayout({
61
- entries: [
62
- {
63
- binding: 0,
64
- visibility: GPUShaderStage.COMPUTE,
65
- buffer: { type: 'uniform' },
66
- },
67
- {
68
- binding: 1,
69
- visibility: GPUShaderStage.COMPUTE,
70
- buffer: { type: 'storage' },
71
- }
72
- ]
73
- });
74
- // Create pipeline to connect compute shader to binding layout
75
- this.#pipeline = this.#device.createComputePipeline({
76
- layout: this.#device.createPipelineLayout({
77
- bindGroupLayouts: [this.#bindGroupLayout]
78
- }),
79
- compute: {
80
- entryPoint: 'main',
81
- module: this.#device.createShaderModule({
82
- code: NanoPowGpuComputeShader
83
- })
84
- }
85
- });
86
- }
87
- static reset() {
88
- console.warn(`GPU device lost. Reinitializing...`);
89
- NanoPowGpu.#cpuBuffer?.destroy();
90
- NanoPowGpu.#gpuBuffer?.destroy();
91
- NanoPowGpu.#uboBuffer?.destroy();
92
- NanoPowGpu.#busy = false;
93
- NanoPowGpu.init();
94
- }
95
- static async #dispatch(seed, hash, threshold, passes) {
96
- if (this.#device == null)
97
- throw new Error(`WebGPU device failed to load.`);
98
- // Set up uniform buffer object
99
- // Note: u32 size is 4, but total alignment must be multiple of 16
100
- const uboView = new DataView(new ArrayBuffer(48));
101
- for (let i = 0; i < 64; i += 8) {
102
- const uint32 = hash.slice(i, i + 8);
103
- uboView.setUint32(i / 2, parseInt(uint32, 16));
104
- }
105
- uboView.setBigUint64(32, seed, true);
106
- uboView.setUint32(40, threshold, true);
107
- this.#device.queue.writeBuffer(this.#uboBuffer, 0, uboView);
108
- // Reset `nonce` and `found` to 0u in WORK before each calculation
109
- this.#device.queue.writeBuffer(this.#gpuBuffer, 0, new Uint32Array([0, 0, 0]));
110
- // Bind UBO read and GPU write buffers
111
- const bindGroup = this.#device.createBindGroup({
112
- layout: this.#bindGroupLayout,
113
- entries: [
114
- {
115
- binding: 0,
116
- resource: {
117
- buffer: this.#uboBuffer
118
- },
119
- },
120
- {
121
- binding: 1,
122
- resource: {
123
- buffer: this.#gpuBuffer
124
- },
125
- },
126
- ],
127
- });
128
- // Create command encoder to issue commands to GPU and initiate computation
129
- const commandEncoder = this.#device.createCommandEncoder();
130
- const passEncoder = commandEncoder.beginComputePass();
131
- // Issue commands and end compute pass structure
132
- passEncoder.setPipeline(this.#pipeline);
133
- passEncoder.setBindGroup(0, bindGroup);
134
- passEncoder.dispatchWorkgroups(passes, passes);
135
- passEncoder.end();
136
- // Copy 8-byte nonce and 4-byte found flag from GPU to CPU for reading
137
- commandEncoder.copyBufferToBuffer(this.#gpuBuffer, 0, this.#cpuBuffer, 0, 12);
138
- // End computation by passing array of command buffers to command queue for execution
139
- this.#device.queue.submit([commandEncoder.finish()]);
140
- // Read results back to Javascript and then unmap buffer after reading
141
- let data = null;
142
- try {
143
- await this.#cpuBuffer.mapAsync(GPUMapMode.READ);
144
- await this.#device.queue.onSubmittedWorkDone();
145
- data = new DataView(this.#cpuBuffer.getMappedRange().slice(0));
146
- this.#cpuBuffer.unmap();
147
- }
148
- catch (err) {
149
- console.warn(`Error getting data from GPU. ${err}`);
150
- return this.#dispatch(seed, hash, threshold, passes);
151
- }
152
- if (data == null)
153
- throw new Error(`Failed to get data from buffer.`);
154
- return data;
155
- }
156
- /**
157
- * Finds a nonce that satisfies the Nano proof-of-work requirements.
158
- *
159
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
160
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
161
- */
162
- static async search(hash, threshold = 0xfffffff8) {
163
- if (this.#busy) {
164
- return new Promise(resolve => {
165
- setTimeout(async () => {
166
- const result = this.search(hash, threshold);
167
- resolve(result);
168
- }, 100);
169
- });
170
- }
171
- this.#busy = true;
172
- if (!/^[A-Fa-f0-9]{64}$/.test(hash))
173
- throw new TypeError(`Invalid hash ${hash}`);
174
- if (typeof threshold !== 'number')
175
- throw new TypeError(`Invalid threshold ${threshold}`);
176
- // Ensure WebGPU is initialized before calculating
177
- let loads = 0;
178
- while (this.#device == null && loads < 20) {
179
- await new Promise(resolve => {
180
- setTimeout(resolve, 500);
181
- });
182
- }
183
- if (this.#device == null)
184
- throw new Error(`WebGPU device failed to load.`);
185
- let nonce = 0n;
186
- do {
187
- const random = Math.floor(Math.random() * 0xffffffff);
188
- const seed = (BigInt(random) << 32n) | BigInt(random);
189
- const data = await this.#dispatch(seed, hash, threshold, 0xff);
190
- nonce = data.getBigUint64(0, true);
191
- this.#busy = !data.getUint32(8);
192
- } while (this.#busy);
193
- return nonce.toString(16).padStart(16, '0');
194
- }
195
- /**
196
- * Validates that a nonce satisfies Nano proof-of-work requirements.
197
- *
198
- * @param {string} work - Hexadecimal proof-of-work value to validate
199
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
200
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
201
- */
202
- static async validate(work, hash, threshold = 0xfffffff8) {
203
- if (this.#busy) {
204
- return new Promise(resolve => {
205
- setTimeout(async () => {
206
- const result = this.validate(work, hash, threshold);
207
- resolve(result);
208
- }, 100);
209
- });
210
- }
211
- this.#busy = true;
212
- if (!/^[A-Fa-f0-9]{16}$/.test(work))
213
- throw new TypeError(`Invalid work ${work}`);
214
- if (!/^[A-Fa-f0-9]{64}$/.test(hash))
215
- throw new TypeError(`Invalid hash ${hash}`);
216
- if (typeof threshold !== 'number')
217
- throw new TypeError(`Invalid threshold ${threshold}`);
218
- // Ensure WebGPU is initialized before calculating
219
- let loads = 0;
220
- while (this.#device == null && loads < 20) {
221
- await new Promise(resolve => {
222
- setTimeout(resolve, 500);
223
- });
224
- }
225
- if (this.#device == null)
226
- throw new Error(`WebGPU device failed to load.`);
227
- const seed = BigInt(`0x${work}`);
228
- const data = await this.#dispatch(seed, hash, threshold, 1);
229
- const nonce = data.getBigUint64(0, true).toString(16).padStart(16, '0');
230
- const found = !!data.getUint32(8);
231
- this.#busy = false;
232
- if (found && work !== nonce)
233
- throw new Error(`Nonce found but does not match work`);
234
- return found;
235
- }
236
- }
@@ -1,4 +0,0 @@
1
- import { NanoPowGl } from "./gl.js";
2
- import { NanoPowGpu } from "./gpu.js";
3
- declare const NanoPow: typeof NanoPowGl | null;
4
- export { NanoPow, NanoPowGl, NanoPowGpu };
@@ -1,23 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-License-Identifier: GPL-3.0-or-later
3
- import { NanoPowGl } from "./gl.js";
4
- import { NanoPowGpu } from "./gpu.js";
5
- let isGlSupported, isGpuSupported = false;
6
- try {
7
- await NanoPowGl.init();
8
- isGlSupported = true;
9
- }
10
- catch (err) {
11
- console.warn(`WebGL is not supported in this environment.`);
12
- isGlSupported = false;
13
- }
14
- try {
15
- await NanoPowGpu.init();
16
- isGpuSupported = true;
17
- }
18
- catch (err) {
19
- console.warn(`WebGPU is not supported in this environment.`);
20
- isGpuSupported = false;
21
- }
22
- const NanoPow = isGpuSupported ? NanoPowGpu : isGlSupported ? NanoPowGl : null;
23
- export { NanoPow, NanoPowGl, NanoPowGpu };
package/dist/global.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/dist/global.js DELETED
@@ -1,6 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-License-Identifier: GPL-3.0-or-later
3
- import { NanoPow as np, NanoPowGl as gl, NanoPowGpu as gpu } from './main.js';
4
- globalThis.NanoPow ??= np;
5
- globalThis.NanoPowGl ??= gl;
6
- globalThis.NanoPowGpu ??= gpu;
package/dist/main.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import { NanoPow, NanoPowGl, NanoPowGpu } from "#classes";
2
- export { NanoPow, NanoPowGl, NanoPowGpu };
3
- export default NanoPow;
package/dist/main.js DELETED
@@ -1,5 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-License-Identifier: GPL-3.0-or-later
3
- import { NanoPow, NanoPowGl, NanoPowGpu } from "#classes";
4
- export { NanoPow, NanoPowGl, NanoPowGpu };
5
- export default NanoPow;
@@ -1 +0,0 @@
1
- export declare const NanoPowGlFragmentShader = "#version 300 es\n#pragma vscode_glsllint_stage: frag\nprecision highp float;\nprecision highp int;\n\nin vec2 uv_pos;\nout vec4 fragColor;\n\n// blockhash - array of precalculated block hash components\n// threshold - 0xfffffff8 for send/change blocks, 0xfffffe00 for all else\n// workload - Defines canvas size\nlayout(std140) uniform UBO {\n\tuint blockhash[8];\n\tuint threshold;\n\tfloat workload;\n};\n\n// Random work values\n// First 2 bytes will be overwritten by texture pixel position\n// Second 2 bytes will be modified if the canvas size is greater than 256x256\n// Last 4 bytes remain as generated externally\nlayout(std140) uniform WORK {\n\tuvec4 work[2];\n};\n\n// Defined separately from uint v[32] below as the original value is required\n// to calculate the second uint32 of the digest for threshold comparison\nconst uint BLAKE2B_IV32_1 = 0x6A09E667u;\n\n// Both buffers represent 16 uint64s as 32 uint32s\n// because that's what GLSL offers, just like Javascript\n\n// Compression buffer, intialized to 2 instances of the initialization vector\n// The following values have been modified from the BLAKE2B_IV:\n// OUTLEN is constant 8 bytes\n// v[0] ^= 0x01010000u ^ uint(OUTLEN);\n// INLEN is constant 40 bytes: work value (8) + block hash (32)\n// v[24] ^= uint(INLEN);\n// It's always the \"last\" compression at this INLEN\n// v[28] = ~v[28];\n// v[29] = ~v[29];\nuint v[32] = uint[32](\n\t0xF2BDC900u, 0x6A09E667u, 0x84CAA73Bu, 0xBB67AE85u,\n\t0xFE94F82Bu, 0x3C6EF372u, 0x5F1D36F1u, 0xA54FF53Au,\n\t0xADE682D1u, 0x510E527Fu, 0x2B3E6C1Fu, 0x9B05688Cu,\n\t0xFB41BD6Bu, 0x1F83D9ABu, 0x137E2179u, 0x5BE0CD19u,\n\t0xF3BCC908u, 0x6A09E667u, 0x84CAA73Bu, 0xBB67AE85u,\n\t0xFE94F82Bu, 0x3C6EF372u, 0x5F1D36F1u, 0xA54FF53Au,\n\t0xADE682F9u, 0x510E527Fu, 0x2B3E6C1Fu, 0x9B05688Cu,\n\t0x04BE4294u, 0xE07C2654u, 0x137E2179u, 0x5BE0CD19u\n);\n// Input data buffer\nuint m[32];\n\n// These are offsets into the input data buffer for each mixing step.\n// They are multiplied by 2 from the original SIGMA values in\n// the C reference implementation, which refered to uint64s.\nconst uint SIGMA82[192] = uint[192](\n\t0u,2u,4u,6u,8u,10u,12u,14u,16u,18u,20u,22u,24u,26u,28u,30u,\n\t28u,20u,8u,16u,18u,30u,26u,12u,2u,24u,0u,4u,22u,14u,10u,6u,\n\t22u,16u,24u,0u,10u,4u,30u,26u,20u,28u,6u,12u,14u,2u,18u,8u,\n\t14u,18u,6u,2u,26u,24u,22u,28u,4u,12u,10u,20u,8u,0u,30u,16u,\n\t18u,0u,10u,14u,4u,8u,20u,30u,28u,2u,22u,24u,12u,16u,6u,26u,\n\t4u,24u,12u,20u,0u,22u,16u,6u,8u,26u,14u,10u,30u,28u,2u,18u,\n\t24u,10u,2u,30u,28u,26u,8u,20u,0u,14u,12u,6u,18u,4u,16u,22u,\n\t26u,22u,14u,28u,24u,2u,6u,18u,10u,0u,30u,8u,16u,12u,4u,20u,\n\t12u,30u,28u,18u,22u,6u,0u,16u,24u,4u,26u,14u,2u,8u,20u,10u,\n\t20u,4u,16u,8u,14u,12u,2u,10u,30u,22u,18u,28u,6u,24u,26u,0u,\n\t0u,2u,4u,6u,8u,10u,12u,14u,16u,18u,20u,22u,24u,26u,28u,30u,\n\t28u,20u,8u,16u,18u,30u,26u,12u,2u,24u,0u,4u,22u,14u,10u,6u\n);\n\n// G mixing function\nvoid G (uint ix, uint iy, uint a, uint b, uint c, uint d) {\n\tbool carry;\n\tuint o0;\n\tuint o1;\n\tuint xor0;\n\tuint xor1;\n\n\t// a = a + b;\n\to0 = v[a] + v[b];\n\to1 = v[a+1u] + v[b+1u];\n\tcarry = o0 < v[a];\n\to1 = o1 + uint(mix(0.0, 1.0, float(carry)));\n\tv[a] = o0;\n\tv[a+1u] = o1;\n\n\t// a = a + m[sigma[r][2*i+0]];\n\to0 = v[a] + m[ix];\n\to1 = v[a+1u] + m[ix+1u];\n\tcarry = o0 < v[a];\n\to1 = o1 + uint(mix(0.0, 1.0, float(carry)));\n\tv[a] = o0;\n\tv[a+1u] = o1;\n\n\t// d = rotr64(d ^ a, 32);\n\txor0 = v[d] ^ v[a];\n\txor1 = v[d+1u] ^ v[a+1u];\n\tv[d] = xor1;\n\tv[d+1u] = xor0;\n\n\t// c = c + d;\n\to0 = v[c] + v[d];\n\to1 = v[c+1u] + v[d+1u];\n\tcarry = o0 < v[c];\n\to1 = o1 + uint(mix(0.0, 1.0, float(carry)));\n\tv[c] = o0;\n\tv[c+1u] = o1;\n\n\t// b = rotr64(b ^ c, 24);\n\txor0 = v[b] ^ v[c];\n\txor1 = v[b+1u] ^ v[c+1u];\n\tv[b] = (xor0 >> 24u) ^ (xor1 << 8u);\n\tv[b+1u] = (xor1 >> 24u) ^ (xor0 << 8u);\n\n\t// a = a + b;\n\to0 = v[a] + v[b];\n\to1 = v[a+1u] + v[b+1u];\n\tcarry = o0 < v[a];\n\to1 = o1 + uint(mix(0.0, 1.0, float(carry)));\n\tv[a] = o0;\n\tv[a+1u] = o1;\n\n\t// a = a + m[sigma[r][2*i+1]];\n\to0 = v[a] + m[iy];\n\to1 = v[a+1u] + m[iy+1u];\n\tcarry = o0 < v[a];\n\to1 = o1 + uint(mix(0.0, 1.0, float(carry)));\n\tv[a] = o0;\n\tv[a+1u] = o1;\n\n\t// d = rotr64(d ^ a, 16)\n\txor0 = v[d] ^ v[a];\n\txor1 = v[d+1u] ^ v[a+1u];\n\tv[d] = (xor0 >> 16u) ^ (xor1 << 16u);\n\tv[d+1u] = (xor1 >> 16u) ^ (xor0 << 16u);\n\n\t// c = c + d;\n\to0 = v[c] + v[d];\n\to1 = v[c+1u] + v[d+1u];\n\tcarry = o0 < v[c];\n\to1 = o1 + uint(mix(0.0, 1.0, float(carry)));\n\tv[c] = o0;\n\tv[c+1u] = o1;\n\n\t// b = rotr64(b ^ c, 63)\n\txor0 = v[b] ^ v[c];\n\txor1 = v[b+1u] ^ v[c+1u];\n\tv[b] = (xor1 >> 31u) ^ (xor0 << 1u);\n\tv[b+1u] = (xor0 >> 31u) ^ (xor1 << 1u);\n}\n\nvoid main() {\n\tint i;\n\tuvec4 u_work0 = work[0u];\n\tuvec4 u_work1 = work[1u];\n\tuint uv_x = uint(uv_pos.x * workload);\n\tuint uv_y = uint(uv_pos.y * workload);\n\tuint x_pos = uv_x % 256u;\n\tuint y_pos = uv_y % 256u;\n\tuint x_index = (uv_x - x_pos) / 256u;\n\tuint y_index = (uv_y - y_pos) / 256u;\n\n\t// First 2 work bytes are the x,y pos within the 256x256 area, the next\n\t// two bytes are modified from the random generated value, XOR'd with\n\t// the x,y area index of where this pixel is located\n\tm[0u] = (x_pos ^ (y_pos << 8u) ^ ((u_work0.b ^ x_index) << 16u) ^ ((u_work0.a ^ y_index) << 24u));\n\n\t// Remaining bytes are un-modified from the random generated value\n\tm[1u] = (u_work1.r ^ (u_work1.g << 8u) ^ (u_work1.b << 16u) ^ (u_work1.a << 24u));\n\n\t// Block hash\n\tfor (uint i = 0u; i < 8u; i = i + 1u) {\n\t\tm[i+2u] = blockhash[i];\n\t}\n\n\t// twelve rounds of mixing\n\tfor(uint i = 0u; i < 12u; i = i + 1u) {\n\t\tG(SIGMA82[i * 16u + 0u], SIGMA82[i * 16u + 1u], 0u, 8u, 16u, 24u);\n\t\tG(SIGMA82[i * 16u + 2u], SIGMA82[i * 16u + 3u], 2u, 10u, 18u, 26u);\n\t\tG(SIGMA82[i * 16u + 4u], SIGMA82[i * 16u + 5u], 4u, 12u, 20u, 28u);\n\t\tG(SIGMA82[i * 16u + 6u], SIGMA82[i * 16u + 7u], 6u, 14u, 22u, 30u);\n\t\tG(SIGMA82[i * 16u + 8u], SIGMA82[i * 16u + 9u], 0u, 10u, 20u, 30u);\n\t\tG(SIGMA82[i * 16u + 10u], SIGMA82[i * 16u + 11u], 2u, 12u, 22u, 24u);\n\t\tG(SIGMA82[i * 16u + 12u], SIGMA82[i * 16u + 13u], 4u, 14u, 16u, 26u);\n\t\tG(SIGMA82[i * 16u + 14u], SIGMA82[i * 16u + 15u], 6u, 8u, 18u, 28u);\n\t}\n\n\t// Pixel data is multipled by threshold test result (0 or 1)\n\t// First 4 bytes insignificant, only calculate digest of second 4 bytes\n\tif ((BLAKE2B_IV32_1 ^ v[1u] ^ v[17u]) > threshold) {\n\t\tfragColor = vec4(\n\t\t\tfloat(x_index + 1u)/255.0, // +1 to distinguish from 0 (unsuccessful) pixels\n\t\t\tfloat(y_index + 1u)/255.0, // Same as previous\n\t\t\tfloat(x_pos)/255.0, // Return the 2 custom bytes used in work value\n\t\t\tfloat(y_pos)/255.0 // Second custom byte\n\t\t);\n\t} else {\n \t\tdiscard;\n\t}\n}\n";
@@ -1,206 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-FileContributor: Ben Green <ben@latenightsketches.com>
3
- // SPDX-License-Identifier: GPL-3.0-or-later AND MIT
4
- export const NanoPowGlFragmentShader = `#version 300 es
5
- #pragma vscode_glsllint_stage: frag
6
- precision highp float;
7
- precision highp int;
8
-
9
- in vec2 uv_pos;
10
- out vec4 fragColor;
11
-
12
- // blockhash - array of precalculated block hash components
13
- // threshold - 0xfffffff8 for send/change blocks, 0xfffffe00 for all else
14
- // workload - Defines canvas size
15
- layout(std140) uniform UBO {
16
- uint blockhash[8];
17
- uint threshold;
18
- float workload;
19
- };
20
-
21
- // Random work values
22
- // First 2 bytes will be overwritten by texture pixel position
23
- // Second 2 bytes will be modified if the canvas size is greater than 256x256
24
- // Last 4 bytes remain as generated externally
25
- layout(std140) uniform WORK {
26
- uvec4 work[2];
27
- };
28
-
29
- // Defined separately from uint v[32] below as the original value is required
30
- // to calculate the second uint32 of the digest for threshold comparison
31
- const uint BLAKE2B_IV32_1 = 0x6A09E667u;
32
-
33
- // Both buffers represent 16 uint64s as 32 uint32s
34
- // because that's what GLSL offers, just like Javascript
35
-
36
- // Compression buffer, intialized to 2 instances of the initialization vector
37
- // The following values have been modified from the BLAKE2B_IV:
38
- // OUTLEN is constant 8 bytes
39
- // v[0] ^= 0x01010000u ^ uint(OUTLEN);
40
- // INLEN is constant 40 bytes: work value (8) + block hash (32)
41
- // v[24] ^= uint(INLEN);
42
- // It's always the "last" compression at this INLEN
43
- // v[28] = ~v[28];
44
- // v[29] = ~v[29];
45
- uint v[32] = uint[32](
46
- 0xF2BDC900u, 0x6A09E667u, 0x84CAA73Bu, 0xBB67AE85u,
47
- 0xFE94F82Bu, 0x3C6EF372u, 0x5F1D36F1u, 0xA54FF53Au,
48
- 0xADE682D1u, 0x510E527Fu, 0x2B3E6C1Fu, 0x9B05688Cu,
49
- 0xFB41BD6Bu, 0x1F83D9ABu, 0x137E2179u, 0x5BE0CD19u,
50
- 0xF3BCC908u, 0x6A09E667u, 0x84CAA73Bu, 0xBB67AE85u,
51
- 0xFE94F82Bu, 0x3C6EF372u, 0x5F1D36F1u, 0xA54FF53Au,
52
- 0xADE682F9u, 0x510E527Fu, 0x2B3E6C1Fu, 0x9B05688Cu,
53
- 0x04BE4294u, 0xE07C2654u, 0x137E2179u, 0x5BE0CD19u
54
- );
55
- // Input data buffer
56
- uint m[32];
57
-
58
- // These are offsets into the input data buffer for each mixing step.
59
- // They are multiplied by 2 from the original SIGMA values in
60
- // the C reference implementation, which refered to uint64s.
61
- const uint SIGMA82[192] = uint[192](
62
- 0u,2u,4u,6u,8u,10u,12u,14u,16u,18u,20u,22u,24u,26u,28u,30u,
63
- 28u,20u,8u,16u,18u,30u,26u,12u,2u,24u,0u,4u,22u,14u,10u,6u,
64
- 22u,16u,24u,0u,10u,4u,30u,26u,20u,28u,6u,12u,14u,2u,18u,8u,
65
- 14u,18u,6u,2u,26u,24u,22u,28u,4u,12u,10u,20u,8u,0u,30u,16u,
66
- 18u,0u,10u,14u,4u,8u,20u,30u,28u,2u,22u,24u,12u,16u,6u,26u,
67
- 4u,24u,12u,20u,0u,22u,16u,6u,8u,26u,14u,10u,30u,28u,2u,18u,
68
- 24u,10u,2u,30u,28u,26u,8u,20u,0u,14u,12u,6u,18u,4u,16u,22u,
69
- 26u,22u,14u,28u,24u,2u,6u,18u,10u,0u,30u,8u,16u,12u,4u,20u,
70
- 12u,30u,28u,18u,22u,6u,0u,16u,24u,4u,26u,14u,2u,8u,20u,10u,
71
- 20u,4u,16u,8u,14u,12u,2u,10u,30u,22u,18u,28u,6u,24u,26u,0u,
72
- 0u,2u,4u,6u,8u,10u,12u,14u,16u,18u,20u,22u,24u,26u,28u,30u,
73
- 28u,20u,8u,16u,18u,30u,26u,12u,2u,24u,0u,4u,22u,14u,10u,6u
74
- );
75
-
76
- // G mixing function
77
- void G (uint ix, uint iy, uint a, uint b, uint c, uint d) {
78
- bool carry;
79
- uint o0;
80
- uint o1;
81
- uint xor0;
82
- uint xor1;
83
-
84
- // a = a + b;
85
- o0 = v[a] + v[b];
86
- o1 = v[a+1u] + v[b+1u];
87
- carry = o0 < v[a];
88
- o1 = o1 + uint(mix(0.0, 1.0, float(carry)));
89
- v[a] = o0;
90
- v[a+1u] = o1;
91
-
92
- // a = a + m[sigma[r][2*i+0]];
93
- o0 = v[a] + m[ix];
94
- o1 = v[a+1u] + m[ix+1u];
95
- carry = o0 < v[a];
96
- o1 = o1 + uint(mix(0.0, 1.0, float(carry)));
97
- v[a] = o0;
98
- v[a+1u] = o1;
99
-
100
- // d = rotr64(d ^ a, 32);
101
- xor0 = v[d] ^ v[a];
102
- xor1 = v[d+1u] ^ v[a+1u];
103
- v[d] = xor1;
104
- v[d+1u] = xor0;
105
-
106
- // c = c + d;
107
- o0 = v[c] + v[d];
108
- o1 = v[c+1u] + v[d+1u];
109
- carry = o0 < v[c];
110
- o1 = o1 + uint(mix(0.0, 1.0, float(carry)));
111
- v[c] = o0;
112
- v[c+1u] = o1;
113
-
114
- // b = rotr64(b ^ c, 24);
115
- xor0 = v[b] ^ v[c];
116
- xor1 = v[b+1u] ^ v[c+1u];
117
- v[b] = (xor0 >> 24u) ^ (xor1 << 8u);
118
- v[b+1u] = (xor1 >> 24u) ^ (xor0 << 8u);
119
-
120
- // a = a + b;
121
- o0 = v[a] + v[b];
122
- o1 = v[a+1u] + v[b+1u];
123
- carry = o0 < v[a];
124
- o1 = o1 + uint(mix(0.0, 1.0, float(carry)));
125
- v[a] = o0;
126
- v[a+1u] = o1;
127
-
128
- // a = a + m[sigma[r][2*i+1]];
129
- o0 = v[a] + m[iy];
130
- o1 = v[a+1u] + m[iy+1u];
131
- carry = o0 < v[a];
132
- o1 = o1 + uint(mix(0.0, 1.0, float(carry)));
133
- v[a] = o0;
134
- v[a+1u] = o1;
135
-
136
- // d = rotr64(d ^ a, 16)
137
- xor0 = v[d] ^ v[a];
138
- xor1 = v[d+1u] ^ v[a+1u];
139
- v[d] = (xor0 >> 16u) ^ (xor1 << 16u);
140
- v[d+1u] = (xor1 >> 16u) ^ (xor0 << 16u);
141
-
142
- // c = c + d;
143
- o0 = v[c] + v[d];
144
- o1 = v[c+1u] + v[d+1u];
145
- carry = o0 < v[c];
146
- o1 = o1 + uint(mix(0.0, 1.0, float(carry)));
147
- v[c] = o0;
148
- v[c+1u] = o1;
149
-
150
- // b = rotr64(b ^ c, 63)
151
- xor0 = v[b] ^ v[c];
152
- xor1 = v[b+1u] ^ v[c+1u];
153
- v[b] = (xor1 >> 31u) ^ (xor0 << 1u);
154
- v[b+1u] = (xor0 >> 31u) ^ (xor1 << 1u);
155
- }
156
-
157
- void main() {
158
- int i;
159
- uvec4 u_work0 = work[0u];
160
- uvec4 u_work1 = work[1u];
161
- uint uv_x = uint(uv_pos.x * workload);
162
- uint uv_y = uint(uv_pos.y * workload);
163
- uint x_pos = uv_x % 256u;
164
- uint y_pos = uv_y % 256u;
165
- uint x_index = (uv_x - x_pos) / 256u;
166
- uint y_index = (uv_y - y_pos) / 256u;
167
-
168
- // First 2 work bytes are the x,y pos within the 256x256 area, the next
169
- // two bytes are modified from the random generated value, XOR'd with
170
- // the x,y area index of where this pixel is located
171
- m[0u] = (x_pos ^ (y_pos << 8u) ^ ((u_work0.b ^ x_index) << 16u) ^ ((u_work0.a ^ y_index) << 24u));
172
-
173
- // Remaining bytes are un-modified from the random generated value
174
- m[1u] = (u_work1.r ^ (u_work1.g << 8u) ^ (u_work1.b << 16u) ^ (u_work1.a << 24u));
175
-
176
- // Block hash
177
- for (uint i = 0u; i < 8u; i = i + 1u) {
178
- m[i+2u] = blockhash[i];
179
- }
180
-
181
- // twelve rounds of mixing
182
- for(uint i = 0u; i < 12u; i = i + 1u) {
183
- G(SIGMA82[i * 16u + 0u], SIGMA82[i * 16u + 1u], 0u, 8u, 16u, 24u);
184
- G(SIGMA82[i * 16u + 2u], SIGMA82[i * 16u + 3u], 2u, 10u, 18u, 26u);
185
- G(SIGMA82[i * 16u + 4u], SIGMA82[i * 16u + 5u], 4u, 12u, 20u, 28u);
186
- G(SIGMA82[i * 16u + 6u], SIGMA82[i * 16u + 7u], 6u, 14u, 22u, 30u);
187
- G(SIGMA82[i * 16u + 8u], SIGMA82[i * 16u + 9u], 0u, 10u, 20u, 30u);
188
- G(SIGMA82[i * 16u + 10u], SIGMA82[i * 16u + 11u], 2u, 12u, 22u, 24u);
189
- G(SIGMA82[i * 16u + 12u], SIGMA82[i * 16u + 13u], 4u, 14u, 16u, 26u);
190
- G(SIGMA82[i * 16u + 14u], SIGMA82[i * 16u + 15u], 6u, 8u, 18u, 28u);
191
- }
192
-
193
- // Pixel data is multipled by threshold test result (0 or 1)
194
- // First 4 bytes insignificant, only calculate digest of second 4 bytes
195
- if ((BLAKE2B_IV32_1 ^ v[1u] ^ v[17u]) > threshold) {
196
- fragColor = vec4(
197
- float(x_index + 1u)/255.0, // +1 to distinguish from 0 (unsuccessful) pixels
198
- float(y_index + 1u)/255.0, // Same as previous
199
- float(x_pos)/255.0, // Return the 2 custom bytes used in work value
200
- float(y_pos)/255.0 // Second custom byte
201
- );
202
- } else {
203
- discard;
204
- }
205
- }
206
- `;
@@ -1 +0,0 @@
1
- export declare const NanoPowGlVertexShader = "#version 300 es\n#pragma vscode_glsllint_stage: vert\nprecision highp float;\nlayout (location=0) in vec4 position;\nlayout (location=1) in vec2 uv;\n\nout vec2 uv_pos;\n\nvoid main() {\n\tuv_pos = uv;\n\tgl_Position = position;\n}\n";
@@ -1,16 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-FileContributor: Ben Green <ben@latenightsketches.com>
3
- // SPDX-License-Identifier: GPL-3.0-or-later AND MIT
4
- export const NanoPowGlVertexShader = `#version 300 es
5
- #pragma vscode_glsllint_stage: vert
6
- precision highp float;
7
- layout (location=0) in vec4 position;
8
- layout (location=1) in vec2 uv;
9
-
10
- out vec2 uv_pos;
11
-
12
- void main() {
13
- uv_pos = uv;
14
- gl_Position = position;
15
- }
16
- `;
@@ -1,4 +0,0 @@
1
- import { default as NanoPowGpuComputeShader } from "./compute.wgsl";
2
- import { NanoPowGlFragmentShader } from "./gl-fragment.js";
3
- import { NanoPowGlVertexShader } from "./gl-vertex.js";
4
- export { NanoPowGpuComputeShader, NanoPowGlFragmentShader, NanoPowGlVertexShader };
@@ -1,6 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-License-Identifier: GPL-3.0-or-later
3
- import { default as NanoPowGpuComputeShader } from "./compute.wgsl";
4
- import { NanoPowGlFragmentShader } from "./gl-fragment.js";
5
- import { NanoPowGlVertexShader } from "./gl-vertex.js";
6
- export { NanoPowGpuComputeShader, NanoPowGlFragmentShader, NanoPowGlVertexShader };