DEV Community

Cover image for Mastering Zero-Knowledge Identity Patterns in Midnight with Compact
Efe Kırbaş
Efe Kırbaş

Posted on

Mastering Zero-Knowledge Identity Patterns in Midnight with Compact

If you're coming from the world of EVM and Solidity, you know the golden rule: everything on the blockchain is public. If you need to verify a user's identity, you typically have to store their public address or identity hash directly on-chain, creating a permanent, public trail of their activities.

Midnight Network flips this paradigm on its head. As a data-protection blockchain, it allows developers to build applications that protect sensitive data while still guaranteeing execution correctness through Zero-Knowledge (ZK) proofs.

In this guide, we're going to dive into Compact (Midnight’s TypeScript-inspired smart contract language) and explore a fundamental privacy pattern: Zero-Knowledge Identity Verification.

The Concept: Commit-Reveal Identity

To verify a user without exposing who they are, we use a pattern where:

  1. The user holds a Private Secret.
  2. The contract stores a Public Commitment (a hash of the secret).
  3. The user generates a ZK Proof locally to prove they know the secret behind the commitment, without ever revealing the secret itself to the network.

In Compact, this is achieved through three core pillars:

  • Ledger: Public state visible to everyone.
  • Witness: Private data that never leaves the user's local machine.
  • Circuit: The logic that generates a ZK proof locally before submitting a transaction.

The Code Implementation

Here is a fully functional Compact contract implementing this pattern.

pragma language_version >= 0.19;
import CompactStandardLibrary;

// 1. PUBLIC LEDGER STATE
// Cell represents a single updatable storage slot on the blockchain.
export ledger last_user: Cell<Bytes<32>>;

// 2. PRIVATE WITNESS DATA
// Witnesses are strictly local. This value is never sent over the network.
witness secret_key(): Bytes<32>;

// 3. ZK CIRCUITS
export circuit update(): [] {
    // Read the private secret key locally from the user's device
    const sk = secret_key();

    // Derive a cryptographic commitment (identifier) from the private key
    const myself = persistent_hash<Bytes<32>>(sk);

    // Write the commitment to the public ledger. 
    // disclose() is used to intentionally make the hashed value public.
    last_user.write(disclose(myself));
}

export circuit verify_user(): [] {
    // Read the private secret key locally again
    const sk = secret_key();

    // Re-calculate the identifier
    const myself = persistent_hash<Bytes<32>>(sk);

    // ZK Assertion: Ensure the calculated hash matches the public ledger state.
    // If this fails, the proof generation fails.
    assert myself == last_user.read(), "Oops: you're not the current user";

    // If successful, the blockchain only receives a mathematical proof 
    // that this assertion passed. The `secret_key` remains hidden!
}
Enter fullscreen mode Exit fullscreen mode

Breaking Down the Magic

Let's look at why this works securely and doesn't leak data:

Step 1: The Witness Function

Unlike Solidity where msg.sender is implicitly public, Compact forces you to define private data explicitly using the witness keyword. When a user interacts with this contract, their local Midnight Proof Server provides the secret_key. It is never broadcasted to the network.

Step 2: The Hash Commitment

We cannot store the secret_key directly on the ledger. Instead, we use persistent_hash, a built-in Compact function designed specifically for deriving state identifiers from private data. It creates a one-way deterministic hash.

Step 3: Zero-Knowledge Assertion

This is where the Zero-Knowledge magic happens. When verify_user() is called, the user's machine executes the code, hashes their local secret, and compares it against last_user.read().
If they match, the machine generates a ZK Proof saying: "I executed this code, and the assertion was true."
The Midnight network validates the proof, not the data. The network knows the user is authorized, but has absolutely no idea what the secret_key actually is.

Conclusion

By separating data into Ledger (public) and Witness (private), and combining them inside a Circuit, Compact makes building Zero-Knowledge applications incredibly intuitive.

You no longer have to be a cryptographer writing complex polynomial equations to utilize ZK-rollups. With a syntax that feels right at home for Web2 and Web3 developers alike, Midnight allows you to build dApps where privacy is the default, not an afterthought.

Have you experimented with Compact yet? Let me know what you're building in the comments!

Top comments (0)