Skip to content

Commit 8765428

Browse files
📐 Add to C# Interface (#199)
* 🚧 Adjust to Single Project Shift project towards new csproj for C# project and away from Shared Setup. Remove the shared project setup and start with .net standard 2.0 and .net framework 4.8 with the goal of adding more pieces including .net core. Fix tests * 🙈 Ignore Test with Memory Address Issues * ✨ Create Release Workflow * ✨ Add links to README * ♻️ Update Make * 🚀 Add so, dylib, and dll to Release * respect configuration when loading binaries * use truncated manifest replace the hardcoded manifest with one that is not affected by #176 * update readme and build tasks * Remove msys package target * try run netstandard tests * only run netstandard tests on macos for now * add chaum pedersen to C interface * Add C# chaum pedersen proofs * update version numbers Co-authored-by: Keith Fung <keith.robert.fung@gmail.com> Co-authored-by: Keith Fung <keith.fung@infernored.com>
1 parent f716332 commit 8765428

18 files changed

Lines changed: 1201 additions & 85 deletions

File tree

.github/workflows/pull-request.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ jobs:
109109
- name: Run Tests
110110
if: (runner.os == 'Windows' && matrix.compiler == 'msvc')
111111
run: make test-msvc
112+
- name: Run .Net Tests
113+
run: make test-netstandard
112114
- name: Run Sanitizer
113115
if: (runner.os == 'Linux' && matrix.os == 'ubuntu-20.04')
114116
run: make sanitize-asan

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ set(META_PROJECT_NAME "ElectionGuard")
66
set(META_PROJECT_EXPORT "ElectionGuard")
77
set(META_PROJECT_TARGET "electionguard")
88
set(META_VERSION_MAJOR "0")
9-
set(META_VERSION_MINOR "0")
10-
set(META_VERSION_PATCH "1")
9+
set(META_VERSION_MINOR "1")
10+
set(META_VERSION_PATCH "2")
1111
set(META_VERSION "${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}")
1212

1313
set(LIBRARY_PUBLIC_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,14 @@ endif
288288
cmake --build $(ELECTIONGUARD_BUILD_LIBS_DIR)/x86_64/$(TARGET)
289289
$(ELECTIONGUARD_BUILD_LIBS_DIR)/x86_64/$(TARGET)/test/ElectionGuardBenchmark
290290

291+
bench-netstandard: build-netstandard
292+
@echo 🧪 BENCHMARK
293+
ifeq ($(OPERATING_SYSTEM),Windows)
294+
295+
else
296+
dotnet ./bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Bench/bin/x64/$(TARGET)/net5.0/ElectionGuard.Encryption.Bench.dll
297+
endif
298+
291299
test:
292300
@echo 🧪 TEST
293301
ifeq ($(OPERATING_SYSTEM),Windows)
@@ -334,7 +342,7 @@ endif
334342

335343
test-netstandard: build-netstandard
336344
@echo 🧪 TEST NETSTANDARD
337-
dotnet test ./bindings/netstandard/ElectionGuard/ElectionGuard.sln
345+
dotnet test --configuration $(TARGET) ./bindings/netstandard/ElectionGuard/ElectionGuard.sln
338346

339347
coverage:
340348
@echo ✅ CHECK COVERAGE

bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/ElectionGuard.Encryption.Tests.csproj

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,19 @@
2020
<ElectionGuardLibs>..\..\..\..\build\libs</ElectionGuardLibs>
2121
</PropertyGroup>
2222
<ItemGroup Label="C++ Built Libraries">
23-
<None Name="Windows MSVC x86"
24-
Visible="false"
25-
Include="$(ElectionGuardLibs)\msvc\Win32\src\$(Configuration)\*.dll*">
23+
<None Name="Windows MSVC x86" Visible="false" Include="$(ElectionGuardLibs)\msvc\Win32\src\$(Configuration)\*.dll*">
2624
<CopyToOutputDirectory Condition="'$(Platform)' == 'x86' AND '$(OS)' == 'Windows_NT'">Always</CopyToOutputDirectory>
2725
</None>
28-
<None Name="Windows MSVC x64"
29-
Visible="false"
30-
Include="$(ElectionGuardLibs)\msvc\x64\src\$(Configuration)\*.dll*">
26+
<None Name="Windows MSVC x64" Visible="false" Include="$(ElectionGuardLibs)\msvc\x64\src\$(Configuration)\*.dll*">
3127
<CopyToOutputDirectory Condition="'$(Platform)' == 'x64' AND '$(OS)' == 'Windows_NT'">Always</CopyToOutputDirectory>
3228
</None>
33-
<None Name="MacOS"
34-
Visible="false"
35-
Include="$(ElectionGuardLibs)\x86_64\$(Configuration)\src\*.dylib"
36-
CopyToOutputDirectory="Always" />
37-
<None Name="Linux"
38-
Visible="false"
39-
Include="$(ElectionGuardLibs)\x86_64\$(Configuration)\src\*.so"
40-
CopyToOutputDirectory="Always" />
29+
<None Name="MacOS" Visible="false" Include="$(ElectionGuardLibs)\x86_64\$(Configuration)\src\*.dylib" CopyToOutputDirectory="Always" />
30+
<None Name="Linux" Visible="false" Include="$(ElectionGuardLibs)\x86_64\$(Configuration)\src\*.so" CopyToOutputDirectory="Always" />
4131
</ItemGroup>
4232

4333
<ItemGroup Label="Json Test Data">
44-
<Content Include="..\..\..\..\data\ballot_in_simple.json"
45-
Link="Data\ballot_in_simple.json"
46-
CopyToOutputDirectory="Always" />
47-
<Content Include="..\..\..\..\data\election_manifest_jefferson_county.json"
48-
Link="Data\election_manifest_jefferson_county.json"
49-
CopyToOutputDirectory="Always" />
34+
<Content Include="..\..\..\..\data\ballot_in_simple.json" Link="Data\ballot_in_simple.json" CopyToOutputDirectory="Always" />
35+
<Content Include="..\..\..\..\data\election_manifest_jefferson_county.json" Link="Data\election_manifest_jefferson_county.json" CopyToOutputDirectory="Always" />
5036
<Folder Include="Data\" />
5137
</ItemGroup>
5238
</Project>

bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/TestBallot.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ namespace ElectionGuard.Encrypt.Tests
88
public class TestBallot
99
{
1010
[Test]
11-
[Ignore("Memory Access Violation")]
1211
public void Test_Ballot_Property_Getters()
1312
{
1413
// Arrange
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using ElectionGuard.Encryption.Tests.Utils;
3+
using NUnit.Framework;
4+
5+
namespace ElectionGuard.Encryption.Tests
6+
{
7+
[TestFixture]
8+
public class TestChaumPedersen
9+
{
10+
[Test]
11+
public void Test_DisjunctiveChaumPedersen()
12+
{
13+
var nonce = Constants.ONE_MOD_Q;
14+
var seed = Constants.TWO_MOD_Q;
15+
var keyPair = ElGamalKeyPair.FromSecret(Constants.TWO_MOD_Q);
16+
const ulong vote = 0UL;
17+
var ciphertext = Elgamal.Encrypt(vote, nonce, keyPair.PublicKey);
18+
19+
var proof = new DisjunctiveChaumPedersenProof(
20+
ciphertext, nonce, keyPair.PublicKey, Constants.ONE_MOD_Q, seed, vote);
21+
22+
Assert.That(proof.IsValid(ciphertext, keyPair.PublicKey, Constants.ONE_MOD_Q));
23+
}
24+
}
25+
}

bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/TestEncrypt.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,45 @@ public class TestEncrypt
99
{
1010
readonly string manifest_json = "{\"ballot_styles\":[{\"geopolitical_unit_ids\":[\"some-geopoltical-unit-id\"],\"object_id\":\"some-ballot-style-id\"}],\"candidates\":[{\"object_id\":\"some-candidate-id-1\"},{\"object_id\":\"some-candidate-id-2\"},{\"object_id\":\"some-candidate-id-3\"}],\"contests\":[{\"ballot_selections\":[{\"candidate_id\":\"some-candidate-id-1\",\"object_id\":\"some-object-id-affirmative\",\"sequence_order\":0},{\"candidate_id\":\"some-candidate-id-2\",\"object_id\":\"some-object-id-negative\",\"sequence_order\":1}],\"electoral_district_id\":\"some-geopoltical-unit-id\",\"name\":\"some-referendum-contest-name\",\"number_elected\":1,\"object_id\":\"some-referendum-contest-object-id\",\"sequence_order\":0,\"vote_variation\":\"one_of_m\"},{\"ballot_selections\":[{\"candidate_id\":\"some-candidate-id-1\",\"object_id\":\"some-object-id-candidate-1\",\"sequence_order\":0},{\"candidate_id\":\"some-candidate-id-2\",\"object_id\":\"some-object-id-candidate-2\",\"sequence_order\":1},{\"candidate_id\":\"some-candidate-id-3\",\"object_id\":\"some-object-id-candidate-3\",\"sequence_order\":2}],\"electoral_district_id\":\"some-geopoltical-unit-id\",\"name\":\"some-candidate-contest-name\",\"number_elected\":2,\"object_id\":\"some-candidate-contest-object-id\",\"sequence_order\":1,\"vote_variation\":\"one_of_m\"}],\"election_scope_id\":\"some-scope-id\",\"end_date\":\"2021-02-04T13:30:10Z\",\"geopolitical_units\":[{\"name\":\"some-gp-unit-name\",\"object_id\":\"some-geopoltical-unit-id\",\"type\":\"unknown\"}],\"parties\":[{\"object_id\":\"some-party-id-1\"},{\"object_id\":\"some-party-id-2\"}],\"start_date\":\"2021-02-04T13:30:10Z\",\"type\":\"unknown\"}";
1111
readonly string plaintext_json = "{\"object_id\":\"some-external-id-string-123\",\"style_id\":\"some-ballot-style-id\",\"contests\":[{\"object_id\":\"some-referendum-contest-object-id\",\"ballot_selections\":[{\"object_id\":\"some-candidate-id-1\",\"vote\":1}]}]}";
12-
12+
13+
[Test]
14+
public void Test_Encrypt_Ballot_Simple_Succeeds()
15+
{
16+
// Configure the election context
17+
var keypair = ElGamalKeyPair.FromSecret(Constants.TWO_MOD_Q);
18+
var manifest = new Manifest(manifest_json);
19+
var internalManifest = new InternalManifest(manifest);
20+
var context = new CiphertextElectionContext(
21+
1UL, 1UL, keypair.PublicKey, Constants.TWO_MOD_Q, internalManifest.ManifestHash);
22+
var device = new EncryptionDevice(12345UL, 23456UL, 34567UL, "Location");
23+
var mediator = new EncryptionMediator(internalManifest, context, device);
24+
25+
var ballot = new PlaintextBallot(plaintext_json);
26+
27+
// Act
28+
var ciphertext = mediator.Encrypt(ballot);
29+
30+
// Assert
31+
32+
// a property
33+
Assert.That(ciphertext.ObjectId == ballot.ObjectId);
34+
35+
// json serialization
36+
var json = ciphertext.ToJson();
37+
var fromJson = new CiphertextBallot(json);
38+
Assert.That(ciphertext.ObjectId == fromJson.ObjectId);
39+
40+
// TODO:
41+
// binary serialization
42+
// var bson = ciphertext.Bson;
43+
// var fromBson = CiphertextBallot.FromBson(bson);
44+
// Assert.That(ciphertext.ObjectId == fromBson.ObjectId);
45+
46+
// TODO: submitted ballot
47+
// var submitted = SubmittedBallot.From(ciphertext, BallotBoxState.cast);
48+
// Assert.That(ciphertext.ObjectId == submitted.ObjectId);
49+
}
50+
1351
[Test]
1452
public void Test_Compact_Encrypt_Ballot_Simple_Succeeds()
1553
{

bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Ballot.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ namespace ElectionGuard
66
// Declare native types for convenience
77
using NativeElementModQ = NativeInterface.ElementModQ.ElementModQHandle;
88
using NativeElGamalCiphertext = NativeInterface.ElGamalCiphertext.ElGamalCiphertextHandle;
9+
using NativeDisjunctiveChaumPedersenProof = NativeInterface.DisjunctiveChaumPedersenProof.DisjunctiveChaumPedersenProofHandle;
10+
using NativeConstantChaumPedersenProof = NativeInterface.ConstantChaumPedersenProof.ConstantChaumPedersenProofHandle;
911
using NativePlaintextBallotSelection = NativeInterface.PlaintextBallotSelection.PlaintextBallotSelectionHandle;
1012
using NativeCiphertextBallotSelection = NativeInterface.CiphertextBallotSelection.CiphertextBallotSelectionHandle;
1113
using NativePlaintextBallotContest = NativeInterface.PlaintextBallotContest.PlaintextBallotContestHandle;
@@ -246,6 +248,25 @@ public unsafe ElementModQ Nonce
246248
}
247249
}
248250

251+
/// <summary>
252+
/// The proof that demonstrates the selection is an encryption of 0 or 1,
253+
/// and was encrypted using the `nonce`
254+
/// </summary>
255+
public unsafe DisjunctiveChaumPedersenProof Proof
256+
{
257+
get
258+
{
259+
var status = NativeInterface.CiphertextBallotSelection.GetProof(
260+
Handle, out NativeDisjunctiveChaumPedersenProof value);
261+
if (status != Status.ELECTIONGUARD_STATUS_SUCCESS)
262+
{
263+
Console.WriteLine($"CiphertextBallotSelection Error Proof: {status}");
264+
return null;
265+
}
266+
return new DisjunctiveChaumPedersenProof(value);
267+
}
268+
}
269+
249270
internal unsafe NativeCiphertextBallotSelection Handle;
250271

251272
unsafe internal CiphertextBallotSelection(NativeCiphertextBallotSelection handle)
@@ -452,6 +473,25 @@ public unsafe ElementModQ Nonce
452473
}
453474
}
454475

476+
/// <summary>
477+
/// The proof demonstrates the sum of the selections does not exceed the maximum
478+
/// available selections for the contest, and that the proof was generated with the nonce
479+
/// </summary>
480+
public unsafe ConstantChaumPedersenProof Proof
481+
{
482+
get
483+
{
484+
var status = NativeInterface.CiphertextBallotContest.GetProof(
485+
Handle, out NativeConstantChaumPedersenProof value);
486+
if (status != Status.ELECTIONGUARD_STATUS_SUCCESS)
487+
{
488+
Console.WriteLine($"CiphertextBallotContest Error Proof: {status}");
489+
return null;
490+
}
491+
return new ConstantChaumPedersenProof(value);
492+
}
493+
}
494+
455495
internal unsafe NativeCiphertextBallotContest Handle;
456496

457497
unsafe internal CiphertextBallotContest(NativeCiphertextBallotContest handle)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
namespace ElectionGuard.Encryption
3+
{
4+
public class BallotCompact
5+
{
6+
public BallotCompact()
7+
{
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)