如何使用HEX格式私钥生成secp256k1签名 解决Hive网络PostingKey签名问题
Hive 网络PostingKey签名问题解决方案
1 原BouncyCastle代码错误修复
原代码的核心错误点:
signer.Init第一个参数传反,签名操作需要传true,false是验签用途- 未指定Hive使用的secp256k1曲线参数,直接初始化空
ECDomainParameters必然失败 BigInteger构造未处理字节序,C#默认的BigInteger为小端序,私钥字节为大端序,需要补充参数修正
修复后的BouncyCastle代码示例:
using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Signers; using Org.BouncyCastle.Math; using System.Text; public static class Signer { // 预加载secp256k1曲线参数 private static readonly ECDomainParameters Secp256k1Params; static Signer() { var secp256k1 = SecNamedCurves.GetByName("secp256k1"); Secp256k1Params = new ECDomainParameters(secp256k1.Curve, secp256k1.G, secp256k1.N, secp256k1.H); } public static byte[] Sign(string message, byte[] privateKey) { var signer = new ECDsaSigner(new HMacDsaKCalculator(new Org.BouncyCastle.Crypto.Digests.Sha256Digest())); // 修正BigInteger字节序问题,1代表大端无符号字节 var bigIntPrivateKey = new BigInteger(1, privateKey); var parameters = new ECPrivateKeyParameters(bigIntPrivateKey, Secp256k1Params); // 签名操作第一个参数必须传true signer.Init(true, parameters); var messageBytes = Encoding.UTF8.GetBytes(message); // ECDSA要求对消息哈希后再签名,不能直接传原消息字节 var messageHash = System.Security.Cryptography.SHA256.HashData(messageBytes); var signature = signer.GenerateSignature(messageHash); // 后续按Hive要求拼接恢复码、r、s、校验位即可 return signature; } }
2 Cryptography.ECDSA库问题修复
2.1 相同入参签名不一致属于正常现象
ECDSA签名默认使用随机k值生成签名,只要r、s符合规范,每次生成的签名不同完全不影响验签结果,eosjs_ecc的签名逻辑也有相同特性。
2.2 验签不通过的核心问题
当前代码大概率是没有先对原消息做SHA256哈希就直接传入签名方法,Hive网络的签名逻辑要求先对原始消息做SHA256运算,再对哈希结果签名,而非直接对原消息签名。
修复后的代码示例:
using Cryptography.ECDSA; using System.Security.Cryptography; using System.Text; public static string SignHiveMessage(string message, byte[] privateKey) { // 第一步:对原消息做SHA256哈希 var messageHash = SHA256.HashData(Encoding.UTF8.GetBytes(message)); // 传入哈希值而非原消息做签名 var buffer = Secp256K1Manager.SignCompressedCompact(messageHash, privateKey); var checksum = Ripemd160Manager.GetHash(buffer); var signatureArray = buffer.Concat(checksum.Take(4)).ToArray(); var result = Base58.Encode(signatureArray); return $"SIG_K1_{result}"; }
2.3 私钥解码注意事项
你提供的示例私钥为WIF格式,解码成32字节私钥时需要注意:
- 先对完整WIF字符串做Base58解码
- 去掉首位的版本字节(0x80)和末尾4位校验字节,中间32字节才是真实私钥
- 解码完成后需要校验校验位,避免私钥解析错误
内容的提问来源于stack exchange,提问作者Assassin
相关产品推荐
相关产品推荐

