mhw0/libethc

Obtaining ECDSA r and s values correctly

Closed this issue · 3 comments

Hey, sorry for another noob question. I'm trying to sign a message and extract r and s values from it correctly but I'm failing with getting the values right.

Here's an identical code in TypeScript using viem:

const { address } = privateKeyToAccount(pk)

console.log(`Address: ${address}`)

const hash = hashMessage('Hello World')

const signature = await sign({ hash, privateKey: pk })

console.log(`\nSignature:\nr = ${signature.r}\ns = ${signature.s}`)

It produces the following output:

Address: 0x765E2DA311bB2CC31B6FCd868A25cD6E99FA15Ae

Signature:
r = 0xafc74bc20e99cf4596bd71568010f2e2af4d5ae47eb2fd8a1b81e77023de8713
s = 0x12b445d37912241b557612657cf39cc4da8f65b931d86c9ba41f3e1029fd7

Internally it does something similar to keccak256p by appending eth prefix

I'm trying to achieve the same result with libethc:

#include <stdio.h>
#include <stdlib.h>
#include <ethc/account.h>
#include <ethc/hex.h>
#include <string.h>
#include <ethc/keccak256.h>

int main() {
    const char *hexstr = getenv("PK"); // 0x9ef...
    uint8_t *privkey;
    
    struct eth_account acc;

    // Call the function with the correct parameters
    eth_hex_to_bytes(&privkey, hexstr, strlen(hexstr));
    eth_account_from_privkey(&acc, privkey);

    char addr[40];
    eth_account_address_get(&addr, &acc);

    printf("Address: 0x%s", addr);

    struct eth_signed signature;
    char str[] = "Hello World"; // Example string
    uint8_t result = (uint8_t)atoi(str);

    // Compute keccak256 + prefix hash;
    uint8_t keccak[32];
    eth_keccak256p(keccak, &result, strlen(str));

    eth_account_sign(&signature, &acc, keccak, 32);

    printf("\n\nSignature: ");
    printf("\nr = 0x");
    char *r;
    eth_hex_from_bytes(&r, signature.r, 32);
    printf(r);
    printf("\ns = 0x");
    char *s;
    eth_hex_from_bytes(&s, signature.s, 32);
    printf(s);
}

But the output is different from viem's:

Address: 0x765e2da311bb2cc31b6fcd868a25cd6e99fa15ae

Signature: 
r = 0x45161301e875d1389fcc738e944ce8310c8ce3ed51e0c2cc45a29ba9abe28eab
s = 0x0e28f678a3b4ec4d077011b8a8ceab7c115614aafc1bc1f800937d2ac92934c6
mhw0 commented

Hello @talentlessguy!

Try passing raw str not the hash of it:

eth_account_sign(&signature, &acc, str, strlen(str));
mhw0 commented

Because eth_account_sign internally hashes the input with eth_keccak256p

Okay it worked, thanks!

sorry once again for bothering 🙏