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:
Pamela Vong 2019-12-02 16:56:39 -05:00 коммит произвёл Ethan Chumley
Родитель a609890fae
Коммит ceb3e10895
20 изменённых файлов: 1468 добавлений и 3 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -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)

13
examples/api/default.nix Normal file
Просмотреть файл

@ -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] ./.;
}

202
examples/api/main.c Normal file
Просмотреть файл

@ -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, &current_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);