From 83e87c2cf4243293506e9d149641918773be4f53 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 16 Sep 2025 17:06:01 -0400 Subject: [PATCH] Adds an event id hash check that doesn't create a separate bytearray to compare between the incoming hex from the relay and the recalculated byte array from SHA256. --- .../quartz/benchmark/HexBenchmark.kt | 7 +++++++ .../vitorpamplona/quartz/nip01Core/EventExt.kt | 2 +- .../quartz/nip01Core/crypto/EventHasher.kt | 15 ++++++++++++++- .../com/vitorpamplona/quartz/utils/Hex.kt | 17 +++++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HexBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HexBenchmark.kt index bb1272d4e..e4553ade8 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HexBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HexBenchmark.kt @@ -43,6 +43,13 @@ class HexBenchmark { fr.acinq.secp256k1.Hex .decode(hex) + @Test + fun hexIsEqual() { + r.measureRepeated { + assert(Hex.isEqual(hex, bytes)) + } + } + @Test fun hexDecodeOurs() { r.measureRepeated { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/EventExt.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/EventExt.kt index 81e828a65..a5cd423e0 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/EventExt.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/EventExt.kt @@ -30,7 +30,7 @@ fun Event.generateId(): String = EventHasher.hashId(pubKey, createdAt, kind, tag fun Event.verifyId(): Boolean { if (id.isEmpty()) return false - return id == generateId() + return EventHasher.hashIdEquals(id, pubKey, createdAt, kind, tags, content) } fun Event.verifySignature(): Boolean { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt index 5fcfd9e8c..c5e2e3fd3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt @@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.node.JsonNodeFactory import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.utils.Hex import com.vitorpamplona.quartz.utils.sha256.sha256 class EventHasher { @@ -80,5 +81,17 @@ class EventHasher { tags: Array>, content: String, ): String = hashIdBytes(pubKey, createdAt, kind, tags, content).toHexKey() + + fun hashIdEquals( + id: HexKey, + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: Array>, + content: String, + ): Boolean { + val outId = hashIdBytes(pubKey, createdAt, kind, tags, content) + return Hex.isEqual(id, outId) + } } -} +} \ No newline at end of file diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Hex.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Hex.kt index 270d66a5e..0ff6eec22 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Hex.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Hex.kt @@ -74,4 +74,21 @@ object Hex { } return String(out) } + + fun isEqual( + id: String, + ourId: ByteArray, + ): Boolean { + var charIndex = 0 + for (i in 0 until ourId.size) { + val chars = byteToHex[ourId[i].toInt() and 0xFF] + if ( + id[charIndex++] != (chars shr 8).toChar() || + id[charIndex++] != (chars and 0xFF).toChar() + ) { + return false + } + } + return true + } }