From aa96052c3aca08511fe63f606c7087a9d6e310fb Mon Sep 17 00:00:00 2001 From: JohnLCaron Date: Fri, 10 May 2024 09:10:32 -0600 Subject: [PATCH] Break Elements out of GroupContext. Separate int group into IntGroupContext, IntElementModP, IntElementModQ. Move some random methods to Utils. --- README.md | 4 +- .../org/cryptobiotic/eg/core/GroupContext.kt | 68 ---- .../org/cryptobiotic/eg/core/GroupElement.kt | 70 ++++ .../kotlin/org/cryptobiotic/eg/core/Utils.kt | 8 + .../eg/core/ecgroup/EcGroupContext.kt | 1 - .../eg/core/intgroup/IntElementModP.kt | 124 +++++++ .../eg/core/intgroup/IntElementModQ.kt | 60 ++++ .../cryptobiotic/eg/core/intgroup/IntGroup.kt | 321 ------------------ .../eg/core/intgroup/IntGroupContext.kt | 152 +++++++++ .../eg/core/intgroup/IntGroups.kt | 8 +- .../cryptobiotic/eg/core/intgroup/PowRadix.kt | 4 +- .../org/cryptobiotic/eg/verifier/Verifier.kt | 4 +- .../org/cryptobiotic/eg/core/TestBase64.kt | 4 +- ...ityTest.kt => GroupElementEqualityTest.kt} | 16 +- .../eg/core/intgroup/IntGroupConstantsTest.kt | 8 +- .../eg/core/intgroup/MontgomeryTest.kt | 8 +- .../eg/core/intgroup/PowRadixTest.kt | 4 +- .../eg/core/intgroup/PrimesTest.kt | 1 + .../eg/publish/json/ElementsTest.kt | 2 +- 19 files changed, 446 insertions(+), 421 deletions(-) create mode 100644 src/main/kotlin/org/cryptobiotic/eg/core/GroupElement.kt create mode 100644 src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntElementModP.kt create mode 100644 src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntElementModQ.kt delete mode 100644 src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroup.kt create mode 100644 src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupContext.kt rename src/test/kotlin/org/cryptobiotic/eg/core/intgroup/{ElementEqualityTest.kt => GroupElementEqualityTest.kt} (90%) diff --git a/README.md b/README.md index 4d2cfe9..21846ff 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.6%25%20LOC%20(7055/7784)-blue) +![Coverage](https://img.shields.io/badge/coverage-90.6%25%20LOC%20(7055/7787)-blue) # ElectionGuard-Kotlin Elliptic Curve -_last update 05/08/2024_ +_last update 05/09/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/src/main/kotlin/org/cryptobiotic/eg/core/GroupContext.kt b/src/main/kotlin/org/cryptobiotic/eg/core/GroupContext.kt index 98581c0..b24b93a 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/core/GroupContext.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/core/GroupContext.kt @@ -1,6 +1,5 @@ package org.cryptobiotic.eg.core -import org.cryptobiotic.eg.core.Base16.toHex import org.cryptobiotic.eg.election.ElectionConstants fun productionGroup(groupName: String = "P-256", useNative: Boolean = true): GroupContext { @@ -126,73 +125,6 @@ interface GroupContext { fun getAndClearOpCounts(): Map } -interface Element { - /** The [GroupContext] it belongs to */ - val group: GroupContext - - /** Validates that this element is a member of the Group */ - fun isValidElement(): Boolean - - /** Converts to a [ByteArray] representation. Inverse to group.binaryToElementModX(). */ - fun byteArray(): ByteArray - - fun toHex() : String = byteArray().toHex() -} - -interface ElementModQ : Element, Comparable { - /** Modular addition */ - operator fun plus(other: ElementModQ): ElementModQ - - /** Modular subtraction */ - operator fun minus(other: ElementModQ): ElementModQ - - /** Modular multiplication */ - operator fun times(other: ElementModQ): ElementModQ - - /** Computes the additive inverse */ - operator fun unaryMinus(): ElementModQ - - /** Finds the multiplicative inverse */ - fun multInv(): ElementModQ - - /** Multiplies by the modular inverse of [denominator] */ - infix operator fun div(denominator: ElementModQ): ElementModQ - - /** Allows elements to be compared (<, >, <=, etc.) using the usual arithmetic operators. */ - override operator fun compareTo(other: ElementModQ): Int - - /** Checks whether this element is zero. */ - fun isZero(): Boolean -} - -interface ElementModP : Element, Comparable { - - /** Computes b^e mod p */ - infix fun powP(exp: ElementModQ): ElementModP - - /** Modular multiplication */ - operator fun times(other: ElementModP): ElementModP - - /** Finds the multiplicative inverse */ - fun multInv(): ElementModP - - /** Multiplies by the modular inverse of [denominator] */ - infix operator fun div(denominator: ElementModP): ElementModP - - /** Allows elements to be compared (<, >, <=, etc.) using the usual arithmetic operators. */ - override operator fun compareTo(other: ElementModP): Int - - /** Create a new instance of this element where the `powP` function will possibly run faster. */ - fun acceleratePow(): ElementModP - - /** Short version of the String for readability. */ - fun toStringShort(): String { - val s = toHex() - val len = s.length - return "${s.substring(0, 7)}...${s.substring(len-8, len)}" - } -} - // Converts an integer to an ElementModQ, with optimizations when possible for small integers fun Int.toElementModQ(ctx: GroupContext) = when { diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/GroupElement.kt b/src/main/kotlin/org/cryptobiotic/eg/core/GroupElement.kt new file mode 100644 index 0000000..2a290aa --- /dev/null +++ b/src/main/kotlin/org/cryptobiotic/eg/core/GroupElement.kt @@ -0,0 +1,70 @@ +package org.cryptobiotic.eg.core + +import org.cryptobiotic.eg.core.Base16.toHex + +interface Element { + /** The [GroupContext] it belongs to */ + val group: GroupContext + + /** Validates that this element is a member of the Group */ + fun isValidElement(): Boolean + + /** Converts to a [ByteArray] representation. Inverse to group.binaryToElementModX(). */ + fun byteArray(): ByteArray + + fun toHex() : String = byteArray().toHex() +} + +interface ElementModQ : Element, Comparable { + /** Modular addition */ + operator fun plus(other: ElementModQ): ElementModQ + + /** Modular subtraction */ + operator fun minus(other: ElementModQ): ElementModQ + + /** Modular multiplication */ + operator fun times(other: ElementModQ): ElementModQ + + /** Computes the additive inverse */ + operator fun unaryMinus(): ElementModQ + + /** Finds the multiplicative inverse */ + fun multInv(): ElementModQ + + /** Multiplies by the modular inverse of [denominator] */ + infix operator fun div(denominator: ElementModQ): ElementModQ + + /** Allows elements to be compared (<, >, <=, etc.) using the usual arithmetic operators. */ + override operator fun compareTo(other: ElementModQ): Int + + /** Checks whether this element is zero. */ + fun isZero(): Boolean +} + +interface ElementModP : Element, Comparable { + + /** Computes b^e mod p */ + infix fun powP(exp: ElementModQ): ElementModP + + /** Modular multiplication */ + operator fun times(other: ElementModP): ElementModP + + /** Finds the multiplicative inverse */ + fun multInv(): ElementModP + + /** Multiplies by the modular inverse of [denominator] */ + infix operator fun div(denominator: ElementModP): ElementModP + + /** Allows elements to be compared (<, >, <=, etc.) using the usual arithmetic operators. */ + override operator fun compareTo(other: ElementModP): Int + + /** Create a new instance of this element where the `powP` function will possibly run faster. */ + fun acceleratePow(): ElementModP + + /** Short version of the String for readability. */ + fun toStringShort(): String { + val s = toHex() + val len = s.length + return "${s.substring(0, 7)}...${s.substring(len-8, len)}" + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/Utils.kt b/src/main/kotlin/org/cryptobiotic/eg/core/Utils.kt index f5397f9..723efd8 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/core/Utils.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/core/Utils.kt @@ -132,6 +132,14 @@ fun BigInteger.normalize() : String { } fun BigInteger.toHex() = this.toByteArray().toHex().lowercase() + +internal fun UInt.toBigInteger() = BigInteger.valueOf(this.toLong()) +internal fun ULong.toBigInteger() = BigInteger.valueOf(this.toLong()) + +/** Convert an array of bytes, in big-endian format, to a BigInteger */ +internal fun ByteArray.toBigInteger() = BigInteger(1, this) + + /** * Convert an integer to a big-endian array of four bytes. Negative numbers will be in * twos-complement. diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/EcGroupContext.kt b/src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/EcGroupContext.kt index e6d7fa1..56066c9 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/EcGroupContext.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/EcGroupContext.kt @@ -1,7 +1,6 @@ package org.cryptobiotic.eg.core.ecgroup import org.cryptobiotic.eg.core.* -import org.cryptobiotic.eg.core.intgroup.toBigInteger import java.math.BigInteger import java.util.concurrent.atomic.AtomicInteger diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntElementModP.kt b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntElementModP.kt new file mode 100644 index 0000000..458763c --- /dev/null +++ b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntElementModP.kt @@ -0,0 +1,124 @@ +package org.cryptobiotic.eg.core.intgroup + +import org.cryptobiotic.eg.core.* +import org.cryptobiotic.eg.core.Base64.toBase64 +import java.math.BigInteger +import java.util.concurrent.atomic.AtomicInteger + +open class IntElementModP(internal val element: BigInteger, val groupContext: IntGroupContext): ElementModP, + Element, Comparable { + + override fun byteArray(): ByteArray = element.toByteArray().normalize(512) + + private fun BigInteger.modWrap(): ElementModP = this.mod(groupContext.p).wrap() + private fun BigInteger.wrap(): ElementModP = IntElementModP(this, groupContext) + + override val group: GroupContext + get() = groupContext + + override operator fun compareTo(other: ElementModP): Int = element.compareTo(other.getCompat(groupContext)) + + /** + * Validates that this element is in Z_p^r, "set of r-th-residues in Z_p". + * "A value x is in Z_p^r if and only if x is an integer such that 0 ≤ x < p + * and x^q mod p == 1", see spec 2.0 p.9. + */ + override fun isValidElement(): Boolean { + groupContext.opCounts.getOrPut("exp") { AtomicInteger(0) }.incrementAndGet() + val inBounds = this.element >= BigInteger.ZERO && this.element < groupContext.p + val residue = this.element.modPow(groupContext.q, groupContext.p) == groupContext.oneModP.element + return inBounds && residue + } + + override infix fun powP(exp: ElementModQ) : ElementModP { + groupContext.opCounts.getOrPut("exp") { AtomicInteger(0) }.incrementAndGet() + return this.element.modPow(exp.getCompat(groupContext), groupContext.p).wrap() + } + + override operator fun times(other: ElementModP) = + (this.element * other.getCompat(groupContext)).modWrap() + + override fun multInv() + = element.modInverse(groupContext.p).wrap() +// = this powP groupContext.qMinus1Q + + // Performance note: multInv() can be expressed with the modInverse() method or we can do + // this exponentiation thing with Q - 1, which works for the subgroup. On the JVM, we get + // basically the same performance either way. + + override infix operator fun div(denominator: ElementModP) = + (element * denominator.getCompat(groupContext).modInverse(groupContext.p)).modWrap() + + override fun acceleratePow() : ElementModP = + AcceleratedElementModP(this) + + fun toMontgomeryElementModP(): MontgomeryElementModP = + ProductionMontgomeryElementModP( + element.shiftLeft(groupContext.productionMode.numBitsInP).mod(groupContext.p), + groupContext + ) + + override fun equals(other: Any?) = when (other) { + is ElementModP -> byteArray().contentEquals(other.byteArray()) + else -> false + } + + override fun hashCode() = byteArray().contentHashCode() + + override fun toString() = byteArray().toBase64() + + private fun ElementModP.getCompat(other: IntGroupContext): BigInteger { + group.assertCompatible(other) + return when (this) { + is IntElementModP -> this.element + else -> throw NotImplementedError("should only be two kinds of elements") + } + } +} + +class AcceleratedElementModP(p: IntElementModP) : IntElementModP(p.element, p.groupContext) { + // Laziness to delay computation of the table until its first use; saves space + val powRadix by lazy { PowRadix(p, p.groupContext.powRadixOption) } + + override fun acceleratePow(): ElementModP = this + + override infix fun powP(exp: ElementModQ) : ElementModP { + groupContext.opCounts.getOrPut("acc") { AtomicInteger(0) }.incrementAndGet() + return powRadix.pow(exp) + } +} + +internal data class ProductionMontgomeryElementModP(val element: BigInteger, val groupContext: IntGroupContext): + MontgomeryElementModP { + internal fun MontgomeryElementModP.getCompat(other: GroupContext): BigInteger { + context.assertCompatible(other) + if (this is ProductionMontgomeryElementModP) { + return this.element + } else { + throw NotImplementedError("unexpected MontgomeryElementModP type") + } + } + + internal fun BigInteger.modI(): BigInteger = this and groupContext.montgomeryIMinusOne + + internal fun BigInteger.divI(): BigInteger = this shr groupContext.productionMode.numBitsInP + + override fun times(other: MontgomeryElementModP): MontgomeryElementModP { + // w = aI * bI = (ab)(I^2) + val w: BigInteger = this.element * other.getCompat(this.context) + + // Z = ((((W mod I)⋅p^' ) mod I)⋅p+W)/I + val z: BigInteger = (((w.modI() * groupContext.montgomeryPPrime).modI() * groupContext.p) + w).divI() + + return ProductionMontgomeryElementModP( + if (z >= groupContext.p) z - groupContext.p else z, + groupContext) + } + + override fun toElementModP(): ElementModP = + IntElementModP((element * groupContext.montgomeryIPrime).mod(groupContext.p), groupContext) + + override val context: GroupContext + get() = groupContext + +} \ No newline at end of file diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntElementModQ.kt b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntElementModQ.kt new file mode 100644 index 0000000..47d8ba6 --- /dev/null +++ b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntElementModQ.kt @@ -0,0 +1,60 @@ +package org.cryptobiotic.eg.core.intgroup + +import org.cryptobiotic.eg.core.Base64.toBase64 +import org.cryptobiotic.eg.core.Element +import org.cryptobiotic.eg.core.ElementModQ +import org.cryptobiotic.eg.core.assertCompatible +import org.cryptobiotic.eg.core.normalize +import java.math.BigInteger + +class IntElementModQ(internal val element: BigInteger, override val group: IntGroupContext): ElementModQ, + Element, Comparable { + + override fun byteArray(): ByteArray = element.toByteArray().normalize(32) + + private fun BigInteger.modWrap(): ElementModQ = this.mod(this@IntElementModQ.group.q).wrap() + private fun BigInteger.wrap(): ElementModQ = IntElementModQ(this, this@IntElementModQ.group) + + override fun isZero() = element == BigInteger.ZERO + override fun isValidElement() = element >= BigInteger.ZERO && element < this.group.q + + override operator fun compareTo(other: ElementModQ): Int = element.compareTo(other.getCompat(this.group)) + + override operator fun plus(other: ElementModQ) = + (this.element + other.getCompat(this.group)).modWrap() + + override operator fun minus(other: ElementModQ) = + this + (-other) + + override operator fun times(other: ElementModQ) = + (this.element * other.getCompat(this.group)).modWrap() + + override fun multInv(): ElementModQ = element.modInverse(this.group.q).wrap() + + override operator fun unaryMinus(): ElementModQ = + if (this == this.group.zeroModQ) + this + else + (this.group.q - element).wrap() + + override infix operator fun div(denominator: ElementModQ): ElementModQ = + this * denominator.multInv() + + + override fun equals(other: Any?) = when (other) { + is ElementModQ -> byteArray().contentEquals(other.byteArray()) + else -> false + } + + override fun hashCode() = byteArray().contentHashCode() + + override fun toString() = byteArray().toBase64() +} + +internal fun ElementModQ.getCompat(other: IntGroupContext): BigInteger { + group.assertCompatible(other) + return when (this) { + is IntElementModQ -> this.element + else -> throw NotImplementedError("should only be two kinds of elements") + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroup.kt b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroup.kt deleted file mode 100644 index e89b6ce..0000000 --- a/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroup.kt +++ /dev/null @@ -1,321 +0,0 @@ -package org.cryptobiotic.eg.core.intgroup - -import org.cryptobiotic.eg.core.* -import org.cryptobiotic.eg.core.Base64.toBase64 -import java.math.BigInteger -import java.util.concurrent.atomic.AtomicInteger - -internal fun UInt.toBigInteger() = BigInteger.valueOf(this.toLong()) -internal fun ULong.toBigInteger() = BigInteger.valueOf(this.toLong()) - -/** Convert an array of bytes, in big-endian format, to a BigInteger */ -internal fun ByteArray.toBigInteger() = BigInteger(1, this) - -class ProductionGroupContext( - pBytes: ByteArray, - qBytes: ByteArray, - gBytes: ByteArray, - rBytes: ByteArray, - montIMinus1Bytes: ByteArray, - montIPrimeBytes: ByteArray, - montPPrimeBytes: ByteArray, - val name: String, - val powRadixOption: PowRadixOption, - val productionMode: ProductionMode, - val numPBits: Int -) : GroupContext { - val p: BigInteger - val q: BigInteger - val g: BigInteger - val r: BigInteger - val oneModP: ProductionElementModP - val gModP: ProductionElementModP - val zeroModQ: ProductionElementModQ - val oneModQ: ProductionElementModQ - val twoModQ: ProductionElementModQ - val dlogger: DLogarithm - val qMinus1Q: ProductionElementModQ - val montgomeryIMinusOne: BigInteger - val montgomeryIPrime: BigInteger - val montgomeryPPrime: BigInteger - - init { - p = pBytes.toBigInteger() - q = qBytes.toBigInteger() - g = gBytes.toBigInteger() - r = rBytes.toBigInteger() - oneModP = ProductionElementModP(1U.toBigInteger(), this) - gModP = ProductionElementModP(g, this).acceleratePow() as ProductionElementModP - zeroModQ = ProductionElementModQ(0U.toBigInteger(), this) - oneModQ = ProductionElementModQ(1U.toBigInteger(), this) - twoModQ = ProductionElementModQ(2U.toBigInteger(), this) - dlogger = DLogarithm(gModP) - qMinus1Q = (zeroModQ - oneModQ) as ProductionElementModQ - montgomeryIMinusOne = montIMinus1Bytes.toBigInteger() - montgomeryIPrime = montIPrimeBytes.toBigInteger() - montgomeryPPrime = montPPrimeBytes.toBigInteger() - } - - val groupConstants = IntGroupConstants(name, p, q, r, g) - val pm1overq = (p - BigInteger.ONE).div(q) // (p-1)/q - - override val constants = groupConstants.constants - - override fun toString() : String = name - - override val ONE_MOD_P : ElementModP - get() = oneModP - - override val G_MOD_P - get() = gModP - - override val ZERO_MOD_Q - get() = zeroModQ - - override val ONE_MOD_Q - get() = oneModQ - - override val TWO_MOD_Q - get() = twoModQ - - override val MAX_BYTES_P: Int - get() = 512 - - override val MAX_BYTES_Q: Int - get() = 32 - - override val NUM_P_BITS: Int - get() = numPBits - - override fun isCompatible(ctx: GroupContext): Boolean { - return (ctx is ProductionGroupContext) && productionMode == ctx.productionMode - } - - /** Returns a random number in [2, P). */ - override fun randomElementModP(statBytes:Int): ElementModP { - val b = randomBytes(MAX_BYTES_P+statBytes) - val bi = b.toBigInteger() - val ti = bi.modPow(pm1overq, p) // by magic this makes it into a group element - - val tinbounds = if (ti < BigInteger.TWO) ti + BigInteger.TWO else ti - return ProductionElementModP(tinbounds, this) - } - - override fun binaryToElementModP(b: ByteArray): ElementModP? = - try { - val tmp = b.toBigInteger() - if (tmp >= p || tmp < BigInteger.ZERO) null else ProductionElementModP(tmp, this) - } catch (t : Throwable) { - null - } - - /** Returns a random number in [2, Q). */ - override fun randomElementModQ(statBytes:Int) : ElementModQ { - val b = randomBytes(MAX_BYTES_Q + statBytes) - val tmp = b.toBigInteger().mod(q) - val tmp2 = if (tmp < BigInteger.TWO) tmp + BigInteger.TWO else tmp - return ProductionElementModQ(tmp2, this) - } - - override fun binaryToElementModQ(b: ByteArray): ElementModQ { - val big = b.toBigInteger().mod(q) - return ProductionElementModQ(big, this) - } - - override fun uIntToElementModQ(i: UInt) : ElementModQ = when (i) { - 0U -> ZERO_MOD_Q - 1U -> ONE_MOD_Q - 2U -> TWO_MOD_Q - else -> ProductionElementModQ(i.toBigInteger(), this) - } - - override fun uLongToElementModQ(i: ULong) : ElementModQ = when (i) { - 0UL -> ZERO_MOD_Q - 1UL -> ONE_MOD_Q - 2UL -> TWO_MOD_Q - else -> ProductionElementModQ(i.toBigInteger(), this) - } - - override fun addQ(cues: Iterable): ElementModQ { - val sum = cues.fold(BigInteger.ZERO) { a, b -> a.plus((b as ProductionElementModQ).element) } - return ProductionElementModQ(sum.mod(q), this) - } - - override fun multP(pees: Iterable): ElementModP { - return pees.fold(ONE_MOD_P) { a, b -> a * b } - } - - override fun gPowP(exp: ElementModQ) = gModP powP exp - - override fun dLogG(p: ElementModP, maxResult: Int): Int? = dlogger.dLog(p, maxResult) - - var opCounts: HashMap = HashMap() - override fun getAndClearOpCounts(): Map { - val result = HashMap() - opCounts.forEach { (key, value) -> result[key] = value.get() } - opCounts = HashMap() - return result.toSortedMap() - } -} - -private fun Element.getCompat(other: ProductionGroupContext): BigInteger { - group.assertCompatible(other) - return when (this) { - is ProductionElementModP -> this.element - is ProductionElementModQ -> this.element - else -> throw NotImplementedError("should only be two kinds of elements") - } -} - -class ProductionElementModQ(internal val element: BigInteger, override val group: ProductionGroupContext): ElementModQ, - Element, Comparable { - - override fun byteArray(): ByteArray = element.toByteArray().normalize(32) - - private fun BigInteger.modWrap(): ElementModQ = this.mod(this@ProductionElementModQ.group.q).wrap() - private fun BigInteger.wrap(): ElementModQ = ProductionElementModQ(this, this@ProductionElementModQ.group) - - override fun isZero() = element == BigInteger.ZERO - override fun isValidElement() = element >= BigInteger.ZERO && element < this.group.q - - override operator fun compareTo(other: ElementModQ): Int = element.compareTo(other.getCompat(this.group)) - - override operator fun plus(other: ElementModQ) = - (this.element + other.getCompat(this.group)).modWrap() - - override operator fun minus(other: ElementModQ) = - this + (-other) - - override operator fun times(other: ElementModQ) = - (this.element * other.getCompat(this.group)).modWrap() - - override fun multInv(): ElementModQ = element.modInverse(this.group.q).wrap() - - override operator fun unaryMinus(): ElementModQ = - if (this == this.group.zeroModQ) - this - else - (this.group.q - element).wrap() - - override infix operator fun div(denominator: ElementModQ): ElementModQ = - this * denominator.multInv() - - - override fun equals(other: Any?) = when (other) { - is ElementModQ -> byteArray().contentEquals(other.byteArray()) - else -> false - } - - override fun hashCode() = byteArray().contentHashCode() - - override fun toString() = byteArray().toBase64() -} - -open class ProductionElementModP(internal val element: BigInteger, val groupContext: ProductionGroupContext): ElementModP, - Element, Comparable { - - override fun byteArray(): ByteArray = element.toByteArray().normalize(512) - - private fun BigInteger.modWrap(): ElementModP = this.mod(groupContext.p).wrap() - private fun BigInteger.wrap(): ElementModP = ProductionElementModP(this, groupContext) - - override val group: GroupContext - get() = groupContext - - override operator fun compareTo(other: ElementModP): Int = element.compareTo(other.getCompat(groupContext)) - - /** - * Validates that this element is in Z_p^r, "set of r-th-residues in Z_p". - * "A value x is in Z_p^r if and only if x is an integer such that 0 ≤ x < p - * and x^q mod p == 1", see spec 2.0 p.9. - */ - override fun isValidElement(): Boolean { - groupContext.opCounts.getOrPut("exp") { AtomicInteger(0) }.incrementAndGet() - val inBounds = this.element >= BigInteger.ZERO && this.element < groupContext.p - val residue = this.element.modPow(groupContext.q, groupContext.p) == groupContext.oneModP.element - return inBounds && residue - } - - override infix fun powP(exp: ElementModQ) : ElementModP { - groupContext.opCounts.getOrPut("exp") { AtomicInteger(0) }.incrementAndGet() - return this.element.modPow(exp.getCompat(groupContext), groupContext.p).wrap() - } - - override operator fun times(other: ElementModP) = - (this.element * other.getCompat(groupContext)).modWrap() - - override fun multInv() - = element.modInverse(groupContext.p).wrap() -// = this powP groupContext.qMinus1Q - - // Performance note: multInv() can be expressed with the modInverse() method or we can do - // this exponentiation thing with Q - 1, which works for the subgroup. On the JVM, we get - // basically the same performance either way. - - override infix operator fun div(denominator: ElementModP) = - (element * denominator.getCompat(groupContext).modInverse(groupContext.p)).modWrap() - - override fun acceleratePow() : ElementModP = - AcceleratedElementModP(this) - - fun toMontgomeryElementModP(): MontgomeryElementModP = - ProductionMontgomeryElementModP( - element.shiftLeft(groupContext.productionMode.numBitsInP).mod(groupContext.p), - groupContext) - - override fun equals(other: Any?) = when (other) { - is ElementModP -> byteArray().contentEquals(other.byteArray()) - else -> false - } - - override fun hashCode() = byteArray().contentHashCode() - - override fun toString() = byteArray().toBase64() -} - -class AcceleratedElementModP(p: ProductionElementModP) : ProductionElementModP(p.element, p.groupContext) { - // Laziness to delay computation of the table until its first use; saves space - val powRadix by lazy { PowRadix(p, p.groupContext.powRadixOption) } - - override fun acceleratePow(): ElementModP = this - - override infix fun powP(exp: ElementModQ) : ElementModP { - groupContext.opCounts.getOrPut("acc") { AtomicInteger(0) }.incrementAndGet() - return powRadix.pow(exp) - } -} - -internal data class ProductionMontgomeryElementModP(val element: BigInteger, val groupContext: ProductionGroupContext): - MontgomeryElementModP { - internal fun MontgomeryElementModP.getCompat(other: GroupContext): BigInteger { - context.assertCompatible(other) - if (this is ProductionMontgomeryElementModP) { - return this.element - } else { - throw NotImplementedError("unexpected MontgomeryElementModP type") - } - } - - internal fun BigInteger.modI(): BigInteger = this and groupContext.montgomeryIMinusOne - - internal fun BigInteger.divI(): BigInteger = this shr groupContext.productionMode.numBitsInP - - override fun times(other: MontgomeryElementModP): MontgomeryElementModP { - // w = aI * bI = (ab)(I^2) - val w: BigInteger = this.element * other.getCompat(this.context) - - // Z = ((((W mod I)⋅p^' ) mod I)⋅p+W)/I - val z: BigInteger = (((w.modI() * groupContext.montgomeryPPrime).modI() * groupContext.p) + w).divI() - - return ProductionMontgomeryElementModP( - if (z >= groupContext.p) z - groupContext.p else z, - groupContext) - } - - override fun toElementModP(): ElementModP = - ProductionElementModP((element * groupContext.montgomeryIPrime).mod(groupContext.p), groupContext) - - override val context: GroupContext - get() = groupContext - -} diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupContext.kt b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupContext.kt new file mode 100644 index 0000000..47bb411 --- /dev/null +++ b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupContext.kt @@ -0,0 +1,152 @@ +package org.cryptobiotic.eg.core.intgroup + +import org.cryptobiotic.eg.core.* +import java.math.BigInteger +import java.util.concurrent.atomic.AtomicInteger + +class IntGroupContext( + pBytes: ByteArray, + qBytes: ByteArray, + gBytes: ByteArray, + rBytes: ByteArray, + montIMinus1Bytes: ByteArray, + montIPrimeBytes: ByteArray, + montPPrimeBytes: ByteArray, + val name: String, + val powRadixOption: PowRadixOption, + val productionMode: ProductionMode, + val numPBits: Int +) : GroupContext { + val p: BigInteger + val q: BigInteger + val g: BigInteger + val r: BigInteger + val oneModP: IntElementModP + val gModP: IntElementModP + val zeroModQ: IntElementModQ + val oneModQ: IntElementModQ + val twoModQ: IntElementModQ + val dlogger: DLogarithm + val qMinus1Q: IntElementModQ + val montgomeryIMinusOne: BigInteger + val montgomeryIPrime: BigInteger + val montgomeryPPrime: BigInteger + + init { + p = pBytes.toBigInteger() + q = qBytes.toBigInteger() + g = gBytes.toBigInteger() + r = rBytes.toBigInteger() + oneModP = IntElementModP(1U.toBigInteger(), this) + gModP = IntElementModP(g, this).acceleratePow() as IntElementModP + zeroModQ = IntElementModQ(0U.toBigInteger(), this) + oneModQ = IntElementModQ(1U.toBigInteger(), this) + twoModQ = IntElementModQ(2U.toBigInteger(), this) + dlogger = DLogarithm(gModP) + qMinus1Q = (zeroModQ - oneModQ) as IntElementModQ + montgomeryIMinusOne = montIMinus1Bytes.toBigInteger() + montgomeryIPrime = montIPrimeBytes.toBigInteger() + montgomeryPPrime = montPPrimeBytes.toBigInteger() + } + + val groupConstants = IntGroupConstants(name, p, q, r, g) + val pm1overq = (p - BigInteger.ONE).div(q) // (p-1)/q + + override val constants = groupConstants.constants + + override fun toString() : String = name + + override val ONE_MOD_P : ElementModP + get() = oneModP + + override val G_MOD_P + get() = gModP + + override val ZERO_MOD_Q + get() = zeroModQ + + override val ONE_MOD_Q + get() = oneModQ + + override val TWO_MOD_Q + get() = twoModQ + + override val MAX_BYTES_P: Int + get() = 512 + + override val MAX_BYTES_Q: Int + get() = 32 + + override val NUM_P_BITS: Int + get() = numPBits + + override fun isCompatible(ctx: GroupContext): Boolean { + return (ctx is IntGroupContext) && productionMode == ctx.productionMode + } + + /** Returns a random number in [2, P). */ + override fun randomElementModP(statBytes:Int): ElementModP { + val b = randomBytes(MAX_BYTES_P+statBytes) + val bi = b.toBigInteger() + val ti = bi.modPow(pm1overq, p) // by magic this makes it into a group element + + val tinbounds = if (ti < BigInteger.TWO) ti + BigInteger.TWO else ti + return IntElementModP(tinbounds, this) + } + + override fun binaryToElementModP(b: ByteArray): ElementModP? = + try { + val tmp = b.toBigInteger() + if (tmp >= p || tmp < BigInteger.ZERO) null else IntElementModP(tmp, this) + } catch (t : Throwable) { + null + } + + /** Returns a random number in [2, Q). */ + override fun randomElementModQ(statBytes:Int) : ElementModQ { + val b = randomBytes(MAX_BYTES_Q + statBytes) + val tmp = b.toBigInteger().mod(q) + val tmp2 = if (tmp < BigInteger.TWO) tmp + BigInteger.TWO else tmp + return IntElementModQ(tmp2, this) + } + + override fun binaryToElementModQ(b: ByteArray): ElementModQ { + val big = b.toBigInteger().mod(q) + return IntElementModQ(big, this) + } + + override fun uIntToElementModQ(i: UInt) : ElementModQ = when (i) { + 0U -> ZERO_MOD_Q + 1U -> ONE_MOD_Q + 2U -> TWO_MOD_Q + else -> IntElementModQ(i.toBigInteger(), this) + } + + override fun uLongToElementModQ(i: ULong) : ElementModQ = when (i) { + 0UL -> ZERO_MOD_Q + 1UL -> ONE_MOD_Q + 2UL -> TWO_MOD_Q + else -> IntElementModQ(i.toBigInteger(), this) + } + + override fun addQ(cues: Iterable): ElementModQ { + val sum = cues.fold(BigInteger.ZERO) { a, b -> a.plus((b as IntElementModQ).element) } + return IntElementModQ(sum.mod(q), this) + } + + override fun multP(pees: Iterable): ElementModP { + return pees.fold(ONE_MOD_P) { a, b -> a * b } + } + + override fun gPowP(exp: ElementModQ) = gModP powP exp + + override fun dLogG(p: ElementModP, maxResult: Int): Int? = dlogger.dLog(p, maxResult) + + var opCounts: HashMap = HashMap() + override fun getAndClearOpCounts(): Map { + val result = HashMap() + opCounts.forEach { (key, value) -> result[key] = value.get() } + opCounts = HashMap() + return result.toSortedMap() + } +} diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroups.kt b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroups.kt index 85b7757..a570c53 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroups.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroups.kt @@ -53,9 +53,9 @@ enum class ProductionMode(val numBitsInP: Int) { private val montgomeryI4096 = BigInteger.ONE shl Primes4096.nbits private val p4096 = BigInteger(Primes4096.pStr, 16) -private val productionGroups4096 : Map = +private val productionGroups4096 : Map = PowRadixOption.entries.associateWith { - ProductionGroupContext( + IntGroupContext( pBytes = Primes4096.largePrimeBytes, qBytes = Primes4096.smallPrimeBytes, gBytes = Primes4096.generatorBytes, @@ -73,9 +73,9 @@ private val productionGroups4096 : Map = private val montgomeryI3072 = BigInteger.ONE shl Primes3072.nbits private val p3072 = BigInteger(Primes3072.pStr, 16) -private val productionGroups3072 : Map = +private val productionGroups3072 : Map = PowRadixOption.entries.associateWith { - ProductionGroupContext( + IntGroupContext( pBytes = Primes3072.largePrimeBytes, qBytes = Primes3072.smallPrimeBytes, gBytes = Primes3072.generatorBytes, diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/PowRadix.kt b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/PowRadix.kt index b514c43..c09b747 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/PowRadix.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/PowRadix.kt @@ -63,7 +63,7 @@ interface MontgomeryElementModP { * * @see PowRadixOption */ -class PowRadix(val basis: ProductionElementModP, val acceleration: PowRadixOption) { +class PowRadix(val basis: IntElementModP, val acceleration: PowRadixOption) { internal val tableLength: Int internal val numColumns: Int internal val table: Array> @@ -71,7 +71,7 @@ class PowRadix(val basis: ProductionElementModP, val acceleration: PowRadixOptio init { val k = acceleration.numBits val mBasis = basis.toMontgomeryElementModP() - montgomeryOne = (basis.group.ONE_MOD_P as ProductionElementModP).toMontgomeryElementModP() + montgomeryOne = (basis.group.ONE_MOD_P as IntElementModP).toMontgomeryElementModP() if (k == 0) { tableLength = 0 diff --git a/src/main/kotlin/org/cryptobiotic/eg/verifier/Verifier.kt b/src/main/kotlin/org/cryptobiotic/eg/verifier/Verifier.kt index c7105f5..bf9281b 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/verifier/Verifier.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/verifier/Verifier.kt @@ -5,7 +5,7 @@ import com.github.michaelbull.result.* import org.cryptobiotic.eg.core.* import org.cryptobiotic.eg.core.intgroup.IntGroupConstants import org.cryptobiotic.eg.core.intgroup.Primes4096 -import org.cryptobiotic.eg.core.intgroup.ProductionGroupContext +import org.cryptobiotic.eg.core.intgroup.IntGroupContext import org.cryptobiotic.eg.election.* import org.cryptobiotic.eg.publish.ElectionRecord import org.cryptobiotic.util.ErrorMessages @@ -131,7 +131,7 @@ class Verifier(val record: ElectionRecord, val nthreads: Int = 11) { } if (group.constants.type == GroupType.IntegerGroup) { - val constants: IntGroupConstants = (group as ProductionGroupContext).groupConstants + val constants: IntGroupConstants = (group as IntGroupContext).groupConstants if (!constants.largePrime.toByteArray().normalize(512).contentEquals(Primes4096.largePrimeBytes)) { check.add(Err(" 1.B The large prime is not equal to p defined in Section 3.1.1")) diff --git a/src/test/kotlin/org/cryptobiotic/eg/core/TestBase64.kt b/src/test/kotlin/org/cryptobiotic/eg/core/TestBase64.kt index 9564d7c..fad1382 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/core/TestBase64.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/core/TestBase64.kt @@ -15,7 +15,7 @@ import org.cryptobiotic.eg.core.Base64.fromBase64Safe import org.cryptobiotic.eg.core.Base64.fromBase64Url import org.cryptobiotic.eg.core.Base64.toBase64 import org.cryptobiotic.eg.core.Base64.toBase64Url -import org.cryptobiotic.eg.core.intgroup.ProductionGroupContext +import org.cryptobiotic.eg.core.intgroup.IntGroupContext import java.nio.charset.StandardCharsets import kotlin.test.* @@ -143,7 +143,7 @@ class TestBase64 { @Test fun testConstants() { val group = productionGroup("Integer4096") - val constants = (group as ProductionGroupContext).groupConstants + val constants = (group as IntGroupContext).groupConstants println("smallPrime size= ${constants.smallPrime.toByteArray().size}") println("smallPrime = ${constants.smallPrime.toHex()}") diff --git a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/ElementEqualityTest.kt b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/GroupElementEqualityTest.kt similarity index 90% rename from src/test/kotlin/org/cryptobiotic/eg/core/intgroup/ElementEqualityTest.kt rename to src/test/kotlin/org/cryptobiotic/eg/core/intgroup/GroupElementEqualityTest.kt index 3b2098e..e7db347 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/ElementEqualityTest.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/GroupElementEqualityTest.kt @@ -11,14 +11,14 @@ class ElementEqualityTest { /** Test ElementModQ compares equal even when BigInteger is unnormalized. */ @Test fun testElementModQ() { - val group = productionIntGroup() as ProductionGroupContext + val group = productionIntGroup() as IntGroupContext val bi = BigInteger("89378920920032937196531702992192972263302712977973574040976517358784464109329") - val biq: ElementModQ = ProductionElementModQ(bi, group) + val biq: ElementModQ = IntElementModQ(bi, group) val biu: UInt256 = biq.toUInt256safe() assertEquals(biu.toString(), "UInt256(0xC59AAD302F149A018F925AEC7B819C6F890441F0954C36C198FD0066C5A93F11)") val bi2 = BigInteger("-26413168317283258227039282016494935589967271687666989998481066649128665530607") - val biq2: ElementModQ = ProductionElementModQ(bi2, group) + val biq2: ElementModQ = IntElementModQ(bi2, group) val biu2: UInt256 = biq2.toUInt256safe() assertEquals(biu2.toString(), "UInt256(0xC59AAD302F149A018F925AEC7B819C6F890441F0954C36C198FD0066C5A93F11)") @@ -35,7 +35,7 @@ class ElementEqualityTest { /** Test ElementModP compares equal even when BigInteger is unnormalized. */ @Test fun testElementModP() { - val group = productionIntGroup() as ProductionGroupContext + val group = productionIntGroup() as IntGroupContext val big10 = BigInteger( "-985885428196823793871112996193692117877338077477509313481176490080043572707575411869476082314071793964095333398744714332767945309577734923855959666952312525705983935794224254844921191506542799980986277785730101641969998008950665607552674779780255443794340755631453736511195965846294137817959149387975188426988363938995046173983376227628568878079936975107253562158738016217863695915516514543524467023351623372147699587151823964788878931625535092111399233104855398144355716461292664016469938048164770562262915176131141149306974339848374124423701816561022798560781880074347370789098569941039608169169423225225700784888687065727520873473846824836442424518979566061683638437879690405121721580003679584987758993406983880687066931891663303142191385688382810398036456017524079326674174907842832390598151860062729968684600437956686678947144020988482631829670396480266255416655992443923337019632004174957302256795150925344684757543832824644645093832263068544636807355769443006223707566815533908185857489241864957258108438753697424938535863201731916633015843613633242770037047355829251893057397651915198708984643944247423365612497135095192340593592328347935363489421152889044708789452933119622244096831912473291882094524612876636835909701347" ) @@ -44,11 +44,11 @@ class ElementEqualityTest { 16 ) assertEquals(big10, big16) - val p: ElementModP = ProductionElementModP(big10, group) + val p: ElementModP = IntElementModP(big10, group) val normalized = p.byteArray() val bign = BigInteger(1, normalized) - val pn = ProductionElementModP(bign, group) + val pn = IntElementModP(bign, group) assertNotEquals(big10, bign) assertEquals(p, pn) @@ -59,7 +59,7 @@ class ElementEqualityTest { /** Shows that BigIntegers's cant be normalized by normalizing the byte array in the constructor. */ @Test fun testNormalizedBigIntegers() { - val group = productionIntGroup() as ProductionGroupContext + val group = productionIntGroup() as IntGroupContext val q2 = group.TWO_MOD_Q val q2b: BigInteger = q2.element assertNotEquals(q2b.toByteArray().size, 32) @@ -67,7 +67,7 @@ class ElementEqualityTest { val ba : ByteArray = q2.element.toByteArray() val ban = ba.normalize(32) assertEquals(ban.size, 32) - val q2n = ProductionElementModQ(BigInteger(ban), group) + val q2n = IntElementModQ(BigInteger(ban), group) assertEquals(q2, q2n) val q2nb: BigInteger = q2n.element diff --git a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupConstantsTest.kt b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupConstantsTest.kt index eedc1ab..8fe38c0 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupConstantsTest.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupConstantsTest.kt @@ -23,17 +23,17 @@ class IntGroupConstantsTest { productionIntGroup( acceleration = PowRadixOption.NO_ACCELERATION, mode = ProductionMode.Mode4096 - ) as ProductionGroupContext + ) as IntGroupContext val productionGroup2 = productionIntGroup( acceleration = PowRadixOption.LOW_MEMORY_USE, mode = ProductionMode.Mode4096 - ) as ProductionGroupContext + ) as IntGroupContext val productionGroup3 = productionIntGroup( acceleration = PowRadixOption.LOW_MEMORY_USE, mode = ProductionMode.Mode3072 - ) as ProductionGroupContext + ) as IntGroupContext assertTrue(tinyGroup.groupConstants.isCompatible(tinyGroup.groupConstants)) assertFalse(tinyGroup.groupConstants.isCompatible(productionGroup1.groupConstants)) @@ -61,7 +61,7 @@ class IntGroupConstantsTest { @Test fun testConstants() { - val group = productionIntGroup() as ProductionGroupContext + val group = productionIntGroup() as IntGroupContext val constants = group.groupConstants println("smallPrime size= ${constants.smallPrime.toByteArray().size}") diff --git a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/MontgomeryTest.kt b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/MontgomeryTest.kt index 6b7563c..743d32e 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/MontgomeryTest.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/MontgomeryTest.kt @@ -33,14 +33,14 @@ class MontgomeryTest { fun shiftyModAndDiv(contextF: () -> GroupContext) { runTest { - val context = contextF() as ProductionGroupContext + val context = contextF() as IntGroupContext checkAll( propTestSlowConfig, validResiduesOfP(context), validResiduesOfP((context)) ) { a, b -> - val aVal = (a as ProductionElementModP).toMontgomeryElementModP() as ProductionMontgomeryElementModP - val bVal = (b as ProductionElementModP).toMontgomeryElementModP() as ProductionMontgomeryElementModP + val aVal = (a as IntElementModP).toMontgomeryElementModP() as ProductionMontgomeryElementModP + val bVal = (b as IntElementModP).toMontgomeryElementModP() as ProductionMontgomeryElementModP with (aVal) { val twoPowPBits = BigInteger.TWO.pow(context.NUM_P_BITS) assertEquals(element, element.modI()) @@ -69,7 +69,7 @@ class MontgomeryTest { runTest { listOf(productionGroup("Integer4096"), productionGroup("Integer3072")) .forEach { context -> - val pContext = context as ProductionGroupContext + val pContext = context as IntGroupContext val pPrime = pContext.montgomeryPPrime val p = pContext.p val iPrime = pContext.montgomeryIPrime diff --git a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/PowRadixTest.kt b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/PowRadixTest.kt index de7186b..ccb0b9c 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/PowRadixTest.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/PowRadixTest.kt @@ -76,7 +76,7 @@ class PowRadixTest { fun bitSlicingBasics() { val option = PowRadixOption.LOW_MEMORY_USE val ctx = productionIntGroup(option) - val powRadix = PowRadix(ctx.G_MOD_P as ProductionElementModP, option) + val powRadix = PowRadix(ctx.G_MOD_P as IntElementModP, option) val bytes = 258.toElementModQ(ctx).byteArray() // validate it's big-endian @@ -113,7 +113,7 @@ class PowRadixTest { runTest { val ctxSlow = productionIntGroup(acceleration = PowRadixOption.NO_ACCELERATION) - val powRadix = PowRadix(ctxSlow.G_MOD_P as ProductionElementModP, option) + val powRadix = PowRadix(ctxSlow.G_MOD_P as IntElementModP, option) assertEquals(ctxSlow.ONE_MOD_P, powRadix.pow(0.toElementModQ(ctxSlow))) assertEquals(ctxSlow.G_MOD_P, powRadix.pow(1.toElementModQ(ctxSlow))) diff --git a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/PrimesTest.kt b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/PrimesTest.kt index 1ed3db2..89a0dbe 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/PrimesTest.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/PrimesTest.kt @@ -5,6 +5,7 @@ import org.cryptobiotic.eg.core.Base64.fromBase64Safe import org.cryptobiotic.eg.core.Base64.toBase64 import org.cryptobiotic.eg.core.hashFunction import org.cryptobiotic.eg.core.normalize +import org.cryptobiotic.eg.core.toBigInteger import org.cryptobiotic.eg.election.parameterBaseHash import org.junit.jupiter.api.Test import java.math.BigInteger diff --git a/src/test/kotlin/org/cryptobiotic/eg/publish/json/ElementsTest.kt b/src/test/kotlin/org/cryptobiotic/eg/publish/json/ElementsTest.kt index 44c158a..5de33cd 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/publish/json/ElementsTest.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/publish/json/ElementsTest.kt @@ -47,7 +47,7 @@ class ElementsTest { fun testElementRoundtrip(group: GroupContext) { runTest { checkAll( - iterations = 10000, + iterations = 100, elementsModP(group), elementsModQ(group) ) { p, q ->