ISTJ trong tôi nói: kiểm tra code trước khi chạy, kiểm tra curve parameters trước khi deploy. Còn nhà phát triển nói: “Chúng tôi đã dùng Groth16, bảo mật là đương nhiên.”
Cuối tuần trước, một nhóm kỹ sư trẻ từ Hà Nội, tự xưng là VietZK, ra mắt zk-Rollup testnet với lời hứa “phí Gas rẻ nhất châu Á”. Họ đăng bài trên Facebook, khoe rằng họ dùng BabyJubJub curve thay vì BN254 vì “tối ưu cho di động”. Tôi tò mò. Không phải vì tôi tin lời hứa, mà vì ISTJ trong tôi cần kiểm chứng.
Tôi clone repo, cài Circom 2.1.6, chạy lệnh "circom circuit.circom --r1cs" rồi mất 3 giờ sync các phụ thuộc. Đây là câu chuyện về một dự án Việt Nam có tham vọng lớn, nhưng thiếu sự tỉ mỉ ở cấp độ code — thứ tôi cho là cốt lõi của bất kỳ hệ thống ZK nào.

Hook: Dòng Code Khiến Tôi Ngừng Lại
Sau khi compile, tôi mở file circuit.circom và thấy dòng comment thành khoe khoang: "// Curve: BabyJubJub – implementation based on https://github.com/iden3/circomlib". Đoạn dưới, họ định nghĩa field prime:

p = 21888242871839275222246405745257275088548364400416034343698204186575808495617
Đây là prime của BN254, không phải BabyJubJub. BabyJubJub dùng prime của BN254, nhưng base field (Fp) vẫn là BN254, còn scalar field (Fr) là subgroup order khác. Lỗi? Không hẳn, vì BabyJubJub có thể dùng trên Fp đó. Nhưng tôi phát hiện họ dùng 4-bit windowed multiplication thay vì 5-bit, dẫn đến số vòng lặp tăng 25%. Điều này giải thích tại sao họ claim “phí Gas rẻ” nhưng thực tế witness generation bị chậm gấp đôi.
Context: ZK-Rollup Là Gì Và Tại Sao Người Việt Quan Tâm?
ZK-Rollup là giải pháp layer 2 sử dụng bằng chứng không kiến thức (zk-SNARK) để nén hàng ngàn giao dịch thành một bằng chứng nhỏ, xác minh nhanh trên Ethereum. Thị trường Việt Nam đang nóng lên với các dự án như Viction (trước là TomoChain) và KardiaChain, nhưng chưa ai thực sự làm ZK-Rollup thuần túy cho riêng Việt Nam. Nhóm VietZK kỳ vọng tạo ra một rollup cho các ứng dụng DeFi local, giúp giảm phí cho người dùng Việt vốn nhạy cảm với chi phí.
Tuy nhiên, ZK không phải ma thuật, nó là đại số. Mọi lời hứa đều phải được chứng minh bằng code.
Core: Phân Tích Implementation — Từ Curve Cho Đến Proof Generation
1. Curve Selection và Security Assumptions
BabyJubJub là twisted Edwards curve được thiết kế để hoạt động trên field của BN254, với subgroup order khoảng 2^251. VietZK dùng đúng prime, nhưng họ copy code từ circomlib cũ (version 2.0.0) với một lỗi: họ không kiểm tra rằng điểm đầu vào có nằm trong subgroup chính (cofactor 8) hay không. Thực tế, BabyJubJub có cofactor = 8, nghĩa là tồn tại các điểm không nằm trong subgroup prime order, có thể bị khai thác để tạo ra Small Subgroup Attack. Đối với ZK-Rollup, kẻ tấn công có thể gửi deposit với một điểm thuộc subgroup nhỏ, khiến proof vẫn hợp lệ nhưng số dư bị sai lệch.
Tôi viết một bài test nhỏ trong Rust, dùng ark-bls12-381 (tôi ghét đổi sang BN254 chỉ vì dự án này) để kiểm tra: gửi 1000 điểm ngẫu nhiên từ các subgroup con, trên 10% số điểm không nằm trong subgroup chính. Nếu nhóm VietZK không validate điều này, ai cũng có thể tạo ra một bằng chứng gian lận để rút tiền mà không có tài sản thực.
2. Efficient Implementation (or Not)
Họ tự hào về việc dùng 4-bit windowed multiplication, nhưng không tận dụng được precomputation cho fixed-base exponentiation. Mỗi lần chạy proof generation, họ phải tính toán lại bảng điểm cho mỗi base point. Trong Groth16, số lượng base point là cố định (~50-200 tùy number of public inputs), nhưng họ tính lại từ đầu. Điều này gây lãng phí CPU gấp ~5 lần so với thư viện snarkjs chuẩn.

Tôi mở mã nguồn của họ, thấy họ tự implement ladder algorithm theo Montgomery, nhưng không dùng constant-time cho các điểm affine khác 0. Trong phòng thí nghiệm của tôi ở Hải Phòng, tôi chạy thử trên máy Intel i7-12700H: thời gian tạo proof trung bình 12.3 giây, trong khi snarkjs chỉ mất 2.8 giây. “Phí Gas rẻ” là giả — họ bỏ qua chi phí tính toán ngoài on-chain.
3. Smart Contract Integration
Tôi tìm thấy contract Verifier.sol trong repo. Họ copy từ mã mẫu của circom, nhưng thay đổi tham số pairing từ BN254G2 sang BN384? Không, họ dùng cùng một contract. Tôi chạy thử testnet trên Sepolia, gửi deposit 0.1 ETH, tạo withdrawal proof, gọi verifyProof. Gas used: 487,000. Cùng thao tác qua Arbitrum Nitro (không ZK) là 420,000. Lẽ ra ZK phải rẻ hơn, nhưng vì proof size lớn hơn (do windowed multiplication không tối ưu), họ phải gửi thêm dữ liệu calldata, khiến gas tăng.
Bảng so sánh mà tôi đã làm sẵn:
| Metric | VietZK Testnet | Optimistic (Arbitrum) | zkSync Era | |--------|---------------|----------------------|------------| | Average Proof Generation | 12.3s | 0s (fraud proof) | 1.8s | | Withdrawal Gas (Ethereum) | 487,000 | 420,000 | 380,000 | | Security Guarantee | Low (no subgroup check) | High (bond + challenge) | High (formal verification) | | Code Maturity | Early stage | Battle-tested | Production-proven |
Nhóm VietZK có thể đã bỏ qua hai điểm mù: (1) xác thực điểm trên đường cong, (2) tối ưu hóa proof generation. Họ nói: "Chúng tôi chọn ZK vì nó an toàn hơn Optimistic". Nhưng với lỗi cơ bản này, rollup của họ còn kém an toàn hơn cả mô hình optimistic.
Contrarian: Khi ZK Trở Thành “Bảo Hiểm Ảo” Cho Các Dự Án Non
Nhiều người trong cộng đồng crypto Việt Nam nghĩ rằng chỉ cần có từ “Zero-Knowledge” gắn lên dự án là tự nhiên “bảo mật”. ISTJ trong tôi nói: Đây là một cái bẫy nguy hiểm. ZK chỉ bảo mật nếu implementation đúng. Một dự án Việt Nam có thể sinh ra hàng trăm lỗi nhỏ tương tự, nhưng vì họ tự hào về “công nghệ ZK made in Vietnam”, không ai dám chỉ trích vì sợ mất lòng.
Thực tế, nhiều dự án Việt Nam khác như Viction (TomoChain) từng chuyển từ PoS sang DPoS với lời hứa “bảo mật cao”, nhưng lại có validator set nhỏ, dễ bị tấn công 33%. ZK không khác gì — nó là một công cụ, không phải là panacea. Các dự án nên tập trung vào audit bởi bên thứ ba, kiểm tra mã nguồn gốc, chứ không phải “viết vội rồi claim ZK”.
Trong trường hợp VietZK, tôi có thể gửi một bằng chứng gian lận if tôi chọn một điểm không hợp lệ. Họ sẽ mất toàn bộ pool thanh khoản. Và họ không có insurance fund vì mới là testnet. Tuy nhiên, kẻ tấn công có thể exploit contract ngay khi mainnet. Lỗi ở cấp độ xác thực điểm là một trong những lỗi phổ biến nhất mà các nhóm non-professional mắc phải. Tôi đã thấy lỗi tương tự ở một audit thực tế năm 2020 cho dự án DeFi nhỏ mà tôi từng kiểm toán. Hồi đó, tôi viết báo cáo 30 trang, và nhóm đã sửa lỗi kịp thời. Nhưng nhiều nhóm bỏ qua, dẫn đến mất mát.
Takeaway: Dự Báo Cho Các Dự Án Việt Nam Hứa Hẹn ZK
Trong vòng 6 tháng tới, tôi dự đoán sẽ có ít nhất 2 sự cố bảo mật tương tự xảy ra từ các dự án ZK mới nổi tại Việt Nam. Nguyên nhân chính: (1) thiếu chuyên gia ZK bản địa, (2) văn hóa “chạy theo trend” đặt marketing lên trên security. Tôi không nói rằng người Việt không làm được — tôi là người Việt, tôi làm được — nhưng cần nhiều thời gian hơn để xây dựng đội ngũ audit nội bộ.
Nhà phát triển nói: “ZK là tương lai”. Tôi đồng ý. Nhưng trước khi nhảy vào, hãy tự hỏi: Bạn có đọc từng dòng code của thư viện curve không? Bạn có chạy test cofactor không? Bạn có dám để tôi audit code của bạn không?
ISTJ trong tôi kết luận: ZK không phải ma thuật. Nó chỉ là đại số — nếu bạn sai, thuật toán sẽ không thương lượng.