213 lines
11 KiB
Plaintext
213 lines
11 KiB
Plaintext
This folder contains proof transcripts that demonstrate a trapdoor in the
|
|
SwissVote-Scytl mixnet. It was generated by Sarah Jamie Lewis, Olivier
|
|
Pereira and Vanessa Teague, using techniques described in our report,
|
|
"Ceci n'est pas une preuve."
|
|
|
|
In order to verify the proof transcripts, you will need to have a running
|
|
copy of the Swisspost-Scytl voting system, which was made available to
|
|
researchers through the Swiss public intrusion test at
|
|
https://onlinevote-pit.ch/details/
|
|
|
|
Folders proof/ and proof-zero/ each contain a manipulated proof transcript, each for
|
|
the sequence of votes (2,2,3,7). In each case, the mixnet manipulates the outcome
|
|
and produces ciphertexts (2,3,3,7) as output, along with a correctness proof
|
|
that passes verification.
|
|
|
|
The transcript in proof/ is a typical run of a real election system, in which the votes
|
|
are properly encrypted with random values. The transcript in proof-zero is an atypical
|
|
run for demonstration purposes, in which zero randomness is used - thus the
|
|
manipulation is immediately obvious to a human reader.
|
|
|
|
Folders proof-2/ and proof-2-zero/ each contain a manipulated proof transcript
|
|
that implements the second kind of cheating described in our paper, in section 2.2.2.
|
|
In this cheat, every ciphertext is multiplied by 2. Again proof-2/ contains
|
|
a typical run with real randomness, while proof-2-zero/ contains a run in which
|
|
zero randomness is used. Hence the cheating is immediately obvious.
|
|
|
|
|
|
Instructions:
|
|
1. Unzip the files and store the proof transcripts.
|
|
2. In your copy of the Swisspost-Scytl code, replace the contents of online-voting-mixing/mixnet-engine/src/test/java/com/scytl/products/ov/mixnet/BaseBGMixnetIOVerifierITest.java with BgIntegrationTestUpdate.java
|
|
3. Update the proofsPath in BgIntegrationTestUpdate.java to wherever you stored the proofs.
|
|
4. Run givenSmallConfigWhenShuffleThenOK()
|
|
5. You should see that the proof passes verification.
|
|
|
|
*************
|
|
The test in proof/ is run with the following inputs:
|
|
|
|
private static boolean CHEATING = true;
|
|
private static boolean CHEATING2 = false;
|
|
|
|
BigInteger p = new BigInteger("15294034768093677312256663166625633354362303");
|
|
q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
|
|
BigInteger g = new BigInteger("2");
|
|
|
|
zp = new ZpSubgroup(g, p, q);
|
|
|
|
//Note
|
|
//pow(2, 2972987297297297296356982562, p)
|
|
//5943523178887533241241798626972220822590095
|
|
ZpGroupElement[] publicKeyArray = new ZpGroupElement[1];
|
|
publicKeyArray[0] = new ZpGroupElement(new BigInteger("5943523178887533241241798626972220822590095"), zp.getP(), zp.getQ());
|
|
ElGamalPublicKey publicKey = new ElGamalPublicKey(Arrays.asList(publicKeyArray), zp);
|
|
|
|
final GjosteenElGamal elgamal = new GjosteenElGamal(zp, publicKey);
|
|
|
|
ZpGroupElement[] elements3 = getAsGroupElementArray(3, zp);
|
|
ZpGroupElement[] elements2 = getAsGroupElementArray(2, zp);
|
|
ZpGroupElement[] elements9 = getAsGroupElementArray(7, zp);
|
|
|
|
final GjosteenElGamalRandomness rhoPrime11 = new GjosteenElGamalRandomness(234522456, q);
|
|
final GjosteenElGamalRandomness rhoPrime12 = new GjosteenElGamalRandomness(788749345, q);
|
|
final GjosteenElGamalRandomness rhoPrime21 = new GjosteenElGamalRandomness(543783459, q);
|
|
final GjosteenElGamalRandomness rhoPrime22 = new GjosteenElGamalRandomness(741325490, q);
|
|
|
|
final GjosteenElGamalRandomness[] rhoPrime = {rhoPrime11, rhoPrime12, rhoPrime21, rhoPrime22};
|
|
|
|
final Ciphertext C11 = elgamal.encrypt(elements2, rhoPrime11);
|
|
final Ciphertext C12 = elgamal.encrypt(elements2, rhoPrime12);
|
|
final Ciphertext C21 = elgamal.encrypt(elements3, rhoPrime21);
|
|
final Ciphertext C22 = elgamal.encrypt(elements9, rhoPrime22);
|
|
|
|
final GjosteenElGamalRandomness rho11 = new GjosteenElGamalRandomness(345167524, q);
|
|
final GjosteenElGamalRandomness rho12 = new GjosteenElGamalRandomness(435732453, q);
|
|
final GjosteenElGamalRandomness rho21 = new GjosteenElGamalRandomness(892468901, q);
|
|
final GjosteenElGamalRandomness rho22 = new GjosteenElGamalRandomness(252437823, q);
|
|
|
|
and then the third element (C21) is copied over the second (C12).
|
|
|
|
****************
|
|
The test in proof-zero/ is run with the following inputs:
|
|
|
|
private static boolean CHEATING = true;
|
|
private static boolean CHEATING2 = false;
|
|
|
|
BigInteger p = new BigInteger("15294034768093677312256663166625633354362303");
|
|
q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
|
|
BigInteger g = new BigInteger("2");
|
|
|
|
zp = new ZpSubgroup(g, p, q);
|
|
|
|
//Note
|
|
//pow(2, 2972987297297297296356982562, p)
|
|
//5943523178887533241241798626972220822590095
|
|
ZpGroupElement[] publicKeyArray = new ZpGroupElement[1];
|
|
publicKeyArray[0] = new ZpGroupElement(new BigInteger("5943523178887533241241798626972220822590095"), zp.getP(), zp.getQ());
|
|
ElGamalPublicKey publicKey = new ElGamalPublicKey(Arrays.asList(publicKeyArray), zp);
|
|
|
|
final GjosteenElGamal elgamal = new GjosteenElGamal(zp, publicKey);
|
|
|
|
ZpGroupElement[] elements3 = getAsGroupElementArray(3, zp);
|
|
ZpGroupElement[] elements2 = getAsGroupElementArray(2, zp);
|
|
ZpGroupElement[] elements9 = getAsGroupElementArray(7, zp);
|
|
|
|
final GjosteenElGamalRandomness rhoPrime11 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rhoPrime12 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rhoPrime21 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rhoPrime22 = new GjosteenElGamalRandomness(0, q);
|
|
|
|
final GjosteenElGamalRandomness[] rhoPrime = {rhoPrime11, rhoPrime12, rhoPrime21, rhoPrime22};
|
|
|
|
final Ciphertext C11 = elgamal.encrypt(elements2, rhoPrime11);
|
|
final Ciphertext C12 = elgamal.encrypt(elements2, rhoPrime12);
|
|
final Ciphertext C21 = elgamal.encrypt(elements3, rhoPrime21);
|
|
final Ciphertext C22 = elgamal.encrypt(elements9, rhoPrime22);
|
|
|
|
final GjosteenElGamalRandomness rho11 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rho12 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rho21 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rho22 = new GjosteenElGamalRandomness(0, q);
|
|
|
|
and then the third element (C21) is copied over the second (C12).
|
|
|
|
|
|
***********
|
|
The test in proof-2-zero/ is run with the following inputs:
|
|
|
|
private static boolean CHEATING = false;
|
|
private static boolean CHEATING2 = true;
|
|
|
|
BigInteger p = new BigInteger("15294034768093677312256663166625633354362303");
|
|
q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
|
|
BigInteger g = new BigInteger("2");
|
|
|
|
ZpGroupElement[] publicKeyArray = new ZpGroupElement[1];
|
|
publicKeyArray[0] = new ZpGroupElement(new BigInteger("5943523178887533241241798626972220822590095"), zp.getP(), zp.getQ());
|
|
ElGamalPublicKey publicKey = new ElGamalPublicKey(Arrays.asList(publicKeyArray), zp);
|
|
|
|
final GjosteenElGamal elgamal = new GjosteenElGamal(zp, publicKey);
|
|
|
|
ZpGroupElement[] elements3 = getAsGroupElementArray(3, zp);
|
|
ZpGroupElement[] elements2 = getAsGroupElementArray(2, zp);
|
|
ZpGroupElement[] elements7 = getAsGroupElementArray(7, zp);
|
|
|
|
final GjosteenElGamalRandomness rhoPrime11 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rhoPrime12 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rhoPrime21 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rhoPrime22 = new GjosteenElGamalRandomness(0, q);
|
|
|
|
final GjosteenElGamalRandomness[] rhoPrime = {rhoPrime11, rhoPrime12, rhoPrime21, rhoPrime22};
|
|
|
|
final Ciphertext C11 = elgamal.encrypt(elements3, rhoPrime11);
|
|
final Ciphertext C12 = elgamal.encrypt(elements3, rhoPrime12);
|
|
final Ciphertext C21 = elgamal.encrypt(elements7, rhoPrime21);
|
|
final Ciphertext C22 = elgamal.encrypt(elements7, rhoPrime22);
|
|
|
|
final GjosteenElGamalRandomness rho11 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rho12 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rho21 = new GjosteenElGamalRandomness(0, q);
|
|
final GjosteenElGamalRandomness rho22 = new GjosteenElGamalRandomness(0, q);
|
|
|
|
final GjosteenElGamalRandomness[] rho = {rho11, rho12, rho21, rho22};
|
|
final Ciphertext[][] vecC = {{C11, C12 }, {C21, C22 }};
|
|
|
|
Ciphertext[][] ciphertexts = {
|
|
{C11.multiply(elgamal.encrypt(elements2, rho11)),
|
|
C12.multiply(elgamal.encrypt(elements2, rho12))},
|
|
{C21.multiply(elgamal.encrypt(elements2, rho21)),
|
|
C22.multiply(elgamal.encrypt(elements2, rho22))}
|
|
};
|
|
|
|
***********
|
|
|
|
The test in proof-2/ is run with the following inputs:
|
|
|
|
private static boolean CHEATING = false;
|
|
private static boolean CHEATING2 = true;
|
|
|
|
ZpGroupElement[] publicKeyArray = new ZpGroupElement[1];
|
|
publicKeyArray[0] = new ZpGroupElement(new BigInteger("5943523178887533241241798626972220822590095"), zp.getP(), zp.getQ());
|
|
ElGamalPublicKey publicKey = new ElGamalPublicKey(Arrays.asList(publicKeyArray), zp);
|
|
|
|
final GjosteenElGamal elgamal = new GjosteenElGamal(zp, publicKey);
|
|
|
|
ZpGroupElement[] elements3 = getAsGroupElementArray(3, zp);
|
|
ZpGroupElement[] elements2 = getAsGroupElementArray(2, zp);
|
|
ZpGroupElement[] elements7 = getAsGroupElementArray(7, zp);
|
|
|
|
final GjosteenElGamalRandomness rhoPrime11 = new GjosteenElGamalRandomness(234522456, q);
|
|
final GjosteenElGamalRandomness rhoPrime12 = new GjosteenElGamalRandomness(788749345, q);
|
|
final GjosteenElGamalRandomness rhoPrime21 = new GjosteenElGamalRandomness(543783459, q);
|
|
final GjosteenElGamalRandomness rhoPrime22 = new GjosteenElGamalRandomness(741325490, q);
|
|
|
|
final GjosteenElGamalRandomness[] rhoPrime = {rhoPrime11, rhoPrime12, rhoPrime21, rhoPrime22};
|
|
|
|
final Ciphertext C11 = elgamal.encrypt(elements3, rhoPrime11);
|
|
final Ciphertext C12 = elgamal.encrypt(elements3, rhoPrime12);
|
|
final Ciphertext C21 = elgamal.encrypt(elements7, rhoPrime21);
|
|
final Ciphertext C22 = elgamal.encrypt(elements7, rhoPrime22);
|
|
|
|
final GjosteenElGamalRandomness rho11 = new GjosteenElGamalRandomness(345167524, q);
|
|
final GjosteenElGamalRandomness rho12 = new GjosteenElGamalRandomness(435732453, q);
|
|
final GjosteenElGamalRandomness rho21 = new GjosteenElGamalRandomness(892468901, q);
|
|
final GjosteenElGamalRandomness rho22 = new GjosteenElGamalRandomness(252437823, q);
|
|
|
|
final GjosteenElGamalRandomness[] rho = {rho11, rho12, rho21, rho22};
|
|
final Ciphertext[][] vecC = {{C11, C12 }, {C21, C22 }};
|
|
|
|
Ciphertext[][] ciphertexts = {
|
|
{C11.multiply(elgamal.encrypt(elements2, rho11)),
|
|
C12.multiply(elgamal.encrypt(elements2, rho12))},
|
|
{C21.multiply(elgamal.encrypt(elements2, rho21)),
|
|
C22.multiply(elgamal.encrypt(elements2, rho22))}
|