Implement API in the C library (#44)
This introduces an api layer to the C library which can be used to execute the entire election via single api methods to create election/key ceremony, encrypt ballot, register ballot, record cast/spoil ballot, and tally votes. * Fix loop in computeTrusteePolynomial that results in segfault * Implement API to Create Election from the C library and update simple example test * Added missing include * Add method to free bytes allocated for trustee states and joint public key * Revert original simple example, create new simple example using api * Intial implementation to encrypt ballot from C API; added new api to example * Refactor create-election api in C to write joint key to config param; updated api example * Update EncryptBallot API signature to work with PInvoke; updated api example * Add API Tests to the test workflow * Fix for EncryptBallot passing in array of selections because booleans are non-blittable from C# and the array is not a fixed size * Implement RecordBallots and TallyVotes API in C library (Merge into PR #44) (#46) * Implement RecordBallots API in C library * Fix C example api tests for selection array; Refactor RecordBallot API to return the created file name * Implement TallyVotes API and example test in C library * Convert to using byte array for input instead of unsigned short array
This commit is contained in:
Родитель
a609890fae
Коммит
ceb3e10895
|
@ -32,4 +32,4 @@ CTestTestfile.cmake
|
|||
_deps
|
||||
|
||||
ElectionGuardConfig.cmake
|
||||
simple_build/
|
||||
*_build/
|
|
@ -12,6 +12,12 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
|
|||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
add_library(electionguard
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/api/base_hash.c
|
||||
${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/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/coordinator.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/num_ballots.h
|
||||
|
@ -51,6 +57,11 @@ add_library(electionguard
|
|||
${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}/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/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
|
||||
|
@ -141,6 +152,15 @@ add_test(NAME build_simple
|
|||
--test-command simple
|
||||
)
|
||||
|
||||
add_test(NAME build_api
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-E env ElectionGuard_DIR=${CMAKE_CURRENT_BINARY_DIR}/ElectionGuard
|
||||
"${CMAKE_CTEST_COMMAND}"
|
||||
--build-and-test "${PROJECT_SOURCE_DIR}/examples/api" "${CMAKE_CURRENT_BINARY_DIR}/api_build"
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--test-command api
|
||||
)
|
||||
|
||||
include(CheckIncludeFiles)
|
||||
check_include_files("windows.h;bcrypt.h" HAVE_BCRYPTGENRANDOM)
|
||||
configure_file(${PROJECT_SOURCE_DIR}/src/electionguard/random_source.h.in ${PROJECT_SOURCE_DIR}/src/electionguard/random_source.h)
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
1. Open a command prompt and navigate to the directory with the vendor-sdk repo.
|
||||
2. Run the following commands:
|
||||
|
||||
set CMAKE_PREFIX_PATH=C:\path\to\vendor-sdk\build\ElectionGuard
|
||||
$env:CMAKE_PREFIX_PATH="C:\path\to\vendor-sdk\build\ElectionGuard"
|
||||
cmake -S examples/simple -B simple_build -G "MSYS Makefiles"
|
||||
cmake --build simple_build --target simple
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project("ElectionGuard API 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(api
|
||||
${PROJECT_SOURCE_DIR}/main.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(api electionguard ${GMP_LIBRARY})
|
||||
else()
|
||||
target_link_libraries(api electionguard gmp)
|
||||
endif()
|
||||
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(api Bcrypt)
|
||||
endif (WIN32)
|
||||
|
||||
add_test(NAME api COMMAND api)
|
||||
|
||||
install(TARGETS api)
|
|
@ -0,0 +1,13 @@
|
|||
{ 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] ./.;
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include <electionguard/api/create_election.h>
|
||||
#include <electionguard/api/encrypt_ballot.h>
|
||||
#include <electionguard/api/record_ballots.h>
|
||||
#include <electionguard/api/tally_votes.h>
|
||||
#include <electionguard/max_values.h>
|
||||
|
||||
static bool random_bit();
|
||||
static void fill_random_ballot(uint8_t *selections);
|
||||
|
||||
// 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;
|
||||
uint32_t const NUM_RANDOM_BALLOT_SELECTIONS = 6;
|
||||
|
||||
// ^The number of trustees that will participate in decryption. Will fail if this is less than THRESHOLD
|
||||
|
||||
int main()
|
||||
{
|
||||
bool ok = true;
|
||||
// Seed the RNG that we use to generate arbitrary ballots. This
|
||||
// relies on the fact that the current implementation of the
|
||||
// cryptography does not rely on the built in RNG.
|
||||
srand(100);
|
||||
|
||||
struct api_config config = {
|
||||
.num_selections = NUM_SELECTIONS,
|
||||
.num_trustees = NUM_TRUSTEES,
|
||||
.threshold = THRESHOLD,
|
||||
.subgroup_order = 0,
|
||||
.election_meta = "placeholder",
|
||||
.joint_key = {.bytes = NULL},
|
||||
};
|
||||
|
||||
// Create Election
|
||||
|
||||
printf("\n--- Create Election ---\n");
|
||||
|
||||
struct trustee_state trustee_states[MAX_TRUSTEES];
|
||||
ok = API_CreateElection(&config, trustee_states);
|
||||
|
||||
for (uint32_t i = 0; i < NUM_TRUSTEES && ok; i++)
|
||||
{
|
||||
if (trustee_states[i].bytes == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Encrypt Ballots
|
||||
|
||||
printf("\n--- Encrypt Ballots ---\n");
|
||||
|
||||
struct register_ballot_message encrypted_ballots[NUM_RANDOM_BALLOT_SELECTIONS];
|
||||
uint64_t ballot_identifiers[NUM_RANDOM_BALLOT_SELECTIONS];
|
||||
char *ballot_trackers[NUM_RANDOM_BALLOT_SELECTIONS];
|
||||
|
||||
if (ok)
|
||||
{
|
||||
uint64_t current_num_ballots = 0;
|
||||
for (uint64_t i = 0; i < NUM_RANDOM_BALLOT_SELECTIONS && ok; i++)
|
||||
{
|
||||
|
||||
uint8_t selections[MAX_SELECTIONS];
|
||||
fill_random_ballot(selections);
|
||||
uint64_t ballotId;
|
||||
struct register_ballot_message encrypted_ballot_message;
|
||||
char *tracker;
|
||||
|
||||
ok = API_EncryptBallot(selections, config, ¤t_num_ballots,
|
||||
&ballotId, &encrypted_ballot_message,
|
||||
&tracker);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
encrypted_ballots[i] = encrypted_ballot_message;
|
||||
ballot_identifiers[i] = ballotId;
|
||||
ballot_trackers[i] = tracker;
|
||||
|
||||
// Print id and tracker
|
||||
printf("Ballot id: %lu\n%s\n", ballotId, tracker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register & Record Cast/Spoil Multiple Ballots
|
||||
|
||||
printf("\n--- Randomly Assigning Ballots to be Cast or Spoil Arrays ---\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];
|
||||
|
||||
for (uint64_t i = 0; i < NUM_RANDOM_BALLOT_SELECTIONS && ok; i++)
|
||||
{
|
||||
if (random_bit())
|
||||
{
|
||||
casted_ballot_ids[current_cast_index] = ballot_identifiers[i];
|
||||
current_cast_index++;
|
||||
|
||||
printf("Cast Ballot Id: %lu\n", ballot_identifiers[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
spoiled_ballot_ids[current_spoiled_index] = ballot_identifiers[i];
|
||||
current_spoiled_index++;
|
||||
|
||||
printf("Spoil Ballot Id: %lu\n", ballot_identifiers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((current_cast_index + current_spoiled_index) != NUM_RANDOM_BALLOT_SELECTIONS)
|
||||
ok = false;
|
||||
|
||||
printf("\n--- Record Ballots (Register, Cast, and Spoil) ---\n");
|
||||
|
||||
char *ballots_filename;
|
||||
if (ok)
|
||||
{
|
||||
// Assigning an output_path fails if this folder doesn't already exist
|
||||
char *output_path = "../"; // 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);
|
||||
|
||||
if (ok)
|
||||
printf("Ballot registrations and recording of cast/spoil successful!\nCheck output file \"%s\"\n",
|
||||
ballots_filename);
|
||||
}
|
||||
|
||||
// Tally Votes & Decrypt Results
|
||||
|
||||
printf("\n--- Tally & Decrypt Votes ---\n");
|
||||
|
||||
char *tally_filename;
|
||||
if (ok)
|
||||
{
|
||||
char *output_path = "../"; // This outputs to the directy above the cwd.
|
||||
char *output_prefix = "tally-";
|
||||
ok = API_TallyVotes(config, trustee_states, DECRYPTING_TRUSTEES,
|
||||
ballots_filename, output_path, output_prefix, &tally_filename);
|
||||
|
||||
if (ok)
|
||||
printf("Tally from ballots input successful!\nCheck output file \"%s\"\n",
|
||||
tally_filename);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
|
||||
API_TallyVotes_free(tally_filename);
|
||||
API_RecordBallots_free(ballots_filename);
|
||||
for (uint64_t i = 0; i < NUM_RANDOM_BALLOT_SELECTIONS && ok; i++)
|
||||
API_EncryptBallot_free(encrypted_ballots[i], ballot_trackers[i]);
|
||||
API_CreateElection_free(config.joint_key, trustee_states);
|
||||
|
||||
if (ok)
|
||||
return EXIT_SUCCESS;
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
bool random_bit() { return 1 & rand(); }
|
||||
|
||||
void fill_random_ballot(uint8_t *selections)
|
||||
{
|
||||
uint8_t selected = 0;
|
||||
for (uint32_t i = 0; i < NUM_SELECTIONS; i++)
|
||||
{
|
||||
if (!selected)
|
||||
{
|
||||
selections[i] = random_bit() ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
selections[i] = 0;
|
||||
}
|
||||
if (selections[i])
|
||||
{
|
||||
selected = 1;
|
||||
}
|
||||
}
|
||||
if (!selected)
|
||||
{
|
||||
selections[NUM_SELECTIONS - 1] = 1;
|
||||
}
|
||||
printf("vote created ");
|
||||
for (uint32_t i = 0; i < NUM_SELECTIONS; i++)
|
||||
{
|
||||
printf("%d ", selections[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef __API_CONFIG_H__
|
||||
#define __API_CONFIG_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <electionguard/crypto.h>
|
||||
|
||||
struct api_config
|
||||
{
|
||||
uint32_t num_selections;
|
||||
uint32_t num_trustees;
|
||||
uint32_t threshold;
|
||||
uint32_t subgroup_order;
|
||||
char * election_meta;
|
||||
struct joint_public_key joint_key;
|
||||
};
|
||||
|
||||
#endif /* __API_CONFIG_H__ */
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef __API_CREATE_ELECTION_H__
|
||||
#define __API_CREATE_ELECTION_H__
|
||||
|
||||
#include <electionguard/api/config.h>
|
||||
#include <electionguard/keyceremony/coordinator.h>
|
||||
#include <electionguard/keyceremony/messages.h>
|
||||
#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. */
|
||||
bool API_CreateElection(struct api_config *config,
|
||||
struct trustee_state *trustee_states);
|
||||
|
||||
/**
|
||||
* Free the bytes allocated by CreateElection */
|
||||
void API_CreateElection_free(struct joint_public_key joint_key,
|
||||
struct trustee_state *trustee_states);
|
||||
|
||||
#endif /* __API_CREATE_ELECTION_H__ */
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef __API_ENCRYPT_BALLOT_H__
|
||||
#define __API_ENCRYPT_BALLOT_H__
|
||||
|
||||
#include <electionguard/api/config.h>
|
||||
#include <electionguard/voting/encrypter.h>
|
||||
#include <electionguard/voting/tracker.h>
|
||||
|
||||
/**
|
||||
* Encrypts the ballot selections given as an array of booleans,
|
||||
* the serialized joint public key, and the current number of ballots. */
|
||||
bool API_EncryptBallot(uint8_t *selections_byte_array,
|
||||
struct api_config config,
|
||||
uint64_t *current_num_ballots,
|
||||
uint64_t *identifier,
|
||||
struct register_ballot_message *encrypted_ballot_message,
|
||||
char **tracker_string);
|
||||
|
||||
/**
|
||||
* Free the bytes allocated by EncryptBallot */
|
||||
void API_EncryptBallot_free(struct register_ballot_message message,
|
||||
char *tracker_string);
|
||||
|
||||
#endif /* __API_ENCRYPT_BALLOT_H__ */
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef __API_RECORD_BALLOTS_H__
|
||||
#define __API_RECORD_BALLOTS_H__
|
||||
|
||||
#include <electionguard/api/config.h>
|
||||
#include <electionguard/voting/coordinator.h>
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
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,
|
||||
struct register_ballot_message *encrypted_ballots,
|
||||
char *export_path,
|
||||
char *filename_prefix,
|
||||
char **output_filename);
|
||||
|
||||
/**
|
||||
* Free the bytes allocated by RecordBallots */
|
||||
void API_RecordBallots_free(char *output_filename);
|
||||
|
||||
#endif /* __API_RECORD_BALLOTS_H__ */
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef __API_TALLY_VOTES_H__
|
||||
#define __API_TALLY_VOTES_H__
|
||||
|
||||
#include <electionguard/api/config.h>
|
||||
#include <electionguard/decryption/coordinator.h>
|
||||
#include <electionguard/decryption/trustee.h>
|
||||
|
||||
/**
|
||||
* Perform all the steps necessary to tally the encypted ballots file and decrypt the tallies. */
|
||||
bool API_TallyVotes(struct api_config config,
|
||||
struct trustee_state *trustee_states,
|
||||
uint32_t num_decrypting_trustees,
|
||||
char *ballots_filename,
|
||||
char *export_path,
|
||||
char *filename_prefix,
|
||||
char **output_filename);
|
||||
|
||||
/**
|
||||
* Free the bytes allocated by TallyVotes */
|
||||
void API_TallyVotes_free(char *output_filename);
|
||||
|
||||
#endif /* __API_TALLY_VOTES_H__ */
|
|
@ -0,0 +1,18 @@
|
|||
#include "api/base_hash.h"
|
||||
|
||||
void create_base_hash_code(struct api_config config)
|
||||
{
|
||||
// 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) (use config.subgroup_order?)
|
||||
// 3. generator (from bignum.h)
|
||||
// 4. config.num_trustees
|
||||
// 5. config.threshold
|
||||
// 6. The date of the election (part of config.election_meta?)
|
||||
// 7. Jurisdictional information for the election (part of config.election_meta?)
|
||||
// TODO: perform hashing with the given config and global Crypto values from bignum.h
|
||||
raw_hash initialized_hash = {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};
|
||||
memcpy(base_hash_code, initialized_hash, sizeof(initialized_hash));
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef __API_BASE_HASH_H__
|
||||
#define __API_BASE_HASH_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <electionguard/crypto.h>
|
||||
#include <electionguard/max_values.h>
|
||||
#include <electionguard/api/config.h>
|
||||
|
||||
// Globally available
|
||||
raw_hash base_hash_code;
|
||||
|
||||
void create_base_hash_code(struct api_config config);
|
||||
|
||||
#endif /* __API_BASE_HASH_H__ */
|
|
@ -0,0 +1,352 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <electionguard/api/create_election.h>
|
||||
|
||||
#include "api/base_hash.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 struct api_config api_config;
|
||||
static KeyCeremony_Coordinator coordinator;
|
||||
static KeyCeremony_Trustee trustees[MAX_TRUSTEES];
|
||||
|
||||
bool API_CreateElection(struct api_config *config,
|
||||
struct trustee_state *trustee_states)
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("API_CreateElection::Config:\n\tnum_trustees: %d\n\tthreshold: %d\n\tsubgroup_order: %d\n\telection_meta: %s\n",
|
||||
config->num_trustees, config->threshold, config->subgroup_order, config->election_meta);
|
||||
#endif
|
||||
|
||||
bool ok = true;
|
||||
|
||||
// Set global variables
|
||||
|
||||
Crypto_parameters_new();
|
||||
api_config = *config;
|
||||
create_base_hash_code(api_config);
|
||||
|
||||
// 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);
|
||||
|
||||
// Publish joint key
|
||||
|
||||
if (ok)
|
||||
{
|
||||
config->joint_key = publish_joint_key();
|
||||
if (config->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 < api_config.num_trustees; i++)
|
||||
{
|
||||
if (trustees[i] != NULL)
|
||||
KeyCeremony_Trustee_free(trustees[i]);
|
||||
}
|
||||
|
||||
if (coordinator != NULL)
|
||||
KeyCeremony_Coordinator_free(coordinator);
|
||||
|
||||
Crypto_parameters_free();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
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[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;
|
||||
}
|
||||
}
|
||||
|
||||
bool initialize_coordinator(void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
struct KeyCeremony_Coordinator_new_r result =
|
||||
KeyCeremony_Coordinator_new(api_config.num_trustees, api_config.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 < api_config.num_trustees && ok; i++)
|
||||
{
|
||||
struct KeyCeremony_Trustee_new_r result =
|
||||
KeyCeremony_Trustee_new(api_config.num_trustees, api_config.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 < api_config.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 < api_config.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 < api_config.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 < api_config.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;
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <electionguard/api/encrypt_ballot.h>
|
||||
|
||||
#include "api/base_hash.h"
|
||||
#include "serialize/voting.h"
|
||||
#include "voting/num_ballots.h"
|
||||
|
||||
static bool initialize_encrypter(struct joint_public_key joint_key);
|
||||
|
||||
// Global state
|
||||
static struct api_config api_config;
|
||||
static Voting_Encrypter encrypter;
|
||||
|
||||
bool API_EncryptBallot(uint8_t *selections_byte_array,
|
||||
struct api_config config,
|
||||
uint64_t *current_num_ballots,
|
||||
uint64_t *identifier,
|
||||
struct register_ballot_message *encrypted_ballot_message,
|
||||
char **tracker_string)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
// Set global variables
|
||||
|
||||
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
|
||||
|
||||
bool selections[config.num_selections];
|
||||
for(uint32_t i = 0; i < config.num_selections; i++) {
|
||||
selections[i] = selections_byte_array[i] == 1;
|
||||
}
|
||||
|
||||
if (!Validate_selections(selections, config.num_selections))
|
||||
ok = false;
|
||||
|
||||
// Initialize Encrypter
|
||||
|
||||
if (ok)
|
||||
ok = initialize_encrypter(api_config.joint_key);
|
||||
|
||||
// Encrypt ballot
|
||||
|
||||
struct Voting_Encrypter_encrypt_ballot_r result = {
|
||||
.id = {.bytes = NULL},
|
||||
.tracker = {.bytes = NULL},
|
||||
};
|
||||
if (ok)
|
||||
{
|
||||
result = Voting_Encrypter_encrypt_ballot(encrypter, selections);
|
||||
|
||||
if (result.status != VOTING_ENCRYPTER_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
{
|
||||
*encrypted_ballot_message = result.message;
|
||||
|
||||
// Deserialize the id to get its ulong representation
|
||||
struct ballot_identifier_rep id_rep;
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_READING,
|
||||
.len = result.id.len,
|
||||
.offset = 0,
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
|
||||
if (result.id.bytes != NULL)
|
||||
{
|
||||
free((void *)result.id.bytes);
|
||||
result.id.bytes = NULL;
|
||||
}
|
||||
|
||||
if (result.tracker.bytes != NULL)
|
||||
{
|
||||
free((void *)result.tracker.bytes);
|
||||
result.tracker.bytes = NULL;
|
||||
}
|
||||
|
||||
if (encrypter != NULL)
|
||||
{
|
||||
Voting_Encrypter_free(encrypter);
|
||||
encrypter = NULL;
|
||||
}
|
||||
|
||||
Crypto_parameters_free();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void API_EncryptBallot_free(struct register_ballot_message message,
|
||||
char *tracker_string)
|
||||
{
|
||||
if (message.bytes != NULL)
|
||||
{
|
||||
free((void *)message.bytes);
|
||||
message.bytes = NULL;
|
||||
}
|
||||
|
||||
if (tracker_string != NULL)
|
||||
free(tracker_string);
|
||||
}
|
||||
|
||||
bool initialize_encrypter(struct joint_public_key joint_key)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
uint8_t id_buf[1] = { 0 };
|
||||
struct uid uid = {
|
||||
.len = 1,
|
||||
.bytes = id_buf,
|
||||
};
|
||||
|
||||
struct Voting_Encrypter_new_r result = Voting_Encrypter_new(
|
||||
uid, joint_key, api_config.num_selections, base_hash_code);
|
||||
|
||||
if (result.status != VOTING_ENCRYPTER_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
encrypter = result.encrypter;
|
||||
|
||||
return ok;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#include "api/filename.h"
|
||||
|
||||
|
||||
bool generate_unique_filename(char *path_in, char *prefix_in, char* default_prefix, char *filename_out)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
char prefix[FILENAME_MAX];
|
||||
char path[FILENAME_MAX];
|
||||
|
||||
// if path is provided, check the last char in the string to make sure it has the appropriate slash
|
||||
strcpy(path, path_in);
|
||||
size_t path_len = strlen(path);
|
||||
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])
|
||||
{
|
||||
strcat(path, directory_separator);
|
||||
}
|
||||
}
|
||||
|
||||
// if prefix is provided for filename, use it, otherwise use the default
|
||||
size_t prefix_size = strlen(prefix_in);
|
||||
if (prefix_size > 0)
|
||||
strcpy(prefix, prefix_in);
|
||||
else
|
||||
strcpy(prefix, default_prefix);
|
||||
|
||||
// get current epoch time
|
||||
time_t now = time(NULL);
|
||||
|
||||
int32_t status = snprintf(filename_out, FILENAME_MAX, "%s%s%ld", path, prefix, now);
|
||||
|
||||
|
||||
if (status < 0)
|
||||
ok = false;
|
||||
|
||||
return ok;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef __API_FILENAME_H__
|
||||
#define __API_FILENAME_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
bool generate_unique_filename(char *path_in, char *prefix_in, char* default_prefix, char *filename_out);
|
||||
|
||||
#endif /* __API_FILENAME_H__ */
|
|
@ -0,0 +1,209 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <electionguard/api/record_ballots.h>
|
||||
|
||||
#include "api/base_hash.h"
|
||||
#include "api/filename.h"
|
||||
#include "serialize/voting.h"
|
||||
#include "voting/num_ballots.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;
|
||||
|
||||
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,
|
||||
struct register_ballot_message *encrypted_ballots,
|
||||
char *export_path,
|
||||
char *filename_prefix,
|
||||
char **output_filename)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
#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;
|
||||
}
|
||||
|
||||
// Record Casted Ballots
|
||||
|
||||
for (uint32_t i = 0; i < num_cast_ballots && ok; i++)
|
||||
{
|
||||
struct ballot_identifier ballot_identifier;
|
||||
|
||||
ok = get_serialized_ballot_identifier(cast_ids[i], &ballot_identifier);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
#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);
|
||||
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Free current ballot identifier
|
||||
|
||||
if (ballot_identifier.bytes != NULL)
|
||||
{
|
||||
free((void *)ballot_identifier.bytes);
|
||||
ballot_identifier.bytes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Record Spoiled Ballots
|
||||
|
||||
for (uint32_t i = 0; i < num_spoil_ballots && ok; i++)
|
||||
{
|
||||
struct ballot_identifier ballot_identifier;
|
||||
|
||||
ok = get_serialized_ballot_identifier(spoil_ids[i], &ballot_identifier);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
#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);
|
||||
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Free current ballot identifier
|
||||
|
||||
if (ballot_identifier.bytes != NULL)
|
||||
{
|
||||
free((void *)ballot_identifier.bytes);
|
||||
ballot_identifier.bytes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Export
|
||||
|
||||
if (ok)
|
||||
ok = export_ballots(export_path, filename_prefix, output_filename);
|
||||
|
||||
// Clean up
|
||||
|
||||
if (coordinator != NULL)
|
||||
{
|
||||
Voting_Coordinator_free(coordinator);
|
||||
coordinator = NULL;
|
||||
}
|
||||
|
||||
Crypto_parameters_free();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void API_RecordBallots_free(char *output_filename)
|
||||
{
|
||||
if (output_filename != NULL)
|
||||
free(output_filename);
|
||||
}
|
||||
|
||||
bool initialize_coordinator(uint32_t num_selections)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool get_serialized_ballot_identifier(int64_t ballot_id, struct ballot_identifier *ballot_identifier)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
struct ballot_identifier_rep rep = {.id = ballot_id};
|
||||
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_RESERVING,
|
||||
.len = 0,
|
||||
.offset = 0,
|
||||
.buf = NULL,
|
||||
};
|
||||
|
||||
Serialize_reserve_ballot_identifier(&state, &rep);
|
||||
Serialize_allocate(&state);
|
||||
Serialize_write_ballot_identifier(&state, &rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
ok = false;
|
||||
else
|
||||
{
|
||||
*ballot_identifier = (struct ballot_identifier){
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool export_ballots(char *export_path, char *filename_prefix, char **output_filename)
|
||||
{
|
||||
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
|
||||
|
||||
if (ok)
|
||||
{
|
||||
FILE *out = fopen(*output_filename, "w+");
|
||||
|
||||
enum Voting_Coordinator_status status =
|
||||
Voting_Coordinator_export_ballots(coordinator, out);
|
||||
|
||||
if (status != VOTING_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
|
||||
if (out != NULL)
|
||||
{
|
||||
fclose(out);
|
||||
out = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <electionguard/api/tally_votes.h>
|
||||
|
||||
#include "api/base_hash.h"
|
||||
#include "api/filename.h"
|
||||
|
||||
// Initialize
|
||||
static bool initialize_coordinator(void);
|
||||
static bool initialize_trustees(struct trustee_state *trustee_states);
|
||||
|
||||
// Tally and Decrypt
|
||||
static bool tally_ballots(char *in_ballots_filename);
|
||||
static bool decrypt_tally_shares(uint32_t num_decrypting_trustees);
|
||||
static bool decrypt_tally_decryption_fragments(
|
||||
bool *requests_present, struct decryption_fragments_request *requests);
|
||||
static bool export_tally_votes(char *export_path, char *filename_prefix, char **output_filename);
|
||||
|
||||
// Global state
|
||||
static struct api_config api_config;
|
||||
static Decryption_Coordinator coordinator;
|
||||
static Decryption_Trustee trustees[MAX_TRUSTEES];
|
||||
|
||||
bool API_TallyVotes(struct api_config config,
|
||||
struct trustee_state *trustee_states,
|
||||
uint32_t num_decrypting_trustees,
|
||||
char *ballots_filename,
|
||||
char *export_path,
|
||||
char *filename_prefix,
|
||||
char **output_filename)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
// Set global variables
|
||||
|
||||
Crypto_parameters_new();
|
||||
api_config = config;
|
||||
create_base_hash_code(api_config);
|
||||
|
||||
// Initialize
|
||||
|
||||
if (ok)
|
||||
ok = initialize_coordinator();
|
||||
|
||||
if (ok)
|
||||
ok = initialize_trustees(trustee_states);
|
||||
|
||||
// Tally and Decrypt Shares
|
||||
|
||||
if (ok)
|
||||
ok = tally_ballots(ballots_filename);
|
||||
|
||||
if (ok)
|
||||
ok = decrypt_tally_shares(num_decrypting_trustees);
|
||||
|
||||
|
||||
struct decryption_fragments_request requests[MAX_TRUSTEES];
|
||||
bool request_present[MAX_TRUSTEES];
|
||||
for (uint32_t i = 0; i < api_config.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)
|
||||
ok = export_tally_votes(export_path, filename_prefix, output_filename);
|
||||
|
||||
// Cleanup
|
||||
|
||||
for (uint32_t i = 0; i < api_config.num_trustees; i++)
|
||||
if (request_present[i])
|
||||
{
|
||||
free((void *)requests[i].bytes);
|
||||
requests[i].bytes = NULL;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < api_config.num_trustees; i++)
|
||||
if (trustees[i] != NULL)
|
||||
{
|
||||
Decryption_Trustee_free(trustees[i]);
|
||||
trustees[i] = NULL;
|
||||
}
|
||||
|
||||
if (coordinator != NULL)
|
||||
{
|
||||
Decryption_Coordinator_free(coordinator);
|
||||
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)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
struct Decryption_Coordinator_new_r result =
|
||||
Decryption_Coordinator_new(api_config.num_trustees, api_config.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 < api_config.num_trustees && ok; i++)
|
||||
{
|
||||
struct Decryption_Trustee_new_r result =
|
||||
Decryption_Trustee_new(api_config.num_trustees, api_config.threshold,
|
||||
api_config.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_ballots(char *in_ballots_filename)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
FILE *in = fopen(in_ballots_filename, "r");
|
||||
|
||||
for (uint32_t i = 0; i < api_config.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;
|
||||
}
|
||||
}
|
||||
|
||||
if (in != NULL)
|
||||
{
|
||||
fclose(in);
|
||||
in = NULL;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool decrypt_tally_shares(uint32_t num_decrypting_trustees)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
for (uint32_t i = 0; i < num_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 < api_config.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;
|
||||
}
|
||||
|
||||
bool export_tally_votes(char *export_path, char *filename_prefix, char **output_filename)
|
||||
{
|
||||
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
|
||||
|
||||
if (ok)
|
||||
{
|
||||
FILE *out = fopen(*output_filename, "w+");
|
||||
|
||||
enum Decryption_Coordinator_status status =
|
||||
Decryption_Coordinator_all_fragments_received(coordinator, out);
|
||||
|
||||
if (status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
|
||||
if (out != NULL)
|
||||
{
|
||||
fclose(out);
|
||||
out = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
|
@ -345,7 +345,7 @@ void computeTrusteePolynomial(mpz_t out, //out
|
|||
mpz_inits(t_1, t_2, i_t, index_t, NULL);
|
||||
mpz_set_ui(index_t, index);
|
||||
mpz_set_ui(out,0);
|
||||
for (uint32_t i = 0; i <= upperBound; i++)
|
||||
for (uint32_t i = 0; i < upperBound; i++)
|
||||
{
|
||||
mpz_set_ui(i_t, i);
|
||||
pow_mod_q(t_1, index_t, i_t);
|
||||
|
|
Загрузка…
Ссылка в новой задаче