You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java/Kotlin中实现与Solidity一致的getMessageHash计算功能

Solidity abi.encodePacked + keccak256 等价 Java/Kotlin 实现

核心原理

Solidity的abi.encodePacked为紧密编码模式,不会对参数做字节对齐补零,本题中三个参数的编码规则如下:

  • address类型:直接编码为20字节原始二进制
  • uint(默认等价uint256)类型:编码为32字节大端序无符号二进制,高位补零至32字节长度
    将三个参数的编码结果按顺序拼接后执行keccak256哈希,最终转为0x开头的十六进制字符串即可得到和Solidity完全一致的结果。
    你之前使用的org.web3j.crypto.Hash.sha3有接收字节数组的重载方法,不需要拼接为单个字符串再传入。

前置依赖

使用web3j的crypto工具包即可,Maven依赖示例:

<dependency>
    <groupId>org.web3j</groupId>
    <artifactId>crypto</artifactId>
    <version>4.10.0</version>
</dependency>

Kotlin 实现

import org.web3j.crypto.Hash
import org.web3j.utils.Numeric
import java.math.BigInteger

// 支持大数值入参版本
fun getMessageHash(signer: String, amount: BigInteger, id: BigInteger): String {
    // 处理address参数:去掉0x前缀转20字节数组
    val signerBytes = Numeric.hexStringToByteArray(signer.removePrefix("0x"))
    require(signerBytes.size == 20) { "非法的address格式" }

    // 处理uint256参数,转32字节大端序数组,高位补零
    val amountBytes = Numeric.toBytesPadded(amount, 32)
    val idBytes = Numeric.toBytesPadded(id, 32)

    // 拼接所有字节数组
    val totalBytes = signerBytes + amountBytes + idBytes

    // 计算keccak256并返回0x开头的十六进制字符串
    return Hash.sha3(totalBytes)
}

// Long类型入参重载,适合数值不超过Long范围的场景
fun getMessageHash(signer: String, amount: Long, id: Long): String {
    return getMessageHash(signer, amount.toBigInteger(), id.toBigInteger())
}

Java 实现

import org.web3j.crypto.Hash;
import org.web3j.utils.Numeric;
import java.math.BigInteger;

public class SolidityHashCalculator {
    // 支持大数值入参版本
    public static String getMessageHash(String signer, BigInteger amount, BigInteger id) {
        // 处理address参数
        byte[] signerBytes = Numeric.hexStringToByteArray(signer.replaceFirst("^0x", ""));
        if (signerBytes.length != 20) {
            throw new IllegalArgumentException("非法的address格式");
        }
        // 处理uint256参数
        byte[] amountBytes = Numeric.toBytesPadded(amount, 32);
        byte[] idBytes = Numeric.toBytesPadded(id, 32);
        // 拼接字节数组
        byte[] totalBytes = new byte[signerBytes.length + amountBytes.length + idBytes.length];
        System.arraycopy(signerBytes, 0, totalBytes, 0, signerBytes.length);
        System.arraycopy(amountBytes, 0, totalBytes, signerBytes.length, amountBytes.length);
        System.arraycopy(idBytes, 0, totalBytes, signerBytes.length + amountBytes.length, idBytes.length);
        // 计算哈希返回
        return Hash.sha3(totalBytes);
    }

    // long类型入参重载
    public static String getMessageHash(String signer, long amount, long id) {
        return getMessageHash(signer, BigInteger.valueOf(amount), BigInteger.valueOf(id));
    }
}

注意事项

  • 若你的Solidity代码中uint不是默认的uint256,比如是uint64,对应的转字节数组时补零长度要改为对应类型的字节数(比如uint64对应8字节)
  • 输入的address需要是合法的40/42位十六进制字符串,否则会抛出参数校验异常

内容的提问来源于stack exchange,提问作者Daguna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 10:03:03