Cointime

Download App
iOS & Android

Nhìn lại nguyên lý của Tornado Cash: cái gai trong mắt cơ quan quản lý nhưng lại là ứng dụng ZK tinh tế nhất

Tác giả: Faust, đam mê web3

Giới thiệu: Gần đây, Vitalik và một số học giả đã cùng xuất bản một bài báo mới, trong đó đề cập đến cách Tornado Cash có thể thực hiện giải pháp chống xi tiền (thực ra, nó cho phép người rút tiền chứng minh rằng hồ sơ gửi tiền của anh ta thuộc về một bộ sưu tập không chứa tiền đen ), nhưng bài viết thiếu hiểu biết về Tornado Cash, việc diễn giải chi tiết về logic và nguyên tắc kinh doanh của Cash khiến người ta tưởng như đã hiểu nhưng chưa hiểu.

Ngoài ra, điều đáng nói là các dự án quyền riêng tư do Tornado đại diện thực sự sử dụng bản chất không có kiến ​​thức của thuật toán ZK-SNARK, trong khi hầu hết các Bản tổng hợp dưới biểu ngữ ZK chỉ sử dụng tính đơn giản của ZK-SNARK. Nhiều khi mọi người có xu hướng nhầm lẫn giữa sự khác biệt giữa Bằng chứng xác thực và ZK, và Tornado là một trường hợp tuyệt vời để hiểu các ứng dụng ZK.

Tác giả bài viết này tình cờ đã viết một bài về nguyên lý của Tornado trong Web3Caff Research vào năm 2022. Hôm nay, tôi đã trích dẫn và mở rộng một số đoạn trong đó và biên soạn thành một tài liệu để mọi người có thể hiểu Tornado Cash một cách có hệ thống.

Liên kết gốc:

https://research.web3caff.com/zh/archives/2663?ref=157

Nguyên lý “cơn lốc xoáy”

Tornado Cash là một giao thức trộn tiền xu sử dụng bằng chứng không có kiến ​​thức. Phiên bản cũ được đưa vào sử dụng vào năm 2019 và phiên bản mới ra mắt phiên bản beta vào cuối năm 2021. Phiên bản cũ của Tornado về cơ bản là phi tập trung. Các hợp đồng trên chuỗi là nguồn mở và không có kiểm soát đa chữ ký. Mã mặt trước là nguồn mở và được sao lưu trong mạng IPFS. Do cấu trúc tổng thể của phiên bản Tornado cũ đơn giản và dễ hiểu hơn nên bài viết này sẽ giải thích về phiên bản cũ.

Ý tưởng chính của Tornado là kết hợp một số lượng lớn tiền gửi và rút tiền với nhau. Sau khi người gửi gửi Mã thông báo vào Tornado, họ sẽ xuất trình Bằng chứng ZK để chứng minh rằng họ đã gửi tiền và sau đó sử dụng địa chỉ mới để rút tiền, từ đó cắt đứt địa chỉ gửi và rút tiền.

Nói một cách cụ thể hơn, Tornado giống như một chiếc hộp thủy tinh với những đồng xu được trộn vào từ nhiều người. Chúng ta có thể thấy ai đã đặt những đồng xu, nhưng những đồng xu này rất đồng nhất, nếu một người lạ lấy một đồng xu từ hộp thủy tinh, chúng ta khó có thể biết được người ban đầu đã đặt đồng xu mà người đó lấy là ai.

Nói một cách cụ thể hơn, Tornado giống như một chiếc hộp thủy tinh với những đồng xu được trộn vào từ nhiều người. Chúng ta có thể thấy ai đã đặt Đồng xu, nhưng những Đồng xu này rất đồng nhất, nếu một người lạ lấy Đồng xu từ hộp thủy tinh, chúng ta khó có thể biết được người ban đầu đã đặt Đồng xu mà người đó lấy là ai.

Kịch bản này có vẻ phổ biến: khi chúng tôi SWAP một vài ETH từ nhóm Uniswap, không có cách nào để biết ai đã cung cấp số ETH đã loại bỏ, bởi vì có quá nhiều người đã cung cấp thanh khoản cho Uniswap. Nhưng điểm khác biệt là mỗi lần sử dụng Uniswap để chuyển Token, chúng ta cần sử dụng các Token khác với chi phí tương đương và tiền không thể được chuyển “riêng” cho người khác; trong khi máy trộn tiền tệ chỉ yêu cầu người rút xuất trình chứng chỉ tiền gửi . .

Để làm cho các hành động gửi và rút tiền trông đồng nhất, số tiền được gửi theo địa chỉ gửi tiền của nhóm Tornado và số tiền được rút theo địa chỉ rút tiền luôn nhất quán, ví dụ: 100 người gửi tiền và 100 người rút tiền của một nhóm nhất định, mặc dù hiển thị công khai , chúng dường như không có mối liên hệ nào với nhau và số tiền mỗi người gửi và rút là như nhau. Vào thời điểm này, có thể khiến công chúng nhầm lẫn và không thể đánh giá mối tương quan dựa trên số tiền gửi và rút tiền, do đó cắt đứt dấu vết chuyển tiền. Rõ ràng, điều này mang lại sự thuận tiện tự nhiên cho hành vi kiếm tiền.

Nhưng có một câu hỏi quan trọng: Làm thế nào người rút tiền có thể chứng minh rằng họ đã gửi tiền khi rút tiền? Địa chỉ bắt đầu rút tiền từ máy trộn không liên quan đến bất kỳ địa chỉ gửi tiền nào, vậy làm cách nào để xác định trình độ rút tiền của anh ta? Có vẻ như phương pháp trực tiếp nhất là người rút tiền tiết lộ trực tiếp hồ sơ gửi tiền mà anh ta đã lập, nhưng điều này trực tiếp tiết lộ danh tính của anh ta. Đây là nơi mà bằng chứng không có kiến ​​thức trở nên hữu ích.

Người rút tiền có thể bắt đầu rút tiền thành công bằng cách phát hành Bằng chứng ZK để chứng minh rằng anh ta có hồ sơ gửi tiền trong hợp đồng Tornado và khoản tiền gửi chưa được rút. Bản thân bằng chứng không kiến ​​thức đã đạt được sự bảo vệ quyền riêng tư, thế giới bên ngoài chỉ biết rằng người rút tiền thực sự đã gửi tiền vào nhóm quỹ, nhưng họ không biết người gửi tiền đó tương ứng với ai.

Để chứng minh rằng "Tôi đã gửi tiền vào quỹ Tornado" có thể được chuyển đổi thành "Hồ sơ gửi tiền của tôi có thể được tìm thấy trong hợp đồng Tornado". Nếu Cn được sử dụng để biểu diễn bản ghi tiền gửi thì vấn đề có thể được tóm tắt như sau:

Được biết, bản ghi tiền gửi của Tornado được thiết lập là {C1, C2,...C100...}, người rút tiền Bob chứng minh rằng anh ta đã sử dụng chìa khóa trong tay để tạo ra một Cn nhất định trong bản ghi tiền gửi, nhưng ZK thì không. tiết lộ Cn là gì. .

Các thuộc tính đặc biệt của Merkle Proof được sử dụng ở đây. Bởi vì tất cả các bản ghi tiền gửi của Tornado được lưu trữ trong MerkleTree được xây dựng trên chuỗi dưới dạng nút lá thấp nhất của nó và tổng số lá là khoảng 2 lũy thừa 20 > 1 triệu, hầu hết chúng đều ở trạng thái trống (được đưa ra ban đầu giá trị). Bất cứ khi nào một khoản tiền gửi mới xảy ra, hợp đồng sẽ ghi giá trị đặc trưng tương ứng của nó là Cam kết vào một chiếc lá, sau đó cập nhật phần gốc của Cây Merkle.

Ví dụ: nếu hoạt động gửi tiền của Bob là hoạt động gửi tiền thứ 10.000 trong lịch sử của Tornado, thì giá trị đặc trưng Cn liên quan đến khoản tiền gửi này sẽ được ghi vào nút lá thứ 10.000 của Cây Merkle, nghĩa là C10000 = Cn. Sau đó hợp đồng sẽ tự động tính Root mới và cập nhật nó. (ps: Để tiết kiệm khối lượng tính toán, hợp đồng Tornado sẽ lưu trữ dữ liệu của lô nút đã thay đổi trước đó, chẳng hạn như Fs1, Fs2 và Fs0 trong hình bên dưới)

Bản thân MerkleProof rất đơn giản và nhẹ, nó tận dụng sự đơn giản của cấu trúc dữ liệu cây trong quá trình truy xuất/truy tìm nguồn. Nếu bạn muốn chứng minh bên ngoài rằng một TD giao dịch nào đó tồn tại trong MerkleTree, bạn chỉ cần đưa MerkleProof tương ứng với Root (phần bên phải trong hình bên dưới), khá đơn giản. Nếu Merkle Tree cực lớn và các lá phía dưới có lũy thừa từ 2 đến 20, nghĩa là nó chứa 1 triệu bản ghi tiền gửi thì Merkle Proof chỉ cần chứa giá trị của 21 nút, tức là rất ngắn.

Nếu bạn muốn chứng minh rằng một giao dịch H3 nhất định thực sự có trong Cây Merkle, hãy thử chứng minh rằng bằng cách sử dụng H3 và một phần dữ liệu khác trên Cây Merkle, Root có thể được tạo và một phần dữ liệu cần thiết để tạo Root (bao gồm Td) cấu thành Bằng chứng Merkle.

Khi Bob rút tiền, anh ta cần chứng minh rằng chứng chỉ mà anh ta sở hữu tương ứng với hàm băm tiền gửi Cn nhất định được ghi trên Cây Merkle. Nói cách khác, ông muốn chứng minh hai điều:

·Cn tồn tại trong Merkle Tree trong hợp đồng Tornado trên chuỗi. Cụ thể, Merkle Proof có thể được xây dựng, chứa Cn;

·Cn liên quan đến chứng chỉ tiền gửi trong tay Bob.

Giải thích chi tiết về logic kinh doanh của Tornado

Giải thích chi tiết về logic kinh doanh của Tornado

Nhiều chức năng đã được triển khai trước trong mã giao diện người dùng của giao diện người dùng Tornado. Khi người gửi tiền mở trang web TornadoCash và nhấp vào nút gửi tiền, chương trình được đính kèm với mã giao diện người dùng sẽ tạo ra hai số ngẫu nhiên K và r cục bộ , sau đó tính Cn=Hash Giá trị của (K, r) được chuyển vào hợp đồng Tornado và Cn (cam kết trong hình bên dưới) được chèn vào Cây Merkle được ghi lại bởi hợp đồng sau. Nói một cách thẳng thắn, K và r tương đương với khóa riêng. Chúng rất quan trọng và người dùng sẽ được nhắc lưu chúng đúng cách. K và r vẫn sẽ được sử dụng khi rút tiền sau này.

Điều đáng chú ý là tất cả công việc trên đều diễn ra ngoài chuỗi, nghĩa là: cả hợp đồng Tornado lẫn những người quan sát bên ngoài đều không biết K và r. Nếu K và r bị rò rỉ, nó tương tự như khóa riêng của ví bị đánh cắp.

Sau khi hợp đồng Tornado nhận tiền gửi của người dùng và nhận Cn=Hash(K, r) do người dùng gửi, nó sẽ chèn Cn vào lớp dưới cùng của cây Merkle dưới dạng nút lá mới và cập nhật giá trị của Root. Do đó, Cn có liên quan 1-1 với hành động gửi tiền của người dùng. Thế giới bên ngoài có thể biết mỗi Cn tương ứng với người dùng nào, ai đã gửi Token vào máy trộn và bản ghi tiền gửi tương ứng với từng người gửi tiền. Cn.

Ở bước rút tiền, người rút tiền nhập chứng chỉ/khóa riêng (số ngẫu nhiên K và r được tạo khi gửi tiền) vào trang web giao diện người dùng. Chương trình trong mã giao diện người dùng TornadoCash sẽ sử dụng K và r, Cn=Hash( K, r), Cn Bằng chứng Merkle tương ứng được sử dụng làm tham số đầu vào để tạo Bằng chứng ZK, chứng minh rằng Cn là một bản ghi tiền gửi nhất định tồn tại trên Cây Merkle và K và r là các chứng chỉ tương ứng với Cn.

Bước này tương đương với việc chứng minh: Tôi biết key tương ứng với bản ghi tiền gửi nào đó được ghi trên Merkle Tree. Khi ZK Proof được gửi đến hợp đồng Tornado, bốn thông số trên sẽ bị ẩn và thế giới bên ngoài không thể biết được (bao gồm cả hợp đồng Tornado), do đó đảm bảo quyền riêng tư.

Các tham số khác liên quan đến việc tạo ZKProof bao gồm: gốc của Merkle Tree trong hợp đồng Tornado khi rút tiền, địa chỉ thanh toán tùy chỉnh A và mã định danh nf để ngăn chặn các cuộc tấn công lặp lại (sẽ thảo luận sau). Ba thông số này sẽ được công bố công khai trên chuỗi và có thể được thế giới bên ngoài biết đến, nhưng quyền riêng tư sẽ không bị ảnh hưởng.

Có một chi tiết ở đây, đó là khi hoạt động gửi tiền tạo ra Cn, hai số ngẫu nhiên K và r được sử dụng để tạo Cn, thay vì một số ngẫu nhiên duy nhất. Điều này là do một số ngẫu nhiên duy nhất không đủ an toàn và có khả năng xảy ra xung đột nhất định, ví dụ: sử dụng một số ngẫu nhiên duy nhất có thể khiến hai người gửi tiền khác nhau sử dụng cùng một số ngẫu nhiên, khiến Cn được tạo ra va chạm.

Có một chi tiết ở đây, đó là khi hoạt động gửi tiền tạo ra Cn, hai số ngẫu nhiên K và r được sử dụng để tạo Cn, thay vì một số ngẫu nhiên duy nhất. Điều này là do một số ngẫu nhiên duy nhất không đủ an toàn và có khả năng xảy ra xung đột nhất định, ví dụ: sử dụng một số ngẫu nhiên duy nhất có thể khiến hai người gửi tiền khác nhau sử dụng cùng một số ngẫu nhiên, khiến Cn được tạo ra va chạm.

Còn chữ A trong hình trên là địa chỉ nhận tiền rút do người rút tiền điền vào. nf là mã định danh nhằm ngăn chặn các cuộc tấn công lặp lại, giá trị của nó nf = Hash(K), K là một trong hai số ngẫu nhiên (K và r) được sử dụng trong bước gửi Cn. Bằng cách này, nf được liên kết với Cn. Nói cách khác, mỗi Cn có một nf tương ứng và cả hai có liên quan với nhau từng cái một.

Tại sao ngăn chặn các cuộc tấn công lặp lại? Do đặc điểm thiết kế của máy trộn coin nên khi rút tiền không biết lá Cn nào của cây Merkle tương ứng với số coin người dùng rút ra và do đó không biết người gửi tiền có liên quan đến ai, hoặc có bao nhiêu người gửi tiền. khoản tiền gửi mà người rút tiền đã thực hiện. Người rút tiền có thể sử dụng tính năng này để rút tiền thường xuyên, khởi động các cuộc tấn công lặp lại và lấy mã thông báo từ nhóm trộn nhiều lần cho đến khi cạn hết quỹ.

Ở đây, vai trò của mã định danh nf tương tự như bộ đếm giao dịch nonce mà mỗi địa chỉ Ethereum có, được đặt để ngăn một giao dịch nhất định được thực hiện lại. Khi việc rút tiền xảy ra, người rút tiền cần gửi nf để kiểm tra xem nf đã được sử dụng chưa (được ghi lại): nếu vậy thì việc rút tiền không hợp lệ. Nếu không, có nghĩa là nf chưa được sử dụng, việc rút tiền hợp lệ và nf tương ứng sẽ được ghi lại. Lần tiếp theo khi ai đó gửi nf này, hành động rút tiền tương ứng sẽ được xác định trực tiếp là không hợp lệ.

Có ổn không nếu ai đó tạo ngẫu nhiên một nf chưa được ghi trong hợp đồng? Tất nhiên là không, bởi vì khi người rút tiền tạo ZK Proof, anh ta cần đảm bảo rằng nf = Hash (K) và số ngẫu nhiên K được liên kết với bản ghi tiền gửi Cn. Nghĩa là, nf được liên kết với một khoản tiền gửi được ghi lại nhất định Cn. Nếu bạn tạo một nf theo ý muốn và nf này không khớp với tất cả các khoản tiền gửi trong hồ sơ gửi tiền, Bằng chứng ZK hợp lệ sẽ không được tạo ra một cách suôn sẻ, công việc tiếp theo sẽ không được hoàn thành một cách suôn sẻ và hoạt động rút tiền sẽ không thành công.

Một số người cũng có thể hỏi: Có thể không có NF không? Vì người rút tiền cần gửi bằng chứng ZK khi rút tiền để chứng minh rằng anh ta có liên quan đến một Cn nhất định, nên việc kiểm tra xem Bằng chứng ZK tương ứng đã được gửi tới chuỗi mỗi lần rút tiền là chưa đủ hay sao?

Nhưng trên thực tế, chi phí cho việc này rất cao, vì hợp đồng tiền mặt Tornado sẽ không lưu trữ vĩnh viễn ZK Proof đã gửi trước đây, vì điều này sẽ gây lãng phí nghiêm trọng không gian lưu trữ. Thay vì so sánh xem mỗi ZKProof mới được gửi tới chuỗi có phù hợp với Bằng chứng hiện có hay không, việc thiết lập một mã định danh nf chiếm một diện tích nhỏ và lưu trữ nó vĩnh viễn sẽ hiệu quả hơn về mặt chi phí.

Theo ví dụ mã của chức năng rút tiền, các tham số bắt buộc và logic nghiệp vụ như sau:

Người dùng gửi ZKProof, nf (NullifierHash) = Hash (K) và tùy chỉnh người nhận địa chỉ để nhận tiền rút. ZKProof ẩn các giá trị của Cn, K và r, khiến thế giới bên ngoài không thể lấy được và xác định danh tính của người dùng. Regent thường sẽ điền một địa chỉ mới rõ ràng và sẽ không tiết lộ thông tin cá nhân.

Người dùng gửi ZKProof, nf (NullifierHash) = Hash (K) và tùy chỉnh người nhận địa chỉ để nhận tiền rút. ZKProof ẩn các giá trị của Cn, K và r, khiến thế giới bên ngoài không thể lấy được và xác định danh tính của người dùng. Regent thường sẽ điền một địa chỉ mới rõ ràng và sẽ không tiết lộ thông tin cá nhân.

Nhưng có một vấn đề nhỏ ở đây, đó là khi người dùng rút tiền, để tránh truy xuất nguồn gốc, họ thường sử dụng địa chỉ mới áp dụng để thực hiện giao dịch rút tiền, lúc này địa chỉ mới không có ETH để trả gas. phí. Vì vậy, khi địa chỉ rút tiền bắt đầu rút tiền thì phải khai báo rõ ràng một người chuyển tiếp sẽ trả phí gas, sau đó hợp đồng trộn sẽ trừ trực tiếp một phần số tiền rút của người dùng và chuyển lại cho người chuyển tiếp.

Tóm lại, TornadoCash có thể che giấu mối quan hệ giữa người rút tiền và người gửi tiền, khi có số lượng người dùng lớn, nó giống như một khu vực trung tâm thành phố, một khi tội phạm trà trộn vào đám đông, cảnh sát sẽ khó theo dõi. . ZK-SNARK được yêu cầu trong quá trình rút tiền. Phần nhân chứng ẩn chứa thông tin chính của người rút tiền, đây là điểm quan trọng nhất của toàn bộ máy trộn tiền xu. Như hiện tại, Tornado có thể là một trong những dự án lớp ứng dụng khéo léo nhất liên quan đến ZK.

Các bình luận

Tất cả bình luận

Recommended for you