พิสูจน์การทำงาน HashWX
HashWX คือโปรโตคอล challenge เริ่มต้นของ Cap แทนที่จะใช้ฟังก์ชันแฮชตายตัวอย่าง SHA-256 challenge ทุกข้อจะสร้างฟังก์ชันทางเดียว ตัวใหม่ ขึ้นมาจาก seed โดยประกอบจากการดำเนินการกับจำนวนเต็มและการแตกกิ่ง ซึ่งเลือกมาให้ GPU รันได้ไม่เร็วกว่า CPU มากนัก
ผู้ออกแบบคือ tevador คนเดียวกับที่เขียน RandomX และ HashX ส่วน Cap ก็รวมบิลด์ WebAssembly ฉบับอ้างอิงมาให้ในตัว
TIP
HashWX เป็นค่าเริ่มต้นของคีย์ Standalone ที่สร้างใหม่ ส่วนใน cap-core ต้องเลือกเปิดเองผ่าน API แบบ format 2 และที่นั่น proof of work แบบ SHA-256 ยังเป็นค่าเริ่มต้นอยู่ ดู challenge แบบ HashWX
ทำไมต้อง HashWX
ปัญหาของ proof of work แบบ SHA-256 คือปริมาณงานต่อวินาที GPU รันฟังก์ชันตายตัวตัวเดียวกันพร้อมกันนับพันเลนอย่างสอดประสาน จึงแก้ challenge ได้ต่อวินาทีมากกว่า CPU อยู่มาก และนั่นคือตัวเลขที่สำคัญจริง ๆ สำหรับการกันบอท: ผู้โจมตีไม่สนว่า challenge ข้อเดียวใช้เวลานานแค่ไหน สนแค่ว่าเคลียร์ได้กี่ข้อต่อชั่วโมง
ก่อนหน้านี้ Cap ใช้ปริศนา time-lock แบบ RSW เพื่อการนี้ RSW ชนะในแง่ เวลาแฝง เพราะการยกกำลังสองตามลำดับภายในปริศนาข้อเดียวทำขนานไม่ได้ แต่แพ้ขาดในแง่ ปริมาณงานต่อวินาที เพราะ GPU รันปริศนาที่เป็นอิสระต่อกันพร้อมกันได้เป็นพันข้อ เมื่อวัดเทียบกับ GPU ระดับผู้ใช้ทั่วไป:
| อัลกอริทึม | CPU, Ryzen 3700X, 16 เธรด | GPU, RTX 5060 Ti | GPU ได้เปรียบ |
|---|---|---|---|
| SHA-256 | 41 MH/s | 6150 MH/s | ~150x |
| RSW | 26 H/s | 4400 H/s | ~170x |
| HashWX | 2.8 MH/s | 5.8 MH/s | ~2x |
ตัวเลขชุดนี้เป็นของ tevador ที่ใช้โค้ด CUDA ของเขาเองซึ่งไม่ได้เปิดเผย เราวัดแถว RSW ซ้ำเองแยกต่างหาก: M3 วัดได้ 2.112 H/s ต่อเธรด ซึ่งคิดเป็น 26 H/s สำหรับ 16 เธรดของ Ryzen
RSW ถูกเลิกใช้แล้ว มันยังเลือกใช้ได้รายคีย์และคีย์เดิมยังทำงานต่อได้ แต่ไม่ควรใช้กับระบบที่ติดตั้งใหม่
ต้นทุน
ต้นทุนฝั่งเซิร์ฟเวอร์ต่อ challenge หนึ่งข้อ วัดบนคอร์เดียวของ Apple M3 เป็นค่ามัธยฐานจากการสร้าง 200 ครั้งและการตรวจสอบ 40 ครั้งผ่าน validateChallenge:
| โปรโตคอล | การสร้าง | การตรวจสอบ | รวม |
|---|---|---|---|
| HashWX, 1 challenge | 14 µs | 40 µs | 54 µs |
| HashWX, 4 challenge ย่อย (ค่าเริ่มต้น) | 20 µs | 129 µs | 149 µs |
| SHA-256 (50 challenge, ความยาก 4) | 4 µs | 83 µs | 87 µs |
| RSW (t = 75,000) | 1522 µs | 14 µs | 1536 µs |
challenge ของ HashWX แบบเดียวมีต้นทุนไป-กลับถูกที่สุดในสามตัวนี้ ค่าเริ่มต้นที่แบ่งเป็นสี่ challenge ย่อยใช้ราว 150 µs มากกว่า SHA-256 แต่เป็นหนึ่งในสิบของ RSW ซึ่งต้องจ่ายค่ายกกำลังมอดุลาร์จริงสี่ครั้งทุกครั้งที่สร้าง ความยากไม่มีผลกับตัวเลขเหล่านี้ เพราะการตรวจสอบคือการแฮชหนึ่งครั้งต่อหนึ่ง challenge ย่อย ไม่ว่าจะหามายากแค่ไหน
ต้นทุนฝั่งไคลเอนต์คืออีกด้านของการแลกเปลี่ยนนี้ challenge เดียวมีเวลาแก้ที่กระจายแบบเอกซ์โพเนนเชียล จึงเหมือนการจับสลาก ความยากเท่ากันอาจใช้ 30 มิลลิวินาทีสำหรับผู้เยี่ยมชมคนหนึ่ง และสามวินาทีสำหรับคนถัดไป Cap จึงแบ่งความยากออกเป็นสี่ challenge ย่อยเป็นค่าเริ่มต้น เพื่อให้เวลาแก้สม่ำเสมอขึ้น วัดผ่านวิดเจ็ตใน Chrome รุ่นเสถียรบน M3 8 คอร์ ชุดละ 72 ครั้ง โดยปรับความยากทั้งสองแบบให้มีค่ามัธยฐานใกล้เคียงกัน:
| 1 challenge, d = 1,330,000 | 4 challenge ย่อย, d = 1,000,000 | |
|---|---|---|
| ค่ามัธยฐาน | 536 ms | 490 ms |
| p90 | 1447 ms | 778 ms |
| ช้าที่สุดใน 72 ครั้ง | 2378 ms | 1490 ms |
คอลัมน์ขวาคือค่าเริ่มต้น เมื่อวัดกับคีย์ของ Standalone ได้ค่ามัธยฐาน 578 มิลลิวินาที และ p90 0.9 วินาที
สำหรับความยากที่กำหนด การแบ่งไม่ได้เปลี่ยนสิ่งที่ผู้โจมตีต้องจ่าย เพราะงานที่คาดหวังยังคงเป็น d แฮชไม่ว่าจะแบ่งอย่างไร สิ่งที่เปลี่ยนคือรูปร่างของการกระจาย ค่ามัธยฐานของ challenge เดียวอยู่ที่ 0.69 เท่าของค่าเฉลี่ย ส่วนสี่ challenge ย่อยจะดันค่ามัธยฐานไปอยู่ราว 0.92 เท่าของค่าเฉลี่ยและทำให้หางสั้นลง ดังนั้นที่ความยากเท่ากัน การแบ่งทำให้การแก้ทั่วไปช้าลงราวหนึ่งในสาม และลด p90 ลงราวหนึ่งในสี่ ตารางด้านบนตรึงค่ามัธยฐานไว้แทน ซึ่งทำให้แบบแบ่งใช้ความยากน้อยลง 25% และผู้โจมตีต้องทำงานน้อยลง 25% ต่อการแก้หนึ่งครั้ง overhead ของวิดเจ็ตเองมีน้อย worker จะตรวจทุก 16 มิลลิวินาทีว่าต้องหยุดหรือไม่ ซึ่งเป็นตัวกำหนดว่าการส่งต่องานระหว่าง challenge ย่อยจะนานได้สูงสุดเท่าใด
เอนจินของเบราว์เซอร์
บิลด์ wasm ทำงานได้ราว 60% ของความเร็วเนทีฟ บน worker เดียวเอนจินหลักทั้งสามเร็วใกล้เคียงกัน แต่เมื่อใช้ทุกคอร์ Safari จะตามหลัง วัดบน M3 เครื่องเดียวกันในรอบเดียวกัน โดยเบราว์เซอร์แต่ละตัวรันแบบ headless หรืออยู่หน้าสุด:
| เอนจิน | 1 worker | 8 worker | การถอยไปใช้โหมดตีความ |
|---|---|---|---|
| Chrome 153 | 440 KH/s | 2050 KH/s | 94 KH/s |
| Firefox 156 | 420 KH/s | 1850 KH/s | 105 KH/s |
| Safari 27.2 | 410 KH/s | 1480 KH/s | 105 KH/s |
บน worker เดียว ทั้งสามต่างกันไม่เกิน 5% บนแปด worker Safari ทำได้ราว 70% ของอัตราของ Chrome ดังนั้นให้ตั้งความยากโดยอิง Safari ที่ d = 1,000,000 เวลาเฉลี่ยจะอยู่ราว 0.5 วินาทีบน Chrome และ 0.7 วินาทีบน Safari
ถ้าจะวัดเอง ให้ใช้บิลด์รุ่นเสถียรของแต่ละเบราว์เซอร์และเปิดแท็บไว้หน้าสุด Firefox ที่มาพร้อม Playwright รันงาน WebAssembly ทุกชนิดช้ากว่า Firefox รุ่นเสถียรสามถึงหกเท่า ไม่ใช่แค่ HashWX และแท็บที่อยู่เบื้องหลังอาจถูกย้ายไปรันบนคอร์ประหยัดพลังงาน ทำให้ตัวเลขทุกตัวลดลงครึ่งหนึ่ง
โทรศัพท์มือถือ
ค่าเริ่มต้นบนโทรศัพท์จริงผ่าน BrowserStack เครื่องละ 15 ครั้ง และ 30 ครั้งสำหรับ Vivo ทุกรอบเริ่มจากหน้าที่เพิ่งโหลดใหม่ เหมือนผู้เยี่ยมชมที่เพิ่งเข้ามา หลังจากหน้าเว็บรัน HashWX ไปแล้วหนึ่งนาที Pixel 6 ใช้เวลาต่อการแก้หนึ่งครั้งน้อยลง 24% และ Vivo น้อยลง 29% ดังนั้นการวัดที่วอร์มอัปก่อนจะได้ตัวเลขดีกว่าในตารางนี้
| อุปกรณ์ | ระบบ | ทุกคอร์ | ค่ามัธยฐาน | ช้าที่สุด |
|---|---|---|---|---|
| Galaxy S24 | Android 14 | 1238 KH/s | 1.1 วินาที | 1.8 วินาที |
| Pixel 9 | Android 15 | 837 KH/s | 1.4 วินาที | 2.0 วินาที |
| Pixel 6 | Android 12 | 746 KH/s | 1.9 วินาที | 2.4 วินาที |
| iPhone 15 | iOS 17 | ไม่ได้วัด | 1.9 วินาที | 4.3 วินาที |
| iPhone 12 | iOS 17 | 620 KH/s | 2.0 วินาที | 3.3 วินาที |
| iPhone 13 | iOS 15 | 678 KH/s | 2.2 วินาที | 4.1 วินาที |
| iPhone SE 2022 | iOS 15 | 588 KH/s | 2.4 วินาที | 4.0 วินาที |
| Redmi Note 11 | Android 11 | 456 KH/s | 2.4 วินาที | 4.8 วินาที |
| Galaxy M32 | Android 11 | 444 KH/s | 2.8 วินาที | 6.1 วินาที |
| Vivo Y21 | Android 11 | 316 KH/s | 5.9 วินาที | 11.0 วินาที |
การแก้แต่ละครั้งรวมการรับส่งข้อมูลไป-กลับกับเซิร์ฟเวอร์ทดสอบสองครั้ง โดยค่ามัธยฐานของแต่ละเครื่องอยู่ที่ 80 ถึง 190 มิลลิวินาที Vivo ซึ่งเป็น Android ราคาประหยัดใช้เวลาราวสิบเท่าของเดสก์ท็อป M3 ถ้าทราฟฟิกส่วนใหญ่ของคุณมาจากมือถือ ให้ลดความยากลง เวลาแก้แปรผันตรงกับความยาก ดังนั้น 500,000 จะทำให้ส่วนที่ใช้คำนวณของตัวเลขทุกตัวในตารางนี้ลดลงราวครึ่งหนึ่ง
ไคลเอนต์ที่ไม่มี WebAssembly แก้ HashWX ไม่ได้เลยและจะได้รับข้อผิดพลาด ถ้าคุณต้องรองรับพวกเขา ให้ใช้ proof of work แบบ SHA-256 ซึ่งมีทางถอยเป็น JS ล้วน บน iPhone วิดเจ็ตต้องใช้ iOS 15 ขึ้นไป
สิ่งที่ HashWX ไม่ได้ป้องกัน
เหมือนกับที่ RSW ป้องกันไม่ได้: ชิปเฉพาะทาง FPGA หรือ ASIC ที่สร้างมาเพื่อสิ่งนี้ยังเอาชนะ CPU ได้อยู่ดี ในเชิงเศรษฐศาสตร์มันไม่คุ้มกับการทำฟาร์ม CAPTCHA เพราะ ASIC มีต้นทุนออกแบบหลายล้าน แต่นี่ก็ไม่ใช่การรับประกันเชิงการเข้ารหัสลับ
และมันก็หยุดฟาร์มที่ใช้คนแก้ไม่ได้ ทั้งตอนนี้และตลอดไป proof of work ทำได้แค่ดันต้นทุนต่อคำขอให้สูงขึ้น ใช้มันคู่กับ challenge แบบ instrumentation เพื่อให้ต้องมีสภาพแวดล้อมเบราว์เซอร์จริงด้วย
ลองใช้งาน
API ของ cap-core มีเอกสารอยู่ที่ challenge แบบ HashWX ตัววิดเจ็ตตรวจจับการตอบกลับแบบ format 2 ได้เอง แค่อัปเกรดเซิร์ฟเวอร์ก็พอ
บน Cap Standalone HashWX เป็นค่าเริ่มต้นของคีย์ที่สร้างใหม่ และสลับได้รายคีย์ในแดชบอร์ด
