public void Step04_TallyVotes() { // assume we have the equivalent number of trustees present to the threshold number required var numberOfTrusteesPresent = _electionGuardConfig.Threshold; var result = ElectionGuardApi.TallyVotes( _electionGuardConfig, _trusteeKeys.Values, numberOfTrusteesPresent, _ballotsFilename, _exportFolder, _tallyPrefix ); Assert.IsNotNull(result.EncryptedTallyFilename); Assert.AreEqual(_electionGuardConfig.NumberOfSelections, result.TallyResults.Count); }
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"); }