OpenZeppelin / OpenZeppelin/compact-contracts
L-07: Missing Recovery Path for Balances Whose Plaintext Can No Longer Be Stated
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 55
- Forks
- 29
- Avg merge
- 5d 7h
- Merged PRs (30d)
- 25
Description
L-04 Missing Recovery Path for Balances Whose Plaintext Can No Longer Be Stated
Severity: Low
Source: Midnight Foundation #02 — OpenZeppelin Compact Contracts Audit, Release 0.3.0-alpha.1 (2026-08-18)
Every path that removes value requires the caller to state the plaintext of their entire balance, which ElGamal_assertDecryptsTo binds to the stored ciphertext against a witness typed Uint<128>. Several independent conditions can leave an account holding value for which no such claim exists, including a credit whose memo was discarded before the wallet folded it into its cache, and a ciphertext that has accumulated past the range the witness type can express. The underlying mismatch is that homomorphic addition accumulates in the Jubjub scalar field, whose order is far above the Uint<128> maximum, so a well-formed ciphertext may encode a quantity the witness cannot name.
Once an account reaches that state, the condition is terminal. The value remains on the ledger and is provably present, yet every debit, approval, and escrow spend fails the assertion for every value the caller could supply. Remediations for the conditions that lead there are preventative in nature, so an account already affected has no exit, and no circuit in the module accepts a claim outside Uint<128> or otherwise re-expresses a balance the caller cannot state.
Consider providing a narrow recovery circuit that accepts a wider plaintext claim, binds it with the existing decryption assertion, and permits the holder to split the balance into pieces each within the ordinary range. Confining the wider claim to that circuit would leave the normal paths and the module's stated Uint<128> balance range unchanged, while giving an affected account a route back to a spendable state.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with contracts/src/token/ConfidentialFungibleToken.compact, especially the balance-removal paths and the ElGamal_assertDecryptsTo binding referenced in the issue. Review the Uint<128> witness constraint and existing balance operations before defining the recovery circuit. Done means an affected holder can re-express the balance as ordinary-range pieces without changing normal balance limits.
Written by the indexing model from the issue text.
Assessment
- Domain
- blockchain, cryptography
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100