Blockchain EP.3 : Digital Wallet

Anonymous
Nextzy
Published in
5 min readApr 17, 2018

หลังจากทำ Transaction แบบอย่างง่ายไปแล้ว ทีนี้เราจะมาสร้างกระเป๋าเงินดิจิตอลเพื่อทำการโอนเงินในระบบกัน

What is Digital Wallet

“Wallet” เป็นชื่อเรียกของการยืนยันตัวตนบนระบบดิจิตอล โดยใช้ระบบกุญแจเข้ารหัสดิจิตอล (Cryptography) แบบ 2 ทางหรือ Asymmetric Cryptography โดยเมื่อเราทำการสร้างกุญแจขึ้นมา เราจะได้กุญแจมา 2 ตัว ซึ่ง 1 ตัวใช้ในการยืนยันความเป็นเจ้าของและใช้สำหรับบันทึกข้อมูลโดยใช้กุญแจตัวนี้ในการเข้ารหัส ส่วนอีก 1 ตัวเป็นกุญแจสาธารณะที่ใช้สำหรับแจกจ่ายให้คนอื่น เพื่อให้คนอื่นสามารถยืนยันข้อมูลที่รับมาว่าเราเป็นคนสร้าง หรือใช้เป็น Address สำหรับรับข้อมูลใน Blockchain โดยทั้ง 2 ตัวนั้นที่กล่าวมานั้น ก็คือ

  • PrivateKey เป็นกุญแจลับสำหรับเข้ารหัสข้อมูลเพื่อออก Signature และส่งให้คนอื่นสามารถตรวจสอบได้ว่าเราเป็นเจ้าของ Wallet Address ที่เราได้เข้าไปทำรายการนั้นจริงๆ เช่น ถ้าเราสร้างคำสั่งโอนจาก Wallet A ไป B ตัว PrivateKey จะเป็นตัวบอกว่าเราเป็นเจ้าของ Wallet A จริงๆ
  • PublicKey เป็นกุญแจสาธารณะที่ใช้สำหรับแจกจ่ายให้บุคคลอื่น ให้สามารถตรวจสอบข้อมูลที่เราส่งให้ที่เข้ารหัสด้วย PrivateKey ไปแล้ว ว่าเราเป็นคนสร้าง หรือเป็นเจ้าของเงินใน Wallet นั้นจริงๆ และยังใช้เป็น Address ให้คนอื่นสามารถทำรายการมาเพื่อโอนเงินให้เราได้ด้วย

How to Create Digital Wallet

การ Generate Private/Public Key นั้นมีอยู่หลายวิธีและหลายอัลกอริทึม โดยหลักๆที่ใช้กันจะมี

  • RSA ใช้ PrimeNumber ในการ Generate KeyPair โดยเป็นอัลกอริทึมที่นิยมใช้มาก
  • ECC ใช้ Elliptic-curve ในการ Generate KeyPair โดยอัลกอริทึมของ ECC นั้นจะให้ Key ที่ได้ออกมานั้น มีขนาดเล็กกว่า RSA ในระดับความปลอดภัยเดียวกัน

ในระยะหลังตัว Bitcoin ได้เปลี่ยนจากการใช้ RSA มาเป็น ECC ในการ Generate Wallet ใหม่ๆแล้ว แต่ในตัวอย่างนี้จะใช้ RSA เพื่อให้ง่ายต่อความเข้าใจนะครับ หากเราทำโดยใช้ Library แล้วยังไงรูปแบบก็จะเหมือนๆกัน แค่ได้ Key ขนาดต่างกันแต่ก็สามารถทำไปใช้ได้เหมือนกันครับ โดยเราจะ Generate ผ่าน Library ที่ชื่อว่า Forge กัน

ในการสร้าง PublicKey / PrivateKey ค่าที่ได้ออกมาจะเป็นค่าทางคณิตศาสตร์ตัวหนึ่ง เป็นชุดของตัวเลขอะไรก็ไม่รู้ยาวไปหมด เราสามารถแปลงค่าเหล่านี้ให้อยู่ใน Format ของตัวอักษรสำหรับเก็บข้อมูลได้ โดยมีใช้กันหลักๆอยู่ 2 Format คือ DER กับ PEM

How to Secure Private Key

Private Key นั้นเป็นสิ่งสำคัญยิ่งในโลกของ Blockchain เพราะเมื่อไม่มี Private Key คุณก็ไม่สามารถทำอะไรกับข้อมูลของคุณที่อยู่ระบบได้ มีเงินเท่าไหร่ก็เอาออกมาใช้ไม่ได้… แล้วจะเก็บอย่างไรให้ปลอดภัยละ

  • Encrypt Private Key เมื่อเราได้ Private Key ออกมาจากการ Generate แล้วสิ่งสำคัญที่ต้องทำก่อนคือ Encrypt มันด้วย Password ไงละ ทีนี้ Private Key จะใช้ได้ก็ต่อเมื่อรู้รหัสผ่านของเรา ถึงจะสามารถ Decrypt มันออกมาใช้งานได้ และแน่นอน …. อย่าลืม Password ละ
เข้ารหัส Private Key ไว้
  • เก็บไว้หลายที่เพื่อป้องกันภัยพิบัติต่างๆที่อาจเกิดขึ้นได้ เช่น ฮาร์ดดิสเสีย FlashDrive พัง อาจจะเก็บไว้สัก 3–4 Copy

ปัญหาคือ Private Key หายแล้วหายเลย จึงเริ่มมีคนออก Solution มาแก้ปัญหาในจุดนี้ ให้สามารถกู้คืน Private Key ขึ้นมาใหม่ได้ ปัจจุบันมีหลายวิธี เช่น สร้าง Private Key จาก Seed (ซึ่งเป็นข้อความยาวๆตัวหนึ่ง)โดยหากเราเก็บ Seed ไว้ก็สามารถนำมา Generate เป็น Private Key ตัวเดิมได้นั่นเอง อันนี้สามารถหาอ่านเพิ่มเติมได้ที่

Wallet Address

ขั้นตอนการ generate wallet address บน format แบบเดียวกับ bitcoin

ตัว Wallet Address แล้วจริงๆมันก็คือ PublicKey นี่แหละ ใช้สำหรับแจกจ่ายให้กับคนอื่นๆได้ เพื่อที่คนอื่นจะสามารถโอนเงินมายังบัญชีเราได้ แต่ตัว PublicKey ที่ Generate โดย RSA และ ECC นั้นมีความยาวค่อนข้างมาก ทำให้ไม่สามารถที่จะส่งให้ได้สะดวก เช่น Public Key ตัวนี้

วิธีการง่ายๆที่ใช้คือการเข้ารหัสทางเดียว (Hash) โดยเมื่อเรา Hash ตัว PublicKey แล้ว เราจะได้ค่าที่สั้นลงโดยการใช้ Sha256 นั้นจะได้ความยาวปรับมาที่ประมาน 64 ตัวอักษรตัว

ซึ่งก็ยังอาจจะยาวไปอยู่ดี ดังนั้นตัว Bitcoin นั้นจึง Hash กันอีกรอบ โดยใช้ Hash อีกหนึ่งอัลกอริทึมคือ RIPEMD-160 เพื่อให้ได้ Hash ที่สั้นลงมาเหลือประมาน 40 ตัว

จากนั้นก็นำค่าสุดท้ายที่ได้มา ไปเข้าฟังก์ชันหาค่า Checksum ซึ่งเราได้ออกมาเป็นค่า “cab5ab6e” จึงนำค่า Version + Hash + Checksum ไปทำการ Encode Base58 จึงได้ออกมาเป็น Wallet Address นะครับ

1MGF6D24S92zaYPL31LDnHczfoTTf7Ehvd

เท่านี้เราก็จะได้ Wallet Address จาก Public Key นั้นแล้ว และสามารถนำไปใช้ในระบบ Blockchain เราได้ โดยเหตุที่ต้องมีค่า Checksum ติดไปใน Wallet Address ด้วยเพื่อให้สามารถตรวจสอบได้ว่าค่า Address นั้นถูกต้องหรือไม่ จะได้ไม่ผิดพลาดในขั้นตอนการทำรายการนั่นเอง

How to Verify Transaction ?

ด้วยความที่ Private Key กับตัว Public Key ที่ Generate ออกมานั้น จริงๆมันมีความสัมพันธ์กันทางคณิตศาสตร์อยู่แล้ว ดังนั้นมันมีข้อมูลมาอย่างที่สามารถเชื่อมโยงกันได้ โดยเราเรียกสิ่งนี้ว่า ลายเซ็นดิจิตอล (Digital Signature) โดยเราสามารถสร้างได้จากการ Hash ข้อมูลที่ต้องการจะส่ง จากนั้น Encrypt ด้วย Private Key จะได้ออกมาเป็นตัวลายเซ็นดิจิตอลนั่นเอง

ขั้นตอนการ Verify ในฝั่งผู้รับ ว่าข้อมูลส่งมานั่นสร้างด้วยคนส่งจริงๆ โดยผู้ส่งจะส่งข้อมูลมา 3 ตัวให้กับผู้รับ คือ PublicKey, Data และ Signature จากนั้นคนรับทำการ
1. Hash ตัว Data ด้วยอัลกอริทึมเดียวกัน
2. Decrypt ตัว Signature ด้วย Public Key ที่รับมา จะได้ค่า Hash ออกมา
เปรียบเทียบค่า Hash ทั้งสองตัวที่ได้มา หากตรงกันก็ถือความเป็นการยืนยันความถูกต้องของข้อมูลเรียบร้อยแล้ว

Let’s Coding

ใน Part นี้เราจะทำแค่ในส่วนของการสร้างและดึง Wallet Address จาก Private Key ที่ถูกสร้างขึ้นมานะครับ ในขั้นตอนการใช้ Private Key และ Address เพื่อทำ Transactions จะอยู่ใน Part ถัดไป ดังนั้น ขั้นตอนนี้คือเราจะไม่ได้เข้าไปยุ่งกับระบบ Blockchain ที่เคยทำมาเลยให้มองว่าเป็นคนละส่วนกัน แต่เพียงแค่เรานำผลลัพธ์ที่ได้คือ PrivateKey และ Wallet Address ไปใช้ในระบบ Blockchain ของเราต่อไป

Wallet Structure

ตัว Wallet นั้นจริงๆจะประกอบไปด้วย 2 ส่วนคือ Private Key และ Public Key สำหรับตัว Wallet Address นั้นก็จะใช้เป็น Getter ในคลาส โดยเมื่อเรียกใช้ก็จะนำ Public Key มา Hash ออกมาเป็นค่า Address นั่นเอง

Generate KeyPair with RSA

เริ่มแรกก็ต้องมา Generate Keypair กันก่อน โดยผมใช้ lib ชื่อ node-forge มาใช้นะครับ โดยสามารถเรียกใช้ฟังก์ชัน generateKeyPair ได้เลย โดยระบุ

  • Private Key ที่ Generate ออกมานั้นจะยังไม่ได้ถูกเข้ารหัสไว้ โดยเราจะใช้ Private Key ตัวนี้ในการสร้าง Transaction ใน Part ถัดไป
  • Public Key ที่ Generate ออกมาได้นั้นจะเป็น Object ที่เก็บชุดของตัวเลขขนาดใหญ่ เราสามารถแปลงเป็น Text ในรูปแบบของ PEM-format ได้ หน้าตาก็จะประมานนี้ และเราก็สามารถนำไป Hash เพื่อแปลงเป็น Wallet Address ได้ทันที

Create New Wallet

พอเราได้ Private Key / Public Key จากการ Generate KeyPair แล้วเราก็สามารถนำค่านี้ไปสร้างเป็น Wallet ตัวใหม่ของเราได้เลย โดยในขั้นตอนการสร้างก็จะรับ Password มาเพื่อ Encrypt ตัว Private Key ด้วยเลย

Save Private Key to PEM File

ทีนี้มาทำฟังก์ชัน Export ตัว Private Key ของเราให้ออกมาเป็นไฟล์เพื่อเอาไว้ใช้เป็นกุญแจในภายภาคหน้ากันฮะ

ฟังก์ชันเซฟไฟล์ง่ายๆ

ใน class Wallet ของเราก็เพิ่ม method ในการ export พร้อมกับระบุ Password ที่ User กรอกมา เพื่อใช้ในการ Encrypt ตัว Private Key ก่อนบันทึกลงไฟล์

เมื่อเรียกใช้ เราก็จะได้ไฟล์ Private Key ที่ Encrypt แล้วมาเก็บไว้ในเครื่องแล้ว อยู่ในโฟลเดอร์ temp

Generate Wallet Address from Public Key

เมื่อเราได้ Public Key ออกมาแล้ว ก็จะมาทำฟังก์ชัน Hash โดยใช้ SHA-256 และ RIPEMD-160 ตามที่อ้างอิงไว้ด้านบน พร้อมกับ Encode ด้วย Base58 กัน

เตรียม Hash ฟังก์ชัน ใช้ผมสร้างออกมาเป็น Utils ไว้สำหรับเรียกใช้ได้ง่ายๆ จากไฟล์อื่นด้วย โดย SHA-256 ใช้ฟังก์ชัน hash จาก lib crypto ที่ติดมากับ node.js ส่วนการ hash ด้วย RIPEMD-160 ใช้ lib แยกชื่อ ripemd160 นะครับ

เตรียมไฟล์ hash.js ไว้

ในส่วนของ Encode ก็ใช้ lib เหมือนกัน โดยใช้ base-x และแยกออกมาเป็น utils เหมือนกัน

และสุดท้าย ก็สร้าง Getter ในคลาส Wallet สำหรับดึง Wallet Address ได้เลยครับ

Decrypt Private Key and Generate Public Key

หลังจากที่ได้ไฟล์ Private Key ออกมาเก็บไว้แล้ว เมื่อเราจะใช้งาน เช่นจะทำรายการโอน หรือต้องการค่า Wallet Address ใหม่ เราสามารถโหลดตัว Private Key นี้เข้าไปในระบบ เพื่อ Generate Public Key เดิมได้เลย โดยขั้นตอนการโหลดจะต้อง Decrypt ตัว Private Key ด้วยรหัสผ่านที่เคยระบุไว้แล้วด้วย จึงจะสามารถใช้งานได้

Wallet Address Verify

ถัดมาสร้างฟังก์ชันในการ Verify ว่า Wallet Address นี้มีค่าถูกต้องหรือไม่ โดยขั้นตอนการตรวจสอบก็มี
1. Decode Wallet Address ด้วย Base58
2. ตัด String 2 ตัวแรก (version) และ 8 ตัวท้ายออก (checksum)
3. นำค่าที่ได้ไป Hash Sha256 ทั้งหมด 2 รอบ แล้วเปรียบเทียบกับ checksum ที่ตัดออกไป ถ้าตรงกันก็แสดงว่าถูกต้องแล้ว

Verify Address Function

Create Transaction with Wallet Address

เริ่มจากการแก้ไขโค้ดเดิมให้เปลี่ยนการสร้าง Transaction เดิมจากที่รับ Address จากคนส่ง มาเป็นรับ Wallet Instance ที่สร้างด้วย Private Key และ Password เพื่อ Verify ขั้นต้นว่าคนที่จะส่งนั้นเป็นเข้าของ Address นั้นจริงๆ จากนั้นดึง Wallet Address จาก Private Key เพื่อไปทำรายการต่อไป

ในขั้นตอนการสร้าง Transaction นั้นเราจะเพิ่มข้อมูลที่ส่งไปสร้าง Transaction ด้วย โดยมี PublicKey และ Signature ที่สร้างจาก Private Key เพื่อใช้ตรวจสอบข้อมูลใน Transaction นี้ว่ามาจากคนส่งจริงหรือไม่

Verify Transaction

ในขั้นตอนการสร้าง Block นั้น คนสร้างหรือขุดจะต้องทำการ Verify Transaction นั้นด้วย โดยเราเรียกใช้ฟังก์ชัน Verify ที่เราสร้างไว้ใน Transaction โดยนำค่า Signature + Public Key + Data จาก Vin ของ Transaction มาทำการตรวจสอบว่าตรงกันหรือไม่ เพื่อตรวจสอบว่าคนส่งเป็นผู้สร้าง Transaction นี้มาจริงๆ โดยเราจะยกเว้นกรณีที่ Transaction นั้นเป็น Coinbase ซึ่งไม่มี Vin จากผู้ส่งจริงๆ จึงไม่จำเป็นต้องตรวจสอบ

ในการ Verify ว่า Signature นั้นตรงกันหรือไม่ จะใช้คำสั่งจากตัวไลบรารี่ forge เลย

สั่ง Verify ตอนสร้าง Block ให้เฉพาะ Transaction ที่ผ่านการ Verify เท่านั้นเข้าไปอยู่ใน Block นั้นได้

Testing

ทดสอบการสร้าง Wallet ด้วยคำสั่ง wallet create -p [password] เราก็จะได้ Wallet Address และไฟล์เก็บ Private Key ที่เข้ารหัสไว้แล้วออกมาในรูปแบบ PEM

ตัวอย่างไฟล์ Private Key ที่ได้มา

จากนั้นทดสอบคำสั่งอื่นๆ

  • ดึง Wallet Address จาก Private Key ด้วยคำสั่ง wallet address -k filePath -p password
  • ตรวจสอบ Wallet Address ที่ได้ว่าถูกต้องตาม Format หรือไม่ ด้วยคำสั่ง wallet verify -a address

ทดสอบการสร้าง Transaction ด้วย Wallet Address โดยเริ่มใหม่ตั้งแต่สร้าง Genesis Block กันเลยนะครับ init -a address ด้วย Wallet Address ใหม่ที่เราสร้างมา

จากนั้นลองโอนโดยใช้ Private Key ไปให้อีก Wallet นึง

เรียบร้อย~

References

--

--