Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
363 commits
Select commit Hold shift + click to select a range
323b66f
parameterize tests
andrew-fleming Aug 13, 2025
00efb15
fix fmt
andrew-fleming Aug 13, 2025
81ebb9f
add ledger and witness docs
andrew-fleming Aug 13, 2025
c5417c1
Revert "Add contractAddress to nonce generation scheme"
emnul Aug 13, 2025
db5821f
Update hashing scheme
emnul Aug 13, 2025
98c86db
Update hash function in witness
emnul Aug 13, 2025
b556fad
improve computeOwnerId assertion
andrew-fleming Aug 15, 2025
a880f8d
use _computeOwnerId in assertOnlyOwner
andrew-fleming Aug 15, 2025
de69018
fix fmt
andrew-fleming Aug 15, 2025
92b46a8
add wrapAsEither circuits
andrew-fleming Aug 16, 2025
9fc5bbe
add option to compile directory in compact
andrew-fleming Aug 17, 2025
98b7a32
add granular compile scripts
andrew-fleming Aug 17, 2025
ae9e311
fix fmt
andrew-fleming Aug 17, 2025
4a9885b
use fast compilation prior to tests, cache tests
andrew-fleming Aug 17, 2025
6fb3f74
add circuit tag
andrew-fleming Aug 17, 2025
6161001
fix conflicts
andrew-fleming Aug 17, 2025
2ac92b5
move ZOwnablePK witness interface
andrew-fleming Aug 17, 2025
db87258
improve in-code docs
andrew-fleming Aug 18, 2025
9d78542
add ZOwnablePK api
andrew-fleming Aug 18, 2025
96f95c9
add withNonce to PS
andrew-fleming Aug 18, 2025
c16cd7d
add ZOwnablePK docs (less setup)
andrew-fleming Aug 18, 2025
3586158
improve sec prop section
andrew-fleming Aug 18, 2025
33148b0
fix fmt
andrew-fleming Aug 18, 2025
71ad93f
add usage section
andrew-fleming Aug 18, 2025
d707d28
revert changes
andrew-fleming Aug 18, 2025
e018e03
fix typo
andrew-fleming Aug 18, 2025
d113802
update readme with targeted compilation
andrew-fleming Aug 18, 2025
b3a0bd4
add k and rows
andrew-fleming Aug 24, 2025
f3e2872
add constraints to docs
andrew-fleming Aug 24, 2025
7b57e93
add SKIP_ZK env var to compile
andrew-fleming Aug 25, 2025
822fcd6
improve docs
andrew-fleming Aug 25, 2025
1c36f67
update README
andrew-fleming Aug 25, 2025
c676fd0
Apply suggestions from code review
andrew-fleming Aug 25, 2025
0cd3c59
change generic H to SHA256 in docs
andrew-fleming Aug 25, 2025
06f3c83
change generic H to SHA256
andrew-fleming Aug 25, 2025
8e28bda
fix lang version in mock
andrew-fleming Aug 25, 2025
9b3e97c
add bad owner id hash scenario
andrew-fleming Aug 26, 2025
35d95d3
Merge branch 'main' into shielded-access-control
emnul Aug 26, 2025
490af83
Apply suggestions from code review
andrew-fleming Aug 26, 2025
018ba5c
improve create proxy constraints, cast circuits to the extracted type…
andrew-fleming Aug 26, 2025
12a06c7
Apply suggestions from code review
andrew-fleming Aug 26, 2025
1b55a09
Remove old dir, rename files
emnul Aug 26, 2025
8e5dd6b
Apply suggestions from code review
andrew-fleming Aug 27, 2025
b100b9e
add AGPK section
andrew-fleming Aug 27, 2025
15aff68
fix guide links in access api, add agpk ref
andrew-fleming Aug 27, 2025
524dab9
add agpk recommendation
andrew-fleming Aug 27, 2025
7ba770d
WIP Experimental re-design
emnul Aug 27, 2025
a3e6a3a
add descriptions to circuits in sim
andrew-fleming Aug 27, 2025
a22ba6c
fix sim state mngr, improve docs
andrew-fleming Aug 27, 2025
37bb7aa
fix fmt
andrew-fleming Aug 27, 2025
02227ab
add non-deterministic sig warning
andrew-fleming Aug 27, 2025
b584c53
add period
andrew-fleming Aug 27, 2025
418a7b5
improve agpk principles
andrew-fleming Aug 27, 2025
bd18c19
improve clarity on 'never used elsewhere'
andrew-fleming Aug 27, 2025
acf3397
add wit_ prefix to witnesses
andrew-fleming Aug 28, 2025
8489924
Apply suggestions from code review
andrew-fleming Aug 28, 2025
67972b9
remove artifacts from inputs
andrew-fleming Aug 28, 2025
f23e56a
fix fmt
andrew-fleming Aug 28, 2025
efaa2a0
Apply suggestions from code review
andrew-fleming Aug 28, 2025
be5b418
Merge branch 'main' into improve-turbo-restructure
andrew-fleming Aug 28, 2025
a902206
Merge branch 'main' into shielded-access-control
emnul Aug 28, 2025
7ad70e6
Merge branch 'improve-turbo-restructure' into shielded-access-control
emnul Aug 28, 2025
eb3d4bc
rebase
andrew-fleming Aug 28, 2025
32a80ff
Merge branch 'add-ownable-shielded' of https://github.com/andrew-flem…
emnul Aug 28, 2025
365b7fd
Merge branch 'main' into shielded-access-control
emnul Aug 28, 2025
e48e6b8
Merge branch 'add-ownable-shielded' into shielded-access-control
emnul Aug 28, 2025
c16a6be
Construct simulator and witnesses for impl
emnul Aug 29, 2025
5882005
Merge branch 'main' into shielded-access-control
emnul Sep 2, 2025
9117fc6
Restrict usage to ZSwapCoinPubKeys, simplify logic
emnul Sep 2, 2025
e77d127
Update *.compact testing dependencies
emnul Sep 2, 2025
0c33611
Add helper fn, update API for improved flexibility
emnul Sep 2, 2025
e3cb30d
Use helper in witness impl
emnul Sep 2, 2025
95821e0
Init tests
emnul Sep 2, 2025
52000a2
Update simulator initialization
emnul Sep 2, 2025
3af7b9a
Update hashing scheme
emnul Sep 3, 2025
8d23061
Fix incorrect default MerkleTreePath construction
emnul Sep 3, 2025
47f5d3e
Improve typesafety of try catch block, add debugging logic
emnul Sep 3, 2025
c607923
Add initialization checks, correct role commitment checks
emnul Sep 3, 2025
dc5aed7
Merge branch 'main' into shielded-access-control
emnul Sep 3, 2025
4140f3b
Use correct MT API
emnul Sep 4, 2025
67f36aa
Add utility fn and improve logging
emnul Sep 4, 2025
99fa0be
add test
emnul Sep 4, 2025
4b1ff86
Fix typo in filename
emnul Sep 8, 2025
9a735b2
Update imports
emnul Sep 8, 2025
2f375ba
Update witness fn signatures
emnul Sep 8, 2025
a5a1763
Update constructor, witnesses setter
emnul Sep 8, 2025
353b379
Add bad index tests
emnul Sep 8, 2025
1fa7122
Merge branch 'main' into shielded-access-control
emnul Sep 8, 2025
26d3576
Update Role field name
emnul Sep 8, 2025
da274c4
Add tests
emnul Sep 8, 2025
7ae6407
Remove _unsafeGrantRole
emnul Sep 8, 2025
5a1b0b4
Improve tests
emnul Sep 8, 2025
923d779
Add helper method
emnul Sep 8, 2025
07dd40b
Change privateState fn signatures
emnul Sep 9, 2025
fdcf13c
Add tests
emnul Sep 9, 2025
b08a600
Merge branch 'main' into shielded-access-control
emnul Sep 11, 2025
7e6a6a0
Should not throw if commitment in nullifer set
emnul Sep 11, 2025
8e5c26f
Export nullifiers for testing
emnul Sep 11, 2025
dd0cd82
Rename var and change return behavior
emnul Sep 11, 2025
f24eeb0
Add _checkRole, grantRole tests
emnul Sep 11, 2025
2cb227e
fmt files
emnul Sep 11, 2025
061ac4a
WIP
emnul Sep 12, 2025
a98144e
Update contracts/src/access/witnesses/ShieldedAccessControlWitnesses.ts
emnul Sep 15, 2025
9d9c256
Optimize loop
emnul Sep 15, 2025
52936ef
Merge branch 'shielded-access-control' of https://github.com/OpenZepp…
emnul Sep 15, 2025
5d2da06
Refactor Shielded Design
emnul Sep 17, 2025
713d3d4
Move resetProxy call to end of fn
emnul Sep 17, 2025
8a5fbba
Fixes incorrect indexing bug
emnul Sep 17, 2025
2fce76c
WIP refactor tests
emnul Sep 17, 2025
306ec1f
Merge branch 'main' into shielded-access-control
emnul Sep 17, 2025
2fb86e7
Fix compiler errors, refactor mock and witnesses
emnul Sep 17, 2025
a2e644d
Refactor test suite
emnul Sep 19, 2025
16928c3
Refactor simulator for new design
emnul Sep 19, 2025
740bb83
WIP
emnul Sep 25, 2025
a6feeff
Remove old
emnul Feb 24, 2026
ccdbe85
Merge branch 'main' into shielded-access-control
emnul Feb 24, 2026
7df0378
Remove unused file
emnul Feb 24, 2026
a6f0eaa
WIP
emnul Feb 24, 2026
dc5001f
Use standard insert method over insertHash
emnul Feb 25, 2026
5a817c9
Update circuit docs
emnul Feb 26, 2026
88355c8
Improve naming, remove dead code, narrow circuit responsibility
emnul Feb 26, 2026
266e0fd
Update module docs
emnul Feb 26, 2026
efdf636
Add nominal type aliases
emnul Feb 26, 2026
1186e51
Refactor witness file
emnul Feb 26, 2026
e819d8d
Change prefix
emnul Feb 26, 2026
1b59084
Refactor simulator
emnul Feb 26, 2026
aef1ed3
Update error message
emnul Feb 26, 2026
1f3349d
rename param
emnul Feb 26, 2026
d4f6b8d
Refactor tests
emnul Feb 26, 2026
e67fc4a
Add Initializable
emnul Feb 27, 2026
01153f0
Refactor sim
emnul Feb 27, 2026
1a3bb3d
improve naming
emnul Feb 27, 2026
bf99e94
WIP refactor tests
emnul Feb 27, 2026
16b0ecd
Add helper methods to sim
emnul Feb 27, 2026
5ddbe1e
Enforce single use role commitments
emnul Feb 28, 2026
f91d346
WIP tests
emnul Feb 28, 2026
b541593
Refactor docs
emnul Feb 28, 2026
13d142c
move disclosure closer to disclosure point
emnul Mar 1, 2026
a5268f6
Reduce metadata leakage
emnul Mar 2, 2026
6a4d55e
Update witness file
emnul Mar 2, 2026
82170b8
Export circuit from Mock
emnul Mar 2, 2026
f3279b4
Update simulator
emnul Mar 2, 2026
0be3e5c
Update method name, assert Initialized in computeAccountId
emnul Mar 2, 2026
5c67ac8
fmt file
emnul Mar 2, 2026
9601c4d
Add assertion to _checkRole
emnul Mar 2, 2026
8053d17
fmt file
emnul Mar 2, 2026
287f7bb
Update default Merkle tree value
emnul Mar 2, 2026
8aedd88
Simplify return statement
emnul Mar 3, 2026
d80091b
fmt files
emnul Mar 3, 2026
d3fa7f7
reorganize code, inline auth logic in _grant/revokeRole
emnul Mar 3, 2026
3a016b1
Update circuit info
emnul Mar 4, 2026
3bb9e4c
WIP commit
emnul Mar 5, 2026
e3cf7e9
Revert "WIP commit"
emnul Mar 5, 2026
1c5f803
Reapply "WIP commit"
emnul Mar 5, 2026
8d9713a
WIP commit
emnul Mar 5, 2026
ae13104
Merge branch 'main' into shielded-access-control
pepebndc Mar 6, 2026
ecbe0da
Add tests for shielded access control
pepebndc Mar 6, 2026
a34d7f5
Merge branch 'shielded-access-control' of https://github.com/OpenZepp…
emnul Mar 6, 2026
d081342
Assert instance salt is not 0
emnul Mar 7, 2026
dc8b522
Merge remote-tracking branch 'origin/feat/tests-shielded-access-contr…
emnul Mar 8, 2026
154938e
Apply suggestions from code review
emnul Mar 8, 2026
c7b3d2a
Merge branch 'shielded-access-control' of https://github.com/OpenZepp…
emnul Mar 8, 2026
3cfa7af
strange compact compiler bug
emnul Mar 8, 2026
a5fe6d1
add tests
emnul Mar 8, 2026
ac33519
update assertion message
emnul Mar 8, 2026
12818f8
Sync mock implementation
emnul Mar 9, 2026
e5b402d
update tests
emnul Mar 9, 2026
a10b9bb
big refactor
emnul Mar 10, 2026
09e4a21
Remove unused witness
emnul Mar 10, 2026
813fa99
update simulator
emnul Mar 10, 2026
36a6d0a
refactor tests
emnul Mar 10, 2026
f2ee664
Update description
emnul Mar 10, 2026
1a74761
Update test
emnul Mar 10, 2026
67b85d1
Refactor contract
emnul Mar 11, 2026
8fefb4e
Refactor simulator
emnul Mar 11, 2026
e8ba943
refactor: harden the shieldedaccesscontrol lib by some improvements a…
0xisk Mar 11, 2026
81002bf
Revert "refactor: harden the shieldedaccesscontrol lib by some improv…
0xisk Mar 11, 2026
d67a369
fmt files, add export to mock
emnul Mar 11, 2026
7546ffd
Add additional documentation
emnul Mar 11, 2026
5f654fc
remove unused types
emnul Mar 11, 2026
ac1077a
Add tests and lint files
emnul Mar 11, 2026
bec51ca
Merge branch 'shielded-access-control' of https://github.com/OpenZepp…
emnul Mar 11, 2026
4757096
fmt file
emnul Mar 11, 2026
187f23f
add test
emnul Mar 12, 2026
593bcc0
refactor files: roleId -> role
emnul Mar 12, 2026
b775993
rm old tests
emnul Mar 12, 2026
4e59f2b
Merge branch 'main' into shielded-access-control
pepebndc Mar 12, 2026
196843e
Simplify internal circuit signature
emnul Mar 12, 2026
036c66c
Merge branch 'shielded-access-control' of https://github.com/OpenZepp…
emnul Mar 12, 2026
1900f04
Remove initialization checks from internal circuits
emnul Mar 12, 2026
fcb9a16
Revert "Remove initialization checks from internal circuits"
emnul Mar 12, 2026
fbe1df8
Reapply "Remove initialization checks from internal circuits"
emnul Mar 12, 2026
80dd34d
Update docs reorganize code
emnul Mar 13, 2026
d38c6dc
Add unchecked circuits
emnul Mar 13, 2026
1b6c2a5
remove init checks from get / set admin circuits
emnul Mar 13, 2026
819c821
fix circuit def
emnul Mar 13, 2026
15a113b
Add unexported circuits to mock
emnul Mar 13, 2026
8f536e0
Fmt Mock
emnul Mar 13, 2026
452c2d9
Add _uncheckedCircuits to sim, tests, fix mock export
emnul Mar 13, 2026
d989f34
Remove admin identifier
emnul Mar 13, 2026
ac4853d
Update docs
emnul Mar 13, 2026
c7d06c0
remove ledger artifact from wit, update sim
andrew-fleming Mar 14, 2026
7e27f80
remove ledger artifact from wit, update sim in zownable
andrew-fleming Mar 14, 2026
7ea82e9
update sim readme
andrew-fleming Mar 14, 2026
c74f42f
add changelog entry
andrew-fleming Mar 14, 2026
f802a54
improve witness docs
andrew-fleming Mar 14, 2026
bcb4ce1
update changelog
andrew-fleming Mar 14, 2026
1b4f5c3
Merge branch 'main' into remove-artifact-ledger-from-witnesses
andrew-fleming Mar 16, 2026
72ed9a5
refactor: test should compare circuit result not callback
emnul Mar 16, 2026
bbbdba9
refactor: test should compare root value not object
emnul Mar 16, 2026
9ed5fec
refactor: DEFAULT_ADMIN_ROLE into pure circuit
emnul Mar 16, 2026
85c71d9
Update mock, sim, and tests with DEFAULT_ADMIN_ROLE circuit
emnul Mar 16, 2026
bc2d635
Update type
emnul Mar 16, 2026
dbdff4c
Update contracts/src/access/witnesses/ShieldedAccessControlWitnesses.ts
emnul Mar 16, 2026
b407b7c
Add matcher for assertion
emnul Mar 16, 2026
67b4753
Merge branch 'shielded-access-control' of https://github.com/OpenZepp…
emnul Mar 16, 2026
6d6e064
Throw error if role nonce is undefined
emnul Mar 17, 2026
7e5f144
Add README to contracts directory
emnul Mar 17, 2026
e001b10
Add disclaimer to all Mock files
emnul Mar 17, 2026
dc3737e
Update contracts/src/access/ShieldedAccessControl.compact
emnul Mar 17, 2026
7c1427a
Update circuit requirements
emnul Mar 17, 2026
99b18c6
Refactor: Remove _uncheckedAssert, keep _grant / _revoke DRY
emnul Mar 17, 2026
75e6dcb
Refactor: remove references to _uncheckedAssert
emnul Mar 17, 2026
72fa7b3
Remove warning from pure circuit
emnul Mar 17, 2026
b2defa9
revert changes to simulator test utils
emnul Mar 17, 2026
79ad5a3
rename circuit
emnul Mar 17, 2026
944d251
Update circuitInfo
emnul Mar 17, 2026
9c86e1a
Remove tests
emnul Mar 17, 2026
8c6ad6d
Merge branch 'main' into shielded-access-control
emnul Mar 17, 2026
e7f5be1
Merge branch 'remove-artifact-ledger-from-witnesses' into shielded-ac…
emnul Mar 17, 2026
bc1ded2
Use generic witness pattern
emnul Mar 17, 2026
748ee62
Add interface to computeAccountId locally, export _computeNullifier a…
emnul Mar 18, 2026
a7566b1
Update tests and simulator
emnul Mar 18, 2026
d24eae9
Remove README
emnul Mar 18, 2026
7b2ef89
Merge branch 'main' into shielded-access-control
emnul Mar 18, 2026
8c8ea72
Update contracts/src/access/ShieldedAccessControl.compact
emnul Mar 18, 2026
c5b34f6
Update contracts/src/access/ShieldedAccessControl.compact
emnul Mar 18, 2026
38b4696
Update contracts/src/access/ShieldedAccessControl.compact
emnul Mar 18, 2026
cc56b39
Update contracts/src/access/ShieldedAccessControl.compact
emnul Mar 18, 2026
dbc85f4
update _setRoleAdmin docs
emnul Mar 18, 2026
8a21058
Merge branch 'shielded-access-control' of https://github.com/OpenZepp…
emnul Mar 18, 2026
7729e67
Update circuit _computeNull and _computeRoleCom names
emnul Mar 18, 2026
9bd47ea
Refactor names in tests / sim
emnul Mar 18, 2026
28cc91e
Refactor _computeAccountId to depend on pure variant, rename pure var…
emnul Mar 18, 2026
ea50c07
Update error message
emnul Mar 19, 2026
9d7f148
Merge branch 'main' into shielded-access-control
0xisk Mar 23, 2026
00d521b
chore: add warning for the exported grant and revoke functions
0xisk Mar 23, 2026
dcf6e7e
chore(access): same ordering everywhere (#410)
0xisk Mar 27, 2026
3c41f95
refactor(access): adding more test cases for shielded access control …
0xisk Mar 27, 2026
6c3f220
Merge branch 'main' into shielded-access-control
andrew-fleming Mar 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Add defensive Buffer copy to ZOwnablePKWitnesses (#397)
- Disclose commitment instead of raw owner id in `_transferOwnership` in ZOwnablePK (#397)
- Use generic ledger type in ZOwnablePKWitnesses (#389)
- Bump compact compiler to v0.29.0 (#366)

## 0.0.1-alpha.1 (2025-12-2)
Expand Down
764 changes: 764 additions & 0 deletions contracts/src/access/ShieldedAccessControl.compact
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @emnul! Looking good! I have some points here and opened this refactor PR to fix them: #382

  1. Type aliases add unnecessary indirectionRoleIdentifier, AdminIdentifier, and AccountIdentifier are thin aliases over Bytes<32> and don't carry enough semantic weight to justify the abstraction. Replaced uniformly with Bytes<32> in the refactor; only RoleCommitment (the Merkle leaf type) is meaningful enough to retain.

  2. Circuit names and signatures diverge from OZ Solidity AccessControl conventions

proveCallerRole, assertOnlyRole, and _validateRole don't map to anything a consumer of the Solidity interface would recognize. Beyond renaming, OZ's AccessControl also exposes two variants of each check — one for the caller and one for an arbitrary account. The current code only supported the caller variant:

before                         after
──────────────────────────     ──────────────────────────────────────
proveCallerRole(role)          hasRole(role)
                               hasRole(role, account)

assertOnlyRole(role)           _checkRole(role)
                               _checkRole(role, account)

_validateRole(role, accountId) _hasRole(role, accountId)

Supporting the two-argument overloads also required extracting _onlyRole(role, accountId) as a shared private primitive (which also solves point 5) — the old assertOnlyRole had identity derivation (ownPublicKey()) baked in and could not be reused for an arbitrary account. The two _checkRole overloads both delegate to _onlyRole after computing the accountId from their respective inputs:

_checkRole(role)              _checkRole(role, account)
      │                               │
_computeAccountId(role,         _computeAccountId(role,
    ownPublicKey())                  account)
      │                               │
      └───────────────┬───────────────┘
                      │
               _onlyRole(role, accountId)
                      │
         assert(_hasRole(role, accountId),
                "unauthorized account")
  1. _computeAccountId exposes the nonce as a parameter, breaking encapsulation — The original signature (zcpk, nonce) requires callers to explicitly pass the secret nonce, spreading witness handling across call sites. The refactor changes the signature to (role, account) and fetches the nonce internally via wit_secretNonce(role), making the witness boundary consistent and reducing the risk of misuse.

  2. No public wrapper for account ID computation_computeAccountId was purely internal with no way to call it from a top-level contract. Added computeAccountId as an exported wrapper.

  3. Redundant init checks fired repeatedly down the call chain In the current code, nearly every circuit called Initializable_assertInitialized() independently — including internal helpers. This meant a single grantRole call triggered the check 6 times:

grantRole
├─ Initializable_assertInitialized()          ← #1
├─ getRoleAdmin(role)
│   └─ Initializable_assertInitialized()      ← #2
├─ assertOnlyRole(...)
│   ├─ Initializable_assertInitialized()      ← #3
│   └─ proveCallerRole(role)
│       ├─ Initializable_assertInitialized()  ← #4
│       └─ _validateRole(...)
│           └─ Initializable_assertInitialized() ← #5
└─ _grantRole(role, accountId)
    └─ Initializable_assertInitialized()      ← #6

The refactor extracts _getRoleAdmin and _uncheckedGrantRole / _uncheckedRevokeRole as init-check-free private primitives. The single check lives only in the public export wrapper, so the same call now fires it exactly once:

grantRole
├─ Initializable_assertInitialized()          ← #1 only
├─ _getRoleAdmin(role)                        ← no check
├─ _onlyRole(...)                             ← no check
└─ _uncheckedGrantRole(role, accountId)       ← no check
  1. Circuit ordering requires forward-jumping to follow the logic — helpers were defined before the public circuits that call them. Reorganized to follow the Stepdown Rule: public circuits first, then the internal circuits they delegate to. This does not follow the Solidity ordering as in Solidity the order is putting all the public functions first and the internal functions at the end, IMO the Stepdown rule makes reading the code way easier and streamlined.

As mentioned above all of those points are resolved in the refactor PR.

Copy link
Copy Markdown
Contributor Author

@emnul emnul Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-posting my thoughts from the PR introduced here:

  1. I'm not sold on getting rid of the nominally typed aliases. I think forcing consumers to pass Bytes<32> values as RoleIdentifier, AccountId etc makes interacting with the contract's API more safe which is one of our top concerns. It adds an extra "are you sure about that?" to every call to the Shielded module. Compact also doesn't have the same tooling maturity as other languages like an official LSP implementation for parameter hinting, go to definition etc. All we really have is the formatter and the compiler so we should use those to maximum effect to make the contracts as safe as possible.

  2. a) In my opinion it's ok to deviate from the Solidity AccessControl naming scheme in this case. The new method names are a better semantic fit for what's actually happening. hasRole implies we're performing a simple lookup but that's not what's happening under the hood. The caller is proving they have knowledge of a Merkle path to a specific commitment in the public Merkle tree. Even if the caller has the role the circuit can still fail with bad witness values. The behavior and assumptions are quite different and the API should reflect that.

    b) hasRole(role, account) and _checkRole(role, account) violate the privacy guarantees of the module by exposing ZswapCoinPublicKey in the public ledger transcript and should not be part of the public API. In general, I don't think it makes sense to have circuits that prove authorization / gate roles for arbitrary accounts when account identities are tightly coupled to a user key and a secret nonce that external accounts shouldnt have knowledge of in the first place.

  1. I updated _computeAccountId to further simplify the signature.

  2. _computeAccountId should remain internal. Exporting the circuit increases the risk that a module consumer would build flows that leak the AccountId metadata and increase linkability

  3. I'm mixed on the internal init check free circuits. I'm leaning towards adding them and think they're fine so long as we're really loud about keeping them internal, but would like @andrew-fleming 's opinion in case I'm missing anything. I'm not sure if I'm being overly concerned with the language limitations described in the comment below Shielded AccessControl #190 (comment)

  4. Is this what you mean?

    grantRole
    |_  _grantRole
    |__ _uncheckedGrantRole
    

Copy link
Copy Markdown
Member

@0xisk 0xisk Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @emnul for the good points.

  1. I agree with you! That's a good point: refactor(access): harden the shieldedaccesscontrol lib by some improvements and fixing some bugs #382 (comment) 👍

I don't think it makes sense to have circuits that prove authorization / gate roles for arbitrary accounts when account identities are tightly coupled to a user key and a secret nonce that external accounts shouldnt have knowledge of in the first place.

That's a fair point — As one motivation is to follow the Sol interface signature, another one is if there are scenarios where a batch API accepting arbitrary accounts could be useful. For example, an admin managing multiple operator keys (e.g., a DAO treasury) might want to grant/check/revoke roles for several accounts in a single circuit call rather than signing separately for each.
However, the current hasRole/_checkRole design doesn't actually enable this. The wit_secretNonce(role) witness returns a single nonce per role, so even though you can pass an arbitrary ZswapCoinPublicKey, you can't supply different nonces for different accounts in the same call. A true batch pattern would require a different circuit design that takes (account, nonce) pairs as explicit parameters.
So I agree these should be removed from the public API for now. The batch use case is worth keeping in mind as a future consideration, but it would need a purpose-built circuit design rather than the current single-account API. @andrew-fleming wdyt?

  1. 👍

  2. The user's should have this primitive to be able to recalculate their AccountId hash locally in case if they have forgotte/lost it, I think it's important utility to be used, and for the security of using it it should be kept on the developer's responsibility.

  3. Just let's make sure to be optimal as we can so that one init assert per exported circuit.

  4. Yup, however, that\s more of a personal pref which not sure if it is followed in the other modules so if you guys @andrew-fleming like it we can start following it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RE: 2b - we may have stumbled onto a disclosure bug in the Compact compiler. Check out this minimal-example I created (sorry for my spaghetti code 😅). If you scroll all the way to the bottom of test.compact you can see that the compiler definitely doesn't enforce a disclosure of account. However, if you run the test script npm run test you can see it does appear in the public transcript. If we think about it from first principles, this makes sense. A verifier cannot be convinced of the validity of a proof for a set of public inputs without having knowledge of the public inputs themselves

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I agree these should be removed from the public API for now. The batch use case is worth keeping in mind as a future consideration, but it would need a purpose-built circuit design rather than the current single-account API

Totally agree, enabling batching would be it's own can of worms esp in the ZK context where everything must be deterministic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Circuit names and signatures diverge from OZ Solidity AccessControl conventions
    proveCallerRole, assertOnlyRole, and _validateRole don't map to anything a consumer of the Solidity interface would recognize. Beyond renaming, OZ's AccessControl also exposes two variants of each check — one for the caller and one for an arbitrary account. The current code only supported the caller variant...

a) In my opinion it's ok to deviate from the Solidity AccessControl naming scheme in this case. The new method names are a better semantic fit for what's actually happening. hasRole implies we're performing a simple lookup but that's not what's happening under the hood. The caller is proving they have knowledge of a Merkle path to a specific commitment in the public Merkle tree. Even if the caller has the role the circuit can still fail with bad witness values. The behavior and assumptions are quite different and the API should reflect that.

a) Fair point on the semantic gap and I agree in principle, but I'm not fully convinced deviating is the right call, @andrew-fleming wdyt?

Sooooo I think it'd be nice to maintain the canonical API because it's familiar and we're not reinventing the wheel. That said, the changed circuit names AFAICT do better reflect the behavior and I agree that the assumptions and behaviors are different. If we stick with the og naming, it borders on being misleading for the sake of familiarity IMO. Taking a good faith perspective, the changed names sort of signal that some circuits are different from the expectation (hopefully further incentivizing users to read the docs)

Note also that the sol impl isn't a ratified standard like EIP20 so we're not breaking a standardized spec (even though following EIPs in this network is not always the best thing)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_computeAccountId should remain internal. Exporting the circuit increases the risk that a module consumer would build flows that leak the AccountId metadata and increase linkability

The user's should have this primitive to be able to recalculate their AccountId hash locally in case if they have forgotte/lost it, I think it's important utility to be used, and for the security of using it it should be kept on the developer's responsibility.

It's not possible to do this locally tho because the hashing scheme includes a reference to the instanceSalt ledger variable. Anyone calling this circuit would leak their accountId on-chain which conflicts with the goals of this module (minimizing metadata leakage). I understand the concern with providing a way to recover an AccountId in cases where it's lost or forgotten, but this should not be done at the smart contract layer imo. This should be done locally in the TypeScript / witness layer and is ultimately the Dapp developer's responsibility to provide a utility for users to recover their accountIds

  1. Not sure if you cann't run this locally, I mean if you fetch the public state and you run the circuit locally and get the hash, you don't have to proceed with forwarding this into a tx, you can just stop here. 🤔
  2. If I'm wrong on no.1 (which I doubt) then maybe adding salt as a param so that the user can fetch the _instanceSalt state and then run this circuit locally by passing it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also on the fence about this one specifically too. An AdminIdentifier IS a RoleIdentifier but unfortunately I could not express that in the language so we have to do that clunky cast

Yeah, I'm not suggesting we create a relationship between the types. I'm just curious on the benefit of having both. I assume we think API clarity is improved with having both?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also on the fence about this one specifically too. An AdminIdentifier IS a RoleIdentifier but unfortunately I could not express that in the language so we have to do that clunky cast

Yeah, I'm not suggesting we create a relationship between the types. I'm just curious on the benefit of having both. I assume we think API clarity is improved with having both?

I'm not convinced there's a huge benefit to API clarity with AdminIdentifier so I removed it and replaced with another RoleIdentifier

Copy link
Copy Markdown
Contributor Author

@emnul emnul Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_computeAccountId should remain internal. Exporting the circuit increases the risk that a module consumer would build flows that leak the AccountId metadata and increase linkability

The user's should have this primitive to be able to recalculate their AccountId hash locally in case if they have forgotte/lost it, I think it's important utility to be used, and for the security of using it it should be kept on the developer's responsibility.

It's not possible to do this locally tho because the hashing scheme includes a reference to the instanceSalt ledger variable. Anyone calling this circuit would leak their accountId on-chain which conflicts with the goals of this module (minimizing metadata leakage). I understand the concern with providing a way to recover an AccountId in cases where it's lost or forgotten, but this should not be done at the smart contract layer imo. This should be done locally in the TypeScript / witness layer and is ultimately the Dapp developer's responsibility to provide a utility for users to recover their accountIds

  1. Not sure if you cann't run this locally, I mean if you fetch the public state and you run the circuit locally and get the hash, you don't have to proceed with forwarding this into a tx, you can just stop here. 🤔
  2. If I'm wrong on no.1 (which I doubt) then maybe adding salt as a param so that the user can fetch the _instanceSalt state and then run this circuit locally by passing it.
  1. This isn't enforceable and can be easily misused. This feels like a huge foot gun to me

    I'm curious if https://github.com/LFDT-Minokawa/compact/blob/HEAD/CHANGELOG.md#added-2 would provide the expressiveness we're looking for Nah, doesn't really do what I thought it would.

Large diffs are not rendered by default.

Loading
Loading