From 1beffe9d25086e79eba5d2d717e813528399c31c Mon Sep 17 00:00:00 2001 From: JohnLCaron Date: Wed, 17 Apr 2024 09:38:55 -0600 Subject: [PATCH] Eliminate TODOs in decrypt classes. Move lagrangeCoordinates to Guardians class. --- README.md | 4 +- docs/CommandLineInterface.md | 26 ++--- .../eg/decrypt/BallotDecryptor.kt | 41 ++----- .../eg/decrypt/CipherDecryptor.kt | 102 +++--------------- .../org/cryptobiotic/eg/decrypt/Guardians.kt | 66 ++++++++++++ .../cryptobiotic/eg/decrypt/TallyDecryptor.kt | 39 +------ .../eg/decrypt/EncryptDecryptTest.kt | 2 +- .../eg/decrypt/LagrangeCoefficientsTest.kt | 2 +- .../cryptobiotic/eg/decrypt/LagrangeTest.kt | 20 ++-- .../eg/workflow/FakeKeyCeremony.kt | 2 +- 10 files changed, 120 insertions(+), 184 deletions(-) diff --git a/README.md b/README.md index a03f18e..2d8eedc 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ [![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.5%25%20LOC%20(7001/7733)-blue) +![Coverage](https://img.shields.io/badge/coverage-90.6%25%20LOC%20(6958/7679)-blue) # ElectionGuard-Kotlin Elliptic Curve -_last update 04/13/2024_ +_last update 04/17/2024_ EGK Elliptic Curve (egk-ec) is an experimental implementation of [ElectionGuard](https://github.com/microsoft/electionguard), [version 2.0](https://github.com/microsoft/electionguard/releases/download/v2.0/EG_Spec_2_0.pdf), diff --git a/docs/CommandLineInterface.md b/docs/CommandLineInterface.md index ce3d2c2..27595c2 100644 --- a/docs/CommandLineInterface.md +++ b/docs/CommandLineInterface.md @@ -54,17 +54,17 @@ last update 04/16/2024 2. Use existing fake ballots for testing in _src/test/data/fakeBallots_. 5. **Encryption**. - 1. The [_RunAddEncryptedBallots_ CLI](#run-addencryptedballots) reads plaintext ballots from a directory and - writes their encryptions into the specified election record. - 1. The [_RunEncryptBallot_ CLI](#run-encrypt-ballot) reads a plaintext ballot from disk and writes its encryption to disk. - 1. The [_RunExampleEncryption_ CLI](#run-example-encryption) Is an example of running RunEncryptBallot to encrypt ballots. - This can simulate more complex election records with multiple voting devices. - 1. The [_RunBatchEncryption_ CLI](#run-batch-encryption) reads plaintext ballots from a directory and writes their encryptions to the - specified election record. It is multithreaded. - 1. _org.cryptobiotic.eg.encrypt.AddEncryptedBallot_ is a class that your program calls to encrypt plaintext ballots - and add them to the election record. (See _org.cryptobiotic.eg.cli.ExampleEncryption_ as an example of using AddEncryptedBallot). - 1. To run encryption with the Encryption server, see the webapps CLI. This allows you to run the encryption on a - different machine than where ballots are generated, and/or to call from a non-JVM program. + 1. The [_RunAddEncryptedBallots_ CLI](#run-addencryptedballots) reads plaintext ballots from a directory and + writes their encryptions into the specified election record. + 1. The [_RunEncryptBallot_ CLI](#run-encrypt-ballot) reads a plaintext ballot from disk and writes its encryption to disk. + 1. The [_RunExampleEncryption_ CLI](#run-example-encryption) Is an example of running RunEncryptBallot to encrypt ballots. + This can simulate more complex election records with multiple voting devices. + 1. The [_RunBatchEncryption_ CLI](#run-batch-encryption) reads plaintext ballots from a directory and writes their encryptions to the + specified election record. It is multithreaded. + 1. _org.cryptobiotic.eg.encrypt.AddEncryptedBallot_ is a class that your program calls to encrypt plaintext ballots + and add them to the election record. (See _org.cryptobiotic.eg.cli.ExampleEncryption_ as an example of using AddEncryptedBallot). + 1. To run encryption with the Encryption server, see the webapps CLI. This allows you to run the encryption on a + different machine than where ballots are generated, and/or to call from a non-JVM program. 6. **Accumulate Tally**. 1. [_RunAccumulateTally_ CLI](#run-accumulate_tally) reads an ElectionInitialized record and EncryptedBallot @@ -85,7 +85,9 @@ last update 04/16/2024 ## Make ekglib uberJar -For classpath simplicity, the examples below use the [ekglib uberJar](https://github.com/JohnLCaron/egk-ec/blob/main/docs/GettingStarted.md#building-a-library-with-all-dependencies-uber-jar). +For classpath simplicity, the examples below use the +[ekglib uberJar](https://github.com/JohnLCaron/egk-ec/blob/main/docs/GettingStarted.md#building-a-library-with-all-dependencies-uber-jar). + https://github.com/JohnLCaron/egk-ec/blob/main/docs/GettingStarted.md#building-a-library-with-all-dependencies-uber-jar ## Election setup diff --git a/src/main/kotlin/org/cryptobiotic/eg/decrypt/BallotDecryptor.kt b/src/main/kotlin/org/cryptobiotic/eg/decrypt/BallotDecryptor.kt index 32b1f38..a6f89a8 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/decrypt/BallotDecryptor.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/decrypt/BallotDecryptor.kt @@ -19,40 +19,8 @@ class BallotDecryptor( val guardians: Guardians, // all guardians decryptingTrustees: List, // the trustees available to decrypt ) { - val lagrangeCoordinates: Map - val stats = Stats() - val nguardians = guardians.guardians.size // number of guardinas - val quorum = guardians.guardians[0].coefficientCommitments().size val decryptor = CipherDecryptor(group, extendedBaseHash, publicKey, guardians, decryptingTrustees) - - init { - // check that the DecryptingTrustee's match their public key - val badTrustees = mutableListOf() - for (trustee in decryptingTrustees) { - val guardian = guardians.guardianMap[trustee.id()] - if (guardian == null) { - badTrustees.add(trustee.id()) - } else { - if (trustee.guardianPublicKey().key != guardian.publicKey()) { - badTrustees.add(trustee.id()) - logger.error { "trustee public key = ${trustee.guardianPublicKey()} not equal guardian = ${guardian.publicKey()}" } - } - } - } - if (badTrustees.isNotEmpty()) { - throw RuntimeException("DecryptingTrustee(s) ${badTrustees.joinToString(",")} do not match the public record") - } - - // build the lagrangeCoordinates once and for all - val dguardians = mutableListOf() - for (trustee in decryptingTrustees) { - val present: List = // available trustees minus me - decryptingTrustees.filter { it.id() != trustee.id() }.map { it.xCoordinate() } - val coeff: ElementModQ = group.computeLagrangeCoefficient(trustee.xCoordinate(), present) - dguardians.add(LagrangeCoordinate(trustee.id(), trustee.xCoordinate(), coeff)) - } - this.lagrangeCoordinates = dguardians.associateBy { it.guardianId } - } + val stats = Stats() fun decrypt(eballot: EncryptedBallotIF, errs : ErrorMessages): DecryptedTallyOrBallot? { if (eballot.electionId != extendedBaseHash) { @@ -87,7 +55,7 @@ class BallotDecryptor( val result = makeBallot(eballot, decryptionAndProofs, contestDecryptionAndProofs, errs.nested("BallotDecryptor.decrypt")) if (!errs.hasErrors()) { val ndecrypt = decryptionAndProofs.size + contestDecryptionAndProofs.size - stats.of("decryptTally").accum(stopwatch.stop(), ndecrypt) + stats.of("decryptBallot").accum(stopwatch.stop(), ndecrypt) } return if (errs.hasErrors()) null else result!! } @@ -103,10 +71,13 @@ class BallotDecryptor( val selections = econtest.selections.map { eselection -> val (decryption, proof) = decryptions[selectionCount++] val (T, tally) = decryption.decryptCiphertext(publicKey) + if (tally == null) { + errs.add("Cant decrypt tally for ${econtest.contestId}.${eselection.selectionId}") + } DecryptedTallyOrBallot.Selection( eselection.selectionId, - tally?: 0, // TODO error handling + tally?: 0, T, (decryption.cipher as Ciphertext).delegate, proof diff --git a/src/main/kotlin/org/cryptobiotic/eg/decrypt/CipherDecryptor.kt b/src/main/kotlin/org/cryptobiotic/eg/decrypt/CipherDecryptor.kt index f09a484..ce8af08 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/decrypt/CipherDecryptor.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/decrypt/CipherDecryptor.kt @@ -6,80 +6,39 @@ import org.cryptobiotic.eg.core.* import org.cryptobiotic.eg.core.Base16.toHex import org.cryptobiotic.eg.election.* import org.cryptobiotic.util.ErrorMessages -import org.cryptobiotic.util.Stats /** Orchestrates the decryption of List or List using DecryptingTrustees. */ class CipherDecryptor( val group: GroupContext, val extendedBaseHash: UInt256, val publicKey: ElGamalPublicKey, - val guardians: Guardians, // all guardians + guardians: Guardians, // all guardians private val decryptingTrustees: List, // the trustees available to decrypt ) { - val lagrangeCoordinates: Map - val stats = Stats() - val nguardians = guardians.guardians.size // number of guardinas - val quorum = guardians.guardians[0].coefficientCommitments().size - - init { - // TODO put these in the guardians - // check that the DecryptingTrustee's match their public key - val badTrustees = mutableListOf() - for (trustee in decryptingTrustees) { - val guardian = guardians.guardianMap[trustee.id()] - if (guardian == null) { - badTrustees.add(trustee.id()) - } else { - if (trustee.guardianPublicKey().key != guardian.publicKey()) { - badTrustees.add(trustee.id()) - logger.error { "trustee public key = ${trustee.guardianPublicKey()} not equal guardian = ${guardian.publicKey()}" } - } - } - } - if (badTrustees.isNotEmpty()) { - throw RuntimeException("DecryptingTrustee(s) ${badTrustees.joinToString(",")} do not match the public record") - } - - // build the lagrangeCoordinates once and for all - val dguardians = mutableListOf() - for (trustee in decryptingTrustees) { - val present: List = // available trustees minus me - decryptingTrustees.filter { it.id() != trustee.id() }.map { it.xCoordinate() } - val coeff: ElementModQ = group.computeLagrangeCoefficient(trustee.xCoordinate(), present) - dguardians.add(LagrangeCoordinate(trustee.id(), trustee.xCoordinate(), coeff)) - } - this.lagrangeCoordinates = dguardians.associateBy { it.guardianId } - } + val lagrangeCoordinates: Map = guardians.buildLagrangeCoordinates(decryptingTrustees) fun decrypt(texts: List, errs : ErrorMessages): List? { if (texts.isEmpty()) return emptyList() // get the PartialDecryptions from each of the trustees - val partialDecryptions = decryptingTrustees.map { // partialDecryptions are in the order of the decryptingTrustees - it.getPartialDecryptionsFromTrustee(texts, errs) + val partialDecryptions = decryptingTrustees.map { trustee -> // partialDecryptions are in order of the decryptingTrustees + trustee.getPartialDecryptionsFromTrustee(texts, errs) } if (errs.hasErrors()) { - logger.error { "partial decryptions failed = ${errs}" } + logger.error { "partial decryptions failed = $errs" } return null } // Do the decryption for each text val decryptions = texts.mapIndexed { idx, text -> - // TODO could use the shares // 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 = with (group) { // for this idx, run over all the trustees partialDecryptions.mapIndexed { tidx, pds -> val trustee = decryptingTrustees[tidx] - val lagrange = lagrangeCoordinates[trustee.id()] - val coeff = if (lagrange == null) { // TODO check to make sure this cant happen - errs.add("missing lagrangeCoordinate for ${trustee.id()}") - group.ONE_MOD_Q - } else { - lagrange.lagrangeCoefficient - } - pds.partial[idx].Mi powP coeff + val lagrange = lagrangeCoordinates[trustee.id()]!! // buildLagrangeCoordinates() guarentees exists + pds.partial[idx].Mi powP lagrange.lagrangeCoefficient }.multP() } @@ -93,7 +52,7 @@ class CipherDecryptor( CipherDecryption(text, weightedProduct, collectiveChallenge) } if (errs.hasErrors()) { - logger.error { "decrypt failed = ${errs}" } + logger.error { "decrypt failed = $errs" } return null } @@ -103,12 +62,12 @@ class CipherDecryptor( trustee.getResponsesFromTrustee(batchId, decryptions, errs.nested("trusteeChallengeResponses")) } if (errs.hasErrors()) { - logger.error { "decrypt failed = ${errs}" } + logger.error { "decrypt failed = $errs" } return null } // After gathering the challenge responses from the available trustees, we can create the proof - return makeHDecryptionAndProofs( decryptions, challengeResponses, errs) + return makeHDecryptionAndProofs( decryptions, challengeResponses) } private fun DecryptingTrusteeIF.getPartialDecryptionsFromTrustee(texts: List, errs : ErrorMessages) : PartialDecryptions { @@ -122,9 +81,9 @@ class CipherDecryptor( return pds } - // send all challenges for a ballot / tally to one trustee, get all its responses + // send all challenges for a ballot / tally to one trustee, get all its responses, in one call fun DecryptingTrusteeIF.getResponsesFromTrustee(batchId: Int, decryptions: List, errs : ErrorMessages) : ChallengeResponses { - val wi = lagrangeCoordinates[this.id()]!!.lagrangeCoefficient // TODO ensure cant fail + val wi = lagrangeCoordinates[this.id()]!!.lagrangeCoefficient // buildLagrangeCoordinates() guarentees exists // Create all the challenges from each Decryption for this trustee val requests: MutableList = mutableListOf() decryptions.forEach { decryption -> @@ -142,14 +101,13 @@ class CipherDecryptor( fun makeHDecryptionAndProofs( decryptions: List, // for each text challengeResponses: List, // for each trustee, list of responses for each text - errs : ErrorMessages, // TODO errors ): List { val ds = mutableListOf() decryptions.forEachIndexed { idx, decryption -> val responsesForIdx = challengeResponses.map { it.responses[idx] } ds.add( makeHDecryptionAndProof( decryption, responsesForIdx) ) } - return ds // for each text + return ds // one for each text } private fun makeHDecryptionAndProof( @@ -205,6 +163,7 @@ class CipherDecryption( // the return value of the decryption data class CipherDecryptionAndProof(val decryption: CipherDecryption, val proof: ChaumPedersenProof) +// abstraction so we can work with either ElGamalCiphertext or HashedElGamalCiphertext interface Cipher { fun pad() : ElementModP fun collectiveChallenge(extendedBaseHash:UInt256, publicKey: ElGamalPublicKey, a: ElementModP, b: ElementModP, beta: ElementModP): UInt256 @@ -234,35 +193,4 @@ data class HashedCiphertext(val delegate: HashedElGamalCiphertext): Cipher { delegate.c1.toHex(), delegate.c2, a, b, beta) -} - -////////////////////////////////////////////////////////////////////////////// - -data class LagrangeCoordinate( - var guardianId: String, - var xCoordinate: Int, - var lagrangeCoefficient: ElementModQ, // wℓ, spec 2.0.0 eq 67 -) { - init { - require(guardianId.isNotEmpty()) - require(xCoordinate > 0) - } -} - -/** Compute the lagrange coefficient, now that we know which guardians are present; 2.0, section 3.6.2, eq 67. */ -fun GroupContext.computeLagrangeCoefficient(coordinate: Int, present: List): ElementModQ { - val others: List = present.filter { it != coordinate } - if (others.isEmpty()) { - return this.ONE_MOD_Q - } - val numerator: Int = others.reduce { a, b -> a * b } - - val diff: List = others.map { degree -> degree - coordinate } - val denominator = diff.reduce { a, b -> a * b } - - val denomQ = - if (denominator > 0) denominator.toElementModQ(this) else (-denominator).toElementModQ(this) - .unaryMinus() - - return numerator.toElementModQ(this) / denomQ } \ No newline at end of file diff --git a/src/main/kotlin/org/cryptobiotic/eg/decrypt/Guardians.kt b/src/main/kotlin/org/cryptobiotic/eg/decrypt/Guardians.kt index f6b4413..312ad12 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/decrypt/Guardians.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/decrypt/Guardians.kt @@ -1,6 +1,8 @@ package org.cryptobiotic.eg.decrypt +import io.github.oshai.kotlinlogging.KotlinLogging import org.cryptobiotic.eg.core.* +import org.cryptobiotic.eg.decrypt.CipherDecryptor.Companion import org.cryptobiotic.eg.election.Guardian import org.cryptobiotic.eg.keyceremony.calculateGexpPiAtL @@ -38,4 +40,68 @@ data class Guardians(val group : GroupContext, val guardians: List) { } } + fun buildLagrangeCoordinates(decryptingTrustees: List) : Map { + // check that the DecryptingTrustee's match their public key + val badTrustees = mutableListOf() + for (trustee in decryptingTrustees) { + val guardian = guardianMap[trustee.id()] + if (guardian == null) { + badTrustees.add(trustee.id()) + } else { + if (trustee.guardianPublicKey().key != guardian.publicKey()) { + badTrustees.add(trustee.id()) + logger.error { "trustee public key = ${trustee.guardianPublicKey()} not equal guardian = ${guardian.publicKey()}" } + } + } + } + if (badTrustees.isNotEmpty()) { + throw RuntimeException("DecryptingTrustee(s) ${badTrustees.joinToString(",")} do not match the public record") + } + + // build lagrange coeff for each trustee + val lagrange = decryptingTrustees.map { trustee -> + val present: List = // available trustees minus me + decryptingTrustees.filter { it.id() != trustee.id() }.map { it.xCoordinate() } + val coeff: ElementModQ = computeLagrangeCoefficient(group, trustee.xCoordinate(), present) + LagrangeCoordinate(trustee.id(), trustee.xCoordinate(), coeff) + } + + return lagrange.associateBy { it.guardianId } + } + + companion object { + private val logger = KotlinLogging.logger("Guardians") + } + +} + +////////////////////////////////////////////////////////////////////////////// + +data class LagrangeCoordinate( + var guardianId: String, + var xCoordinate: Int, + var lagrangeCoefficient: ElementModQ, // wℓ, spec 2.0.0 eq 67 +) { + init { + require(guardianId.isNotEmpty()) + require(xCoordinate > 0) + } +} + +/** Compute the lagrange coefficient, now that we know which guardians are present; 2.0, section 3.6.2, eq 67. */ +fun computeLagrangeCoefficient(group: GroupContext, coordinate: Int, present: List): ElementModQ { + val others: List = present.filter { it != coordinate } + if (others.isEmpty()) { + return group.ONE_MOD_Q + } + val numerator: Int = others.reduce { a, b -> a * b } + + val diff: List = others.map { degree -> degree - coordinate } + val denominator = diff.reduce { a, b -> a * b } + + val denomQ = + if (denominator > 0) denominator.toElementModQ(group) else (-denominator).toElementModQ(group) + .unaryMinus() + + return numerator.toElementModQ(group) / denomQ } \ No newline at end of file diff --git a/src/main/kotlin/org/cryptobiotic/eg/decrypt/TallyDecryptor.kt b/src/main/kotlin/org/cryptobiotic/eg/decrypt/TallyDecryptor.kt index 95238bf..fb3025e 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/decrypt/TallyDecryptor.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/decrypt/TallyDecryptor.kt @@ -16,40 +16,8 @@ class TallyDecryptor( val guardians: Guardians, // all guardians decryptingTrustees: List, // the trustees available to decrypt ) { - val lagrangeCoordinates: Map - val nguardians = guardians.guardians.size // number of guardinas - val quorum = guardians.guardians[0].coefficientCommitments().size val decryptor = CipherDecryptor(group, extendedBaseHash, publicKey, guardians, decryptingTrustees) - init { - // check that the DecryptingTrustee's match their public key - val badTrustees = mutableListOf() - for (trustee in decryptingTrustees) { - val guardian = guardians.guardianMap[trustee.id()] - if (guardian == null) { - badTrustees.add(trustee.id()) - } else { - if (trustee.guardianPublicKey().key != guardian.publicKey()) { - badTrustees.add(trustee.id()) - logger.error { "trustee public key = ${trustee.guardianPublicKey()} not equal guardian = ${guardian.publicKey()}" } - } - } - } - if (badTrustees.isNotEmpty()) { - throw RuntimeException("DecryptingTrustee(s) ${badTrustees.joinToString(",")} do not match the public record") - } - - // build the lagrangeCoordinates once and for all - val dguardians = mutableListOf() - for (trustee in decryptingTrustees) { - val present: List = // available trustees minus me - decryptingTrustees.filter { it.id() != trustee.id() }.map { it.xCoordinate() } - val coeff: ElementModQ = group.computeLagrangeCoefficient(trustee.xCoordinate(), present) - dguardians.add(LagrangeCoordinate(trustee.id(), trustee.xCoordinate(), coeff)) - } - this.lagrangeCoordinates = dguardians.associateBy { it.guardianId } - } - fun decrypt(etally: EncryptedTally, errs : ErrorMessages): DecryptedTallyOrBallot? { if (etally.electionId != extendedBaseHash) { errs.add("Encrypted Tally/Ballot has wrong electionId = ${etally.electionId}") @@ -78,15 +46,16 @@ class TallyDecryptor( ): DecryptedTallyOrBallot? { var count = 0 val contests = etally.contests.map { econtest -> - val cerrs = errs.nested("Contest ${econtest.contestId}") val selections = econtest.selections.map { eselection -> - val serrs = cerrs.nested("Selection ${eselection.selectionId}") val (decryption, proof) = decryptions[count++] val (T, tally) = decryption.decryptCiphertext(publicKey) + if (tally == null) { + errs.add("Cant decrypt tally for ${econtest.contestId}.${eselection.selectionId}") + } DecryptedTallyOrBallot.Selection( eselection.selectionId, - tally!!, // TODO errors + tally!!, T, (decryption.cipher as Ciphertext).delegate, proof diff --git a/src/test/kotlin/org/cryptobiotic/eg/decrypt/EncryptDecryptTest.kt b/src/test/kotlin/org/cryptobiotic/eg/decrypt/EncryptDecryptTest.kt index 076310c..ce8e5ab 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/decrypt/EncryptDecryptTest.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/decrypt/EncryptDecryptTest.kt @@ -69,7 +69,7 @@ fun encryptDecrypt( val evote = vote.encrypt(publicKey, group.randomElementModQ(minimum = 1)) val available = trustees.filter {present.contains(it.xCoordinate())} - val lagrangeCoefficients = available.associate { it.id() to group.computeLagrangeCoefficient(it.xCoordinate(), present) } + val lagrangeCoefficients = available.associate { it.id() to computeLagrangeCoefficient(group, it.xCoordinate(), present) } val shares: List = available.map { val pd = it.decrypt(listOf(evote.pad)) diff --git a/src/test/kotlin/org/cryptobiotic/eg/decrypt/LagrangeCoefficientsTest.kt b/src/test/kotlin/org/cryptobiotic/eg/decrypt/LagrangeCoefficientsTest.kt index 4db58f4..504d1e5 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/decrypt/LagrangeCoefficientsTest.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/decrypt/LagrangeCoefficientsTest.kt @@ -30,7 +30,7 @@ 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 = computeLagrangeCoefficient(group, coord, others.map { it }) println("($coord) $coeff == ${numer} / ${denom} rem ${numer % denom} == $coeffQ") if (exact) { assertEquals(0, numer % denom) diff --git a/src/test/kotlin/org/cryptobiotic/eg/decrypt/LagrangeTest.kt b/src/test/kotlin/org/cryptobiotic/eg/decrypt/LagrangeTest.kt index b26cd03..2f2aad1 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/decrypt/LagrangeTest.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/decrypt/LagrangeTest.kt @@ -12,15 +12,15 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue -private val group = productionGroup() /** Test KeyCeremony Trustee generation and recovered decryption. */ class LagrangeTest { + private val group = productionGroup() @Test fun testLagrangeInterpolation() { - val w1 = group.computeLagrangeCoefficient(1, listOf(1, 2)) - val w2 = group.computeLagrangeCoefficient(2, listOf(1, 2)) + val w1 = computeLagrangeCoefficient(group, 1, listOf(1, 2)) + val w2 = computeLagrangeCoefficient(group, 2, listOf(1, 2)) val polly = group.generatePolynomial("guardian1", 1, 2) val y1 = polly.valueAt(group, 1) @@ -33,8 +33,8 @@ class LagrangeTest { @Test fun testLagrangePolySum() { - val w1 = group.computeLagrangeCoefficient(1, listOf(1, 2)) - val w2 = group.computeLagrangeCoefficient(2, listOf(1, 2)) + val w1 = computeLagrangeCoefficient(group, 1, listOf(1, 2)) + val w2 = computeLagrangeCoefficient(group, 2, listOf(1, 2)) val polly1 = group.generatePolynomial("guardian1", 1, 2) val y11 = polly1.valueAt(group, 1) @@ -51,8 +51,8 @@ class LagrangeTest { @Test fun testTrusteePolySum() { - val w1 = group.computeLagrangeCoefficient(1, listOf(1, 2)) - val w2 = group.computeLagrangeCoefficient(2, listOf(1, 2)) + val w1 = computeLagrangeCoefficient(group, 1, listOf(1, 2)) + val w2 = computeLagrangeCoefficient(group, 2, listOf(1, 2)) val polly1 = KeyCeremonyTrustee(group, "guardian1", 1, 2, 2) val y11 = polly1.valueAt(group, 1) @@ -69,8 +69,8 @@ class LagrangeTest { @Test fun testTrusteePolySum2() { - val w1 = group.computeLagrangeCoefficient(1, listOf(1, 2)) - val w2 = group.computeLagrangeCoefficient(2, listOf(1, 2)) + val w1 = computeLagrangeCoefficient(group, 1, listOf(1, 2)) + val w2 = computeLagrangeCoefficient(group, 2, listOf(1, 2)) val polly1 = KeyCeremonyTrustee(group, "guardian1", 1, 2, 2) val y11 = polly1.valueAt(group, 1) @@ -109,7 +109,7 @@ class LagrangeTest { trustees: List, present: List) { val available = trustees.filter {present.contains(it.xCoordinate())} - val lagrangeCoefficients = available.associate { it.id to group.computeLagrangeCoefficient(it.xCoordinate, present) } + val lagrangeCoefficients = available.associate { it.id to computeLagrangeCoefficient(group, it.xCoordinate, present) } lagrangeCoefficients.values.forEach { assertTrue( it.inBounds()) } val weightedSum = with(group) { diff --git a/src/test/kotlin/org/cryptobiotic/eg/workflow/FakeKeyCeremony.kt b/src/test/kotlin/org/cryptobiotic/eg/workflow/FakeKeyCeremony.kt index cd0aa43..40bc6ed 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/workflow/FakeKeyCeremony.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/workflow/FakeKeyCeremony.kt @@ -138,7 +138,7 @@ fun testDoerreDecrypt(group: GroupContext, val evote = vote.encrypt(publicKey, group.randomElementModQ(minimum = 1)) val available = trustees.filter {present.contains(it.xCoordinate())} - val lagrangeCoefficients = available.associate { it.id to group.computeLagrangeCoefficient(it.xCoordinate, present) } + val lagrangeCoefficients = available.associate { it.id to computeLagrangeCoefficient(group, it.xCoordinate, present) } val shares: List = available.map { val pd = it.decrypt(listOf(evote.pad))