1 package civitas.common.ballotdesign;
2
3 import static org.junit.jupiter.api.Assertions.assertEquals;
4 import static org.junit.jupiter.api.Assertions.assertThrows;
5 import static org.mockito.Mockito.verify;
6
7 import org.junit.jupiter.api.DisplayName;
8 import org.junit.jupiter.api.Test;
9 import org.mockito.InjectMocks;
10
11 import civitas.common.RandomAwareTestBase;
12 import civitas.common.votersubmission.VoterSubmission;
13 import civitas.common.votersubmission.VoterSubmissionTestData;
14 import civitas.crypto.oneoflreencryption.ElGamal1OfLReencryptionTestData;
15
16 class DecomposeBallotTest extends RandomAwareTestBase
17 implements VoterSubmissionTestData, ElGamal1OfLReencryptionTestData {
18
19 @InjectMocks
20 DecomposeBallot decomposeBallot;
21
22 @Test
23 @DisplayName(
24 """
25 Decomposes a ballot into a VoterSubmission
26 - calculates the length of the ballot based on the number of candidates
27 - for each pair i,j:
28 - calculates their position in the matrix
29 - computes the encrypted choice by constructing an 1 of L reeencryption
30 - encrypts the capability from the map
31 - constructs a vote proof using all the above
32 - creates a verifiable vote using the context, the encryted capability and choice and the proof
33 - returns a voter submission for the voter block with the verifiable votes
34 """)
35 void test() {
36 VoterSubmission actual = decomposeBallot.apply(
37 BALLOTDESIGN,
38 BALLOT,
39 VOTER_BLOCK,
40 EL_GAMAL_PUBLIC_KEY_E,
41 CIPHERTEXT_LIST,
42 ADDITIONALENV,
43 CAPABILITY_MAP);
44 assertEquals(VOTER_SUBMISSION, actual);
45 verify(decomposeBallot.calculateBallotLength).apply(BALLOT.k);
46 CalculatePositionInBallot posStub = CalculatePositionInBallotStub.stub();
47 for (int i = 0; i < NUM_CANDIDATES; i++) {
48 for (int j = i + 1; j < NUM_CANDIDATES; j++) {
49 Integer pos = posStub.apply(i, j, NUM_CANDIDATES);
50 verify(decomposeBallot.encryptCapability).apply(EL_GAMAL_PUBLIC_KEY_E, CAPABILITY_MAP, CONTEXT_0);
51 verify(decomposeBallot.encryptChoice).apply(EL_GAMAL_PUBLIC_KEY_E, CIPHERTEXT_LIST, BALLOT.matrix, pos);
52 verify(decomposeBallot.calculatePositionInBallot).apply(i, j, NUM_CANDIDATES);
53
54 verify(decomposeBallot.constructProofVote)
55 .apply(
56 EL_GAMAL_PARAMETERS,
57 ENCRYPTED_SIGNED_VOTE_CAPABILITIES.get(pos),
58 EL_GAMAL_1_OF_L_REENCRYPTION_MAP
59 .get(BALLOT.matrix[pos])
60 .m(),
61 CONTEXT_MAP.get(pos),
62 ELGAMAL_REENCRYPT_FACTOR_E,
63 ELGAMAL_REENCRYPT_FACTOR_EPRIME);
64 }
65 }
66 }
67
68 @Test
69 @DisplayName("if the key is null, IllegalArgumentException is thrown")
70 void test1() {
71 assertThrows(
72 IllegalArgumentException.class,
73 () -> decomposeBallot.apply(
74 BALLOTDESIGN, BALLOT, VOTER_BLOCK, null, CIPHERTEXT_LIST, ADDITIONALENV, CAPABILITY_MAP));
75 }
76
77 @Test
78 @DisplayName("if the number of candidates in the ballot does not match the number of candidates,"
79 + "IllegalArgumentException is thrown")
80 void test2() {
81 assertThrows(
82 IllegalArgumentException.class,
83 () -> decomposeBallot.apply(
84 BALLOTDESIGN,
85 BALLOT_2_CANDIDATES,
86 VOTER_BLOCK,
87 EL_GAMAL_PUBLIC_KEY_E,
88 CIPHERTEXT_LIST,
89 ADDITIONALENV,
90 CAPABILITY_MAP));
91 }
92
93 @Test
94 @DisplayName("if the matrix length in the ballot does not match the number of candidates,"
95 + "IllegalArgumentException is thrown")
96 void test3() {
97 assertThrows(
98 IllegalArgumentException.class,
99 () -> decomposeBallot.apply(
100 BALLOTDESIGN,
101 BALLOT_SHORT_MATRIX,
102 VOTER_BLOCK,
103 EL_GAMAL_PUBLIC_KEY_E,
104 CIPHERTEXT_LIST,
105 ADDITIONALENV,
106 CAPABILITY_MAP));
107 }
108 }