1

The Web3 library provides the function web3.eth.accounts.sign which in return gives the raw RLP encoded signature, using that signature we get the R, S, V values that can be used to recover the signer address.

https://web3js.readthedocs.io/en/v1.2.11/web3-eth-accounts.html#sign

ECDSA signatures in Ethereum consist of three parameters r, s, and v. Solidity provides a globally available method ecrecover that returns an address given these three parameters. If the returned address is the same as the signer’s address, then the signature is valid.

When signing with AWS-KMS it returns signature the value in the required format the returned value is a DER-encoded object.

https://docs.aws.amazon.com/kms/latest/APIReference/API_Sign.html#API_Sign_ResponseSyntax

The cryptographic signature that was generated for the message.

this message contains the R, S but not V. Is it possible to get the V from the signed transaction anyways??

Understanding Ethereum signatures

2 Answers 2

2

This article may help “The Dark Side of the Elliptic Curve - Signing Ethereum Transactions with AWS KMS in JavaScript” https://luhenning.medium.com/the-dark-side-of-the-elliptic-curve-signing-ethereum-transactions-with-aws-kms-in-javascript-83610d9a6f81

1

You're on the right track! To calculate v, you can adapt this logic :

Determining the v Value: The ECDSA signature used in Ethereum consists of three key elements: r, s, and a recovery identifier named v. Historically, before the implementation of EIP-155, the value of v could be either 27 or 28. However, since the adoption of EIP-155, the value of v is now determined based on the chain_id of the network where the transaction is being executed, thus altering the method of calculating this essential component of the signature.

For transactions on networks where EIP-155 is active, the value of v is calculated using the formula v = chain_id * 2 + 35 or v = chain_id * 2 + 36.

To identify the correct value of v in an Ethereum signature, one can use the function ecrecover(sig, v, r, s). This function returns the public key corresponding to an Ethereum signature. Since you have already calculated the Ethereum address before, we know what the result of this equation should be. Thus, it is possible to test the two potential values of v to determine which one is correct.

public static calculateV(address: Buffer, digest: Buffer, r: Buffer, s: Buffer, chainId?: bigint) : bigint {
    /**
     * This is the function to find the right v value
     * There are two matching signatues on the elliptic curve
     * we need to find the one that matches to our public key
     * it can be v = `candidate_1` or v = `candidate_2`
     */
    const candidate_1 = (chainId) ? (chainId * BigInt(2) + BigInt(35)) : BigInt(27);
    const candidate_2 = (chainId) ? (chainId * BigInt(2) + BigInt(36)) : BigInt(28);
    if (Buffer.compare(address, ethutil.publicToAddress(ethutil.ecrecover(digest, candidate_1, r, s, chainId)) === 0) {
        return candidate_1;
    } else if (Buffer.compare(address, ethutil.publicToAddress(ethutil.ecrecover(digest, candidate_2, r, s, chainId)) === 0) {
        return candidate_2;
    } else {
        return BigInt(-1);
    }
}

=> For more details, you can read this article, everything is explained there : https://jonathanokz.medium.com/secure-an-ethereum-wallet-with-a-kms-provider-2914bd1e4341

Alternatively, you can use this npm library to handle all the complexity for you : https://github.com/JonathanOkz/web3-kms-signer

import { Signer } from "@web3-kms-signer/core";
import { KMSWallets } from "@web3-kms-signer/kms-wallets";
import { KMSProviderAWS } from "@web3-kms-signer/kms-provider-aws";

const awsConfig = {
    region: 'us-east-1',
    credentials: {
        accessKeyId: 'YOUR_AWS_ACCESS_KEY_ID',
        secretAccessKey: 'YOUR_AWS_SECRET_ACCESS_KEY'
    }
};
const provider = new KMSProviderAWS(awsConfig);

const chainId = 3; // Ropsten
const signer = new Signer(new KMSWallets(provider), chainId);

const txData = {
    nonce: '0x00', // Replace with actual nonce
    gasPrice: '0x09184e72a000', // Replace with actual gas price
    gasLimit: '0x2710', // Replace with actual gas limit
    to: '0x0000000000000000000000000000000000000000', // Replace with recipient address
    value: '0x00', // Amount to send
    data: '0x0', // Data payload if any
};

const signedTx = await signer.signTransaction({ keyId: 'keyId' }, txData);
2
  • Link only answer are discouraged. Please add an example how to use it, and use the link to expand the details.
    – Ismael
    Commented Feb 21 at 0:54
  • 1
    @Ismael I've expanded on my response as requested. I hope this will be clearer!
    – a9911b
    Commented Feb 21 at 11:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.