diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/GroupContext.kt b/src/main/kotlin/org/cryptobiotic/eg/core/GroupContext.kt index b24b93a..674e4e5 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/core/GroupContext.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/core/GroupContext.kt @@ -63,22 +63,20 @@ interface GroupContext { fun binaryToElementModQ(b: ByteArray): ElementModQ /** Converts a hash value to an [ElementModQ] */ - fun hashToElementModQ(hash: UInt256): ElementModQ = binaryToElementModQ(hash.bytes) + fun hashToElementModQ(hash: UInt256): ElementModQ /** - * Returns a random number in [2, Q). - * Add "statistical distance" when generating. + * Returns a uniform random number in [2, Q). * Uses a "secure" random number generator, such that the results are suitable for use as cryptographic keys. */ - fun randomElementModQ(statBytes:Int = 0) : ElementModQ + fun randomElementModQ() : ElementModQ /** - * Returns a random ElementModP. - * Add "statistical distance" when generating. + * Returns a uniform random ElementModP. * Uses a "secure" random number generator, such that the results are suitable for use as cryptographic keys. * TODO no one actually needs this */ - fun randomElementModP(statBytes:Int = 0) : ElementModP + fun randomElementModP() : ElementModP /** Converts an integer to an ElementModQ, with optimizations when possible for small integers */ fun uIntToElementModQ(i: UInt): ElementModQ 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 56066c9..2ea89dc 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/EcGroupContext.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/EcGroupContext.kt @@ -21,7 +21,7 @@ class EcGroupContext(val name: String, useNative: Boolean = true): GroupContext override val constants = vecGroup.constants private val dlogg = DLogarithm(G_MOD_P) - private val rfc9380 = RFC9380(this, "QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_".toByteArray(), 16) + private val rfc9380 = RFC9380(this, "QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_".toByteArray(), statBytesQ/8) override fun binaryToElementModP(b: ByteArray): ElementModP? { val elem = vecGroup.elementFromByteArray(b) @@ -32,15 +32,14 @@ class EcGroupContext(val name: String, useNative: Boolean = true): GroupContext override fun hashToElementModQ(hash: UInt256): ElementModQ = rfc9380.hash_to_field(hash.bytes) - /** 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(vecGroup.order) - val tmp2 = if (tmp < BigInteger.TWO) tmp + BigInteger.TWO else tmp - return EcElementModQ(this, tmp2) + override fun randomElementModQ() : ElementModQ { + val b = randomBytes(MAX_BYTES_Q) + return rfc9380.hash_to_field(b) } - override fun randomElementModP(statBytes:Int) = EcElementModP(this, vecGroup.randomElement(statBytes)) + override fun randomElementModP() : EcElementModP { + return EcElementModP(this, vecGroup.randomElement(statBytesP)) + } override fun dLogG(p: ElementModP, maxResult: Int): Int? { require(p is EcElementModP) @@ -52,14 +51,6 @@ class EcGroupContext(val name: String, useNative: Boolean = true): GroupContext return EcElementModP(this, vecGroup.g.exp(exp.element)) } - var opCounts: HashMap = HashMap() - override fun getAndClearOpCounts(): Map { - val result = HashMap() - opCounts.forEach { (key, value) -> result[key] = value.get() } - opCounts = HashMap() - return result.toSortedMap() - } - override fun isCompatible(ctx: GroupContext): Boolean { return (ctx is EcGroupContext) && name == ctx.name } @@ -102,4 +93,18 @@ class EcGroupContext(val name: String, useNative: Boolean = true): GroupContext val ec = vecGroup.prodPowers(bases, exps) return EcElementModP(this, ec) } + + + var opCounts: HashMap = HashMap() + override fun getAndClearOpCounts(): Map { + val result = HashMap() + opCounts.forEach { (key, value) -> result[key] = value.get() } + opCounts = HashMap() + return result.toSortedMap() + } + + companion object { + const val statBytesQ = 128 + const val statBytesP = 128 + } } diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/RFC9380.kt b/src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/RFC9380.kt index 0751302..9db7fea 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/RFC9380.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/RFC9380.kt @@ -5,7 +5,7 @@ package org.cryptobiotic.eg.core.ecgroup // You’ll need that algorithms expand_message in 5.3 and hash_to_field in 5.2, which uses expand_message. // Note that you only need to do this for m=1 (and then their q = their p) and count = 1. -// TODO see example output in Appendix J.1 of https://www.rfc-editor.org/rfc/rfc9380.pdf +// This implementation is only for P-256, and its only doing hash_to_field() not hash_to_curve(). import java.math.BigInteger import java.security.MessageDigest @@ -50,7 +50,7 @@ class RFC9380(val group: EcGroupContext, val DST: ByteArray, kBytes: Int) { //Steps: val uniform_bytes = expand_message(msg) val bi = BigInteger(1, uniform_bytes) // OS2IP equiv - return EcElementModQ(group, bi.mod(group.vecGroup.primeModulus)) + return EcElementModQ(group, bi.mod(group.vecGroup.primeModulus)) // note that p == q for P-256 } // expand_message_xmd(msg, DST, len_in_bytes) diff --git a/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupContext.kt b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupContext.kt index 47bb411..1bf0326 100644 --- a/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupContext.kt +++ b/src/main/kotlin/org/cryptobiotic/eg/core/intgroup/IntGroupContext.kt @@ -85,8 +85,8 @@ class IntGroupContext( } /** Returns a random number in [2, P). */ - override fun randomElementModP(statBytes:Int): ElementModP { - val b = randomBytes(MAX_BYTES_P+statBytes) + override fun randomElementModP(): ElementModP { + val b = randomBytes(MAX_BYTES_P) val bi = b.toBigInteger() val ti = bi.modPow(pm1overq, p) // by magic this makes it into a group element @@ -102,9 +102,11 @@ class IntGroupContext( null } + override fun hashToElementModQ(hash: UInt256): ElementModQ = binaryToElementModQ(hash.bytes) + /** Returns a random number in [2, Q). */ - override fun randomElementModQ(statBytes:Int) : ElementModQ { - val b = randomBytes(MAX_BYTES_Q + statBytes) + override fun randomElementModQ() : ElementModQ { + val b = randomBytes(MAX_BYTES_Q) val tmp = b.toBigInteger().mod(q) val tmp2 = if (tmp < BigInteger.TWO) tmp + BigInteger.TWO else tmp return IntElementModQ(tmp2, this) diff --git a/src/test/kotlin/org/cryptobiotic/eg/core/GroupTest.kt b/src/test/kotlin/org/cryptobiotic/eg/core/GroupTest.kt index 2ee570b..f67be13 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/core/GroupTest.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/core/GroupTest.kt @@ -21,7 +21,6 @@ class GroupTest { groups.forEach { testBasics(it) } groups.forEach { testBasicsL(it) } groups.forEach { testRandom(it) } - groups.forEach { testRandomWithStatBytes(it) } } fun testBasics(context: GroupContext) { @@ -41,24 +40,12 @@ class GroupTest { fun testRandom(group: GroupContext) { val randomP = group.randomElementModP() val randomQ = group.randomElementModQ() - if (!randomP.isValidElement()) { - randomP.isValidElement() - } assertTrue(randomP.isValidElement(),"group ${group.constants.name}") assertTrue(randomQ.isValidElement(), "group ${group.constants.name}") println("random p= ${randomP.toStringShort()} random q = $randomQ are ok") } - fun testRandomWithStatBytes(group: GroupContext) { - val randomP = group.randomElementModP(16) - val randomQ = group.randomElementModQ(16) - assertTrue(randomP.isValidElement(), "group ${group.constants.name}") - assertTrue(randomQ.isValidElement(), "group ${group.constants.name}") - - println("random p= ${randomP.toStringShort()} random q = $randomQ are ok") - } - @Test fun comparisonOperations() { groups.forEach { comparisonOperations(it) } diff --git a/src/test/kotlin/org/cryptobiotic/eg/core/ecgroup/TestAgainstNative.kt b/src/test/kotlin/org/cryptobiotic/eg/core/ecgroup/TestAgainstNative.kt index 2bb08bb..15b21de 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/core/ecgroup/TestAgainstNative.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/core/ecgroup/TestAgainstNative.kt @@ -26,7 +26,6 @@ class TestAgainstNative { val elemPyt = vecGroupN.sqrt(elemPy2) assertEquals(elemP.y, elemPyt) - assertEquals(elemPy, elemPyt) } } diff --git a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/TinyGroup.kt b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/TinyGroup.kt index c4f63f5..fe85e39 100644 --- a/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/TinyGroup.kt +++ b/src/test/kotlin/org/cryptobiotic/eg/core/intgroup/TinyGroup.kt @@ -112,14 +112,16 @@ internal class TinyGroupContext( } } - override fun randomElementModQ(statBytes:Int) : ElementModQ { + override fun hashToElementModQ(hash: UInt256): ElementModQ = binaryToElementModQ(hash.bytes) + + override fun randomElementModQ() : ElementModQ { val b = randomBytes(MAX_BYTES_Q) val u32 = b.toUIntMod(q) val result = if (u32 < 2U) u32 + 2U else u32 return uIntToElementModQ(result) } - override fun randomElementModP(statBytes:Int): ElementModP { + override fun randomElementModP(): ElementModP { val tmp = binaryToElementModP(randomBytes(MAX_BYTES_P)) as TinyElementModP val modp = if (tmp.element < 2U) uIntToElementModP(tmp.element + 2U) else tmp return modp powP pm1overq // by magic this makes it into a group element