Skip to content
LogoLogo

The wrapper W

Publics (flat, in this order):

chain_id, pool_address, payment_root, phase_class, time_bucket, registry_root,
fi_index, counterparty_fi_index, state_in, state_out, attestation_in, attestation_out

Witness: phase (constrained by phase_class), FI leaf opening (fi_id, mpk, epk, vk_root, params_commitment, path), vk_salt, the three per-phase VK hashes, the selected policy VK (full), the policy proof, and a Schnorr signature under mpk over all publics.

Checks:

  1. phase_class ∈ {0, 1}. If 0, phase == 0; else phase ∈ {1, 2}. Which of accept or reject was proven is never a public.
  2. Leaf opens under registry_root at fi_index.
  3. vk_root == H(FI_VKS, vk_salt, vk0, vk1, vk2); selected = [vk0,vk1,vk2][phase].
  4. hash(policy_vk) == selected.
  5. context_root = H(CTX_PHASE, payment_root, merkle_16(phase leaves)) where the phase leaves are built from the publics and the witnessed phase.
  6. Recursive verification of the policy proof with inner publics (context_root, leaf.params_commitment, state_in, state_out, attestation_out).
  7. Schnorr verify under mpk over all publics, including fi_index. The signature is the FI vouching; it binds the proof to this FI, this hold, this bucket.

One VK_W for every FI and every phase.

Authority is separate from proving. Only the signature needs msk. The policy proof and the wrapper proof can be produced by a proving service or a relayer that holds the envelope and the FI's params and state preimages. Compromise of that service loses privacy (it sees plaintexts) but cannot move value or vouch for a transition, because it never holds msk.