trc-8004-sdk 0.1.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sdk/signer.py ADDED
@@ -0,0 +1,284 @@
1
+ """
2
+ TRC-8004 SDK 签名器模块
3
+
4
+ 提供区块链交易和消息签名的抽象接口及实现。
5
+
6
+ Classes:
7
+ Signer: 签名器抽象基类
8
+ SimpleSigner: 开发测试用的简单签名器(HMAC-SHA256)
9
+ TronSigner: TRON 区块链签名器(secp256k1)
10
+
11
+ Example:
12
+ >>> from sdk.signer import TronSigner
13
+ >>> signer = TronSigner(private_key="your_hex_private_key")
14
+ >>> address = signer.get_address()
15
+ >>> signature = signer.sign_message(b"hello")
16
+
17
+ Note:
18
+ - SimpleSigner 仅用于本地开发和测试,不提供真正的密码学安全性
19
+ - TronSigner 需要安装 tronpy 库
20
+ - 扩展其他链只需实现 Signer 接口
21
+ """
22
+
23
+ import hashlib
24
+ from typing import Optional, Any
25
+
26
+ from .utils import hmac_sha256_hex
27
+
28
+
29
+ class Signer:
30
+ """
31
+ 签名器抽象基类。
32
+
33
+ 定义了区块链签名器的标准接口,所有具体实现必须继承此类。
34
+
35
+ Methods:
36
+ get_address: 获取签名者的区块链地址
37
+ sign_tx: 签名交易
38
+ sign_message: 签名任意消息
39
+
40
+ Example:
41
+ >>> class MySigner(Signer):
42
+ ... def get_address(self) -> str:
43
+ ... return "0x..."
44
+ ... def sign_tx(self, unsigned_tx: Any) -> Any:
45
+ ... return signed_tx
46
+ ... def sign_message(self, payload: bytes) -> str:
47
+ ... return "0x..."
48
+ """
49
+
50
+ def get_address(self) -> str:
51
+ """
52
+ 获取签名者的区块链地址。
53
+
54
+ Returns:
55
+ 区块链地址字符串(格式取决于具体链)
56
+
57
+ Raises:
58
+ NotImplementedError: 子类必须实现此方法
59
+ """
60
+ raise NotImplementedError
61
+
62
+ def sign_tx(self, unsigned_tx: Any) -> Any:
63
+ """
64
+ 签名未签名的交易。
65
+
66
+ Args:
67
+ unsigned_tx: 未签名的交易对象(格式取决于具体链)
68
+
69
+ Returns:
70
+ 已签名的交易对象
71
+
72
+ Raises:
73
+ NotImplementedError: 子类必须实现此方法
74
+ """
75
+ raise NotImplementedError
76
+
77
+ def sign_message(self, payload: bytes) -> str:
78
+ """
79
+ 签名任意消息。
80
+
81
+ 用于 EIP-191 风格的消息签名,常用于链下验证。
82
+
83
+ Args:
84
+ payload: 待签名的消息字节串(通常是哈希值)
85
+
86
+ Returns:
87
+ 签名的十六进制字符串(带 0x 前缀)
88
+
89
+ Raises:
90
+ NotImplementedError: 子类必须实现此方法
91
+ """
92
+ raise NotImplementedError
93
+
94
+
95
+ class SimpleSigner(Signer):
96
+ """
97
+ 开发测试用的简单签名器。
98
+
99
+ 使用 HMAC-SHA256 进行签名,不是真正的区块链签名,
100
+ 但保持了接口一致性,便于本地开发和单元测试。
101
+
102
+ Attributes:
103
+ _private_key: 私钥字节串
104
+ _address: 派生的伪地址
105
+
106
+ Args:
107
+ private_key: 私钥字符串,默认为 "development-key"
108
+
109
+ Example:
110
+ >>> signer = SimpleSigner(private_key="my-test-key")
111
+ >>> signer.get_address()
112
+ 'T...'
113
+ >>> signer.sign_message(b"hello")
114
+ '0x...'
115
+
116
+ Warning:
117
+ 此签名器仅用于开发测试,不提供密码学安全性!
118
+ 生产环境请使用 TronSigner 或其他真正的区块链签名器。
119
+ """
120
+
121
+ def __init__(self, private_key: Optional[str] = None) -> None:
122
+ """
123
+ 初始化简单签名器。
124
+
125
+ Args:
126
+ private_key: 私钥字符串,用于派生地址和签名。
127
+ 如果为 None,使用默认的开发密钥。
128
+ """
129
+ if private_key is None:
130
+ private_key = "development-key"
131
+ self._private_key = private_key.encode("utf-8")
132
+ self._address = self._derive_address(private_key)
133
+
134
+ @property
135
+ def address(self) -> str:
136
+ """公开的地址属性"""
137
+ return self._address
138
+
139
+ def get_address(self) -> str:
140
+ """
141
+ 获取派生的伪地址。
142
+
143
+ Returns:
144
+ 以 'T' 开头的 34 字符伪地址
145
+ """
146
+ return self._address
147
+
148
+ def sign_tx(self, unsigned_tx: Any) -> Any:
149
+ """
150
+ 签名交易(简化实现)。
151
+
152
+ 对于字节类型的交易,追加 HMAC 签名;
153
+ 对于其他类型,原样返回。
154
+
155
+ Args:
156
+ unsigned_tx: 未签名的交易
157
+
158
+ Returns:
159
+ 带签名的交易(字节类型)或原交易
160
+ """
161
+ if isinstance(unsigned_tx, bytes):
162
+ signature = hmac_sha256_hex(self._private_key, unsigned_tx).encode("utf-8")
163
+ return unsigned_tx + b"|" + signature
164
+ return unsigned_tx
165
+
166
+ def sign_message(self, payload: bytes) -> str:
167
+ """
168
+ 使用 HMAC-SHA256 签名消息。
169
+
170
+ Args:
171
+ payload: 待签名的消息字节串
172
+
173
+ Returns:
174
+ 带 0x 前缀的十六进制签名
175
+ """
176
+ return hmac_sha256_hex(self._private_key, payload)
177
+
178
+ @staticmethod
179
+ def _derive_address(private_key: str) -> str:
180
+ """
181
+ 从私钥派生伪地址。
182
+
183
+ 使用 SHA-256 哈希私钥,取前 33 个字符作为地址。
184
+
185
+ Args:
186
+ private_key: 私钥字符串
187
+
188
+ Returns:
189
+ 以 'T' 开头的伪地址
190
+ """
191
+ digest = hashlib.sha256(private_key.encode("utf-8")).hexdigest()
192
+ return "T" + digest[:33]
193
+
194
+
195
+ class TronSigner(Signer):
196
+ """
197
+ TRON 区块链签名器。
198
+
199
+ 使用 secp256k1 椭圆曲线进行真正的区块链签名,
200
+ 兼容 TRON 网络的交易和消息签名。
201
+
202
+ Attributes:
203
+ _key: tronpy PrivateKey 对象
204
+ _address: TRON base58check 格式地址
205
+ address: 公开的地址属性(与 _address 相同)
206
+
207
+ Args:
208
+ private_key: 十六进制格式的私钥(64 字符,不带 0x 前缀)
209
+
210
+ Raises:
211
+ RuntimeError: 未安装 tronpy 库
212
+
213
+ Example:
214
+ >>> signer = TronSigner(private_key="abc123...")
215
+ >>> signer.get_address()
216
+ 'TJRabPrwbZy45sbavfcjinPJC18kjpRTv8'
217
+ >>> signer.address # 也可以直接访问
218
+ 'TJRabPrwbZy45sbavfcjinPJC18kjpRTv8'
219
+ >>> signer.sign_message(keccak256_bytes(b"hello"))
220
+ '0x...'
221
+
222
+ Note:
223
+ 需要安装 tronpy: pip install tronpy
224
+ """
225
+
226
+ def __init__(self, private_key: str) -> None:
227
+ """
228
+ 初始化 TRON 签名器。
229
+
230
+ Args:
231
+ private_key: 十六进制格式的私钥(64 字符)
232
+
233
+ Raises:
234
+ RuntimeError: 未安装 tronpy 库
235
+ ValueError: 私钥格式无效
236
+ """
237
+ try:
238
+ from tronpy.keys import PrivateKey
239
+ except ImportError as exc:
240
+ raise RuntimeError("tronpy is required for TronSigner") from exc
241
+ self._key = PrivateKey(bytes.fromhex(private_key))
242
+ self._address = self._key.public_key.to_base58check_address()
243
+
244
+ @property
245
+ def address(self) -> str:
246
+ """公开的地址属性"""
247
+ return self._address
248
+
249
+ def get_address(self) -> str:
250
+ """
251
+ 获取 TRON 地址。
252
+
253
+ Returns:
254
+ TRON base58check 格式地址(以 'T' 开头)
255
+ """
256
+ return self._address
257
+
258
+ def sign_tx(self, unsigned_tx: Any) -> Any:
259
+ """
260
+ 签名 TRON 交易。
261
+
262
+ Args:
263
+ unsigned_tx: tronpy 的未签名交易对象
264
+
265
+ Returns:
266
+ 已签名的交易对象
267
+ """
268
+ return unsigned_tx.sign(self._key)
269
+
270
+ def sign_message(self, payload: bytes) -> str:
271
+ """
272
+ 签名消息哈希。
273
+
274
+ 使用 secp256k1 ECDSA 签名,返回 65 字节的签名
275
+ (r: 32 bytes, s: 32 bytes, v: 1 byte)。
276
+
277
+ Args:
278
+ payload: 消息哈希(32 字节)
279
+
280
+ Returns:
281
+ 带 0x 前缀的十六进制签名(130 字符 + 前缀)
282
+ """
283
+ signature = self._key.sign_msg_hash(payload)
284
+ return "0x" + signature.hex()
sdk/utils.py ADDED
@@ -0,0 +1,163 @@
1
+ """
2
+ TRC-8004 SDK 工具函数模块
3
+
4
+ 提供加密哈希、JSON 序列化等基础工具函数。
5
+
6
+ Functions:
7
+ canonical_json: 规范化 JSON 序列化(字节)
8
+ canonical_json_str: 规范化 JSON 序列化(字符串)
9
+ sha256_hex: SHA-256 哈希
10
+ hmac_sha256_hex: HMAC-SHA256 签名
11
+ keccak256_hex: Keccak-256 哈希(十六进制)
12
+ keccak256_bytes: Keccak-256 哈希(字节)
13
+
14
+ Example:
15
+ >>> from sdk.utils import keccak256_hex, canonical_json
16
+ >>> data = {"key": "value", "num": 123}
17
+ >>> hash_hex = keccak256_hex(canonical_json(data))
18
+ >>> print(hash_hex) # 0x...
19
+
20
+ Note:
21
+ - 规范化 JSON 使用键排序和紧凑格式,确保相同数据产生相同哈希
22
+ - Keccak-256 是以太坊/TRON 使用的哈希算法,与 SHA3-256 略有不同
23
+ """
24
+
25
+ import hashlib
26
+ import hmac
27
+ import json
28
+ from typing import Any, Dict
29
+
30
+ from Crypto.Hash import keccak
31
+
32
+
33
+ def canonical_json(payload: Dict[str, Any]) -> bytes:
34
+ """
35
+ 将字典序列化为规范化的 JSON 字节串。
36
+
37
+ 规范化规则:
38
+ - 键按字母顺序排序
39
+ - 使用紧凑格式(无空格)
40
+ - 使用 UTF-8 编码
41
+
42
+ Args:
43
+ payload: 待序列化的字典
44
+
45
+ Returns:
46
+ 规范化的 JSON 字节串
47
+
48
+ Example:
49
+ >>> canonical_json({"b": 2, "a": 1})
50
+ b'{"a":1,"b":2}'
51
+
52
+ Note:
53
+ 规范化确保相同的数据结构总是产生相同的字节串,
54
+ 这对于生成确定性哈希至关重要。
55
+ """
56
+ return json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8")
57
+
58
+
59
+ def canonical_json_str(payload: Dict[str, Any]) -> str:
60
+ """
61
+ 将字典序列化为规范化的 JSON 字符串。
62
+
63
+ 与 canonical_json 相同的规范化规则,但返回字符串而非字节。
64
+
65
+ Args:
66
+ payload: 待序列化的字典
67
+
68
+ Returns:
69
+ 规范化的 JSON 字符串
70
+
71
+ Example:
72
+ >>> canonical_json_str({"b": 2, "a": 1})
73
+ '{"a":1,"b":2}'
74
+ """
75
+ return json.dumps(payload, separators=(",", ":"), sort_keys=True)
76
+
77
+
78
+ def sha256_hex(payload: bytes) -> str:
79
+ """
80
+ 计算 SHA-256 哈希值。
81
+
82
+ Args:
83
+ payload: 待哈希的字节串
84
+
85
+ Returns:
86
+ 带 0x 前缀的十六进制哈希字符串(64 字符 + 前缀)
87
+
88
+ Example:
89
+ >>> sha256_hex(b"hello")
90
+ '0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
91
+ """
92
+ return "0x" + hashlib.sha256(payload).hexdigest()
93
+
94
+
95
+ def hmac_sha256_hex(key: bytes, payload: bytes) -> str:
96
+ """
97
+ 计算 HMAC-SHA256 签名。
98
+
99
+ Args:
100
+ key: 密钥字节串
101
+ payload: 待签名的消息字节串
102
+
103
+ Returns:
104
+ 带 0x 前缀的十六进制签名字符串
105
+
106
+ Example:
107
+ >>> hmac_sha256_hex(b"secret", b"message")
108
+ '0x...'
109
+
110
+ Note:
111
+ HMAC 提供消息认证,确保消息未被篡改且来自持有密钥的发送方。
112
+ """
113
+ return "0x" + hmac.new(key, payload, hashlib.sha256).hexdigest()
114
+
115
+
116
+ def keccak256_hex(payload: bytes) -> str:
117
+ """
118
+ 计算 Keccak-256 哈希值(十六进制格式)。
119
+
120
+ Keccak-256 是以太坊和 TRON 区块链使用的哈希算法。
121
+
122
+ Args:
123
+ payload: 待哈希的字节串
124
+
125
+ Returns:
126
+ 带 0x 前缀的十六进制哈希字符串(64 字符 + 前缀)
127
+
128
+ Example:
129
+ >>> keccak256_hex(b"hello")
130
+ '0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8'
131
+
132
+ Note:
133
+ Keccak-256 与 NIST 标准化的 SHA3-256 略有不同,
134
+ 以太坊在 SHA3 标准化之前就采用了 Keccak。
135
+ """
136
+ hasher = keccak.new(digest_bits=256)
137
+ hasher.update(payload)
138
+ return "0x" + hasher.hexdigest()
139
+
140
+
141
+ def keccak256_bytes(payload: bytes) -> bytes:
142
+ """
143
+ 计算 Keccak-256 哈希值(字节格式)。
144
+
145
+ 与 keccak256_hex 相同,但返回原始字节而非十六进制字符串。
146
+
147
+ Args:
148
+ payload: 待哈希的字节串
149
+
150
+ Returns:
151
+ 32 字节的哈希值
152
+
153
+ Example:
154
+ >>> len(keccak256_bytes(b"hello"))
155
+ 32
156
+
157
+ Note:
158
+ 当需要将哈希用于进一步的密码学操作(如签名)时,
159
+ 使用字节格式更高效。
160
+ """
161
+ hasher = keccak.new(digest_bits=256)
162
+ hasher.update(payload)
163
+ return hasher.digest()