I'm currently relearning Solidity to consolidate some details and write a 'WTF Solidity QuickStart' for newbies to use (programming experts can find other tutorials), with 1-3 updates per week.
Welcome to follow my Twitter: @0xAA_Science
Welcome to join the WTF Scientist community, where you can find instructions to join our WeChat group: link
All code and tutorials are open-sourced on GitHub (course certification with 1024 stars, community NFT with 2048 stars): github.com/AmazingAng/WTF-Solidity
In this lecture, we will briefly introduce the digital signature ECDSA in Ethereum and how to use it to issue an NFT whitelist. The ECDSA library used in the code is simplified from the library of the same name from OpenZeppelin.
Digital Signature
If you have traded NFT on opensea, you are no stranger to signatures. The following picture shows the window that pops up when the metamask wallet signs, which can prove that you own the private key without exposing it to the public.

The digital signature algorithm used in Ethereum is called the Elliptic Curve Digital Signature Algorithm (ECDSA), which is a digital signature algorithm based on the "private-public key" pair of elliptic curves. It mainly plays three roles:
- Identity authentication: Prove that the signer is the holder of the private key.
- Non-repudiation: The sender cannot deny having sent the message.
- Integrity: The message cannot be modified during transmission.
ECDSA Contract
The ECDSA standard consists of two parts:
- The signer uses the
private key(private) to create asignature(public) for themessage(public). - Others use the
message(public) andsignature(public) to recover the signer'spublic key(public) and verify the signature.
We will work together with the ECDSA library to explain these two parts. The private key, public key, message, Ethereum signed message, and signature used in this tutorial are shown below:
Creating a signature
1. Packing the message: In the Ethereum ECDSA standard, the message being signed is the keccak256 hash of a set of data, which is of type bytes32. We can pack any content we want to sign using the abi.encodePacked() function, and then use keccak256() to calculate the hash as the message. In our example, the message is obtained from a 'uint256type variable and anaddress` type variable.

2. Calculate Ethereum Signature Message: The message can be an executable transaction or anything else. In order to prevent users from signing malicious transactions by mistake, EIP191 recommends adding the "\x19Ethereum Signed Message:\n32" character before the message, and then doing another keccak256 hash to create the Ethereum Signature Message. The message processed by the toEthSignedMessageHash() function cannot be used to execute transactions.
The processed message is:

3-1. Sign with wallet: In daily operations, most users sign messages using this method. After obtaining the message that needs to be signed, we need to use the Metamask wallet to sign it. The personal_sign method of Metamask will automatically convert the message into an Ethereum signed message and then initiate the signature. So we only need to input the message and the signer wallet account. It should be noted that the input signer wallet account needs to be consistent with the account currently connected by Metamask.
Therefore, you need to first import the private key in the example into the Foxlet wallet, and then open the console page of the browser: Chrome menu-more tools-developer tools-Console. Under the status of connecting to the wallet (such as connecting to OpenSea, otherwise an error will occur), enter the following instructions step by step to sign:
The created signature can be seen in the returned result (PromiseResult). Different accounts have different private keys, and the created signature values are also different. The signature created using the tutorial's private key is shown below:

3-2. Signing with web3.py: When it comes to batch calling, signing with code is preferred. The following is an implementation based on web3.py.
This is Python code that uses the web3 library and eth_account module to sign a message using a given private key and Ethereum address. It connects to the Ankr ETH RPC endpoint and prints the keccak hash of the message and the resulting signature.
The result of the execution is shown below. The calculated message, signature, and earlier examples are consistent.
Verify Signature
To verify the signature, the verifier needs to have the message, signature, and the public key used to sign the message. We can verify the signature because only the holder of the private key can generate such a signature for the transaction, and nobody else can.
4. Recover Public Key from Signature and Message: The signature is generated by a mathematical algorithm. Here we use the rsv signature, which contains information about r, s, v. Then, we can obtain the public key from r, s, v, and the Ethereum signature message. The recoverSigner() function below implements the above steps. It recovers the public key from the Ethereum signature message _msgHash and the signature _signature (using simple inline assembly):
The parameters are:

5. Compare public keys and verify the signature: Next, we just need to compare the recovered public key with the signer's public key _signer to determine if they are equal: if they are, the signature is valid; otherwise, the signature is invalid.
These are parameters:

Using Signatures to Issue Whitelist for NFTs
The NFT project can use the feature of ECDSA to issue a whitelist. Since the signature is off-chain and does not require gas, this whitelist issuance mode is more economical than the Merkle Tree mode. The method is very simple. The project uses the project account to sign the whitelist issuance address (can add the tokenId that the address can mint). Then, when minting, use ECDSA to check if the signature is valid. If it is valid, give it mint.
The SignatureNFT contract implements the issuance of NFT whitelist using signatures.
State Variables
There are two state variables in the contract:
signer:public key, the project signature address.mintedAddressis amapping, which records the addresses that have already beenminted.
Functions
There are four functions in the contract:
- The constructor initializes the name and symbol of the
NFT, and thesigneraddress ofECDSAsignature. - The
mint()function accepts three parameters: the addressaddress,tokenId, and_signature, verifies whether the signature is valid: if it is valid, theNFToftokenIdis minted to theaddressaddress, and it is recorded inmintedAddress. It calls thegetMessageHash(),ECDSA.toEthSignedMessageHash(), andverify()functions. - The
getMessageHash()function combines themintaddress (addresstype) andtokenId(uint256type) into amessage. - The
verify()function calls theverify()function of theECDSAlibrary to performECDSAsignature verification.
remix Verification
-
Sign the
signatureoff-chain on Ethereum, and whitelist the_accountaddress withtokenId = 0. See the <ECDSAContract> section for the data used. -
Deploy the
SignatureNFTcontract with the following parameters:
Deploying the SignatureNFT contract.
Calling the mint() function to sign and mint the contract using ECDSA verification, with the following parameter:

- By calling the
ownerOf()function, we can see thattokenId = 0has been successfully minted to the address_account, indicating that the contract has been executed successfully!

Summary
In this section, we introduced the digital signature ECDSA in Ethereum, how to create and verify signatures using ECDSA, and ECDSA contracts, and how to distribute NFT whitelists using them. The ECDSA library in the code is simplified from the same library of OpenZeppelin.
- Since the signature is off-chain and does not require
gas, this whitelist distribution model is more cost-effective than theMerkle Treemodel; - However, since users need to request a centralized interface to obtain the signature, a certain degree of decentralization is inevitably sacrificed;
- Another advantage is that the whitelist can be dynamically changed, rather than being hardcoded in the contract in advance because the central backend interface of the project can accept requests from any new address and provide whitelist signatures.