Trang chủHướng dẫnHướng dẫn verify signatures trong Solidity
Blockchain

Hướng dẫn verify signatures trong Solidity

CyStack blog 3 phút để đọc
CyStack blog04/05/2025
Locker Avatar

Đức Hacker

My passion is hunting down the latest attack trends—ransomware, APTs, you name it—while passing on knowledge to help businesses forge ironclad defenses. I’ve left my mark on data encryption projects and intrusion detection tools now widely used across Vietnam. I’m the shadow that strikes before the enemy does.
Locker logo social
Reading Time: 3 minutes

Khi mình bắt đầu tập tành lập trình blockchain, việc verify signatures trong solidity khiến mình khá bối rối. Sau một thời gian tự mày mò, mình đã hiểu được cách hoạt động cũng như cách triển khai nó. Trong bài viết này, mình sẽ chia sẻ lại mọi thứ theo đúng hành trình học và “giác ngộ” của mình, để bạn nào mới tìm hiểu về cách verify signatures trong Solidity cũng có thể nắm bắt nhanh chóng!

verify signatures in solidity

Cách ký một message

Trước khi tìm hiểu cách verify signature Solidity, đầu tiên mình phải học cách ký (sign) một message.

Ở phía frontend (ví dụ như trên website), quá trình ký sẽ diễn ra như thế này:

javascript
CopyEdit
async function signMessage() {
    if (!window.ethereum) return alert("Please cài Metamask!");

    // Kết nối tới ví
    const accounts = await ethereum.request({ method: "eth_requestAccounts" });

    // Message cần ký
    const message = "hello";
    console.log({ message });

    // Hash message
    const hashedMessage = Web3.utils.sha3(message);
    console.log({ hashedMessage });

    // Ký hashed message
    const signature = await ethereum.request({
      method: "personal_sign",
      params: [hashedMessage, accounts[0]],
    });
    console.log({ signature });

    // Tách signature ra thành r, s, v
    const r = signature.slice(0, 66);
    const s = "0x" + signature.slice(66, 130);
    const v = parseInt(signature.slice(130, 132), 16);
    console.log({ r, s, v });
}
💡 Một lưu ý nhỏ: Khi dùng personal_sign, Ethereum sẽ tự động thêm tiền tố “\\x19Ethereum Signed Message:\\n32” trước khi ký, để đảm bảo an toàn, tránh việc ai đó lừa bạn ký những giao dịch nguy hiểm.

Build Smart Contract để Verify

Sau khi đã có message đã được ký, việc tiếp theo là xây smart contract để verify signatures solidity.

Mình đã viết một contract mẫu đơn giản như sau:

solidity
CopyEdit
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Verify {
    function VerifyMessage(bytes32 _hashedMessage, uint8 _v, bytes32 _r, bytes32 _s) public pure returns (address) {
        bytes memory prefix = "\\x19Ethereum Signed Message:\\n32";
        bytes32 prefixedHashMessage = keccak256(abi.encodePacked(prefix, _hashedMessage));
        address signer = ecrecover(prefixedHashMessage, _v, _r, _s);
        return signer;
    }
}

Một vài điểm quan trọng mình muốn nhấn mạnh:

  • Phải thêm prefix trước khi hash lại message.
  • Hàm ecrecover sẽ trả về địa chỉ Ethereum đã ký message đó.
  • Nếu address trả về đúng với người mà bạn mong đợi => signature hợp lệ.

Có thể bạn quan tâm: Quy trình 6 bước để tổ chức ICO token

Ứng dụng thực tế: Game Unity phát thưởng

Một ví dụ thực tế mà mình rất thích: sử dụng verify signature solidity trong game blockchain.

Giả sử bạn lập trình viên game:

  • Khi người chơi thắng, server game sẽ ký một message chứng nhận chiến thắng (giống như phát “phiếu thưởng”).
  • Người chơi gửi signature đó lên smart contract để claim phần thưởng.

Ví dụ contract:

solidity
CopyEdit
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Verify {
    address public owner = 0xdD4c825203f97984e7867F11eeCc813A036089D1; // Địa chỉ của server game

    function claimPrize(bytes32 _hashedMessage, uint8 _v, bytes32 _r, bytes32 _s) public view returns (bool) {
        bytes memory prefix = "\\x19Ethereum Signed Message:\\n32";
        bytes32 prefixedHashMessage = keccak256(abi.encodePacked(prefix, _hashedMessage));
        address signer = ecrecover(prefixedHashMessage, _v, _r, _s);

        if (signer == owner) {
            return true; // Người chơi hợp lệ => thưởng
        }
        return false; // Không hợp lệ
    }
}

Ở client side (ví dụ Unity), mình sẽ tách chữ ký ra như thế này:

csharp
CopyEdit
string signature = "0xb7cf302145348387b9e69fde82d8e634a0f8761e78da3bfa059efced97cbed0d2a66b69167cafe0ccfc726aec6ee393fea3cf0e4f3f9c394705e0f56d9bfe1c91c";
string r = signature.Substring(0, 66);
string s = "0x" + signature.Substring(66, 64);
int v = int.Parse(signature.Substring(130, 2), System.Globalization.NumberStyles.HexNumber);

Sau đó người chơi chỉ cần gửi _r, _s, _vhashedMessage vào contract để nhận thưởng.

Tổng kết

Việc verify signatures in Solidity thực ra không quá phức tạp, bạn chỉ cần lưu ý:

  • Hash message đúng chuẩn.
  • Thêm prefix "\\x19Ethereum Signed Message:\\n32" trước khi xác thực.
  • Dùng ecrecover để lấy địa chỉ người ký.

Nếu bạn đang muốn làm các dự án liên quan tới xác thực người dùng, phát coupon, kiểm tra quyền truy cập… thì việc phải master kỹ năng này là rất hữu ích đấy!

Bài viết liên quan:

0 Bình luận

Đăng nhập để thảo luận

CyStack blog

Mẹo, tin tức, hướng dẫn và các best practice độc quyền của CyStack

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.