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

Add more tests for keyceremony, tally. #61

Merged
merged 1 commit into from
Apr 16, 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.3%25%20LOC%20(6905/7650)-blue)
![Coverage](https://img.shields.io/badge/coverage-90.5%25%20LOC%20(6924/7647)-blue)

# ElectionGuard-Kotlin Elliptic Curve

Expand Down
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ dependencies {
implementation(libs.bundles.eglib)
implementation(libs.bundles.logging)
testImplementation(libs.bundles.egtest)
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation(libs.kotlin.test)
testImplementation(libs.mockk)
}

tasks.test {
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", vers
kotest-property = { module = "io.kotest:kotest-property", version.ref = "kotest-version" }
kotest-datatest = { module = "io.kotest:kotest-framework-datatest", version.ref = "kotest-version" }
kotest-runner = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest-version" }
mockk = { module = "io.mockk:mockk", version = "1.13.7" }
mockk = { module = "io.mockk:mockk", version = "1.13.10" }

[bundles]
eglib = ["bull-result", "kotlinx-cli", "kotlinx-coroutines-core", "kotlinx-datetime", "kotlinx-serialization-json", "oshai-logging"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,6 @@ open class KeyCeremonyTrustee(
}

// If the MAC verifies, Gℓ decrypts b(Pi(ℓ), 32) = Ci,ℓ,1 ⊕ k1 .
// TODO prove always 32 bytes
return ByteArray(32) { c1[it] xor k1[it] }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class RunEncryptBallotTest {
val manifest = record.manifest()
val publisher = makePublisher(outputDeviceDir, true)
val consumerOut = makeConsumer(outputDir, consumerIn.group)
createDirectories("$outputDeviceDir")
createDirectories(outputDeviceDir)

val ballotProvider = RandomBallotProvider(manifest)
repeat(nballots) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package org.cryptobiotic.eg.tally
package org.cryptobiotic.eg.decrypt

import org.cryptobiotic.eg.core.productionGroup
import org.cryptobiotic.eg.decrypt.computeLagrangeCoefficient
import kotlin.test.Test
import kotlin.test.assertEquals

private val group = productionGroup()

class LagrangeCoefficientsTest {
private val group = productionGroup()

@Test
fun testLagrangeCoefficientAreIntegral() {
Expand All @@ -32,39 +30,39 @@ class LagrangeCoefficientsTest {
val coeff: Int = computeLagrangeCoefficientInt(coord, others)
val numer: Int = computeLagrangeNumerator(others)
val denom: Int = computeLagrangeDenominator(coord, others)
val coeffQ = group.computeLagrangeCoefficient(coord, others.map { it})
val coeffQ = group.computeLagrangeCoefficient(coord, others.map { it })
println("($coord) $coeff == ${numer} / ${denom} rem ${numer % denom} == $coeffQ")
if (exact) {
assertEquals(0, numer % denom)
}
}
println()
}
}

fun computeLagrangeCoefficientInt(coordinate: Int, others: List<Int>): Int {
if (others.isEmpty()) {
return 1
}
val numerator: Int = others.reduce { a, b -> a * b }
fun computeLagrangeCoefficientInt(coordinate: Int, others: List<Int>): Int {
if (others.isEmpty()) {
return 1
}
val numerator: Int = others.reduce { a, b -> a * b }

val diff: List<Int> = others.map { degree: Int -> degree - coordinate }
val denominator = diff.reduce { a, b -> a * b }
val diff: List<Int> = others.map { degree: Int -> degree - coordinate }
val denominator = diff.reduce { a, b -> a * b }

return numerator / denominator
}
return numerator / denominator
}

fun computeLagrangeNumerator(others: List<Int>): Int {
if (others.isEmpty()) {
return 1
fun computeLagrangeNumerator(others: List<Int>): Int {
if (others.isEmpty()) {
return 1
}
return others.reduce { a, b -> a * b }
}
return others.reduce { a, b -> a * b }
}

fun computeLagrangeDenominator(coordinate: Int, others: List<Int>): Int {
if (others.isEmpty()) {
return 1
fun computeLagrangeDenominator(coordinate: Int, others: List<Int>): Int {
if (others.isEmpty()) {
return 1
}
val diff: List<Int> = others.map { degree: Int -> degree - coordinate }
return diff.reduce { a, b -> a * b }
}
val diff: List<Int> = others.map { degree: Int -> degree - coordinate }
return diff.reduce { a, b -> a * b }
}
133 changes: 133 additions & 0 deletions src/test/kotlin/org/cryptobiotic/eg/keyceremony/KeyCeremonyMockTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package org.cryptobiotic.eg.keyceremony

import com.github.michaelbull.result.Err
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.unwrap
import io.mockk.every
import io.mockk.spyk
import org.cryptobiotic.eg.core.generateHashedCiphertext
import org.cryptobiotic.eg.core.productionGroup
import kotlin.test.Test

import kotlin.test.assertTrue

class KeyCeremonyMockTest {
val group = productionGroup("P-256")

@Test
fun testKeyCeremonyOk() {
val trustee1 = KeyCeremonyTrustee(group, "id1", 1, 3, 3)
val trustee2 = KeyCeremonyTrustee(group, "id2", 3, 3, 3)
val trustee3 = KeyCeremonyTrustee(group, "id3", 2, 3, 3)
val spy3 = spyk(trustee3)
val trustees = listOf(trustee1, trustee2, spy3)

val result = keyCeremonyExchange(trustees)
assertTrue(result is Ok)
}

@Test
fun testKeyCeremonyMockOk() {
val group = productionGroup()
val trustee1 = KeyCeremonyTrustee(group, "id1", 1, 3, 3)
val trustee2 = KeyCeremonyTrustee(group, "id2", 3, 3, 3)
val trustee3 = KeyCeremonyTrustee(group, "id3", 2, 3, 3)
val spy3 = spyk(trustee3)
every { spy3.encryptedKeyShareFor(trustee1.id()) } answers {
val result1 = trustee3.encryptedKeyShareFor(trustee1.id())
assertTrue(result1 is Ok)
val ss21 = result1.unwrap()
Ok(EncryptedKeyShare(spy3.xCoordinate(), spy3.id(), trustee1.id(), ss21.encryptedCoordinate))
}
val trustees = listOf(trustee1, trustee2, spy3)

val result = keyCeremonyExchange(trustees)
assertTrue(result is Ok)
}

@Test
fun testAllowBadEncryptedShare() {
val group = productionGroup()
val trustee1 = KeyCeremonyTrustee(group, "id1", 1, 3, 3)
val trustee2 = KeyCeremonyTrustee(group, "id2", 3, 3, 3)
val trustee3 = KeyCeremonyTrustee(group, "id3", 2, 3, 3)
val spy3 = spyk(trustee3)
every { spy3.encryptedKeyShareFor(trustee1.id()) } answers {
trustee3.encryptedKeyShareFor(trustee1.id()) // trustee needs to cache
// bad EncryptedShare
Ok(EncryptedKeyShare(spy3.xCoordinate(), spy3.id(), trustee1.id(), generateHashedCiphertext(group)))
}
val trustees = listOf(trustee1, trustee2, spy3)
val result = keyCeremonyExchange(trustees, true)
println("result = $result")
assertTrue(result is Ok)
}

@Test
fun testBadEncryptedShare() {
val group = productionGroup()
val trustee1 = KeyCeremonyTrustee(group, "id1", 1, 3, 3)
val trustee2 = KeyCeremonyTrustee(group, "id2", 3, 3, 3)
val trustee3 = KeyCeremonyTrustee(group, "id3", 2, 3, 3)
val spy3 = spyk(trustee3)
every { spy3.encryptedKeyShareFor(trustee1.id()) } answers {
trustee3.encryptedKeyShareFor(trustee1.id()) // trustee needs to cache
// bad EncryptedShare
Ok(EncryptedKeyShare(spy3.xCoordinate(), spy3.id(), trustee1.id(), generateHashedCiphertext(group)))
}
val trustees = listOf(trustee1, trustee2, spy3)
val result = keyCeremonyExchange(trustees, false)
println("result = $result")
assertTrue(result is Err)
assertTrue(result.error.contains("Trustee 'id1' couldnt decrypt EncryptedKeyShare for missingGuardianId 'id3'"))
}

@Test
fun testBadKeySharesAllowFalse() {
val group = productionGroup()
val trustee1 = KeyCeremonyTrustee(group, "id1", 1, 3, 3)
val trustee2 = KeyCeremonyTrustee(group, "id2", 3, 3, 3)
val trustee3 = KeyCeremonyTrustee(group, "id3", 2, 3, 3)
val spy3 = spyk(trustee3)
every { spy3.encryptedKeyShareFor(trustee1.id()) } answers {
trustee3.encryptedKeyShareFor(trustee1.id()) // trustee needs to cache
// bad EncryptedShare
Ok(EncryptedKeyShare(spy3.xCoordinate(), spy3.id(), trustee1.id(), generateHashedCiphertext(group)))
}
every { spy3.keyShareFor(trustee1.id()) } answers {
// bad KeyShare
Ok(KeyShare(spy3.xCoordinate(), spy3.id(), trustee1.id(), group.TWO_MOD_Q))
}
val trustees = listOf(trustee1, trustee2, spy3)
val result = keyCeremonyExchange(trustees, false)
println("result = $result")
assertTrue(result is Err)
println(result)
assertTrue(result.error.contains("keyCeremonyExchange not complete"))
}

@Test
fun testBadKeySharesAllowTrue() {
val group = productionGroup()
val trustee1 = KeyCeremonyTrustee(group, "id1", 1, 3, 3)
val trustee2 = KeyCeremonyTrustee(group, "id2", 3, 3, 3)
val trustee3 = KeyCeremonyTrustee(group, "id3", 2, 3, 3)
val spy3 = spyk(trustee3)
every { spy3.encryptedKeyShareFor(trustee1.id()) } answers {
trustee3.encryptedKeyShareFor(trustee1.id()) // trustee needs to cache
// bad EncryptedShare
Ok(EncryptedKeyShare(spy3.xCoordinate(), spy3.id(), trustee1.id(), generateHashedCiphertext(group)))
}
every { spy3.keyShareFor(trustee1.id()) } answers {
// bad KeyShare
Ok(KeyShare(spy3.xCoordinate(), spy3.id(), trustee1.id(), group.TWO_MOD_Q))
}
val trustees = listOf(trustee1, trustee2, spy3)
val result = keyCeremonyExchange(trustees, true)
println("result = $result")
assertTrue(result is Err)
println(result)
assertTrue(result.error.contains("keyCeremonyExchange not complete"))
}

}
Loading
Loading