Gnupg secp256k1 서명이 다른 구현과 일치하지 않습니다.

Gnupg secp256k1 서명이 다른 구현과 일치하지 않습니다.

암호화폐 목적으로 gpg 에이전트에 서명을 하려고 합니다. 여러 해시 서명과 서명을 시도했습니다.하나그들 중 몇몇은 얻었어다른 rs다른 구현과 동일한 효과를 달성하면서 .

elliptic결과를 nodejs 라이브러리와 c의 결과와 비교했는데 libsecp256k1결과가 서로 일치했습니다.

아마도 이것은 내 입장에서는 명백하고 어리석은 실수였을 것이고 그렇기 때문에 나는 그것을 스스로 발견할 수 없었습니다.

해당 버전의 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) 출력은 16진수 덤프에 표시됩니다(위에 게시된 질문 하단의 두 번째 프로그램인 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 측면 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 서명 구성 요소)의 마지막 출력이 Bitcoin 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 49b7ab20b014128d1f72fe45071d24971e3463000100ec5dcce13ea0c5f4500c315c964cdee10a055313ea71b7558200e98b1df77f380fb5

% 에코 -n 045ece262213052b8104000a020304d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b621849 b7 ab20b014128d1f72fe45071d24971e3463 |화장실-c

 158 / 2 = 79 = 0x004f

$MasterFingerprintBasis =99004f045ece262213052b8104000a020304d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b62184 9b 7ab20b014128d1f72fe45071d24971e3463

2. 사용자 ID 패킷(태그 13): 0xb4 원래 패킷: b4204d656c76696e20657264203c6d656c76696e40736563686f73742e696e666f3e

% 에코 -n 4d656c76696e20657264203c6d656c76696e40736563686f73742e696e666f3e 화장실 -c |

  64 / 2 = 32 = 0x00000020

$UserIDFingerprintBasis =b4000000204d656c76696e20657264203c6d656c76696e40736563686f73742e696e666f3e

3. ECC 시그니처 패키지(라벨 2): ​​0x88 원래 패킷: 8890041313080038162104d5c4ad7cc2a40ca64860aca504450bed5a1d56d605025ece2622021b03050b0908070305150a09080b051602030100021e010 2 780000a091004450bed5a1d56d64f3a00fc0a8be9d48722bd3e95f44d492a356b65a2299a670a76bd8fd2a28afed4ca532a0100c25e72beda064cf713ec5ce7b48 bdcdaa86a30dfd7e5339b9158397f58e

% 에코 -n |

 124 / 2 = 62 = 0x0000003e

$MasterMagicBasis =041313080038162104d5c4ad7cc2a40ca64860aca504450bed5a1d56d605025ece2622021b03050b0908070305150a09080b051602030100021e0102178004ff0 00003e

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

% 에코 99004f045ece262213052b8104000a020304d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b62 849b7ab20b014128d1f72fe45071d24971e3463b4000000204d656c76696e 20657264203c6d656c76696e40736563686f73742e696e666f3e04131308003 8162104d5c4ad7cc2a40ca64860aca504450bed5a1d56d605025ece2622021b03050b0908070305150a09080b051602030100021e0102178004FF0000003e |sha256 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 = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141입니다.

% 에코 3da18d4125f9b308ec13a3184b714f4bfce132600c3aa2bd6c98a5774c9e4bb3 tr "af" "AF"

3DA18D4125F9B308EC13A3184B714F4BFCE132600C3AA2BD6C98A5774C9E4BB3

% echo "obase=16;ibase=16;FFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141-3DA18D4125F9B308EC13A3184B714F4BFCE132600C3AA2BD6C98A5774C9E4BB3" |

C25E72BEDA064CF713EC5CE7B48EB0B2BDCDAA86A30DFD7E5339B9158397F58E

위에서 계산된 s2 값을 사용하면 수학적 서명을 명확하게 하고 비트코인에서와 같이 s1 < s2와 같이 관례적으로 올바른 서명을 지정하는 규칙을 선택하지 않는 한 서명이 말레이시아화될 수 있습니다. 비트코인의 경우 이는 "거래 가단성"의 이전 형태였습니다. OpenPGP의 경우 이는 일종의 "인증서 가단성"으로 이어질 수 있으며, 이는 여러 서명이 공개 키 블록의 일부가 될 때 더욱 악화됩니다. OpenPGP의 경우 상호 운용성 합의 규칙은 IETF RFC에 문서화되어 있습니다.개발 중현재 인증서 확장성에 대한 대책에 대한 언급은 없습니다.

추가 정보:

아래 키는 위의 비밀 패킷 끝부분에서 찾을 수 있습니다. 압축되지 않은 공개 키(기본적으로 관련 압축 공개 키 크기의 두 배)는 표시된 대로 계산할 수 있으며 결과 공개 키는 다음과 같이 음영 처리된 출력입니다.ㅏ%. "-u" 매개변수를 제거하면 연관된 압축되지 않은 공개 키가 강제로 계산됩니다. 이는 더 짧은 답변이며 현재 GPG에서 작동하지 않습니다.

ㅏ%에코 ec5dcce13ea0c5f4500c315c964cdee10a055313ea71b7558200e98b1df77f38 |BxEU를 대중에게-유

04d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b621849b7ab20b014128d1f72fe45071d24971e3463

두번째%echo99004f045ece262213052b8104000a020304d9bd493708d5e0fca62a7c86e43646595de0fec811395fb009ec811892903d49292cd48390ab0b3433753b621 9b7ab20b014128d1f72fe45071d24971e3463 |BxBase16 디코딩|샤숨-

d5c4ad7cc2a40ca64860aca504450bed5a1d56d6 -

관련 정보