SHA-256 ทำงานยังไง?
SHA-256 เปลี่ยนข้อมูลอินพุตใดก็ได้ให้เป็น fingerprint 256 บิตผ่านสามขั้นตอนที่กำหนดแน่นอน การติดตามขั้นตอนเหล่านี้จะอธิบายว่าทำไมผลลัพธ์ถึงดูสุ่ม — และทำไมมันถึงออกแบบมาแบบนั้น
SHA-256 ในสามขั้นตอน
สามตัวอักษร สามขั้นตอน ตัวอักษรฐานสิบหก 64 ตัวด้านบนเป็นผลลัพธ์ที่หลีกเลี่ยงไม่ได้จากการรัน "abc" ผ่านลำดับการดำเนินการบิตที่เฉพาะเจาะจง นี่คือทุกขั้นตอน
ทุกการคำนวณ SHA-256 ทำตามสูตรเดียวกัน อินพุตอาจเป็นหนึ่งไบต์หรือหนึ่งกิกะไบต์ — สามขั้นตอนเดิมจะทำงานในลำดับเดิมเสมอ
ลองพิมพ์อะไรก็ได้ด้านล่าง สามขั้นตอนเดิมทำงานทุกครั้ง — ทันที และกำหนดแน่นอน
ขั้นตอนที่ 1: การเติม Padding ให้ข้อความ
SHA-256 ประมวลผลข้อมูลใน block ขนาด 512 บิต (64 ไบต์) ก่อนเริ่มแฮช ข้อความจะถูกขยายให้พอดีกับโครงสร้าง block นี้ด้วยรูปแบบสามส่วนที่แม่นยำ
แปลงเป็นไบต์
ข้อความถูกเข้ารหัสเป็นไบต์ ข้อความ ASCII ตรงไปตรงมา: แต่ละตัวอักษรคือหนึ่งไบต์ "abc" กลายเป็นสามไบต์ — 0x61, 0x62, 0x63
ค่าไบต์ถูกกำหนดโดยมาตรฐาน UTF-8 ขั้นตอนนี้เป็นแค่การแทนค่า — การเติม padding จริงเริ่มต้นถัดไป
ต่อท้ายด้วยบิต 1 แล้วตามด้วยศูนย์
ทันทีหลังไบต์สุดท้ายของข้อความ ให้ต่อท้ายด้วยไบต์ 0x80 (ไบนารี: 10000000) ซึ่งทำเครื่องหมายจุดสิ้นสุดของข้อความ
จากนั้นต่อท้ายด้วยไบต์ศูนย์จนเหลือ 8 ไบต์ในบล็อกสุดท้าย ตัวคั่นนี้ทำให้ "abc" และ "abc\x00" เติม padding ต่างกัน — ไม่สามารถสร้าง block เดียวกันได้
ต่อท้ายด้วยความยาวข้อความ
8 ไบต์สุดท้ายเก็บความยาวข้อความต้นฉบับในหน่วยบิตเป็นจำนวนเต็ม 64 บิต big-endian "abc" คือ 3 ไบต์ = 24 บิต ดังนั้น 8 ไบต์สุดท้ายนั้นเข้ารหัส 0x0000000000000018
3 ไบต์ → 64 ไบต์ (1 × block 512 บิต)
เกิดอะไรขึ้นเมื่อข้อความครอบคลุมหลาย block?
block 512 บิตจุได้ 64 ไบต์ การ padding ต้องใช้ overhead 9 ไบต์ (0x80 หนึ่งไบต์ + 8 ไบต์สำหรับความยาว) ดังนั้นข้อความที่ยาวกว่า 55 ไบต์จะล้นไปยัง block ที่สอง
SHA-256 จัดการเรื่องนี้ด้วยการเชื่อมโยง: หลังจากประมวลผล block 1 แล้ว เอาต์พุตของมัน — สถานะภายใน 256 บิต — จะกลายเป็นจุดเริ่มต้นของ block 2 block 2 ผ่านขั้นตอนการบีบอัดเดียวกัน แต่ใช้สถานะเอาต์พุตของ block ก่อนหน้าแทนค่าเริ่มต้นที่กำหนดไว้ แฮชสุดท้ายคือเอาต์พุตของ block สุดท้าย ดังนั้นทุกไบต์ในทุก block มีผลต่อผลลัพธ์
ขั้นตอนที่ 2: สร้าง Message Schedule
SHA-256 ต้องการค่าอินพุตหนึ่งค่าต่อรอบการบีบอัด และมีทั้งหมด 64 รอบ แต่ block 512 บิตที่เติม padding แล้วให้แค่ 16 word (16 × 32 บิต = 512 บิต) ดังนั้น SHA-256 จึงสร้างอีก 48 word โดยผสม 16 word เดิมเข้าด้วยกัน — นี่คือ message schedule
แบ่ง block เป็น 16 word
อ่าน block 512 บิตที่เติม padding แล้วเป็น chunk 32 บิต 16 ชิ้น ระบุเป็น W[0] ถึง W[15] สำหรับ "abc" ที่เติม padding แล้ว สี่ไบต์แรก (0x61, 0x62, 0x63, 0x80) รวมกันเป็น W[0] = 0x61626380 word กลาง 12 ตัวเป็นศูนย์ทั้งหมด W[15] = 0x00000018 เข้ารหัสความยาวข้อความต้นฉบับ: 24 บิต
W[0] – W[15] · "abc" padded
Expansion trace · computing W[17]
Inputs
How σ1(0x00000018) is computed
สร้างอีก 48 word (W[16]–W[63])
สำหรับตำแหน่ง 16 ถึง 63 แต่ละ word ใหม่คำนวณจาก 4 word ก่อนหน้า ฟังก์ชันผสมสองตัว — σ0 และ σ1 — ทำการผสมข้อมูลก่อนที่จะบวกกัน ทั้งสองทำงานเหมือนกัน: นำ word 32 บิต หมุนบิตด้วยปริมาณสองค่าต่างกัน เลื่อนอีกครั้ง แล้ว XOR ผลลัพธ์ทั้งสามเข้าด้วยกัน การหมุนทำให้ทุกบิตในเอาต์พุตขึ้นอยู่กับบิตจากทั่วทั้งอินพุต — การเปลี่ยนแปลงหนึ่งบิตจะกระจายไปยังบิตทั้ง 32 บิตของผลลัพธ์
W[i] = σ1(W[i-2]) + W[i-7] + σ0(W[i-15]) + W[i-16]
σ0(x) = rotr(x,7) ^ rotr(x,18) ^ shr(x,3)
σ1(x) = rotr(x,17) ^ rotr(x,19) ^ shr(x,10)ขั้นตอนที่ 3: การบีบอัด 64 รอบ
ฟังก์ชันการบีบอัดใช้ตัวแปรทำงาน 8 ตัว — a ถึง h — และทำงาน 64 รอบ โดยใช้ schedule word หนึ่งตัวและค่าคงที่หนึ่งตัวต่อรอบ
กำหนดค่าเริ่มต้น
ตัวแปร 8 ตัวถูกกำหนดเป็น 32 บิตแรกของส่วนเศษของรากที่สองของจำนวนเฉพาะ 8 ตัวแรก ตัวเลข "nothing-up-my-sleeve" เหล่านี้พิสูจน์ว่าไม่มีการใส่ backdoor — ใครก็สามารถตรวจสอบได้
H[0] = 6a09e667 // frac(√2)
H[1] = bb67ae85 // frac(√3)
H[2] = 3c6ef372 // frac(√5)
H[3] = a54ff53a // frac(√7)
H[4] = 510e527f // frac(√11)
H[5] = 9b05688c // frac(√13)
H[6] = 1f83d9ab // frac(√17)
H[7] = 5be0cd19 // frac(√19)รัน 64 รอบ
แต่ละรอบใช้ message schedule word W[i] หนึ่งตัวและค่าคงที่รอบ K[i] หนึ่งตัว (จากรากที่สามของจำนวนเฉพาะ) การดำเนินการหกแบบจะผสมตัวแปร 8 ตัวในแต่ละรอบ — การดำเนินการเดียวกับบทเรียนความไม่สามารถย้อนกลับ
ภายในหนึ่งรอบของ SHA-256
1. กระจายข้อมูล (S1)
S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)หมุนบิตของ e ไป 6, 11 และ 25 ตำแหน่ง แล้ว XOR เข้าด้วยกัน เพื่อให้ทุกบิตส่งผลต่อกันอย่างกว้างขวาง
2. การเลือกบิต (Ch)
ch = (e & f) ^ (~e & g)ใช้บิตจาก e เพื่อเลือกบิตระหว่าง f หรือ g
3. การบวกค่าคงที่ (t1)
t1 = h + S1 + ch + k + wรวม h, S1, Ch และ word กับ constant ประจำรอบเข้าด้วยกัน
4. กระจายข้อมูล (S0)
S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)หมุนบิตของ a ไป 2, 13 และ 22 ตำแหน่ง แล้ว XOR เข้าด้วยกัน
5. กฎเสียงข้างมาก (Maj)
maj = (a & b) ^ (a & c) ^ (b & c)สำหรับแต่ละตำแหน่งบิต ให้เลือกค่าที่ปรากฏบ่อยที่สุดใน a, b และ c
6. อัปเดตสถานะ
[a', a, b, c, e', e, f, g]เลื่อนค่าทั้งหมดและคำนวณ a และ e ใหม่สำหรับรอบถัดไป
SHA-256 คำนวณ S0 = rotr(a,2) ^ rotr(a,13) ^ rotr(a,22) ตัวอย่าง 8 บิตนี้ใช้การหมุน 1, 3 และ 5 บิตเพื่อให้เห็นภาพได้ง่าย คลิกที่บิตเพื่อเปลี่ยนค่า
แสดงผลจำลอง (rotr 0/5)
ทำให้แฮชสมบูรณ์
หลังจาก 64 รอบ ให้บวกแต่ละตัวแปรทำงานกลับเข้าสู่ค่า H เริ่มต้น (mod 2³²) word 32 บิต 8 ตัวที่ได้นำมาต่อกันคือแฮช 256 บิต
SHA-256 ใน Bitcoin
Bitcoin ใช้ SHA-256 ในเกือบทุกองค์ประกอบ — โดยปกติจะใช้สองครั้งติดกัน (เรียกว่า SHA256d หรือ double-SHA-256)