bởi @mmjahanara , @pierre
Cảm ơn @b-wagn , @soispoke và @levs57 vì những cuộc thảo luận và bình luận hữu ích đã dẫn đến bài viết này.
Tóm tắt: Chúng tôi sẽ phân tích lý do tại sao thuộc tính khả năng phủ nhận hợp lý của wormhole dường như không tương thích với địa chỉ 160 bit của Ethereum. Ngoài ra, chúng tôi cũng làm sáng tỏ về tập hợp ẩn danh được tuyên bố của EIP-7503, vốn thấp hơn nhiều so với dự kiến trong thực tế. Mặc dù vấn đề thứ hai có thể giải quyết được, chúng tôi tin rằng vấn đề đầu tiên có thể cần phải xem xét lại toàn bộ thiết lập wormhole. Chúng tôi kết luận bài viết bằng một thiết kế tiếp theo tiềm năng, được mô tả ngắn gọn, sử dụng phương pháp gửi tiền vào chuỗi beacon.
Về các lỗ sâu
Các giải pháp bảo mật của Ethereum từ trước đến nay dựa vào các tập hợp ẩn danh dành riêng cho ứng dụng. Trong các giao thức như Tornado Cash , hành động gửi tiền là một tương tác rõ ràng với một hợp đồng thông minh cụ thể. Điều này tạo ra một lỗ hổng cơ bản: trong khi liên kết giữa người gửi tiền và người rút tiền bị phá vỡ, sự tham gia vào giao thức bảo mật lại công khai. Những thiết kế này cho phép những người quan sát chuỗi khối gắn nhãn và có khả năng kiểm duyệt tất cả những người gửi tiền vào tập hợp ẩn danh.
EIP-7503 (lỗ sâu không kiến thức) đề xuất một mô hình khác, dựa trên khả năng phủ nhận hợp lý.
Cơ chế rất đơn giản: người dùng "đốt" tiền bằng cách gửi chúng đến một địa chỉ không thể chi tiêu được xác định bằng mật mã. Sau đó, họ cung cấp bằng chứng không tiết lộ thông tin (NIZK) (không tương tác) chứng minh rằng họ biết ảnh ngược của địa chỉ đó để tạo lại tiền vào một tài khoản mới. Điều quan trọng là, thao tác "gửi tiền" (hoặc "đốt") không thể phân biệt được với một giao dịch chuyển ETH thông thường đến một địa chỉ mới.
Tuy nhiên, chúng tôi tin rằng có thể có một sự đánh đổi cơ bản giữa khả năng phủ nhận hợp lý và bảo mật, điều này có thể cản trở việc thiết lập các lỗ hổng không gian trong L1 hiện nay. Ngoài ra, chúng tôi cũng nêu ra một vấn đề liên quan đến tập hợp ẩn danh hiệu quả của EIP-7503, có thể thấp hơn dự kiến.
Ký hiệu và các giả định
Chúng ta sẽ sử dụng:
- \mathsf{H}(\cdot) H ( ⋅ ) cho một hàm băm 256 bit chung (ví dụ: SHA3, SHA-256, …).
- \operatorname{trunc__{160}(x) trunc 160 ( x ) để cắt bớt giá trị 256 bit x x thành địa chỉ Ethereum 160 bit.
- Các hàm băm phân tách theo miền được định nghĩa là \mathsf{H}(\text{“TAG”} \parallel \cdots) H ( “TAG” ∥ ⋯ ) , trong đó \text{“TAG”} “TAG” là tiền tố ASCII cố định (ví dụ: \text{“worm”} “worm” , \text{“null”} “null” ).
EIP-7503
Trong đặc tả EIP-7503 gốc, địa chỉ ghi được tạo ra từ một bí mật duy nhất s s :
Bước đầu tiên, người dùng đốt tiền bằng cách chọn ngẫu nhiên một chuỗi s và gửi chúng đến Addr_{burn}(s) A d d r b u r n ( s ) . Sau đó, người dùng có thể tạo tiền bằng cách cung cấp cho hợp đồng thông minh một bộ khử trùng \nu = \mathsf{H}(\text{“null”} \parallel s) ν = H ( “null” ∥ s ) và bằng chứng NIZK chứng minh rằng \nu ν phù hợp với một số giao dịch hiện có A\to B A → B (tức là sử dụng s s st B = Addr_{burn}(s) B = A d d r b u r n ( s ) ). Hợp đồng sẽ xác minh bằng chứng và kiểm tra xem \nu ν đã được gửi trước đó hay chưa. Nếu các kiểm tra này thành công, tiền sẽ được tạo.
Các đặc tính bảo mật của cơ chế đốt tiền giả như vậy không được nêu rõ ràng, vì vậy chúng ta hãy định nghĩa chúng một cách không chính thức.
Tính chính xác / Tính đầy đủ
Nếu người dùng hành xử trung thực, họ có thể tạo ra tiền sau khi đốt.
Sự riêng tư
- Không thể liên kết
Theo trực giác, quyền riêng tư ở đây có nghĩa là không ai (ngoại trừ chính người dùng) có thể liên kết giao dịch đốt với quá trình tạo token, tức là giao dịch tạo token được gửi đến hợp đồng tạo token. Nói chính xác hơn, chúng ta xem xét người dùng là trung thực trong trường hợp này, và muốn rằng không một người quan sát nào trên chuỗi khối có thể biết được giao dịch nào là giao dịch đốt tương ứng với giao dịch tạo token.
- Khả năng phủ nhận hợp lý
Thuộc tính bảo mật thứ hai mà chúng ta mong muốn là giao dịch đốt phải trông giống như một giao dịch “thông thường”. Cụ thể, địa chỉ đốt B B phải trông giống như một địa chỉ ngẫu nhiên. Khả năng phủ nhận hợp lý là điều tốt và là một trong những điểm khác biệt chính với các giao thức như tornadocash yêu cầu tương tác hợp đồng rõ ràng. Với wormhole, việc tham gia vào giao thức đốt vẫn được giữ kín - lưu ý rằng việc rút tiền vẫn công khai.
Không lạm phát
Ý tưởng ở đây là chúng ta không muốn ETH được tạo ra từ hư không và có nghĩa là người ta chỉ có thể tạo ra ETH nếu đã đốt trước đó: ánh xạ từ bất kỳ giao dịch tạo ETH thành công nào đến giao dịch đốt ETH phải là đơn ánh. Thoạt nhìn, điều này có nghĩa là ngăn chặn kẻ thù tạo ra hai mã vô hiệu khác nhau cho cùng một giao dịch đốt ETH. Thật vậy, nếu kẻ thù có thể tạo ra hai mã vô hiệu khác nhau như vậy cho cùng một giao dịch đốt ETH, chúng ta sẽ gặp phải lỗi lạm phát.
Vì \mathsf{H}(\cdot) H ( ⋅ ) đang ẩn, chẳng phải điều đó sẽ rất đơn giản sao? Tuy nhiên, như nhóm Scroll đã nhận thấy ngay từ đầu, đây là lúc mọi chuyện trở nên khó khăn.
Nghịch lý ngày sinh nhật
Nghịch lý sinh nhật ngụ ý rằng việc tìm ra hai bí mật bất kỳ s_1, s_2 sao cho các địa chỉ 160 bit trùng nhau là điều không thể.
Việc này đòi hỏi khoảng 2^{80} 2 80 phép toán. Mặc dù số lượng này khá lớn, nhưng nó vẫn nằm trong tầm với của các quốc gia hoặc các nhóm khai thác khổng lồ. Khi kẻ tấn công tìm thấy một xung đột như vậy, giao thức sẽ bị phá vỡ:
- Nạp 100 ETH vào địa chỉ xung đột một lần duy nhất .
- Đúc với bộ khử \nu_1=\mathsf{H}(\text{"null"} \parallel s_1) ν 1 = H ( "null" ∥ s 1 ) và \nu_2=\mathsf{H}(\text{"null"} \parallel s_2) ν 2 = H ( "null" ∥ s 2 ) . Đây là hai bộ khử khác nhau , do đó 100 ETH được đúc hai lần .
- Rút 200 ETH.
Vì trình xác minh chỉ kiểm tra xem mỗi mã hủy được sử dụng một lần, nên nó không thể biết rằng hai lần rút tiền này được hỗ trợ bởi cùng một khoản tiền gửi trên chuỗi. Đây là một lỗi lạm phát vô hạn: xung đột địa chỉ 160 bit tại giới hạn sinh nhật 2^{80} 2 80 sẽ trực tiếp dẫn đến việc tạo ra tiền giả gấp đôi.
Tuy nhiên, cần lưu ý rằng một chuỗi có không gian địa chỉ lớn hơn sẽ không phải đối mặt với nhược điểm bảo mật này: tính bảo mật của hệ thống sẽ được đảm bảo với địa chỉ 320 bit đầy đủ. Việc cắt bớt 160 bit của Ethereum là một tối ưu hóa mà về lý thuyết, nó có thể loại bỏ.
Giải pháp tạm thời: loại bỏ tìm kiếm xung đột và làm cho hệ thống khó bị phá vỡ hơn bằng cách sử dụng dlog thay thế?
Chúng tôi xin đề xuất một ý tưởng: liệu chúng ta có thể giải quyết nghịch lý sinh nhật và thay vì yêu cầu kẻ tấn công tìm ra các xung đột, hãy yêu cầu hắn phá vỡ dlog?
Giả sử chúng ta làm việc với NIZK sau trên câu lệnh (\mathcal{R}_{root}, \nu) ( R r o o t , ν ) và chứng cứ (sk,s_{worm},tx = (A,B,pk),\text{salt},\pi_{merkle}) ( s k , s w o r m , t x = ( A , B , p k ) , salt , π m e r k l e ) theo các ràng buộc sau:
(1) \pi_{merkle} π m e r k l e xác thực tx t x trong \mathcal{R}_{root} R r o o t ;
(2) pk == \mathsf{SkToPk}(sk) p k = = S k T o P k ( s k ) , tức là, pk = sk \cdot G p k = s k ⋅ G đối với các khóa ECDSA;
(4) B == \operatorname{trunc__{160}\!\big(\mathsf{H}(\text{"worm"} \parallel sk \parallel \text{salt})\big) B = = trunc 160 ( H ( "worm" ∥ s k ∥ salt ) ) ;
(5) \nu == \mathsf{H}(\text{"null"} \parallel sk \parallel tx). ν = = H ( "null" ∥ s k ∥ t x ) .
Tính năng đó khá hay: người dùng thậm chí có thể tái sử dụng địa chỉ đốt của mình khi sử dụng cùng một giá trị salt cho hai giao dịch đốt khác nhau!
Lý lẽ về bảo mật cũng khá đơn giản: việc tạo tiền giả kép hiện nay đòi hỏi phải phá vỡ NIZK, ECDSA, hoặc hàm băm được sử dụng cho \nu ν , thay vì khai thác xung đột địa chỉ có chi phí 2^{80} 2 80. Thật vậy, đối với một giao dịch đốt tiền cố định (và do đó A, pk, B cố định ) , chỉ có một sk s k hợp lệ, nếu không bạn sẽ có thể tìm thấy hai khóa bí mật khác nhau ánh xạ tới cùng một khóa công khai đã khởi tạo giao dịch. Do đó, tất cả các nhân chứng xung đột đều ánh xạ tới cùng một bộ vô hiệu hóa.
Đây có phải là giải pháp không?
Thực ra không hẳn vậy, vì ngăn chặn xung đột giữa các bộ khử trùng không phải là vấn đề duy nhất!
Lỗ sâu cũng nên ngăn chặn việc sử dụng địa chỉ đốt để chi tiêu. Như đã được lưu ý trong EIP-7503 ban đầu, kẻ tấn công có thể tìm thấy một cặp bí mật (s_1, s_2) ( s 1 , s 2 ) sao cho create2_address(..., s1) == sha256("wormhole" || s2) . Trong thiết lập đó, kẻ tấn công có thể đốt tiền vào sha256("wormhole" || s2) và sau đó rút chúng từ create2_address(..., s1) . Mặc dù điều đó có nghĩa là kẻ tấn công có thể rút ether của họ hai lần (chỉ một lần), nhưng điều đó vẫn nên được coi là thất bại.
Nhưng liệu chúng ta có thực sự lo ngại khi đã cập nhật mạch ở trên? Vì thiết kế của chúng ta yêu cầu kẻ tấn công phải phá vỡ dlog, liệu chúng ta có thể đơn giản yêu cầu EXTCODESIZE không được 0 khi đốt tiền không? Điều đó sẽ ngăn kẻ tấn công rút tiền đã đốt vào create2_address(..., s1) .
Vấn đề là, ngay từ đầu, việc cho rằng sơ đồ trên yêu cầu kẻ thù phải phá vỡ dlog là một sai lầm. Trên thực tế, trò chơi để kẻ tấn công kiểm soát địa chỉ ghi vẫn gần như giống với trò chơi liên quan đến mã lệnh CREATE2 , bất kể bằng chứng về kiến thức về khóa riêng tư.
Trong thiết lập của chúng tôi, để một địa chỉ đốt có thể được sử dụng, trò chơi diễn ra như sau: nếu kẻ tấn công có thể tìm thấy hai bí mật (s_1, s_2) ( s 1 , s 2 ) sao cho trunc160(H(\text{“worm”} || s_1)) == trunc160(H(skToPk(s_2))) t r u n c 160 ( H ( “worm” | | s 1 ) ) = = t r u n c 160 ( H ( s k T o P k ( s 2 ) ) ) , hắn thắng. Thật vậy, khi điều đó xảy ra, kẻ tấn công sẽ có được một địa chỉ đốt có thể chi tiêu được, vì việc tìm thấy một cặp như vậy cho phép kẻ tấn công khởi tạo một giao dịch từ trunc160(H(skToPk(s_1))) trunc160 ( H ( skToPk ( s1 ) ) ) ) tới trunc160 ( H ( \ text { “ worm ”} || s1)) trunc160 ( H ( “ worm ” || s1 ) ) , một địa chỉ được kiểm soát bởi s_2 s2 !
Chúng ta lại quay về điểm xuất phát: đây vẫn là bài toán tìm kiếm va chạm nhưng chỉ có độ phức tạp là 80 bit.
Các lỗ sâu vũ trụ hiện nay, dù có vẻ khó tin, vẫn cần phải hoạt động với khả năng chống va chạm.
Bỏ qua các phương pháp phát hiện dựa trên kinh nghiệm, yêu cầu về khả năng phủ nhận hợp lý của các lỗ sâu (wormhole) hàm ý rằng không ai quan sát lớp L1 có thể phân biệt được các giao dịch lỗ sâu với các giao dịch thông thường. Thuộc tính này đương nhiên yêu cầu việc tính toán địa chỉ ghi phải được giữ bí mật đối với người dùng khởi tạo thao tác ghi. Nhưng, do trò chơi chống va chạm (collision resistance game), không có cách nào để người dùng chứng minh với mức độ bảo mật cao hơn 80 bit rằng bí mật mà họ sử dụng để tạo ra địa chỉ ghi 160 bit riêng tư không kiểm soát chính nó.
Một giải pháp có thể là đưa địa chỉ đốt tiền vào chính giao thức (ví dụ: gửi tiền đến trunc160(H(\text{“worm”})) t r u n c 160 ( H ( “worm” ) ) ) , biến vấn đề thành một nhiệm vụ tìm kiếm tiền ảnh. Nhưng thiết lập đó sẽ khiến chúng ta mất đi thuộc tính khả năng phủ nhận hợp lý mà chúng ta đang tìm kiếm. Cuối cùng, chúng ta bị mắc kẹt trong việc phải lựa chọn giữa một thiết kế bảo mật yếu nhưng có thể phủ nhận hợp lý và một thiết kế khác gần như tương đương với các thiết lập kiểu tornado-cash.
Chúng tôi liệt kê ở đây ba câu hỏi mà chúng tôi cho là có giá trị trong việc cải thiện tình trạng của các lỗ sâu vũ trụ:
- Liệu có những nguyên thủy nào khác mà chúng ta có thể tận dụng để tạo ra những lỗ sâu không gian có thể phủ nhận được trong L1 không? Chúng tôi nghĩ câu trả lời là có và đang bắt đầu nghiên cứu tiếp theo về việc tận dụng các mỏ tín hiệu. Chúng tôi sẽ mô tả ngắn gọn ý tưởng này trong phần bổ sung bên dưới.
- Liệu có cách nào để tạo ra các lỗ sâu từ bài toán tìm kiếm ảnh trước với khả năng phủ nhận hợp lý không? Chúng tôi không chắc chắn về điều này, dường như khá khó để làm việc với một địa chỉ ghi xác định nhưng riêng tư.
- Liệu có những thay đổi L1 nào dễ thực hiện để chúng ta có thể trả lời tích cực một trong hai câu hỏi trên không?
Các tiện ích bổ sung
Bộ ẩn danh hiệu quả EIP-7503
Có một vấn đề thực tế mà chúng tôi không chắc đã được thảo luận kỹ lưỡng. Vì nghi ngờ, chúng tôi viết điều này ở đây để làm rõ.
EIP-7503 công khai beacon_block_root như một đầu vào cho bằng chứng tạo khối. Nhưng quyết định này thu hẹp tập hợp ẩn danh được tuyên bố ( tất cả các tài khoản Ethereum không có giao dịch gửi đi ) xuống chỉ còn các giao dịch đã xảy ra trong khối đó, vì giao dịch đốt tương ứng phải nằm trong khối được tham chiếu. Nếu các giao thức wormhole quyết định sử dụng các gốc biên nhận giao dịch làm đầu vào cho bằng chứng tạo khối của người dùng, việc duy trì một tập hợp ẩn danh đủ lớn sẽ yêu cầu quyền truy cập vào một bộ tích lũy cung cấp khả năng lấy các đường dẫn xác thực đến tất cả các giao dịch trước đó.
Mặc dù về lý thuyết điều này có thể hoạt động, vì mỗi hàm băm gốc khối là một cam kết cho tất cả các giao dịch trước khối đó, nhưng bằng chứng này sẽ yêu cầu một thuật toán đệ quy phía máy khách hiệu quả hoặc một thiết lập L1 cụ thể - chẳng hạn như thay thế keccak bằng một hàm băm thân thiện với phép toán số học hoặc mở rộng tiêu đề khối với một trường cam kết với một gốc khối được mã hóa chứa tất cả các hàm băm của các khối trước đó.
Công việc tiếp theo: Lỗ sâu gặp các mỏ quặng tín hiệu
Hợp đồng gửi tiền beacon là cầu nối một chiều từ lớp thực thi đến chuỗi beacon. Như hiện tại, mỗi trình xác thực đều có thể được liên kết công khai với đích gửi và rút tiền của nó: hợp đồng cung cấp một chức năng deposit duy nhất chấp nhận khoản tiền gửi cùng với khóa pubkey của trình xác thực và thông tin xác thực rút tiền ( withdrawal_credentials ).
Có thể có cách thiết kế một phiên bản riêng tư của hợp đồng, thay thế pubkey và withdrawal_credentials bằng một cam kết ẩn danh tương ứng. Sau đó, tiền gửi sẽ được nhận trên chuỗi beacon bằng cách cung cấp bằng chứng kiến thức zk. Trong cấu trúc này, trình xác thực chỉ được thêm vào hàng đợi kích hoạt sau khi tiền gửi đã được nhận trên chuỗi beacon. Lưu ý rằng tiền gửi chưa được nhận vẫn có thể được thêm vào hàng đợi rút tiền giống như bất kỳ trình xác thực thông thường nào.
Điều này sẽ đòi hỏi một số thay đổi về cấu trúc giao thức, nhưng nó có thể cải thiện đáng kể quyền riêng tư của người xác thực đồng thời hoạt động như một cơ chế giống như "lỗ sâu" trong giao thức với khả năng phủ nhận hợp lý. Hơn nữa, với khoảng một phần ba ETH được đặt cọc và hàng chục triệu đô la được rút ra mỗi ngày (hoặc hơn), tập hợp ẩn danh thu được có thể rất lớn.
