nano-pow 3.1.1 → 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,28 +2,43 @@
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
- BLOCKHASH is a 64-character hexadecimal string.
13
- Multiple blockhash values must be separated by spaces.
14
- Prints a 16-character hexadecimal work value to standard output.
15
- If using --validate, prints 'true' or 'false' to standard output instead.
16
- All command options are optional.
29
+ BLOCKHASH is a 64-character hexadecimal string. Multiple blockhashes must be separated by whitespace or line breaks.
30
+ Prints a 16-character hexadecimal work value to standard output. If using --validate, prints 'true' or 'false' to standard output instead.
17
31
 
18
32
  -h, --help show this dialog
19
33
  -d, --debug enable additional logging output
20
- -e, --effort <value> increase demand on GPU processing
21
- -t, --threshold <value> override the minimum threshold value
22
- -v, --validate <value> check an existing work value instead of searching for one
34
+ -j, --json format output as JSON
35
+ -e, --effort=<value> increase demand on GPU processing
36
+ -t, --threshold=<value> override the minimum threshold value
37
+ -v, --validate=<value> check an existing work value instead of searching for one
23
38
 
24
39
  If validating a nonce, it must be a 16-character hexadecimal value.
25
- Effort must be a decimal number between 1 - 32.
26
- Threshold must be a hexadecimal number between 0x0 - 0xFFFFFFFF.
40
+ Effort must be a decimal number between 1-32.
41
+ Threshold must be a hexadecimal string between 0-FFFFFFFF.
27
42
 
28
43
  Report bugs: <bug-nano-pow@zoso.dev>
29
44
  Full documentation: <https://www.npmjs.com/package/nano-pow>
@@ -31,18 +46,17 @@ Full documentation: <https://www.npmjs.com/package/nano-pow>
31
46
  process.exit()
32
47
  }
33
48
 
34
- const hashes = []
49
+ const inArgs = []
35
50
  while (/^[0-9A-Fa-f]{64}$/.test(args[args.length - 1] ?? '')) {
36
- hashes.unshift(args.pop())
37
- }
38
- if (hashes.length === 0) {
39
- console.error('Invalid block hash input')
40
- process.exit(1)
51
+ inArgs.unshift(args.pop())
41
52
  }
53
+ hashes.push(...inArgs)
42
54
 
43
55
  let fn = 'search'
44
56
  let work = ''
57
+ let isJson = false
45
58
  const options = {}
59
+
46
60
  for (let i = 0; i < args.length; i++) {
47
61
  switch (args[i]) {
48
62
  case ('--validate'):
@@ -72,13 +86,27 @@ for (let i = 0; i < args.length; i++) {
72
86
  options['debug'] = true
73
87
  break
74
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)
75
102
  }
76
103
  }
77
104
 
78
- if (options['debug']) console.log(`NanoPowCli.${fn}()`)
79
- 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
+ }
80
109
 
81
- ;
82
110
  /**
83
111
  * Main
84
112
  */
@@ -105,10 +133,22 @@ if (options['debug']) console.log(`${fn} options`, JSON.stringify(options))
105
133
  const output = msg.text().split(' ')
106
134
  if (output[0] === 'cli') {
107
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
+ }
108
148
  const end = performance.now()
109
149
  if (options['debug']) console.log(end - start, 'ms total |', (end - start) / hashes.length, 'ms avg')
110
- process.exit()
111
- } else {
150
+ await browser.close()
151
+ } else if (!isJson) {
112
152
  console.log(output[1])
113
153
  }
114
154
  } else if (options['debug']) {
@@ -128,10 +168,12 @@ if (options['debug']) console.log(`${fn} options`, JSON.stringify(options))
128
168
  createScript: string => string,
129
169
  })
130
170
  ${NanoPow}
171
+ window.results = []
131
172
  const hashes = ["${hashes.join('","')}"]
132
173
  for (const hash of hashes) {
133
174
  try {
134
175
  const work = await NanoPow.${fn}(${work}hash, ${JSON.stringify(options)})
176
+ window.results.push(work)
135
177
  console.log(\`cli \${work}\`)
136
178
  } catch (err) {
137
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
@@ -11,15 +11,10 @@ nano-pow \- proof-of-work generation and validation for Nano cryptocurrency
11
11
 
12
12
  .SH DESCRIPTION
13
13
  Generate work for \fIBLOCKHASH\fR, or multiple work values for \fIBLOCKHASH\fR(es).
14
- Nano PoW documentation: <https://docs.nano.org/integration-guides/work-generation/\#work-calculation-details>
15
14
  .PP
16
- \fIBLOCKHASH\fR is a 64-character hexadecimal string.
15
+ \fIBLOCKHASH\fR is a 64-character hexadecimal string. Multiple blockhashes must be separated by whitespace or line breaks.
17
16
  .PP
18
- Multiple blockhash values must be separated by spaces.
19
- .PP
20
- Prints a 16-character hexadecimal work value to standard output.
21
- .PP
22
- If \fB--validate\fR is used, prints 'true' or 'false' to standard output.
17
+ Prints a 16-character hexadecimal work value to standard output. If \fB--validate\fR is used, prints 'true' or 'false' to standard output.
23
18
 
24
19
  .SH OPTIONS
25
20
  .TP
@@ -29,43 +24,54 @@ Show this help dialog and exit.
29
24
  \fB\-d\fR, \fB\-\-debug\fR
30
25
  Enable additional logging output.
31
26
  .TP
32
- \fB\-e\fR, \fB\-\-effort\fR \fIEFFORT\fR
27
+ \fB\-j\fR, \fB\-\-json\fR
28
+ Format output as JSON.
29
+ .TP
30
+ \fB\-e\fR, \fB\-\-effort\fR=\fIEFFORT\fR
33
31
  Increase demand on GPU processing. Must be between 1 and 32 inclusive.
34
32
  .TP
35
- \fB\-t\fR, \fB\-\-threshold\fR \fITHRESHOLD\fR
36
- Override the minimum threshold value. Higher values increase difficulty. Must be in hexadecimal format between 0x0 and 0xFFFFFFFF.
33
+ \fB\-t\fR, \fB\-\-threshold\fR=\fITHRESHOLD\fR
34
+ Override the minimum threshold value. Higher values increase difficulty. Must be a hexadecimal string between 0 and FFFFFFFF inclusive.
37
35
  .TP
38
- \fB\-v\fR, \fB\-\-validate\fR \fIWORK\fR
36
+ \fB\-v\fR, \fB\-\-validate\fR=\fIWORK\fR
39
37
  Check an existing work value instead of searching for one.
40
38
 
41
39
  .SH EXAMPLES
40
+ .PP
42
41
  Search for a work nonce for a blockhash using the default threshold 0xFFFFFFF8:
43
42
  .EX
44
- nano-pow 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
43
+ $ nano-pow \fB0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\fR
45
44
  .EE
46
45
 
46
+ .PP
47
47
  Search for a work nonce using a custom threshold and increased effort:
48
48
  .EX
49
- nano-pow \-t fffffe00 \-e 32 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
49
+ $ nano-pow \fB\-t fffffe00 \-e 32 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\fR
50
50
  .EE
51
51
 
52
- Search for multiple nonces from a file:
52
+ .PP
53
+ Read one or more lines of blockhashes from a file and output to another file:
53
54
  .EX
54
- nano-pow $(cat /path/to/file.txt)
55
+ $ cat /path/to/file.txt | nano-pow --json > work.json
55
56
  .EE
56
57
 
58
+ .PP
57
59
  Validate an existing work nonce against a blockhash and show debugging output:
58
60
  .EX
59
- nano-pow \-d \-v fedcba9876543210 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
61
+ $ nano-pow \fB\-d \-v fedcba9876543210 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\fR
60
62
  .EE
61
63
 
62
64
  .SH AUTHOR
63
65
  Written by Chris Duncan.
64
66
 
65
67
  .SH BUGS
66
- Email: <mailto:bug-nano-pow@zoso.dev>
68
+ Email <bug-nano-pow@zoso.dev>.
67
69
 
68
70
  .SH COPYRIGHT
69
- Copyright \(co 2025 Chris Duncan <chris@zoso.dev>
70
71
  .PP
72
+ .EX
73
+ Copyright \(co 2025 Chris Duncan <chris@zoso.dev>
74
+ Nano PoW documentation: <https://docs.nano.org/integration-guides/work-generation/#work-calculation-details>
71
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>
77
+ .EE
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nano-pow",
3
- "version": "3.1.1",
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": {