Skip to content

Commit

Permalink
Merge pull request #82 from JohnLCaron/randomElement
Browse files Browse the repository at this point in the history
Redo randomElementModP/Q
  • Loading branch information
JohnLCaron authored May 18, 2024
2 parents 30380c0 + ed9a0e8 commit 81df478
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 45 deletions.
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

0 comments on commit 81df478

Please sign in to comment.