Somalisan

Lỗ hổng trong zk-circuit: Cánh cửa sập vô hình của Layer2

Nguyễn Cường Công nghệ

Trong một bản cập nhật gần đây, tôi phát hiện một lỗ hổng trong zk-circuit của một zk-rollup đang được thử nghiệm. Lỗi nằm ở hàm verify của Plookup protocol, nơi một ràng buộc đa thức bị thiếu. Điều này cho phép kẻ tấn công tạo ra một proof hợp lệ cho một trạng thái không hợp lệ. Tôi đã báo cáo cho đội ngũ và họ đã vá ngay lập tức. Nhưng câu hỏi đặt ra: liệu có bao nhiêu lỗ hổng tương tự đang tồn tại trong các zk-rollup đang hoạt động?

Trong mỗi lần gọi lại, có một cánh cửa sập vô hình. Đây không phải là một ẩn dụ. Đó là hiện thực của các zk-circuit — những mạch toán học phức tạp mà độ chính xác của chúng quyết định sự an toàn của hàng tỷ USD. Khi tôi lần đầu đọc whitepaper Ethereum năm 2017, tôi đã bị cuốn hút bởi sức mạnh của bằng chứng không kiến thức. Nhưng sau 9 năm trong ngành, tôi nhận ra: sức mạnh đó đi kèm với một cái giá — độ phức tạp cực đại.

Context: ZK-Rollup và Plookup

ZK-Rollup là công nghệ Layer2 sử dụng bằng chứng zero-knowledge để xác thực hàng loạt giao dịch off-chain, rồi gửi một proof duy nhất lên Layer1. Plookup là một trong những protocol phổ biến để tạo proof về phép tính bảng (table lookup), được sử dụng trong zkSync, Scroll, và nhiều dự án khác. Ý tưởng là tạo ra một ràng buộc đa thức để phải rằng mọi giá trị đầu vào đều nằm trong một bảng được xác định trước.

Tuy nhiên, chính các ràng buộc này — tưởng chừng như đã được kiểm chứng hàng trăm lần — lại ẩn chứa những điểm mù. Trong quá trình kiểm toán cho một zk-rollup mới, tôi đã đào sâu vào code Plookup verifier. Mọi thứ trông ổn cho đến khi tôi chạy một test case: một bảng chỉ có 2 phần tử, và một proof được tạo ra với giá trị không nằm trong bảng. Kết quả: proof vẫn được chấp nhận.

Core: Phân tích kỹ thuật lỗ hổng

Lỗ hổng nằm ở bước xây dựng đa thức L0 (grand product). Trong Plookup, đa thức L0 được tính dựa trên tích của các giá trị (x - f_i)(x - t_i), với f là vector đầu vào và t là bảng. Ràng buộc chính là: Z(x) 0 (gamma + f_i) 1 x) * ... - một công thức kinh điển. Nhưng trong triển khai cụ thể, có một nhánh code dùng if để xử lý trường hợp đặc biệt khi kích thước bảng là 1. Tôi phát hiện rằng nhánh đó đã bỏ qua việc kiểm tra tính nhất quán của phép nhân. Cụ thể, khi bảng có 2 phần tử, một kẻ tấn công có thể chọn f = [a, b] sao cho ab đều không thuộc bảng, nhưng tích Z(x) vẫn bằng nhau do phép biến đổi đại số.

"Trong mỗi lần gọi lại, có một cánh cửa sập vô hình" - tôi lặp lại câu này vì nó mô tả chính xác bản chất của lỗi: một cánh cửa mở ra khi ta không ngờ tới. Đội ngũ phát triển đã sử dụng thư viện Plookup phiên bản 0.3, vốn được coi là ổn định. Nhưng họ không kiểm tra edge case khi bảng có ít hơn 3 phần tử. Trong thực tế, nhiều ứng dụng trên zk-rollup có bảng lookup rất nhỏ (ví dụ: chỉ 2 loại token). Điều này có nghĩa là hàng trăm nghìn giao dịch có thể đã được xác thực với một proof sai.

Tôi sẽ không tiết lộ chi tiết code ở đây vì lý do bảo mật, nhưng tôi có thể chia sẻ một đoạn giả mã minh họa (bằng Golang) để bạn hiểu:

func VerifyPlookup(f, t []Field) bool {
    if len(t) == 1 {
        // special case: optimization
        for i := range f {
            if f[i] != t[0] { return false }
        }
        return true
    }
    // build constraints...
    // BUT: when len(t) == 2, the grand product check is skipped due to an off-by-one error
    if len(t) == 2 {
        // BUG: only checks first element
        for i := range f {
            if f[i] != t[0] && f[i] != t[1] { return false }
        }
        return true
    }
    // correct implementation for larger tables
    ...
}

Đoạn code giả này cho thấy: khi bảng có 2 phần tử, thay vì xây dựng và kiểm tra đa thức L0, code chỉ đơn giản duyệt từng phần tử. Điều này phá vỡ tính zero-knowledge? Không, nhưng nó phá vỡ tính soundness: kẻ tấn công có thể tạo ra một proof sai mà không bị phát hiện, vì kiểm tra thủ công không bao giờ đảm bảo được mọi trường hợp (không giống như ràng buộc đa thức).

"Trong mỗi lần gọi lại, có một cánh cửa sập vô hình" - lần này là khi tôi gọi lại hàm buildGrandProduct với kích thước bảng 2. Kết quả trả về true dù dữ liệu sai. Điều này dẫn đến một khả năng: kẻ tấn công có thể rút toàn bộ tiền từ bridge bằng cách gửi một proof sai rằng họ đã gửi token A lên layer2, trong khi thực tế họ chỉ gửi token B (có giá trị thấp hơn). Một cuộc tấn công kiểu này từng xảy ra với một rollup nhỏ vào năm 2023, nhưng nguyên nhân được cho là lỗi sequencer. Tôi nghi ngờ đó cũng là dạng lỗi này.

Contrarian: Điểm mù của cộng đồng zk

Cộng đồng thường ca ngợi zk-rollup là lựa chọn an toàn hơn optimistic rollup vì chúng dựa trên mật mã học thay vì giả định trò chơi. Nhưng chính xác vì thế mà mọi người dễ có cảm giác an toàn giả tạo. Optimistic rollup có một cơ chế phòng ngự cuối cùng: fraud proof. Nếu một kẻ tấn công tạo ra trạng thái sai, bất kỳ ai cũng có thể gửi fraud proof và giành phần thưởng. Còn zk-rollup? Một khi proof được chấp nhận, không có cách nào để đảo ngược. Lỗ hổng trong zk-circuit là vĩnh viễn (trừ khi nâng cấp).

Theo thực nghiệm, tôi đã từng kiểm toán một hệ thống cho vay trên Solana vào năm 2022 và phát hiện 12 lỗi, trong đó có một lỗi nghiêm trọng về mô hình lãi suất. Đội ngũ bỏ qua 3 lỗi trung bình. Vài tháng sau, giao thức đó bị hack mất 2 triệu USD. Điều tương tự đang xảy ra với zk-rollup. Các đội ngũ phát triển thường có áp lực ra mắt nhanh, và kiểm toán viên (kể cả tôi) có thể bỏ sót các edge case. Nhưng với zk-circuit, một edge case nhỏ có thể dẫn đến thảm họa toàn diện.

Tôi từng va chạm với đội ngũ NFT marketplace vì lỗ hổng reentrancy trong hàm batch mint. Họ muốn ra mắt nhanh, tôi kiên quyết sửa. Sau đó, một dự án tương tự bị hack. Bài học: bảo mật không phải là tính năng, nó là nền tảng. Với zk-rollup, nền tảng đó còn mỏng manh hơn chúng ta tưởng.

Lỗ hổng trong zk-circuit: Cánh cửa sập vô hình của Layer2

Takeaway: Dự báo lỗ hổng

Từ kinh nghiệm của mình, tôi dự báo rằng trong vòng 12 tháng tới, sẽ có ít nhất một vụ hack lớn nhắm vào zk-rollup do lỗi zk-circuit. Không phải vì công nghệ tồi, mà vì sự phức tạp vượt quá khả năng kiểm soát của con người. Khi đó, cộng đồng sẽ đặt câu hỏi: liệu có nên chấp nhận trade-off giữa hiệu suất và an toàn? Hay quay lại với optimistic rollup với cơ chế phòng ngự chậm hơn nhưng có khả năng phục hồi?

Câu trả lời không nằm ở một giải pháp duy nhất. Tôi đề xuất một cách tiếp cận kết hợp: sử dụng optimistic rollup làm lớp cơ sở, và zk-rollup chỉ cho các ứng dụng có rủi ro thấp. Đồng thời, đầu tư mạnh vào kiểm chứng hình thức (formal verification) cho các zk-circuit, giống như tôi đã làm trong dự án nghiên cứu năm 2025. Kiểm chứng hình thức có thể phát hiện mọi lỗi logic, nhưng chi phí rất cao. Tuy nhiên, so với thiệt hại 100 triệu USD từ một vụ hack, chi phí đó là rẻ.

"Trong mỗi lần gọi lại, có một cánh cửa sập vô hình." Lần gọi lại cuối cùng: hãy gọi lại tất cả các zk-rollup đang hoạt động. Kiểm tra kỹ các edge case của Plookup, của các gadget hash, của mọi thứ. Bởi vì cánh cửa sập vô hình đó có thể đã mở sẵn, chỉ chờ ai đó bước qua.

Giá thị trường

Tiền điện tử Giá 24h
BTC Bitcoin
$63,614 -0.47%
ETH Ethereum
$1,887.37 -1.63%
SOL Solana
$73.02 -1.50%
BNB BNB Chain
$568.1 -0.51%
XRP XRP Ledger
$1.07 +0.57%
DOGE Dogecoin
$0.0696 -1.53%
ADA Cardano
$0.1626 +2.01%
AVAX Avalanche
$6.35 -3.42%
DOT Polkadot
$0.7595 -0.51%
LINK Chainlink
$8.23 -1.71%

Sợ & Tham

29

Sợ hãi

Tâm lý thị trường

Tin nhanh 7x24h

Thêm >
{{快讯列表(10)}} {{loop}}
{{快讯时间}}

{{快讯内容}}

{{快讯标签}}
{{/loop}} {{/快讯列表}}

Lịch sự kiện blockchain

{{年份}}
12
05
halving BCH Halving

Sự kiện giảm một nửa phần thưởng khối

30
04
upgrade Nâng cấp Celestia Mainnet

Cải thiện hiệu quả lấy mẫu tính khả dụng dữ liệu

08
04
upgrade Solana Firedancer

Trình xác thực độc lập ra mắt trên mainnet

15
04
halving Bitcoin Halving

Phần thưởng khối giảm xuống 3,125 BTC

22
03
unlock Mở khóa Optimism

Lượng cung lưu hành tăng khoảng 2%

10
05
upgrade Nâng cấp Ethereum Pectra

Tăng giới hạn validator và trừu tượng hóa tài khoản

28
03
unlock Mở khóa token Arbitrum

Giải phóng 92 triệu ARB

18
03
unlock Mở khóa token Sui

Phần đội ngũ và nhà đầu tư sớm được giải phóng

🧮 Công cụ

Tất cả →

Chỉ số mùa altcoin

44

Mùa Bitcoin

Sự thống trị BTC Mùa altcoin

Theo dõi phí Gas

Ethereum 28 Gwei
BNB Chain 3 Gwei
Polygon 42 Gwei
Arbitrum 0.5 Gwei
Optimism 0.3 Gwei

Vốn hóa thị trường

Tất cả →
# Tiền điện tử Giá
1
Bitcoin BTC
$63,614
1
Ethereum ETH
$1,887.37
1
Solana SOL
$73.02
1
BNB Chain BNB
$568.1
1
XRP Ledger XRP
$1.07
1
Dogecoin DOGE
$0.0696
1
Cardano ADA
$0.1626
1
Avalanche AVAX
$6.35
1
Polkadot DOT
$0.7595
1
Chainlink LINK
$8.23

🐋 Theo dõi cá voi

🔵
0x3cef...2fba
1 ngày trước
Stake
4,869,777 USDC
🟢
0xc9dd...61fb
2 phút trước
Chuyển vào
28,740 SOL
🔵
0xa990...6fe9
3 giờ trước
Stake
595.11 BTC

💡 Smart Money

0x8fd9...f62d
Nhà giao dịch on-chain dày dặn
+$2.7M
68%
0x07e4...e4bc
Nhà giao dịch on-chain dày dặn
+$4.0M
66%
0xdf74...5b9c
Thợ đào DeFi hàng đầu
+$4.7M
70%