algosdk 3.7.0-beta.1 → 3.8.0
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/README.md +4 -4
- package/dist/browser/algosdk.min.js +1 -1
- package/dist/browser/algosdk.min.js.map +1 -1
- package/dist/cjs/appAccess.js +4 -0
- package/dist/cjs/appAccess.js.map +1 -1
- package/dist/cjs/client/v2/algod/getPeers.js +20 -0
- package/dist/cjs/client/v2/algod/getPeers.js.map +1 -0
- package/dist/cjs/client/v2/algod/models/types.js +153 -5
- package/dist/cjs/client/v2/algod/models/types.js.map +1 -1
- package/dist/cjs/client/v2/indexer/models/types.js +163 -12
- package/dist/cjs/client/v2/indexer/models/types.js.map +1 -1
- package/dist/cjs/composer.js +4 -6
- package/dist/cjs/composer.js.map +1 -1
- package/dist/cjs/ed25519-signer.js +18 -0
- package/dist/cjs/ed25519-signer.js.map +1 -1
- package/dist/cjs/encoding/address.js +9 -0
- package/dist/cjs/encoding/address.js.map +1 -1
- package/dist/cjs/falcon-signer.js +16 -0
- package/dist/cjs/falcon-signer.js.map +1 -1
- package/dist/cjs/heartbeat.js +7 -0
- package/dist/cjs/heartbeat.js.map +1 -1
- package/dist/cjs/logicsig.js +86 -6
- package/dist/cjs/logicsig.js.map +1 -1
- package/dist/cjs/makeTxn.js +11 -2
- package/dist/cjs/makeTxn.js.map +1 -1
- package/dist/cjs/mnemonic/mnemonic.js +2 -0
- package/dist/cjs/mnemonic/mnemonic.js.map +1 -1
- package/dist/cjs/pq-signer.js +51 -0
- package/dist/cjs/pq-signer.js.map +1 -1
- package/dist/cjs/signer.js.map +1 -1
- package/dist/cjs/signing.js +22 -0
- package/dist/cjs/signing.js.map +1 -1
- package/dist/cjs/transaction.js +8 -0
- package/dist/cjs/transaction.js.map +1 -1
- package/dist/cjs/types/block.js +28 -0
- package/dist/cjs/types/block.js.map +1 -1
- package/dist/cjs/types/statedelta.js +17 -0
- package/dist/cjs/types/statedelta.js.map +1 -1
- package/dist/cjs/utils/utils.js +14 -1
- package/dist/cjs/utils/utils.js.map +1 -1
- package/dist/esm/appAccess.js +4 -0
- package/dist/esm/appAccess.js.map +1 -1
- package/dist/esm/client/v2/algod/getPeers.js +14 -0
- package/dist/esm/client/v2/algod/getPeers.js.map +1 -0
- package/dist/esm/client/v2/algod/models/types.js +149 -3
- package/dist/esm/client/v2/algod/models/types.js.map +1 -1
- package/dist/esm/client/v2/indexer/models/types.js +161 -11
- package/dist/esm/client/v2/indexer/models/types.js.map +1 -1
- package/dist/esm/composer.js +4 -6
- package/dist/esm/composer.js.map +1 -1
- package/dist/esm/ed25519-signer.js +18 -0
- package/dist/esm/ed25519-signer.js.map +1 -1
- package/dist/esm/encoding/address.js +9 -0
- package/dist/esm/encoding/address.js.map +1 -1
- package/dist/esm/falcon-signer.js +16 -0
- package/dist/esm/falcon-signer.js.map +1 -1
- package/dist/esm/heartbeat.js +8 -1
- package/dist/esm/heartbeat.js.map +1 -1
- package/dist/esm/logicsig.js +86 -6
- package/dist/esm/logicsig.js.map +1 -1
- package/dist/esm/makeTxn.js +11 -2
- package/dist/esm/makeTxn.js.map +1 -1
- package/dist/esm/mnemonic/mnemonic.js +2 -0
- package/dist/esm/mnemonic/mnemonic.js.map +1 -1
- package/dist/esm/pq-signer.js +51 -0
- package/dist/esm/pq-signer.js.map +1 -1
- package/dist/esm/signer.js.map +1 -1
- package/dist/esm/signing.js +22 -0
- package/dist/esm/signing.js.map +1 -1
- package/dist/esm/transaction.js +8 -0
- package/dist/esm/transaction.js.map +1 -1
- package/dist/esm/types/block.js +28 -0
- package/dist/esm/types/block.js.map +1 -1
- package/dist/esm/types/statedelta.js +17 -0
- package/dist/esm/types/statedelta.js.map +1 -1
- package/dist/esm/utils/utils.js +12 -0
- package/dist/esm/utils/utils.js.map +1 -1
- package/dist/types/client/v2/algod/getPeers.d.ts +7 -0
- package/dist/types/client/v2/algod/models/types.d.ts +90 -3
- package/dist/types/client/v2/indexer/models/types.d.ts +114 -7
- package/dist/types/composer.d.ts +3 -3
- package/dist/types/ed25519-signer.d.ts +29 -0
- package/dist/types/encoding/address.d.ts +9 -0
- package/dist/types/falcon-signer.d.ts +29 -2
- package/dist/types/heartbeat.d.ts +2 -0
- package/dist/types/logicsig.d.ts +91 -6
- package/dist/types/makeTxn.d.ts +8 -2
- package/dist/types/mnemonic/mnemonic.d.ts +2 -0
- package/dist/types/pq-signer.d.ts +39 -2
- package/dist/types/signer.d.ts +76 -5
- package/dist/types/signing.d.ts +22 -0
- package/dist/types/transaction.d.ts +1 -0
- package/dist/types/types/block.d.ts +22 -0
- package/dist/types/types/statedelta.d.ts +18 -0
- package/dist/types/types/transactions/base.d.ts +10 -0
- package/dist/types/utils/utils.d.ts +1 -0
- package/package.json +2 -2
- package/src/appAccess.ts +5 -0
- package/src/client/v2/algod/models/types.ts +234 -0
- package/src/client/v2/indexer/models/types.ts +280 -8
- package/src/composer.ts +7 -11
- package/src/ed25519-signer.ts +29 -0
- package/src/encoding/address.ts +9 -0
- package/src/falcon-signer.ts +31 -1
- package/src/heartbeat.ts +11 -0
- package/src/logicsig.ts +93 -6
- package/src/makeTxn.ts +13 -4
- package/src/mnemonic/mnemonic.ts +2 -0
- package/src/pq-signer.ts +71 -1
- package/src/signer.ts +77 -5
- package/src/signing.ts +22 -0
- package/src/transaction.ts +10 -0
- package/src/types/block.ts +54 -0
- package/src/types/statedelta.ts +34 -0
- package/src/types/transactions/base.ts +11 -0
- package/src/utils/utils.ts +13 -0
package/src/encoding/address.ts
CHANGED
|
@@ -204,9 +204,16 @@ export function getApplicationAddress(appID: number | bigint): Address {
|
|
|
204
204
|
* Derive a post-quantum (PQ) account address together with the canonical salt
|
|
205
205
|
* used to derive it.
|
|
206
206
|
*
|
|
207
|
+
* @remarks
|
|
208
|
+
* The salt is found by rejection sampling: it is the lowest value whose
|
|
209
|
+
* preimage hashes to something that could not also be an Ed25519 public key, so
|
|
210
|
+
* that a PQ account can never collide with an Ed25519 one.
|
|
211
|
+
*
|
|
207
212
|
* @param schemeBytes - The 2-byte ASCII PQ scheme identifier (e.g. "f1" for Falcon-1024).
|
|
208
213
|
* @param key - The scheme's canonical public key.
|
|
209
214
|
* @returns The derived Address and the canonical 1-byte salt.
|
|
215
|
+
* @throws If `schemeBytes` is not exactly {@link PQ_SCHEME_SIZE} bytes, or in
|
|
216
|
+
* the ~2^-256 case where no salt in range yields a valid address.
|
|
210
217
|
*/
|
|
211
218
|
export function addressFromPQKey(
|
|
212
219
|
schemeBytes: Uint8Array,
|
|
@@ -248,6 +255,8 @@ export function addressFromPQKey(
|
|
|
248
255
|
*
|
|
249
256
|
* @param pqsig - The post-quantum signature to derive the address from.
|
|
250
257
|
* @returns The address of the account the signature authorizes.
|
|
258
|
+
* @throws If the signature's scheme is malformed, or if its salt is not the
|
|
259
|
+
* canonical one for its scheme and public key.
|
|
251
260
|
*/
|
|
252
261
|
export function addressFromPQSig(pqsig: EncodedPQSig): Address {
|
|
253
262
|
const { address, salt } = addressFromPQKey(pqsig.sch, pqsig.pk);
|
package/src/falcon-signer.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Address } from './encoding/address.js';
|
|
2
2
|
import {
|
|
3
3
|
AddressWithDelegatedLsigSigner,
|
|
4
|
+
AddressWithEmptyTransactionSigner,
|
|
4
5
|
AddressWithTransactionSigner,
|
|
5
6
|
} from './signer.js';
|
|
6
7
|
import { addressWithSignersFromRawPQSigner } from './pq-signer.js';
|
|
@@ -10,15 +11,44 @@ import { addressWithSignersFromRawPQSigner } from './pq-signer.js';
|
|
|
10
11
|
*/
|
|
11
12
|
export const FALCON_1024_SCHEME = new TextEncoder().encode('f1');
|
|
12
13
|
|
|
14
|
+
/**
|
|
15
|
+
* A Falcon-1024 public key paired with a function that signs raw bytes with the
|
|
16
|
+
* corresponding secret key.
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* `falcon1024Signer` receives the exact bytes to sign, with every
|
|
20
|
+
* domain-separation prefix already applied, so it can be backed by a key that
|
|
21
|
+
* never leaves a wallet, HSM or hardware device.
|
|
22
|
+
*/
|
|
13
23
|
export interface Falcon1024SigningKey {
|
|
24
|
+
/** The Falcon-1024 public key. */
|
|
14
25
|
falcon1024PublicKey: Uint8Array;
|
|
26
|
+
/** Signs the given bytes verbatim with the corresponding secret key. */
|
|
15
27
|
falcon1024Signer: (bytesToSign: Uint8Array) => Promise<Uint8Array>;
|
|
16
28
|
}
|
|
17
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Build the full set of signers for a Falcon-1024 key from a function that
|
|
32
|
+
* signs raw bytes with it.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* A thin wrapper around {@link addressWithSignersFromRawPQSigner} that supplies
|
|
36
|
+
* the {@link FALCON_1024_SCHEME} identifier, so see that function for the
|
|
37
|
+
* details and limitations of post-quantum signing.
|
|
38
|
+
*
|
|
39
|
+
* @param falconSigningKey - The public key and raw signing function to build the signers from
|
|
40
|
+
* @param sendingAddress - The address transactions are sent from. Defaults to
|
|
41
|
+
* the derived Falcon-1024 address; supply it when this key is the auth
|
|
42
|
+
* address of a rekeyed account.
|
|
43
|
+
* @returns An address bundled with transaction, empty transaction and delegated
|
|
44
|
+
* LogicSig signers
|
|
45
|
+
*/
|
|
18
46
|
export function addressWithSignersFromRawFalcon1024Signer(
|
|
19
47
|
falconSigningKey: Falcon1024SigningKey,
|
|
20
48
|
sendingAddress?: Address
|
|
21
|
-
): AddressWithTransactionSigner &
|
|
49
|
+
): AddressWithTransactionSigner &
|
|
50
|
+
AddressWithDelegatedLsigSigner &
|
|
51
|
+
AddressWithEmptyTransactionSigner {
|
|
22
52
|
return addressWithSignersFromRawPQSigner(
|
|
23
53
|
{
|
|
24
54
|
pqScheme: FALCON_1024_SCHEME,
|
package/src/heartbeat.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Address } from './encoding/address.js';
|
|
|
2
2
|
import { Encodable, Schema } from './encoding/encoding.js';
|
|
3
3
|
import {
|
|
4
4
|
AddressSchema,
|
|
5
|
+
BooleanSchema,
|
|
5
6
|
Uint64Schema,
|
|
6
7
|
ByteArraySchema,
|
|
7
8
|
FixedLengthByteArraySchema,
|
|
@@ -111,6 +112,10 @@ export class Heartbeat implements Encodable {
|
|
|
111
112
|
key: 'kd', // HbKeyDilution
|
|
112
113
|
valueSchema: new Uint64Schema(),
|
|
113
114
|
},
|
|
115
|
+
{
|
|
116
|
+
key: 'c', // HbChallengeDiscount
|
|
117
|
+
valueSchema: new BooleanSchema(),
|
|
118
|
+
},
|
|
114
119
|
])
|
|
115
120
|
);
|
|
116
121
|
|
|
@@ -124,18 +129,22 @@ export class Heartbeat implements Encodable {
|
|
|
124
129
|
|
|
125
130
|
public keyDilution: bigint;
|
|
126
131
|
|
|
132
|
+
public challengeDiscount: boolean;
|
|
133
|
+
|
|
127
134
|
public constructor(params: {
|
|
128
135
|
address: Address;
|
|
129
136
|
proof: HeartbeatProof;
|
|
130
137
|
seed: Uint8Array;
|
|
131
138
|
voteID: Uint8Array;
|
|
132
139
|
keyDilution: bigint;
|
|
140
|
+
challengeDiscount?: boolean;
|
|
133
141
|
}) {
|
|
134
142
|
this.address = params.address;
|
|
135
143
|
this.proof = params.proof;
|
|
136
144
|
this.seed = params.seed;
|
|
137
145
|
this.voteID = params.voteID;
|
|
138
146
|
this.keyDilution = params.keyDilution;
|
|
147
|
+
this.challengeDiscount = params.challengeDiscount ?? false;
|
|
139
148
|
}
|
|
140
149
|
|
|
141
150
|
// eslint-disable-next-line class-methods-use-this
|
|
@@ -150,6 +159,7 @@ export class Heartbeat implements Encodable {
|
|
|
150
159
|
['sd', this.seed],
|
|
151
160
|
['vid', this.voteID],
|
|
152
161
|
['kd', this.keyDilution],
|
|
162
|
+
['c', this.challengeDiscount],
|
|
153
163
|
]);
|
|
154
164
|
}
|
|
155
165
|
|
|
@@ -163,6 +173,7 @@ export class Heartbeat implements Encodable {
|
|
|
163
173
|
seed: data.get('sd'),
|
|
164
174
|
voteID: data.get('vid'),
|
|
165
175
|
keyDilution: data.get('kd'),
|
|
176
|
+
challengeDiscount: data.get('c'),
|
|
166
177
|
});
|
|
167
178
|
}
|
|
168
179
|
}
|
package/src/logicsig.ts
CHANGED
|
@@ -68,8 +68,22 @@ export function sanityCheckProgram(program: Uint8Array) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* The domain-separation prefix prepended to a program before it is hashed into
|
|
73
|
+
* an escrow address, or signed for delegation by a single ed25519 account.
|
|
74
|
+
*/
|
|
71
75
|
export const PROGRAM_TAG = new TextEncoder().encode('Program');
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The domain-separation prefix prepended to a post-quantum delegating account's
|
|
79
|
+
* address and a program before the program is signed for delegation.
|
|
80
|
+
*/
|
|
72
81
|
export const PQ_PROGRAM_TAG = new TextEncoder().encode('PQProgram');
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The domain-separation prefix prepended to a delegating multisig account's
|
|
85
|
+
* address and a program before the program is signed for delegation.
|
|
86
|
+
*/
|
|
73
87
|
export const MSIG_PROGRAM_TAG = new TextEncoder().encode('MsigProgram');
|
|
74
88
|
|
|
75
89
|
/**
|
|
@@ -112,6 +126,11 @@ export class LogicSig implements encoding.Encodable {
|
|
|
112
126
|
sig?: Uint8Array;
|
|
113
127
|
msig?: EncodedMultisig;
|
|
114
128
|
lmsig?: EncodedMultisig;
|
|
129
|
+
/**
|
|
130
|
+
* The post-quantum delegation signature, if the delegating account is a
|
|
131
|
+
* post-quantum account. At most one of `sig`, `msig`, `lmsig` and `pqsig` may
|
|
132
|
+
* be set.
|
|
133
|
+
*/
|
|
115
134
|
pqsig?: EncodedPQSig;
|
|
116
135
|
|
|
117
136
|
constructor(program: Uint8Array, programArgs?: Array<Uint8Array> | null) {
|
|
@@ -276,6 +295,11 @@ export class LogicSig implements encoding.Encodable {
|
|
|
276
295
|
/**
|
|
277
296
|
* Signs this LogicSig for delegation using the given signer.
|
|
278
297
|
*
|
|
298
|
+
* @remarks
|
|
299
|
+
* Re-signing an already-signed LogicSig is allowed, and replaces the previous
|
|
300
|
+
* delegation signature. At most one of `sig`, `msig`, `lmsig` and `pqsig` may
|
|
301
|
+
* be set, so any signature left over from an earlier call is cleared.
|
|
302
|
+
*
|
|
279
303
|
* @param signer - The signer to delegate to
|
|
280
304
|
* @param msig - Optional multisig account the signer is a subsigner of
|
|
281
305
|
* @returns The address the signer signed as. When `msig` is omitted this is
|
|
@@ -283,10 +307,9 @@ export class LogicSig implements encoding.Encodable {
|
|
|
283
307
|
* subsigner, not the multisig, so the delegating account is
|
|
284
308
|
* `multisigAddress(msig)`. Either way it is an authorizing address, which
|
|
285
309
|
* is not necessarily the address a signer sends transactions from.
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
* be set, so any signature left over from an earlier call is cleared.
|
|
310
|
+
* @throws If the signer returns a signature of the wrong kind for the
|
|
311
|
+
* requested delegation, or an `lmsig` whose version, threshold or public
|
|
312
|
+
* keys do not match `msig`
|
|
290
313
|
*/
|
|
291
314
|
async signWithSigner(
|
|
292
315
|
signer: DelegatedLsigSigner,
|
|
@@ -360,6 +383,24 @@ export class LogicSig implements encoding.Encodable {
|
|
|
360
383
|
this.lmsig.subsig[index].s = sig;
|
|
361
384
|
}
|
|
362
385
|
|
|
386
|
+
/**
|
|
387
|
+
* Appends an additional subsignature to this LogicSig's existing multisig
|
|
388
|
+
* delegation.
|
|
389
|
+
*
|
|
390
|
+
* @remarks
|
|
391
|
+
* The multisig preimage is taken from the `lmsig` already on this LogicSig,
|
|
392
|
+
* so {@link signWithSigner} must have been called with an `msig` argument
|
|
393
|
+
* first. The signer must hold a key belonging to that multisig.
|
|
394
|
+
*
|
|
395
|
+
* A signature already collected from another member is never silently
|
|
396
|
+
* replaced: if the signer returns a different signature for a subsig that is
|
|
397
|
+
* already filled in, this throws instead.
|
|
398
|
+
*
|
|
399
|
+
* @param signer - The signer to append a subsignature from
|
|
400
|
+
* @throws If there is no multisig on this LogicSig, if the signer returns no
|
|
401
|
+
* signature, a signature for a key outside the multisig, or one that
|
|
402
|
+
* conflicts with a signature already collected
|
|
403
|
+
*/
|
|
363
404
|
async appendToMultisigWithSigner(signer: DelegatedLsigSigner) {
|
|
364
405
|
if (this.lmsig === undefined) {
|
|
365
406
|
throw new Error('no multisig present');
|
|
@@ -475,8 +516,15 @@ export class LogicSig implements encoding.Encodable {
|
|
|
475
516
|
* Signs arbitrary data for use with the `ed25519verify` opcode from within
|
|
476
517
|
* this LogicSig's program.
|
|
477
518
|
*
|
|
519
|
+
* @remarks
|
|
520
|
+
* This does not modify the LogicSig or delegate it; the LogicSig is only used
|
|
521
|
+
* for the address that domain-separates the signature. The program is
|
|
522
|
+
* responsible for verifying the returned signature against the signer's
|
|
523
|
+
* public key.
|
|
524
|
+
*
|
|
478
525
|
* @param signer - The signer to sign the data with
|
|
479
526
|
* @param data - The data to sign
|
|
527
|
+
* @returns A promise which resolves to the raw signature over the data
|
|
480
528
|
*/
|
|
481
529
|
async signDataWithSigner(signer: ProgramDataSigner, data: Uint8Array) {
|
|
482
530
|
return signer(data, this);
|
|
@@ -656,6 +704,22 @@ export class LogicSigAccount implements encoding.Encodable {
|
|
|
656
704
|
this.lsig.sign(secretKey, msig);
|
|
657
705
|
}
|
|
658
706
|
|
|
707
|
+
/**
|
|
708
|
+
* Turns this LogicSigAccount into a delegated LogicSig, signed by one member
|
|
709
|
+
* of a delegating multisig account.
|
|
710
|
+
*
|
|
711
|
+
* @remarks
|
|
712
|
+
* This produces a LogicSig with a single subsignature filled in. Unless the
|
|
713
|
+
* multisig's threshold is 1, call {@link LogicSigAccount.appendToMultisigWithSigner}
|
|
714
|
+
* with the remaining members' signers before the LogicSig can authorize
|
|
715
|
+
* transactions.
|
|
716
|
+
*
|
|
717
|
+
* If the delegating account is not a multisig, use
|
|
718
|
+
* {@link LogicSigAccount.signWithSigner} instead.
|
|
719
|
+
*
|
|
720
|
+
* @param msig - The multisig delegating to this LogicSig
|
|
721
|
+
* @param signer - The signer of one member of `msig`
|
|
722
|
+
*/
|
|
659
723
|
async signMultisigWithSigner(
|
|
660
724
|
msig: MultisigMetadata,
|
|
661
725
|
signer: DelegatedLsigSigner
|
|
@@ -676,6 +740,16 @@ export class LogicSigAccount implements encoding.Encodable {
|
|
|
676
740
|
this.lsig.appendToMultisig(secretKey);
|
|
677
741
|
}
|
|
678
742
|
|
|
743
|
+
/**
|
|
744
|
+
* Adds an additional signature from a member of the delegating multisig
|
|
745
|
+
* account.
|
|
746
|
+
*
|
|
747
|
+
* @remarks
|
|
748
|
+
* {@link LogicSigAccount.signMultisigWithSigner} must have been called first
|
|
749
|
+
* to establish the multisig this signature belongs to.
|
|
750
|
+
*
|
|
751
|
+
* @param signer - The signer of another member of the delegating multisig account
|
|
752
|
+
*/
|
|
679
753
|
async appendToMultisigWithSigner(signer: DelegatedLsigSigner) {
|
|
680
754
|
await this.lsig.appendToMultisigWithSigner(signer);
|
|
681
755
|
}
|
|
@@ -697,8 +771,17 @@ export class LogicSigAccount implements encoding.Encodable {
|
|
|
697
771
|
|
|
698
772
|
/**
|
|
699
773
|
* Turns this LogicSigAccount into a delegated LogicSig, signed by the given
|
|
700
|
-
* signer.
|
|
701
|
-
*
|
|
774
|
+
* signer. This type of LogicSig has the authority to sign transactions on
|
|
775
|
+
* behalf of another account, called the delegating account.
|
|
776
|
+
*
|
|
777
|
+
* @remarks
|
|
778
|
+
* If the delegating account is a multisig account, use
|
|
779
|
+
* {@link LogicSigAccount.signMultisigWithSigner} instead.
|
|
780
|
+
*
|
|
781
|
+
* The delegating account is taken to be the address the signer reports having
|
|
782
|
+
* signed as, not any sending address the signer advertises: for a rekeyed
|
|
783
|
+
* account the latter is the address it sends transactions from, which is not
|
|
784
|
+
* the account authorizing this delegation.
|
|
702
785
|
*
|
|
703
786
|
* @param signer - The signer of the delegating account.
|
|
704
787
|
*/
|
|
@@ -720,6 +803,10 @@ export function logicSigFromByte(encoded: Uint8Array): LogicSig {
|
|
|
720
803
|
return encoding.decodeMsgpack(encoded, LogicSig);
|
|
721
804
|
}
|
|
722
805
|
|
|
806
|
+
/**
|
|
807
|
+
* The domain-separation prefix prepended, along with the program's address, to
|
|
808
|
+
* data signed for verification by the `ed25519verify` opcode.
|
|
809
|
+
*/
|
|
723
810
|
export const SIGN_PROGRAM_DATA_PREFIX = new TextEncoder().encode('ProgData');
|
|
724
811
|
|
|
725
812
|
/**
|
package/src/makeTxn.ts
CHANGED
|
@@ -539,7 +539,13 @@ export function makeApplicationCreateTxnFromObject({
|
|
|
539
539
|
}
|
|
540
540
|
|
|
541
541
|
/**
|
|
542
|
-
* Make a transaction that changes an application's approval and clear programs
|
|
542
|
+
* Make a transaction that changes an application's approval and clear programs.
|
|
543
|
+
*
|
|
544
|
+
* The application's global state schema and extra program pages may also be changed during an
|
|
545
|
+
* update by providing numGlobalInts, numGlobalByteSlices, and/or extraPages. The local state schema
|
|
546
|
+
* cannot be changed after application creation. If the pages or global schema increases in size, the entire
|
|
547
|
+
* MBR for the application will move to the sender of the update and that account will become the `sizeSponsor`
|
|
548
|
+
* in the application's parameters. A decrease in schema or pages does not affect MBR or `sizeSponsor`.
|
|
543
549
|
*
|
|
544
550
|
* @param options - Application update transaction parameters
|
|
545
551
|
*/
|
|
@@ -557,6 +563,9 @@ export function makeApplicationUpdateTxnFromObject({
|
|
|
557
563
|
access,
|
|
558
564
|
approvalProgram,
|
|
559
565
|
clearProgram,
|
|
566
|
+
numGlobalInts,
|
|
567
|
+
numGlobalByteSlices,
|
|
568
|
+
extraPages,
|
|
560
569
|
note,
|
|
561
570
|
lease,
|
|
562
571
|
rekeyTo,
|
|
@@ -566,9 +575,6 @@ export function makeApplicationUpdateTxnFromObject({
|
|
|
566
575
|
| 'onComplete'
|
|
567
576
|
| 'numLocalInts'
|
|
568
577
|
| 'numLocalByteSlices'
|
|
569
|
-
| 'numGlobalInts'
|
|
570
|
-
| 'numGlobalByteSlices'
|
|
571
|
-
| 'extraPages'
|
|
572
578
|
| 'approvalProgram'
|
|
573
579
|
| 'clearProgram'
|
|
574
580
|
> &
|
|
@@ -598,6 +604,9 @@ export function makeApplicationUpdateTxnFromObject({
|
|
|
598
604
|
access,
|
|
599
605
|
approvalProgram,
|
|
600
606
|
clearProgram,
|
|
607
|
+
numGlobalInts,
|
|
608
|
+
numGlobalByteSlices,
|
|
609
|
+
extraPages,
|
|
601
610
|
note,
|
|
602
611
|
lease,
|
|
603
612
|
rekeyTo,
|
package/src/mnemonic/mnemonic.ts
CHANGED
|
@@ -198,6 +198,8 @@ const PQ_KEY_PREFIX = new TextEncoder().encode('PQK');
|
|
|
198
198
|
* @param mn - A 25-word Algorand mnemonic
|
|
199
199
|
* @param scheme - The 2-byte ASCII PQ scheme identifier (e.g. "f1" for Falcon-1024)
|
|
200
200
|
* @returns The 32-byte seed to hand to the scheme's key generator
|
|
201
|
+
* @throws If `mn` is not a valid 25-word mnemonic, or if `scheme` is not
|
|
202
|
+
* exactly {@link PQ_SCHEME_SIZE} bytes
|
|
201
203
|
*/
|
|
202
204
|
export function pq25WordMnemonicToSeed(
|
|
203
205
|
mn: string,
|
package/src/pq-signer.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { MultisigMetadata } from './multisig.js';
|
|
|
5
5
|
import { SignedTransaction } from './signedTransaction.js';
|
|
6
6
|
import {
|
|
7
7
|
AddressWithDelegatedLsigSigner,
|
|
8
|
+
AddressWithEmptyTransactionSigner,
|
|
8
9
|
AddressWithTransactionSigner,
|
|
9
10
|
DelegatedLsigSigner,
|
|
10
11
|
TransactionSigner,
|
|
@@ -13,16 +14,55 @@ import { Transaction } from './transaction.js';
|
|
|
13
14
|
import { EncodedPQSig } from './types/transactions/encoded.js';
|
|
14
15
|
import { concatArrays } from './utils/utils.js';
|
|
15
16
|
|
|
17
|
+
/**
|
|
18
|
+
* A post-quantum public key, its scheme identifier, and a function that signs
|
|
19
|
+
* raw bytes with the corresponding secret key.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* `pqSigner` receives the exact bytes to sign, with every domain-separation
|
|
23
|
+
* prefix already applied, so it can be backed by a key that never leaves a
|
|
24
|
+
* wallet, HSM or hardware device.
|
|
25
|
+
*/
|
|
16
26
|
export interface PQSigningKey {
|
|
27
|
+
/** The 2-byte ASCII PQ scheme identifier (e.g. "f1" for Falcon-1024). */
|
|
17
28
|
pqScheme: Uint8Array;
|
|
29
|
+
/** The scheme's canonical public key. */
|
|
18
30
|
pqPublicKey: Uint8Array;
|
|
31
|
+
/** Signs the given bytes verbatim with the corresponding secret key. */
|
|
19
32
|
pqSigner: (bytesToSign: Uint8Array) => Promise<Uint8Array>;
|
|
20
33
|
}
|
|
21
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Build the full set of signers for a post-quantum key from a function that
|
|
37
|
+
* signs raw bytes with it.
|
|
38
|
+
*
|
|
39
|
+
* @remarks
|
|
40
|
+
* The account address is derived from the scheme and public key via
|
|
41
|
+
* {@link addressFromPQKey}, so it does not have to be supplied. Every signature
|
|
42
|
+
* produced carries the scheme, canonical salt and public key alongside the
|
|
43
|
+
* signature bytes, which is what lets the network recover the authorizing
|
|
44
|
+
* address from the signature alone.
|
|
45
|
+
*
|
|
46
|
+
* PQ schemes cannot participate in multisig, so `delegatedLsigSigner` throws if
|
|
47
|
+
* given an `msig` argument, and no `mxBytesSigner` or `programDataSigner` is
|
|
48
|
+
* returned — signing arbitrary bytes and program data are ed25519-only
|
|
49
|
+
* operations.
|
|
50
|
+
*
|
|
51
|
+
* @param signingKey - The scheme, public key and raw signing function to build the signers from
|
|
52
|
+
* @param sendingAddress - The address transactions are sent from. Defaults to
|
|
53
|
+
* the derived PQ address; supply it when the PQ key is the auth address of a
|
|
54
|
+
* rekeyed account, in which case the produced transactions carry the derived
|
|
55
|
+
* address in their `sgnr` field.
|
|
56
|
+
* @returns An address bundled with transaction, empty transaction and delegated
|
|
57
|
+
* LogicSig signers
|
|
58
|
+
* @throws If `pqScheme` is not exactly 2 bytes
|
|
59
|
+
*/
|
|
22
60
|
export function addressWithSignersFromRawPQSigner(
|
|
23
61
|
signingKey: PQSigningKey,
|
|
24
62
|
sendingAddress?: Address
|
|
25
|
-
): AddressWithTransactionSigner &
|
|
63
|
+
): AddressWithTransactionSigner &
|
|
64
|
+
AddressWithDelegatedLsigSigner &
|
|
65
|
+
AddressWithEmptyTransactionSigner {
|
|
26
66
|
const { pqPublicKey, pqSigner: rawSigner, pqScheme } = signingKey;
|
|
27
67
|
const { address: authAddress, salt } = addressFromPQKey(
|
|
28
68
|
pqScheme,
|
|
@@ -56,6 +96,35 @@ export function addressWithSignersFromRawPQSigner(
|
|
|
56
96
|
return stxns.map((stxn) => encodeMsgpack(stxn));
|
|
57
97
|
};
|
|
58
98
|
|
|
99
|
+
// A TransactionSigner that attaches a placeholder PQ envelope rather than a
|
|
100
|
+
// real signature. The scheme, salt, and public key are populated but the
|
|
101
|
+
// signature bytes are left empty. When simulated with `allowEmptySignatures`,
|
|
102
|
+
// algod derives the authorizer from this envelope and charges the post-quantum
|
|
103
|
+
// fee surcharge, so the reported fee usage matches a genuinely signed group -
|
|
104
|
+
// all without paying the cost of producing a (large, slow) Falcon signature.
|
|
105
|
+
const emptyTxnSigner: TransactionSigner = (
|
|
106
|
+
txnGroup: Transaction[],
|
|
107
|
+
indexesToSign: number[]
|
|
108
|
+
) => {
|
|
109
|
+
const stxns: Uint8Array[] = [];
|
|
110
|
+
for (const index of indexesToSign) {
|
|
111
|
+
const txn = txnGroup[index];
|
|
112
|
+
const pqsig: EncodedPQSig = {
|
|
113
|
+
sch: pqScheme,
|
|
114
|
+
slt: salt,
|
|
115
|
+
pk: pqPublicKey,
|
|
116
|
+
sig: new Uint8Array(),
|
|
117
|
+
};
|
|
118
|
+
const stxn = new SignedTransaction({
|
|
119
|
+
txn,
|
|
120
|
+
pqsig,
|
|
121
|
+
sgnr: txn.sender.equals(authAddress) ? undefined : authAddress,
|
|
122
|
+
});
|
|
123
|
+
stxns.push(encodeMsgpack(stxn));
|
|
124
|
+
}
|
|
125
|
+
return Promise.resolve(stxns);
|
|
126
|
+
};
|
|
127
|
+
|
|
59
128
|
const delegatedLsigSigner: DelegatedLsigSigner = async (
|
|
60
129
|
lsig: LogicSig,
|
|
61
130
|
msig?: MultisigMetadata
|
|
@@ -85,6 +154,7 @@ export function addressWithSignersFromRawPQSigner(
|
|
|
85
154
|
return {
|
|
86
155
|
address: sendingAddress ?? authAddress,
|
|
87
156
|
txnSigner,
|
|
157
|
+
emptyTxnSigner,
|
|
88
158
|
delegatedLsigSigner,
|
|
89
159
|
};
|
|
90
160
|
}
|
package/src/signer.ts
CHANGED
|
@@ -36,15 +36,54 @@ export type TransactionSigner = (
|
|
|
36
36
|
indexesToSign: number[]
|
|
37
37
|
) => Promise<Uint8Array[]>;
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* An address paired with a signer able to sign transactions on its behalf.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* `address` is the address transactions are sent from, which is not necessarily
|
|
44
|
+
* the address that authorizes them: for a rekeyed account the two differ, and
|
|
45
|
+
* `txnSigner` sets the transaction's `sgnr` field accordingly.
|
|
46
|
+
*/
|
|
39
47
|
export interface AddressWithTransactionSigner extends Addressable {
|
|
40
48
|
txnSigner: TransactionSigner;
|
|
41
49
|
}
|
|
42
50
|
|
|
43
|
-
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
51
|
+
/**
|
|
52
|
+
* An address paired with a signer that produces placeholder signatures for it.
|
|
53
|
+
*
|
|
54
|
+
* @remarks
|
|
55
|
+
* Useful for post-quantum accounts, whose real signatures are large and slow to
|
|
56
|
+
* produce, when only a simulation of the group is needed.
|
|
57
|
+
*/
|
|
58
|
+
export interface AddressWithEmptyTransactionSigner extends Addressable {
|
|
59
|
+
/**
|
|
60
|
+
* A TransactionSigner that produces unsigned (or placeholder-signed)
|
|
61
|
+
* transactions. This must only be used to simulate transactions with the
|
|
62
|
+
* `allowEmptySignatures` option enabled.
|
|
63
|
+
*/
|
|
64
|
+
emptyTxnSigner: TransactionSigner;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* This type represents a function which can sign a LogicSig for delegation.
|
|
69
|
+
*
|
|
70
|
+
* @remarks
|
|
71
|
+
* Exactly one of `sig`, `lmsig` and `pqsig` is returned, according to the kind
|
|
72
|
+
* of key the signer holds and whether `msig` was supplied:
|
|
73
|
+
*
|
|
74
|
+
* - `sig` - an ed25519 signature from a single delegating account
|
|
75
|
+
* - `lmsig` - a multisig containing this signer's subsignature, returned when
|
|
76
|
+
* `msig` is supplied
|
|
77
|
+
* - `pqsig` - a post-quantum signature from a single delegating account
|
|
78
|
+
*
|
|
79
|
+
* @param lsig - The logic signature that is being signed for delegation
|
|
80
|
+
* @param msig - Optional multisig account that should be set when a public key is signing as a subsigner of a multisig
|
|
81
|
+
* @returns A promise which resolves to the signature and the address that
|
|
82
|
+
* produced it. When `msig` is omitted this is the delegating account; when
|
|
83
|
+
* `msig` is supplied it is the individual subsigner rather than the multisig.
|
|
84
|
+
* Either way it is an authorizing address, which is not necessarily the
|
|
85
|
+
* address the signer sends transactions from.
|
|
86
|
+
*/
|
|
48
87
|
export type DelegatedLsigSigner = (
|
|
49
88
|
lsig: LogicSig,
|
|
50
89
|
msig?: MultisigMetadata
|
|
@@ -56,21 +95,54 @@ export type DelegatedLsigSigner = (
|
|
|
56
95
|
)
|
|
57
96
|
>;
|
|
58
97
|
|
|
98
|
+
/**
|
|
99
|
+
* An address paired with a signer able to delegate a LogicSig to it.
|
|
100
|
+
*/
|
|
59
101
|
export interface AddressWithDelegatedLsigSigner extends Addressable {
|
|
60
102
|
delegatedLsigSigner: DelegatedLsigSigner;
|
|
61
103
|
}
|
|
62
104
|
|
|
105
|
+
/**
|
|
106
|
+
* This type represents a function which can sign arbitrary bytes, for use with
|
|
107
|
+
* {@link verifyBytes}.
|
|
108
|
+
*
|
|
109
|
+
* @remarks
|
|
110
|
+
* The implementation is responsible for prepending the "MX" domain-separation
|
|
111
|
+
* prefix ({@link SIGN_BYTES_PREFIX}) before signing, so `bytesToSign` is the
|
|
112
|
+
* caller's bytes alone.
|
|
113
|
+
*
|
|
114
|
+
* @param bytesToSign - The bytes to sign, without any domain-separation prefix
|
|
115
|
+
* @returns A promise which resolves to the raw signature
|
|
116
|
+
*/
|
|
63
117
|
export type MxBytesSigner = (bytesToSign: Uint8Array) => Promise<Uint8Array>;
|
|
64
118
|
|
|
119
|
+
/**
|
|
120
|
+
* An address paired with a signer able to sign arbitrary bytes on its behalf.
|
|
121
|
+
*/
|
|
65
122
|
export interface AddressWithMxBytesSigner extends Addressable {
|
|
66
123
|
mxBytesSigner: MxBytesSigner;
|
|
67
124
|
}
|
|
68
125
|
|
|
126
|
+
/**
|
|
127
|
+
* This type represents a function which can sign data for use with the
|
|
128
|
+
* `ed25519verify` opcode from within a LogicSig's program.
|
|
129
|
+
*
|
|
130
|
+
* @remarks
|
|
131
|
+
* The implementation is responsible for prepending the "ProgData" prefix
|
|
132
|
+
* ({@link SIGN_PROGRAM_DATA_PREFIX}) and the LogicSig's address before signing.
|
|
133
|
+
*
|
|
134
|
+
* @param data - The data to sign, without any prefix
|
|
135
|
+
* @param lsig - The LogicSig whose program will verify the signature
|
|
136
|
+
* @returns A promise which resolves to the raw signature
|
|
137
|
+
*/
|
|
69
138
|
export type ProgramDataSigner = (
|
|
70
139
|
data: Uint8Array,
|
|
71
140
|
lsig: LogicSig
|
|
72
141
|
) => Promise<Uint8Array>;
|
|
73
142
|
|
|
143
|
+
/**
|
|
144
|
+
* An address paired with a signer able to sign program data on its behalf.
|
|
145
|
+
*/
|
|
74
146
|
export interface AddressWithProgramDataSigner extends Addressable {
|
|
75
147
|
programDataSigner: ProgramDataSigner;
|
|
76
148
|
}
|
package/src/signing.ts
CHANGED
|
@@ -8,6 +8,11 @@ import { LogicSig, LogicSigAccount, sanityCheckProgram } from './logicsig.js';
|
|
|
8
8
|
import { addressFromMultisigPreImg } from './multisig.js';
|
|
9
9
|
import type { TransactionSigner } from './signer.js';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* The domain-separation prefix prepended to arbitrary bytes before signing them
|
|
13
|
+
* with {@link signBytes}, so that such a signature can never be mistaken for a
|
|
14
|
+
* signature over a transaction or a program.
|
|
15
|
+
*/
|
|
11
16
|
export const SIGN_BYTES_PREFIX = Uint8Array.from([77, 88]); // "MX"
|
|
12
17
|
|
|
13
18
|
/**
|
|
@@ -34,6 +39,23 @@ export function signTransaction(txn: Transaction, sk: Uint8Array) {
|
|
|
34
39
|
};
|
|
35
40
|
}
|
|
36
41
|
|
|
42
|
+
/**
|
|
43
|
+
* signTransactionWithSigner signs a single transaction with the given signer.
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
* This is the replacement for the deprecated {@link signTransaction}, which can
|
|
47
|
+
* only sign with a raw ed25519 secret key. Because a `TransactionSigner` signs
|
|
48
|
+
* a group, the transaction is passed as a one-element group and the single
|
|
49
|
+
* result is returned.
|
|
50
|
+
*
|
|
51
|
+
* The decoded `stxn` is returned alongside the blob so callers can read what
|
|
52
|
+
* the signer produced — its `sig`, `pqsig` or `msig` field, and the `sgnr` field
|
|
53
|
+
* naming the key that signed when it is not the transaction sender.
|
|
54
|
+
*
|
|
55
|
+
* @param txn - the transaction to sign
|
|
56
|
+
* @param signer - the signer to sign with
|
|
57
|
+
* @returns an object with blob, txID and stxn properties
|
|
58
|
+
*/
|
|
37
59
|
export async function signTransactionWithSigner(
|
|
38
60
|
txn: Transaction,
|
|
39
61
|
signer: TransactionSigner
|
package/src/transaction.ts
CHANGED
|
@@ -247,6 +247,12 @@ function ensureResourceReference(input: unknown): TransactionResourceReference {
|
|
|
247
247
|
if (box !== undefined) {
|
|
248
248
|
return { box: ensureBoxReference(box) };
|
|
249
249
|
}
|
|
250
|
+
|
|
251
|
+
// An empty resource reference is meaningful: it asks for a box I/O quota
|
|
252
|
+
// bump without naming a resource.
|
|
253
|
+
if (utils.isEmptyObject(input)) {
|
|
254
|
+
return {};
|
|
255
|
+
}
|
|
250
256
|
}
|
|
251
257
|
throw new Error(`Not a resource reference: ${input}`);
|
|
252
258
|
}
|
|
@@ -329,6 +335,7 @@ export interface HeartbeatTransactionFields {
|
|
|
329
335
|
readonly seed: Uint8Array;
|
|
330
336
|
readonly voteID: Uint8Array;
|
|
331
337
|
readonly keyDilution: bigint;
|
|
338
|
+
readonly challengeDiscount: boolean;
|
|
332
339
|
}
|
|
333
340
|
|
|
334
341
|
/**
|
|
@@ -876,6 +883,7 @@ export class Transaction implements encoding.Encodable {
|
|
|
876
883
|
seed: params.heartbeatParams.seed,
|
|
877
884
|
voteID: params.heartbeatParams.voteID,
|
|
878
885
|
keyDilution: params.heartbeatParams.keyDilution,
|
|
886
|
+
challengeDiscount: params.heartbeatParams.challengeDiscount,
|
|
879
887
|
});
|
|
880
888
|
}
|
|
881
889
|
|
|
@@ -1035,6 +1043,7 @@ export class Transaction implements encoding.Encodable {
|
|
|
1035
1043
|
seed: this.heartbeat.seed,
|
|
1036
1044
|
voteID: this.heartbeat.voteID,
|
|
1037
1045
|
keyDilution: this.heartbeat.keyDilution,
|
|
1046
|
+
challengeDiscount: this.heartbeat.challengeDiscount,
|
|
1038
1047
|
});
|
|
1039
1048
|
data.set('hb', heartbeat.toEncodingData());
|
|
1040
1049
|
return data;
|
|
@@ -1219,6 +1228,7 @@ export class Transaction implements encoding.Encodable {
|
|
|
1219
1228
|
seed: heartbeat.seed,
|
|
1220
1229
|
voteID: heartbeat.voteID,
|
|
1221
1230
|
keyDilution: heartbeat.keyDilution,
|
|
1231
|
+
challengeDiscount: heartbeat.challengeDiscount,
|
|
1222
1232
|
};
|
|
1223
1233
|
params.heartbeatParams = heartbeatParams;
|
|
1224
1234
|
} else {
|