Ballot Tally Algorithms

We publish our counting logic so anyone can reproduce tallies offline. For Ranked Choice Voting (Instant Runoff), each round counts current first preferences; the lowest candidate is eliminated and their ballots transfer to the next ranked continuing candidate until a winner emerges or a tie persists.

Ranked Choice (IRV) Example

[
  {
    "round": 1,
    "counts": {
      "A": 2,
      "B": 2,
      "C": 1
    },
    "eliminated": "C",
    "exhausted": 0
  },
  {
    "round": 2,
    "counts": {
      "A": 2,
      "B": 3
    },
    "exhausted": 0
  }
]

Winner: B

Tie-break strategy (if needed): lexicographically compare candidate IDs among lowest group; eliminate last.

Simple & Approval

Simple: highest vote count wins. Approval: each option accrues one count per approving voter; highest total wins. Hash of tally uses canonical JSON: sha256(JSON.stringify({ ballotId, type, results })).

Verification Tools

Use the offline CLI (packages/shared/dist/verify/cli.js) to recompute tally hashes and verify the ledger chain. Download a ballot export bundle and run:

node packages/shared/dist/verify/cli.js --ballot export.json --ledger ledger.json