วิทาลิก บูเตริน ผ่านทาง บล็อกของ Vitalik Buterin
นี่คือกระจกของการโพสต์ที่ https://medium.com/@VitalikButerin/zk-snarks-under-the-hood-b33151a013f6
นี่เป็นส่วนที่สามของชุดบทความที่อธิบายวิธีการทำงานของเทคโนโลยีที่อยู่เบื้องหลัง zk-SNARKs บทความก่อนหน้านี้เกี่ยวกับ โปรแกรมเลขคณิตกำลังสอง และ การจับคู่เส้นโค้งวงรี จำเป็นต้องอ่าน และบทความนี้จะถือว่าความรู้ของทั้งสองแนวคิด ความรู้พื้นฐานเกี่ยวกับ zk-SNARK คืออะไรและทำอะไรได้บ้าง ดูสิ่งนี้ด้วย บทความของ Christian Reitwiessner ที่นี่ สำหรับการแนะนำทางเทคนิคอื่น
ในบทความก่อนหน้านี้ เราได้แนะนำโปรแกรมเลขคณิตกำลังสอง ซึ่งเป็นวิธีการแทนปัญหาทางการคำนวณด้วยสมการพหุนามที่คล้อยตามกลอุบายทางคณิตศาสตร์รูปแบบต่างๆ ได้มากกว่า นอกจากนี้เรายังแนะนำการจับคู่เส้นโค้งวงรี ซึ่งช่วยให้มีรูปแบบการเข้ารหัสโฮโมมอร์ฟิกทางเดียวในรูปแบบที่จำกัดมาก ซึ่งช่วยให้คุณตรวจสอบความเท่าเทียมกันได้ ตอนนี้ เราจะเริ่มต้นจากจุดที่เราค้างไว้ และใช้การจับคู่เส้นโค้งวงรี ร่วมกับเทคนิคทางคณิตศาสตร์อื่นๆ เพื่อให้ผู้พิสูจน์พิสูจน์ได้ว่าพวกเขารู้วิธีแก้ปัญหาสำหรับ QAP โดยเฉพาะ โดยไม่เปิดเผยสิ่งอื่นใดเกี่ยวกับ วิธีแก้ปัญหาที่แท้จริง
บทความนี้จะเน้นที่ โปรโตคอลของพินอคคิโอ โดย Parno, Gentry, Howell และ Raykova จากปี 2013 (มักเรียกว่า PGHR13); กลไกพื้นฐานมีความแตกต่างกันเล็กน้อย ดังนั้นโครงการ zk-SNARK ที่นำไปใช้ในทางปฏิบัติอาจทำงานแตกต่างออกไปเล็กน้อย แต่หลักการพื้นฐานโดยทั่วไปจะยังคงเหมือนเดิม
ในการเริ่มต้น ให้เราเข้าสู่สมมติฐานการเข้ารหัสลับที่สำคัญซึ่งอยู่ภายใต้ความปลอดภัยของกลไกที่เราจะใช้: *ความรู้ของเลขยกกำลัง* สมมติฐาน
โดยพื้นฐานแล้ว หากคุณได้คะแนน � และ � สองจุด โดยที่ �⋅�=� และคุณได้รับคะแนน � ก็เป็นไปไม่ได้ที่จะเกิดขึ้นกับ �⋅� เว้นแต่ � จะ “ได้มาจาก � ในทางใดทางหนึ่ง ที่คุณรู้ สิ่งนี้อาจดูชัดเจนโดยสัญชาตญาณ แต่จริงๆ แล้วสมมติฐานนี้ไม่สามารถมาจากสมมติฐานอื่นๆ ได้ (เช่น ความแข็งของบันทึกแบบไม่ต่อเนื่อง) ที่เรามักจะใช้เมื่อพิสูจน์ความปลอดภัยของโปรโตคอลที่ใช้เส้นโค้งวงรี และจริงๆ แล้ว zk-SNARK จึงพักอยู่บน รากฐานที่สั่นคลอนกว่าการเข้ารหัสแบบ elliptic curve โดยทั่วไป - แม้ว่ามันจะยังแข็งแกร่งพอที่นักเข้ารหัสส่วนใหญ่ก็โอเค
ตอนนี้เรามาดูวิธีการใช้สิ่งนี้กันดีกว่า สมมุติว่าจุดคู่หนึ่ง (�,�) ตกลงมาจากท้องฟ้า โดยที่ �⋅�=� แต่ไม่มีใครรู้ว่าค่าของ � คืออะไร ทีนี้ สมมติว่าผมได้จุดคู่หนึ่ง (�,�) โดยที่ �⋅�=� จากนั้น สมมติฐาน KoE บอกเป็นนัยว่าวิธีเดียวที่ฉันสามารถสร้างจุดคู่นั้นได้คือการเอา � และ � และคูณทั้งสองด้วยตัวประกอบ r ที่ฉันรู้เป็นการส่วนตัว. โปรดทราบด้วยว่าด้วยความมหัศจรรย์ของการจับคู่เส้นโค้งวงรี โดยตรวจสอบว่า �=�⋅� จริงๆ แล้วไม่จำเป็นต้องรู้ � – แทน คุณสามารถตรวจสอบได้ว่า �(�,�)=�(�,�) หรือไม่
มาทำอะไรที่น่าสนใจกว่านี้กันดีกว่า สมมติว่าเรามีจุด 1 คู่ที่ตกลงมาจากท้องฟ้า: (�1,�2),(�2,�10)…(�10,�XNUMX) ในทุกกรณี ��⋅�=�� สมมติว่าฉันให้จุดคู่หนึ่ง (�,�) แก่คุณ โดยที่ �⋅�=� คุณรู้อะไรตอนนี้? คุณรู้ไหมว่า � คือผลรวมเชิงเส้น �1⋅�1+�2⋅�2+…+�10⋅�10 โดยที่ฉันรู้สัมประสิทธิ์ �1,�2…�10 นั่นคือ วิธีเดียวที่จะไปถึงจุดคู่ดังกล่าว (�,�) ได้คือนำผลคูณของ �1,�2…�10 มาบวกกัน แล้วทำการคำนวณแบบเดียวกันกับ �1,�2… �10.
โปรดทราบว่า เมื่อพิจารณาชุดเฉพาะของ �1…�10 จุด ที่คุณอาจต้องการตรวจสอบผลรวมเชิงเส้น คุณจะไม่สามารถสร้างจุด �1…�10 จุด ประกอบโดยไม่รู้ว่า � คืออะไร และถ้าคุณรู้ว่าอะไร � คือคุณสามารถสร้างคู่ (�,�) โดยที่ �⋅�=� สำหรับอะไรก็ได้ � ที่คุณต้องการ โดยไม่ต้องสร้างผลรวมเชิงเส้น ดังนั้น เพื่อให้ได้ผล จึงจำเป็นอย่างยิ่งที่ใครก็ตามที่สร้างคะแนนเหล่านั้นจะต้องเชื่อถือได้ และจะลบ � ทันทีที่พวกเขาสร้างคะแนนทั้งสิบนั้น นี่คือที่มาของแนวคิดของ "การตั้งค่าที่เชื่อถือได้".
โปรดจำไว้ว่าคำตอบของ QAP คือเซตของพหุนาม (�,�,�) โดยที่ �(�)⋅(�)−�(�)=�(�)⋅�(�) โดยที่:
- � คือผลรวมเชิงเส้นของเซตของพหุนาม {�1…��}
- � คือผลรวมเชิงเส้นของ {�1…��} ที่มีค่าสัมประสิทธิ์เท่ากัน
- � คือผลรวมเชิงเส้นของ {�1…��} ที่มีค่าสัมประสิทธิ์เท่ากัน
เซต {�1…��},{�1…��} และ {�1…��} และพหุนาม � เป็นส่วนหนึ่งของคำชี้แจงปัญหา
อย่างไรก็ตาม ในกรณีส่วนใหญ่ �,� และ � มีขนาดใหญ่มาก สำหรับบางสิ่งที่มีวงจรเกตหลายพันตัว เช่น ฟังก์ชันแฮช พหุนาม (และตัวประกอบของผลรวมเชิงเส้น) อาจมีพจน์ได้หลายพันพจน์ ดังนั้น แทนที่จะให้ผู้พิสูจน์ระบุผลรวมเชิงเส้นโดยตรง เราจะใช้เคล็ดลับที่เราแนะนำข้างต้นเพื่อให้ผู้พิสูจน์พิสูจน์ว่าพวกเขากำลังให้บางสิ่งที่เป็นผลรวมเชิงเส้น แต่ไม่เปิดเผยสิ่งอื่นใด
คุณอาจสังเกตเห็นว่าเคล็ดลับข้างต้นใช้ได้กับเส้นโค้งรูปวงรี ไม่ใช่พหุนาม ดังนั้น สิ่งที่เกิดขึ้นจริงคือเราเพิ่มค่าต่อไปนี้ให้กับการตั้งค่าที่เชื่อถือได้:
- �⋅�1(�),�⋅�1(�)⋅��
- �⋅�2(�),�⋅�2(�)⋅��
- ...
- �⋅�1(�),�⋅�1(�)⋅��
- �⋅�2(�),�⋅�2(�)⋅��
- ...
- �⋅�1(�),�⋅�1(�)⋅��
- �⋅�2(�),�⋅�2(�)⋅��
- ...
คุณสามารถมอง t เป็น "จุดลับ" ที่ใช้ประเมินพหุนามได้ � คือ “ตัวกำเนิด” (จุดโค้งวงรีสุ่มบางจุดที่ระบุเป็นส่วนหนึ่งของโปรโตคอล) และ �,��,�� และ �� คือ “ของเสียที่เป็นพิษ” ซึ่งเป็นตัวเลขที่ต้องลบออกโดยสิ้นเชิงไม่ว่าจะด้วยวิธีใดก็ตาม มิฉะนั้น ใครก็ตามที่มีพวกเขาจะสามารถสร้างหลักฐานปลอมได้ ทีนี้ หากมีใครให้คะแนน �, � กับคุณโดยที่ �⋅��=� (คำเตือน: เราไม่จำเป็นต้อง �� เพื่อตรวจสอบสิ่งนี้ เพราะเราสามารถตรวจสอบการจับคู่ได้) คุณจะรู้ว่าสิ่งที่พวกเขาเหล่านั้น จะให้ผลรวมเชิงเส้นของ �� พหุนามที่ประเมินที่ �
ดังนั้น จนถึงขณะนี้ ผู้พิสูจน์จะต้องให้:
- ��=�⋅�(�),��′=�⋅�(�)⋅��
- ��=�⋅�(�),��′=�⋅�(�)⋅��
- ��=�⋅�(�),��′=�⋅�(�)⋅��
โปรดทราบว่าผู้พิสูจน์ไม่จำเป็นต้องรู้จริงๆ (และไม่ควรรู้!) �,��,�� หรือ �� ในการคำนวณค่าเหล่านี้ แต่ผู้พิสูจน์ควรจะสามารถคำนวณค่าเหล่านี้ได้จากจุดที่เราเพิ่มไปยังการตั้งค่าที่เชื่อถือได้
ขั้นตอนต่อไปคือต้องแน่ใจว่าชุดค่าผสมเชิงเส้นทั้งสามชุดมีค่าสัมประสิทธิ์เท่ากัน ซึ่งเราสามารถทำได้โดยการเพิ่มค่าอีกชุดหนึ่งให้กับการตั้งค่าที่เชื่อถือได้: �⋅(��(�)+��(�)+��(�))⋅� โดยที่ � เป็นอีกตัวเลขหนึ่งที่ควรพิจารณาว่า “เป็นพิษ” เสีย” และทิ้งทันทีที่การตั้งค่าที่เชื่อถือได้เสร็จสิ้น จากนั้นเราสามารถให้ผู้พิสูจน์สร้างผลรวมเชิงเส้นด้วยค่าเหล่านี้โดยมีค่าสัมประสิทธิ์เท่ากัน และใช้เคล็ดลับการจับคู่แบบเดียวกับข้างต้นเพื่อตรวจสอบว่าค่านี้ตรงกับค่า �+�+� ที่ให้มา
สุดท้าย เราต้องพิสูจน์ว่า �⋅�−�=�⋅� เราทำสิ่งนี้อีกครั้งด้วยการตรวจสอบการจับคู่:
�(��,��)/�(��,�)?=�(�ℎ,�⋅�(�))
โดยที่ �ℎ=�⋅�(�) หากความเชื่อมโยงระหว่างสมการนี้กับ �⋅�−�=�⋅� ไม่สมเหตุสมผลสำหรับคุณ ให้กลับไปอ่าน บทความเกี่ยวกับการจับคู่.
เราเห็นวิธีการแปลง �,� และ � เป็นจุดโค้งวงรีข้างต้นแล้ว � เป็นเพียงตัวกำเนิด (เช่น จุดเส้นโค้งวงรีเทียบเท่ากับเลขหนึ่ง) เราสามารถเพิ่ม �⋅�(�) ให้กับการตั้งค่าที่เชื่อถือได้ � ยากกว่า � เป็นเพียงพหุนาม และเราคาดการณ์ล่วงหน้าน้อยมากว่าค่าสัมประสิทธิ์ของมันจะเป็นเท่าใดสำหรับโซลูชัน QAP แต่ละตัว ดังนั้นเราจึงจำเป็นต้องเพิ่มข้อมูลเพิ่มเติมให้กับการตั้งค่าที่เชื่อถือได้ โดยเฉพาะลำดับ:
�,�⋅�,�⋅�2,�⋅�3,�⋅�4….
ในการตั้งค่าที่เชื่อถือได้ของ Zcash ลำดับที่นี่จะสูงถึงประมาณ 2 ล้าน นี่คือจำนวนพลังของ � ที่คุณต้องการเพื่อให้แน่ใจว่าคุณจะสามารถคำนวณ �(�) ได้เสมอ อย่างน้อยสำหรับอินสแตนซ์ QAP เฉพาะที่พวกเขาสนใจ และด้วยเหตุนี้ ผู้พิสูจน์จึงสามารถให้ข้อมูลทั้งหมดแก่ผู้ตรวจสอบเพื่อทำการตรวจสอบขั้นสุดท้ายได้
มีรายละเอียดอีกประการหนึ่งที่เราต้องหารือกัน โดยส่วนใหญ่แล้ว เราไม่เพียงแค่ต้องการพิสูจน์ในเชิงนามธรรมว่ามีวิธีแก้ปัญหาบางอย่างสำหรับปัญหาเฉพาะบางอย่างเท่านั้น แต่เราต้องการพิสูจน์ความถูกต้องของวิธีแก้ปัญหาเฉพาะบางอย่าง (เช่น พิสูจน์ว่าหากคุณใช้คำว่า "cow" และแฮช SHA3 ล้านครั้ง ผลลัพธ์สุดท้ายจะเริ่มต้นด้วย 0x73064fe5) หรือแสดงว่ามีวิธีแก้ปัญหาอยู่หากคุณจำกัด พารามิเตอร์บางส่วน ตัวอย่างเช่น ในอินสแตนซ์ของสกุลเงินดิจิทัลที่มีการเข้ารหัสจำนวนธุรกรรมและยอดคงเหลือในบัญชี คุณต้องการพิสูจน์ว่าคุณรู้จักคีย์ถอดรหัส k บางอย่างที่:
decrypt(old_balance, k) >= decrypt(tx_value, k)
decrypt(old_balance, k) - decrypt(tx_value, k) = decrypt(new_balance, k)
การเข้ารหัส old_balance
, tx_value
และ new_balance
ควรระบุต่อสาธารณะ เนื่องจากเป็นค่าเฉพาะที่เราต้องการตรวจสอบ ณ เวลานั้น ควรซ่อนเฉพาะคีย์ถอดรหัสเท่านั้น จำเป็นต้องมีการแก้ไขโปรโตคอลเล็กน้อยเพื่อสร้าง "คีย์การยืนยันแบบกำหนดเอง" ที่สอดคล้องกับข้อจำกัดเฉพาะบางประการของอินพุต
เอาล่ะ ย้อนกลับไปสักหน่อย ก่อนอื่น นี่คืออัลกอริธึมการยืนยันทั้งหมด โดยได้รับความอนุเคราะห์จากเบ็น แซสซง, โตรเมอร์, วีร์ซ่า และเคียซ่า:
บรรทัดแรกเกี่ยวข้องกับพาราเมตริกซ์ โดยพื้นฐานแล้ว คุณสามารถนึกถึงฟังก์ชันของมันคือการสร้าง "รหัสยืนยันที่กำหนดเอง" สำหรับกรณีเฉพาะของปัญหา โดยระบุข้อโต้แย้งบางส่วนไว้ บรรทัดที่สองคือการตรวจสอบการรวมเชิงเส้นสำหรับ �,� และ �; บรรทัดที่สามคือการตรวจสอบว่าชุดค่าผสมเชิงเส้นมีค่าสัมประสิทธิ์เท่ากัน และบรรทัดที่สี่คือการตรวจสอบผลคูณ �⋅�−�=�⋅�
โดยรวมแล้ว กระบวนการตรวจสอบคือการคูณเส้นโค้งวงรีสองสามรายการ (หนึ่งรายการสำหรับตัวแปรอินพุต "สาธารณะ" แต่ละตัว) และการตรวจสอบการจับคู่ห้าครั้ง ซึ่งหนึ่งในนั้นรวมถึงการคูณการจับคู่เพิ่มเติม การพิสูจน์ประกอบด้วยเส้นโค้งรูปไข่แปดจุด: จุดคู่สำหรับ �(�), �(�) และ �(�), จุด �� สำหรับ �⋅(�(�)+�(�)+�(� )) และจุด �ℎ สำหรับ �(�) จุดเจ็ดจุดเหล่านี้อยู่บนเส้นโค้ง �� (จุดละ 32 ไบต์ เนื่องจากคุณสามารถบีบอัดพิกัด � ให้เป็นบิตเดียวได้) และในการใช้ Zcash จุดหนึ่ง (��) จะอยู่บนเส้นโค้งบิดใน ��2 (64 ไบต์) ดังนั้นขนาดรวมของการพิสูจน์คือ ~288 ไบต์
ส่วนที่ยากที่สุดในการคำนวณสองส่วนที่ยากที่สุดในการสร้างหลักฐานคือ:
- การหาร (�⋅�−�)/� เพื่อให้ได้ � (อัลกอริทึมตาม การแปลงฟูริเยร์อย่างรวดเร็ว สามารถทำได้ในเวลาแบบซับกำลังสอง แต่ก็ยังใช้การคำนวณค่อนข้างมาก)
- ทำการคูณและการบวกเส้นโค้งวงรีเพื่อสร้างค่า �(�), �(�),�(�) และ �(�) และคู่ที่สอดคล้องกัน
เหตุผลพื้นฐานว่าทำไมการสร้างการพิสูจน์จึงยากมากก็คือความจริงที่ว่าสิ่งที่เป็นไบนารีลอจิกเกตเดียวในการคำนวณดั้งเดิมนั้นกลายเป็นการดำเนินการที่ต้องได้รับการประมวลผลแบบเข้ารหัสลับผ่านการดำเนินการเส้นโค้งวงรีหากเรากำลังสร้างการพิสูจน์ความรู้เป็นศูนย์จากมัน . ข้อเท็จจริงนี้ประกอบกับความเหนือชั้นของการแปลงฟูเรียร์ที่รวดเร็ว หมายความว่าการสร้างหลักฐานจะใช้เวลาประมาณ 20–40 วินาทีสำหรับธุรกรรม Zcash
คำถามที่สำคัญมากอีกข้อหนึ่งคือ: เราจะพยายามทำให้การตั้งค่าที่เชื่อถือได้น้อยลง... เรียกร้องความไว้วางใจน้อยลงได้หรือไม่ น่าเสียดายที่เราไม่สามารถทำให้มันไร้ความน่าเชื่อถือได้อย่างสมบูรณ์ สมมติฐานของ KoE นั้นขัดขวางการสร้างคู่อิสระ (��,��⋅�) โดยไม่รู้ว่า � คืออะไร อย่างไรก็ตาม เราสามารถเพิ่มความปลอดภัยได้อย่างมากโดยใช้การคำนวณแบบหลายฝ่าย “ของ-” นั่นคือ การสร้างการตั้งค่าที่เชื่อถือได้ระหว่างฝ่าย � ในลักษณะที่ตราบใดที่ผู้เข้าร่วมอย่างน้อยหนึ่งคนลบของเสียที่เป็นพิษออกไป คุณก็ไม่เป็นไร .
เพื่อให้เข้าใจว่าคุณจะทำเช่นนี้อย่างไร นี่เป็นอัลกอริธึมง่ายๆ สำหรับการนำชุดที่มีอยู่ (�,�⋅�,�⋅�2,�⋅�3…) และ “เพิ่ม” ความลับของคุณเอง เพื่อที่คุณจะได้ต้องใช้ทั้งความลับของคุณและความลับก่อนหน้า (หรือความลับชุดก่อนหน้า) เพื่อโกง
ชุดเอาต์พุตเป็นเพียง:
�,(�⋅�)⋅�,(�⋅�2)⋅�2,(�⋅�3)⋅�3…
โปรดทราบว่าคุณสามารถสร้างชุดนี้โดยรู้เฉพาะชุดดั้งเดิมและ s และชุดใหม่ทำหน้าที่ในลักษณะเดียวกับชุดเก่า ยกเว้นตอนนี้ใช้ �⋅� เป็น “ขยะพิษ” แทน � ตราบใดที่คุณและบุคคล (หรือผู้คน) ที่สร้างชุดก่อนหน้านี้ไม่ล้มเหลวในการกำจัดของเสียที่เป็นพิษและสมรู้ร่วมคิดในภายหลัง ชุดนั้นจะ "ปลอดภัย"
การทำเช่นนี้เพื่อการตั้งค่าที่เชื่อถือได้โดยสมบูรณ์นั้นค่อนข้างยากขึ้นเล็กน้อย เนื่องจากมีหลายค่าที่เกี่ยวข้อง และอัลกอริทึมจะต้องทำระหว่างฝ่ายต่างๆ ในหลายรอบ เป็นขอบเขตของการวิจัยเชิงรุกเพื่อดูว่าอัลกอริธึมการคำนวณแบบหลายฝ่ายสามารถทำให้ง่ายขึ้นเพิ่มเติมได้หรือไม่ และต้องใช้รอบน้อยลงหรือทำให้สามารถขนานกันได้มากขึ้นเท่านั้น เนื่องจากยิ่งคุณทำได้มากเท่าไรก็ยิ่งมีความเป็นไปได้ที่จะรวมไว้ในขั้นตอนการตั้งค่าที่เชื่อถือได้มากขึ้นเท่านั้น . มีเหตุผลที่จะเห็นว่าเหตุใดการตั้งค่าที่เชื่อถือได้ระหว่างผู้เข้าร่วมหกคนที่รู้จักและทำงานร่วมกันอาจทำให้บางคนไม่สบายใจ แต่การตั้งค่าที่เชื่อถือได้ซึ่งมีผู้เข้าร่วมหลายพันคนแทบจะแยกไม่ออกจากการไม่ไว้วางใจเลย และหากคุณหวาดระแวงจริงๆ คุณสามารถเข้าร่วมขั้นตอนการตั้งค่าได้ด้วยตัวเอง และอย่าลืมลบค่าของคุณเป็นการส่วนตัว
การวิจัยเชิงรุกอีกด้านหนึ่งคือการใช้วิธีการอื่นที่ไม่ใช้การจับคู่และกระบวนทัศน์การตั้งค่าที่เชื่อถือได้แบบเดียวกันเพื่อให้บรรลุเป้าหมายเดียวกัน ดู การนำเสนอล่าสุดของ Eli ben Sasson สำหรับทางเลือกหนึ่ง (แม้ว่าจะได้รับการเตือน แต่อย่างน้อยก็ซับซ้อนทางคณิตศาสตร์เท่ากับ SNARK!)
ขอขอบคุณเป็นพิเศษสำหรับ Ariel Gabizon และ Christian Reitwiessner สำหรับการตรวจสอบ
- เนื้อหาที่ขับเคลื่อนด้วย SEO และการเผยแพร่ประชาสัมพันธ์ รับการขยายวันนี้
- PlatoData.Network Vertical Generative Ai เพิ่มพลังให้กับตัวเอง เข้าถึงได้ที่นี่.
- เพลโตไอสตรีม. Web3 อัจฉริยะ ขยายความรู้ เข้าถึงได้ที่นี่.
- เพลโตESG. คาร์บอน, คลีนเทค, พลังงาน, สิ่งแวดล้อม แสงอาทิตย์, การจัดการของเสีย. เข้าถึงได้ที่นี่.
- เพลโตสุขภาพ เทคโนโลยีชีวภาพและข่าวกรองการทดลองทางคลินิก เข้าถึงได้ที่นี่.
- BlockOffsets การปรับปรุงการเป็นเจ้าของออฟเซ็ตด้านสิ่งแวดล้อมให้ทันสมัย เข้าถึงได้ที่นี่.
- ที่มา: เพลโต ดาต้า อินเทลลิเจนซ์