refactor(RLN): remove verifier and exit function

This commit is contained in:
r4bbit
2025-07-15 15:18:21 +02:00
parent fdc45eac07
commit 22ba4ff130
5 changed files with 31 additions and 210 deletions

View File

@@ -4,13 +4,13 @@
+=================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| 295493 | 1374 | | | | |
| 272694 | 1374 | | | | |
|-------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| | | | | | |
|-------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| fallback | 5145 | 64591 | 33119 | 193478 | 3571 |
| fallback | 5145 | 65050 | 33119 | 193478 | 3522 |
╰-------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------╯
╭-----------------------------------------------------+-----------------+---------+---------+---------+---------╮
@@ -24,7 +24,7 @@
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| run | 4666141 | 4666141 | 4666141 | 4666141 | 186 |
| run | 4666141 | 4666141 | 4666141 | 4666141 | 182 |
╰-----------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭-----------------------------------------------------------+-----------------+---------+---------+---------+---------╮
@@ -80,7 +80,7 @@
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| activeNetworkConfig | 455 | 2090 | 455 | 4455 | 548 |
| activeNetworkConfig | 455 | 2084 | 455 | 4455 | 540 |
╰---------------------------------------------------------+-----------------+------+--------+------+---------╯
╭---------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
@@ -114,11 +114,11 @@
|------------------------------+-----------------+--------+--------+--------+---------|
| OPERATOR_ROLE | 262 | 262 | 262 | 262 | 2 |
|------------------------------+-----------------+--------+--------+--------+---------|
| SLASHER_ROLE | 262 | 262 | 262 | 262 | 34 |
| SLASHER_ROLE | 262 | 262 | 262 | 262 | 30 |
|------------------------------+-----------------+--------+--------+--------+---------|
| accountSlashAmount | 2611 | 2611 | 2611 | 2611 | 2 |
|------------------------------+-----------------+--------+--------+--------+---------|
| addRewardDistributor | 29975 | 63560 | 70903 | 70903 | 304 |
| addRewardDistributor | 29975 | 63592 | 70903 | 70903 | 296 |
|------------------------------+-----------------+--------+--------+--------+---------|
| allowance | 573 | 573 | 573 | 573 | 8 |
|------------------------------+-----------------+--------+--------+--------+---------|
@@ -130,11 +130,11 @@
|------------------------------+-----------------+--------+--------+--------+---------|
| getRewardDistributors | 5132 | 7710 | 9644 | 9644 | 21 |
|------------------------------+-----------------+--------+--------+--------+---------|
| grantRole | 29490 | 29490 | 29490 | 29490 | 39 |
| grantRole | 29490 | 29490 | 29490 | 29490 | 35 |
|------------------------------+-----------------+--------+--------+--------+---------|
| hasRole | 2754 | 2754 | 2754 | 2754 | 4 |
|------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 116796 | 116796 | 116796 | 116796 | 186 |
| initialize | 116796 | 116796 | 116796 | 116796 | 182 |
|------------------------------+-----------------+--------+--------+--------+---------|
| mint | 4869 | 50370 | 51342 | 51342 | 551 |
|------------------------------+-----------------+--------+--------+--------+---------|
@@ -396,7 +396,7 @@
+===============================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 1204853 | 6015 | | | | |
| 1204853 | 6207 | | | | |
|------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
@@ -436,55 +436,33 @@
+=====================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------+-----------------+--------+--------+--------+---------|
| 1982512 | 9143 | | | | |
| 1751905 | 8068 | | | | |
|------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|------------------------------+-----------------+--------+--------+--------+---------|
| DEFAULT_ADMIN_ROLE | 262 | 262 | 262 | 262 | 10 |
| DEFAULT_ADMIN_ROLE | 262 | 262 | 262 | 262 | 6 |
|------------------------------+-----------------+--------+--------+--------+---------|
| REGISTER_ROLE | 262 | 262 | 262 | 262 | 10 |
| REGISTER_ROLE | 262 | 262 | 262 | 262 | 6 |
|------------------------------+-----------------+--------+--------+--------+---------|
| SET_SIZE | 2339 | 2339 | 2339 | 2339 | 1 |
|------------------------------+-----------------+--------+--------+--------+---------|
| SLASHER_ROLE | 262 | 262 | 262 | 262 | 10 |
| SLASHER_ROLE | 262 | 262 | 262 | 262 | 6 |
|------------------------------+-----------------+--------+--------+--------+---------|
| exit | 7068 | 16233 | 18694 | 22939 | 3 |
|------------------------------+-----------------+--------+--------+--------+---------|
| hasRole | 2707 | 2707 | 2707 | 2707 | 30 |
| hasRole | 2707 | 2707 | 2707 | 2707 | 18 |
|------------------------------+-----------------+--------+--------+--------+---------|
| identityCommitmentIndex | 2340 | 2340 | 2340 | 2340 | 5 |
|------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 165036 | 165036 | 165036 | 165036 | 11 |
| initialize | 142752 | 142752 | 142752 | 142752 | 7 |
|------------------------------+-----------------+--------+--------+--------+---------|
| members | 4669 | 4669 | 4669 | 4669 | 6 |
| members | 4669 | 4669 | 4669 | 4669 | 5 |
|------------------------------+-----------------+--------+--------+--------+---------|
| register | 6997 | 45345 | 53001 | 55801 | 11 |
| register | 6997 | 42474 | 53001 | 55801 | 8 |
|------------------------------+-----------------+--------+--------+--------+---------|
| slash | 7111 | 54764 | 18737 | 138444 | 3 |
|------------------------------+-----------------+--------+--------+--------+---------|
| verifier | 2359 | 2359 | 2359 | 2359 | 1 |
| slash | 7032 | 66881 | 66881 | 126731 | 2 |
╰------------------------------+-----------------+--------+--------+--------+---------╯
╭--------------------------------------+-----------------+-------+--------+-------+---------╮
| test/RLN.t.sol:MockVerifier Contract | | | | | |
+===========================================================================================+
| Deployment Cost | Deployment Size | | | | |
|--------------------------------------+-----------------+-------+--------+-------+---------|
| 204321 | 642 | | | | |
|--------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|--------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|--------------------------------------+-----------------+-------+--------+-------+---------|
| changeResult | 21649 | 21649 | 21649 | 21649 | 2 |
|--------------------------------------+-----------------+-------+--------+-------+---------|
| result | 2298 | 2298 | 2298 | 2298 | 3 |
|--------------------------------------+-----------------+-------+--------+-------+---------|
| verifyProof | 4790 | 4790 | 4790 | 4790 | 4 |
╰--------------------------------------+-----------------+-------+--------+-------+---------╯
╭-------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/mocks/KarmaDistributorMock.sol:KarmaDistributorMock Contract | | | | | |
+========================================================================================================================+

View File

@@ -112,16 +112,12 @@ OverflowTest:testTotalSupply() (gas: 359391)
OverflowTest:testTransfersNotAllowed() (gas: 61925)
OverflowTest:test_RevertWhen_MintingCausesOverflow() (gas: 129592)
OverflowTest:test_RevertWhen_SettingRewardCausesOverflow() (gas: 127920)
RLNTest:test_exit_fails_when_invalid_proof() (gas: 195432)
RLNTest:test_exit_fails_when_not_registered() (gas: 64843)
RLNTest:test_exit_succeeds() (gas: 187485)
RLNTest:test_initial_state() (gas: 60571)
RLNTest:test_register_fails_when_duplicate_identity_commitment() (gas: 131752)
RLNTest:test_register_fails_when_index_exceeds_set_size() (gas: 2569410)
RLNTest:test_register_succeeds() (gas: 272680)
RLNTest:test_slash_fails_when_invalid_proof() (gas: 195506)
RLNTest:test_slash_fails_when_not_registered() (gas: 64886)
RLNTest:test_slash_succeeds() (gas: 438591)
RLNTest:test_initial_state() (gas: 45654)
RLNTest:test_register_fails_when_duplicate_identity_commitment() (gas: 131740)
RLNTest:test_register_fails_when_index_exceeds_set_size() (gas: 2313519)
RLNTest:test_register_succeeds() (gas: 272683)
RLNTest:test_slash_fails_when_not_registered() (gas: 46080)
RLNTest:test_slash_succeeds() (gas: 408157)
RemoveRewardDistributorTest:testAddKarmaDistributorOnlyAdmin() (gas: 438248)
RemoveRewardDistributorTest:testBalanceOf() (gas: 456715)
RemoveRewardDistributorTest:testBalanceOfWithNoSystemTotalKarma() (gas: 83783)

View File

@@ -6,11 +6,9 @@ import { DeploymentConfig } from "./DeploymentConfig.s.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { Groth16Verifier } from "../src/rln/Verifier.sol";
import { RLN } from "../src/rln/RLN.sol";
contract DeployRLNScript is BaseScript {
error InvalidDepth();
error InvalidAddress();
@@ -28,10 +26,9 @@ contract DeployRLNScript is BaseScript {
}
vm.startBroadcast(deployer);
address verifier = (address)(new Groth16Verifier());
// Deploy Karma logic contract
bytes memory initializeData =
abi.encodeCall(RLN.initialize, (deployer, deployer, deployer, depth, verifier, karmaAddress));
abi.encodeCall(RLN.initialize, (deployer, deployer, deployer, depth, karmaAddress));
address impl = address(new RLN());
// Create upgradeable proxy
address proxy = address(new ERC1967Proxy(impl, initializeData));

View File

@@ -6,7 +6,6 @@ import { Karma } from "../Karma.sol";
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { IVerifier } from "./IVerifier.sol";
/// @title Rate-Limiting Nullifier registry contract
/// @dev This contract allows you to register RLN commitment and withdraw/slash.
@@ -14,7 +13,6 @@ contract RLN is Initializable, UUPSUpgradeable, AccessControlUpgradeable {
bytes32 public constant SLASHER_ROLE = keccak256("SLASHER_ROLE");
bytes32 public constant REGISTER_ROLE = keccak256("REGISTER_ROLE");
error RLN__InvalidProof();
error RLN__MemberNotFound();
error RLN__IdCommitmentAlreadyRegistered();
error RLN__SetIsFull();
@@ -40,18 +38,11 @@ contract RLN is Initializable, UUPSUpgradeable, AccessControlUpgradeable {
/// @dev Karma Token used for registering.
Karma public karma;
/// @dev Groth16 verifier.
IVerifier public verifier;
/// @dev Emmited when a new member registered.
/// @param identityCommitment: `identityCommitment`;
/// @param index: idCommitmentIndex value.
event MemberRegistered(uint256 identityCommitment, uint256 index);
/// @dev Emmited when a member was withdrawn.
/// @param index: index of `identityCommitment`;
event MemberExited(uint256 index);
/// @dev Emmited when a member was slashed.
/// @param index: index of `identityCommitment`;
/// @param slasher: address of slasher (msg.sender).
@@ -67,13 +58,11 @@ contract RLN is Initializable, UUPSUpgradeable, AccessControlUpgradeable {
/// @param _register: address of the register;
/// @param depth: depth of the merkle tree;
/// @param _token: address of the ERC20 contract;
/// @param _verifier: address of the Groth16 Verifier.
function initialize(
address _owner,
address _slasher,
address _register,
uint256 depth,
address _verifier,
address _token
)
public
@@ -87,7 +76,6 @@ contract RLN is Initializable, UUPSUpgradeable, AccessControlUpgradeable {
SET_SIZE = 1 << depth;
karma = Karma(_token);
verifier = IVerifier(_verifier);
}
/**
@@ -122,47 +110,16 @@ contract RLN is Initializable, UUPSUpgradeable, AccessControlUpgradeable {
}
}
/// @dev Request for exit.
/// @param identityCommitment: `identityCommitment`;
/// @param proof: snarkjs's format generated proof (without public inputs) packed consequently.
function exit(uint256 identityCommitment, uint256[8] calldata proof) external onlyRole(REGISTER_ROLE) {
User memory member = members[identityCommitment];
if (member.userAddress == address(0)) {
revert RLN__MemberNotFound();
}
if (!_verifyProof(identityCommitment, proof)) {
revert RLN__InvalidProof();
}
delete members[identityCommitment];
emit MemberExited(member.index);
}
/// @dev Slashes identity with identityCommitment.
/// @param identityCommitment: `identityCommitment`;
/// @param proof: snarkjs's format generated proof (without public inputs) packed consequently.
function slash(uint256 identityCommitment, uint256[8] calldata proof) external onlyRole(SLASHER_ROLE) {
function slash(uint256 identityCommitment) external onlyRole(SLASHER_ROLE) {
User memory member = members[identityCommitment];
if (member.userAddress == address(0)) {
revert RLN__MemberNotFound();
}
if (!_verifyProof(identityCommitment, proof)) {
revert RLN__InvalidProof();
}
karma.slash(member.userAddress);
delete members[identityCommitment];
emit MemberSlashed(member.index, msg.sender);
}
/// @dev Groth16 proof verification
function _verifyProof(uint256 identityCommitment, uint256[8] calldata proof) internal view returns (bool) {
return verifier.verifyProof(
[proof[0], proof[1]],
[[proof[2], proof[3]], [proof[4], proof[5]]],
[proof[6], proof[7]],
[identityCommitment, uint256(0)]
);
}
}

View File

@@ -4,44 +4,14 @@ pragma solidity ^0.8.26;
import { Test } from "forge-std/Test.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { RLN } from "../src/rln/RLN.sol";
import { IVerifier } from "../src/rln/IVerifier.sol";
import { Karma } from "../src/Karma.sol";
import { KarmaDistributorMock } from "./mocks/KarmaDistributorMock.sol";
import { DeployKarmaScript } from "../script/DeployKarma.s.sol";
import { DeployRLNScript } from "../script/RLN.s.sol";
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
/// @dev A mock verifier that allows toggling proof validity.
contract MockVerifier is IVerifier {
bool public result;
constructor() {
result = true;
}
function verifyProof(
uint256[2] memory,
uint256[2][2] memory,
uint256[2] memory,
uint256[2] memory
)
external
view
override
returns (bool)
{
return result;
}
function changeResult(bool _result) external {
result = _result;
}
}
contract RLNTest is Test {
RLN public rln;
MockVerifier public verifier;
uint256 private constant DEPTH = 2; // for most tests
uint256 private constant SMALL_DEPTH = 1; // for “full” test
@@ -51,10 +21,6 @@ contract RLNTest is Test {
uint256 private identityCommitment1 = 5678;
uint256 private identityCommitment2 = 9999;
// Sample SNARK proof (8element array)
uint256[8] private mockProof =
[uint256(0), uint256(1), uint256(2), uint256(3), uint256(4), uint256(5), uint256(6), uint256(7)];
// Roleholders
address private owner;
Karma private karma;
@@ -83,11 +49,8 @@ contract RLNTest is Test {
registerAddr = makeAddr("register");
slasherAddr = makeAddr("slasher");
// Deploy mock verifier
verifier = new MockVerifier();
// Deploy RLN via UUPS proxy with DEPTH = 2
rln = _deployRLN(DEPTH, address(verifier), karma);
rln = _deployRLN(DEPTH, karma);
// Sanitycheck that roles were assigned correctly
assertTrue(rln.hasRole(rln.DEFAULT_ADMIN_ROLE(), adminAddr));
@@ -102,7 +65,7 @@ contract RLNTest is Test {
}
/// @dev Deploys a new RLN instance (behind ERC1967Proxy).
function _deployRLN(uint256 depth, address verifierAddr, Karma karmaToken) internal returns (RLN) {
function _deployRLN(uint256 depth, Karma karmaToken) internal returns (RLN) {
bytes memory initData = abi.encodeCall(
RLN.initialize,
(
@@ -110,7 +73,6 @@ contract RLNTest is Test {
slasherAddr,
registerAddr,
depth,
verifierAddr,
address(karmaToken) // token address unused in these tests
)
);
@@ -132,9 +94,6 @@ contract RLNTest is Test {
(address user0, uint256 idx0) = _memberData(identityCommitment0);
assertEq(user0, address(0));
assertEq(idx0, 0);
// Verifier address matches
assertEq(address(rln.verifier()), address(verifier));
}
/* ---------- REGISTER ---------- */
@@ -169,7 +128,7 @@ contract RLNTest is Test {
function test_register_fails_when_index_exceeds_set_size() public {
// Deploy a small RLN with depth = 1 => SET_SIZE = 2
RLN smallRLN = _deployRLN(SMALL_DEPTH, address(verifier), karma);
RLN smallRLN = _deployRLN(SMALL_DEPTH, karma);
address smallRegister = registerAddr;
// Fill up both slots
@@ -198,55 +157,6 @@ contract RLNTest is Test {
vm.stopPrank();
}
/* ---------- EXIT ---------- */
function test_exit_succeeds() public {
// Register the identity
vm.startPrank(registerAddr);
rln.register(identityCommitment0, user1Addr);
vm.stopPrank();
// Ensure mock verifier returns true by default
assertTrue(verifier.result());
// Call exit with a valid proof
vm.startPrank(registerAddr);
vm.expectEmit(false, false, false, true);
emit RLN.MemberExited(0);
rln.exit(identityCommitment0, mockProof);
vm.stopPrank();
// After exit, the member record should be cleared
(address u0, uint256 i0) = _memberData(identityCommitment0);
assertEq(u0, address(0));
assertEq(i0, 0);
}
function test_exit_fails_when_not_registered() public {
// Attempt exit without prior registration
vm.startPrank(registerAddr);
vm.expectRevert(RLN.RLN__MemberNotFound.selector);
rln.exit(identityCommitment1, mockProof);
vm.stopPrank();
}
function test_exit_fails_when_invalid_proof() public {
// Register the identity
vm.startPrank(registerAddr);
rln.register(identityCommitment0, user1Addr);
vm.stopPrank();
// Make proof invalid
verifier.changeResult(false);
assertFalse(verifier.result());
// Attempt exit with invalid proof
vm.startPrank(registerAddr);
vm.expectRevert(RLN.RLN__InvalidProof.selector);
rln.exit(identityCommitment0, mockProof);
vm.stopPrank();
}
/* ---------- SLASH ---------- */
function test_slash_succeeds() public {
@@ -268,7 +178,7 @@ contract RLNTest is Test {
vm.startPrank(slasherAddr);
vm.expectEmit(false, true, false, true);
emit RLN.MemberSlashed(index1, slasherAddr);
rln.slash(identityCommitment1, mockProof);
rln.slash(identityCommitment1);
vm.stopPrank();
// After slash, the member record should be cleared
@@ -281,24 +191,7 @@ contract RLNTest is Test {
// Attempt to slash a nonexistent identity
vm.startPrank(slasherAddr);
vm.expectRevert(RLN.RLN__MemberNotFound.selector);
rln.slash(identityCommitment0, mockProof);
vm.stopPrank();
}
function test_slash_fails_when_invalid_proof() public {
// Register the identity
vm.startPrank(registerAddr);
rln.register(identityCommitment0, user1Addr);
vm.stopPrank();
// Make proof invalid
verifier.changeResult(false);
assertFalse(verifier.result());
// Attempt to slash with invalid proof
vm.startPrank(slasherAddr);
vm.expectRevert(RLN.RLN__InvalidProof.selector);
rln.slash(identityCommitment0, mockProof);
rln.slash(identityCommitment0);
vm.stopPrank();
}