# Best way to verify klaytn account ownership

**URL:** https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264
**Category:** Kaia
**Created:** [6월 7, 2021, 7:43오후 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264 "2021-06-07T19:43:33Z")
**Posts on this page:** 15
**Page:** 1

<div class="post-metadata">

### Author: ![rlopez](https://avatars.discourse-cdn.com/v4/letter/r/3be4f8/32.png) [@rlopez](https://devforum.kaia.io/u/rlopez)
#### Post date: [6월 7, 2021, 7:43오후 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/1 "2021-06-07T19:43:33Z")

</div>

If an end user, wishes to link their pre-existing klaytn account to a non klaytn service account that we host, what is the best way to confirm that they own the account?

I’ve considered having the end user sign some text with their private key, but I’m unable to identify the best API for looking up **their** public key to verify the signature.

Looking up my own public key is very easy using the wallet api. But looking up someone else’s public key, to verify their signature, and therefore ownership of their account, does not seem to be possible via the API.

Am I going about this the wrong way? Is there a better strategy for verifying account ownership?

---

<div class="post-metadata">

### Author: ![colin.kim](https://yyz1.discourse-cdn.com/flex035/user_avatar/devforum.kaia.io/colin.kim/32/55_2.png) [@colin.kim](https://devforum.kaia.io/u/colin.kim)
#### Post date: [6월 8, 2021, 4:30오전 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/2 "2021-06-08T04:30:54Z")

</div>

Hi, thanks for filing a question on Klaytn Forum.

Your approach to check the ownership of the account seems good to me.

You can check out someone else’s public key via [klay\_getAccountKey](https://docs.klaytn.com/bapp/json-rpc/api-references/klay/account#klay_getaccountkey).

Note that there can be some cases that the account’s public key type is [AccountKeyLegacy](https://docs.klaytn.com/klaytn/design/accounts#accountkeylegacy). In this case, the public key will not be shown. You can find the address like the following formula:

`Address = keccak256(pubkey)[12:]`

Hope this helps.

---

<div class="post-metadata">

### Author: ![rlopez](https://avatars.discourse-cdn.com/v4/letter/r/3be4f8/32.png) [@rlopez](https://devforum.kaia.io/u/rlopez)
#### Post date: [6월 8, 2021, 11:48오후 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/3 "2021-06-08T23:48:59Z")

</div>

I’m having trouble getting this to work. Can anyone comment on what is wrong with this request? ( note creds removed )

```auto
curl https://node-api.klaytnapi.com/v1/klaytn --header 'x-chain-id: 1001' -H "Content-Type: application/json" -u ***:*** --data '{"jsonrpc":"2.0","method":"klay_getAccountKey","params":["0xE93a82CF4840666977b84f5a3AD63b351DC6eF35", "latest"],"id":1}'

```

I get the following response:

```auto
{"jsonrpc":"2.0","id":2,"result":null}

```

---

<div class="post-metadata">

### Author: ![colin.kim](https://yyz1.discourse-cdn.com/flex035/user_avatar/devforum.kaia.io/colin.kim/32/55_2.png) [@colin.kim](https://devforum.kaia.io/u/colin.kim)
#### Post date: [6월 8, 2021, 11:52오후 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/4 "2021-06-08T23:52:17Z")

</div>

It seems the account may not be initialized (i.e., the account has not been used.)

Please try to use an account which has been sent/receive KLAY or executed any contract.

for the uninitialized accounts, you can follow the second rule as I told you before:

`Address = keccak256(pubkey)[12:]`

---

<div class="post-metadata">

### Author: ![rlopez](https://avatars.discourse-cdn.com/v4/letter/r/3be4f8/32.png) [@rlopez](https://devforum.kaia.io/u/rlopez)
#### Post date: [6월 8, 2021, 11:57오후 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/5 "2021-06-08T23:57:28Z")

</div>

Awesome! Thank you. I will initialize the address and test.

However, regarding this:

> [@colin.kim](#):
>
> Address = keccak256(pubkey)[12:]

It looks like the address is derived from the keccak256 hash of the public key. Have I understood that correctly?

In my case, I’d like to do the reverse. I’d like to get a public key, from a known address.

The idea is that the user requests to link an address to our service.

We give the user keccak256 hashed value to sign.

The user signs this value using

```auto
https://wallet-api.klaytnapi.com/v2/key/krn: ***:wallet:*** :key-pool:default:***/sign

```

Then we lookup their public key, using the address they specified in their initial request, and verify the signature.

---

<div class="post-metadata">

### Author: ![rlopez](https://avatars.discourse-cdn.com/v4/letter/r/3be4f8/32.png) [@rlopez](https://devforum.kaia.io/u/rlopez)
#### Post date: [6월 9, 2021, 12:06오전 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/6 "2021-06-09T00:06:03Z")

</div>

Okay, using a wallet that has sent Klay, I do get a response as follows:

```auto
curl https://node-api.klaytnapi.com/v1/klaytn --header 'x-chain-id: 1001' -H "Content-Type: application/json" -u ***:*** --data '{"jsonrpc":"2.0","method":"klay_getAccountKey","params":["0x329d18c99f679d721100f1ca85e1fe0c986f3268", "latest"],"id":2}'

```

Returns

```auto
{"jsonrpc":"2.0","id":2,"result":{"keyType":1,"key":{}}}

```

As you can see the keytype is 1. Which appears to be legacy as you have mentioned above.

---

<div class="post-metadata">

### Author: ![colin.kim](https://yyz1.discourse-cdn.com/flex035/user_avatar/devforum.kaia.io/colin.kim/32/55_2.png) [@colin.kim](https://devforum.kaia.io/u/colin.kim)
#### Post date: [6월 9, 2021, 12:07오전 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/7 "2021-06-09T00:07:30Z")

</div>

Actually, reversing keccak256 should be impossible. If it is easy, then the hash function should be replaced. 🙂

So, I think this can be done like below:

1. You received the signature from the sign API as you said.
2. You can get the public key from the signature.
3. You can derive the address from the signature.

At the moment, we do not provide function 2 in our SDK. Sorry for that. The function will be released soon. (We are implementing this.)

But you can get the address (combination of 2 and 3) via [caver.utils.recover](https://docs.klaytn.com/bapp/sdk/caver-js/api-references/caver.utils#recover).

Hope this helps.

---

<div class="post-metadata">

### Author: ![rlopez](https://avatars.discourse-cdn.com/v4/letter/r/3be4f8/32.png) [@rlopez](https://devforum.kaia.io/u/rlopez)
#### Post date: [6월 9, 2021, 12:10오전 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/8 "2021-06-09T00:10:48Z")

</div>

This is an incredible help. That should give me everything I need.

Thanks @colin.kim!

---

<div class="post-metadata">

### Author: ![rlopez](https://avatars.discourse-cdn.com/v4/letter/r/3be4f8/32.png) [@rlopez](https://devforum.kaia.io/u/rlopez)
#### Post date: [6월 9, 2021, 6:27오전 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/9 "2021-06-09T06:27:12Z")

</div>

Well, I’m back.

Here’s my signature

```auto

0xbf55f159f05b73e48a83806a7cf836c5e3efe8699532116995e22f64b6db315f783de8d75d35494b5b357c91fe750def0463be1b86777cb74a6068a9bf619d3d01

```

I’ve been looking through carver-java source code to try and find out how to get the public key out of this so I can verify it.

The problem is, I can’t tell how it’s encoded.

Is it raw encoding? rlp? der? I can’t seem to get it to parse no matter what I do.

How can I extract the R, S and V components needed to recover the public key?

You’ll notice that my key doesn’t end in “0x1b” as do the keys on carver-js.

> **[caver.wallet.keyring](https://docs.klaytn.com/bapp/sdk/caver-js/api-references/caver.wallet/keyring#signaturedata)**

I believe that is supposed to be the “recovery id” in a simple concatenation encoding of the signature.

But mine is below “27” and so is invalid. Therefore, the signatures obtained from the “key api” “sign” call must be in a different format.

Again I’m using this API

```auto
curl --request POST 'https://wallet-api.klaytnapi.com/v2/key/krn:1001:wallet:2b90x ***:key-pool:default:0x*** /sign'

```

Rather than this one

```auto
curl https://node-api.klaytnapi.com/v1/klaytn --header 'x-chain-id: 1001' -H "Content-Type: application/json" -u ***:*** --data '{"jsonrpc":"2.0","method":"klay_sign","params":["0x329d18c99f679d721100f1ca85e1fe0c986f3268", "0xdeadbeaf"],"id":1}'

```

Because the latter is documented as not supported by KAS and gives me the following error:

```auto
Unsupported method - klay_sign"

```

---

<div class="post-metadata">

### Author: ![rlopez](https://avatars.discourse-cdn.com/v4/letter/r/3be4f8/32.png) [@rlopez](https://devforum.kaia.io/u/rlopez)
#### Post date: [6월 10, 2021, 1:22오전 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/10 "2021-06-10T01:22:28Z")

</div>

Looking closer at the signature. It can’t be a DER. There aren’t enough bytes to cover the R & S values of the signature plus all of the header bytes.

But it’s doesn’t appear to have a “recId” for recovering the public key. When you sign through the RPC api ( not available on KAS ) you get a proper “recovery id” byte at the end. That recovery id value has to be in a certain range and in this case, the value at that position is “1” which is not a valid recovery id.

It’s possible the last byte is just a version. That would mean the format includes the R & S segments of the signature, plus a version . The issue with that format is, I don’t believe I can recover the public key.

However, all of that is probably moot anyway, because I believe the wallet API will only apply to KAS hosted wallets. Which means that we’ll need a different strategy for enabling customers to sign messages that does not involve the KAS APIs at all.

Still, I’d love to know what the format of this signature is, if anyone is able to comment. Just for a sense of resolution 🙂

---

<div class="post-metadata">

### Author: ![rlopez](https://avatars.discourse-cdn.com/v4/letter/r/3be4f8/32.png) [@rlopez](https://devforum.kaia.io/u/rlopez)
#### Post date: [6월 10, 2021, 3:31오전 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/11 "2021-06-10T03:31:57Z")

</div>

On further reading. It seems that versions 1 & 0 are also technically valid versions. Though 27 and 28 are generally expected.

---

<div class="post-metadata">

### Author: ![rlopez](https://avatars.discourse-cdn.com/v4/letter/r/3be4f8/32.png) [@rlopez](https://devforum.kaia.io/u/rlopez)
#### Post date: [6월 10, 2021, 7:55오전 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/12 "2021-06-10T07:55:41Z")

</div>

After a lot of digging and testing. I believe this is the appropriate way to deserialize the signature.

```auto

        final Sign.SignatureData signatureData = new Sign.SignatureData(
                Arrays.copyOfRange(signatureBytes, 64, 65),
                Arrays.copyOfRange(signatureBytes, 0, 32),
                Arrays.copyOfRange(signatureBytes, 32, 64)
                );

```

Similar implementation here:

. [eth-lib/account.js at master · MaiaVictor/eth-lib · GitHub](https://github.com/MaiaVictor/eth-lib/blob/master/src/account.js)

Which I believe is used here

. [caver-js/utils.js at dev · klaytn/caver-js · GitHub](https://github.com/klaytn/caver-js/blob/dev/packages/caver-utils/src/utils.js)

However, using this approach, along with carver-java’s “Utils.recover()” method, I’m unable to correctly extract the address used to sign an arbitrary string with the Kaikas wallet on the kaikas tutorials site.

```auto
Address: 0x9462e1f20dd41d3def4a206e00a1767a6787411a
Message: test
Signature: 0x70b6343882d94dfc34f201b368d2747b0dab3f0db02804408680835ec3d513567c33a8bb58e19eafc371e2dc10a99fc9b1579577f1c21d0e616fce99d5971e391c

```

When I run a

```auto
Utils.recover("test", signatureData /* as deserialized above*/) 

```

I get the following address:

```auto
0x849963e0388746505e3839d3048a83fc007ef189

```

Which naturally is not a match and does not validate.

However, if I use the private key for this address

```auto
0x329d18c99f679d721100f1ca85e1fe0c986f3268

```

To sign a message using

```auto
org.web3j.crypto.Sign.signMessage()

```

And then run a `Utils.recover` on that, I get the correct address as a result.

What do I need to do differently to verify Kaikas signatures? It would seem that they are using a different algorithm.

---

<div class="post-metadata">

### Author: ![rlopez](https://avatars.discourse-cdn.com/v4/letter/r/3be4f8/32.png) [@rlopez](https://devforum.kaia.io/u/rlopez)
#### Post date: [6월 13, 2021, 12:35오전 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/13 "2021-06-13T00:35:28Z")

</div>

Okay, here are all the details of my latest attempt to verify a signature produced by kaikas wallet.

( sans private key, although, this is a test only wallet )

Signature was produced here: [https://tutorial.kaikas.io/](https://tutorial.kaikas.io/) ( See attached screenshot )

 ![address2](https://canada1.discourse-cdn.com/flex035/uploads/klaytn/original/1X/945b5e072e73c55286b5eb8303226b8748153fea.png)

Verification Details

```auto
        final String address = "0x50E97c2F3fEaD7ea27a0620a48272C16472636a2";
        final String message = "test";
        final String messageBytesHexEncoded = "0x74657374";
        final String preamble = "\\x19Klaytn Signed Message:\\n4";
        final String preambleBytesHexEncoded = "0x5c7831394b6c6179746e205369676e6564204d6573736167653a5c6e34";
        final String messageBytesPrependedWithKlaytnPreambleBytes = "0x5c7831394b6c6179746e205369676e6564204d6573736167653a5c6e3474657374";
        final String messagePrependedWithKlaytnPreambleHashedKeccak256 = "0x0f38a34b35e1508707d3ecc1d4fe01ce9f33f659897432f4a36048bdd207bcf6";
        final String signature = "0xd7e1d551839cd40679ea5d6188683c2e821695991e9de7c91a18f6c8bf100f3b4855ae255698a880c3d71c8e32af6da6877acdbce43980d43bef4b7c98728a4f1c";
        final String signatureV= "0x1c";
        final String signatureR= "0xd7e1d551839cd40679ea5d6188683c2e821695991e9de7c91a18f6c8bf100f3b";
        final String signatureS= "0x4855ae255698a880c3d71c8e32af6da6877acdbce43980d43bef4b7c98728a4f";

        com.klaytn.caver.utils.Utils.recover(mesasgePrependedWithKlaytnPreambleHashedKeccak256, new SignatureData(signatureV, signatureR, signatureS), true);
        org.opentest4j.AssertionFailedError:
        Expected :0x50E97c2F3fEaD7ea27a0620a48272C16472636a2
        Actual :0x72088fd4a2594a0d3dcb17b2b259a42227ce7507

```

Can anyone comment on what I’m doing wrong trying to verify this signature?

---

<div class="post-metadata">

### Author: ![Kale](https://yyz1.discourse-cdn.com/flex035/user_avatar/devforum.kaia.io/kale/32/148_2.png) [@Kale](https://devforum.kaia.io/u/Kale)
#### Post date: [6월 15, 2021, 4:55오전 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/14 "2021-06-15T04:55:07Z")

</div>

Hi, @rlopez.  
Sorry for the late reply.  
There was a problem with caver-java’s Utils.recover() method.([Modified to hashMessage() logic and add a Utils.decodeSignature() by sirano11 · Pull Request #248 · klaytn/caver-java · GitHub](https://github.com/klaytn/caver-java/pull/248))  
We published caver-java v1.6.2-rc.4 version that solved this problem.(Of course, caver-java v1.6.2 version will also be published today.)  
If you use this version and refer to the following code, I think the address through the signature will be verified.

```auto
String signData = "0xf6fa6ccc206eaff47d907304c25bd3d1af498a4d0a8dd014c0b4879d66d70aff7f4309981bb92a781248a612a78207587d0c4d8d69cf015afe02342c0ca1b8011b";
String expectedAddress = "0xb6a1f97502431e6f8d701f9e192c3cc43c07351a";

String recovered = caver.utils.recover("sign test", caver.utils.decodeSignature(signData));
System.out.println(recovered.equals(expectedAddress));

```

---

<div class="post-metadata">

### Author: ![rlopez](https://avatars.discourse-cdn.com/v4/letter/r/3be4f8/32.png) [@rlopez](https://devforum.kaia.io/u/rlopez)
#### Post date: [6월 17, 2021, 2:30오전 UTC](https://devforum.kaia.io/t/best-way-to-verify-klaytn-account-ownership/1264/15 "2021-06-17T02:30:16Z")

</div>

SO AWESOME!!!

You guys!! I love that there is a `decodeSignature()` too! 🙂 THANK YOU!

```auto
Address recovered from Kaikas signature: 0x50e97c2f3fead7ea27a0620a48272c16472636a2

```

SUCCESS!!!

This unlocks so many doors. I’m super excited.
