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
|
||||
*.o.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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include "max_values.h"
|
||||
|
||||
#include "main_decryption.h"
|
||||
#include "main_key_ceremony.h"
|
||||
#include "main_keyceremony.h"
|
||||
#include "main_params.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
|
||||
uint32_t const NUM_TRUSTEES = 10;
|
||||
uint32_t const THRESHOLD = 8;
|
||||
// Election Parameters
|
||||
uint32_t const NUM_TRUSTEES = 5;
|
||||
uint32_t const THRESHOLD = 4;
|
||||
uint32_t const NUM_ENCRYPTERS = 3;
|
||||
uint32_t const NUM_SELECTIONS = 3;
|
||||
|
||||
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);
|
||||
|
||||
bool ok = true;
|
||||
|
@ -32,35 +39,26 @@ int main()
|
|||
if (ok)
|
||||
ok = key_ceremony(&joint_key, trustee_states);
|
||||
|
||||
// Open the voting results files
|
||||
// Open the voting results file
|
||||
FILE *voting_results = NULL;
|
||||
|
||||
if (ok)
|
||||
{
|
||||
voting_results = fmkstemps("voting_results-XXXXXX.txt", 4, "w");
|
||||
voting_results = fmkstemps("voting_results-XXXXXX", "w+x");
|
||||
if (voting_results == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Voting
|
||||
|
||||
if (ok)
|
||||
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
|
||||
FILE *tally = NULL;
|
||||
|
||||
if (ok)
|
||||
{
|
||||
tally = fmkstemps("tally-XXXXXX.txt", 4, "w");
|
||||
tally = fmkstemps("tally-XXXXXX", "wx");
|
||||
if (tally == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
@ -70,6 +68,7 @@ int main()
|
|||
ok = decryption(voting_results, tally, trustee_states);
|
||||
|
||||
// Cleanup
|
||||
|
||||
if (voting_results != NULL)
|
||||
{
|
||||
fclose(voting_results);
|
||||
|
@ -101,37 +100,34 @@ int main()
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
FILE *fmkstemps(char const *template, int suffixlen, const char *mode)
|
||||
FILE *fmkstemps(char const *template, const char *mode)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
FILE *result = NULL;
|
||||
|
||||
// Duplicate the template. It needs to be mutable for mkstemps.
|
||||
char *template_mut = strdup(template);
|
||||
if (template_mut == NULL)
|
||||
ok = false;
|
||||
|
||||
int fd = -1;
|
||||
// Create and open the temporary file
|
||||
if (ok)
|
||||
{
|
||||
fd = mkstemps(template_mut, suffixlen);
|
||||
if (fd < 0)
|
||||
template_mut = mktemp(template_mut);
|
||||
if (template_mut == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Convert the file descripter to a FILE*
|
||||
if (ok)
|
||||
{
|
||||
result = fdopen(fd, mode);
|
||||
result = fopen(template_mut, mode);
|
||||
if (result == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!ok && fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
// Free the duplicated template
|
||||
if (template_mut != NULL)
|
||||
{
|
||||
free(template_mut);
|
||||
|
|
|
@ -16,8 +16,8 @@ static bool tally_voting_records(FILE *in);
|
|||
|
||||
static bool decrypt_tally_shares(void);
|
||||
|
||||
static bool decrypt_tally_fragments(bool *requests_present,
|
||||
struct fragments_request *requests);
|
||||
static bool decrypt_tally_decryption_fragments(
|
||||
bool *requests_present, struct decryption_fragments_request *requests);
|
||||
|
||||
static Decryption_Trustee trustees[MAX_TRUSTEES];
|
||||
static Decryption_Coordinator coordinator;
|
||||
|
@ -38,15 +38,15 @@ bool decryption(FILE *in, FILE *out, struct trustee_state *trustee_states)
|
|||
if (ok)
|
||||
ok = decrypt_tally_shares();
|
||||
|
||||
struct fragments_request requests[MAX_TRUSTEES];
|
||||
struct decryption_fragments_request requests[MAX_TRUSTEES];
|
||||
bool request_present[MAX_TRUSTEES];
|
||||
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)
|
||||
{
|
||||
struct Decryption_Coordinator_all_tally_shares_received_r result =
|
||||
Decryption_Coordinator_all_tally_shares_received(coordinator);
|
||||
struct Decryption_Coordinator_all_shares_received_r result =
|
||||
Decryption_Coordinator_all_shares_received(coordinator);
|
||||
|
||||
if (result.status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
|
@ -57,7 +57,7 @@ bool decryption(FILE *in, FILE *out, struct trustee_state *trustee_states)
|
|||
}
|
||||
|
||||
if (ok)
|
||||
ok = decrypt_tally_fragments(request_present, requests);
|
||||
ok = decrypt_tally_decryption_fragments(request_present, requests);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
|
@ -156,8 +156,8 @@ bool decrypt_tally_shares(void)
|
|||
struct decryption_share share = {.bytes = NULL};
|
||||
|
||||
{
|
||||
struct Decryption_Trustee_decrypt_tally_share_r result =
|
||||
Decryption_Trustee_decrypt_tally_share(trustees[i]);
|
||||
struct Decryption_Trustee_compute_share_r result =
|
||||
Decryption_Trustee_compute_share(trustees[i]);
|
||||
|
||||
if (result.status != DECRYPTION_TRUSTEE_SUCCESS)
|
||||
ok = false;
|
||||
|
@ -168,7 +168,7 @@ bool decrypt_tally_shares(void)
|
|||
if (ok)
|
||||
{
|
||||
enum Decryption_Coordinator_status status =
|
||||
Decryption_Coordinator_recieve_tally_share(coordinator, share);
|
||||
Decryption_Coordinator_receive_share(coordinator, share);
|
||||
if (status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
@ -183,8 +183,8 @@ bool decrypt_tally_shares(void)
|
|||
return ok;
|
||||
}
|
||||
|
||||
bool decrypt_tally_fragments(bool *requests_present,
|
||||
struct fragments_request *requests)
|
||||
bool decrypt_tally_decryption_fragments(
|
||||
bool *requests_present, struct decryption_fragments_request *requests)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
|
@ -192,33 +192,33 @@ bool decrypt_tally_fragments(bool *requests_present,
|
|||
{
|
||||
if (requests_present[i])
|
||||
{
|
||||
struct fragments fragments = {.bytes = NULL};
|
||||
struct decryption_fragments decryption_fragments = {.bytes = NULL};
|
||||
|
||||
{
|
||||
struct Decryption_Trustee_decrypt_share_fragments_r result =
|
||||
Decryption_Trustee_decrypt_tally_share_fragments(
|
||||
trustees[i], requests[i]);
|
||||
struct Decryption_Trustee_compute_fragments_r result =
|
||||
Decryption_Trustee_compute_fragments(trustees[i],
|
||||
requests[i]);
|
||||
|
||||
if (result.status != DECRYPTION_TRUSTEE_SUCCESS)
|
||||
ok = false;
|
||||
else
|
||||
fragments = result.fragments;
|
||||
decryption_fragments = result.fragments;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
enum Decryption_Coordinator_status status =
|
||||
Decryption_Coordinator_receive_tally_fragments(coordinator,
|
||||
fragments);
|
||||
Decryption_Coordinator_receive_fragments(
|
||||
coordinator, decryption_fragments);
|
||||
|
||||
if (status != DECRYPTION_COORDINATOR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (fragments.bytes != NULL)
|
||||
if (decryption_fragments.bytes != NULL)
|
||||
{
|
||||
free((void *)fragments.bytes);
|
||||
fragments.bytes = NULL;
|
||||
free((void *)decryption_fragments.bytes);
|
||||
decryption_fragments.bytes = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "main_key_ceremony.h"
|
||||
#include "main_keyceremony.h"
|
||||
#include "main_params.h"
|
||||
|
||||
// Initialize
|
|
@ -1,8 +1,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "main_params.h"
|
||||
#include "main_voting.h"
|
||||
#include "voting/tracker.h"
|
||||
|
||||
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
|
||||
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"
|
||||
|
||||
enum KeySize_e
|
||||
/** Size of a key in bytes. */
|
||||
enum KEY_SIZE_e
|
||||
{
|
||||
/* Size of a key in bytes. */
|
||||
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,
|
||||
};
|
||||
|
||||
/* A public key that will be used to encrypt ballots, such that
|
||||
* any group of `k` of the original trustees can decrypt a message
|
||||
/** Maximum size of a public key in bytes. */
|
||||
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. */
|
||||
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 ***************************/
|
||||
|
||||
/* Create a new decryption coordinator */
|
||||
/**
|
||||
* Create a new decryption coordinator.
|
||||
*/
|
||||
struct Decryption_Coordinator_new_r
|
||||
Decryption_Coordinator_new(uint32_t num_trustees, uint32_t threshold);
|
||||
|
||||
|
@ -42,47 +44,54 @@ struct Decryption_Coordinator_new_r
|
|||
Decryption_Coordinator coordinator;
|
||||
};
|
||||
|
||||
/* Free a decryption coordinator. */
|
||||
/**
|
||||
* Free a decryption coordinator.
|
||||
*/
|
||||
void Decryption_Coordinator_free(Decryption_Coordinator c);
|
||||
|
||||
/********************************* ANNOUNCING **********************************/
|
||||
|
||||
/* Receive a trustee's share of a decrypted tally */
|
||||
enum Decryption_Coordinator_status
|
||||
Decryption_Coordinator_recieve_tally_share(Decryption_Coordinator c,
|
||||
struct decryption_share share);
|
||||
Decryption_Coordinator_receive_share(Decryption_Coordinator c,
|
||||
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
|
||||
each trustee who has sent a share: for each trustee index i from 0
|
||||
to num_trustees (exclusive), if request_present[i] is true, the
|
||||
caller must pass requests[i] to the appropriate trustee, and must
|
||||
free requests[i].bytes. If status is not
|
||||
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);
|
||||
/**
|
||||
* Check that at least the threshold number of trustees have sent
|
||||
* their shares. Return a list of share fragments to be provided by
|
||||
* each trustee who has sent a share: for each trustee index i from 0
|
||||
* to num_trustees (exclusive), if request_present[i] is true, the
|
||||
* caller must pass requests[i] to the appropriate trustee, and must
|
||||
* free requests[i].bytes. If status is not
|
||||
* DECRYPTION_COORDINATOR_SUCCESS, the client is not responsible for
|
||||
* freeing anything.
|
||||
*/
|
||||
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;
|
||||
uint32_t num_trustees;
|
||||
bool request_present[MAX_TRUSTEES];
|
||||
struct fragments_request requests[MAX_TRUSTEES];
|
||||
struct decryption_fragments_request requests[MAX_TRUSTEES];
|
||||
};
|
||||
|
||||
/******************************* 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
|
||||
Decryption_Coordinator_receive_tally_fragments(Decryption_Coordinator c,
|
||||
struct fragments fragments);
|
||||
Decryption_Coordinator_receive_fragments(Decryption_Coordinator c,
|
||||
struct decryption_fragments fragments);
|
||||
|
||||
// @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
|
||||
Decryption_Coordinator_all_fragments_received(Decryption_Coordinator c,
|
||||
FILE *out);
|
||||
|
|
|
@ -3,24 +3,26 @@
|
|||
|
||||
#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
|
||||
{
|
||||
uint64_t len;
|
||||
uint8_t const *bytes;
|
||||
};
|
||||
|
||||
/* A request from the coordinator to a trustee, asking it to provide
|
||||
fragments to compensate for a missing trustee. */
|
||||
struct fragments_request
|
||||
/**
|
||||
* A request from the coordinator to a trustee, asking it to provide
|
||||
* fragments to compensate for a missing trustee. */
|
||||
struct decryption_fragments_request
|
||||
{
|
||||
uint64_t len;
|
||||
uint8_t const *bytes;
|
||||
};
|
||||
|
||||
/* A response from a trustee to a coordinator providing fragments to
|
||||
compensate for a missing trustee. */
|
||||
struct fragments
|
||||
/**
|
||||
* A response from a trustee to a coordinator providing fragments to
|
||||
* compensate for a missing trustee. */
|
||||
struct decryption_fragments
|
||||
{
|
||||
uint64_t len;
|
||||
uint8_t const *bytes;
|
||||
|
|
|
@ -30,7 +30,7 @@ enum Decryption_Trustee_status
|
|||
// because the same message (ie. from a coordinator) may need to be
|
||||
// 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
|
||||
Decryption_Trustee_new(uint32_t num_trustees, uint32_t threshold,
|
||||
uint32_t num_selections, struct trustee_state state);
|
||||
|
@ -41,22 +41,22 @@ struct Decryption_Trustee_new_r
|
|||
Decryption_Trustee decryptor;
|
||||
};
|
||||
|
||||
/* Free a trustee. */
|
||||
/** Free a trustee. */
|
||||
void Decryption_Trustee_free(Decryption_Trustee d);
|
||||
|
||||
/********************************* 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
|
||||
Decryption_Trustee_tally_voting_record(Decryption_Trustee d, FILE *in);
|
||||
|
||||
/********************************* ANNOUNCING **********************************/
|
||||
|
||||
/* Decrypt this trustee's share of the tally. */
|
||||
struct Decryption_Trustee_decrypt_tally_share_r
|
||||
Decryption_Trustee_decrypt_tally_share(Decryption_Trustee d);
|
||||
/** Decrypt this trustee's share of the tally. */
|
||||
struct Decryption_Trustee_compute_share_r
|
||||
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;
|
||||
struct decryption_share share;
|
||||
|
@ -64,15 +64,15 @@ struct Decryption_Trustee_decrypt_tally_share_r
|
|||
|
||||
/******************************* COMPENSATING ********************************/
|
||||
|
||||
/* Decrypt this trustee's fragment of another trustee's share of the tally.*/
|
||||
struct Decryption_Trustee_decrypt_share_fragments_r
|
||||
Decryption_Trustee_decrypt_tally_share_fragments(Decryption_Trustee d,
|
||||
struct fragments_request req);
|
||||
/** Decrypt this trustee's fragment of another trustee's share of the tally.*/
|
||||
struct Decryption_Trustee_compute_fragments_r
|
||||
Decryption_Trustee_compute_fragments(Decryption_Trustee d,
|
||||
struct decryption_fragments_request req);
|
||||
|
||||
struct Decryption_Trustee_decrypt_share_fragments_r
|
||||
struct Decryption_Trustee_compute_fragments_r
|
||||
{
|
||||
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 "keyceremony/messages.h"
|
||||
|
||||
/**
|
||||
* Responsible for coordinating communication between the trustees
|
||||
* during the key ceremony.
|
||||
*/
|
||||
typedef struct KeyCeremony_Coordinator_s *KeyCeremony_Coordinator;
|
||||
|
||||
// @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_SERIALIZE_ERROR,
|
||||
KEYCEREMONY_COORDINATOR_DESERIALIZE_ERROR,
|
||||
} KeyCeremony_Coordinator_Status;
|
||||
};
|
||||
|
||||
/************************** INITIALIZATION & FREEING ***************************/
|
||||
|
||||
/* Create a new coordinator. */
|
||||
/** Create a new coordinator. */
|
||||
struct KeyCeremony_Coordinator_new_r
|
||||
KeyCeremony_Coordinator_new(uint32_t num_trustees, uint32_t threshold);
|
||||
|
||||
|
@ -38,7 +42,7 @@ struct KeyCeremony_Coordinator_new_r
|
|||
KeyCeremony_Coordinator coordinator;
|
||||
};
|
||||
|
||||
/* Free a coordinator. */
|
||||
/** Free a coordinator. */
|
||||
void KeyCeremony_Coordinator_free(KeyCeremony_Coordinator c);
|
||||
|
||||
/******************************* 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
|
||||
// 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
|
||||
of possession of the private key.*/
|
||||
/**
|
||||
* Receive a message indicating that a trustee has generated its
|
||||
* key-pair, which contains the trustee's public key. Checks the NIZKP
|
||||
* of possession of the private key.*/
|
||||
enum KeyCeremony_Coordinator_status
|
||||
KeyCeremony_Coordinator_receive_key_generated(
|
||||
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
|
||||
all of the public keys. */
|
||||
/**
|
||||
* Assert that exactly one key_generated_message from each trustee has
|
||||
* been received, and generate an all_keys_generated_message
|
||||
* containing all of the public keys. */
|
||||
struct KeyCeremony_Coordinator_all_keys_received_r
|
||||
KeyCeremony_Coordinator_all_keys_received(KeyCeremony_Coordinator c);
|
||||
|
||||
|
@ -77,15 +83,17 @@ struct KeyCeremony_Coordinator_all_keys_received_r
|
|||
|
||||
/****************************** 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
|
||||
KeyCeremony_Coordinator_receive_shares_generated(
|
||||
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
|
||||
containing all of the encrypted key shares. */
|
||||
/**
|
||||
* Assert that exactly one shares_generated_message from each trustee
|
||||
* has been received, and generate an all_shares_received_message
|
||||
* containing all of the encrypted key shares. */
|
||||
struct KeyCeremony_Coordinator_all_shares_received_r
|
||||
KeyCeremony_Coordinator_all_shares_received(KeyCeremony_Coordinator c);
|
||||
|
||||
|
@ -97,16 +105,18 @@ struct KeyCeremony_Coordinator_all_shares_received_r
|
|||
|
||||
/******************************** VERIFICATION *********************************/
|
||||
|
||||
/* Receive a message indicating that a trustee has verified that the
|
||||
key shares it has received are consistent with the commitments in
|
||||
the public keys of each trustee. */
|
||||
/**
|
||||
* Receive a message indicating that a trustee has verified that the
|
||||
* key shares it has received are consistent with the commitments in
|
||||
* the public keys of each trustee. */
|
||||
enum KeyCeremony_Coordinator_status
|
||||
KeyCeremony_Coordinator_receive_shares_verified(
|
||||
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
|
||||
encrypt votes in the election. */
|
||||
/**
|
||||
* Assert that exactly one shares_verified_message from each trustee
|
||||
* 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
|
||||
KeyCeremony_Coordinator_publish_joint_key(KeyCeremony_Coordinator c);
|
||||
|
||||
|
|
|
@ -3,43 +3,48 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
/* The message that is produced by a trustee after generating their
|
||||
public/private keypair, and which must be passed to the
|
||||
coordinator. */
|
||||
/**
|
||||
* The message that is produced by a trustee after generating their
|
||||
* public/private keypair, and which must be passed to the
|
||||
* coordinator. */
|
||||
struct key_generated_message
|
||||
{
|
||||
uint64_t len;
|
||||
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
|
||||
must be passed back to each trustee. */
|
||||
/**
|
||||
* The message that is produced by a coordinator after confirming that
|
||||
* is has received all of the trustees' public keys, and which must be
|
||||
* passed back to each trustee. */
|
||||
struct all_keys_received_message
|
||||
{
|
||||
uint64_t len;
|
||||
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
|
||||
{
|
||||
uint64_t len;
|
||||
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,
|
||||
and which must be passed back to each trustee. */
|
||||
/**
|
||||
* The message that is produced by a coordinator after confirming that
|
||||
* 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
|
||||
{
|
||||
uint64_t len;
|
||||
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
|
||||
{
|
||||
uint64_t len;
|
||||
|
|
|
@ -25,7 +25,7 @@ enum KeyCeremony_Trustee_status
|
|||
|
||||
/************************** INITIALIZATION & FREEING ***************************/
|
||||
|
||||
/* Create an new trustee. */
|
||||
/** Create an new trustee. */
|
||||
struct KeyCeremony_Trustee_new_r KeyCeremony_Trustee_new(uint32_t num_trustees,
|
||||
uint32_t threshold,
|
||||
uint32_t index);
|
||||
|
@ -36,13 +36,14 @@ struct KeyCeremony_Trustee_new_r
|
|||
KeyCeremony_Trustee trustee;
|
||||
};
|
||||
|
||||
/* Free a trustee. */
|
||||
/** Free a trustee. */
|
||||
void KeyCeremony_Trustee_free(KeyCeremony_Trustee t);
|
||||
|
||||
/******************************* 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
|
||||
KeyCeremony_Trustee_generate_key(KeyCeremony_Trustee t);
|
||||
|
||||
|
@ -54,11 +55,13 @@ struct KeyCeremony_Trustee_generate_key_r
|
|||
|
||||
/****************************** SHARE_GENERATION *******************************/
|
||||
|
||||
/* Verify in_message to ensure:
|
||||
- that this trustee's public key is present
|
||||
- that any NIZKPs are valid
|
||||
Then, compute and encrypt the shares of this trustee's private key for the
|
||||
other trustees. */
|
||||
/**
|
||||
* Verify in_message to ensure:
|
||||
* - that this trustee's public key is present
|
||||
* - that any NIZKPs are valid
|
||||
*
|
||||
* Then, compute and encrypt the shares of this trustee's private key
|
||||
* for the other trustees. */
|
||||
struct KeyCeremony_Trustee_generate_shares_r
|
||||
KeyCeremony_Trustee_generate_shares(
|
||||
KeyCeremony_Trustee t, struct all_keys_received_message in_message);
|
||||
|
@ -71,8 +74,9 @@ struct KeyCeremony_Trustee_generate_shares_r
|
|||
|
||||
/******************************** 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(
|
||||
KeyCeremony_Trustee t, struct all_shares_received_message in_message);
|
||||
|
||||
|
@ -84,8 +88,9 @@ struct KeyCeremony_Trustee_verify_shares_r
|
|||
|
||||
/********************************* 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
|
||||
KeyCeremony_Trustee_export_state(KeyCeremony_Trustee t);
|
||||
|
||||
|
|
|
@ -7,21 +7,23 @@
|
|||
// constant expressions, allowing us to use them as array sizes, but
|
||||
// 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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
MAX_SELECTIONS = 1000
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
#include <stddef.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 election results. This state can be serialized and stored, and
|
||||
then deserialized and used to construct a Decryption_Trustee. */
|
||||
/**
|
||||
* 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 election results. This state can be serialized and stored, and
|
||||
* then deserialized and used to construct a Decryption_Trustee. */
|
||||
struct trustee_state
|
||||
{
|
||||
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
|
||||
// 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
|
||||
|
@ -39,23 +39,24 @@ struct Voting_Coordinator_new_r
|
|||
Voting_Coordinator coordinator;
|
||||
};
|
||||
|
||||
/* Free a ballot box. */
|
||||
/** Free a ballot box. */
|
||||
void Voting_Coordinator_free(Voting_Coordinator coordinator);
|
||||
|
||||
/****************** 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
|
||||
Voting_Coordinator_register_ballot(Voting_Coordinator coordinator,
|
||||
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
|
||||
Voting_Coordinator_cast_ballot(Voting_Coordinator coordinator,
|
||||
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
|
||||
Voting_Coordinator_spoil_ballot(Voting_Coordinator coordinator,
|
||||
struct ballot_identifier ballot_id);
|
||||
|
@ -66,7 +67,7 @@ Voting_Coordinator_spoil_ballot(Voting_Coordinator coordinator,
|
|||
|
||||
// @todo jwaksbaum What format is it writing in?
|
||||
|
||||
/* Write all of the cast and spoiled ballots to out. */
|
||||
/** Write all of the cast and spoiled ballots to out. */
|
||||
enum Voting_Coordinator_status
|
||||
Voting_Coordinator_export_ballots(Voting_Coordinator coordinator, FILE *out);
|
||||
|
||||
|
|
|
@ -24,10 +24,11 @@ struct uid
|
|||
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
|
||||
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);
|
||||
|
||||
struct Voting_Encrypter_new_r
|
||||
|
@ -36,7 +37,7 @@ struct Voting_Encrypter_new_r
|
|||
Voting_Encrypter encrypter;
|
||||
};
|
||||
|
||||
/* Free a ballot marking device. */
|
||||
/** Free a ballot marking device. */
|
||||
void Voting_Encrypter_free(Voting_Encrypter encrypter);
|
||||
|
||||
/***************************** BALLOT ENCRYPTION ******************************/
|
||||
|
@ -49,9 +50,10 @@ void Voting_Encrypter_free(Voting_Encrypter encrypter);
|
|||
// responsible for adding information like time, unique ID, etc? Or
|
||||
// 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
|
||||
when done, ie. they own them. */
|
||||
/**
|
||||
* Encrypt an unencrypted ballot, producing an encrypted ballot, a
|
||||
* ballot tracker, and a ballot identifier. The caller must free both
|
||||
* when done, ie. they own them. */
|
||||
struct Voting_Encrypter_encrypt_ballot_r
|
||||
Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter,
|
||||
bool const *selections);
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
#include <stddef.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
|
||||
{
|
||||
uint64_t len;
|
||||
|
@ -20,17 +21,19 @@ struct register_ballot_message
|
|||
// with identical identifiers, even if we try to make sure that never
|
||||
// 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
|
||||
{
|
||||
uint64_t len;
|
||||
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
|
||||
to mark a ballot as cast. */
|
||||
/**
|
||||
* Uniquely identifies a ballot in a given polling place for the
|
||||
* duration of a ballot's liveness, and is scanned by the ballot box
|
||||
* to mark a ballot as cast. */
|
||||
struct ballot_identifier
|
||||
{
|
||||
uint64_t len;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
#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
|
||||
* is the caller's responsibility to free it. */
|
||||
/**
|
||||
* Produce a character representation of a ballot tracker, suitable
|
||||
* 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);
|
||||
|
|
|
@ -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 <stdint.h>
|
||||
|
||||
#include "crypto.h"
|
||||
// @todo jwaksbaum Fix name clashes with MSC
|
||||
#include "../include/crypto.h"
|
||||
#include "max_values.h"
|
||||
|
||||
enum Crypto_status
|
||||
|
|
|
@ -22,10 +22,10 @@ struct Decryption_Coordinator_s
|
|||
uint64_t num_tallies;
|
||||
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];
|
||||
// How many fragments we have received to compensate for each trustee
|
||||
uint32_t num_fragments[MAX_TRUSTEES];
|
||||
// How many decryption_fragments we have received to compensate for each trustee
|
||||
uint32_t num_decryption_fragments[MAX_TRUSTEES];
|
||||
};
|
||||
|
||||
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); }
|
||||
|
||||
enum Decryption_Coordinator_status
|
||||
Decryption_Coordinator_recieve_tally_share(Decryption_Coordinator c,
|
||||
struct decryption_share share)
|
||||
Decryption_Coordinator_receive_share(Decryption_Coordinator c,
|
||||
struct decryption_share share)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
static bool
|
||||
Decryption_Coordinator_fill_requests(Decryption_Coordinator c,
|
||||
bool *request_present,
|
||||
struct fragments_request *requests)
|
||||
static bool Decryption_Coordinator_fill_requests(
|
||||
Decryption_Coordinator c, bool *request_present,
|
||||
struct decryption_fragments_request *requests)
|
||||
{
|
||||
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;
|
||||
|
||||
for (uint32_t i = 0; i < c->num_trustees && ok; i++)
|
||||
|
@ -148,7 +147,7 @@ Decryption_Coordinator_fill_requests(Decryption_Coordinator c,
|
|||
else
|
||||
{
|
||||
// Build the message
|
||||
struct fragments_request_rep request_rep;
|
||||
struct decryption_fragments_request_rep request_rep;
|
||||
request_rep.num_trustees = c->num_trustees;
|
||||
|
||||
if (num_requested < c->threshold)
|
||||
|
@ -169,16 +168,17 @@ Decryption_Coordinator_fill_requests(Decryption_Coordinator c,
|
|||
.buf = NULL,
|
||||
};
|
||||
|
||||
Serialize_reserve_fragments_request(&state, &request_rep);
|
||||
Serialize_reserve_decryption_fragments_request(&state,
|
||||
&request_rep);
|
||||
Serialize_allocate(&state);
|
||||
Serialize_write_fragments_request(&state, &request_rep);
|
||||
Serialize_write_decryption_fragments_request(&state, &request_rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
ok = false;
|
||||
else
|
||||
{
|
||||
request_present[i] = true;
|
||||
requests[i] = (struct fragments_request){
|
||||
requests[i] = (struct decryption_fragments_request){
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
|
@ -195,10 +195,10 @@ Decryption_Coordinator_fill_requests(Decryption_Coordinator c,
|
|||
return ok;
|
||||
}
|
||||
|
||||
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 result;
|
||||
struct Decryption_Coordinator_all_shares_received_r result;
|
||||
result.status = DECRYPTION_COORDINATOR_SUCCESS;
|
||||
result.num_trustees = c->num_trustees;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Prepare to receive fragments
|
||||
// Prepare to receive decryption_fragments
|
||||
if (result.status == DECRYPTION_COORDINATOR_SUCCESS)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
enum Decryption_Coordinator_status
|
||||
Decryption_Coordinator_receive_tally_fragments(Decryption_Coordinator c,
|
||||
struct fragments fragments)
|
||||
enum Decryption_Coordinator_status Decryption_Coordinator_receive_fragments(
|
||||
Decryption_Coordinator c, struct decryption_fragments decryption_fragments)
|
||||
{
|
||||
enum Decryption_Coordinator_status status = DECRYPTION_COORDINATOR_SUCCESS;
|
||||
|
||||
struct fragments_rep fragments_rep;
|
||||
struct decryption_fragments_rep decryption_fragments_rep;
|
||||
|
||||
// Deserialize the input
|
||||
{
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_READING,
|
||||
.len = fragments.len,
|
||||
.len = decryption_fragments.len,
|
||||
.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)
|
||||
status = DECRYPTION_COORDINATOR_DESERIALIZE_ERROR;
|
||||
|
@ -258,23 +258,23 @@ Decryption_Coordinator_receive_tally_fragments(Decryption_Coordinator c,
|
|||
// and has not yet responded
|
||||
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;
|
||||
else if (!c->anounced[fragments_rep.trustee_index])
|
||||
else if (!c->anounced[decryption_fragments_rep.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;
|
||||
}
|
||||
|
||||
// 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
|
||||
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++)
|
||||
if (fragments_rep.requested[i])
|
||||
c->num_fragments[i]++;
|
||||
if (decryption_fragments_rep.requested[i])
|
||||
c->num_decryption_fragments[i]++;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -288,7 +288,7 @@ static bool Decryption_Coordinator_all_trustees_seen_or_compensated(
|
|||
if (c->anounced[i])
|
||||
ok = ok && c->responded[i];
|
||||
else
|
||||
ok = ok && (c->num_fragments[i] == c->threshold);
|
||||
ok = ok && (c->num_decryption_fragments[i] == c->threshold);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
|
|
@ -13,13 +13,13 @@ struct decryption_share_rep
|
|||
uint64_t tallies[MAX_SELECTIONS];
|
||||
};
|
||||
|
||||
struct fragments_request_rep
|
||||
struct decryption_fragments_request_rep
|
||||
{
|
||||
uint32_t num_trustees;
|
||||
bool requested[MAX_TRUSTEES];
|
||||
};
|
||||
|
||||
struct fragments_rep
|
||||
struct decryption_fragments_rep
|
||||
{
|
||||
uint32_t trustee_index;
|
||||
uint32_t num_trustees;
|
||||
|
|
|
@ -147,10 +147,10 @@ Decryption_Trustee_tally_voting_record(Decryption_Trustee d, FILE *in)
|
|||
return status;
|
||||
}
|
||||
|
||||
struct Decryption_Trustee_decrypt_tally_share_r
|
||||
Decryption_Trustee_decrypt_tally_share(Decryption_Trustee d)
|
||||
struct Decryption_Trustee_compute_share_r
|
||||
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;
|
||||
|
||||
{
|
||||
|
@ -187,14 +187,14 @@ Decryption_Trustee_decrypt_tally_share(Decryption_Trustee d)
|
|||
return result;
|
||||
}
|
||||
|
||||
struct Decryption_Trustee_decrypt_share_fragments_r
|
||||
Decryption_Trustee_decrypt_tally_share_fragments(Decryption_Trustee d,
|
||||
struct fragments_request req)
|
||||
struct Decryption_Trustee_compute_fragments_r
|
||||
Decryption_Trustee_compute_fragments(Decryption_Trustee d,
|
||||
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;
|
||||
|
||||
struct fragments_request_rep req_rep;
|
||||
struct decryption_fragments_request_rep req_rep;
|
||||
|
||||
// Deserialize the input
|
||||
{
|
||||
|
@ -205,7 +205,7 @@ Decryption_Trustee_decrypt_tally_share_fragments(Decryption_Trustee d,
|
|||
.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)
|
||||
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)
|
||||
{
|
||||
// Build the message
|
||||
struct fragments_rep fragments_rep;
|
||||
fragments_rep.trustee_index = d->index;
|
||||
fragments_rep.num_trustees = req_rep.num_trustees;
|
||||
memcpy(fragments_rep.requested, req_rep.requested,
|
||||
struct decryption_fragments_rep decryption_fragments_rep;
|
||||
decryption_fragments_rep.trustee_index = d->index;
|
||||
decryption_fragments_rep.num_trustees = req_rep.num_trustees;
|
||||
memcpy(decryption_fragments_rep.requested, req_rep.requested,
|
||||
req_rep.num_trustees * sizeof(bool));
|
||||
|
||||
// Serialize the message
|
||||
|
@ -228,15 +228,16 @@ Decryption_Trustee_decrypt_tally_share_fragments(Decryption_Trustee d,
|
|||
.buf = NULL,
|
||||
};
|
||||
|
||||
Serialize_reserve_fragments(&state, &fragments_rep);
|
||||
Serialize_reserve_decryption_fragments(&state,
|
||||
&decryption_fragments_rep);
|
||||
Serialize_allocate(&state);
|
||||
Serialize_write_fragments(&state, &fragments_rep);
|
||||
Serialize_write_decryption_fragments(&state, &decryption_fragments_rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
result.status = DECRYPTION_TRUSTEE_SERIALIZE_ERROR;
|
||||
else
|
||||
{
|
||||
result.fragments = (struct fragments){
|
||||
result.fragments = (struct decryption_fragments){
|
||||
.len = state.len,
|
||||
.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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -29,32 +29,35 @@ void Serialize_read_decryption_share(struct serialize_state *state,
|
|||
Serialize_read_uint64(state, &data->tallies[i]);
|
||||
}
|
||||
|
||||
void Serialize_reserve_fragments_request(
|
||||
struct serialize_state *state, struct fragments_request_rep const *data)
|
||||
void Serialize_reserve_decryption_fragments_request(
|
||||
struct serialize_state *state,
|
||||
struct decryption_fragments_request_rep const *data)
|
||||
{
|
||||
Serialize_reserve_uint32(state, &data->num_trustees);
|
||||
for (uint32_t i = 0; i < data->num_trustees; i++)
|
||||
Serialize_reserve_bool(state, &data->requested[i]);
|
||||
}
|
||||
|
||||
void Serialize_write_fragments_request(struct serialize_state *state,
|
||||
struct fragments_request_rep const *data)
|
||||
void Serialize_write_decryption_fragments_request(
|
||||
struct serialize_state *state,
|
||||
struct decryption_fragments_request_rep const *data)
|
||||
{
|
||||
Serialize_write_uint32(state, &data->num_trustees);
|
||||
for (uint32_t i = 0; i < data->num_trustees; i++)
|
||||
Serialize_write_bool(state, &data->requested[i]);
|
||||
}
|
||||
|
||||
void Serialize_read_fragments_request(struct serialize_state *state,
|
||||
struct fragments_request_rep *data)
|
||||
void Serialize_read_decryption_fragments_request(
|
||||
struct serialize_state *state,
|
||||
struct decryption_fragments_request_rep *data)
|
||||
{
|
||||
Serialize_read_uint32(state, &data->num_trustees);
|
||||
for (uint32_t i = 0; i < data->num_trustees; i++)
|
||||
Serialize_read_bool(state, &data->requested[i]);
|
||||
}
|
||||
|
||||
void Serialize_reserve_fragments(struct serialize_state *state,
|
||||
struct fragments_rep const *data)
|
||||
void Serialize_reserve_decryption_fragments(
|
||||
struct serialize_state *state, struct decryption_fragments_rep const *data)
|
||||
{
|
||||
Serialize_reserve_uint32(state, &data->trustee_index);
|
||||
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]);
|
||||
}
|
||||
|
||||
void Serialize_write_fragments(struct serialize_state *state,
|
||||
struct fragments_rep const *data)
|
||||
void Serialize_write_decryption_fragments(
|
||||
struct serialize_state *state, struct decryption_fragments_rep const *data)
|
||||
{
|
||||
Serialize_write_uint32(state, &data->trustee_index);
|
||||
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]);
|
||||
}
|
||||
|
||||
void Serialize_read_fragments(struct serialize_state *state,
|
||||
struct fragments_rep *data)
|
||||
void Serialize_read_decryption_fragments(struct serialize_state *state,
|
||||
struct decryption_fragments_rep *data)
|
||||
{
|
||||
Serialize_read_uint32(state, &data->trustee_index);
|
||||
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,
|
||||
struct decryption_share_rep *data);
|
||||
|
||||
void Serialize_reserve_fragments_request(
|
||||
struct serialize_state *state, struct fragments_request_rep const *data);
|
||||
void Serialize_reserve_decryption_fragments_request(
|
||||
struct serialize_state *state,
|
||||
struct decryption_fragments_request_rep const *data);
|
||||
|
||||
void Serialize_write_fragments_request(
|
||||
struct serialize_state *state, struct fragments_request_rep const *data);
|
||||
void Serialize_write_decryption_fragments_request(
|
||||
struct serialize_state *state,
|
||||
struct decryption_fragments_request_rep const *data);
|
||||
|
||||
void Serialize_read_fragments_request(struct serialize_state *state,
|
||||
struct fragments_request_rep *data);
|
||||
void Serialize_read_decryption_fragments_request(
|
||||
struct serialize_state *state,
|
||||
struct decryption_fragments_request_rep *data);
|
||||
|
||||
void Serialize_reserve_fragments(struct serialize_state *state,
|
||||
struct fragments_rep const *data);
|
||||
void Serialize_reserve_decryption_fragments(
|
||||
struct serialize_state *state, struct decryption_fragments_rep const *data);
|
||||
|
||||
void Serialize_write_fragments(struct serialize_state *state,
|
||||
struct fragments_rep const *data);
|
||||
void Serialize_write_decryption_fragments(
|
||||
struct serialize_state *state, struct decryption_fragments_rep const *data);
|
||||
|
||||
void Serialize_read_fragments(struct serialize_state *state,
|
||||
struct fragments_rep *data);
|
||||
void Serialize_read_decryption_fragments(struct serialize_state *state,
|
||||
struct decryption_fragments_rep *data);
|
||||
|
||||
#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
|
||||
if (result == VOTING_COORDINATOR_SUCCESS)
|
||||
//@ 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;
|
||||
|
||||
return result;
|
||||
|
@ -161,7 +161,7 @@ Voting_Coordinator_spoil_ballot(Voting_Coordinator coordinator,
|
|||
|
||||
// Mark the ballot as cast
|
||||
if (result == VOTING_COORDINATOR_SUCCESS)
|
||||
coordinator->cast[i] = true;
|
||||
coordinator->spoiled[i] = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче