@openzeppelin/compact-contracts 0.3.0-rc.2 → 0.3.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 +11 -3
- package/access/AccessControl.compact +1 -1
- package/access/Ownable.compact +1 -1
- package/access/ShieldedAccessControl.compact +39 -36
- package/access/ZOwnablePK.compact +1 -1
- package/crypto/EcdhMask.compact +1 -1
- package/crypto/ElGamal.compact +1 -1
- package/multisig/ForwarderPrivate.compact +1 -1
- package/multisig/ForwarderShielded.compact +1 -1
- package/multisig/ForwarderUnshielded.compact +1 -1
- package/multisig/ProposalManager.compact +1 -1
- package/multisig/ShieldedTreasury.compact +1 -1
- package/multisig/ShieldedTreasuryStateless.compact +1 -1
- package/multisig/Signer.compact +1 -1
- package/multisig/UnshieldedTreasury.compact +1 -1
- package/multisig/presets/ShieldedMultiSig.compact +1 -1
- package/multisig/presets/ShieldedMultiSigV2.compact +1 -1
- package/multisig/presets/forwarder/ForwarderPrivate.compact +1 -1
- package/multisig/presets/forwarder/ForwarderShielded.compact +1 -1
- package/multisig/presets/forwarder/ForwarderUnshielded.compact +1 -1
- package/package.json +1 -1
- package/security/Allowlist.compact +1 -1
- package/security/Blocklist.compact +1 -1
- package/security/Initializable.compact +1 -1
- package/security/Pausable.compact +1 -1
- package/token/ConfidentialFungibleToken.compact +3 -3
- package/token/FungibleToken.compact +1 -1
- package/token/MultiToken.compact +1 -1
- package/token/NativeShieldedToken.compact +1 -1
- package/token/NativeShieldedTokenCore.compact +1 -1
- package/token/NativeShieldedTokenFamily.compact +1 -1
- package/token/NonFungibleToken.compact +1 -1
- package/token/examples/ZOwnableNativeShieldedTokenExample.compact +1 -1
- package/token/extensions/ConfidentialFungibleTokenPublicSupply.compact +1 -1
- package/token/extensions/NativeShieldedTokenDerivedNonce.compact +1 -1
- package/token/presets/ZOwnableNativeShieldedToken.compact +1 -1
- package/utils/Utils.compact +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ This project is built on the Midnight Network.
|
|
|
10
10
|
|
|
11
11
|
> ## ⚠️ WARNING! ⚠️
|
|
12
12
|
>
|
|
13
|
-
>
|
|
13
|
+
> Pre-release versions (`-alpha`, `-rc`) contain experimental, unaudited code.
|
|
14
14
|
> Expect rapid iteration.
|
|
15
15
|
> **Use at your own risk.**
|
|
16
16
|
|
|
@@ -268,9 +268,17 @@ rm -rf .turbo/
|
|
|
268
268
|
|
|
269
269
|
## Security
|
|
270
270
|
|
|
271
|
-
|
|
271
|
+
For production, use a stable release (no `-alpha` or `-rc` suffix) on the Midnight ledger it targets. Pre-releases are not audited and should not be used in production.
|
|
272
272
|
|
|
273
|
-
|
|
273
|
+
| Release | Midnight ledger | Compact compiler | Audits |
|
|
274
|
+
| ------- | --------------- | ---------------- | ------ |
|
|
275
|
+
| 0.3.0 | Ledger v8 | 0.31.0 | [Aug 2026](./audits/2026-08-v0.3.0-alpha.1.pdf), [Oct 2026](./audits/2026-10-v0.3.0-rc.2-v0.4.0-alpha.6.pdf) |
|
|
276
|
+
| 0.2.0 | Ledger v7 | 0.29.0 | None of its own. Its changes were reviewed in the Aug 2026 audit. |
|
|
277
|
+
| 0.1.0 | Ledger v7 | 0.29.0 | [May 2026](./audits/2026-05-v0.1.0.pdf) |
|
|
278
|
+
|
|
279
|
+
Scopes and audited commits are listed in [audits](./audits/README.md).
|
|
280
|
+
|
|
281
|
+
Please report any security issues you find to <security@openzeppelin.com>. See [SECURITY.md](SECURITY.md).
|
|
274
282
|
|
|
275
283
|
### Provenance
|
|
276
284
|
|
package/access/Ownable.compact
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0 (access/ShieldedAccessControl.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
|
@@ -108,8 +108,8 @@ pragma language_version >= 0.23.0;
|
|
|
108
108
|
* depends on the number of plausible `(role, accountId)` pairings. Since role identifiers
|
|
109
109
|
* are public, the anonymity set is effectively the number of plausible account IDs per role.
|
|
110
110
|
* - Outside observers will know when roles are granted and revoked.
|
|
111
|
-
* - Outside observers can infer the total number of role
|
|
112
|
-
*
|
|
111
|
+
* - Outside observers can infer the total number of distinct `(role, accountId)` pairings granted
|
|
112
|
+
* across all roles, not per-role counts.
|
|
113
113
|
* - Outside observers can link calls made by the same role instance across time.
|
|
114
114
|
* - Users can be retroactively deanonymized if their secret key is exposed.
|
|
115
115
|
* - Outside observers will NOT be able to identify the holder of any role
|
|
@@ -133,29 +133,20 @@ pragma language_version >= 0.23.0;
|
|
|
133
133
|
* - It's strongly recommended to use cryptographically secure random values for the `_instanceSalt`.
|
|
134
134
|
* Failure to do so may weaken privacy guarantees.
|
|
135
135
|
* - The `_instanceSalt` is immutable and used to differentiate deployments.
|
|
136
|
-
* - The `_operatorRoles` Merkle tree has a fixed capacity of 2^20 leaf slots.
|
|
137
|
-
*
|
|
138
|
-
* capacity through repeated grants of the same active (role, accountId) pairing.
|
|
139
|
-
* Duplicate grants are benign from a security perspective. They produce identical
|
|
140
|
-
* commitments and a single nullifier invalidates all copies; however, they waste tree capacity.
|
|
141
|
-
* Implementing contracts are responsible for mitigating tree exhaustion risk.
|
|
136
|
+
* - The `_operatorRoles` Merkle tree has a fixed capacity of 2^20 leaf slots. Each distinct
|
|
137
|
+
* `(role, accountId)` pairing consumes one slot; re-granting an active pairing is a no-op.
|
|
142
138
|
* - A single `secretKey` compromise exposes all roles held by that user within the contract
|
|
143
139
|
* instance, since all roles share the same `accountId`. Users requiring compartmentalization
|
|
144
140
|
* between roles should use separate keys per role and accept the additional key management overhead.
|
|
145
141
|
* In the event of key compromise, the user should coordinate with admins to revoke all roles
|
|
146
142
|
* under the compromised `accountId` and re-grant under a new identity.
|
|
147
|
-
* -
|
|
148
|
-
*
|
|
149
|
-
* nullifier for that pairing, blocking any future grant. Admin trust is a fundamental
|
|
150
|
-
* assumption of this system. Off-chain validation should confirm that a pairing was actually
|
|
151
|
-
* granted before submitting a revocation transaction.
|
|
152
|
-
* - `renounceRole` allows burning nullifiers for roles the caller does not currently hold,
|
|
153
|
-
* provided they possess the correct `secretKey`. This requires knowledge of the secret key,
|
|
154
|
-
* at which point the `accountId` should be considered fully compromised regardless.
|
|
143
|
+
* - A `(role, accountId)` pairing can only be revoked after it was granted, so the nullifier
|
|
144
|
+
* set holds at most one entry per granted pairing.
|
|
155
145
|
* - The Merkle tree capacity of 2^20 leaf slots is a permanent, irrecoverable resource.
|
|
156
146
|
* There is no mechanism to reclaim slots after revocation, no upgrade path, and no emergency
|
|
157
147
|
* recovery. Once exhausted, the contract is permanently unable to grant new roles. Deployers
|
|
158
|
-
* must monitor slot consumption off-chain and plan capacity accordingly.
|
|
148
|
+
* must monitor slot consumption off-chain and plan capacity accordingly. The exported tree
|
|
149
|
+
* reports occupancy via `firstFree()` (TypeScript) and `isFull()` (circuit).
|
|
159
150
|
*
|
|
160
151
|
* @notice Using the SHA256 hashing function comes at a significant performance cost. In the future, we
|
|
161
152
|
* plan on migrating to a ZK-friendly hashing function when an implementation is available.
|
|
@@ -209,6 +200,14 @@ module ShieldedAccessControl {
|
|
|
209
200
|
*/
|
|
210
201
|
export ledger _roleCommitmentNullifiers: Set<RoleNullifier>;
|
|
211
202
|
|
|
203
|
+
/**
|
|
204
|
+
* @description Nullifiers of every pairing ever granted. Makes a repeated grant a no-op so
|
|
205
|
+
* one pairing can never consume more than one `_operatorRoles` slot, and gates revocation
|
|
206
|
+
* so a nullifier can only exist for a granted pairing.
|
|
207
|
+
* @type {Set<RoleNullifier>} _grantedRoleNullifiers
|
|
208
|
+
*/
|
|
209
|
+
export ledger _grantedRoleNullifiers: Set<RoleNullifier>;
|
|
210
|
+
|
|
212
211
|
/**
|
|
213
212
|
* @sealed @ledger _instanceSalt
|
|
214
213
|
* @description A per-instance value provided at initialization used to namespace
|
|
@@ -387,9 +386,8 @@ module ShieldedAccessControl {
|
|
|
387
386
|
|
|
388
387
|
/**
|
|
389
388
|
* @description Grants `role` to `accountId` by inserting a role commitment unique to the
|
|
390
|
-
* `(role, accountId)` pairing into the `_operatorRoles` Merkle tree.
|
|
391
|
-
*
|
|
392
|
-
* limited Merkle tree storage slots. Once revoked, a role cannot be re-granted to the same `accountId`. A new
|
|
389
|
+
* `(role, accountId)` pairing into the `_operatorRoles` Merkle tree. Granting an already active
|
|
390
|
+
* pairing is a no-op. Once revoked, a role cannot be re-granted to the same `accountId`. A new
|
|
393
391
|
* `accountId` must be generated to be re-authorized for a revoked `role`.
|
|
394
392
|
*
|
|
395
393
|
* Requirements:
|
|
@@ -419,9 +417,8 @@ module ShieldedAccessControl {
|
|
|
419
417
|
|
|
420
418
|
/**
|
|
421
419
|
* @description Grants `role` to `accountId` by inserting a role commitment unique to the
|
|
422
|
-
* `(role, accountId)` pairing into the `_operatorRoles` Merkle tree.
|
|
423
|
-
*
|
|
424
|
-
* limited Merkle tree storage slots. Once revoked, a role cannot be re-granted to the same `accountId`. A new
|
|
420
|
+
* `(role, accountId)` pairing into the `_operatorRoles` Merkle tree. Granting an already active
|
|
421
|
+
* pairing is a no-op. Once revoked, a role cannot be re-granted to the same `accountId`. A new
|
|
425
422
|
* `accountId` must be generated to be re-authorized for a revoked `role`.
|
|
426
423
|
*
|
|
427
424
|
* Internal circuit without access restriction.
|
|
@@ -429,10 +426,8 @@ module ShieldedAccessControl {
|
|
|
429
426
|
* @warning Exposing this circuit directly in an implementing contract would allow anyone to grant
|
|
430
427
|
* roles without authorization. It must be wrapped with appropriate access control.
|
|
431
428
|
*
|
|
432
|
-
* @warning The `_operatorRoles` Merkle tree has a fixed capacity of 2^20 leaf slots
|
|
433
|
-
* Deployers should monitor slot consumption off-chain.
|
|
434
|
-
* but are otherwise benign. A single nullifier invalidates all duplicate commitments.
|
|
435
|
-
* Implementing contracts are responsible for mitigating tree exhaustion risk.
|
|
429
|
+
* @warning The `_operatorRoles` Merkle tree has a fixed capacity of 2^20 leaf slots, one per
|
|
430
|
+
* distinct pairing. Deployers should monitor slot consumption off-chain.
|
|
436
431
|
*
|
|
437
432
|
* Requirements:
|
|
438
433
|
*
|
|
@@ -462,6 +457,7 @@ module ShieldedAccessControl {
|
|
|
462
457
|
* @notice Roles are often managed via {grantRole} and {revokeRole}: this circuit's
|
|
463
458
|
* purpose is to provide a mechanism for accounts to lose their privileges
|
|
464
459
|
* if they are compromised (such as when a trusted device is misplaced).
|
|
460
|
+
* Consumers with no need for self-revocation should not export this circuit.
|
|
465
461
|
*
|
|
466
462
|
* @warning Outside observers may be able to use timing and pattern analysis to weaken pseudonymity
|
|
467
463
|
* guarantees if renounceRole is used in tandem with other on-chain actions.
|
|
@@ -469,6 +465,7 @@ module ShieldedAccessControl {
|
|
|
469
465
|
* Requirements:
|
|
470
466
|
*
|
|
471
467
|
* - The caller must provide a valid `accountId` for the role.
|
|
468
|
+
* - The `(role, accountId)` pairing must have been granted.
|
|
472
469
|
* - The `(role, accountId)` pairing must not be already revoked.
|
|
473
470
|
* - Contract is initialized.
|
|
474
471
|
*
|
|
@@ -494,13 +491,13 @@ module ShieldedAccessControl {
|
|
|
494
491
|
/**
|
|
495
492
|
* @description Permanently revokes `role` from `accountId` by inserting a role nullifier into the
|
|
496
493
|
* `_roleCommitmentNullifiers` set. Once revoked, a new `accountId` must be generated to be re-authorized for
|
|
497
|
-
* `role`.
|
|
498
|
-
* so a `(role, accountId)` pairing that does not exist can still be revoked.
|
|
494
|
+
* `role`.
|
|
499
495
|
*
|
|
500
496
|
* Requirements:
|
|
501
497
|
*
|
|
502
498
|
* - caller must prove they're an admin for `role`.
|
|
503
499
|
* - caller must not provide valid Merkle tree path for a different `(role, accountId)` pairing.
|
|
500
|
+
* - The `(role, accountId)` pairing must have been granted.
|
|
504
501
|
* - The `(role, accountId)` pairing must not be already revoked.
|
|
505
502
|
* - Contract is initialized.
|
|
506
503
|
*
|
|
@@ -525,8 +522,7 @@ module ShieldedAccessControl {
|
|
|
525
522
|
/**
|
|
526
523
|
* @description Permanently revokes `role` from `accountId` by inserting a role nullifier into the
|
|
527
524
|
* `_roleCommitmentNullifiers` set. Once revoked, a new `accountId` must be generated to be re-authorized for
|
|
528
|
-
* `role`.
|
|
529
|
-
* so a `(role, accountId)` pairing that does not exist can still be revoked.
|
|
525
|
+
* `role`.
|
|
530
526
|
*
|
|
531
527
|
* Internal circuit without access restriction.
|
|
532
528
|
*
|
|
@@ -535,6 +531,7 @@ module ShieldedAccessControl {
|
|
|
535
531
|
*
|
|
536
532
|
* Requirements:
|
|
537
533
|
*
|
|
534
|
+
* - The `(role, accountId)` pairing must have been granted.
|
|
538
535
|
* - The `(role, accountId)` pairing must not be already revoked.
|
|
539
536
|
* - Contract is initialized.
|
|
540
537
|
*
|
|
@@ -555,13 +552,14 @@ module ShieldedAccessControl {
|
|
|
555
552
|
/**
|
|
556
553
|
* @description Core business logic for the grant/revoke role circuits. Asserts that the
|
|
557
554
|
* `(role, accountId)` pairing has not already been revoked. On success, dispatches on
|
|
558
|
-
* `updateType`: a `Grant` inserts the role commitment into `_operatorRoles
|
|
559
|
-
* a `Revoke`
|
|
555
|
+
* `updateType`: a `Grant` inserts the role commitment into `_operatorRoles` unless the
|
|
556
|
+
* nullifier is already in `_grantedRoleNullifiers`, and a `Revoke` asserts the nullifier
|
|
557
|
+
* is in `_grantedRoleNullifiers` before inserting it into `_roleCommitmentNullifiers`.
|
|
560
558
|
*
|
|
561
559
|
* Disclosures:
|
|
562
560
|
*
|
|
563
561
|
* - A nullifier for the respective role commitment.
|
|
564
|
-
* - A role commitment (on Grant only).
|
|
562
|
+
* - A role commitment (on first Grant only).
|
|
565
563
|
*
|
|
566
564
|
* @notice The nullifier is disclosed via `_roleCommitmentNullifiers.member` on every call,
|
|
567
565
|
* regardless of the update type. Since `Set.member` publicly reveals its argument, the
|
|
@@ -584,9 +582,14 @@ module ShieldedAccessControl {
|
|
|
584
582
|
const isRevoked = _roleCommitmentNullifiers.member(disclose(roleNullifier));
|
|
585
583
|
assert(!isRevoked, "ShieldedAccessControl: role is already revoked");
|
|
586
584
|
|
|
585
|
+
const isGranted = _grantedRoleNullifiers.member(disclose(roleNullifier));
|
|
587
586
|
if (updateType == UpdateType.Grant) {
|
|
588
|
-
|
|
587
|
+
if (!isGranted) {
|
|
588
|
+
_grantedRoleNullifiers.insert(disclose(roleNullifier));
|
|
589
|
+
_operatorRoles.insert(disclose(roleCommitment));
|
|
590
|
+
}
|
|
589
591
|
} else {
|
|
592
|
+
assert(isGranted, "ShieldedAccessControl: role was never granted");
|
|
590
593
|
_roleCommitmentNullifiers.insert(disclose(roleNullifier));
|
|
591
594
|
}
|
|
592
595
|
}
|
package/crypto/EcdhMask.compact
CHANGED
package/crypto/ElGamal.compact
CHANGED
package/multisig/Signer.compact
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0 (multisig/presets/forwarder/ForwarderPrivate.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0 (multisig/presets/forwarder/ForwarderShielded.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0 (multisig/presets/forwarder/ForwarderUnshielded.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0 (token/ConfidentialFungibleToken.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
|
@@ -1037,7 +1037,7 @@ module ConfidentialFungibleToken {
|
|
|
1037
1037
|
* caller via `approve`) and credits it to `to`, reducing both escrow copies by
|
|
1038
1038
|
* `value`. The amount is hidden.
|
|
1039
1039
|
*
|
|
1040
|
-
*
|
|
1040
|
+
* @circuitInfo k=16, rows=72346
|
|
1041
1041
|
*
|
|
1042
1042
|
* @notice Returns the caller's (spender's) `accountId` for caller-side gating.
|
|
1043
1043
|
*
|
|
@@ -1286,7 +1286,7 @@ module ConfidentialFungibleToken {
|
|
|
1286
1286
|
* recipient credit. The building block for a composing contract's
|
|
1287
1287
|
* `burnFrom`; it performs no supply accounting (see `_burn`).
|
|
1288
1288
|
*
|
|
1289
|
-
*
|
|
1289
|
+
* @circuitInfo k=16, rows=45376
|
|
1290
1290
|
*
|
|
1291
1291
|
* Requirements:
|
|
1292
1292
|
*
|
package/token/MultiToken.compact
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0 (token/examples/ZOwnableNativeShieldedTokenExample.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0 (token/extensions/ConfidentialFungibleTokenPublicSupply.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.3.0
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.3.0 (token/extensions/NativeShieldedTokenDerivedNonce.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.23.0;
|
|
5
5
|
|
package/utils/Utils.compact
CHANGED