initial cryptography implementation
This commit is contained in:
Родитель
647510887e
Коммит
e666de2826
|
@ -6,3 +6,6 @@ main
|
|||
compile_commands.json
|
||||
html
|
||||
doxygen
|
||||
result
|
||||
build
|
||||
/src/electionguard/random_source.h
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[submodule "doc/sphinx-typlog-theme"]
|
||||
path = doc/sphinx-typlog-theme
|
||||
[submodule "docs/sphinx-typlog-theme"]
|
||||
path = docs/sphinx-typlog-theme
|
||||
url = https://github.com/jbaum98/sphinx-typlog-theme
|
||||
|
|
138
CMakeLists.txt
138
CMakeLists.txt
|
@ -1,37 +1,64 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project("ElectionGuard SDK" LANGUAGES C)
|
||||
project("ElectionGuard SDK" VERSION 0.0.1 LANGUAGES C)
|
||||
|
||||
enable_testing()
|
||||
|
||||
# Allow us to import cmake scripts from ./cmake
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
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)
|
||||
add_library(electionguard
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/crypto_reps.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/coordinator.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/num_ballots.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/message_reps.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/nouns.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/tracker.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/nouns.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/voting/encrypter.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/builtins.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/trustee_state.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/state.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/keyceremony.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/decryption.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/voting.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/crypto.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/builtins.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/trustee_state.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/voting.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/decryption.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/keyceremony.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/state.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/serialize/crypto.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/decryption/coordinator.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/decryption/message_reps.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/decryption/trustee.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/keyceremony/coordinator.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/keyceremony/message_reps.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/keyceremony/trustee.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/uint4096.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/crypto.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/random_source.h
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/random_source.c
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard/trustee_state_rep.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/max_values.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/trustee_state.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/voting/messages.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/voting/encrypter.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/voting/coordinator.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/voting/tracker.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/decryption/messages.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/decryption/coordinator.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/decryption/trustee.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/crypto.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/keyceremony/messages.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/keyceremony/coordinator.h
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/keyceremony/trustee.h
|
||||
)
|
||||
|
||||
# Compiler flags
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||
|
@ -44,13 +71,54 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
|||
target_compile_options(electionguard PRIVATE -Wenum-compare)
|
||||
endif()
|
||||
|
||||
# examples
|
||||
add_subdirectory(examples)
|
||||
# Set the public include directory depending on if the target is being exported
|
||||
# or installed
|
||||
target_include_directories(electionguard
|
||||
SYSTEM PUBLIC
|
||||
$<INSTALL_INTERFACE:include>
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/src/electionguard
|
||||
)
|
||||
|
||||
# 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})
|
||||
# Install the electionguard library in the default location, and associate
|
||||
# electionguard with the ElectionGuard export
|
||||
install(TARGETS electionguard EXPORT ElectionGuard)
|
||||
|
||||
# Install public header files
|
||||
install(
|
||||
DIRECTORY ${PROJECT_SOURCE_DIR}/include/electionguard
|
||||
TYPE INCLUDE
|
||||
FILES_MATCHING PATTERN "*.h*"
|
||||
)
|
||||
|
||||
# Generate the build-tree ElectionGuardConfig.cmake for use in other cmake
|
||||
# projects without needing to install
|
||||
export(
|
||||
EXPORT ElectionGuard
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/ElectionGuard/ElectionGuardConfig.cmake"
|
||||
)
|
||||
|
||||
# Generate the install-tree ElectionGuardConfig.cmake for use in other cmake
|
||||
# projects after this library has been installed
|
||||
install(
|
||||
EXPORT ElectionGuard
|
||||
FILE ElectionGuardConfig.cmake
|
||||
DESTINATION lib/cmake/ElectionGuard
|
||||
)
|
||||
|
||||
add_subdirectory(docs)
|
||||
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/simple_build")
|
||||
add_test(NAME build_simple
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-E env ElectionGuard_DIR=${CMAKE_CURRENT_BINARY_DIR}/ElectionGuard
|
||||
"${CMAKE_CTEST_COMMAND}"
|
||||
--build-and-test "${PROJECT_SOURCE_DIR}/examples/simple" "${CMAKE_CURRENT_BINARY_DIR}/simple_build"
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--test-command simple
|
||||
)
|
||||
|
||||
include(CheckIncludeFiles)
|
||||
check_include_files(bcrypt.h HAVE_BCRYPTGENRANDOM)
|
||||
configure_file(${PROJECT_SOURCE_DIR}/src/electionguard/random_source.h.in ${PROJECT_SOURCE_DIR}/src/electionguard/random_source.h)
|
||||
|
|
112
README.rst
112
README.rst
|
@ -1,8 +1,14 @@
|
|||
ElectionGuard SDK Mock Implementation
|
||||
ElectionGuard SDK No-Cryptography Implementation
|
||||
=====================================
|
||||
|
||||
This implementation of the ElectionGuard SDK serves to showcase the API
|
||||
provided by the SDK. For more details about that API, see the
|
||||
provided by the SDK. It focuses on specifying and fixing the API.
|
||||
Although it currently doesn't have encryption, programming against the
|
||||
header files presented in the include document should allow you to
|
||||
develop a voting system that is automatically improved with encryption
|
||||
as the develoment of the ElectionGuard SDK continues.
|
||||
|
||||
For more details about that API, see the
|
||||
:ref:`include`.
|
||||
|
||||
.. _building:
|
||||
|
@ -10,45 +16,34 @@ provided by the SDK. For more details about that API, see the
|
|||
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.
|
||||
To enable cross-platform building, we use `cmake
|
||||
<https://cmake.org/>`_. Any generator should work, but we describe
|
||||
here how build using `Visual Studio
|
||||
<https://visualstudio.microsoft.com/>`_ and using a Unix-like shell.
|
||||
|
||||
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``.
|
||||
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
|
||||
selecting ``Build > Build All`` in the menu.
|
||||
|
||||
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.
|
||||
First create a build directory and configure the build.
|
||||
|
||||
.. code:: sh
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake -S . -B build
|
||||
|
||||
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
|
||||
cmake --build build
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
@ -75,28 +70,45 @@ also execute the client directly to better examine the output it produces.
|
|||
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``.
|
||||
To build and execute an example client of the SDK, run the tests,
|
||||
for example by selecting ``Test > Run CTests for ElectionGuard SDK``.
|
||||
|
||||
The example client can also be built as a standalone project if it is
|
||||
configured with the location of the SDK, but this is not covered here.
|
||||
|
||||
|
||||
Unix-like Systems
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
From the build directory, run
|
||||
To build and run an example client of the SDK, run the tests:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
make test
|
||||
cmake --build build --target test
|
||||
|
||||
Alternatively you can build the client as a stand-alone project.
|
||||
Create a separate build directory for the client, configure the build
|
||||
to refer to the built library, and build the client.
|
||||
|
||||
.. code:: sh
|
||||
|
||||
mkdir simple_build
|
||||
ElectionGuard_DIR="$PWD/build/ElectionGuard" cmake -S examples/simple -B simple_build
|
||||
cmake --build simple_build --target simple
|
||||
|
||||
The built binary should be located at :file:`simple_build/simple`.
|
||||
|
||||
|
||||
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
|
||||
``Debug`` when configuring. From the command-line, this looks like
|
||||
|
||||
.. code:: sh
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
|
||||
|
||||
Developing
|
||||
----------
|
||||
|
@ -109,31 +121,15 @@ From the command-line, this looks like
|
|||
|
||||
.. code:: sh
|
||||
|
||||
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
|
||||
cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
|
||||
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
|
||||
|
||||
``sphinx`` and ``breathe`` packages. Then configure your build with
|
||||
the ``BUILD_DOCUMENTATION`` variable set and rebuild.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -144,6 +140,24 @@ running a local server
|
|||
|
||||
git submodule update --init --recursive
|
||||
|
||||
|
||||
.. code:: sh
|
||||
|
||||
cmake -S . -B build -DBUILD_DOCUMENTATION=ON
|
||||
cmake --build build
|
||||
|
||||
and the documentation will be built in the :file:`build/docs/html`
|
||||
directory. You can browse it locally by opening
|
||||
:file:`build/docs/html/index.html`, or by running a local server
|
||||
|
||||
.. code::sh
|
||||
|
||||
# python2
|
||||
(cd build/docs/html && python -m SimpleHTTPServer)
|
||||
|
||||
# python3
|
||||
python3 -m http.server --directory build/docs/html
|
||||
|
||||
Memory Management/Ownership: Who frees what?
|
||||
--------------------------------------------
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
find_program(SPHINX_EXECUTABLE
|
||||
NAMES sphinx-build
|
||||
DOC "Sphinx documentation generator"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(Sphinx DEFAULT_MSG SPHINX_EXECUTABLE)
|
|
@ -0,0 +1,10 @@
|
|||
let
|
||||
rev = "ed27ba064ca6f8c783";
|
||||
nixpkgs = builtins.fetchTarball {
|
||||
url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz";
|
||||
sha256 = "1lhpbgi8gcdmwwwkgdvlqdk1n4hr5fri8vracl3axzh9n9qrdrxr";
|
||||
};
|
||||
in with import nixpkgs {}; rec {
|
||||
electionguard = callPackages ./derivation.nix { };
|
||||
simple = callPackages ./examples/simple { inherit electionguard; };
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{ stdenv, nix-gitignore, cmake, doxygen, pythonPackages }:
|
||||
stdenv.mkDerivation {
|
||||
pname = "electionguard-sdk";
|
||||
version = "0.0.1";
|
||||
|
||||
nativeBuildInputs = with pythonPackages; [ cmake doxygen sphinx breathe ];
|
||||
|
||||
cmakeFlags = "-DBUILD_DOCUMENTATION=ON";
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
||||
doCheck = true;
|
||||
|
||||
src = nix-gitignore.gitignoreSource ["*.nix"] ./.;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
.. include:: /../include/decryption/README.rst
|
|
@ -1 +0,0 @@
|
|||
.. include:: /../include/keyceremony/README.rst
|
|
@ -1 +0,0 @@
|
|||
.. include:: /../include/voting/README.rst
|
|
@ -0,0 +1,77 @@
|
|||
option(BUILD_DOCUMENTATION
|
||||
"Create and install the HTML based API documentation (requires Doxygen and Shinx)" OFF)
|
||||
|
||||
IF(BUILD_DOCUMENTATION)
|
||||
find_package(Doxygen REQUIRED)
|
||||
find_package(Sphinx REQUIRED)
|
||||
|
||||
set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/include)
|
||||
set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doxygen)
|
||||
set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/xml/index.xml)
|
||||
set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
|
||||
set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
||||
|
||||
configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)
|
||||
|
||||
get_target_property(ELECTIONGUARD_PUBLIC_HEADER_DIR electionguard INTERFACE_INCLUDE_DIRECTORIES)
|
||||
file(GLOB_RECURSE ELECTIONGUARD_PUBLIC_HEADERS ${ELECTIONGUARD_PUBLIC_HEADER_DIR}/*.h)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${DOXYGEN_INDEX_FILE}
|
||||
DEPENDS ${ELECTIONGUARD_PUBLIC_HEADERS}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
|
||||
MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN}
|
||||
COMMENT "Generating doxygen XML"
|
||||
)
|
||||
|
||||
add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE})
|
||||
|
||||
set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/html)
|
||||
set(SPHINX_CACHE ${CMAKE_CURRENT_BINARY_DIR}/_doctrees)
|
||||
set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html)
|
||||
|
||||
set(ELECTIONGUARD_RST
|
||||
${PROJECT_SOURCE_DIR}/README.rst
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/README.rst
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/keyceremony/README.rst
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/voting/README.rst
|
||||
${PROJECT_SOURCE_DIR}/include/electionguard/decryption/README.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/index.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/examples.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/voting.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/keyceremony.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/simple.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/index.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/crypto.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/trustee_state.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/voting/coordinator.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/voting/encrypter.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/voting/messages.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/voting/tracker.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/decryption/coordinator.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/decryption/trustee.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/decryption/messages.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/keyceremony/coordinator.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/keyceremony/trustee.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/keyceremony/messages.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api/max_values.rst
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/decryption.rst
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${SPHINX_INDEX_FILE}
|
||||
COMMAND ${SPHINX_EXECUTABLE} -b html
|
||||
-Dbreathe_projects.ElectionGuardSDK=${DOXYGEN_OUTPUT_DIR}/xml
|
||||
-d ${SPHINX_CACHE}
|
||||
${SPHINX_SOURCE} ${SPHINX_BUILD}
|
||||
WORKING_DIRECTORY ${SPHINX_SOURCE}
|
||||
MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py
|
||||
DEPENDS ${ELECTIONGUARD_RST} ${DOXYGEN_INDEX_FILE}
|
||||
COMMENT "Generating HTML documentation"
|
||||
)
|
||||
|
||||
add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE})
|
||||
|
||||
install(DIRECTORY ${SPHINX_BUILD} TYPE DOC)
|
||||
endif()
|
|
@ -58,7 +58,7 @@ PROJECT_LOGO =
|
|||
# entered, it will be relative to the location where doxygen was started. If
|
||||
# left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = "doxygen"
|
||||
OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIR@"
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
|
||||
# directories (in 2 levels) under the output directory of each output format and
|
||||
|
@ -813,7 +813,7 @@ WARN_LOGFILE =
|
|||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = ./include
|
||||
INPUT = "@DOXYGEN_INPUT_DIR@"
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
|
@ -1,6 +1,6 @@
|
|||
.. _include:
|
||||
|
||||
.. include:: ../../include/README.rst
|
||||
.. include:: /../include/electionguard/README.rst
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
|
@ -52,8 +52,7 @@ extensions = [
|
|||
]
|
||||
|
||||
# Breathe Configuration
|
||||
breathe_projects = { "ElectionGuard SDK": "../doxygen/xml" }
|
||||
breathe_default_project = "ElectionGuard SDK"
|
||||
breathe_default_project = "ElectionGuardSDK"
|
||||
breathe_domain_by_extension = {"h" : "c", "c" : "c"}
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
|
@ -0,0 +1 @@
|
|||
.. include:: /../include/electionguard/decryption/README.rst
|
|
@ -0,0 +1 @@
|
|||
.. include:: /../include/electionguard/keyceremony/README.rst
|
|
@ -0,0 +1 @@
|
|||
.. include:: /../include/electionguard/voting/README.rst
|
|
@ -1,19 +0,0 @@
|
|||
# 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)
|
|
@ -0,0 +1,27 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project("ElectionGuard Simple Example Client" VERSION 0.0.1 LANGUAGES C)
|
||||
|
||||
enable_testing()
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS ON)
|
||||
|
||||
add_executable(simple
|
||||
${PROJECT_SOURCE_DIR}/main_params.h
|
||||
${PROJECT_SOURCE_DIR}/main_voting.h
|
||||
${PROJECT_SOURCE_DIR}/main_decryption.c
|
||||
${PROJECT_SOURCE_DIR}/main_keyceremony.c
|
||||
${PROJECT_SOURCE_DIR}/main.c
|
||||
${PROJECT_SOURCE_DIR}/main_voting.c
|
||||
${PROJECT_SOURCE_DIR}/main_keyceremony.h
|
||||
${PROJECT_SOURCE_DIR}/main_decryption.h
|
||||
)
|
||||
|
||||
find_package(ElectionGuard REQUIRED)
|
||||
target_link_libraries(simple electionguard)
|
||||
|
||||
add_test(NAME simple COMMAND simple)
|
||||
|
||||
install(TARGETS simple)
|
|
@ -0,0 +1,13 @@
|
|||
{ stdenv, nix-gitignore, cmake, electionguard }:
|
||||
stdenv.mkDerivation {
|
||||
pname = "electionguard-sdk";
|
||||
version = "0.0.1";
|
||||
|
||||
nativeBuildInputs = [ cmake electionguard ];
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
||||
doCheck = true;
|
||||
|
||||
src = nix-gitignore.gitignoreSourcePure ["*.nix" ../../.gitignore] ./.;
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include "max_values.h"
|
||||
#include <electionguard/max_values.h>
|
||||
|
||||
#include "main_decryption.h"
|
||||
#include "main_keyceremony.h"
|
||||
|
@ -104,9 +104,10 @@ FILE *fmkstemps(char const *template, const char *mode)
|
|||
{
|
||||
bool ok = true;
|
||||
|
||||
int result_fd = -1;
|
||||
FILE *result = NULL;
|
||||
|
||||
// Duplicate the template. It needs to be mutable for mkstemps.
|
||||
// Duplicate the template. It needs to be mutable for mkstemp.
|
||||
char *template_mut = strdup(template);
|
||||
if (template_mut == NULL)
|
||||
ok = false;
|
||||
|
@ -114,15 +115,15 @@ FILE *fmkstemps(char const *template, const char *mode)
|
|||
// Create and open the temporary file
|
||||
if (ok)
|
||||
{
|
||||
template_mut = mktemp(template_mut);
|
||||
if (template_mut == NULL)
|
||||
result_fd = mkstemp(template_mut);
|
||||
if (-1 == result_fd)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
// Convert the file descripter to a FILE*
|
||||
// Convert the file descriptor to a FILE*
|
||||
if (ok)
|
||||
{
|
||||
result = fopen(template_mut, mode);
|
||||
result = fdopen(result_fd, mode);
|
||||
if (result == NULL)
|
||||
ok = false;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "decryption/coordinator.h"
|
||||
#include "decryption/trustee.h"
|
||||
#include <electionguard/decryption/coordinator.h>
|
||||
#include <electionguard/decryption/trustee.h>
|
||||
|
||||
#include "main_decryption.h"
|
||||
#include "main_params.h"
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "max_values.h"
|
||||
#include "trustee_state.h"
|
||||
#include <electionguard/crypto.h>
|
||||
#include <electionguard/max_values.h>
|
||||
#include <electionguard/trustee_state.h>
|
||||
|
||||
bool decryption(FILE *in, FILE *out, struct trustee_state *trustee_states);
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef __MAIN_KEY_CEREMONY_H__
|
||||
#define __MAIN_KEY_CEREMONY_H__
|
||||
|
||||
#include "keyceremony/coordinator.h"
|
||||
#include "keyceremony/messages.h"
|
||||
#include "keyceremony/trustee.h"
|
||||
#include <electionguard/keyceremony/coordinator.h>
|
||||
#include <electionguard/keyceremony/messages.h>
|
||||
#include <electionguard/keyceremony/trustee.h>
|
||||
|
||||
/* Carry out the key ceremony phase of an election, storing the joint
|
||||
key and trustee_states in the provided pointers. */
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <electionguard/voting/tracker.h>
|
||||
|
||||
#include "main_params.h"
|
||||
#include "main_voting.h"
|
||||
#include "voting/tracker.h"
|
||||
|
||||
static bool initialize_encrypters(struct joint_public_key joint_key);
|
||||
|
||||
|
@ -151,6 +152,7 @@ bool simulate_random_votes(uint32_t encrypter_ix, uint64_t num_ballots)
|
|||
{
|
||||
char *tracker_string = display_ballot_tracker(tracker);
|
||||
int status = puts(tracker_string);
|
||||
free(tracker_string);
|
||||
if (status == EOF)
|
||||
ok = false;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef __MAIN_VOTING_H__
|
||||
#define __MAIN_VOTING_H__
|
||||
|
||||
#include "voting/coordinator.h"
|
||||
#include "voting/encrypter.h"
|
||||
#include <electionguard/voting/coordinator.h>
|
||||
#include <electionguard/voting/encrypter.h>
|
||||
|
||||
bool voting(struct joint_public_key joint_key, FILE *out);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "max_values.h"
|
||||
#include <electionguard/max_values.h>
|
||||
|
||||
/** Size of a key in bytes. */
|
||||
enum KEY_SIZE_e
|
|
@ -5,8 +5,8 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "decryption/messages.h"
|
||||
#include "max_values.h"
|
||||
#include <electionguard/decryption/messages.h>
|
||||
#include <electionguard/max_values.h>
|
||||
|
||||
// @design jwaksbaum Should we have separate entities to decrypt
|
||||
// totals and spoiled ballots? The types are different, but maybe we
|
||||
|
@ -28,6 +28,7 @@ enum Decryption_Coordinator_status
|
|||
DECRYPTION_COORDINATOR_IO_ERROR,
|
||||
DECRYPTION_COORDINATOR_SERIALIZE_ERROR,
|
||||
DECRYPTION_COORDINATOR_DESERIALIZE_ERROR,
|
||||
DECRYPTION_COORDINATOR_CONFUSED_DECRYPTION_TRUSTEE,
|
||||
};
|
||||
|
||||
/************************** INITIALIZATION & FREEING ***************************/
|
|
@ -4,8 +4,8 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "decryption/messages.h"
|
||||
#include "trustee_state.h"
|
||||
#include <electionguard/decryption/messages.h>
|
||||
#include <electionguard/trustee_state.h>
|
||||
|
||||
typedef struct Decryption_Trustee_s *Decryption_Trustee;
|
||||
|
|
@ -4,8 +4,8 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "keyceremony/messages.h"
|
||||
#include <electionguard/crypto.h>
|
||||
#include <electionguard/keyceremony/messages.h>
|
||||
|
||||
/**
|
||||
* Responsible for coordinating communication between the trustees
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "keyceremony/messages.h"
|
||||
#include "max_values.h"
|
||||
#include "trustee_state.h"
|
||||
#include <electionguard/crypto.h>
|
||||
#include <electionguard/keyceremony/messages.h>
|
||||
#include <electionguard/max_values.h>
|
||||
#include <electionguard/trustee_state.h>
|
||||
|
||||
typedef struct KeyCeremony_Trustee_s *KeyCeremony_Trustee;
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "voting/messages.h"
|
||||
#include <electionguard/voting/messages.h>
|
||||
|
||||
// @todo jwaksbaum What sort of assurances do we make about the
|
||||
// machine being shut off? How does it persist votes?
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "voting/messages.h"
|
||||
#include <electionguard/crypto.h>
|
||||
#include <electionguard/voting/messages.h>
|
||||
|
||||
typedef struct Voting_Encrypter_s *Voting_Encrypter;
|
||||
|
||||
|
@ -14,6 +14,9 @@ enum Voting_Encrypter_status
|
|||
VOTING_ENCRYPTER_INSUFFICIENT_MEMORY,
|
||||
VOTING_ENCRYPTER_SERIALIZE_ERROR,
|
||||
VOTING_ENCRYPTER_DESERIALIZE_ERROR,
|
||||
VOTING_ENCRYPTER_IO_ERROR,
|
||||
// It is a bug for the SDK to produce one of these.
|
||||
VOTING_ENCRYPTER_UNKNOWN_ERROR
|
||||
};
|
||||
|
||||
/************************** INITIALIZATION & FREEING ***************************/
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include "messages.h"
|
||||
#include <electionguard/voting/messages.h>
|
||||
|
||||
/**
|
||||
* Produce a character representation of a ballot tracker, suitable
|
89
src/crypto.c
89
src/crypto.c
|
@ -1,89 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "crypto_reps.h"
|
||||
|
||||
bool Crypto_public_key_equal(struct public_key const *key1,
|
||||
struct public_key const *key2)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (key1->threshold != key2->threshold)
|
||||
ok = false;
|
||||
|
||||
for (uint32_t i = 0; i < key1->threshold && ok; i++)
|
||||
for (uint32_t j = 0; j < KEY_SIZE && ok; j++)
|
||||
if (key1->coef_committments[i].bytes[j] !=
|
||||
key2->coef_committments[i].bytes[j])
|
||||
ok = false;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
struct Crypto_gen_keypair_r Crypto_gen_keypair(uint32_t num_coefficients)
|
||||
{
|
||||
struct Crypto_gen_keypair_r result;
|
||||
result.status = CRYPTO_SUCCESS;
|
||||
|
||||
result.private_key.threshold = num_coefficients;
|
||||
result.public_key.threshold = num_coefficients;
|
||||
|
||||
// Set all bytes to a non-zero value to help catch bugs. Before I
|
||||
// did this, I had a couple of bugs related to actually copying
|
||||
// the keys around, but because everything was zeroes nothing
|
||||
// broke.
|
||||
for (uint32_t i = 0; i < num_coefficients; i++)
|
||||
{
|
||||
for (uint32_t j = 0; j < KEY_SIZE; j++)
|
||||
{
|
||||
result.private_key.coefficients[i].bytes[j] = rand();
|
||||
result.public_key.coef_committments[i].bytes[j] = rand();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Crypto_private_key_copy(struct private_key *dst,
|
||||
struct private_key const *src)
|
||||
{
|
||||
dst->threshold = src->threshold;
|
||||
for (uint32_t i = 0; i < src->threshold; i++)
|
||||
memcpy(&dst->coefficients[i].bytes, &src->coefficients[i].bytes,
|
||||
KEY_SIZE * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void Crypto_public_key_copy(struct public_key *dst,
|
||||
struct public_key const *src)
|
||||
{
|
||||
dst->threshold = src->threshold;
|
||||
for (uint32_t i = 0; i < src->threshold; i++)
|
||||
memcpy(&dst->coef_committments[i].bytes,
|
||||
&src->coef_committments[i].bytes, KEY_SIZE * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void Crypto_encrypted_key_share_copy(struct encrypted_key_share *dst,
|
||||
struct encrypted_key_share const *src)
|
||||
{
|
||||
Crypto_private_key_copy(&dst->private_key, &src->private_key);
|
||||
Crypto_public_key_copy(&dst->recipient_public_key,
|
||||
&src->recipient_public_key);
|
||||
}
|
||||
|
||||
void Crypto_joint_public_key_copy(struct joint_public_key_rep *dst,
|
||||
struct joint_public_key_rep const *src)
|
||||
{
|
||||
dst->num_trustees = src->num_trustees;
|
||||
for (uint32_t i = 0; i < src->num_trustees; i++)
|
||||
Crypto_public_key_copy(&dst->public_keys[i], &src->public_keys[i]);
|
||||
}
|
||||
|
||||
void Crypto_generate_joint_public_key(struct joint_public_key_rep *dst,
|
||||
struct public_key const *public_keys,
|
||||
uint32_t num_keys)
|
||||
{
|
||||
dst->num_trustees = num_keys;
|
||||
for (uint32_t i = 0; i < num_keys; i++)
|
||||
Crypto_public_key_copy(&dst->public_keys[i], &public_keys[i]);
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <electionguard/crypto.h>
|
||||
|
||||
#include "random_source.h"
|
||||
#include "crypto_reps.h"
|
||||
|
||||
bool Crypto_public_key_equal(struct public_key const *key1,
|
||||
struct public_key const *key2)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (key1->threshold != key2->threshold)
|
||||
ok = false;
|
||||
|
||||
for (uint32_t i = 0; i < key1->threshold && ok; i++)
|
||||
ok = ok && uint4096_eq(&key1->coef_commitments[i],
|
||||
&key2->coef_commitments[i]);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
enum Crypto_status Crypto_RandomSource_status_convert(enum RandomSource_status status) {
|
||||
switch(status) {
|
||||
case RANDOM_SOURCE_SUCCESS: return CRYPTO_SUCCESS;
|
||||
case RANDOM_SOURCE_INSUFFICIENT_MEMORY: return CRYPTO_INSUFFICIENT_MEMORY;
|
||||
case RANDOM_SOURCE_IO_ERROR: return CRYPTO_IO_ERROR;
|
||||
// should never happen
|
||||
default: return CRYPTO_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
struct Crypto_gen_keypair_r Crypto_gen_keypair(uint32_t num_coefficients)
|
||||
{
|
||||
struct Crypto_gen_keypair_r result;
|
||||
result.status = CRYPTO_SUCCESS;
|
||||
|
||||
result.private_key.threshold = num_coefficients;
|
||||
result.public_key.threshold = num_coefficients;
|
||||
|
||||
RandomSource source;
|
||||
if(CRYPTO_SUCCESS == result.status) {
|
||||
struct RandomSource_new_r source_r = RandomSource_new();
|
||||
source = source_r.source;
|
||||
result.status = Crypto_RandomSource_status_convert(source_r.status);
|
||||
}
|
||||
|
||||
// Set all bytes to a non-zero value to help catch bugs. Before I
|
||||
// did this, I had a couple of bugs related to actually copying
|
||||
// the keys around, but because everything was zeroes nothing
|
||||
// broke.
|
||||
for (uint32_t i = 0; i < num_coefficients; i++)
|
||||
{
|
||||
if(CRYPTO_SUCCESS == result.status) {
|
||||
result.status = Crypto_RandomSource_status_convert(RandomSource_uniform_o(source, &result.private_key.coefficients[i]));
|
||||
if(CRYPTO_SUCCESS != result.status) {
|
||||
RandomSource_free(source);
|
||||
}
|
||||
}
|
||||
|
||||
if(CRYPTO_SUCCESS == result.status) {
|
||||
uint4096_powmod_o
|
||||
( &result.public_key.coef_commitments[i]
|
||||
, uint4096_generator_default
|
||||
, &result.private_key.coefficients[i]
|
||||
, Modulus4096_modulus_default
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(CRYPTO_SUCCESS == result.status) {
|
||||
RandomSource_free(source);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Crypto_private_key_copy(struct private_key *dst,
|
||||
struct private_key const *src)
|
||||
{
|
||||
dst->threshold = src->threshold;
|
||||
for (uint32_t i = 0; i < src->threshold; i++)
|
||||
uint4096_copy_o(&dst->coefficients[i], &src->coefficients[i]);
|
||||
}
|
||||
|
||||
void Crypto_public_key_copy(struct public_key *dst,
|
||||
struct public_key const *src)
|
||||
{
|
||||
dst->threshold = src->threshold;
|
||||
for (uint32_t i = 0; i < src->threshold; i++)
|
||||
uint4096_copy_o(&dst->coef_commitments[i], &src->coef_commitments[i]);
|
||||
}
|
||||
|
||||
void Crypto_encrypted_key_share_copy(struct encrypted_key_share *dst,
|
||||
struct encrypted_key_share const *src)
|
||||
{
|
||||
Crypto_private_key_copy(&dst->private_key, &src->private_key);
|
||||
Crypto_public_key_copy(&dst->recipient_public_key,
|
||||
&src->recipient_public_key);
|
||||
}
|
||||
|
||||
void Crypto_joint_public_key_copy(struct joint_public_key_rep *dst,
|
||||
struct joint_public_key_rep const *src)
|
||||
{
|
||||
dst->num_trustees = src->num_trustees;
|
||||
uint4096_copy_o(&dst->public_key, &src->public_key);
|
||||
}
|
||||
|
||||
void Crypto_generate_joint_public_key(struct joint_public_key_rep *dst,
|
||||
struct public_key const *public_keys,
|
||||
uint32_t num_keys)
|
||||
{
|
||||
dst->num_trustees = num_keys;
|
||||
uint4096_zext_o(&dst->public_key, (uint8_t[]){1}, 1);
|
||||
for (uint32_t i = 0; i < num_keys; i++)
|
||||
uint4096_multmod_o(&dst->public_key, &dst->public_key, &public_keys[i].coef_commitments[0], Modulus4096_modulus_default);
|
||||
}
|
||||
|
||||
void Crypto_encrypt(struct encryption_rep *out, RandomSource source, const struct joint_public_key_rep *key, const_uint4096 message) {
|
||||
struct uint4096_s r;
|
||||
RandomSource_uniform_o(source, &r);
|
||||
uint4096_powmod_o(&out->nonce_encoding, uint4096_generator_default, &r, Modulus4096_modulus_default);
|
||||
uint4096_powmod_o(&out->message_encoding, &key->public_key, &r, Modulus4096_modulus_default);
|
||||
uint4096_multmod_o(&out->message_encoding, &out->message_encoding, message, Modulus4096_modulus_default);
|
||||
}
|
||||
|
||||
void Crypto_encryption_homomorphic_zero(struct encryption_rep *out) {
|
||||
uint4096_zext_o(&out->nonce_encoding, (uint8_t[]){1}, 1);
|
||||
uint4096_zext_o(&out->message_encoding, (uint8_t[]){1}, 1);
|
||||
}
|
||||
|
||||
void Crypto_encryption_homomorphic_add(struct encryption_rep *out, const struct encryption_rep *a, const struct encryption_rep *b) {
|
||||
uint4096_multmod_o(&out->nonce_encoding, &a->nonce_encoding, &b->nonce_encoding, Modulus4096_modulus_default);
|
||||
uint4096_multmod_o(&out->message_encoding, &a->message_encoding, &b->message_encoding, Modulus4096_modulus_default);
|
||||
}
|
||||
|
||||
bool Crypto_encryption_fprint(FILE *out, const struct encryption_rep *rep) {
|
||||
bool ok = true;
|
||||
|
||||
if(ok) ok = fprintf(out, "(") == 1;
|
||||
if(ok) ok = uint4096_fprint(out, &rep->nonce_encoding);
|
||||
if(ok) ok = fprintf(out, ",") == 1;
|
||||
if(ok) ok = uint4096_fprint(out, &rep->message_encoding);
|
||||
if(ok) ok = fprintf(out, ")") == 1;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
struct Crypto_encrypted_ballot_new_r Crypto_encrypted_ballot_new(uint32_t num_selections, uint64_t id) {
|
||||
struct Crypto_encrypted_ballot_new_r result;
|
||||
result.result.id = id;
|
||||
result.result.num_selections = num_selections;
|
||||
result.result.selections = malloc(num_selections * sizeof(*result.result.selections));
|
||||
if(NULL == result.result.selections)
|
||||
result.status = CRYPTO_INSUFFICIENT_MEMORY;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Crypto_encrypted_ballot_free(struct encrypted_ballot_rep *ballot) {
|
||||
free(ballot->selections);
|
||||
}
|
|
@ -5,27 +5,25 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// @todo jwaksbaum Fix name clashes with MSC
|
||||
#include "../include/crypto.h"
|
||||
#include "max_values.h"
|
||||
#include <electionguard/crypto.h>
|
||||
#include <electionguard/max_values.h>
|
||||
#include "random_source.h"
|
||||
#include "uint4096.h"
|
||||
|
||||
enum Crypto_status
|
||||
{
|
||||
CRYPTO_SUCCESS,
|
||||
CRYPTO_INSUFFICIENT_MEMORY,
|
||||
};
|
||||
|
||||
/* A single secret or coefficient, ie. a 4096 bit number for now. */
|
||||
struct key
|
||||
{
|
||||
uint8_t bytes[KEY_SIZE];
|
||||
CRYPTO_IO_ERROR,
|
||||
// it is a bug for the SDK to generate one of these
|
||||
CRYPTO_UNKNOWN_ERROR
|
||||
};
|
||||
|
||||
/* A private key, including coefficients */
|
||||
struct private_key
|
||||
{
|
||||
uint32_t threshold;
|
||||
struct key coefficients[MAX_TRUSTEES];
|
||||
struct uint4096_s coefficients[MAX_TRUSTEES];
|
||||
};
|
||||
|
||||
void Crypto_private_key_copy(struct private_key *dst,
|
||||
|
@ -35,7 +33,7 @@ void Crypto_private_key_copy(struct private_key *dst,
|
|||
struct public_key
|
||||
{
|
||||
uint32_t threshold;
|
||||
struct key coef_committments[MAX_TRUSTEES];
|
||||
struct uint4096_s coef_commitments[MAX_TRUSTEES];
|
||||
};
|
||||
|
||||
/* Check if two public keys are equal. */
|
||||
|
@ -72,7 +70,7 @@ void Crypto_encrypted_key_share_copy(struct encrypted_key_share *dst,
|
|||
struct joint_public_key_rep
|
||||
{
|
||||
uint32_t num_trustees;
|
||||
struct public_key public_keys[MAX_TRUSTEES];
|
||||
struct uint4096_s public_key;
|
||||
};
|
||||
|
||||
void Crypto_joint_public_key_copy(struct joint_public_key_rep *dst,
|
||||
|
@ -84,4 +82,31 @@ void Crypto_generate_joint_public_key(struct joint_public_key_rep *dst,
|
|||
struct public_key const *public_keys,
|
||||
uint32_t num_keys);
|
||||
|
||||
struct encryption_rep
|
||||
{
|
||||
struct uint4096_s nonce_encoding;
|
||||
struct uint4096_s message_encoding;
|
||||
};
|
||||
|
||||
void Crypto_encrypt(struct encryption_rep *out, RandomSource source, const struct joint_public_key_rep *key, const_uint4096 message);
|
||||
void Crypto_encryption_homomorphic_zero(struct encryption_rep *out);
|
||||
void Crypto_encryption_homomorphic_add(struct encryption_rep *out, const struct encryption_rep *a, const struct encryption_rep *b);
|
||||
|
||||
bool Crypto_encryption_fprint(FILE *out, const struct encryption_rep *rep);
|
||||
|
||||
struct encrypted_ballot_rep
|
||||
{
|
||||
uint64_t id;
|
||||
uint32_t num_selections;
|
||||
struct encryption_rep *selections;
|
||||
};
|
||||
|
||||
struct Crypto_encrypted_ballot_new_r {
|
||||
enum Crypto_status status;
|
||||
struct encrypted_ballot_rep result;
|
||||
};
|
||||
|
||||
struct Crypto_encrypted_ballot_new_r Crypto_encrypted_ballot_new(uint32_t num_selections, uint64_t id);
|
||||
void Crypto_encrypted_ballot_free(struct encrypted_ballot_rep *ballot);
|
||||
|
||||
#endif /* __CRYPTO_REPS_H__ */
|
|
@ -3,9 +3,10 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "decryption/coordinator.h"
|
||||
#include <electionguard/decryption/coordinator.h>
|
||||
#include <electionguard/max_values.h>
|
||||
|
||||
#include "decryption/message_reps.h"
|
||||
#include "max_values.h"
|
||||
#include "serialize/decryption.h"
|
||||
|
||||
struct Decryption_Coordinator_s
|
||||
|
@ -20,7 +21,7 @@ struct Decryption_Coordinator_s
|
|||
// Record the tallies from any trustee to return
|
||||
bool tallies_initialized;
|
||||
uint64_t num_tallies;
|
||||
uint64_t tallies[MAX_SELECTIONS];
|
||||
struct encryption_rep tallies[MAX_SELECTIONS]; // \Prod_i M_i in the spec
|
||||
|
||||
// Which trustees have responded, and with which decryption_fragments
|
||||
bool responded[MAX_TRUSTEES];
|
||||
|
@ -95,19 +96,25 @@ Decryption_Coordinator_receive_share(Decryption_Coordinator c,
|
|||
status = DECRYPTION_COORDINATOR_DUPLICATE_TRUSTEE_INDEX;
|
||||
}
|
||||
|
||||
if (status == DECRYPTION_COORDINATOR_SUCCESS)
|
||||
if (status == DECRYPTION_COORDINATOR_SUCCESS) {
|
||||
c->anounced[share_rep.trustee_index] = true;
|
||||
|
||||
// If this is the first trustee we've seen, record the tallies
|
||||
|
||||
// @todo jwaksbaum We could check that everyone agrees, but for
|
||||
// this version I don't think it's worth the trouble
|
||||
if (!c->tallies_initialized)
|
||||
{
|
||||
memcpy(c->tallies, share_rep.tallies,
|
||||
share_rep.num_tallies * sizeof(uint64_t));
|
||||
c->num_tallies = share_rep.num_tallies;
|
||||
c->tallies_initialized = true;
|
||||
if(c->tallies_initialized) {
|
||||
if(share_rep.num_tallies != c->num_tallies) {
|
||||
status = DECRYPTION_COORDINATOR_CONFUSED_DECRYPTION_TRUSTEE;
|
||||
}
|
||||
for(size_t i = 0; i < share_rep.num_tallies && DECRYPTION_COORDINATOR_SUCCESS == status; i++) {
|
||||
uint4096_multmod_o(&c->tallies[i].nonce_encoding, &c->tallies[i].nonce_encoding, &share_rep.tally_share[i].nonce_encoding, Modulus4096_modulus_default);
|
||||
if(!uint4096_eq(&c->tallies[i].message_encoding, &share_rep.tally_share[i].message_encoding))
|
||||
status = DECRYPTION_COORDINATOR_CONFUSED_DECRYPTION_TRUSTEE;
|
||||
}
|
||||
} else {
|
||||
c->num_tallies = share_rep.num_tallies;
|
||||
for(size_t i = 0; i < share_rep.num_tallies; i++) {
|
||||
uint4096_copy_o(&c->tallies[i].nonce_encoding, &share_rep.tally_share[i].nonce_encoding);
|
||||
uint4096_copy_o(&c->tallies[i].message_encoding, &share_rep.tally_share[i].message_encoding);
|
||||
}
|
||||
c->tallies_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -305,9 +312,24 @@ Decryption_Coordinator_all_fragments_received(Decryption_Coordinator c,
|
|||
for (uint64_t i = 0;
|
||||
i < c->num_tallies && status == DECRYPTION_COORDINATOR_SUCCESS; i++)
|
||||
{
|
||||
int io_status = fprintf(out, "%" PRIu64 "\n", c->tallies[i]);
|
||||
if (io_status < 0)
|
||||
// TODO: the division and discrete log parts of the decryption
|
||||
const char *preamble_format = "tally %" PRIu64 ": ";
|
||||
const int expected_len = snprintf(NULL, 0, preamble_format, i);
|
||||
|
||||
if(fprintf(out, preamble_format, i) < expected_len)
|
||||
status = DECRYPTION_COORDINATOR_IO_ERROR;
|
||||
|
||||
if(DECRYPTION_COORDINATOR_SUCCESS == status) {
|
||||
if(!Crypto_encryption_fprint(out, &c->tallies[i])) {
|
||||
status = DECRYPTION_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if(DECRYPTION_COORDINATOR_SUCCESS == status) {
|
||||
if(fprintf(out, "\n") < 1) {
|
||||
status = DECRYPTION_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
|
@ -4,13 +4,14 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "max_values.h"
|
||||
#include <electionguard/max_values.h>
|
||||
#include "crypto_reps.h"
|
||||
|
||||
struct decryption_share_rep
|
||||
{
|
||||
uint32_t trustee_index;
|
||||
uint64_t num_tallies;
|
||||
uint64_t tallies[MAX_SELECTIONS];
|
||||
struct encryption_rep tally_share[MAX_SELECTIONS];
|
||||
};
|
||||
|
||||
struct decryption_fragments_request_rep
|
|
@ -2,9 +2,10 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <electionguard/decryption/trustee.h>
|
||||
|
||||
#include "crypto_reps.h"
|
||||
#include "decryption/message_reps.h"
|
||||
#include "decryption/trustee.h"
|
||||
#include "serialize/decryption.h"
|
||||
#include "serialize/trustee_state.h"
|
||||
#include "trustee_state_rep.h"
|
||||
|
@ -15,7 +16,7 @@ struct Decryption_Trustee_s
|
|||
uint32_t threshold;
|
||||
uint32_t num_selections;
|
||||
uint32_t index;
|
||||
uint64_t tallies[MAX_SELECTIONS];
|
||||
struct encryption_rep tallies[MAX_SELECTIONS];
|
||||
//@secret the private key must not be leaked from the system
|
||||
struct private_key private_key;
|
||||
};
|
||||
|
@ -63,7 +64,9 @@ Decryption_Trustee_new(uint32_t num_trustees, uint32_t threshold,
|
|||
result.decryptor->threshold = threshold;
|
||||
result.decryptor->num_selections = num_selections;
|
||||
result.decryptor->index = state_rep.index;
|
||||
memset(result.decryptor->tallies, 0, MAX_SELECTIONS * sizeof(uint64_t));
|
||||
for(size_t i = 0; i < MAX_SELECTIONS; i++) {
|
||||
Crypto_encryption_homomorphic_zero(&result.decryptor->tallies[i]);
|
||||
}
|
||||
Crypto_private_key_copy(&result.decryptor->private_key,
|
||||
&state_rep.private_key);
|
||||
}
|
||||
|
@ -75,7 +78,7 @@ void Decryption_Trustee_free(Decryption_Trustee d) { free(d); }
|
|||
|
||||
static enum Decryption_Trustee_status
|
||||
Decryption_Trustee_read_ballot(FILE *in, uint64_t *ballot_id, bool *cast,
|
||||
uint32_t num_selections, bool *selections)
|
||||
uint32_t num_selections, struct encryption_rep *selections)
|
||||
{
|
||||
enum Decryption_Trustee_status status = DECRYPTION_TRUSTEE_SUCCESS;
|
||||
|
||||
|
@ -91,22 +94,39 @@ Decryption_Trustee_read_ballot(FILE *in, uint64_t *ballot_id, bool *cast,
|
|||
for (uint32_t i = 0;
|
||||
i < num_selections && status == DECRYPTION_TRUSTEE_SUCCESS; i++)
|
||||
{
|
||||
int selection;
|
||||
int num_read = fscanf(in, "\t%d", &selection);
|
||||
if (num_read != 1)
|
||||
int num_read = fscanf(in, "\t(");
|
||||
if (0 != num_read) // can this actually happen????
|
||||
status = DECRYPTION_TRUSTEE_IO_ERROR;
|
||||
else
|
||||
selections[i] = selection;
|
||||
|
||||
if(DECRYPTION_TRUSTEE_SUCCESS == status) {
|
||||
if(!uint4096_fscan(in, &selections[i].nonce_encoding))
|
||||
status = DECRYPTION_TRUSTEE_IO_ERROR;
|
||||
}
|
||||
|
||||
if(DECRYPTION_TRUSTEE_SUCCESS == status) {
|
||||
num_read = fscanf(in, ",");
|
||||
if(0 != num_read) status = DECRYPTION_TRUSTEE_IO_ERROR;
|
||||
}
|
||||
|
||||
if(DECRYPTION_TRUSTEE_SUCCESS == status) {
|
||||
if(!uint4096_fscan(in, &selections[i].message_encoding))
|
||||
status = DECRYPTION_TRUSTEE_IO_ERROR;
|
||||
}
|
||||
|
||||
if(DECRYPTION_TRUSTEE_SUCCESS == status) {
|
||||
num_read = fscanf(in, ")");
|
||||
if(0 != num_read) status = DECRYPTION_TRUSTEE_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void Decryption_Trustee_accum_tally(Decryption_Trustee d,
|
||||
bool *selections)
|
||||
struct encryption_rep *selections)
|
||||
{
|
||||
for (size_t i = 0; i < d->num_selections; i++)
|
||||
d->tallies[i] += selections[i];
|
||||
Crypto_encryption_homomorphic_add(&d->tallies[i], &d->tallies[i], &selections[i]);
|
||||
}
|
||||
|
||||
enum Decryption_Trustee_status
|
||||
|
@ -135,7 +155,7 @@ Decryption_Trustee_tally_voting_record(Decryption_Trustee d, FILE *in)
|
|||
{
|
||||
uint64_t ballot_id;
|
||||
bool cast;
|
||||
bool selections[MAX_SELECTIONS];
|
||||
struct encryption_rep selections[MAX_SELECTIONS];
|
||||
|
||||
status = Decryption_Trustee_read_ballot(in, &ballot_id, &cast,
|
||||
d->num_selections, selections);
|
||||
|
@ -158,8 +178,10 @@ Decryption_Trustee_compute_share(Decryption_Trustee d)
|
|||
struct decryption_share_rep share_rep;
|
||||
share_rep.trustee_index = d->index;
|
||||
share_rep.num_tallies = d->num_selections;
|
||||
memcpy(share_rep.tallies, d->tallies,
|
||||
d->num_selections * sizeof(uint64_t));
|
||||
for(size_t i = 0; i < d->num_selections; i++) {
|
||||
uint4096_powmod_o(&share_rep.tally_share[i].nonce_encoding, &d->tallies[i].nonce_encoding, &d->private_key.coefficients[0], Modulus4096_modulus_default);
|
||||
uint4096_copy_o(&share_rep.tally_share[i].message_encoding, &d->tallies[i].message_encoding);
|
||||
}
|
||||
|
||||
// Serialize the message
|
||||
struct serialize_state state = {
|
|
@ -3,9 +3,10 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "keyceremony/coordinator.h"
|
||||
#include <electionguard/keyceremony/coordinator.h>
|
||||
#include <electionguard/max_values.h>
|
||||
|
||||
#include "keyceremony/message_reps.h"
|
||||
#include "max_values.h"
|
||||
#include "serialize/crypto.h"
|
||||
#include "serialize/keyceremony.h"
|
||||
|
|
@ -4,9 +4,10 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <electionguard/keyceremony/trustee.h>
|
||||
#include <electionguard/max_values.h>
|
||||
|
||||
#include "keyceremony/message_reps.h"
|
||||
#include "keyceremony/trustee.h"
|
||||
#include "max_values.h"
|
||||
#include "serialize/keyceremony.h"
|
||||
#include "serialize/trustee_state.h"
|
||||
#include "trustee_state_rep.h"
|
|
@ -0,0 +1,101 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "random_source.h"
|
||||
|
||||
struct RandomSource_s {
|
||||
#ifdef HAVE_BCRYPTGENRANDOM
|
||||
// These links will be helpful for fixing this error:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptopenalgorithmprovider
|
||||
#error Support for generating random byte sequences on Windows is not yet implemented.
|
||||
#else
|
||||
FILE *dev_random;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct RandomSource_new_r RandomSource_new(void) {
|
||||
struct RandomSource_new_r result;
|
||||
result.status = RANDOM_SOURCE_SUCCESS;
|
||||
|
||||
if(RANDOM_SOURCE_SUCCESS == result.status) {
|
||||
result.source = malloc(sizeof(*result.source));
|
||||
if(NULL == result.source) {
|
||||
result.status = RANDOM_SOURCE_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if(RANDOM_SOURCE_SUCCESS == result.status) {
|
||||
#ifdef HAVE_BCRYPTGENRANDOM
|
||||
#error Support for generating random byte sequences on Windows is not yet implemented.
|
||||
#else
|
||||
result.source->dev_random = fopen("/dev/urandom", "r");
|
||||
if(NULL == result.source->dev_random) {
|
||||
result.status = RANDOM_SOURCE_IO_ERROR;
|
||||
free(result.source);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void RandomSource_free(RandomSource source) {
|
||||
#ifdef HAVE_BCRYPTGENRANDOM
|
||||
#error Support for generating random byte sequences on Windows is not yet implemented.
|
||||
#else
|
||||
fclose(source->dev_random);
|
||||
free(source);
|
||||
#endif
|
||||
}
|
||||
|
||||
enum RandomSource_status RandomSource_uniform_o(RandomSource source, uint4096 out) {
|
||||
uint8_t raw_bytes[UINT4096_SIZE_BYTES];
|
||||
size_t item_count;
|
||||
enum RandomSource_status result = RANDOM_SOURCE_SUCCESS;
|
||||
struct uint4096_s zero;
|
||||
uint4096_zext_o(&zero, NULL, 0);
|
||||
|
||||
do {
|
||||
if(RANDOM_SOURCE_SUCCESS == result) {
|
||||
#ifdef HAVE_BCRYPTGENRANDOM
|
||||
#error Support for generating random byte sequences on Windows is not yet implemented.
|
||||
#else
|
||||
item_count = fread(raw_bytes, UINT4096_SIZE_BYTES, 1, source->dev_random);
|
||||
if(1 != item_count) {
|
||||
result = RANDOM_SOURCE_IO_ERROR;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if(RANDOM_SOURCE_SUCCESS == result) {
|
||||
uint4096_zext_o(out, raw_bytes, UINT4096_SIZE_BYTES);
|
||||
}
|
||||
} while(RANDOM_SOURCE_SUCCESS == result &&
|
||||
(uint4096_le(out, &zero) ||
|
||||
!uint4096_lt(out, uint4096_modulus_default)
|
||||
)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct RandomSource_uniform_r RandomSource_uniform(RandomSource source) {
|
||||
struct RandomSource_uniform_r result;
|
||||
result.status = RANDOM_SOURCE_SUCCESS;
|
||||
|
||||
if(RANDOM_SOURCE_SUCCESS == result.status) {
|
||||
result.result = uint4096_zext(NULL,0);
|
||||
if(NULL == result.result) {
|
||||
result.status = RANDOM_SOURCE_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if(RANDOM_SOURCE_SUCCESS == result.status) {
|
||||
result.status = RandomSource_uniform_o(source, result.result);
|
||||
if(RANDOM_SOURCE_SUCCESS != result.status) {
|
||||
uint4096_free(result.result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include "uint4096.h"
|
||||
|
||||
#cmakedefine HAVE_BCRYPTGENRANDOM
|
||||
|
||||
// You should create one of these for each thread that may run.
|
||||
typedef struct RandomSource_s *RandomSource;
|
||||
|
||||
enum RandomSource_status {
|
||||
RANDOM_SOURCE_SUCCESS,
|
||||
RANDOM_SOURCE_INSUFFICIENT_MEMORY,
|
||||
RANDOM_SOURCE_IO_ERROR
|
||||
};
|
||||
|
||||
struct RandomSource_new_r {
|
||||
enum RandomSource_status status;
|
||||
RandomSource source;
|
||||
};
|
||||
|
||||
struct RandomSource_new_r RandomSource_new(void);
|
||||
void RandomSource_free(RandomSource source);
|
||||
|
||||
struct RandomSource_uniform_r {
|
||||
enum RandomSource_status status;
|
||||
uint4096 result;
|
||||
};
|
||||
|
||||
// Uses rejection sampling to pick a number between 1 and modulus_default-1,
|
||||
// inclusive.
|
||||
struct RandomSource_uniform_r RandomSource_uniform(RandomSource source);
|
||||
enum RandomSource_status RandomSource_uniform_o(RandomSource source, uint4096 out);
|
|
@ -0,0 +1,168 @@
|
|||
#include <stdlib.h>
|
||||
#include "serialize/crypto.h"
|
||||
#include "serialize/builtins.h"
|
||||
|
||||
void Serialize_reserve_uint4096(struct serialize_state *state, const_uint4096 data)
|
||||
{
|
||||
for (uint32_t i = 0; i < UINT4096_WORD_COUNT; i++)
|
||||
Serialize_reserve_uint64(state, &data->words[i]);
|
||||
}
|
||||
|
||||
void Serialize_write_uint4096(struct serialize_state *state, const_uint4096 data)
|
||||
{
|
||||
for (uint32_t i = 0; i < UINT4096_WORD_COUNT; i++)
|
||||
Serialize_write_uint64(state, &data->words[i]);
|
||||
}
|
||||
|
||||
void Serialize_read_uint4096(struct serialize_state *state, uint4096 data)
|
||||
{
|
||||
for (uint32_t i = 0; i < UINT4096_WORD_COUNT; i++)
|
||||
Serialize_read_uint64(state, &data->words[i]);
|
||||
// TODO: check that the key is in the right range??
|
||||
}
|
||||
|
||||
void Serialize_reserve_private_key(struct serialize_state *state,
|
||||
struct private_key const *data)
|
||||
{
|
||||
Serialize_reserve_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_reserve_uint4096(state, &data->coefficients[i]);
|
||||
}
|
||||
|
||||
void Serialize_write_private_key(struct serialize_state *state,
|
||||
struct private_key const *data)
|
||||
{
|
||||
Serialize_write_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_write_uint4096(state, &data->coefficients[i]);
|
||||
}
|
||||
|
||||
void Serialize_read_private_key(struct serialize_state *state,
|
||||
struct private_key *data)
|
||||
{
|
||||
Serialize_read_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_read_uint4096(state, &data->coefficients[i]);
|
||||
}
|
||||
|
||||
void Serialize_reserve_public_key(struct serialize_state *state,
|
||||
struct public_key const *data)
|
||||
{
|
||||
Serialize_reserve_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_reserve_uint4096(state, &data->coef_commitments[i]);
|
||||
}
|
||||
|
||||
void Serialize_write_public_key(struct serialize_state *state,
|
||||
struct public_key const *data)
|
||||
{
|
||||
Serialize_write_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_write_uint4096(state, &data->coef_commitments[i]);
|
||||
}
|
||||
|
||||
void Serialize_read_public_key(struct serialize_state *state,
|
||||
struct public_key *data)
|
||||
{
|
||||
Serialize_read_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_read_uint4096(state, &data->coef_commitments[i]);
|
||||
}
|
||||
|
||||
void Serialize_reserve_encrypted_key_share(
|
||||
struct serialize_state *state, struct encrypted_key_share const *data)
|
||||
{
|
||||
Serialize_reserve_private_key(state, &data->private_key);
|
||||
Serialize_reserve_public_key(state, &data->recipient_public_key);
|
||||
}
|
||||
|
||||
void Serialize_write_encrypted_key_share(struct serialize_state *state,
|
||||
struct encrypted_key_share const *data)
|
||||
{
|
||||
Serialize_write_private_key(state, &data->private_key);
|
||||
Serialize_write_public_key(state, &data->recipient_public_key);
|
||||
}
|
||||
|
||||
void Serialize_read_encrypted_key_share(struct serialize_state *state,
|
||||
struct encrypted_key_share *data)
|
||||
{
|
||||
Serialize_read_private_key(state, &data->private_key);
|
||||
Serialize_read_public_key(state, &data->recipient_public_key);
|
||||
}
|
||||
|
||||
void Serialize_reserve_joint_public_key(struct serialize_state *state,
|
||||
struct joint_public_key_rep const *data)
|
||||
{
|
||||
Serialize_reserve_uint32(state, &data->num_trustees);
|
||||
Serialize_reserve_uint4096(state, &data->public_key);
|
||||
}
|
||||
|
||||
void Serialize_write_joint_public_key(struct serialize_state *state,
|
||||
struct joint_public_key_rep const *data)
|
||||
{
|
||||
Serialize_write_uint32(state, &data->num_trustees);
|
||||
Serialize_write_uint4096(state, &data->public_key);
|
||||
}
|
||||
|
||||
void Serialize_read_joint_public_key(struct serialize_state *state,
|
||||
struct joint_public_key_rep *data)
|
||||
{
|
||||
Serialize_read_uint32(state, &data->num_trustees);
|
||||
Serialize_read_uint4096(state, &data->public_key);
|
||||
}
|
||||
|
||||
void Serialize_reserve_encryption(struct serialize_state *state,
|
||||
struct encryption_rep const *data)
|
||||
{
|
||||
Serialize_reserve_uint4096(state, &data->nonce_encoding);
|
||||
Serialize_reserve_uint4096(state, &data->message_encoding);
|
||||
}
|
||||
|
||||
void Serialize_write_encryption(struct serialize_state *state,
|
||||
struct encryption_rep const *data)
|
||||
{
|
||||
Serialize_write_uint4096(state, &data->nonce_encoding);
|
||||
Serialize_write_uint4096(state, &data->message_encoding);
|
||||
}
|
||||
|
||||
void Serialize_read_encryption(struct serialize_state *state,
|
||||
struct encryption_rep *data)
|
||||
{
|
||||
Serialize_read_uint4096(state, &data->nonce_encoding);
|
||||
Serialize_read_uint4096(state, &data->message_encoding);
|
||||
}
|
||||
|
||||
void Serialize_reserve_encrypted_ballot(struct serialize_state *state,
|
||||
struct encrypted_ballot_rep const *data)
|
||||
{
|
||||
Serialize_reserve_uint64(state, &data->id);
|
||||
Serialize_reserve_uint32(state, &data->num_selections);
|
||||
for(uint32_t i = 0; i < data->num_selections; i++) {
|
||||
Serialize_reserve_encryption(state, &data->selections[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Serialize_write_encrypted_ballot(struct serialize_state *state,
|
||||
struct encrypted_ballot_rep const *data)
|
||||
{
|
||||
Serialize_write_uint64(state, &data->id);
|
||||
Serialize_write_uint32(state, &data->num_selections);
|
||||
for(uint32_t i = 0; i < data->num_selections; i++) {
|
||||
Serialize_write_encryption(state, &data->selections[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Serialize_read_encrypted_ballot(struct serialize_state *state,
|
||||
struct encrypted_ballot_rep *data)
|
||||
{
|
||||
Serialize_read_uint64(state, &data->id);
|
||||
Serialize_read_uint32(state, &data->num_selections);
|
||||
data->selections = malloc(data->num_selections * sizeof(*data->selections));
|
||||
if(NULL == data->selections) {
|
||||
state->status = SERIALIZE_STATE_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < data->num_selections && SERIALIZE_STATE_READING == state->status; i++) {
|
||||
Serialize_read_encryption(state, &data->selections[i]);
|
||||
}
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
#ifndef __SERIALIZE_CRYPTO_H__
|
||||
#define __SERIALIZE_CRYPTO_H__
|
||||
|
||||
#include "crypto.h"
|
||||
#include <electionguard/crypto.h>
|
||||
|
||||
#include "crypto_reps.h"
|
||||
#include "serialize/state.h"
|
||||
|
||||
void Serialize_reserve_key(struct serialize_state *state,
|
||||
struct key const *data);
|
||||
void Serialize_reserve_uint4096(struct serialize_state *state, const_uint4096 data);
|
||||
|
||||
void Serialize_write_key(struct serialize_state *state, struct key const *data);
|
||||
void Serialize_write_uint4096(struct serialize_state *state, const_uint4096 data);
|
||||
|
||||
void Serialize_read_key(struct serialize_state *state, struct key *data);
|
||||
void Serialize_read_uint4096(struct serialize_state *state, uint4096 data);
|
||||
|
||||
void Serialize_reserve_private_key(struct serialize_state *state,
|
||||
struct private_key const *data);
|
||||
|
@ -48,4 +48,22 @@ void Serialize_write_joint_public_key(struct serialize_state *state,
|
|||
void Serialize_read_joint_public_key(struct serialize_state *state,
|
||||
struct joint_public_key_rep *data);
|
||||
|
||||
void Serialize_reserve_encryption(struct serialize_state *state,
|
||||
struct encryption_rep const *data);
|
||||
|
||||
void Serialize_write_encryption(struct serialize_state *state,
|
||||
struct encryption_rep const *data);
|
||||
|
||||
void Serialize_read_encryption(struct serialize_state *state,
|
||||
struct encryption_rep *data);
|
||||
|
||||
void Serialize_reserve_encrypted_ballot(struct serialize_state *state,
|
||||
struct encrypted_ballot_rep const *data);
|
||||
|
||||
void Serialize_write_encrypted_ballot(struct serialize_state *state,
|
||||
struct encrypted_ballot_rep const *data);
|
||||
|
||||
void Serialize_read_encrypted_ballot(struct serialize_state *state,
|
||||
struct encrypted_ballot_rep *data);
|
||||
|
||||
#endif /* __CRYPTO_SERIALIZE_H__ */
|
|
@ -8,7 +8,7 @@ void Serialize_reserve_decryption_share(struct serialize_state *state,
|
|||
Serialize_reserve_uint32(state, &data->trustee_index);
|
||||
Serialize_reserve_uint64(state, &data->num_tallies);
|
||||
for (uint64_t i = 0; i < data->num_tallies; i++)
|
||||
Serialize_reserve_uint64(state, &data->tallies[i]);
|
||||
Serialize_reserve_encryption(state, &data->tally_share[i]);
|
||||
}
|
||||
|
||||
void Serialize_write_decryption_share(struct serialize_state *state,
|
||||
|
@ -17,7 +17,7 @@ void Serialize_write_decryption_share(struct serialize_state *state,
|
|||
Serialize_write_uint32(state, &data->trustee_index);
|
||||
Serialize_write_uint64(state, &data->num_tallies);
|
||||
for (uint64_t i = 0; i < data->num_tallies; i++)
|
||||
Serialize_write_uint64(state, &data->tallies[i]);
|
||||
Serialize_write_encryption(state, &data->tally_share[i]);
|
||||
}
|
||||
|
||||
void Serialize_read_decryption_share(struct serialize_state *state,
|
||||
|
@ -26,7 +26,7 @@ void Serialize_read_decryption_share(struct serialize_state *state,
|
|||
Serialize_read_uint32(state, &data->trustee_index);
|
||||
Serialize_read_uint64(state, &data->num_tallies);
|
||||
for (uint64_t i = 0; i < data->num_tallies; i++)
|
||||
Serialize_read_uint64(state, &data->tallies[i]);
|
||||
Serialize_read_encryption(state, &data->tally_share[i]);
|
||||
}
|
||||
|
||||
void Serialize_reserve_decryption_fragments_request(
|
|
@ -1,33 +1,6 @@
|
|||
#include "serialize/voting.h"
|
||||
#include "serialize/builtins.h"
|
||||
|
||||
void Serialize_reserve_register_ballot(struct serialize_state *state,
|
||||
struct register_ballot_rep const *data)
|
||||
{
|
||||
Serialize_reserve_uint64(state, &data->id);
|
||||
Serialize_reserve_uint32(state, &data->num_selections);
|
||||
for (uint32_t i = 0; i < data->num_selections; i++)
|
||||
Serialize_reserve_bool(state, &data->selections[i]);
|
||||
}
|
||||
|
||||
void Serialize_write_register_ballot(struct serialize_state *state,
|
||||
struct register_ballot_rep const *data)
|
||||
{
|
||||
Serialize_write_uint64(state, &data->id);
|
||||
Serialize_write_uint32(state, &data->num_selections);
|
||||
for (uint32_t i = 0; i < data->num_selections; i++)
|
||||
Serialize_write_bool(state, &data->selections[i]);
|
||||
}
|
||||
|
||||
void Serialize_read_register_ballot(struct serialize_state *state,
|
||||
struct register_ballot_rep *data)
|
||||
{
|
||||
Serialize_read_uint64(state, &data->id);
|
||||
Serialize_read_uint32(state, &data->num_selections);
|
||||
for (uint32_t i = 0; i < data->num_selections; i++)
|
||||
Serialize_read_bool(state, &data->selections[i]);
|
||||
}
|
||||
|
||||
void Serialize_reserve_ballot_tracker(struct serialize_state *state,
|
||||
struct ballot_tracker_rep const *data)
|
||||
{
|
|
@ -0,0 +1,410 @@
|
|||
// This file was written under the assumption that timing attacks were not
|
||||
// dangerous. If this changes in the future, I have left the comment
|
||||
// // timing
|
||||
// at points where there are conditions that may depend on sensitive data, so
|
||||
// you should begin your code audit by reviewing the code near these comments.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "uint4096.h"
|
||||
|
||||
// =============================================================================
|
||||
//
|
||||
// Type Definitions
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
typedef struct uint8192_s { UINT4096_WORD_T words[2*UINT4096_WORD_COUNT]; } *uint8192;
|
||||
typedef struct uint8192_s const *const_uint8192;
|
||||
|
||||
// Algorithms which use one of these assume that
|
||||
// reciprocal = floor(2^8192/modulus)
|
||||
// without checking it. Violating this assumption is safe (you will still get
|
||||
// the right answer) but slow (the function may not finish before the universe
|
||||
// does).
|
||||
typedef struct Modulus4096_s {
|
||||
const struct uint4096_s modulus;
|
||||
const struct uint8192_s reciprocal;
|
||||
} const *const Modulus4096;
|
||||
|
||||
// =============================================================================
|
||||
//
|
||||
// Dynamically-sized operations that work for arbitrary word-counts
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
// Returns whether the addition overflowed or not.
|
||||
bool uintnwords_add_o(size_t n, UINT4096_WORD_T *out, const UINT4096_WORD_T *a, const UINT4096_WORD_T *b) {
|
||||
// Simple ripple-carry adder.
|
||||
UINT4096_WORD_T carry = 0;
|
||||
while(n-- > 0) {
|
||||
UINT4096_WORD_T new_carry = 0;
|
||||
new_carry |= !!__builtin_add_overflow(a[n], b[n], out+n);
|
||||
new_carry |= !!__builtin_add_overflow(out[n], carry, out+n);
|
||||
carry = new_carry;
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
// Returns whether the successor operation overflowed or not.
|
||||
bool uintnwords_succ_o(size_t n, UINT4096_WORD_T *out, const UINT4096_WORD_T *a) {
|
||||
bool carry = true;
|
||||
// timing
|
||||
while(carry && n-- > 0) {
|
||||
carry = __builtin_add_overflow(a[n], 1, a+n);
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
void uintnwords_negate_o(size_t n, UINT4096_WORD_T *out, const UINT4096_WORD_T *a) {
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
out[i] = ~a[i];
|
||||
}
|
||||
uintnwords_succ_o(n, out, out);
|
||||
}
|
||||
|
||||
int uintnwords_cmp(size_t n, const UINT4096_WORD_T *a, const UINT4096_WORD_T *b) {
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
// timing
|
||||
if(a[i] < b[i]) return -1;
|
||||
if(a[i] > b[i]) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool uintnwords_le(size_t n, const UINT4096_WORD_T *a, const UINT4096_WORD_T *b) {
|
||||
return uintnwords_cmp(n, a, b) <= 0;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
//
|
||||
// Dynamically-sized operations that work on power-of-two word counts only
|
||||
//
|
||||
// Define the function f this way:
|
||||
// f(n) = 2^n * UINT4096_WORD_SIZE_BITS
|
||||
// Then we will use uintfn as the name of a dynamically-sized uint with f(n)
|
||||
// bits; e.g. if n=0 then uintfn is a representation of a uint64_t; n=6 gets
|
||||
// you a uint4096_s.
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
const int UINT4096_HALFWORD_SIZE_BYTES = UINT4096_WORD_SIZE_BYTES/2;
|
||||
const int UINT4096_HALFWORD_SIZE_BITS = UINT4096_WORD_SIZE_BITS/2;
|
||||
const UINT4096_WORD_T UINT4096_HALFWORD_BOTTOM_MASK = ((UINT4096_WORD_T)1<<(UINT4096_WORD_SIZE_BITS/2))-1;
|
||||
|
||||
// Contract: a and b are 2^n-word-long numbers, and out has enough space for a
|
||||
// 2^(n+1)-word-long number.
|
||||
void uintfn_mult_o(unsigned n, UINT4096_WORD_T *out, const UINT4096_WORD_T *a, const UINT4096_WORD_T *b) {
|
||||
if(n == 0) {
|
||||
// Textbook multiplication on half-word values, because I believe
|
||||
// saving one hardware multiplication at the cost of a conditional
|
||||
// branch (for the sign stuff) is probably a loss.
|
||||
const UINT4096_WORD_T a_upper_halfword = a[0] >> UINT4096_HALFWORD_SIZE_BITS;
|
||||
const UINT4096_WORD_T b_upper_halfword = b[0] >> UINT4096_HALFWORD_SIZE_BITS;
|
||||
const UINT4096_WORD_T a_lower_halfword = a[0] & UINT4096_HALFWORD_BOTTOM_MASK;
|
||||
const UINT4096_WORD_T b_lower_halfword = b[0] & UINT4096_HALFWORD_BOTTOM_MASK;
|
||||
out[0] = a_upper_halfword * b_upper_halfword;
|
||||
out[1] = a_lower_halfword * b_lower_halfword;
|
||||
const UINT4096_WORD_T out_middle_word_1 = a_upper_halfword * b_lower_halfword;
|
||||
const UINT4096_WORD_T out_middle_word_2 = b_upper_halfword * a_lower_halfword;
|
||||
uintnwords_add_o(2, out, out, (UINT4096_WORD_T []){out_middle_word_1 >> UINT4096_HALFWORD_SIZE_BITS, out_middle_word_1 << UINT4096_HALFWORD_SIZE_BITS});
|
||||
uintnwords_add_o(2, out, out, (UINT4096_WORD_T []){out_middle_word_2 >> UINT4096_HALFWORD_SIZE_BITS, out_middle_word_2 << UINT4096_HALFWORD_SIZE_BITS});
|
||||
}
|
||||
|
||||
else {
|
||||
// Karatsuba multiplication.
|
||||
const size_t SMALL = (size_t)1 << (n-1), MEDIUM = SMALL << 1, LARGE = MEDIUM << 1;
|
||||
UINT4096_WORD_T out_tmp[LARGE];
|
||||
uintfn_mult_o(n-1, out_tmp, a, b);
|
||||
uintfn_mult_o(n-1, out_tmp + MEDIUM, a + SMALL, b + SMALL);
|
||||
|
||||
UINT4096_WORD_T sign = -1, diff1[SMALL], diff2[SMALL], addend[MEDIUM+1], sum[LARGE];
|
||||
UINT4096_WORD_T *const middle_of_sum = sum+SMALL-1;
|
||||
|
||||
if(uintnwords_le(SMALL, a, a+SMALL)) {
|
||||
sign *= 1;
|
||||
uintnwords_negate_o(SMALL, diff1, a);
|
||||
uintnwords_add_o(SMALL, diff1, diff1, a+SMALL);
|
||||
}
|
||||
else {
|
||||
sign *= -1;
|
||||
uintnwords_negate_o(SMALL, diff1, a+SMALL);
|
||||
uintnwords_add_o(SMALL, diff1, diff1, a);
|
||||
}
|
||||
|
||||
if(uintnwords_le(SMALL, b, b+SMALL)) {
|
||||
sign *= 1;
|
||||
uintnwords_negate_o(SMALL, diff2, b);
|
||||
uintnwords_add_o(SMALL, diff2, diff2, b+SMALL);
|
||||
}
|
||||
else {
|
||||
sign *= -1;
|
||||
uintnwords_negate_o(SMALL, diff2, b+SMALL);
|
||||
uintnwords_add_o(SMALL, diff2, diff2, b);
|
||||
}
|
||||
|
||||
memset(sum, 0, sizeof(sum));
|
||||
uintfn_mult_o(n-1, sum+SMALL, diff1, diff2);
|
||||
// timing
|
||||
if(-1 == sign) uintnwords_negate_o(MEDIUM+1, middle_of_sum, middle_of_sum);
|
||||
|
||||
addend[0] = 0;
|
||||
memmove(addend+1, out_tmp, MEDIUM*UINT4096_WORD_SIZE_BYTES);
|
||||
uintnwords_add_o(MEDIUM+1, middle_of_sum, middle_of_sum, addend);
|
||||
memmove(addend+1, out_tmp+MEDIUM, MEDIUM*UINT4096_WORD_SIZE_BYTES);
|
||||
uintnwords_add_o(MEDIUM+1, middle_of_sum, middle_of_sum, addend);
|
||||
|
||||
uintnwords_add_o(LARGE, out, out_tmp, sum);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
//
|
||||
// 8192-bit operations
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
void uint8192_mod_o(uint4096 out, const_uint8192 a, Modulus4096 modulus) {
|
||||
UINT4096_WORD_T result[4*UINT4096_WORD_COUNT];
|
||||
UINT4096_WORD_T *lores = result + 2*UINT4096_WORD_COUNT;
|
||||
UINT4096_WORD_T promoted_modulus[2*UINT4096_WORD_COUNT];
|
||||
memset(promoted_modulus, 0, UINT4096_WORD_COUNT*sizeof(UINT4096_WORD_T));
|
||||
memcpy(promoted_modulus+UINT4096_WORD_COUNT, modulus->modulus.words, UINT4096_WORD_COUNT*sizeof(UINT4096_WORD_T));
|
||||
|
||||
uintfn_mult_o(UINT4096_LOG2_WORD_COUNT+1, result, a->words, modulus->reciprocal.words);
|
||||
uintfn_mult_o(UINT4096_LOG2_WORD_COUNT+1, result, result, promoted_modulus);
|
||||
uintnwords_negate_o(2*UINT4096_WORD_COUNT, lores, lores);
|
||||
uintnwords_add_o(2*UINT4096_WORD_COUNT, lores, lores, a->words);
|
||||
// If I've done my algebra correctly, this loop runs at most once. (If this
|
||||
// turns out not to be the case, and you can't restore that property by
|
||||
// fixing the algebra, you might want to revisit the decision to allocate
|
||||
// and negate the modulus inside the loop.)
|
||||
// timing
|
||||
while(uintnwords_le(2*UINT4096_WORD_COUNT, promoted_modulus, lores)) {
|
||||
UINT4096_WORD_T negated_modulus[2*UINT4096_WORD_COUNT];
|
||||
uintnwords_negate_o(2*UINT4096_WORD_COUNT, negated_modulus, promoted_modulus);
|
||||
uintnwords_add_o(2*UINT4096_WORD_COUNT, lores, lores, negated_modulus);
|
||||
}
|
||||
|
||||
memcpy(out->words, lores + UINT4096_WORD_COUNT, UINT4096_WORD_COUNT*sizeof(UINT4096_WORD_T));
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
//
|
||||
// 4096-bit operations that do not need to dynamically allocate
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
void uint4096_zext_o(uint4096 out, const uint8_t *bytes, size_t num_bytes) {
|
||||
// ub = upper bound
|
||||
const size_t ub = UINT4096_WORD_COUNT*UINT4096_WORD_SIZE_BYTES;
|
||||
if(num_bytes > ub) {
|
||||
bytes += num_bytes - ub;
|
||||
num_bytes = ub;
|
||||
}
|
||||
memset(out->words, 0, sizeof(out->words));
|
||||
for(size_t i = 0; i < num_bytes; i++)
|
||||
out->words[UINT4096_WORD_COUNT-1 - i/UINT4096_WORD_SIZE_BYTES] |= (UINT4096_WORD_T)bytes[num_bytes-1 - i] << 8 * (i%UINT4096_WORD_SIZE_BYTES);
|
||||
}
|
||||
|
||||
void uint4096_downcast_o(uint4096 out, Modulus4096 modulus) {
|
||||
memmove(out->words, modulus->modulus.words, UINT4096_WORD_COUNT*UINT4096_WORD_SIZE_BYTES);
|
||||
}
|
||||
|
||||
bool uint4096_eq(const_uint4096 a, const_uint4096 b) { return 0 == uintnwords_cmp(UINT4096_WORD_COUNT, a->words, b->words); }
|
||||
bool uint4096_le(const_uint4096 a, const_uint4096 b) { return 0 >= uintnwords_cmp(UINT4096_WORD_COUNT, a->words, b->words); }
|
||||
bool uint4096_lt(const_uint4096 a, const_uint4096 b) { return 0 > uintnwords_cmp(UINT4096_WORD_COUNT, a->words, b->words); }
|
||||
bool uint4096_ge(const_uint4096 a, const_uint4096 b) { return 0 <= uintnwords_cmp(UINT4096_WORD_COUNT, a->words, b->words); }
|
||||
bool uint4096_gt(const_uint4096 a, const_uint4096 b) { return 0 < uintnwords_cmp(UINT4096_WORD_COUNT, a->words, b->words); }
|
||||
|
||||
void uint4096_multmod_o(uint4096 out, const_uint4096 a, const_uint4096 b, Modulus4096 modulus) {
|
||||
struct uint8192_s product;
|
||||
uintfn_mult_o(UINT4096_LOG2_WORD_COUNT, product.words, a->words, b->words);
|
||||
uint8192_mod_o(out, &product, modulus);
|
||||
}
|
||||
|
||||
void uint4096_powmod_o(uint4096 out, const_uint4096 base, const_uint4096 exponent, Modulus4096 modulus) {
|
||||
// Scan from the left to find the highest set bit.
|
||||
int max_bit;
|
||||
for(max_bit = 0; max_bit < UINT4096_WORD_COUNT && exponent->words[max_bit] == 0; max_bit++) {}
|
||||
UINT4096_WORD_T word = max_bit < UINT4096_WORD_COUNT ? exponent->words[max_bit] : 0;
|
||||
max_bit = (UINT4096_WORD_COUNT-1 - max_bit) * UINT4096_WORD_SIZE_BITS; // change from most-significant word index to least-significant bit index
|
||||
while(word) { word >>= 1; max_bit++; }
|
||||
|
||||
struct uint4096_s out_tmp;
|
||||
struct uint4096_s base_tmp;
|
||||
uint4096_zext_o(&out_tmp, (uint8_t[]){1}, 1);
|
||||
memcpy(&base_tmp, base, sizeof(struct uint4096_s));
|
||||
|
||||
// Now do some repeated squaring.
|
||||
// timing
|
||||
for(int i = 0; i < max_bit; i++) {
|
||||
if(exponent->words[UINT4096_WORD_COUNT-1 - i/UINT4096_WORD_SIZE_BITS] & (UINT4096_WORD_T)1<<i%UINT4096_WORD_SIZE_BITS)
|
||||
uint4096_multmod_o(&out_tmp, &out_tmp, &base_tmp, modulus);
|
||||
uint4096_multmod_o(&base_tmp, &base_tmp, &base_tmp, modulus);
|
||||
}
|
||||
|
||||
memcpy(out, &out_tmp, sizeof(struct uint4096_s));
|
||||
}
|
||||
|
||||
uint64_t uint4096_logmod(const_uint4096 base, const_uint4096 a, Modulus4096 modulus) {
|
||||
uint64_t exponent = 0;
|
||||
struct uint4096_s powmod;
|
||||
uint4096_zext_o(&powmod, (uint8_t[]){1}, 1);
|
||||
while(!uint4096_eq(&powmod, a)) {
|
||||
exponent++;
|
||||
uint4096_multmod_o(&powmod, &powmod, base, modulus);
|
||||
}
|
||||
return exponent;
|
||||
}
|
||||
|
||||
void uint4096_copy_o(uint4096 out, const_uint4096 src) {
|
||||
memmove(out, src, sizeof(*src));
|
||||
}
|
||||
|
||||
// Currently just a wrapper around free; exists for abstraction boundary's sake.
|
||||
void uint4096_free(uint4096 a) { free(a); }
|
||||
|
||||
bool uint4096_fprint(FILE *out, const_uint4096 a) {
|
||||
if(2 != fprintf(out, "0x")) return false;
|
||||
for(size_t i = 0; i < UINT4096_WORD_COUNT; i++) {
|
||||
if(2*UINT4096_WORD_SIZE_BYTES != fprintf(out, PRIxUINT4096_WORD_T, a->words[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uint4096_fscan(FILE *in, uint4096 out) {
|
||||
int num_read = fscanf(in, "0x");
|
||||
if(0 != num_read) return false;
|
||||
for(size_t i = 0; i < UINT4096_WORD_COUNT; i++) {
|
||||
num_read = fscanf(in, PRIxUINT4096_WORD_T, &out->words[i]);
|
||||
if(1 != num_read) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
//
|
||||
// Dynamically-allocating wrappers around the core 4096-bit operations
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
uint4096 uint4096_zext(const uint8_t *bytes, size_t num_bytes) {
|
||||
uint4096 out = malloc(sizeof(struct uint4096_s));
|
||||
if(out != NULL) uint4096_zext_o(out, bytes, num_bytes);
|
||||
return out;
|
||||
}
|
||||
|
||||
uint4096 uint4096_downcast(Modulus4096 modulus) {
|
||||
uint4096 out = malloc(sizeof(struct uint4096_s));
|
||||
if(out != NULL) uint4096_downcast_o(out, modulus);
|
||||
return out;
|
||||
}
|
||||
|
||||
uint4096 uint4096_multmod(const_uint4096 a, const_uint4096 b, Modulus4096 modulus) {
|
||||
uint4096 out = malloc(sizeof(struct uint4096_s));
|
||||
if(out != NULL) uint4096_multmod_o(out, a, b, modulus);
|
||||
return out;
|
||||
}
|
||||
|
||||
uint4096 uint4096_powmod(const_uint4096 base, const_uint4096 exponent, Modulus4096 modulus) {
|
||||
uint4096 out = malloc(sizeof(struct uint4096_s));
|
||||
if(out != NULL) uint4096_powmod_o(out, base, exponent, modulus);
|
||||
return out;
|
||||
}
|
||||
|
||||
uint4096 uint4096_copy(const_uint4096 src) {
|
||||
uint4096 out = malloc(sizeof(struct uint4096_s));
|
||||
if(out != NULL) uint4096_copy_o(out, src);
|
||||
return out;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
//
|
||||
// Static data
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
struct Modulus4096_s p = {
|
||||
.modulus = {
|
||||
.words = {
|
||||
0xFFFFFFFFFFFFFFFF, 0xC90FDAA22168C234, 0xC4C6628B80DC1CD1, 0x29024E088A67CC74,
|
||||
0x020BBEA63B139B22, 0x514A08798E3404DD, 0xEF9519B3CD3A431B, 0x302B0A6DF25F1437,
|
||||
0x4FE1356D6D51C245, 0xE485B576625E7EC6, 0xF44C42E9A637ED6B, 0x0BFF5CB6F406B7ED,
|
||||
0xEE386BFB5A899FA5, 0xAE9F24117C4B1FE6, 0x49286651ECE45B3D, 0xC2007CB8A163BF05,
|
||||
0x98DA48361C55D39A, 0x69163FA8FD24CF5F, 0x83655D23DCA3AD96, 0x1C62F356208552BB,
|
||||
0x9ED529077096966D, 0x670C354E4ABC9804, 0xF1746C08CA18217C, 0x32905E462E36CE3B,
|
||||
0xE39E772C180E8603, 0x9B2783A2EC07A28F, 0xB5C55DF06F4C52C9, 0xDE2BCBF695581718,
|
||||
0x3995497CEA956AE5, 0x15D2261898FA0510, 0x15728E5A8AAAC42D, 0xAD33170D04507A33,
|
||||
0xA85521ABDF1CBA64, 0xECFB850458DBEF0A, 0x8AEA71575D060C7D, 0xB3970F85A6E1E4C7,
|
||||
0xABF5AE8CDB0933D7, 0x1E8C94E04A25619D, 0xCEE3D2261AD2EE6B, 0xF12FFA06D98A0864,
|
||||
0xD87602733EC86A64, 0x521F2B18177B200C, 0xBBE117577A615D6C, 0x770988C0BAD946E2,
|
||||
0x08E24FA074E5AB31, 0x43DB5BFCE0FD108E, 0x4B82D120A9210801, 0x1A723C12A787E6D7,
|
||||
0x88719A10BDBA5B26, 0x99C327186AF4E23C, 0x1A946834B6150BDA, 0x2583E9CA2AD44CE8,
|
||||
0xDBBBC2DB04DE8EF9, 0x2E8EFC141FBECAA6, 0x287C59474E6BC05D, 0x99B2964FA090C3A2,
|
||||
0x233BA186515BE7ED, 0x1F612970CEE2D7AF, 0xB81BDD762170481C, 0xD0069127D5B05AA9,
|
||||
0x93B4EA988D8FDDC1, 0x86FFB7DC90A6C08F, 0x4DF435C934063199, 0xFFFFFFFFFFFFFFFF
|
||||
}
|
||||
},
|
||||
.reciprocal = {
|
||||
.words = {
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000001,
|
||||
0x0000000000000000, 0x36F0255DDE973DCB, 0x4703CE7E2E815197, 0xA6DB0F588448B611,
|
||||
0x64CFCAC5F1872E51, 0xB1F9FBB5BF16FBE7, 0x9689FC0903A801E3, 0xD4802FB8D329550D,
|
||||
0xC8C9D3D922EECE9A, 0x5475DB33DB7B83BB, 0x5C0E13D168049BBC, 0x86C5817647B088D1,
|
||||
0x7AA5CC40E0203558, 0x8EDB2DE189934137, 0x19FC258D79BC217A, 0xC4B8739CBEA038AA,
|
||||
0xA88D0D2F78A77A8A, 0x6FC7FAA8B2BDCA9B, 0xE7502D2F5F6A7B65, 0xF5E4F07AB8B286E4,
|
||||
0x1115F024A6E976BD, 0x2BCE3E5190B891AB, 0xBF2331E9C94DE91F, 0xBE8574370494A354,
|
||||
0xEAC9BE0B31EB3185, 0x40E4069D556E9DD0, 0x9D5D89D7DE4A75C8, 0x8BB49316C106E4E0,
|
||||
0x14B636E60FEBC292, 0xE6249105F5B195FE, 0x906EEF7D26CAF052, 0x9A3E0BC10E100CE0,
|
||||
0xA899C59999BF877D, 0xBA72C59BF5CCF326, 0x2EB59041E144783A, 0xEE4CD860EE0B6450,
|
||||
0x6DAB2569611BADDB, 0x6B78E82043041716, 0xDEC14CC95569811E, 0x498FDEC9D54BD071,
|
||||
0x1EC97A0B25201C17, 0x763900498B0F0308, 0x746D18CEEDB565FF, 0x29964AFA53E3C1B9,
|
||||
0x67ED5909172FB4D7, 0xF345A315C4768765, 0x5294F5E127281391, 0x0C258E7E91556CE5,
|
||||
0xC145E09DAE0A5C7E, 0xEDE843F90F5DA834, 0x399A4ECB4B05F36F, 0xE586ABCAEF7FA12E,
|
||||
0x18B7F0A5564A1616, 0x5D4680FE70FC2A3F, 0xEDFD7374A1D9CA9A, 0xEFBDDF3F3060E354,
|
||||
0x8E1CD71EA518F66B, 0x9725EFEC54AEDB55, 0xAE1CF670C7E28D82, 0x07F6D09E269060E5,
|
||||
0x591A0721ADFEA421, 0x8E27DA72BF177212, 0x072053629D931252, 0xC14AB0DDCC03AA20
|
||||
}
|
||||
}
|
||||
};
|
||||
Modulus4096 Modulus4096_modulus_default = &p;
|
||||
const_uint4096 uint4096_modulus_default = &p.modulus;
|
||||
|
||||
struct uint4096_s g = {
|
||||
.words = {
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000002
|
||||
}
|
||||
};
|
||||
const_uint4096 uint4096_generator_default = &g;
|
|
@ -0,0 +1,73 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Important invariants:
|
||||
// UINT4096_SIZE_BYTES * 8 = UINT4096_SIZE_BITS = 4096
|
||||
// WORD_SIZE_BITS = WORD_SIZE_BYTES * 8
|
||||
// WORD_COUNT * WORD_SIZE_BITS = UINT4096_SIZE_BITS
|
||||
// WORD_T = uintWORD_SIZE_BITS_t
|
||||
// 2^LOG2_WORD_COUNT = WORD_COUNT
|
||||
// PRIxUINT4096_WORD_T uses the right format string for a UINT4096_WORD_T
|
||||
#define UINT4096_SIZE_BITS 4096
|
||||
#define UINT4096_SIZE_BYTES 512
|
||||
#define UINT4096_WORD_COUNT 64
|
||||
#define UINT4096_WORD_SIZE_BYTES 8
|
||||
#define UINT4096_WORD_SIZE_BITS 64
|
||||
#define UINT4096_WORD_T uint64_t
|
||||
#define UINT4096_LOG2_WORD_COUNT 6
|
||||
#define PRIxUINT4096_WORD_T ("%016" PRIx64)
|
||||
|
||||
struct uint4096_s { UINT4096_WORD_T words[UINT4096_WORD_COUNT]; };
|
||||
|
||||
// Some discussion of naming here. There are two conflicts to resolve:
|
||||
//
|
||||
// 1. The ElectionGuard convention uses upper case, but the base integer types
|
||||
// in C are all uint*_t (lower-case).
|
||||
// 2. The ElectionGuard convention only includes _r and _s as possible
|
||||
// suffixes, preferring no suffix at all for abstract types, but the base
|
||||
// integer types use a _t suffix to indicate they are types.
|
||||
//
|
||||
// There's no solution that will please everybody, I suspect. I choose the
|
||||
// ElectionGuard convention everywhere except that I keep uint lower-case,
|
||||
// because the lower-case uint naming convention is so widespread and
|
||||
// well-known.
|
||||
typedef struct uint4096_s *uint4096;
|
||||
typedef struct uint4096_s const *const_uint4096;
|
||||
typedef struct Modulus4096_s const *const Modulus4096;
|
||||
|
||||
// The functions below that return a uint4096 use NULL to signal out-of-memory
|
||||
// conditions.
|
||||
|
||||
// The first byte is the most-significant byte. If there are too many bytes,
|
||||
// the most-significant ones are dropped.
|
||||
uint4096 uint4096_zext(const uint8_t *bytes, size_t num_bytes);
|
||||
uint4096 uint4096_downcast(Modulus4096 modulus);
|
||||
bool uint4096_eq(const_uint4096 a, const_uint4096 b);
|
||||
bool uint4096_le(const_uint4096 a, const_uint4096 b);
|
||||
bool uint4096_lt(const_uint4096 a, const_uint4096 b);
|
||||
bool uint4096_ge(const_uint4096 a, const_uint4096 b);
|
||||
bool uint4096_gt(const_uint4096 a, const_uint4096 b);
|
||||
uint4096 uint4096_multmod(const_uint4096 a, const_uint4096 b, Modulus4096 modulus);
|
||||
uint4096 uint4096_powmod(const_uint4096 base, const_uint4096 exponent, Modulus4096 modulus);
|
||||
uint64_t uint4096_logmod(const_uint4096 base, const_uint4096 a, Modulus4096 modulus);
|
||||
uint4096 uint4096_copy(const_uint4096 src);
|
||||
void uint4096_free(uint4096 a);
|
||||
|
||||
// _o suffix: overwrite an existing, already-allocated uint4096
|
||||
void uint4096_zext_o(uint4096 out, const uint8_t *bytes, size_t num_bytes);
|
||||
void uint4096_downcast_o(uint4096 out, Modulus4096 modulus);
|
||||
void uint4096_multmod_o(uint4096 out, const_uint4096 a, const_uint4096 b, Modulus4096 modulus);
|
||||
void uint4096_powmod_o(uint4096 out, const_uint4096 base, const_uint4096 exponent, Modulus4096 modulus);
|
||||
void uint4096_copy_o(uint4096 out, const_uint4096 src);
|
||||
|
||||
bool uint4096_fprint(FILE *out, const_uint4096 a);
|
||||
bool uint4096_fscan(FILE *in, uint4096 out);
|
||||
|
||||
// The prime modulus and generator given in the ElectionGuard specification.
|
||||
extern Modulus4096 Modulus4096_modulus_default;
|
||||
extern const_uint4096 uint4096_modulus_default;
|
||||
extern const_uint4096 uint4096_generator_default;
|
|
@ -2,9 +2,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <electionguard/voting/coordinator.h>
|
||||
|
||||
#include "serialize/crypto.h"
|
||||
#include "serialize/voting.h"
|
||||
#include "voting/coordinator.h"
|
||||
#include "voting/message_reps.h"
|
||||
#include "crypto_reps.h"
|
||||
#include "voting/num_ballots.h"
|
||||
|
||||
// @design jwaksbaum This implementation relies on the fact that the
|
||||
|
@ -17,7 +20,7 @@ struct Voting_Coordinator_s
|
|||
{
|
||||
// The number of selections on each ballot
|
||||
uint32_t num_selections;
|
||||
bool selections[MAX_BALLOTS][MAX_SELECTIONS];
|
||||
struct encryption_rep *selections[MAX_BALLOTS];
|
||||
bool registered[MAX_BALLOTS];
|
||||
bool cast[MAX_BALLOTS];
|
||||
bool spoiled[MAX_BALLOTS];
|
||||
|
@ -46,6 +49,9 @@ struct Voting_Coordinator_new_r Voting_Coordinator_new(uint32_t num_selections)
|
|||
|
||||
void Voting_Coordinator_free(Voting_Coordinator ballot_box)
|
||||
{
|
||||
for(size_t i = 0; i < MAX_BALLOTS; i++)
|
||||
if(ballot_box->registered[i])
|
||||
free(ballot_box->selections[i]);
|
||||
free(ballot_box);
|
||||
}
|
||||
|
||||
|
@ -55,7 +61,7 @@ Voting_Coordinator_register_ballot(Voting_Coordinator c,
|
|||
{
|
||||
enum Voting_Coordinator_status status = VOTING_COORDINATOR_SUCCESS;
|
||||
|
||||
struct register_ballot_rep message_rep;
|
||||
struct encrypted_ballot_rep message_rep;
|
||||
|
||||
// Deserialize the message
|
||||
if (status == VOTING_COORDINATOR_SUCCESS)
|
||||
|
@ -67,7 +73,7 @@ Voting_Coordinator_register_ballot(Voting_Coordinator c,
|
|||
.buf = (uint8_t *)message.bytes,
|
||||
};
|
||||
|
||||
Serialize_read_register_ballot(&state, &message_rep);
|
||||
Serialize_read_encrypted_ballot(&state, &message_rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_READING)
|
||||
status = VOTING_COORDINATOR_DESERIALIZE_ERROR;
|
||||
|
@ -86,9 +92,8 @@ Voting_Coordinator_register_ballot(Voting_Coordinator c,
|
|||
|
||||
if (status == VOTING_COORDINATOR_SUCCESS)
|
||||
{
|
||||
// Copy the ballot into the ballot box state
|
||||
memcpy(c->selections[message_rep.id], message_rep.selections,
|
||||
c->num_selections * sizeof(bool));
|
||||
// Move the ballot into the ballot box state
|
||||
c->selections[message_rep.id] = message_rep.selections;
|
||||
|
||||
// Mark it as registered but unspoiled and uncast
|
||||
c->registered[message_rep.id] = true;
|
||||
|
@ -171,7 +176,7 @@ Voting_Coordinator_spoil_ballot(Voting_Coordinator coordinator,
|
|||
*/
|
||||
static enum Voting_Coordinator_status
|
||||
Voting_Coordinator_write_ballot(FILE *out, uint64_t ballot_id, bool cast,
|
||||
uint32_t num_selections, bool *selections)
|
||||
uint32_t num_selections, struct encryption_rep *selections)
|
||||
{
|
||||
enum Voting_Coordinator_status status = VOTING_COORDINATOR_SUCCESS;
|
||||
|
||||
|
@ -186,8 +191,16 @@ Voting_Coordinator_write_ballot(FILE *out, uint64_t ballot_id, bool cast,
|
|||
|
||||
// Write the selections
|
||||
for (uint32_t i = 0;
|
||||
i < num_selections && status == VOTING_COORDINATOR_SUCCESS; i++)
|
||||
fprintf(out, "\t%d", selections[i]);
|
||||
i < num_selections && status == VOTING_COORDINATOR_SUCCESS; i++) {
|
||||
if(fprintf(out, "\t") < 1)
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
|
||||
if(VOTING_COORDINATOR_SUCCESS == status) {
|
||||
if(!Crypto_encryption_fprint(out, &selections[i])) {
|
||||
status = VOTING_COORDINATOR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write the newline
|
||||
if (status == VOTING_COORDINATOR_SUCCESS)
|
|
@ -0,0 +1,229 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <electionguard/voting/encrypter.h>
|
||||
|
||||
#include "crypto_reps.h"
|
||||
#include "random_source.h"
|
||||
#include "serialize/crypto.h"
|
||||
#include "serialize/state.h"
|
||||
#include "serialize/voting.h"
|
||||
#include "voting/message_reps.h"
|
||||
#include "voting/num_ballots.h"
|
||||
|
||||
uint64_t Voting_num_ballots = 0;
|
||||
|
||||
struct Voting_Encrypter_s
|
||||
{
|
||||
struct uid uid;
|
||||
struct joint_public_key_rep joint_key;
|
||||
uint32_t num_selections;
|
||||
RandomSource source;
|
||||
};
|
||||
|
||||
enum Voting_Encrypter_status Voting_Encrypter_RandomSource_status_convert(enum RandomSource_status status) {
|
||||
switch(status) {
|
||||
case RANDOM_SOURCE_SUCCESS: return VOTING_ENCRYPTER_SUCCESS;
|
||||
case RANDOM_SOURCE_INSUFFICIENT_MEMORY: return VOTING_ENCRYPTER_INSUFFICIENT_MEMORY;
|
||||
case RANDOM_SOURCE_IO_ERROR: return VOTING_ENCRYPTER_IO_ERROR;
|
||||
default: return VOTING_ENCRYPTER_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
enum Voting_Encrypter_status Voting_Encrypter_serialize_read_status_convert(enum serialize_status status) {
|
||||
switch(status) {
|
||||
case SERIALIZE_STATE_READING: return VOTING_ENCRYPTER_SUCCESS;
|
||||
case SERIALIZE_STATE_INSUFFICIENT_MEMORY: return VOTING_ENCRYPTER_INSUFFICIENT_MEMORY;
|
||||
case SERIALIZE_STATE_BUFFER_TOO_SMALL: return VOTING_ENCRYPTER_DESERIALIZE_ERROR;
|
||||
default: return VOTING_ENCRYPTER_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
struct Voting_Encrypter_new_r
|
||||
Voting_Encrypter_new(struct uid uid, struct joint_public_key joint_key,
|
||||
uint32_t num_selections)
|
||||
{
|
||||
struct Voting_Encrypter_new_r result;
|
||||
result.encrypter = NULL;
|
||||
result.status = VOTING_ENCRYPTER_SUCCESS;
|
||||
|
||||
// Allocate the Encrypter
|
||||
result.encrypter = malloc(sizeof(struct Voting_Encrypter_s));
|
||||
if (result.encrypter == NULL)
|
||||
result.status = VOTING_ENCRYPTER_INSUFFICIENT_MEMORY;
|
||||
|
||||
// Clone the uid
|
||||
uint8_t *uid_buf = NULL;
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
uid_buf = malloc(uid.len);
|
||||
if (uid_buf == NULL)
|
||||
result.status = VOTING_ENCRYPTER_INSUFFICIENT_MEMORY;
|
||||
else
|
||||
memcpy(uid_buf, uid.bytes, uid.len);
|
||||
|
||||
result.encrypter->uid = (struct uid){
|
||||
.len = uid.len,
|
||||
.bytes = uid_buf,
|
||||
};
|
||||
}
|
||||
|
||||
// Clone the joint key
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
struct serialize_state state =
|
||||
{ .status = SERIALIZE_STATE_READING
|
||||
, .len = joint_key.len
|
||||
, .offset = 0
|
||||
, .buf = (uint8_t *)joint_key.bytes // discard const-ness and pray
|
||||
};
|
||||
Serialize_read_joint_public_key(&state, &result.encrypter->joint_key);
|
||||
result.status = Voting_Encrypter_serialize_read_status_convert(state.status);
|
||||
}
|
||||
|
||||
// Get a random source
|
||||
RandomSource source = NULL;
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS) {
|
||||
struct RandomSource_new_r rs = RandomSource_new();
|
||||
result.status = Voting_Encrypter_RandomSource_status_convert(rs.status);
|
||||
if(VOTING_ENCRYPTER_SUCCESS == result.status) {
|
||||
source = rs.source;
|
||||
result.encrypter->source = rs.source;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
result.encrypter->num_selections = num_selections;
|
||||
|
||||
if (VOTING_ENCRYPTER_SUCCESS != result.status) {
|
||||
if (NULL != source) RandomSource_free(source);
|
||||
if (NULL != uid_buf) free(uid_buf);
|
||||
if (NULL != result.encrypter) free(result.encrypter);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Voting_Encrypter_free(Voting_Encrypter encrypter)
|
||||
{
|
||||
free((void *)encrypter->uid.bytes);
|
||||
RandomSource_free(encrypter->source);
|
||||
free((void *)encrypter);
|
||||
}
|
||||
|
||||
enum Voting_Encrypter_status Voting_Encrypter_Crypto_status_convert(enum Crypto_status status) {
|
||||
switch(status) {
|
||||
case CRYPTO_SUCCESS: return VOTING_ENCRYPTER_SUCCESS;
|
||||
case CRYPTO_INSUFFICIENT_MEMORY: return VOTING_ENCRYPTER_INSUFFICIENT_MEMORY;
|
||||
case CRYPTO_IO_ERROR: return VOTING_ENCRYPTER_IO_ERROR;
|
||||
default: return VOTING_ENCRYPTER_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
struct Voting_Encrypter_encrypt_ballot_r
|
||||
Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter,
|
||||
bool const *selections)
|
||||
{
|
||||
struct Voting_Encrypter_encrypt_ballot_r result;
|
||||
result.status = VOTING_ENCRYPTER_SUCCESS;
|
||||
|
||||
// Construct the ballot id
|
||||
{
|
||||
struct ballot_identifier_rep rep = {.id = Voting_num_ballots};
|
||||
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_RESERVING,
|
||||
.len = 0,
|
||||
.offset = 0,
|
||||
.buf = NULL,
|
||||
};
|
||||
|
||||
Serialize_reserve_ballot_identifier(&state, &rep);
|
||||
Serialize_allocate(&state);
|
||||
Serialize_write_ballot_identifier(&state, &rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
result.status = VOTING_ENCRYPTER_SERIALIZE_ERROR;
|
||||
else
|
||||
{
|
||||
result.id = (struct ballot_identifier){
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the ballot tracker
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
struct ballot_tracker_rep rep = {.id = Voting_num_ballots};
|
||||
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_RESERVING,
|
||||
.len = 0,
|
||||
.offset = 0,
|
||||
.buf = NULL,
|
||||
};
|
||||
|
||||
Serialize_reserve_ballot_tracker(&state, &rep);
|
||||
Serialize_allocate(&state);
|
||||
Serialize_write_ballot_tracker(&state, &rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
result.status = VOTING_ENCRYPTER_SERIALIZE_ERROR;
|
||||
else
|
||||
{
|
||||
result.tracker = (struct ballot_tracker){
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the message
|
||||
struct encrypted_ballot_rep encrypted_ballot;
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
struct Crypto_encrypted_ballot_new_r result = Crypto_encrypted_ballot_new(encrypter->num_selections, Voting_num_ballots);
|
||||
encrypted_ballot = result.result;
|
||||
result.status = Voting_Encrypter_Crypto_status_convert(result.status);
|
||||
}
|
||||
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
struct uint4096_s uint4096_false_s;
|
||||
uint4096_zext_o(&uint4096_false_s, (uint8_t[]){1}, 1);
|
||||
const_uint4096 uint4096_true = uint4096_generator_default, uint4096_false = &uint4096_false_s;
|
||||
|
||||
for(uint32_t i = 0; i < encrypter->num_selections; i++) {
|
||||
Crypto_encrypt(&encrypted_ballot.selections[i], encrypter->source, &encrypter->joint_key,
|
||||
selections[i] ? uint4096_true : uint4096_false);
|
||||
}
|
||||
|
||||
struct serialize_state state =
|
||||
{ .status = SERIALIZE_STATE_RESERVING
|
||||
, .len = 0
|
||||
, .offset = 0
|
||||
, .buf = NULL
|
||||
};
|
||||
Serialize_reserve_encrypted_ballot(&state, &encrypted_ballot);
|
||||
Serialize_allocate(&state);
|
||||
Serialize_write_encrypted_ballot(&state, &encrypted_ballot);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
result.status = VOTING_ENCRYPTER_SERIALIZE_ERROR;
|
||||
else
|
||||
{
|
||||
result.message = (struct register_ballot_message){
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
Voting_num_ballots++;
|
||||
|
||||
return result;
|
||||
}
|
|
@ -4,15 +4,8 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "max_values.h"
|
||||
#include "voting/messages.h"
|
||||
|
||||
struct register_ballot_rep
|
||||
{
|
||||
uint64_t id;
|
||||
uint32_t num_selections;
|
||||
bool selections[MAX_SELECTIONS];
|
||||
};
|
||||
#include <electionguard/max_values.h>
|
||||
#include <electionguard/voting/messages.h>
|
||||
|
||||
struct ballot_tracker_rep
|
||||
{
|
|
@ -1,8 +1,10 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "voting/tracker.h"
|
||||
#include "nouns.h"
|
||||
|
||||
#include <electionguard/voting/tracker.h>
|
||||
|
||||
#include "voting/nouns.h"
|
||||
|
||||
const char chars[16] = "2346789BCDFGHJKM";
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
#include "serialize/crypto.h"
|
||||
#include "serialize/builtins.h"
|
||||
|
||||
void Serialize_reserve_key(struct serialize_state *state,
|
||||
struct key const *data)
|
||||
{
|
||||
for (uint32_t i = 0; i < KEY_SIZE; i++)
|
||||
Serialize_reserve_uint8(state, &data->bytes[i]);
|
||||
}
|
||||
|
||||
void Serialize_write_key(struct serialize_state *state, struct key const *data)
|
||||
{
|
||||
for (uint32_t i = 0; i < KEY_SIZE; i++)
|
||||
Serialize_write_uint8(state, &data->bytes[i]);
|
||||
}
|
||||
|
||||
void Serialize_read_key(struct serialize_state *state, struct key *data)
|
||||
{
|
||||
for (uint32_t i = 0; i < KEY_SIZE; i++)
|
||||
Serialize_read_uint8(state, &data->bytes[i]);
|
||||
}
|
||||
|
||||
void Serialize_reserve_private_key(struct serialize_state *state,
|
||||
struct private_key const *data)
|
||||
{
|
||||
Serialize_reserve_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_reserve_key(state, &data->coefficients[i]);
|
||||
}
|
||||
|
||||
void Serialize_write_private_key(struct serialize_state *state,
|
||||
struct private_key const *data)
|
||||
{
|
||||
Serialize_write_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_write_key(state, &data->coefficients[i]);
|
||||
}
|
||||
|
||||
void Serialize_read_private_key(struct serialize_state *state,
|
||||
struct private_key *data)
|
||||
{
|
||||
Serialize_read_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_read_key(state, &data->coefficients[i]);
|
||||
}
|
||||
|
||||
void Serialize_reserve_public_key(struct serialize_state *state,
|
||||
struct public_key const *data)
|
||||
{
|
||||
Serialize_reserve_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_reserve_key(state, &data->coef_committments[i]);
|
||||
}
|
||||
|
||||
void Serialize_write_public_key(struct serialize_state *state,
|
||||
struct public_key const *data)
|
||||
{
|
||||
Serialize_write_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_write_key(state, &data->coef_committments[i]);
|
||||
}
|
||||
|
||||
void Serialize_read_public_key(struct serialize_state *state,
|
||||
struct public_key *data)
|
||||
{
|
||||
Serialize_read_uint32(state, &data->threshold);
|
||||
for (uint32_t i = 0; i < data->threshold; i++)
|
||||
Serialize_read_key(state, &data->coef_committments[i]);
|
||||
}
|
||||
|
||||
void Serialize_reserve_encrypted_key_share(
|
||||
struct serialize_state *state, struct encrypted_key_share const *data)
|
||||
{
|
||||
Serialize_reserve_private_key(state, &data->private_key);
|
||||
Serialize_reserve_public_key(state, &data->recipient_public_key);
|
||||
}
|
||||
|
||||
void Serialize_write_encrypted_key_share(struct serialize_state *state,
|
||||
struct encrypted_key_share const *data)
|
||||
{
|
||||
Serialize_write_private_key(state, &data->private_key);
|
||||
Serialize_write_public_key(state, &data->recipient_public_key);
|
||||
}
|
||||
|
||||
void Serialize_read_encrypted_key_share(struct serialize_state *state,
|
||||
struct encrypted_key_share *data)
|
||||
{
|
||||
Serialize_read_private_key(state, &data->private_key);
|
||||
Serialize_read_public_key(state, &data->recipient_public_key);
|
||||
}
|
||||
|
||||
void Serialize_reserve_joint_public_key(struct serialize_state *state,
|
||||
struct joint_public_key_rep const *data)
|
||||
{
|
||||
Serialize_reserve_uint32(state, &data->num_trustees);
|
||||
for (size_t i = 0; i < data->num_trustees; i++)
|
||||
Serialize_reserve_public_key(state, &data->public_keys[i]);
|
||||
}
|
||||
|
||||
void Serialize_write_joint_public_key(struct serialize_state *state,
|
||||
struct joint_public_key_rep const *data)
|
||||
{
|
||||
Serialize_write_uint32(state, &data->num_trustees);
|
||||
for (size_t i = 0; i < data->num_trustees; i++)
|
||||
Serialize_write_public_key(state, &data->public_keys[i]);
|
||||
}
|
||||
|
||||
void Serialize_read_joint_public_key(struct serialize_state *state,
|
||||
struct joint_public_key_rep *data)
|
||||
{
|
||||
Serialize_read_uint32(state, &data->num_trustees);
|
||||
for (size_t i = 0; i < data->num_trustees; i++)
|
||||
Serialize_read_public_key(state, &data->public_keys[i]);
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "crypto_reps.h"
|
||||
#include "serialize/state.h"
|
||||
#include "serialize/voting.h"
|
||||
#include "voting/encrypter.h"
|
||||
#include "voting/message_reps.h"
|
||||
#include "voting/num_ballots.h"
|
||||
|
||||
uint64_t Voting_num_ballots = 0;
|
||||
|
||||
struct Voting_Encrypter_s
|
||||
{
|
||||
struct uid uid;
|
||||
struct joint_public_key joint_key;
|
||||
uint32_t num_selections;
|
||||
};
|
||||
|
||||
struct Voting_Encrypter_new_r
|
||||
Voting_Encrypter_new(struct uid uid, struct joint_public_key joint_key,
|
||||
uint32_t num_selections)
|
||||
{
|
||||
struct Voting_Encrypter_new_r result;
|
||||
result.status = VOTING_ENCRYPTER_SUCCESS;
|
||||
|
||||
// Allocate the Encrypter
|
||||
result.encrypter = malloc(sizeof(struct Voting_Encrypter_s));
|
||||
if (result.encrypter == NULL)
|
||||
result.status = VOTING_ENCRYPTER_INSUFFICIENT_MEMORY;
|
||||
|
||||
// Clone the uid
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
uint8_t *buf = malloc(uid.len);
|
||||
if (buf == NULL)
|
||||
result.status = VOTING_ENCRYPTER_INSUFFICIENT_MEMORY;
|
||||
else
|
||||
memcpy(buf, uid.bytes, uid.len);
|
||||
|
||||
result.encrypter->uid = (struct uid){
|
||||
.len = uid.len,
|
||||
.bytes = buf,
|
||||
};
|
||||
}
|
||||
|
||||
// Clone the joint key
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
uint8_t *buf = malloc(joint_key.len);
|
||||
if (buf == NULL)
|
||||
result.status = VOTING_ENCRYPTER_INSUFFICIENT_MEMORY;
|
||||
else
|
||||
memcpy(buf, joint_key.bytes, joint_key.len);
|
||||
|
||||
result.encrypter->joint_key = (struct joint_public_key){
|
||||
.len = joint_key.len,
|
||||
.bytes = buf,
|
||||
};
|
||||
}
|
||||
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
result.encrypter->num_selections = num_selections;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Voting_Encrypter_free(Voting_Encrypter encrypter)
|
||||
{
|
||||
free((void *)encrypter->uid.bytes);
|
||||
free((void *)encrypter->joint_key.bytes);
|
||||
free((void *)encrypter);
|
||||
}
|
||||
|
||||
struct Voting_Encrypter_encrypt_ballot_r
|
||||
Voting_Encrypter_encrypt_ballot(Voting_Encrypter encrypter,
|
||||
bool const *selections)
|
||||
{
|
||||
// Suppress compiler warning that encrypter is unused
|
||||
(void)encrypter;
|
||||
|
||||
struct Voting_Encrypter_encrypt_ballot_r result;
|
||||
result.status = VOTING_ENCRYPTER_SUCCESS;
|
||||
|
||||
// Construct the ballot id
|
||||
{
|
||||
struct ballot_identifier_rep rep = {.id = Voting_num_ballots};
|
||||
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_RESERVING,
|
||||
.len = 0,
|
||||
.offset = 0,
|
||||
.buf = NULL,
|
||||
};
|
||||
|
||||
Serialize_reserve_ballot_identifier(&state, &rep);
|
||||
Serialize_allocate(&state);
|
||||
Serialize_write_ballot_identifier(&state, &rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
result.status = VOTING_ENCRYPTER_SERIALIZE_ERROR;
|
||||
else
|
||||
{
|
||||
result.id = (struct ballot_identifier){
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the ballot tracker
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
struct ballot_tracker_rep rep = {.id = Voting_num_ballots};
|
||||
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_RESERVING,
|
||||
.len = 0,
|
||||
.offset = 0,
|
||||
.buf = NULL,
|
||||
};
|
||||
|
||||
Serialize_reserve_ballot_tracker(&state, &rep);
|
||||
Serialize_allocate(&state);
|
||||
Serialize_write_ballot_tracker(&state, &rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
result.status = VOTING_ENCRYPTER_SERIALIZE_ERROR;
|
||||
else
|
||||
{
|
||||
result.tracker = (struct ballot_tracker){
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the message
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
{
|
||||
struct register_ballot_rep rep;
|
||||
rep.id = Voting_num_ballots;
|
||||
rep.num_selections = encrypter->num_selections;
|
||||
memcpy(&rep.selections, selections,
|
||||
encrypter->num_selections * sizeof(bool));
|
||||
|
||||
struct serialize_state state = {
|
||||
.status = SERIALIZE_STATE_RESERVING,
|
||||
.len = 0,
|
||||
.offset = 0,
|
||||
.buf = NULL,
|
||||
};
|
||||
|
||||
Serialize_reserve_register_ballot(&state, &rep);
|
||||
Serialize_allocate(&state);
|
||||
Serialize_write_register_ballot(&state, &rep);
|
||||
|
||||
if (state.status != SERIALIZE_STATE_WRITING)
|
||||
result.status = VOTING_ENCRYPTER_SERIALIZE_ERROR;
|
||||
else
|
||||
{
|
||||
result.message = (struct register_ballot_message){
|
||||
.len = state.len,
|
||||
.bytes = state.buf,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (result.status == VOTING_ENCRYPTER_SUCCESS)
|
||||
Voting_num_ballots++;
|
||||
|
||||
return result;
|
||||
}
|
Загрузка…
Ссылка в новой задаче