从签名中恢复公钥:一步步揭开区块链签名的神秘面纱
从签名中恢复公钥:一步步揭开区块链签名的神秘面纱
本文中所有数据为虚构,可根据实际情况从区块链获取数据.
为什么要恢复公钥?
在区块链的世界里,私钥签名、公钥验证是最基本也最重要的安全机制之一.
我们通常:
- 使用私钥对一笔交易进行签名
- 网络节点用公钥验证这笔交易是否合法
背景知识
签名结构
区块链签名基于椭圆曲线 secp256k1,结构通常为 (r, s, v)
:
r
和s
是签名的两部分v
是恢复参数,用于帮助从签名中恢复出对应的公钥
什么是 raw_data?
raw_data
是一笔交易在签名前的原始字节数据.系统会对其进行一次 SHA256 哈希,然后将哈希结果用于签名.
恢复流程就是从该哈希值和签名结构 (r, s, v)
中推导出公钥.
核心原理简图
1
2
3
4
5
6
7
raw_data --SHA256--> message_hash
|
↓
signature (r, s, v) + message_hash
|
↓
recover → public key
使用 Python 实现公钥恢复
安装依赖
1
pip install eth-keys
编写恢复函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import hashlib
from eth_keys.datatypes import Signature
def recover_public_key_from_tron_signature(raw_data_hex: str, signature_hex: str) -> str:
"""
从 TRON 的交易原始数据和签名中恢复椭圆曲线公钥
:param raw_data_hex: 原始交易数据(十六进制字符串)
:param signature_hex: 签名数据(65字节十六进制字符串)
:return: 恢复出来的未压缩公钥(十六进制字符串)
"""
# 1. 对 raw_data 执行 SHA256 哈希
raw_data_bytes = bytes.fromhex(raw_data_hex)
message_hash = hashlib.sha256(raw_data_bytes).digest()
print("Message Hash (SHA256 of raw_data):", message_hash.hex())
# 2. 提取 r, s, v
signature_bytes = bytes.fromhex(signature_hex)
if len(signature_bytes) != 65:
raise ValueError("签名必须是 65 字节 (r:32 + s:32 + v:1)")
r = int.from_bytes(signature_bytes[0:32], byteorder='big')
s = int.from_bytes(signature_bytes[32:64], byteorder='big')
v = signature_bytes[64]
if v >= 27:
v -= 27 # 标准化处理为 0 或 1
print(f"Parsed Signature:
r = {hex(r)}
s = {hex(s)}
v = {v}")
# 3. 恢复公钥
sig = Signature(vrs=(v, r, s))
public_key = sig.recover_public_key_from_msg_hash(message_hash)
public_key_hex = public_key.to_bytes().hex()
print("Recovered Public Key (hex):", public_key_hex)
return public_key_hex
示例演示
我们用一组实际签名数据作为演示:
1
2
3
4
5
6
7
raw_data_hex = "0a0265782208706c61792d6d6f6465120f0a0b08c0843d1215e1a0e7c2d103"
signature_hex = (
"7db18bd6ccfffd4f8a5c208a3fd3f34d8f6e2db6f6ea84539b1b3e42b3d47809"
"79f18e5f741188cb80795d5f8a590b92edbb3e351c80e58208e7b4bbdcbb4ffb1b"
)
recover_public_key_from_tron_signature(raw_data_hex, signature_hex)
输出结果:
1
2
3
4
5
6
Message Hash (SHA256 of raw_data): 9f1430d6ee3d00b8bd5f2a78cbf60b683bdd3d3e1a7b2cf361942c5e110ce1a1
Parsed Signature:
r = 0x7db18bd6ccfffd4f8a5c208a3fd3f34d8f6e2db6f6ea84539b1b3e42b3d47809
s = 0x79f18e5f741188cb80795d5f8a590b92edbb3e351c80e58208e7b4bbdcbb4ffb
v = 1
Recovered Public Key (hex): 04a3f5d0c72ae1955bbf61a69b276bda7e3a7dcff4790d85e3c166e2c99f3b37d3d5f31a7e8876e37e63c6d2dfd4717e7e8c5f8c99b624d6c1441188ac11bca5ed
该公钥为未压缩格式,长度为 130 个 hex 字符(65 字节),开头的 04
表示其是未压缩的公钥格式.
应用场景
- 安全审计与身份分析
- 多签交易参与者比对
- 合约授权中对公钥白名单的支持
- 跨链签名关联验证
This post is licensed under CC BY 4.0 by the author.