How to recovery the publicKey with "js-ethereum-cryptography" version 2.0?

111 Views Asked by At

I have a problem with the recoverPublicKey() method in the latest version of . I can get the values of { r, s, recovery }, but I cannot recover the public key because I get an undefined error in the browser. Thanks for your help!

app.post("/send", (req, res) => {
  const { sender, recipient, amount, signature } = req.body;
  const { r, s, recovery } = signature;
  const publicKey = secp.secp256k1.recoverPublicKey({ r, s, recovery }, sender);
  console.log(publicKey.toString());
  //...
});
1

There are 1 best solutions below

0
lcnicolau On

From the Upgrading section of oficial repository:

Upgrading from 1.0 to 2.0:

  1. secp256k1 module was changed massively: before, it was using noble-secp256k1 1.7; now it uses safer noble-curves. Please refer to upgrading section from curves README. Main changes to keep in mind: a) sign now returns Signature instance b) recoverPublicKey got moved onto a Signature instance
  2. node.js 14 and older support was dropped. Upgrade to node.js 16 or later.

And from Upgrading section of noble-curves:

Upgrading from noble-secp256k1 1.7:

  • recoverPublicKey(msg, sig, rec) was changed to sig.recoverPublicKey(msg)

So, you should first recreate the signature object from the JSON data, and then use it to recover the public key. Note that depending on how you serialised the (BigInt) r and s, you may need to convert them back to BigInt first.

Also, even in the old version of the library, recovery is done from the signature and the hash of the transaction data, not from the sender (as in your code).

const { secp256k1 } = require("ethereum-cryptography/secp256k1");
const { keccak256 } = require("ethereum-cryptography/keccak");
const { utf8ToBytes } = require("ethereum-cryptography/utils");

//...

app.post("/send", (req, res) => {
    const { transaction, signature } = req.body;
    const { sender, recipient, amount } = transaction;
    const { r, s, recovery } = signature;

    //const sig = new secp256k1.Signature(BigInt(r), BigInt(s), recovery);
    const sig = new secp256k1.Signature(r, s, recovery);

    const data = JSON.stringify(transaction);
    const hash = keccak256(utf8ToBytes(data));

    //const publicKey = sig.recoverPublicKey(hash).toRawBytes();
    const publicKey = sig.recoverPublicKey(hash).toHex();
    console.log('public key:', publicKey);

    //...
});

Finally, depending on what you need to do with the public key, you can use the toRawBytes() or toHex() methods, and even get the uncompressed version by specifying the isCompressed = false parameter.