documentation and API design
This commit is contained in:
Родитель
1f9353ebe6
Коммит
647510887e
|
@ -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
|
|
|
@ -4,3 +4,5 @@
|
||||||
main
|
main
|
||||||
*.o.json
|
*.o.json
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
html
|
||||||
|
doxygen
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "doc/sphinx-typlog-theme"]
|
||||||
|
path = doc/sphinx-typlog-theme
|
||||||
|
url = https://github.com/jbaum98/sphinx-typlog-theme
|
|
@ -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})
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
21
Makefile
21
Makefile
|
@ -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
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;
|
|
||||||
};
|
|
||||||
```
|
|
|
@ -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 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``.
|
||||||
|
|
||||||
|
.. 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;
|
||||||
|
};
|
|
@ -0,0 +1,2 @@
|
||||||
|
_static/*
|
||||||
|
!.gitkeep
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
.. include:: /../include/decryption/README.rst
|
|
@ -0,0 +1 @@
|
||||||
|
.. include:: /../examples/README.rst
|
|
@ -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
|
|
@ -0,0 +1,17 @@
|
||||||
|
.. include:: ../README.rst
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
keyceremony
|
||||||
|
voting
|
||||||
|
decryption
|
||||||
|
api/index
|
||||||
|
examples
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`search`
|
|
@ -0,0 +1 @@
|
||||||
|
.. include:: /../include/keyceremony/README.rst
|
|
@ -0,0 +1 @@
|
||||||
|
.. include:: /../include/voting/README.rst
|
|
@ -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.
|
|
|
@ -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.
|
|
|
@ -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 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 :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::
|
||||||
|
|
||||||
|
It’s easy to get confused if we aren’t 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 it’s 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 trustee’s 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
|
||||||
|
trustee’s 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.
|
|
|
@ -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 voter’s 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;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче