[RFC Draft] ZK-Whiteblow: A ZK-Primitive to Solve Treasury Collusion & Accountability

[RFC Draft] Project ZK-Whiteblow: A ZK-Primitive to Solve Treasury Collusion & Accountability

Collusion thrives in the dark. Let’s use Zero-Knowledge to turn on the lights.

Category: Governance / Tech & Engineering
Tags: #ZeroKnowledge Governance treasury #Rust #AntiCollusion

The Problem: The “Whale” in the Room

Polkadot’s OpenGov is one of the most advanced decentralized governance systems in the world. However, like all weighted-voting systems, it suffers from the Principal-Agent Problem:

  • Concentration: High token concentration allows large holders (“Whales”) to push through Treasury proposals that may not align with the collective good.
  • Opacity of Execution: Once a Treasury Referendum passes and funds are disbursed, on-chain tracking stops. We rely on “social reports” to verify if the marketing campaign actually happened or if the software was actually built.
  • The Silence of Insiders: Team members, sub-contractors, or multi-sig signers often see mismanagement or fraud (e.g., funds siphoned off for personal use) but stay silent due to fear of doxxing, retaliation, or blacklisting by influential whales.

Collusion becomes profitable because accountability is low. If a Whale votes to fund a crony project, and that project embezzles the funds with no consequences, the Treasury bleeds.

The Proposal: “Whiteblowing” (Whistleblowing-as-a-Service)

I propose integrating a Byzantine-Fault Tolerant ZK-Primitive directly into the governance stack (potentially as a system parachain or a Pallet).

“Whiteblow” is a protocol that allows insiders to cryptographically prove financial misconduct or data mismatches regarding a funded proposal without revealing their identity.

It changes the game theory of collusion:

  • Current State: Looting the Treasury is safe if you have the votes.
  • Whiteblow State: Looting is high-risk because any insider (dev, accountant, multi-sig holder) can anonymously prove the fraud, slash the project’s staked DOT, and claim a bounty.

How It Works (The Architecture)

We have built a Proof-of-Concept in Rust using the Twisted ElGamal encryption scheme on the Ristretto255 curve (the same family as Polkadot’s sr25519).

The Protocol Flow:

The Commitment: When a team requests Treasury funds, they must register a set of “Insider Keys” (pubkeys of team members/signers) and lock a portion of tokens (or future vesting) as a bond.

The Detection: An insider detects a discrepancy (e.g., The on-chain report claims $100k for “Vendor X”, but the internal invoice shows $10k or a transfer to a personal wallet).

The ZK-Proof: The insider runs a client-side Rust binary that generates a Zero-Knowledge Consistency Proof:

  • Encrypts the discrepancy amount (Twisted ElGamal).
  • Proves the math is correct (Chaum-Pedersen).
  • Attests membership in the “Insider Set” (Schnorr/Ring Signature) without revealing which insider they are.

The Slash: The network verifies the proof. If valid, the smart contract automatically slashes the project’s bonded DOT.

The Bounty: The slashed funds are split: burned (deflationary) and sent to the whistleblower’s fresh address (Bounty).

Why This Fits Polkadot

  • Rust Native: The entire toolkit is built in Rust using curve25519-dalek, ensuring compatibility with Substrate and WASM runtimes.
  • Treasury Efficiency: It acts as a “Decentralized Auditor.” Instead of paying Big 4 firms to audit huge proposals, we crowdsource integrity to the people closest to the data.
  • Sybil Resistance: Proofs are bound to specific BountyIDs and key sets, preventing spam.

Technical Deep Dive

The core logic relies on a Non-Interactive Sigma Protocol (Fiat-Shamir).

  • Encryption: We use Twisted ElGamal to allow the network to operate on encrypted “misconduct values” (e.g., checking if Discrepancy > 0) without seeing the raw data initially.
  • Binding: We use a Chaum-Pedersen proof to bind the Intent (The Proposal ID) to the Evidence (The encrypted mismatch). This prevents “replay attacks” where a whistleblower tries to slash the wrong project.

Code Reference: You can review the cryptographic primitives and the BFT logic in our open repository: zk-whiteblow

Request for Comment

Looking for feedback from the community, specifically:

  • Integration: Should this live as a standalone Parachain offering “Audit Services” to the whole ecosystem, or as a Pallet integrated into the Asset Hub?
  • Economic Parameters: What is the ideal % for the Whistleblower Bounty to incentivize honesty without encouraging frivolous reports?

Diego Correa Tristain
Polkadot Blockchain Academy, Cohort 3

1 Like

The working proof-of-concept has a Fiat-Shamir Heuristic implementation which can conveniently be adapted to contain the context of the disclosure (BountyID, ReformerID, Quantities involved, receipts) and it uses elliptic curve cryptography for asymmetric key implementation: ZK-WhiteBlow.

It also implements a Pedersen-style commitment which can be conveniently aggregated in batches.

    // C. Whistleblowing (Client-Side)
    // The reformer creates the proof using the DAO's public key
    let (proof, ciphertext, commitment) = Reformer::create_whiteblow(fraud_amount, &dao.keys.pk);

    // D. Protocol Verification (On-Chain / Smart Contract)
    println!("\n🤖 [Protocol] Verifying ZK Proof...");
    
    let is_valid = proof.validate();

Can you explain more how the proof works? Most fraud (for example like we’ve seen in marketing bounty) are only proved by cross-referencing them with off-chain data (receipts, exchange, etc). What exactly is the on-chain proof validating and does it require an additional manual on-chain vote or something?

Thank you for digging deeper.

The ZKP implementation validates the source for credibility, which is what actually removes spam. The idea is that the proof filters who is allowed to raise a claim so that the receipt (the whistleblowing report) can be safely handed to an Executor: an entity with enough authority to apply a slash, but with limited resources to manually review every raw, unfiltered proposal. In other words, the ZKP layer acts as a cryptographic pre-filter that ensures only authenticated insiders can trigger this high-impact path.

In the context of this proposal, the core value lies in how we can hide, bind, and verify claims on-chain while keeping all sensitive off-chain information private, and this is achieved by anchoring everything in a well-defined Fiat–Shamir context domain. Concretely, in the current design the proof hides and binds a scalar discrepancy amount (modeled as a u64) together with a public/private keypair whose public key is a RistrettoPoint. These are embedded into a Fiat–Shamir transcript that can include the relevant context such as the bounty or proposal ID and hashes of the off-chain evidence. In this way, the ZK proof does not just say “I claims X,” but rather: “an authorized insider, within this exact context, attests that this specific encrypted discrepancy exists and is backed by this specific body of evidence,” all without revealing the evidence itself.

From here, the same construction naturally extends to a hash of a u64 or a larger numeric domain and to a multi-party key setup, where the on-chain verifier only checks that the proving key is a valid member of a predefined insider set. The crucial point is that the membership proof and the fraud claim receipt are both bound to the Fiat–Shamir transcript, so the insider’s attestation is inseparable from the precise context of the bounty, the project, and the hashed receipts or documents. This effectively turns the insider into a privacy-preserving “human oracle”: their proof is anonymous at the individual level, but cryptographically tied to a specific dispute domain, making it impossible to later reinterpret or recontextualize the claim without breaking the hash binding. In short, the mechanism leverages Fiat–Shamir to bind identity, fraud receipt, and off-chain evidence into a single context-specific proof, enabling accountable whistleblowing without sacrificing privacy.

For those interested in the underlying cryptography, there is an explanation of how Twisted ElGamal is implemented within the context of Sigma Protocols directly in the ZKP codebase here:

@sorpaas I think what op is trying to build is a rust programming library for Twisted ElGama(targeted against people that want to build a pallet around it? its not no-std which is requeired for smart contracts on polkavm…), its not like Noir or Circom where the user defines a zk circuit and it generates a solidity verifier contract that users can upload and use with their smart contracts, but rather a generic rust library for this, but since most zk dapps use Groth16, Halo2 and/or plonk(aka other zk systems). Since this seems to be ment as an extra layer on opengov I want to ask:

How are you planning on getting this pallet into the chains that people vote on?

how can it be byzantine fault tolerant when its not quantum safe?

Have you made a client proof generator that uses the browser with wasm or similar to check client side proofs?

Looks like you are using a std random number generator, not compatible with polkavm, how are you thinking of putting your application into production? will you have a pallet with a custom rng or will you hack one together that works with polkavm?

@labormedia

Do you have a PoC of this on some local substrate chain?

Thanks for the sharp questions @RustSyndicate. You are right to check the implementation details—it is important to be specific about how this actually compiles and runs. However, while I am happy to clarify the engineering stack to prove viability, I want to emphasize that these are implementation details that support the larger goal: solving the Principal-Agent problem in the Treasury.

Regarding your concerns about no_std environments and randomness, the architecture relies on a strict separation between the Prover and the Verifier. The on-chain Verifier is strictly no_std because it never needs to generate randomness; instead, it utilizes the Fiat-Shamir Heuristic to derive challenges deterministically by hashing the proof transcript. The random blinding factors are generated solely by the Prover, which runs off-chain (in a browser or CLI) where std and OS entropy are available. We simply use curve25519-dalek with default-features = false, keeping the pallet logic lightweight and fully compatible with the Substrate runtime.

On the topic of the Ring Signature proof of concept, we are moving beyond theoretical descriptions to a concrete port of the 1-out-of-N Sigma Protocol (Abe-Ohkubo-Suzuki). The verification logic does not require heavy circuits or trusted setups; it is a linear “Ring Loop” that is highly efficient for the Polkadot Runtime. The chain verifies the ring is closed by iterating through the set of public keys without ever needing to identify the specific signer. It essentially looks like this:

// On-Chain Verifier (no_std)
// The Runtime iterates through the keys to ensure the ring "closes" mathematically
let mut current_challenge = proof.c_0;

for (i, pubkey) in insider_keys.iter().enumerate() {
    // 1. Add context to transcript
    transcript.append_message(b"ring_member", pubkey.as_bytes());
    
    // 2. Calculate the "commitment" for this step using the response (s)
    // R = s*G - c*P
    let R = RistrettoPoint::vartime_double_scalar_mul_basepoint(
        &proof.s[i], 
        &RistrettoPoint::basepoint(), 
        &current_challenge, 
        &(-pubkey)
    );
    
    // 3. Hash the result to get the challenge for the NEXT member
    transcript.append_point(b"R", &R);
    current_challenge = transcript.challenge_scalar(b"next_challenge");
}

// 4. The Loop Must Close: The final challenge must match the initial seed
ensure!(current_challenge == proof.c_0, "Invalid Ring Signature");

Addressing the distinction between BFT and Quantum safety, these operate at different layers of the stack. Byzantine Fault Tolerance here refers to the system’s ability to reach a truthful consensus on slashing even if a majority of the multisig insiders are corrupt (“Byzantine”); a single honest insider can generate the valid proof that forces the protocol to slash. Quantum safety refers to the cryptographic hardness, and in this regard, we rely on the same discrete log assumptions as the Polkadot Relay Chain itself (sr25519).

However, I want to ensure we don’t miss the forest for the trees. The purpose of this RFC is not just to debate library constraints—which are solvable engineering tasks—but to validate the Governance Mechanism. The critical feedback we need from the community is not on rand crate dependencies, but on the economic game theory: Does a 100% slash vs. a partial bounty create the right incentives? Should this live on Asset Hub or as a standalone auditing parachain? I’ve provided the code above to show the engine works, but I am most interested in discussing where we should drive this concept towards to.

I appreciate the comments.

I will leave this DRAFT proposal in standby in response to a higher level and technically detailed, consistent and verified for the expansion on the benefits of treating anti-trust considerations endogenously and intrinsically within the Protocol Architecture.

It would result in a more complex RFC to review and workover, but the intention is to open the debate on what I believe is the best course towards the mission behind the protocol.

I am learning too much on this process too. I am sure many newcomers would be interested in this chain of thought and participation.