-
Notifications
You must be signed in to change notification settings - Fork 1
/
generate.js
243 lines (208 loc) · 7.68 KB
/
generate.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
'use strict'
var B58 = require('./node_modules/monero-wallet-generator/cnBase58')
var CnUtilGen = require('./node_modules/monero-wallet-generator/cnUtilGen')
var Module = require('./node_modules/monero-wallet-generator/Module')
var MersenneTwister = require('mersenne-twister')
var Sodium = require('sodium-native')
// RNG seed to make process reproducible
// let seed = new Date().getTime()
let seed = 1565298689469
console.log('Mersenne Twister seed: ', seed)
/*
Mersenne Twister seed: 1565298689469
[ 'ArQmAburnTh',
'ePremineFor',
'TheDeViLinT',
'heBLoCKCHAi',
'N666o666oo',
'inPrivacyWe',
'Trust666ooo' ]
Public spend key found at iteration 14:
310639d136fb3ae68e40db5db8c8df90857c64d2254d9fa21745a7b2cd58f2fa
Public view key found at iteration 8:
08a159c6202b7e134419366ee61ef9cd5bdf80bcd1ffa096b5e3a652590a364a
Generated address:
ar2uzTMs3KGArQmAburnThePremineForTheDeViLinTheBLoCKCHAiN666o666oo3inPrivacyWeTrust666ooo1U36QYkkA
*/
var generator = new MersenneTwister(seed)
// network prefix
let prefix = 0x2cca // mainnet
// let prefix = 0x39ca // stagenet
// config for cnUtilGen
var arqmaConfig = {
coinUnitPlaces: 9,
coinSymbol: 'ARQ',
coinName: 'ArQmA',
coinUriPrefix: 'arqma:',
addressPrefix: prefix
}
var cnUtil = CnUtilGen(arqmaConfig)
// This program generates a BURN address for ArQmA
// The public keys are generated randomly and are NOT derived from any private keys
// The private keys are not recoverable
// Any amount sent to an address generated by this program is not recoverable. The amount will be lost forever.
// ArQmA address = 8 strings of 11 characters + 1 string of 9 characters === 4 hex (prefix) + 64 hex (public spend key) + 64 hex (public view key) + 8 hex (checksum)
// First string has to be in the range defined by lowerFirst and upperFirst
// The first string is randomly generated to facilitate brute forcing of the public spend key
// The next seven strings have to be in the range of lowerEleven and UpperEleven functions to not generate any overflow when converting to base58
// The last string has to be in range defined by lowerNine and upperNine
// Last string (9 chars) contains the calculated checksum and is randomly generated to facilitate brute forcing of the public view key
// The validation of both keys is done using ge_frombytes_vartime and the function crypto_core_ed25519_is_valid_point from libsodium to check if EC point are valid.
// https://monero.stackexchange.com/questions/980/what-are-the-public-viewkeys-and-spendkeys
// https://monero.stackexchange.com/questions/8755/how-to-programatically-validate-monero-address
// https://steemit.com/monero/@luigi1111/understanding-monero-cryptography-privacy-introduction
// Fill the desired text => max 11 chars per input
var input = ['ArQmAburnTh', 'ePremineFor', 'TheDeViLinT', 'heBLoCKCHAi', 'N666o666oo', 'inPrivacyWe', 'Trust666ooo'] // 7 * 11 chars
console.log(input)
// Control padding of the input strings / true = pad / false = random
let pad = false
let padding = '1'
// Max number of iterations to try before quitting
let maxIteration = 100
var KEY_SIZE = 32
var STRUCT_SIZES = {
GE_P3: 160,
GE_P2: 120,
GE_P1P1: 160,
GE_CACHED: 160,
EC_SCALAR: 32,
EC_POINT: 32,
KEY_IMAGE: 32,
GE_DSMP: 160 * 8, // ge_cached * 8
SIGNATURE: 64 // ec_scalar * 2
}
var alphabetHex = '0123456789abcdef'
function generateHexString (length) {
let str = ''
for (let i = 0; i < length; i++) {
str = str + alphabetHex[Math.round(generator.random() * 15)]
}
return str
}
var alphabetBase58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
let lowerFirst = B58.encode(cnUtil.encode_varint(prefix) + '000000000000')
let upperFirst = B58.encode(cnUtil.encode_varint(prefix) + 'ffffffffffff')
let lowerEleven = '11111111111'
let upperEleven = B58.encode('ffffffffffffffff')
let lowerNine = '111111111'
let upperNine = B58.encode('ffffffffffff')
let upperFirstHex = []
let upperElevenHex = []
for (let i = 0; i < 11; i++) {
upperFirstHex[i] = alphabetBase58.indexOf(upperFirst[i])
}
for (let i = 0; i < 11; i++) {
upperElevenHex[i] = alphabetBase58.indexOf(upperEleven[i])
}
// not used in this version
function isValidFirstString (str) {
return (str >= lowerFirst && str <= upperFirst)
}
function isValidStringNine (str) {
return (str >= lowerNine && str <= upperNine)
}
function isValidStringEleven (str) {
return (str >= lowerEleven && str <= upperEleven)
}
function generateBase58String (offset, length, upper) {
let str = ''
for (let i = 0; i < length; i++) {
str = str + alphabetBase58[Math.round(generator.random() * upper[i + offset])]
}
return str
}
function generateFirstBlock (prefix) {
return B58.encode(cnUtil.encode_varint(prefix) + generateHexString(12))
}
function generateLastBlock (str) {
let hex = B58.decode(str)
if (hex.length !== 128) {
throw new Error('Length must be 128!')
} else {
let testNine = '1'
let rnd = ''
let data = ''
let checksum = ''
do {
rnd = generateHexString(4)
data = hex + rnd
checksum = cnUtil.cn_fast_hash(data)
checksum = checksum.slice(0, 4 * 2)
testNine = isValidStringNine(rnd + checksum)
} while (testNine === false)
return B58.encode(data + checksum)
}
}
function isValidKey (key) {
var pub_b = B58.hextobin(key)
var pub_m = Module._malloc(KEY_SIZE)
Module.HEAPU8.set(pub_b, pub_m)
var ge_p3_m = Module._malloc(STRUCT_SIZES.GE_P3)
return (Module.ccall("ge_frombytes_vartime", "bool", ["number", "number"], [ge_p3_m, pub_m]) === 0)
}
// bruteforcing the public spend key
let address = ''
let length = ''
let dec = ''
let hex = ''
let key = ''
let addressPrefix = ''
let candidate = []
for (let i = 0; i < maxIteration; i++) {
address = generateFirstBlock(prefix)
for (let j = 0; j < 4; j++) {
length = input[j].length
if (length > 11) {
throw new Error(`${j + 1}th string length over 11 chars!`)
} else if (length < 11 && !pad) {
candidate[j] = input[j] + generateBase58String(length, 11 - length, upperElevenHex)
} else if (length < 11 && pad) {
candidate[j] = input[j] + padding.repeat(11 - length)
} else {
candidate[j] = input[j]
}
if (isValidStringEleven(candidate[j]) === false) {
throw new Error(`${j + 1}th string out of allowed range!`)
}
}
address = address + candidate.slice(0, 4).join('')
dec = B58.decode(address)
hex = dec.slice(4, 68)
key = Buffer.from(hex)
if (Sodium.crypto_core_ed25519_is_valid_point(key) && isValidKey(hex)) {
console.log(`Public spend key found at iteration ${i}:\n`, hex)
addressPrefix = address.slice(0, 11)
break
} else if (i + 1 === maxIteration) {
throw new Error('Public spend key not found!')
}
}
// bruteforcing the public view key
for (let i = 0; i < maxIteration; i++) {
for (let j = 4; j < 7; j++) {
length = input[j].length
if (length > 11) {
throw new Error(`${j + 1}th string length over 11 chars!`)
} else if (length < 11 && !pad) {
candidate[j] = input[j] + generateBase58String(length, 11 - length, upperElevenHex)
} else if (length < 11 && pad) {
candidate[j] = input[j] + padding.repeat(11 - length)
} else {
candidate[j] = input[j]
}
if (isValidStringEleven(candidate[j]) === false) {
throw new Error(`${j + 1}th string out of allowed range!`)
}
}
address = generateLastBlock(addressPrefix + candidate.slice(0, 7).join(''))
dec = B58.decode(address)
hex = dec.slice(68, 132)
key = Buffer.from(hex)
if (Sodium.crypto_core_ed25519_is_valid_point(key) && isValidKey(hex)) {
console.log(`Public view key found at iteration ${i}:\n`, hex)
break
} else if (i + 1 === maxIteration) {
throw new Error('Public view key not found!')
}
}
console.log('Generated address:\n' + address)