Support external_ballot_identifer as a string (#71)
* Support external_ballot_identifer as a string. Export/import ballots from encrypter Add support for encrypter to export ballots to the file system. Import encrypter ballots into coordinator. Add a hashtable implementation that tracks ballot cast/spoil state against the external identifier (ballot_collection.c). Support loading ballots into a buffer. Fix memory leaks in bignum.c, crypto.c, decryption/coordinator.c, decryption/trustee.c, voting/coordinator.c, voting/encrypter.c, etc. Rework the API example to demonstrate the new external id and file system changes. Improve debug logging. Add more api documentation. Modify MAX_BALLOT_PAYLOAD to 2000. Explicitly add // TODO: to track remaining work. Note this commit is a work in progress and currently breaks the simple example. * Remove Simple Example, add api doc stubs Add stubs for the api documentation. Remove the simple example and use the api sample in the PR pipeline workflow * Fix Merge Issue * Verify malloc success * Address PR Feedback * Fix LGTM alerts * Add soft delete of encrypter files * Free CP Proof * Fix windows Makefile * test fix pr workflow on windows * use secure api's * explicitly compile release * flush file write before read * clean up makefile * Document consumers resonsible for free when calling an api that generates a filename as an out parameter, the caller is responsible for managing the memory of the out parameter when the call is successful * Rename static coordinators in API to differentiate local vars add an underscore prefix to static coordinator instance handles to differentiate vars until #62 is complete * add new enum cases to the end on voting coordinator * Add convenience logging * Handle error cases on file access use convenience logging * use consistent file formatting when rebuilding tracker string * optimize null check * explicitly set tracker array positions to NULL on failure * Reformat refactor Decryption_Coordinator_receive_share * guard tallies_initialized when freeing resources explicitly initialize num_tallies * rename _encrypted_ballot_count * don't return early * do not fail soft delete if rename fails * fix assignment * adjust number of ballots to force a rebuild
This commit is contained in:
Родитель
6aa4464f2d
Коммит
d9dd0a1037
|
@ -22,14 +22,14 @@ jobs:
|
|||
cmake --version
|
||||
cmake -S . -B build
|
||||
cmake --build build
|
||||
- name: 'Build Simple Election'
|
||||
- name: 'Build API Sample Election'
|
||||
run: |
|
||||
ElectionGuard_DIR="$PWD/build/ElectionGuard" cmake -S examples/simple -B simple_build
|
||||
cmake --build simple_build --target simple
|
||||
- name: 'Test Simple Election'
|
||||
ElectionGuard_DIR="$PWD/build/ElectionGuard" cmake -S examples/api -B api_build
|
||||
cmake --build api_build --target api
|
||||
- name: 'Test API Sample Election'
|
||||
run: |
|
||||
cd simple_build
|
||||
./simple
|
||||
cd api_build
|
||||
./api
|
||||
windows_build:
|
||||
name: 'Windows Build'
|
||||
runs-on: 'windows-latest'
|
||||
|
@ -55,15 +55,15 @@ jobs:
|
|||
cmake --version
|
||||
cmake -S . -B build -G "MSYS Makefiles"
|
||||
cmake --build build
|
||||
- name: 'Build Simple Election'
|
||||
- name: 'Build API Sample Election'
|
||||
run: |
|
||||
$env:CMAKE_PREFIX_PATH="./build/ElectionGuard"
|
||||
cmake -S examples/simple -B simple_build -G "MSYS Makefiles"
|
||||
cmake --build simple_build --target simple
|
||||
- name: 'Test Simple Election'
|
||||
cmake -S examples/api -B api_build -G "MSYS Makefiles"
|
||||
cmake --build api_build --target api
|
||||
- name: 'Test API Sample Election'
|
||||
run: |
|
||||
cd simple_build
|
||||
$outcome = Invoke-Expression ".\simple.exe"
|
||||
$env:Path+=";.\build\"
|
||||
$outcome = Invoke-Expression ".\api_build\api.exe"
|
||||
echo $outcome
|
||||
macos_build:
|
||||
name: 'MacOS Build'
|
||||
|
@ -82,11 +82,11 @@ jobs:
|
|||
cmake --version
|
||||
cmake -S . -B build
|
||||
cmake --build build
|
||||
- name: 'Build Simple Election'
|
||||
- name: 'Build API Sample Election'
|
||||
run: |
|
||||
ElectionGuard_DIR="$PWD/build/ElectionGuard" cmake -S examples/simple -B simple_build
|
||||
cmake --build simple_build --target simple
|
||||
- name: 'Test Simple Election'
|
||||
ElectionGuard_DIR="$PWD/build/ElectionGuard" cmake -S examples/api -B api_build
|
||||
cmake --build api_build --target api
|
||||
- name: 'Test API Sample Election'
|
||||
run: |
|
||||
cd simple_build
|
||||
./simple
|
||||
cd api_build
|
||||
./api
|
|
@ -34,3 +34,7 @@ _deps
|
|||
ElectionGuardConfig.cmake
|
||||
*_build/
|
||||
ballots/
|
||||
|
||||
ballots_encrypter/
|
||||
|
||||
tallies/
|
||||
|
|
|
@ -12,8 +12,8 @@ set(CMAKE_C_EXTENSIONS OFF)
|
|||
message("Generated with config types: ${CMAKE_CONFIGURATION_TYPES}")
|
||||
|
||||
IF(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
message("setting DEBUG_PRINT")
|
||||
add_compile_definitions(DEBUG_PRINT)
|
||||
message("setting DEBUG during compile")
|
||||
add_compile_definitions(DEBUG)
|
||||
ENDIF()
|
||||
|
||||
|
||||
|
@ -22,11 +22,13 @@ add_library(electionguard
|
|||
${PROJECT_SOURCE_DIR}/src/electionguard/api/filename.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/api/create_election.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/api/encrypt_ballot.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/api/load_ballots.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/api/record_ballots.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/api/tally_votes.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/crypto_reps.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/ballot_collection.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/coordinator.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/num_ballots.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/messages.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/message_reps.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/nouns.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/tracker.c
|
||||
|
@ -54,6 +56,7 @@ add_library(electionguard
|
|||
${PROJECT_SOURCE_DIR}/src/electionguard/keyceremony/trustee.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/uint4096.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/bignum.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/log.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/sha2-openbsd.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/sha2-openbsd.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/crypto.c
|
||||
|
@ -62,15 +65,15 @@ add_library(electionguard
|
|||
${PROJECT_SOURCE_DIR}/src/electionguard/random_source.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/random_source.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/trustee_state_rep.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/file.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/directory.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/directory.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/uthash.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/api/config.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/api/create_election.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/api/encrypt_ballot.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/api/load_ballots.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/api/record_ballots.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/api/tally_votes.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/file.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/max_values.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/trustee_state.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/voting/messages.h
|
||||
|
@ -109,8 +112,8 @@ if (MINGW)
|
|||
set_target_properties(electionguard PROPERTIES PREFIX "")
|
||||
endif()
|
||||
|
||||
# Set the public include directory depending on if the target is being exported
|
||||
# or installed
|
||||
# Set the public include directory depending on
|
||||
# if the target is being exported or installed
|
||||
target_include_directories(electionguard
|
||||
SYSTEM PUBLIC
|
||||
$<INSTALL_INTERFACE:include>
|
||||
|
@ -148,18 +151,9 @@ install(
|
|||
|
||||
add_subdirectory(docs)
|
||||
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/simple_build")
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/api_build")
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug" CACHE STRING "" FORCE)
|
||||
|
||||
add_test(NAME build_simple
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-E env ElectionGuard_DIR=${CMAKE_CURRENT_BINARY_DIR}/ElectionGuard
|
||||
"${CMAKE_CTEST_COMMAND}"
|
||||
--build-and-test "${PROJECT_SOURCE_DIR}/examples/simple" "${CMAKE_CURRENT_BINARY_DIR}/simple_build"
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--test-command simple
|
||||
)
|
||||
|
||||
add_test(NAME build_api
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-E env ElectionGuard_DIR=${CMAKE_CURRENT_BINARY_DIR}/ElectionGuard
|
||||
|
|
|
@ -14,7 +14,7 @@ If new to the project,
|
|||
2. Install according to [ReadMe](./README.rst)
|
||||
OR
|
||||
refer to [Documentation](https://electionguard.github.io/ElectionGuard-SDK-C-Documentation/)
|
||||
3. Once you're up and running, be sure to run the simple election test
|
||||
3. Once you're up and running, be sure to run the API sample election test
|
||||
|
||||
⚠ Note: If you get stuck, take a look at our [GitHub Action](./.github/workflows/pr-workflow.yml)
|
||||
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
.PHONY: add-dependencies build build-debug clean run-api test
|
||||
|
||||
BUILD_DEBUG?=true
|
||||
|
||||
.EXPORT_ALL_VARIABLES:
|
||||
ELECTIONGUARD_DIR="$(realpath .)/build/ElectionGuard"
|
||||
|
||||
# Detect operating system
|
||||
ifeq ($(OS),Windows_NT)
|
||||
OPERATING_SYSTEM := Windows
|
||||
else
|
||||
OPERATING_SYSTEM := $(shell uname 2>/dev/null || echo Unknown)
|
||||
endif
|
||||
|
||||
add-dependencies:
|
||||
ifeq ($(OPERATING_SYSTEM),Darwin)
|
||||
|
||||
endif
|
||||
ifeq ($(OPERATING_SYSTEM),Linux)
|
||||
|
||||
endif
|
||||
ifeq ($(OPERATING_SYSTEM),Windows)
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_DEBUG),true)
|
||||
build: build-debug
|
||||
else
|
||||
build: build-release
|
||||
endif
|
||||
|
||||
build-debug: clean
|
||||
if [ ! -d "build" ]; then mkdir build; fi
|
||||
ifeq ($(OPERATING_SYSTEM),Windows)
|
||||
cmake -S . -B build -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug
|
||||
else
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
|
||||
endif
|
||||
cmake --build build
|
||||
|
||||
build-release: clean
|
||||
if [ ! -d "build" ]; then mkdir build; fi
|
||||
ifeq ($(OPERATING_SYSTEM),Windows)
|
||||
cmake -S . -B build -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON
|
||||
else
|
||||
cmake -S . -B build -DBUILD_SHARED_LIBS=ON
|
||||
endif
|
||||
cmake --build build
|
||||
|
||||
clean:
|
||||
rm -rf ./build/* ./api_build/*
|
||||
|
||||
run-api: build
|
||||
if [ ! -d "api_build" ]; then mkdir api_build; fi
|
||||
ifeq ($(OPERATING_SYSTEM),Windows)
|
||||
CMAKE_PREFIX_PATH="./build/ElectionGuard" cmake -S examples/api -B api_build -G "MSYS Makefiles"
|
||||
cmake --build api_build --target api
|
||||
PATH=$(PWD)/build:$$PATH; ./api_build/api
|
||||
else
|
||||
ElectionGuard_DIR=$(ELECTIONGUARD_DIR) cmake -S examples/api -B api_build
|
||||
cmake --build api_build --target api
|
||||
./api_build/api
|
||||
endif
|
||||
|
||||
test: build
|
||||
cmake --build build --target test
|
||||
|
|
@ -23,13 +23,13 @@
|
|||
cmake --build build
|
||||
|
||||
3. You should now have a `electionguard.a` or `electionguard.dll` (depending on the how cmake was configured).
|
||||
3. (Optional) Build the simple example election driver.
|
||||
3. (Optional) Build the api example election driver.
|
||||
1. Open a command prompt and navigate to the directory with the ElectionGuard-SDK-C-Implementation repo.
|
||||
2. Run the following commands:
|
||||
|
||||
set PATH=%PATH%;C:\path\to\ElectionGuard-SDK-C-Implementation\build\
|
||||
set CMAKE_PREFIX_PATH=C:\path\to\ElectionGuard-SDK-C-Implementation\build\ElectionGuard
|
||||
cmake -S examples/simple -B simple_build -G "MSYS Makefiles"
|
||||
cmake --build simple_build --target simple
|
||||
cmake -S examples/api -B api_build -G "MSYS Makefiles"
|
||||
cmake --build api_build --target api
|
||||
|
||||
3. You should now have a `simple.exe` that simulates some random voters and generates election record artifacts.
|
||||
3. You should now have a `api.exe` that simulates some random voters and generates election record artifacts.
|
||||
|
|
24
README.rst
24
README.rst
|
@ -53,11 +53,17 @@ To build the SDK static library ``libelectionguard.a``, run
|
|||
|
||||
cmake --build build
|
||||
|
||||
Alternatively there is a `Makefile` to wrap the cmake commands:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
make build
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Currently you can exercise the SDK by running the :doc:`example client
|
||||
<examples/simple>`. We include a cmake test to do so automatically. You can
|
||||
Currently you can exercise the SDK by running the :doc:`api client
|
||||
<examples/api>`. We include a cmake test to do so automatically. You can
|
||||
also execute the client directly to better examine the output it produces.
|
||||
|
||||
.. warning::
|
||||
|
@ -95,11 +101,17 @@ to refer to the built library, and build the client.
|
|||
|
||||
.. code:: sh
|
||||
|
||||
mkdir simple_build
|
||||
ElectionGuard_DIR="$PWD/build/ElectionGuard" cmake -S examples/simple -B simple_build
|
||||
cmake --build simple_build --target simple
|
||||
mkdir api_build
|
||||
ElectionGuard_DIR="$PWD/build/ElectionGuard" cmake -S examples/api -B api_build
|
||||
cmake --build api_build --target api
|
||||
|
||||
The built binary should be located at :file:`simple_build/simple`.
|
||||
The built binary should be located at :file:`api_build/api`.
|
||||
|
||||
alternatively, you can use the convenience Makefile
|
||||
|
||||
.. code:: sh
|
||||
|
||||
make run-api
|
||||
|
||||
|
||||
Debugging
|
||||
|
|
|
@ -6,5 +6,5 @@ let
|
|||
};
|
||||
in with import nixpkgs {}; rec {
|
||||
electionguard = callPackages ./derivation.nix { };
|
||||
simple = callPackages ./examples/simple { inherit electionguard; };
|
||||
api = callPackages ./examples/api { inherit electionguard; };
|
||||
}
|
||||
|
|
|
@ -41,10 +41,16 @@ IF(BUILD_DOCUMENTATION)
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/examples.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/voting.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/keyceremony.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/simple.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/api.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/index.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/crypto.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/trustee_state.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/api/config.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/api/create_election.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/api/encrypt_ballot.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/api/load_ballots.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/api/record_ballots.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/api/tally_votes.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/voting/coordinator.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/voting/encrypter.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/voting/messages.rst
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Config
|
||||
======
|
|
@ -0,0 +1,2 @@
|
|||
Create Election
|
||||
===============
|
|
@ -0,0 +1,2 @@
|
|||
Encrypt Ballot
|
||||
==============
|
|
@ -0,0 +1,2 @@
|
|||
Load Ballots
|
||||
============
|
|
@ -0,0 +1,2 @@
|
|||
Record Ballots
|
||||
==============
|
|
@ -0,0 +1,2 @@
|
|||
Tally Votes
|
||||
===========
|
|
@ -0,0 +1,19 @@
|
|||
API Example Client
|
||||
===============
|
||||
|
||||
This simple client is designed to showcase the API by demonstrating
|
||||
the correct sequence of function calls used in an elecition.
|
||||
|
||||
.. warning::
|
||||
|
||||
This example client **does not** do any sort of error handling in
|
||||
order to more clearly highlight the "happy path" of an election.
|
||||
Please do not use this code in a real system.
|
||||
|
||||
:file:`main.c`
|
||||
--------------
|
||||
|
||||
.. literalinclude:: /../examples/api/main.c
|
||||
:language: c
|
||||
:linenos:
|
||||
:caption: main.c
|
|
@ -1,43 +0,0 @@
|
|||
Simple Client
|
||||
===============
|
||||
|
||||
This simple client is designed to showcase the API by demonstrating
|
||||
the correct sequence of function calls used in an elecition.
|
||||
|
||||
.. warning::
|
||||
|
||||
This example client **does not** do any sort of error handling in
|
||||
order to more clearly highlight the "happy path" of an election.
|
||||
Please do not use this code in a real system.
|
||||
|
||||
:file:`main.c`
|
||||
--------------
|
||||
|
||||
.. literalinclude:: /../examples/simple/main.c
|
||||
:language: c
|
||||
:linenos:
|
||||
:caption: main.c
|
||||
|
||||
:file:`main_keyceremony.c`
|
||||
--------------------------
|
||||
|
||||
.. literalinclude:: /../examples/simple/main_keyceremony.c
|
||||
:language: c
|
||||
:linenos:
|
||||
:caption: main_keyceremony.c
|
||||
|
||||
:file:`main_voting.c`
|
||||
---------------------
|
||||
|
||||
.. literalinclude:: /../examples/simple/main_voting.c
|
||||
:language: c
|
||||
:linenos:
|
||||
:caption: main_voting.c
|
||||
|
||||
:file:`main_decryption.c`
|
||||
-------------------------
|
||||
|
||||
.. literalinclude:: /../examples/simple/main_decryption.c
|
||||
:language: c
|
||||
:linenos:
|
||||
:caption: main_decryption.c
|
|
@ -1,20 +1,24 @@
|
|||
Example Clients
|
||||
===============
|
||||
|
||||
These examples demonstrate correct usage of the ElectionGuard SDK.
|
||||
These examples demonstrate usage of the ElectionGuard SDK.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:hidden:
|
||||
|
||||
Simple Client <examples/simple>
|
||||
API Client <examples/api>
|
||||
|
||||
- The :doc:`simple client <examples/simple>` carries out an election where all
|
||||
entities communicate via argument-passing.
|
||||
- The :doc:`api client <examples/api>` carries out an election where all
|
||||
entities communicate via argument-passing. It demonstrates using the
|
||||
high level API's
|
||||
|
||||
It should successfully exit with return status ``0``, and produce two files
|
||||
in the current directory with names of the form :file:`voting_results-XXXXXX`
|
||||
and :file:`tally-XXXXXX` containing ballots and the decrypted tallies
|
||||
respectively. It should also print all of the ballot trackers on STDOUT using
|
||||
- It should successfully exit with return status ``0``, and produce three files:
|
||||
- ballots/registered-ballots_YYY_MM_DD
|
||||
- ballots_encrypter/encrypted-ballots_YYYY_MM_DD
|
||||
- tallies/tallies_YYYY_MM_DD
|
||||
|
||||
- It should also print all of the ballot trackers on STDOUT using
|
||||
a representation where each byte is converted to a specific word.
|
||||
|
||||
- It should execute verification steps as part of the example
|
|
@ -17,7 +17,6 @@ add_executable(api
|
|||
${PROJECT_SOURCE_DIR}/main.c
|
||||
)
|
||||
|
||||
|
||||
find_package(ElectionGuard REQUIRED)
|
||||
|
||||
find_package(GMP REQUIRED)
|
||||
|
@ -31,7 +30,6 @@ else()
|
|||
target_link_libraries(api electionguard gmp)
|
||||
endif()
|
||||
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(api Bcrypt)
|
||||
endif (WIN32)
|
||||
|
|
|
@ -10,30 +10,47 @@
|
|||
|
||||
#include <electionguard/api/create_election.h>
|
||||
#include <electionguard/api/encrypt_ballot.h>
|
||||
#include <electionguard/api/load_ballots.h>
|
||||
#include <electionguard/api/record_ballots.h>
|
||||
#include <electionguard/api/tally_votes.h>
|
||||
#include <electionguard/max_values.h>
|
||||
|
||||
// test struct to capture ballot state
|
||||
struct test_ballot
|
||||
{
|
||||
uint64_t ballotId;
|
||||
char external_identifier[MAX_EXTERNAL_ID_LENGTH];
|
||||
bool isCast;
|
||||
bool isSpoiled;
|
||||
char *tracker;
|
||||
uint8_t selections[MAX_SELECTIONS];
|
||||
};
|
||||
|
||||
// misc functions
|
||||
static bool random_bit();
|
||||
static bool compare_string(char *first, char *second);
|
||||
static int32_t fill_random_ballot(uint8_t *selections);
|
||||
static bool result_equals_expected_selections(struct test_ballot *testBallots, uint32_t actual_tally, uint32_t selection_index);
|
||||
|
||||
// assertion functions
|
||||
static bool loaded_ballots_match_encrypted_ballots(
|
||||
struct register_ballot_message *loaded_ballots,
|
||||
struct register_ballot_message *encrypted_ballots,
|
||||
uint32_t ballot_count);
|
||||
static bool loaded_ballot_identifiers_match_encrypted_ballots(
|
||||
char **loaded_ballot_identifiers,
|
||||
struct test_ballot *test_ballots,
|
||||
uint32_t ballot_count);
|
||||
static bool result_equals_expected_selections(
|
||||
struct test_ballot *testBallots,
|
||||
uint32_t actual_tally,
|
||||
uint32_t selection_index);
|
||||
|
||||
// Election Parameters
|
||||
uint32_t const NUM_TRUSTEES = 3;
|
||||
uint32_t const THRESHOLD = 2;
|
||||
uint32_t const NUM_ENCRYPTERS = 3;
|
||||
uint32_t const NUM_SELECTIONS = 6;
|
||||
uint32_t const NUM_SELECTIONS = 12; // the number of total contest selections for an election
|
||||
uint32_t const DECRYPTING_TRUSTEES = 2; // must be >= THRESHOLD && <= NUM_TRUSTEES
|
||||
uint32_t const NUM_RANDOM_BALLOT_SELECTIONS = 6;
|
||||
uint32_t const NUM_RANDOM_BALLOTS = 5; // the number of ballots to use when executing the test
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@ -41,6 +58,8 @@ int main()
|
|||
|
||||
srand(time(NULL));
|
||||
|
||||
// TODO: name all output artifacts for the test run instance (e.g. by start time)
|
||||
|
||||
struct api_config config = {
|
||||
.num_selections = NUM_SELECTIONS,
|
||||
.num_trustees = NUM_TRUSTEES,
|
||||
|
@ -66,104 +85,214 @@ int main()
|
|||
|
||||
printf("\n--- Encrypt Ballots ---\n\n");
|
||||
|
||||
struct register_ballot_message encrypted_ballots[NUM_RANDOM_BALLOT_SELECTIONS];
|
||||
struct test_ballot testBallots[NUM_RANDOM_BALLOT_SELECTIONS];
|
||||
struct register_ballot_message memory_encrypted_ballots[NUM_RANDOM_BALLOTS];
|
||||
struct test_ballot testBallots[NUM_RANDOM_BALLOTS];
|
||||
|
||||
char *encrypted_ballots_filename = NULL;
|
||||
char *encrypted_output_path = "./ballots_encrypter/"; // This outputs to the directy above the cwd.
|
||||
char encrypted_output_prefix[50];
|
||||
|
||||
//generate a unique file name
|
||||
time_t now = time(NULL);
|
||||
struct tm *local_time = 0;
|
||||
local_time = localtime(&now);
|
||||
if (local_time == 0)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
sprintf(encrypted_output_prefix, "%s_%d_%d_%d", "encrypted-ballots",
|
||||
local_time->tm_year + 1900, local_time->tm_mon + 1, local_time->tm_mday);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
uint64_t current_num_ballots = 0;
|
||||
for (uint64_t i = 0; i < NUM_RANDOM_BALLOT_SELECTIONS && ok; i++)
|
||||
ok = API_EncryptBallot_soft_delete_file(encrypted_output_path, encrypted_output_prefix);
|
||||
|
||||
for (uint32_t i = 0; i < NUM_RANDOM_BALLOTS && ok; i++)
|
||||
{
|
||||
struct test_ballot testBallot;
|
||||
sprintf(testBallot.external_identifier, "some_string_value_%d", i);
|
||||
|
||||
struct register_ballot_message encrypted_ballot_message;
|
||||
//char *tracker;
|
||||
|
||||
// we're assuming that the returned number of true selections for this ballot
|
||||
// TODO: demonstrate the empty null field
|
||||
|
||||
// for now, we're assuming that the returned number of true selections for this ballot
|
||||
// is the the correct expected number for this ballot style in order to encrypt it
|
||||
uint32_t selected_count = fill_random_ballot(testBallot.selections);
|
||||
|
||||
ok = API_EncryptBallot(testBallot.selections, selected_count, config, ¤t_num_ballots,
|
||||
&testBallot.ballotId, &encrypted_ballot_message,
|
||||
&testBallot.tracker);
|
||||
ok = API_EncryptBallot(
|
||||
testBallot.selections,
|
||||
selected_count,
|
||||
config,
|
||||
testBallot.external_identifier,
|
||||
&encrypted_ballot_message,
|
||||
encrypted_output_path,
|
||||
encrypted_output_prefix,
|
||||
&encrypted_ballots_filename,
|
||||
&testBallot.tracker
|
||||
);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
encrypted_ballots[i] = encrypted_ballot_message;
|
||||
// ballot_identifiers[i] = testBallot.ballotId;
|
||||
// ballot_trackers[i] = testBallot.tracker;
|
||||
|
||||
memory_encrypted_ballots[i] = encrypted_ballot_message;
|
||||
testBallots[i] = testBallot;
|
||||
|
||||
// Print id and tracker
|
||||
printf("Ballot id: %lu\n%s\n\n", testBallot.ballotId, testBallot.tracker);
|
||||
printf("Encrypted Ballot id: %s\n%s\n\n",
|
||||
testBallots[i].external_identifier, testBallots[i].tracker);
|
||||
} else {
|
||||
printf("encrypt ballot failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: test simulating multiple encrypters or an encrypter being reset
|
||||
|
||||
// [START] OPTIONAL:
|
||||
|
||||
// When running an encrypter on another device, it is possible to import a file
|
||||
// and pass it to the tally functions, but this is not strictly necessary
|
||||
// from an API Perspective.
|
||||
|
||||
printf("\n--- Load Ballots ---\n\n");
|
||||
|
||||
// load the ballot ID's so we can cast/spoil them
|
||||
char *loaded_external_identifiers[NUM_RANDOM_BALLOTS];
|
||||
|
||||
// Load the data from the file that is created
|
||||
struct register_ballot_message loaded_encrypted_ballots[NUM_RANDOM_BALLOTS];
|
||||
|
||||
if (ok)
|
||||
{
|
||||
ok = API_LoadBallots(
|
||||
0,
|
||||
NUM_RANDOM_BALLOTS,
|
||||
NUM_SELECTIONS,
|
||||
encrypted_ballots_filename,
|
||||
loaded_external_identifiers,
|
||||
loaded_encrypted_ballots
|
||||
) == API_LOADBALLOTS_SUCCESS;
|
||||
|
||||
printf("\n--- Validate Ballots ---\n\n");
|
||||
|
||||
// verify the loaded ballots match the ones in memory
|
||||
assert(
|
||||
loaded_ballot_identifiers_match_encrypted_ballots(
|
||||
loaded_external_identifiers,
|
||||
testBallots,
|
||||
NUM_RANDOM_BALLOTS)
|
||||
);
|
||||
assert(
|
||||
loaded_ballots_match_encrypted_ballots(
|
||||
loaded_encrypted_ballots,
|
||||
memory_encrypted_ballots,
|
||||
NUM_RANDOM_BALLOTS
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: test loading ballots in batches
|
||||
|
||||
// free the ballots we loaded from disk
|
||||
// since they are not actually used in this test
|
||||
for (uint32_t i = 0; i < NUM_RANDOM_BALLOTS && ok; i++)
|
||||
API_EncryptBallot_free(loaded_encrypted_ballots[i], NULL);
|
||||
|
||||
// free the external identifiers we loaded for assertions
|
||||
// since they are not actually used in this test
|
||||
for (uint32_t i = 0; i < NUM_RANDOM_BALLOTS && ok; i++)
|
||||
free(loaded_external_identifiers[i]);
|
||||
|
||||
// [END] OPTIONAL:
|
||||
|
||||
// Register & Record Cast/Spoil Multiple Ballots
|
||||
|
||||
printf("\n--- Randomly Assigning Ballots to be Cast or Spoil Arrays ---\n\n");
|
||||
printf("\n\n--- Randomly Assigning Ballots to be Cast or Spoil Arrays ---\n\n");
|
||||
|
||||
uint32_t current_cast_index = 0;
|
||||
uint32_t current_spoiled_index = 0;
|
||||
uint64_t casted_ballot_ids[NUM_RANDOM_BALLOT_SELECTIONS];
|
||||
uint64_t spoiled_ballot_ids[NUM_RANDOM_BALLOT_SELECTIONS];
|
||||
char *casted_ballot_ids[NUM_RANDOM_BALLOTS];
|
||||
char *spoiled_ballot_ids[NUM_RANDOM_BALLOTS];
|
||||
char *memory_external_identifiers[NUM_RANDOM_BALLOTS];
|
||||
|
||||
for (uint64_t i = 0; i < NUM_RANDOM_BALLOT_SELECTIONS && ok; i++)
|
||||
for (uint32_t i = 0; i < NUM_RANDOM_BALLOTS && ok; i++)
|
||||
{
|
||||
char *id = testBallots[i].external_identifier;
|
||||
memory_external_identifiers[i] = id;
|
||||
if (random_bit())
|
||||
{
|
||||
testBallots[i].isCast = true;
|
||||
casted_ballot_ids[current_cast_index] = testBallots[i].ballotId;
|
||||
testBallots[i].isSpoiled = false;
|
||||
casted_ballot_ids[current_cast_index] = id;
|
||||
|
||||
printf("Ballot Id: %s - Cast!\n", casted_ballot_ids[current_cast_index]);
|
||||
current_cast_index++;
|
||||
|
||||
printf("Ballot Id: %lu - Cast!\n", testBallots[i].ballotId);
|
||||
}
|
||||
else
|
||||
{
|
||||
testBallots[i].isCast = false;
|
||||
testBallots[i].isSpoiled = true;
|
||||
spoiled_ballot_ids[current_spoiled_index] = testBallots[i].ballotId;
|
||||
current_spoiled_index++;
|
||||
spoiled_ballot_ids[current_spoiled_index] = id;
|
||||
|
||||
printf("Ballot Id: %lu - Spoiled!\n", testBallots[i].ballotId);
|
||||
printf("Ballot Id: %s - Spoiled!\n", spoiled_ballot_ids[current_spoiled_index]);
|
||||
current_spoiled_index++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((current_cast_index + current_spoiled_index) != NUM_RANDOM_BALLOT_SELECTIONS)
|
||||
if ((current_cast_index + current_spoiled_index) != NUM_RANDOM_BALLOTS)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
printf("\n--- Record Ballots (Register, Cast, and Spoil) ---\n\n");
|
||||
|
||||
char *ballots_filename;
|
||||
char *cast_and_spoiled_ballots_filename = NULL;
|
||||
char *casted_trackers[current_cast_index];
|
||||
char *spoiled_trackers[current_spoiled_index];
|
||||
|
||||
if (ok)
|
||||
{
|
||||
// Assigning an output_path fails if this folder doesn't already exist
|
||||
char *output_path = "./ballots/"; // This outputs to the directy above the cwd.
|
||||
char *output_prefix = "ballots-";
|
||||
ok = API_RecordBallots(config.num_selections, current_cast_index, current_spoiled_index,
|
||||
NUM_RANDOM_BALLOT_SELECTIONS, casted_ballot_ids, spoiled_ballot_ids, encrypted_ballots,
|
||||
output_path, output_prefix, &ballots_filename, casted_trackers, spoiled_trackers);
|
||||
char output_prefix[50];
|
||||
|
||||
sprintf(output_prefix, "%s_%d_%d_%d", "registered-ballots",
|
||||
local_time->tm_year + 1900, local_time->tm_mon + 1, local_time->tm_mday);
|
||||
|
||||
ok = API_RecordBallots(
|
||||
config.num_selections,
|
||||
current_cast_index,
|
||||
current_spoiled_index,
|
||||
NUM_RANDOM_BALLOTS,
|
||||
casted_ballot_ids,
|
||||
spoiled_ballot_ids,
|
||||
memory_external_identifiers,
|
||||
memory_encrypted_ballots,
|
||||
output_path,
|
||||
output_prefix,
|
||||
&cast_and_spoiled_ballots_filename,
|
||||
casted_trackers,
|
||||
spoiled_trackers
|
||||
);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
printf("Casted Ballot Trackers:\n");
|
||||
// TODO: assert on outputs not testBallots inputs
|
||||
|
||||
printf("\nCast Ballot Trackers:\n");
|
||||
for (uint32_t i = 0; i < current_cast_index; i++)
|
||||
{
|
||||
uint64_t id = casted_ballot_ids[i];
|
||||
assert(testBallots[id].isCast == true);
|
||||
printf("\t%ld: %s\n", id, casted_trackers[i]);
|
||||
printf("\t%s: %s\n", casted_ballot_ids[i], casted_trackers[i]);
|
||||
}
|
||||
|
||||
printf("\nSpoiled Ballot Trackers:\n");
|
||||
for (uint32_t i = 0; i < current_spoiled_index; i++)
|
||||
{
|
||||
uint64_t id = spoiled_ballot_ids[i];
|
||||
assert(testBallots[id].isSpoiled == true);
|
||||
printf("\t%ld: %s\n", id, spoiled_trackers[i]);
|
||||
printf("\t%s: %s\n", spoiled_ballot_ids[i], spoiled_trackers[i]);
|
||||
}
|
||||
|
||||
printf("\nBallot registrations and recording of cast/spoil successful!\nCheck output file \"%s\"\n",
|
||||
ballots_filename);
|
||||
cast_and_spoiled_ballots_filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,12 +300,16 @@ int main()
|
|||
|
||||
printf("\n--- Tally & Decrypt Votes ---\n\n");
|
||||
|
||||
char *tally_filename;
|
||||
char *tally_filename = NULL;
|
||||
uint32_t tally_results[config.num_selections];
|
||||
|
||||
if (ok)
|
||||
{
|
||||
char *output_path = "./tallies/"; // This outputs to the directy above the cwd.
|
||||
char *output_prefix = "tally-";
|
||||
char *output_path = "./tallies/"; // output to the directy above the cwd.
|
||||
char output_prefix[50];
|
||||
|
||||
sprintf(output_prefix, "%s_%d_%d_%d", "tally",
|
||||
local_time->tm_year + 1900, local_time->tm_mon + 1, local_time->tm_mday);
|
||||
|
||||
// copy the threshold number of trustees needed to decrypt
|
||||
struct trustee_state threshold_trustee_states[MAX_TRUSTEES];
|
||||
|
@ -185,11 +318,21 @@ int main()
|
|||
threshold_trustee_states[i] = trustee_states[i];
|
||||
assert(threshold_trustee_states[i].bytes != NULL);
|
||||
}
|
||||
|
||||
|
||||
// run the tally
|
||||
|
||||
printf("Tallying with %d of %d trustees \n\n", DECRYPTING_TRUSTEES, config.num_trustees);
|
||||
|
||||
ok = API_TallyVotes(config, threshold_trustee_states, DECRYPTING_TRUSTEES,
|
||||
ballots_filename, output_path, output_prefix, &tally_filename, tally_results);
|
||||
ok = API_TallyVotes(
|
||||
config,
|
||||
threshold_trustee_states,
|
||||
DECRYPTING_TRUSTEES,
|
||||
cast_and_spoiled_ballots_filename,
|
||||
output_path,
|
||||
output_prefix,
|
||||
&tally_filename,
|
||||
tally_results
|
||||
);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
|
@ -207,46 +350,108 @@ int main()
|
|||
|
||||
// Cleanup
|
||||
|
||||
printf("\n--- Cleaning Up Resources ---\n\n");
|
||||
|
||||
API_TallyVotes_free(tally_filename);
|
||||
API_RecordBallots_free(ballots_filename, current_cast_index, current_spoiled_index, casted_trackers, spoiled_trackers);
|
||||
for (uint64_t i = 0; i < NUM_RANDOM_BALLOT_SELECTIONS && ok; i++)
|
||||
API_EncryptBallot_free(encrypted_ballots[i], testBallots[i].tracker);
|
||||
|
||||
API_RecordBallots_free(
|
||||
cast_and_spoiled_ballots_filename,
|
||||
current_cast_index,
|
||||
current_spoiled_index,
|
||||
casted_trackers,
|
||||
spoiled_trackers
|
||||
);
|
||||
|
||||
API_LoadBallots_free(encrypted_ballots_filename);
|
||||
|
||||
for (uint32_t i = 0; i < NUM_RANDOM_BALLOTS && ok; i++)
|
||||
API_EncryptBallot_free(memory_encrypted_ballots[i], testBallots[i].tracker);
|
||||
|
||||
API_CreateElection_free(config.joint_key, trustee_states);
|
||||
|
||||
printf("\n--- Done! ---\n\n");
|
||||
|
||||
if (ok)
|
||||
return EXIT_SUCCESS;
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
bool result_equals_expected_selections(struct test_ballot *testBallots, uint32_t actual_tally, uint32_t selection_index)
|
||||
bool result_equals_expected_selections(
|
||||
struct test_ballot *testBallots, uint32_t actual_tally, uint32_t selection_index)
|
||||
{
|
||||
uint32_t expected_tally = 0;
|
||||
|
||||
for (uint64_t i = 0; i < NUM_RANDOM_BALLOT_SELECTIONS; i++)
|
||||
for (uint32_t i = 0; i < NUM_RANDOM_BALLOTS; i++)
|
||||
{
|
||||
if (testBallots[i].isCast) {
|
||||
expected_tally += testBallots[i].selections[selection_index];
|
||||
}
|
||||
}
|
||||
printf("\tselection: %d: expected: %d actual: %d\n", selection_index, expected_tally, actual_tally);
|
||||
printf("\tselection: %d: expected: %d actual: %d\n",
|
||||
selection_index, expected_tally, actual_tally);
|
||||
return expected_tally == actual_tally;
|
||||
}
|
||||
|
||||
bool loaded_ballots_match_encrypted_ballots(
|
||||
struct register_ballot_message *loaded_ballots,
|
||||
struct register_ballot_message *encrypted_ballots,
|
||||
uint32_t ballot_count)
|
||||
{
|
||||
printf("\nverifying %d ballots \n", ballot_count);
|
||||
|
||||
bool ok = true;
|
||||
for (uint32_t i = 0; i < ballot_count && ok; i++)
|
||||
{
|
||||
ok = Messages_are_equal(&loaded_ballots[i], &encrypted_ballots[i]);
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
printf("loaded ballots did not match the encrypted ballots!");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool loaded_ballot_identifiers_match_encrypted_ballots(
|
||||
char **loaded_ballot_identifiers, struct test_ballot *test_ballots, uint32_t ballot_count)
|
||||
{
|
||||
printf("\nverifying %d ballot identifiers\n", ballot_count);
|
||||
|
||||
bool ok = true;
|
||||
for (uint32_t i = 0; i < ballot_count && ok; i++)
|
||||
{
|
||||
printf("\ncompare_string:\n - expect: %s\n - actual: %s\n",
|
||||
loaded_ballot_identifiers[i], test_ballots[i].external_identifier);
|
||||
ok = compare_string(test_ballots[i].external_identifier, loaded_ballot_identifiers[i]);
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
printf("\nloaded ballot identifiers did not match the encrypted ballots!\n");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool random_bit() { return 1 & rand(); }
|
||||
|
||||
int32_t fill_random_ballot(uint8_t *selections)
|
||||
{
|
||||
// TODO: Handle null votes / expected num selected
|
||||
uint32_t selected_count = 0;
|
||||
for (uint32_t i = 0; i < NUM_SELECTIONS; i++)
|
||||
{
|
||||
if (random_bit())
|
||||
{
|
||||
// write true
|
||||
selections[i] = 1;
|
||||
selected_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// write false
|
||||
selections[i] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -260,3 +465,28 @@ int32_t fill_random_ballot(uint8_t *selections)
|
|||
|
||||
return selected_count;
|
||||
}
|
||||
|
||||
|
||||
bool compare_string(char *expected, char *actual)
|
||||
{
|
||||
while (*expected == *actual)
|
||||
{
|
||||
if (*expected == '\0' || *actual == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
expected++;
|
||||
actual++;
|
||||
}
|
||||
|
||||
if (*expected == '\0' && *actual == '\0')
|
||||
{
|
||||
printf("compare_string: success\n");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("compare_string: failed!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project("ElectionGuard Simple Example Client" VERSION 0.0.1 LANGUAGES C)
|
||||
|
||||
enable_testing()
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS ON)
|
||||
|
||||
set(CMAKE_MODULE_PATH
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../cmake
|
||||
${CMAKE_MODULE_PATH}
|
||||
)
|
||||
|
||||
add_executable(simple
|
||||
${PROJECT_SOURCE_DIR}/main_params.h
|
||||
${PROJECT_SOURCE_DIR}/main_voting.h
|
||||
${PROJECT_SOURCE_DIR}/main_decryption.c
|
||||
${PROJECT_SOURCE_DIR}/main_keyceremony.c
|
||||
${PROJECT_SOURCE_DIR}/main.c
|
||||
${PROJECT_SOURCE_DIR}/main_voting.c
|
||||
${PROJECT_SOURCE_DIR}/main_keyceremony.h
|
||||
${PROJECT_SOURCE_DIR}/main_decryption.h
|
||||
${PROJECT_SOURCE_DIR}/main_rsa.h
|
||||
${PROJECT_SOURCE_DIR}/main_rsa.c
|
||||
)
|
||||
|
||||
|
||||
find_package(ElectionGuard REQUIRED)
|
||||
|
||||
find_package(GMP REQUIRED)
|
||||
message(STATUS "GMP library found.")
|
||||
message(STATUS "GMP include dir is: ${GMP_INCLUDE_DIR}")
|
||||
message(STATUS "GMP library is: ${GMP_LIBRARY}")
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(simple electionguard ${GMP_LIBRARY})
|
||||
else()
|
||||
target_link_libraries(simple electionguard gmp)
|
||||
endif()
|
||||
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(simple Bcrypt)
|
||||
endif (WIN32)
|
||||
|
||||
add_test(NAME simple COMMAND simple)
|
||||
|
||||
install(TARGETS simple)
|
|
@ -1,13 +0,0 @@
|
|||
{ stdenv, nix-gitignore, cmake, electionguard }:
|
||||
stdenv.mkDerivation {
|
||||
pname = "electionguard-sdk";
|
||||
version = "0.0.1";
|
||||
|
||||
nativeBuildInputs = [ cmake electionguard ];
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
||||
doCheck = true;
|
||||
|
||||
src = nix-gitignore.gitignoreSourcePure ["*.nix" ../../.gitignore] ./.;
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include <electionguard/max_values.h>
|
||||
|
||||
#include "main_decryption.h"
|
||||
#include "main_keyceremony.h"
|
||||
#include "main_params.h"
|
||||
#include "main_rsa.h"
|
||||
#include "main_voting.h"
|
||||
|
||||
/** Create a new temporary file from a template. */
|
||||
static FILE *fmkstemps(char const *template, const char *mode);
|
||||
|
||||
// Election Parameters
|
||||
uint32_t const NUM_TRUSTEES = 3;
|
||||
uint32_t const THRESHOLD = 2;
|
||||
uint32_t const NUM_ENCRYPTERS = 3;
|
||||
uint32_t const NUM_SELECTIONS = 3;
|
||||
uint32_t const DECRYPTING_TRUSTEES = 2;
|
||||
|
||||
// ^The number of trustees that will participate in decryption. Will fail if this is less than THRESHOLD
|
||||
|
||||
// This is a temporary placeholder. In a real election, this should be
|
||||
// initialized by hashing:
|
||||
// 1. p (from bignum.h)
|
||||
// 2. The subgroup order (not yet named in the current implementation)
|
||||
// 3. generator (from bignum.h)
|
||||
// 4. NUM_TRUSTEES
|
||||
// 5. THRESHOLD
|
||||
// 6. The date of the election
|
||||
// 7. Jurisdictional information for the election
|
||||
raw_hash BASE_HASH_CODE = {0, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
int main()
|
||||
{
|
||||
srand(time(NULL));
|
||||
|
||||
Crypto_parameters_new();
|
||||
|
||||
// Outputs of the key ceremony
|
||||
struct trustee_state trustee_states[MAX_TRUSTEES];
|
||||
struct joint_public_key joint_key;
|
||||
|
||||
// Key Ceremony
|
||||
|
||||
bool ok = key_ceremony(&joint_key, trustee_states);
|
||||
|
||||
// Open the voting results file
|
||||
FILE *voting_results = NULL;
|
||||
|
||||
if (ok)
|
||||
{
|
||||
//Gcc on windows appears to not support the "x" flag at the time of writing
|
||||
#ifdef _WIN32
|
||||
voting_results = fmkstemps("voting_results-XXXXXX", "w+");
|
||||
#else
|
||||
voting_results = fmkstemps("voting_results-XXXXXX", "w+x");
|
||||
#endif
|
||||
|
||||
if (voting_results == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Voting
|
||||
if (ok)
|
||||
ok = voting(joint_key, voting_results);
|
||||
|
||||
// Open the tally file
|
||||
FILE *tally = NULL;
|
||||
|
||||
// // RSA encrypt decrypt check
|
||||
// if(ok)
|
||||
// ok = main_rsa();
|
||||
if (ok)
|
||||
{
|
||||
//Gcc on windows appears to not support the "x" flag at the time of writing
|
||||
#ifdef _WIN32
|
||||
tally = fmkstemps("tally-XXXXXX", "w");
|
||||
#else
|
||||
tally = fmkstemps("tally-XXXXXX", "wx");
|
||||
#endif
|
||||
|
||||
if (tally == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Decryption
|
||||
if (ok)
|
||||
ok = decryption(voting_results, tally, trustee_states);
|
||||
|
||||
// Cleanup
|
||||
|
||||
if (voting_results != NULL)
|
||||
{
|
||||
fclose(voting_results);
|
||||
voting_results = NULL;
|
||||
}
|
||||
|
||||
if (tally != NULL)
|
||||
{
|
||||
fclose(tally);
|
||||
tally = NULL;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES; i++)
|
||||
if (trustee_states[i].bytes != NULL)
|
||||
{
|
||||
free((void *)trustee_states[i].bytes);
|
||||
trustee_states[i].bytes = NULL;
|
||||
}
|
||||
|
||||
if (joint_key.bytes != NULL)
|
||||
{
|
||||
free((void *)joint_key.bytes);
|
||||
joint_key.bytes = NULL;
|
||||
}
|
||||
|
||||
Crypto_parameters_free();
|
||||
|
||||
if (ok)
|
||||
return EXIT_SUCCESS;
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
FILE *fmkstemps(char const *template, const char *mode)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
int result_fd = -1;
|
||||
FILE *result = NULL;
|
||||
|
||||
// Duplicate the template. It needs to be mutable for mkstemp.
|
||||
char *template_mut = strdup(template);
|
||||
if (template_mut == NULL)
|
||||
ok = false;
|
||||
|
||||
// Create and open the temporary file
|
||||
if (ok)
|
||||
{
|
||||
result_fd = mkstemp(template_mut);
|
||||
if (-1 == result_fd)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Convert the file descriptor to a FILE*
|
||||
if (ok)
|
||||
{
|
||||
result = fdopen(result_fd, mode);
|
||||
if (result == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Free the duplicated template
|
||||
if (template_mut != NULL)
|
||||
{
|
||||
free(template_mut);
|
||||
template_mut = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <electionguard/decryption/coordinator.h>
|
||||
#include <electionguard/decryption/trustee.h>
|
||||
|
||||
#include "main_decryption.h"
|
||||
#include "main_params.h"
|
||||
|
||||
static bool initialize_coordinator(void);
|
||||
|
||||
static bool initialize_trustees(struct trustee_state *trustee_states);
|
||||
|
||||
static bool tally_voting_records(FILE *in);
|
||||
|
||||
static bool decrypt_tally_shares(void);
|
||||
|
||||
static bool decrypt_tally_decryption_fragments(
|
||||
bool *requests_present, struct decryption_fragments_request *requests);
|
||||
|
||||
static Decryption_Trustee trustees[MAX_TRUSTEES];
|
||||
static Decryption_Coordinator coordinator;
|
||||
|
||||
bool decryption(FILE *in, FILE *out, struct trustee_state *trustee_states)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (ok)
|
||||
ok = initialize_coordinator();
|
||||
|
||||
if (ok)
|
||||
ok = initialize_trustees(trustee_states);
|
||||
|
||||
if (ok)
|
||||
ok = tally_voting_records(in);
|
||||
|
||||
if (ok)
|
||||
ok = decrypt_tally_shares();
|
||||
|
||||
struct decryption_fragments_request requests[MAX_TRUSTEES];
|
||||
bool request_present[MAX_TRUSTEES];
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES; i++)
|
||||
requests[i] = (struct decryption_fragments_request){.bytes = NULL};
|
||||
|
||||
if (ok)
|
||||
{
|
||||
struct Decryption_Coordinator_all_shares_received_r result =
|
||||
Decryption_Coordinator_all_shares_received(coordinator);
|
||||
|
||||
if (result.status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
for (uint32_t i = 0; i < result.num_trustees; i++)
|
||||
requests[i] = result.requests[i],
|
||||
request_present[i] = result.request_present[i];
|
||||
}
|
||||
|
||||
if (ok)
|
||||
ok = decrypt_tally_decryption_fragments(request_present, requests);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
uint32_t tally_results[NUM_SELECTIONS];
|
||||
enum Decryption_Coordinator_status status =
|
||||
Decryption_Coordinator_all_fragments_received(coordinator, out, tally_results);
|
||||
|
||||
if (status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < NUM_SELECTIONS; i++)
|
||||
{
|
||||
printf("Tally %u results = %u\n", i, tally_results[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES; i++)
|
||||
if (request_present[i])
|
||||
{
|
||||
free((void *)requests[i].bytes);
|
||||
requests[i].bytes = NULL;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES; i++)
|
||||
if (trustees[i] != NULL)
|
||||
{
|
||||
Decryption_Trustee_free(trustees[i]);
|
||||
trustees[i] = NULL;
|
||||
}
|
||||
|
||||
if (coordinator != NULL)
|
||||
{
|
||||
Decryption_Coordinator_free(coordinator);
|
||||
coordinator = NULL;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool initialize_coordinator(void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
struct Decryption_Coordinator_new_r result =
|
||||
Decryption_Coordinator_new(NUM_TRUSTEES, THRESHOLD);
|
||||
|
||||
if (result.status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
coordinator = result.coordinator;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool initialize_trustees(struct trustee_state *trustee_states)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES && ok; i++)
|
||||
{
|
||||
struct Decryption_Trustee_new_r result = Decryption_Trustee_new(
|
||||
NUM_TRUSTEES, THRESHOLD, NUM_SELECTIONS, trustee_states[i], BASE_HASH_CODE);
|
||||
|
||||
if (result.status != DECRYPTION_TRUSTEE_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
trustees[i] = result.decryptor;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool tally_voting_records(FILE *in)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES && ok; i++)
|
||||
{
|
||||
int seek_status = fseek(in, 0L, SEEK_SET);
|
||||
if (seek_status != 0)
|
||||
ok = false;
|
||||
|
||||
if (ok)
|
||||
{
|
||||
enum Decryption_Trustee_status status =
|
||||
Decryption_Trustee_tally_voting_record(trustees[i], in);
|
||||
|
||||
if (status != DECRYPTION_TRUSTEE_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool decrypt_tally_shares(void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
for (uint32_t i = 0; i < DECRYPTING_TRUSTEES && ok; i++)
|
||||
{
|
||||
struct decryption_share share = {.bytes = NULL};
|
||||
|
||||
{
|
||||
struct Decryption_Trustee_compute_share_r result =
|
||||
Decryption_Trustee_compute_share(trustees[i]);
|
||||
|
||||
if (result.status != DECRYPTION_TRUSTEE_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
share = result.share;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
enum Decryption_Coordinator_status status =
|
||||
Decryption_Coordinator_receive_share(coordinator, share);
|
||||
if (status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (share.bytes != NULL)
|
||||
{
|
||||
free((void *)share.bytes);
|
||||
share.bytes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool decrypt_tally_decryption_fragments(
|
||||
bool *requests_present, struct decryption_fragments_request *requests)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES && ok; i++)
|
||||
{
|
||||
if (requests_present[i])
|
||||
{
|
||||
struct decryption_fragments decryption_fragments = {.bytes = NULL};
|
||||
|
||||
{
|
||||
struct Decryption_Trustee_compute_fragments_r result =
|
||||
Decryption_Trustee_compute_fragments(trustees[i],
|
||||
requests[i]);
|
||||
|
||||
if (result.status != DECRYPTION_TRUSTEE_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
decryption_fragments = result.fragments;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
enum Decryption_Coordinator_status status =
|
||||
Decryption_Coordinator_receive_fragments(
|
||||
coordinator, decryption_fragments);
|
||||
|
||||
if (status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (decryption_fragments.bytes != NULL)
|
||||
{
|
||||
free((void *)decryption_fragments.bytes);
|
||||
decryption_fragments.bytes = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef __MAIN_DECRYPTION_H__
|
||||
#define __MAIN_DECRYPTION_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <electionguard/crypto.h>
|
||||
#include <electionguard/max_values.h>
|
||||
#include <electionguard/trustee_state.h>
|
||||
|
||||
bool decryption(FILE *in, FILE *out, struct trustee_state *trustee_states);
|
||||
|
||||
#endif /* __MAIN_DECRYPTION_H__ */
|
|
@ -1,320 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "main_keyceremony.h"
|
||||
#include "main_params.h"
|
||||
|
||||
// Initialize
|
||||
static bool initialize_coordinator(void);
|
||||
static bool initialize_trustees(void);
|
||||
|
||||
// Key Generation
|
||||
static bool generate_keys(void);
|
||||
static struct all_keys_received_message receive_keys(void);
|
||||
|
||||
// Share Generation
|
||||
static bool generate_shares(struct all_keys_received_message all_keys_received);
|
||||
static struct all_shares_received_message receive_shares(void);
|
||||
|
||||
// Verification
|
||||
static bool
|
||||
verify_shares(struct all_shares_received_message all_shares_received);
|
||||
static struct joint_public_key publish_joint_key(void);
|
||||
|
||||
// Export trustees state
|
||||
static bool export_trustee_states(struct trustee_state *trustee_states);
|
||||
|
||||
// Global state
|
||||
static KeyCeremony_Coordinator coordinator;
|
||||
static KeyCeremony_Trustee trustees[MAX_TRUSTEES];
|
||||
|
||||
bool key_ceremony(struct joint_public_key *joint_key,
|
||||
struct trustee_state *trustee_states)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
// Initialize
|
||||
|
||||
if (ok)
|
||||
ok = initialize_coordinator();
|
||||
|
||||
if (ok)
|
||||
ok = initialize_trustees();
|
||||
|
||||
// Key Ceremony
|
||||
|
||||
if (ok)
|
||||
ok = generate_keys();
|
||||
|
||||
struct all_keys_received_message all_keys_received = {.bytes = NULL};
|
||||
|
||||
if (ok)
|
||||
{
|
||||
all_keys_received = receive_keys();
|
||||
if (all_keys_received.bytes == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Share Generation
|
||||
|
||||
if (ok)
|
||||
ok = generate_shares(all_keys_received);
|
||||
|
||||
struct all_shares_received_message all_shares_received = {.bytes = NULL};
|
||||
|
||||
if (ok)
|
||||
{
|
||||
all_shares_received = receive_shares();
|
||||
if (all_shares_received.bytes == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Verification
|
||||
|
||||
if (ok)
|
||||
ok = verify_shares(all_shares_received);
|
||||
|
||||
*joint_key = (struct joint_public_key){.bytes = NULL};
|
||||
|
||||
if (ok)
|
||||
{
|
||||
*joint_key = publish_joint_key();
|
||||
if (joint_key->bytes == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Export trustee state
|
||||
|
||||
if (ok)
|
||||
ok = export_trustee_states(trustee_states);
|
||||
|
||||
// Cleanup
|
||||
|
||||
if (all_shares_received.bytes != NULL)
|
||||
{
|
||||
free((void *)all_shares_received.bytes);
|
||||
all_shares_received.bytes = NULL;
|
||||
}
|
||||
|
||||
if (all_keys_received.bytes != NULL)
|
||||
{
|
||||
free((void *)all_keys_received.bytes);
|
||||
all_keys_received.bytes = NULL;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES; i++)
|
||||
{
|
||||
if (trustees[i] != NULL)
|
||||
KeyCeremony_Trustee_free(trustees[i]);
|
||||
}
|
||||
|
||||
if (coordinator != NULL)
|
||||
KeyCeremony_Coordinator_free(coordinator);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool initialize_coordinator(void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
struct KeyCeremony_Coordinator_new_r result =
|
||||
KeyCeremony_Coordinator_new(NUM_TRUSTEES, THRESHOLD);
|
||||
|
||||
if (result.status != KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
coordinator = result.coordinator;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool initialize_trustees(void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES && ok; i++)
|
||||
{
|
||||
struct KeyCeremony_Trustee_new_r result =
|
||||
KeyCeremony_Trustee_new(NUM_TRUSTEES, THRESHOLD, i);
|
||||
|
||||
if (result.status != KEYCEREMONY_TRUSTEE_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
trustees[i] = result.trustee;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool generate_keys(void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES && ok; i++)
|
||||
{
|
||||
struct key_generated_message key_generated = {.bytes = NULL};
|
||||
|
||||
{
|
||||
struct KeyCeremony_Trustee_generate_key_r result =
|
||||
KeyCeremony_Trustee_generate_key(trustees[i], BASE_HASH_CODE);
|
||||
|
||||
if (result.status != KEYCEREMONY_TRUSTEE_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
key_generated = result.message;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
enum KeyCeremony_Coordinator_status status =
|
||||
KeyCeremony_Coordinator_receive_key_generated(coordinator,
|
||||
key_generated);
|
||||
if (status != KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (key_generated.bytes != NULL)
|
||||
{
|
||||
free((void *)key_generated.bytes);
|
||||
key_generated.bytes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
struct all_keys_received_message receive_keys(void)
|
||||
{
|
||||
struct all_keys_received_message message = {.bytes = NULL};
|
||||
|
||||
struct KeyCeremony_Coordinator_all_keys_received_r result =
|
||||
KeyCeremony_Coordinator_all_keys_received(coordinator);
|
||||
|
||||
if (result.status == KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
message = result.message;
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
bool generate_shares(struct all_keys_received_message all_keys_received)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES && ok; i++)
|
||||
{
|
||||
struct shares_generated_message shares_generated = {.bytes = NULL};
|
||||
|
||||
{
|
||||
struct KeyCeremony_Trustee_generate_shares_r result =
|
||||
KeyCeremony_Trustee_generate_shares(trustees[i],
|
||||
all_keys_received);
|
||||
|
||||
if (result.status != KEYCEREMONY_TRUSTEE_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
{
|
||||
shares_generated = result.message;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
enum KeyCeremony_Coordinator_status cstatus =
|
||||
KeyCeremony_Coordinator_receive_shares_generated(
|
||||
coordinator, shares_generated);
|
||||
if (cstatus != KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (shares_generated.bytes != NULL)
|
||||
{
|
||||
free((void *)shares_generated.bytes);
|
||||
shares_generated.bytes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
struct all_shares_received_message receive_shares()
|
||||
{
|
||||
struct all_shares_received_message message = {.bytes = NULL};
|
||||
|
||||
struct KeyCeremony_Coordinator_all_shares_received_r result =
|
||||
KeyCeremony_Coordinator_all_shares_received(coordinator);
|
||||
|
||||
if (result.status == KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
message = result.message;
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
bool verify_shares(struct all_shares_received_message all_shares_received)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES && ok; i++)
|
||||
{
|
||||
struct shares_verified_message shares_verified;
|
||||
|
||||
{
|
||||
struct KeyCeremony_Trustee_verify_shares_r result =
|
||||
KeyCeremony_Trustee_verify_shares(trustees[i],
|
||||
all_shares_received);
|
||||
if (result.status != KEYCEREMONY_TRUSTEE_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
shares_verified = result.message;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
enum KeyCeremony_Coordinator_status status =
|
||||
KeyCeremony_Coordinator_receive_shares_verified(
|
||||
coordinator, shares_verified);
|
||||
if (status != KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (shares_verified.bytes != NULL)
|
||||
{
|
||||
free((void *)shares_verified.bytes);
|
||||
shares_verified.bytes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
struct joint_public_key publish_joint_key(void)
|
||||
{
|
||||
struct joint_public_key key = {.bytes = NULL};
|
||||
|
||||
struct KeyCeremony_Coordinator_publish_joint_key_r cresult =
|
||||
KeyCeremony_Coordinator_publish_joint_key(coordinator);
|
||||
|
||||
if (cresult.status == KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
key = cresult.key;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static bool export_trustee_states(struct trustee_state *trustee_states)
|
||||
{
|
||||
|
||||
bool ok = true;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES && ok; i++)
|
||||
{
|
||||
struct KeyCeremony_Trustee_export_state_r result =
|
||||
KeyCeremony_Trustee_export_state(trustees[i]);
|
||||
|
||||
if (result.status != KEYCEREMONY_TRUSTEE_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
trustee_states[i] = result.state;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef __MAIN_KEY_CEREMONY_H__
|
||||
#define __MAIN_KEY_CEREMONY_H__
|
||||
|
||||
#include <electionguard/keyceremony/coordinator.h>
|
||||
#include <electionguard/keyceremony/messages.h>
|
||||
#include <electionguard/keyceremony/trustee.h>
|
||||
|
||||
/* Carry out the key ceremony phase of an election, storing the joint
|
||||
key and trustee_states in the provided pointers. */
|
||||
bool key_ceremony(struct joint_public_key *joint_key,
|
||||
struct trustee_state *trustee_states);
|
||||
|
||||
#endif /* __MAIN_KEY_CEREMONY_H__ */
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef __MAIN_PARAMS_H__
|
||||
#define __MAIN_PARAMS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <electionguard/crypto.h>
|
||||
|
||||
extern uint32_t const NUM_TRUSTEES;
|
||||
extern uint32_t const THRESHOLD;
|
||||
extern uint32_t const NUM_ENCRYPTERS;
|
||||
extern uint32_t const NUM_SELECTIONS;
|
||||
extern uint32_t const DECRYPTING_TRUSTEES;
|
||||
extern raw_hash BASE_HASH_CODE;
|
||||
|
||||
#endif /* __MAIN_PARAMS_H__ */
|
|
@ -1,235 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <electionguard/voting/tracker.h>
|
||||
|
||||
#include "electionguard/voting/encrypter.h"
|
||||
#include "main_params.h"
|
||||
#include "main_voting.h"
|
||||
|
||||
static bool initialize_encrypters(struct joint_public_key joint_key);
|
||||
|
||||
static bool initialize_coordinator(void);
|
||||
|
||||
static bool simulate_random_votes(uint32_t encrypter_ix, uint64_t num_ballots);
|
||||
|
||||
static Voting_Encrypter *encrypters;
|
||||
static Voting_Coordinator coordinator;
|
||||
|
||||
bool voting(struct joint_public_key joint_key, FILE *out)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (ok)
|
||||
{
|
||||
encrypters = malloc(NUM_ENCRYPTERS * sizeof(Voting_Encrypter));
|
||||
if (encrypters == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
ok = initialize_encrypters(joint_key);
|
||||
|
||||
if (ok)
|
||||
ok = initialize_coordinator();
|
||||
|
||||
if (ok)
|
||||
{
|
||||
for (uint32_t i = 0; i < NUM_ENCRYPTERS && ok; i++)
|
||||
ok = simulate_random_votes(i, 2);
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
enum Voting_Coordinator_status status =
|
||||
Voting_Coordinator_export_ballots(coordinator, out);
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (coordinator != NULL)
|
||||
{
|
||||
Voting_Coordinator_free(coordinator);
|
||||
coordinator = NULL;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < NUM_ENCRYPTERS; i++)
|
||||
if (encrypters != NULL && encrypters[i] != NULL)
|
||||
{
|
||||
Voting_Encrypter_free(encrypters[i]);
|
||||
encrypters[i] = NULL;
|
||||
}
|
||||
|
||||
if (encrypters != NULL)
|
||||
{
|
||||
free(encrypters);
|
||||
encrypters = NULL;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool initialize_encrypters(struct joint_public_key joint_key)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
uint8_t id_buf[1];
|
||||
struct uid uid = {
|
||||
.len = 1,
|
||||
.bytes = id_buf,
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < NUM_ENCRYPTERS && ok; i++)
|
||||
{
|
||||
id_buf[0] = i;
|
||||
struct Voting_Encrypter_new_r result = Voting_Encrypter_new(
|
||||
uid, joint_key, NUM_SELECTIONS, BASE_HASH_CODE);
|
||||
|
||||
if (result.status != VOTING_ENCRYPTER_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
encrypters[i] = result.encrypter;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool initialize_coordinator(void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
struct Voting_Coordinator_new_r result =
|
||||
Voting_Coordinator_new(NUM_SELECTIONS);
|
||||
|
||||
if (result.status != VOTING_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
coordinator = result.coordinator;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool random_bit() { return 1 & rand(); }
|
||||
|
||||
static int32_t fill_random_ballot(bool *selections)
|
||||
{
|
||||
uint32_t selected_count = 0;
|
||||
for (uint32_t i = 0; i < NUM_SELECTIONS; i++)
|
||||
{
|
||||
if (random_bit())
|
||||
{
|
||||
selections[i] = 1;
|
||||
selected_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
selections[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("vote created ");
|
||||
for (uint32_t i = 0; i < NUM_SELECTIONS; i++)
|
||||
{
|
||||
printf("%d ", selections[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return selected_count;
|
||||
}
|
||||
|
||||
bool simulate_random_votes(uint32_t encrypter_ix, uint64_t num_ballots)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
Voting_Encrypter const encrypter = encrypters[encrypter_ix];
|
||||
|
||||
for (uint64_t i = 0; i < num_ballots && ok; i++)
|
||||
{
|
||||
bool selections[MAX_SELECTIONS];
|
||||
|
||||
// we're assuming that the returned number of true selections for this ballot
|
||||
// is the the correct expected number for this ballot style in order to encrypt it
|
||||
uint32_t num_selected = fill_random_ballot(selections);
|
||||
|
||||
struct register_ballot_message message = {.bytes = NULL};
|
||||
struct ballot_tracker tracker = {.bytes = NULL};
|
||||
struct ballot_identifier identifier = {.bytes = NULL};
|
||||
|
||||
// Encrypt the ballot
|
||||
if (ok)
|
||||
{
|
||||
struct Voting_Encrypter_encrypt_ballot_r result =
|
||||
Voting_Encrypter_encrypt_ballot(encrypter, selections, num_selected);
|
||||
|
||||
if (result.status != VOTING_ENCRYPTER_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
{
|
||||
message = result.message;
|
||||
tracker = result.tracker;
|
||||
identifier = result.id;
|
||||
}
|
||||
}
|
||||
|
||||
// Print the tracker
|
||||
if (ok)
|
||||
{
|
||||
char *tracker_string = display_ballot_tracker(tracker);
|
||||
int status = puts(tracker_string);
|
||||
free(tracker_string);
|
||||
if (status == EOF)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Register the ballot
|
||||
if (ok)
|
||||
{
|
||||
enum Voting_Coordinator_status status =
|
||||
Voting_Coordinator_register_ballot(coordinator, message);
|
||||
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Randomly cast or spoil the ballot
|
||||
if (ok)
|
||||
{
|
||||
enum Voting_Coordinator_status status;
|
||||
|
||||
if (random_bit())
|
||||
{
|
||||
status =
|
||||
Voting_Coordinator_cast_ballot(coordinator, identifier);
|
||||
printf("Cast\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
status =
|
||||
Voting_Coordinator_spoil_ballot(coordinator, identifier);
|
||||
printf("Spoiled\n");
|
||||
}
|
||||
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (message.bytes != NULL)
|
||||
{
|
||||
free((void *)message.bytes);
|
||||
message.bytes = NULL;
|
||||
}
|
||||
|
||||
if (tracker.bytes != NULL)
|
||||
{
|
||||
free((void *)tracker.bytes);
|
||||
message.bytes = NULL;
|
||||
}
|
||||
|
||||
if (identifier.bytes != NULL)
|
||||
{
|
||||
free((void *)identifier.bytes);
|
||||
identifier.bytes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef __MAIN_VOTING_H__
|
||||
#define __MAIN_VOTING_H__
|
||||
|
||||
#include <electionguard/voting/coordinator.h>
|
||||
#include <electionguard/voting/encrypter.h>
|
||||
|
||||
bool voting(struct joint_public_key joint_key, FILE *out);
|
||||
|
||||
#endif /* __MAIN_VOTING_H__ */
|
|
@ -0,0 +1,21 @@
|
|||
API
|
||||
===
|
||||
|
||||
The API is a higher level abstraction around the underlying
|
||||
Electionguard process that is designed to automate the logical
|
||||
functions of executing an election.
|
||||
|
||||
Create Election
|
||||
---------------
|
||||
|
||||
Encrypt Ballot
|
||||
--------------
|
||||
|
||||
Load Ballots
|
||||
------------
|
||||
|
||||
Record Ballots
|
||||
--------------
|
||||
|
||||
Tally Votes
|
||||
-----------
|
|
@ -7,13 +7,17 @@
|
|||
#include <electionguard/keyceremony/trustee.h>
|
||||
|
||||
/**
|
||||
* Perform all the steps necessary to initialize a new election from the given config.
|
||||
* Perform the key ceremony, return joint key assigned to config and assign the trustee_states in the provided pointer. */
|
||||
* Perform all the steps necessary to initialize
|
||||
* a new election from the given config.
|
||||
* Perform the key ceremony, return joint key assigned
|
||||
* to config and assign the trustee_states in the provided pointer.
|
||||
*/
|
||||
bool API_CreateElection(struct api_config *config,
|
||||
struct trustee_state *trustee_states);
|
||||
|
||||
/**
|
||||
* Free the bytes allocated by CreateElection */
|
||||
* Free the bytes allocated by CreateElection
|
||||
*/
|
||||
void API_CreateElection_free(struct joint_public_key joint_key,
|
||||
struct trustee_state *trustee_states);
|
||||
|
||||
|
|
|
@ -7,17 +7,38 @@
|
|||
|
||||
/**
|
||||
* Encrypts the ballot selections given as an array of booleans,
|
||||
* the serialized joint public key, and the current number of ballots. */
|
||||
* the serialized joint public key, and the current number of ballots.
|
||||
* @param uint8_t *selections_byte_array a byte array representing the selections on the ballot
|
||||
* @param uint32_t expected_num_selected the expected number of true values in *selections_byte_array
|
||||
* @param api_config config the election configuration
|
||||
* @param char *external_identifier an arbitrary value meaninful to the library consumer that is associated
|
||||
* with each encrypted ballot
|
||||
* @param char *export_path
|
||||
* @param char *filename
|
||||
* @param char **output_filename return value of the generated file.
|
||||
* when successful, caller is responsible for Freeing output_filename
|
||||
* @param char **tracker_string representation of the ballot's tracking Id after encryption
|
||||
*/
|
||||
bool API_EncryptBallot(uint8_t *selections_byte_array,
|
||||
uint32_t expected_num_selected,
|
||||
struct api_config config,
|
||||
uint64_t *current_num_ballots,
|
||||
uint64_t *identifier,
|
||||
char *external_identifier,
|
||||
struct register_ballot_message *encrypted_ballot_message,
|
||||
char *export_path,
|
||||
char *filename,
|
||||
char **output_filename,
|
||||
char **tracker_string);
|
||||
|
||||
// TODO: API endpoint that does not use the file system
|
||||
|
||||
/**
|
||||
* Free the bytes allocated by EncryptBallot */
|
||||
* Soft delete a file by renaming it with the current system time
|
||||
*/
|
||||
bool API_EncryptBallot_soft_delete_file(char *export_path, char *filename);
|
||||
|
||||
/**
|
||||
* Free the bytes allocated by EncryptBallot
|
||||
*/
|
||||
void API_EncryptBallot_free(struct register_ballot_message message,
|
||||
char *tracker_string);
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef __API_LOAD_BALLOTS_H__
|
||||
#define __API_LOAD_BALLOTS_H__
|
||||
|
||||
#include <electionguard/voting/coordinator.h>
|
||||
|
||||
typedef enum API_LoadBallots_status
|
||||
{
|
||||
API_LOADBALLOTS_SUCCESS,
|
||||
API_LOADBALLOTS_INITIALIZATION_ERROR,
|
||||
API_LOADBALLOTS_INSUFFICIENT_MEMORY,
|
||||
API_LOADBALLOTS_INVALID_BALLOT_INDEX,
|
||||
API_LOADBALLOTS_END_OF_FILE,
|
||||
API_LOADBALLOTS_TIMED_OUT,
|
||||
API_LOADBALLOTS_IO_ERROR,
|
||||
API_LOADBALLOTS_SERIALIZE_ERROR,
|
||||
API_LOADBALLOTS_DESERIALIZE_ERROR,
|
||||
} API_LoadBallots_status;
|
||||
|
||||
/**
|
||||
* Load a range of ballots from a specified file on the file system
|
||||
*/
|
||||
API_LoadBallots_status API_LoadBallots(
|
||||
uint64_t start_index,
|
||||
uint64_t count,
|
||||
uint32_t num_selections,
|
||||
char *import_filepath,
|
||||
char **out_external_identifiers,
|
||||
struct register_ballot_message *out_encrypted_ballots);
|
||||
|
||||
/**
|
||||
* Free the bytes allocated by LoadBallots
|
||||
*/
|
||||
API_LoadBallots_status API_LoadBallots_free(char *output_filename);
|
||||
|
||||
#endif /* __API_LOAD_BALLOTS_H__ */
|
|
@ -7,13 +7,30 @@
|
|||
/**
|
||||
* Performs Ballot Registration and Recording Cast/Spoil for the ballot in bulk.
|
||||
* Operates on the array of encrypted ballot messages, the array of casted ballot ids,
|
||||
* and the array of spoiled ballot ids. */
|
||||
* and the array of spoiled ballot ids.
|
||||
* uint32_t num_selections,
|
||||
* @param uint32_t num_cast_ballots,
|
||||
* @param uint32_t num_spoil_ballots,
|
||||
* @param uint64_t total_num_ballots,
|
||||
* @param char *cast_ids array pointing to the cast id's in external_identifiers
|
||||
* @param char *spoil_ids array pointing to the spoiled id's in external_identifiers
|
||||
* @param char *external_identifiers index-based array pointing to the external identifiers
|
||||
* associated with encrypted_ballots
|
||||
* @param struct register_ballot_message *encrypted_ballots array pointing to serialized encrypted ballots
|
||||
* @param char *export_path path to export the ballots file for use when decrypting
|
||||
* @param char *filename_prefix previx to use on the file name
|
||||
* @param char **output_filename return value of the generated file.
|
||||
* when successful, caller is responsible for Freeing output_filename
|
||||
* @param char **casted_tracker_strings return value of the trackers that were cast
|
||||
* @param char **spoiled_tracker_strings return value of the trackers that were spoiled
|
||||
*/
|
||||
bool API_RecordBallots(uint32_t num_selections,
|
||||
uint32_t num_cast_ballots,
|
||||
uint32_t num_spoil_ballots,
|
||||
uint64_t total_num_ballots,
|
||||
uint64_t *cast_ids,
|
||||
uint64_t *spoil_ids,
|
||||
uint32_t total_num_ballots,
|
||||
char **cast_ids,
|
||||
char **spoil_ids,
|
||||
char **external_identifiers,
|
||||
struct register_ballot_message *encrypted_ballots,
|
||||
char *export_path,
|
||||
char *filename_prefix,
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
#include <electionguard/decryption/trustee.h>
|
||||
|
||||
/**
|
||||
* Perform all the steps necessary to tally the encypted ballots file and decrypt the tallies. */
|
||||
* Perform all the steps necessary to tally the encypted ballots file and decrypt the tallies.
|
||||
* * @param char **output_filename return value of the generated file.
|
||||
* when successful, caller is responsible for Freeing output_filename
|
||||
*/
|
||||
bool API_TallyVotes(struct api_config config,
|
||||
struct trustee_state *trustee_states,
|
||||
uint32_t num_decrypting_trustees,
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
FILE *File_new(char const *template);
|
||||
|
||||
void File_close(FILE *file);
|
||||
|
||||
void File_seek(FILE *file);
|
|
@ -7,6 +7,11 @@
|
|||
// constant expressions, allowing us to use them as array sizes, but
|
||||
// they are not compiled away, making it easier to debug.
|
||||
|
||||
enum MAX_EXTERNAL_IDENIFIER_LENGTH_e
|
||||
{
|
||||
MAX_EXTERNAL_ID_LENGTH = 4095
|
||||
};
|
||||
|
||||
/** The maximum number of total trustees. */
|
||||
enum MAX_TRUSTEES_e
|
||||
{
|
||||
|
@ -14,16 +19,27 @@ enum MAX_TRUSTEES_e
|
|||
};
|
||||
|
||||
/**
|
||||
* The maximum number of ballots that can be cast by a voting single
|
||||
* coordinator. */
|
||||
* The maximum number of ballots that can be
|
||||
* cast at one time by a voting single coordinator.
|
||||
*/
|
||||
enum MAX_BALLOTS_e
|
||||
{
|
||||
MAX_BALLOTS = 1000
|
||||
/** The Maximum ballots for an election
|
||||
* that one Voting Coordinator can track
|
||||
*/
|
||||
MAX_BALLOTS = 10000,
|
||||
|
||||
/** The Maximum ballots that can be passed
|
||||
* to a Voting Coordinator for
|
||||
* Registration, Casting, or Spoiling at one time
|
||||
*/
|
||||
MAX_BALLOT_PAYLOAD = 2000
|
||||
};
|
||||
|
||||
/**
|
||||
* The maximum number of selections that can be present for a single
|
||||
* contest. */
|
||||
* The maximum number of selections that
|
||||
* can be present for a single contest.
|
||||
*/
|
||||
enum MAX_SELECTIONS_e
|
||||
{
|
||||
MAX_SELECTIONS = 1000
|
||||
|
|
|
@ -23,6 +23,9 @@ enum Voting_Coordinator_status
|
|||
VOTING_COORDINATOR_IO_ERROR,
|
||||
VOTING_COORDINATOR_SERIALIZE_ERROR,
|
||||
VOTING_COORDINATOR_DESERIALIZE_ERROR,
|
||||
VOTING_COORDINATOR_INVALID_BALLOT_INDEX,
|
||||
VOTING_COORDINATOR_END_OF_FILE,
|
||||
VOTING_COORDINATOR_ERROR_ALREADY_EXISTS,
|
||||
};
|
||||
|
||||
/************************** INITIALIZATION & FREEING ***************************/
|
||||
|
@ -31,7 +34,19 @@ enum Voting_Coordinator_status
|
|||
// formats so that we can validate that the ballots we receive are
|
||||
// well-formed?
|
||||
|
||||
/** Create a new voting coordinator. */
|
||||
/**
|
||||
* Create a new voting coordinator.
|
||||
*
|
||||
* This component mutates the state of votes by handling loading ballots,
|
||||
* registering them, marking them as cast, or spoiled, and caching the state.
|
||||
*
|
||||
* The Voting Coordinator can track the state of:
|
||||
* -- MAX_BALLOTS it can hold in memory and
|
||||
* -- MAX_BALLOT_PAYLOAD selections and trackers it can buffer before writing to cache
|
||||
*
|
||||
* @param uint32_t num_selections the total number of selections
|
||||
* available on the ballot
|
||||
*/
|
||||
struct Voting_Coordinator_new_r Voting_Coordinator_new(uint32_t num_selections);
|
||||
|
||||
struct Voting_Coordinator_new_r
|
||||
|
@ -40,31 +55,46 @@ struct Voting_Coordinator_new_r
|
|||
Voting_Coordinator coordinator;
|
||||
};
|
||||
|
||||
/** Free a ballot box. */
|
||||
/**
|
||||
* Free the Voting Coordinator
|
||||
*
|
||||
* Clears the component state including the tracked state of a ballot box
|
||||
* and the buffered selections and trackers being held in memory.
|
||||
*/
|
||||
void Voting_Coordinator_free(Voting_Coordinator coordinator);
|
||||
|
||||
/**
|
||||
* Clear the selections buffer and drop instance references to any external id's
|
||||
*/
|
||||
enum Voting_Coordinator_status Voting_Coordinator_clear_buffer(Voting_Coordinator coordinator);
|
||||
|
||||
/****************** REGISTERING, CASTING & SPOILING BALLOTS *******************/
|
||||
|
||||
/**
|
||||
* Register a ballot with the coordinator so that it may be cast or
|
||||
* spoiled. */
|
||||
* spoiled.
|
||||
*/
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_register_ballot(Voting_Coordinator coordinator,
|
||||
struct register_ballot_message message);
|
||||
char *external_identifier,
|
||||
struct register_ballot_message message,
|
||||
char **out_ballot_tracker);
|
||||
|
||||
/** Mark the ballot specified by ballot_id as cast. */
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_cast_ballot(Voting_Coordinator coordinator,
|
||||
struct ballot_identifier ballot_id);
|
||||
char *external_identifier,
|
||||
char **out_tracker);
|
||||
|
||||
/** Mark the ballot specified by ballot_id as spoiled. */
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_spoil_ballot(Voting_Coordinator coordinator,
|
||||
struct ballot_identifier ballot_id);
|
||||
char *external_identifier,
|
||||
char **out_tracker);
|
||||
|
||||
/** Get the tracker string for the given ballot_id */
|
||||
char *Voting_Coordinator_get_tracker(Voting_Coordinator coordinator,
|
||||
struct ballot_identifier ballot_id);
|
||||
char *external_identifier);
|
||||
|
||||
/***************************** EXPORTING BALLOTS ******************************/
|
||||
|
||||
|
@ -72,8 +102,34 @@ char *Voting_Coordinator_get_tracker(Voting_Coordinator coordinator,
|
|||
|
||||
// @todo jwaksbaum What format is it writing in?
|
||||
|
||||
/** Write all of the cast and spoiled ballots to out. */
|
||||
/**
|
||||
* Write all of the cast and spoiled ballots to out to the specified file.
|
||||
* Clears the Voting Coordinator buffer in the process
|
||||
*/
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_export_ballots(Voting_Coordinator coordinator, FILE *out);
|
||||
Voting_Coordinator_export_buffered_ballots(Voting_Coordinator coordinator, FILE *out);
|
||||
|
||||
/**
|
||||
* Import ballots from the specified file. Expects a file that was build
|
||||
* With the Voting Encrypter using the format:
|
||||
* <ballot_id> TAB <encrypted_ballot_message> \n
|
||||
*
|
||||
* @see Voting_Encrypter_write_ballot
|
||||
* @param Voting_Coordinator coordinator the voting coordinator instance
|
||||
* @param uint64_t start_index the start index to import form the file
|
||||
* @param uint64_t count the count of ballots to import
|
||||
* @param FILE *in the file to read
|
||||
* @param char **out_external_identifiers index-based array of external identifiers
|
||||
* @param register_ballot_message out_messages index-based collection of register ballot messages
|
||||
* @return Voting_Coordinator_status indicating success or failure
|
||||
*/
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_import_encrypted_ballots(Voting_Coordinator coordinator,
|
||||
uint64_t start_index,
|
||||
uint64_t count,
|
||||
uint32_t num_selections,
|
||||
FILE *in,
|
||||
char **out_external_identifiers,
|
||||
struct register_ballot_message *out_messages);
|
||||
|
||||
#endif /* __VOTING_COORDINATOR_H__ */
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#define __VOTING_ENCRYPTER_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <electionguard/crypto.h>
|
||||
#include <electionguard/voting/messages.h>
|
||||
|
@ -60,6 +62,7 @@ void Voting_Encrypter_free(Voting_Encrypter encrypter);
|
|||
* when done, ie. they own them. */
|
||||
struct Voting_Encrypter_encrypt_ballot_r
|
||||
Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter,
|
||||
char *external_identifier,
|
||||
bool const *selections,
|
||||
uint32_t expected_num_selected);
|
||||
|
||||
|
@ -70,6 +73,14 @@ struct Voting_Encrypter_encrypt_ballot_r
|
|||
struct ballot_tracker tracker;
|
||||
struct ballot_identifier id;
|
||||
};
|
||||
bool Validate_selections(bool const *selections, uint32_t num_selections, uint32_t expected_num_selected);
|
||||
bool Validate_selections(
|
||||
bool const *selections, uint32_t num_selections, uint32_t expected_num_selected);
|
||||
|
||||
/** Write a single ballot to out, using the format
|
||||
* <ballot_id> TAB <encrypted_ballot_message> \n
|
||||
*/
|
||||
enum Voting_Encrypter_status
|
||||
Voting_Encrypter_write_ballot(FILE *out, char *external_identifier,
|
||||
struct register_ballot_message *encrypted_ballot_message);
|
||||
|
||||
#endif /* __VOTING_ENCRYPTER_H__ */
|
||||
|
|
|
@ -40,4 +40,12 @@ struct ballot_identifier
|
|||
uint8_t const *bytes;
|
||||
};
|
||||
|
||||
struct external_identifier_message
|
||||
{
|
||||
uint64_t len;
|
||||
uint8_t const *bytes;
|
||||
};
|
||||
|
||||
bool Messages_are_equal(struct register_ballot_message *left_message, struct register_ballot_message *right_message);
|
||||
|
||||
#endif /* __VOTING_MESSAGES_H__ */
|
||||
|
|
4
lgtm.yml
4
lgtm.yml
|
@ -11,5 +11,5 @@ extraction:
|
|||
- cmake --version
|
||||
- cmake -S . -B build
|
||||
- cmake --build build
|
||||
- ElectionGuard_DIR="$PWD/build/ElectionGuard" cmake -S examples/simple -B simple_build
|
||||
- cmake --build simple_build --target simple
|
||||
- ElectionGuard_DIR="$PWD/build/ElectionGuard" cmake -S examples/api -B api_build
|
||||
- cmake --build api_build --target api
|
|
@ -27,7 +27,7 @@ static bool export_trustee_states(struct trustee_state *trustee_states);
|
|||
|
||||
// Global state
|
||||
static struct api_config api_config;
|
||||
static KeyCeremony_Coordinator coordinator;
|
||||
static KeyCeremony_Coordinator _keyceremony_coordinator;
|
||||
static KeyCeremony_Trustee trustees[MAX_TRUSTEES];
|
||||
|
||||
bool API_CreateElection(struct api_config *config,
|
||||
|
@ -121,8 +121,10 @@ bool API_CreateElection(struct api_config *config,
|
|||
KeyCeremony_Trustee_free(trustees[i]);
|
||||
}
|
||||
|
||||
if (coordinator != NULL)
|
||||
KeyCeremony_Coordinator_free(coordinator);
|
||||
// Key Ceremony Coordinator is only used in
|
||||
// this part of the workflow so free it
|
||||
if (_keyceremony_coordinator != NULL)
|
||||
KeyCeremony_Coordinator_free(_keyceremony_coordinator);
|
||||
|
||||
Crypto_parameters_free();
|
||||
|
||||
|
@ -132,12 +134,15 @@ bool API_CreateElection(struct api_config *config,
|
|||
void API_CreateElection_free(struct joint_public_key joint_key,
|
||||
struct trustee_state *trustee_states)
|
||||
{
|
||||
for (uint32_t i = 0; i < api_config.num_trustees; i++)
|
||||
if (trustee_states != NULL)
|
||||
{
|
||||
if (trustee_states[i].bytes != NULL)
|
||||
for (uint32_t i = 0; i < api_config.num_trustees; i++)
|
||||
{
|
||||
free((void *)trustee_states[i].bytes);
|
||||
trustee_states[i].bytes = NULL;
|
||||
if (trustee_states[i].bytes != NULL)
|
||||
{
|
||||
free((void *)trustee_states[i].bytes);
|
||||
trustee_states[i].bytes = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,7 +163,7 @@ bool initialize_coordinator(void)
|
|||
if (result.status != KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
coordinator = result.coordinator;
|
||||
_keyceremony_coordinator = result.coordinator;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
@ -200,8 +205,10 @@ bool generate_keys(void)
|
|||
if (ok)
|
||||
{
|
||||
enum KeyCeremony_Coordinator_status status =
|
||||
KeyCeremony_Coordinator_receive_key_generated(coordinator,
|
||||
key_generated);
|
||||
KeyCeremony_Coordinator_receive_key_generated(
|
||||
_keyceremony_coordinator,
|
||||
key_generated
|
||||
);
|
||||
if (status != KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
@ -221,7 +228,7 @@ struct all_keys_received_message receive_keys(void)
|
|||
struct all_keys_received_message message = {.bytes = NULL};
|
||||
|
||||
struct KeyCeremony_Coordinator_all_keys_received_r result =
|
||||
KeyCeremony_Coordinator_all_keys_received(coordinator);
|
||||
KeyCeremony_Coordinator_all_keys_received(_keyceremony_coordinator);
|
||||
|
||||
if (result.status == KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
message = result.message;
|
||||
|
@ -254,7 +261,7 @@ bool generate_shares(struct all_keys_received_message all_keys_received)
|
|||
{
|
||||
enum KeyCeremony_Coordinator_status cstatus =
|
||||
KeyCeremony_Coordinator_receive_shares_generated(
|
||||
coordinator, shares_generated);
|
||||
_keyceremony_coordinator, shares_generated);
|
||||
if (cstatus != KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
@ -274,7 +281,7 @@ struct all_shares_received_message receive_shares()
|
|||
struct all_shares_received_message message = {.bytes = NULL};
|
||||
|
||||
struct KeyCeremony_Coordinator_all_shares_received_r result =
|
||||
KeyCeremony_Coordinator_all_shares_received(coordinator);
|
||||
KeyCeremony_Coordinator_all_shares_received(_keyceremony_coordinator);
|
||||
|
||||
if (result.status == KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
message = result.message;
|
||||
|
@ -304,7 +311,7 @@ bool verify_shares(struct all_shares_received_message all_shares_received)
|
|||
{
|
||||
enum KeyCeremony_Coordinator_status status =
|
||||
KeyCeremony_Coordinator_receive_shares_verified(
|
||||
coordinator, shares_verified);
|
||||
_keyceremony_coordinator, shares_verified);
|
||||
if (status != KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
@ -324,7 +331,7 @@ struct joint_public_key publish_joint_key(void)
|
|||
struct joint_public_key key = {.bytes = NULL};
|
||||
|
||||
struct KeyCeremony_Coordinator_publish_joint_key_r cresult =
|
||||
KeyCeremony_Coordinator_publish_joint_key(coordinator);
|
||||
KeyCeremony_Coordinator_publish_joint_key(_keyceremony_coordinator);
|
||||
|
||||
if (cresult.status == KEYCEREMONY_COORDINATOR_SUCCESS)
|
||||
key = cresult.key;
|
||||
|
|
|
@ -2,22 +2,29 @@
|
|||
|
||||
#include <electionguard/api/encrypt_ballot.h>
|
||||
|
||||
#include <log.h>
|
||||
|
||||
#include "api/base_hash.h"
|
||||
#include "directory.h"
|
||||
#include "api/filename.h"
|
||||
#include "serialize/voting.h"
|
||||
#include "voting/num_ballots.h"
|
||||
|
||||
static bool initialize_encrypter(struct joint_public_key joint_key);
|
||||
static bool export_ballot(char *export_path, char *filename_prefix, char **output_filename, char *identifier,
|
||||
struct register_ballot_message *encrypted_ballot_message);
|
||||
|
||||
// Global state
|
||||
static struct api_config api_config;
|
||||
static Voting_Encrypter encrypter;
|
||||
static Voting_Encrypter _encrypter;
|
||||
|
||||
bool API_EncryptBallot(uint8_t *selections_byte_array,
|
||||
uint32_t expected_num_selected,
|
||||
struct api_config config,
|
||||
uint64_t *current_num_ballots,
|
||||
uint64_t *identifier,
|
||||
char *external_identifier,
|
||||
struct register_ballot_message *encrypted_ballot_message,
|
||||
char *export_path,
|
||||
char *filename_prefix,
|
||||
char **output_filename,
|
||||
char **tracker_string)
|
||||
{
|
||||
bool ok = true;
|
||||
|
@ -27,7 +34,6 @@ bool API_EncryptBallot(uint8_t *selections_byte_array,
|
|||
Crypto_parameters_new();
|
||||
api_config = config;
|
||||
create_base_hash_code(api_config);
|
||||
Voting_num_ballots = *current_num_ballots;
|
||||
|
||||
// Convert selections byte array to boolean array
|
||||
// And validate ballot selections before continuing
|
||||
|
@ -40,7 +46,9 @@ bool API_EncryptBallot(uint8_t *selections_byte_array,
|
|||
// Initialize Encrypter
|
||||
|
||||
if (ok)
|
||||
{
|
||||
ok = initialize_encrypter(api_config.joint_key);
|
||||
}
|
||||
|
||||
// Encrypt ballot
|
||||
|
||||
|
@ -48,9 +56,15 @@ bool API_EncryptBallot(uint8_t *selections_byte_array,
|
|||
.id = {.bytes = NULL},
|
||||
.tracker = {.bytes = NULL},
|
||||
};
|
||||
|
||||
if (ok)
|
||||
{
|
||||
result = Voting_Encrypter_encrypt_ballot(encrypter, selections, expected_num_selected);
|
||||
result = Voting_Encrypter_encrypt_ballot(
|
||||
_encrypter,
|
||||
external_identifier,
|
||||
selections,
|
||||
expected_num_selected
|
||||
);
|
||||
|
||||
if (result.status != VOTING_ENCRYPTER_SUCCESS)
|
||||
ok = false;
|
||||
|
@ -58,7 +72,7 @@ bool API_EncryptBallot(uint8_t *selections_byte_array,
|
|||
{
|
||||
*encrypted_ballot_message = result.message;
|
||||
|
||||
// Deserialize the id to get its ulong representation
|
||||
// Deserialize the id to get its representation
|
||||
struct ballot_identifier_rep id_rep;
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_READING,
|
||||
|
@ -67,17 +81,23 @@ bool API_EncryptBallot(uint8_t *selections_byte_array,
|
|||
.buf = (uint8_t *)result.id.bytes,
|
||||
};
|
||||
Serialize_read_ballot_identifier(&state, &id_rep);
|
||||
*identifier = id_rep.id;
|
||||
|
||||
// Convert tracker to string represntation
|
||||
*tracker_string = display_ballot_tracker(result.tracker);
|
||||
|
||||
// Voting_Encrypter_encrypt_ballot will increment the global Voting_num_ballots.
|
||||
// Update the *current_num_ballots param to have new value tracked by caller
|
||||
*current_num_ballots = Voting_num_ballots;
|
||||
*tracker_string = display_ballot_tracker(result.tracker);
|
||||
}
|
||||
}
|
||||
|
||||
// Export to file system
|
||||
|
||||
if (ok)
|
||||
ok = export_ballot(
|
||||
export_path,
|
||||
filename_prefix,
|
||||
output_filename,
|
||||
external_identifier,
|
||||
encrypted_ballot_message
|
||||
);
|
||||
|
||||
// Clean up
|
||||
|
||||
if (result.id.bytes != NULL)
|
||||
|
@ -92,10 +112,10 @@ bool API_EncryptBallot(uint8_t *selections_byte_array,
|
|||
result.tracker.bytes = NULL;
|
||||
}
|
||||
|
||||
if (encrypter != NULL)
|
||||
if (_encrypter != NULL)
|
||||
{
|
||||
Voting_Encrypter_free(encrypter);
|
||||
encrypter = NULL;
|
||||
Voting_Encrypter_free(_encrypter);
|
||||
_encrypter = NULL;
|
||||
}
|
||||
|
||||
Crypto_parameters_free();
|
||||
|
@ -113,7 +133,124 @@ void API_EncryptBallot_free(struct register_ballot_message message,
|
|||
}
|
||||
|
||||
if (tracker_string != NULL)
|
||||
{
|
||||
free(tracker_string);
|
||||
tracker_string = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool API_EncryptBallot_soft_delete_file(char *export_path, char *filename)
|
||||
{
|
||||
bool ok = true;
|
||||
char *default_prefix = "electionguard_encrypted_ballots-";
|
||||
char *existing_filename = malloc(FILENAME_MAX + 1);
|
||||
if (existing_filename == NULL)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
char *soft_delete_filename = malloc(FILENAME_MAX + 1);
|
||||
if (soft_delete_filename == NULL)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
ok = generate_filename(export_path, filename, default_prefix, existing_filename);
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
ok = generate_unique_filename(export_path, filename, default_prefix, soft_delete_filename);
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
uint32_t result = rename(existing_filename, soft_delete_filename);
|
||||
if (result != 0)
|
||||
{
|
||||
// failure to rename is a valid case
|
||||
//ok = false;
|
||||
DEBUG_PRINT(("API_EncryptBallot_soft_delete_file: unable to rename the file\n\n"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
DEBUG_PRINT(("API_EncryptBallot_soft_delete_file: unable to sofdt delete the file\n\n"));
|
||||
}
|
||||
|
||||
free(existing_filename);
|
||||
free(soft_delete_filename);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool export_ballot(char *export_path, char *filename, char **output_filename,
|
||||
char *identifier,
|
||||
struct register_ballot_message *encrypted_ballot_message)
|
||||
{
|
||||
bool ok = true;
|
||||
char *default_prefix = "electionguard_encrypted_ballots-";
|
||||
*output_filename = malloc(FILENAME_MAX + 1);
|
||||
if (output_filename == NULL)
|
||||
{
|
||||
ok = false;
|
||||
return ok;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
ok = generate_filename(export_path, filename, default_prefix, *output_filename);
|
||||
DEBUG_PRINT(("API_EncryptBallots: generated filename for export at \"%s\"\n", *output_filename));
|
||||
}
|
||||
|
||||
if (ok && !Directory_exists(export_path))
|
||||
{
|
||||
ok = create_directory(export_path);
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
FILE *out = fopen(*output_filename, "a+");
|
||||
if (out == NULL)
|
||||
{
|
||||
INFO_PRINT(("API_EncryptBallots: export_ballot error accessing file\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
int seek_status = fseek(out, 0, SEEK_END);
|
||||
if (seek_status != 0)
|
||||
{
|
||||
INFO_PRINT(("API_EncryptBallots: export_ballot error seeking file\n"));
|
||||
fclose(out);
|
||||
return false;
|
||||
}
|
||||
|
||||
enum Voting_Encrypter_status status =
|
||||
Voting_Encrypter_write_ballot(out, identifier, encrypted_ballot_message);
|
||||
|
||||
if (status != VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (out != NULL)
|
||||
{
|
||||
fclose(out);
|
||||
out = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
free(output_filename);
|
||||
output_filename = NULL;
|
||||
DEBUG_PRINT(("API_EncryptBallots: error exporting to: %s\n", *output_filename));
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool initialize_encrypter(struct joint_public_key joint_key)
|
||||
|
@ -132,7 +269,7 @@ bool initialize_encrypter(struct joint_public_key joint_key)
|
|||
if (result.status != VOTING_ENCRYPTER_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
encrypter = result.encrypter;
|
||||
_encrypter = result.encrypter;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,113 @@
|
|||
#define __USE_SECURE_APIS__
|
||||
#endif
|
||||
|
||||
bool generate_filename(char *path_in, char *prefix_in, char* default_prefix, char *filename_out)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
char prefix[FILENAME_MAX];
|
||||
char path[FILENAME_MAX];
|
||||
char *inUsePrefix = default_prefix;
|
||||
size_t path_len = 0;
|
||||
size_t prefix_size = 0;
|
||||
|
||||
// if path is provided, check the last char in the string to make sure it has the appropriate slash
|
||||
#ifdef __USE_SECURE_APIS__
|
||||
errno_t err = strcpy_s(path, FILENAME_MAX, path_in);
|
||||
if (0 != err)
|
||||
{
|
||||
ok = false;
|
||||
goto Exit;
|
||||
}
|
||||
#else
|
||||
path_len = strlen(path_in);
|
||||
if (path_len >= FILENAME_MAX)
|
||||
{
|
||||
ok = false;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
strcpy(path, path_in);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __USE_SECURE_APIS__
|
||||
path_len = strnlen_s(path, FILENAME_MAX);
|
||||
if (path_len == 0 || path_len == FILENAME_MAX)
|
||||
{
|
||||
ok = false;
|
||||
goto Exit;
|
||||
}
|
||||
#else
|
||||
path_len = strlen(path);
|
||||
#endif
|
||||
|
||||
|
||||
if (path_len > 0)
|
||||
{
|
||||
char *directory_separator;
|
||||
#ifdef _WIN32
|
||||
directory_separator = "\\";
|
||||
#else
|
||||
directory_separator = "/";
|
||||
#endif
|
||||
char path_end_char = path_in[path_len-1];
|
||||
if (path_end_char != directory_separator[0])
|
||||
{
|
||||
#ifdef __USE_SECURE_APIS__
|
||||
err = strcat_s(path, FILENAME_MAX, directory_separator);
|
||||
if (0 != err)
|
||||
{
|
||||
ok = false;
|
||||
goto Exit;
|
||||
}
|
||||
#else
|
||||
path_len += 1;
|
||||
if (path_len >= FILENAME_MAX)
|
||||
{
|
||||
ok = false;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
strcat(path, directory_separator);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// if prefix is provided for filename, use it, otherwise use the default
|
||||
prefix_size = strlen(prefix_in);
|
||||
if (prefix_size > 0)
|
||||
inUsePrefix = prefix_in;
|
||||
else
|
||||
prefix_size = strlen(inUsePrefix);
|
||||
|
||||
#ifdef __USE_SECURE_APIS__
|
||||
err = strcpy_s(prefix, FILENAME_MAX, inUsePrefix);
|
||||
|
||||
if (0 != err)
|
||||
{
|
||||
ok = false;
|
||||
goto Exit;
|
||||
}
|
||||
#else
|
||||
if (prefix_size >= FILENAME_MAX)
|
||||
{
|
||||
ok = false;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
strcpy(prefix, inUsePrefix);
|
||||
#endif
|
||||
|
||||
int32_t status = snprintf(filename_out, FILENAME_MAX, "%s%s", path, prefix);
|
||||
|
||||
if (status < 0)
|
||||
ok = false;
|
||||
|
||||
Exit:
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool generate_unique_filename(char *path_in, char *prefix_in, char* default_prefix, char *filename_out)
|
||||
{
|
||||
bool ok = true;
|
||||
|
@ -113,4 +220,4 @@ bool generate_unique_filename(char *path_in, char *prefix_in, char* default_pref
|
|||
|
||||
Exit:
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
bool generate_filename(char *path_in, char *prefix_in, char* default_prefix, char *filename_out);
|
||||
|
||||
bool generate_unique_filename(char *path_in, char *prefix_in, char* default_prefix, char *filename_out);
|
||||
|
||||
#endif /* __API_FILENAME_H__ */
|
|
@ -0,0 +1,150 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <electionguard/api/load_ballots.h>
|
||||
|
||||
#include <log.h>
|
||||
|
||||
#include "api/base_hash.h"
|
||||
#include "directory.h"
|
||||
#include "api/filename.h"
|
||||
|
||||
static API_LoadBallots_status initialize_coordinator(uint32_t num_selections);
|
||||
static API_LoadBallots_status load_ballots(uint64_t start_index,
|
||||
uint64_t count,
|
||||
uint32_t num_selections,
|
||||
char *import_filepath,
|
||||
char **out_external_identifiers,
|
||||
struct register_ballot_message *out_encrypted_ballots);
|
||||
|
||||
// Global state
|
||||
static Voting_Coordinator _load_coordinator = NULL;
|
||||
|
||||
/**
|
||||
* Load a range of ballots from a specified file on the file system
|
||||
*/
|
||||
API_LoadBallots_status API_LoadBallots(
|
||||
uint64_t start_index,
|
||||
uint64_t count,
|
||||
uint32_t num_selections,
|
||||
char *import_filepath,
|
||||
char **out_external_identifiers,
|
||||
struct register_ballot_message *out_encrypted_ballots)
|
||||
{
|
||||
enum API_LoadBallots_status status = API_LOADBALLOTS_SUCCESS;
|
||||
|
||||
// Set global variables
|
||||
Crypto_parameters_new();
|
||||
|
||||
if (_load_coordinator == NULL)
|
||||
{
|
||||
status = initialize_coordinator(num_selections);
|
||||
}
|
||||
|
||||
if (status == API_LOADBALLOTS_SUCCESS)
|
||||
{
|
||||
status = load_ballots(
|
||||
start_index,
|
||||
count,
|
||||
num_selections,
|
||||
import_filepath,
|
||||
out_external_identifiers,
|
||||
out_encrypted_ballots
|
||||
);
|
||||
}
|
||||
|
||||
// Unlike other API Methods, we do not call
|
||||
// Voting_Coordinator_free, because that component
|
||||
// is used both when loading ballots and
|
||||
// during record/cast/spoil.
|
||||
|
||||
Crypto_parameters_free();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the bytes allocated by LoadBallots
|
||||
*/
|
||||
API_LoadBallots_status API_LoadBallots_free(char *output_filename)
|
||||
{
|
||||
enum API_LoadBallots_status status = API_LOADBALLOTS_SUCCESS;
|
||||
|
||||
if (output_filename != NULL)
|
||||
{
|
||||
free(output_filename);
|
||||
}
|
||||
|
||||
if (_load_coordinator != NULL)
|
||||
{
|
||||
Voting_Coordinator_free(_load_coordinator);
|
||||
_load_coordinator = NULL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
API_LoadBallots_status initialize_coordinator(uint32_t num_selections)
|
||||
{
|
||||
struct Voting_Coordinator_new_r result =
|
||||
Voting_Coordinator_new(num_selections);
|
||||
|
||||
if (result.status != VOTING_COORDINATOR_SUCCESS)
|
||||
return API_LOADBALLOTS_INITIALIZATION_ERROR;
|
||||
else
|
||||
{
|
||||
_load_coordinator = result.coordinator;
|
||||
return API_LOADBALLOTS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
API_LoadBallots_status load_ballots(uint64_t start_index,
|
||||
uint64_t count,
|
||||
uint32_t num_selections,
|
||||
char *import_filepath,
|
||||
char **out_external_identifiers,
|
||||
struct register_ballot_message *out_encrypted_ballots)
|
||||
{
|
||||
// open the file for read
|
||||
FILE *in = fopen(import_filepath, "r");
|
||||
if (in == NULL)
|
||||
{
|
||||
INFO_PRINT(("API_LoadBallots: load_ballots error accessing file\n"));
|
||||
return API_LOADBALLOTS_IO_ERROR;
|
||||
}
|
||||
|
||||
int seek_status = fseek(in, 0, SEEK_SET);
|
||||
if (seek_status != 0)
|
||||
{
|
||||
INFO_PRINT(("API_LoadBallots: load_ballots error seeking file\n"));
|
||||
fclose(in);
|
||||
return API_LOADBALLOTS_IO_ERROR;
|
||||
}
|
||||
|
||||
enum Voting_Coordinator_status load_result = VOTING_COORDINATOR_SUCCESS;
|
||||
|
||||
load_result = Voting_Coordinator_import_encrypted_ballots(
|
||||
_load_coordinator,
|
||||
start_index,
|
||||
count,
|
||||
num_selections,
|
||||
in,
|
||||
out_external_identifiers,
|
||||
out_encrypted_ballots
|
||||
);
|
||||
|
||||
if (in != NULL)
|
||||
{
|
||||
fclose(in);
|
||||
in = NULL;
|
||||
}
|
||||
|
||||
switch (load_result)
|
||||
{
|
||||
case VOTING_COORDINATOR_INSUFFICIENT_MEMORY:
|
||||
return API_LOADBALLOTS_INSUFFICIENT_MEMORY;
|
||||
// TODO: other cases
|
||||
case VOTING_COORDINATOR_SUCCESS:
|
||||
default:
|
||||
return API_LOADBALLOTS_SUCCESS;
|
||||
}
|
||||
}
|
|
@ -2,25 +2,27 @@
|
|||
|
||||
#include <electionguard/api/record_ballots.h>
|
||||
|
||||
#include <log.h>
|
||||
|
||||
#include "api/base_hash.h"
|
||||
#include "directory.h"
|
||||
#include "api/filename.h"
|
||||
#include "serialize/voting.h"
|
||||
#include "voting/num_ballots.h"
|
||||
#include "directory.h"
|
||||
|
||||
static bool initialize_coordinator(uint32_t num_selections);
|
||||
static bool get_serialized_ballot_identifier(int64_t ballot_id, struct ballot_identifier *ballot_identifier);
|
||||
static bool export_ballots(char *export_path, char *filename_prefix, char **output_filename);
|
||||
|
||||
// Global state
|
||||
static Voting_Coordinator coordinator;
|
||||
static Voting_Coordinator _record_coordinator = NULL;
|
||||
|
||||
bool API_RecordBallots(uint32_t num_selections,
|
||||
uint32_t num_cast_ballots,
|
||||
uint32_t num_spoil_ballots,
|
||||
uint64_t total_num_ballots,
|
||||
uint64_t *cast_ids,
|
||||
uint64_t *spoil_ids,
|
||||
uint32_t total_num_ballots,
|
||||
char **cast_ids,
|
||||
char **spoil_ids,
|
||||
char **external_identifiers,
|
||||
struct register_ballot_message *encrypted_ballots,
|
||||
char *export_path,
|
||||
char *filename_prefix,
|
||||
|
@ -29,105 +31,102 @@ bool API_RecordBallots(uint32_t num_selections,
|
|||
char **spoiled_tracker_strings)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
|
||||
// Set global variables
|
||||
|
||||
Crypto_parameters_new();
|
||||
Voting_num_ballots = total_num_ballots;
|
||||
|
||||
|
||||
// Initialize Voting Coordinator
|
||||
|
||||
if (ok)
|
||||
ok = initialize_coordinator(num_selections);
|
||||
|
||||
// Register Ballots
|
||||
|
||||
for (uint64_t i = 0; i < total_num_ballots && ok; i++)
|
||||
if (ok && _record_coordinator == NULL)
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("API_RecordBallots :: Voting_Coordinator_register_ballot :: i = %lu :: encrypted_ballots[i].len = %lu\n", i, encrypted_ballots[i].len);
|
||||
#endif
|
||||
enum Voting_Coordinator_status status =
|
||||
Voting_Coordinator_register_ballot(coordinator, encrypted_ballots[i]);
|
||||
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
ok = initialize_coordinator(num_selections);
|
||||
}
|
||||
|
||||
// Record Casted Ballots
|
||||
// Register Ballots
|
||||
for (uint32_t i = 0; i < total_num_ballots && ok; i++)
|
||||
{
|
||||
DEBUG_PRINT(("\nAPI_RecordBallots: register_ballot: id: %s .len = %lu\n", external_identifiers[i], encrypted_ballots[i].len));
|
||||
|
||||
char *registered_tracker;
|
||||
enum Voting_Coordinator_status status =
|
||||
Voting_Coordinator_register_ballot(
|
||||
_record_coordinator,
|
||||
external_identifiers[i],
|
||||
encrypted_ballots[i],
|
||||
®istered_tracker
|
||||
);
|
||||
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
DEBUG_PRINT(("API_RecordBallots: register_ballot: failed!\n"));
|
||||
ok = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_PRINT(("API_RecordBallots: register_ballot: success! tracker: %.20s...\n", registered_tracker));
|
||||
}
|
||||
}
|
||||
|
||||
// Record Cast Ballots
|
||||
for (uint32_t i = 0; i < num_cast_ballots && ok; i++)
|
||||
{
|
||||
struct ballot_identifier ballot_identifier;
|
||||
DEBUG_PRINT(("\nAPI_RecordBallots: cast_ballot : id: %s\n", cast_ids[i]));
|
||||
|
||||
ok = get_serialized_ballot_identifier(cast_ids[i], &ballot_identifier);
|
||||
char *cast_tracker;
|
||||
enum Voting_Coordinator_status status =
|
||||
Voting_Coordinator_cast_ballot(_record_coordinator, cast_ids[i], &cast_tracker);
|
||||
|
||||
if (ok)
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("API_RecordBallots :: Voting_Coordinator_cast_ballot :: i = %u :: cast_ids[i] = %lu\n", i, cast_ids[i]);
|
||||
#endif
|
||||
enum Voting_Coordinator_status status =
|
||||
Voting_Coordinator_cast_ballot(coordinator, ballot_identifier);
|
||||
|
||||
casted_tracker_strings[i] = Voting_Coordinator_get_tracker(coordinator, ballot_identifier);
|
||||
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
DEBUG_PRINT(("API_RecordBallots: cast_ballot : failed!\n"));
|
||||
casted_tracker_strings[i] = NULL;
|
||||
ok = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_PRINT(("API_RecordBallots: cast_ballot : sucess! tracker: %.20s...\n", cast_tracker));
|
||||
}
|
||||
|
||||
// Free current ballot identifier
|
||||
|
||||
if (ballot_identifier.bytes != NULL)
|
||||
{
|
||||
free((void *)ballot_identifier.bytes);
|
||||
ballot_identifier.bytes = NULL;
|
||||
}
|
||||
casted_tracker_strings[i] = cast_tracker;
|
||||
}
|
||||
|
||||
// Record Spoiled Ballots
|
||||
|
||||
for (uint32_t i = 0; i < num_spoil_ballots && ok; i++)
|
||||
{
|
||||
struct ballot_identifier ballot_identifier;
|
||||
DEBUG_PRINT(("\nAPI_RecordBallots: spoil_ballot: id: %s\n", spoil_ids[i]));
|
||||
|
||||
ok = get_serialized_ballot_identifier(spoil_ids[i], &ballot_identifier);
|
||||
char *spoiled_tracker;
|
||||
enum Voting_Coordinator_status status =
|
||||
Voting_Coordinator_spoil_ballot(_record_coordinator, spoil_ids[i], &spoiled_tracker);
|
||||
|
||||
if (ok)
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("API_RecordBallots :: Voting_Coordinator_spoil_ballot :: i = %u :: spoil_ids[i] = %lu\n", i, spoil_ids[i]);
|
||||
#endif
|
||||
enum Voting_Coordinator_status status =
|
||||
Voting_Coordinator_spoil_ballot(coordinator, ballot_identifier);
|
||||
|
||||
spoiled_tracker_strings[i] = Voting_Coordinator_get_tracker(coordinator, ballot_identifier);
|
||||
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
DEBUG_PRINT(("API_RecordBallots: spoil_ballot : failed!\n"));
|
||||
spoiled_tracker_strings[i] = NULL;
|
||||
ok = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_PRINT(("API_RecordBallots: spoil_ballot: success! tracker: %.20s...\n", spoiled_tracker));
|
||||
}
|
||||
|
||||
// Free current ballot identifier
|
||||
|
||||
if (ballot_identifier.bytes != NULL)
|
||||
{
|
||||
free((void *)ballot_identifier.bytes);
|
||||
ballot_identifier.bytes = NULL;
|
||||
}
|
||||
spoiled_tracker_strings[i] = spoiled_tracker;
|
||||
}
|
||||
|
||||
// Export
|
||||
|
||||
if (ok)
|
||||
{
|
||||
ok = export_ballots(export_path, filename_prefix, output_filename);
|
||||
}
|
||||
|
||||
// Clean up
|
||||
|
||||
if (coordinator != NULL)
|
||||
{
|
||||
Voting_Coordinator_free(coordinator);
|
||||
coordinator = NULL;
|
||||
}
|
||||
Voting_Coordinator_clear_buffer(_record_coordinator);
|
||||
|
||||
// Unlike other API Methods, we do not call
|
||||
// Voting_Coordinator_free, because that component
|
||||
// is used both when loading ballots and
|
||||
// during record/cast/spoil
|
||||
|
||||
Crypto_parameters_free();
|
||||
|
||||
|
@ -141,15 +140,30 @@ void API_RecordBallots_free(char *output_filename,
|
|||
char **spoiled_tracker_strings)
|
||||
{
|
||||
if (output_filename != NULL)
|
||||
{
|
||||
free(output_filename);
|
||||
output_filename = NULL;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_cast_ballots; i++)
|
||||
{
|
||||
if (casted_tracker_strings[i] != NULL)
|
||||
{
|
||||
free(casted_tracker_strings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_spoil_ballots; i++)
|
||||
{
|
||||
if (spoiled_tracker_strings[i] != NULL)
|
||||
free(spoiled_tracker_strings[i]);
|
||||
}
|
||||
|
||||
if (_record_coordinator != NULL)
|
||||
{
|
||||
Voting_Coordinator_free(_record_coordinator);
|
||||
_record_coordinator = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool initialize_coordinator(uint32_t num_selections)
|
||||
|
@ -162,7 +176,7 @@ bool initialize_coordinator(uint32_t num_selections)
|
|||
if (result.status != VOTING_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
coordinator = result.coordinator;
|
||||
_record_coordinator = result.coordinator;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
@ -188,7 +202,7 @@ bool get_serialized_ballot_identifier(int64_t ballot_id, struct ballot_identifie
|
|||
ok = false;
|
||||
else
|
||||
{
|
||||
*ballot_identifier = (struct ballot_identifier){
|
||||
*ballot_identifier = (struct ballot_identifier) {
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
|
@ -201,25 +215,40 @@ bool export_ballots(char *export_path, char *filename_prefix, char **output_file
|
|||
{
|
||||
bool ok = true;
|
||||
char *default_prefix = "electionguard_ballots-";
|
||||
*output_filename = malloc(FILENAME_MAX * sizeof(char));
|
||||
ok = generate_unique_filename(export_path, filename_prefix, default_prefix, *output_filename);
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("API_RecordBallots :: generated unique filename for export at \"%s\"\n", *output_filename);
|
||||
#endif
|
||||
*output_filename = malloc(FILENAME_MAX + 1);
|
||||
if (output_filename == NULL)
|
||||
{
|
||||
ok = false;
|
||||
return ok;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
if (ok)
|
||||
{
|
||||
ok = generate_filename(export_path, filename_prefix, default_prefix, *output_filename);
|
||||
DEBUG_PRINT(("\nAPI_RecordBallots: generated unique filename for export at \"%s\"\n", *output_filename));
|
||||
}
|
||||
|
||||
if (ok && !Directory_exists(export_path))
|
||||
{
|
||||
ok = create_directory(export_path);
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
FILE *out = fopen(*output_filename, "w+");
|
||||
if (out == NULL)
|
||||
{
|
||||
INFO_PRINT(("API_RecordBallots: error accessing file\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
enum Voting_Coordinator_status status =
|
||||
Voting_Coordinator_export_ballots(coordinator, out);
|
||||
Voting_Coordinator_export_buffered_ballots(_record_coordinator, out);
|
||||
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (out != NULL)
|
||||
{
|
||||
|
@ -228,5 +257,12 @@ bool export_ballots(char *export_path, char *filename_prefix, char **output_file
|
|||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
free(output_filename);
|
||||
output_filename = NULL;
|
||||
DEBUG_PRINT(("API_RecordBallots: error exporting to: %s\n", *output_filename));
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <electionguard/api/tally_votes.h>
|
||||
|
||||
#include <log.h>
|
||||
|
||||
#include "api/base_hash.h"
|
||||
#include "api/filename.h"
|
||||
#include "directory.h"
|
||||
|
@ -23,7 +25,7 @@ static bool export_tally_votes(char *export_path, char *filename_prefix,
|
|||
|
||||
// Global state
|
||||
static struct api_config api_config;
|
||||
static Decryption_Coordinator coordinator;
|
||||
static Decryption_Coordinator _decryption_coordinator;
|
||||
static Decryption_Trustee decryption_trustees[MAX_TRUSTEES];
|
||||
|
||||
bool API_TallyVotes(struct api_config config,
|
||||
|
@ -88,21 +90,23 @@ bool API_TallyVotes(struct api_config config,
|
|||
decryption_trustees[i] = NULL;
|
||||
}
|
||||
|
||||
if (coordinator != NULL)
|
||||
if (_decryption_coordinator != NULL)
|
||||
{
|
||||
Decryption_Coordinator_free(coordinator);
|
||||
coordinator = NULL;
|
||||
Decryption_Coordinator_free(_decryption_coordinator);
|
||||
_decryption_coordinator = NULL;
|
||||
}
|
||||
|
||||
Crypto_parameters_free();
|
||||
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void API_TallyVotes_free(char *output_filename)
|
||||
{
|
||||
if (output_filename != NULL)
|
||||
{
|
||||
free(output_filename);
|
||||
}
|
||||
}
|
||||
|
||||
bool initialize_coordinator(void)
|
||||
|
@ -115,7 +119,7 @@ bool initialize_coordinator(void)
|
|||
if (result.status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
coordinator = result.coordinator;
|
||||
_decryption_coordinator = result.coordinator;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
@ -198,7 +202,7 @@ bool decrypt_tally_shares()
|
|||
if (ok)
|
||||
{
|
||||
enum Decryption_Coordinator_status status =
|
||||
Decryption_Coordinator_receive_share(coordinator, share);
|
||||
Decryption_Coordinator_receive_share(_decryption_coordinator, share);
|
||||
if (status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
@ -225,7 +229,7 @@ bool request_missing_trustee_tally_shares(
|
|||
if (ok)
|
||||
{
|
||||
struct Decryption_Coordinator_all_shares_received_r result =
|
||||
Decryption_Coordinator_all_shares_received(coordinator);
|
||||
Decryption_Coordinator_all_shares_received(_decryption_coordinator);
|
||||
|
||||
if (result.status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
|
@ -271,7 +275,7 @@ bool decrypt_tally_decryption_fragments(
|
|||
{
|
||||
enum Decryption_Coordinator_status status =
|
||||
Decryption_Coordinator_receive_fragments(
|
||||
coordinator, decryption_fragments);
|
||||
_decryption_coordinator, decryption_fragments);
|
||||
|
||||
if (status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
|
@ -293,25 +297,40 @@ bool export_tally_votes(char *export_path, char *filename_prefix,
|
|||
{
|
||||
bool ok = true;
|
||||
char *default_prefix = "electionguard_tally-";
|
||||
*output_filename = malloc(FILENAME_MAX * sizeof(char));
|
||||
ok = generate_unique_filename(export_path, filename_prefix, default_prefix, *output_filename);
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("API_TALLYVOTES :: generated unique filename for export at \"%s\"\n", *output_filename);
|
||||
#endif
|
||||
*output_filename = malloc(FILENAME_MAX + 1);
|
||||
if (output_filename == NULL)
|
||||
{
|
||||
ok = false;
|
||||
return ok;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
ok = generate_unique_filename(export_path, filename_prefix, default_prefix, *output_filename);
|
||||
DEBUG_PRINT(("API_TALLYVOTES :: generated unique filename for export at \"%s\"\n", *output_filename));
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
if (ok && !Directory_exists(export_path))
|
||||
{
|
||||
ok = create_directory(export_path);
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
FILE *out = fopen(*output_filename, "w+");
|
||||
if (out == NULL)
|
||||
{
|
||||
INFO_PRINT(("API_TallyVotes: error accessing file\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
enum Decryption_Coordinator_status status =
|
||||
Decryption_Coordinator_all_fragments_received(coordinator, out, tally_results_array);
|
||||
Decryption_Coordinator_all_fragments_received(_decryption_coordinator, out, tally_results_array);
|
||||
|
||||
if (status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (out != NULL)
|
||||
{
|
||||
|
@ -320,5 +339,12 @@ bool export_tally_votes(char *export_path, char *filename_prefix,
|
|||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
free(output_filename);
|
||||
output_filename = NULL;
|
||||
DEBUG_PRINT(("API_TallyVotes: error exporting to: %s\n", *output_filename));
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
|
|
@ -104,7 +104,9 @@ void Crypto_parameters_new()
|
|||
void Crypto_parameters_free()
|
||||
{
|
||||
mpz_clear(p);
|
||||
mpz_clear(q);
|
||||
mpz_clear(generator);
|
||||
mpz_clear(bignum_one);
|
||||
}
|
||||
|
||||
void print_base16(const mpz_t z)
|
||||
|
|
|
@ -983,10 +983,10 @@ bool Crypto_encryption_fprint(FILE *out, const struct encryption_rep *rep)
|
|||
}
|
||||
|
||||
struct Crypto_encrypted_ballot_new_r
|
||||
Crypto_encrypted_ballot_new(uint32_t num_selections, uint64_t id)
|
||||
Crypto_encrypted_ballot_new(uint32_t num_selections, uint64_t ballot_id)
|
||||
{
|
||||
struct Crypto_encrypted_ballot_new_r result;
|
||||
result.result.id = id;
|
||||
result.result.id = ballot_id;
|
||||
result.result.num_selections = num_selections;
|
||||
result.result.selections =
|
||||
malloc(num_selections * sizeof(*result.result.selections));
|
||||
|
@ -1025,5 +1025,11 @@ void Crypto_encrypted_ballot_free(struct encrypted_ballot_rep *ballot)
|
|||
Crypto_encryption_rep_free(&ballot->selections[i]);
|
||||
}
|
||||
free(ballot->selections);
|
||||
|
||||
if (ballot->dis_proof != NULL)
|
||||
{
|
||||
Crypto_dis_proof_free(ballot->dis_proof);
|
||||
}
|
||||
|
||||
Crypto_cp_proof_free(&ballot->cp_proof);
|
||||
}
|
||||
|
|
|
@ -242,7 +242,7 @@ void Crypto_encryption_rep_copy(struct encryption_rep *dst,
|
|||
struct encryption_rep *src);
|
||||
|
||||
struct Crypto_encrypted_ballot_new_r
|
||||
Crypto_encrypted_ballot_new(uint32_t num_selections, uint64_t id);
|
||||
Crypto_encrypted_ballot_new(uint32_t num_selections, uint64_t ballot_id);
|
||||
void Crypto_encrypted_ballot_free(struct encrypted_ballot_rep *ballot);
|
||||
|
||||
#endif /* __CRYPTO_REPS_H__ */
|
||||
|
|
|
@ -65,15 +65,26 @@ Decryption_Coordinator_new(uint32_t num_trustees, uint32_t threshold)
|
|||
result.coordinator->num_trustees * sizeof(bool));
|
||||
|
||||
result.coordinator->tallies_initialized = false;
|
||||
result.coordinator->num_tallies = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Decryption_Coordinator_free(Decryption_Coordinator c) { free(c); }
|
||||
void Decryption_Coordinator_free(Decryption_Coordinator coordinator)
|
||||
{
|
||||
for(uint32_t i = 0; i < coordinator->num_tallies && coordinator->tallies_initialized; i++)
|
||||
{
|
||||
Crypto_encryption_rep_free(&coordinator->tallies[i]);
|
||||
}
|
||||
|
||||
coordinator->tallies_initialized = false;
|
||||
|
||||
free(coordinator);
|
||||
}
|
||||
|
||||
enum Decryption_Coordinator_status
|
||||
Decryption_Coordinator_receive_share(Decryption_Coordinator c,
|
||||
Decryption_Coordinator_receive_share(Decryption_Coordinator coordinator,
|
||||
struct decryption_share share)
|
||||
{
|
||||
enum Decryption_Coordinator_status status = DECRYPTION_COORDINATOR_SUCCESS;
|
||||
|
@ -97,39 +108,56 @@ Decryption_Coordinator_receive_share(Decryption_Coordinator c,
|
|||
Serialize_read_decryption_share(&state, &share_rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_READING)
|
||||
{
|
||||
status = DECRYPTION_COORDINATOR_DESERIALIZE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that we haven't already seen this trustee
|
||||
if (status == DECRYPTION_COORDINATOR_SUCCESS)
|
||||
{
|
||||
if (share_rep.trustee_index >= c->num_trustees)
|
||||
if (share_rep.trustee_index >= coordinator->num_trustees)
|
||||
{
|
||||
status = DECRYPTION_COORDINATOR_INVALID_TRUSTEE_INDEX;
|
||||
else if (c->anounced[share_rep.trustee_index])
|
||||
}
|
||||
else if (coordinator->anounced[share_rep.trustee_index])
|
||||
{
|
||||
status = DECRYPTION_COORDINATOR_DUPLICATE_TRUSTEE_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == DECRYPTION_COORDINATOR_SUCCESS)
|
||||
{
|
||||
c->anounced[share_rep.trustee_index] = true;
|
||||
coordinator->anounced[share_rep.trustee_index] = true;
|
||||
|
||||
// We check to see if this is the first time through
|
||||
if (c->tallies_initialized)
|
||||
if (coordinator->tallies_initialized)
|
||||
{
|
||||
// If it is, we add in the shares for the new tally
|
||||
if (share_rep.num_tallies != c->num_tallies)
|
||||
if (share_rep.num_tallies != coordinator->num_tallies)
|
||||
{
|
||||
status = DECRYPTION_COORDINATOR_CONFUSED_DECRYPTION_TRUSTEE;
|
||||
}
|
||||
for (size_t i = 0; i < share_rep.num_tallies &&
|
||||
DECRYPTION_COORDINATOR_SUCCESS == status;
|
||||
i++)
|
||||
|
||||
for (size_t i = 0; i < share_rep.num_tallies
|
||||
&& DECRYPTION_COORDINATOR_SUCCESS == status;
|
||||
i++)
|
||||
{
|
||||
mul_mod_p(c->tallies[i].nonce_encoding,
|
||||
c->tallies[i].nonce_encoding,
|
||||
share_rep.tally_share[i].nonce_encoding);
|
||||
if (!(0 == mpz_cmp(c->tallies[i].message_encoding,
|
||||
share_rep.tally_share[i].message_encoding)))
|
||||
mul_mod_p(
|
||||
coordinator->tallies[i].nonce_encoding,
|
||||
coordinator->tallies[i].nonce_encoding,
|
||||
share_rep.tally_share[i].nonce_encoding
|
||||
);
|
||||
|
||||
int compare_result = mpz_cmp(
|
||||
coordinator->tallies[i].message_encoding,
|
||||
share_rep.tally_share[i].message_encoding
|
||||
);
|
||||
|
||||
if (compare_result != 0)
|
||||
{
|
||||
status = DECRYPTION_COORDINATOR_CONFUSED_DECRYPTION_TRUSTEE;
|
||||
}
|
||||
|
||||
// printf("Comparing message encodings\n");
|
||||
// print_base16(c->tallies[i].message_encoding);
|
||||
|
@ -139,19 +167,29 @@ Decryption_Coordinator_receive_share(Decryption_Coordinator c,
|
|||
else
|
||||
{
|
||||
//If this is the first one, we just copy them over
|
||||
c->num_tallies = share_rep.num_tallies;
|
||||
coordinator->num_tallies = share_rep.num_tallies;
|
||||
for (size_t i = 0; i < share_rep.num_tallies; i++)
|
||||
{
|
||||
Crypto_encryption_rep_new(&c->tallies[i]);
|
||||
mpz_set(c->tallies[i].nonce_encoding,
|
||||
share_rep.tally_share[i].nonce_encoding);
|
||||
mpz_set(c->tallies[i].message_encoding,
|
||||
share_rep.tally_share[i].message_encoding);
|
||||
Crypto_encryption_rep_new(&coordinator->tallies[i]);
|
||||
mpz_set(
|
||||
coordinator->tallies[i].nonce_encoding,
|
||||
share_rep.tally_share[i].nonce_encoding
|
||||
);
|
||||
mpz_set(
|
||||
coordinator->tallies[i].message_encoding,
|
||||
share_rep.tally_share[i].message_encoding
|
||||
);
|
||||
}
|
||||
c->tallies_initialized = true;
|
||||
coordinator->tallies_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
// free
|
||||
for (uint32_t i = 0; i < share_rep.num_tallies; i++)
|
||||
{
|
||||
Crypto_encryption_rep_free(&share_rep.tally_share[i]);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ Decryption_Trustee_new(uint32_t num_trustees, uint32_t threshold,
|
|||
|
||||
void Decryption_Trustee_free(Decryption_Trustee decryption_trustee)
|
||||
{
|
||||
for (size_t i = 0; i < MAX_SELECTIONS; i++)
|
||||
for (size_t i = 0; i < decryption_trustee->num_selections; i++)
|
||||
{
|
||||
Crypto_encryption_rep_free(&decryption_trustee->tallies[i]);
|
||||
}
|
||||
|
@ -199,8 +199,13 @@ static void Decryption_Trustee_accum_tally(Decryption_Trustee decryption_trustee
|
|||
struct encryption_rep *selections)
|
||||
{
|
||||
for (size_t i = 0; i < decryption_trustee->num_selections; i++)
|
||||
Crypto_encryption_homomorphic_add(&decryption_trustee->tallies[i], &decryption_trustee->tallies[i],
|
||||
&selections[i]);
|
||||
{
|
||||
Crypto_encryption_homomorphic_add(
|
||||
&decryption_trustee->tallies[i],
|
||||
&decryption_trustee->tallies[i],
|
||||
&selections[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum Decryption_Trustee_status
|
||||
|
@ -208,6 +213,7 @@ Decryption_Trustee_tally_voting_record(Decryption_Trustee decryption_trustee, FI
|
|||
{
|
||||
enum Decryption_Trustee_status status = DECRYPTION_TRUSTEE_SUCCESS;
|
||||
|
||||
// get the number of ballots from the ballots file header
|
||||
uint64_t num_ballots;
|
||||
{
|
||||
int num_read = fscanf(in, "%" PRIu64 "\n", &num_ballots);
|
||||
|
@ -215,6 +221,7 @@ Decryption_Trustee_tally_voting_record(Decryption_Trustee decryption_trustee, FI
|
|||
status = DECRYPTION_TRUSTEE_IO_ERROR;
|
||||
}
|
||||
|
||||
//get the number of selections from the ballots file header
|
||||
uint64_t num_selections;
|
||||
{
|
||||
int num_read = fscanf(in, "%" PRIu64 "\n", &num_selections);
|
||||
|
@ -231,16 +238,28 @@ Decryption_Trustee_tally_voting_record(Decryption_Trustee decryption_trustee, FI
|
|||
bool cast;
|
||||
struct encryption_rep selections[MAX_SELECTIONS];
|
||||
|
||||
for (int j = 0; j < MAX_SELECTIONS; j++)
|
||||
for (int j = 0; j < decryption_trustee->num_selections; j++)
|
||||
{
|
||||
Crypto_encryption_rep_new(&selections[j]);
|
||||
}
|
||||
|
||||
status = Decryption_Trustee_read_ballot(in, &ballot_id, &cast,
|
||||
decryption_trustee->num_selections, selections);
|
||||
status = Decryption_Trustee_read_ballot(
|
||||
in,
|
||||
&ballot_id,
|
||||
&cast,
|
||||
decryption_trustee->num_selections,
|
||||
selections
|
||||
);
|
||||
|
||||
if (status == DECRYPTION_TRUSTEE_SUCCESS && cast)
|
||||
{
|
||||
Decryption_Trustee_accum_tally(decryption_trustee, selections);
|
||||
}
|
||||
|
||||
for (int j = 0; j < decryption_trustee->num_selections; j++)
|
||||
{
|
||||
Crypto_encryption_rep_free(&selections[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -313,6 +332,7 @@ Decryption_Trustee_compute_share(Decryption_Trustee decryption_trustee)
|
|||
for (size_t i = 0; i < decryption_trustee->num_selections; i++)
|
||||
{
|
||||
Crypto_encryption_rep_free(&share_rep.tally_share[i]);
|
||||
Crypto_cp_proof_free(&share_rep.cp_proofs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -67,4 +67,15 @@ bool create_directory(const char *path)
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Directory_exists(const char *path)
|
||||
{
|
||||
bool exists = false;
|
||||
struct stat stats = {0};
|
||||
if (stat(path, &stats) == 0 && S_ISDIR(stats.st_mode))
|
||||
{
|
||||
exists = true;
|
||||
}
|
||||
return exists;
|
||||
}
|
|
@ -6,4 +6,6 @@
|
|||
|
||||
bool create_directory(const char *path);
|
||||
|
||||
bool Directory_exists(const char *path);
|
||||
|
||||
#endif /* __DIRECTORY_H__ */
|
|
@ -1,64 +0,0 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <electionguard/file.h>
|
||||
|
||||
// Create a new file according to template
|
||||
FILE *File_new(char const *template)
|
||||
{
|
||||
bool ok = true;
|
||||
int result_fd = -1;
|
||||
FILE *result = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
const char *mode = "w+";
|
||||
#else
|
||||
const char *mode = "w+x";
|
||||
#endif
|
||||
|
||||
// Duplicate the template. It needs to be mutable for mkstemp.
|
||||
char *template_mut = strdup(template);
|
||||
if (template_mut == NULL)
|
||||
ok = false;
|
||||
|
||||
// Create and open the temporary file
|
||||
if (ok)
|
||||
{
|
||||
result_fd = mkstemp(template_mut);
|
||||
if (-1 == result_fd)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Convert the file descriptor to a FILE*
|
||||
if (ok)
|
||||
{
|
||||
result = fdopen(result_fd, mode);
|
||||
if (result == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Free the duplicated template
|
||||
if (template_mut != NULL)
|
||||
{
|
||||
free(template_mut);
|
||||
template_mut = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Close file
|
||||
void File_close(FILE *file)
|
||||
{
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
// Seek file to beginning
|
||||
void File_seek(FILE *file)
|
||||
{
|
||||
int seek_status = fseek(file, 0L, SEEK_SET);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef __LOG_H__
|
||||
#define __LOG_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void log_stdout(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void log_stderr(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_PRINT(x) do { log_stdout x; } while (0)
|
||||
#else
|
||||
#define DEBUG_PRINT(x) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define INFO_PRINT(x) do { log_stdout x; } while (0)
|
||||
#define ERROR_PRINT(x) do { log_stderr x; } while (0)
|
||||
|
||||
#endif /* __LOG_H__ */
|
|
@ -4,7 +4,9 @@
|
|||
#include <assert.h>
|
||||
|
||||
/**
|
||||
* Best-effort function for zeroing a buffer that abstracts the API available for the platform */
|
||||
* Best-effort function for zeroing a buffer
|
||||
* that abstracts the API available for the platform
|
||||
*/
|
||||
void secure_zero_memory(
|
||||
#ifdef _WIN32
|
||||
#elif __STDC_LIB_EXT1__
|
||||
|
@ -15,16 +17,24 @@ void secure_zero_memory(
|
|||
size_t cnt)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
/* For Windows builds, use SecureZeroMemory, which guarantess that it will not be removed during optimization */
|
||||
/**
|
||||
* For Windows builds, use SecureZeroMemory,
|
||||
* which guarantess that it will not be removed during optimization
|
||||
*/
|
||||
SecureZeroMemory(ptr, cnt);
|
||||
#elif __STDC_LIB_EXT1__
|
||||
/* For C11 (or higher) compilers, use memset_s, which guarantess that it will not be removed during optimization */
|
||||
/**
|
||||
* For C11 (or higher) compilers, use memset_s,
|
||||
* which guarantess that it will not be removed during optimization
|
||||
*/
|
||||
int retval = memset_s(ptr, cnt, 0, cnt);
|
||||
|
||||
/* Check on debug only */
|
||||
assert(retval == 0);
|
||||
#else
|
||||
/* For any other platforms, use memset with teh argument marked as volatile to try to avoid optimization. Best-effort.*/
|
||||
/** For any other platforms, use memset with the argument
|
||||
* marked as volatile to try to avoid optimization. Best-effort.
|
||||
*/
|
||||
memset((void*)ptr, 0, cnt);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "serialize/crypto.h"
|
||||
#include "serialize/voting.h"
|
||||
#include "serialize/builtins.h"
|
||||
|
||||
|
@ -36,3 +37,18 @@ void Serialize_read_ballot_identifier(struct serialize_state *state,
|
|||
{
|
||||
Serialize_read_uint64(state, &data->id);
|
||||
}
|
||||
|
||||
bool Serialize_deserialize_register_ballot_message(struct register_ballot_message *ballot_message,
|
||||
struct encrypted_ballot_rep *out_ballot_rep)
|
||||
{
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_READING,
|
||||
.len = ballot_message->len,
|
||||
.offset = 0,
|
||||
.buf = (uint8_t *)ballot_message->bytes,
|
||||
};
|
||||
|
||||
Serialize_read_encrypted_ballot(&state, out_ballot_rep);
|
||||
|
||||
return state.status == SERIALIZE_STATE_READING;
|
||||
}
|
|
@ -1,17 +1,11 @@
|
|||
#ifndef __SERIALIZE_VOTING_H__
|
||||
#define __SERIALIZE_VOTING_H__
|
||||
|
||||
#include "crypto_reps.h"
|
||||
#include "serialize/state.h"
|
||||
#include "voting/message_reps.h"
|
||||
|
||||
void Serialize_reserve_register_ballot(struct serialize_state *state,
|
||||
struct register_ballot_rep const *data);
|
||||
|
||||
void Serialize_write_register_ballot(struct serialize_state *state,
|
||||
struct register_ballot_rep const *data);
|
||||
|
||||
void Serialize_read_register_ballot(struct serialize_state *state,
|
||||
struct register_ballot_rep *data);
|
||||
#include <electionguard/voting/messages.h>
|
||||
|
||||
void Serialize_reserve_ballot_tracker(struct serialize_state *state,
|
||||
struct ballot_tracker_rep const *data);
|
||||
|
@ -31,4 +25,10 @@ void Serialize_write_ballot_identifier(
|
|||
void Serialize_read_ballot_identifier(struct serialize_state *state,
|
||||
struct ballot_identifier_rep *data);
|
||||
|
||||
bool Serialize_deserialize_ballot_identifier_message(struct ballot_identifier *ballot_identifier_message,
|
||||
struct ballot_identifier_rep *out_ballot_identifier_rep);
|
||||
|
||||
bool Serialize_deserialize_register_ballot_message(struct register_ballot_message *ballot_message,
|
||||
struct encrypted_ballot_rep *out_ballot_rep);
|
||||
|
||||
#endif /* __SERIALIZE_VOTING_H__ */
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,217 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "voting/ballot_collection.h"
|
||||
|
||||
struct ballot_state *ballot_box = NULL;
|
||||
|
||||
static enum Ballot_Collection_result Ballot_Collection_update(
|
||||
char *external_identifier, bool cast, bool spoiled, char **out_tracker);
|
||||
static enum Ballot_Collection_result Ballot_Collection_assert_can_mutate_state(
|
||||
struct ballot_state *existing_ballot);
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_new()
|
||||
{
|
||||
// nothing to do, just following the component initialization pattern
|
||||
return BALLOT_COLLECTION_SUCCESS;
|
||||
}
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_free()
|
||||
{
|
||||
enum Ballot_Collection_result delete_result = Ballot_Collection_remove_all();
|
||||
if (delete_result != BALLOT_COLLECTION_SUCCESS)
|
||||
{
|
||||
return delete_result;
|
||||
}
|
||||
|
||||
ballot_box = NULL;
|
||||
return BALLOT_COLLECTION_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t Ballot_Collection_size()
|
||||
{
|
||||
return HASH_COUNT(ballot_box);
|
||||
}
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_register_ballot(char *external_identifier, char *tracker, uint32_t registered_index)
|
||||
{
|
||||
struct ballot_state *existing_ballot, *new_ballot = NULL;
|
||||
if (Ballot_Collection_get_ballot(external_identifier, &existing_ballot) == BALLOT_COLLECTION_SUCCESS)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_ALREADY_REGISTERED;
|
||||
}
|
||||
|
||||
new_ballot = (struct ballot_state *)malloc(sizeof *new_ballot);
|
||||
if (new_ballot == NULL)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
new_ballot->external_identifier = external_identifier;
|
||||
new_ballot->registered_index = registered_index;
|
||||
new_ballot->registered = true;
|
||||
new_ballot->cast = false;
|
||||
new_ballot->spoiled = false;
|
||||
new_ballot->tracker = tracker;
|
||||
|
||||
HASH_ADD_KEYPTR(
|
||||
hh,
|
||||
ballot_box,
|
||||
new_ballot->external_identifier,
|
||||
strlen(new_ballot->external_identifier),
|
||||
new_ballot
|
||||
);
|
||||
|
||||
return BALLOT_COLLECTION_SUCCESS;
|
||||
}
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_mark_cast(char *external_identifier, char **out_tracker)
|
||||
{
|
||||
return Ballot_Collection_update(external_identifier, true, false, out_tracker);
|
||||
}
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_mark_spoiled(char *external_identifier, char **out_tracker)
|
||||
{
|
||||
return Ballot_Collection_update(external_identifier, false, true, out_tracker);
|
||||
}
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_get_ballot(char *external_identifier, struct ballot_state **ballot)
|
||||
{
|
||||
struct ballot_state *existing_ballot = NULL;
|
||||
HASH_FIND_STR(ballot_box, external_identifier, existing_ballot);
|
||||
|
||||
if (existing_ballot != NULL)
|
||||
{
|
||||
*ballot = existing_ballot;
|
||||
existing_ballot = NULL;
|
||||
|
||||
return BALLOT_COLLECTION_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_remove_ballot(char *external_identifier)
|
||||
{
|
||||
struct ballot_state *existing_ballot;
|
||||
if (Ballot_Collection_get_ballot(external_identifier, &existing_ballot) == BALLOT_COLLECTION_ERROR_NOT_FOUND)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (existing_ballot == NULL)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
HASH_DEL(
|
||||
ballot_box,
|
||||
existing_ballot
|
||||
);
|
||||
|
||||
free(existing_ballot);
|
||||
existing_ballot = NULL;
|
||||
return BALLOT_COLLECTION_SUCCESS;
|
||||
}
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_remove_all()
|
||||
{
|
||||
struct ballot_state *existing_ballot, *tmp_ballot;
|
||||
|
||||
HASH_ITER(hh, ballot_box, existing_ballot, tmp_ballot)
|
||||
{
|
||||
HASH_DEL(ballot_box, existing_ballot);
|
||||
free(existing_ballot);
|
||||
}
|
||||
|
||||
return BALLOT_COLLECTION_SUCCESS;
|
||||
}
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_update(
|
||||
char *external_identifier, bool cast, bool spoiled, char **out_tracker)
|
||||
{
|
||||
if (cast == spoiled)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
struct ballot_state *new_ballot_state, *existing_ballot, *tmp = NULL;
|
||||
if (Ballot_Collection_get_ballot(external_identifier, &existing_ballot) == BALLOT_COLLECTION_ERROR_NOT_FOUND)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (existing_ballot == NULL)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
// verify that the existing_ballot is registered and not already cast or spoiled
|
||||
enum Ballot_Collection_result assert_can_mutuate = Ballot_Collection_assert_can_mutate_state(
|
||||
existing_ballot);
|
||||
if (assert_can_mutuate != BALLOT_COLLECTION_SUCCESS)
|
||||
{
|
||||
return assert_can_mutuate;
|
||||
}
|
||||
|
||||
// copy the existing state to the new state
|
||||
new_ballot_state = (struct ballot_state *)malloc(sizeof *new_ballot_state);
|
||||
if (new_ballot_state == NULL)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(new_ballot_state, existing_ballot, sizeof(ballot_state));
|
||||
new_ballot_state->cast = cast;
|
||||
new_ballot_state->spoiled = spoiled;
|
||||
|
||||
// replace the existing state with the new state
|
||||
HASH_DEL(
|
||||
ballot_box,
|
||||
existing_ballot
|
||||
);
|
||||
|
||||
free(existing_ballot);
|
||||
existing_ballot = NULL;
|
||||
|
||||
HASH_ADD_KEYPTR(
|
||||
hh,
|
||||
ballot_box,
|
||||
new_ballot_state->external_identifier,
|
||||
strlen(new_ballot_state->external_identifier),
|
||||
new_ballot_state
|
||||
);
|
||||
|
||||
// assign out parameter
|
||||
*out_tracker = new_ballot_state->tracker;
|
||||
|
||||
return BALLOT_COLLECTION_SUCCESS;
|
||||
}
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_assert_can_mutate_state(
|
||||
struct ballot_state *existing_ballot)
|
||||
{
|
||||
if (existing_ballot == NULL)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (existing_ballot->registered == false)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (existing_ballot->cast == true)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_ALREADY_CAST;
|
||||
}
|
||||
|
||||
if (existing_ballot->spoiled == true)
|
||||
{
|
||||
return BALLOT_COLLECTION_ERROR_ALREADY_SPOILED;
|
||||
}
|
||||
|
||||
return BALLOT_COLLECTION_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef __BALLOT_COLLECTION_H__
|
||||
#define __BALLOT_COLLECTION_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "uthash.h"
|
||||
|
||||
/**
|
||||
* Representation of a ballot in a ballot box
|
||||
*/
|
||||
typedef struct ballot_state {
|
||||
char *external_identifier;
|
||||
uint32_t registered_index;
|
||||
bool registered;
|
||||
bool cast;
|
||||
bool spoiled;
|
||||
char *tracker;
|
||||
UT_hash_handle hh;
|
||||
} ballot_state;
|
||||
|
||||
enum Ballot_Collection_result
|
||||
{
|
||||
BALLOT_COLLECTION_SUCCESS,
|
||||
BALLOT_COLLECTION_ERROR_ALREADY_REGISTERED,
|
||||
BALLOT_COLLECTION_ERROR_ALREADY_CAST,
|
||||
BALLOT_COLLECTION_ERROR_ALREADY_SPOILED,
|
||||
BALLOT_COLLECTION_ERROR_INSUFFICIENT_MEMORY,
|
||||
BALLOT_COLLECTION_ERROR_INVALID_ARGUMENT,
|
||||
BALLOT_COLLECTION_ERROR_NOT_FOUND,
|
||||
BALLOT_COLLECTION_ERROR_UNKNOWN
|
||||
};
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_new();
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_free();
|
||||
|
||||
uint32_t Ballot_Collection_size();
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_register_ballot(char *external_identifier, char *tracker, uint32_t registered_index);
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_mark_cast(char *external_identifier, char **out_tracker);
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_mark_spoiled(char *external_identifier, char **out_tracker);
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_get_ballot(char *external_identifier, struct ballot_state **ballot);
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_remove_ballot(char *external_identifier);
|
||||
|
||||
enum Ballot_Collection_result Ballot_Collection_remove_all();
|
||||
|
||||
|
||||
#endif /* __BALLOT_COLLECTION_H__ */
|
|
@ -8,221 +8,319 @@
|
|||
#include "serialize/crypto.h"
|
||||
#include "serialize/voting.h"
|
||||
#include "sha2-openbsd.h"
|
||||
#include "voting/ballot_collection.h"
|
||||
#include "voting/message_reps.h"
|
||||
#include "voting/num_ballots.h"
|
||||
|
||||
// @design jwaksbaum This implementation relies on the fact that the
|
||||
// Encrypters are generating uids from a shared counter, so we can
|
||||
// just store the ballots at the index of their uid and they will all
|
||||
// be contiguous. In a real implementation you would probably need a
|
||||
// hash table.
|
||||
// @design mwilhelm This implementation utilizes a hash table to keep
|
||||
// track of external ballot identifiers (strings) that are already
|
||||
// registered, cast, or spoiled. Additionally, to support low-memory
|
||||
// systems it also allows batch-processing when importing ballots.
|
||||
// there should only ever be one voting coordinator in memory on a system
|
||||
// and it should retain it's state through the ballot load and cast cycle
|
||||
|
||||
/**
|
||||
* The current state of a voting coordinator
|
||||
*/
|
||||
struct Voting_Coordinator_s
|
||||
{
|
||||
// The number of selections on each ballot
|
||||
// The number of selections available on each ballot
|
||||
uint32_t num_selections;
|
||||
struct encryption_rep *selections[MAX_BALLOTS];
|
||||
bool registered[MAX_BALLOTS];
|
||||
bool cast[MAX_BALLOTS];
|
||||
bool spoiled[MAX_BALLOTS];
|
||||
char *tracker[MAX_BALLOTS];
|
||||
|
||||
// count of ballots registered
|
||||
uint32_t registered_num_ballots;
|
||||
|
||||
// count of ballots in the buffer
|
||||
uint32_t buffered_num_ballots;
|
||||
|
||||
// external id buffer
|
||||
char *buffered_external_id[MAX_BALLOT_PAYLOAD];
|
||||
|
||||
// selections buffer
|
||||
struct encryption_rep *selections[MAX_BALLOT_PAYLOAD];
|
||||
};
|
||||
|
||||
static int Voting_Coordinator_ref_count = 0;
|
||||
|
||||
// use a static result as a singleton instance
|
||||
// since only one coordinator should exist
|
||||
// per application instance
|
||||
static struct Voting_Coordinator_new_r voting_coordinator_singleton;
|
||||
|
||||
struct Voting_Coordinator_new_r Voting_Coordinator_new(uint32_t num_selections)
|
||||
{
|
||||
struct Voting_Coordinator_new_r result;
|
||||
result.status = VOTING_COORDINATOR_SUCCESS;
|
||||
voting_coordinator_singleton.status = VOTING_COORDINATOR_SUCCESS;
|
||||
|
||||
// Allocate the ballot box
|
||||
result.coordinator = malloc(sizeof(struct Voting_Coordinator_s));
|
||||
if (result.coordinator == NULL)
|
||||
result.status = VOTING_COORDINATOR_INSUFFICIENT_MEMORY;
|
||||
|
||||
// Initialize the ballot box
|
||||
if (result.status == VOTING_COORDINATOR_SUCCESS)
|
||||
// sanity-check if the instance exists and matches this election configuration
|
||||
if (voting_coordinator_singleton.coordinator != NULL
|
||||
&& voting_coordinator_singleton.coordinator->num_selections == num_selections)
|
||||
{
|
||||
result.coordinator->num_selections = num_selections;
|
||||
memset(result.coordinator->registered, 0,
|
||||
sizeof(result.coordinator->registered));
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("\nVoting_Coordinator_new: already exists. Returning existing instance\n");
|
||||
#endif
|
||||
Voting_Coordinator_ref_count++;
|
||||
return voting_coordinator_singleton;
|
||||
}
|
||||
|
||||
return result;
|
||||
if (voting_coordinator_singleton.coordinator != NULL
|
||||
&& voting_coordinator_singleton.coordinator->num_selections != num_selections)
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("\nVoting_Coordinator_new: already exists for a different number of selections.\n");
|
||||
#endif
|
||||
struct Voting_Coordinator_new_r error_result;
|
||||
error_result.status = VOTING_COORDINATOR_ERROR_ALREADY_EXISTS;
|
||||
return error_result;
|
||||
}
|
||||
|
||||
// Allocate the instance
|
||||
voting_coordinator_singleton.coordinator = malloc(sizeof(struct Voting_Coordinator_s));
|
||||
if (voting_coordinator_singleton.coordinator == NULL)
|
||||
{
|
||||
voting_coordinator_singleton.status = VOTING_COORDINATOR_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
// Initialize the instance
|
||||
if (voting_coordinator_singleton.status == VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
voting_coordinator_singleton.coordinator->num_selections = num_selections;
|
||||
voting_coordinator_singleton.coordinator->registered_num_ballots = 0;
|
||||
voting_coordinator_singleton.coordinator->buffered_num_ballots = 0;
|
||||
|
||||
Ballot_Collection_new();
|
||||
|
||||
Voting_Coordinator_ref_count++;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("\nVoting_Coordinator_new: success!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
return voting_coordinator_singleton;
|
||||
}
|
||||
|
||||
void Voting_Coordinator_free(Voting_Coordinator ballot_box)
|
||||
enum Voting_Coordinator_status Voting_Coordinator_clear_buffer(Voting_Coordinator coordinator)
|
||||
{
|
||||
for(size_t i = 0; i < MAX_BALLOTS; i++)
|
||||
if (ballot_box->registered[i]) {
|
||||
for(uint32_t j=0; j<ballot_box->num_selections; j++){
|
||||
Crypto_encryption_rep_free(&ballot_box->selections[i][j]);
|
||||
for(uint32_t i = 0; i < coordinator->buffered_num_ballots; i++)
|
||||
{
|
||||
// clear the slections buffer
|
||||
if (coordinator->selections[i] != NULL)
|
||||
{
|
||||
for(uint32_t j = 0; j < coordinator->num_selections; j++)
|
||||
{
|
||||
Crypto_encryption_rep_free(&coordinator->selections[i][j]);
|
||||
}
|
||||
}
|
||||
free(ballot_box);
|
||||
|
||||
// clear references to buffered external_id's
|
||||
// but don't actually free the strings
|
||||
if (coordinator->buffered_external_id[i] != NULL)
|
||||
{
|
||||
coordinator->buffered_external_id[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
coordinator->buffered_num_ballots = 0;
|
||||
|
||||
return VOTING_COORDINATOR_SUCCESS;
|
||||
}
|
||||
|
||||
void Voting_Coordinator_free(Voting_Coordinator coordinator)
|
||||
{
|
||||
if (Voting_Coordinator_ref_count > 0)
|
||||
{
|
||||
Voting_Coordinator_ref_count--;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("\nVoting_Coordinator_free: active referneces: %u\n", Voting_Coordinator_ref_count);
|
||||
#endif
|
||||
|
||||
if (Voting_Coordinator_ref_count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Voting_Coordinator_clear_buffer(coordinator);
|
||||
Ballot_Collection_free();
|
||||
|
||||
coordinator->num_selections = 0;
|
||||
coordinator->buffered_num_ballots = 0;
|
||||
coordinator->registered_num_ballots = 0;
|
||||
|
||||
voting_coordinator_singleton.status = VOTING_COORDINATOR_SUCCESS;
|
||||
voting_coordinator_singleton.coordinator = NULL;
|
||||
|
||||
free(coordinator);
|
||||
}
|
||||
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_register_ballot(Voting_Coordinator c,
|
||||
struct register_ballot_message message)
|
||||
Voting_Coordinator_register_ballot(Voting_Coordinator coordinator,
|
||||
char *external_identifier,
|
||||
struct register_ballot_message message,
|
||||
char **out_ballot_tracker)
|
||||
{
|
||||
enum Voting_Coordinator_status status = VOTING_COORDINATOR_SUCCESS;
|
||||
// Verify the ballot does not already exist
|
||||
struct ballot_state *existing_ballot = NULL;
|
||||
if (Ballot_Collection_get_ballot(external_identifier, &existing_ballot
|
||||
) == BALLOT_COLLECTION_SUCCESS)
|
||||
{
|
||||
free(existing_ballot);
|
||||
return VOTING_COORDINATOR_DUPLICATE_BALLOT;
|
||||
}
|
||||
|
||||
struct encrypted_ballot_rep message_rep;
|
||||
// Verify we can load another ballot into the ballot state cache
|
||||
if (Ballot_Collection_size() >= MAX_BALLOTS)
|
||||
{
|
||||
return VOTING_COORDINATOR_INVALID_BALLOT_INDEX;
|
||||
}
|
||||
|
||||
// Verify we can load another ballot into the selections buffer cache
|
||||
if (coordinator->buffered_num_ballots >= MAX_BALLOT_PAYLOAD)
|
||||
{
|
||||
return VOTING_COORDINATOR_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
// Deserialize the message
|
||||
if (status == VOTING_COORDINATOR_SUCCESS)
|
||||
struct encrypted_ballot_rep message_rep;
|
||||
if (!Serialize_deserialize_register_ballot_message(&message, &message_rep))
|
||||
{
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_READING,
|
||||
.len = message.len,
|
||||
.offset = 0,
|
||||
.buf = (uint8_t *)message.bytes,
|
||||
};
|
||||
|
||||
Serialize_read_encrypted_ballot(&state, &message_rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_READING)
|
||||
status = VOTING_COORDINATOR_DESERIALIZE_ERROR;
|
||||
return VOTING_COORDINATOR_DESERIALIZE_ERROR;
|
||||
}
|
||||
|
||||
// Ensure we have space for another ballot
|
||||
if (status == VOTING_COORDINATOR_SUCCESS)
|
||||
// Verify the message content contains the correct number of selections
|
||||
if (message_rep.num_selections != coordinator->num_selections)
|
||||
{
|
||||
if (message_rep.id >= MAX_BALLOTS)
|
||||
status = VOTING_COORDINATOR_INVALID_BALLOT_ID;
|
||||
else if (c->registered[message_rep.id])
|
||||
status = VOTING_COORDINATOR_DUPLICATE_BALLOT;
|
||||
else if (message_rep.num_selections != c->num_selections)
|
||||
status = VOTING_COORDINATOR_INVALID_BALLOT;
|
||||
return VOTING_COORDINATOR_INVALID_BALLOT;
|
||||
}
|
||||
|
||||
if (status == VOTING_COORDINATOR_SUCCESS)
|
||||
// Reconstruct the ballot tracker
|
||||
SHA2_CTX context;
|
||||
uint8_t *digest_buffer = malloc(sizeof(uint8_t) * SHA256_DIGEST_LENGTH);
|
||||
if (digest_buffer == NULL)
|
||||
{
|
||||
// Move the ballot into the ballot box state
|
||||
c->selections[message_rep.id] = message_rep.selections;
|
||||
// handle insufficient memory error
|
||||
return VOTING_COORDINATOR_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
// Mark it as registered but unspoiled and uncast
|
||||
c->registered[message_rep.id] = true;
|
||||
c->cast[message_rep.id] = false;
|
||||
c->spoiled[message_rep.id] = false;
|
||||
SHA256Init(&context);
|
||||
SHA256Update(&context, message.bytes, message.len);
|
||||
SHA256Final(digest_buffer, &context);
|
||||
|
||||
// Reconstruct the ballot tracker
|
||||
SHA2_CTX context;
|
||||
uint8_t *digest_buffer = malloc(sizeof(uint8_t) * SHA256_DIGEST_LENGTH);
|
||||
SHA256Init(&context);
|
||||
SHA256Update(&context, message.bytes, message.len);
|
||||
SHA256Final(digest_buffer, &context);
|
||||
struct ballot_tracker tracker = {
|
||||
.len = SHA256_DIGEST_LENGTH,
|
||||
.bytes = digest_buffer,
|
||||
};
|
||||
struct ballot_tracker tracker = {
|
||||
.len = SHA256_DIGEST_LENGTH,
|
||||
.bytes = digest_buffer,
|
||||
};
|
||||
|
||||
c->tracker[message_rep.id] = display_ballot_tracker(tracker);
|
||||
*out_ballot_tracker = display_ballot_tracker(tracker);
|
||||
|
||||
// clear the tracker message
|
||||
if (tracker.bytes != NULL)
|
||||
{
|
||||
free((void *)tracker.bytes);
|
||||
tracker.bytes = NULL;
|
||||
}
|
||||
|
||||
// Move the ballot into the ballot box state (registered)
|
||||
if (Ballot_Collection_register_ballot(
|
||||
external_identifier, *out_ballot_tracker, coordinator->registered_num_ballots
|
||||
) != BALLOT_COLLECTION_SUCCESS)
|
||||
{
|
||||
// note: case alrady handled with Ballot_Collection_get_ballot,
|
||||
// however we respect the failure return response from Ballot collection
|
||||
// by returning a non-duplicated failure case
|
||||
return VOTING_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
|
||||
// cache a handle to the external id for lookups
|
||||
coordinator->buffered_external_id[coordinator->buffered_num_ballots] = external_identifier;
|
||||
|
||||
// cache the ballot selections in the buffer
|
||||
coordinator->selections[coordinator->buffered_num_ballots] = message_rep.selections;
|
||||
|
||||
if (tracker.bytes != NULL)
|
||||
{
|
||||
free((void *)tracker.bytes);
|
||||
tracker.bytes = NULL;
|
||||
}
|
||||
}
|
||||
coordinator->registered_num_ballots++;
|
||||
coordinator->buffered_num_ballots++;
|
||||
|
||||
return status;
|
||||
return VOTING_COORDINATOR_SUCCESS;
|
||||
}
|
||||
|
||||
static enum Voting_Coordinator_status
|
||||
Voting_Coordinator_assert_registered(Voting_Coordinator coordinator,
|
||||
struct ballot_identifier ballot_id,
|
||||
uint64_t *i)
|
||||
char *external_identifier)
|
||||
{
|
||||
enum Voting_Coordinator_status result = VOTING_COORDINATOR_SUCCESS;
|
||||
struct ballot_state *existing_ballot = NULL;
|
||||
if (Ballot_Collection_get_ballot(external_identifier, &existing_ballot) != BALLOT_COLLECTION_SUCCESS)
|
||||
{
|
||||
return VOTING_COORDINATOR_UNREGISTERED_BALLOT;
|
||||
}
|
||||
|
||||
// Check that the bytes look like what we think a ballot
|
||||
// identifier should be
|
||||
if (ballot_id.len != sizeof(uint64_t))
|
||||
result = VOTING_COORDINATOR_INVALID_BALLOT_ID;
|
||||
if (existing_ballot->cast || existing_ballot->spoiled)
|
||||
{
|
||||
return VOTING_COORDINATOR_DUPLICATE_BALLOT;
|
||||
}
|
||||
|
||||
// "Deserialize" the ballot identifier
|
||||
if (result == VOTING_COORDINATOR_SUCCESS)
|
||||
memcpy(i, ballot_id.bytes, ballot_id.len);
|
||||
|
||||
// Verify that the ballot identifier is a valid index
|
||||
if (result == VOTING_COORDINATOR_SUCCESS)
|
||||
if (*i >= Voting_num_ballots)
|
||||
result = VOTING_COORDINATOR_INVALID_BALLOT_ID;
|
||||
|
||||
// Verify that the ballot is registered
|
||||
if (result == VOTING_COORDINATOR_SUCCESS)
|
||||
if (!coordinator->registered[*i])
|
||||
result = VOTING_COORDINATOR_UNREGISTERED_BALLOT;
|
||||
|
||||
// Check that the ballot isn't already cast or spoiled
|
||||
if (result == VOTING_COORDINATOR_SUCCESS)
|
||||
//@ assert ballot_box->ballot_ids[i] == ballot->ballot_id;
|
||||
if (coordinator->cast[*i] || coordinator->spoiled[*i])
|
||||
result = VOTING_COORDINATOR_DUPLICATE_BALLOT;
|
||||
|
||||
return result;
|
||||
return VOTING_COORDINATOR_SUCCESS;
|
||||
}
|
||||
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_cast_ballot(Voting_Coordinator coordinator,
|
||||
struct ballot_identifier ballot_id)
|
||||
char *external_identifier, char **out_tracker)
|
||||
{
|
||||
uint64_t i;
|
||||
enum Ballot_Collection_result result = Ballot_Collection_mark_cast(
|
||||
external_identifier, out_tracker);
|
||||
if (result == BALLOT_COLLECTION_SUCCESS)
|
||||
{
|
||||
return VOTING_COORDINATOR_SUCCESS;
|
||||
}
|
||||
|
||||
enum Voting_Coordinator_status result =
|
||||
Voting_Coordinator_assert_registered(coordinator, ballot_id, &i);
|
||||
|
||||
// Mark the ballot as cast
|
||||
if (result == VOTING_COORDINATOR_SUCCESS)
|
||||
coordinator->cast[i] = true;
|
||||
|
||||
return result;
|
||||
// TODO: map Ballot Colection enums to Voting Coordinator Enums
|
||||
return VOTING_COORDINATOR_INVALID_BALLOT;
|
||||
}
|
||||
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_spoil_ballot(Voting_Coordinator coordinator,
|
||||
struct ballot_identifier ballot_id)
|
||||
char *external_identifier, char **out_tracker)
|
||||
{
|
||||
uint64_t i;
|
||||
enum Ballot_Collection_result result = Ballot_Collection_mark_spoiled(
|
||||
external_identifier, out_tracker);
|
||||
if (result == BALLOT_COLLECTION_SUCCESS)
|
||||
{
|
||||
return VOTING_COORDINATOR_SUCCESS;
|
||||
}
|
||||
|
||||
enum Voting_Coordinator_status result =
|
||||
Voting_Coordinator_assert_registered(coordinator, ballot_id, &i);
|
||||
|
||||
// Mark the ballot as cast
|
||||
if (result == VOTING_COORDINATOR_SUCCESS)
|
||||
coordinator->spoiled[i] = true;
|
||||
|
||||
return result;
|
||||
// TODO: map Ballot Colection enums to Voting Coordinator Enums
|
||||
return VOTING_COORDINATOR_INVALID_BALLOT;
|
||||
}
|
||||
|
||||
char *Voting_Coordinator_get_tracker(Voting_Coordinator coordinator,
|
||||
struct ballot_identifier ballot_id)
|
||||
char *external_identifier)
|
||||
{
|
||||
uint64_t i;
|
||||
struct ballot_state *existing_ballot = NULL;
|
||||
if (Ballot_Collection_get_ballot(external_identifier, &existing_ballot
|
||||
) != BALLOT_COLLECTION_SUCCESS)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum Voting_Coordinator_status result =
|
||||
Voting_Coordinator_assert_registered(coordinator, ballot_id, &i);
|
||||
|
||||
return coordinator->tracker[i];
|
||||
char *result = existing_ballot->tracker;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Write a single ballot to out, using the format
|
||||
/* Write a single ballot to the out file to be imported for decryption, using the format
|
||||
<cast> TAB <id> TAB <selection1> ... \n
|
||||
*/
|
||||
static enum Voting_Coordinator_status
|
||||
Voting_Coordinator_write_ballot(FILE *out, uint64_t ballot_id, bool cast,
|
||||
Voting_Coordinator_write_ballot(FILE *out, uint32_t registered_ballot_index, bool cast,
|
||||
uint32_t num_selections, struct encryption_rep *selections)
|
||||
{
|
||||
enum Voting_Coordinator_status status = VOTING_COORDINATOR_SUCCESS;
|
||||
|
||||
// Write the fixed-length part of the line, ie. everything but the
|
||||
// selections
|
||||
{
|
||||
const char *header_fmt = "%d\t%" PRIu64;
|
||||
int io_status = fprintf(out, header_fmt, cast, ballot_id);
|
||||
if (io_status < 0)
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
// Write the fixed-length part of the line,
|
||||
// ie. everything but the selections
|
||||
const char *header_fmt = "%d\t%" PRIu32;
|
||||
int io_status = fprintf(out, header_fmt, cast, registered_ballot_index);
|
||||
if (io_status < 0)
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
|
||||
|
||||
// Write the selections
|
||||
for (uint32_t i = 0;
|
||||
|
@ -248,14 +346,14 @@ Voting_Coordinator_write_ballot(FILE *out, uint64_t ballot_id, bool cast,
|
|||
return status;
|
||||
}
|
||||
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_export_ballots(Voting_Coordinator c, FILE *out)
|
||||
static enum Voting_Coordinator_status
|
||||
Voting_Coordinator_write_ballots_file_header(Voting_Coordinator coordinator, FILE *out)
|
||||
{
|
||||
enum Voting_Coordinator_status status = VOTING_COORDINATOR_SUCCESS;
|
||||
|
||||
// Write the first line containing the number of ballots
|
||||
{
|
||||
int io_status = fprintf(out, "%" PRIu64 "\n", Voting_num_ballots);
|
||||
int io_status = fprintf(out, "%" PRIu32 "\n", coordinator->registered_num_ballots);
|
||||
if (io_status < 0)
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
|
@ -263,16 +361,239 @@ Voting_Coordinator_export_ballots(Voting_Coordinator c, FILE *out)
|
|||
// Write the second line containing the number of selections per ballot
|
||||
if (status == VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
int io_status = fprintf(out, "%" PRIu32 "\n", c->num_selections);
|
||||
int io_status = fprintf(out, "%" PRIu32 "\n", coordinator->num_selections);
|
||||
if (io_status < 0)
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_export_buffered_ballots(Voting_Coordinator coordinator, FILE *out)
|
||||
{
|
||||
enum Voting_Coordinator_status status = VOTING_COORDINATOR_SUCCESS;
|
||||
|
||||
// ensure the file cursor is at the beginning
|
||||
int seek_status = fseek(out, 0L, SEEK_SET);
|
||||
|
||||
// write the header
|
||||
status = Voting_Coordinator_write_ballots_file_header(coordinator, out);
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
// flush the write buffer before reading the file
|
||||
fflush(out);
|
||||
|
||||
// seek to the end of the file
|
||||
int character, number_of_ballots_written = 0;
|
||||
while ((character = fgetc(out)) != EOF)
|
||||
{
|
||||
if (character == '\n')
|
||||
{
|
||||
number_of_ballots_written++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t registered_ballot_index = number_of_ballots_written;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("\nVoting_Coordinator_export: writing out %u ballots\n\n", coordinator->buffered_num_ballots);
|
||||
#endif
|
||||
|
||||
// Write each ballot
|
||||
for (uint64_t i = 0;
|
||||
i < Voting_num_ballots && status == VOTING_COORDINATOR_SUCCESS; i++)
|
||||
for (uint32_t i = 0;
|
||||
i < coordinator->buffered_num_ballots && status == VOTING_COORDINATOR_SUCCESS;
|
||||
i++)
|
||||
{
|
||||
struct ballot_state *ballot_state = NULL;
|
||||
if (Ballot_Collection_get_ballot(
|
||||
coordinator->buffered_external_id[i], &ballot_state
|
||||
) != BALLOT_COLLECTION_SUCCESS)
|
||||
{
|
||||
printf("\n could not find in cache: %s\n", coordinator->buffered_external_id[i]);
|
||||
return status = VOTING_COORDINATOR_INVALID_BALLOT_ID;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("Voting_Coordinator_export: id: %s registered: %d cast: %d spoiled: %d\n",
|
||||
ballot_state->external_identifier, ballot_state->registered, ballot_state->cast, ballot_state->spoiled);
|
||||
#endif
|
||||
|
||||
status = Voting_Coordinator_write_ballot(
|
||||
out, i, c->cast[i], c->num_selections, c->selections[i]);
|
||||
out,
|
||||
registered_ballot_index,
|
||||
ballot_state->cast,
|
||||
coordinator->num_selections,
|
||||
coordinator->selections[i]
|
||||
);
|
||||
|
||||
registered_ballot_index++;
|
||||
}
|
||||
|
||||
// clear the selections buffer
|
||||
status = Voting_Coordinator_clear_buffer(coordinator);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum Voting_Coordinator_status
|
||||
Voting_Coordinator_read_ballot(FILE *in,
|
||||
uint32_t num_selections,
|
||||
char *out_external_identifier,
|
||||
struct encryption_rep *out_selections)
|
||||
{
|
||||
enum Voting_Coordinator_status status = VOTING_COORDINATOR_SUCCESS;
|
||||
|
||||
// get the external ballot Id
|
||||
{
|
||||
int num_read = fscanf(in, "%s", out_external_identifier);
|
||||
if (num_read == EOF)
|
||||
{
|
||||
status = VOTING_COORDINATOR_END_OF_FILE;
|
||||
}
|
||||
else if (num_read != 1)
|
||||
{
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0;
|
||||
i < num_selections && status == VOTING_COORDINATOR_SUCCESS; i++)
|
||||
{
|
||||
// read the nonce encoding
|
||||
int num_read = fscanf(in, "\t(");
|
||||
if (0 != num_read)
|
||||
{
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
|
||||
if (status == VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
if (!mpz_t_fscan(in, out_selections[i].nonce_encoding))
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
|
||||
// move the cursor to the separator
|
||||
if (status == VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
num_read = fscanf(in, ",");
|
||||
if (0 != num_read)
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
|
||||
// read the message encoding
|
||||
if (status == VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
if (!mpz_t_fscan(in, out_selections[i].message_encoding))
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
|
||||
if (status == VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
num_read = fscanf(in, ")");
|
||||
if (0 != num_read)
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_import_encrypted_ballots(Voting_Coordinator coordinator,
|
||||
uint64_t start_index,
|
||||
uint64_t count,
|
||||
uint32_t num_selections,
|
||||
FILE *in,
|
||||
char **out_external_identifiers,
|
||||
struct register_ballot_message *out_messages)
|
||||
{
|
||||
enum Voting_Coordinator_status status = VOTING_COORDINATOR_SUCCESS;
|
||||
|
||||
// start at the index
|
||||
if (in == NULL || fseek(in, start_index, SEEK_SET) != 0) {
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("Voting_Coordinator_import_encrypted_ballots: attempting to import: %ld\n", count);
|
||||
#endif
|
||||
|
||||
int scanResult = 0;
|
||||
enum Voting_Coordinator_status load_status = VOTING_COORDINATOR_SUCCESS;
|
||||
|
||||
for (uint32_t i = 0; i < count && load_status == VOTING_COORDINATOR_SUCCESS; i++) {
|
||||
|
||||
out_external_identifiers[i] = malloc(MAX_EXTERNAL_ID_LENGTH*sizeof(char));
|
||||
if (out_external_identifiers[i] == NULL)
|
||||
{
|
||||
load_status = VOTING_COORDINATOR_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
// create an encryption representation
|
||||
struct encryption_rep selections[num_selections];
|
||||
for (int j = 0; j < num_selections; j++)
|
||||
{
|
||||
Crypto_encryption_rep_new(&selections[j]);
|
||||
}
|
||||
|
||||
// load the data from the row in the file
|
||||
load_status = Voting_Coordinator_read_ballot(
|
||||
in,
|
||||
num_selections,
|
||||
out_external_identifiers[i],
|
||||
selections);
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("Voting_Coordinator_import_encrypted_ballots: imported: %s\n", out_external_identifiers[i]);
|
||||
#endif
|
||||
|
||||
// reconstruct the original register_ballot_message
|
||||
struct encrypted_ballot_rep encrypted_ballot;
|
||||
struct Crypto_encrypted_ballot_new_r result =
|
||||
Crypto_encrypted_ballot_new(num_selections, i);
|
||||
encrypted_ballot = result.result;
|
||||
|
||||
// TODO: check/convert status from result
|
||||
|
||||
encrypted_ballot.selections = selections;
|
||||
|
||||
// serialize the encrypted ballot
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_RESERVING,
|
||||
.len = 0,
|
||||
.offset = 0,
|
||||
.buf = NULL
|
||||
};
|
||||
|
||||
Serialize_reserve_encrypted_ballot(&state, &encrypted_ballot);
|
||||
Serialize_allocate(&state);
|
||||
Serialize_write_encrypted_ballot(&state, &encrypted_ballot);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
status = VOTING_COORDINATOR_SERIALIZE_ERROR;
|
||||
else
|
||||
{
|
||||
// add the serialization to message_out
|
||||
struct register_ballot_message scanned_message = (struct register_ballot_message)
|
||||
{
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
|
||||
out_messages[start_index + scanResult] = scanned_message;
|
||||
}
|
||||
|
||||
// clean up
|
||||
// TODO: free encryption rep?
|
||||
|
||||
scanResult++;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
#include "serialize/voting.h"
|
||||
#include "sha2-openbsd.h"
|
||||
#include "voting/message_reps.h"
|
||||
#include "voting/num_ballots.h"
|
||||
|
||||
uint64_t Voting_num_ballots = 0;
|
||||
// count of ballots encrypted with this encrypter
|
||||
uint64_t _encrypted_ballot_count = 0;
|
||||
|
||||
struct Voting_Encrypter_s
|
||||
{
|
||||
|
@ -174,22 +174,32 @@ bool Validate_selections(bool const *selections, uint32_t num_selections, uint32
|
|||
}
|
||||
return count == expected_num_selected ? true : false;
|
||||
}
|
||||
|
||||
struct Voting_Encrypter_encrypt_ballot_r
|
||||
Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter,
|
||||
char *external_identifier,
|
||||
bool const *selections,
|
||||
uint32_t expected_num_selected)
|
||||
{
|
||||
|
||||
struct Voting_Encrypter_encrypt_ballot_r balotR;
|
||||
balotR.status = VOTING_ENCRYPTER_SUCCESS;
|
||||
// TODO: associate the external_identifier with the internal one, possibly via hash
|
||||
|
||||
uint64_t internal_ballot_id = _encrypted_ballot_count;
|
||||
struct Voting_Encrypter_encrypt_ballot_r ballot_result;
|
||||
ballot_result.status = VOTING_ENCRYPTER_SUCCESS;
|
||||
|
||||
// validate selection
|
||||
if (!Validate_selections(selections, encrypter->num_selections, expected_num_selected))
|
||||
balotR.status = VOTING_ENCRYPTER_SELECTION_ERROR;
|
||||
if (balotR.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
// Construct the ballot id
|
||||
{
|
||||
struct ballot_identifier_rep rep = {.id = Voting_num_ballots};
|
||||
ballot_result.status = VOTING_ENCRYPTER_SELECTION_ERROR;
|
||||
}
|
||||
|
||||
// TODO: refactor this since this block exists in record_ballots.c
|
||||
// Construct the ballot id
|
||||
if (ballot_result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
struct ballot_identifier_rep rep = {
|
||||
.id = internal_ballot_id
|
||||
};
|
||||
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_RESERVING,
|
||||
|
@ -203,10 +213,13 @@ Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter,
|
|||
Serialize_write_ballot_identifier(&state, &rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
balotR.status = VOTING_ENCRYPTER_SERIALIZE_ERROR;
|
||||
{
|
||||
ballot_result.status = VOTING_ENCRYPTER_SERIALIZE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
balotR.id = (struct ballot_identifier){
|
||||
ballot_result.id = (struct ballot_identifier)
|
||||
{
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
|
@ -214,17 +227,22 @@ Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter,
|
|||
}
|
||||
|
||||
// Construct the message
|
||||
// TODO: refactor this out as it is similar to the one in coordinator.c
|
||||
struct encrypted_ballot_rep encrypted_ballot;
|
||||
if (balotR.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
if (ballot_result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
struct Crypto_encrypted_ballot_new_r result =
|
||||
// TODO: verify that _encrypted_ballot_count can be duplicated in a single file
|
||||
// but not in a single instance
|
||||
struct Crypto_encrypted_ballot_new_r temp_result =
|
||||
Crypto_encrypted_ballot_new(encrypter->num_selections,
|
||||
Voting_num_ballots);
|
||||
encrypted_ballot = result.result;
|
||||
balotR.status = Voting_Encrypter_Crypto_status_convert(result.status);
|
||||
internal_ballot_id);
|
||||
encrypted_ballot = temp_result.result;
|
||||
|
||||
// TODO: use this pattern for swith/case conversions?
|
||||
ballot_result.status = Voting_Encrypter_Crypto_status_convert(temp_result.status);
|
||||
}
|
||||
|
||||
if (balotR.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
if (ballot_result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
struct encryption_rep tally;
|
||||
Crypto_encryption_rep_new(&tally);
|
||||
|
@ -234,14 +252,22 @@ Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter,
|
|||
mpz_init(nonce);
|
||||
mpz_init(aggregate_nonce);
|
||||
|
||||
// encrypt the ballot
|
||||
for (uint32_t i = 0; i < encrypter->num_selections; i++)
|
||||
{
|
||||
Crypto_encrypt(
|
||||
&encrypted_ballot.selections[i], nonce, encrypter->source,
|
||||
&encrypted_ballot.selections[i],
|
||||
nonce,
|
||||
encrypter->source,
|
||||
&encrypter->joint_key,
|
||||
selections[i] ? generator /*g^1*/ : bignum_one /*g^0*/);
|
||||
Crypto_encryption_homomorphic_add(&tally, &tally,
|
||||
&encrypted_ballot.selections[i]);
|
||||
selections[i]
|
||||
? generator /*g^1*/
|
||||
: bignum_one /*g^0*/
|
||||
);
|
||||
|
||||
Crypto_encryption_homomorphic_add(
|
||||
&tally, &tally, &encrypted_ballot.selections[i]);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
mpz_set(aggregate_nonce, nonce);
|
||||
|
@ -250,55 +276,76 @@ Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter,
|
|||
{
|
||||
add_mod_q(aggregate_nonce, aggregate_nonce, nonce);
|
||||
}
|
||||
|
||||
Crypto_generate_dis_proof(&encrypted_ballot.dis_proof[i],
|
||||
encrypter->source, encrypter->base_hash,
|
||||
encrypter->source,
|
||||
encrypter->base_hash,
|
||||
selections[i],
|
||||
encrypter->joint_key.public_key,
|
||||
encrypted_ballot.selections[i], nonce);
|
||||
encrypted_ballot.selections[i],
|
||||
nonce);
|
||||
if (!Crypto_check_dis_proof(encrypted_ballot.dis_proof[i],
|
||||
encrypted_ballot.selections[i],
|
||||
encrypter->base_hash,
|
||||
encrypter->joint_key.public_key))
|
||||
{
|
||||
balotR.status = VOTING_ENCRYPTER_UNKNOWN_ERROR;
|
||||
ballot_result.status = VOTING_ENCRYPTER_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
Crypto_generate_aggregate_cp_proof(
|
||||
&encrypted_ballot.cp_proof, encrypter->source, aggregate_nonce,
|
||||
tally, encrypter->base_hash, encrypter->joint_key.public_key);
|
||||
&encrypted_ballot.cp_proof,
|
||||
encrypter->source, aggregate_nonce,
|
||||
tally, encrypter->base_hash,
|
||||
encrypter->joint_key.public_key
|
||||
);
|
||||
|
||||
if (!Crypto_check_aggregate_cp_proof(encrypted_ballot.cp_proof, tally,
|
||||
encrypter->base_hash,
|
||||
encrypter->joint_key.public_key,
|
||||
expected_num_selected))
|
||||
{
|
||||
balotR.status = VOTING_ENCRYPTER_UNKNOWN_ERROR;
|
||||
ballot_result.status = VOTING_ENCRYPTER_UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
mpz_clear(nonce);
|
||||
mpz_clear(aggregate_nonce);
|
||||
Crypto_encryption_rep_free(&tally);
|
||||
struct serialize_state state = {.status = SERIALIZE_STATE_RESERVING,
|
||||
.len = 0,
|
||||
.offset = 0,
|
||||
.buf = NULL};
|
||||
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_RESERVING,
|
||||
.len = 0,
|
||||
.offset = 0,
|
||||
.buf = NULL
|
||||
};
|
||||
|
||||
Serialize_reserve_encrypted_ballot(&state, &encrypted_ballot);
|
||||
Serialize_allocate(&state);
|
||||
Serialize_write_encrypted_ballot(&state, &encrypted_ballot);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
balotR.status = VOTING_ENCRYPTER_SERIALIZE_ERROR;
|
||||
ballot_result.status = VOTING_ENCRYPTER_SERIALIZE_ERROR;
|
||||
else
|
||||
{
|
||||
balotR.message = (struct register_ballot_message){
|
||||
ballot_result.message = (struct register_ballot_message)
|
||||
{
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
}
|
||||
//TODO clear proofs and encrypted ballot
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Voting_Encrypter_encrypt_ballot: ERROR! encrypting ballot");
|
||||
}
|
||||
|
||||
// clear proofs and encrypted ballot
|
||||
Crypto_encrypted_ballot_free(&encrypted_ballot);
|
||||
|
||||
// TODO: clear temp_result
|
||||
|
||||
// Construct the ballot tracker
|
||||
if (balotR.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
if (ballot_result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
SHA2_CTX context;
|
||||
uint8_t *digest_buffer = malloc(sizeof(uint8_t) * SHA256_DIGEST_LENGTH);
|
||||
|
@ -306,22 +353,87 @@ Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter,
|
|||
if (digest_buffer == NULL)
|
||||
{
|
||||
// handle insufficient memory error
|
||||
balotR.status = VOTING_ENCRYPTER_INSUFFICIENT_MEMORY;
|
||||
return balotR;
|
||||
ballot_result.status = VOTING_ENCRYPTER_INSUFFICIENT_MEMORY;
|
||||
return ballot_result;
|
||||
}
|
||||
|
||||
SHA256Init(&context);
|
||||
SHA256Update(&context, balotR.message.bytes, balotR.message.len);
|
||||
SHA256Update(&context, ballot_result.message.bytes, ballot_result.message.len);
|
||||
SHA256Final(digest_buffer, &context);
|
||||
|
||||
balotR.tracker = (struct ballot_tracker){
|
||||
ballot_result.tracker = (struct ballot_tracker)
|
||||
{
|
||||
.len = SHA256_DIGEST_LENGTH,
|
||||
.bytes = digest_buffer,
|
||||
};
|
||||
}
|
||||
|
||||
if (balotR.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
Voting_num_ballots++;
|
||||
if (ballot_result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
_encrypted_ballot_count++;
|
||||
|
||||
return balotR;
|
||||
return ballot_result;
|
||||
}
|
||||
|
||||
enum Voting_Encrypter_status
|
||||
Voting_Encrypter_write_ballot(FILE *out, char *external_identifier,
|
||||
struct register_ballot_message *encrypted_ballot_message)
|
||||
{
|
||||
enum Voting_Encrypter_status status = VOTING_ENCRYPTER_SUCCESS;
|
||||
|
||||
// TODO: dedupe this code. it is here, and in a few other places
|
||||
struct encrypted_ballot_rep message_rep;
|
||||
|
||||
// Deserialize the message
|
||||
if (status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_READING,
|
||||
.len = encrypted_ballot_message->len,
|
||||
.offset = 0,
|
||||
.buf = (uint8_t *)encrypted_ballot_message->bytes,
|
||||
};
|
||||
|
||||
Serialize_read_encrypted_ballot(&state, &message_rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_READING)
|
||||
status = VOTING_ENCRYPTER_DESERIALIZE_ERROR;
|
||||
}
|
||||
|
||||
// Write the fixed length part of the line
|
||||
{
|
||||
const char *header_fmt = "%s\t";
|
||||
int io_status = fprintf(out, header_fmt, external_identifier);
|
||||
if (io_status < 0)
|
||||
status = VOTING_ENCRYPTER_IO_ERROR;
|
||||
}
|
||||
|
||||
// Write the selections
|
||||
for (uint32_t i = 0;
|
||||
i < message_rep.num_selections && status == VOTING_ENCRYPTER_SUCCESS; i++) {
|
||||
if(fprintf(out, "\t") < 1)
|
||||
status = VOTING_ENCRYPTER_IO_ERROR;
|
||||
|
||||
if(VOTING_ENCRYPTER_SUCCESS == status) {
|
||||
if(!Crypto_encryption_fprint(out, &message_rep.selections[i])) {
|
||||
status = VOTING_ENCRYPTER_IO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write the newline
|
||||
if (status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
int put_status = fputc('\n', out);
|
||||
if (put_status == EOF)
|
||||
status = VOTING_ENCRYPTER_IO_ERROR;
|
||||
}
|
||||
|
||||
// free the ballot rep
|
||||
for (uint32_t i = 0; i < message_rep.num_selections; i++)
|
||||
{
|
||||
Crypto_encryption_rep_free(&message_rep.selections[i]);
|
||||
}
|
||||
free(message_rep.selections);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <electionguard/max_values.h>
|
||||
#include <electionguard/voting/messages.h>
|
||||
|
||||
struct ballot_tracker_rep
|
||||
{
|
||||
uint64_t id;
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
#include <electionguard/voting/messages.h>
|
||||
#include <gmp.h>
|
||||
#include "serialize/voting.h"
|
||||
|
||||
bool Messages_are_equal(struct register_ballot_message *left_message, struct register_ballot_message *right_message)
|
||||
{
|
||||
bool ok = true;
|
||||
struct encrypted_ballot_rep left_ballot_rep;
|
||||
ok = Serialize_deserialize_register_ballot_message(left_message, &left_ballot_rep);
|
||||
|
||||
struct encrypted_ballot_rep right_vallot_rep;
|
||||
ok = Serialize_deserialize_register_ballot_message(right_message, &right_vallot_rep);
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("\nMessages_are_equal: comparing left_id %lu right_id: %lu:",
|
||||
left_ballot_rep.id, right_vallot_rep.id);
|
||||
#endif
|
||||
|
||||
ok = left_ballot_rep.id == right_vallot_rep.id
|
||||
&& left_ballot_rep.num_selections == right_vallot_rep.num_selections;
|
||||
|
||||
if (ok)
|
||||
{
|
||||
for (uint32_t i = 0; i < left_ballot_rep.num_selections && ok; i++)
|
||||
{
|
||||
bool comp_nonce = mpz_cmp(
|
||||
left_ballot_rep.selections[i].nonce_encoding,
|
||||
right_vallot_rep.selections[i].nonce_encoding
|
||||
) == 0;
|
||||
|
||||
bool comp_msg = mpz_cmp(
|
||||
left_ballot_rep.selections[i].message_encoding,
|
||||
right_vallot_rep.selections[i].message_encoding
|
||||
) == 0;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
|
||||
if (!comp_nonce)
|
||||
{
|
||||
printf("\nMessages_are_equal: ERROR! nonce_encoding did not match! :\n");
|
||||
print_base16(left_ballot_rep.selections[i].nonce_encoding);
|
||||
print_base16(right_vallot_rep.selections[i].nonce_encoding);
|
||||
}
|
||||
|
||||
if (!comp_msg)
|
||||
{
|
||||
printf("\nMessages_are_equal: ERROR! message_encoding did not match! :\n");
|
||||
print_base16(left_ballot_rep.selections[i].message_encoding);
|
||||
print_base16(right_vallot_rep.selections[i].message_encoding);
|
||||
}
|
||||
#endif
|
||||
ok = comp_nonce && comp_msg;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("\nMessage_are_equal: false!\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef __VOTING_NUM_BALLOTS_H__
|
||||
#define __VOTING_NUM_BALLOTS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// A hacky way to ensure unique ballot ids for now
|
||||
extern uint64_t Voting_num_ballots;
|
||||
|
||||
#endif /* __VOTING_NUM_BALLOTS_H__ */
|
|
@ -8,22 +8,26 @@
|
|||
|
||||
const char chars[16] = "2346789BCDFGHJKM";
|
||||
|
||||
char const *display_noun(uint8_t a, uint8_t b) {
|
||||
char const *display_noun(uint8_t a, uint8_t b)
|
||||
{
|
||||
return get_noun((uint16_t)a*16 + (b>>4));
|
||||
}
|
||||
|
||||
size_t chunk_len(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
||||
size_t chunk_len(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
|
||||
{
|
||||
// c and d aren't used; they're included in the argument list for consistency with display_chunk
|
||||
(void)c; (void)d;
|
||||
|
||||
return strlen(display_noun(a, b)) + 5/* hex digits */ + 2/* spaces */;
|
||||
}
|
||||
|
||||
size_t display_chunk(char *out, size_t out_len, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
||||
size_t display_chunk(char *out, size_t out_len, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
|
||||
{
|
||||
char const *noun = display_noun(a, b);
|
||||
const size_t noun_len = strlen(noun);
|
||||
const size_t space_used = noun_len + 5/* hex digits */ + 2/* spaces */;
|
||||
assert(space_used <= out_len);
|
||||
|
||||
memcpy(out, noun, noun_len);
|
||||
out[noun_len+0] = ' ';
|
||||
out[noun_len+1] = chars[(b & 0x0f) >> 0];
|
||||
|
@ -35,12 +39,22 @@ size_t display_chunk(char *out, size_t out_len, uint8_t a, uint8_t b, uint8_t c,
|
|||
return space_used;
|
||||
}
|
||||
|
||||
char *display_ballot_tracker(struct ballot_tracker tracker) {
|
||||
char *display_ballot_tracker(struct ballot_tracker tracker)
|
||||
{
|
||||
// First compute how much space we need to allocate.
|
||||
size_t len = 0, i;
|
||||
for(i = 0; i+3 < tracker.len; i += 4)
|
||||
len += chunk_len(tracker.bytes[i], tracker.bytes[i+1], tracker.bytes[i+2], tracker.bytes[i+3]);
|
||||
if(i < tracker.len) {
|
||||
{
|
||||
len += chunk_len(
|
||||
tracker.bytes[i],
|
||||
tracker.bytes[i+1],
|
||||
tracker.bytes[i+2],
|
||||
tracker.bytes[i+3]
|
||||
);
|
||||
}
|
||||
|
||||
if(i < tracker.len)
|
||||
{
|
||||
const size_t remaining = tracker.len - i;
|
||||
len += chunk_len(
|
||||
remaining > 0 ? tracker.bytes[i+0] : 0,
|
||||
|
@ -57,18 +71,33 @@ char *display_ballot_tracker(struct ballot_tracker tracker) {
|
|||
// Now fill the space.
|
||||
size_t cur_idx = 0;
|
||||
for(i = 0; i+3 < tracker.len; i += 4)
|
||||
cur_idx += display_chunk(result+cur_idx, len-cur_idx, tracker.bytes[i], tracker.bytes[i+1], tracker.bytes[i+2], tracker.bytes[i+3]);
|
||||
if(i < tracker.len) {
|
||||
{
|
||||
cur_idx += display_chunk(
|
||||
result+cur_idx,
|
||||
len-cur_idx,
|
||||
tracker.bytes[i],
|
||||
tracker.bytes[i+1],
|
||||
tracker.bytes[i+2],
|
||||
tracker.bytes[i+3]
|
||||
);
|
||||
}
|
||||
|
||||
if(i < tracker.len)
|
||||
{
|
||||
const size_t remaining = tracker.len - i;
|
||||
cur_idx += display_chunk(result+cur_idx, len-cur_idx,
|
||||
cur_idx += display_chunk(
|
||||
result+cur_idx,
|
||||
len-cur_idx,
|
||||
remaining > 0 ? tracker.bytes[i+0] : 0,
|
||||
remaining > 1 ? tracker.bytes[i+1] : 0,
|
||||
remaining > 2 ? tracker.bytes[i+2] : 0,
|
||||
remaining > 3 ? tracker.bytes[i+3] : 0);
|
||||
remaining > 3 ? tracker.bytes[i+3] : 0
|
||||
);
|
||||
}
|
||||
|
||||
// How paranoid can we be? Let's find out.
|
||||
assert(cur_idx == len);
|
||||
|
||||
// Null terminator.
|
||||
result[cur_idx-1] = '\0';
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче