Bitcoin Forum
September 20, 2020, 11:11:33 AM *
News: Latest Bitcoin Core release: 0.20.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Is possible get public key from signature?  (Read 341 times)
Frodek
Member
**
Offline Offline

Activity: 133
Merit: 18


View Profile
October 11, 2019, 02:29:24 PM
Merited by joniboini (2), LoyceV (1), hugeblack (1)
 #1

Transaction inputs script are usually (but coinbase) 73 bytes signature + 65 bytes key.
But in rare cases I see is only 73 bytes signature.
Is possible get 65 or 33 key from it?
I see
https://learnmeabitcoin.com/guide/digital_signatures_signing_verifying

https://learnmeabitcoin.com/guide/digital_signatures

But I don't know which bytes is messages which is "r" and "s" to divide. I wanna example how to get key from 73 bytes signature (or maybe from signature and message=other fields of input, like amount etc?)
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction. Advertise here.
Coding Enthusiast
Legendary
*
Offline Offline

Activity: 825
Merit: 1616


Bitcoin and C♯ Enthusiast


View Profile WWW
October 11, 2019, 04:14:07 PM
Merited by hugeblack (2), joniboini (2), ETFbitcoin (1), LoyceV (1), AdolfinWolf (1), mr_random (1), Heisenberg_Hunter (1), TalkStar (1)
 #2

First let's get something out of the way, "scripts" are just scripts. Think of them as a series of data and commands that programmatically define the locking and unlocking conditions for each transaction. They don't have to contain signature + public key. They can have multiple signatures or no signatures at all. For example this script I posted recently is a simple mathematical formula (2+3=5) as the signature!

In bitcoin when an ECDSA signature is provided it will always be accompanied by the corresponding public key. In other words the blockchain already contains the pubkey you just have to first have to figure out the type of script they are using and locate it based on that. There can be lots of scripts but a handful are the most common (and considered standard):
- P2PK (uncommon these days) -> the public key will be in previous transaction's (tx being spent) PubkeyScript (aka scriptpub)
- P2PKH (aka legacy) -> pubkey is in SignatureScript (aka scriptsig)
- P2SH -> in common cases the pub key(s) are in redeem script which is the last item being pushed in SignatureScript
- P2WPKH (aka native SegWit) -> pubkey is in witness item corresponding to the input index.
- P2WSH (aka native SegWit script hash) -> similar to P2SH but it will be in witness items
- nested SegWit (P2WPKH-P2SH and P2WSH-P2SH) are similar to their native counterparts and have the "sig+pub" in their witness

The only thing remaining is to deserialize the transaction bytes into an object (or basically read it byte by byte) to get to the public key. A short example:
Script Sig:
Code:
483045022100f3581e1972ae8ac7c7367a7a253bc1135223adb9a468bb3a59233f45bc578380022059af01ca17d00e41837a1d58e97aa31bae584edec28d35bd96923690913bae9a0141049c02bfc97ef236ce6d8fe5d94013c721e915982acd2b12b65d9b7d59e20a842005f8fc4e02532e873d37b96f09d6d4511ada8f14042f46614a4c70c0f14beff5
Breaking it apart:
Code:
48 <-push
30-45 <-seq. tag + len
02-21 <-int tag + len
00f3581e1972ae8ac7c7367a7a253bc1135223adb9a468bb3a59233f45bc578380 <-r
02-20 <-int tag + len
59af01ca17d00e41837a1d58e97aa31bae584edec28d35bd96923690913bae9a <-s
01 <- sighash type
41 <- push
049c02bfc97ef236ce6d8fe5d94013c721e915982acd2b12b65d9b7d59e20a842005f8fc4e02532e873d37b96f09d6d4511ada8f14042f46614a4c70c0f14beff5 <- uncompressed pubkey
I think this answers your question about getting public key from a "transaction" or "scripts". I didn't want to make this reply that long but if you want to extract signatures (r,s) and derive the public key from that I could explain that part for you too.

Projects List+Suggestion box
Donate: 1Q9s or bc1q
|
|
|
FinderOuter(0.5.0)Ann-git
Denovo(0.0.0)Ann-git
Bitcoin.Net(0.5.0)Ann-git
|
|
|
BitcoinTransactionTool(0.11.0)Ann-git
WatchOnlyBitcoinWallet(3.2.1)Ann-git
SharpPusher(0.10.0)Ann-git
Frodek
Member
**
Offline Offline

Activity: 133
Merit: 18


View Profile
October 11, 2019, 08:43:24 PM
 #3

Thanks!
I previously thougt that "r" and "s" is one array
r and s are relative smaller numbers than key
How compute key? I have "r" and "s" but what is number "message".
Whose numbers I must divide by them?


Code:
049c02bfc97ef236ce6d8fe5d94013c721e915982acd2b12b65d9b7d59e20a842005f8fc4e02532e873d37b96f09d6d4511ada8f14042f46614a4c70c0f14beff5
The number aboce is key?
But is possible compute key from r and s knowing "message"?
bitaps
Member
**
Offline Offline

Activity: 142
Merit: 43

https://bitaps.com/


View Profile WWW
October 11, 2019, 09:15:06 PM
Merited by suchmoon (4), joniboini (2), ETFbitcoin (1), LoyceV (1), Coding Enthusiast (1)
 #4

Yes it is possible but each signature corresponds to 4 possible public key (only 2 in most cases) and you should check all of them

please read this https://crypto.stackexchange.com/questions/60218/recovery-public-key-from-secp256k1-signature-and-message

implementation on python

https://github.com/bitaps-com/pybtc/blob/master/pybtc/functions/script.py#L432

This is example of usage

https://github.com/bitaps-com/pybtc/blob/master/pybtc/transaction.py#L895

https://github.com/bitaps-com/pybtc/blob/master/pybtc/test/transaction_constructor.py#L561





Coding Enthusiast
Legendary
*
Offline Offline

Activity: 825
Merit: 1616


Bitcoin and C♯ Enthusiast


View Profile WWW
October 12, 2019, 03:38:01 AM
Last edit: October 12, 2019, 06:30:09 AM by Coding Enthusiast
 #5

r and s are relative smaller numbers than key
r and s are two numbers that represent x and y coordinates on the elliptic curve used in bitcoin (secp256k1). (correction thanks to achow101) r is the x coordinate of a point on curve, and s is s = k−1(e + rdU) mod n. Because of (mod n) they are both smaller than n which is 32 bytes in length.
If by "key" you mean the public key, you can't define "smaller or bigger" for points (pubkey is also a point). As for the length of them in bytes or the values compared to each other (r with pubkey.x) there still is no reason for it being smaller or bigger. These are numbers that could take up from 1 byte to 32 bytes (ignoring the sign byte).

How compute key? I have "r" and "s" but what is number "message".
The SE link posted by above user explains it.
The "message" for a transaction is double SHA256 hash of the serialized transaction in a different way depending on the SigHashType and the output type (PublicScript) that is being spent. Example of SigHashType.ALL and P2PKH output: https://bitcoin.stackexchange.com/questions/32628/redeeming-a-raw-transaction-step-by-step-example-required

Projects List+Suggestion box
Donate: 1Q9s or bc1q
|
|
|
FinderOuter(0.5.0)Ann-git
Denovo(0.0.0)Ann-git
Bitcoin.Net(0.5.0)Ann-git
|
|
|
BitcoinTransactionTool(0.11.0)Ann-git
WatchOnlyBitcoinWallet(3.2.1)Ann-git
SharpPusher(0.10.0)Ann-git
achow101
Moderator
Legendary
*
expert
Offline Offline

Activity: 2254
Merit: 3456


bc1qshxkrpe4arppq89fpzm6c0tpdvx5cfkve2c8kl


View Profile WWW
October 12, 2019, 05:14:27 AM
Merited by Coding Enthusiast (2), ETFbitcoin (1), hugeblack (1), nc50lc (1)
 #6

Transaction inputs script are usually (but coinbase) 73 bytes signature + 65 bytes key.
But in rare cases I see is only 73 bytes signature.
Is possible get 65 or 33 key from it?
I see
https://learnmeabitcoin.com/guide/digital_signatures_signing_verifying

https://learnmeabitcoin.com/guide/digital_signatures

But I don't know which bytes is messages which is "r" and "s" to divide. I wanna example how to get key from 73 bytes signature (or maybe from signature and message=other fields of input, like amount etc?)
In those cases, the public key is in the blockchain as part of the output. The output is a P2PK output. Bitcoin does not use public key recovery anywhere in transaction validation.

R and s are part of the signature. The signature is a DER encoded signature, and the breakdown of the encoding is given by Coding Enthusiast above.

Thanks!
I previously thougt that "r" and "s" is one array
It is. In Bitcoin, it is one item: a DER encoded signature. Because it is encoded, it can be further broken down into the R and s components. This is done by signature verifiers; Bitcoin itself (i.e. consensus and the script evaluator), do not care that it is encoded and just treat the signature as a single array.

r and s are relative smaller numbers than key
The key itself can be broken down into X and Y components, each of which are of the same magnitude of R and s. The key is also encoded.

How compute key? I have "r" and "s" but what is number "message".
The message is the double SHA256 of the transaction with some modification. For your specific example/question, this SE question and answer should be sufficient: https://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx.

r and s are two numbers that represent x and y coordinates on the elliptic curve used in bitcoin (secp256k1).
They are not. The signature is not a curve point.

R is the X component of the "public key" of the nonce. S is just a scalar computed by the ECDSA formula.

bitaps
Member
**
Offline Offline

Activity: 142
Merit: 43

https://bitaps.com/


View Profile WWW
October 12, 2019, 05:33:05 AM
 #7


How compute key? I have "r" and "s" but what is number "message".
The message is the double SHA256 of the transaction with some modification. For your specific example/question, this SE question and answer should be sufficient: https://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx.


The  "message" in bitcoin transaction signing process this is sighash. We have 2 classes of sighash today, first one is sighash for non segwit inputs and second for segwit inputs.

Sighash calculation algorithm:

for non witness inputs  explained here: https://en.bitcoin.it/wiki/OP_CHECKSIG
                                  python implementation: https://github.com/bitaps-com/pybtc/blob/master/pybtc/transaction.py#L947
                                  tests and examples: https://github.com/bitaps-com/pybtc/blob/master/pybtc/test/sighash.py#L14

for witness inputs defined in BIP 143 https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification
                                  python implementation: https://github.com/bitaps-com/pybtc/blob/master/pybtc/transaction.py#L1020
                                  tests and examples: https://github.com/bitaps-com/pybtc/blob/master/pybtc/test/sighash.py#L521

Frodek
Member
**
Offline Offline

Activity: 133
Merit: 18


View Profile
October 14, 2019, 04:05:17 PM
 #8

I can' t understand because is
48 <-push
30-45 <-seq. tag + len

Hexadecinal 0x48 because in script.h is
Code:
enum opcodetype
{
    // push value
    OP_0 = 0x00,
    OP_FALSE = OP_0,
    OP_PUSHDATA1 = 0x4c,
    OP_PUSHDATA2 = 0x4d,
    OP_PUSHDATA4 = 0x4e,
..........
0x48 is len, not push?
Coding Enthusiast
Legendary
*
Offline Offline

Activity: 825
Merit: 1616


Bitcoin and C♯ Enthusiast


View Profile WWW
October 14, 2019, 04:14:47 PM
 #9

I can' t understand because is
0x48 is len, not push?

True, it is length of the data to be "pushed" onto the stack.
These bytes (from 0x01 to 0x4b) have no name because there is no point in naming them since they each indicate the length equal to their value, so they could be referred to as "push" OPs.

Projects List+Suggestion box
Donate: 1Q9s or bc1q
|
|
|
FinderOuter(0.5.0)Ann-git
Denovo(0.0.0)Ann-git
Bitcoin.Net(0.5.0)Ann-git
|
|
|
BitcoinTransactionTool(0.11.0)Ann-git
WatchOnlyBitcoinWallet(3.2.1)Ann-git
SharpPusher(0.10.0)Ann-git
Frodek
Member
**
Offline Offline

Activity: 133
Merit: 18


View Profile
October 15, 2019, 04:38:39 PM
 #10

I see Bitcoin method:
Quote
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
    if (vchSig.size() != COMPACT_SIGNATURE_SIZE)
        return false;
    int recid = (vchSig[0] - 27) & 3;
    bool fComp = ((vchSig[0] - 27) & 4) != 0;
    secp256k1_pubkey pubkey;
    secp256k1_ecdsa_recoverable_signature sig;
    if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) {
        return false;
    }
    if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) {
        return false;
    }
    unsigned char pub[PUBLIC_KEY_SIZE];
    size_t publen = PUBLIC_KEY_SIZE;
    secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
    Set(pub, pub + publen);
    return true;
}
What is compact signature? It have 65 bytes instead of 73. This are r+s numbers alone?
How I find if r have 32 or 33 bytes?
bitaps
Member
**
Offline Offline

Activity: 142
Merit: 43

https://bitaps.com/


View Profile WWW
October 15, 2019, 06:06:21 PM
 #11

Bitcoin used DER signature format:
Code:
Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
First step you should parse DER format, R and S is always 32 bytes after DER encoding
Code:
compact signature = [R][S] 
look at
Code:
static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) {
    const unsigned char *sigend = sig + size;
    int rlen;
    if (sig == sigend || *(sig++) != 0x30) {
        /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */
        return 0;
    }
    rlen = secp256k1_der_read_len(&sig, sigend);
    if (rlen < 0 || sig + rlen > sigend) {
        /* Tuple exceeds bounds */
        return 0;
    }
    if (sig + rlen != sigend) {
        /* Garbage after tuple. */
        return 0;
    }
    if (!secp256k1_der_parse_integer(rr, &sig, sigend)) {
        return 0;
    }
    if (!secp256k1_der_parse_integer(rs, &sig, sigend)) {
        return 0;
    }
    if (sig != sigend) {
        /* Trailing garbage inside tuple. */
        return 0;
    }
    return 1;
}

secp256k1_der_parse_integer used to parse R and S from DER

https://github.com/bitcoin/bitcoin/blob/452bb90c718da18a79bfad50ff9b7d1c8f1b4aa3/src/secp256k1/src/ecdsa_impl.h#L99


Coding Enthusiast
Legendary
*
Offline Offline

Activity: 825
Merit: 1616


Bitcoin and C♯ Enthusiast


View Profile WWW
October 15, 2019, 06:32:27 PM
Last edit: October 18, 2019, 12:32:42 PM by Coding Enthusiast
 #12

R and S is always 32 bytes after DER encoding

r and s are both at most 32 bytes with 1 byte for sign if the most significant bit is set (they can be smaller than 32 bytes).

Projects List+Suggestion box
Donate: 1Q9s or bc1q
|
|
|
FinderOuter(0.5.0)Ann-git
Denovo(0.0.0)Ann-git
Bitcoin.Net(0.5.0)Ann-git
|
|
|
BitcoinTransactionTool(0.11.0)Ann-git
WatchOnlyBitcoinWallet(3.2.1)Ann-git
SharpPusher(0.10.0)Ann-git
bitaps
Member
**
Offline Offline

Activity: 142
Merit: 43

https://bitaps.com/


View Profile WWW
October 15, 2019, 06:36:49 PM
 #13

In context of compact signature format r and s  32 bytes, this is not about actual value

Frodek
Member
**
Offline Offline

Activity: 133
Merit: 18


View Profile
October 16, 2019, 04:56:07 PM
 #14

Now, let try it with example: (this exmaple is from LTC block 500186, but for Bitcoin this should be similar)
hash (big endian) 3f74be6a1fbd15a5e1101c48e7e31b7777c68fb125f143587d19e1e1c157575c
signature (72 bytes) 304502205d2cb95368167baa75ff86a36827a732ac1ab4ea5c9f53ebebf1c2ae738cc9db0221009 cbec84f5941c7a85a76ef4c617b66a0c52e66e9ec5e8374480521d57a588eb701
key (33 bytes) 026795b2f312bf34204cd314d06b165ca8bb56702eb5ff27b57acfd7c8051e75d8

From signature I tried two methods of extract r and s, first is mine procedure:
Code:
void decodeSignature(vector<unsigned char> &signature, vector<unsigned char> &rnumber, vector<unsigned char> &snumber)
{
    rnumber.clear();
    snumber.clear();
    uint8_t* bytesBegin = signature.data();
    ptrdiff_t ptr = 0;
    if (bytesBegin[ptr] != 0x30)
        throw Exception("signature must have seq. tag = 0x30");
    ptr++;
    int seqLen = bytesBegin[ptr];
    if (seqLen+3 != signature.size())
        throw Exception("signature seq. len mismatch");
    ptr++;
    if (bytesBegin[ptr] != 0x02)
        throw Exception("signature must have int tag = 0x02");
    ptr++;
    int intLen = bytesBegin[ptr];
      rnumber.insert(rnumber.end(), signature.begin()+ptr, signature.begin()+ptr+intLen);
    ptr+=intLen+1;
    if (bytesBegin[ptr] != 0x02)
        throw Exception("signature must have int tag = 0x02");
    ptr++;
    intLen = bytesBegin[ptr];
    snumber.insert(snumber.end(), signature.begin()+ptr, signature.begin()+ptr+intLen);
}

This procedure give me:
r= 205d2cb95368167baa75ff86a36827a732ac1ab4ea5c9f53ebebf1c2ae738cc9
s=21009cbec84f5941c7a85a76ef4c617b66a0c52e66e9ec5e8374480521d57a588e
is easy to verify that its are substring of signature hex string

Second method: is using secp256k1_ecdsa_sig_parse
Code:
uint8_t rr[32], rs[32];
secp256k1_ecdsa_sig_parse((secp256k1_scalar*)rr, (secp256k1_scalar*)rs, signature.data(), signature.size()-1);
Note:
1. I must write signature.size()-1 instead of signature.size() because else is called secp256k1_der_read_len and len mismatch with byte signature[1] meaing len = 69
But output are:
r = dbc98c73aec2f1ebeb539f5ceab41aac32a72768a386ff75aa7b166853b92c5d
s = b78e587ad521054874835eece9662ec5a0667b614cef765aa8c741594fc8be9c
both len are 32 instead of 32 and 33,
Next I concat s+r (mine, because second method give me 32 and 32 not 33)
and call method:
Code:
    vchSig.insert(vchSig.end(), snumber.begin(), snumber.end());
    recoverCompact(hash.data(), vchSig);

bool recoverCompact(const uint8_t hash[32], const std::vector<unsigned char>& vchSig) {
    if (vchSig.size() != COMPACT_SIGNATURE_SIZE)
        return false;
    int recid = (vchSig[0] - 27) & 3;
    bool fComp = ((vchSig[0] - 27) & 4) != 0;
    secp256k1_pubkey pubkey;
    secp256k1_ecdsa_recoverable_signature sig;
    if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) {
        return false;
    }
    if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash)) {
        return false;
    }
    unsigned char pub[PUBLIC_KEY_SIZE];
    size_t publen = PUBLIC_KEY_SIZE;
    secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
    //Set(pub, pub + publen);
    return true;
}
Is error in secp256k1_ecdsa_recover
Code:
        if (i < bits_ng && (n = wnaf_ng[i])) {
            ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G);
            secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
        }
in ecmult-impl.h
I must use not miny but r and s returned by second method? But the are both 32 bytes and is called signature.size()-1
Frodek
Member
**
Offline Offline

Activity: 133
Merit: 18


View Profile
October 17, 2019, 03:06:36 PM
 #15

Two problems:
1. When I secp256k1_ecdsa_sig_parse with sample signature, len mismatch
2. Result are two 32 bytes numbers, whereas
COMPACT_SIGNATURE_SIZE      = 65
(32+33, not 32 +32)
BrewMaster
Legendary
*
Offline Offline

Activity: 1666
Merit: 1129


There is trouble abrewing


View Profile
October 17, 2019, 03:11:46 PM
 #16

This procedure give me:
r= 205d2cb95368167baa75ff86a36827a732ac1ab4ea5c9f53ebebf1c2ae738cc9
s=21009cbec84f5941c7a85a76ef4c617b66a0c52e66e9ec5e8374480521d57a588e
is easy to verify that its are substring of signature hex string

you are forgetting to move your pointer forward after you read the integer lengths after "int intLen = bytesBegin[ptr];" and "intLen = bytesBegin[ptr];" lines. the result is that your r and s values have an extra byte in then (20 and 21 respectively).

achow101
Moderator
Legendary
*
expert
Offline Offline

Activity: 2254
Merit: 3456


bc1qshxkrpe4arppq89fpzm6c0tpdvx5cfkve2c8kl


View Profile WWW
October 17, 2019, 05:18:58 PM
Merited by ETFbitcoin (1), Coding Enthusiast (1)
 #17

R and S is always 32 bytes after DER encoding

r and s are both at most 32 bytes with 1 byte for sign if the most significant bit is set (they can be smaller than 32 bytes).
It isn't really "1 byte for sign". Rather they are big endian signed integers. Because R and s cannot be negative, there is an additional byte added in order to make them a positive signed integer as otherwise they would be interpreted as a negative value which is not valid.

This procedure give me:
r= 205d2cb95368167baa75ff86a36827a732ac1ab4ea5c9f53ebebf1c2ae738cc9
s=21009cbec84f5941c7a85a76ef4c617b66a0c52e66e9ec5e8374480521d57a588e
is easy to verify that its are substring of signature hex string
You have an off by one error in your code somewhere. s begins with 009c.... The 0x21 byte is the length.

Even so, s would still be a 33 byte value. This is because, again, DER requires positive signed integers. However compact signatures use big endian unsigned integers which are always positive. This means that in converting from DER to compact, you can drop leading 0x00 bytes as those are only there to make the integer a positive signed integer.

Two problems:
1. When I secp256k1_ecdsa_sig_parse with sample signature, len mismatch
2. Result are two 32 bytes numbers, whereas
COMPACT_SIGNATURE_SIZE      = 65
(32+33, not 32 +32)
The size of a compact signature here does not refer to just the r and s values. It also includes one additional byte for the recovery id. This is because compact signatures in Bitcoin are only used for signed messages which do public key recovery (as you are trying to do). The recovery id is the first byte of the signature, the rest is the compact signature that you expect (32 byte R followed by 32 byte s).

Frodek
Member
**
Offline Offline

Activity: 133
Merit: 18


View Profile
October 18, 2019, 06:27:52 PM
Last edit: October 18, 2019, 07:46:19 PM by Frodek
 #18

What I am wrong using only Bitcoin code?
I move source code from key_tests.cpp :
Code:
....................
        CPubKey pubkey1  = key1. GetPubKey();
        CPubKey pubkey2  = key2. GetPubKey();
        CPubKey pubkey1C = key1C.GetPubKey();
        CPubKey pubkey2C = key2C.GetPubKey();

        BOOST_CHECK(key1.VerifyPubKey(pubkey1));
        BOOST_CHECK(!key1.VerifyPubKey(pubkey1C));
        BOOST_CHECK(!key1.VerifyPubKey(pubkey2));
        BOOST_CHECK(!key1.VerifyPubKey(pubkey2C));
....................
and it is OK, but my code:
Code:
       vector<uint8_t> vch;
        hashFromString("3f74be6a1fbd15a5e1101c48e7e31b7777c68fb125f143587d19e1e1c157575c", vch);
        uint256 hashMsgMy(vch);
        CPubKey rkeymy;
        std::vector<unsigned char> csignmy;
        hashFromStringLE("304502205d2cb95368167baa75ff86a36827a732ac1ab4ea5c9f53ebebf1c2ae738cc9db0221009cbec84f5941c7a85a76ef4c617b66a0c52e66e9ec5e8374480521d57a588eb701", csignmy);
        BOOST_CHECK(rkeymy.RecoverCompact (hashMsgMy, csignmy));
        string str = hashToStringLE(rkeymy.data(), 65);
        cout << str <<endl;
should be key (33 bytes) 026795b2f312bf34204cd314d06b165ca8bb56702eb5ff27b57acfd7c8051e75d8
but is ff0000007d5671f4de5e3d054859e06f20919cc3d882220266c7a16014560000160000000000000 04d32a26014560000a0f9bcdbff7e0000000000000000000000

Maybe trash in  - trash out, hash is bad or signature is bad, but
why in result is so zeros, even if we get first 33 bytes from 65 bytes

note: string str = HexStr(rkeymy.begin(), rkeymy.end()); give me empty string, because size is 0, all 65 bytes are trash
because
    
Code:
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
    if (vchSig.size() != COMPACT_SIGNATURE_SIZE)
        return false;
Must be 65 not 72 bytes, I again must take a look at changing 72 to 65 bytes

---------------
NOW is without old problems
r = 205d2cb95368167baa75ff86a36827a732ac1ab4ea5c9f53ebebf1c2ae738cc9
s = 009cbec84f5941c7a85a76ef4c617b66a0c52e66e9ec5e8374480521d57a588eb7
but key is 0229364d20762e423fb1d93d1fa05150a2d0277f49feaff924405785de9b6abb4d - look ok,
but I want key 026795b2f312bf34204cd314d06b165ca8bb56702eb5ff27b57acfd7c8051e75d8
What I do wrong?
I give one LTC transaction input.
I give script (thus r and s) give key from script to verify
message to recover script I give hash previous transaction, it is ok?

another:
hash Be 57ad3c7b7ce0654e43ecf7477879c167dcfb079614a1f785a5e87b84823f7d47
signature (71 bytes) 304402200f2f95941a847d5f43d241297e98de0da340cdb4232176be61babd7572b641b30220353 ed805ecda266dfc8ebf56c142239030d3e8be432d3590aeeacfdae15b8abc01
key (33 bytes) 025a76dd6561c1da7be001fa3b7aab0c56496be0230d06c5cd28bdec6ca6a71c85
- can't recover
and other can't recover, only can (with other pubkey than derived fro script)
hash Be 3f74be6a1fbd15a5e1101c48e7e31b7777c68fb125f143587d19e1e1c157575c
signature (72 bytes) 304502205d2cb95368167baa75ff86a36827a732ac1ab4ea5c9f53ebebf1c2ae738cc9db0221009 cbec84f5941c7a85a76ef4c617b66a0c52e66e9ec5e8374480521d57a588eb701

WARNING: only first signature has 32+33 int numbers within, else have 32+32 or 33+33, it is possible?
I call:
Code:
    myRecover("3f74be6a1fbd15a5e1101c48e7e31b7777c68fb125f143587d19e1e1c157575c",
              "304502205d2cb95368167baa75ff86a36827a732ac1ab4ea5c9f53ebebf1c2ae738cc9db0221009cbec84f5941c7a85a76ef4c617b66a0c52e66e9ec5e8374480521d57a588eb701");
    myRecover("57ad3c7b7ce0654e43ecf7477879c167dcfb079614a1f785a5e87b84823f7d47",
              "304402200f2f95941a847d5f43d241297e98de0da340cdb4232176be61babd7572b641b30220353ed805ecda266dfc8ebf56c142239030d3e8be432d3590aeeacfdae15b8abc01");
    myRecover("ae18beb79e3f3f61f080a6a6e4ad793f4557b1a4c0f2bd03bbe0f581916ff24a",
              "3046022100f4d66692601dca84a67c4115affbce4824d02b602197c03f931ae8d5e41fa50c022100b7926308754801fcaacb0a961ebac249b4e4415185df022dae807b3385067d5401");
where
Code:
void myRecover(string hashStr, string signatureStr) {
    vector<unsigned char> script, signature;
    hashFromStringLE(signatureStr.c_str(), signature);
    vector<unsigned char> rnumber, snumber;
    decodeSignature(signature, rnumber, snumber);
    printf("%d %d\n", rnumber.size(), snumber.size());
    decodeSignature(signature, rnumber, snumber);
    string str = hashToStringLE(rnumber);
    printf("r = %s\n", str.c_str());
    str = hashToStringLE(snumber);
    printf("s = %s\n", str.c_str());
    vector<unsigned char> vchSig = rnumber;
    vchSig.insert(vchSig.end(), snumber.begin(), snumber.end());
    vector<uint8_t> vch;
    hashFromString(hashStr.c_str(), vch);
    uint256 hashMsgMy(vch);
    CPubKey rkeymy;
    printf("%d\n", rkeymy.RecoverCompact(hashMsgMy, vchSig));
    str = HexStr(rkeymy.begin(), rkeymy.end());
    cout << str << endl;
}
Frodek
Member
**
Offline Offline

Activity: 133
Merit: 18


View Profile
October 23, 2019, 10:37:41 AM
 #19

Main problem: there are two ways of signing: normal key1.Sign(hashMsg, sign1) and compat key1.SignCompact(hashMsg, csign1) and one recovering rkey1.RecoverCompact(hashMsg, csign1)
CKey::SignCompact uses secp256k1_ecdsa_sign_recoverable but CKey::Sign uses secp256k1_ecdsa_sign (not recoverable) and uses extra_entropy.
It is impossible recover public key from normal signed message?
Warning: inputs signatures are normal signed (70-72 bytes) not compact (65 bytes) followed by key. Is any way to verify?
achow101
Moderator
Legendary
*
expert
Offline Offline

Activity: 2254
Merit: 3456


bc1qshxkrpe4arppq89fpzm6c0tpdvx5cfkve2c8kl


View Profile WWW
October 23, 2019, 08:14:57 PM
 #20

It is extremely likely that you are parsing the hex strings into bytes improperly (or maybe not at all). What do your "hashFromString" and "hashFromStringLE" functions do/work?

Also, the signature is not a hash nor anything little endian, so I don't know why you are passing that into a function named "hashFromStringLE". It isn't hashed either.

Lastly, as has been said multiple times, RecoverCompact takes 65 byte signatures which you can retrieve from the 72 byte one by extracting R and s. Again, R and s BOTH may have leading 0 bytes due to signed integers. You can drop the leading 0 byte so that both R and s are 32 bytes long. If they are shorter than 32 bytes (that is possible), then you need to pad 0's in front of them until they are 32 bytes.

The first byte of the compact signature needs to be a recovery id.

If you have done everything correctly but are still getting the wrong public key, try different recovery ids. There are 4 possible public keys you can recover from the signature, the recovery id just specifies which of those 4. Since you don't have a recovery id, you need to just guess.

Pages: [1]
  Print  
 
Jump to:  

Sponsored by , a Bitcoin-accepting VPN.
Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!