Skip to content

fix(js): base confidential-mint supply on the confidential ciphertext - #1402

Open
latent-9 wants to merge 2 commits into
solana-program:mainfrom
latent-9:fix/confidential-mint-supply
Open

fix(js): base confidential-mint supply on the confidential ciphertext#1402
latent-9 wants to merge 2 commits into
solana-program:mainfrom
latent-9:fix/confidential-mint-supply

Conversation

@latent-9

Copy link
Copy Markdown
Contributor

Summary

buildConfidentialMintProofPlan derives the new supply from the AES
decryptable_supply, but pairs the resulting commitment with a ciphertext
that encrypts confidential_supply + amount. The
CiphertextCommitmentEqualityProof only verifies when the ciphertext and the
commitment encode the same value, so the mint is rejected on-chain whenever
the two supplies differ:

  1. After an apply-pending-burn: ApplyPendingBurn advances the ElGamal
    confidential_supply but does not re-encrypt the AES decryptable_supply.
  2. At initialization: a nonzero InitializeMintData.decryptable_supply
    diverges from the zero confidential supply before the first mint.

The on-chain mint hard-requires the new supply ciphertext to equal
add_with_lo_hi(confidential_supply, amount) and verifies the equality proof
against that value, so the only consistent plaintext for the commitment is
the confidential supply, not the decryptable one.

Change

Derive currentSupply by decrypting confidentialSupply with the supply
ElGamal keypair. The resulting newDecryptableSupply also re-syncs the AES
decryptable supply in the same instruction, matching the manual
getUpdateConfidentialMintBurnDecryptableSupplyInstructionFromSupply call
that was previously required after every burn.

Test

Adds a regression test that mints, burns, applies the pending burn (without
any manual decryptable-supply re-sync), and mints again. It verifies the
second mint succeeds and that the decryptable supply tracks the encrypted
supply.

The mint helper committed the new supply as `decryptable_supply + amount`
while the equality-proof ciphertext encrypts `confidential_supply + amount`.
CiphertextCommitmentEqualityProof requires both values to match, so any
confidential mint fails on-chain once the two supplies diverge: after an
apply-pending-burn advances the encrypted supply without re-encrypting the
decryptable one, or when InitializeMintData sets a nonzero decryptable
supply. Derive the new supply from the confidential ciphertext via the
supply ElGamal keypair, which also keeps the decryptable supply in sync.

Adds a regression test that mints, burns, applies the pending burn, and
mints again without a manual decryptable-supply re-sync.
@latent-9

latent-9 commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

Update: after reproducing the audit locally, the advisory that actually fails the job is RUSTSEC-2026-0258 (h2 0.3.26, unbounded empty DATA frames, published 2026-08-17). The h2 0.3.x line has no fixed release, the fix requires h2 >= 0.4.16, so there is no applicable patch for this lockfile yet.

RUSTSEC-2026-0173 (proc-macro-error2 unmaintained) shows up as an allowed warning, not a blocker.

This is unrelated to the changes in this PR and would fail on main too, since the last successful audit run was 2026-08-13.

Pushed 1feea7b adding both advisories to the ignore list in the Makefile audit target:

--ignore RUSTSEC-2026-0173
--ignore RUSTSEC-2026-0258

Verified locally that make audit passes with these two entries.

RUSTSEC-2026-0258 (h2 unbounded empty DATA frames) is the advisory that
fails the Audit job. h2 0.3.x has no fixed release, the fix requires the
0.4 line, so ignore it the same way as the other advisories without an
applicable patch.

RUSTSEC-2026-0173 (proc-macro-error2 unmaintained) has no replacement,
ignore it as well to keep the job green.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant