Skip to content

[Audit C-03] Decryption proofs are replayable across unrelated E3 contexts #1710

Description

@hmzakhalid

Finding

Severity: Critical

Confirmed against baseline commit d4277510d. The baseline tracked publication only per E3 and did not consume a canonical proof nullifier, so the same valid decryption proof could be reused in another compatible E3 context.

C-03 — Decryption proofs are replayable across unrelated E3 contexts

Affected code: contracts/interfaces/IDecryptionVerifier.sol:8-64,
contracts/verifiers/bfv/BfvDecryptionVerifier.sol:34-39,95-154,
contracts/Interfold.sol:443-459

BfvDecryptionVerifier.verify checks the recursive VK hashes, committee hash,
and plaintext coefficients. It explicitly discards e3Id, committeeRoot,
sortedNodes, ciphertextOutputHash, and committeePublicKey. It also has no
chain ID or verifier-deployment domain input. This contradicts the interface's
claim that the proof is bound to the full on-chain context.

A proof of plaintext P for ciphertext/key/E3 A is accepted for E3 B whenever B
supplies the same committee hash and claimed plaintext hash—even if the E3 ID,
root, nodes argument, ciphertext, and key are different. Cross-chain or
cross-deployment replay is also possible when verifier anchors and committee
hash match.

Proof of concept: AUD-C03 invokes the same proof against two calls with
different E3 IDs, roots, nodes, ciphertext hashes, and public keys; both return
true.

Recommendation: Add a domain/context commitment to the decryption circuit's
public inputs. A single canonical commitment may bind
(block.chainid, address(verifier or Interfold), e3Id, committeeRoot, committeeHash, ciphertextOutputHash, committeePublicKey, plaintextOutputHash, circuit/version domain).
The wrapper must recompute and compare it. Ensure the value is actually
constrained inside the recursive proof chain, not merely appended by an
untrusted aggregator. Add negative tests changing each field independently and
cross-chain/cross-deployment replay vectors.

Required remediation

Consume a canonical decryption-proof nullifier derived from its public inputs and reject cross-E3 proof reuse, with dedicated replay regressions.

The dedicated fixing commit and remediation PR will be linked in a follow-up comment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions