LOCAL-TRUE · not on-chain

Sealed polls · private votes

Private Ballot Studio

World-class educational studio for Midnight-style private ballots: publish a public question, seal votes + nullifiers in a vault, prove eligibility without revealing identity, then run a tally theater that certifies counts — without claiming on-chain settlement, Lace, or a real Compact runtime. By @kshot9000 · nightdream.xyz.

B Ballot V Vote T Tally ? Shortcuts D Donate
Honest scope: local HTML/JS simulation only. Does not run Compact, a proof server, Lace, or real ADA / DUST transfers. Does not claim GitHub Pages is live until Actions are enabled. Commitments, nullifiers, and tallies are teaching stand-ins — verify against official Compact / Zswap crypto before shipping.

Ballot journey

Labeled phases from idle → sealed → voting → tallying → certified. Double-vote reject is first-class.

  1. 1
    Idle Compose a poll
  2. 2
    Sealed Ballot opened · commit live
  3. 3
    Voting Sealed ballots + nullifiers
  4. 4
    Tallying Aggregate without openings
  5. 5
    Certified Counts + π (simulated)

Phase: idle — compose a ballot to begin.

What a private ballot is really saying

Observers see the question, option labels, ballot commitments, and nullifiers. Choices and voter secrets stay local until (optionally) disclosed.

Private vault

Never leave the client in the dual-state model. Teaching stand-in: values you type below.

  • Voter secrets & eligibility salts
  • Chosen option index
  • Opening notes for ballot commits

Public surface

What the simulated “ledger” / tally board is allowed to see.

  • Question + option labels
  • Ballot commitment hashes
  • Nullifiers (anti-double-vote)
  • Certified aggregate counts

Ballot veil

How veiled individual choices stay after the last action.

100% veiled (no disclose)

Public rail

How much the board learned from commits + tally.

0% public surface

Compose & seal a ballot

Public question + options. Eligibility salt stays in the vault. Press B to focus.

New poll

0/120
Public labels only — choices stay sealed until tally (or disclose).
Binds who may vote without publishing the roster.

Active ballot preview

No ballot yet Seal a poll to publish the question, option labels, and eligibility commitment — never the salt itself.

Cast a sealed vote

Choice + voter secret → ballot commit + nullifier. Double nullifiers reject. Press V.

Private ballot

Combined with eligibility salt → nullifier (anti-double-vote).

Eligibility & nullifier theater

  1. 1
    Bind voter secret
    hash locally
    —
  2. 2
    Eligibility gate
    roster membership (sim)
    —
  3. 3
    Emit nullifier
    public · unique per voter
    —
  4. 4
    Seal ballot commit
    choice veiled
    —
Awaiting cast…

Tally / certify theater

Simulated stages only — no proof server. Tamper & double-vote fails are intentional teaching moments. Press T.

  1. 1
    Collect commits
    public ballot hashes
    —
  2. 2
    Check nullifiers
    reject duplicates
    —
  3. 3
    Aggregate counts
    openings stay local (sim)
    —
  4. 4
    Certify tally π
    SIMULATED · SHA-256 stand-in
    —

0% — idle

No tally yet

—

LOCAL STUB · simulated certification only.

Certified results

Seal votes, then run tally to see aggregate bars.

Awaiting tally…

Ballot board

Local-only ballots + sealed votes in localStorage. Clear anytime — nothing left the browser.

Ballots: 0 Votes: 0 Rejected: 0 Certified: 0

Open ballots

    Sealed votes

      Anti-pattern vs safe pattern

      Teaching sketches — not deployable Compact. Always verify against official docs.

      ✗ Anti-pattern — clear votes on-chain
      // BAD: public ledger sees every choice
      ledger {
        voter: Bytes<32>;   // identity leaked
        choice: Uint<8>;    // vote leaked
      }
      ✓ Safer sketch — commit + nullifier
      // BETTER (sketch): public commit + nullifier
      ledger {
        ballotCommit: Bytes<32>;
        nullifier: Bytes<32>;  // unique, no identity
        tallies: Vector<Uint<64>>;
      }
      witness choice: Uint<8>;
      witness voterSecret: Bytes<32>;
      // prove eligible + one-vote without publishing who

      These snippets are educational illustrations. Official Compact syntax, circuits, and Zswap commitments may differ — check Midnight docs before shipping.