@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
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
// Copyright (c) 2020, The TurtleCoin Developers
|
|
2
|
+
//
|
|
3
|
+
// Please see the included LICENSE file for more information.
|
|
4
|
+
|
|
5
|
+
import {Address} from './Address';
|
|
6
|
+
import {AddressPrefix} from './AddressPrefix';
|
|
7
|
+
import {ED25519, Interfaces as TransactionInterfaces, MultisigInterfaces, TurtleCoinCrypto} from './Types';
|
|
8
|
+
import {Counter, ModeOfOperation, utils as AESUtils} from 'aes-js';
|
|
9
|
+
import {Reader, Writer} from 'bytestream-helper';
|
|
10
|
+
import {Base58} from 'turtlecoin-base58';
|
|
11
|
+
|
|
12
|
+
/** @ignore */
|
|
13
|
+
const messagePrefix: number = 0xde0aec198;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Represents a Multisignature inter-wallet Message that is used to exchange data between multisignature participants
|
|
17
|
+
*/
|
|
18
|
+
export class MultisigMessage {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The private view key communicated in the message
|
|
22
|
+
*/
|
|
23
|
+
public get view(): string {
|
|
24
|
+
return this.m_privateViewKey.privateKey;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The source individual wallet address that the message is being sent FROM
|
|
29
|
+
*/
|
|
30
|
+
public get source(): Address {
|
|
31
|
+
return this.m_source;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public set source(source: Address) {
|
|
35
|
+
if (source.view.privateKey.length === 0) {
|
|
36
|
+
throw new Error('Source private view key not available');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
this.m_source = source;
|
|
40
|
+
|
|
41
|
+
this.m_privateViewKey = source.view;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The destination individual wallet address the message is being sent TO
|
|
46
|
+
*/
|
|
47
|
+
public get destination(): Address {
|
|
48
|
+
return this.m_destination;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public set destination(destination: Address) {
|
|
52
|
+
this.m_destination = destination;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A one-time nonce value that should increment/change for every message exchanged between the wallets
|
|
57
|
+
*/
|
|
58
|
+
public get nonce(): number {
|
|
59
|
+
return this.m_nonce;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The multisig public spend keys transferred in the message
|
|
64
|
+
*/
|
|
65
|
+
public get spendKeys(): ED25519.KeyPair[] {
|
|
66
|
+
return this.m_spendKeys;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The partial key images transferred in the message
|
|
71
|
+
*/
|
|
72
|
+
public get partialKeyImages(): MultisigInterfaces.PartialKeyImage[] {
|
|
73
|
+
return this.m_partialKeyImages;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public set partialKeyImages(partialKeyImages: MultisigInterfaces.PartialKeyImage[]) {
|
|
77
|
+
this.m_partialKeyImages = partialKeyImages;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The partial signing keys transferred in the message
|
|
82
|
+
*/
|
|
83
|
+
public get partialSigningKeys(): MultisigInterfaces.PartialSigningKey[] {
|
|
84
|
+
return this.m_partialSigningKeys;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public set partialSigningKeys(partialSigningKeys: MultisigInterfaces.PartialSigningKey[]) {
|
|
88
|
+
this.m_partialSigningKeys = partialSigningKeys;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The prepared transactions transferred in the message
|
|
93
|
+
*/
|
|
94
|
+
public get preparedTransactions(): TransactionInterfaces.PreparedTransaction[] {
|
|
95
|
+
return this.m_preparedTransactions;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public set preparedTransactions(preparedTransactions: TransactionInterfaces.PreparedTransaction[]) {
|
|
99
|
+
this.m_preparedTransactions = preparedTransactions;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Decodes a Base58 string into a multisig message object.
|
|
104
|
+
*
|
|
105
|
+
* This method validates that all signatures included in the data are valid, the data is properly
|
|
106
|
+
* decrypted, and the signatures of the public keys included in the payload(s) are valid
|
|
107
|
+
*
|
|
108
|
+
* @async
|
|
109
|
+
* @param destination The wallet address that this message was sent
|
|
110
|
+
* @param base58 The Base58 encoded data
|
|
111
|
+
*/
|
|
112
|
+
public static async decode(destination: Address, base58: string): Promise<MultisigMessage> {
|
|
113
|
+
if (!destination.spend.isPaired) {
|
|
114
|
+
throw new Error('Cannot attempt decryption without private spend key');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const prefix = new AddressPrefix(messagePrefix);
|
|
118
|
+
|
|
119
|
+
const decoded = Base58.decode(base58);
|
|
120
|
+
|
|
121
|
+
const signature = decoded.slice(-128);
|
|
122
|
+
|
|
123
|
+
const rawData = decoded.slice(0, decoded.length - 128);
|
|
124
|
+
|
|
125
|
+
const hash = await TurtleCoinCrypto.cn_fast_hash(rawData);
|
|
126
|
+
|
|
127
|
+
const reader = new Reader(rawData);
|
|
128
|
+
|
|
129
|
+
const foundPrefix = reader.hex(prefix.varint.length);
|
|
130
|
+
|
|
131
|
+
if (foundPrefix !== prefix.hex) {
|
|
132
|
+
throw new Error('Invalid data supplied');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const nonce = reader.varint().toJSNumber();
|
|
136
|
+
|
|
137
|
+
const length = reader.varint().toJSNumber();
|
|
138
|
+
|
|
139
|
+
const transfer: MultisigInterfaces.Transfer = JSON.parse(reader.bytes(length).toString());
|
|
140
|
+
|
|
141
|
+
const source = Address.fromAddress(transfer.address);
|
|
142
|
+
|
|
143
|
+
if (!await TurtleCoinCrypto.checkSignature(hash, source.spend.publicKey, signature)) {
|
|
144
|
+
throw new Error('Invalid data signature');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (reader.unreadBytes !== 0) {
|
|
148
|
+
throw new RangeError('Data contains unstructured information');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const result = new MultisigMessage();
|
|
152
|
+
|
|
153
|
+
result.m_source = source;
|
|
154
|
+
|
|
155
|
+
result.destination = destination;
|
|
156
|
+
|
|
157
|
+
result.m_nonce = nonce;
|
|
158
|
+
|
|
159
|
+
const payload = await decrypt(destination, transfer, nonce);
|
|
160
|
+
|
|
161
|
+
for (const publicSpendKey of payload.publicSpendKeys) {
|
|
162
|
+
result.m_spendKeys.push(new ED25519.KeyPair(publicSpendKey.key));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (payload.partialKeyImages) {
|
|
166
|
+
result.partialKeyImages = payload.partialKeyImages;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (payload.partialSigningKeys) {
|
|
170
|
+
result.partialSigningKeys = payload.partialSigningKeys;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (payload.preparedTransactions) {
|
|
174
|
+
result.preparedTransactions = payload.preparedTransactions;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
result.m_privateViewKey = new ED25519.KeyPair(undefined, payload.privateViewKey);
|
|
178
|
+
|
|
179
|
+
await verifySpendKeySignatures(payload.publicSpendKeys);
|
|
180
|
+
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
protected m_source: Address = new Address();
|
|
185
|
+
protected m_spendKeys: ED25519.KeyPair[] = [];
|
|
186
|
+
protected m_privateViewKey: ED25519.KeyPair = new ED25519.KeyPair();
|
|
187
|
+
protected m_nonce: number = 1;
|
|
188
|
+
protected m_partialKeyImages: MultisigInterfaces.PartialKeyImage[] = [];
|
|
189
|
+
protected m_partialSigningKeys: MultisigInterfaces.PartialSigningKey[] = [];
|
|
190
|
+
protected m_preparedTransactions: TransactionInterfaces.PreparedTransaction[] = [];
|
|
191
|
+
private m_destination: Address = new Address();
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Constructs a new instance of a MultisigMessage object
|
|
195
|
+
* @param [source] The source individual wallet address that the message is being sent FROM
|
|
196
|
+
* @param [destination] The destination individual wallet address the message is being sent TO
|
|
197
|
+
* @param [nonce] A one-time nonce value that should increment/change for every message
|
|
198
|
+
* exchanged between the wallets
|
|
199
|
+
*/
|
|
200
|
+
constructor(source?: Address, destination?: Address, nonce?: number) {
|
|
201
|
+
if (source) {
|
|
202
|
+
this.source = source;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (destination) {
|
|
206
|
+
this.destination = destination;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (nonce) {
|
|
210
|
+
this.m_nonce = nonce;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Adds a new set of spend keys to the message
|
|
216
|
+
*
|
|
217
|
+
* Note: The key pair must be complete (both private and public) to complete the necessary
|
|
218
|
+
* signing processes to provide proof that we have the private key for the given public key.
|
|
219
|
+
*
|
|
220
|
+
* @param keypair The spend key pair to include.
|
|
221
|
+
*/
|
|
222
|
+
public addSpendKeys(keypair: ED25519.KeyPair): boolean {
|
|
223
|
+
if (!keypair.isPaired) {
|
|
224
|
+
throw new Error('The private key and public key are not cryptographically paired');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
for (const k of this.m_spendKeys) {
|
|
228
|
+
if (k.publicKey === keypair.publicKey) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
this.m_spendKeys.push(keypair);
|
|
234
|
+
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Encodes the multisig message object as a Base58 encoded string that can be easily
|
|
240
|
+
*
|
|
241
|
+
* This method performs all necessary signing of the supplied public keys, encrypts the payload,
|
|
242
|
+
* and signs the message to prevent tampering and protect the confidential information inside.
|
|
243
|
+
*
|
|
244
|
+
* transferred between multisig wallet participants
|
|
245
|
+
* @async
|
|
246
|
+
* @returns The Base58 encoded string for transmission
|
|
247
|
+
*/
|
|
248
|
+
public async encode(): Promise<string> {
|
|
249
|
+
if (!this.source.spend.isPaired) {
|
|
250
|
+
throw new Error('Cannot encode as we do not have the full key pair to do so [SPEND]');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (!this.source.view.isPaired) {
|
|
254
|
+
throw new Error('Cannot encode as we do not have the full key pair to do so [VIEW]');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const payload: MultisigInterfaces.Payload = {
|
|
258
|
+
publicSpendKeys: await calculateSpendKeySignatures(this.spendKeys),
|
|
259
|
+
privateViewKey: this.source.view.privateKey,
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
if (this.partialKeyImages.length !== 0) {
|
|
263
|
+
payload.partialKeyImages = this.partialKeyImages;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (this.partialSigningKeys.length !== 0) {
|
|
267
|
+
payload.partialSigningKeys = this.partialSigningKeys;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (this.preparedTransactions.length !== 0) {
|
|
271
|
+
payload.preparedTransactions = this.preparedTransactions;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const prefix = new AddressPrefix(messagePrefix);
|
|
275
|
+
|
|
276
|
+
const writer = new Writer();
|
|
277
|
+
|
|
278
|
+
writer.hex(prefix.hex);
|
|
279
|
+
|
|
280
|
+
writer.varint(this.nonce);
|
|
281
|
+
|
|
282
|
+
const transfer = await encrypt(this.source, this.destination, payload, this.nonce);
|
|
283
|
+
|
|
284
|
+
const subWriter = new Writer();
|
|
285
|
+
|
|
286
|
+
subWriter.write(transfer);
|
|
287
|
+
|
|
288
|
+
writer.varint(subWriter.length);
|
|
289
|
+
|
|
290
|
+
writer.write(subWriter.buffer);
|
|
291
|
+
|
|
292
|
+
const hash = await TurtleCoinCrypto.cn_fast_hash(writer.blob);
|
|
293
|
+
|
|
294
|
+
const sig = await TurtleCoinCrypto.generateSignature(
|
|
295
|
+
hash, this.source.spend.publicKey, this.source.spend.privateKey);
|
|
296
|
+
|
|
297
|
+
writer.hex(sig);
|
|
298
|
+
|
|
299
|
+
return Base58.encode(writer.blob);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** @ignore */
|
|
305
|
+
async function encrypt(
|
|
306
|
+
source: Address,
|
|
307
|
+
destination: Address,
|
|
308
|
+
payload: MultisigInterfaces.Payload,
|
|
309
|
+
nonce: number): Promise<MultisigInterfaces.Transfer> {
|
|
310
|
+
const transfer = Buffer.from(JSON.stringify(payload));
|
|
311
|
+
|
|
312
|
+
const aesKey = Buffer.from(
|
|
313
|
+
await TurtleCoinCrypto.generateKeyDerivation(
|
|
314
|
+
destination.spend.publicKey, source.spend.privateKey), 'hex');
|
|
315
|
+
|
|
316
|
+
const ctx = new ModeOfOperation.ctr(aesKey, new Counter(nonce));
|
|
317
|
+
|
|
318
|
+
const encryptedBytes = ctx.encrypt(transfer);
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
address: source.address,
|
|
322
|
+
messageId: nonce,
|
|
323
|
+
payload: AESUtils.hex.fromBytes(encryptedBytes),
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** @ignore */
|
|
328
|
+
async function decrypt(
|
|
329
|
+
destination: Address,
|
|
330
|
+
transfer: MultisigInterfaces.Transfer,
|
|
331
|
+
nonce: number): Promise<MultisigInterfaces.Payload> {
|
|
332
|
+
const sender = Address.fromAddress(transfer.address);
|
|
333
|
+
|
|
334
|
+
const aesKey = Buffer.from(
|
|
335
|
+
await TurtleCoinCrypto.generateKeyDerivation(
|
|
336
|
+
sender.spend.publicKey, destination.spend.privateKey), 'hex');
|
|
337
|
+
|
|
338
|
+
const ctx = new ModeOfOperation.ctr(aesKey, new Counter(nonce));
|
|
339
|
+
|
|
340
|
+
const decryptedBytes = ctx.decrypt(AESUtils.hex.toBytes(transfer.payload));
|
|
341
|
+
|
|
342
|
+
try {
|
|
343
|
+
return JSON.parse(Buffer.from(decryptedBytes).toString());
|
|
344
|
+
} catch {
|
|
345
|
+
throw new Error('Could not decrypt transfer');
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** @ignore */
|
|
350
|
+
async function calculateSpendKeySignatures(
|
|
351
|
+
spendKeys: ED25519.KeyPair[]): Promise<MultisigInterfaces.PublicSpendKey[]> {
|
|
352
|
+
const signatures: MultisigInterfaces.PublicSpendKey[] = [];
|
|
353
|
+
|
|
354
|
+
for (const keys of spendKeys) {
|
|
355
|
+
if (!keys.isPaired) {
|
|
356
|
+
throw new Error('The supplied spend keys are not paired correctly');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const sig = TurtleCoinCrypto.generateSignature(keys.publicKey, keys.publicKey, keys.privateKey);
|
|
360
|
+
|
|
361
|
+
signatures.push({key: keys.publicKey, signature: sig});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return signatures;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** @ignore */
|
|
368
|
+
async function verifySpendKeySignatures(spendKeys: MultisigInterfaces.PublicSpendKey[]): Promise<void> {
|
|
369
|
+
for (const spendKey of spendKeys) {
|
|
370
|
+
if (!await TurtleCoinCrypto.checkSignature(spendKey.key, spendKey.key, spendKey.signature)) {
|
|
371
|
+
throw new Error('Invalid public spend key signature for: ' + spendKey.key);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Copyright (c) 2018-2020, The TurtleCoin Developers
|
|
2
|
+
//
|
|
3
|
+
// Please see the included LICENSE file for more information.
|
|
4
|
+
|
|
5
|
+
import {Transaction} from './Transaction';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents a parent block object
|
|
9
|
+
*/
|
|
10
|
+
export class ParentBlock {
|
|
11
|
+
/**
|
|
12
|
+
* The major block version number
|
|
13
|
+
*/
|
|
14
|
+
public majorVersion: number = 0;
|
|
15
|
+
/**
|
|
16
|
+
* The minor block version number
|
|
17
|
+
*/
|
|
18
|
+
public minorVersion: number = 0;
|
|
19
|
+
/**
|
|
20
|
+
* The previous block hash
|
|
21
|
+
*/
|
|
22
|
+
public previousBlockHash: string = ''.padStart(64, '0');
|
|
23
|
+
/**
|
|
24
|
+
* The number of transactions in the block
|
|
25
|
+
*/
|
|
26
|
+
public transactionCount: number = 0;
|
|
27
|
+
/**
|
|
28
|
+
* The base transaction branches
|
|
29
|
+
*/
|
|
30
|
+
public baseTransactionBranch: string[] = [];
|
|
31
|
+
/**
|
|
32
|
+
* The miner reward transaction
|
|
33
|
+
*/
|
|
34
|
+
public minerTransaction: Transaction = new Transaction();
|
|
35
|
+
/**
|
|
36
|
+
* The blockchain branches
|
|
37
|
+
*/
|
|
38
|
+
public blockchainBranch: string[] = [];
|
|
39
|
+
}
|