比特币ECDSA签名算法中z值计算及代码实现疑问咨询
关于比特币ECDSA签名z值计算的问题解答
问题1解答
是,比特币使用的secp256k1椭圆曲线的群阶n确实为0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,对应的比特长度是256位。
问题2解答
你的理解是对的。
secp256k1的群阶n是略小于2^256的素数,256位无符号二进制数的取值范围是[0, 2^256-1],最大值显然大于n,因此取e的最左256位得到的z完全可以是比n更大的数值,只要它的比特位不超过256位即可,不需要提前对n取模。比如你举的n+1就是典型的合法z值,和n的比特长度相同,但数值更大。
问题3/代码逻辑校验
你的z值计算代码存在两处核心问题,逻辑不正确:
- 哈希函数选择错误:比特币ECDSA签名使用的哈希函数是SHA-256,不是你代码里用的keccak(Keccak是以太坊签名用的哈希算法),这会导致最终生成的签名无法被比特币网络验证通过。
- 转二进制切片的逻辑有漏洞:
BigInt.prototype.toString(2)不会自动补前导零,如果哈希值对应的二进制长度不足256位(比如哈希的最高几位都是0),你调用getFirst256Chars拿到的就是完整的短于256位的二进制串,本质上是把高位的0丢弃了,得到的结果就不是e的最左256位了。
实际上你完全不需要做二进制转换切片,256位哈希输出本身就是固定32字节,直接按大端字节序转成BigInt就是你要的z值,更简单也不会出错。
额外代码问题提示
你当前的签名实现还有一处容易混淆的命名错误:你定义的BTC_PRIME_MODULO实际是群阶n,而secp256k1的素数域模数p是另一个值0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F,如果后续你把域运算和群阶运算的模搞混,会直接导致签名计算错误。
另外s值计算完成后,比特币规范要求s必须取小于等于n/2的值,避免签名延展性问题,你现在的代码没有做这一步处理,建议补充。
内容的提问来源于stack exchange,提问作者J. Hesters
相关产品推荐
相关产品推荐

