diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d51fb5a..6cefd31c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(META_PROJECT_EXPORT "ElectionGuard") set(META_PROJECT_TARGET "electionguard") set(META_VERSION_MAJOR "0") set(META_VERSION_MINOR "1") -set(META_VERSION_PATCH "11") +set(META_VERSION_PATCH "12") set(META_VERSION "${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}") set(LIBRARY_PUBLIC_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/TestCollections.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/TestCollections.cs index c94f3c46..e84745b5 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/TestCollections.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption.Tests/TestCollections.cs @@ -23,6 +23,9 @@ public void Test_Can_Create_Linked_list() // Assert Assert.That(firstValue == "value"); Assert.That(secondValue == "thing"); + Assert.That(list["some"] == "value"); + Assert.That(list["another"] == "thing"); + Assert.That(list["notthere"] == null); } } } diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Collections.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Collections.cs index 098a3c24..badb7441 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Collections.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Collections.cs @@ -77,6 +77,27 @@ public unsafe string GetValueAt(ulong position) return Marshal.PtrToStringAnsi(value); } + + /// + /// Get the value using the designated key + /// + public unsafe string this[string searchKey] + { + get + { + var count = NativeInterface.LinkedList.GetCount(Handle); + for (ulong position = 0; position < count; position++) + { + var status = NativeInterface.LinkedList.GetElementAt( + Handle, position, out IntPtr key, out IntPtr value); + status.ThrowIfError(); + if (Marshal.PtrToStringAnsi(key) == searchKey) + return Marshal.PtrToStringAnsi(value); + } + return null; + } + } + #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member protected override unsafe void DisposeUnmanaged() #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuard.Encryption.csproj b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuard.Encryption.csproj index 067156c3..36161457 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuard.Encryption.csproj +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/ElectionGuard.Encryption.csproj @@ -7,9 +7,9 @@ ElectionGuard ElectionGuard.Encryption - 0.1.11 - 0.1.11.0 - 0.1.11.0 + 0.1.12 + 0.1.12.0 + 0.1.12.0 @@ -19,7 +19,7 @@ ElectionGuard Encryption Open source implementation of ElectionGuard's ballot encryption. Microsoft - 0.1.11 + 0.1.12 MIT https://github.com/microsoft/electionguard-cpp https://github.com/microsoft/electionguard-cpp diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Manifest.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Manifest.cs index 95a22e70..a30b85ec 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Manifest.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/Manifest.cs @@ -2209,6 +2209,79 @@ public unsafe Manifest( } } + /// + /// Creates a `Manifest` object + /// + /// + /// election type + /// start date for election + /// end data for the election + /// array of the `GeopoliticalUnit` for election + /// array of the `Party` for election + /// array of the `Candidate` for election + /// array of the `ContestDescription` for election + /// array of the `BallotStyle` for election + /// name of the election + /// contact information for the election + public unsafe Manifest( + string electionScopeId, ElectionType electionType, + DateTime startDate, DateTime endDate, + GeopoliticalUnit[] gpUnits, Party[] parties, + Candidate[] candidates, ContestDescription[] contests, + BallotStyle[] ballotStyles, InternationalizedText name, ContactInformation contact) + { + IntPtr[] gpUnitPointers = new IntPtr[gpUnits.Length]; + for (var i = 0; i < gpUnits.Length; i++) + { + gpUnitPointers[i] = gpUnits[i].Handle.Ptr; + gpUnits[i].Dispose(); + } + + IntPtr[] partyPointers = new IntPtr[parties.Length]; + for (var i = 0; i < parties.Length; i++) + { + partyPointers[i] = parties[i].Handle.Ptr; + parties[i].Dispose(); + } + + IntPtr[] candidatePointers = new IntPtr[candidates.Length]; + for (var i = 0; i < candidates.Length; i++) + { + candidatePointers[i] = candidates[i].Handle.Ptr; + candidates[i].Dispose(); + } + + IntPtr[] contestPointers = new IntPtr[contests.Length]; + for (var i = 0; i < contests.Length; i++) + { + contestPointers[i] = contests[i].Handle.Ptr; + contests[i].Dispose(); + } + + IntPtr[] ballotStylePointers = new IntPtr[ballotStyles.Length]; + for (var i = 0; i < ballotStyles.Length; i++) + { + ballotStylePointers[i] = ballotStyles[i].Handle.Ptr; + ballotStyles[i].Dispose(); + } + + var status = NativeInterface.Manifest.New( + electionScopeId, electionType, name.Handle, + (ulong)new DateTimeOffset(startDate).ToUnixTimeMilliseconds(), + (ulong)new DateTimeOffset(endDate).ToUnixTimeMilliseconds(), + gpUnitPointers, (ulong)gpUnitPointers.LongLength, + partyPointers, (ulong)partyPointers.LongLength, + candidatePointers, (ulong)candidatePointers.LongLength, + contestPointers, (ulong)contestPointers.LongLength, + ballotStylePointers, (ulong)ballotStylePointers.LongLength, + contact.Handle, + out Handle); + if (status != Status.ELECTIONGUARD_STATUS_SUCCESS) + { + throw new ElectionGuardException($"Manifest Error Status: {status}"); + } + } + #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member protected override unsafe void DisposeUnmanaged() #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member diff --git a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/NativeInterface.cs b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/NativeInterface.cs index e72e03c2..8bdf6a08 100644 --- a/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/NativeInterface.cs +++ b/bindings/netstandard/ElectionGuard/ElectionGuard.Encryption/NativeInterface.cs @@ -1888,7 +1888,31 @@ internal static extern Status New( ulong ballotStylesSize, out ManifestHandle handle); - // TODO: eg_election_manifest_new_with_contact + [DllImport(DllName, EntryPoint = "eg_election_manifest_new_with_contact", + CallingConvention = CallingConvention.Cdecl, SetLastError = true)] + internal static extern Status New( + [MarshalAs(UnmanagedType.LPStr)] string electionScopeId, + ElectionType electionType, + InternationalizedText.InternationalizedTextHandle name, + ulong startDate, + ulong endDate, + // TODO ISSUE #212: type safety + [MarshalAs(UnmanagedType.LPArray)] IntPtr[] gpUnits, + ulong gpUnitsSize, + // TODO ISSUE #212: type safety + [MarshalAs(UnmanagedType.LPArray)] IntPtr[] parties, + ulong partiesSize, + // TODO ISSUE #212: type safety + [MarshalAs(UnmanagedType.LPArray)] IntPtr[] candidates, + ulong candidatesSize, + // TODO ISSUE #212: type safety + [MarshalAs(UnmanagedType.LPArray)] IntPtr[] contests, + ulong contestSize, + // TODO ISSUE #212: type safety + [MarshalAs(UnmanagedType.LPArray)] IntPtr[] ballotStyles, + ulong ballotStylesSize, + ContactInformation.ContactInformationHandle contact, + out ManifestHandle handle); [DllImport(DllName, EntryPoint = "eg_election_manifest_free", CallingConvention = CallingConvention.Cdecl, SetLastError = true)] diff --git a/src/electionguard/serialize.hpp b/src/electionguard/serialize.hpp index b694ec1d..0cf12154 100644 --- a/src/electionguard/serialize.hpp +++ b/src/electionguard/serialize.hpp @@ -513,6 +513,8 @@ namespace electionguard serialized.push_back({"contact_information", contactInformation}); } + serialized.push_back({"spec_version", "1.0"}); + return serialized; } @@ -1059,7 +1061,7 @@ namespace electionguard {"manifest_hash", serializable.getManifestHash()->toHex()}, {"code_seed", serializable.getBallotCodeSeed()->toHex()}, {"contests", contests}, - {"ballot_code", serializable.getBallotCode()->toHex()}, + {"code", serializable.getBallotCode()->toHex()}, {"timestamp", serializable.getTimestamp()}, {"crypto_hash", serializable.getCryptoHash()->toHex()}, }; @@ -1074,7 +1076,7 @@ namespace electionguard auto style_id = j["style_id"].get(); auto manifest_hash = j["manifest_hash"].get(); auto code_seed = j["code_seed"].get(); - auto ballot_code = j["ballot_code"].get(); + auto ballot_code = j["code"].get(); auto timestamp = j["timestamp"].get(); auto ballot_nonce = j["nonce"].is_null() ? "" : j["nonce"].get(); auto crypto_hash = j["crypto_hash"].get(); @@ -1265,7 +1267,7 @@ namespace electionguard { auto result = SubmittedBallotWrapper::fromObjectWrapper(serializable); - result["state"] = getBallotBoxStateString(serializable.getState()); + result["state"] = serializable.getState(); return result; } @@ -1273,7 +1275,7 @@ namespace electionguard static unique_ptr toObject(json j) { auto ciphertext = SubmittedBallotWrapper::toObjectWrapper(j); - auto state = getBallotBoxState(j["state"].get()); + auto state = electionguard::BallotBoxState(j["state"].get()); // TODO: make this a move instead of a copy return electionguard::SubmittedBallot::from(*ciphertext, state); } @@ -1327,30 +1329,29 @@ namespace electionguard json plaintext = CompactPlaintextBallotWrapper::fromObjectWrapper(*serializable.getPlaintext()); - json result = { - {"plaintext", plaintext}, - {"code_seed", serializable.getBallotCodeSeed()->toHex()}, - {"ballot_code", serializable.getBallotCode()->toHex()}, - {"nonce", serializable.getNonce()->toHex()}, - {"timestamp", serializable.getTimestamp()}, - {"ballot_box_state", getBallotBoxStateString(serializable.getBallotBoxState())}}; + json result = {{"plaintext", plaintext}, + {"code_seed", serializable.getBallotCodeSeed()->toHex()}, + {"code", serializable.getBallotCode()->toHex()}, + {"nonce", serializable.getNonce()->toHex()}, + {"timestamp", serializable.getTimestamp()}, + {"ballot_box_state", serializable.getBallotBoxState()}}; return result; } static unique_ptr toObject(json j) { auto codeSeed = j["code_seed"].get(); - auto ballotCode = j["ballot_code"].get(); + auto ballotCode = j["code"].get(); auto nonce = j["nonce"].get(); auto timestamp = j["timestamp"].get(); - auto ballotBoxState = j["ballot_box_state"].get(); + auto ballotBoxState = + electionguard::BallotBoxState(j["ballot_box_state"].get()); auto plaintext = CompactPlaintextBallotWrapper::toObjectWrapper(j["plaintext"]); return make_unique( - move(plaintext), getBallotBoxState(ballotBoxState), - ElementModQ::fromHex(codeSeed), ElementModQ::fromHex(ballotCode), timestamp, - ElementModQ::fromHex(nonce)); + move(plaintext), ballotBoxState, ElementModQ::fromHex(codeSeed), + ElementModQ::fromHex(ballotCode), timestamp, ElementModQ::fromHex(nonce)); } public: