You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python ecdsa库secp256r1签名如何获取v(恢复ID)字节?

解决Python ecdsa库生成secp256r1 65字节[r,s,v]签名的问题

核心思路

要生成符合要求的65字节签名,需从sign_deterministic返回的签名对象中提取r、s,再手动计算归一化后的s和恢复ID v(0-3),完全对齐你提供的Rust fastcrypto逻辑。

实现步骤

  1. 导入依赖库
import hashlib
import ecdsa
from ecdsa.curves import SECP256r1
from ecdsa.util import sigdecode_string
from ecdsa import rfc6979
  1. 生成密钥对与签名对象
# 生成secp256r1密钥对
private_key = ecdsa.SigningKey.generate(curve=SECP256r1)
public_key = private_key.get_verifying_key()

# 待签名数据与哈希
data = b"your_transaction_data_here"
hash_data = hashlib.sha256(data).digest()

# 获取签名对象(而非直接转64字节)
sig_obj = private_key.sign_deterministic(hash_data, hashfunc=hashlib.sha256)
# 解码签名得到原始r、s值
r, s = sigdecode_string(sig_obj, SECP256r1.order)
  1. 归一化s值
    secp256r1要求s必须落在曲线阶的下半部分(≤n/2),若原始s超出范围则转为n - s:
n = SECP256r1.order
s_high = s > n // 2
s_normalized = n - s if s_high else s
  1. 计算恢复ID v
    对应Rust代码逻辑,先获取签名生成时临时点k*G的y坐标奇偶性,再结合s是否高位的异或结果,最终得到v(0-3):
# 用RFC6979生成确定性签名的k值
k = rfc6979.generate_k(n, private_key.privkey.secret_multiplier, hashlib.sha256, hash_data)
# 计算k*G的y坐标奇偶性
point = SECP256r1.generator * k
y_odd = point.y() % 2 == 1

# 按Rust逻辑计算is_y_odd
is_y_odd = y_odd ^ s_high

# 确定v值:s高位时v加2,否则直接取is_y_odd
v = is_y_odd + 2 if s_high else is_y_odd
  1. 拼接65字节签名
    将r、归一化后的s、v分别转为字节并拼接:
r_bytes = r.to_bytes(32, byteorder='big')
s_bytes = s_normalized.to_bytes(32, byteorder='big')
v_bytes = bytes([v])
signature_65 = r_bytes + s_bytes + v_bytes

关键说明

  • 恢复ID v的取值0-3对应两种场景:s是否需要归一化(加2标识)、临时点y坐标的奇偶性(0/1),完全匹配你提供的Rust逻辑。
  • 全程未使用EIP-155链ID计算v,符合区块链规范要求。

内容的提问来源于stack exchange,提问作者Frank C.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 03:15:46