Gnupg secp256k1 签名与其他实现不匹配

Gnupg secp256k1 签名与其他实现不匹配

我正在尝试让 gpg 代理签署加密货币目的。我尝试过签署几个哈希值,以及签名他们中的人得到了不同的 r同时获得s与其他实现相同的效果。

我将结果与ellipticnodejs 库和libsecp256k1c 中的结果进行了比较,它们的结果相互匹配。

想必这是我的一个明显而愚蠢的错误,这就是原因,但我自己无法发现它。

这是该版本的 c 源代码libsecp256k1

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <secp256k1.h>

const unsigned char msg[32] = {0xc3, 0xaf, 0xca, 0x60, 0x84, 0xa5, 0x8f, 0x5b, 0x06, 0x0d, 0x0a, 0x4a, 0xaa, 0x6e, 0xd9, 0x06, 0x3a, 0x9b, 0xa7, 0x0f, 0x2b, 0xd4, 0xa7, 0x68, 0xf4, 0xad, 0x41, 0x41, 0x74, 0x28, 0xf8, 0x02};
const unsigned char pk[32] = {0xEC, 0x5D, 0xCC, 0xE1, 0x3E, 0xA0, 0xC5, 0xF4, 0x50, 0x0C, 0x31, 0x5C, 0x96, 0x4C, 0xDE, 0xE1, 0x0A, 0x05, 0x53, 0x13, 0xEA, 0x71, 0xB7, 0x55, 0x82, 0x00, 0xE9, 0x8B, 0x1D, 0xF7, 0x7F, 0x38};


int main() {
    int r;
    int fd;
    secp256k1_context *ctx;
    secp256k1_ecdsa_signature sig;
    unsigned char *serialized_signature;

    ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
    r = secp256k1_ecdsa_sign(ctx, &sig, (const unsigned char*)msg, (const unsigned char*)pk, NULL, NULL);
    if (r != 1) {
        return 1;
    }

    serialized_signature = malloc(64);  
    r = secp256k1_ecdsa_signature_serialize_compact(ctx, serialized_signature, &sig);
    if (r != 1) {
        return 1;
    }
    fwrite(serialized_signature, 1, 64, stdout);
    free(serialized_signature);
    secp256k1_context_destroy(ctx);

    return 0;
}

---

outputs:
$ ./a.out | hexdump -C
00000000  26 0d c8 ab 01 f0 79 64  0b dd 8d 5b 5b 43 76 bd  |&.....yd...[[Cv.|
00000010  d2 db 1d 66 fa ce 87 57  6e f1 1f 04 df 54 24 67  |...f...Wn....T$g|
00000020  0f 50 01 c3 3c 17 b5 5e  a1 c7 dc cb 2a 38 af 69  |.P..<..^....*8.i|
00000030  7c a1 8e 38 48 6c b4 7a  9b d7 f3 24 c9 99 17 b3  ||..8Hl.z...$....|

这是使用 gnupg 的尝试:

keyid=D5C4AD7CC2A40CA64860ACA504450BED5A1D56D6
keygrip=A6D4B5C57143CE15C07D0DDEA5986B13B5F7ED72
hsh=c3afca6084a58f5b060d0a4aaa6ed9063a9ba70f2bd4a768f4ad41417428f802

cat <<EOF | gpg --import
-----BEGIN PGP PRIVATE KEY BLOCK-----

lHQEXs4mIhMFK4EEAAoCAwTZvUk3CNXg/KYqfIbkNkZZXeD+yBE5X7AJ7IEYkpA9
SSks1IOQqws0M3U7YhhJt6sgsBQSjR9y/kUHHSSXHjRjAAEA7F3M4T6gxfRQDDFc
lkze4QoFUxPqcbdVggDpix33fzgPtbQgTWVsdmluIGVyZCA8bWVsdmluQHNlY2hv
c3QuaW5mbz6IkAQTEwgAOBYhBNXErXzCpAymSGCspQRFC+1aHVbWBQJeziYiAhsD
BQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEARFC+1aHVbWTzoA/AqL6dSHIr0+
lfRNSSo1a2WiKZpnCna9j9Kiiv7UylMqAQDCXnK+2gZM9xPsXOe0jrCyvc2qhqMN
/X5TObkVg5f1jg==
=OhY5
-----END PGP PRIVATE KEY BLOCK-----
EOF

gpg-connect-agent <<EOF | hexdump -C
SIGKEY $keygrip
SETHASH --hash=sha256 $hsh
PKSIGN
EOF

---

outputs:

$ bash agent-sign.sh 
gpg: key 04450BED5A1D56D6: "Melvin erd <[email protected]>" not changed
gpg: key 04450BED5A1D56D6: secret key imported
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1
gpg:  secret keys unchanged: 1
00000000  4f 4b 0a 4f 4b 0a 44 20  28 37 3a 73 69 67 2d 76  |OK.OK.D (7:sig-v|
00000010  61 6c 28 35 3a 65 63 64  73 61 28 31 3a 72 33 32  |al(5:ecdsa(1:r32|
00000020  3a 26 25 30 44 c8 ab 01  f0 79 64 0b dd 8d 5b 5b  |:&%0D....yd...[[|
00000030  43 76 bd d2 db 1d 66 fa  ce 87 57 6e f1 1f 04 df  |Cv....f...Wn....|
00000040  54 24 67 29 28 31 3a 73  33 32 3a 0f 50 01 c3 3c  |T$g)(1:s32:.P..<|
00000050  17 b5 5e a1 c7 dc cb 2a  38 af 69 7c a1 8e 38 48  |..^....*8.i|..8H|
00000060  6c b4 7a 9b d7 f3 24 c9  99 17 b3 29 29 29 0a 4f  |l.z...$....))).O|
00000070  4b 0a                                             |K.|
00000072

(signature itself; r at 0x21 and, s at `0x4b`)

答案1

gpg secp256k1 曲线符号表达式 (S-EXP) 输出结果显示在十六进制转储中(来自 gpg 脚本,上面发布的问题底部的第二个程序)。 0x28“(”和0x29“)”表示括号,它构成了 R & S 签名组件的 32 字节 S-EXP 编码。

libsecp256k1 Code Output:

R 签名组件 =26 0d c8 ab 01 f0 79 64 0b dd 8d 5b 5b 43 76 bd d2 db 1d 66 面 ce 87 57 6e f1 1f 04 df 54 24 67

S 签名组件 =0f 50 01 c3 3c 17 b5 5e a1 c7 dc CB 2a 38 af 69 7c a1 8e 38 48 6c b4 7a 9b d7 f3 24 c9 99 17 b3

GPG Script S-EXP Output:

R 签名组件 =2625 30 44c8 ab 01 f0 79 64 0b dd 8d 5b 5b 43 76 bd d2 db 1d 66 面 ce 87 57 6e f1 1f 04 df 54 24 67

S 签名组件 =0f 50 01 c3 3c 17 b5 5e a1 c7 dc CB 2a 38 af 69 7c a1 8e 38 48 6c b4 7a 9b d7 f3 24 c9 99 17 b3

S 签名组件似乎与 libsecp256k1 输出的结果完全匹配。只有 R 组件的第二个字节似乎有所不同,但值得注意的是,来自 S-EXP 的“25 30 44”的 %0D 解码确实看起来像第一个程序的 R 组件的 0x0d 第二个输出字节输出。

% 猫 melvin_5a1d56d6.asc

-----BEGIN PGP PRIVATE KEY BLOCK-----

lHQEXs4mIhMFK4EEAAoCAwTZvUk3CNXg/KYqfIbkNkZZXeD+yBE5X7AJ7IEYkpA9
SSks1IOQqws0M3U7YhhJt6sgsBQSjR9y/kUHHSSXHjRjAAEA7F3M4T6gxfRQDDFc
lkze4QoFUxPqcbdVggDpix33fzgPtbQgTWVsdmluIGVyZCA8bWVsdmluQHNlY2hv
c3QuaW5mbz6IkAQTEwgAOBYhBNXErXzCpAymSGCspQRFC+1aHVbWBQJeziYiAhsD
BQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEARFC+1aHVbWTzoA/AqL6dSHIr0+
lfRNSSo1a2WiKZpnCna9j9Kiiv7UylMqAQDCXnK+2gZM9xPsXOe0jrCyvc2qhqMN
/X5TObkVg5f1jg==
=OhY5
-----END PGP PRIVATE KEY BLOCK-----

请注意 gpg 计算的最后一个输出(S 签名组件)与下面应用比特币 secp256k1 签名的手动计算有何不同:

% 猫 melvin_5a1d56d6.asc | gpg --list-packets --verbose

# off=0 ctb=94 tag=5 hlen=2 plen=116
:secret key packet:
    version 4, algo 19, created 1590568482, expires 0
    pkey[0]: 052B8104000A secp256k1 (1.3.132.0.10)
    pkey[1]: 04D9BD493708D5E0FCA62A7C86E43646595DE0FEC811395FB009EC811892903D49292CD48390AB0B3433753B621849B7AB20B014128D1F72FE45071D24971E3463
    skey[2]: EC5DCCE13EA0C5F4500C315C964CDEE10A055313EA71B7558200E98B1DF77F38
    checksum: 0fb5
    keyid: 04450BED5A1D56D6
# off=118 ctb=b4 tag=13 hlen=2 plen=32
:user ID packet: "Melvin erd <[email protected]>"
# off=152 ctb=88 tag=2 hlen=2 plen=144
:signature packet: algo 19, keyid 04450BED5A1D56D6
    version 4, created 1590568482, md5len 0, sigclass 0x13
    digest algo 8, begin of digest 4f 3a
    hashed subpkt 33 len 21 (issuer fpr v4 D5C4AD7CC2A40CA64860ACA504450BED5A1D56D6)
    hashed subpkt 2 len 4 (sig created 2020-05-27)
    hashed subpkt 27 len 1 (key flags: 03)
    hashed subpkt 11 len 4 (pref-sym-algos: 9 8 7 3)
    hashed subpkt 21 len 4 (pref-hash-algos: 10 9 8 11)
    hashed subpkt 22 len 4 (pref-zip-algos: 2 3 1 0)
    hashed subpkt 30 len 1 (features: 01)
    hashed subpkt 23 len 1 (keyserver preferences: 80)
    subpkt 16 len 8 (issuer key ID 04450BED5A1D56D6)
    data: 0A8BE9D48722BD3E95F44D492A356B65A2299A670A76BD8FD2A28AFED4CA532A
    data: C25E72BEDA064CF713EC5CE7B48EB0B2BDCDAA86A30DFD7E5339B9158397F58E
% cat melvin_5a1d56d6.asc | sed 's/\[GNUPG:\].*$//' | sed 's/-----BEGIN PGP PRIVATE KEY BLOCK-----//' | sed 's/-----END PGP PRIVATE KEY BLOCK-----//' | sed 's/-----BEGIN PGP PUBLIC KEY BLOCK-----//' | sed 's/-----END PGP PUBLIC KEY BLOCK-----//' | sed 's/-----BEGIN PGP SIGNATURE-----//' | sed 's/-----END PGP SIGNATURE-----//' | sed '/^$/d' | sed '/^=.*$/d' |  tr -d '\n' | bx base64-decode | bx base16-encode
9474045ece262213052b8104000a020304d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b621849b7ab20b014128d1f72fe45071d24971e3463000100ec5dcce13ea0c5f4500c315c964cdee10a055313ea71b7558200e98b1df77f380fb5b4204d656c76696e20657264203c6d656c76696e40736563686f73742e696e666f3e8890041313080038162104d5c4ad7cc2a40ca64860aca504450bed5a1d56d605025ece2622021b03050b0908070305150a09080b051602030100021e01021780000a091004450bed5a1d56d64f3a00fc0a8be9d48722bd3e95f44d492a356b65a2299a670a76bd8fd2a28afed4ca532a0100c25e72beda064cf713ec5ce7b48eb0b2bdcdaa86a30dfd7e5339b9158397f58e

1. ECC密钥包(标签5):0x94 原始数据包:9474045ece262213052b8104000a020304d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b621 849b7ab20b014128d1f72fe45071d24971e3463000100ec5dcce13ea0c5f4500c315c964cdee10a055313ea71b7558200e98b1df77f380fb5

%回声-n 045ece262213052b8104000a020304d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b621849 b7ab20b014128d1f72fe45071d24971e3463 |厕所-c

 158 / 2 = 79 = 0x004f

$MasterFingerprintBasis =99004f045ece262213052b8104000a020304d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b621849b 7ab20b014128d1f72fe45071d24971e3463

2. 用户ID数据包(标签13):0xb4 原始数据包:b4204d656c76696e20657264203c6d656c76696e40736563686f73742e696e666f3e

%回显-n 4d656c76696e20657264203c6d656c76696e40736563686f73742e696e666f3e |厕所-c

  64 / 2 = 32 = 0x00000020

$UserIDFingerprintBasis =b4000000204d656c76696e20657264203c6d656c76696e40736563686f73742e696e666f3e

3. ECC签名包(标签2):0x88 原始数据包:8890041313080038162104d5c4ad7cc2a40ca64860aca504450bed5a1d56d605025ece2622021b03050b0908070305150a09080b051602030100021e010 21780000a091004450bed5a1d56d64f3a00fc0a8be9d48722bd3e95f44d492a356b65a2299a670a76bd8fd2a28afed4ca532a0100c25e72beda064cf713ec5ce7b48 eb0b2bdcdaa86a30dfd7e5339b9158397f58e

%回声-n |厕所-c

 124 / 2 = 62 = 0x0000003e

$MasterMagicBasis =041313080038162104d5c4ad7cc2a40ca64860aca504450bed5a1d56d605025ece2622021b03050b0908070305150a09080b051602030100021e0102178004ff0 000003e

4. SHA256($MasterFingerprintBasis + $UserIDFingerprintBasis + $MasterMagicBasis)

%回显99004f045ece262213052b8104000a020304d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b62 1849b7ab20b014128d1f72fe45071d24971e3463b4000000204d656c76696e 20657264203c6d656c76696e40736563686f73742e696e666f3e04131308003 8162104d5c4ad7cc2a40ca64860aca504450bed5a1d56d605025ece2622021b03050b0908070305150a09080b051602030100021e0102178004FF0000003e |沙256 4f3a4cc1a8f4bea91ddca5688b73b9379edd80876a1b5ed47543f33939f3b7cf

5. 对计算的哈希值进行签名

./btc_sign_secp256k1 -k EC5DCCE13EA0C5F4500C315C964CDEE10A055313EA71B7558200E98B1DF77F38 -m 4f3a4cc1a8f4bea91ddca5688b73b9379edd80876a1b5ed47543 f33939f3b7cf

 secp256k1 Uncompressed Pubkey : 04d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b621849b7ab20b014128d1f72fe45071d24971e3463

 Message is binary encoded as HEX        : 4f3a4cc1a8f4bea91ddca5688b73b9379edd80876a1b5ed47543f33939f3b7cf
         secp256k1 R Signature Component : 0a8be9d48722bd3e95f44d492a356b65a2299a670a76bd8fd2a28afed4ca532a
         secp256k1 S Signature Component : 3da18d4125f9b308ec13a3184b714f4bfce132600c3aa2bd6c98a5774c9e4bb3

现在让我们计算不需要私钥即可计算的互补签名。 (r1,s1) 的补码签名将为 (r1,s2),其中“s1+s2=n”,对于 sep256k1 曲线 n = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141。

%回显3da18d4125f9b308ec13a3184b714f4bfce132600c3aa2bd6c98a5774c9e4bb3 | tr“af”“AF”

3DA18D4125F9B308EC13A3184B714F4BFCE132600C3AA2BD6C98A5774C9E4BB3

%回显“obase = 16; ibase = 16; FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141-3DA18D4125F9B308EC13A3184B714F4BFCE132600C3AA2BD6C98A5774C9E4BB3”|公元前

C25E72BEDA064CF713EC5CE7B48EB0B2BDCDAA86A30DFD7E5339B9158397F58E

使用上面计算的 s2 值,可以对签名进行马来化,除非选择约定来消除数学签名的歧义并指定传统上正确的签名,使得 s1 < s2 就像比特币那样。对于比特币来说,这是“交易延展性”的一种先前形式。对于 OpenPGP,这可能会导致某种形式的“证书可延展性”,当多个签名成为公钥块的一部分时,这种情况会加剧。对于 OpenPGP,互操作性共识规则记录在 IETF RFC 中正在开发中目前没有提及证书可延展性的对策。

附加信息:

下面的密钥可以在上面的秘密数据包的尾部找到。未压缩的公钥(基本上是相关压缩公钥的两倍)可以按所示计算,所得公钥是以下阴影输出A%。删除“-u”参数会强制计算关联的未压缩公钥,这是一个较短的答案,目前不适用于 GPG。

A%回声 ec5dcce13ea0c5f4500c315c964cdee10a055313ea71b7558200e98b1df77f38 |乙x欧盟向公众-u

04d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b621849b7ab20b014128d1f72fe45071d24971e3463

乙%回声99004f045ece262213052b8104000a020304d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b62184 9b7ab20b014128d1f72fe45071d24971e3463 |乙xBase16 解码|沙苏姆-

d5c4ad7cc2a40ca64860aca504450bed5a1d56d6 -

相关内容