-
Notifications
You must be signed in to change notification settings - Fork 12
Open
Labels
enhancementNew feature or requestNew feature or requestwork-in-progressPull requests which are still being worked on, more changes will follow.Pull requests which are still being worked on, more changes will follow.
Milestone
Description
Shielded Access Control Proposal
I aim to outline a Shielded Access Control module that would enable developers to define role-based access control mechanisms without publicly revealing the role assignments of accounts.
Challenges
We can’t enforce the HKDF nonce derivation, since it’s computed and shared off-chain. Without circuit verification in Compact, users can use any nonce, as long as it’s unique for the PK-role pair to avoid commitment collisions. The HKDF method is a secure recommendation for randomness and privacy, but enforcing it requires on-chain HKDF verification, which isn’t supported. Users should follow this approach for best security. To address this challenge we should provide a HKDF nonce derivation implementation.
Contract Outline
Ledger
// MerkleTree with 2^4 - 1 leaves
// Each leaf equals H(PK, role, nonce)
export ledger _roles: MerkleTree<4, Bytes<32>;
export ledger DEFAULT_ADMIN_ROLE: Bytes<32>;
Private State
// Generic role names to be modified by implementation
type RoleNames = "admin" | "minter" | "burner";
type RoleData = {
[role in RoleNames]: {
merkleTreeIndex: bigint; // Not sure about this one
nonce: Uint8Array;
};
};
type ShieldedAccessControlPrivateState = {
readonly secretKey: Uint8Array;
roles: RoleData
};
External Circuits
export circuit getAdminRole(role: Bytes<32>)
export circuit grantRole(pk: Bytes<32>, role: Bytes<32>, nonce: Bytes<16>): Bytes<32> {
commitment = hashUserRole(PK || role || nonce)
Call _addRole(commitment)
Return commitment
}
export circuit revokeRole(pk: Bytes<32>, role: Bytes<32>, nonce: Bytes<16>): [] {
commitment = hashUserRole(PK || role || nonce)
Call _revokeRole(commitment)
Return commitment
}
export circuit renounceRole(role: Bytes<32>, callerConfirmation: Either<ZswapCoinPublicKey, ContractAddress>): [] {
assert callerConfirmation == left<ZswapCoinPublicKey,ContractAddress>(own_public_key()) "ShieldedAccessControl: bad confirmation";
_revokeRole(role);
}
export circuit hasRole(role: Bytes<32>, account: Either<ZswapCoinPublicKey, ContractAddress>, nonce: Bytes<16>): Boolean
export circuit assertOnlyRole(role: Bytes<32>): [] {
}
/**
* @description creates public hash of secret key
export circuit publicKey(sk: Bytes<32>, nonce: Bytes<16>): Bytes<32> {
return persistent_hash<Vector<3, Bytes<32>>>([pad(32, "shieldedAccessControl:pk:"), pad(32, nonce) , sk]);
}
Internal Circuits
_grantRole(merkleTreeCommitment: Bytes<32>): Boolean
_revokeRole(merkleTreeCommitment: Bytes<32>): Boolean
Witnesses
/**
* @description Provide proof of knowledge of `role` - H(PK, role, nonce) - in MerkleTree
* Since nonce is only known locally and to the admin it's not possible
*/
witness assertOnlyRole(role: Bytes<32>): MerkleTreePath<10, Bytes<32>>;
/**
* @description Getter for secret key
*/
witness localSecretKey();
Off-chain Functions
function HKDF(keyingMaterial, info, len)
function roleRequest(pubkey, role, nonce)
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or requestwork-in-progressPull requests which are still being worked on, more changes will follow.Pull requests which are still being worked on, more changes will follow.