0
$\begingroup$

I tried to recover public key from P256 signature. With 2 recovery id ( 0, 1 ), signature makes 2 public key. And I tried to verify signature with public key and verification was succeed all of 2 keys.

Isn’t it correct that only one of the two should succeed? Or is there some cryptographic knowledge I don't know about? Is it correct that both public keys succeed? I attach the data I used below.

original public key

asn1 der (hex) : 3059301306072a8648ce3d020106082a8648ce3d03010703420004761c025b761d7a7c6d4bfd8d944975915e3d4879a2fead6e4417bdfe5de0ac36f5730e0e8082a3a964bd1e503236b1356f086b08dc39cc24288c6ef563917c53
---
x (hex) : 761c025b761d7a7c6d4bfd8d944975915e3d4879a2fead6e4417bdfe5de0ac36
y (hex) : f5730e0e8082a3a964bd1e503236b1356f086b08dc39cc24288c6ef563917c53

Signature

raw message (hex) : 49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763050000000047e4a6a9816d7dd36ad0772e8738f9423d147ebf0253cc91c5a0def297d0decb
sha256 hashed message ( for signature recovery ) (hex) : fdb2e37b8fdc643c1c94e1a1abd1876966e8f17a2d63dd2e4acb7be2e680751a

signature asn1 der (hex) : 3046022100cf4f49499b70e7fcc76193478fedcba4735456d9ca3b4fda3feafe2c16e35b6d022100cb30d5bbbb42eca0fb4dd8b056df2e058db0b8dc63e2f52d137cb580688f4063
- r (hex) : cf4f49499b70e7fcc76193478fedcba4735456d9ca3b4fda3feafe2c16e35b6d
- s (hex) : cb30d5bbbb42eca0fb4dd8b056df2e058db0b8dc63e2f52d137cb580688f4063

Recovered Public Key

recovered public key with recovery id 0
hex : 04260e3fa4c347cccdcc12e86e2f1a543f679648a31d0b26484da39f75b16b0be06d8f8231e1f819368c6c0dc52a9e62a3e90095478ead3ba4ee62e84e90182862
- x (hex) : 260e3fa4c347cccdcc12e86e2f1a543f679648a31d0b26484da39f75b16b0be0
- y (hex) : 6d8f8231e1f819368c6c0dc52a9e62a3e90095478ead3ba4ee62e84e90182862

recovered public key with recovery id 1
hex : 04761c025b761d7a7c6d4bfd8d944975915e3d4879a2fead6e4417bdfe5de0ac36f5730e0e8082a3a964bd1e503236b1356f086b08dc39cc24288c6ef563917c53
- x (hex) : 761c025b761d7a7c6d4bfd8d944975915e3d4879a2fead6e4417bdfe5de0ac36
- y (hex) : f5730e0e8082a3a964bd1e503236b1356f086b08dc39cc24288c6ef563917c53

and all of two keys succeed to verify above signature(3046022100cf4f4....).

In order to extract the correct public key from the signature, I obtained the public key corresponding to all recovery IDs (0 to 3, a total of 4), and verified the signature with these public keys to find a successful public key. However, both public keys successfully verified their signatures. I'm curious about this.

Below is the code where I experimented with this process.

import {secp256r1} from '@noble/curves/p256'
import sha256 from 'sha256';


async function test2() {
    let pub = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdhwCW3YdenxtS_2NlEl1kV49SHmi_q1uRBe9_l3grDb1cw4OgIKjqWS9HlAyNrE1bwhrCNw5zCQojG71Y5F8Uw'
    let hexPub = Buffer.from(pub, 'base64').toString('hex')
    console.log(hexPub)
    const mayBeX = '761c025b761d7a7c6d4bfd8d944975915e3d4879a2fead6e4417bdfe5de0ac36' // i want find this public key from signature ( assume i dont know recovery id )
    const mayBeY = 'f5730e0e8082a3a964bd1e503236b1356f086b08dc39cc24288c6ef563917c53' // i want find this public key from signature ( assume i dont know recovery id )

    const testChallengeHex = '49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763050000000047e4a6a9816d7dd36ad0772e8738f9423d147ebf0253cc91c5a0def297d0decb'
    const testHexSig = '3046022100cf4f49499b70e7fcc76193478fedcba4735456d9ca3b4fda3feafe2c16e35b6d022100cb30d5bbbb42eca0fb4dd8b056df2e058db0b8dc63e2f52d137cb580688f4063'

    const msgHash = sha256(Buffer.from(testChallengeHex, 'hex'));
    let sigObj = secp256r1.Signature.fromDER(testHexSig)
    console.log('signature')
    console.log(sigObj.r.toString(16))
    console.log(sigObj.s.toString(16))

    sigObj = sigObj.addRecoveryBit(0)
    console.log(`msgHash`)
    console.log(msgHash)
    console.log('----------------')

    const recovered = sigObj.recoverPublicKey(msgHash);
    console.log(`recovered`)
    console.log(recovered.toHex(false))
    console.log(recovered.toAffine().x.toString(16))
    console.log(recovered.toAffine().y.toString(16))
    console.log('----------------')
    const verified = secp256r1.verify(sigObj, msgHash, recovered.toHex(false))
    console.log(verified)

}

test2().catch(console.log)

Thank you for your interest in my problem.

$\endgroup$
2
  • $\begingroup$ @Gilles'SO-stopbeingevil' crypto.stackexchange.com/a/18138/114071 says that both key ( by recovery id 0 , 1 and ignore n>2 case ) can validate same signature. If that's true, then it's the answer I was looking for. It would be nice if the process was a little more detailed, but as long as the answer is correct, the answer to my question is correct. $\endgroup$
    – 박해성
    Commented Feb 11 at 10:23
  • $\begingroup$ Top. If you're still stuck somewhere don't hesitate to comment or ask a new question :) $\endgroup$
    – Maarten Bodewes
    Commented Feb 12 at 14:31

0