248 | )
249 | }
250 | }
251 | export default KeyGeneratorTool
252 |
--------------------------------------------------------------------------------
/src/base32.js:
--------------------------------------------------------------------------------
1 | //nano-base32 from https://github.com/termhn/nano-base32/blob/d6b160aba47595180b67cc8a30096a11525e4010/index.js
2 | //blake2b from https://github.com/emilbayes/blake2b/blob/f0a7c7b550133eca5f5fc3b751ccfd2335ce736f/index.js
3 |
4 | const alphabet = '13456789abcdefghijkmnopqrstuwxyz'
5 |
6 | /**
7 | * Encode provided Uint8Array using the Nano-specific Base-32 implementeation.
8 | * @param {Uint8Array} view Input buffer formatted as a Uint8Array
9 | * @returns {string}
10 | */
11 | export function encode(view) {
12 | if (view.constructor !== Uint8Array) {
13 | throw new Error('View must be a Uint8Array!')
14 | }
15 | const length = view.length
16 | const leftover = (length * 8) % 5
17 | const offset = leftover === 0 ? 0 : 5 - leftover
18 |
19 | let value = 0
20 | let output = ''
21 | let bits = 0
22 |
23 | for (var i = 0; i < length; i++) {
24 | value = (value << 8) | view[i]
25 | bits += 8
26 |
27 | while (bits >= 5) {
28 | output += alphabet[(value >>> (bits + offset - 5)) & 31]
29 | bits -= 5
30 | }
31 | }
32 |
33 | if (bits > 0) {
34 | output += alphabet[(value << (5 - (bits + offset))) & 31]
35 | }
36 |
37 | return output
38 | }
39 |
40 | export function readChar(char) {
41 | var idx = alphabet.indexOf(char)
42 |
43 | if (idx === -1) {
44 | throw new Error('Invalid character found: ' + char)
45 | }
46 |
47 | return idx
48 | }
49 |
50 | /**
51 | * Decodes a Nano-implementation Base32 encoded string into a Uint8Array
52 | * @param {string} input A Nano-Base32 encoded string
53 | * @returns {Uint8Array}
54 | */
55 | export function decode(input) {
56 | if (typeof input !== 'string') {
57 | throw new Error('Input must be a string!')
58 | }
59 | var length = input.length
60 | const leftover = (length * 5) % 8
61 | const offset = leftover === 0 ? 0 : 8 - leftover
62 |
63 | var bits = 0
64 | var value = 0
65 |
66 | var index = 0
67 | var output = new Uint8Array(Math.ceil(length * 5 / 8))
68 |
69 | for (var i = 0; i < length; i++) {
70 | value = (value << 5) | readChar(input[i])
71 | bits += 5
72 |
73 | if (bits >= 8) {
74 | output[index++] = (value >>> (bits + offset - 8)) & 255
75 | bits -= 8
76 | }
77 | }
78 | if (bits > 0) {
79 | output[index++] = (value << (bits + offset - 8)) & 255
80 | }
81 |
82 | if (leftover !== 0) {
83 | output = output.slice(1)
84 | }
85 | return output
86 | }
87 |
88 | // 64-bit unsigned addition
89 | // Sets v[a,a+1] += v[b,b+1]
90 | // v should be a Uint32Array
91 | export function ADD64AA(v, a, b) {
92 | var o0 = v[a] + v[b]
93 | var o1 = v[a + 1] + v[b + 1]
94 | if (o0 >= 0x100000000) {
95 | o1++
96 | }
97 | v[a] = o0
98 | v[a + 1] = o1
99 | }
100 |
101 | // 64-bit unsigned addition
102 | // Sets v[a,a+1] += b
103 | // b0 is the low 32 bits of b, b1 represents the high 32 bits
104 | export function ADD64AC(v, a, b0, b1) {
105 | var o0 = v[a] + b0
106 | if (b0 < 0) {
107 | o0 += 0x100000000
108 | }
109 | var o1 = v[a + 1] + b1
110 | if (o0 >= 0x100000000) {
111 | o1++
112 | }
113 | v[a] = o0
114 | v[a + 1] = o1
115 | }
116 |
117 | // Little-endian byte access
118 | export function B2B_GET32(arr, i) {
119 | return (arr[i] ^
120 | (arr[i + 1] << 8) ^
121 | (arr[i + 2] << 16) ^
122 | (arr[i + 3] << 24))
123 | }
124 |
125 | // G Mixing function
126 | // The ROTRs are inlined for speed
127 | export function B2B_G(a, b, c, d, ix, iy) {
128 | var x0 = m[ix]
129 | var x1 = m[ix + 1]
130 | var y0 = m[iy]
131 | var y1 = m[iy + 1]
132 |
133 | ADD64AA(v, a, b) // v[a,a+1] += v[b,b+1] ... in JS we must store a uint64 as two uint32s
134 | ADD64AC(v, a, x0, x1) // v[a, a+1] += x ... x0 is the low 32 bits of x, x1 is the high 32 bits
135 |
136 | // v[d,d+1] = (v[d,d+1] xor v[a,a+1]) rotated to the right by 32 bits
137 | var xor0 = v[d] ^ v[a]
138 | var xor1 = v[d + 1] ^ v[a + 1]
139 | v[d] = xor1
140 | v[d + 1] = xor0
141 |
142 | ADD64AA(v, c, d)
143 |
144 | // v[b,b+1] = (v[b,b+1] xor v[c,c+1]) rotated right by 24 bits
145 | xor0 = v[b] ^ v[c]
146 | xor1 = v[b + 1] ^ v[c + 1]
147 | v[b] = (xor0 >>> 24) ^ (xor1 << 8)
148 | v[b + 1] = (xor1 >>> 24) ^ (xor0 << 8)
149 |
150 | ADD64AA(v, a, b)
151 | ADD64AC(v, a, y0, y1)
152 |
153 | // v[d,d+1] = (v[d,d+1] xor v[a,a+1]) rotated right by 16 bits
154 | xor0 = v[d] ^ v[a]
155 | xor1 = v[d + 1] ^ v[a + 1]
156 | v[d] = (xor0 >>> 16) ^ (xor1 << 16)
157 | v[d + 1] = (xor1 >>> 16) ^ (xor0 << 16)
158 |
159 | ADD64AA(v, c, d)
160 |
161 | // v[b,b+1] = (v[b,b+1] xor v[c,c+1]) rotated right by 63 bits
162 | xor0 = v[b] ^ v[c]
163 | xor1 = v[b + 1] ^ v[c + 1]
164 | v[b] = (xor1 >>> 31) ^ (xor0 << 1)
165 | v[b + 1] = (xor0 >>> 31) ^ (xor1 << 1)
166 | }
167 |
168 | // Initialization Vector
169 | var BLAKE2B_IV32 = new Uint32Array([
170 | 0xF3BCC908, 0x6A09E667, 0x84CAA73B, 0xBB67AE85,
171 | 0xFE94F82B, 0x3C6EF372, 0x5F1D36F1, 0xA54FF53A,
172 | 0xADE682D1, 0x510E527F, 0x2B3E6C1F, 0x9B05688C,
173 | 0xFB41BD6B, 0x1F83D9AB, 0x137E2179, 0x5BE0CD19
174 | ])
175 |
176 | var SIGMA8 = [
177 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
178 | 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
179 | 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
180 | 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
181 | 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
182 | 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
183 | 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
184 | 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
185 | 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
186 | 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
187 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
188 | 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3
189 | ]
190 |
191 | // These are offsets into a uint64 buffer.
192 | // Multiply them all by 2 to make them offsets into a uint32 buffer,
193 | // because this is Javascript and we don't have uint64s
194 | var SIGMA82 = new Uint8Array(SIGMA8.map(function (x) { return x * 2 }))
195 |
196 | // Compression function. 'last' flag indicates last block.
197 | // Note we're representing 16 uint64s as 32 uint32s
198 | var v = new Uint32Array(32)
199 | var m = new Uint32Array(32)
200 | export function blake2bCompress(ctx, last) {
201 | var i = 0
202 |
203 | // init work variables
204 | for (i = 0; i < 16; i++) {
205 | v[i] = ctx.h[i]
206 | v[i + 16] = BLAKE2B_IV32[i]
207 | }
208 |
209 | // low 64 bits of offset
210 | v[24] = v[24] ^ ctx.t
211 | v[25] = v[25] ^ (ctx.t / 0x100000000)
212 | // high 64 bits not supported, offset may not be higher than 2**53-1
213 |
214 | // last block flag set ?
215 | if (last) {
216 | v[28] = ~v[28]
217 | v[29] = ~v[29]
218 | }
219 |
220 | // get little-endian words
221 | for (i = 0; i < 32; i++) {
222 | m[i] = B2B_GET32(ctx.b, 4 * i)
223 | }
224 |
225 | // twelve rounds of mixing
226 | for (i = 0; i < 12; i++) {
227 | B2B_G(0, 8, 16, 24, SIGMA82[i * 16 + 0], SIGMA82[i * 16 + 1])
228 | B2B_G(2, 10, 18, 26, SIGMA82[i * 16 + 2], SIGMA82[i * 16 + 3])
229 | B2B_G(4, 12, 20, 28, SIGMA82[i * 16 + 4], SIGMA82[i * 16 + 5])
230 | B2B_G(6, 14, 22, 30, SIGMA82[i * 16 + 6], SIGMA82[i * 16 + 7])
231 | B2B_G(0, 10, 20, 30, SIGMA82[i * 16 + 8], SIGMA82[i * 16 + 9])
232 | B2B_G(2, 12, 22, 24, SIGMA82[i * 16 + 10], SIGMA82[i * 16 + 11])
233 | B2B_G(4, 14, 16, 26, SIGMA82[i * 16 + 12], SIGMA82[i * 16 + 13])
234 | B2B_G(6, 8, 18, 28, SIGMA82[i * 16 + 14], SIGMA82[i * 16 + 15])
235 | }
236 |
237 | for (i = 0; i < 16; i++) {
238 | ctx.h[i] = ctx.h[i] ^ v[i] ^ v[i + 16]
239 | }
240 | }
241 |
242 | // reusable parameter_block
243 | var parameter_block = new Uint8Array([
244 | 0, 0, 0, 0, // 0: outlen, keylen, fanout, depth
245 | 0, 0, 0, 0, // 4: leaf length, sequential mode
246 | 0, 0, 0, 0, // 8: node offset
247 | 0, 0, 0, 0, // 12: node offset
248 | 0, 0, 0, 0, // 16: node depth, inner length, rfu
249 | 0, 0, 0, 0, // 20: rfu
250 | 0, 0, 0, 0, // 24: rfu
251 | 0, 0, 0, 0, // 28: rfu
252 | 0, 0, 0, 0, // 32: salt
253 | 0, 0, 0, 0, // 36: salt
254 | 0, 0, 0, 0, // 40: salt
255 | 0, 0, 0, 0, // 44: salt
256 | 0, 0, 0, 0, // 48: personal
257 | 0, 0, 0, 0, // 52: personal
258 | 0, 0, 0, 0, // 56: personal
259 | 0, 0, 0, 0 // 60: personal
260 | ])
261 |
262 | // Creates a BLAKE2b hashing context
263 | // Requires an output length between 1 and 64 bytes
264 | // Takes an optional Uint8Array key
265 | export function Blake2b(outlen, key, salt, personal) {
266 | // zero out parameter_block before usage
267 | parameter_block.fill(0)
268 | // state, 'param block'
269 |
270 | this.b = new Uint8Array(128)
271 | this.h = new Uint32Array(16)
272 | this.t = 0 // input count
273 | this.c = 0 // pointer within buffer
274 | this.outlen = outlen // output length in bytes
275 |
276 | parameter_block[0] = outlen
277 | if (key) parameter_block[1] = key.length
278 | parameter_block[2] = 1 // fanout
279 | parameter_block[3] = 1 // depth
280 |
281 | if (salt) parameter_block.set(salt, 32)
282 | if (personal) parameter_block.set(personal, 48)
283 |
284 | // initialize hash state
285 | for (var i = 0; i < 16; i++) {
286 | this.h[i] = BLAKE2B_IV32[i] ^ B2B_GET32(parameter_block, i * 4)
287 | }
288 |
289 | // key the hash, if applicable
290 | if (key) {
291 | blake2bUpdate(this, key)
292 | // at the end
293 | this.c = 128
294 | }
295 | }
296 |
297 | Blake2b.prototype.update = function (input) {
298 | this.assert(input instanceof Uint8Array, 'input must be Uint8Array or Buffer')
299 | blake2bUpdate(this, input)
300 | return this
301 | }
302 |
303 | Blake2b.prototype.digest = function (out) {
304 | var buf = (!out || out === 'binary' || out === 'hex') ? new Uint8Array(this.outlen) : out
305 | this.assert(buf instanceof Uint8Array, 'out must be "binary", "hex", Uint8Array, or Buffer')
306 | this.assert(buf.length >= this.outlen, 'out must have at least outlen bytes of space')
307 | blake2bFinal(this, buf)
308 | if (out === 'hex') return this.hexSlice(buf)
309 | return buf
310 | }
311 |
312 | Blake2b.prototype.final = Blake2b.prototype.digest
313 |
314 | Blake2b.ready = function (cb) {
315 | this.b2wasm.ready(function () {
316 | cb() // ignore the error
317 | })
318 | }
319 |
320 | // Updates a BLAKE2b streaming hash
321 | // Requires hash context and Uint8Array (byte array)
322 | export function blake2bUpdate(ctx, input) {
323 | for (var i = 0; i < input.length; i++) {
324 | if (ctx.c === 128) { // buffer full ?
325 | ctx.t += ctx.c // add counters
326 | blake2bCompress(ctx, false) // compress (not last)
327 | ctx.c = 0 // counter to zero
328 | }
329 | ctx.b[ctx.c++] = input[i]
330 | }
331 | }
332 |
333 | // Completes a BLAKE2b streaming hash
334 | // Returns a Uint8Array containing the message digest
335 | export function blake2bFinal(ctx, out) {
336 | ctx.t += ctx.c // mark last block offset
337 |
338 | while (ctx.c < 128) { // fill up with zeros
339 | ctx.b[ctx.c++] = 0
340 | }
341 | blake2bCompress(ctx, true) // final block flag = 1
342 |
343 | for (var i = 0; i < ctx.outlen; i++) {
344 | out[i] = ctx.h[i >> 2] >> (8 * (i & 3))
345 | }
346 | return out
347 | }
--------------------------------------------------------------------------------
/src/tools/DifficultyTool.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { InputGroup, FormControl, Button} from 'react-bootstrap'
3 | import * as helpers from '../helpers'
4 | import removeTrailingZeros from 'remove-trailing-zeros'
5 | import bigDec from 'bigdecimal'
6 | import {toast } from 'react-toastify'
7 | const toolParam = 'difficulty'
8 |
9 | class DifficultyTool extends Component {
10 | constructor(props) {
11 | super(props)
12 |
13 | this.inputToast = null //disallow duplicates
14 |
15 | this.state = {
16 | baseDifficulty: 'fffffff800000000',
17 | newDifficulty: '',
18 | multiplier: '',
19 | validBase: true,
20 | validNew: false,
21 | validMultiplier: false,
22 | }
23 |
24 | this.handleBaseChange = this.handleBaseChange.bind(this)
25 | this.handleNewChange = this.handleNewChange.bind(this)
26 | this.handleMultiplierChange = this.handleMultiplierChange.bind(this)
27 | this.clearText = this.clearText.bind(this)
28 | this.clearAll = this.clearAll.bind(this)
29 | this.setParams = this.setParams.bind(this)
30 | this.invertMultiplier = this.invertMultiplier.bind(this)
31 | }
32 |
33 | componentDidMount = () => {
34 | // Read URL params from parent and construct new quick path
35 | var baseDiff = this.props.state.baseDiff
36 | var newDiff = this.props.state.newDiff
37 | var multiplier = this.props.state.multiplier
38 |
39 | if (baseDiff && newDiff) {
40 | this.setState({
41 | baseDifficulty: baseDiff,
42 | newDifficulty: newDiff,
43 | validBase: true,
44 | validNew: true,
45 | },
46 | function() {
47 | this.newChange(newDiff)
48 | })
49 | }
50 | else if (baseDiff && multiplier) {
51 | this.setState({
52 | baseDifficulty: baseDiff,
53 | multiplier: multiplier,
54 | validBase: true,
55 | validMultiplier: true,
56 | },
57 | function() {
58 | this.multiplierChange(multiplier)
59 | })
60 | }
61 | else if (baseDiff) {
62 | this.setState({
63 | baseDifficulty: baseDiff,
64 | validBase: true,
65 | })
66 | }
67 | if (!baseDiff && !newDiff && !multiplier) {
68 | this.setParams()
69 | }
70 | }
71 |
72 | // Defines the url params
73 | setParams(type) {
74 | switch (type) {
75 | case 'baseDiff':
76 | helpers.setURLParams('?tool='+toolParam + '&basediff='+this.state.baseDifficulty)
77 | break
78 |
79 | case 'newDiff':
80 | helpers.setURLParams('?tool='+toolParam + '&basediff='+this.state.baseDifficulty + '&newdiff='+this.state.newDifficulty)
81 | break
82 |
83 | case 'multiplier':
84 | helpers.setURLParams('?tool='+toolParam + '&basediff='+this.state.baseDifficulty + '&multiplier='+this.state.multiplier)
85 | break
86 |
87 | default:
88 | helpers.setURLParams('?tool='+toolParam)
89 | break
90 | }
91 | }
92 |
93 | //Clear text from input field
94 | clearText(event) {
95 | switch(event.target.value) {
96 | case 'baseDiff':
97 | this.setState({
98 | baseDifficulty: '',
99 | validBase: false,
100 | })
101 | break
102 | case 'newDiff':
103 | this.setState({
104 | newDifficulty: '',
105 | validNew: false,
106 | })
107 | break
108 | case 'multiplier':
109 | this.setState({
110 | multiplier: '',
111 | validMultiplier: false,
112 | })
113 | break
114 | default:
115 | break
116 | }
117 | }
118 |
119 | clearAll() {
120 | this.setState({
121 | baseDifficulty: '',
122 | validBase: false,
123 | newDifficulty: '',
124 | validNew: false,
125 | multiplier: '',
126 | validMultiplier: false,
127 | },
128 | function() {
129 | this.setParams()
130 | })
131 | }
132 |
133 | invertMultiplier() {
134 | if (this.state.multiplier !== '0') {
135 | let mode = bigDec.RoundingMode.HALF_DOWN()
136 | let newMulti = removeTrailingZeros(bigDec.BigDecimal(1).divide(bigDec.BigDecimal(this.state.multiplier),32,mode).toPlainString())
137 | this.setState({
138 | multiplier: newMulti,
139 | },
140 | function() {
141 | this.multiplierChange(newMulti)
142 | })
143 | }
144 | }
145 |
146 | // Validate if a 16 char hex string
147 | checkDifficulty(diff) {
148 | return (helpers.isHex(diff) && diff.length === 16)
149 | }
150 |
151 | handleBaseChange(event) {
152 | this.baseChange(event.target.value)
153 | }
154 | baseChange(value) {
155 | let val = value.toLowerCase()
156 | if (!this.checkDifficulty(val)) {
157 | if (val !== '') {
158 | if (!toast.isActive(this.inputToast)) {
159 | this.inputToast = toast("Not a valid difficulty hex string", helpers.getToast(helpers.toastType.ERROR_AUTO))
160 | }
161 | }
162 | this.setState({
163 | baseDifficulty: val,
164 | validBase: false,
165 | validMultiplier: false,
166 | multiplier: '',
167 | },
168 | function() {
169 | this.setParams('baseDiff')
170 | })
171 | return
172 | }
173 | this.inputToast = toast("Valid threshold entered", helpers.getToast(helpers.toastType.SUCCESS_AUTO))
174 | this.setState({
175 | baseDifficulty: val,
176 | multiplier: this.state.validNew ? removeTrailingZeros(helpers.multiplier_from_difficulty(this.state.newDifficulty, val).toString()): '',
177 | validBase: true,
178 | validMultiplier: true,
179 | },
180 | function() {
181 | this.setParams('baseDiff')
182 | })
183 | }
184 |
185 | handleNewChange(event) {
186 | this.newChange(event.target.value)
187 | }
188 | newChange(value) {
189 | let val = value.toLowerCase()
190 | if (!this.checkDifficulty(val)) {
191 | if (val !== '') {
192 | if (!toast.isActive(this.inputToast)) {
193 | this.inputToast = toast("Not a valid difficulty hex string", helpers.getToast(helpers.toastType.ERROR_AUTO))
194 | }
195 | }
196 | this.setState({
197 | newDifficulty: val,
198 | multiplier: '',
199 | validNew: false,
200 | validMultiplier: false,
201 | },
202 | function() {
203 | this.setParams('newDiff')
204 | })
205 | return
206 | }
207 | this.inputToast = toast("Valid threshold entered", helpers.getToast(helpers.toastType.SUCCESS_AUTO))
208 | this.setState({
209 | newDifficulty: val,
210 | validNew: true,
211 | validMultiplier: true,
212 | multiplier: this.state.validBase ? removeTrailingZeros(helpers.multiplier_from_difficulty(val,this.state.baseDifficulty).toString()): '',
213 | },
214 | function() {
215 | this.setParams('newDiff')
216 | })
217 | }
218 |
219 | handleMultiplierChange(event) {
220 | this.multiplierChange(event.target.value)
221 | }
222 | multiplierChange(val) {
223 | if (!helpers.isValidDiffMultiplier(val)) {
224 | if (val !== '' && val.slice(-1) !== '.' && val.slice(-1) !== '0') {
225 | if (!toast.isActive(this.inputToast)) {
226 | this.inputToast = toast("Not a valid positive natural or decimal number", helpers.getToast(helpers.toastType.ERROR_AUTO))
227 | }
228 | }
229 | this.setState({
230 | newDifficulty: '',
231 | multiplier: val,
232 | validMultiplier: false,
233 | validNew: false,
234 | },
235 | function() {
236 | this.setParams('multiplier')
237 | })
238 | return
239 | }
240 |
241 | let newDiff = this.state.validBase ? helpers.difficulty_from_multiplier(val,this.state.baseDifficulty): ''
242 | if (newDiff.charAt(0) === '-' || newDiff.length > 16) {
243 | newDiff = ''
244 | if (!toast.isActive(this.inputToast)) {
245 | this.inputToast = toast("Invalid multiplier", helpers.getToast(helpers.toastType.ERROR_AUTO))
246 | }
247 | }
248 |
249 | this.setState({
250 | multiplier: val,
251 | validMultiplier: true,
252 | validNew: true,
253 | newDifficulty: newDiff,
254 | },
255 | function() {
256 | this.setParams('multiplier')
257 | })
258 | }
259 |
260 | render() {
261 | return (
262 |