コード例 #1
0
        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));
            }
        }
コード例 #2
0
        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;
        }
コード例 #3
0
 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);
     }
 }
コード例 #4
0
        /// <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();
                }
            }
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        /// <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();
            }
        }
コード例 #7
0
        /// <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);
            }
        }
コード例 #8
0
        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";
        }
コード例 #9
0
        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");
        }
コード例 #10
0
        /// <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();
                }
            }
        }