Skip to content

Commit

Permalink
Feature/cli verify (#451)
Browse files Browse the repository at this point in the history
* Add Encryption Device member accessors

* add ballot id to tally

* add encryption device converter

* Add ElectionRecordManager

add election record data structure to decryption library and modify the generator in the ui project to use the core values when exporting

* add verification result

* add verify command

* add documentation and lint

* add dependencies

* add arm

* add encryption project instead of nuget package

* add a sample election record

* Add verify steps

* update docs

* update category

* cleanup verification 

replace record with one that passes

* add verbose printing

* add verification 4

* realign verification order based on new e.g 2.0 spec

* use ToHashCode

add equality comparer

* verify confirmation code

* verify ciphertext tally

* stub in verify contest range proof

* fix verifiation

* Ensure Accumulated shares propagate proofs

create Decrypt overrides that accept and check for proofs for decryption selections. ensure those proofs are copied into the decryption results.

* adjust the GenerateElectionRecord test to console log

ensure the runsetup task runs a part of the unit test and not as part of the one time setup process

* only add proof if not null

* sum challenge responses

adjust decryption proofs an their equation reference numbers to match the new spec. ad a test covering the share proof accumulation

* reorder and rename verifications

* adjust verification 9

* fix compilation errors

* fix missing usings

* fix compilation error

* add Verification 12

* Add verification 10

* add verification 13

* adjust cp proof interface

* add implementation for Verification 6

* annotate missing verifications

* fix json property names in election constants file

* adjust numbering and check for null proofs

* ensure decrypted value M is assigned

* add decrypted tally to plaintext tally selection

adjust verifier steps

* address PR feedback

* remove debug check

* fix spoiled ballot tests
  • Loading branch information
AddressXception authored Sep 11, 2023
1 parent 900fbae commit ac86614
Show file tree
Hide file tree
Showing 72 changed files with 2,792 additions and 394 deletions.
13 changes: 11 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all build build-msys2 build-android build-ios build-netstandard build-ui build-wasm build-npm clean clean-netstandard clean-ui clean-wasm environment environment-wasm format memcheck sanitize sanitize-asan sanitize-tsan bench bench-netstandard test test-msys2 test-netstandard test-netstandard-copy-output
.PHONY: all build build-msys2 build-android build-ios build-netstandard build-ui build-wasm build-npm clean clean-netstandard clean-ui clean-wasm environment environment-wasm format memcheck sanitize sanitize-asan sanitize-tsan bench bench-netstandard test test-msys2 test-netstandard test-netstandard-copy-output generate-sample-election-record verify

.EXPORT_ALL_VARIABLES:
ELECTIONGUARD_CACHE=$(subst \,/,$(realpath .))/.cache
Expand Down Expand Up @@ -717,7 +717,6 @@ endif

TEMPFILE=sample-data-1-0.zip
fetch-sample-data:

@echo ⬇️ FETCH Sample Data
wget -O $(TEMPFILE) https://github.com/microsoft/electionguard/releases/download/v1.0/sample-data.zip
unzip -o $(TEMPFILE)
Expand All @@ -726,3 +725,13 @@ fetch-sample-data:
generate-sample-data: build-netstandard
@echo Generate Sample Data
dotnet test -a $(PROCESSOR) -c $(TARGET) --filter TestCategory=OutputTestData ./bindings/netstandard/ElectionGuard/ElectionGuard.Decryption.Tests/ElectionGuard.Decryption.Tests.csproj

generate-sample-election-record: build-netstandard
@echo Generate Sample Data
dotnet test -a $(PROCESSOR) -c $(TARGET) --filter TestCategory=GenerateElectionRecord ./bindings/netstandard/ElectionGuard/ElectionGuard.Decryption.Tests/ElectionGuard.Decryption.Tests.csproj


verify: build-cli
@echo 🧪 Executing CLI Verifier $(OPERATING_SYSTEM) $(PROCESSOR) $(TARGET)
cd ./apps/electionguard-cli && dotnet run -a $(PROCESSOR) -c $(TARGET) verify -- -f $(ELECTIONGUARD_DATA_DIR)/test/ElectionRecord.zip

4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ make build-netstandard

Then, open Visual studio for Mac and run the `ElectionGuard.Tests.Android` or `ElectionGuard.Tests.iOS` project.

## Command Line Interface

There is a command line interface in the `./apps/electionguard-cli` folder. This is a tool useful for generating test data and interacting with ElectionGuard.

## 📄 Documentation

## Contributing
Expand Down
3 changes: 3 additions & 0 deletions apps/electionguard-cli/Create/CreateElectionCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

namespace ElectionGuard.CLI.Encrypt
{
/// <summary>
/// Create an Election Package.
/// </summary>
internal class CreateElectionCommand
{
public static Task Execute(CreateElectionOptions options)
Expand Down
34 changes: 33 additions & 1 deletion apps/electionguard-cli/ElectionGuard.CLI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<AssemblyName>ElectionGuard.CLI</AssemblyName>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<Platforms>x64;x86</Platforms>
<Platforms>arm64;x64;x86</Platforms>
</PropertyGroup>

<PropertyGroup>
Expand All @@ -21,9 +21,13 @@

<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<!-- <PackageReference Include="ElectionGuard.Encryption" Version="1.91.11" /> -->
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Decryption\ElectionGuard.Decryption.csproj" />
<ProjectReference Include="..\..\bindings\netstandard\ElectionGuard\ElectionGuard.ElectionSetup\ElectionGuard.ElectionSetup.csproj" />
<ProjectReference Include="..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Encryption\ElectionGuard.Encryption.csproj" />
<ProjectReference Include="..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Encryption.Utils\ElectionGuard.Encryption.Utils.csproj" />
</ItemGroup>

Expand All @@ -42,4 +46,32 @@
<WarningsNotAsErrors>SYSLIB0004</WarningsNotAsErrors>
</PropertyGroup>

<PropertyGroup Label="Library Paths">
<ElectionGuardData>..\..\data</ElectionGuardData>
<ElectionGuardLibs>..\..\build\libs</ElectionGuardLibs>
</PropertyGroup>
<ItemGroup>
<Content Include="$(ElectionGuardData)\**" LinkBase="data">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup Label="C++ Built Libraries">
<None Name="Windows (MSVC)" Visible="false" Include="$(ElectionGuardLibs)\Windows\$(PlatformTarget)\$(Configuration)\src\$(Configuration)\*.dll*">
<CopyToOutputDirectory Condition="'$(OS)' == 'Windows_NT'">PreserveNewest</CopyToOutputDirectory>
</None>
<None Name="Windows HACL (MSVC)" Visible="false" Include="$(ElectionGuardLibs)\Windows\$(PlatformTarget)\$(Configuration)\libs\hacl\$(Configuration)\*.dll*">
<CopyToOutputDirectory Condition="'$(OS)' == 'Windows_NT'">PreserveNewest</CopyToOutputDirectory>
</None>
<None Name="Windows Symbols (MSVC)" Visible="false" Include="$(ElectionGuardLibs)\Windows\$(PlatformTarget)\$(Configuration)\src\$(Configuration)\*.pdb*">
<CopyToOutputDirectory Condition="'$(OS)' == 'Windows_NT'">PreserveNewest</CopyToOutputDirectory>
</None>

<None Name="Windows (msys2)" Visible="false" Include="$(ElectionGuardLibs)\$(PlatformTarget)\$(Configuration)\src\*.dll*" CopyToOutputDirectory="PreserveNewest" />
<None Name="Windows HACL (msys2)" Visible="false" Include="$(ElectionGuardLibs)\$(PlatformTarget)\$(Configuration)\libs\hacl\*.dll*" CopyToOutputDirectory="PreserveNewest" />
<None Name="MacOS" Visible="false" Include="$(ElectionGuardLibs)\Darwin\$(PlatformTarget)\$(Configuration)\src\*.dylib" CopyToOutputDirectory="PreserveNewest" />
<None Name="MacOS HACL" Visible="false" Include="$(ElectionGuardLibs)\Darwin\$(PlatformTarget)\$(Configuration)\libs\hacl\*.dylib" CopyToOutputDirectory="PreserveNewest" />
<None Name="Linux" Visible="false" Include="$(ElectionGuardLibs)\Linux\$(PlatformTarget)\$(Configuration)\src\*.so" CopyToOutputDirectory="PreserveNewest" />
<None Name="Linux HACL" Visible="false" Include="$(ElectionGuardLibs)\Linux\$(PlatformTarget)\$(Configuration)\libs\hacl\*.so" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

</Project>
42 changes: 42 additions & 0 deletions apps/electionguard-cli/ElectionGuard.CLI.sln
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption.Ut
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectionGuard.Encryption", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Encryption\ElectionGuard.Encryption.csproj", "{DC80E980-829A-4AFF-BB29-AAA594A4118B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectionGuard.ElectionSetup", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.ElectionSetup\ElectionGuard.ElectionSetup.csproj", "{507D524F-0911-4575-8991-C36741FD5A46}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectionGuard.Decryption", "..\..\bindings\netstandard\ElectionGuard\ElectionGuard.Decryption\ElectionGuard.Decryption.csproj", "{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
Debug|arm64 = Debug|arm64
Release|arm64 = Release|arm64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0771316F-7C71-4795-90DF-705EC63442ED}.Debug|x64.ActiveCfg = Debug|x64
Expand All @@ -33,6 +39,10 @@ Global
{0771316F-7C71-4795-90DF-705EC63442ED}.Release|x64.Build.0 = Release|x64
{0771316F-7C71-4795-90DF-705EC63442ED}.Release|x86.ActiveCfg = Release|x86
{0771316F-7C71-4795-90DF-705EC63442ED}.Release|x86.Build.0 = Release|x86
{0771316F-7C71-4795-90DF-705EC63442ED}.Debug|arm64.ActiveCfg = Debug|arm64
{0771316F-7C71-4795-90DF-705EC63442ED}.Debug|arm64.Build.0 = Debug|arm64
{0771316F-7C71-4795-90DF-705EC63442ED}.Release|arm64.ActiveCfg = Release|arm64
{0771316F-7C71-4795-90DF-705EC63442ED}.Release|arm64.Build.0 = Release|arm64
{9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|x64.ActiveCfg = Debug|x64
{9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|x64.Build.0 = Debug|x64
{9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|x86.ActiveCfg = Debug|x86
Expand All @@ -41,6 +51,10 @@ Global
{9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|x64.Build.0 = Release|x64
{9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|x86.ActiveCfg = Release|x86
{9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|x86.Build.0 = Release|x86
{9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|arm64.ActiveCfg = Debug|arm64
{9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Debug|arm64.Build.0 = Debug|arm64
{9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|arm64.ActiveCfg = Release|arm64
{9CF2608E-9B97-4E21-B5B7-C59E2435B110}.Release|arm64.Build.0 = Release|arm64
{DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|x64.ActiveCfg = Debug|x64
{DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|x64.Build.0 = Debug|x64
{DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|x86.ActiveCfg = Debug|x86
Expand All @@ -49,6 +63,34 @@ Global
{DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|x64.Build.0 = Release|x64
{DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|x86.ActiveCfg = Release|x86
{DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|x86.Build.0 = Release|x86
{DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|arm64.ActiveCfg = Debug|arm64
{DC80E980-829A-4AFF-BB29-AAA594A4118B}.Debug|arm64.Build.0 = Debug|arm64
{DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|arm64.ActiveCfg = Release|arm64
{DC80E980-829A-4AFF-BB29-AAA594A4118B}.Release|arm64.Build.0 = Release|arm64
{507D524F-0911-4575-8991-C36741FD5A46}.Debug|x64.ActiveCfg = Debug|x64
{507D524F-0911-4575-8991-C36741FD5A46}.Debug|x64.Build.0 = Debug|x64
{507D524F-0911-4575-8991-C36741FD5A46}.Debug|x86.ActiveCfg = Debug|x86
{507D524F-0911-4575-8991-C36741FD5A46}.Debug|x86.Build.0 = Debug|x86
{507D524F-0911-4575-8991-C36741FD5A46}.Release|x64.ActiveCfg = Release|x64
{507D524F-0911-4575-8991-C36741FD5A46}.Release|x64.Build.0 = Release|x64
{507D524F-0911-4575-8991-C36741FD5A46}.Release|x86.ActiveCfg = Release|x86
{507D524F-0911-4575-8991-C36741FD5A46}.Release|x86.Build.0 = Release|x86
{507D524F-0911-4575-8991-C36741FD5A46}.Debug|arm64.ActiveCfg = Debug|arm64
{507D524F-0911-4575-8991-C36741FD5A46}.Debug|arm64.Build.0 = Debug|arm64
{507D524F-0911-4575-8991-C36741FD5A46}.Release|arm64.ActiveCfg = Release|arm64
{507D524F-0911-4575-8991-C36741FD5A46}.Release|arm64.Build.0 = Release|arm64
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x64.ActiveCfg = Debug|x64
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x64.Build.0 = Debug|x64
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x86.ActiveCfg = Debug|x86
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|x86.Build.0 = Debug|x86
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x64.ActiveCfg = Release|x64
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x64.Build.0 = Release|x64
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x86.ActiveCfg = Release|x86
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|x86.Build.0 = Release|x86
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|arm64.ActiveCfg = Debug|arm64
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Debug|arm64.Build.0 = Debug|arm64
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|arm64.ActiveCfg = Release|arm64
{7EC2EFE1-834D-40DC-BD93-50FBCD95FDCC}.Release|arm64.Build.0 = Release|arm64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
3 changes: 3 additions & 0 deletions apps/electionguard-cli/Encrypt/EncryptCommand.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace ElectionGuard.CLI.Encrypt
{
/// <summary>
/// Encrypt a collection of plaintext ballots
/// </summary>
internal class EncryptCommand
{
public static Task Execute(EncryptOptions options)
Expand Down
89 changes: 46 additions & 43 deletions apps/electionguard-cli/Generate/GenerateCommand.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using ElectionGuard.Encryption.Utils.Generators;
using ElectionGuard.Extensions;
using Newtonsoft.Json;

using ElectionGuard.Encryption.Utils.Generators;
using ElectionGuard.Extensions;
using Newtonsoft.Json;

namespace ElectionGuard.CLI.Generate
{
/// <summary>
/// Generate plaintext ballots from a manifest and encrypt them using a context.
/// </summary>
internal class GenerateCommand
{
public static Task Execute(GenerateOptions options)
Expand All @@ -28,51 +31,51 @@ private async Task ExecuteInternal(GenerateOptions options)
var context = Path.Combine(options.WorkingDir, "context.json");
var manifest = Path.Combine(options.WorkingDir, "manifest.json");
using var internalManifest = GetInternalManifest(manifest);
using var encryptionMediator = GetEncryptionMediator(context, manifest);

var plaintextBallots = BallotGenerator.GetFakeBallots(
using var encryptionMediator = GetEncryptionMediator(context, manifest);

var plaintextBallots = BallotGenerator.GetFakeBallots(
internalManifest, Random.Shared, options.BallotCount);

var plaintextPath = Path.Combine(options.WorkingDir, "plaintext");

var plaintextPath = Path.Combine(options.WorkingDir, "plaintext");
var encryptedPath = Path.Combine(options.WorkingDir, "encrypted_ballots");

foreach (var ballot in plaintextBallots)
{
var ciphertext = encryptionMediator.Encrypt(ballot, false);
if (Random.Shared.NextSingle() > options.SpoiledPercent / 100.0)
{
ciphertext.Cast();

foreach (var ballot in plaintextBallots)
{
var ciphertext = encryptionMediator.Encrypt(ballot, false);
if (Random.Shared.NextSingle() > options.SpoiledPercent / 100.0)
{
ciphertext.Cast();
}
else
{
ciphertext.Challenge();
}
var ballotCode = ciphertext.BallotCode;
var ballotData = ciphertext.ToJson();
File.WriteAllText(Path.Combine(encryptedPath, $"{ballotCode}.json"), ballotData);
var data = ballot.ToJson();

if (tally == null)
{
tally = JsonConvert.DeserializeObject<PlainTally>(data);
tally?.Clear();
tally.object_id = $"Tally for {plaintextBallots.Count} ballots";
tally.style_id = string.Empty;
}
if (ciphertext.IsCast)
{
var b = JsonConvert.DeserializeObject<PlainTally>(data);
tally += b;
}
if (options.PlaintextOutput)
{
File.WriteAllText(Path.Combine(plaintextPath, $"{ballotCode}.json"), data);
}
{
ciphertext.Challenge();
}
var ballotCode = ciphertext.BallotCode;
var ballotData = ciphertext.ToJson();
File.WriteAllText(Path.Combine(encryptedPath, $"{ballotCode}.json"), ballotData);
var data = ballot.ToJson();

if (tally == null)
{
tally = JsonConvert.DeserializeObject<PlainTally>(data);
tally?.Clear();
tally.object_id = $"Tally for {plaintextBallots.Count} ballots";
tally.style_id = string.Empty;
}
if (ciphertext.IsCast)
{
var b = JsonConvert.DeserializeObject<PlainTally>(data);
tally += b;
}
if (options.PlaintextOutput)
{
File.WriteAllText(Path.Combine(plaintextPath, $"{ballotCode}.json"), data);
}
Console.WriteLine($"Generated Ballot {ballotCode}.json");
ciphertext.Dispose();
}
var tallyJson = JsonConvert.SerializeObject(tally);
File.WriteAllText(Path.Combine(options.WorkingDir, $"tally.json"), tallyJson);
}
var tallyJson = JsonConvert.SerializeObject(tally);
File.WriteAllText(Path.Combine(options.WorkingDir, $"tally.json"), tallyJson);

plaintextBallots.Dispose();
encryptionMediator.Dispose();
Expand Down
8 changes: 7 additions & 1 deletion apps/electionguard-cli/Program.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
using CommandLine;
using ElectionGuard.CLI.Encrypt;
using ElectionGuard.CLI.Generate;
using ElectionGuard.CLI.Generate;
using System.Reflection;
using ElectionGuard.Converters;
using Newtonsoft.Json;

namespace ElectionGuard.CLI;

class Program
{
static async Task Main(string[] args)
{
JsonConvert.DefaultSettings = SerializationSettings.NewtonsoftSettings;
var verbs = LoadVerbs();
_ = await Parser.Default.ParseArguments(args, verbs)
.WithParsedAsync(Run);
Expand All @@ -34,6 +37,9 @@ private static async Task Run(object obj)
case GenerateOptions g:
await GenerateCommand.Execute(g);
break;
case VerifyOptions v:
await VerifyCommand.Execute(v);
break;
}
}
}
24 changes: 22 additions & 2 deletions apps/electionguard-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Learn More in the [ElectionGuard Repository](https://github.com/microsoft/electi

## CLI

This project is a command line utility for encrypting ballots which simulates an encryption device.
This project is a command line utility that includes various functions to generate test data and interact with election guard. It is able to create an encryption package that would be used with an encryption device, it can simulate an encryption device by encrypting ballots, it can generate ballots from a manifest, and it can verify an election record.

## Getting Started

Expand All @@ -24,4 +24,24 @@ dotnet pack
# add the tool for global use
dotnet tool install --global --add-source ./nupkg electionguard

```
```

## Commands

The CLI Tool includes a number of commands for working with electionguard data.

### Create Election

Create an election package to be used by an encryption device.

### Encrypt Ballot

Encrypt Ballots using a context.

### Generate Ballots

Generate plaintext ballots from a manifest and context, and encrypt them.

### Verify Election Record

Verify an election record.
Loading

0 comments on commit ac86614

Please sign in to comment.