Vitalik Buterin thông qua Blog Vitalik Buterin
Đây là sự phản ánh của bài viết tại https://medium.com/@VitalikButerin/chương trình số học bậc hai-từ-zero-to-hero-f6d558cea649
Gần đây có rất nhiều sự quan tâm đến công nghệ đằng sau zk-SNARK và mọi người ngày càng quan tâm nhiều hơn đến đang cố gắng làm sáng tỏ thứ mà nhiều người gọi là “toán học mặt trăng” do tính phức tạp không thể giải mã được của nó. zk-SNARK thực sự khá khó nắm bắt, đặc biệt là do số lượng lớn các bộ phận chuyển động cần kết hợp với nhau để toàn bộ hoạt động, nhưng nếu chúng ta chia công nghệ ra từng phần một thì việc hiểu nó sẽ trở nên đơn giản hơn.
Mục đích của bài đăng này không nhằm mục đích giới thiệu đầy đủ về zk-SNARK; nó giả định kiến thức nền tảng rằng (i) bạn biết zk-SNARK là gì và chúng làm gì, đồng thời (ii) biết đủ toán để có thể suy luận về những thứ như đa thức (nếu câu lệnh �(�)+�(�) =(�+�)(�) , trong đó � và � là đa thức, có vẻ tự nhiên và hiển nhiên đối với bạn, thì bạn đã ở đúng cấp độ). Thay vào đó, bài đăng đào sâu hơn vào bộ máy đằng sau công nghệ và cố gắng giải thích rõ ràng nhất có thể về nửa đầu của quy trình, như nhà nghiên cứu zk-SNARK Eran Tromer đã vẽ ở đây:
Các bước ở đây có thể được chia thành hai nửa. Đầu tiên, zk-SNARK không thể được áp dụng trực tiếp cho bất kỳ vấn đề tính toán nào; đúng hơn, bạn phải chuyển vấn đề sang “dạng” phù hợp để giải quyết vấn đề. Biểu mẫu này được gọi là “chương trình số học bậc hai” (QAP) và việc chuyển đổi mã của một hàm thành một trong các mã này bản thân nó là điều hết sức không cần thiết. Cùng với quy trình chuyển đổi mã của hàm thành QAP là một quy trình khác có thể được chạy song song để nếu bạn có đầu vào cho mã, bạn có thể tạo giải pháp tương ứng (đôi khi được gọi là “làm chứng” cho QAP). Sau đó, có một quy trình khá phức tạp khác để tạo ra “bằng chứng không có kiến thức” thực tế cho nhân chứng này và một quy trình riêng để xác minh bằng chứng mà người khác đã chuyển cho bạn, nhưng đây là những chi tiết nằm ngoài phạm vi của bài đăng này. .
Ví dụ mà chúng ta sẽ chọn là một ví dụ đơn giản: chứng minh rằng bạn biết nghiệm của phương trình bậc ba: �3+�+5=35 (gợi ý: đáp án là 3). Vấn đề này đủ đơn giản để QAP thu được sẽ không lớn đến mức đáng sợ, nhưng đủ nhỏ để bạn có thể thấy tất cả các máy móc đều hoạt động.
Hãy để chúng tôi viết ra chức năng của chúng tôi như sau:
def qeval(x):
y = x**3
return x + y + 5
Ngôn ngữ lập trình có mục đích đặc biệt đơn giản mà chúng tôi đang sử dụng ở đây hỗ trợ số học cơ bản (+, −, ⋅, /), lũy thừa lũy thừa không đổi (�7 chứ không phải ��) và phép gán biến, đủ mạnh để về mặt lý thuyết bạn có thể làm được bất kỳ tính toán nào bên trong nó (miễn là số bước tính toán bị giới hạn; không cho phép vòng lặp). Lưu ý rằng các toán tử modulo (%) và toán tử so sánh (<, >, ≤, ≥) KHÔNG được hỗ trợ, vì không có cách nào hiệu quả để thực hiện modulo hoặc so sánh trực tiếp trong số học nhóm tuần hoàn hữu hạn (hãy biết ơn vì điều này; nếu có một cách để thực hiện một trong hai, thì mật mã đường cong elip sẽ bị phá vỡ nhanh hơn bạn có thể nói “tìm kiếm nhị phân” và “định lý số dư Trung Hoa”).
Bạn có thể mở rộng ngôn ngữ sang modulo và so sánh bằng cách cung cấp các phân tách bit (ví dụ: 13=23+22+1) làm đầu vào phụ, chứng minh tính đúng đắn của các phân tách đó và thực hiện phép toán trong mạch nhị phân; trong số học trường hữu hạn, việc thực hiện kiểm tra đẳng thức (==) cũng có thể thực hiện được và trên thực tế còn dễ dàng hơn một chút, nhưng đây đều là những chi tiết mà chúng ta sẽ không đề cập ngay bây giờ. Chúng ta có thể mở rộng ngôn ngữ để hỗ trợ các điều kiện (ví dụ: if �<5:�=7; else: �=9) bằng cách chuyển đổi chúng sang dạng số học: �=7⋅(�<5)+9⋅(� ≥5 ) tuy nhiên hãy lưu ý rằng cả hai “đường dẫn” của điều kiện sẽ cần phải được thực thi và nếu bạn có nhiều điều kiện lồng nhau thì điều này có thể dẫn đến một lượng lớn chi phí.
Bây giờ chúng ta hãy đi qua quá trình này từng bước một. Nếu bạn muốn tự mình làm điều này với bất kỳ đoạn mã nào, tôi đã triển khai trình biên dịch tại đây (chỉ dành cho mục đích giáo dục; chưa sẵn sàng để tạo QAP cho zk-SNARK trong thế giới thực!).
Làm phẳng
Bước đầu tiên là quy trình “làm phẳng”, trong đó chúng tôi chuyển đổi mã gốc, có thể chứa các câu lệnh và biểu thức phức tạp tùy ý, thành một chuỗi các câu lệnh có hai dạng: �=� (trong đó � có thể là một biến hoặc một số ) và �=� (��) � (trong đó �� có thể là +, −, ⋅, / và � và � có thể là biến, số hoặc chính chúng là biểu thức con). Bạn có thể coi mỗi câu lệnh này giống như các cổng logic trong một mạch điện. Kết quả của quá trình làm phẳng cho đoạn mã trên như sau:
sym_1 = x * x
y = sym_1 * x
sym_2 = y + x
~out = sym_2 + 5
Nếu bạn đọc mã gốc và mã ở đây, bạn có thể dễ dàng thấy rằng cả hai đều tương đương nhau.
Cổng vào R1CS
Bây giờ, chúng tôi chuyển đổi hệ thống này thành một thứ gọi là hệ thống ràng buộc cấp 1 (R1CS). R1CS là một chuỗi gồm các nhóm gồm ba vectơ (�, �, �) và nghiệm của R1CS là vectơ �, trong đó � phải thỏa mãn phương trình �.�⋅�.�−�.�=0, trong đó . đại diện cho tích số chấm – nói một cách đơn giản hơn, nếu chúng ta “kết hợp” � và �, nhân hai giá trị ở cùng một vị trí, rồi lấy tổng của các tích này, sau đó thực hiện tương tự với � và � rồi � và � , thì kết quả thứ ba bằng tích của hai kết quả đầu tiên. Ví dụ: đây là một R1CS hài lòng:
Đầu tiên, chúng tôi sẽ cung cấp ánh xạ biến mà chúng tôi sẽ sử dụng:
'~one', 'x', '~out', 'sym_1', 'y', 'sym_2'
Vectơ giải pháp sẽ bao gồm các phép gán cho tất cả các biến này theo thứ tự đó.
Bây giờ, chúng ta sẽ đưa ra bộ ba (�,�,�) cho cổng đầu tiên:
a = [0, 1, 0, 0, 0, 0]
b = [0, 1, 0, 0, 0, 0]
c = [0, 0, 0, 1, 0, 0]
Bạn có thể thấy rằng nếu vectơ nghiệm chứa 3 ở vị trí thứ hai và 9 ở vị trí thứ tư thì bất kể nội dung còn lại của vectơ nghiệm là gì, việc kiểm tra tích số chấm sẽ rút gọn thành 3⋅3=9, và thế là nó sẽ qua. Nếu vectơ nghiệm có −3 ở vị trí thứ hai và 9 ở vị trí thứ tư thì phép kiểm tra cũng sẽ đạt; trên thực tế, nếu vectơ giải pháp có 7 ở vị trí thứ hai và 49 ở vị trí thứ tư thì kiểm tra đó sẽ vẫn đạt - mục đích của kiểm tra đầu tiên này là để xác minh tính nhất quán của đầu vào và đầu ra của cổng đầu tiên.
Bây giờ chúng ta sang cổng thứ hai:
a = [0, 0, 0, 1, 0, 0]
b = [0, 1, 0, 0, 0, 0]
c = [0, 0, 0, 0, 1, 0]
Theo cách tương tự như kiểm tra tích số chấm đầu tiên, ở đây chúng ta đang kiểm tra ���1⋅�=�.
Bây giờ là cổng thứ ba:
a = [0, 1, 0, 0, 1, 0]
b = [1, 0, 0, 0, 0, 0]
c = [0, 0, 0, 0, 0, 1]
Ở đây, mẫu hơi khác một chút: đó là nhân phần tử đầu tiên trong vectơ nghiệm với phần tử thứ hai, sau đó với phần tử thứ năm, cộng hai kết quả và kiểm tra xem tổng có bằng phần tử thứ sáu hay không. Vì phần tử đầu tiên trong vectơ nghiệm luôn là một nên đây chỉ là phép kiểm tra phép cộng, kiểm tra xem đầu ra có bằng tổng của hai đầu vào hay không.
Cuối cùng là cổng thứ tư:
a = [5, 0, 0, 0, 0, 1]
b = [1, 0, 0, 0, 0, 0]
c = [0, 0, 1, 0, 0, 0]
Ở đây, chúng ta đang đánh giá lần kiểm tra cuối cùng, ~out =���2+5. Kiểm tra tích số chấm hoạt động bằng cách lấy phần tử thứ sáu trong vectơ nghiệm, cộng năm lần phần tử đầu tiên (nhắc nhở: phần tử đầu tiên là 1, vì vậy điều này thực chất có nghĩa là thêm 5) và kiểm tra nó với phần tử thứ ba, đó là nơi chúng ta lưu trữ biến đầu ra.
Và ở đó chúng ta có R1CS với bốn ràng buộc. Nhân chứng chỉ đơn giản là sự gán cho tất cả các biến, bao gồm các biến đầu vào, đầu ra và nội bộ:
[1, 3, 35, 9, 27, 30]
Bạn có thể tự mình tính toán điều này bằng cách đơn giản là “thực thi” đoạn mã đã được làm phẳng ở trên, bắt đầu bằng phép gán biến đầu vào �=3 và nhập giá trị của tất cả các biến trung gian và đầu ra khi bạn tính toán chúng.
R1CS hoàn chỉnh được ghép lại với nhau là:
A
[0, 1, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0]
[0, 1, 0, 0, 1, 0]
[5, 0, 0, 0, 0, 1]
B
[0, 1, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 0]
C
[0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 1]
[0, 0, 1, 0, 0, 0]
R1CS sang QAP
Bước tiếp theo là lấy R1CS này và chuyển đổi nó thành dạng QAP, thực hiện logic tương tự ngoại trừ việc sử dụng đa thức thay vì tích số chấm. Chúng tôi làm điều này như sau. Chúng ta đi từ bốn nhóm ba vectơ có độ dài từ sáu đến sáu nhóm đa thức ba bậc 3, trong đó việc đánh giá các đa thức ở mỗi nhóm tọa độ x đại diện cho một trong những hạn chế. Nghĩa là, nếu chúng ta định giá các đa thức ở �=1, thì chúng ta sẽ có được tập vectơ đầu tiên, nếu chúng ta định giá các đa thức ở �=2, thì chúng ta sẽ có được tập vectơ thứ hai, v.v.
Chúng ta có thể thực hiện sự chuyển đổi này bằng cách sử dụng một thứ gọi là Nội suy Lagrange. Vấn đề mà phép nội suy Lagrange giải quyết là: nếu bạn có một tập hợp các điểm (tức là các cặp tọa độ (�,�)), thì việc thực hiện phép nội suy Lagrange trên các điểm đó sẽ cho bạn một đa thức đi qua tất cả các điểm đó. Chúng ta thực hiện điều này bằng cách giải bài toán: với mỗi tọa độ �, chúng ta tạo một đa thức có tọa độ � mong muốn tại tọa độ � đó và tọa độ � bằng 0 ở tất cả các tọa độ � khác mà chúng ta quan tâm, và sau đó thu được kết quả cuối cùng kết quả là chúng ta cộng tất cả các đa thức lại với nhau.
Hãy làm một ví dụ. Giả sử chúng ta muốn một đa thức đi qua (1,3),(2,2) và (3,4). Chúng ta bắt đầu bằng cách tạo một đa thức đi qua (1,3),(2,0) và (3,0). Hóa ra, việc tạo ra một đa thức “nhô ra” tại �=1 và bằng XNUMX tại các điểm quan tâm khác là điều dễ dàng; chúng tôi chỉ đơn giản làm:
(x - 2) * (x - 3)
Trông như thế này:
(x - 2) * (x - 3) * 3 / ((1 - 2) * (1 - 3))
Điều này cho chúng ta:
1.5 * x**2 - 7.5 * x + 9
1.5 * x**2 - 5.5 * x + 7
Bây giờ, hãy sử dụng phép nội suy Lagrange để biến đổi R1CS của chúng ta. Những gì chúng ta sắp làm là lấy giá trị đầu tiên ra khỏi mỗi vectơ �, sử dụng phép nội suy Lagrange để tạo ra đa thức từ giá trị đó (trong đó việc đánh giá đa thức tại � sẽ mang lại cho bạn giá trị đầu tiên của vectơ �th �), lặp lại quy trình đối với giá trị đầu tiên của mọi vectơ � và �, sau đó lặp lại quá trình đó cho các giá trị thứ hai, giá trị thứ ba, v.v. Để thuận tiện, tôi sẽ cung cấp câu trả lời ngay bây giờ:
A polynomials
[-5.0, 9.166, -5.0, 0.833]
[8.0, -11.333, 5.0, -0.666]
[0.0, 0.0, 0.0, 0.0]
[-6.0, 9.5, -4.0, 0.5]
[4.0, -7.0, 3.5, -0.5]
[-1.0, 1.833, -1.0, 0.166]
B polynomials
[3.0, -5.166, 2.5, -0.333]
[-2.0, 5.166, -2.5, 0.333]
[0.0, 0.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 0.0]
C polynomials
[0.0, 0.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 0.0]
[-1.0, 1.833, -1.0, 0.166]
[4.0, -4.333, 1.5, -0.166]
[-6.0, 9.5, -4.0, 0.5]
[4.0, -7.0, 3.5, -0.5]
Các hệ số được sắp xếp tăng dần nên đa thức đầu tiên ở trên thực tế là 0.833⋅�3—5⋅�2+9.166⋅�−5. Tập hợp đa thức này (cộng với đa thức Z mà tôi sẽ giải thích sau) tạo nên các tham số cho phiên bản QAP cụ thể này. Lưu ý rằng tất cả công việc cho đến thời điểm này chỉ cần được thực hiện một lần cho mọi chức năng mà bạn đang cố gắng sử dụng zk-SNARK để xác minh; khi các tham số QAP được tạo, chúng có thể được sử dụng lại.
Hãy thử đánh giá tất cả các đa thức này tại �=1. Việc tính một đa thức tại �=1 đơn giản có nghĩa là cộng tất cả các hệ số (là 1�=1 với mọi �), nên không khó. Chúng tôi nhận được:
A results at x=1
0
1
0
0
0
0
B results at x=1
0
1
0
0
0
0
C results at x=1
0
0
0
1
0
0
Và kìa, những gì chúng ta có ở đây giống hệt như bộ ba vectơ cho cổng logic đầu tiên mà chúng ta đã tạo ở trên.
Kiểm tra QAP
Bây giờ mục đích của sự biến đổi điên rồ này là gì? Câu trả lời là thay vì kiểm tra các ràng buộc trong R1CS riêng lẻ, giờ đây chúng ta có thể kiểm tra tất cả các ràng buộc cùng một lúc bằng cách thực hiện kiểm tra sản phẩm chấm về đa thức.
Lưu ý rằng bản thân đa thức thu được không nhất thiết phải bằng 0 và trên thực tế, trong hầu hết các trường hợp sẽ không bằng 0; nó có thể có bất kỳ hành vi nào tại các điểm không tương ứng với bất kỳ cổng logic nào, miễn là kết quả bằng 0 tại tất cả các điểm do tương ứng với một cổng nào đó. Để kiểm tra tính đúng đắn, chúng ta thực sự không đánh giá đa thức �=�.�⋅�.�−�.� tại mọi điểm tương ứng với một cổng; thay vào đó, chúng ta chia � cho một đa thức khác, �, và kiểm tra xem � có chia đều � – nghĩa là phép chia �/� không để lại số dư.
� được định nghĩa là (�−1)⋅(�−2)⋅(�−3)… – đa thức đơn giản nhất bằng XNUMX tại tất cả các điểm tương ứng với cổng logic. Đó là một thực tế cơ bản của đại số bất kì đa thức bằng 0 tại tất cả các điểm này phải là bội số của đa thức tối thiểu này, và nếu một đa thức là bội số của � thì đánh giá của nó tại bất kỳ điểm nào trong số đó sẽ bằng 0; sự tương đương này làm cho công việc của chúng tôi dễ dàng hơn nhiều.
Bây giờ, chúng ta hãy thực hiện việc kiểm tra tích chấm với các đa thức ở trên. Đầu tiên, các đa thức trung gian:
A . s = [43.0, -73.333, 38.5, -5.166]
B . s = [-3.0, 10.333, -5.0, 0.666]
C . s = [-41.0, 71.666, -24.5, 2.833]
Bây giờ, �.�⋅�.�—�.�:
t = [-88.0, 592.666, -1063.777, 805.833, -294.777, 51.5, -3.444]
Bây giờ, đa thức tối thiểu �=(�−1)⋅(�−2)⋅(�−3)⋅(�−4):
Z = [24, -50, 35, -10, 1]
Và nếu chúng ta chia kết quả trên cho �, chúng ta nhận được:
h = t / Z = [-3.666, 17.055, -3.444]
Không có phần còn lại.
Và thế là chúng ta có giải pháp cho QAP. Nếu chúng ta cố gắng làm sai lệch bất kỳ biến nào trong giải pháp R1CS mà chúng ta đang rút ra giải pháp QAP này - chẳng hạn, đặt biến cuối cùng thành 31 thay vì 30, thì chúng ta sẽ nhận được một đa thức � không thực hiện được một trong các bước kiểm tra (đặc biệt là trường hợp, kết quả tại �=3 sẽ bằng −1 thay vì 0), và hơn nữa � sẽ không phải là bội số của �; đúng hơn, chia �/� sẽ cho số dư là [−5.0,8.833,−4.5,0.666].
Lưu ý rằng ở trên là sự đơn giản hóa; “trong thế giới thực”, phép cộng, nhân, trừ và chia sẽ không xảy ra với các số thông thường mà với các phần tử trường hữu hạn - một loại số học ma quái tự nhất quán, vì vậy tất cả các định luật đại số mà chúng ta biết và yêu thích vẫn còn đúng, nhưng trong đó tất cả các câu trả lời đều là phần tử của một số tập hợp có kích thước hữu hạn, thường là các số nguyên trong phạm vi từ 0 đến �−1 đối với một số �. Ví dụ: nếu �=13, thì 1/2=7 (và 7⋅2=1),3⋅5=2, v.v. Việc sử dụng số học trường hữu hạn sẽ loại bỏ nhu cầu lo lắng về lỗi làm tròn và cho phép hệ thống hoạt động tốt với các đường cong elip, điều này trở nên cần thiết đối với phần còn lại của bộ máy zk-SNARK giúp giao thức zk-SNARK thực sự an toàn.
Đặc biệt cảm ơn Eran Tromer vì đã giúp giải thích nhiều chi tiết về hoạt động bên trong của zk-SNARK cho tôi.
- Phân phối nội dung và PR được hỗ trợ bởi SEO. Được khuếch đại ngay hôm nay.
- PlatoData.Network Vertical Generative Ai. Trao quyền cho chính mình. Truy cập Tại đây.
- PlatoAiStream. Thông minh Web3. Kiến thức khuếch đại. Truy cập Tại đây.
- Trung tâmESG. Than đá, công nghệ sạch, Năng lượng, Môi trường Hệ mặt trời, Quản lý chất thải. Truy cập Tại đây.
- PlatoSức khỏe. Tình báo thử nghiệm lâm sàng và công nghệ sinh học. Truy cập Tại đây.
- BlockOffsets. Hiện đại hóa quyền sở hữu bù đắp môi trường. Truy cập Tại đây.
- nguồn: Trí thông minh dữ liệu Plato.