diff --git a/egklib/build.gradle.kts b/egklib/build.gradle.kts index b0ef91ff..ce6cdb27 100644 --- a/egklib/build.gradle.kts +++ b/egklib/build.gradle.kts @@ -13,8 +13,14 @@ version = "2.0.0-SNAPSHOT" kotlin { jvm { - compilations.all { kotlinOptions.jvmTarget = "1.8" } - // withJava() + compilations.all { + kotlinOptions.jvmTarget = "1.8" + kotlinOptions.freeCompilerArgs = listOf( + "-Xexpect-actual-classes", + "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi,kotlinx.serialization.ExperimentalSerializationApi" + ) + } + testRuns["test"].executionTask .configure { useJUnitPlatform() diff --git a/egklib/src/commonMain/kotlin/electionguard/encrypt/AddEncryptedBallot.kt b/egklib/src/commonMain/kotlin/electionguard/encrypt/AddEncryptedBallot.kt index eca12afc..af9aac13 100644 --- a/egklib/src/commonMain/kotlin/electionguard/encrypt/AddEncryptedBallot.kt +++ b/egklib/src/commonMain/kotlin/electionguard/encrypt/AddEncryptedBallot.kt @@ -21,7 +21,7 @@ private val logger = KotlinLogging.logger("AddEncryptedBallot") /** Encrypt a ballot and add to election record. Single threaded only. */ class AddEncryptedBallot( val group: GroupContext, - val manifest: Manifest, + val manifest: Manifest, // should already be validated val electionInit: ElectionInitialized, val deviceName: String, val outputDir: String, // write ballots to outputDir/encrypted_ballots/deviceName, must not have multiple writers to same directory @@ -46,23 +46,17 @@ class AddEncryptedBallot( val publisher = makePublisher(outputDir, false, isJson) val sink: EncryptedBallotSinkIF = publisher.encryptedBallotSink(deviceName) - val ballotIds = mutableListOf() - val pending = mutableMapOf() // key = ccode.toHex() val configBaux0: ByteArray = electionInit.config.configBaux0 val configChaining: Boolean = electionInit.config.chainConfirmationCodes val baux0: ByteArray + private val ballotIds = mutableListOf() + private val pending = mutableMapOf() // key = ccode.toHex() private var lastConfirmationCode: UInt256 = UInt256.ZERO private var first = true private var closed = false init { - val manifestValidator = ManifestInputValidation(manifest) - val errors = manifestValidator.validate() - if (errors.hasErrors()) { - throw RuntimeException("ManifestInputValidation error $errors") - } - val consumer = makeConsumer(group, outputDir, isJson) val chainResult = consumer.readEncryptedBallotChain(deviceName) if (chainResult is Ok) { @@ -106,7 +100,7 @@ class AddEncryptedBallot( this.lastConfirmationCode = ciphertextBallot.confirmationCode // hmmm you could write CiphertextBallot to a log, in case of crash - pending[ciphertextBallot.confirmationCode.toHex()] = ciphertextBallot + pending[ciphertextBallot.confirmationCode] = ciphertextBallot return Ok(ciphertextBallot) } @@ -122,13 +116,13 @@ class AddEncryptedBallot( submit(eballot.confirmationCode, EncryptedBallot.BallotState.CAST) } else { // remove from pending - pending.remove(eballot.confirmationCode.toHex()) + pending.remove(eballot.confirmationCode) } return Ok(eballot) } fun submit(ccode: UInt256, state: EncryptedBallot.BallotState): Result { - val cballot = pending.remove(ccode.toHex()) + val cballot = pending.remove(ccode) if (cballot == null) { logger.error { "Tried to submit state=$state unknown ballot ccode=$ccode" } return Err("Tried to submit state=$state unknown ballot ccode=$ccode") @@ -152,7 +146,7 @@ class AddEncryptedBallot( } fun challengeAndDecrypt(ccode: UInt256): Result { - val cballot = pending.remove(ccode.toHex()) + val cballot = pending.remove(ccode) if (cballot == null) { logger.error { "Tried to submit unknown ballot ccode=$ccode" } return Err("Tried to submit unknown ballot ccode=$ccode") @@ -177,11 +171,9 @@ class AddEncryptedBallot( // write out pending encryptedBallots, and chain (if chainCodes is true) fun sync() { if (pending.isNotEmpty()) { - val keys = pending.keys.toList() - keys.forEach { - logger.error { "pending Ciphertext ballot ${it} was not submitted" } - val ba = it.fromHex() ?: throw RuntimeException("illegal confirmation code") - submit(UInt256(ba), EncryptedBallot.BallotState.UNKNOWN) + pending.keys.forEach { + logger.error { "pending Ciphertext ballot ${it} was not submitted, marking 'UNKNOWN'" } + submit(it, EncryptedBallot.BallotState.UNKNOWN) } } val closing = diff --git a/egklib/src/commonMain/kotlin/electionguard/input/ManifestInputValidation.kt b/egklib/src/commonMain/kotlin/electionguard/input/ManifestInputValidation.kt index b1c5877f..20dd02f5 100644 --- a/egklib/src/commonMain/kotlin/electionguard/input/ManifestInputValidation.kt +++ b/egklib/src/commonMain/kotlin/electionguard/input/ManifestInputValidation.kt @@ -10,8 +10,8 @@ import io.github.oshai.kotlinlogging.KotlinLogging private val logger = KotlinLogging.logger("ManifestInputValidation") /** - * Validate an election manifest, give human readable error information. - * See [ElectionGuard Input Validation](https://github.com/danwallach/electionguard-kotlin-multiplatform/blob/main/docs/InputValidation.md) + * Validate an election manifest, return human readable error information. + * See [Input Validation](https://github.com/votingworks/electionguard-kotlin-multiplatform/blob/main/docs/InputValidation.md) */ class ManifestInputValidation(val manifest: Manifest) { private val gpUnits: Set = manifest.geopoliticalUnits.map { it.geopoliticalUnitId }.toSet() diff --git a/egklib/src/commonMain/kotlin/electionguard/preencrypt/PreBallot.kt b/egklib/src/commonMain/kotlin/electionguard/preencrypt/PreBallot.kt index 798b41b1..1bf5b68a 100644 --- a/egklib/src/commonMain/kotlin/electionguard/preencrypt/PreBallot.kt +++ b/egklib/src/commonMain/kotlin/electionguard/preencrypt/PreBallot.kt @@ -1,6 +1,7 @@ package electionguard.preencrypt import electionguard.core.* +import electionguard.util.ErrorMessages /** * Intermediate working ballot to transform pre encrypted ballot to an Encrypted ballot. @@ -31,7 +32,7 @@ internal data class PreContest( val votedFor: List // nselections, in order by sequence_order ) { init { - require(votedFor.size == allSelectionHashes.size - selectedVectors.size) + require(votedFor.size == allSelectionHashes.size - selectedVectors.size) // TODO } fun selectedCodes() : List = selectedVectors.map { it.shortCode } fun nselections() = votedFor.size @@ -52,37 +53,52 @@ internal data class PreSelectionVector( } } -internal fun MarkedPreEncryptedBallot.makePreBallot(preeBallot : PreEncryptedBallot): PreBallot { +internal fun MarkedPreEncryptedBallot.makePreBallot(preeBallot : PreEncryptedBallot, errs : ErrorMessages): PreBallot? { val contests = mutableListOf() preeBallot.contests.forEach { preeContest -> val markedContest = this.contests.find { it.contestId == preeContest.contestId } - ?: throw IllegalArgumentException("Cant find ${preeContest.contestId}") + if (markedContest == null) { + errs.add("Cant find PreContest ${preeContest.contestId}") + return null + } // find the selected selections by their shortCode - val selected = mutableListOf() + val preSelections = mutableListOf() markedContest.selectedCodes.map { selectedShortCode -> - val selection = preeContest.selections.find { it.shortCode == selectedShortCode } ?: - throw RuntimeException() - selected.add(selection) + val selection = preeContest.selections.find { it.shortCode == selectedShortCode } + if (selection == null) { + errs.add("Cant find PreEncryptedSelection $selectedShortCode") + } else { + preSelections.add(selection) + } } + if (errs.hasErrors()) return null val nselections = preeContest.selections.size - preeContest.votesAllowed val votedFor = mutableListOf() repeat(nselections) { idx -> val selection = preeContest.selections[idx] - votedFor.add( selected.find { it.selectionId == selection.selectionId } != null) + votedFor.add( preSelections.find { it.selectionId == selection.selectionId } != null) } - // add null vector on undervote - val votesMissing = preeContest.votesAllowed - selected.size + // add null vectors on undervote + val votesMissing = preeContest.votesAllowed - preSelections.size repeat (votesMissing) { - val nullVector = findNullVectorNotSelected(preeContest.selections, selected) - selected.add(nullVector) + val nullVector = findNullVectorNotSelected(preeContest.selections, preSelections) + if (nullVector == null) { + errs.add("Cant find NullVector idx=$it") + } else { + preSelections.add(nullVector) + } + } + if (errs.hasErrors()) return null + if (preSelections.size != preeContest.votesAllowed) { + errs.add("preSelections.size ${preSelections.size } != preeContest.votesAllowed ${preeContest.votesAllowed}") + return null } - require (selected.size == preeContest.votesAllowed) // The selectionVectors are sorted numerically by selectionHash, so cant be associated with a selection - val sortedSelectedVectors = selected.sortedBy { it.selectionHash } + val sortedSelectedVectors = preSelections.sortedBy { it.selectionHash } val sortedRecordedVectors = sortedSelectedVectors.map { preeSelection -> PreSelectionVector(preeSelection.selectionId, preeSelection.selectionHash, preeSelection.shortCode, preeSelection.selectionVector, preeSelection.selectionNonces) @@ -108,7 +124,7 @@ internal fun MarkedPreEncryptedBallot.makePreBallot(preeBallot : PreEncryptedBal } // find a null vector not already in selections -private fun findNullVectorNotSelected(allSelections : List, selections : List) : PreEncryptedSelection { +private fun findNullVectorNotSelected(allSelections : List, selections : List) : PreEncryptedSelection? { allSelections.forEach { if (it.selectionId.startsWith("null")) { if (null == selections.find{ have -> have.selectionId == it.selectionId }) { @@ -116,5 +132,5 @@ private fun findNullVectorNotSelected(allSelections : List { + internal fun MarkedPreEncryptedBallot.record( + ballotNonce: UInt256, + errs: ErrorMessages, + codeBaux: ByteArray = ByteArray(0), + ): Pair? { + // uses the primary nonce ξ to regenerate all of the encryptions on the ballot val preEncryptedBallot = preEncryptor.preencrypt(this.ballotId, this.ballotStyleId, ballotNonce) - val preBallot = this.makePreBallot(preEncryptedBallot) - val timestamp = (getSystemTimeInMillis() / 1000) // secs since epoch + val preBallot = this.makePreBallot(preEncryptedBallot, errs) + if (errs.hasErrors()) return null // match against the choices in MarkedPreEncryptedBallot - val preContests = preBallot.contests.associateBy { it.contestId } + val preContests = preBallot!!.contests.associateBy { it.contestId } - val contests = mutableListOf() - for (preeContest in preEncryptedBallot.contests) { - val preContest = preContests[preeContest.contestId]!! - val cipherContest = preContest.makeContest(ballotNonce, preeContest) - contests.add( cipherContest) + val contests = preEncryptedBallot.contests.map { + val preContest = preContests[it.contestId] ?: errs.addNull("Cant find contest ${it.contestId}") as PreContest? + preContest?.makeContest(ballotNonce, it, errs.nested("PreContest ${it.contestId}")) } + if (errs.hasErrors()) return null val ciphertextBallot = CiphertextBallot( ballotId, ballotStyleId, votingDevice, - timestamp, + (getSystemTimeInMillis() / 1000), // secs since epoch codeBaux, preEncryptedBallot.confirmationCode, extendedBaseHash, - contests, + contests.filterNotNull(), ballotNonce, true, ) @@ -71,7 +76,7 @@ class Recorder( return Pair(recordPreBallot, ciphertextBallot) } - private fun PreContest.makeContest(ballotNonce: UInt256, preeContest: PreEncryptedContest): CiphertextBallot.Contest { + private fun PreContest.makeContest(ballotNonce: UInt256, preeContest: PreEncryptedContest, errs: ErrorMessages): CiphertextBallot.Contest { // Find the pre-encryptions corresponding to the selections made by the voter and, using // the encryption nonces derived from the primary nonce, generate proofs of ballot correctness as in @@ -84,7 +89,7 @@ class Recorder( // to create suitable nonces for this combined pre-encryption vector. These derived nonces will be // necessary to form zero-knowledge proofs that the associated encryption vectors are well-formed. - val selections = this.makeSelections(preeContest) + val selections = this.makeSelections(preeContest, errs) val texts: List = selections.map { it.ciphertext } val ciphertextAccumulation: ElGamalCiphertext = texts.encryptedSum()?: 0.encrypt(publicKeyEG) @@ -123,11 +128,13 @@ class Recorder( contestHash, selections, proof, contestDataEncrypted) } - private fun PreContest.makeSelections(preeContest: PreEncryptedContest): List { + private fun PreContest.makeSelections(preeContest: PreEncryptedContest, errs: ErrorMessages): List { val nselections = preeContest.selections.size - preeContest.votesAllowed val nvectors = this.selectedVectors.size - require (nvectors == preeContest.votesAllowed) + if (nvectors != preeContest.votesAllowed) { + errs.add("nvectors $nvectors != ${preeContest.votesAllowed} preeContest.votesAllowed") + } // homomorphically combine the selected pre-encryption vectors by component wise multiplication val combinedEncryption = mutableListOf() @@ -145,10 +152,15 @@ class Recorder( } if (preeContest.votesAllowed == 1) { - require(combinedEncryption.size == nselections) + if (nselections != combinedEncryption.size) { + errs.add("nselections $nselections != ${combinedEncryption.size} combinedEncryption.size") + } + val selectedEncryption = this.selectedVectors[0].encryptions repeat(nselections) { idx -> - require(combinedEncryption[idx] == selectedEncryption[idx]) + if (combinedEncryption[idx] != selectedEncryption[idx]) { + errs.add("$idx combinedEncryption != selectedEncryption") + } } } diff --git a/egklib/src/commonMain/kotlin/electionguard/publish/ElectionRecordFactory.kt b/egklib/src/commonMain/kotlin/electionguard/publish/ElectionRecordFactory.kt index 257176cf..734bfa4e 100644 --- a/egklib/src/commonMain/kotlin/electionguard/publish/ElectionRecordFactory.kt +++ b/egklib/src/commonMain/kotlin/electionguard/publish/ElectionRecordFactory.kt @@ -7,6 +7,7 @@ import electionguard.ballot.* import electionguard.core.ElementModP import electionguard.core.GroupContext import electionguard.core.UInt256 +import electionguard.input.ManifestInputValidation import electionguard.util.ErrorMessages import io.github.oshai.kotlinlogging.KotlinLogging @@ -18,6 +19,7 @@ fun readElectionRecord(group : GroupContext, topDir: String) : ElectionRecord { } // there must at least be a config record +// this throws Exceptions fun readElectionRecord(consumer: Consumer) : ElectionRecord { var decryptionResult : DecryptionResult? = null var tallyResult : TallyResult? = null @@ -33,10 +35,10 @@ fun readElectionRecord(consumer: Consumer) : ElectionRecord { config = init.config stage = ElectionRecord.Stage.DECRYPTED } else { - val err : ErrorMessages = readDecryptionResult.unwrapError() - if (!err.contains("file does not exist")) { - logger.error{ err.toString() } - throw RuntimeException(err.toString()) + val errs1 : ErrorMessages = readDecryptionResult.unwrapError() + if (!errs1.contains("file does not exist")) { + logger.error{ errs1.toString() } + throw RuntimeException(errs1.toString()) } val readTallyResult = consumer.readTallyResult() if (readTallyResult is Ok) { @@ -45,10 +47,10 @@ fun readElectionRecord(consumer: Consumer) : ElectionRecord { config = init.config stage = ElectionRecord.Stage.TALLIED } else { - val err : ErrorMessages = readTallyResult.unwrapError() - if (!err.contains("file does not exist")) { - logger.error{ err.toString() } - throw RuntimeException(err.toString()) + val errs2 : ErrorMessages = readTallyResult.unwrapError() + if (!errs2.contains("file does not exist")) { + logger.error{ errs2.toString() } + throw RuntimeException(errs2.toString()) } val readInitResult = consumer.readElectionInitialized() if (readInitResult is Ok) { @@ -56,28 +58,31 @@ fun readElectionRecord(consumer: Consumer) : ElectionRecord { config = init.config stage = ElectionRecord.Stage.INIT } else { - val err : ErrorMessages = readInitResult.unwrapError() - if (!err.contains("file does not exist")) { - logger.error{ err.toString() } - throw RuntimeException(err.toString()) + val errs3 : ErrorMessages = readInitResult.unwrapError() + if (!errs3.contains("file does not exist")) { + logger.error{ errs3.toString() } + throw RuntimeException(errs3.toString()) } val readConfigResult = consumer.readElectionConfig() if (readConfigResult is Ok) { config = readConfigResult.value stage = ElectionRecord.Stage.CONFIG } else { + // Always has to be a config throw RuntimeException(readConfigResult.unwrapError().toString()) } } } } - // Always has to be a config and the original manifest bytes, from which the manifest is parsed - require(config != null) { "no election config file found in ${consumer.topdir()}" } require(config.manifestHash == manifestHash(config.parameterBaseHash, config.manifestBytes)) { "config.manifestHash fails to match ${consumer.topdir()}" } val manifest : Manifest = consumer.makeManifest(config.manifestBytes) + val errors = ManifestInputValidation(manifest).validate() + if (ManifestInputValidation(manifest).validate().hasErrors()) { + throw RuntimeException("ManifestInputValidation error $errors") + } if (stage == ElectionRecord.Stage.INIT && consumer.hasEncryptedBallots()) { stage = ElectionRecord.Stage.ENCRYPTED diff --git a/egklib/src/commonTest/kotlin/electionguard/json2/ElectionConfigTest.kt b/egklib/src/commonTest/kotlin/electionguard/json2/ElectionConfigTest.kt index 9bcac8d1..4e6ed89a 100644 --- a/egklib/src/commonTest/kotlin/electionguard/json2/ElectionConfigTest.kt +++ b/egklib/src/commonTest/kotlin/electionguard/json2/ElectionConfigTest.kt @@ -1,16 +1,11 @@ package electionguard.json2 -import com.github.michaelbull.result.Err -import com.github.michaelbull.result.Ok -import com.github.michaelbull.result.getError -import com.github.michaelbull.result.unwrap import electionguard.ballot.ElectionConfig import electionguard.ballot.ElectionConstants import electionguard.core.Base16.fromHex import electionguard.core.UInt256 import electionguard.core.productionGroup import electionguard.util.ErrorMessages -import io.kotest.assertions.throwables.shouldThrowUnitWithMessage import kotlin.test.* class ElectionConfigTest { diff --git a/egklib/src/commonTest/kotlin/electionguard/preencrypt/PreEncryptorOutputTest.kt b/egklib/src/commonTest/kotlin/electionguard/preencrypt/PreEncryptorOutputTest.kt index 6b27336d..a6b93ba8 100644 --- a/egklib/src/commonTest/kotlin/electionguard/preencrypt/PreEncryptorOutputTest.kt +++ b/egklib/src/commonTest/kotlin/electionguard/preencrypt/PreEncryptorOutputTest.kt @@ -76,9 +76,15 @@ internal class PreEncryptorOutputTest { // record val recorder = Recorder(group, manifest, publicKey, extendedBaseHash, "device", ::sigma) - val (recordedBallot, ciphertextBallot) = with(recorder) { - markedBallot.record(primaryNonce) + val errs = ErrorMessages("MarkedBallot ${markedBallot.ballotId}") + val pair = with(recorder) { + markedBallot.record(primaryNonce, errs) } + if (errs.hasErrors()) { + println(errs) + return + } + val (recordedBallot, ciphertextBallot) = pair!! // show record results if (show) { diff --git a/egklib/src/commonTest/kotlin/electionguard/preencrypt/PreEncryptorTest.kt b/egklib/src/commonTest/kotlin/electionguard/preencrypt/PreEncryptorTest.kt index 63d94403..e6559365 100644 --- a/egklib/src/commonTest/kotlin/electionguard/preencrypt/PreEncryptorTest.kt +++ b/egklib/src/commonTest/kotlin/electionguard/preencrypt/PreEncryptorTest.kt @@ -24,6 +24,7 @@ import kotlin.math.min import kotlin.random.Random import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertTrue private val random = Random @@ -73,9 +74,11 @@ internal class PreEncryptorTest { val recorder = Recorder(group, manifest, electionInit.jointPublicKey, electionInit.extendedBaseHash, "device", ::sigma) + val errs = ErrorMessages("MarkedBallot ${mballot.ballotId}") with(recorder) { - mballot.record(primaryNonce) + mballot.record(primaryNonce, errs) } + assertFalse(errs.hasErrors()) } } @@ -206,9 +209,12 @@ internal fun runComplete( // record val recorder = Recorder(group, manifest, publicKey, qbar, "device", ::sigma) - val (recordedBallot, ciphertextBallot) = with(recorder) { - markedBallot.record(primaryNonce) + val errs = ErrorMessages("MarkedBallot ${markedBallot.ballotId}") + val pair = with(recorder) { + markedBallot.record(primaryNonce, errs) } + assertFalse(errs.hasErrors()) + val (recordedBallot, ciphertextBallot) = pair!! // show record results if (show) { diff --git a/egklib/src/commonTest/kotlin/electionguard/workflow/TestNumGuardians.kt b/egklib/src/commonTest/kotlin/electionguard/workflow/TestNumGuardians.kt index 57c20620..b3533d50 100644 --- a/egklib/src/commonTest/kotlin/electionguard/workflow/TestNumGuardians.kt +++ b/egklib/src/commonTest/kotlin/electionguard/workflow/TestNumGuardians.kt @@ -70,7 +70,7 @@ class TestNumGuardians { ) // key ceremony - val (manifest, init) = runFakeKeyCeremony(group, workingDir, workingDir, trusteeDir, nguardians, quorum, false) + val (_, init) = runFakeKeyCeremony(group, workingDir, workingDir, trusteeDir, nguardians, quorum, false) println("FakeKeyCeremony created ElectionInitialized, guardians = $present") println("----------- after keyCeremony ${group.showAndClearCountPowP()}") diff --git a/egklib/src/commonTest/kotlin/electionguard/workflow/TestPepWorkflow.kt b/egklib/src/commonTest/kotlin/electionguard/workflow/TestPepWorkflow.kt index c821ccdb..ed13b8c0 100644 --- a/egklib/src/commonTest/kotlin/electionguard/workflow/TestPepWorkflow.kt +++ b/egklib/src/commonTest/kotlin/electionguard/workflow/TestPepWorkflow.kt @@ -58,7 +58,7 @@ class TestPepWorkflow { ) // key ceremony - val (manifest, init) = runFakeKeyCeremony(group, workingDir, workingDir, trusteeDir, nguardians, quorum, false) + val (_, init) = runFakeKeyCeremony(group, workingDir, workingDir, trusteeDir, nguardians, quorum, false) // encrypt group.showAndClearCountPowP() diff --git a/egklib/src/jvmMain/kotlin/electionguard/cli/RunExampleEncryption.kt b/egklib/src/jvmMain/kotlin/electionguard/cli/RunExampleEncryption.kt index 6ec2f390..4a431d86 100644 --- a/egklib/src/jvmMain/kotlin/electionguard/cli/RunExampleEncryption.kt +++ b/egklib/src/jvmMain/kotlin/electionguard/cli/RunExampleEncryption.kt @@ -6,6 +6,7 @@ import com.github.michaelbull.result.getError import com.github.michaelbull.result.unwrap import electionguard.core.* import electionguard.encrypt.AddEncryptedBallot +import electionguard.input.ManifestInputValidation import electionguard.input.RandomBallotProvider import electionguard.publish.makeConsumer import electionguard.publish.makePublisher @@ -31,6 +32,10 @@ class RunExampleEncryption { } val electionInit = initResult.unwrap() val manifest = consumerIn.makeManifest(electionInit.config.manifestBytes) + val errors = ManifestInputValidation(manifest).validate() + if (ManifestInputValidation(manifest).validate().hasErrors()) { + throw RuntimeException("ManifestInputValidation error $errors") + } val publisher = makePublisher(outputDir, true, consumerIn.isJson()) publisher.writeElectionInitialized(electionInit) diff --git a/egklib/src/jvmTest/kotlin/electionguard/core/SimpleBallotBenchmark.kt b/egklib/src/jvmTest/kotlin/electionguard/core/SimpleBallotBenchmark.kt index fbb18961..c9178904 100644 --- a/egklib/src/jvmTest/kotlin/electionguard/core/SimpleBallotBenchmark.kt +++ b/egklib/src/jvmTest/kotlin/electionguard/core/SimpleBallotBenchmark.kt @@ -16,7 +16,7 @@ class SimplePlaintextBallot(val selections: List) class SimpleEncryptedBallot(val selectionsAndProofs: List>, val sumProof: ChaumPedersenRangeProofKnownNonce) -fun SimplePlaintextBallot.encrypt(context: GroupContext, keypair: ElGamalKeypair, seed: ElementModQ, limit : Int = 1): SimpleEncryptedBallot { +fun SimplePlaintextBallot.encrypt(keypair: ElGamalKeypair, seed: ElementModQ, limit : Int = 1): SimpleEncryptedBallot { val encryptionNonces = Nonces(seed, "encryption") val proofNonces = Nonces(seed, "proof") val plaintextWithNonce = selections.mapIndexed { i, s -> Pair(s, encryptionNonces[i]) } @@ -59,9 +59,9 @@ fun main() { println("Ballot encryption simulation benchmark, JDK: ${System.getProperty("java.version")}") runBlocking { - ProductionMode.values() + ProductionMode.entries .forEach { mode -> - PowRadixOption.values().filter { it != PowRadixOption.EXTREME_MEMORY_USE } + PowRadixOption.entries.filter { it != PowRadixOption.EXTREME_MEMORY_USE } .forEach { powRadixOption -> println("=======================================================") println("Initializing benchmark for $powRadixOption, $mode") @@ -75,9 +75,8 @@ fun main() { 1.encrypt(keypair, nonces[0]).decrypt(keypair) println("Running!") - var results: List val encryptionTimeMs = measureTimeMillis { - results = ProgressBar + ProgressBar .wrap( (0 until numBallots).asIterable().toList(), ProgressBarBuilder() @@ -89,7 +88,7 @@ fun main() { .setMaxRenderedLength(100) .showSpeed() ) - .map { ballots[it].encrypt(context, keypair, nonces[it]) } + .map { ballots[it].encrypt(keypair, nonces[it]) } } val encryptionTime = encryptionTimeMs / 1000.0 diff --git a/egklib/src/jvmTest/kotlin/electionguard/json/PrimesTest.kt b/egklib/src/jvmTest/kotlin/electionguard/json/PrimesTest.kt index b5b0e2ca..fe09b1d3 100644 --- a/egklib/src/jvmTest/kotlin/electionguard/json/PrimesTest.kt +++ b/egklib/src/jvmTest/kotlin/electionguard/json/PrimesTest.kt @@ -40,7 +40,7 @@ class PrimesTest { val rnn = Primes4096.residualNotNormalized println("rnn in base64 = ${rnn.toBase64()}") - val rnnelem = ProductionElementModP(rnn.toBigInteger(), group as ProductionGroupContext) + val rnnelem = ProductionElementModP(rnn.toBigInteger(), group) println("rnn == r as bigInt ${r.toBigInteger() == rnn.toBigInteger()}") println("rnn == r as ElementModP ${relem == rnnelem}") @@ -49,7 +49,7 @@ class PrimesTest { val q = Primes4096.smallPrimeBytes.toBigInteger() val cr = (p - BigInteger.ONE) / q println("computed r in base64 = ${cr.toByteArray().toBase64()}") - val crelem = ProductionElementModP(cr, group as ProductionGroupContext) + val crelem = ProductionElementModP(cr, group) println("cr == r as bigInt ${r.toBigInteger() == cr}") println("cr == r as ElementModP ${relem == crelem}") @@ -63,7 +63,7 @@ class PrimesTest { val ba2 = ba.normalize(nbytes) val rsb = ba2.toBigInteger() println("rs == r as bigInt ${r.toBigInteger() == rsb}") - val rsbelem = ProductionElementModP(rsb, group as ProductionGroupContext) + val rsbelem = ProductionElementModP(rsb, group) println("rs == r as ElementModP ${relem == rsbelem}") assertEquals(relem, rsbelem) } diff --git a/egklib/src/jvmTest/kotlin/electionguard/testvectors/BallotEncryptionTestVector.kt b/egklib/src/jvmTest/kotlin/electionguard/testvectors/BallotEncryptionTestVector.kt index 2ff9efab..a8f89e9c 100644 --- a/egklib/src/jvmTest/kotlin/electionguard/testvectors/BallotEncryptionTestVector.kt +++ b/egklib/src/jvmTest/kotlin/electionguard/testvectors/BallotEncryptionTestVector.kt @@ -196,7 +196,6 @@ class BallotEncryptionTestVector { val plainContest: PlaintextContestJsonV = pair.first val expectContest: EncryptedContestJson = pair.second - val limit = expectContest.expected_proof.proofs.size val randomUj = expectContest.expected_proof.proofs.map { it.u_nonce.import(group) ?: throw IllegalArgumentException("readBallotEncryptionTestVector malformed u_nonce") } val randomCj = expectContest.expected_proof.proofs.map { it.c_nonce.import(group) ?: throw IllegalArgumentException("readBallotEncryptionTestVector malformed c_nonce") } @@ -221,20 +220,19 @@ class BallotEncryptionTestVector { val plainSelection: PlaintextSelectionJsonV = pair2.first val expectSelection: EncryptedSelectionJson = pair2.second - val limit = expectSelection.expected_proof.proofs.size - val randomUj = expectSelection.expected_proof.proofs.map { it.u_nonce.import(group) ?: throw IllegalArgumentException("readBallotEncryptionTestVector malformed u_nonce") } - val randomCj = expectSelection.expected_proof.proofs.map { it.c_nonce.import(group) ?: throw IllegalArgumentException("readBallotEncryptionTestVector malformed u_nonce") } + val randomUjSel = expectSelection.expected_proof.proofs.map { it.u_nonce.import(group) ?: throw IllegalArgumentException("readBallotEncryptionTestVector malformed u_nonce") } + val randomCjSel = expectSelection.expected_proof.proofs.map { it.c_nonce.import(group) ?: throw IllegalArgumentException("readBallotEncryptionTestVector malformed u_nonce") } - val proofWithNonces: ChaumPedersenRangeProofKnownNonce = actualSelection.ciphertext.makeChaumPedersenWithNonces( + val proofWithNoncesSel: ChaumPedersenRangeProofKnownNonce = actualSelection.ciphertext.makeChaumPedersenWithNonces( plainSelection.vote, actualSelection.selectionNonce, // encryption nonce ξ for which (α, β) is an encryption of ℓ. publicKey, extendedBaseHash, - randomUj, - randomCj + randomUjSel, + randomCjSel ) - assertEquals(expectSelection.expected_proof.import(group), proofWithNonces) + assertEquals(expectSelection.expected_proof.import(group), proofWithNoncesSel) } } diff --git a/egklib/src/jvmTest/kotlin/electionguard/testvectors/PreEncryptionRecordedTestVector.kt b/egklib/src/jvmTest/kotlin/electionguard/testvectors/PreEncryptionRecordedTestVector.kt index 28c9643d..f937f9c1 100644 --- a/egklib/src/jvmTest/kotlin/electionguard/testvectors/PreEncryptionRecordedTestVector.kt +++ b/egklib/src/jvmTest/kotlin/electionguard/testvectors/PreEncryptionRecordedTestVector.kt @@ -27,6 +27,7 @@ import kotlin.io.use import kotlin.random.Random import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFalse /** Generate the election record information from a Pre-encrypted Ballot that has been voted. */ class PreEncryptionRecordedTestVector { @@ -83,9 +84,12 @@ class PreEncryptionRecordedTestVector { // record val recorder = Recorder(group, manifest, publicKey, extendedBaseHash, "device", ::sigma) - val (recordedBallot, ciphertextBallot) = with(recorder) { - markedBallot.record(primaryNonce) + val errs = ErrorMessages("MarkedBallot ${markedBallot.ballotId}") + val pair = with(recorder) { + markedBallot.record(primaryNonce, errs) } + assertFalse(errs.hasErrors()) + val (recordedBallot, ciphertextBallot) = pair!! // roundtrip through the proto, combines the recordedBallot val encryptedBallot = ciphertextBallot.cast() @@ -131,9 +135,12 @@ class PreEncryptionRecordedTestVector { // record val recorder = Recorder(group, manifest, publicKey, extendedBaseHash, "device", ::sigma) - val (recordedBallot, ciphertextBallot) = with(recorder) { - markedBallot.record(primaryNonce) + val errs = ErrorMessages("MarkedBallot ${markedBallot.ballotId}") + val pair = with(recorder) { + markedBallot.record(primaryNonce, errs) } + assertFalse(errs.hasErrors()) + val (recordedBallot, ciphertextBallot) = pair!! // roundtrip through the proto, combines the recordedBallot val encryptedBallot = ciphertextBallot.cast()