From 10c4a7fa31c3f64cacf04d7931e91e6ceec21cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Such=C3=BD?= Date: Tue, 25 Nov 2025 23:11:32 +0100 Subject: [PATCH] fix: keccak256 treats string as utf8 not hex --- cpp/HybridNativeUtils.cpp | 12 ------------ cpp/HybridNativeUtils.hpp | 1 - src/NativeUtils.nitro.ts | 1 - src/index.tsx | 12 ++++++++---- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/cpp/HybridNativeUtils.cpp b/cpp/HybridNativeUtils.cpp index c999547..20f0de1 100644 --- a/cpp/HybridNativeUtils.cpp +++ b/cpp/HybridNativeUtils.cpp @@ -133,18 +133,6 @@ static std::shared_ptr keccak256Hash(const uint8_t* dataBytes, size return result; } -std::shared_ptr HybridNativeUtils::keccak256(const std::string& data) { - validateHexString(data); - - size_t dataLen = data.length() / 2; - - auto dataBuffer = ArrayBuffer::allocate(dataLen); - uint8_t* dataBytes = static_cast(dataBuffer->data()); - - hexToBytes(data, dataBytes, dataLen); - - return keccak256FromBytes(dataBuffer); -} std::shared_ptr HybridNativeUtils::keccak256FromBytes(const std::shared_ptr& data) { // Get the data bytes const uint8_t* dataBytes = static_cast(data->data()); diff --git a/cpp/HybridNativeUtils.hpp b/cpp/HybridNativeUtils.hpp index ee92eac..9d87658 100644 --- a/cpp/HybridNativeUtils.hpp +++ b/cpp/HybridNativeUtils.hpp @@ -14,7 +14,6 @@ class HybridNativeUtils : public HybridNativeUtilsSpec { std::shared_ptr toPublicKeyFromBytes(const std::shared_ptr& privateKey, bool isCompressed) override; std::shared_ptr getPublicKeyEd25519(const std::string& privateKey) override; std::shared_ptr getPublicKeyEd25519FromBytes(const std::shared_ptr& privateKey) override; - std::shared_ptr keccak256(const std::string& data) override; std::shared_ptr keccak256FromBytes(const std::shared_ptr& data) override; std::shared_ptr pubToAddress(const std::shared_ptr& pubKey, bool sanitize = false) override; std::shared_ptr hmacSha512(const std::shared_ptr& key, const std::shared_ptr& data) override; diff --git a/src/NativeUtils.nitro.ts b/src/NativeUtils.nitro.ts index 8f254cb..bc14e75 100644 --- a/src/NativeUtils.nitro.ts +++ b/src/NativeUtils.nitro.ts @@ -10,7 +10,6 @@ export interface NativeUtils ): ArrayBuffer; getPublicKeyEd25519(privateKey: string): ArrayBuffer; getPublicKeyEd25519FromBytes(privateKey: ArrayBuffer): ArrayBuffer; - keccak256(data: string): ArrayBuffer; keccak256FromBytes(data: ArrayBuffer): ArrayBuffer; pubToAddress(pubKey: ArrayBuffer, sanitize: boolean): ArrayBuffer; hmacSha512(key: ArrayBuffer, data: ArrayBuffer): ArrayBuffer; diff --git a/src/index.tsx b/src/index.tsx index 200c5fa..4a33fec 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -66,9 +66,10 @@ export function getPublicKey( /** * Compute Keccak-256 hash using native implementation. + * 100% compatible with @noble/hashes keccak_256 API. * Accepts multiple input types for maximum flexibility. * - * @param data - The data to hash as string (hex), number[], ArrayBuffer, or Uint8Array + * @param data - The data to hash as string (UTF-8), number[], ArrayBuffer, or Uint8Array * @returns Uint8Array containing the 32-byte Keccak-256 hash */ export function keccak256( @@ -77,8 +78,11 @@ export function keccak256( let result: ArrayBuffer; if (typeof data === 'string') { - // Assume hex string, use the string version (C++ will handle hex validation) - result = NativeUtilsHybridObject.keccak256(data); + // Match noble's behavior: treat string as UTF-8 text, not hex + const encoder = new TextEncoder(); + const bytes = encoder.encode(data); + const buffer = uint8ArrayToArrayBuffer(bytes); + result = NativeUtilsHybridObject.keccak256FromBytes(buffer); } else if (Array.isArray(data)) { // Convert number array to Uint8Array, then to ArrayBuffer const bytes = numberArrayToUint8Array(data); @@ -93,7 +97,7 @@ export function keccak256( result = NativeUtilsHybridObject.keccak256FromBytes(buffer); } else { throw new Error( - 'Data must be a hex string, number[], ArrayBuffer, or Uint8Array', + 'Data must be a string, number[], ArrayBuffer, or Uint8Array', ); }