Proof of Reserves
Under MiCA (Art. 22, Art. 56), EMT issuers must periodically report the value of issued tokens and demonstrate that reserves cover all outstanding supply. In a standard ERC-20 this is trivial — totalSupply() is public. In a privacy system, it is not: individual balances are ElGamal ciphertexts (and later UTXOs), and the total amount held across all users is not directly observable on-chain.
encryptedTotalSupply tracks true issued supply — the running net of all mints and burns across both layers. Layer-crossing operations (publicToEncryptedTransfer, encryptedToPublicTransfer, autoEncrypt) relocate already-issued tokens between public and encrypted representations and do NOT touch the counter. Tracking the number via a public counter would work, but it would leak information about particular burns (and hence private offramps). Instead, the total supply is stored as an encrypted counter that only an authorized party (auditor, regulator, or reserve custodian) can decrypt.
Encrypted Total Supply Counter
The contract stores a single ElGamal ciphertext TS = (R_ts, C_ts) encrypted under a dedicated total_supply_key (a Grumpkin public key). This counter is updated homomorphically on every operation that changes issued supply — i.e. the four mint/burn entry points:
| Operation | Effect on total supply counter |
|---|---|
publicMint(to, amount) (mint to public ERC-20) | TS += amount · G (public delta, r = 0) |
publicBurn(burnFrom, amount) (burn burnFrom's public ERC-20) | TS -= amount · G (public delta) |
encryptedMint(epk, mintCt, tsCt, trcCt, proof) (mint to encrypted) | TS += tsCt (hidden amount, homomorphic) |
encryptedBurn(epk, newBalance, tsCt, trcCt, …, proof) (burn from encrypted) | TS -= tsCt (hidden amount, homomorphic) |
The counter starts at the identity ciphertext (O, O), which encrypts zero. Layer-crossing operations and encrypted-to-encrypted transfers leave the counter unchanged.
On-chain mechanics
The contract stores a single counter and the key it's encrypted under (one EBEMT deployment = one token, so no per-token mapping is needed):
ElGamalCiphertext public encryptedTotalSupply;
Point public totalSupplyPk;
On each mint/burn, the contract performs ElGamal homomorphic addition (or subtraction) on encryptedTotalSupply. For public-amount operations (publicMint, publicBurn), the contract computes amount · G on-chain (an r = 0 encryption) and adds/subtracts from the counter's C component — no circuit involved. For encrypted mint and burn, the amount is hidden, so the respective ZK circuit must output tsCt = Enc(amount, totalSupplyPk, r) as a public input using fresh randomness; the contract adds or subtracts that ciphertext component-wise.
Key management
The total supply key is a Grumpkin keypair (totalSupplySK, totalSupplyPk) where:
totalSupplyPkis stored on-chain and used by the contract (for public mint/burn) and by the mint/burn circuits (for encrypted mint/burn) to encrypt amounts into the counter.totalSupplySKis held by the authorized party (e.g., the EMI compliance team).
The key holder can decrypt the total supply counter at any time: total_supply · G = C_ts - totalSupplySK · R_ts, then solve the discrete log. Since total supply is bounded by reasonable token economics — e.g., 10^13 micro-units for a $10M stablecoin with 6 decimals, roughly 2^43 — the discrete log solver using Boosted Kangaroos recovers the plaintext total supply in milliseconds.
Verification
To prove reserves, the keyholder generates a ZK proof that a given total_supply value matches encryptedTotalSupply at a given block. This proof can be produced for an off-chain verifier such as a regulator or auditor. Publishing and verifying the proof on-chain is a possible integration point for a deployment that adds a dedicated entry point.
Costs and risks
Each of the four supply-changing operations (publicMint, publicBurn, encryptedMint, encryptedBurn) pays an additional on-chain cost on top of the base ERC-20 / encrypted-layer work: for public paths, one scalar-base-mul + one affine point addition on the counter's C component; for encrypted paths, one affine point addition per component (R and C) using the ciphertext the circuit already produces. Layer-crossing operations (publicToEncryptedTransfer, encryptedToPublicTransfer, autoEncrypt) do not touch the counter and incur no added cost.
Managing totalSupplyPk / totalSupplySK requires key rotation, backup, and access control. If totalSupplySK is compromised, the attacker learns total supply (but not individual balances). If totalSupplySK is lost, the counter becomes undecryptable — the system continues to function, but auditing is impossible until a new counter is initialized.