nano-pow 3.1.2 → 3.1.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.
package/README.md CHANGED
@@ -143,7 +143,8 @@ Email: <bug-nano-pow@zoso.dev>
143
143
  implementation
144
144
 
145
145
  ## Licenses
146
- GPLv3 (or later) & MIT
146
+ GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
147
+ Portions of this code are also provided under the MIT License: <https://spdx.org/licenses/MIT.html>
147
148
 
148
149
  ## Donations
149
150
  If you find this package helpful, please consider tipping the developer.
package/dist/cli.js CHANGED
@@ -2,11 +2,28 @@
2
2
  //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
3
3
  //! SPDX-License-Identifier: GPL-3.0-or-later
4
4
 
5
- import * as puppeteer from 'puppeteer'
6
5
  import * as fs from 'node:fs/promises'
6
+ import * as readline from 'node:readline/promises'
7
+ import * as puppeteer from 'puppeteer'
8
+
9
+ const hashes = []
10
+
11
+ const stdinErrors = []
12
+ if (!process.stdin.isTTY) {
13
+ const stdin = readline.createInterface({
14
+ input: process.stdin
15
+ })
16
+ for await (const line of stdin) {
17
+ if (/^[0-9A-Fa-f]{64}$/.test(line)) {
18
+ hashes.push(line)
19
+ } else {
20
+ stdinErrors.push(`Skipping invalid stdin input: ${line}`)
21
+ }
22
+ }
23
+ }
7
24
 
8
25
  const args = process.argv.slice(2)
9
- if (args.length === 0 || args.some(v => v === '--help' || v === '-h')) {
26
+ if ((hashes.length === 0 && args.length === 0) || (args.some(v => v === '--help' || v === '-h'))) {
10
27
  console.log(`Usage: nano-pow [OPTION]... BLOCKHASH...
11
28
  Generate work for BLOCKHASH, or multiple work values for BLOCKHASH(es)
12
29
  BLOCKHASH is a 64-character hexadecimal string. Multiple blockhashes must be separated by whitespace or line breaks.
@@ -14,6 +31,7 @@ Prints a 16-character hexadecimal work value to standard output. If using --vali
14
31
 
15
32
  -h, --help show this dialog
16
33
  -d, --debug enable additional logging output
34
+ -j, --json format output as JSON
17
35
  -e, --effort=<value> increase demand on GPU processing
18
36
  -t, --threshold=<value> override the minimum threshold value
19
37
  -v, --validate=<value> check an existing work value instead of searching for one
@@ -28,18 +46,17 @@ Full documentation: <https://www.npmjs.com/package/nano-pow>
28
46
  process.exit()
29
47
  }
30
48
 
31
- const hashes = []
49
+ const inArgs = []
32
50
  while (/^[0-9A-Fa-f]{64}$/.test(args[args.length - 1] ?? '')) {
33
- hashes.unshift(args.pop())
34
- }
35
- if (hashes.length === 0) {
36
- console.error('Invalid block hash input')
37
- process.exit(1)
51
+ inArgs.unshift(args.pop())
38
52
  }
53
+ hashes.push(...inArgs)
39
54
 
40
55
  let fn = 'search'
41
56
  let work = ''
57
+ let isJson = false
42
58
  const options = {}
59
+
43
60
  for (let i = 0; i < args.length; i++) {
44
61
  switch (args[i]) {
45
62
  case ('--validate'):
@@ -69,13 +86,27 @@ for (let i = 0; i < args.length; i++) {
69
86
  options['debug'] = true
70
87
  break
71
88
  }
89
+ case ('--json'):
90
+ case ('-j'): {
91
+ isJson = true
92
+ break
93
+ }
94
+ }
95
+ }
96
+
97
+ if (options['debug']) {
98
+ console.log(`NanoPowCli.${fn}()`)
99
+ console.log(`${fn} options`, JSON.stringify(options))
100
+ for (const stdinErr of stdinErrors) {
101
+ console.warn(stdinErr)
72
102
  }
73
103
  }
74
104
 
75
- if (options['debug']) console.log(`NanoPowCli.${fn}()`)
76
- if (options['debug']) console.log(`${fn} options`, JSON.stringify(options))
105
+ if (hashes.length === 0) {
106
+ console.error('Invalid block hash input')
107
+ process.exit(1)
108
+ }
77
109
 
78
- ;
79
110
  /**
80
111
  * Main
81
112
  */
@@ -102,10 +133,22 @@ if (options['debug']) console.log(`${fn} options`, JSON.stringify(options))
102
133
  const output = msg.text().split(' ')
103
134
  if (output[0] === 'cli') {
104
135
  if (output[1] === 'exit') {
136
+ if (isJson) {
137
+ const results = await page.evaluate(() => {
138
+ return window.results
139
+ })
140
+ for (let i = 0; i < results.length; i++) {
141
+ results[i] = {
142
+ blockhash: hashes[i],
143
+ work: results[i]
144
+ }
145
+ }
146
+ console.log(JSON.stringify(results, null, 4))
147
+ }
105
148
  const end = performance.now()
106
149
  if (options['debug']) console.log(end - start, 'ms total |', (end - start) / hashes.length, 'ms avg')
107
- process.exit()
108
- } else {
150
+ await browser.close()
151
+ } else if (!isJson) {
109
152
  console.log(output[1])
110
153
  }
111
154
  } else if (options['debug']) {
@@ -125,10 +168,12 @@ if (options['debug']) console.log(`${fn} options`, JSON.stringify(options))
125
168
  createScript: string => string,
126
169
  })
127
170
  ${NanoPow}
171
+ window.results = []
128
172
  const hashes = ["${hashes.join('","')}"]
129
173
  for (const hash of hashes) {
130
174
  try {
131
175
  const work = await NanoPow.${fn}(${work}hash, ${JSON.stringify(options)})
176
+ window.results.push(work)
132
177
  console.log(\`cli \${work}\`)
133
178
  } catch (err) {
134
179
  console.error(\`cli \${err}\`)
package/dist/main.min.js CHANGED
@@ -68,6 +68,66 @@ layout(std140) uniform WORK {
68
68
  uvec2 seed;
69
69
  };
70
70
 
71
+ /**
72
+ * Initialization vector defined by BLAKE2. Each vec2<u32> represents two halves
73
+ * of the original u64 value from the reference implementation. They appear
74
+ * reversed pairwise as defined below, but this is an illusion due to endianness:
75
+ * the \`x\` component of the vector is the low bits and the \`y\` component is the
76
+ * high bits, and if you laid the bits out individually, they would match the
77
+ * little-endian 64-bit representation.
78
+ */
79
+ const uvec2 BLAKE2B_IV[8] = uvec2[8](
80
+ uvec2(0xF3BCC908u, 0x6A09E667u),
81
+ uvec2(0x84CAA73Bu, 0xBB67AE85u),
82
+ uvec2(0xFE94F82Bu, 0x3C6EF372u),
83
+ uvec2(0x5F1D36F1u, 0xA54FF53Au),
84
+ uvec2(0xADE682D1u, 0x510E527Fu),
85
+ uvec2(0x2B3E6C1Fu, 0x9B05688Cu),
86
+ uvec2(0xFB41BD6Bu, 0x1F83D9ABu),
87
+ uvec2(0x137E2179u, 0x5BE0CD19u)
88
+ );
89
+
90
+ /**
91
+ * Parameter block as defined in BLAKE2 section 2.8 and configured as follows:
92
+ * maximal depth = 1, fanout = 1, digest byte length = 8
93
+ */
94
+ const uvec2 BLAKE2B_PARAM = uvec2(0x01010008u, 0u);
95
+
96
+ /**
97
+ * Message input length which is always 40 for Nano.
98
+ * 8 nonce bytes + 32 block hash bytes
99
+ */
100
+ const uvec2 BLAKE2B_INLEN = uvec2(0x00000028u, 0u);
101
+
102
+ /**
103
+ * Finalization flag as defined in BLAKE2 section 2.4 and set to ~0 since this is
104
+ * the final (and only) message block being hashed.
105
+ */
106
+ const uvec2 BLAKE2B_FINAL = uvec2(0xFFFFFFFFu, 0xFFFFFFFFu);
107
+
108
+ /**
109
+ * Fully initialized state array that is locally copied at each thread start.
110
+ * Application of each XOR is defined by BLAKE2 section 2.4 compression function.
111
+ */
112
+ const uvec2 BLAKE2B_INIT[16] = uvec2[16](
113
+ BLAKE2B_IV[0u] ^ BLAKE2B_PARAM,
114
+ BLAKE2B_IV[1u],
115
+ BLAKE2B_IV[2u],
116
+ BLAKE2B_IV[3u],
117
+ BLAKE2B_IV[4u],
118
+ BLAKE2B_IV[5u],
119
+ BLAKE2B_IV[6u],
120
+ BLAKE2B_IV[7u],
121
+ BLAKE2B_IV[0u],
122
+ BLAKE2B_IV[1u],
123
+ BLAKE2B_IV[2u],
124
+ BLAKE2B_IV[3u],
125
+ BLAKE2B_IV[4u] ^ BLAKE2B_INLEN,
126
+ BLAKE2B_IV[5u],
127
+ BLAKE2B_IV[6u] ^ BLAKE2B_FINAL,
128
+ BLAKE2B_IV[7u]
129
+ );
130
+
71
131
  // Defined separately from uint v[0].y below as the original value is required
72
132
  // to calculate the second uint32 of the digest for threshold comparison
73
133
  const uint BLAKE2B_IV32_1 = 0x6A09E667u;
@@ -79,36 +139,6 @@ const uvec4 ROTATE_16 = uvec4(16u);
79
139
  const uvec4 ROTATE_24 = uvec4(24u);
80
140
  const uvec4 ROTATE_31 = uvec4(31u);
81
141
 
82
- // Both buffers represent 16 uint64s as 32 uint32s
83
- // because that's what GLSL offers, just like Javascript
84
-
85
- // Compression buffer, intialized to 2 instances of the initialization vector
86
- // The following values have been modified from the BLAKE2B_IV:
87
- // OUTLEN is constant 8 bytes
88
- // v[0] ^= 0x01010000u ^ uint(OUTLEN);
89
- // INLEN is constant 40 bytes: work value (8) + block hash (32)
90
- // v[12] ^= uint(INLEN);
91
- // It's always the "last" compression at this INLEN
92
- // v[14] = ~v[14];
93
- const uvec2 blake2b_iv[16] = uvec2[16](
94
- uvec2(0xF2BDC900u, 0x6A09E667u),
95
- uvec2(0x84CAA73Bu, 0xBB67AE85u),
96
- uvec2(0xFE94F82Bu, 0x3C6EF372u),
97
- uvec2(0x5F1D36F1u, 0xA54FF53Au),
98
- uvec2(0xADE682D1u, 0x510E527Fu),
99
- uvec2(0x2B3E6C1Fu, 0x9B05688Cu),
100
- uvec2(0xFB41BD6Bu, 0x1F83D9ABu),
101
- uvec2(0x137E2179u, 0x5BE0CD19u),
102
- uvec2(0xF3BCC908u, 0x6A09E667u),
103
- uvec2(0x84CAA73Bu, 0xBB67AE85u),
104
- uvec2(0xFE94F82Bu, 0x3C6EF372u),
105
- uvec2(0x5F1D36F1u, 0xA54FF53Au),
106
- uvec2(0xADE682F9u, 0x510E527Fu),
107
- uvec2(0x2B3E6C1Fu, 0x9B05688Cu),
108
- uvec2(0x04BE4294u, 0xE07C2654u),
109
- uvec2(0x137E2179u, 0x5BE0CD19u)
110
- );
111
-
112
142
  // Iterated initialization vector
113
143
  uvec2 v[16];
114
144
 
@@ -162,7 +192,7 @@ void main() {
162
192
  m[4u] = uvec2(blockhash[6u], blockhash[7u]);
163
193
 
164
194
  // Reset v
165
- v = blake2b_iv;
195
+ v = BLAKE2B_INIT;
166
196
 
167
197
  // Twelve rounds of G mixing
168
198
 
@@ -240,7 +270,7 @@ void main() {
240
270
 
241
271
  // Pixel data set from work seed values
242
272
  // Finalize digest from high bits, low bits can be safely ignored
243
- if ((BLAKE2B_IV32_1 ^ v[0u].y ^ v[8u].y) >= threshold && (search || uvec2(gl_FragCoord) == uvec2(0u))) {
273
+ if ((BLAKE2B_INIT[0u].y ^ v[0u].y ^ v[8u].y) >= threshold && (search || uvec2(gl_FragCoord) == uvec2(0u))) {
244
274
  nonce = uvec4(1u, m[0u].y, m[0u].x, (uint(gl_FragCoord.x) << 16u) | uint(gl_FragCoord.y));
245
275
  }
246
276
 
package/dist/nano-pow.1 CHANGED
@@ -24,6 +24,9 @@ Show this help dialog and exit.
24
24
  \fB\-d\fR, \fB\-\-debug\fR
25
25
  Enable additional logging output.
26
26
  .TP
27
+ \fB\-j\fR, \fB\-\-json\fR
28
+ Format output as JSON.
29
+ .TP
27
30
  \fB\-e\fR, \fB\-\-effort\fR=\fIEFFORT\fR
28
31
  Increase demand on GPU processing. Must be between 1 and 32 inclusive.
29
32
  .TP
@@ -47,9 +50,9 @@ $ nano-pow \fB\-t fffffe00 \-e 32 0123456789abcdef0123456789abcdef0123456789abcd
47
50
  .EE
48
51
 
49
52
  .PP
50
- Search for multiple nonces from a file:
53
+ Read one or more lines of blockhashes from a file and output to another file:
51
54
  .EX
52
- $ nano-pow \fB$(cat /path/to/file.txt)\fR
55
+ $ cat /path/to/file.txt | nano-pow --json > work.json
53
56
  .EE
54
57
 
55
58
  .PP
@@ -70,4 +73,5 @@ Email <bug-nano-pow@zoso.dev>.
70
73
  Copyright \(co 2025 Chris Duncan <chris@zoso.dev>
71
74
  Nano PoW documentation: <https://docs.nano.org/integration-guides/work-generation/#work-calculation-details>
72
75
  License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
76
+ Portions of this code are also provided under the MIT License: <https://spdx.org/licenses/MIT.html>
73
77
  .EE
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nano-pow",
3
- "version": "3.1.2",
3
+ "version": "3.1.3",
4
4
  "description": "Proof-of-work generation and validation with WebGPU/WebGL for Nano cryptocurrency.",
5
5
  "keywords": [
6
6
  "nemo",
@@ -8,6 +8,7 @@
8
8
  "cash",
9
9
  "crypto",
10
10
  "currency",
11
+ "cryptocurrency",
11
12
  "coin",
12
13
  "nonce",
13
14
  "pow",
@@ -32,8 +33,7 @@
32
33
  ],
33
34
  "main": "dist/main.min.js",
34
35
  "browser": {
35
- "dist/main.min.js": true,
36
- "node:worker_threads": false
36
+ "./dist/main.min.js": true
37
37
  },
38
38
  "bin": "./dist/cli.js",
39
39
  "man": "./dist/nano-pow.1",
@@ -53,10 +53,12 @@
53
53
  "typescript": "^5.8.2"
54
54
  },
55
55
  "type": "module",
56
- "exports": [
57
- "./dist/main.min.js",
58
- "./dist/types.d.ts"
59
- ],
56
+ "exports": {
57
+ ".": {
58
+ "types": "./dist/types.d.ts",
59
+ "default": "./dist/main.min.js"
60
+ }
61
+ },
60
62
  "types": "./dist/types.d.ts",
61
63
  "unpkg": "./dist/main.min.js",
62
64
  "optionalDependencies": {