DEV Community

Cover image for The Elliptic Curve Digital Signature Algorithm ECDSA
Yusuf Erdogan
Yusuf Erdogan

Posted on

The Elliptic Curve Digital Signature Algorithm ECDSA

The Elliptic Curve Digital Signature Algorithm: ECDSA

The Elliptic Curve Digital Signature Algorithm (ECDSA) is a cryptographic algorithm used to create and verify digital signatures. It is based on the mathematics of elliptic curves and is used in many applications where security and authentication are important, such as in the banking industry, e-commerce, and digital identity systems.

ECDSA works by using a private key to generate a signature for a message, and a corresponding public key to verify the signature. The private key is kept secret and the public key can be shared openly. When a message is signed with the private key, the resulting signature is unique to that message and the private key used to sign it.

To verify the signature, the recipient of the message uses the public key to validate the signature. If the signature is valid, the recipient can be sure that the message was sent by the owner of the private key.

ECDSA is widely used because it provides strong security while requiring relatively little computational power. It is considered one of the most secure signature schemes available today and is widely used in modern cryptography.

How ECDSA used in Ethereum

In Ethereum, ECDSA is used as the algorithm for creating and verifying digital signatures for transaction authentication. Ethereum transactions are signed with the private key of the sender using the ECDSA algorithm, and the signature is included in the transaction data.

When a transaction is broadcasted to the network, nodes on the network use the ECDSA algorithm to verify the signature using the sender's public key. If the signature is valid, the transaction is considered authenticated and can be added to the blockchain.

ECDSA is also used in Ethereum for key management, where public-private key pairs are generated and used to authenticate transactions and sign messages. Additionally, smart contracts in Ethereum can make use of ECDSA for various applications that require secure authentication and digital signatures.

How to create digital signatures using ECDSA

  1. Generate a key pair: The first step is to generate a public-private key pair. This involves selecting a random private key, which is a secret number and using it to derive a public key, which can be shared publicly. The public key is derived by multiplying a fixed point on the elliptic curve by the private key.
  2. Hash the message: The message that needs to be signed is hashed using a cryptographic hash function, which produces a fixed-length hash value.
  3. Sign the message: The ECDSA digital signature is created by performing a series of mathematical operations on the hash value and the private key. These operations result in a unique signature that can only be generated by the sender's private key.
  4. Transmit the message and signature: The original message, along with the digital signature, can be transmitted to the recipient.

Math behind ECDSA

image

ECDSA (Elliptic Curve Digital Signature Algorithm) is a type of digital signature algorithm that uses the mathematics of elliptic curves to provide strong security with relatively little computational power. Here is a brief overview of the math behind ECDSA:

Elliptic curves are a type of algebraic curve defined by an equation in two variables. An elliptic curve over a finite field is a set of points that satisfy the curve equation, along with a point at infinity. The elliptic curve equation takes the form:

y^2 = x^3 + ax + b

where a and b are constants, and x and y are variables that represent the coordinates of a point on the curve.

In ECDSA, the key pair is generated by selecting a random private key, which is a secret number and using it to derive a public key, which can be shared publicly. The public key is derived by multiplying a fixed point on the elliptic curve, known as the generator point, by the private key. The multiplication is done using a special operation called scalar multiplication, which involves adding the generator point to itself a certain number of times.

The digital signature is created by performing a series of mathematical operations on the hash value of the message being signed and the private key. The operations involve scalar multiplication of the generator point and the addition of points on the elliptic curve. The result is a pair of integers that form the signature.

To verify the signature, the recipient performs a similar series of mathematical operations using the public key and the signature. If the result matches the original hash value, then the signature is considered valid.

The security of ECDSA relies on the difficulty of solving the elliptic curve discrete logarithm problem, which involves finding the private key given the public key and the generator point. The elliptic curve discrete logarithm problem is believed to be computationally infeasible for sufficiently large key sizes, making ECDSA a secure digital signature algorithm.

Transaction Signing in Practice

To produce a valid transaction, the originator must digitally sign the message, using
the Elliptic Curve Digital Signature Algorithm. When we say “sign the transaction”
we actually mean “sign the Keccak-256 hash of the RLP-serialized transaction data.”
The signature is applied to the hash of the transaction data, not the transaction itself.
To sign a transaction in Ethereum, the originator must:

  1. Create a transaction data structure, containing nine fields: nonce, gasPrice, gas Limit, to, value, data, chainID, 0, 0.
  2. Produce an RLP-encoded serialized message of the transaction data structure.
  3. Compute the Keccak-256 hash of this serialized message.
  4. Compute the ECDSA signature, signing the hash with the originating EOA’s private key.
  5. Append the ECDSA signature’s computed v, r, and s values to the transaction.

EIP-155 And Replay Attacks

Ethereum prevented replay attacks through the implementation of a feature called "chain ID". Chain ID is a unique identifier that is included in the digital signature of a transaction and indicates which network the transaction is intended for. The chain ID was introduced as part of the Spurious Dragon hard fork, which was implemented in 2016-2017.

Prior to the implementation of chain ID, Ethereum transactions did not include a way to differentiate between different networks. This made them vulnerable to replay attacks, where an attacker could intercept a valid transaction on one network and resubmit it on another network, potentially leading to unintended or malicious behavior.

By adding chain ID to Ethereum transactions, each transaction is now uniquely identified with a specific network. This means that if a transaction is submitted on one network, it cannot be replayed on another network, as the transaction data would be different due to the inclusion of the chain ID.

In practice, the chain ID is included in the v field of the transaction's digital signature data. This allows nodes on the network to verify that a transaction is intended for the correct network before executing it. Transactions that do not include the correct chain ID are rejected by the network, preventing replay attacks from occurring.

Overall, the implementation of chain ID has significantly improved the security and reliability of the Ethereum network by preventing replay attacks and enabling better interoperability between different Ethereum-based networks.

Create Transaction with Ethers.js

Create a hardhat project via npx hardhat and enter the console via yarn run hardhat console

Get a signer from ethers.

signer = await ethers.getSigner()
Enter fullscreen mode Exit fullscreen mode

set Transaction fields

const recipientAddress = "0x1234567890123456789012345678901234567890";
const amountToSend = ethers.utils.parseEther("1.0"); // Send 1 ETH
const gasPrice = ethers.utils.parseUnits("30", "gwei");
const gasLimit = 21000; 
const txData = {
    to: recipientAddress,
    value: amountToSend,
    gasPrice: gasPrice,
    gasLimit: gasLimit
};
Enter fullscreen mode Exit fullscreen mode

With this txData object, we can create transactions using the sendTransaction method.

await signer.sendTransaction(txData)
Enter fullscreen mode Exit fullscreen mode

As we said Create a transaction data structure, containing nine fields: nonce, gasPrice, gasLimit, to, value, data, chainId, 0, 0.

We learned how to check and calculate the nonce of the account in my previous article if you haven't read yet check this article.

https://mirror.xyz/0xE3004Ed52154BfA442C3eD70E924E9C32897Aee5/eLK3X4M0_AaNVOCfkfppIYfhEYzhqBSo5ngSs253CmY

We didn't specify the data so it will be empty.

But v,r, and s values will be calculated when the transaction is signed with the private key.

But if you use 6 elements excluding (chainId,0,0) then the v value will be 27,28 since it is being used until spurious dragon hard fork

But after EIP-155 the following formula is used.

CHAIN_ID * 2 + 35 + {0,1}
Enter fullscreen mode Exit fullscreen mode

The chainId of the ethereum mainnet is 1 so v will be {37,38} for the ethereum transaction.

Signing a message and recovering the address

Let's go to the

https://playground.ethers.org/

And create some random wallet

w = Wallet.createRandom()
Enter fullscreen mode Exit fullscreen mode

And Sign a message using signMessage method. Put any input you want. Mine will be my name.

w.signMessage("Yusuf")
// output : 0xcefc106ffc27cb0defc2b141823433359f72d049de2c296c243bdb5c3f1639366018a1c0fdf2c1fdab4baca7119f6e2348806a2edcc24ec6fb7e671ddff4dc801c
Enter fullscreen mode Exit fullscreen mode

With this output, we proved that this account is ours. And we will be able to recover the public key of this account using the signature and message.

Recover address

We can recover address using solidity in Remix-ide

Our Complete Function will be like this.

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.17;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

contract ECDSASignatures {
    using ECDSA for bytes32;

    function recoverSigner(string memory message, bytes memory signature) public view returns (address) {
        bytes32 hash = ECDSA.toEthSignedMessageHash(bytes(message));
        address signer = ECDSA.recover(hash, signature);
        return signer;
    }

}
Enter fullscreen mode Exit fullscreen mode

I will describe the details from the image because of the line numbers.

We will use OZ’s ECDSA library.

Our Method takes two parameters first one is the message the second one is the signature.

This method is created for educational purposes. You may want to take only the signature and want to sign specific messages from the originator.

Firstly in line 12, we have to find the hash of the message. But messages should be prefixed with "\x19Ethereum Signed Message:\n<LENGTH_OF_THE_STRING>" so my message is “yusuf” its equivalent to 0x5975737566 which is 5 bytes so the length will be five. So the value of the hash variable will be equal to the hash of "\x19Ethereum Signed Message:\n5Yusuf".

When this hash and signature are given to the library method, the signer will be found. And we are %100 percent sure that this address signed this message. This recover method uses ecrecover opcode to recover the address.

image

Check Results

Let's deploy this code on Remix-ide.

And after specifying the parameters we recovered the address.

Screenshot from 2023-03-21 18-08-45

And let's check this address that equals our signer address.

Screenshot from 2023-03-21 18-09-25

We successfully recovered the signer's public key.

References

Contact with me

Oldest comments (0)