Standards

Chapter 10 / 15

Zero-Knowledge Proofs

selective_disclosure, verified_by — proving properties without revealing data.


ZK proofs let a contract verify a claim — "the user is over 18", "the balance exceeds 1000 USDC", "the merkle path is valid" — without the contract ever seeing the underlying data. Covenant's zk_proof type and verified_by clause compile to STATICCALL into the chain's ZK precompile (0x05000x0501).

age_gate.cov — prove age without revealing it
interface IZKVerifier {
    // Returns true if proof is valid for the given public inputs
    view verify(proof: zk_proof, inputs: [field; 4]) -> bool;
}

record AgeGate {
    verifier:  address;    // chain-deployed ZK verifier precompile
    min_age:   u32  = 18;
    members:   map(address => bool);

    error ProofInvalid();

    // User proves age >= 18 without revealing birth date
    // Public inputs: [min_age, current_year, 0, 0]
    action join(proof: zk_proof) {
        let ok = IZKVerifier(self.verifier).verify(
            proof,
            [self.min_age as field, block.timestamp / 31_536_000 as field, 0, 0]
        );
        if !ok {
            revert_with ProofInvalid();
        }
        self.members[msg.sender] = true;
    }

    view is_member(who: address) -> bool {
        return self.members[who];
    }
}
merkle_drop.cov — airdrop via Merkle proof
record MerkleDrop {
    root:     hash;
    token:    address;
    claimed:  map(address => bool);

    error AlreadyClaimed();
    error InvalidProof();

    // Claim tokens by proving inclusion in the Merkle tree
    action claim(amount: u256, proof: [hash; 32]) {
        if self.claimed[msg.sender] {
            revert_with AlreadyClaimed();
        }

        // Reconstruct leaf = keccak256(address ++ amount)
        let leaf = keccak256(msg.sender, amount);

        // Verify Merkle path
        if !merkle_verify(leaf, proof, self.root) {
            revert_with InvalidProof();
        }

        self.claimed[msg.sender] = true;
        IERC20(self.token).transfer(msg.sender, amount);
    }
}

Annotations

zk_proofis an opaque byte-array type. Its validity is verified by the ZK precompile, not Covenant itself.
fieldis a finite-field element (BN254 scalar by default). ZK circuits express inputs as field elements.
merkle_verifyis a Covenant built-in that compiles to the ZK precompile's Merkle path verification entry-point.
Nova IVC vs Halo2Nova is preferred for recursive proofs (incrementally verifiable computation); Halo2 for single-shot range/inclusion proofs. Chain precompile support varies.

Key takeaways