diff --git a/.github/workflows/python.ci.yml b/.github/workflows/python.ci.yml index 27070e0..9593fb2 100644 --- a/.github/workflows/python.ci.yml +++ b/.github/workflows/python.ci.yml @@ -13,5 +13,5 @@ testbuild : - apt-get install -y build-essential - apt-get install -y libgmp3-dev - conda env create -f environment.yml - - source activate verificationtool + - source activate polyas-checker - python -m unittest discover src diff --git a/README.md b/README.md index 9d59472..b9e0050 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,13 @@ for its system specification. ### Setup Environment ```bash -conda env create --name verificationtool --file environment.yml +conda env create --name polyas-checker --file environment.yml ``` ### Activating Environment Before executing the tool or unittests, run the following: ```bash -conda activate verificationtool +conda activate polyas-checker ``` ## Installation Using [pip](https://pip.pypa.io) @@ -34,7 +34,7 @@ python -m pip install -r requirements.txt ## Running Polyas-Checker ### In the Command Line ```bash -python src/verificationtool.py [-s | --second-device] [-r | --receipt] [--log] [-l | --language lang] src +python src/polyas_checker.py [-s | --second-device] [-r | --receipt] [--log] [-l | --language lang] src ``` * ``src``: Absolute path to election files * ``-s, --second-device``: Check second device public parameters in file ``src/second-device-public-parameters.json`` @@ -46,7 +46,7 @@ python src/verificationtool.py [-s | --second-device] [-r | --receipt] [--log] [ Additionally, this repository contains a GUI tool based on [Qt5](https://github.com/qt/qt5). ```bash -python src/verificationtoolGUI.py +python src/polyas_checkerGUI.py ``` The path to the election files as well as all other options are then entered in the GUI. diff --git a/environment.yml b/environment.yml index 31607f2..22cee21 100644 --- a/environment.yml +++ b/environment.yml @@ -1,4 +1,4 @@ -name: verificationtool +name: polyas-checker channels: - defaults - conda-forge diff --git a/run.sh b/run.sh index f79064e..560ad4b 100644 --- a/run.sh +++ b/run.sh @@ -2,4 +2,4 @@ # Copyright © 2019-2023, Karlsruhe Institute of Technology (KIT), Maximilian Noppel, Christoph Niederbudde -python ./src/verificationtoolGUI.py +python ./src/polyas_checkerGUI.py diff --git a/src/verificationtool.py b/src/polyas_checker.py similarity index 90% rename from src/verificationtool.py rename to src/polyas_checker.py index 7e41a7e..416b65a 100644 --- a/src/verificationtool.py +++ b/src/polyas_checker.py @@ -25,7 +25,7 @@ VERSION = "v" + str(VERSION_MAJOR) + "." + str(VERSION_MINOR) + "." + str(VERSION_PATCH) -logger = logging.getLogger("verificationtool.py") +logger = logging.getLogger("polyas_checker.py") logger.setLevel(logging.DEBUG) ch = logging.StreamHandler() @@ -154,7 +154,7 @@ def verify_ballot_box(path, progressbar=None): bba = ballotBoxFlagged[i] if not bba.ballot.__eq__(bb): progressbar.setValue(int((i + 1) * 100 / len(ballotBox))) if progressbar is not None else None - logger.info("Ballot of voter %s incorrectly transferred from ballot-box to ballot-box-flagged" % bb.voterID) + logger.info("The ballot of voter %s is incorrectly transferred from the ballot box to ballot-box-flagged." % bb.voterID) return False flag = "" if not verification_of_a_ballot_entry_extended(registry, bb, pastCredentials, pk): @@ -165,7 +165,7 @@ def verify_ballot_box(path, progressbar=None): flag = BallotStatus.OK pastCredentials += [bb.publicCredential] if flag != bba.status: - logger.info("Ballot of voter %s incorrectly flagged: Expected %s but was %s" % (bb.voterID, flag, bba.status)) + logger.info("The ballot of voter %s is incorrectly flagged: Expected %s but was %s." % (bb.voterID, flag, bba.status)) return False if progressbar is not None: @@ -242,7 +242,7 @@ def verify_mixing_input(path, progressbar=None): inputMixPackets = load_mixing_input_packets(path) flaggedBallots = load_ballot_box_flagged(path) registry = load_registry(path) - # Grouping mix packets by their public label + # Grouping mixing packets by their public label packetsByLabel = {} # Position of all packets fwith a given public label in inputMixPackets packetCountByLabel = {} # Position the first packet that has not been fully analysed in the corresponding list in packetsByLabel packetPosByLabel = {} # Position of the first ballot that has not been analysed in the current package @@ -266,7 +266,7 @@ def verify_mixing_input(path, progressbar=None): if len(inputMixPackets[packet].ciphertexts) > registry.packetSize or len(inputMixPackets[packet].ciphertexts) < registry.packetSize / 2: if progressbar is not None: progressbar.setValue(100) - logger.info("A packet on board mixing-input-packets for public label %s has an invalid size" % publicLabel) + logger.info("A packet on the board mixing-input-packets for public label %s has an invalid size." % publicLabel) return False # Check that all valid ballots are transferred to the mixing packets @@ -278,13 +278,13 @@ def verify_mixing_input(path, progressbar=None): if label not in packetsByLabel: if progressbar is not None: progressbar.setValue(100) - logger.info("Board mixing-input-packets misses ballot of voter %s" % expectedBallot.voterID) + logger.info("The board mixing-input-packets misses the ballot of voter %s." % expectedBallot.voterID) return False correspondingPacket = inputMixPackets[packetsByLabel[label][packetCountByLabel[label]]] if not expectedBallot.ballot.encryptedChoice.__eq__(correspondingPacket.ciphertexts[packetPosByLabel[label]]): if progressbar is not None: progressbar.setValue(100) - logger.info("Board mixing-input-packets misses ballot of voter %s" % expectedBallot.voterID) + logger.info("The board mixing-input-packets misses the ballot of voter %s." % expectedBallot.voterID) return False packetPosByLabel[label] += 1 if packetPosByLabel[label] >= len(correspondingPacket.ciphertexts): @@ -303,7 +303,7 @@ def verify_mixing_input(path, progressbar=None): if len(packetsByLabel) > 0: if progressbar is not None: progressbar.setValue(100) - logger.info("Board mixing-input-packets contains additional ballots") + logger.info("The board mixing-input-packets contains additional ballots.") return False return True @@ -318,7 +318,7 @@ def verify_shuffle(path, progressbar=None): if len(mixPackets) != len(inputMixPackets): if progressbar is not None: progressbar.setValue(100) - logger.info("Number of packets before and after mixing are not equal") + logger.info("The number of the packets before and after the mixing differ.") return False for i in range(len(mixPackets)): @@ -376,14 +376,14 @@ def verify_ballot_decryption(path, progressbar=None): if (len(messages) != len(mixMixingPackets)): if progressbar is not None: progressbar.setValue(100) - logger.info("Number of decrypted packets is not equal to number of mixed packets") + logger.info("The number of the decrypted packets differs from the number of mixing packets.") return False for i in range(len(messages)): if (len(messages[i].messagesWithZKP) != len(mixMixingPackets[i].ciphertexts)): if progressbar is not None: progressbar.setValue(100) - logger.info("Number of decrypted messages in a packet is not equal to number of encrypted messages in corresponding mixing packet") + logger.info("The number of decrypted messages in a packet differs from the number of encrypted messages in the corresponding mixing packet.") return False for j in range(len(mixMixingPackets[i].ciphertexts)): messagesWithZKP = messages[i].messagesWithZKP[j] @@ -597,7 +597,7 @@ def verify_second_device_public_parameters(path, phase1=None): logger.info("----------------------------------------------------------") logger.info("VERIFYING") logger.info("----------------------------------------------------------") - logger.info("Verifying second device public parameters...") + logger.info("Verifying the second device public parameters...") parametersJSON = {} fingerprint = "" try: @@ -609,13 +609,13 @@ def verify_second_device_public_parameters(path, phase1=None): if phase1: phase1.setValue(100) phase1.setStyleSheet(redStyle) - logger.info("Second device public parameters are: [\033[1;31m NOT ACCEPTED \033[0;0m]") + logger.info("The second device public parameters are: [\033[1;31m NOT ACCEPTED \033[0;0m]") return False parameterBytes = build_bytearray_by_type(json.dumps(parametersJSON)) fingerprintRecalc = hashlib.sha256(parameterBytes).hexdigest() registryJSON = loadSecureJSON(path, "registry.json") if fingerprint != fingerprintRecalc: - logger.info("Fingerprint of second device public parameters is invalid.") + logger.info("The fingerprint of the second device public parameters is invalid.") if phase1: phase1.setStyleSheet(redStyle) accepted = False @@ -630,11 +630,11 @@ def verify_second_device_public_parameters(path, phase1=None): if phase1: phase1.setValue(100) phase1.setStyleSheet(redStyle) - logger.info("Second device public parameters are: [\033[1;31m NOT ACCEPTED \033[0;0m]") + logger.info("The second device public parameters are: [\033[1;31m NOT ACCEPTED \033[0;0m]") return False if parametersJSON["publicKey"] != keygen.publicKey.hex(): - logger.info("Public key of second device public parameters is invalid.") + logger.info("The public key of the second device public parameters is invalid.") if phase1: phase1.setStyleSheet(redStyle) accepted = False @@ -642,7 +642,7 @@ def verify_second_device_public_parameters(path, phase1=None): phase1.setValue(50) if parametersJSON["verificationKey"] != verificationKey: - logger.info("VerificationKey of second device public parameters is invalid.") + logger.info("The verification key of the second device public parameters is invalid.") if phase1: phase1.setStyleSheet(redStyle) accepted = False @@ -650,7 +650,7 @@ def verify_second_device_public_parameters(path, phase1=None): phase1.setValue(75) if parametersJSON["ballots"] != registryJSON["ballotStructures"]: - logger.info("Ballots of second device public parameters are invalid.") + logger.info("The ballots of the second device public parameters are invalid.") if phase1: phase1.setStyleSheet(redStyle) accepted = False @@ -659,9 +659,9 @@ def verify_second_device_public_parameters(path, phase1=None): logger.info("----------------------------------------------------------") if accepted: - logger.info("Second device public parameters are: [\033[1;32m ACCEPTED \033[0;0m]") + logger.info("The second device public parameters are: [\033[1;32m ACCEPTED \033[0;0m]") else: - logger.info("Second device public parameters are: [\033[1;31m NOT ACCEPTED \033[0;0m]") + logger.info("The second device public parameters are: [\033[1;31m NOT ACCEPTED \033[0;0m]") logger.info("") return accepted @@ -689,12 +689,12 @@ def get_signature_if_valid(receiptPath: str, file: str, key: str, logTo=None): signList = re.findall(r".*BEGIN SIGNATURE----- ?(.*) ?-----END SIGNATURE.*", receipt) if len(fingerprintList) != 1 or len(signList) != 1: - logger.info("Ballot cast confirmation file %s does not have the correct format." % file) + logger.info("The ballot cast confirmation file %s does not have the correct format." % file) if logTo: logTo.append({"status": ReceiptStatus.MALFORMED, "file": file}) return None if not verify_signature_rsa(fingerprintList[0], signList[0], key): - logger.info("Ballot cast confirmation file %s does not contain a valid signature." % file) + logger.info("The ballot cast confirmation file %s does not contain a valid signature." % file) if logTo: logTo.append({"status": ReceiptStatus.INVALID, "file": file}) return None @@ -714,7 +714,7 @@ def verify_receipts(path, phase1=None, log=False, logTo=None): if phase1: phase1.setValue(100) phase1.setStyleSheet(redStyle) - logger.info("Ballot cast confirmations are: [\033[1;31m NOT ACCEPTED \033[0;0m]") + logger.info("The ballot cast confirmations are: [\033[1;31m NOT ACCEPTED \033[0;0m]") return False if not os.path.exists(receiptPath): @@ -722,7 +722,7 @@ def verify_receipts(path, phase1=None, log=False, logTo=None): if phase1: phase1.setValue(100) phase1.setStyleSheet(redStyle) - logger.info("Ballot cast confirmations are: [\033[1;31m NOT ACCEPTED \033[0;0m]") + logger.info("The ballot cast confirmations are: [\033[1;31m NOT ACCEPTED \033[0;0m]") return False if phase1: @@ -738,7 +738,7 @@ def verify_receipts(path, phase1=None, log=False, logTo=None): for t in range(len(files)): fingerprint = get_signature_if_valid(receiptPath, files[t], verificationKey, logTo) if fingerprint and fingerprint not in ballotsByFingerprint: - logger.info("Ballot %s is not included in the ballot box." % fingerprint) + logger.info("The ballot %s is not included in the ballot box." % fingerprint) if logTo is not None: logTo.append({"status": ReceiptStatus.MISSING, "fingerprint": fingerprint}) valid = False @@ -757,7 +757,7 @@ def verify_receipts(path, phase1=None, log=False, logTo=None): if log and fingerprint in ballotsByFingerprint: status = ballots[ballotsByFingerprint[fingerprint]].status - logger.info("Ballot %s is included in the ballot box with status %s." % (fingerprint, status)) + logger.info("The ballot %s is included in the ballot box with status %s." % (fingerprint, status)) if logTo is not None: logTo.append({"status": ReceiptStatus.PRESENT, "fingerprint": fingerprint, "ballotStatus": status}) if phase1: @@ -768,9 +768,9 @@ def verify_receipts(path, phase1=None, log=False, logTo=None): logger.info("----------------------------------------------------------") if valid: - logger.info("Ballot cast confirmations are: [\033[1;32m ACCEPTED \033[0;0m]") + logger.info("The ballot cast confirmations are: [\033[1;32m ACCEPTED \033[0;0m]") else: - logger.info("Ballot cast confirmations are: [\033[1;31m NOT ACCEPTED \033[0;0m]") + logger.info("The ballot cast confirmations are: [\033[1;31m NOT ACCEPTED \033[0;0m]") if phase1: phase1.setStyleSheet(redStyle) logger.info("") @@ -796,7 +796,7 @@ def verification(path, accepted, phase1=None, phase2=None, phase3=None, phase4=N logger.info("----------------------------------------------------------") logger.info("VERIFYING") logger.info("----------------------------------------------------------") - logger.info("Verifying the public election key with zk-proof...") + logger.info("Verifying the public election key with zero-knowledge proof...") if verify_public_election_key(path, phase1) is not True: printFailed() accepted = False @@ -807,7 +807,7 @@ def verification(path, accepted, phase1=None, phase2=None, phase3=None, phase4=N if phase1: phase1.setStyleSheet(greenStyle) - logger.info("Verifying ballot-box...") + logger.info("Verifying ballot box...") if verify_ballot_box(path, phase2) is not True: printFailed() accepted = False @@ -829,7 +829,7 @@ def verification(path, accepted, phase1=None, phase2=None, phase3=None, phase4=N if phase3: phase3.setStyleSheet(greenStyle) - logger.info("Verifying mix packets...") + logger.info("Verifying mixing packets...") if verify_mixing_input(path, phase4) is not True: printFailed() accepted = False @@ -864,19 +864,19 @@ def verification(path, accepted, phase1=None, phase2=None, phase3=None, phase4=N if __name__ == '__main__': parser = argparse.ArgumentParser( - prog='verificationtool.py', - description='Program to verify the election results of a polyas election', + prog='polyas_checker.py', + description='Program to check the election results (universal verification) of a polyas election', epilog='') parser.add_argument('path', type=str, help='The absolute path to the polyas verification files.') - parser.add_argument('-s', '--second-device', action='store_true', dest='sdpp', help='Verificationtool will verify second device public parameters.') - parser.add_argument('-r', '--receipts', action='store_true', dest='rec', help='Verificationtool will check ballot cast confirmations in folder \receipts\'.') - parser.add_argument('--log', action='store_true', dest='list', help='Verificationtool will log additional information for ballot cast confirmations.') + parser.add_argument('-s', '--second-device', action='store_true', dest='sdpp', help='Polyas-Checker will verify second device public parameters.') + parser.add_argument('-r', '--receipts', action='store_true', dest='rec', help='Polyas-Checker will check ballot cast confirmations in folder \receipts\'.') + parser.add_argument('--log', action='store_true', dest='list', help='Polyas-Checker will log additional information for ballot cast confirmations.') parser.add_argument('-l', '--language', type=str, help="Set preferred language") args = parser.parse_args() logger.info("\033[0;0m") - logger.info("VerificationTool") + logger.info("Polyas-Checker") logger.info("Running version " + VERSION) accepted = True diff --git a/src/verificationtoolGUI.py b/src/polyas_checkerGUI.py similarity index 93% rename from src/verificationtoolGUI.py rename to src/polyas_checkerGUI.py index a7df3d7..be5cab3 100644 --- a/src/verificationtoolGUI.py +++ b/src/polyas_checkerGUI.py @@ -4,8 +4,8 @@ from PyQt5.QtWidgets import QTableWidgetItem, QFileDialog, QApplication, QWidget, QVBoxLayout, QPushButton, QLineEdit, QLabel, QGroupBox from PyQt5.QtWidgets import QCheckBox, QProgressBar, QTableWidget, QGridLayout, QScrollArea -from verificationtool import checking_files, load_registry, do_tallying, print_registry, get_tallying_result_cmdline, logger, verification -from verificationtool import verify_second_device_public_parameters, verify_receipts, ReceiptStatus, greenStyle +from polyas_checker import checking_files, load_registry, do_tallying, print_registry, get_tallying_result_cmdline, logger, verification +from polyas_checker import verify_second_device_public_parameters, verify_receipts, ReceiptStatus, greenStyle import sys headerStyle = """ @@ -216,25 +216,25 @@ def browse(): progressWidget.setLayout(progressLayout) # Phase 1 -phase1Label = QLabel("Verifying the public election key with zk-proof") +phase1Label = QLabel("Verifying the public election key with the zero-knowledge proof") progressLayout.addWidget(phase1Label) phase1 = QProgressBar() progressLayout.addWidget(phase1) # Phase 2 -phase2Label = QLabel("Verifying ballot-box") +phase2Label = QLabel("Verifying the ballot box") progressLayout.addWidget(phase2Label) phase2 = QProgressBar() progressLayout.addWidget(phase2) # Phase 3 -phase3Label = QLabel("Verifying ballot decryption") +phase3Label = QLabel("Verifying the ballot decryption(s)") progressLayout.addWidget(phase3Label) phase3 = QProgressBar() progressLayout.addWidget(phase3) # Phase 4 -phase4Label = QLabel("Verifying shuffle") +phase4Label = QLabel("Verifying the shuffle(s)") progressLayout.addWidget(phase4Label) phase4 = QProgressBar() progressLayout.addWidget(phase4) @@ -271,18 +271,18 @@ def browse(): resLabel.setStyleSheet(resStyle) receiptsLogLabel.setStyleSheet(logStyle) -btStartVerification = QPushButton('Start verification') +btStartVerification = QPushButton('Start universal verification') btStartVerification.clicked.connect(start_verification) layout.addWidget(btStartVerification) -resetButton = QPushButton('New verification') +resetButton = QPushButton('New universal verification') resetButton.clicked.connect(reset) resetButton.setVisible(False) layout.addWidget(resetButton) window.setLayout(layout) -window.setWindowTitle('Verification of election result') +window.setWindowTitle('Polyas-Checker') window.setFixedSize(800, 800) window.show() diff --git a/src/test/integrationtests.py b/src/test/integrationtests.py index b886513..b112997 100644 --- a/src/test/integrationtests.py +++ b/src/test/integrationtests.py @@ -7,7 +7,7 @@ import json from parameterized import parameterized from app.helper.classes import BallotBoxEntry -from app.verificationtool import verify_ballot_box, verify_mixing_input, get_signature_if_valid, initialize_gpg +from app.polyas-checker import verify_ballot_box, verify_mixing_input, get_signature_if_valid, initialize_gpg from app.helper.secureJSON import loadSecureJSON logger = logging.getLogger()