def test_election_hash_is_consistent_regardless_of_format(self): # Act subject1 = election_factory.get_simple_election_from_file() subject1.start_date = read_json('"2020-03-01T08:00:00-05:00"', datetime) subject2 = election_factory.get_simple_election_from_file() subject2.start_date = read_json('"2020-03-01T13:00:00-00:00"', datetime) subject3 = election_factory.get_simple_election_from_file() subject3.start_date = read_json('"2020-03-01T13:00:00.000-00:00"', datetime) subjects = [subject1, subject2, subject3] # Assert hashes = [subject.crypto_hash() for subject in subjects] for other_hash in hashes[1:]: self.assertEqual(hashes[0], other_hash)
def test_read_and_write_json(self) -> None: # Act json_string = write_json(JSON_DATA) # Assert self.assertEqual(json_string, EXPECTED_JSON_STRING) # Act read_json_data = read_json(json_string, DataModel) # Assert self.assertEqual(read_json_data, JSON_DATA)
def test_read_iso_date(self) -> None: # Arrange target_date = datetime(2020, 9, 28, 20, 11, 31, tzinfo=timezone.utc) representations = [ # UTC '"2020-09-28T20:11:31+00:00"', '"2020-09-28T20:11:31.000+00:00"', '"2020-09-28T20:11:31.000Z"', '"2020-09-28T20:11:31Z"', # Other time zone '"2020-09-28T21:11:31+01:00"', '"2020-09-28T21:11:31.000+01:00"', ] # Act results = [read_json(value, datetime) for value in representations] # Assert # expected_timestamp = target_date.timestamp() for result in results: self.assertEqual(target_date, result)
def deserialize(obj: str, type: Type[T]) -> T: return read_json(obj, type)
def main() -> int: """Function which reads and deserializes election results into memory via command line arguments and then invokes verification function. Primary target of command line utility.""" # Parse argument from command line parser = ArgumentParser(description='ElectionGuard Verifier.') parser.add_argument('directory', default=getcwd(), nargs='?', help='Directory containing election files.') parser.add_argument( '-c', '--context', help= 'File containing election context JSON, overriding files found in election directory.' ) parser.add_argument( '-d', '--description', help= 'File containing election description JSON, overriding files found in election directory.' ) parser.add_argument( '-e', '--encrypted-tally', help= 'File containing election encrypted tally JSON, overriding files found in election directory.' ) parser.add_argument( '-k', '--constants', help= 'File containing election constants JSON, overriding files found in election directory.' ) parser.add_argument( '-t', '--tally', help= 'File containing election tally JSON, overriding files found in election directory.' ) parser.add_argument( '-x', '--devices-prefix', help="Prefix for device JSON file names, overriding default prefix.") parser.add_argument( '-X', '--devices-dir', help= "Directory containing device JSON, overriding election subdirectory.") parser.add_argument( '-b', '--encrypted-ballots-prefix', help= "Prefix for encrypted ballot JSON file names, overriding default prefix." ) parser.add_argument( '-B', '--encrypted-ballots-dir', help= "Directory containing encrypted ballots JSON, overriding election subdirectory." ) parser.add_argument( '-s', '--spoiled-ballots-prefix', help= "Prefix for spoiled ballot JSON file names, overriding default prefix." ) parser.add_argument( '-S', '--spoiled-ballots-dir', help= "Directory containing spoiled ballots JSON, overriding election subdirectory." ) parser.add_argument( '-f', '--coefficients-prefix', help= "Prefix for coefficient validation set JSON file names, overriding default prefix." ) parser.add_argument( '-F', '--coefficients-dir', help= "Directory containing coefficient validation set JSON, overriding election subdirectory." ) parser.add_argument('-v', '--verbose', default=False, action='store_true', help='Output vaildation details.') parser.add_argument( '-n', '--no-warn', default=False, action='store_true', help='Silence all warnings. Has no effect in verbose mode.') args = parser.parse_args() # Deserialize election results context_path: str = args.context or join(args.directory, CONTEXT_FILE_NAME + JSON_EXT) with open(context_path, READ) as f: context: CiphertextElectionContext = read_json( f.read(), CiphertextElectionContext) description_path: str = args.description or join( args.directory, DESCRIPTION_FILE_NAME + JSON_EXT) with open(description_path, READ) as f: description: ElectionDescription = read_json(f.read(), ElectionDescription) ciphertext_tally_path: str = args.encrypted_tally or join( args.directory, ENCRYPTED_TALLY_FILE_NAME + JSON_EXT) with open(ciphertext_tally_path, READ) as f: ciphertext_tally: PublishedCiphertextTally = read_json( f.read(), PublishedCiphertextTally) constants_path: str = args.constants or join( args.directory, CONSTANTS_FILE_NAME + JSON_EXT) with open(constants_path, READ) as f: constants: ElectionConstants = read_json(f.read(), ElectionConstants) plaintext_tally_path: str = args.tally or join(args.directory, TALLY_FILE_NAME + JSON_EXT) with open(plaintext_tally_path, READ) as f: plaintext_tally: PlaintextTally = read_json(f.read(), PlaintextTally) devices_dir: str = args.devices_dir or join(args.directory, split(DEVICES_DIR)[-1]) devices_prefix: str = args.devices_prefix or DEVICE_PREFIX device_files: list[str] = glob( join(devices_dir, f'{devices_prefix}*{JSON_EXT}')) devices: list[EncryptionDevice] = [] for device_file in device_files: with open(device_file, READ) as f: devices.append(read_json(f.read(), EncryptionDevice)) enc_ballots_dir: str = args.encrypted_ballots_dir or join( args.directory, split(BALLOTS_DIR)[-1]) enc_ballots_prefix: str = args.encrypted_ballots_prefix or BALLOT_PREFIX enc_ballot_files: list[str] = glob( join(enc_ballots_dir, f'{enc_ballots_prefix}*{JSON_EXT}')) ciphertext_ballots: list[CiphertextAcceptedBallot] = [] for enc_ballot in enc_ballot_files: with open(enc_ballot, READ) as f: ciphertext_ballots.append( read_json(f.read(), CiphertextAcceptedBallot)) spoiled_ballots_dir: str = args.spoiled_ballots_dir or join( args.directory, split(SPOILED_DIR)[-1]) spoiled_ballots_prefix: str = args.spoiled_ballots_prefix or BALLOT_PREFIX spoiled_ballot_files: list[str] = glob( join(spoiled_ballots_dir, f'{spoiled_ballots_prefix}*{JSON_EXT}')) spoiled_ballots: list[CiphertextAcceptedBallot] = [] for spoiled_ballot in spoiled_ballot_files: with open(spoiled_ballot, READ) as f: spoiled_ballots.append( read_json(f.read(), CiphertextAcceptedBallot)) coefficients_dir: str = args.coefficients_dir or join( args.directory, split(COEFFICIENTS_DIR)[-1]) coefficients_prefix: str = args.coefficients_prefix or COEFFICIENT_PREFIX coefficients_files: list[str] = glob( join(coefficients_dir, f'{coefficients_prefix}*{JSON_EXT}')) coefficient_validation_sets: list[CoefficientValidationSet] = [] for coefficient in coefficients_files: with open(coefficient, READ) as f: coefficient_validation_sets.append( read_json(f.read(), CoefficientValidationSet)) # Set logging verbosity if (args.verbose): basicConfig(level=INFO, format='%(message)s') elif (args.no_warn): basicConfig(level=ERROR, format='%(message)s') else: basicConfig(format='%(message)s') # Verify election is_valid: bool = verify(description, context, constants, devices, ciphertext_ballots, spoiled_ballots, ciphertext_tally, plaintext_tally, coefficient_validation_sets) # Exit with result if (is_valid): print("Election valid.") return EXIT_SUCCESS else: print("Election invalid.") return EXIT_FAILURE