Skip to content

Commit

Permalink
Merge pull request #389 from JohnLCaron/runTrustedPep
Browse files Browse the repository at this point in the history
Add threaded RunTrustedPep CLI.
  • Loading branch information
JohnLCaron authored Oct 7, 2023
2 parents b2c3a7a + 4befdee commit 2622633
Show file tree
Hide file tree
Showing 37 changed files with 753 additions and 262 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class AddEncryptedBallot(
throw RuntimeException("ManifestInputValidation FAILED $errors")
}

val consumer = makeConsumer(outputDir, group, isJson)
val consumer = makeConsumer(group, outputDir, isJson)
val chainResult = consumer.readEncryptedBallotChain(deviceName)
if (chainResult is Ok) {
// this is a restart on an existing chain
Expand Down
125 changes: 125 additions & 0 deletions egklib/src/commonMain/kotlin/electionguard/pep/BallotPep.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package electionguard.pep

import electionguard.ballot.DecryptedTallyOrBallot
import electionguard.core.*
import electionguard.json2.*
import kotlinx.serialization.Serializable

data class BallotPep(
val ballotId: String,
val isEq: Boolean,
val contests: List<ContestPep>,
)

data class ContestPep(
val contestId: String,
val selections: List<SelectionPep>,
)

data class SelectionPep(
val selectionId: String,
val ciphertextRatio: ElGamalCiphertext, // α, β
val ciphertextAB: ElGamalCiphertext, // A, B
val blindingProof: ChaumPedersenProof,
val T: ElementModP,
val decryptionProof: ChaumPedersenProof,
) {

constructor(step1: PepSimple.SelectionStep1, dselection: DecryptedTallyOrBallot.Selection) : this (
dselection.selectionId,
step1.ciphertextRatio,
step1.ciphertextAB,
ChaumPedersenProof(step1.c, step1.v),
dselection.bOverM,
dselection.proof,
)
constructor(selection: PepTrusted.SelectionWorking, dselection: DecryptedTallyOrBallot.Selection) : this(
dselection.selectionId,
selection.ciphertextRatio,
selection.ciphertextAB,
ChaumPedersenProof(selection.c, selection.v),
dselection.bOverM,
dselection.proof,
)
constructor(work: BlindWorking, dselection: DecryptedTallyOrBallot.Selection) : this (
dselection.selectionId,
work.ciphertextRatio,
work.ciphertextAB!!,
ChaumPedersenProof(work.c, work.v!!),
dselection.bOverM,
dselection.proof,
)
}

@Serializable
data class BallotPepJson(
val ballot_id: String,
val is_equal: Boolean,
val contests: List<ContestPepJson>,
)

@Serializable
data class ContestPepJson(
val contest_id: String,
val selections: List<SelectionPepJson>,
)

@Serializable
data class SelectionPepJson(
val selection_id: String,
val ciphertext_ratio: ElGamalCiphertextJson,
val ciphertext_AB: ElGamalCiphertextJson,
val blinding_proof: ChaumPedersenJson,
val T: ElementModPJson,
val decryption_proof: ChaumPedersenJson,
)

fun BallotPep.publishJson(): BallotPepJson {
val contests = this.contests.map { pcontest ->

// val selectionId: String,
// val ciphertextRatio: ElGamalCiphertext, // α, β
// val ciphertextAB: ElGamalCiphertext, // A, B
// val blindingProof: ChaumPedersenProof,
// val T: ElementModP,
// val decryptionProof: ChaumPedersenProof,
ContestPepJson(
pcontest.contestId,
pcontest.selections.map {
SelectionPepJson(
it.selectionId,
it.ciphertextRatio.publishJson(),
it.ciphertextAB.publishJson(),
it.blindingProof.publishJson(),
it.T.publishJson(),
it.decryptionProof.publishJson(),
)
})
}
return BallotPepJson(this.ballotId, this.isEq, contests)
}

fun BallotPepJson.import(group: GroupContext): BallotPep {
val contests = this.contests.map { pcontest ->

// val selection_id: String,
// val ciphertext_ratio: ElGamalCiphertextJson,
// val ciphertext_AB: ElGamalCiphertextJson,
// val blinding_proof: ChaumPedersenJson,
// val T: ElementModPJson,
// val decryption_proof: ChaumPedersenJson,
ContestPep(
pcontest.contest_id,
pcontest.selections.map {
SelectionPep(
it.selection_id,
it.ciphertext_ratio.import(group),
it.ciphertext_AB.import(group),
it.blinding_proof.import(group),
it.T.import(group),
it.decryption_proof.import(group),
)
})
}
return BallotPep(this.ballot_id, this.is_equal, contests)
}
45 changes: 14 additions & 31 deletions egklib/src/commonMain/kotlin/electionguard/pep/PepBlindTrust.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class PepBlindTrust(
decryptingTrustees: List<DecryptingTrusteeIF>, // the trustees available to decrypt
) : PepAlgorithm {
val decryptor = DecryptorDoerre(group, extendedBaseHash, jointPublicKey, guardians, decryptingTrustees)
val stats = Stats()

// test if ballot1 and ballot2 are equivalent or not.
override fun testEquivalent(ballot1: EncryptedBallot, ballot2: EncryptedBallot): Result<Boolean, String> {
Expand All @@ -34,6 +35,8 @@ class PepBlindTrust(
}

override fun doEgkPep(ballot1: EncryptedBallot, ballot2: EncryptedBallot): Result<BallotPep, String> {
val startPep = System.currentTimeMillis()

// LOOK check ballotIds match, styleIds?
val errorMesses = ValidationMessages("Ballot '${ballot1.ballotId}'", 1)
if (ballot1.ballotId != ballot2.ballotId) {
Expand Down Expand Up @@ -64,7 +67,7 @@ class PepBlindTrust(
// (d) Compute aj = α^uj mod p and bj = β^uj mod p
// (e) Send (Aj, Bj, aj, bj) to admin
// step 1: for each trustee, a list of its responses
val step1s : List<List<BlindResponse>> = blindTrustees.map { it.blind(ratioCiphertexts) }
val step1s: List<List<BlindResponse>> = blindTrustees.map { it.blind(ratioCiphertexts) }
require(step1s.size == nb) // list(nd, texts)

// for each ciphertext, a list of responses from all the trustees
Expand Down Expand Up @@ -123,7 +126,7 @@ class PepBlindTrust(

// step 3: form all the challenges to each trustee, put them in working
// while were at it , we also need to know the original BlindResponse, so put those in working
blindResponses.zip(work23s).map { (responsesForTrustees : List<BlindResponse>, work23 : BlindWorking) ->
blindResponses.zip(work23s).map { (responsesForTrustees: List<BlindResponse>, work23: BlindWorking) ->
responsesForTrustees.forEach { br ->
work23.blindChallenges.add(BlindChallenge(work23.c, br.eps, br.u))
}
Expand All @@ -136,7 +139,7 @@ class PepBlindTrust(
// send to admin

// step 4: gather all challenges, get response from each trustee
val step4 : List<List<BlindChallengeResponse>> = blindTrustees.mapIndexed { idx, trustee ->
val step4: List<List<BlindChallengeResponse>> = blindTrustees.mapIndexed { idx, trustee ->
val allChallengesForIthTrustee = work23s.map { it.blindChallenges[idx] }
trustee.challenge(allChallengesForIthTrustee)
}
Expand Down Expand Up @@ -165,15 +168,15 @@ class PepBlindTrust(
require(bjp == br.bj)
}
// cough, cough, while were at it: 6(b) v = Sum_dj(vj)
work23.v = with (group) { step4.map { it.response }.addQ() }
work23.v = with(group) { step4.map { it.response }.addQ() }
}

// create an EncryptedBallot with the ciphertexts = (A, B), this is what we decrypt
var workIterator = work23s.iterator()
val contestsAB =
ballot1.contests.map { contest ->
val selectionsAB =
contest.selections.map{ selection ->
contest.selections.map { selection ->
val work = workIterator.next()
work.ciphertextAB = ElGamalCiphertext(work.bigA, work.bigB)
selection.copy(encryptedVote = work.ciphertextAB!!)
Expand All @@ -184,7 +187,7 @@ class PepBlindTrust(

//6. admin:
// (a) decrypt (A, B): (T, ChaumPedersenProof(c',v')) = EGDecrypt(A, B) // 8*nd
val decryption : DecryptedTallyOrBallot = decryptor.decryptPep(ballotAB)
val decryption: DecryptedTallyOrBallot = decryptor.decryptPep(ballotAB)

// (b) v = Sum_dj(vj), IsEq = (T == 1)
// (c) Send (IsEq, c, v, α, β, c′, v′, A, B, T) to V and publish to BB.
Expand All @@ -193,40 +196,20 @@ class PepBlindTrust(
val contestsPEP =
decryption.contests.map { dContest ->
val selectionsPEP =
dContest.selections.map{ dSelection ->
dContest.selections.map { dSelection ->
isEq = isEq && (dSelection.bOverM == group.ONE_MOD_P)
if (!isEq)
println("wtf")
val work = workIterator.next()
SelectionPep(work, dSelection)
}
ContestPep(dContest.contestId, selectionsPEP)
}
val ballotPEP = BallotPep(isEq, decryption.id, contestsPEP)
val ballotPEP = BallotPep(decryption.id, isEq, contestsPEP)

stats.of("egkPep", "selection").accum(getSystemTimeInMillis() - startPep, ntexts)

// step 6: verify
val verifyResult = VerifierPep(group, extendedBaseHash, jointPublicKey).verify(ballotPEP)
return if (verifyResult is Ok) Ok(ballotPEP) else Err(verifyResult.getError()!!)
}

data class BallotWorking(
val ballotId: String,
val contests: List<ContestWorking>,
)

data class ContestWorking(
val contestId: String,
val selections: List<SelectionWorking>,
)

inner class SelectionWorking(
val selectionId: String,
val ciphertextRatio: ElGamalCiphertext,
val ciphertextAB: ElGamalCiphertext,
val a: ElementModP,
val b: ElementModP
) {
var c: ElementModQ = group.ZERO_MOD_Q
var v: ElementModQ = group.ZERO_MOD_Q
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class PepSimple(
}
ContestPep(dContest.contestId, selectionsPEP)
}
val ballotPEP = BallotPep(isEq, decryption.id, contestsPEP)
val ballotPEP = BallotPep(decryption.id, isEq, contestsPEP)

// step 6: verify
val verifyResult = VerifierPep(group, extendedBaseHash, jointPublicKey).verify(ballotPEP)
Expand Down
Loading

0 comments on commit 2622633

Please sign in to comment.