账户模型¶
账户模型介绍¶
TRON 采用账户模型进行记账。网络中的所有活动,如转账、投票、部署合约等,都围绕账户展开。
- 唯一标识:每个账户的唯一标识是其地址 (Address),通常以
T
开头。 - 权限控制:对账户的任何操作(如转账)都需要对应的私钥进行签名。
-
账户资产与能力:每个账户可以拥有和管理多种资源,包括:
- 资产:TRX、TRC-10、TRC-20、TRC-721/TRC-1155 NFT 等。
- 网络资源:带宽和能量。
- 权限与活动:发起交易、部署和调用智能合约、参与超级代表选举(投票或成为候选人)等。
创建账号的方式¶
创建一个新的 TRON 账户主要有两种方式:
方式一:链下生成与激活
- 生成地址:使用钱包应用(如 TronLink)生成一对私钥和地址。
- 激活账户:此时账户仅存在于理论上,需要被“激活”才能在链上使用。激活方式是从一个已存在的账户向这个新地址发送任意数量的 TRX 或 TRC-10 代币。交易成功后,新账户即在 TRON 网络上被创建。
方式二:通过内置合约创建
- 开发者可以调用
CreateAccount
内置合约,完成创建账户。
账户的创建成本:
- 创建并激活一个新账户需支付的 1 TRX 创建账户的费。
- 除此之外,如果账户拥有足够的带宽(包括质押 TRX 获得的带宽或他人代理的带宽),那么创建账户只会消耗带宽,否则,创建账户需要支付 0.1 个TRX带宽费用。
生成密钥对算法¶
TRON 的签名算法为 ECDSA,选用曲线为 SECP256K1。其私钥为一个随机数,公钥为椭圆曲线上一个点。生成过程为:首先生成一个随机数 d
作为私钥,再计算 P = d × G
作为公钥,其中 G
为椭圆曲线的基点,基点是公开的。
私钥是一个 32 字节的大数,公钥由 2 个 32 字节的大数组成,分别是上述 P
点的横坐标和纵坐标。
TRON 地址生成¶
- 用公钥
P
作为输入,计算 SHA3 得到结果H
,SHA3 选用 Keccak256。 - 取
H
的最后 20 字节,在前面填充一个字节0x41
得到address
。 - 对
address
进行 Base58check 计算得到最终地址。
Base58Check 计算过程¶
- 计算校验码
a. 对
address
进行 SHA256 哈希运算,得到h1
b. 对h1
再次进行 SHA256 运算,得到h2
c. 取h2
的前 4 字节作为校验码check
- 拼接数据
将check
拼接到address
之后,得到address||check
- Base58 编码
对address||check
进行 Base58 编码,Base58 的字符表为:"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
,排除了易混淆字符:0
(阿拉伯数字 0) 、O
(大写字母 O)、I
(大写字母 I)、l
(小写字母 l)。
TRON 地址特性¶
Base58 编码原理是将以 256 为基数的大整数转换为以 58 为基数表示,再映射到字符表。由于 address||check
首字节固定为 0x41
,其十进制值 N
满足:65 × 256²⁴ ≤ N < 66 × 256²⁴
。
- 长度为
34
位:由于58³⁴ > 66 × 256²⁴
表明34
位足够,58³³ < 65 × 256²⁴
表明33
位不够,所以所以长度只能是34
位 - 首字母为
T
:首先长度已经确定是34
位,并且由于27 × 58³³ > 66 × 256²⁴
表明第一位必须小于 27,26 × 58³³ < 65 × 256²⁴
表明第一位必须大于等于 26,所以最高位只能是26
,而26
对应 base58 字符表的T
(0
对应'1'
)
签名说明¶
算法¶
- 取交易的
rawdata
,转成byte[]
格式,记为data
(以 Java 中类型为例:byte[]
)。 - 对
data
进行 sha256 运算得到交易的 hash 值,记为hash
。 -
用交易合约中的地址对应的私钥
d
,对hash
进行签名,签名算法为 ECDSA 算法(选用的曲线为 SECP256K1)。签名结果包含r
,s
,v
三个值:- 计算
r
值:随机生成一个临时私钥k
,计算临时公钥K = k × G
(G
:曲线基点),r = K_x mod n
,即K
的横坐标模n
,其中n
是曲线阶数(n
和G
满足n × G = O
,O
是有限域上椭圆曲线群的零点)。r
为 32 个字节。 - 计算
s
值:先计算临时私钥k
对 n 的模逆k⁻¹
,即k⁻¹
满足k⁻¹ × k = 1 mod n
,再通过交易的hash
、用户的私钥d
、r
值计算s
值,s = (k⁻¹ × (hash + d × r)) mod n
。s
为 32 个字节。 - 计算
v
值:v
值是恢复标志符,由于r
值有取模运算以及椭圆曲线的对称性,如果只有r
值,一个r
最多可以恢复出四个K
。v
值的取值范围是0、1、2、3
四个整数,历史上为了和以太坊保持一致,最后的v
值会在0、1、2、3
的基础上再加27
,即最后v
值的取值范围是27、28、29、30
。有了确定的v
,就可以恢复出唯一的K
。v
为 1 个字节。
- 计算
-
将签名结果
r
,s
,v
拼接后添加到交易中,拼接顺序为v || r || s
。
Java 代码示例¶
public static Transaction sign(Transaction transaction, ECKey myKey) {
Transaction.Builder transactionBuilderSigned = transaction.toBuilder();
byte[] hash = sha256(transaction.getRawData().toByteArray());
ECDSASignature signature = myKey.sign(hash);
ByteString bsSign = ByteString.copyFrom(signature.toByteArray());
transactionBuilderSigned.addSignature(bsSign);
}
签名验证¶
Fullnode 节点收到交易后,会使用交易中的哈希和签名,通过 ECDSA 的恢复机制(ecrecover)计算出一个公钥,并由此推算出地址。如果该地址与交易中指定的发起方地址匹配,则验签通过。
算法¶
- 恢复公钥点
K
:通过签名中的v
和r
可以唯一恢复出临时公钥点K
。 -
推导公钥
P
: -
已知签名方程:
s = k⁻¹(hash + d × r) mod n
- 两边同乘
k
:s × k = (hash + d × r) mod n
- 两边再同乘曲线的基点
G
(利用K = k × G
和P = d × G
):s × K = hash × G + r × P
-
因
s、K、hash、G、r
均已知,可求得P
-
生成 TRON 地址:同 TRON 地址的生成。
- 地址验证:比对生成的 TRON 地址与交易合约中的地址是否一致。
示例¶
验证签名由全节点进行,ECDSA 算法的验签 可参考 java-tron,核心函数为 signatureToAddress
。
签名规范化¶
ECDSA 签名(采用 secp256k1 曲线)存在延展性,即对于签名 (r, s), 其中 r, s \in [1, n-1], (r, n - s) 仍然是合法的签名。由于比特币和以太坊签名会影响交易 ID, 分别在 BIP-62 和 EIP-2 要求签名必须规范化,即 s \leq n/2。 但对于 TRON 网络,交易 ID 并不包含签名信息,所以并不需要对签名规范化作严格的限制,验签也不需要对签名作规范化判断。虽然没有严格限制,但是目前 java-tron
和 wallet-cli
都对签名做了规范化处理。