OpenZeppelin / OpenZeppelin/compact-contracts

L-07: Missing Recovery Path for Balances Whose Plaintext Can No Longer Be Stated

Open
#805 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

2-low audit
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.