🪙Bitcoin, explained
ระดับกลางการเข้ารหัสอ่าน 10 นาที

SHA-256 ทำงานยังไง?

SHA-256 เปลี่ยนข้อมูลอินพุตใดก็ได้ให้เป็น fingerprint 256 บิตผ่านสามขั้นตอนที่กำหนดแน่นอน การติดตามขั้นตอนเหล่านี้จะอธิบายว่าทำไมผลลัพธ์ถึงดูสุ่ม — และทำไมมันถึงออกแบบมาแบบนั้น

สตริง "abc" — แฮชด้วย SHA-256

ba7816bf8f01cfea414140de5dae2ec73b00361bbef0469f8f9b64b96d7ff1a

สามตัวอักษร สามขั้นตอน ตัวอักษรฐานสิบหก 64 ตัวด้านบนเป็นผลลัพธ์ที่หลีกเลี่ยงไม่ได้จากการรัน "abc" ผ่านลำดับการดำเนินการบิตที่เฉพาะเจาะจง นี่คือทุกขั้นตอน

SHA-256 ในสามขั้นตอน

ทุกการคำนวณ SHA-256 ทำตามสูตรเดียวกัน อินพุตอาจเป็นหนึ่งไบต์หรือหนึ่งกิกะไบต์ — สามขั้นตอนเดิมจะทำงานในลำดับเดิมเสมอ

01เติม Padding ขยายข้อความให้เป็นจำนวนเต็มของ 512 บิตโดยใช้รูปแบบที่แม่นยำ
02สร้าง Schedule ขยาย block ที่เติม padding แล้วจาก 16 word เป็น schedule 64 word ของค่าที่ผสมแล้ว
03บีบอัด รัน 8 ตัวแปรการทำงานผ่าน 64 รอบของการดำเนินการบิต แล้วส่งออกแฮช 256 บิตสุดท้าย

ลองพิมพ์อะไรก็ได้ด้านล่าง สามขั้นตอนเดิมทำงานทุกครั้ง — ทันที และกำหนดแน่นอน

⌨️ลองแฮชเองเลยSHA-256 · แบบสด
0 ตัวอักษร · 0 ไบต์
ผลลัพธ์ SHA-256 — 64 ตัวอักษรเสมอ
กำลังคำนวณ...

ขั้นตอนที่ 1: การเติม Padding ให้ข้อความ

SHA-256 ประมวลผลข้อมูลใน block ขนาด 512 บิต (64 ไบต์) ก่อนเริ่มแฮช ข้อความจะถูกขยายให้พอดีกับโครงสร้าง block นี้ด้วยรูปแบบสามส่วนที่แม่นยำ

1

แปลงเป็นไบต์

ข้อความถูกเข้ารหัสเป็นไบต์ ข้อความ ASCII ตรงไปตรงมา: แต่ละตัวอักษรคือหนึ่งไบต์ "abc" กลายเป็นสามไบต์ — 0x61, 0x62, 0x63

ค่าไบต์ถูกกำหนดโดยมาตรฐาน UTF-8 ขั้นตอนนี้เป็นแค่การแทนค่า — การเติม padding จริงเริ่มต้นถัดไป

2

ต่อท้ายด้วยบิต 1 แล้วตามด้วยศูนย์

ทันทีหลังไบต์สุดท้ายของข้อความ ให้ต่อท้ายด้วยไบต์ 0x80 (ไบนารี: 10000000) ซึ่งทำเครื่องหมายจุดสิ้นสุดของข้อความ

จากนั้นต่อท้ายด้วยไบต์ศูนย์จนเหลือ 8 ไบต์ในบล็อกสุดท้าย ตัวคั่นนี้ทำให้ "abc" และ "abc\x00" เติม padding ต่างกัน — ไม่สามารถสร้าง block เดียวกันได้

3

ต่อท้ายด้วยความยาวข้อความ

8 ไบต์สุดท้ายเก็บความยาวข้อความต้นฉบับในหน่วยบิตเป็นจำนวนเต็ม 64 บิต big-endian "abc" คือ 3 ไบต์ = 24 บิต ดังนั้น 8 ไบต์สุดท้ายนั้นเข้ารหัส 0x0000000000000018

📦การเติม Padding ข้อความSHA-256 · แบบสด
61
62
63
80
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
18
ไบต์ข้อความ
0x80 (จุดเริ่ม padding)
ศูนย์ padding
ความยาว (64 บิต)

3 ไบต์ → 64 ไบต์ (1 × block 512 บิต)

💡
ถ้าข้อความยาวเกินไปที่จะใส่ใน block 512 บิตเดียวหลังเติม padding SHA-256 จะใช้หลาย block — บีบอัดทีละ block ตามลำดับ
4

เกิดอะไรขึ้นเมื่อข้อความครอบคลุมหลาย 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 ถัดไป

Block 1512 bits
Compression
State out256 bits
becomes initial state
Block 2512 bits
Compression
State out256 bits
becomes initial state
Block 3512 bits
Compression
Final hash256 bits
💡
ลองดู: พิมพ์ข้อความที่ยาวกว่า 55 ตัวอักษรในการสาธิตด้านบน — คุณจะเห็น block ที่สองปรากฏขึ้น

ขั้นตอนที่ 2: สร้าง Message Schedule

SHA-256 ต้องการค่าอินพุตหนึ่งค่าต่อรอบการบีบอัด และมีทั้งหมด 64 รอบ แต่ block 512 บิตที่เติม padding แล้วให้แค่ 16 word (16 × 32 บิต = 512 บิต) ดังนั้น SHA-256 จึงสร้างอีก 48 word โดยผสม 16 word เดิมเข้าด้วยกัน — นี่คือ message schedule

1

แบ่ง 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

W[0]0x61626380
W[1]0x00000000
W[2]0x00000000
W[3]0x00000000
W[4]0x00000000
W[5]0x00000000
W[6]0x00000000
W[7]0x00000000
W[8]0x00000000
W[9]0x00000000
W[10]0x00000000
W[11]0x00000000
W[12]0x00000000
W[13]0x00000000
W[14]0x00000000
W[15]0x00000018
Message data (W[0])
Zero padding (W[1]–W[14])
Length (W[15])

Expansion trace · computing W[17]

W[17] = σ1(W[15]) + W[10] + σ0(W[2]) + W[1]

Inputs

σ1(W[15])0x000F0000
W[10]0x00000000
σ0(W[2])0x00000000
W[1]0x00000000

How σ1(0x00000018) is computed

rotr(x, 17)0x000C0000
rotr(x, 19)0x00030000
shr(x, 10)0x00000000
XOR all three →0x000F0000
W[17] = σ1(W[15]) + 0 + 0 + 00x000F0000
2

สร้างอีก 48 word (W[16]–W[63])

สำหรับตำแหน่ง 16 ถึง 63 แต่ละ word ใหม่คำนวณจาก 4 word ก่อนหน้า ฟังก์ชันผสมสองตัว — σ0 และ σ1 — ทำการผสมข้อมูลก่อนที่จะบวกกัน ทั้งสองทำงานเหมือนกัน: นำ word 32 บิต หมุนบิตด้วยปริมาณสองค่าต่างกัน เลื่อนอีกครั้ง แล้ว XOR ผลลัพธ์ทั้งสามเข้าด้วยกัน การหมุนทำให้ทุกบิตในเอาต์พุตขึ้นอยู่กับบิตจากทั่วทั้งอินพุต — การเปลี่ยนแปลงหนึ่งบิตจะกระจายไปยังบิตทั้ง 32 บิตของผลลัพธ์

pseudocode
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)
เมื่อถึง W[63] ทุก word จะถูกผสมกับ word อื่นๆ ทุกตัว การเปลี่ยนแปลงหนึ่งบิตในข้อความต้นฉบับจะส่งผลกระทบไปทั่วทั้ง schedule 64 word

ขั้นตอนที่ 3: การบีบอัด 64 รอบ

ฟังก์ชันการบีบอัดใช้ตัวแปรทำงาน 8 ตัว — a ถึง h — และทำงาน 64 รอบ โดยใช้ schedule word หนึ่งตัวและค่าคงที่หนึ่งตัวต่อรอบ

1

กำหนดค่าเริ่มต้น

ตัวแปร 8 ตัวถูกกำหนดเป็น 32 บิตแรกของส่วนเศษของรากที่สองของจำนวนเฉพาะ 8 ตัวแรก ตัวเลข "nothing-up-my-sleeve" เหล่านี้พิสูจน์ว่าไม่มีการใส่ backdoor — ใครก็สามารถตรวจสอบได้

initial values
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)
2

รัน 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 ใหม่สำหรับรอบถัดไป

🔬สำรวจการทำงานภายในตัวอย่าง 8 บิต · SHA-256 ของจริงใช้ 32 บิต
S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)

SHA-256 คำนวณ S0 = rotr(a,2) ^ rotr(a,13) ^ rotr(a,22) ตัวอย่าง 8 บิตนี้ใช้การหมุน 1, 3 และ 5 บิตเพื่อให้เห็นภาพได้ง่าย คลิกที่บิตเพื่อเปลี่ยนค่า

a
← คลิกเพื่อเปลี่ยนค่า
rotr(a, 1)
rotr(a, 3)
rotr(a, 5)
XOR ทั้งสามตัว ↓
ผลลัพธ์ S0

แสดงผลจำลอง (rotr 0/5)

0
1
2
3
4
5
6
7
ขั้นตอนที่ 0 จาก 5
ทำไมถึงย้อนกลับไม่ได้: การหมุนบิตเพียงครั้งเดียวนั้นย้อนกลับได้ — แค่หมุนกลับ แต่ SHA-256 นำการหมุนที่แตกต่างกันสามแบบมา XOR กัน เมื่อรวมกันด้วย XOR แล้ว คุณไม่สามารถบอกได้ว่าบิตใดมาจากตัวหมุนไหน การหาค่า a จาก S0 จึงต้องแก้ระบบสมการที่ซับซ้อน — ไม่มีทางลัดทางพีชคณิต
3

ทำให้แฮชสมบูรณ์

หลังจาก 64 รอบ ให้บวกแต่ละตัวแปรทำงานกลับเข้าสู่ค่า H เริ่มต้น (mod 2³²) word 32 บิต 8 ตัวที่ได้นำมาต่อกันคือแฮช 256 บิต

ประมวลผลหลาย block 512 บิต? ผลลัพธ์แฮชจาก block หนึ่งแทนที่ H[0]–H[7] เป็นสถานะเริ่มต้นสำหรับ block ถัดไป ทุก block มีผลต่อผลลัพธ์สุดท้าย

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 แฮชไม่สามารถย้อนกลับได้ — ที่อยู่ของคุณไม่เปิดเผยข้อมูลใดๆ เกี่ยวกับกุญแจส่วนตัว

SHA-256 ถูกออกแบบโดย NSA และรับรองมาตรฐานโดย NIST ในปี 2001 ความปลอดภัยขึ้นอยู่กับคุณสมบัติทางคณิตศาสตร์ที่คุณเพิ่งติดตามมา — ไม่ใช่การเก็บอัลกอริทึมเป็นความลับ
เครื่องมือโต้ตอบ

ดูทุกไบต์ padding ทั้ง 64 schedule word และทุกรอบการบีบอัด — พร้อมค่าจริงจากข้อความของคุณ

เปิด visualizer →

บทเรียนที่เกี่ยวข้อง

ทำไม SHA-256 ถึงย้อนกลับไม่ได้?