Plonky3 MultiField32Challenger: transcript malleability and challenge entropy loss
Description
Impact
- Key:
challenger/src/multi_field_challenger.rs|MultiField32Challenger::duplexing|transcript_malleability - Affected files:
challenger/src/multi_field_challenger.rs,field/src/helpers.rs - Violated invariant: The Fiat-Shamir sponge must bind challenges to the exact sequence of observed field elements. Specifically: (1) absorption must be injective — distinct observation streams must produce distinct sponge states, (2) squeezing must be injective — distinct PF rate cells must yield distinct F challenge sequences, and (3) all bits of each absorbed PF element must influence the sponge state.
- Exploit scenario: An attacker controlling prover-side observations can craft distinct transcripts that produce identical challenges, breaking the binding property of Fiat-Shamir. Three independent attack vectors exist:
- Partial-chunk aliasing (absorb):
duplexing()packsinput_buffer.chunks(num_f_elms)viareduce_32(base 2^32) with no length marker and no zeroing of unused rate slots. Observing[x]followed by a sample yields the same sponge state as[x, 0, ..., 0](padded tonum_f_elms) followed by a sample, sincereduce_32treats missing high limbs identically to explicit zeros. The attacker can extend or truncate the tail of any observation batch without changing future challenges.
- Non-injective squeeze (squeeze):
split_32decomposes each PF rate cell into base-2^64 digits and maps each throughTF::from_u64, which reduces modF::ORDER(~2^31). Two distinct PF values whose base-2^64 digits differ only in their upper 33 bits produce identical F challenge sequences. This weakens the entropy of sampled challenges and can enable selective forgery when the attacker can influence the sponge state pre-squeeze.
- High-bit truncation (observe Hash/MerkleCap):
num_f_elms = PF::bits() / 64computes the number of F limbs per PF element. For BN254 (254-bit field), this yields 3 limbs covering 192 bits — the top 62 bits of every digest word are silently discarded. An attacker can find two distinct BN254 hash digests that differ only in bits 192–253 and observe them interchangeably without affecting challenges.
- Evidence: In
duplexing(), the absorb path (reduce_32with base 2^32) and the squeeze path (split_32with base 2^64) use incompatible radices with no length domain separation.reduce_32is a plain Horner foldacc * 2^32 + digitwith no padding or tag, so trailing zeros are free.split_32extracts u64 digits and casts each viaTF::from_u64, which performs modular reduction, collapsing the top bits. The limb countPF::bits() / 64is a floor division that silently drops all bits beyond64 * num_f_elmsfor fields whose bit-width is not a multiple of 64.
Patches
Included in v0.4.3 and v0.5.3
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Plonky3's MultiField32Challenger has three design flaws allowing transcript malleability, enabling attackers to forge proofs by manipulating observations to produce duplicate challenges.
CVE-2026-46654 describes a set of high-severity vulnerabilities in Plonky3's MultiField32Challenger, a component implementing the Fiat-Shamir transform for proof systems. The core issue is a violation of the invariant that the sponge must bind challenges to the exact sequence of observed field elements. Three independent flaws exist in the duplexing() function, which handles absorption and squeezing, and in the handling of hash digests for proofs like Merkle caps [1][2].
Attack
Vectors The first vector, *partial-chunk aliasing*, occurs during absorption: duplexing() processes input chunks via reduce_32 without marking length or zeroing unused rate slots, so observing [x] followed by a sample produces the same sponge state as [x, 0, ..., 0]. The second, *non-injective squeeze*, results from split_32 mapping PF rate cells to base‑2^64 digits and then reducing modulo F::ORDER (~2^31), meaning two distinct PF values whose digits differ only in the upper 33 bits yield identical challenge sequences. The third, *high-bit truncation*, applies when absorbing hash digests or Merkle cap data: num_f_elms = PF::bits() / 64 computes the number of limbs per PF element, and for BN254 (254-bit field) this truncates the top 62 bits of every digest word [1][2].
Impact
An attacker who can control prover-side observations can exploit any of these vectors to craft distinct transcripts that produce identical challenges. This breaks the binding property of the Fiat-Shamir heuristic, enabling selective forgery of proofs without detection. The vulnerability weakens the entropy of sampled challenges and allows transcript malleability, potentially leading to complete compromise of proof soundness [1][2].
Mitigation
Patches are available in version 0.4.3 (for the 0.4.x line) and 0.5.3 (for 0.5.x). Users should upgrade immediately. No workarounds have been published, and the flaw is not yet listed in CISA's Known Exploited Vulnerabilities catalog [1].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
0No patches discovered yet.
Vulnerability mechanics
AI mechanics synthesis has not run for this CVE yet.
References
2News mentions
0No linked articles in our index yet.