Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redo randomElementModP/Q #82

Merged
merged 1 commit into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions src/main/kotlin/org/cryptobiotic/eg/core/GroupContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 21 additions & 16 deletions src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/EcGroupContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -52,14 +51,6 @@ class EcGroupContext(val name: String, useNative: Boolean = true): GroupContext
return EcElementModP(this, vecGroup.g.exp(exp.element))
}

var opCounts: HashMap<String, AtomicInteger> = HashMap()
override fun getAndClearOpCounts(): Map<String, Int> {
val result = HashMap<String, Int>()
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
}
Expand Down Expand Up @@ -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<String, AtomicInteger> = HashMap()
override fun getAndClearOpCounts(): Map<String, Int> {
val result = HashMap<String, Int>()
opCounts.forEach { (key, value) -> result[key] = value.get() }
opCounts = HashMap()
return result.toSortedMap()
}

companion object {
const val statBytesQ = 128
const val statBytesP = 128
}
}
4 changes: 2 additions & 2 deletions src/main/kotlin/org/cryptobiotic/eg/core/ecgroup/RFC9380.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand Down
13 changes: 0 additions & 13 deletions src/test/kotlin/org/cryptobiotic/eg/core/GroupTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class TestAgainstNative {

val elemPyt = vecGroupN.sqrt(elemPy2)
assertEquals(elemP.y, elemPyt)

assertEquals(elemPy, elemPyt)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading