Skip to content
LogoLogo

Registry and FI state

leaf    = H(FI_LEAF, fi_id, mpk.x, mpk.y, epk.x, epk.y, vk_root, params_commitment)
vk_root = H(FI_VKS, vk_salt, vk_hash_initiate, vk_hash_accept, vk_hash_reject)

Registry is a Poseidon2 Merkle tree of depth 16 indexed by FI index; leaves are replaced in place. State is not in the leaf. The pool holds fiState[fi_index], a state root it alone writes, checked by plain equality against wrapper publics. The registry root therefore moves only on admin operations, and the pool accepts any registry_root from a window of the R_REG most recent roots. Revocation is checked directly against revoked[fi_index], so the window does not delay it.

On-chain Registry contract:

FunctionAuthEffect
admit(fi_id, mpk, epk, vk_root, params_commitment, π_possess)authoritynew leaf; π_possess is a Schnorr signature under mpk over (chain_id, registry_address, fi_id), proving possession of msk so no FI can register another's key
rotate(index, vk_root)signature under current mpkcode change
setParams(index, params_commitment)signature under mpktuning change, no VK change
rotateKey(index, new_mpk, new_epk, π_possess)signature under current mpkkey rotation
revoke(index)authorityleaf zeroed, revoked[index] = true
root(), recentRoots()viewcurrent root and the R_REG window

The pool exposes fiState(index); it is written only by the pool after a successful policy-carrying transition (§4.9). fiState == 0 is the canonical empty state (§5.5).

A no-op policy is a fixed, published VK; an FI with no rule at a phase registers the no-op's hash in that slot. vk_root is a salted commitment, so which policies an FI runs stays private even when every slot is the no-op; the leaf is public.