以太坊交易签名实战:token-core-android 中 RLP 编码与 EIP-155 全流程
【免费下载链接】token-core-androida blockchain private key management library on android项目地址: https://gitcode.com/gh_mirrors/to/token-core-android
对于刚接触区块链开发的 Android 工程师来说,以太坊交易签名往往是一道绕不开的门槛:非对称加密、Keccak-256、RLP 编码、EIP-155……一系列名词扑面而来。而token-core-android正是一个专注于区块链私钥管理与离线签名的 Android 库,它用不到两百行核心代码,把"构造交易 → 编码 → 签名 → 广播"的完整链路封装得清晰易懂。本文将以源码为线索,带你一步步拆解以太坊交易签名全流程,彻底搞懂 RLP 编码与 EIP-155 重放保护背后的原理。
一次以太坊交易签名,到底经历了哪几步?
以太坊交易签名绝不是"给字符串加个密"这么简单。在 token-core-android 中,一次完整的签名流程分为四个阶段:
- RLP 编码:把 nonce、gasPrice、gasLimit、to、value、data 六个字段按固定顺序编码为字节流;
- 哈希与 ECDSA 签名:对编码结果做 Keccak-256 哈希,再用私钥生成 (v, r, s) 签名;
- EIP-155 二次编码:把链 ID 折叠进 v 值,重新 RLP 编码得到可广播的原始交易;
- 计算交易哈希:对签名后的交易再做一次 Keccak-256,得到可查询的 txHash。
这四步分别对应四个核心类,下面逐一深入。
第一步:交易字段的 RLP 编码规则
RLP(Recursive Length Prefix)是以太坊底层通用的序列化格式,它的规则很简单:
- 单个字节且值在 0x00~0x7f 之间,直接原样输出;
- 长度不超过 55 字节的字符串,前缀
0x80 + 长度; - 更长的字符串,前缀标记长度字段本身的字节数;
- 列表(List)在拼接所有元素后,前缀
0xc0 + 总长度。
token-core-android 把这三条规则完整实现在 RlpEncoder.java 中,配合 RlpString.java 与 RlpList.java 两个数据类型,构成一套简洁的 RLP 工具箱。
// RlpEncoder.java 核心逻辑 public static byte[] encode(RlpType value) { if (value instanceof RlpString) { return encodeString((RlpString) value); } else { return encodeList((RlpList) value); } }第二步:六个字段如何按顺序入列?
以太坊规定交易的 RLP 结构必须严格按nonce → gasPrice → gasLimit → to → value → data排列。在 EthereumTransaction.java 的asRlpValues()方法中,你可以看到几个非常讲究的细节:
- to 地址为空时(合约创建交易),编码为空字符串,而不是数字 0;
- to 地址带前导零时,必须按字节原样编码,防止被当作数值截断;
- data 字段需要先从十六进制字符串还原成字节数组再编码;
- 非负数、零值都有专门的处理分支,避免出现多余的前导零。
这些细节正是"看着简单、做起来容易出错"的地方,token-core-android 已经帮你全部处理妥当。
第三步:Keccak-256 哈希与 ECDSA 可恢复签名
RLP 编码完成后,签名正式开始。核心逻辑在 EthereumSign.java 中:
static SignatureData signMessage(byte[] message, byte[] prvKeyBytes) { ECKey ecKey = ECKey.fromPrivate(prvKeyBytes); byte[] messageHash = Hash.keccak256(message); return signAsRecoverable(messageHash, ecKey); }这里有两个关键点:
- Keccak-256与常见的 SHA-256 并不相同,项目在 Hash.java 中提供了原生实现;
- 可恢复签名(recoverable signature):签名结果会额外携带 recovery ID,用于反推公钥,这也是后续
ecRecover验签、恢复地址的基础。signAsRecoverable()会遍历 0~3 四个候选 ID,找到能恢复出当前公钥的那一个,最终得到 (v, r, s) 三件套,封装在 SignatureData.java 中。
第四步:EIP-155 如何防止跨链重放攻击?
早期以太坊交易只有 v = 27/28 两种取值,同一笔签名交易可以原封不动地在其他链(比如 ETC)上重放。EIP-155 提案的解决方案是:把链 ID 编码进 v 值。
在createEip155SignatureData()方法中可以看到那条经典的公式:
private static SignatureData createEip155SignatureData(SignatureData signatureData, int chainId) { int v = signatureData.getV() + (chainId * 2) + 8; return new SignatureData(v, signatureData.getR(), signatureData.getS()); }即v = 35 + chainId * 2 + recoveryId(其中 recoveryId 范围为 0~1)。这样一来,为以太坊主网签名的交易,其 v 值天然与以太坊经典(ETC)不兼容,重放攻击被从数学上杜绝。项目在 ChainId.java 中预置了常用链 ID:以太坊主网 1、Ropsten 3、Kovan 42、ETC 主网 61 等,直接引用即可。
💡 冷知识:EIP-155 签名要求先带链 ID 编码一次(此时 v 占位为链 ID、r/s 为空),哈希签名后再把真实 v 值代入重新编码。这个过程在
signTransaction(int chainId, byte[] privateKey)中完整呈现,两轮编码一步不差。
第五步:得到可广播的 signedTx 与 txHash
签名与二次编码完成后,signTransaction()返回一个 TxSignResult.java 对象,包含两个关键字段:
- signedTx:十六进制编码的原始交易(Raw Transaction),直接交给节点或钱包广播;
- txHash:对 signedTx 再做一次 Keccak-256 得到的交易哈希,用于在区块浏览器中查询交易状态。
String calcTxHash(String signedTx) { return NumericUtil.prependHexPrefix(Hash.keccak256(signedTx)); }项目在 EthereumTransactionTest.java 中保留了 EIP-155 官方测试向量,可以用固定私钥0x4646...4646验证你的实现输出是否与预期完全一致,非常适合作为自测基准。
在 Android 项目中如何快速落地?
在真实 App 中,私钥通常保存在加密 keystore 中,因此对外暴露的 API 是"密码 + 钱包"而非裸私钥:
EthereumTransaction tx = new EthereumTransaction( nonce, gasPrice, gasLimit, toAddress, value, data); TxSignResult result = tx.signTransaction( ChainId.ETHEREUM_MAINNET, password, ethereumWallet); String signedTx = result.getSignedTx(); // 广播用 String txHash = result.getTxHash(); // 查询用私钥的加解密在 Wallet.java 的decryptMainKey()中完成,签名全程在本地设备离线进行,私钥永不触网——这也是移动钱包安全性的根基。
总结:一条链路,四个关键文件
- 交易模型与 EIP-155 逻辑:EthereumTransaction.java
- Keccak-256 哈希与 ECDSA 签名:EthereumSign.java
- RLP 编码实现:RlpEncoder.java
- 签名结果载体:SignatureData.java
以太坊交易签名并不神秘:它无非是"固定字段顺序 + RLP 序列化 + Keccak-256 哈希 + ECDSA 签名 + 链 ID 防重放"的组合拳。借助 token-core-android 这份简洁的开源实现,你不仅能快速在自己的 Android 项目中接入离线签名能力,更能通过源码真正吃透底层原理,为后续深入智能合约交互、多链钱包开发打下扎实基础。😊
【免费下载链接】token-core-androida blockchain private key management library on android项目地址: https://gitcode.com/gh_mirrors/to/token-core-android
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考