public async Task <ActionResult <InitializeEncryptionResponse> > InitializeEncryption(InitializeEncryptionRequest request) { try { _currentBallotCount = 0; _election = request.Election; _electionMap = _electionMapper.GetElectionMap(request.Election); _electionGuardConfig = request.ElectionGuardConfig; _exportPath = request.ExportPath; _encryptedBallotsExportFileName = request.ExportFileName; await _config.SetElectionAsync(_election); await _config.setElectionGuardConfigAsync(_electionGuardConfig); var response = new InitializeEncryptionResponse { Election = request.Election, ElectionGuardConfig = _electionGuardConfig, ElectionMap = _electionMap }; return(AcceptedAtAction(nameof(InitializeEncryption), response)); } catch (Exception ex) { _logger.LogError("InitializeEncryption: ", ex); return(StatusCode(500)); } }
public SimpleElectionTest(int numberOfTrustees, int threshold, int numberOfBallots, string exportFolder, string encryptedBallotsPrefix, string ballotsPrefix, string tallyPrefix) { _electionGuardConfig = new ElectionGuardConfig() { NumberOfTrustees = numberOfTrustees, NumberOfSelections = 3, Threshold = threshold, SubgroupOrder = 0, ElectionMetadata = "placeholder", }; if (!string.IsNullOrWhiteSpace(exportFolder)) { Directory.CreateDirectory(exportFolder); } _exportFolder = exportFolder; _encryptedBallotsPrefix = encryptedBallotsPrefix; _ballotsPrefix = ballotsPrefix; _tallyPrefix = tallyPrefix; _numberOfBallots = numberOfBallots; _encryptedBallots = new List <string>(); _ballotIds = new List <string>(); _expectedNumberOfSelected = 2; }
public async Task <bool> setElectionGuardConfigAsync(ElectionGuardConfig config) { try { var path = Path.Combine(GetDataDirectory(), "election.config.json"); return(await WriteJsonFileAsync(path, config)); } catch (Exception) { return(false); } }
/// <summary> /// Tallies the ballots file and Decrypts the results into a different output file /// </summary> /// <param name="electionGuardConfig"></param> /// <param name="trusteeKeys"></param> /// <param name="numberOfTrusteesPresent"></param> /// <param name="ballotsFilename"></param> /// <param name="exportPath"></param> /// <param name="exportFilenamePrefix"></param> /// <returns>The filename created containing the tally results</returns> public static TallyVotesResult TallyVotes(ElectionGuardConfig electionGuardConfig, ICollection <string> trusteeKeys, int numberOfTrusteesPresent, string ballotsFilename, string exportPath = "./", string exportFilenamePrefix = "") { var apiConfig = electionGuardConfig.GetApiConfig(); var serializedBytesWithGcHandles = trusteeKeys.Select(ByteSerializer.ConvertFromBase64String); var bytesWithGcHandles = serializedBytesWithGcHandles.ToList(); var trusteeKeysArray = bytesWithGcHandles.Select(bytesWithGcHandle => bytesWithGcHandle.SerializedBytes).ToArray(); var tallyResults = new uint[electionGuardConfig.NumberOfSelections]; var outputFilenamePtr = new IntPtr(); try { var success = API.TallyVotes(apiConfig, trusteeKeysArray, (uint)numberOfTrusteesPresent, ballotsFilename, exportPath, exportFilenamePrefix, out outputFilenamePtr, tallyResults); if (!success) { throw new Exception("ElectionGuardAPI TallyVotes failed"); } var result = new TallyVotesResult() { EncryptedTallyFilename = Marshal.PtrToStringAnsi(outputFilenamePtr), TallyResults = tallyResults.Cast <int>().ToList(), }; return(result); } finally { // Free unmanaged memory API.FreeTallyVotes(outputFilenamePtr); foreach (var bytes in bytesWithGcHandles) { bytes.Handle.Free(); } } }
public void Step01_InitializeElection() { var result = ElectionGuardApi.CreateElection(_electionGuardConfig); _electionGuardConfig = result.ElectionGuardConfig; Assert.That(string.IsNullOrEmpty(_electionGuardConfig.JointPublicKey), Is.False); _trusteeKeys = result.TrusteeKeys; Assert.AreEqual(result.ElectionGuardConfig.NumberOfTrustees, _trusteeKeys.Count); Assert.Greater(_electionGuardConfig.NumberOfSelections, 0); var expectedNumberOfSelections = 3; Assert.AreEqual(expectedNumberOfSelections, result.ElectionGuardConfig.NumberOfSelections); }
/// <summary> /// Encrypts the ballot selections /// </summary> /// <param name="selections"></param> /// <param name="expectedNumberOfSelected"></param> /// <param name="electionGuardConfig"></param> /// <param name="externalIdentifier"></param> /// <param name="exportPath"></param> /// <param name="exportFileName"></param> /// <returns>EncryptBallotResult containing the encrypted ballot, its external id, its tracker string, /// and the file that includes the ballot</returns> public static EncryptBallotResult EncryptBallot( bool[] selections, int expectedNumberOfSelected, ElectionGuardConfig electionGuardConfig, string externalIdentifier, string exportPath = "./", string exportFileName = "") { var apiConfig = electionGuardConfig.GetApiConfig(); var serializedBytesWithGcHandle = ByteSerializer.ConvertFromBase64String(electionGuardConfig.JointPublicKey); apiConfig.SerializedJointPublicKey = serializedBytesWithGcHandle.SerializedBytes; var encryptedBallotMessage = new SerializedBytes(); var trackerPtr = new IntPtr(); try { var success = API.EncryptBallot( selections.Select(b => (byte)(b ? 1 : 0)).ToArray(), (uint)expectedNumberOfSelected, apiConfig, externalIdentifier, out encryptedBallotMessage, exportPath, exportFileName, out IntPtr outputFilename, out trackerPtr); if (!success) { throw new Exception("ElectionGuardAPI EncryptBallot failed"); } var result = new EncryptBallotResult() { ExternalIdentifier = externalIdentifier, EncryptedBallotMessage = ByteSerializer.ConvertToBase64String(encryptedBallotMessage), Tracker = Marshal.PtrToStringAnsi(trackerPtr), OutputFileName = Marshal.PtrToStringAnsi(outputFilename), }; return(result); } finally { // Free unmanaged memory API.FreeEncryptBallot(encryptedBallotMessage, trackerPtr); serializedBytesWithGcHandle.Handle.Free(); } }
/// <summary> /// CreateElection entry point - performs the initial KeyCeremony process to generate public keys and trustee keys /// </summary> /// <param name="initialConfig"></param> /// <returns>CreateElectionResult containing the private trustee keys and /// the updated ElectionGuardConfig with the public key</returns> public static CreateElectionResult CreateElection(ElectionGuardConfig initialConfig) { var apiConfig = initialConfig.GetApiConfig(); // Set up trustee states array to be allocated in the api var trusteeStates = new SerializedBytes[Constants.MaxTrustees]; try { // Call the C library API to create the election and get back the joint public key bytes // The trusteeStates array should be filled out with the appropriate serialized returns as well var success = API.CreateElection(ref apiConfig, trusteeStates); if (!success) { throw new Exception("ElectionGuardAPI CreateElection failed"); } var electionGuardConfig = new ElectionGuardConfig(apiConfig); var trusteeKeys = new Dictionary <int, string>(); // Iterate through the trusteeStates returned and convert each to its base64 representation for (var i = 0; i < trusteeStates.Length; i++) { var trusteeState = trusteeStates[i]; if (trusteeState.Length > 0) { var trusteeStateKeys = ByteSerializer.ConvertToBase64String(trusteeState); trusteeKeys.Add(i, trusteeStateKeys); } } return(new CreateElectionResult() { ElectionGuardConfig = electionGuardConfig, TrusteeKeys = trusteeKeys }); } finally { // Free bytes in unmanaged memory API.FreeCreateElection(apiConfig.SerializedJointPublicKey, trusteeStates); } }
public ElectionGuardController(ILogger <ElectionGuardController> logger, IElectionMapper <Election, Ballot, VoteTally> electionMapper, IConfigFileService configService) { _config = configService; _logger = logger; _electionMapper = electionMapper; _exportPath = Path.Combine(_config.GetDataDirectory(), "election_results"); logger.LogInformation($"DATA: resolved at: {_config.GetDataDirectory()}"); // try to load the election config files from the file system var election = _config.GetElection(); if (election != null) { logger.LogInformation("ElectionController: Found Election"); _election = election; _electionMap = _electionMapper.GetElectionMap(_election); } else { logger.LogInformation("ElectionController: Could not find election.json"); } var electionguardConfig = _config.getElectionGuardConfig(); if (electionguardConfig != null) { logger.LogInformation("ElectionController: Found ElectionGuard Config"); _electionGuardConfig = electionguardConfig; } else { logger.LogInformation("ElectionController: Could not find election.config.json"); } var now = DateTime.Now; _encryptedBallotsExportFileName = $"encrypted-ballots_{now.Year}_{now.Month}_{now.Day}"; _registeredBallotsExportFileNamePrefix = $"registered-ballots"; _tallyExportFileNamePrefix = "tally-results"; }
static int NUM_RANDOM_BALLOTS = 5; // the number of ballots to use when executing the test static void Main(string[] args) { var initialConfig = new ElectionGuardConfig() { NumberOfTrustees = NUM_TRUSTEES, NumberOfSelections = NUM_SELECTIONS, Threshold = THRESHOLD, SubgroupOrder = 0, ElectionMetadata = "placeholder", }; // Create Election Console.WriteLine("\n--- Create Election ---\n"); var electionResult = ElectionGuardApi.CreateElection(initialConfig); foreach (KeyValuePair <int, string> entry in electionResult.TrusteeKeys) { if (String.IsNullOrWhiteSpace(entry.Value)) { throw new Exception("Error reading trustee keys"); } } // Encrypt Ballots Console.WriteLine("\n--- Encrypt Ballots ---\n"); var now = DateTime.Now; var expectedNumberOfSelected = 2; var encryptedBallotsFileName = ""; var encryptedOutputPath = "./ballots_encrypter/"; var encryptedOutputPrefix = $"encrypted-ballots_{now.Year}_{now.Month}_{now.Day}"; if (!ElectionGuardApi.SoftDeleteEncryptedBallotsFile(encryptedOutputPath, encryptedOutputPrefix)) { throw new Exception("Failed soft deleting the encrypted ballots file"); } var testBallots = new List <TestBallot>(); for (var i = 0; i < NUM_RANDOM_BALLOTS; i++) { var ballot = new TestBallot(); ballot.ExternalIdentifier = $"{encryptedOutputPrefix}_{i}"; ballot.Selections = FillRandomBallot(NUM_SELECTIONS, expectedNumberOfSelected); var encryptBallotResult = ElectionGuardApi.EncryptBallot( ballot.Selections, expectedNumberOfSelected, electionResult.ElectionGuardConfig, ballot.ExternalIdentifier, encryptedOutputPath, encryptedOutputPrefix ); Console.WriteLine($"Encrypted Ballot {i}:"); Console.WriteLine($"\tIdentifier = {encryptBallotResult.ExternalIdentifier}"); Console.WriteLine($"\tTracker = {encryptBallotResult.Tracker}"); Console.WriteLine($"\tEncryptedBallotMessage.Length = {encryptBallotResult.EncryptedBallotMessage.Length}"); ballot.EncryptedBallotMessage = encryptBallotResult.EncryptedBallotMessage; ballot.Tracker = encryptBallotResult.Tracker; encryptedBallotsFileName = encryptBallotResult.OutputFileName; testBallots.Add(ballot); } // TODO: test simulating multiple encrypters or an encrypter being reset // [START] OPTIONAL: // When running an encrypter on another device, it is possible to import a file // and pass it to the tally functions, but this is not strictly necessary // from an API Perspective. Console.WriteLine("\n--- Load Ballots ---\n"); var loadBallotsResult = ElectionGuardApi.LoadBallotsFile( 0, 2000, NUM_SELECTIONS, encryptedBallotsFileName ); var loadedExternalIdentifiers = (List <string>)loadBallotsResult.ExternalIdentifiers; var loadedEncryptedBallots = (List <string>)loadBallotsResult.EncryptedBallotMessages; Debug.Assert( LoadedBallotIdentifiersMatchEncryptedBallots( loadedExternalIdentifiers, testBallots, NUM_RANDOM_BALLOTS ) ); Debug.Assert( LoadedBallotsMatchEncryptedBallots( loadedEncryptedBallots, testBallots, NUM_RANDOM_BALLOTS ) ); // TODO: test loading ballots in batches // [END] OPTIONAL: // Register & Record Cast/Spoil Multiple Ballots Console.WriteLine("\n--- Randomly Assigning Ballots to be Cast or Spoil Arrays ---\n"); int currentCastIndex = 0; int currentSpoiledIndex = 0; var castIds = new List <string>(); var spoiledIds = new List <string>(); var memoryExternalIdentifiers = new List <string>(); var memoryEncryptedBallots = new List <string>(); for (int i = 0; i < NUM_RANDOM_BALLOTS; i++) { memoryExternalIdentifiers.Add(testBallots[i].ExternalIdentifier); memoryEncryptedBallots.Add(testBallots[i].EncryptedBallotMessage); if (RandomBit()) { testBallots[i].IsCast = true; testBallots[i].IsSpoiled = false; castIds.Add(testBallots[i].ExternalIdentifier); Console.WriteLine($"Ballot Id: {testBallots[i].ExternalIdentifier} - Cast!"); currentCastIndex++; } else { testBallots[i].IsCast = false; testBallots[i].IsSpoiled = true; spoiledIds.Add(testBallots[i].ExternalIdentifier); Console.WriteLine($"Ballot Id: {testBallots[i].ExternalIdentifier} - Spiled!"); currentSpoiledIndex++; } } if ((currentCastIndex + currentSpoiledIndex) != NUM_RANDOM_BALLOTS) { throw new Exception("Cast and Spil did not match expected ballots"); } Console.WriteLine("\n--- Record Ballots (Register, Cast, and Spoil) ---\n"); var registeredBallotsOutputPath = "./ballots/"; var registeredBallotsOutputPrefix = $"registered-ballots_{now.Year}_{now.Month}_{now.Day}"; var recordResult = ElectionGuardApi.RecordBallots( electionResult.ElectionGuardConfig, castIds, spoiledIds, memoryExternalIdentifiers, memoryEncryptedBallots, registeredBallotsOutputPath, registeredBallotsOutputPrefix ); var castedTrackers = (List <string>)recordResult.CastedBallotTrackers; var spoiledTrackers = (List <string>)recordResult.SpoiledBallotTrackers; Console.WriteLine($"RecordBallots cast trackers\n"); for (int i = 0; i < currentCastIndex; i++) { Console.WriteLine($"\t{castIds[i]}: {castedTrackers[i]}"); } Console.WriteLine($"\nRecordBallots spoiled trackers\n"); for (int i = 0; i < currentSpoiledIndex; i++) { Console.WriteLine($"\t{spoiledIds[i]}: {spoiledTrackers[i]}"); } Console.WriteLine("\nBallot registrations and recording of cast/spoil successful!\n"); Console.WriteLine($"RecordBallots outputted to file = {recordResult.EncryptedBallotsFilename}"); // Tally Votes & Decrypt Results Console.WriteLine("\n--- Tally & Decrypt Votes ---\n"); var tallyOutputPath = "./tallies/"; var tallyOutputPrefix = $"tally_{now.Year}_{now.Month}_{now.Day}"; var tallyResult = ElectionGuardApi.TallyVotes( electionResult.ElectionGuardConfig, electionResult.TrusteeKeys.Values, DECRYPTING_TRUSTEES, recordResult.EncryptedBallotsFilename, tallyOutputPath, tallyOutputPrefix ); var tallyResults = (List <int>)tallyResult.TallyResults; Console.WriteLine("\nTally Results:"); for (int i = 0; i < electionResult.ElectionGuardConfig.NumberOfSelections; i++) { Debug.Assert( ResultEqualsExpectedSelections( testBallots, tallyResults[i], i ) ); } Console.WriteLine($"\nTallyVotes output to file = {tallyResult.EncryptedTallyFilename}"); Console.WriteLine("\n--- Done! ---\n\n"); }
/// <summary> /// Registers all the ballots and records which ballots have been cast or spoiled /// and exports encrypted ballots to a file /// </summary> /// <param name="electionGuardConfig"></param> /// <param name="encryptedBallotMessages"></param> /// <param name="castBallotIds"></param> /// <param name="spoiledBallotIds"></param> /// <param name="exportPath">optional, if exclused uses current working directory</param> /// <param name="exportFilenamePrefix">optional, if excluded uses default value</param> /// <returns>The filename created containing the encrypted ballots and their state (registered/cast/spoiled)</returns> public static RecordBallotsResult RecordBallots(ElectionGuardConfig electionGuardConfig, ICollection <string> castBallotIds, ICollection <string> spoiledBallotIds, ICollection <string> externalIdentifiers, ICollection <string> encryptedBallotMessages, string exportPath = "./", string exportFilenamePrefix = "") { var serializedBytesWithGcHandles = encryptedBallotMessages .Select(ByteSerializer.ConvertFromBase64String); var bytesWithGcHandles = serializedBytesWithGcHandles.ToList(); var ballotsArray = bytesWithGcHandles.Select(bytesWithGcHandle => bytesWithGcHandle.SerializedBytes).ToArray(); var castArray = castBallotIds.Select(id => id).ToArray(); var spoiledArray = spoiledBallotIds.Select(id => id).ToArray(); var identifiersArray = externalIdentifiers.Select(id => id).ToArray(); var castTrackerPtrs = new IntPtr[castBallotIds.Count]; var spoiledTrackerPtrs = new IntPtr[spoiledBallotIds.Count]; var outputFilenamePtr = new IntPtr(); try { var success = API.RecordBallots((uint)electionGuardConfig.NumberOfSelections, (uint)castBallotIds.Count, (uint)spoiledBallotIds.Count, (ulong)encryptedBallotMessages.Count, castArray, spoiledArray, identifiersArray, ballotsArray, exportPath, exportFilenamePrefix, out outputFilenamePtr, castTrackerPtrs, spoiledTrackerPtrs); if (!success) { throw new Exception("ElectionGuardAPI RecordBallots failed"); } var result = new RecordBallotsResult() { EncryptedBallotsFilename = Marshal.PtrToStringAnsi(outputFilenamePtr), CastedBallotTrackers = castTrackerPtrs.Select(tracker => Marshal.PtrToStringAnsi(tracker)).ToList(), SpoiledBallotTrackers = spoiledTrackerPtrs.Select(tracker => Marshal.PtrToStringAnsi(tracker)).ToList(), }; return(result); } finally { // Free unmanaged memory API.FreeRecordBallots(outputFilenamePtr, (uint)castBallotIds.Count, (uint)spoiledBallotIds.Count, castTrackerPtrs, spoiledTrackerPtrs); foreach (var bytes in bytesWithGcHandles) { bytes.Handle.Free(); } } }