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)
Пример #3
0
    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)
Пример #4
0
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