使用曲线 secp224k1 使用私钥签署 ECDSA

Signing ECDSA with private key with curve secp224k1

我想通过 ECDSA secp224k1 获得签名。我无法获得与手册中 CoinFLEX Authentication Process 示例相同的签名。我正在使用 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());

预期的byteArr(第10步的r值):

r = 0x3fb77a9d 7b5b2a68 209e76f6 872078c5 791340d5 989854ad a3ab735e<br>

我的byteArr(这是错误的值,因为它与第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;
}
  • 根据instructions, not the 40-byte-message should be signed, but the SHA224-hash of this message: The client signs the 28-byte SHA-224 digest of the 40-byte message.... Note, that the data are not automatically hashed by the GenerateSignature-method, i.e. it must be hashed explicitly, see also here and these examples的第10步。

  • -method (which is used in the C#-code) outputs the byte-array in big-endian-format (unlike .Net, whose System.Numerics.BigInteger.ToByteArray-方法使用小端格式)。因此,没有必要颠倒字节顺序(使用Reverse-方法)。

  • 经过这些修改,签名为:

      r = 0x1781ff4997b48d389f518df75001c4b6564082956228d74dd0321656
      s = 0x0aadc68cf78dc75d44fb300f200465e72a70826ec2d5577d49b62e59
    

    然而,这仍然与说明中显示的签名不同。

    在 C# 代码中,ECDsaSigner-instance is created with a HMacDsaKCalculator-instance, generating a deterministic signature based on RFC6979. When creating a signature with ECDSA, the k-parameter is chosen randomly for the non-deterministic ECDSA, whereas in the deterministic variant it is created from the message and the private key according to a specific algorithm (described in RFC6979), see here。因此,确定性变体为相同的消息和私钥生成相同的签名,而非确定性变体生成不同的签名。

    签名之间的差异可能是由于 CoinFLEX 使用了非确定性变体造成的。不幸的是,这些说明没有详细说明所使用的 ECDSA 程序。

更新:

两种变体,确定性和非确定性,提供有效 ECDSA签名!在确定性变体之前 (RFC6979 is from August 2013) there was only the non-deterministic variant, see here.

我安装并测试了 sign_secp224k1-tool on a Linux (Debian) machine. As suspected, the tool generates different signatures for the same private key and the same message, obviously using the non-deterministic variant. This can also be easily verified from the source-code: The signature is calculated using the ecp_sign-method, which randomly determines the k-value using /dev/urandom

因此很明显,使用确定性变体的 C# 代码生成的签名 通常无法匹配 sign_secp224k1 工具使用非确定性变体生成的签名-确定性变体。