# Miniscript-based scripting language for Bitcoin contracts

Miniscript เป็นภาษาสคริปต์ย่อยของบิตคอยน์ที่ออกแบบโดย Blockstream ในปี 2019 เพื่อให้สามารถเขียนเงื่อนไขการใช้จ่ายของบิตคอยน์ได้ โดยมีโครงสร้างที่เข้าใจง่ายและปลอดภัยกว่า Script แบบเดิม ๆ (หมายถึง Bitcoin Script แบบเดิมที่เป็นภาษา stack-based ซึ่งยากต่อการวิเคราะห์และใช้งานร่วมกัน (เช่น การเขียน multisig ที่มีเงื่อนไขซับซ้อน) ) Miniscript เข้ามาแก้ไขปัญหาพวกนี้โดยการกำหนดโครงสร้างของ script ให้เป็น Tree ทำให้ง่ายต่อการวิเคราะห์, ตรวจสอบ, รวมสคริปต์เข้าด้วยกัน, และคำนวณค่า fees ได้อย่างอัตโนมัติ&#x20;

สรุปง่ายๆ ว่า Miniscript ช่วยให้ผู้พัฒนาสามารถเขียนสคริปต์ที่เข้าใจง่ายขึ้น วิเคราะห์ได้ และสร้างระบบ multisig หรือ escrow ที่ซับซ้อนได้อย่างมีประสิทธิภาพและปลอดภัย

การออกแบบของ Miniscript ช่วยให้นักพัฒนาสามารถ **วิเคราะห์และคอมไพล์สคริปต์อัตโนมัติ** ได้ Wallet รุ่นใหม่จึงไม่จำเป็นต้องเขียนโค้ดเฉพาะเพื่อรับกับสคริปต์แต่ละแบบอีกต่อไป ตัวอย่างเช่น Wallet สามารถตรวจสอบได้ว่าในการใช้จ่ายเหรียญใดบ้างต้องมีลายเซ็นต์หรือข้อมูลอะไรบ้าง (witness data) และยังสามารถประเมินต้นทุนการใช้จ่ายได้ล่วงหน้าอีกด้วย นอกจากนี้ Miniscript ยังอนุญาตให้เขียนเงื่อนไขการใช้จ่ายได้หลากหลายแบบ เช่น การผสมเงื่อนไขลายเซ็นต์, hash lock, หรือ time lock แบบต่างๆ ไว้ในสคริปต์เดียวกันได้

### โครงสร้างและ Syntax เบื้องต้นของ Miniscript

Miniscript นิยามสคริปต์ในรูปแบบขององค์ประกอบ (fragments) แต่ละตัวแทนคำสั่ง Script ย่อยๆ ที่มีหน้าที่ชัดเจน โดยนำมาต่อกันเป็น tree ตามเงื่อนไขในระดับนโยบาย ทำให้สามารถวิเคราะห์อย่างเป็นระบบได้ โดยแต่ละ fragment นั้นมีชื่อเฉพาะ เช่น `pk(key)` (requiring signature จากคีย์), `sha256(H)` (requiring เปิดเงื่อนไข hash), `older(n)`/`after(n)` (time-lock), รวมถึงตัวเชื่อมเชิงตรรกะเช่น `and_v`, `or_d`, `or_i`, `thresh` เป็นต้น

#### ตัวอย่างการใช้งานตัวดำเนินการใน Miniscript

* `and_v(X,Y)`: หมายถึงทั้งเงื่อนไข X และ Y ต้องเป็นจริง (คล้ายกับ _AND_) ในระดับ Bitcoin Script จะเทียบเท่ากับการวางผลลัพธ์ของ X บนสแต็ก ตามด้วยผลลัพธ์ของ Y (`[X] [Y]`)&#x20;
* `or_d(X,Z)`: หมายถึงต้องเป็นเงื่อนไข X หรือ Z ก็ได้ (คล้ายกับ _OR_) การแปลงเป็น Bitcoin Script จะได้ `[X] IFDUP NOTIF [Z] ENDIF` ซึ่งเป็นวิธีเขียน OR แบบมี fallback และมี property พิเศษเรื่อง “dissatisfiable” (สามารถตอบสนองเงื่อนไขให้ผิดได้อย่างสมบูรณ์)
* `or_i(X,Z)`: เป็นอีกวิธีของ OR ที่แปลงเป็น `IF [X] ELSE [Z] ENDIF` มีรูปแบบผลลัพธ์ต่างกันในแง่ขนาดสคริปต์และ witness
* `thresh(k, X₁,...,Xₙ)`: กำหนดว่าเงื่อนไขย่อยทั้งหมด X₁..Xₙ ต้องเป็นจริงอย่างน้อย k ในจำนวนนั้น (k-of-n) ใน Bitcoin Script จะถูกแปลงเป็นการรวมผลลัพธ์ย่อยเข้าด้วยกัน เช่น `[X1] [X2] ADD ... [Xn] ADD ... <k> EQUAL` เพื่อเช็คว่าจำนวนเงื่อนไขที่เป็นจริงเท่ากับ k
* **Wrappers** เช่น `v:X` (VERIFY), `s:X` (SWAP), `c:X` (CHECKSIG), `d:X` (DUP-IF), `j:X` (SIZE-IF), เป็นต้น ใช้เปลี่ยนแปลงพฤติกรรมของ fragment ที่อยู่ถัดไป โดยมีการแมปเป็น Opcode เฉพาะ  fragment แต่ละอัน เช่น `pk(key)` จะแปลเป็น `<key> OP_CHECKSIG`, `pkh(key)` แปลเป็น `DUP HASH160 <hash160> EQUALVERIFY CHECKSIG` ตามลำดับ

โครงสร้างของ Miniscript จึงง่ายต่อการตรวจสอบคุณสมบัติ เช่น มันแบ่งการทำงานเป็น 4 ประเภทหลัก (Base, Verify, Key, Wrapped) เพื่อกำหนดเงื่อนไขการใช้สแต็กและความปลอดภัยอย่างชัดเจน ข้อนี้ทำให้เรามั่นใจได้ว่าสคริปต์ที่ได้จะไม่ก่อปัญหาด้าน malleability หรือ op-limit ต่าง ๆ ที่อาจเกิดกับ Bitcoin Script แบบเดิม

### ตัวอย่าง

Miniscript เหมาะสำหรับใช้สร้างเงื่อนไขการใช้จ่ายที่ซับซ้อน เช่น การแบ่งเงินแบบ _Escrow_ หรือ _HTLC_ (Hashed Time-Locked Contract) เป็นต้น โดยเขียนเป็นโค้ดที่อ่านง่าย เช่น:

* **Escrow contract (A และ B หรือ C คนเดียว):**\
  สมมติต้องการสัญญาว่า เหรียญจะถูกใช้จ่ายได้เมื่อมี **ลายเซ็นต์ของ A กับ B พร้อมกัน** หรือ **มีลายเซ็นต์ของ C คนเดียว** แบบใดก็ได้ เราสามารถเขียนด้วย Miniscript ได้ตัวอย่างเช่น:

```
( pk(A) && pk(B) ) || pk(C)

```

ความหมายคือให้ทั้ง A และ B ต้องเซ็นต์ (AND) หรือไม่ก็ให้ C เซ็นต์เพียงคนเดียวก็ได้ (OR) ใน Blockly Miniscript แบบ infix นี้ `&&` หมายถึง `and_v` (AND แบบ Verify) ส่วน `||` หมายถึง OR แบบปกติ เมื่อนำมาคอมไพล์เป็น Bitcoin Script แล้วจะเทียบเท่ากับคำสั่ง stack ของ A และ B แล้วทำ BOOLOR กับ C วิธีนี้ช่วยให้เราเขียน escrow สลับซับซ้อนได้ง่ายขึ้น

* **HTLC (Lightning/Atomic Swap):**\
  ตัวอย่างมาตรฐานของ HTLC คือ **ผู้รับ (A) จะได้เหรียญเมื่อเปิดเผยค่า preimage H หรือมิฉะนั้นจะคืนเงินกลับไปยังผู้ส่ง (B) หลังผ่านเวลา** เราเขียนได้เป็น

```
( pk(A) && sha256(H) ) || ( pk(B) && older(10) )
```

ความหมายคือ _เงื่อนไขแรก_ `(pk(A) && sha256(H))` หมายถึง “ลายเซ็นต์ของ A พร้อมกับการเปิดเผย preimage ที่มีค่า SHA256 เป็น H” (A ได้เหรียญได้ทันทีเมื่อเปิด H ถูก) และ _เงื่อนไขที่สอง_ `(pk(B) && older(10))` หมายถึง “ลายเซ็นต์ของ B หลังจากผ่านเวลา 10 บล็อกแล้ว” (B ได้เงินคืนหลังเวลาที่กำหนด) เราสามารถเขียนสั้นๆ ด้วย infix `&&` และ `||` ดังตัวอย่างใน [Minsc playground](https://min.sc/#threshold-operator) วิธีนี้ช่วยให้สร้าง HTLC ได้ชัดเจน เทียบกับการเขียน Script ด้วยมือจะซับซ้อนมากกว่า (นอกจากนี้ Lightning Network ยังใช้ HTLC ที่คล้ายกันซึ่งอาจใช้ hash160 หรือ block time ก็ได้ ขึ้นกับเงื่อนไข เช่น BOLT#3 ใช้นโยบายแบบ `or_d(pk(primary), and_v(v:pk(recovery), older(12960)))` )

นอกจากตัวอย่างข้างต้นแล้ว เราสามารถใช้ Miniscript สร้าง _multi-signature_ หรือ **Threshold** อื่นๆ ได้เช่นกัน เช่น ตัวอย่างด้านล่างคือ Escrow แบบต้องการลายเซ็นต์จาก 2 ใน 3 ฝ่าย (ผู้ซื้อ, ผู้ขาย, หรือนายประกัน)

```
2 of [ pk(buyer_pk), pk(seller_pk), pk(arbiter_pk) ]
```

ข้อดีของ Miniscript คือเราแค่กำหนดเงื่อนไขในรูปนโยบายหรือโค้ดข้างต้น โปรแกรมจะช่วยคอมไพล์เป็นสคริปต์ Bitcoin ที่เหมาะสมให้โดยอัตโนมัติ

#### การแปลง Miniscript เป็น Bitcoin Script

Miniscript แต่ละ fragment มีการแมปกับชุดคำสั่ง Script ชัดเจน สามารถเรียกใช้ไลบรารีหรือคอมไพล์เลอร์เพื่อแปลงเป็นสคริปต์จริงได้โดยตรง ตัวอย่างเช่น สคริปต์ Miniscript ต่อไปนี้:

```
or_b(pk(key1), s:pk(key2))
```

จะถูกแปลงเป็น Bitcoin Script ตามตัวอย่างด้านบน:

```
<key1> OP_CHECKSIG OP_SWAP <key2> OP_CHECKSIG OP_BOOLOR
```

(ส่วนโค้ด `OP_SWAP` มาจาก wrapper `s:` โดยสลับตำแหน่งสแต็กก่อนเช็คลายเซ็นต์) ในเอกสารอ้างอิงของ Miniscript จะมีตารางแสดงการแมปทุก fragment และ wrapper กับ Script อยู่ เด้ะทิ้ง link ไว้ไปอ่านกันต่อข้างล่างนะ เมื่อได้สคริปต์ Bitcoin แล้ว ก็สามารถนำไปทำ P2WSH หรือ Tapscript และสร้างที่อยู่รับเหรียญได้โดยอัตโนมัติ ตัวอย่างข้างต้นนำไปสู่เงื่อนไขที่หากแต่ละ key เซ็นต์แล้วผลลัพธ์เป็นการ OR ด้วย OP\_BOOLOR ตามลำดับ

ไลบรารีอย่าง **rust-miniscript** (ของ Blockstream) ก็สามารถแปลงนโยบาย (policy) เป็น Miniscript และสุดท้ายเป็น Bitcoin Script ได้เสมอ ทำให้การสร้าง wallet descriptor ยืดหยุ่นและปลอดภัยขึ้น โดยทั่วไป เมื่อเราเขียน Miniscript ใดๆ ขึ้นมา (หรือเขียนโพลิซีให้คอมไพล์เป็น Miniscript) เราจะได้ Script เดิมแบบ deterministic เสมอ ซึ่งช่วยให้ระบบการสร้าง witness (ลายเซ็นต์กับข้อมูลช่วยเหลือ) และการวิเคราะห์ต่าง ๆ ทำได้ง่าย

ใครสนใจแล้วอยากลองเขียน ผมแนะนำ [https://min.sc/#threshold-operator](https://min.sc/#threshold-operator) ลองเข้าไปเล่นดูครับผม
