This commit is contained in:
Jake Waksbaum 2019-09-24 06:47:31 -07:00 коммит произвёл Joey Dodds
Родитель 1f9353ebe6
Коммит 647510887e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: D135B87AB5B74652
71 изменённых файлов: 4096 добавлений и 790 удалений

Просмотреть файл

@ -1,54 +0,0 @@
personal_ws-1.1 en 53
NIZKPs
structs
stacksize
uncast
uids
enums
typedef
struct
enum
deallocate
decrypted
txt
encrypter
hacky
ulimit
BMD
cquery
decrypt
todo
unencrypted
encrypters
jwaksbaum
booleans
READMEs
decrypts
ccls
NIZKP
valgrind
keyceremony
cryptographic
ElectionGuard
verifiers
APIs
SDK
params
libelectionguard
builtins
XXXXXX
deserialization
json
deserialize
ie
decrypting
crypto
deserialized
keypair
gdb
lldb
liveness
num
serializable
stackframe
uid

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

@ -4,3 +4,5 @@
main main
*.o.json *.o.json
compile_commands.json compile_commands.json
html
doxygen

3
.gitmodules поставляемый Normal file
Просмотреть файл

@ -0,0 +1,3 @@
[submodule "doc/sphinx-typlog-theme"]
path = doc/sphinx-typlog-theme
url = https://github.com/jbaum98/sphinx-typlog-theme

56
CMakeLists.txt Normal file
Просмотреть файл

@ -0,0 +1,56 @@
cmake_minimum_required(VERSION 3.13)
project("ElectionGuard SDK" LANGUAGES C)
enable_testing()
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
add_library(electionguard STATIC
${PROJECT_SOURCE_DIR}/src/voting/coordinator.c
${PROJECT_SOURCE_DIR}/src/keyceremony/coordinator.c
${PROJECT_SOURCE_DIR}/src/keyceremony/trustee.c
${PROJECT_SOURCE_DIR}/src/voting/nouns.c
${PROJECT_SOURCE_DIR}/src/voting/tracker.c
${PROJECT_SOURCE_DIR}/src/voting/encrypter.c
${PROJECT_SOURCE_DIR}/src/decryption/coordinator.c
${PROJECT_SOURCE_DIR}/src/decryption/trustee.c
${PROJECT_SOURCE_DIR}/src/serialize/builtins.c
${PROJECT_SOURCE_DIR}/src/serialize/state.c
${PROJECT_SOURCE_DIR}/src/serialize/decryption.c
${PROJECT_SOURCE_DIR}/src/serialize/trustee_state.c
${PROJECT_SOURCE_DIR}/src/serialize/voting.c
${PROJECT_SOURCE_DIR}/src/serialize/keyceremony.c
${PROJECT_SOURCE_DIR}/src/serialize/crypto.c
${PROJECT_SOURCE_DIR}/src/crypto.c)
target_include_directories(electionguard
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
PRIVATE
${PROJECT_SOURCE_DIR}/src)
# Compiler flags
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
target_compile_options(electionguard PRIVATE -Wall -Wextra -pedantic -pedantic-errors -Wunreachable-code -Wmissing-field-initializers)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
target_compile_options(electionguard PRIVATE -Wgnu-empty-initializer)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
target_compile_options(electionguard PRIVATE -Wenum-compare)
endif()
# examples
add_subdirectory(examples)
# documentation
set(DOXYGEN_INPUT ${PROJECT_SOURCE_DIR}/Doxyfile)
set(DOCS_OUTPUT ${PROJECT_BINARY_DIR}/html)
add_custom_target(docs
COMMAND doxygen ${DOXYGEN_INPUT}
COMMAND sphinx-build -b html ${PROJECT_SOURCE_DIR}/doc ${DOCS_OUTPUT}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})

2494
Doxyfile Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,21 +0,0 @@
include makefiles/cflags.mk
include makefiles/libelectionguard.mk
include examples/simple.mk
.DEFAULT_GOAL := libelectionguard.a
all: examples/simple/main
FIND_O_JSON = find . -name '*.o.json'
compile_commands.json: $(shell $(FIND_O_JSON))
$(FIND_O_JSON) | xargs sed -e '1s/^/[\n/' -e '$$s/,$$/\n]/' > $@ $<
.PHONY: spell
spell:
for f in $$(find . -iname '*.c' -o -iname '*.h' -o -iname '*.md'); do \
aspell --lang=en --personal=./.aspell-wordlist.txt check "$$f"; \
done
DEP = $(shell find . -name '*.d')
$(DEP):
include $(wildcard $(DEP))

163
README.md
Просмотреть файл

@ -1,163 +0,0 @@
# ElectionGuard SDK Mock Implementation
This implementation of the ElectionGuard SDK serves to showcase the
API provided by the SDK. For more details about that API, see the
[`include`](./include) directory.
## Table of Contents
- The [`include`](./include) directory contains the header files that
form the public API of the SDK.
- The [`examples`](./examples) directory contains example clients of
the API, showing how it can be used to run an election.
- The [`src`](./src) directory contains an implementation of the SDK.
At this time, it does not actually implement any cryptographic features,
and can only run elections that take place on a single machine.
However, the API was designed to allow for elections run across many
machines.
## Building
To build the SDK static library `libelectionguard.a`, run
```sh
make libelectionguard.a
```
To build an example client of the SDK, run
```sh
make examples/simple/main
```
### Debugging
To enable debug builds suitable for running with debuggers like `gdb`
or `lldb`, set the `DEBUG` environment variable:
``` sh
DEBUG=1 make examples/simple/main
```
When the `CC` environment variable is set to `clang`, debug builds
will also be built with the address sanitizer enabled, which helps to
catch memory management errors.
``` sh
CC=clang DEBUG=1 make examples/simple/main
```
**Note:** The current implementation allocates most things statically,
leading to a large stack. This leads to stack-overflow errors with
address sanitizer, unless the default stack size is increased. In our
experience, using `ulimit` like this fixes the issue:
``` sh
ulimit -s 32768
```
In addition, this causes issues with `valgrind`. The error messages are usually
pretty helpful. As of the last time this was updated, this valgrind command
works without errors:
```sh
valgrind --main-stacksize=33445532 --max-stackframe=27686064 ./examples/simple/main
```
### Developing
Some development tools like `ccls` or `cquery` use a JSON file called
`compile_commands.json` to lookup which build flags are used to build
different files. To produce such a file while compiling, set the
`COMPILE_COMMANDS` environment variable and then run the
`compile_commands.json` target.
``` sh
COMPILE_COMMANDS=1 make examples/simple/main compile_commands.json
```
## Testing
Build the example client as described in [Building](#Building), and
run it. It should successfully exit with return status `0`, and
produce two files in the current directory with names of the form
`voting_results-XXXXXX.txt` and `tally-XXXXXX.txt` containing ballots
and the decrypted tallies respectively. For more details see [the
source of the example client](./examples/simple).
## Memory Management/Ownership: Who frees what?
Any pointers *returned by* functions in the SDK are considered to be
owned by the caller. This means that the SDK will retain no references
to them, and that the caller must free them when they are done.
Any pointers *passed to* functions in the SDK as arguments are
considered to be borrowed by the function, which means that they will
not be freed by that function, and it is still the responsibility of
the caller to free the pointer. This of course excludes functions
whose purpose is to free an opaque data type, like
`Key_Ceremony_Trustee_free`.
This only applies when functions return with a successful status. If a
function returns with an error status, the client does not need to
free any memory that may have been allocated by the function; it will
clean up after itself.
## Naming Conventions
All public functions are prefixed with the name of their "class" or
module, capitalized.
There are a few different kinds of types, and they each have their own
naming conventions. The rationale is that for types that we rely on
the fact that they are enums or structs, we should not `typedef` them so
that it is clear that they are enums and structs. If that changes, we
will have to go fix it everywhere, which is good, because now we
cannot rely on their representation anymore. Abstract types should be
`typedef`ed because we don't rely on their implementation.
### Abstract Type
A type whose implementation we want to be hidden from clients. This
means that it must be hidden behind a pointer so its size doesn't need
to be known.
**Naming convention:** uppercase, with their structs suffixed with `_s`.
```c
typedef struct Car_s *Car;
```
### Status Enum
A enum whose values represent possible statuses that we want to
return.
**Naming convention:** prefixed by module or scope, then lowercase,
and no `typedef`.
```c
enum Car_status {
CAR_SUCCESS,
CAR_ON_FIRE,
};
```
### Return Struct
A struct whose sole purpose is to allow us to return multiple values,
often a status enum and a payload.
**Naming convention:** prefixed by module or scope, then lowercase,
then `_r`, and no `typedef`. If only used for a single function, make
the name identical to the function name, then `_r`. You can forward
declare in the return type.
```c
struct Car_drive_r Car_drive(Car c);
struct Car_drive_r {
enum Car_status status;
int x;
int y;
};
```
### Internal Struct
A type we want to name, but whose implementation need not be hidden.
In fact, we might rely on the details of its representation.
**Naming convention:** all lowercase, no `typedef`.
```c
struct model {
int year;
enum color color;
};
```

243
README.rst Normal file
Просмотреть файл

@ -0,0 +1,243 @@
ElectionGuard SDK Mock Implementation
=====================================
This implementation of the ElectionGuard SDK serves to showcase the API
provided by the SDK. For more details about that API, see the
:ref:`include`.
.. _building:
Building
--------
To enable cross-platform building, we use `cmake <https://cmake.org/>`_. Here
we describe how to use Microsoft Visual Studio and :program:`make`, but other
backends like :program:`ninja` should work as well.
Visual Studio
~~~~~~~~~~~~~
As long as you have the C++ CMake tools for Windows installed, :program:`cmake`
should automatically integrate with Visual Studio. This means you can build the
project from the IDE, for example by right-clicking :file:`CMakeLists.txt` and
then selecting ``Build``.
Unix-like Systems
~~~~~~~~~~~~~~~~~
First use :program:`cmake` to generate build instructions for some
generator like :program:`make` or :program:`ninja`. You can see a list
of available generators by running ``cmake -G``. We will assume from
now on that you are using the :program:`make` generator, but it should
be straightforward to build the corresponding targets with whatever
generator you choose to use.
.. code:: sh
mkdir build
cd build
cmake ..
To build the SDK static library ``libelectionguard.a``, run
.. code:: sh
make electionguard
To build an example client of the SDK, run
.. code:: sh
make simple
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
also execute the client directly to better examine the output it produces.
.. warning::
The current implementation allocates most things statically, leading
to a large stack. This can cause stack-overflows.
The size of the stack mostly depends on the value of :data:`MAX_TRUSTEES` in
:file:`include/max_trustees.h`, so one way to fix the problem is to reduce
that number and recompile.
You can also increase the stack size, for example using :command:`ulimit`.
In addition, this causes issues with :program:`valgrind`. The error messages
are usually pretty helpful, and setting ``--main-stacksize`` and
``--main-stackframe`` according to its reccomendations usually fixes the issue.
Visual Studio
~~~~~~~~~~~~~
As with building, you should be able to use the IDE to run the tests, for
example by right-clicking :file:`CMakeLists.txt` and then selecing ``Run Tests``.
Unix-like Systems
~~~~~~~~~~~~~~~~~
From the build directory, run
.. code:: sh
make test
Debugging
---------
To enable debug builds suitable for running with debuggers like
:program:`lldb`, set the ``CMAKE_BUILD_TYPE`` cmake variable to
``Debug``. From the command-line, this looks like
.. code:: sh
cmake -DCMAKE_BUILD_TYPE=Debug ..
Developing
----------
Some development tools like :program:`ccls` or :program:`cquery` use a
JSON file called :file:`compile_commands.json` to lookup which build
flags are used to build different files. To produce such a file while
compiling, set the ``CMAKE_EXPORT_COMPILE_COMMANDS`` cmake variable.
From the command-line, this looks like
.. code:: sh
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
Documentation
-------------
To build the HTML documentation, you will need to have
:program:`doxygen` installed, as well as :program:`python` with the
``sphinx`` and ``breathe`` packages. Then run
.. code:: sh
make docs
and the documentation will be built in the :file:`html` directory. You
can browse it locally by opening :file:`html/index.html`, or by
running a local server
.. code::sh
# python2
(cd html && python -m SimpleHTTPServer)
# python3
python3 -m http.server --directory html
.. note::
Make sure that you've initialized :program:`git` submodules
correctly. The theme used for the documentation is in a submodule.
.. code:: sh
git submodule update --init --recursive
Memory Management/Ownership: Who frees what?
--------------------------------------------
Any pointers *returned by* functions in the SDK are considered to be
owned by the caller. This means that the SDK will retain no references
to them, and that the caller must free them when they are done.
Any pointers *passed to* functions in the SDK as arguments are
considered to be borrowed by the function, which means that they will
not be freed by that function, and it is still the responsibility of the
caller to free the pointer. This of course excludes functions whose
purpose is to free an opaque data type, like
:func:`KeyCeremony_Trustee_free()`.
This only applies when functions return with a successful status. If a
function returns with an error status, the client does not need to free
any memory that may have been allocated by the function; it will clean
up after itself.
Naming Conventions
------------------
All public functions are prefixed with the name of their “class” or
module, capitalized.
There are a few different kinds of types, and they each have their own
naming conventions. The rationale is that for types that we rely on the
fact that they are enums or structs, we should not ``typedef`` them so
that it is clear that they are enums and structs. If that changes, we
will have to go fix it everywhere, which is good, because now we cannot
rely on their representation anymore. Abstract types should be
``typedef``\ ed because we dont rely on their implementation.
Abstract Type
~~~~~~~~~~~~~
A type whose implementation we want to be hidden from clients. This
means that it must be hidden behind a pointer so its size doesnt need
to be known.
**Naming convention:** uppercase, with their structs suffixed with
``_s``.
.. code:: c
typedef struct Car_s *Car;
Status Enum
~~~~~~~~~~~
A enum whose values represent possible statuses that we want to return.
**Naming convention:** prefixed by module or scope, then lowercase, and
no ``typedef``.
.. code:: c
enum Car_status {
CAR_SUCCESS,
CAR_ON_FIRE,
};
Return Struct
~~~~~~~~~~~~~
A struct whose sole purpose is to allow us to return multiple values,
often a status enum and a payload.
**Naming convention:** prefixed by module or scope, then lowercase, then
``_r``, and no ``typedef``. If only used for a single function, make the
name identical to the function name, then ``_r``. You can forward
declare in the return type.
.. code:: c
struct Car_drive_r Car_drive(Car c);
struct Car_drive_r {
enum Car_status status;
int x;
int y;
};
Internal Struct
~~~~~~~~~~~~~~~
A type we want to name, but whose implementation need not be hidden. In
fact, we might rely on the details of its representation.
**Naming convention:** all lowercase, no ``typedef``.
.. code:: c
struct model {
int year;
enum color color;
};

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

@ -0,0 +1,2 @@
_static/*
!.gitkeep

0
doc/_static/.gitkeep поставляемый Normal file
Просмотреть файл

10
doc/api/crypto.rst Normal file
Просмотреть файл

@ -0,0 +1,10 @@
Crypto
======
.. doxygenenum:: KEY_SIZE_e
.. doxygenenum:: MAX_PRIVATE_KEY_SIZE_e
.. doxygenenum:: MAX_PUBLIC_KEY_SIZE_e
.. doxygenstruct:: joint_public_key
:members:
:undoc-members:

Просмотреть файл

@ -0,0 +1,37 @@
Decryption Coordinator
======================
.. doxygentypedef:: Decryption_Coordinator
Initialization and Freeing
--------------------------
.. doxygenfunction:: Decryption_Coordinator_new
.. doxygenstruct:: Decryption_Coordinator_new_r
:members:
:undoc-members:
.. doxygenfunction:: Decryption_Coordinator_free
Anouncing
---------
.. doxygenfunction:: Decryption_Coordinator_receive_share
.. doxygenfunction:: Decryption_Coordinator_all_shares_received
.. doxygenstruct:: Decryption_Coordinator_all_shares_received_r
:members:
:undoc-members:
Compensating
------------
.. doxygenfunction:: Decryption_Coordinator_receive_fragments
.. doxygenfunction:: Decryption_Coordinator_all_fragments_received
Status Codes
------------
.. doxygenenum:: Decryption_Coordinator_status

Просмотреть файл

@ -0,0 +1,14 @@
Decryption Messages
===================
.. doxygenstruct:: decryption_share
:members:
:undoc-members:
.. doxygenstruct:: decryption_fragments_request
:members:
:undoc-members:
.. doxygenstruct:: decryption_fragments
:members:
:undoc-members:

Просмотреть файл

@ -0,0 +1,40 @@
Decryption Trustee
==================
.. doxygentypedef:: Decryption_Trustee
Initialization and Freeing
--------------------------
.. doxygenfunction:: Decryption_Trustee_new
.. doxygenstruct:: Decryption_Trustee_new_r
:members:
:undoc-members:
.. doxygenfunction:: Decryption_Trustee_free
Tallying
--------
.. doxygenfunction:: Decryption_Trustee_tally_voting_record
Announcing
----------
.. doxygenfunction:: Decryption_Trustee_compute_share
.. doxygenstruct:: Decryption_Trustee_compute_share_r
:members:
:undoc-members:
Compensating
------------
.. doxygenfunction:: Decryption_Trustee_compute_fragments
.. doxygenstruct:: Decryption_Trustee_compute_fragments_r
:members:
:undoc-members:
Status Codes
------------
.. doxygenenum:: Decryption_Trustee_status

20
doc/api/index.rst Normal file
Просмотреть файл

@ -0,0 +1,20 @@
.. _include:
.. include:: ../../include/README.rst
.. toctree::
:hidden:
keyceremony/trustee
keyceremony/coordinator
keyceremony/messages
voting/encrypter
voting/coordinator
voting/messages
voting/tracker
decryption/trustee
decryption/coordinator
decryption/messages
trustee_state
crypto
max_values

Просмотреть файл

@ -0,0 +1,49 @@
Key Ceremony Coordinator
========================
.. doxygentypedef:: KeyCeremony_Coordinator
Initialization and Freeing
--------------------------
.. doxygenfunction:: KeyCeremony_Coordinator_new
.. doxygenstruct:: KeyCeremony_Coordinator_new_r
:members:
:undoc-members:
.. doxygenfunction:: KeyCeremony_Coordinator_free
Key Generation
--------------
.. doxygenfunction:: KeyCeremony_Coordinator_receive_key_generated
.. doxygenfunction:: KeyCeremony_Coordinator_all_keys_received
.. doxygenstruct:: KeyCeremony_Coordinator_all_keys_received_r
:members:
:undoc-members:
Share Generation
----------------
.. doxygenfunction:: KeyCeremony_Coordinator_receive_shares_generated
.. doxygenfunction:: KeyCeremony_Coordinator_all_shares_received
.. doxygenstruct:: KeyCeremony_Coordinator_all_shares_received_r
:members:
:undoc-members:
Verification
------------
.. doxygenfunction:: KeyCeremony_Coordinator_receive_shares_verified
.. doxygenfunction:: KeyCeremony_Coordinator_publish_joint_key
.. doxygenstruct:: KeyCeremony_Coordinator_publish_joint_key_r
:members:
:undoc-members:
Status Codes
------------
.. doxygenenum:: KeyCeremony_Coordinator_status

Просмотреть файл

@ -0,0 +1,22 @@
Key Ceremony Messages
=====================
.. doxygenstruct:: key_generated_message
:members:
:undoc-members:
.. doxygenstruct:: all_keys_received_message
:members:
:undoc-members:
.. doxygenstruct:: shares_generated_message
:members:
:undoc-members:
.. doxygenstruct:: all_shares_received_message
:members:
:undoc-members:
.. doxygenstruct:: shares_verified_message
:members:
:undoc-members:

Просмотреть файл

@ -0,0 +1,50 @@
Key Ceremony Trustee
========================
.. doxygentypedef:: KeyCeremony_Trustee
Initialization and Freeing
--------------------------
.. doxygenfunction:: KeyCeremony_Trustee_new
.. doxygenstruct:: KeyCeremony_Trustee_new_r
:members:
:undoc-members:
.. doxygenfunction:: KeyCeremony_Trustee_free
Key Generation
--------------
.. doxygenfunction:: KeyCeremony_Trustee_generate_key
.. doxygenstruct:: KeyCeremony_Trustee_generate_key_r
:members:
:undoc-members:
Share Generation
----------------
.. doxygenfunction:: KeyCeremony_Trustee_generate_shares
.. doxygenstruct:: KeyCeremony_Trustee_generate_shares_r
:members:
:undoc-members:
Verification
------------
.. doxygenfunction:: KeyCeremony_Trustee_verify_shares
.. doxygenstruct:: KeyCeremony_Trustee_verify_shares_r
State Export
------------
.. doxygenfunction:: KeyCeremony_Trustee_export_state
.. doxygenstruct:: KeyCeremony_Trustee_export_state_r
Status Codes
------------
.. doxygenenum:: KeyCeremony_Trustee_status

6
doc/api/max_values.rst Normal file
Просмотреть файл

@ -0,0 +1,6 @@
Maximum Values
==============
.. doxygenenum:: MAX_TRUSTEES_e
.. doxygenenum:: MAX_BALLOTS_e
.. doxygenenum:: MAX_SELECTIONS_e

Просмотреть файл

@ -0,0 +1,6 @@
Trustee State
=============
.. doxygenstruct:: trustee_state
:members:
:undoc-members:

Просмотреть файл

@ -0,0 +1,32 @@
Voting Coordinator
==================
.. doxygentypedef:: Voting_Coordinator
Initialization and Freeing
--------------------------
.. doxygenfunction:: Voting_Coordinator_new
.. doxygenstruct:: Voting_Coordinator_new_r
:members:
:undoc-members:
.. doxygenfunction:: Voting_Coordinator_free
Registering, Casting and Spoiling Ballots
-----------------------------------------
.. doxygenfunction:: Voting_Coordinator_register_ballot
.. doxygenfunction:: Voting_Coordinator_cast_ballot
.. doxygenfunction:: Voting_Coordinator_spoil_ballot
Exporting Ballots
-----------------
.. doxygenfunction:: Voting_Coordinator_export_ballots
Status Codes
------------
.. doxygenenum:: Voting_Coordinator_status

Просмотреть файл

@ -0,0 +1,30 @@
Voting Encrypter
================
.. doxygentypedef:: Voting_Encrypter
.. doxygenstruct:: uid
:members:
:undoc-members:
.. doxygenfunction:: Voting_Encrypter_new
.. doxygenstruct:: Voting_Encrypter_new_r
:members:
:undoc-members:
.. doxygenfunction:: Voting_Encrypter_free
Ballot Encryption
-----------------
.. doxygenfunction:: Voting_Encrypter_encrypt_ballot
.. doxygenstruct:: Voting_Encrypter_encrypt_ballot_r
:members:
:undoc-members:
Status Codes
------------
.. doxygenenum:: Voting_Encrypter_status

Просмотреть файл

@ -0,0 +1,14 @@
Voting Messsages
================
.. doxygenstruct:: register_ballot_message
:members:
:undoc-members:
.. doxygenstruct:: ballot_tracker
:members:
:undoc-members:
.. doxygenstruct:: ballot_identifier
:members:
:undoc-members:

Просмотреть файл

@ -0,0 +1,4 @@
Ballot Tracker
==============
.. doxygenfunction:: display_ballot_tracker

214
doc/conf.py Normal file
Просмотреть файл

@ -0,0 +1,214 @@
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('./sphinx-typlog-theme'))
# -- Project information -----------------------------------------------------
project = 'ElectionGuard SDK'
copyright = '2019, Jake Waksbaum'
author = 'Jake Waksbaum'
# The short X.Y version
version = ''
# The full version, including alpha/beta/rc tags
release = ''
# -- General configuration ---------------------------------------------------
primary_domain = "c"
default_role = "math"
nitpicky = True
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.todo',
'sphinx.ext.mathjax',
'sphinx.ext.ifconfig',
'sphinx.ext.viewcode',
'sphinx.ext.viewcode',
'breathe',
]
# Breathe Configuration
breathe_projects = { "ElectionGuard SDK": "../doxygen/xml" }
breathe_default_project = "ElectionGuard SDK"
breathe_domain_by_extension = {"h" : "c", "c" : "c"}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = [ "sphinx-typlog-theme/*" ]
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = None
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme_path = ["./sphinx-typlog-theme"]
html_theme = 'sphinx_typlog_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
"color": "#268bd2",
"logo_name": "ElectionGuard SDK",
"description": "Building E2E verifiable elections.",
"github_user": "microsoft",
"github_repo": "ElectionGuard-SDK",
}
html_sidebars = {
'index': ['logo.html', 'github.html', 'globaltoc.html', 'localtoc.html', 'searchbox.html'],
'examples/*': ['logo.html', 'github.html', 'globaltoc.html', 'localtoc.html', 'searchbox.html'],
'**': ['logo.html', 'github.html', 'globaltoc.html', 'searchbox.html'],
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'ElectionGuardSDKdoc'
# -- Options for LaTeX output ------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'ElectionGuardSDK.tex', 'ElectionGuard SDK Documentation',
'Jake Waksbaum', 'manual'),
]
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'electionguardsdk', 'ElectionGuard SDK Documentation',
[author], 1)
]
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'ElectionGuardSDK', 'ElectionGuard SDK Documentation',
author, 'ElectionGuardSDK', 'One line description of project.',
'Miscellaneous'),
]
# -- Options for Epub output -------------------------------------------------
# Bibliographic Dublin Core info.
epub_title = project
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''
# A unique identification for the text.
#
# epub_uid = ''
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
# -- Extension configuration -------------------------------------------------
# -- Options for intersphinx extension ---------------------------------------
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/': None}
# -- Options for todo extension ----------------------------------------------
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True

1
doc/decryption.rst Normal file
Просмотреть файл

@ -0,0 +1 @@
.. include:: /../include/decryption/README.rst

1
doc/examples.rst Normal file
Просмотреть файл

@ -0,0 +1 @@
.. include:: /../examples/README.rst

43
doc/examples/simple.rst Normal file
Просмотреть файл

@ -0,0 +1,43 @@
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

17
doc/index.rst Normal file
Просмотреть файл

@ -0,0 +1,17 @@
.. include:: ../README.rst
.. toctree::
:maxdepth: 2
:hidden:
keyceremony
voting
decryption
api/index
examples
Indices and tables
------------------
* :ref:`genindex`
* :ref:`search`

1
doc/keyceremony.rst Normal file
Просмотреть файл

@ -0,0 +1 @@
.. include:: /../include/keyceremony/README.rst

1
doc/voting.rst Normal file
Просмотреть файл

@ -0,0 +1 @@
.. include:: /../include/voting/README.rst

19
examples/CMakeLists.txt Normal file
Просмотреть файл

@ -0,0 +1,19 @@
# simple example
add_executable(simple
${CMAKE_CURRENT_SOURCE_DIR}/simple/main.c
${CMAKE_CURRENT_SOURCE_DIR}/simple/main_keyceremony.c
${CMAKE_CURRENT_SOURCE_DIR}/simple/main_voting.c
${CMAKE_CURRENT_SOURCE_DIR}/simple/main_decryption.c)
target_include_directories(simple PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(simple electionguard)
add_test(NAME simple COMMAND simple)
add_test(NAME build_simple
COMMAND "${CMAKE_COMMAND}"
--build "${CMAKE_BINARY_DIR}"
--target simple
)
set_tests_properties(simple PROPERTIES FIXTURES_REQUIRED simple)
set_tests_properties(build_simple PROPERTIES FIXTURES_SETUP simple)

Просмотреть файл

@ -1,9 +0,0 @@
# ElectionGuard SDK Example Clients
These examples demonstrate correct usage of the ElectionGuard SDK.
## Table of Contents
- [`simple`](./simple) carries out an election where all entities
communicate via argument-passing, so no serialization or
deserialization are necessary.

20
examples/README.rst Normal file
Просмотреть файл

@ -0,0 +1,20 @@
Example Clients
===============
These examples demonstrate correct usage of the ElectionGuard SDK.
.. toctree::
:maxdepth: 1
:hidden:
Simple Client <examples/simple>
- The :doc:`simple client <examples/simple>` carries out an election where all
entities communicate via argument-passing.
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
a representation where each byte is converted to a specific word.

Просмотреть файл

@ -1,5 +0,0 @@
SRC += $(wildcard examples/simple/*.c)
examples/simple/main: LDFLAGS += -L.
examples/simple/main: $(patsubst %.c,%.o,$(wildcard examples/simple/*.c)) libelectionguard.a
$(CC) $(CFLAGS) -o $@ $(patsubst %.c,%.o,$(wildcard examples/simple/*.c)) $(LDFLAGS) -lelectionguard

Просмотреть файл

@ -1,25 +1,32 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #ifdef _MSC_VER
#include <io.h>
#endif
#include "max_values.h" #include "max_values.h"
#include "main_decryption.h" #include "main_decryption.h"
#include "main_key_ceremony.h" #include "main_keyceremony.h"
#include "main_params.h" #include "main_params.h"
#include "main_voting.h" #include "main_voting.h"
static FILE *fmkstemps(char const *template, int suffixlen, const char *mode); /** Create a new temporary file from a template. */
static FILE *fmkstemps(char const *template, const char *mode);
// Parameters // Election Parameters
uint32_t const NUM_TRUSTEES = 10; uint32_t const NUM_TRUSTEES = 5;
uint32_t const THRESHOLD = 8; uint32_t const THRESHOLD = 4;
uint32_t const NUM_ENCRYPTERS = 3; uint32_t const NUM_ENCRYPTERS = 3;
uint32_t const NUM_SELECTIONS = 3; uint32_t const NUM_SELECTIONS = 3;
int main() int main()
{ {
// 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); srand(100);
bool ok = true; bool ok = true;
@ -32,35 +39,26 @@ int main()
if (ok) if (ok)
ok = key_ceremony(&joint_key, trustee_states); ok = key_ceremony(&joint_key, trustee_states);
// Open the voting results files // Open the voting results file
FILE *voting_results = NULL; FILE *voting_results = NULL;
if (ok) if (ok)
{ {
voting_results = fmkstemps("voting_results-XXXXXX.txt", 4, "w"); voting_results = fmkstemps("voting_results-XXXXXX", "w+x");
if (voting_results == NULL) if (voting_results == NULL)
ok = false; ok = false;
} }
// Voting // Voting
if (ok) if (ok)
ok = voting(joint_key, voting_results); ok = voting(joint_key, voting_results);
// Rewind the voting results file to the beginning and set mode to reading
if (ok)
{
voting_results = freopen(NULL, "r", voting_results);
if (voting_results == NULL)
ok = false;
}
// Open the tally file // Open the tally file
FILE *tally = NULL; FILE *tally = NULL;
if (ok) if (ok)
{ {
tally = fmkstemps("tally-XXXXXX.txt", 4, "w"); tally = fmkstemps("tally-XXXXXX", "wx");
if (tally == NULL) if (tally == NULL)
ok = false; ok = false;
} }
@ -70,6 +68,7 @@ int main()
ok = decryption(voting_results, tally, trustee_states); ok = decryption(voting_results, tally, trustee_states);
// Cleanup // Cleanup
if (voting_results != NULL) if (voting_results != NULL)
{ {
fclose(voting_results); fclose(voting_results);
@ -101,37 +100,34 @@ int main()
return EXIT_FAILURE; return EXIT_FAILURE;
} }
FILE *fmkstemps(char const *template, int suffixlen, const char *mode) FILE *fmkstemps(char const *template, const char *mode)
{ {
bool ok = true; bool ok = true;
FILE *result = NULL; FILE *result = NULL;
// Duplicate the template. It needs to be mutable for mkstemps.
char *template_mut = strdup(template); char *template_mut = strdup(template);
if (template_mut == NULL) if (template_mut == NULL)
ok = false; ok = false;
int fd = -1; // Create and open the temporary file
if (ok) if (ok)
{ {
fd = mkstemps(template_mut, suffixlen); template_mut = mktemp(template_mut);
if (fd < 0) if (template_mut == NULL)
ok = false; ok = false;
} }
// Convert the file descripter to a FILE*
if (ok) if (ok)
{ {
result = fdopen(fd, mode); result = fopen(template_mut, mode);
if (result == NULL) if (result == NULL)
ok = false; ok = false;
} }
if (!ok && fd >= 0) // Free the duplicated template
{
close(fd);
fd = -1;
}
if (template_mut != NULL) if (template_mut != NULL)
{ {
free(template_mut); free(template_mut);

Просмотреть файл

@ -16,8 +16,8 @@ static bool tally_voting_records(FILE *in);
static bool decrypt_tally_shares(void); static bool decrypt_tally_shares(void);
static bool decrypt_tally_fragments(bool *requests_present, static bool decrypt_tally_decryption_fragments(
struct fragments_request *requests); bool *requests_present, struct decryption_fragments_request *requests);
static Decryption_Trustee trustees[MAX_TRUSTEES]; static Decryption_Trustee trustees[MAX_TRUSTEES];
static Decryption_Coordinator coordinator; static Decryption_Coordinator coordinator;
@ -38,15 +38,15 @@ bool decryption(FILE *in, FILE *out, struct trustee_state *trustee_states)
if (ok) if (ok)
ok = decrypt_tally_shares(); ok = decrypt_tally_shares();
struct fragments_request requests[MAX_TRUSTEES]; struct decryption_fragments_request requests[MAX_TRUSTEES];
bool request_present[MAX_TRUSTEES]; bool request_present[MAX_TRUSTEES];
for (uint32_t i = 0; i < NUM_TRUSTEES; i++) for (uint32_t i = 0; i < NUM_TRUSTEES; i++)
requests[i] = (struct fragments_request){.bytes = NULL}; requests[i] = (struct decryption_fragments_request){.bytes = NULL};
if (ok) if (ok)
{ {
struct Decryption_Coordinator_all_tally_shares_received_r result = struct Decryption_Coordinator_all_shares_received_r result =
Decryption_Coordinator_all_tally_shares_received(coordinator); Decryption_Coordinator_all_shares_received(coordinator);
if (result.status != DECRYPTION_COORDINATOR_SUCCESS) if (result.status != DECRYPTION_COORDINATOR_SUCCESS)
ok = false; ok = false;
@ -57,7 +57,7 @@ bool decryption(FILE *in, FILE *out, struct trustee_state *trustee_states)
} }
if (ok) if (ok)
ok = decrypt_tally_fragments(request_present, requests); ok = decrypt_tally_decryption_fragments(request_present, requests);
if (ok) if (ok)
{ {
@ -156,8 +156,8 @@ bool decrypt_tally_shares(void)
struct decryption_share share = {.bytes = NULL}; struct decryption_share share = {.bytes = NULL};
{ {
struct Decryption_Trustee_decrypt_tally_share_r result = struct Decryption_Trustee_compute_share_r result =
Decryption_Trustee_decrypt_tally_share(trustees[i]); Decryption_Trustee_compute_share(trustees[i]);
if (result.status != DECRYPTION_TRUSTEE_SUCCESS) if (result.status != DECRYPTION_TRUSTEE_SUCCESS)
ok = false; ok = false;
@ -168,7 +168,7 @@ bool decrypt_tally_shares(void)
if (ok) if (ok)
{ {
enum Decryption_Coordinator_status status = enum Decryption_Coordinator_status status =
Decryption_Coordinator_recieve_tally_share(coordinator, share); Decryption_Coordinator_receive_share(coordinator, share);
if (status != DECRYPTION_COORDINATOR_SUCCESS) if (status != DECRYPTION_COORDINATOR_SUCCESS)
ok = false; ok = false;
} }
@ -183,8 +183,8 @@ bool decrypt_tally_shares(void)
return ok; return ok;
} }
bool decrypt_tally_fragments(bool *requests_present, bool decrypt_tally_decryption_fragments(
struct fragments_request *requests) bool *requests_present, struct decryption_fragments_request *requests)
{ {
bool ok = true; bool ok = true;
@ -192,33 +192,33 @@ bool decrypt_tally_fragments(bool *requests_present,
{ {
if (requests_present[i]) if (requests_present[i])
{ {
struct fragments fragments = {.bytes = NULL}; struct decryption_fragments decryption_fragments = {.bytes = NULL};
{ {
struct Decryption_Trustee_decrypt_share_fragments_r result = struct Decryption_Trustee_compute_fragments_r result =
Decryption_Trustee_decrypt_tally_share_fragments( Decryption_Trustee_compute_fragments(trustees[i],
trustees[i], requests[i]); requests[i]);
if (result.status != DECRYPTION_TRUSTEE_SUCCESS) if (result.status != DECRYPTION_TRUSTEE_SUCCESS)
ok = false; ok = false;
else else
fragments = result.fragments; decryption_fragments = result.fragments;
} }
if (ok) if (ok)
{ {
enum Decryption_Coordinator_status status = enum Decryption_Coordinator_status status =
Decryption_Coordinator_receive_tally_fragments(coordinator, Decryption_Coordinator_receive_fragments(
fragments); coordinator, decryption_fragments);
if (status != DECRYPTION_COORDINATOR_SUCCESS) if (status != DECRYPTION_COORDINATOR_SUCCESS)
ok = false; ok = false;
} }
if (fragments.bytes != NULL) if (decryption_fragments.bytes != NULL)
{ {
free((void *)fragments.bytes); free((void *)decryption_fragments.bytes);
fragments.bytes = NULL; decryption_fragments.bytes = NULL;
} }
} }
} }

Просмотреть файл

@ -1,7 +1,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "main_key_ceremony.h" #include "main_keyceremony.h"
#include "main_params.h" #include "main_params.h"
// Initialize // Initialize

Просмотреть файл

Просмотреть файл

@ -1,8 +1,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include "main_params.h" #include "main_params.h"
#include "main_voting.h" #include "main_voting.h"
#include "voting/tracker.h"
static bool initialize_encrypters(struct joint_public_key joint_key); static bool initialize_encrypters(struct joint_public_key joint_key);
@ -146,6 +146,15 @@ bool simulate_random_votes(uint32_t encrypter_ix, uint64_t num_ballots)
} }
} }
// Print the tracker
if (ok)
{
char *tracker_string = display_ballot_tracker(tracker);
int status = puts(tracker_string);
if (status == EOF)
ok = false;
}
// Register the ballot // Register the ballot
if (ok) if (ok)
{ {

Просмотреть файл

@ -1,101 +0,0 @@
# ElectionGuard SDK Public API
This API is designed to allow clients to correctly implement an E2E
Verifiable election. In designing this API, we tried to balance the
following constraints and goals:
- *correct*: The API must provide the necessary tools to implement a
correct E2E verifiable election system.
- *communication agnostic*: The client is responsible for managing
communication between components. Those components may be a part of
the same program and communicate via argument-passing, or they may
be on entirely different servers and communicate over a network.
This leads to a design in which the entities produce and consume
messages that drive the election process forward and enforce an
ordering on operations.
- *easy to use*: We want the API to be easy to use correctly. This
means reducing the number of methods and calls as much as possible,
as well as using the types of messages to guide the user towards
correct usage of the API.
- *general*: We try to no extra assumptions about the set-up of the
election other than those required by the ElectionGuard E2E
Verifiable specification.
## Overview of an election
There are 3 phases of an election:
1. **Key Ceremony**: A group of `n` trustees jointly generate a joint
public key such that for a predetermined threshold `k`, any `k` of
the trustees can decrypt a message encrypted by the public key.
2. **Voting**: Voters cast their ballots at various polling locations.
Their ballots are encrypted using the the joint public key.
3. **Tallying and Decryption**: A group of at least `k` of the
trustees jointly decrypt the tally of all the ballots and publish
sufficient information for anyone to verify that the tally and
decryption was carried out correctly.
For more information about these phases, see the READMEs in
[`key_ceremony`](./key_ceremony), [`voting`](./voting),
[`decryption`](./decryption) respectively.
Within the API, these phases are represented by interactions between
various entities:
1. The key ceremony is carried out by `n` `Key_Ceremony_Trustee` objects
representing the election trustees, and a single
`Key_Ceremony_Coordinator` object that provides a central "location"
to which `Key_Ceremony_Trustee`s submit pieces of information and
which then broadcasts the information of all the `Key_Ceremony_Trustee`s
back to each `Trustee`.
2. Voting is carried out by groups of many `Voting_Encrypters`s
(probably located within Ballot Marking Devices) connected to a
single `Voting_Coordinator`, where each group represents a single
polling location. The `Voting_Coordinator` is responsible for
keeping track of which ballots have been registered, cast, and
spoiled.
3. Tallying is carried out by a group of at least `k`
`Decryption_Trustee` objects representing the election trustees,
and a single `Decryption_Coordinator` object in a structure very
similar to that of the Key Ceremony.
We chose to separate the trustees and coordinators
into `Key_Ceremony_Trustee`s/`Decryption_Trustee`s and
`Key_Ceremony_Coordinator`s/`Decryption_Coordinator`s respectively.
This is because conceptually a trustee has two distinct tasks, key
generation and decryption, that are linked by a small kernel of
persisted information such as the trustee's private key and key
shares. Decryption will probably happen at least a day after the key
ceremony, so it is important that the information necessary for
decryption can be stored for a long period of time. Making the
distinction between `Key_Ceremony_Trustee`s and `Decryption_Trustee`s
and making the persisted `struct trustee_state` explicit and serializable
makes the APIs of each component simpler and makes it easier to
persist the `struct trustee_state` over the course of the election.
## Table of Contents
- [`keyceremony`](/.keyceremony)
- [`messages.h`](./keyceremony/messages.h) defines the types of the
messages used in the key ceremony.
- [`trustee.h`](./keyceremony/trustee.h) defines the
`Key_Ceremony_Trustee` type.
- [`coordinator.h`](./keyceremony/coordinator.h) defines the
`Key_Ceremony_Coordinator` type.
- [`voting`](./voting)
- [`messages.h`](./voting/messages.h) defines the types of messages used in voting.
- [`encrypter.h`](./voting/encrypter.h) defines the
type `Voting_Encrypter`.
- [`coordinator.h`](./voting/coordinator.h) defines the type `Voting_Coordinator`.
- [`decryption`](./decryption)
- [`messages.h`](./decryption/messages.h) defines the types of the
messages used in decryption.
- [`trustee.h`](./decryption/trustee.h) defines the
`Decryption_Trustee` type.
- [`coordinator.h`](./decryption/coordinator.h) defines the
`Decryption_Coordinator` type.
- [`trustee_state.h`](./trustee_state.h) defines the `struct trustee_state`
type, which links `Key_Ceremony_Trustee`s to `Decryption_Trustee`s.
- [`crypto.h`](./crypto.h) defines the type `struct joint_public_key`
which represents the joint public key produced at the end of the
key ceremony.
- [`max_values.h`](./max_values.h) defines compile-time upper bounds
on certain values, such as the number of trustees. This allows us
to use static allocation in many contexts.

76
include/README.rst Normal file
Просмотреть файл

@ -0,0 +1,76 @@
API Reference
============================
This API is designed to allow clients to correctly implement an E2E
Verifiable election. In designing this API, we tried to balance the
following constraints and goals:
- *correct:* The API must provide the necessary tools to implement a correct
E2E verifiable election system.
- *communication agnostic:* The client is responsible for managing
communications between components. Those components may be a part of
the same program and communicate via argument-passing, or they may
be on entirely different servers and communicate over a network.
This leads to a design in which the entities produce and consume
messages that drive the election process forward and enforce an
ordering on operations.
- *easy to use:* API should be easy to use correctly. This means
reducing the number of functions calls where possible, as
well as using the types of messages to guide the user towards
correct usage of the API.
- *general:* We try to make no extra assumptions about the set-up of the election
other than those required by the ElectionGuard E2E Verifiable specification.
There are 3 phases of an election:
1. :doc:`Key Ceremony </keyceremony>`: A group of `n` trustees jointly
generate a joint public key such that for a predetermined threshold
`k`, any `k` of the trustees can decrypt a message encrypted by the
public key.
2. :doc:`Voting </voting>`: Voters cast their ballots at various
polling locations. Their ballots are encrypted using the the joint
public key.
3. :doc:`Decryption </decryption>`: A group of at least `k` of the
trustees jointly decrypt the tally of all the ballots and publish
sufficient information for anyone to verify that the tally and
decryption was carried out correctly.
Within the API, these phases are represented by interactions between
various entities:
1. The key ceremony is carried out by `n` :type:`KeyCeremony_Trustee`
objects representing the election trustees, and a single
:type:`KeyCeremony_Coordinator` object that provides a central
“location” to which :type:`KeyCeremony_Trustee`\ s submit pieces of
information, and which then broadcasts that information to all the
:type:`KeyCeremony_Trustee`\ s.
2. Voting is carried out by groups of many :type:`Voting_Encrypter`\ s
(probably located within ballot marking devices) connected to a
single :type:`Voting_Coordinator`. Each group represents a single
polling location. The :type:`Voting_Encrypter` is responsible for
encrypting ballots to produce :type:`ballot_tracker`\ s and
:type:`ballot_identifier`\ s. The :type:`Voting_Coordinator`
is responsible for keeping track of which ballots have been
registered, cast, and spoiled.
3. Tallying is carried out by a group of at least `k`
:type:`Decryption_Trustee` objects representing the election
trustees, and a single :type:`Decryption_Coordinator` object in a
structure very similar to that of the Key Ceremony.
We chose to separate the trustees and coordinators into
:type:`KeyCeremony_Trustee`\ s/\ :type:`Decryption_Trustee`\ s and
:type:`KeyCeremony_Coordinator`\ s/\ :type:`Decryption_Coordinator`\
s respectively. This is because conceptually a trustee has two
distinct tasks, key generation and decryption, that are linked by a
small kernel of persisted information such as the trustees private
key and key shares. Decryption will probably happen at least a day
after the key ceremony, so it is important that the information
necessary for decryption can be stored for a long period of time.
Making the distinction between :type:`KeyCeremony_Trustee`\ s and
:type:`Decryption_Trustee`\ s and making the persisted
:type:`trustee_state` explicit and serializable makes the APIs of each
component simpler and makes it easier to persist the
:type:`trustee_state` over the course of the election.

Просмотреть файл

@ -5,17 +5,27 @@
#include "max_values.h" #include "max_values.h"
enum KeySize_e /** Size of a key in bytes. */
enum KEY_SIZE_e
{ {
/* Size of a key in bytes. */
KEY_SIZE = 4096 / 8, KEY_SIZE = 4096 / 8,
};
MAX_PUBLIC_KEY_SIZE = MAX_TRUSTEES * KEY_SIZE, /** Maximum size of a private key in bytes. */
enum MAX_PRIVATE_KEY_SIZE_e
{
MAX_PRIVATE_KEY_SIZE = MAX_TRUSTEES * KEY_SIZE, MAX_PRIVATE_KEY_SIZE = MAX_TRUSTEES * KEY_SIZE,
}; };
/* A public key that will be used to encrypt ballots, such that /** Maximum size of a public key in bytes. */
* any group of `k` of the original trustees can decrypt a message enum MAX_PUBLIC_KEY_SIZE_e
{
MAX_PUBLIC_KEY_SIZE = MAX_TRUSTEES * KEY_SIZE,
};
/**
* A public key that will be used to encrypt ballots, such that any
* group of `k` of the original trustees can decrypt a message
* encrypted with this key. */ * encrypted with this key. */
struct joint_public_key struct joint_public_key
{ {

Просмотреть файл

@ -1,47 +0,0 @@
# Decryption
After the election is over, the voting records from each polling
location are aggregated and tallied by the trustees. They each submit
a share of the decrypted tallies to the coordinator. The coordinator
may request fragments of shares from coordinators in order to
compensate for missing trustees. Then the coordinator combines the
shares to form the decrypted tallies, and publishes them along with
the necessary information for external verifiers to verify the
tallies, and for individual voters to verify that their vote was
included in the tally.
**Note:** It's easy to get confused if we aren't careful about
distinguishing between a trustee's portion of a decrypted message
(which I refer to as a share) and a trustee's portion of some other
missing trustees portion of a decrypted message (which I refer to as a
share fragment). I think it's okay if we also use share to refer to
the pieces of the other trustee's private keys, because in both cases
every trustee has exactly `n` of them.
## Tallying
After the election, the encrypted totals need to be transported to
each of the trustees individually and combined to form the voting
record of the election. Independently, each trustee then computes
their share of the decrypted tallies.
## Announcing
Each trustee announces their presence by publishing their share of the
encrypted tally. The proof of correctness ensures that each trustee is
actually in possession of that trustee's private key.
## Compensating
Once the coordinator decides that all trustees who
are going to announce have announced, it checks how many trustees
have announced.
a. If fewer than the threshold have announced, error.
b. If enough trustees have announced to reach the threshold, it returns
a list of requests for some of the announced trustees. These
requests must be passed to the trustees, who will respond with
share fragments to fulfill those requests. It is up to the
coordinator how to split the task of compensating for missing
trustees between the announced trustees. The coordinator can choose
not to produce requests for some of the announced trustees, or to
produce requests that request no fragments.

Просмотреть файл

@ -0,0 +1,91 @@
Decryption
==========
After the election is over, the voting records from each polling
location are aggregated and tallied by the :type:`trustee
<Decryption_Trustee>`\ s. [#]_ They each submit a :type:`share
<decryption_share>` of the decrypted tallies to the :type:`coordinator
<Decryption_Coordinator>`. [#]_ The :type:`coordinator
<Decryption_Coordinator>` may request :type:`fragments of shares
<decryption_fragments>` from :type:`trustee <Decryption_Trustee>`\ s in order to
compensate for missing :type:`trustee <Decryption_Trustee>`\ s. [#]_
Then the :type:`coordinator <Decryption_Coordinator>` combines the
shares to form the decrypted tallies, and publishes them along with
the necessary information for external verifiers to verify the
tallies, and for individual voters to verify that their vote was
included in the tally. [#]_
.. [#] :func:`Decryption_Trustee_tally_voting_record()`
.. [#] :func:`Decryption_Coordinator_receive_share()`
.. [#] :func:`Decryption_Coordinator_all_shares_received()`, :func:`Decryption_Trustee_compute_fragments()`
.. [#] :func:`Decryption_Coordinator_all_fragments_received`
.. note::
Its easy to get confused if we arent careful about distinguishing
between a :type:`trustee <Decryption_Trustee>`\ 's portion of a
decrypted total (which I refer to as a share) and a :type:`trustee
<Decryption_Trustee>`\ 's portion of some other missing
:type:`trustee <Decryption_Trustee>`\ 's portion of a decrypted
total (which I refer to as a share fragment). I think its okay if
we also use share to refer to the pieces of the other :type:`trustee
<Decryption_Trustee>`\ 's private keys, because in both cases every
:type:`trustee <Decryption_Trustee>` has exactly `n` of them.
Tallying
--------
After the election, the encrypted totals need to be transported to
each :type:`trustee <Decryption_Trustee>` individually and combined to
form the voting record of the election. [#]_ Independently, each trustee
then computes their share of the decrypted tallies. [#]_
.. [#] :func:`Decryption_Trustee_tally_voting_record()`
.. [#] :func:`Decryption_Trustee_compute_share()`
Announcing
----------
Each :type:`trustee <Decryption_Trustee>` announces their presence by
publishing their share of the encrypted tally. [#]_ The proof of
correctness ensures that each :type:`trustee <Decryption_Trustee>` is
actually in possession of that :type:`trustee <Decryption_Trustee>`\
's private key.
.. [#] :func:`Decryption_Coordinator_receive_share()`
Compensating
------------
Once the :type:`coordinator <Decryption_Coordinator>` decides that all
:type:`trustee <Decryption_Trustee>`\ s who are going to announce have
announced, it checks how many :type:`trustee <Decryption_Trustee>`\ s
have announced. [#]_
a. If fewer than the threshold have announced, error.
b. If enough :type:`trustee <Decryption_Trustee>`\ s have announced to
reach the threshold, it returns a list of :type:`request
<decryption_fragments_request>`\ s for some of the announced :type:`trustee
<Decryption_Trustee>`\ s. These :type:`request
<decryption_fragments_request>`\ s must be passed to the :type:`trustee
<Decryption_Trustee>`\ s, who will respond with :type:`share
fragments <decryption_fragments>` to fulfill those requests. [#]_
It is up to the :type:`coordinator <Decryption_Coordinator>` how to
split the task of compensating for missing :type:`trustee
<Decryption_Trustee>`\ s between the announced :type:`trustee
<Decryption_Trustee>`\ s. The coordinator can choose not to produce
requests for some of the announced :type:`trustee
<Decryption_Trustee>`\ s, or to produce requests that request no
fragments.
Publishing
----------
After all missing trustees have been compensated for, the
:type:`coordinator <Decryption_Coordinator>` publishes the decrypted
totals and the necessary information to verify the election. [#]_
.. [#] :func:`Decryption_Coordinator_all_shares_received()`
.. [#] :func:`Decryption_Trustee_compute_fragments()`
.. [#] :func:`Decryption_Coordinator_all_fragments_received()`

Просмотреть файл

@ -32,7 +32,9 @@ enum Decryption_Coordinator_status
/************************** INITIALIZATION & FREEING ***************************/ /************************** INITIALIZATION & FREEING ***************************/
/* Create a new decryption coordinator */ /**
* Create a new decryption coordinator.
*/
struct Decryption_Coordinator_new_r struct Decryption_Coordinator_new_r
Decryption_Coordinator_new(uint32_t num_trustees, uint32_t threshold); Decryption_Coordinator_new(uint32_t num_trustees, uint32_t threshold);
@ -42,47 +44,54 @@ struct Decryption_Coordinator_new_r
Decryption_Coordinator coordinator; Decryption_Coordinator coordinator;
}; };
/* Free a decryption coordinator. */ /**
* Free a decryption coordinator.
*/
void Decryption_Coordinator_free(Decryption_Coordinator c); void Decryption_Coordinator_free(Decryption_Coordinator c);
/********************************* ANNOUNCING **********************************/ /********************************* ANNOUNCING **********************************/
/* Receive a trustee's share of a decrypted tally */ /* Receive a trustee's share of a decrypted tally */
enum Decryption_Coordinator_status enum Decryption_Coordinator_status
Decryption_Coordinator_recieve_tally_share(Decryption_Coordinator c, Decryption_Coordinator_receive_share(Decryption_Coordinator c,
struct decryption_share share); struct decryption_share share);
/* Check that at least the threshold number of trustees have sent /**
their shares. Return a list of share fragments to be provided by * Check that at least the threshold number of trustees have sent
each trustee who has sent a share: for each trustee index i from 0 * their shares. Return a list of share fragments to be provided by
to num_trustees (exclusive), if request_present[i] is true, the * each trustee who has sent a share: for each trustee index i from 0
caller must pass requests[i] to the appropriate trustee, and must * to num_trustees (exclusive), if request_present[i] is true, the
free requests[i].bytes. If status is not * caller must pass requests[i] to the appropriate trustee, and must
DECRYPTION_COORDINATOR_SUCCESS, the client is not responsible for * free requests[i].bytes. If status is not
freeing anything. * DECRYPTION_COORDINATOR_SUCCESS, the client is not responsible for
*/ * freeing anything.
struct Decryption_Coordinator_all_tally_shares_received_r */
Decryption_Coordinator_all_tally_shares_received(Decryption_Coordinator c); struct Decryption_Coordinator_all_shares_received_r
Decryption_Coordinator_all_shares_received(Decryption_Coordinator c);
struct Decryption_Coordinator_all_tally_shares_received_r struct Decryption_Coordinator_all_shares_received_r
{ {
enum Decryption_Coordinator_status status; enum Decryption_Coordinator_status status;
uint32_t num_trustees; uint32_t num_trustees;
bool request_present[MAX_TRUSTEES]; bool request_present[MAX_TRUSTEES];
struct fragments_request requests[MAX_TRUSTEES]; struct decryption_fragments_request requests[MAX_TRUSTEES];
}; };
/******************************* COMPENSATING ********************************/ /******************************* COMPENSATING ********************************/
/* Receive the requested set of share fragments from a trustee */ /**
* Receive the requested set of share fragments from a trustee.
*/
enum Decryption_Coordinator_status enum Decryption_Coordinator_status
Decryption_Coordinator_receive_tally_fragments(Decryption_Coordinator c, Decryption_Coordinator_receive_fragments(Decryption_Coordinator c,
struct fragments fragments); struct decryption_fragments fragments);
// @todo jwaksbaum Do we want to return the number of bytes written? // @todo jwaksbaum Do we want to return the number of bytes written?
/* Check that all trustees have sent their share fragments of the /**
missing trustees' shares. Write the decrypted total to out. */ * Check that all trustees have sent their share fragments of the
* missing trustees' shares. Write the decrypted total to out.
*/
enum Decryption_Coordinator_status enum Decryption_Coordinator_status
Decryption_Coordinator_all_fragments_received(Decryption_Coordinator c, Decryption_Coordinator_all_fragments_received(Decryption_Coordinator c,
FILE *out); FILE *out);

Просмотреть файл

@ -3,24 +3,26 @@
#include <stdint.h> #include <stdint.h>
/* A trustee's share of decrypting the results of an election. */ /** A trustee's share of decrypting the results of an election. */
struct decryption_share struct decryption_share
{ {
uint64_t len; uint64_t len;
uint8_t const *bytes; uint8_t const *bytes;
}; };
/* A request from the coordinator to a trustee, asking it to provide /**
fragments to compensate for a missing trustee. */ * A request from the coordinator to a trustee, asking it to provide
struct fragments_request * fragments to compensate for a missing trustee. */
struct decryption_fragments_request
{ {
uint64_t len; uint64_t len;
uint8_t const *bytes; uint8_t const *bytes;
}; };
/* A response from a trustee to a coordinator providing fragments to /**
compensate for a missing trustee. */ * A response from a trustee to a coordinator providing fragments to
struct fragments * compensate for a missing trustee. */
struct decryption_fragments
{ {
uint64_t len; uint64_t len;
uint8_t const *bytes; uint8_t const *bytes;

Просмотреть файл

@ -30,7 +30,7 @@ enum Decryption_Trustee_status
// because the same message (ie. from a coordinator) may need to be // because the same message (ie. from a coordinator) may need to be
// consumed multiple times. // consumed multiple times.
/* Create a new trustee. Does not free the trustee state. */ /** Create a new trustee. Does not free the trustee state. */
struct Decryption_Trustee_new_r struct Decryption_Trustee_new_r
Decryption_Trustee_new(uint32_t num_trustees, uint32_t threshold, Decryption_Trustee_new(uint32_t num_trustees, uint32_t threshold,
uint32_t num_selections, struct trustee_state state); uint32_t num_selections, struct trustee_state state);
@ -41,22 +41,22 @@ struct Decryption_Trustee_new_r
Decryption_Trustee decryptor; Decryption_Trustee decryptor;
}; };
/* Free a trustee. */ /** Free a trustee. */
void Decryption_Trustee_free(Decryption_Trustee d); void Decryption_Trustee_free(Decryption_Trustee d);
/********************************* TALLYING **********************************/ /********************************* TALLYING **********************************/
/* Parse a voting record, tally it, and store the encrypted tally of all the votes. */ /** Parse a voting record, tally it, and store the encrypted tally of all the votes. */
enum Decryption_Trustee_status enum Decryption_Trustee_status
Decryption_Trustee_tally_voting_record(Decryption_Trustee d, FILE *in); Decryption_Trustee_tally_voting_record(Decryption_Trustee d, FILE *in);
/********************************* ANNOUNCING **********************************/ /********************************* ANNOUNCING **********************************/
/* Decrypt this trustee's share of the tally. */ /** Decrypt this trustee's share of the tally. */
struct Decryption_Trustee_decrypt_tally_share_r struct Decryption_Trustee_compute_share_r
Decryption_Trustee_decrypt_tally_share(Decryption_Trustee d); Decryption_Trustee_compute_share(Decryption_Trustee d);
struct Decryption_Trustee_decrypt_tally_share_r struct Decryption_Trustee_compute_share_r
{ {
enum Decryption_Trustee_status status; enum Decryption_Trustee_status status;
struct decryption_share share; struct decryption_share share;
@ -64,15 +64,15 @@ struct Decryption_Trustee_decrypt_tally_share_r
/******************************* COMPENSATING ********************************/ /******************************* COMPENSATING ********************************/
/* Decrypt this trustee's fragment of another trustee's share of the tally.*/ /** Decrypt this trustee's fragment of another trustee's share of the tally.*/
struct Decryption_Trustee_decrypt_share_fragments_r struct Decryption_Trustee_compute_fragments_r
Decryption_Trustee_decrypt_tally_share_fragments(Decryption_Trustee d, Decryption_Trustee_compute_fragments(Decryption_Trustee d,
struct fragments_request req); struct decryption_fragments_request req);
struct Decryption_Trustee_decrypt_share_fragments_r struct Decryption_Trustee_compute_fragments_r
{ {
enum Decryption_Trustee_status status; enum Decryption_Trustee_status status;
struct fragments fragments; struct decryption_fragments fragments;
}; };
#endif #endif /* __DECRYPTION_TRUSTEE_H__ */

Просмотреть файл

@ -1,43 +0,0 @@
# Key Ceremony
The key ceremony is carried out between `n` trustees and a single
coordinator. Its purpose is to ensure that the coordinator
possesses an joint public key, and that each trustee possesses:
- a private key
- all the trustees' public keys
- a set of key shares that allow the trustee to, as a part of a
group of at least `k` trustees, to decrypt a missing trustee's
share of a message encrypted with the aggregate public key.
## Key Generation
The first phase is **key generation**:
1. Each trustee generates a key pair, producing a
`struct key_generated_message`.
2. These `n` `struct key_generated_message`s are passed to the
coordinator.
3. The coordinator produces an `struct all_keys_received_message`,
which must be passed back to each trustee.
## Share Generation
The second phase is **share generation**:
1. Each trustee, having received an `struct
all_keys_received_message`, computes a key share for each other
trustee, and encrypts it with that trustee's public key, producing
a `struct shares_generated_message`.
2. These `n` `struct shares_generated_message`s are passed to the
coordinator.
3. The coordinator produces a `struct all_shares_received_message`,
which must be passed back to each trustee.
## Verification
The third phase is **verification**:
1. Each trustee, having received an `struct
all_shares_received_message`, decrypts its shares of the other
trustees keys and verifies that they match the commitments in their
public keys, producing a `struct shares_verified_message`.
2. These `n` `struct shares_verified_message`s are passed to the
coordinator.
3. The coordinator produces a `struct joint_public_key`.

Просмотреть файл

@ -0,0 +1,62 @@
Key Ceremony
============
The key ceremony is carried out between `n` :type:`trustee
<KeyCeremony_Trustee>`\ s and a single :type:`coordinator
<KeyCeremony_Coordinator>`. Its purpose is to ensure that the
coordinator possesses an joint public key, and that each trustee
possesses: - a private key - all the trustees public keys - a set of
key shares that allow the trustee to, as a part of a group of at least
`k` trustees, to decrypt a missing trustees share of a message
encrypted with the aggregate public key.
Key Generation
--------------
1. Each trustee generates a key pair, [#]_ producing a
:type:`key-generated message <key_generated_message>`.
2. These `n` :type:`key-generated message <key_generated_message>`\ s are passed to the
coordinator. [#]_
3. The coordinator produces an :type:`all-keys-received message <all_keys_received_message>`, [#]_
which must be passed back to each trustee. [#]_
.. [#] :func:`KeyCeremony_Trustee_generate_key()`
.. [#] :func:`KeyCeremony_Coordinator_receive_key_generated()`
.. [#] :func:`KeyCeremony_Coordinator_all_keys_received()`
.. [#] :func:`KeyCeremony_Trustee_generate_shares()`
Share Generation
----------------
1. Each trustee, having received an :type:`all-keys-received message
<all_keys_received_message>`, computes a key share for every
trustee, and encrypts each key share with the corresponding
trustees public key to produce a :type:`shares-generated message
<shares_generated_message>` [#]_.
2. These `n` :type:`shares-generated message
<shares_generated_message>`\ s are passed to the coordinator [#]_.
3. The coordinator produces a :type:`all-shares-received message
<all_shares_received_message>`, [#]_ which must be passed back to
each trustee. [#]_
.. [#] :func:`KeyCeremony_Trustee_generate_shares()`
.. [#] :func:`KeyCeremony_Coordinator_receive_shares_generated()`
.. [#] :func:`KeyCeremony_Coordinator_all_shares_received()`
.. [#] :func:`KeyCeremony_Trustee_verify_shares()`
Verification
------------
1. Each trustee, having received an :type:`all-shares-received message
<all_shares_received_message>`, decrypts its shares of the other
trustees keys and verifies that they match the commitments in their
public keys, producing a :type:`shares-verified message
<shares_verified_message>`. [#]_
2. These `n` :type:`shares-verified message
<shares_verified_message>`\ s are passed to the coordinator. [#]_
3. The coordinator produces a :type:`joint public key
<joint_public_key>`. [#]_
.. [#] :func:`KeyCeremony_Trustee_verify_shares()`
.. [#] :func:`KeyCeremony_Coordinator_receive_shares_verified`
.. [#] :func:`KeyCeremony_Coordinator_publish_joint_key`

Просмотреть файл

@ -7,6 +7,10 @@
#include "crypto.h" #include "crypto.h"
#include "keyceremony/messages.h" #include "keyceremony/messages.h"
/**
* Responsible for coordinating communication between the trustees
* during the key ceremony.
*/
typedef struct KeyCeremony_Coordinator_s *KeyCeremony_Coordinator; typedef struct KeyCeremony_Coordinator_s *KeyCeremony_Coordinator;
// @todo jwaksbaum Document what these means, maybe even add a way to // @todo jwaksbaum Document what these means, maybe even add a way to
@ -24,11 +28,11 @@ enum KeyCeremony_Coordinator_status
KEYCEREMONY_COORDINATOR_TRUSTEE_INVALIDATION, KEYCEREMONY_COORDINATOR_TRUSTEE_INVALIDATION,
KEYCEREMONY_COORDINATOR_SERIALIZE_ERROR, KEYCEREMONY_COORDINATOR_SERIALIZE_ERROR,
KEYCEREMONY_COORDINATOR_DESERIALIZE_ERROR, KEYCEREMONY_COORDINATOR_DESERIALIZE_ERROR,
} KeyCeremony_Coordinator_Status; };
/************************** INITIALIZATION & FREEING ***************************/ /************************** INITIALIZATION & FREEING ***************************/
/* Create a new coordinator. */ /** Create a new coordinator. */
struct KeyCeremony_Coordinator_new_r struct KeyCeremony_Coordinator_new_r
KeyCeremony_Coordinator_new(uint32_t num_trustees, uint32_t threshold); KeyCeremony_Coordinator_new(uint32_t num_trustees, uint32_t threshold);
@ -38,7 +42,7 @@ struct KeyCeremony_Coordinator_new_r
KeyCeremony_Coordinator coordinator; KeyCeremony_Coordinator coordinator;
}; };
/* Free a coordinator. */ /** Free a coordinator. */
void KeyCeremony_Coordinator_free(KeyCeremony_Coordinator c); void KeyCeremony_Coordinator_free(KeyCeremony_Coordinator c);
/******************************* KEY_GENERATION ********************************/ /******************************* KEY_GENERATION ********************************/
@ -56,16 +60,18 @@ void KeyCeremony_Coordinator_free(KeyCeremony_Coordinator c);
// - In the case of failure, do we require that the entire process // - In the case of failure, do we require that the entire process
// restart, or do we let them try again from where the left off? // restart, or do we let them try again from where the left off?
/* Receive a message indicating that a trustee has generated its /**
key-pair, which contains the trustee's public key. Checks the NIZKP * Receive a message indicating that a trustee has generated its
of possession of the private key.*/ * key-pair, which contains the trustee's public key. Checks the NIZKP
* of possession of the private key.*/
enum KeyCeremony_Coordinator_status enum KeyCeremony_Coordinator_status
KeyCeremony_Coordinator_receive_key_generated( KeyCeremony_Coordinator_receive_key_generated(
KeyCeremony_Coordinator c, struct key_generated_message message); KeyCeremony_Coordinator c, struct key_generated_message message);
/* Assert that exactly one key_generated_message from each trustee has /**
been received, and generate an all_keys_generated_message containing * Assert that exactly one key_generated_message from each trustee has
all of the public keys. */ * been received, and generate an all_keys_generated_message
* containing all of the public keys. */
struct KeyCeremony_Coordinator_all_keys_received_r struct KeyCeremony_Coordinator_all_keys_received_r
KeyCeremony_Coordinator_all_keys_received(KeyCeremony_Coordinator c); KeyCeremony_Coordinator_all_keys_received(KeyCeremony_Coordinator c);
@ -77,15 +83,17 @@ struct KeyCeremony_Coordinator_all_keys_received_r
/****************************** SHARE_GENERATION *******************************/ /****************************** SHARE_GENERATION *******************************/
/* Receive a message containing a trustees encrypted shares of its /**
private key. */ * Receive a message containing a trustees encrypted shares of its
* private key. */
enum KeyCeremony_Coordinator_status enum KeyCeremony_Coordinator_status
KeyCeremony_Coordinator_receive_shares_generated( KeyCeremony_Coordinator_receive_shares_generated(
KeyCeremony_Coordinator c, struct shares_generated_message message); KeyCeremony_Coordinator c, struct shares_generated_message message);
/* Assert that exactly one shares_generated_message from each trustee /**
has been received, and generate an all_shares_received_message * Assert that exactly one shares_generated_message from each trustee
containing all of the encrypted key shares. */ * has been received, and generate an all_shares_received_message
* containing all of the encrypted key shares. */
struct KeyCeremony_Coordinator_all_shares_received_r struct KeyCeremony_Coordinator_all_shares_received_r
KeyCeremony_Coordinator_all_shares_received(KeyCeremony_Coordinator c); KeyCeremony_Coordinator_all_shares_received(KeyCeremony_Coordinator c);
@ -97,16 +105,18 @@ struct KeyCeremony_Coordinator_all_shares_received_r
/******************************** VERIFICATION *********************************/ /******************************** VERIFICATION *********************************/
/* Receive a message indicating that a trustee has verified that the /**
key shares it has received are consistent with the commitments in * Receive a message indicating that a trustee has verified that the
the public keys of each trustee. */ * key shares it has received are consistent with the commitments in
* the public keys of each trustee. */
enum KeyCeremony_Coordinator_status enum KeyCeremony_Coordinator_status
KeyCeremony_Coordinator_receive_shares_verified( KeyCeremony_Coordinator_receive_shares_verified(
KeyCeremony_Coordinator c, struct shares_verified_message message); KeyCeremony_Coordinator c, struct shares_verified_message message);
/* Assert that exactly one shares_verified_message from each trustee /**
has been received, and generate the joint public key to be used to * Assert that exactly one shares_verified_message from each trustee
encrypt votes in the election. */ * has been received, and generate the joint public key to be used to
* encrypt votes in the election. */
struct KeyCeremony_Coordinator_publish_joint_key_r struct KeyCeremony_Coordinator_publish_joint_key_r
KeyCeremony_Coordinator_publish_joint_key(KeyCeremony_Coordinator c); KeyCeremony_Coordinator_publish_joint_key(KeyCeremony_Coordinator c);

Просмотреть файл

@ -3,43 +3,48 @@
#include <stdint.h> #include <stdint.h>
/* The message that is produced by a trustee after generating their /**
public/private keypair, and which must be passed to the * The message that is produced by a trustee after generating their
coordinator. */ * public/private keypair, and which must be passed to the
* coordinator. */
struct key_generated_message struct key_generated_message
{ {
uint64_t len; uint64_t len;
uint8_t const *bytes; uint8_t const *bytes;
}; };
/* The message that is produced by a coordinator after confirming /**
that is has received all of the trustees' public keys, and which * The message that is produced by a coordinator after confirming that
must be passed back to each trustee. */ * is has received all of the trustees' public keys, and which must be
* passed back to each trustee. */
struct all_keys_received_message struct all_keys_received_message
{ {
uint64_t len; uint64_t len;
uint8_t const *bytes; uint8_t const *bytes;
}; };
/* The message that is produced by a trustee after computing and /**
encrypting the shares of its private key for the other trustees. */ * The message that is produced by a trustee after computing and
* encrypting the shares of its private key for the other trustees. */
struct shares_generated_message struct shares_generated_message
{ {
uint64_t len; uint64_t len;
uint8_t const *bytes; uint8_t const *bytes;
}; };
/* The message that is produced by a coordinator after confirming that /**
is has received all of the trustees' encrypted private key shares, * The message that is produced by a coordinator after confirming that
and which must be passed back to each trustee. */ * is has received all of the trustees' encrypted private key shares,
* and which must be passed back to each trustee. */
struct all_shares_received_message struct all_shares_received_message
{ {
uint64_t len; uint64_t len;
uint8_t const *bytes; uint8_t const *bytes;
}; };
/* The message that is produced by a trustee after verifying the /**
private shares of the other trustees. */ * The message that is produced by a trustee after verifying the
* private shares of the other trustees. */
struct shares_verified_message struct shares_verified_message
{ {
uint64_t len; uint64_t len;

Просмотреть файл

@ -25,7 +25,7 @@ enum KeyCeremony_Trustee_status
/************************** INITIALIZATION & FREEING ***************************/ /************************** INITIALIZATION & FREEING ***************************/
/* Create an new trustee. */ /** Create an new trustee. */
struct KeyCeremony_Trustee_new_r KeyCeremony_Trustee_new(uint32_t num_trustees, struct KeyCeremony_Trustee_new_r KeyCeremony_Trustee_new(uint32_t num_trustees,
uint32_t threshold, uint32_t threshold,
uint32_t index); uint32_t index);
@ -36,13 +36,14 @@ struct KeyCeremony_Trustee_new_r
KeyCeremony_Trustee trustee; KeyCeremony_Trustee trustee;
}; };
/* Free a trustee. */ /** Free a trustee. */
void KeyCeremony_Trustee_free(KeyCeremony_Trustee t); void KeyCeremony_Trustee_free(KeyCeremony_Trustee t);
/******************************* KEY_GENERATION ********************************/ /******************************* KEY_GENERATION ********************************/
/* Generate a key pair and return the key_generated_message to be /**
passed to the coordinator. */ * Generate a key pair and return the key_generated_message to be
* passed to the coordinator. */
struct KeyCeremony_Trustee_generate_key_r struct KeyCeremony_Trustee_generate_key_r
KeyCeremony_Trustee_generate_key(KeyCeremony_Trustee t); KeyCeremony_Trustee_generate_key(KeyCeremony_Trustee t);
@ -54,11 +55,13 @@ struct KeyCeremony_Trustee_generate_key_r
/****************************** SHARE_GENERATION *******************************/ /****************************** SHARE_GENERATION *******************************/
/* Verify in_message to ensure: /**
- that this trustee's public key is present * Verify in_message to ensure:
- that any NIZKPs are valid * - that this trustee's public key is present
Then, compute and encrypt the shares of this trustee's private key for the * - that any NIZKPs are valid
other trustees. */ *
* Then, compute and encrypt the shares of this trustee's private key
* for the other trustees. */
struct KeyCeremony_Trustee_generate_shares_r struct KeyCeremony_Trustee_generate_shares_r
KeyCeremony_Trustee_generate_shares( KeyCeremony_Trustee_generate_shares(
KeyCeremony_Trustee t, struct all_keys_received_message in_message); KeyCeremony_Trustee t, struct all_keys_received_message in_message);
@ -71,8 +74,9 @@ struct KeyCeremony_Trustee_generate_shares_r
/******************************** VERIFICATION *********************************/ /******************************** VERIFICATION *********************************/
/* Verify that the private key shares in in_message match the /**
commitments in the previously received public keys. */ * Verify that the private key shares in in_message match the
* commitments in the previously received public keys. */
struct KeyCeremony_Trustee_verify_shares_r KeyCeremony_Trustee_verify_shares( struct KeyCeremony_Trustee_verify_shares_r KeyCeremony_Trustee_verify_shares(
KeyCeremony_Trustee t, struct all_shares_received_message in_message); KeyCeremony_Trustee t, struct all_shares_received_message in_message);
@ -84,8 +88,9 @@ struct KeyCeremony_Trustee_verify_shares_r
/********************************* STATE EXPORT ********************************/ /********************************* STATE EXPORT ********************************/
/* Export the portion of the trustee's state that will be necessary /**
for decryption. */ * Export the portion of the trustee's state that will be necessary
* for decryption. */
struct KeyCeremony_Trustee_export_state_r struct KeyCeremony_Trustee_export_state_r
KeyCeremony_Trustee_export_state(KeyCeremony_Trustee t); KeyCeremony_Trustee_export_state(KeyCeremony_Trustee t);

Просмотреть файл

@ -7,21 +7,23 @@
// constant expressions, allowing us to use them as array sizes, but // constant expressions, allowing us to use them as array sizes, but
// they are not compiled away, making it easier to debug. // they are not compiled away, making it easier to debug.
/* The maximum number of total trustees. */ /** The maximum number of total trustees. */
enum MAX_TRUSTEES_e enum MAX_TRUSTEES_e
{ {
MAX_TRUSTEES = 30 MAX_TRUSTEES = 5
}; };
/* The maximum number of ballots that can be cast by a single ballot /**
box. */ * The maximum number of ballots that can be cast by a voting single
* coordinator. */
enum MAX_BALLOTS_e enum MAX_BALLOTS_e
{ {
MAX_BALLOTS = 1000 MAX_BALLOTS = 1000
}; };
/* The maximum number of selections that can be present for a single /**
election. This is across all races. */ * The maximum number of selections that can be present for a single
* contest. */
enum MAX_SELECTIONS_e enum MAX_SELECTIONS_e
{ {
MAX_SELECTIONS = 1000 MAX_SELECTIONS = 1000

Просмотреть файл

@ -4,10 +4,11 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
/* The state that needs to be persisted over the course of an election /**
and that will be necessary for the trustee to decrypt its share of * The state that needs to be persisted over the course of an election
the election results. This state can be serialized and stored, and * and that will be necessary for the trustee to decrypt its share of
then deserialized and used to construct a Decryption_Trustee. */ * the election results. This state can be serialized and stored, and
* then deserialized and used to construct a Decryption_Trustee. */
struct trustee_state struct trustee_state
{ {
uint64_t len; uint64_t len;

Просмотреть файл

@ -1,48 +0,0 @@
# Voting
Voters cast their ballots at polling locations, which consist of
multiple devices connected on a local network. The types of devices
and their functions can vary based on the details of the election
system, but the ElectionGuard system relies on a voting process in
which voters first create ballots that contain their preferences, and
then can choose to cast or spoil those ballots. To that end, we
provide encrypters to encrypt ballots, and coordinators, which track
which ballots have been created, cast, and spoiled. You can think of
the encrypters as running on the same machine as the ballot marking
devices, and the coordinator as running on the same machine as a
single ballot box.
The flow for casting a ballot is:
1. An encrypter receives an unencrypted ballot and produces
- an *encrypted ballot*, containing all of the selection
information
- a *ballot tracker*, which will be kept by the voter and
used to identify their vote in the list of encrypted
ballots that are included in the final tally
- a *ballot identifier*, which is used to uniquely identify a
ballot in a voting place for the duration of its liveness.
2. The ballot marking device prints
- the ballot tracker
- the ballot identifier, perhaps attached to the unencrypted
contents of the voter's ballot so that they can review their
choices before casting their ballot
3. The encrypted ballot along with the ballot identifier is registered
with the coordinator.
4. The voter may choose to cast or spoil their ballot:
a. If the voter wishes to cast their ballot, they insert the paper
containing the ballot identifier into the ballot box, which
scans it and tells the coordinator to mark the corresponding
ballot as cast.
b. If the voter wishes to spoil their ballot, they take it to a
poll worker where it is marked as spoiled. Optionally, the poll
worker can notify the coordinator that the ballot was spoiled to
ensure that the vote cannot be cast. Otherwise, once the
lifetime of the ballot has passed, the ballot will automatically
be considered as spoiled.
The reason for the addition of the ballot identifier is that the
encrypted ballot will be on the order of megabytes, so we need
another way of referring to a registered ballot.
After voting is over, the coordinator exports the voting record to be
transported to the trustees and decrypted.

91
include/voting/README.rst Normal file
Просмотреть файл

@ -0,0 +1,91 @@
Voting
======
Voters cast their ballots at polling locations, which consist of
multiple devices connected on a local network. The types of devices and
their functions can vary based on the details of the election system,
but the ElectionGuard system relies on a voting process in which voters
first create ballots that contain their preferences, and then can choose
to cast or spoil those ballots.
To that end, we provide :type:`encrypter <Voting_Encrypter>`\ s to
encrypt ballots, and :type:`coordinators <Voting_Coordinator>`, which
track which ballots have been created, cast, and spoiled. In a system
with many ballot marking devices and a single ballot box, you can
think of the encrypters as running on the same machine as the ballot
marking devices, and the coordinator as running on the same machine as
the ballot box.
Initialization
--------------
At the beginning of the election, each :type:`encrypter
<Voting_Encrypter>` must be initialized with the :type:`joint key
<joint_public_key>` that was produced at the end of the key ceremony,
so that the ballots can be encrypted with it. In addition, each
:type:`encrypter <Voting_Encrypter>` is initialized with a
:type:`unique identifier <uid>` that must be unique within a single
polling location.
Casting a Ballot
----------------
The process for casting a ballot is:
1. An encrypter receives an unencrypted ballot (from some sort of
frontend) and produces [#]_
- an :type:`encrypted ballot <register_ballot_message>`, containing
all of the selection information
- a :type:`ballot tracker <ballot_tracker>`, which will be kept by
the voter and used to identify their vote in the list of
encrypted ballots that are included in the final tally
- a :type:`ballot identifier <ballot_identifier>`, which is used to
uniquely identify a ballot in a voting place for the duration of
its liveness. This identifier should not contain any information
about the voter; its purpose is to allow the physical piece of
paper used to cast or spoil a ballot to refer to a specific
ballot without having to encode all of the ballot's contents
.. [#] :func:`Voting_Encrypter_encrypt_ballot()`
2. The ballot marking device, or whatever device the voter is
interacting with, prints
- the :type:`ballot tracker <ballot_tracker>`
- the :type:`ballot identifier <ballot_identifier>`, perhaps
attached to the unencrypted contents of the voters ballot so
that they can review their choices before casting their ballot.
Ideally the `ballot identifier <ballot_identifier>` should be
encoded transparently to the voter so they can see that no
personal information is being associated with their ballot.
3. The :type:`encrypted ballot <register_ballot_message>` along with
the ballot identifier is registered with the coordinator so that it
knows which ballot the identifier refers to. [#]_
.. [#] :func:`Voting_Coordinator_register_ballot()`
4. The voter may choose to cast or spoil their ballot:
a. If the voter wishes to cast their ballot, they insert the paper
containing the ballot identifier into the ballot box or a
similar device, which scans it and tells the coordinator to mark
the corresponding ballot as cast. [#]_
b. If the voter wishes to spoil their ballot, they take it to a
poll worker where it is marked as spoiled. Optionally, the poll
worker can notify the coordinator that the ballot was spoiled to
ensure that the vote cannot be cast. [#]_ Otherwise, once the
lifetime of the ballot has passed, the ballot will automatically
be considered to be spoiled.
.. [#] :func:`Voting_Coordinator_cast_ballot()`
.. [#] :func:`Voting_Coordinator_spoil_ballot()`
Exporting the Voting Record
---------------------------
After voting is over, the coordinator exports the voting record to be
transported to the trustees and decrypted. [#]_
.. [#] :func:`Voting_Coordinator_export_ballots()`

Просмотреть файл

@ -30,7 +30,7 @@ enum Voting_Coordinator_status
// formats so that we can validate that the ballots we receive are // formats so that we can validate that the ballots we receive are
// well-formed? // well-formed?
/* Create a new voting coordinator. */ /** Create a new voting coordinator. */
struct Voting_Coordinator_new_r Voting_Coordinator_new(uint32_t num_selections); struct Voting_Coordinator_new_r Voting_Coordinator_new(uint32_t num_selections);
struct Voting_Coordinator_new_r struct Voting_Coordinator_new_r
@ -39,23 +39,24 @@ struct Voting_Coordinator_new_r
Voting_Coordinator coordinator; Voting_Coordinator coordinator;
}; };
/* Free a ballot box. */ /** Free a ballot box. */
void Voting_Coordinator_free(Voting_Coordinator coordinator); void Voting_Coordinator_free(Voting_Coordinator coordinator);
/****************** REGISTERING, CASTING & SPOILING BALLOTS *******************/ /****************** REGISTERING, CASTING & SPOILING BALLOTS *******************/
/* Register a ballot with the coordinator so that it may be cast or /**
spoiled. */ * Register a ballot with the coordinator so that it may be cast or
* spoiled. */
enum Voting_Coordinator_status enum Voting_Coordinator_status
Voting_Coordinator_register_ballot(Voting_Coordinator coordinator, Voting_Coordinator_register_ballot(Voting_Coordinator coordinator,
struct register_ballot_message message); struct register_ballot_message message);
/* Mark the ballot specified by ballot_id as cast. */ /** Mark the ballot specified by ballot_id as cast. */
enum Voting_Coordinator_status enum Voting_Coordinator_status
Voting_Coordinator_cast_ballot(Voting_Coordinator coordinator, Voting_Coordinator_cast_ballot(Voting_Coordinator coordinator,
struct ballot_identifier ballot_id); struct ballot_identifier ballot_id);
/* Mark the ballot specified by ballot_id as spoiled. */ /** Mark the ballot specified by ballot_id as spoiled. */
enum Voting_Coordinator_status enum Voting_Coordinator_status
Voting_Coordinator_spoil_ballot(Voting_Coordinator coordinator, Voting_Coordinator_spoil_ballot(Voting_Coordinator coordinator,
struct ballot_identifier ballot_id); struct ballot_identifier ballot_id);
@ -66,7 +67,7 @@ Voting_Coordinator_spoil_ballot(Voting_Coordinator coordinator,
// @todo jwaksbaum What format is it writing in? // @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. */
enum Voting_Coordinator_status enum Voting_Coordinator_status
Voting_Coordinator_export_ballots(Voting_Coordinator coordinator, FILE *out); Voting_Coordinator_export_ballots(Voting_Coordinator coordinator, FILE *out);

Просмотреть файл

@ -24,10 +24,11 @@ struct uid
uint8_t const *bytes; uint8_t const *bytes;
}; };
/* Create a new encrypter. Does not transfer ownership of the public /**
key, but creates and allocates a new copy. */ * Create a new encrypter. Does not transfer ownership of the public
* key, but creates and allocates a new copy. */
struct Voting_Encrypter_new_r struct Voting_Encrypter_new_r
Voting_Encrypter_new(struct uid, struct joint_public_key joint_key, Voting_Encrypter_new(struct uid uid, struct joint_public_key joint_key,
uint32_t num_selections); uint32_t num_selections);
struct Voting_Encrypter_new_r struct Voting_Encrypter_new_r
@ -36,7 +37,7 @@ struct Voting_Encrypter_new_r
Voting_Encrypter encrypter; Voting_Encrypter encrypter;
}; };
/* Free a ballot marking device. */ /** Free a ballot marking device. */
void Voting_Encrypter_free(Voting_Encrypter encrypter); void Voting_Encrypter_free(Voting_Encrypter encrypter);
/***************************** BALLOT ENCRYPTION ******************************/ /***************************** BALLOT ENCRYPTION ******************************/
@ -49,9 +50,10 @@ void Voting_Encrypter_free(Voting_Encrypter encrypter);
// responsible for adding information like time, unique ID, etc? Or // responsible for adding information like time, unique ID, etc? Or
// should the GUI layer provide any of that info? // should the GUI layer provide any of that info?
/* Encrypt an unencrypted ballot, producing an encrypted ballot, a /**
ballot tracker, and a ballot identifier. The caller must free both * Encrypt an unencrypted ballot, producing an encrypted ballot, a
when done, ie. they own them. */ * ballot tracker, and a ballot identifier. The caller must free both
* when done, ie. they own them. */
struct Voting_Encrypter_encrypt_ballot_r struct Voting_Encrypter_encrypt_ballot_r
Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter, Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter,
bool const *selections); bool const *selections);

Просмотреть файл

@ -5,8 +5,9 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
/* The message that is passed from the encrypter to the ballot box to /**
register a ballot. */ * The message that is passed from the encrypter to the ballot box to
* register a ballot. */
struct register_ballot_message struct register_ballot_message
{ {
uint64_t len; uint64_t len;
@ -20,17 +21,19 @@ struct register_ballot_message
// with identical identifiers, even if we try to make sure that never // with identical identifiers, even if we try to make sure that never
// happens. // happens.
/* Used by a voter to confirm that their ballot was included in the /**
final tally. */ * Used by a voter to confirm that their ballot was included in the
* final tally. */
struct ballot_tracker struct ballot_tracker
{ {
uint64_t len; uint64_t len;
uint8_t const *bytes; uint8_t const *bytes;
}; };
/* Uniquely identifies a ballot in a given polling place for the /**
duration of a ballot's liveness, and is scanned by the ballot box * Uniquely identifies a ballot in a given polling place for the
to mark a ballot as cast. */ * duration of a ballot's liveness, and is scanned by the ballot box
* to mark a ballot as cast. */
struct ballot_identifier struct ballot_identifier
{ {
uint64_t len; uint64_t len;

Просмотреть файл

@ -1,7 +1,8 @@
#pragma once #pragma once
#include "messages.h" #include "messages.h"
/* Produce a character representation of a ballot tracker, suitable for /**
* presentation to a user. The pointer returned will be freshly allocated; it * Produce a character representation of a ballot tracker, suitable
* is the caller's responsibility to free it. */ * for presentation to a user. The pointer returned will be freshly
* allocated; it is the caller's responsibility to free it. */
char *display_ballot_tracker(struct ballot_tracker tracker); char *display_ballot_tracker(struct ballot_tracker tracker);

Просмотреть файл

@ -1,32 +0,0 @@
# Includes
CFLAGS += -Iinclude
# Warnings
CFLAGS += -Wall -Werror -Wextra -pedantic -pedantic-errors -Wmissing-field-initializers
# Compiler specific warnings
ifeq ($(CC),gcc)
CFLAGS += -Wenum-compare
else ifeq ($(CC),clnag)
CFLAGS += -Wgnu-empty-initializer
endif
# Debug builds by setting DEBUG environment variable
ifdef DEBUG
CFLAGS += -DDEBUG -g
# TODO gcc with nixpkgs address sanitizer doesn't work
ifeq ($(CC),clang)
CFLAGS += -fsanitize=address
endif
endif
# Create compile_commands.json by setting COMPILE_COMMANDS while building, and
# then building the compile_commands.json target
ifdef COMPILE_COMMANDS
CFLAGS += -MJ $*.o.json
endif
# Automatic dependency generation based on
# http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/#traditional
#
# The additional flags we need to pass to CC to produce the dep file
CFLAGS += -MT $@ -MMD -MP -MF $*.d

Просмотреть файл

@ -1,6 +0,0 @@
LIBELECTIONGUARD_SRC = $(shell find src -name '*.c')
LIBELECTIONGUARD_OBJ = $(patsubst %.c,%.o,$(LIBELECTIONGUARD_SRC))
$(LIBELECTIONGUARD_OBJ): CFLAGS += -Isrc
libelectionguard.a: $(LIBELECTIONGUARD_OBJ)
$(AR) rcs $@ $^

Просмотреть файл

@ -5,7 +5,8 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "crypto.h" // @todo jwaksbaum Fix name clashes with MSC
#include "../include/crypto.h"
#include "max_values.h" #include "max_values.h"
enum Crypto_status enum Crypto_status

Просмотреть файл

@ -22,10 +22,10 @@ struct Decryption_Coordinator_s
uint64_t num_tallies; uint64_t num_tallies;
uint64_t tallies[MAX_SELECTIONS]; uint64_t tallies[MAX_SELECTIONS];
// Which trustees have responded, and with which fragments // Which trustees have responded, and with which decryption_fragments
bool responded[MAX_TRUSTEES]; bool responded[MAX_TRUSTEES];
// How many fragments we have received to compensate for each trustee // How many decryption_fragments we have received to compensate for each trustee
uint32_t num_fragments[MAX_TRUSTEES]; uint32_t num_decryption_fragments[MAX_TRUSTEES];
}; };
struct Decryption_Coordinator_new_r struct Decryption_Coordinator_new_r
@ -64,8 +64,8 @@ Decryption_Coordinator_new(uint32_t num_trustees, uint32_t threshold)
void Decryption_Coordinator_free(Decryption_Coordinator c) { free(c); } void Decryption_Coordinator_free(Decryption_Coordinator c) { free(c); }
enum Decryption_Coordinator_status enum Decryption_Coordinator_status
Decryption_Coordinator_recieve_tally_share(Decryption_Coordinator c, Decryption_Coordinator_receive_share(Decryption_Coordinator c,
struct decryption_share share) struct decryption_share share)
{ {
enum Decryption_Coordinator_status status = DECRYPTION_COORDINATOR_SUCCESS; enum Decryption_Coordinator_status status = DECRYPTION_COORDINATOR_SUCCESS;
@ -131,14 +131,13 @@ Decryption_Coordinator_fill_missing_indices(Decryption_Coordinator c,
indices[i] = !c->anounced[i]; indices[i] = !c->anounced[i];
} }
static bool static bool Decryption_Coordinator_fill_requests(
Decryption_Coordinator_fill_requests(Decryption_Coordinator c, Decryption_Coordinator c, bool *request_present,
bool *request_present, struct decryption_fragments_request *requests)
struct fragments_request *requests)
{ {
bool ok = true; bool ok = true;
// The number of trustees from who've we requested the missing trustee fragments // The number of trustees from who've we requested the missing trustee decryption_fragments
uint32_t num_requested = 0; uint32_t num_requested = 0;
for (uint32_t i = 0; i < c->num_trustees && ok; i++) for (uint32_t i = 0; i < c->num_trustees && ok; i++)
@ -148,7 +147,7 @@ Decryption_Coordinator_fill_requests(Decryption_Coordinator c,
else else
{ {
// Build the message // Build the message
struct fragments_request_rep request_rep; struct decryption_fragments_request_rep request_rep;
request_rep.num_trustees = c->num_trustees; request_rep.num_trustees = c->num_trustees;
if (num_requested < c->threshold) if (num_requested < c->threshold)
@ -169,16 +168,17 @@ Decryption_Coordinator_fill_requests(Decryption_Coordinator c,
.buf = NULL, .buf = NULL,
}; };
Serialize_reserve_fragments_request(&state, &request_rep); Serialize_reserve_decryption_fragments_request(&state,
&request_rep);
Serialize_allocate(&state); Serialize_allocate(&state);
Serialize_write_fragments_request(&state, &request_rep); Serialize_write_decryption_fragments_request(&state, &request_rep);
if (state.status != SERIALIZE_STATE_WRITING) if (state.status != SERIALIZE_STATE_WRITING)
ok = false; ok = false;
else else
{ {
request_present[i] = true; request_present[i] = true;
requests[i] = (struct fragments_request){ requests[i] = (struct decryption_fragments_request){
.len = state.len, .len = state.len,
.bytes = state.buf, .bytes = state.buf,
}; };
@ -195,10 +195,10 @@ Decryption_Coordinator_fill_requests(Decryption_Coordinator c,
return ok; return ok;
} }
struct Decryption_Coordinator_all_tally_shares_received_r struct Decryption_Coordinator_all_shares_received_r
Decryption_Coordinator_all_tally_shares_received(Decryption_Coordinator c) Decryption_Coordinator_all_shares_received(Decryption_Coordinator c)
{ {
struct Decryption_Coordinator_all_tally_shares_received_r result; struct Decryption_Coordinator_all_shares_received_r result;
result.status = DECRYPTION_COORDINATOR_SUCCESS; result.status = DECRYPTION_COORDINATOR_SUCCESS;
result.num_trustees = c->num_trustees; result.num_trustees = c->num_trustees;
// It is important that the entries of request_present are set to // It is important that the entries of request_present are set to
@ -221,34 +221,34 @@ Decryption_Coordinator_all_tally_shares_received(Decryption_Coordinator c)
result.status = DECRYPTION_COORDINATOR_INSUFFICIENT_MEMORY; result.status = DECRYPTION_COORDINATOR_INSUFFICIENT_MEMORY;
} }
// Prepare to receive fragments // Prepare to receive decryption_fragments
if (result.status == DECRYPTION_COORDINATOR_SUCCESS) if (result.status == DECRYPTION_COORDINATOR_SUCCESS)
{ {
memset(c->responded, false, c->num_trustees * sizeof(bool)); memset(c->responded, false, c->num_trustees * sizeof(bool));
memset(c->num_fragments, false, c->num_trustees * sizeof(uint32_t)); memset(c->num_decryption_fragments, false,
c->num_trustees * sizeof(uint32_t));
} }
return result; return result;
} }
enum Decryption_Coordinator_status enum Decryption_Coordinator_status Decryption_Coordinator_receive_fragments(
Decryption_Coordinator_receive_tally_fragments(Decryption_Coordinator c, Decryption_Coordinator c, struct decryption_fragments decryption_fragments)
struct fragments fragments)
{ {
enum Decryption_Coordinator_status status = DECRYPTION_COORDINATOR_SUCCESS; enum Decryption_Coordinator_status status = DECRYPTION_COORDINATOR_SUCCESS;
struct fragments_rep fragments_rep; struct decryption_fragments_rep decryption_fragments_rep;
// Deserialize the input // Deserialize the input
{ {
struct serialize_state state = { struct serialize_state state = {
.status = SERIALIZE_STATE_READING, .status = SERIALIZE_STATE_READING,
.len = fragments.len, .len = decryption_fragments.len,
.offset = 0, .offset = 0,
.buf = (uint8_t *)fragments.bytes, .buf = (uint8_t *)decryption_fragments.bytes,
}; };
Serialize_read_fragments(&state, &fragments_rep); Serialize_read_decryption_fragments(&state, &decryption_fragments_rep);
if (state.status != SERIALIZE_STATE_READING) if (state.status != SERIALIZE_STATE_READING)
status = DECRYPTION_COORDINATOR_DESERIALIZE_ERROR; status = DECRYPTION_COORDINATOR_DESERIALIZE_ERROR;
@ -258,23 +258,23 @@ Decryption_Coordinator_receive_tally_fragments(Decryption_Coordinator c,
// and has not yet responded // and has not yet responded
if (status == DECRYPTION_COORDINATOR_SUCCESS) if (status == DECRYPTION_COORDINATOR_SUCCESS)
{ {
if (!(fragments_rep.trustee_index < c->num_trustees)) if (!(decryption_fragments_rep.trustee_index < c->num_trustees))
status = DECRYPTION_COORDINATOR_INVALID_TRUSTEE_INDEX; status = DECRYPTION_COORDINATOR_INVALID_TRUSTEE_INDEX;
else if (!c->anounced[fragments_rep.trustee_index]) else if (!c->anounced[decryption_fragments_rep.trustee_index])
status = DECRYPTION_COORDINATOR_INVALID_TRUSTEE_INDEX; status = DECRYPTION_COORDINATOR_INVALID_TRUSTEE_INDEX;
else if (c->responded[fragments_rep.trustee_index]) else if (c->responded[decryption_fragments_rep.trustee_index])
status = DECRYPTION_COORDINATOR_DUPLICATE_TRUSTEE_INDEX; status = DECRYPTION_COORDINATOR_DUPLICATE_TRUSTEE_INDEX;
} }
// Mark this trustee as having responded and increment the count // Mark this trustee as having responded and increment the count
// of fragments for each of the trustees for whom he is providing // of decryption_fragments for each of the trustees for whom he is providing
// a fragment // a fragment
if (status == DECRYPTION_COORDINATOR_SUCCESS) if (status == DECRYPTION_COORDINATOR_SUCCESS)
{ {
c->responded[fragments_rep.trustee_index] = true; c->responded[decryption_fragments_rep.trustee_index] = true;
for (uint32_t i = 0; i < c->num_trustees; i++) for (uint32_t i = 0; i < c->num_trustees; i++)
if (fragments_rep.requested[i]) if (decryption_fragments_rep.requested[i])
c->num_fragments[i]++; c->num_decryption_fragments[i]++;
} }
return status; return status;
@ -288,7 +288,7 @@ static bool Decryption_Coordinator_all_trustees_seen_or_compensated(
if (c->anounced[i]) if (c->anounced[i])
ok = ok && c->responded[i]; ok = ok && c->responded[i];
else else
ok = ok && (c->num_fragments[i] == c->threshold); ok = ok && (c->num_decryption_fragments[i] == c->threshold);
return ok; return ok;
} }

Просмотреть файл

@ -13,13 +13,13 @@ struct decryption_share_rep
uint64_t tallies[MAX_SELECTIONS]; uint64_t tallies[MAX_SELECTIONS];
}; };
struct fragments_request_rep struct decryption_fragments_request_rep
{ {
uint32_t num_trustees; uint32_t num_trustees;
bool requested[MAX_TRUSTEES]; bool requested[MAX_TRUSTEES];
}; };
struct fragments_rep struct decryption_fragments_rep
{ {
uint32_t trustee_index; uint32_t trustee_index;
uint32_t num_trustees; uint32_t num_trustees;

Просмотреть файл

@ -147,10 +147,10 @@ Decryption_Trustee_tally_voting_record(Decryption_Trustee d, FILE *in)
return status; return status;
} }
struct Decryption_Trustee_decrypt_tally_share_r struct Decryption_Trustee_compute_share_r
Decryption_Trustee_decrypt_tally_share(Decryption_Trustee d) Decryption_Trustee_compute_share(Decryption_Trustee d)
{ {
struct Decryption_Trustee_decrypt_tally_share_r result; struct Decryption_Trustee_compute_share_r result;
result.status = DECRYPTION_TRUSTEE_SUCCESS; result.status = DECRYPTION_TRUSTEE_SUCCESS;
{ {
@ -187,14 +187,14 @@ Decryption_Trustee_decrypt_tally_share(Decryption_Trustee d)
return result; return result;
} }
struct Decryption_Trustee_decrypt_share_fragments_r struct Decryption_Trustee_compute_fragments_r
Decryption_Trustee_decrypt_tally_share_fragments(Decryption_Trustee d, Decryption_Trustee_compute_fragments(Decryption_Trustee d,
struct fragments_request req) struct decryption_fragments_request req)
{ {
struct Decryption_Trustee_decrypt_share_fragments_r result; struct Decryption_Trustee_compute_fragments_r result;
result.status = DECRYPTION_TRUSTEE_SUCCESS; result.status = DECRYPTION_TRUSTEE_SUCCESS;
struct fragments_request_rep req_rep; struct decryption_fragments_request_rep req_rep;
// Deserialize the input // Deserialize the input
{ {
@ -205,7 +205,7 @@ Decryption_Trustee_decrypt_tally_share_fragments(Decryption_Trustee d,
.buf = (uint8_t *)req.bytes, .buf = (uint8_t *)req.bytes,
}; };
Serialize_read_fragments_request(&state, &req_rep); Serialize_read_decryption_fragments_request(&state, &req_rep);
if (state.status != SERIALIZE_STATE_READING) if (state.status != SERIALIZE_STATE_READING)
result.status = DECRYPTION_TRUSTEE_DESERIALIZE_ERROR; result.status = DECRYPTION_TRUSTEE_DESERIALIZE_ERROR;
@ -214,10 +214,10 @@ Decryption_Trustee_decrypt_tally_share_fragments(Decryption_Trustee d,
if (result.status == DECRYPTION_TRUSTEE_SUCCESS) if (result.status == DECRYPTION_TRUSTEE_SUCCESS)
{ {
// Build the message // Build the message
struct fragments_rep fragments_rep; struct decryption_fragments_rep decryption_fragments_rep;
fragments_rep.trustee_index = d->index; decryption_fragments_rep.trustee_index = d->index;
fragments_rep.num_trustees = req_rep.num_trustees; decryption_fragments_rep.num_trustees = req_rep.num_trustees;
memcpy(fragments_rep.requested, req_rep.requested, memcpy(decryption_fragments_rep.requested, req_rep.requested,
req_rep.num_trustees * sizeof(bool)); req_rep.num_trustees * sizeof(bool));
// Serialize the message // Serialize the message
@ -228,15 +228,16 @@ Decryption_Trustee_decrypt_tally_share_fragments(Decryption_Trustee d,
.buf = NULL, .buf = NULL,
}; };
Serialize_reserve_fragments(&state, &fragments_rep); Serialize_reserve_decryption_fragments(&state,
&decryption_fragments_rep);
Serialize_allocate(&state); Serialize_allocate(&state);
Serialize_write_fragments(&state, &fragments_rep); Serialize_write_decryption_fragments(&state, &decryption_fragments_rep);
if (state.status != SERIALIZE_STATE_WRITING) if (state.status != SERIALIZE_STATE_WRITING)
result.status = DECRYPTION_TRUSTEE_SERIALIZE_ERROR; result.status = DECRYPTION_TRUSTEE_SERIALIZE_ERROR;
else else
{ {
result.fragments = (struct fragments){ result.fragments = (struct decryption_fragments){
.len = state.len, .len = state.len,
.bytes = state.buf, .bytes = state.buf,
}; };

Просмотреть файл

@ -112,7 +112,7 @@ void Serialize_reserve_uint64(struct serialize_state *state,
void Serialize_write_uint64(struct serialize_state *state, uint64_t const *data) void Serialize_write_uint64(struct serialize_state *state, uint64_t const *data)
{ {
static const size_t num_bytes = sizeof(data) / sizeof(uint8_t); static const size_t num_bytes = sizeof(uint64_t) / sizeof(uint8_t);
if (state->status == SERIALIZE_STATE_WRITING) if (state->status == SERIALIZE_STATE_WRITING)
{ {

Просмотреть файл

@ -29,32 +29,35 @@ void Serialize_read_decryption_share(struct serialize_state *state,
Serialize_read_uint64(state, &data->tallies[i]); Serialize_read_uint64(state, &data->tallies[i]);
} }
void Serialize_reserve_fragments_request( void Serialize_reserve_decryption_fragments_request(
struct serialize_state *state, struct fragments_request_rep const *data) struct serialize_state *state,
struct decryption_fragments_request_rep const *data)
{ {
Serialize_reserve_uint32(state, &data->num_trustees); Serialize_reserve_uint32(state, &data->num_trustees);
for (uint32_t i = 0; i < data->num_trustees; i++) for (uint32_t i = 0; i < data->num_trustees; i++)
Serialize_reserve_bool(state, &data->requested[i]); Serialize_reserve_bool(state, &data->requested[i]);
} }
void Serialize_write_fragments_request(struct serialize_state *state, void Serialize_write_decryption_fragments_request(
struct fragments_request_rep const *data) struct serialize_state *state,
struct decryption_fragments_request_rep const *data)
{ {
Serialize_write_uint32(state, &data->num_trustees); Serialize_write_uint32(state, &data->num_trustees);
for (uint32_t i = 0; i < data->num_trustees; i++) for (uint32_t i = 0; i < data->num_trustees; i++)
Serialize_write_bool(state, &data->requested[i]); Serialize_write_bool(state, &data->requested[i]);
} }
void Serialize_read_fragments_request(struct serialize_state *state, void Serialize_read_decryption_fragments_request(
struct fragments_request_rep *data) struct serialize_state *state,
struct decryption_fragments_request_rep *data)
{ {
Serialize_read_uint32(state, &data->num_trustees); Serialize_read_uint32(state, &data->num_trustees);
for (uint32_t i = 0; i < data->num_trustees; i++) for (uint32_t i = 0; i < data->num_trustees; i++)
Serialize_read_bool(state, &data->requested[i]); Serialize_read_bool(state, &data->requested[i]);
} }
void Serialize_reserve_fragments(struct serialize_state *state, void Serialize_reserve_decryption_fragments(
struct fragments_rep const *data) struct serialize_state *state, struct decryption_fragments_rep const *data)
{ {
Serialize_reserve_uint32(state, &data->trustee_index); Serialize_reserve_uint32(state, &data->trustee_index);
Serialize_reserve_uint32(state, &data->num_trustees); Serialize_reserve_uint32(state, &data->num_trustees);
@ -62,8 +65,8 @@ void Serialize_reserve_fragments(struct serialize_state *state,
Serialize_reserve_bool(state, &data->requested[i]); Serialize_reserve_bool(state, &data->requested[i]);
} }
void Serialize_write_fragments(struct serialize_state *state, void Serialize_write_decryption_fragments(
struct fragments_rep const *data) struct serialize_state *state, struct decryption_fragments_rep const *data)
{ {
Serialize_write_uint32(state, &data->trustee_index); Serialize_write_uint32(state, &data->trustee_index);
Serialize_write_uint32(state, &data->num_trustees); Serialize_write_uint32(state, &data->num_trustees);
@ -71,8 +74,8 @@ void Serialize_write_fragments(struct serialize_state *state,
Serialize_write_bool(state, &data->requested[i]); Serialize_write_bool(state, &data->requested[i]);
} }
void Serialize_read_fragments(struct serialize_state *state, void Serialize_read_decryption_fragments(struct serialize_state *state,
struct fragments_rep *data) struct decryption_fragments_rep *data)
{ {
Serialize_read_uint32(state, &data->trustee_index); Serialize_read_uint32(state, &data->trustee_index);
Serialize_read_uint32(state, &data->num_trustees); Serialize_read_uint32(state, &data->num_trustees);

Просмотреть файл

@ -13,22 +13,25 @@ void Serialize_write_decryption_share(struct serialize_state *state,
void Serialize_read_decryption_share(struct serialize_state *state, void Serialize_read_decryption_share(struct serialize_state *state,
struct decryption_share_rep *data); struct decryption_share_rep *data);
void Serialize_reserve_fragments_request( void Serialize_reserve_decryption_fragments_request(
struct serialize_state *state, struct fragments_request_rep const *data); struct serialize_state *state,
struct decryption_fragments_request_rep const *data);
void Serialize_write_fragments_request( void Serialize_write_decryption_fragments_request(
struct serialize_state *state, struct fragments_request_rep const *data); struct serialize_state *state,
struct decryption_fragments_request_rep const *data);
void Serialize_read_fragments_request(struct serialize_state *state, void Serialize_read_decryption_fragments_request(
struct fragments_request_rep *data); struct serialize_state *state,
struct decryption_fragments_request_rep *data);
void Serialize_reserve_fragments(struct serialize_state *state, void Serialize_reserve_decryption_fragments(
struct fragments_rep const *data); struct serialize_state *state, struct decryption_fragments_rep const *data);
void Serialize_write_fragments(struct serialize_state *state, void Serialize_write_decryption_fragments(
struct fragments_rep const *data); struct serialize_state *state, struct decryption_fragments_rep const *data);
void Serialize_read_fragments(struct serialize_state *state, void Serialize_read_decryption_fragments(struct serialize_state *state,
struct fragments_rep *data); struct decryption_fragments_rep *data);
#endif /* __SERIALIZE_DECRYPTION_H__ */ #endif /* __SERIALIZE_DECRYPTION_H__ */

Просмотреть файл

@ -128,7 +128,7 @@ Voting_Coordinator_assert_registered(Voting_Coordinator coordinator,
// Check that the ballot isn't already cast or spoiled // Check that the ballot isn't already cast or spoiled
if (result == VOTING_COORDINATOR_SUCCESS) if (result == VOTING_COORDINATOR_SUCCESS)
//@ assert ballot_box->ballot_ids[i] == ballot->ballot_id; //@ assert ballot_box->ballot_ids[i] == ballot->ballot_id;
if (coordinator->cast[*i] || coordinator->cast[*i]) if (coordinator->cast[*i] || coordinator->spoiled[*i])
result = VOTING_COORDINATOR_DUPLICATE_BALLOT; result = VOTING_COORDINATOR_DUPLICATE_BALLOT;
return result; return result;
@ -161,7 +161,7 @@ Voting_Coordinator_spoil_ballot(Voting_Coordinator coordinator,
// Mark the ballot as cast // Mark the ballot as cast
if (result == VOTING_COORDINATOR_SUCCESS) if (result == VOTING_COORDINATOR_SUCCESS)
coordinator->cast[i] = true; coordinator->spoiled[i] = true;
return result; return result;
} }