SHA-256 ทำงานยังไง?
SHA-256 เปลี่ยนข้อมูลอินพุตใดก็ได้ให้เป็น fingerprint 256 บิตผ่านสามขั้นตอนที่กำหนดแน่นอน การติดตามขั้นตอนเหล่านี้จะอธิบายว่าทำไมผลลัพธ์ถึงดูสุ่ม — และทำไมมันถึงออกแบบมาแบบนั้น
ba7816bf8f01cfea414140de5dae2ec73b00361bbef0469f8f9b64b96d7ff1a
สามตัวอักษร สามขั้นตอน ตัวอักษรฐานสิบหก 64 ตัวด้านบนเป็นผลลัพธ์ที่หลีกเลี่ยงไม่ได้จากการรัน "abc" ผ่านลำดับการดำเนินการบิตที่เฉพาะเจาะจง นี่คือทุกขั้นตอน
SHA-256 ในสามขั้นตอน
ทุกการคำนวณ 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 มีผลต่อผลลัพธ์
การเชื่อมโยง: เอาต์พุตของแต่ละ 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)
การขุด (Proof of Work)
นักขุดค้นหา block header ที่แฮช SHA256d ขึ้นต้นด้วยบิตศูนย์เพียงพอ ไม่มีทางลัด — วิธีเดียวคือเปลี่ยน nonce และแฮชใหม่หลายพันล้านครั้งต่อวินาที
Transaction ID
ทุก transaction ถูกระบุด้วย SHA256d ของข้อมูลดิบ TxID นี้คือสิ่งที่ wallet และ block explorer ใช้อ้างอิง transaction เฉพาะ
Merkle Tree
transaction ทั้งหมดใน block ถูกแฮชเป็นคู่ซ้ำๆ จนเหลือ root hash เดียว Merkle root นี้ให้ทุกคนพิสูจน์ว่า transaction อยู่ใน block โดยไม่ต้องดาวน์โหลดทั้ง block
การสร้างที่อยู่
กุญแจส่วนตัวของคุณถูกแฮชด้วย SHA-256 (แล้วตามด้วย RIPEMD-160) เพื่อสร้างที่อยู่ Bitcoin แฮชไม่สามารถย้อนกลับได้ — ที่อยู่ของคุณไม่เปิดเผยข้อมูลใดๆ เกี่ยวกับกุญแจส่วนตัว
ดูทุกไบต์ padding ทั้ง 64 schedule word และทุกรอบการบีบอัด — พร้อมค่าจริงจากข้อความของคุณ
เปิด visualizer →บทเรียนที่เกี่ยวข้อง
ทำไม SHA-256 ถึงย้อนกลับไม่ได้?→