@leocuvee/turtlecoin-utils 0.0.14
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/.github/workflows/ci.yml +27 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/inspectionProfiles/Project_Default.xml +7 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/turtlecoin-utils.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/.travis.yml +11 -0
- package/CONTRIBUTING.md +3 -0
- package/LICENSE +674 -0
- package/README.md +203 -0
- package/config.json +7 -0
- package/docs/.nojekyll +0 -0
- package/docs/CNAME +1 -0
- package/docs/assets/css/main.css +2321 -0
- package/docs/assets/images/icons.png +0 -0
- package/docs/assets/images/icons@2x.png +0 -0
- package/docs/assets/images/widgets.png +0 -0
- package/docs/assets/images/widgets@2x.png +0 -0
- package/docs/assets/js/main.js +1 -0
- package/docs/assets/js/search.js +3 -0
- package/docs/classes/address.html +964 -0
- package/docs/classes/addressprefix.html +431 -0
- package/docs/classes/block.html +965 -0
- package/docs/classes/blocktemplate.html +695 -0
- package/docs/classes/cryptonote.html +1137 -0
- package/docs/classes/ed25519.keypair.html +400 -0
- package/docs/classes/ed25519.keys.html +373 -0
- package/docs/classes/extranoncetag.extranoncedata.html +454 -0
- package/docs/classes/extranoncetag.extranoncepaymentid.html +453 -0
- package/docs/classes/extranoncetag.iextranonce.html +347 -0
- package/docs/classes/extratag.extramergedmining.html +494 -0
- package/docs/classes/extratag.extranonce.html +530 -0
- package/docs/classes/extratag.extrapadding.html +456 -0
- package/docs/classes/extratag.extrapublickey.html +460 -0
- package/docs/classes/extratag.iextratag.html +355 -0
- package/docs/classes/levinpacket.html +674 -0
- package/docs/classes/levinpayloads.handshake.html +731 -0
- package/docs/classes/levinpayloads.ilevinpayload.html +318 -0
- package/docs/classes/levinpayloads.liteblock.html +494 -0
- package/docs/classes/levinpayloads.missingtransactions.html +494 -0
- package/docs/classes/levinpayloads.newblock.html +540 -0
- package/docs/classes/levinpayloads.newtransactions.html +402 -0
- package/docs/classes/levinpayloads.peerentry.html +610 -0
- package/docs/classes/levinpayloads.ping.html +450 -0
- package/docs/classes/levinpayloads.rawblock.html +344 -0
- package/docs/classes/levinpayloads.requestchain.html +402 -0
- package/docs/classes/levinpayloads.requestgetobjects.html +448 -0
- package/docs/classes/levinpayloads.requesttxpool.html +402 -0
- package/docs/classes/levinpayloads.responsechain.html +494 -0
- package/docs/classes/levinpayloads.responsegetobjects.html +540 -0
- package/docs/classes/levinpayloads.timedsync.html +540 -0
- package/docs/classes/multisig.html +930 -0
- package/docs/classes/multisigmessage.html +694 -0
- package/docs/classes/parentblock.html +347 -0
- package/docs/classes/transaction.html +925 -0
- package/docs/classes/transactioninputs.coinbaseinput.html +390 -0
- package/docs/classes/transactioninputs.itransactioninput.html +321 -0
- package/docs/classes/transactioninputs.keyinput.html +459 -0
- package/docs/classes/transactionoutputs.itransactionoutput.html +317 -0
- package/docs/classes/transactionoutputs.keyoutput.html +422 -0
- package/docs/enums/extranoncetag.noncetagtype.html +246 -0
- package/docs/enums/extratag.extratagtype.html +280 -0
- package/docs/enums/levinprotocol.commandtype.html +391 -0
- package/docs/enums/transactioninputs.inputtype.html +246 -0
- package/docs/enums/transactionoutputs.outputtype.html +229 -0
- package/docs/globals.html +238 -0
- package/docs/index.html +271 -0
- package/docs/interfaces/interfaces.config.html +590 -0
- package/docs/interfaces/interfaces.daemonblocktemplateresponse.html +323 -0
- package/docs/interfaces/interfaces.generatedinput.html +304 -0
- package/docs/interfaces/interfaces.generatedoutput.html +285 -0
- package/docs/interfaces/interfaces.inputkeys.html +304 -0
- package/docs/interfaces/interfaces.ipreparedtransaction.html +268 -0
- package/docs/interfaces/interfaces.output.html +399 -0
- package/docs/interfaces/interfaces.preparedringsignature.html +377 -0
- package/docs/interfaces/interfaces.preparedtransaction.html +329 -0
- package/docs/interfaces/interfaces.randomoutput.html +285 -0
- package/docs/interfaces/interfaces.transactionrecipient.html +285 -0
- package/docs/interfaces/multisiginterfaces.partialkeyimage.html +277 -0
- package/docs/interfaces/multisiginterfaces.partialsigningkey.html +277 -0
- package/docs/modules/ed25519.html +195 -0
- package/docs/modules/extranoncetag.html +208 -0
- package/docs/modules/extratag.html +216 -0
- package/docs/modules/interfaces.html +231 -0
- package/docs/modules/levinpayloads.html +247 -0
- package/docs/modules/levinprotocol.html +191 -0
- package/docs/modules/multisiginterfaces.html +195 -0
- package/docs/modules/transactioninputs.html +208 -0
- package/docs/modules/transactionoutputs.html +204 -0
- package/index.d.ts +417 -0
- package/index.js +1508 -0
- package/lib/base58.js +220 -0
- package/lib/biginteger.js +1591 -0
- package/lib/blocktemplate.js +408 -0
- package/lib/crypto.js +19698 -0
- package/lib/mnemonic.js +1204 -0
- package/lib/nacl-fast-cn.js +608 -0
- package/lib/ringsigs.js +24262 -0
- package/lib/sha3.js +477 -0
- package/package.json +58 -0
- package/src/Address.ts +433 -0
- package/src/AddressPrefix.ts +117 -0
- package/src/Block.ts +556 -0
- package/src/BlockTemplate.ts +289 -0
- package/src/Common.ts +105 -0
- package/src/Config.ts +66 -0
- package/src/CryptoNote.ts +1072 -0
- package/src/LevinPacket.ts +366 -0
- package/src/Multisig.ts +600 -0
- package/src/MultisigMessage.ts +374 -0
- package/src/ParentBlock.ts +39 -0
- package/src/Transaction.ts +628 -0
- package/src/Types/ED25519.ts +187 -0
- package/src/Types/IExtraNonce.ts +225 -0
- package/src/Types/IExtraTag.ts +507 -0
- package/src/Types/ITransaction.ts +230 -0
- package/src/Types/ITransactionInput.ts +190 -0
- package/src/Types/ITransactionOutput.ts +108 -0
- package/src/Types/LevinPayloads.ts +1576 -0
- package/src/Types/MultisigInterfaces.ts +65 -0
- package/src/Types/PortableStorage.ts +289 -0
- package/src/Types.ts +36 -0
- package/src/index.ts +36 -0
- package/test/template.json +6 -0
- package/test/test.js +1457 -0
- package/tests/blocktemplate.json +6 -0
- package/tests/tests.js +215 -0
- package/tsconfig.json +15 -0
- package/tslint.json +36 -0
- package/typedoc.json +10 -0
- package/webpack.config.js +15 -0
package/src/Address.ts
ADDED
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
// Copyright (c) 2018-2020, The TurtleCoin Developers
|
|
2
|
+
//
|
|
3
|
+
// Please see the included LICENSE file for more information.
|
|
4
|
+
|
|
5
|
+
import {AddressPrefix} from './AddressPrefix';
|
|
6
|
+
import {Base58} from 'turtlecoin-base58';
|
|
7
|
+
import {Common} from './Common';
|
|
8
|
+
import * as ConfigInterface from './Config';
|
|
9
|
+
import {ED25519, TurtleCoinCrypto} from './Types';
|
|
10
|
+
import {Mnemonics} from 'turtlecoin-mnemonics';
|
|
11
|
+
import {Reader, Writer} from 'bytestream-helper';
|
|
12
|
+
import Config = ConfigInterface.Interfaces.Config;
|
|
13
|
+
|
|
14
|
+
/** @ignore */
|
|
15
|
+
const Config: Config = require('../config.json');
|
|
16
|
+
|
|
17
|
+
/** @ignore */
|
|
18
|
+
interface Cache {
|
|
19
|
+
addressPrefix: string;
|
|
20
|
+
address: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** @ignore */
|
|
24
|
+
export enum SIZES {
|
|
25
|
+
KEY = 32,
|
|
26
|
+
CHECKSUM = 4,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Represents a TurtleCoin address
|
|
31
|
+
*/
|
|
32
|
+
export class Address {
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The Base58 encoded address
|
|
36
|
+
*/
|
|
37
|
+
public get address(): string {
|
|
38
|
+
return this.toString();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The address index number [0=primary]
|
|
43
|
+
*/
|
|
44
|
+
public get subwalletIndex(): number {
|
|
45
|
+
return this.m_subwalletIndex;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The seed phrase for the address if available
|
|
50
|
+
*/
|
|
51
|
+
public get seed(): string | undefined {
|
|
52
|
+
return this.m_seed;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The mnemonic phrase for the address if available
|
|
57
|
+
*/
|
|
58
|
+
public get mnemonic(): string | undefined {
|
|
59
|
+
return (this.m_seed) ? Mnemonics.encode(this.m_seed) : undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The payment Id of the address if one exists
|
|
64
|
+
*/
|
|
65
|
+
public get paymentId(): string {
|
|
66
|
+
let s: string;
|
|
67
|
+
s = Buffer.from(this.m_paymentId || '', 'hex').toString().toLowerCase();
|
|
68
|
+
return s;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public set paymentId(paymentId: string) {
|
|
72
|
+
if (!Common.isHex64(paymentId)) {
|
|
73
|
+
throw new Error('Invalid payment ID supplied');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
this.m_paymentId = Buffer.from(paymentId).toString('hex');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The address prefix
|
|
81
|
+
*/
|
|
82
|
+
public get prefix(): AddressPrefix {
|
|
83
|
+
return this.m_prefix;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public set prefix(addressPrefix: AddressPrefix) {
|
|
87
|
+
this.m_prefix = addressPrefix;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The address spend keys
|
|
92
|
+
*/
|
|
93
|
+
public get spend(): ED25519.KeyPair {
|
|
94
|
+
return this.m_keys.spend;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public set spend(keys: ED25519.KeyPair) {
|
|
98
|
+
this.m_keys.spend = keys;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The address view keys
|
|
103
|
+
*/
|
|
104
|
+
public get view(): ED25519.KeyPair {
|
|
105
|
+
return this.m_keys.view;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public set view(keys: ED25519.KeyPair) {
|
|
109
|
+
this.m_keys.view = keys;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Creates a new address object from a Base58 address
|
|
114
|
+
* @param address the public address to decode
|
|
115
|
+
* @param [prefix] the address prefix
|
|
116
|
+
* @returns a new address object
|
|
117
|
+
*/
|
|
118
|
+
public static fromAddress(address: string, prefix?: AddressPrefix | number): Address {
|
|
119
|
+
if (typeof prefix === 'number') {
|
|
120
|
+
prefix = new AddressPrefix(prefix);
|
|
121
|
+
} else if (typeof prefix === 'undefined') {
|
|
122
|
+
prefix = new AddressPrefix();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const decodedAddress = Base58.decode(address);
|
|
126
|
+
|
|
127
|
+
const reader = new Reader(decodedAddress);
|
|
128
|
+
|
|
129
|
+
const decodedPrefix = reader.bytes(prefix.size).toString('hex');
|
|
130
|
+
|
|
131
|
+
if (decodedPrefix !== prefix.hex) {
|
|
132
|
+
throw new Error('Invalid address prefix');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let paymentId = '';
|
|
136
|
+
|
|
137
|
+
if (reader.unreadBytes > ((SIZES.KEY * 2) + SIZES.CHECKSUM)) {
|
|
138
|
+
paymentId = reader.hex(SIZES.KEY * 2);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const publicSpend = reader.hash();
|
|
142
|
+
const publicView = reader.hash();
|
|
143
|
+
const expectedChecksum = reader.bytes(SIZES.CHECKSUM).toString('hex');
|
|
144
|
+
|
|
145
|
+
const checksum = (new Reader(
|
|
146
|
+
TurtleCoinCrypto.cn_fast_hash(decodedPrefix + paymentId + publicSpend + publicView),
|
|
147
|
+
)).bytes(SIZES.CHECKSUM).toString('hex');
|
|
148
|
+
|
|
149
|
+
if (expectedChecksum !== checksum) {
|
|
150
|
+
throw new Error('Could not parse address: checksum mismatch');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const result = new Address();
|
|
154
|
+
|
|
155
|
+
result.m_paymentId = paymentId;
|
|
156
|
+
|
|
157
|
+
result.m_keys = new ED25519.Keys(
|
|
158
|
+
new ED25519.KeyPair(publicSpend),
|
|
159
|
+
new ED25519.KeyPair(publicView),
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Creates a new address object using the supplied public keys
|
|
167
|
+
* @param publicSpendKey the public spend key
|
|
168
|
+
* @param publicViewKey the public view key
|
|
169
|
+
* @param [paymentId] the payment ID
|
|
170
|
+
* @param [prefix] the address prefix
|
|
171
|
+
* @returns a new address object
|
|
172
|
+
*/
|
|
173
|
+
public static fromPublicKeys(
|
|
174
|
+
publicSpendKey: string,
|
|
175
|
+
publicViewKey: string,
|
|
176
|
+
paymentId?: string,
|
|
177
|
+
prefix?: AddressPrefix | number): Address {
|
|
178
|
+
if (typeof prefix === 'number') {
|
|
179
|
+
prefix = new AddressPrefix(prefix);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const address = new Address();
|
|
183
|
+
|
|
184
|
+
if (prefix) {
|
|
185
|
+
address.prefix = prefix;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (paymentId) {
|
|
189
|
+
address.paymentId = paymentId;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
address.m_keys = new ED25519.Keys(
|
|
193
|
+
new ED25519.KeyPair(publicSpendKey),
|
|
194
|
+
new ED25519.KeyPair(publicViewKey),
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
return address;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Creates a new address object (view only) using the supplied keys
|
|
202
|
+
* @param publicSpendKey the public spend key
|
|
203
|
+
* @param privateViewKey the private view key
|
|
204
|
+
* @param [paymentId] the payment ID
|
|
205
|
+
* @param [prefix] the address prefix
|
|
206
|
+
* @returns a new address object
|
|
207
|
+
*/
|
|
208
|
+
public static fromViewOnlyKeys(
|
|
209
|
+
publicSpendKey: string,
|
|
210
|
+
privateViewKey: string,
|
|
211
|
+
paymentId?: string,
|
|
212
|
+
prefix?: AddressPrefix | number): Address {
|
|
213
|
+
if (typeof prefix === 'number') {
|
|
214
|
+
prefix = new AddressPrefix(prefix);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const address = new Address();
|
|
218
|
+
|
|
219
|
+
if (prefix) {
|
|
220
|
+
address.prefix = prefix;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (paymentId) {
|
|
224
|
+
address.paymentId = paymentId;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
address.m_keys = new ED25519.Keys(
|
|
228
|
+
new ED25519.KeyPair(publicSpendKey),
|
|
229
|
+
new ED25519.KeyPair(undefined, privateViewKey),
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
return address;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Creates a new address object using the supplied private keys
|
|
237
|
+
* @param privateSpendKey the private spend key
|
|
238
|
+
* @param privateViewKey the private view key
|
|
239
|
+
* @param [prefix] the address prefix
|
|
240
|
+
* @returns a new address object
|
|
241
|
+
*/
|
|
242
|
+
public static fromKeys(
|
|
243
|
+
privateSpendKey: string,
|
|
244
|
+
privateViewKey: string,
|
|
245
|
+
prefix?: AddressPrefix | number): Address {
|
|
246
|
+
if (typeof prefix === 'number') {
|
|
247
|
+
prefix = new AddressPrefix(prefix);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const address = new Address();
|
|
251
|
+
|
|
252
|
+
if (prefix) {
|
|
253
|
+
address.prefix = prefix;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
address.m_keys = new ED25519.Keys(
|
|
257
|
+
new ED25519.KeyPair(undefined, privateSpendKey),
|
|
258
|
+
new ED25519.KeyPair(undefined, privateViewKey),
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
const derivedViewKey = new ED25519.KeyPair(undefined, privateSpendKey, undefined, 1);
|
|
262
|
+
|
|
263
|
+
if (derivedViewKey.privateKey === privateViewKey) {
|
|
264
|
+
address.m_seed = privateSpendKey;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return address;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Creates a new address object from a mnemonic phrase
|
|
272
|
+
* @param mnemonic the wallet mnemonic phrase
|
|
273
|
+
* @param [language] the language of the mnemonic phrase
|
|
274
|
+
* @param [prefix] the address prefix
|
|
275
|
+
* @returns a new address object
|
|
276
|
+
*/
|
|
277
|
+
public static fromMnemonic(mnemonic: string, language?: string, prefix?: AddressPrefix | number): Address {
|
|
278
|
+
const seed = Mnemonics.decode(mnemonic);
|
|
279
|
+
|
|
280
|
+
return Address.fromSeed(seed, language, prefix);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Creates a new address object from a seed
|
|
285
|
+
* @param seed the wallet seed
|
|
286
|
+
* @param [language] the language of the mnemonic phrase
|
|
287
|
+
* @param [prefix] the address prefix
|
|
288
|
+
* @returns a new address object
|
|
289
|
+
*/
|
|
290
|
+
public static fromSeed(seed: string, language?: string, prefix?: AddressPrefix | number): Address {
|
|
291
|
+
if (typeof prefix === 'number') {
|
|
292
|
+
prefix = new AddressPrefix(prefix);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (!Common.isHex64(seed)) {
|
|
296
|
+
seed = TurtleCoinCrypto.cn_fast_hash(seed);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const address = new Address();
|
|
300
|
+
|
|
301
|
+
address.m_seed = seed;
|
|
302
|
+
|
|
303
|
+
address.m_language = language || 'english';
|
|
304
|
+
|
|
305
|
+
if (prefix) {
|
|
306
|
+
address.prefix = prefix;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
address.m_keys = new ED25519.Keys(
|
|
310
|
+
new ED25519.KeyPair(undefined, seed),
|
|
311
|
+
new ED25519.KeyPair(undefined, seed, undefined, 1));
|
|
312
|
+
|
|
313
|
+
return address;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Creates a new address object from entropy (new address)
|
|
318
|
+
* @param [entropy] data to use for entropy to feed to the underlying random generation function
|
|
319
|
+
* @param [language] the language of the mnemonic phrase
|
|
320
|
+
* @param [prefix] the address prefix
|
|
321
|
+
* @returns a new address object
|
|
322
|
+
*/
|
|
323
|
+
public static fromEntropy(entropy?: string, language?: string, prefix?: AddressPrefix | number): Address {
|
|
324
|
+
const seed = Address.generateSeed(entropy);
|
|
325
|
+
|
|
326
|
+
return Address.fromSeed(seed, language, prefix);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Generates a new seed from entropy
|
|
331
|
+
* @param [entropy] data to use for entropy to feed to the underlying random generation function
|
|
332
|
+
* @param [iterations] the number of iterations to run the hashing function when generating the seed
|
|
333
|
+
* @returns a new randomly created seed
|
|
334
|
+
*/
|
|
335
|
+
public static generateSeed(entropy?: string, iterations?: number): string {
|
|
336
|
+
const random = new ED25519.KeyPair(undefined, undefined, entropy, iterations);
|
|
337
|
+
|
|
338
|
+
return random.privateKey;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Generates a new subwallet address object using the supplied parameters
|
|
343
|
+
* @param privateSpendKey the private spend key
|
|
344
|
+
* @param subwalletIndex the subwallet index number
|
|
345
|
+
* @param [language] the language of the mnemonic phrase
|
|
346
|
+
* @param [prefix] the address prefix
|
|
347
|
+
* @returns a new address object
|
|
348
|
+
*/
|
|
349
|
+
public static generateSubwallet(
|
|
350
|
+
privateSpendKey: string,
|
|
351
|
+
subwalletIndex: number,
|
|
352
|
+
language?: string,
|
|
353
|
+
prefix?: AddressPrefix | number): Address {
|
|
354
|
+
if (typeof prefix === 'number') {
|
|
355
|
+
prefix = new AddressPrefix(prefix);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (!TurtleCoinCrypto.checkScalar(privateSpendKey)) {
|
|
359
|
+
throw new Error('Invalid private spend key supplied');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
subwalletIndex = Math.abs(subwalletIndex);
|
|
363
|
+
|
|
364
|
+
if (subwalletIndex === 0) {
|
|
365
|
+
return Address.fromSeed(privateSpendKey, language, prefix);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const address = new Address();
|
|
369
|
+
|
|
370
|
+
address.m_subwalletIndex = subwalletIndex;
|
|
371
|
+
|
|
372
|
+
if (prefix) {
|
|
373
|
+
address.prefix = prefix;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const view = new ED25519.KeyPair(undefined, privateSpendKey, undefined, 1);
|
|
377
|
+
|
|
378
|
+
const spend = TurtleCoinCrypto.generateDeterministicSubwalletKeys(privateSpendKey, subwalletIndex);
|
|
379
|
+
|
|
380
|
+
address.m_keys = new ED25519.Keys(new ED25519.KeyPair(spend.publicKey, spend.privateKey), view);
|
|
381
|
+
|
|
382
|
+
return address;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Encodes a raw address (hex) into Base58 notation
|
|
387
|
+
* @param rawAddress the raw address in hexadecimal form
|
|
388
|
+
* @retursn the Base58 representation of the address
|
|
389
|
+
*/
|
|
390
|
+
public static encodeRaw(rawAddress: string): string {
|
|
391
|
+
return Base58.encode(rawAddress);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
protected m_paymentId?: string;
|
|
395
|
+
protected m_seed?: string;
|
|
396
|
+
protected m_keys: ED25519.Keys = new ED25519.Keys();
|
|
397
|
+
protected m_language: string = 'english';
|
|
398
|
+
protected m_subwalletIndex: number = 0;
|
|
399
|
+
private m_prefix: AddressPrefix = new AddressPrefix(Config.addressPrefix);
|
|
400
|
+
private m_cached: Cache = {addressPrefix: '', address: ''};
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Returns the Base58 encoded address
|
|
404
|
+
* @returns Base58 encoded address
|
|
405
|
+
*/
|
|
406
|
+
public toString(): string {
|
|
407
|
+
const writer = new Writer();
|
|
408
|
+
|
|
409
|
+
writer.hex(this.prefix.hex);
|
|
410
|
+
|
|
411
|
+
if (this.m_paymentId) {
|
|
412
|
+
writer.hex(this.m_paymentId);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
writer.hash(this.m_keys.spend.publicKey);
|
|
416
|
+
|
|
417
|
+
writer.hash(this.m_keys.view.publicKey);
|
|
418
|
+
|
|
419
|
+
if (this.m_cached.addressPrefix === writer.blob && this.m_cached.address.length !== 0) {
|
|
420
|
+
return this.m_cached.address;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const checksum = TurtleCoinCrypto.cn_fast_hash(writer.blob).slice(0, 8);
|
|
424
|
+
|
|
425
|
+
this.m_cached.addressPrefix = writer.blob;
|
|
426
|
+
|
|
427
|
+
writer.hex(checksum);
|
|
428
|
+
|
|
429
|
+
this.m_cached.address = writer.blob;
|
|
430
|
+
|
|
431
|
+
return Base58.encode(writer.blob);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Copyright (c) 2018-2020, The TurtleCoin Developers
|
|
2
|
+
//
|
|
3
|
+
// Please see the included LICENSE file for more information.
|
|
4
|
+
|
|
5
|
+
import {Base58} from 'turtlecoin-base58';
|
|
6
|
+
import * as ConfigInterface from './Config';
|
|
7
|
+
import {Reader, Writer} from 'bytestream-helper';
|
|
8
|
+
import Config = ConfigInterface.Interfaces.Config;
|
|
9
|
+
|
|
10
|
+
/** @ignore */
|
|
11
|
+
export enum SIZES {
|
|
12
|
+
KEY = 32,
|
|
13
|
+
CHECKSUM = 4,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** @ignore */
|
|
17
|
+
const Config: Config = require('../config.json');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Represents a TurtleCoin address prefix
|
|
21
|
+
*/
|
|
22
|
+
export class AddressPrefix {
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The Base58 encoded address prefix
|
|
26
|
+
*/
|
|
27
|
+
public get base58(): string {
|
|
28
|
+
if (this.m_base58) {
|
|
29
|
+
return this.m_base58;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return Base58.encode(this.hex);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The decimal encoded address prefix
|
|
37
|
+
*/
|
|
38
|
+
public get decimal(): number {
|
|
39
|
+
return this.m_decimal || 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The hexadecimal encoded address prefix
|
|
44
|
+
*/
|
|
45
|
+
public get hex(): string {
|
|
46
|
+
return this.varint.toString('hex');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The varint encoded address prefix
|
|
51
|
+
*/
|
|
52
|
+
public get varint(): Buffer {
|
|
53
|
+
const writer = new Writer();
|
|
54
|
+
|
|
55
|
+
writer.varint(this.decimal);
|
|
56
|
+
|
|
57
|
+
return writer.buffer;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The size of the address prefix in bytes
|
|
62
|
+
*/
|
|
63
|
+
public get size(): number {
|
|
64
|
+
return this.varint.length;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Creates a new address prefix object from a Base58 encoded address
|
|
69
|
+
* @param address the public wallet address to decode to obtain the address prefix
|
|
70
|
+
* @returns the address prefix
|
|
71
|
+
*/
|
|
72
|
+
public static from(address: string): AddressPrefix {
|
|
73
|
+
let decodedAddress = Base58.decode(address);
|
|
74
|
+
|
|
75
|
+
/* Chop off the checksum */
|
|
76
|
+
decodedAddress = decodedAddress.slice(0, -(SIZES.CHECKSUM * 2));
|
|
77
|
+
|
|
78
|
+
const prefixLength = decodedAddress.length % (SIZES.KEY * 2);
|
|
79
|
+
|
|
80
|
+
const prefixDecoded = decodedAddress.slice(0, prefixLength);
|
|
81
|
+
|
|
82
|
+
const reader = new Reader(prefixDecoded);
|
|
83
|
+
|
|
84
|
+
const prefixDecimal = reader.varint().toJSNumber();
|
|
85
|
+
|
|
86
|
+
/* This starts a bit of hackery to deal with the block encoding
|
|
87
|
+
* used by Base58 and the fact that the prefix may not be exactly
|
|
88
|
+
* one data block long */
|
|
89
|
+
let offset = (prefixDecimal.toString().length % 2 === 0) ? 1 : 0;
|
|
90
|
+
|
|
91
|
+
if (prefixDecimal.toString().length > 10) {
|
|
92
|
+
offset += Math.floor((prefixDecimal.toString().length % 10) / 2);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const prefixEncoded = address.slice(0, Math.ceil(prefixDecimal.toString().length / 2) + offset);
|
|
96
|
+
|
|
97
|
+
return new AddressPrefix(prefixDecimal, prefixEncoded);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
protected m_base58?: string;
|
|
101
|
+
protected m_decimal: number = Config.addressPrefix || 3914525;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates a new address prefix object
|
|
105
|
+
* @param [decimal] the decimal representation of the address prefix
|
|
106
|
+
* @param [base58] the Base58 representation of the address prefix
|
|
107
|
+
*/
|
|
108
|
+
constructor(decimal?: number, base58?: string) {
|
|
109
|
+
if (decimal) {
|
|
110
|
+
this.m_decimal = decimal;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (base58) {
|
|
114
|
+
this.m_base58 = base58;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|