<divclass="part-sub">Before we touch any math, let's understand<br>what makes electronic voting one of the hardest<br>open problems in applied cryptography.</div>
</div>
`
},
{
part: 'Part I: The Problem',
title: 'The Contradictory Requirements',
html: `
<p>In a paper election, we take two things for granted that are actually in deep tension:</p>
<divstyle="font-size:13px;">You (and the public) should be able to verify that the result is correct.</div>
</div>
</div>
<divclass="think-box">Think about this tension for a moment. If nobody can see your vote, how can anyone verify the count is right? And if everyone can verify, doesn't that mean votes are visible?<br><br>In a paper election, we solve this with physical properties: sealed envelopes, physical mixing of ballots, public counting by humans. But in a digital system, there are no envelopes. Bits can be copied, modified, and traced. How do we square this circle?</div>
`
},
{
part: 'Part I: The Problem',
title: 'What Could Go Wrong?',
html: `
<p>Let's think like an attacker. In an electronic election, who might cheat?</p>
<divstyle="margin:14px 0;">
<divstyle="margin:8px 0;"><spanclass="em">The server</span> -- could silently change votes, add fake ballots, or drop real ones.</div>
<divstyle="margin:8px 0;"><spanclass="em">An insider</span> -- a system admin could read all votes and sell the data.</div>
<divstyle="margin:8px 0;"><spanclass="em">A man-in-the-middle</span> -- could intercept your vote between your browser and the server.</div>
<divstyle="margin:8px 0;"><spanclass="em">The voting software itself</span> -- could display "Alice" but actually send "Bob".</div>
</div>
<divclass="problem-box">The fundamental challenge: in an electronic system, the entity that <em>runs</em> the election is also the entity most capable of <em>cheating</em>. We need a protocol where <strong>you don't have to trust anyone</strong> -- not the server, not the operators, not even the software on your machine.</div>
`
},
{
part: 'Part I: The Problem',
title: 'The Three Properties We Need',
html: `
<p>Cryptographers have formalized what a secure electronic election requires:</p>
Anyone (even a random citizen with no special access) can verify: "the published result matches the submitted ballots, and no ballots were added, removed, or changed."<br>
<spanclass="dim">This is the big one. It means the entire election is publicly auditable using math alone.</span>
</div>
<divclass="insight-box">The Swiss Post system achieves all three simultaneously. That's what we're about to see.</div>
`
},
{
part: 'Part I: The Problem',
title: 'The High-Level Idea',
html: `
<p>Here's the plan, in plain language. We'll formalize everything later.</p>
<olstyle="line-height:2.2;">
<li><spanclass="em">Encrypt</span> every vote in the voter's browser. The server stores only ciphertext -- random-looking noise.</li>
<li><spanclass="em">Shuffle</span> the encrypted votes through multiple independent nodes, so nobody can trace a ciphertext back to a voter.</li>
<li><spanclass="em">Prove</span> each shuffle was honest, using zero-knowledge proofs. Anyone can verify these proofs.</li>
<li><spanclass="em">Decrypt</span> only after shuffling. The result comes out in random order -- votes are visible, but voter identities are lost.</li>
</ol>
<divclass="analogy-box">Imagine 6 people write their votes on paper and seal them in identical envelopes. The envelopes pass through 5 rooms. In each room, a person secretly rearranges them, puts each into a new envelope, and slides them under the door to the next room. After 5 rooms, nobody can remember the order. Now you open them and count. That's a mix-net. Except we need to do it digitally, and prove nobody cheated in any room.</div>
<divclass="math-block"><spanclass="def">Step 3: Pick a generator g</span>
g = 4 <spanclass="cmt">(= 2<sup>2</sup>, a quadratic residue)</span>
<spanclass="cmt">Every element of G<sub>q</sub> can be written as g<sup>k</sup> for some k.</span>
<spanclass="cmt">With p=23: 4<sup>1</sup>=4, 4<sup>2</sup>=16, 4<sup>3</sup>=18, 4<sup>4</sup>=3, ... cycles through all 11 elements.</span></div>
<divclass="think-box">Why do we need the group to have <em>prime</em> order? Because prime order means there are no non-trivial subgroups. This prevents "small subgroup attacks" where an attacker could leak information about secrets by trapping values in a small subgroup. With prime order q, every element except 1 generates the whole group.</div>
`
},
{
part: 'Part II: The Math',
title: 'Building Block 1b: The Discrete Log Problem',
html: `
<p>The security of everything that follows rests on one assumption:</p>
<divclass="def-box">
<divclass="def-title">The Discrete Logarithm Problem (DLog)</div>
Given g and h = g<sup>x</sup> mod p, find x.<br><br>
<spanclass="dim">Going "forward" (computing g<sup>x</sup>) is fast: O(log x) multiplications.</span><br>
<spanclass="dim">Going "backward" (finding x from g<sup>x</sup>) is believed to be infeasible: best known algorithms take O(√q) steps.</span>
</div>
<divclass="analogy-box">Think of it like a one-way street. You can easily compute 4<sup>x</sup> mod p for any x. But if I give you the result and ask "what was x?" -- you're stuck. For 256-bit q, brute force would take ~2<sup>128</sup> operations. That's more than the number of atoms in the universe.</div>
<divclass="insight-box">This asymmetry is the foundation. Secret keys are exponents (easy to compute with, hard to extract from public values). Everything -- encryption, proofs, shuffles -- exploits this one-way door.</div>
`
},
{
part: 'Part II: The Math',
title: 'Building Block 2: ElGamal Encryption',
html: `
<p>Now we can encrypt. <spanclass="em">ElGamal encryption</span> hides a message inside the group using the discrete log problem.</p>
= (pk<sup>r</sup>· m) / (g<sup>r</sup>)<sup>sk</sup>
= (g<sup>sk·r</sup>· m) / g<sup>sk·r</sup>
= m <spanclass="grn">the pk<sup>r</sup> cancels out!</span></div>
<divclass="think-box">Notice that the randomness r appears in both γ and φ. If you encrypt "Alice" twice with different r values, you get two completely different ciphertexts. This is crucial: the server can't tell if two voters made the same choice by comparing ciphertexts.</div>
`
},
{
part: 'Part II: The Math',
title: 'Building Block 2b: The Re-Encryption Trick',
html: `
<p>Here's the magical property that makes the whole mix-net possible:</p>
<divclass="def-box">
<divclass="def-title">ElGamal Re-Encryption</div>
Given a ciphertext (γ, φ) encrypting some unknown message m, anyone can produce a <em>new</em> ciphertext (γ', φ') that also encrypts m -- without knowing m or the secret key.
φ' = pk<sup>r'</sup>·φ = pk<sup>r'+r</sup>· m
<spanclass="cmt">Result: (γ', φ') is a valid encryption of the same m</span>
<spanclass="cmt">with combined randomness (r' + r) instead of r.</span></div>
<divclass="insight-box">This is the core trick of the mix-net. A shuffle node can take a ciphertext, re-encrypt it (changing every bit), and the result still decrypts to the same vote. The new ciphertext looks <em>completely unrelated</em> to the old one -- even to someone who sees both. Under the DDH assumption, no efficient algorithm can link them.</div>
<divclass="think-box">This doesn't require the secret key! Anyone with just the public key can re-encrypt. That's why a mix-node doesn't need to decrypt in order to shuffle -- it just permutes and re-encrypts.</div>
`
},
{
part: 'Part II: The Math',
title: 'Building Block 3: Zero-Knowledge Proofs',
html: `
<p>The last building block. We need a way to prove statements without revealing secrets.</p>
<divclass="def-box">
<divclass="def-title">Zero-Knowledge Proof</div>
A protocol where a <em>prover</em> convinces a <em>verifier</em> that a statement is true, without revealing <em>any</em> information beyond the truth of the statement itself.
</div>
<divclass="analogy-box"><strong>The Ali Baba cave:</strong> Imagine a circular cave with a locked door in the middle. I claim I know the secret word that opens the door. You stand at the entrance. I go in and randomly take the left or right path. You then shout "come out the left side!" or "come out the right side!" If I know the word, I can always comply (opening the door if needed). If I don't, I can only comply 50% of the time. After 100 rounds, you're convinced. But you learned <em>nothing</em> about the secret word -- you could have simulated this whole exchange yourself by recording only the rounds where I got lucky.</div>
<p>We'll use two kinds of zero-knowledge proofs:</p>
<ol>
<li><spanclass="em">Schnorr proof</span> -- "I know the secret key behind this public key" (used for key holders)</li>
<li><spanclass="em">Bayer-Groth argument</span> -- "I shuffled these ciphertexts honestly" (used for mix-nodes)</li>
</ol>
`
},
{
part: 'Part II: The Math',
title: 'The Schnorr Protocol (Step by Step)',
html: `
<p>Let's see a concrete zero-knowledge proof. I want to prove I know <spanclass="secret">sk</span> such that <spanclass="public">pk</span> = g<sup>sk</sup>, without revealing sk.</p>
<spanclass="blu">Prover (knows sk)</span><spanclass="grn">Verifier (knows only pk)</span>
<spanclass="cmt">1.</span> Pick random b ← Z<sub>q</sub>
Compute c = g<sup>b</sup>
<spanclass="cmt">--- send c ---></span>
<spanclass="cmt">2.</span> Pick random challenge e ← Z<sub>q</sub>
<spanclass="cmt"><-- send e ---</span>
<spanclass="cmt">3.</span> Compute z = b + e · sk mod q
<spanclass="cmt">--- send z ---></span>
<spanclass="cmt">4.</span> Check: g<sup>z</sup> == c · pk<sup>e</sup> ?
<spanclass="def">Why does the check work?</span>
g<sup>z</sup> = g<sup>(b + e·sk)</sup> = g<sup>b</sup>· g<sup>e·sk</sup> = c · (g<sup>sk</sup>)<sup>e</sup> = c · pk<sup>e</sup><spanclass="grn">always passes for honest prover</span></div>
<divclass="think-box"><strong>Why is this zero-knowledge?</strong> The verifier sees (c, e, z). But they could have <em>generated the same transcript themselves</em> without the prover: pick any z and e, compute c = g<sup>z</sup>· pk<sup>-e</sup>. This "simulated" transcript is indistinguishable from a real one. So the proof reveals no information about sk.
<strong>Why is this sound?</strong> If you could answer two different challenges e and e' for the same commitment c, then from z - z' = (e - e') · sk mod q, we can extract sk. So a cheater who doesn't know sk can only guess one challenge correctly -- probability 1/q (negligible).</div>
<p>The Schnorr protocol is interactive (the verifier sends a challenge). For an election, we need proofs anyone can check later, with no interaction.</p>
The prover computes the challenge themselves using a hash function. Since the hash is unpredictable (modeled as a "random oracle"), the prover can't cheat by picking c to match a pre-chosen e.
b ← Z<sub>q</sub>, c = g<sup>b</sup>, e = H(g, pk, c), z = b + e·sk mod q
<spanclass="def">Publish proof = (e, z)</span><spanclass="cmt">(just two numbers!)</span>
<spanclass="cmt">Anyone can verify:</span>
c' = g<sup>z</sup>· pk<sup>-e</sup><spanclass="cmt">(recompute commitment from proof)</span>
check: H(g, pk, c') == e ?</div>
<divclass="insight-box">This is how all proofs work in the Swiss Post system. Every proof is non-interactive: just a few numbers that anyone can verify with public data, at any time, without contacting the prover. The hash function (SHA3-256) acts as the "honest verifier" that nobody can manipulate.</div>
`
},
{
part: 'Part II: The Math',
title: 'Recap: Our Toolkit',
html: `
<p>Before we start the election, let's recap what we have:</p>
<divstyle="font-size:13px;">Encrypt: (γ, φ) = (g<sup>r</sup>, pk<sup>r</sup>·m). Random r makes each ciphertext unique. Can re-encrypt without decrypting.</div>
<divstyle="font-size:13px;">Prove knowledge of secrets without revealing them. Schnorr for keys, Bayer-Groth for shuffles. Non-interactive via Fiat-Shamir.</div>
</div>
</div>
<p>Now let's run an election and see how these pieces fit together.</p>
<divclass="think-box">As we go through the election, keep asking yourself: "Where is the privacy coming from?" and "Where is the verifiability coming from?" You'll see that privacy comes from <em>encryption + re-encryption shuffles</em>, and verifiability comes from <em>zero-knowledge proofs at every step</em>.</div>
<divclass="insight-box"><strong>Why square the primes?</strong> We need encodings inside G<sub>q</sub> (the quadratic residues). Squaring any number mod p guarantees it lands in G<sub>q</sub>. Small primes are used so that after decryption, we can recover the vote by trial division: if the decrypted value is 4 = 2<sup>2</sup>, the vote was Alice. If it's 9 = 3<sup>2</sup>, Bob.</div>
`
},
{
part: 'Part III: The Election',
role: 'CC0 Operator (Bern)',
roleClass: 'role-cc',
title: 'Distributed Key Generation',
html: `
<p>You are <spanclass="em color-cc">CC0, the operator in Bern</span>. You sit at an air-gapped machine. Your job: generate one piece of the election's encryption key.</p>
<divclass="decision-box">
<divclass="decision-question">Generate your key pair?</div>
<divclass="decision-answer role-cc">Generate my key</div>
<spanclass="public">pk[0]</span> = g<sup>sk[0]</sup> mod p = 164907173125453164942397900344209023580...
<spanclass="public">pk[1]</span> = g<sup>sk[1]</sup> mod p = 865964935823822544135231120873786690830...</div>
<divclass="insight-box"><strong>Why two components?</strong> The system uses "wide" ElGamal with w=2 components per ciphertext. This is needed for the return code protocol (which we'll skip in detail). The important point: the secret key is a <em>vector</em> (sk[0], sk[1]) and the public key is a <em>vector</em> (pk[0], pk[1]).</div>
<pclass="note">There are 5 key holders total: 4 Control Components (Bern, Zurich, Geneva, Lugano) + 1 Electoral Board. Each generates independently.</p>
`
},
{
part: 'Part III: The Election',
role: 'CC0 Operator (Bern)',
roleClass: 'role-cc',
title: 'Proving You Know Your Key (Schnorr)',
html: `
<p>You just generated a secret key. But how does the world know you <em>actually know</em> the secret behind your public key, and didn't just pick a random number as pk?</p>
<p>Answer: you generate a <spanclass="em">Schnorr proof</span>. This is exactly the protocol we studied in Part II.</p>
<divclass="decision-box">
<divclass="decision-question">Generate the Schnorr proof?</div>
<divclass="crypto-block"><spanclass="highlight">1.</span> b ← Z<sub>q</sub>, c = g<sup>b</sup> = <spanclass="public">196993736651760197696345266502366676991...</span>
<spanclass="highlight">2.</span> e = H(p, q, g, pk, c) = <spanclass="value">280555736662452288549346417809892436748...</span>
<spanclass="highlight">3.</span> z = b + e·sk mod q = <spanclass="value">137947587127192694451619751067570738829...</span>
<spanclass="label">Proof = (e, z)</span><spanclass="dim">Two numbers. Anyone can check: g<sup>z</sup>· pk<sup>-e</sup> recomputes c, then H(... c) == e.</span>
<spanclass="dim">Self-check:</span> g<sup>z</sup> == c · pk<sup>e</sup><spanclass="public">PROOF VALID</span></div>
<divclass="think-box">After this proof, anyone in the world can verify that the CC0 operator in Bern <em>genuinely knows</em> the secret key behind their public key. But the proof reveals <em>zero information</em> about what that secret key is. This is the Schnorr Σ-protocol + Fiat-Shamir in action -- exactly as we defined it.</div>
`
},
{
part: 'Part III: The Election',
role: 'CC0 Operator (Bern)',
roleClass: 'role-cc',
title: 'The Other Key Holders',
html: `
<p>Three more Control Components do the same (key generation + Schnorr proof), each on their own air-gapped machine in a different Swiss city:</p>
<p>Now, combine all 5 public keys by multiplication:</p>
<divclass="crypto-block"><spanclass="label">ElectionPK</span> = pk<sub>0</sub>· pk<sub>1</sub>· pk<sub>2</sub>· pk<sub>3</sub>· pk<sub>4</sub> mod p
= g<sup>(sk<sub>0</sub> + sk<sub>1</sub> + sk<sub>2</sub> + sk<sub>3</sub> + sk<sub>4</sub>)</sup> mod p
<divclass="insight-box"><strong>Nobody ever computes the full secret key.</strong> The combined secret sk = sk<sub>0</sub> + ... + sk<sub>4</sub> mod q exists mathematically, but no single machine ever holds it. To decrypt, all 5 must cooperate -- each removing their own layer. This is an additive secret sharing with threshold 5-of-5.</div>
`
},
{
part: 'Part III: The Election',
role: 'Registry Officer',
roleClass: 'role-chancellor',
title: 'Printing the Voting Cards',
html: `
<p>Each voter gets a physical card in the mail with secret codes. This card is the basis for <spanclass="em">individual verifiability</span>.</p>
<divclass="think-box"><strong>Why does individual verifiability need a physical card?</strong> The voting software on your computer could be compromised. If the return code was generated by the same software, a virus could fake it. But the code on the <em>paper card</em> was generated during setup by the 4 CCs -- completely independent of your browser. If the code on screen matches the code on paper, no single compromised component could have faked it.</div>
`
},
// --- Phase 2: Voting ---
{
part: 'Part III: The Election',
html: `
<divclass="part-card"style="padding-top:20vh;">
<divclass="part-num">Phase 2</div>
<h1>Voting</h1>
<divclass="part-sub">6 voters cast their ballots. All encryption<br>happens in the browser. The server sees only noise.</div>
</div>
`
},
{
part: 'Part III: The Election',
role: 'Voter Anna',
roleClass: 'role-voter',
title: 'Anna Votes for Alice',
html: `
<p>You are <spanclass="em color-voter">Anna</span>. You open the voting portal, enter SVK-0000, and select Alice.</p>
<divclass="decision-box">
<divclass="decision-question">Who do you vote for?</div>
<spanclass="label">Card:</span> Alice = <spanclass="highlight">CC00</span><spanclass="public">MATCH!</span><spanclass="dim">← "My vote was recorded as Alice."</span>
<spanclass="dim">Anna enters BCK-0000 to confirm.</span>
<spanclass="label">Card:</span> VCC = <spanclass="highlight">VCC00</span><spanclass="public">MATCH!</span><spanclass="dim">← "My vote is sealed."</span></div>
<divclass="insight-box"><strong>What just happened cryptographically:</strong> Anna's browser encrypted "4" under the ElectionPK. The server stored (γ, φ) -- which is computationally indistinguishable from a random pair of group elements (IND-CPA under DDH). The return code CC00 was computed by 4 independent CCs doing partial decryptions of a pre-computed code -- no single CC learned Anna's choice. Anna verified using a code from a <em>physical card</em> that was generated offline.</div>
`
},
{
part: 'Part III: The Election',
role: 'Voters',
roleClass: 'role-voter',
title: 'The Remaining 5 Voters',
html: `
<p>Five more voters go through the same process. Each browser independently generates a random r and encrypts.</p>
<divclass="think-box"><strong>Notice:</strong> Anna, Beat, Clara, Daniel, and Eva all voted for Alice (m=4). But each used a different random r<sub>i</sub>, so all 5 ciphertexts are <em>completely different</em>. The server cannot tell, by looking at the ciphertexts, that these 5 voters made the same choice. This is the IND-CPA property of ElGamal in action.</div>
<spanclass="dim">[2] Clara </span><spanclass="value">FF1D9B7179...735424E93A</span>
<spanclass="dim">[3] Daniel </span><spanclass="value">4931157C26...9D6A03E982</span>
<spanclass="dim">[4] Eva </span><spanclass="value">13C275835F...BF41E92D91</span>
<spanclass="dim">[5] Fritz </span><spanclass="value">1232996CD9...3791B60DCF</span></div>
<divclass="problem-box">We could decrypt these right now and count. But there's a problem: ciphertext [0] belongs to Anna, [1] to Beat, etc. If we decrypt in order, we learn <em>who voted for what</em>. That violates ballot secrecy. We need to break the link between the voter's identity and their ciphertext <em>before</em> decrypting.</div>
<p>This is where the mix-net comes in.</p>
`
},
// --- Phase 3: Tally ---
{
part: 'Part III: The Election',
html: `
<divclass="part-card"style="padding-top:20vh;">
<divclass="part-num">Phase 3</div>
<h1>Tally: The Mix-Net</h1>
<divclass="part-sub">5 nodes shuffle the ballots in sequence.<br>Each proves its shuffle was honest.<br>Then the votes are decrypted in random order.</div>
</div>
`
},
{
part: 'Part III: The Election',
role: 'CC0 Operator (Bern)',
roleClass: 'role-cc',
title: 'CC0 Shuffles the Ballots',
html: `
<p>As CC0, you receive the 6 ciphertexts. You will <spanclass="em">permute</span> them and <spanclass="em">re-encrypt</span> each one.</p>
<divclass="decision-box">
<divclass="decision-question">Begin your shuffle?</div>
<divclass="insight-box"><strong>Compare input [0] to any output.</strong> Every byte is different. The re-encryption changed every number. Under DDH, no efficient algorithm can determine which input corresponds to which output. Even CC0 itself can't -- it destroyed π.</div>
`
},
{
part: 'Part III: The Election',
role: 'CC0 Operator (Bern)',
roleClass: 'role-cc',
title: 'The Shuffle Proof (Bayer-Groth)',
html: `
<p>But wait -- how does anyone know CC0 didn't cheat? Maybe it replaced someone's vote, or duplicated a ballot. We need a <spanclass="em">proof that the shuffle was honest</span>.</p>
<divclass="problem-box">The shuffle proof must convince a verifier of two things simultaneously:<br>
1. The output is a <strong>permutation</strong> of the input (same ballots, just reordered).<br>
2. Each ciphertext was <strong>re-encrypted</strong> (not modified).<br>
And it must do this <strong>without revealing the permutation</strong>.</div>
<p>This is the <spanclass="em">Bayer-Groth argument</span> (Eurocrypt 2012). It's the most complex proof in the system, so let's unpack its structure.</p>
<divclass="math-block"><spanclass="def">Bayer-Groth argument structure for N=6 ciphertexts:</span>
<spanclass="cmt">Arrange N ciphertexts in an m×n matrix (here 2×3).</span>
<spanclass="cmt">The proof has 3 sub-arguments:</span>
<spanclass="cmt">"The output ciphertexts are the correct multi-exponentiations</span>
<spanclass="cmt"> of the inputs with the permutation matrix as exponents."</span></div>
<divclass="analogy-box"><strong>Simplified intuition:</strong> Imagine you have 6 sealed boxes numbered 1-6. You rearrange them and put them in new boxes. The ProductArgument proves "I used each number exactly once" (it's a valid permutation). The MultiExponentiationArgument proves "the new boxes contain the same items as the old boxes" (the ciphertexts were correctly re-encrypted, not swapped for fakes).</div>
<divclass="insight-box"><strong>Watch it happen.</strong> Run <code>evote cockpit</code> (browser) or <code>evote cockpit --tmux</code> (terminal): as the mix-net executes, each of these sub-arguments is rendered as live typeset mathematics with the real runtime values, in the order it is constructed — the Pedersen commitment to the permutation matrix, then the Product / Hadamard / Zero / SingleValueProduct / MultiExponentiation arguments, then the partial decryptions. The tree above is not a diagram of the code; it <em>is</em> the code, narrating itself.</div>
<spanclass="cmt">This means: C'<sub>k</sub> is the re-encryption of the permuted input.</span>
<spanclass="cmt">The a<sub>i,k</sub> are the permutation matrix entries (0s and 1s),</span>
<spanclass="cmt">so this selects exactly one input ciphertext per output slot.</span></div>
<divclass="insight-box"><strong>Complexity:</strong> The proof size is O(√N) group elements, not O(N). For our 2×3 matrix, it's about 5 group elements and 5 field elements. For the production system with thousands of ballots, this sublinear scaling is critical. Verification takes O(N√N) exponentiations -- efficient enough to run on any laptop.</div>
`
},
{
part: 'Part III: The Election',
title: 'The Remaining Shuffles',
html: `
<p>CC0's output feeds into CC1, which shuffles again with its own random π<sub>1</sub>. Then CC2, CC3, and finally the Electoral Board.</p>
<divclass="decision-box">
<divclass="decision-question">Process the remaining 4 shuffles?</div>
<divclass="think-box"><strong>Why 5 shuffles, not just 1?</strong> Privacy requires that <em>at least one</em> shuffle node is honest (destroys its π). If CC0 is compromised, CC1 still shuffles honestly, and the combined permutation is random. After 5 independent shuffles, the final order is determined by the composition π<sub>4</sub>∘π<sub>3</sub>∘π<sub>2</sub>∘π<sub>1</sub>∘π<sub>0</sub>. Even if 4 out of 5 collude and reveal their permutations, the honest one's π makes the composition uniformly random. This is <em>information-theoretic</em> privacy -- no amount of computation helps.</div>
`
},
{
part: 'Part III: The Election',
role: 'EB President',
roleClass: 'role-eb',
title: 'Opening the Ballot Box',
html: `
<p>After 5 shuffles and 5 partial decryptions, the ballots are fully decrypted -- in random order.</p>
<divclass="decision-box">
<divclass="decision-question">Open the ballot box?</div>
<divclass="decision-answer role-eb">Open</div>
</div>
<divclass="math-block"><spanclass="def">Sequential partial decryption (how the 5 layers are removed):</span>
<divclass="think-box"><strong>But should we trust this result?</strong> The server computed it. The CCs computed it. Any of them could have cheated. The result <em>looks</em> right (5 Alice + 1 Bob = 6 ballots), but how do we <em>know</em>? This is where universal verifiability comes in -- and it's the most powerful part of the whole system.</div>
<divclass="part-sub">Anyone can audit the election using only<br>public data and mathematics. No secrets needed.<br>No trust required.</div>
</div>
`
},
{
part: 'Part IV: Verification',
role: 'Public Auditor',
roleClass: 'role-auditor',
title: 'You Are a Public Auditor',
html: `
<p>You are a <spanclass="em color-auditor">random citizen</span>. You have:</p>
<ul>
<li>The public keys of all 5 key holders</li>
<li>All 6 encrypted ballots (input to the mix-net)</li>
<li>All shuffle outputs (from each CC)</li>
<li>All proofs (Schnorr proofs for keys, Bayer-Groth proofs for shuffles)</li>
<li>The decrypted result</li>
</ul>
<p>You do <spanclass="em">NOT</span> have any secret keys, passwords, or special access.</p>
<divclass="insight-box"><strong>The claim:</strong> with just the public data above, you can independently verify that the election result is correct and that no cheating occurred. Let's do it step by step.</div>
`
},
{
part: 'Part IV: Verification',
role: 'Public Auditor',
roleClass: 'role-auditor',
title: 'Check 1: Key Proofs',
html: `
<p>First, verify that each key holder actually knows their secret key.</p>
<divclass="math-block"><spanclass="def">For each CC<sub>j</sub>, you have the Schnorr proof (e<sub>j</sub>, z<sub>j</sub>) and public key pk<sub>j</sub>.</span>
<spanclass="cmt">Verification equation:</span>
c' = g<sup>z<sub>j</sub></sup>· pk<sub>j</sub><sup>-e<sub>j</sub></sup> mod p <spanclass="cmt">(recompute the commitment)</span>
check: H(p, q, g, pk<sub>j</sub>, c') == e<sub>j</sub><spanclass="cmt">(verify the Fiat-Shamir hash)</span>
<divclass="insight-box"><strong>What this guarantees:</strong> Each CC genuinely possesses the secret key corresponding to their published public key. They couldn't have picked a random pk and faked the proof -- by special soundness of Schnorr, faking requires solving DLog. This means the ElectionPK was correctly constructed from legitimate keys.</div>
`
},
{
part: 'Part IV: Verification',
role: 'Public Auditor',
roleClass: 'role-auditor',
title: 'Check 2: Shuffle Proofs',
html: `
<p>Now verify that each of the 5 shuffles was honest -- same ballots in, same ballots out, just reordered.</p>
<divclass="insight-box"><strong>What this guarantees:</strong> Each shuffle node's output is a valid permutation + re-encryption of its input. Combined with the ballot count check (6 in, 6 out at each step), this proves: <em>no ballots were added, removed, or modified anywhere in the pipeline</em>. Under the DLog assumption, producing a valid Bayer-Groth proof for a dishonest shuffle is computationally infeasible.</div>
==><spanclass="proof-pass">PASS: Every ballot is accounted for at every stage.</span></div>
<divclass="insight-box"><strong>Combining the checks:</strong>
<br>Key proofs <spanclass="proof-pass">PASS</span>→ the election key is legitimate
<br>Shuffle proofs <spanclass="proof-pass">PASS</span>→ every shuffle was an honest permutation + re-encryption
<br>Ballot count <spanclass="proof-pass">PASS</span>→ no ballots added or removed
<br><br>Together, these form a <em>chain of mathematical evidence</em> from encrypted ballots to the final tally. Every link is publicly verifiable. No trust required.</div>
<p>How does a voter know their <em>encrypted</em> ballot really contains their choice, when malware could have swapped it? The return code -- a short code printed on their card -- must be computed <spanclass="em">from the submitted ciphertext</span>, not merely looked up.</p>
<p>The voter sends the ballot <code>E1</code>, a second ciphertext <code>E2 = Enc(vote, returnCodesPK)</code>, and a <spanclass="em">plaintext-equality proof</span> that both encrypt the same vote:</p>
(the shared plaintext <em>cancels</em> in φ₁/φ₂— so equality is proven without revealing it)
</div>
<p>Each CC verifies this proof. Then the CCs exponentiate <code>E2</code> by their return-code keys and jointly decrypt, recovering <spanclass="em">vote<sup>Σk</sup></span> = the card's base <spanclass="em">prime<sub>sel</sub><sup>Σk</sup></span>, which maps to the short code returned to the voter.</p>
<divclass="insight-box">Because the equality proof binds <code>E2</code> to the tallied ballot <code>E1</code>, the code reflects the vote that is actually counted. Malware that alters the vote produces a code that <em>won't match the card</em> -- and it can't forge a matching one without the control components' secrets.</div>
`
},
{
part: 'Part IV½: The Channels',
title: 'Transport Security: EdDSA + ECDH',
html: `
<p>Everything so far is the <em>protocol</em>. But the parties -- setup component, four control components, electoral board, voting server, voters, verifier -- run on separate machines and must authenticate every message they exchange. That's a different cryptographic layer:</p>
<divstyle="margin:12px 0;">
<divstyle="margin:8px 0;"><spanclass="em">Ed25519</span>— every inter-party message is signed; the receiver verifies against the sender's certificate.</div>
<divstyle="margin:8px 0;"><spanclass="em">X25519 (ECDH)</span>— confidential deliveries (voting cards) derive an AES-256-GCM session key from a Diffie-Hellman exchange.</div>
<divstyle="margin:8px 0;"><spanclass="em">Ed25519 X.509 PKI</span>— a root CA issues each party an identity certificate; no RSA anywhere.</div>
</div>
<p>In this PoC these primitives are implemented in a small <spanclass="em">Rust</span> crate (<code>ed25519-dalek</code>, <code>x25519-dalek</code>) and called from Go over a C ABI -- a clean separation between the hand-built protocol math and the audited, constant-time transport primitives.</p>
<divclass="insight-box">Two independent trust arguments: the <em>protocol</em> proofs (Schnorr, Bayer-Groth) make the election publicly verifiable; the <em>transport</em> signatures make each message attributable to a specific party. Verifiability answers "is the tally correct?"; transport security answers "who said this?"</div>
<p>As a public auditor with <em>no special access</em>, you verified:</p>
<divstyle="margin:14px 0 14px 10px;">
<divstyle="margin:6px 0;"><spanclass="proof-pass">[x]</span> All 4 CCs proved knowledge of their secret keys (Schnorr Σ-protocol + Fiat-Shamir)</div>
<divstyle="margin:6px 0;"><spanclass="proof-pass">[x]</span> All 5 shuffles are valid permutation + re-encryption (Bayer-Groth argument)</div>
<divstyle="margin:6px 0;"><spanclass="proof-pass">[x]</span> No ballots were added, removed, or modified (count invariant at each stage)</div>
<divstyle="margin:6px 0;"><spanclass="proof-pass">[x]</span> The final tally matches the decrypted ballots (prime factorization decoding)</div>
<spanstyle="color:#24292f; font-size:14px;"> ElGamal IND-CPA under DDH. Re-encryption mix-net with 5 nodes. Information-theoretic unlinkability if ≥1 node is honest.</span>
<div><spanclass="dim">1.</span> Bayer, Groth. <spanclass="em">"Efficient Zero-Knowledge Argument for Correctness of a Shuffle."</span> Eurocrypt 2012.</div>
<div><spanclass="dim">2.</span> Schnorr. <spanclass="em">"Efficient Signature Generation by Smart Cards."</span> J. Cryptology, 1991.</div>
<div><spanclass="dim">3.</span> ElGamal. <spanclass="em">"A Public-Key Cryptosystem and a Signature Scheme Based on Discrete Logarithms."</span> IEEE Trans. IT, 1985.</div>
<div><spanclass="dim">4.</span> Fiat, Shamir. <spanclass="em">"How to Prove Yourself: Practical Solutions to Identification and Signature Problems."</span> Crypto 1986.</div>
<h3style="margin-top:20px; margin-bottom:12px;">Swiss Post Documentation</h3>
<div><spanclass="dim">5.</span> Swiss Post. <spanclass="em">Crypto-primitives specification.</span> 2024.</div>
<div><spanclass="dim">6.</span> Swiss Post. <spanclass="em">Protocol specification: Mixing.</span> 2024.</div>
<div><spanclass="dim">7.</span> Swiss Post. <spanclass="em">System architecture document.</span> 2024.</div>