Skip to content
Tech News
← Back to articles

Unverified Evaluations in Dusk's PLONK

read original get PLONK Zero-Knowledge Proof Kit → more articles
Why This Matters

The discovery of a critical vulnerability in Dusk Network's PLONK implementation highlights the importance of rigorous verification in zero-knowledge proof systems. If exploited, this flaw could allow malicious actors to forge proofs and manipulate transactions, posing significant security risks for blockchain platforms relying on this technology. Addressing such vulnerabilities is essential to maintain trust and security in privacy-focused blockchain networks and cryptographic protocols.

Key Takeaways

Commitment Issues: Unverified Evaluations in Dusk's PLONK

We found a critical soundness vulnerability in dusk-plonk, the PLONK implementation powering Dusk Network's ~$60M market cap. By exploiting a gap in the verification step, a malicious prover could forge verifying proofs for arbitrary false statements, bypassing every constraint in the transaction circuit. On the live Rusk network, this would have enabled minting arbitrary amounts of DUSK and moving forged shielded funds through the normal Phoenix path.

The root cause was that the prover slipped four public selector evaluations into the proof struct, and the verifier consumed them in its final equation without ever validating them against the trusted commitments in the verifier key. The prover can set them to whatever values make the equation pass.

For a rigorous treatment see the original paper; what follows covers only the parts needed to understand the bug.

A prover wants to convince a verifier that it knows secret inputs satisfying some computation (an arithmetic circuit) without revealing those inputs, and the resulting proof should be short and quick to verify.

An arithmetic circuit is a series of addition and multiplication gates wired together. An example would be proving that we know of some point (x,y) on an elliptic curve, by e.g proving that y2=x3+7 , here in F37​ .

Arithmetic Circuit In F 37 \mathbb{F}_{37} F 37 ​ Circuit computes y 2 − ( x 3 + 7 ) y^2-(x^3+7) y2−(x3+7) over F 37 \mathbb{F}_{37} F37​ and checks whether it equals 0 0 0. 6 36 31 1 1 1 a b b o a o a b a b o a o b o x y × × 7 + × − 0 x = 6 y = 1 gate \text{gate} gate q M q_M q M ​ q L q_L q L ​ q R q_R q R ​ q O q_O q O ​ q C q_C q C ​ a a a b b b o o o × ( x ⋅ x ) \times\,(x\cdot x) × ( x ⋅ x ) 1 0 0 -1 0 6 6 36 × ( x 2 ⋅ x ) \times\,(x^2\cdot x) × ( x 2 ⋅ x ) 1 0 0 -1 0 36 6 31 + ( x 3 + 7 ) +\,(x^3+7) + ( x 3 + 7 ) 0 1 0 -1 7 31 0 1 × ( y ⋅ y ) \times\,(y\cdot y) × ( y ⋅ y ) 1 0 0 -1 0 1 1 1 − ( y 2 − ( x 3 + 7 ) ) -\,(y^2-(x^3+7)) − ( y 2 − ( x 3 + 7 )) 0 1 -1 -1 0 1 1 0 = ? 0 \overset{?}{=}0 = ? 0 0 1 0 0 0 0 0 0 Using the same witness selected above, x = 6 , y = 1 x=6,\;y=1 x=6,y=1, the table columns induce interpolated polynomials over F 37 \mathbb{F}_{37} F37​. Show interpolated polynomials When F ( x ) F(x) F(x) is zero at all six interpolation points, Z H ( x ) = x 6 − 1 Z_H(x)=x^6-1 ZH​(x)=x6−1 divides it, so F ( x ) / Z H ( x ) F(x)/Z_H(x) F(x)/ZH​(x) is again a polynomial. For the current witness, Z H ( x ) = x 6 − 1 Z_H(x)=x^6-1 ZH​(x)=x6−1 divides F ( x ) F(x) F(x).

Each gate i has a left input li​ , right input ri​ , and output oi​ . The prover's job is to show it knows wire values that satisfy every gate.

Each gate imposes a constraint, and PLONK unifies all gate types into one expression using selector values that act as switches: setting qM​=1 makes a row a multiplication gate, setting qL​=1 makes it contribute an addition term, and so on. The selector values define the circuit's shape and are public, known to both prover and verifier, while the wire values are the prover's secret witness. This per-row check does not ensure that wires between gates are consistent (that the output of one gate equals the input of the next); PLONK uses a separate permutation argument for that, which we will not cover here.

Instead of checking each gate individually, PLONK reads the execution trace column by column and uses FFT interpolation to convert each array of values to a single polynomial. The wire values become witness polynomials fL​(x) , fR​(x) , fO​(x) and the selectors become selector polynomials QM​(x) , QL​(x) , etc., all interpolated over a domain H of n -th roots of unity. Evaluating fL​(x) at the i -th root recovers the left wire value at row i .

... continue reading