使用带有曲线secp224k1的私钥对ECDSA进行签名



我想通过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 生成的签名相匹配。

最新更新