Skip to content

[FEAT] Add CommitmentRegistry contract#57

Open
roeezolantz wants to merge 10 commits intomasterfrom
feat/commitment-registry
Open

[FEAT] Add CommitmentRegistry contract#57
roeezolantz wants to merge 10 commits intomasterfrom
feat/commitment-registry

Conversation

@roeezolantz
Copy link
Copy Markdown
Contributor

@roeezolantz roeezolantz commented Mar 24, 2026

Summary

UUPS-upgradeable contract for on-chain FHE computation commitments on Arbitrum One. Threshold Network verifies ciphertext integrity before decrypting by looking up committed hashes. Part of the effort to reduce trust between CoFHE components.

Storage: mapping(version => mapping(handle => commitHash)) + bytes32[] handlesByVersion for enumeration. Write-once, version lifecycle enforced.

Design decisions

  • Direct mapping over merkle tree — TN needs instant O(1) lookup (getCommitment). Merkle can be added via UUPS upgrade if costs warrant it (~10-20x cheaper but requires an event indexing service).
  • Explicit version in postCommitments — The version is an opaque bytes32 from the FHE engine: keccak256(publicKey[securityZone], library_id, version, params). Explicit because:
    • Multiple versions can be active simultaneously (different security zones have different keys)
    • No coupling to FHE internals — contract is FHE-library-agnostic
    • Race condition safety — version in calldata preserves poster intent if admin changes active version mid-flight
    • Auditability — every commitment permanently tagged with its version
  • Array-based enumerationhandlesByVersion array enables paginated cursor (getHandles) for migration and iteration. Roughly doubles gas per commitment vs mapping-only.
  • Version state machine — Unset -> Active -> Deprecated/Revoked. No resurrection.
  • ERC-7201 storage — matching ACL pattern for upgrade safety.

Gas (measured, includes mapping + array)

Per commitment (L2 execution):

  • Single post: 102,222 gas (~$0.007/CT)
  • Batch of 10: 51,773 gas/CT (~$0.003/CT)
  • Batch of 50: 47,286 gas/CT (~$0.003/CT)

At 0.03 gwei effective gas price, ETH ~$2,140.

Monthly at 100K CTs/day: $9K-20K/mo depending on batch efficiency.

Test plan

  • 59 tests covering all code paths
  • Deployed on Arbitrum Sepolia (0x753882Fa0389E600913657B846990beBDC4BBeb6)
  • Measure real mainnet L1+L2 costs
  • Integrate poster service + TN verification

See README in contracts/internal/registry-chain/contracts/commitment-registry/.

@roeezolantz roeezolantz changed the title Add CommitmentRegistry contract [FEAT] Add CommitmentRegistry contract Mar 24, 2026
@roeezolantz roeezolantz marked this pull request as ready for review March 24, 2026 20:19
@roeezolantz roeezolantz requested a review from a team as a code owner March 24, 2026 20:19
@roeezolantz
Copy link
Copy Markdown
Contributor Author

Adding comparison with OZ's EnumerableMap :

EnumerableMap is a general-purpose library: mapping + array + index tracking. Supports insert, update, delete, existence check, and key enumeration. Battle-tested, audited, composable across any contract.

CommitmentRegistry is purpose-built for write-once commitments. It drops deletion, update, and index tracking — features we don't need, which gives us:

  • ~22k less gas per insert (3 SSTOREs vs 4)
  • Half the gas per read (1 SLOAD vs 2)
  • No zero-value ambiguity (banned at write boundary, so 0 = "doesn't exist" is always true)
  • No swap-and-pop logic = less attack surface for feature we don't even need (deletions)
  • Built-in access control, versions lifecycle, ERC-7201 storage, and pagination

I recommend keeping our version, as it's simpler, cheaper, and more secure for our specific use case. OZ solves a broader problem we don't have.
While OZ's audit status carries real weight, forking it would mean stripping out deletion, adding version management, access control, ERC-7201 storage, and zero-value guards, at which point the audited code is buried under enough modifications that a reviewer would need to understand both the original OZ patterns and why we deviated from them, rather than just reading a clean, purpose-built contract.

mapping(bytes32 version => mapping(bytes32 handle => bytes32 commitHash)) commitments;
mapping(bytes32 version => bytes32[]) handlesByVersion;
mapping(bytes32 version => VersionStatus) versionStatus;
address poster;
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.

rethinking now, this maybe has to be multiple instead of single, to allow multiple addressed in case we have to scale this way
i'm still thinking about it in the new TxSender DR, so will update here accordingly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant