Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contest data #69

Merged
merged 2 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![License](https://img.shields.io/github/license/JohnLCaron/egk-ec)](https://github.com/JohnLCaron/egk-ec/blob/main/LICENSE.txt)
![GitHub branch checks state](https://img.shields.io/github/actions/workflow/status/JohnLCaron/egk-ec/unit-tests.yml)
![Coverage](https://img.shields.io/badge/coverage-90.6%25%20LOC%20(6958/7679)-blue)
![Coverage](https://img.shields.io/badge/coverage-90.7%25%20LOC%20(6931/7639)-blue)

# ElectionGuard-Kotlin Elliptic Curve

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ data class ElGamalCiphertext(val pad: ElementModP, val data: ElementModP) {
fun decryptWithShares(publicKey: ElGamalPublicKey, shares: Iterable<ElementModP>): Int? {
val sharesList = shares.toList()
val context = compatibleContextOrFail(pad, data, publicKey.key, *(sharesList.toTypedArray()))
val allSharesProductM: ElementModP = with(context) { sharesList.multP() }
val allSharesProductM: ElementModP = context.multP(sharesList)
val decryptedValue: ElementModP = this.data / allSharesProductM
return publicKey.dLog(decryptedValue)
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/org/cryptobiotic/eg/core/ElGamalKeys.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class ElGamalPublicKey(inputKey: ElementModP) {
class ElGamalSecretKey(val key: ElementModQ) {
init {
if (key < key.context.TWO_MOD_Q)
throw ArithmeticException("secret key must be in [2, Q)")
throw ArithmeticException("secret key must be in [2, Q) group=${key.context.javaClass.name}")
}
val negativeKey: ElementModQ = -key
val context: GroupContext
Expand Down
16 changes: 2 additions & 14 deletions src/main/kotlin/org/cryptobiotic/eg/core/GroupContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,13 @@ interface GroupContext {
* Computes the sum of the given elements, mod q; this can be faster than using the addition
* operation for large numbers of inputs.
*/
fun Iterable<ElementModQ>.addQ(): ElementModQ
fun addQ(cues: Iterable<ElementModQ>): ElementModQ

/**
* Computes the product of the given elements, mod p; this can be faster than using the
* multiplication operation for large numbers of inputs.
*/
fun Iterable<ElementModP>.multP(): ElementModP
fun multP(pees: Iterable<ElementModP>): ElementModP

/** Computes G^e mod p, where G is our generator */
fun gPowP(exp: ElementModQ): ElementModP
Expand Down Expand Up @@ -263,18 +263,6 @@ fun compatibleContextOrFail(vararg elements: Element): GroupContext {
return headContext
}

/**
* Computes the sum of the given elements, mod q; this can be faster than using the addition
* operation for large enough numbers of inputs.
*/
fun GroupContext.addQ(vararg elements: ElementModQ) = elements.asIterable().addQ()

/**
* Computes the product of the given elements, mod p; this can be faster than using the
* multiplication operation for large enough numbers of inputs.
*/
fun GroupContext.multP(vararg elements: ElementModP) = elements.asIterable().multP()

fun GroupContext.showOpCountResults(where: String): String {
val opCounts = this.getAndClearOpCounts()
return buildString {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class EcElementModP(val group: EcGroupContext, val ec: VecElementP): ElementModP
}

// TODO what does it mean to be in bounds ??
override fun inBounds(): Boolean = true // TODO("Not yet implemented")
override fun inBounds(): Boolean = true

// TODO check this
override fun isValidResidue(): Boolean {
Expand Down
17 changes: 5 additions & 12 deletions src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/EcGroupContext.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.cryptobiotic.eg.core.ecgroup


import org.cryptobiotic.eg.core.*
import java.math.BigInteger
import java.util.concurrent.atomic.AtomicInteger
Expand Down Expand Up @@ -77,23 +76,17 @@ class EcGroupContext(val name: String, useNative: Boolean = true): GroupContext
return EcElementModQ(this, BigInteger.valueOf(i.toLong()))
}

override fun Iterable<ElementModQ>.addQ(): ElementModQ {
return addQQ(this)
override fun addQ(cues: Iterable<ElementModQ>): ElementModQ {
val sum = cues.fold(BigInteger.ZERO) { a, b -> a.plus((b as EcElementModQ).element) }
return EcElementModQ(this, sum.mod(vecGroup.order))
}

override fun Iterable<ElementModP>.multP(): ElementModP {
// TODO what if this.isEmpty() ?
return this.reduce { a, b -> a * b }
override fun multP(pees: Iterable<ElementModP>): ElementModP {
return pees.fold(ONE_MOD_P) { a, b -> a * b }
}

override fun randomElementModP(minimum: Int) = EcElementModP(this, vecGroup.randomElement())

fun addQQ(cues: Iterable<ElementModQ>): ElementModQ {
// TODO what if cues.isEmpty() ?
val sum = cues.fold(BigInteger.ZERO) { a, b -> a.plus((b as EcElementModQ).element) }
return EcElementModQ(this, sum.mod(vecGroup.order))
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
Expand Down
25 changes: 19 additions & 6 deletions src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroup.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class ProductionGroupContext(
override fun isProductionStrength() = true
override fun toString() : String = name

override val ONE_MOD_P
override val ONE_MOD_P : ElementModP
get() = oneModP

override val G_MOD_P
Expand Down Expand Up @@ -149,12 +149,17 @@ class ProductionGroupContext(
else -> ProductionElementModQ(i.toBigInteger(), this)
}

override fun addQ(cues: Iterable<ElementModQ>): ElementModQ {
val sum = cues.fold(BigInteger.ZERO) { a, b -> a.plus((b as ProductionElementModQ).element) }
return ProductionElementModQ(sum.mod(q), this)
}

/*
override fun Iterable<ElementModQ>.addQ(): ElementModQ {
val input = iterator().asSequence().toList()

// TODO why not return 0 ?
if (input.isEmpty()) {
throw ArithmeticException("addQ not defined on empty lists")
return ZERO_MOD_Q
}

if (input.count() == 1) {
Expand All @@ -170,12 +175,18 @@ class ProductionGroupContext(
return ProductionElementModQ(result, this@ProductionGroupContext)
}

*/

override fun multP(pees: Iterable<ElementModP>): ElementModP {
return pees.fold(ONE_MOD_P) { a, b -> a * b }
}

/*
override fun Iterable<ElementModP>.multP(): ElementModP {
val input = iterator().asSequence().toList()

// TODO why not return 1 ?
if (input.isEmpty()) {
throw ArithmeticException("multP not defined on empty lists")
return ONE_MOD_P
}

if (input.count() == 1) {
Expand All @@ -191,6 +202,8 @@ class ProductionGroupContext(
return ProductionElementModP(result, this@ProductionGroupContext)
}

*/

override fun gPowP(exp: ElementModQ) = gModP powP exp

override fun dLogG(p: ElementModP, maxResult: Int): Int? = dlogger.dLog(p, maxResult)
Expand Down Expand Up @@ -278,7 +291,7 @@ open class ProductionElementModP(internal val element: BigInteger, val groupCont

override fun isValidResidue(): Boolean {
groupContext.opCounts.getOrPut("exp") { AtomicInteger(0) }.incrementAndGet()
val residue = this.element.modPow(groupContext.q, groupContext.p) == groupContext.ONE_MOD_P.element
val residue = this.element.modPow(groupContext.q, groupContext.p) == groupContext.oneModP.element
return inBounds() && residue
}

Expand Down
12 changes: 6 additions & 6 deletions src/main/kotlin/org/cryptobiotic/eg/decrypt/CipherDecryptor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,19 @@ class CipherDecryptor(
val decryptions = texts.mapIndexed { idx, text ->

// lagrange weighted product of the shares, M = Prod(M_i^w_i) mod p; spec 2.0.0, eq 68
val weightedProduct = with (group) {
val weightedProduct = group.multP(
// for this idx, run over all the trustees
partialDecryptions.mapIndexed { tidx, pds ->
val trustee = decryptingTrustees[tidx]
val lagrange = lagrangeCoordinates[trustee.id()]!! // buildLagrangeCoordinates() guarentees exists
pds.partial[idx].Mi powP lagrange.lagrangeCoefficient
}.multP()
}
}
)

// compute the collective challenge, needed for the collective proof; spec 2.0.0 eq 70
val shares: List<PartialDecryption> = partialDecryptions.map { it.partial[idx] } // for this text, one from each trustee
val a: ElementModP = with(group) { shares.map { it.a }.multP() } // Prod(ai)
val b: ElementModP = with(group) { shares.map { it.b }.multP() } // Prod(bi)
val a: ElementModP = group.multP(shares.map { it.a }) // Prod(ai)
val b: ElementModP = group.multP(shares.map { it.b }) // Prod(bi)

val collectiveChallenge = text.collectiveChallenge(extendedBaseHash, publicKey, a, b, weightedProduct)

Expand Down Expand Up @@ -115,7 +115,7 @@ class CipherDecryptor(
challengeResponses: List<ElementModQ>, // across trustees for this decryption
): CipherDecryptionAndProof {
// v = Sum(v_i mod q); spec 2.0.0 eq 76
val response: ElementModQ = with(group) { challengeResponses.map { it }.addQ() }
val response: ElementModQ = group.addQ(challengeResponses)
val proof = ChaumPedersenProof(decryption.collectiveChallenge.toElementModQ(group), response)
return CipherDecryptionAndProof(decryption, proof)
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/kotlin/org/cryptobiotic/eg/decrypt/Guardians.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ data class Guardians(val group : GroupContext, val guardians: List<Guardian>) {
val guardian = guardianMap[guardianId]
?: throw IllegalStateException("Guardians.getGexpP doesnt have guardian id = '$guardianId'")

with(group) {
guardians.map { calculateGexpPiAtL(it.guardianId, guardian.xCoordinate, it.coefficientCommitments()) }.multP()
}
group.multP(
guardians.map { calculateGexpPiAtL(it.guardianId, guardian.xCoordinate, it.coefficientCommitments()) }
)
}
}

Expand Down
Loading
Loading