Score:1

js-ethereum-cryptography secp256k1 signature difficulties

pt flag

I'm currently undertaking a course on Blockchain cryptography. And our first project is to transfer tokens from one wallet to another using client / server application. All mock of course.

This project is using the prescribed https://www.npmjs.com/package/ethereum-cryptography

The theory is this as I understand it:

Client side

  • generate public and private key
  • Create what I call an action object - {operation: "transfer", from (public key), to (public key), amount}
  • Hash the action
  • Sign the hash with private key to create a signature
  • Post the {action, signature} to the server

Server side

  • Verify the action using the signature and public key
  • Perform the transfer between wallets (if valid)

I'm pretty sure that this is correct.

Now what I had to do required quite a bit of investigation and work arounds and it just feels like it should have been simpler. I'd like to know if there is a better way. Here is what I had to do:

Client side

  • Client side - generate public and private key
  • Create what I call an action - {operation: "transfer", from (public key), to (public key), amount}
  • Hash the action with keccak256(utf8ToBytes(JSON.stringify(action)))
  • Sign the hash with private key to create a Signature using secp256k1.sign(actionHash, privateKey)
  • work around -> Because the returned Signature contains bigints (which seemingly don't serialize), I had to use https://www.npmjs.com/package/json-bigint to stringify it
  • Post the {action, signature} to the server

Server side

  • work around -> Use json-bigint with { useNativeBigInt: true } option to parse the signature (for BigInt(..) in the next step)
  • Whoops, I missed a detail previously. The (typed) signature of verify is:
    verify: (signature: Hex | {
        r: bigint;
        s: bigint;
    }, msgHash: Hex, publicKey: Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;

and as I discuss below, I couldn't get the Hex version of signature to work and despite it just seeming to take a {r: bigInt, s: bigInt}, verify complained that I need to pass a Signature object.

class Signature {
    constructor({r, s, recovery}) {
        // const {r, s, recovery} = SigLikeObj;
        this.r = BigInt(r);
        this.s = BigInt(s);
        this.recovery = recovery;
    }
}
  • Verify it with secp256k1.verify(signatureFixed, actionHash, publicKey)
  • Perform transfer

The json-bigint requirement is a detail, but the need to create a class Signature seems wrong.

I saw that the signature in verify() can be a Hex though I couldn't see a way to create this.

I tried this on the Server:

    const signatureObj = JSONbig.parse(signatureJson);
    const signatureHex = toHex(new Uint8Array(signatureObj))
    const isValid = secp256k1.verify(signatureHex, actionHash, publicKey);

But verification fails this way.

Am I missing something - is there an easier way to handle the class Signature or to make a Hex out of it?

Score:1
pt flag

Doh! I updated the question with more detail of the error and then that action highlighted that I completely missed something so obvious.

I just needed to do this for the signature problem:

    const signatureObj = JSONbig.parse(signatureJson);
    const signatureObj2 = { r: signatureObj.r, s: signatureObj.s }
    const isValid = secp256k1.verify(signatureObj2, actionHash, publicKey);

I must admit I've solved a lot of issues by trying to explain the problem on StackExchange. Most often I work it out before posting the question. Oh well, I hope I've helped others.

I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.