algosdk 3.5.2 → 3.7.0-beta.1

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.
Files changed (133) hide show
  1. package/README.md +4 -4
  2. package/dist/browser/algosdk.min.js +1 -1
  3. package/dist/browser/algosdk.min.js.map +1 -1
  4. package/dist/cjs/appAccess.js +8 -5
  5. package/dist/cjs/appAccess.js.map +1 -1
  6. package/dist/cjs/client/v2/algod/accountApplicationsInformation.js +38 -0
  7. package/dist/cjs/client/v2/algod/accountApplicationsInformation.js.map +1 -0
  8. package/dist/cjs/client/v2/algod/accountAssetsInformation.js +31 -0
  9. package/dist/cjs/client/v2/algod/accountAssetsInformation.js.map +1 -0
  10. package/dist/cjs/client/v2/algod/algod.js +23 -19
  11. package/dist/cjs/client/v2/algod/algod.js.map +1 -1
  12. package/dist/cjs/client/v2/algod/getApplicationBoxes.js +116 -5
  13. package/dist/cjs/client/v2/algod/getApplicationBoxes.js.map +1 -1
  14. package/dist/cjs/client/v2/algod/models/types.js +243 -452
  15. package/dist/cjs/client/v2/algod/models/types.js.map +1 -1
  16. package/dist/cjs/ed25519-signer.js +76 -0
  17. package/dist/cjs/ed25519-signer.js.map +1 -0
  18. package/dist/cjs/encoding/address.js +61 -1
  19. package/dist/cjs/encoding/address.js.map +1 -1
  20. package/dist/cjs/falcon-signer.js +17 -0
  21. package/dist/cjs/falcon-signer.js.map +1 -0
  22. package/dist/cjs/logicsig.js +201 -16
  23. package/dist/cjs/logicsig.js.map +1 -1
  24. package/dist/cjs/main.js +32 -63
  25. package/dist/cjs/main.js.map +1 -1
  26. package/dist/cjs/mnemonic/mnemonic.js +26 -1
  27. package/dist/cjs/mnemonic/mnemonic.js.map +1 -1
  28. package/dist/cjs/multisigSigning.js +78 -1
  29. package/dist/cjs/multisigSigning.js.map +1 -1
  30. package/dist/cjs/pq-signer.js +54 -0
  31. package/dist/cjs/pq-signer.js.map +1 -0
  32. package/dist/cjs/signedTransaction.js +15 -1
  33. package/dist/cjs/signedTransaction.js.map +1 -1
  34. package/dist/cjs/signer.js.map +1 -1
  35. package/dist/cjs/signing.js +94 -7
  36. package/dist/cjs/signing.js.map +1 -1
  37. package/dist/cjs/transaction.js +9 -1
  38. package/dist/cjs/transaction.js.map +1 -1
  39. package/dist/cjs/types/transactions/encoded.js +51 -1
  40. package/dist/cjs/types/transactions/encoded.js.map +1 -1
  41. package/dist/cjs/utils/ed25519-check.js +69 -0
  42. package/dist/cjs/utils/ed25519-check.js.map +1 -0
  43. package/dist/esm/appAccess.js +8 -5
  44. package/dist/esm/appAccess.js.map +1 -1
  45. package/dist/esm/client/v2/algod/accountApplicationsInformation.js +32 -0
  46. package/dist/esm/client/v2/algod/accountApplicationsInformation.js.map +1 -0
  47. package/dist/esm/client/v2/algod/accountAssetsInformation.js +25 -0
  48. package/dist/esm/client/v2/algod/accountAssetsInformation.js.map +1 -0
  49. package/dist/esm/client/v2/algod/algod.js +23 -19
  50. package/dist/esm/client/v2/algod/algod.js.map +1 -1
  51. package/dist/esm/client/v2/algod/getApplicationBoxes.js +116 -5
  52. package/dist/esm/client/v2/algod/getApplicationBoxes.js.map +1 -1
  53. package/dist/esm/client/v2/algod/models/types.js +239 -445
  54. package/dist/esm/client/v2/algod/models/types.js.map +1 -1
  55. package/dist/esm/ed25519-signer.js +72 -0
  56. package/dist/esm/ed25519-signer.js.map +1 -0
  57. package/dist/esm/encoding/address.js +58 -0
  58. package/dist/esm/encoding/address.js.map +1 -1
  59. package/dist/esm/falcon-signer.js +13 -0
  60. package/dist/esm/falcon-signer.js.map +1 -0
  61. package/dist/esm/logicsig.js +200 -15
  62. package/dist/esm/logicsig.js.map +1 -1
  63. package/dist/esm/main.js +8 -56
  64. package/dist/esm/main.js.map +1 -1
  65. package/dist/esm/mnemonic/mnemonic.js +25 -1
  66. package/dist/esm/mnemonic/mnemonic.js.map +1 -1
  67. package/dist/esm/multisigSigning.js +75 -0
  68. package/dist/esm/multisigSigning.js.map +1 -1
  69. package/dist/esm/pq-signer.js +50 -0
  70. package/dist/esm/pq-signer.js.map +1 -0
  71. package/dist/esm/signedTransaction.js +16 -2
  72. package/dist/esm/signedTransaction.js.map +1 -1
  73. package/dist/esm/signer.js.map +1 -1
  74. package/dist/esm/signing.js +91 -8
  75. package/dist/esm/signing.js.map +1 -1
  76. package/dist/esm/transaction.js +9 -1
  77. package/dist/esm/transaction.js.map +1 -1
  78. package/dist/esm/types/transactions/encoded.js +49 -1
  79. package/dist/esm/types/transactions/encoded.js.map +1 -1
  80. package/dist/esm/utils/ed25519-check.js +65 -0
  81. package/dist/esm/utils/ed25519-check.js.map +1 -0
  82. package/dist/types/client/v2/algod/accountApplicationsInformation.d.ts +16 -0
  83. package/dist/types/client/v2/algod/accountAssetsInformation.d.ts +12 -0
  84. package/dist/types/client/v2/algod/algod.d.ts +19 -17
  85. package/dist/types/client/v2/algod/getApplicationBoxes.d.ts +100 -5
  86. package/dist/types/client/v2/algod/models/types.d.ts +146 -232
  87. package/dist/types/ed25519-signer.d.ts +7 -0
  88. package/dist/types/encoding/address.d.ts +37 -0
  89. package/dist/types/falcon-signer.d.ts +11 -0
  90. package/dist/types/logicsig.d.ts +72 -1
  91. package/dist/types/main.d.ts +8 -44
  92. package/dist/types/mnemonic/mnemonic.d.ts +13 -0
  93. package/dist/types/multisigSigning.d.ts +49 -0
  94. package/dist/types/pq-signer.d.ts +8 -0
  95. package/dist/types/signedTransaction.d.ts +7 -2
  96. package/dist/types/signer.d.ts +38 -0
  97. package/dist/types/signing.d.ts +45 -0
  98. package/dist/types/transaction.d.ts +9 -0
  99. package/dist/types/types/transactions/encoded.d.ts +27 -0
  100. package/dist/types/utils/ed25519-check.d.ts +10 -0
  101. package/package.json +2 -1
  102. package/src/appAccess.ts +10 -5
  103. package/src/client/v2/algod/accountApplicationsInformation.ts +46 -0
  104. package/src/client/v2/algod/accountAssetsInformation.ts +33 -0
  105. package/src/client/v2/algod/algod.ts +25 -20
  106. package/src/client/v2/algod/getApplicationBoxes.ts +123 -5
  107. package/src/client/v2/algod/models/types.ts +523 -846
  108. package/src/ed25519-signer.ts +125 -0
  109. package/src/encoding/address.ts +80 -0
  110. package/src/falcon-signer.ts +30 -0
  111. package/src/logicsig.ts +258 -16
  112. package/src/main.ts +30 -60
  113. package/src/mnemonic/mnemonic.ts +34 -1
  114. package/src/multisigSigning.ts +111 -0
  115. package/src/pq-signer.ts +90 -0
  116. package/src/signedTransaction.ts +24 -0
  117. package/src/signer.ts +53 -0
  118. package/src/signing.ts +109 -8
  119. package/src/transaction.ts +9 -1
  120. package/src/types/transactions/encoded.ts +88 -0
  121. package/src/utils/ed25519-check.ts +67 -0
  122. package/dist/cjs/client/v2/algod/dryrun.js +0 -34
  123. package/dist/cjs/client/v2/algod/dryrun.js.map +0 -1
  124. package/dist/cjs/dryrun.js +0 -214
  125. package/dist/cjs/dryrun.js.map +0 -1
  126. package/dist/esm/client/v2/algod/dryrun.js +0 -28
  127. package/dist/esm/client/v2/algod/dryrun.js.map +0 -1
  128. package/dist/esm/dryrun.js +0 -208
  129. package/dist/esm/dryrun.js.map +0 -1
  130. package/dist/types/client/v2/algod/dryrun.d.ts +0 -11
  131. package/dist/types/dryrun.d.ts +0 -28
  132. package/src/client/v2/algod/dryrun.ts +0 -38
  133. package/src/dryrun.ts +0 -292
package/src/logicsig.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  import * as nacl from './nacl/naclWrappers.js';
2
- import { Address, isValidAddress } from './encoding/address.js';
2
+ import {
3
+ Address,
4
+ addressFromPQSig,
5
+ isValidAddress,
6
+ } from './encoding/address.js';
3
7
  import * as encoding from './encoding/encoding.js';
4
8
  import {
5
9
  NamedMapSchema,
@@ -21,7 +25,12 @@ import {
21
25
  encodedMultiSigToEncodingData,
22
26
  encodedMultiSigFromEncodingData,
23
27
  ENCODED_MULTISIG_SCHEMA,
28
+ EncodedPQSig,
29
+ ENCODED_PQSIG_SCHEMA,
30
+ encodedPQSigToEncodingData,
31
+ encodedPQSigFromEncodingData,
24
32
  } from './types/transactions/encoded.js';
33
+ import type { DelegatedLsigSigner, ProgramDataSigner } from './signer.js';
25
34
 
26
35
  // base64regex is the regex to test for base64 strings
27
36
  const base64regex =
@@ -59,8 +68,9 @@ export function sanityCheckProgram(program: Uint8Array) {
59
68
  }
60
69
  }
61
70
 
62
- const programTag = new TextEncoder().encode('Program');
63
- const multisigProgramTag = new TextEncoder().encode('MsigProgram');
71
+ export const PROGRAM_TAG = new TextEncoder().encode('Program');
72
+ export const PQ_PROGRAM_TAG = new TextEncoder().encode('PQProgram');
73
+ export const MSIG_PROGRAM_TAG = new TextEncoder().encode('MsigProgram');
64
74
 
65
75
  /**
66
76
  LogicSig implementation
@@ -90,6 +100,10 @@ export class LogicSig implements encoding.Encodable {
90
100
  key: 'lmsig',
91
101
  valueSchema: new OptionalSchema(ENCODED_MULTISIG_SCHEMA),
92
102
  },
103
+ {
104
+ key: 'pqsig',
105
+ valueSchema: new OptionalSchema(ENCODED_PQSIG_SCHEMA),
106
+ },
93
107
  ])
94
108
  );
95
109
 
@@ -98,6 +112,7 @@ export class LogicSig implements encoding.Encodable {
98
112
  sig?: Uint8Array;
99
113
  msig?: EncodedMultisig;
100
114
  lmsig?: EncodedMultisig;
115
+ pqsig?: EncodedPQSig;
101
116
 
102
117
  constructor(program: Uint8Array, programArgs?: Array<Uint8Array> | null) {
103
118
  if (
@@ -119,6 +134,7 @@ export class LogicSig implements encoding.Encodable {
119
134
  this.sig = undefined;
120
135
  this.msig = undefined;
121
136
  this.lmsig = undefined;
137
+ this.pqsig = undefined;
122
138
  }
123
139
 
124
140
  // eslint-disable-next-line class-methods-use-this
@@ -138,6 +154,9 @@ export class LogicSig implements encoding.Encodable {
138
154
  if (this.lmsig) {
139
155
  data.set('lmsig', encodedMultiSigToEncodingData(this.lmsig));
140
156
  }
157
+ if (this.pqsig) {
158
+ data.set('pqsig', encodedPQSigToEncodingData(this.pqsig));
159
+ }
141
160
  return data;
142
161
  }
143
162
 
@@ -153,15 +172,23 @@ export class LogicSig implements encoding.Encodable {
153
172
  if (data.get('lmsig')) {
154
173
  lsig.lmsig = encodedMultiSigFromEncodingData(data.get('lmsig'));
155
174
  }
175
+ if (data.get('pqsig')) {
176
+ lsig.pqsig = encodedPQSigFromEncodingData(data.get('pqsig'));
177
+ }
156
178
  return lsig;
157
179
  }
158
180
 
159
181
  /**
182
+ * @deprecated This function does not perform full verification and should not be fully trusted on its own.
183
+ * For example, it does not evaluate programs and does not have the ability to validate PQ signatures.
184
+ *
160
185
  * Performs signature verification
161
186
  * @param publicKey - Verification key (derived from sender address or escrow address)
162
187
  */
163
188
  verify(publicKey: Uint8Array) {
164
- const sigCount = [this.sig, this.msig, this.lmsig].filter(Boolean).length;
189
+ const sigCount = [this.sig, this.msig, this.lmsig, this.pqsig].filter(
190
+ Boolean
191
+ ).length;
165
192
  if (sigCount > 1) {
166
193
  return false;
167
194
  }
@@ -172,13 +199,21 @@ export class LogicSig implements encoding.Encodable {
172
199
  return false;
173
200
  }
174
201
 
175
- const toBeSigned = utils.concatArrays(programTag, this.logic);
202
+ const toBeSigned = utils.concatArrays(PROGRAM_TAG, this.logic);
176
203
 
177
- if (!this.sig && !this.msig && !this.lmsig) {
204
+ if (!this.sig && !this.msig && !this.lmsig && !this.pqsig) {
178
205
  const hash = nacl.genericHash(toBeSigned);
179
206
  return utils.arrayEqual(hash, publicKey);
180
207
  }
181
208
 
209
+ if (this.pqsig) {
210
+ // This function has no way to validate a post-quantum signature, so it
211
+ // cannot report success here. Callers that need to sign a transaction
212
+ // with a PQ delegated LogicSig should go through
213
+ // signLogicSigTransactionObject, which skips this check.
214
+ return false;
215
+ }
216
+
182
217
  if (this.sig) {
183
218
  return nacl.verify(toBeSigned, this.sig, publicKey);
184
219
  }
@@ -190,7 +225,7 @@ export class LogicSig implements encoding.Encodable {
190
225
  pks: this.lmsig.subsig.map((subsig) => subsig.pk),
191
226
  });
192
227
  const lmsigProgram = utils.concatArrays(
193
- multisigProgramTag,
228
+ MSIG_PROGRAM_TAG,
194
229
  multisigAddr.publicKey,
195
230
  this.logic
196
231
  );
@@ -209,12 +244,14 @@ export class LogicSig implements encoding.Encodable {
209
244
  * @returns String representation of the address
210
245
  */
211
246
  address(): Address {
212
- const toBeSigned = utils.concatArrays(programTag, this.logic);
247
+ const toBeSigned = utils.concatArrays(PROGRAM_TAG, this.logic);
213
248
  const hash = nacl.genericHash(toBeSigned);
214
249
  return new Address(Uint8Array.from(hash));
215
250
  }
216
251
 
217
252
  /**
253
+ * @deprecated Use `signWithSigner` instead
254
+ *
218
255
  * Creates signature (if no msig provided) or multi signature otherwise
219
256
  * @param secretKey - Secret key to sign with
220
257
  * @param msig - Multisig account as \{version, threshold, addrs\}
@@ -237,6 +274,81 @@ export class LogicSig implements encoding.Encodable {
237
274
  }
238
275
 
239
276
  /**
277
+ * Signs this LogicSig for delegation using the given signer.
278
+ *
279
+ * @param signer - The signer to delegate to
280
+ * @param msig - Optional multisig account the signer is a subsigner of
281
+ * @returns The address the signer signed as. When `msig` is omitted this is
282
+ * the delegating account. When `msig` is given it is the individual
283
+ * subsigner, not the multisig, so the delegating account is
284
+ * `multisigAddress(msig)`. Either way it is an authorizing address, which
285
+ * is not necessarily the address a signer sends transactions from.
286
+ *
287
+ * Re-signing an already-signed LogicSig is allowed, and replaces the previous
288
+ * delegation signature. At most one of `sig`, `msig`, `lmsig` and `pqsig` may
289
+ * be set, so any signature left over from an earlier call is cleared.
290
+ */
291
+ async signWithSigner(
292
+ signer: DelegatedLsigSigner,
293
+ msig?: MultisigMetadata
294
+ ): Promise<Address> {
295
+ const sigResult = await signer(this, msig);
296
+ if (msig == null) {
297
+ if ('pqsig' in sigResult && sigResult.pqsig) {
298
+ this.clearSignatures();
299
+ this.pqsig = sigResult.pqsig;
300
+ return sigResult.address;
301
+ }
302
+
303
+ if (!('sig' in sigResult) || !sigResult.sig) {
304
+ throw Error(
305
+ 'Expected DelegatedLsigSigner to return sig or pqsig, but both are undefined. If signing for an msig, be sure to pass the msig argument'
306
+ );
307
+ }
308
+ this.clearSignatures();
309
+ this.sig = sigResult.sig;
310
+ } else {
311
+ if (!('lmsig' in sigResult) || !sigResult.lmsig) {
312
+ throw Error(
313
+ 'Expected DelegatedLsigSigner to return lmsig, but lmsig is undefined. If signing for a single account, do not pass msig argument'
314
+ );
315
+ }
316
+ const { lmsig } = sigResult;
317
+ const expectedPks = pksFromAddresses(msig.addrs);
318
+ if (
319
+ lmsig.v !== msig.version ||
320
+ lmsig.thr !== msig.threshold ||
321
+ lmsig.subsig.length !== expectedPks.length ||
322
+ !lmsig.subsig.every((subsig, i) =>
323
+ utils.arrayEqual(subsig.pk, expectedPks[i])
324
+ )
325
+ ) {
326
+ throw Error(
327
+ 'DelegatedLsigSigner returned an lmsig whose version, threshold or public keys do not match the requested multisig'
328
+ );
329
+ }
330
+
331
+ this.clearSignatures();
332
+ this.lmsig = sigResult.lmsig;
333
+ }
334
+
335
+ return sigResult.address;
336
+ }
337
+
338
+ /**
339
+ * Removes every delegation signature from this LogicSig, so that exactly one
340
+ * of them can be set afterwards.
341
+ */
342
+ private clearSignatures() {
343
+ this.sig = undefined;
344
+ this.msig = undefined;
345
+ this.lmsig = undefined;
346
+ this.pqsig = undefined;
347
+ }
348
+
349
+ /**
350
+ * @deprecated Use `appendToMultisigWithSigner` instead
351
+ *
240
352
  * Appends a signature to multi signature
241
353
  * @param secretKey - Secret key to sign with
242
354
  */
@@ -248,12 +360,71 @@ export class LogicSig implements encoding.Encodable {
248
360
  this.lmsig.subsig[index].s = sig;
249
361
  }
250
362
 
363
+ async appendToMultisigWithSigner(signer: DelegatedLsigSigner) {
364
+ if (this.lmsig === undefined) {
365
+ throw new Error('no multisig present');
366
+ }
367
+
368
+ const sigResult = await signer(this, {
369
+ version: this.lmsig.v,
370
+ threshold: this.lmsig.thr,
371
+ addrs: this.lmsig.subsig.map((s) => new Address(s.pk)),
372
+ });
373
+
374
+ if (!('lmsig' in sigResult) || !sigResult.lmsig) {
375
+ throw Error(
376
+ 'Expected DelegatedLsigSigner to return lmsig, but lmsig is undefined'
377
+ );
378
+ }
379
+ if (
380
+ sigResult.lmsig.v !== this.lmsig.v ||
381
+ sigResult.lmsig.thr !== this.lmsig.thr
382
+ ) {
383
+ throw Error(
384
+ 'DelegatedLsigSigner returned an lmsig whose version or threshold does not match the current msig'
385
+ );
386
+ }
387
+
388
+ let signaturesReturned = false;
389
+ for (const subsig of sigResult.lmsig.subsig) {
390
+ if (subsig.s) {
391
+ signaturesReturned = true;
392
+ const thisSubsig = this.lmsig.subsig.find((s) =>
393
+ utils.arrayEqual(s.pk, subsig.pk)
394
+ );
395
+ if (thisSubsig === undefined) {
396
+ throw Error(
397
+ `DelegatedLsigSigner returned a signature for ${new Address(subsig.pk)} but this pk is not in the current msig`
398
+ );
399
+ }
400
+ // Never let the signer silently replace a signature already collected
401
+ // from another member.
402
+ if (thisSubsig.s && !utils.arrayEqual(thisSubsig.s, subsig.s)) {
403
+ throw Error(
404
+ `DelegatedLsigSigner returned a signature for ${new Address(subsig.pk)} that conflicts with the signature already collected for it`
405
+ );
406
+ }
407
+ thisSubsig.s = subsig.s;
408
+ }
409
+ }
410
+
411
+ if (!signaturesReturned) {
412
+ throw Error('DelegatedLsigSigner returned an lmsig with no signatures');
413
+ }
414
+ }
415
+
416
+ /**
417
+ * @deprecated Use `signWithSigner` followed by `.sig` instead
418
+ */
251
419
  signProgram(secretKey: Uint8Array) {
252
- const toBeSigned = utils.concatArrays(programTag, this.logic);
420
+ const toBeSigned = utils.concatArrays(PROGRAM_TAG, this.logic);
253
421
  const sig = nacl.sign(toBeSigned, secretKey);
254
422
  return sig;
255
423
  }
256
424
 
425
+ /**
426
+ * @deprecated Use `signWithSigner` followed by `.sig` instead
427
+ */
257
428
  signProgramMultisig(secretKey: Uint8Array, msig: EncodedMultisig) {
258
429
  const multisigAddr = addressFromMultisigPreImg({
259
430
  version: msig.v,
@@ -261,7 +432,7 @@ export class LogicSig implements encoding.Encodable {
261
432
  pks: msig.subsig.map((subsig) => subsig.pk),
262
433
  });
263
434
  const toBeSigned = utils.concatArrays(
264
- multisigProgramTag,
435
+ MSIG_PROGRAM_TAG,
265
436
  multisigAddr.publicKey,
266
437
  this.logic
267
438
  );
@@ -269,6 +440,9 @@ export class LogicSig implements encoding.Encodable {
269
440
  return sig;
270
441
  }
271
442
 
443
+ /**
444
+ * @deprecated Use `signWithSigner` followed by `.sig` instead
445
+ */
272
446
  singleSignMultisig(
273
447
  secretKey: Uint8Array,
274
448
  msig: EncodedMultisig
@@ -296,6 +470,17 @@ export class LogicSig implements encoding.Encodable {
296
470
  static fromByte(encoded: ArrayLike<any>): LogicSig {
297
471
  return encoding.decodeMsgpack(encoded, LogicSig);
298
472
  }
473
+
474
+ /**
475
+ * Signs arbitrary data for use with the `ed25519verify` opcode from within
476
+ * this LogicSig's program.
477
+ *
478
+ * @param signer - The signer to sign the data with
479
+ * @param data - The data to sign
480
+ */
481
+ async signDataWithSigner(signer: ProgramDataSigner, data: Uint8Array) {
482
+ return signer(data, this);
483
+ }
299
484
  }
300
485
 
301
486
  /**
@@ -379,10 +564,18 @@ export class LogicSigAccount implements encoding.Encodable {
379
564
  * To verify the delegation signature, use `verify`.
380
565
  */
381
566
  isDelegated() {
382
- return !!(this.lsig.sig || this.lsig.msig || this.lsig.lmsig);
567
+ return !!(
568
+ this.lsig.sig ||
569
+ this.lsig.msig ||
570
+ this.lsig.lmsig ||
571
+ this.lsig.pqsig
572
+ );
383
573
  }
384
574
 
385
575
  /**
576
+ * @deprecated This function does not perform full verification and should not be fully trusted on its own.
577
+ * For example, it does not evaluate programs and does not have the ability to validate PQ signatures.
578
+ *
386
579
  * Verifies this LogicSig's program and signatures.
387
580
  * @returns true if and only if the LogicSig program and signatures are valid.
388
581
  */
@@ -401,15 +594,31 @@ export class LogicSigAccount implements encoding.Encodable {
401
594
  * escrow address that is the hash of the LogicSig's program code.
402
595
  */
403
596
  address(): Address {
404
- const sigCount = [this.lsig.sig, this.lsig.msig, this.lsig.lmsig].filter(
405
- Boolean
406
- ).length;
597
+ const sigCount = [
598
+ this.lsig.sig,
599
+ this.lsig.msig,
600
+ this.lsig.lmsig,
601
+ this.lsig.pqsig,
602
+ ].filter(Boolean).length;
407
603
  if (sigCount > 1) {
408
604
  throw new Error(
409
- 'LogicSig has too many signatures. At most one of sig, msig, or lmsig may be present'
605
+ 'LogicSig has too many signatures. At most one of sig, msig, lmsig, or pqsig may be present'
410
606
  );
411
607
  }
412
608
 
609
+ if (this.lsig.pqsig) {
610
+ // A PQ signature carries the scheme, salt and public key of the
611
+ // delegating account, so derive the address rather than trusting
612
+ // `sigkey`. Also throws if the signature is not self-consistent.
613
+ const derived = addressFromPQSig(this.lsig.pqsig);
614
+ if (this.sigkey && !utils.arrayEqual(this.sigkey, derived.publicKey)) {
615
+ throw new Error(
616
+ `Signing key for delegated account does not match the PQ signature. The signature authorizes ${derived}, but sigkey is ${new Address(this.sigkey)}`
617
+ );
618
+ }
619
+ return derived;
620
+ }
621
+
413
622
  if (this.lsig.sig) {
414
623
  if (!this.sigkey) {
415
624
  throw new Error('Signing key for delegated account is missing');
@@ -431,6 +640,8 @@ export class LogicSigAccount implements encoding.Encodable {
431
640
  }
432
641
 
433
642
  /**
643
+ * @deprecated Use `signMultisigWithSigner` instead
644
+ *
434
645
  * Turns this LogicSigAccount into a delegated LogicSig. This type of LogicSig
435
646
  * has the authority to sign transactions on behalf of another account, called
436
647
  * the delegating account. Use this function if the delegating account is a
@@ -445,7 +656,16 @@ export class LogicSigAccount implements encoding.Encodable {
445
656
  this.lsig.sign(secretKey, msig);
446
657
  }
447
658
 
659
+ async signMultisigWithSigner(
660
+ msig: MultisigMetadata,
661
+ signer: DelegatedLsigSigner
662
+ ) {
663
+ await this.lsig.signWithSigner(signer, msig);
664
+ }
665
+
448
666
  /**
667
+ * @deprecated Use appendToMultisigWithSigner
668
+ *
449
669
  * Adds an additional signature from a member of the delegating multisig
450
670
  * account.
451
671
  *
@@ -456,7 +676,13 @@ export class LogicSigAccount implements encoding.Encodable {
456
676
  this.lsig.appendToMultisig(secretKey);
457
677
  }
458
678
 
679
+ async appendToMultisigWithSigner(signer: DelegatedLsigSigner) {
680
+ await this.lsig.appendToMultisigWithSigner(signer);
681
+ }
682
+
459
683
  /**
684
+ * @deprecated Use `signWithSigner` instead
685
+ *
460
686
  * Turns this LogicSigAccount into a delegated LogicSig. This type of LogicSig
461
687
  * has the authority to sign transactions on behalf of another account, called
462
688
  * the delegating account. If the delegating account is a multisig account,
@@ -468,6 +694,22 @@ export class LogicSigAccount implements encoding.Encodable {
468
694
  this.lsig.sign(secretKey);
469
695
  this.sigkey = nacl.keyPairFromSecretKey(secretKey).publicKey;
470
696
  }
697
+
698
+ /**
699
+ * Turns this LogicSigAccount into a delegated LogicSig, signed by the given
700
+ * signer. If the delegating account is a multisig account, use
701
+ * `signMultisigWithSigner` instead.
702
+ *
703
+ * @param signer - The signer of the delegating account.
704
+ */
705
+ async signWithSigner(signer: DelegatedLsigSigner) {
706
+ // Record the address the signer reports rather than any sending address it
707
+ // may advertise: the latter is the address the signer sends transactions
708
+ // from, which for a rekeyed account is not the account that authorizes
709
+ // this delegation.
710
+ const delegatingAddress = await this.lsig.signWithSigner(signer);
711
+ this.sigkey = delegatingAddress.publicKey;
712
+ }
471
713
  }
472
714
 
473
715
  /**
@@ -478,7 +720,7 @@ export function logicSigFromByte(encoded: Uint8Array): LogicSig {
478
720
  return encoding.decodeMsgpack(encoded, LogicSig);
479
721
  }
480
722
 
481
- const SIGN_PROGRAM_DATA_PREFIX = new TextEncoder().encode('ProgData');
723
+ export const SIGN_PROGRAM_DATA_PREFIX = new TextEncoder().encode('ProgData');
482
724
 
483
725
  /**
484
726
  * tealSign creates a signature compatible with ed25519verify opcode from program hash
package/src/main.ts CHANGED
@@ -1,68 +1,9 @@
1
- import * as nacl from './nacl/naclWrappers.js';
2
- import { Address } from './encoding/address.js';
3
- import { Transaction } from './transaction.js';
4
1
  import * as convert from './convert.js';
5
- import * as utils from './utils/utils.js';
6
-
7
- const SIGN_BYTES_PREFIX = Uint8Array.from([77, 88]); // "MX"
8
2
 
9
3
  // Errors
10
4
  export const MULTISIG_BAD_SENDER_ERROR_MSG =
11
5
  'The transaction sender address and multisig preimage do not match.';
12
6
 
13
- /**
14
- * signTransaction takes an object with either payment or key registration fields and
15
- * a secret key and returns a signed blob.
16
- *
17
- * Payment transaction fields: from, to, amount, fee, firstValid, lastValid, genesisHash,
18
- * note(optional), GenesisID(optional), closeRemainderTo(optional)
19
- *
20
- * Key registration fields: fee, firstValid, lastValid, voteKey, selectionKey, voteFirst,
21
- * voteLast, voteKeyDilution, genesisHash, note(optional), GenesisID(optional)
22
- *
23
- * If flatFee is not set and the final calculated fee is lower than the protocol minimum fee, the fee will be increased to match the minimum.
24
- * @param txn - object with either payment or key registration fields
25
- * @param sk - Algorand Secret Key
26
- * @returns object contains the binary signed transaction and its txID
27
- */
28
- export function signTransaction(txn: Transaction, sk: Uint8Array) {
29
- return {
30
- txID: txn.txID(),
31
- blob: txn.signTxn(sk),
32
- };
33
- }
34
-
35
- /**
36
- * signBytes takes arbitrary bytes and a secret key, prepends the bytes with "MX" for domain separation, signs the bytes
37
- * with the private key, and returns the signature.
38
- * @param bytes - Uint8array
39
- * @param sk - Algorand secret key
40
- * @returns binary signature
41
- */
42
- export function signBytes(bytes: Uint8Array, sk: Uint8Array) {
43
- const toBeSigned = utils.concatArrays(SIGN_BYTES_PREFIX, bytes);
44
- const sig = nacl.sign(toBeSigned, sk);
45
- return sig;
46
- }
47
-
48
- /**
49
- * verifyBytes takes array of bytes, an address, and a signature and verifies if the signature is correct for the public
50
- * key and the bytes (the bytes should have been signed with "MX" prepended for domain separation).
51
- * @param bytes - Uint8Array
52
- * @param signature - binary signature
53
- * @param addr - string address
54
- * @returns bool
55
- */
56
- export function verifyBytes(
57
- bytes: Uint8Array,
58
- signature: Uint8Array,
59
- addr: string | Address
60
- ) {
61
- const toBeVerified = utils.concatArrays(SIGN_BYTES_PREFIX, bytes);
62
- const addrObj = typeof addr === 'string' ? Address.fromString(addr) : addr;
63
- return nacl.verify(toBeVerified, signature, addrObj.publicKey);
64
- }
65
-
66
7
  export const ERROR_MULTISIG_BAD_SENDER = new Error(
67
8
  MULTISIG_BAD_SENDER_ERROR_MSG
68
9
  );
@@ -109,6 +50,10 @@ export {
109
50
  encodeAddress,
110
51
  decodeAddress,
111
52
  getApplicationAddress,
53
+ addressFromPQKey,
54
+ addressFromPQSig,
55
+ PQ_SCHEME_SIZE,
56
+ PQ_SALT_MAX,
112
57
  ALGORAND_ZERO_ADDRESS_STRING,
113
58
  } from './encoding/address.js';
114
59
  export { bytesToBigInt, bigIntToBytes } from './encoding/bigint.js';
@@ -136,6 +81,7 @@ export {
136
81
  mnemonicToSecretKey,
137
82
  seedFromMnemonic,
138
83
  mnemonicFromSeed,
84
+ pq25WordMnemonicToSeed,
139
85
  } from './mnemonic/mnemonic.js';
140
86
  export {
141
87
  microalgosToAlgos,
@@ -149,6 +95,11 @@ export {
149
95
  encodeUnsignedSimulateTransaction,
150
96
  } from './signedTransaction.js';
151
97
  export {
98
+ SIGN_BYTES_PREFIX,
99
+ signTransaction,
100
+ signTransactionWithSigner,
101
+ signBytes,
102
+ verifyBytes,
152
103
  signLogicSigTransaction,
153
104
  signLogicSigTransactionObject,
154
105
  } from './signing.js';
@@ -159,6 +110,10 @@ export {
159
110
  tealSign,
160
111
  tealSignFromProgram,
161
112
  verifyTealSign,
113
+ PROGRAM_TAG,
114
+ PQ_PROGRAM_TAG,
115
+ MSIG_PROGRAM_TAG,
116
+ SIGN_PROGRAM_DATA_PREFIX,
162
117
  } from './logicsig.js';
163
118
  export {
164
119
  MultisigMetadata,
@@ -171,6 +126,8 @@ export {
171
126
  appendSignMultisigTransaction,
172
127
  createMultisigTransaction,
173
128
  appendSignRawMultisigSignature,
129
+ signMultisigTransactionWithSigner,
130
+ appendSignMultisigTransactionWithSigner,
174
131
  } from './multisigSigning.js';
175
132
  export {
176
133
  ProgramSourceMap,
@@ -178,7 +135,20 @@ export {
178
135
  PcLineLocation,
179
136
  } from './logic/sourcemap.js';
180
137
 
181
- export * from './dryrun.js';
138
+ export {
139
+ Ed25519SigningKey,
140
+ addressWithSignersFromRawEd25519Signer,
141
+ } from './ed25519-signer.js';
142
+ export {
143
+ FALCON_1024_SCHEME,
144
+ Falcon1024SigningKey,
145
+ addressWithSignersFromRawFalcon1024Signer,
146
+ } from './falcon-signer.js';
147
+ export {
148
+ PQSigningKey,
149
+ addressWithSignersFromRawPQSigner,
150
+ } from './pq-signer.js';
151
+
182
152
  export * from './makeTxn.js';
183
153
  export * from './transaction.js';
184
154
  export * from './signer.js';
@@ -1,8 +1,9 @@
1
1
  /* eslint-disable no-bitwise */
2
2
  import english from './wordlists/english.js';
3
3
  import * as nacl from '../nacl/naclWrappers.js';
4
- import { Address } from '../encoding/address.js';
4
+ import { Address, PQ_SCHEME_SIZE } from '../encoding/address.js';
5
5
  import Account from '../types/account.js';
6
+ import { concatArrays } from '../utils/utils.js';
6
7
 
7
8
  export const FAIL_TO_DECODE_MNEMONIC_ERROR_MSG = 'failed to decode mnemonic';
8
9
  export const NOT_IN_WORDS_LIST_ERROR_MSG =
@@ -179,3 +180,35 @@ export function mnemonicToMasterDerivationKey(mn: string) {
179
180
  export function masterDerivationKeyToMnemonic(mdk: Uint8Array) {
180
181
  return mnemonicFromSeed(mdk);
181
182
  }
183
+
184
+ /**
185
+ * The domain-separation prefix prepended to a post-quantum key seed preimage
186
+ * before hashing. Matches go-algorand's protocol.PostQuantumKey HashID.
187
+ */
188
+ const PQ_KEY_PREFIX = new TextEncoder().encode('PQK');
189
+
190
+ /**
191
+ * pq25WordMnemonicToSeed derives a post-quantum key seed from a standard 25-word
192
+ * Algorand mnemonic.
193
+ *
194
+ * The seed is domain-separated by the PQ scheme, so the same mnemonic yields a
195
+ * different key for each scheme, and a different key again from the ed25519
196
+ * account that `mnemonicToSecretKey` derives from it.
197
+ *
198
+ * @param mn - A 25-word Algorand mnemonic
199
+ * @param scheme - The 2-byte ASCII PQ scheme identifier (e.g. "f1" for Falcon-1024)
200
+ * @returns The 32-byte seed to hand to the scheme's key generator
201
+ */
202
+ export function pq25WordMnemonicToSeed(
203
+ mn: string,
204
+ scheme: Uint8Array
205
+ ): Uint8Array {
206
+ if (scheme.length !== PQ_SCHEME_SIZE) {
207
+ throw new Error(
208
+ `invalid PQ scheme length: expected ${PQ_SCHEME_SIZE} bytes, got ${scheme.length}`
209
+ );
210
+ }
211
+ return new Uint8Array(
212
+ nacl.genericHash(concatArrays(PQ_KEY_PREFIX, scheme, seedFromMnemonic(mn)))
213
+ );
214
+ }