@openzeppelin/compact-contracts 0.4.0-alpha.5 → 0.4.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.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/access/AccessControl.compact +1 -1
  3. package/access/Ownable.compact +1 -3
  4. package/access/ShieldedAccessControl.compact +44 -41
  5. package/access/ZOwnablePK.compact +12 -5
  6. package/crypto/EcdhMask.compact +11 -1
  7. package/crypto/Ecdsa.compact +1 -1
  8. package/crypto/Eip712.compact +1 -1
  9. package/crypto/ElGamal.compact +1 -1
  10. package/multisig/ForwarderPrivate.compact +17 -6
  11. package/multisig/ForwarderShielded.compact +1 -1
  12. package/multisig/ForwarderUnshielded.compact +1 -1
  13. package/multisig/ProposalManager.compact +65 -127
  14. package/multisig/RecipientTypes.compact +48 -0
  15. package/multisig/Secp256k1EcdsaMultisig.compact +275 -0
  16. package/multisig/ShieldedTreasury.compact +20 -8
  17. package/multisig/ShieldedTreasuryStateless.compact +11 -5
  18. package/multisig/Signer.compact +1 -1
  19. package/multisig/UnshieldedTreasury.compact +24 -11
  20. package/multisig/examples/ForwarderPrivateExample.compact +3 -2
  21. package/multisig/examples/ForwarderShieldedExample.compact +1 -1
  22. package/multisig/examples/ForwarderUnshieldedExample.compact +1 -1
  23. package/multisig/examples/NativeShieldedTokenIssuerExample.compact +4 -4
  24. package/multisig/examples/ShieldedMultiSigV2Example.compact +7 -9
  25. package/multisig/presets/NativeShieldedTokenIssuer.compact +88 -84
  26. package/multisig/presets/ShieldedMultiSigV2.compact +50 -52
  27. package/package.json +1 -1
  28. package/security/Allowlist.compact +1 -1
  29. package/security/Blocklist.compact +1 -1
  30. package/security/Initializable.compact +1 -3
  31. package/security/Pausable.compact +1 -1
  32. package/token/ConfidentialFungibleToken.compact +70 -22
  33. package/token/FungibleToken.compact +1 -3
  34. package/token/MultiToken.compact +1 -3
  35. package/token/NativeShieldedToken.compact +11 -3
  36. package/token/NativeShieldedTokenCore.compact +1 -1
  37. package/token/NativeShieldedTokenFamily.compact +1 -1
  38. package/token/NonFungibleToken.compact +1 -3
  39. package/token/examples/ZOwnableNativeShieldedTokenExample.compact +109 -0
  40. package/token/extensions/ConfidentialFungibleTokenPublicSupply.compact +1 -1
  41. package/token/extensions/NativeShieldedTokenDerivedNonce.compact +1 -1
  42. package/token/presets/ZOwnableNativeShieldedToken.compact +314 -0
  43. package/utils/EvmAbi.compact +1 -1
  44. package/utils/Utils.compact +1 -1
  45. package/multisig/EcdsaSignerManager.compact +0 -248
@@ -1,19 +1,19 @@
1
1
  // SPDX-License-Identifier: MIT
2
- // OpenZeppelin Compact Contracts v0.4.0-alpha.5 (multisig/presets/NativeShieldedTokenIssuer.compact)
2
+ // OpenZeppelin Compact Contracts v0.4.0 (multisig/presets/NativeShieldedTokenIssuer.compact)
3
3
 
4
4
  pragma language_version >= 0.26.0;
5
5
 
6
6
  /**
7
7
  * @module NativeShieldedTokenIssuer
8
8
  * @description
9
- * A 2-of-3 ECDSA multisig that mints and burns one native shielded token,
9
+ * A threshold ECDSA multisig that mints and burns one native shielded token,
10
10
  * for tokenized deposits. Value enters only through `mint` (to a holder's
11
11
  * coin public key) or `mintToSelf` (a coin this contract holds) and leaves
12
12
  * only through `burn` (a holder's coin, paid into the tx) or `burnFromSelf`
13
- * (a coin this contract holds); each is a single tx carrying two registered
14
- * signers' approvals, so no single party creates or destroys tokens.
13
+ * (a coin this contract holds); each is a single tx carrying `t` registered
14
+ * signers' approvals.
15
15
  *
16
- * Composes `EcdsaSignerManager` (signer commitments, approval checks),
16
+ * Composes `Secp256k1EcdsaMultisig` (signer commitments, approval checks),
17
17
  * `NativeShieldedToken` as `NST_` (one token; domain, `name`, `symbol` and
18
18
  * `decimals` fixed at construction) and `NativeShieldedTokenDerivedNonce` as
19
19
  * `NSTDerivedNonce_` (coin nonces derived from a counter).
@@ -58,9 +58,9 @@ pragma language_version >= 0.26.0;
58
58
  * uint256 amount,bytes32 coinNonce,uint256 coinValue)")`, written as
59
59
  * literal words.
60
60
  * - Signer commitment: `cm = H<SignerCommitmentInput>({ pkX, pkY, salt,
61
- * domain: pad(32, "multisig:signer:") })`, `pkX` / `pkY` the affine
62
- * coordinates as `Bytes<32>`. `_calculateSignerId` is the exported pure
63
- * circuit.
61
+ * domain: pad(32, "Secp256k1EcdsaMultisig:signer") })`, `pkX` / `pkY`
62
+ * the affine coordinates as `Bytes<32>`. `_calculateSignerId` is the
63
+ * exported pure circuit.
64
64
  * - Coin nonce: `evolveNonce(counter, pad(32, "NativeShieldedToken:nonce"))`
65
65
  * over the derived-nonce counter after its increment.
66
66
  * - Encoding: `H` hashes the Compact encoding, not a byte concatenation.
@@ -72,25 +72,31 @@ pragma language_version >= 0.26.0;
72
72
  *
73
73
  * @notice Implementing contracts register the signer set from their
74
74
  * constructor by calling this module's `initialize`, and MUST NOT import
75
- * `EcdsaSignerManager` directly.
75
+ * `Signer` or `Secp256k1EcdsaMultisig` directly.
76
76
  *
77
77
  * @dev Parameterization:
78
- * None: the signer set is hardcoded to 3 and the threshold to 2.
78
+ * `t` is the approval width and the threshold, fixed at import
79
+ * (`"../presets/NativeShieldedTokenIssuer"<t>`). The implementing contract
80
+ * fixes the signer count `n` at `initialize`. Import one width per contract:
81
+ * two widths share one signer registry, see `Secp256k1EcdsaMultisig`.
82
+ * `NativeShieldedTokenIssuerExample` fixes 2-of-3. The `@constraints` tags on
83
+ * the gated circuits are measured at `t = 2`.
79
84
  *
80
85
  * @dev Compatibility:
81
86
  * The wire format the custodian's signer implements is the EIP-712 domain
82
87
  * (`NativeShieldedTokenIssuer`, version `1`, salt), the `Mint` /
83
- * `MintToSelf` / `Burn` / `BurnFromSelf` type strings, the `multisig:signer:` commitment domain (generic prefix,
84
- * owned by `EcdsaSignerManager`), the `cm` preimage struct, and the
85
- * `Vector<2>` / `Vector<3>` shapes. Changing any of them breaks every
86
- * existing signer setup. The test suite pins them through
87
- * `EcdsaTestUtils.ts`.
88
+ * `MintToSelf` / `Burn` / `BurnFromSelf` type strings, the
89
+ * `Secp256k1EcdsaMultisig:signer` commitment domain (owned by
90
+ * `Secp256k1EcdsaMultisig`), the `cm` preimage struct, and the
91
+ * `Vector<t>` / `Vector<n>` shapes the implementing contract fixes. Changing
92
+ * any of them breaks every existing signer setup. The test suite pins them
93
+ * through `EcdsaTestUtils.ts`.
88
94
  *
89
95
  * @notice Privacy:
90
96
  * - Public, per tx:
91
97
  * - Entry point: which of the four operations ran.
92
- * - Approvers: the two signer commitments (`disclose(commitment)` in
93
- * `Signer_assertSigner`), so WHICH two of the three signers approved.
98
+ * - Approvers: the `t` signer commitments (`disclose(commitment)` in
99
+ * `Signer_assertSigner`), so WHICH signers approved.
94
100
  * - Mint: `amount`, as the `shieldedMints` effect under the token domain,
95
101
  * and the coin commitment as a spend claim. Recipient and nonce are not
96
102
  * published. The nonce is `evolveNonce` of the public
@@ -149,12 +155,11 @@ pragma language_version >= 0.26.0;
149
155
  * still refunds the bound `refundTo`.
150
156
  * - Low-s: verification goes through `Ecdsa_secp256k1EcdsaVerifyLowS`, so a
151
157
  * high-s encoding is an invalid signature.
152
- * - Distinct signers: `assertApprovals` asserts both entries and rejects a
153
- * repeated commitment, so two distinct registered signers are always
154
- * required. The threshold `2` is the only value `EcdsaSignerManager` accepts.
158
+ * - Distinct signers: every gated circuit verifies `t` distinct registered
159
+ * signers, so no set of fewer than `t` keys creates or destroys tokens.
155
160
  * - Immutable signer set: no signer reconfiguration circuit is exported, so
156
- * the three commitments and the threshold are fixed. Losing two of the
157
- * three keys freezes the contract.
161
+ * the commitments and the threshold are fixed. Losing more than `n - t`
162
+ * keys freezes the contract.
158
163
  * - Griefing: the derived-nonce mints are the only mint paths and both are
159
164
  * threshold-gated, so `NativeShieldedTokenDerivedNonce`'s
160
165
  * collision-griefing precondition (a caller-nonce mint at another trust
@@ -165,8 +170,8 @@ pragma language_version >= 0.26.0;
165
170
  * @notice Concurrency:
166
171
  * - Replay counter: `mint`, `mintToSelf`, `burn` and `burnFromSelf` read
167
172
  * `_counter` into the digest. The read is pinned, so any two of them in one block
168
- * conflict: at most one operation lands per block, and the losing signer
169
- * pair re-signs at the next nonce.
173
+ * conflict: at most one operation lands per block, and the losing signers
174
+ * re-sign at the next nonce.
170
175
  * - Derived-nonce counter: both mints also pin it (`evolveNonce` consumes
171
176
  * it); the `_counter` conflict already covers those pairs.
172
177
  * - `getNonce`: submitted as a tx it pins `_counter` and conflicts with any
@@ -178,16 +183,19 @@ pragma language_version >= 0.26.0;
178
183
  * Mint and burn only. No send, transfer or execute circuit exists, so
179
184
  * contract-held coins (from `mintToSelf` or `burnFromSelf` change) leave only
180
185
  * through `burnFromSelf`, supplied by the operator as
181
- * `QualifiedShieldedCoinInfo`. Coins minted to users are ordinary
186
+ * `QualifiedShieldedCoinInfo`. Moving such a coin anywhere else needs a
187
+ * custody module composed by the consumer that records the coin without
188
+ * claiming it a second time; `ShieldedTreasury._deposit` is not that module
189
+ * today (compact-contracts#1112). Coins minted to users are ordinary
182
190
  * Zswap coins the contract neither tracks nor restricts; a holder redeems by
183
191
  * paying the coin into a `burn` tx. No supply accounting.
184
192
  *
185
193
  * @notice Client-side duties:
186
194
  * - Before deploy: pick a random `instanceSalt`, derive each `cm` with
187
- * `_calculateSignerId(pk, salt)`, pass the three as `signerCommitments`.
195
+ * `_calculateSignerId(pk, salt)`, pass them as `signerCommitments`.
188
196
  * - Per operation: read `getNonce()`, rebuild the digest as
189
- * `EcdsaTestUtils.ts` does, collect two low-s signatures off-chain, submit
190
- * keys and signatures in matching `Vector<2>` positions.
197
+ * `EcdsaTestUtils.ts` does, collect `t` low-s signatures off-chain, submit
198
+ * keys and signatures in matching `Vector<t>` positions.
191
199
  * - `mint`: hand the returned `ShieldedCoinInfo` to the recipient out of
192
200
  * band; contract-initiated mints create no ciphertext, so a wallet cannot
193
201
  * find the coin by scanning.
@@ -212,7 +220,7 @@ pragma language_version >= 0.26.0;
212
220
  *
213
221
  * @notice Scalability:
214
222
  * - Throughput: one operation per block (see Concurrency).
215
- * - State: constant-size, two counters and a three-entry signer set. Nothing
223
+ * - State: constant-size, two counters and an `n`-entry signer set. Nothing
216
224
  * grows per operation.
217
225
  * - Amounts: mints cap at `Uint<64>` by `mintShieldedToken`. Burns take
218
226
  * `Uint<128>`, the coin value range.
@@ -225,10 +233,10 @@ pragma language_version >= 0.26.0;
225
233
  *
226
234
  * @notice Requires ZKIR v3: `keccak256` is unavailable on the v2 backend.
227
235
  */
228
- module NativeShieldedTokenIssuer {
236
+ module NativeShieldedTokenIssuer<#t> {
229
237
  import CompactStandardLibrary;
230
238
 
231
- import "../EcdsaSignerManager" prefix EcdsaSignerManager_;
239
+ import "../Secp256k1EcdsaMultisig"<t> prefix Secp256k1EcdsaMultisig_;
232
240
  import "../../crypto/Eip712" prefix Eip712_;
233
241
  import "../../utils/EvmAbi" prefix EvmAbi_;
234
242
  import "../../token/NativeShieldedToken" prefix NST_;
@@ -238,7 +246,7 @@ module NativeShieldedTokenIssuer {
238
246
  // implementing contract can surface every ledger field under its own key.
239
247
  // The circuits stay behind the prefixes above. The derived-nonce counter is
240
248
  // aliased because this module's replay counter already owns `_counter`.
241
- import { _instanceSalt, _signers, _signerCount, _threshold } from "../EcdsaSignerManager";
249
+ import { _instanceSalt, _signers, _signerCount, _threshold } from "../Secp256k1EcdsaMultisig"<t>;
242
250
  import { _domain, _name, _symbol, _decimals, _isInitialized } from "../../token/NativeShieldedToken";
243
251
  import { _counter as _derivedNonceCounter } from "../../token/extensions/NativeShieldedTokenDerivedNonce";
244
252
  export { _instanceSalt, _signers, _signerCount, _threshold };
@@ -262,9 +270,8 @@ module NativeShieldedTokenIssuer {
262
270
  export sealed ledger _domainSeparator: Bytes<32>;
263
271
 
264
272
  /**
265
- * @description Registers the signer set, initializes the token metadata
266
- * and domain, and fixes the EIP-712 domain separator. The threshold is
267
- * fixed at 2.
273
+ * @description Registers the signer set at threshold `t`, initializes the
274
+ * token metadata and domain, and fixes the EIP-712 domain separator.
268
275
  *
269
276
  * @notice Call from the implementing contract's constructor only. It writes
270
277
  * the token module's `sealed` domain and `_domainSeparator`, so
@@ -281,24 +288,25 @@ module NativeShieldedTokenIssuer {
281
288
  *
282
289
  * - `instanceSalt` should be cryptographically random.
283
290
  * - `signerCommitments` must not contain duplicates.
291
+ * - `n` must be at least `t`.
284
292
  *
285
293
  * @param {Bytes<32>} instanceSalt - Per-deployment salt for commitment derivation.
286
294
  * @param {Bytes<32>} tokenDomain - Domain separator for this contract's token color.
287
295
  * @param {Opaque<"string">} name_ - The token name.
288
296
  * @param {Opaque<"string">} symbol_ - The token symbol.
289
297
  * @param {Uint<8>} decimals_ - The token decimals.
290
- * @param {Vector<3, Bytes<32>>} signerCommitments - Hashed signer identities.
298
+ * @param {Vector<n, Bytes<32>>} signerCommitments - Hashed signer identities.
291
299
  * @returns {[]} Empty tuple.
292
300
  */
293
- export circuit initialize(
301
+ export circuit initialize<#n>(
294
302
  instanceSalt: Bytes<32>,
295
303
  tokenDomain: Bytes<32>,
296
304
  name_: Opaque<"string">,
297
305
  symbol_: Opaque<"string">,
298
306
  decimals_: Uint<8>,
299
- signerCommitments: Vector<3, Bytes<32>>,
307
+ signerCommitments: Vector<n, Bytes<32>>
300
308
  ): [] {
301
- EcdsaSignerManager_initialize<3>(instanceSalt, signerCommitments, 2);
309
+ Secp256k1EcdsaMultisig_initialize<n>(instanceSalt, signerCommitments);
302
310
  NST_initialize(tokenDomain, name_, symbol_, decimals_);
303
311
 
304
312
  const hashedName = keccak256<Bytes<25>>(pad(25, "NativeShieldedTokenIssuer"));
@@ -394,7 +402,7 @@ module NativeShieldedTokenIssuer {
394
402
 
395
403
  /**
396
404
  * @description Computes a signer commitment from a secp256k1 public key,
397
- * as `persistentHash(pkX, pkY, salt, "multisig:signer:")`.
405
+ * as `persistentHash(pkX, pkY, salt, "Secp256k1EcdsaMultisig:signer")`.
398
406
  *
399
407
  * Pure, so the deployer can derive constructor commitments off-chain.
400
408
  *
@@ -410,7 +418,7 @@ module NativeShieldedTokenIssuer {
410
418
  pk: Secp256k1Point,
411
419
  salt: Bytes<32>
412
420
  ): Bytes<32> {
413
- return EcdsaSignerManager_calculateSignerId(pk, salt);
421
+ return Secp256k1EcdsaMultisig_calculateSignerId(pk, salt);
414
422
  }
415
423
 
416
424
  /**
@@ -423,27 +431,26 @@ module NativeShieldedTokenIssuer {
423
431
  * @notice The returned coin info is the only copy available to the
424
432
  * recipient; deliver it out of band.
425
433
  *
426
- * @constraints k=17, rows=89815 (zkir-v3)
434
+ * @constraints k=17, rows=89807 (zkir-v3)
427
435
  *
428
436
  * Requirements:
429
437
  *
430
- * - Both public keys must hash to registered signer commitments.
431
- * - Both signatures must be valid over the mint message hash.
432
- * - Signers must not be duplicates.
433
- * - Threshold must be met.
438
+ * - No two entries may be the same signer.
439
+ * - Every public key must hash to a registered signer commitment.
440
+ * - Every signature must be valid over the mint message hash.
434
441
  * - `recipient` is not zero.
435
442
  *
436
443
  * @param {Uint<64>} amount - The token amount to mint.
437
444
  * @param {ZswapCoinPublicKey} recipient - The coin public key to receive the minted tokens.
438
- * @param {Vector<2, Secp256k1Point>} pubkeys - Public keys of approving signers.
439
- * @param {Vector<2, Secp256k1EcdsaSignature>} signatures - ECDSA signatures over the mint hash.
445
+ * @param {Vector<t, Secp256k1Point>} pubkeys - Public keys of approving signers.
446
+ * @param {Vector<t, Secp256k1EcdsaSignature>} signatures - ECDSA signatures over the mint hash.
440
447
  * @returns {ShieldedCoinInfo} The minted coin (nonce, color, value).
441
448
  */
442
449
  export circuit mint(
443
450
  amount: Uint<64>,
444
451
  recipient: ZswapCoinPublicKey,
445
- pubkeys: Vector<2, Secp256k1Point>,
446
- signatures: Vector<2, Secp256k1EcdsaSignature>
452
+ pubkeys: Vector<t, Secp256k1Point>,
453
+ signatures: Vector<t, Secp256k1EcdsaSignature>
447
454
  ): ShieldedCoinInfo {
448
455
  const opNonce = _counter;
449
456
  _counter.increment(1);
@@ -459,7 +466,7 @@ module NativeShieldedTokenIssuer {
459
466
  EvmAbi_uint64Word(amount)
460
467
  ]));
461
468
 
462
- EcdsaSignerManager_assertApprovals(msgHash, pubkeys, signatures);
469
+ Secp256k1EcdsaMultisig_assertApprovals(msgHash, pubkeys, signatures);
463
470
 
464
471
  return NST__mint(recipient, amount, NSTDerivedNonce__deriveNonce());
465
472
  }
@@ -472,24 +479,23 @@ module NativeShieldedTokenIssuer {
472
479
  * @notice The returned coin info is the contract's only record of the
473
480
  * holding; persist it for `burnFromSelf`.
474
481
  *
475
- * @constraints k=17, rows=85594 (zkir-v3)
482
+ * @constraints k=17, rows=85586 (zkir-v3)
476
483
  *
477
484
  * Requirements:
478
485
  *
479
- * - Both public keys must hash to registered signer commitments.
480
- * - Both signatures must be valid over the mint-to-self message hash.
481
- * - Signers must not be duplicates.
482
- * - Threshold must be met.
486
+ * - No two entries may be the same signer.
487
+ * - Every public key must hash to a registered signer commitment.
488
+ * - Every signature must be valid over the mint-to-self message hash.
483
489
  *
484
490
  * @param {Uint<64>} amount - The token amount to mint.
485
- * @param {Vector<2, Secp256k1Point>} pubkeys - Public keys of approving signers.
486
- * @param {Vector<2, Secp256k1EcdsaSignature>} signatures - ECDSA signatures over the mint-to-self hash.
491
+ * @param {Vector<t, Secp256k1Point>} pubkeys - Public keys of approving signers.
492
+ * @param {Vector<t, Secp256k1EcdsaSignature>} signatures - ECDSA signatures over the mint-to-self hash.
487
493
  * @returns {ShieldedCoinInfo} The minted coin (nonce, color, value).
488
494
  */
489
495
  export circuit mintToSelf(
490
496
  amount: Uint<64>,
491
- pubkeys: Vector<2, Secp256k1Point>,
492
- signatures: Vector<2, Secp256k1EcdsaSignature>
497
+ pubkeys: Vector<t, Secp256k1Point>,
498
+ signatures: Vector<t, Secp256k1EcdsaSignature>
493
499
  ): ShieldedCoinInfo {
494
500
  const opNonce = _counter;
495
501
  _counter.increment(1);
@@ -504,7 +510,7 @@ module NativeShieldedTokenIssuer {
504
510
  EvmAbi_uint64Word(amount)
505
511
  ]));
506
512
 
507
- EcdsaSignerManager_assertApprovals(msgHash, pubkeys, signatures);
513
+ Secp256k1EcdsaMultisig_assertApprovals(msgHash, pubkeys, signatures);
508
514
 
509
515
  return NST__mintToSelf(amount, NSTDerivedNonce__deriveNonce());
510
516
  }
@@ -517,14 +523,13 @@ module NativeShieldedTokenIssuer {
517
523
  * @notice The returned refund coin info is the only copy available to
518
524
  * `refundTo`; deliver it out of band.
519
525
  *
520
- * @constraints k=17, rows=119826 (zkir-v3)
526
+ * @constraints k=17, rows=119818 (zkir-v3)
521
527
  *
522
528
  * Requirements:
523
529
  *
524
- * - Both public keys must hash to registered signer commitments.
525
- * - Both signatures must be valid over the burn message hash.
526
- * - Signers must not be duplicates.
527
- * - Threshold must be met.
530
+ * - No two entries may be the same signer.
531
+ * - Every public key must hash to a registered signer commitment.
532
+ * - Every signature must be valid over the burn message hash.
528
533
  * - `coin.color` is this contract's token color.
529
534
  * - `amount` is less than or equal to `coin.value`.
530
535
  * - `refundTo` is not zero.
@@ -532,8 +537,8 @@ module NativeShieldedTokenIssuer {
532
537
  * @param {ShieldedCoinInfo} coin - The holder's coin to burn from.
533
538
  * @param {Uint<128>} amount - The token amount to burn.
534
539
  * @param {ZswapCoinPublicKey} refundTo - Receives `coin.value - amount`.
535
- * @param {Vector<2, Secp256k1Point>} pubkeys - Public keys of approving signers.
536
- * @param {Vector<2, Secp256k1EcdsaSignature>} signatures - ECDSA signatures over the burn hash.
540
+ * @param {Vector<t, Secp256k1Point>} pubkeys - Public keys of approving signers.
541
+ * @param {Vector<t, Secp256k1EcdsaSignature>} signatures - ECDSA signatures over the burn hash.
537
542
  * @returns {Maybe<ShieldedCoinInfo>} The refund coin created for `refundTo`,
538
543
  * or `none` if the coin was burned in full.
539
544
  */
@@ -541,8 +546,8 @@ module NativeShieldedTokenIssuer {
541
546
  coin: ShieldedCoinInfo,
542
547
  amount: Uint<128>,
543
548
  refundTo: ZswapCoinPublicKey,
544
- pubkeys: Vector<2, Secp256k1Point>,
545
- signatures: Vector<2, Secp256k1EcdsaSignature>
549
+ pubkeys: Vector<t, Secp256k1Point>,
550
+ signatures: Vector<t, Secp256k1EcdsaSignature>
546
551
  ): Maybe<ShieldedCoinInfo> {
547
552
  const opNonce = _counter;
548
553
  _counter.increment(1);
@@ -558,7 +563,7 @@ module NativeShieldedTokenIssuer {
558
563
  EvmAbi_uint128Word(amount)
559
564
  ]));
560
565
 
561
- EcdsaSignerManager_assertApprovals(msgHash, pubkeys, signatures);
566
+ Secp256k1EcdsaMultisig_assertApprovals(msgHash, pubkeys, signatures);
562
567
 
563
568
  return NST__burn(coin, amount, refundTo);
564
569
  }
@@ -575,30 +580,29 @@ module NativeShieldedTokenIssuer {
575
580
  * The digest binds `coin.nonce` and `coin.value`, so approvals authorize one
576
581
  * specific holding rather than an amount.
577
582
  *
578
- * @constraints k=17, rows=104981 (zkir-v3)
583
+ * @constraints k=17, rows=104973 (zkir-v3)
579
584
  *
580
585
  * Requirements:
581
586
  *
582
- * - Both public keys must hash to registered signer commitments.
583
- * - Both signatures must be valid over the burn-from-self message hash.
584
- * - Signers must not be duplicates.
585
- * - Threshold must be met.
587
+ * - No two entries may be the same signer.
588
+ * - Every public key must hash to a registered signer commitment.
589
+ * - Every signature must be valid over the burn-from-self message hash.
586
590
  * - `coin.color` is this contract's token color.
587
591
  * - `amount` is less than or equal to `coin.value`.
588
592
  * - `coin.nonce` and `coin.value` match the approved coin.
589
593
  *
590
594
  * @param {QualifiedShieldedCoinInfo} coin - The contract-held coin to burn from.
591
595
  * @param {Uint<128>} amount - The token amount to burn.
592
- * @param {Vector<2, Secp256k1Point>} pubkeys - Public keys of approving signers.
593
- * @param {Vector<2, Secp256k1EcdsaSignature>} signatures - ECDSA signatures over the burn-from-self hash.
596
+ * @param {Vector<t, Secp256k1Point>} pubkeys - Public keys of approving signers.
597
+ * @param {Vector<t, Secp256k1EcdsaSignature>} signatures - ECDSA signatures over the burn-from-self hash.
594
598
  * @returns {Maybe<ShieldedCoinInfo>} The change coin retained by the
595
599
  * contract, or `none` if the coin was burned in full.
596
600
  */
597
601
  export circuit burnFromSelf(
598
602
  coin: QualifiedShieldedCoinInfo,
599
603
  amount: Uint<128>,
600
- pubkeys: Vector<2, Secp256k1Point>,
601
- signatures: Vector<2, Secp256k1EcdsaSignature>
604
+ pubkeys: Vector<t, Secp256k1Point>,
605
+ signatures: Vector<t, Secp256k1EcdsaSignature>
602
606
  ): Maybe<ShieldedCoinInfo> {
603
607
  const opNonce = _counter;
604
608
  _counter.increment(1);
@@ -615,7 +619,7 @@ module NativeShieldedTokenIssuer {
615
619
  EvmAbi_uint128Word(coin.value)
616
620
  ]));
617
621
 
618
- EcdsaSignerManager_assertApprovals(msgHash, pubkeys, signatures);
622
+ Secp256k1EcdsaMultisig_assertApprovals(msgHash, pubkeys, signatures);
619
623
 
620
624
  return NST__burnFromSelf(coin, amount);
621
625
  }
@@ -684,7 +688,7 @@ module NativeShieldedTokenIssuer {
684
688
  * @returns {Uint<8>} The signer count.
685
689
  */
686
690
  export circuit getSignerCount(): Uint<8> {
687
- return EcdsaSignerManager_getSignerCount();
691
+ return Secp256k1EcdsaMultisig_getSignerCount();
688
692
  }
689
693
 
690
694
  /**
@@ -695,7 +699,7 @@ module NativeShieldedTokenIssuer {
695
699
  * @returns {Uint<8>} The threshold.
696
700
  */
697
701
  export circuit getThreshold(): Uint<8> {
698
- return EcdsaSignerManager_getThreshold();
702
+ return Secp256k1EcdsaMultisig_getThreshold();
699
703
  }
700
704
 
701
705
  /**
@@ -707,6 +711,6 @@ module NativeShieldedTokenIssuer {
707
711
  * @returns {Boolean} True if registered.
708
712
  */
709
713
  export circuit isSigner(commitment: Bytes<32>): Boolean {
710
- return EcdsaSignerManager_isSigner(commitment);
714
+ return Secp256k1EcdsaMultisig_isSigner(commitment);
711
715
  }
712
716
  }