Skip to content

Commit

Permalink
Update hash_to_curve to latest spec requirement
Browse files Browse the repository at this point in the history
  • Loading branch information
thunderbiscuit committed Mar 21, 2024
1 parent 2e80eaf commit bee9f31
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 7 deletions.
20 changes: 16 additions & 4 deletions lib/src/main/kotlin/me/tb/cashuclient/Utilities.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ package me.tb.cashuclient
import fr.acinq.bitcoin.PublicKey
import fr.acinq.bitcoin.crypto.Digest
import me.tb.cashuclient.types.SwapRequired
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.security.SecureRandom
import kotlin.math.pow

Expand All @@ -33,19 +35,29 @@ public fun decomposeAmount(value: ULong): List<ULong> {
*/
public fun hashToCurve(message: ByteArray): PublicKey {
var point: PublicKey? = null
var msgToHash: ByteArray = message
val domainSeparator: ByteArray = "Secp256k1_HashToCurve_Cashu_".toByteArray()
val msgToHash: ByteArray = Digest.sha256().hash(domainSeparator + message)
var counter: UInt = 0u

while (point == null || !point.isValid()) {
val hash: ByteArray = Digest.sha256().hash(msgToHash)
val counterBytes = ByteBuffer.allocate(Long.SIZE_BYTES)
.order(ByteOrder.LITTLE_ENDIAN)
.putLong(counter.toLong())
.array()
.take(4)
.toByteArray()

val hash: ByteArray = Digest.sha256().hash(msgToHash + counterBytes)

// The point on the curve will always have an even y-coordinate (0x02 prefix)
// For more information as to why this doesn't impact security, see: https://github.com/cashubtc/nuts/issues/24
point = PublicKey(byteArrayOf(0x02) + hash)

// If the hash of the message did not produce a valid point, we hash the hash and try again
// If the hash of the message did not produce a valid point, we bump the counter and try again
if (!point.isValid()) {
msgToHash = hash
counter++
}
// TODO: If we've tried 2^32 times and still haven't found a valid point, we throw an error
}
return point
}
Expand Down
6 changes: 3 additions & 3 deletions lib/src/test/kotlin/me/tb/cashuclient/NUTsTestVectors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,21 @@ class NUTsTestVectors {
val message1: ByteArray = Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")
val point1: PublicKey = hashToCurve(message1)
assertEquals<String>(
expected = "0266687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925",
expected = "024cce997d3b518f739663b757deaec95bcd9473c30a14ac2fd04023a739d1a725",
actual = point1.toHex()
)

val message2: ByteArray = Hex.decode("0000000000000000000000000000000000000000000000000000000000000001")
val point2: PublicKey = hashToCurve(message2)
assertEquals<String>(
expected = "02ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5",
expected = "022e7158e11c9506f1aa4248bf531298daa7febd6194f003edcd9b93ade6253acf",
actual = point2.toHex()
)

val message3: ByteArray = Hex.decode("0000000000000000000000000000000000000000000000000000000000000002")
val point3: PublicKey = hashToCurve(message3)
assertEquals<String>(
expected = "02076c988b353fcbb748178ecb286bc9d0b4acf474d4ba31ba62334e46c97c416a",
expected = "026cdbe15362df59cd1dd3c9c11de8aedac2106eca69236ecd9fbe117af897be4f",
actual = point3.toHex()
)
}
Expand Down

0 comments on commit bee9f31

Please sign in to comment.