我想通过ECDSA secp224k1获得符号。我无法从手册中获得与CoinFLEX身份验证过程示例中相同的签名。我正在使用C# BouncyCastle。
为什么我的代码无法获得手册页的签名?
// manual page's step 7
byte[] fortyByteMessage = fromHexStringToByteArr("0x00000000 00000001").Concat(fromHexStringToByteArr("0x6b347302 2e6b9b5a f2fe5d1d ae7cf5bf")).Concat(fromHexStringToByteArr("0xf08c98ca f1fd82e8 cea9825d bff04fd0")).ToArray();
// manual page's step 9
byte[] privateKey = fromHexStringToByteArr("0xb89ea7fc d22cc059 c2673dc2 4ff40b97 83074646 86560d0a d7561b83");
// manual page's step 10
X9ECParameters spec = ECNamedCurveTable.GetByName("secp224k1");
ECDomainParameters domain = new ECDomainParameters(spec.Curve, spec.G, spec.N);
ECDsaSigner signer = new ECDsaSigner(new HMacDsaKCalculator(new Sha224Digest()));
signer.Init(true, new ECPrivateKeyParameters(new BigInteger(privateKey), domain));
BigInteger[] signature = signer.GenerateSignature(fortyByteMessage);
byte[] r = signature[0].ToByteArray().SkipWhile(b => b == 0x00).Reverse().ToArray(); // (r) r should be 0x3fb77a9d 7b5b2a68 209e76f6 872078c5 791340d5 989854ad a3ab735e, but not.
Console.WriteLine(BitConverter.ToString(r).Replace("-", string.Empty).ToLower());
预期字节Arr(步长10 r值(:
r = 0x3fb77a9d 7b5b2a68 209e76f6 872078c5 791340d5 989854ad a3ab735e<br>
我的字节Arr(这是错误的值,因为它与步骤10 r值不同(
r = 0x1e3b3f4f 7401ff9d 827b7222 47823919 452d3adb effa7aa4 52a0879e<br>
另一个功能:
static byte[] fromHexStringToByteArr(string paramHexString)
{
string hexString = paramHexString.Substring(2).Replace(" ", "");
byte[] result = new byte[hexString.Length / 2];
int cur = 0;
for (int i = 0; i < hexString.Length; i = i + 2)
{
string w = hexString.Substring(i, 2);
result[cur] = Convert.ToByte(w, 16);
cur++;
}
return result;
}
-
根据指令的步骤 10,不应对 40 字节消息进行签名,而应对此消息的 SHA224 哈希进行签名:客户端对 40 字节消息的 28 字节 SHA-224 摘要进行签名...。请注意,数据不会由
GenerateSignature
-方法自动散列,即必须显式散列,另请参阅此处和这些示例。 -
Org.BouncyCastle.Math.BigInteger.ToByteArray
-方法(在 C# 代码中使用(以大端格式输出字节数组(与 .Net 不同,System.Numerics.BigInteger.ToByteArray
-方法 使用小端格式(。因此,没有必要反转字节顺序(使用Reverse
-方法(。 -
通过这些修改,签名为:
r = 0x1781ff4997b48d389f518df75001c4b6564082956228d74dd0321656 s = 0x0aadc68cf78dc75d44fb300f200465e72a70826ec2d5577d49b62e59
但是,这仍然与说明中显示的签名不同。
在 C# 代码中,
ECDsaSigner
实例是使用HMacDsaKCalculator
实例创建的,基于 RFC6979 生成确定性签名。使用 ECDSA 创建签名时,k
参数是为非确定性 ECDSA 随机选择的,而在确定性变体中,它是根据特定算法从消息和私钥创建的(在RFC6979中描述(,请参阅此处。因此,确定性变体为相同的消息和私钥生成相同的签名,而非确定性变体生成不同的签名。签名之间的差异可能是由于CoinFLEX使用非确定性变体引起的。不幸的是,这些说明没有详细说明所使用的ECDSA程序。
更新:
两种变体,确定性和非确定性,都提供有效的ECDSA 签名!在确定性变体(RFC6979从 2013 年 8 月开始(之前,只有非确定性变体,请参见此处。
我在Linux(Debian(机器上安装并测试了sign_secp224k1
工具。正如所怀疑的那样,该工具为相同的私钥和相同的消息生成不同的签名,显然使用了非确定性变体。这也可以从源代码中轻松验证:签名是使用ecp_sign
-方法计算的,该方法使用/dev/urandom
随机确定k
值。
因此,很明显,使用确定性变体的 C# 代码生成的签名通常无法与使用非确定性变体的sign_secp224k1
-tool 生成的签名相匹配。