Midnight logoMidnight Academy
← back to projects

Project 03

Private Voting

This is where Module 04's witness pattern stops being an abstract exercise and becomes something genuinely useful: a vote that's publicly countable, but privately cast.

What you'll learn

The contract

Save this as contracts/voting.compact:

pragma language_version >= 0.23;

import CompactStandardLibrary;

witness getVoterChoice(): Boolean;

export ledger yesVotes: Uint<32>;
export ledger noVotes: Uint<32>;

export circuit castVote(): [] {
    if (disclose(getVoterChoice())) {
        yesVotes = yesVotes + 1;
    } else {
        noVotes = noVotes + 1;
    }
}

Read this contract closely

Notice what's not in ledger state: there's no list of who voted, and no record tying any specific voter to yes or no. Only two running counts exist on-chain. The vote itself, cast inside getVoterChoice(), stays private to the voter, only the tally increment is disclosed.

The honest limitation here

This simplified version doesn't yet prevent one wallet from calling castVote()multiple times. A real voting system needs a way to prove "this voter hasn't voted yet" without revealing whichvoter is calling, typically via a nullifier pattern. That's a genuinely harder problem, and a good next thing to research once this version makes sense to you.

Build it yourself

compact compile contracts/voting.compact contracts/managed/voting

Deploy, call castVote() a few times with your witness returning different values, and confirm yesVotes and noVotes update correctly, with no way to recover which specific call produced which result just from reading the chain.

Next: Project 04 — Messaging →