-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #81 from JohnLCaron/intGroupContext
Break Elements out of GroupContext.
- Loading branch information
Showing
19 changed files
with
446 additions
and
421 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<ElementModQ> { | ||
/** 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<ElementModP> { | ||
|
||
/** 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)}" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 0 additions & 1 deletion
1
src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/EcGroupContext.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 124 additions & 0 deletions
124
src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntElementModP.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<ElementModP> { | ||
|
||
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 | ||
|
||
} |
60 changes: 60 additions & 0 deletions
60
src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntElementModQ.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<ElementModQ> { | ||
|
||
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") | ||
} | ||
} |
Oops, something went wrong.