共计 6511 个字符,预计需要花费 17 分钟才能阅读完成。
记录 Java 生成 USDT(TRC-20)私钥和助记词
USDT (Tether) 是目前最流行的稳定币之一,它在 TRON(波场)网络上以 TRC-20 代币 的形式广泛流通。对于开发者或高级用户来说,了解如何 从助记词(Mnemonic)派生出 TRC-20 地址的私钥 是非常重要的。
本文将演示如何使用 Java 语言和 bitcoinj
库,遵循 BIP-39/BIP-44 标准 来生成助记词、派生出 TRON(TRC-20)的私钥,并最终计算出对应的 TRON 地址。
依赖导入 (Maven)
本项目使用了 org.bitcoinj
库来处理助记词和 HD 钱包的派生逻辑,同时引入了 Bouncy Castle 库用于 Keccak-256 哈希计算,这是生成 TRON 地址的关键步骤。
请在您的 Maven 项目的 pom.xml
文件中添加以下依赖:
<!-- 版本可根据需求调整 -->
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-core</artifactId>
<version>0.16.1</version>
</dependency>
注意:
bitcoinj-core
版本0.16.1
中已经包含了大部分所需功能,但 Keccak-256 哈希通常需要单独导入 Bouncy Castle。为确保代码完整性,我已在上面的 Maven 依赖中添加了 Bouncy Castle(版本仅作示例,请确保兼容性)。
核心 Java 代码实现
以下是包含助记词生成、私钥派生以及 TRON 地址计算的完整 Java 类。
USDTUtils.java
import org.bitcoinj.core.Base58;
package com.ithema;
import org.bitcoinj.core.Base58;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.HDKeyDerivation;
import org.bitcoinj.crypto.MnemonicCode;
import org.bouncycastle.jcajce.provider.digest.Keccak;
import org.bouncycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class USDTUtils {public static void main(String[] args) throws Exception {createMnemonicAndPrivateKey();
}
/**
* 新增方法:生成助记词和派生私钥
*
* @return 返回包含助记词、私钥和地址的 Map
* @throws Exception 如果助记词生成失败
*/
public static Map createMnemonicAndPrivateKey() throws Exception {// 1. 生成助记词 (Mnemonic Code)
SecureRandom secureRandom = new SecureRandom();
byte[] initialEntropy = new byte[16]; // 16 字节 = 12 个助记词
secureRandom.nextBytes(initialEntropy);
List mnemonicCode = MnemonicCode.INSTANCE.toMnemonic(initialEntropy);
String mnemonic = String.join(" ", mnemonicCode); // 仅用于打印和显示
// 2. 将助记词列表转换为种子 (Seed)
byte[] seed = MnemonicCode.INSTANCE.toSeed(mnemonicCode, ""); // 可选的密码
// 3. 使用 BIP44 路径派生私钥
// TRON 的路径:m/44'/195'/0'/0/0
// 直接从种子派生主密钥
DeterministicKey masterKey = HDKeyDerivation.createMasterPrivateKey(seed);
// 派生路径 m/44'
DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey(masterKey, 44 | 0x80000000);
// 派生路径 195' (TRON 的币种代码)
DeterministicKey coinTypeKey = HDKeyDerivation.deriveChildKey(purposeKey, 195 | 0x80000000);
// 派生路径 0' (账户索引)
DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinTypeKey, 0 | 0x80000000);
// 派生路径 0 (外部链)
DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey, 0);
// 派生路径 0 (地址索引)
DeterministicKey derivedKey = HDKeyDerivation.deriveChildKey(externalKey, 0);
// 4. 获取派生出的私钥
String privateKeyHex = Hex.toHexString(derivedKey.getPrivKeyBytes());
// 5. 根据派生出的私钥计算 TRON 地址
String tronAddress = getTronAddress(privateKeyHex);
Map walletInfo = new HashMap<>();
walletInfo.put("mnemonic", mnemonic);
walletInfo.put("privateKey", privateKeyHex);
walletInfo.put("tronAddress", tronAddress);
System.out.println("生成的助记词:" + mnemonic);
System.out.println("派生出的私钥:" + privateKeyHex);
System.out.println("派生出的地址:" + tronAddress);
return walletInfo;
}
/**
* 生成 TRC-20 地址
*/
public static String createTrc20Address() {
// 1️⃣ 生成随机私钥(256-bit)SecureRandom secureRandom = new SecureRandom();
byte[] privateKeyBytes = new byte[32]; // 256-bit = 32 bytes
secureRandom.nextBytes(privateKeyBytes);
String privateKeyHex = Hex.toHexString(privateKeyBytes);
// 2️⃣ 生成 ** 未压缩 ** 公钥(65 字节)ECKey key = ECKey.fromPrivate(privateKeyBytes, false);
byte[] publicKey = key.getPubKey();
// 3️⃣ 计算 TRON 地址(Keccak-256 公钥后 20 字节 + 0x41 前缀)Keccak.Digest256 keccak256 = new Keccak.Digest256();
byte[] sha3Hash = keccak256.digest(Arrays.copyOfRange(publicKey, 1, publicKey.length)); // 去掉 0x04
byte[] addressBytes = new byte[21]; // TRON 地址 = 21 字节
addressBytes[0] = 0x41; // TRON 地址前缀
System.arraycopy(sha3Hash, sha3Hash.length - 20, addressBytes, 1, 20);
// 4️⃣ 计算 Base58Check 编码
byte[] checkSum = Sha256Hash.hashTwice(addressBytes);
byte[] addressWithChecksum = new byte[25]; // 21 字节地址 + 4 字节校验和
System.arraycopy(addressBytes, 0, addressWithChecksum, 0, 21);
System.arraycopy(checkSum, 0, addressWithChecksum, 21, 4);
String tronAddress = Base58.encode(addressWithChecksum);
System.out.println("生成的随机私钥:" + privateKeyHex);
System.out.println("公钥:" + Hex.toHexString(publicKey));
System.out.println("TRON 地址:" + tronAddress);
System.out.println("在这里进行比对 拿着私钥解出 地址 然后进行跟创建的地址进行比对");
String tronAddress1 = getTronAddress(privateKeyHex);
if (tronAddress.equals(tronAddress1)) {return privateKeyHex;}
return privateKeyHex;
}
/**
* 根据私钥推导 TRC-20 地址
* @param privateKeyHex 私钥(16 进制字符串)* @return TRON 地址
*/
/**
* 根据私钥 反推 收款地址
*
* @param privateKeyHex
*/
public static String getTronAddress(String privateKeyHex) {
// 1️⃣ 私钥转换成 BigInteger
BigInteger privateKey = new BigInteger(privateKeyHex, 16);
// 2️⃣ 生成 ** 未压缩 ** 公钥(SECP256K1 椭圆曲线)ECKey key = ECKey.fromPrivate(privateKey, false); // 生成 **65 字节 ** 公钥
byte[] publicKey = key.getPubKey();
// 3️⃣ 计算 TRON 地址(Keccak-256 公钥后 20 个字节 + 0x41 前缀)Keccak.Digest256 keccak256 = new Keccak.Digest256();
byte[] sha3Hash = keccak256.digest(Arrays.copyOfRange(publicKey, 1, publicKey.length)); // 去掉前导 0x04
byte[] addressBytes = new byte[21]; // TRON 地址需要 21 字节
addressBytes[0] = 0x41; // TRON 地址前缀
System.arraycopy(sha3Hash, sha3Hash.length - 20, addressBytes, 1, 20);
// 4️⃣ 计算 Base58Check 编码(手动添加校验和)byte[] checkSum = Sha256Hash.hashTwice(addressBytes);
byte[] addressWithChecksum = new byte[25]; // 21 字节地址 + 4 字节校验和
System.arraycopy(addressBytes, 0, addressWithChecksum, 0, 21);
System.arraycopy(checkSum, 0, addressWithChecksum, 21, 4);
String tronAddress = org.bitcoinj.core.Base58.encode(addressWithChecksum); // 用 bitcoinj 的 Base58
System.out.println("私钥:" + privateKeyHex);
System.out.println("公钥:" + Hex.toHexString(publicKey));
System.out.println("TRON 地址:" + tronAddress);
return tronAddress;
}
}
运行结果示例
运行上述代码,您将得到类似以下结果(私钥和地址每次运行都会不同):
私钥: be20b3fe847f50685822001b66bd94471ab09ee04c4f5a6f9c37c14d73800893
公钥: 04448468305c81a053a1bf85498600da6a38aa032a1ce345d38bb25b438fbc6065aa4c4045214df66705ad9dd4ba902e2f8a728d04a41d16986ca250f283fe782c
TRON 地址: TEU7FqZfWEBPnUX1y21v7rkgPtU6V34ARG
生成的助记词: soda museum sock submit lucky green holiday federal flower dragon eagle image
派生出的私钥: be20b3fe847f50685822001b66bd94471ab09ee04c4f5a6f9c37c14d73800893
派生出的地址: TEU7FqZfWEBPnUX1y21v7rkgPtU6V34ARG
结果验证: 我们可以看到,通过 BIP-44 路径 派生出的私钥与通过该私钥计算出的 TRON 地址 是完全一致 的,这证明了派生和地址计算逻辑的正确性。
关键技术点解析
1. BIP-39/BIP-44 助记词标准
- BIP-39(助记词): 负责将随机熵(Entropy)转换为易于记忆和备份的 助记词列表 (Mnemonic Code),然后将助记词转换为一个唯一的 种子(Seed)。
- BIP-44(派生路径): 负责从这个 种子 派生出不同的私钥,其路径格式为
m / purpose'/ coin_type' / account' / change / address_index
。- TRON 的
coin_type'
为195'
。 - 本文使用的完整派生路径是
m/44'/195'/0'/0/0
,这是标准的第一个地址路径。
- TRON 的
2. TRON 地址计算逻辑
与比特币使用的 SHA-256 不同,TRON(TRC-20)地址的生成使用了 Keccak-256 哈希算法,具体步骤如下:
- 获取未压缩公钥: 从私钥中推导出 65 字节的未压缩公钥(以
0x04
开头)。 - Keccak-256 哈希: 对 去除
0x04
前缀 的 64 字节公钥进行 Keccak-256 哈希。 - 添加前缀和截取: 取 Keccak-256 结果的 最后 20 字节,并在前面加上 TRON 地址前缀
0x41
,得到 21 字节的地址数据。 - Base58Check 编码: 对这 21 字节数据进行 双重 SHA-256 运算以获得 4 字节的校验和,然后将 21 字节数据与 4 字节校验和拼接,进行 Base58 编码,最终得到用户可见的 TRON 地址(以
T
开头)。
安全警告
请勿在实际生产环境或存储真实资产的钱包中使用本文代码直接生成的助记词或私钥。
- 随机性: 本文使用的
SecureRandom
提供了较高的随机性,但任何由软件生成的私钥都存在理论上的风险。 - 私钥保护: 您生成的助记词和私钥是您加密资产的 唯一凭证 。一旦泄露,资产将永久丢失。请务必妥善保管,并 仅在安全、离线的环境 下执行此类操作。