Skip to content

Commit

Permalink
Merge pull request #394 from JohnLCaron/verifier
Browse files Browse the repository at this point in the history
Cleanup Verifier.
  • Loading branch information
JohnLCaron authored Oct 10, 2023
2 parents 7e7c70c + 0b22318 commit 8b66346
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 25 deletions.
20 changes: 20 additions & 0 deletions dependencies.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
org.jetbrains.kotlinx:kotlinx-cli:0.3.6
org.jetbrains.kotlinx:kotlinx-datetime:0.4.1
org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4
org.jetbrains.kotlinx:atomicfu:0.20.2
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10
org.jetbrains:annotations:13.0

com.michael-bull.kotlin-result:kotlin-result:1.1.18

io.github.microutils:kotlin-logging:3.0.5
org.slf4j:slf4j-api:2.0.3

pro.streem.pbandk:pbandk-runtime:0.14.2

+--- ch.qos.logback:logback-classic:1.4.11
| +--- ch.qos.logback:logback-core:1.4.11
| \--- org.slf4j:slf4j-api:2.0.7


10 changes: 5 additions & 5 deletions docs/CommandLineInterface.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ Example:
/usr/lib/jvm/jdk-19/bin/java \
-classpath egklib/egklib-all.jar \
electionguard.cli.RunVerifier \
-in testOut/cliWorkflow/electionRecord \
-in testOut/cliWorkflow/electionRecord
````

## Encrypt plaintext files again for Pep
Expand Down Expand Up @@ -345,7 +345,7 @@ Example:
-in egklib/src/commonTest/data/workflow/allAvailableJson \
-trustees egklib/src/commonTest/data/workflow/allAvailableJson/private_data/trustees \
-scanned testOut/pep/testPepAllJson/encrypted_ballots/scanned \
-out testOut/pep/testPepAllJson \
-out testOut/pep/testPepAllJson/pepBallots \
-nthreads 25
````

Expand All @@ -355,7 +355,7 @@ Example:
Usage: RunVerifyPep options_list
Options:
--inputDir, -in -> Directory containing input election record (always required) { String }
--pepDirectory, -pep -> Directory containing PEP output (always required) { String }
--pepBallotDir, -pep -> Directory containing PEP output (always required) { String }
--nthreads, -nthreads [11] -> Number of parallel threads to use { Int }
--help, -h -> Usage info
````
Expand All @@ -366,6 +366,6 @@ Example:
/usr/lib/jvm/jdk-19/bin/java \
-classpath egklib/egklib-all.jar \
electionguard.cli.RunVerifyPep \
-in egklib/src/commonTest/data/workflow/allAvailableJson \
-pep testOut/pep/testPepAllJson
--inputDir egklib/src/commonTest/data/workflow/allAvailableJson \
--pepBallotDir testOut/pep/testPepAllJson/pepBallots
````
Binary file modified egklib/egklib-all.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,15 @@ fun ChaumPedersenRangeProofKnownNonce.verify(
val (alpha, beta) = ciphertext
results.add(
if (alpha.isValidResidue() && beta.isValidResidue()) Ok(true) else
Err(" 5.A,6.A invalid residue: alpha = ${alpha.inBounds()} beta = ${beta.inBounds()}")
Err(" 5.A,6.A values not in Zp^r: alpha = ${alpha.inBounds()} beta = ${beta.inBounds()}")
)

val expandedProofs = proofs.mapIndexed { j, proof ->
// recomputes all the a and b values
val (cj, vj) = proof
results.add(
if (cj.inBounds() && vj.inBounds()) Ok(true) else
Err(" 5.B,6.B c = ${cj.inBounds()} v = ${vj.inBounds()} idx=$j")
)
if (cj.inBounds() && vj.inBounds()) results.add(Ok(true))
if (!cj.inBounds()) results.add(Err(" 5.B,6.B cj (idx $j) not in bounds"))
if (!vj.inBounds()) results.add(Err(" 5.C,6.C vj (idx $j) not in bounds"))

val wj = (vj - j.toElementModQ(group) * cj)
ExpandedChaumPedersenProof(
Expand Down
45 changes: 32 additions & 13 deletions egklib/src/commonMain/kotlin/electionguard/verifier/Verifier.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,21 @@ class Verifier(val record: ElectionRecord, val nthreads: Int = 11) {
val publicKeyOk = verifyElectionPublicKey()
println(" 3. verifyElectionPublicKey= $publicKeyOk")

val baseHashOk = verifyExtendedBaseHash()
println(" 4. verifyExtendedBaseHAsh= $baseHashOk")

if (record.stage() < ElectionRecord.Stage.ENCRYPTED) {
println("election record stage = ${record.stage()}, stopping verification now\n")
val took = getSystemTimeInMillis() - starting13
if (showTime) println(" verify 2,3 took $took millisecs")
if (showTime) println(" verify 2,3,4 took $took millisecs")
return true
}


// encryption and vote limits 5,6,7
val verifyEncryptions = VerifyEncryptedBallots(group, manifest, jointPublicKey, He, config, nthreads)
// Note we are validating all ballots, not just CAST
val ballotResult = verifyEncryptions.verifyBallots(record.encryptedAllBallots { true }, stats, showTime)
println(" 5,6,7,16,17. verifyEncryptedBallots $ballotResult")
println(" 5,6,17,18. verifyEncryptedBallots $ballotResult")

val chainResults = if (config.chainConfirmationCodes) {
val chainResult = verifyEncryptions.verifyConfirmationChain(record)
Expand All @@ -75,7 +77,7 @@ class Verifier(val record: ElectionRecord, val nthreads: Int = 11) {
// tally accumulation, box 7 and 9E
val verifyAggregation = VerifyAggregation(group, verifyEncryptions.aggregator)
val aggResult = verifyAggregation.verify(record.encryptedTally()!!, showTime)
println(" 7. verifyBallotAggregation $aggResult")
println(" 8. verifyBallotAggregation $aggResult")

if (record.stage() < ElectionRecord.Stage.DECRYPTED) {
println("election record stage = ${record.stage()}, stopping verification now\n")
Expand All @@ -85,14 +87,15 @@ class Verifier(val record: ElectionRecord, val nthreads: Int = 11) {
// tally decryption
val verifyDecryption = VerifyDecryption(group, manifest, jointPublicKey, He)
val tallyResult = verifyDecryption.verify(record.decryptedTally()!!, isBallot = false, stats)
println(" 8,9. verifyTallyDecryption $tallyResult")
println(" 9,10,11. verifyTallyDecryption $tallyResult")

// 10, 11, 12, 13, 14 spoiled ballots
// 12, 13, 14 spoiled ballots
val spoiledResult =
verifyDecryption.verifySpoiledBallotTallies(record.decryptedBallots(), nthreads, stats, showTime)
println(" 10,11,12,13,14. verifySpoiledBallotTallies $spoiledResult")
println(" 12,13,14. verifySpoiledBallotTallies $spoiledResult")

val allOk = (parametersOk is Ok) && (guardiansOk is Ok) && (publicKeyOk is Ok) && (ballotResult is Ok) &&
val allOk = (parametersOk is Ok) && (guardiansOk is Ok) && (publicKeyOk is Ok) && (baseHashOk is Ok) &&
(ballotResult is Ok) &&
(chainResults is Ok) && (aggResult is Ok) && (tallyResult is Ok) && (spoiledResult is Ok)
println("verify allOK = $allOk\n")
return allOk
Expand Down Expand Up @@ -151,15 +154,33 @@ class Verifier(val record: ElectionRecord, val nthreads: Int = 11) {
return checkProofs.merge()
}

// Verification Box 3
// Verification 3 (Election public-key validation)
//An election verifier must verify the correct computation of the joint election public key.
//(3.A) The value Ki is in Zpr and Ki ̸= 1 mod p
private fun verifyElectionPublicKey(): Result<Boolean, String> {
val errors = mutableListOf<Result<Boolean, String>>()

val guardiansSorted = this.record.guardians().sortedBy { it.xCoordinate }
guardiansSorted.forEach {
val Ki = it.publicKey()
if (!Ki.isValidResidue()) {
errors.add(Err(" 3.A publicKey Ki (${it.guardianId} is not in Zp^r"))
}
if (Ki == group.ONE_MOD_P) {
errors.add(Err(" 3.A publicKey Ki is equal to ONE_MOD_P"))
}
}

val jointPublicKeyComputed = guardiansSorted.map { it.publicKey() }.reduce { a, b -> a * b }
if (!jointPublicKey.equals(jointPublicKeyComputed)) {
errors.add(Err(" 3.A jointPublicKey K does not equal computed K = Prod(K_i)"))
errors.add(Err(" 3.B jointPublicKey K does not equal computed K = Prod(K_i)"))
}
return errors.merge()
}

private fun verifyExtendedBaseHash(): Result<Boolean, String> {
val errors = mutableListOf<Result<Boolean, String>>()
val guardiansSorted = this.record.guardians().sortedBy { it.xCoordinate }

val commitments = mutableListOf<ElementModP>()
guardiansSorted.forEach { commitments.addAll(it.coefficientCommitments()) }
Expand All @@ -168,10 +189,8 @@ class Verifier(val record: ElectionRecord, val nthreads: Int = 11) {
// He = H(HB ; 0x12, K) ; spec 2.0.0 p.25, eq 23.
val computeHe = hashFunction(record.electionBaseHash().bytes, 0x12.toByte(), jointPublicKey.key)
if (He != computeHe) {
errors.add(Err(" 3.B extendedBaseHash does not match computed"))
println("extendedBaseHash $He != computed $computeHe")
errors.add(Err(" 4.A extendedBaseHash does not match computed"))
}

return errors.merge()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ class RunTrustedPepBatchTest {
)
}

@Test
// @Test
fun testVerifyPep() {
val inputDir = "src/commonTest/data/workflow/allAvailableJson"
val outputDir = "testOut/pep/testPepAllJson"
val outputDir = "../testOut/pep/testPepAllJson"

RunVerifyPep.main(
arrayOf(
Expand All @@ -93,4 +93,5 @@ class RunTrustedPepBatchTest {
)
}


}

0 comments on commit 8b66346

Please sign in to comment.