<rss
      xmlns:atom="http://www.w3.org/2005/Atom"
      xmlns:media="http://search.yahoo.com/mrss/"
      xmlns:content="http://purl.org/rss/1.0/modules/content/"
      xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
      xmlns:dc="http://purl.org/dc/elements/1.1/"
      version="2.0"
    >
      <channel>
        <title><![CDATA[Learning BTC&NOSTR]]></title>
        <description><![CDATA[สร้างมาเพื่อแชร์เรื่องราวที่ได้ศึกษาจากการเรียนรู้เรื่องของบิตคอยน์และนอสเตอร์ จะพยายามเขียนทุกวันวันละโพสต์เพื่อเป็นการบังคับให้ตัวเองได้ศึกษามันเรื่อย ๆ ทุกวัน ถ้าผิดพลาดตรงไหนรบกวนช่วยแก้ไขกันด้วยนะครับ]]></description>
        <link>https://learnbn.npub.pro/</link>
        <atom:link href="https://learnbn.npub.pro/rss/" rel="self" type="application/rss+xml"/>
        <itunes:new-feed-url>https://learnbn.npub.pro/rss/</itunes:new-feed-url>
        <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
        <itunes:subtitle><![CDATA[สร้างมาเพื่อแชร์เรื่องราวที่ได้ศึกษาจากการเรียนรู้เรื่องของบิตคอยน์และนอสเตอร์ จะพยายามเขียนทุกวันวันละโพสต์เพื่อเป็นการบังคับให้ตัวเองได้ศึกษามันเรื่อย ๆ ทุกวัน ถ้าผิดพลาดตรงไหนรบกวนช่วยแก้ไขกันด้วยนะครับ]]></itunes:subtitle>
        <itunes:type>episodic</itunes:type>
        <itunes:owner>
          <itunes:name><![CDATA[Learning_BTC&NOSTR]]></itunes:name>
          <itunes:email><![CDATA[Learning_BTC&NOSTR]]></itunes:email>
        </itunes:owner>
            
      <pubDate>Fri, 02 Jan 2026 14:28:47 GMT</pubDate>
      <lastBuildDate>Fri, 02 Jan 2026 14:28:47 GMT</lastBuildDate>
      
      <itunes:image href="https://i.imgur.com/e6cvtcn.png" />
      <image>
        <title><![CDATA[Learning BTC&NOSTR]]></title>
        <link>https://learnbn.npub.pro/</link>
        <url>https://i.imgur.com/e6cvtcn.png</url>
      </image>
      <item>
      <title><![CDATA[สรุป Mastering Bitcoin บทที่ 7 Authorization and Authentication]]></title>
      <description><![CDATA[ฮี่ ๆๆๆๆๆ สวัสดีปีใหม่คร้าบบบบบ]]></description>
             <itunes:subtitle><![CDATA[ฮี่ ๆๆๆๆๆ สวัสดีปีใหม่คร้าบบบบบ]]></itunes:subtitle>
      <pubDate>Fri, 02 Jan 2026 14:28:47 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/i-0kfbut8da_crrpiaeae/</link>
      <comments>https://learnbn.npub.pro/post/i-0kfbut8da_crrpiaeae/</comments>
      <guid isPermaLink="false">naddr1qq25jtfsddnxya258pzyzhmr2ff8qj2pv4s52q3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wf0l0hd</guid>
      <category>ลองฟอร์มของไดโน</category>
      
        <media:content url="https://image.nostr.build/2eb9a47ba4fe6ecbc3d12dae8434d45ad15840655e6ee833420bb2ee307cf614.jpg" medium="image"/>
        <enclosure 
          url="https://image.nostr.build/2eb9a47ba4fe6ecbc3d12dae8434d45ad15840655e6ee833420bb2ee307cf614.jpg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qq25jtfsddnxya258pzyzhmr2ff8qj2pv4s52q3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wf0l0hd</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<h1><strong>บทที่ 7: Authorization and Authentication</strong></h1>
<hr>
<p>เมื่อคุณได้รับบิตคอยน์ คุณต้องตัดสินใจว่าใครจะได้รับสิทธิ์ในการใช้จ่ายเหรียญนั้น ซึ่งเรียกว่า authorization (การอนุญาต) นอกจากนี้ คุณต้องตัดสินใจด้วยว่า full node ควรแยกแยะผู้ที่ได้รับอนุญาตให้ใช้จ่ายออกจากคนอื่น ๆ อย่างไร ซึ่งเรียกว่า authentication (การยืนยันตัวตน) คำสั่งเกี่ยวกับการอนุญาตของคุณ และหลักฐานการยืนยันตัวตนจากผู้ใช้จ่าย จะถูกตรวจสอบโดย full node นับพัน ซึ่งต้องได้ข้อสรุปตรงกันว่าการใช้จ่ายนั้นได้รับอนุญาตและได้รับการยืนยันตัวตนอย่างถูกต้อง เพื่อให้ธุรกรรมดังกล่าวเป็นธุรกรรมที่ถูกต้อง</p>
<p>คำอธิบายดั้งเดิมของบิตคอยน์ใช้ public key ในการทำ authorization โดย Alice ส่งเหรียญให้ Bob ด้วยการใส่ public key ของเขาลงในเอาต์พุตของธุรกรรม ส่วนการทำ authentication มาจากการลงนาม (signature) โดย Bob ซึ่งผูกพันกับธุรกรรมการใช้จ่าย เช่น การที่ Bob ส่งต่อให้ Carol</p>
<p>ในเวอร์ชันแรกของบิตคอยน์ที่ถูกปล่อยออกมา ได้จัดเตรียมกลไกที่ยืดหยุ่นกว่าสำหรับทั้ง authorization และ authentication และการพัฒนาต่อมาทำให้กลไกเหล่านี้ยืดหยุ่นยิ่งขึ้นกว่าเดิม ในบทนี้ เราจะสำรวจฟีเจอร์เหล่านั้นและดูว่ามันถูกใช้งานอย่างแพร่หลายได้อย่างไร</p>
<h2>Transaction Scripts and Script Language</h2>
<p>เวอร์ชันแรก ๆ ของบิตคอยน์ได้แนะนำภาษาการเขียนโปรแกรมใหม่ชื่อว่า Script ซึ่งเป็นภาษาลักษณะคล้าย Forth ที่ทำงานบนสแตก ทั้งสคริปต์ที่ถูกวางไว้ในเอาต์พุต และสคริปต์อินพุตแบบ legacy ที่ใช้ในธุรกรรมการใช้จ่าย ล้วนเขียนด้วยภาษาสคริปต์นี้ทั้งสิ้น</p>
<p>Script เป็นภาษาที่เรียบง่ายมาก ต้องการการประมวลผลเพียงเล็กน้อย และไม่สามารถทำสิ่งซับซ้อนแบบที่ภาษาสมัยใหม่สามารถทำได้</p>
<p>เมื่อธุรกรรมแบบ legacy ยังเป็นรูปแบบที่ใช้กันมากที่สุด ธุรกรรมส่วนใหญ่ที่ประมวลผลบนเครือข่ายบิตคอยน์อยู่ในรูปแบบเดียวกันกับที่ alice จ่ายให้ bob ในบทก่อนหน้าและใช้สคริปต์ที่เรียกว่า pay to public key hash (P2PKH) แต่อย่างไรก็ตาม ธุรกรรมบิตคอยน์ไม่ได้จำกัดอยู่แค่สคริปต์ในรูปแบบนี้เท่านั้น จริง ๆ แล้วสคริปต์สามารถเขียนเพื่อกำหนดเงื่อนไขที่ซับซ้อนหลากหลายรูปแบบได้ แต่เพื่อที่จะเข้าใจสคริปต์ที่ซับซ้อนเหล่านั้น เราจำเป็นต้องเข้าใจพื้นฐานของสคริปต์ธุรกรรมและภาษาสคริปต์เสียก่อน</p>
<p>ในส่วนนี้ เราจะสาธิตองค์ประกอบพื้นฐานของภาษาสคริปต์สำหรับธุรกรรมบิตคอยน์ และแสดงให้เห็นว่าภาษานี้ใช้เพื่อกำหนดเงื่อนไขสำหรับการใช้จ่ายอย่างไร และจะสามารถทำให้เงื่อนไขนั้นสำเร็จได้อย่างไร</p>
<blockquote>
<p>TIP: การตรวจสอบความถูกต้องของธุรกรรมบิตคอยน์ไม่ได้อาศัยรูปแบบตายตัว แต่เกิดจากการ รันภาษาสคริปต์ ซึ่งเปิดโอกาสให้สามารถกำหนดเงื่อนไขได้หลากหลายแทบไม่จำกัด</p>
</blockquote>
<h2>Turing Incompleteness</h2>
<p>ภาษาสคริปต์ของธุรกรรมบิตคอยน์มีโอเปอเรเตอร์จำนวนมาก แต่ถูกจำกัดไว้อย่างจงใจในด้านสำคัญอย่างหนึ่ง คือ ไม่มีลูปหรือโครงสร้างควบคุมการไหลที่ซับซ้อน นอกเหนือจากการควบคุมแบบมีเงื่อนไขเท่านั้น สิ่งนี้ทำให้ภาษา ไม่เป็น Turing Complete หมายความว่าสคริปต์มีความซับซ้อนได้จำกัดและมีเวลาการประมวลผลที่คาดเดาได้ Script ไม่ใช่ภาษาสำหรับงานทั่วไป ข้อจำกัดเหล่านี้ช่วยป้องกันไม่ให้ภาษาใช้สร้างลูปไม่รู้จบหรือ “logic bomb” รูปแบบอื่นที่อาจแฝงอยู่ในธุรกรรมและถูกใช้โจมตีแบบปฏิเสธการให้บริการ (DoS) ต่อเครือข่ายบิตคอยน์ได้ โปรดจำไว้ว่า ทุกธุรกรรมจะถูกยืนยันโดย full node ทุกตัวในเครือข่ายบิตคอยน์ ภาษาแบบจำกัดช่วยป้องกันไม่ให้กลไกตรวจสอบธุรกรรมกลายเป็นช่องโหว่</p>
<h2>Stateless Verification</h2>
<p>ภาษาสคริปต์ของธุรกรรมบิตคอยน์เป็นแบบ stateless กล่าวคือไม่มีสถานะก่อนเริ่มการประมวลผลสคริปต์ และไม่มีการเก็บสถานะหลังจากสคริปต์รันเสร็จ ข้อมูลทั้งหมดที่จำเป็นสำหรับการประมวลผลสคริปต์อยู่ในสคริปต์และธุรกรรมที่กำลังรันสคริปต์เท่านั้น สคริปต์จะทำงานเหมือนกันทุกครั้งบนทุกระบบ หากระบบของคุณตรวจสอบสคริปต์ผ่าน คุณมั่นใจได้ว่าระบบอื่นในเครือข่ายบิตคอยน์ทั้งหมดก็จะตรวจสอบผ่านเช่นกัน หมายความว่า ธุรกรรมที่ถูกต้องจะถูกต้องสำหรับทุกคน และทุกคนรู้เช่นนั้น ความสามารถในการคาดเดาผลลัพธ์ได้แบบนี้เป็นประโยชน์สำคัญของระบบบิตคอยน์</p>
<h2>Script Construction</h2>
<p>กลไกการตรวจสอบธุรกรรมแบบดั้งเดิมของ Bitcoin อาศัยสองส่วนของสคริปต์ในการตรวจสอบธุรกรรม: output script และ input script</p>
<p>output script ระบุเงื่อนไขที่ต้องถูกทำให้สำเร็จเพื่อใช้จ่ายเอาต์พุตในอนาคต เช่น ใครมีสิทธิ์ใช้จ่ายเอาต์พุต และจะมีการตรวจสอบสิทธิ์อย่างไร</p>
<p>input script คือสคริปต์ที่ทำให้เงื่อนไขใน output script สำเร็จ และอนุญาตให้เอาต์พุตถูกใช้จ่ายได้ Input script เป็นส่วนหนึ่งของทุก ๆ อินพุตภายในธุรกรรม ส่วนใหญ่ในธุรกรรมแบบเดิมจะมีลายเซ็นดิจิทัลที่สร้างจาก private key ของผู้ใช้ แต่ input script ไม่จำเป็นต้องมีลายเซ็นเสมอไป</p>
<p>ทุกโหนดที่ตรวจสอบ Bitcoin จะตรวจสอบธุรกรรมโดยรัน output script และ input script ตามที่ได้กล่าวไว้ในบทที่ 4 อินพุตแต่ละตัวมี outpoint ที่อ้างถึงเอาต์พุตของธุรกรรมก่อนหน้า อินพุตยังมี input script อยู่ด้วย ซอฟต์แวร์ตรวจสอบจะคัดลอก input script ดึง UTXO ที่อินพุตอ้างถึง และคัดลอก output script จาก UTXO นั้น จากนั้น output script และ input script จะถูกประมวลผลรวมกัน อินพุตจะถูกพิจารณาว่าถูกต้องหาก input script ทำให้เงื่อนไขใน output script สำเร็จ (จะอธิบายในหัวข้อ Separate execution of output and input scripts) อินพุตทุกตัวจะถูกตรวจสอบแยกกันเป็นส่วนหนึ่งของการตรวจสอบธุรกรรมโดยรวม</p>
<p>โปรดสังเกตว่า ขั้นตอนข้างต้นเกี่ยวข้องกับการคัดลอกข้อมูลทั้งหมด ข้อมูลต้นฉบับในเอาต์พุตก่อนหน้าและในอินพุตปัจจุบันจะไม่ถูกเปลี่ยนแปลงเลย เอาต์พุตก่อนหน้าไม่ถูกเปลี่ยนแปลงและไม่ได้รับผลกระทบจากความพยายามใช้จ่ายที่ล้มเหลว มีเพียงธุรกรรมที่ถูกต้องซึ่งทำให้เงื่อนไขใน output script สำเร็จเท่านั้นที่จะทำให้เอาต์พุตถูกพิจารณาว่า “ถูกใช้จ่ายแล้ว”</p>
<p>การผสาน input script และ output script เพื่อประเมินสคริปต์ของธุรกรรม คือ ตัวอย่างของ output script และ input script ของธุรกรรม Bitcoin แบบดั้งเดิมที่พบมากที่สุด (การชำระเงินไปยัง public key hash) ซึ่งแสดงสคริปต์ที่รวมกันจากการนำทั้งสองสคริปต์มาต่อกันก่อนการตรวจสอบ</p>
<p> <img src="https://image.nostr.build/5be02a704fca95d54b831b0ae9a66e09ea4804b95dde7c25d75decb167b1d55c.jpg" alt="image"></p>
<h3>The script execution stack</h3>
<p>ภาษาสคริปต์ของ Bitcoin ถูกเรียกว่า stack-based language เพราะใช้โครงสร้างข้อมูลที่เรียกว่า stack สแตกเป็นโครงสร้างข้อมูลที่เรียบง่ายมาก มองภาพได้เหมือนกองไพ่ สแตกมีสองการทำงานพื้นฐาน: push และ pop push คือการเพิ่มข้อมูลหนึ่งรายการไว้ด้านบนของสแตก ส่วน pop คือการนำรายการด้านบนสุดออกจากสแตก</p>
<p>ภาษาสคริปต์จะรันสคริปต์โดยประมวลผลรายการแต่ละรายการจากซ้ายไปขวา ตัวเลข (ค่าคงที่ของข้อมูล) จะถูก push ลงบนสแตก ตัวโอเปอเรเตอร์จะ push หรือ pop พารามิเตอร์หนึ่งตัวหรือมากกว่าจากสแตก นำไปประมวลผล และอาจ push ผลลัพธ์กลับลงสแตก ตัวอย่างเช่น OP_ADD จะ pop ข้อมูลสองรายการออกจากสแตก นำมาบวกกัน แล้ว push ผลรวมกลับลงบนสแตก</p>
<p>โอเปอเรเตอร์แบบมีเงื่อนไขจะประเมินเงื่อนไขและให้ผลลัพธ์เป็น boolean TRUE หรือ FALSE ตัวอย่างเช่น OP_EQUAL จะ pop ข้อมูลสองรายการจากสแตก และ push TRUE (TRUE แทนด้วยเลข 1) หากสองค่านั้นเท่ากัน หรือ push FALSE (แทนด้วยเลข 0) หากไม่เท่ากัน สคริปต์ของธุรกรรม Bitcoin มักมีโอเปอเรเตอร์แบบมีเงื่อนไขเพื่อสร้างผลลัพธ์ TRUE ที่แสดงว่าธุรกรรมนั้นถูกต้อง</p>
<h3>A simple script (สคริปต์อย่างง่าย)</h3>
<p>ตอนนี้เรามาลองประยุกต์สิ่งที่เราได้เรียนรู้เกี่ยวกับ scripts และ stacks กับตัวอย่างง่าย ๆ กัน </p>
<p>ในบทก่อนหน้าเราได้ยกสคริปต์อย่างง่ายมาตัวหนึ่งคือ</p>
<pre><code>2 3 OP_ADD 5 OP_EQUAL
</code></pre>
<p>แสดงการทำงานของโอเปอเรเตอร์คณิตศาสตร์ OP_ADD ซึ่งทำการบวกตัวเลขสองตัวแล้ววางผลลัพธ์ไว้บนสแต็ก จากนั้นตามด้วยโอเปอเรเตอร์แบบเงื่อนไข OP_EQUAL ที่ตรวจสอบว่าผลรวมดังกล่าวเท่ากับ 5 หรือไม่ ในหนังสือเล่มนี้ เพื่อความกระชับ อาจมีการละคำนำหน้า OP_ ในบางตัวอย่าง หากต้องการรายละเอียดเพิ่มเติมเกี่ยวกับโอเปอเรเตอร์และฟังก์ชันทั้งหมดของสคริปต์ สามารถดูได้ที่หน้า Script ของ Bitcoin Wiki<br>แม้ว่าผลลัพธ์สคริปต์แบบ Legacy ส่วนใหญ่จะอ้างอิง public key hash (ซึ่งโดยพื้นฐานคือ Bitcoin address แบบดั้งเดิม) เพื่อบังคับให้ต้องพิสูจน์ความเป็นเจ้าของก่อนจึงจะใช้เงินได้ แต่จริง ๆ แล้วสคริปต์ไม่จำเป็นต้องซับซ้อนขนาดนั้นก็ได้ สคริปต์ใด ๆ ที่ผสมกันระหว่าง output script และ input script แล้วให้ผลเป็น TRUE ถือว่า “ถูกต้อง”ดังนั้นสคริปต์คณิตศาสตร์ง่าย ๆ อย่างที่ใช้เป็นตัวอย่างในที่นี้ ก็ถือว่าเป็นสคริปต์ที่ถูกต้องเช่นกัน</p>
<p>ใช้ส่วนหนึ่งของสคริปต์คณิตศาสตร์เป็น output script</p>
<p>ให้ output script เป็น:</p>
<pre><code>3 OP_ADD 5 OP_EQUAL
</code></pre>
<p>ซึ่งสามารถถูกทำให้สำเร็จ (satisfied) ด้วยธุรกรรมที่มี input script แบบนี้:</p>
<pre><code>2
</code></pre>
<p>ซอฟต์แวร์ตรวจสอบความถูกต้อง (validation software) จะรวมสองสคริปต์เข้าด้วยกันกลายเป็น:</p>
<pre><code>2 3 OP_ADD 5 OP_EQUAL
</code></pre>
<p>เมื่อสคริปต์นี้ถูกประมวลผล ตามที่เราเห็นในบทก่อนหน้า ผลลัพธ์สุดท้ายคือ OP_TRUE ทำให้ธุรกรรมนี้ “ถูกต้อง” แม้ว่านี่จะเป็น output script ที่ถูกต้อง แต่ให้สังเกตว่า UTXO ที่สร้างขึ้น สามารถถูกใช้จ่ายได้โดยใครก็ตาม ที่มีทักษะคณิตศาสตร์พอจะรู้ว่าเลข 2 จะทำให้สคริปต์นี้สำเร็จได้<br> <img src="https://image.nostr.build/277a418d6958becf1c914c6eecd0732585265acceed0e238e9258e464c280728.jpg" alt="image"></p>
<blockquote>
<p>TIP: ธุรกรรมจะถือว่า ถูกต้อง (valid) หากผลลัพธ์บนยอดสแต็กเป็นค่า TRUE ซึ่งหมายถึงค่าที่ไม่ใช่ศูนย์ใด ๆ ทั้งหมด ธุรกรรมจะถือว่า ไม่ถูกต้อง (invalid) หากผลบนยอดสแต็กเป็นค่า FALSE (ศูนย์ หรือสแต็กว่าง), หรือการประมวลผลสคริปต์ถูกหยุดโดยตรงด้วยโอเปอเรเตอร์บางตัว (เช่น VERIFY, OP_RETURN), หรือสคริปต์นั้นมีความผิดพลาดทางไวยากรณ์/ความหมาย (semantic) เช่น มีคำสั่ง OP_IF แต่ไม่มี OP_ENDIF ปิดท้าย ดูรายละเอียดเพิ่มเติมได้ที่หน้า Script ของ Bitcoin Wiki</p>
</blockquote>
<p>สคริปต์ตัวอย่างถัดไปนี้จะมีความซับซ้อนขึ้นเล็กน้อย โดยมันคำนวณค่า 2 + 7 – 3 + 1 สังเกตว่าเมื่อสคริปต์มีโอเปอเรเตอร์หลายตัวต่อกัน สแต็กจะทำให้ผลลัพธ์ของโอเปอเรเตอร์ก่อนหน้า ถูกนำไปใช้ต่อโดยโอเปอเรเตอร์ตัวถัดไปได้</p>
<pre><code>2 7 OP_ADD 3 OP_SUB 1 OP_ADD 7 OP_EQUAL
</code></pre>
<p>ลองตรวจสอบสคริปต์ก่อนหน้านี้ด้วยตัวเอง โดยใช้ดินสอและกระดาษ เมื่อการประมวลผลสคริปต์สิ้นสุดลง คุณควรจะเหลือค่าบนสแต็กเป็นค่า TRUE</p>
<h3>Separate execution of output and input scripts</h3>
<p>ในไคลเอนต์ Bitcoin เวอร์ชันแรก ๆ  นั้น สคริปต์ของ output และ input ถูกต่อกันแล้วประมวลผลเป็นลำดับเดียว ด้วยเหตุผลด้านความปลอดภัย ซึ่งเกิดจากช่องโหว่ที่รู้จักกันในชื่อ 1 OP_RETURN bug ซึ่งวิธีนี้ถูกเปลี่ยนแปลงในปี 2010 เพื่อความปลอดภัย ในการใช้งานปัจจุบัน สคริปต์ทั้งสองจะถูกประมวลผลแยกกันโดยมีการคัดลอกสแต็กไปยังการประมวลผลครั้งถัดไป</p>
<p>อันดับแรก สคริปต์ input จะถูกประมวลผลโดยการดำเนินการของสแต็ก (stack execution engine) หากสคริปต์ input ถูกประมวลผลโดยไม่มีข้อผิดพลาดและไม่มีโอเปอเรชันเหลืออยู่ สแต็กจะถูกคัดลอกแล้วสคริปต์ output จะถูกประมวลผลต่อ หากผลลัพธ์ของการประมวลผลสคริปต์ output โดยใช้ข้อมูลสแต็กที่คัดลอกมาจาก input เป็น TRUE แสดงว่าสคริปต์ input สามารถแก้เงื่อนไขที่สคริปต์ output กำหนดได้ และด้วยเหตุนี้ input จึงเป็นการอนุญาตที่ถูกต้องสำหรับการใช้จ่าย UTXO นั้น แต่หากผลลัพธ์ใด ๆ นอกเหนือจาก TRUE ยังคงอยู่หลังการประมวลผลของสคริปต์รวมกัน แสดงว่า input นั้นไม่ถูกต้องเพราะล้มเหลวในการตอบสนองเงื่อนไขการใช้จ่ายที่วางไว้บน output</p>
<h2>Pay to Public Key Hash</h2>
<p>สคริปต์แบบ pay to public key hash (P2PKH) ใช้ output script ที่ภายในมีค่าแฮชซึ่งผูกพัน (commit) กับ public key หนึ่งค่า P2PKH เป็นที่รู้จักกันดีที่สุดในฐานะ Legacy Bitcoin address เอาต์พุตแบบ P2PKH สามารถถูกใช้จ่ายได้โดยการนำเสนอ public key ที่ตรงกับค่าแฮชที่ระบุไว้ และลายเซ็นดิจิทัลที่สร้างขึ้นด้วย private key ที่สอดคล้องกัน (ดูเรื่องนี้เพิ่มได้ในบทถัดไป) ส่วนตอนนี้มาดูตัวอย่างของ P2PKH output script กัน:</p>
<pre><code>OP_DUP OP_HASH160 &lt;Key Hash&gt; OP_EQUALVERIFY OP_CHECKSIG
</code></pre>
<p>Key Hash คือข้อมูลที่เมื่อนำไปเข้ารหัส จะกลายเป็น Bitcoin address แบบ legacy ในรูปแบบ base58check แอปพลิเคชันส่วนใหญ่จะแสดงค่า public key hash ภายในสคริปต์ในรูปแบบเลขฐานสิบหก (hexadecimal) แทนที่จะเป็นรูปแบบ Bitcoin address แบบ base58check ที่ผู้ใช้คุ้นเคย ซึ่งจะขึ้นต้นด้วยตัวอักษร “1”<br>output script ก่อนหน้านี้สามารถถูกทำให้สำเร็จ (satisfied) ได้ด้วย input script ในรูปแบบ:</p>
<pre><code>&lt;Signature&gt; &lt;Public Key&gt;
</code></pre>
<p>เมื่อรวมสคริปต์ทั้งสองเข้าด้วยกัน จะได้สคริปต์ตรวจสอบความถูกต้อง (combined validation script) ดังนี้:</p>
<pre><code>&lt;Sig&gt; &lt;Pubkey&gt; OP_DUP OP_HASH160 &lt;Hash&gt; OP_EQUALVERIFY OP_CHECKSIG
</code></pre>
<p>ผลลัพธ์จะเป็นค่า TRUE หาก input script มีลายเซ็นที่ถูกต้อง ซึ่งถูกสร้างขึ้นจาก private key ของของผู้ส่ง และสอดคล้องกับ public key hash ที่ถูกกำหนดไว้เป็นเงื่อนไขการใช้จ่ายนั้น</p>
<p> <img src="https://image.nostr.build/53dda9b219893a6b51c0dbf4b96b4c5eda32f2c2cd62a8c77b13fbec2e6280dc.jpg" alt="image"><br> <img src="https://image.nostr.build/318690aac1933790ae7bd5600e90c2fa311383a30515d80d9b2f9e0ff99bbcd7.jpg" alt="image"></p>
<h2>Scripted Multisignatures</h2>
<p>สคริปต์แบบมัลติซิกเนเจอร์ (multisignature) กำหนดเงื่อนไขโดยบันทึกค่าของ public key จำนวน k ค่าไว้ในสคริปต์ และต้องมีลายเซ็นอย่างน้อย t ค่าจาก public key เหล่านั้นจึงจะสามารถใช้จ่ายเงินได้ เรียกรูปแบบนี้ว่า t-of-k ตัวอย่างเช่น 2-of-3 multisignature คือกรณีที่มีการระบุ public key ไว้ทั้งหมดสามค่าในฐานะผู้มีสิทธิ์ลงนาม และต้องใช้ลายเซ็นอย่างน้อยสองจากสามค่านั้น เพื่อสร้างธุรกรรมที่ถูกต้องสำหรับการใช้จ่ายเงิน</p>
<blockquote>
<p>TIP: เอกสารของบิตคอยน์บางแหล่ง รวมถึงหนังสือเล่มนี้ในฉบับก่อนหน้า ใช้คำว่า “m-of-n” เพื่อเรียกมัลติซิกเนเจอร์แบบดั้งเดิม อย่างไรก็ตาม เมื่อพูดออกเสียงแล้ว ตัวอักษร m และ n แยกออกจากกันได้ยาก จึงมีการเลือกใช้คำว่า t-of-k แทน ทั้งสองคำนี้หมายถึงรูปแบบของระบบลายเซ็นแบบเดียวกัน</p>
</blockquote>
<p>รูปแบบทั่วไปของ output script ที่กำหนดเงื่อนไขมัลติซิกเนเจอร์แบบ t-of-k มีดังนี้:</p>
<pre><code>t &lt;Public Key 1&gt; &lt;Public Key 2&gt; ... &lt;Public Key k&gt; k OP_CHECKMULTISIG
</code></pre>
<p>โดยที่ k คือจำนวน public key ทั้งหมดที่ระบุไว้ และ t คือจำนวนลายเซ็นขั้นต่ำที่ต้องใช้เพื่อสามารถใช้จ่าย output นั้นได้<br>output script ที่กำหนดเงื่อนไขมัลติซิกเนเจอร์แบบ 2-of-3 จะมีลักษณะดังนี้:</p>
<pre><code>2 &lt;Public Key A&gt; &lt;Public Key B&gt; &lt;Public Key C&gt; 3 OP_CHECKMULTISIG
</code></pre>
<p>output script ข้างต้นสามารถถูกทำให้สำเร็จได้ด้วย input script ที่มีลายเซ็น เช่น:</p>
<pre><code>&lt;Signature B&gt; &lt;Signature C&gt;
</code></pre>
<p>หรือจะเป็นชุดลายเซ็นสองชุดใดก็ได้ ที่มาจาก private key ที่สอดคล้องกับ public key ทั้งสามค่าที่ถูกระบุไว้</p>
<p>เมื่อรวมสคริปต์ทั้งสองเข้าด้วยกัน จะได้สคริปต์ตรวจสอบความถูกต้องดังนี้:</p>
<pre><code>&lt;Sig B&gt; &lt;Sig C&gt; 2 &lt;Pubkey A&gt; &lt;Pubkey B&gt; &lt;Pubkey C&gt; 3 OP_CHECKMULTISIG
</code></pre>
<p>เมื่อถูกประมวลผล สคริปต์ที่ถูกรวมกันนี้จะให้ผลลัพธ์เป็นค่า TRUE หาก input script มีลายเซ็นที่ถูกต้องจำนวนสองชุด ซึ่งมาจาก private key ที่สอดคล้องกับ public key สองค่าใดก็ได้ จากสามค่าที่ถูกกำหนดไว้เป็นเงื่อนไขการใช้จ่าย</p>
<p>ในปัจจุบัน นโยบายการส่งต่อธุรกรรม (transaction relay policy) ของ Bitcoin Core จำกัดจำนวน public key ใน multisignature output script ไว้สูงสุดที่สามค่า หมายความว่าสามารถสร้างมัลติซิกเนเจอร์ได้ตั้งแต่แบบ 1-of-1 ไปจนถึง 3-of-3 หรือรูปแบบใด ๆ ภายในช่วงนี้ คุณอาจต้องการตรวจสอบฟังก์ชัน IsStandard() เพื่อดูว่าขณะนี้เครือข่ายยอมรับรูปแบบใดบ้าง โปรดสังเกตว่า ข้อจำกัดที่สามคีย์นี้ใช้กับ multisignature script แบบมาตรฐานเท่านั้น (ซึ่งเรียกอีกชื่อหนึ่งว่า “bare” multisignature) ไม่ได้ใช้กับสคริปต์ที่ถูกห่อหุ้มด้วยโครงสร้างอื่น เช่น P2SH, P2WSH, หรือ P2TR สำหรับ multisignature script แบบ P2SH จะถูกจำกัดทั้งในระดับนโยบาย (policy) และฉันทามติ (consensus) ไว้ที่สูงสุด 15 คีย์ ทำให้สามารถสร้างมัลติซิกเนเจอร์ได้สูงสุดแบบ 15-of-15 เราจะเรียนรู้เกี่ยวกับ P2SH ในหัวข้อ Pay to Script Hash ส่วนสคริปต์รูปแบบอื่นทั้งหมด จะถูกจำกัดโดยฉันทามติไว้ที่ public key ได้ไม่เกิน 20 คีย์ ต่อคำสั่ง OP_CHECKMULTISIG หรือ OP_CHECKMULTISIGVERIFY หนึ่งคำสั่ง ทั้งนี้ สคริปต์หนึ่งรายการอาจมีคำสั่งเหล่านี้ได้มากกว่าหนึ่งครั้ง</p>
<h3>An Oddity in CHECKMULTISIG Execution</h3>
<p>มีความผิดปกติ (oddity) อย่างหนึ่งในการทำงานของ OP_CHECKMULTISIG ซึ่งทำให้ต้องมีวิธีแก้ไขเฉพาะหน้าเล็กน้อย เมื่อ OP_CHECKMULTISIG ถูกประมวลผล ตามหลักแล้วมันควรจะนำข้อมูลออกจากสแต็กมาใช้เป็นพารามิเตอร์จำนวน t + k + 2 ค่า อย่างไรก็ตาม เนื่องจากความผิดปกตินี้ OP_CHECKMULTISIG จะดึงค่าจากสแต็กออกมา มากกว่าที่คาดไว้หนึ่งค่า</p>
<p>เรามาดูรายละเอียดของเรื่องนี้ให้ชัดเจนขึ้น โดยใช้ตัวอย่างสคริปต์ตรวจสอบความถูกต้องจากก่อนหน้านี้:</p>
<pre><code>&lt;Sig B&gt; &lt;Sig C&gt; 2 &lt;Pubkey A&gt; &lt;Pubkey B&gt; &lt;Pubkey C&gt; 3 OP_CHECKMULTISIG
</code></pre>
<p>ขั้นแรก OP_CHECKMULTISIG จะนำค่าแรกบนสุดของสแต็กออกมา ซึ่งก็คือ k (ในตัวอย่างนี้คือ “3”) จากนั้นจะนำข้อมูลออกมาอีก k ค่า ซึ่งเป็น public key ที่สามารถใช้ลงนามได้ ในตัวอย่างนี้คือ public key A, B และ C จากนั้นมันจะนำค่าออกมาอีกหนึ่งค่า ซึ่งก็คือ t หรือจำนวนลายเซ็นขั้นต่ำที่ต้องใช้ (quorum) โดยในกรณีนี้ t = 2 ตามปกติแล้ว ณ จุดนี้ OP_CHECKMULTISIG ควรจะนำค่าออกมาอีก t ค่า ซึ่งเป็นลายเซ็น เพื่อตรวจสอบว่าถูกต้องหรือไม่ อย่างไรก็ตาม เนื่องจากความผิดปกติในการนำไปใช้งานจริง OP_CHECKMULTISIG จะนำค่าจากสแต็กออกมา มากกว่าที่ควรหนึ่งค่า (รวมเป็น t + 1 ค่า) ค่าส่วนเกินนี้ถูกเรียกว่า dummy stack element และจะถูกละเว้นในระหว่างการตรวจสอบลายเซ็น ดังนั้นมันจึงไม่มีผลโดยตรงต่อการทำงานของ OP_CHECKMULTISIG เอง อย่างไรก็ตาม dummy element นี้ จำเป็นต้องมีอยู่ เพราะหากไม่มีค่าเหลืออยู่บนสแต็กในขณะที่ OP_CHECKMULTISIG พยายามดึงค่าออกมาเพิ่ม จะทำให้เกิด stack error และสคริปต์ล้มเหลว ส่งผลให้ธุรกรรมนั้นไม่ถูกต้อง เนื่องจาก dummy element ถูกละเว้น ค่าของมันจึงสามารถเป็นค่าอะไรก็ได้ แต่ในช่วงแรกได้มีธรรมเนียมใช้ค่า OP_0 สำหรับตำแหน่งนี้ ต่อมาสิ่งนี้ได้กลายเป็นกฎของ relay policy และในที่สุดก็กลายเป็นกฎระดับฉันทามติ (consensus rule) เมื่อมีการบังคับใช้ BIP147</p>
<p>เนื่องจากการนำ dummy element ออกจากสแต็กเป็นส่วนหนึ่งของกฎฉันทามติ (consensus rules) พฤติกรรมนี้จึงต้องถูกคงไว้และทำซ้ำตลอดไป ดังนั้นสคริปต์จึงควรมีหน้าตาเป็นดังนี้:</p>
<pre><code>OP_0 &lt;Sig B&gt; &lt;Sig C&gt; 2 &lt;Pubkey A&gt; &lt;Pubkey B&gt; &lt;Pubkey C&gt; 3 OP_CHECKMULTISIG
</code></pre>
<p>ด้วยเหตุนี้ input script ที่ถูกใช้งานจริงใน multisignature จะ ไม่ใช่:</p>
<pre><code>&lt;Signature B&gt; &lt;Signature C&gt;
</code></pre>
<p>แต่จะต้องเป็น:</p>
<pre><code>OP_0 &lt;Sig B&gt; &lt;Sig C&gt;
</code></pre>
<p>บางคนเชื่อว่าความผิดปกตินี้เกิดจากบั๊กในโค้ดต้นฉบับของบิตคอยน์ แต่อย่างไรก็ตาม ยังมีคำอธิบายทางเลือกที่สมเหตุสมผลอยู่ การตรวจสอบลายเซ็นแบบ t-of-k อาจต้องใช้การตรวจสอบลายเซ็นมากกว่าทั้งค่า t หรือ k เพียงอย่างเดียว</p>
<p>ลองพิจารณาตัวอย่างง่าย ๆ แบบ 1-in-5 โดยมีสคริปต์ตรวจสอบความถูกต้องที่ถูกรวมกันดังนี้:</p>
<pre><code>&lt;dummy&gt; &lt;Sig4&gt; 1 &lt;key0&gt; &lt;key1&gt; &lt;key2&gt; &lt;key3&gt; &lt;key4&gt; 5 OP_CHECKMULTISIG
</code></pre>
<p>ลายเซ็นจะถูกตรวจสอบกับ key0 ก่อน จากนั้นกับ key1 และต่อเนื่องไปยัง key อื่น ๆ จนกระทั่งในที่สุดจึงถูกนำไปเปรียบเทียบกับ public key ที่สอดคล้องกันจริง ๆ คือ key4 นั่นหมายความว่า จำเป็นต้องมีการตรวจสอบลายเซ็นถึง ห้าครั้ง ทั้งที่มีลายเซ็นเพียงหนึ่งรายการเท่านั้น แนวทางหนึ่งในการลดความซ้ำซ้อนนี้ คือให้ OP_CHECKMULTISIG รับข้อมูลในลักษณะเป็น map ที่ระบุว่าแต่ละลายเซ็นที่ส่งเข้ามาสัมพันธ์กับ public key ใด ซึ่งจะทำให้ OP_CHECKMULTISIG ต้องทำการตรวจสอบลายเซ็นเพียง t ครั้ง เท่านั้น จึงเป็นไปได้ว่า นักพัฒนาของบิตคอยน์ได้เพิ่มองค์ประกอบพิเศษนี้เข้าไปตั้งแต่เวอร์ชันแรก (ซึ่งปัจจุบันเราเรียกว่า dummy stack element) เพื่อเปิดทางให้สามารถเพิ่มความสามารถดังกล่าวผ่าน soft fork ในอนาคตได้ อย่างไรก็ตาม ฟีเจอร์ดังกล่าวไม่เคยถูกนำมาใช้งานจริง และการอัปเดตกฎฉันทามติด้วย BIP147 ในปี 2017 ก็ทำให้ไม่สามารถเพิ่มฟีเจอร์นี้ได้อีกต่อไปในอนาคต </p>
<p>มีเพียงนักพัฒนาของบิตคอยน์เท่านั้น ที่จะสามารถบอกได้ว่าการมีอยู่ของ dummy stack element นั้นเกิดจากบั๊ก หรือเป็นการวางแผนสำหรับการอัปเกรดในอนาคต สำหรับหนังสือเล่มนี้ เราเรียกสิ่งนี้เพียงว่าเป็น “ความผิดปกติ” (oddity) </p>
<p>นับจากนี้เป็นต้นไป หากคุณเห็นสคริปต์แบบ multisignature ให้คาดไว้เลยว่าจะต้องมี OP_0 เพิ่มเข้ามาในตอนต้น โดยจุดประสงค์เดียวของมันคือการเป็นวิธีแก้ปัญหาเฉพาะหน้า สำหรับความผิดปกติที่มีอยู่ในกฎฉันทามติ</p>
<h2>Pay to Script Hash</h2>
<p>Pay to Script Hash (P2SH) ถูกนำมาใช้ในปี 2012 ในฐานะรูปแบบการทำงานแบบใหม่ที่ทรงพลัง ซึ่งช่วยทำให้การใช้งานสคริปต์ที่ซับซ้อนเป็นเรื่องง่ายขึ้นอย่างมาก เพื่ออธิบายความจำเป็นของ P2SH เรามาดูตัวอย่างเชิงปฏิบัติกัน</p>
<p>โมฮัมเหม็ดเป็นผู้นำเข้าอุปกรณ์อิเล็กทรอนิกส์ซึ่งตั้งอยู่ในดูไบ บริษัทของโมฮัมเหม็ดใช้ฟีเจอร์มัลติซิกเนเจอร์ของบิตคอยน์อย่างแพร่หลายสำหรับบัญชีขององค์กร สคริปต์มัลติซิกเนเจอร์เป็นหนึ่งในการใช้งานความสามารถด้านสคริปต์ขั้นสูงของบิตคอยน์ที่พบได้บ่อยที่สุด และเป็นฟีเจอร์ที่ทรงพลังมาก บริษัทของโมฮัมเหม็ดใช้สคริปต์มัลติซิกเนเจอร์กับการชำระเงินจากลูกค้าทุกราย การชำระเงินของลูกค้าจะถูกล็อกไว้ในลักษณะที่ต้องใช้ลายเซ็นอย่างน้อยสองชุดจึงจะสามารถปลดล็อกได้ โมฮัมเหม็ด หุ้นส่วนอีกสามคนของเขา และทนายความของบริษัท ต่างสามารถให้ลายเซ็นได้คนละหนึ่งชุด รูปแบบมัลติซิกเนเจอร์เช่นนี้ช่วยสร้างกลไกกำกับดูแลกิจการ และป้องกันการโจรกรรม การยักยอก หรือการสูญหายของเงินได้</p>
<p>สคริปต์ที่ได้จากเงื่อนไขดังกล่าวจะค่อนข้างยาว และมีลักษณะดังนี้:</p>
<pre><code>2 &lt;Mohammed's Public Key&gt; &lt;Partner1 Public Key&gt; &lt;Partner2 Public Key&gt;
&lt;Partner3 Public Key&gt; &lt;Attorney Public Key&gt; 5 OP_CHECKMULTISIG
</code></pre>
<p>แม้ว่าสคริปต์แบบมัลติซิกเนเจอร์จะเป็นฟีเจอร์ที่ทรงพลังมาก แต่ก็ใช้งานได้ค่อนข้างยุ่งยาก จากสคริปต์ตัวอย่างก่อนหน้า โมฮัมเหม็ดจะต้องสื่อสารสคริปต์นี้ให้ลูกค้าทุกรายทราบก่อนทำการชำระเงิน ลูกค้าแต่ละรายยังจำเป็นต้องใช้ซอฟต์แวร์กระเป๋าเงินบิตคอยน์แบบพิเศษ ที่สามารถสร้างสคริปต์ธุรกรรมแบบกำหนดเองได้ นอกจากนี้ ธุรกรรมที่ได้จะมีขนาดใหญ่กว่าธุรกรรมการชำระเงินแบบธรรมดาประมาณห้าเท่า เนื่องจากสคริปต์นี้มี public key ที่มีความยาวมาก ภาระของข้อมูลส่วนเกินนี้จะตกอยู่กับลูกค้าในรูปของค่าธรรมเนียมธุรกรรมที่สูงขึ้น สุดท้ายแล้ว สคริปต์ธุรกรรมขนาดใหญ่เช่นนี้จะถูกเก็บไว้ในชุดข้อมูล UTXO set ของทุก full node จนกว่าจะถูกใช้จ่าย ซึ่งปัญหาเหล่านี้ทั้งหมดทำให้การใช้งาน output script ที่ซับซ้อนเป็นเรื่องยากในทางปฏิบัติ</p>
<p>P2SH ถูกพัฒนาขึ้นมาเพื่อแก้ไขปัญหาเชิงปฏิบัติเหล่านี้ และเพื่อทำให้การใช้งานสคริปต์ที่ซับซ้อนง่ายพอ ๆ กับการชำระเงินไปยัง Bitcoin address แบบกุญแจเดียว ด้วยการชำระเงินแบบ P2SH สคริปต์ที่ซับซ้อนจะถูกแทนที่ด้วย “คำมั่น” (commitment) ซึ่งก็คือค่าแฮชเชิงคริปโตกราฟีของสคริปต์นั้น เมื่อมีการนำเสนอธุรกรรมเพื่อใช้จ่าย UTXO ในภายหลัง ธุรกรรมนั้นจะต้องมีทั้งสคริปต์ที่ตรงกับค่าแฮชที่ถูกผูกไว้ และข้อมูลที่ใช้ทำให้สคริปต์ดังกล่าวสำเร็จ กล่าวอย่างง่ายที่สุด P2SH หมายถึง “จ่ายเงินให้กับสคริปต์ที่ตรงกับค่าแฮชนี้ โดยสคริปต์นั้นจะถูกนำมาแสดงในภายหลังเมื่อ output นี้ถูกใช้จ่าย”</p>
<p>ในธุรกรรมแบบ P2SH สคริปต์ที่ถูกแทนที่ด้วยค่าแฮชจะถูกเรียกว่า redeem script เนื่องจากสคริปต์นี้จะถูกนำเสนอให้ระบบในช่วงเวลาที่มีการนำมาใช้จ่าย (redeem) แทนที่จะถูกใส่ไว้เป็น output script ตั้งแต่ต้นตารางด้านล่างจะ แสดงสคริปต์ในกรณีที่ไม่ใช้ P2SH และแสดงสคริปต์เดียวกันที่ถูกเข้ารหัสในรูปแบบ P2SH</p>
<p>Complex script without P2SH</p>
<table>
<thead>
<tr>
<th align="left">Output script</th>
<th align="left">2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 OP_CHECKMULTISIG</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Input script</td>
<td align="left">Sig1 Sig2</td>
</tr>
</tbody></table>
<p>Complex script as P2SH</p>
<table>
<thead>
<tr>
<th align="left">Redeem script</th>
<th align="left">2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 OP_CHECKMULTISIG</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Output script</td>
<td align="left">OP_HASH160 &lt;20-byte hash of redeem script&gt; OP_EQUAL</td>
</tr>
<tr>
<td align="left">Input script</td>
<td align="left">Sig1 Sig2 &lt;redeem script&gt;</td>
</tr>
</tbody></table>
<p>ดังที่เห็นได้จากตาราง เมื่อใช้ P2SH สคริปต์ที่ซับซ้อนซึ่งระบุเงื่อนไขในการใช้จ่าย output (redeem script) จะไม่ถูกนำมาใส่ไว้ใน output script อีกต่อไป แต่จะมีเพียงค่าแฮชของสคริปต์นั้นอยู่ใน output script เท่านั้น ส่วนตัว redeem script เองจะถูกนำมาแสดงภายหลังในฐานะส่วนหนึ่งของ input script เมื่อมีการใช้จ่าย output นั้นแนวทางนี้ทำให้ภาระในด้านค่าธรรมเนียมและความซับซ้อน ถูกย้ายจากฝั่งผู้รับเงิน ไปยังฝั่งผู้ใช้จ่ายเงินในภายหลังเรามาดูกรณีของบริษัทโมฮัมเหม็ด สคริปต์มัลติซิกเนเจอร์ที่ซับซ้อน และสคริปต์ P2SH ที่ได้จากมันกัน อันดับแรก คือสคริปต์มัลติซิกเนเจอร์ที่บริษัทของโมฮัมเหม็ดใช้สำหรับการรับชำระเงินจากลูกค้าทุกราย:</p>
<pre><code>2 &lt;Mohammed's Public Key&gt; &lt;Partner1 Public Key&gt; &lt;Partner2 Public Key&gt;
&lt;Partner3 Public Key&gt; &lt;Attorney Public Key&gt; 5 OP_CHECKMULTISIG
</code></pre>
<p>สคริปต์ทั้งหมดนี้สามารถถูกแทนที่ด้วยค่าแฮชเชิงคริปโตกราฟีขนาด 20 ไบต์ ได้ โดยเริ่มจากการนำสคริปต์ไปผ่านอัลกอริทึมแฮช SHA256 ก่อน จากนั้นจึงนำผลลัพธ์ที่ได้ไปแฮชต่อด้วยอัลกอริทึม RIPEMD-160 ตัวอย่างเช่น เริ่มต้นด้วยค่าแฮชของ redeem script ของบริษัทโมฮัมเหม็ด:</p>
<pre><code>54c557e07dde5bb6cb791c7a540e0a4796f5e97e
</code></pre>
<p>ธุรกรรมแบบ P2SH จะล็อก output ไว้กับค่าแฮชนี้ แทนที่จะใช้ redeem script ที่ยาวกว่า โดยใช้แม่แบบ output script แบบพิเศษดังนี้:</p>
<pre><code>OP_HASH160 54c557e07dde5bb6cb791c7a540e0a4796f5e97e OP_EQUAL
</code></pre>
<p>ซึ่งอย่างที่เห็น จะสั้นกว่ามาก แทนที่จะเป็น “จ่ายไปยังสคริปต์มัลติซิกเนเจอร์ที่มี 5 คีย์นี้” ธุรกรรมแบบ P2SH จะกลายเป็น “จ่ายไปยังสคริปต์ที่มีค่าแฮชนี้” ลูกค้าที่ชำระเงินให้บริษัทของโมฮัมเหม็ด จำเป็นต้องใส่เพียง output script ที่สั้นกว่านี้ลงในธุรกรรมเท่านั้น</p>
<p>เมื่อโมฮัมเหม็ดและหุ้นส่วนต้องการใช้จ่าย UTXO นี้ พวกเขาจะต้องแสดง redeem script ต้นฉบับ (ซึ่งเป็นสคริปต์ที่ค่าแฮชของมันถูกใช้ล็อก UTXO ไว้) พร้อมกับลายเซ็นที่จำเป็นเพื่อปลดล็อกสคริปต์นั้น ดังนี้:</p>
<pre><code>&lt;Sig1&gt; &lt;Sig2&gt; &lt;2 PK1 PK2 PK3 PK4 PK5 5 OP_CHECKMULTISIG&gt;
</code></pre>
<p>สคริปต์ทั้งสองจะถูกรวมกันเป็นสองขั้นตอน ขั้นแรก redeem script จะถูกตรวจสอบกับ output script เพื่อยืนยันว่าค่าแฮชตรงกัน:</p>
<pre><code>&lt;2 PK1 PK2 PK3 PK4 PK5 5 OP_CHECKMULTISIG&gt; OP_HASH160 &lt;script hash&gt; OP_EQUAL
</code></pre>
<p>หากค่าแฮชของ redeem script ตรงกัน จากนั้น redeem script จะถูกนำมาประมวลผล:</p>
<pre><code>&lt;Sig1&gt; &lt;Sig2&gt; 2 &lt;PK1&gt; &lt;PK2&gt; &lt;PK3&gt; &lt;PK4&gt; &lt;PK5&gt; 5 OP_CHECKMULTISIG
</code></pre>
<h3>P2SH Addresses</h3>
<p>อีกส่วนสำคัญของฟีเจอร์ P2SH คือความสามารถในการเข้ารหัสค่าแฮชของสคริปต์ให้อยู่ในรูปของ “address” ตามที่กำหนดไว้ใน BIP13 ที่อยู่แบบ P2SH คือการเข้ารหัสแบบ base58check ของค่าแฮชขนาด 20 ไบต์ของสคริปต์ เช่นเดียวกับที่ Bitcoin address ปกติคือการเข้ารหัสแบบ base58check ของค่าแฮชขนาด 20 ไบต์ของ public key ที่อยู่แบบ P2SH ใช้ version prefix เป็น “5” ซึ่งทำให้ที่อยู่ที่ถูกเข้ารหัสออกมาในรูป base58check เริ่มต้นด้วยตัวเลข “3”</p>
<p>ตัวอย่างเช่น สคริปต์ที่ซับซ้อนของบริษัทโมฮัมเหม็ด เมื่อนำไปแฮชและเข้ารหัสแบบ base58check เป็นที่อยู่ P2SH จะได้เป็น:</p>
<pre><code>39RF6JqABiHdYHkfChV6USGMe6Nsr66Gzw
</code></pre>
<p>จากนี้ไป โมฮัมเหม็ดสามารถให้ “address” นี้กับลูกค้าได้ และลูกค้าก็สามารถใช้กระเป๋าเงินบิตคอยน์ทั่วไปแทบทุกแบบ เพื่อทำการชำระเงินอย่างง่าย ๆ ได้ เหมือนกับการจ่ายไปยัง Bitcoin address ปกติทั่วไป ตัวเลขนำหน้า 3 จะช่วยบอกใบ้ให้ทราบว่านี่คือที่อยู่แบบพิเศษ ซึ่งเชื่อมโยงกับสคริปต์ ไม่ใช่กับ public key โดยตรง แต่ในแง่ของการใช้งานแล้ว มันทำงานเหมือนกับการชำระเงินไปยัง Bitcoin address อื่น ๆ ทุกประการ ที่อยู่แบบ </p>
<p>P2SH ช่วยซ่อนความซับซ้อนทั้งหมดเอาไว้ ทำให้ผู้ที่ทำการชำระเงินไม่จำเป็นต้องเห็นหรือเข้าใจสคริปต์เลย</p>
<h3>Benefits of P2SH</h3>
<p>ฟีเจอร์ P2SH มีข้อดีเมื่อเทียบกับการใช้งานสคริปต์ที่ซับซ้อนโดยตรงใน output ดังนี้:</p>
<ul>
<li><p>ความคล้ายคลึงกับ Bitcoin address แบบ legacy เดิม ทำให้ผู้ส่งและซอฟต์แวร์กระเป๋าเงินของผู้ส่ง ไม่จำเป็นต้องมีการออกแบบหรือพัฒนาเพิ่มเติมที่ซับซ้อนเพื่อรองรับ P2SH</p>
</li>
<li><p>P2SH ย้ายภาระในการจัดเก็บข้อมูลของสคริปต์ที่ยาว จากฝั่ง output (ซึ่งนอกจากจะถูกเก็บไว้บนบล็อกเชนแล้ว ยังอยู่ในชุดข้อมูล UTXO set ด้วย) ไปอยู่ที่ฝั่ง input (ซึ่งจะถูกเก็บไว้บนบล็อกเชนเท่านั้น)</p>
</li>
<li><p>P2SH ย้ายภาระในการจัดเก็บข้อมูลของสคริปต์ที่ยาว จากช่วงเวลาปัจจุบันขณะชำระเงิน ไปยังช่วงเวลาในอนาคตเมื่อมีการนำ output นั้นมาใช้จ่าย</p>
</li>
<li><p>P2SH ย้ายภาระค่าธรรมเนียมธุรกรรมที่เกิดจากสคริปต์ยาว จากผู้ส่ง ไปยังผู้รับ ซึ่งเป็นฝ่ายที่ต้องใส่ redeem script ที่ยาวลงไปเมื่อทำการใช้จ่าย</p>
</li>
</ul>
<h3>Redeem Script and Validation</h3>
<p>คุณไม่สามารถใส่ P2SH ซ้อนอยู่ภายใน redeem script ของ P2SH ได้ เนื่องจากข้อกำหนดของ P2SH ไม่ได้รองรับการทำงานแบบเรียกซ้ำ (recursive) นอกจากนี้ แม้ในเชิงเทคนิคจะสามารถใส่ OP_RETURN (ดูหัวข้อ Data Recording Output (OP_RETURN)) ลงไปใน redeem script ได้ เพราะกฎไม่ได้ห้ามไว้ แต่ในทางปฏิบัติกลับไม่มีประโยชน์ใด ๆ เนื่องจากเมื่อมีการประมวลผล OP_RETURN ระหว่างขั้นตอนการตรวจสอบความถูกต้อง ธุรกรรมจะถูกตัดสินว่าไม่ถูกต้องทันที</p>
<p>โปรดสังเกตว่า เนื่องจาก redeem script จะไม่ถูกเผยแพร่ให้เครือข่ายทราบจนกว่าจะมีการพยายามใช้จ่าย P2SH output หากคุณสร้าง output ด้วยค่าแฮชของ redeem script ที่ไม่ถูกต้อง คุณจะไม่สามารถใช้จ่ายมันได้เลย ธุรกรรมที่พยายามใช้จ่าย ซึ่งต้องแนบ redeem script เข้ามาด้วย จะไม่ถูกยอมรับ เนื่องจากสคริปต์นั้นไม่ถูกต้อง สิ่งนี้ก่อให้เกิดความเสี่ยง เพราะเป็นไปได้ที่จะส่งบิตคอยน์ไปยัง P2SH address ที่ไม่สามารถถูกใช้จ่ายได้ในภายหลัง</p>
<blockquote>
<p>คำเตือน: output script แบบ P2SH จะบรรจุเพียงค่าแฮชของ redeem script เท่านั้น ซึ่งไม่ได้ให้ข้อมูลใด ๆ เกี่ยวกับเนื้อหาของ redeem script เลย ดังนั้น P2SH output จะยังคงถูกถือว่าถูกต้องและถูกรับรอง แม้ว่า redeem script ที่ถูกอ้างถึงนั้นจะไม่ถูกต้องก็ตาม ด้วยเหตุนี้เองที่จะทำให้คุณอาจเผลอได้รับบิตคอยน์ในรูปแบบที่ไม่สามารถนำไปใช้จ่ายได้ในภายหลัง</p>
</blockquote>
<h3>Data Recording Output (OP_RETURN)</h3>
<p>บิตคอยน์มีบล็อกเชนกระจายศูนย์ที่มีการประทับเวลา (timestamped blockchain) ซึ่งมีศักยภาพในการนำไปใช้มากกว่าการชำระเงิน หลายคนพยายามใช้ภาษาสคริปต์ของธุรกรรมเพื่อใช้ประโยชน์จากความปลอดภัยและความทนทานของระบบสำหรับแอปพลิเคชันอื่น เช่น บริการทนายความดิจิทัล (digital notary services) ความพยายามในช่วงแรก ๆ เพื่อใช้สคริปต์ของบิตคอยน์ในลักษณะนี้เกี่ยวข้องกับการสร้าง transaction output ที่บันทึกข้อมูลลงบนบล็อกเชน เช่น การบันทึก commitment ต่อไฟล์หนึ่งไฟล์ เพื่อให้ใครก็ตามสามารถตรวจสอบการมีอยู่จริงของไฟล์นั้น ณ วันที่หนึ่งได้ โดยอ้างอิงจากธุรกรรมนั้น</p>
<p>การใช้บล็อกเชนของบิตคอยน์เพื่อเก็บข้อมูลที่ไม่เกี่ยวข้องกับการชำระเงินเป็นประเด็นที่ถกเถียงกัน หลายคนมองว่าเป็นการใช้งานที่ไม่เหมาะสมและควรถูกขัดขวาง ขณะที่อีกกลุ่มมองว่าเป็นตัวอย่างของความสามารถทรงพลังของเทคโนโลยีบล็อกเชนและควรสนับสนุนการทดลองเช่นนี้ ผู้คัดค้านให้เหตุผลว่าการบรรจุข้อมูลเหล่านี้ทำให้ผู้ที่รันฟูลโหนดต้องแบกรับต้นทุนพื้นที่จัดเก็บข้อมูลที่ไม่ใช่สิ่งที่บล็อกเชนถูกออกแบบมาเพื่อรองรับ นอกจากนี้ ธุรกรรมลักษณะนี้ยังอาจสร้าง UTXO ที่ไม่สามารถใช้จ่ายได้ โดยใช้ legacy Bitcoin address เป็นพื้นที่ข้อมูลขนาด 20 ไบต์ เพราะแอดเดรสนั้นถูกใช้เป็นข้อมูลและไม่สอดคล้องกับกุญแจส่วนตัว UTXO ที่เกิดขึ้นจึงไม่มีวันถูกใช้จ่ายได้ และเป็น "ธุรกรรมปลอม" ซึ่งจะไม่ถูกลบออกจาก UTXO set ทำให้ฐานข้อมูล UTXO โตขึ้นเรื่อย ๆ หรือที่เรียกว่า "bloat"</p>
<p>โดยในที่สุดก็ได้มีการประนีประนอมโดยอนุญาตให้ output script ที่เริ่มต้นด้วย OP_RETURN สามารถเพิ่มข้อมูลที่ไม่เกี่ยวกับการชำระเงินลงใน transaction output ได้ อย่างไรก็ตาม แตกต่างจาก UTXO ปลอม OP_RETURN จะสร้างเอาต์พุตที่พิสูจน์ได้อย่างชัดเจนว่าไม่สามารถใช้จ่ายได้ ทำให้ไม่จำเป็นต้องถูกเก็บไว้ใน UTXO set เอาต์พุตที่มี OP_RETURN จะถูกบันทึกลงในบล็อกเชน ดังนั้นจึงใช้พื้นที่ดิสก์และเพิ่มขนาดบล็อกเชน แต่จะไม่ถูกเก็บใน UTXO set และจึงไม่ทำให้ Full node ต้องแบกรับต้นทุนฐานข้อมูลที่แพงขึ้น</p>
<p>OP_RETURN scripts จะมีรูปแบบประมาณนี้:</p>
<pre><code>OP_RETURN &lt;data&gt;
</code></pre>
<p>ส่วนข้อมูล (data portion) มักใช้แทนค่าแฮช เช่น เอาต์พุตจากอัลกอริทึม SHA256 ซึ่งมีขนาด 32 ไบต์ แอปพลิเคชันบางประเภทจะใส่คำนำหน้า (prefix) ไว้หน้าข้อมูล เพื่อช่วยระบุว่าเป็นข้อมูลของแอปพลิเคชันใด ตัวอย่างเช่น บริการรับรองเอกสารดิจิทัล Proof of Existence ใช้คำนำหน้าขนาด 8 ไบต์คือคำว่า DOCPROOF ซึ่งเข้ารหัสแบบ ASCII และแสดงในรูปเลขฐานสิบหกเป็น 44 4f 43 50 52 4f 4f 46</p>
<p>ควรทำความเข้าใจว่าไม่มี input script ใดที่สามารถสอดคล้องกับ OP_RETURN เพื่อนำมา “ใช้จ่าย” (spend) เอาต์พุตแบบ OP_RETURN ได้ จุดประสงค์ทั้งหมดของ OP_RETURN คือการสร้างเอาต์พุตที่ไม่สามารถใช้จ่ายได้ตั้งแต่ต้น ดังนั้นจึงไม่จำเป็นต้องถูกเก็บไว้ใน UTXO set ในฐานะเอาต์พุตที่อาจถูกใช้จ่ายในอนาคต กล่าวได้ว่า OP_RETURN outputs เป็นเอาต์พุตที่พิสูจน์ได้ชัดเจนว่าไม่สามารถใช้จ่ายได้ (provably unspendable)</p>
<p>โดยทั่วไป OP_RETURN outputs จะกำหนดจำนวนบิตคอยน์เป็นศูนย์ เพราะบิตคอยน์ใด ๆ ที่ถูกกำหนดไว้ในเอาต์พุตลักษณะนี้ จะถือว่าสูญหายไปตลอดกาล หากมีการอ้างอิง OP_RETURN output มาเป็น input ของธุรกรรมใด ธุรกรรมนั้นจะถูกเครื่องยนต์ตรวจสอบสคริปต์ (script validation engine) ยุติการทำงานทันทีและถูกตัดสินว่าไม่ถูกต้อง การทำงานของ OP_RETURN จะทำให้สคริปต์ “คืนค่า” FALSE และหยุดการประมวลผล ดังนั้น หากอ้างอิง OP_RETURN output มาเป็น input โดยไม่ตั้งใจ ธุรกรรมนั้นจะเป็นธุรกรรมที่ไม่ถูกต้องทันที</p>
<h2>ข้อจำกัดของ Transaction Lock Time</h2>
<p>การใช้ค่า lock time ทำให้ผู้ใช้จ่ายสามารถกำหนดเงื่อนไขได้ว่าธุรกรรมจะยังไม่ถูกนำไปรวมอยู่ในบล็อกจนกว่าจะถึงความสูงของบล็อก (block height) หรือเวลาที่กำหนดไว้ แต่ ไม่ได้ ป้องกันไม่ให้เงินก้อนนั้นถูกนำไปใช้จ่ายผ่านธุรกรรมอื่นก่อนหน้านั้น อธิบายด้วยตัวอย่างต่อไปนี้</p>
<p>Alice ลงนามในธุรกรรมที่ใช้จ่ายเอาต์พุตหนึ่งของเธอไปยังที่อยู่ของ Bob และตั้งค่า transaction lock time ไว้ล่วงหน้า 3 เดือน จากนั้น Alice ส่งธุรกรรมนั้นให้ Bob เก็บไว้ เมื่อเป็นเช่นนี้ Alice และ Bob จะทราบว่า:</p>
<ul>
<li>Bob ไม่สามารถกระจาย (broadcast) ธุรกรรมนี้เพื่อรับเงินได้ จนกว่าจะครบกำหนด 3 เดือน  </li>
<li>Bob สามารถกระจายธุรกรรมนี้ได้หลังจากครบ 3 เดือนแล้ว</li>
</ul>
<p>อย่างไรก็ตาม:</p>
<ul>
<li>Alice สามารถสร้างธุรกรรมอีกชุดที่ขัดแย้งกัน โดยใช้จ่ายอินพุตเดียวกันแต่ไม่ใส่ค่า lock time ซึ่งหมายความว่า Alice สามารถใช้จ่าย UTXO เดียวกันได้ก่อนครบ 3 เดือน  </li>
<li>Bob จึงไม่มีหลักประกันใด ๆ ว่า Alice จะไม่ทำเช่นนั้น</li>
</ul>
<p>สิ่งสำคัญคือ ต้องเข้าใจข้อจำกัดของ transaction lock time ให้ชัดเจน เงื่อนไขเพียงอย่างเดียวที่รับประกันได้คือ Bob จะไม่สามารถนำธุรกรรมที่ลงนามล่วงหน้าไปใช้ก่อนครบ 3 เดือนได้ แต่ ไม่มีการรับประกันว่า Bob จะได้รับเงินก้อนนั้นจริง หากต้องการให้ Bob ได้รับเงินอย่างแน่นอน แต่ไม่สามารถใช้จ่ายได้จนกว่าจะครบ 3 เดือน ต้องกำหนดเงื่อนไข timelock ไว้บนตัว UTXO เองในสคริปต์ แทนที่จะกำหนดไว้ในธุรกรรม ซึ่งทำได้ด้วยรูปแบบของ timelock ถัดไปที่เรียกว่า Check Lock Time Verify (CLTV)</p>
<h2>Check Lock Time Verify (OP_CLTV)</h2>
<p>ในเดือนธันวาคม ค.ศ. 2015 ได้มีการเพิ่มรูปแบบของ timelock แบบใหม่เข้ามาในบิตคอยน์ผ่านการอัปเกรดแบบ soft fork โดยอ้างอิงตามข้อกำหนดใน BIP65 มีการเพิ่มคำสั่งสคริปต์ใหม่ที่ชื่อว่า OP_CHECKLOCKTIMEVERIFY (OP_CLTV) เข้าไปในภาษา scripting ของบิตคอยน์ OP_CLTV เป็น timelock ระดับเอาต์พุต (per-output timelock) แตกต่างจาก lock time แบบเดิมซึ่งเป็น timelock ระดับธุรกรรม (per-transaction timelock) ทำให้สามารถกำหนดเงื่อนไขด้านเวลาได้ยืดหยุ่นมากยิ่งขึ้น</p>
<p>กล่าวโดยสรุป เมื่อมีการใส่ opcode OP_CLTV ลงไปในเอาต์พุต เอาต์พุตนั้นจะถูกจำกัดไม่ให้สามารถใช้จ่ายได้จนกว่าจะถึงเวลาที่กำหนดไว้</p>
<p>OP_CLTV ไม่ได้มาแทนที่ lock time แต่ทำหน้าที่จำกัด UTXO เฉพาะรายการ ให้สามารถถูกใช้จ่ายได้ก็ต่อเมื่อธุรกรรมที่จะนำมาใช้จ่ายนั้นมีค่า lock time ที่ตั้งไว้มากกว่าหรือเท่ากับค่าที่กำหนดใน OP_CLTV</p>
<p>คำสั่ง OP_CLTV รับพารามิเตอร์หนึ่งค่าเป็นอินพุต ซึ่งแสดงเป็นตัวเลขในรูปแบบเดียวกับ lock time (อาจเป็นความสูงของบล็อก หรือเวลา Unix epoch) และตามที่คำว่า VERIFY ระบุไว้ OP_CLTV เป็น opcode ประเภทที่หากผลลัพธ์เป็น FALSE จะหยุดการทำงานของสคริปต์ทันที แต่ถ้าผลลัพธ์เป็น TRUE สคริปต์จะทำงานต่อไป</p>
<p>ในการใช้งาน OP_CLTV จะต้องใส่คำสั่งนี้ไว้ใน redeem script ของเอาต์พุตในธุรกรรมที่สร้างเอาต์พุตนั้นขึ้นมา ตัวอย่างเช่น หากอลิซต้องการจ่ายเงินให้บ็อบ ปกติบ็อบอาจยอมรับการจ่ายเงินผ่านสคริปต์ P2SH ลักษณะดังนี้</p>
<pre><code>&lt;Bob's public key&gt; OP_CHECKSIG
</code></pre>
<p>เพื่อทำการล็อกเอาต์พุตไว้จนถึงเวลาที่กำหนด เช่น อีก 3 เดือนนับจากนี้ สคริปต์ P2SH ของบ็อบจะถูกเปลี่ยนเป็นแบบนี้แทน:</p>
<pre><code>&lt;Bob's pubkey&gt; OP_CHECKSIGVERIFY &lt;now + 3 months&gt; OP_CHECKLOCKTIMEVERIFY
</code></pre>
<p>โดยที่ค่า &lt;now {plus} 3 months&gt; คือความสูงบล็อกหรือค่าเวลาที่ประเมินว่าจะตรงกับอีก 3 เดือนหลังจากที่ธุรกรรมถูกขุดลงบล็อก เช่น ความสูงบล็อกปัจจุบัน + 12,960 บล็อก หรือ Unix epoch time ปัจจุบัน + 7,760,000 วินาที</p>
<p>เมื่อบ็อบต้องการใช้จ่าย UTXO นี้ เขาจะสร้างธุรกรรมใหม่ที่อ้างอิง UTXO นั้นเป็นอินพุต จากนั้นใส่ลายเซ็นและกุญแจสาธารณะของเขาในสคริปต์อินพุต พร้อมตั้งค่า lock time ของธุรกรรมให้มากกว่าหรือเท่ากับค่าทิมล็อกที่ระบุไว้ใน OP_CHECKLOCKTIMEVERIFY ที่อลิซกำหนด แล้วจึงกระจายธุรกรรมนี้ไปยังเครือข่ายบิตคอยน์</p>
<p>ธุรกรรมของบ็อบจะถูกประเมินดังนี้: หากค่าพารามิเตอร์ของ OP_CHECKLOCKTIMEVERIFY ที่อลิซตั้งไว้นั้นน้อยกว่าหรือเท่ากับ lock time ของธุรกรรมที่ใช้จ่าย สคริปต์จะทำงานต่อไป (มีผลเหมือนกับไม่มีการทำงาน หรือเหมือน opcode ประเภท OP_NOP) แต่ถ้าค่าดังกล่าวมากกว่า lock time การทำงานของสคริปต์จะหยุดลงทันที และธุรกรรมจะถูกมองว่าไม่ถูกต้อง</p>
<p>กล่าวให้ชัดเจนยิ่งขึ้น BIP65 อธิบายว่า OP_CHECKLOCKTIMEVERIFY จะล้มเหลวและหยุดการทำงานของสคริปต์ทันที หากเกิดเงื่อนไขอย่างใดอย่างหนึ่งต่อไปนี้:</p>
<ul>
<li>สแตกว่างเปล่า  </li>
<li>ค่าบนสุดของสแตกมีค่าน้อยกว่า 0  </li>
<li>ประเภทของ lock time (ความสูงบล็อกเทียบกับ timestamp) ของค่าบนสุดในสแตกไม่ตรงกับประเภทของ lock time ในฟิลด์ lock time ของธุรกรรม  </li>
<li>ค่าบนสุดของสแตกมีค่ามากกว่าค่า lock time ของธุรกรรม  </li>
<li>ฟิลด์ sequence ของอินพุตมีค่าเป็น 0xffffffff</li>
</ul>
<h3>Timelock Conflicts</h3>
<p>OP_CLTV และ locktime นั้นได้ใช้รูปแบบเดียวกันในการอธิบายระยะเวลาในการล๊อค ไม่ว่าจะเป็น block height หรือเมื่อเวลาผ่านไปในหน่วยของวินาทีตาม unix epoch ส่วนที่สำคัญคือ รูปแบบของ timelock จะต้องตรงกับรูปแบบของ OP_CLTV ใน output ทั้งคู่ต้องอ้างอิงแบบเดียวกัน คือจะเป็น block height หรือหน่วยวินาทีก็ตาม</p>
<p>สิ่งนี้หมายความว่าสคริปต์จะไม่มีทางเป็นสคริปต์ได้ ถ้ามีการเรียก OP_CLTV สองครั้งโดยใช้รูแปบบที่แตกต่างกัน คือครั้งนึงเป็น block height และ อีกครั้งหนึ่งเป็น timestamp ซึ่งส่วนนี้เองเป็นข้อผิดพลาดที่เกิดได้ง่ายและมักจะเกิดขึ้น เพราะฉะนั้นควรทดสอบสคริปต์อย่างละเอียดบน testnet หรือใช้เครื่องมือที่ออกแบบมาเพื่อป้องกันปัญหานี้ เช่น Miniscript compiler</p>
<p>ผลอีกอย่างที่สืบเนื่องกันมาจากข้อกำหนดที่ว่าหนึ่งธุรกรรมสามารถใช้ OP_CLTV ได้แบบเดียวเท่านั้น จึงทำให้ในธุรกรรมที่มีหลาย ๆ input โดยแต่ละ input ใช้รูปแบบของ OP_CLTV ที่แตกต่างกัน จะไม่สามารถนำมาสร้างธุรกรรมที่ใช้ input ทั้งสองพร้อมกันได้</p>
<p>โดยหลังจากมีการประมวลผล หากเงื่อนไขของ OP_CLTV เป็นจริง พารามิเตอร์ที่อยู่ก่อนหน้า OP_CLTV จะยังคงอยู่บนสุดของแสตก และอาจจำเป็นต้องเอาออกด้วย OP_DROP เพื่อให้การทำงานของ opcode อื่น ๆ ในสคริปต์ถัดไปได้เป็นไปอย่างถูกต้อง ด้วยเหตุนี้เราจึงมักจะเห็น OP_CHECKLOCKTIMEVERIFY จะถูกใช้ตามด้วย OP_DROP ในสคริปต์ต่าง ๆ เช่นเดียวกับ OP_CSV (จะอธิบายต่อในหัวข้อ Relative timelock) OP_CLTV มีพฤติกรรมที่แตกต่างจาก opcode ในกลุ่ม CHECKVERIFY ตัวอื่น ๆ ตรงที่ไม่ได้นำข้อมูลออกจากสแตก แต่ทั้งนี้ทั้งนั้นมันเป็นเพราะ ซอฟต์ฟอร์กที่เพิ่ม opcode เหล่านี้เข้าไป ได้อาศัยการนิยามใหม่ของ opcode ที่เคยเป็น no-operation (NOP) ซึ่งเดิมไม่ได้ลบข้อมูลออกจากสแตก และพฤติกรรมของ opcode NOP เดิมเหล่านั้นจำเป็นต้องถูกคงไว้เพื่อความเข้ากันได้</p>
<p>และด้วยการใช้ lock time ร่วมกันกับ OP_CLTV นั้นจะทำให้ในส่วนที่เราได้อธิบายไว้ในหัวข้อ ข้อจำกัดของ Transaction Lock Time เปลี่ยนแปลงไปเล็กน้อย เนื่องจากอลิสสามารถส่งบิตคอยน์ของเธอได้ทันที โดยกำหนดให้เงินถูกล๊อคไว้ที่กุญแจของบ๊อบตั้งแต่วินาทีนั้น อลิสจะไม่สามารถใช้เงินก้อนนี้ซ้ำได้อีก และในขณะเดียวกันบ๊อบก็ยังคงต้องรอ 3 เดือนก่อนตามที่กำหนดไว้</p>
<p>อยากตัวอย่างดังกล่าว ผู้อ่านทุกท่านคงจะได้เห็นแล้วว่าการนำ timelock เข้ามาไว้ในภาษา scripting ทำให้ OP_CLTV เปิดโอกาสให้เราสามารถพัฒนาสคริปต์ที่ซับซ้อนและน่าสนใจได้หลากหลายรูปแบบ</p>
<p>ซึ่งมาตรฐานดังกล่าวถูกกำหนดไว้ใน BIP65 (OP_CHECKLOCKTIMEVERIFY)</p>
<h3>Relative Timelocks</h3>
<p>Lock time และ OP_CLTV ทั้งคู่เป็น absolute timelocks กล่าวคือ เป็นการกำหนดเวลาที่ตายตัว ส่วนกลไก timelock อีกสองรูปแบบที่เราจะพิจรณาต่อไปนี้เป็น relative timelocks ซึ่งเป็นการกำหนดเงื่อนไขการใช้จ่าย output โดยอ้างอิงกับกับระยะเวลาตั้งแต่ธุกรรมก่อนหน้าได้รับการยืนยันและถูกบันทึกลงบนบล๊อคเชน</p>
<p>relative timelocks นั้นสามารถช่วยให้เราสามารถกำหนดข้อจำกัดในด้านของเวลาให้กำธุรกรรมนั้น ๆ โดยอ้างอิงจากเวลาที่ธุรกรรมก่อนหน้าถูกยืนยัน หรือกล่าวได้ว่าเวลาของธุรกรรมนั้นจะไม่ถูกนับจนกว่า UTXO ก่อนหน้าจะปรากฎบนบล๊อคเชน ฟังก์ชันนี้มีความสำคัญอย่างยิ่งกับการทำ bidirectional state channels และ Lightning Network (LN) ซึ่งเราจะได้อ่านเรื่องนี้เพิ่มเติมในหัวข้อ state channels </p>
<p>Relative timelocks นั้นได้มีการถูกนำมาใช้งานทั้งในระดับธุรกรรมและในระดับของสคริปต์ เช่นเดียวกันกับ absolute timelocks โดยในระดับธุรกรรมนั้นจะถูกใช้ในฟิลด์ของ sequence ซึ่งเป็นฟิลด์ที่ต้องอยู่ในส่วนของ input ในทุกธุรกรรมของบิตคอยน์ ส่วนในระดับของสคริปต์นั้นจะถูกเรียกใช้ผ่าน opcode ที่ชื่อ OP_CHECKSEQUENCEVERIFY (OP_CSV)</p>
<p>Relative timelocks ถูกนำมาใช้งานตามข้อกำหนดที่ระบุไว้ใน BIP68: Relative Lock-Time Using Consensus-Enforced Sequence Numbers และ BIP112: OP_CHECKSEQUENCEVERIFY</p>
<p>ทั้ง BIP68 และ BIP112 ถูกเปิดใช้งานในเดือนพฤษภาคม ปี 2016 ในรูปแบบของการอัปเกรดกฎ consensus แบบ soft fork</p>
<h3>Relative Timelocks with OP_CSV</h3>
<p>เช่นเดียวกันกับ OP_CLTV และ lock time ในระบบของบิตคอยน์มี opcode ในระดัสคริปต์สำหรับ relative timelock ที่อาศัยค่า sequence ภายในสคริปต์ด้วย opcode นั้นคือ OP_CHECKSEQUENCEVERIFY ซึ่งมักเรียกย่อว่า OP_CSV</p>
<p>เมื่อ opcode อย่าง OP_CSV ถูกประเมิณค่าในสคริปต์ของ UTXO จะอนุญาตให้ใช้จ่ายได้เฉพาะในธุรกรรมที่ค่า sequence ของ input มีค่ามากกว่าหรือเท่ากับพารามิเตอร์ของ OP_CSV เท่านั้น โดยสรุปแล้ว กลไกนี้จะจำกัดการใช้จ่าย UTXO จนกว่าจะมีจำนวนบล็อกหรือเวลาหน่วยวินาทีผ่านไปตามที่กำหนดไว้ นับจากเวลาที่ UTXO นั้นถูกขุดและบันทึกลงในบล็อกเชน</p>
<p>และเช่นเดียวกันกับ CLTV ค่าใน OP_CSV จะต้องมีรูปแบบที่สอดคล้องกับค่า sequence ที่ใช้คู่กัน โดยหาก OP_CSV ถูกกำหนดไว้เป็นจำนวนบล๊อก ค่า sequence ก็จำเป็นต้องอยู่ในรูปแบบของจำนวนบล๊อก และหาก OP_CSV ถูกกำหนดค่าไว้เป็นวินาที ค่า sequence ก็จำเป็นต้องเป็นค่าวินาทีเช่นกัน</p>
<blockquote>
<p>คำเตือน: สคริปต์ที่มีการเรียกใช้ OP_CSV หลายครั้ง จะต้องใช้รูปแบบเดียวกันทั้งหมด คือจะเป็นรูปแบบของวินาที ก็ต้องเป็นวินาทีทั้งหมด ถ้าเป็นจำนวนบล๊อกก็ต้องเป็นจำนวนบล๊อกทั้งหมดเท่านั้น การผสมทั้งสองรูปแบบเข้าด้วยกันจะทำให้สคริปต์นั้นถูกมองว่าไม่ถูกต้อง และไม่สามารถถูกใช้จ่ายได้ตลอดไป ซึ่งเป็นปัญหาเดียวกันกับ OP_CLTV ในหัวข้อ Timelock Conflicts แต่อย่างไรก็ตาม OP_CSV อณุญาติให้มี input ที่ถูกต้องได้หลายแบบภายในธุรกรรมเดียวกัน ดังนั้นปัญหาของการปฎิสัมพันธ์ข้าม input ที่เกิดขึ้นกับ OP_CLTV จึงจะไม่เกิดขึ้นกับ OP_CSV</p>
</blockquote>
<p>relative timelock ด้วย OP_CSV นั้นมีประโยชน์อย่างยิ่งในกรณีที่มีการสร้างและลงนามธุรกรรมหลายรายการที่เชื่อมต่อกันเป็นลูกโซ่ แต่ยังไม่ถูกเผยแพร่ไปยังเครือข่าย นั่นคือถูกเก็บไว้นอกบล็อกเชน ธุรกรรมลูกเหล่านั้นจะไม่สามารถถูกใช้งานได้จนกว่าธุรกรรมแม่จะถูกเผยแพร่ ถูกขุดรวมเข้าไปในบล็อกเชน และมีอายุผ่านไปตามระยะเวลาที่ระบุไว้ใน relative timelock การใช้งานลักษณะนี้แสดงตัวอย่างไว้ใน state channels และ lightning network</p>
<p>OP_CSV ถูกกำหนดรายละเอียดไว้ใน BIP112 และ CHECKSEQUENCEVERIFY</p>
<h3>สคริปต์ที่มีการควบคุมลำดับการทำงาน (เงื่อนไขหลายเงื่อนไข)</h3>
<p>หนึ่งในสิ่งที่น่าสนใจ และคุณสมบัติที่ทรงพลังมาก ๆ ของ Bitcoin script คือการควบคุมลำดับการทำงาน (Flow control) หรือที่เลือกว่าเงื่อนไขหลายเงื่อนไข คุณน่าจะคุ้นเคยกับแนวคิดของ flow control จากภาษาโปรแกรมต่าง ๆ ที่ใช้โครงสร้าง IF…THEN…ELSE เงื่อนไขใน Bitcoin Script แม้จะมีรูปแบบแตกต่างออกไปเล็กน้อย แต่โดยรวมแล้วเป็นโครงสร้างเดียวกัน</p>
<p>ในระดับพื้นฐาน opcode นั้นมีเงื่อนไขของบิตคอยน์ที่ช่วยให้เราสามารถสร้างสคริปต์ที่มีวิธีปลดล็อกได้สองแบบ ขึ้นอยู่กับผลลัพธ์ TRUE/FALSE จากการประเมินเงื่อนไขในทางตรรกะ ตัวอย่างเช่น หากค่า x เป็น TRUE เส้นทางของโค้ดที่ถูกประมวลผลคือ A และหากไม่เป็นเช่นนั้น (ELSE) เส้นทางของโค้ดคือเส้นทาง B</p>
<p>นอกจากนี้ นิพจน์ต่าง  ๆ ภายในเงื่อนไขของบิตคอยน์ยังสามารถทับซ้อนกันได้อย่างไม่จำกัด หรือกล่าวได้ว่าภายในเงื่อนไขใด ๆ สามารถอีกอีกเงื่อนไขอยู่ด้านในได้ สคริปต์ของบิตคอยน์ที่มีการควบคุมลำดับการทำงาน จึงสามารถใช้สร้างสคริปต์ที่ซับซ้อนมาก โดยมีเส้นทางการประมวลผลที่เป็นไปได้หลายร้อยแบบ แม้จะไม่มีข้อจำกัดด้านระดับความลึกของการซ้อนเงื่อนไขแต่กฎฉันทามติ ก็ได้กำหนดข้อจำกัดไว้ที่ขนาดสูงสุดของสคริปต์ในหน่วยไบต์</p>
<p>บิตคอยน์ได้ใช้การควบคุมระดับการทำงานผ่าน opcode  อย่าง OP_IF OP_ELSE OP_ENDIF และ OP_NOTIF นอกจากนี้นิพจน์เงื่อนไขยังสามารถมีตัวดำเนินการเชิงตระกะอย่าง OP_BOOLAND, OP_BOOLOR และ OP_NOT ได้ด้วย</p>
<p>ในภาษาโปรแกรมแบบดั้งเดิม (เชิงกระบวนการ) ส่วนใหญ่ การควบคุมลำดับการทำงานจะมีลักษณะดังนี้:<br>pseudocode ของการควบคุมลำดับการทำงานในภาษาโปรแกรมส่วนใหญ่</p>
<pre><code>if (condition):
  code to run when condition is true
else:
  code to run when condition is false
endif
code to run in either case
</code></pre>
<p>แต่ในภาษาที่อิงกับสแตก (stack-based) อย่าง Bitcoin Script เงื่อนไขเชิงตรรกะจะมาก่อนคำสั่ง IF ซึ่งทำให้โครงสร้างดูเหมือน “กลับด้าน”:<br>การควบคุมลำดับการทำงานใน Bitcoin Script</p>
<pre><code>condition
IF
  code to run when condition is true
OP_ELSE
  code to run when condition is false
OP_ENDIF
code to run in either case
</code></pre>
<p>เมื่ออ่าน Bitcoin Script ให้จำไว้ว่า เงื่อนไขที่ถูกนำมาประเมินค่าจะมาก่อน opcode IF เสมอ</p>
<h2>เงื่อนไขแบบมี verify opcode</h2>
<p>เงื่อนไขในอีกรูปแบบหนึ่งของบิตคอยน์สคริปต์ คือ opcode ใด ๆ ที่ลงท้ายด้วย VERIFY โดยคำต่อท้าย VERIFY หมายความว่า หากเงื่อนไขที่ถูกประเมินค่าไม่เป็น TRUE การทำงานของสคริปต์จะถูกยุติทันที และธุรกรรมจะถูกพิจารณาว่าไม่ถูกต้อง</p>
<p>ซึ่งแตกต่างจากการทำงานของ IF ซึ่งได้เปิดโอกาสให้มีเส้นทางการทำงานหลายรูปแบบ opcode ที่ลงท้ายด้วย VERIFY จะทำหน้าที่เป็น guard clause หรือก็คือตรรกะที่ต้องประเมินผลให้เป็นจริง เพื่อให้การดำเนินการของโปรแกรมสามารถดำเนินต่อไปได้</p>
<p>ตัวอย่างเช่น ในสคริปต์ต่อไปนี้ได้มีการกำหนดให้ต้องมีทั้งลายเซ็นของบ๊อบและค่า preimage ที่เมื่อแฮชแล้วต้องได้ค่าตามที่กำหนด ทั้งสองเงื่อนไขนี้เองต้องถูกทำให้เป็นจริงจึงจะสามารถปลดล๊อคได้:</p>
<p>สคริปต์ที่มี OP_EQUALVERIFY เป็น guard clause</p>
<pre><code>OP_HASH160 &lt;expected hash&gt; OP_EQUALVERIFY &lt;Bob's Pubkey&gt; OP_CHECKSIG
</code></pre>
<p>เพื่อที่จะใช้จ่ายเงินก้อนนี้บ๊อบจำเป็นต้องแสดง preimage และลายเซ็นที่ถูกต้องเท่านั้น</p>
<pre><code>&lt;Bob's Sig&gt; &lt;hash pre-image&gt;
</code></pre>
<p>หากไม่ได้นำเสนอ preimage มาก่อน Bob จะไม่สามารถไปถึงส่วนของสคริปต์ที่ตรวจสอบลายเซ็นของเขาได้</p>
<p>สคริปต์นี้สามารถเขียนใหม่โดยใช้ OP_IF แทนได้ดังนี้:</p>
<p>สคริปต์ที่มี IF ทำหน้าที่เป็น guard clause</p>
<pre><code>OP_HASH160 &lt;expected hash&gt; OP_EQUAL
OP_IF
   &lt;Bob's Pubkey&gt; OP_CHECKSIG
OP_ENDIF
</code></pre>
<p>ข้อมูลยืนยันตัวตนของ Bob ยังคงเหมือนเดิม:</p>
<p>การทำให้สคริปต์ข้างต้นเป็นจริง</p>
<pre><code>&lt;Bob's Sig&gt; &lt;hash pre-image&gt;
</code></pre>
<p>สคริปต์ที่มีการใช้ OP_IF ให้ผลลัพธ์เหมือนกับการใช้ opcode ที่มีคำต่อท้าย VERIFY โดยทั้งสองแบบทำหน้าที่เป็น guard clause เหมือนกัน แต่อย่างไรก็ตาม โครงสร้างที่ใช้ VERIFY ใช้จะมีประสิทธิภาพมากกว่า เนื่องจากมีการใช้ opcode น้อยกว่าสองตัว</p>
<p>แล้วเมื่อไหร่ที่เราควรใช้ VERIFY แล้วเมื่อไหร่ที่เราควรใช้ OP_IF ? หากสิ่งที่เราต้องการทำมีเพียงการกำหนดเงื่อนไขเบื้องต้น (guard clause) VERIFY จะเป็นทางเลือกที่ดีกว่า แต่หากเราต้องการให้มีเส้นทางการทำงานมากกว่าหนึ่งแบบ (flow control) เราจำเป็นต้องใช้โครงสร้างควบคุมลำดับการทำงานแบบ OP_IF...OP_ELSE แทน</p>
<h3>การใช้ Flow control ในสคริปต์</h3>
<p>วิธีใช้การควบคุมลำดับการทำงานโดยทั่วไปภายในสคริปต์ของบิตคอยน์นั้นมักเป็นการสร้างสคริปต์ที่เปิดโอกาสให้สามารถสร้างเส้นทางการทำงานของสคริปต์ได้หลายแบบ โดยแต่ละเส้นทางก็มีวิธีการในการใช้จ่าย UTXO ที่แตกต่างกัน </p>
<p>ลองมาพิจรณาจากตัวยอ่างง่าย ๆ นี้กัน โดยเรามีผู้ที่สามารถลงนามในธุรกรรมนี้ได้สองคน นั้นคืออลิซและบ๊อบโดยขอแค่เป็นใครคนใดคนหนึ่งในสองคนนี้ก็สามารถใช้จ่ายได้ โดยจะเขียนออกมาเป็น 1-of-2 multisig แต่เราจะทำสิ่งเดียวกันนี้โดยใช้คำสั่ง OP_IF:</p>
<pre><code>OP_IF
 &lt;Alice's Pubkey&gt;
OP_ELSE
 &lt;Bob's Pubkey&gt;
OP_ENDIF
OP_CHECKSIG
</code></pre>
<p>ถ้ามองสคริปต์ในตัวอย่างแล้วคุณอาจสงสัยว่า แล้วเงื่อนไขอยู่ตรงไหน? ทำไมไม่มีอะไรอยู่ก่อนคำสั่ง IF เลย</p>
<p>ส่วนเหตุผลนั้นก็เป็นเพราะว่าเงื่อนไขนั้นไม่ได้เป็นส่วนหนึ่งของสคริปต์ แต่จะถูกส่งมาในตอนที่มีการใช้จ่ายแทน ซึ่งทำให้ Alice และ Bob สามารถ “เลือก” เส้นทางการทำงานที่ต้องการได้:</p>
<pre><code>&lt;Alice's Sig&gt; OP_TRUE
</code></pre>
<p>OP_TRUE ที่อยู่ท้ายสุดทำหน้าที่เป็นเงื่อนไข (TRUE) ซึ่งจะทำให้คำสั่ง OP_IF เลือกเส้นทางการใช้จ่ายแรก โดยในเงื่อนไขนี้จะทำให้ public key ที่อลิซมีลายเซ็นตรงกันถูกนำขึ้นสแตก Opcode OP_TRUE หรือที่เรียกว่า OP_1 จะใส่ค่าเลข 1 ลงบนสแตก</p>
<p>ส่วนสำหรับบ๊อบหากต้องการใช้จ่าย UTXO นี้ เขาจะต้องเลือกเส้นทางการทำงานที่สองของ OP_IF โดยให้ค่า FALSE แทน Opcode OP_FALSE หรือที่เรียกว่า OP_0 จะใส่ค่าเป็นอาร์เรย์ไบต์ว่างลงบนสแตก:</p>
<pre><code>&lt;Bob's Sig&gt; OP_FALSE
</code></pre>
<p>input สคริปต์ของ Bob จะทำให้คำสั่ง OP_IF ไปสคริปต์ในส่วนที่สอง (OP_ELSE) ซึ่งต้องการลายเซ็นของบ๊อบแทน</p>
<p>เนื่องจากคำสั่ง OP_IF สามารถซ้อนกันได้ เราจึงสามารถสร้าง “เขาวงกต” ของเส้นทางการทำงานได้ โดย input script จะทำหน้าที่เสมือน “แผนที่” ที่ใช้เลือกว่าจริง ๆ แล้วเส้นทางการทำงานใดจะถูกนำมาใช้</p>
<pre><code>OP_IF
  subscript A
OP_ELSE
  OP_IF
    subscript B
  OP_ELSE
    subscript C
  OP_ENDIF
OP_ENDIF
</code></pre>
<p>ในตัวอย่างนี้จะมีเส้นทางการทำงานทั้งหมดสามเส้นทางด้วยกัน (subscript A, subscript B, subscript C) โดย input script จะเป็นผู้กำหนดเส้นทางตามรูปแบบของลำดับค่า TRUE หรือ FALSE อย่างเช่น หากต้องการเลือกเส้นทาง subscript B input script จะต้องลงท้ายด้วย OP_1 OP_0 (TRUE, FALSE) ค่าเหล่านี้จะถูกนำขึ้นแสตกทำให้ค่า FALSE อยู่จุดบนสุดของแสตก ซึ่ง OP_IF ชั้นนอกจะทำการดึงค่า FALSE ออกมาและนำส่วน OP_ELSE แรก จากนั้นค่า TRUE จะเลื่อนขึ้นมาอยู่บนสุดของแสตก และจะถูกประเมิณโดย OP_IF ชั้นใน ซึ่งจะเลือกเส้นทางการทำงานแบบ B</p>
<p>ด้วยโครงสร้างของสคริปต์แบบนี้ เราจะสามารถสร้าง redeem script ที่มีเส้นทางการทำงานได้หลายสิบ หรือหลายร้อยเส้นทาง โดยแต่ละเส้นจะเสนอวิธีการใช้จ่าย UTXO ที่แตกต่างกันออกไป เมื่อเราต้องการใช้จ่าย เราจะสร้าง input script ที่นำทางไปตามเส้นทางการทำงานนั้น ๆ ด้วยการใส่ค่า TRUE และ FALSE ที่เหมาะสมลงบนสแตกในแต่ละจุดของการควบคุมลำดับการทำงาน</p>
<h3>ตัวอย่างสคริปต์แบบซับซ้อน</h3>
<p>ในส่วนนี้เราจะนำแนวคิดทั้งหมดที่ได้เรียนรู้จากบทนี้มารวมกันไว้ในตัวอย่างเดียว</p>
<p>สมมุติว่าโมฮัมเหม็ด ซึ่งเป็นเจ้าของบริษัทนำเข้าและส่งออกในดูไบ เขาต้องการสร้างบัญชีเงินทุนของบริษัทที่มีกฏเกณฑ์ที่ยืดหยุ่น และแผนของเขาคือการออกแบบมาเพื่อให้ใช้ระดับในการอณุญาติที่แตกต่างกันไปตามเงื่อนไขของ timelock และผู้เข้าร่วมโครงสร้าง multisig นี้จะประกอบไปด้วย โมฮัมเหม็ด หุ้นส่วนอย่าง ซาอีดและไซรา และสุดท้ายเป็นทนายความของบริษัท โดยหุ้นส่วนทั้งสามตัดสินใจโดยใช้หลักเสียงข้างมาก ดังนั้นจะต้องมีอย่างน้อยสองในสามคนเห็นชอบสำหรับกรณีต่าง ๆ แต่อย่างไรก็ตาม ในกรณีที่เกิดปัญหากับ key ของพวกเขา พวกเขาเพียงต้องการให้ทนายความสามารถกู้คืนเงินได้ โดยใช้ลายเซ็นของหุ้นส่วนคนใดคนหนึ่งจากสามคนร่วมด้วย สุดท้ายแล้วหากหุ้นส่วนทั้งหมดไม่สามารถติดต่อได้หรือไม่สามารถปฏิบัติน่าที่ได้เป็นระยะเวลาหนึ่ง พวกเขาต้องการให้ทนายความสามารถจัดการบัญชีได้โดยตรงหลังจากที่เขาได้รับสิทธ์เข้าถึงบันทึกธุรกรรมของบัญชีเงินทุนนี้ได้</p>
<p>สคริปต์ไถ่ถอนแบบ multisignature ที่เปลี่ยนแปลงได้ร่วมกันกับ timelock คือสิ่งที่โมฮัมเหม็ดต้องออกแบบขึ้นมาเพื่อให้บรรลุเป้าหมายนี้</p>
<p>ตัวอย่างที่ 1: การใช้ Multisignature ร่วมกับ timelock</p>
<pre><code>01  OP_IF
02    OP_IF
03      2
04    OP_ELSE
05      &lt;30 days&gt; OP_CHECKSEQUENCEVERIFY OP_DROP
06      &lt;Lawyer's Pubkey&gt; OP_CHECKSIGVERIFY
07      1
08    OP_ENDIF
09    &lt;Mohammed's Pubkey&gt; &lt;Saeed's Pubkey&gt; &lt;Zaira's Pubkey&gt; 3 OP_CHECKMULTISIG
10  OP_ELSE
11    &lt;90 days&gt; OP_CHECKSEQUENCEVERIFY OP_DROP
12    &lt;Lawyer's Pubkey&gt; OP_CHECKSIG
13  OP_ENDIF
</code></pre>
<p>สคริปต์ของโมฮัมเหม็ดใช้โครงสร้างควบคุมลำดับการทำงานแบบ OP_IF…OP_ELSE ที่ซ้อนกันเพื่อสร้างเส้นทางการทำงานทั้งหมดสามเส้นทาง</p>
<p>ในเส้นทางการทำงานเส้นทางแรก สคริปต์นี้จะทำงานเหมือน multisig 2-of-3 ธรรมดา ๆ ระหว่างหุ้นส่วนทั้งสาม โดยเส้นทางการทำงานนี้ประกอบด้วยบรรทัดที่ 3 และบรรทัดที่ 9 โดยบรรทัดที่ 3 กำหนดโดย quorum ของ multisig เป็น 2 (2-of-3) เส้นทางการทำงานนี้สามารถถูกเลือกได้โดยการใส่ OP_TRUE OP_TRUE ต่อท้ายใน input script: </p>
<p>ข้อมูลการใช้จ่ายสำหรับเส้นทางการทำงานแรก (multisig แบบ 2-of-3)</p>
<pre><code>OP_0 &lt;Mohammed's Sig&gt; &lt;Zaira's Sig&gt; OP_TRUE OP_TRUE
</code></pre>
<blockquote>
<p>TIP: OP_0 ที่อยู่ตอนต้นของ input script นี้มีสาเหตุมาจากความผิดปกติของ OP_CHECKMULTISIG ซึ่งจะดึงค่าออกจากแสตกมากกว่าที่ควรหนึ่งค่า ค่าที่ถูกดึงออกมาเกินนี้จะถูกละเลยโดย OP_CHECKMULTISIG แต่มันจำเป็นต้องมีอยู่ มิฉะนั้นสคริปค์จะล้มเหลว การใส่อาร์เรย์ไบต์ว่างด้วย OP_0 จึงเป็นวิธีแก้ปัญหาชั่วคราวสำหรับความผิดปกตินี้ ตามที่อธิบายไว้ในหัวข้อ An Oddity in CHECKMULTISIG Execution</p>
</blockquote>
<p>ในเส้นทางการทำงานเส้นทางที่สองสามารถถูกใช้งานได้ก็ต่อเมื่อผ่านไปแล้ว 30 วันหลังจากที่ UTXO ถูกสร้างขึ้น และเมื่อถึงเวลานั้น สคริปต์จะต้องการลายเซ็นของทนายความ และลายเซ็นจากหนึ่งในหุ้นส่วน (multisig 1 of 3) โดยเงื่อนไขนี้ถูกกำหนดโดยบรรทัดที่ 7 ซึ่งตั้งค่า quorum ของ multisigไว้ที่ 1 และเพื่อเลือกใช้เส้นทางการทำงานนี้ input script จะต้องลงท้ายด้วย OP_FALSE OP_TRUE:</p>
<p>ข้อมูลการใช้จ่ายสำหรับเส้นทางการทำงานที่สอง (ทนายความ + multisig แบบ 1-of-3)</p>
<pre><code>OP_0 &lt;Saeed's Sig&gt; &lt;Lawer's Sig&gt; OP_FALSE OP_TRUE
</code></pre>
<blockquote>
<p>TIP: OP_FALSE จะถูกใส่ลงบนสแตกก่อน จากนั้น OP_TRUE จะถูกใส่ลงไปอยู่ด้านบนของมัน ดังนั้นค่า TRUE จึงถูกดึง (pop) ออกมาก่อนโดย opcode OP_IF ตัวแรก</p>
</blockquote>
<p>สุดท้าย เส้นทางการทำงานที่สามอนุญาตให้ทนายความสามารถใช้จ่ายเงินได้เพียงคนเดียว แต่จะทำได้ก็ต่อเมื่อผ่านไปแล้ว 90 วันเท่านั้น เพื่อเลือกเส้นทางการทำงานนี้  Input script จะต้องลงท้ายด้วย OP_FALSE:</p>
<p>ข้อมูลการใช้จ่ายสำหรับเส้นทางการทำงานที่สาม (ทนายความ)</p>
<pre><code>&lt;Lawyer's Sig&gt; OP_FALSE
</code></pre>
<p>ลองจำลองการรันสคริปต์บนกระดาษเพื่อดูว่ามันทำงานอย่างไรบนสแตก</p>
<h2>Pay to witness public key hash (P2WPKH)</h2>
<p>เริ่มจากดูตัวอย่างของ output script แบบ P2PKH กันก่อน:</p>
<p>ตัวอย่าง output script P2PKH</p>
<pre><code>OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7
OP_EQUALVERIFY OP_CHECKSIG
</code></pre>
<p>เมื่อใช้ segregated witness อลิซจะสร้างสคริปต์แบบ P2WPKH หากสคริปต์นั้นผูกกับ public key เดียวกัน ก็จะมีหน้าตาประมาณนี้: </p>
<pre><code>0 ab68025513c3dbd2f7b92a94e0581f5d50f654e7
</code></pre>
<p>อย่างที่เห็นว่า output script แบบ P2WPKH นั้นเรียบง่ายกว่าสคริปต์แบบ P2PKH เป็นอย่างมากถ้าเราเอามาเปรียบเทียบกัน มันประกอบด้วยค่าเพียงแค่สองค่าเท่านั้นที่จะถูกใส่ลงในแสตกสำหรับการประมวลผลสคริปต์ โดยสำหรับไคล์เอนต์บิตคอยน์รุ่นเก่า ๆ (ที่ยังไม่รองรับ segwit) การใส่สองค่านี้จะดูเหมือน output ที่ใครก็สามารถใช้จ่ายได้ แต่สำหรับไคลเอนต์รุ่นใหม่ที่รองรับ segwit ตัวเลขตัวแรก (0) จะถูกตีความเป็นหมายเลขเวอร์ชัน (witness version) และส่วนที่สอง (ขนาด 20 ไบต์) คือ witness program โดย witness program ขนาด 20 ไบต์นี้ก็คือแฮชของ public key เช่นเดียวกับในสคริปต์แบบ P2PKH</p>
<p>ตอนนี้เรามาดูธุรกรรมที่เกี่ยวข้องกันซึ่งบ๊อบใช้เพื่อจ่าย output นี้กัน โดยสำหรับสคริปต์แบบ lagacy นั้น ธุรกรรมที่ใช้จ่ายนั้นจะต้องใส่ลายเซ็นไว้ในส่วน input ของธุรกรรม:</p>
<pre><code>[...]
"vin" : [
  "txid": "abcdef12345...",
  "vout": 0,
  "scriptSig": “&lt;Bob’s scriptSig&gt;”,
]
[...]
</code></pre>
<p>แต่อย่างไรก็ตาม เพื่อใช้จ่าย output แบบ P2WPKH ธุรกรรมจะไม่มีลายเซ็นอยู่ในส่วนของ input เลย แต่แทนที่จะเป็นเช่นนั้น ธุรกรรมของบ๊อบจะมี input script ที่ว่างเปล่า และจะใส่ข้อมูลไว้ในส่วนของ witness แทน:</p>
<pre><code>[...]
"vin" : [
  "txid": "abcdef12345...",
  "vout": 0,
  "scriptSig": “”,
]
[...]
“witness”: “&lt;Bob’s witness structure&gt;”
[...]
</code></pre>
<h2>การสร้างกระเป๋าเงินแบบ P2WPKH</h2>
<p>สิ่งที่สำคัญที่สุดและควรจะทราบไว้คือ witness program แบบ P2WPKH ควรจะถูกสร้างขึ้นโดยผู้รับเงินเท่านั้น และไม่ควรแปลงมาจาก public key ของผู้ที่รู้จักอยู่แล้ว เพราะสคริปต์ของ P2PKH หรือแม้แต่จาก address ใด ๆ นั้นผู้ใช้จ่ายไม่มีทางรู้ได้เลยว่ากระเป๋าเงินของผู้รับนั้นสามารถสร้างธุรกรรมแบบ segwit และสามารถใช้จ่าย output แบบ P2WPKH ได้หรือไม่</p>
<p>นอกจากนี้ output แบบ P2WPKH นั้นจะต้องถูกสร้างจาก hash ของ compressed public key เท่านั้น เพราะว่า public key แบบ uncompressed นั้นถือว่าไม่อยู่ในมาตรฐานของ segwit และอาจจะถูกปิดการใช้งานอย่างชัดเจนใน soft fork ที่เกิดขึ้นภายหลัง หาก hash ที่ใช้ได้ใน P2WPKH มาจาก public key แบบ uncompressed จะทำให้ output ที่เกิดขึ้นนั้นไม่สามารถจ่ายออกได้อีก และจะทำให้คุณอาจที่จะสูญเสียเงินนั้นไปตลอดกาล นั่นจึงเป็นเหตุผลที่ว่าทำไม output แบบ P2WPKH นั้นถึงควรถูกสร้างโดยแอปกระเป๋าเงินของผู้รับผ่านการสร้าง compress public key จาก private key ของเขาเอง</p>
<blockquote>
<p>Warning: P2WPKH ควรถูกสร้างโดยผู้รับ โดยการนำ public key แบบ compressed มาแปลงเป็น P2WPKH hash เท่านั้น ไม่ควรให้ผู้ใช้หรือบุคคลอื่นใด แปลง P2PKH script, Address, หรือ public key แบบ uncompressed ให้กลายเป็น P2WPKH witness script ซึ่งเป็นเรื่องปกติอยู่แล้วที่ผู้ใช้ควรส่งเงินให้ผู้รับ ในรูปแบบที่ผู้รับได้ระบุไว้เท่านั้น</p>
</blockquote>
<h3>Pay to witness script hash (P2WSH)</h3>
<p>witness program ประเภทนี้จะสอดคล้องกันกับ P2SH ที่เราได้ผ่านกันมาก่อนหน้านี้ ในหัวข้อของ ในหัวข้อ Pay to Script Hash และในตัวอย่างที่บริษัทของนายโมฮัมเหม็ดได้ใช้สคริปต์แบบ P2SH เพื่อทำ multisig โดยสคริปต์ที่ถูกเข้ารหัสของเขาจะมีหน้าตาแบบนี้</p>
<pre><code>OP_HASH160 54c557e07dde5bb6cb791c7a540e0a4796f5e97e OP_EQUAL
</code></pre>
<p>สคริปต์ P2SH นี้อ้างอิงไปยังแฮชของ redeem script ซึ่งได้กำหนดเงื่อนไขการใช้จ่ายแบบ multisig 2-of-3 เอาไว้เพื่อใช้ในการปลดล๊อคเงินทุน การจะใช้จ่าย output นี้ บริษัทของโมฮัมเหม็ดจะต้องแสดง redeem script ซึ่งมีค่าแฮชตรงกันกับ script hash ที่อยู่ภายใน P2SH output พร้อมกับลายเซ็นที่จำเป็นตามเงื่อนไขของ redeem script นั้น โดยใส่ทั้งหมดไว้ภายใน transaction input:</p>
<pre><code>[...]
"vin" : [
  "txid": "abcdef12345...",
  "vout": 0,
  "scriptSig": “&lt;SigA&gt; &lt;SigB&gt; &lt;2 PubA PubB PubC PubD PubE 5 OP_CHECKMULTISIG&gt;”,
]
</code></pre>
<p>ทีนี้เรามาดูกันดีกว่าว่าตัวอย่างที่เกริ่นมาข้างต้นนี้จะถูกอัปเกรดเป็น segwit v0 ได้อย่างไร หากลูกค้าของนายโมฮัมเหม็ดใช้กระเป๋าเงินที่รับรอง segwit พวกเขาจะทำการชำระเงินได้โดยการสร้าง P2WSH output ซึ่งมีลักษณะดังนี้:</p>
<pre><code>0 a9b7b38d972cabc7961dbfbcb841ad4508d133c47ba87457b4a0e8aae86dbb89
</code></pre>
<p>เช่นเดียวกันกับตัวอย่างของ P2WPKH คุณจะเห็นได้ว่าสคริปต์แบบ segregated witness ที่ทำงานในแบบเดียวกันนั้นเรียบง่ายกว่า และนอกจากนี้ยังช่วยลด overhead ของเทมเพลตที่พบในสคริปต์ P2SH ลงไปได้มากอีกด้วย เนื่องจากสคริปต์ของ segreted witness นั้นประกอบด้วยค่าเพียง 2 ค่าที่ถูกใส่ลงในแสตก นั่นคือ witness version(0) และค่าแฮชของ SHA256 ขนาด 32 ไบต์ของ witness script (ในบางครั้งอาจถูกเรียกว่า witness program)</p>
<blockquote>
<p>TIP: ในขณะที่ P2SH ใช้แฮชแบบ RIPEMD160(SHA256(script)) ขนาด 20 ไบต์ แต่ witness program ของ P2WSH จะใช้แฮชแบบ SHA256(script) ขนาด 32 ไบต์ ความแตกต่างในการเลือกอัลกอริทึมในการแฮชนี้ถูกออกแบบมาเพื่อเพิ่มความแข็งแกร่งในด้านความปลอดภัยให้กับ P2WSH แต่ในบางกรณีก็มีบ้างที่ความปลอดภัยระดับ 128 บิตใน P2WSH นั้นมีความปลอดภัยเท่ากับ 80 บิตใน P2SH ดูรายละเอียดเพิ่มเติมได้ที่ P2SH collision attack</p>
</blockquote>
<p>หลังจากนั้นบริษัทของนายโมฮัมเหม็ดก็สามารถใช้จ่าย output แบบ P2WSH ได้โดยการนำเสนอ witness script ที่ถูกต้องพร้อมกับลายเซ็นในจำนวนที่เพียงพอเพื่อทำให้สคริปต์นั้นผ่านเงื่อนไขของ witness script และลายเซ็นเหล่านี้เองจะถูกรวมอยู่ในโครงสร้างของ witness โดยจะไม่มีข้อมูลใดถูกใส่ไว้ใน input script เนื่องจากนี่เป็น native witness program ซึ่งไม่ใช้ฟิลด์ input script เหมือนกับประเภท legacy</p>
<pre><code>[...]
"vin" : [
  "txid": "abcdef12345...",
  "vout": 0,
  "scriptSig": “”,
]
[...]
“witness”: “&lt;SigA&gt; &lt;SigB&gt; &lt;2 PubA PubB PubC PubD PubE 5 OP_CHECKMULTISIG&gt;”
[...]
</code></pre>
<h3>ความแตกต่างระหว่าง P2WPKH และ P2WSH</h3>
<p>ในสองหัวข้อก่อนหน้านี้เราได้อธิบายถึง witness program อยู่ 2 ประเภท ได้แก่ Pay to Witness Public Key Hash (P2WPKH) และ Pay to Witness Script Hash (P2WSH) โดย witness program ของทั้งสองประเภทนั้นมีหมายเลขเวอร์ชันเดียวกัน ตามด้วยการใส่ข้อมูลหนึ่งค่าลงในแสตกเหมือนกัน ทำให้รูปแบบของทั้งสองดูคล้ายคลึงกัน แต่การตีความของทั้งสองนั้นแตกต่างกันอย่างสิ้นเชิง โดยแบบหนึ่งจะถูกตีความเป็นแฮชของ public key ซึ่งปลดล๊อกได้ด้วยลายเซ็นในขณะที่อีกแบบหนึ่งนั้นจะถูกตีความเป็นค่าแฮชของสคริปต์ซึ่งปลดล๊อกได้ด้วย witness script</p>
<p>และความแตกต่างที่สำคัญที่สุดระหว่างทั้งสองคือความยาวของ witness program:</p>
<ul>
<li>witness program ของ P2WPKH มีขนาด 20 ไบต์  </li>
<li>witness program ของ P2WSH มีขนาด 32 ไบต์</li>
</ul>
<p>ความแตกต่างเพียงจุดเดียวนี้เองทำให้โหนดของบิตคอยน์สามารถแยกได้ว่า witness program นั้นเป็นของสคริปต์รูปแบบใด โดยดูจากเพียงแค่ความยาวของแฮช</p>
<h3>การอัปเกรดไปใช้ Segregated Witness</h3>
<p>จากตัวอย่างก่อนหน้านี้ เราจะเห็นได้ว่าการอัปเกรดไปใช้ segregated witness นั้นเป็นกระบวนการที่มี 2 ขั้นตอนด้วยกัน ขั้นตอนแรก คือกระเป๋าเงินต้องสามารถสร้าง output แบบ segwit ได้ จากนั้น output เหล่านี้จึงสามารถถูกใช้ได้ด้วยกระเป๋าเงินที่รู้วิผะีสร้างธุรกรรมแบบ segregated witness โดยในตัวอย่างที่กล่าวมากระเป๋าเงินของอลิซสามารถสร้าง output จ่ายไปยังสคริปต์แบบ segregated witness ได้และกระเป๋าของบ๊อบก็รองรับ segwit และสามารถใช้จ่ายได้เช่นกัน</p>
<p>Segregated witness ถูกนำมาใช้ในลักษณะของการอัปเกรดที่ยังคงเข้ากันได้ย้อนหลัง (backward-compatible) ซึ่งทำให้ไคลเอนต์ทั้งแบบเก่าและแบบใหม่สามารถอยู่ร่วมกันได้ นักพัฒนากระเป๋าเงินได้อัปเกรดซอฟต์แวร์ของตนอย่างอิสระเพื่อเพิ่มความสามารถรองรับ segwit ส่วนรูปแบบเดิมอย่าง P2PKH และ P2SH ก็ยังคงใช้งานได้ตามปกติสำหรับกระเป๋าเงินที่ยังไม่ได้อัปเกรด</p>
<p>สิ่งนี้ทำให้เกิดสองสถานการณ์สำคัญ ซึ่งจะถูกอธิบายในหัวข้อถัดไป:</p>
<ul>
<li>ความสามารถของกระเป๋าเงินฝั่งผู้จ่ายที่ไม่รองรับ segwit ในการชำระเงินให้กับกระเป๋าเงินฝั่งผู้รับที่สามารถประมวลผลธุรกรรมแบบ segwit ได้  </li>
<li>ความสามารถของกระเป๋าเงินฝั่งผู้จ่ายที่รองรับ segwit ในการรับรู้และแยกแยะได้ว่าผู้รับรายใดรองรับ segwit และรายใดไม่รองรับ โดยพิจารณาจากรูปแบบของ address</li>
</ul>
<h3>การฝัง segregated witness ไว้ภายใน P2SH</h3>
<p>สมมุติว่ากระเป๋าเงินของอลิซยังไม่ได้อัปเกรดเป็น segwit แต่กระเป๋าเงินของบ๊อบได้อัปเกรดแล้ว และสามารถจัดการธุรกรรมแบบ segwit ได้ ทั้งอลิซและบ๊อบยังสามารถใช้ output แบบดั้งเดิมที่ไม่ใช้ segwit ได้ตามปกติ อย่างไรก็ตามบ๊อบมักจะต้องการใช้ segwit เพื่อช่วยลดค่าธรรมเนียมธุรกรรมโดยอาศัยต้นทุนที่ต่ำกว่าสำหรับส่วน witness</p>
<p>ในกรณีนี้กระเป๋าเงินของบ๊อบสามารถสร้างที่อยู่แบบ P2SH ซึ่งภายในบรรจุสคริปต์ segwit อยู่ได้ กระเป๋าเงินของอลิซสามารถส่งเงินไปยัง address นั้นได้โดยไม่จำเป็นต้องรู้จักหรือเข้าใจ segwit แต่อย่างใด นอกจากนี้กระเป๋าเงินของบ๊อบก็สามารถใช้จ่าย output นั้นด้วยธุรกรรมแบบ segwit ได้ และทำให้ได้ประโยชน์จาก segwit และช่วยลดค่าธรรมเนียมธุรกรรมได้</p>
<p>สคริปต์ witness ทั้งสองรูปแบบ คือ P2WPKH และ P2WSH สามารถถูกฝังอยู่ภายใน address แบบ P2SH ได้ โดยจะเรียกว่า nested P2WPKH และ nested P2WSH ตามลำดับ</p>
<h3>Nested pay to witness public key hash</h3>
<p>รูปแบบแรกของ output script ที่เราจะพิจรณาคือ nested P2WPKH ซึ่งเป็น witness program แบบ pay to witness public key hash ที่ถูกฝังอยู่ภายในสคริปต์แบบ pay to script hash เพื่อให้กระเป๋าเงินที่ยังไม่รู้จัก segwit สามารถส่งเงินไปยัง output นี้ได้</p>
<p>กระเป๋าเงินของบ๊อบจะสร้าง P2WPKH witness program จาก public key ของ Bob จากนั้นนำ witness program นี้ไปแฮช และนำค่าแฮชที่ได้ไปเข้ารหัสเป็นสคริปต์แบบ P2SH โดยตัวสคริปต์นี้เองจะถูกแปลงเป็น address ของบิตคอยน์ ซึ่งจะเป็น address ที่ขึ้นต้นด้วย 3 เช่นเดียวกันกับ Pay to script hash</p>
<p>กระเป๋าเงินของบ๊อบเริ่มต้นด้วย witness version และ witness program แบบ P2WPKH ที่เราได้เห็นก่อนหน้านี้:</p>
<pre><code>0 ab68025513c3dbd2f7b92a94e0581f5d50f654e7
</code></pre>
<p>ข้อมูลนี้จะประกอบด้วย witness version และค่าแฮชของ public key ของบ๊อบขนาด 20 ไบต์</p>
<p>จากนั้นกระเป๋าของเขาจะนำข้อมูลนี้ไปแฮช โดยเริ่มจาก SHA256 ก่อน แล้วตามด้วย RIPEMD 160 ทำให้ได้ค่าแฮชขนาด 20 ไบต์อีกค่าหนึ่ง ต่อมาแฮชของ redeem script นี้จะถูกแปลงเป็น address ของบิตคอยน์ในท้ายที่สุด จากนั้นกระเป๋าเงินของอลิซก็สามารถส่งเงินไปยังที่อยู่ 37Lx99uaGn5avKBxiW26HjedQE3LrDCZru ได้เช่นเดียวกันกับการส่งไปยัง address ทั่ว ๆ ไป</p>
<p>เพื่อจ่ายเงินให้บ๊อบ กระเป๋าเงินของอลิซจะล็อกเอาต์พุตด้วยสคริปต์แบบ P2SH ดังนี้:</p>
<pre><code>OP_HASH160 3e0547268b3b19288b3adef9719ec8659f4b2b0b OP_EQUAL
</code></pre>
<p>แม้ว่ากระเป๋าเงินของอลิซจะไม่รองรับ segwit เลยก็ตาม แต่การชำระเงินที่เธอสร้างขึ้นนี้บ๊อบก็ยังสามารถนำไปใช้จ่ายต่อได้ด้วยธุรกรรมแบบ segwit</p>
<h3>Nested pay to witness script hash</h3>
<p>ในทำนองเดียวกันกับ witness program แบบ P2WSH สำหรับสคริปต์ multisig หรือสคริปต์ที่ซับซ้อนอื่น ๆ สามารถถูกฝังอยู่ภายใน address แบบ P2SH ได้ ทำให้กระเป๋าเงินใด ๆ ก็ตามสามารถชำระเงินได้ในลักษณะที่เข้ากันได้กับ segwit</p>
<p>ดังที่เราเห็นในหัวข้อของ Pay to witness script hash (P2WSH) บริษัทของโมฮัมเหม็ดใช้การชำระเงินแบบ segregated witness ไปยังสคริปต์ multisignature เพื่อให้ลูกค้าทุกรายสามารถชำระเงินให้บริษัทของเขาได้ ไม่ว่ากระเป๋าเงินของลูกค้าจะอัปเกรดรองรับ segwit แล้วหรือไม่ กระเป๋าเงินของโมฮัมเหม็ดก็สามารถผัง P2WSH witness program ไว้ภายในสคริปต์แบบ P2SH ได้</p>
<p>ขั้นแรกกระเป๋าเงินของโมฮัมเหม็ดจะนำ witness script ไปแฮชด้วย SHA256(ครั้งเดียว) และได้ค่าแฮชดังนี้:</p>
<pre><code>9592d601848d04b172905e0ddb0adde59f1590f1e553ffc81ddc4b0ed927dd73
</code></pre>
<p>ถัดมา witness script ที่ถูกแฮชแล้วจะถูกแปลงให้เป็น P2WSH witness program ที่มีการใส่เวอร์ชันนำหน้า:</p>
<pre><code>0 9592d601848d04b172905e0ddb0adde59f1590f1e553ffc81ddc4b0ed927dd73
</code></pre>
<p>จากนั้น witness program นี้จะถูกแฮชอีกครั้งด้วย SHA256 และ RIPEMD160 ตามลำดับ ทำให้ได้แฮชขนาด 20 ไบต์ใหม่ดังงนี้:</p>
<pre><code>86762607e8fe87c0c37740cddee880988b9455b2
</code></pre>
<p>ต่อมากระเป๋าเงินจะสร้าง address บิตคอยน์ แบบ P2SH จากแฮชนี้:</p>
<pre><code>3Dwz1MXhM6EfFoJChHCxh1jWHb8GQqRenG
</code></pre>
<p>โดยจากจุดนี้เอง ลูกค้าของโมฮัมเหม็ดก็สามารถชำระเงินมายัง address นี้ได้ แม้ว่ากระเป๋าเงินของพวกเขาจะไม่รับรอง segwit ก็ตามเพื่อส่งเงินให้โมฮัมเหม็ด กระเป๋าเงินของผู้ส่งจะล็อก output ด้วยสคริปต์ P2SH ดังต่อไปนี้:</p>
<pre><code>OP_HASH160 86762607e8fe87c0c37740cddee880988b9455b2 OP_EQUAL
</code></pre>
<p>จากนั้นบริษัทของโมฮัมเหม็ดก็สามารถสร้างธุรกรรมแบบ segwit เพื่อใช้จ่ายเงินเหล่านี้ได้ โดยได้รับประโยชน์จากคุณสมบัติของ segwit รวมถึงค่าธรรมเนียมธุรกรรมที่ต่ำลง</p>
<h2>Merklized Alternative Script Trees (MAST)</h2>
<p>การใช้ OP_IF นั้นสามารถกำหนดเงื่อนไขสำหรับการใช้จ่ายได้หลายรูปแบบ แต่แนวทางนี้เองก็มีข้อเสียที่ไม่พึงประสงค์อยู่หลายประการ อาทิเช่น</p>
<h5>น้ำหนัก(ต้นทุนในการทำธุรกรรม)</h5>
<p>ทุกเงื่อนไขที่เพิ่มเข้าไปในสคริปต์นั้นจะทำให้สคริปต์มีขนาดใหญ่ขึ้น ซึ่งจะส่งผลให้ต้นทุนในการทำธุรกรรมเพิ่มขึ้นเมื่อต้องการใช้จ่ายบิตคอยน์ที่ถูกป้องกันไว้ด้วยสคริปต์นี้</p>
<h5>ข้อจำกัดด้านขนาด</h5>
<p>แม้ว่าคุณจะยอมจ่ายค่าธรรมเนียมเพิ่มเพื่อให้ใส่เงื่อนไขได้มากขึ้นก็ตาม แต่ก็ยังมีข้อจำกัดในด้านของเงื่อนไขสูงสุดที่สามารถใส่ได้ในสคริปต์อยู่ดี อย่างเช่น legacy script ถูกจำกัดขนาดไว้ที่ 10,000 ไบต์ ซึ่งทำให้ในทางปฏิบัตินั้นสามารถใส่ได้เพียงไม่กี่ร้อยเงื่อนไขเท่านั้น และแม้ว่าจะสามารถสร้างสคริปต์ที่มีขนาดใหญ่เท่ากับบล๊อคทั้งบล๊อคได้ ก็ยังจะมีได้เพียงประมาณ 20,000 เงื่อนไขเท่านั้นที่ใช้งานได้จริง ซึ่งถือว่ามากแล้วสำหรับการชำระเงินแบบง่าย ๆ แต่ก็เล็กมากเมื่อเทียบกับการใช้งานบางอย่างที่จินตนาการไว้สำหรับบิตคอยน์</p>
<h5>การขาดแคลนความเป็นส่วนตัว</h5>
<p>ทุกเงื่อนไขที่มีการเพิ่มเข้าไปในสคริปต์นั้นจะกลายเป๋นข้อมูลสาธารณะเมื่อคุณใช้จ่ายบิตคอยน์ที่ถูกปกป้องไว้ด้วยสคริปต์นั้น ๆ ตัวอย่างเช่นทนายความและหุ้นส่วนทางธุรกิจของนายโมฮัมเหม็ดก็จะสามารถเห็นสคริปต์ทั้งหมดไม่ว่าจะในตัว multi-signature หรือ timelock ก็ตาม และทุกครั้งที่มีการใช้จ่ายกับบัญชีนี้ จะทำให้ทนายความของพวกเขาติดตามธุรกรรมทั้งหมดได้แม้ว่าจะไม่ได้ร่วมลงนามก็ตาม</p>
<p>แต่อย่างไรก็ตาม บิตคอยน์มีการใช้โครงสร้างข้อมูลที่เรียกว่า merkle tree อยู่แล้ว ซึ่งมันช่วยให้สามารถตรวจสอบได้ว่าองค์ประกอบใด ๆ เป็นสมาชิกของข้อมูลหรือไม่โดยไม่จำเป็นต้องเปิดเผยหรือระบุสมาชิกอื่น ๆ ทั้งหมดของชุดนั้น</p>
<p>ซึ่งเราจะได้เรียนรู้เกี่ยวกับ merkle tree มากขึ้นในหัวข้อของ merkle trees แต่สาระสำคัญคือ สมาชิกแต่ละตัวของชุดข้อมูลที่เราต้องการ (เช่น เงื่อนไขการอณุญาตที่มีความยาวเท่าใดก็ได้) สามารถนำไปผ่านฟังก์ชันแฮชแล้วนำแฮชมารวมกันอีกครั้งเพื่อสร้างค่าผูกมัดของกิ่งทั้งสองกิ่ง ซึ่งเรียกว่า branch commitment</p>
<p>โดยค่าผูกมัดของกิ่งทั้งสองเองก็สามารถสร้างได้ด้วยวิธีเดียวกัน ขั้นตอนนี้จะถูกทำซ้ำเรื่อย ๆ จนเหลือตัวเดียวและเราจะเรียกตัวนั้นว่า merkle root</p>
<p>จากตัวอย่างสคริปต์ในหัวข้อ Variable multi-signature with timelock เราสามารถสร้าง Merkle tree สำหรับเงื่อนไขการอณุญาตทั้งสามแบบใน A MAST ที่มีสามสคริปต์ย่อยได้<br> <img src="https://image.nostr.build/3d6230c0a0ee745196a957384b79606c729d3829efbaf1b4125e357bc6a68f24.jpg" alt="image"></p>
<p>ในขณะนี้เราสามารถสร้างหลักฐานการเป็นสมาชิกแบบกระทัดรัด (Compact membership proof) เพื่อพิสูจน์ได้ว่าเงื่อนไขการอนุญาตเงื่อนไขใดเงื่อนไขหนึ่งเป็นสมาชิกของ merkle tree โดยไม่ต้องเปิดเผยรายละเอียดใด ๆ ของสมาชิกอื่น ๆ ใน merkle tree สามาดูได้ในตัวอย่างของ A MAST membership proof for one of the subscripts และสังเกตว่าโหนดที่แรเงาไว้สามารถคำนวณได้จากข้อมูลอื่นที่ผู้ใช้ให้มา ดังนั้นจึงไม่จำเป็นต้องระบุโหนดเหล่านั้นในขณะทำการใช้จ่าย<br> <img src="https://image.nostr.build/3a5c3e43c266357582fb4bc17eedefaed398306d84750072af061d07cc99e513.jpg" alt="image"></p>
<p>ค่าแฮชที่ใช้ในการสร้างคอมมิจเมนต์แต่ละตัวมีขนาด 32 ไบต์ ดังนั้นการพิสูจน์ว่าการใช้จ่ายใน A MAST membership proof for one of the subscripts ได้รับอนุญาต (โดยใช้ merkle tree และเงื่อนไขที่เกี่ยวข้อง) และได้รับการพิสูจน์ตัวตน(ด้วยการใช้ลายเซ็น) จะใช้ข้อมูลทั้งหมด 383 ไบต์เมื่อเปรียบเทียบกันแล้ว การใช้จ่ายแบบเดียวกันโดยไม่ใช้ merkle tree (กล่าวคือ ต้องแสดงเงื่อนไขทั้งหมดที่เป็นไปได้) ที่จะใช้ข้อมูลถึง 412 ไบต์</p>
<p>การประหยัดได้ 29 ไบต์ (7%) ในตัวอย่างนี้ยังสะท้อนให้เห็นถึงศักยภาพในการประหยัดได้ไม่ครบถ้วน เนื่องจากลักษณะของ merkle tree ที่เป็นโครงสร้างแบบไบนารีทรีนั้น ทุกครั้งที่มีการเพิ่มจำนวนสมาชิกในเซตเพิ่มขึ้นเป็นสองเท่า เราจำเป็นต้องเพิ่มคอมมิตเมนต์ขนาด 32 ไบต์เพียงตัวเดียวเท่านั้น เช่นในกรณีที่มีทั้งหมด 3 เงื่อนไขเราจำเป็นต้องใช้คอมมิตเมนต์ 3 ตัว (ซึ่งหนึ่งในนั้นคือ merkle root ที่ต้องถูกรวมในการอณุญาตอยู่แล้ว) และเรายังสามารถมีคอมมิตเมนต์ได้ถึง 4 ตัวด้วยต้นทุนที่เท่าเดิม และหากมีคอมมิตเมนต์เพิ่มขึ้นอีกตัวหนึ่งจะทำให้เราสามารถรองรับเงื่อนไขได้สูงสุดถึงแปดเงื่อนไขด้วยกัน และในทำนองเดียวกันหากเรามี 16 คอมมิตเมนต์(ขนาดรวมเป็น 512 ไบต์) เราจะสามารถมีเงื่อนไขการอณุญาตได้มากกว่า 32,000 เงื่อนไข ซึ่งนั้นก็มากเกินกว่าที่จะนำไปใช้ได้จริงในบล็อก ๆ หนึ่งที่เต็มไปด้วยธุรกรรมที่มีคำสั่ง OP_IF ทั้งหมดเสียอีก และหากเราใช้ถึง 128 คอมมิตเมนต์ (4096 ไบต์) จำนวนเงื่อนไขที่เราจะสามารถสร้างได้ในเชิงทฤษฏีจะมีมากเกินกว่าเงื่อนไขทั้งหมดที่คอมพิวเตอร์ทุกเครื่องบนโลกจะสามารถสร้างขึ้นมาได้</p>
<p>โดยทั่วไปแล้ว เงื่อนไขการอณุญาตไม่ได้มีโอกาสถูกใช้งานเท่า ๆ กันทั้งหมด ในกรณีตัวอย่างของเรา เราคาดว่าโมฮัมเหม็ดและหุ้นส่วนของเขาจะใช้จ่ายเป็นประจำ ส่วนเงื่อนไขการหน่วงเวลามีไว้ใช้ในกรณีที่เกิดปัญหาเท่านั้น เราสามารถนำความรู้นี้มาใช้ในการปรับโครงสร้างของ tree ใหม่ทั้งหมดได้ ดังที่แสดงในรูปภาพข้างล่างนี้ โดยมีการจัดสคริปต์ที่คาดว่าจะมีการใช้งานมากที่สุดอยู่ในตำแหน่งที่เหมาะสมที่สุด</p>
<p> <img src="https://image.nostr.build/a60366f9810f9eb3e364bc0d83e4ef733991fdbd3ae1625c9acfe45256b08578.jpg" alt="image"></p>
<p>ในกรณีนี้ เราจำเป็นที่จะต้องให้คอมมิตเมนต์เพียงสองค่าเท่านั้นในกรณีที่ใช้จ่ายแบบที่คาดว่าจะบ่อยที่สุด (ประหยัดได้ 32 ไบต์) แม้ว่าการใช้จ่ายด้วยกรณีอื่น ๆ ยังคงจำเป็นต้องใช้ 3 คอมมิตเมนต์ก็ตาม ซึ่งแบบว่าหากคุณทราบหรือสามารถคาดเดาถึงความน่าจะเป็นของการใช้เงื่อนไขแต่ละแบบได้ คุณจะสามารถใช้อัลกอริทึมอย่าง Huffman เพื่อจัดวางเงื่อนไขเหล่านี้ลงไปในตำแหน่งที่ทำให้มีประสิทธิภาพสูงสุดได้ โดยสามารถดูรายละเอียดเพิ่มเติมได้ใน BIP341</p>
<p>นอกจากจะเพิ่มความซับซ้อนให้กับบิตคอยน์มาอีกเล็กน้อยแล้ว MAST ก็ยังแทบไม่มีข้อเสียที่สำคัญอะไรต่อบิตคอยน์เลย และก่อนที่จะพบแนวทางที่ดีกว่าในภายหลัง (เดี๋ยวเราจะได้เห็นในหัวข้อ taproot) ก็มีข้อเสนอที่แข็งแรงอยู่แล้วถึงสองอันสำหรับ MAST นั้นคือ BIP114 และ BIP116</p>
<h3>MAST เทียบกับ MAST</h3>
<p>แนวคิดแรกเริ่มของสิ่งที่ปัจจุบันเราเรียกว่า MAST ในบิตคอยน์ คือแนวคิดของ merklized abstract syntax trees (ต้นไม้โครงสร้างไวยากรณ์เชิงนามธรรมที่ถูกเมอร์เคิลไลซ์) ในต้นไม้โครงสร้างไวยากรณ์เชิงนามธรรม (AST) แต่ละเงื่อนไขในสคริปต์จะสร้างสาขาใหม่ ดังที่แสดงไว้ในรูปภาพข้างล่าง<br> <img src="https://image.nostr.build/2278f96ec80d7fe7e93c87a73ef70b42934a05bc110abcf9c2d1aa1c41433d91.jpg" alt="image"></p>
<p>AST นั้นได้ถูกใช้อย่างแพร่หลายในโปรแกรมที่ทำหน้าที่แยกวิเคราห์และปรับแต่งโค้ดของโปรแกรมอื่น ๆ เช่น คอมไพเลอร์ หากนำ AST มาใช้ในรูปแบบที่ถูกเมอร์เคิลไลซ์ (merklized AST) ก็จะสามารถผูกมัดได้กับทุกส่วนของโปรแกรม และเปิดให้ใช้คุณสมบัติต่าง ๆ ที่อธิบายไว้ใน merklized Alternative Script Trees (MAST) แต่อย่างไรก็ตามวิธีนี้จะต้องเปิดเผยค่าแฮชขนาด 32 ไบต์อย่างน้อยหนึ่งค่า สำหรับทุกส่วนย่อยของโปรแกรม ซึ่งทำให้ไม่ค่อยมีประสิธิภาพในด้านพื้นที่ของบล็อกเชนสำหรับโปรแกรมส่วนใหญ่</p>
<p>สิ่งที่ผู้คนส่วนใหญ่มักเรียกว่า MAST ในบริบทของบิตคอยน์ในปัจจุบันคือ merklized alternative script trees ซึ่งเป็น backronym ที่ถูกตั้งขึ้นโดยนักพัฒนา Anthony Towns ซึ่ง alternative script tree คือชุดของสคริปต์หลายสคริปต์ ซึ่งแต่ละสคริปต์นั้นมีความสมบูรณืในตัวเองและสามารถเลือกใช้งานได้เพียงหนึ่งสคริปต์เท่านั้น ทำให้สครืปต์เหบ่านี้เป็นทางเลือกแทนกัน ซึ่งแสดงไว้ในภาพด้านล่าง</p>
<p> <img src="https://image.nostr.build/d87c36148baa4429f15264771a0341e787e343df3de17136c16db0d3d61397d6.jpg" alt="image"></p>
<p>ต้นไม้สคริปต์แบบทางเลือก (alternative script trees) ต้องการเพียงเปิดเผยไดเจสเพียง 32 ไบต์เท่านั้นสำหรับความลึกในแต่ละลำดับที่ผู้ใช้เลือกใช้และ merkle root สำหรับสคริปต์ส่วนใหญ่ นี่ถือเป็นการใช้พื้นที่ในบล๊อกเชนที่มีประสิธิภาพมากกว่าเป็นอย่างมาก</p>
<h2>Pay to Contract (P2C)</h2>
<p>ดังที่เราได้เห็นในบทก่อนหน้าในหัวข้อ public child key derivation คณิตศาสตร์ของการเข้ารหัสด้วยเส้นโค้งวงรี (Eliptic Curve Cryptography:ECC) อณุญาตให้อลิซใช้ private key เพื่อสร้าง public key ที่เธอมอบให้บ๊อบ สามารถเพิ่มค่าที่เป็นไปได้ค่าใดก็ได้เข้ามาใน public key นั้น  เพื่อสร้าง public key ใหม่ขึ้นมา หากบ๊อบส่งค่าที่เขาเพิ่มนั้นกลับไปให้อลิซ เธอก็สามารถนำค่าเดียวกันไปบวกกับ private key ของเธอ เพื่อสร้าง private key ที่สอดคล้องกับ public key ที่ถูกอนุพันธ์ขึ้นมาได้</p>
<p>สรุปสั้น ๆ ก็คือบ๊อบสามารถสร้าง child public key ซึ่งมีเพียงอลิซเท่านั้นที่สามารถสร้าง private key ที่สอดคล้องกันขึ้นมาได้ สิ่งนี้เป็นประโยชน์สำหรับการกู้คืนกระเป๋าเงินแบบ Hierarchical Determinstic (HD) ตามมาตรฐานของ BIP32 แต่ก็ยังสามารถนำไปใช้ในวัตถุประสงค์อื่นได้อีกด้วย</p>
<p>ลองจินตนาการดูสิว่าบ๊อบต้องการซื้อของบางอย่างจากอลิซ แต่เขาก็ต้องการความสามารถในการพิสูจน์ภายหลังได้ว่าเขาจ่ายเงินไปเพื่ออะไร ในกรณีที่เกิดข้อพิพาทขึ้นอลิซและบ๊อบจึงตกลงกันเกี่ยวกับชื่อของสินค้าหรือบริการที่ขาย (เช่น “พอดแคสต์ของอลิซตอนที่#123”) แล้วแปลงคำอธิบายนั้นให้เป็นตัวเลข โดยการนำไปแฮชและตีความค่าแฮชที่ได้เป็นตัวเลข จากนั้นบ๊อบนำตัวเลขนั้นไปบวกกับ public key ของอลิซและจ่ายเงินให้ไป กระบวนการนี้เรียกว่า key tweaking และตัวเลขนั้นเรียกว่า tweak</p>
<p>อลิซสามารถใช้จ่ายเงินดังกล่าวได้โดยการปรับแต่ง(tweak) private key ของตัวเธอเองด้วยเลขเดียวกัน</p>
<p>และในภายหลังบ๊อบเองก็สามารถพิสูจน์กับใครก็ตามได้ว่าเขาได้จ่ายเงินให้อลิซเพื่ออะไร โดยการเปิดเผยถึงกุญแจตั้งต้น (underlying key) ของอลิซและคำอธิบายของสินค้าหรือบริการที่ทั้งสองใช้ร่วมกัน ทุกคนสามารถตรวจสอบได้ว่า public key ที่ถูกนำไปใช้ชำระเงินนั้นเท่ากับกุญแจตั้งต้นบวกกับค่าแฮช ของคำอธิบายนั้น และหากอลิซยอมรับว่ากุญแจดังกล่าวเป็นของเธอ ก็ย่อมแสดงว่าเธอยอมรับว่าเธอเป็นผู้รับเงินก้อนนั้น และหากอลิซเป็นผู้ใช้จ่ายเงินออกไป ก็ยิ่งเป็นหลักฐานยืนยันเพิ่มเติมว่าเธอรู้คำอธิบายนั้นตั้งแต่ตอนที่เธอลงนามในธุรกรรมการจ่ายเงิน เพราะเธอสามารถสร้างลายเซ็นที่ถูกต้องได้สำหรับ public key ที่ถูกปรับแต่ง ได้ก็ต่อเมื่อเธอรู้ว่าค่า tweak คืออะไรเท่านั้น</p>
<p>หากอลิซและบ๊อบไม่ได้ตัดสินใจเปิดเผยคำอธิบายที่พวกเขาใช้ต่อสาธารณะการชำระเงินระหว่างทั้งสองก็จะดูไม่ต่างจากการชำระเงินทั่วไปอื่น ๆ และจะไม่ก่อให้เกิดการสูญเสียความเป็นส่วนตัวแต่อย่างใด</p>
<p>เนื่องจาก P2C มีความเป็นส่วนตัวโดยปริยาย เราจึงไม่สามารถทราบได้ว่ามันถูกใช้งานตามวัตถุประสงค์ดั้งเดิมบ่อยเพียงใด ในทางทฤษฏีแล้ว การชำระเงินทุกครั้งอาจใช้วิธีนี้ก็ได้ แม้ว่าเราจะมองว่าสถานการณ์เช่นนั้นไม่น่าเกิดขึ้นก็ตาม แต่ในปัจจุบันนั้น P2C ถูกใช้อย่างแพร่หลายในรูปแบบที่แตกต่างกันออกไปเล็กน้อย ซึ่งเราจะได้เห็นกันใน taproot ที่จะอธิบายต่อภายหลัง</p>
<h2>Scriptless Multisignatures and Threshold Signatures</h2>
<p>ในการทำ Scripted Multisignatures คือการพิจรณาสคริปต์ที่กำหนดให้ต้องมีลายเซ็นจากหลายฝ่าย อย่างไรก็ตามยังมีอีกหนึ่งวิธีในการบังคับให้ต้องใช้กุญแจหลายดอกร่วมกัน ซึ่งก็น่าจะทำให้สับสนได้ไม่น้อย เพราะมันก็ถูกเรียกว่า multisignature เช่นกัน แต่เพื่อแยกความแตกต่างระหว่างสองแนวทางนี้ ในส่วนนี้เราจะเรียกเวอร์ชันที่ใช้ opcode แบบ OP_CHECKSIG ว่า script multisignatures และอีกเวอร์ชันที่จะพูดถึงต่อไปว่า scriptless multisignatures</p>
<p>Scriptless multisignature ทำงานโดยให้ผู้เข้าร่วมแต่ละคนสร้างความลับของตนเองขึ้นมาคล้ายกับวิธีสร้าง private key โดยเราจะเรียกความลับนี้ว่า partial private key โดยแม้ว่ามันจะมีความยาวเท่ากับ private key แบบปกติทุกประการจาก partial private key อันนี้ ผู้เข้าร่วมแต่ละคนจะอนุมาน partial public key โดยใช้อัลกอริทึมเดียวกันกับที่ใช้สร้าง public key ทั่วไป ตามที่อธิบายไว้ในหัวข้อ public key derivation จากนั้นผู้เข้าร่วมทุกคนจะแชร์ partial public key ของตนให้กับผู้เข้าร่วมอื่น ๆ และนำกุญแจทั้งหมดมารวมกันเพื่อสร้าง scriptless multisignature public key เพียงดอกเดียว</p>
<p>กุญแจสาธรณะที่ถูกรวมกันนี้จะมีลักษณะไม่ต่างจาก public key ทั่วไป บุคคลที่สามไม่สามารถแยกแยะได้ว่า public key นี้เกิดจากผู้ใช้หลายคนร่วมกัน หรือเป็น public key ธรรมดาที่สร้างขึ้นโดยผู้ใช้เพียงคนเดียว</p>
<p>สำหรับการใช้จ่ายบิตคอยน์ที่ถูกป้องกันด้วย scriptless multisignature public key ผู้เข้าร่วมแต่ละคนจะสร้างลายเซ็นย่อย (partial signature) ของตนเอง จากนั้นลายเซ็นย่อยเหล่านี้จะถูกรวมเข้าด้วยกันเพื่อสร้างเป็นลายเซ็นที่สมบูรณ์ (บางที่เรียกว่า Full signature) ซึ่งก็มีวิธีที่เป็นที่รู้จักกันหลายรูปแบบสำหรับการสร้างและรวมลายเซ็น ซึ่งเราจะกลับมาลงลึกในประเด็นนี้กันอีกครั้งในหัวข้อ Signature (บทที่ 8) และเช่นเดียวกันกับกรณีของ public key สำหรับ scriptless multisignatures ลายเซ็นที่ได้จากกระบวนการนี้จะมีหน้าตาเหมือนกับลายเซ็นทั่วไปทุกประการ บุคคลที่สามไม่สามารถตรวจสอบได้ว่าลายเซ็นนั้นถูกสร้างขึ้นโดยคนเพียงคนเดียวหรือเกิดจากความร่วมมือของผู้คนจำนวนมาก แม้ว่าจะเป็นการร่วมมือกันระดับล้านคนก็มองไม่ออก</p>
<p>Scriptless multisignatures มีทั้งขนาดเล็กกว่าและมีความเป็นส่วนตัวสูงกว่า scripted multisignatures อย่างชัดเจน สำหรับ scripted multisignatures จำนวนไบต์ที่ต้องบันทึกลงในธุรกรรมจะเพิ่มขึ้นตามจำนวนกุญแจและลายเซ็นที่เกี่ยวข้อง ยิ่งมีผู้ลงนามมาก ข้อมูลในธุรกรรมก็ยิ่งใหญ่ตามไปด้วย แต่ในทางตรงกันข้ามกัน สำหรับ scriptless signatures ขนาดของข้อมูลจะคงที่ ไม่ว่าจะมีผู้เข้าร่วมกี่คนก็ตาม แม้จะมีส่วนร่วมโดยคนเป็นล้านคนก็ตาม แต่ละคนสร้าง partial key และ partial signature ของตนเอง ธุรกรรมที่ได้จะมีขนาดข้อมูลเท่ากันทุกประการกับกรณีที่มีผู้ใช้เพียงคนเดียวใช้กุญแจดอกเดียวและลายเซ็นเพียงอันเดียว</p>
<p>ในแง่ของความเป็นส่วนตัวก็เป็นไปในทิศทางเดียวกัน เนื่องจาก scripted multisignatures ต้องเพิ่มข้อมูลทุกครั้งที่มีการเพิ่มกุญแจหรือลายเซ็น ธุรกรรมจึงเปิดเผยโดยนัยว่ามีการใช้กุญแจและลายเซ็นจำนวนเท่าใด ซึ่งอาจทำให้สามารถคาดเดาได้ว่าธุรกรรมนั้นจะสร้างขึ้นโดยกลุ่มคนใด แต่สำหรับ scriptless multisignatures ธุรกรรมทุกอันจะมีลักษณะเหมือนกันหมด และยังเหมือนกับธุรกรรมแบบลายเซ็นเดียวด้วย ทำให้ไม่มีข้อมูลรั่วไหลลออกมาทำให้ลดทอนความเป็นส่วนตัวของผู้ใช้งาน</p>
<p>ส่วนสำหรับข้อเสียของ scriptless multisignatures มีอยู่สองประการ อย่างแรกคืออัลกอริทึมที่ปลอดภัยทั้งหมดซึ่งเป็นที่รู้จักกันในปัจจุบันสำหรับการสร้าง scriptless multisignatures บนบิตคอยน์ จำเป็นต้องมีรอบของการโต้ตอบกันหรือไม่ก็ต้องมีการจัดการสถานะที่รอบคอบกว่าเมื่อเทียบกับ scripted signatures สิ่งนี้กลายเป็นความท้าทายในกรณีที่ลายเซ็นนั้นถูกสร้างโดยอุปกรณ์ลงนามแบบฮาร์ดแวร์ซึ่งแทบไม่มีการเช็คสถานะ และกุญแจกระจายอยู่ในสถานที่ทางกายภาพที่แตกต่างกัน ตัวอย่างเช่น หากคุณเก็บอุปกรณ์ลงนามแบบฮาร์ดแวร์ไว้ในตู้เซฟของธนาคาร สำหรับ scripted multisignature คุณอาจจะต้องไปที่ตู้เซฟนั้นเพียงครั้งเดียว แต่สำหรับ scriptless แล้วคุณอาจต้องไปสองถึงสามครั้งเพื่อทำให้กระบวนการลงนามเสร็จสมบูรณ์</p>
<p>ส่วนข้อเสียอีกอย่างหนึ่งคือการลงนามแบบ threshold signing ไม่เปิดเผยว่าใครเป็นผู้ลงนามจริงใน scripted threshold signing ตัวอย่างเช่น อลิซ บ๊อบ และคอลไลร์ ตกลงกันว่าเพียงมีลายเซ็นจากใครก็ได้สองในสามคน ก็เพียงพอที่จะใช้จ่ายเงินก้อนนี้ได้ หากอลิซและบ๊อบเป็นผู้ลงนามจะต้องใส่ลายเซ็นของทั้งสองคนลงในบล๊อกเชนซึ่งทำให้ใครก็ตามที่รู้จักกุญแจของพวกเขาก็สามารถพิสูจน์ได้ว่าอลิซและบ๊อบเป็นผู้ลงนามและคอไลร์ไม่ใช่ผู้ลงนาม แต่ใน scriptless threshold signing ลายเซ็นที่เกิดจากอลิซและบ๊อบจะแยกไม่ออกจากลายเซ็นที่เกิดขึ้นโดยอลิซกับคอไลร์หรือจากบ๊อบกับคอไลร์ ซึ่งมันเป็นข้อดีด้านความเป็นส่วนตัว เนื่องจากมันไม่เปิดเผยว่าใครร่วมลงนามบ้าง แต่อย่างไรก็ตามมันก็มีข้อเสียตามมา นั้นก็คือแม้ว่าคอไลร์จะอ้างว่าเธอไม่ได้ลงนาม แต่ก็ไม่มีอะไรเลยที่สามารถพิสูจน์ได้ว่าเธอไม่ได้ลงนามจริง ๆ ซึ่งอาจเป็นปัญหาในแง่ความรับผิดชอบและการตรวจสอบย้อนหลัง</p>
<p>สำหรับผู้ใช้ที่ต้องมีการย้ายเงินเข้าออกบ่อย ๆ ข้อดีด้านขนาดธุรกรรมที่เล็กลง และความเป็นส่วนตัวที่เพิ่มขึ้นของ multisignatures มีประโยชน์มากกว่าความยุ่งยากที่อาจเกิดขึ้นเป็นครั้งคราวในการสร้างลายเซ็นและการตรวจสอบย้อนหลังของลายเซ็นเหล่านั้น</p>
<h2>Taproot</h2>
<p>เหตุผลอย่างหนึ่งที่ผู้คนเลือกใช้บิตคอยน์คือสามารถสร้างสัญญาที่ให้ผลลัพธ์ได้อย่างคาดการณ์ได้สูงมาก สัญญาทางกฎหมายที่บังคับใช้โดยศาลขึ้นอยู่กับการตัดสินใจของผู้พิพากษาและคณะลูกขุน ในทางกลับกัน สัญญาของบิตคอยน์มักจะต้องการการกระทำจากผู้เข้าร่วมแต่จะถูกบังคับใช้โดยโหนดแบบเต็มนับพันที่รันโค้ดเหมือนกัน เมื่อได้รับสัญญาเดียวกันและข้อมูลชุดเดียวกัน โหนดแบบเต็มทุกตัวจะให้ผลลัพธ์เหมือนกันเสมอ การเบี่ยงเบนใด ๆ หมายความว่าบิตคอยน์ถูกทำลายไปแล้ว ผู้พิพากษาและคณะลูกขุนสามารถยืดหยุ่นได้มากกว่าโปรแกรม แต่เมื่อไม่ต้องการหรือไม่จำเป็นต้องมีความยืดหยุ่นนั้น ความสามารถในการคาดการณ์ของสัญญาบิตคอยน์ถือเป็นคุณสมบัติสำคัญ</p>
<p>หากผู้เข้าร่วมทั้งหมดเห็นว่าผลลัพธ์ของสัญญากลายเป็นเรื่องที่คาดการณ์ได้ทั้งหมด จริง ๆ แล้วก็ไม่มีความจำเป็นที่พวกเขาจะต้องใช้สัญญาต่อไป พวกเขาอาจทำในสิ่งที่สัญญาบังคับให้ทำแล้วยุติสัญญา ในสังคม นี่คือวิธีที่สัญญาส่วนใหญ่ยุติ: หากผู้ที่เกี่ยวข้องพอใจ พวกเขาจะไม่ยื่นสัญญาต่อศาล ในบิตคอยน์ หมายความว่าสัญญาที่ย่อมต้องใช้พื้นที่บล็อกจำนวนมากในการยุติ ควรมีข้อคลอสหนึ่งที่อนุญาตให้ยุติโดยความพึงพอใจร่วมกันแทน</p>
<p>ใน MAST และ scriptless multisignatures การออกแบบสัญญาแบบยินยอมร่วมกันเป็นเรื่องง่าย เพราะเราเพียงทำให้หนึ่งในใบไม้ชั้นบนสุดของต้นสคริปต์เป็น scriptless multisignature ระหว่างผู้เข้าร่วมทั้งหมด ซึ่งเราจะแสดงให้เห็นในรูปภาพที่ได้เห็นข้างบนเราสามารถทำให้มันมีประสิทธิภาพยิ่งขึ้นโดยเปลี่ยนจาก scripted multisignature เป็น scriptless multisignature</p>
<p>แนวทางนี้เองถือว่ามีประสิทธิภาพและความเป็นส่วนตัวพอสมควร หากมีการใช้สัญญาการยินยอมร่วมกัน เราจำเป็นต้องเปิดเผยเพียง merkle branch เดียว และสิ่งที่ถูกเปิดเผยก็มีแค่ว่าลายเซ็นใดที่ถูกใช้เท่านั้น ซึ่งอาจเป็นลายเซ็นจากคนเพียงคนเดียว หรือจากผู้เข้าร่วมหลายพันคนก็ไม่ได้มีใครแยกแยะได้</p>
<p>อย่างไรก็ตามในปี 2018 นักพัฒนาได้ตระหนักได้ว่าเราสามารถทำให้ดีกว่านี้ได้อีก หากนำแนวคิด pay to contract มาใช้ร่วมด้วย</p>
<p>ในคำอธิบายก่อนหน้านี้ของ Pay to contract ในหัวข้อ Pay to Contract (P2C) เราได้ tweak public key เพื่อผูกมัดกับข้อความของข้อตกลงระหว่างอลิซและบ๊อบ แทนที่จะเป็นเช่นนั้น เราสามารถผูกมัดกับโค้ดโปรแกรมของสัญญาได้โดยการผูกมัดกับ root ของ MAST tweak public key นั้นเป็น public key ปกติ ซึ่งหมายความว่ามันอาจต้องการลายเซ็นจากบุคคลเดียว หรืออาจเป็นจากหลายคน (หรืออาจถูกสร้างในลักษณะพิเศษให้เป็นไปไม่ได้ที่จะสร้างลายเซ็นสำหรับมัน) นั่นหมายความว่าเราสามารถทำให้สัญญาสำเร็จได้ด้วยลายเซ็นเดียวจากทุกฝ่ายที่เกี่ยวข้อง หรือโดยการเปิด branch ของ MAST ที่เราต้องการใช้ commitment tree ที่ประกอบด้วย public key และ MAST ดังกล่าวดังที่แสดงไว้ในภาพข้างล่าง<br> <img src="https://image.nostr.build/6155acd9c2852a12cea4667b89c2adc912d68aeab458213a729b13bbdb3d811b.jpg" alt="image"></p>
<p>สิ่งนี้เองที่ทำให้สัญญาแบบยินยอมร่วมกันโดยใช้ multisignature มีประสิธิภาพสูงและมีความเป็นส่วนตัวมากยิ่งขึ้น เพราะธุรกรรมที่สร้างโดยใช้โดยคนเพียงคนเดียวซึ่งต้องการให้ยุติโดยลายเซ็นเดียว (หรือ multisignature ที่สร้างโดยหลายกระเป๋าที่เขาควบคุม) จะดูเหมือนกันกับการใช้จ่ายของสัญญาแบบยินยอมร่วมกัน ไม่มีความแตกต่างกันบนบล๊อกเชน ในกรณีนี้ระหว่างการใช้จ่ายโดยกลุ่มผู้ใช้เป็นล้านคนในสัญญาที่ซับซ้อน หรือจ่ายโดยคนเพียงคนเดียว</p>
<p>เมื่อการใช้จ่ายสามารถทำได้โดยใช้เพียงกุญแจ เช่นกรณีลายเซ็นเดี่ยวหรือ scriptless multisig จะเรียกการใช้จ่ายแบบนี้ว่า keypath spending เมื่อใช้ต้นไม้ของสคริปต์ จะเรียกการใช้จ่ายแบบนั้นว่า scriptpath spending สำหรับการใช้จ่ายแบบ keypath ข้อมูลที่จะถูกใส่บนบล๊อกเชนคือ public key (ที่อยู่ใน witness program) และลายเซ็น (ที่อยู่บน witness stack)</p>
<p>สำหรับการใช้จ่ายแบบ scriptpath spending ข้อมูลบนบล๊อกเชนจะรวมถึง public key ด้วยโดย public key นี้จะถูกใส่ไว้ใน witness program และในบริบทนี้เรียกว่า taproot output key โครงสร้างของ witness จะประกอบไปด้วยข้อมูลต่อไปนี้:</p>
<ul>
<li>หมายเลขเวอร์ชัน (Version number)  </li>
<li>กุญแจพื้นฐาน (Underlying key) คือกุญแจที่มีอยู่ก่อนที่จะถูกปรับแต่ง (tweak) ด้วย merkle root เพื่อสร้าง taproot output key กุญแจพื้นฐานนี้เรียกว่า taproot internal key  </li>
<li>สคริปต์ที่ถูกนำมาประมวลผลนี้เรียกว่า leaf script  </li>
<li>ค่าแฮชขนาด 32 ไบต์จำนวนหนึ่งค่าต่อหนึ่งจุดที่เชื่อมใน merkle tree ตามเส้นทางที่ leaf เชื่อมเข้ากับ Merkle root  </li>
<li>ข้อมูลใด ๆ ที่จำเป็นต่อการทำให้สคริปต์เป็นจริง (เช่น ลายเซ็น หรือ hash preimage)</li>
</ul>
<p>ข้อเสียสำคัญเพียงอย่างเดียวของ taproot ที่มีการอธิบายไว้คือ กรณีของสัญญาที่ผู้เข้าร่วมต้องการใช้ MAST แต่ไม่ต้องการมีเงื่อนไขการยุติความพึงพอใจร่วมกัน สัญญาเหล่านั้นจำเป็นต้องบันทึก taproot internal key ได้บนบล๊อกเชน ซึ่งเพิ่ม overhead ประมาณ 33 ไบต์ แต่อย่างไรก็ตาม เนื่องจากคาดว่าสัญญาส่วนใหญ่จะได้รับประโยชน์จากเงื่อนไขหารยุติโดยใช้ความพึงพอใจร่วมกัน หรืออย่างน้อยก็มีเงื่อนไข multisignature อื่นที่ใช้ public key ที่อยู่ในระดับบนสุด และผู้ใช้ทุกคนยังได้รับประโยชน์จากการเพิ่ม anonymity set ที่ทำให้ output มีลักษณะคล้ายกันมากขึ้น overhead ที่เกิดขึ้นในกรณีที่พบไม่บ่อยนี้จึงไม่ถูกมองว่าสำคัญโดยผู้ใช้ส่วนใหญ่ที่มีส่วนร่วมในการเปิดใช้งาน taproot</p>
<p>การรองรับ taproot ถูกเพิ่มเข้ามาในบิตคอยน์ผ่านการทำ soft fork ซึ่งถูกเปิดใช้งานในเดือนพฤศจิกายนปี 2021</p>
<h3>Tapscript</h3>
<p>Taproot ทำให้สามารถใช้ MAST ได้ แต่ในภาษาสคริปต์ของบิตคอยน์ในเวอร์ชันที่แตกต่างจากเดิมเล็กน้อย โดยเวอร์ชันใหม่นี้เรียกว่า Tapscript โดยความแตกต่างสำคัญประกอบด้วย:</p>
<h5>การเปลี่ยนแปลงของ scripted multisignature:</h5>
<p>opcode เดิมอย่าง OP_CHECKMULTISIG และ OP_CHECKMULTISIGVERIFY ถูกนำออกไป เนื่องจาก opcode เหล่านี้ไม่สามารถทำงานร่วมกันได้ดีนักกับการเปลี่ยนแปลงอีกอย่างใน soft fork ของ taproot นั่นคือความสามารถในการใช้ลายเซ็นแบบ schnorr ร่วมกับการตรวจสอบแบบ batch แทนที่ด้วย opcode ใหม่คือ OP_CHECKSIGADD</p>
<p>เมื่อ OP_CHECKSIGADD ตรวจสอบลายเซ็นสำเร็จแล้ว จะเพิ่มค่าตัวนับขึ้นหนึ่ง ทำให้สามารถนับจำนวนลายเซ็นที่ผ่านการตรวจสอบได้อย่างสะดวก และนำไปเปรียบเทียบกับจำนวนลายเซ็นที่ต้องการ เพื่อสร้างพฤติกรรมเดียวกันกับที่ OP_CHECKMULTISIG เคยทำได้</p>
<h5>การเปลี่ยนแปลงของลายเซ็นทั้งหมด:</h5>
<p>การดำเนินการที่เกี่ยวข้องกับลายเซ็นทั้งหมดใน tapscript ใช้อัลกอริทึมลายเซ็นแบบ Schorr จามที่นิยามไว้ใน BIP340 เราจะอธิบายรายละเอียดของลายเซ็นแบบ schorr เพิ่มเติมในบทถัดไป นอกจากนี้ การดำเนินการตรวจสอบใด ๆ ที่คาดว่าจะไม่ผ่านการตรวจสอบ จะต้องได้รับค่า OP_FALSE (หรือที่เรียกว่า OP_0) แทนการส่งลายเซ็นจริงเข้าไป หากส่งค่าอื่นใดไปยังการตรวจสอบลายเซ็นที่ล้มเหลว สคริปต์ทั้งหมดจะล้มเหลวทันที กลไกนี้ยังช่วยสนับสนุนการตรวจสอบลายเซ็น Schnorr แบบ batch validation ได้อีกด้วย</p>
<h5>opcode กลุ่ม OP_SUCCESSx:</h5>
<p>opcode ที่ไม่สามารถใช้งานได้ใน script เวอร์ชันก่อนหน้าได้ถูกนิยามใหม่ให้เมื่อถูกเรียกใช้แล้วทำให้สคริปต์ทั้งหมดสำเร็จทันที (script succeeds) โดยกลไกนี้เปิดทางให้ soft fork ในอนาคตสามารถนิยามเงื่อนไขเพิ่มเติมได้ว่า opcode เหล่านี้จะไม่ทำให้สคริปต์สำเร็จในบางกรณี ซึ่งถือเป็นการ “จำกัดความสามารถลง” และจึงสามารถทำได้ผ่าน soft fork ในทางกลับกัน การเปลี่ยน opcode ที่เดิม ไม่ทำให้สคริปต์สำเร็จ ให้กลายเป็น opcode ที่ทำให้สคริปต์สำเร็จนั้น จะทำได้ผ่าน hard fork เท่านั้น ซึ่งเป็นแนวทางการอัปเกรดที่ยากและมีความเสี่ยงมากกว่า</p>
<p>แม้ว่าในบทนี้เราจะได้พิจรณาเรื่องการให้สิทธิ์และการยืนยันตัวตนอย่างละเอียดแล้ว แต่เรายังข้ามที่ส่วนสำคัญมากส่วนหนึ่งของวิธีที่บิตคอยน์ใช้ยืนยันผู้ใช้จ่ายไป นั่นคือลายเซ็น ซึ่งเราจะไปศึกษาในลำดับถัดไปในบทที่ 8 <img src="https://image.nostr.build/2eb9a47ba4fe6ecbc3d12dae8434d45ad15840655e6ee833420bb2ee307cf614.jpg" alt="image"></p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<h1><strong>บทที่ 7: Authorization and Authentication</strong></h1>
<hr>
<p>เมื่อคุณได้รับบิตคอยน์ คุณต้องตัดสินใจว่าใครจะได้รับสิทธิ์ในการใช้จ่ายเหรียญนั้น ซึ่งเรียกว่า authorization (การอนุญาต) นอกจากนี้ คุณต้องตัดสินใจด้วยว่า full node ควรแยกแยะผู้ที่ได้รับอนุญาตให้ใช้จ่ายออกจากคนอื่น ๆ อย่างไร ซึ่งเรียกว่า authentication (การยืนยันตัวตน) คำสั่งเกี่ยวกับการอนุญาตของคุณ และหลักฐานการยืนยันตัวตนจากผู้ใช้จ่าย จะถูกตรวจสอบโดย full node นับพัน ซึ่งต้องได้ข้อสรุปตรงกันว่าการใช้จ่ายนั้นได้รับอนุญาตและได้รับการยืนยันตัวตนอย่างถูกต้อง เพื่อให้ธุรกรรมดังกล่าวเป็นธุรกรรมที่ถูกต้อง</p>
<p>คำอธิบายดั้งเดิมของบิตคอยน์ใช้ public key ในการทำ authorization โดย Alice ส่งเหรียญให้ Bob ด้วยการใส่ public key ของเขาลงในเอาต์พุตของธุรกรรม ส่วนการทำ authentication มาจากการลงนาม (signature) โดย Bob ซึ่งผูกพันกับธุรกรรมการใช้จ่าย เช่น การที่ Bob ส่งต่อให้ Carol</p>
<p>ในเวอร์ชันแรกของบิตคอยน์ที่ถูกปล่อยออกมา ได้จัดเตรียมกลไกที่ยืดหยุ่นกว่าสำหรับทั้ง authorization และ authentication และการพัฒนาต่อมาทำให้กลไกเหล่านี้ยืดหยุ่นยิ่งขึ้นกว่าเดิม ในบทนี้ เราจะสำรวจฟีเจอร์เหล่านั้นและดูว่ามันถูกใช้งานอย่างแพร่หลายได้อย่างไร</p>
<h2>Transaction Scripts and Script Language</h2>
<p>เวอร์ชันแรก ๆ ของบิตคอยน์ได้แนะนำภาษาการเขียนโปรแกรมใหม่ชื่อว่า Script ซึ่งเป็นภาษาลักษณะคล้าย Forth ที่ทำงานบนสแตก ทั้งสคริปต์ที่ถูกวางไว้ในเอาต์พุต และสคริปต์อินพุตแบบ legacy ที่ใช้ในธุรกรรมการใช้จ่าย ล้วนเขียนด้วยภาษาสคริปต์นี้ทั้งสิ้น</p>
<p>Script เป็นภาษาที่เรียบง่ายมาก ต้องการการประมวลผลเพียงเล็กน้อย และไม่สามารถทำสิ่งซับซ้อนแบบที่ภาษาสมัยใหม่สามารถทำได้</p>
<p>เมื่อธุรกรรมแบบ legacy ยังเป็นรูปแบบที่ใช้กันมากที่สุด ธุรกรรมส่วนใหญ่ที่ประมวลผลบนเครือข่ายบิตคอยน์อยู่ในรูปแบบเดียวกันกับที่ alice จ่ายให้ bob ในบทก่อนหน้าและใช้สคริปต์ที่เรียกว่า pay to public key hash (P2PKH) แต่อย่างไรก็ตาม ธุรกรรมบิตคอยน์ไม่ได้จำกัดอยู่แค่สคริปต์ในรูปแบบนี้เท่านั้น จริง ๆ แล้วสคริปต์สามารถเขียนเพื่อกำหนดเงื่อนไขที่ซับซ้อนหลากหลายรูปแบบได้ แต่เพื่อที่จะเข้าใจสคริปต์ที่ซับซ้อนเหล่านั้น เราจำเป็นต้องเข้าใจพื้นฐานของสคริปต์ธุรกรรมและภาษาสคริปต์เสียก่อน</p>
<p>ในส่วนนี้ เราจะสาธิตองค์ประกอบพื้นฐานของภาษาสคริปต์สำหรับธุรกรรมบิตคอยน์ และแสดงให้เห็นว่าภาษานี้ใช้เพื่อกำหนดเงื่อนไขสำหรับการใช้จ่ายอย่างไร และจะสามารถทำให้เงื่อนไขนั้นสำเร็จได้อย่างไร</p>
<blockquote>
<p>TIP: การตรวจสอบความถูกต้องของธุรกรรมบิตคอยน์ไม่ได้อาศัยรูปแบบตายตัว แต่เกิดจากการ รันภาษาสคริปต์ ซึ่งเปิดโอกาสให้สามารถกำหนดเงื่อนไขได้หลากหลายแทบไม่จำกัด</p>
</blockquote>
<h2>Turing Incompleteness</h2>
<p>ภาษาสคริปต์ของธุรกรรมบิตคอยน์มีโอเปอเรเตอร์จำนวนมาก แต่ถูกจำกัดไว้อย่างจงใจในด้านสำคัญอย่างหนึ่ง คือ ไม่มีลูปหรือโครงสร้างควบคุมการไหลที่ซับซ้อน นอกเหนือจากการควบคุมแบบมีเงื่อนไขเท่านั้น สิ่งนี้ทำให้ภาษา ไม่เป็น Turing Complete หมายความว่าสคริปต์มีความซับซ้อนได้จำกัดและมีเวลาการประมวลผลที่คาดเดาได้ Script ไม่ใช่ภาษาสำหรับงานทั่วไป ข้อจำกัดเหล่านี้ช่วยป้องกันไม่ให้ภาษาใช้สร้างลูปไม่รู้จบหรือ “logic bomb” รูปแบบอื่นที่อาจแฝงอยู่ในธุรกรรมและถูกใช้โจมตีแบบปฏิเสธการให้บริการ (DoS) ต่อเครือข่ายบิตคอยน์ได้ โปรดจำไว้ว่า ทุกธุรกรรมจะถูกยืนยันโดย full node ทุกตัวในเครือข่ายบิตคอยน์ ภาษาแบบจำกัดช่วยป้องกันไม่ให้กลไกตรวจสอบธุรกรรมกลายเป็นช่องโหว่</p>
<h2>Stateless Verification</h2>
<p>ภาษาสคริปต์ของธุรกรรมบิตคอยน์เป็นแบบ stateless กล่าวคือไม่มีสถานะก่อนเริ่มการประมวลผลสคริปต์ และไม่มีการเก็บสถานะหลังจากสคริปต์รันเสร็จ ข้อมูลทั้งหมดที่จำเป็นสำหรับการประมวลผลสคริปต์อยู่ในสคริปต์และธุรกรรมที่กำลังรันสคริปต์เท่านั้น สคริปต์จะทำงานเหมือนกันทุกครั้งบนทุกระบบ หากระบบของคุณตรวจสอบสคริปต์ผ่าน คุณมั่นใจได้ว่าระบบอื่นในเครือข่ายบิตคอยน์ทั้งหมดก็จะตรวจสอบผ่านเช่นกัน หมายความว่า ธุรกรรมที่ถูกต้องจะถูกต้องสำหรับทุกคน และทุกคนรู้เช่นนั้น ความสามารถในการคาดเดาผลลัพธ์ได้แบบนี้เป็นประโยชน์สำคัญของระบบบิตคอยน์</p>
<h2>Script Construction</h2>
<p>กลไกการตรวจสอบธุรกรรมแบบดั้งเดิมของ Bitcoin อาศัยสองส่วนของสคริปต์ในการตรวจสอบธุรกรรม: output script และ input script</p>
<p>output script ระบุเงื่อนไขที่ต้องถูกทำให้สำเร็จเพื่อใช้จ่ายเอาต์พุตในอนาคต เช่น ใครมีสิทธิ์ใช้จ่ายเอาต์พุต และจะมีการตรวจสอบสิทธิ์อย่างไร</p>
<p>input script คือสคริปต์ที่ทำให้เงื่อนไขใน output script สำเร็จ และอนุญาตให้เอาต์พุตถูกใช้จ่ายได้ Input script เป็นส่วนหนึ่งของทุก ๆ อินพุตภายในธุรกรรม ส่วนใหญ่ในธุรกรรมแบบเดิมจะมีลายเซ็นดิจิทัลที่สร้างจาก private key ของผู้ใช้ แต่ input script ไม่จำเป็นต้องมีลายเซ็นเสมอไป</p>
<p>ทุกโหนดที่ตรวจสอบ Bitcoin จะตรวจสอบธุรกรรมโดยรัน output script และ input script ตามที่ได้กล่าวไว้ในบทที่ 4 อินพุตแต่ละตัวมี outpoint ที่อ้างถึงเอาต์พุตของธุรกรรมก่อนหน้า อินพุตยังมี input script อยู่ด้วย ซอฟต์แวร์ตรวจสอบจะคัดลอก input script ดึง UTXO ที่อินพุตอ้างถึง และคัดลอก output script จาก UTXO นั้น จากนั้น output script และ input script จะถูกประมวลผลรวมกัน อินพุตจะถูกพิจารณาว่าถูกต้องหาก input script ทำให้เงื่อนไขใน output script สำเร็จ (จะอธิบายในหัวข้อ Separate execution of output and input scripts) อินพุตทุกตัวจะถูกตรวจสอบแยกกันเป็นส่วนหนึ่งของการตรวจสอบธุรกรรมโดยรวม</p>
<p>โปรดสังเกตว่า ขั้นตอนข้างต้นเกี่ยวข้องกับการคัดลอกข้อมูลทั้งหมด ข้อมูลต้นฉบับในเอาต์พุตก่อนหน้าและในอินพุตปัจจุบันจะไม่ถูกเปลี่ยนแปลงเลย เอาต์พุตก่อนหน้าไม่ถูกเปลี่ยนแปลงและไม่ได้รับผลกระทบจากความพยายามใช้จ่ายที่ล้มเหลว มีเพียงธุรกรรมที่ถูกต้องซึ่งทำให้เงื่อนไขใน output script สำเร็จเท่านั้นที่จะทำให้เอาต์พุตถูกพิจารณาว่า “ถูกใช้จ่ายแล้ว”</p>
<p>การผสาน input script และ output script เพื่อประเมินสคริปต์ของธุรกรรม คือ ตัวอย่างของ output script และ input script ของธุรกรรม Bitcoin แบบดั้งเดิมที่พบมากที่สุด (การชำระเงินไปยัง public key hash) ซึ่งแสดงสคริปต์ที่รวมกันจากการนำทั้งสองสคริปต์มาต่อกันก่อนการตรวจสอบ</p>
<p> <img src="https://image.nostr.build/5be02a704fca95d54b831b0ae9a66e09ea4804b95dde7c25d75decb167b1d55c.jpg" alt="image"></p>
<h3>The script execution stack</h3>
<p>ภาษาสคริปต์ของ Bitcoin ถูกเรียกว่า stack-based language เพราะใช้โครงสร้างข้อมูลที่เรียกว่า stack สแตกเป็นโครงสร้างข้อมูลที่เรียบง่ายมาก มองภาพได้เหมือนกองไพ่ สแตกมีสองการทำงานพื้นฐาน: push และ pop push คือการเพิ่มข้อมูลหนึ่งรายการไว้ด้านบนของสแตก ส่วน pop คือการนำรายการด้านบนสุดออกจากสแตก</p>
<p>ภาษาสคริปต์จะรันสคริปต์โดยประมวลผลรายการแต่ละรายการจากซ้ายไปขวา ตัวเลข (ค่าคงที่ของข้อมูล) จะถูก push ลงบนสแตก ตัวโอเปอเรเตอร์จะ push หรือ pop พารามิเตอร์หนึ่งตัวหรือมากกว่าจากสแตก นำไปประมวลผล และอาจ push ผลลัพธ์กลับลงสแตก ตัวอย่างเช่น OP_ADD จะ pop ข้อมูลสองรายการออกจากสแตก นำมาบวกกัน แล้ว push ผลรวมกลับลงบนสแตก</p>
<p>โอเปอเรเตอร์แบบมีเงื่อนไขจะประเมินเงื่อนไขและให้ผลลัพธ์เป็น boolean TRUE หรือ FALSE ตัวอย่างเช่น OP_EQUAL จะ pop ข้อมูลสองรายการจากสแตก และ push TRUE (TRUE แทนด้วยเลข 1) หากสองค่านั้นเท่ากัน หรือ push FALSE (แทนด้วยเลข 0) หากไม่เท่ากัน สคริปต์ของธุรกรรม Bitcoin มักมีโอเปอเรเตอร์แบบมีเงื่อนไขเพื่อสร้างผลลัพธ์ TRUE ที่แสดงว่าธุรกรรมนั้นถูกต้อง</p>
<h3>A simple script (สคริปต์อย่างง่าย)</h3>
<p>ตอนนี้เรามาลองประยุกต์สิ่งที่เราได้เรียนรู้เกี่ยวกับ scripts และ stacks กับตัวอย่างง่าย ๆ กัน </p>
<p>ในบทก่อนหน้าเราได้ยกสคริปต์อย่างง่ายมาตัวหนึ่งคือ</p>
<pre><code>2 3 OP_ADD 5 OP_EQUAL
</code></pre>
<p>แสดงการทำงานของโอเปอเรเตอร์คณิตศาสตร์ OP_ADD ซึ่งทำการบวกตัวเลขสองตัวแล้ววางผลลัพธ์ไว้บนสแต็ก จากนั้นตามด้วยโอเปอเรเตอร์แบบเงื่อนไข OP_EQUAL ที่ตรวจสอบว่าผลรวมดังกล่าวเท่ากับ 5 หรือไม่ ในหนังสือเล่มนี้ เพื่อความกระชับ อาจมีการละคำนำหน้า OP_ ในบางตัวอย่าง หากต้องการรายละเอียดเพิ่มเติมเกี่ยวกับโอเปอเรเตอร์และฟังก์ชันทั้งหมดของสคริปต์ สามารถดูได้ที่หน้า Script ของ Bitcoin Wiki<br>แม้ว่าผลลัพธ์สคริปต์แบบ Legacy ส่วนใหญ่จะอ้างอิง public key hash (ซึ่งโดยพื้นฐานคือ Bitcoin address แบบดั้งเดิม) เพื่อบังคับให้ต้องพิสูจน์ความเป็นเจ้าของก่อนจึงจะใช้เงินได้ แต่จริง ๆ แล้วสคริปต์ไม่จำเป็นต้องซับซ้อนขนาดนั้นก็ได้ สคริปต์ใด ๆ ที่ผสมกันระหว่าง output script และ input script แล้วให้ผลเป็น TRUE ถือว่า “ถูกต้อง”ดังนั้นสคริปต์คณิตศาสตร์ง่าย ๆ อย่างที่ใช้เป็นตัวอย่างในที่นี้ ก็ถือว่าเป็นสคริปต์ที่ถูกต้องเช่นกัน</p>
<p>ใช้ส่วนหนึ่งของสคริปต์คณิตศาสตร์เป็น output script</p>
<p>ให้ output script เป็น:</p>
<pre><code>3 OP_ADD 5 OP_EQUAL
</code></pre>
<p>ซึ่งสามารถถูกทำให้สำเร็จ (satisfied) ด้วยธุรกรรมที่มี input script แบบนี้:</p>
<pre><code>2
</code></pre>
<p>ซอฟต์แวร์ตรวจสอบความถูกต้อง (validation software) จะรวมสองสคริปต์เข้าด้วยกันกลายเป็น:</p>
<pre><code>2 3 OP_ADD 5 OP_EQUAL
</code></pre>
<p>เมื่อสคริปต์นี้ถูกประมวลผล ตามที่เราเห็นในบทก่อนหน้า ผลลัพธ์สุดท้ายคือ OP_TRUE ทำให้ธุรกรรมนี้ “ถูกต้อง” แม้ว่านี่จะเป็น output script ที่ถูกต้อง แต่ให้สังเกตว่า UTXO ที่สร้างขึ้น สามารถถูกใช้จ่ายได้โดยใครก็ตาม ที่มีทักษะคณิตศาสตร์พอจะรู้ว่าเลข 2 จะทำให้สคริปต์นี้สำเร็จได้<br> <img src="https://image.nostr.build/277a418d6958becf1c914c6eecd0732585265acceed0e238e9258e464c280728.jpg" alt="image"></p>
<blockquote>
<p>TIP: ธุรกรรมจะถือว่า ถูกต้อง (valid) หากผลลัพธ์บนยอดสแต็กเป็นค่า TRUE ซึ่งหมายถึงค่าที่ไม่ใช่ศูนย์ใด ๆ ทั้งหมด ธุรกรรมจะถือว่า ไม่ถูกต้อง (invalid) หากผลบนยอดสแต็กเป็นค่า FALSE (ศูนย์ หรือสแต็กว่าง), หรือการประมวลผลสคริปต์ถูกหยุดโดยตรงด้วยโอเปอเรเตอร์บางตัว (เช่น VERIFY, OP_RETURN), หรือสคริปต์นั้นมีความผิดพลาดทางไวยากรณ์/ความหมาย (semantic) เช่น มีคำสั่ง OP_IF แต่ไม่มี OP_ENDIF ปิดท้าย ดูรายละเอียดเพิ่มเติมได้ที่หน้า Script ของ Bitcoin Wiki</p>
</blockquote>
<p>สคริปต์ตัวอย่างถัดไปนี้จะมีความซับซ้อนขึ้นเล็กน้อย โดยมันคำนวณค่า 2 + 7 – 3 + 1 สังเกตว่าเมื่อสคริปต์มีโอเปอเรเตอร์หลายตัวต่อกัน สแต็กจะทำให้ผลลัพธ์ของโอเปอเรเตอร์ก่อนหน้า ถูกนำไปใช้ต่อโดยโอเปอเรเตอร์ตัวถัดไปได้</p>
<pre><code>2 7 OP_ADD 3 OP_SUB 1 OP_ADD 7 OP_EQUAL
</code></pre>
<p>ลองตรวจสอบสคริปต์ก่อนหน้านี้ด้วยตัวเอง โดยใช้ดินสอและกระดาษ เมื่อการประมวลผลสคริปต์สิ้นสุดลง คุณควรจะเหลือค่าบนสแต็กเป็นค่า TRUE</p>
<h3>Separate execution of output and input scripts</h3>
<p>ในไคลเอนต์ Bitcoin เวอร์ชันแรก ๆ  นั้น สคริปต์ของ output และ input ถูกต่อกันแล้วประมวลผลเป็นลำดับเดียว ด้วยเหตุผลด้านความปลอดภัย ซึ่งเกิดจากช่องโหว่ที่รู้จักกันในชื่อ 1 OP_RETURN bug ซึ่งวิธีนี้ถูกเปลี่ยนแปลงในปี 2010 เพื่อความปลอดภัย ในการใช้งานปัจจุบัน สคริปต์ทั้งสองจะถูกประมวลผลแยกกันโดยมีการคัดลอกสแต็กไปยังการประมวลผลครั้งถัดไป</p>
<p>อันดับแรก สคริปต์ input จะถูกประมวลผลโดยการดำเนินการของสแต็ก (stack execution engine) หากสคริปต์ input ถูกประมวลผลโดยไม่มีข้อผิดพลาดและไม่มีโอเปอเรชันเหลืออยู่ สแต็กจะถูกคัดลอกแล้วสคริปต์ output จะถูกประมวลผลต่อ หากผลลัพธ์ของการประมวลผลสคริปต์ output โดยใช้ข้อมูลสแต็กที่คัดลอกมาจาก input เป็น TRUE แสดงว่าสคริปต์ input สามารถแก้เงื่อนไขที่สคริปต์ output กำหนดได้ และด้วยเหตุนี้ input จึงเป็นการอนุญาตที่ถูกต้องสำหรับการใช้จ่าย UTXO นั้น แต่หากผลลัพธ์ใด ๆ นอกเหนือจาก TRUE ยังคงอยู่หลังการประมวลผลของสคริปต์รวมกัน แสดงว่า input นั้นไม่ถูกต้องเพราะล้มเหลวในการตอบสนองเงื่อนไขการใช้จ่ายที่วางไว้บน output</p>
<h2>Pay to Public Key Hash</h2>
<p>สคริปต์แบบ pay to public key hash (P2PKH) ใช้ output script ที่ภายในมีค่าแฮชซึ่งผูกพัน (commit) กับ public key หนึ่งค่า P2PKH เป็นที่รู้จักกันดีที่สุดในฐานะ Legacy Bitcoin address เอาต์พุตแบบ P2PKH สามารถถูกใช้จ่ายได้โดยการนำเสนอ public key ที่ตรงกับค่าแฮชที่ระบุไว้ และลายเซ็นดิจิทัลที่สร้างขึ้นด้วย private key ที่สอดคล้องกัน (ดูเรื่องนี้เพิ่มได้ในบทถัดไป) ส่วนตอนนี้มาดูตัวอย่างของ P2PKH output script กัน:</p>
<pre><code>OP_DUP OP_HASH160 &lt;Key Hash&gt; OP_EQUALVERIFY OP_CHECKSIG
</code></pre>
<p>Key Hash คือข้อมูลที่เมื่อนำไปเข้ารหัส จะกลายเป็น Bitcoin address แบบ legacy ในรูปแบบ base58check แอปพลิเคชันส่วนใหญ่จะแสดงค่า public key hash ภายในสคริปต์ในรูปแบบเลขฐานสิบหก (hexadecimal) แทนที่จะเป็นรูปแบบ Bitcoin address แบบ base58check ที่ผู้ใช้คุ้นเคย ซึ่งจะขึ้นต้นด้วยตัวอักษร “1”<br>output script ก่อนหน้านี้สามารถถูกทำให้สำเร็จ (satisfied) ได้ด้วย input script ในรูปแบบ:</p>
<pre><code>&lt;Signature&gt; &lt;Public Key&gt;
</code></pre>
<p>เมื่อรวมสคริปต์ทั้งสองเข้าด้วยกัน จะได้สคริปต์ตรวจสอบความถูกต้อง (combined validation script) ดังนี้:</p>
<pre><code>&lt;Sig&gt; &lt;Pubkey&gt; OP_DUP OP_HASH160 &lt;Hash&gt; OP_EQUALVERIFY OP_CHECKSIG
</code></pre>
<p>ผลลัพธ์จะเป็นค่า TRUE หาก input script มีลายเซ็นที่ถูกต้อง ซึ่งถูกสร้างขึ้นจาก private key ของของผู้ส่ง และสอดคล้องกับ public key hash ที่ถูกกำหนดไว้เป็นเงื่อนไขการใช้จ่ายนั้น</p>
<p> <img src="https://image.nostr.build/53dda9b219893a6b51c0dbf4b96b4c5eda32f2c2cd62a8c77b13fbec2e6280dc.jpg" alt="image"><br> <img src="https://image.nostr.build/318690aac1933790ae7bd5600e90c2fa311383a30515d80d9b2f9e0ff99bbcd7.jpg" alt="image"></p>
<h2>Scripted Multisignatures</h2>
<p>สคริปต์แบบมัลติซิกเนเจอร์ (multisignature) กำหนดเงื่อนไขโดยบันทึกค่าของ public key จำนวน k ค่าไว้ในสคริปต์ และต้องมีลายเซ็นอย่างน้อย t ค่าจาก public key เหล่านั้นจึงจะสามารถใช้จ่ายเงินได้ เรียกรูปแบบนี้ว่า t-of-k ตัวอย่างเช่น 2-of-3 multisignature คือกรณีที่มีการระบุ public key ไว้ทั้งหมดสามค่าในฐานะผู้มีสิทธิ์ลงนาม และต้องใช้ลายเซ็นอย่างน้อยสองจากสามค่านั้น เพื่อสร้างธุรกรรมที่ถูกต้องสำหรับการใช้จ่ายเงิน</p>
<blockquote>
<p>TIP: เอกสารของบิตคอยน์บางแหล่ง รวมถึงหนังสือเล่มนี้ในฉบับก่อนหน้า ใช้คำว่า “m-of-n” เพื่อเรียกมัลติซิกเนเจอร์แบบดั้งเดิม อย่างไรก็ตาม เมื่อพูดออกเสียงแล้ว ตัวอักษร m และ n แยกออกจากกันได้ยาก จึงมีการเลือกใช้คำว่า t-of-k แทน ทั้งสองคำนี้หมายถึงรูปแบบของระบบลายเซ็นแบบเดียวกัน</p>
</blockquote>
<p>รูปแบบทั่วไปของ output script ที่กำหนดเงื่อนไขมัลติซิกเนเจอร์แบบ t-of-k มีดังนี้:</p>
<pre><code>t &lt;Public Key 1&gt; &lt;Public Key 2&gt; ... &lt;Public Key k&gt; k OP_CHECKMULTISIG
</code></pre>
<p>โดยที่ k คือจำนวน public key ทั้งหมดที่ระบุไว้ และ t คือจำนวนลายเซ็นขั้นต่ำที่ต้องใช้เพื่อสามารถใช้จ่าย output นั้นได้<br>output script ที่กำหนดเงื่อนไขมัลติซิกเนเจอร์แบบ 2-of-3 จะมีลักษณะดังนี้:</p>
<pre><code>2 &lt;Public Key A&gt; &lt;Public Key B&gt; &lt;Public Key C&gt; 3 OP_CHECKMULTISIG
</code></pre>
<p>output script ข้างต้นสามารถถูกทำให้สำเร็จได้ด้วย input script ที่มีลายเซ็น เช่น:</p>
<pre><code>&lt;Signature B&gt; &lt;Signature C&gt;
</code></pre>
<p>หรือจะเป็นชุดลายเซ็นสองชุดใดก็ได้ ที่มาจาก private key ที่สอดคล้องกับ public key ทั้งสามค่าที่ถูกระบุไว้</p>
<p>เมื่อรวมสคริปต์ทั้งสองเข้าด้วยกัน จะได้สคริปต์ตรวจสอบความถูกต้องดังนี้:</p>
<pre><code>&lt;Sig B&gt; &lt;Sig C&gt; 2 &lt;Pubkey A&gt; &lt;Pubkey B&gt; &lt;Pubkey C&gt; 3 OP_CHECKMULTISIG
</code></pre>
<p>เมื่อถูกประมวลผล สคริปต์ที่ถูกรวมกันนี้จะให้ผลลัพธ์เป็นค่า TRUE หาก input script มีลายเซ็นที่ถูกต้องจำนวนสองชุด ซึ่งมาจาก private key ที่สอดคล้องกับ public key สองค่าใดก็ได้ จากสามค่าที่ถูกกำหนดไว้เป็นเงื่อนไขการใช้จ่าย</p>
<p>ในปัจจุบัน นโยบายการส่งต่อธุรกรรม (transaction relay policy) ของ Bitcoin Core จำกัดจำนวน public key ใน multisignature output script ไว้สูงสุดที่สามค่า หมายความว่าสามารถสร้างมัลติซิกเนเจอร์ได้ตั้งแต่แบบ 1-of-1 ไปจนถึง 3-of-3 หรือรูปแบบใด ๆ ภายในช่วงนี้ คุณอาจต้องการตรวจสอบฟังก์ชัน IsStandard() เพื่อดูว่าขณะนี้เครือข่ายยอมรับรูปแบบใดบ้าง โปรดสังเกตว่า ข้อจำกัดที่สามคีย์นี้ใช้กับ multisignature script แบบมาตรฐานเท่านั้น (ซึ่งเรียกอีกชื่อหนึ่งว่า “bare” multisignature) ไม่ได้ใช้กับสคริปต์ที่ถูกห่อหุ้มด้วยโครงสร้างอื่น เช่น P2SH, P2WSH, หรือ P2TR สำหรับ multisignature script แบบ P2SH จะถูกจำกัดทั้งในระดับนโยบาย (policy) และฉันทามติ (consensus) ไว้ที่สูงสุด 15 คีย์ ทำให้สามารถสร้างมัลติซิกเนเจอร์ได้สูงสุดแบบ 15-of-15 เราจะเรียนรู้เกี่ยวกับ P2SH ในหัวข้อ Pay to Script Hash ส่วนสคริปต์รูปแบบอื่นทั้งหมด จะถูกจำกัดโดยฉันทามติไว้ที่ public key ได้ไม่เกิน 20 คีย์ ต่อคำสั่ง OP_CHECKMULTISIG หรือ OP_CHECKMULTISIGVERIFY หนึ่งคำสั่ง ทั้งนี้ สคริปต์หนึ่งรายการอาจมีคำสั่งเหล่านี้ได้มากกว่าหนึ่งครั้ง</p>
<h3>An Oddity in CHECKMULTISIG Execution</h3>
<p>มีความผิดปกติ (oddity) อย่างหนึ่งในการทำงานของ OP_CHECKMULTISIG ซึ่งทำให้ต้องมีวิธีแก้ไขเฉพาะหน้าเล็กน้อย เมื่อ OP_CHECKMULTISIG ถูกประมวลผล ตามหลักแล้วมันควรจะนำข้อมูลออกจากสแต็กมาใช้เป็นพารามิเตอร์จำนวน t + k + 2 ค่า อย่างไรก็ตาม เนื่องจากความผิดปกตินี้ OP_CHECKMULTISIG จะดึงค่าจากสแต็กออกมา มากกว่าที่คาดไว้หนึ่งค่า</p>
<p>เรามาดูรายละเอียดของเรื่องนี้ให้ชัดเจนขึ้น โดยใช้ตัวอย่างสคริปต์ตรวจสอบความถูกต้องจากก่อนหน้านี้:</p>
<pre><code>&lt;Sig B&gt; &lt;Sig C&gt; 2 &lt;Pubkey A&gt; &lt;Pubkey B&gt; &lt;Pubkey C&gt; 3 OP_CHECKMULTISIG
</code></pre>
<p>ขั้นแรก OP_CHECKMULTISIG จะนำค่าแรกบนสุดของสแต็กออกมา ซึ่งก็คือ k (ในตัวอย่างนี้คือ “3”) จากนั้นจะนำข้อมูลออกมาอีก k ค่า ซึ่งเป็น public key ที่สามารถใช้ลงนามได้ ในตัวอย่างนี้คือ public key A, B และ C จากนั้นมันจะนำค่าออกมาอีกหนึ่งค่า ซึ่งก็คือ t หรือจำนวนลายเซ็นขั้นต่ำที่ต้องใช้ (quorum) โดยในกรณีนี้ t = 2 ตามปกติแล้ว ณ จุดนี้ OP_CHECKMULTISIG ควรจะนำค่าออกมาอีก t ค่า ซึ่งเป็นลายเซ็น เพื่อตรวจสอบว่าถูกต้องหรือไม่ อย่างไรก็ตาม เนื่องจากความผิดปกติในการนำไปใช้งานจริง OP_CHECKMULTISIG จะนำค่าจากสแต็กออกมา มากกว่าที่ควรหนึ่งค่า (รวมเป็น t + 1 ค่า) ค่าส่วนเกินนี้ถูกเรียกว่า dummy stack element และจะถูกละเว้นในระหว่างการตรวจสอบลายเซ็น ดังนั้นมันจึงไม่มีผลโดยตรงต่อการทำงานของ OP_CHECKMULTISIG เอง อย่างไรก็ตาม dummy element นี้ จำเป็นต้องมีอยู่ เพราะหากไม่มีค่าเหลืออยู่บนสแต็กในขณะที่ OP_CHECKMULTISIG พยายามดึงค่าออกมาเพิ่ม จะทำให้เกิด stack error และสคริปต์ล้มเหลว ส่งผลให้ธุรกรรมนั้นไม่ถูกต้อง เนื่องจาก dummy element ถูกละเว้น ค่าของมันจึงสามารถเป็นค่าอะไรก็ได้ แต่ในช่วงแรกได้มีธรรมเนียมใช้ค่า OP_0 สำหรับตำแหน่งนี้ ต่อมาสิ่งนี้ได้กลายเป็นกฎของ relay policy และในที่สุดก็กลายเป็นกฎระดับฉันทามติ (consensus rule) เมื่อมีการบังคับใช้ BIP147</p>
<p>เนื่องจากการนำ dummy element ออกจากสแต็กเป็นส่วนหนึ่งของกฎฉันทามติ (consensus rules) พฤติกรรมนี้จึงต้องถูกคงไว้และทำซ้ำตลอดไป ดังนั้นสคริปต์จึงควรมีหน้าตาเป็นดังนี้:</p>
<pre><code>OP_0 &lt;Sig B&gt; &lt;Sig C&gt; 2 &lt;Pubkey A&gt; &lt;Pubkey B&gt; &lt;Pubkey C&gt; 3 OP_CHECKMULTISIG
</code></pre>
<p>ด้วยเหตุนี้ input script ที่ถูกใช้งานจริงใน multisignature จะ ไม่ใช่:</p>
<pre><code>&lt;Signature B&gt; &lt;Signature C&gt;
</code></pre>
<p>แต่จะต้องเป็น:</p>
<pre><code>OP_0 &lt;Sig B&gt; &lt;Sig C&gt;
</code></pre>
<p>บางคนเชื่อว่าความผิดปกตินี้เกิดจากบั๊กในโค้ดต้นฉบับของบิตคอยน์ แต่อย่างไรก็ตาม ยังมีคำอธิบายทางเลือกที่สมเหตุสมผลอยู่ การตรวจสอบลายเซ็นแบบ t-of-k อาจต้องใช้การตรวจสอบลายเซ็นมากกว่าทั้งค่า t หรือ k เพียงอย่างเดียว</p>
<p>ลองพิจารณาตัวอย่างง่าย ๆ แบบ 1-in-5 โดยมีสคริปต์ตรวจสอบความถูกต้องที่ถูกรวมกันดังนี้:</p>
<pre><code>&lt;dummy&gt; &lt;Sig4&gt; 1 &lt;key0&gt; &lt;key1&gt; &lt;key2&gt; &lt;key3&gt; &lt;key4&gt; 5 OP_CHECKMULTISIG
</code></pre>
<p>ลายเซ็นจะถูกตรวจสอบกับ key0 ก่อน จากนั้นกับ key1 และต่อเนื่องไปยัง key อื่น ๆ จนกระทั่งในที่สุดจึงถูกนำไปเปรียบเทียบกับ public key ที่สอดคล้องกันจริง ๆ คือ key4 นั่นหมายความว่า จำเป็นต้องมีการตรวจสอบลายเซ็นถึง ห้าครั้ง ทั้งที่มีลายเซ็นเพียงหนึ่งรายการเท่านั้น แนวทางหนึ่งในการลดความซ้ำซ้อนนี้ คือให้ OP_CHECKMULTISIG รับข้อมูลในลักษณะเป็น map ที่ระบุว่าแต่ละลายเซ็นที่ส่งเข้ามาสัมพันธ์กับ public key ใด ซึ่งจะทำให้ OP_CHECKMULTISIG ต้องทำการตรวจสอบลายเซ็นเพียง t ครั้ง เท่านั้น จึงเป็นไปได้ว่า นักพัฒนาของบิตคอยน์ได้เพิ่มองค์ประกอบพิเศษนี้เข้าไปตั้งแต่เวอร์ชันแรก (ซึ่งปัจจุบันเราเรียกว่า dummy stack element) เพื่อเปิดทางให้สามารถเพิ่มความสามารถดังกล่าวผ่าน soft fork ในอนาคตได้ อย่างไรก็ตาม ฟีเจอร์ดังกล่าวไม่เคยถูกนำมาใช้งานจริง และการอัปเดตกฎฉันทามติด้วย BIP147 ในปี 2017 ก็ทำให้ไม่สามารถเพิ่มฟีเจอร์นี้ได้อีกต่อไปในอนาคต </p>
<p>มีเพียงนักพัฒนาของบิตคอยน์เท่านั้น ที่จะสามารถบอกได้ว่าการมีอยู่ของ dummy stack element นั้นเกิดจากบั๊ก หรือเป็นการวางแผนสำหรับการอัปเกรดในอนาคต สำหรับหนังสือเล่มนี้ เราเรียกสิ่งนี้เพียงว่าเป็น “ความผิดปกติ” (oddity) </p>
<p>นับจากนี้เป็นต้นไป หากคุณเห็นสคริปต์แบบ multisignature ให้คาดไว้เลยว่าจะต้องมี OP_0 เพิ่มเข้ามาในตอนต้น โดยจุดประสงค์เดียวของมันคือการเป็นวิธีแก้ปัญหาเฉพาะหน้า สำหรับความผิดปกติที่มีอยู่ในกฎฉันทามติ</p>
<h2>Pay to Script Hash</h2>
<p>Pay to Script Hash (P2SH) ถูกนำมาใช้ในปี 2012 ในฐานะรูปแบบการทำงานแบบใหม่ที่ทรงพลัง ซึ่งช่วยทำให้การใช้งานสคริปต์ที่ซับซ้อนเป็นเรื่องง่ายขึ้นอย่างมาก เพื่ออธิบายความจำเป็นของ P2SH เรามาดูตัวอย่างเชิงปฏิบัติกัน</p>
<p>โมฮัมเหม็ดเป็นผู้นำเข้าอุปกรณ์อิเล็กทรอนิกส์ซึ่งตั้งอยู่ในดูไบ บริษัทของโมฮัมเหม็ดใช้ฟีเจอร์มัลติซิกเนเจอร์ของบิตคอยน์อย่างแพร่หลายสำหรับบัญชีขององค์กร สคริปต์มัลติซิกเนเจอร์เป็นหนึ่งในการใช้งานความสามารถด้านสคริปต์ขั้นสูงของบิตคอยน์ที่พบได้บ่อยที่สุด และเป็นฟีเจอร์ที่ทรงพลังมาก บริษัทของโมฮัมเหม็ดใช้สคริปต์มัลติซิกเนเจอร์กับการชำระเงินจากลูกค้าทุกราย การชำระเงินของลูกค้าจะถูกล็อกไว้ในลักษณะที่ต้องใช้ลายเซ็นอย่างน้อยสองชุดจึงจะสามารถปลดล็อกได้ โมฮัมเหม็ด หุ้นส่วนอีกสามคนของเขา และทนายความของบริษัท ต่างสามารถให้ลายเซ็นได้คนละหนึ่งชุด รูปแบบมัลติซิกเนเจอร์เช่นนี้ช่วยสร้างกลไกกำกับดูแลกิจการ และป้องกันการโจรกรรม การยักยอก หรือการสูญหายของเงินได้</p>
<p>สคริปต์ที่ได้จากเงื่อนไขดังกล่าวจะค่อนข้างยาว และมีลักษณะดังนี้:</p>
<pre><code>2 &lt;Mohammed's Public Key&gt; &lt;Partner1 Public Key&gt; &lt;Partner2 Public Key&gt;
&lt;Partner3 Public Key&gt; &lt;Attorney Public Key&gt; 5 OP_CHECKMULTISIG
</code></pre>
<p>แม้ว่าสคริปต์แบบมัลติซิกเนเจอร์จะเป็นฟีเจอร์ที่ทรงพลังมาก แต่ก็ใช้งานได้ค่อนข้างยุ่งยาก จากสคริปต์ตัวอย่างก่อนหน้า โมฮัมเหม็ดจะต้องสื่อสารสคริปต์นี้ให้ลูกค้าทุกรายทราบก่อนทำการชำระเงิน ลูกค้าแต่ละรายยังจำเป็นต้องใช้ซอฟต์แวร์กระเป๋าเงินบิตคอยน์แบบพิเศษ ที่สามารถสร้างสคริปต์ธุรกรรมแบบกำหนดเองได้ นอกจากนี้ ธุรกรรมที่ได้จะมีขนาดใหญ่กว่าธุรกรรมการชำระเงินแบบธรรมดาประมาณห้าเท่า เนื่องจากสคริปต์นี้มี public key ที่มีความยาวมาก ภาระของข้อมูลส่วนเกินนี้จะตกอยู่กับลูกค้าในรูปของค่าธรรมเนียมธุรกรรมที่สูงขึ้น สุดท้ายแล้ว สคริปต์ธุรกรรมขนาดใหญ่เช่นนี้จะถูกเก็บไว้ในชุดข้อมูล UTXO set ของทุก full node จนกว่าจะถูกใช้จ่าย ซึ่งปัญหาเหล่านี้ทั้งหมดทำให้การใช้งาน output script ที่ซับซ้อนเป็นเรื่องยากในทางปฏิบัติ</p>
<p>P2SH ถูกพัฒนาขึ้นมาเพื่อแก้ไขปัญหาเชิงปฏิบัติเหล่านี้ และเพื่อทำให้การใช้งานสคริปต์ที่ซับซ้อนง่ายพอ ๆ กับการชำระเงินไปยัง Bitcoin address แบบกุญแจเดียว ด้วยการชำระเงินแบบ P2SH สคริปต์ที่ซับซ้อนจะถูกแทนที่ด้วย “คำมั่น” (commitment) ซึ่งก็คือค่าแฮชเชิงคริปโตกราฟีของสคริปต์นั้น เมื่อมีการนำเสนอธุรกรรมเพื่อใช้จ่าย UTXO ในภายหลัง ธุรกรรมนั้นจะต้องมีทั้งสคริปต์ที่ตรงกับค่าแฮชที่ถูกผูกไว้ และข้อมูลที่ใช้ทำให้สคริปต์ดังกล่าวสำเร็จ กล่าวอย่างง่ายที่สุด P2SH หมายถึง “จ่ายเงินให้กับสคริปต์ที่ตรงกับค่าแฮชนี้ โดยสคริปต์นั้นจะถูกนำมาแสดงในภายหลังเมื่อ output นี้ถูกใช้จ่าย”</p>
<p>ในธุรกรรมแบบ P2SH สคริปต์ที่ถูกแทนที่ด้วยค่าแฮชจะถูกเรียกว่า redeem script เนื่องจากสคริปต์นี้จะถูกนำเสนอให้ระบบในช่วงเวลาที่มีการนำมาใช้จ่าย (redeem) แทนที่จะถูกใส่ไว้เป็น output script ตั้งแต่ต้นตารางด้านล่างจะ แสดงสคริปต์ในกรณีที่ไม่ใช้ P2SH และแสดงสคริปต์เดียวกันที่ถูกเข้ารหัสในรูปแบบ P2SH</p>
<p>Complex script without P2SH</p>
<table>
<thead>
<tr>
<th align="left">Output script</th>
<th align="left">2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 OP_CHECKMULTISIG</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Input script</td>
<td align="left">Sig1 Sig2</td>
</tr>
</tbody></table>
<p>Complex script as P2SH</p>
<table>
<thead>
<tr>
<th align="left">Redeem script</th>
<th align="left">2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 OP_CHECKMULTISIG</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Output script</td>
<td align="left">OP_HASH160 &lt;20-byte hash of redeem script&gt; OP_EQUAL</td>
</tr>
<tr>
<td align="left">Input script</td>
<td align="left">Sig1 Sig2 &lt;redeem script&gt;</td>
</tr>
</tbody></table>
<p>ดังที่เห็นได้จากตาราง เมื่อใช้ P2SH สคริปต์ที่ซับซ้อนซึ่งระบุเงื่อนไขในการใช้จ่าย output (redeem script) จะไม่ถูกนำมาใส่ไว้ใน output script อีกต่อไป แต่จะมีเพียงค่าแฮชของสคริปต์นั้นอยู่ใน output script เท่านั้น ส่วนตัว redeem script เองจะถูกนำมาแสดงภายหลังในฐานะส่วนหนึ่งของ input script เมื่อมีการใช้จ่าย output นั้นแนวทางนี้ทำให้ภาระในด้านค่าธรรมเนียมและความซับซ้อน ถูกย้ายจากฝั่งผู้รับเงิน ไปยังฝั่งผู้ใช้จ่ายเงินในภายหลังเรามาดูกรณีของบริษัทโมฮัมเหม็ด สคริปต์มัลติซิกเนเจอร์ที่ซับซ้อน และสคริปต์ P2SH ที่ได้จากมันกัน อันดับแรก คือสคริปต์มัลติซิกเนเจอร์ที่บริษัทของโมฮัมเหม็ดใช้สำหรับการรับชำระเงินจากลูกค้าทุกราย:</p>
<pre><code>2 &lt;Mohammed's Public Key&gt; &lt;Partner1 Public Key&gt; &lt;Partner2 Public Key&gt;
&lt;Partner3 Public Key&gt; &lt;Attorney Public Key&gt; 5 OP_CHECKMULTISIG
</code></pre>
<p>สคริปต์ทั้งหมดนี้สามารถถูกแทนที่ด้วยค่าแฮชเชิงคริปโตกราฟีขนาด 20 ไบต์ ได้ โดยเริ่มจากการนำสคริปต์ไปผ่านอัลกอริทึมแฮช SHA256 ก่อน จากนั้นจึงนำผลลัพธ์ที่ได้ไปแฮชต่อด้วยอัลกอริทึม RIPEMD-160 ตัวอย่างเช่น เริ่มต้นด้วยค่าแฮชของ redeem script ของบริษัทโมฮัมเหม็ด:</p>
<pre><code>54c557e07dde5bb6cb791c7a540e0a4796f5e97e
</code></pre>
<p>ธุรกรรมแบบ P2SH จะล็อก output ไว้กับค่าแฮชนี้ แทนที่จะใช้ redeem script ที่ยาวกว่า โดยใช้แม่แบบ output script แบบพิเศษดังนี้:</p>
<pre><code>OP_HASH160 54c557e07dde5bb6cb791c7a540e0a4796f5e97e OP_EQUAL
</code></pre>
<p>ซึ่งอย่างที่เห็น จะสั้นกว่ามาก แทนที่จะเป็น “จ่ายไปยังสคริปต์มัลติซิกเนเจอร์ที่มี 5 คีย์นี้” ธุรกรรมแบบ P2SH จะกลายเป็น “จ่ายไปยังสคริปต์ที่มีค่าแฮชนี้” ลูกค้าที่ชำระเงินให้บริษัทของโมฮัมเหม็ด จำเป็นต้องใส่เพียง output script ที่สั้นกว่านี้ลงในธุรกรรมเท่านั้น</p>
<p>เมื่อโมฮัมเหม็ดและหุ้นส่วนต้องการใช้จ่าย UTXO นี้ พวกเขาจะต้องแสดง redeem script ต้นฉบับ (ซึ่งเป็นสคริปต์ที่ค่าแฮชของมันถูกใช้ล็อก UTXO ไว้) พร้อมกับลายเซ็นที่จำเป็นเพื่อปลดล็อกสคริปต์นั้น ดังนี้:</p>
<pre><code>&lt;Sig1&gt; &lt;Sig2&gt; &lt;2 PK1 PK2 PK3 PK4 PK5 5 OP_CHECKMULTISIG&gt;
</code></pre>
<p>สคริปต์ทั้งสองจะถูกรวมกันเป็นสองขั้นตอน ขั้นแรก redeem script จะถูกตรวจสอบกับ output script เพื่อยืนยันว่าค่าแฮชตรงกัน:</p>
<pre><code>&lt;2 PK1 PK2 PK3 PK4 PK5 5 OP_CHECKMULTISIG&gt; OP_HASH160 &lt;script hash&gt; OP_EQUAL
</code></pre>
<p>หากค่าแฮชของ redeem script ตรงกัน จากนั้น redeem script จะถูกนำมาประมวลผล:</p>
<pre><code>&lt;Sig1&gt; &lt;Sig2&gt; 2 &lt;PK1&gt; &lt;PK2&gt; &lt;PK3&gt; &lt;PK4&gt; &lt;PK5&gt; 5 OP_CHECKMULTISIG
</code></pre>
<h3>P2SH Addresses</h3>
<p>อีกส่วนสำคัญของฟีเจอร์ P2SH คือความสามารถในการเข้ารหัสค่าแฮชของสคริปต์ให้อยู่ในรูปของ “address” ตามที่กำหนดไว้ใน BIP13 ที่อยู่แบบ P2SH คือการเข้ารหัสแบบ base58check ของค่าแฮชขนาด 20 ไบต์ของสคริปต์ เช่นเดียวกับที่ Bitcoin address ปกติคือการเข้ารหัสแบบ base58check ของค่าแฮชขนาด 20 ไบต์ของ public key ที่อยู่แบบ P2SH ใช้ version prefix เป็น “5” ซึ่งทำให้ที่อยู่ที่ถูกเข้ารหัสออกมาในรูป base58check เริ่มต้นด้วยตัวเลข “3”</p>
<p>ตัวอย่างเช่น สคริปต์ที่ซับซ้อนของบริษัทโมฮัมเหม็ด เมื่อนำไปแฮชและเข้ารหัสแบบ base58check เป็นที่อยู่ P2SH จะได้เป็น:</p>
<pre><code>39RF6JqABiHdYHkfChV6USGMe6Nsr66Gzw
</code></pre>
<p>จากนี้ไป โมฮัมเหม็ดสามารถให้ “address” นี้กับลูกค้าได้ และลูกค้าก็สามารถใช้กระเป๋าเงินบิตคอยน์ทั่วไปแทบทุกแบบ เพื่อทำการชำระเงินอย่างง่าย ๆ ได้ เหมือนกับการจ่ายไปยัง Bitcoin address ปกติทั่วไป ตัวเลขนำหน้า 3 จะช่วยบอกใบ้ให้ทราบว่านี่คือที่อยู่แบบพิเศษ ซึ่งเชื่อมโยงกับสคริปต์ ไม่ใช่กับ public key โดยตรง แต่ในแง่ของการใช้งานแล้ว มันทำงานเหมือนกับการชำระเงินไปยัง Bitcoin address อื่น ๆ ทุกประการ ที่อยู่แบบ </p>
<p>P2SH ช่วยซ่อนความซับซ้อนทั้งหมดเอาไว้ ทำให้ผู้ที่ทำการชำระเงินไม่จำเป็นต้องเห็นหรือเข้าใจสคริปต์เลย</p>
<h3>Benefits of P2SH</h3>
<p>ฟีเจอร์ P2SH มีข้อดีเมื่อเทียบกับการใช้งานสคริปต์ที่ซับซ้อนโดยตรงใน output ดังนี้:</p>
<ul>
<li><p>ความคล้ายคลึงกับ Bitcoin address แบบ legacy เดิม ทำให้ผู้ส่งและซอฟต์แวร์กระเป๋าเงินของผู้ส่ง ไม่จำเป็นต้องมีการออกแบบหรือพัฒนาเพิ่มเติมที่ซับซ้อนเพื่อรองรับ P2SH</p>
</li>
<li><p>P2SH ย้ายภาระในการจัดเก็บข้อมูลของสคริปต์ที่ยาว จากฝั่ง output (ซึ่งนอกจากจะถูกเก็บไว้บนบล็อกเชนแล้ว ยังอยู่ในชุดข้อมูล UTXO set ด้วย) ไปอยู่ที่ฝั่ง input (ซึ่งจะถูกเก็บไว้บนบล็อกเชนเท่านั้น)</p>
</li>
<li><p>P2SH ย้ายภาระในการจัดเก็บข้อมูลของสคริปต์ที่ยาว จากช่วงเวลาปัจจุบันขณะชำระเงิน ไปยังช่วงเวลาในอนาคตเมื่อมีการนำ output นั้นมาใช้จ่าย</p>
</li>
<li><p>P2SH ย้ายภาระค่าธรรมเนียมธุรกรรมที่เกิดจากสคริปต์ยาว จากผู้ส่ง ไปยังผู้รับ ซึ่งเป็นฝ่ายที่ต้องใส่ redeem script ที่ยาวลงไปเมื่อทำการใช้จ่าย</p>
</li>
</ul>
<h3>Redeem Script and Validation</h3>
<p>คุณไม่สามารถใส่ P2SH ซ้อนอยู่ภายใน redeem script ของ P2SH ได้ เนื่องจากข้อกำหนดของ P2SH ไม่ได้รองรับการทำงานแบบเรียกซ้ำ (recursive) นอกจากนี้ แม้ในเชิงเทคนิคจะสามารถใส่ OP_RETURN (ดูหัวข้อ Data Recording Output (OP_RETURN)) ลงไปใน redeem script ได้ เพราะกฎไม่ได้ห้ามไว้ แต่ในทางปฏิบัติกลับไม่มีประโยชน์ใด ๆ เนื่องจากเมื่อมีการประมวลผล OP_RETURN ระหว่างขั้นตอนการตรวจสอบความถูกต้อง ธุรกรรมจะถูกตัดสินว่าไม่ถูกต้องทันที</p>
<p>โปรดสังเกตว่า เนื่องจาก redeem script จะไม่ถูกเผยแพร่ให้เครือข่ายทราบจนกว่าจะมีการพยายามใช้จ่าย P2SH output หากคุณสร้าง output ด้วยค่าแฮชของ redeem script ที่ไม่ถูกต้อง คุณจะไม่สามารถใช้จ่ายมันได้เลย ธุรกรรมที่พยายามใช้จ่าย ซึ่งต้องแนบ redeem script เข้ามาด้วย จะไม่ถูกยอมรับ เนื่องจากสคริปต์นั้นไม่ถูกต้อง สิ่งนี้ก่อให้เกิดความเสี่ยง เพราะเป็นไปได้ที่จะส่งบิตคอยน์ไปยัง P2SH address ที่ไม่สามารถถูกใช้จ่ายได้ในภายหลัง</p>
<blockquote>
<p>คำเตือน: output script แบบ P2SH จะบรรจุเพียงค่าแฮชของ redeem script เท่านั้น ซึ่งไม่ได้ให้ข้อมูลใด ๆ เกี่ยวกับเนื้อหาของ redeem script เลย ดังนั้น P2SH output จะยังคงถูกถือว่าถูกต้องและถูกรับรอง แม้ว่า redeem script ที่ถูกอ้างถึงนั้นจะไม่ถูกต้องก็ตาม ด้วยเหตุนี้เองที่จะทำให้คุณอาจเผลอได้รับบิตคอยน์ในรูปแบบที่ไม่สามารถนำไปใช้จ่ายได้ในภายหลัง</p>
</blockquote>
<h3>Data Recording Output (OP_RETURN)</h3>
<p>บิตคอยน์มีบล็อกเชนกระจายศูนย์ที่มีการประทับเวลา (timestamped blockchain) ซึ่งมีศักยภาพในการนำไปใช้มากกว่าการชำระเงิน หลายคนพยายามใช้ภาษาสคริปต์ของธุรกรรมเพื่อใช้ประโยชน์จากความปลอดภัยและความทนทานของระบบสำหรับแอปพลิเคชันอื่น เช่น บริการทนายความดิจิทัล (digital notary services) ความพยายามในช่วงแรก ๆ เพื่อใช้สคริปต์ของบิตคอยน์ในลักษณะนี้เกี่ยวข้องกับการสร้าง transaction output ที่บันทึกข้อมูลลงบนบล็อกเชน เช่น การบันทึก commitment ต่อไฟล์หนึ่งไฟล์ เพื่อให้ใครก็ตามสามารถตรวจสอบการมีอยู่จริงของไฟล์นั้น ณ วันที่หนึ่งได้ โดยอ้างอิงจากธุรกรรมนั้น</p>
<p>การใช้บล็อกเชนของบิตคอยน์เพื่อเก็บข้อมูลที่ไม่เกี่ยวข้องกับการชำระเงินเป็นประเด็นที่ถกเถียงกัน หลายคนมองว่าเป็นการใช้งานที่ไม่เหมาะสมและควรถูกขัดขวาง ขณะที่อีกกลุ่มมองว่าเป็นตัวอย่างของความสามารถทรงพลังของเทคโนโลยีบล็อกเชนและควรสนับสนุนการทดลองเช่นนี้ ผู้คัดค้านให้เหตุผลว่าการบรรจุข้อมูลเหล่านี้ทำให้ผู้ที่รันฟูลโหนดต้องแบกรับต้นทุนพื้นที่จัดเก็บข้อมูลที่ไม่ใช่สิ่งที่บล็อกเชนถูกออกแบบมาเพื่อรองรับ นอกจากนี้ ธุรกรรมลักษณะนี้ยังอาจสร้าง UTXO ที่ไม่สามารถใช้จ่ายได้ โดยใช้ legacy Bitcoin address เป็นพื้นที่ข้อมูลขนาด 20 ไบต์ เพราะแอดเดรสนั้นถูกใช้เป็นข้อมูลและไม่สอดคล้องกับกุญแจส่วนตัว UTXO ที่เกิดขึ้นจึงไม่มีวันถูกใช้จ่ายได้ และเป็น "ธุรกรรมปลอม" ซึ่งจะไม่ถูกลบออกจาก UTXO set ทำให้ฐานข้อมูล UTXO โตขึ้นเรื่อย ๆ หรือที่เรียกว่า "bloat"</p>
<p>โดยในที่สุดก็ได้มีการประนีประนอมโดยอนุญาตให้ output script ที่เริ่มต้นด้วย OP_RETURN สามารถเพิ่มข้อมูลที่ไม่เกี่ยวกับการชำระเงินลงใน transaction output ได้ อย่างไรก็ตาม แตกต่างจาก UTXO ปลอม OP_RETURN จะสร้างเอาต์พุตที่พิสูจน์ได้อย่างชัดเจนว่าไม่สามารถใช้จ่ายได้ ทำให้ไม่จำเป็นต้องถูกเก็บไว้ใน UTXO set เอาต์พุตที่มี OP_RETURN จะถูกบันทึกลงในบล็อกเชน ดังนั้นจึงใช้พื้นที่ดิสก์และเพิ่มขนาดบล็อกเชน แต่จะไม่ถูกเก็บใน UTXO set และจึงไม่ทำให้ Full node ต้องแบกรับต้นทุนฐานข้อมูลที่แพงขึ้น</p>
<p>OP_RETURN scripts จะมีรูปแบบประมาณนี้:</p>
<pre><code>OP_RETURN &lt;data&gt;
</code></pre>
<p>ส่วนข้อมูล (data portion) มักใช้แทนค่าแฮช เช่น เอาต์พุตจากอัลกอริทึม SHA256 ซึ่งมีขนาด 32 ไบต์ แอปพลิเคชันบางประเภทจะใส่คำนำหน้า (prefix) ไว้หน้าข้อมูล เพื่อช่วยระบุว่าเป็นข้อมูลของแอปพลิเคชันใด ตัวอย่างเช่น บริการรับรองเอกสารดิจิทัล Proof of Existence ใช้คำนำหน้าขนาด 8 ไบต์คือคำว่า DOCPROOF ซึ่งเข้ารหัสแบบ ASCII และแสดงในรูปเลขฐานสิบหกเป็น 44 4f 43 50 52 4f 4f 46</p>
<p>ควรทำความเข้าใจว่าไม่มี input script ใดที่สามารถสอดคล้องกับ OP_RETURN เพื่อนำมา “ใช้จ่าย” (spend) เอาต์พุตแบบ OP_RETURN ได้ จุดประสงค์ทั้งหมดของ OP_RETURN คือการสร้างเอาต์พุตที่ไม่สามารถใช้จ่ายได้ตั้งแต่ต้น ดังนั้นจึงไม่จำเป็นต้องถูกเก็บไว้ใน UTXO set ในฐานะเอาต์พุตที่อาจถูกใช้จ่ายในอนาคต กล่าวได้ว่า OP_RETURN outputs เป็นเอาต์พุตที่พิสูจน์ได้ชัดเจนว่าไม่สามารถใช้จ่ายได้ (provably unspendable)</p>
<p>โดยทั่วไป OP_RETURN outputs จะกำหนดจำนวนบิตคอยน์เป็นศูนย์ เพราะบิตคอยน์ใด ๆ ที่ถูกกำหนดไว้ในเอาต์พุตลักษณะนี้ จะถือว่าสูญหายไปตลอดกาล หากมีการอ้างอิง OP_RETURN output มาเป็น input ของธุรกรรมใด ธุรกรรมนั้นจะถูกเครื่องยนต์ตรวจสอบสคริปต์ (script validation engine) ยุติการทำงานทันทีและถูกตัดสินว่าไม่ถูกต้อง การทำงานของ OP_RETURN จะทำให้สคริปต์ “คืนค่า” FALSE และหยุดการประมวลผล ดังนั้น หากอ้างอิง OP_RETURN output มาเป็น input โดยไม่ตั้งใจ ธุรกรรมนั้นจะเป็นธุรกรรมที่ไม่ถูกต้องทันที</p>
<h2>ข้อจำกัดของ Transaction Lock Time</h2>
<p>การใช้ค่า lock time ทำให้ผู้ใช้จ่ายสามารถกำหนดเงื่อนไขได้ว่าธุรกรรมจะยังไม่ถูกนำไปรวมอยู่ในบล็อกจนกว่าจะถึงความสูงของบล็อก (block height) หรือเวลาที่กำหนดไว้ แต่ ไม่ได้ ป้องกันไม่ให้เงินก้อนนั้นถูกนำไปใช้จ่ายผ่านธุรกรรมอื่นก่อนหน้านั้น อธิบายด้วยตัวอย่างต่อไปนี้</p>
<p>Alice ลงนามในธุรกรรมที่ใช้จ่ายเอาต์พุตหนึ่งของเธอไปยังที่อยู่ของ Bob และตั้งค่า transaction lock time ไว้ล่วงหน้า 3 เดือน จากนั้น Alice ส่งธุรกรรมนั้นให้ Bob เก็บไว้ เมื่อเป็นเช่นนี้ Alice และ Bob จะทราบว่า:</p>
<ul>
<li>Bob ไม่สามารถกระจาย (broadcast) ธุรกรรมนี้เพื่อรับเงินได้ จนกว่าจะครบกำหนด 3 เดือน  </li>
<li>Bob สามารถกระจายธุรกรรมนี้ได้หลังจากครบ 3 เดือนแล้ว</li>
</ul>
<p>อย่างไรก็ตาม:</p>
<ul>
<li>Alice สามารถสร้างธุรกรรมอีกชุดที่ขัดแย้งกัน โดยใช้จ่ายอินพุตเดียวกันแต่ไม่ใส่ค่า lock time ซึ่งหมายความว่า Alice สามารถใช้จ่าย UTXO เดียวกันได้ก่อนครบ 3 เดือน  </li>
<li>Bob จึงไม่มีหลักประกันใด ๆ ว่า Alice จะไม่ทำเช่นนั้น</li>
</ul>
<p>สิ่งสำคัญคือ ต้องเข้าใจข้อจำกัดของ transaction lock time ให้ชัดเจน เงื่อนไขเพียงอย่างเดียวที่รับประกันได้คือ Bob จะไม่สามารถนำธุรกรรมที่ลงนามล่วงหน้าไปใช้ก่อนครบ 3 เดือนได้ แต่ ไม่มีการรับประกันว่า Bob จะได้รับเงินก้อนนั้นจริง หากต้องการให้ Bob ได้รับเงินอย่างแน่นอน แต่ไม่สามารถใช้จ่ายได้จนกว่าจะครบ 3 เดือน ต้องกำหนดเงื่อนไข timelock ไว้บนตัว UTXO เองในสคริปต์ แทนที่จะกำหนดไว้ในธุรกรรม ซึ่งทำได้ด้วยรูปแบบของ timelock ถัดไปที่เรียกว่า Check Lock Time Verify (CLTV)</p>
<h2>Check Lock Time Verify (OP_CLTV)</h2>
<p>ในเดือนธันวาคม ค.ศ. 2015 ได้มีการเพิ่มรูปแบบของ timelock แบบใหม่เข้ามาในบิตคอยน์ผ่านการอัปเกรดแบบ soft fork โดยอ้างอิงตามข้อกำหนดใน BIP65 มีการเพิ่มคำสั่งสคริปต์ใหม่ที่ชื่อว่า OP_CHECKLOCKTIMEVERIFY (OP_CLTV) เข้าไปในภาษา scripting ของบิตคอยน์ OP_CLTV เป็น timelock ระดับเอาต์พุต (per-output timelock) แตกต่างจาก lock time แบบเดิมซึ่งเป็น timelock ระดับธุรกรรม (per-transaction timelock) ทำให้สามารถกำหนดเงื่อนไขด้านเวลาได้ยืดหยุ่นมากยิ่งขึ้น</p>
<p>กล่าวโดยสรุป เมื่อมีการใส่ opcode OP_CLTV ลงไปในเอาต์พุต เอาต์พุตนั้นจะถูกจำกัดไม่ให้สามารถใช้จ่ายได้จนกว่าจะถึงเวลาที่กำหนดไว้</p>
<p>OP_CLTV ไม่ได้มาแทนที่ lock time แต่ทำหน้าที่จำกัด UTXO เฉพาะรายการ ให้สามารถถูกใช้จ่ายได้ก็ต่อเมื่อธุรกรรมที่จะนำมาใช้จ่ายนั้นมีค่า lock time ที่ตั้งไว้มากกว่าหรือเท่ากับค่าที่กำหนดใน OP_CLTV</p>
<p>คำสั่ง OP_CLTV รับพารามิเตอร์หนึ่งค่าเป็นอินพุต ซึ่งแสดงเป็นตัวเลขในรูปแบบเดียวกับ lock time (อาจเป็นความสูงของบล็อก หรือเวลา Unix epoch) และตามที่คำว่า VERIFY ระบุไว้ OP_CLTV เป็น opcode ประเภทที่หากผลลัพธ์เป็น FALSE จะหยุดการทำงานของสคริปต์ทันที แต่ถ้าผลลัพธ์เป็น TRUE สคริปต์จะทำงานต่อไป</p>
<p>ในการใช้งาน OP_CLTV จะต้องใส่คำสั่งนี้ไว้ใน redeem script ของเอาต์พุตในธุรกรรมที่สร้างเอาต์พุตนั้นขึ้นมา ตัวอย่างเช่น หากอลิซต้องการจ่ายเงินให้บ็อบ ปกติบ็อบอาจยอมรับการจ่ายเงินผ่านสคริปต์ P2SH ลักษณะดังนี้</p>
<pre><code>&lt;Bob's public key&gt; OP_CHECKSIG
</code></pre>
<p>เพื่อทำการล็อกเอาต์พุตไว้จนถึงเวลาที่กำหนด เช่น อีก 3 เดือนนับจากนี้ สคริปต์ P2SH ของบ็อบจะถูกเปลี่ยนเป็นแบบนี้แทน:</p>
<pre><code>&lt;Bob's pubkey&gt; OP_CHECKSIGVERIFY &lt;now + 3 months&gt; OP_CHECKLOCKTIMEVERIFY
</code></pre>
<p>โดยที่ค่า &lt;now {plus} 3 months&gt; คือความสูงบล็อกหรือค่าเวลาที่ประเมินว่าจะตรงกับอีก 3 เดือนหลังจากที่ธุรกรรมถูกขุดลงบล็อก เช่น ความสูงบล็อกปัจจุบัน + 12,960 บล็อก หรือ Unix epoch time ปัจจุบัน + 7,760,000 วินาที</p>
<p>เมื่อบ็อบต้องการใช้จ่าย UTXO นี้ เขาจะสร้างธุรกรรมใหม่ที่อ้างอิง UTXO นั้นเป็นอินพุต จากนั้นใส่ลายเซ็นและกุญแจสาธารณะของเขาในสคริปต์อินพุต พร้อมตั้งค่า lock time ของธุรกรรมให้มากกว่าหรือเท่ากับค่าทิมล็อกที่ระบุไว้ใน OP_CHECKLOCKTIMEVERIFY ที่อลิซกำหนด แล้วจึงกระจายธุรกรรมนี้ไปยังเครือข่ายบิตคอยน์</p>
<p>ธุรกรรมของบ็อบจะถูกประเมินดังนี้: หากค่าพารามิเตอร์ของ OP_CHECKLOCKTIMEVERIFY ที่อลิซตั้งไว้นั้นน้อยกว่าหรือเท่ากับ lock time ของธุรกรรมที่ใช้จ่าย สคริปต์จะทำงานต่อไป (มีผลเหมือนกับไม่มีการทำงาน หรือเหมือน opcode ประเภท OP_NOP) แต่ถ้าค่าดังกล่าวมากกว่า lock time การทำงานของสคริปต์จะหยุดลงทันที และธุรกรรมจะถูกมองว่าไม่ถูกต้อง</p>
<p>กล่าวให้ชัดเจนยิ่งขึ้น BIP65 อธิบายว่า OP_CHECKLOCKTIMEVERIFY จะล้มเหลวและหยุดการทำงานของสคริปต์ทันที หากเกิดเงื่อนไขอย่างใดอย่างหนึ่งต่อไปนี้:</p>
<ul>
<li>สแตกว่างเปล่า  </li>
<li>ค่าบนสุดของสแตกมีค่าน้อยกว่า 0  </li>
<li>ประเภทของ lock time (ความสูงบล็อกเทียบกับ timestamp) ของค่าบนสุดในสแตกไม่ตรงกับประเภทของ lock time ในฟิลด์ lock time ของธุรกรรม  </li>
<li>ค่าบนสุดของสแตกมีค่ามากกว่าค่า lock time ของธุรกรรม  </li>
<li>ฟิลด์ sequence ของอินพุตมีค่าเป็น 0xffffffff</li>
</ul>
<h3>Timelock Conflicts</h3>
<p>OP_CLTV และ locktime นั้นได้ใช้รูปแบบเดียวกันในการอธิบายระยะเวลาในการล๊อค ไม่ว่าจะเป็น block height หรือเมื่อเวลาผ่านไปในหน่วยของวินาทีตาม unix epoch ส่วนที่สำคัญคือ รูปแบบของ timelock จะต้องตรงกับรูปแบบของ OP_CLTV ใน output ทั้งคู่ต้องอ้างอิงแบบเดียวกัน คือจะเป็น block height หรือหน่วยวินาทีก็ตาม</p>
<p>สิ่งนี้หมายความว่าสคริปต์จะไม่มีทางเป็นสคริปต์ได้ ถ้ามีการเรียก OP_CLTV สองครั้งโดยใช้รูแปบบที่แตกต่างกัน คือครั้งนึงเป็น block height และ อีกครั้งหนึ่งเป็น timestamp ซึ่งส่วนนี้เองเป็นข้อผิดพลาดที่เกิดได้ง่ายและมักจะเกิดขึ้น เพราะฉะนั้นควรทดสอบสคริปต์อย่างละเอียดบน testnet หรือใช้เครื่องมือที่ออกแบบมาเพื่อป้องกันปัญหานี้ เช่น Miniscript compiler</p>
<p>ผลอีกอย่างที่สืบเนื่องกันมาจากข้อกำหนดที่ว่าหนึ่งธุรกรรมสามารถใช้ OP_CLTV ได้แบบเดียวเท่านั้น จึงทำให้ในธุรกรรมที่มีหลาย ๆ input โดยแต่ละ input ใช้รูปแบบของ OP_CLTV ที่แตกต่างกัน จะไม่สามารถนำมาสร้างธุรกรรมที่ใช้ input ทั้งสองพร้อมกันได้</p>
<p>โดยหลังจากมีการประมวลผล หากเงื่อนไขของ OP_CLTV เป็นจริง พารามิเตอร์ที่อยู่ก่อนหน้า OP_CLTV จะยังคงอยู่บนสุดของแสตก และอาจจำเป็นต้องเอาออกด้วย OP_DROP เพื่อให้การทำงานของ opcode อื่น ๆ ในสคริปต์ถัดไปได้เป็นไปอย่างถูกต้อง ด้วยเหตุนี้เราจึงมักจะเห็น OP_CHECKLOCKTIMEVERIFY จะถูกใช้ตามด้วย OP_DROP ในสคริปต์ต่าง ๆ เช่นเดียวกับ OP_CSV (จะอธิบายต่อในหัวข้อ Relative timelock) OP_CLTV มีพฤติกรรมที่แตกต่างจาก opcode ในกลุ่ม CHECKVERIFY ตัวอื่น ๆ ตรงที่ไม่ได้นำข้อมูลออกจากสแตก แต่ทั้งนี้ทั้งนั้นมันเป็นเพราะ ซอฟต์ฟอร์กที่เพิ่ม opcode เหล่านี้เข้าไป ได้อาศัยการนิยามใหม่ของ opcode ที่เคยเป็น no-operation (NOP) ซึ่งเดิมไม่ได้ลบข้อมูลออกจากสแตก และพฤติกรรมของ opcode NOP เดิมเหล่านั้นจำเป็นต้องถูกคงไว้เพื่อความเข้ากันได้</p>
<p>และด้วยการใช้ lock time ร่วมกันกับ OP_CLTV นั้นจะทำให้ในส่วนที่เราได้อธิบายไว้ในหัวข้อ ข้อจำกัดของ Transaction Lock Time เปลี่ยนแปลงไปเล็กน้อย เนื่องจากอลิสสามารถส่งบิตคอยน์ของเธอได้ทันที โดยกำหนดให้เงินถูกล๊อคไว้ที่กุญแจของบ๊อบตั้งแต่วินาทีนั้น อลิสจะไม่สามารถใช้เงินก้อนนี้ซ้ำได้อีก และในขณะเดียวกันบ๊อบก็ยังคงต้องรอ 3 เดือนก่อนตามที่กำหนดไว้</p>
<p>อยากตัวอย่างดังกล่าว ผู้อ่านทุกท่านคงจะได้เห็นแล้วว่าการนำ timelock เข้ามาไว้ในภาษา scripting ทำให้ OP_CLTV เปิดโอกาสให้เราสามารถพัฒนาสคริปต์ที่ซับซ้อนและน่าสนใจได้หลากหลายรูปแบบ</p>
<p>ซึ่งมาตรฐานดังกล่าวถูกกำหนดไว้ใน BIP65 (OP_CHECKLOCKTIMEVERIFY)</p>
<h3>Relative Timelocks</h3>
<p>Lock time และ OP_CLTV ทั้งคู่เป็น absolute timelocks กล่าวคือ เป็นการกำหนดเวลาที่ตายตัว ส่วนกลไก timelock อีกสองรูปแบบที่เราจะพิจรณาต่อไปนี้เป็น relative timelocks ซึ่งเป็นการกำหนดเงื่อนไขการใช้จ่าย output โดยอ้างอิงกับกับระยะเวลาตั้งแต่ธุกรรมก่อนหน้าได้รับการยืนยันและถูกบันทึกลงบนบล๊อคเชน</p>
<p>relative timelocks นั้นสามารถช่วยให้เราสามารถกำหนดข้อจำกัดในด้านของเวลาให้กำธุรกรรมนั้น ๆ โดยอ้างอิงจากเวลาที่ธุรกรรมก่อนหน้าถูกยืนยัน หรือกล่าวได้ว่าเวลาของธุรกรรมนั้นจะไม่ถูกนับจนกว่า UTXO ก่อนหน้าจะปรากฎบนบล๊อคเชน ฟังก์ชันนี้มีความสำคัญอย่างยิ่งกับการทำ bidirectional state channels และ Lightning Network (LN) ซึ่งเราจะได้อ่านเรื่องนี้เพิ่มเติมในหัวข้อ state channels </p>
<p>Relative timelocks นั้นได้มีการถูกนำมาใช้งานทั้งในระดับธุรกรรมและในระดับของสคริปต์ เช่นเดียวกันกับ absolute timelocks โดยในระดับธุรกรรมนั้นจะถูกใช้ในฟิลด์ของ sequence ซึ่งเป็นฟิลด์ที่ต้องอยู่ในส่วนของ input ในทุกธุรกรรมของบิตคอยน์ ส่วนในระดับของสคริปต์นั้นจะถูกเรียกใช้ผ่าน opcode ที่ชื่อ OP_CHECKSEQUENCEVERIFY (OP_CSV)</p>
<p>Relative timelocks ถูกนำมาใช้งานตามข้อกำหนดที่ระบุไว้ใน BIP68: Relative Lock-Time Using Consensus-Enforced Sequence Numbers และ BIP112: OP_CHECKSEQUENCEVERIFY</p>
<p>ทั้ง BIP68 และ BIP112 ถูกเปิดใช้งานในเดือนพฤษภาคม ปี 2016 ในรูปแบบของการอัปเกรดกฎ consensus แบบ soft fork</p>
<h3>Relative Timelocks with OP_CSV</h3>
<p>เช่นเดียวกันกับ OP_CLTV และ lock time ในระบบของบิตคอยน์มี opcode ในระดัสคริปต์สำหรับ relative timelock ที่อาศัยค่า sequence ภายในสคริปต์ด้วย opcode นั้นคือ OP_CHECKSEQUENCEVERIFY ซึ่งมักเรียกย่อว่า OP_CSV</p>
<p>เมื่อ opcode อย่าง OP_CSV ถูกประเมิณค่าในสคริปต์ของ UTXO จะอนุญาตให้ใช้จ่ายได้เฉพาะในธุรกรรมที่ค่า sequence ของ input มีค่ามากกว่าหรือเท่ากับพารามิเตอร์ของ OP_CSV เท่านั้น โดยสรุปแล้ว กลไกนี้จะจำกัดการใช้จ่าย UTXO จนกว่าจะมีจำนวนบล็อกหรือเวลาหน่วยวินาทีผ่านไปตามที่กำหนดไว้ นับจากเวลาที่ UTXO นั้นถูกขุดและบันทึกลงในบล็อกเชน</p>
<p>และเช่นเดียวกันกับ CLTV ค่าใน OP_CSV จะต้องมีรูปแบบที่สอดคล้องกับค่า sequence ที่ใช้คู่กัน โดยหาก OP_CSV ถูกกำหนดไว้เป็นจำนวนบล๊อก ค่า sequence ก็จำเป็นต้องอยู่ในรูปแบบของจำนวนบล๊อก และหาก OP_CSV ถูกกำหนดค่าไว้เป็นวินาที ค่า sequence ก็จำเป็นต้องเป็นค่าวินาทีเช่นกัน</p>
<blockquote>
<p>คำเตือน: สคริปต์ที่มีการเรียกใช้ OP_CSV หลายครั้ง จะต้องใช้รูปแบบเดียวกันทั้งหมด คือจะเป็นรูปแบบของวินาที ก็ต้องเป็นวินาทีทั้งหมด ถ้าเป็นจำนวนบล๊อกก็ต้องเป็นจำนวนบล๊อกทั้งหมดเท่านั้น การผสมทั้งสองรูปแบบเข้าด้วยกันจะทำให้สคริปต์นั้นถูกมองว่าไม่ถูกต้อง และไม่สามารถถูกใช้จ่ายได้ตลอดไป ซึ่งเป็นปัญหาเดียวกันกับ OP_CLTV ในหัวข้อ Timelock Conflicts แต่อย่างไรก็ตาม OP_CSV อณุญาติให้มี input ที่ถูกต้องได้หลายแบบภายในธุรกรรมเดียวกัน ดังนั้นปัญหาของการปฎิสัมพันธ์ข้าม input ที่เกิดขึ้นกับ OP_CLTV จึงจะไม่เกิดขึ้นกับ OP_CSV</p>
</blockquote>
<p>relative timelock ด้วย OP_CSV นั้นมีประโยชน์อย่างยิ่งในกรณีที่มีการสร้างและลงนามธุรกรรมหลายรายการที่เชื่อมต่อกันเป็นลูกโซ่ แต่ยังไม่ถูกเผยแพร่ไปยังเครือข่าย นั่นคือถูกเก็บไว้นอกบล็อกเชน ธุรกรรมลูกเหล่านั้นจะไม่สามารถถูกใช้งานได้จนกว่าธุรกรรมแม่จะถูกเผยแพร่ ถูกขุดรวมเข้าไปในบล็อกเชน และมีอายุผ่านไปตามระยะเวลาที่ระบุไว้ใน relative timelock การใช้งานลักษณะนี้แสดงตัวอย่างไว้ใน state channels และ lightning network</p>
<p>OP_CSV ถูกกำหนดรายละเอียดไว้ใน BIP112 และ CHECKSEQUENCEVERIFY</p>
<h3>สคริปต์ที่มีการควบคุมลำดับการทำงาน (เงื่อนไขหลายเงื่อนไข)</h3>
<p>หนึ่งในสิ่งที่น่าสนใจ และคุณสมบัติที่ทรงพลังมาก ๆ ของ Bitcoin script คือการควบคุมลำดับการทำงาน (Flow control) หรือที่เลือกว่าเงื่อนไขหลายเงื่อนไข คุณน่าจะคุ้นเคยกับแนวคิดของ flow control จากภาษาโปรแกรมต่าง ๆ ที่ใช้โครงสร้าง IF…THEN…ELSE เงื่อนไขใน Bitcoin Script แม้จะมีรูปแบบแตกต่างออกไปเล็กน้อย แต่โดยรวมแล้วเป็นโครงสร้างเดียวกัน</p>
<p>ในระดับพื้นฐาน opcode นั้นมีเงื่อนไขของบิตคอยน์ที่ช่วยให้เราสามารถสร้างสคริปต์ที่มีวิธีปลดล็อกได้สองแบบ ขึ้นอยู่กับผลลัพธ์ TRUE/FALSE จากการประเมินเงื่อนไขในทางตรรกะ ตัวอย่างเช่น หากค่า x เป็น TRUE เส้นทางของโค้ดที่ถูกประมวลผลคือ A และหากไม่เป็นเช่นนั้น (ELSE) เส้นทางของโค้ดคือเส้นทาง B</p>
<p>นอกจากนี้ นิพจน์ต่าง  ๆ ภายในเงื่อนไขของบิตคอยน์ยังสามารถทับซ้อนกันได้อย่างไม่จำกัด หรือกล่าวได้ว่าภายในเงื่อนไขใด ๆ สามารถอีกอีกเงื่อนไขอยู่ด้านในได้ สคริปต์ของบิตคอยน์ที่มีการควบคุมลำดับการทำงาน จึงสามารถใช้สร้างสคริปต์ที่ซับซ้อนมาก โดยมีเส้นทางการประมวลผลที่เป็นไปได้หลายร้อยแบบ แม้จะไม่มีข้อจำกัดด้านระดับความลึกของการซ้อนเงื่อนไขแต่กฎฉันทามติ ก็ได้กำหนดข้อจำกัดไว้ที่ขนาดสูงสุดของสคริปต์ในหน่วยไบต์</p>
<p>บิตคอยน์ได้ใช้การควบคุมระดับการทำงานผ่าน opcode  อย่าง OP_IF OP_ELSE OP_ENDIF และ OP_NOTIF นอกจากนี้นิพจน์เงื่อนไขยังสามารถมีตัวดำเนินการเชิงตระกะอย่าง OP_BOOLAND, OP_BOOLOR และ OP_NOT ได้ด้วย</p>
<p>ในภาษาโปรแกรมแบบดั้งเดิม (เชิงกระบวนการ) ส่วนใหญ่ การควบคุมลำดับการทำงานจะมีลักษณะดังนี้:<br>pseudocode ของการควบคุมลำดับการทำงานในภาษาโปรแกรมส่วนใหญ่</p>
<pre><code>if (condition):
  code to run when condition is true
else:
  code to run when condition is false
endif
code to run in either case
</code></pre>
<p>แต่ในภาษาที่อิงกับสแตก (stack-based) อย่าง Bitcoin Script เงื่อนไขเชิงตรรกะจะมาก่อนคำสั่ง IF ซึ่งทำให้โครงสร้างดูเหมือน “กลับด้าน”:<br>การควบคุมลำดับการทำงานใน Bitcoin Script</p>
<pre><code>condition
IF
  code to run when condition is true
OP_ELSE
  code to run when condition is false
OP_ENDIF
code to run in either case
</code></pre>
<p>เมื่ออ่าน Bitcoin Script ให้จำไว้ว่า เงื่อนไขที่ถูกนำมาประเมินค่าจะมาก่อน opcode IF เสมอ</p>
<h2>เงื่อนไขแบบมี verify opcode</h2>
<p>เงื่อนไขในอีกรูปแบบหนึ่งของบิตคอยน์สคริปต์ คือ opcode ใด ๆ ที่ลงท้ายด้วย VERIFY โดยคำต่อท้าย VERIFY หมายความว่า หากเงื่อนไขที่ถูกประเมินค่าไม่เป็น TRUE การทำงานของสคริปต์จะถูกยุติทันที และธุรกรรมจะถูกพิจารณาว่าไม่ถูกต้อง</p>
<p>ซึ่งแตกต่างจากการทำงานของ IF ซึ่งได้เปิดโอกาสให้มีเส้นทางการทำงานหลายรูปแบบ opcode ที่ลงท้ายด้วย VERIFY จะทำหน้าที่เป็น guard clause หรือก็คือตรรกะที่ต้องประเมินผลให้เป็นจริง เพื่อให้การดำเนินการของโปรแกรมสามารถดำเนินต่อไปได้</p>
<p>ตัวอย่างเช่น ในสคริปต์ต่อไปนี้ได้มีการกำหนดให้ต้องมีทั้งลายเซ็นของบ๊อบและค่า preimage ที่เมื่อแฮชแล้วต้องได้ค่าตามที่กำหนด ทั้งสองเงื่อนไขนี้เองต้องถูกทำให้เป็นจริงจึงจะสามารถปลดล๊อคได้:</p>
<p>สคริปต์ที่มี OP_EQUALVERIFY เป็น guard clause</p>
<pre><code>OP_HASH160 &lt;expected hash&gt; OP_EQUALVERIFY &lt;Bob's Pubkey&gt; OP_CHECKSIG
</code></pre>
<p>เพื่อที่จะใช้จ่ายเงินก้อนนี้บ๊อบจำเป็นต้องแสดง preimage และลายเซ็นที่ถูกต้องเท่านั้น</p>
<pre><code>&lt;Bob's Sig&gt; &lt;hash pre-image&gt;
</code></pre>
<p>หากไม่ได้นำเสนอ preimage มาก่อน Bob จะไม่สามารถไปถึงส่วนของสคริปต์ที่ตรวจสอบลายเซ็นของเขาได้</p>
<p>สคริปต์นี้สามารถเขียนใหม่โดยใช้ OP_IF แทนได้ดังนี้:</p>
<p>สคริปต์ที่มี IF ทำหน้าที่เป็น guard clause</p>
<pre><code>OP_HASH160 &lt;expected hash&gt; OP_EQUAL
OP_IF
   &lt;Bob's Pubkey&gt; OP_CHECKSIG
OP_ENDIF
</code></pre>
<p>ข้อมูลยืนยันตัวตนของ Bob ยังคงเหมือนเดิม:</p>
<p>การทำให้สคริปต์ข้างต้นเป็นจริง</p>
<pre><code>&lt;Bob's Sig&gt; &lt;hash pre-image&gt;
</code></pre>
<p>สคริปต์ที่มีการใช้ OP_IF ให้ผลลัพธ์เหมือนกับการใช้ opcode ที่มีคำต่อท้าย VERIFY โดยทั้งสองแบบทำหน้าที่เป็น guard clause เหมือนกัน แต่อย่างไรก็ตาม โครงสร้างที่ใช้ VERIFY ใช้จะมีประสิทธิภาพมากกว่า เนื่องจากมีการใช้ opcode น้อยกว่าสองตัว</p>
<p>แล้วเมื่อไหร่ที่เราควรใช้ VERIFY แล้วเมื่อไหร่ที่เราควรใช้ OP_IF ? หากสิ่งที่เราต้องการทำมีเพียงการกำหนดเงื่อนไขเบื้องต้น (guard clause) VERIFY จะเป็นทางเลือกที่ดีกว่า แต่หากเราต้องการให้มีเส้นทางการทำงานมากกว่าหนึ่งแบบ (flow control) เราจำเป็นต้องใช้โครงสร้างควบคุมลำดับการทำงานแบบ OP_IF...OP_ELSE แทน</p>
<h3>การใช้ Flow control ในสคริปต์</h3>
<p>วิธีใช้การควบคุมลำดับการทำงานโดยทั่วไปภายในสคริปต์ของบิตคอยน์นั้นมักเป็นการสร้างสคริปต์ที่เปิดโอกาสให้สามารถสร้างเส้นทางการทำงานของสคริปต์ได้หลายแบบ โดยแต่ละเส้นทางก็มีวิธีการในการใช้จ่าย UTXO ที่แตกต่างกัน </p>
<p>ลองมาพิจรณาจากตัวยอ่างง่าย ๆ นี้กัน โดยเรามีผู้ที่สามารถลงนามในธุรกรรมนี้ได้สองคน นั้นคืออลิซและบ๊อบโดยขอแค่เป็นใครคนใดคนหนึ่งในสองคนนี้ก็สามารถใช้จ่ายได้ โดยจะเขียนออกมาเป็น 1-of-2 multisig แต่เราจะทำสิ่งเดียวกันนี้โดยใช้คำสั่ง OP_IF:</p>
<pre><code>OP_IF
 &lt;Alice's Pubkey&gt;
OP_ELSE
 &lt;Bob's Pubkey&gt;
OP_ENDIF
OP_CHECKSIG
</code></pre>
<p>ถ้ามองสคริปต์ในตัวอย่างแล้วคุณอาจสงสัยว่า แล้วเงื่อนไขอยู่ตรงไหน? ทำไมไม่มีอะไรอยู่ก่อนคำสั่ง IF เลย</p>
<p>ส่วนเหตุผลนั้นก็เป็นเพราะว่าเงื่อนไขนั้นไม่ได้เป็นส่วนหนึ่งของสคริปต์ แต่จะถูกส่งมาในตอนที่มีการใช้จ่ายแทน ซึ่งทำให้ Alice และ Bob สามารถ “เลือก” เส้นทางการทำงานที่ต้องการได้:</p>
<pre><code>&lt;Alice's Sig&gt; OP_TRUE
</code></pre>
<p>OP_TRUE ที่อยู่ท้ายสุดทำหน้าที่เป็นเงื่อนไข (TRUE) ซึ่งจะทำให้คำสั่ง OP_IF เลือกเส้นทางการใช้จ่ายแรก โดยในเงื่อนไขนี้จะทำให้ public key ที่อลิซมีลายเซ็นตรงกันถูกนำขึ้นสแตก Opcode OP_TRUE หรือที่เรียกว่า OP_1 จะใส่ค่าเลข 1 ลงบนสแตก</p>
<p>ส่วนสำหรับบ๊อบหากต้องการใช้จ่าย UTXO นี้ เขาจะต้องเลือกเส้นทางการทำงานที่สองของ OP_IF โดยให้ค่า FALSE แทน Opcode OP_FALSE หรือที่เรียกว่า OP_0 จะใส่ค่าเป็นอาร์เรย์ไบต์ว่างลงบนสแตก:</p>
<pre><code>&lt;Bob's Sig&gt; OP_FALSE
</code></pre>
<p>input สคริปต์ของ Bob จะทำให้คำสั่ง OP_IF ไปสคริปต์ในส่วนที่สอง (OP_ELSE) ซึ่งต้องการลายเซ็นของบ๊อบแทน</p>
<p>เนื่องจากคำสั่ง OP_IF สามารถซ้อนกันได้ เราจึงสามารถสร้าง “เขาวงกต” ของเส้นทางการทำงานได้ โดย input script จะทำหน้าที่เสมือน “แผนที่” ที่ใช้เลือกว่าจริง ๆ แล้วเส้นทางการทำงานใดจะถูกนำมาใช้</p>
<pre><code>OP_IF
  subscript A
OP_ELSE
  OP_IF
    subscript B
  OP_ELSE
    subscript C
  OP_ENDIF
OP_ENDIF
</code></pre>
<p>ในตัวอย่างนี้จะมีเส้นทางการทำงานทั้งหมดสามเส้นทางด้วยกัน (subscript A, subscript B, subscript C) โดย input script จะเป็นผู้กำหนดเส้นทางตามรูปแบบของลำดับค่า TRUE หรือ FALSE อย่างเช่น หากต้องการเลือกเส้นทาง subscript B input script จะต้องลงท้ายด้วย OP_1 OP_0 (TRUE, FALSE) ค่าเหล่านี้จะถูกนำขึ้นแสตกทำให้ค่า FALSE อยู่จุดบนสุดของแสตก ซึ่ง OP_IF ชั้นนอกจะทำการดึงค่า FALSE ออกมาและนำส่วน OP_ELSE แรก จากนั้นค่า TRUE จะเลื่อนขึ้นมาอยู่บนสุดของแสตก และจะถูกประเมิณโดย OP_IF ชั้นใน ซึ่งจะเลือกเส้นทางการทำงานแบบ B</p>
<p>ด้วยโครงสร้างของสคริปต์แบบนี้ เราจะสามารถสร้าง redeem script ที่มีเส้นทางการทำงานได้หลายสิบ หรือหลายร้อยเส้นทาง โดยแต่ละเส้นจะเสนอวิธีการใช้จ่าย UTXO ที่แตกต่างกันออกไป เมื่อเราต้องการใช้จ่าย เราจะสร้าง input script ที่นำทางไปตามเส้นทางการทำงานนั้น ๆ ด้วยการใส่ค่า TRUE และ FALSE ที่เหมาะสมลงบนสแตกในแต่ละจุดของการควบคุมลำดับการทำงาน</p>
<h3>ตัวอย่างสคริปต์แบบซับซ้อน</h3>
<p>ในส่วนนี้เราจะนำแนวคิดทั้งหมดที่ได้เรียนรู้จากบทนี้มารวมกันไว้ในตัวอย่างเดียว</p>
<p>สมมุติว่าโมฮัมเหม็ด ซึ่งเป็นเจ้าของบริษัทนำเข้าและส่งออกในดูไบ เขาต้องการสร้างบัญชีเงินทุนของบริษัทที่มีกฏเกณฑ์ที่ยืดหยุ่น และแผนของเขาคือการออกแบบมาเพื่อให้ใช้ระดับในการอณุญาติที่แตกต่างกันไปตามเงื่อนไขของ timelock และผู้เข้าร่วมโครงสร้าง multisig นี้จะประกอบไปด้วย โมฮัมเหม็ด หุ้นส่วนอย่าง ซาอีดและไซรา และสุดท้ายเป็นทนายความของบริษัท โดยหุ้นส่วนทั้งสามตัดสินใจโดยใช้หลักเสียงข้างมาก ดังนั้นจะต้องมีอย่างน้อยสองในสามคนเห็นชอบสำหรับกรณีต่าง ๆ แต่อย่างไรก็ตาม ในกรณีที่เกิดปัญหากับ key ของพวกเขา พวกเขาเพียงต้องการให้ทนายความสามารถกู้คืนเงินได้ โดยใช้ลายเซ็นของหุ้นส่วนคนใดคนหนึ่งจากสามคนร่วมด้วย สุดท้ายแล้วหากหุ้นส่วนทั้งหมดไม่สามารถติดต่อได้หรือไม่สามารถปฏิบัติน่าที่ได้เป็นระยะเวลาหนึ่ง พวกเขาต้องการให้ทนายความสามารถจัดการบัญชีได้โดยตรงหลังจากที่เขาได้รับสิทธ์เข้าถึงบันทึกธุรกรรมของบัญชีเงินทุนนี้ได้</p>
<p>สคริปต์ไถ่ถอนแบบ multisignature ที่เปลี่ยนแปลงได้ร่วมกันกับ timelock คือสิ่งที่โมฮัมเหม็ดต้องออกแบบขึ้นมาเพื่อให้บรรลุเป้าหมายนี้</p>
<p>ตัวอย่างที่ 1: การใช้ Multisignature ร่วมกับ timelock</p>
<pre><code>01  OP_IF
02    OP_IF
03      2
04    OP_ELSE
05      &lt;30 days&gt; OP_CHECKSEQUENCEVERIFY OP_DROP
06      &lt;Lawyer's Pubkey&gt; OP_CHECKSIGVERIFY
07      1
08    OP_ENDIF
09    &lt;Mohammed's Pubkey&gt; &lt;Saeed's Pubkey&gt; &lt;Zaira's Pubkey&gt; 3 OP_CHECKMULTISIG
10  OP_ELSE
11    &lt;90 days&gt; OP_CHECKSEQUENCEVERIFY OP_DROP
12    &lt;Lawyer's Pubkey&gt; OP_CHECKSIG
13  OP_ENDIF
</code></pre>
<p>สคริปต์ของโมฮัมเหม็ดใช้โครงสร้างควบคุมลำดับการทำงานแบบ OP_IF…OP_ELSE ที่ซ้อนกันเพื่อสร้างเส้นทางการทำงานทั้งหมดสามเส้นทาง</p>
<p>ในเส้นทางการทำงานเส้นทางแรก สคริปต์นี้จะทำงานเหมือน multisig 2-of-3 ธรรมดา ๆ ระหว่างหุ้นส่วนทั้งสาม โดยเส้นทางการทำงานนี้ประกอบด้วยบรรทัดที่ 3 และบรรทัดที่ 9 โดยบรรทัดที่ 3 กำหนดโดย quorum ของ multisig เป็น 2 (2-of-3) เส้นทางการทำงานนี้สามารถถูกเลือกได้โดยการใส่ OP_TRUE OP_TRUE ต่อท้ายใน input script: </p>
<p>ข้อมูลการใช้จ่ายสำหรับเส้นทางการทำงานแรก (multisig แบบ 2-of-3)</p>
<pre><code>OP_0 &lt;Mohammed's Sig&gt; &lt;Zaira's Sig&gt; OP_TRUE OP_TRUE
</code></pre>
<blockquote>
<p>TIP: OP_0 ที่อยู่ตอนต้นของ input script นี้มีสาเหตุมาจากความผิดปกติของ OP_CHECKMULTISIG ซึ่งจะดึงค่าออกจากแสตกมากกว่าที่ควรหนึ่งค่า ค่าที่ถูกดึงออกมาเกินนี้จะถูกละเลยโดย OP_CHECKMULTISIG แต่มันจำเป็นต้องมีอยู่ มิฉะนั้นสคริปค์จะล้มเหลว การใส่อาร์เรย์ไบต์ว่างด้วย OP_0 จึงเป็นวิธีแก้ปัญหาชั่วคราวสำหรับความผิดปกตินี้ ตามที่อธิบายไว้ในหัวข้อ An Oddity in CHECKMULTISIG Execution</p>
</blockquote>
<p>ในเส้นทางการทำงานเส้นทางที่สองสามารถถูกใช้งานได้ก็ต่อเมื่อผ่านไปแล้ว 30 วันหลังจากที่ UTXO ถูกสร้างขึ้น และเมื่อถึงเวลานั้น สคริปต์จะต้องการลายเซ็นของทนายความ และลายเซ็นจากหนึ่งในหุ้นส่วน (multisig 1 of 3) โดยเงื่อนไขนี้ถูกกำหนดโดยบรรทัดที่ 7 ซึ่งตั้งค่า quorum ของ multisigไว้ที่ 1 และเพื่อเลือกใช้เส้นทางการทำงานนี้ input script จะต้องลงท้ายด้วย OP_FALSE OP_TRUE:</p>
<p>ข้อมูลการใช้จ่ายสำหรับเส้นทางการทำงานที่สอง (ทนายความ + multisig แบบ 1-of-3)</p>
<pre><code>OP_0 &lt;Saeed's Sig&gt; &lt;Lawer's Sig&gt; OP_FALSE OP_TRUE
</code></pre>
<blockquote>
<p>TIP: OP_FALSE จะถูกใส่ลงบนสแตกก่อน จากนั้น OP_TRUE จะถูกใส่ลงไปอยู่ด้านบนของมัน ดังนั้นค่า TRUE จึงถูกดึง (pop) ออกมาก่อนโดย opcode OP_IF ตัวแรก</p>
</blockquote>
<p>สุดท้าย เส้นทางการทำงานที่สามอนุญาตให้ทนายความสามารถใช้จ่ายเงินได้เพียงคนเดียว แต่จะทำได้ก็ต่อเมื่อผ่านไปแล้ว 90 วันเท่านั้น เพื่อเลือกเส้นทางการทำงานนี้  Input script จะต้องลงท้ายด้วย OP_FALSE:</p>
<p>ข้อมูลการใช้จ่ายสำหรับเส้นทางการทำงานที่สาม (ทนายความ)</p>
<pre><code>&lt;Lawyer's Sig&gt; OP_FALSE
</code></pre>
<p>ลองจำลองการรันสคริปต์บนกระดาษเพื่อดูว่ามันทำงานอย่างไรบนสแตก</p>
<h2>Pay to witness public key hash (P2WPKH)</h2>
<p>เริ่มจากดูตัวอย่างของ output script แบบ P2PKH กันก่อน:</p>
<p>ตัวอย่าง output script P2PKH</p>
<pre><code>OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7
OP_EQUALVERIFY OP_CHECKSIG
</code></pre>
<p>เมื่อใช้ segregated witness อลิซจะสร้างสคริปต์แบบ P2WPKH หากสคริปต์นั้นผูกกับ public key เดียวกัน ก็จะมีหน้าตาประมาณนี้: </p>
<pre><code>0 ab68025513c3dbd2f7b92a94e0581f5d50f654e7
</code></pre>
<p>อย่างที่เห็นว่า output script แบบ P2WPKH นั้นเรียบง่ายกว่าสคริปต์แบบ P2PKH เป็นอย่างมากถ้าเราเอามาเปรียบเทียบกัน มันประกอบด้วยค่าเพียงแค่สองค่าเท่านั้นที่จะถูกใส่ลงในแสตกสำหรับการประมวลผลสคริปต์ โดยสำหรับไคล์เอนต์บิตคอยน์รุ่นเก่า ๆ (ที่ยังไม่รองรับ segwit) การใส่สองค่านี้จะดูเหมือน output ที่ใครก็สามารถใช้จ่ายได้ แต่สำหรับไคลเอนต์รุ่นใหม่ที่รองรับ segwit ตัวเลขตัวแรก (0) จะถูกตีความเป็นหมายเลขเวอร์ชัน (witness version) และส่วนที่สอง (ขนาด 20 ไบต์) คือ witness program โดย witness program ขนาด 20 ไบต์นี้ก็คือแฮชของ public key เช่นเดียวกับในสคริปต์แบบ P2PKH</p>
<p>ตอนนี้เรามาดูธุรกรรมที่เกี่ยวข้องกันซึ่งบ๊อบใช้เพื่อจ่าย output นี้กัน โดยสำหรับสคริปต์แบบ lagacy นั้น ธุรกรรมที่ใช้จ่ายนั้นจะต้องใส่ลายเซ็นไว้ในส่วน input ของธุรกรรม:</p>
<pre><code>[...]
"vin" : [
  "txid": "abcdef12345...",
  "vout": 0,
  "scriptSig": “&lt;Bob’s scriptSig&gt;”,
]
[...]
</code></pre>
<p>แต่อย่างไรก็ตาม เพื่อใช้จ่าย output แบบ P2WPKH ธุรกรรมจะไม่มีลายเซ็นอยู่ในส่วนของ input เลย แต่แทนที่จะเป็นเช่นนั้น ธุรกรรมของบ๊อบจะมี input script ที่ว่างเปล่า และจะใส่ข้อมูลไว้ในส่วนของ witness แทน:</p>
<pre><code>[...]
"vin" : [
  "txid": "abcdef12345...",
  "vout": 0,
  "scriptSig": “”,
]
[...]
“witness”: “&lt;Bob’s witness structure&gt;”
[...]
</code></pre>
<h2>การสร้างกระเป๋าเงินแบบ P2WPKH</h2>
<p>สิ่งที่สำคัญที่สุดและควรจะทราบไว้คือ witness program แบบ P2WPKH ควรจะถูกสร้างขึ้นโดยผู้รับเงินเท่านั้น และไม่ควรแปลงมาจาก public key ของผู้ที่รู้จักอยู่แล้ว เพราะสคริปต์ของ P2PKH หรือแม้แต่จาก address ใด ๆ นั้นผู้ใช้จ่ายไม่มีทางรู้ได้เลยว่ากระเป๋าเงินของผู้รับนั้นสามารถสร้างธุรกรรมแบบ segwit และสามารถใช้จ่าย output แบบ P2WPKH ได้หรือไม่</p>
<p>นอกจากนี้ output แบบ P2WPKH นั้นจะต้องถูกสร้างจาก hash ของ compressed public key เท่านั้น เพราะว่า public key แบบ uncompressed นั้นถือว่าไม่อยู่ในมาตรฐานของ segwit และอาจจะถูกปิดการใช้งานอย่างชัดเจนใน soft fork ที่เกิดขึ้นภายหลัง หาก hash ที่ใช้ได้ใน P2WPKH มาจาก public key แบบ uncompressed จะทำให้ output ที่เกิดขึ้นนั้นไม่สามารถจ่ายออกได้อีก และจะทำให้คุณอาจที่จะสูญเสียเงินนั้นไปตลอดกาล นั่นจึงเป็นเหตุผลที่ว่าทำไม output แบบ P2WPKH นั้นถึงควรถูกสร้างโดยแอปกระเป๋าเงินของผู้รับผ่านการสร้าง compress public key จาก private key ของเขาเอง</p>
<blockquote>
<p>Warning: P2WPKH ควรถูกสร้างโดยผู้รับ โดยการนำ public key แบบ compressed มาแปลงเป็น P2WPKH hash เท่านั้น ไม่ควรให้ผู้ใช้หรือบุคคลอื่นใด แปลง P2PKH script, Address, หรือ public key แบบ uncompressed ให้กลายเป็น P2WPKH witness script ซึ่งเป็นเรื่องปกติอยู่แล้วที่ผู้ใช้ควรส่งเงินให้ผู้รับ ในรูปแบบที่ผู้รับได้ระบุไว้เท่านั้น</p>
</blockquote>
<h3>Pay to witness script hash (P2WSH)</h3>
<p>witness program ประเภทนี้จะสอดคล้องกันกับ P2SH ที่เราได้ผ่านกันมาก่อนหน้านี้ ในหัวข้อของ ในหัวข้อ Pay to Script Hash และในตัวอย่างที่บริษัทของนายโมฮัมเหม็ดได้ใช้สคริปต์แบบ P2SH เพื่อทำ multisig โดยสคริปต์ที่ถูกเข้ารหัสของเขาจะมีหน้าตาแบบนี้</p>
<pre><code>OP_HASH160 54c557e07dde5bb6cb791c7a540e0a4796f5e97e OP_EQUAL
</code></pre>
<p>สคริปต์ P2SH นี้อ้างอิงไปยังแฮชของ redeem script ซึ่งได้กำหนดเงื่อนไขการใช้จ่ายแบบ multisig 2-of-3 เอาไว้เพื่อใช้ในการปลดล๊อคเงินทุน การจะใช้จ่าย output นี้ บริษัทของโมฮัมเหม็ดจะต้องแสดง redeem script ซึ่งมีค่าแฮชตรงกันกับ script hash ที่อยู่ภายใน P2SH output พร้อมกับลายเซ็นที่จำเป็นตามเงื่อนไขของ redeem script นั้น โดยใส่ทั้งหมดไว้ภายใน transaction input:</p>
<pre><code>[...]
"vin" : [
  "txid": "abcdef12345...",
  "vout": 0,
  "scriptSig": “&lt;SigA&gt; &lt;SigB&gt; &lt;2 PubA PubB PubC PubD PubE 5 OP_CHECKMULTISIG&gt;”,
]
</code></pre>
<p>ทีนี้เรามาดูกันดีกว่าว่าตัวอย่างที่เกริ่นมาข้างต้นนี้จะถูกอัปเกรดเป็น segwit v0 ได้อย่างไร หากลูกค้าของนายโมฮัมเหม็ดใช้กระเป๋าเงินที่รับรอง segwit พวกเขาจะทำการชำระเงินได้โดยการสร้าง P2WSH output ซึ่งมีลักษณะดังนี้:</p>
<pre><code>0 a9b7b38d972cabc7961dbfbcb841ad4508d133c47ba87457b4a0e8aae86dbb89
</code></pre>
<p>เช่นเดียวกันกับตัวอย่างของ P2WPKH คุณจะเห็นได้ว่าสคริปต์แบบ segregated witness ที่ทำงานในแบบเดียวกันนั้นเรียบง่ายกว่า และนอกจากนี้ยังช่วยลด overhead ของเทมเพลตที่พบในสคริปต์ P2SH ลงไปได้มากอีกด้วย เนื่องจากสคริปต์ของ segreted witness นั้นประกอบด้วยค่าเพียง 2 ค่าที่ถูกใส่ลงในแสตก นั่นคือ witness version(0) และค่าแฮชของ SHA256 ขนาด 32 ไบต์ของ witness script (ในบางครั้งอาจถูกเรียกว่า witness program)</p>
<blockquote>
<p>TIP: ในขณะที่ P2SH ใช้แฮชแบบ RIPEMD160(SHA256(script)) ขนาด 20 ไบต์ แต่ witness program ของ P2WSH จะใช้แฮชแบบ SHA256(script) ขนาด 32 ไบต์ ความแตกต่างในการเลือกอัลกอริทึมในการแฮชนี้ถูกออกแบบมาเพื่อเพิ่มความแข็งแกร่งในด้านความปลอดภัยให้กับ P2WSH แต่ในบางกรณีก็มีบ้างที่ความปลอดภัยระดับ 128 บิตใน P2WSH นั้นมีความปลอดภัยเท่ากับ 80 บิตใน P2SH ดูรายละเอียดเพิ่มเติมได้ที่ P2SH collision attack</p>
</blockquote>
<p>หลังจากนั้นบริษัทของนายโมฮัมเหม็ดก็สามารถใช้จ่าย output แบบ P2WSH ได้โดยการนำเสนอ witness script ที่ถูกต้องพร้อมกับลายเซ็นในจำนวนที่เพียงพอเพื่อทำให้สคริปต์นั้นผ่านเงื่อนไขของ witness script และลายเซ็นเหล่านี้เองจะถูกรวมอยู่ในโครงสร้างของ witness โดยจะไม่มีข้อมูลใดถูกใส่ไว้ใน input script เนื่องจากนี่เป็น native witness program ซึ่งไม่ใช้ฟิลด์ input script เหมือนกับประเภท legacy</p>
<pre><code>[...]
"vin" : [
  "txid": "abcdef12345...",
  "vout": 0,
  "scriptSig": “”,
]
[...]
“witness”: “&lt;SigA&gt; &lt;SigB&gt; &lt;2 PubA PubB PubC PubD PubE 5 OP_CHECKMULTISIG&gt;”
[...]
</code></pre>
<h3>ความแตกต่างระหว่าง P2WPKH และ P2WSH</h3>
<p>ในสองหัวข้อก่อนหน้านี้เราได้อธิบายถึง witness program อยู่ 2 ประเภท ได้แก่ Pay to Witness Public Key Hash (P2WPKH) และ Pay to Witness Script Hash (P2WSH) โดย witness program ของทั้งสองประเภทนั้นมีหมายเลขเวอร์ชันเดียวกัน ตามด้วยการใส่ข้อมูลหนึ่งค่าลงในแสตกเหมือนกัน ทำให้รูปแบบของทั้งสองดูคล้ายคลึงกัน แต่การตีความของทั้งสองนั้นแตกต่างกันอย่างสิ้นเชิง โดยแบบหนึ่งจะถูกตีความเป็นแฮชของ public key ซึ่งปลดล๊อกได้ด้วยลายเซ็นในขณะที่อีกแบบหนึ่งนั้นจะถูกตีความเป็นค่าแฮชของสคริปต์ซึ่งปลดล๊อกได้ด้วย witness script</p>
<p>และความแตกต่างที่สำคัญที่สุดระหว่างทั้งสองคือความยาวของ witness program:</p>
<ul>
<li>witness program ของ P2WPKH มีขนาด 20 ไบต์  </li>
<li>witness program ของ P2WSH มีขนาด 32 ไบต์</li>
</ul>
<p>ความแตกต่างเพียงจุดเดียวนี้เองทำให้โหนดของบิตคอยน์สามารถแยกได้ว่า witness program นั้นเป็นของสคริปต์รูปแบบใด โดยดูจากเพียงแค่ความยาวของแฮช</p>
<h3>การอัปเกรดไปใช้ Segregated Witness</h3>
<p>จากตัวอย่างก่อนหน้านี้ เราจะเห็นได้ว่าการอัปเกรดไปใช้ segregated witness นั้นเป็นกระบวนการที่มี 2 ขั้นตอนด้วยกัน ขั้นตอนแรก คือกระเป๋าเงินต้องสามารถสร้าง output แบบ segwit ได้ จากนั้น output เหล่านี้จึงสามารถถูกใช้ได้ด้วยกระเป๋าเงินที่รู้วิผะีสร้างธุรกรรมแบบ segregated witness โดยในตัวอย่างที่กล่าวมากระเป๋าเงินของอลิซสามารถสร้าง output จ่ายไปยังสคริปต์แบบ segregated witness ได้และกระเป๋าของบ๊อบก็รองรับ segwit และสามารถใช้จ่ายได้เช่นกัน</p>
<p>Segregated witness ถูกนำมาใช้ในลักษณะของการอัปเกรดที่ยังคงเข้ากันได้ย้อนหลัง (backward-compatible) ซึ่งทำให้ไคลเอนต์ทั้งแบบเก่าและแบบใหม่สามารถอยู่ร่วมกันได้ นักพัฒนากระเป๋าเงินได้อัปเกรดซอฟต์แวร์ของตนอย่างอิสระเพื่อเพิ่มความสามารถรองรับ segwit ส่วนรูปแบบเดิมอย่าง P2PKH และ P2SH ก็ยังคงใช้งานได้ตามปกติสำหรับกระเป๋าเงินที่ยังไม่ได้อัปเกรด</p>
<p>สิ่งนี้ทำให้เกิดสองสถานการณ์สำคัญ ซึ่งจะถูกอธิบายในหัวข้อถัดไป:</p>
<ul>
<li>ความสามารถของกระเป๋าเงินฝั่งผู้จ่ายที่ไม่รองรับ segwit ในการชำระเงินให้กับกระเป๋าเงินฝั่งผู้รับที่สามารถประมวลผลธุรกรรมแบบ segwit ได้  </li>
<li>ความสามารถของกระเป๋าเงินฝั่งผู้จ่ายที่รองรับ segwit ในการรับรู้และแยกแยะได้ว่าผู้รับรายใดรองรับ segwit และรายใดไม่รองรับ โดยพิจารณาจากรูปแบบของ address</li>
</ul>
<h3>การฝัง segregated witness ไว้ภายใน P2SH</h3>
<p>สมมุติว่ากระเป๋าเงินของอลิซยังไม่ได้อัปเกรดเป็น segwit แต่กระเป๋าเงินของบ๊อบได้อัปเกรดแล้ว และสามารถจัดการธุรกรรมแบบ segwit ได้ ทั้งอลิซและบ๊อบยังสามารถใช้ output แบบดั้งเดิมที่ไม่ใช้ segwit ได้ตามปกติ อย่างไรก็ตามบ๊อบมักจะต้องการใช้ segwit เพื่อช่วยลดค่าธรรมเนียมธุรกรรมโดยอาศัยต้นทุนที่ต่ำกว่าสำหรับส่วน witness</p>
<p>ในกรณีนี้กระเป๋าเงินของบ๊อบสามารถสร้างที่อยู่แบบ P2SH ซึ่งภายในบรรจุสคริปต์ segwit อยู่ได้ กระเป๋าเงินของอลิซสามารถส่งเงินไปยัง address นั้นได้โดยไม่จำเป็นต้องรู้จักหรือเข้าใจ segwit แต่อย่างใด นอกจากนี้กระเป๋าเงินของบ๊อบก็สามารถใช้จ่าย output นั้นด้วยธุรกรรมแบบ segwit ได้ และทำให้ได้ประโยชน์จาก segwit และช่วยลดค่าธรรมเนียมธุรกรรมได้</p>
<p>สคริปต์ witness ทั้งสองรูปแบบ คือ P2WPKH และ P2WSH สามารถถูกฝังอยู่ภายใน address แบบ P2SH ได้ โดยจะเรียกว่า nested P2WPKH และ nested P2WSH ตามลำดับ</p>
<h3>Nested pay to witness public key hash</h3>
<p>รูปแบบแรกของ output script ที่เราจะพิจรณาคือ nested P2WPKH ซึ่งเป็น witness program แบบ pay to witness public key hash ที่ถูกฝังอยู่ภายในสคริปต์แบบ pay to script hash เพื่อให้กระเป๋าเงินที่ยังไม่รู้จัก segwit สามารถส่งเงินไปยัง output นี้ได้</p>
<p>กระเป๋าเงินของบ๊อบจะสร้าง P2WPKH witness program จาก public key ของ Bob จากนั้นนำ witness program นี้ไปแฮช และนำค่าแฮชที่ได้ไปเข้ารหัสเป็นสคริปต์แบบ P2SH โดยตัวสคริปต์นี้เองจะถูกแปลงเป็น address ของบิตคอยน์ ซึ่งจะเป็น address ที่ขึ้นต้นด้วย 3 เช่นเดียวกันกับ Pay to script hash</p>
<p>กระเป๋าเงินของบ๊อบเริ่มต้นด้วย witness version และ witness program แบบ P2WPKH ที่เราได้เห็นก่อนหน้านี้:</p>
<pre><code>0 ab68025513c3dbd2f7b92a94e0581f5d50f654e7
</code></pre>
<p>ข้อมูลนี้จะประกอบด้วย witness version และค่าแฮชของ public key ของบ๊อบขนาด 20 ไบต์</p>
<p>จากนั้นกระเป๋าของเขาจะนำข้อมูลนี้ไปแฮช โดยเริ่มจาก SHA256 ก่อน แล้วตามด้วย RIPEMD 160 ทำให้ได้ค่าแฮชขนาด 20 ไบต์อีกค่าหนึ่ง ต่อมาแฮชของ redeem script นี้จะถูกแปลงเป็น address ของบิตคอยน์ในท้ายที่สุด จากนั้นกระเป๋าเงินของอลิซก็สามารถส่งเงินไปยังที่อยู่ 37Lx99uaGn5avKBxiW26HjedQE3LrDCZru ได้เช่นเดียวกันกับการส่งไปยัง address ทั่ว ๆ ไป</p>
<p>เพื่อจ่ายเงินให้บ๊อบ กระเป๋าเงินของอลิซจะล็อกเอาต์พุตด้วยสคริปต์แบบ P2SH ดังนี้:</p>
<pre><code>OP_HASH160 3e0547268b3b19288b3adef9719ec8659f4b2b0b OP_EQUAL
</code></pre>
<p>แม้ว่ากระเป๋าเงินของอลิซจะไม่รองรับ segwit เลยก็ตาม แต่การชำระเงินที่เธอสร้างขึ้นนี้บ๊อบก็ยังสามารถนำไปใช้จ่ายต่อได้ด้วยธุรกรรมแบบ segwit</p>
<h3>Nested pay to witness script hash</h3>
<p>ในทำนองเดียวกันกับ witness program แบบ P2WSH สำหรับสคริปต์ multisig หรือสคริปต์ที่ซับซ้อนอื่น ๆ สามารถถูกฝังอยู่ภายใน address แบบ P2SH ได้ ทำให้กระเป๋าเงินใด ๆ ก็ตามสามารถชำระเงินได้ในลักษณะที่เข้ากันได้กับ segwit</p>
<p>ดังที่เราเห็นในหัวข้อของ Pay to witness script hash (P2WSH) บริษัทของโมฮัมเหม็ดใช้การชำระเงินแบบ segregated witness ไปยังสคริปต์ multisignature เพื่อให้ลูกค้าทุกรายสามารถชำระเงินให้บริษัทของเขาได้ ไม่ว่ากระเป๋าเงินของลูกค้าจะอัปเกรดรองรับ segwit แล้วหรือไม่ กระเป๋าเงินของโมฮัมเหม็ดก็สามารถผัง P2WSH witness program ไว้ภายในสคริปต์แบบ P2SH ได้</p>
<p>ขั้นแรกกระเป๋าเงินของโมฮัมเหม็ดจะนำ witness script ไปแฮชด้วย SHA256(ครั้งเดียว) และได้ค่าแฮชดังนี้:</p>
<pre><code>9592d601848d04b172905e0ddb0adde59f1590f1e553ffc81ddc4b0ed927dd73
</code></pre>
<p>ถัดมา witness script ที่ถูกแฮชแล้วจะถูกแปลงให้เป็น P2WSH witness program ที่มีการใส่เวอร์ชันนำหน้า:</p>
<pre><code>0 9592d601848d04b172905e0ddb0adde59f1590f1e553ffc81ddc4b0ed927dd73
</code></pre>
<p>จากนั้น witness program นี้จะถูกแฮชอีกครั้งด้วย SHA256 และ RIPEMD160 ตามลำดับ ทำให้ได้แฮชขนาด 20 ไบต์ใหม่ดังงนี้:</p>
<pre><code>86762607e8fe87c0c37740cddee880988b9455b2
</code></pre>
<p>ต่อมากระเป๋าเงินจะสร้าง address บิตคอยน์ แบบ P2SH จากแฮชนี้:</p>
<pre><code>3Dwz1MXhM6EfFoJChHCxh1jWHb8GQqRenG
</code></pre>
<p>โดยจากจุดนี้เอง ลูกค้าของโมฮัมเหม็ดก็สามารถชำระเงินมายัง address นี้ได้ แม้ว่ากระเป๋าเงินของพวกเขาจะไม่รับรอง segwit ก็ตามเพื่อส่งเงินให้โมฮัมเหม็ด กระเป๋าเงินของผู้ส่งจะล็อก output ด้วยสคริปต์ P2SH ดังต่อไปนี้:</p>
<pre><code>OP_HASH160 86762607e8fe87c0c37740cddee880988b9455b2 OP_EQUAL
</code></pre>
<p>จากนั้นบริษัทของโมฮัมเหม็ดก็สามารถสร้างธุรกรรมแบบ segwit เพื่อใช้จ่ายเงินเหล่านี้ได้ โดยได้รับประโยชน์จากคุณสมบัติของ segwit รวมถึงค่าธรรมเนียมธุรกรรมที่ต่ำลง</p>
<h2>Merklized Alternative Script Trees (MAST)</h2>
<p>การใช้ OP_IF นั้นสามารถกำหนดเงื่อนไขสำหรับการใช้จ่ายได้หลายรูปแบบ แต่แนวทางนี้เองก็มีข้อเสียที่ไม่พึงประสงค์อยู่หลายประการ อาทิเช่น</p>
<h5>น้ำหนัก(ต้นทุนในการทำธุรกรรม)</h5>
<p>ทุกเงื่อนไขที่เพิ่มเข้าไปในสคริปต์นั้นจะทำให้สคริปต์มีขนาดใหญ่ขึ้น ซึ่งจะส่งผลให้ต้นทุนในการทำธุรกรรมเพิ่มขึ้นเมื่อต้องการใช้จ่ายบิตคอยน์ที่ถูกป้องกันไว้ด้วยสคริปต์นี้</p>
<h5>ข้อจำกัดด้านขนาด</h5>
<p>แม้ว่าคุณจะยอมจ่ายค่าธรรมเนียมเพิ่มเพื่อให้ใส่เงื่อนไขได้มากขึ้นก็ตาม แต่ก็ยังมีข้อจำกัดในด้านของเงื่อนไขสูงสุดที่สามารถใส่ได้ในสคริปต์อยู่ดี อย่างเช่น legacy script ถูกจำกัดขนาดไว้ที่ 10,000 ไบต์ ซึ่งทำให้ในทางปฏิบัตินั้นสามารถใส่ได้เพียงไม่กี่ร้อยเงื่อนไขเท่านั้น และแม้ว่าจะสามารถสร้างสคริปต์ที่มีขนาดใหญ่เท่ากับบล๊อคทั้งบล๊อคได้ ก็ยังจะมีได้เพียงประมาณ 20,000 เงื่อนไขเท่านั้นที่ใช้งานได้จริง ซึ่งถือว่ามากแล้วสำหรับการชำระเงินแบบง่าย ๆ แต่ก็เล็กมากเมื่อเทียบกับการใช้งานบางอย่างที่จินตนาการไว้สำหรับบิตคอยน์</p>
<h5>การขาดแคลนความเป็นส่วนตัว</h5>
<p>ทุกเงื่อนไขที่มีการเพิ่มเข้าไปในสคริปต์นั้นจะกลายเป๋นข้อมูลสาธารณะเมื่อคุณใช้จ่ายบิตคอยน์ที่ถูกปกป้องไว้ด้วยสคริปต์นั้น ๆ ตัวอย่างเช่นทนายความและหุ้นส่วนทางธุรกิจของนายโมฮัมเหม็ดก็จะสามารถเห็นสคริปต์ทั้งหมดไม่ว่าจะในตัว multi-signature หรือ timelock ก็ตาม และทุกครั้งที่มีการใช้จ่ายกับบัญชีนี้ จะทำให้ทนายความของพวกเขาติดตามธุรกรรมทั้งหมดได้แม้ว่าจะไม่ได้ร่วมลงนามก็ตาม</p>
<p>แต่อย่างไรก็ตาม บิตคอยน์มีการใช้โครงสร้างข้อมูลที่เรียกว่า merkle tree อยู่แล้ว ซึ่งมันช่วยให้สามารถตรวจสอบได้ว่าองค์ประกอบใด ๆ เป็นสมาชิกของข้อมูลหรือไม่โดยไม่จำเป็นต้องเปิดเผยหรือระบุสมาชิกอื่น ๆ ทั้งหมดของชุดนั้น</p>
<p>ซึ่งเราจะได้เรียนรู้เกี่ยวกับ merkle tree มากขึ้นในหัวข้อของ merkle trees แต่สาระสำคัญคือ สมาชิกแต่ละตัวของชุดข้อมูลที่เราต้องการ (เช่น เงื่อนไขการอณุญาตที่มีความยาวเท่าใดก็ได้) สามารถนำไปผ่านฟังก์ชันแฮชแล้วนำแฮชมารวมกันอีกครั้งเพื่อสร้างค่าผูกมัดของกิ่งทั้งสองกิ่ง ซึ่งเรียกว่า branch commitment</p>
<p>โดยค่าผูกมัดของกิ่งทั้งสองเองก็สามารถสร้างได้ด้วยวิธีเดียวกัน ขั้นตอนนี้จะถูกทำซ้ำเรื่อย ๆ จนเหลือตัวเดียวและเราจะเรียกตัวนั้นว่า merkle root</p>
<p>จากตัวอย่างสคริปต์ในหัวข้อ Variable multi-signature with timelock เราสามารถสร้าง Merkle tree สำหรับเงื่อนไขการอณุญาตทั้งสามแบบใน A MAST ที่มีสามสคริปต์ย่อยได้<br> <img src="https://image.nostr.build/3d6230c0a0ee745196a957384b79606c729d3829efbaf1b4125e357bc6a68f24.jpg" alt="image"></p>
<p>ในขณะนี้เราสามารถสร้างหลักฐานการเป็นสมาชิกแบบกระทัดรัด (Compact membership proof) เพื่อพิสูจน์ได้ว่าเงื่อนไขการอนุญาตเงื่อนไขใดเงื่อนไขหนึ่งเป็นสมาชิกของ merkle tree โดยไม่ต้องเปิดเผยรายละเอียดใด ๆ ของสมาชิกอื่น ๆ ใน merkle tree สามาดูได้ในตัวอย่างของ A MAST membership proof for one of the subscripts และสังเกตว่าโหนดที่แรเงาไว้สามารถคำนวณได้จากข้อมูลอื่นที่ผู้ใช้ให้มา ดังนั้นจึงไม่จำเป็นต้องระบุโหนดเหล่านั้นในขณะทำการใช้จ่าย<br> <img src="https://image.nostr.build/3a5c3e43c266357582fb4bc17eedefaed398306d84750072af061d07cc99e513.jpg" alt="image"></p>
<p>ค่าแฮชที่ใช้ในการสร้างคอมมิจเมนต์แต่ละตัวมีขนาด 32 ไบต์ ดังนั้นการพิสูจน์ว่าการใช้จ่ายใน A MAST membership proof for one of the subscripts ได้รับอนุญาต (โดยใช้ merkle tree และเงื่อนไขที่เกี่ยวข้อง) และได้รับการพิสูจน์ตัวตน(ด้วยการใช้ลายเซ็น) จะใช้ข้อมูลทั้งหมด 383 ไบต์เมื่อเปรียบเทียบกันแล้ว การใช้จ่ายแบบเดียวกันโดยไม่ใช้ merkle tree (กล่าวคือ ต้องแสดงเงื่อนไขทั้งหมดที่เป็นไปได้) ที่จะใช้ข้อมูลถึง 412 ไบต์</p>
<p>การประหยัดได้ 29 ไบต์ (7%) ในตัวอย่างนี้ยังสะท้อนให้เห็นถึงศักยภาพในการประหยัดได้ไม่ครบถ้วน เนื่องจากลักษณะของ merkle tree ที่เป็นโครงสร้างแบบไบนารีทรีนั้น ทุกครั้งที่มีการเพิ่มจำนวนสมาชิกในเซตเพิ่มขึ้นเป็นสองเท่า เราจำเป็นต้องเพิ่มคอมมิตเมนต์ขนาด 32 ไบต์เพียงตัวเดียวเท่านั้น เช่นในกรณีที่มีทั้งหมด 3 เงื่อนไขเราจำเป็นต้องใช้คอมมิตเมนต์ 3 ตัว (ซึ่งหนึ่งในนั้นคือ merkle root ที่ต้องถูกรวมในการอณุญาตอยู่แล้ว) และเรายังสามารถมีคอมมิตเมนต์ได้ถึง 4 ตัวด้วยต้นทุนที่เท่าเดิม และหากมีคอมมิตเมนต์เพิ่มขึ้นอีกตัวหนึ่งจะทำให้เราสามารถรองรับเงื่อนไขได้สูงสุดถึงแปดเงื่อนไขด้วยกัน และในทำนองเดียวกันหากเรามี 16 คอมมิตเมนต์(ขนาดรวมเป็น 512 ไบต์) เราจะสามารถมีเงื่อนไขการอณุญาตได้มากกว่า 32,000 เงื่อนไข ซึ่งนั้นก็มากเกินกว่าที่จะนำไปใช้ได้จริงในบล็อก ๆ หนึ่งที่เต็มไปด้วยธุรกรรมที่มีคำสั่ง OP_IF ทั้งหมดเสียอีก และหากเราใช้ถึง 128 คอมมิตเมนต์ (4096 ไบต์) จำนวนเงื่อนไขที่เราจะสามารถสร้างได้ในเชิงทฤษฏีจะมีมากเกินกว่าเงื่อนไขทั้งหมดที่คอมพิวเตอร์ทุกเครื่องบนโลกจะสามารถสร้างขึ้นมาได้</p>
<p>โดยทั่วไปแล้ว เงื่อนไขการอณุญาตไม่ได้มีโอกาสถูกใช้งานเท่า ๆ กันทั้งหมด ในกรณีตัวอย่างของเรา เราคาดว่าโมฮัมเหม็ดและหุ้นส่วนของเขาจะใช้จ่ายเป็นประจำ ส่วนเงื่อนไขการหน่วงเวลามีไว้ใช้ในกรณีที่เกิดปัญหาเท่านั้น เราสามารถนำความรู้นี้มาใช้ในการปรับโครงสร้างของ tree ใหม่ทั้งหมดได้ ดังที่แสดงในรูปภาพข้างล่างนี้ โดยมีการจัดสคริปต์ที่คาดว่าจะมีการใช้งานมากที่สุดอยู่ในตำแหน่งที่เหมาะสมที่สุด</p>
<p> <img src="https://image.nostr.build/a60366f9810f9eb3e364bc0d83e4ef733991fdbd3ae1625c9acfe45256b08578.jpg" alt="image"></p>
<p>ในกรณีนี้ เราจำเป็นที่จะต้องให้คอมมิตเมนต์เพียงสองค่าเท่านั้นในกรณีที่ใช้จ่ายแบบที่คาดว่าจะบ่อยที่สุด (ประหยัดได้ 32 ไบต์) แม้ว่าการใช้จ่ายด้วยกรณีอื่น ๆ ยังคงจำเป็นต้องใช้ 3 คอมมิตเมนต์ก็ตาม ซึ่งแบบว่าหากคุณทราบหรือสามารถคาดเดาถึงความน่าจะเป็นของการใช้เงื่อนไขแต่ละแบบได้ คุณจะสามารถใช้อัลกอริทึมอย่าง Huffman เพื่อจัดวางเงื่อนไขเหล่านี้ลงไปในตำแหน่งที่ทำให้มีประสิทธิภาพสูงสุดได้ โดยสามารถดูรายละเอียดเพิ่มเติมได้ใน BIP341</p>
<p>นอกจากจะเพิ่มความซับซ้อนให้กับบิตคอยน์มาอีกเล็กน้อยแล้ว MAST ก็ยังแทบไม่มีข้อเสียที่สำคัญอะไรต่อบิตคอยน์เลย และก่อนที่จะพบแนวทางที่ดีกว่าในภายหลัง (เดี๋ยวเราจะได้เห็นในหัวข้อ taproot) ก็มีข้อเสนอที่แข็งแรงอยู่แล้วถึงสองอันสำหรับ MAST นั้นคือ BIP114 และ BIP116</p>
<h3>MAST เทียบกับ MAST</h3>
<p>แนวคิดแรกเริ่มของสิ่งที่ปัจจุบันเราเรียกว่า MAST ในบิตคอยน์ คือแนวคิดของ merklized abstract syntax trees (ต้นไม้โครงสร้างไวยากรณ์เชิงนามธรรมที่ถูกเมอร์เคิลไลซ์) ในต้นไม้โครงสร้างไวยากรณ์เชิงนามธรรม (AST) แต่ละเงื่อนไขในสคริปต์จะสร้างสาขาใหม่ ดังที่แสดงไว้ในรูปภาพข้างล่าง<br> <img src="https://image.nostr.build/2278f96ec80d7fe7e93c87a73ef70b42934a05bc110abcf9c2d1aa1c41433d91.jpg" alt="image"></p>
<p>AST นั้นได้ถูกใช้อย่างแพร่หลายในโปรแกรมที่ทำหน้าที่แยกวิเคราห์และปรับแต่งโค้ดของโปรแกรมอื่น ๆ เช่น คอมไพเลอร์ หากนำ AST มาใช้ในรูปแบบที่ถูกเมอร์เคิลไลซ์ (merklized AST) ก็จะสามารถผูกมัดได้กับทุกส่วนของโปรแกรม และเปิดให้ใช้คุณสมบัติต่าง ๆ ที่อธิบายไว้ใน merklized Alternative Script Trees (MAST) แต่อย่างไรก็ตามวิธีนี้จะต้องเปิดเผยค่าแฮชขนาด 32 ไบต์อย่างน้อยหนึ่งค่า สำหรับทุกส่วนย่อยของโปรแกรม ซึ่งทำให้ไม่ค่อยมีประสิธิภาพในด้านพื้นที่ของบล็อกเชนสำหรับโปรแกรมส่วนใหญ่</p>
<p>สิ่งที่ผู้คนส่วนใหญ่มักเรียกว่า MAST ในบริบทของบิตคอยน์ในปัจจุบันคือ merklized alternative script trees ซึ่งเป็น backronym ที่ถูกตั้งขึ้นโดยนักพัฒนา Anthony Towns ซึ่ง alternative script tree คือชุดของสคริปต์หลายสคริปต์ ซึ่งแต่ละสคริปต์นั้นมีความสมบูรณืในตัวเองและสามารถเลือกใช้งานได้เพียงหนึ่งสคริปต์เท่านั้น ทำให้สครืปต์เหบ่านี้เป็นทางเลือกแทนกัน ซึ่งแสดงไว้ในภาพด้านล่าง</p>
<p> <img src="https://image.nostr.build/d87c36148baa4429f15264771a0341e787e343df3de17136c16db0d3d61397d6.jpg" alt="image"></p>
<p>ต้นไม้สคริปต์แบบทางเลือก (alternative script trees) ต้องการเพียงเปิดเผยไดเจสเพียง 32 ไบต์เท่านั้นสำหรับความลึกในแต่ละลำดับที่ผู้ใช้เลือกใช้และ merkle root สำหรับสคริปต์ส่วนใหญ่ นี่ถือเป็นการใช้พื้นที่ในบล๊อกเชนที่มีประสิธิภาพมากกว่าเป็นอย่างมาก</p>
<h2>Pay to Contract (P2C)</h2>
<p>ดังที่เราได้เห็นในบทก่อนหน้าในหัวข้อ public child key derivation คณิตศาสตร์ของการเข้ารหัสด้วยเส้นโค้งวงรี (Eliptic Curve Cryptography:ECC) อณุญาตให้อลิซใช้ private key เพื่อสร้าง public key ที่เธอมอบให้บ๊อบ สามารถเพิ่มค่าที่เป็นไปได้ค่าใดก็ได้เข้ามาใน public key นั้น  เพื่อสร้าง public key ใหม่ขึ้นมา หากบ๊อบส่งค่าที่เขาเพิ่มนั้นกลับไปให้อลิซ เธอก็สามารถนำค่าเดียวกันไปบวกกับ private key ของเธอ เพื่อสร้าง private key ที่สอดคล้องกับ public key ที่ถูกอนุพันธ์ขึ้นมาได้</p>
<p>สรุปสั้น ๆ ก็คือบ๊อบสามารถสร้าง child public key ซึ่งมีเพียงอลิซเท่านั้นที่สามารถสร้าง private key ที่สอดคล้องกันขึ้นมาได้ สิ่งนี้เป็นประโยชน์สำหรับการกู้คืนกระเป๋าเงินแบบ Hierarchical Determinstic (HD) ตามมาตรฐานของ BIP32 แต่ก็ยังสามารถนำไปใช้ในวัตถุประสงค์อื่นได้อีกด้วย</p>
<p>ลองจินตนาการดูสิว่าบ๊อบต้องการซื้อของบางอย่างจากอลิซ แต่เขาก็ต้องการความสามารถในการพิสูจน์ภายหลังได้ว่าเขาจ่ายเงินไปเพื่ออะไร ในกรณีที่เกิดข้อพิพาทขึ้นอลิซและบ๊อบจึงตกลงกันเกี่ยวกับชื่อของสินค้าหรือบริการที่ขาย (เช่น “พอดแคสต์ของอลิซตอนที่#123”) แล้วแปลงคำอธิบายนั้นให้เป็นตัวเลข โดยการนำไปแฮชและตีความค่าแฮชที่ได้เป็นตัวเลข จากนั้นบ๊อบนำตัวเลขนั้นไปบวกกับ public key ของอลิซและจ่ายเงินให้ไป กระบวนการนี้เรียกว่า key tweaking และตัวเลขนั้นเรียกว่า tweak</p>
<p>อลิซสามารถใช้จ่ายเงินดังกล่าวได้โดยการปรับแต่ง(tweak) private key ของตัวเธอเองด้วยเลขเดียวกัน</p>
<p>และในภายหลังบ๊อบเองก็สามารถพิสูจน์กับใครก็ตามได้ว่าเขาได้จ่ายเงินให้อลิซเพื่ออะไร โดยการเปิดเผยถึงกุญแจตั้งต้น (underlying key) ของอลิซและคำอธิบายของสินค้าหรือบริการที่ทั้งสองใช้ร่วมกัน ทุกคนสามารถตรวจสอบได้ว่า public key ที่ถูกนำไปใช้ชำระเงินนั้นเท่ากับกุญแจตั้งต้นบวกกับค่าแฮช ของคำอธิบายนั้น และหากอลิซยอมรับว่ากุญแจดังกล่าวเป็นของเธอ ก็ย่อมแสดงว่าเธอยอมรับว่าเธอเป็นผู้รับเงินก้อนนั้น และหากอลิซเป็นผู้ใช้จ่ายเงินออกไป ก็ยิ่งเป็นหลักฐานยืนยันเพิ่มเติมว่าเธอรู้คำอธิบายนั้นตั้งแต่ตอนที่เธอลงนามในธุรกรรมการจ่ายเงิน เพราะเธอสามารถสร้างลายเซ็นที่ถูกต้องได้สำหรับ public key ที่ถูกปรับแต่ง ได้ก็ต่อเมื่อเธอรู้ว่าค่า tweak คืออะไรเท่านั้น</p>
<p>หากอลิซและบ๊อบไม่ได้ตัดสินใจเปิดเผยคำอธิบายที่พวกเขาใช้ต่อสาธารณะการชำระเงินระหว่างทั้งสองก็จะดูไม่ต่างจากการชำระเงินทั่วไปอื่น ๆ และจะไม่ก่อให้เกิดการสูญเสียความเป็นส่วนตัวแต่อย่างใด</p>
<p>เนื่องจาก P2C มีความเป็นส่วนตัวโดยปริยาย เราจึงไม่สามารถทราบได้ว่ามันถูกใช้งานตามวัตถุประสงค์ดั้งเดิมบ่อยเพียงใด ในทางทฤษฏีแล้ว การชำระเงินทุกครั้งอาจใช้วิธีนี้ก็ได้ แม้ว่าเราจะมองว่าสถานการณ์เช่นนั้นไม่น่าเกิดขึ้นก็ตาม แต่ในปัจจุบันนั้น P2C ถูกใช้อย่างแพร่หลายในรูปแบบที่แตกต่างกันออกไปเล็กน้อย ซึ่งเราจะได้เห็นกันใน taproot ที่จะอธิบายต่อภายหลัง</p>
<h2>Scriptless Multisignatures and Threshold Signatures</h2>
<p>ในการทำ Scripted Multisignatures คือการพิจรณาสคริปต์ที่กำหนดให้ต้องมีลายเซ็นจากหลายฝ่าย อย่างไรก็ตามยังมีอีกหนึ่งวิธีในการบังคับให้ต้องใช้กุญแจหลายดอกร่วมกัน ซึ่งก็น่าจะทำให้สับสนได้ไม่น้อย เพราะมันก็ถูกเรียกว่า multisignature เช่นกัน แต่เพื่อแยกความแตกต่างระหว่างสองแนวทางนี้ ในส่วนนี้เราจะเรียกเวอร์ชันที่ใช้ opcode แบบ OP_CHECKSIG ว่า script multisignatures และอีกเวอร์ชันที่จะพูดถึงต่อไปว่า scriptless multisignatures</p>
<p>Scriptless multisignature ทำงานโดยให้ผู้เข้าร่วมแต่ละคนสร้างความลับของตนเองขึ้นมาคล้ายกับวิธีสร้าง private key โดยเราจะเรียกความลับนี้ว่า partial private key โดยแม้ว่ามันจะมีความยาวเท่ากับ private key แบบปกติทุกประการจาก partial private key อันนี้ ผู้เข้าร่วมแต่ละคนจะอนุมาน partial public key โดยใช้อัลกอริทึมเดียวกันกับที่ใช้สร้าง public key ทั่วไป ตามที่อธิบายไว้ในหัวข้อ public key derivation จากนั้นผู้เข้าร่วมทุกคนจะแชร์ partial public key ของตนให้กับผู้เข้าร่วมอื่น ๆ และนำกุญแจทั้งหมดมารวมกันเพื่อสร้าง scriptless multisignature public key เพียงดอกเดียว</p>
<p>กุญแจสาธรณะที่ถูกรวมกันนี้จะมีลักษณะไม่ต่างจาก public key ทั่วไป บุคคลที่สามไม่สามารถแยกแยะได้ว่า public key นี้เกิดจากผู้ใช้หลายคนร่วมกัน หรือเป็น public key ธรรมดาที่สร้างขึ้นโดยผู้ใช้เพียงคนเดียว</p>
<p>สำหรับการใช้จ่ายบิตคอยน์ที่ถูกป้องกันด้วย scriptless multisignature public key ผู้เข้าร่วมแต่ละคนจะสร้างลายเซ็นย่อย (partial signature) ของตนเอง จากนั้นลายเซ็นย่อยเหล่านี้จะถูกรวมเข้าด้วยกันเพื่อสร้างเป็นลายเซ็นที่สมบูรณ์ (บางที่เรียกว่า Full signature) ซึ่งก็มีวิธีที่เป็นที่รู้จักกันหลายรูปแบบสำหรับการสร้างและรวมลายเซ็น ซึ่งเราจะกลับมาลงลึกในประเด็นนี้กันอีกครั้งในหัวข้อ Signature (บทที่ 8) และเช่นเดียวกันกับกรณีของ public key สำหรับ scriptless multisignatures ลายเซ็นที่ได้จากกระบวนการนี้จะมีหน้าตาเหมือนกับลายเซ็นทั่วไปทุกประการ บุคคลที่สามไม่สามารถตรวจสอบได้ว่าลายเซ็นนั้นถูกสร้างขึ้นโดยคนเพียงคนเดียวหรือเกิดจากความร่วมมือของผู้คนจำนวนมาก แม้ว่าจะเป็นการร่วมมือกันระดับล้านคนก็มองไม่ออก</p>
<p>Scriptless multisignatures มีทั้งขนาดเล็กกว่าและมีความเป็นส่วนตัวสูงกว่า scripted multisignatures อย่างชัดเจน สำหรับ scripted multisignatures จำนวนไบต์ที่ต้องบันทึกลงในธุรกรรมจะเพิ่มขึ้นตามจำนวนกุญแจและลายเซ็นที่เกี่ยวข้อง ยิ่งมีผู้ลงนามมาก ข้อมูลในธุรกรรมก็ยิ่งใหญ่ตามไปด้วย แต่ในทางตรงกันข้ามกัน สำหรับ scriptless signatures ขนาดของข้อมูลจะคงที่ ไม่ว่าจะมีผู้เข้าร่วมกี่คนก็ตาม แม้จะมีส่วนร่วมโดยคนเป็นล้านคนก็ตาม แต่ละคนสร้าง partial key และ partial signature ของตนเอง ธุรกรรมที่ได้จะมีขนาดข้อมูลเท่ากันทุกประการกับกรณีที่มีผู้ใช้เพียงคนเดียวใช้กุญแจดอกเดียวและลายเซ็นเพียงอันเดียว</p>
<p>ในแง่ของความเป็นส่วนตัวก็เป็นไปในทิศทางเดียวกัน เนื่องจาก scripted multisignatures ต้องเพิ่มข้อมูลทุกครั้งที่มีการเพิ่มกุญแจหรือลายเซ็น ธุรกรรมจึงเปิดเผยโดยนัยว่ามีการใช้กุญแจและลายเซ็นจำนวนเท่าใด ซึ่งอาจทำให้สามารถคาดเดาได้ว่าธุรกรรมนั้นจะสร้างขึ้นโดยกลุ่มคนใด แต่สำหรับ scriptless multisignatures ธุรกรรมทุกอันจะมีลักษณะเหมือนกันหมด และยังเหมือนกับธุรกรรมแบบลายเซ็นเดียวด้วย ทำให้ไม่มีข้อมูลรั่วไหลลออกมาทำให้ลดทอนความเป็นส่วนตัวของผู้ใช้งาน</p>
<p>ส่วนสำหรับข้อเสียของ scriptless multisignatures มีอยู่สองประการ อย่างแรกคืออัลกอริทึมที่ปลอดภัยทั้งหมดซึ่งเป็นที่รู้จักกันในปัจจุบันสำหรับการสร้าง scriptless multisignatures บนบิตคอยน์ จำเป็นต้องมีรอบของการโต้ตอบกันหรือไม่ก็ต้องมีการจัดการสถานะที่รอบคอบกว่าเมื่อเทียบกับ scripted signatures สิ่งนี้กลายเป็นความท้าทายในกรณีที่ลายเซ็นนั้นถูกสร้างโดยอุปกรณ์ลงนามแบบฮาร์ดแวร์ซึ่งแทบไม่มีการเช็คสถานะ และกุญแจกระจายอยู่ในสถานที่ทางกายภาพที่แตกต่างกัน ตัวอย่างเช่น หากคุณเก็บอุปกรณ์ลงนามแบบฮาร์ดแวร์ไว้ในตู้เซฟของธนาคาร สำหรับ scripted multisignature คุณอาจจะต้องไปที่ตู้เซฟนั้นเพียงครั้งเดียว แต่สำหรับ scriptless แล้วคุณอาจต้องไปสองถึงสามครั้งเพื่อทำให้กระบวนการลงนามเสร็จสมบูรณ์</p>
<p>ส่วนข้อเสียอีกอย่างหนึ่งคือการลงนามแบบ threshold signing ไม่เปิดเผยว่าใครเป็นผู้ลงนามจริงใน scripted threshold signing ตัวอย่างเช่น อลิซ บ๊อบ และคอลไลร์ ตกลงกันว่าเพียงมีลายเซ็นจากใครก็ได้สองในสามคน ก็เพียงพอที่จะใช้จ่ายเงินก้อนนี้ได้ หากอลิซและบ๊อบเป็นผู้ลงนามจะต้องใส่ลายเซ็นของทั้งสองคนลงในบล๊อกเชนซึ่งทำให้ใครก็ตามที่รู้จักกุญแจของพวกเขาก็สามารถพิสูจน์ได้ว่าอลิซและบ๊อบเป็นผู้ลงนามและคอไลร์ไม่ใช่ผู้ลงนาม แต่ใน scriptless threshold signing ลายเซ็นที่เกิดจากอลิซและบ๊อบจะแยกไม่ออกจากลายเซ็นที่เกิดขึ้นโดยอลิซกับคอไลร์หรือจากบ๊อบกับคอไลร์ ซึ่งมันเป็นข้อดีด้านความเป็นส่วนตัว เนื่องจากมันไม่เปิดเผยว่าใครร่วมลงนามบ้าง แต่อย่างไรก็ตามมันก็มีข้อเสียตามมา นั้นก็คือแม้ว่าคอไลร์จะอ้างว่าเธอไม่ได้ลงนาม แต่ก็ไม่มีอะไรเลยที่สามารถพิสูจน์ได้ว่าเธอไม่ได้ลงนามจริง ๆ ซึ่งอาจเป็นปัญหาในแง่ความรับผิดชอบและการตรวจสอบย้อนหลัง</p>
<p>สำหรับผู้ใช้ที่ต้องมีการย้ายเงินเข้าออกบ่อย ๆ ข้อดีด้านขนาดธุรกรรมที่เล็กลง และความเป็นส่วนตัวที่เพิ่มขึ้นของ multisignatures มีประโยชน์มากกว่าความยุ่งยากที่อาจเกิดขึ้นเป็นครั้งคราวในการสร้างลายเซ็นและการตรวจสอบย้อนหลังของลายเซ็นเหล่านั้น</p>
<h2>Taproot</h2>
<p>เหตุผลอย่างหนึ่งที่ผู้คนเลือกใช้บิตคอยน์คือสามารถสร้างสัญญาที่ให้ผลลัพธ์ได้อย่างคาดการณ์ได้สูงมาก สัญญาทางกฎหมายที่บังคับใช้โดยศาลขึ้นอยู่กับการตัดสินใจของผู้พิพากษาและคณะลูกขุน ในทางกลับกัน สัญญาของบิตคอยน์มักจะต้องการการกระทำจากผู้เข้าร่วมแต่จะถูกบังคับใช้โดยโหนดแบบเต็มนับพันที่รันโค้ดเหมือนกัน เมื่อได้รับสัญญาเดียวกันและข้อมูลชุดเดียวกัน โหนดแบบเต็มทุกตัวจะให้ผลลัพธ์เหมือนกันเสมอ การเบี่ยงเบนใด ๆ หมายความว่าบิตคอยน์ถูกทำลายไปแล้ว ผู้พิพากษาและคณะลูกขุนสามารถยืดหยุ่นได้มากกว่าโปรแกรม แต่เมื่อไม่ต้องการหรือไม่จำเป็นต้องมีความยืดหยุ่นนั้น ความสามารถในการคาดการณ์ของสัญญาบิตคอยน์ถือเป็นคุณสมบัติสำคัญ</p>
<p>หากผู้เข้าร่วมทั้งหมดเห็นว่าผลลัพธ์ของสัญญากลายเป็นเรื่องที่คาดการณ์ได้ทั้งหมด จริง ๆ แล้วก็ไม่มีความจำเป็นที่พวกเขาจะต้องใช้สัญญาต่อไป พวกเขาอาจทำในสิ่งที่สัญญาบังคับให้ทำแล้วยุติสัญญา ในสังคม นี่คือวิธีที่สัญญาส่วนใหญ่ยุติ: หากผู้ที่เกี่ยวข้องพอใจ พวกเขาจะไม่ยื่นสัญญาต่อศาล ในบิตคอยน์ หมายความว่าสัญญาที่ย่อมต้องใช้พื้นที่บล็อกจำนวนมากในการยุติ ควรมีข้อคลอสหนึ่งที่อนุญาตให้ยุติโดยความพึงพอใจร่วมกันแทน</p>
<p>ใน MAST และ scriptless multisignatures การออกแบบสัญญาแบบยินยอมร่วมกันเป็นเรื่องง่าย เพราะเราเพียงทำให้หนึ่งในใบไม้ชั้นบนสุดของต้นสคริปต์เป็น scriptless multisignature ระหว่างผู้เข้าร่วมทั้งหมด ซึ่งเราจะแสดงให้เห็นในรูปภาพที่ได้เห็นข้างบนเราสามารถทำให้มันมีประสิทธิภาพยิ่งขึ้นโดยเปลี่ยนจาก scripted multisignature เป็น scriptless multisignature</p>
<p>แนวทางนี้เองถือว่ามีประสิทธิภาพและความเป็นส่วนตัวพอสมควร หากมีการใช้สัญญาการยินยอมร่วมกัน เราจำเป็นต้องเปิดเผยเพียง merkle branch เดียว และสิ่งที่ถูกเปิดเผยก็มีแค่ว่าลายเซ็นใดที่ถูกใช้เท่านั้น ซึ่งอาจเป็นลายเซ็นจากคนเพียงคนเดียว หรือจากผู้เข้าร่วมหลายพันคนก็ไม่ได้มีใครแยกแยะได้</p>
<p>อย่างไรก็ตามในปี 2018 นักพัฒนาได้ตระหนักได้ว่าเราสามารถทำให้ดีกว่านี้ได้อีก หากนำแนวคิด pay to contract มาใช้ร่วมด้วย</p>
<p>ในคำอธิบายก่อนหน้านี้ของ Pay to contract ในหัวข้อ Pay to Contract (P2C) เราได้ tweak public key เพื่อผูกมัดกับข้อความของข้อตกลงระหว่างอลิซและบ๊อบ แทนที่จะเป็นเช่นนั้น เราสามารถผูกมัดกับโค้ดโปรแกรมของสัญญาได้โดยการผูกมัดกับ root ของ MAST tweak public key นั้นเป็น public key ปกติ ซึ่งหมายความว่ามันอาจต้องการลายเซ็นจากบุคคลเดียว หรืออาจเป็นจากหลายคน (หรืออาจถูกสร้างในลักษณะพิเศษให้เป็นไปไม่ได้ที่จะสร้างลายเซ็นสำหรับมัน) นั่นหมายความว่าเราสามารถทำให้สัญญาสำเร็จได้ด้วยลายเซ็นเดียวจากทุกฝ่ายที่เกี่ยวข้อง หรือโดยการเปิด branch ของ MAST ที่เราต้องการใช้ commitment tree ที่ประกอบด้วย public key และ MAST ดังกล่าวดังที่แสดงไว้ในภาพข้างล่าง<br> <img src="https://image.nostr.build/6155acd9c2852a12cea4667b89c2adc912d68aeab458213a729b13bbdb3d811b.jpg" alt="image"></p>
<p>สิ่งนี้เองที่ทำให้สัญญาแบบยินยอมร่วมกันโดยใช้ multisignature มีประสิธิภาพสูงและมีความเป็นส่วนตัวมากยิ่งขึ้น เพราะธุรกรรมที่สร้างโดยใช้โดยคนเพียงคนเดียวซึ่งต้องการให้ยุติโดยลายเซ็นเดียว (หรือ multisignature ที่สร้างโดยหลายกระเป๋าที่เขาควบคุม) จะดูเหมือนกันกับการใช้จ่ายของสัญญาแบบยินยอมร่วมกัน ไม่มีความแตกต่างกันบนบล๊อกเชน ในกรณีนี้ระหว่างการใช้จ่ายโดยกลุ่มผู้ใช้เป็นล้านคนในสัญญาที่ซับซ้อน หรือจ่ายโดยคนเพียงคนเดียว</p>
<p>เมื่อการใช้จ่ายสามารถทำได้โดยใช้เพียงกุญแจ เช่นกรณีลายเซ็นเดี่ยวหรือ scriptless multisig จะเรียกการใช้จ่ายแบบนี้ว่า keypath spending เมื่อใช้ต้นไม้ของสคริปต์ จะเรียกการใช้จ่ายแบบนั้นว่า scriptpath spending สำหรับการใช้จ่ายแบบ keypath ข้อมูลที่จะถูกใส่บนบล๊อกเชนคือ public key (ที่อยู่ใน witness program) และลายเซ็น (ที่อยู่บน witness stack)</p>
<p>สำหรับการใช้จ่ายแบบ scriptpath spending ข้อมูลบนบล๊อกเชนจะรวมถึง public key ด้วยโดย public key นี้จะถูกใส่ไว้ใน witness program และในบริบทนี้เรียกว่า taproot output key โครงสร้างของ witness จะประกอบไปด้วยข้อมูลต่อไปนี้:</p>
<ul>
<li>หมายเลขเวอร์ชัน (Version number)  </li>
<li>กุญแจพื้นฐาน (Underlying key) คือกุญแจที่มีอยู่ก่อนที่จะถูกปรับแต่ง (tweak) ด้วย merkle root เพื่อสร้าง taproot output key กุญแจพื้นฐานนี้เรียกว่า taproot internal key  </li>
<li>สคริปต์ที่ถูกนำมาประมวลผลนี้เรียกว่า leaf script  </li>
<li>ค่าแฮชขนาด 32 ไบต์จำนวนหนึ่งค่าต่อหนึ่งจุดที่เชื่อมใน merkle tree ตามเส้นทางที่ leaf เชื่อมเข้ากับ Merkle root  </li>
<li>ข้อมูลใด ๆ ที่จำเป็นต่อการทำให้สคริปต์เป็นจริง (เช่น ลายเซ็น หรือ hash preimage)</li>
</ul>
<p>ข้อเสียสำคัญเพียงอย่างเดียวของ taproot ที่มีการอธิบายไว้คือ กรณีของสัญญาที่ผู้เข้าร่วมต้องการใช้ MAST แต่ไม่ต้องการมีเงื่อนไขการยุติความพึงพอใจร่วมกัน สัญญาเหล่านั้นจำเป็นต้องบันทึก taproot internal key ได้บนบล๊อกเชน ซึ่งเพิ่ม overhead ประมาณ 33 ไบต์ แต่อย่างไรก็ตาม เนื่องจากคาดว่าสัญญาส่วนใหญ่จะได้รับประโยชน์จากเงื่อนไขหารยุติโดยใช้ความพึงพอใจร่วมกัน หรืออย่างน้อยก็มีเงื่อนไข multisignature อื่นที่ใช้ public key ที่อยู่ในระดับบนสุด และผู้ใช้ทุกคนยังได้รับประโยชน์จากการเพิ่ม anonymity set ที่ทำให้ output มีลักษณะคล้ายกันมากขึ้น overhead ที่เกิดขึ้นในกรณีที่พบไม่บ่อยนี้จึงไม่ถูกมองว่าสำคัญโดยผู้ใช้ส่วนใหญ่ที่มีส่วนร่วมในการเปิดใช้งาน taproot</p>
<p>การรองรับ taproot ถูกเพิ่มเข้ามาในบิตคอยน์ผ่านการทำ soft fork ซึ่งถูกเปิดใช้งานในเดือนพฤศจิกายนปี 2021</p>
<h3>Tapscript</h3>
<p>Taproot ทำให้สามารถใช้ MAST ได้ แต่ในภาษาสคริปต์ของบิตคอยน์ในเวอร์ชันที่แตกต่างจากเดิมเล็กน้อย โดยเวอร์ชันใหม่นี้เรียกว่า Tapscript โดยความแตกต่างสำคัญประกอบด้วย:</p>
<h5>การเปลี่ยนแปลงของ scripted multisignature:</h5>
<p>opcode เดิมอย่าง OP_CHECKMULTISIG และ OP_CHECKMULTISIGVERIFY ถูกนำออกไป เนื่องจาก opcode เหล่านี้ไม่สามารถทำงานร่วมกันได้ดีนักกับการเปลี่ยนแปลงอีกอย่างใน soft fork ของ taproot นั่นคือความสามารถในการใช้ลายเซ็นแบบ schnorr ร่วมกับการตรวจสอบแบบ batch แทนที่ด้วย opcode ใหม่คือ OP_CHECKSIGADD</p>
<p>เมื่อ OP_CHECKSIGADD ตรวจสอบลายเซ็นสำเร็จแล้ว จะเพิ่มค่าตัวนับขึ้นหนึ่ง ทำให้สามารถนับจำนวนลายเซ็นที่ผ่านการตรวจสอบได้อย่างสะดวก และนำไปเปรียบเทียบกับจำนวนลายเซ็นที่ต้องการ เพื่อสร้างพฤติกรรมเดียวกันกับที่ OP_CHECKMULTISIG เคยทำได้</p>
<h5>การเปลี่ยนแปลงของลายเซ็นทั้งหมด:</h5>
<p>การดำเนินการที่เกี่ยวข้องกับลายเซ็นทั้งหมดใน tapscript ใช้อัลกอริทึมลายเซ็นแบบ Schorr จามที่นิยามไว้ใน BIP340 เราจะอธิบายรายละเอียดของลายเซ็นแบบ schorr เพิ่มเติมในบทถัดไป นอกจากนี้ การดำเนินการตรวจสอบใด ๆ ที่คาดว่าจะไม่ผ่านการตรวจสอบ จะต้องได้รับค่า OP_FALSE (หรือที่เรียกว่า OP_0) แทนการส่งลายเซ็นจริงเข้าไป หากส่งค่าอื่นใดไปยังการตรวจสอบลายเซ็นที่ล้มเหลว สคริปต์ทั้งหมดจะล้มเหลวทันที กลไกนี้ยังช่วยสนับสนุนการตรวจสอบลายเซ็น Schnorr แบบ batch validation ได้อีกด้วย</p>
<h5>opcode กลุ่ม OP_SUCCESSx:</h5>
<p>opcode ที่ไม่สามารถใช้งานได้ใน script เวอร์ชันก่อนหน้าได้ถูกนิยามใหม่ให้เมื่อถูกเรียกใช้แล้วทำให้สคริปต์ทั้งหมดสำเร็จทันที (script succeeds) โดยกลไกนี้เปิดทางให้ soft fork ในอนาคตสามารถนิยามเงื่อนไขเพิ่มเติมได้ว่า opcode เหล่านี้จะไม่ทำให้สคริปต์สำเร็จในบางกรณี ซึ่งถือเป็นการ “จำกัดความสามารถลง” และจึงสามารถทำได้ผ่าน soft fork ในทางกลับกัน การเปลี่ยน opcode ที่เดิม ไม่ทำให้สคริปต์สำเร็จ ให้กลายเป็น opcode ที่ทำให้สคริปต์สำเร็จนั้น จะทำได้ผ่าน hard fork เท่านั้น ซึ่งเป็นแนวทางการอัปเกรดที่ยากและมีความเสี่ยงมากกว่า</p>
<p>แม้ว่าในบทนี้เราจะได้พิจรณาเรื่องการให้สิทธิ์และการยืนยันตัวตนอย่างละเอียดแล้ว แต่เรายังข้ามที่ส่วนสำคัญมากส่วนหนึ่งของวิธีที่บิตคอยน์ใช้ยืนยันผู้ใช้จ่ายไป นั่นคือลายเซ็น ซึ่งเราจะไปศึกษาในลำดับถัดไปในบทที่ 8 <img src="https://image.nostr.build/2eb9a47ba4fe6ecbc3d12dae8434d45ad15840655e6ee833420bb2ee307cf614.jpg" alt="image"></p>
]]></itunes:summary>
      <itunes:image href="https://image.nostr.build/2eb9a47ba4fe6ecbc3d12dae8434d45ad15840655e6ee833420bb2ee307cf614.jpg"/>
      </item>
      
      <item>
      <title><![CDATA[สรุป Mastering Bitcoin: Programming the Open Blockchain บทที่ 6]]></title>
      <description><![CDATA[ต้นฉบับแบบว่ายาวไปไม่อ่าน อ่านละปวดหัว มาดูสรุปดีกว่า แต่ดูทรงปวดหัวกว่าเดิม งั้นไปอ่านต้นฉบับล้ากานนนนนนนน]]></description>
             <itunes:subtitle><![CDATA[ต้นฉบับแบบว่ายาวไปไม่อ่าน อ่านละปวดหัว มาดูสรุปดีกว่า แต่ดูทรงปวดหัวกว่าเดิม งั้นไปอ่านต้นฉบับล้ากานนนนนนนน]]></itunes:subtitle>
      <pubDate>Wed, 26 Nov 2025 07:21:18 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/lggw7qwvndvilmhvl5tz3/</link>
      <comments>https://learnbn.npub.pro/post/lggw7qwvndvilmhvl5tz3/</comments>
      <guid isPermaLink="false">naddr1qq25c368wumhz46kfej9v62vf458vnp423drxq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wg7tnyr</guid>
      <category>ลองฟอร์มของไดโน</category>
      
        <media:content url="https://image.nostr.build/4b81c193b6eb1d9d47353f31f88c3268884a8a2a3d74e771052448fec8a6f793.jpg" medium="image"/>
        <enclosure 
          url="https://image.nostr.build/4b81c193b6eb1d9d47353f31f88c3268884a8a2a3d74e771052448fec8a6f793.jpg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qq25c368wumhz46kfej9v62vf458vnp423drxq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wg7tnyr</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<h1>บทที่ 6:Transactions: ธุรกรรมในบิตคอยน์</h1>
<hr>
<p>วิธีที่เรามักใช้ในการโอนเงินสดนั้นแทบไม่เหมือนกับวิธีที่เราโอนบิตคอยน์เลย เงินสดจริงเป็นโทเค็นที่ผู้ใช้ถือครองได้โดยตรง เช่นเมื่ออลิซจ่ายให้บ็อบโดยการยื่นโทเค็นจำนวนหนึ่ง เช่น การส่งธนบัตรดอลลาร์ให้เขา แต่มันไม่ใช่แบบนั้นเลยสำหรับบิตคอยน์  บิตคอยน์ไม่ได้มีอยู่จริงทั้งในรูปแบบทางกายภาพหรือในรูปแบบข้อมูลดิจิทัล อลิซไม่สามารถยื่นบิตคอยน์ให้บ็อบหรือส่งให้ทางอีเมลได้</p>
<p>ลองจินตนการดูว่าหากอลิซต้องการโอนสิทธ์ในการครอบครองที่ดินผืนหนึ่งให้บ๊อบได้อย่างไร เธอไม่สามารถยกที่ดินขึ้นมาแล้วยื่นให้บ็อบได้ แต่จะมีบันทึกบางอย่าง (ที่โดยทั่วไปดูแลโดยหน่วยงานของรัฐท้องถิ่น) ที่ระบุว่าที่ดินผืนนั้นเป็นของอลิซ แปลว่าอลิซสามารถโอนที่ดินให้บ็อบโดยทำให้รัฐบาลอัปเดตบันทึกนั้นให้ระบุว่าบ็อบเป็นเจ้าของที่ดินแทนเธอ</p>
<p>บิตคอยน์ทำงานในลักษณะคล้ายกัน มีฐานข้อมูลของมันอยู่บนโหนดทุก ๆ โหนดของบิตคอยน์ ที่ระบุว่าอลิซควบคุมบิตคอยน์จำนวนหนึ่ง อลิซจ่ายให้บ็อบโดยทำให้โหนด เหล่านั้นอัปเดตฐานข้อมูลของพวกเขาให้ระบุว่าบิตคอยน์บางส่วนของอลิซตอนนี้อยู่ภายใต้การควบคุมของบ็อบ ข้อมูลที่อลิซใช้เพื่อทำให้โหนดอัปเดตฐานข้อมูลของพวกเขาเรียกว่า “ธุรกรรม” ซึ่งกระทำได้โดยไม่ต้องใช้ตัวตนของอลิซหรือบ็อบโดยตรง</p>
<p>ในบทนี้ เราจะมาวิเคราะห์โครงสร้างของธุรกรรมบิตคอยน์และพิจารณาแต่ละส่วนประกอบ เพื่อดูว่ามันเอื้อต่อการโอนมูลค่าได้อย่างไรในรูปแบบที่มีความยืดหยุ่นและน่าเชื่อถือได้อย่างไร</p>
<h2>Serialized Bitcoin Transaction: ธุรกรรมบิตคอยน์ในรูปแบบลำดับข้อมูล</h2>
<p>ในบทที่ 3 เราได้ใช้ Bitcoin Core โดยเปิดใช้งานตัวเลือก txindex เพื่อดึงสำเนาของธุรกรรมการชำระเงินที่อลิซส่งให้บ็อบ ทีนี้เรามาลองดึงธุรกรรมที่มีการชำระเงินนั้นอีกครั้ง โดยจะแสดงอยู่ในธุรกรรมแบบลำดับข้อมูลของอลิซแทน</p>
<pre><code>$ bitcoin-cli getrawtransaction 466200308696215bbc949d5141a49a41\
38ecdfdfaa2a8029c1f9bcecd1f96177

01000000000101eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da13569
8679268041c54a0100000000ffffffff02204e0000000000002251203b41daba
4c9ace578369740f15e5ec880c28279ee7f51b07dca69c7061e07068f8240100
000000001600147752c165ea7be772b2c0acb7f4d6047ae6f4768e0141cf5efe
2d8ef13ed0af21d4f4cb82422d6252d70324f6f4576b727b7d918e521c00b51b
e739df2f899c49dc267c0ad280aca6dab0d2fa2b42a45182fc83e81713010000
0000
</code></pre>
<p>รูปแบบการลำดับข้อมูลของ Bitcoin Core นั้นมีความพิเศษ เพราะเป็นรูปแบบที่ใช้ในการสร้างคอมมิตเมนต์ของธุรกรรมและส่งต่อธุรกรรมนั้นผ่านเครือข่าย P2P ของบิตคอยน์ อย่างไรก็ตาม โปรแกรมอื่น ๆ สามารถใช้รูปแบบที่ต่างออกไปได้ ตราบใดที่มีการส่งข้อมูลชุดเดียวกันทั้งหมด แต่เนื่องจากรูปแบบของ Bitcoin Core มีความกระทัดรัดเมื่อเทียบกับปริมาณข้อมูลที่ส่ง และยังสามารถแยกวิเคราะห์ได้ง่าย โปรแกรมบิตคอยน์อื่น ๆ จำนวนมากจึงเลือกใช้รูปแบบนี้เช่นกัน</p>
<blockquote>
<p>Tip: รูปแบบการลำดับธุรกรรมอีกแบบหนึ่งที่ถูกใช้อย่างแพร่หลายที่เราทราบคือ partially signed bitcoin transaction (PSBT) ซึ่งมีการอธิบายไว้ใน BIP 174 และ BIP 370 (รวมถึงส่วนขยายที่ระบุไว้ใน BIP อื่น ๆ ) PSBT อนุญาตให้โปรแกรมที่ไม่น่าเชื่อถือสร้างเทมเพลตของธุรกรรมขึ้นมา เพื่อให้โปรแกรมที่เชื่อถือได้ (เช่น อุปกรณ์ฮาร์ดแวร์ที่ใช้ลงนามธุรกรรม) ซึ่งถือกุญแจส่วนตัวหรือข้อมูลสำคัญอื่น ๆ ที่จำเป็น สามารถตรวจสอบและเติมข้อมูลในเทมเพลตนั้นได้ เพื่อให้ทำเช่นนี้ได้ PSBT จึงรองรับการจัดเก็บข้อมูลเมตา (metadata) จำนวนมากเกี่ยวกับธุรกรรม ซึ่งทำให้มันมีขนาดใหญ่และไม่กระทัดรัดเท่ารูปแบบการลำดับข้อมูลมาตรฐาน หนังสือเล่มนี้จะไม่ลงรายละเอียดเกี่ยวกับ PSBT แต่เราแนะนำอย่างยิ่งสำหรับนักพัฒนา wallet ที่ต้องการรองรับการเซ็นชื่อด้วยหลายกุญแจ</p>
</blockquote>
<p>ธุรกรรมที่แสดงในรูปเลขฐาน 16 ข้างต้น ถูกจำลองเป็นแผนผังไบต์ในรูปข้างล่างนี้ โปรดสังเกตว่าการแสดงข้อมูลขนาด 32 ไบต์ต้องใช้เลขฐานสิบหกจำนวน 64 ตัว แผนผังนี้แสดงเฉพาะฟิลด์ในระดับบนสุดเท่านั้น เราจะมาพิจารณาแต่ละฟิลด์ตามลำดับที่มันปรากฏในธุรกรรม พร้อมอธิบายฟิลด์เพิ่มเติมที่อยู่ภายในแต่ละส่วน</p>
<p> <img src="https://image.nostr.build/14264e82a143c3c72a68453c951fb6ec4e0a542186c365eee5483108c9de1be7.jpg" alt="image"></p>
<h2>Version</h2>
<p>ไบต์สี่ตัวแรกของธุรกรรมบิตคอยน์ในรูปแบบลำดับข้อมูล คือ “เวอร์ชัน” ของมัน เวอร์ชันดั้งเดิมของธุรกรรมบิตคอยน์คือเวอร์ชัน 1 (0x01000000) ธุรกรรมทั้งหมดในระบบบิตคอยน์ต้องปฏิบัติตามกฎของธุรกรรมเวอร์ชัน 1 ซึ่งหลายส่วนของหนังสือเล่มนี้ได้อธิบายกฎเหล่านั้นไว้แล้ว</p>
<p>ธุรกรรมบิตคอยน์เวอร์ชัน 2 ถูกนำมาใช้ครั้งแรกในการอัปเกรดแบบซอฟต์ฟอร์กตามข้อเสนอ BIP68 ซึ่งเพิ่มข้อจำกัดเพิ่มเติมกับฟิลด์ sequence แต่ข้อจำกัดนี้จะมีผลเฉพาะกับธุรกรรมเวอร์ชัน 2 ขึ้นไปเท่านั้น ส่วนธุรกรรมเวอร์ชัน 1 จะไม่ได้รับผลกระทบ ข้อเสนอ BIP112 ซึ่งเป็นส่วนหนึ่งของซอฟต์ฟอร์กเดียวกันกับ BIP68 ได้อัปเกรดคำสั่ง OP_CHECKSEQUENCEVERIFY โดยทำให้คำสั่งนี้ล้มเหลวหากถูกประเมินในธุรกรรมที่มีเวอร์ชันต่ำกว่า 2 นอกเหนือจากการเปลี่ยนแปลงสองจุดนี้ ธุรกรรมเวอร์ชัน 2 จะเหมือนกับเวอร์ชัน 1 ทุกประการ</p>
<h3>Protecting Presigned Transactions</h3>
<p>ขั้นตอนสุดท้ายก่อนการกระจายธุรกรรมเข้าสู่เครือข่ายเพื่อบันทึกลงในบล็อกเชนคือ “การลงนาม” ธุรกรรม อย่างไรก็ตาม สามารถลงนามในธุรกรรมได้โดยยังไม่ต้องกระจายออกไปทันที คุณสามารถเก็บธุรกรรมที่ลงนามล่วงหน้าไว้นานหลายเดือนหรือหลายปี โดยเชื่อว่าจะสามารถนำมาบันทึกลงบล็อกเชนได้ในภายหลังเมื่อมีการกระจายธุรกรรมนั้น ในระหว่างนั้นคุณอาจสูญเสียการเข้าถึง private key ที่จำเป็นสำหรับการเซ็นธุรกรรมอื่นเพื่อใช้จ่ายเงินเดียวกันได้ ปรากฏการณ์นี้ไม่ใช่เรื่องสมมติ โปรโตคอลหลายอย่างที่สร้างบนบิตคอยน์ เช่น Lightning Network พึ่งพาธุรกรรมที่ลงนามล่วงหน้าเหล่านี้</p>
<p>สิ่งนี้สร้างความท้าทายให้กับนักพัฒนาโปรโตคอล เมื่อพวกเขาต้องช่วยผู้ใช้อัปเกรดโปรโตคอลฉันทามติของบิตคอยน์ การเพิ่มข้อจำกัดใหม่ เช่นที่ BIP68 เพิ่มไว้ในฟิลด์ sequence  อาจทำให้ธุรกรรมที่ลงนามล่วงหน้าบางรายการกลายเป็นโมฆะ และหากไม่สามารถสร้างลายเซ็นใหม่สำหรับธุรกรรมที่เทียบเท่ากันได้ เงินในธุรกรรมเหล่านั้นก็จะสูญหายไปอย่างถาวร</p>
<p>ปัญหานี้ได้รับการแก้ไขโดยการ “สงวน” ฟีเจอร์บางอย่างของธุรกรรมไว้สำหรับการอัปเกรดในอนาคต เช่น หมายเลขเวอร์ชัน ผู้ที่สร้างธุรกรรมแบบลงนามล่วงหน้าก่อน BIP68 ควรใช้ธุรกรรมเวอร์ชัน 1 ดังนั้นการที่ BIP68 กำหนดข้อจำกัดเพิ่มเติมให้มีผลเฉพาะกับธุรกรรมเวอร์ชัน 2 ขึ้นไป จึงไม่ทำให้ธุรกรรมที่ลงนามไว้ก่อนหน้านั้นเป็นโมฆะ</p>
<p>หากคุณกำลังพัฒนาโปรโตคอลที่ใช้ธุรกรรมแบบลงนามล่วงหน้า ให้แน่ใจว่าโปรโตคอลของคุณไม่ได้ใช้ฟีเจอร์ที่ถูกสงวนไว้สำหรับการอัปเกรดในอนาคต นโยบายการส่งต่อธุรกรรม (relay policy) เริ่มต้นของ Bitcoin Core ไม่อนุญาตให้ใช้ฟีเจอร์ที่ถูกสงวนเหล่านี้ คุณสามารถทดสอบว่าธุรกรรมของคุณสอดคล้องกับนโยบายดังกล่าวหรือไม่ โดยใช้คำสั่ง RPC testmempoolaccept บน Bitcoin mainnet</p>
<p>ณ เวลาที่เขียนนี้ มีข้อเสนอให้เริ่มใช้ธุรกรรมเวอร์ชัน 3 อย่างแพร่หลาย ข้อเสนอนี้ไม่ได้เปลี่ยนแปลงกฎฉันทามติของบิตคอยน์ แต่เปลี่ยนเฉพาะนโยบายที่โหนดใช้ในการส่งต่อธุรกรรม โดยภายใต้ข้อเสนอนั้น ธุรกรรมเวอร์ชัน 3 จะถูกกำหนดข้อจำกัดเพิ่มเติม เพื่อป้องกันการโจมตีแบบ Denial of Service (DoS) บางรูปแบบ ซึ่งเราจะกล่าวถึงเพิ่มเติมในส่วนถัดไป</p>
<h2>Extended Marker and Flag: ตัวระบุ Marker และ Flag แบบขยาย</h2>
<p>ฟิลด์สองช่องถัดไปของตัวอย่างธุรกรรมในรูปแบบลำดับข้อมูล ถูกเพิ่มเข้ามาในกระบวนการอัปเกรดแบบ soft fork ของ Segregated Witness (SegWit) ซึ่งเป็นการเปลี่ยนแปลงในกฎฉันทามติของบิตคอยน์ การเปลี่ยนแปลงนี้อ้างอิงตามข้อเสนอ BIP141 และ BIP143 โดยที่รูปแบบการลำดับข้อมูลแบบขยายนี้ถูกกำหนดไว้ใน BIP144</p>
<p>หากธุรกรรมมีโครงสร้างของ witness (ซึ่งเราจะอธิบายในหัวข้อ “Witness Structure”) ค่า marker ต้องเป็นศูนย์ (0x00) และค่า flag ต้องไม่เป็นศูนย์ ในโปรโตคอล P2P ปัจจุบัน ค่าของ flag ควรเป็นหนึ่ง (0x01) เสมอ โดยมีการสงวนค่าอื่นไว้สำหรับการอัปเกรดโปรโตคอลในอนาคต</p>
<p>หากธุรกรรมไม่มีข้อมูล witness stack ค่า marker และ flag จะต้องไม่ปรากฏอยู่ในธุรกรรม ซึ่งทำให้สามารถทำงานร่วมกับรูปแบบการลำดับข้อมูลดั้งเดิมของบิตคอยน์ได้ หรือที่ปัจจุบันเรียกว่า legacy serialization (รายละเอียดเพิ่มเติมดูได้ในหัวข้อ “Legacy Serialization”)</p>
<p>ในรูปแบบ legacy การตีความค่า marker จะถือว่าเป็นจำนวนของอินพุต (ซึ่งในกรณีนี้คือศูนย์) แต่ธุรกรรมไม่สามารถมีอินพุตเป็นศูนย์ได้ ดังนั้น marker จึงทำหน้าที่เป็นสัญญาณให้โปรแกรมรุ่นใหม่รู้ว่า ธุรกรรมนี้ใช้รูปแบบการลำดับข้อมูลแบบขยาย ส่วนฟิลด์ flag ก็ทำหน้าที่ในลักษณะเดียวกัน และยังช่วยให้การอัปเดตรูปแบบการลำดับข้อมูลในอนาคตเป็นไปได้ง่ายขึ้นอีกด้วย</p>
<h2>Inputs</h2>
<p>ฟิลด์ inputs ประกอบด้วยฟิลด์ย่อยหลายส่วน ดังนั้นเราจะมาเริ่มกันจากการดูแผนผังไบต์ของฟิลด์นี้ในตัวอย่างธุรกรรมของอลิซ ที่แสดงไว้ในภาพด้านล่าง<br> <img src="https://image.nostr.build/604cd0c7982b98dde29a0a676db0f8d28e080317d20a1a81a886730139ff3b11.jpg" alt="image"></p>
<h3>Length of Transaction Input List: ความยาวของรายการอินพุตของธุรกรรม</h3>
<p>รายการอินพุตของธุรกรรมจะเริ่มต้นด้วยจำนวนเต็มที่ระบุจำนวนอินพุตทั้งหมดในธุรกรรมนั้น ค่าต่ำสุดคือหนึ่ง และแม้จะไม่มีการกำหนดค่าสูงสุดอย่างชัดเจน แต่ข้อจำกัดของขนาดธุรกรรมสูงสุดในบิตคอยน์จะจำกัดให้ธุรกรรมหนึ่งมีได้เพียงไม่กี่พันอินพุตเท่านั้น ตัวเลขนี้จะถูกเข้ารหัสในรูปแบบ compactSize unsigned integer</p>
<h3>CompactSize Unsigned Integers: จำนวนเต็มแบบ CompactSize</h3>
<p>จำนวนเต็มที่ไม่มีเครื่องหมาย (unsigned integers) ในบิตคอยน์ ซึ่งโดยทั่วไปมักมีค่าต่ำ แต่บางครั้งอาจมีค่าสูง จะถูกเข้ารหัสโดยใช้ชนิดข้อมูลที่เรียกว่า compactSize ซึ่งเป็นรูปแบบของจำนวนเต็มแบบความยาวแปรผัน (variable-length integer) จึงมักถูกเรียกว่า var_int หรือ varint (ดูรายละเอียดเพิ่มเติมได้ในเอกสารของ BIP37 และ BIP144)</p>
<blockquote>
<p>warning: มีรูปแบบของ “จำนวนเต็มแบบความยาวแปรผัน” (variable-length integers) หลายแบบที่ถูกใช้ในโปรแกรมต่าง ๆ รวมถึงโปรแกรมในระบบบิตคอยน์เองด้วย ตัวอย่างเช่น Bitcoin Core ใช้ชนิดข้อมูลที่เรียกว่า VarInts ในการจัดเก็บฐานข้อมูล UTXO ซึ่ง แตกต่างจาก compactSize นอกจากนี้ ฟิลด์ nBits ในส่วนหัวของบล็อก (block header) ก็ถูกเข้ารหัสด้วยชนิดข้อมูลเฉพาะที่เรียกว่า Compact ซึ่งก็ไม่เกี่ยวข้องกับ compactSize เช่นกัน ดังนั้น เมื่อเราอ้างถึงจำนวนเต็มแบบความยาวแปรผันที่ใช้ในการ serialize ธุรกรรมบิตคอยน์ (Bitcoin transaction) และในส่วนอื่นของ โปรโตคอล P2P ของบิตคอยน์ เราจะใช้คำเต็มว่า compactSize เสมอ เพื่อป้องกันความสับสนกับรูปแบบอื่น ๆ ที่ชื่อคล้ายกันแต่มีโครงสร้างต่างกัน</p>
</blockquote>
<p>สำหรับตัวเลขในช่วง 0 ถึง 252 ค่าของ compactSize unsigned integers จะเหมือนกับชนิดข้อมูล uint8_t ในภาษา C ทุกประการ ซึ่งเป็นรูปแบบการเข้ารหัสตัวเลขที่โปรแกรมเมอร์ส่วนใหญ่คุ้นเคยอยู่แล้ว แต่สำหรับตัวเลขที่มีค่ามากกว่า 252 (จนถึง 0xffffffffffffffff) จะมีการเพิ่ม ไบต์นำหน้า (prefix byte) เพื่อระบุความยาวของจำนวนตัวเลขนั้น อย่างไรก็ตาม นอกจากไบต์นำหน้าแล้ว ตัวเลขส่วนที่เหลือจะยังคงมีลักษณะเหมือนกับการเข้ารหัสของจำนวนเต็มแบบ unsigned ปกติในภาษา C อยู่ดี</p>
<table>
<thead>
<tr>
<th align="left">ค่าตัวเลข (Value)</th>
<th>จำนวนไบต์ที่ใช้ (Bytes used)</th>
<th>รูปแบบ (Format)</th>
</tr>
</thead>
<tbody><tr>
<td align="left">≥ 0 และ ≤ 252 (0xfc)</td>
<td>1</td>
<td>เข้ารหัสเป็น uint8_t</td>
</tr>
<tr>
<td align="left">≥ 253 และ ≤ 0xffff</td>
<td>3</td>
<td>เริ่มด้วย 0xfd ตามด้วยตัวเลขที่เข้ารหัสเป็น uint16_t</td>
</tr>
<tr>
<td align="left">≥ 0x10000 และ ≤ 0xffffffff</td>
<td>5</td>
<td>เริ่มด้วย 0xfe ตามด้วยตัวเลขที่เข้ารหัสเป็น uint32_t</td>
</tr>
<tr>
<td align="left">≥ 0x100000000 และ ≤ 0xffffffffffffffff</td>
<td>9</td>
<td>เริ่มด้วย 0xff ตามด้วยตัวเลขที่เข้ารหัสเป็น uint64_t</td>
</tr>
</tbody></table>
<p>อินพุตแต่ละรายการในธุรกรรมจะต้องมีสามฟิลด์หลัก ได้แก่ Outpoint field, Length-prefixed input script field, และ Sequence</p>
<p>เราจะพิจารณาแต่ละฟิลด์เหล่านี้ในส่วนถัดไป อินพุตบางรายการยังมี witness stack ด้วย แต่จะถูกจัดลำดับข้อมูลไว้ที่ท้ายธุรกรรม ดังนั้นเราจะมาศึกษามันในภายหลัง</p>
<h3>Outpoint</h3>
<p>ธุรกรรมบิตคอยน์คือคำขอที่ส่งให้ full node ทำการอัปเดตฐานข้อมูลเกี่ยวกับข้อมูลความเป็นเจ้าของเหรียญ สำหรับอลิซที่จะโอนบิตคอยน์บางส่วนของเธอให้บ๊อบ เธอต้องบอกให้โหนดรู้ก่อนว่าจะหาธุรกรรมก่อนหน้าที่เธอได้รับบิตคอยน์เหล่านั้นได้จากที่ไหน เนื่องจากการควบคุมบิตคอยน์ถูกกำหนดไว้ใน output ของธุรกรรม อลิซจึงชี้ไปยัง output ก่อนหน้าโดยใช้ฟิลด์ outpoint อินพุตแต่ละรายการต้องมี outpoint หนึ่งรายการเสมอ</p>
<p>outpoint ประกอบด้วย txid ขนาด 32 ไบต์ของธุรกรรมที่อลิซได้รับบิตคอยน์ที่เธอต้องการใช้จ่าย txid นี้อยู่ในลำดับไบต์ภายในของบิตคอยน์สำหรับแฮช (ดูหัวข้อ Internal and Display Byte Orders)</p>
<p>เนื่องจากธุรกรรมหนึ่งรายการอาจมีหลาย output อลิซจึงต้องระบุด้วยว่าเธอจะใช้ output ใดจากธุรกรรมนั้น ซึ่งเรียกว่า output index โดย output index เป็นจำนวนเต็มแบบไม่ติดลบ (unsigned integer) ขนาด 4 ไบต์ เริ่มจากศูนย์</p>
<p>เมื่อ full node พบ outpoint มันจะใช้ข้อมูลนี้เพื่อค้นหา output ที่ถูกอ้างอิง โหนดเต็มจะต้องค้นหาเฉพาะธุรกรรมก่อนหน้าในบล็อกเชนเท่านั้น ตัวอย่างเช่น หากธุรกรรมของอลิซถูกบันทึกไว้ในบล็อก 774,958  full node ที่ตรวจสอบธุรกรรมของเธอจะค้นหา output ที่ถูกอ้างอิงในบล็อกนั้นและบล็อกก่อนหน้าเท่านั้น ไม่ใช่บล็อกที่อยู่หลังจากนั้น ภายในบล็อก 774,958 full node จะค้นหาเฉพาะธุรกรรมที่อยู่ก่อนธุรกรรมของอลิซ โดยพิจารณาตามลำดับของ leaf ใน merkle tree ของบล็อกนั้น </p>
<p>เมื่อพบ output ก่อนหน้าแล้ว full node จะได้รับข้อมูลสำคัญหลายอย่างจากมัน ได้แก่</p>
<ul>
<li><p>จำนวนบิตคอยน์ที่ถูกกำหนดไว้ใน output ก่อนหน้า: บิตคอยน์ทั้งหมดใน output นั้นจะถูกโอนไปในธุรกรรมนี้ ตัวอย่างเช่น ในธุรกรรมตัวอย่าง ค่าใน output ก่อนหน้าคือ 100,000 satoshis</p>
</li>
<li><p>เงื่อนไขการอนุญาตของ output ก่อนหน้า: เงื่อนไขที่ต้องถูกปฏิบัติตามเพื่อที่จะใช้จ่ายบิตคอยน์ที่ถูกกำหนดไว้ใน output นั้น</p>
</li>
<li><p>สำหรับธุรกรรมที่ได้รับการยืนยันแล้ว (confirmed transactions) full node จะทราบ block height ที่ธุรกรรมได้รับการยืนยัน และ ค่า median time past (MTP) ของบล็อกนั้น ข้อมูลนี้จำเป็นสำหรับการทำงานของ relative timelock (อธิบายไว้ในหัวข้อ Sequence as a consensus-enforced relative timelock) และสำหรับ output ของ coinbase transaction (อธิบายไว้ในหัวข้อ Coinbase Transactions)</p>
</li>
<li><p>หลักฐานว่า output ก่อนหน้านั้นมีอยู่จริงในบล็อกเชน (หรือเป็นธุรกรรมที่ยังไม่ได้ยืนยันแต่เป็นที่รู้จัก) และยังไม่มีธุรกรรมอื่นใดที่ใช้มันไปแล้ว หนึ่งในกฎฉันทามติของบิตคอยน์ห้ามไม่ให้ output เดียวกันถูกใช้มากกว่าหนึ่งครั้งภายในบล็อกเชน นี่คือกฎที่ป้องกัน double spending อลิซไม่สามารถใช้ output เดิมเดียวกันเพื่อจ่ายทั้งให้บ๊อบและแครอลในธุรกรรมที่แยกกันได้ สองธุรกรรมที่พยายามใช้ output เดียวกันเรียกว่า conflicting transactions เพราะมีเพียงหนึ่งในนั้นเท่านั้นที่สามารถถูกบันทึกในบล็อกเชนได้</p>
</li>
</ul>
<p>แนวทางที่แตกต่างกันในการติดตาม output ก่อนหน้าได้ถูกทดลองใช้โดยการทำงานของ full node ที่แตกต่างกันในช่วงเวลาต่าง ๆ ส่วนในปัจจุบัน Bitcoin Core ใช้วิธีที่เชื่อว่าได้ผลดีที่สุดในการเก็บรักษาข้อมูลที่จำเป็นทั้งหมดในขณะที่ลดการใช้พื้นที่ดิสก์ให้น้อยที่สุด คือมันเก็บฐานข้อมูลที่บันทึกทุก UTXO และเมตาดาต้าที่จำเป็นเกี่ยวกับมัน (เช่น block height) ทุกครั้งที่บล็อกใหม่ของธุรกรรมเข้ามา output ทั้งหมดที่ถูกใช้จะถูกลบออกจากฐานข้อมูล UTXO และ output ทั้งหมดที่ถูกสร้างขึ้นใหม่จะถูกเพิ่มเข้าไปในฐานข้อมูล</p>
<h3>Internal and Display Byte Orders(การจัดเรียงไบต์ภายในและสำหรับการแสดงผล)</h3>
<p>บิตคอยน์ได้ใช้ hash function ที่เรียกว่า digest ในหลายรูปแบบ Digest ถูกใช้เป็นตัวระบุเฉพาะสำหรับบล็อกและธุรกรรม ใช้ในกระบวนการยืนยันความถูกต้องของ address บล็อก ธุรกรรม ลายเซ็น และอื่น ๆ อีกมากมาย นอกจากนี้ digest ยังถูกนำมาใช้ซ้ำในฟังก์ชัน proof-of-work ของ Bitcoin ในบางกรณี digest ของ hash จะถูกแสดงให้ผู้ใช้เห็นในรูปแบบการจัดเรียงไบต์หนึ่ง แต่ระบบภายในกลับใช้รูปแบบการจัดเรียงไบต์อีกแบบหนึ่ง ซึ่งอาจก่อให้เกิดความสับสนได้ ตัวอย่างเช่น ลองพิจารณา txid ของ output ก่อนหน้าใน outpoint ของธุรกรรมตัวอย่างของเรา</p>
<pre><code>eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da135698679268041c54a
</code></pre>
<p>ถ้าเราพยายามใช้ txid นั้นเพื่อดึงข้อมูลธุรกรรมจาก Bitcoin Core เราจะพบข้อผิดพลาด และจำเป็นต้องสลับลำดับไบต์ของมันก่อน</p>
<pre><code>$ bitcoin-cli getrawtransaction \
  eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da135698679268041c54a
error code: -5
error message:
No such mempool or blockchain transaction.
Use gettransaction for wallet transactions.
$ echo eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da135698679268041c54a \
  | fold -w2 | tac | tr -d "\n"
4ac541802679866935a19d4f40728bb89204d0cac90d85f3a51a19278fe33aeb
$ bitcoin-cli getrawtransaction \
  4ac541802679866935a19d4f40728bb89204d0cac90d85f3a51a19278fe33aeb
02000000000101c25ae90c9f3d40cc1fc509ecfd54b06e35450702…
</code></pre>
<p>พฤติกรรมแปลก ๆ นี้น่าจะเป็นผลที่เกิดขึ้นโดยไม่ได้ตั้งใจจากการตัดสินใจออกแบบในซอฟต์แวร์บิตคอยน์ยุคแรก ๆ ในทางปฏิบัติ นั่นหมายความว่านักพัฒนาซอฟต์แวร์บิตคอยน์จำเป็นต้องจำไว้ว่าต้องสลับลำดับไบต์ในตัวระบุธุรกรรมและบล็อกก่อนที่จะแสดงให้ผู้ใช้เห็น</p>
<p>ในหนังสือเล่มนี้ เราใช้คำว่า ลำดับไบต์ภายใน (internal byte order) สำหรับข้อมูลที่ปรากฏอยู่ภายในธุรกรรมและบล็อก และใช้คำว่า ลำดับไบต์สำหรับแสดงผล (display byte order) สำหรับรูปแบบที่แสดงต่อผู้ใช้ อีกชุดของคำที่มักใช้กันคือ ลำดับไบต์แบบ little-endian สำหรับรูปแบบภายใน และ ลำดับไบต์แบบ big-endian สำหรับรูปแบบที่แสดงผล</p>
<blockquote>
<p>อันนี้หลามเสริมให้ มันคือการแบ่งทีละสองตำแหน่งและนับว่านั่นเป็นหนึ่ง เช่น abcdef ก็จะเป็น ab คือ 1 cd คือ 2 ef คือ 3 พอแปลงเป็น display byte order ก็ทำการสลับเป็น 3,2,1 หรือ efcdab</p>
</blockquote>
<h2>Input Script</h2>
<p>ฟิลด์ input script เป็นส่วนที่หลงเหลือมาจากรูปแบบธุรกรรมแบบดั้งเดิม (legacy transaction format) ตัวอย่างธุรกรรมของเราเป็น input ที่ใช้จ่าย output แบบ native segwit ซึ่งไม่จำเป็นต้องมีข้อมูลใน input script ดังนั้นค่านำหน้าความยาว (length prefix) ของ input script จึงถูกตั้งค่าเป็นศูนย์ (0x00)</p>
<p>สำหรับตัวอย่างของ input script ที่มีค่านำหน้าความยาวและใช้จ่าย output แบบดั้งเดิม เราจะใช้ตัวอย่างจากธุรกรรมหนึ่งในบล็อกล่าสุดในขณะที่เขียนอยู่นี้</p>
<pre><code>6b483045022100a6cc4e8cd0847951a71fad3bc9b14f24d44ba59d19094e0a8c
fa2580bb664b020220366060ea8203d766722ed0a02d1599b99d3c95b97dab8e
41d3e4d3fe33a5706201210369e03e2c91f0badec46c9c903d9e9edae67c167b
9ef9b550356ee791c9a40896
</code></pre>
<p>ค่านำหน้าความยาว (length prefix) เป็นจำนวนเต็มแบบ compactSize unsigned integer ที่ระบุความยาวของฟิลด์ input script ที่ถูกซีเรียลไลซ์ไว้ ในกรณีนี้เป็นไบต์เดียว (0x6b) ซึ่งระบุว่า input script มีความยาว 107 ไบต์</p>
<h2>Sequence(ลำดับ)</h2>
<p>ไบต์สี่ตัวสุดท้ายของ input คือหมายเลขลำดับ (sequence number) ซึ่งการใช้งานและความหมายของฟิลด์นี้ได้มีการเปลี่ยนแปลงไปตามกาลเวลา</p>
<h3>การแทนที่ธุรกรรมโดยอิงตามลำดับ (Original sequence-based transaction replacement)</h3>
<p>เดิมทีฟิลด์ sequence ถูกออกแบบมาเพื่อให้สามารถสร้างหลายเวอร์ชันของธุรกรรมเดียวกันได้ โดยที่เวอร์ชันหลังสามารถแทนที่เวอร์ชันก่อนหน้าในฐานะตัวเลือกสำหรับการยืนยัน หมายเลขลำดับทำหน้าที่ติดตามเวอร์ชันของธุรกรรม</p>
<p>ตัวอย่างเช่น ลองจินตนาการว่าอลิซและบ็อบต้องการเดิมพันผลเกมไพ่ พวกเขาเริ่มจากการลงนามธุรกรรมที่แต่ละคนฝากเงินไว้ในเอาต์พุตซึ่งต้องการลายเซ็นจากทั้งคู่เพื่อใช้จ่าย ซึ่งเรียกว่า สคริปต์หลายลายเซ็น (multisignature script หรือ multisig) ธุรกรรมนี้เรียกว่า setup transaction จากนั้นพวกเขาสร้างธุรกรรมที่ใช้จ่ายเอาต์พุตนั้นดังนี้</p>
<ul>
<li>เวอร์ชันแรกของธุรกรรม โดยมีค่า <code>nSequence</code> เท่ากับ 0 (0x00000000) เป็นการคืนเงินให้อลิซและบ็อบตามจำนวนที่แต่ละคนฝากไว้ในตอนแรก ธุรกรรมนี้เรียกว่า <em>refund transaction</em> ซึ่งทั้งคู่ยังไม่เผยแพร่ในตอนนี้ จะใช้ก็ต่อเมื่อเกิดปัญหาเท่านั้น  </li>
<li>อลิซชนะรอบแรกของเกมไพ่ ธุรกรรมเวอร์ชันที่สองมีค่า <em>sequence</em> เป็น 1 และปรับจำนวนเงินที่อลิซได้รับให้มากขึ้น ในขณะที่ส่วนของบ็อบลดลง ทั้งคู่ลงนามในธุรกรรมที่อัปเดตแล้วนี้อีกครั้ง แต่ก็ยังไม่เผยแพร่ เว้นแต่จะมีเหตุจำเป็น  </li>
<li>บ็อบชนะรอบที่สอง ลำดับจึงถูกเพิ่มเป็น 2 ส่วนแบ่งของอลิซลดลงและของบ็อบเพิ่มขึ้น ทั้งคู่ลงนามอีกครั้งแต่ยังไม่เผยแพร่</li>
</ul>
<p>หลังจากเล่นอีกหลายรอบ โดยที่ค่า sequence ถูกเพิ่มขึ้นในแต่ละรอบ เงินถูกปรับสมดุลใหม่ และธุรกรรมถูกลงนามแต่ยังไม่เผยแพร่ พวกเขาตัดสินใจจะสิ้นสุดเกม ด้วยการสร้างธุรกรรมสุดท้ายที่สะท้อนยอดเงินสุดท้ายของทั้งคู่ จากนั้นตั้งค่า sequence เป็นค่าสูงสุด (0xffffffff) เพื่อเป็นการ “สิ้นสุด” ธุรกรรมนี้ พวกเขาจึงเผยแพร่เวอร์ชันนี้ออกไป ธุรกรรมถูกส่งต่อไปทั่วเครือข่าย และในที่สุดก็ได้รับการยืนยันโดยนักขุด</p>
<p>เราสามารถเห็นกฎการแทนที่ของ sequence ทำงานอย่างไรได้ หากพิจารณาสถานการณ์ทางเลือกดังต่อไปนี้</p>
<ul>
<li><p>ลองจินตนาการว่าอลิซเผยแพร่ธุรกรรมสุดท้ายที่มีค่า sequence เท่ากับ 0xffffffff จากนั้นบ็อบเผยแพร่ธุรกรรมเวอร์ชันก่อนหน้าที่เขาได้รับส่วนแบ่งมากกว่า เนื่องจากเวอร์ชันของบ็อบมีหมายเลขลำดับต่ำกว่า โหนดเต็ม (full nodes) ที่ใช้โค้ดบิตคอยน์เวอร์ชันดั้งเดิมจะไม่ส่งต่อธุรกรรมนั้นไปยังนักขุด และนักขุดที่ใช้โค้ดเวอร์ชันเดิมก็จะไม่ขุดมันเช่นกัน</p>
</li>
<li><p>ในอีกสถานการณ์หนึ่ง สมมติว่าบ็อบเผยแพร่ธุรกรรมเวอร์ชันก่อนหน้าเพียงไม่กี่วินาทีก่อนที่อลิซจะเผยแพร่เวอร์ชันสุดท้าย โหนดต่าง ๆ จะส่งต่อเวอร์ชันของบ็อบและนักขุดจะพยายามขุดมัน แต่เมื่อเวอร์ชันของอลิซที่มีหมายเลขลำดับสูงกว่ามาถึง โหนดก็จะส่งต่อเวอร์ชันของอลิซด้วย และนักขุดที่ใช้โค้ดบิตคอยน์เวอร์ชันดั้งเดิมจะพยายามขุดเวอร์ชันของอลิซแทนเวอร์ชันของบ็อบ เว้นแต่ว่าบ็อบจะโชคดีและมีการค้นพบบล็อกก่อนที่เวอร์ชันของอลิซจะมาถึง มิฉะนั้นธุรกรรมเวอร์ชันของอลิซจะเป็นเวอร์ชันที่ได้รับการยืนยันในที่สุด</p>
</li>
</ul>
<p>โปรโตคอลประเภทนี้คือสิ่งที่เราเรียกว่า payment channel ในปัจจุบัน ผู้สร้างบิตคอยน์ได้กล่าวถึงในอีเมลที่มีการอ้างถึงเขา เรียกธุรกรรมประเภทนี้ว่า high-frequency transactions และได้อธิบายคุณสมบัติบางอย่างที่เพิ่มเข้าไปในโปรโตคอลเพื่อรองรับการใช้งานเหล่านี้ เราจะเรียนรู้เกี่ยวกับคุณสมบัติอื่น ๆ เหล่านี้ในภายหลัง และยังจะได้เห็นด้วยว่าเวอร์ชันสมัยใหม่ของ payment channel ถูกนำมาใช้ในบิตคอยน์อย่างแพร่หลายมากขึ้นในปัจจุบัน</p>
<p>มีปัญหาบางประการกับ payment channel ที่อิงตาม sequence เพียงอย่างเดียว ปัญหาแรกคือกฎสำหรับการแทนที่ธุรกรรมที่มี sequence ต่ำด้วยธุรกรรมที่มี sequence สูงเป็นเพียงนโยบายของซอฟต์แวร์เท่านั้น ไม่มีแรงจูงใจโดยตรงให้นักขุดชอบเวอร์ชันใดเวอร์ชันหนึ่งมากกว่าเวอร์ชันอื่น ปัญหาที่สองคือคนแรกที่ส่งธุรกรรมอาจโชคดีให้ธุรกรรมนั้นได้รับการยืนยัน แม้ว่าจะไม่ใช่ธุรกรรมที่มี sequence สูงสุดก็ตาม โปรโตคอลด้านความปลอดภัยที่ล้มเหลวบ้างเพียงไม่กี่เปอร์เซ็นต์เพราะโชคไม่ดีจึงไม่ใช่โปรโตคอลที่มีประสิทธิภาพนัก</p>
<p>ปัญหาที่สามคือสามารถแทนที่เวอร์ชันหนึ่งของธุรกรรมด้วยเวอร์ชันที่ต่างออกไปได้โดยไม่จำกัดจำนวนครั้ง แต่ละครั้งที่แทนที่จะใช้แบนด์วิดท์ของโหนดเต็มที่ทำหน้าที่ส่งต่อบนเครือข่ายทั้งหมด ยกตัวอย่างเช่น ณ เวลาที่เขียนนี้ มี full node ที่ทำหน้าที่ส่งต่อประมาณ 50,000 โหนด; ผู้โจมตีที่สร้างธุรกรรมแทนที่ 1,000 รายการต่อหนึ่งนาที โดยแต่ละรายการมีขนาด 200 ไบต์ จะใช้แบนด์วิดท์ส่วนตัวของเขาประมาณ 20 KB ต่อหนึ่งนาที แต่จะใช้แบนด์วิดท์เครือข่ายของ full node ประมาณ 10 GB ทุก ๆ นาที นอกจากค่าใช้จ่ายแบนด์วิดท์ส่วนตัว 20 KB/นาที และค่าธรรมเนียมเพียงเป็นครั้งคราวเมื่อต้องมีธุรกรรมที่ถูกยืนยัน ผู้โจมตีจะไม่ต้องจ่ายค่าใช้จ่ายใด ๆ สำหรับภาระอันมหาศาลที่พวกเขาก่อขึ้นกับผู้ดำเนิน full node เลย</p>
<p>เพื่อกำจัดความเสี่ยงจากการโจมตีนี้ รูปแบบการแทนที่ธุรกรรมที่อิงตาม sequence แบบเดิมถูกปิดใช้งานในเวอร์ชันแรก ๆ ของซอฟต์แวร์บิตคอยน์ ในช่วงหลายปี  full node ของบิตคอยน์จะไม่อนุญาตให้ธุรกรรมที่ยังไม่ได้ยืนยันซึ่งมีอินพุตหนึ่ง (ตามที่ระบุโดย outpoint) ถูกแทนที่ด้วยธุรกรรมอื่นที่มีอินพุตเดียวกัน อย่างไรก็ตาม สถานการณ์นั้นไม่ได้ดำเนินต่อไปตลอดเวลา</p>
<h3>การสัญญาณเพื่อแทนที่ธุรกรรมแบบ Opt-in</h3>
<p>หลังจากรูปแบบการแทนที่ธุรกรรมที่อิงตาม sequence แบบเดิมถูกปิดใช้งานเนื่องจากมีความเสี่ยงที่จะถูกละเมิด ได้มีการเสนอวิธีแก้ไข: การโปรแกรม Bitcoin Core และซอฟต์แวร์โหนดเต็มที่ส่งต่อธุรกรรมอื่น ๆ ให้อนุญาตให้ธุรกรรมที่จ่ายค่าธรรมเนียมสูงแทนที่ธุรกรรมที่ขัดแย้งและจ่ายค่าธรรมเนียมต่ำกว่า เรียกวิธีนี้ว่า replace by fee (RBF)</p>
<p>ผู้ใช้และธุรกิจบางรายคัดค้านการเพิ่มการสนับสนุนการแทนที่ธุรกรรมกลับเข้าไปใน Bitcoin Core ดังนั้นจึงได้ข้อยุติด้วยการใช้ฟิลด์ sequence อีกครั้งเพื่อสนับสนุนการแทนที่</p>
<p>ตามที่ระบุใน BIP125 ธุรกรรมที่ยังไม่ได้ยืนยันซึ่งมีอินพุตใด ๆ ที่ตั้งค่า sequence ต่ำกว่า 0xfffffffe (เช่น อย่างน้อย 2 ต่ำกว่าค่าสูงสุด) จะส่งสัญญาณไปยังเครือข่ายว่าผู้ลงนามต้องการให้ธุรกรรมนี้สามารถถูกแทนที่ด้วยธุรกรรมที่จ่ายค่าธรรมเนียมสูงกว่าได้ Bitcoin Core อนุญาตให้ธุรกรรมที่ยังไม่ได้ยืนยันเหล่านี้ถูกแทนที่ได้ และยังคงไม่อนุญาตให้ธุรกรรมอื่น ๆ ถูกแทนที่ ทำให้ผู้ใช้และธุรกิจที่คัดค้านการแทนที่สามารถเพิกเฉยต่อธุรกรรมที่ยังไม่ได้ยืนยันซึ่งมีสัญญาณ BIP125 จนกว่าจะได้รับการยืนยัน</p>
<p>นโยบายการแทนที่ธุรกรรมสมัยใหม่มีมากกว่าการพิจารณาค่าธรรมเนียมและสัญญาณ sequence ซึ่งเราจะเห็นรายละเอียดเพิ่มเติมในหัวข้อ rbf</p>
<h3>Sequence ในฐานะกลไกกำหนดเวลาล็อกแบบสัมพัทธ์ (relative timelock) ที่ถูกบังคับโดยฉันทามติ</h3>
<p>ในหัวข้อ Version เราได้เรียนรู้ว่า soft fork BIP68 ได้เพิ่มข้อจำกัดใหม่ให้กับธุรกรรมที่มีหมายเลขเวอร์ชัน 2 ขึ้นไป ซึ่งข้อจำกัดนั้นถูกใช้กับฟิลด์ sequence</p>
<p>อินพุตของธุรกรรมที่มีค่า sequence น้อยกว่า 2³¹ จะถูกตีความว่ามีการตั้ง relative timelock และธุรกรรมดังกล่าวจะสามารถถูกบรรจุเข้าไปในบล็อกเชนได้ก็ต่อเมื่อเอาต์พุตก่อนหน้า (ที่ถูกอ้างอิงโดย outpoint) ผ่านระยะเวลาเท่ากับค่าของ relative timelock มาแล้ว ตัวอย่างเช่น ธุรกรรมที่มีอินพุตหนึ่งตัวตั้ง relative timelock ไว้ 30 บล็อก จะสามารถถูกยืนยันในบล็อกที่มีอย่างน้อย 29 บล็อกคั่นอยู่ระหว่างบล็อกนั้นกับบล็อกที่มีเอาต์พุตซึ่งกำลังถูกใช้จ่ายอยู่บนบล็อกเชนเดียวกัน เนื่องจาก sequence เป็นฟิลด์ที่ผูกกับแต่ละอินพุต ธุรกรรมหนึ่งรายการอาจมีอินพุตหลายตัวที่มีการตั้ง timelock และอินพุตทั้งหมดต้องผ่านช่วงเวลาตามที่กำหนดแล้วจึงทำให้ธุรกรรมถือว่าถูกต้อง มี disable flag ที่อนุญาตให้ธุรกรรมสามารถรวมอินพุตแบบมี relative timelock (sequence &lt; 2³¹) และอินพุตที่ไม่มี relative timelock (sequence ≥ 2³¹) ไว้ในธุรกรรมเดียวกันได้</p>
<p>ค่า sequence สามารถกำหนดเป็นหน่วยบล็อกหรือหน่วยวินาทีได้ โดยมี type-flag ใช้แยกความแตกต่างระหว่างค่าที่นับเป็นบล็อกกับค่าที่นับเป็นวินาที type-flag จะถูกตั้งค่าไว้ที่บิตลำดับที่ 23 (กล่าวคือค่า 1&lt;&lt;22) หาก type-flag ถูกตั้งค่า ค่า sequence จะถูกตีความเป็นจำนวนเท่าของ 512 วินาที แต่ถ้า type-flag ไม่ได้ถูกตั้งค่า ค่า sequence จะถูกตีความเป็นจำนวนบล็อก เมื่อทำการตีความ sequence เป็น relative timelock จะพิจารณาเฉพาะ 16 บิตที่มีค่าน้อยที่สุดเท่านั้น เมื่อทำการประเมินค่าสถานะของ flags แล้ว (บิต 32 และบิต 23) ค่า sequence จะถูก “mask” ด้วย mask ขนาด 16 บิต (เช่น sequence &amp; 0x0000FFFF) ค่าหนึ่งเท่าของ 512 วินาทีมีค่าประมาณเท่ากับเวลาเฉลี่ยระหว่างบล็อก ดังนั้นค่า relative timelock สูงสุดจาก 16 บิต (2¹⁶) ทั้งในหน่วยบล็อกและหน่วยวินาที จะมีค่าเกินหนึ่งปีเล็กน้อย</p>
<p>คำจำกัดความของ sequence encoding ตาม BIP68 (ที่มา: BIP68) แสดงผังไบนารีของค่า sequence ตามที่กำหนดใน BIP68<br> <img src="https://image.nostr.build/a19cad6116cdee116a4b577c21c4b4d5861df50e7874d1da00ca9286e25970cf.jpg" alt="image"></p>
<h2>Outputs</h2>
<p>ฟิลด์ outputs ของธุรกรรมประกอบด้วยฟิลด์หลายตัวที่เกี่ยวข้องกับเอาต์พุตแต่ละรายการ เช่นเดียวกับที่เราทำกับฟิลด์ inputs เราจะเริ่มจากการดูไบต์เฉพาะของฟิลด์ outputs จากตัวอย่างธุรกรรมที่ Alice จ่ายให้ Bob ซึ่งถูกแสดงในรูปแบบแผนที่ของไบต์เหล่านั้นในตัวอย่างตอนต้นของบทนี้<br> <img src="https://image.nostr.build/d9e1d6dbe12c88189f42ee36cc478a37039a81fb4cfa13e3efad7e97eb40a5e0.jpg" alt="image"></p>
<h3><strong>Output count (จำนวน Outputs)</strong></h3>
<p>เช่นเดียวกับจุดเริ่มต้นของส่วน inputs ของธุรกรรม ฟิลด์ outputs จะเริ่มต้นด้วยตัวนับที่ระบุจำนวนของ outputs ในธุรกรรมนี้ ซึ่งเป็น compactSize integer และต้องมีค่ามากกว่าศูนย์ โดยธุรกรรมตัวอย่างมีสอง outputs</p>
<h3><strong>Amount(จำนวนเงิน)</strong></h3>
<p>ฟิลด์แรกของ output หนึ่งรายการคือจำนวนเงินของมัน ซึ่งใน Bitcoin Core เรียกว่า “value” เป็น signed integer ขนาด 8 ไบต์ที่ระบุจำนวน satoshis ที่ต้องการโอน (satoshi คือหน่วยที่เล็กที่สุดของ bitcoin ที่สามารถแสดงได้ในธุรกรรมบนบล็อกเชน หนึ่ง bitcoin มี 100 ล้าน satoshis) และในกฎฉันทามติของ Bitcoin อนุญาตให้ output มีค่าตั้งแต่ศูนย์จนถึงสูงสุด 21 ล้าน bitcoins (2.1 quadrillion satoshis)</p>
<h4>Uneconomical outputs and disallowed dust (เอาต์พุตที่ไม่คุ้มค่าเชิงเศรษฐกิจและฝุ่น (dust) ที่ถูกห้าม)</h4>
<p>แม้ว่าจะไม่มีมูลค่า แต่เอาต์พุตที่มีค่าเป็นศูนย์สามารถถูกใช้จ่ายได้ภายใต้กฎเดียวกับเอาต์พุตอื่น ๆ อย่างไรก็ตาม การใช้จ่ายเอาต์พุต (นำมันไปใช้เป็นอินพุตในธุรกรรม) ทำให้ขนาดของธุรกรรมเพิ่มขึ้น ซึ่งทำให้ค่าธรรมเนียมที่ต้องจ่ายเพิ่มขึ้นด้วย หากมูลค่าของเอาต์พุตมีค่าน้อยกว่าค่าธรรมเนียมที่ต้องจ่ายเพิ่ม การใช้จ่ายเอาต์พุตนั้นก็ไม่มีความคุ้มค่าทางเศรษฐกิจ เอาต์พุตเช่นนี้เรียกว่า uneconomical outputs</p>
<p>เอาต์พุตที่มีค่าเป็นศูนย์เป็น uneconomical output เสมอ เพราะมันจะไม่เพิ่มมูลค่าใด ๆ ให้กับธุรกรรมที่ใช้มัน แม้ว่าอัตราค่าธรรมเนียมจะเป็นศูนย์ก็ตาม แต่อย่างไรก็ตาม เอาต์พุตอื่น ๆ ที่มีมูลค่าต่ำก็อาจเป็น uneconomical เช่นกัน แม้จะไม่ได้ตั้งใจ ตัวอย่างเช่น ที่อัตราค่าธรรมเนียมปกติบนเครือข่ายในวันนี้ เอาต์พุตหนึ่งอาจเพิ่มมูลค่ามากกว่าค่าใช้จ่ายในการนำไปใช้ แต่วันพรุ่งนี้อัตราค่าธรรมเนียมอาจสูงขึ้นและทำให้เอาต์พุตนั้นกลายเป็น uneconomical</p>
<p>ความจำเป็นที่ full node ต้องติดตาม UTXO ทั้งหมด ตามที่อธิบายไว้ในหัวข้อ Outpoint หมายความว่า UTXO ทุกตัวทำให้การรัน full node ยากขึ้นเล็กน้อย สำหรับ UTXO ที่มีมูลค่ามาก ผู้ใช้มีแรงจูงใจที่จะใช้จ่ายมันในที่สุด ดังนั้นมันไม่ก่อปัญหา แต่สำหรับผู้ที่ถือ UTXO ที่ไม่คุ้มค่าทางเศรษฐกิจ ไม่มีแรงจูงใจที่จะใช้จ่ายมันเลย ซึ่งอาจทำให้มันกลายเป็นภาระถาวรสำหรับผู้ดูแล full node และเนื่องจากการกระจายศูนย์ของ Bitcoin ขึ้นอยู่กับจำนวนผู้ที่ยินดีรัน full node ซอฟต์แวร์ full node หลาย ๆ ตัว เช่น Bitcoin Core จึงใช้ข้อกำหนดที่ส่งผลต่อการส่งต่อธุรกรรมและการขุดธุรกรรมที่ยังไม่ได้คอนเฟิร์ม เพื่อป้องกันการสร้างเอาต์พุตที่ไม่คุ้มค่าทางเศรษฐกิจ</p>
<p>ข้อกำหนดที่ห้ามการส่งต่อหรือการขุดธุรกรรมที่สร้างเอาต์พุตที่ไม่คุ้มค่าเรียกว่า dust policies ตั้งตามการเปรียบเทียบเชิงสัญลักษณ์ระหว่างเอาต์พุตที่มีมูลค่าน้อยมากกับอนุภาคที่มีขนาดเล็กมาก (เล็กจนเป็นฝุ่น) dust policy ของ Bitcoin Core นั้นซับซ้อนและมีตัวเลขกำหนดหลายค่า ดังนั้นโปรแกรมจำนวนมากมักถือเอาว่าเอาต์พุตที่มีค่าน้อยกว่า 546 satoshis คือ dust และจะไม่ถูกส่งต่อหรือขุดตามค่าตั้งต้น แต่ก็มีบ้างเป็นครั้งคราวที่มีข้อเสนอให้ลดขีดจำกัดของ dust และก็มีข้อเสนอคัดค้านให้เพิ่มขีดจำกัดเช่นกัน ดังนั้นเราขอแนะนำให้นักพัฒนาที่ใช้ presigned transactions หรือโปรโตคอลแบบหลายฝ่าย ตรวจสอบว่าข้อกำหนดนี้มีการเปลี่ยนแปลงตั้งแต่วันที่หนังสือเล่มนี้เผยแพร่หรือไม่</p>
<blockquote>
<p>TIP: ตั้งแต่การกำเนิดของ Bitcoin full node ทุกตัวจำเป็นต้องเก็บสำเนาของ UTXO ทุกตัว แต่สิ่งนี้อาจไม่จำเป็นต้องเป็นเช่นนั้นตลอดไป นักพัฒนาหลายคนกำลังทำงานกับ Utreexo ซึ่งเป็นโปรเจกต์ที่ทำให้โหนดเต็มสามารถเก็บข้อมูลแบบ commitment ต่อชุดของ UTXO แทนการเก็บข้อมูลจริง commitment ที่เล็กที่สุดอาจมีขนาดเพียงหนึ่งหรือสองกิโลไบต์—เทียบกับข้อมูลมากกว่า 5 กิกะไบต์ที่ Bitcoin Core เก็บ ณ เวลาที่เขียนหนังสือนี้ (และตอนที่ผมแปลอยู่ที่ประมาณ 11 GB) </p>
</blockquote>
<blockquote>
<p>อย่างไรก็ตาม Utreexo จะยังคงต้องให้บางโหนดเก็บข้อมูล UTXO ทั้งหมด โดยเฉพาะโหนดที่ให้บริการนักขุดหรือการดำเนินงานอื่น ๆ ที่ต้องตรวจสอบบล็อกใหม่อย่างรวดเร็ว นั่นหมายความว่า uneconomical outputs ก็ยังคงเป็นปัญหาสำหรับ full node แม้ในอนาคตที่เป็นไปได้ซึ่งโหนดส่วนใหญ่ใช้ Utreexo ก็ตาม</p>
</blockquote>
<p>กฎนโยบายของ Bitcoin Core เกี่ยวกับ dust มีข้อยกเว้นหนึ่งข้อ: output script ที่เริ่มต้นด้วย OP_RETURN ซึ่งเรียกว่า data carrier outputs สามารถมีมูลค่าเป็นศูนย์ได้ OP_RETURN opcode ทำให้สคริปต์ล้มเหลวทันทีไม่ว่าจะมีอะไรตามมาหลังจากนั้น ดังนั้นเอาต์พุตเหล่านี้ไม่สามารถถูกใช้จ่ายได้เลย นั่นหมายความว่า full node ไม่จำเป็นต้องติดตามเอาต์พุตเหล่านี้ ซึ่งเป็นคุณสมบัติที่ Bitcoin Core ใช้เพื่อให้ผู้ใช้สามารถจัดเก็บข้อมูลเล็กน้อยตามต้องการลงในบล็อกเชนได้โดยไม่ทำให้ฐานข้อมูล UTXO มีขนาดใหญ่ขึ้น เนื่องจากเอาต์พุตเหล่านี้ไม่สามารถใช้จ่ายได้ จึงไม่ถือว่าเป็น uneconomical แต่ว่า satoshis ใด ๆ ก็ตามที่กำหนดให้กับมันจะกลายเป็นใช้ไม่ได้อย่างถาวร ดังนั้นการอนุญาตให้จำนวนเงินเป็นศูนย์จึงช่วยให้มั่นใจว่า satoshis จะไม่ถูกทำลาย</p>
<h3><strong>Output Scripts</strong></h3>
<p>หลังจากจำนวนเงินของเอาต์พุต จะมี compactSize integer ที่บอกความยาวของ output script ซึ่งเป็นสคริปต์ที่มีเงื่อนไขที่ต้องปฏิบัติตามเพื่อใช้จ่ายบิตคอยน์ ตามกฎฉันทามติของ Bitcoin ขนาดขั้นต่ำของ output script คือศูนย์</p>
<p>ขนาดสูงสุดตามฉันทามติที่อนุญาตของ output script จะแตกต่างกันไปขึ้นอยู่กับช่วงเวลาที่มีการตรวจสอบ ไม่มีขีดจำกัดที่ระบุไว้อย่างชัดเจนสำหรับขนาดของ output script ในเอาต์พุตของธุรกรรม แต่ธุรกรรมถัดไปสามารถใช้จ่ายเอาต์พุตก่อนหน้าได้เฉพาะเมื่อสคริปต์มีขนาด 10,000 ไบต์หรือน้อยกว่าเท่านั้น โดยนัยคือสคริปต์ของเอาต์พุตสามารถมีขนาดใหญ่เกือบเท่ากับตัวธุรกรรมที่บรรจุมันไว้ และธุรกรรมก็สามารถมีขนาดใหญ่เกือบเท่ากับบล็อกที่บรรจุธุรกรรมนั้นไว้</p>
<blockquote>
<p>TIP: output script ที่มีความยาวเป็นศูนย์สามารถถูกใช้จ่ายได้โดย input script ที่มี OP_TRUE อยู่ภายใน โดยใคร ๆ ก็สามารถสร้าง input script แบบนั้นได้ ซึ่งหมายความว่าใครก็สามารถใช้จ่าย output script ที่ว่างเปล่าได้ มีจำนวนสคริปต์แทบไม่จำกัดที่ใครก็สามารถใช้จ่ายได้ และนักพัฒนาโปรโตคอล Bitcoin เรียกสิ่งเหล่านี้ว่า anyone can spends การอัปเกรดภาษาสคริปต์ของ Bitcoin มักจะนำสคริปต์ที่เป็น anyone-can-spend มาเพิ่มเงื่อนไขใหม่เข้าไป ทำให้สามารถใช้จ่ายได้เฉพาะภายใต้เงื่อนไขใหม่เท่านั้น นักพัฒนาแอปพลิเคชันไม่ควรจำเป็นต้องใช้ anyone-can-spend script เลย แต่หากคุณจำเป็นต้องใช้ เราขอแนะนำอย่างยิ่งให้ประกาศแผนของคุณอย่างชัดเจนต่อผู้ใช้และนักพัฒนา Bitcoin เพื่อไม่ให้การอัปเกรดในอนาคตไปรบกวนระบบของคุณโดยไม่ตั้งใจ</p>
</blockquote>
<p>นโยบายของ Bitcoin Core สำหรับการรีเลย์และการขุดธุรกรรม จะจำกัด output script ให้เหลือเพียงไม่กี่รูปแบบ ซึ่งเรียกว่า standard transaction outputs การจำกัดนี้ถูกนำมาใช้ครั้งแรกหลังจากค้นพบบั๊กในยุคแรกของ Bitcoin ที่เกี่ยวข้องกับภาษา Script และยังถูกคงไว้ใน Bitcoin Core ยุคปัจจุบันเพื่อรองรับการอัปเกรดแบบ anyone-can-spend และเพื่อส่งเสริมแนวทางที่ดีที่สุดในการวางเงื่อนไขสคริปต์ไว้ใน P2SH redeem scripts, segwit v0 witness scripts และ segwit v1 (taproot) leaf scripts เราจะดูแต่ละรูปแบบของ standard transaction templates ในปัจจุบัน และเรียนรู้วิธีการ parse สคริปต์ในบทถัดไป</p>
<h3>Witness Structure</h3>
<p>ในศาล “พยาน” คือบุคคลที่ให้การว่าตนเห็นเหตุการณ์สำคัญบางอย่างเกิดขึ้น พยานมนุษย์ไม่ใช่สิ่งที่เชื่อถือได้เสมอไป ดังนั้นศาลจึงมีขั้นตอนต่าง ๆ สำหรับการสอบสวนพยานเพื่อ (อย่างน้อยก็ในอุดมคติ) รับหลักฐานเฉพาะจากผู้ที่เชื่อถือได้เท่านั้น </p>
<p>ลองจินตนาการว่าถ้ามี “พยาน” สำหรับโจทย์คณิตศาสตร์จะมีหน้าตาอย่างไร ตัวอย่างเช่น หากปัญหาสำคัญคือ x + 2 == 4 และมีใครสักคนอ้างว่าตนเป็นพยานที่เห็นวิธีแก้ เราจะถามอะไรพวกเขา? เราต้องการ “หลักฐานทางคณิตศาสตร์” ที่แสดงค่าหนึ่งที่สามารถนำมาบวกกับ 2 แล้วได้ 4 เราอาจตัดความจำเป็นของการมีบุคคลออกไปเลย และใช้ “ค่าที่เสนอให้เป็น x” นั้นเป็นพยานแทนก็ได้ หากเราถูกบอกว่าพยานคือ 2 เราก็สามารถแทนค่าในสมการ ตรวจสอบว่าถูกต้อง และสรุปว่าปัญหาสำคัญนั้นได้รับการแก้ไขแล้ว </p>
<p>เมื่อมีการใช้จ่ายบิตคอยน์ ปัญหาสำคัญที่เราต้องการแก้คือ “การยืนยันว่าการใช้จ่ายนั้นได้รับอนุญาตจากบุคคลหรือกลุ่มบุคคลที่ควบคุมบิตคอยน์เหล่านั้นจริงหรือไม่” โหนดเต็มนับพันที่บังคับใช้กฎฉันทามติของบิตคอยน์ไม่สามารถสอบสวนพยานมนุษย์ได้ แต่พวกมันสามารถรับ “พยาน” ที่ประกอบด้วยข้อมูลล้วน ๆ สำหรับแก้ปัญหาทางคณิตศาสตร์ได้ ตัวอย่างเช่น พยานที่เป็นค่า 2 จะทำให้สามารถใช้จ่ายบิตคอยน์ที่ถูกป้องกันด้วยสคริปต์ต่อไปนี้ได้:</p>
<pre><code>2 OP_ADD 4 OP_EQUAL
</code></pre>
<p>แน่นอนว่า การอนุญาตให้บิตคอยน์ของคุณถูกใช้จ่ายโดยใครก็ตามที่สามารถแก้สมการง่าย ๆ ได้ย่อมไม่ปลอดภัย อย่างที่เราจะเห็นในบทที่ 8 กลไกการลงนามดิจิทัลที่ปลอมแปลงไม่ได้ (unforgeable digital signature scheme) ใช้สมการที่สามารถถูกแก้ได้โดยเฉพาะผู้ที่ครอบครองข้อมูลบางอย่างซึ่งพวกเขาสามารถเก็บไว้เป็นความลับได้ พวกเขาสามารถอ้างอิงข้อมูลลับนั้นโดยใช้ตัวระบุสาธารณะ ซึ่งตัวระบุดังกล่าวเรียกว่า public key และคำตอบของสมการนั้นเรียกว่า signature</p>
<p>สคริปต์ต่อไปนี้มี public key และ opcode ที่ต้องการ signature ที่สอดคล้องกันเพื่อ commit กับข้อมูลในธุรกรรมที่กำลังใช้จ่าย เช่นเดียวกับตัวเลข 2 ในตัวอย่างง่าย ๆ ของเรา signature คือพยานของเรา:</p>
<pre><code>&lt;public key&gt; OP_CHECKSIG
</code></pre>
<p>พยาน (witnesses) ซึ่งเป็นค่าที่ใช้ในการแก้ปัญหาทางคณิตศาสตร์ที่ปกป้องบิตคอยน์ จำเป็นต้องถูกใส่รวมอยู่ในธุรกรรมที่ใช้มัน เพื่อให้โหนดเต็มสามารถตรวจสอบได้ ในรูปแบบธุรกรรมแบบดั้งเดิม (legacy transaction format) ที่ใช้ในธุรกรรมบิตคอยน์ยุคแรก ๆ ทั้งหมดนั้น ลายเซ็นและข้อมูลอื่น ๆ ถูกวางไว้ในฟิลด์ input script อย่างไรก็ตาม เมื่อผู้พัฒนาเริ่มนำโปรโตคอลสัญญาต่าง ๆ มาใช้บนบิตคอยน์ เช่นที่เราเห็นใน Original sequence-based transaction replacement พวกเขาค้นพบปัญหาที่สำคัญหลายประการเกี่ยวกับการใส่พยานไว้ในฟิลด์ input script</p>
<h4>Circular Dependencies</h4>
<p>โปรโตคอลสัญญาหลายอย่างสำหรับบิตคอยน์เกี่ยวข้องกับชุดของธุรกรรมที่ถูกเซ็นนอกลำดับ ตัวอย่างเช่น Alice และ Bob ต้องการฝากเงินเข้าไปในสคริปต์ที่สามารถใช้จ่ายได้ด้วยลายเซ็นของทั้งคู่ แต่พวกเขาก็ต้องการให้สามารถได้เงินคืนได้หากอีกฝ่ายหนึ่งไม่ตอบสนอง วิธีแก้ปัญหาอย่างง่ายคือการเซ็นธุรกรรมนอกลำดับ:</p>
<ul>
<li>Tx0 จ่ายเงินจาก Alice และเงินจาก Bob ไปยังเอาต์พุตที่มีสคริปต์ที่ต้องการลายเซ็นจากทั้ง Alice และ Bob เพื่อที่จะใช้จ่ายได้  </li>
<li>Tx1 ใช้จ่ายเอาต์พุตก่อนหน้าไปยังสองเอาต์พุต—หนึ่งคืนเงินให้ Alice และอีกหนึ่งคืนเงินให้ Bob (หักจำนวนเล็กน้อยเป็นค่าธรรมเนียมธุรกรรม)  </li>
<li>หาก Alice และ Bob เซ็น Tx1 ก่อนที่พวกเขาจะเซ็น Tx0 พวกเขาทั้งคู่ก็จะมั่นใจได้ว่าจะรับเงินคืนได้ทุกเมื่อ โปรโตคอลนี้ไม่ต้องการให้ฝ่ายหนึ่งไว้ใจอีกฝ่ายหนึ่ง ทำให้มันเป็นโปรโตคอลแบบ trustless</li>
</ul>
<p>ปัญหาของโครงสร้างนี้ในรูปแบบธุรกรรมแบบดั้งเดิมคือทุกฟิลด์ รวมถึงฟิลด์ input script ที่มีลายเซ็น จะถูกใช้ในการสร้างตัวระบุของธุรกรรม (txid) ค่า txid ของ Tx0 เป็นส่วนหนึ่งของ outpoint ของอินพุตใน Tx1 นั่นหมายความว่าไม่มีทางที่ Alice และ Bob จะสร้าง Tx1 ได้จนกว่าจะทราบลายเซ็นทั้งสองของ Tx0 — แต่ถ้าพวกเขารู้ลายเซ็นของ Tx0 หนึ่งในนั้นสามารถออกอากาศธุรกรรมนั้นก่อนที่จะเซ็นธุรกรรมคืนเงิน ทำให้การรับประกันการคืนเงินถูกลบล้างไป นี่คือปัญหา circular dependency</p>
<h4>Third-Party Transaction Malleability (การเปลี่ยนแปลงธุรกรรมโดยบุคคลที่สาม)</h4>
<p>ลำดับธุรกรรมที่ซับซ้อนกว่าสามารถแก้ปัญหา circular dependency ได้ในบางครั้ง แต่โปรโตคอลจำนวนมากจะพบกับความกังวลใหม่: มักจะสามารถแก้สคริปต์เดียวกันได้หลายวิธี ตัวอย่างเช่น พิจารณาสคริปต์แบบง่ายของเราจากหัวข้อ Witness Structure:</p>
<pre><code>2 OP_ADD 4 OP_EQUAL
</code></pre>
<p>เราสามารถทำให้สคริปต์นี้ผ่านได้โดยการใส่ค่า 2 ลงใน input script แต่มีหลายวิธีที่จะวางค่านั้นลงบนสแตกในบิตคอยน์ ต่อไปนี้คือเพียงบางตัวอย่าง:</p>
<pre><code>OP_2
OP_PUSH1 0x02
OP_PUSH2 0x0002
OP_PUSH3 0x000002
...
OP_PUSHDATA1 0x0102
OP_PUSHDATA1 0x020002
...
OP_PUSHDATA2 0x000102
OP_PUSHDATA2 0x00020002
...
OP_PUSHDATA4 0x0000000102
OP_PUSHDATA4 0x000000020002
...
</code></pre>
<p>แต่ละรูปแบบการเข้ารหัสของตัวเลข 2 ใน input script จะสร้างธุรกรรมที่แตกต่างกันเล็กน้อย พร้อมกับ txid ที่แตกต่างกันอย่างสิ้นเชิง แต่ละเวอร์ชันของธุรกรรมจะใช้จ่ายอินพุต (outpoints) เดียวกันกับทุกเวอร์ชันอื่น ๆ ทำให้พวกมันขัดแย้งกันเอง ทั้งหมดนี้ทำให้มีเพียงหนึ่งเวอร์ชันจากชุดของธุรกรรมที่ขัดแย้งกันเท่านั้นที่สามารถอยู่ในบล็อกเชนที่ถูกต้องได้</p>
<p>ลองนึกภาพว่ามีครั้งหนึ่ง Alice สร้างเวอร์ชันของธุรกรรมที่มี OP_2 ใน input script และมี output ที่จ่ายให้ Bob จากนั้น Bob ก็ใช้จ่าย output นั้นต่อให้ Carol ทันที บุคคลใดก็ตามบนเครือข่ายสามารถแทนที่ OP_2 ด้วย OP_PUSH1 0x02 ทำให้เกิดธุรกรรมที่ขัดแย้งกับเวอร์ชันต้นฉบับของ Alice หากธุรกรรมที่ขัดแย้งนั้นถูกยืนยัน ก็จะไม่มีทางรวมเวอร์ชันต้นฉบับของ Alice เข้าไปในบล็อกเชนเดียวกันได้ ซึ่งหมายความว่าไม่มีทางที่ธุรกรรมของ Bob จะใช้จ่าย output ของมันได้ การจ่ายเงินของ Bob ให้ Carol จึงกลายเป็นโมฆะ ทั้งที่ Alice, Bob หรือ Carol ไม่ได้ทำอะไรผิดเลย คนที่ไม่ได้เกี่ยวข้องกับธุรกรรม (บุคคลที่สาม) สามารถเปลี่ยนแปลง (mutate) ธุรกรรมของ Alice ได้ ซึ่งเป็นปัญหาที่เรียกว่า unwanted third-party transaction malleability</p>
<blockquote>
<p>TIP: มีหลายกรณีที่ผู้คนต้องการให้ธุรกรรมของพวกเขาถูกดัดแปลงได้ (malleable) และบิตคอยน์ก็มีฟีเจอร์หลายอย่างรองรับสิ่งนี้ โดยเฉพาะ signature hashes (sighash) ที่เราจะได้เรียนรู้ใน [sighash_types] ตัวอย่างเช่น Alice สามารถใช้ sighash เพื่อให้ Bob ช่วยจ่ายค่าธรรมเนียมบางส่วนได้ ซึ่งทำให้ธุรกรรมของ Alice ถูกเปลี่ยนแปลง แต่เป็นการเปลี่ยนแปลงในแบบที่ Alice ต้องการ ด้วยเหตุนี้เราจะใส่คำว่า unwanted นำหน้าคำว่า transaction malleability ในบางครั้ง แม้ว่าเราหรือผู้เขียนเทคนิคบิตคอยน์คนอื่น ๆ จะใช้คำเวอร์ชันสั้น เราก็กำลังพูดถึงรูปแบบของ malleability ที่ไม่พึงประสงค์แทบทุกครั้ง</p>
</blockquote>
<h4>Second-Party Transaction Malleability(ผู้ร่วมธุรกรรมอีกฝ่าย)</h4>
<p>เมื่อรูปแบบธุรกรรมแบบดั้งเดิม (legacy transaction format) เป็นรูปแบบเดียวที่มีให้ใช้ นักพัฒนาก็ทำงานบนข้อเสนอเพื่อลดปัญหา third-party malleability เอาไว้อย่างเช่น BIP62 แต่อย่างไรก็ตาม แม้ว่าจะสามารถกำจัด third-party malleability ได้ทั้งหมด ผู้ใช้งานโปรโตคอลแบบสัญญา (contract protocols) ก็ยังพบปัญหาอีกแบบหนึ่ง คือถ้าต้องใช้ลายเซ็นของอีกฝ่ายหนึ่งที่อยู่ในโปรโตคอล ฝ่ายนั้นสามารถสร้างลายเซ็นทางเลือกขึ้นมาและเปลี่ยน txid ได้</p>
<p>ตัวอย่างเช่น Alice และ Bob ฝากเงินของพวกเขาเข้าไปในสคริปต์ที่ต้องการลายเซ็นของทั้งคู่เพื่อใช้จ่าย พวกเขายังสร้าง "ธุรกรรมคืนเงิน" (refund transaction) ที่จะให้ทั้งสองฝ่ายสามารถดึงเงินกลับได้ทุกเมื่อ และต่อมา Alice ต้องการใช้เงินบางส่วน เธอจึงร่วมมือกับ Bob สร้างลำดับธุรกรรมดังนี้:</p>
<ul>
<li>Tx0 รวมลายเซ็นจาก Alice และ Bob และใช้จ่ายบิตคอยน์ไปยังสอง output โดย output แรกจ่ายเงินบางส่วนให้ Alice และอีกอัน คืนเงินส่วนที่เหลือกลับเข้าไปยังสคริปต์เดิม ซึ่งยังคงต้องใช้ลายเซ็นของทั้ง Alice และ Bob แน่นอนว่าก่อนที่พวกเขาจะเซ็น Tx0 พวกเขาสร้างธุรกรรมคืนเงินชุดใหม่ Tx1  </li>
<li>Tx1 ใช้จ่าย output ที่สองของ Tx0 ไปยังสอง output ใหม่—หนึ่งให้ Alice ตามส่วนแบ่งของเธอ และอีกหนึ่งให้ Bob ตามส่วนแบ่งของเขา Alice และ Bob ต่างเซ็น Tx1 เสร็จก่อนที่จะเซ็น Tx0</li>
</ul>
<p>ตรงนี้ไม่มี circular dependency และถ้าเรามองข้าม third-party malleability ก็จะดูเหมือนเป็นโปรโตคอลที่ไม่ต้องเชื่อใจใคร (trustless) ได้ แต่ปัญหาคือ คุณสมบัติของลายเซ็นบิตคอยน์มีความสุ่มโดยธรรมชาติ —ผู้เซ็นต้องเลือกตัวเลขสุ่มขนาดใหญ่ทุกครั้งที่สร้างลายเซ็น หากเลือกเลขสุ่มต่างกัน ลายเซ็นที่ได้ก็จะต่างกัน แม้ข้อมูลที่ถูกเซ็นจะเหมือนเดิมทั้งหมดก็ตาม คล้ายกับการที่คุณเซ็นชื่อบนสัญญาเหมือนกันสองชุด ลายเซ็นจริง ๆ บนกระดาษทั้งสองแผ่นก็ไม่เหมือนกัน 100%</p>
<p>ความสามารถในการถูกดัดแปลงของลายเซ็นนี้ เป็นช่องให้ Bob สร้างธุรกรรมที่ขัดแย้งกับ Tx0 ได้ หาก Alice พยายามประกาศ Tx0 (ซึ่งมีลายเซ็นของ Bob อยู่) Bob สามารถสร้างลายเซ็นใหม่ที่แตกต่างออกมา ผลิต Tx0 เวอร์ชันใหม่ที่มี txid แตกต่างกันขึ้นมาได้ ถ้า Tx0 เวอร์ชันที่ Bob เปลี่ยนแปลงถูกยืนยันขึ้นมา Alice จะไม่สามารถใช้ Tx1 ที่ลงนามไว้ล่วงหน้าเพื่อรับเงินคืนของเธอได้ เพราะ Tx1 อ้างอิง txid เดิมของ Tx0 ซึ่งไม่ตรงกับเวอร์ชันที่ถูกยืนยัน พฤติกรรมแบบนี้เรียกว่า unwanted second-party transaction malleability คือการที่อีกฝ่ายในโปรโตคอลสามารถดัดแปลงธุรกรรมให้เปลี่ยน txid ได้โดยไม่ต้องร่วมมือกับคุณ</p>
<h4>Segregated Witness(การแยกพยานออกจากธุรกรรม)</h4>
<p>ตั้งแต่ช่วงต้นปี 2011 นักพัฒนาระบบโปรโตคอลของบิตคอยน์ก็ทราบวิธีแก้ปัญหา circular dependence, third-party malleability, และ second-party malleability แล้ว แนวคิดคือการหลีกเลี่ยงไม่ให้นำ input script มารวมอยู่ในการคำนวณที่ใช้สร้าง txid ของธุรกรรม จำได้ว่า ชื่อเชิงนามธรรมสำหรับข้อมูลที่อยู่ใน input script คือคำว่า witness แนวคิดในการแยกข้อมูลส่วนอื่น ๆ ของธุรกรรมออกจาก witness เพื่อใช้ในการสร้าง txid นี้ เรียกว่า segregated witness (segwit)</p>
<p>วิธีที่ตรงไปตรงมาที่สุดในการทำให้ segwit ใช้งานได้จริงนั้น ต้องมีการเปลี่ยนแปลงกฎ consensus ของบิตคอยน์ในลักษณะที่ ไม่สามารถเข้ากันได้กับ full node รุ่นเก่า หรือที่เรียกว่า hard fork Hard fork นั้นมาพร้อมกับความท้าทายจำนวนมาก ซึ่งเราจะอธิบายเพิ่มเติมในส่วน hardfork</p>
<p>แนวทางทางเลือกสำหรับ segwit ถูกอธิบายไว้ในช่วงปลายปี 2015 แนวทางนี้ใช้การเปลี่ยนแปลงกฎ consensus แบบ เข้ากันได้ย้อนหลัง (backward-compatible) ซึ่งเรียกว่า soft fork คำว่า “เข้ากันได้ย้อนหลัง” หมายความว่า full node ที่ใช้กฎใหม่จะต้อง ไม่ยอมรับบล็อกใด ๆ ที่ full node รุ่นเก่ามองว่าไม่ถูกต้อง ตราบเท่าที่พวกเขาปฏิบัติตามกฎนั้น full node รุ่นใหม่จึงสามารถ ปฏิเสธบล็อกที่ full node รุ่นเก่ายอมรับได้ ซึ่งทำให้พวกเขาสามารถบังคับใช้กฎ consensus ใหม่ได้ (แต่มีเงื่อนไขว่า full node รุ่นใหม่เหล่านั้นจะต้อง เป็นตัวแทนของฉันทามติทางเศรษฐกิจของผู้ใช้บิตคอยน์ด้วย—เราจะสำรวจรายละเอียดเกี่ยวกับการอัปเกรดกฎ consensus ของบิตคอยน์ในส่วนของ mining</p>
<p>การใช้ซอฟต์ฟอร์กแบบเซกวิทอาศัยแนวคิดเอาต์พุตสคริปต์แบบ “anyone-can-spend” เป็นพื้นฐาน สคริปต์ที่ขึ้นต้นด้วยตัวเลขตั้งแต่ 0 ถึง 16 และตามด้วยข้อมูลขนาด 2 ถึง 40 ไบต์ ถูกกำหนดให้เป็นแม่แบบเอาต์พุตสคริปต์ของเซกวิท ตัวเลขนั้นคือหมายเลขเวอร์ชันของเซกวิท (เช่น 0 คือเซกวิทเวอร์ชัน 0 หรือ segwit v0) ส่วนข้อมูลที่ตามมานั้นเรียกว่า witness program นอกจากนี้ยังสามารถนำแม่แบบเซกวิทไปห่อด้วยคอมมิตเมนต์แบบ P2SH ได้ แต่ในบทนี้เราจะยังไม่กล่าวถึง</p>
<p>จากมุมมองของโหนดเก่า เอาต์พุตสคริปต์แม่แบบเหล่านี้สามารถถูกใช้จ่ายด้วย input script ที่ว่างเปล่าได้ จากมุมมองของโหนดใหม่ที่รู้กฎของเซกวิท การใช้จ่ายเอาต์พุตที่เป็นแม่แบบเซกวิทต้องใช้ input script ที่ว่างเปล่าเท่านั้น สังเกตความแตกต่าง: โหนดเก่า “อนุญาต” ให้ใช้สคริปต์ว่างเปล่า ส่วนโหนดใหม่ “กำหนด” ให้ต้องเป็นสคริปต์ว่างเปล่า</p>
<p>การใช้ input script ว่างเปล่าทำให้ข้อมูลพยานไม่ไปกระทบกับ txid ช่วยกำจัดปัญหาการพึ่งพาวนซ้ำ การเปลี่ยนแปลงธุรกรรมโดยบุคคลที่สาม และการเปลี่ยนแปลงธุรกรรมโดยคู่สัญญา แต่เมื่อไม่สามารถใส่ข้อมูลใด ๆ ใน input script ได้ ผู้ใช้แม่แบบเอาต์พุตเซกวิทจึงต้องมีฟิลด์ใหม่ ฟิลด์นี้คือโครงสร้างพยาน (witness structure)</p>
<p>การเกิดขึ้นของ witness programs และ witness structure ทำให้บิตคอยน์ซับซ้อนขึ้น แต่สิ่งนี้ก็สอดคล้องกับแนวโน้มที่มีอยู่แล้วของการเพิ่มระดับนามธรรมในระบบบิตคอยน์ จากที่กล่าวไว้ในบทที่ 4 ว่าไวท์เปเปอร์บิตคอยน์ดั้งเดิมอธิบายระบบที่บิตคอยน์ถูก “รับ” ไปยัง public keys (pubkeys) และถูก “ใช้จ่าย” ด้วย signatures (sigs) pubkey ระบุว่าใครได้รับอนุญาตให้ใช้จ่ายบิตคอยน์ (คือผู้ที่ควบคุม private key ที่สอดคล้องกัน) และลายเซ็นเป็นการตรวจสอบว่าธุรกรรมการใช้จ่ายนั้นมาจากผู้ที่ควบคุม private key จริง ๆ เพื่อทำให้ระบบนั้นยืดหยุ่นขึ้น รุ่นแรกสุดของบิตคอยน์ได้แนะนำ scripts ซึ่งอนุญาตให้รับบิตคอยน์ไปยัง output scripts และใช้จ่ายด้วย input scripts ประสบการณ์ภายหลังจากการใช้งานโปรโตคอลสัญญาต่าง ๆ ได้นำไปสู่การอนุญาตให้รับบิตคอยน์ไปยัง witness programs และใช้จ่ายด้วย witness structure คำต่าง ๆ และฟิลด์ที่ถูกใช้ในเวอร์ชันต่าง ๆ ของบิตคอยน์ถูกแสดงไว้ในตารางข้างล่างนี้</p>
<table>
<thead>
<tr>
<th></th>
<th>Authorization</th>
<th>Authentication</th>
</tr>
</thead>
<tbody><tr>
<td>Whitepaper</td>
<td>Public key</td>
<td>Signature</td>
</tr>
<tr>
<td>Original (Legacy)</td>
<td>Output script</td>
<td>Input script</td>
</tr>
<tr>
<td>Segwit</td>
<td>Witness program</td>
<td>Witness structure</td>
</tr>
</tbody></table>
<h4>Witness Structure Serialization</h4>
<p>เช่นเดียวกับฟิลด์ inputs และ outputs, witness structure ก็มีฟิลด์ย่อยอื่น ๆ อยู่ภายใน ดังนั้นเราจะเริ่มต้นด้วยแผนที่ไบต์ (byte map) ของข้อมูลเหล่านั้นจากธุรกรรมของ Alice ซึ่งแสดงอยู่ในรูปด้านล่าง</p>
<p> <img src="https://image.nostr.build/d5c8cf4712e321ee4a37fa93b0a5c12364a7f321c6655a035ce56a20e3d9367e.jpg" alt="image"></p>
<p>ต่างจากฟิลด์ inputs และ outputs ตรงที่ witness structure โดยรวมจะไม่เริ่มต้นด้วยตัวบ่งชี้จำนวนของ witness stack ทั้งหมดที่มีอยู่ แต่จำนวนดังกล่าวถูกกำหนดโดยฟิลด์ inputs—กล่าวคือ ธุรกรรมหนึ่งรายการจะมีหนึ่ง witness stack ต่อหนึ่ง input เสมอ</p>
<p>สำหรับ witness structure ของแต่ละ input จะเริ่มต้นด้วยตัวนับจำนวนขององค์ประกอบที่อยู่ภายใน ซึ่งองค์ประกอบเหล่านี้เรียกว่า witness items เราจะศึกษารายละเอียดของมันในภายหลังในบทต่อไป แต่ตอนนี้สิ่งที่ต้องรู้คือ witness item แต่ละรายการจะถูกนำหน้าด้วย compactSize integer ที่ระบุขนาดของมัน</p>
<p>สำหรับ legacy inputs จะไม่มี witness items อยู่เลย ดังนั้น witness stack ของมันประกอบด้วยค่า 0 เพียงค่าเดียว (0x00)</p>
<p>ธุรกรรมของ Alice มี input หนึ่งรายการ และมี witness item หนึ่งรายการ</p>
<h3>Lock Time</h3>
<p>ฟิลด์สุดท้ายในธุรกรรมที่ถูกซีเรียลไลซ์คือ lock time ฟิลด์นี้เป็นส่วนหนึ่งของรูปแบบการซีเรียลไลซ์ดั้งเดิมของบิตคอยน์ แต่ในช่วงแรกมีผลเฉพาะกับนโยบายการเลือกธุรกรรมเข้าสู่บล็อกของบิตคอยน์เท่านั้น</p>
<p>ซอฟต์ฟอร์กที่บันทึกได้เป็นครั้งแรกของบิตคอยน์ได้เพิ่มกฎใหม่ว่า เริ่มตั้งแต่บล็อกหมายเลข 31,000 เป็นต้นไป ห้ามรวมธุรกรรมในบล็อก เว้นแต่ธุรกรรมนั้นจะเป็นไปตามหนึ่งในกฎต่อไปนี้:</p>
<ul>
<li>ธุรกรรมระบุว่า สามารถถูกรวมในบล็อกใดก็ได้ โดยตั้งค่า lock time เป็น 0  </li>
<li>ธุรกรรมระบุว่าต้องการจำกัดว่าบล็อกใดที่สามารถรวมมันได้ โดยตั้งค่า lock time ให้มีค่าต่ำกว่า 500,000,000 ในกรณีนี้ ธุรกรรมสามารถถูกบรรจุได้เฉพาะในบล็อกที่มีความสูงของบล็อก (block height) เท่ากับ lock time หรือมากกว่า ตัวอย่างเช่น ธุรกรรมที่มี lock time เป็น 123,456 สามารถอยู่ในบล็อก 123,456 หรือบล็อกใดที่สูงกว่า  </li>
<li>ธุรกรรมระบุว่าต้องการจำกัดเวลาที่สามารถถูกบรรจุเข้าสู่บล็อกเชนได้ โดยตั้งค่า lock time ให้มีค่า 500,000,000 หรือมากกว่า ในกรณีนี้ lock time จะถูกตีความเป็นเวลาตาม epoch time (จำนวนวินาทีตั้งแต่ 1970-01-01T00:00 UTC) ธุรกรรมจะถูกบรรจุได้เฉพาะในบล็อกที่มี median time past (MTP) มากกว่า lock time โดยทั่วไป MTP จะช้ากว่าเวลาปัจจุบันประมาณหนึ่งถึงสองชั่วโมง กฎของ MTP อธิบายไว้ในส่วนของ mtp</li>
</ul>
<h2><strong>Coinbase Transactions</strong></h2>
<p>ธุรกรรมแรกในทุกบล็อกเป็นกรณีพิเศษ เอกสารรุ่นเก่าหลายฉบับเรียกธุรกรรมนี้ว่า generation transaction แต่เอกสารรุ่นใหม่ส่วนใหญ่เรียกว่า coinbase transaction (ไม่เกี่ยวข้องกับธุรกรรมที่สร้างโดยบริษัทชื่อ “Coinbase”)</p>
<p>Coinbase transactions ถูกสร้างขึ้นโดยนักขุดที่ขุดบล็อกนั้น และเปิดโอกาสให้นักขุดสามารถรับ ค่าธรรมเนียม (fees) ทั้งหมดจากธุรกรรมที่อยู่ในบล็อกนั้นได้ นอกจากนี้ จนถึงบล็อกหมายเลข 6,720,000 นักขุดยังสามารถรับ subsidy ซึ่งเป็นบิตคอยน์ที่ถูกสร้างขึ้นใหม่และไม่เคยหมุนเวียนมาก่อน เรียกว่า block subsidy จำนวนรวมที่นักขุดสามารถรับได้จากบล็อกหนึ่ง ๆ — ประกอบด้วยค่าธรรมเนียมและ block subsidy — เรียกว่า block reward</p>
<p>พฤติกรรมพิเศษบางประการของ coinbase transactions มีดังนี้:</p>
<ul>
<li>ธุรกรรม coinbase สามารถมีอินพุตได้เพียงหนึ่งรายการเท่านั้น  </li>
<li>อินพุตเพียงรายการนั้นต้องมี outpoint ที่มี txid เป็นค่าว่าง (ศูนย์ทั้งหมด) และมี output index สูงสุด (0xffffffff) สิ่งนี้ทำให้ coinbase transaction ไม่สามารถอ้างอิงเอาต์พุตของธุรกรรมก่อนหน้า ซึ่งจะสร้างความสับสนเพราะ coinbase transaction มีหน้าที่จ่ายค่าธรรมเนียมและ subsidy  </li>
<li>ฟิลด์ที่โดยปกติจะเป็น input script จะถูกเรียกว่า coinbase ในธุรกรรมประเภทนี้ และนี่คือที่มาของชื่อ coinbase transaction ฟิลด์ coinbase ต้องมีความยาวอย่างน้อย 2 ไบต์ และต้องไม่เกิน 100 ไบต์ สคริปต์นี้ ไม่ถูกประมวลผล แต่ยังคงอยู่ภายใต้กฎจำกัดจำนวน sigops แบบ legacy ดังนั้นข้อมูลใด ๆ ที่ใส่เข้าไปควรถูกนำหน้าด้วย opcode สำหรับการ push data นอกจากนี้ ตั้งแต่ soft fork ปี 2013 (BIP34) ไบต์แรก ๆ ของฟิลด์นี้ต้องปฏิบัติตามกฎเพิ่มเติม ซึ่งจะอธิบายทีหลัง  </li>
<li>ผลรวมของค่าเอาต์พุตทั้งหมดต้องไม่เกินค่าธรรมเนียมจากธุรกรรมทั้งหมดในบล็อกนั้นรวมกับ subsidy โดย subsidy เริ่มต้นที่ 50 BTC ต่อบล็อก และลดลงครึ่งหนึ่งทุก 210,000 บล็อก (ประมาณทุก 4 ปี) โดยปัดเศษลงถึง satoshi ที่ใกล้ที่สุด  </li>
<li>ตั้งแต่ soft fork segwit ปี 2017 (BIP141) บล็อกใดก็ตามที่มีธุรกรรมใช้จ่าย segwit output ต้องมีเอาต์พุตใน coinbase transaction ที่เป็นการ commit ถึงธุรกรรมทั้งหมดในบล็อก (รวมถึง witness ด้วย) รายละเอียดจะอธิบายในส่วน mining</li>
</ul>
<p>coinbase transaction สามารถมีเอาต์พุตอื่น ๆ ที่ถูกต้องตามกฎเหมือนธุรกรรมทั่วไปได้ อย่างไรก็ตาม ธุรกรรมที่ใช้จ่ายเอาต์พุตของ coinbase จะไม่สามารถใส่ในบล็อกได้จนกว่าธุรกรรมนั้นจะมีอย่างน้อย 100 confirmations สิ่งนี้เรียกว่า maturity rule และเอาต์พุตของ coinbase ที่ยังไม่ถึง 100 confirmations จะถูกเรียกว่า immature แต่เนื่องจากลักษณะพิเศษของมัน ทำให้บางครั้งอาจเป็นสาเหตุของปัญหาที่ไม่คาดคิดในซอฟต์แวร์ที่ไม่ได้ออกแบบมาเพื่อรองรับกรณีเหล่านี้</p>
<h2><strong>Weight and Vbytes</strong></h2>
<p>แต่ละบล็อกของบิตคอยน์มีข้อจำกัดปริมาณข้อมูลธุรกรรมที่บรรจุได้ ดังนั้นซอฟต์แวร์บิตคอยน์ส่วนใหญ่จึงต้องสามารถวัดขนาดของธุรกรรมที่สร้างหรือประมวลผลได้ หน่วยวัดสมัยใหม่ที่ใช้คือ weight อีกหน่วยหนึ่งคือ vbytes ซึ่งคำนวณจากการนำ weight มาหารด้วยสี่ ทำให้สามารถเทียบกับหน่วยไบต์ในบล็อกแบบดั้งเดิมได้ง่ายขึ้น</p>
<p>ขนาดสูงสุดของบล็อกคือ <strong>4 ล้าน weight</strong> ส่วน <strong>block header</strong> ใช้พื้นที่ไป 240 weight และช่องข้อมูล <strong>transaction count</strong> ใช้อีก 4 หรือ 12 weight พื้นที่ที่เหลือทั้งหมดสามารถใช้สำหรับข้อมูลธุรกรรมได้</p>
<p>การคำนวณ weight ของฟิลด์หนึ่ง ๆ ในธุรกรรมทำได้โดยการนำจำนวนไบต์ของฟิลด์ที่ serialize แล้วไปคูณกับตัวคูณเฉพาะฟิลด์นั้น ๆ จากนั้นเมื่อต้องการหาน้ำหนักรวมของธุรกรรม ก็เพียงนำ weight ของทุกฟิลด์มาบวกกัน ตัวคูณสำหรับแต่ละฟิลด์ถูกระบุไว้ในตารางข้างล่างนี้ นอกจากนี้ยังมีตัวอย่างการคำนวณ weight ของแต่ละฟิลด์ในธุรกรรมตัวอย่างของบทนี้ (ธุรกรรมจาก Alice ไปยัง Bob)</p>
<p>ตัวคูณเหล่านี้ รวมถึงฟิลด์ที่เกี่ยวข้อง ถูกออกแบบมาเพื่อลดน้ำหนักเมื่อมีการใช้ UTXO ช่วยลดแรงจูงใจในการสร้างเอาต์พุตที่ไม่คุ้มค่า (uneconomical outputs) และหลีกเลี่ยงปัญหา dust ที่ไม่เหมาะสมตามที่อธิบายไว้ในหัวข้อ Uneconomical outputs and disallowed dust</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Factor</th>
<th>Weight in Alice’s Tx</th>
</tr>
</thead>
<tbody><tr>
<td>Version</td>
<td>4</td>
<td>16</td>
</tr>
<tr>
<td>Marker &amp; Flag</td>
<td>1</td>
<td>2</td>
</tr>
<tr>
<td>Inputs Count</td>
<td>4</td>
<td>4</td>
</tr>
<tr>
<td>Outpoint</td>
<td>4</td>
<td>144</td>
</tr>
<tr>
<td>Input script</td>
<td>4</td>
<td>4</td>
</tr>
<tr>
<td>Sequence</td>
<td>4</td>
<td>16</td>
</tr>
<tr>
<td>Outputs Count</td>
<td>4</td>
<td>4</td>
</tr>
<tr>
<td>Amount</td>
<td>4</td>
<td>64 (2 outputs)</td>
</tr>
<tr>
<td>Output script</td>
<td>4</td>
<td>232 (2 outputs with different scripts)</td>
</tr>
<tr>
<td>Witness Count</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>Witness items</td>
<td>1</td>
<td>66</td>
</tr>
<tr>
<td>Lock time</td>
<td>4</td>
<td>16</td>
</tr>
<tr>
<td>Total</td>
<td><em>N/A</em></td>
<td>569</td>
</tr>
</tbody></table>
<p>เราสามารถตรวจสอบความถูกต้องของการคำนวณ weight ได้โดยดูค่าน้ำหนักรวมของธุรกรรมของ Alice จาก Bitcoin Core ได้โดยตรง:</p>
<pre><code>$ bitcoin-cli getrawtransaction 466200308696215bbc949d5141a49a41\\

38ecdfdfaa2a8029c1f9bcecd1f96177 2 | jq .weight

569
</code></pre>
<p> <img src="https://image.nostr.build/2e3675764c1b67d8b9e19db81101b336607f7aa8ec79b094fc2244a70a6ad7b2.jpg" alt="image"></p>
<h3><strong>Legacy Serialization</strong></h3>
<p>รูปแบบการซีเรียลไลซ์ที่อธิบายไว้ในบทนี้คือรูปแบบที่ใช้กับธุรกรรมบิตคอยน์ส่วนใหญ่ในปัจจุบัน แต่ก็ยังมีรูปแบบเก่าที่ถูกใช้งานอยู่ในธุรกรรมจำนวนมากเช่นกัน รูปแบบเก่านั้นเรียกว่า <strong>legacy serialization</strong> และต้องใช้บนเครือข่าย Bitcoin P2P สำหรับธุรกรรมที่มีโครงสร้าง witness ว่างเปล่า (ซึ่งจะเกิดขึ้นได้ก็ต่อเมื่อธุรกรรมนั้นไม่ได้ใช้จ่าย witness programs ใด ๆ)</p>
<p>Legacy serialization จะ <strong>ไม่มี</strong> ฟิลด์ต่อไปนี้: marker, flag, witness structure</p>
<p>ในบทนี้ เราได้ดูฟิลด์ต่าง ๆ ในหนึ่งธุรกรรมและเห็นว่าฟิลด์เหล่านั้นสื่อสารข้อมูลให้โหนดเต็มทราบว่าเหรียญควรถูกโอนจากใครไปหาใครอย่างไร เราได้กล่าวถึง output script, input script และ witness structure เพียงคร่าว ๆ ซึ่งมีหน้าที่กำหนดเงื่อนไขและเปิดโอกาสให้ผู้ใช้พิสูจน์สิทธิ์ในการใช้จ่ายเหรียญได้</p>
<p>การเข้าใจวิธีสร้างและใช้งานเงื่อนไขเหล่านี้เป็นสิ่งสำคัญเพื่อให้แน่ใจว่าเฉพาะ Alice เท่านั้นที่จะสามารถใช้จ่ายบิตคอยน์ของเธอได้ ดังนั้นหัวข้อนี้จะเป็นเนื้อหาของบทถัดไป</p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<h1>บทที่ 6:Transactions: ธุรกรรมในบิตคอยน์</h1>
<hr>
<p>วิธีที่เรามักใช้ในการโอนเงินสดนั้นแทบไม่เหมือนกับวิธีที่เราโอนบิตคอยน์เลย เงินสดจริงเป็นโทเค็นที่ผู้ใช้ถือครองได้โดยตรง เช่นเมื่ออลิซจ่ายให้บ็อบโดยการยื่นโทเค็นจำนวนหนึ่ง เช่น การส่งธนบัตรดอลลาร์ให้เขา แต่มันไม่ใช่แบบนั้นเลยสำหรับบิตคอยน์  บิตคอยน์ไม่ได้มีอยู่จริงทั้งในรูปแบบทางกายภาพหรือในรูปแบบข้อมูลดิจิทัล อลิซไม่สามารถยื่นบิตคอยน์ให้บ็อบหรือส่งให้ทางอีเมลได้</p>
<p>ลองจินตนการดูว่าหากอลิซต้องการโอนสิทธ์ในการครอบครองที่ดินผืนหนึ่งให้บ๊อบได้อย่างไร เธอไม่สามารถยกที่ดินขึ้นมาแล้วยื่นให้บ็อบได้ แต่จะมีบันทึกบางอย่าง (ที่โดยทั่วไปดูแลโดยหน่วยงานของรัฐท้องถิ่น) ที่ระบุว่าที่ดินผืนนั้นเป็นของอลิซ แปลว่าอลิซสามารถโอนที่ดินให้บ็อบโดยทำให้รัฐบาลอัปเดตบันทึกนั้นให้ระบุว่าบ็อบเป็นเจ้าของที่ดินแทนเธอ</p>
<p>บิตคอยน์ทำงานในลักษณะคล้ายกัน มีฐานข้อมูลของมันอยู่บนโหนดทุก ๆ โหนดของบิตคอยน์ ที่ระบุว่าอลิซควบคุมบิตคอยน์จำนวนหนึ่ง อลิซจ่ายให้บ็อบโดยทำให้โหนด เหล่านั้นอัปเดตฐานข้อมูลของพวกเขาให้ระบุว่าบิตคอยน์บางส่วนของอลิซตอนนี้อยู่ภายใต้การควบคุมของบ็อบ ข้อมูลที่อลิซใช้เพื่อทำให้โหนดอัปเดตฐานข้อมูลของพวกเขาเรียกว่า “ธุรกรรม” ซึ่งกระทำได้โดยไม่ต้องใช้ตัวตนของอลิซหรือบ็อบโดยตรง</p>
<p>ในบทนี้ เราจะมาวิเคราะห์โครงสร้างของธุรกรรมบิตคอยน์และพิจารณาแต่ละส่วนประกอบ เพื่อดูว่ามันเอื้อต่อการโอนมูลค่าได้อย่างไรในรูปแบบที่มีความยืดหยุ่นและน่าเชื่อถือได้อย่างไร</p>
<h2>Serialized Bitcoin Transaction: ธุรกรรมบิตคอยน์ในรูปแบบลำดับข้อมูล</h2>
<p>ในบทที่ 3 เราได้ใช้ Bitcoin Core โดยเปิดใช้งานตัวเลือก txindex เพื่อดึงสำเนาของธุรกรรมการชำระเงินที่อลิซส่งให้บ็อบ ทีนี้เรามาลองดึงธุรกรรมที่มีการชำระเงินนั้นอีกครั้ง โดยจะแสดงอยู่ในธุรกรรมแบบลำดับข้อมูลของอลิซแทน</p>
<pre><code>$ bitcoin-cli getrawtransaction 466200308696215bbc949d5141a49a41\
38ecdfdfaa2a8029c1f9bcecd1f96177

01000000000101eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da13569
8679268041c54a0100000000ffffffff02204e0000000000002251203b41daba
4c9ace578369740f15e5ec880c28279ee7f51b07dca69c7061e07068f8240100
000000001600147752c165ea7be772b2c0acb7f4d6047ae6f4768e0141cf5efe
2d8ef13ed0af21d4f4cb82422d6252d70324f6f4576b727b7d918e521c00b51b
e739df2f899c49dc267c0ad280aca6dab0d2fa2b42a45182fc83e81713010000
0000
</code></pre>
<p>รูปแบบการลำดับข้อมูลของ Bitcoin Core นั้นมีความพิเศษ เพราะเป็นรูปแบบที่ใช้ในการสร้างคอมมิตเมนต์ของธุรกรรมและส่งต่อธุรกรรมนั้นผ่านเครือข่าย P2P ของบิตคอยน์ อย่างไรก็ตาม โปรแกรมอื่น ๆ สามารถใช้รูปแบบที่ต่างออกไปได้ ตราบใดที่มีการส่งข้อมูลชุดเดียวกันทั้งหมด แต่เนื่องจากรูปแบบของ Bitcoin Core มีความกระทัดรัดเมื่อเทียบกับปริมาณข้อมูลที่ส่ง และยังสามารถแยกวิเคราะห์ได้ง่าย โปรแกรมบิตคอยน์อื่น ๆ จำนวนมากจึงเลือกใช้รูปแบบนี้เช่นกัน</p>
<blockquote>
<p>Tip: รูปแบบการลำดับธุรกรรมอีกแบบหนึ่งที่ถูกใช้อย่างแพร่หลายที่เราทราบคือ partially signed bitcoin transaction (PSBT) ซึ่งมีการอธิบายไว้ใน BIP 174 และ BIP 370 (รวมถึงส่วนขยายที่ระบุไว้ใน BIP อื่น ๆ ) PSBT อนุญาตให้โปรแกรมที่ไม่น่าเชื่อถือสร้างเทมเพลตของธุรกรรมขึ้นมา เพื่อให้โปรแกรมที่เชื่อถือได้ (เช่น อุปกรณ์ฮาร์ดแวร์ที่ใช้ลงนามธุรกรรม) ซึ่งถือกุญแจส่วนตัวหรือข้อมูลสำคัญอื่น ๆ ที่จำเป็น สามารถตรวจสอบและเติมข้อมูลในเทมเพลตนั้นได้ เพื่อให้ทำเช่นนี้ได้ PSBT จึงรองรับการจัดเก็บข้อมูลเมตา (metadata) จำนวนมากเกี่ยวกับธุรกรรม ซึ่งทำให้มันมีขนาดใหญ่และไม่กระทัดรัดเท่ารูปแบบการลำดับข้อมูลมาตรฐาน หนังสือเล่มนี้จะไม่ลงรายละเอียดเกี่ยวกับ PSBT แต่เราแนะนำอย่างยิ่งสำหรับนักพัฒนา wallet ที่ต้องการรองรับการเซ็นชื่อด้วยหลายกุญแจ</p>
</blockquote>
<p>ธุรกรรมที่แสดงในรูปเลขฐาน 16 ข้างต้น ถูกจำลองเป็นแผนผังไบต์ในรูปข้างล่างนี้ โปรดสังเกตว่าการแสดงข้อมูลขนาด 32 ไบต์ต้องใช้เลขฐานสิบหกจำนวน 64 ตัว แผนผังนี้แสดงเฉพาะฟิลด์ในระดับบนสุดเท่านั้น เราจะมาพิจารณาแต่ละฟิลด์ตามลำดับที่มันปรากฏในธุรกรรม พร้อมอธิบายฟิลด์เพิ่มเติมที่อยู่ภายในแต่ละส่วน</p>
<p> <img src="https://image.nostr.build/14264e82a143c3c72a68453c951fb6ec4e0a542186c365eee5483108c9de1be7.jpg" alt="image"></p>
<h2>Version</h2>
<p>ไบต์สี่ตัวแรกของธุรกรรมบิตคอยน์ในรูปแบบลำดับข้อมูล คือ “เวอร์ชัน” ของมัน เวอร์ชันดั้งเดิมของธุรกรรมบิตคอยน์คือเวอร์ชัน 1 (0x01000000) ธุรกรรมทั้งหมดในระบบบิตคอยน์ต้องปฏิบัติตามกฎของธุรกรรมเวอร์ชัน 1 ซึ่งหลายส่วนของหนังสือเล่มนี้ได้อธิบายกฎเหล่านั้นไว้แล้ว</p>
<p>ธุรกรรมบิตคอยน์เวอร์ชัน 2 ถูกนำมาใช้ครั้งแรกในการอัปเกรดแบบซอฟต์ฟอร์กตามข้อเสนอ BIP68 ซึ่งเพิ่มข้อจำกัดเพิ่มเติมกับฟิลด์ sequence แต่ข้อจำกัดนี้จะมีผลเฉพาะกับธุรกรรมเวอร์ชัน 2 ขึ้นไปเท่านั้น ส่วนธุรกรรมเวอร์ชัน 1 จะไม่ได้รับผลกระทบ ข้อเสนอ BIP112 ซึ่งเป็นส่วนหนึ่งของซอฟต์ฟอร์กเดียวกันกับ BIP68 ได้อัปเกรดคำสั่ง OP_CHECKSEQUENCEVERIFY โดยทำให้คำสั่งนี้ล้มเหลวหากถูกประเมินในธุรกรรมที่มีเวอร์ชันต่ำกว่า 2 นอกเหนือจากการเปลี่ยนแปลงสองจุดนี้ ธุรกรรมเวอร์ชัน 2 จะเหมือนกับเวอร์ชัน 1 ทุกประการ</p>
<h3>Protecting Presigned Transactions</h3>
<p>ขั้นตอนสุดท้ายก่อนการกระจายธุรกรรมเข้าสู่เครือข่ายเพื่อบันทึกลงในบล็อกเชนคือ “การลงนาม” ธุรกรรม อย่างไรก็ตาม สามารถลงนามในธุรกรรมได้โดยยังไม่ต้องกระจายออกไปทันที คุณสามารถเก็บธุรกรรมที่ลงนามล่วงหน้าไว้นานหลายเดือนหรือหลายปี โดยเชื่อว่าจะสามารถนำมาบันทึกลงบล็อกเชนได้ในภายหลังเมื่อมีการกระจายธุรกรรมนั้น ในระหว่างนั้นคุณอาจสูญเสียการเข้าถึง private key ที่จำเป็นสำหรับการเซ็นธุรกรรมอื่นเพื่อใช้จ่ายเงินเดียวกันได้ ปรากฏการณ์นี้ไม่ใช่เรื่องสมมติ โปรโตคอลหลายอย่างที่สร้างบนบิตคอยน์ เช่น Lightning Network พึ่งพาธุรกรรมที่ลงนามล่วงหน้าเหล่านี้</p>
<p>สิ่งนี้สร้างความท้าทายให้กับนักพัฒนาโปรโตคอล เมื่อพวกเขาต้องช่วยผู้ใช้อัปเกรดโปรโตคอลฉันทามติของบิตคอยน์ การเพิ่มข้อจำกัดใหม่ เช่นที่ BIP68 เพิ่มไว้ในฟิลด์ sequence  อาจทำให้ธุรกรรมที่ลงนามล่วงหน้าบางรายการกลายเป็นโมฆะ และหากไม่สามารถสร้างลายเซ็นใหม่สำหรับธุรกรรมที่เทียบเท่ากันได้ เงินในธุรกรรมเหล่านั้นก็จะสูญหายไปอย่างถาวร</p>
<p>ปัญหานี้ได้รับการแก้ไขโดยการ “สงวน” ฟีเจอร์บางอย่างของธุรกรรมไว้สำหรับการอัปเกรดในอนาคต เช่น หมายเลขเวอร์ชัน ผู้ที่สร้างธุรกรรมแบบลงนามล่วงหน้าก่อน BIP68 ควรใช้ธุรกรรมเวอร์ชัน 1 ดังนั้นการที่ BIP68 กำหนดข้อจำกัดเพิ่มเติมให้มีผลเฉพาะกับธุรกรรมเวอร์ชัน 2 ขึ้นไป จึงไม่ทำให้ธุรกรรมที่ลงนามไว้ก่อนหน้านั้นเป็นโมฆะ</p>
<p>หากคุณกำลังพัฒนาโปรโตคอลที่ใช้ธุรกรรมแบบลงนามล่วงหน้า ให้แน่ใจว่าโปรโตคอลของคุณไม่ได้ใช้ฟีเจอร์ที่ถูกสงวนไว้สำหรับการอัปเกรดในอนาคต นโยบายการส่งต่อธุรกรรม (relay policy) เริ่มต้นของ Bitcoin Core ไม่อนุญาตให้ใช้ฟีเจอร์ที่ถูกสงวนเหล่านี้ คุณสามารถทดสอบว่าธุรกรรมของคุณสอดคล้องกับนโยบายดังกล่าวหรือไม่ โดยใช้คำสั่ง RPC testmempoolaccept บน Bitcoin mainnet</p>
<p>ณ เวลาที่เขียนนี้ มีข้อเสนอให้เริ่มใช้ธุรกรรมเวอร์ชัน 3 อย่างแพร่หลาย ข้อเสนอนี้ไม่ได้เปลี่ยนแปลงกฎฉันทามติของบิตคอยน์ แต่เปลี่ยนเฉพาะนโยบายที่โหนดใช้ในการส่งต่อธุรกรรม โดยภายใต้ข้อเสนอนั้น ธุรกรรมเวอร์ชัน 3 จะถูกกำหนดข้อจำกัดเพิ่มเติม เพื่อป้องกันการโจมตีแบบ Denial of Service (DoS) บางรูปแบบ ซึ่งเราจะกล่าวถึงเพิ่มเติมในส่วนถัดไป</p>
<h2>Extended Marker and Flag: ตัวระบุ Marker และ Flag แบบขยาย</h2>
<p>ฟิลด์สองช่องถัดไปของตัวอย่างธุรกรรมในรูปแบบลำดับข้อมูล ถูกเพิ่มเข้ามาในกระบวนการอัปเกรดแบบ soft fork ของ Segregated Witness (SegWit) ซึ่งเป็นการเปลี่ยนแปลงในกฎฉันทามติของบิตคอยน์ การเปลี่ยนแปลงนี้อ้างอิงตามข้อเสนอ BIP141 และ BIP143 โดยที่รูปแบบการลำดับข้อมูลแบบขยายนี้ถูกกำหนดไว้ใน BIP144</p>
<p>หากธุรกรรมมีโครงสร้างของ witness (ซึ่งเราจะอธิบายในหัวข้อ “Witness Structure”) ค่า marker ต้องเป็นศูนย์ (0x00) และค่า flag ต้องไม่เป็นศูนย์ ในโปรโตคอล P2P ปัจจุบัน ค่าของ flag ควรเป็นหนึ่ง (0x01) เสมอ โดยมีการสงวนค่าอื่นไว้สำหรับการอัปเกรดโปรโตคอลในอนาคต</p>
<p>หากธุรกรรมไม่มีข้อมูล witness stack ค่า marker และ flag จะต้องไม่ปรากฏอยู่ในธุรกรรม ซึ่งทำให้สามารถทำงานร่วมกับรูปแบบการลำดับข้อมูลดั้งเดิมของบิตคอยน์ได้ หรือที่ปัจจุบันเรียกว่า legacy serialization (รายละเอียดเพิ่มเติมดูได้ในหัวข้อ “Legacy Serialization”)</p>
<p>ในรูปแบบ legacy การตีความค่า marker จะถือว่าเป็นจำนวนของอินพุต (ซึ่งในกรณีนี้คือศูนย์) แต่ธุรกรรมไม่สามารถมีอินพุตเป็นศูนย์ได้ ดังนั้น marker จึงทำหน้าที่เป็นสัญญาณให้โปรแกรมรุ่นใหม่รู้ว่า ธุรกรรมนี้ใช้รูปแบบการลำดับข้อมูลแบบขยาย ส่วนฟิลด์ flag ก็ทำหน้าที่ในลักษณะเดียวกัน และยังช่วยให้การอัปเดตรูปแบบการลำดับข้อมูลในอนาคตเป็นไปได้ง่ายขึ้นอีกด้วย</p>
<h2>Inputs</h2>
<p>ฟิลด์ inputs ประกอบด้วยฟิลด์ย่อยหลายส่วน ดังนั้นเราจะมาเริ่มกันจากการดูแผนผังไบต์ของฟิลด์นี้ในตัวอย่างธุรกรรมของอลิซ ที่แสดงไว้ในภาพด้านล่าง<br> <img src="https://image.nostr.build/604cd0c7982b98dde29a0a676db0f8d28e080317d20a1a81a886730139ff3b11.jpg" alt="image"></p>
<h3>Length of Transaction Input List: ความยาวของรายการอินพุตของธุรกรรม</h3>
<p>รายการอินพุตของธุรกรรมจะเริ่มต้นด้วยจำนวนเต็มที่ระบุจำนวนอินพุตทั้งหมดในธุรกรรมนั้น ค่าต่ำสุดคือหนึ่ง และแม้จะไม่มีการกำหนดค่าสูงสุดอย่างชัดเจน แต่ข้อจำกัดของขนาดธุรกรรมสูงสุดในบิตคอยน์จะจำกัดให้ธุรกรรมหนึ่งมีได้เพียงไม่กี่พันอินพุตเท่านั้น ตัวเลขนี้จะถูกเข้ารหัสในรูปแบบ compactSize unsigned integer</p>
<h3>CompactSize Unsigned Integers: จำนวนเต็มแบบ CompactSize</h3>
<p>จำนวนเต็มที่ไม่มีเครื่องหมาย (unsigned integers) ในบิตคอยน์ ซึ่งโดยทั่วไปมักมีค่าต่ำ แต่บางครั้งอาจมีค่าสูง จะถูกเข้ารหัสโดยใช้ชนิดข้อมูลที่เรียกว่า compactSize ซึ่งเป็นรูปแบบของจำนวนเต็มแบบความยาวแปรผัน (variable-length integer) จึงมักถูกเรียกว่า var_int หรือ varint (ดูรายละเอียดเพิ่มเติมได้ในเอกสารของ BIP37 และ BIP144)</p>
<blockquote>
<p>warning: มีรูปแบบของ “จำนวนเต็มแบบความยาวแปรผัน” (variable-length integers) หลายแบบที่ถูกใช้ในโปรแกรมต่าง ๆ รวมถึงโปรแกรมในระบบบิตคอยน์เองด้วย ตัวอย่างเช่น Bitcoin Core ใช้ชนิดข้อมูลที่เรียกว่า VarInts ในการจัดเก็บฐานข้อมูล UTXO ซึ่ง แตกต่างจาก compactSize นอกจากนี้ ฟิลด์ nBits ในส่วนหัวของบล็อก (block header) ก็ถูกเข้ารหัสด้วยชนิดข้อมูลเฉพาะที่เรียกว่า Compact ซึ่งก็ไม่เกี่ยวข้องกับ compactSize เช่นกัน ดังนั้น เมื่อเราอ้างถึงจำนวนเต็มแบบความยาวแปรผันที่ใช้ในการ serialize ธุรกรรมบิตคอยน์ (Bitcoin transaction) และในส่วนอื่นของ โปรโตคอล P2P ของบิตคอยน์ เราจะใช้คำเต็มว่า compactSize เสมอ เพื่อป้องกันความสับสนกับรูปแบบอื่น ๆ ที่ชื่อคล้ายกันแต่มีโครงสร้างต่างกัน</p>
</blockquote>
<p>สำหรับตัวเลขในช่วง 0 ถึง 252 ค่าของ compactSize unsigned integers จะเหมือนกับชนิดข้อมูล uint8_t ในภาษา C ทุกประการ ซึ่งเป็นรูปแบบการเข้ารหัสตัวเลขที่โปรแกรมเมอร์ส่วนใหญ่คุ้นเคยอยู่แล้ว แต่สำหรับตัวเลขที่มีค่ามากกว่า 252 (จนถึง 0xffffffffffffffff) จะมีการเพิ่ม ไบต์นำหน้า (prefix byte) เพื่อระบุความยาวของจำนวนตัวเลขนั้น อย่างไรก็ตาม นอกจากไบต์นำหน้าแล้ว ตัวเลขส่วนที่เหลือจะยังคงมีลักษณะเหมือนกับการเข้ารหัสของจำนวนเต็มแบบ unsigned ปกติในภาษา C อยู่ดี</p>
<table>
<thead>
<tr>
<th align="left">ค่าตัวเลข (Value)</th>
<th>จำนวนไบต์ที่ใช้ (Bytes used)</th>
<th>รูปแบบ (Format)</th>
</tr>
</thead>
<tbody><tr>
<td align="left">≥ 0 และ ≤ 252 (0xfc)</td>
<td>1</td>
<td>เข้ารหัสเป็น uint8_t</td>
</tr>
<tr>
<td align="left">≥ 253 และ ≤ 0xffff</td>
<td>3</td>
<td>เริ่มด้วย 0xfd ตามด้วยตัวเลขที่เข้ารหัสเป็น uint16_t</td>
</tr>
<tr>
<td align="left">≥ 0x10000 และ ≤ 0xffffffff</td>
<td>5</td>
<td>เริ่มด้วย 0xfe ตามด้วยตัวเลขที่เข้ารหัสเป็น uint32_t</td>
</tr>
<tr>
<td align="left">≥ 0x100000000 และ ≤ 0xffffffffffffffff</td>
<td>9</td>
<td>เริ่มด้วย 0xff ตามด้วยตัวเลขที่เข้ารหัสเป็น uint64_t</td>
</tr>
</tbody></table>
<p>อินพุตแต่ละรายการในธุรกรรมจะต้องมีสามฟิลด์หลัก ได้แก่ Outpoint field, Length-prefixed input script field, และ Sequence</p>
<p>เราจะพิจารณาแต่ละฟิลด์เหล่านี้ในส่วนถัดไป อินพุตบางรายการยังมี witness stack ด้วย แต่จะถูกจัดลำดับข้อมูลไว้ที่ท้ายธุรกรรม ดังนั้นเราจะมาศึกษามันในภายหลัง</p>
<h3>Outpoint</h3>
<p>ธุรกรรมบิตคอยน์คือคำขอที่ส่งให้ full node ทำการอัปเดตฐานข้อมูลเกี่ยวกับข้อมูลความเป็นเจ้าของเหรียญ สำหรับอลิซที่จะโอนบิตคอยน์บางส่วนของเธอให้บ๊อบ เธอต้องบอกให้โหนดรู้ก่อนว่าจะหาธุรกรรมก่อนหน้าที่เธอได้รับบิตคอยน์เหล่านั้นได้จากที่ไหน เนื่องจากการควบคุมบิตคอยน์ถูกกำหนดไว้ใน output ของธุรกรรม อลิซจึงชี้ไปยัง output ก่อนหน้าโดยใช้ฟิลด์ outpoint อินพุตแต่ละรายการต้องมี outpoint หนึ่งรายการเสมอ</p>
<p>outpoint ประกอบด้วย txid ขนาด 32 ไบต์ของธุรกรรมที่อลิซได้รับบิตคอยน์ที่เธอต้องการใช้จ่าย txid นี้อยู่ในลำดับไบต์ภายในของบิตคอยน์สำหรับแฮช (ดูหัวข้อ Internal and Display Byte Orders)</p>
<p>เนื่องจากธุรกรรมหนึ่งรายการอาจมีหลาย output อลิซจึงต้องระบุด้วยว่าเธอจะใช้ output ใดจากธุรกรรมนั้น ซึ่งเรียกว่า output index โดย output index เป็นจำนวนเต็มแบบไม่ติดลบ (unsigned integer) ขนาด 4 ไบต์ เริ่มจากศูนย์</p>
<p>เมื่อ full node พบ outpoint มันจะใช้ข้อมูลนี้เพื่อค้นหา output ที่ถูกอ้างอิง โหนดเต็มจะต้องค้นหาเฉพาะธุรกรรมก่อนหน้าในบล็อกเชนเท่านั้น ตัวอย่างเช่น หากธุรกรรมของอลิซถูกบันทึกไว้ในบล็อก 774,958  full node ที่ตรวจสอบธุรกรรมของเธอจะค้นหา output ที่ถูกอ้างอิงในบล็อกนั้นและบล็อกก่อนหน้าเท่านั้น ไม่ใช่บล็อกที่อยู่หลังจากนั้น ภายในบล็อก 774,958 full node จะค้นหาเฉพาะธุรกรรมที่อยู่ก่อนธุรกรรมของอลิซ โดยพิจารณาตามลำดับของ leaf ใน merkle tree ของบล็อกนั้น </p>
<p>เมื่อพบ output ก่อนหน้าแล้ว full node จะได้รับข้อมูลสำคัญหลายอย่างจากมัน ได้แก่</p>
<ul>
<li><p>จำนวนบิตคอยน์ที่ถูกกำหนดไว้ใน output ก่อนหน้า: บิตคอยน์ทั้งหมดใน output นั้นจะถูกโอนไปในธุรกรรมนี้ ตัวอย่างเช่น ในธุรกรรมตัวอย่าง ค่าใน output ก่อนหน้าคือ 100,000 satoshis</p>
</li>
<li><p>เงื่อนไขการอนุญาตของ output ก่อนหน้า: เงื่อนไขที่ต้องถูกปฏิบัติตามเพื่อที่จะใช้จ่ายบิตคอยน์ที่ถูกกำหนดไว้ใน output นั้น</p>
</li>
<li><p>สำหรับธุรกรรมที่ได้รับการยืนยันแล้ว (confirmed transactions) full node จะทราบ block height ที่ธุรกรรมได้รับการยืนยัน และ ค่า median time past (MTP) ของบล็อกนั้น ข้อมูลนี้จำเป็นสำหรับการทำงานของ relative timelock (อธิบายไว้ในหัวข้อ Sequence as a consensus-enforced relative timelock) และสำหรับ output ของ coinbase transaction (อธิบายไว้ในหัวข้อ Coinbase Transactions)</p>
</li>
<li><p>หลักฐานว่า output ก่อนหน้านั้นมีอยู่จริงในบล็อกเชน (หรือเป็นธุรกรรมที่ยังไม่ได้ยืนยันแต่เป็นที่รู้จัก) และยังไม่มีธุรกรรมอื่นใดที่ใช้มันไปแล้ว หนึ่งในกฎฉันทามติของบิตคอยน์ห้ามไม่ให้ output เดียวกันถูกใช้มากกว่าหนึ่งครั้งภายในบล็อกเชน นี่คือกฎที่ป้องกัน double spending อลิซไม่สามารถใช้ output เดิมเดียวกันเพื่อจ่ายทั้งให้บ๊อบและแครอลในธุรกรรมที่แยกกันได้ สองธุรกรรมที่พยายามใช้ output เดียวกันเรียกว่า conflicting transactions เพราะมีเพียงหนึ่งในนั้นเท่านั้นที่สามารถถูกบันทึกในบล็อกเชนได้</p>
</li>
</ul>
<p>แนวทางที่แตกต่างกันในการติดตาม output ก่อนหน้าได้ถูกทดลองใช้โดยการทำงานของ full node ที่แตกต่างกันในช่วงเวลาต่าง ๆ ส่วนในปัจจุบัน Bitcoin Core ใช้วิธีที่เชื่อว่าได้ผลดีที่สุดในการเก็บรักษาข้อมูลที่จำเป็นทั้งหมดในขณะที่ลดการใช้พื้นที่ดิสก์ให้น้อยที่สุด คือมันเก็บฐานข้อมูลที่บันทึกทุก UTXO และเมตาดาต้าที่จำเป็นเกี่ยวกับมัน (เช่น block height) ทุกครั้งที่บล็อกใหม่ของธุรกรรมเข้ามา output ทั้งหมดที่ถูกใช้จะถูกลบออกจากฐานข้อมูล UTXO และ output ทั้งหมดที่ถูกสร้างขึ้นใหม่จะถูกเพิ่มเข้าไปในฐานข้อมูล</p>
<h3>Internal and Display Byte Orders(การจัดเรียงไบต์ภายในและสำหรับการแสดงผล)</h3>
<p>บิตคอยน์ได้ใช้ hash function ที่เรียกว่า digest ในหลายรูปแบบ Digest ถูกใช้เป็นตัวระบุเฉพาะสำหรับบล็อกและธุรกรรม ใช้ในกระบวนการยืนยันความถูกต้องของ address บล็อก ธุรกรรม ลายเซ็น และอื่น ๆ อีกมากมาย นอกจากนี้ digest ยังถูกนำมาใช้ซ้ำในฟังก์ชัน proof-of-work ของ Bitcoin ในบางกรณี digest ของ hash จะถูกแสดงให้ผู้ใช้เห็นในรูปแบบการจัดเรียงไบต์หนึ่ง แต่ระบบภายในกลับใช้รูปแบบการจัดเรียงไบต์อีกแบบหนึ่ง ซึ่งอาจก่อให้เกิดความสับสนได้ ตัวอย่างเช่น ลองพิจารณา txid ของ output ก่อนหน้าใน outpoint ของธุรกรรมตัวอย่างของเรา</p>
<pre><code>eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da135698679268041c54a
</code></pre>
<p>ถ้าเราพยายามใช้ txid นั้นเพื่อดึงข้อมูลธุรกรรมจาก Bitcoin Core เราจะพบข้อผิดพลาด และจำเป็นต้องสลับลำดับไบต์ของมันก่อน</p>
<pre><code>$ bitcoin-cli getrawtransaction \
  eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da135698679268041c54a
error code: -5
error message:
No such mempool or blockchain transaction.
Use gettransaction for wallet transactions.
$ echo eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da135698679268041c54a \
  | fold -w2 | tac | tr -d "\n"
4ac541802679866935a19d4f40728bb89204d0cac90d85f3a51a19278fe33aeb
$ bitcoin-cli getrawtransaction \
  4ac541802679866935a19d4f40728bb89204d0cac90d85f3a51a19278fe33aeb
02000000000101c25ae90c9f3d40cc1fc509ecfd54b06e35450702…
</code></pre>
<p>พฤติกรรมแปลก ๆ นี้น่าจะเป็นผลที่เกิดขึ้นโดยไม่ได้ตั้งใจจากการตัดสินใจออกแบบในซอฟต์แวร์บิตคอยน์ยุคแรก ๆ ในทางปฏิบัติ นั่นหมายความว่านักพัฒนาซอฟต์แวร์บิตคอยน์จำเป็นต้องจำไว้ว่าต้องสลับลำดับไบต์ในตัวระบุธุรกรรมและบล็อกก่อนที่จะแสดงให้ผู้ใช้เห็น</p>
<p>ในหนังสือเล่มนี้ เราใช้คำว่า ลำดับไบต์ภายใน (internal byte order) สำหรับข้อมูลที่ปรากฏอยู่ภายในธุรกรรมและบล็อก และใช้คำว่า ลำดับไบต์สำหรับแสดงผล (display byte order) สำหรับรูปแบบที่แสดงต่อผู้ใช้ อีกชุดของคำที่มักใช้กันคือ ลำดับไบต์แบบ little-endian สำหรับรูปแบบภายใน และ ลำดับไบต์แบบ big-endian สำหรับรูปแบบที่แสดงผล</p>
<blockquote>
<p>อันนี้หลามเสริมให้ มันคือการแบ่งทีละสองตำแหน่งและนับว่านั่นเป็นหนึ่ง เช่น abcdef ก็จะเป็น ab คือ 1 cd คือ 2 ef คือ 3 พอแปลงเป็น display byte order ก็ทำการสลับเป็น 3,2,1 หรือ efcdab</p>
</blockquote>
<h2>Input Script</h2>
<p>ฟิลด์ input script เป็นส่วนที่หลงเหลือมาจากรูปแบบธุรกรรมแบบดั้งเดิม (legacy transaction format) ตัวอย่างธุรกรรมของเราเป็น input ที่ใช้จ่าย output แบบ native segwit ซึ่งไม่จำเป็นต้องมีข้อมูลใน input script ดังนั้นค่านำหน้าความยาว (length prefix) ของ input script จึงถูกตั้งค่าเป็นศูนย์ (0x00)</p>
<p>สำหรับตัวอย่างของ input script ที่มีค่านำหน้าความยาวและใช้จ่าย output แบบดั้งเดิม เราจะใช้ตัวอย่างจากธุรกรรมหนึ่งในบล็อกล่าสุดในขณะที่เขียนอยู่นี้</p>
<pre><code>6b483045022100a6cc4e8cd0847951a71fad3bc9b14f24d44ba59d19094e0a8c
fa2580bb664b020220366060ea8203d766722ed0a02d1599b99d3c95b97dab8e
41d3e4d3fe33a5706201210369e03e2c91f0badec46c9c903d9e9edae67c167b
9ef9b550356ee791c9a40896
</code></pre>
<p>ค่านำหน้าความยาว (length prefix) เป็นจำนวนเต็มแบบ compactSize unsigned integer ที่ระบุความยาวของฟิลด์ input script ที่ถูกซีเรียลไลซ์ไว้ ในกรณีนี้เป็นไบต์เดียว (0x6b) ซึ่งระบุว่า input script มีความยาว 107 ไบต์</p>
<h2>Sequence(ลำดับ)</h2>
<p>ไบต์สี่ตัวสุดท้ายของ input คือหมายเลขลำดับ (sequence number) ซึ่งการใช้งานและความหมายของฟิลด์นี้ได้มีการเปลี่ยนแปลงไปตามกาลเวลา</p>
<h3>การแทนที่ธุรกรรมโดยอิงตามลำดับ (Original sequence-based transaction replacement)</h3>
<p>เดิมทีฟิลด์ sequence ถูกออกแบบมาเพื่อให้สามารถสร้างหลายเวอร์ชันของธุรกรรมเดียวกันได้ โดยที่เวอร์ชันหลังสามารถแทนที่เวอร์ชันก่อนหน้าในฐานะตัวเลือกสำหรับการยืนยัน หมายเลขลำดับทำหน้าที่ติดตามเวอร์ชันของธุรกรรม</p>
<p>ตัวอย่างเช่น ลองจินตนาการว่าอลิซและบ็อบต้องการเดิมพันผลเกมไพ่ พวกเขาเริ่มจากการลงนามธุรกรรมที่แต่ละคนฝากเงินไว้ในเอาต์พุตซึ่งต้องการลายเซ็นจากทั้งคู่เพื่อใช้จ่าย ซึ่งเรียกว่า สคริปต์หลายลายเซ็น (multisignature script หรือ multisig) ธุรกรรมนี้เรียกว่า setup transaction จากนั้นพวกเขาสร้างธุรกรรมที่ใช้จ่ายเอาต์พุตนั้นดังนี้</p>
<ul>
<li>เวอร์ชันแรกของธุรกรรม โดยมีค่า <code>nSequence</code> เท่ากับ 0 (0x00000000) เป็นการคืนเงินให้อลิซและบ็อบตามจำนวนที่แต่ละคนฝากไว้ในตอนแรก ธุรกรรมนี้เรียกว่า <em>refund transaction</em> ซึ่งทั้งคู่ยังไม่เผยแพร่ในตอนนี้ จะใช้ก็ต่อเมื่อเกิดปัญหาเท่านั้น  </li>
<li>อลิซชนะรอบแรกของเกมไพ่ ธุรกรรมเวอร์ชันที่สองมีค่า <em>sequence</em> เป็น 1 และปรับจำนวนเงินที่อลิซได้รับให้มากขึ้น ในขณะที่ส่วนของบ็อบลดลง ทั้งคู่ลงนามในธุรกรรมที่อัปเดตแล้วนี้อีกครั้ง แต่ก็ยังไม่เผยแพร่ เว้นแต่จะมีเหตุจำเป็น  </li>
<li>บ็อบชนะรอบที่สอง ลำดับจึงถูกเพิ่มเป็น 2 ส่วนแบ่งของอลิซลดลงและของบ็อบเพิ่มขึ้น ทั้งคู่ลงนามอีกครั้งแต่ยังไม่เผยแพร่</li>
</ul>
<p>หลังจากเล่นอีกหลายรอบ โดยที่ค่า sequence ถูกเพิ่มขึ้นในแต่ละรอบ เงินถูกปรับสมดุลใหม่ และธุรกรรมถูกลงนามแต่ยังไม่เผยแพร่ พวกเขาตัดสินใจจะสิ้นสุดเกม ด้วยการสร้างธุรกรรมสุดท้ายที่สะท้อนยอดเงินสุดท้ายของทั้งคู่ จากนั้นตั้งค่า sequence เป็นค่าสูงสุด (0xffffffff) เพื่อเป็นการ “สิ้นสุด” ธุรกรรมนี้ พวกเขาจึงเผยแพร่เวอร์ชันนี้ออกไป ธุรกรรมถูกส่งต่อไปทั่วเครือข่าย และในที่สุดก็ได้รับการยืนยันโดยนักขุด</p>
<p>เราสามารถเห็นกฎการแทนที่ของ sequence ทำงานอย่างไรได้ หากพิจารณาสถานการณ์ทางเลือกดังต่อไปนี้</p>
<ul>
<li><p>ลองจินตนาการว่าอลิซเผยแพร่ธุรกรรมสุดท้ายที่มีค่า sequence เท่ากับ 0xffffffff จากนั้นบ็อบเผยแพร่ธุรกรรมเวอร์ชันก่อนหน้าที่เขาได้รับส่วนแบ่งมากกว่า เนื่องจากเวอร์ชันของบ็อบมีหมายเลขลำดับต่ำกว่า โหนดเต็ม (full nodes) ที่ใช้โค้ดบิตคอยน์เวอร์ชันดั้งเดิมจะไม่ส่งต่อธุรกรรมนั้นไปยังนักขุด และนักขุดที่ใช้โค้ดเวอร์ชันเดิมก็จะไม่ขุดมันเช่นกัน</p>
</li>
<li><p>ในอีกสถานการณ์หนึ่ง สมมติว่าบ็อบเผยแพร่ธุรกรรมเวอร์ชันก่อนหน้าเพียงไม่กี่วินาทีก่อนที่อลิซจะเผยแพร่เวอร์ชันสุดท้าย โหนดต่าง ๆ จะส่งต่อเวอร์ชันของบ็อบและนักขุดจะพยายามขุดมัน แต่เมื่อเวอร์ชันของอลิซที่มีหมายเลขลำดับสูงกว่ามาถึง โหนดก็จะส่งต่อเวอร์ชันของอลิซด้วย และนักขุดที่ใช้โค้ดบิตคอยน์เวอร์ชันดั้งเดิมจะพยายามขุดเวอร์ชันของอลิซแทนเวอร์ชันของบ็อบ เว้นแต่ว่าบ็อบจะโชคดีและมีการค้นพบบล็อกก่อนที่เวอร์ชันของอลิซจะมาถึง มิฉะนั้นธุรกรรมเวอร์ชันของอลิซจะเป็นเวอร์ชันที่ได้รับการยืนยันในที่สุด</p>
</li>
</ul>
<p>โปรโตคอลประเภทนี้คือสิ่งที่เราเรียกว่า payment channel ในปัจจุบัน ผู้สร้างบิตคอยน์ได้กล่าวถึงในอีเมลที่มีการอ้างถึงเขา เรียกธุรกรรมประเภทนี้ว่า high-frequency transactions และได้อธิบายคุณสมบัติบางอย่างที่เพิ่มเข้าไปในโปรโตคอลเพื่อรองรับการใช้งานเหล่านี้ เราจะเรียนรู้เกี่ยวกับคุณสมบัติอื่น ๆ เหล่านี้ในภายหลัง และยังจะได้เห็นด้วยว่าเวอร์ชันสมัยใหม่ของ payment channel ถูกนำมาใช้ในบิตคอยน์อย่างแพร่หลายมากขึ้นในปัจจุบัน</p>
<p>มีปัญหาบางประการกับ payment channel ที่อิงตาม sequence เพียงอย่างเดียว ปัญหาแรกคือกฎสำหรับการแทนที่ธุรกรรมที่มี sequence ต่ำด้วยธุรกรรมที่มี sequence สูงเป็นเพียงนโยบายของซอฟต์แวร์เท่านั้น ไม่มีแรงจูงใจโดยตรงให้นักขุดชอบเวอร์ชันใดเวอร์ชันหนึ่งมากกว่าเวอร์ชันอื่น ปัญหาที่สองคือคนแรกที่ส่งธุรกรรมอาจโชคดีให้ธุรกรรมนั้นได้รับการยืนยัน แม้ว่าจะไม่ใช่ธุรกรรมที่มี sequence สูงสุดก็ตาม โปรโตคอลด้านความปลอดภัยที่ล้มเหลวบ้างเพียงไม่กี่เปอร์เซ็นต์เพราะโชคไม่ดีจึงไม่ใช่โปรโตคอลที่มีประสิทธิภาพนัก</p>
<p>ปัญหาที่สามคือสามารถแทนที่เวอร์ชันหนึ่งของธุรกรรมด้วยเวอร์ชันที่ต่างออกไปได้โดยไม่จำกัดจำนวนครั้ง แต่ละครั้งที่แทนที่จะใช้แบนด์วิดท์ของโหนดเต็มที่ทำหน้าที่ส่งต่อบนเครือข่ายทั้งหมด ยกตัวอย่างเช่น ณ เวลาที่เขียนนี้ มี full node ที่ทำหน้าที่ส่งต่อประมาณ 50,000 โหนด; ผู้โจมตีที่สร้างธุรกรรมแทนที่ 1,000 รายการต่อหนึ่งนาที โดยแต่ละรายการมีขนาด 200 ไบต์ จะใช้แบนด์วิดท์ส่วนตัวของเขาประมาณ 20 KB ต่อหนึ่งนาที แต่จะใช้แบนด์วิดท์เครือข่ายของ full node ประมาณ 10 GB ทุก ๆ นาที นอกจากค่าใช้จ่ายแบนด์วิดท์ส่วนตัว 20 KB/นาที และค่าธรรมเนียมเพียงเป็นครั้งคราวเมื่อต้องมีธุรกรรมที่ถูกยืนยัน ผู้โจมตีจะไม่ต้องจ่ายค่าใช้จ่ายใด ๆ สำหรับภาระอันมหาศาลที่พวกเขาก่อขึ้นกับผู้ดำเนิน full node เลย</p>
<p>เพื่อกำจัดความเสี่ยงจากการโจมตีนี้ รูปแบบการแทนที่ธุรกรรมที่อิงตาม sequence แบบเดิมถูกปิดใช้งานในเวอร์ชันแรก ๆ ของซอฟต์แวร์บิตคอยน์ ในช่วงหลายปี  full node ของบิตคอยน์จะไม่อนุญาตให้ธุรกรรมที่ยังไม่ได้ยืนยันซึ่งมีอินพุตหนึ่ง (ตามที่ระบุโดย outpoint) ถูกแทนที่ด้วยธุรกรรมอื่นที่มีอินพุตเดียวกัน อย่างไรก็ตาม สถานการณ์นั้นไม่ได้ดำเนินต่อไปตลอดเวลา</p>
<h3>การสัญญาณเพื่อแทนที่ธุรกรรมแบบ Opt-in</h3>
<p>หลังจากรูปแบบการแทนที่ธุรกรรมที่อิงตาม sequence แบบเดิมถูกปิดใช้งานเนื่องจากมีความเสี่ยงที่จะถูกละเมิด ได้มีการเสนอวิธีแก้ไข: การโปรแกรม Bitcoin Core และซอฟต์แวร์โหนดเต็มที่ส่งต่อธุรกรรมอื่น ๆ ให้อนุญาตให้ธุรกรรมที่จ่ายค่าธรรมเนียมสูงแทนที่ธุรกรรมที่ขัดแย้งและจ่ายค่าธรรมเนียมต่ำกว่า เรียกวิธีนี้ว่า replace by fee (RBF)</p>
<p>ผู้ใช้และธุรกิจบางรายคัดค้านการเพิ่มการสนับสนุนการแทนที่ธุรกรรมกลับเข้าไปใน Bitcoin Core ดังนั้นจึงได้ข้อยุติด้วยการใช้ฟิลด์ sequence อีกครั้งเพื่อสนับสนุนการแทนที่</p>
<p>ตามที่ระบุใน BIP125 ธุรกรรมที่ยังไม่ได้ยืนยันซึ่งมีอินพุตใด ๆ ที่ตั้งค่า sequence ต่ำกว่า 0xfffffffe (เช่น อย่างน้อย 2 ต่ำกว่าค่าสูงสุด) จะส่งสัญญาณไปยังเครือข่ายว่าผู้ลงนามต้องการให้ธุรกรรมนี้สามารถถูกแทนที่ด้วยธุรกรรมที่จ่ายค่าธรรมเนียมสูงกว่าได้ Bitcoin Core อนุญาตให้ธุรกรรมที่ยังไม่ได้ยืนยันเหล่านี้ถูกแทนที่ได้ และยังคงไม่อนุญาตให้ธุรกรรมอื่น ๆ ถูกแทนที่ ทำให้ผู้ใช้และธุรกิจที่คัดค้านการแทนที่สามารถเพิกเฉยต่อธุรกรรมที่ยังไม่ได้ยืนยันซึ่งมีสัญญาณ BIP125 จนกว่าจะได้รับการยืนยัน</p>
<p>นโยบายการแทนที่ธุรกรรมสมัยใหม่มีมากกว่าการพิจารณาค่าธรรมเนียมและสัญญาณ sequence ซึ่งเราจะเห็นรายละเอียดเพิ่มเติมในหัวข้อ rbf</p>
<h3>Sequence ในฐานะกลไกกำหนดเวลาล็อกแบบสัมพัทธ์ (relative timelock) ที่ถูกบังคับโดยฉันทามติ</h3>
<p>ในหัวข้อ Version เราได้เรียนรู้ว่า soft fork BIP68 ได้เพิ่มข้อจำกัดใหม่ให้กับธุรกรรมที่มีหมายเลขเวอร์ชัน 2 ขึ้นไป ซึ่งข้อจำกัดนั้นถูกใช้กับฟิลด์ sequence</p>
<p>อินพุตของธุรกรรมที่มีค่า sequence น้อยกว่า 2³¹ จะถูกตีความว่ามีการตั้ง relative timelock และธุรกรรมดังกล่าวจะสามารถถูกบรรจุเข้าไปในบล็อกเชนได้ก็ต่อเมื่อเอาต์พุตก่อนหน้า (ที่ถูกอ้างอิงโดย outpoint) ผ่านระยะเวลาเท่ากับค่าของ relative timelock มาแล้ว ตัวอย่างเช่น ธุรกรรมที่มีอินพุตหนึ่งตัวตั้ง relative timelock ไว้ 30 บล็อก จะสามารถถูกยืนยันในบล็อกที่มีอย่างน้อย 29 บล็อกคั่นอยู่ระหว่างบล็อกนั้นกับบล็อกที่มีเอาต์พุตซึ่งกำลังถูกใช้จ่ายอยู่บนบล็อกเชนเดียวกัน เนื่องจาก sequence เป็นฟิลด์ที่ผูกกับแต่ละอินพุต ธุรกรรมหนึ่งรายการอาจมีอินพุตหลายตัวที่มีการตั้ง timelock และอินพุตทั้งหมดต้องผ่านช่วงเวลาตามที่กำหนดแล้วจึงทำให้ธุรกรรมถือว่าถูกต้อง มี disable flag ที่อนุญาตให้ธุรกรรมสามารถรวมอินพุตแบบมี relative timelock (sequence &lt; 2³¹) และอินพุตที่ไม่มี relative timelock (sequence ≥ 2³¹) ไว้ในธุรกรรมเดียวกันได้</p>
<p>ค่า sequence สามารถกำหนดเป็นหน่วยบล็อกหรือหน่วยวินาทีได้ โดยมี type-flag ใช้แยกความแตกต่างระหว่างค่าที่นับเป็นบล็อกกับค่าที่นับเป็นวินาที type-flag จะถูกตั้งค่าไว้ที่บิตลำดับที่ 23 (กล่าวคือค่า 1&lt;&lt;22) หาก type-flag ถูกตั้งค่า ค่า sequence จะถูกตีความเป็นจำนวนเท่าของ 512 วินาที แต่ถ้า type-flag ไม่ได้ถูกตั้งค่า ค่า sequence จะถูกตีความเป็นจำนวนบล็อก เมื่อทำการตีความ sequence เป็น relative timelock จะพิจารณาเฉพาะ 16 บิตที่มีค่าน้อยที่สุดเท่านั้น เมื่อทำการประเมินค่าสถานะของ flags แล้ว (บิต 32 และบิต 23) ค่า sequence จะถูก “mask” ด้วย mask ขนาด 16 บิต (เช่น sequence &amp; 0x0000FFFF) ค่าหนึ่งเท่าของ 512 วินาทีมีค่าประมาณเท่ากับเวลาเฉลี่ยระหว่างบล็อก ดังนั้นค่า relative timelock สูงสุดจาก 16 บิต (2¹⁶) ทั้งในหน่วยบล็อกและหน่วยวินาที จะมีค่าเกินหนึ่งปีเล็กน้อย</p>
<p>คำจำกัดความของ sequence encoding ตาม BIP68 (ที่มา: BIP68) แสดงผังไบนารีของค่า sequence ตามที่กำหนดใน BIP68<br> <img src="https://image.nostr.build/a19cad6116cdee116a4b577c21c4b4d5861df50e7874d1da00ca9286e25970cf.jpg" alt="image"></p>
<h2>Outputs</h2>
<p>ฟิลด์ outputs ของธุรกรรมประกอบด้วยฟิลด์หลายตัวที่เกี่ยวข้องกับเอาต์พุตแต่ละรายการ เช่นเดียวกับที่เราทำกับฟิลด์ inputs เราจะเริ่มจากการดูไบต์เฉพาะของฟิลด์ outputs จากตัวอย่างธุรกรรมที่ Alice จ่ายให้ Bob ซึ่งถูกแสดงในรูปแบบแผนที่ของไบต์เหล่านั้นในตัวอย่างตอนต้นของบทนี้<br> <img src="https://image.nostr.build/d9e1d6dbe12c88189f42ee36cc478a37039a81fb4cfa13e3efad7e97eb40a5e0.jpg" alt="image"></p>
<h3><strong>Output count (จำนวน Outputs)</strong></h3>
<p>เช่นเดียวกับจุดเริ่มต้นของส่วน inputs ของธุรกรรม ฟิลด์ outputs จะเริ่มต้นด้วยตัวนับที่ระบุจำนวนของ outputs ในธุรกรรมนี้ ซึ่งเป็น compactSize integer และต้องมีค่ามากกว่าศูนย์ โดยธุรกรรมตัวอย่างมีสอง outputs</p>
<h3><strong>Amount(จำนวนเงิน)</strong></h3>
<p>ฟิลด์แรกของ output หนึ่งรายการคือจำนวนเงินของมัน ซึ่งใน Bitcoin Core เรียกว่า “value” เป็น signed integer ขนาด 8 ไบต์ที่ระบุจำนวน satoshis ที่ต้องการโอน (satoshi คือหน่วยที่เล็กที่สุดของ bitcoin ที่สามารถแสดงได้ในธุรกรรมบนบล็อกเชน หนึ่ง bitcoin มี 100 ล้าน satoshis) และในกฎฉันทามติของ Bitcoin อนุญาตให้ output มีค่าตั้งแต่ศูนย์จนถึงสูงสุด 21 ล้าน bitcoins (2.1 quadrillion satoshis)</p>
<h4>Uneconomical outputs and disallowed dust (เอาต์พุตที่ไม่คุ้มค่าเชิงเศรษฐกิจและฝุ่น (dust) ที่ถูกห้าม)</h4>
<p>แม้ว่าจะไม่มีมูลค่า แต่เอาต์พุตที่มีค่าเป็นศูนย์สามารถถูกใช้จ่ายได้ภายใต้กฎเดียวกับเอาต์พุตอื่น ๆ อย่างไรก็ตาม การใช้จ่ายเอาต์พุต (นำมันไปใช้เป็นอินพุตในธุรกรรม) ทำให้ขนาดของธุรกรรมเพิ่มขึ้น ซึ่งทำให้ค่าธรรมเนียมที่ต้องจ่ายเพิ่มขึ้นด้วย หากมูลค่าของเอาต์พุตมีค่าน้อยกว่าค่าธรรมเนียมที่ต้องจ่ายเพิ่ม การใช้จ่ายเอาต์พุตนั้นก็ไม่มีความคุ้มค่าทางเศรษฐกิจ เอาต์พุตเช่นนี้เรียกว่า uneconomical outputs</p>
<p>เอาต์พุตที่มีค่าเป็นศูนย์เป็น uneconomical output เสมอ เพราะมันจะไม่เพิ่มมูลค่าใด ๆ ให้กับธุรกรรมที่ใช้มัน แม้ว่าอัตราค่าธรรมเนียมจะเป็นศูนย์ก็ตาม แต่อย่างไรก็ตาม เอาต์พุตอื่น ๆ ที่มีมูลค่าต่ำก็อาจเป็น uneconomical เช่นกัน แม้จะไม่ได้ตั้งใจ ตัวอย่างเช่น ที่อัตราค่าธรรมเนียมปกติบนเครือข่ายในวันนี้ เอาต์พุตหนึ่งอาจเพิ่มมูลค่ามากกว่าค่าใช้จ่ายในการนำไปใช้ แต่วันพรุ่งนี้อัตราค่าธรรมเนียมอาจสูงขึ้นและทำให้เอาต์พุตนั้นกลายเป็น uneconomical</p>
<p>ความจำเป็นที่ full node ต้องติดตาม UTXO ทั้งหมด ตามที่อธิบายไว้ในหัวข้อ Outpoint หมายความว่า UTXO ทุกตัวทำให้การรัน full node ยากขึ้นเล็กน้อย สำหรับ UTXO ที่มีมูลค่ามาก ผู้ใช้มีแรงจูงใจที่จะใช้จ่ายมันในที่สุด ดังนั้นมันไม่ก่อปัญหา แต่สำหรับผู้ที่ถือ UTXO ที่ไม่คุ้มค่าทางเศรษฐกิจ ไม่มีแรงจูงใจที่จะใช้จ่ายมันเลย ซึ่งอาจทำให้มันกลายเป็นภาระถาวรสำหรับผู้ดูแล full node และเนื่องจากการกระจายศูนย์ของ Bitcoin ขึ้นอยู่กับจำนวนผู้ที่ยินดีรัน full node ซอฟต์แวร์ full node หลาย ๆ ตัว เช่น Bitcoin Core จึงใช้ข้อกำหนดที่ส่งผลต่อการส่งต่อธุรกรรมและการขุดธุรกรรมที่ยังไม่ได้คอนเฟิร์ม เพื่อป้องกันการสร้างเอาต์พุตที่ไม่คุ้มค่าทางเศรษฐกิจ</p>
<p>ข้อกำหนดที่ห้ามการส่งต่อหรือการขุดธุรกรรมที่สร้างเอาต์พุตที่ไม่คุ้มค่าเรียกว่า dust policies ตั้งตามการเปรียบเทียบเชิงสัญลักษณ์ระหว่างเอาต์พุตที่มีมูลค่าน้อยมากกับอนุภาคที่มีขนาดเล็กมาก (เล็กจนเป็นฝุ่น) dust policy ของ Bitcoin Core นั้นซับซ้อนและมีตัวเลขกำหนดหลายค่า ดังนั้นโปรแกรมจำนวนมากมักถือเอาว่าเอาต์พุตที่มีค่าน้อยกว่า 546 satoshis คือ dust และจะไม่ถูกส่งต่อหรือขุดตามค่าตั้งต้น แต่ก็มีบ้างเป็นครั้งคราวที่มีข้อเสนอให้ลดขีดจำกัดของ dust และก็มีข้อเสนอคัดค้านให้เพิ่มขีดจำกัดเช่นกัน ดังนั้นเราขอแนะนำให้นักพัฒนาที่ใช้ presigned transactions หรือโปรโตคอลแบบหลายฝ่าย ตรวจสอบว่าข้อกำหนดนี้มีการเปลี่ยนแปลงตั้งแต่วันที่หนังสือเล่มนี้เผยแพร่หรือไม่</p>
<blockquote>
<p>TIP: ตั้งแต่การกำเนิดของ Bitcoin full node ทุกตัวจำเป็นต้องเก็บสำเนาของ UTXO ทุกตัว แต่สิ่งนี้อาจไม่จำเป็นต้องเป็นเช่นนั้นตลอดไป นักพัฒนาหลายคนกำลังทำงานกับ Utreexo ซึ่งเป็นโปรเจกต์ที่ทำให้โหนดเต็มสามารถเก็บข้อมูลแบบ commitment ต่อชุดของ UTXO แทนการเก็บข้อมูลจริง commitment ที่เล็กที่สุดอาจมีขนาดเพียงหนึ่งหรือสองกิโลไบต์—เทียบกับข้อมูลมากกว่า 5 กิกะไบต์ที่ Bitcoin Core เก็บ ณ เวลาที่เขียนหนังสือนี้ (และตอนที่ผมแปลอยู่ที่ประมาณ 11 GB) </p>
</blockquote>
<blockquote>
<p>อย่างไรก็ตาม Utreexo จะยังคงต้องให้บางโหนดเก็บข้อมูล UTXO ทั้งหมด โดยเฉพาะโหนดที่ให้บริการนักขุดหรือการดำเนินงานอื่น ๆ ที่ต้องตรวจสอบบล็อกใหม่อย่างรวดเร็ว นั่นหมายความว่า uneconomical outputs ก็ยังคงเป็นปัญหาสำหรับ full node แม้ในอนาคตที่เป็นไปได้ซึ่งโหนดส่วนใหญ่ใช้ Utreexo ก็ตาม</p>
</blockquote>
<p>กฎนโยบายของ Bitcoin Core เกี่ยวกับ dust มีข้อยกเว้นหนึ่งข้อ: output script ที่เริ่มต้นด้วย OP_RETURN ซึ่งเรียกว่า data carrier outputs สามารถมีมูลค่าเป็นศูนย์ได้ OP_RETURN opcode ทำให้สคริปต์ล้มเหลวทันทีไม่ว่าจะมีอะไรตามมาหลังจากนั้น ดังนั้นเอาต์พุตเหล่านี้ไม่สามารถถูกใช้จ่ายได้เลย นั่นหมายความว่า full node ไม่จำเป็นต้องติดตามเอาต์พุตเหล่านี้ ซึ่งเป็นคุณสมบัติที่ Bitcoin Core ใช้เพื่อให้ผู้ใช้สามารถจัดเก็บข้อมูลเล็กน้อยตามต้องการลงในบล็อกเชนได้โดยไม่ทำให้ฐานข้อมูล UTXO มีขนาดใหญ่ขึ้น เนื่องจากเอาต์พุตเหล่านี้ไม่สามารถใช้จ่ายได้ จึงไม่ถือว่าเป็น uneconomical แต่ว่า satoshis ใด ๆ ก็ตามที่กำหนดให้กับมันจะกลายเป็นใช้ไม่ได้อย่างถาวร ดังนั้นการอนุญาตให้จำนวนเงินเป็นศูนย์จึงช่วยให้มั่นใจว่า satoshis จะไม่ถูกทำลาย</p>
<h3><strong>Output Scripts</strong></h3>
<p>หลังจากจำนวนเงินของเอาต์พุต จะมี compactSize integer ที่บอกความยาวของ output script ซึ่งเป็นสคริปต์ที่มีเงื่อนไขที่ต้องปฏิบัติตามเพื่อใช้จ่ายบิตคอยน์ ตามกฎฉันทามติของ Bitcoin ขนาดขั้นต่ำของ output script คือศูนย์</p>
<p>ขนาดสูงสุดตามฉันทามติที่อนุญาตของ output script จะแตกต่างกันไปขึ้นอยู่กับช่วงเวลาที่มีการตรวจสอบ ไม่มีขีดจำกัดที่ระบุไว้อย่างชัดเจนสำหรับขนาดของ output script ในเอาต์พุตของธุรกรรม แต่ธุรกรรมถัดไปสามารถใช้จ่ายเอาต์พุตก่อนหน้าได้เฉพาะเมื่อสคริปต์มีขนาด 10,000 ไบต์หรือน้อยกว่าเท่านั้น โดยนัยคือสคริปต์ของเอาต์พุตสามารถมีขนาดใหญ่เกือบเท่ากับตัวธุรกรรมที่บรรจุมันไว้ และธุรกรรมก็สามารถมีขนาดใหญ่เกือบเท่ากับบล็อกที่บรรจุธุรกรรมนั้นไว้</p>
<blockquote>
<p>TIP: output script ที่มีความยาวเป็นศูนย์สามารถถูกใช้จ่ายได้โดย input script ที่มี OP_TRUE อยู่ภายใน โดยใคร ๆ ก็สามารถสร้าง input script แบบนั้นได้ ซึ่งหมายความว่าใครก็สามารถใช้จ่าย output script ที่ว่างเปล่าได้ มีจำนวนสคริปต์แทบไม่จำกัดที่ใครก็สามารถใช้จ่ายได้ และนักพัฒนาโปรโตคอล Bitcoin เรียกสิ่งเหล่านี้ว่า anyone can spends การอัปเกรดภาษาสคริปต์ของ Bitcoin มักจะนำสคริปต์ที่เป็น anyone-can-spend มาเพิ่มเงื่อนไขใหม่เข้าไป ทำให้สามารถใช้จ่ายได้เฉพาะภายใต้เงื่อนไขใหม่เท่านั้น นักพัฒนาแอปพลิเคชันไม่ควรจำเป็นต้องใช้ anyone-can-spend script เลย แต่หากคุณจำเป็นต้องใช้ เราขอแนะนำอย่างยิ่งให้ประกาศแผนของคุณอย่างชัดเจนต่อผู้ใช้และนักพัฒนา Bitcoin เพื่อไม่ให้การอัปเกรดในอนาคตไปรบกวนระบบของคุณโดยไม่ตั้งใจ</p>
</blockquote>
<p>นโยบายของ Bitcoin Core สำหรับการรีเลย์และการขุดธุรกรรม จะจำกัด output script ให้เหลือเพียงไม่กี่รูปแบบ ซึ่งเรียกว่า standard transaction outputs การจำกัดนี้ถูกนำมาใช้ครั้งแรกหลังจากค้นพบบั๊กในยุคแรกของ Bitcoin ที่เกี่ยวข้องกับภาษา Script และยังถูกคงไว้ใน Bitcoin Core ยุคปัจจุบันเพื่อรองรับการอัปเกรดแบบ anyone-can-spend และเพื่อส่งเสริมแนวทางที่ดีที่สุดในการวางเงื่อนไขสคริปต์ไว้ใน P2SH redeem scripts, segwit v0 witness scripts และ segwit v1 (taproot) leaf scripts เราจะดูแต่ละรูปแบบของ standard transaction templates ในปัจจุบัน และเรียนรู้วิธีการ parse สคริปต์ในบทถัดไป</p>
<h3>Witness Structure</h3>
<p>ในศาล “พยาน” คือบุคคลที่ให้การว่าตนเห็นเหตุการณ์สำคัญบางอย่างเกิดขึ้น พยานมนุษย์ไม่ใช่สิ่งที่เชื่อถือได้เสมอไป ดังนั้นศาลจึงมีขั้นตอนต่าง ๆ สำหรับการสอบสวนพยานเพื่อ (อย่างน้อยก็ในอุดมคติ) รับหลักฐานเฉพาะจากผู้ที่เชื่อถือได้เท่านั้น </p>
<p>ลองจินตนาการว่าถ้ามี “พยาน” สำหรับโจทย์คณิตศาสตร์จะมีหน้าตาอย่างไร ตัวอย่างเช่น หากปัญหาสำคัญคือ x + 2 == 4 และมีใครสักคนอ้างว่าตนเป็นพยานที่เห็นวิธีแก้ เราจะถามอะไรพวกเขา? เราต้องการ “หลักฐานทางคณิตศาสตร์” ที่แสดงค่าหนึ่งที่สามารถนำมาบวกกับ 2 แล้วได้ 4 เราอาจตัดความจำเป็นของการมีบุคคลออกไปเลย และใช้ “ค่าที่เสนอให้เป็น x” นั้นเป็นพยานแทนก็ได้ หากเราถูกบอกว่าพยานคือ 2 เราก็สามารถแทนค่าในสมการ ตรวจสอบว่าถูกต้อง และสรุปว่าปัญหาสำคัญนั้นได้รับการแก้ไขแล้ว </p>
<p>เมื่อมีการใช้จ่ายบิตคอยน์ ปัญหาสำคัญที่เราต้องการแก้คือ “การยืนยันว่าการใช้จ่ายนั้นได้รับอนุญาตจากบุคคลหรือกลุ่มบุคคลที่ควบคุมบิตคอยน์เหล่านั้นจริงหรือไม่” โหนดเต็มนับพันที่บังคับใช้กฎฉันทามติของบิตคอยน์ไม่สามารถสอบสวนพยานมนุษย์ได้ แต่พวกมันสามารถรับ “พยาน” ที่ประกอบด้วยข้อมูลล้วน ๆ สำหรับแก้ปัญหาทางคณิตศาสตร์ได้ ตัวอย่างเช่น พยานที่เป็นค่า 2 จะทำให้สามารถใช้จ่ายบิตคอยน์ที่ถูกป้องกันด้วยสคริปต์ต่อไปนี้ได้:</p>
<pre><code>2 OP_ADD 4 OP_EQUAL
</code></pre>
<p>แน่นอนว่า การอนุญาตให้บิตคอยน์ของคุณถูกใช้จ่ายโดยใครก็ตามที่สามารถแก้สมการง่าย ๆ ได้ย่อมไม่ปลอดภัย อย่างที่เราจะเห็นในบทที่ 8 กลไกการลงนามดิจิทัลที่ปลอมแปลงไม่ได้ (unforgeable digital signature scheme) ใช้สมการที่สามารถถูกแก้ได้โดยเฉพาะผู้ที่ครอบครองข้อมูลบางอย่างซึ่งพวกเขาสามารถเก็บไว้เป็นความลับได้ พวกเขาสามารถอ้างอิงข้อมูลลับนั้นโดยใช้ตัวระบุสาธารณะ ซึ่งตัวระบุดังกล่าวเรียกว่า public key และคำตอบของสมการนั้นเรียกว่า signature</p>
<p>สคริปต์ต่อไปนี้มี public key และ opcode ที่ต้องการ signature ที่สอดคล้องกันเพื่อ commit กับข้อมูลในธุรกรรมที่กำลังใช้จ่าย เช่นเดียวกับตัวเลข 2 ในตัวอย่างง่าย ๆ ของเรา signature คือพยานของเรา:</p>
<pre><code>&lt;public key&gt; OP_CHECKSIG
</code></pre>
<p>พยาน (witnesses) ซึ่งเป็นค่าที่ใช้ในการแก้ปัญหาทางคณิตศาสตร์ที่ปกป้องบิตคอยน์ จำเป็นต้องถูกใส่รวมอยู่ในธุรกรรมที่ใช้มัน เพื่อให้โหนดเต็มสามารถตรวจสอบได้ ในรูปแบบธุรกรรมแบบดั้งเดิม (legacy transaction format) ที่ใช้ในธุรกรรมบิตคอยน์ยุคแรก ๆ ทั้งหมดนั้น ลายเซ็นและข้อมูลอื่น ๆ ถูกวางไว้ในฟิลด์ input script อย่างไรก็ตาม เมื่อผู้พัฒนาเริ่มนำโปรโตคอลสัญญาต่าง ๆ มาใช้บนบิตคอยน์ เช่นที่เราเห็นใน Original sequence-based transaction replacement พวกเขาค้นพบปัญหาที่สำคัญหลายประการเกี่ยวกับการใส่พยานไว้ในฟิลด์ input script</p>
<h4>Circular Dependencies</h4>
<p>โปรโตคอลสัญญาหลายอย่างสำหรับบิตคอยน์เกี่ยวข้องกับชุดของธุรกรรมที่ถูกเซ็นนอกลำดับ ตัวอย่างเช่น Alice และ Bob ต้องการฝากเงินเข้าไปในสคริปต์ที่สามารถใช้จ่ายได้ด้วยลายเซ็นของทั้งคู่ แต่พวกเขาก็ต้องการให้สามารถได้เงินคืนได้หากอีกฝ่ายหนึ่งไม่ตอบสนอง วิธีแก้ปัญหาอย่างง่ายคือการเซ็นธุรกรรมนอกลำดับ:</p>
<ul>
<li>Tx0 จ่ายเงินจาก Alice และเงินจาก Bob ไปยังเอาต์พุตที่มีสคริปต์ที่ต้องการลายเซ็นจากทั้ง Alice และ Bob เพื่อที่จะใช้จ่ายได้  </li>
<li>Tx1 ใช้จ่ายเอาต์พุตก่อนหน้าไปยังสองเอาต์พุต—หนึ่งคืนเงินให้ Alice และอีกหนึ่งคืนเงินให้ Bob (หักจำนวนเล็กน้อยเป็นค่าธรรมเนียมธุรกรรม)  </li>
<li>หาก Alice และ Bob เซ็น Tx1 ก่อนที่พวกเขาจะเซ็น Tx0 พวกเขาทั้งคู่ก็จะมั่นใจได้ว่าจะรับเงินคืนได้ทุกเมื่อ โปรโตคอลนี้ไม่ต้องการให้ฝ่ายหนึ่งไว้ใจอีกฝ่ายหนึ่ง ทำให้มันเป็นโปรโตคอลแบบ trustless</li>
</ul>
<p>ปัญหาของโครงสร้างนี้ในรูปแบบธุรกรรมแบบดั้งเดิมคือทุกฟิลด์ รวมถึงฟิลด์ input script ที่มีลายเซ็น จะถูกใช้ในการสร้างตัวระบุของธุรกรรม (txid) ค่า txid ของ Tx0 เป็นส่วนหนึ่งของ outpoint ของอินพุตใน Tx1 นั่นหมายความว่าไม่มีทางที่ Alice และ Bob จะสร้าง Tx1 ได้จนกว่าจะทราบลายเซ็นทั้งสองของ Tx0 — แต่ถ้าพวกเขารู้ลายเซ็นของ Tx0 หนึ่งในนั้นสามารถออกอากาศธุรกรรมนั้นก่อนที่จะเซ็นธุรกรรมคืนเงิน ทำให้การรับประกันการคืนเงินถูกลบล้างไป นี่คือปัญหา circular dependency</p>
<h4>Third-Party Transaction Malleability (การเปลี่ยนแปลงธุรกรรมโดยบุคคลที่สาม)</h4>
<p>ลำดับธุรกรรมที่ซับซ้อนกว่าสามารถแก้ปัญหา circular dependency ได้ในบางครั้ง แต่โปรโตคอลจำนวนมากจะพบกับความกังวลใหม่: มักจะสามารถแก้สคริปต์เดียวกันได้หลายวิธี ตัวอย่างเช่น พิจารณาสคริปต์แบบง่ายของเราจากหัวข้อ Witness Structure:</p>
<pre><code>2 OP_ADD 4 OP_EQUAL
</code></pre>
<p>เราสามารถทำให้สคริปต์นี้ผ่านได้โดยการใส่ค่า 2 ลงใน input script แต่มีหลายวิธีที่จะวางค่านั้นลงบนสแตกในบิตคอยน์ ต่อไปนี้คือเพียงบางตัวอย่าง:</p>
<pre><code>OP_2
OP_PUSH1 0x02
OP_PUSH2 0x0002
OP_PUSH3 0x000002
...
OP_PUSHDATA1 0x0102
OP_PUSHDATA1 0x020002
...
OP_PUSHDATA2 0x000102
OP_PUSHDATA2 0x00020002
...
OP_PUSHDATA4 0x0000000102
OP_PUSHDATA4 0x000000020002
...
</code></pre>
<p>แต่ละรูปแบบการเข้ารหัสของตัวเลข 2 ใน input script จะสร้างธุรกรรมที่แตกต่างกันเล็กน้อย พร้อมกับ txid ที่แตกต่างกันอย่างสิ้นเชิง แต่ละเวอร์ชันของธุรกรรมจะใช้จ่ายอินพุต (outpoints) เดียวกันกับทุกเวอร์ชันอื่น ๆ ทำให้พวกมันขัดแย้งกันเอง ทั้งหมดนี้ทำให้มีเพียงหนึ่งเวอร์ชันจากชุดของธุรกรรมที่ขัดแย้งกันเท่านั้นที่สามารถอยู่ในบล็อกเชนที่ถูกต้องได้</p>
<p>ลองนึกภาพว่ามีครั้งหนึ่ง Alice สร้างเวอร์ชันของธุรกรรมที่มี OP_2 ใน input script และมี output ที่จ่ายให้ Bob จากนั้น Bob ก็ใช้จ่าย output นั้นต่อให้ Carol ทันที บุคคลใดก็ตามบนเครือข่ายสามารถแทนที่ OP_2 ด้วย OP_PUSH1 0x02 ทำให้เกิดธุรกรรมที่ขัดแย้งกับเวอร์ชันต้นฉบับของ Alice หากธุรกรรมที่ขัดแย้งนั้นถูกยืนยัน ก็จะไม่มีทางรวมเวอร์ชันต้นฉบับของ Alice เข้าไปในบล็อกเชนเดียวกันได้ ซึ่งหมายความว่าไม่มีทางที่ธุรกรรมของ Bob จะใช้จ่าย output ของมันได้ การจ่ายเงินของ Bob ให้ Carol จึงกลายเป็นโมฆะ ทั้งที่ Alice, Bob หรือ Carol ไม่ได้ทำอะไรผิดเลย คนที่ไม่ได้เกี่ยวข้องกับธุรกรรม (บุคคลที่สาม) สามารถเปลี่ยนแปลง (mutate) ธุรกรรมของ Alice ได้ ซึ่งเป็นปัญหาที่เรียกว่า unwanted third-party transaction malleability</p>
<blockquote>
<p>TIP: มีหลายกรณีที่ผู้คนต้องการให้ธุรกรรมของพวกเขาถูกดัดแปลงได้ (malleable) และบิตคอยน์ก็มีฟีเจอร์หลายอย่างรองรับสิ่งนี้ โดยเฉพาะ signature hashes (sighash) ที่เราจะได้เรียนรู้ใน [sighash_types] ตัวอย่างเช่น Alice สามารถใช้ sighash เพื่อให้ Bob ช่วยจ่ายค่าธรรมเนียมบางส่วนได้ ซึ่งทำให้ธุรกรรมของ Alice ถูกเปลี่ยนแปลง แต่เป็นการเปลี่ยนแปลงในแบบที่ Alice ต้องการ ด้วยเหตุนี้เราจะใส่คำว่า unwanted นำหน้าคำว่า transaction malleability ในบางครั้ง แม้ว่าเราหรือผู้เขียนเทคนิคบิตคอยน์คนอื่น ๆ จะใช้คำเวอร์ชันสั้น เราก็กำลังพูดถึงรูปแบบของ malleability ที่ไม่พึงประสงค์แทบทุกครั้ง</p>
</blockquote>
<h4>Second-Party Transaction Malleability(ผู้ร่วมธุรกรรมอีกฝ่าย)</h4>
<p>เมื่อรูปแบบธุรกรรมแบบดั้งเดิม (legacy transaction format) เป็นรูปแบบเดียวที่มีให้ใช้ นักพัฒนาก็ทำงานบนข้อเสนอเพื่อลดปัญหา third-party malleability เอาไว้อย่างเช่น BIP62 แต่อย่างไรก็ตาม แม้ว่าจะสามารถกำจัด third-party malleability ได้ทั้งหมด ผู้ใช้งานโปรโตคอลแบบสัญญา (contract protocols) ก็ยังพบปัญหาอีกแบบหนึ่ง คือถ้าต้องใช้ลายเซ็นของอีกฝ่ายหนึ่งที่อยู่ในโปรโตคอล ฝ่ายนั้นสามารถสร้างลายเซ็นทางเลือกขึ้นมาและเปลี่ยน txid ได้</p>
<p>ตัวอย่างเช่น Alice และ Bob ฝากเงินของพวกเขาเข้าไปในสคริปต์ที่ต้องการลายเซ็นของทั้งคู่เพื่อใช้จ่าย พวกเขายังสร้าง "ธุรกรรมคืนเงิน" (refund transaction) ที่จะให้ทั้งสองฝ่ายสามารถดึงเงินกลับได้ทุกเมื่อ และต่อมา Alice ต้องการใช้เงินบางส่วน เธอจึงร่วมมือกับ Bob สร้างลำดับธุรกรรมดังนี้:</p>
<ul>
<li>Tx0 รวมลายเซ็นจาก Alice และ Bob และใช้จ่ายบิตคอยน์ไปยังสอง output โดย output แรกจ่ายเงินบางส่วนให้ Alice และอีกอัน คืนเงินส่วนที่เหลือกลับเข้าไปยังสคริปต์เดิม ซึ่งยังคงต้องใช้ลายเซ็นของทั้ง Alice และ Bob แน่นอนว่าก่อนที่พวกเขาจะเซ็น Tx0 พวกเขาสร้างธุรกรรมคืนเงินชุดใหม่ Tx1  </li>
<li>Tx1 ใช้จ่าย output ที่สองของ Tx0 ไปยังสอง output ใหม่—หนึ่งให้ Alice ตามส่วนแบ่งของเธอ และอีกหนึ่งให้ Bob ตามส่วนแบ่งของเขา Alice และ Bob ต่างเซ็น Tx1 เสร็จก่อนที่จะเซ็น Tx0</li>
</ul>
<p>ตรงนี้ไม่มี circular dependency และถ้าเรามองข้าม third-party malleability ก็จะดูเหมือนเป็นโปรโตคอลที่ไม่ต้องเชื่อใจใคร (trustless) ได้ แต่ปัญหาคือ คุณสมบัติของลายเซ็นบิตคอยน์มีความสุ่มโดยธรรมชาติ —ผู้เซ็นต้องเลือกตัวเลขสุ่มขนาดใหญ่ทุกครั้งที่สร้างลายเซ็น หากเลือกเลขสุ่มต่างกัน ลายเซ็นที่ได้ก็จะต่างกัน แม้ข้อมูลที่ถูกเซ็นจะเหมือนเดิมทั้งหมดก็ตาม คล้ายกับการที่คุณเซ็นชื่อบนสัญญาเหมือนกันสองชุด ลายเซ็นจริง ๆ บนกระดาษทั้งสองแผ่นก็ไม่เหมือนกัน 100%</p>
<p>ความสามารถในการถูกดัดแปลงของลายเซ็นนี้ เป็นช่องให้ Bob สร้างธุรกรรมที่ขัดแย้งกับ Tx0 ได้ หาก Alice พยายามประกาศ Tx0 (ซึ่งมีลายเซ็นของ Bob อยู่) Bob สามารถสร้างลายเซ็นใหม่ที่แตกต่างออกมา ผลิต Tx0 เวอร์ชันใหม่ที่มี txid แตกต่างกันขึ้นมาได้ ถ้า Tx0 เวอร์ชันที่ Bob เปลี่ยนแปลงถูกยืนยันขึ้นมา Alice จะไม่สามารถใช้ Tx1 ที่ลงนามไว้ล่วงหน้าเพื่อรับเงินคืนของเธอได้ เพราะ Tx1 อ้างอิง txid เดิมของ Tx0 ซึ่งไม่ตรงกับเวอร์ชันที่ถูกยืนยัน พฤติกรรมแบบนี้เรียกว่า unwanted second-party transaction malleability คือการที่อีกฝ่ายในโปรโตคอลสามารถดัดแปลงธุรกรรมให้เปลี่ยน txid ได้โดยไม่ต้องร่วมมือกับคุณ</p>
<h4>Segregated Witness(การแยกพยานออกจากธุรกรรม)</h4>
<p>ตั้งแต่ช่วงต้นปี 2011 นักพัฒนาระบบโปรโตคอลของบิตคอยน์ก็ทราบวิธีแก้ปัญหา circular dependence, third-party malleability, และ second-party malleability แล้ว แนวคิดคือการหลีกเลี่ยงไม่ให้นำ input script มารวมอยู่ในการคำนวณที่ใช้สร้าง txid ของธุรกรรม จำได้ว่า ชื่อเชิงนามธรรมสำหรับข้อมูลที่อยู่ใน input script คือคำว่า witness แนวคิดในการแยกข้อมูลส่วนอื่น ๆ ของธุรกรรมออกจาก witness เพื่อใช้ในการสร้าง txid นี้ เรียกว่า segregated witness (segwit)</p>
<p>วิธีที่ตรงไปตรงมาที่สุดในการทำให้ segwit ใช้งานได้จริงนั้น ต้องมีการเปลี่ยนแปลงกฎ consensus ของบิตคอยน์ในลักษณะที่ ไม่สามารถเข้ากันได้กับ full node รุ่นเก่า หรือที่เรียกว่า hard fork Hard fork นั้นมาพร้อมกับความท้าทายจำนวนมาก ซึ่งเราจะอธิบายเพิ่มเติมในส่วน hardfork</p>
<p>แนวทางทางเลือกสำหรับ segwit ถูกอธิบายไว้ในช่วงปลายปี 2015 แนวทางนี้ใช้การเปลี่ยนแปลงกฎ consensus แบบ เข้ากันได้ย้อนหลัง (backward-compatible) ซึ่งเรียกว่า soft fork คำว่า “เข้ากันได้ย้อนหลัง” หมายความว่า full node ที่ใช้กฎใหม่จะต้อง ไม่ยอมรับบล็อกใด ๆ ที่ full node รุ่นเก่ามองว่าไม่ถูกต้อง ตราบเท่าที่พวกเขาปฏิบัติตามกฎนั้น full node รุ่นใหม่จึงสามารถ ปฏิเสธบล็อกที่ full node รุ่นเก่ายอมรับได้ ซึ่งทำให้พวกเขาสามารถบังคับใช้กฎ consensus ใหม่ได้ (แต่มีเงื่อนไขว่า full node รุ่นใหม่เหล่านั้นจะต้อง เป็นตัวแทนของฉันทามติทางเศรษฐกิจของผู้ใช้บิตคอยน์ด้วย—เราจะสำรวจรายละเอียดเกี่ยวกับการอัปเกรดกฎ consensus ของบิตคอยน์ในส่วนของ mining</p>
<p>การใช้ซอฟต์ฟอร์กแบบเซกวิทอาศัยแนวคิดเอาต์พุตสคริปต์แบบ “anyone-can-spend” เป็นพื้นฐาน สคริปต์ที่ขึ้นต้นด้วยตัวเลขตั้งแต่ 0 ถึง 16 และตามด้วยข้อมูลขนาด 2 ถึง 40 ไบต์ ถูกกำหนดให้เป็นแม่แบบเอาต์พุตสคริปต์ของเซกวิท ตัวเลขนั้นคือหมายเลขเวอร์ชันของเซกวิท (เช่น 0 คือเซกวิทเวอร์ชัน 0 หรือ segwit v0) ส่วนข้อมูลที่ตามมานั้นเรียกว่า witness program นอกจากนี้ยังสามารถนำแม่แบบเซกวิทไปห่อด้วยคอมมิตเมนต์แบบ P2SH ได้ แต่ในบทนี้เราจะยังไม่กล่าวถึง</p>
<p>จากมุมมองของโหนดเก่า เอาต์พุตสคริปต์แม่แบบเหล่านี้สามารถถูกใช้จ่ายด้วย input script ที่ว่างเปล่าได้ จากมุมมองของโหนดใหม่ที่รู้กฎของเซกวิท การใช้จ่ายเอาต์พุตที่เป็นแม่แบบเซกวิทต้องใช้ input script ที่ว่างเปล่าเท่านั้น สังเกตความแตกต่าง: โหนดเก่า “อนุญาต” ให้ใช้สคริปต์ว่างเปล่า ส่วนโหนดใหม่ “กำหนด” ให้ต้องเป็นสคริปต์ว่างเปล่า</p>
<p>การใช้ input script ว่างเปล่าทำให้ข้อมูลพยานไม่ไปกระทบกับ txid ช่วยกำจัดปัญหาการพึ่งพาวนซ้ำ การเปลี่ยนแปลงธุรกรรมโดยบุคคลที่สาม และการเปลี่ยนแปลงธุรกรรมโดยคู่สัญญา แต่เมื่อไม่สามารถใส่ข้อมูลใด ๆ ใน input script ได้ ผู้ใช้แม่แบบเอาต์พุตเซกวิทจึงต้องมีฟิลด์ใหม่ ฟิลด์นี้คือโครงสร้างพยาน (witness structure)</p>
<p>การเกิดขึ้นของ witness programs และ witness structure ทำให้บิตคอยน์ซับซ้อนขึ้น แต่สิ่งนี้ก็สอดคล้องกับแนวโน้มที่มีอยู่แล้วของการเพิ่มระดับนามธรรมในระบบบิตคอยน์ จากที่กล่าวไว้ในบทที่ 4 ว่าไวท์เปเปอร์บิตคอยน์ดั้งเดิมอธิบายระบบที่บิตคอยน์ถูก “รับ” ไปยัง public keys (pubkeys) และถูก “ใช้จ่าย” ด้วย signatures (sigs) pubkey ระบุว่าใครได้รับอนุญาตให้ใช้จ่ายบิตคอยน์ (คือผู้ที่ควบคุม private key ที่สอดคล้องกัน) และลายเซ็นเป็นการตรวจสอบว่าธุรกรรมการใช้จ่ายนั้นมาจากผู้ที่ควบคุม private key จริง ๆ เพื่อทำให้ระบบนั้นยืดหยุ่นขึ้น รุ่นแรกสุดของบิตคอยน์ได้แนะนำ scripts ซึ่งอนุญาตให้รับบิตคอยน์ไปยัง output scripts และใช้จ่ายด้วย input scripts ประสบการณ์ภายหลังจากการใช้งานโปรโตคอลสัญญาต่าง ๆ ได้นำไปสู่การอนุญาตให้รับบิตคอยน์ไปยัง witness programs และใช้จ่ายด้วย witness structure คำต่าง ๆ และฟิลด์ที่ถูกใช้ในเวอร์ชันต่าง ๆ ของบิตคอยน์ถูกแสดงไว้ในตารางข้างล่างนี้</p>
<table>
<thead>
<tr>
<th></th>
<th>Authorization</th>
<th>Authentication</th>
</tr>
</thead>
<tbody><tr>
<td>Whitepaper</td>
<td>Public key</td>
<td>Signature</td>
</tr>
<tr>
<td>Original (Legacy)</td>
<td>Output script</td>
<td>Input script</td>
</tr>
<tr>
<td>Segwit</td>
<td>Witness program</td>
<td>Witness structure</td>
</tr>
</tbody></table>
<h4>Witness Structure Serialization</h4>
<p>เช่นเดียวกับฟิลด์ inputs และ outputs, witness structure ก็มีฟิลด์ย่อยอื่น ๆ อยู่ภายใน ดังนั้นเราจะเริ่มต้นด้วยแผนที่ไบต์ (byte map) ของข้อมูลเหล่านั้นจากธุรกรรมของ Alice ซึ่งแสดงอยู่ในรูปด้านล่าง</p>
<p> <img src="https://image.nostr.build/d5c8cf4712e321ee4a37fa93b0a5c12364a7f321c6655a035ce56a20e3d9367e.jpg" alt="image"></p>
<p>ต่างจากฟิลด์ inputs และ outputs ตรงที่ witness structure โดยรวมจะไม่เริ่มต้นด้วยตัวบ่งชี้จำนวนของ witness stack ทั้งหมดที่มีอยู่ แต่จำนวนดังกล่าวถูกกำหนดโดยฟิลด์ inputs—กล่าวคือ ธุรกรรมหนึ่งรายการจะมีหนึ่ง witness stack ต่อหนึ่ง input เสมอ</p>
<p>สำหรับ witness structure ของแต่ละ input จะเริ่มต้นด้วยตัวนับจำนวนขององค์ประกอบที่อยู่ภายใน ซึ่งองค์ประกอบเหล่านี้เรียกว่า witness items เราจะศึกษารายละเอียดของมันในภายหลังในบทต่อไป แต่ตอนนี้สิ่งที่ต้องรู้คือ witness item แต่ละรายการจะถูกนำหน้าด้วย compactSize integer ที่ระบุขนาดของมัน</p>
<p>สำหรับ legacy inputs จะไม่มี witness items อยู่เลย ดังนั้น witness stack ของมันประกอบด้วยค่า 0 เพียงค่าเดียว (0x00)</p>
<p>ธุรกรรมของ Alice มี input หนึ่งรายการ และมี witness item หนึ่งรายการ</p>
<h3>Lock Time</h3>
<p>ฟิลด์สุดท้ายในธุรกรรมที่ถูกซีเรียลไลซ์คือ lock time ฟิลด์นี้เป็นส่วนหนึ่งของรูปแบบการซีเรียลไลซ์ดั้งเดิมของบิตคอยน์ แต่ในช่วงแรกมีผลเฉพาะกับนโยบายการเลือกธุรกรรมเข้าสู่บล็อกของบิตคอยน์เท่านั้น</p>
<p>ซอฟต์ฟอร์กที่บันทึกได้เป็นครั้งแรกของบิตคอยน์ได้เพิ่มกฎใหม่ว่า เริ่มตั้งแต่บล็อกหมายเลข 31,000 เป็นต้นไป ห้ามรวมธุรกรรมในบล็อก เว้นแต่ธุรกรรมนั้นจะเป็นไปตามหนึ่งในกฎต่อไปนี้:</p>
<ul>
<li>ธุรกรรมระบุว่า สามารถถูกรวมในบล็อกใดก็ได้ โดยตั้งค่า lock time เป็น 0  </li>
<li>ธุรกรรมระบุว่าต้องการจำกัดว่าบล็อกใดที่สามารถรวมมันได้ โดยตั้งค่า lock time ให้มีค่าต่ำกว่า 500,000,000 ในกรณีนี้ ธุรกรรมสามารถถูกบรรจุได้เฉพาะในบล็อกที่มีความสูงของบล็อก (block height) เท่ากับ lock time หรือมากกว่า ตัวอย่างเช่น ธุรกรรมที่มี lock time เป็น 123,456 สามารถอยู่ในบล็อก 123,456 หรือบล็อกใดที่สูงกว่า  </li>
<li>ธุรกรรมระบุว่าต้องการจำกัดเวลาที่สามารถถูกบรรจุเข้าสู่บล็อกเชนได้ โดยตั้งค่า lock time ให้มีค่า 500,000,000 หรือมากกว่า ในกรณีนี้ lock time จะถูกตีความเป็นเวลาตาม epoch time (จำนวนวินาทีตั้งแต่ 1970-01-01T00:00 UTC) ธุรกรรมจะถูกบรรจุได้เฉพาะในบล็อกที่มี median time past (MTP) มากกว่า lock time โดยทั่วไป MTP จะช้ากว่าเวลาปัจจุบันประมาณหนึ่งถึงสองชั่วโมง กฎของ MTP อธิบายไว้ในส่วนของ mtp</li>
</ul>
<h2><strong>Coinbase Transactions</strong></h2>
<p>ธุรกรรมแรกในทุกบล็อกเป็นกรณีพิเศษ เอกสารรุ่นเก่าหลายฉบับเรียกธุรกรรมนี้ว่า generation transaction แต่เอกสารรุ่นใหม่ส่วนใหญ่เรียกว่า coinbase transaction (ไม่เกี่ยวข้องกับธุรกรรมที่สร้างโดยบริษัทชื่อ “Coinbase”)</p>
<p>Coinbase transactions ถูกสร้างขึ้นโดยนักขุดที่ขุดบล็อกนั้น และเปิดโอกาสให้นักขุดสามารถรับ ค่าธรรมเนียม (fees) ทั้งหมดจากธุรกรรมที่อยู่ในบล็อกนั้นได้ นอกจากนี้ จนถึงบล็อกหมายเลข 6,720,000 นักขุดยังสามารถรับ subsidy ซึ่งเป็นบิตคอยน์ที่ถูกสร้างขึ้นใหม่และไม่เคยหมุนเวียนมาก่อน เรียกว่า block subsidy จำนวนรวมที่นักขุดสามารถรับได้จากบล็อกหนึ่ง ๆ — ประกอบด้วยค่าธรรมเนียมและ block subsidy — เรียกว่า block reward</p>
<p>พฤติกรรมพิเศษบางประการของ coinbase transactions มีดังนี้:</p>
<ul>
<li>ธุรกรรม coinbase สามารถมีอินพุตได้เพียงหนึ่งรายการเท่านั้น  </li>
<li>อินพุตเพียงรายการนั้นต้องมี outpoint ที่มี txid เป็นค่าว่าง (ศูนย์ทั้งหมด) และมี output index สูงสุด (0xffffffff) สิ่งนี้ทำให้ coinbase transaction ไม่สามารถอ้างอิงเอาต์พุตของธุรกรรมก่อนหน้า ซึ่งจะสร้างความสับสนเพราะ coinbase transaction มีหน้าที่จ่ายค่าธรรมเนียมและ subsidy  </li>
<li>ฟิลด์ที่โดยปกติจะเป็น input script จะถูกเรียกว่า coinbase ในธุรกรรมประเภทนี้ และนี่คือที่มาของชื่อ coinbase transaction ฟิลด์ coinbase ต้องมีความยาวอย่างน้อย 2 ไบต์ และต้องไม่เกิน 100 ไบต์ สคริปต์นี้ ไม่ถูกประมวลผล แต่ยังคงอยู่ภายใต้กฎจำกัดจำนวน sigops แบบ legacy ดังนั้นข้อมูลใด ๆ ที่ใส่เข้าไปควรถูกนำหน้าด้วย opcode สำหรับการ push data นอกจากนี้ ตั้งแต่ soft fork ปี 2013 (BIP34) ไบต์แรก ๆ ของฟิลด์นี้ต้องปฏิบัติตามกฎเพิ่มเติม ซึ่งจะอธิบายทีหลัง  </li>
<li>ผลรวมของค่าเอาต์พุตทั้งหมดต้องไม่เกินค่าธรรมเนียมจากธุรกรรมทั้งหมดในบล็อกนั้นรวมกับ subsidy โดย subsidy เริ่มต้นที่ 50 BTC ต่อบล็อก และลดลงครึ่งหนึ่งทุก 210,000 บล็อก (ประมาณทุก 4 ปี) โดยปัดเศษลงถึง satoshi ที่ใกล้ที่สุด  </li>
<li>ตั้งแต่ soft fork segwit ปี 2017 (BIP141) บล็อกใดก็ตามที่มีธุรกรรมใช้จ่าย segwit output ต้องมีเอาต์พุตใน coinbase transaction ที่เป็นการ commit ถึงธุรกรรมทั้งหมดในบล็อก (รวมถึง witness ด้วย) รายละเอียดจะอธิบายในส่วน mining</li>
</ul>
<p>coinbase transaction สามารถมีเอาต์พุตอื่น ๆ ที่ถูกต้องตามกฎเหมือนธุรกรรมทั่วไปได้ อย่างไรก็ตาม ธุรกรรมที่ใช้จ่ายเอาต์พุตของ coinbase จะไม่สามารถใส่ในบล็อกได้จนกว่าธุรกรรมนั้นจะมีอย่างน้อย 100 confirmations สิ่งนี้เรียกว่า maturity rule และเอาต์พุตของ coinbase ที่ยังไม่ถึง 100 confirmations จะถูกเรียกว่า immature แต่เนื่องจากลักษณะพิเศษของมัน ทำให้บางครั้งอาจเป็นสาเหตุของปัญหาที่ไม่คาดคิดในซอฟต์แวร์ที่ไม่ได้ออกแบบมาเพื่อรองรับกรณีเหล่านี้</p>
<h2><strong>Weight and Vbytes</strong></h2>
<p>แต่ละบล็อกของบิตคอยน์มีข้อจำกัดปริมาณข้อมูลธุรกรรมที่บรรจุได้ ดังนั้นซอฟต์แวร์บิตคอยน์ส่วนใหญ่จึงต้องสามารถวัดขนาดของธุรกรรมที่สร้างหรือประมวลผลได้ หน่วยวัดสมัยใหม่ที่ใช้คือ weight อีกหน่วยหนึ่งคือ vbytes ซึ่งคำนวณจากการนำ weight มาหารด้วยสี่ ทำให้สามารถเทียบกับหน่วยไบต์ในบล็อกแบบดั้งเดิมได้ง่ายขึ้น</p>
<p>ขนาดสูงสุดของบล็อกคือ <strong>4 ล้าน weight</strong> ส่วน <strong>block header</strong> ใช้พื้นที่ไป 240 weight และช่องข้อมูล <strong>transaction count</strong> ใช้อีก 4 หรือ 12 weight พื้นที่ที่เหลือทั้งหมดสามารถใช้สำหรับข้อมูลธุรกรรมได้</p>
<p>การคำนวณ weight ของฟิลด์หนึ่ง ๆ ในธุรกรรมทำได้โดยการนำจำนวนไบต์ของฟิลด์ที่ serialize แล้วไปคูณกับตัวคูณเฉพาะฟิลด์นั้น ๆ จากนั้นเมื่อต้องการหาน้ำหนักรวมของธุรกรรม ก็เพียงนำ weight ของทุกฟิลด์มาบวกกัน ตัวคูณสำหรับแต่ละฟิลด์ถูกระบุไว้ในตารางข้างล่างนี้ นอกจากนี้ยังมีตัวอย่างการคำนวณ weight ของแต่ละฟิลด์ในธุรกรรมตัวอย่างของบทนี้ (ธุรกรรมจาก Alice ไปยัง Bob)</p>
<p>ตัวคูณเหล่านี้ รวมถึงฟิลด์ที่เกี่ยวข้อง ถูกออกแบบมาเพื่อลดน้ำหนักเมื่อมีการใช้ UTXO ช่วยลดแรงจูงใจในการสร้างเอาต์พุตที่ไม่คุ้มค่า (uneconomical outputs) และหลีกเลี่ยงปัญหา dust ที่ไม่เหมาะสมตามที่อธิบายไว้ในหัวข้อ Uneconomical outputs and disallowed dust</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Factor</th>
<th>Weight in Alice’s Tx</th>
</tr>
</thead>
<tbody><tr>
<td>Version</td>
<td>4</td>
<td>16</td>
</tr>
<tr>
<td>Marker &amp; Flag</td>
<td>1</td>
<td>2</td>
</tr>
<tr>
<td>Inputs Count</td>
<td>4</td>
<td>4</td>
</tr>
<tr>
<td>Outpoint</td>
<td>4</td>
<td>144</td>
</tr>
<tr>
<td>Input script</td>
<td>4</td>
<td>4</td>
</tr>
<tr>
<td>Sequence</td>
<td>4</td>
<td>16</td>
</tr>
<tr>
<td>Outputs Count</td>
<td>4</td>
<td>4</td>
</tr>
<tr>
<td>Amount</td>
<td>4</td>
<td>64 (2 outputs)</td>
</tr>
<tr>
<td>Output script</td>
<td>4</td>
<td>232 (2 outputs with different scripts)</td>
</tr>
<tr>
<td>Witness Count</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>Witness items</td>
<td>1</td>
<td>66</td>
</tr>
<tr>
<td>Lock time</td>
<td>4</td>
<td>16</td>
</tr>
<tr>
<td>Total</td>
<td><em>N/A</em></td>
<td>569</td>
</tr>
</tbody></table>
<p>เราสามารถตรวจสอบความถูกต้องของการคำนวณ weight ได้โดยดูค่าน้ำหนักรวมของธุรกรรมของ Alice จาก Bitcoin Core ได้โดยตรง:</p>
<pre><code>$ bitcoin-cli getrawtransaction 466200308696215bbc949d5141a49a41\\

38ecdfdfaa2a8029c1f9bcecd1f96177 2 | jq .weight

569
</code></pre>
<p> <img src="https://image.nostr.build/2e3675764c1b67d8b9e19db81101b336607f7aa8ec79b094fc2244a70a6ad7b2.jpg" alt="image"></p>
<h3><strong>Legacy Serialization</strong></h3>
<p>รูปแบบการซีเรียลไลซ์ที่อธิบายไว้ในบทนี้คือรูปแบบที่ใช้กับธุรกรรมบิตคอยน์ส่วนใหญ่ในปัจจุบัน แต่ก็ยังมีรูปแบบเก่าที่ถูกใช้งานอยู่ในธุรกรรมจำนวนมากเช่นกัน รูปแบบเก่านั้นเรียกว่า <strong>legacy serialization</strong> และต้องใช้บนเครือข่าย Bitcoin P2P สำหรับธุรกรรมที่มีโครงสร้าง witness ว่างเปล่า (ซึ่งจะเกิดขึ้นได้ก็ต่อเมื่อธุรกรรมนั้นไม่ได้ใช้จ่าย witness programs ใด ๆ)</p>
<p>Legacy serialization จะ <strong>ไม่มี</strong> ฟิลด์ต่อไปนี้: marker, flag, witness structure</p>
<p>ในบทนี้ เราได้ดูฟิลด์ต่าง ๆ ในหนึ่งธุรกรรมและเห็นว่าฟิลด์เหล่านั้นสื่อสารข้อมูลให้โหนดเต็มทราบว่าเหรียญควรถูกโอนจากใครไปหาใครอย่างไร เราได้กล่าวถึง output script, input script และ witness structure เพียงคร่าว ๆ ซึ่งมีหน้าที่กำหนดเงื่อนไขและเปิดโอกาสให้ผู้ใช้พิสูจน์สิทธิ์ในการใช้จ่ายเหรียญได้</p>
<p>การเข้าใจวิธีสร้างและใช้งานเงื่อนไขเหล่านี้เป็นสิ่งสำคัญเพื่อให้แน่ใจว่าเฉพาะ Alice เท่านั้นที่จะสามารถใช้จ่ายบิตคอยน์ของเธอได้ ดังนั้นหัวข้อนี้จะเป็นเนื้อหาของบทถัดไป</p>
]]></itunes:summary>
      <itunes:image href="https://image.nostr.build/4b81c193b6eb1d9d47353f31f88c3268884a8a2a3d74e771052448fec8a6f793.jpg"/>
      </item>
      
      <item>
      <title><![CDATA[สรุป Mastering Bitcoin: Programming the Open Blockchain บทที่ 5]]></title>
      <description><![CDATA[หายไปนานไม่ใช่ low time แค่มันขี้เกียจจจจจ]]></description>
             <itunes:subtitle><![CDATA[หายไปนานไม่ใช่ low time แค่มันขี้เกียจจจจจ]]></itunes:subtitle>
      <pubDate>Fri, 03 Oct 2025 06:06:56 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/wfd4wwt8q7kucwwvpl-l/</link>
      <comments>https://learnbn.npub.pro/post/wfd4wwt8q7kucwwvpl-l/</comments>
      <guid isPermaLink="false">naddr1qq2j64mxvs68wam58pcnw6m4vdt4w4nsfskkcq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65w7jkf9t</guid>
      <category></category>
      
        <media:content url="https://image.nostr.build/e5c951d87cf8197f45fe863c18b31eab095566d7f3ff772ec86cc8e05f957168.jpg" medium="image"/>
        <enclosure 
          url="https://image.nostr.build/e5c951d87cf8197f45fe863c18b31eab095566d7f3ff772ec86cc8e05f957168.jpg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qq2j64mxvs68wam58pcnw6m4vdt4w4nsfskkcq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65w7jkf9t</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<h1>Wallet Recovery: การกู้คืนกระเป๋าบิตคอยน์</h1>
<p>การสร้างคู่กุญแจ private key และ public key เป็นส่วนสำคัญในการอนุญาตให้กระเป๋าเงินบิตคอยน์สามารถรับและใช้จ่ายบิตคอยน์ได้ แต่การสูญเสีย private key ไปนั้นจะทำให้ไม่สามารถนำบิตคอยน์ที่เกี่ยวข้องกับ public key ที่คู่กันออกมาใช้จ่ายได้อีกเลย ตลอดหลายปีที่ผ่านมา นักพัฒนากระเป๋าเงินและโปรโตคอลได้ทำงานเพื่อออกแบบระบบที่ช่วยให้ผู้ใช้สามารถกู้คืนการเข้าถึงบิตคอยน์ของตนหลังจากเกิดปัญหาโดยไม่ทำให้ความปลอดภัยนั้นลดน้อยถอยลง</p>
<p>ในบทนี้ เราจะสำรวจวิธีการกู้คืนและป้องกันการสูญหายของข้อมูลที่ใช้กันในกระเป๋าเงินสมัยใหม่ บางวิธีได้รับการยอมรับอย่างกว้างขวางเพราะแทบไม่มีข้อเสีย และจึงถือเป็นแนวปฏิบัติที่ดีที่สุด ส่วนวิธีอื่น ๆ แม้จะมีข้อดี แต่ก็มาพร้อมข้อจำกัดบางประการ ทำให้ผู้พัฒนากระเป๋าเงินเลือกใช้แตกต่างกันไป เราจะอธิบายทั้งข้อดี ข้อเสีย และทางเลือกเหล่านี้อย่างเป็นระบบ เพื่อให้ผู้อ่านเข้าใจภาพรวมทั้งหมด</p>
<h2>กระเป๋าประเภทสร้างคู่กุญแจแบบอิสระ (Independent Key Generation)</h2>
<p>ก่อนอื่นควรทำความเข้าใจก่อนว่า bitcoin wallet หรือ “กระเป๋าเก็บบิตคอยน์” แท้จริงแล้วไม่ได้เก็บบิตคอยน์ไว้ข้างใน แต่เก็บเพียงกุญแจ (keys) ไว้เท่านั้น กุญแจเหล่านี้เชื่อมโยงกับบิตคอยน์ที่ถูกบันทึกไว้บนบล็อกเชน และใช้การพิสูจน์ต่อเครือข่ายว่าคุณถือครอง private key เป็นหลักฐานว่าคุณสามารถใช้จ่ายบิตคอยน์ที่เกี่ยวข้องนั้นได้ ซึ่งต่างจากกระเป๋าสตางค์ทั่วไปที่เก็บเงินสดไว้ภายใน</p>
<p>โดยทั่วไป กระเป๋าเงินบิตคอยน์จะมีทั้ง public key สำหรับสร้าง address และ private key สำหรับสร้างลายเซ็นเพื่ออนุมัติการใช้จ่าย และอีกประเภทหนึ่งคือกระเป๋าที่เก็บเพียง public key ในแอปพลิเคชัน ส่วน private key จะถูกเก็บไว้ในอุปกรณ์ภายนอก เช่น ฮาร์ดแวร์วอลเล็ตหรือระบบหลายลายเซ็น (multisig)</p>
<p>ในยุคแรก แอปพลิเคชันกระเป๋าเงินมักสร้างคู่กุญแจใหม่แบบอิสระทุกครั้งที่ต้องการใช้งาน จากนั้นผู้ใช้จำเป็นต้องสำรองฐานข้อมูลกระเป๋าเงินนั้น ๆ อยู่เสมอ เพื่อป้องกันไม่ให้กุญแจที่สร้างใหม่สูญหาย การล้มเหลวในการสำรองทันเวลาอาจทำให้สูญเสียการเข้าถึงบิตคอยน์ที่เก็บไว้ในกุญแจเหล่านั้นโดยถาวร</p>
<p>กุญแจแต่ละชุดที่สร้างอย่างอิสระมีขนาดประมาณ 32 ไบต์ การสำรองกุญแจจำนวนมากจึงเป็นภาระสำหรับผู้ใช้ บางคนพยายามลดภาระนี้ด้วยการใช้เพียงกุญแจเดียวในการทำธุรกรรมหลายครั้ง แต่ถึงแม้ว่าจะช่วยให้ง่ายต่อการสำรองข้อมูล แต่มันกลับทำให้ความเป็นส่วนตัวลดลงอย่างมาก เนื่องจากทุกธุรกรรมสามารถโยงกลับไปยังผู้ใช้รายเดิมได้ ด้วยเหตุนี้ ผู้ที่ให้ความสำคัญกับความเป็นส่วนตัวมักเลือกสร้างกุญแจใหม่สำหรับแต่ละธุรกรรม ซึ่งทำให้การสำรองข้อมูลเป็นไปได้จริงเพียงบนสื่อดิจิทัลที่มีความจุเพียงพอเท่านั้น<br><img src="https://github.com/bitcoinbook/bitcoinbook/blob/develop/images/mbc3_0501.png?raw=true" alt="image"></p>
<h2>กระเป๋าเก็บบิตคอยน์ประเภทสร้างกุญแจแบบกำหนดได้ (Deterministic Key)</h2>
<p>ฟังก์ชันแฮชจะสร้างเอาต์พุตเดิมเสมอเมื่อรับอินพุตเดิม แต่ถ้าอินพุตเปลี่ยนแปลงเพียงเล็กน้อย เอาต์พุตจะแตกต่างกัน หากฟังก์ชันมีความปลอดภัยทางการเข้ารหัส จะไม่มีใครสามารถคาดเดาเอาต์พุตใหม่ได้ เว้นเสียแต่ว่าพวกเขารู้อินพุตใหม่</p>
<p>เราสามารถใช้คุณสมบัตินี้เพื่อแปลงค่าใด ๆ (เช่น seed) ให้กลายเป็นชุดค่าที่ได้มาอย่างกำหนดได้ซ้ำ ๆ — นั่นคือ ถ้าใช้ seed เดิมกับขั้นตอนเดิม เราจะได้กุญแจอนุพันธ์ชุดเดียวกันทุกครั้ง ตัวอย่างเชิงปฏิบัติ:</p>
<pre><code># เก็บ entropy แบบสุ่ม แล้วแฮชเป็น seed
$ dd if=/dev/random count=1 status=none | sha256sum
f1cc3bc03ef51cb43ee7844460fa5049e779e7425a6349c8e89dfbb0fd97bb73  -
# กำหนด seed
$ seed=f1cc3bc03ef51cb43ee7844460fa5049e779e7425a6349c8e89dfbb0fd97bb73
# สร้างค่าที่ได้มาแบบกำหนดได้
$ for i in {0..2} ; do echo "$seed + $i" | sha256sum ; done
50b18e0bd9508310b8f699bad425efdf67d668cb2462b909fdb6b9bd2437beb3  -
a965dbcd901a9e3d66af11759e64a58d0ed5c6863e901dfda43adcd5f8c744f3  -
19580c97eb9048599f069472744e51ab2213f687d4720b0efc5bb344d624c3aa  -
</code></pre>
<p>ถ้าเรานำค่าที่ได้มาเหล่านี้ไปใช้เป็น private key ของ address ต่าง ๆ เราก็สามารถสร้างกุญแจทั้งหมดซ้ำได้โดยใช้เพียง seed และอัลกอริทึมเดียวกัน ดังนั้นการสำรองข้อมูลเพื่อกู้คืนกระเป๋าที่สร้างกุญแจแบบกำหนดได้จึงทำได้ง่าย — แทนที่จะสำรองกุญแจทุกดอก ผู้ใช้เพียงบันทึก seed และวิธีการ (algorithm/derivation) ที่ใช้เท่านั้น ตัวอย่างเช่น แม้อลิซจะมีบิตคอยน์ที่กระจายอยู่ในหนึ่งล้าน address ต่างกัน สิ่งที่ต้องสำรองเพื่อกู้คืนทั้งหมดอาจเป็นเพียง seed ชุดเดียว:</p>
<pre><code>f1cc 3bc0 3ef5 1cb4 3ee7 8444 60fa 5049
e779 e742 5a63 49c8 e89d fbb0 fd97 bb73
</code></pre>
<p>โครงตรรกะของการสร้างกุญแจแบบกำหนดได้แบบเรียงลำดับจะแสดงให้เห็นว่าจาก seed เดียวสามารถแยกสาขา (derive) กุญแจได้หลายดอก แต่กระเป๋าเงินสมัยใหม่มีวิธีที่พัฒนาขึ้น (เช่น แนวคิดกระเป๋าแบบ hierarchical deterministic) ที่ช่วยแยกการสร้าง public key ออกจาก private key ได้ ทำให้สามารถเผยหรือใช้ public key ได้โดยไม่ต้องเก็บ private key ไว้ในที่เสี่ยง เหมาะกับการจัดการความปลอดภัยและความเป็นส่วนตัวมากขึ้น<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0502.png" alt="image"></p>
<h3>การดึงกุญแจลูกสาธารณะ (Public Child Key Derivation)</h3>
<p>จากที่เราได้เรียนเรื่องของ public key กันไปในบทก่อนหน้า เราได้เรียนรู้วิธีการสร้าง public key จาก private key โดยใช้การเข้ารหัสแบบเส้นโค้งวงรี (ECC) แล้วมันจะเป็นอย่างไรหากเราใช้วิธีการเดิมแต่เปลี่ยนไปใช้ public key เป็นตัวตั้งแทน พิจารณาการดำเนินการที่เราใช้ในบทก่อนหน้าสำหรับการสร้าง public key (K) จาก private key (k) โดยใช้จุดกำเนิด (G): <code>$$K = k * G $$</code></p>
<p>คำถามคือ หากเราใช้ public key ที่มีอยู่แทนการสร้างใหม่จาก private key จะสามารถสร้างกุญแจลูก (child key) ได้หรือไม่?</p>
<p>ลองพิจารณาสมการเดิม หากเราบวกค่าเพิ่มเติมเดียวกันทั้งสองฝั่ง เช่น ค่า “123” เราจะได้ว่า:<br><code>$$K+(123×G)≡(k+123)×G$$</code></p>
<blockquote>
<p>TIP: ในหนังสือเล่มนี้ สัญลักษณ์ “=” ใช้แสดงการคำนวณค่า ส่วน “==” ใช้เพื่อแสดงความสมมูลระหว่างสองด้านของสมการ หากทั้งสองด้านไม่สมมูล ค่าที่ได้จะเป็น “false”</p>
</blockquote>
<p>สิ่งที่น่าสนใจคือ การเพิ่มค่า (tweak) เช่น 123 ลงใน public key สามารถทำได้ด้วยข้อมูลสาธารณะเพียงอย่างเดียว โดยไม่ต้องรู้ private key เลย</p>
<p>ตัวอย่างเช่น อลิซสร้าง public key (K) และส่งให้บ็อบ ถึงแม้บ็อบจะไม่รู้ค่า private key (k) แต่เขารู้จุดกำเนิด (G) ดังนั้นเขาสามารถสร้าง public child key ได้ด้วยการเพิ่มค่าใด ๆ ลงไป หากบ็อบแจ้งค่า tweak ที่ใช้กับอลิซ อลิซก็สามารถเพิ่มค่าดังกล่าวลงใน private key ของเธอ เพื่อให้ได้ private child key ที่สอดคล้องกับ public child key ที่บ็อบสร้างขึ้น</p>
<p>กล่าวอีกอย่างคือ แม้ผู้ที่ไม่รู้ private key ก็ยังสามารถสร้าง public child key ได้ไม่จำกัดจาก public key อันเดียว หากมีการกำหนดวิธีสร้าง key tweaks อย่างเป็นระบบ ผู้ที่ถือครอง private key สามารถใช้ key tweaks เดียวกันเพื่อสร้าง private child key ที่ตรงกันได้เสมอเช่นกัน</p>
<p>เทคนิคนี้ช่วยให้ข้อมูลสาธารณะ เช่น public key ของผู้ใช้ สามารถถูกแจกจ่ายไปยังบุคคลอื่น โดยไม่ต้องเปิดเผย private key เมื่อถึงเวลาที่ต้องใช้จ่ายเงิน อลิซสามารถส่งรายการ key tweaks ที่ใช้ไปยังอุปกรณ์ลงนามแบบฮาร์ดแวร์ (hardware wallet) ซึ่งเก็บ private key ไว้อย่างปลอดภัย อุปกรณ์นั้นจะใช้ key tweaks เพื่อสร้าง private child key ที่จำเป็นสำหรับการลงนามธุรกรรม จากนั้นส่งธุรกรรมที่ลงนามแล้วกลับไปยังส่วนติดต่อผู้ใช้ที่ปลอดภัยน้อยกว่าเพื่อเผยแพร่ไปยังเครือข่ายบิตคอยน์</p>
<p>การดึง public child key สามารถสร้างเป็นลำดับเชิงเส้นของกุญแจ คล้ายกับกระเป๋าเงินแบบกำหนดได้ (deterministic wallets) ที่สร้างกุญแจจาก seed อย่างไรก็ตาม กระเป๋าเงินสมัยใหม่ก้าวไปอีกขั้น โดยใช้เทคนิคเพิ่มเติมเพื่อสร้างชุดของ public child keys ที่ซับซ้อนกว่า และจะอธิบายในส่วนถัดไป</p>
<h2>การสร้างกุญแจแบบลำดับชั้นเชิงกำหนด (HD) ตามมาตรฐาน BIP32</h2>
<p>วอลเล็ตบิตคอยน์สมัยใหม่ทั้งหมดที่เรารู้จัก ใช้การสร้างกุญแจแบบลำดับชั้นเชิงกำหนด (HD) เป็นค่าเริ่มต้น มาตรฐานนี้ถูกกำหนดไว้ใน BIP32 โดยใช้หลักการสร้างกุญแจแบบกำหนดค่าได้ร่วมกับการดึง public child key แบบเลือกได้ผ่านอัลกอริทึมที่สร้างโครงสร้างเป็น tree ของกุญแจ </p>
<p>ใน tree นี้ กุญแจใด ๆ สามารถทำหน้าที่เป็นพ่อแม่ของชุด child key ได้ และ child key แต่ละดอกก็สามารถกลายเป็นพ่อแม่ของชุด child key ใหม่ได้เช่นกัน ไม่มีข้อจำกัดตายตัวในเรื่องความลึกของ tree โครงสร้างแบบนี้ช่วยให้วอลเล็ต HD สามารถสร้างกุญแจจำนวนมากจาก seed เดียว โดยผู้ใช้เพียงสำรอง seed ก็สามารถกู้คืนกุญแจทั้งหมดใน tree ได้อย่างปลอดภัยและสะดวก ดูตัวอย่างได้ในภาพประกอบข้างล่างนี้<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0503.png" alt="image"></p>
<p>โครงสร้างแบบ tree ของกุญแจยังสามารถสะท้อนการจัดการและการแบ่งหมวดหมู่ได้อย่างชัดเจน ตัวอย่างเช่น กิ่งหนึ่งของ child key อาจใช้สำหรับรับการชำระเงินขาเข้า อีกกิ่งหนึ่งอาจใช้สำหรับรับเงินทอนจากการชำระเงินขาออก นอกจากนี้ กิ่งของกุญแจยังสามารถประยุกต์ใช้ในบริบทขององค์กร เช่น แยกกิ่งต่าง ๆ ให้กับแผนก บริษัทในเครือ หน้าที่เฉพาะ หรือหมวดหมู่การบัญชี</p>
<p>บทต่อไปเราจะเจาะลึกเรื่องวอลเล็ต HD และอธิบายวิธีการสร้างวอลเล็ตจาก seed ในหัวข้อ "การสร้างวอลเล็ต HD จาก seed"</p>
<h2>Seeds and Recovery Codes</h2>
<p>วอลเล็ต HD เป็นกลไกที่ทรงพลังสำหรับจัดการกุญแจจำนวนมากที่สกัดมาจาก seed เดียวกัน หากฐานข้อมูลวอลเล็ตของคุณเสียหายหรือสูญหาย คุณสามารถสร้าง private key ทั้งหมดกลับคืนมาได้โดยใช้ seed ชุดเดิม แต่ข้อเสียสำคัญคือ หากผู้อื่นได้ seed ของคุณไป พวกเขาจะสามารถสร้างกุญแจส่วนตัวทั้งหมดได้เช่นกัน ซึ่งอาจทำให้บิตคอยน์ถูกขโมยจากวอลเล็ตแบบลงนามเดี่ยว หรือทำให้ความปลอดภัยของวอลเล็ตแบบหลายลายเซ็นลดลง </p>
<p>ในส่วนนี้เราจะอธิบายรูปแบบของ โค้ดกู้คืน (recovery code) หลายแบบ โดยมุ่งหมายเพื่อทำให้การสำรองข้อมูลทั้งสะดวกและปลอดภัยมากขึ้น</p>
<p>แม้ว่า seed โดยพื้นฐานเป็นตัวเลขสุ่มขนาดใหญ่ — โดยทั่วไปมีขนาดตั้งแต่ 128 ถึง 256 บิต — โค้ดกู้คืนส่วนใหญ่ถูกออกแบบให้เป็น คำในภาษามนุษย์ เพื่อให้จดจำและเขียนเก็บได้ง่ายกว่ารหัสไบนารีหรือเลขฐานสิบหก ตัวอย่างแรงจูงใจในการใช้คำคือผู้ใช้สามารถจดหรือพูดได้โดยไม่ต้องคัดลอกตัวอักษรยาว ๆ และลดความเสี่ยงจากความผิดพลาดเมื่อสำรองด้วยมือ</p>
<p>ตัวอย่างการเก็บ seed สองรูปแบบ (เลขฐานสิบหก กับ คำศัพท์ภาษาอังกฤษ):</p>
<pre><code>Hex-encoded:
0C1E 24E5 9177 79D2 97E1 4D45 F14E 1A1A

Word-encoded:
army van defense carry jealous true
garbage claim echo media make crunch
</code></pre>
<p>การจดจำโค้ดกู้คืนเพียงอย่างเดียวอาจเป็นคุณสมบัติที่มีประโยชน์ในบางสถานการณ์ เช่น เมื่อคุณไม่สามารถขนย้ายสิ่งของทางกายภาพ เช่น กระดาษที่เขียนโค้ดกู้คืน โดยไม่เสี่ยงต่อการถูกยึดหรือถูกตรวจค้นโดยบุคคลภายนอกที่อาจขโมยบิตคอยน์ของคุณได้</p>
<p>อย่างไรก็ตาม การพึ่งพาความทรงจำเพียงอย่างเดียวถือเป็นเรื่องอันตราย เพราะมีความเสี่ยงหลายประการ:</p>
<ul>
<li><p>หากคุณลืมโค้ดกู้คืนและไม่สามารถเข้าถึงฐานข้อมูลวอลเล็ตเดิม บิตคอยน์ของคุณจะสูญหายตลอดกาล</p>
</li>
<li><p>หากคุณเสียชีวิตหรือได้รับบาดเจ็บรุนแรง และทายาทไม่สามารถเข้าถึงฐานข้อมูลวอลเล็ตเดิม พวกเขาจะไม่สามารถรับมรดกบิตคอยน์ของคุณได้</p>
</li>
<li><p>หากมีคนเชื่อว่าคุณจำโค้ดกู้คืนได้ พวกเขาอาจพยายามบังคับให้คุณเปิดเผยรหัสนั้น ในเวลาที่เขียนหนังสือเล่มนี้ เจมสัน ล็อปป์ ผู้มีส่วนร่วมในการพัฒนาบิตคอยน์ ได้บันทึกเหตุโจมตีทางกายภาพต่อผู้ที่สงสัยว่าเป็นเจ้าของบิตคอยน์และสินทรัพย์ดิจิทัลอื่น ๆ มากกว่า 100 ครั้ง รวมถึงมีการเสียชีวิตอย่างน้อย 3 ราย และหลายกรณีที่เกี่ยวข้องกับการทรมาน จับเป็นตัวประกัน หรือคุกคามครอบครัว</p>
</li>
</ul>
<blockquote>
<p>TIP: แม้ว่าคุณจะใช้โค้ดกู้คืนที่ออกแบบมาให้จดจำง่าย เราขอแนะนำอย่างยิ่งให้คุณพิจารณาจดบันทึกไว้</p>
</blockquote>
<h3>ปัจจุบันมีรหัสกู้คืนหลายประเภทที่มีการใช้งานอย่างแพร่หลาย:</h3>
<ul>
<li><p>BIP39: เป็นวิธีที่ได้รับความนิยมมากที่สุดในการสร้างรหัสกู้คืนในช่วงทศวรรษที่ผ่านมา BIP39 เกี่ยวข้องกับการสร้างลำดับไบต์แบบสุ่ม เพิ่มเช็คซัมเข้าไป และเข้ารหัสข้อมูลเป็นชุดคำศัพท์ 12 ถึง 24 คำ (ซึ่งอาจแปลเป็นภาษาท้องถิ่นของผู้ใช้) คำเหล่านี้ (บวกกับ passphrase ) จะถูกประมวลผ่านฟังก์ชัน key-stretching และนำผลลัพธ์มาใช้เป็น seed BIP39 มีข้อบกพร่องหลายประการซึ่งระบบอื่น ๆ ที่พัฒนาขึ้นภายหลังพยายามแก้ไข</p>
</li>
<li><p>Electrum v2: ถูกใช้ในกระเป๋าเงิน Electrum (เวอร์ชัน 2.0 ขึ้นไป) รหัสกู้คืนที่ใช้คำนี้มีข้อดีหลายประการเหนือ BIP39 มันไม่ได้พึ่งพารายการคำศัพท์สากลที่ต้องนำไปใช้ในทุกเวอร์ชันของทุกโปรแกรมที่เข้ากันได้ อีกทั้งรหัสกู้คืนยังมีหมายเลขเวอร์ชันที่ช่วยเพิ่มความน่าเชื่อถือและประสิทธิภาพ เช่นเดียวกับ BIP39 มันรองรับ passphrase (ซึ่ง Electrum เรียกว่า seed extension ) และใช้ฟังก์ชัน key-stretching แบบเดียวกัน</p>
</li>
<li><p>Aezeed: ถูกใช้ในกระเป๋าเงิน LND นี่เป็นอีกรหัสกู้คืนที่ใช้คำซึ่งมีการปรับปรุงจาก BIP39 มันรวมหมายเลขเวอร์ชันสองตัว: ตัวแรกเป็นภายในและช่วยกำจัดปัญหาหลายอย่างในการอัปเกรดแอปพลิเคชันกระเป๋าเงิน (เหมือนหมายเลขเวอร์ชันของ Electrum v2); อีกหมายเลขเวอร์ชันเป็นภายนอก ซึ่งสามารถเพิ่มเข้ามาเพื่อเปลี่ยนคุณสมบัติทางการเข้ารหัสพื้นฐานของรหัสกู้คืน นอกจากนี้ยังรวม วันเกิดของกระเป๋าเงิน ในรหัสกู้คืน ซึ่งอ้างอิงถึงวันที่ผู้ใช้สร้างฐานข้อมูลกระเป๋าเงิน โดยสิ่งนี้ช่วยให้กระบวนการกู้คืนสามารถค้นหาเงินทั้งหมดที่เกี่ยวข้องกับกระเป๋าเงินโดยไม่ต้องสแกนบล็อกเชนทั้งหมด ซึ่งมีประโยชน์อย่างยิ่งสำหรับซอฟแวร์ที่เน้นความเป็นส่วนตัว มันรองรับการเปลี่ยนรหัสผ่านหรือเปลี่ยนแปลงรูปแบบอื่น ๆ ของรหัสกู้คืนโดยไม่จำเป็นต้องย้ายเงินไปยัง seed ใหม่—ผู้ใช้เพียงแค่ต้องสำรองรหัสกู้คืนใหม่เท่านั้น ข้อเสียเปรียบเมื่อเทียบกับ Electrum v2 คือ เช่นเดียวกับ BIP39 มันต้องพึ่งพาทั้งซอฟต์แวร์สำรองและกู้คืนที่รองรับรายการคำศัพท์เดียวกัน</p>
</li>
<li><p>Muun: ถูกใช้ในกระเป๋าเงิน Muun โดยค่าเริ่มต้นกำหนดให้ธุรกรรมการใช้จ่ายต้องถูกลงนามด้วยกุญแจหลายดอก นี่เป็นรหัสที่ไม่ใช่คำซึ่งต้องมาพร้อมกับข้อมูลเพิ่มเติม (ปัจจุบัน Muun ให้มาในรูปแบบ PDF) รหัสกู้คืนนี้ไม่เกี่ยวข้องกับ seed และถูกใช้เพื่อถอดรหัส private key ที่อยู่ใน PDF แทน แม้ว่าวิธีนี้จะยุ่งยากเมื่อเทียบกับรหัสกู้คืน BIP39, Electrum v2 และ Aezeed แต่มันรองรับเทคโนโลยีและมาตรฐานใหม่ที่กำลังกลายเป็นที่นิยมมากขึ้นในกระเป๋าเงินใหม่ ๆ เช่น การสนับสนุน Lightning Network (LN), ตัวอธิบายสคริปต์เอาต์พุต และ miniscript</p>
</li>
<li><p>SLIP39: เป็นวิธีที่พัฒนามาต่อจาก BIP39 โดยนักพัฒนาบางคนที่มีส่วนร่วมใน BIP39 ซึ่ง SLIP39 อนุญาตให้ seed เดียวกระจายโดยใช้รหัสกู้คืนหลายชุดที่สามารถเก็บไว้ในสถานที่ต่างกัน (หรือโดยคนต่างกัน) เมื่อคุณสร้างรหัสกู้คืน คุณสามารถระบุจำนวนที่จะต้องใช้เพื่อกู้คืน seed ได้ ตัวอย่างเช่น คุณสร้างรหัสกู้คืนห้าชุดแต่ต้องการเพียงสามชุดเพื่อกู้คืนซีด SLIP39 ให้การสนับสนุน passphrase ขึ้นอยู่กับรายการคำศัพท์สากล และไม่ได้ให้การกำหนดเวอร์ชันโดยตรง</p>
</li>
</ul>
<blockquote>
<p>NOTE: ระบบใหม่สำหรับการกระจายรหัสกู้คืนที่มีความคล้ายคลึงกับ SLIP39 ได้ถูกนำเสนอระหว่างการเขียนหนังสือเล่มนี้ โดยมันมีชื่อ Codex32 ช่วยให้สามารถสร้างและตรวจสอบรหัสกู้คืนได้โดยใช้เพียงคำแนะนำที่พิมพ์ไว้ กรรไกร มีดคัตเตอร์แบบละเอียด ตัวยึดทองเหลือง และปากกา—บวกกับความเป็นส่วนตัวและเวลาว่างสักสองสามชั่วโมง ผู้ที่ไว้วางใจคอมพิวเตอร์สามารถสร้างรหัสกู้คืนได้ทันทีโดยใช้ซอฟต์แวร์บนอุปกรณ์ดิจิทัล คุณสามารถสร้างรหัสกู้คืนได้สูงสุด 31 ชุดเพื่อเก็บไว้ในสถานที่ต่าง ๆ โดยระบุจำนวนที่จะต้องใช้เพื่อกู้คืน seed เนื่องจากเป็นข้อเสนอใหม่ รายละเอียดเกี่ยวกับ Codex32 อาจเปลี่ยนแปลงอย่างมีนัยสำคัญก่อนที่หนังสือเล่มนี้จะตีพิมพ์ ดังนั้นเราจึงแนะนำให้ผู้อ่านที่สนใจรหัสกู้คืนแบบกระจายศูนย์ตรวจสอบสถานะปัจจุบันของมัน <np-embed url="https://secretcodex32.com/"><a href="https://secretcodex32.com/">https://secretcodex32.com/</a></np-embed></p>
</blockquote>
<h2>passphrase</h2>
<p>รูปแบบ BIP39, Electrum v2, Aezeed, และ SLIP39 ทั้งหมดสามารถรองรับการใช้ passphrase ได้ หากคุณเก็บ passphrase ไว้ในความทรงจำ (ไม่จด) มันก็จะมีข้อดีข้อเสียแบบเดียวกับการจดจำ seed เช่นกัน</p>
<p>สามระบบ (BIP39, Electrum v2, และ SLIP39) ไม่ได้รวม passphrase เข้าไปในเช็คซัมที่ใช้ตรวจจับความผิดพลาดในการป้อนข้อมูล ทุก passphrase (รวมถึงการไม่ใช้เลย) จะให้ผลลัพธ์เป็น seed สำหรับโครงสร้างกุญแจ BIP32 แต่จะเป็นโครงสร้างที่ต่างกัน passphrase ที่ต่างกันจะได้กุญแจคนละชุด ซึ่งจุดนี้อาจเป็นทั้งข้อดีหรือข้อเสีย ขึ้นกับมุมมองของคุณ</p>
<ul>
<li><p>ในด้านบวก หากมีคนได้รหัสกู้คืน (คำศัพท์ 12–24 คำ) ของคุณไป แต่ไม่มี passphrase พวกเขาจะได้โครงสร้างกุญแจ BIP32 หนึ่งชุดที่ใช้งานได้ หากคุณวางแผนรับมือไว้ล่วงหน้า (เช่น โอนบิตคอยน์บางส่วนไปยังโครงสร้างที่ไม่มี passphrase) การถูกขโมยบางส่วนอาจเป็นสัญญาณเตือนว่ารหัสกู้คืนถูกบุกรุก ทำให้คุณมีโอกาสตอบโต้ได้ การที่รหัสกู้คืนเดียวสามารถมี passphrase หลายค่าแล้วให้ผลลัพธ์ที่ดูถูกต้องทั้งหมด ก็เป็นรูปแบบของ plausible deniability (การปฏิเสธที่เป็นไปได้)</p>
</li>
<li><p>ในด้านลบ หากคุณถูกบังคับให้มอบรหัสกู้คืน ผู้โจมตีอาจยังคงบีบบังคับให้คุณเปิดเผย passphrase เพิ่มเติมหากยอดที่เห็นไม่ตรงกับที่คาดหวัง การออกแบบเพื่อรองรับการปฏิเสธที่เป็นไปได้จึงไม่มีวิธีพิสูจน์ต่อผู้โจมตีได้ว่าคุณได้เปิดเผยข้อมูลทั้งหมดแล้ว ดังนั้นความเสี่ยงคือพวกเขาอาจยังคงบังคับต่อแม้คุณจะให้รหัสทั้งหมดแล้วก็ตาม</p>
</li>
<li><p>ข้อเสียอีกประการคือการลดทอนการตรวจจับข้อผิดพลาด หากคุณพิมพ์ passphrase ผิดเพียงเล็กน้อยเมื่อกู้คืนจากการสำรอง กระเป๋าเงินจะไม่แจ้งเตือนความผิดพลาดได้ชัดเจน — แอปจะแสดงโครงสร้างกุญแจใหม่ที่ใช้งานได้แต่ยอดเป็นศูนย์ ซึ่งผู้ใช้มือใหม่อาจคิดว่าเงินหายไปจริง ๆ และทำการตัดสินใจผิดพลาด เช่น ทิ้งรหัสกู้คืนหรือยอมแพ้ ในทางกลับกัน หากคุณคาดหวังยอดคงเหลือเป็นศูนย์จริง ๆ คุณอาจไม่รู้ตัวถึงความผิดพลาดนั้นเป็นเวลาหลายปีจนกว่าจะลองกู้คืนด้วย passphrase ที่ถูกต้อง</p>
</li>
</ul>
<p>มีเพียง Aezeed เท่านั้นที่รับรองการตรวจสอบความถูกต้องของ passphrase และจะแจ้งข้อผิดพลาดเมื่อใส่ค่าไม่ถูกต้อง ข้อนี้ช่วยลดปัญหาการปฏิเสธที่เป็นไปได้โดยเพิ่มการตรวจจับข้อผิดพลาด และทำให้เป็นไปได้ที่จะพิสูจน์แก่ผู้โจมตีได้ว่าคุณได้เปิดเผย passphrase แล้ว</p>
<p>ผู้ใช้และนักพัฒนามีมุมมองแตกต่างกันเกี่ยวกับวิธีที่ดีกว่า บางคนสนับสนุนการปฏิเสธที่เป็นไปได้อย่างเต็มที่ ขณะที่บางคนชอบความปลอดภัยจากการตรวจจับข้อผิดพลาดสำหรับผู้ใช้มือใหม่และผู้ที่ตกอยู่ภายใต้ความกดดัน เราคาดว่าการถกเถียงนี้จะยังคงอยู่ตราบเท่าที่รหัสกู้คืนยังใช้กันแพร่หลาย</p>
<h3>การสำรองข้อมูลอื่น ๆ</h3>
<p>แน่นอนว่าข้อมูลที่สำคัญที่สุดนั้นคือ private key เพราะหากคุณสูญเสีย private key คุณจะสูญเสียความสามารถในการใช้จ่ายบิตคอยน์ของคุณ การสร้างกุญแจแบบกำหนดได้และรหัสกู้คืน (คำศัพท์ 12-24 คำ) ให้วิธีแก้ปัญหาที่ค่อนข้างแข็งแกร่งสำหรับการสำรองและกู้คืนกุญแจของคุณและบิตคอยน์ที่พวกมันควบคุม แต่อย่างไรก็ตาม สิ่งสำคัญที่ต้องพิจารณาคือฐานข้อมูลกระเป๋าเงินหลายแห่งเก็บข้อมูลมากกว่าแค่กุญแจ </p>
<p>ตัวอย่างเช่น เมื่อบ๊อบสร้าง address ใหม่เพื่อส่ง invoice ให้อลิซ เขาจะเพิ่ม ป้ายกำกับ (label) ให้กับ address นั้น เพื่อให้สามารถแยกการชำระเงินของอลิซออกจากการชำระเงินอื่น ๆ ที่เขาได้รับได้ เมื่ออลิซจ่ายเงินตาม address ดังกล่าว เธอก็ติดป้ายกำกับกับธุรกรรมด้วยเหตุผลเดียวกัน</p>
<p>กระเป๋าเงินบางแห่งยังสามารถบันทึกข้อมูลเพิ่มเติมที่เป็นประโยชน์กับผู้ใช้ เช่น อัตราแลกเปลี่ยนปัจจุบัน ซึ่งช่วยให้คำนวณภาษีหรือรายงานทางบัญชีได้สะดวกยิ่งขึ้น</p>
<p>ป้ายกำกับและข้อมูลเสริมทั้งหมดนี้จะถูกเก็บไว้ ภายในกระเป๋าเงินของผู้ใช้ เท่านั้น ไม่ได้แชร์กับเครือข่ายบิตคอยน์ ซึ่งช่วยปกป้องความเป็นส่วนตัวและลดการเปิดเผยข้อมูลส่วนบุคคลที่ไม่จำเป็นบนบล็อกเชน</p>
<p>สำหรับตัวอย่างข้อมูล สามารถดูได้จากตารางด้านล่างนี้:</p>
<table>
<thead>
<tr>
<th align="left">DATE</th>
<th align="left">LABEL</th>
<th align="left">BTC</th>
</tr>
</thead>
<tbody><tr>
<td align="left">2023-01-01</td>
<td align="left">Bought bitcoins from Joe</td>
<td align="left">+0.00100</td>
</tr>
<tr>
<td align="left">2023-01-02</td>
<td align="left">Paid Bob for podcast</td>
<td align="left">−0.00075</td>
</tr>
</tbody></table>
<blockquote>
<p>ข้อความจากหลาม: ในบางกระเป๋าจะเก็บพวกข้อมูลธุรกรรมของเราด้วย เช่นที่เราส่งหรือที่เรารับ ยกตัวอย่างเช่น sparrow จะเก็บพวก transaction ที่เราเคยรับมา เพื่อให้ไม่ต้องเรียกจาก blockchain หลาย ๆ รอบ</p>
</blockquote>
<p>อย่างไรก็ตาม เนื่องจาก ป้ายกำกับของ address และธุรกรรม ถูกเก็บไว้เฉพาะในฐานข้อมูลกระเป๋าเงินของผู้ใช้แต่ละคน และไม่ได้ถูกกำหนดไว้ล่วงหน้า จึงไม่สามารถกู้คืนได้เพียงแค่ใช้รหัสกู้คืนหรือ seed เมื่อกู้คืนจาก seed ผู้ใช้จะเห็นเพียงรายการเวลาธุรกรรมโดยประมาณและจำนวนบิตคอยน์เท่านั้น ซึ่งอาจทำให้ยากต่อการติดตามว่าเงินถูกใช้ไปอย่างไร ลองนึกภาพการตรวจสอบรายการธนาคารหรือบัตรเครดิตจากปีที่แล้วที่มีวันที่และจำนวนเงินครบ แต่ช่อง “คำอธิบาย” กลับว่างเปล่า</p>
<p>ดังนั้น กระเป๋าเงินควรมีวิธีที่สะดวกสำหรับผู้ใช้ในการ สำรองข้อมูลป้ายกำกับ แม้ว่าจะดูเหมือนเป็นเรื่องชัดเจน แต่หลายแอปพลิเคชันที่ได้รับความนิยมทำให้การสร้างและใช้รหัสกู้คืนเป็นเรื่องง่าย กลับไม่มีวิธีสำรองหรือกู้คืนป้ายกำกับ</p>
<p>นอกจากนี้ อาจเป็นประโยชน์หากกระเป๋าเงินรองรับ รูปแบบมาตรฐานในการส่งออกป้ายกำกับ เพื่อให้สามารถนำไปใช้กับแอปพลิเคชันอื่นได้ เช่น ซอฟต์แวร์บัญชี มาตรฐานสำหรับการส่งออกนี้ถูกเสนอไว้ใน BIP329</p>
<p>สำหรับกระเป๋าเงินที่สนับสนุนโปรโตคอลเพิ่มเติม นอกจากการทำงานพื้นฐานของบิตคอยน์ อาจจำเป็นต้องเก็บข้อมูลอื่น ๆ ด้วย ตัวอย่างเช่น ในปี 2023 แอปพลิเคชันหลายตัวได้เพิ่มการสนับสนุนการส่งและรับธุรกรรมผ่าน Lightning Network (LN) แม้ว่าโปรโตคอล LN จะมีวิธีการกู้คืนเงินในกรณีข้อมูลสูญหายที่เรียกว่า static channel backups แต่ก็ไม่สามารถรับประกันผลลัพธ์ได้ หากโหนดที่กระเป๋าเงินของคุณเชื่อมต่อรู้ว่าคุณสูญเสียข้อมูล โหนดนั้นอาจสามารถขโมยบิตคอยน์จากคุณได้ หากฐานข้อมูลของโหนดสูญหายพร้อมกับฐานข้อมูลของคุณ และไม่มีใครมีสำเนาสำรองเพียงพอ ทั้งคุณและโหนดนั้นก็อาจสูญเสียเงินทั้งหมด</p>
<h2>การสำรองเส้นทางการสร้างกุญแจ (Backing Up Key Derivation Paths)</h2>
<p>ในโครงสร้างกุญแจ BIP32 มีกุญแจระดับแรกประมาณสี่พันล้านคู่ แต่ละคู่สามารถมีลูกของตัวเองอีกสี่พันล้านคู่ และลูกแต่ละตัวก็สามารถมีลูกต่อได้อีกสี่พันล้านคู่ต่อไปเรื่อย ๆ เป็นไปไม่ได้ที่แอปพลิเคชันกระเป๋าเงินจะสร้างแม้แต่เศษเล็กน้อยของคู่กุญแจทั้งหมดในโครงสร้าง BIP32 ซึ่งหมายความว่าการกู้คืนจากการสูญเสียข้อมูลจำเป็นต้องใช้มากกว่ารหัสกู้คืนเพียงอย่างเดียว ต้องอาศัย อัลกอริทึมสำหรับรับ seed (เช่น BIP39) และ อัลกอริทึมการสร้างคู่กุญแจแบบกำหนดได้ (เช่น BIP32) ร่วมด้วย</p>
<p>มีสองวิธีที่ถูกนำเสนอเพื่อแก้ปัญหานี้ วิธีแรกคือ การกำหนดมาตรฐานเส้นทางการสร้างกุญแจ ทุกครั้งที่มีการสร้างหรือเปลี่ยนแปลง address แอปพลิเคชันกระเป๋าบิตคอยน์จะคำนวณ address ใหม่จากเส้นทางมาตรฐานที่กำหนดไว้ ตัวอย่างเช่น BIP44 กำหนดเส้นทางมาตรฐานเป็น m/44'/0'/0' สำหรับ legacy address แอปพลิเคชันกระเป๋าเงินจะใช้เส้นทางนี้ในการคำนวณกุญแจต่าง ๆ ทั้งเมื่อเริ่มใช้งานครั้งแรกและหลังจากกู้คืนจากรหัสกู้คืน</p>
<p>วิธีแก้ปัญหานี้เรียกว่า เส้นทางโดยนัย (Implicit Path) เส้นทางโดยนัยที่เป็นที่นิยมหลายแบบซึ่งกำหนดโดย BIP ต่าง ๆ แสดงอยู่ในตารางด้านล่างนี้:</p>
<table>
<thead>
<tr>
<th>Standard</th>
<th>Script</th>
<th>BIP32 Path</th>
</tr>
</thead>
<tbody><tr>
<td>BIP 44</td>
<td>P2PKH</td>
<td>m/44'/0'/0'</td>
</tr>
<tr>
<td>BIP 49</td>
<td>Nested P2WPKH</td>
<td>m/49'/1'/0'</td>
</tr>
<tr>
<td>BIP 84</td>
<td>P2WPKH</td>
<td>m/84'/0'/0'</td>
</tr>
<tr>
<td>BIP 86</td>
<td>P2TR Single-key</td>
<td>m/86'/0'/0'</td>
</tr>
</tbody></table>
<p>วิธีที่สองคือ การสำรองเส้นทาง (path) ร่วมกับรหัสกู้คืน (recovery code) โดยระบุอย่างชัดเจนว่าเส้นทางใดใช้กับสคริปต์ใด เราเรียกวิธีนี้ว่า การระบุเส้นทางอย่างชัดเจน (explicit paths)</p>
<p>ข้อดีของ เส้นทางโดยปริยาย (implicit paths) คือผู้ใช้ไม่จำเป็นต้องจดจำหรือบันทึกข้อมูลเส้นทางใด ๆ หากป้อนรหัสกู้คืนเข้าไปในแอปพลิเคชันกระเป๋าเงินเดียวกับที่เคยใช้ก่อนหน้านี้ (เวอร์ชันเดียวกันหรือล่าสุดกว่า) ระบบจะสร้างกุญแจสำหรับเส้นทางเดิมโดยอัตโนมัติ</p>
<p>ข้อเสียของ implicit paths คือความไม่ยืดหยุ่น เมื่อใช้รหัสกู้คืน แอปพลิเคชันจะต้องสร้างกุญแจสำหรับทุกเส้นทางที่รองรับ และต้องสแกนบล็อกเชนเพื่อค้นหาธุรกรรมที่เกี่ยวข้อง หากไม่ทำเช่นนั้น อาจทำให้ไม่พบธุรกรรมทั้งหมดของผู้ใช้ วิธีนี้จึงสิ้นเปลืองทรัพยากร โดยเฉพาะในกระเป๋าที่รองรับฟีเจอร์หลายอย่างแต่ผู้ใช้อาจใช้เพียงบางฟีเจอร์เท่านั้น</p>
<p>สำหรับ implicit path recovery codes ที่ไม่มีหมายเลขเวอร์ชัน เช่น BIP39 และ SLIP39 เวอร์ชันใหม่ของแอปกระเป๋าที่เลิกสนับสนุนเส้นทางเก่า ๆ จะไม่สามารถเตือนผู้ใช้ระหว่างกู้คืนได้ว่าเงินบางส่วนอาจไม่ถูกค้นพบ เช่นเดียวกัน หากผู้ใช้ป้อนรหัสกู้คืนลงในซอฟต์แวร์รุ่นเก่า ซอฟต์แวร์ก็จะไม่สามารถค้นหาเส้นทางใหม่ ๆ ที่ผู้ใช้อาจเคยได้รับเงินเข้ามาได้</p>
<p>รหัสกู้คืนที่มีข้อมูลเวอร์ชัน เช่น Electrum v2 และ Aezeed สามารถตรวจจับได้ว่าผู้ใช้กำลังป้อนรหัสกู้คืนที่ใหม่กว่าหรือเก่ากว่า และสามารถแนะนำผู้ใช้ไปยังแหล่งข้อมูลที่เหมาะสมได้</p>
<p>ผลลัพธ์ของ implicit paths คือมันสามารถรวมเฉพาะข้อมูลที่เป็นสากล (เช่น เส้นทางที่กำหนดเป็นมาตรฐาน) หรือข้อมูลที่ได้จาก seed (เช่น keys) เท่านั้น ข้อมูลที่ไม่เป็นเชิงกำหนดและเฉพาะตัวผู้ใช้ไม่สามารถกู้คืนได้</p>
<p>ตัวอย่างเช่น Alice, Bob และ Carol มีบิตคอยน์ที่สามารถใช้ลายเซ็นของสองในสามคนได้ แม้ Alice ต้องการเพียงลายเซ็นของ Bob หรือ Carol เพื่อใช้จ่าย เธอก็ยังต้องมี public keys ของทั้งสองคนเพื่อค้นหาทรัพย์สินร่วมบนบล็อกเชน ซึ่งหมายความว่าทุกคนต้องสำรอง public keys ของทั้งสามคน เมื่อ multisignature และสคริปต์ขั้นสูงอื่น ๆ ถูกใช้งานมากขึ้น ความไม่ยืดหยุ่นของ implicit paths ก็ชัดเจนขึ้น</p>
<p>ข้อดีของ explicit paths คือสามารถระบุได้ชัดเจนว่า key ใดใช้กับ script ใด ทำให้ไม่จำเป็นต้องรองรับสคริปต์ล้าสมัย ไม่มีปัญหาความเข้ากันได้ย้อนหลังหรือไปข้างหน้า และข้อมูลเพิ่มเติม เช่น public keys ของผู้ใช้อื่น สามารถรวมเข้าไปได้โดยตรง</p>
<p>ข้อเสียคือผู้ใช้ต้องสำรองข้อมูลเพิ่มเติมควบคู่กับรหัสกู้คืน ข้อมูลเหล่านี้โดยทั่วไปไม่กระทบต่อความปลอดภัย จึงไม่ต้องการการป้องกันเท่ารหัสกู้คืน แต่ยังคงลดความเป็นส่วนตัวและต้องมีการปกป้องบางส่วน</p>
<p>กระเป๋าเงินเกือบทั้งหมดที่ใช้ explicit paths ปัจจุบันใช้ output script descriptors (เรียกสั้น ๆ ว่า descriptors) ตามที่กำหนดใน BIPs 380, 381, 382, 383, 384, 385, 386 และ 389 โดย descriptors ใช้อธิบาย script และ keys (หรือ key paths) ที่ควรใช้งานร่วมกับมัน</p>
<table>
<thead>
<tr>
<th>Descriptor</th>
<th>Explanation</th>
</tr>
</thead>
<tbody><tr>
<td><code>pkh(02c6…​9ee5)</code></td>
<td>P2PKH script สำหรับ public key ที่ให้มา</td>
</tr>
<tr>
<td><code>sh(multi(2,022f…​2a01,03ac…​ccbe))</code></td>
<td>P2SH multisignature script ที่ต้องการลายเซ็นสองอันที่สอดคล้องกับ public key ทั้งสองนี้</td>
</tr>
<tr>
<td><code>pkh([d34db33f/44'/0'/0']xpub6ERA…​RcEL/1/*)</code></td>
<td>P2PKH scripts สำหรับ BIP32 path <code>d34db33f</code> โดยใช้ extended public key (xpub) ที่ path <code>M/44'/0'/0'</code> ซึ่งคือ <code>xpub6ERA…​RcEL</code> และใช้ keys ที่ path <code>M/1/*</code> ของ xpub นั้น</td>
</tr>
</tbody></table>
<p>เป็นเวลานานแล้วที่กระเป๋าเงิน (wallet applications) ที่ออกแบบมาเพื่อใช้งานกับ single signature scripts เพียงอย่างเดียว มักใช้ implicit paths ส่วนกระเป๋าเงินที่ออกแบบมาสำหรับ multisignature หรือสคริปต์ขั้นสูงอื่น ๆ นั้น กำลังหันมาใช้ explicit paths โดยใช้ descriptors มากขึ้นเรื่อย ๆ สำหรับแอปพลิเคชันที่รองรับทั้งสองแบบ มักจะปฏิบัติตามมาตรฐานของ implicit paths และในขณะเดียวกันก็ให้การรองรับ descriptors ด้วย</p>
<h2>เทคโนโลยีของกระเป๋าเงิน (A Wallet Technology Stack in Detail)</h2>
<p>นักพัฒนากระเป๋าเงินสมัยใหม่สามารถเลือกใช้เทคโนโลยีหลายรูปแบบเพื่อช่วยผู้ใช้ในการสร้างและจัดการการสำรองข้อมูล โดยทุกปีจะมีโซลูชันใหม่ ๆ เกิดขึ้น แทนที่จะลงลึกในรายละเอียดของแต่ละตัวเลือกที่อธิบายไปก่อนหน้านี้ในบทนี้ เราจะเน้นที่ชุดเทคโนโลยี (technology stack) ที่นิยมใช้อย่างแพร่หลายในกระเป๋าเงิน ณ ต้นปี 2023 ได้แก่:</p>
<ul>
<li>BIP39 recovery codes</li>
<li>BIP32 HD key derivation</li>
<li>BIP44-style implicit paths</li>
</ul>
<p>มาตรฐานเหล่านี้มีมาตั้งแต่ปี 2014 หรือก่อนหน้านั้น และสามารถหาข้อมูลเพิ่มเติมเพื่อนำมาใช้งานได้ไม่ยาก อย่างไรก็ตาม หากคุณสนใจทดลองสิ่งใหม่ ๆ เราแนะนำให้ศึกษามาตรฐานสมัยใหม่ที่อาจเพิ่มฟีเจอร์หรือความปลอดภัยให้มากขึ้นได้</p>
<h3>BIP39 Recovery Codes</h3>
<p>BIP39 recovery codes คือ ลำดับคำ (word sequences) ที่ใช้แทนตัวเลขสุ่ม เพื่อทำหน้าที่เป็น seed สำหรับการสร้างกระเป๋าเงินแบบกำหนดค่าได้ล่วงหน้า (deterministic wallet) ลำดับคำชุดเดียวก็เพียงพอที่จะสร้าง seed ใหม่ และสามารถสร้างกุญแจทั้งหมดที่เกี่ยวข้อง (derived keys) ได้</p>
<p>แอปกระเป๋าเงินที่รองรับ deterministic wallets ด้วย BIP39 recovery codes จะให้ผู้ใช้บันทึกลำดับคำจำนวน 12–24 คำ เมื่อสร้างกระเป๋าเงินครั้งแรก ลำดับคำเหล่านี้ทำหน้าที่เป็น การสำรองข้อมูลของกระเป๋าเงิน (wallet backup) และสามารถใช้กู้คืนหรือสร้างกุญแจทั้งหมดใหม่ได้ ไม่ว่าจะใช้แอปเดียวกันหรือแอปกระเป๋าเงินอื่นที่รองรับมาตรฐานเดียวกัน</p>
<p>รหัสกู้คืน (recovery codes) ทำให้การสำรองข้อมูลสะดวกขึ้น เพราะอ่านง่าย และสามารถถ่ายทอดหรือจดบันทึกได้อย่างถูกต้อง</p>
<blockquote>
<p>Tip:รหัสกู้คืน (recovery codes) มักถูกเข้าใจผิดว่าเหมือนกับ “brainwallets” แต่จริง ๆ แล้วไม่เหมือนกัน ความแตกต่างหลักคือ</p>
<ul>
<li>Brainwallet → เป็นคำที่ผู้ใช้เลือกขึ้นมาเอง</li>
<li>Recovery code → เป็นคำที่ถูกสุ่มสร้างขึ้นโดยกระเป๋าเงิน แล้วแสดงให้ผู้ใช้บันทึก</li>
</ul>
<p>ความแตกต่างนี้สำคัญมาก เพราะทำให้ recovery codes มีความปลอดภัยกว่ามาก เนื่องจากมนุษย์มักจะไม่สามารถสร้างความสุ่มที่แท้จริงได้ดีนัก</p>
</blockquote>
<p>โปรดทราบว่า BIP39 เป็นหนึ่งในการนำมาตรฐานรหัสกู้คืน (recovery code standard) มาประยุกต์ใช้ โดย BIP39 ถูกเสนอโดยบริษัทผู้อยู่เบื้องหลัง Trezor hardware wallet และสามารถใช้งานร่วมกับแอปกระเป๋าเงินอื่น ๆ ได้มากมาย แม้ว่าจะไม่ใช่ทุกแอปที่จะรองรับก็ตาม</p>
<h4>การสร้างรหัสสำรอง (Generating a Recovery Code)</h4>
<p>รหัสกู้คืน (Recovery codes) ถูกสร้างขึ้นโดยอัตโนมัติจากแอปกระเป๋าเงิน โดยใช้กระบวนการมาตรฐานที่กำหนดไว้ใน BIP39 ขั้นตอนการสร้างมีดังนี้:</p>
<ol>
<li>สร้างลำดับสุ่ม (entropy) ความยาวระหว่าง 128 ถึง 256 บิต</li>
<li>สร้างค่า checksum ของลำดับสุ่ม โดยการนำบิตแรกจำนวน (ความยาว entropy ÷ 32) ของค่า SHA256 hash มาใช้</li>
<li>เติมค่า checksum ต่อท้ายลำดับ entropy</li>
<li>แบ่งผลลัพธ์ออกเป็นกลุ่มย่อย ความยาว 11 บิตต่อกลุ่ม</li>
<li>นำค่า 11 บิตแต่ละกลุ่มไปแมปกับคำหนึ่งคำจาก พจนานุกรมมาตรฐานที่มี 2,048 คำ</li>
<li>ผลลัพธ์สุดท้ายก็คือ รหัสกู้คืน (recovery code) ซึ่งอยู่ในรูปแบบลำดับคำ (word sequence)<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0504.png" alt="image"></li>
</ol>
<h5>BIP39:Entropy และความยาวของคำ</h5>
<table>
<thead>
<tr>
<th align="center">Entropy (bits)</th>
<th align="center">Checksum (bits)</th>
<th align="center">Entropy + checksum (bits)</th>
<th align="center">Recovery code words</th>
</tr>
</thead>
<tbody><tr>
<td align="center">128</td>
<td align="center">4</td>
<td align="center">132</td>
<td align="center">12</td>
</tr>
<tr>
<td align="center">160</td>
<td align="center">5</td>
<td align="center">165</td>
<td align="center">15</td>
</tr>
<tr>
<td align="center">192</td>
<td align="center">6</td>
<td align="center">198</td>
<td align="center">18</td>
</tr>
<tr>
<td align="center">224</td>
<td align="center">7</td>
<td align="center">231</td>
<td align="center">21</td>
</tr>
<tr>
<td align="center">256</td>
<td align="center">8</td>
<td align="center">264</td>
<td align="center">24</td>
</tr>
</tbody></table>
<h4>จากรหัสกู้คืนสู่seed (From recovery code to seed)</h4>
<p>รหัสกู้คืน (recovery code) แทนค่า entropy ที่มีความยาวระหว่าง 128 ถึง 256 บิต จากนั้น entropy จะถูกใช้สร้าง seed ที่ยาวกว่า (512 บิต) ผ่านฟังก์ชัน key-stretching ชื่อ PBKDF2 ซึ่ง seed ที่ได้จะถูกนำไปสร้างกระเป๋าเงินแบบกำหนดค่าได้ล่วงหน้า (deterministic wallet) และสร้างกุญแจอนุพันธ์ (derived keys) ต่อไป</p>
<p>ฟังก์ชัน key-stretching จะรับพารามิเตอร์สองค่า ได้แก่ entropy และ salt ปกติ salt มีหน้าที่ป้องกันการโจมตีแบบ brute-force โดยทำให้การสร้างตารางค้นหาทำได้ยากขึ้น แต่ในมาตรฐาน BIP39 salt ยังใช้อนุญาตให้ผู้ใช้เพิ่ม passphrase ซึ่งเป็นปัจจัยด้านความปลอดภัยเพิ่มเติมสำหรับการป้องกัน seed (จะอธิบายรายละเอียดในหัวข้อ Optional passphrase in BIP39)</p>
<blockquote>
<p>Tip: ฟังก์ชัน key-stretching ของ BIP39 ใช้การแฮช 2,048 รอบ ทำให้การโจมตีแบบ brute-force ด้วยซอฟต์แวร์ทำได้ยากขึ้นเล็กน้อย แต่ฮาร์ดแวร์เฉพาะทาง (special-purpose hardware) จะไม่ได้รับผลกระทบมากนัก สำหรับผู้โจมตีที่ต้องเดา recovery code ทั้งหมด ความยาวขั้นต่ำ 128 บิตของรหัสก็เพียงพอที่จะมอบความปลอดภัยสูงแล้ว อย่างไรก็ตาม หากผู้โจมตีรู้บางส่วนของรหัส ฟังก์ชัน key-stretching จะช่วยเพิ่มความปลอดภัยโดยทำให้การตรวจสอบความเป็นไปได้ของรหัสแต่ละแบบช้าลง</p>
</blockquote>
<p>อย่างไรก็ดี พารามิเตอร์ของ BIP39 ถูกมองว่าค่อนข้างอ่อนแอเมื่อเทียบกับมาตรฐานสมัยใหม่ แม้ในช่วงที่เผยแพร่เมื่อเกือบสิบปีก่อน ก็เพื่อรองรับอุปกรณ์ hardware signing devices ที่มี CPU กำลังต่ำ มาตรฐานทางเลือกบางตัว เช่น Aezeed ใช้การแฮช 32,768 รอบผ่านอัลกอริทึม Scrypt ที่ซับซ้อนกว่า แม้ว่าจะไม่สะดวกในการใช้งานบนอุปกรณ์ฮาร์ดแวร์</p>
<p>กระบวนการดังกล่าวในขั้นตอนที่ 7 ถึง 10 เป็นการต่อเนื่องจากหัวข้อ Generating a recovery code ที่อธิบายไปก่อนหน้านี้:</p>
<ol start="7">
<li>พารามิเตอร์แรก ของฟังก์ชัน key-stretching PBKDF2 คือ entropy ที่ได้มาจาก ขั้นตอนที่ 6</li>
<li>พารามิเตอร์ที่สอง ของ PBKDF2 คือ salt โดย salt นี้ถูกสร้างขึ้นจากสตริงคงที่ "mnemonic" ต่อเข้ากับสตริง passphrase ที่ผู้ใช้จะใส่เพิ่ม (ซึ่งเป็นทางเลือก ไม่จำเป็นต้องใส่)</li>
<li>PBKDF2 จะทำการขยาย (stretch) recovery code และ salt ด้วยการแฮชจำนวน 2,048 รอบ โดยใช้อัลกอริทึม HMAC-SHA512 และสร้างค่าผลลัพธ์สุดท้ายเป็นค่า 512 บิต</li>
<li>ค่าที่ได้ซึ่งเป็น 512 บิต นี้ก็คือ seed<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0505.png" alt="image"></li>
</ol>
<h5>128-bit entropy BIP39 recovery code, no passphrase, resulting seed</h5>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1759396589355-YAKIHONNES3.png" alt="image"></p>
<h5>128-bit entropy BIP39 recovery code, with passphrase, resulting seed</h5>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1759410306820-YAKIHONNES3.png" alt="image"></p>
<h5>256-bit entropy BIP39 recovery code, no passphrase, resulting seed</h5>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1759410572591-YAKIHONNES3.png" alt="image"></p>
<h4>คุณต้องการ Entropy มากแค่ไหน?</h4>
<p>BIP32 อนุญาตให้ seed มีค่าได้ตั้งแต่ 128 ถึง 512 บิต BIP39 รับค่าได้ตั้งแต่ 128 ถึง 256 บิต; Electrum v2 รับค่าได้ 132 บิต; Aezeed รับค่าได้ 128 บิต; SLIP39 รับค่าได้ 128 หรือ 256 บิต ความแตกต่างของตัวเลขเหล่านี้ทำให้ไม่ชัดเจนว่าต้องใช้ entropy เท่าไรถึงจะปลอดภัย เราจะพยายามอธิบายให้กระจ่าง</p>
<p>extended private key ของ BIP32 ประกอบด้วยคีย์ขนาด 256 บิตและ chain code ขนาด 256 บิต รวมทั้งหมด 512 บิต นั่นหมายความว่ามีคีย์ส่วนตัวแบบขยายได้สูงสุด 2^512 แบบ หากคุณเริ่มต้นด้วย entropy ที่มากกว่า 512 บิต คุณก็ยังจะได้ extended private key ที่มี entropy เพียง 512 บิตอยู่ดี—ดังนั้นจึงไม่มีประโยชน์ที่จะใช้มากกว่า 512 บิต แม้ว่าในบรรดามาตรฐานที่กล่าวมาจะอนุญาตให้ทำก็ตาม</p>
<p>อย่างไรก็ตาม แม้ว่าจะสามารถสร้างคีย์ส่วนตัวแบบขยาย (extended private key) ได้มากถึง 2^512 แบบ แต่คีย์ส่วนตัวจริง ๆ (regular private key) ที่ใช้งานได้มีเพียงประมาณ 2^256 แบบเท่านั้น—และคีย์เหล่านี้เองที่เป็นตัวปกป้องบิตคอยน์ของคุณ ซึ่งหมายความว่า ถึงคุณจะใช้ entropy เกิน 256 บิตในการสร้าง seed สุดท้ายแล้วคีย์ส่วนตัวที่ได้ก็ยังมี entropy เพียง 256 บิตอยู่ดี แม้ว่าในอนาคตอาจมีโปรโตคอลบิตคอยน์บางชนิดที่สามารถนำ entropy ส่วนเกินใน extended key มาใช้เพื่อเพิ่มความปลอดภัย แต่ในปัจจุบันยังไม่มีการใช้งานจริง</p>
<p>ระดับความปลอดภัยของ public key บิตคอยน์อยู่ที่ 128 บิต หมายความว่าผู้โจมตีต้องคำนวณราว 2^128 ครั้งบน elliptic curve จึงจะหาคีย์ส่วนตัวได้ ดังนั้นการใช้ entropy เกิน 128 บิตไม่ได้เพิ่มประโยชน์ด้านความปลอดภัย ตราบใดที่คีย์ส่วนตัวถูกสุ่มอย่างทั่วถึงในช่วง 2^256 ทั้งหมด</p>
<p>มีประโยชน์เพิ่มเติมอย่างหนึ่งจาก entropy ที่มากขึ้น: ถ้าผู้โจมตีเห็น recovery code ของคุณบางส่วน (แต่ไม่ใช่ทั้งหมด) ยิ่ง entropy มาก การที่เขาจะเดาส่วนที่เหลือก็จะยากขึ้น ยกตัวอย่างเช่น ถ้าผู้โจมตีเห็นครึ่งหนึ่งของโค้ด 128 บิต (64 บิต) ก็มีความเป็นไปได้ที่เขาจะ brute force อีก 64 บิตที่เหลือได้ แต่ถ้าเขาเห็นครึ่งหนึ่งของโค้ด 256 บิต (128 บิต) ก็ไม่เป็นไปได้ที่เขาจะ brute force ส่วนที่เหลือได้ เราไม่แนะนำให้พึ่งพาการป้องกันแบบนี้—ควรเก็บ recovery code ของคุณให้ปลอดภัย หรือใช้วิธีอย่าง SLIP39 ที่ให้คุณสามารถกระจาย recovery code ไว้หลายที่ โดยไม่ต้องอาศัยความปลอดภัยจากโค้ดใดโค้ดหนึ่งเพียงอย่างเดียว</p>
<p>ณ ปี 2023 กระเป๋าสตางค์สมัยใหม่ส่วนใหญ่สร้าง entropy ขนาด 128 บิตสำหรับ recovery code ของพวกเขา (หรือค่าที่ใกล้เคียง 128 เช่น Electrum v2 ที่ใช้ 132 บิต)</p>
<h4>passphrase ใน BIP39</h4>
<p>มาตรฐาน BIP39 อนุญาตให้ใส่ passphrase เสริมเพื่อสร้าง seed  หากไม่ใส่ จะใช้ salt เป็นสตริงคงที่ "mnemonic" ทำให้ recovery code ใด ๆ ให้ผลเป็น seed เดียวตามมาตรฐาน แต่เมื่อมี passphrase ใด ๆ เข้ามา จะได้ seed ที่ต่างจากเดิม: ทุก passphrase ที่เป็นไปได้จะให้ seed คนละค่า ไม่มีค่าใดที่ถือว่า “ผิด” ดังนั้นรหัสกู้คืนชุดเดียวสามารถจับคู่กับ passphrase หลายค่าได้ ผลคือมีชุดกระเป๋า (wallets) ขนาดมหาศาล ขยายได้ถึงระดับประมาณ 2^512 ทำให้การเดาแบบ brute-force เพื่อไปพบกระเป๋าที่มีการใช้งานจริงเป็นสิ่งที่เป็นไปไม่ได้ในทางปฏิบัติ.</p>
<blockquote>
<p>Tip: ใน BIP39 ไม่มี passphrase ที่ “ผิด” ทุก passphrase จะนำไปสู่กระเป๋าสตางค์บางใบ ซึ่งหากไม่เคยถูกใช้งานมาก่อน กระเป๋าสตางค์นั้นก็จะว่างเปล่า</p>
</blockquote>
<p>Passphrase แบบเลือกใช้จะสร้างคุณสมบัติที่สำคัญสองประการ:</p>
<ul>
<li>มีสิ่งที่จดจำได้ ที่ทำให้ recovery code ใช้งานไม่ได้ด้วยตัวมันเอง ปกป้อง recovery code จากการถูกขโมยโดยโจรทั่วไป สำหรับการป้องกันจากโจรที่มีความรู้ด้านเทคนิค คุณจำเป็นต้องใช้ passphrase ที่แข็งแกร่งมาก</li>
<li>รูปแบบหนึ่งของ plausible deniability หรือ “กระเป๋าลับ” (duress wallet) ซึ่ง passphrase ที่เลือกจะนำไปยังกระเป๋าที่มีเงินจำนวนน้อย ใช้เพื่อเบี่ยงเบนความสนใจของผู้โจมตีจาก “กระเป๋าจริง” ที่เก็บเงินส่วนใหญ่</li>
</ul>
<p>สิ่งสำคัญที่ควรทราบคือ การใช้ passphrase ยังนำมาซึ่งความเสี่ยงของการสูญเสีย:</p>
<ul>
<li>หากเจ้าของกระเป๋าไม่สามารถใช้งานได้หรือเสียชีวิตไป และไม่มีใครรู้ passphrase ค่า seed จะไร้ประโยชน์ และเงินทั้งหมดที่เก็บในกระเป๋าจะสูญหายไปตลอดกาล</li>
<li>ในทางกลับกัน หากเจ้าของทำการสำรอง passphrase ไว้ในที่เดียวกับ seed มันก็จะทำลายวัตถุประสงค์ของการมีปัจจัยที่สอง</li>
</ul>
<p>แม้ว่า passphrase จะมีประโยชน์มาก แต่ควรใช้งานร่วมกับกระบวนการที่วางแผนอย่างรอบคอบสำหรับการสำรองและการกู้คืน โดยคำนึงถึงความเป็นไปได้ในการมีชีวิตต่อจากเจ้าของ และเปิดโอกาสให้ครอบครัวสามารถกู้คืนได้</p>
<h3>การสร้าง HD Wallet จาก Seed</h3>
<p>กระเป๋าเงินแบบ HD ถูกสร้างจาก root seed เดียว ซึ่งเป็นตัวเลขสุ่มขนาด 128, 256 หรือ 512 บิต โดยทั่วไป seed นี้จะถูกสร้างขึ้นโดยแอปหรือถอดรหัสมาจาก recovery code ตามที่อธิบายไว้ก่อนหน้านี้</p>
<p>กุญแจทุกดอกในกระเป๋าเงิน HD จะถูกอนุพันธ์อย่างกำหนดได้จาก root seed เดียวกัน ส่งผลให้สามารถสร้างกระเป๋าเงิน HD ทั้งหมดใหม่ได้จาก seed ชุดเดียว ในระบบที่เข้ากันได้ วิธีนี้ทำให้การ สำรอง, กู้คืน, ส่งออก และ นำเข้ากระเป๋าเงิน ซึ่งอาจมีจำนวนกุญแจเป็นพันหรือเป็นล้าน ดำเนินการได้สะดวกเพียงแค่เก็บรักษา recovery code ที่มาจาก root seed เท่านั้น</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0506.png" alt="image"></p>
<p>root seed จะถูกป้อนเข้าไปในอัลกอริทึม HMAC-SHA512 และค่าแฮชที่ได้จะถูกนำมาใช้สร้าง master private key (m) และ master chain code (c)</p>
<p>จากนั้น master private key (m) จะสร้าง master public key (M) ที่สอดคล้องกัน โดยใช้กระบวนการ elliptic curve multiplication แบบปกติ คือ m × G ตามที่เราเห็นไปแล้วใน public_key_derivation</p>
<p>ส่วน master chain code (c) จะถูกใช้เพื่อเพิ่ม entropy ในฟังก์ชันที่สร้าง child keys จาก parent keys ซึ่งเราจะได้เห็นในหัวข้อถัดไป</p>
<h4>Private child key derivation</h4>
<p>กระเป๋าเงิน HD ใช้ฟังก์ชัน child key derivation (CKD) เพื่อสร้าง child keys จาก parent keys</p>
<p>ฟังก์ชัน CKD จะอิงกับ one-way hash function ที่รวมข้อมูลดังนี้:</p>
<ul>
<li>กุญแจ private หรือ public ของ parent (uncompressed key)</li>
<li>chain code (256 บิต)</li>
<li>หมายเลขดัชนี (index number) (32 บิต)</li>
</ul>
<p>chain code ถูกใช้เพื่อเพิ่มข้อมูลสุ่มเชิงกำหนด (deterministic random data) ลงในกระบวนการ เพื่อให้การรู้แค่ index และ child key ไม่เพียงพอที่จะสร้าง child keys อื่น ๆ ได้ การรู้เพียง child key ไม่สามารถหาพี่น้อง (siblings) ของมันได้ เว้นแต่จะมี chain code ด้วย โดย chain code เริ่มต้น (ที่ root ของ tree) จะมาจาก seed ในขณะที่ chain codes ถัดไปจะถูกอนุพันธ์มาจาก chain code ของ parent แต่ละตัว</p>
<p>สามองค์ประกอบนี้ (parent key, chain code, index) จะถูกนำมารวมกันและทำการ hash เพื่อสร้าง child keys ดังนี้:</p>
<ul>
<li>parent public key, chain code และ index number จะถูกนำมารวมกันแล้วทำการ hash ด้วยอัลกอริทึม HMAC-SHA512 เพื่อสร้างค่าแฮช 512 บิต</li>
<li>ค่าแฮช 512 บิตนี้จะถูกแบ่งออกเป็นสองส่วน ส่วนละ 256 บิต<ul>
<li>ครึ่งขวา (256 บิต) จะกลายเป็น chain code สำหรับ child</li>
<li>ครึ่งซ้าย (256 บิต) จะถูกนำไปบวกกับ parent private key เพื่อสร้าง child private key</li>
</ul>
</li>
</ul>
<p>จากรูปข้างล่างเราจะเห็นตัวอย่างที่ใช้ index = 0 เพื่อสร้าง child ตัวแรก (zero child) ของ parent<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0507.png" alt="image"></p>
<p>การเปลี่ยนค่า index ช่วยให้สามารถขยายจากกุญแจแม่ (parent key) เพื่อสร้างกุญแจลูก (child keys) ในลำดับได้ เช่น Child 0, Child 1, Child 2 และต่อไปเรื่อย ๆ โดยกุญแจแม่แต่ละดอกสามารถมีลูกได้สูงสุด 2,147,483,647 ดอก (2³¹) ซึ่งคิดเป็นครึ่งหนึ่งของช่วงค่า 2³² ทั้งหมด อีกครึ่งหนึ่งถูกสงวนไว้สำหรับรูปแบบการอนุพันธ์พิเศษที่จะอธิบายในบทถัดไป</p>
<p>เมื่อกระบวนการนี้ถูกทำซ้ำในระดับถัดไป แต่ละกุญแจลูกก็สามารถกลายเป็นกุญแจแม่และสร้างกุญแจลูกของมันเองต่อไปได้เช่นกัน ทำให้เกิดการขยายแบบลำดับชั้นได้อย่างไม่จำกัด (infinite generations)</p>
<h4>Using derived child keys</h4>
<p>child private keys ไม่สามารถแยกความแตกต่างได้จากกุญแจแบบไม่กำหนดล่วงหน้า (nondeterministic หรือกุญแจสุ่ม) เนื่องจากฟังก์ชัน derivation เป็น one-way function ดังนั้น child key ไม่สามารถถูกใช้เพื่อหากุญแจ parent ได้ และ child key ก็ไม่สามารถถูกใช้เพื่อหาพี่น้อง (siblings) ได้เช่นกัน หากคุณมีกุญแจลูกลำดับที่ n คุณจะไม่สามารถหาพี่น้องของมัน เช่น กุญแจ n–1 หรือ n+1 หรือกุญแจอื่น ๆ ที่อยู่ในลำดับได้ มีเพียง parent key และ chain code เท่านั้น ที่สามารถอนุพันธ์ลูกทั้งหมดออกมาได้ หากไม่มี child chain code กุญแจลูกก็ไม่สามารถถูกใช้เพื่อสร้างกุญแจหลาน (grandchildren) ได้เช่นกัน คุณจำเป็นต้องมีทั้ง child private key และ child chain code เพื่อเริ่มต้นสาขาใหม่และสร้าง grandchildren</p>
<p>แล้ว child private key สามารถใช้ทำอะไรได้บ้าง? มันสามารถถูกใช้เพื่อสร้าง public key และ Bitcoin address และสามารถใช้เพื่อ เซ็นธุรกรรม (sign transactions) เพื่อใช้จ่าย Bitcoin ที่ถูกส่งเข้ามายัง address นั้นได้</p>
<blockquote>
<p>Tip: child private key, public key ที่สอดคล้องกัน และ Bitcoin address ทั้งหมดนี้ไม่สามารถแยกความแตกต่างได้จากกุญแจและ address ที่ถูกสร้างขึ้นแบบสุ่ม ความจริงที่ว่ามันเป็นส่วนหนึ่งของลำดับจะไม่สามารถมองเห็นได้จากภายนอกฟังก์ชันของ HD wallet ที่สร้างมันขึ้นมา และเมื่อมันถูกสร้างขึ้นแล้ว มันก็ทำงานเหมือนกับกุญแจ “ปกติ” ทุกประการ</p>
</blockquote>
<h4>Extended keys</h4>
<p>ตามที่เราได้เห็นไปก่อนหน้านี้ ฟังก์ชัน key derivation สามารถถูกใช้เพื่อสร้าง children ได้ในทุกระดับของ tree โดยอ้างอิงจากข้อมูลนำเข้าสามส่วน: key, chain code และ index ของ child ที่ต้องการ โดยองค์ประกอบที่สำคัญที่สุดสองอย่างคือ key และ chain code ซึ่งเมื่อรวมกันแล้วจะถูกเรียกว่า extended key คำว่า extended key อาจถูกมองว่าเป็น extensible key ก็ได้ เพราะกุญแจลักษณะนี้สามารถถูกใช้เพื่อสร้าง children ได้</p>
<p>Extended keys จะถูกเก็บและแสดงผลในรูปแบบง่าย ๆ คือการนำ key มาต่อกับ chain code ซึ่งมีอยู่สองประเภทหลัก ได้แก่:</p>
<ul>
<li><p>Extended private key คือการรวมกันของ private key และ chain code ที่สามารถใช้สร้าง child private keys ได้ (และจากนั้นก็สร้าง child public keys ได้อีกต่อหนึ่ง)</p>
</li>
<li><p>Extended public key คือการรวมกันของ public key และ chain code ที่สามารถใช้สร้างได้เฉพาะ child public keys เท่านั้น ตามที่อธิบายไว้ใน public_key_derivation</p>
</li>
</ul>
<p>ลองนึกภาพ extended key เป็นเสมือนรากของกิ่งก้าน (branch) ในโครงสร้างต้นไม้ของ HD wallet เมื่อคุณมีรากนี้แล้ว ก็สามารถแตกกิ่งก้านที่เหลือต่อไปได้ โดย extended private key จะสร้างกิ่งก้านที่สมบูรณ์ได้ทั้งหมด ขณะที่ extended public key จะสร้างได้เพียงกิ่งก้านที่ประกอบด้วยเฉพาะ public keys เท่านั้น</p>
<p>Extended keys ยังถูกเข้ารหัสด้วย base58check เพื่อให้ง่ายต่อการส่งออกและนำเข้าไปยังกระเป๋าเงินอื่น ๆ ที่รองรับ BIP32 โดยการเข้ารหัส base58check สำหรับ extended keys จะใช้หมายเลขเวอร์ชันพิเศษ ทำให้เมื่อถูกเข้ารหัสออกมาเป็นอักขระ base58 จะขึ้นต้นด้วย prefix ที่จดจำง่ายอย่าง "xprv" และ "xpub" ทั้งนี้ เนื่องจาก extended key บรรจุข้อมูลมากกว่าที่อยู่ (address) ปกติหลายเท่า มันจึงมีความยาวมากกว่าสตริงที่เข้ารหัสด้วย base58check แบบอื่น ๆ ที่เราเคยเห็นมาก่อนหน้านี้</p>
<p>นี่คือตัวอย่างของ extended private key ที่เข้ารหัสด้วย base58check:</p>
<pre><code>xprv9tyUQV64JT5qs3RSTJkXCWKMyUgoQp7F3hA1xzG6ZGu6u6Q9VMNjGr67Lctvy5P8oyaYAL9CAWrUE9i6GoNMKUga5biW6Hx4tws2six3b9c
</code></pre>
<p>นี่คือตัวอย่างของ extended public key ที่เข้ารหัสด้วย base58check ซึ่งตรงกับ private key ข้างต้น:</p>
<pre><code>xpub67xpozcx8pe95XVuZLHXZeG6XWXHpGq6Qv5cmNfi7cS5mtjJ2tgypeQbBs2UAR6KECeeMVKZBPLrtJunSDMstweyLXhRgPxdp14sk9tJPW9
</code></pre>
<h4>การสร้าง Public child key derivation</h4>
<p>ดังที่กล่าวไว้ก่อนหน้านี้ คุณสมบัติที่มีประโยชน์อย่างมากของ HD wallet คือความสามารถในการสร้างกุญแจสาธารณะลูกได้จากกุญแจสาธารณะหลักโดยไม่ต้องมี private key อยู่ด้วย วิธีนี้ทำให้มีสองแนวทางในการได้มาซึ่งกุญแจสาธารณะลูก: สร้างจาก private child key หรือสร้างโดยตรงจาก extended public key ของกุญแจหลัก</p>
<p>Extended public key สามารถใช้สร้างกุญแจสาธารณะทั้งหมด (แต่เฉพาะกุญแจสาธารณะเท่านั้น) ในสาขาหนึ่งของโครงสร้าง HD wallet ได้ ทางลัดนี้เปิดทางให้สร้างระบบที่ทำงานบนข้อมูลสาธารณะเพียงอย่างเดียว — เซิร์ฟเวอร์หรือแอปพลิเคชันสามารถมีสำเนา extended public key แต่ไม่ได้เก็บ private key ใด ๆ ไว้ การติดตั้งแบบนี้อนุญาตให้เซิร์ฟเวอร์สร้างกุญแจสาธารณะและที่อยู่บิตคอยน์ได้ไม่จำกัด ขณะเดียวกันก็ไม่สามารถใช้จ่ายเงินจากที่อยู่เหล่านั้นได้</p>
<p>เมื่อต้องการใช้เงินจริง ให้ย้ายกระบวนการลงนามไปยังเครื่องที่ปลอดภัยกว่า ซึ่งเก็บ extended private key หรือ private keys ไว้ เสียง่ายคือ เซิร์ฟเวอร์สาธารณะทำหน้าที่ “สร้างที่อยู่” และมอบข้อมูลให้ลูกค้า/ผู้ใช้ ส่วนการลงนามธุรกรรมทำบนอุปกรณ์ที่มีความปลอดภัยสูงกว่า</p>
<p>การประยุกต์ใช้งานทั่วไปของแนวทางนี้คือการติดตั้ง extended public key บนเว็บเซิร์ฟเวอร์ของระบบอีคอมเมิร์ซ เว็บเซิร์ฟเวอร์สามารถสร้างที่อยู่บิตคอยน์ใหม่สำหรับแต่ละคำสั่งซื้อหรือแต่ละตะกร้าสินค้าได้ทันที โดยไม่ต้องเก็บ private key ไว้บนเซิร์ฟเวอร์ที่เสี่ยงต่อการถูกโจมตี หากไม่มี HD wallet ตัวเลือกเดียวที่มีจะเป็นการสร้างที่อยู่จำนวนมากล่วงหน้าในเซิร์ฟเวอร์แยกที่ปลอดภัย แล้วคอยโหลดเข้ามาใช้งาน ซึ่งยุ่งยากและต้องดูแลสต็อกที่อยู่ให้เพียงพออยู่ตลอดเวลา</p>
<h4>ระวังช่องว่าง (Mind the Gap)</h4>
<p>Extended public key สามารถสร้างกุญแจลูกได้โดยตรงมากถึงประมาณ 4 พันล้านกุญแจ ซึ่งถือว่าเกินพอสำหรับการใช้งานในร้านค้าหรือแอปพลิเคชันใด ๆ อยู่แล้ว อย่างไรก็ตาม การให้ wallet สร้างกุญแจทั้ง 4 พันล้านดอกและสแกนบล็อกเชนทั้งหมดเพื่อหาธุรกรรมที่เกี่ยวข้องนั้นแทบจะเป็นไปไม่ได้ในทางปฏิบัติ เนื่องจากจะใช้เวลามหาศาล ด้วยเหตุนี้ wallet ส่วนใหญ่จึงเลือกสร้างกุญแจเพียงไม่กี่ดอกในแต่ละครั้ง สแกนหาธุรกรรมที่ตรงกับกุญแจเหล่านั้น และเมื่อกุญแจที่สร้างไปก่อนหน้านี้ถูกใช้งานแล้ว จึงสร้างกุญแจใหม่ต่อไปตามลำดับ</p>
<p>ตัวอย่างเช่น wallet ของ Alice อาจสร้างกุญแจขึ้นมา 100 ดอก เมื่อพบว่ามีการชำระเงินไปยังกุญแจแรก มันก็จะสร้างกุญแจดอกที่ 101 ต่อทันที</p>
<p>บางครั้งอาจมีกรณีที่ wallet แจกกุญแจให้กับใครบางคน แต่ภายหลังคู่สัญญากลับไม่ทำการชำระเงิน ทำให้เกิด “ช่องว่าง” (gap) ในสายกุญแจ ซึ่งโดยทั่วไปไม่ถือว่าเป็นปัญหา ตราบใดที่ wallet ยังคงสร้างกุญแจถัดไปหลังช่องว่างนั้นต่อไป กระบวนการสแกนก็จะยังคงค้นพบธุรกรรมได้ในอนาคต การกำหนดจำนวนกุญแจที่สามารถสร้างไว้ล่วงหน้าโดยยังไม่ถูกใช้งาน และต่อเนื่องกันได้สูงสุดโดยไม่ก่อให้เกิดปัญหา เรียกว่า gap limit</p>
<p>เมื่อ wallet สร้างกุญแจจนถึงขีดจำกัด gap limit แล้ว แต่ไม่มีธุรกรรมเข้ามาที่กุญแจเหล่านั้น มันจะต้องเลือกวิธีรับมือเมื่อมีการขอกุญแจใหม่ในอนาคต ซึ่งมีอยู่ 3 แนวทางหลักคือ:</p>
<ul>
<li>ปฏิเสธการสร้างกุญแจใหม่ – ทำให้ไม่สามารถรับการชำระเงินได้อีก วิธีนี้แม้ง่ายที่สุด แต่ก็เป็นตัวเลือกที่ไม่เหมาะสมที่สุด</li>
<li>สร้างกุญแจใหม่เกินกว่า gap limit – วิธีนี้รับประกันว่าทุกการชำระเงินจะได้ที่อยู่ใหม่ ไม่เกิดการใช้ที่อยู่ซ้ำ และเพิ่มความเป็นส่วนตัว อย่างไรก็ตาม หากต้องกู้ wallet จาก recovery code หรือหากนำ extended public key เดียวกันไปใช้กับซอฟต์แวร์อื่น ซอฟต์แวร์เหล่านั้นจะไม่สามารถเห็นการชำระเงินที่เกิดขึ้นหลังจากเกิน gap limit ได้ </li>
<li>แจกจ่ายกุญแจเก่าซ้ำ – ช่วยให้การกู้คืน wallet เป็นไปอย่างราบรื่น แต่แลกมาด้วยการลดทอนความเป็นส่วนตัวของเจ้าของกระเป๋าและคู่ธุรกรรม</li>
</ul>
<p>ระบบโอเพ่นซอร์สสำหรับร้านค้าออนไลน์ เช่น BTCPay Server แก้ปัญหานี้โดยการใช้ gap limit ที่มีค่ามหาศาล และจำกัดอัตราการสร้างใบแจ้งหนี้ (invoice) ขณะเดียวกันก็มีวิธีแก้ปัญหาเชิงแนวคิดอื่น ๆ ถูกเสนอขึ้นมา เช่น ให้ wallet ของผู้จ่ายสร้างธุรกรรมชั่วคราว (แต่ยังไม่กระจายสู่เครือข่าย) ไปยังที่อยู่ซ้ำก่อนที่จะได้รับที่อยู่ใหม่สำหรับธุรกรรมจริง อย่างไรก็ตาม วิธีเหล่านี้ยังไม่ถูกนำมาใช้จริงในระบบการผลิต ณ เวลาที่เขียนนี้</p>
<p>การใช้งานที่พบบ่อยอีกแบบหนึ่งคือ cold storage หรือ hardware signing device โดยในสถานการณ์นี้ extended private key จะถูกเก็บไว้อย่างปลอดภัยแบบออฟไลน์ เช่น บนกระดาษหรือบนอุปกรณ์ฮาร์ดแวร์ ในขณะที่ extended public key ถูกเก็บไว้ในระบบออนไลน์ ผู้ใช้จึงสามารถสร้างที่อยู่สำหรับการ “รับเงิน” ได้เรื่อย ๆ โดยไม่ต้องเสี่ยงเปิดเผย private key และเมื่อถึงเวลาที่ต้องใช้จ่ายเงิน ก็สามารถนำ extended private key มาสร้างและลงนามธุรกรรมบนซอฟต์แวร์ออฟไลน์หรืออุปกรณ์ฮาร์ดแวร์ได้โดยตรง</p>
<p>แผนภาพ “Extending a parent public key to create a child public key” จะแสดงให้เห็นกลไกการขยายกุญแจสาธารณะหลักเพื่อสร้างกุญแจสาธารณะลูกตามแนวคิดที่กล่าวมานี้<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0508.png" alt="image"></p>
<h4>การใช้ Extended Public Key บนร้านค้าออนไลน์</h4>
<p>มาดูกันว่า HD wallet ถูกนำไปใช้งานจริงอย่างไร ผ่านตัวอย่างร้านค้าออนไลน์ของ Gabriel</p>
<p>Gabriel เริ่มต้นทำร้านค้าออนไลน์เล็ก ๆ ของเขาเป็นงานอดิเรก โดยใช้ WordPress โฮสต์เองแบบง่าย ๆ ร้านค้ามีเพียงไม่กี่หน้าและฟอร์มสั่งซื้อที่ระบุที่อยู่บิตคอยน์เพียงหนึ่งเดียวสำหรับการชำระเงิน เขาใช้ที่อยู่บิตคอยน์แรกที่สร้างขึ้นจากกระเป๋าเงินส่วนตัวเป็นที่อยู่หลัก ลูกค้าส่งคำสั่งซื้อและโอนเงินไปยังที่อยู่นี้ ระบบจะส่งอีเมลแจ้งคำสั่งซื้อเพื่อให้ Gabriel ดำเนินการต่อ สำหรับคำสั่งซื้อเพียงไม่กี่ครั้งต่อสัปดาห์ วิธีนี้ก็ถือว่าเพียงพอ แม้ว่าจะมีข้อเสียด้านความเป็นส่วนตัวทั้งสำหรับ Gabriel เอง ลูกค้า และผู้ที่เขาส่งเงินต่อให้ก็ตาม</p>
<p>แต่เมื่อเวลาผ่านไป ร้านค้าเล็ก ๆ ของ Gabriel กลับได้รับความนิยมมากขึ้น คำสั่งซื้อหลั่งไหลเข้ามาจากลูกค้าในชุมชนท้องถิ่นจนเขาเริ่มจัดการไม่ทัน ปัญหาหลักคือคำสั่งซื้อทั้งหมดถูกส่งไปยังที่อยู่เดียวกัน ทำให้ยากต่อการจับคู่ธุรกรรมกับคำสั่งซื้อได้อย่างถูกต้อง โดยเฉพาะเมื่อมีหลายคำสั่งที่มียอดเงินเท่ากันเข้ามาในช่วงเวลาใกล้กัน อีกทั้งในธุรกรรมบิตคอยน์เอง ผู้รับสามารถระบุได้เพียงจำนวนเงินและที่อยู่ปลายทางเท่านั้น ไม่มีช่องสำหรับบันทึกหมายเลขใบแจ้งหนี้หรือข้อความอธิบายเพิ่มเติม</p>
<p>ทางออกของปัญหานี้มาจากการใช้ HD wallet ซึ่งสามารถสร้างกุญแจสาธารณะลูกจาก extended public key (xpub) โดยไม่ต้องใช้ private key Gabriel จึงสามารถนำ xpub ไปติดตั้งไว้บนเว็บไซต์ของร้านค้า และใช้สร้างที่อยู่ใหม่ที่ไม่ซ้ำสำหรับคำสั่งซื้อแต่ละรายการ วิธีนี้ไม่เพียงช่วยให้การจับคู่ธุรกรรมกับคำสั่งซื้อเป็นไปอย่างแม่นยำ แต่ยังช่วยเพิ่มความเป็นส่วนตัวและความปลอดภัย เนื่องจากแต่ละคำสั่งซื้อจะมีที่อยู่เฉพาะของตัวเอง</p>
<p>ข้อดีอีกอย่างคือ HD wallet ทำให้ Gabriel ยังคงควบคุมการใช้จ่ายเงินได้จากกระเป๋าส่วนตัวของเขา ขณะที่เว็บไซต์มีเพียง xpub ที่ใช้สร้างที่อยู่รับเงินได้เท่านั้น เว็บไซต์ไม่เก็บ private key ใด ๆ เลย หากวันหนึ่งถูกเจาะระบบ สิ่งที่คนร้ายอาจได้ไปก็มีเพียงที่อยู่ที่จะใช้รับเงินในอนาคต ไม่ใช่กุญแจที่สามารถเข้าถึงเงินที่ Gabriel ได้รับไปแล้ว</p>
<p>เพื่อส่งออก xpub จากอุปกรณ์เซ็นธุรกรรม Trezor ของเขา Gabriel ใช้แอปกระเป๋าเงิน Trezor เวอร์ชันเว็บ ซึ่งต้องเชื่อมต่อกับอุปกรณ์ก่อนจึงจะสามารถส่งออกกุญแจสาธารณะได้ ที่สำคัญ อุปกรณ์เซ็นธุรกรรมส่วนใหญ่จะไม่ส่งออก private key เลย Private key จะถูกเก็บอยู่บนอุปกรณ์เท่านั้น Gabriel จึงมั่นใจได้ว่าเงินของเขายังคงปลอดภัย</p>
<p>หลังจากนั้น เขาคัดลอก xpub ไปยังซอฟต์แวร์สำหรับจัดการการชำระเงินบิตคอยน์ของร้านค้า เช่น BTCPay Server ซึ่งเป็นโอเพ่นซอร์สที่ได้รับความนิยมอย่างมาก และสามารถสร้างระบบชำระเงินที่ยืดหยุ่นและปลอดภัยสำหรับธุรกิจของเขาได้ทันที</p>
<h4>การสร้างอนุพันธ์กุญแจลูกแบบเสริมความแข็งแกร่ง</h4>
<p>ความสามารถในการสร้างกิ่งกุญแจสาธารณะจาก xpub นั้นมีประโยชน์อย่างมาก แต่ก็แฝงไปด้วยความเสี่ยงบางประการ การเข้าถึง xpub โดยตรงไม่สามารถทำให้ได้ private key ตัวลูก แต่อย่างไรก็ตาม เนื่องจาก xpub มี chain code อยู่ด้วย หาก private key ตัวใดตัวหนึ่งรั่วไหลหรือถูกเปิดเผยขึ้นมา มันสามารถถูกนำมาใช้ร่วมกับ chain code เพื่อสร้าง private key ลูกตัวอื่น ๆ ได้ทั้งหมด กล่าวคือ เพียงแค่ private key ตัวลูกที่รั่วไหลหนึ่งตัว บวกกับ chain code ของตัวแม่ ก็เพียงพอที่จะเปิดเผย private key ตัวลูกทั้งหมด ยิ่งไปกว่านั้น เมื่อ private key ตัวลูก รวมกับ chain code ของแม่ ยังสามารถถูกใช้เพื่อคำนวณหา private key ตัวแม่ได้อีกด้วย</p>
<p>เพื่อป้องกันความเสี่ยงนี้ HD wallet จึงมีอีกหนึ่งกลไกที่เรียกว่า hardened derivation ซึ่งทำหน้าที่ตัดความสัมพันธ์ระหว่าง public key ตัวแม่กับ chain code ของลูกออกไป ฟังก์ชัน hardened derivation จะใช้ private key ตัวแม่ในการสร้าง chaincode ของตัวลูกแทนการใช้ public key ของตัวแม่ วิธีนี้เปรียบเสมือนการสร้าง “ไฟร์วอลล์” ในสายลำดับแม่/ลูก ทำให้ chain code ที่ได้ไม่สามารถนำไปใช้เพื่อเจาะหา private key อื่น ๆ ได้อีกต่อไป</p>
<p>ฟังก์ชัน hardened derivation ดูคล้ายกับฟังก์ชันการสร้างกุญแจลูกแบบปกติ เพียงแต่มันใช้ private key แม่เป็น input ของ hash function แทน public key ดังที่แสดงในแผนภาพข้างล่าง</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0509.png" alt="image"></p>
<p>เมื่อใช้ฟังก์ชัน hardened derivation ผลลัพธ์ที่เกิดทั้ง private key และ chain code ของตัวลูกจะต่างไปโดยสิ้นเชิงจากสิ่งที่จะได้จากการอนุพันธ์แบบปกติ กิ่งที่ได้ด้วยวิธีนี้สามารถนำไปสร้างเป็น extended public keys ได้โดยที่ความปลอดภัยไม่ถูกทำลาย เพราะ chain code ของกิ่งเหล่านั้นไม่สามารถนำไปใช้เปิดเผย private key ใด ๆ  ในกิ่งอื่น ๆ ได้ การอนุพันธ์แบบ hardened จึงทำหน้าที่สร้าง “ช่องกั้น” (firewall) ในโครงสร้างต้นไม้ เหนือระดับที่มีการเผยแพร่ extended public keys</p>
<p>สรุปง่าย ๆ คือ หากคุณต้องการใช้ความสะดวกของ xpub เพื่อสร้าง public key หลาย ๆ ดอก โดยไม่เสี่ยงให้ตัวเองถูกเจาะจากการรั่วของ chain code ควรแยกสาขานั้นมาจากกุญแจพ่อแม่ที่สร้างด้วย hardened derivation แทนการใช้กุญแจพ่อแม่แบบปกติ โดยเป็นแนวปฏิบัติที่ดีที่สุดที่ลูกระดับแรก (level 1) ของกุญแจมาสเตอร์จะถูกสร้างด้วย hardened derivation เสมอ เพื่อป้องกันการถูกเจาะของกุญแจมาสเตอร์</p>
<h5>หมายเลขดัชนีสำหรับการแตกกุญแจแบบปกติและแบบ hardened</h5>
<p>หมายเลขดัชนีที่ใช้ในการอนุพันธ์กุญแจเป็นจำนวนเต็มขนาด 32 บิต เพื่อแยกความแตกต่างระหว่างการอนุพันธ์แบบปกติกับแบบ hardened หมายเลขดัชนีช่วง 0 ถึง 2³¹−1 (0x00000000 ถึง 0x7FFFFFFF) จะใช้สำหรับการอนุพันธ์แบบปกติ ส่วนหมายเลขดัชนีช่วง 2³¹ ถึง 2³²−1 (0x80000000 ถึง 0xFFFFFFFF) จะใช้สำหรับการอนุพันธ์แบบ hardened ดังนั้น หากค่าดัชนีต่ำกว่า 2³¹ กุญแจลูกจะเป็นแบบปกติ แต่ถ้าค่าเท่าหรือมากกว่า 2³¹ กุญแจลูกจะเป็นแบบ hardened</p>
<p>เพื่อให้อ่านและแสดงดัชนีได้สะดวกกว่า ค่าดัชนีของกุญแจ hardened มักจะแสดงด้วยตัวเลขเริ่มจากศูนย์ผนวกเครื่องหมาย prime (′) แทนค่าแบบไบนารี่ ตัวอย่างเช่น กุญแจลูกปกติแรกจะแสดงเป็น 0 ในขณะที่กุญแจลูก hardened แรก (ดัชนี 0x80000000) จะแสดงเป็น 0′ กุญแจ hardened ตัวถัดมาจะเป็น 1′ ซึ่งตามนิยาม i′ หมายถึงค่า 2³¹ + i ในการเขียนแบบ ASCII ปกติ เครื่องหมาย prime มักใช้เป็นอัปอสโทรฟเดี่ยว (') หรือในบริบทที่อัปอสโทรฟมีความหมายพิเศษ อาจใช้ตัวอักษร h แทน (เช่น 0h, 1h) ซึ่งเป็นรูปแบบที่มักแนะนำสำหรับการนำไปใช้ใน shell หรือใน output script descriptors.</p>
<h3>ตัวระบุคีย์ใน HD wallet (path)</h3>
<p>คีย์ใน HD wallet จะถูกระบุด้วยรูปแบบ path ซึ่งแยกระดับชั้นของต้นไม้ด้วยเครื่องหมายทับ (/) แต่ละระดับระบุการอนุพันธ์หนึ่งขั้น private key ที่อนุพันธ์มาจาก master private key จะขึ้นต้นด้วย m ในขณะที่ public key ที่อนุพันธ์มาจาก master public key จะขึ้นต้นด้วย M ตัวอย่างเช่น private key ลูกดอกแรกของ master private key จะเป็น m/0 และ public key ลูกดอกแรก จะเป็น M/0 และหลานลำดับที่สองของ Master private key ก็จะเป็น m/0/1 ไปเรื่อย ๆ</p>
<p>การอ่าน “ลำดับชั้น” ของ path ทำได้โดยอ่านจากซ้ายไปขวาโดยเริ่มจาก master key ไปยังกิ่งที่ลึกขึ้น เช่น ตัวระบุ m/x/y/z หมายความว่ากุญแจนี้เป็นกุญแจลูกลำดับที่ z ของกุญแจ m/x/y ซึ่งเป็นลูกลำดับที่ y ของกุญแจ m/x ซึ่งเป็นลูกลำดับที่ x ของ m — กล่าวคือ path แต่ละระดับบอกขั้นตอนการอนุพันธ์ที่ต่อเนื่องจาก master ลงไปยังกุญแจปัจจุบัน</p>
<table>
<thead>
<tr>
<th>HD path</th>
<th>คีย์ที่อธิบาย</th>
</tr>
</thead>
<tbody><tr>
<td><strong>m/0</strong></td>
<td>กุญแจส่วนตัวลูกตัวแรก (0) จาก master private key (m)</td>
</tr>
<tr>
<td><strong>m/0/0</strong></td>
<td>กุญแจส่วนตัวหลานตัวแรกจากลูกตัวแรก (m/0)</td>
</tr>
<tr>
<td><strong>m/0'/0</strong></td>
<td>กุญแจส่วนตัวหลานปกติ (normal grandchild) ตัวแรกจากลูกแบบ hardened ตัวแรก (m/0')</td>
</tr>
<tr>
<td><strong>m/1/0</strong></td>
<td>กุญแจส่วนตัวหลานตัวแรกจากลูกตัวที่สอง (m/1)</td>
</tr>
<tr>
<td><strong>M/23/17/0/0</strong></td>
<td>กุญแจสาธารณะเหลนเหลน (great-great-grandchild) ตัวแรกจากเหลนตัวแรก (first great-grandchild) จากหลานตัวที่ 18 (18th grandchild) จากลูกตัวที่ 24 (24th child)</td>
</tr>
</tbody></table>
<h4>การใช้งานเส้นทางในโครงสร้างต้นไม้ของกระเป๋าเงินแบบ HD</h4>
<p>โครงสร้างต้นไม้ของ HD wallet มอบความยืดหยุ่นอย่างมาก แต่ละกุญแจขยายที่เป็นพ่อแม่สามารถมีลูกได้ 4 พันล้านกุญแจ: 2 พันล้านกุญแจปกติ และ 2 พันล้านกุญแจ hardened ลูกแต่ละกุญแจเหล่านั้นสามารถมีลูกอีก 4 พันล้านกุญแจ และต่อไปได้เรื่อย ๆ ต้นไม้สามารถลึกได้เท่าที่คุณต้องการ โดยมีจำนวนรุ่นไม่สิ้นสุด อย่างไรก็ตาม ด้วยความยืดหยุ่นทั้งหมดนั้น มันจึงกลายเป็นเรื่องที่ค่อนข้างยากที่จะใช้งานเส้นทางในต้นไม้ที่ไม่สิ้นสุดนี้ โดยเฉพาะอย่างยิ่งเมื่อมีการถ่ายโอน HD wallet ระหว่างการนำไปใช้งานต่าง ๆ เนื่องจากความเป็นไปได้สำหรับการจัดระเบียบภายในไปสู่กิ่งและกิ่งย่อยนั้นมีอยู่อย่างไม่จำกัด</p>
<p>สอง BIP นำเสนอโซลูชันสำหรับความซับซ้อนนี้ โดยการสร้างมาตรฐานที่เสนอไว้บางอย่างสำหรับโครงสร้างของต้นไม้ HD wallet BIP43 เสนอการใช้ hardened child index ตัวแรกเป็นตัวระบุพิเศษที่บ่งบอกถึง “วัตถุประสงค์” ของโครงสร้างต้นไม้ ตามที่ BIP43 กล่าวไว้ HD wallet ควรใช้เพียงกิ่งระดับ 1 ของต้นไม้ โดยหมายเลข index จะบ่งบอกถึงโครงสร้างและ namespace ของต้นไม้ที่เหลือโดยการกำหนดวัตถุประสงค์ ตัวอย่างเช่น HD wallet ที่ใช้เพียงกิ่ง m/i' มีเจตนาที่จะบ่งบอกถึงวัตถุประสงค์เฉพาะ และวัตถุประสงค์นั้นถูกระบุด้วยหมายเลข index “i”</p>
<p>โดยการขยายข้อกำหนดนั้น BIP44 เสนอ multiaccount structure เป็น “วัตถุประสงค์” หมายเลข 44' ภายใต้ BIP43 HD wallet ทั้งหมดที่ปฏิบัติตามโครงสร้าง BIP44 จะถูกระบุโดยข้อเท็จจริงที่ว่าพวกมันใช้เพียงกิ่งเดียวของต้นไม้: m/44'</p>
<p>BIP44 กำหนดโครงสร้างว่า ประกอบด้วยห้าระดับของต้นไม้ที่ถูกกำหนดไว้ล่วงหน้า:</p>
<pre><code>m / purpose' / coin_type' / account' / change / address_index
</code></pre>
<p>ระดับแรก “purpose” จะถูกตั้งค่าเป็น 44’ เสมอ ระดับที่สอง “coin_type” ระบุชนิดของเหรียญ cryptocurrency โดยอนุญาตให้มี multicurrency HD wallets ที่แต่ละสกุลเงินมี subtree ของตัวเองภายใต้ระดับที่สอง Bitcoin คือ m/44’/0’ และ Bitcoin Testnet คือ m/44’/1’</p>
<p>ระดับที่สามของต้นไม้คือ “account” ซึ่งอนุญาตให้ผู้ใช้แบ่งย่อยกระเป๋าของพวกเขาออกเป็น subaccount เชิงตรรกะแยกกันเพื่อการบัญชีหรือวัตถุประสงค์ด้านการจัดการ ตัวอย่างเช่น HD wallet อาจมีสอง “account” ของ Bitcoin: m/44’/0’/0’ และ m/44’/0’/1’ แต่ละ account เป็นรากของ subtree ของมันเอง</p>
<p>ในระดับที่สี่ “change” HD wallet มีสอง subtree หนึ่งสำหรับการสร้าง receiving address และอีกหนึ่งสำหรับการสร้าง change address โปรดทราบว่าในขณะที่ระดับก่อนหน้านี้ใช้ hardened derivation แต่ระดับนี้ใช้ normal derivation นี่เป็นการอนุญาตให้ระดับนี้ของต้นไม้สามารถส่งออก extended public keys เพื่อใช้ในสภาพแวดล้อมที่ไม่ปลอดภัยได้ ที่อยู่ที่สามารถใช้งานได้ถูกสร้างขึ้นโดย HD wallet ในฐานะลูกของระดับที่สี่ ทำให้ระดับที่ห้าของต้นไม้คือ “address_index” ตัวอย่างเช่น receiving address ที่สามสำหรับการชำระเงินใน account หลักจะเป็น M/44’/0’/0’/0/2 ตารางข้างล่างจะแสดงตัวอย่างเพิ่มเติมอีกเล็กน้อย</p>
<table>
<thead>
<tr>
<th>HD path</th>
<th>คำอธิบายคีย์</th>
</tr>
</thead>
<tbody><tr>
<td>M/44'/0'/0'/0/2</td>
<td>กุญแจสาธารณะสำหรับรับเงินตัวที่สามของบัญชี Bitcoin หลัก</td>
</tr>
<tr>
<td>M/44'/0'/3'/1/14</td>
<td>กุญแจสาธารณะสำหรับที่อยู่ทอน (change-address) ตัวที่สิบห้าของบัญชี Bitcoin ที่สี่</td>
</tr>
<tr>
<td>m/44'/2'/0'/0/1</td>
<td>กุญแจส่วนตัวที่สองในบัญชีหลักของ Litecoin สำหรับใช้ลงลายเซ็นธุรกรรม</td>
</tr>
</tbody></table>
<p>หลายคนมุ่งเน้นไปที่การปกป้องบิตคอยน์ของตนจากการขโมยและการโจมตีรูปแบบต่าง ๆ แต่หนึ่งในสาเหตุสำคัญของการสูญเสียบิตคอยน์—ซึ่งอาจเป็นสาเหตุหลักเลยก็ว่าได้—ก็คือการสูญหายของข้อมูล หากกุญแจและข้อมูลสำคัญอื่น ๆ ที่จำเป็นต่อการใช้จ่ายบิตคอยน์ของคุณสูญหายไป บิตคอยน์เหล่านั้นก็จะไม่สามารถถูกใช้จ่ายได้อีกต่อไป และไม่มีใครสามารถกู้คืนให้คุณได้ ในบทนี้ เราได้พิจารณาระบบที่กระเป๋าเงินสมัยใหม่ใช้เพื่อช่วยป้องกันไม่ให้คุณสูญเสียข้อมูลนั้น แต่อย่าลืมว่า การใช้งานระบบที่มีอยู่เพื่อสร้างการสำรองข้อมูลที่ดีและทดสอบอย่างสม่ำเสมอนั้น ขึ้นอยู่กับคุณเอง</p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<h1>Wallet Recovery: การกู้คืนกระเป๋าบิตคอยน์</h1>
<p>การสร้างคู่กุญแจ private key และ public key เป็นส่วนสำคัญในการอนุญาตให้กระเป๋าเงินบิตคอยน์สามารถรับและใช้จ่ายบิตคอยน์ได้ แต่การสูญเสีย private key ไปนั้นจะทำให้ไม่สามารถนำบิตคอยน์ที่เกี่ยวข้องกับ public key ที่คู่กันออกมาใช้จ่ายได้อีกเลย ตลอดหลายปีที่ผ่านมา นักพัฒนากระเป๋าเงินและโปรโตคอลได้ทำงานเพื่อออกแบบระบบที่ช่วยให้ผู้ใช้สามารถกู้คืนการเข้าถึงบิตคอยน์ของตนหลังจากเกิดปัญหาโดยไม่ทำให้ความปลอดภัยนั้นลดน้อยถอยลง</p>
<p>ในบทนี้ เราจะสำรวจวิธีการกู้คืนและป้องกันการสูญหายของข้อมูลที่ใช้กันในกระเป๋าเงินสมัยใหม่ บางวิธีได้รับการยอมรับอย่างกว้างขวางเพราะแทบไม่มีข้อเสีย และจึงถือเป็นแนวปฏิบัติที่ดีที่สุด ส่วนวิธีอื่น ๆ แม้จะมีข้อดี แต่ก็มาพร้อมข้อจำกัดบางประการ ทำให้ผู้พัฒนากระเป๋าเงินเลือกใช้แตกต่างกันไป เราจะอธิบายทั้งข้อดี ข้อเสีย และทางเลือกเหล่านี้อย่างเป็นระบบ เพื่อให้ผู้อ่านเข้าใจภาพรวมทั้งหมด</p>
<h2>กระเป๋าประเภทสร้างคู่กุญแจแบบอิสระ (Independent Key Generation)</h2>
<p>ก่อนอื่นควรทำความเข้าใจก่อนว่า bitcoin wallet หรือ “กระเป๋าเก็บบิตคอยน์” แท้จริงแล้วไม่ได้เก็บบิตคอยน์ไว้ข้างใน แต่เก็บเพียงกุญแจ (keys) ไว้เท่านั้น กุญแจเหล่านี้เชื่อมโยงกับบิตคอยน์ที่ถูกบันทึกไว้บนบล็อกเชน และใช้การพิสูจน์ต่อเครือข่ายว่าคุณถือครอง private key เป็นหลักฐานว่าคุณสามารถใช้จ่ายบิตคอยน์ที่เกี่ยวข้องนั้นได้ ซึ่งต่างจากกระเป๋าสตางค์ทั่วไปที่เก็บเงินสดไว้ภายใน</p>
<p>โดยทั่วไป กระเป๋าเงินบิตคอยน์จะมีทั้ง public key สำหรับสร้าง address และ private key สำหรับสร้างลายเซ็นเพื่ออนุมัติการใช้จ่าย และอีกประเภทหนึ่งคือกระเป๋าที่เก็บเพียง public key ในแอปพลิเคชัน ส่วน private key จะถูกเก็บไว้ในอุปกรณ์ภายนอก เช่น ฮาร์ดแวร์วอลเล็ตหรือระบบหลายลายเซ็น (multisig)</p>
<p>ในยุคแรก แอปพลิเคชันกระเป๋าเงินมักสร้างคู่กุญแจใหม่แบบอิสระทุกครั้งที่ต้องการใช้งาน จากนั้นผู้ใช้จำเป็นต้องสำรองฐานข้อมูลกระเป๋าเงินนั้น ๆ อยู่เสมอ เพื่อป้องกันไม่ให้กุญแจที่สร้างใหม่สูญหาย การล้มเหลวในการสำรองทันเวลาอาจทำให้สูญเสียการเข้าถึงบิตคอยน์ที่เก็บไว้ในกุญแจเหล่านั้นโดยถาวร</p>
<p>กุญแจแต่ละชุดที่สร้างอย่างอิสระมีขนาดประมาณ 32 ไบต์ การสำรองกุญแจจำนวนมากจึงเป็นภาระสำหรับผู้ใช้ บางคนพยายามลดภาระนี้ด้วยการใช้เพียงกุญแจเดียวในการทำธุรกรรมหลายครั้ง แต่ถึงแม้ว่าจะช่วยให้ง่ายต่อการสำรองข้อมูล แต่มันกลับทำให้ความเป็นส่วนตัวลดลงอย่างมาก เนื่องจากทุกธุรกรรมสามารถโยงกลับไปยังผู้ใช้รายเดิมได้ ด้วยเหตุนี้ ผู้ที่ให้ความสำคัญกับความเป็นส่วนตัวมักเลือกสร้างกุญแจใหม่สำหรับแต่ละธุรกรรม ซึ่งทำให้การสำรองข้อมูลเป็นไปได้จริงเพียงบนสื่อดิจิทัลที่มีความจุเพียงพอเท่านั้น<br><img src="https://github.com/bitcoinbook/bitcoinbook/blob/develop/images/mbc3_0501.png?raw=true" alt="image"></p>
<h2>กระเป๋าเก็บบิตคอยน์ประเภทสร้างกุญแจแบบกำหนดได้ (Deterministic Key)</h2>
<p>ฟังก์ชันแฮชจะสร้างเอาต์พุตเดิมเสมอเมื่อรับอินพุตเดิม แต่ถ้าอินพุตเปลี่ยนแปลงเพียงเล็กน้อย เอาต์พุตจะแตกต่างกัน หากฟังก์ชันมีความปลอดภัยทางการเข้ารหัส จะไม่มีใครสามารถคาดเดาเอาต์พุตใหม่ได้ เว้นเสียแต่ว่าพวกเขารู้อินพุตใหม่</p>
<p>เราสามารถใช้คุณสมบัตินี้เพื่อแปลงค่าใด ๆ (เช่น seed) ให้กลายเป็นชุดค่าที่ได้มาอย่างกำหนดได้ซ้ำ ๆ — นั่นคือ ถ้าใช้ seed เดิมกับขั้นตอนเดิม เราจะได้กุญแจอนุพันธ์ชุดเดียวกันทุกครั้ง ตัวอย่างเชิงปฏิบัติ:</p>
<pre><code># เก็บ entropy แบบสุ่ม แล้วแฮชเป็น seed
$ dd if=/dev/random count=1 status=none | sha256sum
f1cc3bc03ef51cb43ee7844460fa5049e779e7425a6349c8e89dfbb0fd97bb73  -
# กำหนด seed
$ seed=f1cc3bc03ef51cb43ee7844460fa5049e779e7425a6349c8e89dfbb0fd97bb73
# สร้างค่าที่ได้มาแบบกำหนดได้
$ for i in {0..2} ; do echo "$seed + $i" | sha256sum ; done
50b18e0bd9508310b8f699bad425efdf67d668cb2462b909fdb6b9bd2437beb3  -
a965dbcd901a9e3d66af11759e64a58d0ed5c6863e901dfda43adcd5f8c744f3  -
19580c97eb9048599f069472744e51ab2213f687d4720b0efc5bb344d624c3aa  -
</code></pre>
<p>ถ้าเรานำค่าที่ได้มาเหล่านี้ไปใช้เป็น private key ของ address ต่าง ๆ เราก็สามารถสร้างกุญแจทั้งหมดซ้ำได้โดยใช้เพียง seed และอัลกอริทึมเดียวกัน ดังนั้นการสำรองข้อมูลเพื่อกู้คืนกระเป๋าที่สร้างกุญแจแบบกำหนดได้จึงทำได้ง่าย — แทนที่จะสำรองกุญแจทุกดอก ผู้ใช้เพียงบันทึก seed และวิธีการ (algorithm/derivation) ที่ใช้เท่านั้น ตัวอย่างเช่น แม้อลิซจะมีบิตคอยน์ที่กระจายอยู่ในหนึ่งล้าน address ต่างกัน สิ่งที่ต้องสำรองเพื่อกู้คืนทั้งหมดอาจเป็นเพียง seed ชุดเดียว:</p>
<pre><code>f1cc 3bc0 3ef5 1cb4 3ee7 8444 60fa 5049
e779 e742 5a63 49c8 e89d fbb0 fd97 bb73
</code></pre>
<p>โครงตรรกะของการสร้างกุญแจแบบกำหนดได้แบบเรียงลำดับจะแสดงให้เห็นว่าจาก seed เดียวสามารถแยกสาขา (derive) กุญแจได้หลายดอก แต่กระเป๋าเงินสมัยใหม่มีวิธีที่พัฒนาขึ้น (เช่น แนวคิดกระเป๋าแบบ hierarchical deterministic) ที่ช่วยแยกการสร้าง public key ออกจาก private key ได้ ทำให้สามารถเผยหรือใช้ public key ได้โดยไม่ต้องเก็บ private key ไว้ในที่เสี่ยง เหมาะกับการจัดการความปลอดภัยและความเป็นส่วนตัวมากขึ้น<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0502.png" alt="image"></p>
<h3>การดึงกุญแจลูกสาธารณะ (Public Child Key Derivation)</h3>
<p>จากที่เราได้เรียนเรื่องของ public key กันไปในบทก่อนหน้า เราได้เรียนรู้วิธีการสร้าง public key จาก private key โดยใช้การเข้ารหัสแบบเส้นโค้งวงรี (ECC) แล้วมันจะเป็นอย่างไรหากเราใช้วิธีการเดิมแต่เปลี่ยนไปใช้ public key เป็นตัวตั้งแทน พิจารณาการดำเนินการที่เราใช้ในบทก่อนหน้าสำหรับการสร้าง public key (K) จาก private key (k) โดยใช้จุดกำเนิด (G): <code>$$K = k * G $$</code></p>
<p>คำถามคือ หากเราใช้ public key ที่มีอยู่แทนการสร้างใหม่จาก private key จะสามารถสร้างกุญแจลูก (child key) ได้หรือไม่?</p>
<p>ลองพิจารณาสมการเดิม หากเราบวกค่าเพิ่มเติมเดียวกันทั้งสองฝั่ง เช่น ค่า “123” เราจะได้ว่า:<br><code>$$K+(123×G)≡(k+123)×G$$</code></p>
<blockquote>
<p>TIP: ในหนังสือเล่มนี้ สัญลักษณ์ “=” ใช้แสดงการคำนวณค่า ส่วน “==” ใช้เพื่อแสดงความสมมูลระหว่างสองด้านของสมการ หากทั้งสองด้านไม่สมมูล ค่าที่ได้จะเป็น “false”</p>
</blockquote>
<p>สิ่งที่น่าสนใจคือ การเพิ่มค่า (tweak) เช่น 123 ลงใน public key สามารถทำได้ด้วยข้อมูลสาธารณะเพียงอย่างเดียว โดยไม่ต้องรู้ private key เลย</p>
<p>ตัวอย่างเช่น อลิซสร้าง public key (K) และส่งให้บ็อบ ถึงแม้บ็อบจะไม่รู้ค่า private key (k) แต่เขารู้จุดกำเนิด (G) ดังนั้นเขาสามารถสร้าง public child key ได้ด้วยการเพิ่มค่าใด ๆ ลงไป หากบ็อบแจ้งค่า tweak ที่ใช้กับอลิซ อลิซก็สามารถเพิ่มค่าดังกล่าวลงใน private key ของเธอ เพื่อให้ได้ private child key ที่สอดคล้องกับ public child key ที่บ็อบสร้างขึ้น</p>
<p>กล่าวอีกอย่างคือ แม้ผู้ที่ไม่รู้ private key ก็ยังสามารถสร้าง public child key ได้ไม่จำกัดจาก public key อันเดียว หากมีการกำหนดวิธีสร้าง key tweaks อย่างเป็นระบบ ผู้ที่ถือครอง private key สามารถใช้ key tweaks เดียวกันเพื่อสร้าง private child key ที่ตรงกันได้เสมอเช่นกัน</p>
<p>เทคนิคนี้ช่วยให้ข้อมูลสาธารณะ เช่น public key ของผู้ใช้ สามารถถูกแจกจ่ายไปยังบุคคลอื่น โดยไม่ต้องเปิดเผย private key เมื่อถึงเวลาที่ต้องใช้จ่ายเงิน อลิซสามารถส่งรายการ key tweaks ที่ใช้ไปยังอุปกรณ์ลงนามแบบฮาร์ดแวร์ (hardware wallet) ซึ่งเก็บ private key ไว้อย่างปลอดภัย อุปกรณ์นั้นจะใช้ key tweaks เพื่อสร้าง private child key ที่จำเป็นสำหรับการลงนามธุรกรรม จากนั้นส่งธุรกรรมที่ลงนามแล้วกลับไปยังส่วนติดต่อผู้ใช้ที่ปลอดภัยน้อยกว่าเพื่อเผยแพร่ไปยังเครือข่ายบิตคอยน์</p>
<p>การดึง public child key สามารถสร้างเป็นลำดับเชิงเส้นของกุญแจ คล้ายกับกระเป๋าเงินแบบกำหนดได้ (deterministic wallets) ที่สร้างกุญแจจาก seed อย่างไรก็ตาม กระเป๋าเงินสมัยใหม่ก้าวไปอีกขั้น โดยใช้เทคนิคเพิ่มเติมเพื่อสร้างชุดของ public child keys ที่ซับซ้อนกว่า และจะอธิบายในส่วนถัดไป</p>
<h2>การสร้างกุญแจแบบลำดับชั้นเชิงกำหนด (HD) ตามมาตรฐาน BIP32</h2>
<p>วอลเล็ตบิตคอยน์สมัยใหม่ทั้งหมดที่เรารู้จัก ใช้การสร้างกุญแจแบบลำดับชั้นเชิงกำหนด (HD) เป็นค่าเริ่มต้น มาตรฐานนี้ถูกกำหนดไว้ใน BIP32 โดยใช้หลักการสร้างกุญแจแบบกำหนดค่าได้ร่วมกับการดึง public child key แบบเลือกได้ผ่านอัลกอริทึมที่สร้างโครงสร้างเป็น tree ของกุญแจ </p>
<p>ใน tree นี้ กุญแจใด ๆ สามารถทำหน้าที่เป็นพ่อแม่ของชุด child key ได้ และ child key แต่ละดอกก็สามารถกลายเป็นพ่อแม่ของชุด child key ใหม่ได้เช่นกัน ไม่มีข้อจำกัดตายตัวในเรื่องความลึกของ tree โครงสร้างแบบนี้ช่วยให้วอลเล็ต HD สามารถสร้างกุญแจจำนวนมากจาก seed เดียว โดยผู้ใช้เพียงสำรอง seed ก็สามารถกู้คืนกุญแจทั้งหมดใน tree ได้อย่างปลอดภัยและสะดวก ดูตัวอย่างได้ในภาพประกอบข้างล่างนี้<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0503.png" alt="image"></p>
<p>โครงสร้างแบบ tree ของกุญแจยังสามารถสะท้อนการจัดการและการแบ่งหมวดหมู่ได้อย่างชัดเจน ตัวอย่างเช่น กิ่งหนึ่งของ child key อาจใช้สำหรับรับการชำระเงินขาเข้า อีกกิ่งหนึ่งอาจใช้สำหรับรับเงินทอนจากการชำระเงินขาออก นอกจากนี้ กิ่งของกุญแจยังสามารถประยุกต์ใช้ในบริบทขององค์กร เช่น แยกกิ่งต่าง ๆ ให้กับแผนก บริษัทในเครือ หน้าที่เฉพาะ หรือหมวดหมู่การบัญชี</p>
<p>บทต่อไปเราจะเจาะลึกเรื่องวอลเล็ต HD และอธิบายวิธีการสร้างวอลเล็ตจาก seed ในหัวข้อ "การสร้างวอลเล็ต HD จาก seed"</p>
<h2>Seeds and Recovery Codes</h2>
<p>วอลเล็ต HD เป็นกลไกที่ทรงพลังสำหรับจัดการกุญแจจำนวนมากที่สกัดมาจาก seed เดียวกัน หากฐานข้อมูลวอลเล็ตของคุณเสียหายหรือสูญหาย คุณสามารถสร้าง private key ทั้งหมดกลับคืนมาได้โดยใช้ seed ชุดเดิม แต่ข้อเสียสำคัญคือ หากผู้อื่นได้ seed ของคุณไป พวกเขาจะสามารถสร้างกุญแจส่วนตัวทั้งหมดได้เช่นกัน ซึ่งอาจทำให้บิตคอยน์ถูกขโมยจากวอลเล็ตแบบลงนามเดี่ยว หรือทำให้ความปลอดภัยของวอลเล็ตแบบหลายลายเซ็นลดลง </p>
<p>ในส่วนนี้เราจะอธิบายรูปแบบของ โค้ดกู้คืน (recovery code) หลายแบบ โดยมุ่งหมายเพื่อทำให้การสำรองข้อมูลทั้งสะดวกและปลอดภัยมากขึ้น</p>
<p>แม้ว่า seed โดยพื้นฐานเป็นตัวเลขสุ่มขนาดใหญ่ — โดยทั่วไปมีขนาดตั้งแต่ 128 ถึง 256 บิต — โค้ดกู้คืนส่วนใหญ่ถูกออกแบบให้เป็น คำในภาษามนุษย์ เพื่อให้จดจำและเขียนเก็บได้ง่ายกว่ารหัสไบนารีหรือเลขฐานสิบหก ตัวอย่างแรงจูงใจในการใช้คำคือผู้ใช้สามารถจดหรือพูดได้โดยไม่ต้องคัดลอกตัวอักษรยาว ๆ และลดความเสี่ยงจากความผิดพลาดเมื่อสำรองด้วยมือ</p>
<p>ตัวอย่างการเก็บ seed สองรูปแบบ (เลขฐานสิบหก กับ คำศัพท์ภาษาอังกฤษ):</p>
<pre><code>Hex-encoded:
0C1E 24E5 9177 79D2 97E1 4D45 F14E 1A1A

Word-encoded:
army van defense carry jealous true
garbage claim echo media make crunch
</code></pre>
<p>การจดจำโค้ดกู้คืนเพียงอย่างเดียวอาจเป็นคุณสมบัติที่มีประโยชน์ในบางสถานการณ์ เช่น เมื่อคุณไม่สามารถขนย้ายสิ่งของทางกายภาพ เช่น กระดาษที่เขียนโค้ดกู้คืน โดยไม่เสี่ยงต่อการถูกยึดหรือถูกตรวจค้นโดยบุคคลภายนอกที่อาจขโมยบิตคอยน์ของคุณได้</p>
<p>อย่างไรก็ตาม การพึ่งพาความทรงจำเพียงอย่างเดียวถือเป็นเรื่องอันตราย เพราะมีความเสี่ยงหลายประการ:</p>
<ul>
<li><p>หากคุณลืมโค้ดกู้คืนและไม่สามารถเข้าถึงฐานข้อมูลวอลเล็ตเดิม บิตคอยน์ของคุณจะสูญหายตลอดกาล</p>
</li>
<li><p>หากคุณเสียชีวิตหรือได้รับบาดเจ็บรุนแรง และทายาทไม่สามารถเข้าถึงฐานข้อมูลวอลเล็ตเดิม พวกเขาจะไม่สามารถรับมรดกบิตคอยน์ของคุณได้</p>
</li>
<li><p>หากมีคนเชื่อว่าคุณจำโค้ดกู้คืนได้ พวกเขาอาจพยายามบังคับให้คุณเปิดเผยรหัสนั้น ในเวลาที่เขียนหนังสือเล่มนี้ เจมสัน ล็อปป์ ผู้มีส่วนร่วมในการพัฒนาบิตคอยน์ ได้บันทึกเหตุโจมตีทางกายภาพต่อผู้ที่สงสัยว่าเป็นเจ้าของบิตคอยน์และสินทรัพย์ดิจิทัลอื่น ๆ มากกว่า 100 ครั้ง รวมถึงมีการเสียชีวิตอย่างน้อย 3 ราย และหลายกรณีที่เกี่ยวข้องกับการทรมาน จับเป็นตัวประกัน หรือคุกคามครอบครัว</p>
</li>
</ul>
<blockquote>
<p>TIP: แม้ว่าคุณจะใช้โค้ดกู้คืนที่ออกแบบมาให้จดจำง่าย เราขอแนะนำอย่างยิ่งให้คุณพิจารณาจดบันทึกไว้</p>
</blockquote>
<h3>ปัจจุบันมีรหัสกู้คืนหลายประเภทที่มีการใช้งานอย่างแพร่หลาย:</h3>
<ul>
<li><p>BIP39: เป็นวิธีที่ได้รับความนิยมมากที่สุดในการสร้างรหัสกู้คืนในช่วงทศวรรษที่ผ่านมา BIP39 เกี่ยวข้องกับการสร้างลำดับไบต์แบบสุ่ม เพิ่มเช็คซัมเข้าไป และเข้ารหัสข้อมูลเป็นชุดคำศัพท์ 12 ถึง 24 คำ (ซึ่งอาจแปลเป็นภาษาท้องถิ่นของผู้ใช้) คำเหล่านี้ (บวกกับ passphrase ) จะถูกประมวลผ่านฟังก์ชัน key-stretching และนำผลลัพธ์มาใช้เป็น seed BIP39 มีข้อบกพร่องหลายประการซึ่งระบบอื่น ๆ ที่พัฒนาขึ้นภายหลังพยายามแก้ไข</p>
</li>
<li><p>Electrum v2: ถูกใช้ในกระเป๋าเงิน Electrum (เวอร์ชัน 2.0 ขึ้นไป) รหัสกู้คืนที่ใช้คำนี้มีข้อดีหลายประการเหนือ BIP39 มันไม่ได้พึ่งพารายการคำศัพท์สากลที่ต้องนำไปใช้ในทุกเวอร์ชันของทุกโปรแกรมที่เข้ากันได้ อีกทั้งรหัสกู้คืนยังมีหมายเลขเวอร์ชันที่ช่วยเพิ่มความน่าเชื่อถือและประสิทธิภาพ เช่นเดียวกับ BIP39 มันรองรับ passphrase (ซึ่ง Electrum เรียกว่า seed extension ) และใช้ฟังก์ชัน key-stretching แบบเดียวกัน</p>
</li>
<li><p>Aezeed: ถูกใช้ในกระเป๋าเงิน LND นี่เป็นอีกรหัสกู้คืนที่ใช้คำซึ่งมีการปรับปรุงจาก BIP39 มันรวมหมายเลขเวอร์ชันสองตัว: ตัวแรกเป็นภายในและช่วยกำจัดปัญหาหลายอย่างในการอัปเกรดแอปพลิเคชันกระเป๋าเงิน (เหมือนหมายเลขเวอร์ชันของ Electrum v2); อีกหมายเลขเวอร์ชันเป็นภายนอก ซึ่งสามารถเพิ่มเข้ามาเพื่อเปลี่ยนคุณสมบัติทางการเข้ารหัสพื้นฐานของรหัสกู้คืน นอกจากนี้ยังรวม วันเกิดของกระเป๋าเงิน ในรหัสกู้คืน ซึ่งอ้างอิงถึงวันที่ผู้ใช้สร้างฐานข้อมูลกระเป๋าเงิน โดยสิ่งนี้ช่วยให้กระบวนการกู้คืนสามารถค้นหาเงินทั้งหมดที่เกี่ยวข้องกับกระเป๋าเงินโดยไม่ต้องสแกนบล็อกเชนทั้งหมด ซึ่งมีประโยชน์อย่างยิ่งสำหรับซอฟแวร์ที่เน้นความเป็นส่วนตัว มันรองรับการเปลี่ยนรหัสผ่านหรือเปลี่ยนแปลงรูปแบบอื่น ๆ ของรหัสกู้คืนโดยไม่จำเป็นต้องย้ายเงินไปยัง seed ใหม่—ผู้ใช้เพียงแค่ต้องสำรองรหัสกู้คืนใหม่เท่านั้น ข้อเสียเปรียบเมื่อเทียบกับ Electrum v2 คือ เช่นเดียวกับ BIP39 มันต้องพึ่งพาทั้งซอฟต์แวร์สำรองและกู้คืนที่รองรับรายการคำศัพท์เดียวกัน</p>
</li>
<li><p>Muun: ถูกใช้ในกระเป๋าเงิน Muun โดยค่าเริ่มต้นกำหนดให้ธุรกรรมการใช้จ่ายต้องถูกลงนามด้วยกุญแจหลายดอก นี่เป็นรหัสที่ไม่ใช่คำซึ่งต้องมาพร้อมกับข้อมูลเพิ่มเติม (ปัจจุบัน Muun ให้มาในรูปแบบ PDF) รหัสกู้คืนนี้ไม่เกี่ยวข้องกับ seed และถูกใช้เพื่อถอดรหัส private key ที่อยู่ใน PDF แทน แม้ว่าวิธีนี้จะยุ่งยากเมื่อเทียบกับรหัสกู้คืน BIP39, Electrum v2 และ Aezeed แต่มันรองรับเทคโนโลยีและมาตรฐานใหม่ที่กำลังกลายเป็นที่นิยมมากขึ้นในกระเป๋าเงินใหม่ ๆ เช่น การสนับสนุน Lightning Network (LN), ตัวอธิบายสคริปต์เอาต์พุต และ miniscript</p>
</li>
<li><p>SLIP39: เป็นวิธีที่พัฒนามาต่อจาก BIP39 โดยนักพัฒนาบางคนที่มีส่วนร่วมใน BIP39 ซึ่ง SLIP39 อนุญาตให้ seed เดียวกระจายโดยใช้รหัสกู้คืนหลายชุดที่สามารถเก็บไว้ในสถานที่ต่างกัน (หรือโดยคนต่างกัน) เมื่อคุณสร้างรหัสกู้คืน คุณสามารถระบุจำนวนที่จะต้องใช้เพื่อกู้คืน seed ได้ ตัวอย่างเช่น คุณสร้างรหัสกู้คืนห้าชุดแต่ต้องการเพียงสามชุดเพื่อกู้คืนซีด SLIP39 ให้การสนับสนุน passphrase ขึ้นอยู่กับรายการคำศัพท์สากล และไม่ได้ให้การกำหนดเวอร์ชันโดยตรง</p>
</li>
</ul>
<blockquote>
<p>NOTE: ระบบใหม่สำหรับการกระจายรหัสกู้คืนที่มีความคล้ายคลึงกับ SLIP39 ได้ถูกนำเสนอระหว่างการเขียนหนังสือเล่มนี้ โดยมันมีชื่อ Codex32 ช่วยให้สามารถสร้างและตรวจสอบรหัสกู้คืนได้โดยใช้เพียงคำแนะนำที่พิมพ์ไว้ กรรไกร มีดคัตเตอร์แบบละเอียด ตัวยึดทองเหลือง และปากกา—บวกกับความเป็นส่วนตัวและเวลาว่างสักสองสามชั่วโมง ผู้ที่ไว้วางใจคอมพิวเตอร์สามารถสร้างรหัสกู้คืนได้ทันทีโดยใช้ซอฟต์แวร์บนอุปกรณ์ดิจิทัล คุณสามารถสร้างรหัสกู้คืนได้สูงสุด 31 ชุดเพื่อเก็บไว้ในสถานที่ต่าง ๆ โดยระบุจำนวนที่จะต้องใช้เพื่อกู้คืน seed เนื่องจากเป็นข้อเสนอใหม่ รายละเอียดเกี่ยวกับ Codex32 อาจเปลี่ยนแปลงอย่างมีนัยสำคัญก่อนที่หนังสือเล่มนี้จะตีพิมพ์ ดังนั้นเราจึงแนะนำให้ผู้อ่านที่สนใจรหัสกู้คืนแบบกระจายศูนย์ตรวจสอบสถานะปัจจุบันของมัน <np-embed url="https://secretcodex32.com/"><a href="https://secretcodex32.com/">https://secretcodex32.com/</a></np-embed></p>
</blockquote>
<h2>passphrase</h2>
<p>รูปแบบ BIP39, Electrum v2, Aezeed, และ SLIP39 ทั้งหมดสามารถรองรับการใช้ passphrase ได้ หากคุณเก็บ passphrase ไว้ในความทรงจำ (ไม่จด) มันก็จะมีข้อดีข้อเสียแบบเดียวกับการจดจำ seed เช่นกัน</p>
<p>สามระบบ (BIP39, Electrum v2, และ SLIP39) ไม่ได้รวม passphrase เข้าไปในเช็คซัมที่ใช้ตรวจจับความผิดพลาดในการป้อนข้อมูล ทุก passphrase (รวมถึงการไม่ใช้เลย) จะให้ผลลัพธ์เป็น seed สำหรับโครงสร้างกุญแจ BIP32 แต่จะเป็นโครงสร้างที่ต่างกัน passphrase ที่ต่างกันจะได้กุญแจคนละชุด ซึ่งจุดนี้อาจเป็นทั้งข้อดีหรือข้อเสีย ขึ้นกับมุมมองของคุณ</p>
<ul>
<li><p>ในด้านบวก หากมีคนได้รหัสกู้คืน (คำศัพท์ 12–24 คำ) ของคุณไป แต่ไม่มี passphrase พวกเขาจะได้โครงสร้างกุญแจ BIP32 หนึ่งชุดที่ใช้งานได้ หากคุณวางแผนรับมือไว้ล่วงหน้า (เช่น โอนบิตคอยน์บางส่วนไปยังโครงสร้างที่ไม่มี passphrase) การถูกขโมยบางส่วนอาจเป็นสัญญาณเตือนว่ารหัสกู้คืนถูกบุกรุก ทำให้คุณมีโอกาสตอบโต้ได้ การที่รหัสกู้คืนเดียวสามารถมี passphrase หลายค่าแล้วให้ผลลัพธ์ที่ดูถูกต้องทั้งหมด ก็เป็นรูปแบบของ plausible deniability (การปฏิเสธที่เป็นไปได้)</p>
</li>
<li><p>ในด้านลบ หากคุณถูกบังคับให้มอบรหัสกู้คืน ผู้โจมตีอาจยังคงบีบบังคับให้คุณเปิดเผย passphrase เพิ่มเติมหากยอดที่เห็นไม่ตรงกับที่คาดหวัง การออกแบบเพื่อรองรับการปฏิเสธที่เป็นไปได้จึงไม่มีวิธีพิสูจน์ต่อผู้โจมตีได้ว่าคุณได้เปิดเผยข้อมูลทั้งหมดแล้ว ดังนั้นความเสี่ยงคือพวกเขาอาจยังคงบังคับต่อแม้คุณจะให้รหัสทั้งหมดแล้วก็ตาม</p>
</li>
<li><p>ข้อเสียอีกประการคือการลดทอนการตรวจจับข้อผิดพลาด หากคุณพิมพ์ passphrase ผิดเพียงเล็กน้อยเมื่อกู้คืนจากการสำรอง กระเป๋าเงินจะไม่แจ้งเตือนความผิดพลาดได้ชัดเจน — แอปจะแสดงโครงสร้างกุญแจใหม่ที่ใช้งานได้แต่ยอดเป็นศูนย์ ซึ่งผู้ใช้มือใหม่อาจคิดว่าเงินหายไปจริง ๆ และทำการตัดสินใจผิดพลาด เช่น ทิ้งรหัสกู้คืนหรือยอมแพ้ ในทางกลับกัน หากคุณคาดหวังยอดคงเหลือเป็นศูนย์จริง ๆ คุณอาจไม่รู้ตัวถึงความผิดพลาดนั้นเป็นเวลาหลายปีจนกว่าจะลองกู้คืนด้วย passphrase ที่ถูกต้อง</p>
</li>
</ul>
<p>มีเพียง Aezeed เท่านั้นที่รับรองการตรวจสอบความถูกต้องของ passphrase และจะแจ้งข้อผิดพลาดเมื่อใส่ค่าไม่ถูกต้อง ข้อนี้ช่วยลดปัญหาการปฏิเสธที่เป็นไปได้โดยเพิ่มการตรวจจับข้อผิดพลาด และทำให้เป็นไปได้ที่จะพิสูจน์แก่ผู้โจมตีได้ว่าคุณได้เปิดเผย passphrase แล้ว</p>
<p>ผู้ใช้และนักพัฒนามีมุมมองแตกต่างกันเกี่ยวกับวิธีที่ดีกว่า บางคนสนับสนุนการปฏิเสธที่เป็นไปได้อย่างเต็มที่ ขณะที่บางคนชอบความปลอดภัยจากการตรวจจับข้อผิดพลาดสำหรับผู้ใช้มือใหม่และผู้ที่ตกอยู่ภายใต้ความกดดัน เราคาดว่าการถกเถียงนี้จะยังคงอยู่ตราบเท่าที่รหัสกู้คืนยังใช้กันแพร่หลาย</p>
<h3>การสำรองข้อมูลอื่น ๆ</h3>
<p>แน่นอนว่าข้อมูลที่สำคัญที่สุดนั้นคือ private key เพราะหากคุณสูญเสีย private key คุณจะสูญเสียความสามารถในการใช้จ่ายบิตคอยน์ของคุณ การสร้างกุญแจแบบกำหนดได้และรหัสกู้คืน (คำศัพท์ 12-24 คำ) ให้วิธีแก้ปัญหาที่ค่อนข้างแข็งแกร่งสำหรับการสำรองและกู้คืนกุญแจของคุณและบิตคอยน์ที่พวกมันควบคุม แต่อย่างไรก็ตาม สิ่งสำคัญที่ต้องพิจารณาคือฐานข้อมูลกระเป๋าเงินหลายแห่งเก็บข้อมูลมากกว่าแค่กุญแจ </p>
<p>ตัวอย่างเช่น เมื่อบ๊อบสร้าง address ใหม่เพื่อส่ง invoice ให้อลิซ เขาจะเพิ่ม ป้ายกำกับ (label) ให้กับ address นั้น เพื่อให้สามารถแยกการชำระเงินของอลิซออกจากการชำระเงินอื่น ๆ ที่เขาได้รับได้ เมื่ออลิซจ่ายเงินตาม address ดังกล่าว เธอก็ติดป้ายกำกับกับธุรกรรมด้วยเหตุผลเดียวกัน</p>
<p>กระเป๋าเงินบางแห่งยังสามารถบันทึกข้อมูลเพิ่มเติมที่เป็นประโยชน์กับผู้ใช้ เช่น อัตราแลกเปลี่ยนปัจจุบัน ซึ่งช่วยให้คำนวณภาษีหรือรายงานทางบัญชีได้สะดวกยิ่งขึ้น</p>
<p>ป้ายกำกับและข้อมูลเสริมทั้งหมดนี้จะถูกเก็บไว้ ภายในกระเป๋าเงินของผู้ใช้ เท่านั้น ไม่ได้แชร์กับเครือข่ายบิตคอยน์ ซึ่งช่วยปกป้องความเป็นส่วนตัวและลดการเปิดเผยข้อมูลส่วนบุคคลที่ไม่จำเป็นบนบล็อกเชน</p>
<p>สำหรับตัวอย่างข้อมูล สามารถดูได้จากตารางด้านล่างนี้:</p>
<table>
<thead>
<tr>
<th align="left">DATE</th>
<th align="left">LABEL</th>
<th align="left">BTC</th>
</tr>
</thead>
<tbody><tr>
<td align="left">2023-01-01</td>
<td align="left">Bought bitcoins from Joe</td>
<td align="left">+0.00100</td>
</tr>
<tr>
<td align="left">2023-01-02</td>
<td align="left">Paid Bob for podcast</td>
<td align="left">−0.00075</td>
</tr>
</tbody></table>
<blockquote>
<p>ข้อความจากหลาม: ในบางกระเป๋าจะเก็บพวกข้อมูลธุรกรรมของเราด้วย เช่นที่เราส่งหรือที่เรารับ ยกตัวอย่างเช่น sparrow จะเก็บพวก transaction ที่เราเคยรับมา เพื่อให้ไม่ต้องเรียกจาก blockchain หลาย ๆ รอบ</p>
</blockquote>
<p>อย่างไรก็ตาม เนื่องจาก ป้ายกำกับของ address และธุรกรรม ถูกเก็บไว้เฉพาะในฐานข้อมูลกระเป๋าเงินของผู้ใช้แต่ละคน และไม่ได้ถูกกำหนดไว้ล่วงหน้า จึงไม่สามารถกู้คืนได้เพียงแค่ใช้รหัสกู้คืนหรือ seed เมื่อกู้คืนจาก seed ผู้ใช้จะเห็นเพียงรายการเวลาธุรกรรมโดยประมาณและจำนวนบิตคอยน์เท่านั้น ซึ่งอาจทำให้ยากต่อการติดตามว่าเงินถูกใช้ไปอย่างไร ลองนึกภาพการตรวจสอบรายการธนาคารหรือบัตรเครดิตจากปีที่แล้วที่มีวันที่และจำนวนเงินครบ แต่ช่อง “คำอธิบาย” กลับว่างเปล่า</p>
<p>ดังนั้น กระเป๋าเงินควรมีวิธีที่สะดวกสำหรับผู้ใช้ในการ สำรองข้อมูลป้ายกำกับ แม้ว่าจะดูเหมือนเป็นเรื่องชัดเจน แต่หลายแอปพลิเคชันที่ได้รับความนิยมทำให้การสร้างและใช้รหัสกู้คืนเป็นเรื่องง่าย กลับไม่มีวิธีสำรองหรือกู้คืนป้ายกำกับ</p>
<p>นอกจากนี้ อาจเป็นประโยชน์หากกระเป๋าเงินรองรับ รูปแบบมาตรฐานในการส่งออกป้ายกำกับ เพื่อให้สามารถนำไปใช้กับแอปพลิเคชันอื่นได้ เช่น ซอฟต์แวร์บัญชี มาตรฐานสำหรับการส่งออกนี้ถูกเสนอไว้ใน BIP329</p>
<p>สำหรับกระเป๋าเงินที่สนับสนุนโปรโตคอลเพิ่มเติม นอกจากการทำงานพื้นฐานของบิตคอยน์ อาจจำเป็นต้องเก็บข้อมูลอื่น ๆ ด้วย ตัวอย่างเช่น ในปี 2023 แอปพลิเคชันหลายตัวได้เพิ่มการสนับสนุนการส่งและรับธุรกรรมผ่าน Lightning Network (LN) แม้ว่าโปรโตคอล LN จะมีวิธีการกู้คืนเงินในกรณีข้อมูลสูญหายที่เรียกว่า static channel backups แต่ก็ไม่สามารถรับประกันผลลัพธ์ได้ หากโหนดที่กระเป๋าเงินของคุณเชื่อมต่อรู้ว่าคุณสูญเสียข้อมูล โหนดนั้นอาจสามารถขโมยบิตคอยน์จากคุณได้ หากฐานข้อมูลของโหนดสูญหายพร้อมกับฐานข้อมูลของคุณ และไม่มีใครมีสำเนาสำรองเพียงพอ ทั้งคุณและโหนดนั้นก็อาจสูญเสียเงินทั้งหมด</p>
<h2>การสำรองเส้นทางการสร้างกุญแจ (Backing Up Key Derivation Paths)</h2>
<p>ในโครงสร้างกุญแจ BIP32 มีกุญแจระดับแรกประมาณสี่พันล้านคู่ แต่ละคู่สามารถมีลูกของตัวเองอีกสี่พันล้านคู่ และลูกแต่ละตัวก็สามารถมีลูกต่อได้อีกสี่พันล้านคู่ต่อไปเรื่อย ๆ เป็นไปไม่ได้ที่แอปพลิเคชันกระเป๋าเงินจะสร้างแม้แต่เศษเล็กน้อยของคู่กุญแจทั้งหมดในโครงสร้าง BIP32 ซึ่งหมายความว่าการกู้คืนจากการสูญเสียข้อมูลจำเป็นต้องใช้มากกว่ารหัสกู้คืนเพียงอย่างเดียว ต้องอาศัย อัลกอริทึมสำหรับรับ seed (เช่น BIP39) และ อัลกอริทึมการสร้างคู่กุญแจแบบกำหนดได้ (เช่น BIP32) ร่วมด้วย</p>
<p>มีสองวิธีที่ถูกนำเสนอเพื่อแก้ปัญหานี้ วิธีแรกคือ การกำหนดมาตรฐานเส้นทางการสร้างกุญแจ ทุกครั้งที่มีการสร้างหรือเปลี่ยนแปลง address แอปพลิเคชันกระเป๋าบิตคอยน์จะคำนวณ address ใหม่จากเส้นทางมาตรฐานที่กำหนดไว้ ตัวอย่างเช่น BIP44 กำหนดเส้นทางมาตรฐานเป็น m/44'/0'/0' สำหรับ legacy address แอปพลิเคชันกระเป๋าเงินจะใช้เส้นทางนี้ในการคำนวณกุญแจต่าง ๆ ทั้งเมื่อเริ่มใช้งานครั้งแรกและหลังจากกู้คืนจากรหัสกู้คืน</p>
<p>วิธีแก้ปัญหานี้เรียกว่า เส้นทางโดยนัย (Implicit Path) เส้นทางโดยนัยที่เป็นที่นิยมหลายแบบซึ่งกำหนดโดย BIP ต่าง ๆ แสดงอยู่ในตารางด้านล่างนี้:</p>
<table>
<thead>
<tr>
<th>Standard</th>
<th>Script</th>
<th>BIP32 Path</th>
</tr>
</thead>
<tbody><tr>
<td>BIP 44</td>
<td>P2PKH</td>
<td>m/44'/0'/0'</td>
</tr>
<tr>
<td>BIP 49</td>
<td>Nested P2WPKH</td>
<td>m/49'/1'/0'</td>
</tr>
<tr>
<td>BIP 84</td>
<td>P2WPKH</td>
<td>m/84'/0'/0'</td>
</tr>
<tr>
<td>BIP 86</td>
<td>P2TR Single-key</td>
<td>m/86'/0'/0'</td>
</tr>
</tbody></table>
<p>วิธีที่สองคือ การสำรองเส้นทาง (path) ร่วมกับรหัสกู้คืน (recovery code) โดยระบุอย่างชัดเจนว่าเส้นทางใดใช้กับสคริปต์ใด เราเรียกวิธีนี้ว่า การระบุเส้นทางอย่างชัดเจน (explicit paths)</p>
<p>ข้อดีของ เส้นทางโดยปริยาย (implicit paths) คือผู้ใช้ไม่จำเป็นต้องจดจำหรือบันทึกข้อมูลเส้นทางใด ๆ หากป้อนรหัสกู้คืนเข้าไปในแอปพลิเคชันกระเป๋าเงินเดียวกับที่เคยใช้ก่อนหน้านี้ (เวอร์ชันเดียวกันหรือล่าสุดกว่า) ระบบจะสร้างกุญแจสำหรับเส้นทางเดิมโดยอัตโนมัติ</p>
<p>ข้อเสียของ implicit paths คือความไม่ยืดหยุ่น เมื่อใช้รหัสกู้คืน แอปพลิเคชันจะต้องสร้างกุญแจสำหรับทุกเส้นทางที่รองรับ และต้องสแกนบล็อกเชนเพื่อค้นหาธุรกรรมที่เกี่ยวข้อง หากไม่ทำเช่นนั้น อาจทำให้ไม่พบธุรกรรมทั้งหมดของผู้ใช้ วิธีนี้จึงสิ้นเปลืองทรัพยากร โดยเฉพาะในกระเป๋าที่รองรับฟีเจอร์หลายอย่างแต่ผู้ใช้อาจใช้เพียงบางฟีเจอร์เท่านั้น</p>
<p>สำหรับ implicit path recovery codes ที่ไม่มีหมายเลขเวอร์ชัน เช่น BIP39 และ SLIP39 เวอร์ชันใหม่ของแอปกระเป๋าที่เลิกสนับสนุนเส้นทางเก่า ๆ จะไม่สามารถเตือนผู้ใช้ระหว่างกู้คืนได้ว่าเงินบางส่วนอาจไม่ถูกค้นพบ เช่นเดียวกัน หากผู้ใช้ป้อนรหัสกู้คืนลงในซอฟต์แวร์รุ่นเก่า ซอฟต์แวร์ก็จะไม่สามารถค้นหาเส้นทางใหม่ ๆ ที่ผู้ใช้อาจเคยได้รับเงินเข้ามาได้</p>
<p>รหัสกู้คืนที่มีข้อมูลเวอร์ชัน เช่น Electrum v2 และ Aezeed สามารถตรวจจับได้ว่าผู้ใช้กำลังป้อนรหัสกู้คืนที่ใหม่กว่าหรือเก่ากว่า และสามารถแนะนำผู้ใช้ไปยังแหล่งข้อมูลที่เหมาะสมได้</p>
<p>ผลลัพธ์ของ implicit paths คือมันสามารถรวมเฉพาะข้อมูลที่เป็นสากล (เช่น เส้นทางที่กำหนดเป็นมาตรฐาน) หรือข้อมูลที่ได้จาก seed (เช่น keys) เท่านั้น ข้อมูลที่ไม่เป็นเชิงกำหนดและเฉพาะตัวผู้ใช้ไม่สามารถกู้คืนได้</p>
<p>ตัวอย่างเช่น Alice, Bob และ Carol มีบิตคอยน์ที่สามารถใช้ลายเซ็นของสองในสามคนได้ แม้ Alice ต้องการเพียงลายเซ็นของ Bob หรือ Carol เพื่อใช้จ่าย เธอก็ยังต้องมี public keys ของทั้งสองคนเพื่อค้นหาทรัพย์สินร่วมบนบล็อกเชน ซึ่งหมายความว่าทุกคนต้องสำรอง public keys ของทั้งสามคน เมื่อ multisignature และสคริปต์ขั้นสูงอื่น ๆ ถูกใช้งานมากขึ้น ความไม่ยืดหยุ่นของ implicit paths ก็ชัดเจนขึ้น</p>
<p>ข้อดีของ explicit paths คือสามารถระบุได้ชัดเจนว่า key ใดใช้กับ script ใด ทำให้ไม่จำเป็นต้องรองรับสคริปต์ล้าสมัย ไม่มีปัญหาความเข้ากันได้ย้อนหลังหรือไปข้างหน้า และข้อมูลเพิ่มเติม เช่น public keys ของผู้ใช้อื่น สามารถรวมเข้าไปได้โดยตรง</p>
<p>ข้อเสียคือผู้ใช้ต้องสำรองข้อมูลเพิ่มเติมควบคู่กับรหัสกู้คืน ข้อมูลเหล่านี้โดยทั่วไปไม่กระทบต่อความปลอดภัย จึงไม่ต้องการการป้องกันเท่ารหัสกู้คืน แต่ยังคงลดความเป็นส่วนตัวและต้องมีการปกป้องบางส่วน</p>
<p>กระเป๋าเงินเกือบทั้งหมดที่ใช้ explicit paths ปัจจุบันใช้ output script descriptors (เรียกสั้น ๆ ว่า descriptors) ตามที่กำหนดใน BIPs 380, 381, 382, 383, 384, 385, 386 และ 389 โดย descriptors ใช้อธิบาย script และ keys (หรือ key paths) ที่ควรใช้งานร่วมกับมัน</p>
<table>
<thead>
<tr>
<th>Descriptor</th>
<th>Explanation</th>
</tr>
</thead>
<tbody><tr>
<td><code>pkh(02c6…​9ee5)</code></td>
<td>P2PKH script สำหรับ public key ที่ให้มา</td>
</tr>
<tr>
<td><code>sh(multi(2,022f…​2a01,03ac…​ccbe))</code></td>
<td>P2SH multisignature script ที่ต้องการลายเซ็นสองอันที่สอดคล้องกับ public key ทั้งสองนี้</td>
</tr>
<tr>
<td><code>pkh([d34db33f/44'/0'/0']xpub6ERA…​RcEL/1/*)</code></td>
<td>P2PKH scripts สำหรับ BIP32 path <code>d34db33f</code> โดยใช้ extended public key (xpub) ที่ path <code>M/44'/0'/0'</code> ซึ่งคือ <code>xpub6ERA…​RcEL</code> และใช้ keys ที่ path <code>M/1/*</code> ของ xpub นั้น</td>
</tr>
</tbody></table>
<p>เป็นเวลานานแล้วที่กระเป๋าเงิน (wallet applications) ที่ออกแบบมาเพื่อใช้งานกับ single signature scripts เพียงอย่างเดียว มักใช้ implicit paths ส่วนกระเป๋าเงินที่ออกแบบมาสำหรับ multisignature หรือสคริปต์ขั้นสูงอื่น ๆ นั้น กำลังหันมาใช้ explicit paths โดยใช้ descriptors มากขึ้นเรื่อย ๆ สำหรับแอปพลิเคชันที่รองรับทั้งสองแบบ มักจะปฏิบัติตามมาตรฐานของ implicit paths และในขณะเดียวกันก็ให้การรองรับ descriptors ด้วย</p>
<h2>เทคโนโลยีของกระเป๋าเงิน (A Wallet Technology Stack in Detail)</h2>
<p>นักพัฒนากระเป๋าเงินสมัยใหม่สามารถเลือกใช้เทคโนโลยีหลายรูปแบบเพื่อช่วยผู้ใช้ในการสร้างและจัดการการสำรองข้อมูล โดยทุกปีจะมีโซลูชันใหม่ ๆ เกิดขึ้น แทนที่จะลงลึกในรายละเอียดของแต่ละตัวเลือกที่อธิบายไปก่อนหน้านี้ในบทนี้ เราจะเน้นที่ชุดเทคโนโลยี (technology stack) ที่นิยมใช้อย่างแพร่หลายในกระเป๋าเงิน ณ ต้นปี 2023 ได้แก่:</p>
<ul>
<li>BIP39 recovery codes</li>
<li>BIP32 HD key derivation</li>
<li>BIP44-style implicit paths</li>
</ul>
<p>มาตรฐานเหล่านี้มีมาตั้งแต่ปี 2014 หรือก่อนหน้านั้น และสามารถหาข้อมูลเพิ่มเติมเพื่อนำมาใช้งานได้ไม่ยาก อย่างไรก็ตาม หากคุณสนใจทดลองสิ่งใหม่ ๆ เราแนะนำให้ศึกษามาตรฐานสมัยใหม่ที่อาจเพิ่มฟีเจอร์หรือความปลอดภัยให้มากขึ้นได้</p>
<h3>BIP39 Recovery Codes</h3>
<p>BIP39 recovery codes คือ ลำดับคำ (word sequences) ที่ใช้แทนตัวเลขสุ่ม เพื่อทำหน้าที่เป็น seed สำหรับการสร้างกระเป๋าเงินแบบกำหนดค่าได้ล่วงหน้า (deterministic wallet) ลำดับคำชุดเดียวก็เพียงพอที่จะสร้าง seed ใหม่ และสามารถสร้างกุญแจทั้งหมดที่เกี่ยวข้อง (derived keys) ได้</p>
<p>แอปกระเป๋าเงินที่รองรับ deterministic wallets ด้วย BIP39 recovery codes จะให้ผู้ใช้บันทึกลำดับคำจำนวน 12–24 คำ เมื่อสร้างกระเป๋าเงินครั้งแรก ลำดับคำเหล่านี้ทำหน้าที่เป็น การสำรองข้อมูลของกระเป๋าเงิน (wallet backup) และสามารถใช้กู้คืนหรือสร้างกุญแจทั้งหมดใหม่ได้ ไม่ว่าจะใช้แอปเดียวกันหรือแอปกระเป๋าเงินอื่นที่รองรับมาตรฐานเดียวกัน</p>
<p>รหัสกู้คืน (recovery codes) ทำให้การสำรองข้อมูลสะดวกขึ้น เพราะอ่านง่าย และสามารถถ่ายทอดหรือจดบันทึกได้อย่างถูกต้อง</p>
<blockquote>
<p>Tip:รหัสกู้คืน (recovery codes) มักถูกเข้าใจผิดว่าเหมือนกับ “brainwallets” แต่จริง ๆ แล้วไม่เหมือนกัน ความแตกต่างหลักคือ</p>
<ul>
<li>Brainwallet → เป็นคำที่ผู้ใช้เลือกขึ้นมาเอง</li>
<li>Recovery code → เป็นคำที่ถูกสุ่มสร้างขึ้นโดยกระเป๋าเงิน แล้วแสดงให้ผู้ใช้บันทึก</li>
</ul>
<p>ความแตกต่างนี้สำคัญมาก เพราะทำให้ recovery codes มีความปลอดภัยกว่ามาก เนื่องจากมนุษย์มักจะไม่สามารถสร้างความสุ่มที่แท้จริงได้ดีนัก</p>
</blockquote>
<p>โปรดทราบว่า BIP39 เป็นหนึ่งในการนำมาตรฐานรหัสกู้คืน (recovery code standard) มาประยุกต์ใช้ โดย BIP39 ถูกเสนอโดยบริษัทผู้อยู่เบื้องหลัง Trezor hardware wallet และสามารถใช้งานร่วมกับแอปกระเป๋าเงินอื่น ๆ ได้มากมาย แม้ว่าจะไม่ใช่ทุกแอปที่จะรองรับก็ตาม</p>
<h4>การสร้างรหัสสำรอง (Generating a Recovery Code)</h4>
<p>รหัสกู้คืน (Recovery codes) ถูกสร้างขึ้นโดยอัตโนมัติจากแอปกระเป๋าเงิน โดยใช้กระบวนการมาตรฐานที่กำหนดไว้ใน BIP39 ขั้นตอนการสร้างมีดังนี้:</p>
<ol>
<li>สร้างลำดับสุ่ม (entropy) ความยาวระหว่าง 128 ถึง 256 บิต</li>
<li>สร้างค่า checksum ของลำดับสุ่ม โดยการนำบิตแรกจำนวน (ความยาว entropy ÷ 32) ของค่า SHA256 hash มาใช้</li>
<li>เติมค่า checksum ต่อท้ายลำดับ entropy</li>
<li>แบ่งผลลัพธ์ออกเป็นกลุ่มย่อย ความยาว 11 บิตต่อกลุ่ม</li>
<li>นำค่า 11 บิตแต่ละกลุ่มไปแมปกับคำหนึ่งคำจาก พจนานุกรมมาตรฐานที่มี 2,048 คำ</li>
<li>ผลลัพธ์สุดท้ายก็คือ รหัสกู้คืน (recovery code) ซึ่งอยู่ในรูปแบบลำดับคำ (word sequence)<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0504.png" alt="image"></li>
</ol>
<h5>BIP39:Entropy และความยาวของคำ</h5>
<table>
<thead>
<tr>
<th align="center">Entropy (bits)</th>
<th align="center">Checksum (bits)</th>
<th align="center">Entropy + checksum (bits)</th>
<th align="center">Recovery code words</th>
</tr>
</thead>
<tbody><tr>
<td align="center">128</td>
<td align="center">4</td>
<td align="center">132</td>
<td align="center">12</td>
</tr>
<tr>
<td align="center">160</td>
<td align="center">5</td>
<td align="center">165</td>
<td align="center">15</td>
</tr>
<tr>
<td align="center">192</td>
<td align="center">6</td>
<td align="center">198</td>
<td align="center">18</td>
</tr>
<tr>
<td align="center">224</td>
<td align="center">7</td>
<td align="center">231</td>
<td align="center">21</td>
</tr>
<tr>
<td align="center">256</td>
<td align="center">8</td>
<td align="center">264</td>
<td align="center">24</td>
</tr>
</tbody></table>
<h4>จากรหัสกู้คืนสู่seed (From recovery code to seed)</h4>
<p>รหัสกู้คืน (recovery code) แทนค่า entropy ที่มีความยาวระหว่าง 128 ถึง 256 บิต จากนั้น entropy จะถูกใช้สร้าง seed ที่ยาวกว่า (512 บิต) ผ่านฟังก์ชัน key-stretching ชื่อ PBKDF2 ซึ่ง seed ที่ได้จะถูกนำไปสร้างกระเป๋าเงินแบบกำหนดค่าได้ล่วงหน้า (deterministic wallet) และสร้างกุญแจอนุพันธ์ (derived keys) ต่อไป</p>
<p>ฟังก์ชัน key-stretching จะรับพารามิเตอร์สองค่า ได้แก่ entropy และ salt ปกติ salt มีหน้าที่ป้องกันการโจมตีแบบ brute-force โดยทำให้การสร้างตารางค้นหาทำได้ยากขึ้น แต่ในมาตรฐาน BIP39 salt ยังใช้อนุญาตให้ผู้ใช้เพิ่ม passphrase ซึ่งเป็นปัจจัยด้านความปลอดภัยเพิ่มเติมสำหรับการป้องกัน seed (จะอธิบายรายละเอียดในหัวข้อ Optional passphrase in BIP39)</p>
<blockquote>
<p>Tip: ฟังก์ชัน key-stretching ของ BIP39 ใช้การแฮช 2,048 รอบ ทำให้การโจมตีแบบ brute-force ด้วยซอฟต์แวร์ทำได้ยากขึ้นเล็กน้อย แต่ฮาร์ดแวร์เฉพาะทาง (special-purpose hardware) จะไม่ได้รับผลกระทบมากนัก สำหรับผู้โจมตีที่ต้องเดา recovery code ทั้งหมด ความยาวขั้นต่ำ 128 บิตของรหัสก็เพียงพอที่จะมอบความปลอดภัยสูงแล้ว อย่างไรก็ตาม หากผู้โจมตีรู้บางส่วนของรหัส ฟังก์ชัน key-stretching จะช่วยเพิ่มความปลอดภัยโดยทำให้การตรวจสอบความเป็นไปได้ของรหัสแต่ละแบบช้าลง</p>
</blockquote>
<p>อย่างไรก็ดี พารามิเตอร์ของ BIP39 ถูกมองว่าค่อนข้างอ่อนแอเมื่อเทียบกับมาตรฐานสมัยใหม่ แม้ในช่วงที่เผยแพร่เมื่อเกือบสิบปีก่อน ก็เพื่อรองรับอุปกรณ์ hardware signing devices ที่มี CPU กำลังต่ำ มาตรฐานทางเลือกบางตัว เช่น Aezeed ใช้การแฮช 32,768 รอบผ่านอัลกอริทึม Scrypt ที่ซับซ้อนกว่า แม้ว่าจะไม่สะดวกในการใช้งานบนอุปกรณ์ฮาร์ดแวร์</p>
<p>กระบวนการดังกล่าวในขั้นตอนที่ 7 ถึง 10 เป็นการต่อเนื่องจากหัวข้อ Generating a recovery code ที่อธิบายไปก่อนหน้านี้:</p>
<ol start="7">
<li>พารามิเตอร์แรก ของฟังก์ชัน key-stretching PBKDF2 คือ entropy ที่ได้มาจาก ขั้นตอนที่ 6</li>
<li>พารามิเตอร์ที่สอง ของ PBKDF2 คือ salt โดย salt นี้ถูกสร้างขึ้นจากสตริงคงที่ "mnemonic" ต่อเข้ากับสตริง passphrase ที่ผู้ใช้จะใส่เพิ่ม (ซึ่งเป็นทางเลือก ไม่จำเป็นต้องใส่)</li>
<li>PBKDF2 จะทำการขยาย (stretch) recovery code และ salt ด้วยการแฮชจำนวน 2,048 รอบ โดยใช้อัลกอริทึม HMAC-SHA512 และสร้างค่าผลลัพธ์สุดท้ายเป็นค่า 512 บิต</li>
<li>ค่าที่ได้ซึ่งเป็น 512 บิต นี้ก็คือ seed<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0505.png" alt="image"></li>
</ol>
<h5>128-bit entropy BIP39 recovery code, no passphrase, resulting seed</h5>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1759396589355-YAKIHONNES3.png" alt="image"></p>
<h5>128-bit entropy BIP39 recovery code, with passphrase, resulting seed</h5>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1759410306820-YAKIHONNES3.png" alt="image"></p>
<h5>256-bit entropy BIP39 recovery code, no passphrase, resulting seed</h5>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1759410572591-YAKIHONNES3.png" alt="image"></p>
<h4>คุณต้องการ Entropy มากแค่ไหน?</h4>
<p>BIP32 อนุญาตให้ seed มีค่าได้ตั้งแต่ 128 ถึง 512 บิต BIP39 รับค่าได้ตั้งแต่ 128 ถึง 256 บิต; Electrum v2 รับค่าได้ 132 บิต; Aezeed รับค่าได้ 128 บิต; SLIP39 รับค่าได้ 128 หรือ 256 บิต ความแตกต่างของตัวเลขเหล่านี้ทำให้ไม่ชัดเจนว่าต้องใช้ entropy เท่าไรถึงจะปลอดภัย เราจะพยายามอธิบายให้กระจ่าง</p>
<p>extended private key ของ BIP32 ประกอบด้วยคีย์ขนาด 256 บิตและ chain code ขนาด 256 บิต รวมทั้งหมด 512 บิต นั่นหมายความว่ามีคีย์ส่วนตัวแบบขยายได้สูงสุด 2^512 แบบ หากคุณเริ่มต้นด้วย entropy ที่มากกว่า 512 บิต คุณก็ยังจะได้ extended private key ที่มี entropy เพียง 512 บิตอยู่ดี—ดังนั้นจึงไม่มีประโยชน์ที่จะใช้มากกว่า 512 บิต แม้ว่าในบรรดามาตรฐานที่กล่าวมาจะอนุญาตให้ทำก็ตาม</p>
<p>อย่างไรก็ตาม แม้ว่าจะสามารถสร้างคีย์ส่วนตัวแบบขยาย (extended private key) ได้มากถึง 2^512 แบบ แต่คีย์ส่วนตัวจริง ๆ (regular private key) ที่ใช้งานได้มีเพียงประมาณ 2^256 แบบเท่านั้น—และคีย์เหล่านี้เองที่เป็นตัวปกป้องบิตคอยน์ของคุณ ซึ่งหมายความว่า ถึงคุณจะใช้ entropy เกิน 256 บิตในการสร้าง seed สุดท้ายแล้วคีย์ส่วนตัวที่ได้ก็ยังมี entropy เพียง 256 บิตอยู่ดี แม้ว่าในอนาคตอาจมีโปรโตคอลบิตคอยน์บางชนิดที่สามารถนำ entropy ส่วนเกินใน extended key มาใช้เพื่อเพิ่มความปลอดภัย แต่ในปัจจุบันยังไม่มีการใช้งานจริง</p>
<p>ระดับความปลอดภัยของ public key บิตคอยน์อยู่ที่ 128 บิต หมายความว่าผู้โจมตีต้องคำนวณราว 2^128 ครั้งบน elliptic curve จึงจะหาคีย์ส่วนตัวได้ ดังนั้นการใช้ entropy เกิน 128 บิตไม่ได้เพิ่มประโยชน์ด้านความปลอดภัย ตราบใดที่คีย์ส่วนตัวถูกสุ่มอย่างทั่วถึงในช่วง 2^256 ทั้งหมด</p>
<p>มีประโยชน์เพิ่มเติมอย่างหนึ่งจาก entropy ที่มากขึ้น: ถ้าผู้โจมตีเห็น recovery code ของคุณบางส่วน (แต่ไม่ใช่ทั้งหมด) ยิ่ง entropy มาก การที่เขาจะเดาส่วนที่เหลือก็จะยากขึ้น ยกตัวอย่างเช่น ถ้าผู้โจมตีเห็นครึ่งหนึ่งของโค้ด 128 บิต (64 บิต) ก็มีความเป็นไปได้ที่เขาจะ brute force อีก 64 บิตที่เหลือได้ แต่ถ้าเขาเห็นครึ่งหนึ่งของโค้ด 256 บิต (128 บิต) ก็ไม่เป็นไปได้ที่เขาจะ brute force ส่วนที่เหลือได้ เราไม่แนะนำให้พึ่งพาการป้องกันแบบนี้—ควรเก็บ recovery code ของคุณให้ปลอดภัย หรือใช้วิธีอย่าง SLIP39 ที่ให้คุณสามารถกระจาย recovery code ไว้หลายที่ โดยไม่ต้องอาศัยความปลอดภัยจากโค้ดใดโค้ดหนึ่งเพียงอย่างเดียว</p>
<p>ณ ปี 2023 กระเป๋าสตางค์สมัยใหม่ส่วนใหญ่สร้าง entropy ขนาด 128 บิตสำหรับ recovery code ของพวกเขา (หรือค่าที่ใกล้เคียง 128 เช่น Electrum v2 ที่ใช้ 132 บิต)</p>
<h4>passphrase ใน BIP39</h4>
<p>มาตรฐาน BIP39 อนุญาตให้ใส่ passphrase เสริมเพื่อสร้าง seed  หากไม่ใส่ จะใช้ salt เป็นสตริงคงที่ "mnemonic" ทำให้ recovery code ใด ๆ ให้ผลเป็น seed เดียวตามมาตรฐาน แต่เมื่อมี passphrase ใด ๆ เข้ามา จะได้ seed ที่ต่างจากเดิม: ทุก passphrase ที่เป็นไปได้จะให้ seed คนละค่า ไม่มีค่าใดที่ถือว่า “ผิด” ดังนั้นรหัสกู้คืนชุดเดียวสามารถจับคู่กับ passphrase หลายค่าได้ ผลคือมีชุดกระเป๋า (wallets) ขนาดมหาศาล ขยายได้ถึงระดับประมาณ 2^512 ทำให้การเดาแบบ brute-force เพื่อไปพบกระเป๋าที่มีการใช้งานจริงเป็นสิ่งที่เป็นไปไม่ได้ในทางปฏิบัติ.</p>
<blockquote>
<p>Tip: ใน BIP39 ไม่มี passphrase ที่ “ผิด” ทุก passphrase จะนำไปสู่กระเป๋าสตางค์บางใบ ซึ่งหากไม่เคยถูกใช้งานมาก่อน กระเป๋าสตางค์นั้นก็จะว่างเปล่า</p>
</blockquote>
<p>Passphrase แบบเลือกใช้จะสร้างคุณสมบัติที่สำคัญสองประการ:</p>
<ul>
<li>มีสิ่งที่จดจำได้ ที่ทำให้ recovery code ใช้งานไม่ได้ด้วยตัวมันเอง ปกป้อง recovery code จากการถูกขโมยโดยโจรทั่วไป สำหรับการป้องกันจากโจรที่มีความรู้ด้านเทคนิค คุณจำเป็นต้องใช้ passphrase ที่แข็งแกร่งมาก</li>
<li>รูปแบบหนึ่งของ plausible deniability หรือ “กระเป๋าลับ” (duress wallet) ซึ่ง passphrase ที่เลือกจะนำไปยังกระเป๋าที่มีเงินจำนวนน้อย ใช้เพื่อเบี่ยงเบนความสนใจของผู้โจมตีจาก “กระเป๋าจริง” ที่เก็บเงินส่วนใหญ่</li>
</ul>
<p>สิ่งสำคัญที่ควรทราบคือ การใช้ passphrase ยังนำมาซึ่งความเสี่ยงของการสูญเสีย:</p>
<ul>
<li>หากเจ้าของกระเป๋าไม่สามารถใช้งานได้หรือเสียชีวิตไป และไม่มีใครรู้ passphrase ค่า seed จะไร้ประโยชน์ และเงินทั้งหมดที่เก็บในกระเป๋าจะสูญหายไปตลอดกาล</li>
<li>ในทางกลับกัน หากเจ้าของทำการสำรอง passphrase ไว้ในที่เดียวกับ seed มันก็จะทำลายวัตถุประสงค์ของการมีปัจจัยที่สอง</li>
</ul>
<p>แม้ว่า passphrase จะมีประโยชน์มาก แต่ควรใช้งานร่วมกับกระบวนการที่วางแผนอย่างรอบคอบสำหรับการสำรองและการกู้คืน โดยคำนึงถึงความเป็นไปได้ในการมีชีวิตต่อจากเจ้าของ และเปิดโอกาสให้ครอบครัวสามารถกู้คืนได้</p>
<h3>การสร้าง HD Wallet จาก Seed</h3>
<p>กระเป๋าเงินแบบ HD ถูกสร้างจาก root seed เดียว ซึ่งเป็นตัวเลขสุ่มขนาด 128, 256 หรือ 512 บิต โดยทั่วไป seed นี้จะถูกสร้างขึ้นโดยแอปหรือถอดรหัสมาจาก recovery code ตามที่อธิบายไว้ก่อนหน้านี้</p>
<p>กุญแจทุกดอกในกระเป๋าเงิน HD จะถูกอนุพันธ์อย่างกำหนดได้จาก root seed เดียวกัน ส่งผลให้สามารถสร้างกระเป๋าเงิน HD ทั้งหมดใหม่ได้จาก seed ชุดเดียว ในระบบที่เข้ากันได้ วิธีนี้ทำให้การ สำรอง, กู้คืน, ส่งออก และ นำเข้ากระเป๋าเงิน ซึ่งอาจมีจำนวนกุญแจเป็นพันหรือเป็นล้าน ดำเนินการได้สะดวกเพียงแค่เก็บรักษา recovery code ที่มาจาก root seed เท่านั้น</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0506.png" alt="image"></p>
<p>root seed จะถูกป้อนเข้าไปในอัลกอริทึม HMAC-SHA512 และค่าแฮชที่ได้จะถูกนำมาใช้สร้าง master private key (m) และ master chain code (c)</p>
<p>จากนั้น master private key (m) จะสร้าง master public key (M) ที่สอดคล้องกัน โดยใช้กระบวนการ elliptic curve multiplication แบบปกติ คือ m × G ตามที่เราเห็นไปแล้วใน public_key_derivation</p>
<p>ส่วน master chain code (c) จะถูกใช้เพื่อเพิ่ม entropy ในฟังก์ชันที่สร้าง child keys จาก parent keys ซึ่งเราจะได้เห็นในหัวข้อถัดไป</p>
<h4>Private child key derivation</h4>
<p>กระเป๋าเงิน HD ใช้ฟังก์ชัน child key derivation (CKD) เพื่อสร้าง child keys จาก parent keys</p>
<p>ฟังก์ชัน CKD จะอิงกับ one-way hash function ที่รวมข้อมูลดังนี้:</p>
<ul>
<li>กุญแจ private หรือ public ของ parent (uncompressed key)</li>
<li>chain code (256 บิต)</li>
<li>หมายเลขดัชนี (index number) (32 บิต)</li>
</ul>
<p>chain code ถูกใช้เพื่อเพิ่มข้อมูลสุ่มเชิงกำหนด (deterministic random data) ลงในกระบวนการ เพื่อให้การรู้แค่ index และ child key ไม่เพียงพอที่จะสร้าง child keys อื่น ๆ ได้ การรู้เพียง child key ไม่สามารถหาพี่น้อง (siblings) ของมันได้ เว้นแต่จะมี chain code ด้วย โดย chain code เริ่มต้น (ที่ root ของ tree) จะมาจาก seed ในขณะที่ chain codes ถัดไปจะถูกอนุพันธ์มาจาก chain code ของ parent แต่ละตัว</p>
<p>สามองค์ประกอบนี้ (parent key, chain code, index) จะถูกนำมารวมกันและทำการ hash เพื่อสร้าง child keys ดังนี้:</p>
<ul>
<li>parent public key, chain code และ index number จะถูกนำมารวมกันแล้วทำการ hash ด้วยอัลกอริทึม HMAC-SHA512 เพื่อสร้างค่าแฮช 512 บิต</li>
<li>ค่าแฮช 512 บิตนี้จะถูกแบ่งออกเป็นสองส่วน ส่วนละ 256 บิต<ul>
<li>ครึ่งขวา (256 บิต) จะกลายเป็น chain code สำหรับ child</li>
<li>ครึ่งซ้าย (256 บิต) จะถูกนำไปบวกกับ parent private key เพื่อสร้าง child private key</li>
</ul>
</li>
</ul>
<p>จากรูปข้างล่างเราจะเห็นตัวอย่างที่ใช้ index = 0 เพื่อสร้าง child ตัวแรก (zero child) ของ parent<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0507.png" alt="image"></p>
<p>การเปลี่ยนค่า index ช่วยให้สามารถขยายจากกุญแจแม่ (parent key) เพื่อสร้างกุญแจลูก (child keys) ในลำดับได้ เช่น Child 0, Child 1, Child 2 และต่อไปเรื่อย ๆ โดยกุญแจแม่แต่ละดอกสามารถมีลูกได้สูงสุด 2,147,483,647 ดอก (2³¹) ซึ่งคิดเป็นครึ่งหนึ่งของช่วงค่า 2³² ทั้งหมด อีกครึ่งหนึ่งถูกสงวนไว้สำหรับรูปแบบการอนุพันธ์พิเศษที่จะอธิบายในบทถัดไป</p>
<p>เมื่อกระบวนการนี้ถูกทำซ้ำในระดับถัดไป แต่ละกุญแจลูกก็สามารถกลายเป็นกุญแจแม่และสร้างกุญแจลูกของมันเองต่อไปได้เช่นกัน ทำให้เกิดการขยายแบบลำดับชั้นได้อย่างไม่จำกัด (infinite generations)</p>
<h4>Using derived child keys</h4>
<p>child private keys ไม่สามารถแยกความแตกต่างได้จากกุญแจแบบไม่กำหนดล่วงหน้า (nondeterministic หรือกุญแจสุ่ม) เนื่องจากฟังก์ชัน derivation เป็น one-way function ดังนั้น child key ไม่สามารถถูกใช้เพื่อหากุญแจ parent ได้ และ child key ก็ไม่สามารถถูกใช้เพื่อหาพี่น้อง (siblings) ได้เช่นกัน หากคุณมีกุญแจลูกลำดับที่ n คุณจะไม่สามารถหาพี่น้องของมัน เช่น กุญแจ n–1 หรือ n+1 หรือกุญแจอื่น ๆ ที่อยู่ในลำดับได้ มีเพียง parent key และ chain code เท่านั้น ที่สามารถอนุพันธ์ลูกทั้งหมดออกมาได้ หากไม่มี child chain code กุญแจลูกก็ไม่สามารถถูกใช้เพื่อสร้างกุญแจหลาน (grandchildren) ได้เช่นกัน คุณจำเป็นต้องมีทั้ง child private key และ child chain code เพื่อเริ่มต้นสาขาใหม่และสร้าง grandchildren</p>
<p>แล้ว child private key สามารถใช้ทำอะไรได้บ้าง? มันสามารถถูกใช้เพื่อสร้าง public key และ Bitcoin address และสามารถใช้เพื่อ เซ็นธุรกรรม (sign transactions) เพื่อใช้จ่าย Bitcoin ที่ถูกส่งเข้ามายัง address นั้นได้</p>
<blockquote>
<p>Tip: child private key, public key ที่สอดคล้องกัน และ Bitcoin address ทั้งหมดนี้ไม่สามารถแยกความแตกต่างได้จากกุญแจและ address ที่ถูกสร้างขึ้นแบบสุ่ม ความจริงที่ว่ามันเป็นส่วนหนึ่งของลำดับจะไม่สามารถมองเห็นได้จากภายนอกฟังก์ชันของ HD wallet ที่สร้างมันขึ้นมา และเมื่อมันถูกสร้างขึ้นแล้ว มันก็ทำงานเหมือนกับกุญแจ “ปกติ” ทุกประการ</p>
</blockquote>
<h4>Extended keys</h4>
<p>ตามที่เราได้เห็นไปก่อนหน้านี้ ฟังก์ชัน key derivation สามารถถูกใช้เพื่อสร้าง children ได้ในทุกระดับของ tree โดยอ้างอิงจากข้อมูลนำเข้าสามส่วน: key, chain code และ index ของ child ที่ต้องการ โดยองค์ประกอบที่สำคัญที่สุดสองอย่างคือ key และ chain code ซึ่งเมื่อรวมกันแล้วจะถูกเรียกว่า extended key คำว่า extended key อาจถูกมองว่าเป็น extensible key ก็ได้ เพราะกุญแจลักษณะนี้สามารถถูกใช้เพื่อสร้าง children ได้</p>
<p>Extended keys จะถูกเก็บและแสดงผลในรูปแบบง่าย ๆ คือการนำ key มาต่อกับ chain code ซึ่งมีอยู่สองประเภทหลัก ได้แก่:</p>
<ul>
<li><p>Extended private key คือการรวมกันของ private key และ chain code ที่สามารถใช้สร้าง child private keys ได้ (และจากนั้นก็สร้าง child public keys ได้อีกต่อหนึ่ง)</p>
</li>
<li><p>Extended public key คือการรวมกันของ public key และ chain code ที่สามารถใช้สร้างได้เฉพาะ child public keys เท่านั้น ตามที่อธิบายไว้ใน public_key_derivation</p>
</li>
</ul>
<p>ลองนึกภาพ extended key เป็นเสมือนรากของกิ่งก้าน (branch) ในโครงสร้างต้นไม้ของ HD wallet เมื่อคุณมีรากนี้แล้ว ก็สามารถแตกกิ่งก้านที่เหลือต่อไปได้ โดย extended private key จะสร้างกิ่งก้านที่สมบูรณ์ได้ทั้งหมด ขณะที่ extended public key จะสร้างได้เพียงกิ่งก้านที่ประกอบด้วยเฉพาะ public keys เท่านั้น</p>
<p>Extended keys ยังถูกเข้ารหัสด้วย base58check เพื่อให้ง่ายต่อการส่งออกและนำเข้าไปยังกระเป๋าเงินอื่น ๆ ที่รองรับ BIP32 โดยการเข้ารหัส base58check สำหรับ extended keys จะใช้หมายเลขเวอร์ชันพิเศษ ทำให้เมื่อถูกเข้ารหัสออกมาเป็นอักขระ base58 จะขึ้นต้นด้วย prefix ที่จดจำง่ายอย่าง "xprv" และ "xpub" ทั้งนี้ เนื่องจาก extended key บรรจุข้อมูลมากกว่าที่อยู่ (address) ปกติหลายเท่า มันจึงมีความยาวมากกว่าสตริงที่เข้ารหัสด้วย base58check แบบอื่น ๆ ที่เราเคยเห็นมาก่อนหน้านี้</p>
<p>นี่คือตัวอย่างของ extended private key ที่เข้ารหัสด้วย base58check:</p>
<pre><code>xprv9tyUQV64JT5qs3RSTJkXCWKMyUgoQp7F3hA1xzG6ZGu6u6Q9VMNjGr67Lctvy5P8oyaYAL9CAWrUE9i6GoNMKUga5biW6Hx4tws2six3b9c
</code></pre>
<p>นี่คือตัวอย่างของ extended public key ที่เข้ารหัสด้วย base58check ซึ่งตรงกับ private key ข้างต้น:</p>
<pre><code>xpub67xpozcx8pe95XVuZLHXZeG6XWXHpGq6Qv5cmNfi7cS5mtjJ2tgypeQbBs2UAR6KECeeMVKZBPLrtJunSDMstweyLXhRgPxdp14sk9tJPW9
</code></pre>
<h4>การสร้าง Public child key derivation</h4>
<p>ดังที่กล่าวไว้ก่อนหน้านี้ คุณสมบัติที่มีประโยชน์อย่างมากของ HD wallet คือความสามารถในการสร้างกุญแจสาธารณะลูกได้จากกุญแจสาธารณะหลักโดยไม่ต้องมี private key อยู่ด้วย วิธีนี้ทำให้มีสองแนวทางในการได้มาซึ่งกุญแจสาธารณะลูก: สร้างจาก private child key หรือสร้างโดยตรงจาก extended public key ของกุญแจหลัก</p>
<p>Extended public key สามารถใช้สร้างกุญแจสาธารณะทั้งหมด (แต่เฉพาะกุญแจสาธารณะเท่านั้น) ในสาขาหนึ่งของโครงสร้าง HD wallet ได้ ทางลัดนี้เปิดทางให้สร้างระบบที่ทำงานบนข้อมูลสาธารณะเพียงอย่างเดียว — เซิร์ฟเวอร์หรือแอปพลิเคชันสามารถมีสำเนา extended public key แต่ไม่ได้เก็บ private key ใด ๆ ไว้ การติดตั้งแบบนี้อนุญาตให้เซิร์ฟเวอร์สร้างกุญแจสาธารณะและที่อยู่บิตคอยน์ได้ไม่จำกัด ขณะเดียวกันก็ไม่สามารถใช้จ่ายเงินจากที่อยู่เหล่านั้นได้</p>
<p>เมื่อต้องการใช้เงินจริง ให้ย้ายกระบวนการลงนามไปยังเครื่องที่ปลอดภัยกว่า ซึ่งเก็บ extended private key หรือ private keys ไว้ เสียง่ายคือ เซิร์ฟเวอร์สาธารณะทำหน้าที่ “สร้างที่อยู่” และมอบข้อมูลให้ลูกค้า/ผู้ใช้ ส่วนการลงนามธุรกรรมทำบนอุปกรณ์ที่มีความปลอดภัยสูงกว่า</p>
<p>การประยุกต์ใช้งานทั่วไปของแนวทางนี้คือการติดตั้ง extended public key บนเว็บเซิร์ฟเวอร์ของระบบอีคอมเมิร์ซ เว็บเซิร์ฟเวอร์สามารถสร้างที่อยู่บิตคอยน์ใหม่สำหรับแต่ละคำสั่งซื้อหรือแต่ละตะกร้าสินค้าได้ทันที โดยไม่ต้องเก็บ private key ไว้บนเซิร์ฟเวอร์ที่เสี่ยงต่อการถูกโจมตี หากไม่มี HD wallet ตัวเลือกเดียวที่มีจะเป็นการสร้างที่อยู่จำนวนมากล่วงหน้าในเซิร์ฟเวอร์แยกที่ปลอดภัย แล้วคอยโหลดเข้ามาใช้งาน ซึ่งยุ่งยากและต้องดูแลสต็อกที่อยู่ให้เพียงพออยู่ตลอดเวลา</p>
<h4>ระวังช่องว่าง (Mind the Gap)</h4>
<p>Extended public key สามารถสร้างกุญแจลูกได้โดยตรงมากถึงประมาณ 4 พันล้านกุญแจ ซึ่งถือว่าเกินพอสำหรับการใช้งานในร้านค้าหรือแอปพลิเคชันใด ๆ อยู่แล้ว อย่างไรก็ตาม การให้ wallet สร้างกุญแจทั้ง 4 พันล้านดอกและสแกนบล็อกเชนทั้งหมดเพื่อหาธุรกรรมที่เกี่ยวข้องนั้นแทบจะเป็นไปไม่ได้ในทางปฏิบัติ เนื่องจากจะใช้เวลามหาศาล ด้วยเหตุนี้ wallet ส่วนใหญ่จึงเลือกสร้างกุญแจเพียงไม่กี่ดอกในแต่ละครั้ง สแกนหาธุรกรรมที่ตรงกับกุญแจเหล่านั้น และเมื่อกุญแจที่สร้างไปก่อนหน้านี้ถูกใช้งานแล้ว จึงสร้างกุญแจใหม่ต่อไปตามลำดับ</p>
<p>ตัวอย่างเช่น wallet ของ Alice อาจสร้างกุญแจขึ้นมา 100 ดอก เมื่อพบว่ามีการชำระเงินไปยังกุญแจแรก มันก็จะสร้างกุญแจดอกที่ 101 ต่อทันที</p>
<p>บางครั้งอาจมีกรณีที่ wallet แจกกุญแจให้กับใครบางคน แต่ภายหลังคู่สัญญากลับไม่ทำการชำระเงิน ทำให้เกิด “ช่องว่าง” (gap) ในสายกุญแจ ซึ่งโดยทั่วไปไม่ถือว่าเป็นปัญหา ตราบใดที่ wallet ยังคงสร้างกุญแจถัดไปหลังช่องว่างนั้นต่อไป กระบวนการสแกนก็จะยังคงค้นพบธุรกรรมได้ในอนาคต การกำหนดจำนวนกุญแจที่สามารถสร้างไว้ล่วงหน้าโดยยังไม่ถูกใช้งาน และต่อเนื่องกันได้สูงสุดโดยไม่ก่อให้เกิดปัญหา เรียกว่า gap limit</p>
<p>เมื่อ wallet สร้างกุญแจจนถึงขีดจำกัด gap limit แล้ว แต่ไม่มีธุรกรรมเข้ามาที่กุญแจเหล่านั้น มันจะต้องเลือกวิธีรับมือเมื่อมีการขอกุญแจใหม่ในอนาคต ซึ่งมีอยู่ 3 แนวทางหลักคือ:</p>
<ul>
<li>ปฏิเสธการสร้างกุญแจใหม่ – ทำให้ไม่สามารถรับการชำระเงินได้อีก วิธีนี้แม้ง่ายที่สุด แต่ก็เป็นตัวเลือกที่ไม่เหมาะสมที่สุด</li>
<li>สร้างกุญแจใหม่เกินกว่า gap limit – วิธีนี้รับประกันว่าทุกการชำระเงินจะได้ที่อยู่ใหม่ ไม่เกิดการใช้ที่อยู่ซ้ำ และเพิ่มความเป็นส่วนตัว อย่างไรก็ตาม หากต้องกู้ wallet จาก recovery code หรือหากนำ extended public key เดียวกันไปใช้กับซอฟต์แวร์อื่น ซอฟต์แวร์เหล่านั้นจะไม่สามารถเห็นการชำระเงินที่เกิดขึ้นหลังจากเกิน gap limit ได้ </li>
<li>แจกจ่ายกุญแจเก่าซ้ำ – ช่วยให้การกู้คืน wallet เป็นไปอย่างราบรื่น แต่แลกมาด้วยการลดทอนความเป็นส่วนตัวของเจ้าของกระเป๋าและคู่ธุรกรรม</li>
</ul>
<p>ระบบโอเพ่นซอร์สสำหรับร้านค้าออนไลน์ เช่น BTCPay Server แก้ปัญหานี้โดยการใช้ gap limit ที่มีค่ามหาศาล และจำกัดอัตราการสร้างใบแจ้งหนี้ (invoice) ขณะเดียวกันก็มีวิธีแก้ปัญหาเชิงแนวคิดอื่น ๆ ถูกเสนอขึ้นมา เช่น ให้ wallet ของผู้จ่ายสร้างธุรกรรมชั่วคราว (แต่ยังไม่กระจายสู่เครือข่าย) ไปยังที่อยู่ซ้ำก่อนที่จะได้รับที่อยู่ใหม่สำหรับธุรกรรมจริง อย่างไรก็ตาม วิธีเหล่านี้ยังไม่ถูกนำมาใช้จริงในระบบการผลิต ณ เวลาที่เขียนนี้</p>
<p>การใช้งานที่พบบ่อยอีกแบบหนึ่งคือ cold storage หรือ hardware signing device โดยในสถานการณ์นี้ extended private key จะถูกเก็บไว้อย่างปลอดภัยแบบออฟไลน์ เช่น บนกระดาษหรือบนอุปกรณ์ฮาร์ดแวร์ ในขณะที่ extended public key ถูกเก็บไว้ในระบบออนไลน์ ผู้ใช้จึงสามารถสร้างที่อยู่สำหรับการ “รับเงิน” ได้เรื่อย ๆ โดยไม่ต้องเสี่ยงเปิดเผย private key และเมื่อถึงเวลาที่ต้องใช้จ่ายเงิน ก็สามารถนำ extended private key มาสร้างและลงนามธุรกรรมบนซอฟต์แวร์ออฟไลน์หรืออุปกรณ์ฮาร์ดแวร์ได้โดยตรง</p>
<p>แผนภาพ “Extending a parent public key to create a child public key” จะแสดงให้เห็นกลไกการขยายกุญแจสาธารณะหลักเพื่อสร้างกุญแจสาธารณะลูกตามแนวคิดที่กล่าวมานี้<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0508.png" alt="image"></p>
<h4>การใช้ Extended Public Key บนร้านค้าออนไลน์</h4>
<p>มาดูกันว่า HD wallet ถูกนำไปใช้งานจริงอย่างไร ผ่านตัวอย่างร้านค้าออนไลน์ของ Gabriel</p>
<p>Gabriel เริ่มต้นทำร้านค้าออนไลน์เล็ก ๆ ของเขาเป็นงานอดิเรก โดยใช้ WordPress โฮสต์เองแบบง่าย ๆ ร้านค้ามีเพียงไม่กี่หน้าและฟอร์มสั่งซื้อที่ระบุที่อยู่บิตคอยน์เพียงหนึ่งเดียวสำหรับการชำระเงิน เขาใช้ที่อยู่บิตคอยน์แรกที่สร้างขึ้นจากกระเป๋าเงินส่วนตัวเป็นที่อยู่หลัก ลูกค้าส่งคำสั่งซื้อและโอนเงินไปยังที่อยู่นี้ ระบบจะส่งอีเมลแจ้งคำสั่งซื้อเพื่อให้ Gabriel ดำเนินการต่อ สำหรับคำสั่งซื้อเพียงไม่กี่ครั้งต่อสัปดาห์ วิธีนี้ก็ถือว่าเพียงพอ แม้ว่าจะมีข้อเสียด้านความเป็นส่วนตัวทั้งสำหรับ Gabriel เอง ลูกค้า และผู้ที่เขาส่งเงินต่อให้ก็ตาม</p>
<p>แต่เมื่อเวลาผ่านไป ร้านค้าเล็ก ๆ ของ Gabriel กลับได้รับความนิยมมากขึ้น คำสั่งซื้อหลั่งไหลเข้ามาจากลูกค้าในชุมชนท้องถิ่นจนเขาเริ่มจัดการไม่ทัน ปัญหาหลักคือคำสั่งซื้อทั้งหมดถูกส่งไปยังที่อยู่เดียวกัน ทำให้ยากต่อการจับคู่ธุรกรรมกับคำสั่งซื้อได้อย่างถูกต้อง โดยเฉพาะเมื่อมีหลายคำสั่งที่มียอดเงินเท่ากันเข้ามาในช่วงเวลาใกล้กัน อีกทั้งในธุรกรรมบิตคอยน์เอง ผู้รับสามารถระบุได้เพียงจำนวนเงินและที่อยู่ปลายทางเท่านั้น ไม่มีช่องสำหรับบันทึกหมายเลขใบแจ้งหนี้หรือข้อความอธิบายเพิ่มเติม</p>
<p>ทางออกของปัญหานี้มาจากการใช้ HD wallet ซึ่งสามารถสร้างกุญแจสาธารณะลูกจาก extended public key (xpub) โดยไม่ต้องใช้ private key Gabriel จึงสามารถนำ xpub ไปติดตั้งไว้บนเว็บไซต์ของร้านค้า และใช้สร้างที่อยู่ใหม่ที่ไม่ซ้ำสำหรับคำสั่งซื้อแต่ละรายการ วิธีนี้ไม่เพียงช่วยให้การจับคู่ธุรกรรมกับคำสั่งซื้อเป็นไปอย่างแม่นยำ แต่ยังช่วยเพิ่มความเป็นส่วนตัวและความปลอดภัย เนื่องจากแต่ละคำสั่งซื้อจะมีที่อยู่เฉพาะของตัวเอง</p>
<p>ข้อดีอีกอย่างคือ HD wallet ทำให้ Gabriel ยังคงควบคุมการใช้จ่ายเงินได้จากกระเป๋าส่วนตัวของเขา ขณะที่เว็บไซต์มีเพียง xpub ที่ใช้สร้างที่อยู่รับเงินได้เท่านั้น เว็บไซต์ไม่เก็บ private key ใด ๆ เลย หากวันหนึ่งถูกเจาะระบบ สิ่งที่คนร้ายอาจได้ไปก็มีเพียงที่อยู่ที่จะใช้รับเงินในอนาคต ไม่ใช่กุญแจที่สามารถเข้าถึงเงินที่ Gabriel ได้รับไปแล้ว</p>
<p>เพื่อส่งออก xpub จากอุปกรณ์เซ็นธุรกรรม Trezor ของเขา Gabriel ใช้แอปกระเป๋าเงิน Trezor เวอร์ชันเว็บ ซึ่งต้องเชื่อมต่อกับอุปกรณ์ก่อนจึงจะสามารถส่งออกกุญแจสาธารณะได้ ที่สำคัญ อุปกรณ์เซ็นธุรกรรมส่วนใหญ่จะไม่ส่งออก private key เลย Private key จะถูกเก็บอยู่บนอุปกรณ์เท่านั้น Gabriel จึงมั่นใจได้ว่าเงินของเขายังคงปลอดภัย</p>
<p>หลังจากนั้น เขาคัดลอก xpub ไปยังซอฟต์แวร์สำหรับจัดการการชำระเงินบิตคอยน์ของร้านค้า เช่น BTCPay Server ซึ่งเป็นโอเพ่นซอร์สที่ได้รับความนิยมอย่างมาก และสามารถสร้างระบบชำระเงินที่ยืดหยุ่นและปลอดภัยสำหรับธุรกิจของเขาได้ทันที</p>
<h4>การสร้างอนุพันธ์กุญแจลูกแบบเสริมความแข็งแกร่ง</h4>
<p>ความสามารถในการสร้างกิ่งกุญแจสาธารณะจาก xpub นั้นมีประโยชน์อย่างมาก แต่ก็แฝงไปด้วยความเสี่ยงบางประการ การเข้าถึง xpub โดยตรงไม่สามารถทำให้ได้ private key ตัวลูก แต่อย่างไรก็ตาม เนื่องจาก xpub มี chain code อยู่ด้วย หาก private key ตัวใดตัวหนึ่งรั่วไหลหรือถูกเปิดเผยขึ้นมา มันสามารถถูกนำมาใช้ร่วมกับ chain code เพื่อสร้าง private key ลูกตัวอื่น ๆ ได้ทั้งหมด กล่าวคือ เพียงแค่ private key ตัวลูกที่รั่วไหลหนึ่งตัว บวกกับ chain code ของตัวแม่ ก็เพียงพอที่จะเปิดเผย private key ตัวลูกทั้งหมด ยิ่งไปกว่านั้น เมื่อ private key ตัวลูก รวมกับ chain code ของแม่ ยังสามารถถูกใช้เพื่อคำนวณหา private key ตัวแม่ได้อีกด้วย</p>
<p>เพื่อป้องกันความเสี่ยงนี้ HD wallet จึงมีอีกหนึ่งกลไกที่เรียกว่า hardened derivation ซึ่งทำหน้าที่ตัดความสัมพันธ์ระหว่าง public key ตัวแม่กับ chain code ของลูกออกไป ฟังก์ชัน hardened derivation จะใช้ private key ตัวแม่ในการสร้าง chaincode ของตัวลูกแทนการใช้ public key ของตัวแม่ วิธีนี้เปรียบเสมือนการสร้าง “ไฟร์วอลล์” ในสายลำดับแม่/ลูก ทำให้ chain code ที่ได้ไม่สามารถนำไปใช้เพื่อเจาะหา private key อื่น ๆ ได้อีกต่อไป</p>
<p>ฟังก์ชัน hardened derivation ดูคล้ายกับฟังก์ชันการสร้างกุญแจลูกแบบปกติ เพียงแต่มันใช้ private key แม่เป็น input ของ hash function แทน public key ดังที่แสดงในแผนภาพข้างล่าง</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0509.png" alt="image"></p>
<p>เมื่อใช้ฟังก์ชัน hardened derivation ผลลัพธ์ที่เกิดทั้ง private key และ chain code ของตัวลูกจะต่างไปโดยสิ้นเชิงจากสิ่งที่จะได้จากการอนุพันธ์แบบปกติ กิ่งที่ได้ด้วยวิธีนี้สามารถนำไปสร้างเป็น extended public keys ได้โดยที่ความปลอดภัยไม่ถูกทำลาย เพราะ chain code ของกิ่งเหล่านั้นไม่สามารถนำไปใช้เปิดเผย private key ใด ๆ  ในกิ่งอื่น ๆ ได้ การอนุพันธ์แบบ hardened จึงทำหน้าที่สร้าง “ช่องกั้น” (firewall) ในโครงสร้างต้นไม้ เหนือระดับที่มีการเผยแพร่ extended public keys</p>
<p>สรุปง่าย ๆ คือ หากคุณต้องการใช้ความสะดวกของ xpub เพื่อสร้าง public key หลาย ๆ ดอก โดยไม่เสี่ยงให้ตัวเองถูกเจาะจากการรั่วของ chain code ควรแยกสาขานั้นมาจากกุญแจพ่อแม่ที่สร้างด้วย hardened derivation แทนการใช้กุญแจพ่อแม่แบบปกติ โดยเป็นแนวปฏิบัติที่ดีที่สุดที่ลูกระดับแรก (level 1) ของกุญแจมาสเตอร์จะถูกสร้างด้วย hardened derivation เสมอ เพื่อป้องกันการถูกเจาะของกุญแจมาสเตอร์</p>
<h5>หมายเลขดัชนีสำหรับการแตกกุญแจแบบปกติและแบบ hardened</h5>
<p>หมายเลขดัชนีที่ใช้ในการอนุพันธ์กุญแจเป็นจำนวนเต็มขนาด 32 บิต เพื่อแยกความแตกต่างระหว่างการอนุพันธ์แบบปกติกับแบบ hardened หมายเลขดัชนีช่วง 0 ถึง 2³¹−1 (0x00000000 ถึง 0x7FFFFFFF) จะใช้สำหรับการอนุพันธ์แบบปกติ ส่วนหมายเลขดัชนีช่วง 2³¹ ถึง 2³²−1 (0x80000000 ถึง 0xFFFFFFFF) จะใช้สำหรับการอนุพันธ์แบบ hardened ดังนั้น หากค่าดัชนีต่ำกว่า 2³¹ กุญแจลูกจะเป็นแบบปกติ แต่ถ้าค่าเท่าหรือมากกว่า 2³¹ กุญแจลูกจะเป็นแบบ hardened</p>
<p>เพื่อให้อ่านและแสดงดัชนีได้สะดวกกว่า ค่าดัชนีของกุญแจ hardened มักจะแสดงด้วยตัวเลขเริ่มจากศูนย์ผนวกเครื่องหมาย prime (′) แทนค่าแบบไบนารี่ ตัวอย่างเช่น กุญแจลูกปกติแรกจะแสดงเป็น 0 ในขณะที่กุญแจลูก hardened แรก (ดัชนี 0x80000000) จะแสดงเป็น 0′ กุญแจ hardened ตัวถัดมาจะเป็น 1′ ซึ่งตามนิยาม i′ หมายถึงค่า 2³¹ + i ในการเขียนแบบ ASCII ปกติ เครื่องหมาย prime มักใช้เป็นอัปอสโทรฟเดี่ยว (') หรือในบริบทที่อัปอสโทรฟมีความหมายพิเศษ อาจใช้ตัวอักษร h แทน (เช่น 0h, 1h) ซึ่งเป็นรูปแบบที่มักแนะนำสำหรับการนำไปใช้ใน shell หรือใน output script descriptors.</p>
<h3>ตัวระบุคีย์ใน HD wallet (path)</h3>
<p>คีย์ใน HD wallet จะถูกระบุด้วยรูปแบบ path ซึ่งแยกระดับชั้นของต้นไม้ด้วยเครื่องหมายทับ (/) แต่ละระดับระบุการอนุพันธ์หนึ่งขั้น private key ที่อนุพันธ์มาจาก master private key จะขึ้นต้นด้วย m ในขณะที่ public key ที่อนุพันธ์มาจาก master public key จะขึ้นต้นด้วย M ตัวอย่างเช่น private key ลูกดอกแรกของ master private key จะเป็น m/0 และ public key ลูกดอกแรก จะเป็น M/0 และหลานลำดับที่สองของ Master private key ก็จะเป็น m/0/1 ไปเรื่อย ๆ</p>
<p>การอ่าน “ลำดับชั้น” ของ path ทำได้โดยอ่านจากซ้ายไปขวาโดยเริ่มจาก master key ไปยังกิ่งที่ลึกขึ้น เช่น ตัวระบุ m/x/y/z หมายความว่ากุญแจนี้เป็นกุญแจลูกลำดับที่ z ของกุญแจ m/x/y ซึ่งเป็นลูกลำดับที่ y ของกุญแจ m/x ซึ่งเป็นลูกลำดับที่ x ของ m — กล่าวคือ path แต่ละระดับบอกขั้นตอนการอนุพันธ์ที่ต่อเนื่องจาก master ลงไปยังกุญแจปัจจุบัน</p>
<table>
<thead>
<tr>
<th>HD path</th>
<th>คีย์ที่อธิบาย</th>
</tr>
</thead>
<tbody><tr>
<td><strong>m/0</strong></td>
<td>กุญแจส่วนตัวลูกตัวแรก (0) จาก master private key (m)</td>
</tr>
<tr>
<td><strong>m/0/0</strong></td>
<td>กุญแจส่วนตัวหลานตัวแรกจากลูกตัวแรก (m/0)</td>
</tr>
<tr>
<td><strong>m/0'/0</strong></td>
<td>กุญแจส่วนตัวหลานปกติ (normal grandchild) ตัวแรกจากลูกแบบ hardened ตัวแรก (m/0')</td>
</tr>
<tr>
<td><strong>m/1/0</strong></td>
<td>กุญแจส่วนตัวหลานตัวแรกจากลูกตัวที่สอง (m/1)</td>
</tr>
<tr>
<td><strong>M/23/17/0/0</strong></td>
<td>กุญแจสาธารณะเหลนเหลน (great-great-grandchild) ตัวแรกจากเหลนตัวแรก (first great-grandchild) จากหลานตัวที่ 18 (18th grandchild) จากลูกตัวที่ 24 (24th child)</td>
</tr>
</tbody></table>
<h4>การใช้งานเส้นทางในโครงสร้างต้นไม้ของกระเป๋าเงินแบบ HD</h4>
<p>โครงสร้างต้นไม้ของ HD wallet มอบความยืดหยุ่นอย่างมาก แต่ละกุญแจขยายที่เป็นพ่อแม่สามารถมีลูกได้ 4 พันล้านกุญแจ: 2 พันล้านกุญแจปกติ และ 2 พันล้านกุญแจ hardened ลูกแต่ละกุญแจเหล่านั้นสามารถมีลูกอีก 4 พันล้านกุญแจ และต่อไปได้เรื่อย ๆ ต้นไม้สามารถลึกได้เท่าที่คุณต้องการ โดยมีจำนวนรุ่นไม่สิ้นสุด อย่างไรก็ตาม ด้วยความยืดหยุ่นทั้งหมดนั้น มันจึงกลายเป็นเรื่องที่ค่อนข้างยากที่จะใช้งานเส้นทางในต้นไม้ที่ไม่สิ้นสุดนี้ โดยเฉพาะอย่างยิ่งเมื่อมีการถ่ายโอน HD wallet ระหว่างการนำไปใช้งานต่าง ๆ เนื่องจากความเป็นไปได้สำหรับการจัดระเบียบภายในไปสู่กิ่งและกิ่งย่อยนั้นมีอยู่อย่างไม่จำกัด</p>
<p>สอง BIP นำเสนอโซลูชันสำหรับความซับซ้อนนี้ โดยการสร้างมาตรฐานที่เสนอไว้บางอย่างสำหรับโครงสร้างของต้นไม้ HD wallet BIP43 เสนอการใช้ hardened child index ตัวแรกเป็นตัวระบุพิเศษที่บ่งบอกถึง “วัตถุประสงค์” ของโครงสร้างต้นไม้ ตามที่ BIP43 กล่าวไว้ HD wallet ควรใช้เพียงกิ่งระดับ 1 ของต้นไม้ โดยหมายเลข index จะบ่งบอกถึงโครงสร้างและ namespace ของต้นไม้ที่เหลือโดยการกำหนดวัตถุประสงค์ ตัวอย่างเช่น HD wallet ที่ใช้เพียงกิ่ง m/i' มีเจตนาที่จะบ่งบอกถึงวัตถุประสงค์เฉพาะ และวัตถุประสงค์นั้นถูกระบุด้วยหมายเลข index “i”</p>
<p>โดยการขยายข้อกำหนดนั้น BIP44 เสนอ multiaccount structure เป็น “วัตถุประสงค์” หมายเลข 44' ภายใต้ BIP43 HD wallet ทั้งหมดที่ปฏิบัติตามโครงสร้าง BIP44 จะถูกระบุโดยข้อเท็จจริงที่ว่าพวกมันใช้เพียงกิ่งเดียวของต้นไม้: m/44'</p>
<p>BIP44 กำหนดโครงสร้างว่า ประกอบด้วยห้าระดับของต้นไม้ที่ถูกกำหนดไว้ล่วงหน้า:</p>
<pre><code>m / purpose' / coin_type' / account' / change / address_index
</code></pre>
<p>ระดับแรก “purpose” จะถูกตั้งค่าเป็น 44’ เสมอ ระดับที่สอง “coin_type” ระบุชนิดของเหรียญ cryptocurrency โดยอนุญาตให้มี multicurrency HD wallets ที่แต่ละสกุลเงินมี subtree ของตัวเองภายใต้ระดับที่สอง Bitcoin คือ m/44’/0’ และ Bitcoin Testnet คือ m/44’/1’</p>
<p>ระดับที่สามของต้นไม้คือ “account” ซึ่งอนุญาตให้ผู้ใช้แบ่งย่อยกระเป๋าของพวกเขาออกเป็น subaccount เชิงตรรกะแยกกันเพื่อการบัญชีหรือวัตถุประสงค์ด้านการจัดการ ตัวอย่างเช่น HD wallet อาจมีสอง “account” ของ Bitcoin: m/44’/0’/0’ และ m/44’/0’/1’ แต่ละ account เป็นรากของ subtree ของมันเอง</p>
<p>ในระดับที่สี่ “change” HD wallet มีสอง subtree หนึ่งสำหรับการสร้าง receiving address และอีกหนึ่งสำหรับการสร้าง change address โปรดทราบว่าในขณะที่ระดับก่อนหน้านี้ใช้ hardened derivation แต่ระดับนี้ใช้ normal derivation นี่เป็นการอนุญาตให้ระดับนี้ของต้นไม้สามารถส่งออก extended public keys เพื่อใช้ในสภาพแวดล้อมที่ไม่ปลอดภัยได้ ที่อยู่ที่สามารถใช้งานได้ถูกสร้างขึ้นโดย HD wallet ในฐานะลูกของระดับที่สี่ ทำให้ระดับที่ห้าของต้นไม้คือ “address_index” ตัวอย่างเช่น receiving address ที่สามสำหรับการชำระเงินใน account หลักจะเป็น M/44’/0’/0’/0/2 ตารางข้างล่างจะแสดงตัวอย่างเพิ่มเติมอีกเล็กน้อย</p>
<table>
<thead>
<tr>
<th>HD path</th>
<th>คำอธิบายคีย์</th>
</tr>
</thead>
<tbody><tr>
<td>M/44'/0'/0'/0/2</td>
<td>กุญแจสาธารณะสำหรับรับเงินตัวที่สามของบัญชี Bitcoin หลัก</td>
</tr>
<tr>
<td>M/44'/0'/3'/1/14</td>
<td>กุญแจสาธารณะสำหรับที่อยู่ทอน (change-address) ตัวที่สิบห้าของบัญชี Bitcoin ที่สี่</td>
</tr>
<tr>
<td>m/44'/2'/0'/0/1</td>
<td>กุญแจส่วนตัวที่สองในบัญชีหลักของ Litecoin สำหรับใช้ลงลายเซ็นธุรกรรม</td>
</tr>
</tbody></table>
<p>หลายคนมุ่งเน้นไปที่การปกป้องบิตคอยน์ของตนจากการขโมยและการโจมตีรูปแบบต่าง ๆ แต่หนึ่งในสาเหตุสำคัญของการสูญเสียบิตคอยน์—ซึ่งอาจเป็นสาเหตุหลักเลยก็ว่าได้—ก็คือการสูญหายของข้อมูล หากกุญแจและข้อมูลสำคัญอื่น ๆ ที่จำเป็นต่อการใช้จ่ายบิตคอยน์ของคุณสูญหายไป บิตคอยน์เหล่านั้นก็จะไม่สามารถถูกใช้จ่ายได้อีกต่อไป และไม่มีใครสามารถกู้คืนให้คุณได้ ในบทนี้ เราได้พิจารณาระบบที่กระเป๋าเงินสมัยใหม่ใช้เพื่อช่วยป้องกันไม่ให้คุณสูญเสียข้อมูลนั้น แต่อย่าลืมว่า การใช้งานระบบที่มีอยู่เพื่อสร้างการสำรองข้อมูลที่ดีและทดสอบอย่างสม่ำเสมอนั้น ขึ้นอยู่กับคุณเอง</p>
]]></itunes:summary>
      <itunes:image href="https://image.nostr.build/e5c951d87cf8197f45fe863c18b31eab095566d7f3ff772ec86cc8e05f957168.jpg"/>
      </item>
      
      <item>
      <title><![CDATA[สรุป Mastering Bitcoin: Programming the Open Blockchain บทที่ 4]]></title>
      <description><![CDATA[อ่านต้นฉบับแล้วมัน อู้อี่อี่อี่อู้อี่อี่อ้า อู่อู่อี้อี้อ้า อีอ้าอีอู่ เลยหาสรุป แต่พออ่านสรุปแล้วมัน อู่อีอีอ้าอีอู่ อูอีอีอ้าอีอู่ กลับไปอ่านต้นฉบับดีกว่าา !!!]]></description>
             <itunes:subtitle><![CDATA[อ่านต้นฉบับแล้วมัน อู้อี่อี่อี่อู้อี่อี่อ้า อู่อู่อี้อี้อ้า อีอ้าอีอู่ เลยหาสรุป แต่พออ่านสรุปแล้วมัน อู่อีอีอ้าอีอู่ อูอีอีอ้าอีอู่ กลับไปอ่านต้นฉบับดีกว่าา !!!]]></itunes:subtitle>
      <pubDate>Sat, 22 Mar 2025 11:11:35 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/bbid3bt12898zobcwj9ex/</link>
      <comments>https://learnbn.npub.pro/post/bbid3bt12898zobcwj9ex/</comments>
      <guid isPermaLink="false">naddr1qq25ysnfvsekyap3xgurjwz6fapyxam289jhsq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wsceefr</guid>
      <category>ลองฟอร์มของไดโน</category>
      
        <media:content url="https://image.nostr.build/0e43fa1dec4fb36a9b30035d0e83cf3759ece78d64813fc0b5182c5a62dd6e34.jpg" medium="image"/>
        <enclosure 
          url="https://image.nostr.build/0e43fa1dec4fb36a9b30035d0e83cf3759ece78d64813fc0b5182c5a62dd6e34.jpg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qq25ysnfvsekyap3xgurjwz6fapyxam289jhsq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wsceefr</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<h2>Keys and Addresses</h2>
<p>อลิซต้องการจ่ายเงินให้กับบ๊อบแต่โหนดของบิตคอยน์ในระบบหลายพันโหนดจะตรวจสอบธุรกรรมของเธอ โดยไม่รู้ว่าอลิซหรือบ๊อบเป็นใคร ละเราต้องการรักษาความเป็นส่วนตัวของพวกเขาไว้เช่นนี้ อลิซจำเป็นต้องสื่อสารว่าบ๊อบควรได้รับบิตคอยน์บางส่วนของเธอโดยไม่เชื่อมโยงแง่มุมใด ๆ ของธุรกรรมนั้นกับตัวตนในโลกจริงของบ๊อบ หรือกับการชำระเงินด้วยบิตคอยน์ครั้งอื่น ๆ ที่บ๊อบได้รับ อลิซใช้ต้องทำให้มั่นใจว่ามีเพียแค่บ๊อบเท่านั้นที่สามารถใช้จ่ายบิตคอยน์ที่เขาได้รับต่อไปได้</p>
<p>ในบิตคอยน์ไวท์เปเปอร์ได้อธิบายถึงแผนการที่เรียบง่ายมากสำหรับการบรรลุเป้าหมายเหล่านั้น ดังที่แสดงในรูปด้านล่างนี้ </p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_aain01.png" alt="image"></p>
<p>ตัวของผู้รับอย่างบ๊อบเองจะได้รับบิตคอยน์ไปยัง public key ของเขาที่ถูกลงนามโดยผู้จ่ายอย่างอลิซ โดยบิตคอยน์ที่อลิซนำมาจ่ายนั้นก็ได้รับมาจากที่ใครสักคนส่งมาที่ public key ของเธอ และเธอก็ใช้ private key ของเธอในการลงนามเพื่อสร้างลายเซ็นของเธอและโหนดต่าง ๆ ของบิตคอยน์จะทำการตรวจสอบว่าลายเซ็นของอลิซผูกมัดกับเอาต์พุตของฟังก์ชันแฮชซึ่งตัวมันเองผูกมัดกับ public key ของบ๊อบและรายละเอียดธุรกรรมอื่นๆ</p>
<p>ในบทนี้เราจะพิจารณาpublic key  private key  Digital signatrue และ hash function จากนั้นใช้ทั้งหมดนี้ร่วมกันเพื่ออธิบาย address ที่ใช้โดยซอฟต์แวร์บิตคอยน์สมัยใหม่</p>
<h3>Public Key Cryptography (การเข้ารหัสของ public key)</h3>
<p>ระบบเข้ารหัสของ public key ถูกคิดค้นขึ้นในทศวรรษ 1970 มาจากรากฐานทางคณิตศาสตร์สำหรับความปลอดภัยของคอมพิวเตอร์และข้อมูลสมัยใหม่</p>
<p>นับตั้งแต่การคิดค้นระบบเข้ารหัส public key ได้มีการค้นพบฟังก์ชันทางคณิตศาสตร์ที่เหมาะสมหลายอย่าง เช่น การยกกำลังของจำนวนเฉพาะและการคูณของเส้นโค้งวงรี โดยฟังก์ชันทางคณิตศาสตร์เหล่านี้สามารถคำนวณได้ง่ายในทิศทางหนึ่ง แต่เป็นไปไม่ได้ที่จะคำนวณในทิศทางตรงกันข้ามโดยใช้คอมพิวเตอร์และอัลกอริทึมที่มีอยู่ในปัจจุบัน จากฟังก์ชันทางคณิตศาสตร์เหล่านี้ การเข้ารหัสลับช่วยให้สามารถสร้างลายเซ็นดิจิทัลที่ไม่สามารถปลอมแปลงได้และบิตคอยน์ได้ใช้การบวกและการคูณของเส้นโค้งวงรีเป็นพื้นฐานสำหรับการเข้ารหัสลับของมัน</p>
<p>ในบิตคอยน์ เราสามารถใช้ระบบเข้ารหัส public key เพื่อสร้างคู่กุญแจที่ควบคุมการเข้าถึงบิตคอยน์ คู่กุญแจประกอบด้วย private key และ public key ที่ได้มาจาก private key public keyใช้สำหรับรับเงิน และ private key ใช้สำหรับลงนามในธุรกรรมเพื่อใช้จ่ายเงิน</p>
<p>ความสัมพันธ์ทางคณิตศาสตร์ระหว่าง public key และ private key ที่ช่วยให้ private key สามารถใช้สร้างลายเซ็นบนข้อความได้ ลายเซ็นเหล่านี้สามารถตรวจสอบความถูกต้องกับ public key ได้โดยไม่เปิดเผย private key</p>
<blockquote>
<p>TIP: ในการใช้งานซอฟแวร์กระเป๋าเงินบิตคอยน์บสงอัน จะทำการเก็บ private key และ public key ถูกเก็บไว้ด้วยกันในรูปแบบคู่กุญแจเพื่อความสะดวก แต่อย่างไรก็ตาม public key สามารถคำนวณได้จาก private key ดังนั้นการเก็บเพียง private key เท่านั้นก็เป็นไปได้เช่นกัน</p>
</blockquote>
<p>bitcoin wallet มักจะทำการรวบรวมคู่กุญแต่ละคู่ ซึ่งจะประกอบไปด้วย private key และ public key โดย private key จะเป็นตัวเลขที่ถูกสุ่มเลือกขึ้นมา และเราขะใช้เส้นโค้งวงรี ซึ่งเป็นฟังก์ชันการเข้ารหัสทางเดียว เพื่อสร้าง public key ขึ้นมา</p>
<h3>ทำไมจึงใช้การเข้ารหัสแบบอสมมาตร</h3>
<p>ทำไมการเข้ารหัสแบบอสมมาตรจึงถูกใช้บิตคอยน์? มันไม่ได้ถูกใช้เพื่อ "เข้ารหัส" (ทำให้เป็นความลับ) ธุรกรรม แต่คุณสมบัติที่มีประโยชน์ของการเข้ารหัสแบบอสมมาตรคือความสามารถในการสร้าง ลายเซ็นดิจิทัล private key สามารถนำไปใช้กับธุรกรรมเพื่อสร้างลายเซ็นเชิงตัวเลข ลายเซ็นนี้สามารถสร้างได้เฉพาะโดยผู้ที่มีความเกี่ยวข้องกับ private key เท่านั้น แต่อย่างไรก็ตาม ทุกคนที่สามารถเข้าถึง public key และธุรกรรมสามารถใช้สิ่งเหล่านี้เพื่อ ตรวจสอบ ลายเซ็นได้ คุณสมบัติที่มีประโยชน์นี้ของการเข้ารหัสแบบอสมมาตรทำให้ทุกคนสามารถตรวจสอบลายเซ็นทุกรายการในทุกธุรกรรมได้ ในขณะที่มั่นใจว่าเฉพาะเจ้าของ private key เท่านั้นที่สามารถสร้างลายเซ็นที่ถูกต้องได้</p>
<h3>Private keys</h3>
<p>private key เป็นเพียงตัวเลขที่ถูกสุ่มขึ้น และการควบคุม private key ก็เป็นรากฐานสำคัญที่ทำให้เจ้าชองกุญแจดอกนี้สามารถควบคุมบิตคอยน์ทั้งหมดที่มีความเกี่ยวข้องกับ public key ที่คู่กัน private key นั้นใช้ในการสร้างลายเซ็นดิจิทัลที่ใช้ในการเคลื่อนย้ายบิตคอยน์ เราจำเป็นต้องเก็บ private key ให้เป็นความลับตลอดเวลา เพราะการเปิดเผยมันให้กับบุคคลอื่นนั้นก็เปรียบเสมือนกับการนำอำนาจในการควบคุมบิตคอยน์ไปให้แก่เขา นอกจากนี้ private key ยังจำเป็นต้องได้รับการสำรองข้อมูลและป้องกันจากการสูญหายโดยไม่ตั้งใจ เพราะหากเราได้ทำมันสูญหายไป จะไม่สามารถกู้คืนได้ และบิตคอยน์เหล่านั้นจะถูกปกป้องโดยกุญแจที่หายไปนั้นตลอดกาลเช่นกัน</p>
<blockquote>
<p>TIP: private key ของบิตคอยน์นั้นเป็นเพียงแค่ตัวเลข คุณสามารถสร้างมันได้โดยใช้เพียงเหรียญ ดินสอ และกระดาษ โดยการโยนเหรียญเพียง 256 ครั้งจะทำให้คุณได้เลขฐานสองที่สามารถใช้เป็น private key ของบิตคอยน์ จากนั้นคุณสามารถใช้มันในการคำนวณหา public key แต่อย่างไรก็ตาม โปรดระมัดระวังเกี่ยวกับการเลือใช้วิธีการสุ่มที่ไม่สมบูรณ์ เพราะนั่นอาจลดความปลอดภัยของ private key และบิตคอยน์ที่มัมปกป้องอยู่อย่างมีนัยสำคัญ</p>
</blockquote>
<p>ขั้นตอนแรกและสำคัญที่สุดในการสร้างกุญแจคือการหาแหล่งที่มาของความสุ่มที่ปลอดภัย (ซึ่งเรียกว่า เอนโทรปี) การสร้างกุญแจของบิตคอยน์นั้นเกือบเหมือนกับ "เลือกตัวเลขระหว่าง 1 และ 2^256" ซึ่งวิธีที่แน่นอนที่คุณใช้ในการเลือกตัวเลขนั้นไม่สำคัญตราบใดที่มันไม่สามารถคาดเดาหรือทำซ้ำได้ โดยปกติแล้วซอฟต์แวร์ของบิตคอยน์มักจะใช้ตัวสร้างตัวเลขสุ่มที่มีความปลอดภัยทางการเข้ารหัสเพื่อสร้างเอนโทรปี 256 บิต</p>
<p>สิ่งที่สำคัญในเรื่องนี้คือ private key สามารถเป็นตัวเลขใดๆ ระหว่าง 0 และ n - 1 (รวมทั้งสองค่า) โดยที่ n เป็นค่าคงที่ (n = 1.1578 × 10^77 ซึ่งน้อยกว่า 2^256 เล็กน้อย) ซึ่งกำหนดอยู่ใน elliptic curve ที่ใช้ใน Bitcoin ในการสร้างกุญแจดังกล่าว เราสุ่มเลือกเลขขนาด 256 บิตและตรวจสอบว่ามันน้อยกว่า n ในแง่ของการเขียนโปรแกรม โดยปกติแล้วสิ่งนี้ทำได้โดยการป้อนสตริงของบิตสุ่มที่ใหญ่กว่า ซึ่งรวบรวมจากแหล่งที่มาของความสุ่มที่มีความปลอดภัยทางการเข้ารหัส เข้าไปในอัลกอริทึมแฮช SHA256 ซึ่งจะสร้างค่าขนาด 256 บิตที่สามารถตีความเป็นตัวเลขได้อย่างสะดวก หากผลลัพธ์น้อยกว่า n เราจะได้กุญแจส่วนตัวที่เหมาะสม มิฉะนั้น เราก็เพียงแค่ลองอีกครั้งด้วยตัวเลขสุ่มอื่น</p>
<blockquote>
<p>คำเตือน: อย่าเขียนโค้ดของคุณเองเพื่อสร้างตัวเลขสุ่ม หรือใช้ตัวสร้างตัวเลขสุ่ม "แบบง่าย" ที่มีให้ในภาษาโปรแกรมของคุณ ใช้ตัวสร้างตัวเลขสุ่มเทียมที่มีความปลอดภัยทางการเข้ารหัส (CSPRNG) จากแหล่งที่มีเอนโทรปีเพียงพอ ศึกษาเอกสารของไลบรารีตัวสร้างตัวเลขสุ่มที่คุณเลือกเพื่อให้มั่นใจว่ามีความปลอดภัยทางการเข้ารหัส การใช้งาน CSPRNG ที่ถูกต้องมีความสำคัญอย่างยิ่งต่อความปลอดภัยของกุญแจ</p>
</blockquote>
<p>ต่อไปนี้คือกุญแจส่วนตัว (k) ที่สร้างขึ้นแบบสุ่มซึ่งแสดงในรูปแบบเลขฐานสิบหก (256 บิตแสดงเป็น 64 หลักเลขฐานสิบหก โดยแต่ละหลักคือ 4 บิต):</p>
<pre><code>1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD
</code></pre>
<blockquote>
<p>TIP: จำนวนที่เป็นไปได้ของ private key ทั้งหมดนั้นมีอยู่ 2^256 เป็นตัวเลขที่ใหญ่มากจนยากจะจินตนาการได้ มันมีค่าประมาณ 10^77 (เลข 1 ตามด้วยเลข 0 อีก 77 ตัว) ในระบบเลขฐานสิบ เพื่อให้เข้าใจง่ายขึ้น ลองเปรียบเทียบกับจักรวาลที่เรามองเห็นได้ซึ่งนักวิทยาศาสตร์ประมาณการว่ามีอะตอมทั้งหมดประมาณ 10^80 อะตอม นั่นหมายความว่าช่วงค่าของกุญแจส่วนตัว Bitcoin มีขนาดใกล้เคียงกับจำนวนอะตอมทั้งหมดในจักรวาลที่เรามองเห็นได้</p>
</blockquote>
<h3>การอธิบายเกี่ยวกับวิทยาการเข้ารหัสแบบเส้นโค้งวงรี (Elliptic Curve Cryptography)</h3>
<p>วิทยาการเข้ารหัสแบบเส้นโค้งวงรี (ECC) เป็นประเภทหนึ่งของการเข้ารหัสแบบอสมมาตรหรือ public key ซึ่งอาศัยหลักการของปัญหาลอการิทึมแบบไม่ต่อเนื่อง โดยแสดงออกผ่านการบวกและการคูณบนจุดต่างๆ ของเส้นโค้งวงรี</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0402.png" alt="image"></p>
<p>บิตคอยน์ใช้เส้นโค้งวงรีเฉพาะและชุดค่าคงที่ทางคณิตศาสตร์ ตามที่กำหนดไว้ในมาตรฐานที่เรียกว่า secp256k1 ซึ่งกำหนดโดยสถาบันมาตรฐานและเทคโนโลยีแห่งชาติ (NIST) เส้นโค้ง secp256k1 ถูกกำหนดโดยฟังก์ชันต่อไปนี้ ซึ่งสร้างเส้นโค้งวงรี: y² = (x³ + 7) บนฟิลด์จำกัด (F_p) หรือ y² mod p = (x³ + 7) mod p</p>
<p>โดยที่ mod p (มอดูโลจำนวนเฉพาะ p) แสดงว่าเส้นโค้งนี้อยู่บนฟิลด์จำกัดของอันดับจำนวนเฉพาะ p ซึ่งเขียนได้เป็น F_p โดย p = 2^256 – 2^32 – 2^9 – 2^8 – 2^7 – 2^6 – 2^4 – 1 ซึ่งเป็นจำนวนเฉพาะที่มีค่ามหาศาล</p>
<p>บิตคอยน์ใช้เส้นโค้งวงรีที่ถูกนิยามบนฟิลด์จำกัดของอันดับจำนวนเฉพาะแทนที่จะอยู่บนจำนวนจริง ทำให้มันมีลักษณะเหมือนรูปแบบของจุดที่กระจัดกระจายในสองมิติ ซึ่งทำให้ยากต่อการจินตนาการภาพ อย่างไรก็ตาม คณิตศาสตร์ที่ใช้นั้นเหมือนกับเส้นโค้งวงรีบนจำนวนจริง</p>
<p>ตัวอย่างเช่น การเข้ารหัสลับด้วยเส้นโค้งวงรี: การแสดงภาพเส้นโค้งวงรีบน F(p) โดยที่ p=17 แสดงเส้นโค้งวงรีเดียวกันบนฟิลด์จำกัดของอันดับจำนวนเฉพาะ 17 ที่มีขนาดเล็กกว่ามาก ซึ่งแสดงรูปแบบของจุดบนตาราง</p>
<p>เส้นโค้งวงรี secp256k1 ที่ใช้ในบิตคอยน์สามารถนึกถึงได้ว่าเป็นรูปแบบของจุดที่ซับซ้อนมากกว่าบนตารางที่มีขนาดใหญ่มหาศาลจนยากจะเข้าใจได้</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0403.png" alt="image"></p>
<p>ตัวอย่างเช่น จุด P ที่มีพิกัด (x, y) ต่อไปนี้เป็นจุดที่อยู่บนเส้นโค้ง secp256k1:</p>
<pre><code>P =
(55066263022277343669578718895168534326250603453777594175500187360389116729240,
32670510020758816978083085130507043184471273380659243275938904335757337482424)
</code></pre>
<p>เราสามารถใช้ Python เพื่อยืนยันว่าจุดนี้อยู่บนเส้นโค้งวงรีได้ตามตัวอย่างนี้:<br>ตัวอย่างที่ 1: การใช้ Python เพื่อยืนยันว่าจุดนี้อยู่บนเส้นโค้งวงรี</p>
<pre><code>Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
&gt; p = 115792089237316195423570985008687907853269984665640564039457584007908834671663
&gt; x = 55066263022277343669578718895168534326250603453777594175500187360389116729240
&gt; y = 32670510020758816978083085130507043184471273380659243275938904335757337482424
&gt; (x ** 3 + 7 - y**2) % p
0
</code></pre>
<p>ผลลัพธ์เป็น 0 ซึ่งแสดงว่าจุดนี้อยู่บนเส้นโค้งวงรีจริง เพราะเมื่อแทนค่า x และ y ลงในสมการ y² = (x³ + 7) mod p แล้ว ทั้งสองด้านของสมการมีค่าเท่ากัน</p>
<p>ในคณิตศาสตร์ของเส้นโค้งวงรี มีจุดที่เรียกว่า "จุดที่อนันต์" (point at infinity) ซึ่งมีบทบาทคล้ายกับศูนย์ในการบวก บนคอมพิวเตอร์ บางครั้งจุดนี้แทนด้วย x = y = 0 (ซึ่งไม่เป็นไปตามสมการเส้นโค้งวงรี แต่เป็นกรณีพิเศษที่สามารถตรวจสอบได้ง่าย)</p>
<p>มีตัวดำเนินการ + ที่เรียกว่า "การบวก" ซึ่งมีคุณสมบัติคล้ายกับการบวกแบบดั้งเดิมของจำนวนจริงที่เด็กๆ เรียนในโรงเรียน เมื่อมีจุดสองจุด P1 และ P2 บนเส้นโค้งวงรี จะมีจุดที่สาม P3 = P1 + P2 ซึ่งอยู่บนเส้นโค้งวงรีเช่นกัน</p>
<p>ในเชิงเรขาคณิต จุดที่สาม P3 นี้คำนวณได้โดยการลากเส้นระหว่าง P1 และ P2 เส้นนี้จะตัดกับเส้นโค้งวงรีที่จุดเพิ่มเติมอีกหนึ่งจุดพอดี เรียกจุดนี้ว่า P3' = (x, y) จากนั้นให้สะท้อนกับแกน x เพื่อได้ P3 = (x, -y)</p>
<p>มีกรณีพิเศษบางกรณีที่อธิบายความจำเป็นของ "จุดที่อนันต์":</p>
<ol>
<li>ถ้า P1 และ P2 เป็นจุดเดียวกัน เส้น "ระหว่าง" P1 และ P2 ควรขยายเป็นเส้นสัมผัสกับเส้นโค้ง ณ จุด P1 นี้ เส้นสัมผัสนี้จะตัดกับเส้นโค้งที่จุดใหม่อีกหนึ่งจุดพอดี คุณสามารถใช้เทคนิคจากแคลคูลัสเพื่อหาความชันของเส้นสัมผัส เทคนิคเหล่านี้ใช้ได้อย่างน่าแปลกใจ แม้ว่าเราจะจำกัดความสนใจไว้ที่จุดบนเส้นโค้งที่มีพิกัดเป็นจำนวนเต็มเท่านั้น!</li>
<li>ในบางกรณี (เช่น ถ้า P1 และ P2 มีค่า x เดียวกันแต่ค่า y ต่างกัน) เส้นสัมผัสจะตั้งฉากพอดี ซึ่งในกรณีนี้ P3 = "จุดที่อนันต์"</li>
<li>ถ้า P1 เป็น "จุดที่อนันต์" แล้ว P1 + P2 = P2 ในทำนองเดียวกัน ถ้า P2 เป็นจุดที่อนันต์ แล้ว P1 + P2 = P1 นี่แสดงให้เห็นว่าจุดที่อนันต์มีบทบาทเป็นศูนย์</li>
</ol>
<p>การบวกนี้มีคุณสมบัติเชิงสมาคม (associative) ซึ่งหมายความว่า (A + B) + C = A + (B + C) นั่นหมายความว่าเราสามารถเขียน A + B + C โดยไม่ต้องมีวงเล็บและไม่มีความกำกวม</p>
<p>เมื่อเรานิยามการบวกแล้ว เราสามารถนิยามการคูณในแบบมาตรฐานที่ต่อยอดจากการบวก สำหรับจุด P บนเส้นโค้งวงรี ถ้า k เป็นจำนวนเต็มบวก แล้ว kP = P + P + P + … + P (k ครั้ง) โปรดทราบว่า k บางครั้งถูกเรียกว่า "เลขชี้กำลัง"</p>
<h3>Public Keys</h3>
<p>ในระบบคริปโตกราฟีแบบเส้นโค้งวงรี (Elliptic Curve Cryptography)  public key ถูกคำนวณจาก private key โดยใช้การคูณเส้นโค้งวงรี ซึ่งเป็นกระบวนการที่ไม่สามารถย้อนกลับได้:</p>
<p>K = k × G</p>
<p>โดยที่:</p>
<ul>
<li>k คือ private key</li>
<li>G คือจุดคงที่ที่เรียกว่า จุดกำเนิด (generator point)</li>
<li>K คือ public key</li>
</ul>
<p>การดำเนินการย้อนกลับ ที่เรียกว่า "การหาลอการิทึมแบบไม่ต่อเนื่อง" (finding the discrete logarithm) - คือการคำนวณหา k เมื่อรู้ค่า K - เป็นสิ่งที่ยากมากเทียบเท่ากับการลองค่า k ทุกค่าที่เป็นไปได้ (วิธีการแบบ brute-force)</p>
<p>ความยากของการย้อนกลับนี้คือหลักการความปลอดภัยหลักของระบบ ECC ที่ใช้ในบิตคอยน์ ซึ่งทำให้สามารถเผยแพร่ public key ได้อย่างปลอดภัย โดยที่ไม่ต้องกังวลว่าจะมีใครสามารถคำนวณย้อนกลับเพื่อหา private key ได้</p>
<blockquote>
<p>TIP:การคูณเส้นโค้งวงรีเป็นฟังก์ชันประเภทที่นักเข้ารหัสลับเรียกว่า “ trap door function ”:</p>
</blockquote>
<blockquote>
</blockquote>
<ul>
<li>เป็นสิ่งที่ทำได้ง่ายในทิศทางหนึ่ง</li>
<li>แต่เป็นไปไม่ได้ที่จะทำในทิศทางตรงกันข้าม</li>
</ul>
<blockquote>
<p>คนที่มี private key สามารถสร้าง public key ได้อย่างง่ายดาย และสามารถแบ่งปันกับโลกได้โดยรู้ว่าไม่มีใครสามารถย้อนกลับฟังก์ชันและคำนวณ private key จาก public key ได้ กลวิธีทางคณิตศาสตร์นี้กลายเป็นพื้นฐานสำหรับลายเซ็นดิจิทัลที่ปลอมแปลงไม่ได้และมีความปลอดภัย ซึ่งใช้พิสูจน์การควบคุมเงินบิตคอยน์</p>
</blockquote>
<p>เริ่มต้นด้วยการใช้ private key ในรูปแบบของตัวเลขสุ่ม เราคูณมันด้วยจุดที่กำหนดไว้ล่วงหน้าบนเส้นโค้งที่เรียกว่า จุดกำเนิด (generator point)  เพื่อสร้างจุดอื่นที่อยู่บนเส้นโค้งเดียวกัน ซึ่งคำตอบจะเป็น public key ที่สอดคล้องกัน จุดกำเนิดถูกกำหนดไว้เป็นส่วนหนึ่งของมาตรฐาน secp256k1 และเป็นค่าเดียวกันสำหรับกุญแจทั้งหมดในระบบบิตคอยน์</p>
<p>เนื่องจากจุดกำเนิด G เป็นค่าเดียวกันสำหรับผู้ใช้บิตคอยน์ทุกคน private key (k) ที่คูณกับ G จะได้ public key (K) เดียวกันเสมอ ความสัมพันธ์ระหว่าง k และ K เป็นแบบตายตัวแต่สามารถคำนวณได้ในทิศทางเดียวเท่านั้น คือจาก k ไปยัง K นี่คือเหตุผลที่ public key ของบิตคอยน์ (K) สามารถแบ่งปันกับทุกคนได้โดยไม่เปิดเผย private key (k) ของผู้ใช้</p>
<blockquote>
<p>TIP: private key สามารถแปลงเป็น public key ได้ แต่ public key ไม่สามารถแปลงกลับเป็น private key ได้ เพราะคณิตศาสตร์ที่ใช้ทำงานได้เพียงทิศทางเดียวเท่านั้น</p>
</blockquote>
<p>เมื่อนำการคูณเส้นโค้งวงรีมาใช้งาน เราจะนำ private key (k) ที่สร้างขึ้นก่อนหน้านี้มาคูณกับจุดกำเนิด G เพื่อหา public key (K):</p>
<pre><code>K = 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD × G
</code></pre>
<p>public key (K) จะถูกกำหนดเป็นจุด K = (x, y) โดยที่:</p>
<pre><code>x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
</code></pre>
<p>เพื่อจะให้เห็นภาพของการคูณจุดด้วยจำนวนเต็มมากขึ้น เราจะใช้เส้นโค้งวงรีที่ง่ายกว่าบนจำนวนจริง (โดยหลักการทางคณิตศาสตร์ยังคงเหมือนกัน) เป้าหมายของเราคือการหาผลคูณ kG ของจุดกำเนิด G ซึ่งเทียบเท่ากับการบวก G เข้ากับตัวเอง k ครั้งติดต่อกัน</p>
<p>ในเส้นโค้งวงรี การบวกจุดเข้ากับตัวเองเทียบเท่ากับการลากเส้นสัมผัสที่จุดนั้นและหาว่าเส้นนั้นตัดกับเส้นโค้งอีกครั้งที่จุดใด จากนั้นจึงสะท้อนจุดนั้นบนแกน x</p>
<p>การเข้ารหัสลับด้วยเส้นโค้งวงรี: การแสดงภาพการคูณจุด G ด้วยจำนวนเต็ม k บนเส้นโค้งวงรี แสดงกระบวนการในการหา G, 2G, 4G เป็นการดำเนินการทางเรขาคณิตบนเส้นโค้งได้ดังนี้</p>
<blockquote>
<p>TIP: ในซอฟแวร์ของบิตคอยน์ส่วนใหญ่ใช้ไลบรารีเข้ารหัสลับ libsecp256k1 เพื่อทำการคำนวณทางคณิตศาสตร์เส้นโค้งวงรี<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0404.png" alt="image"></p>
</blockquote>
<h3>Output and Input Scripts</h3>
<p>แม้ว่าภาพประกอบจาก Bitcoin whitepaper ที่แสดงเรื่อง "Transaction chain" จะแสดงให้เห็นว่ามีการใช้ public key และ digital signature โดยตรง แต่ในความเป็นจริงบิตคอยน์เวอร์ชันแรกนั้นมีการส่งการชำระเงินไปยังฟิลด์ที่เรียกว่า output script และมีการใช้จ่ายบิตคอยน์เหล่านั้นโดยได้รับอนุญาตจากฟิลด์ที่เรียกว่า input script ฟิลด์เหล่านี้อนุญาตให้มีการดำเนินการเพิ่มเติมนอกเหนือจาก (หรือแทนที่) การตรวจสอบว่าลายเซ็นสอดคล้องกับ public key หรือไม่ ตัวอย่างเช่น output script สามารถมี public key สองดอกและต้องการลายเซ็นสองลายเซ็นที่สอดคล้องกันในฟิลด์ input script ที่ใช้จ่าย</p>
<p>ในภายหลัง ในหัวข้อ [tx_script] เราจะได้เรียนรู้เกี่ยวกับสคริปต์อย่างละเอียด สำหรับตอนนี้ สิ่งที่เราต้องเข้าใจคือ บิตคอยน์จะถูกรับเข้า output script ที่ทำหน้าที่เหมือน public key และการใช้จ่ายบิตคอยน์จะได้รับอนุญาตโดย input script ที่ทำหน้าที่เหมือนลายเซ็น</p>
<h4>IP Addresses: The Original Address for Bitcoin (P2PK)</h4>
<p>เราได้เห็นแล้วว่าอลิซสามารถจ่ายเงินให้บ็อบโดยการมอบบิตคอยน์บางส่วนของเธอให้กับกุญแจสาธารณะของบ็อบ แต่อลิซจะได้กุญแจสาธารณะของบ็อบมาได้อย่างไร? บ็อบอาจจะให้สำเนากุญแจแก่เธอ แต่ลองดูกุญแจสาธารณะที่เราใช้งานในตัวอย่างที่ผ่านมาอีกครั้ง:</p>
<pre><code>x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
</code></pre>
<blockquote>
<p>TIP จากหลาม: :สังเกตได้ว่า public key มีความยาวมาก ลองจินตนาการว่าบ็อบพยายามอ่านกุญแจนี้ให้อลิซฟังทางโทรศัพท์ คงจะยากมากที่จะอ่านและบันทึกโดยไม่มีข้อผิดพลาด</p>
</blockquote>
<p>แทนที่จะป้อนกุญแจสาธารณะโดยตรง เวอร์ชันแรกของซอฟต์แวร์บิตคอยน์อนุญาตให้ผู้จ่ายเงินป้อนที่อยู่ IP ของผู้รับได้ ตามที่แสดงในหน้าจอการส่งเงินรุ่นแรกของบิตคอยน์ผ่าน The Internet Archive</p>
<p>คุณสมบัตินี้ถูกลบออกในภายหลัง เนื่องจากมีปัญหามากมายในการใช้ที่อยู่ IP แต่คำอธิบายสั้นๆ จะช่วยให้เราเข้าใจได้ดีขึ้นว่าทำไมคุณสมบัติบางอย่างอาจถูกเพิ่มเข้าไปในโปรโตคอลบิตคอยน์</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0405.png" alt="image"></p>
<p>เมื่ออลิซป้อนที่อยู่ IP ของบ็อบในบิตคอยน์เวอร์ชัน 0.1 Full node ของเธอจะทำการเชื่อมต่อกับ full node ของเขาและได้รับ public key ใหม่จากกระเป๋าสตางค์ของบ็อบที่โหนดของเขาไม่เคยให้กับใครมาก่อน การที่เป็น public key ใหม่นี้มีความสำคัญเพื่อให้แน่ใจว่าธุรกรรมต่าง ๆ ที่จ่ายให้บ็อบจะไม่สามารถถูกเชื่อมโยงเข้าด้วยกันโดยคนที่กำลังดูบล็อกเชนและสังเกตเห็นว่าธุรกรรมทั้งหมดจ่ายไปยัง public key เดียวกัน</p>
<p>เมื่อใช้ public key จากโหนดของอลิซซึ่งได้รับมาจากโหนดของบ็อบ กระเป๋าสตางค์ของอลิซจะสร้างเอาต์พุตธุรกรรมที่จ่ายให้กับสคริปต์เอาต์พุตดังนี้</p>
<pre><code>&lt;Bob's public key&gt; OP_CHECKSIG
</code></pre>
<p>ต่อมาบ็อบจะสามารถใช้จ่ายเอาต์พุตนั้นด้วยสคริปต์อินพุตที่ประกอบด้วยลายเซ็นของเขาเท่านั้น:</p>
<pre><code>&lt;Bob's signature&gt;
</code></pre>
<p>เพื่อให้เข้าใจว่าสคริปต์อินพุตและเอาต์พุตกำลังทำอะไร คุณสามารถรวมพวกมันเข้าด้วยกัน (สคริปต์อินพุตก่อน) แล้วสังเกตว่าข้อมูลแต่ละชิ้น (แสดงในเครื่องหมาย &lt; &gt;) จะถูกวางไว้ที่ด้านบนสุดของรายการที่เรียกว่าสแตก (stack) เมื่อพบรหัสคำสั่ง (opcode) มันจะใช้รายการจากสแตก โดยเริ่มจากรายการบนสุด มาดูว่ามันทำงานอย่างไรโดยเริ่มจากสคริปต์ที่รวมกัน:</p>
<pre><code>&lt;Bob's signature&gt; &lt;Bob's public key&gt; OP_CHECKSIG
</code></pre>
<p>สำหรับสคริปต์นี้ ลายเซ็นของบ็อบจะถูกนำไปไว้บนสแตก จากนั้น public key ของบ็อบจะถูกวางไว้ด้านบนของลายเซ็น และบนสุดจะเป็นคำสั่ง OP_CHECKSIG ที่จะใช้องค์ประกอบสองอย่าง เริ่มจาก public key ตามด้วยลายเซ็น โดยลบพวกมันออกจากสแตก มันจะตรวจสอบว่าลายเซ็นตรงกับ public key และยืนยันฟิลด์ต่าง ๆ ในธุรกรรม ถ้าลายเซ็นถูกต้อง OP_CHECKSIG จะแทนที่ตัวเองบนสแตกด้วยค่า 1 ถ้าลายเซ็นไม่ถูกต้อง มันจะแทนที่ตัวเองด้วย 0 ถ้ามีรายการที่ไม่ใช่ศูนย์อยู่บนสุดของสแตกเมื่อสิ้นสุดการประเมิน สคริปต์ก็จะผ่าน ถ้าสคริปต์ทั้งหมดในธุรกรรมผ่าน และรายละเอียดอื่น ๆ ทั้งหมดเกี่ยวกับธุรกรรมนั้นต้องถูกต้องจึงจะถือว่าธุรกรรมนั้นถูกต้อง</p>
<p>โดยสรุป สคริปต์ข้างต้นใช้ public key และลายเซ็นเดียวกันกับที่อธิบายใน whitepaper แต่เพิ่มความซับซ้อนของฟิลด์สคริปต์สองฟิลด์และรหัสคำสั่งหนึ่งตัว ซึ่งเราจะเริ่มเห็นประโยชน์เมื่อเรามองที่ส่วนต่อไป</p>
<blockquote>
<p>TIP:จากหลาม agian: เอาต์พุตประเภทนี้เป็นที่รู้จักในปัจจุบันว่า P2PK ซึ่งมันไม่เคยถูกใช้อย่างแพร่หลายสำหรับการชำระเงิน และไม่มีโปรแกรมที่ใช้กันอย่างแพร่หลายที่รองรับการชำระเงินผ่านที่อยู่ IP เป็นเวลาเกือบทศวรรษแล้ว</p>
</blockquote>
<h4>Legacy addresses for P2PKH</h4>
<p>แน่นอนว่าการป้อนที่อยู่ IP ของคนที่คุณต้องการจ่ายเงินให้นั้นมีข้อดีหลายประการ แต่ก็มีข้อเสียหลายประการเช่นกัน หนึ่งในข้อเสียที่สำคัญคือผู้รับจำเป็นต้องให้กระเป๋าสตางค์ของพวกเขาออนไลน์ที่ที่อยู่ IP ของพวกเขา และต้องสามารถเข้าถึงได้จากโลกภายนอก </p>
<p>ซึ่งสำหรับคนจำนวนมากนั่นไม่ใช่ตัวเลือกที่เป็นไปได้เพราะหากพวกเขา:</p>
<ul>
<li>ปิดคอมพิวเตอร์ในเวลากลางคืน</li>
<li>แล็ปท็อปของพวกเขาเข้าสู่โหมดสลีป</li>
<li>อยู่หลังไฟร์วอลล์</li>
<li>หรือกำลังใช้การแปลงที่อยู่เครือข่าย (NAT)</li>
</ul>
<p>ปัญหานี้นำเรากลับมาสู่ความท้าทายเดิมที่ผู้รับเงินอย่างบ็อบต้องให้ public key ที่มีความยาวมากแก่ผู้จ่ายเงินอย่างอลิซ  public key ของบิตคอยน์ที่สั้นที่สุดที่นักพัฒนาบิตคอยน์รุ่นแรกรู้จักมีขนาด 65 ไบต์ เทียบเท่ากับ 130 ตัวอักษรเมื่อเขียนในรูปแบบเลขฐานสิบหก (เฮกซาเดซิมอล) แต่อย่างไรก็ตาม บิตคอยน์มีโครงสร้างข้อมูลหลายอย่างที่มีขนาดใหญ่กว่า 65 ไบต์มาก ซึ่งจำเป็นต้องถูกอ้างอิงอย่างปลอดภัยในส่วนอื่น ๆ ของบิตคอยน์โดยใช้ข้อมูลขนาดเล็กที่สุดเท่าที่จะปลอดภัยได้</p>
<p>โดยบิตคอยน์แก้ปัญหานี้ด้วย ฟังก์ชันแฮช (hash function) ซึ่งเป็นฟังก์ชันที่รับข้อมูลที่อาจมีขนาดใหญ่ นำมาแฮช และให้ผลลัพธ์เป็นข้อมูลขนาดคงที่ ฟังก์ชันแฮชจะผลิตผลลัพธ์เดียวกันเสมอเมื่อได้รับข้อมูลนำเข้าแบบเดียวกัน และฟังก์ชันที่ปลอดภัยจะทำให้เป็นไปไม่ได้ในทางปฏิบัติสำหรับผู้ที่ต้องการเลือกข้อมูลนำเข้าอื่นที่ให้ผลลัพธ์เหมือนกันได้ นั่นทำให้ผลลัพธ์เป็น คำมั่นสัญญา (commitment) ต่อข้อมูลนำเข้า เป็นสัญญาว่าในทางปฏิบัติ มีเพียงข้อมูลนำเข้า x เท่านั้นที่จะให้ผลลัพธ์ X</p>
<p>สมมติว่าผมต้องการถามคำถามคุณและให้คำตอบของผมในรูปแบบที่คุณไม่สามารถอ่านได้ทันที สมมติว่าคำถามคือ "ในปีไหนที่ซาโตชิ นาคาโมโตะเริ่มทำงานบนบิทคอยน์?" ผมจะให้การยืนยันคำตอบของผมในรูปแบบของผลลัพธ์จากฟังก์ชันแฮช SHA256 ซึ่งเป็นฟังก์ชันที่ใช้บ่อยที่สุดในบิทคอยน์:</p>
<pre><code>94d7a772612c8f2f2ec609d41f5bd3d04a5aa1dfe3582f04af517d396a302e4e
</code></pre>
<p>ต่อมา หลังจากคุณบอกคำตอบที่คุณเดาสำหรับคำถามนั้น ผมสามารถเปิดเผยคำตอบของผมและพิสูจน์ให้คุณเห็นว่าคำตอบของผม เมื่อใช้เป็นข้อมูลสำหรับฟังก์ชันแฮช จะให้ผลลัพธ์เดียวกันกับที่ผมให้คุณก่อนหน้านี้</p>
<pre><code>$ echo "2007.  He said about a year and a half before Oct 2008" | sha256sum
94d7a772612c8f2f2ec609d41f5bd3d04a5aa1dfe3582f04af517d396a302e4e
</code></pre>
<p>ทีนี้ให้สมมติว่าเราถามบ็อบว่า " public key ของคุณคืออะไร?" บ็อบสามารถใช้ฟังก์ชันแฮชเพื่อให้การยืนยันที่ปลอดภัยทางการเข้ารหัสต่อ public key ของเขา หากเขาเปิดเผยกุญแจในภายหลัง และเราตรวจสอบว่ามันให้ผลการยืนยันเดียวกันกับที่เขาให้เราก่อนหน้านี้ เราสามารถมั่นใจได้ว่ามันเป็นกุญแจเดียวกันที่ใช้สร้างการยืนยันก่อนหน้านี้</p>
<p>ฟังก์ชันแฮช SHA256 ถือว่าปลอดภัยมากและให้ผลลัพธ์ 256 บิต (32 ไบต์) น้อยกว่าครึ่งหนึ่งของขนาด public key ของบิทคอยน์ดั้งเดิม แต่อย่างไรก็ตาม มีฟังก์ชันแฮชอื่นๆ ที่ปลอดภัยน้อยกว่าเล็กน้อยที่ให้ผลลัพธ์ขนาดเล็กกว่า เช่น ฟังก์ชันแฮช RIPEMD-160 ซึ่งให้ผลลัพธ์ 160 บิต (20 ไบต์) ด้วยเหตุผลที่ซาโตชิ นาคาโมโตะไม่เคยระบุ เวอร์ชันดั้งเดิมของบิทคอยน์สร้างการยืนยันต่อ public key โดยการแฮชกุญแจด้วย SHA256 ก่อน แล้วแฮชผลลัพธ์นั้นด้วย RIPEMD-160 ซึ่งให้การยืนยันขนาด 20 ไบต์ต่อ public key</p>
<p>เราสามารถดูสิ่งนี้ตามอัลกอริทึม เริ่มจากกุญแจสาธารณะ K เราคำนวณแฮช SHA256 และคำนวณแฮช RIPEMD-160 ของผลลัพธ์ ซึ่งให้ตัวเลข 160 บิต (20 ไบต์): A = RIPEMD160(SHA256(K))</p>
<p>ทีนี้เราคงเข้าใจวิธีสร้างการยืนยันต่อ public key แล้ว ต่อไปเราจะมาดูวิธีการใช้งานโดยพิจารณาสคริปต์เอาต์พุตต่อไปนี้:</p>
<pre><code>OP_DUP OP_HASH160 &lt;Bob's commitment&gt; OP_EQUAL OP_CHECKSIG
</code></pre>
<p>และสคริปต์อินพุตต่อไปนี้:</p>
<pre><code>&lt;Bob's signature&gt; &lt;Bob's public key&gt;
</code></pre>
<p>และเมื่อเรารวมมันเข้าด้วยกันเราจะได้ผลลัพธ์ดังนี้:</p>
<pre><code>&lt;Bob's signature&gt; &lt;Bob's public key&gt; OP_DUP OP_HASH160 &lt;Bob's commitment&gt; OP_EQUAL OP_CHECKSIG
</code></pre>
<p>เหมือนที่เราทำใน IP Addresses: The Original Address for Bitcoin (P2PK) เราเริ่มวางรายการลงในสแต็ก ลายเซ็นของบ็อบถูกวางก่อน จากนั้น public key ของเขาถูกวางไว้ด้านบน จากนั้นดำเนินการ OP_DUP เพื่อทำสำเนารายการบนสุด ดังนั้นรายการบนสุดและรายการที่สองจากบนในสแต็กตอนนี้เป็น public key ของบ็อบทั้งคู่ การดำเนินการ OP_HASH160 ใช้ (ลบ) public key บนสุดและแทนที่ด้วยผลลัพธ์ของการแฮชด้วย RIPEMD160(SHA256(K)) ดังนั้นตอนนี้บนสุดของสแต็กคือแฮชของ public key ของบ็อบ ต่อไป  commitment ถูกเพิ่มไว้บนสุดของสแต็ก การดำเนินการ OP_EQUALVERIFY ใช้รายการสองรายการบนสุดและตรวจสอบว่าพวกมันเท่ากัน ซึ่งควรเป็นเช่นนั้นหาก public key ที่บ็อบให้ในสคริปต์อินพุตเป็น public key เดียวกันกับที่ใช้สร้างการยืนยันในสคริปต์เอาต์พุตที่อลิซจ่าย หาก OP_EQUALVERIFY ล้มเหลว ทั้งสคริปต์จะล้มเหลว สุดท้าย เราเหลือสแต็กที่มีเพียงลายเซ็นของบ็อบและ public key ของเขา รหัสปฏิบัติการ OP_CHECKSIG ตรวจสอบว่าพวกมันสอดคล้องกัน</p>
<blockquote>
<p>TIP: จากหลาม ถ้าอ่านตรงนี้และงง ๆ ผมไปทำรูปมาให้ดูง่ายขึ้นครับ</p>
</blockquote>
<p><img src="https://image.nostr.build/3ea1036b7de3d83b960d1ed862e738120159e4f173d55a4dfdaddc75c3b25166.png" alt="image"></p>
<p>แม้กระบวนการของการ pay-to-publickey-hash(P2PKH) อาจดูซับซ้อน แต่มันทำให้การที่อลิซจ่ายเงินให้บ็อบมีเพียงการยืนยันเพียง 20 ไบต์ต่อ public key ของเขาแทนที่จะเป็นตัวกุญแจเอง ซึ่งจะมีขนาด 65 ไบต์ในเวอร์ชันดั้งเดิมของบิทคอยน์ นั่นเป็นข้อมูลที่น้อยกว่ามากที่บ็อบต้องสื่อสารกับอลิซ</p>
<p>แต่อย่างไรก็ตาม เรายังไม่ได้พูดถึงวิธีที่บ็อบรับ 20 ไบต์เหล่านั้นจากกระเป๋าเงินบิทคอยน์ของเขาไปยังกระเป๋าเงินของอลิซ มีการเข้ารหัสค่าไบต์ที่ใช้กันอย่างแพร่หลาย เช่น เลขฐานสิบหก แต่ข้อผิดพลาดใด ๆ ในการคัดลอกการยืนยันจะทำให้บิทคอยน์ถูกส่งไปยังเอาต์พุตที่ไม่สามารถใช้จ่ายได้ ทำให้พวกมันสูญหายไปตลอดกาล โดยในส่วนถัดไป เราจะดูที่การเข้ารหัสแบบกะทัดรัดและการตรวจสอบความถูกต้อง</p>
<h4>Base58check Encoding</h4>
<p>ระบบคอมพิวเตอร์มีวิธีเขียนตัวเลขยาวๆ ให้สั้นลงโดยใช้ทั้งตัวเลขและตัวอักษรผสมกัน เพื่อใช้พื้นที่น้อยลงอย่างเช่น</p>
<ul>
<li>ระบบเลขฐานสิบ (ปกติที่เราใช้) - ใช้เลข 0-9 เท่านั้น</li>
<li>ระบบเลขฐานสิบหก - ใช้เลข 0-9 และตัวอักษร A-F ตัวอย่าง: เลข 255 ในระบบปกติ เขียนเป็น FF ในระบบเลขฐานสิบหก (สั้นกว่า)</li>
<li>ระบบเลขฐานหกสิบสี่ (Base64) - ใช้สัญลักษณ์ถึง 64 ตัว: ตัวอักษรเล็ก (a-z) 26 ตัว, ตัวอักษรใหญ่ (A-Z) 26 ตัว, ตัวเลข (0-9) 10 ตัว, สัญลักษณ์พิเศษอีก 2 ตัว ("+" และ "/")</li>
</ul>
<p>โดยระบบ Base64 นี้ช่วยให้เราส่งไฟล์คอมพิวเตอร์ผ่านข้อความธรรมดาได้ เช่น การส่งรูปภาพผ่านอีเมล โดยใช้พื้นที่น้อยกว่าการเขียนเป็นเลขฐานสิบแบบปกติมาก</p>
<p>การเข้ารหัสแบบ Base58 คล้ายกับ Base64 โดยใช้ตัวอักษรพิมพ์ใหญ่ พิมพ์เล็ก และตัวเลข แต่ได้ตัดตัวอักษรบางตัวที่มักถูกเข้าใจผิดว่าเป็นตัวอื่นและอาจดูเหมือนกันเมื่อแสดงในฟอนต์บางประเภทออกไป</p>
<p>Base58 คือ Base64 ที่ตัดตัวอักษรต่อไปนี้ออก:</p>
<ul>
<li>เลข 0 (ศูนย์)</li>
<li>ตัวอักษร O (ตัว O พิมพ์ใหญ่)</li>
<li>ตัวอักษร l (ตัว L พิมพ์เล็ก)</li>
<li>ตัวอักษร I (ตัว I พิมพ์ใหญ่)</li>
<li>และสัญลักษณ์ "+" และ "/"</li>
</ul>
<p>หรือพูดให้ง่ายขึ้น Base58 คือกลุ่มตัวอักษรพิมพ์เล็ก พิมพ์ใหญ่ และตัวเลข แต่ไม่มีตัวอักษรทั้งสี่ตัว (0, O, l, I) ที่กล่าวถึงข้างต้น ตัวอักษรทั้งหมดที่ใช้ใน Base58 จะแสดงให้เห็นในตัวอักษร Base58 ของบิทคอยน์</p>
<p>Example 2. Bitcoin’s base58 alphabet</p>
<pre><code>123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
</code></pre>
<p>การเพิ่มความปลอดภัยพิเศษเพื่อป้องกันการพิมพ์ผิดหรือข้อผิดพลาดในการคัดลอก base58check ได้รวม รหัสตรวจสอบ (checksum) ที่เข้ารหัสในตัวอักษร base58 เข้าไปด้วย รหัสตรวจสอบนี้คือข้อมูลเพิ่มเติมอีก 4 ไบต์ที่เพิ่มเข้าไปที่ท้ายของข้อมูลที่กำลังถูกเข้ารหัส</p>
<p>รหัสตรวจสอบนี้ได้มาจากการแฮชข้อมูลที่ถูกเข้ารหัส และจึงสามารถใช้เพื่อตรวจจับข้อผิดพลาดจากการคัดลอกและการพิมพ์ได้ เมื่อโปรแกรมได้รับรหัส base58check ซอฟต์แวร์ถอดรหัสจะคำนวณรหัสตรวจสอบของข้อมูลและเปรียบเทียบกับรหัสตรวจสอบที่รวมอยู่ในรหัสนั้น</p>
<p>หากทั้งสองไม่ตรงกัน แสดงว่ามีข้อผิดพลาดเกิดขึ้น และข้อมูล base58check นั้นไม่ถูกต้อง กระบวนการนี้ช่วยป้องกันไม่ให้ address บิทคอยน์ที่พิมพ์ผิดถูกยอมรับโดยซอฟต์แวร์กระเป๋าเงินว่าเป็น address ที่ถูกต้อง ซึ่งเป็นข้อผิดพลาดที่อาจส่งผลให้สูญเสียเงินได้</p>
<p>การแปลงข้อมูล (ตัวเลข) เป็นรูปแบบ base58check มีขั้นตอนดังนี้:</p>
<ol>
<li>เราเริ่มโดยการเพิ่ม prefix เข้าไปในข้อมูล เรียกว่า "version byte" ซึ่งช่วยให้ระบุประเภทของข้อมูลที่ถูกเข้ารหัสได้ง่าย ตัวอย่างเช่น: prefix ศูนย์ (0x00 ในระบบเลขฐานสิบหก) แสดงว่าข้อมูลควรถูกใช้เป็นการยืนยัน (hash) ในสคริปต์เอาต์พุต legacy P2PKH</li>
<li>จากนั้น เราคำนวณ "double-SHA" checksum ซึ่งหมายถึงการใช้อัลกอริทึมแฮช SHA256 สองครั้งกับผลลัพธ์ก่อนหน้า (prefix ต่อกับข้อมูล):<pre><code>checksum = SHA256(SHA256(prefix||data))
</code></pre>
</li>
<li>จากแฮช 32 ไบต์ที่ได้ (การแฮชซ้อนแฮช) เราเลือกเฉพาะ 4 ไบต์แรก ไบต์ทั้งสี่นี้ทำหน้าที่เป็นรหัสตรวจสอบข้อผิดพลาดหรือ checksum</li>
<li>นำ checksum นี้ไปต่อที่ท้ายข้อมูล</li>
</ol>
<p>การเข้ารหัสแบบ base58check คือรูปแบบการเข้ารหัสที่ใช้ base58 พร้อมกับการระบุเวอร์ชันและการตรวจสอบความถูกต้อง เพื่อการเข้ารหัสข้อมูลบิทคอยน์ โดยคุณสามารถดูภาพประกอบด้านล่างเพื่อความเข้าใจเพิ่มเติม</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0406.png" alt="image"></p>
<p>ในบิตคอยน์นั้น นอกจากจะใช้ base58check ในการยืนยัน public key แล้ว ก็ยังมีการใช้ในข้อมูลอื่น ๆ ด้วย เพื่อทำให้ข้อมูลนั้นกะทัดรัด อ่านง่าย และตรวจจับข้อผิดพลาดได้ง่ายด้วยรหัสนำหน้า (version prefix) ในการเข้ารหัสแบบ base58check ถูกใช้เพื่อสร้างรูปแบบที่แยกแยะได้ง่าย ซึ่งเมื่อเข้ารหัสด้วย base58 โดยจะมีตัวอักษรเฉพาะที่จุดเริ่มต้นของข้อมูลที่เข้ารหัส base58check ตัวอักษรเหล่านี้ช่วยให้เราระบุประเภทของข้อมูลที่ถูกเข้ารหัสและวิธีการใช้งานได้ง่าย นี่คือสิ่งที่แยกความแตกต่าง ตัวอย่างเช่น ระหว่าง address บิทคอยน์ที่เข้ารหัส base58check ซึ่งขึ้นต้นด้วยเลข 1 กับรูปแบบการนำเข้า private key  (WIF - Wallet Import Format) ที่เข้ารหัส base58check ซึ่งขึ้นต้นด้วยเลข 5 ตัวอย่างของ version prefix สามารถดูได้ตามตารางด้านล่างนี้</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742640432919-YAKIHONNES3.png" alt="image"></p>
<p>ภาพต่อไปนี้จะทำให้คุณเห็นภาพของกระบวนการแปลง public key ให้เป็น bitcoin address</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0407.png" alt="image"></p>
<h3>Compressed Public Keys</h3>
<p>ในยุคแรก ๆ ของบิตคอยน์นั้น มีเพียงการสร้าง public key แบบ 65 Bytes เท่านั้น แต่ในเวลาต่อมา เหล่านักพัฒนาในยุคหลังได้พบวิธีการสร้าง public key แบบใหม่ที่มีเพียง 33 Bytes และสามารถทำงานร่วมกันกับโหนดทั้งหมดในขณะนั้นได้ จีงไม่จะเป็นต้องเปลี่ยนแปลงกฎหรือโครงสร้างภายในโปรโตคอลของบิตคอยน์ โดย poublic key แบบใหม่ที่มีขนาด 33 Bytes นี้เรียกว่า compressed public key (public key ที่ถูกบีบอัด) และมีการเรียก public key ที่มีขนาด 65 Bytes ว่า uncompressed public key (public key ที่ไม่ถูกบีบอัด) ซึ่งประโยชน์ของ public key ที่เล็กลงนั้น นอกจากจะช่วยให้การส่ง public key ให้ผู้อื่นทำได้ง่ายขึ้นแล้ว ยังช่วยให้ธุรกรรมมีขนาดเล็กลง และช่วยให้สามารถทำการชำระเงินได้มากขึ้นในบล็อกเดียวกัน</p>
<p>อย่างที่เราได้เรียนรู้จากเนื้อหาในส่วนของ public key เราได้ทราบว่า public key คือจุด (x, y) บนเส้นโค้งวงรี เนื่องจากเส้นโค้งแสดงฟังก์ชันทางคณิตศาสตร์ จุดบนเส้นโค้งจึงเป็นคำตอบของสมการ ดังนั้นหากเรารู้พิกัด x เราก็สามารถคำนวณพิกัด y ได้โดยแก้สมการ y² mod p = (x³ + 7) mod p นั่นหมายความว่าเราสามารถเก็บเพียงพิกัด x ของ public key โดยละพิกัด y ไว้ ซึ่งช่วยลดขนาดของกุญแจและพื้นที่ที่ต้องใช้เก็บข้อมูลลง 256 บิต การลดขนาดลงเกือบ 50% ในทุกธุรกรรมรวมกันแล้วช่วยประหยัดข้อมูลได้มากมายในระยะยาว!</p>
<p>นี่คือ public key ที่ได้ยกเป็นตัวอย่างไว้ก่อนหน้า</p>
<pre><code>x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
</code></pre>
<p>และนี่คือ public key ที่มีตัวนำหน้า 04 ตามด้วยพิกัด x และ y ในรูปแบบ 04 x y:</p>
<pre><code>K = 04F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
</code></pre>
<p>uncompressed public key นั้นจะมีตัวนำหน้าเป็น 04 แต่ compressed public key จะมีตัวนำหน้าเป็น 02 หรือ 03 โดยเหตุผลนั้นมาจากสมการ y² mod p = (x³ + 7) mod p เนื่องจากด้านซ้ายของสมการคือ y² คำตอบสำหรับ y จึงเป็นรากที่สอง ซึ่งอาจมีค่าเป็นบวกหรือลบก็ได้ หากมองเชิงภาพ นี่หมายความว่าพิกัด y ที่ได้อาจอยู่เหนือหรือใต้แกน x เราต้องไม่ลืมว่าเส้นโค้งมีความสมมาตร ซึ่งหมายความว่ามันจะสะท้อนเหมือนกระจกโดยแกน x ดังนั้น แม้เราจะละพิกัด y ได้ แต่เราต้องเก็บ เครื่องหมาย ของ y (บวกหรือลบ) หรืออีกนัยหนึ่งคือเราต้องจำว่ามันอยู่เหนือหรือใต้แกน x เพราะแต่ละตำแหน่งแทนจุดที่แตกต่างกันและเป็น public key ที่แตกต่างกัน</p>
<p>เมื่อคำนวณเส้นโค้งวงรีในระบบเลขฐานสองบนสนามจำกัดของเลขจำนวนเฉพาะ p พิกัด y จะเป็นเลขคู่หรือเลขคี่ ซึ่งสอดคล้องกับเครื่องหมายบวก/ลบตามที่อธิบายก่อนหน้านี้ ดังนั้น เพื่อแยกความแตกต่างระหว่างค่าที่เป็นไปได้สองค่าของ y เราจึงเก็บ compressed public key ด้วยตัวนำหน้า 02 ถ้า y เป็นเลขคู่ และ 03 ถ้า y เป็นเลขคี่ ซึ่งช่วยให้ซอฟต์แวร์สามารถอนุมานพิกัด y จากพิกัด x และคลายการบีบอัดของ public key ไปยังพิกัดเต็มของจุดได้อย่างถูกต้อง ดังภาพประกอบต่อไปนี้</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0408.png" alt="image"></p>
<p>นี่คือ public key เดียวกันกับที่ยกตัวอย่างไว้ข้างต้นซึ่งแสดงให้เห็นในรูป compressed public key ที่เก็บใน 264 บิต (66 ตัวอักษรเลขฐานสิบหก) โดยมีตัวนำหน้า 03 ซึ่งบ่งชี้ว่าพิกัด y เป็นเลขคี่:</p>
<pre><code>K = 03F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
</code></pre>
<p>compressed public key สอดคล้องกับ private key เดียวกันกับ uncompressed public key หมายความว่ามันถูกสร้างจาก private key เดียวกัน แต่อย่างไรก็ตาม มันก็มีส่วนที่แตกต่างจาก uncompressed public key นั้นคือ หากเราแปลง compressed public key เป็น commitment โดยใช้ฟังก์ชัน HASH160 (RIPEMD160(SHA256(K))) มันจะสร้าง commitment ที่แตกต่างจาก uncompressed public key และจะนำไปสู่ bitcoin address ที่แตกต่างกันในที่สุด สิ่งนี้อาจทำให้สับสนเพราะหมายความว่า private key เดียวสามารถสร้าง public key ในสองรูปแบบที่แตกต่างกัน (แบบบีบอัดและแบบไม่บีบอัด) ซึ่งสร้าง bitcoin address ที่แตกต่างกัน</p>
<p>compressed public key เป็นค่าเริ่มต้นในซอฟต์แวร์บิตคอยน์เกือบทั้งหมดในปัจจุบัน และถูกกำหนดให้ใช้กับคุณสมบัติใหม่บางอย่างที่เพิ่มในการอัปเกรดโปรโตคอลในภายหลัง</p>
<p>อย่างไรก็ตาม ซอฟต์แวร์บางตัวยังคงต้องรองรับ uncompressed public key เช่น แอปพลิเคชันกระเป๋าเงินที่นำเข้า private key จากกระเป๋าเงินเก่า เมื่อกระเป๋าเงินใหม่สแกนบล็อกเชนสำหรับผลลัพธ์และอินพุต P2PKH เก่า มันจำเป็นต้องรู้ว่าควรสแกนกุญแจขนาด 65 ไบต์ (และ commitment ของกุญแจเหล่านั้น) หรือกุญแจขนาด 33 ไบต์ (และ commitment ของกุญแจเหล่านั้น) หากไม่สแกนหาประเภทที่ถูกต้อง อาจทำให้ผู้ใช้ไม่สามารถใช้ยอดคงเหลือทั้งหมดได้ เพื่อแก้ไขปัญหานี้ เมื่อส่งออก private key จากกระเป๋าเงิน WIF ที่ใช้แสดง private key ในกระเป๋าเงินบิตคอยน์รุ่นใหม่จะถูกนำไปใช้แตกต่างกันเล็กน้อยเพื่อบ่งชี้ว่า private key เหล่านี้ถูกใช้ในการสร้าง compressed public key</p>
<h4>Legacy: Pay to Script Hash (P2SH)</h4>
<p>ตามที่เราได้เห็นในส่วนก่อนหน้านี้ ผู้รับบิตคอยน์ สามารถกำหนดให้การชำระเงินที่ส่งมาให้เขานั้นมีเงื่อนไขบางอย่างในสคริปต์เอาต์พุตได้โดยจะต้องปฏิบัติตามเงื่อนไขเหล่านั้นโดยใช้สคริปต์อินพุตเมื่อเขาใช้จ่ายบิตคอยน์เหล่านั้น ในส่วน IP Addresses: The Original Address for Bitcoin (P2PK) เงื่อนไขก็คือสคริปต์อินพุตต้องให้ลายเซ็นที่เหมาะสม ในส่วน Legacy Addresses for P2PKH นั้นจำเป็นต้องมี public key ที่เหมาะสมด้วย</p>
<p>ส่วนสำหรับผู้ส่งก็จะวางเงื่อนไขที่ผู้รับต้องการในสคริปต์เอาต์พุตที่ใช้จ่ายให้กับผู้รับ โดยผู้รับจะต้องสื่อสารเงื่อนไขเหล่านั้นให้ผู้ส่งทราบ ซึ่งคล้ายกับปัญหาที่บ๊อบต้องสื่อสาร public key ของเขาให้อลิซทราบ และเช่นเดียวกับปัญหานั้นที่ public key อาจมีขนาดค่อนข้างใหญ่ เงื่อนไขที่บ๊อบใช้ก็อาจมีขนาดใหญ่มากเช่นกัน—อาจมีขนาดหลายพันไบต์ นั่นไม่เพียงแต่เป็นข้อมูลหลายพันไบต์ที่ต้องสื่อสารให้อลิซทราบ แต่ยังเป็นข้อมูลหลายพันไบต์ที่เธอต้องจ่ายค่าธรรมเนียมธุรกรรมทุกครั้งที่ต้องการใช้จ่ายเงินให้บ๊อบ อย่างไรก็ตาม การใช้ฟังก์ชันแฮชเพื่อสร้าง commitment ขนาดเล็กสำหรับข้อมูลขนาดใหญ่ก็สามารถนำมาใช้ได้ในกรณีนี้เช่นกัน</p>
<p>ในเวลาต่อมานั้น การอัปเกรด BIP16 สำหรับโปรโตคอลบิตคอยน์ในปี 2012 ได้อนุญาตให้สคริปต์เอาต์พุตสร้าง commitment กับ redemption script (redeem script) ได้ แปลว่าเมื่อบ๊อบใช้จ่ายบิตคอยน์ของเขา ภายในสคริปต์อินพุตของเขานั้นจะต้องให้ redeem script ที่ตรงกับ commitment และข้อมูลที่จำเป็นเพื่อให้เป็นไปตาม redeem script (เช่น ลายเซ็น) เริ่มต้นด้วยการจินตนาการว่าบ๊อบต้องการให้มีลายเซ็นสองอันเพื่อใช้จ่ายบิตคอยน์ของเขา หนึ่งลายเซ็นจากกระเป๋าเงินบนเดสก์ท็อปและอีกหนึ่งจากอุปกรณ์เซ็นแบบฮาร์ดแวร์ เขาใส่เงื่อนไขเหล่านั้นลงใน redeem script:</p>
<pre><code>&lt;public key 1&gt; OP_CHECKSIGVERIFY &lt;public key 2&gt; OP_CHECKSIG
</code></pre>
<p>จากนั้นเขาสร้าง commitment กับ redeem script โดยใช้กลไก HASH160 เดียวกับที่ใช้สำหรับ commitment แบบ P2PKH, RIPEMD160(SHA256(script)) commitment นั้นถูกวางไว้ในสคริปต์เอาต์พุตโดยใช้เทมเพลตพิเศษ:</p>
<pre><code>OP_HASH160 &lt;commitment&gt; OP_EQUAL
</code></pre>
<blockquote>
<p>คำเตือน: เมื่อใช้ pay to script hash (P2SH) คุณต้องใช้เทมเพลต P2SH โดยเฉพาะ ซึ่งจะไม่มีข้อมูลหรือเงื่อนไขเพิ่มเติมในสคริปต์เอาต์พุต หากสคริปต์เอาต์พุตไม่ได้เป็น OP_HASH160 &lt;20 ไบต์&gt; OP_EQUAL แน่นอนว่า redeem script จะไม่ถูกใช้และบิตคอยน์ใด ๆ อาจไม่สามารถใช้จ่ายได้หรืออาจถูกใช้จ่ายได้โดยทุกคน (หมายความว่าใครก็สามารถนำไปใช้ได้)</p>
</blockquote>
<p>เมื่อบ๊อบต้องการจ่ายเงินที่เขาได้รับผ่าน commitment สำหรับสคริปต์ของเขา เขาจะใช้สคริปต์อินพุตที่รวมถึง redeem script ซึ่งถูกแปลงให้เป็นข้อมูลอีลิเมนต์เดียว นอกจากนี้เขายังให้ลายเซ็นที่จำเป็นเพื่อให้เป็นไปตาม redeem script โดยเรียงลำดับตามที่จะถูกใช้โดย opcodes:</p>
<pre><code>&lt;signature2&gt; &lt;signature1&gt; &lt;redeem script&gt;
</code></pre>
<p>เมื่อโหนดของบิตคอยน์ได้รับการใช้จ่ายของบ๊อบพวกมันจะตรวจสอบว่า redeem script ที่ถูกแปลงเป็นค่าแฮชแล้วมีค่าเดียวกันกับ commitment มั้ย หลังจากนั้นพวกมันจะแทนที่มันบนสแต็คด้วยค่าที่ถอดรหัสแล้ว:</p>
<pre><code>&lt;signature2&gt; &lt;signature1&gt; &lt;pubkey1&gt; OP_CHECKSIGVERIFY &lt;pubkey2&gt; OP_CHECKSIG
</code></pre>
<p>สคริปต์จะถูกประมวลผล และหากผ่านการตรวจสอบและรายละเอียดธุรกรรมอื่น ๆ ทั้งหมดถูกต้อง ธุรกรรมก็จะถือว่าใช้ได้</p>
<p>address สำหรับ P2SH ก็ถูกสร้างด้วย base58check เช่นกัน คำนำหน้าเวอร์ชันถูกตั้งเป็น 5 ซึ่งทำให้ที่อยู่ที่เข้ารหัสแล้วขึ้นต้นด้วยเลข 3 ตัวอย่างของที่อยู่ P2SH คือ 3F6i6kwkevjR7AsAd4te2YB2zZyASEm1HM</p>
<blockquote>
<p>TIP: P2SH ไม่จำเป็นต้องเหมือนกับธุรกรรมแบบหลายลายเซ็น (multisignature) เสมอไป ถึง address P2SH ส่วนใหญ่ แทนสคริปต์แบบหลายลายเซ็นก็ตาม แต่อาจแทนสคริปต์ที่เข้ารหัสธุรกรรมประเภทอื่น ๆ ได้ด้วย</p>
</blockquote>
<p>P2PKH และ P2SH เป็นสองเทมเพลตสคริปต์เท่านั้นที่ใช้กับการเข้ารหัสแบบ base58check พวกมันเป็นที่รู้จักในปัจจุบันว่าเป็น address แบบ legacy และกลายเป็นรูปแบบที่พบน้อยลงเรื่อยๆ address แบบ legacy ถูกแทนที่ด้วยaddress ตระกูล bech32</p>
<h4>การโจมตี P2SH แบบ Collision</h4>
<p>address ทั้งหมดที่อิงกับฟังก์ชันแฮชมีความเสี่ยงในทางทฤษฎีต่อผู้โจมตีที่อาจค้นพบอินพุตเดียวกันที่สร้างเอาต์พุตฟังก์ชันแฮช (commitment) โดยอิสระ ในกรณีของบิตคอยน์ หากพวกเขาค้นพบอินพุตในวิธีเดียวกับที่ผู้ใช้ดั้งเดิมทำ พวกเขาจะรู้ private key ของผู้ใช้และสามารถใช้จ่ายบิตคอยน์ของผู้ใช้นั้นได้ โอกาสที่ผู้โจมตีจะสร้างอินพุตสำหรับ commitment ที่มีอยู่แล้วโดยอิสระนั้นขึ้นอยู่กับความแข็งแกร่งของอัลกอริทึมแฮช สำหรับอัลกอริทึมที่ปลอดภัย 160 บิตอย่าง HASH160 ความน่าจะเป็นอยู่ที่ 1 ใน 2^160 นี่เรียกว่าการโจมตีแบบ preimage attack</p>
<p>ผู้โจมตีสามารถพยายามสร้างข้อมูลนำเข้าสองชุดที่แตกต่างกัน (เช่น redeem scripts) ที่สร้างการเข้ารหัสแบบเดียวกันได้ สำหรับ address ที่สร้างโดยฝ่ายเดียวทั้งหมด โอกาสที่ผู้โจมตีจะสร้างข้อมูลนำเข้าที่แตกต่างสำหรับการเข้ารหัสที่มีอยู่แล้วมีประมาณ 1 ใน 2^160 สำหรับอัลกอริทึม HASH160 นี่คือการโจมตีแบบ second preimage attack </p>
<p>อย่างไรก็ตาม สถานการณ์จะเปลี่ยนไปเมื่อผู้โจมตีสามารถมีอิทธิพลต่อค่าข้อมูลนำเข้าดั้งเดิมได้ ตัวอย่างเช่น ผู้โจมตีมีส่วนร่วมในการสร้างสคริปต์แบบหลายลายเซ็น (multisignature script) ซึ่งพวกเขาไม่จำเป็นต้องส่ง public key ของตนจนกว่าจะทราบ public key ของฝ่ายอื่นทั้งหมด ในกรณีนั้น ความแข็งแกร่งของอัลกอริทึมการแฮชจะลดลงเหลือรากที่สองของมัน สำหรับ HASH160 ความน่าจะเป็นจะกลายเป็น 1 ใน 2^80 นี่คือการโจมตีแบบ collision attack</p>
<p>เพื่อให้เข้าใจตัวเลขเหล่านี้ในบริบทที่ชัดเจน ข้อมูล ณ ต้นปี 2023 นักขุดบิตคอยน์ทั้งหมดรวมกันสามารถประมวลผลฟังก์ชันแฮชประมาณ 2^80 ทุกชั่วโมง พวกเขาใช้ฟังก์ชันแฮชที่แตกต่างจาก HASH160 ดังนั้นฮาร์ดแวร์ที่มีอยู่จึงไม่สามารถสร้างการโจมตีแบบ collision attack สำหรับมันได้ แต่การมีอยู่ของเครือข่ายบิตคอยน์พิสูจน์ว่าการโจมตีแบบชนกันต่อฟังก์ชัน 160 บิตอย่าง HASH160 สามารถทำได้จริงในทางปฏิบัติ นักขุดบิตคอยน์ได้ลงทุนเทียบเท่ากับหลายพันล้านดอลลาร์สหรัฐในฮาร์ดแวร์พิเศษ ดังนั้นการสร้างการโจมตีแบบ collision attack จึงไม่ใช่เรื่องถูก แต่มีองค์กรที่คาดหวังว่าจะได้รับบิตคอยน์มูลค่าหลายพันล้านดอลลาร์ไปยัง address ที่สร้างโดยกระบวนการที่เกี่ยวข้องกับหลายฝ่าย ซึ่งอาจทำให้การโจมตีนี้มีกำไร</p>
<p>มีโปรโตคอลการเข้ารหัสที่เป็นที่ยอมรับอย่างดีในการป้องกันการโจมตีแบบ collision attack แต่วิธีแก้ปัญหาที่ง่ายโดยไม่ต้องใช้ความรู้พิเศษจากผู้พัฒนากระเป๋าเงินคือการใช้ฟังก์ชันแฮชที่แข็งแกร่งกว่า การอัปเกรดบิตคอยน์ในภายหลังทำให้เป็นไปได้ และ address บิตคอยน์ใหม่ให้ความต้านทานการชนกันอย่างน้อย 128 บิต การดำเนินการแฮช 2^128 ครั้งจะใช้เวลานักขุดบิตคอยน์ปัจจุบันทั้งหมดประมาณ 32 พันล้านปี</p>
<p>แม้ว่าเราไม่เชื่อว่ามีภัยคุกคามเร่งด่วนต่อผู้ที่สร้าง address P2SH ใหม่ แต่เราแนะนำให้กระเป๋าเงินใหม่ทั้งหมดใช้ที่อยู่ประเภทใหม่เพื่อขจัดความกังวลเกี่ยวกับการโจมตีแบบ collision attack ของ P2SH address</p>
<h4>Bech32 Addresses</h4>
<p>ในปี 2017 โปรโตคอลบิตคอยน์ได้รับการอัปเกรด เพื่อป้องกันไม่ให้ตัวระบุธุรกรรม (txids) ไม่สามารถเปลี่ยนแปลงได้ โดยไม่ได้รับความยินยอมจากผู้ใช้ที่ทำการใช้จ่าย (หรือองค์ประชุมของผู้ลงนามเมื่อต้องมีลายเซ็นหลายรายการ) การอัปเกรดนี้เรียกว่า segregated witness (หรือเรียกสั้นๆ ว่า segwit) ซึ่งยังให้ความสามารถเพิ่มเติมสำหรับข้อมูลธุรกรรมในบล็อกและประโยชน์อื่น ๆ อีกหลายประการ แต่อย่างไรก็ตาม หากมีผู้ใช้เก่าที่ต้องการเข้าถึงประโยชน์ของ segwit โดยตรงต้องยอมรับการชำระเงินไปยังสคริปต์เอาต์พุตใหม่</p>
<p>ตามที่ได้กล่าวไว้ใน p2sh หนึ่งในข้อดีของเอาต์พุตประเภท P2SH คือผู้จ่ายไม่จำเป็นต้องรู้รายละเอียดของสคริปต์ที่ผู้รับใช้ การอัปเกรด segwit ถูกออกแบบมาให้ใช้กลไกนี้ได้ดังเดิม จึง ทำให้ผู้จ่ายสามารถเริ่มเข้าถึงประโยชน์ใหม่ ๆ หลายอย่างได้ทันทีโดยใช้ที่อยู่ P2SH แต่เพื่อให้ผู้รับสามารถเข้าถึงประโยชน์เหล่านั้นได้ พวกเขาจำเป็นจะต้องให้กระเป๋าเงินของผู้จ่ายจ่ายเงินให้เขาโดยใช้สคริปต์ประเภทอื่นแทน ซึ่งจะต้องอาศัยการอัปเกรดกระเป๋าเงินของผู้จ่ายเพื่อรองรับสคริปต์ใหม่เหล่านี้</p>
<p>ในช่วงแรก เหล่านักพัฒนาบิตคอยน์ได้นำเสนอ BIP142 ซึ่งจะยังคงใช้ base58check ร่วมกับไบต์เวอร์ชันใหม่ คล้ายกับการอัปเกรด P2SH แต่การให้กระเป๋าเงินทั้งหมดอัปเกรดไปใช้สคริปต์ใหม่ที่มีเวอร์ชัน base58check ใหม่นั้น คาดว่าจะต้องใช้ความพยายามเกือบเท่ากับการให้พวกเขาอัปเกรดไปใช้รูปแบบ address ที่เป็นแบบใหม่ทั้งหมด ด้วยเหตุนี้้เอง ผู้สนับสนุนบิตคอยน์หลายคนจึงเริ่มออกแบบรูปแบบ address ที่ดีที่สุดเท่าที่เป็นไปได้ พวกเขาระบุปัญหาหลายอย่างกับ base58check ไว้ดังนี้:</p>
<ul>
<li>การที่ base58check ใช้อักษรที่มีทั้งตัวพิมพ์ใหญ่และตัวพิมพ์เล็กทำให้ไม่สะดวกในการอ่านออกเสียงหรือคัดลอก ลองอ่าน address แบบเก่าในบทนี้ให้เพื่อนฟังและให้พวกเขาคัดลอก คุณจะสังเกตว่าคุณต้องระบุคำนำหน้าทุกตัวอักษรด้วยคำว่า "ตัวพิมพ์ใหญ่" และ "ตัวพิมพ์เล็ก" และเมื่อคุณตรวจสอบสิ่งที่พวกเขาเขียน คุณจะพบว่าตัวพิมพ์ใหญ่และตัวพิมพ์เล็กของตัวอักษรบางตัวอาจดูคล้ายกันในลายมือของคนส่วนใหญ่</li>
<li>รูปแบบนี้สามารถตรวจจับข้อผิดพลาดได้ แต่ไม่สามารถช่วยผู้ใช้แก้ไขข้อผิดพลาดเหล่านั้น ตัวอย่างเช่น หากคุณสลับตำแหน่งตัวอักษรสองตัวโดยไม่ตั้งใจเมื่อป้อน address ด้วยตนเอง กระเป๋าเงินของคุณจะเตือนว่ามีข้อผิดพลาดเกิดขึ้นแน่นอน แต่จะไม่ช่วยให้คุณค้นพบว่าข้อผิดพลาดอยู่ที่ไหน คุณอาจต้องใช้เวลาหลายนาทีที่น่าหงุดหงิดเพื่อค้นหาข้อผิดพลาดในที่สุด</li>
<li>การใช้ตัวอักษรที่มีทั้งตัวพิมพ์ใหญ่และตัวพิมพ์เล็กยังต้องใช้พื้นที่เพิ่มเติมในการเข้ารหัสใน QR code ซึ่งนิยมใช้ในการแชร์ address และ invoice ระหว่างกระเป๋าเงิน พื้นที่เพิ่มเติมนี้หมายความว่า QR code จำเป็นต้องมีขนาดใหญ่ขึ้นที่ความละเอียดเดียวกัน หรือไม่เช่นนั้นก็จะยากต่อการสแกนอย่างรวดเร็ว</li>
<li>การที่ต้องการให้กระเป๋าเงินผู้จ่ายทุกใบอัปเกรดเพื่อรองรับคุณสมบัติโปรโตคอลใหม่ เช่น P2SH และ segwit แม้ว่าการอัปเกรดเองอาจไม่ต้องใช้โค้ดมากนัก แต่ประสบการณ์แสดงให้เห็นว่าผู้พัฒนากระเป๋าเงินหลายรายมักยุ่งกับงานอื่น ๆ และบางครั้งอาจล่าช้าในการอัปเกรดเป็นเวลาหลายปี สิ่งนี้ส่งผลเสียต่อทุกคนที่ต้องการใช้คุณสมบัติใหม่ ๆ เหล่านี้</li>
</ul>
<p>นักพัฒนาที่ทำงานเกี่ยวกับรูปแบบ address สำหรับ segwit ได้พบวิธีแก้ปัญหาเหล่านี้ทั้งหมดในรูปแบบ address แบบใหม่ที่เรียกว่า bech32 (ออกเสียงด้วย "ch" อ่อน เช่นใน "เบช สามสิบสอง") คำว่า "bech" มาจาก BCH ซึ่งเป็นอักษรย่อของบุคคลสามคนที่ค้นพบรหัสวนนี้ในปี 1959 และ 1960 ซึ่งเป็นพื้นฐานของ bech32 ส่วน "32" หมายถึงจำนวนตัวอักษรในชุดตัวอักษร bech32 (คล้ายกับ 58 ใน base58check):</p>
<ul>
<li><p>Bech32 ใช้เฉพาะตัวเลขและตัวอักษรรูปแบบเดียว (โดยปกติจะแสดงเป็นตัวพิมพ์เล็ก) แม้ว่าชุดตัวอักษรของมันจะมีขนาดเกือบครึ่งหนึ่งของชุดตัวอักษรใน base58check ก็ตามแต่ address bech32 สำหรับสคริปต์ pay to witness public key hash (P2WPKH) ก็ยังยาวกว่า legacy address และมีขนาดเท่ากันกับสคริปต์ P2PKH </p>
</li>
<li><p>Bech32 สามารถทั้งตรวจจับและช่วยแก้ไขข้อผิดพลาดได้ ใน address ที่มีความยาวตามที่คาดหวังได้ และสามารถรับประกันทางคณิตศาสตร์ได้ว่าจะตรวจพบข้อผิดพลาดใด ๆ ที่ส่งผลกระทบต่อตัวอักษร 4 ตัวหรือน้อยกว่า ซึ่งเชื่อถือได้มากกว่า base58check ส่วนสำหรับข้อผิดพลาดที่ยาวกว่านั้น จะไม่สามารถตรวจพบได้ (โอกาสเกิดน้อยกว่าหนึ่งครั้งในหนึ่งพันล้าน) ซึ่งมีความเชื่อถือได้ประมาณเท่ากับ base58check ยิ่งไปกว่านั้น สำหรับ adddress ที่พิมพ์โดยมีข้อผิดพลาดเพียงเล็กน้อย มันสามารถบอกผู้ใช้ได้ว่าข้อผิดพลาดเหล่านั้นเกิดขึ้นที่ไหน ช่วยให้พวกเขาสามารถแก้ไขข้อผิดพลาดจากการคัดลอกเล็ก ๆ น้อย ๆ ได้อย่างรวดเร็ว </p>
</li>
<li><p>ตัวอย่างที่ 3 Bech32 address ที่มีข้อผิดพลาด<br>Address: bc1p9nh05ha8wrljf7ru236awn4t2x0d5ctkkywmv9sclnm4t0av2vgs4k3au7<br>ข้อผิดพลาดที่ตรวจพบแสดงเป็นตัวหนาและขีดเส้นใต้ สร้างโดยใช้โปรแกรมสาธิตการถอดรหัส  bech32 address</p>
</li>
<li><p>bech32 address นิยมเขียนด้วยตัวอักษรพิมพ์เล็กเท่านั้น แต่ตัวอักษรพิมพ์เล็กเหล่านี้สามารถแทนที่ด้วยตัวอักษรพิมพ์ใหญ่ก่อนการเข้ารหัส address ในรหัส QR ได้ วิธีนี้ช่วยให้สามารถใช้โหมดการเข้ารหัส QR แบบพิเศษที่ใช้พื้นที่น้อยกว่า คุณจะสังเกตเห็นความแตกต่างในขนาดและความซับซ้อนของรหัส QR ทั้งสองสำหรับที่อยู่เดียวกันในรูปภาพข้างล่างนี้</p>
</li>
</ul>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0409.png" alt="image"></p>
<ul>
<li>Bech32 ใช้ประโยชน์จากกลไกการอัปเกรดที่ออกแบบมาเป็นส่วนหนึ่งของ segwit เพื่อทำให้กระเป๋าเงินผู้จ่ายสามารถจ่ายเงินไปยังประเภทเอาต์พุตที่ยังไม่ได้ใช้งานได้ โดยมีเป้าหมายคือการอนุญาตให้นักพัฒนาสร้างกระเป๋าเงินในวันนี้ที่สามารถใช้จ่ายไปยัง bech32 address และทำให้กระเป๋าเงินนั้นยังคงสามารถใช้จ่ายไปยัง bech32address ได้สำหรับผู้ใช้คุณสมบัติใหม่ที่เพิ่มในการอัปเกรดโปรโตคอลในอนาคต โดยที่มีความหวังว่าเราอาจไม่จำเป็นต้องผ่านรอบการอัปเกรดทั้งระบบอีกต่อไป ซึ่งจำเป็นสำหรับการให้ผู้คนใช้งาน P2SH และ segwit ได้อย่างเต็มรูปแบบ</li>
<li></li>
<li><h4>Problems with Bech32 Addresses</h4>
</li>
</ul>
<p>address แบบ bech32 ประสบความสำเร็จในทุกด้านยกเว้นปัญหาหนึ่ง คือการรับประกันทางคณิตศาสตร์เกี่ยวกับความสามารถในการตรวจจับข้อผิดพลาดจะใช้ได้เฉพาะเมื่อความยาวของ address ที่คุณป้อนเข้าไปในกระเป๋าเงินมีความยาวเท่ากับ address ดั้งเดิมเท่านั้น หากคุณเพิ่มหรือลบตัวอักษรใด ๆ ระหว่างการคัดลอกจะทำให้ไม่สามารถตรวจจับได้ การรับประกันนี้จะไม่มีผล และกระเป๋าเงินของคุณอาจใช้จ่ายเงินไปยัง address ที่ไม่ถูกต้อง แต่อย่างไรก็ตาม แม้จะไม่มีคุณสมบัตินี้ มีความเชื่อว่าเป็นไปได้ยากมากที่ผู้ใช้ที่เพิ่มหรือลบตัวอักษรจะสร้างสตริงที่มีผลรวมตรวจสอบที่ถูกต้อง ซึ่งช่วยให้มั่นใจได้ว่าเงินของผู้ใช้จะปลอดภัย</p>
<p>น่าเสียดายที่การเลือกใช้ค่าคงที่ตัวหนึ่งในอัลกอริทึม bech32 บังเอิญทำให้การเพิ่มหรือลบตัวอักษร "q" ในตำแหน่งที่สองจากท้ายของ address ที่ลงท้ายด้วยตัวอักษร "p" เป็นเรื่องง่ายมาก ในกรณีเหล่านั้น คุณยังสามารถเพิ่มหรือลบตัวอักษร "q" หลายครั้งได้ด้วย ข้อผิดพลาดนี้จะถูกตรวจจับโดยผลรวมตรวจสอบ (checksum) ในบางครั้ง แต่จะถูกมองข้ามบ่อยกว่าความคาดหวังหนึ่งในพันล้านสำหรับข้อผิดพลาดจากการแทนที่ของ bech32 อย่างมาก สำหรับตัวอย่างสามารถดูได้ในรูปภาพข้างล่างนี้</p>
<p>ตัวอย่างที่ 4. การขยายความยาวของ bech32 address โดยไม่ทำให้ผลรวมตรวจสอบเป็นโมฆะ</p>
<pre><code>bech32 address ที่ถูกต้อง:
bc1pqqqsq9txsqp

address ที่ไม่ถูกต้องแต่มีผลรวมตรวจสอบที่ถูกต้อง:
bc1pqqqsq9txsqqqqp
bc1pqqqsq9txsqqqqqqp
bc1pqqqsq9txsqqqqqqqqp
bc1pqqqsq9txsqqqqqqqqqp
bc1pqqqsq9txsqqqqqqqqqqqp
</code></pre>
<p>จากตัวอย่างนี้ คุณจะเห็นว่าแม้มีการเพิ่มตัวอักษร "q" เข้าไปหลายตัวก่อนตัวอักษร "p" ตัวสุดท้าย ระบบตรวจสอบก็ยังคงยอมรับว่า address เหล่านี้ถูกต้อง นี่เป็นข้อบกพร่องสำคัญของ bech32 เพราะอาจทำให้เงินถูกส่งไปยัง address ที่ไม่มีใครเป็นเจ้าของจริง ๆ หรือ address ที่ไม่ได้ตั้งใจจะส่งไป</p>
<p>สำหรับเวอร์ชันเริ่มต้นของ segwit (เวอร์ชัน 0) ปัญหานี้ไม่ใช่ความกังวลในทางปฏิบัติ เพราะมีความยาวที่ถูกต้องมีเพียงสองแบบที่กำหนดไว้สำหรับเอาต์พุต นั้นคือ 22 Byte และ 34 Byte ซึ่งสอดคล้องกับ bech32 address ที่มีความยาวยาวที่ 42 หรือ 62 ตัวอักษร ดังนั้นคนจะต้องเพิ่มหรือลบตัวอักษร "q" จากตำแหน่งที่สองจากท้ายของ bech32 address ถึง 20 ครั้งเพื่อส่งเงินไปยัง address ที่ไม่ถูกต้องโดยที่กระเป๋าเงินไม่สามารถตรวจจับได้ อย่างไรก็ตาม มันอาจกลายเป็นปัญหาสำหรับผู้ใช้ในอนาคตหากมีการนำการอัปเกรดบนพื้นฐานของ segwit มาใช้</p>
<h4>Bech32m</h4>
<p>แม้ว่า bech32 จะทำงานได้ดีสำหรับ segwit v0 แต่นักพัฒนาไม่ต้องการจำกัดขนาดเอาต์พุตโดยไม่จำเป็นในเวอร์ชันหลังๆ ของ segwit หากไม่มีข้อจำกัด การเพิ่มหรือลบตัวอักษร "q" เพียงตัวเดียวใน bech32 address อาจทำให้ผู้ใช้ส่งเงินโดยไม่ตั้งใจไปยังเอาต์พุตที่ไม่สามารถใช้จ่ายได้หรือสามารถใช้จ่ายได้โดยทุกคน (ทำให้บิตคอยน์เหล่านั้นถูกนำไปโดยทุกคนได้) นักพัฒนาได้วิเคราะห์ปัญหา bech32 อย่างละเอียดและพบว่าการเปลี่ยนค่าคงที่เพียงตัวเดียวในอัลกอริทึมของพวกเขาจะขจัดปัญหานี้ได้ ทำให้มั่นใจว่าการแทรกหรือลบตัวอักษรสูงสุดห้าตัวจะไม่ถูกตรวจจับน้อยกว่าหนึ่งครั้งในหนึ่งพันล้านเท่านั้น</p>
<p>เวอร์ชันของ bech32 ที่มีค่าคงที่เพียงหนึ่งตัวที่แตกต่างกันเรียกว่า bech32 แบบปรับแต่ง (bech32m) ตัวอักษรทั้งหมดใน address แบบ bech32 และ bech32m สำหรับข้อมูลพื้นฐานเดียวกันจะเหมือนกันทั้งหมด ยกเว้นหกตัวสุดท้าย (ซึ่งเป็นส่วนของ checksum) นั่นหมายความว่ากระเป๋าเงินจำเป็นต้องรู้ว่ากำลังใช้เวอร์ชันใดเพื่อตรวจสอบความถูกต้องของ checksum แต่ address ทั้งสองประเภทมีไบต์เวอร์ชันภายในที่ทำให้การระบุเวอร์ชันที่ใช้อยู่เป็นเรื่องที่ง่าย<br>ในการทำงานกับทั้ง bech32 และ bech32m เราจะพิจารณากฎการเข้ารหัสและการแยกวิเคราะห์สำหรับ address บิตคอยน์แบบ bech32m เนื่องจากพวกมันครอบคลุมความสามารถในการแยกวิเคราะห์บน address แบบ bech32 และเป็นรูปแบบ address ที่แนะนำในปัจจุบันสำหรับกระเป๋าเงินบิตคอยน์</p>
<blockquote>
<p>ข้อความจากหลาม: คือผมว่าตรงนี้เขาเขียนไม่รู้เรื่อง แต่เดาว่าเขาน่าจะสื่อว่า เราควรเรียนรู้วิธีการทำงานกับ bech32m เพราะมันเป็นรูปแบบที่แนะนำให้ใช้ในปัจจุบัน และมันมีข้อดีเพราะbech32m สามารถรองรับการอ่าน address แบบ bech32 แบบเก่าได้ด้วย ง่ายๆ คือ ถ้าคุณเรียนรู้วิธีทำงานกับ bech32m คุณจะสามารถทำงานกับทั้ง bech32m และ bech32 ได้ทั้งสองแบบ</p>
</blockquote>
<p>bech32m address ริ่มต้นด้วยส่วนที่มนุษย์อ่านได้ (Human Readable Part: HRP) BIP173 มีกฎสำหรับการสร้าง HRP ของคุณเอง แต่สำหรับบิตคอยน์ คุณเพียงแค่จำเป็นต้องรู้จัก HRP ที่ถูกเลือกไว้แล้วตามที่แสดงในตารางข้างล่างนี้</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641071606-YAKIHONNES3.png" alt="image"></p>
<p>ส่วน HRP ตามด้วยตัวคั่น ซึ่งก็คือเลข "1" ในข้อเสนอก่อนหน้านี้สำหรับตัวคั่นโปรโตคอลได้ใช้เครื่องหมายทวิภาค (colon) แต่ระบบปฏิบัติการและแอปพลิเคชันบางตัวที่อนุญาตให้ผู้ใช้ดับเบิลคลิกคำเพื่อไฮไลต์สำหรับการคัดลอกและวางนั้นจะไม่ขยายการไฮไลต์ไปถึงและผ่านเครื่องหมายทวิภาค</p>
<p>การใช้ตัวเลขช่วยให้มั่นใจได้ว่าการไฮไลต์ด้วยดับเบิลคลิกจะทำงานได้กับโปรแกรมใดๆ ที่รองรับสตริง bech32m โดยทั่วไป (ซึ่งรวมถึงตัวเลขอื่นๆ ด้วย) เลข "1" ถูกเลือกเพราะสตริง bech32 ไม่ได้ใช้เลข 1 ในกรณีอื่น เพื่อป้องกันการแปลงโดยไม่ตั้งใจระหว่างเลข "1" กับตัวอักษรพิมพ์เล็ก "l"</p>
<p>และส่วนอื่นของ bech32m address เรียกว่า "ส่วนข้อมูล" (data part) ซึ่งประกอบด้วยสามองค์ประกอบ:</p>
<ul>
<li><strong>Witness version:</strong> ไบต์ถัดไปหลังจากตัวคั่นตัวอักษรนี้แทนเวอร์ชันของ segwit ตัวอักษร "q" คือการเข้ารหัสของ "0" สำหรับ segwit v0 ซึ่งเป็นเวอร์ชันแรกของ segwit ที่มีการแนะนำที่อยู่ bech32 ตัวอักษร "p" คือการเข้ารหัสของ "1" สำหรับ segwit v1 (หรือเรียกว่า taproot) ซึ่งเริ่มมีการใช้งาน bech32m มีเวอร์ชันที่เป็นไปได้ทั้งหมด 17 เวอร์ชันของ segwit และสำหรับ Bitcoin จำเป็นต้องให้ไบต์แรกของส่วนข้อมูล bech32m ถอดรหัสเป็นตัวเลข 0 ถึง 16 (รวมทั้งสองค่า)</li>
<li><strong>Witness program:</strong> คือตำแหน่งหลังจาก witnessversion ตั้งแต่ตำแหน่ง 2 ถึง 40 Byte สำหรับ segwit v0 นี้ต้องมีความยาว 20 หรือ 32 Byte ไม่สามารถ<br>ffมีขนาดอื่นได้ สำหรับ segwit v1 ความยาวเดียวที่ถูกกำหนดไว้ ณ เวลาที่เขียนนี้คือ 32 ไบต์ แต่อาจมีการกำหนดความยาวอื่น ๆ ได้ในภายหลัง</li>
<li><strong>Checksum:</strong> มีความยาว 6 ตัวอักษร โดยส่วนนี้ถูกสร้างขึ้นโดยใช้รหัส BCH ซึ่งเป็นประเภทของรหัสแก้ไขข้อผิดพลาด (error corection code) (แต่อย่างไรก็ตาม สำหรับ address บิตคอยน์ เราจะเห็นในภายหลังว่าเป็นสิ่งสำคัญที่จะใช้ checksum เพื่อการตรวจจับข้อผิดพลาดเท่านั้น—ไม่ใช่การแก้ไข</li>
</ul>
<p>ในส่วนต่อไปหลังจากนี้เราจะลองสร้าง address แบบ bech32 และ bech32m สำหรับตัวอย่างทั้งหมดต่อไปนี้ เราจะใช้โค้ดอ้างอิง bech32m สำหรับ Python</p>
<p>เราจะเริ่มด้วยการสร้างสคริปต์เอาต์พุตสี่ตัว หนึ่งตัวสำหรับแต่ละเอาต์พุต segwit ที่แตกต่างกันที่ใช้ในช่วงเวลาของการเผยแพร่ บวกกับอีกหนึ่งตัวสำหรับเวอร์ชัน segwit ในอนาคตที่ยังไม่มีความหมายที่กำหนดไว้ สคริปต์เหล่านี้แสดงอยู่ในตารางข้างล่างนี้<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641245046-YAKIHONNES3.png" alt="image"></p>
<p>สำหรับเอาต์พุต P2WPKH witness program มีการผูก commitment ที่สร้างขึ้นในลักษณะเดียวกันกับ P2PKH ที่เห็นใน Legacy Addresses for P2PKH โดย public key ถูกส่งเข้าไปในฟังก์ชันแฮช SHA256 ไดเจสต์ขนาด 32 ไบต์ที่ได้จะถูกส่งเข้าไปในฟังก์ชันแฮช RIPEMD-160 ไดเจสต์ของฟังก์ชันนั้น จะถูกวางไว้ใน witness program</p>
<p>สำหรับเอาต์พุตแบบ pay to witness script hash (P2WSH) เราไม่ได้ใช้อัลกอริทึม P2SH แต่เราจะนำสคริปต์ ส่งเข้าไปในฟังก์ชันแฮช SHA256 และใช้ไดเจสต์ขนาด 32 ไบต์ของฟังก์ชันนั้นใน witness program สำหรับ P2SH ไดเจสต์ SHA256 จะถูกแฮชอีกครั้งด้วย RIPEMD-160 ซึ่งแน่นอนว่าอาจจะไม่ปลอดภัย ในบางกรณี สำหรับรายละเอียด ดูที่ P2SH Collision Attacks ผลลัพธ์ของการใช้ SHA256 โดยไม่มี RIPEMD-160 คือ การผูกพันแบบ P2WSH มีขนาด 32 ไบต์ (256 บิต) แทนที่จะเป็น 20 ไบต์ (160 บิต)</p>
<p>สำหรับเอาต์พุตแบบ pay-to-taproot (P2TR) witness program คือจุดบนเส้นโค้ง secp256k1 มันอาจเป็น public key แบบธรรมดา แต่ในกรณีส่วนใหญ่มันควรเป็น public key ที่ผูกพันกับข้อมูลเพิ่มเติมบางอย่าง เราจะเรียนรู้เพิ่มเติมเกี่ยวกับการผูกพันนั้นในหัวข้อของ taproot</p>
<p>สำหรับตัวอย่างของเวอร์ชัน segwit ในอนาคต เราเพียงแค่ใช้หมายเลขเวอร์ชัน segwit ที่สูงที่สุดที่เป็นไปได้ (16) และ witness program ที่มีขนาดเล็กที่สุดที่อนุญาต (2 ไบต์) โดยมีค่าเป็นศูนย์ (null value)</p>
<p>เมื่อเรารู้หมายเลขเวอร์ชันและ witness program แล้ว เราสามารถแปลงแต่ละอย่างให้เป็น bech32 address ได้ โดยการใช้ไลบรารีอ้างอิง bech32m สำหรับ Python เพื่อสร้าง address เหล่านั้นอย่างรวดเร็ว และจากนั้นมาดูอย่างละเอียดว่าเกิดอะไรขึ้น:</p>
<pre><code>$ github=" https://raw.githubusercontent.com"
$ wget $github/sipa/bech32/master/ref/python/segwit_addr.py
$ python
&gt;&gt;&gt; from segwit_addr import *
&gt;&gt;&gt; from binascii import unhexlify
&gt;&gt;&gt; help(encode)
encode(hrp, witver, witprog)
    Encode a segwit address.
&gt;&gt;&gt; encode('bc', 0, unhexlify('2b626ed108ad00a944bb2922a309844611d25468'))
'bc1q9d3xa5gg45q2j39m9y32xzvygcgay4rgc6aaee'
&gt;&gt;&gt; encode('bc', 0,
unhexlify('648a32e50b6fb7c5233b228f60a6a2ca4158400268844c4bc295ed5e8c3d626f'))
'bc1qvj9r9egtd7mu2gemy28kpf4zefq4ssqzdzzycj7zjhk4arpavfhsct5a3p'
&gt;&gt;&gt; encode('bc', 1,
unhexlify('2ceefa5fa770ff24f87c5475d76eab519eda6176b11dbe1618fcf755bfac5311'))
'bc1p9nh05ha8wrljf7ru236awm4t2x0d5ctkkywmu9sclnm4t0av2vgs4k3au7'
&gt;&gt;&gt; encode('bc', 16, unhexlify('0000'))
'bc1sqqqqkfw08p'
</code></pre>
<p>หากเราเปิดไฟล์ segwit_addr.py และดูว่าโค้ดกำลังทำอะไร สิ่งแรกที่เราจะสังเกตเห็นคือความแตกต่างเพียงอย่างเดียวระหว่าง bech32 (ที่ใช้สำหรับ segwit v0) และ bech32m (ที่ใช้สำหรับเวอร์ชัน segwit รุ่นหลัง) คือค่าคงที่:</p>
<pre><code>BECH32_CONSTANT = 1
BECH32M_CONSTANT = 0x2bc830a3
</code></pre>
<p>และในส่วนต่อไป เราจะเห็นโค้ดที่สร้าง checksum ในขั้นตอนสุดท้ายของการสร้าง checksum ค่าคงที่ที่เหมาะสมถูกรวมเข้ากับข้อมูลอื่น ๆ โดยใช้การดำเนินการ xor ค่าเดียวนั้นคือความแตกต่างเพียงอย่างเดียวระหว่าง bech32 และ bech32m</p>
<p>เมื่อสร้าง checksum แล้ว อักขระ 5 บิตแต่ละตัวในส่วนข้อมูล (รวมถึง witness version, witness program และ checksum) จะถูกแปลงเป็นตัวอักษรและตัวเลข</p>
<p>สำหรับการถอดรหัสกลับเป็นสคริปต์เอาต์พุต เราทำงานย้อนกลับ ลองใช้ไลบรารีอ้างอิงเพื่อถอดรหัส address สอง address ของเรา:</p>
<pre><code>&gt;&gt;&gt; help(decode)
decode(hrp, addr)
    Decode a segwit address.
&gt;&gt;&gt; _ = decode("bc", "bc1q9d3xa5gg45q2j39m9y32xzvygcgay4rgc6aaee")
&gt;&gt;&gt;  _[0], bytes(_[1]).hex()
(0, '2b626ed108ad00a944bb2922a309844611d25468')
&gt;&gt;&gt; _ = decode("bc",
        "bc1p9nh05ha8wrljf7ru236awm4t2x0d5ctkkywmu9sclnm4t0av2vgs4k3au7")
&gt;&gt;&gt; _[0], bytes(_[1]).hex()
(1, '2ceefa5fa770ff24f87c5475d76eab519eda6176b11dbe1618fcf755bfac5311')
</code></pre>
<p>เราได้รับทั้ง witness version และ witness program กลับมา สิ่งเหล่านี้สามารถแทรกลงในเทมเพลตสำหรับสคริปต์เอาต์พุตของเรา:</p>
<pre><code>&lt;version&gt; &lt;program&gt;
</code></pre>
<p>ตัวอย่างเช่น:</p>
<pre><code>OP_0 2b626ed108ad00a944bb2922a309844611d25468
OP_1 2ceefa5fa770ff24f87c5475d76eab519eda6176b11dbe1618fcf755bfac5311
</code></pre>
<blockquote>
<p>คำเตือน: ข้อผิดพลาดที่อาจเกิดขึ้นที่ควรระวังคือ witness version ที่มีค่า 0 ใช้สำหรับ OP_0 ซึ่งใช้ไบต์ 0x00—แต่เวอร์ชัน witness ที่มีค่า 1 ใช้ OP_1 ซึ่งเป็นไบต์ 0x51 เวอร์ชัน witness 2 ถึง 16 ใช้ไบต์ 0x52 ถึง 0x60 ตามลำดับ</p>
</blockquote>
<p>เมื่อทำการเขียนโค้ดเพื่อเข้ารหัสหรือถอดรหัส bech32m เราขอแนะนำอย่างยิ่งให้คุณใช้เวกเตอร์ทดสอบ (test vectors) ที่มีให้ใน BIP350 เราขอให้คุณตรวจสอบให้แน่ใจว่าโค้ดของคุณผ่านเวกเตอร์ทดสอบที่เกี่ยวข้องกับการจ่ายเงินให้กับเวอร์ชัน segwit ในอนาคตที่ยังไม่ได้รับการกำหนด สิ่งนี้จะช่วยให้ซอฟต์แวร์ของคุณสามารถใช้งานได้อีกหลายปีข้างหน้า แม้ว่าคุณอาจจะไม่สามารถเพิ่มการรองรับคุณสมบัติใหม่ ๆ ของบิตคอยน์ได้ทันทีที่คุณสมบัตินั้น ๆ เริ่มใช้งานได้</p>
<h3>Private Key Formats</h3>
<p>private key สามารถถูกแสดงได้ในหลาย ๆ รูปแบบที่ต่างกันซึ่งสามารถแปลงเป็นตัวเลขขนาด 256 bit ชุดเดียวกันได้ ดังที่เราจะแสดงให้ดูในตารางข้างล่างนี้ รูปแบบที่แตกต่างกันถูกใช้ในสถานการณ์ที่ต่างกัน รูปแบบเลขฐานสิบหก (Hexadecimal) และรูปแบบไบนารี (raw binary) ถูกใช้ภายในซอฟต์แวร์และแทบจะไม่แสดงให้ผู้ใช้เห็น WIF ถูกใช้สำหรับการนำเข้า/ส่งออกกุญแจระหว่างกระเป๋าเงินและมักใช้ในการแสดงกุญแจส่วนตัวแบบ QR code</p>
<h4>รูปแบบของ private key ในปัจจุบัน</h4>
<p>ซอฟต์แวร์กระเป๋าเงินบิตคอยน์ในยุคแรกได้สร้าง private key อิสระอย่างน้อยหนึ่งดอกเมื่อกระเป๋าเงินของผู้ใช้ใหม่ถูกเริ่มต้น เมื่อชุดกุญแจเริ่มต้นถูกใช้ทั้งหมดแล้ว กระเป๋าเงินอาจสร้าง private key เพิ่มเติม  private key แต่ละดอกสามารถส่งออกหรือนำเข้าได้ ทุกครั้งที่มีการสร้างหรือนำเข้า private key ใหม่ จะต้องมีการสร้างการสำรองข้อมูลกระเป๋าเงินใหม่ด้วย</p>
<p>กระเป๋าเงินบิตคอยน์ในยุคหลังเริ่มใช้กระเป๋าเงินแบบกำหนดได้ (deterministic wallets) ซึ่ง private key ทั้งหมดถูกสร้างจาก seed เพียงค่าเดียว กระเป๋าเงินเหล่านี้จำเป็นต้องสำรองข้อมูลเพียงครั้งเดียวเท่านั้นสำหรับการใช้งานบนเชนทั่วไป แต่อย่างไรก็ตาม หากผู้ใช้ส่งออก private key เพียงดอกเดียวจากกระเป๋าเงินเหล่านี้ และผู้โจมตีได้รับกุญแจนั้นรวมถึงข้อมูลที่ไม่ใช่ข้อมูลส่วนตัวบางอย่างเกี่ยวกับกระเป๋าเงิน พวกเขาอาจสามารถสร้างกุญแจส่วนตัวใด ๆ ในกระเป๋าเงินได้—ทำให้ผู้โจมตีสามารถขโมยเงินทั้งหมดในกระเป๋าเงินได้ นอกจากนี้ ยังไม่สามารถนำเข้ากุญแจสู่กระเป๋าเงินแบบกำหนดได้ นี่หมายความว่าแทบไม่มีกระเป๋าเงินสมัยใหม่ที่รองรับความสามารถในการส่งออกหรือนำเข้ากุญแจเฉพาะดอก ข้อมูลในส่วนนี้มีความสำคัญหลัก ๆ สำหรับผู้ที่ต้องการความเข้ากันได้กับกระเป๋าเงินบิตคอยน์ในยุคแรก ๆ</p>
<p>รูปแบบของ private key (รูปแบบการเข้ารหัส)<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641438678-YAKIHONNES3.png" alt="image"><br>private key เดียวกันในแต่ละ format<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641472205-YAKIHONNES3.png" alt="image"><br>รูปแบบการแสดงผลทั้งหมดเหล่านี้เป็นวิธีต่างๆ ในการแสดงเลขจำนวนเดียวกัน private key เดียวกัน พวกมันดูแตกต่างกัน แต่รูปแบบใดรูปแบบหนึ่งสามารถแปลงไปเป็นรูปแบบอื่นได้อย่างง่ายดาย</p>
<h3>Compressed Private Keys</h3>
<p>คำว่า compressed private key ที่ใช้กันทั่วไปนั้นเป็นคำที่เรียกผิด เพราะเมื่อ private key ถูกส่งออกไปในรูปแบบ WIF-compressed มันจะมีความยาวมากกว่า private key แบบ uncompressed 1 Byte (เลข 01 ในช่อง Hex-compressed ในตารางด้านล่างนี้) ซึ่งบ่งบอกว่า private key ตัวนี้ มาจากกระเป๋าเงินรุ่นใหม่และควรใช้เพื่อสร้าง compressed public key เท่านั้น</p>
<p>private key เองไม่ได้ถูกบีบอัดและไม่สามารถบีบอัดได้ คำว่า compressed private key จริงๆ แล้วหมายถึง " private key ซึ่งควรใช้สร้าง compressed public key เท่านั้น" ในขณะที่ uncompressed private key จริงๆ แล้วหมายถึง “private key ซึ่งควรใช้สร้าง uncompressed public key เท่านั้น” คุณควรใช้เพื่ออ้างถึงรูปแบบการส่งออกเป็น "WIF-compressed" หรือ "WIF" เท่านั้น และไม่ควรอ้างถึง private key ว่า "บีบอัด" เพื่อหลีกเลี่ยงความสับสนต่อไป</p>
<p>ตารางนี้แสดงกุญแจเดียวกันที่ถูกเข้ารหัสในรูปแบบ WIF และ WIF-compressed</p>
<p>ตัวอย่าง: กุญแจเดียวกัน แต่รูปแบบต่างกัน<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641542538-YAKIHONNES3.png" alt="image"></p>
<p>สังเกตว่ารูปแบบ Hex-compressed มีไบต์เพิ่มเติมหนึ่งไบต์ที่ท้าย (01 ในเลขฐานสิบหก) ในขณะที่คำนำหน้าเวอร์ชันการเข้ารหัสแบบ base58 เป็นค่าเดียวกัน (0x80) สำหรับทั้งรูปแบบ WIF และ WIF-compressed การเพิ่มหนึ่งไบต์ที่ท้ายของตัวเลขทำให้อักขระตัวแรกของการเข้ารหัสแบบ base58 เปลี่ยนจาก 5 เป็น K หรือ L</p>
<p>คุณสามารถคิดถึงสิ่งนี้เหมือนกับความแตกต่างของการเข้ารหัสเลขฐานสิบระหว่างตัวเลข 100 และตัวเลข 99 ในขณะที่ 100 มีความยาวมากกว่า 99 หนึ่งหลัก มันยังมีคำนำหน้าเป็น 1 แทนที่จะเป็นคำนำหน้า 9 เมื่อความยาวเปลี่ยนไป มันส่งผลต่อคำนำหน้า ในระบบ base58 คำนำหน้า 5 เปลี่ยนเป็น K หรือ L เมื่อความยาวของตัวเลขเพิ่มขึ้นหนึ่งไบต์</p>
<blockquote>
<p>TIPจากหลาม: ผมว่าเขาเขียนย่อหน้านี้ไม่ค่อยรู้เรื่อง แต่ความหมายมันจะประมาณว่า เหมือนถ้าเราต้องการเขียนเลข 100 ในฐาน 10 เราต้องใช้สามตำแหน่ง 100 แต่ถ้าใช้ฐาน 16 เราจะใช้แค่ 2 ตำแหน่งคือ 64 ซึ่งมีค่าเท่ากัน</p>
</blockquote>
<p>ถ้ากระเป๋าเงินบิตคอยน์สามารถใช้ compressed public key ได้ มันจะใช้ในทุกธุรกรรม private key ในกระเป๋าเงินจะถูกใช้เพื่อสร้างจุด public key บนเส้นโค้ง ซึ่งจะถูกบีบอัด compressed public key จะถูกใช้เพื่อสร้าง address และ address เหล่านี้จะถูกใช้ในธุรกรรม เมื่อส่งออก private key จากกระเป๋าเงินใหม่ที่ใช้ compressed public key WIF จะถูกปรับเปลี่ยน โดยเพิ่มต่อท้ายขนาด 1 ไบต์ 01 ให้กับ private key ที่ถูกเข้ารหัสแบบ base58check ที่ได้จะเรียกว่า "WIF-compressed" และจะขึ้นต้นด้วยอักษร K หรือ L แทนที่จะขึ้นต้นด้วย "5" เหมือนกับกรณีของคีย์ที่เข้ารหัสแบบ WIF (ไม่บีบอัด) จากกระเป๋าเงินรุ่นเก่า</p>
<h3>Advanced Keys and Addresses</h3>
<p>ในส่วนต่อไปนี้ เราจะดูรูปแบบของคีย์และ address เช่น vanity addresses และ paper wallets </p>
<h4>vanity addresses</h4>
<p>vanity addresses หรือ addresses แบบกำหนดเอง คือ address ที่มีข้อความที่มนุษย์อ่านได้และสามารถใช้งานได้จริง ตัวอย่างเช่น 1LoveBPzzD72PUXLzCkYAtGFYmK5vYNR33 อย่างที่เห็นว่ามันเป็น address ที่ถูกต้องซึ่งมีตัวอักษรเป็นคำว่า Love เป็นตัวอักษร base58 สี่ตัวแรก addresses แบบกำหนดเองต้องอาศัยการสร้างและทดสอบ private key หลายพันล้านตัวจนกว่าจะพบ address ที่มีรูปแบบตามที่ต้องการ แม้ว่าจะมีการปรับปรุงบางอย่างในอัลกอริทึมการสร้าง addresses แบบกำหนดเอง แต่กระบวนการนี้ต้องใช้การสุ่มเลือก private key มาสร้าง public key และนำไปสร้าง address และตรวจสอบว่าตรงกับรูปแบบที่ต้องการหรือไม่ โดยทำซ้ำหลายพันล้านครั้งจนกว่าจะพบที่ตรงกัน</p>
<p>เมื่อพบ  address ที่ตรงกับรูปแบบที่ต้องการแล้ว  private key ที่ใช้สร้าง address นั้นสามารถใช้โดยเจ้าของเพื่อใช้จ่ายบิตคอยน์ได้เหมือนกับ address อื่น ๆ ทุกประการ address ที่กำหนดเองไม่ได้มีความปลอดภัยน้อยกว่าหรือมากกว่าที่ address ๆ พวกมันขึ้นอยู่กับการเข้ารหัสเส้นโค้งรูปวงรี (ECC) และอัลกอริทึมแฮชที่ปลอดภัย (SHA) เหมือนกับ address อื่น ๆ คุณไม่สามารถค้นหา private key ของ address ที่ขึ้นต้นด้วยรูปแบบที่กำหนดเองได้ง่ายกว่า address อื่น ๆ</p>
<p>ตัวอย่างเช่น ยูจีเนียเป็นผู้อำนวยการการกุศลเพื่อเด็กที่ทำงานในฟิลิปปินส์ สมมติว่ายูจีเนียกำลังจัดการระดมทุนและต้องการใช้ address ที่กำหนดเองเพื่อประชาสัมพันธ์การระดมทุน ยูจีเนียจะสร้าง address ที่กำหนดเองที่ขึ้นต้นด้วย "1Kids" เพื่อส่งเสริมการระดมทุนเพื่อการกุศลสำหรับเด็ก มาดูกันว่า address ที่กำหนดเองนี้จะถูกสร้างขึ้นอย่างไรและมีความหมายอย่างไรต่อความปลอดภัยของการกุศลของยูจีเนีย</p>
<h4>การสร้าง address ที่กำหนดเอง</h4>
<p>ควรเข้าใจว่า address ของบิตคอยน์เป็นเพียงตัวเลขที่แสดงด้วยสัญลักษณ์ในรูปแบบตัวอักษร base58 เท่านั้น เพราะฉะนั้นแล้ว การค้นหารูปแบบเช่น "1Kids" สามารถมองได้ว่าเป็นการค้นหาที่อยู่ในช่วงตั้งแต่ 1Kids11111111111111111111111111111 ถึง 1Kidszzzzzzzzzzzzzzzzzzzzzzzzzzzzz มีประมาณ 5829 (ประมาณ 1.4 × 1051) address ในช่วงนั้น ทั้งหมดขึ้นต้นด้วย "1Kids" ตารางด้านล่างนี้แสดงช่วงของ address ที่มีคำนำหน้า 1Kids<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641701955-YAKIHONNES3.png" alt="image">ลองดูรูปแบบ "1Kids" ในรูปของตัวเลขและดูว่าเราอาจพบรูปแบบนี้ใน bitcoin address บ่อยแค่ไหน โดยตารางข้างล่างนี้แสดงให้เห็นถีงคอมพิวเตอร์เดสก์ท็อปทั่วไปที่ไม่มีฮาร์ดแวร์พิเศษสามารถค้นหาคีย์ได้ประมาณ 100,000 คีย์ต่อวินาที</p>
<p>ความถี่ของ address ที่กำหนดเอง (1KidsCharity) และเวลาค้นหาเฉลี่ยบนคอมพิวเตอร์เดสก์ท็อป</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641750817-YAKIHONNES3.png" alt="image"></p>
<p>ดังที่เห็นได้ ยูจีเนียคงไม่สามารถสร้าง address แบบกำหนดเอง "1KidsCharity" ได้ในเร็ว ๆ นี้ แม้ว่าเธอจะมีคอมพิวเตอร์หลายพันเครื่องก็ตาม ทุกตัวอักษรที่เพิ่มขึ้นจะเพิ่มความยากขึ้น 58 เท่า รูปแบบที่มีมากกว่า 7 ตัวอักษรมักจะถูกค้นพบโดยฮาร์ดแวร์พิเศษ เช่น คอมพิวเตอร์เดสก์ท็อปที่สร้างขึ้นเป็นพิเศษที่มีหน่วยประมวลผลกราฟิก (GPUs) หลายตัว การค้นหา address แบบกำหนดเองบนระบบ GPU เร็วกว่าบน CPU ทั่วไปหลายเท่า</p>
<p>อีกวิธีหนึ่งในการหา address แบบกำหนดเองคือการจ้างงานไปยังกลุ่มคนขุด vanity addresses กลุ่มคนขุดvanity addresses เป็นบริการที่ให้ผู้ที่มีฮาร์ดแวร์ที่เร็วได้รับบิตคอยน์จากการค้นหา vanity addresses ให้กับผู้อื่น ยูจีเนียสามารถจ่ายค่าธรรมเนียมเพื่อจ้างงานการค้นหา vanity addresses ที่มีรูปแบบ 7 ตัวอักษรและได้ผลลัพธ์ในเวลาเพียงไม่กี่ชั่วโมงแทนที่จะต้องใช้ CPU ค้นหาเป็นเดือน ๆ</p>
<p>การสร้างที่ address แบบกำหนดเองเป็นการใช้วิธีการแบบ brute-force (ลองทุกความเป็นไปได้): ลองใช้คีย์สุ่ม ตรวจสอบ address ที่ได้ว่าตรงกับรูปแบบที่ต้องการหรือไม่ และทำซ้ำจนกว่าจะสำเร็จ</p>
<h4>ความปลอดภัยและความเป็นส่วนตัวของ address แบบกำหนดเอง</h4>
<p>address แบบกำหนดเองเคยเป็นที่นิยมในช่วงแรก ๆ ของบิตคอยน์ แต่แทบจะหายไปจากการใช้งานทั้งหมดในปี 2023 มีสาเหตุที่น่าจะเป็นไปได้สองประการสำหรับแนวโน้มนี้:</p>
<ul>
<li><p><strong>Deterministic wallets:</strong> ดังที่เราเห็นในพาร์ทของการกู้คืน การที่จะสำรองคีย์ทุกตัวในกระเป๋าเงินสมัยใหม่ส่วนใหญ่นั้น ทำเพียงแค่จดคำหรือตัวอักษรไม่กี่ตัว ซึ่งนี่เป็นผลจากการสร้างคีย์ทุกตัวในกระเป๋าเงินจากคำหรือตัวอักษรเหล่านั้นโดยใช้อัลกอริทึมแบบกำหนดได้ จึงไม่สามารถใช้ address แบบกำหนดเองกับ Deterministic wallets ได้ เว้นแต่ผู้ใช้จะสำรองข้อมูลเพิ่มเติมสำหรับ address แบบกำหนดเองทุก address ที่พวกเขาสร้าง ในทางปฏิบัติแล้วกระเป๋าเงินส่วนใหญ่ที่ใช้การสร้างคีย์แบบกำหนดได้ โดยไม่อนุญาตให้นำเข้าคีย์ส่วนตัวหรือการปรับแต่งคีย์จากโปรแกรมสร้าง address ที่กำหนดเอง</p>
</li>
<li><p><strong>การหลีกเลี่ยงการใช้ address ซ้ำซ้อน:</strong> การใช้ address แบบกำหนดเองเพื่อรับการชำระเงินหลายครั้งไปยัง address เดียวกันจะสร้างความเชื่อมโยงระหว่างการชำระเงินทั้งหมดเหล่านั้น นี่อาจเป็นที่ยอมรับได้สำหรับยูจีเนียหากองค์กรไม่แสวงหาผลกำไรของเธอจำเป็นต้องรายงานรายได้และค่าใช้จ่ายต่อหน่วยงานภาษีอยู่แล้ว แต่อย่างไรก็ตาม มันยังลดความเป็นส่วนตัวของคนที่จ่ายเงินให้ยูจีเนียหรือรับเงินจากเธอด้วย ตัวอย่างเช่น อลิซอาจต้องการบริจาคโดยไม่เปิดเผยตัวตน และบ็อบอาจไม่ต้องการให้ลูกค้ารายอื่นของเขารู้ว่าเขาให้ราคาส่วนลดแก่ยูจีเนีย</p>
</li>
</ul>
<p>เราไม่คาดว่าจะเห็น address แบบกำหนดเองมากนักในอนาคต เว้นแต่ปัญหาที่กล่าวมาก่อนหน้านี้จะได้รับการแก้ไข</p>
<h3>Paper Wallets</h3>
<p>paper wallet หรือก็คือ private key ที่พิมพ์ลงในกระดาษ และโดยทั่วไปแล้วมักจะมีข้อมูลของ public key หรือ address บนกระดาษนั้นด้วยแม้ว่าจริง ๆ แล้วมันจะสามารถคำนวณได้ด้วย private key ก็ตาม</p>
<blockquote>
<p>คำเตือน: paper wallet เป็นเทคโนโลยีที่ล้าสมัยแล้วและอันตรายสำหรับผู้ใช้ส่วนใหญ่ เพราะเป็นเรื่องยากที่จะสร้างมันอย่างปลอดภัย โดยเฉพาะอย่างยิ่งความเป็นไปได้ที่โค้ดที่ใช้สร้างอาจถูกแทรกแซงด้วยผู้ไม่ประสงค์ดี และอาจจะทำให้ผู้ใช้โดนขโมยบิตคอยน์ทั้งหมดไปได้ paper wallet ถูกแสดงที่นี่เพื่อวัตถุประสงค์ในการให้ข้อมูลเท่านั้นและไม่ควรใช้สำหรับเก็บบิตคอยน์</p>
</blockquote>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0410.png" alt="image"></p>
<p>paper wallet ได้ถูกออกแบบมาเพื่อเป็นของขวัญและมีธีมตามฤดูกาล เช่น คริสต์มาสและปีใหม่ ส่วนเหตุผลอื่น ๆ ถูกออกแบบเพื่อการเก็บรักษาในตู้นิรภัยของธนาคารหรือตู้เซฟโดยมี private key ถูกซ่อนไว้ในบางวิธี ไม่ว่าจะด้วยสติกเกอร์แบบขูดที่ทึบแสงหรือพับและปิดผนึกด้วยแผ่นฟอยล์กันการงัดแงะ ส่วนการออกแบบอื่น ๆ มีสำเนาเพิ่มเติมของคีย์และ address ในรูปแบบของตอนฉีกที่แยกออกได้คล้ายกับตั๋ว ช่วยให้คุณสามารถเก็บสำเนาหลายชุดเพื่อป้องกันจากไฟไหม้ น้ำท่วม หรือภัยพิบัติทางธรรมชาติอื่น ๆ</p>
<p>จากการออกแบบเดิมของบิตคอยน์ที่เน้น public key ไปจนถึง address และสคริปต์สมัยใหม่อย่าง bech32m และ pay to taproot—และแม้แต่การอัพเกรดบิตคอยน์ในอนาคต—คุณได้เรียนรู้วิธีที่โปรโตคอลบิตคอยน์อนุญาตให้ผู้จ่ายเงินระบุกระเป๋าเงินที่ควรได้รับการชำระเงินของพวกเขา แต่เมื่อเป็นกระเป๋าเงินของคุณเองที่รับการชำระเงิน คุณจะต้องการความมั่นใจว่าคุณจะยังคงเข้าถึงเงินนั้นได้แม้ว่าจะเกิดอะไรขึ้นกับข้อมูลกระเป๋าเงินของคุณ ในบทต่อไป เราจะดูว่ากระเป๋าเงินบิตคอยน์ถูกออกแบบอย่างไรเพื่อปกป้องเงินทุนจากภัยคุกคามหลากหลายรูปแบบ</p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<h2>Keys and Addresses</h2>
<p>อลิซต้องการจ่ายเงินให้กับบ๊อบแต่โหนดของบิตคอยน์ในระบบหลายพันโหนดจะตรวจสอบธุรกรรมของเธอ โดยไม่รู้ว่าอลิซหรือบ๊อบเป็นใคร ละเราต้องการรักษาความเป็นส่วนตัวของพวกเขาไว้เช่นนี้ อลิซจำเป็นต้องสื่อสารว่าบ๊อบควรได้รับบิตคอยน์บางส่วนของเธอโดยไม่เชื่อมโยงแง่มุมใด ๆ ของธุรกรรมนั้นกับตัวตนในโลกจริงของบ๊อบ หรือกับการชำระเงินด้วยบิตคอยน์ครั้งอื่น ๆ ที่บ๊อบได้รับ อลิซใช้ต้องทำให้มั่นใจว่ามีเพียแค่บ๊อบเท่านั้นที่สามารถใช้จ่ายบิตคอยน์ที่เขาได้รับต่อไปได้</p>
<p>ในบิตคอยน์ไวท์เปเปอร์ได้อธิบายถึงแผนการที่เรียบง่ายมากสำหรับการบรรลุเป้าหมายเหล่านั้น ดังที่แสดงในรูปด้านล่างนี้ </p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_aain01.png" alt="image"></p>
<p>ตัวของผู้รับอย่างบ๊อบเองจะได้รับบิตคอยน์ไปยัง public key ของเขาที่ถูกลงนามโดยผู้จ่ายอย่างอลิซ โดยบิตคอยน์ที่อลิซนำมาจ่ายนั้นก็ได้รับมาจากที่ใครสักคนส่งมาที่ public key ของเธอ และเธอก็ใช้ private key ของเธอในการลงนามเพื่อสร้างลายเซ็นของเธอและโหนดต่าง ๆ ของบิตคอยน์จะทำการตรวจสอบว่าลายเซ็นของอลิซผูกมัดกับเอาต์พุตของฟังก์ชันแฮชซึ่งตัวมันเองผูกมัดกับ public key ของบ๊อบและรายละเอียดธุรกรรมอื่นๆ</p>
<p>ในบทนี้เราจะพิจารณาpublic key  private key  Digital signatrue และ hash function จากนั้นใช้ทั้งหมดนี้ร่วมกันเพื่ออธิบาย address ที่ใช้โดยซอฟต์แวร์บิตคอยน์สมัยใหม่</p>
<h3>Public Key Cryptography (การเข้ารหัสของ public key)</h3>
<p>ระบบเข้ารหัสของ public key ถูกคิดค้นขึ้นในทศวรรษ 1970 มาจากรากฐานทางคณิตศาสตร์สำหรับความปลอดภัยของคอมพิวเตอร์และข้อมูลสมัยใหม่</p>
<p>นับตั้งแต่การคิดค้นระบบเข้ารหัส public key ได้มีการค้นพบฟังก์ชันทางคณิตศาสตร์ที่เหมาะสมหลายอย่าง เช่น การยกกำลังของจำนวนเฉพาะและการคูณของเส้นโค้งวงรี โดยฟังก์ชันทางคณิตศาสตร์เหล่านี้สามารถคำนวณได้ง่ายในทิศทางหนึ่ง แต่เป็นไปไม่ได้ที่จะคำนวณในทิศทางตรงกันข้ามโดยใช้คอมพิวเตอร์และอัลกอริทึมที่มีอยู่ในปัจจุบัน จากฟังก์ชันทางคณิตศาสตร์เหล่านี้ การเข้ารหัสลับช่วยให้สามารถสร้างลายเซ็นดิจิทัลที่ไม่สามารถปลอมแปลงได้และบิตคอยน์ได้ใช้การบวกและการคูณของเส้นโค้งวงรีเป็นพื้นฐานสำหรับการเข้ารหัสลับของมัน</p>
<p>ในบิตคอยน์ เราสามารถใช้ระบบเข้ารหัส public key เพื่อสร้างคู่กุญแจที่ควบคุมการเข้าถึงบิตคอยน์ คู่กุญแจประกอบด้วย private key และ public key ที่ได้มาจาก private key public keyใช้สำหรับรับเงิน และ private key ใช้สำหรับลงนามในธุรกรรมเพื่อใช้จ่ายเงิน</p>
<p>ความสัมพันธ์ทางคณิตศาสตร์ระหว่าง public key และ private key ที่ช่วยให้ private key สามารถใช้สร้างลายเซ็นบนข้อความได้ ลายเซ็นเหล่านี้สามารถตรวจสอบความถูกต้องกับ public key ได้โดยไม่เปิดเผย private key</p>
<blockquote>
<p>TIP: ในการใช้งานซอฟแวร์กระเป๋าเงินบิตคอยน์บสงอัน จะทำการเก็บ private key และ public key ถูกเก็บไว้ด้วยกันในรูปแบบคู่กุญแจเพื่อความสะดวก แต่อย่างไรก็ตาม public key สามารถคำนวณได้จาก private key ดังนั้นการเก็บเพียง private key เท่านั้นก็เป็นไปได้เช่นกัน</p>
</blockquote>
<p>bitcoin wallet มักจะทำการรวบรวมคู่กุญแต่ละคู่ ซึ่งจะประกอบไปด้วย private key และ public key โดย private key จะเป็นตัวเลขที่ถูกสุ่มเลือกขึ้นมา และเราขะใช้เส้นโค้งวงรี ซึ่งเป็นฟังก์ชันการเข้ารหัสทางเดียว เพื่อสร้าง public key ขึ้นมา</p>
<h3>ทำไมจึงใช้การเข้ารหัสแบบอสมมาตร</h3>
<p>ทำไมการเข้ารหัสแบบอสมมาตรจึงถูกใช้บิตคอยน์? มันไม่ได้ถูกใช้เพื่อ "เข้ารหัส" (ทำให้เป็นความลับ) ธุรกรรม แต่คุณสมบัติที่มีประโยชน์ของการเข้ารหัสแบบอสมมาตรคือความสามารถในการสร้าง ลายเซ็นดิจิทัล private key สามารถนำไปใช้กับธุรกรรมเพื่อสร้างลายเซ็นเชิงตัวเลข ลายเซ็นนี้สามารถสร้างได้เฉพาะโดยผู้ที่มีความเกี่ยวข้องกับ private key เท่านั้น แต่อย่างไรก็ตาม ทุกคนที่สามารถเข้าถึง public key และธุรกรรมสามารถใช้สิ่งเหล่านี้เพื่อ ตรวจสอบ ลายเซ็นได้ คุณสมบัติที่มีประโยชน์นี้ของการเข้ารหัสแบบอสมมาตรทำให้ทุกคนสามารถตรวจสอบลายเซ็นทุกรายการในทุกธุรกรรมได้ ในขณะที่มั่นใจว่าเฉพาะเจ้าของ private key เท่านั้นที่สามารถสร้างลายเซ็นที่ถูกต้องได้</p>
<h3>Private keys</h3>
<p>private key เป็นเพียงตัวเลขที่ถูกสุ่มขึ้น และการควบคุม private key ก็เป็นรากฐานสำคัญที่ทำให้เจ้าชองกุญแจดอกนี้สามารถควบคุมบิตคอยน์ทั้งหมดที่มีความเกี่ยวข้องกับ public key ที่คู่กัน private key นั้นใช้ในการสร้างลายเซ็นดิจิทัลที่ใช้ในการเคลื่อนย้ายบิตคอยน์ เราจำเป็นต้องเก็บ private key ให้เป็นความลับตลอดเวลา เพราะการเปิดเผยมันให้กับบุคคลอื่นนั้นก็เปรียบเสมือนกับการนำอำนาจในการควบคุมบิตคอยน์ไปให้แก่เขา นอกจากนี้ private key ยังจำเป็นต้องได้รับการสำรองข้อมูลและป้องกันจากการสูญหายโดยไม่ตั้งใจ เพราะหากเราได้ทำมันสูญหายไป จะไม่สามารถกู้คืนได้ และบิตคอยน์เหล่านั้นจะถูกปกป้องโดยกุญแจที่หายไปนั้นตลอดกาลเช่นกัน</p>
<blockquote>
<p>TIP: private key ของบิตคอยน์นั้นเป็นเพียงแค่ตัวเลข คุณสามารถสร้างมันได้โดยใช้เพียงเหรียญ ดินสอ และกระดาษ โดยการโยนเหรียญเพียง 256 ครั้งจะทำให้คุณได้เลขฐานสองที่สามารถใช้เป็น private key ของบิตคอยน์ จากนั้นคุณสามารถใช้มันในการคำนวณหา public key แต่อย่างไรก็ตาม โปรดระมัดระวังเกี่ยวกับการเลือใช้วิธีการสุ่มที่ไม่สมบูรณ์ เพราะนั่นอาจลดความปลอดภัยของ private key และบิตคอยน์ที่มัมปกป้องอยู่อย่างมีนัยสำคัญ</p>
</blockquote>
<p>ขั้นตอนแรกและสำคัญที่สุดในการสร้างกุญแจคือการหาแหล่งที่มาของความสุ่มที่ปลอดภัย (ซึ่งเรียกว่า เอนโทรปี) การสร้างกุญแจของบิตคอยน์นั้นเกือบเหมือนกับ "เลือกตัวเลขระหว่าง 1 และ 2^256" ซึ่งวิธีที่แน่นอนที่คุณใช้ในการเลือกตัวเลขนั้นไม่สำคัญตราบใดที่มันไม่สามารถคาดเดาหรือทำซ้ำได้ โดยปกติแล้วซอฟต์แวร์ของบิตคอยน์มักจะใช้ตัวสร้างตัวเลขสุ่มที่มีความปลอดภัยทางการเข้ารหัสเพื่อสร้างเอนโทรปี 256 บิต</p>
<p>สิ่งที่สำคัญในเรื่องนี้คือ private key สามารถเป็นตัวเลขใดๆ ระหว่าง 0 และ n - 1 (รวมทั้งสองค่า) โดยที่ n เป็นค่าคงที่ (n = 1.1578 × 10^77 ซึ่งน้อยกว่า 2^256 เล็กน้อย) ซึ่งกำหนดอยู่ใน elliptic curve ที่ใช้ใน Bitcoin ในการสร้างกุญแจดังกล่าว เราสุ่มเลือกเลขขนาด 256 บิตและตรวจสอบว่ามันน้อยกว่า n ในแง่ของการเขียนโปรแกรม โดยปกติแล้วสิ่งนี้ทำได้โดยการป้อนสตริงของบิตสุ่มที่ใหญ่กว่า ซึ่งรวบรวมจากแหล่งที่มาของความสุ่มที่มีความปลอดภัยทางการเข้ารหัส เข้าไปในอัลกอริทึมแฮช SHA256 ซึ่งจะสร้างค่าขนาด 256 บิตที่สามารถตีความเป็นตัวเลขได้อย่างสะดวก หากผลลัพธ์น้อยกว่า n เราจะได้กุญแจส่วนตัวที่เหมาะสม มิฉะนั้น เราก็เพียงแค่ลองอีกครั้งด้วยตัวเลขสุ่มอื่น</p>
<blockquote>
<p>คำเตือน: อย่าเขียนโค้ดของคุณเองเพื่อสร้างตัวเลขสุ่ม หรือใช้ตัวสร้างตัวเลขสุ่ม "แบบง่าย" ที่มีให้ในภาษาโปรแกรมของคุณ ใช้ตัวสร้างตัวเลขสุ่มเทียมที่มีความปลอดภัยทางการเข้ารหัส (CSPRNG) จากแหล่งที่มีเอนโทรปีเพียงพอ ศึกษาเอกสารของไลบรารีตัวสร้างตัวเลขสุ่มที่คุณเลือกเพื่อให้มั่นใจว่ามีความปลอดภัยทางการเข้ารหัส การใช้งาน CSPRNG ที่ถูกต้องมีความสำคัญอย่างยิ่งต่อความปลอดภัยของกุญแจ</p>
</blockquote>
<p>ต่อไปนี้คือกุญแจส่วนตัว (k) ที่สร้างขึ้นแบบสุ่มซึ่งแสดงในรูปแบบเลขฐานสิบหก (256 บิตแสดงเป็น 64 หลักเลขฐานสิบหก โดยแต่ละหลักคือ 4 บิต):</p>
<pre><code>1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD
</code></pre>
<blockquote>
<p>TIP: จำนวนที่เป็นไปได้ของ private key ทั้งหมดนั้นมีอยู่ 2^256 เป็นตัวเลขที่ใหญ่มากจนยากจะจินตนาการได้ มันมีค่าประมาณ 10^77 (เลข 1 ตามด้วยเลข 0 อีก 77 ตัว) ในระบบเลขฐานสิบ เพื่อให้เข้าใจง่ายขึ้น ลองเปรียบเทียบกับจักรวาลที่เรามองเห็นได้ซึ่งนักวิทยาศาสตร์ประมาณการว่ามีอะตอมทั้งหมดประมาณ 10^80 อะตอม นั่นหมายความว่าช่วงค่าของกุญแจส่วนตัว Bitcoin มีขนาดใกล้เคียงกับจำนวนอะตอมทั้งหมดในจักรวาลที่เรามองเห็นได้</p>
</blockquote>
<h3>การอธิบายเกี่ยวกับวิทยาการเข้ารหัสแบบเส้นโค้งวงรี (Elliptic Curve Cryptography)</h3>
<p>วิทยาการเข้ารหัสแบบเส้นโค้งวงรี (ECC) เป็นประเภทหนึ่งของการเข้ารหัสแบบอสมมาตรหรือ public key ซึ่งอาศัยหลักการของปัญหาลอการิทึมแบบไม่ต่อเนื่อง โดยแสดงออกผ่านการบวกและการคูณบนจุดต่างๆ ของเส้นโค้งวงรี</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0402.png" alt="image"></p>
<p>บิตคอยน์ใช้เส้นโค้งวงรีเฉพาะและชุดค่าคงที่ทางคณิตศาสตร์ ตามที่กำหนดไว้ในมาตรฐานที่เรียกว่า secp256k1 ซึ่งกำหนดโดยสถาบันมาตรฐานและเทคโนโลยีแห่งชาติ (NIST) เส้นโค้ง secp256k1 ถูกกำหนดโดยฟังก์ชันต่อไปนี้ ซึ่งสร้างเส้นโค้งวงรี: y² = (x³ + 7) บนฟิลด์จำกัด (F_p) หรือ y² mod p = (x³ + 7) mod p</p>
<p>โดยที่ mod p (มอดูโลจำนวนเฉพาะ p) แสดงว่าเส้นโค้งนี้อยู่บนฟิลด์จำกัดของอันดับจำนวนเฉพาะ p ซึ่งเขียนได้เป็น F_p โดย p = 2^256 – 2^32 – 2^9 – 2^8 – 2^7 – 2^6 – 2^4 – 1 ซึ่งเป็นจำนวนเฉพาะที่มีค่ามหาศาล</p>
<p>บิตคอยน์ใช้เส้นโค้งวงรีที่ถูกนิยามบนฟิลด์จำกัดของอันดับจำนวนเฉพาะแทนที่จะอยู่บนจำนวนจริง ทำให้มันมีลักษณะเหมือนรูปแบบของจุดที่กระจัดกระจายในสองมิติ ซึ่งทำให้ยากต่อการจินตนาการภาพ อย่างไรก็ตาม คณิตศาสตร์ที่ใช้นั้นเหมือนกับเส้นโค้งวงรีบนจำนวนจริง</p>
<p>ตัวอย่างเช่น การเข้ารหัสลับด้วยเส้นโค้งวงรี: การแสดงภาพเส้นโค้งวงรีบน F(p) โดยที่ p=17 แสดงเส้นโค้งวงรีเดียวกันบนฟิลด์จำกัดของอันดับจำนวนเฉพาะ 17 ที่มีขนาดเล็กกว่ามาก ซึ่งแสดงรูปแบบของจุดบนตาราง</p>
<p>เส้นโค้งวงรี secp256k1 ที่ใช้ในบิตคอยน์สามารถนึกถึงได้ว่าเป็นรูปแบบของจุดที่ซับซ้อนมากกว่าบนตารางที่มีขนาดใหญ่มหาศาลจนยากจะเข้าใจได้</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0403.png" alt="image"></p>
<p>ตัวอย่างเช่น จุด P ที่มีพิกัด (x, y) ต่อไปนี้เป็นจุดที่อยู่บนเส้นโค้ง secp256k1:</p>
<pre><code>P =
(55066263022277343669578718895168534326250603453777594175500187360389116729240,
32670510020758816978083085130507043184471273380659243275938904335757337482424)
</code></pre>
<p>เราสามารถใช้ Python เพื่อยืนยันว่าจุดนี้อยู่บนเส้นโค้งวงรีได้ตามตัวอย่างนี้:<br>ตัวอย่างที่ 1: การใช้ Python เพื่อยืนยันว่าจุดนี้อยู่บนเส้นโค้งวงรี</p>
<pre><code>Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
&gt; p = 115792089237316195423570985008687907853269984665640564039457584007908834671663
&gt; x = 55066263022277343669578718895168534326250603453777594175500187360389116729240
&gt; y = 32670510020758816978083085130507043184471273380659243275938904335757337482424
&gt; (x ** 3 + 7 - y**2) % p
0
</code></pre>
<p>ผลลัพธ์เป็น 0 ซึ่งแสดงว่าจุดนี้อยู่บนเส้นโค้งวงรีจริง เพราะเมื่อแทนค่า x และ y ลงในสมการ y² = (x³ + 7) mod p แล้ว ทั้งสองด้านของสมการมีค่าเท่ากัน</p>
<p>ในคณิตศาสตร์ของเส้นโค้งวงรี มีจุดที่เรียกว่า "จุดที่อนันต์" (point at infinity) ซึ่งมีบทบาทคล้ายกับศูนย์ในการบวก บนคอมพิวเตอร์ บางครั้งจุดนี้แทนด้วย x = y = 0 (ซึ่งไม่เป็นไปตามสมการเส้นโค้งวงรี แต่เป็นกรณีพิเศษที่สามารถตรวจสอบได้ง่าย)</p>
<p>มีตัวดำเนินการ + ที่เรียกว่า "การบวก" ซึ่งมีคุณสมบัติคล้ายกับการบวกแบบดั้งเดิมของจำนวนจริงที่เด็กๆ เรียนในโรงเรียน เมื่อมีจุดสองจุด P1 และ P2 บนเส้นโค้งวงรี จะมีจุดที่สาม P3 = P1 + P2 ซึ่งอยู่บนเส้นโค้งวงรีเช่นกัน</p>
<p>ในเชิงเรขาคณิต จุดที่สาม P3 นี้คำนวณได้โดยการลากเส้นระหว่าง P1 และ P2 เส้นนี้จะตัดกับเส้นโค้งวงรีที่จุดเพิ่มเติมอีกหนึ่งจุดพอดี เรียกจุดนี้ว่า P3' = (x, y) จากนั้นให้สะท้อนกับแกน x เพื่อได้ P3 = (x, -y)</p>
<p>มีกรณีพิเศษบางกรณีที่อธิบายความจำเป็นของ "จุดที่อนันต์":</p>
<ol>
<li>ถ้า P1 และ P2 เป็นจุดเดียวกัน เส้น "ระหว่าง" P1 และ P2 ควรขยายเป็นเส้นสัมผัสกับเส้นโค้ง ณ จุด P1 นี้ เส้นสัมผัสนี้จะตัดกับเส้นโค้งที่จุดใหม่อีกหนึ่งจุดพอดี คุณสามารถใช้เทคนิคจากแคลคูลัสเพื่อหาความชันของเส้นสัมผัส เทคนิคเหล่านี้ใช้ได้อย่างน่าแปลกใจ แม้ว่าเราจะจำกัดความสนใจไว้ที่จุดบนเส้นโค้งที่มีพิกัดเป็นจำนวนเต็มเท่านั้น!</li>
<li>ในบางกรณี (เช่น ถ้า P1 และ P2 มีค่า x เดียวกันแต่ค่า y ต่างกัน) เส้นสัมผัสจะตั้งฉากพอดี ซึ่งในกรณีนี้ P3 = "จุดที่อนันต์"</li>
<li>ถ้า P1 เป็น "จุดที่อนันต์" แล้ว P1 + P2 = P2 ในทำนองเดียวกัน ถ้า P2 เป็นจุดที่อนันต์ แล้ว P1 + P2 = P1 นี่แสดงให้เห็นว่าจุดที่อนันต์มีบทบาทเป็นศูนย์</li>
</ol>
<p>การบวกนี้มีคุณสมบัติเชิงสมาคม (associative) ซึ่งหมายความว่า (A + B) + C = A + (B + C) นั่นหมายความว่าเราสามารถเขียน A + B + C โดยไม่ต้องมีวงเล็บและไม่มีความกำกวม</p>
<p>เมื่อเรานิยามการบวกแล้ว เราสามารถนิยามการคูณในแบบมาตรฐานที่ต่อยอดจากการบวก สำหรับจุด P บนเส้นโค้งวงรี ถ้า k เป็นจำนวนเต็มบวก แล้ว kP = P + P + P + … + P (k ครั้ง) โปรดทราบว่า k บางครั้งถูกเรียกว่า "เลขชี้กำลัง"</p>
<h3>Public Keys</h3>
<p>ในระบบคริปโตกราฟีแบบเส้นโค้งวงรี (Elliptic Curve Cryptography)  public key ถูกคำนวณจาก private key โดยใช้การคูณเส้นโค้งวงรี ซึ่งเป็นกระบวนการที่ไม่สามารถย้อนกลับได้:</p>
<p>K = k × G</p>
<p>โดยที่:</p>
<ul>
<li>k คือ private key</li>
<li>G คือจุดคงที่ที่เรียกว่า จุดกำเนิด (generator point)</li>
<li>K คือ public key</li>
</ul>
<p>การดำเนินการย้อนกลับ ที่เรียกว่า "การหาลอการิทึมแบบไม่ต่อเนื่อง" (finding the discrete logarithm) - คือการคำนวณหา k เมื่อรู้ค่า K - เป็นสิ่งที่ยากมากเทียบเท่ากับการลองค่า k ทุกค่าที่เป็นไปได้ (วิธีการแบบ brute-force)</p>
<p>ความยากของการย้อนกลับนี้คือหลักการความปลอดภัยหลักของระบบ ECC ที่ใช้ในบิตคอยน์ ซึ่งทำให้สามารถเผยแพร่ public key ได้อย่างปลอดภัย โดยที่ไม่ต้องกังวลว่าจะมีใครสามารถคำนวณย้อนกลับเพื่อหา private key ได้</p>
<blockquote>
<p>TIP:การคูณเส้นโค้งวงรีเป็นฟังก์ชันประเภทที่นักเข้ารหัสลับเรียกว่า “ trap door function ”:</p>
</blockquote>
<blockquote>
</blockquote>
<ul>
<li>เป็นสิ่งที่ทำได้ง่ายในทิศทางหนึ่ง</li>
<li>แต่เป็นไปไม่ได้ที่จะทำในทิศทางตรงกันข้าม</li>
</ul>
<blockquote>
<p>คนที่มี private key สามารถสร้าง public key ได้อย่างง่ายดาย และสามารถแบ่งปันกับโลกได้โดยรู้ว่าไม่มีใครสามารถย้อนกลับฟังก์ชันและคำนวณ private key จาก public key ได้ กลวิธีทางคณิตศาสตร์นี้กลายเป็นพื้นฐานสำหรับลายเซ็นดิจิทัลที่ปลอมแปลงไม่ได้และมีความปลอดภัย ซึ่งใช้พิสูจน์การควบคุมเงินบิตคอยน์</p>
</blockquote>
<p>เริ่มต้นด้วยการใช้ private key ในรูปแบบของตัวเลขสุ่ม เราคูณมันด้วยจุดที่กำหนดไว้ล่วงหน้าบนเส้นโค้งที่เรียกว่า จุดกำเนิด (generator point)  เพื่อสร้างจุดอื่นที่อยู่บนเส้นโค้งเดียวกัน ซึ่งคำตอบจะเป็น public key ที่สอดคล้องกัน จุดกำเนิดถูกกำหนดไว้เป็นส่วนหนึ่งของมาตรฐาน secp256k1 และเป็นค่าเดียวกันสำหรับกุญแจทั้งหมดในระบบบิตคอยน์</p>
<p>เนื่องจากจุดกำเนิด G เป็นค่าเดียวกันสำหรับผู้ใช้บิตคอยน์ทุกคน private key (k) ที่คูณกับ G จะได้ public key (K) เดียวกันเสมอ ความสัมพันธ์ระหว่าง k และ K เป็นแบบตายตัวแต่สามารถคำนวณได้ในทิศทางเดียวเท่านั้น คือจาก k ไปยัง K นี่คือเหตุผลที่ public key ของบิตคอยน์ (K) สามารถแบ่งปันกับทุกคนได้โดยไม่เปิดเผย private key (k) ของผู้ใช้</p>
<blockquote>
<p>TIP: private key สามารถแปลงเป็น public key ได้ แต่ public key ไม่สามารถแปลงกลับเป็น private key ได้ เพราะคณิตศาสตร์ที่ใช้ทำงานได้เพียงทิศทางเดียวเท่านั้น</p>
</blockquote>
<p>เมื่อนำการคูณเส้นโค้งวงรีมาใช้งาน เราจะนำ private key (k) ที่สร้างขึ้นก่อนหน้านี้มาคูณกับจุดกำเนิด G เพื่อหา public key (K):</p>
<pre><code>K = 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD × G
</code></pre>
<p>public key (K) จะถูกกำหนดเป็นจุด K = (x, y) โดยที่:</p>
<pre><code>x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
</code></pre>
<p>เพื่อจะให้เห็นภาพของการคูณจุดด้วยจำนวนเต็มมากขึ้น เราจะใช้เส้นโค้งวงรีที่ง่ายกว่าบนจำนวนจริง (โดยหลักการทางคณิตศาสตร์ยังคงเหมือนกัน) เป้าหมายของเราคือการหาผลคูณ kG ของจุดกำเนิด G ซึ่งเทียบเท่ากับการบวก G เข้ากับตัวเอง k ครั้งติดต่อกัน</p>
<p>ในเส้นโค้งวงรี การบวกจุดเข้ากับตัวเองเทียบเท่ากับการลากเส้นสัมผัสที่จุดนั้นและหาว่าเส้นนั้นตัดกับเส้นโค้งอีกครั้งที่จุดใด จากนั้นจึงสะท้อนจุดนั้นบนแกน x</p>
<p>การเข้ารหัสลับด้วยเส้นโค้งวงรี: การแสดงภาพการคูณจุด G ด้วยจำนวนเต็ม k บนเส้นโค้งวงรี แสดงกระบวนการในการหา G, 2G, 4G เป็นการดำเนินการทางเรขาคณิตบนเส้นโค้งได้ดังนี้</p>
<blockquote>
<p>TIP: ในซอฟแวร์ของบิตคอยน์ส่วนใหญ่ใช้ไลบรารีเข้ารหัสลับ libsecp256k1 เพื่อทำการคำนวณทางคณิตศาสตร์เส้นโค้งวงรี<br><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0404.png" alt="image"></p>
</blockquote>
<h3>Output and Input Scripts</h3>
<p>แม้ว่าภาพประกอบจาก Bitcoin whitepaper ที่แสดงเรื่อง "Transaction chain" จะแสดงให้เห็นว่ามีการใช้ public key และ digital signature โดยตรง แต่ในความเป็นจริงบิตคอยน์เวอร์ชันแรกนั้นมีการส่งการชำระเงินไปยังฟิลด์ที่เรียกว่า output script และมีการใช้จ่ายบิตคอยน์เหล่านั้นโดยได้รับอนุญาตจากฟิลด์ที่เรียกว่า input script ฟิลด์เหล่านี้อนุญาตให้มีการดำเนินการเพิ่มเติมนอกเหนือจาก (หรือแทนที่) การตรวจสอบว่าลายเซ็นสอดคล้องกับ public key หรือไม่ ตัวอย่างเช่น output script สามารถมี public key สองดอกและต้องการลายเซ็นสองลายเซ็นที่สอดคล้องกันในฟิลด์ input script ที่ใช้จ่าย</p>
<p>ในภายหลัง ในหัวข้อ [tx_script] เราจะได้เรียนรู้เกี่ยวกับสคริปต์อย่างละเอียด สำหรับตอนนี้ สิ่งที่เราต้องเข้าใจคือ บิตคอยน์จะถูกรับเข้า output script ที่ทำหน้าที่เหมือน public key และการใช้จ่ายบิตคอยน์จะได้รับอนุญาตโดย input script ที่ทำหน้าที่เหมือนลายเซ็น</p>
<h4>IP Addresses: The Original Address for Bitcoin (P2PK)</h4>
<p>เราได้เห็นแล้วว่าอลิซสามารถจ่ายเงินให้บ็อบโดยการมอบบิตคอยน์บางส่วนของเธอให้กับกุญแจสาธารณะของบ็อบ แต่อลิซจะได้กุญแจสาธารณะของบ็อบมาได้อย่างไร? บ็อบอาจจะให้สำเนากุญแจแก่เธอ แต่ลองดูกุญแจสาธารณะที่เราใช้งานในตัวอย่างที่ผ่านมาอีกครั้ง:</p>
<pre><code>x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
</code></pre>
<blockquote>
<p>TIP จากหลาม: :สังเกตได้ว่า public key มีความยาวมาก ลองจินตนาการว่าบ็อบพยายามอ่านกุญแจนี้ให้อลิซฟังทางโทรศัพท์ คงจะยากมากที่จะอ่านและบันทึกโดยไม่มีข้อผิดพลาด</p>
</blockquote>
<p>แทนที่จะป้อนกุญแจสาธารณะโดยตรง เวอร์ชันแรกของซอฟต์แวร์บิตคอยน์อนุญาตให้ผู้จ่ายเงินป้อนที่อยู่ IP ของผู้รับได้ ตามที่แสดงในหน้าจอการส่งเงินรุ่นแรกของบิตคอยน์ผ่าน The Internet Archive</p>
<p>คุณสมบัตินี้ถูกลบออกในภายหลัง เนื่องจากมีปัญหามากมายในการใช้ที่อยู่ IP แต่คำอธิบายสั้นๆ จะช่วยให้เราเข้าใจได้ดีขึ้นว่าทำไมคุณสมบัติบางอย่างอาจถูกเพิ่มเข้าไปในโปรโตคอลบิตคอยน์</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0405.png" alt="image"></p>
<p>เมื่ออลิซป้อนที่อยู่ IP ของบ็อบในบิตคอยน์เวอร์ชัน 0.1 Full node ของเธอจะทำการเชื่อมต่อกับ full node ของเขาและได้รับ public key ใหม่จากกระเป๋าสตางค์ของบ็อบที่โหนดของเขาไม่เคยให้กับใครมาก่อน การที่เป็น public key ใหม่นี้มีความสำคัญเพื่อให้แน่ใจว่าธุรกรรมต่าง ๆ ที่จ่ายให้บ็อบจะไม่สามารถถูกเชื่อมโยงเข้าด้วยกันโดยคนที่กำลังดูบล็อกเชนและสังเกตเห็นว่าธุรกรรมทั้งหมดจ่ายไปยัง public key เดียวกัน</p>
<p>เมื่อใช้ public key จากโหนดของอลิซซึ่งได้รับมาจากโหนดของบ็อบ กระเป๋าสตางค์ของอลิซจะสร้างเอาต์พุตธุรกรรมที่จ่ายให้กับสคริปต์เอาต์พุตดังนี้</p>
<pre><code>&lt;Bob's public key&gt; OP_CHECKSIG
</code></pre>
<p>ต่อมาบ็อบจะสามารถใช้จ่ายเอาต์พุตนั้นด้วยสคริปต์อินพุตที่ประกอบด้วยลายเซ็นของเขาเท่านั้น:</p>
<pre><code>&lt;Bob's signature&gt;
</code></pre>
<p>เพื่อให้เข้าใจว่าสคริปต์อินพุตและเอาต์พุตกำลังทำอะไร คุณสามารถรวมพวกมันเข้าด้วยกัน (สคริปต์อินพุตก่อน) แล้วสังเกตว่าข้อมูลแต่ละชิ้น (แสดงในเครื่องหมาย &lt; &gt;) จะถูกวางไว้ที่ด้านบนสุดของรายการที่เรียกว่าสแตก (stack) เมื่อพบรหัสคำสั่ง (opcode) มันจะใช้รายการจากสแตก โดยเริ่มจากรายการบนสุด มาดูว่ามันทำงานอย่างไรโดยเริ่มจากสคริปต์ที่รวมกัน:</p>
<pre><code>&lt;Bob's signature&gt; &lt;Bob's public key&gt; OP_CHECKSIG
</code></pre>
<p>สำหรับสคริปต์นี้ ลายเซ็นของบ็อบจะถูกนำไปไว้บนสแตก จากนั้น public key ของบ็อบจะถูกวางไว้ด้านบนของลายเซ็น และบนสุดจะเป็นคำสั่ง OP_CHECKSIG ที่จะใช้องค์ประกอบสองอย่าง เริ่มจาก public key ตามด้วยลายเซ็น โดยลบพวกมันออกจากสแตก มันจะตรวจสอบว่าลายเซ็นตรงกับ public key และยืนยันฟิลด์ต่าง ๆ ในธุรกรรม ถ้าลายเซ็นถูกต้อง OP_CHECKSIG จะแทนที่ตัวเองบนสแตกด้วยค่า 1 ถ้าลายเซ็นไม่ถูกต้อง มันจะแทนที่ตัวเองด้วย 0 ถ้ามีรายการที่ไม่ใช่ศูนย์อยู่บนสุดของสแตกเมื่อสิ้นสุดการประเมิน สคริปต์ก็จะผ่าน ถ้าสคริปต์ทั้งหมดในธุรกรรมผ่าน และรายละเอียดอื่น ๆ ทั้งหมดเกี่ยวกับธุรกรรมนั้นต้องถูกต้องจึงจะถือว่าธุรกรรมนั้นถูกต้อง</p>
<p>โดยสรุป สคริปต์ข้างต้นใช้ public key และลายเซ็นเดียวกันกับที่อธิบายใน whitepaper แต่เพิ่มความซับซ้อนของฟิลด์สคริปต์สองฟิลด์และรหัสคำสั่งหนึ่งตัว ซึ่งเราจะเริ่มเห็นประโยชน์เมื่อเรามองที่ส่วนต่อไป</p>
<blockquote>
<p>TIP:จากหลาม agian: เอาต์พุตประเภทนี้เป็นที่รู้จักในปัจจุบันว่า P2PK ซึ่งมันไม่เคยถูกใช้อย่างแพร่หลายสำหรับการชำระเงิน และไม่มีโปรแกรมที่ใช้กันอย่างแพร่หลายที่รองรับการชำระเงินผ่านที่อยู่ IP เป็นเวลาเกือบทศวรรษแล้ว</p>
</blockquote>
<h4>Legacy addresses for P2PKH</h4>
<p>แน่นอนว่าการป้อนที่อยู่ IP ของคนที่คุณต้องการจ่ายเงินให้นั้นมีข้อดีหลายประการ แต่ก็มีข้อเสียหลายประการเช่นกัน หนึ่งในข้อเสียที่สำคัญคือผู้รับจำเป็นต้องให้กระเป๋าสตางค์ของพวกเขาออนไลน์ที่ที่อยู่ IP ของพวกเขา และต้องสามารถเข้าถึงได้จากโลกภายนอก </p>
<p>ซึ่งสำหรับคนจำนวนมากนั่นไม่ใช่ตัวเลือกที่เป็นไปได้เพราะหากพวกเขา:</p>
<ul>
<li>ปิดคอมพิวเตอร์ในเวลากลางคืน</li>
<li>แล็ปท็อปของพวกเขาเข้าสู่โหมดสลีป</li>
<li>อยู่หลังไฟร์วอลล์</li>
<li>หรือกำลังใช้การแปลงที่อยู่เครือข่าย (NAT)</li>
</ul>
<p>ปัญหานี้นำเรากลับมาสู่ความท้าทายเดิมที่ผู้รับเงินอย่างบ็อบต้องให้ public key ที่มีความยาวมากแก่ผู้จ่ายเงินอย่างอลิซ  public key ของบิตคอยน์ที่สั้นที่สุดที่นักพัฒนาบิตคอยน์รุ่นแรกรู้จักมีขนาด 65 ไบต์ เทียบเท่ากับ 130 ตัวอักษรเมื่อเขียนในรูปแบบเลขฐานสิบหก (เฮกซาเดซิมอล) แต่อย่างไรก็ตาม บิตคอยน์มีโครงสร้างข้อมูลหลายอย่างที่มีขนาดใหญ่กว่า 65 ไบต์มาก ซึ่งจำเป็นต้องถูกอ้างอิงอย่างปลอดภัยในส่วนอื่น ๆ ของบิตคอยน์โดยใช้ข้อมูลขนาดเล็กที่สุดเท่าที่จะปลอดภัยได้</p>
<p>โดยบิตคอยน์แก้ปัญหานี้ด้วย ฟังก์ชันแฮช (hash function) ซึ่งเป็นฟังก์ชันที่รับข้อมูลที่อาจมีขนาดใหญ่ นำมาแฮช และให้ผลลัพธ์เป็นข้อมูลขนาดคงที่ ฟังก์ชันแฮชจะผลิตผลลัพธ์เดียวกันเสมอเมื่อได้รับข้อมูลนำเข้าแบบเดียวกัน และฟังก์ชันที่ปลอดภัยจะทำให้เป็นไปไม่ได้ในทางปฏิบัติสำหรับผู้ที่ต้องการเลือกข้อมูลนำเข้าอื่นที่ให้ผลลัพธ์เหมือนกันได้ นั่นทำให้ผลลัพธ์เป็น คำมั่นสัญญา (commitment) ต่อข้อมูลนำเข้า เป็นสัญญาว่าในทางปฏิบัติ มีเพียงข้อมูลนำเข้า x เท่านั้นที่จะให้ผลลัพธ์ X</p>
<p>สมมติว่าผมต้องการถามคำถามคุณและให้คำตอบของผมในรูปแบบที่คุณไม่สามารถอ่านได้ทันที สมมติว่าคำถามคือ "ในปีไหนที่ซาโตชิ นาคาโมโตะเริ่มทำงานบนบิทคอยน์?" ผมจะให้การยืนยันคำตอบของผมในรูปแบบของผลลัพธ์จากฟังก์ชันแฮช SHA256 ซึ่งเป็นฟังก์ชันที่ใช้บ่อยที่สุดในบิทคอยน์:</p>
<pre><code>94d7a772612c8f2f2ec609d41f5bd3d04a5aa1dfe3582f04af517d396a302e4e
</code></pre>
<p>ต่อมา หลังจากคุณบอกคำตอบที่คุณเดาสำหรับคำถามนั้น ผมสามารถเปิดเผยคำตอบของผมและพิสูจน์ให้คุณเห็นว่าคำตอบของผม เมื่อใช้เป็นข้อมูลสำหรับฟังก์ชันแฮช จะให้ผลลัพธ์เดียวกันกับที่ผมให้คุณก่อนหน้านี้</p>
<pre><code>$ echo "2007.  He said about a year and a half before Oct 2008" | sha256sum
94d7a772612c8f2f2ec609d41f5bd3d04a5aa1dfe3582f04af517d396a302e4e
</code></pre>
<p>ทีนี้ให้สมมติว่าเราถามบ็อบว่า " public key ของคุณคืออะไร?" บ็อบสามารถใช้ฟังก์ชันแฮชเพื่อให้การยืนยันที่ปลอดภัยทางการเข้ารหัสต่อ public key ของเขา หากเขาเปิดเผยกุญแจในภายหลัง และเราตรวจสอบว่ามันให้ผลการยืนยันเดียวกันกับที่เขาให้เราก่อนหน้านี้ เราสามารถมั่นใจได้ว่ามันเป็นกุญแจเดียวกันที่ใช้สร้างการยืนยันก่อนหน้านี้</p>
<p>ฟังก์ชันแฮช SHA256 ถือว่าปลอดภัยมากและให้ผลลัพธ์ 256 บิต (32 ไบต์) น้อยกว่าครึ่งหนึ่งของขนาด public key ของบิทคอยน์ดั้งเดิม แต่อย่างไรก็ตาม มีฟังก์ชันแฮชอื่นๆ ที่ปลอดภัยน้อยกว่าเล็กน้อยที่ให้ผลลัพธ์ขนาดเล็กกว่า เช่น ฟังก์ชันแฮช RIPEMD-160 ซึ่งให้ผลลัพธ์ 160 บิต (20 ไบต์) ด้วยเหตุผลที่ซาโตชิ นาคาโมโตะไม่เคยระบุ เวอร์ชันดั้งเดิมของบิทคอยน์สร้างการยืนยันต่อ public key โดยการแฮชกุญแจด้วย SHA256 ก่อน แล้วแฮชผลลัพธ์นั้นด้วย RIPEMD-160 ซึ่งให้การยืนยันขนาด 20 ไบต์ต่อ public key</p>
<p>เราสามารถดูสิ่งนี้ตามอัลกอริทึม เริ่มจากกุญแจสาธารณะ K เราคำนวณแฮช SHA256 และคำนวณแฮช RIPEMD-160 ของผลลัพธ์ ซึ่งให้ตัวเลข 160 บิต (20 ไบต์): A = RIPEMD160(SHA256(K))</p>
<p>ทีนี้เราคงเข้าใจวิธีสร้างการยืนยันต่อ public key แล้ว ต่อไปเราจะมาดูวิธีการใช้งานโดยพิจารณาสคริปต์เอาต์พุตต่อไปนี้:</p>
<pre><code>OP_DUP OP_HASH160 &lt;Bob's commitment&gt; OP_EQUAL OP_CHECKSIG
</code></pre>
<p>และสคริปต์อินพุตต่อไปนี้:</p>
<pre><code>&lt;Bob's signature&gt; &lt;Bob's public key&gt;
</code></pre>
<p>และเมื่อเรารวมมันเข้าด้วยกันเราจะได้ผลลัพธ์ดังนี้:</p>
<pre><code>&lt;Bob's signature&gt; &lt;Bob's public key&gt; OP_DUP OP_HASH160 &lt;Bob's commitment&gt; OP_EQUAL OP_CHECKSIG
</code></pre>
<p>เหมือนที่เราทำใน IP Addresses: The Original Address for Bitcoin (P2PK) เราเริ่มวางรายการลงในสแต็ก ลายเซ็นของบ็อบถูกวางก่อน จากนั้น public key ของเขาถูกวางไว้ด้านบน จากนั้นดำเนินการ OP_DUP เพื่อทำสำเนารายการบนสุด ดังนั้นรายการบนสุดและรายการที่สองจากบนในสแต็กตอนนี้เป็น public key ของบ็อบทั้งคู่ การดำเนินการ OP_HASH160 ใช้ (ลบ) public key บนสุดและแทนที่ด้วยผลลัพธ์ของการแฮชด้วย RIPEMD160(SHA256(K)) ดังนั้นตอนนี้บนสุดของสแต็กคือแฮชของ public key ของบ็อบ ต่อไป  commitment ถูกเพิ่มไว้บนสุดของสแต็ก การดำเนินการ OP_EQUALVERIFY ใช้รายการสองรายการบนสุดและตรวจสอบว่าพวกมันเท่ากัน ซึ่งควรเป็นเช่นนั้นหาก public key ที่บ็อบให้ในสคริปต์อินพุตเป็น public key เดียวกันกับที่ใช้สร้างการยืนยันในสคริปต์เอาต์พุตที่อลิซจ่าย หาก OP_EQUALVERIFY ล้มเหลว ทั้งสคริปต์จะล้มเหลว สุดท้าย เราเหลือสแต็กที่มีเพียงลายเซ็นของบ็อบและ public key ของเขา รหัสปฏิบัติการ OP_CHECKSIG ตรวจสอบว่าพวกมันสอดคล้องกัน</p>
<blockquote>
<p>TIP: จากหลาม ถ้าอ่านตรงนี้และงง ๆ ผมไปทำรูปมาให้ดูง่ายขึ้นครับ</p>
</blockquote>
<p><img src="https://image.nostr.build/3ea1036b7de3d83b960d1ed862e738120159e4f173d55a4dfdaddc75c3b25166.png" alt="image"></p>
<p>แม้กระบวนการของการ pay-to-publickey-hash(P2PKH) อาจดูซับซ้อน แต่มันทำให้การที่อลิซจ่ายเงินให้บ็อบมีเพียงการยืนยันเพียง 20 ไบต์ต่อ public key ของเขาแทนที่จะเป็นตัวกุญแจเอง ซึ่งจะมีขนาด 65 ไบต์ในเวอร์ชันดั้งเดิมของบิทคอยน์ นั่นเป็นข้อมูลที่น้อยกว่ามากที่บ็อบต้องสื่อสารกับอลิซ</p>
<p>แต่อย่างไรก็ตาม เรายังไม่ได้พูดถึงวิธีที่บ็อบรับ 20 ไบต์เหล่านั้นจากกระเป๋าเงินบิทคอยน์ของเขาไปยังกระเป๋าเงินของอลิซ มีการเข้ารหัสค่าไบต์ที่ใช้กันอย่างแพร่หลาย เช่น เลขฐานสิบหก แต่ข้อผิดพลาดใด ๆ ในการคัดลอกการยืนยันจะทำให้บิทคอยน์ถูกส่งไปยังเอาต์พุตที่ไม่สามารถใช้จ่ายได้ ทำให้พวกมันสูญหายไปตลอดกาล โดยในส่วนถัดไป เราจะดูที่การเข้ารหัสแบบกะทัดรัดและการตรวจสอบความถูกต้อง</p>
<h4>Base58check Encoding</h4>
<p>ระบบคอมพิวเตอร์มีวิธีเขียนตัวเลขยาวๆ ให้สั้นลงโดยใช้ทั้งตัวเลขและตัวอักษรผสมกัน เพื่อใช้พื้นที่น้อยลงอย่างเช่น</p>
<ul>
<li>ระบบเลขฐานสิบ (ปกติที่เราใช้) - ใช้เลข 0-9 เท่านั้น</li>
<li>ระบบเลขฐานสิบหก - ใช้เลข 0-9 และตัวอักษร A-F ตัวอย่าง: เลข 255 ในระบบปกติ เขียนเป็น FF ในระบบเลขฐานสิบหก (สั้นกว่า)</li>
<li>ระบบเลขฐานหกสิบสี่ (Base64) - ใช้สัญลักษณ์ถึง 64 ตัว: ตัวอักษรเล็ก (a-z) 26 ตัว, ตัวอักษรใหญ่ (A-Z) 26 ตัว, ตัวเลข (0-9) 10 ตัว, สัญลักษณ์พิเศษอีก 2 ตัว ("+" และ "/")</li>
</ul>
<p>โดยระบบ Base64 นี้ช่วยให้เราส่งไฟล์คอมพิวเตอร์ผ่านข้อความธรรมดาได้ เช่น การส่งรูปภาพผ่านอีเมล โดยใช้พื้นที่น้อยกว่าการเขียนเป็นเลขฐานสิบแบบปกติมาก</p>
<p>การเข้ารหัสแบบ Base58 คล้ายกับ Base64 โดยใช้ตัวอักษรพิมพ์ใหญ่ พิมพ์เล็ก และตัวเลข แต่ได้ตัดตัวอักษรบางตัวที่มักถูกเข้าใจผิดว่าเป็นตัวอื่นและอาจดูเหมือนกันเมื่อแสดงในฟอนต์บางประเภทออกไป</p>
<p>Base58 คือ Base64 ที่ตัดตัวอักษรต่อไปนี้ออก:</p>
<ul>
<li>เลข 0 (ศูนย์)</li>
<li>ตัวอักษร O (ตัว O พิมพ์ใหญ่)</li>
<li>ตัวอักษร l (ตัว L พิมพ์เล็ก)</li>
<li>ตัวอักษร I (ตัว I พิมพ์ใหญ่)</li>
<li>และสัญลักษณ์ "+" และ "/"</li>
</ul>
<p>หรือพูดให้ง่ายขึ้น Base58 คือกลุ่มตัวอักษรพิมพ์เล็ก พิมพ์ใหญ่ และตัวเลข แต่ไม่มีตัวอักษรทั้งสี่ตัว (0, O, l, I) ที่กล่าวถึงข้างต้น ตัวอักษรทั้งหมดที่ใช้ใน Base58 จะแสดงให้เห็นในตัวอักษร Base58 ของบิทคอยน์</p>
<p>Example 2. Bitcoin’s base58 alphabet</p>
<pre><code>123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
</code></pre>
<p>การเพิ่มความปลอดภัยพิเศษเพื่อป้องกันการพิมพ์ผิดหรือข้อผิดพลาดในการคัดลอก base58check ได้รวม รหัสตรวจสอบ (checksum) ที่เข้ารหัสในตัวอักษร base58 เข้าไปด้วย รหัสตรวจสอบนี้คือข้อมูลเพิ่มเติมอีก 4 ไบต์ที่เพิ่มเข้าไปที่ท้ายของข้อมูลที่กำลังถูกเข้ารหัส</p>
<p>รหัสตรวจสอบนี้ได้มาจากการแฮชข้อมูลที่ถูกเข้ารหัส และจึงสามารถใช้เพื่อตรวจจับข้อผิดพลาดจากการคัดลอกและการพิมพ์ได้ เมื่อโปรแกรมได้รับรหัส base58check ซอฟต์แวร์ถอดรหัสจะคำนวณรหัสตรวจสอบของข้อมูลและเปรียบเทียบกับรหัสตรวจสอบที่รวมอยู่ในรหัสนั้น</p>
<p>หากทั้งสองไม่ตรงกัน แสดงว่ามีข้อผิดพลาดเกิดขึ้น และข้อมูล base58check นั้นไม่ถูกต้อง กระบวนการนี้ช่วยป้องกันไม่ให้ address บิทคอยน์ที่พิมพ์ผิดถูกยอมรับโดยซอฟต์แวร์กระเป๋าเงินว่าเป็น address ที่ถูกต้อง ซึ่งเป็นข้อผิดพลาดที่อาจส่งผลให้สูญเสียเงินได้</p>
<p>การแปลงข้อมูล (ตัวเลข) เป็นรูปแบบ base58check มีขั้นตอนดังนี้:</p>
<ol>
<li>เราเริ่มโดยการเพิ่ม prefix เข้าไปในข้อมูล เรียกว่า "version byte" ซึ่งช่วยให้ระบุประเภทของข้อมูลที่ถูกเข้ารหัสได้ง่าย ตัวอย่างเช่น: prefix ศูนย์ (0x00 ในระบบเลขฐานสิบหก) แสดงว่าข้อมูลควรถูกใช้เป็นการยืนยัน (hash) ในสคริปต์เอาต์พุต legacy P2PKH</li>
<li>จากนั้น เราคำนวณ "double-SHA" checksum ซึ่งหมายถึงการใช้อัลกอริทึมแฮช SHA256 สองครั้งกับผลลัพธ์ก่อนหน้า (prefix ต่อกับข้อมูล):<pre><code>checksum = SHA256(SHA256(prefix||data))
</code></pre>
</li>
<li>จากแฮช 32 ไบต์ที่ได้ (การแฮชซ้อนแฮช) เราเลือกเฉพาะ 4 ไบต์แรก ไบต์ทั้งสี่นี้ทำหน้าที่เป็นรหัสตรวจสอบข้อผิดพลาดหรือ checksum</li>
<li>นำ checksum นี้ไปต่อที่ท้ายข้อมูล</li>
</ol>
<p>การเข้ารหัสแบบ base58check คือรูปแบบการเข้ารหัสที่ใช้ base58 พร้อมกับการระบุเวอร์ชันและการตรวจสอบความถูกต้อง เพื่อการเข้ารหัสข้อมูลบิทคอยน์ โดยคุณสามารถดูภาพประกอบด้านล่างเพื่อความเข้าใจเพิ่มเติม</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0406.png" alt="image"></p>
<p>ในบิตคอยน์นั้น นอกจากจะใช้ base58check ในการยืนยัน public key แล้ว ก็ยังมีการใช้ในข้อมูลอื่น ๆ ด้วย เพื่อทำให้ข้อมูลนั้นกะทัดรัด อ่านง่าย และตรวจจับข้อผิดพลาดได้ง่ายด้วยรหัสนำหน้า (version prefix) ในการเข้ารหัสแบบ base58check ถูกใช้เพื่อสร้างรูปแบบที่แยกแยะได้ง่าย ซึ่งเมื่อเข้ารหัสด้วย base58 โดยจะมีตัวอักษรเฉพาะที่จุดเริ่มต้นของข้อมูลที่เข้ารหัส base58check ตัวอักษรเหล่านี้ช่วยให้เราระบุประเภทของข้อมูลที่ถูกเข้ารหัสและวิธีการใช้งานได้ง่าย นี่คือสิ่งที่แยกความแตกต่าง ตัวอย่างเช่น ระหว่าง address บิทคอยน์ที่เข้ารหัส base58check ซึ่งขึ้นต้นด้วยเลข 1 กับรูปแบบการนำเข้า private key  (WIF - Wallet Import Format) ที่เข้ารหัส base58check ซึ่งขึ้นต้นด้วยเลข 5 ตัวอย่างของ version prefix สามารถดูได้ตามตารางด้านล่างนี้</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742640432919-YAKIHONNES3.png" alt="image"></p>
<p>ภาพต่อไปนี้จะทำให้คุณเห็นภาพของกระบวนการแปลง public key ให้เป็น bitcoin address</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0407.png" alt="image"></p>
<h3>Compressed Public Keys</h3>
<p>ในยุคแรก ๆ ของบิตคอยน์นั้น มีเพียงการสร้าง public key แบบ 65 Bytes เท่านั้น แต่ในเวลาต่อมา เหล่านักพัฒนาในยุคหลังได้พบวิธีการสร้าง public key แบบใหม่ที่มีเพียง 33 Bytes และสามารถทำงานร่วมกันกับโหนดทั้งหมดในขณะนั้นได้ จีงไม่จะเป็นต้องเปลี่ยนแปลงกฎหรือโครงสร้างภายในโปรโตคอลของบิตคอยน์ โดย poublic key แบบใหม่ที่มีขนาด 33 Bytes นี้เรียกว่า compressed public key (public key ที่ถูกบีบอัด) และมีการเรียก public key ที่มีขนาด 65 Bytes ว่า uncompressed public key (public key ที่ไม่ถูกบีบอัด) ซึ่งประโยชน์ของ public key ที่เล็กลงนั้น นอกจากจะช่วยให้การส่ง public key ให้ผู้อื่นทำได้ง่ายขึ้นแล้ว ยังช่วยให้ธุรกรรมมีขนาดเล็กลง และช่วยให้สามารถทำการชำระเงินได้มากขึ้นในบล็อกเดียวกัน</p>
<p>อย่างที่เราได้เรียนรู้จากเนื้อหาในส่วนของ public key เราได้ทราบว่า public key คือจุด (x, y) บนเส้นโค้งวงรี เนื่องจากเส้นโค้งแสดงฟังก์ชันทางคณิตศาสตร์ จุดบนเส้นโค้งจึงเป็นคำตอบของสมการ ดังนั้นหากเรารู้พิกัด x เราก็สามารถคำนวณพิกัด y ได้โดยแก้สมการ y² mod p = (x³ + 7) mod p นั่นหมายความว่าเราสามารถเก็บเพียงพิกัด x ของ public key โดยละพิกัด y ไว้ ซึ่งช่วยลดขนาดของกุญแจและพื้นที่ที่ต้องใช้เก็บข้อมูลลง 256 บิต การลดขนาดลงเกือบ 50% ในทุกธุรกรรมรวมกันแล้วช่วยประหยัดข้อมูลได้มากมายในระยะยาว!</p>
<p>นี่คือ public key ที่ได้ยกเป็นตัวอย่างไว้ก่อนหน้า</p>
<pre><code>x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
</code></pre>
<p>และนี่คือ public key ที่มีตัวนำหน้า 04 ตามด้วยพิกัด x และ y ในรูปแบบ 04 x y:</p>
<pre><code>K = 04F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
</code></pre>
<p>uncompressed public key นั้นจะมีตัวนำหน้าเป็น 04 แต่ compressed public key จะมีตัวนำหน้าเป็น 02 หรือ 03 โดยเหตุผลนั้นมาจากสมการ y² mod p = (x³ + 7) mod p เนื่องจากด้านซ้ายของสมการคือ y² คำตอบสำหรับ y จึงเป็นรากที่สอง ซึ่งอาจมีค่าเป็นบวกหรือลบก็ได้ หากมองเชิงภาพ นี่หมายความว่าพิกัด y ที่ได้อาจอยู่เหนือหรือใต้แกน x เราต้องไม่ลืมว่าเส้นโค้งมีความสมมาตร ซึ่งหมายความว่ามันจะสะท้อนเหมือนกระจกโดยแกน x ดังนั้น แม้เราจะละพิกัด y ได้ แต่เราต้องเก็บ เครื่องหมาย ของ y (บวกหรือลบ) หรืออีกนัยหนึ่งคือเราต้องจำว่ามันอยู่เหนือหรือใต้แกน x เพราะแต่ละตำแหน่งแทนจุดที่แตกต่างกันและเป็น public key ที่แตกต่างกัน</p>
<p>เมื่อคำนวณเส้นโค้งวงรีในระบบเลขฐานสองบนสนามจำกัดของเลขจำนวนเฉพาะ p พิกัด y จะเป็นเลขคู่หรือเลขคี่ ซึ่งสอดคล้องกับเครื่องหมายบวก/ลบตามที่อธิบายก่อนหน้านี้ ดังนั้น เพื่อแยกความแตกต่างระหว่างค่าที่เป็นไปได้สองค่าของ y เราจึงเก็บ compressed public key ด้วยตัวนำหน้า 02 ถ้า y เป็นเลขคู่ และ 03 ถ้า y เป็นเลขคี่ ซึ่งช่วยให้ซอฟต์แวร์สามารถอนุมานพิกัด y จากพิกัด x และคลายการบีบอัดของ public key ไปยังพิกัดเต็มของจุดได้อย่างถูกต้อง ดังภาพประกอบต่อไปนี้</p>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0408.png" alt="image"></p>
<p>นี่คือ public key เดียวกันกับที่ยกตัวอย่างไว้ข้างต้นซึ่งแสดงให้เห็นในรูป compressed public key ที่เก็บใน 264 บิต (66 ตัวอักษรเลขฐานสิบหก) โดยมีตัวนำหน้า 03 ซึ่งบ่งชี้ว่าพิกัด y เป็นเลขคี่:</p>
<pre><code>K = 03F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
</code></pre>
<p>compressed public key สอดคล้องกับ private key เดียวกันกับ uncompressed public key หมายความว่ามันถูกสร้างจาก private key เดียวกัน แต่อย่างไรก็ตาม มันก็มีส่วนที่แตกต่างจาก uncompressed public key นั้นคือ หากเราแปลง compressed public key เป็น commitment โดยใช้ฟังก์ชัน HASH160 (RIPEMD160(SHA256(K))) มันจะสร้าง commitment ที่แตกต่างจาก uncompressed public key และจะนำไปสู่ bitcoin address ที่แตกต่างกันในที่สุด สิ่งนี้อาจทำให้สับสนเพราะหมายความว่า private key เดียวสามารถสร้าง public key ในสองรูปแบบที่แตกต่างกัน (แบบบีบอัดและแบบไม่บีบอัด) ซึ่งสร้าง bitcoin address ที่แตกต่างกัน</p>
<p>compressed public key เป็นค่าเริ่มต้นในซอฟต์แวร์บิตคอยน์เกือบทั้งหมดในปัจจุบัน และถูกกำหนดให้ใช้กับคุณสมบัติใหม่บางอย่างที่เพิ่มในการอัปเกรดโปรโตคอลในภายหลัง</p>
<p>อย่างไรก็ตาม ซอฟต์แวร์บางตัวยังคงต้องรองรับ uncompressed public key เช่น แอปพลิเคชันกระเป๋าเงินที่นำเข้า private key จากกระเป๋าเงินเก่า เมื่อกระเป๋าเงินใหม่สแกนบล็อกเชนสำหรับผลลัพธ์และอินพุต P2PKH เก่า มันจำเป็นต้องรู้ว่าควรสแกนกุญแจขนาด 65 ไบต์ (และ commitment ของกุญแจเหล่านั้น) หรือกุญแจขนาด 33 ไบต์ (และ commitment ของกุญแจเหล่านั้น) หากไม่สแกนหาประเภทที่ถูกต้อง อาจทำให้ผู้ใช้ไม่สามารถใช้ยอดคงเหลือทั้งหมดได้ เพื่อแก้ไขปัญหานี้ เมื่อส่งออก private key จากกระเป๋าเงิน WIF ที่ใช้แสดง private key ในกระเป๋าเงินบิตคอยน์รุ่นใหม่จะถูกนำไปใช้แตกต่างกันเล็กน้อยเพื่อบ่งชี้ว่า private key เหล่านี้ถูกใช้ในการสร้าง compressed public key</p>
<h4>Legacy: Pay to Script Hash (P2SH)</h4>
<p>ตามที่เราได้เห็นในส่วนก่อนหน้านี้ ผู้รับบิตคอยน์ สามารถกำหนดให้การชำระเงินที่ส่งมาให้เขานั้นมีเงื่อนไขบางอย่างในสคริปต์เอาต์พุตได้โดยจะต้องปฏิบัติตามเงื่อนไขเหล่านั้นโดยใช้สคริปต์อินพุตเมื่อเขาใช้จ่ายบิตคอยน์เหล่านั้น ในส่วน IP Addresses: The Original Address for Bitcoin (P2PK) เงื่อนไขก็คือสคริปต์อินพุตต้องให้ลายเซ็นที่เหมาะสม ในส่วน Legacy Addresses for P2PKH นั้นจำเป็นต้องมี public key ที่เหมาะสมด้วย</p>
<p>ส่วนสำหรับผู้ส่งก็จะวางเงื่อนไขที่ผู้รับต้องการในสคริปต์เอาต์พุตที่ใช้จ่ายให้กับผู้รับ โดยผู้รับจะต้องสื่อสารเงื่อนไขเหล่านั้นให้ผู้ส่งทราบ ซึ่งคล้ายกับปัญหาที่บ๊อบต้องสื่อสาร public key ของเขาให้อลิซทราบ และเช่นเดียวกับปัญหานั้นที่ public key อาจมีขนาดค่อนข้างใหญ่ เงื่อนไขที่บ๊อบใช้ก็อาจมีขนาดใหญ่มากเช่นกัน—อาจมีขนาดหลายพันไบต์ นั่นไม่เพียงแต่เป็นข้อมูลหลายพันไบต์ที่ต้องสื่อสารให้อลิซทราบ แต่ยังเป็นข้อมูลหลายพันไบต์ที่เธอต้องจ่ายค่าธรรมเนียมธุรกรรมทุกครั้งที่ต้องการใช้จ่ายเงินให้บ๊อบ อย่างไรก็ตาม การใช้ฟังก์ชันแฮชเพื่อสร้าง commitment ขนาดเล็กสำหรับข้อมูลขนาดใหญ่ก็สามารถนำมาใช้ได้ในกรณีนี้เช่นกัน</p>
<p>ในเวลาต่อมานั้น การอัปเกรด BIP16 สำหรับโปรโตคอลบิตคอยน์ในปี 2012 ได้อนุญาตให้สคริปต์เอาต์พุตสร้าง commitment กับ redemption script (redeem script) ได้ แปลว่าเมื่อบ๊อบใช้จ่ายบิตคอยน์ของเขา ภายในสคริปต์อินพุตของเขานั้นจะต้องให้ redeem script ที่ตรงกับ commitment และข้อมูลที่จำเป็นเพื่อให้เป็นไปตาม redeem script (เช่น ลายเซ็น) เริ่มต้นด้วยการจินตนาการว่าบ๊อบต้องการให้มีลายเซ็นสองอันเพื่อใช้จ่ายบิตคอยน์ของเขา หนึ่งลายเซ็นจากกระเป๋าเงินบนเดสก์ท็อปและอีกหนึ่งจากอุปกรณ์เซ็นแบบฮาร์ดแวร์ เขาใส่เงื่อนไขเหล่านั้นลงใน redeem script:</p>
<pre><code>&lt;public key 1&gt; OP_CHECKSIGVERIFY &lt;public key 2&gt; OP_CHECKSIG
</code></pre>
<p>จากนั้นเขาสร้าง commitment กับ redeem script โดยใช้กลไก HASH160 เดียวกับที่ใช้สำหรับ commitment แบบ P2PKH, RIPEMD160(SHA256(script)) commitment นั้นถูกวางไว้ในสคริปต์เอาต์พุตโดยใช้เทมเพลตพิเศษ:</p>
<pre><code>OP_HASH160 &lt;commitment&gt; OP_EQUAL
</code></pre>
<blockquote>
<p>คำเตือน: เมื่อใช้ pay to script hash (P2SH) คุณต้องใช้เทมเพลต P2SH โดยเฉพาะ ซึ่งจะไม่มีข้อมูลหรือเงื่อนไขเพิ่มเติมในสคริปต์เอาต์พุต หากสคริปต์เอาต์พุตไม่ได้เป็น OP_HASH160 &lt;20 ไบต์&gt; OP_EQUAL แน่นอนว่า redeem script จะไม่ถูกใช้และบิตคอยน์ใด ๆ อาจไม่สามารถใช้จ่ายได้หรืออาจถูกใช้จ่ายได้โดยทุกคน (หมายความว่าใครก็สามารถนำไปใช้ได้)</p>
</blockquote>
<p>เมื่อบ๊อบต้องการจ่ายเงินที่เขาได้รับผ่าน commitment สำหรับสคริปต์ของเขา เขาจะใช้สคริปต์อินพุตที่รวมถึง redeem script ซึ่งถูกแปลงให้เป็นข้อมูลอีลิเมนต์เดียว นอกจากนี้เขายังให้ลายเซ็นที่จำเป็นเพื่อให้เป็นไปตาม redeem script โดยเรียงลำดับตามที่จะถูกใช้โดย opcodes:</p>
<pre><code>&lt;signature2&gt; &lt;signature1&gt; &lt;redeem script&gt;
</code></pre>
<p>เมื่อโหนดของบิตคอยน์ได้รับการใช้จ่ายของบ๊อบพวกมันจะตรวจสอบว่า redeem script ที่ถูกแปลงเป็นค่าแฮชแล้วมีค่าเดียวกันกับ commitment มั้ย หลังจากนั้นพวกมันจะแทนที่มันบนสแต็คด้วยค่าที่ถอดรหัสแล้ว:</p>
<pre><code>&lt;signature2&gt; &lt;signature1&gt; &lt;pubkey1&gt; OP_CHECKSIGVERIFY &lt;pubkey2&gt; OP_CHECKSIG
</code></pre>
<p>สคริปต์จะถูกประมวลผล และหากผ่านการตรวจสอบและรายละเอียดธุรกรรมอื่น ๆ ทั้งหมดถูกต้อง ธุรกรรมก็จะถือว่าใช้ได้</p>
<p>address สำหรับ P2SH ก็ถูกสร้างด้วย base58check เช่นกัน คำนำหน้าเวอร์ชันถูกตั้งเป็น 5 ซึ่งทำให้ที่อยู่ที่เข้ารหัสแล้วขึ้นต้นด้วยเลข 3 ตัวอย่างของที่อยู่ P2SH คือ 3F6i6kwkevjR7AsAd4te2YB2zZyASEm1HM</p>
<blockquote>
<p>TIP: P2SH ไม่จำเป็นต้องเหมือนกับธุรกรรมแบบหลายลายเซ็น (multisignature) เสมอไป ถึง address P2SH ส่วนใหญ่ แทนสคริปต์แบบหลายลายเซ็นก็ตาม แต่อาจแทนสคริปต์ที่เข้ารหัสธุรกรรมประเภทอื่น ๆ ได้ด้วย</p>
</blockquote>
<p>P2PKH และ P2SH เป็นสองเทมเพลตสคริปต์เท่านั้นที่ใช้กับการเข้ารหัสแบบ base58check พวกมันเป็นที่รู้จักในปัจจุบันว่าเป็น address แบบ legacy และกลายเป็นรูปแบบที่พบน้อยลงเรื่อยๆ address แบบ legacy ถูกแทนที่ด้วยaddress ตระกูล bech32</p>
<h4>การโจมตี P2SH แบบ Collision</h4>
<p>address ทั้งหมดที่อิงกับฟังก์ชันแฮชมีความเสี่ยงในทางทฤษฎีต่อผู้โจมตีที่อาจค้นพบอินพุตเดียวกันที่สร้างเอาต์พุตฟังก์ชันแฮช (commitment) โดยอิสระ ในกรณีของบิตคอยน์ หากพวกเขาค้นพบอินพุตในวิธีเดียวกับที่ผู้ใช้ดั้งเดิมทำ พวกเขาจะรู้ private key ของผู้ใช้และสามารถใช้จ่ายบิตคอยน์ของผู้ใช้นั้นได้ โอกาสที่ผู้โจมตีจะสร้างอินพุตสำหรับ commitment ที่มีอยู่แล้วโดยอิสระนั้นขึ้นอยู่กับความแข็งแกร่งของอัลกอริทึมแฮช สำหรับอัลกอริทึมที่ปลอดภัย 160 บิตอย่าง HASH160 ความน่าจะเป็นอยู่ที่ 1 ใน 2^160 นี่เรียกว่าการโจมตีแบบ preimage attack</p>
<p>ผู้โจมตีสามารถพยายามสร้างข้อมูลนำเข้าสองชุดที่แตกต่างกัน (เช่น redeem scripts) ที่สร้างการเข้ารหัสแบบเดียวกันได้ สำหรับ address ที่สร้างโดยฝ่ายเดียวทั้งหมด โอกาสที่ผู้โจมตีจะสร้างข้อมูลนำเข้าที่แตกต่างสำหรับการเข้ารหัสที่มีอยู่แล้วมีประมาณ 1 ใน 2^160 สำหรับอัลกอริทึม HASH160 นี่คือการโจมตีแบบ second preimage attack </p>
<p>อย่างไรก็ตาม สถานการณ์จะเปลี่ยนไปเมื่อผู้โจมตีสามารถมีอิทธิพลต่อค่าข้อมูลนำเข้าดั้งเดิมได้ ตัวอย่างเช่น ผู้โจมตีมีส่วนร่วมในการสร้างสคริปต์แบบหลายลายเซ็น (multisignature script) ซึ่งพวกเขาไม่จำเป็นต้องส่ง public key ของตนจนกว่าจะทราบ public key ของฝ่ายอื่นทั้งหมด ในกรณีนั้น ความแข็งแกร่งของอัลกอริทึมการแฮชจะลดลงเหลือรากที่สองของมัน สำหรับ HASH160 ความน่าจะเป็นจะกลายเป็น 1 ใน 2^80 นี่คือการโจมตีแบบ collision attack</p>
<p>เพื่อให้เข้าใจตัวเลขเหล่านี้ในบริบทที่ชัดเจน ข้อมูล ณ ต้นปี 2023 นักขุดบิตคอยน์ทั้งหมดรวมกันสามารถประมวลผลฟังก์ชันแฮชประมาณ 2^80 ทุกชั่วโมง พวกเขาใช้ฟังก์ชันแฮชที่แตกต่างจาก HASH160 ดังนั้นฮาร์ดแวร์ที่มีอยู่จึงไม่สามารถสร้างการโจมตีแบบ collision attack สำหรับมันได้ แต่การมีอยู่ของเครือข่ายบิตคอยน์พิสูจน์ว่าการโจมตีแบบชนกันต่อฟังก์ชัน 160 บิตอย่าง HASH160 สามารถทำได้จริงในทางปฏิบัติ นักขุดบิตคอยน์ได้ลงทุนเทียบเท่ากับหลายพันล้านดอลลาร์สหรัฐในฮาร์ดแวร์พิเศษ ดังนั้นการสร้างการโจมตีแบบ collision attack จึงไม่ใช่เรื่องถูก แต่มีองค์กรที่คาดหวังว่าจะได้รับบิตคอยน์มูลค่าหลายพันล้านดอลลาร์ไปยัง address ที่สร้างโดยกระบวนการที่เกี่ยวข้องกับหลายฝ่าย ซึ่งอาจทำให้การโจมตีนี้มีกำไร</p>
<p>มีโปรโตคอลการเข้ารหัสที่เป็นที่ยอมรับอย่างดีในการป้องกันการโจมตีแบบ collision attack แต่วิธีแก้ปัญหาที่ง่ายโดยไม่ต้องใช้ความรู้พิเศษจากผู้พัฒนากระเป๋าเงินคือการใช้ฟังก์ชันแฮชที่แข็งแกร่งกว่า การอัปเกรดบิตคอยน์ในภายหลังทำให้เป็นไปได้ และ address บิตคอยน์ใหม่ให้ความต้านทานการชนกันอย่างน้อย 128 บิต การดำเนินการแฮช 2^128 ครั้งจะใช้เวลานักขุดบิตคอยน์ปัจจุบันทั้งหมดประมาณ 32 พันล้านปี</p>
<p>แม้ว่าเราไม่เชื่อว่ามีภัยคุกคามเร่งด่วนต่อผู้ที่สร้าง address P2SH ใหม่ แต่เราแนะนำให้กระเป๋าเงินใหม่ทั้งหมดใช้ที่อยู่ประเภทใหม่เพื่อขจัดความกังวลเกี่ยวกับการโจมตีแบบ collision attack ของ P2SH address</p>
<h4>Bech32 Addresses</h4>
<p>ในปี 2017 โปรโตคอลบิตคอยน์ได้รับการอัปเกรด เพื่อป้องกันไม่ให้ตัวระบุธุรกรรม (txids) ไม่สามารถเปลี่ยนแปลงได้ โดยไม่ได้รับความยินยอมจากผู้ใช้ที่ทำการใช้จ่าย (หรือองค์ประชุมของผู้ลงนามเมื่อต้องมีลายเซ็นหลายรายการ) การอัปเกรดนี้เรียกว่า segregated witness (หรือเรียกสั้นๆ ว่า segwit) ซึ่งยังให้ความสามารถเพิ่มเติมสำหรับข้อมูลธุรกรรมในบล็อกและประโยชน์อื่น ๆ อีกหลายประการ แต่อย่างไรก็ตาม หากมีผู้ใช้เก่าที่ต้องการเข้าถึงประโยชน์ของ segwit โดยตรงต้องยอมรับการชำระเงินไปยังสคริปต์เอาต์พุตใหม่</p>
<p>ตามที่ได้กล่าวไว้ใน p2sh หนึ่งในข้อดีของเอาต์พุตประเภท P2SH คือผู้จ่ายไม่จำเป็นต้องรู้รายละเอียดของสคริปต์ที่ผู้รับใช้ การอัปเกรด segwit ถูกออกแบบมาให้ใช้กลไกนี้ได้ดังเดิม จึง ทำให้ผู้จ่ายสามารถเริ่มเข้าถึงประโยชน์ใหม่ ๆ หลายอย่างได้ทันทีโดยใช้ที่อยู่ P2SH แต่เพื่อให้ผู้รับสามารถเข้าถึงประโยชน์เหล่านั้นได้ พวกเขาจำเป็นจะต้องให้กระเป๋าเงินของผู้จ่ายจ่ายเงินให้เขาโดยใช้สคริปต์ประเภทอื่นแทน ซึ่งจะต้องอาศัยการอัปเกรดกระเป๋าเงินของผู้จ่ายเพื่อรองรับสคริปต์ใหม่เหล่านี้</p>
<p>ในช่วงแรก เหล่านักพัฒนาบิตคอยน์ได้นำเสนอ BIP142 ซึ่งจะยังคงใช้ base58check ร่วมกับไบต์เวอร์ชันใหม่ คล้ายกับการอัปเกรด P2SH แต่การให้กระเป๋าเงินทั้งหมดอัปเกรดไปใช้สคริปต์ใหม่ที่มีเวอร์ชัน base58check ใหม่นั้น คาดว่าจะต้องใช้ความพยายามเกือบเท่ากับการให้พวกเขาอัปเกรดไปใช้รูปแบบ address ที่เป็นแบบใหม่ทั้งหมด ด้วยเหตุนี้้เอง ผู้สนับสนุนบิตคอยน์หลายคนจึงเริ่มออกแบบรูปแบบ address ที่ดีที่สุดเท่าที่เป็นไปได้ พวกเขาระบุปัญหาหลายอย่างกับ base58check ไว้ดังนี้:</p>
<ul>
<li>การที่ base58check ใช้อักษรที่มีทั้งตัวพิมพ์ใหญ่และตัวพิมพ์เล็กทำให้ไม่สะดวกในการอ่านออกเสียงหรือคัดลอก ลองอ่าน address แบบเก่าในบทนี้ให้เพื่อนฟังและให้พวกเขาคัดลอก คุณจะสังเกตว่าคุณต้องระบุคำนำหน้าทุกตัวอักษรด้วยคำว่า "ตัวพิมพ์ใหญ่" และ "ตัวพิมพ์เล็ก" และเมื่อคุณตรวจสอบสิ่งที่พวกเขาเขียน คุณจะพบว่าตัวพิมพ์ใหญ่และตัวพิมพ์เล็กของตัวอักษรบางตัวอาจดูคล้ายกันในลายมือของคนส่วนใหญ่</li>
<li>รูปแบบนี้สามารถตรวจจับข้อผิดพลาดได้ แต่ไม่สามารถช่วยผู้ใช้แก้ไขข้อผิดพลาดเหล่านั้น ตัวอย่างเช่น หากคุณสลับตำแหน่งตัวอักษรสองตัวโดยไม่ตั้งใจเมื่อป้อน address ด้วยตนเอง กระเป๋าเงินของคุณจะเตือนว่ามีข้อผิดพลาดเกิดขึ้นแน่นอน แต่จะไม่ช่วยให้คุณค้นพบว่าข้อผิดพลาดอยู่ที่ไหน คุณอาจต้องใช้เวลาหลายนาทีที่น่าหงุดหงิดเพื่อค้นหาข้อผิดพลาดในที่สุด</li>
<li>การใช้ตัวอักษรที่มีทั้งตัวพิมพ์ใหญ่และตัวพิมพ์เล็กยังต้องใช้พื้นที่เพิ่มเติมในการเข้ารหัสใน QR code ซึ่งนิยมใช้ในการแชร์ address และ invoice ระหว่างกระเป๋าเงิน พื้นที่เพิ่มเติมนี้หมายความว่า QR code จำเป็นต้องมีขนาดใหญ่ขึ้นที่ความละเอียดเดียวกัน หรือไม่เช่นนั้นก็จะยากต่อการสแกนอย่างรวดเร็ว</li>
<li>การที่ต้องการให้กระเป๋าเงินผู้จ่ายทุกใบอัปเกรดเพื่อรองรับคุณสมบัติโปรโตคอลใหม่ เช่น P2SH และ segwit แม้ว่าการอัปเกรดเองอาจไม่ต้องใช้โค้ดมากนัก แต่ประสบการณ์แสดงให้เห็นว่าผู้พัฒนากระเป๋าเงินหลายรายมักยุ่งกับงานอื่น ๆ และบางครั้งอาจล่าช้าในการอัปเกรดเป็นเวลาหลายปี สิ่งนี้ส่งผลเสียต่อทุกคนที่ต้องการใช้คุณสมบัติใหม่ ๆ เหล่านี้</li>
</ul>
<p>นักพัฒนาที่ทำงานเกี่ยวกับรูปแบบ address สำหรับ segwit ได้พบวิธีแก้ปัญหาเหล่านี้ทั้งหมดในรูปแบบ address แบบใหม่ที่เรียกว่า bech32 (ออกเสียงด้วย "ch" อ่อน เช่นใน "เบช สามสิบสอง") คำว่า "bech" มาจาก BCH ซึ่งเป็นอักษรย่อของบุคคลสามคนที่ค้นพบรหัสวนนี้ในปี 1959 และ 1960 ซึ่งเป็นพื้นฐานของ bech32 ส่วน "32" หมายถึงจำนวนตัวอักษรในชุดตัวอักษร bech32 (คล้ายกับ 58 ใน base58check):</p>
<ul>
<li><p>Bech32 ใช้เฉพาะตัวเลขและตัวอักษรรูปแบบเดียว (โดยปกติจะแสดงเป็นตัวพิมพ์เล็ก) แม้ว่าชุดตัวอักษรของมันจะมีขนาดเกือบครึ่งหนึ่งของชุดตัวอักษรใน base58check ก็ตามแต่ address bech32 สำหรับสคริปต์ pay to witness public key hash (P2WPKH) ก็ยังยาวกว่า legacy address และมีขนาดเท่ากันกับสคริปต์ P2PKH </p>
</li>
<li><p>Bech32 สามารถทั้งตรวจจับและช่วยแก้ไขข้อผิดพลาดได้ ใน address ที่มีความยาวตามที่คาดหวังได้ และสามารถรับประกันทางคณิตศาสตร์ได้ว่าจะตรวจพบข้อผิดพลาดใด ๆ ที่ส่งผลกระทบต่อตัวอักษร 4 ตัวหรือน้อยกว่า ซึ่งเชื่อถือได้มากกว่า base58check ส่วนสำหรับข้อผิดพลาดที่ยาวกว่านั้น จะไม่สามารถตรวจพบได้ (โอกาสเกิดน้อยกว่าหนึ่งครั้งในหนึ่งพันล้าน) ซึ่งมีความเชื่อถือได้ประมาณเท่ากับ base58check ยิ่งไปกว่านั้น สำหรับ adddress ที่พิมพ์โดยมีข้อผิดพลาดเพียงเล็กน้อย มันสามารถบอกผู้ใช้ได้ว่าข้อผิดพลาดเหล่านั้นเกิดขึ้นที่ไหน ช่วยให้พวกเขาสามารถแก้ไขข้อผิดพลาดจากการคัดลอกเล็ก ๆ น้อย ๆ ได้อย่างรวดเร็ว </p>
</li>
<li><p>ตัวอย่างที่ 3 Bech32 address ที่มีข้อผิดพลาด<br>Address: bc1p9nh05ha8wrljf7ru236awn4t2x0d5ctkkywmv9sclnm4t0av2vgs4k3au7<br>ข้อผิดพลาดที่ตรวจพบแสดงเป็นตัวหนาและขีดเส้นใต้ สร้างโดยใช้โปรแกรมสาธิตการถอดรหัส  bech32 address</p>
</li>
<li><p>bech32 address นิยมเขียนด้วยตัวอักษรพิมพ์เล็กเท่านั้น แต่ตัวอักษรพิมพ์เล็กเหล่านี้สามารถแทนที่ด้วยตัวอักษรพิมพ์ใหญ่ก่อนการเข้ารหัส address ในรหัส QR ได้ วิธีนี้ช่วยให้สามารถใช้โหมดการเข้ารหัส QR แบบพิเศษที่ใช้พื้นที่น้อยกว่า คุณจะสังเกตเห็นความแตกต่างในขนาดและความซับซ้อนของรหัส QR ทั้งสองสำหรับที่อยู่เดียวกันในรูปภาพข้างล่างนี้</p>
</li>
</ul>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0409.png" alt="image"></p>
<ul>
<li>Bech32 ใช้ประโยชน์จากกลไกการอัปเกรดที่ออกแบบมาเป็นส่วนหนึ่งของ segwit เพื่อทำให้กระเป๋าเงินผู้จ่ายสามารถจ่ายเงินไปยังประเภทเอาต์พุตที่ยังไม่ได้ใช้งานได้ โดยมีเป้าหมายคือการอนุญาตให้นักพัฒนาสร้างกระเป๋าเงินในวันนี้ที่สามารถใช้จ่ายไปยัง bech32 address และทำให้กระเป๋าเงินนั้นยังคงสามารถใช้จ่ายไปยัง bech32address ได้สำหรับผู้ใช้คุณสมบัติใหม่ที่เพิ่มในการอัปเกรดโปรโตคอลในอนาคต โดยที่มีความหวังว่าเราอาจไม่จำเป็นต้องผ่านรอบการอัปเกรดทั้งระบบอีกต่อไป ซึ่งจำเป็นสำหรับการให้ผู้คนใช้งาน P2SH และ segwit ได้อย่างเต็มรูปแบบ</li>
<li></li>
<li><h4>Problems with Bech32 Addresses</h4>
</li>
</ul>
<p>address แบบ bech32 ประสบความสำเร็จในทุกด้านยกเว้นปัญหาหนึ่ง คือการรับประกันทางคณิตศาสตร์เกี่ยวกับความสามารถในการตรวจจับข้อผิดพลาดจะใช้ได้เฉพาะเมื่อความยาวของ address ที่คุณป้อนเข้าไปในกระเป๋าเงินมีความยาวเท่ากับ address ดั้งเดิมเท่านั้น หากคุณเพิ่มหรือลบตัวอักษรใด ๆ ระหว่างการคัดลอกจะทำให้ไม่สามารถตรวจจับได้ การรับประกันนี้จะไม่มีผล และกระเป๋าเงินของคุณอาจใช้จ่ายเงินไปยัง address ที่ไม่ถูกต้อง แต่อย่างไรก็ตาม แม้จะไม่มีคุณสมบัตินี้ มีความเชื่อว่าเป็นไปได้ยากมากที่ผู้ใช้ที่เพิ่มหรือลบตัวอักษรจะสร้างสตริงที่มีผลรวมตรวจสอบที่ถูกต้อง ซึ่งช่วยให้มั่นใจได้ว่าเงินของผู้ใช้จะปลอดภัย</p>
<p>น่าเสียดายที่การเลือกใช้ค่าคงที่ตัวหนึ่งในอัลกอริทึม bech32 บังเอิญทำให้การเพิ่มหรือลบตัวอักษร "q" ในตำแหน่งที่สองจากท้ายของ address ที่ลงท้ายด้วยตัวอักษร "p" เป็นเรื่องง่ายมาก ในกรณีเหล่านั้น คุณยังสามารถเพิ่มหรือลบตัวอักษร "q" หลายครั้งได้ด้วย ข้อผิดพลาดนี้จะถูกตรวจจับโดยผลรวมตรวจสอบ (checksum) ในบางครั้ง แต่จะถูกมองข้ามบ่อยกว่าความคาดหวังหนึ่งในพันล้านสำหรับข้อผิดพลาดจากการแทนที่ของ bech32 อย่างมาก สำหรับตัวอย่างสามารถดูได้ในรูปภาพข้างล่างนี้</p>
<p>ตัวอย่างที่ 4. การขยายความยาวของ bech32 address โดยไม่ทำให้ผลรวมตรวจสอบเป็นโมฆะ</p>
<pre><code>bech32 address ที่ถูกต้อง:
bc1pqqqsq9txsqp

address ที่ไม่ถูกต้องแต่มีผลรวมตรวจสอบที่ถูกต้อง:
bc1pqqqsq9txsqqqqp
bc1pqqqsq9txsqqqqqqp
bc1pqqqsq9txsqqqqqqqqp
bc1pqqqsq9txsqqqqqqqqqp
bc1pqqqsq9txsqqqqqqqqqqqp
</code></pre>
<p>จากตัวอย่างนี้ คุณจะเห็นว่าแม้มีการเพิ่มตัวอักษร "q" เข้าไปหลายตัวก่อนตัวอักษร "p" ตัวสุดท้าย ระบบตรวจสอบก็ยังคงยอมรับว่า address เหล่านี้ถูกต้อง นี่เป็นข้อบกพร่องสำคัญของ bech32 เพราะอาจทำให้เงินถูกส่งไปยัง address ที่ไม่มีใครเป็นเจ้าของจริง ๆ หรือ address ที่ไม่ได้ตั้งใจจะส่งไป</p>
<p>สำหรับเวอร์ชันเริ่มต้นของ segwit (เวอร์ชัน 0) ปัญหานี้ไม่ใช่ความกังวลในทางปฏิบัติ เพราะมีความยาวที่ถูกต้องมีเพียงสองแบบที่กำหนดไว้สำหรับเอาต์พุต นั้นคือ 22 Byte และ 34 Byte ซึ่งสอดคล้องกับ bech32 address ที่มีความยาวยาวที่ 42 หรือ 62 ตัวอักษร ดังนั้นคนจะต้องเพิ่มหรือลบตัวอักษร "q" จากตำแหน่งที่สองจากท้ายของ bech32 address ถึง 20 ครั้งเพื่อส่งเงินไปยัง address ที่ไม่ถูกต้องโดยที่กระเป๋าเงินไม่สามารถตรวจจับได้ อย่างไรก็ตาม มันอาจกลายเป็นปัญหาสำหรับผู้ใช้ในอนาคตหากมีการนำการอัปเกรดบนพื้นฐานของ segwit มาใช้</p>
<h4>Bech32m</h4>
<p>แม้ว่า bech32 จะทำงานได้ดีสำหรับ segwit v0 แต่นักพัฒนาไม่ต้องการจำกัดขนาดเอาต์พุตโดยไม่จำเป็นในเวอร์ชันหลังๆ ของ segwit หากไม่มีข้อจำกัด การเพิ่มหรือลบตัวอักษร "q" เพียงตัวเดียวใน bech32 address อาจทำให้ผู้ใช้ส่งเงินโดยไม่ตั้งใจไปยังเอาต์พุตที่ไม่สามารถใช้จ่ายได้หรือสามารถใช้จ่ายได้โดยทุกคน (ทำให้บิตคอยน์เหล่านั้นถูกนำไปโดยทุกคนได้) นักพัฒนาได้วิเคราะห์ปัญหา bech32 อย่างละเอียดและพบว่าการเปลี่ยนค่าคงที่เพียงตัวเดียวในอัลกอริทึมของพวกเขาจะขจัดปัญหานี้ได้ ทำให้มั่นใจว่าการแทรกหรือลบตัวอักษรสูงสุดห้าตัวจะไม่ถูกตรวจจับน้อยกว่าหนึ่งครั้งในหนึ่งพันล้านเท่านั้น</p>
<p>เวอร์ชันของ bech32 ที่มีค่าคงที่เพียงหนึ่งตัวที่แตกต่างกันเรียกว่า bech32 แบบปรับแต่ง (bech32m) ตัวอักษรทั้งหมดใน address แบบ bech32 และ bech32m สำหรับข้อมูลพื้นฐานเดียวกันจะเหมือนกันทั้งหมด ยกเว้นหกตัวสุดท้าย (ซึ่งเป็นส่วนของ checksum) นั่นหมายความว่ากระเป๋าเงินจำเป็นต้องรู้ว่ากำลังใช้เวอร์ชันใดเพื่อตรวจสอบความถูกต้องของ checksum แต่ address ทั้งสองประเภทมีไบต์เวอร์ชันภายในที่ทำให้การระบุเวอร์ชันที่ใช้อยู่เป็นเรื่องที่ง่าย<br>ในการทำงานกับทั้ง bech32 และ bech32m เราจะพิจารณากฎการเข้ารหัสและการแยกวิเคราะห์สำหรับ address บิตคอยน์แบบ bech32m เนื่องจากพวกมันครอบคลุมความสามารถในการแยกวิเคราะห์บน address แบบ bech32 และเป็นรูปแบบ address ที่แนะนำในปัจจุบันสำหรับกระเป๋าเงินบิตคอยน์</p>
<blockquote>
<p>ข้อความจากหลาม: คือผมว่าตรงนี้เขาเขียนไม่รู้เรื่อง แต่เดาว่าเขาน่าจะสื่อว่า เราควรเรียนรู้วิธีการทำงานกับ bech32m เพราะมันเป็นรูปแบบที่แนะนำให้ใช้ในปัจจุบัน และมันมีข้อดีเพราะbech32m สามารถรองรับการอ่าน address แบบ bech32 แบบเก่าได้ด้วย ง่ายๆ คือ ถ้าคุณเรียนรู้วิธีทำงานกับ bech32m คุณจะสามารถทำงานกับทั้ง bech32m และ bech32 ได้ทั้งสองแบบ</p>
</blockquote>
<p>bech32m address ริ่มต้นด้วยส่วนที่มนุษย์อ่านได้ (Human Readable Part: HRP) BIP173 มีกฎสำหรับการสร้าง HRP ของคุณเอง แต่สำหรับบิตคอยน์ คุณเพียงแค่จำเป็นต้องรู้จัก HRP ที่ถูกเลือกไว้แล้วตามที่แสดงในตารางข้างล่างนี้</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641071606-YAKIHONNES3.png" alt="image"></p>
<p>ส่วน HRP ตามด้วยตัวคั่น ซึ่งก็คือเลข "1" ในข้อเสนอก่อนหน้านี้สำหรับตัวคั่นโปรโตคอลได้ใช้เครื่องหมายทวิภาค (colon) แต่ระบบปฏิบัติการและแอปพลิเคชันบางตัวที่อนุญาตให้ผู้ใช้ดับเบิลคลิกคำเพื่อไฮไลต์สำหรับการคัดลอกและวางนั้นจะไม่ขยายการไฮไลต์ไปถึงและผ่านเครื่องหมายทวิภาค</p>
<p>การใช้ตัวเลขช่วยให้มั่นใจได้ว่าการไฮไลต์ด้วยดับเบิลคลิกจะทำงานได้กับโปรแกรมใดๆ ที่รองรับสตริง bech32m โดยทั่วไป (ซึ่งรวมถึงตัวเลขอื่นๆ ด้วย) เลข "1" ถูกเลือกเพราะสตริง bech32 ไม่ได้ใช้เลข 1 ในกรณีอื่น เพื่อป้องกันการแปลงโดยไม่ตั้งใจระหว่างเลข "1" กับตัวอักษรพิมพ์เล็ก "l"</p>
<p>และส่วนอื่นของ bech32m address เรียกว่า "ส่วนข้อมูล" (data part) ซึ่งประกอบด้วยสามองค์ประกอบ:</p>
<ul>
<li><strong>Witness version:</strong> ไบต์ถัดไปหลังจากตัวคั่นตัวอักษรนี้แทนเวอร์ชันของ segwit ตัวอักษร "q" คือการเข้ารหัสของ "0" สำหรับ segwit v0 ซึ่งเป็นเวอร์ชันแรกของ segwit ที่มีการแนะนำที่อยู่ bech32 ตัวอักษร "p" คือการเข้ารหัสของ "1" สำหรับ segwit v1 (หรือเรียกว่า taproot) ซึ่งเริ่มมีการใช้งาน bech32m มีเวอร์ชันที่เป็นไปได้ทั้งหมด 17 เวอร์ชันของ segwit และสำหรับ Bitcoin จำเป็นต้องให้ไบต์แรกของส่วนข้อมูล bech32m ถอดรหัสเป็นตัวเลข 0 ถึง 16 (รวมทั้งสองค่า)</li>
<li><strong>Witness program:</strong> คือตำแหน่งหลังจาก witnessversion ตั้งแต่ตำแหน่ง 2 ถึง 40 Byte สำหรับ segwit v0 นี้ต้องมีความยาว 20 หรือ 32 Byte ไม่สามารถ<br>ffมีขนาดอื่นได้ สำหรับ segwit v1 ความยาวเดียวที่ถูกกำหนดไว้ ณ เวลาที่เขียนนี้คือ 32 ไบต์ แต่อาจมีการกำหนดความยาวอื่น ๆ ได้ในภายหลัง</li>
<li><strong>Checksum:</strong> มีความยาว 6 ตัวอักษร โดยส่วนนี้ถูกสร้างขึ้นโดยใช้รหัส BCH ซึ่งเป็นประเภทของรหัสแก้ไขข้อผิดพลาด (error corection code) (แต่อย่างไรก็ตาม สำหรับ address บิตคอยน์ เราจะเห็นในภายหลังว่าเป็นสิ่งสำคัญที่จะใช้ checksum เพื่อการตรวจจับข้อผิดพลาดเท่านั้น—ไม่ใช่การแก้ไข</li>
</ul>
<p>ในส่วนต่อไปหลังจากนี้เราจะลองสร้าง address แบบ bech32 และ bech32m สำหรับตัวอย่างทั้งหมดต่อไปนี้ เราจะใช้โค้ดอ้างอิง bech32m สำหรับ Python</p>
<p>เราจะเริ่มด้วยการสร้างสคริปต์เอาต์พุตสี่ตัว หนึ่งตัวสำหรับแต่ละเอาต์พุต segwit ที่แตกต่างกันที่ใช้ในช่วงเวลาของการเผยแพร่ บวกกับอีกหนึ่งตัวสำหรับเวอร์ชัน segwit ในอนาคตที่ยังไม่มีความหมายที่กำหนดไว้ สคริปต์เหล่านี้แสดงอยู่ในตารางข้างล่างนี้<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641245046-YAKIHONNES3.png" alt="image"></p>
<p>สำหรับเอาต์พุต P2WPKH witness program มีการผูก commitment ที่สร้างขึ้นในลักษณะเดียวกันกับ P2PKH ที่เห็นใน Legacy Addresses for P2PKH โดย public key ถูกส่งเข้าไปในฟังก์ชันแฮช SHA256 ไดเจสต์ขนาด 32 ไบต์ที่ได้จะถูกส่งเข้าไปในฟังก์ชันแฮช RIPEMD-160 ไดเจสต์ของฟังก์ชันนั้น จะถูกวางไว้ใน witness program</p>
<p>สำหรับเอาต์พุตแบบ pay to witness script hash (P2WSH) เราไม่ได้ใช้อัลกอริทึม P2SH แต่เราจะนำสคริปต์ ส่งเข้าไปในฟังก์ชันแฮช SHA256 และใช้ไดเจสต์ขนาด 32 ไบต์ของฟังก์ชันนั้นใน witness program สำหรับ P2SH ไดเจสต์ SHA256 จะถูกแฮชอีกครั้งด้วย RIPEMD-160 ซึ่งแน่นอนว่าอาจจะไม่ปลอดภัย ในบางกรณี สำหรับรายละเอียด ดูที่ P2SH Collision Attacks ผลลัพธ์ของการใช้ SHA256 โดยไม่มี RIPEMD-160 คือ การผูกพันแบบ P2WSH มีขนาด 32 ไบต์ (256 บิต) แทนที่จะเป็น 20 ไบต์ (160 บิต)</p>
<p>สำหรับเอาต์พุตแบบ pay-to-taproot (P2TR) witness program คือจุดบนเส้นโค้ง secp256k1 มันอาจเป็น public key แบบธรรมดา แต่ในกรณีส่วนใหญ่มันควรเป็น public key ที่ผูกพันกับข้อมูลเพิ่มเติมบางอย่าง เราจะเรียนรู้เพิ่มเติมเกี่ยวกับการผูกพันนั้นในหัวข้อของ taproot</p>
<p>สำหรับตัวอย่างของเวอร์ชัน segwit ในอนาคต เราเพียงแค่ใช้หมายเลขเวอร์ชัน segwit ที่สูงที่สุดที่เป็นไปได้ (16) และ witness program ที่มีขนาดเล็กที่สุดที่อนุญาต (2 ไบต์) โดยมีค่าเป็นศูนย์ (null value)</p>
<p>เมื่อเรารู้หมายเลขเวอร์ชันและ witness program แล้ว เราสามารถแปลงแต่ละอย่างให้เป็น bech32 address ได้ โดยการใช้ไลบรารีอ้างอิง bech32m สำหรับ Python เพื่อสร้าง address เหล่านั้นอย่างรวดเร็ว และจากนั้นมาดูอย่างละเอียดว่าเกิดอะไรขึ้น:</p>
<pre><code>$ github=" https://raw.githubusercontent.com"
$ wget $github/sipa/bech32/master/ref/python/segwit_addr.py
$ python
&gt;&gt;&gt; from segwit_addr import *
&gt;&gt;&gt; from binascii import unhexlify
&gt;&gt;&gt; help(encode)
encode(hrp, witver, witprog)
    Encode a segwit address.
&gt;&gt;&gt; encode('bc', 0, unhexlify('2b626ed108ad00a944bb2922a309844611d25468'))
'bc1q9d3xa5gg45q2j39m9y32xzvygcgay4rgc6aaee'
&gt;&gt;&gt; encode('bc', 0,
unhexlify('648a32e50b6fb7c5233b228f60a6a2ca4158400268844c4bc295ed5e8c3d626f'))
'bc1qvj9r9egtd7mu2gemy28kpf4zefq4ssqzdzzycj7zjhk4arpavfhsct5a3p'
&gt;&gt;&gt; encode('bc', 1,
unhexlify('2ceefa5fa770ff24f87c5475d76eab519eda6176b11dbe1618fcf755bfac5311'))
'bc1p9nh05ha8wrljf7ru236awm4t2x0d5ctkkywmu9sclnm4t0av2vgs4k3au7'
&gt;&gt;&gt; encode('bc', 16, unhexlify('0000'))
'bc1sqqqqkfw08p'
</code></pre>
<p>หากเราเปิดไฟล์ segwit_addr.py และดูว่าโค้ดกำลังทำอะไร สิ่งแรกที่เราจะสังเกตเห็นคือความแตกต่างเพียงอย่างเดียวระหว่าง bech32 (ที่ใช้สำหรับ segwit v0) และ bech32m (ที่ใช้สำหรับเวอร์ชัน segwit รุ่นหลัง) คือค่าคงที่:</p>
<pre><code>BECH32_CONSTANT = 1
BECH32M_CONSTANT = 0x2bc830a3
</code></pre>
<p>และในส่วนต่อไป เราจะเห็นโค้ดที่สร้าง checksum ในขั้นตอนสุดท้ายของการสร้าง checksum ค่าคงที่ที่เหมาะสมถูกรวมเข้ากับข้อมูลอื่น ๆ โดยใช้การดำเนินการ xor ค่าเดียวนั้นคือความแตกต่างเพียงอย่างเดียวระหว่าง bech32 และ bech32m</p>
<p>เมื่อสร้าง checksum แล้ว อักขระ 5 บิตแต่ละตัวในส่วนข้อมูล (รวมถึง witness version, witness program และ checksum) จะถูกแปลงเป็นตัวอักษรและตัวเลข</p>
<p>สำหรับการถอดรหัสกลับเป็นสคริปต์เอาต์พุต เราทำงานย้อนกลับ ลองใช้ไลบรารีอ้างอิงเพื่อถอดรหัส address สอง address ของเรา:</p>
<pre><code>&gt;&gt;&gt; help(decode)
decode(hrp, addr)
    Decode a segwit address.
&gt;&gt;&gt; _ = decode("bc", "bc1q9d3xa5gg45q2j39m9y32xzvygcgay4rgc6aaee")
&gt;&gt;&gt;  _[0], bytes(_[1]).hex()
(0, '2b626ed108ad00a944bb2922a309844611d25468')
&gt;&gt;&gt; _ = decode("bc",
        "bc1p9nh05ha8wrljf7ru236awm4t2x0d5ctkkywmu9sclnm4t0av2vgs4k3au7")
&gt;&gt;&gt; _[0], bytes(_[1]).hex()
(1, '2ceefa5fa770ff24f87c5475d76eab519eda6176b11dbe1618fcf755bfac5311')
</code></pre>
<p>เราได้รับทั้ง witness version และ witness program กลับมา สิ่งเหล่านี้สามารถแทรกลงในเทมเพลตสำหรับสคริปต์เอาต์พุตของเรา:</p>
<pre><code>&lt;version&gt; &lt;program&gt;
</code></pre>
<p>ตัวอย่างเช่น:</p>
<pre><code>OP_0 2b626ed108ad00a944bb2922a309844611d25468
OP_1 2ceefa5fa770ff24f87c5475d76eab519eda6176b11dbe1618fcf755bfac5311
</code></pre>
<blockquote>
<p>คำเตือน: ข้อผิดพลาดที่อาจเกิดขึ้นที่ควรระวังคือ witness version ที่มีค่า 0 ใช้สำหรับ OP_0 ซึ่งใช้ไบต์ 0x00—แต่เวอร์ชัน witness ที่มีค่า 1 ใช้ OP_1 ซึ่งเป็นไบต์ 0x51 เวอร์ชัน witness 2 ถึง 16 ใช้ไบต์ 0x52 ถึง 0x60 ตามลำดับ</p>
</blockquote>
<p>เมื่อทำการเขียนโค้ดเพื่อเข้ารหัสหรือถอดรหัส bech32m เราขอแนะนำอย่างยิ่งให้คุณใช้เวกเตอร์ทดสอบ (test vectors) ที่มีให้ใน BIP350 เราขอให้คุณตรวจสอบให้แน่ใจว่าโค้ดของคุณผ่านเวกเตอร์ทดสอบที่เกี่ยวข้องกับการจ่ายเงินให้กับเวอร์ชัน segwit ในอนาคตที่ยังไม่ได้รับการกำหนด สิ่งนี้จะช่วยให้ซอฟต์แวร์ของคุณสามารถใช้งานได้อีกหลายปีข้างหน้า แม้ว่าคุณอาจจะไม่สามารถเพิ่มการรองรับคุณสมบัติใหม่ ๆ ของบิตคอยน์ได้ทันทีที่คุณสมบัตินั้น ๆ เริ่มใช้งานได้</p>
<h3>Private Key Formats</h3>
<p>private key สามารถถูกแสดงได้ในหลาย ๆ รูปแบบที่ต่างกันซึ่งสามารถแปลงเป็นตัวเลขขนาด 256 bit ชุดเดียวกันได้ ดังที่เราจะแสดงให้ดูในตารางข้างล่างนี้ รูปแบบที่แตกต่างกันถูกใช้ในสถานการณ์ที่ต่างกัน รูปแบบเลขฐานสิบหก (Hexadecimal) และรูปแบบไบนารี (raw binary) ถูกใช้ภายในซอฟต์แวร์และแทบจะไม่แสดงให้ผู้ใช้เห็น WIF ถูกใช้สำหรับการนำเข้า/ส่งออกกุญแจระหว่างกระเป๋าเงินและมักใช้ในการแสดงกุญแจส่วนตัวแบบ QR code</p>
<h4>รูปแบบของ private key ในปัจจุบัน</h4>
<p>ซอฟต์แวร์กระเป๋าเงินบิตคอยน์ในยุคแรกได้สร้าง private key อิสระอย่างน้อยหนึ่งดอกเมื่อกระเป๋าเงินของผู้ใช้ใหม่ถูกเริ่มต้น เมื่อชุดกุญแจเริ่มต้นถูกใช้ทั้งหมดแล้ว กระเป๋าเงินอาจสร้าง private key เพิ่มเติม  private key แต่ละดอกสามารถส่งออกหรือนำเข้าได้ ทุกครั้งที่มีการสร้างหรือนำเข้า private key ใหม่ จะต้องมีการสร้างการสำรองข้อมูลกระเป๋าเงินใหม่ด้วย</p>
<p>กระเป๋าเงินบิตคอยน์ในยุคหลังเริ่มใช้กระเป๋าเงินแบบกำหนดได้ (deterministic wallets) ซึ่ง private key ทั้งหมดถูกสร้างจาก seed เพียงค่าเดียว กระเป๋าเงินเหล่านี้จำเป็นต้องสำรองข้อมูลเพียงครั้งเดียวเท่านั้นสำหรับการใช้งานบนเชนทั่วไป แต่อย่างไรก็ตาม หากผู้ใช้ส่งออก private key เพียงดอกเดียวจากกระเป๋าเงินเหล่านี้ และผู้โจมตีได้รับกุญแจนั้นรวมถึงข้อมูลที่ไม่ใช่ข้อมูลส่วนตัวบางอย่างเกี่ยวกับกระเป๋าเงิน พวกเขาอาจสามารถสร้างกุญแจส่วนตัวใด ๆ ในกระเป๋าเงินได้—ทำให้ผู้โจมตีสามารถขโมยเงินทั้งหมดในกระเป๋าเงินได้ นอกจากนี้ ยังไม่สามารถนำเข้ากุญแจสู่กระเป๋าเงินแบบกำหนดได้ นี่หมายความว่าแทบไม่มีกระเป๋าเงินสมัยใหม่ที่รองรับความสามารถในการส่งออกหรือนำเข้ากุญแจเฉพาะดอก ข้อมูลในส่วนนี้มีความสำคัญหลัก ๆ สำหรับผู้ที่ต้องการความเข้ากันได้กับกระเป๋าเงินบิตคอยน์ในยุคแรก ๆ</p>
<p>รูปแบบของ private key (รูปแบบการเข้ารหัส)<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641438678-YAKIHONNES3.png" alt="image"><br>private key เดียวกันในแต่ละ format<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641472205-YAKIHONNES3.png" alt="image"><br>รูปแบบการแสดงผลทั้งหมดเหล่านี้เป็นวิธีต่างๆ ในการแสดงเลขจำนวนเดียวกัน private key เดียวกัน พวกมันดูแตกต่างกัน แต่รูปแบบใดรูปแบบหนึ่งสามารถแปลงไปเป็นรูปแบบอื่นได้อย่างง่ายดาย</p>
<h3>Compressed Private Keys</h3>
<p>คำว่า compressed private key ที่ใช้กันทั่วไปนั้นเป็นคำที่เรียกผิด เพราะเมื่อ private key ถูกส่งออกไปในรูปแบบ WIF-compressed มันจะมีความยาวมากกว่า private key แบบ uncompressed 1 Byte (เลข 01 ในช่อง Hex-compressed ในตารางด้านล่างนี้) ซึ่งบ่งบอกว่า private key ตัวนี้ มาจากกระเป๋าเงินรุ่นใหม่และควรใช้เพื่อสร้าง compressed public key เท่านั้น</p>
<p>private key เองไม่ได้ถูกบีบอัดและไม่สามารถบีบอัดได้ คำว่า compressed private key จริงๆ แล้วหมายถึง " private key ซึ่งควรใช้สร้าง compressed public key เท่านั้น" ในขณะที่ uncompressed private key จริงๆ แล้วหมายถึง “private key ซึ่งควรใช้สร้าง uncompressed public key เท่านั้น” คุณควรใช้เพื่ออ้างถึงรูปแบบการส่งออกเป็น "WIF-compressed" หรือ "WIF" เท่านั้น และไม่ควรอ้างถึง private key ว่า "บีบอัด" เพื่อหลีกเลี่ยงความสับสนต่อไป</p>
<p>ตารางนี้แสดงกุญแจเดียวกันที่ถูกเข้ารหัสในรูปแบบ WIF และ WIF-compressed</p>
<p>ตัวอย่าง: กุญแจเดียวกัน แต่รูปแบบต่างกัน<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641542538-YAKIHONNES3.png" alt="image"></p>
<p>สังเกตว่ารูปแบบ Hex-compressed มีไบต์เพิ่มเติมหนึ่งไบต์ที่ท้าย (01 ในเลขฐานสิบหก) ในขณะที่คำนำหน้าเวอร์ชันการเข้ารหัสแบบ base58 เป็นค่าเดียวกัน (0x80) สำหรับทั้งรูปแบบ WIF และ WIF-compressed การเพิ่มหนึ่งไบต์ที่ท้ายของตัวเลขทำให้อักขระตัวแรกของการเข้ารหัสแบบ base58 เปลี่ยนจาก 5 เป็น K หรือ L</p>
<p>คุณสามารถคิดถึงสิ่งนี้เหมือนกับความแตกต่างของการเข้ารหัสเลขฐานสิบระหว่างตัวเลข 100 และตัวเลข 99 ในขณะที่ 100 มีความยาวมากกว่า 99 หนึ่งหลัก มันยังมีคำนำหน้าเป็น 1 แทนที่จะเป็นคำนำหน้า 9 เมื่อความยาวเปลี่ยนไป มันส่งผลต่อคำนำหน้า ในระบบ base58 คำนำหน้า 5 เปลี่ยนเป็น K หรือ L เมื่อความยาวของตัวเลขเพิ่มขึ้นหนึ่งไบต์</p>
<blockquote>
<p>TIPจากหลาม: ผมว่าเขาเขียนย่อหน้านี้ไม่ค่อยรู้เรื่อง แต่ความหมายมันจะประมาณว่า เหมือนถ้าเราต้องการเขียนเลข 100 ในฐาน 10 เราต้องใช้สามตำแหน่ง 100 แต่ถ้าใช้ฐาน 16 เราจะใช้แค่ 2 ตำแหน่งคือ 64 ซึ่งมีค่าเท่ากัน</p>
</blockquote>
<p>ถ้ากระเป๋าเงินบิตคอยน์สามารถใช้ compressed public key ได้ มันจะใช้ในทุกธุรกรรม private key ในกระเป๋าเงินจะถูกใช้เพื่อสร้างจุด public key บนเส้นโค้ง ซึ่งจะถูกบีบอัด compressed public key จะถูกใช้เพื่อสร้าง address และ address เหล่านี้จะถูกใช้ในธุรกรรม เมื่อส่งออก private key จากกระเป๋าเงินใหม่ที่ใช้ compressed public key WIF จะถูกปรับเปลี่ยน โดยเพิ่มต่อท้ายขนาด 1 ไบต์ 01 ให้กับ private key ที่ถูกเข้ารหัสแบบ base58check ที่ได้จะเรียกว่า "WIF-compressed" และจะขึ้นต้นด้วยอักษร K หรือ L แทนที่จะขึ้นต้นด้วย "5" เหมือนกับกรณีของคีย์ที่เข้ารหัสแบบ WIF (ไม่บีบอัด) จากกระเป๋าเงินรุ่นเก่า</p>
<h3>Advanced Keys and Addresses</h3>
<p>ในส่วนต่อไปนี้ เราจะดูรูปแบบของคีย์และ address เช่น vanity addresses และ paper wallets </p>
<h4>vanity addresses</h4>
<p>vanity addresses หรือ addresses แบบกำหนดเอง คือ address ที่มีข้อความที่มนุษย์อ่านได้และสามารถใช้งานได้จริง ตัวอย่างเช่น 1LoveBPzzD72PUXLzCkYAtGFYmK5vYNR33 อย่างที่เห็นว่ามันเป็น address ที่ถูกต้องซึ่งมีตัวอักษรเป็นคำว่า Love เป็นตัวอักษร base58 สี่ตัวแรก addresses แบบกำหนดเองต้องอาศัยการสร้างและทดสอบ private key หลายพันล้านตัวจนกว่าจะพบ address ที่มีรูปแบบตามที่ต้องการ แม้ว่าจะมีการปรับปรุงบางอย่างในอัลกอริทึมการสร้าง addresses แบบกำหนดเอง แต่กระบวนการนี้ต้องใช้การสุ่มเลือก private key มาสร้าง public key และนำไปสร้าง address และตรวจสอบว่าตรงกับรูปแบบที่ต้องการหรือไม่ โดยทำซ้ำหลายพันล้านครั้งจนกว่าจะพบที่ตรงกัน</p>
<p>เมื่อพบ  address ที่ตรงกับรูปแบบที่ต้องการแล้ว  private key ที่ใช้สร้าง address นั้นสามารถใช้โดยเจ้าของเพื่อใช้จ่ายบิตคอยน์ได้เหมือนกับ address อื่น ๆ ทุกประการ address ที่กำหนดเองไม่ได้มีความปลอดภัยน้อยกว่าหรือมากกว่าที่ address ๆ พวกมันขึ้นอยู่กับการเข้ารหัสเส้นโค้งรูปวงรี (ECC) และอัลกอริทึมแฮชที่ปลอดภัย (SHA) เหมือนกับ address อื่น ๆ คุณไม่สามารถค้นหา private key ของ address ที่ขึ้นต้นด้วยรูปแบบที่กำหนดเองได้ง่ายกว่า address อื่น ๆ</p>
<p>ตัวอย่างเช่น ยูจีเนียเป็นผู้อำนวยการการกุศลเพื่อเด็กที่ทำงานในฟิลิปปินส์ สมมติว่ายูจีเนียกำลังจัดการระดมทุนและต้องการใช้ address ที่กำหนดเองเพื่อประชาสัมพันธ์การระดมทุน ยูจีเนียจะสร้าง address ที่กำหนดเองที่ขึ้นต้นด้วย "1Kids" เพื่อส่งเสริมการระดมทุนเพื่อการกุศลสำหรับเด็ก มาดูกันว่า address ที่กำหนดเองนี้จะถูกสร้างขึ้นอย่างไรและมีความหมายอย่างไรต่อความปลอดภัยของการกุศลของยูจีเนีย</p>
<h4>การสร้าง address ที่กำหนดเอง</h4>
<p>ควรเข้าใจว่า address ของบิตคอยน์เป็นเพียงตัวเลขที่แสดงด้วยสัญลักษณ์ในรูปแบบตัวอักษร base58 เท่านั้น เพราะฉะนั้นแล้ว การค้นหารูปแบบเช่น "1Kids" สามารถมองได้ว่าเป็นการค้นหาที่อยู่ในช่วงตั้งแต่ 1Kids11111111111111111111111111111 ถึง 1Kidszzzzzzzzzzzzzzzzzzzzzzzzzzzzz มีประมาณ 5829 (ประมาณ 1.4 × 1051) address ในช่วงนั้น ทั้งหมดขึ้นต้นด้วย "1Kids" ตารางด้านล่างนี้แสดงช่วงของ address ที่มีคำนำหน้า 1Kids<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641701955-YAKIHONNES3.png" alt="image">ลองดูรูปแบบ "1Kids" ในรูปของตัวเลขและดูว่าเราอาจพบรูปแบบนี้ใน bitcoin address บ่อยแค่ไหน โดยตารางข้างล่างนี้แสดงให้เห็นถีงคอมพิวเตอร์เดสก์ท็อปทั่วไปที่ไม่มีฮาร์ดแวร์พิเศษสามารถค้นหาคีย์ได้ประมาณ 100,000 คีย์ต่อวินาที</p>
<p>ความถี่ของ address ที่กำหนดเอง (1KidsCharity) และเวลาค้นหาเฉลี่ยบนคอมพิวเตอร์เดสก์ท็อป</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1742641750817-YAKIHONNES3.png" alt="image"></p>
<p>ดังที่เห็นได้ ยูจีเนียคงไม่สามารถสร้าง address แบบกำหนดเอง "1KidsCharity" ได้ในเร็ว ๆ นี้ แม้ว่าเธอจะมีคอมพิวเตอร์หลายพันเครื่องก็ตาม ทุกตัวอักษรที่เพิ่มขึ้นจะเพิ่มความยากขึ้น 58 เท่า รูปแบบที่มีมากกว่า 7 ตัวอักษรมักจะถูกค้นพบโดยฮาร์ดแวร์พิเศษ เช่น คอมพิวเตอร์เดสก์ท็อปที่สร้างขึ้นเป็นพิเศษที่มีหน่วยประมวลผลกราฟิก (GPUs) หลายตัว การค้นหา address แบบกำหนดเองบนระบบ GPU เร็วกว่าบน CPU ทั่วไปหลายเท่า</p>
<p>อีกวิธีหนึ่งในการหา address แบบกำหนดเองคือการจ้างงานไปยังกลุ่มคนขุด vanity addresses กลุ่มคนขุดvanity addresses เป็นบริการที่ให้ผู้ที่มีฮาร์ดแวร์ที่เร็วได้รับบิตคอยน์จากการค้นหา vanity addresses ให้กับผู้อื่น ยูจีเนียสามารถจ่ายค่าธรรมเนียมเพื่อจ้างงานการค้นหา vanity addresses ที่มีรูปแบบ 7 ตัวอักษรและได้ผลลัพธ์ในเวลาเพียงไม่กี่ชั่วโมงแทนที่จะต้องใช้ CPU ค้นหาเป็นเดือน ๆ</p>
<p>การสร้างที่ address แบบกำหนดเองเป็นการใช้วิธีการแบบ brute-force (ลองทุกความเป็นไปได้): ลองใช้คีย์สุ่ม ตรวจสอบ address ที่ได้ว่าตรงกับรูปแบบที่ต้องการหรือไม่ และทำซ้ำจนกว่าจะสำเร็จ</p>
<h4>ความปลอดภัยและความเป็นส่วนตัวของ address แบบกำหนดเอง</h4>
<p>address แบบกำหนดเองเคยเป็นที่นิยมในช่วงแรก ๆ ของบิตคอยน์ แต่แทบจะหายไปจากการใช้งานทั้งหมดในปี 2023 มีสาเหตุที่น่าจะเป็นไปได้สองประการสำหรับแนวโน้มนี้:</p>
<ul>
<li><p><strong>Deterministic wallets:</strong> ดังที่เราเห็นในพาร์ทของการกู้คืน การที่จะสำรองคีย์ทุกตัวในกระเป๋าเงินสมัยใหม่ส่วนใหญ่นั้น ทำเพียงแค่จดคำหรือตัวอักษรไม่กี่ตัว ซึ่งนี่เป็นผลจากการสร้างคีย์ทุกตัวในกระเป๋าเงินจากคำหรือตัวอักษรเหล่านั้นโดยใช้อัลกอริทึมแบบกำหนดได้ จึงไม่สามารถใช้ address แบบกำหนดเองกับ Deterministic wallets ได้ เว้นแต่ผู้ใช้จะสำรองข้อมูลเพิ่มเติมสำหรับ address แบบกำหนดเองทุก address ที่พวกเขาสร้าง ในทางปฏิบัติแล้วกระเป๋าเงินส่วนใหญ่ที่ใช้การสร้างคีย์แบบกำหนดได้ โดยไม่อนุญาตให้นำเข้าคีย์ส่วนตัวหรือการปรับแต่งคีย์จากโปรแกรมสร้าง address ที่กำหนดเอง</p>
</li>
<li><p><strong>การหลีกเลี่ยงการใช้ address ซ้ำซ้อน:</strong> การใช้ address แบบกำหนดเองเพื่อรับการชำระเงินหลายครั้งไปยัง address เดียวกันจะสร้างความเชื่อมโยงระหว่างการชำระเงินทั้งหมดเหล่านั้น นี่อาจเป็นที่ยอมรับได้สำหรับยูจีเนียหากองค์กรไม่แสวงหาผลกำไรของเธอจำเป็นต้องรายงานรายได้และค่าใช้จ่ายต่อหน่วยงานภาษีอยู่แล้ว แต่อย่างไรก็ตาม มันยังลดความเป็นส่วนตัวของคนที่จ่ายเงินให้ยูจีเนียหรือรับเงินจากเธอด้วย ตัวอย่างเช่น อลิซอาจต้องการบริจาคโดยไม่เปิดเผยตัวตน และบ็อบอาจไม่ต้องการให้ลูกค้ารายอื่นของเขารู้ว่าเขาให้ราคาส่วนลดแก่ยูจีเนีย</p>
</li>
</ul>
<p>เราไม่คาดว่าจะเห็น address แบบกำหนดเองมากนักในอนาคต เว้นแต่ปัญหาที่กล่าวมาก่อนหน้านี้จะได้รับการแก้ไข</p>
<h3>Paper Wallets</h3>
<p>paper wallet หรือก็คือ private key ที่พิมพ์ลงในกระดาษ และโดยทั่วไปแล้วมักจะมีข้อมูลของ public key หรือ address บนกระดาษนั้นด้วยแม้ว่าจริง ๆ แล้วมันจะสามารถคำนวณได้ด้วย private key ก็ตาม</p>
<blockquote>
<p>คำเตือน: paper wallet เป็นเทคโนโลยีที่ล้าสมัยแล้วและอันตรายสำหรับผู้ใช้ส่วนใหญ่ เพราะเป็นเรื่องยากที่จะสร้างมันอย่างปลอดภัย โดยเฉพาะอย่างยิ่งความเป็นไปได้ที่โค้ดที่ใช้สร้างอาจถูกแทรกแซงด้วยผู้ไม่ประสงค์ดี และอาจจะทำให้ผู้ใช้โดนขโมยบิตคอยน์ทั้งหมดไปได้ paper wallet ถูกแสดงที่นี่เพื่อวัตถุประสงค์ในการให้ข้อมูลเท่านั้นและไม่ควรใช้สำหรับเก็บบิตคอยน์</p>
</blockquote>
<p><img src="https://github.com/bitcoinbook/bitcoinbook/raw/develop/images/mbc3_0410.png" alt="image"></p>
<p>paper wallet ได้ถูกออกแบบมาเพื่อเป็นของขวัญและมีธีมตามฤดูกาล เช่น คริสต์มาสและปีใหม่ ส่วนเหตุผลอื่น ๆ ถูกออกแบบเพื่อการเก็บรักษาในตู้นิรภัยของธนาคารหรือตู้เซฟโดยมี private key ถูกซ่อนไว้ในบางวิธี ไม่ว่าจะด้วยสติกเกอร์แบบขูดที่ทึบแสงหรือพับและปิดผนึกด้วยแผ่นฟอยล์กันการงัดแงะ ส่วนการออกแบบอื่น ๆ มีสำเนาเพิ่มเติมของคีย์และ address ในรูปแบบของตอนฉีกที่แยกออกได้คล้ายกับตั๋ว ช่วยให้คุณสามารถเก็บสำเนาหลายชุดเพื่อป้องกันจากไฟไหม้ น้ำท่วม หรือภัยพิบัติทางธรรมชาติอื่น ๆ</p>
<p>จากการออกแบบเดิมของบิตคอยน์ที่เน้น public key ไปจนถึง address และสคริปต์สมัยใหม่อย่าง bech32m และ pay to taproot—และแม้แต่การอัพเกรดบิตคอยน์ในอนาคต—คุณได้เรียนรู้วิธีที่โปรโตคอลบิตคอยน์อนุญาตให้ผู้จ่ายเงินระบุกระเป๋าเงินที่ควรได้รับการชำระเงินของพวกเขา แต่เมื่อเป็นกระเป๋าเงินของคุณเองที่รับการชำระเงิน คุณจะต้องการความมั่นใจว่าคุณจะยังคงเข้าถึงเงินนั้นได้แม้ว่าจะเกิดอะไรขึ้นกับข้อมูลกระเป๋าเงินของคุณ ในบทต่อไป เราจะดูว่ากระเป๋าเงินบิตคอยน์ถูกออกแบบอย่างไรเพื่อปกป้องเงินทุนจากภัยคุกคามหลากหลายรูปแบบ</p>
]]></itunes:summary>
      <itunes:image href="https://image.nostr.build/0e43fa1dec4fb36a9b30035d0e83cf3759ece78d64813fc0b5182c5a62dd6e34.jpg"/>
      </item>
      
      <item>
      <title><![CDATA[สรุป Mastering Bitcoin: Programming the Open Blockchain บทที่ 3]]></title>
      <description><![CDATA[ต้นฉบับแบบว่ายาวไปไม่อ่าน อ่านละปวดหัว มาดูสรุปดีกว่า แต่ดูทรงปวดหัวกว่าเดิม งั้นไปอ่านต้นฉบับล้ากานนนนนนนน]]></description>
             <itunes:subtitle><![CDATA[ต้นฉบับแบบว่ายาวไปไม่อ่าน อ่านละปวดหัว มาดูสรุปดีกว่า แต่ดูทรงปวดหัวกว่าเดิม งั้นไปอ่านต้นฉบับล้ากานนนนนนนน]]></itunes:subtitle>
      <pubDate>Sat, 08 Mar 2025 07:04:36 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/zhbi56eoe8gyr4ti9n5le/</link>
      <comments>https://learnbn.npub.pro/post/zhbi56eoe8gyr4ti9n5le/</comments>
      <guid isPermaLink="false">naddr1qq2456rzfy6nve20g5uywk2jx36yjw2wx4xx2q3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65w9y4smc</guid>
      <category>ลองฟอร์มของไดโน</category>
      
        <media:content url="https://image.nostr.build/29da6e18e9b5a07f5cd1b52ef33ccaad9e0d438a203316facaed75bc6b83de6c.jpg" medium="image"/>
        <enclosure 
          url="https://image.nostr.build/29da6e18e9b5a07f5cd1b52ef33ccaad9e0d438a203316facaed75bc6b83de6c.jpg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qq2456rzfy6nve20g5uywk2jx36yjw2wx4xx2q3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65w9y4smc</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<h2>Bitcoin Core: The Reference Implementation</h2>
<hr>
<p>ผู้คนจะยอมรับเงินใด ๆ เพื่อแลกเปลี่ยนกับสินค้าและบริการก็ต่อเมื่อคนนั้น ๆ เชื่อว่าเงินนี้จะมีมูลค่าในอนาคต เงินปลอมหรือเงินที่เสื่อมค่าโดยไม่คาดคิดนั้นอาจไม่สามารถใช้ได้ในอนาคต ดังนั้นทุกคนที่รับบิตคอยน์จึงมีแรงจูงใจที่แข็งแกร่งในการตรวจสอบความถูกต้องของบิตคอยน์ที่พวกเขาได้รับ ระบบของบิตคอยน์นั้นถูกออกแบบมาให้เข้าถึง, ป้องกันการปลอมแปลง, การเสื่อมค่า และปัญหาสำคัญอื่น ๆ ได้อย่างสมบูรณ์ได้ด้วยคอมพิวเตอร์ทั่วไป โดยซอฟต์แวร์ที่ให้ฟังก์ชันนี้เรียกว่า Full node ซึ่งทำหน้าที่ตรวจสอบธุรกรรมบิตคอยน์ทุกครั้งที่ได้รับการยืนยันตามกฎของระบบ นอกจากนี้ Full node ยังสามารถให้เครื่องมือและข้อมูลเพื่อทำความเข้าใจการทำงานของบิตคอยน์และสภาพปัจจุบันของเครือข่าย</p>
<p>ในบทนี้เอง เราจะทำการติดตั้ง Bitcoin Core ซึ่งเป็นซอฟต์แวร์ที่ผู้ใช้งาน Full node ส่วนใหญ่เลือกใช้เพื่อเป็นประตูบานแรกในการเข้าถึงระบบนิเวศของบิตคอยน์ เราจะตรวจสอบบล็อก ธุรกรรม และข้อมูลอื่น ๆ จากโหนดของคุณ ซึ่งเป็นข้อมูลที่เชื่อถือได้ (ไม่ใช่เพราะหน่วยงานทรงอำนาจกำหนดให้เป็นเช่นนั้น) แต่เป็นเพราะโหนดของคุณได้ตรวจสอบข้อมูลนั้นอย่างอิสระ ตลอดเนื้อหาที่เหลือในหนังสือเล่มนี้ เราจะใช้ Bitcoin Core เพื่อสร้างและตรวจสอบข้อมูลที่เกี่ยวข้องกับบล็อกเชนและเครือข่าย</p>
<h3>จาก Bitcoin สู่ Bitcoin Core</h3>
<p>บิตคอยน์เป็นโครงการโอเพ่นซอร์ส โดยซอร์สโค้ดทั้งหมดก็สามารถดาวน์โหลดและใช้งานได้ฟรีภายใต้ใบอณุญาตแบบเปิด (MIT License) นอกจากจะเป็นโอเพ่นซอร์สแล้วบิตคอยน์ยังได้รับการพัฒนาโดยชุมชนอาสาสมัครแบบเปิดกว้าง แน่นอนว่าในช่วงแรกนั้นชุมชนนี้ประกอบด้วย Satoshi Nakamoto เพียงคนเดียว แต่ภายในปี 2023 ซอร์สโค้ดของบิตคอยน์มีผู้ร่วมพัฒนามากกว่า 1,000 คน</p>
<p>เมื่อ Satoshi Nakamoto ได้สร้างซอฟแวร์บิตคอยน์ตัวนี้และพัฒนามันจนเกือบสมบูรณ์ก่อนแล้วจึงเผยแพร่เอกสารไวท์เปเปอร์ เขาน่าจะต้องการให้มั่นใจว่าการใช้งานจริงสามารถทำงานได้ก่อนเผยแพร่เอกสาร โดยซอฟต์แวร์เวอร์ชันแรกที่รู้จักในชื่อ "Bitcoin" นั้นได้รับการปรับปรุงและพัฒนามาอย่างมาก จนได้กลายเป็นสิ่งที่เรารู้จักกันในชื่อ Bitcoin Core และเพื่อแยกความแตกต่างจากการใช้งานอื่น ๆ Bitcoin Core เป็นซอฟต์แวร์ต้นแบบอ้างอิง (reference implementation) ของระบบบิตคอยน์ซึ่งแสดงวิธีการทำงานของแต่ละส่วนในเชิงเทคโนโลยี นอกจากนี้ Bitcoin Core รวมถึงการใช้งานฟังก์ชันทั้งหมดของบิตคอยน์ เช่น กระเป๋าเงิน เครื่องมือตรวจสอบธุรกรรมและบล็อก เครื่องมือสำหรับการสร้างบล็อก และส่วนต่าง ๆ ของการสื่อสารแบบ peer-to-peer ของบิตคอยน์<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1741413625372-YAKIHONNES3.png" alt="image"></p>
<h3>Bitcoin Development Environment</h3>
<p>สำหรับนักพัฒนาที่ต้องการเขียนแอปพลิเคชันเกี่ยวกับบิตคอยน์ ทั้งการตั้งค่าสภาพแวดล้อมสำหรับการพัฒนาพร้อมเครื่องมือ ไลบรารี และซอฟต์แวร์สนับสนุนเป็นสิ่งสำคัญ ซึ่งเนื้อหาในบทนี้นั้นจะเป็นเรื่องทางเทคนิคอลค่อนข้างเยอะ ในบทนี้เราจะอธิบายขั้นตอนการตั้งค่าอย่างละเอียด หากคุณพบว่าเนื้อหานี้ซับซ้อนเกินไป (และไม่ได้ต้องการตั้งค่าสภาพแวดล้อมสำหรับการพัฒนาจริง ๆ) คุณสามารถข้ามไปยังบทถัดไปที่มีเนื้อหาน้อยทางเทคนิคกว่าได้</p>
<h3>มาคอมไพล์ Bitcoin core จากซอร์สโค้ดกันเถอะ !!</h3>
<p>ซอร์สโค้ดทั้งหมดของ BItcoin Core นั้นสามารถดาวน์โหลดได้ในรูปแบบไฟล์อาร์ไคฟ์หรือโดยการโคลนที่เก็บซอร์สโค้ดจาก GitHub โดยตรง บนหน้าดาวน์โหลดของ Bitcoin Core ให้เลือกเวอร์ชันล่าสุดและดาวน์โหลดไฟล์อัดบีบของซอร์สโค้ด หรือใช้คำสั่ง Git เพื่อสร้างสำเนาซอร์สโค้ดบนเครื่องของคุณจากหน้า GitHub ของ Bitcoin</p>
<blockquote>
<p>TIP: ในตัวอย่างหลาย ๆ ส่วนของบทนี้ เราจะใช้ อินเทอร์เฟซบรรทัดคำสั่ง (Command-Line Interface - CLI) ของระบบปฏิบัติการ หรือที่เรียกว่า "shell" ซึ่งสามารถเข้าถึงได้ผ่านแอปพลิเคชัน terminal โดย shell จะแสดง พรอมต์ (prompt) เพื่อรอรับคำสั่งที่คุณพิมพ์ จากนั้นจะแสดงผลลัพธ์ออกมาแล้วรอรับคำสั่งถัดไป</p>
</blockquote>
<blockquote>
<p>TIP จากหลาม: แบบง่าย ๆ ก็คือไม่ต้องพิมพ์ $ และถ้าพิมพ์จบหนึ่งคำสั่งก็กด enter ซ่ะด้วย</p>
</blockquote>
<p>ขั้นตอนในการลง bitcoin core มีดังนี้:</p>
<ol>
<li>สั่ง git clone เพื่อทำการสร้างสำเนาของซอร์สโค้ดลงในเครื่องของเรา</li>
</ol>
<pre><code>$ git clone https://github.com/bitcoin/bitcoin.git
Cloning into 'bitcoin'...
remote: Enumerating objects: 245912, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 245912 (delta 1), reused 2 (delta 1), pack-reused 245909
Receiving objects: 100% (245912/245912), 217.74 MiB | 13.05 MiB/s, done.
Resolving deltas: 100% (175649/175649), done.
</code></pre>
<blockquote>
<p>TIP: Git เป็นระบบควบคุมเวอร์ชันแบบกระจายที่ใช้กันอย่างแพร่หลายและเป็นส่วนสำคัญในเครื่องมือของนักพัฒนาซอฟต์แวร์ คุณอาจจำเป็นต้องติดตั้งคำสั่ง git หรือส่วนต่อประสานกราฟิก (GUI) สำหรับ Git บนระบบปฏิบัติการของคุณ หากยังไม่มี </p>
</blockquote>
<ol start="2">
<li>เมื่อการโคลน Git เสร็จสมบูรณ์แล้ว คุณจะมีสำเนาท้องถิ่นครบถ้วนของที่เก็บซอร์สโค้ดในไดเรกทอรี bitcoin ให้เปลี่ยนไปยังไดเรกทอรีนี้โดยใช้คำสั่ง cd:</li>
</ol>
<pre><code>$ cd bitcoin
</code></pre>
<ol start="3">
<li>เลือก version ของ bitcoin core: โดยค่าเริ่มต้น สำเนาจองเราจะซิงโครไนซ์กับโค้ดล่าสุด ซึ่งอาจเป็นเวอร์ชันที่ไม่เสถียรหรือเบต้าของ Bitcoin ก่อนที่จะคอมไพล์โค้ด ให้เลือกเวอร์ชันเฉพาะโดยการตรวจสอบ (checkout) แท็กของการปล่อย (release tag) ซึ่งจะซิงโครไนซ์สำเนาท้องถิ่นกับสแนปช็อตของที่เก็บซอร์สโค้ดที่ระบุด้วยแท็ก แท็กเหล่านี้ถูกใช้งานโดยนักพัฒนาเพื่อระบุเวอร์ชันของโค้ดตามหมายเลขเวอร์ชัน ซึ่งทำได้โดยใช้คำสั่ง git tag</li>
</ol>
<pre><code>$ git tag
v0.1.5
v0.1.6test1
v0.10.0
...
v0.11.2
v0.11.2rc1
v0.12.0rc1
v0.12.0rc2
...
</code></pre>
<p>รายการแท็กจะแสดงทุกเวอร์ชันที่ปล่อยออกมา โดยทั่วไป release candidates (เวอร์ชันทดสอบ) จะมีต่อท้ายว่า "rc" ส่วนเวอร์ชันเสถียรที่ใช้งานในระบบ production จะไม่มีต่อท้ายอะไรเลย จากรายการด้านบน ให้เลือกเวอร์ชันที่สูงสุด ซึ่งในขณะที่เขียนบทความนี้คือ v24.0.1 เพื่อซิงโครไนซ์โค้ดท้องถิ่นกับเวอร์ชันนี้ ให้ใช้คำสั่ง:</p>
<pre><code>$ git checkout v24.0.1
Note: switching to 'v24.0.1'.
</code></pre>
<p>จากนั้นสั่ง git status เพื่อเช็คเวอร์ชัน</p>
<h3>Configuring the Bitcoin Core Build</h3>
<p>ในโค้ดของบิตคอยน์ที่เราได้ดาวน์โหลดมาในหัวข้อก่อนหน้านั้น มีเอกสารประกอบอยู่หลายไฟล์ โดยคุณสามารถดูเอกสารหลักได้จากไฟล์ README.md ในไดเรกทอรี bitcoin ในบทนี้ เราจะสร้าง daemon (เซิร์ฟเวอร์) ของ Bitcoin Core ซึ่งรู้จักกันในชื่อ bitcoind บน Linux (หรือระบบที่คล้ายกับ Unix) โดยให้ตรวจสอบคำแนะนำสำหรับการคอมไพล์ bitcoind แบบบรรทัดคำสั่งบนแพลตฟอร์มของคุณโดยอ่านไฟล์ doc/build-unix.md นอกจากนี้ ยังมีคำแนะนำสำหรับระบบอื่น ๆ ในไดเรกทอรี doc เช่น build-windows.md สำหรับ Windows จนถึงขณะนี้ คำแนะนำมีให้สำหรับ Android, FreeBSD, NetBSD, OpenBSD, macOS (OSX), Unix</p>
<p>หลังจากนั้นคุณควรตรวจสอบความต้องการเบื้องต้นในการสร้าง (build pre-requisites) ซึ่งระบุไว้ในส่วนแรกของเอกสารการสร้าง สิ่งเหล่านี้คือไลบรารีที่ต้องมีอยู่ในระบบของคุณก่อนที่คุณจะเริ่มคอมไพล์ Bitcoin หากมีไลบรารีที่จำเป็นหายไป กระบวนการสร้างจะล้มเหลวและแสดงข้อผิดพลาด หากเกิดปัญหานี้เพราะคุณพลาด pre-requisite คุณสามารถติดตั้งไลบรารีที่ขาดหายไปแล้วดำเนินการสร้างต่อจากจุดที่ค้างไว้</p>
<p>สมมุติว่า pre-requisite ถูกติดตั้งแล้ว ให้เริ่มกระบวนการสร้างโดยการสร้างชุดสคริปต์สำหรับการสร้างด้วยการรันสคริปต์ autogen.sh:</p>
<hr>
<pre><code>$ ./autogen.sh
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, 'build-aux'.
libtoolize: copying file 'build-aux/ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'build-aux/m4'.
 ...
configure.ac:58: installing 'build-aux/missing'
src/Makefile.am: installing 'build-aux/depcomp'
parallel-tests: installing 'build-aux/test-driver'
</code></pre>
<p>สคริปต์ autogen.sh นี้จะสร้างชุดสคริปต์ที่กำหนดค่าอัตโนมัติที่จะตรวจสอบระบบของคุณเพื่อค้นหาการตั้งค่าที่ถูกต้องและตรวจสอบให้แน่ใจว่ามีไลบรารีที่จำเป็นสำหรับการคอมไพล์โค้ด โดยสคริปต์ที่สำคัญที่สุดในสคริปต์เหล่านี้คือสคริปต์ configure ซึ่งมีตัวเลือกต่าง ๆ สำหรับการปรับแต่งกระบวนการสร้าง</p>
<p>ใช้ flag --help เพื่อดูตัวเลือกทั้งหมด:</p>
<pre><code>$ ./configure --help
`configure' configures Bitcoin Core 24.0.1 to adapt to many kinds of systems.
Usage: ./configure [OPTION]... [VAR=VALUE]...
...
Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
  --enable-silent-rules   less verbose build output (undo: "make V=1")
  --disable-silent-rules  verbose build output (undo: "make V=0")
...
</code></pre>
<p>สคริปต์ configure ช่วยให้คุณสามารถเปิดหรือปิดคุณสมบัติบางอย่างของ bitcoind ผ่านการใช้ flag --enable-FEATURE และ --disable-FEATURE โดยที่ FEATURE แทนชื่อคุณสมบัติที่ระบุในข้อความช่วยเหลือ ในบทนี้ เราจะสร้าง bitcoind ด้วยคุณสมบัติตั้งต้นทั้งหมด โดยไม่ใช้ flag การกำหนดค่าเพิ่มเติม แต่คุณควรตรวจสอบตัวเลือกเหล่านี้เพื่อเข้าใจว่ามีคุณสมบัติเพิ่มเติมอะไรบ้าง หากคุณอยู่ในสภาพแวดล้อมทางการศึกษา ห้องปฏิบัติการคอมพิวเตอร์ หรือมีข้อจำกัดในการติดตั้งโปรแกรม คุณอาจต้องติดตั้งแอปพลิเคชันไว้ในไดเรกทอรี home (เช่นโดยใช้ flag --prefix=$HOME)</p>
<p>ตัวเลือกที่มีประโยชน์สำหรับการกำหนดค่า</p>
<ul>
<li>--prefix=$HOME: เปลี่ยนตำแหน่งการติดตั้งเริ่มต้น (ซึ่งโดยปกติคือ /usr/local/) ให้เป็นไดเรกทอรี home ของคุณ หรือเส้นทางที่คุณต้องการ</li>
<li>--disable-wallet: ใช้เพื่อปิดการใช้งานฟังก์ชัน wallet แบบอ้างอิง</li>
<li>--with-incompatible-bdb: หากคุณกำลังสร้าง wallet ให้ยอมรับการใช้ไลบรารี Berkeley DB เวอร์ชันที่ไม่เข้ากันได้</li>
<li>--with-gui=no: ไม่สร้างส่วนติดต่อผู้ใช้แบบกราฟิก (GUI) ซึ่งต้องใช้ไลบรารี Qt โดยตัวเลือกนี้จะสร้างเฉพาะเซิร์ฟเวอร์และ Bitcoin Core แบบ commandline เท่านั้น</li>
</ul>
<pre><code>
</code></pre>
<p>ต่อไป ให้รันสคริปต์ configure เพื่อให้ระบบตรวจสอบไลบรารีที่จำเป็นทั้งหมดและสร้างสคริปต์สำหรับการสร้างที่ปรับแต่งให้ตรงกับระบบของคุณ:</p>
<pre><code>$ ./configure
checking for pkg-config... /usr/bin/pkg-config
checking pkg-config is at least version 0.9.0... yes
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking for a BSD-compatible install... /usr/bin/install -c
...
[many pages of configuration tests follow]
...
</code></pre>
<p>หากทุกอย่างดำเนินไปด้วยดี คำสั่ง configure จะสิ้นสุดด้วยการสร้างสคริปต์การสร้างที่ปรับแต่งให้กับระบบของคุณ แต่หากมีไลบรารีที่หายไปหรือเกิดข้อผิดพลาด คำสั่ง configure จะหยุดและแสดงข้อผิดพลาดแทนที่จะสร้างสคริปต์ในกรณีที่เกิดข้อผิดพลาดขึ้น สาเหตุที่พบบ่อยคือการขาดหายหรือความไม่เข้ากันของไลบรารี ให้ตรวจสอบเอกสารการสร้างอีกครั้งและติดตั้ง pre-requisite ที่ขาดไป จากนั้นรัน configure อีกครั้งเพื่อดูว่าปัญหานั้นได้รับการแก้ไขแล้วหรือไม่</p>
<h3>การสร้าง Executable ของ Bitcoin Core</h3>
<p>ต่อไป คุณจะทำการคอมไพล์ซอร์สโค้ด กระบวนการนี้อาจใช้เวลาถึงหนึ่งชั่วโมง ขึ้นอยู่กับความเร็วของ CPU และหน่วยความจำที่มีอยู่ หากเกิดข้อผิดพลาด หรือการคอมไพล์ถูกขัดจังหวะ คุณสามารถดำเนินการต่อได้โดยการพิมพ์คำสั่ง make อีกครั้ง</p>
<p>พิมพ์ make เพื่อเริ่มคอมไพล์แอปพลิเคชันที่สามารถรันได้:</p>
<pre><code>$ make
Making all in src
  CXX      bitcoind-bitcoind.o
  CXX      libbitcoin_node_a-addrdb.o
  CXX      libbitcoin_node_a-addrman.o
  CXX      libbitcoin_node_a-banman.o
  CXX      libbitcoin_node_a-blockencodings.o
  CXX      libbitcoin_node_a-blockfilter.o
[... many more compilation messages follow ...]
</code></pre>
<p>บนระบบที่มีความเร็วและมี CPU หลายคอร์ คุณอาจต้องการตั้งค่าจำนวนงานคอมไพล์แบบขนาน (parallel compile jobs) เช่น การใช้คำสั่ง make -j 2 จะใช้สองคอร์หากมีอยู่ หากทุกอย่างดำเนินไปด้วยดี Bitcoin Core จะถูกคอมไพล์เรียบร้อยแล้ว คุณควรรันชุดการทดสอบหน่วย (unit test suite) ด้วยคำสั่ง make check เพื่อให้แน่ใจว่าไลบรารีที่ลิงค์เข้าด้วยกันไม่มีข้อผิดพลาดอย่าง ขั้นตอนสุดท้ายคือการติดตั้ง executable ต่าง ๆ ลงในระบบของคุณโดยใช้คำสั่ง make install ซึ่งอาจมีการร้องขอรหัสผ่านของผู้ใช้เนื่องจากขั้นตอนนี้ต้องการสิทธิ์ผู้ดูแลระบบ:</p>
<pre><code>$ make check &amp;&amp; sudo make install
Password:
Making install in src
 ../build-aux/install-sh -c -d '/usr/local/lib'
libtool: install: /usr/bin/install -c bitcoind /usr/local/bin/bitcoind
libtool: install: /usr/bin/install -c bitcoin-cli /usr/local/bin/bitcoin-cli
libtool: install: /usr/bin/install -c bitcoin-tx /usr/local/bin/bitcoin-tx
...
</code></pre>
<p>การติดตั้งเริ่มต้นของ bitcoind จะอยู่ในไดเรกทอรี /usr/local/bin โดยคุณสามารถตรวจสอบว่า Bitcoin Core ถูกติดตั้งเรียบร้อยแล้วโดยใช้คำสั่งเพื่อตรวจสอบตำแหน่งของ executable ดังนี้:</p>
<pre><code>$ which bitcoind
/usr/local/bin/bitcoind
$ which bitcoin-cli
/usr/local/bin/bitcoin-cli
</code></pre>
<h3>มาลองรัน Bitcoin node กันเถอะ</h3>
<p>อย่างที่ได้กล่าวในบทก่อนหน้า เครือข่ายแบบเพียร์ทูเพียร์ของบิตคอยน์ประกอบด้วยเครือข่าย "โหนด" ซึ่งส่วนใหญ่รันโดยบุคคลและธุรกิจบางแห่งที่ให้บริการ ผู้ที่รันโหนดบิตคอยน์จะมีมุมมองที่ตรงและน่าเชื่อถือเกี่ยวกับบล๊อกเชนของบิตคอยน์พร้อมสำเนาข้อมูลบิตคอยน์ที่ใช้จ่ายได้ทั้งหมดซึ่งได้รับการตรวจสอบอย่างอิสระโดยระบบของตนเอง การรันโหนดทำให้คุณไม่ต้องพึ่งบุคคลที่สามในการตรวจสอบธุรกรรม นอกจากนี้การใช้โหนดบิตคอยน์เพื่อตรวจสอบธุรกรรมที่ได้รับในกระเป๋าเงินของคุณ ยังช่วยให้คุณมีส่วนร่วมในเครือข่ายบิตคอยน์และช่วยทำให้เครือข่ายมีความแข็งแกร่งมากขึ้นอีกด้วย</p>
<p>การรันโหนดต้องดาวน์โหลดและประมวลผลข้อมูลมากกว่า 500 GB ในช่วงเริ่มแรก และประมาณ 400 MB ของธุรกรรม Bitcoin ต่อวัน ตัวเลขเหล่านี้เป็นของปี 2023 และอาจเพิ่มขึ้นในอนาคต หากคุณปิดโหนดหรือหลุดจากอินเทอร์เน็ตเป็นเวลาหลายวัน โหนดของคุณจะต้องดาวน์โหลดข้อมูลที่พลาดไป ตัวอย่างเช่น หากคุณปิด Bitcoin Core เป็นเวลา 10 วัน คุณจะต้องดาวน์โหลดประมาณ 4 GB ในครั้งถัดไปที่คุณเริ่มใช้งาน</p>
<p>ขึ้นอยู่กับการเลือกของคุณว่าจะทำดัชนีธุรกรรมทั้งหมดและเก็บสำเนาบล๊อกเชนแบบเต็ม คุณอาจต้องใช้พื้นที่ดิสก์มาก - อย่างน้อย 1 TB หากคุณวางแผนจะรัน Bitcoin Core เป็นเวลาหลายปี โดยค่าเริ่มต้นโหนดบิตคอยน์ยังส่งธุรกรรมและบล็อกไปยังโหนดอื่น ๆ (เรียกว่า "เพียร์") ซึ่งจะใช้แบนด์วิดท์อัปโหลดอินเทอร์เน็ต หากการเชื่อมต่ออินเทอร์เน็ตของคุณมีขีดจำกัด มีขีดจำกัดการใช้ข้อมูลต่ำ หรือคิดค่าบริการตามข้อมูล (เมตเตอร์) คุณไม่ควรรันโหนดบิตคอยน์บนระบบนั้น หรือรันโดยจำกัดแบนด์วิดท์ (ดู การกำหนดค่าโหนด Bitcoin Core) คุณอาจเชื่อมต่อโหนดของคุณแทนไปยังเครือข่ายทางเลือก เช่น ผู้ให้บริการข้อมูลดาวเทียมฟรีอย่าง Blockstream Satellite</p>
<blockquote>
<p>Tip: Bitcoin Core เก็บสำเนาบล๊อกเชนแบบเต็ม (ตามค่าเริ่มต้น ) พร้อมธุรกรรมเกือบทั้งหมดที่เคยได้รับการยืนยันบนเครือข่าย Bitcoin ตั้งแต่เริ่มต้นในปี 2009 ชุดข้อมูลนี้มีขนาดหลายร้อย GB และจะถูกดาวน์โหลดเพิ่มขึ้นทีละน้อยในช่วงหลายชั่วโมงหรือหลายวัน ขึ้นอยู่กับความเร็ว CPU และการเชื่อมต่ออินเทอร์เน็ตของคุณ Bitcoin Core จะไม่สามารถประมวลผลธุรกรรมหรืออัปเดตยอดคงเหลือของบัญชีจนกว่าชุดข้อมูล blockchain จะดาวน์โหลดเสร็จสมบูรณ์ ตรวจสอบให้แน่ใจว่าคุณมีพื้นที่ดิสก์ แบนด์วิดท์ และเวลาเพียงพอในการซิงโครไนซ์เริ่มแรก คุณสามารถกำหนดค่า Bitcoin Core เพื่อลดขนาด blockchain โดยการทิ้งบล็อกเก่า แต่โปรแกรมยังคงดาวน์โหลดชุดข้อมูลทั้งหมด</p>
</blockquote>
<blockquote>
<p>TIPจากหลาม agian: ซื้อ NVMe SSD 2TB เป็นอย่างต่ำซ่ะ m.2 ได้ยิ่งดีเลยจ้า </p>
</blockquote>
<p>แม้ว่าจะมีข้อกำหนดด้านทรัพยากรเหล่านี้ แต่มีผู้คนหลายพันรายที่รันโหนด Bitcoin บางคนรันบนระบบง่าย ๆ อย่าง Raspberry Pi (คอมพิวเตอร์ราคา 35 เหรียญสหรัฐที่มีขนาดเท่ากับกล่องบุหรี่)</p>
<p>ทำไมคุณถึงอยากรันโหนด? นี่คือเหตุผลที่พบบ่อยที่สุด:</p>
<ul>
<li>คุณไม่ต้องการพึ่งบุคคลที่สามในการตรวจสอบธุรกรรมที่คุณได้รับ</li>
<li>คุณไม่ต้องการเปิดเผยให้บุคคลที่สามรู้ว่าธุรกรรมใดเป็นของกระเป๋าเงินคุณ</li>
<li>คุณกำลังพัฒนาซอฟต์แวร์ Bitcoin และต้องการพึ่งโหนด Bitcoin เพื่อเข้าถึงเครือข่ายและ blockchain ผ่าน API</li>
<li>คุณกำลังสร้างแอปพลิเคชันที่ต้องตรวจสอบธุรกรรมตามกฎฉันทามติของ Bitcoin โดยทั่วไป บริษัทซอฟต์แวร์ Bitcoin มักจะรันโหนดหลายโหนด</li>
<li>คุณต้องการสนับสนุน Bitcoin การรันโหนดที่คุณใช้ตรวจสอบธุรกรรมที่ได้รับในกระเป๋าเงินจะช่วยทำให้เครือข่ายมีความแข็งแกร่งมากขึ้น</li>
</ul>
<p>หากคุณกำลังอ่านหนังสือเล่มนี้และสนใจความปลอดภัยที่เข้มงวด ความเป็นส่วนตัวที่เหนือกว่า หรือการพัฒนาซอฟต์แวร์ Bitcoin คุณควรรันโหนดของตัวเอง</p>
<h3>การกำหนดค่าโหนด Bitcoin Core</h3>
<p>Bitcoin Core จะค้นหาไฟล์การกำหนดค่าในไดเรกทอรีข้อมูลทุกครั้งที่เริ่มทำงาน ในส่วนนี้เราจะตรวจสอบตัวเลือกการกำหนดค่าต่าง ๆ และตั้งค่าไฟล์การกำหนดค่า</p>
<p>เพื่อค้นหาไฟล์การกำหนดค่า ให้รัน bitcoind -printtoconsole ในเทอร์มินัลของคุณ และดูบรรทัดแรก ๆ:</p>
<pre><code>$ bitcoind -printtoconsole
2023-01-28T03:21:42Z Bitcoin Core version v24.0.1
2023-01-28T03:21:42Z Using the 'x86_shani(1way,2way)' SHA256 implementation
2023-01-28T03:21:42Z Using RdSeed as an additional entropy source
2023-01-28T03:21:42Z Using RdRand as an additional entropy source
2023-01-28T03:21:42Z Default data directory /home/harding/.bitcoin
2023-01-28T03:21:42Z Using data directory /home/harding/.bitcoin
2023-01-28T03:21:42Z Config file: /home/harding/.bitcoin/bitcoin.conf
...
[a lot more debug output]
...
</code></pre>
<blockquote>
<p>tatatipจากหลามอีกครั้ง: สังเกตเห็นหรือไม่ว่าในตัวอย่างนี้ Bitcoin Core กำลังชี้ไปที่ไฟล์การกำหนดค่าที่ไดเรกทอรี /home/harding/.bitcoin/bitcoin.conf ซึ่งจะแตกต่างกันไปขึ้นอยู่กับผู้ใช้และระบบปฏิบัติการ</p>
</blockquote>
<p>คุณสามารถกด Ctrl-C เพื่อปิดโหนดหลังจากที่ระบุตำแหน่งไฟล์การกำหนดค่า โดยปกติไฟล์การกำหนดค่าจะอยู่ในไดเรกทอรี .bitcoin ภายใต้โฮมไดเรกทอรีของผู้ใช้ เปิดไฟล์ configuration ด้วยโปรแกรมแก้ไขได้ตามที่คุณชอบ</p>
<p>Bitcoin Core มีตัวเลือกการกำหนดค่ามากกว่า 100 ตัวเลือกที่สามารถปรับเปลี่ยนพฤติกรรมของโหนดเครือข่าย การจัดเก็บบล๊อกเชน และแง่มุมอื่น ๆ ของการทำงาน เพื่อดูรายการตัวเลือก ให้รัน bitcoind --help:</p>
<pre><code>$ bitcoind --help
Bitcoin Core version v24.0.1
Usage:  bitcoind [options]                     Start Bitcoin Core
Options:
  -?
       Print this help message and exit
  -alertnotify=&lt;cmd&gt;
       Execute command when an alert is raised (%s in cmd is replaced by
       message)
...
[many more options]
</code></pre>
<p>นี่คือตัวเลือกที่บางประการที่คุณสามารถตั้งในไฟล์ configuration หรือเป็นพารามิเตอร์บรรทัดคำสั่งสำหรับ bitcoind:</p>
<ul>
<li>alertnotify: เรียกใช้คำสั่งหรือสคริปต์เพื่อส่งการแจ้งเตือนฉุกเฉินไปยังเจ้าของโหนดนี้</li>
<li>conf: ตำแหน่งทางเลือกสำหรับไฟล์ configuration เมื่อใช้เป็นพารามิเตอร์ cli สำหรับ bitcoind เท่านั้น เนื่องจากไม่สามารถอยู่ในไฟล์ configuration ที่มันอ้างถึงได้</li>
<li>datadir: เลือกไดเรกทอรีและระบบไฟล์สำหรับจัดเก็บข้อมูลบล๊อกเชนตามค่าเริ่มต้นนี้คือไดเรกทอรีย่อย .bitcoin ในไดเรกทอรีโฮมของคุณ ขึ้นอยู่กับการกำหนดค่า สามารถใช้พื้นที่ตั้งแต่ประมาณ 10 GB ถึงเกือบ 1 TB ณ ขณะนี้ คาดว่าขนาดสูงสุดจะเพิ่มขึ้นหลายร้อย GB ต่อปี</li>
<li>prune: ลดความต้องการพื้นที่ดิสก์บล๊อกเชนลงเหลือกี่เมกะไบต์โดยการลบบล็อกเก่า ใช้สำหรับโหนดที่มีทรัพยากรจำกัดซึ่งไม่สามารถบรรจุบล๊อกเชนแบบเต็มได้ ส่วนอื่น ๆ ของระบบจะใช้พื้นที่ดิสก์อื่นที่ไม่สามารถตัดทอนได้ ดังนั้นคุณยังคงต้องมีพื้นที่อย่างน้อยตามที่ระบุในตัวเลือก datadir</li>
<li>txindex: รักษาดัชนีของธุรกรรมทั้งหมด ช่วยให้คุณสามารถดึงธุรกรรมใด ๆ โดยใช้ ID ของมันได้โดยโปรแกรม โดยที่บล็อกที่มีธุรกรรมนั้นยังไม่ถูกตัดทอน</li>
<li>dbcache: ขนาดของแคช UTXO ค่าเริ่มต้นคือ 450 เมบิไบต์ (MiB) เพิ่มขนาดนี้บนฮาร์ดแวร์ระดับสูงเพื่ออ่านและเขียนจากดิสก์น้อยลง หรือลดขนาดลงบนฮาร์ดแวร์ระดับต่ำเพื่อประหยัดหน่วยความจำโดยยอมให้ใช้ดิสก์บ่อยขึ้น</li>
<li>blocksonly: ลดการใช้แบนด์วิดท์โดยการรับเฉพาะบล็อกของธุรกรรมที่ได้รับการยืนยันจากเพียร์ แทนที่จะส่งต่อธุรกรรมที่ยังไม่ได้รับการยืนยัน</li>
<li>maxmempool: จำกัดพูลหน่วยความจำของธุรกรรมเป็นกี่เมกะไบต์ ใช้เพื่อลดการใช้หน่วยความจำบนโหนดที่มีหน่วยความจำจำกัด</li>
</ul>
<h3>ดัชนีฐานข้อมูลธุรกรรมและตัวเลือก txindex</h3>
<p>ตามค่าเริ่มต้น Bitcoin Core จะสร้างฐานข้อมูลที่มีเพียงธุรกรรมที่เกี่ยวข้องกับกระเป๋าเงินของผู้ใช้เท่านั้น หากคุณต้องการสามารถเข้าถึงธุรกรรมใด ๆ ด้วยคำสั่งเช่น getrawtransaction คุณจะต้องกำหนดค่า Bitcoin Core ให้สร้างดัชนีธุรกรรมแบบสมบูรณ์ ซึ่งสามารถทำได้ด้วยตัวเลือก txindex โดยตั้ง txindex=1 ในไฟล์การกำหนดค่า Bitcoin Core หากคุณไม่ได้ตั้งตัวเลือกนี้ตั้งแต่แรกและต่อมาตั้งเป็นการทำดัชนีแบบเต็ม คุณจะต้องรอให้มันสร้างดัชนีใหม่</p>
<p>ตัวอย่างการกำหนดค่าโหนดดัชนีแบบเต็มแสดงวิธีที่คุณอาจรวมตัวเลือกก่อนหน้านี้กับโหนดที่มีดัชนีแบบเต็ม โดยทำงานเป็นแบ็กเอนด์ API สำหรับแอปพลิเคชัน bitcoin</p>
<p>ตัวอย่างที่ 1. การกำหนดค่าโหนดดัชนีแบบเต็ม</p>
<pre><code>alertnotify=myemailscript.sh "Alert: %s"
datadir=/lotsofspace/bitcoin
txindex=1
</code></pre>
<p>ตัวอย่างที่ 2. การกำหนดค่าระบบที่มีทรัพยากรจำกัด</p>
<pre><code>alertnotify=myemailscript.sh "Alert: %s"
blocksonly=1
prune=5000
dbcache=150
maxmempool=150
</code></pre>
<p>หลังจากที่คุณแก้ไขไฟล์การกำหนดค่าและตั้งตัวเลือกที่ดีที่สุดตามความต้องการของคุณ คุณสามารถทดสอบ bitcoind ด้วยการกำหนดค่านี้ รัน Bitcoin Core ด้วยตัวเลือก printtoconsole เพื่อรันที่ foreground พร้อมแสดงผลลัพธ์ที่คอนโซล:</p>
<pre><code>$ bitcoind -printtoconsole
2023-01-28T03:43:39Z Bitcoin Core version v24.0.1
2023-01-28T03:43:39Z Using the 'x86_shani(1way,2way)' SHA256 implementation
2023-01-28T03:43:39Z Using RdSeed as an additional entropy source
2023-01-28T03:43:39Z Using RdRand as an additional entropy source
2023-01-28T03:43:39Z Default data directory /home/harding/.bitcoin
2023-01-28T03:43:39Z Using data directory /lotsofspace/bitcoin
2023-01-28T03:43:39Z Config file: /home/harding/.bitcoin/bitcoin.conf
2023-01-28T03:43:39Z Config file arg: [main] blockfilterindex="1"
2023-01-28T03:43:39Z Config file arg: [main] maxuploadtarget="1000"
2023-01-28T03:43:39Z Config file arg: [main] txindex="1"
2023-01-28T03:43:39Z Setting file arg: wallet = ["msig0"]
2023-01-28T03:43:39Z Command-line arg: printtoconsole=""
2023-01-28T03:43:39Z Using at most 125 automatic connections
2023-01-28T03:43:39Z Using 16 MiB out of 16 MiB requested for signature cache
2023-01-28T03:43:39Z Using 16 MiB out of 16 MiB requested for script execution
2023-01-28T03:43:39Z Script verification uses 3 additional threads
2023-01-28T03:43:39Z scheduler thread start
2023-01-28T03:43:39Z [http] creating work queue of depth 16
2023-01-28T03:43:39Z Using random cookie authentication.
2023-01-28T03:43:39Z Generated RPC cookie /lotsofspace/bitcoin/.cookie
2023-01-28T03:43:39Z [http] starting 4 worker threads
2023-01-28T03:43:39Z Using wallet directory /lotsofspace/bitcoin/wallets
2023-01-28T03:43:39Z init message: Verifying wallet(s)…
2023-01-28T03:43:39Z Using BerkeleyDB version Berkeley DB 4.8.30
2023-01-28T03:43:39Z Using /16 prefix for IP bucketing
2023-01-28T03:43:39Z init message: Loading P2P addresses…
2023-01-28T03:43:39Z Loaded 63866 addresses from peers.dat  114ms
[... more startup messages ...]
</code></pre>
<p>คุณสามารถกด Ctrl-C เพื่อหยุดกระบวนการเมื่อคุณพอใจว่ากำลังโหลดการตั้งค่าที่ถูกต้องและทำงานตามที่คาดหวัง</p>
<p>เพื่อรัน Bitcoin Core ที่พื้นหลังเป็นโพรเซส ให้เริ่มด้วยตัวเลือก daemon เช่น bitcoind -daemon</p>
<p>เพื่อตรวจสอบความคืบหน้าและสถานะการทำงานของโหนด Bitcoin ให้เริ่มในโหมด daemon แล้วใช้คำสั่ง bitcoin-cli getblockchaininfo:</p>
<pre><code>$ bitcoin-cli getblockchaininfo

{
"chain": "main",
"blocks": 0,
"headers": 83999,
"bestblockhash": "[...]19d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"difficulty": 1,
"time": 1673379796,
"mediantime": 1231006505,
"verificationprogress": 3.783041623201835e-09,
"initialblockdownload": true,
"chainwork": "[...]000000000000000000000000000000000000000000000100010001",
"size_on_disk": 89087,
"pruned": false,
"warnings": ""
}
</code></pre>
<p>นี่แสดงโหนดที่มีความสูงของ blockchain เป็น 0 บล็อก และ 83,999 เฮดเดอร์ โหนดจะดึงเฮดเดอร์ของบล็อกจากเพียร์ของตนก่อนเพื่อค้นหา blockchain ที่มีหลักฐานการทำงานมากที่สุด จากนั้นจึงดำเนินการดาวน์โหลดบล็อกเต็มโดยตรวจสอบความถูกต้องไปพร้อมกัน</p>
<p>เมื่อคุณพอใจกับตัวเลือกการกำหนดค่าที่เลือก คุณควรเพิ่ม Bitcoin Core ลงในสคริปต์เริ่มต้นของระบบปฏิบัติการ เพื่อให้มันทำงานอย่างต่อเนื่องและรีสตาร์ทเมื่อระบบปฏิบัติการรีสตาร์ท คุณจะพบสคริปต์เริ่มต้นตัวอย่างสำหรับระบบปฏิบัติการต่าง ๆ ในไดเรกทอรีซอร์สของ Bitcoin Core ภายใต้ contrib/init และไฟล์ README.md ที่แสดงว่าระบบใดใช้สคริปต์ใด</p>
<h3>Bitcoin Core API</h3>
<p>Bitcoin Core ใช้อินเทอร์เฟซ JSON-RPC ซึ่งสามารถเข้าถึงได้โดยใช้เครื่องมืออย่าง bitcoin-cli ซึ่งช่วยให้เราสามารถทดลองใช้งานความสามารถต่างๆ แบบโต้ตอบได้ ซึ่งความสามารถเหล่านี้ยังสามารถใช้งานได้ผ่านทาง API ในรูปแบบโปรแกรม เพื่อเริ่มต้น ให้เรียกใช้คำสั่ง help เพื่อดูรายการคำสั่ง Bitcoin Core RPC ที่มีอยู่:</p>
<pre><code>$ bitcoin-cli help
+== Blockchain ==
getbestblockhash
getblock "blockhash" ( verbosity )
getblockchaininfo
...
walletpassphrase "passphrase" timeout
walletpassphrasechange "oldpassphrase" "newpassphrase"
walletprocesspsbt "psbt" ( sign "sighashtype" bip32derivs finalize )
</code></pre>
<p>คำสั่งแต่ละรายการอาจต้องการพารามิเตอร์หลายตัว เพื่อรับความช่วยเหลือเพิ่มเติม คำอธิบายโดยละเอียด และข้อมูลเกี่ยวกับพารามิเตอร์ต่างๆ ให้เพิ่มชื่อคำสั่งหลังคำว่า help ตัวอย่างเช่น เพื่อดูความช่วยเหลือเกี่ยวกับคำสั่ง RPC getblockhash:</p>
<pre><code>$ bitcoin-cli help getblockhash
getblockhash height
Returns hash of block in best-block-chain at height provided.
Arguments:
1. height    (numeric, required) The height index
Result:
"hex"    (string) The block hash
Examples:
&gt; bitcoin-cli getblockhash 1000
&gt; curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest",
  "method": "getblockhash",
  "params": [1000]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
</code></pre>
<p>ในส่วนท้ายของข้อมูลคำสั่ง help คุณจะเห็นตัวอย่างสองตัวอย่างของคำสั่ง RPC ซึ่งใช้ตัวช่วย bitcoin-cli หรือ HTTP client curl ตัวอย่างเหล่านี้แสดงให้เห็นว่าคุณอาจเรียกใช้คำสั่งได้อย่างไร ลองคัดลอกตัวอย่างแรกและดูผลลัพธ์:</p>
<pre><code>$ bitcoin-cli getblockhash 1000
00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09
</code></pre>
<p>ผลลัพธ์คือแฮชของบล็อก ซึ่งจะอธิบายในรายละเอียดเพิ่มเติมในบทต่อไป แต่ในตอนนี้ คำสั่งนี้ควรให้ผลลัพธ์เหมือนกันบนระบบของคุณ ซึ่งแสดงให้เห็นว่าโหนด Bitcoin Core ของคุณกำลังทำงาน กำลังรับคำสั่ง และมีข้อมูลเกี่ยวกับบล็อก 1,000 ที่จะส่งกลับมาให้คุณ</p>
<h3>การรับข้อมูลสถานะของ Bitcoin Core</h3>
<p>Bitcoin Core ให้รายงานสถานะเกี่ยวกับโมดูลต่างๆ ผ่านอินเตอร์เฟส JSON-RPC คำสั่งที่สำคัญที่สุดรวมถึง getblockchaininfo, getmempoolinfo, getnetworkinfo และ getwalletinfo</p>
<p>คำสั่ง RPC getblockchaininfo ของ Bitcoin ได้ถูกแนะนำไปก่อนหน้านี้แล้ว คำสั่ง getnetworkinfo แสดงข้อมูลพื้นฐานเกี่ยวกับสถานะของโหนดเครือข่าย Bitcoin ใช้ bitcoin-cli เพื่อรันคำสั่งนี้:</p>
<pre><code>$ bitcoin-cli getnetworkinfo
{
  "version": 240001,
  "subversion": "/Satoshi:24.0.1/",
  "protocolversion": 70016,
  "localservices": "0000000000000409",
  "localservicesnames": [
    "NETWORK",
    "WITNESS",
    "NETWORK_LIMITED"
  ],
  "localrelay": true,
  "timeoffset": -1,
  "networkactive": true,
  "connections": 10,
  "connections_in": 0,
  "connections_out": 10,
  "networks": [
    "...detailed information about all networks..."
  ],
  "relayfee": 0.00001000,
  "incrementalfee": 0.00001000,
  "localaddresses": [
  ],
  "warnings": ""
}
</code></pre>
<p>ซึ่งข้อมูลต่าง ๆ จะถูกส่งคืนในรูปแบบ JavaScript Object Notation (JSON) ซึ่งเป็นรูปแบบที่สามารถ "อ่าน" ได้อย่างง่ายดายโดยทุกภาษาโปรแกรมมิ่ง และยังเป็นรูปแบบที่มนุษย์อ่านได้ง่ายอีกด้วย ในข้อมูลนี้เราเห็นหมายเลขเวอร์ชันสำหรับซอฟต์แวร์ Bitcoin Core และโปรโตคอลบิตคอยน์เราเห็นจำนวนการเชื่อมต่อในปัจจุบันและข้อมูลต่างๆ เกี่ยวกับเครือข่ายบิตคอยน์และการตั้งค่าที่เกี่ยวข้องกับโหนดนี้</p>
<blockquote>
<p>TIP: จะใช้เวลาสักระยะ อาจมากกว่าหนึ่งวัน สำหรับ bitcoind ในการอัพเดทให้ทันกับบล็อกล่าสุดของบล็อกเชนปัจจุบัน ในขณะที่มันดาวน์โหลดบล็อกจากโหนดอื่นๆ และตรวจสอบความถูกต้องของทุกธุรกรรมในบล็อกเหล่านั้น—ซึ่งมีเกือบหนึ่งพันล้านธุรกรรม ณ เวลาที่เขียนนี้ คุณสามารถตรวจสอบความคืบหน้าโดยใช้ getblockchaininfo เพื่อดูจำนวนบล็อกที่ทราบ ตัวอย่างในส่วนที่เหลือของบทนี้สมมติว่าคุณอยู่อย่างน้อยที่บล็อก 775,072 เนื่องจากความปลอดภัยของธุรกรรมขึ้นอยู่กับจำ</p>
</blockquote>
<h3>มาสำรวจและถอดรหัสธุรกรรมของบิตคอยน์กันเถอะ!!</h3>
<p>อย่างในบทที่สอง อลิซได้ซื้อสินค้าจากร้านของบ็อบและธุรกรรมของเธอถูกบันทึกลงในบล็อกเชนของบิตคอยน์ โดยเราสามารถใช้ API เพื่อดึงและตรวจสอบธุรกรรมนั้นได้โดยการใช้ txid เป็นพารามิเตอร์:</p>
<pre><code>$ bitcoin-cli getrawtransaction 466200308696215bbc949d5141a49a4138ecdfdfaa2a8029c1f9bcecd1f96177
--ผลลัพธ์ของคำสั่ง
01000000000101eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da13569
8679268041c54a0100000000ffffffff02204e0000000000002251203b41daba
4c9ace578369740f15e5ec880c28279ee7f51b07dca69c7061e07068f8240100
000000001600147752c165ea7be772b2c0acb7f4d6047ae6f4768e0141cf5efe
2d8ef13ed0af21d4f4cb82422d6252d70324f6f4576b727b7d918e521c00b51b
e739df2f899c49dc267c0ad280aca6dab0d2fa2b42a45182fc83e81713010000
0000
</code></pre>
<blockquote>
<p>TIP: txid ไม่ใช่สิ่งที่สามารถเชื่อถือได้ขนาดนั้น เพราะการไม่มี txid ในบล๊อกเชนของบิตคอยน์นั้นไม่ได้หมายความว่าธุรกรรมไม่ได้ถูกประมวลผล โดยสิ่งนี้เรียกว่า "transaction malleability" (ความสามารถในการเปลี่ยนแปลงธุรกรรม) เพราะธุรกรรมสามารถถูกแก้ไขก่อนการยืนยันในบล็อก ซึ่งเปลี่ยน txid ของพวกมัน หลังจากธุรกรรมถูกรวมอยู่ในบล็อกแล้ว txid ของมันไม่สามารถเปลี่ยนแปลงได้อีก เว้นแต่จะมีการจัดระเบียบบล็อกเชนใหม่และบล็อกนั้นถูกลบออกจากบล็อกเชนที่ดีที่สุด โดยการจัดระเบียบใหม่เกิดขึ้นได้ยากหลังจากธุรกรรมได้รับการยืนยันหลายครั้งแล้ว</p>
</blockquote>
<p>คำสั่ง getrawtransaction จะส่งคืนธุรกรรมที่เข้ารหัสในรูปแบบเลขฐานสิบหกและเพื่อถอดรหัสนั้น เราใช้คำสั่ง decoderawtransaction โดยส่งข้อมูลเลขฐานสิบหกเป็นพารามิเตอร์ คุณสามารถคัดลอกเลขฐานสิบหกที่ส่งคืนโดย getrawtransaction และวางเป็นพารามิเตอร์ให้กับ decoderawtransaction ได้:</p>
<pre><code>$ bitcoin-cli decoderawtransaction 01000000000101eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da135698679268041c54a0100000000ffffffff02204e0000000000002251203b41daba4c9ace578369740f15e5ec880c28279ee7f51b07dca69c7061e07068f8240100000000001600147752c165ea7be772b2c0acb7f4d6047ae6f4768e0141cf5efe2d8ef13ed0af21d4f4cb82422d6252d70324f6f4576b727b7d918e521c00b51be739df2f899c49dc267c0ad280aca6dab0d2fa2b42a45182fc83e817130100000000
--ผลลัพธ์ของคำสั่ง
{
  "txid": "466200308696215bbc949d5141a49a4138ecdfdfaa2a8029c1f9bcecd1f96177",
  "hash": "f7cdbc7cf8b910d35cc69962e791138624e4eae7901010a6da4c02e7d238cdac",
  "version": 1,
  "size": 194,
  "vsize": 143,
  "weight": 569,
  "locktime": 0,
  "vin": [
    {
      "txid": "4ac541802679866935a19d4f40728bb89204d0cac90d85f3a51a19...aeb",
      "vout": 1,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "txinwitness": [
        "cf5efe2d8ef13ed0af21d4f4cb82422d6252d70324f6f4576b727b7d918e5...301"
      ],
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 0.00020000,
      "n": 0,
      "scriptPubKey": {
        "asm": "1 3b41daba4c9ace578369740f15e5ec880c28279ee7f51b07dca...068",
        "desc": "rawtr(3b41daba4c9ace578369740f15e5ec880c28279ee7f51b...6ev",
        "hex": "51203b41daba4c9ace578369740f15e5ec880c28279ee7f51b07d...068",
        "address": "bc1p8dqa4wjvnt890qmfws83te0v3qxzsfu7ul63kp7u56w8q...5qn",
        "type": "witness_v1_taproot"
      }
    },
    {
      "value": 0.00075000,
      "n": 1,
      "scriptPubKey": {
        "asm": "0 7752c165ea7be772b2c0acb7f4d6047ae6f4768e",
        "desc": "addr(bc1qwafvze0200nh9vkq4jmlf4sy0tn0ga5w0zpkpg)#qq404gts",
        "hex": "00147752c165ea7be772b2c0acb7f4d6047ae6f4768e",
        "address": "bc1qwafvze0200nh9vkq4jmlf4sy0tn0ga5w0zpkpg",
        "type": "witness_v0_keyhash"
      }
    }
  ]
}
</code></pre>
<p>การถอดรหัสธุรกรรมแสดงส่วนประกอบทั้งหมดของธุรกรรมนี้ รวมถึงอินพุตและเอาต์พุตของธุรกรรม ในกรณีนี้เราเห็นว่าธุรกรรมใช้อินพุตหนึ่งรายการและสร้างเอาต์พุตสองรายการ อินพุตของธุรกรรมนี้คือเอาต์พุตจากธุรกรรมที่ได้รับการยืนยันก่อนหน้านี้ (แสดงเป็น txid ของอินพุต) เอาต์พุตทั้งสองรายการสอดคล้องกับการชำระเงินให้บ็อบและเงินทอนกลับให้อลิซ</p>
<h3>มาสำรวจบล็อกของบิตคอยน์กัน!!</h3>
<p>การสำรวจบล็อกนั้นคล้ายกับการสำรวจธุรกรรม แต่อย่างไรก็ตามบล็อกสามารถอ้างอิงได้ทั้งโดยลำดับของบล็อกหรือโดยแฮชของบล็อก เราใช้คำสั่ง getblockhash ซึ่งรับลำดับของบล็อกเป็นพารามิเตอร์และส่งคืน แฮชของบล็อกนั้น:</p>
<pre><code>$ bitcoin-cli getblockhash 123456
--ผลลัพธ์ของคำสั่ง
0000000000002917ed80650c6174aac8dfc46f5fe36480aaef682ff6cd83c3ca
</code></pre>
<p>ตอนนี้เรารู้แฮชสำหรับบล็อกที่เราเลือกแล้ว เราสามารถดูบล็อกนั้นได้ เราใช้คำสั่ง getblock โดยมีแฮชของบล็อกเป็นพารามิเตอร์:</p>
<pre><code>$ bitcoin-cli getblockhash 0000000000002917ed80650c6174aac8dfc46f5fe36480aaef682ff6cd83c3ca
--ผลลัพธ์ของคำสั่ง
{
  "hash": "0000000000002917ed80650c6174aac8dfc46f5fe36480aaef682ff6cd83c3ca",
  "confirmations": 651742,
  "height": 123456,
  "version": 1,
  "versionHex": "00000001",
  "merkleroot": "0e60651a9934e8f0decd1c[...]48fca0cd1c84a21ddfde95033762d86c",
  "time": 1305200806,
  "mediantime": 1305197900,
  "nonce": 2436437219,
  "bits": "1a6a93b3",
  "difficulty": 157416.4018436489,
  "chainwork": "[...]00000000000000000000000000000000000000541788211ac227bc",
  "nTx": 13,
  "previousblockhash": "[...]60bc96a44724fd72daf9b92cf8ad00510b5224c6253ac40095",
  "nextblockhash": "[...]00129f5f02be247070bf7334d3753e4ddee502780c2acaecec6d66",
  "strippedsize": 4179,
  "size": 4179,
  "weight": 16716,
  "tx": [
    "5b75086dafeede555fc8f9a810d8b10df57c46f9f176ccc3dd8d2fa20edd685b",
    "e3d0425ab346dd5b76f44c222a4bb5d16640a4247050ef82462ab17e229c83b4",
    "137d247eca8b99dee58e1e9232014183a5c5a9e338001a0109df32794cdcc92e",
    "5fd167f7b8c417e59106ef5acfe181b09d71b8353a61a55a2f01aa266af5412d",
    "60925f1948b71f429d514ead7ae7391e0edf965bf5a60331398dae24c6964774",
    "d4d5fc1529487527e9873256934dfb1e4cdcb39f4c0509577ca19bfad6c5d28f",
    "7b29d65e5018c56a33652085dbb13f2df39a1a9942bfe1f7e78e97919a6bdea2",
    "0b89e120efd0a4674c127a76ff5f7590ca304e6a064fbc51adffbd7ce3a3deef",
    "603f2044da9656084174cfb5812feaf510f862d3addcf70cacce3dc55dab446e",
    "9a4ed892b43a4df916a7a1213b78e83cd83f5695f635d535c94b2b65ffb144d3",
    "dda726e3dad9504dce5098dfab5064ecd4a7650bfe854bb2606da3152b60e427",
    "e46ea8b4d68719b65ead930f07f1f3804cb3701014f8e6d76c4bdbc390893b94",
    "864a102aeedf53dd9b2baab4eeb898c5083fde6141113e0606b664c41fe15e1f"
  ]
}
</code></pre>
<p>รายการ confirmations บอกเราถึง ความลึก ของบล็อกนี้—มีกี่บล็อกที่ถูกสร้างทับบนบล็อกนี้ ซึ่งบ่งบอกถึงความยากในการเปลี่ยนแปลงธุรกรรมใดๆ ในบล็อกนี้ ลำดับบอกเราว่ามีกี่บล็อกที่มาก่อนหน้าบล็อกนี้ เราเห็นเวอร์ชันของบล็อก เวลาที่มันถูกสร้าง (ตามข้อมูลของนักขุด) เวลาเฉลี่ยของ 11 บล็อกที่มาก่อนหน้าบล็อกนี้ (การวัดเวลาที่นักขุดปลอมแปลงได้ยากกว่า) และขนาดของบล็อกในการวัดสามแบบต่างกัน (ขนาดดั้งเดิมที่ถูกลบข้อมูลบางส่วนออก, ขนาดเต็ม, และขนาดในหน่วยน้ำหนัก) เรายังเห็นฟิลด์บางอย่างที่ใช้สำหรับความปลอดภัยและหลักฐานการทำงาน (merkle root, nonce, bits, difficulty, และ chainwork) เราจะตรวจสอบสิ่งเหล่านี้โดยละเอียดในส่วนของการขุดในบทที่ 12</p>
<h3>การใช้อินเตอร์เฟสโปรแกรมของ Bitcoin Core</h3>
<p>bitcoin-cli มีประโยชน์มากสำหรับการใช้งาน API ของ Bitcoin Core และการทดสอบฟังก์ชันต่าง ๆ แต่จุดประสงค์หลักของ API คือการเข้าถึงฟังก์ชันด้วยโปรแกรม ในส่วนนี้เราจะสาธิตการเข้าถึง Bitcoin Core จากโปรแกรมอื่น</p>
<p>API ของ Bitcoin Core เป็นอินเตอร์เฟส JSON-RPC โดย JSON เป็นวิธีที่สะดวกมากในการนำเสนอข้อมูลที่ทั้งมนุษย์และโปรแกรมสามารถอ่านได้ง่าย RPC ย่อมาจาก remote procedure call ซึ่งหมายความว่าเรากำลังเรียกใช้กระบวนการ (ฟังก์ชัน) ที่อยู่ห่างไกล (บนโหนด Bitcoin Core) ผ่านโปรโตคอลเครือข่าย ในกรณีนี้ โปรโตคอลเครือข่ายคือ HTTP</p>
<p>เมื่อเราใช้คำสั่ง bitcoin-cli เพื่อขอความช่วยเหลือเกี่ยวกับคำสั่ง มันแสดงตัวอย่างการใช้ curl ซึ่งเป็นไคลเอนต์ HTTP ทางคอมมานด์ไลน์ที่ยืดหยุ่น เพื่อสร้างคำเรียก JSON-RPC เหล่านี้:</p>
<pre><code>$ curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest",
  "method": "getblockchaininfo",
  "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/
</code></pre>
<p>คำสั่งนี้แสดงว่า curl ส่งคำขอ HTTP ไปยัง localhost (127.0.0.1) เชื่อมต่อกับพอร์ต RPC เริ่มต้นของ Bitcoin (8332) และส่งคำขอ jsonrpc โดยใช้เมธอดเป็น getblockchaininfo โดยใช้การเข้ารหัสแบบ text/plain</p>
<p>คุณอาจสังเกตว่า curl จะขอให้ส่งข้อมูลประจำตัวไปพร้อมกับคำขอ Bitcoin Core จะสร้างรหัสผ่านแบบสุ่มในแต่ละครั้งที่เริ่มต้นและวางไว้ในไดเรกทอรีข้อมูลภายใต้ชื่อ .cookie โดย bitcoin-cli สามารถอ่านไฟล์รหัสผ่านนี้โดยให้ไดเรกทอรีข้อมูล ในทำนองเดียวกัน คุณสามารถคัดลอกรหัสผ่านและส่งไปยัง curl (หรือตัวครอบ Bitcoin Core RPC ระดับสูงอื่น ๆ ) ตามที่เห็นในการใช้การตรวจสอบสิทธิ์แบบใช้คุกกี้กับ Bitcoin Core</p>
<p>ตัวอย่างที่ 3. การใช้การตรวจสอบสิทธิ์แบบใช้คุกกี้กับ Bitcoin Core</p>
<pre><code>$ cat .bitcoin/.cookie
  __cookie__:17c9b71cef21b893e1a019f4bc071950c7942f49796ed061b274031b17b19cd0
$ curl
  --user __cookie__:17c9b71cef21b893e1a019f4bc071950c7942f49796ed061b274031b17b19cd0
  --data-binary '{"jsonrpc": "1.0", "id":"curltest",
  "method": "getblockchaininfo",
  "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/
{"result":{"chain":"main","blocks":799278,"headers":799278,
"bestblockhash":"000000000000000000018387c50988ec705a95d6f765b206b6629971e6978879",
"difficulty":53911173001054.59,"time":1689703111,"mediantime":1689701260,
"verificationprogress":0.9999979206082515,"initialblockdownload":false,
"chainwork":"00000000000000000000000000000000000000004f3e111bf32bcb47f9dfad5b",
"size_on_disk":563894577967,"pruned":false,"warnings":""},"error":null,
"id":"curltest"}
</code></pre>
<p>นอกจากนี้คุณยังสามารถตั้งรหัสผ่านด้วยตัวเองใน ./share/rpcauth/rpcauth.py ภายในไดเรกทอรีของ Bitcoin Core</p>
<p>หากคุณกำลังใช้การเรียก JSON-RPC ในโปรแกรมของคุณเอง คุณสามารถใช้ไลบรารี HTTP ทั่วไปเพื่อสร้างการเรียกได้ คล้ายกับที่แสดงในตัวอย่าง curl ก่อนหน้านี้</p>
<p>อย่างไรก็ตาม มีไลบรารีในภาษาโปรแกรมยอดนิยมส่วนใหญ่ที่ "wrap" API ของ Bitcoin Core ในลักษณะที่ทำให้การใช้งานง่ายขึ้นมาก เราจะใช้ไลบรารี python-bitcoinlib เพื่อทำให้การเข้าถึง API นั้นง่ายขึ้น โดยไลบรารีนี้ไม่ได้เป็นส่วนหนึ่งของโครงการ Bitcoin Core และจำเป็นต้องติดตั้งด้วยวิธีปกติที่คุณติดตั้งไลบรารี Python โปรดจำไว้ว่า การใช้งานนี้ต้องมีอินสแตนซ์ Bitcoin Core ที่กำลังทำงานอยู่ ซึ่งจะถูกใช้เพื่อทำการเรียก JSON-RPC</p>
<p>ตัวอย่างสคริปต์ Python ใน " การทำงาน getblockchaininfo ผ่าน API JSON-RPC ของ Bitcoin Core" ซึ่งทำการเรียก getblockchaininfo อย่างง่ายและพิมพ์พารามิเตอร์ block จากข้อมูลที่ส่งคืนโดย Bitcoin Core</p>
<p>ตัวอย่างที่ 4. การทำงาน getblockchaininfo ผ่าน API JSON-RPC ของ Bitcoin Core</p>
<pre><code>from bitcoin.rpc import RawProxy
# Create a connection to local Bitcoin Core node
p = RawProxy()
# Run the getblockchaininfo command, store the resulting data in info
info = p.getblockchaininfo()
# Retrieve the 'blocks' element from the info
print(info['blocks'])
--ผลลัพธ์ของคำสั่ง
$ python rpc_example.py
773973
</code></pre>
<p>มันบอกเราว่าโหนด Bitcoin Core ในเครื่องของเรามีกี่บล็อกในบล็อกเชนของมัน ซึ่งไม่ใช่ผลลัพธ์ที่น่าทึ่ง แต่มันแสดงการใช้งานพื้นฐานของไลบรารีในฐานะอินเตอร์เฟสที่ถูกทำให้ง่ายขึ้นสำหรับ API JSON-RPC ของ Bitcoin Core</p>
<p>ต่อไป เราจะใช้คำสั่ง getrawtransaction และ decodetransaction เพื่อดึงข้อมูลรายละเอียดของการชำระเงินจาก Alice ไปยัง Bob ในส่วนของการดึงข้อมูลธุรกรรมและการวนลูปเอาต์พุตของธุรกรรม เราจะดึงธุรกรรมของ Alice และแสดงรายการเอาต์พุตของธุรกรรม สำหรับแต่ละเอาต์พุต เราจะแสดงที่อยู่ผู้รับและมูลค่า โดยธุรกรรมของ Alice มีเอาต์พุตหนึ่งรายการที่จ่ายให้ Bob และอีกหนึ่งรายการเป็นเงินทอนกลับไปยัง Alice</p>
<p>ตัวอย่างที่ 5 การดึงข้อมูลธุรกรรมและการวนลูปเอาต์พุตของธุรกรรม</p>
<pre><code>from bitcoin.rpc import RawProxy
p = RawProxy()
# Alice's transaction ID
txid = "466200308696215bbc949d5141a49a4138ecdfdfaa2a8029c1f9bcecd1f96177"
# First, retrieve the raw transaction in hex
raw_tx = p.getrawtransaction(txid)
# Decode the transaction hex into a JSON object
decoded_tx = p.decoderawtransaction(raw_tx)
# Retrieve each of the outputs from the transaction
for output in decoded_tx['vout']:
    print(output['scriptPubKey']['address'], output['value'])
--ผลลัพธ์ของคำสั่ง
$ python rpc_transaction.py
bc1p8dqa4wjvnt890qmfws83te0v3qxzsfu7ul63kp7u56w8qc0qwp5qv995qn 0.00020000
bc1qwafvze0200nh9vkq4jmlf4sy0tn0ga5w0zpkpg 0.00075000
</code></pre>
<p>ตัวอย่างทั้งสองข้างต้นค่อนข้างง่าย คุณไม่จำเป็นต้องใช้โปรแกรมในการรันพวกมัน คุณสามารถใช้ตัวช่วย bitcoin-cli ได้ง่าย ๆ แต่อย่างไรก็ตาม ตัวอย่างถัดไปต้องใช้การเรียก RPC หลายร้อยครั้งและแสดงให้เห็นถึงการใช้อินเทอร์เฟซเชิงโปรแกรมได้ชัดเจนยิ่งขึ้น</p>
<p>ในส่วนของการดึงข้อมูลบล็อกและการรวมเอาต์พุตของทุกธุรกรรม เราจะเริ่มต้นด้วยการดึงข้อมูลบล็อก จากนั้นดึงข้อมูลธุรกรรมแต่ละรายการภายในบล็อกโดยอ้างอิงถึง ID ของแต่ละธุรกรรม ต่อมา เราจะวนลูปผ่านเอาต์พุตของแต่ละธุรกรรมและรวมมูลค่าทั้งหมด</p>
<p>ตัวอย่างที่ 6 การดึงข้อมูลบล็อกและการรวมเอาต์พุตของทุกธุรกรรม</p>
<pre><code>from bitcoin.rpc import RawProxy
p = RawProxy()
# The block height where Alice's transaction was recorded
blockheight = 775072
# Get the block hash of the block at the given height
blockhash = p.getblockhash(blockheight)
# Retrieve the block by its hash
block = p.getblock(blockhash)
# Element tx contains the list of all transaction IDs in the block
transactions = block['tx']
block_value = 0
# Iterate through each transaction ID in the block
for txid in transactions:
    tx_value = 0
    # Retrieve the raw transaction by ID
    raw_tx = p.getrawtransaction(txid)
    # Decode the transaction
    decoded_tx = p.decoderawtransaction(raw_tx)
    # Iterate through each output in the transaction
    for output in decoded_tx['vout']:
        # Add up the value of each output
        tx_value = tx_value + output['value']
    # Add the value of this transaction to the total
    block_value = block_value + tx_value
print("Total value in block: ", block_value)
--ผลลัพธ์ของคำสั่ง
$ python rpc_block.py
Total value in block:  10322.07722534
</code></pre>
<p>โค้ดตัวอย่างของเราคำนวณว่ามูลค่ารวมที่ถูกทำธุรกรรมในบล็อกนี้คือ 10,322.07722534 BTC (รวมถึงรางวัล 25 BTC และค่าธรรมเนียม 0.0909 BTC) ลองเปรียบเทียบกับจำนวนที่รายงานโดยเว็บไซต์สำรวจบล็อก (block explorer) โดยการค้นหาแฮชของบล็อกหรือเลขลำดับของบล็อก เครื่องมือสำรวจบล็อกบางตัวรายงานมูลค่ารวมโดยไม่รวมรางวัลและไม่รวมค่าธรรมเนียม ลองดูว่าคุณสามารถสังเกตเห็นความแตกต่างได้หรือไม่</p>
<h3>ไคลเอนต์ทางเลือก, ไลบรารี, และชุดเครื่องมือ</h3>
<p>C/C++<br>Bitcoin Core:การใช้งานอ้างอิงของ Bitcoin<br>JavaScript<br>bcoin: การใช้งานโหนดแบบเต็มรูปแบบที่มีความยืดหยุ่นและขยายได้พร้อม API<br>Bitcore: โหนดเต็มรูปแบบ, API, และไลบรารีโดย Bitpay<br>BitcoinJS: ไลบรารี Bitcoin ที่เขียนด้วย JavaScript ล้วนๆ สำหรับ node.js และเบราว์เซอร์<br>Java<br>bitcoinj: ไลบรารีไคลเอนต์โหนดเต็มรูปแบบที่เขียนด้วย Java<br>Python<br>python-bitcoinlib: ไลบรารี Bitcoin, ไลบรารีฉันทามติ, และโหนดที่เขียนด้วย Python โดย Peter Todd<br>pycoin: ไลบรารี Bitcoin ที่เขียนด้วย Python โดย Richard Kiss<br>Go<br>btcd: ไคลเอนต์ Bitcoin โหนดเต็มรูปแบบที่เขียนด้วยภาษา Go<br>Rust<br>rust-bitcoin: ไลบรารี Bitcoin ที่เขียนด้วย Rust สำหรับการจัดรูปแบบข้อมูล, การแยกวิเคราะห์, และการเรียกใช้ API<br>Scala<br>bitcoin-s: การใช้งาน Bitcoin ที่เขียนด้วย Scala<br>C#<br>NBitcoin: ไลบรารี Bitcoin ที่ครอบคลุมสำหรับเฟรมเวิร์ก .NET</p>
<p>ยังมีไลบรารีอีกมากมายในภาษาโปรแกรมมิ่งอื่น ๆ อีกหลากหลาย และมีการสร้างขึ้นใหม่อยู่ตลอดเวลา</p>
<p>หากคุณทำตามคำแนะนำในบทนี้ ตอนนี้คุณมี Bitcoin Core ที่ทำงานอยู่และได้เริ่มสำรวจเครือข่ายและบล็อกเชนโดยใช้โหนดของคุณเอง จากนี้ไปคุณสามารถใช้ซอฟต์แวร์ที่คุณควบคุมได้โดยอิสระ—บนคอมพิวเตอร์ที่คุณควบคุม—เพื่อตรวจสอบว่า bitcoin ใด ๆ ที่คุณได้รับปฏิบัติตามกฎทุกข้อในระบบ Bitcoin โดยไม่ต้องไว้วางใจองค์กรภายนอกใด ๆ ในบทต่อไป เราจะเรียนรู้เพิ่มเติมเกี่ยวกับกฎของระบบและวิธีที่โหนดและกระเป๋าเงินของคุณใช้กฎเหล่านั้นเพื่อรักษาความปลอดภัยของเงินของคุณ ปกป้องความเป็นส่วนตัวของคุณ และทำให้การใช้จ่ายและการรับเงินสะดวกสบาย</p>
<p>ฮึ่ ๆ หลาม ๆ มาอีกแล้ว จริง ๆ เนื้อหาของบทที่สามมันจบลงตรงนี้แหละ แต่ว่าถ้าสมมุตืว่าใครลองไปทำตามจริง ๆ แล้วอยากรู้ว่าเราสามารถทำอะไรจาก node ของเราได้อีกบ้าง เลยมีกิจกรรมขำ ๆ มาให้ทำครับ โดยความยากจะมีทั้งหมด 3 ระดับ ดังนี้</p>
<ul>
<li>ง่าย (สามารถหาคำตอบได้ด้วย bitcoin-cli command เดียว)</li>
</ul>
<ol>
<li>แฮชของบล๊อก 774698 คืออะไร?</li>
<li>signature ของข้อความจาก address นี้ถูกต้องหรือไม่</li>
</ol>
<pre><code>address: 1E9YwDtYf9R29ekNAfbV7MvB4LNv7v3fGa
message: 1E9YwDtYf9R29ekNAfbV7MvB4LNv7v3fGa
signature:HCsBcgB+Wcm8kOGMH8IpNeg0H4gjCrlqwDf/GlSXphZGBYxm0QkKEPhh9DTJRp2IDNUhVr0FhP9qCqo2W0recNM=
</code></pre>
<ul>
<li>ทำได้แหละ (สามารถหาคำตอบได้ด้วย bitcoin-cli command เดียว หรืออาจจะมากกว่าหนึ่ง)</li>
</ul>
<ol start="3">
<li>มี output ใหม่กี่อันที่เกิดในบล๊อก 774698 ?</li>
<li>ใช้ wallet descriptors หา taproot address ที่ 100 จาก extended public key ที่กำหนดให้ xpub6DLd5RvY42Q5HAmBhHPUbDGdeS9VvsYNauiuN8r6NzbiXSSNWpNVrDGTUScJ9fS2orMtuB3VdxMdUH83fPtwbrizfJg9LwWnGqtL7RTs5h1</li>
<li>สร้าง multisig address แบบ P2SH แบบ 1-of-4 จาก publickey ในอินพุตทั้งสี่ของธุรกรรมนี้:37d966a263350fe747f1c606b159987545844a493dd38d84b070027a895c4517</li>
</ol>
<ul>
<li>ต้องคิดเชิงตรรกะได้เล็กน้อย (สามารถหาคำตอบได้ด้วย bitcoin-cli command และพวก if-else/loop)</li>
</ul>
<ol start="6">
<li>tx ใดในบล็อก 257,343 ที่ใช้เอาท์พุตของ coinbase ของบล็อก 256,128?</li>
<li>มีเอาต์พุตเดียวที่ยังไม่ได้ใช้งานจากบล็อก 123,321 เอาต์พุตดังกล่าวถูกส่งไปที่ address ไหน</li>
<li>public key ใดที่ลงนามอินพุต 0 ใน tx นี้:e5969add849689854ac7f28e45628b89f7454b83e9699e551ce14b6f90c86163</li>
</ol>
<p>ใครทำได้พร้อมแชร์วิธีการใต้โพสต์นี้เดี๋ยวจะมีไดโนเสาร์ส่งแซตเป็นกำลังใจให้เล็กน้อยครับ</p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<h2>Bitcoin Core: The Reference Implementation</h2>
<hr>
<p>ผู้คนจะยอมรับเงินใด ๆ เพื่อแลกเปลี่ยนกับสินค้าและบริการก็ต่อเมื่อคนนั้น ๆ เชื่อว่าเงินนี้จะมีมูลค่าในอนาคต เงินปลอมหรือเงินที่เสื่อมค่าโดยไม่คาดคิดนั้นอาจไม่สามารถใช้ได้ในอนาคต ดังนั้นทุกคนที่รับบิตคอยน์จึงมีแรงจูงใจที่แข็งแกร่งในการตรวจสอบความถูกต้องของบิตคอยน์ที่พวกเขาได้รับ ระบบของบิตคอยน์นั้นถูกออกแบบมาให้เข้าถึง, ป้องกันการปลอมแปลง, การเสื่อมค่า และปัญหาสำคัญอื่น ๆ ได้อย่างสมบูรณ์ได้ด้วยคอมพิวเตอร์ทั่วไป โดยซอฟต์แวร์ที่ให้ฟังก์ชันนี้เรียกว่า Full node ซึ่งทำหน้าที่ตรวจสอบธุรกรรมบิตคอยน์ทุกครั้งที่ได้รับการยืนยันตามกฎของระบบ นอกจากนี้ Full node ยังสามารถให้เครื่องมือและข้อมูลเพื่อทำความเข้าใจการทำงานของบิตคอยน์และสภาพปัจจุบันของเครือข่าย</p>
<p>ในบทนี้เอง เราจะทำการติดตั้ง Bitcoin Core ซึ่งเป็นซอฟต์แวร์ที่ผู้ใช้งาน Full node ส่วนใหญ่เลือกใช้เพื่อเป็นประตูบานแรกในการเข้าถึงระบบนิเวศของบิตคอยน์ เราจะตรวจสอบบล็อก ธุรกรรม และข้อมูลอื่น ๆ จากโหนดของคุณ ซึ่งเป็นข้อมูลที่เชื่อถือได้ (ไม่ใช่เพราะหน่วยงานทรงอำนาจกำหนดให้เป็นเช่นนั้น) แต่เป็นเพราะโหนดของคุณได้ตรวจสอบข้อมูลนั้นอย่างอิสระ ตลอดเนื้อหาที่เหลือในหนังสือเล่มนี้ เราจะใช้ Bitcoin Core เพื่อสร้างและตรวจสอบข้อมูลที่เกี่ยวข้องกับบล็อกเชนและเครือข่าย</p>
<h3>จาก Bitcoin สู่ Bitcoin Core</h3>
<p>บิตคอยน์เป็นโครงการโอเพ่นซอร์ส โดยซอร์สโค้ดทั้งหมดก็สามารถดาวน์โหลดและใช้งานได้ฟรีภายใต้ใบอณุญาตแบบเปิด (MIT License) นอกจากจะเป็นโอเพ่นซอร์สแล้วบิตคอยน์ยังได้รับการพัฒนาโดยชุมชนอาสาสมัครแบบเปิดกว้าง แน่นอนว่าในช่วงแรกนั้นชุมชนนี้ประกอบด้วย Satoshi Nakamoto เพียงคนเดียว แต่ภายในปี 2023 ซอร์สโค้ดของบิตคอยน์มีผู้ร่วมพัฒนามากกว่า 1,000 คน</p>
<p>เมื่อ Satoshi Nakamoto ได้สร้างซอฟแวร์บิตคอยน์ตัวนี้และพัฒนามันจนเกือบสมบูรณ์ก่อนแล้วจึงเผยแพร่เอกสารไวท์เปเปอร์ เขาน่าจะต้องการให้มั่นใจว่าการใช้งานจริงสามารถทำงานได้ก่อนเผยแพร่เอกสาร โดยซอฟต์แวร์เวอร์ชันแรกที่รู้จักในชื่อ "Bitcoin" นั้นได้รับการปรับปรุงและพัฒนามาอย่างมาก จนได้กลายเป็นสิ่งที่เรารู้จักกันในชื่อ Bitcoin Core และเพื่อแยกความแตกต่างจากการใช้งานอื่น ๆ Bitcoin Core เป็นซอฟต์แวร์ต้นแบบอ้างอิง (reference implementation) ของระบบบิตคอยน์ซึ่งแสดงวิธีการทำงานของแต่ละส่วนในเชิงเทคโนโลยี นอกจากนี้ Bitcoin Core รวมถึงการใช้งานฟังก์ชันทั้งหมดของบิตคอยน์ เช่น กระเป๋าเงิน เครื่องมือตรวจสอบธุรกรรมและบล็อก เครื่องมือสำหรับการสร้างบล็อก และส่วนต่าง ๆ ของการสื่อสารแบบ peer-to-peer ของบิตคอยน์<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1741413625372-YAKIHONNES3.png" alt="image"></p>
<h3>Bitcoin Development Environment</h3>
<p>สำหรับนักพัฒนาที่ต้องการเขียนแอปพลิเคชันเกี่ยวกับบิตคอยน์ ทั้งการตั้งค่าสภาพแวดล้อมสำหรับการพัฒนาพร้อมเครื่องมือ ไลบรารี และซอฟต์แวร์สนับสนุนเป็นสิ่งสำคัญ ซึ่งเนื้อหาในบทนี้นั้นจะเป็นเรื่องทางเทคนิคอลค่อนข้างเยอะ ในบทนี้เราจะอธิบายขั้นตอนการตั้งค่าอย่างละเอียด หากคุณพบว่าเนื้อหานี้ซับซ้อนเกินไป (และไม่ได้ต้องการตั้งค่าสภาพแวดล้อมสำหรับการพัฒนาจริง ๆ) คุณสามารถข้ามไปยังบทถัดไปที่มีเนื้อหาน้อยทางเทคนิคกว่าได้</p>
<h3>มาคอมไพล์ Bitcoin core จากซอร์สโค้ดกันเถอะ !!</h3>
<p>ซอร์สโค้ดทั้งหมดของ BItcoin Core นั้นสามารถดาวน์โหลดได้ในรูปแบบไฟล์อาร์ไคฟ์หรือโดยการโคลนที่เก็บซอร์สโค้ดจาก GitHub โดยตรง บนหน้าดาวน์โหลดของ Bitcoin Core ให้เลือกเวอร์ชันล่าสุดและดาวน์โหลดไฟล์อัดบีบของซอร์สโค้ด หรือใช้คำสั่ง Git เพื่อสร้างสำเนาซอร์สโค้ดบนเครื่องของคุณจากหน้า GitHub ของ Bitcoin</p>
<blockquote>
<p>TIP: ในตัวอย่างหลาย ๆ ส่วนของบทนี้ เราจะใช้ อินเทอร์เฟซบรรทัดคำสั่ง (Command-Line Interface - CLI) ของระบบปฏิบัติการ หรือที่เรียกว่า "shell" ซึ่งสามารถเข้าถึงได้ผ่านแอปพลิเคชัน terminal โดย shell จะแสดง พรอมต์ (prompt) เพื่อรอรับคำสั่งที่คุณพิมพ์ จากนั้นจะแสดงผลลัพธ์ออกมาแล้วรอรับคำสั่งถัดไป</p>
</blockquote>
<blockquote>
<p>TIP จากหลาม: แบบง่าย ๆ ก็คือไม่ต้องพิมพ์ $ และถ้าพิมพ์จบหนึ่งคำสั่งก็กด enter ซ่ะด้วย</p>
</blockquote>
<p>ขั้นตอนในการลง bitcoin core มีดังนี้:</p>
<ol>
<li>สั่ง git clone เพื่อทำการสร้างสำเนาของซอร์สโค้ดลงในเครื่องของเรา</li>
</ol>
<pre><code>$ git clone https://github.com/bitcoin/bitcoin.git
Cloning into 'bitcoin'...
remote: Enumerating objects: 245912, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 245912 (delta 1), reused 2 (delta 1), pack-reused 245909
Receiving objects: 100% (245912/245912), 217.74 MiB | 13.05 MiB/s, done.
Resolving deltas: 100% (175649/175649), done.
</code></pre>
<blockquote>
<p>TIP: Git เป็นระบบควบคุมเวอร์ชันแบบกระจายที่ใช้กันอย่างแพร่หลายและเป็นส่วนสำคัญในเครื่องมือของนักพัฒนาซอฟต์แวร์ คุณอาจจำเป็นต้องติดตั้งคำสั่ง git หรือส่วนต่อประสานกราฟิก (GUI) สำหรับ Git บนระบบปฏิบัติการของคุณ หากยังไม่มี </p>
</blockquote>
<ol start="2">
<li>เมื่อการโคลน Git เสร็จสมบูรณ์แล้ว คุณจะมีสำเนาท้องถิ่นครบถ้วนของที่เก็บซอร์สโค้ดในไดเรกทอรี bitcoin ให้เปลี่ยนไปยังไดเรกทอรีนี้โดยใช้คำสั่ง cd:</li>
</ol>
<pre><code>$ cd bitcoin
</code></pre>
<ol start="3">
<li>เลือก version ของ bitcoin core: โดยค่าเริ่มต้น สำเนาจองเราจะซิงโครไนซ์กับโค้ดล่าสุด ซึ่งอาจเป็นเวอร์ชันที่ไม่เสถียรหรือเบต้าของ Bitcoin ก่อนที่จะคอมไพล์โค้ด ให้เลือกเวอร์ชันเฉพาะโดยการตรวจสอบ (checkout) แท็กของการปล่อย (release tag) ซึ่งจะซิงโครไนซ์สำเนาท้องถิ่นกับสแนปช็อตของที่เก็บซอร์สโค้ดที่ระบุด้วยแท็ก แท็กเหล่านี้ถูกใช้งานโดยนักพัฒนาเพื่อระบุเวอร์ชันของโค้ดตามหมายเลขเวอร์ชัน ซึ่งทำได้โดยใช้คำสั่ง git tag</li>
</ol>
<pre><code>$ git tag
v0.1.5
v0.1.6test1
v0.10.0
...
v0.11.2
v0.11.2rc1
v0.12.0rc1
v0.12.0rc2
...
</code></pre>
<p>รายการแท็กจะแสดงทุกเวอร์ชันที่ปล่อยออกมา โดยทั่วไป release candidates (เวอร์ชันทดสอบ) จะมีต่อท้ายว่า "rc" ส่วนเวอร์ชันเสถียรที่ใช้งานในระบบ production จะไม่มีต่อท้ายอะไรเลย จากรายการด้านบน ให้เลือกเวอร์ชันที่สูงสุด ซึ่งในขณะที่เขียนบทความนี้คือ v24.0.1 เพื่อซิงโครไนซ์โค้ดท้องถิ่นกับเวอร์ชันนี้ ให้ใช้คำสั่ง:</p>
<pre><code>$ git checkout v24.0.1
Note: switching to 'v24.0.1'.
</code></pre>
<p>จากนั้นสั่ง git status เพื่อเช็คเวอร์ชัน</p>
<h3>Configuring the Bitcoin Core Build</h3>
<p>ในโค้ดของบิตคอยน์ที่เราได้ดาวน์โหลดมาในหัวข้อก่อนหน้านั้น มีเอกสารประกอบอยู่หลายไฟล์ โดยคุณสามารถดูเอกสารหลักได้จากไฟล์ README.md ในไดเรกทอรี bitcoin ในบทนี้ เราจะสร้าง daemon (เซิร์ฟเวอร์) ของ Bitcoin Core ซึ่งรู้จักกันในชื่อ bitcoind บน Linux (หรือระบบที่คล้ายกับ Unix) โดยให้ตรวจสอบคำแนะนำสำหรับการคอมไพล์ bitcoind แบบบรรทัดคำสั่งบนแพลตฟอร์มของคุณโดยอ่านไฟล์ doc/build-unix.md นอกจากนี้ ยังมีคำแนะนำสำหรับระบบอื่น ๆ ในไดเรกทอรี doc เช่น build-windows.md สำหรับ Windows จนถึงขณะนี้ คำแนะนำมีให้สำหรับ Android, FreeBSD, NetBSD, OpenBSD, macOS (OSX), Unix</p>
<p>หลังจากนั้นคุณควรตรวจสอบความต้องการเบื้องต้นในการสร้าง (build pre-requisites) ซึ่งระบุไว้ในส่วนแรกของเอกสารการสร้าง สิ่งเหล่านี้คือไลบรารีที่ต้องมีอยู่ในระบบของคุณก่อนที่คุณจะเริ่มคอมไพล์ Bitcoin หากมีไลบรารีที่จำเป็นหายไป กระบวนการสร้างจะล้มเหลวและแสดงข้อผิดพลาด หากเกิดปัญหานี้เพราะคุณพลาด pre-requisite คุณสามารถติดตั้งไลบรารีที่ขาดหายไปแล้วดำเนินการสร้างต่อจากจุดที่ค้างไว้</p>
<p>สมมุติว่า pre-requisite ถูกติดตั้งแล้ว ให้เริ่มกระบวนการสร้างโดยการสร้างชุดสคริปต์สำหรับการสร้างด้วยการรันสคริปต์ autogen.sh:</p>
<hr>
<pre><code>$ ./autogen.sh
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, 'build-aux'.
libtoolize: copying file 'build-aux/ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'build-aux/m4'.
 ...
configure.ac:58: installing 'build-aux/missing'
src/Makefile.am: installing 'build-aux/depcomp'
parallel-tests: installing 'build-aux/test-driver'
</code></pre>
<p>สคริปต์ autogen.sh นี้จะสร้างชุดสคริปต์ที่กำหนดค่าอัตโนมัติที่จะตรวจสอบระบบของคุณเพื่อค้นหาการตั้งค่าที่ถูกต้องและตรวจสอบให้แน่ใจว่ามีไลบรารีที่จำเป็นสำหรับการคอมไพล์โค้ด โดยสคริปต์ที่สำคัญที่สุดในสคริปต์เหล่านี้คือสคริปต์ configure ซึ่งมีตัวเลือกต่าง ๆ สำหรับการปรับแต่งกระบวนการสร้าง</p>
<p>ใช้ flag --help เพื่อดูตัวเลือกทั้งหมด:</p>
<pre><code>$ ./configure --help
`configure' configures Bitcoin Core 24.0.1 to adapt to many kinds of systems.
Usage: ./configure [OPTION]... [VAR=VALUE]...
...
Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
  --enable-silent-rules   less verbose build output (undo: "make V=1")
  --disable-silent-rules  verbose build output (undo: "make V=0")
...
</code></pre>
<p>สคริปต์ configure ช่วยให้คุณสามารถเปิดหรือปิดคุณสมบัติบางอย่างของ bitcoind ผ่านการใช้ flag --enable-FEATURE และ --disable-FEATURE โดยที่ FEATURE แทนชื่อคุณสมบัติที่ระบุในข้อความช่วยเหลือ ในบทนี้ เราจะสร้าง bitcoind ด้วยคุณสมบัติตั้งต้นทั้งหมด โดยไม่ใช้ flag การกำหนดค่าเพิ่มเติม แต่คุณควรตรวจสอบตัวเลือกเหล่านี้เพื่อเข้าใจว่ามีคุณสมบัติเพิ่มเติมอะไรบ้าง หากคุณอยู่ในสภาพแวดล้อมทางการศึกษา ห้องปฏิบัติการคอมพิวเตอร์ หรือมีข้อจำกัดในการติดตั้งโปรแกรม คุณอาจต้องติดตั้งแอปพลิเคชันไว้ในไดเรกทอรี home (เช่นโดยใช้ flag --prefix=$HOME)</p>
<p>ตัวเลือกที่มีประโยชน์สำหรับการกำหนดค่า</p>
<ul>
<li>--prefix=$HOME: เปลี่ยนตำแหน่งการติดตั้งเริ่มต้น (ซึ่งโดยปกติคือ /usr/local/) ให้เป็นไดเรกทอรี home ของคุณ หรือเส้นทางที่คุณต้องการ</li>
<li>--disable-wallet: ใช้เพื่อปิดการใช้งานฟังก์ชัน wallet แบบอ้างอิง</li>
<li>--with-incompatible-bdb: หากคุณกำลังสร้าง wallet ให้ยอมรับการใช้ไลบรารี Berkeley DB เวอร์ชันที่ไม่เข้ากันได้</li>
<li>--with-gui=no: ไม่สร้างส่วนติดต่อผู้ใช้แบบกราฟิก (GUI) ซึ่งต้องใช้ไลบรารี Qt โดยตัวเลือกนี้จะสร้างเฉพาะเซิร์ฟเวอร์และ Bitcoin Core แบบ commandline เท่านั้น</li>
</ul>
<pre><code>
</code></pre>
<p>ต่อไป ให้รันสคริปต์ configure เพื่อให้ระบบตรวจสอบไลบรารีที่จำเป็นทั้งหมดและสร้างสคริปต์สำหรับการสร้างที่ปรับแต่งให้ตรงกับระบบของคุณ:</p>
<pre><code>$ ./configure
checking for pkg-config... /usr/bin/pkg-config
checking pkg-config is at least version 0.9.0... yes
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking for a BSD-compatible install... /usr/bin/install -c
...
[many pages of configuration tests follow]
...
</code></pre>
<p>หากทุกอย่างดำเนินไปด้วยดี คำสั่ง configure จะสิ้นสุดด้วยการสร้างสคริปต์การสร้างที่ปรับแต่งให้กับระบบของคุณ แต่หากมีไลบรารีที่หายไปหรือเกิดข้อผิดพลาด คำสั่ง configure จะหยุดและแสดงข้อผิดพลาดแทนที่จะสร้างสคริปต์ในกรณีที่เกิดข้อผิดพลาดขึ้น สาเหตุที่พบบ่อยคือการขาดหายหรือความไม่เข้ากันของไลบรารี ให้ตรวจสอบเอกสารการสร้างอีกครั้งและติดตั้ง pre-requisite ที่ขาดไป จากนั้นรัน configure อีกครั้งเพื่อดูว่าปัญหานั้นได้รับการแก้ไขแล้วหรือไม่</p>
<h3>การสร้าง Executable ของ Bitcoin Core</h3>
<p>ต่อไป คุณจะทำการคอมไพล์ซอร์สโค้ด กระบวนการนี้อาจใช้เวลาถึงหนึ่งชั่วโมง ขึ้นอยู่กับความเร็วของ CPU และหน่วยความจำที่มีอยู่ หากเกิดข้อผิดพลาด หรือการคอมไพล์ถูกขัดจังหวะ คุณสามารถดำเนินการต่อได้โดยการพิมพ์คำสั่ง make อีกครั้ง</p>
<p>พิมพ์ make เพื่อเริ่มคอมไพล์แอปพลิเคชันที่สามารถรันได้:</p>
<pre><code>$ make
Making all in src
  CXX      bitcoind-bitcoind.o
  CXX      libbitcoin_node_a-addrdb.o
  CXX      libbitcoin_node_a-addrman.o
  CXX      libbitcoin_node_a-banman.o
  CXX      libbitcoin_node_a-blockencodings.o
  CXX      libbitcoin_node_a-blockfilter.o
[... many more compilation messages follow ...]
</code></pre>
<p>บนระบบที่มีความเร็วและมี CPU หลายคอร์ คุณอาจต้องการตั้งค่าจำนวนงานคอมไพล์แบบขนาน (parallel compile jobs) เช่น การใช้คำสั่ง make -j 2 จะใช้สองคอร์หากมีอยู่ หากทุกอย่างดำเนินไปด้วยดี Bitcoin Core จะถูกคอมไพล์เรียบร้อยแล้ว คุณควรรันชุดการทดสอบหน่วย (unit test suite) ด้วยคำสั่ง make check เพื่อให้แน่ใจว่าไลบรารีที่ลิงค์เข้าด้วยกันไม่มีข้อผิดพลาดอย่าง ขั้นตอนสุดท้ายคือการติดตั้ง executable ต่าง ๆ ลงในระบบของคุณโดยใช้คำสั่ง make install ซึ่งอาจมีการร้องขอรหัสผ่านของผู้ใช้เนื่องจากขั้นตอนนี้ต้องการสิทธิ์ผู้ดูแลระบบ:</p>
<pre><code>$ make check &amp;&amp; sudo make install
Password:
Making install in src
 ../build-aux/install-sh -c -d '/usr/local/lib'
libtool: install: /usr/bin/install -c bitcoind /usr/local/bin/bitcoind
libtool: install: /usr/bin/install -c bitcoin-cli /usr/local/bin/bitcoin-cli
libtool: install: /usr/bin/install -c bitcoin-tx /usr/local/bin/bitcoin-tx
...
</code></pre>
<p>การติดตั้งเริ่มต้นของ bitcoind จะอยู่ในไดเรกทอรี /usr/local/bin โดยคุณสามารถตรวจสอบว่า Bitcoin Core ถูกติดตั้งเรียบร้อยแล้วโดยใช้คำสั่งเพื่อตรวจสอบตำแหน่งของ executable ดังนี้:</p>
<pre><code>$ which bitcoind
/usr/local/bin/bitcoind
$ which bitcoin-cli
/usr/local/bin/bitcoin-cli
</code></pre>
<h3>มาลองรัน Bitcoin node กันเถอะ</h3>
<p>อย่างที่ได้กล่าวในบทก่อนหน้า เครือข่ายแบบเพียร์ทูเพียร์ของบิตคอยน์ประกอบด้วยเครือข่าย "โหนด" ซึ่งส่วนใหญ่รันโดยบุคคลและธุรกิจบางแห่งที่ให้บริการ ผู้ที่รันโหนดบิตคอยน์จะมีมุมมองที่ตรงและน่าเชื่อถือเกี่ยวกับบล๊อกเชนของบิตคอยน์พร้อมสำเนาข้อมูลบิตคอยน์ที่ใช้จ่ายได้ทั้งหมดซึ่งได้รับการตรวจสอบอย่างอิสระโดยระบบของตนเอง การรันโหนดทำให้คุณไม่ต้องพึ่งบุคคลที่สามในการตรวจสอบธุรกรรม นอกจากนี้การใช้โหนดบิตคอยน์เพื่อตรวจสอบธุรกรรมที่ได้รับในกระเป๋าเงินของคุณ ยังช่วยให้คุณมีส่วนร่วมในเครือข่ายบิตคอยน์และช่วยทำให้เครือข่ายมีความแข็งแกร่งมากขึ้นอีกด้วย</p>
<p>การรันโหนดต้องดาวน์โหลดและประมวลผลข้อมูลมากกว่า 500 GB ในช่วงเริ่มแรก และประมาณ 400 MB ของธุรกรรม Bitcoin ต่อวัน ตัวเลขเหล่านี้เป็นของปี 2023 และอาจเพิ่มขึ้นในอนาคต หากคุณปิดโหนดหรือหลุดจากอินเทอร์เน็ตเป็นเวลาหลายวัน โหนดของคุณจะต้องดาวน์โหลดข้อมูลที่พลาดไป ตัวอย่างเช่น หากคุณปิด Bitcoin Core เป็นเวลา 10 วัน คุณจะต้องดาวน์โหลดประมาณ 4 GB ในครั้งถัดไปที่คุณเริ่มใช้งาน</p>
<p>ขึ้นอยู่กับการเลือกของคุณว่าจะทำดัชนีธุรกรรมทั้งหมดและเก็บสำเนาบล๊อกเชนแบบเต็ม คุณอาจต้องใช้พื้นที่ดิสก์มาก - อย่างน้อย 1 TB หากคุณวางแผนจะรัน Bitcoin Core เป็นเวลาหลายปี โดยค่าเริ่มต้นโหนดบิตคอยน์ยังส่งธุรกรรมและบล็อกไปยังโหนดอื่น ๆ (เรียกว่า "เพียร์") ซึ่งจะใช้แบนด์วิดท์อัปโหลดอินเทอร์เน็ต หากการเชื่อมต่ออินเทอร์เน็ตของคุณมีขีดจำกัด มีขีดจำกัดการใช้ข้อมูลต่ำ หรือคิดค่าบริการตามข้อมูล (เมตเตอร์) คุณไม่ควรรันโหนดบิตคอยน์บนระบบนั้น หรือรันโดยจำกัดแบนด์วิดท์ (ดู การกำหนดค่าโหนด Bitcoin Core) คุณอาจเชื่อมต่อโหนดของคุณแทนไปยังเครือข่ายทางเลือก เช่น ผู้ให้บริการข้อมูลดาวเทียมฟรีอย่าง Blockstream Satellite</p>
<blockquote>
<p>Tip: Bitcoin Core เก็บสำเนาบล๊อกเชนแบบเต็ม (ตามค่าเริ่มต้น ) พร้อมธุรกรรมเกือบทั้งหมดที่เคยได้รับการยืนยันบนเครือข่าย Bitcoin ตั้งแต่เริ่มต้นในปี 2009 ชุดข้อมูลนี้มีขนาดหลายร้อย GB และจะถูกดาวน์โหลดเพิ่มขึ้นทีละน้อยในช่วงหลายชั่วโมงหรือหลายวัน ขึ้นอยู่กับความเร็ว CPU และการเชื่อมต่ออินเทอร์เน็ตของคุณ Bitcoin Core จะไม่สามารถประมวลผลธุรกรรมหรืออัปเดตยอดคงเหลือของบัญชีจนกว่าชุดข้อมูล blockchain จะดาวน์โหลดเสร็จสมบูรณ์ ตรวจสอบให้แน่ใจว่าคุณมีพื้นที่ดิสก์ แบนด์วิดท์ และเวลาเพียงพอในการซิงโครไนซ์เริ่มแรก คุณสามารถกำหนดค่า Bitcoin Core เพื่อลดขนาด blockchain โดยการทิ้งบล็อกเก่า แต่โปรแกรมยังคงดาวน์โหลดชุดข้อมูลทั้งหมด</p>
</blockquote>
<blockquote>
<p>TIPจากหลาม agian: ซื้อ NVMe SSD 2TB เป็นอย่างต่ำซ่ะ m.2 ได้ยิ่งดีเลยจ้า </p>
</blockquote>
<p>แม้ว่าจะมีข้อกำหนดด้านทรัพยากรเหล่านี้ แต่มีผู้คนหลายพันรายที่รันโหนด Bitcoin บางคนรันบนระบบง่าย ๆ อย่าง Raspberry Pi (คอมพิวเตอร์ราคา 35 เหรียญสหรัฐที่มีขนาดเท่ากับกล่องบุหรี่)</p>
<p>ทำไมคุณถึงอยากรันโหนด? นี่คือเหตุผลที่พบบ่อยที่สุด:</p>
<ul>
<li>คุณไม่ต้องการพึ่งบุคคลที่สามในการตรวจสอบธุรกรรมที่คุณได้รับ</li>
<li>คุณไม่ต้องการเปิดเผยให้บุคคลที่สามรู้ว่าธุรกรรมใดเป็นของกระเป๋าเงินคุณ</li>
<li>คุณกำลังพัฒนาซอฟต์แวร์ Bitcoin และต้องการพึ่งโหนด Bitcoin เพื่อเข้าถึงเครือข่ายและ blockchain ผ่าน API</li>
<li>คุณกำลังสร้างแอปพลิเคชันที่ต้องตรวจสอบธุรกรรมตามกฎฉันทามติของ Bitcoin โดยทั่วไป บริษัทซอฟต์แวร์ Bitcoin มักจะรันโหนดหลายโหนด</li>
<li>คุณต้องการสนับสนุน Bitcoin การรันโหนดที่คุณใช้ตรวจสอบธุรกรรมที่ได้รับในกระเป๋าเงินจะช่วยทำให้เครือข่ายมีความแข็งแกร่งมากขึ้น</li>
</ul>
<p>หากคุณกำลังอ่านหนังสือเล่มนี้และสนใจความปลอดภัยที่เข้มงวด ความเป็นส่วนตัวที่เหนือกว่า หรือการพัฒนาซอฟต์แวร์ Bitcoin คุณควรรันโหนดของตัวเอง</p>
<h3>การกำหนดค่าโหนด Bitcoin Core</h3>
<p>Bitcoin Core จะค้นหาไฟล์การกำหนดค่าในไดเรกทอรีข้อมูลทุกครั้งที่เริ่มทำงาน ในส่วนนี้เราจะตรวจสอบตัวเลือกการกำหนดค่าต่าง ๆ และตั้งค่าไฟล์การกำหนดค่า</p>
<p>เพื่อค้นหาไฟล์การกำหนดค่า ให้รัน bitcoind -printtoconsole ในเทอร์มินัลของคุณ และดูบรรทัดแรก ๆ:</p>
<pre><code>$ bitcoind -printtoconsole
2023-01-28T03:21:42Z Bitcoin Core version v24.0.1
2023-01-28T03:21:42Z Using the 'x86_shani(1way,2way)' SHA256 implementation
2023-01-28T03:21:42Z Using RdSeed as an additional entropy source
2023-01-28T03:21:42Z Using RdRand as an additional entropy source
2023-01-28T03:21:42Z Default data directory /home/harding/.bitcoin
2023-01-28T03:21:42Z Using data directory /home/harding/.bitcoin
2023-01-28T03:21:42Z Config file: /home/harding/.bitcoin/bitcoin.conf
...
[a lot more debug output]
...
</code></pre>
<blockquote>
<p>tatatipจากหลามอีกครั้ง: สังเกตเห็นหรือไม่ว่าในตัวอย่างนี้ Bitcoin Core กำลังชี้ไปที่ไฟล์การกำหนดค่าที่ไดเรกทอรี /home/harding/.bitcoin/bitcoin.conf ซึ่งจะแตกต่างกันไปขึ้นอยู่กับผู้ใช้และระบบปฏิบัติการ</p>
</blockquote>
<p>คุณสามารถกด Ctrl-C เพื่อปิดโหนดหลังจากที่ระบุตำแหน่งไฟล์การกำหนดค่า โดยปกติไฟล์การกำหนดค่าจะอยู่ในไดเรกทอรี .bitcoin ภายใต้โฮมไดเรกทอรีของผู้ใช้ เปิดไฟล์ configuration ด้วยโปรแกรมแก้ไขได้ตามที่คุณชอบ</p>
<p>Bitcoin Core มีตัวเลือกการกำหนดค่ามากกว่า 100 ตัวเลือกที่สามารถปรับเปลี่ยนพฤติกรรมของโหนดเครือข่าย การจัดเก็บบล๊อกเชน และแง่มุมอื่น ๆ ของการทำงาน เพื่อดูรายการตัวเลือก ให้รัน bitcoind --help:</p>
<pre><code>$ bitcoind --help
Bitcoin Core version v24.0.1
Usage:  bitcoind [options]                     Start Bitcoin Core
Options:
  -?
       Print this help message and exit
  -alertnotify=&lt;cmd&gt;
       Execute command when an alert is raised (%s in cmd is replaced by
       message)
...
[many more options]
</code></pre>
<p>นี่คือตัวเลือกที่บางประการที่คุณสามารถตั้งในไฟล์ configuration หรือเป็นพารามิเตอร์บรรทัดคำสั่งสำหรับ bitcoind:</p>
<ul>
<li>alertnotify: เรียกใช้คำสั่งหรือสคริปต์เพื่อส่งการแจ้งเตือนฉุกเฉินไปยังเจ้าของโหนดนี้</li>
<li>conf: ตำแหน่งทางเลือกสำหรับไฟล์ configuration เมื่อใช้เป็นพารามิเตอร์ cli สำหรับ bitcoind เท่านั้น เนื่องจากไม่สามารถอยู่ในไฟล์ configuration ที่มันอ้างถึงได้</li>
<li>datadir: เลือกไดเรกทอรีและระบบไฟล์สำหรับจัดเก็บข้อมูลบล๊อกเชนตามค่าเริ่มต้นนี้คือไดเรกทอรีย่อย .bitcoin ในไดเรกทอรีโฮมของคุณ ขึ้นอยู่กับการกำหนดค่า สามารถใช้พื้นที่ตั้งแต่ประมาณ 10 GB ถึงเกือบ 1 TB ณ ขณะนี้ คาดว่าขนาดสูงสุดจะเพิ่มขึ้นหลายร้อย GB ต่อปี</li>
<li>prune: ลดความต้องการพื้นที่ดิสก์บล๊อกเชนลงเหลือกี่เมกะไบต์โดยการลบบล็อกเก่า ใช้สำหรับโหนดที่มีทรัพยากรจำกัดซึ่งไม่สามารถบรรจุบล๊อกเชนแบบเต็มได้ ส่วนอื่น ๆ ของระบบจะใช้พื้นที่ดิสก์อื่นที่ไม่สามารถตัดทอนได้ ดังนั้นคุณยังคงต้องมีพื้นที่อย่างน้อยตามที่ระบุในตัวเลือก datadir</li>
<li>txindex: รักษาดัชนีของธุรกรรมทั้งหมด ช่วยให้คุณสามารถดึงธุรกรรมใด ๆ โดยใช้ ID ของมันได้โดยโปรแกรม โดยที่บล็อกที่มีธุรกรรมนั้นยังไม่ถูกตัดทอน</li>
<li>dbcache: ขนาดของแคช UTXO ค่าเริ่มต้นคือ 450 เมบิไบต์ (MiB) เพิ่มขนาดนี้บนฮาร์ดแวร์ระดับสูงเพื่ออ่านและเขียนจากดิสก์น้อยลง หรือลดขนาดลงบนฮาร์ดแวร์ระดับต่ำเพื่อประหยัดหน่วยความจำโดยยอมให้ใช้ดิสก์บ่อยขึ้น</li>
<li>blocksonly: ลดการใช้แบนด์วิดท์โดยการรับเฉพาะบล็อกของธุรกรรมที่ได้รับการยืนยันจากเพียร์ แทนที่จะส่งต่อธุรกรรมที่ยังไม่ได้รับการยืนยัน</li>
<li>maxmempool: จำกัดพูลหน่วยความจำของธุรกรรมเป็นกี่เมกะไบต์ ใช้เพื่อลดการใช้หน่วยความจำบนโหนดที่มีหน่วยความจำจำกัด</li>
</ul>
<h3>ดัชนีฐานข้อมูลธุรกรรมและตัวเลือก txindex</h3>
<p>ตามค่าเริ่มต้น Bitcoin Core จะสร้างฐานข้อมูลที่มีเพียงธุรกรรมที่เกี่ยวข้องกับกระเป๋าเงินของผู้ใช้เท่านั้น หากคุณต้องการสามารถเข้าถึงธุรกรรมใด ๆ ด้วยคำสั่งเช่น getrawtransaction คุณจะต้องกำหนดค่า Bitcoin Core ให้สร้างดัชนีธุรกรรมแบบสมบูรณ์ ซึ่งสามารถทำได้ด้วยตัวเลือก txindex โดยตั้ง txindex=1 ในไฟล์การกำหนดค่า Bitcoin Core หากคุณไม่ได้ตั้งตัวเลือกนี้ตั้งแต่แรกและต่อมาตั้งเป็นการทำดัชนีแบบเต็ม คุณจะต้องรอให้มันสร้างดัชนีใหม่</p>
<p>ตัวอย่างการกำหนดค่าโหนดดัชนีแบบเต็มแสดงวิธีที่คุณอาจรวมตัวเลือกก่อนหน้านี้กับโหนดที่มีดัชนีแบบเต็ม โดยทำงานเป็นแบ็กเอนด์ API สำหรับแอปพลิเคชัน bitcoin</p>
<p>ตัวอย่างที่ 1. การกำหนดค่าโหนดดัชนีแบบเต็ม</p>
<pre><code>alertnotify=myemailscript.sh "Alert: %s"
datadir=/lotsofspace/bitcoin
txindex=1
</code></pre>
<p>ตัวอย่างที่ 2. การกำหนดค่าระบบที่มีทรัพยากรจำกัด</p>
<pre><code>alertnotify=myemailscript.sh "Alert: %s"
blocksonly=1
prune=5000
dbcache=150
maxmempool=150
</code></pre>
<p>หลังจากที่คุณแก้ไขไฟล์การกำหนดค่าและตั้งตัวเลือกที่ดีที่สุดตามความต้องการของคุณ คุณสามารถทดสอบ bitcoind ด้วยการกำหนดค่านี้ รัน Bitcoin Core ด้วยตัวเลือก printtoconsole เพื่อรันที่ foreground พร้อมแสดงผลลัพธ์ที่คอนโซล:</p>
<pre><code>$ bitcoind -printtoconsole
2023-01-28T03:43:39Z Bitcoin Core version v24.0.1
2023-01-28T03:43:39Z Using the 'x86_shani(1way,2way)' SHA256 implementation
2023-01-28T03:43:39Z Using RdSeed as an additional entropy source
2023-01-28T03:43:39Z Using RdRand as an additional entropy source
2023-01-28T03:43:39Z Default data directory /home/harding/.bitcoin
2023-01-28T03:43:39Z Using data directory /lotsofspace/bitcoin
2023-01-28T03:43:39Z Config file: /home/harding/.bitcoin/bitcoin.conf
2023-01-28T03:43:39Z Config file arg: [main] blockfilterindex="1"
2023-01-28T03:43:39Z Config file arg: [main] maxuploadtarget="1000"
2023-01-28T03:43:39Z Config file arg: [main] txindex="1"
2023-01-28T03:43:39Z Setting file arg: wallet = ["msig0"]
2023-01-28T03:43:39Z Command-line arg: printtoconsole=""
2023-01-28T03:43:39Z Using at most 125 automatic connections
2023-01-28T03:43:39Z Using 16 MiB out of 16 MiB requested for signature cache
2023-01-28T03:43:39Z Using 16 MiB out of 16 MiB requested for script execution
2023-01-28T03:43:39Z Script verification uses 3 additional threads
2023-01-28T03:43:39Z scheduler thread start
2023-01-28T03:43:39Z [http] creating work queue of depth 16
2023-01-28T03:43:39Z Using random cookie authentication.
2023-01-28T03:43:39Z Generated RPC cookie /lotsofspace/bitcoin/.cookie
2023-01-28T03:43:39Z [http] starting 4 worker threads
2023-01-28T03:43:39Z Using wallet directory /lotsofspace/bitcoin/wallets
2023-01-28T03:43:39Z init message: Verifying wallet(s)…
2023-01-28T03:43:39Z Using BerkeleyDB version Berkeley DB 4.8.30
2023-01-28T03:43:39Z Using /16 prefix for IP bucketing
2023-01-28T03:43:39Z init message: Loading P2P addresses…
2023-01-28T03:43:39Z Loaded 63866 addresses from peers.dat  114ms
[... more startup messages ...]
</code></pre>
<p>คุณสามารถกด Ctrl-C เพื่อหยุดกระบวนการเมื่อคุณพอใจว่ากำลังโหลดการตั้งค่าที่ถูกต้องและทำงานตามที่คาดหวัง</p>
<p>เพื่อรัน Bitcoin Core ที่พื้นหลังเป็นโพรเซส ให้เริ่มด้วยตัวเลือก daemon เช่น bitcoind -daemon</p>
<p>เพื่อตรวจสอบความคืบหน้าและสถานะการทำงานของโหนด Bitcoin ให้เริ่มในโหมด daemon แล้วใช้คำสั่ง bitcoin-cli getblockchaininfo:</p>
<pre><code>$ bitcoin-cli getblockchaininfo

{
"chain": "main",
"blocks": 0,
"headers": 83999,
"bestblockhash": "[...]19d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"difficulty": 1,
"time": 1673379796,
"mediantime": 1231006505,
"verificationprogress": 3.783041623201835e-09,
"initialblockdownload": true,
"chainwork": "[...]000000000000000000000000000000000000000000000100010001",
"size_on_disk": 89087,
"pruned": false,
"warnings": ""
}
</code></pre>
<p>นี่แสดงโหนดที่มีความสูงของ blockchain เป็น 0 บล็อก และ 83,999 เฮดเดอร์ โหนดจะดึงเฮดเดอร์ของบล็อกจากเพียร์ของตนก่อนเพื่อค้นหา blockchain ที่มีหลักฐานการทำงานมากที่สุด จากนั้นจึงดำเนินการดาวน์โหลดบล็อกเต็มโดยตรวจสอบความถูกต้องไปพร้อมกัน</p>
<p>เมื่อคุณพอใจกับตัวเลือกการกำหนดค่าที่เลือก คุณควรเพิ่ม Bitcoin Core ลงในสคริปต์เริ่มต้นของระบบปฏิบัติการ เพื่อให้มันทำงานอย่างต่อเนื่องและรีสตาร์ทเมื่อระบบปฏิบัติการรีสตาร์ท คุณจะพบสคริปต์เริ่มต้นตัวอย่างสำหรับระบบปฏิบัติการต่าง ๆ ในไดเรกทอรีซอร์สของ Bitcoin Core ภายใต้ contrib/init และไฟล์ README.md ที่แสดงว่าระบบใดใช้สคริปต์ใด</p>
<h3>Bitcoin Core API</h3>
<p>Bitcoin Core ใช้อินเทอร์เฟซ JSON-RPC ซึ่งสามารถเข้าถึงได้โดยใช้เครื่องมืออย่าง bitcoin-cli ซึ่งช่วยให้เราสามารถทดลองใช้งานความสามารถต่างๆ แบบโต้ตอบได้ ซึ่งความสามารถเหล่านี้ยังสามารถใช้งานได้ผ่านทาง API ในรูปแบบโปรแกรม เพื่อเริ่มต้น ให้เรียกใช้คำสั่ง help เพื่อดูรายการคำสั่ง Bitcoin Core RPC ที่มีอยู่:</p>
<pre><code>$ bitcoin-cli help
+== Blockchain ==
getbestblockhash
getblock "blockhash" ( verbosity )
getblockchaininfo
...
walletpassphrase "passphrase" timeout
walletpassphrasechange "oldpassphrase" "newpassphrase"
walletprocesspsbt "psbt" ( sign "sighashtype" bip32derivs finalize )
</code></pre>
<p>คำสั่งแต่ละรายการอาจต้องการพารามิเตอร์หลายตัว เพื่อรับความช่วยเหลือเพิ่มเติม คำอธิบายโดยละเอียด และข้อมูลเกี่ยวกับพารามิเตอร์ต่างๆ ให้เพิ่มชื่อคำสั่งหลังคำว่า help ตัวอย่างเช่น เพื่อดูความช่วยเหลือเกี่ยวกับคำสั่ง RPC getblockhash:</p>
<pre><code>$ bitcoin-cli help getblockhash
getblockhash height
Returns hash of block in best-block-chain at height provided.
Arguments:
1. height    (numeric, required) The height index
Result:
"hex"    (string) The block hash
Examples:
&gt; bitcoin-cli getblockhash 1000
&gt; curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest",
  "method": "getblockhash",
  "params": [1000]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
</code></pre>
<p>ในส่วนท้ายของข้อมูลคำสั่ง help คุณจะเห็นตัวอย่างสองตัวอย่างของคำสั่ง RPC ซึ่งใช้ตัวช่วย bitcoin-cli หรือ HTTP client curl ตัวอย่างเหล่านี้แสดงให้เห็นว่าคุณอาจเรียกใช้คำสั่งได้อย่างไร ลองคัดลอกตัวอย่างแรกและดูผลลัพธ์:</p>
<pre><code>$ bitcoin-cli getblockhash 1000
00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09
</code></pre>
<p>ผลลัพธ์คือแฮชของบล็อก ซึ่งจะอธิบายในรายละเอียดเพิ่มเติมในบทต่อไป แต่ในตอนนี้ คำสั่งนี้ควรให้ผลลัพธ์เหมือนกันบนระบบของคุณ ซึ่งแสดงให้เห็นว่าโหนด Bitcoin Core ของคุณกำลังทำงาน กำลังรับคำสั่ง และมีข้อมูลเกี่ยวกับบล็อก 1,000 ที่จะส่งกลับมาให้คุณ</p>
<h3>การรับข้อมูลสถานะของ Bitcoin Core</h3>
<p>Bitcoin Core ให้รายงานสถานะเกี่ยวกับโมดูลต่างๆ ผ่านอินเตอร์เฟส JSON-RPC คำสั่งที่สำคัญที่สุดรวมถึง getblockchaininfo, getmempoolinfo, getnetworkinfo และ getwalletinfo</p>
<p>คำสั่ง RPC getblockchaininfo ของ Bitcoin ได้ถูกแนะนำไปก่อนหน้านี้แล้ว คำสั่ง getnetworkinfo แสดงข้อมูลพื้นฐานเกี่ยวกับสถานะของโหนดเครือข่าย Bitcoin ใช้ bitcoin-cli เพื่อรันคำสั่งนี้:</p>
<pre><code>$ bitcoin-cli getnetworkinfo
{
  "version": 240001,
  "subversion": "/Satoshi:24.0.1/",
  "protocolversion": 70016,
  "localservices": "0000000000000409",
  "localservicesnames": [
    "NETWORK",
    "WITNESS",
    "NETWORK_LIMITED"
  ],
  "localrelay": true,
  "timeoffset": -1,
  "networkactive": true,
  "connections": 10,
  "connections_in": 0,
  "connections_out": 10,
  "networks": [
    "...detailed information about all networks..."
  ],
  "relayfee": 0.00001000,
  "incrementalfee": 0.00001000,
  "localaddresses": [
  ],
  "warnings": ""
}
</code></pre>
<p>ซึ่งข้อมูลต่าง ๆ จะถูกส่งคืนในรูปแบบ JavaScript Object Notation (JSON) ซึ่งเป็นรูปแบบที่สามารถ "อ่าน" ได้อย่างง่ายดายโดยทุกภาษาโปรแกรมมิ่ง และยังเป็นรูปแบบที่มนุษย์อ่านได้ง่ายอีกด้วย ในข้อมูลนี้เราเห็นหมายเลขเวอร์ชันสำหรับซอฟต์แวร์ Bitcoin Core และโปรโตคอลบิตคอยน์เราเห็นจำนวนการเชื่อมต่อในปัจจุบันและข้อมูลต่างๆ เกี่ยวกับเครือข่ายบิตคอยน์และการตั้งค่าที่เกี่ยวข้องกับโหนดนี้</p>
<blockquote>
<p>TIP: จะใช้เวลาสักระยะ อาจมากกว่าหนึ่งวัน สำหรับ bitcoind ในการอัพเดทให้ทันกับบล็อกล่าสุดของบล็อกเชนปัจจุบัน ในขณะที่มันดาวน์โหลดบล็อกจากโหนดอื่นๆ และตรวจสอบความถูกต้องของทุกธุรกรรมในบล็อกเหล่านั้น—ซึ่งมีเกือบหนึ่งพันล้านธุรกรรม ณ เวลาที่เขียนนี้ คุณสามารถตรวจสอบความคืบหน้าโดยใช้ getblockchaininfo เพื่อดูจำนวนบล็อกที่ทราบ ตัวอย่างในส่วนที่เหลือของบทนี้สมมติว่าคุณอยู่อย่างน้อยที่บล็อก 775,072 เนื่องจากความปลอดภัยของธุรกรรมขึ้นอยู่กับจำ</p>
</blockquote>
<h3>มาสำรวจและถอดรหัสธุรกรรมของบิตคอยน์กันเถอะ!!</h3>
<p>อย่างในบทที่สอง อลิซได้ซื้อสินค้าจากร้านของบ็อบและธุรกรรมของเธอถูกบันทึกลงในบล็อกเชนของบิตคอยน์ โดยเราสามารถใช้ API เพื่อดึงและตรวจสอบธุรกรรมนั้นได้โดยการใช้ txid เป็นพารามิเตอร์:</p>
<pre><code>$ bitcoin-cli getrawtransaction 466200308696215bbc949d5141a49a4138ecdfdfaa2a8029c1f9bcecd1f96177
--ผลลัพธ์ของคำสั่ง
01000000000101eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da13569
8679268041c54a0100000000ffffffff02204e0000000000002251203b41daba
4c9ace578369740f15e5ec880c28279ee7f51b07dca69c7061e07068f8240100
000000001600147752c165ea7be772b2c0acb7f4d6047ae6f4768e0141cf5efe
2d8ef13ed0af21d4f4cb82422d6252d70324f6f4576b727b7d918e521c00b51b
e739df2f899c49dc267c0ad280aca6dab0d2fa2b42a45182fc83e81713010000
0000
</code></pre>
<blockquote>
<p>TIP: txid ไม่ใช่สิ่งที่สามารถเชื่อถือได้ขนาดนั้น เพราะการไม่มี txid ในบล๊อกเชนของบิตคอยน์นั้นไม่ได้หมายความว่าธุรกรรมไม่ได้ถูกประมวลผล โดยสิ่งนี้เรียกว่า "transaction malleability" (ความสามารถในการเปลี่ยนแปลงธุรกรรม) เพราะธุรกรรมสามารถถูกแก้ไขก่อนการยืนยันในบล็อก ซึ่งเปลี่ยน txid ของพวกมัน หลังจากธุรกรรมถูกรวมอยู่ในบล็อกแล้ว txid ของมันไม่สามารถเปลี่ยนแปลงได้อีก เว้นแต่จะมีการจัดระเบียบบล็อกเชนใหม่และบล็อกนั้นถูกลบออกจากบล็อกเชนที่ดีที่สุด โดยการจัดระเบียบใหม่เกิดขึ้นได้ยากหลังจากธุรกรรมได้รับการยืนยันหลายครั้งแล้ว</p>
</blockquote>
<p>คำสั่ง getrawtransaction จะส่งคืนธุรกรรมที่เข้ารหัสในรูปแบบเลขฐานสิบหกและเพื่อถอดรหัสนั้น เราใช้คำสั่ง decoderawtransaction โดยส่งข้อมูลเลขฐานสิบหกเป็นพารามิเตอร์ คุณสามารถคัดลอกเลขฐานสิบหกที่ส่งคืนโดย getrawtransaction และวางเป็นพารามิเตอร์ให้กับ decoderawtransaction ได้:</p>
<pre><code>$ bitcoin-cli decoderawtransaction 01000000000101eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da135698679268041c54a0100000000ffffffff02204e0000000000002251203b41daba4c9ace578369740f15e5ec880c28279ee7f51b07dca69c7061e07068f8240100000000001600147752c165ea7be772b2c0acb7f4d6047ae6f4768e0141cf5efe2d8ef13ed0af21d4f4cb82422d6252d70324f6f4576b727b7d918e521c00b51be739df2f899c49dc267c0ad280aca6dab0d2fa2b42a45182fc83e817130100000000
--ผลลัพธ์ของคำสั่ง
{
  "txid": "466200308696215bbc949d5141a49a4138ecdfdfaa2a8029c1f9bcecd1f96177",
  "hash": "f7cdbc7cf8b910d35cc69962e791138624e4eae7901010a6da4c02e7d238cdac",
  "version": 1,
  "size": 194,
  "vsize": 143,
  "weight": 569,
  "locktime": 0,
  "vin": [
    {
      "txid": "4ac541802679866935a19d4f40728bb89204d0cac90d85f3a51a19...aeb",
      "vout": 1,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "txinwitness": [
        "cf5efe2d8ef13ed0af21d4f4cb82422d6252d70324f6f4576b727b7d918e5...301"
      ],
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 0.00020000,
      "n": 0,
      "scriptPubKey": {
        "asm": "1 3b41daba4c9ace578369740f15e5ec880c28279ee7f51b07dca...068",
        "desc": "rawtr(3b41daba4c9ace578369740f15e5ec880c28279ee7f51b...6ev",
        "hex": "51203b41daba4c9ace578369740f15e5ec880c28279ee7f51b07d...068",
        "address": "bc1p8dqa4wjvnt890qmfws83te0v3qxzsfu7ul63kp7u56w8q...5qn",
        "type": "witness_v1_taproot"
      }
    },
    {
      "value": 0.00075000,
      "n": 1,
      "scriptPubKey": {
        "asm": "0 7752c165ea7be772b2c0acb7f4d6047ae6f4768e",
        "desc": "addr(bc1qwafvze0200nh9vkq4jmlf4sy0tn0ga5w0zpkpg)#qq404gts",
        "hex": "00147752c165ea7be772b2c0acb7f4d6047ae6f4768e",
        "address": "bc1qwafvze0200nh9vkq4jmlf4sy0tn0ga5w0zpkpg",
        "type": "witness_v0_keyhash"
      }
    }
  ]
}
</code></pre>
<p>การถอดรหัสธุรกรรมแสดงส่วนประกอบทั้งหมดของธุรกรรมนี้ รวมถึงอินพุตและเอาต์พุตของธุรกรรม ในกรณีนี้เราเห็นว่าธุรกรรมใช้อินพุตหนึ่งรายการและสร้างเอาต์พุตสองรายการ อินพุตของธุรกรรมนี้คือเอาต์พุตจากธุรกรรมที่ได้รับการยืนยันก่อนหน้านี้ (แสดงเป็น txid ของอินพุต) เอาต์พุตทั้งสองรายการสอดคล้องกับการชำระเงินให้บ็อบและเงินทอนกลับให้อลิซ</p>
<h3>มาสำรวจบล็อกของบิตคอยน์กัน!!</h3>
<p>การสำรวจบล็อกนั้นคล้ายกับการสำรวจธุรกรรม แต่อย่างไรก็ตามบล็อกสามารถอ้างอิงได้ทั้งโดยลำดับของบล็อกหรือโดยแฮชของบล็อก เราใช้คำสั่ง getblockhash ซึ่งรับลำดับของบล็อกเป็นพารามิเตอร์และส่งคืน แฮชของบล็อกนั้น:</p>
<pre><code>$ bitcoin-cli getblockhash 123456
--ผลลัพธ์ของคำสั่ง
0000000000002917ed80650c6174aac8dfc46f5fe36480aaef682ff6cd83c3ca
</code></pre>
<p>ตอนนี้เรารู้แฮชสำหรับบล็อกที่เราเลือกแล้ว เราสามารถดูบล็อกนั้นได้ เราใช้คำสั่ง getblock โดยมีแฮชของบล็อกเป็นพารามิเตอร์:</p>
<pre><code>$ bitcoin-cli getblockhash 0000000000002917ed80650c6174aac8dfc46f5fe36480aaef682ff6cd83c3ca
--ผลลัพธ์ของคำสั่ง
{
  "hash": "0000000000002917ed80650c6174aac8dfc46f5fe36480aaef682ff6cd83c3ca",
  "confirmations": 651742,
  "height": 123456,
  "version": 1,
  "versionHex": "00000001",
  "merkleroot": "0e60651a9934e8f0decd1c[...]48fca0cd1c84a21ddfde95033762d86c",
  "time": 1305200806,
  "mediantime": 1305197900,
  "nonce": 2436437219,
  "bits": "1a6a93b3",
  "difficulty": 157416.4018436489,
  "chainwork": "[...]00000000000000000000000000000000000000541788211ac227bc",
  "nTx": 13,
  "previousblockhash": "[...]60bc96a44724fd72daf9b92cf8ad00510b5224c6253ac40095",
  "nextblockhash": "[...]00129f5f02be247070bf7334d3753e4ddee502780c2acaecec6d66",
  "strippedsize": 4179,
  "size": 4179,
  "weight": 16716,
  "tx": [
    "5b75086dafeede555fc8f9a810d8b10df57c46f9f176ccc3dd8d2fa20edd685b",
    "e3d0425ab346dd5b76f44c222a4bb5d16640a4247050ef82462ab17e229c83b4",
    "137d247eca8b99dee58e1e9232014183a5c5a9e338001a0109df32794cdcc92e",
    "5fd167f7b8c417e59106ef5acfe181b09d71b8353a61a55a2f01aa266af5412d",
    "60925f1948b71f429d514ead7ae7391e0edf965bf5a60331398dae24c6964774",
    "d4d5fc1529487527e9873256934dfb1e4cdcb39f4c0509577ca19bfad6c5d28f",
    "7b29d65e5018c56a33652085dbb13f2df39a1a9942bfe1f7e78e97919a6bdea2",
    "0b89e120efd0a4674c127a76ff5f7590ca304e6a064fbc51adffbd7ce3a3deef",
    "603f2044da9656084174cfb5812feaf510f862d3addcf70cacce3dc55dab446e",
    "9a4ed892b43a4df916a7a1213b78e83cd83f5695f635d535c94b2b65ffb144d3",
    "dda726e3dad9504dce5098dfab5064ecd4a7650bfe854bb2606da3152b60e427",
    "e46ea8b4d68719b65ead930f07f1f3804cb3701014f8e6d76c4bdbc390893b94",
    "864a102aeedf53dd9b2baab4eeb898c5083fde6141113e0606b664c41fe15e1f"
  ]
}
</code></pre>
<p>รายการ confirmations บอกเราถึง ความลึก ของบล็อกนี้—มีกี่บล็อกที่ถูกสร้างทับบนบล็อกนี้ ซึ่งบ่งบอกถึงความยากในการเปลี่ยนแปลงธุรกรรมใดๆ ในบล็อกนี้ ลำดับบอกเราว่ามีกี่บล็อกที่มาก่อนหน้าบล็อกนี้ เราเห็นเวอร์ชันของบล็อก เวลาที่มันถูกสร้าง (ตามข้อมูลของนักขุด) เวลาเฉลี่ยของ 11 บล็อกที่มาก่อนหน้าบล็อกนี้ (การวัดเวลาที่นักขุดปลอมแปลงได้ยากกว่า) และขนาดของบล็อกในการวัดสามแบบต่างกัน (ขนาดดั้งเดิมที่ถูกลบข้อมูลบางส่วนออก, ขนาดเต็ม, และขนาดในหน่วยน้ำหนัก) เรายังเห็นฟิลด์บางอย่างที่ใช้สำหรับความปลอดภัยและหลักฐานการทำงาน (merkle root, nonce, bits, difficulty, และ chainwork) เราจะตรวจสอบสิ่งเหล่านี้โดยละเอียดในส่วนของการขุดในบทที่ 12</p>
<h3>การใช้อินเตอร์เฟสโปรแกรมของ Bitcoin Core</h3>
<p>bitcoin-cli มีประโยชน์มากสำหรับการใช้งาน API ของ Bitcoin Core และการทดสอบฟังก์ชันต่าง ๆ แต่จุดประสงค์หลักของ API คือการเข้าถึงฟังก์ชันด้วยโปรแกรม ในส่วนนี้เราจะสาธิตการเข้าถึง Bitcoin Core จากโปรแกรมอื่น</p>
<p>API ของ Bitcoin Core เป็นอินเตอร์เฟส JSON-RPC โดย JSON เป็นวิธีที่สะดวกมากในการนำเสนอข้อมูลที่ทั้งมนุษย์และโปรแกรมสามารถอ่านได้ง่าย RPC ย่อมาจาก remote procedure call ซึ่งหมายความว่าเรากำลังเรียกใช้กระบวนการ (ฟังก์ชัน) ที่อยู่ห่างไกล (บนโหนด Bitcoin Core) ผ่านโปรโตคอลเครือข่าย ในกรณีนี้ โปรโตคอลเครือข่ายคือ HTTP</p>
<p>เมื่อเราใช้คำสั่ง bitcoin-cli เพื่อขอความช่วยเหลือเกี่ยวกับคำสั่ง มันแสดงตัวอย่างการใช้ curl ซึ่งเป็นไคลเอนต์ HTTP ทางคอมมานด์ไลน์ที่ยืดหยุ่น เพื่อสร้างคำเรียก JSON-RPC เหล่านี้:</p>
<pre><code>$ curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest",
  "method": "getblockchaininfo",
  "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/
</code></pre>
<p>คำสั่งนี้แสดงว่า curl ส่งคำขอ HTTP ไปยัง localhost (127.0.0.1) เชื่อมต่อกับพอร์ต RPC เริ่มต้นของ Bitcoin (8332) และส่งคำขอ jsonrpc โดยใช้เมธอดเป็น getblockchaininfo โดยใช้การเข้ารหัสแบบ text/plain</p>
<p>คุณอาจสังเกตว่า curl จะขอให้ส่งข้อมูลประจำตัวไปพร้อมกับคำขอ Bitcoin Core จะสร้างรหัสผ่านแบบสุ่มในแต่ละครั้งที่เริ่มต้นและวางไว้ในไดเรกทอรีข้อมูลภายใต้ชื่อ .cookie โดย bitcoin-cli สามารถอ่านไฟล์รหัสผ่านนี้โดยให้ไดเรกทอรีข้อมูล ในทำนองเดียวกัน คุณสามารถคัดลอกรหัสผ่านและส่งไปยัง curl (หรือตัวครอบ Bitcoin Core RPC ระดับสูงอื่น ๆ ) ตามที่เห็นในการใช้การตรวจสอบสิทธิ์แบบใช้คุกกี้กับ Bitcoin Core</p>
<p>ตัวอย่างที่ 3. การใช้การตรวจสอบสิทธิ์แบบใช้คุกกี้กับ Bitcoin Core</p>
<pre><code>$ cat .bitcoin/.cookie
  __cookie__:17c9b71cef21b893e1a019f4bc071950c7942f49796ed061b274031b17b19cd0
$ curl
  --user __cookie__:17c9b71cef21b893e1a019f4bc071950c7942f49796ed061b274031b17b19cd0
  --data-binary '{"jsonrpc": "1.0", "id":"curltest",
  "method": "getblockchaininfo",
  "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/
{"result":{"chain":"main","blocks":799278,"headers":799278,
"bestblockhash":"000000000000000000018387c50988ec705a95d6f765b206b6629971e6978879",
"difficulty":53911173001054.59,"time":1689703111,"mediantime":1689701260,
"verificationprogress":0.9999979206082515,"initialblockdownload":false,
"chainwork":"00000000000000000000000000000000000000004f3e111bf32bcb47f9dfad5b",
"size_on_disk":563894577967,"pruned":false,"warnings":""},"error":null,
"id":"curltest"}
</code></pre>
<p>นอกจากนี้คุณยังสามารถตั้งรหัสผ่านด้วยตัวเองใน ./share/rpcauth/rpcauth.py ภายในไดเรกทอรีของ Bitcoin Core</p>
<p>หากคุณกำลังใช้การเรียก JSON-RPC ในโปรแกรมของคุณเอง คุณสามารถใช้ไลบรารี HTTP ทั่วไปเพื่อสร้างการเรียกได้ คล้ายกับที่แสดงในตัวอย่าง curl ก่อนหน้านี้</p>
<p>อย่างไรก็ตาม มีไลบรารีในภาษาโปรแกรมยอดนิยมส่วนใหญ่ที่ "wrap" API ของ Bitcoin Core ในลักษณะที่ทำให้การใช้งานง่ายขึ้นมาก เราจะใช้ไลบรารี python-bitcoinlib เพื่อทำให้การเข้าถึง API นั้นง่ายขึ้น โดยไลบรารีนี้ไม่ได้เป็นส่วนหนึ่งของโครงการ Bitcoin Core และจำเป็นต้องติดตั้งด้วยวิธีปกติที่คุณติดตั้งไลบรารี Python โปรดจำไว้ว่า การใช้งานนี้ต้องมีอินสแตนซ์ Bitcoin Core ที่กำลังทำงานอยู่ ซึ่งจะถูกใช้เพื่อทำการเรียก JSON-RPC</p>
<p>ตัวอย่างสคริปต์ Python ใน " การทำงาน getblockchaininfo ผ่าน API JSON-RPC ของ Bitcoin Core" ซึ่งทำการเรียก getblockchaininfo อย่างง่ายและพิมพ์พารามิเตอร์ block จากข้อมูลที่ส่งคืนโดย Bitcoin Core</p>
<p>ตัวอย่างที่ 4. การทำงาน getblockchaininfo ผ่าน API JSON-RPC ของ Bitcoin Core</p>
<pre><code>from bitcoin.rpc import RawProxy
# Create a connection to local Bitcoin Core node
p = RawProxy()
# Run the getblockchaininfo command, store the resulting data in info
info = p.getblockchaininfo()
# Retrieve the 'blocks' element from the info
print(info['blocks'])
--ผลลัพธ์ของคำสั่ง
$ python rpc_example.py
773973
</code></pre>
<p>มันบอกเราว่าโหนด Bitcoin Core ในเครื่องของเรามีกี่บล็อกในบล็อกเชนของมัน ซึ่งไม่ใช่ผลลัพธ์ที่น่าทึ่ง แต่มันแสดงการใช้งานพื้นฐานของไลบรารีในฐานะอินเตอร์เฟสที่ถูกทำให้ง่ายขึ้นสำหรับ API JSON-RPC ของ Bitcoin Core</p>
<p>ต่อไป เราจะใช้คำสั่ง getrawtransaction และ decodetransaction เพื่อดึงข้อมูลรายละเอียดของการชำระเงินจาก Alice ไปยัง Bob ในส่วนของการดึงข้อมูลธุรกรรมและการวนลูปเอาต์พุตของธุรกรรม เราจะดึงธุรกรรมของ Alice และแสดงรายการเอาต์พุตของธุรกรรม สำหรับแต่ละเอาต์พุต เราจะแสดงที่อยู่ผู้รับและมูลค่า โดยธุรกรรมของ Alice มีเอาต์พุตหนึ่งรายการที่จ่ายให้ Bob และอีกหนึ่งรายการเป็นเงินทอนกลับไปยัง Alice</p>
<p>ตัวอย่างที่ 5 การดึงข้อมูลธุรกรรมและการวนลูปเอาต์พุตของธุรกรรม</p>
<pre><code>from bitcoin.rpc import RawProxy
p = RawProxy()
# Alice's transaction ID
txid = "466200308696215bbc949d5141a49a4138ecdfdfaa2a8029c1f9bcecd1f96177"
# First, retrieve the raw transaction in hex
raw_tx = p.getrawtransaction(txid)
# Decode the transaction hex into a JSON object
decoded_tx = p.decoderawtransaction(raw_tx)
# Retrieve each of the outputs from the transaction
for output in decoded_tx['vout']:
    print(output['scriptPubKey']['address'], output['value'])
--ผลลัพธ์ของคำสั่ง
$ python rpc_transaction.py
bc1p8dqa4wjvnt890qmfws83te0v3qxzsfu7ul63kp7u56w8qc0qwp5qv995qn 0.00020000
bc1qwafvze0200nh9vkq4jmlf4sy0tn0ga5w0zpkpg 0.00075000
</code></pre>
<p>ตัวอย่างทั้งสองข้างต้นค่อนข้างง่าย คุณไม่จำเป็นต้องใช้โปรแกรมในการรันพวกมัน คุณสามารถใช้ตัวช่วย bitcoin-cli ได้ง่าย ๆ แต่อย่างไรก็ตาม ตัวอย่างถัดไปต้องใช้การเรียก RPC หลายร้อยครั้งและแสดงให้เห็นถึงการใช้อินเทอร์เฟซเชิงโปรแกรมได้ชัดเจนยิ่งขึ้น</p>
<p>ในส่วนของการดึงข้อมูลบล็อกและการรวมเอาต์พุตของทุกธุรกรรม เราจะเริ่มต้นด้วยการดึงข้อมูลบล็อก จากนั้นดึงข้อมูลธุรกรรมแต่ละรายการภายในบล็อกโดยอ้างอิงถึง ID ของแต่ละธุรกรรม ต่อมา เราจะวนลูปผ่านเอาต์พุตของแต่ละธุรกรรมและรวมมูลค่าทั้งหมด</p>
<p>ตัวอย่างที่ 6 การดึงข้อมูลบล็อกและการรวมเอาต์พุตของทุกธุรกรรม</p>
<pre><code>from bitcoin.rpc import RawProxy
p = RawProxy()
# The block height where Alice's transaction was recorded
blockheight = 775072
# Get the block hash of the block at the given height
blockhash = p.getblockhash(blockheight)
# Retrieve the block by its hash
block = p.getblock(blockhash)
# Element tx contains the list of all transaction IDs in the block
transactions = block['tx']
block_value = 0
# Iterate through each transaction ID in the block
for txid in transactions:
    tx_value = 0
    # Retrieve the raw transaction by ID
    raw_tx = p.getrawtransaction(txid)
    # Decode the transaction
    decoded_tx = p.decoderawtransaction(raw_tx)
    # Iterate through each output in the transaction
    for output in decoded_tx['vout']:
        # Add up the value of each output
        tx_value = tx_value + output['value']
    # Add the value of this transaction to the total
    block_value = block_value + tx_value
print("Total value in block: ", block_value)
--ผลลัพธ์ของคำสั่ง
$ python rpc_block.py
Total value in block:  10322.07722534
</code></pre>
<p>โค้ดตัวอย่างของเราคำนวณว่ามูลค่ารวมที่ถูกทำธุรกรรมในบล็อกนี้คือ 10,322.07722534 BTC (รวมถึงรางวัล 25 BTC และค่าธรรมเนียม 0.0909 BTC) ลองเปรียบเทียบกับจำนวนที่รายงานโดยเว็บไซต์สำรวจบล็อก (block explorer) โดยการค้นหาแฮชของบล็อกหรือเลขลำดับของบล็อก เครื่องมือสำรวจบล็อกบางตัวรายงานมูลค่ารวมโดยไม่รวมรางวัลและไม่รวมค่าธรรมเนียม ลองดูว่าคุณสามารถสังเกตเห็นความแตกต่างได้หรือไม่</p>
<h3>ไคลเอนต์ทางเลือก, ไลบรารี, และชุดเครื่องมือ</h3>
<p>C/C++<br>Bitcoin Core:การใช้งานอ้างอิงของ Bitcoin<br>JavaScript<br>bcoin: การใช้งานโหนดแบบเต็มรูปแบบที่มีความยืดหยุ่นและขยายได้พร้อม API<br>Bitcore: โหนดเต็มรูปแบบ, API, และไลบรารีโดย Bitpay<br>BitcoinJS: ไลบรารี Bitcoin ที่เขียนด้วย JavaScript ล้วนๆ สำหรับ node.js และเบราว์เซอร์<br>Java<br>bitcoinj: ไลบรารีไคลเอนต์โหนดเต็มรูปแบบที่เขียนด้วย Java<br>Python<br>python-bitcoinlib: ไลบรารี Bitcoin, ไลบรารีฉันทามติ, และโหนดที่เขียนด้วย Python โดย Peter Todd<br>pycoin: ไลบรารี Bitcoin ที่เขียนด้วย Python โดย Richard Kiss<br>Go<br>btcd: ไคลเอนต์ Bitcoin โหนดเต็มรูปแบบที่เขียนด้วยภาษา Go<br>Rust<br>rust-bitcoin: ไลบรารี Bitcoin ที่เขียนด้วย Rust สำหรับการจัดรูปแบบข้อมูล, การแยกวิเคราะห์, และการเรียกใช้ API<br>Scala<br>bitcoin-s: การใช้งาน Bitcoin ที่เขียนด้วย Scala<br>C#<br>NBitcoin: ไลบรารี Bitcoin ที่ครอบคลุมสำหรับเฟรมเวิร์ก .NET</p>
<p>ยังมีไลบรารีอีกมากมายในภาษาโปรแกรมมิ่งอื่น ๆ อีกหลากหลาย และมีการสร้างขึ้นใหม่อยู่ตลอดเวลา</p>
<p>หากคุณทำตามคำแนะนำในบทนี้ ตอนนี้คุณมี Bitcoin Core ที่ทำงานอยู่และได้เริ่มสำรวจเครือข่ายและบล็อกเชนโดยใช้โหนดของคุณเอง จากนี้ไปคุณสามารถใช้ซอฟต์แวร์ที่คุณควบคุมได้โดยอิสระ—บนคอมพิวเตอร์ที่คุณควบคุม—เพื่อตรวจสอบว่า bitcoin ใด ๆ ที่คุณได้รับปฏิบัติตามกฎทุกข้อในระบบ Bitcoin โดยไม่ต้องไว้วางใจองค์กรภายนอกใด ๆ ในบทต่อไป เราจะเรียนรู้เพิ่มเติมเกี่ยวกับกฎของระบบและวิธีที่โหนดและกระเป๋าเงินของคุณใช้กฎเหล่านั้นเพื่อรักษาความปลอดภัยของเงินของคุณ ปกป้องความเป็นส่วนตัวของคุณ และทำให้การใช้จ่ายและการรับเงินสะดวกสบาย</p>
<p>ฮึ่ ๆ หลาม ๆ มาอีกแล้ว จริง ๆ เนื้อหาของบทที่สามมันจบลงตรงนี้แหละ แต่ว่าถ้าสมมุตืว่าใครลองไปทำตามจริง ๆ แล้วอยากรู้ว่าเราสามารถทำอะไรจาก node ของเราได้อีกบ้าง เลยมีกิจกรรมขำ ๆ มาให้ทำครับ โดยความยากจะมีทั้งหมด 3 ระดับ ดังนี้</p>
<ul>
<li>ง่าย (สามารถหาคำตอบได้ด้วย bitcoin-cli command เดียว)</li>
</ul>
<ol>
<li>แฮชของบล๊อก 774698 คืออะไร?</li>
<li>signature ของข้อความจาก address นี้ถูกต้องหรือไม่</li>
</ol>
<pre><code>address: 1E9YwDtYf9R29ekNAfbV7MvB4LNv7v3fGa
message: 1E9YwDtYf9R29ekNAfbV7MvB4LNv7v3fGa
signature:HCsBcgB+Wcm8kOGMH8IpNeg0H4gjCrlqwDf/GlSXphZGBYxm0QkKEPhh9DTJRp2IDNUhVr0FhP9qCqo2W0recNM=
</code></pre>
<ul>
<li>ทำได้แหละ (สามารถหาคำตอบได้ด้วย bitcoin-cli command เดียว หรืออาจจะมากกว่าหนึ่ง)</li>
</ul>
<ol start="3">
<li>มี output ใหม่กี่อันที่เกิดในบล๊อก 774698 ?</li>
<li>ใช้ wallet descriptors หา taproot address ที่ 100 จาก extended public key ที่กำหนดให้ xpub6DLd5RvY42Q5HAmBhHPUbDGdeS9VvsYNauiuN8r6NzbiXSSNWpNVrDGTUScJ9fS2orMtuB3VdxMdUH83fPtwbrizfJg9LwWnGqtL7RTs5h1</li>
<li>สร้าง multisig address แบบ P2SH แบบ 1-of-4 จาก publickey ในอินพุตทั้งสี่ของธุรกรรมนี้:37d966a263350fe747f1c606b159987545844a493dd38d84b070027a895c4517</li>
</ol>
<ul>
<li>ต้องคิดเชิงตรรกะได้เล็กน้อย (สามารถหาคำตอบได้ด้วย bitcoin-cli command และพวก if-else/loop)</li>
</ul>
<ol start="6">
<li>tx ใดในบล็อก 257,343 ที่ใช้เอาท์พุตของ coinbase ของบล็อก 256,128?</li>
<li>มีเอาต์พุตเดียวที่ยังไม่ได้ใช้งานจากบล็อก 123,321 เอาต์พุตดังกล่าวถูกส่งไปที่ address ไหน</li>
<li>public key ใดที่ลงนามอินพุต 0 ใน tx นี้:e5969add849689854ac7f28e45628b89f7454b83e9699e551ce14b6f90c86163</li>
</ol>
<p>ใครทำได้พร้อมแชร์วิธีการใต้โพสต์นี้เดี๋ยวจะมีไดโนเสาร์ส่งแซตเป็นกำลังใจให้เล็กน้อยครับ</p>
]]></itunes:summary>
      <itunes:image href="https://image.nostr.build/29da6e18e9b5a07f5cd1b52ef33ccaad9e0d438a203316facaed75bc6b83de6c.jpg"/>
      </item>
      
      <item>
      <title><![CDATA[สรุป Mastering Bitcoin: Programming the Open Blockchain บทที่ 2
]]></title>
      <description><![CDATA[อ่านอังกฤษไม่ไหวเลยมาทางนี้แต่อ่านอันนี้ก็ปวดหัวโอ้ยยย กลับไปอ่านต้นฉบับดีกว่าาา!!!!]]></description>
             <itunes:subtitle><![CDATA[อ่านอังกฤษไม่ไหวเลยมาทางนี้แต่อ่านอันนี้ก็ปวดหัวโอ้ยยย กลับไปอ่านต้นฉบับดีกว่าาา!!!!]]></itunes:subtitle>
      <pubDate>Sat, 21 Dec 2024 13:38:09 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/u8oa1nsgwwiruk-qmreu1/</link>
      <comments>https://learnbn.npub.pro/post/u8oa1nsgwwiruk-qmreu1/</comments>
      <guid isPermaLink="false">naddr1qq242wr0gyckuu682at5jun4dvk4zmtjv46nzq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65w3mgjxl</guid>
      <category>ลองฟอร์มของไดโน</category>
      
        <media:content url="https://image.nostr.build/5648ee8b923cd74f0d7f797a52aa66cff315a0e887e7683a2f9fbd72e6a81187.jpg" medium="image"/>
        <enclosure 
          url="https://image.nostr.build/5648ee8b923cd74f0d7f797a52aa66cff315a0e887e7683a2f9fbd72e6a81187.jpg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qq242wr0gyckuu682at5jun4dvk4zmtjv46nzq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65w3mgjxl</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<h2>บทที่ 2: ภาพรวมการทำงานของบิตคอยน์</h2>
<h1>บิตคอยน์ทำงานอย่างไร</h1>
<p>ระบบอย่างบิตคอยน์นั้นแตกต่างกับระบบธนาคารและระบบการชำระเงินแบบดั้งเดิมอย่างสิ้นเชิง เพราะมันสามารถทำงานได้โดยไม่จำเป็นต้องไว้วางใจบุคคลที่สาม แทนที่จะมีหน่วยงานกลางที่เชื่อถือได้ บิตคอยน์ได้อณุญาตให้ผู้ใช้แต่ละคนใช้ซอฟต์แวร์บนคอมพิวเตอร์ของตนเองเพื่อตรวจสอบการทำงานที่ถูกต้องของทุกส่วนในระบบ ซึ่งในบทนี้เอง เราจะทำการสำรวจบิตคอยน์ภาพรวมโดยติดตามธุรกรรมหนึ่งรายการผ่านระบบของบิตคอยน์ ดูว่าธุรกรรมนั้นถูกบันทึกลงในบล็อกเชนอย่างไร และการบันทึกธุรกรรมแบบกระจายศูนย์นั้นทำได้อย่างไร ส่วนในบทถัดไปจะลงลึกถึงเทคโนโลยีที่อยู่เบื้องหลังธุรกรรม เครือข่าย และการขุด</p>
<h2>ภาพรวมของบิตคอยน์</h2>
<p>ระบบของบิตคอยน์นั้นประกอบไปด้วย เหล่าผู้ใช้งาน wallet ต่าง ๆ , ธุรกรรมที่กระจายไปทั่วเครือข่าย และเหล่านักขุดที่จะคอยแข่งขันกันเพื่อสร้างบล๊อกใหม่ โดยที่มีบล๊อกเชนเป็นเหมือนสมุดบันทึกธุรกรรมที่รวมธุรกรรมทั้งหมดไว้ ตัวอย่างที่จะได้เห็นต่อไปนี้เป็นธุรกรรมที่เกิดขึ้นจริงบนเครือข่ายของบิตคอยน์ โดยจำลองการโต้ตอบระหว่างผู้ใช้หลายคนผ่านการส่งเงินจาก wallet หนึ่งไปยังอีก wallet และในขณะนั้นเราจะติดตามธุรกรรมผ่านเครือข่ายบิตคอยน์ ไปจนถึงบล็อกเชน เราจะใช้เว็บไซต์สำรวจบล็อกเชน (blockchain explorer) เพื่อดูภาพรวมในแต่ละขั้นตอน โดยมีเว็บไซต์สำรวจบล็อกเชนที่นิยม ดังนี้</p>
<ul>
<li>Blockstream Explorer</li>
<li>Mempool.Space</li>
<li>BlockCypher Explorer</li>
</ul>
<p>เว็บไซต์เหล่านี้มีฟังก์ชันการค้นหาที่สามารถใช้ค้นหา Bitcoin address, Transaction Hash, หมายเลขบล็อก หรือ Block hash และเรียกดูข้อมูลที่เกี่ยวข้องจากเครือข่ายบิตคอยน์ได้ สำหรับแต่ละตัวอย่างธุรกรรมหรือบล็อก เราจะให้ URL เพื่อให้คุณสามารถค้นหาและศึกษาข้อมูลเพิ่มเติมได้ด้วยตัวเอง</p>
<h3>คำเตือนเกี่ยวกับความเป็นส่วนตัวของการใช้ Block Explorer</h3>
<p>การค้นหาข้อมูลใน block explorer อาจเปิดเผยให้ผู้ให้บริการทราบว่าคุณสนใจข้อมูลนั้น ซึ่งอาจเชื่อมโยงกับที่อยู่ IP ของคุณ รายละเอียดของเบราว์เซอร์ การค้นหาที่ผ่านมา หรือข้อมูลที่สามารถระบุตัวตนได้อื่น ๆ หากคุณค้นหาธุรกรรมจากหนังสือเล่มนี้ ผู้ให้บริการอาจคาดเดาได้ว่าคุณกำลังศึกษาเกี่ยวกับบิตคอยน์ ซึ่งไม่น่าจะมีปัญหาอะไร แต่หากคุณค้นหาธุรกรรมของตนเอง ผู้ให้บริการอาจสามารถคาดเดาได้ว่าคุณได้รับ ใช้จ่าย และมีบิตคอยน์อยู่เท่าใดในปัจจุบัน</p>
<h2>การซื้อของจากร้านค้าออนไลน์</h2>
<p>อลิซเป็นผู้ใช้งานใหม่ ที่พึ่งได้รับบิตคอยน์เป็นครั้งแรกจากคำแนะนำของโจเมื่อบทที่แล้ว โดยเธอได้ซื้อบิตคอยน์จากโจเก็บไว้ และตั้งแต่นั้นมาอลิซก็ซื้อบิตคอยน์เพิ่มเรื่อย ๆ และตอนนี้อลิซต้องการทำธุรกรรมด้วยบิตคอยน์ครั้งแรกของเธอ โดยการใช้จ่ายมันเพื่อแลกกับสิทธิ์เข้าถึงพอดแคสต์ตอนพิเศษจากร้านค้าออนไลน์ของบ๊อบ  ร้านค้าออนไลน์ของบ๊อบเองก็เพิ่งมีการเพิ่มบิตคอยน์เป็นตัวเลือกในการทำธุรกรรม ราคาสินค้าในร้านของบ๊อบแสดงเป็นสกุลเงินท้องถิ่น (ดอลลาร์สหรัฐ) แต่ในหน้าชำระเงิน ลูกค้าสามารถเลือกชำระเงินเป็นดอลลาร์หรือบิตคอยน์ก็ได้</p>
<p>อลิซเลือกตอนพอดแคสต์ที่เธอต้องการซื้อและดำเนินการไปยังหน้าชำระเงิน ในหน้าชำระเงิน อลิซพบตัวเลือกในการชำระเงินด้วยบิตคอยน์ นอกเหนือจากตัวเลือกปกติ แต่ในตะกร้าชำระเงินจะแสดงราคาทั้งในรูปแบบดอลลาร์สหรัฐและบิตคอยน์ตามอัตราแลกเปลี่ยนในขณะนั้น หลังจากกดจ่ายด้วยบิตคอยน์ระบบของบ๊อบได้ทำการสร้างใบเรียกเก็บเงิน (invoice) ในรูปแบบของ QR-code ตามภาพด้านล่าง</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734787367004-YAKIHONNES3.png" alt="image"></p>
<p>ต่างจาก QR code ทั่วไปที่มีเพียง Bitcoin address ปลายทางเท่านั้น ใบแจ้งหนี้นี้เป็น QR code แบบ URI ที่ประกอบด้วย Bitcoin address จำนวนเงินชำระ และคำอธิบาย (memo) ซึ่งช่วยให้ Bitcoin wallet แอปพลิเคชันเติมข้อมูลที่ใช้ในการชำระเงินล่วงหน้าได้ และยังแสดงคำอธิบายที่อ่านเข้าใจง่ายให้กับผู้ใช้อีกด้วย คุณสามารถสแกน QR code นี้ด้วย Bitcoin wallet เพื่อดูสิ่งที่อลิซจะเห็น</p>
<h3>QR Code ของใบแจ้งหนี้นี้เข้ารหัส URI ดังต่อไปนี้ ซึ่งถูกกำหนดไว้ใน BIP21:</h3>
<p><code>bitcoin:bc1qk2g6u8p4qm2s2lh3gts5cpt2mrv5skcuu7u3e4?amount=0.01577764&amp;</code><br><code>label=Bob%27s%20Store&amp;</code><br><code>message=Purchase%20at%20Bob%27s%20Store</code></p>
<p>โดยส่วนประกอบของ URI สามารถจำแนกได้ ดังนี้</p>
<ul>
<li>A Bitcoin address: "bc1qk2g6u8p4qm2s2lh3gts5cpt2mrv5skcuu7u3e4"</li>
<li>The payment amount (จำนวนบิตคอยน์) : "0.01577764"</li>
<li>A label for the recipient address (label): "Bob's Store"</li>
<li>A description for the payment (memo): "Purchase at Bob's Store"</li>
</ul>
<p>อลิซใช้สมาร์ทโฟนของเธอสแกนบาร์โค้ดที่แสดงอยู่ หน้าจอสมาร์ทโฟนของเธอจะแสดงการชำระเงินในจำนวนที่ถูกต้องสำหรับร้านของบ๊อบ และเธอกด “Send” เพื่อยืนยันการชำระเงิน ภายในไม่กี่วินาที (เวลาประมาณเดียวกับการอนุมัติบัตรเครดิต) บ๊อบก็จะเห็นธุรกรรมดังกล่าวปรากฏบนเครื่องรับชำระเงินของเขา</p>
<blockquote>
<p>เครือข่ายบิตคอยน์สามารถทำธุรกรรมในมูลค่าเศษส่วนได้ เช่น มิลลิบิทคอยน์ (1/1,000 ของบิทคอยน์) ไปจนถึง 1/100,000,000 ของบิทคอยน์ ซึ่งเรียกว่า "ซาโตชิ" ในหนังสือเล่มนี้ใช้กฎการพหูพจน์เดียวกันกับดอลลาร์หรือสกุลเงินแบบดั้งเดิมเมื่อพูดถึงจำนวนที่มากกว่าหนึ่งบิทคอยน์ เช่น "10 บิตคอยน์" หรือ "0.001 บิตคอยน์" กฎเดียวกันนี้ยังนำไปใช้กับหน่วยบัญชีบิทคอยน์อื่น ๆ เช่น มิลลิบิทคอยน์และซาโตชิอีกด้วย</p>
</blockquote>
<h2>ธุรกรรมในระบบบิตคอยน์</h2>
<p>ธุรกรรมในระบบบิตคอยน์คือการแจ้งเครือข่ายว่าเจ้าของบิทคอยน์ได้อนุมัติการโอนมูลค่าไปยังเจ้าของใหม่แล้ว และ เจ้าของใหม่สามารถใช้บิทคอยน์เหล่านั้นได้ โดยสร้างธุรกรรมใหม่เพื่อรออนุมัติการโอนไปยังเจ้าของคนอื่นต่อ ๆ ไป ทำให้เกิดการส่งต่อความเป็นเจ้าของอย่างต่อเนื่อง</p>
<h3>ธุรกรรมขาเข้าและขาออกของบิตคอยน์</h3>
<p>ธุรกรรมเปรียบเสมือนบันทึกในสมุดบัญชีแบบสองทาง โดยธุรกรรมแต่ละรายการจะมีอินพุต (inputs) หนึ่งรายการหรือมากกว่านั้นที่ใช้จ่ายเงิน และมีเอาต์พุต (outputs) หนึ่งรายการหรือมากกว่าที่รับเงิน มูลค่าของอินพุตและเอาต์พุตไม่จำเป็นต้องเท่ากันเสมอไป เอาต์พุตมักจะมีมูลค่าน้อยกว่าอินพุตเล็กน้อย ซึ่งส่วนต่างนี้คือ "ค่าธรรมเนียมธุรกรรม" ที่นักขุดจะได้รับเมื่อรวมธุรกรรมในบล็อกเชน</p>
<p>ธุรกรรมยังมีหลักฐานการเป็นเจ้าของสำหรับจำนวนบิตคอยน์ (อินพุต) ที่ถูกใช้ในรูปของลายเซ็นดิจิทัลจากเจ้าของเดิม ซึ่งสามารถตรวจสอบความถูกต้องได้ ในระบบบิตคอยน์การใช้จ่ายบิตคอยน์คือการลงนามในธุรกรรมเพื่อโอนมูลค่าจากธุรกรรมก่อนหน้าไปยังเจ้าของใหม่ที่ระบุผ่าน Bitcoin adress</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734787627692-YAKIHONNES3.png" alt="image"></p>
<h3>ห่วงโซ่ของธุรกรรม</h3>
<p>การชำระเงินของอลิซไปยังร้านของบ็อบนั้นเป็นใช้เอาต์พุตจากธุรกรรมก่อนหน้าเป็นอินพุตในธุรกรรมครั้งนี้ (ในบทก่อนหน้า อลิซได้รับบิทคอยน์จากโจเพื่อนของเธอ ) เราเรียกธุรกรรมนี้ว่า "ธุรกรรมที่ 1 (Tx1)" ซึ่งแสดงถึงห่วงโซ่ของธุรกรรมที่เอาต์พุตของธุรกรรมหนึ่งถูกใช้เป็นอินพุตในธุรกรรมถัดไป</p>
<h4>การอ้างอิงอินพุตจากเอาต์พุตก่อนหน้า</h4>
<p>Tx1 โอน 0.001 บิทคอยน์ (100,000 ซาโตชิ) ไปยังเอาต์พุตที่ล็อกด้วยกุญแจของอลิซ และในธุรกรรมใหม่ของอลิซ (Tx2) ที่ส่งให้ร้านของบ็อบ เธออ้างถึงเอาต์พุตก่อนหน้าเป็นอินพุต อย่างที่เห็นในภาพประกอบ การอ้างอิงด้วยลูกศรและระบุอินพุตว่า "Tx1:0" ในธุรกรรมจริง การอ้างอิงจะใช้รหัสประจำธุรกรรม (txid) เป็นตัวระบุขนาด 32 ไบต์ที่แสดงถึงธุรกรรมที่อลิซได้รับเงินจากโจ ส่วน ":0" หมายถึงตำแหน่งของเอาต์พุตที่อลิซได้รับเงิน ซึ่งในกรณีนี้คือตำแหน่งแรก (ตำแหน่ง 0)</p>
<h4>การคำนวณมูลค่าอินพุต</h4>
<p>เนื่องจากธุรกรรมของบิตคอยน์นั้นไม่ได้ระบุค่าของอินพุตอย่างชัดเจน ตัวซอฟต์แวร์เลยจะต้องใช้การอ้างอิงของอินพุตเพื่อค้นหาเอาต์พุตของธุรกรรมก่อนหน้าที่ถูกใช้ไป</p>
<h4>เอาต์พุตใน Tx2 ของอลิซ</h4>
<p>Tx2 ของอลิซมีเอาต์พุตใหม่สองรายการ รายการหนึ่งจ่าย 75,000 ซาโตชิสำหรับพอดแคสต์ และอีกรายการจ่าย 20,000 ซาโตชิคืนให้อลิซเป็นเงินทอน<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734787700413-YAKIHONNES3.png" alt="image"></p>
<blockquote>
<h4>เกร็ดสาระเล็ก ๆ น้อย ๆ</h4>
<ul>
<li>ธุรกรรมของบิตคอยน์นั้นอยู่ในรูปแบบซีเรียลไลซ์ (serialized) เป็นรูปแบบข้อมูลที่ซอฟต์แวร์ใช้สำหรับการส่งธุรกรรม โดยจะเข้ารหัสมูลค่าที่ต้องการโอนด้วยตัวเลขจำนวนเต็มซึ่งเป็นหน่วยมูลค่าที่เล็กที่สุดในระบบ on-chain</li>
<li>ที่มาของชื่อ "ซาโตชิ" :เมื่อบิตคอยน์ถูกสร้างขึ้นในครั้งแรก หน่วยมูลค่านี้ยังไม่มีชื่อเรียก นักพัฒนาบางคนจึงเรียกมันว่า "หน่วยฐาน" (base unit) แต่ต่อมาผู้ใช้งานหลาย ๆ คนเริ่มเรียกหน่วยนี้ว่า "ซาโตชิ" (satoshi หรือ sat) เพื่อเป็นเกียรติแก่ผู้สร้างบิตคอยน์</li>
</ul>
</blockquote>
<h4>การทอนเงิน</h4>
<p>นอกเหนือจากการสร้างเอาต์พุตเพื่อจ่ายให้กับผู้รับบิตคอยน์แล้ว ธุรกรรมจำนวนมากยังมีเอาต์พุตที่จ่ายเงินคืนให้กับผู้จ่าย ซึ่งเรียกว่า เอาต์พุตทอนเงิน (change output) เนื่องจากอินพุตของธุรกรรม (คล้ายกับธนบัตร) ไม่สามารถแบ่งใช้บางส่วนได้ เช่น ถ้าคุณซื้อของราคา 5 ดอลลาร์และจ่ายด้วยธนบัตร 20 ดอลลาร์ คุณคาดหวังว่าจะได้เงินทอน 15 ดอลลาร์ ในทำนองเดียวกัน ในธุรกรรม Bitcoin หากคุณซื้อสินค้าราคา 5 บิตคอยน์แต่มีอินพุตมูลค่า 20 บิตคอยน์ คุณจะสร้างเอาต์พุต 5 บิตคอยน์ไปยังเจ้าของร้าน และอีกเอาต์พุต 15 บิตคอยน์คืนให้ตัวคุณเองเป็นเงินทอน (ไม่นับรวมค่าธรรมเนียมธุรกรรม) </p>
<blockquote>
<ul>
<li>หากมองผ่านมุมของโปรโตคอลบิตคอยน์นั้นไม่ได้มีความแตกต่างใด ๆ ระหว่างเอาต์พุตเงินทอนกับเอาต์พุตการจ่ายเงินปกติ</li>
<li>โดยทั่วไปแล้วเอาต์พุตเงินทอนจะเป็นการโอนไปจ่ายให้กับ Bitcoin Address อันใหม่ในกระเป๋าตัวเองดังรูปที่แสดงข้างล่าง</li>
</ul>
</blockquote>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734787818103-YAKIHONNES3.png" alt="image"></p>
<h3>การสร้างธุรกรรม</h3>
<p>แอปพิเคชั่นกระเป๋าเงินของอลิซจะทำการสร้างอินพุตและสร้างเอาต์พุตตามที่ Alice ต้องการ โดยที่เธอเพียงแค่กรอกปลายทาง จำนวนเงิน และค่าธรรมเนียมธุรกรรมกระเป๋าเงินจะทำงานที่เหลือให้โดยอัตโนมัติ นอกจากนี้ กระเป๋าเงินยังสามารถสร้างธุรกรรมแบบออฟไลน์ได้ คล้ายกับการเขียนเช็คที่บ้านแล้วค่อยนำไปฝากธนาคารในภายหลังอีกด้วย</p>
<h4>การเลือกอินพุตที่เหมาะสม</h4>
<p>กระเป๋าเงินจะเลือกอินพุตที่มีมูลค่าเพียงพอสำหรับการชำระเงินไปยังบ๊อบโดยตรวจสอบเอาต์พุตที่ยังไม่ได้ใช้ (UTXOs) ซึ่งหากมูลค่าไม่เพียงพอ กระเป๋าเงินก็จะทำการรวม UTXOs หลาย ๆ รายการเข้าด้วยกัน เพื่อให้ได้ยอดที่ต้องการ และหากอินพุตมีมูลค่าสูงกว่าค่าที่ต้องจ่าย กระเป๋าเงินจะสร้างเอาต์พุตสำหรับทอนเงินกลับมาให้อลิซ</p>
<h4>การสร้างเอาต์พุต</h4>
<p>เอาต์พุตประกอบด้วยสคริปต์ที่กำหนดให้ผู้ที่มีคีย์ของบ๊อบเท่านั้นสามารถลงนามเพื่อที่จะใช้เงินได้ นอกจากนี้ยังมีเอาต์พุตสำหรับทอนเงินกลับมาให้อลิซ ซึ่งทำให้เธอสามารถใช้เงินทอนนั้นในการทำธุรกรรมถัดไป และค่าธรรมเนียมธุรกรรมจะถูกคำนวณจากส่วนต่างระหว่างอินพุตและเอาต์พุต และนั่นเองที่จะเป็นรางวัลสำหรับนักขุดที่บันทึกธุรกรรมลงบล็อกเชนของบิตคอยน์</p>
<h2>การใส่ธุรกรรมลงในบล๊อกเชน</h2>
<p>ธุรกรรมที่สร้างขึ้นโดย Bitcoin wallet ของอลิซมีข้อมูลทั้งหมดที่จำเป็นสำหรับการสร้างธุรกรรม (การยืนยันว่าอลิซเป็นเจ้าของเงิน และ Bitcoin address ปลายทาง) จากนั้นธุรกรรมนี้จะต้องถูกส่งไปยังเครือข่ายของบิตคอยน์ เพื่อที่จะให้ธุรกรรมนั้นเป็นส่วนนึงในเครือข่ายของบิตคอยน์ และในส่วนถัดไปของหนังสือเล่มนี้ เราจะอธิบายถึงว่าธุรกรรมกลายเป็นส่วนหนึ่งของบล็อกใหม่อย่างไร และกระบวนการขุดบล็อกเป็นอย่างไร รวมถึงการที่บล็อกใหม่ได้รับความไว้วางใจมากขึ้นเมื่อมีการเพิ่มบล็อกใหม่ ๆ เข้ามาเรื่อย ๆ หมายถึงอะไร ?</p>
<h3>การส่งธุรกรรมเข้าไปยังเครือข่าย</h3>
<p>เนื่องจากธุรกรรมมีข้อมูลที่จำเป็นสำหรับการประมวลผลทั้งหมด จึงทำให้การส่งผ่านสามารถทำได้จากที่ไหนหรืออย่างไรก็ได้ อย่างที่ได้กล่าวไปว่าเครือข่ายของบิตคอยน์เป็นเครือข่ายแบบ peer-to-peer โดยที่แต่ละโหนดเชื่อมต่อกับโหนดอื่น ๆ อีกหลายโหนด เพื่อทำหน้าที่กระจายธุรกรรมและบล็อกให้กับผู้เข้าร่วมทั้งหมดในระบบ</p>
<h3>การกระจายธุรกรรม</h3>
<p>โหนดในเครือข่าย peer-to-peer ของบิตคอยน์นั้นเป็นซอฟต์แวร์ที่สามารถตรวจสอบความถูกต้องของธุรกรรมได้  และการเชื่อมต่อระหว่างโหนดสามารถแสดงเป็นเส้นในกราฟ ทำให้โหนดเหล่านี้เรียกว่า “โหนดตรวจสอบเต็มรูปแบบ” (full nodes) กระเป๋าเงินของอลิซสามารถส่งธุรกรรมไปยังโหนดบิตคอยน์ใด ๆ ผ่านการเชื่อมต่อใด ๆ ก็ได้ เช่น สายแลน WiFi หรือ เครือข่ายมือถือ โดยถ้าหากโหนดได้รับธุรกรรมที่ถูกต้องซึ่งยังไม่เคยเห็นมาก่อน มันจะกระจายธุรกรรมนี้ไปยังโหนดอื่น ๆ ที่เชื่อมต่อด้วย ซึ่งเป็นเทคนิคที่เรียกว่า gossiping ซึ่งทำให้ธุรกรรมแพร่กระจายไปทั่วเครือข่ายอย่างรวดเร็วภายในไม่กี่วินาที</p>
<h3>การขุดบิตคอยน์</h3>
<p>ตอนนี้ธุรกรรมของอลิซได้เข้าไปสู่ในเครือข่ายของบิตคอยน์แล้ว แต่มันยังไม่ได้ถูกบรรจุลงในบล๊อกเชนเนื่องจากจะต้องรอให้นักขุดทำการนำธุรกรรมนั้น ๆ เข้าไปในบล๊อกและบล๊อกนั้นจำเป็นต้องผ่านการตรวจสอบโดยโหนดในเครือข่ายของบิตคอยน์เสียก่อน จึงจะถูกบันทึกลงในบล๊อกเชน<br>ในระบบของบิตคอยน์นั้น มีการป้องกันการปลอมแปลงด้วยการคำนวณทางคณิตศาสตร์ ซึ่งเป็นการคำนวณที่จำเป็นต้องใช้พลังงานมหาศาลในการคำนวณ แต่ใช้พลังงานเพียงเล็กน้อยในการตรวจสอบ โดยธุรกรรมทั้งหมดจะถูกจัดเรียงเป็นบล๊อกและแต่ละบล๊อกจะมีบล๊อกเฮดเดอร์ที่จำเป็นต้องสร้างตามเงื่อนไขเฉพาะ โดยกระบวนการขุดบิตคอยน์นั้นมีวัตถุประสงค์อยู่สองอย่าง ดังนี้:</p>
<ul>
<li>สร้างแรงจูงใจให้ขุดเฉพาะธุรกรรมที่ถูกต้องตามกฎ: เนื่องจากวิธีที่เหล่านักขุดจะได้รับผลกำไรที่สูงที่สุดจากการสร้างบล๊อกที่ตรงกับฉันทมติของระบบเท่านั้น (หากไม่ทำตามบล๊อกจะไม่ถูกยอมรับโดยโหนด และนั่นจะเป็นการสิ้นเปลืองพลังงานที่ได้คำนวณมาโดยเปล่าประโยชน์) นั้นจึงเป็นแรงจูงใจหลัก ๆ ให้เหล่านักขุดทำการใส่ธุรกรรมที่ถูกต้องตามกฏเท่านั้นลงในบล๊อกที่ตนสร้าง และสิ่งนี้เองก็ทำให้ผู้ใช้สามารถเลือกที่จะสันนิษฐานโดยอิงตามความไว้วางใจว่าธุรกรรมใด ๆ ในบล็อกนั้น ๆ เป็นธุรกรรมที่ถูกต้อง </li>
<li>สร้างเหรียญใหม่ตามตารางการออกเหรียญที่กำหนดไว้ล่วงหน้า: ในปัจจุบันนั้นจะมีการสร้างบิตคอยน์ใหม่ในแต่ละบล็อก คล้ายคลึงกับธนาคารกลางที่พิมพ์เงินใหม่ โดยจำนวนบิตคอยน์ในแต่ละบล๊อกที่จะถูกผลิตขึ้นมาใหม่นั้นถูกกำหนดมาตั้งแต่วันที่ระบบของบิตคอยน์ได้เริ่มขึ้นและไม่สามารถเปลี่ยนแปลงได้</li>
</ul>
<p>การขุดได้ช่วยให้เกิดความสมดุลระหว่างต้นทุนและผลตอบแทน เนื่องจากการขุดมีการใช้ไฟฟ้าเพื่อแก้ปัญหาการคำนวณ และนักขุดที่ประสบความสำเร็จจะได้รับรางวัลในรูปแบบของบิตคอยน์ใหม่และค่าธรรมเนียมจากการทำธุรกรรม แต่อย่างไรก็ตาม รางวัลจะถูกเก็บรวบรวมก็ต่อเมื่อนักขุดรวมเฉพาะธุรกรรมที่ถูกต้องเท่านั้น โดยกฎของโปรโตคอลบิตคอยน์สำหรับการสร้างฉันทามติ จะกำหนดว่าอะไรถูกต้อง โดยความสมดุลที่ละเอียดอ่อนนี้เองที่คอยสร้างให้ความปลอดภัยแก่บิตคอยน์โดยไม่ต้องมีหน่วยงานกลางมาคอยดูแล</p>
<p>การขุดถูกออกแบบให้เหมือนกับการจับสลากแบบกระจายศูนย์ นักขุดแต่ละคนสามารถสร้าง "สลาก" ของตัวเองได้โดยการสร้างบล็อกตัวอย่างที่ประกอบไปด้วยธุรกรรมใหม่ที่ต้องการขุด พร้อมกับข้อมูลอื่น ๆ และนักขุดจะป้อนบล็อกตัวอย่างนี้เข้าไปในอัลกอริทึมที่ออกแบบมาเป็นพิเศษเพื่อแฮชข้อมูล ทำให้ได้ค่าผลลัพธ์ที่แตกต่างจากข้อมูลเดิมอย่างสิ้นเชิง โดยแฮชฟังก์ชันนี้จะให้ผลลัพธ์เดียวกันเสมอสำหรับข้อมูลชุดเดิม แต่ไม่สามารถคาดเดาผลลัพธ์ได้หากป้อนข้อมูลใหม่ แม้จะแตกต่างเพียงเล็กน้อยจากข้อมูลก่อนหน้า</p>
<p>หากค่าผลลัพธ์ของแฮชตรงกับเงื่อนไขที่กำหนดของโปรโตคอล นักขุดจะชนะการจับสลาก และผู้ใช้งานบิตคอยน์ จะยอมรับบล็อกนี้พร้อมกับธุรกรรมในนั้นว่าเป็นบล็อกที่ถูกต้อง หากไม่ตรงกับเงื่อนไข นักขุดจะปรับข้อมูลในบล็อกเล็กน้อยและลองทำการแฮชใหม่ กระบวนการนี้ต้องทำซ้ำหลายครั้ง โดย ณ ขณะที่เขียนนี้ นักขุดต้องลองสร้างบล็อกตัวอย่างประมาณ 168 พันล้านล้านครั้ง เพื่อหาคำตอบที่ถูกต้อง ซึ่งหมายถึงการรันแฮชฟังก์ชันในจำนวนครั้งมหาศาลมาก ๆ </p>
<p>แต่เมื่อพบคำตอบที่ถูกต้องแล้ว ใครก็ตามสามารถตรวจสอบว่าบล็อกนั้นถูกต้องได้โดยการรันแฮชฟังก์ชันเพียงครั้งเดียว ซึ่งทำให้การสร้างบล็อกที่ถูกต้องต้องใช้พลังงานคำนวณมหาศาล แต่การตรวจสอบทำได้ง่ายมาก กระบวนการตรวจสอบนี้สามารถพิสูจน์ได้อย่างมีหลักการว่ามีการทำงานเกิดขึ้นจริง ดังนั้น ข้อมูลที่ใช้สร้างหลักฐานนี้—ในที่นี้คือบล็อก—เรียกว่า "หลักฐานการทำงาน" หรือ Proof of Work (PoW)</p>
<p>ธุรกรรมจะถูกเพิ่มลงในบล็อกใหม่ โดยให้ความสำคัญกับธุรกรรมที่มีค่าธรรมเนียมสูงสุดก่อนและพิจารณาจากปัจจัยอื่น ๆ อีกเล็กน้อย นักขุดแต่ละคนจะเริ่มกระบวนการสร้างบล็อกตัวอย่างใหม่ทันทีหลังจากได้รับบล็อกก่อนหน้าจากเครือข่าย โดยรู้ว่ามีคนอื่นชนะรางวัลไปแล้วในรอบนั้น พวกเขาจะสร้างบล็อกตัวอย่างใหม่ที่เชื่อมโยงกับบล็อกก่อนหน้า ใส่ธุรกรรมเข้าไป และเริ่มคำนวณ Proof of Work (PoW) สำหรับบล็อกตัวอย่างนี้ นักขุดจะเพิ่มธุรกรรมพิเศษที่จ่ายรางวัลบล็อกและค่าธรรมเนียมธุรกรรมรวมเข้ากับที่อยู่บิตคอยน์ของตนเอง หากพวกเขาพบบล็อกที่ถูกต้องและถูกเพิ่มในบล็อกเชน นักขุดจะได้รับรางวัลนั้น และธุรกรรมรางวัลนี้ก็จะใช้งานได้ นักขุดที่ทำงานร่วมกับพูลจะตั้งค่าให้รางวัลถูกส่งไปยังที่อยู่ของพูล จากนั้นจะแบ่งรางวัลให้สมาชิกตามสัดส่วนการทำงานที่แต่ละคนมีส่วนร่วม</p>
<p>กลับมาที่ธุรกรรมของอลิซ ตอนนี้ธุรกรรมของอลิซได้ถูกเครือข่ายรับไปแล้วและเพิ่มลงในพูลของธุรกรรมที่ยังไม่ได้รับการยืนยันเรียบร้อย จากนั้นเมื่อธุรกรรมนั้นผ่านการตรวจสอบจาก full node แล้ว มันจะถูกรวมไว้ในบล็อกตัวอย่าง และประมาณห้านาทีหลังจากที่อลิซส่งธุรกรรมจากกระเป๋าเงินของเธอ นักขุดคนหนึ่งพบคำตอบสำหรับบล็อกนั้นและประกาศไปยังเครือข่าย หลังจากที่นักขุดคนอื่น ๆ ตรวจสอบความถูกต้องของบล็อกที่ชนะ พวกเขาก็เริ่มกระบวนการสุ่มอีกครั้งเพื่อสร้างบล็อกถัดไป</p>
<p>บล็อกที่ชนะซึ่งมีธุรกรรมของอลิซอยู่ในนั้น ได้กลายเป็นส่วนหนึ่งของบล็อกเชน และบล็อกนี้ถูกนับเป็นการยืนยันหนึ่งครั้งสำหรับธุรกรรมนั้น หลังจากที่บล็อกที่มีธุรกรรมของอลิซได้ถูกเผยแพร่ไปทั่วเครือข่าย การสร้างบล็อกทางเลือกที่มีเวอร์ชันอื่นของธุรกรรมของอลิซ (เช่น ธุรกรรมที่ไม่ได้จ่ายให้ บ๊อบ) จะต้องใช้ปริมาณงานเท่ากับที่นักขุดทั้งหมดต้องใช้ในการสร้างบล็อกใหม่ทั้งบล็อก เมื่อมีบล็อกทางเลือกหลายบล็อกให้เลือก full node ในเครือข่ายของบิตคอยน์ก็จะทำการเลือกบล็อกเชนที่ถูกต้อง โดยจะเป็นเชนซึ่งมี Proof of Work (PoW) รวมมากที่สุด ซึ่งเรียกว่าบล็อกเชนที่ดีที่สุด หากเครือข่ายทั้งหมดจะยอมรับบล็อกทางเลือก จะต้องมีการขุดบล็อกใหม่เพิ่มเติมอีกหนึ่งบล็อกต่อจากบล็อกทางเลือกนั้น</p>
<p>นั่นหมายความว่านักขุดมีตัวเลือกอื่น อย่างเช่นการที่พวกเขาสามารถร่วมมือกับอลิซเพื่อสร้างธุรกรรมทางเลือกที่เธอไม่ได้จ่ายเงินให้บ๊อบ โดยอลิซอาจเสนอส่วนแบ่งจากเงินที่เธอเคยจ่ายให้บ๊อบแก่นักขุด แต่การกระทำที่ไม่ซื่อสัตย์นี้จะต้องใช้ความพยายามเท่ากับการสร้างบล็อกใหม่ถึงสองบล็อก ซึ่งในทางกลับกันแล้ว นักขุดที่ทำงานอย่างซื่อสัตย์สามารถสร้างบล็อกใหม่เพียงบล็อกเดียวและได้รับค่าธรรมเนียมจากธุรกรรมทั้งหมดที่รวมอยู่ในบล็อก พร้อมกับรางวัลบล็อก (block subsidy) นอกจากนี้ต้นทุนที่สูงในการสร้างบล็อกสองบล็อกเพื่อพยายามเปลี่ยนแปลงธุรกรรมที่ยืนยันแล้วสำหรับผลตอบแทนเพียงเล็กน้อยนั้นไม่คุ้มค่าและการกระทำดังกล่าวมีโอกาสน้อยที่จะเกิดขึ้น สำหรับ บ๊อบ นั่นหมายความว่าเขาสามารถเริ่มเชื่อถือได้ว่าการชำระเงินจากอลิซนั้นเป็นสิ่งที่เชื่อถือได้</p>
<p>ประมาณ 19 นาทีหลังจากบล็อกที่มีธุรกรรมของอลิซ ได้ถูกเผยแพร่บล็อกใหม่ถูกขุดขึ้นโดยนักขุดอีกคน และเนื่องจากบล็อกใหม่นี้ถูกสร้างต่อจากบล็อกที่มีธุรกรรมของอลิซ (ทำให้ธุรกรรมของอลิซได้รับการยืนยันสองครั้ง) ธุรกรรมของ อลิซจะสามารถเปลี่ยนแปลงได้ก็ต่อเมื่อมีการขุดบล็อกทางเลือกสองบล็อกขึ้นมา และมีบล็อกใหม่ที่สร้างต่อจากบล็อกเหล่านั้น รวมเป็นสามบล็อกที่ต้องถูกขุดเพื่อให้อลิซสามารถดึงเงินที่เธอส่งให้บ๊อบกลับมาได้ และทุกบล็อกที่ขุดต่อจากบล็อกที่มีธุรกรรมของอลิซนั้นจะนับเป็นการยืนยันเพิ่มเติม เมื่อจำนวนบล็อกที่ต่อกันเพิ่มมากขึ้น การย้อนกลับธุรกรรมก็จะยากขึ้นเรื่อย ๆ ทำให้บ๊อบมั่นใจมากขึ้นเรื่อย ๆ ว่าการชำระเงินของอลิซนั้นจะปลอดภัย</p>
<p>จากภาพที่แนบไว้ข้างล่างนี้ เราสามารถเห็นบล็อกที่มีธุรกรรมของอลิซและด้านล่างของบล็อกนี้มีบล็อกอีกหลายแสนบล็อกที่เชื่อมต่อกันเป็นโซ่ (blockchain) ต่อเนื่องไปจนถึงบล็อกหมายเลข <a href='/tag/0/'>#0</a> หรือที่เรียกว่า genesis block  และเมื่อเวลาผ่านไป "ความสูง" ของบล็อกใหม่ที่เพิ่มขึ้นจะทำให้ความยากในการคำนวณของทั้งเครือข่ายเพิ่มขึ้นตามไปด้วย ตามธรรมเนียมแล้ว บล็อกใด ๆ ที่มีการยืนยันมากกว่าหกครั้งจะถือว่ายากมากที่จะเปลี่ยนแปลง เพราะต้องใช้การคำนวณอย่างมหาศาลในการคำนวณบล็อกหกบล็อกใหม่ (รวมถึงบล็อกใหม่อีกหนึ่งบล็อก)</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734788200516-YAKIHONNES3.png" alt="image"></p>
<h4>การใช้จ่ายในธุรกรรม</h4>
<p>เมื่อธุรกรรมของอลิซได้กลายเป็นส่วนหนึ่งของบล็อกเชน แปลว่ามันสามารถถูกเรียกดูได้จากทุกบิตคอยน์แอปพลิเคชัน และทุกโหนดสามารถที่จะตรวจสอบธุรกรรมนี้ได้อย่างอิสระ ว่าธุรกรรมนี้ถูกต้องหรือไม่ โดยจะตรวจสอบย้อนไปตั้งแต่ตอนที่เหรียญนั้น ๆ ถูกสร้างและตรวจสอบต่อมาเรื่อย ๆ จนถึงธุรกรรมปัจจุบัน ไคลเอนต์จะสามารถตรวจสอบการชำระเงินได้บางส่วน โดยการยืนยันว่าธุรกรรมนั้นอยู่ในบล็อกเชนแล้ว และมีบล็อกจำนวนมากที่ถูกขุดหลังจากนั้น ซึ่งนี่ช่วยให้มั่นใจได้ว่ามีการใช้ความพยายามอย่างมากในการยืนยันธุรกรรมนี้โดยเหล่านักขุดไปแล้ว </p>
<p>ในตอนนี้บ็อบสามารถใช้บิตคอยน์ที่อลิซส่งให้ต่อได้แล้ว! สมมุติว่าบ๊อบต้องการจ่ายค่าจ้างให้ผู้รับเหมาหรือผู้จัดหาสินค้า โดยการโอนมูลค่าจากการชำระเงินของอลิซสำหรับพอดแคสต์ไปยังเจ้าของรายใหม่ เมื่อบ๊อบใช้เงินที่ได้รับจากอลิซและลูกค้าคนอื่น ๆ เขาก็ขยายสายโซ่ของธุรกรรมออกไป สมมติว่าบ๊อบจ่ายค่าจ้างให้กรูฟซึ่งเป็นนักออกแบบเว็บไซต์ของเขาสำหรับสร้างหน้าเว็บใหม่ สายโซ่ของธุรกรรมจะมีลักษณะดังนี้:</p>
<ul>
<li>ธุรกรรมจากโจถึงอลิซ: โจโอนบิตคอยน์ให้อลิซเพื่อการซื้อขายหรือจ่ายค่าบริการบางอย่าง</li>
<li>ธุรกรรมจากอลิซถึงบ๊อบ: อลิซโอนบิตคอยน์ให้บ๊อบเพื่อชำระค่าพอดแคสต์</li>
<li>ธุรกรรมจากบ๊อบถึงกรูฟ: บ๊อบโอนบิตคอยน์จากที่ได้รับจากอลิซให้กรูฟเพื่อจ่ายค่าจ้างออกแบบเว็บไซต์</li>
</ul>
<p>สายโซ่ของธุรกรรมนี้แสดงให้เห็นการเชื่อมต่อของธุรกรรมจากโจถึงอลิซและจากอลิซถึงบ๊อบต่อด้วยจากบ๊อบถึง กรูฟ โดยแต่ละธุรกรรมได้รับการบันทึกไว้ในบล็อกเชน ซึ่งช่วยให้ทุกคนสามารถตรวจสอบความถูกต้องของธุรกรรมในสายโซ่นี้ได้</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734788274465-YAKIHONNES3.png" alt="image"></p>
<p>ในบทนี้ เราได้เห็นวิธีที่ธุรกรรมสร้างสายโซ่ที่ถ่ายโอนมูลค่าจากเจ้าของหนึ่งไปยังอีกเจ้าของหนึ่ง นอกจากนี้เรายังได้ติดตามธุรกรรมของอลิซตั้งแต่เริ่มสร้างในกระเป๋าเงินของเธอ ผ่านเครือข่ายบิตคอยน์ไปจนถึงนักขุดที่บันทึกมันลงในบล็อกเชน และสำหรับในส่วนที่เหลือของหนังสือเล่มนี้ เราจะศึกษารายละเอียดเกี่ยวกับเทคโนโลยีที่เกี่ยวข้อง ไม่ว่าจะเป็นกระเป๋าเงิน, address, digital signature, network และกระบวนการขุดอย่างละเอียด</p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<h2>บทที่ 2: ภาพรวมการทำงานของบิตคอยน์</h2>
<h1>บิตคอยน์ทำงานอย่างไร</h1>
<p>ระบบอย่างบิตคอยน์นั้นแตกต่างกับระบบธนาคารและระบบการชำระเงินแบบดั้งเดิมอย่างสิ้นเชิง เพราะมันสามารถทำงานได้โดยไม่จำเป็นต้องไว้วางใจบุคคลที่สาม แทนที่จะมีหน่วยงานกลางที่เชื่อถือได้ บิตคอยน์ได้อณุญาตให้ผู้ใช้แต่ละคนใช้ซอฟต์แวร์บนคอมพิวเตอร์ของตนเองเพื่อตรวจสอบการทำงานที่ถูกต้องของทุกส่วนในระบบ ซึ่งในบทนี้เอง เราจะทำการสำรวจบิตคอยน์ภาพรวมโดยติดตามธุรกรรมหนึ่งรายการผ่านระบบของบิตคอยน์ ดูว่าธุรกรรมนั้นถูกบันทึกลงในบล็อกเชนอย่างไร และการบันทึกธุรกรรมแบบกระจายศูนย์นั้นทำได้อย่างไร ส่วนในบทถัดไปจะลงลึกถึงเทคโนโลยีที่อยู่เบื้องหลังธุรกรรม เครือข่าย และการขุด</p>
<h2>ภาพรวมของบิตคอยน์</h2>
<p>ระบบของบิตคอยน์นั้นประกอบไปด้วย เหล่าผู้ใช้งาน wallet ต่าง ๆ , ธุรกรรมที่กระจายไปทั่วเครือข่าย และเหล่านักขุดที่จะคอยแข่งขันกันเพื่อสร้างบล๊อกใหม่ โดยที่มีบล๊อกเชนเป็นเหมือนสมุดบันทึกธุรกรรมที่รวมธุรกรรมทั้งหมดไว้ ตัวอย่างที่จะได้เห็นต่อไปนี้เป็นธุรกรรมที่เกิดขึ้นจริงบนเครือข่ายของบิตคอยน์ โดยจำลองการโต้ตอบระหว่างผู้ใช้หลายคนผ่านการส่งเงินจาก wallet หนึ่งไปยังอีก wallet และในขณะนั้นเราจะติดตามธุรกรรมผ่านเครือข่ายบิตคอยน์ ไปจนถึงบล็อกเชน เราจะใช้เว็บไซต์สำรวจบล็อกเชน (blockchain explorer) เพื่อดูภาพรวมในแต่ละขั้นตอน โดยมีเว็บไซต์สำรวจบล็อกเชนที่นิยม ดังนี้</p>
<ul>
<li>Blockstream Explorer</li>
<li>Mempool.Space</li>
<li>BlockCypher Explorer</li>
</ul>
<p>เว็บไซต์เหล่านี้มีฟังก์ชันการค้นหาที่สามารถใช้ค้นหา Bitcoin address, Transaction Hash, หมายเลขบล็อก หรือ Block hash และเรียกดูข้อมูลที่เกี่ยวข้องจากเครือข่ายบิตคอยน์ได้ สำหรับแต่ละตัวอย่างธุรกรรมหรือบล็อก เราจะให้ URL เพื่อให้คุณสามารถค้นหาและศึกษาข้อมูลเพิ่มเติมได้ด้วยตัวเอง</p>
<h3>คำเตือนเกี่ยวกับความเป็นส่วนตัวของการใช้ Block Explorer</h3>
<p>การค้นหาข้อมูลใน block explorer อาจเปิดเผยให้ผู้ให้บริการทราบว่าคุณสนใจข้อมูลนั้น ซึ่งอาจเชื่อมโยงกับที่อยู่ IP ของคุณ รายละเอียดของเบราว์เซอร์ การค้นหาที่ผ่านมา หรือข้อมูลที่สามารถระบุตัวตนได้อื่น ๆ หากคุณค้นหาธุรกรรมจากหนังสือเล่มนี้ ผู้ให้บริการอาจคาดเดาได้ว่าคุณกำลังศึกษาเกี่ยวกับบิตคอยน์ ซึ่งไม่น่าจะมีปัญหาอะไร แต่หากคุณค้นหาธุรกรรมของตนเอง ผู้ให้บริการอาจสามารถคาดเดาได้ว่าคุณได้รับ ใช้จ่าย และมีบิตคอยน์อยู่เท่าใดในปัจจุบัน</p>
<h2>การซื้อของจากร้านค้าออนไลน์</h2>
<p>อลิซเป็นผู้ใช้งานใหม่ ที่พึ่งได้รับบิตคอยน์เป็นครั้งแรกจากคำแนะนำของโจเมื่อบทที่แล้ว โดยเธอได้ซื้อบิตคอยน์จากโจเก็บไว้ และตั้งแต่นั้นมาอลิซก็ซื้อบิตคอยน์เพิ่มเรื่อย ๆ และตอนนี้อลิซต้องการทำธุรกรรมด้วยบิตคอยน์ครั้งแรกของเธอ โดยการใช้จ่ายมันเพื่อแลกกับสิทธิ์เข้าถึงพอดแคสต์ตอนพิเศษจากร้านค้าออนไลน์ของบ๊อบ  ร้านค้าออนไลน์ของบ๊อบเองก็เพิ่งมีการเพิ่มบิตคอยน์เป็นตัวเลือกในการทำธุรกรรม ราคาสินค้าในร้านของบ๊อบแสดงเป็นสกุลเงินท้องถิ่น (ดอลลาร์สหรัฐ) แต่ในหน้าชำระเงิน ลูกค้าสามารถเลือกชำระเงินเป็นดอลลาร์หรือบิตคอยน์ก็ได้</p>
<p>อลิซเลือกตอนพอดแคสต์ที่เธอต้องการซื้อและดำเนินการไปยังหน้าชำระเงิน ในหน้าชำระเงิน อลิซพบตัวเลือกในการชำระเงินด้วยบิตคอยน์ นอกเหนือจากตัวเลือกปกติ แต่ในตะกร้าชำระเงินจะแสดงราคาทั้งในรูปแบบดอลลาร์สหรัฐและบิตคอยน์ตามอัตราแลกเปลี่ยนในขณะนั้น หลังจากกดจ่ายด้วยบิตคอยน์ระบบของบ๊อบได้ทำการสร้างใบเรียกเก็บเงิน (invoice) ในรูปแบบของ QR-code ตามภาพด้านล่าง</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734787367004-YAKIHONNES3.png" alt="image"></p>
<p>ต่างจาก QR code ทั่วไปที่มีเพียง Bitcoin address ปลายทางเท่านั้น ใบแจ้งหนี้นี้เป็น QR code แบบ URI ที่ประกอบด้วย Bitcoin address จำนวนเงินชำระ และคำอธิบาย (memo) ซึ่งช่วยให้ Bitcoin wallet แอปพลิเคชันเติมข้อมูลที่ใช้ในการชำระเงินล่วงหน้าได้ และยังแสดงคำอธิบายที่อ่านเข้าใจง่ายให้กับผู้ใช้อีกด้วย คุณสามารถสแกน QR code นี้ด้วย Bitcoin wallet เพื่อดูสิ่งที่อลิซจะเห็น</p>
<h3>QR Code ของใบแจ้งหนี้นี้เข้ารหัส URI ดังต่อไปนี้ ซึ่งถูกกำหนดไว้ใน BIP21:</h3>
<p><code>bitcoin:bc1qk2g6u8p4qm2s2lh3gts5cpt2mrv5skcuu7u3e4?amount=0.01577764&amp;</code><br><code>label=Bob%27s%20Store&amp;</code><br><code>message=Purchase%20at%20Bob%27s%20Store</code></p>
<p>โดยส่วนประกอบของ URI สามารถจำแนกได้ ดังนี้</p>
<ul>
<li>A Bitcoin address: "bc1qk2g6u8p4qm2s2lh3gts5cpt2mrv5skcuu7u3e4"</li>
<li>The payment amount (จำนวนบิตคอยน์) : "0.01577764"</li>
<li>A label for the recipient address (label): "Bob's Store"</li>
<li>A description for the payment (memo): "Purchase at Bob's Store"</li>
</ul>
<p>อลิซใช้สมาร์ทโฟนของเธอสแกนบาร์โค้ดที่แสดงอยู่ หน้าจอสมาร์ทโฟนของเธอจะแสดงการชำระเงินในจำนวนที่ถูกต้องสำหรับร้านของบ๊อบ และเธอกด “Send” เพื่อยืนยันการชำระเงิน ภายในไม่กี่วินาที (เวลาประมาณเดียวกับการอนุมัติบัตรเครดิต) บ๊อบก็จะเห็นธุรกรรมดังกล่าวปรากฏบนเครื่องรับชำระเงินของเขา</p>
<blockquote>
<p>เครือข่ายบิตคอยน์สามารถทำธุรกรรมในมูลค่าเศษส่วนได้ เช่น มิลลิบิทคอยน์ (1/1,000 ของบิทคอยน์) ไปจนถึง 1/100,000,000 ของบิทคอยน์ ซึ่งเรียกว่า "ซาโตชิ" ในหนังสือเล่มนี้ใช้กฎการพหูพจน์เดียวกันกับดอลลาร์หรือสกุลเงินแบบดั้งเดิมเมื่อพูดถึงจำนวนที่มากกว่าหนึ่งบิทคอยน์ เช่น "10 บิตคอยน์" หรือ "0.001 บิตคอยน์" กฎเดียวกันนี้ยังนำไปใช้กับหน่วยบัญชีบิทคอยน์อื่น ๆ เช่น มิลลิบิทคอยน์และซาโตชิอีกด้วย</p>
</blockquote>
<h2>ธุรกรรมในระบบบิตคอยน์</h2>
<p>ธุรกรรมในระบบบิตคอยน์คือการแจ้งเครือข่ายว่าเจ้าของบิทคอยน์ได้อนุมัติการโอนมูลค่าไปยังเจ้าของใหม่แล้ว และ เจ้าของใหม่สามารถใช้บิทคอยน์เหล่านั้นได้ โดยสร้างธุรกรรมใหม่เพื่อรออนุมัติการโอนไปยังเจ้าของคนอื่นต่อ ๆ ไป ทำให้เกิดการส่งต่อความเป็นเจ้าของอย่างต่อเนื่อง</p>
<h3>ธุรกรรมขาเข้าและขาออกของบิตคอยน์</h3>
<p>ธุรกรรมเปรียบเสมือนบันทึกในสมุดบัญชีแบบสองทาง โดยธุรกรรมแต่ละรายการจะมีอินพุต (inputs) หนึ่งรายการหรือมากกว่านั้นที่ใช้จ่ายเงิน และมีเอาต์พุต (outputs) หนึ่งรายการหรือมากกว่าที่รับเงิน มูลค่าของอินพุตและเอาต์พุตไม่จำเป็นต้องเท่ากันเสมอไป เอาต์พุตมักจะมีมูลค่าน้อยกว่าอินพุตเล็กน้อย ซึ่งส่วนต่างนี้คือ "ค่าธรรมเนียมธุรกรรม" ที่นักขุดจะได้รับเมื่อรวมธุรกรรมในบล็อกเชน</p>
<p>ธุรกรรมยังมีหลักฐานการเป็นเจ้าของสำหรับจำนวนบิตคอยน์ (อินพุต) ที่ถูกใช้ในรูปของลายเซ็นดิจิทัลจากเจ้าของเดิม ซึ่งสามารถตรวจสอบความถูกต้องได้ ในระบบบิตคอยน์การใช้จ่ายบิตคอยน์คือการลงนามในธุรกรรมเพื่อโอนมูลค่าจากธุรกรรมก่อนหน้าไปยังเจ้าของใหม่ที่ระบุผ่าน Bitcoin adress</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734787627692-YAKIHONNES3.png" alt="image"></p>
<h3>ห่วงโซ่ของธุรกรรม</h3>
<p>การชำระเงินของอลิซไปยังร้านของบ็อบนั้นเป็นใช้เอาต์พุตจากธุรกรรมก่อนหน้าเป็นอินพุตในธุรกรรมครั้งนี้ (ในบทก่อนหน้า อลิซได้รับบิทคอยน์จากโจเพื่อนของเธอ ) เราเรียกธุรกรรมนี้ว่า "ธุรกรรมที่ 1 (Tx1)" ซึ่งแสดงถึงห่วงโซ่ของธุรกรรมที่เอาต์พุตของธุรกรรมหนึ่งถูกใช้เป็นอินพุตในธุรกรรมถัดไป</p>
<h4>การอ้างอิงอินพุตจากเอาต์พุตก่อนหน้า</h4>
<p>Tx1 โอน 0.001 บิทคอยน์ (100,000 ซาโตชิ) ไปยังเอาต์พุตที่ล็อกด้วยกุญแจของอลิซ และในธุรกรรมใหม่ของอลิซ (Tx2) ที่ส่งให้ร้านของบ็อบ เธออ้างถึงเอาต์พุตก่อนหน้าเป็นอินพุต อย่างที่เห็นในภาพประกอบ การอ้างอิงด้วยลูกศรและระบุอินพุตว่า "Tx1:0" ในธุรกรรมจริง การอ้างอิงจะใช้รหัสประจำธุรกรรม (txid) เป็นตัวระบุขนาด 32 ไบต์ที่แสดงถึงธุรกรรมที่อลิซได้รับเงินจากโจ ส่วน ":0" หมายถึงตำแหน่งของเอาต์พุตที่อลิซได้รับเงิน ซึ่งในกรณีนี้คือตำแหน่งแรก (ตำแหน่ง 0)</p>
<h4>การคำนวณมูลค่าอินพุต</h4>
<p>เนื่องจากธุรกรรมของบิตคอยน์นั้นไม่ได้ระบุค่าของอินพุตอย่างชัดเจน ตัวซอฟต์แวร์เลยจะต้องใช้การอ้างอิงของอินพุตเพื่อค้นหาเอาต์พุตของธุรกรรมก่อนหน้าที่ถูกใช้ไป</p>
<h4>เอาต์พุตใน Tx2 ของอลิซ</h4>
<p>Tx2 ของอลิซมีเอาต์พุตใหม่สองรายการ รายการหนึ่งจ่าย 75,000 ซาโตชิสำหรับพอดแคสต์ และอีกรายการจ่าย 20,000 ซาโตชิคืนให้อลิซเป็นเงินทอน<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734787700413-YAKIHONNES3.png" alt="image"></p>
<blockquote>
<h4>เกร็ดสาระเล็ก ๆ น้อย ๆ</h4>
<ul>
<li>ธุรกรรมของบิตคอยน์นั้นอยู่ในรูปแบบซีเรียลไลซ์ (serialized) เป็นรูปแบบข้อมูลที่ซอฟต์แวร์ใช้สำหรับการส่งธุรกรรม โดยจะเข้ารหัสมูลค่าที่ต้องการโอนด้วยตัวเลขจำนวนเต็มซึ่งเป็นหน่วยมูลค่าที่เล็กที่สุดในระบบ on-chain</li>
<li>ที่มาของชื่อ "ซาโตชิ" :เมื่อบิตคอยน์ถูกสร้างขึ้นในครั้งแรก หน่วยมูลค่านี้ยังไม่มีชื่อเรียก นักพัฒนาบางคนจึงเรียกมันว่า "หน่วยฐาน" (base unit) แต่ต่อมาผู้ใช้งานหลาย ๆ คนเริ่มเรียกหน่วยนี้ว่า "ซาโตชิ" (satoshi หรือ sat) เพื่อเป็นเกียรติแก่ผู้สร้างบิตคอยน์</li>
</ul>
</blockquote>
<h4>การทอนเงิน</h4>
<p>นอกเหนือจากการสร้างเอาต์พุตเพื่อจ่ายให้กับผู้รับบิตคอยน์แล้ว ธุรกรรมจำนวนมากยังมีเอาต์พุตที่จ่ายเงินคืนให้กับผู้จ่าย ซึ่งเรียกว่า เอาต์พุตทอนเงิน (change output) เนื่องจากอินพุตของธุรกรรม (คล้ายกับธนบัตร) ไม่สามารถแบ่งใช้บางส่วนได้ เช่น ถ้าคุณซื้อของราคา 5 ดอลลาร์และจ่ายด้วยธนบัตร 20 ดอลลาร์ คุณคาดหวังว่าจะได้เงินทอน 15 ดอลลาร์ ในทำนองเดียวกัน ในธุรกรรม Bitcoin หากคุณซื้อสินค้าราคา 5 บิตคอยน์แต่มีอินพุตมูลค่า 20 บิตคอยน์ คุณจะสร้างเอาต์พุต 5 บิตคอยน์ไปยังเจ้าของร้าน และอีกเอาต์พุต 15 บิตคอยน์คืนให้ตัวคุณเองเป็นเงินทอน (ไม่นับรวมค่าธรรมเนียมธุรกรรม) </p>
<blockquote>
<ul>
<li>หากมองผ่านมุมของโปรโตคอลบิตคอยน์นั้นไม่ได้มีความแตกต่างใด ๆ ระหว่างเอาต์พุตเงินทอนกับเอาต์พุตการจ่ายเงินปกติ</li>
<li>โดยทั่วไปแล้วเอาต์พุตเงินทอนจะเป็นการโอนไปจ่ายให้กับ Bitcoin Address อันใหม่ในกระเป๋าตัวเองดังรูปที่แสดงข้างล่าง</li>
</ul>
</blockquote>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734787818103-YAKIHONNES3.png" alt="image"></p>
<h3>การสร้างธุรกรรม</h3>
<p>แอปพิเคชั่นกระเป๋าเงินของอลิซจะทำการสร้างอินพุตและสร้างเอาต์พุตตามที่ Alice ต้องการ โดยที่เธอเพียงแค่กรอกปลายทาง จำนวนเงิน และค่าธรรมเนียมธุรกรรมกระเป๋าเงินจะทำงานที่เหลือให้โดยอัตโนมัติ นอกจากนี้ กระเป๋าเงินยังสามารถสร้างธุรกรรมแบบออฟไลน์ได้ คล้ายกับการเขียนเช็คที่บ้านแล้วค่อยนำไปฝากธนาคารในภายหลังอีกด้วย</p>
<h4>การเลือกอินพุตที่เหมาะสม</h4>
<p>กระเป๋าเงินจะเลือกอินพุตที่มีมูลค่าเพียงพอสำหรับการชำระเงินไปยังบ๊อบโดยตรวจสอบเอาต์พุตที่ยังไม่ได้ใช้ (UTXOs) ซึ่งหากมูลค่าไม่เพียงพอ กระเป๋าเงินก็จะทำการรวม UTXOs หลาย ๆ รายการเข้าด้วยกัน เพื่อให้ได้ยอดที่ต้องการ และหากอินพุตมีมูลค่าสูงกว่าค่าที่ต้องจ่าย กระเป๋าเงินจะสร้างเอาต์พุตสำหรับทอนเงินกลับมาให้อลิซ</p>
<h4>การสร้างเอาต์พุต</h4>
<p>เอาต์พุตประกอบด้วยสคริปต์ที่กำหนดให้ผู้ที่มีคีย์ของบ๊อบเท่านั้นสามารถลงนามเพื่อที่จะใช้เงินได้ นอกจากนี้ยังมีเอาต์พุตสำหรับทอนเงินกลับมาให้อลิซ ซึ่งทำให้เธอสามารถใช้เงินทอนนั้นในการทำธุรกรรมถัดไป และค่าธรรมเนียมธุรกรรมจะถูกคำนวณจากส่วนต่างระหว่างอินพุตและเอาต์พุต และนั่นเองที่จะเป็นรางวัลสำหรับนักขุดที่บันทึกธุรกรรมลงบล็อกเชนของบิตคอยน์</p>
<h2>การใส่ธุรกรรมลงในบล๊อกเชน</h2>
<p>ธุรกรรมที่สร้างขึ้นโดย Bitcoin wallet ของอลิซมีข้อมูลทั้งหมดที่จำเป็นสำหรับการสร้างธุรกรรม (การยืนยันว่าอลิซเป็นเจ้าของเงิน และ Bitcoin address ปลายทาง) จากนั้นธุรกรรมนี้จะต้องถูกส่งไปยังเครือข่ายของบิตคอยน์ เพื่อที่จะให้ธุรกรรมนั้นเป็นส่วนนึงในเครือข่ายของบิตคอยน์ และในส่วนถัดไปของหนังสือเล่มนี้ เราจะอธิบายถึงว่าธุรกรรมกลายเป็นส่วนหนึ่งของบล็อกใหม่อย่างไร และกระบวนการขุดบล็อกเป็นอย่างไร รวมถึงการที่บล็อกใหม่ได้รับความไว้วางใจมากขึ้นเมื่อมีการเพิ่มบล็อกใหม่ ๆ เข้ามาเรื่อย ๆ หมายถึงอะไร ?</p>
<h3>การส่งธุรกรรมเข้าไปยังเครือข่าย</h3>
<p>เนื่องจากธุรกรรมมีข้อมูลที่จำเป็นสำหรับการประมวลผลทั้งหมด จึงทำให้การส่งผ่านสามารถทำได้จากที่ไหนหรืออย่างไรก็ได้ อย่างที่ได้กล่าวไปว่าเครือข่ายของบิตคอยน์เป็นเครือข่ายแบบ peer-to-peer โดยที่แต่ละโหนดเชื่อมต่อกับโหนดอื่น ๆ อีกหลายโหนด เพื่อทำหน้าที่กระจายธุรกรรมและบล็อกให้กับผู้เข้าร่วมทั้งหมดในระบบ</p>
<h3>การกระจายธุรกรรม</h3>
<p>โหนดในเครือข่าย peer-to-peer ของบิตคอยน์นั้นเป็นซอฟต์แวร์ที่สามารถตรวจสอบความถูกต้องของธุรกรรมได้  และการเชื่อมต่อระหว่างโหนดสามารถแสดงเป็นเส้นในกราฟ ทำให้โหนดเหล่านี้เรียกว่า “โหนดตรวจสอบเต็มรูปแบบ” (full nodes) กระเป๋าเงินของอลิซสามารถส่งธุรกรรมไปยังโหนดบิตคอยน์ใด ๆ ผ่านการเชื่อมต่อใด ๆ ก็ได้ เช่น สายแลน WiFi หรือ เครือข่ายมือถือ โดยถ้าหากโหนดได้รับธุรกรรมที่ถูกต้องซึ่งยังไม่เคยเห็นมาก่อน มันจะกระจายธุรกรรมนี้ไปยังโหนดอื่น ๆ ที่เชื่อมต่อด้วย ซึ่งเป็นเทคนิคที่เรียกว่า gossiping ซึ่งทำให้ธุรกรรมแพร่กระจายไปทั่วเครือข่ายอย่างรวดเร็วภายในไม่กี่วินาที</p>
<h3>การขุดบิตคอยน์</h3>
<p>ตอนนี้ธุรกรรมของอลิซได้เข้าไปสู่ในเครือข่ายของบิตคอยน์แล้ว แต่มันยังไม่ได้ถูกบรรจุลงในบล๊อกเชนเนื่องจากจะต้องรอให้นักขุดทำการนำธุรกรรมนั้น ๆ เข้าไปในบล๊อกและบล๊อกนั้นจำเป็นต้องผ่านการตรวจสอบโดยโหนดในเครือข่ายของบิตคอยน์เสียก่อน จึงจะถูกบันทึกลงในบล๊อกเชน<br>ในระบบของบิตคอยน์นั้น มีการป้องกันการปลอมแปลงด้วยการคำนวณทางคณิตศาสตร์ ซึ่งเป็นการคำนวณที่จำเป็นต้องใช้พลังงานมหาศาลในการคำนวณ แต่ใช้พลังงานเพียงเล็กน้อยในการตรวจสอบ โดยธุรกรรมทั้งหมดจะถูกจัดเรียงเป็นบล๊อกและแต่ละบล๊อกจะมีบล๊อกเฮดเดอร์ที่จำเป็นต้องสร้างตามเงื่อนไขเฉพาะ โดยกระบวนการขุดบิตคอยน์นั้นมีวัตถุประสงค์อยู่สองอย่าง ดังนี้:</p>
<ul>
<li>สร้างแรงจูงใจให้ขุดเฉพาะธุรกรรมที่ถูกต้องตามกฎ: เนื่องจากวิธีที่เหล่านักขุดจะได้รับผลกำไรที่สูงที่สุดจากการสร้างบล๊อกที่ตรงกับฉันทมติของระบบเท่านั้น (หากไม่ทำตามบล๊อกจะไม่ถูกยอมรับโดยโหนด และนั่นจะเป็นการสิ้นเปลืองพลังงานที่ได้คำนวณมาโดยเปล่าประโยชน์) นั้นจึงเป็นแรงจูงใจหลัก ๆ ให้เหล่านักขุดทำการใส่ธุรกรรมที่ถูกต้องตามกฏเท่านั้นลงในบล๊อกที่ตนสร้าง และสิ่งนี้เองก็ทำให้ผู้ใช้สามารถเลือกที่จะสันนิษฐานโดยอิงตามความไว้วางใจว่าธุรกรรมใด ๆ ในบล็อกนั้น ๆ เป็นธุรกรรมที่ถูกต้อง </li>
<li>สร้างเหรียญใหม่ตามตารางการออกเหรียญที่กำหนดไว้ล่วงหน้า: ในปัจจุบันนั้นจะมีการสร้างบิตคอยน์ใหม่ในแต่ละบล็อก คล้ายคลึงกับธนาคารกลางที่พิมพ์เงินใหม่ โดยจำนวนบิตคอยน์ในแต่ละบล๊อกที่จะถูกผลิตขึ้นมาใหม่นั้นถูกกำหนดมาตั้งแต่วันที่ระบบของบิตคอยน์ได้เริ่มขึ้นและไม่สามารถเปลี่ยนแปลงได้</li>
</ul>
<p>การขุดได้ช่วยให้เกิดความสมดุลระหว่างต้นทุนและผลตอบแทน เนื่องจากการขุดมีการใช้ไฟฟ้าเพื่อแก้ปัญหาการคำนวณ และนักขุดที่ประสบความสำเร็จจะได้รับรางวัลในรูปแบบของบิตคอยน์ใหม่และค่าธรรมเนียมจากการทำธุรกรรม แต่อย่างไรก็ตาม รางวัลจะถูกเก็บรวบรวมก็ต่อเมื่อนักขุดรวมเฉพาะธุรกรรมที่ถูกต้องเท่านั้น โดยกฎของโปรโตคอลบิตคอยน์สำหรับการสร้างฉันทามติ จะกำหนดว่าอะไรถูกต้อง โดยความสมดุลที่ละเอียดอ่อนนี้เองที่คอยสร้างให้ความปลอดภัยแก่บิตคอยน์โดยไม่ต้องมีหน่วยงานกลางมาคอยดูแล</p>
<p>การขุดถูกออกแบบให้เหมือนกับการจับสลากแบบกระจายศูนย์ นักขุดแต่ละคนสามารถสร้าง "สลาก" ของตัวเองได้โดยการสร้างบล็อกตัวอย่างที่ประกอบไปด้วยธุรกรรมใหม่ที่ต้องการขุด พร้อมกับข้อมูลอื่น ๆ และนักขุดจะป้อนบล็อกตัวอย่างนี้เข้าไปในอัลกอริทึมที่ออกแบบมาเป็นพิเศษเพื่อแฮชข้อมูล ทำให้ได้ค่าผลลัพธ์ที่แตกต่างจากข้อมูลเดิมอย่างสิ้นเชิง โดยแฮชฟังก์ชันนี้จะให้ผลลัพธ์เดียวกันเสมอสำหรับข้อมูลชุดเดิม แต่ไม่สามารถคาดเดาผลลัพธ์ได้หากป้อนข้อมูลใหม่ แม้จะแตกต่างเพียงเล็กน้อยจากข้อมูลก่อนหน้า</p>
<p>หากค่าผลลัพธ์ของแฮชตรงกับเงื่อนไขที่กำหนดของโปรโตคอล นักขุดจะชนะการจับสลาก และผู้ใช้งานบิตคอยน์ จะยอมรับบล็อกนี้พร้อมกับธุรกรรมในนั้นว่าเป็นบล็อกที่ถูกต้อง หากไม่ตรงกับเงื่อนไข นักขุดจะปรับข้อมูลในบล็อกเล็กน้อยและลองทำการแฮชใหม่ กระบวนการนี้ต้องทำซ้ำหลายครั้ง โดย ณ ขณะที่เขียนนี้ นักขุดต้องลองสร้างบล็อกตัวอย่างประมาณ 168 พันล้านล้านครั้ง เพื่อหาคำตอบที่ถูกต้อง ซึ่งหมายถึงการรันแฮชฟังก์ชันในจำนวนครั้งมหาศาลมาก ๆ </p>
<p>แต่เมื่อพบคำตอบที่ถูกต้องแล้ว ใครก็ตามสามารถตรวจสอบว่าบล็อกนั้นถูกต้องได้โดยการรันแฮชฟังก์ชันเพียงครั้งเดียว ซึ่งทำให้การสร้างบล็อกที่ถูกต้องต้องใช้พลังงานคำนวณมหาศาล แต่การตรวจสอบทำได้ง่ายมาก กระบวนการตรวจสอบนี้สามารถพิสูจน์ได้อย่างมีหลักการว่ามีการทำงานเกิดขึ้นจริง ดังนั้น ข้อมูลที่ใช้สร้างหลักฐานนี้—ในที่นี้คือบล็อก—เรียกว่า "หลักฐานการทำงาน" หรือ Proof of Work (PoW)</p>
<p>ธุรกรรมจะถูกเพิ่มลงในบล็อกใหม่ โดยให้ความสำคัญกับธุรกรรมที่มีค่าธรรมเนียมสูงสุดก่อนและพิจารณาจากปัจจัยอื่น ๆ อีกเล็กน้อย นักขุดแต่ละคนจะเริ่มกระบวนการสร้างบล็อกตัวอย่างใหม่ทันทีหลังจากได้รับบล็อกก่อนหน้าจากเครือข่าย โดยรู้ว่ามีคนอื่นชนะรางวัลไปแล้วในรอบนั้น พวกเขาจะสร้างบล็อกตัวอย่างใหม่ที่เชื่อมโยงกับบล็อกก่อนหน้า ใส่ธุรกรรมเข้าไป และเริ่มคำนวณ Proof of Work (PoW) สำหรับบล็อกตัวอย่างนี้ นักขุดจะเพิ่มธุรกรรมพิเศษที่จ่ายรางวัลบล็อกและค่าธรรมเนียมธุรกรรมรวมเข้ากับที่อยู่บิตคอยน์ของตนเอง หากพวกเขาพบบล็อกที่ถูกต้องและถูกเพิ่มในบล็อกเชน นักขุดจะได้รับรางวัลนั้น และธุรกรรมรางวัลนี้ก็จะใช้งานได้ นักขุดที่ทำงานร่วมกับพูลจะตั้งค่าให้รางวัลถูกส่งไปยังที่อยู่ของพูล จากนั้นจะแบ่งรางวัลให้สมาชิกตามสัดส่วนการทำงานที่แต่ละคนมีส่วนร่วม</p>
<p>กลับมาที่ธุรกรรมของอลิซ ตอนนี้ธุรกรรมของอลิซได้ถูกเครือข่ายรับไปแล้วและเพิ่มลงในพูลของธุรกรรมที่ยังไม่ได้รับการยืนยันเรียบร้อย จากนั้นเมื่อธุรกรรมนั้นผ่านการตรวจสอบจาก full node แล้ว มันจะถูกรวมไว้ในบล็อกตัวอย่าง และประมาณห้านาทีหลังจากที่อลิซส่งธุรกรรมจากกระเป๋าเงินของเธอ นักขุดคนหนึ่งพบคำตอบสำหรับบล็อกนั้นและประกาศไปยังเครือข่าย หลังจากที่นักขุดคนอื่น ๆ ตรวจสอบความถูกต้องของบล็อกที่ชนะ พวกเขาก็เริ่มกระบวนการสุ่มอีกครั้งเพื่อสร้างบล็อกถัดไป</p>
<p>บล็อกที่ชนะซึ่งมีธุรกรรมของอลิซอยู่ในนั้น ได้กลายเป็นส่วนหนึ่งของบล็อกเชน และบล็อกนี้ถูกนับเป็นการยืนยันหนึ่งครั้งสำหรับธุรกรรมนั้น หลังจากที่บล็อกที่มีธุรกรรมของอลิซได้ถูกเผยแพร่ไปทั่วเครือข่าย การสร้างบล็อกทางเลือกที่มีเวอร์ชันอื่นของธุรกรรมของอลิซ (เช่น ธุรกรรมที่ไม่ได้จ่ายให้ บ๊อบ) จะต้องใช้ปริมาณงานเท่ากับที่นักขุดทั้งหมดต้องใช้ในการสร้างบล็อกใหม่ทั้งบล็อก เมื่อมีบล็อกทางเลือกหลายบล็อกให้เลือก full node ในเครือข่ายของบิตคอยน์ก็จะทำการเลือกบล็อกเชนที่ถูกต้อง โดยจะเป็นเชนซึ่งมี Proof of Work (PoW) รวมมากที่สุด ซึ่งเรียกว่าบล็อกเชนที่ดีที่สุด หากเครือข่ายทั้งหมดจะยอมรับบล็อกทางเลือก จะต้องมีการขุดบล็อกใหม่เพิ่มเติมอีกหนึ่งบล็อกต่อจากบล็อกทางเลือกนั้น</p>
<p>นั่นหมายความว่านักขุดมีตัวเลือกอื่น อย่างเช่นการที่พวกเขาสามารถร่วมมือกับอลิซเพื่อสร้างธุรกรรมทางเลือกที่เธอไม่ได้จ่ายเงินให้บ๊อบ โดยอลิซอาจเสนอส่วนแบ่งจากเงินที่เธอเคยจ่ายให้บ๊อบแก่นักขุด แต่การกระทำที่ไม่ซื่อสัตย์นี้จะต้องใช้ความพยายามเท่ากับการสร้างบล็อกใหม่ถึงสองบล็อก ซึ่งในทางกลับกันแล้ว นักขุดที่ทำงานอย่างซื่อสัตย์สามารถสร้างบล็อกใหม่เพียงบล็อกเดียวและได้รับค่าธรรมเนียมจากธุรกรรมทั้งหมดที่รวมอยู่ในบล็อก พร้อมกับรางวัลบล็อก (block subsidy) นอกจากนี้ต้นทุนที่สูงในการสร้างบล็อกสองบล็อกเพื่อพยายามเปลี่ยนแปลงธุรกรรมที่ยืนยันแล้วสำหรับผลตอบแทนเพียงเล็กน้อยนั้นไม่คุ้มค่าและการกระทำดังกล่าวมีโอกาสน้อยที่จะเกิดขึ้น สำหรับ บ๊อบ นั่นหมายความว่าเขาสามารถเริ่มเชื่อถือได้ว่าการชำระเงินจากอลิซนั้นเป็นสิ่งที่เชื่อถือได้</p>
<p>ประมาณ 19 นาทีหลังจากบล็อกที่มีธุรกรรมของอลิซ ได้ถูกเผยแพร่บล็อกใหม่ถูกขุดขึ้นโดยนักขุดอีกคน และเนื่องจากบล็อกใหม่นี้ถูกสร้างต่อจากบล็อกที่มีธุรกรรมของอลิซ (ทำให้ธุรกรรมของอลิซได้รับการยืนยันสองครั้ง) ธุรกรรมของ อลิซจะสามารถเปลี่ยนแปลงได้ก็ต่อเมื่อมีการขุดบล็อกทางเลือกสองบล็อกขึ้นมา และมีบล็อกใหม่ที่สร้างต่อจากบล็อกเหล่านั้น รวมเป็นสามบล็อกที่ต้องถูกขุดเพื่อให้อลิซสามารถดึงเงินที่เธอส่งให้บ๊อบกลับมาได้ และทุกบล็อกที่ขุดต่อจากบล็อกที่มีธุรกรรมของอลิซนั้นจะนับเป็นการยืนยันเพิ่มเติม เมื่อจำนวนบล็อกที่ต่อกันเพิ่มมากขึ้น การย้อนกลับธุรกรรมก็จะยากขึ้นเรื่อย ๆ ทำให้บ๊อบมั่นใจมากขึ้นเรื่อย ๆ ว่าการชำระเงินของอลิซนั้นจะปลอดภัย</p>
<p>จากภาพที่แนบไว้ข้างล่างนี้ เราสามารถเห็นบล็อกที่มีธุรกรรมของอลิซและด้านล่างของบล็อกนี้มีบล็อกอีกหลายแสนบล็อกที่เชื่อมต่อกันเป็นโซ่ (blockchain) ต่อเนื่องไปจนถึงบล็อกหมายเลข <a href='/tag/0/'>#0</a> หรือที่เรียกว่า genesis block  และเมื่อเวลาผ่านไป "ความสูง" ของบล็อกใหม่ที่เพิ่มขึ้นจะทำให้ความยากในการคำนวณของทั้งเครือข่ายเพิ่มขึ้นตามไปด้วย ตามธรรมเนียมแล้ว บล็อกใด ๆ ที่มีการยืนยันมากกว่าหกครั้งจะถือว่ายากมากที่จะเปลี่ยนแปลง เพราะต้องใช้การคำนวณอย่างมหาศาลในการคำนวณบล็อกหกบล็อกใหม่ (รวมถึงบล็อกใหม่อีกหนึ่งบล็อก)</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734788200516-YAKIHONNES3.png" alt="image"></p>
<h4>การใช้จ่ายในธุรกรรม</h4>
<p>เมื่อธุรกรรมของอลิซได้กลายเป็นส่วนหนึ่งของบล็อกเชน แปลว่ามันสามารถถูกเรียกดูได้จากทุกบิตคอยน์แอปพลิเคชัน และทุกโหนดสามารถที่จะตรวจสอบธุรกรรมนี้ได้อย่างอิสระ ว่าธุรกรรมนี้ถูกต้องหรือไม่ โดยจะตรวจสอบย้อนไปตั้งแต่ตอนที่เหรียญนั้น ๆ ถูกสร้างและตรวจสอบต่อมาเรื่อย ๆ จนถึงธุรกรรมปัจจุบัน ไคลเอนต์จะสามารถตรวจสอบการชำระเงินได้บางส่วน โดยการยืนยันว่าธุรกรรมนั้นอยู่ในบล็อกเชนแล้ว และมีบล็อกจำนวนมากที่ถูกขุดหลังจากนั้น ซึ่งนี่ช่วยให้มั่นใจได้ว่ามีการใช้ความพยายามอย่างมากในการยืนยันธุรกรรมนี้โดยเหล่านักขุดไปแล้ว </p>
<p>ในตอนนี้บ็อบสามารถใช้บิตคอยน์ที่อลิซส่งให้ต่อได้แล้ว! สมมุติว่าบ๊อบต้องการจ่ายค่าจ้างให้ผู้รับเหมาหรือผู้จัดหาสินค้า โดยการโอนมูลค่าจากการชำระเงินของอลิซสำหรับพอดแคสต์ไปยังเจ้าของรายใหม่ เมื่อบ๊อบใช้เงินที่ได้รับจากอลิซและลูกค้าคนอื่น ๆ เขาก็ขยายสายโซ่ของธุรกรรมออกไป สมมติว่าบ๊อบจ่ายค่าจ้างให้กรูฟซึ่งเป็นนักออกแบบเว็บไซต์ของเขาสำหรับสร้างหน้าเว็บใหม่ สายโซ่ของธุรกรรมจะมีลักษณะดังนี้:</p>
<ul>
<li>ธุรกรรมจากโจถึงอลิซ: โจโอนบิตคอยน์ให้อลิซเพื่อการซื้อขายหรือจ่ายค่าบริการบางอย่าง</li>
<li>ธุรกรรมจากอลิซถึงบ๊อบ: อลิซโอนบิตคอยน์ให้บ๊อบเพื่อชำระค่าพอดแคสต์</li>
<li>ธุรกรรมจากบ๊อบถึงกรูฟ: บ๊อบโอนบิตคอยน์จากที่ได้รับจากอลิซให้กรูฟเพื่อจ่ายค่าจ้างออกแบบเว็บไซต์</li>
</ul>
<p>สายโซ่ของธุรกรรมนี้แสดงให้เห็นการเชื่อมต่อของธุรกรรมจากโจถึงอลิซและจากอลิซถึงบ๊อบต่อด้วยจากบ๊อบถึง กรูฟ โดยแต่ละธุรกรรมได้รับการบันทึกไว้ในบล็อกเชน ซึ่งช่วยให้ทุกคนสามารถตรวจสอบความถูกต้องของธุรกรรมในสายโซ่นี้ได้</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734788274465-YAKIHONNES3.png" alt="image"></p>
<p>ในบทนี้ เราได้เห็นวิธีที่ธุรกรรมสร้างสายโซ่ที่ถ่ายโอนมูลค่าจากเจ้าของหนึ่งไปยังอีกเจ้าของหนึ่ง นอกจากนี้เรายังได้ติดตามธุรกรรมของอลิซตั้งแต่เริ่มสร้างในกระเป๋าเงินของเธอ ผ่านเครือข่ายบิตคอยน์ไปจนถึงนักขุดที่บันทึกมันลงในบล็อกเชน และสำหรับในส่วนที่เหลือของหนังสือเล่มนี้ เราจะศึกษารายละเอียดเกี่ยวกับเทคโนโลยีที่เกี่ยวข้อง ไม่ว่าจะเป็นกระเป๋าเงิน, address, digital signature, network และกระบวนการขุดอย่างละเอียด</p>
]]></itunes:summary>
      <itunes:image href="https://image.nostr.build/5648ee8b923cd74f0d7f797a52aa66cff315a0e887e7683a2f9fbd72e6a81187.jpg"/>
      </item>
      
      <item>
      <title><![CDATA[Npub.pro เว็บไซต์ส่วนตัวที่ช่วยโชว์สิ่งที่คุณทำใน Nostr สู่โลกภายนอก]]></title>
      <description><![CDATA[อย่างที่ทราบกันอยู่แล้วว่า Nostr เป็นได้มากกว่า Note แล้วจะเป็นอย่างไรล่ะ ถ้า Note และลองฟอร์มต่าง ๆ ที่เราเคยเขียนกันมาสามารถกลายเป็นเว็บบอร์ดที่เราสามารถใช้เก็บผลงานและโชว์ให้กับคนอื่น ๆ ในโลกอินเตอร์เน็ตทั่วไปได้อีกด้วย]]></description>
             <itunes:subtitle><![CDATA[อย่างที่ทราบกันอยู่แล้วว่า Nostr เป็นได้มากกว่า Note แล้วจะเป็นอย่างไรล่ะ ถ้า Note และลองฟอร์มต่าง ๆ ที่เราเคยเขียนกันมาสามารถกลายเป็นเว็บบอร์ดที่เราสามารถใช้เก็บผลงานและโชว์ให้กับคนอื่น ๆ ในโลกอินเตอร์เน็ตทั่วไปได้อีกด้วย]]></itunes:subtitle>
      <pubDate>Wed, 18 Dec 2024 09:00:11 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/nasua-iwqexcymvwj5w-p/</link>
      <comments>https://learnbn.npub.pro/post/nasua-iwqexcymvwj5w-p/</comments>
      <guid isPermaLink="false">naddr1qq2kuctnw4sj662h29zhss6ed4t9w6342uk4qq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65w03vg7f</guid>
      <category></category>
      
        <media:content url="https://image.nostr.build/f3330ab80d2a4799df8759b946e0f10173d6bae017623bfa4272ec248e269ae9.jpg" medium="image"/>
        <enclosure 
          url="https://image.nostr.build/f3330ab80d2a4799df8759b946e0f10173d6bae017623bfa4272ec248e269ae9.jpg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qq2kuctnw4sj662h29zhss6ed4t9w6342uk4qq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65w03vg7f</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<blockquote>
<p>อย่างที่ทราบกันอยู่แล้วว่า Nostr เป็นได้มากกว่า Note แล้วจะเป็นอย่างไรล่ะ ถ้า Note และลองฟอร์มต่าง ๆ ที่เราเคยเขียนกันมาสามารถกลายเป็นเว็บบอร์ดที่เราสามารถใช้เก็บผลงานและโชว์ให้กับคนอื่น ๆ ในโลกอินเตอร์เน็ตทั่วไปได้อีกด้วย</p>
</blockquote>
<h2>Npub.pro คืออะไร ?</h2>
<p>Npub.pro เป็น Other stuff ตัวหนึ่งที่ช่วยแปลง note และ long form ต่าง ๆ ที่เราเคยได้ลงไว้ในโปรโตคอลของ Nostr และแปลงมันมาเป็นเว็บบอร์ดที่สวยสะอาดตา และมีธีมให้เลือกอีกหลากหลาย ซึ่งเหมาะสมมาก ๆ กับเหล่าครีเอเตอร์ต่าง ๆ สำหรับที่จะใช้มันในการโชว์ผลงาน ไม่ว่าจะเป็นสายถ่ายภาพ เก็บรวบรวมบทความ หรืออีกหลาย ๆ แง่มุมที่สามารถเกิดขึ้นได้</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734501549644-YAKIHONNES3.png" alt="image"></p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734501746979-YAKIHONNES3.png" alt="image"></p>
<p>นี่เองคือหนึ่งในตัวอย่างที่ผมได้ทำไว้เพื่อแพร่กระจายบทความต่าง ๆ ให้ออกไปสู่ผู้คนที่อาจจะไม่ได้รู้จักหรือใช้งาน Nostr อยู่</p>
<h3>แล้วมันทำงานอย่างไร ?</h3>
<p>Npub.pro นั้นจะทำการดึง Notes และ Long form ของเรามาจาก relay ต่าง ๆ ที่เราได้มีการเชื่อมต่อไว้ในบัญชีของเรา และทำการนำมาจัดรูปแบบใหม่ตามธีมที่เราได้เลือกไว้ และแสดงผลออกมามาในรูปแบบเว็บบอร์ด นอกจากนี้ยังมีการใส่ตัว nostr log-in เข้ามาเพื่อช่วยให้คนที่มีบัญชี nostr สามารถใช้บัญชีของตนในการ zap หรือ คอมเม้นได้ รวมทั้งยังอณุญาตให้ผู้ใช้ใส่ script เพิ่มเติมลงไปทั้งในส่วนหัวและท้ายของเว็บบอร์ดได้อีกด้วย ดังเช่น</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734502591203-YAKIHONNES3.png" alt="image"></p>
<p>ทั้งหมดที่กล่าวมาข้างต้นเป็นประสบการณ์ส่วนตัวของผมเองที่ได้มีการทดลองใช้งานมาระยะหนึ่ง และในส่วนต่อไป เราจะมาดูกันถึงวิธีการสร้างว่าเราต้องทำอย่างไร จึงจะมีเว็บไซต์สวย ๆ แบบนี้ได้</p>
<h2>วิธีการสร้าง</h2>
<h3>1. เข้าเว็บ Npub.pro</h3>
<p>หลังจากเข้ามาในเว็บไซต์ให้เรากด "try now"<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734511919965-YAKIHONNES3.png" alt="image"></p>
<h3>2. เลือกธีม</h3>
<p>จากนั้นจะมีธีมต่าง ๆ ขึ้นมาให้คุณเลือก ในจุดนี้ผมแนะนำว่าให้เลือกให้เหมาะสมกับผลงานของคุณ (สามารถเปลี่ยนได้ภายหลัง)<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734512111435-YAKIHONNES3.png" alt="image"></p>
<h3>3. ตั้งค่าส่วนอื่น ๆ</h3>
<p>หลังจากเลือกเสร็จเรียบร้อยเราต้องทำการใส่ title bio และอื่น ๆ ให้เรียบร้อยจากนั้นให้ทำการกด publish<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734512308362-YAKIHONNES3.png" alt="image"></p>
<p>เพียงแค่นี้คุณก็จะมีเว็บบอร์ดเจ๋ง ๆ ที่จะคอยอัพเดตอัตโนมัติเพมื่อคุณได้โพสต์บางอย่างลงบน Nostr ;)</p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<blockquote>
<p>อย่างที่ทราบกันอยู่แล้วว่า Nostr เป็นได้มากกว่า Note แล้วจะเป็นอย่างไรล่ะ ถ้า Note และลองฟอร์มต่าง ๆ ที่เราเคยเขียนกันมาสามารถกลายเป็นเว็บบอร์ดที่เราสามารถใช้เก็บผลงานและโชว์ให้กับคนอื่น ๆ ในโลกอินเตอร์เน็ตทั่วไปได้อีกด้วย</p>
</blockquote>
<h2>Npub.pro คืออะไร ?</h2>
<p>Npub.pro เป็น Other stuff ตัวหนึ่งที่ช่วยแปลง note และ long form ต่าง ๆ ที่เราเคยได้ลงไว้ในโปรโตคอลของ Nostr และแปลงมันมาเป็นเว็บบอร์ดที่สวยสะอาดตา และมีธีมให้เลือกอีกหลากหลาย ซึ่งเหมาะสมมาก ๆ กับเหล่าครีเอเตอร์ต่าง ๆ สำหรับที่จะใช้มันในการโชว์ผลงาน ไม่ว่าจะเป็นสายถ่ายภาพ เก็บรวบรวมบทความ หรืออีกหลาย ๆ แง่มุมที่สามารถเกิดขึ้นได้</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734501549644-YAKIHONNES3.png" alt="image"></p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734501746979-YAKIHONNES3.png" alt="image"></p>
<p>นี่เองคือหนึ่งในตัวอย่างที่ผมได้ทำไว้เพื่อแพร่กระจายบทความต่าง ๆ ให้ออกไปสู่ผู้คนที่อาจจะไม่ได้รู้จักหรือใช้งาน Nostr อยู่</p>
<h3>แล้วมันทำงานอย่างไร ?</h3>
<p>Npub.pro นั้นจะทำการดึง Notes และ Long form ของเรามาจาก relay ต่าง ๆ ที่เราได้มีการเชื่อมต่อไว้ในบัญชีของเรา และทำการนำมาจัดรูปแบบใหม่ตามธีมที่เราได้เลือกไว้ และแสดงผลออกมามาในรูปแบบเว็บบอร์ด นอกจากนี้ยังมีการใส่ตัว nostr log-in เข้ามาเพื่อช่วยให้คนที่มีบัญชี nostr สามารถใช้บัญชีของตนในการ zap หรือ คอมเม้นได้ รวมทั้งยังอณุญาตให้ผู้ใช้ใส่ script เพิ่มเติมลงไปทั้งในส่วนหัวและท้ายของเว็บบอร์ดได้อีกด้วย ดังเช่น</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734502591203-YAKIHONNES3.png" alt="image"></p>
<p>ทั้งหมดที่กล่าวมาข้างต้นเป็นประสบการณ์ส่วนตัวของผมเองที่ได้มีการทดลองใช้งานมาระยะหนึ่ง และในส่วนต่อไป เราจะมาดูกันถึงวิธีการสร้างว่าเราต้องทำอย่างไร จึงจะมีเว็บไซต์สวย ๆ แบบนี้ได้</p>
<h2>วิธีการสร้าง</h2>
<h3>1. เข้าเว็บ Npub.pro</h3>
<p>หลังจากเข้ามาในเว็บไซต์ให้เรากด "try now"<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734511919965-YAKIHONNES3.png" alt="image"></p>
<h3>2. เลือกธีม</h3>
<p>จากนั้นจะมีธีมต่าง ๆ ขึ้นมาให้คุณเลือก ในจุดนี้ผมแนะนำว่าให้เลือกให้เหมาะสมกับผลงานของคุณ (สามารถเปลี่ยนได้ภายหลัง)<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734512111435-YAKIHONNES3.png" alt="image"></p>
<h3>3. ตั้งค่าส่วนอื่น ๆ</h3>
<p>หลังจากเลือกเสร็จเรียบร้อยเราต้องทำการใส่ title bio และอื่น ๆ ให้เรียบร้อยจากนั้นให้ทำการกด publish<br><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1734512308362-YAKIHONNES3.png" alt="image"></p>
<p>เพียงแค่นี้คุณก็จะมีเว็บบอร์ดเจ๋ง ๆ ที่จะคอยอัพเดตอัตโนมัติเพมื่อคุณได้โพสต์บางอย่างลงบน Nostr ;)</p>
]]></itunes:summary>
      <itunes:image href="https://image.nostr.build/f3330ab80d2a4799df8759b946e0f10173d6bae017623bfa4272ec248e269ae9.jpg"/>
      </item>
      
      <item>
      <title><![CDATA[สรุป Mastering Bitcoin: Programming the Open Blockchain บทที่ 1]]></title>
      <description><![CDATA[ต้นฉบับมันแบบว่ายาวไปไม่อ่าน อ่านสรุปดีกว่า โอ๊ยกำอ่านสรุปแล้วปวดหัวกลับไปอ่านต้นฉบับละกานนนนนน]]></description>
             <itunes:subtitle><![CDATA[ต้นฉบับมันแบบว่ายาวไปไม่อ่าน อ่านสรุปดีกว่า โอ๊ยกำอ่านสรุปแล้วปวดหัวกลับไปอ่านต้นฉบับละกานนนนนน]]></itunes:subtitle>
      <pubDate>Sun, 01 Dec 2024 03:15:03 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/o2xy4r5lyvfqhaccoudz3/</link>
      <comments>https://learnbn.npub.pro/post/o2xy4r5lyvfqhaccoudz3/</comments>
      <guid isPermaLink="false">naddr1qq2k7vjcty69ydtv09tyvu2gv9pkxnm4v3drxq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65w9v352e</guid>
      <category></category>
      
        <media:content url="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1733022903046-YAKIHONNES3.jpg" medium="image"/>
        <enclosure 
          url="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1733022903046-YAKIHONNES3.jpg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qq2k7vjcty69ydtv09tyvu2gv9pkxnm4v3drxq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65w9v352e</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<h2>บทที่ 1: เกริ่นนำ</h2>
<h2>เกริ่นนำเรื่องราวของบิตคอยน์แบบกระทัดรัด</h2>
<p>บิตคอยน์ (Bitcoin) เป็นชุดแนวคิดและเทคโนโลยีที่เข้ามาผสมผสานรวมกันจนได้กลายเป็นระบบเงินสดอิเล็กทรอนิกส์ หน่วยเงินที่เรียกว่าบิตคอยน์นั้น ใช้เพื่อเก็บและส่งต่อมูลค่าให้กับผู้ใช้คนอื่น ๆ ในระบบ ผู้ใช้ทั้งระบบสื่อสารกันบนโปรโตคอลของบิตคอยน์ โดยผู้ใช้ส่วนใหญ่ก็เข้าถึงกันผ่านอินเตอร์เน็ต แต่ก็ไม่ได้หมายความว่าระบบนี้ไม่สามารถใช้เครือข่ายการสื่อสารรูปแบบอื่นได้ ซอฟต์แวร์ของโปรโตคอลนี้เป็นโอเพนซอร์สและสามารถรันได้บนอุปกรณ์คอมพิวเตอร์หลายประเภท เช่น แล็ปท็อปและสมาร์ทโฟน และสิ่งนี้เองที่ทำให้เทคโนโลยีนี้สามารถเข้าถึงได้ง่าย</p>
<p>ผู้ใช้งานสามารถส่งบิตคอยน์ให้กันผ่านเครือข่ายของบิตคอยน์เพื่อทำกิจกรรมต่าง ๆ เช่น ซื้อ-ขายแลกเปลี่ยนสินค้าและบริการ หรือใช้เพื่อแลกเปลี่ยนเป็นสกุลเงินต่าง ๆ ซึ่งถือว่าเหมาะสมเป็นอย่างมากสำหรับการใช้งานบนอินเทอร์เน็ต เพราะมีทั้งความรวดเร็ว ความปลอดภัย และยังข้อจำกัดเรื่องพรมแดน</p>
<p>ซึ่งบิตคอยน์นั้นแตกต่างจากสกุลเงินโดยทั่วไป เนื่องจากเป็นระบบเงินอิเล็กทรอนิกส์ จึงไม่มีเหรียญหรือธนบัตรจริง ๆ ให้ได้จับต้อง แต่คำว่าเหรียญที่มักใช้กันในสังคมของบิตคอยน์จะหมายถึงในธุรกรรมที่ผู้ใช้รายหนึ่งโอนมูลค่าไปยังผู้ใช้อีกรายหนึ่ง ผู้ใช้งานบิตคอยน์จะควบคุมคีย์ (Private Key) ที่ใช้พิสูจน์ความเป็นเจ้าของในบิตคอยน์นั้น ๆ ในเครือข่าย และด้วยคีย์นี้เองทำให้พวกเขาสามารถเซ็นชื่อในธุรกรรมเพื่อปลดล็อกมูลค่าและทำการส่งมันต่อไปยังผู้รับอีกรายหนึ่ง ซึ่งมักจะถูกเก็บอยู่ในกระเป๋าเงินดิจิทัล หรือสมาร์ทโฟนของผู้ใช้งาน การครอบครองคีย์ที่สามารถเซ็นชื่อในธุรกรรมได้เป็นสิ่งเดียวที่จำเป็นในการใช้จ่ายในระบบของบิตคอยน์ และนั่นเป็นเหตุผลที่ทำให้ความสามารถในการควบคุมบิตคอยน์อยู่ในมือผู้ใช้แต่ละคน</p>
<blockquote>
<p>เข้าใจว่าในบริบทนี้น่าจะหมายถึง Hot-wallet เพราะงั้นผมไม่ได้แนะนำให้เก็บคีย์คอมพิวเตอร์หรือมือถือนะครับ ส่วนถ้าคุณอยากทำก็เรื่องของคุณจ้าแนะนำเฉย ๆ อยากทำไรทำ</p>
</blockquote>
<p>บิตคอยน์นั้นเป็นระบบแบบกระจายศูนย์และทำงานแบบเพียร์-ทู-เพียร์ (Peer-to-Peer) หรือเอาภาษาบ้าน ๆ ว่า เป็นระบบการทำงานแบบบุคคลสู่บุลคลที่ไม่มีตัวกลางระหว่างการทำงาน ดังนั้นจึงไม่มีเซิร์ฟเวอร์กลางหรือจุดควบคุม บิตคอยน์นั้นถูกสร้างขึ้นโดยกระบวนการที่เรียกว่าการขุด ซึ่งเป็นการทำงานทางการคำนวณซ้ำ ๆ ที่อ้างอิงกับรายการธุรกรรมบิตคอยน์ล่าสุด (จริง ๆ ก็มี hash ของบล็อกก่อนหน้าด้วย) ซึ่งผู้ใช้งานบิตคอยน์ทุกคนสามารถที่จะขุดบิตคอยน์ได้ โดยใช้อุปกรณ์คอมพิวเตอร์ของตนเพื่อช่วยรักษาความปลอดภัยในธุรกรรม โดยทุก ๆ สิบนาทีโดยเฉลี่ยนั้น จะมีนักขุดคนหนึ่งที่ได้ช่วยเพิ่มความปลอดภัยให้กับธุรกรรมในอดีต และจะได้รับรางวัลเป็นบิตคอยน์ใหม่และค่าธรรมเนียมจากธุรกรรมชุดล่าสุด ซึ่งกระบวนการนี้ทำให้การออกสกุลเงินและการชำระธุรกรรมไม่จำเป็นต้องมีธนาคารกลาง</p>
<p>โปรโตคอลของบิตคอยน์ มีอัลกอรึทึมที่คอยควบคุมความยากง่ายในการการขุดให้อยู่ในระดับที่เหมาะสม โดยความยากง่ายในการขุดจะขึ้นจะถูกปรับตามระยะเวลาเฉลี่ยของการขุดในช่วงก่อนหน้านี้เพื่อให้การขุดนั้นมีโอกาสสำเร็จเฉลี่ยในทุก ๆ 10 นาที ไม่ว่ามีจำนวนผู้ขุดและการประมวลผลเท่าใดก็ตาม และนอกจากนี้เองโปรโตคอลของบิตคอยน์นั้นยังลดจำนวนของบิตคอยน์ที่นักขุดจะได้เป็นรางวัลลงเรื่อย ๆ ซึ่งจะทำให้บิตคอยน์ที่สร้างได้ในระบบนั้นมีไม่เกิน 21,000,000 ล้านบิตคอยน์ ซึ่งผลลัพธ์ที่ได้ก็คือ จำนวนบิตคอยน์ที่หมุนเวียนในระบบนั้นจะสามารถคาดเดาได้อย่างง่ายดาย ซึ่งอีกครึ่งหนึ่งของบิตคอยน์ที่เหลืออยู่จะถูกเพิ่มเข้าไปในระบบทุก ๆ 4 ปี และที่บล๊อกประมาณ  1,411,200 ซึ่งคาดว่าจะเกิดประมาณปี 2035 จะมีบิตคอยน์เป็นจำนวน 99 % ของที่สามารถเกิดขึ้นได้ในระบบ เนื่องจากอัตราการการผลิตของบิตคอยน์ที่น้อยลงเรื่อย ๆ ทำให้บิตคอยน์มีลักษณะของเงินฝืดในระยะยาว นอกจากนี้ยังไม่มีใครที่สามารถบังคับให้คุณรับบิตคอยน์ที่ถูกผลิตมานอกเหนือจากชุดกฎที่คุณเลือกได้</p>
<p>เบื้องหลังต่าง ๆ ของโปรโตคอลบิตคอยน์ที่ทำให้มันเป็น เครือข่ายแบบบุคคลถึงบุคคล และการคำนวณแบบกระจายศูนย์นั้น ถูกสร้างขึ้นมาบนพื้นฐานของงานวิจัยในด้านการเข้ารหัสและระบบกระจายศูนย์มาเนิ่นนานหลายทศวรรษ โดยมีการรวมเอานวัตกรรมสำคัญ ๆ 4 อย่างนี้มารวมเข้าด้วยกัน:</p>
<ul>
<li>เครือข่ายเพียร์ทูเพียร์ที่กระจายศูนย์ (ฺBitcoin protocol)</li>
<li>บัญชีธุรกรรมสาธารณะ (Blockchain)</li>
<li>ชุดของกฎในการตรวจสอบธุรกรรมอย่างอิสระและการออกสกุลเงิน ( consensus rules )</li>
<li>กลไกในการหาข้อตกลงร่วมกันทั่วโลกเกี่ยวกับบล็อกเชนที่ถูกต้อง (PoW algorithm)</li>
</ul>
<blockquote>
<p> ในมุมมองของนักพัฒนา นาย Andreas M. Antonopoulos and David A. Harding ( ไม่ใช่ผมจ้าา ถึงจะเห็นด้วยก็ตาม) พวกเขามองว่าบิตคอยน์นั้นคล้ายกับอินเทอร์เน็ตของเงิน เป็นเครือข่ายสำหรับการกระจายมูลค่าและการรักษาความเป็นเจ้าของสินทรัพย์ดิจิทัลผ่านการคำนวณแบบกระจายศูนย์ ซึ่งบิตคอยน์มีรายระเอียดเยอะกว่าที่พวกเขาเห็นในตอนแรกมาก ๆ</p>
</blockquote>
<p>ในบทนี้เองจะเป็นการอธิบายแนวคิด และคำศัพท์หลัก ๆ รวมทั้งการติดตั้งซอฟแวร์ต่าง ๆ ที่จำเป็นในการทอดลองใช้บิตคอยน์สำหรับทำธุรกรรมง่าย ๆ และสำหรับในบทถัดไป เราจะทำการดำดิ่งลงไปในเทคโนโลยีต่าง ๆ ที่ประกอบรวมกันเป็นบิตคอยน์ว่าทำไมมันถึงเป็นไปได้ และตรวจสอบการทำงานภายในของเครือข่ายและโปรโตคอล</p>
<h3>ก่อนการมาถึงของบิตคอยน์</h3>
<p>สกุลเงินดิจิทัลที่ใช้งานได้จริงในอดีตนั้นมักเกี่ยวข้องกับพัฒนาการในด้านการเข้ารหัส ซึ่งนั่นก็ไม่ได้แปลกอะไรหากเราพิจารณาถึงปัญหาพื้นฐานในการใช้ข้อมูลเพื่อแทนมูลค่าที่สามารถแลกเปลี่ยนเป็นสินค้าและบริการ โดยการที่เงินดิจิทัลจะถูกยอมรับได้นั้นมักจะต้องสามารถตอบคำถามทั้งสามข้อนี้ได้เสียก่อน:</p>
<ul>
<li>ฉันจะเชื่อได้อย่างไรว่าเงินนั้นเป็นของจริงและไม่ใช่ของปลอม?</li>
<li>ฉันจะเชื่อได้อย่างไรว่าเงินดิจิทัลสามารถใช้ได้เพียงครั้งเดียว (ปัญหาการใช้ซ้ำหรือ "double-spend")?</li>
<li>ฉันจะมั่นใจได้อย่างไรว่าไม่มีใครสามารถอ้างสิทธิ์ว่าเงินนี้เป็นของพวกเขาไม่ใช่ของฉัน?</li>
</ul>
<p>ผู้ที่ออกเงินกระดาษเองก็พยายามต่อสู้กับปัญหาการปลอมแปลงโดยการใช้เทคโนโลยีการพิมพ์ที่ซับซ้อนมากขึ้นเรื่อย ๆ และเงินกายภาพเองก็จัดการปัญหาการใช้ซ้ำได้ง่ายเพราะธนบัตรเดียวกันไม่สามารถอยู่ในสองที่พร้อมกันได้ แน่นอนละว่าเงินทั่วไปก็ถูกเก็บและส่งแบบดิจิทัลเช่นกัน ในกรณีเหล่านี้ ปัญหาการปลอมแปลงและการใช้ซ้ำจะถูกจัดการโดยการเคลียร์ธุรกรรมทางอิเล็กทรอนิกส์ทั้งหมดผ่านหน่วยงานกลางที่สามารถตรวจสอบสถานะของเงินได้ แต่สำหรับเงินดิจิทัลที่ไม่สามารถใช้หมึกพิเศษหรือแถบโฮโลแกรมได้ การเข้ารหัสจึงเป็นพื้นฐานสำคัญในการยืนยันความถูกต้องของการอ้างสิทธิ์ในมูลค่าของผู้ใช้ โดยเฉพาะอย่างยิ่ง การเซ็นชื่อดิจิทัลที่เข้ารหัสช่วยให้ผู้ใช้สามารถเซ็นชื่อในสินทรัพย์ดิจิทัลหรือธุรกรรมเพื่อยืนยันการเป็นเจ้าของสินทรัพย์นั้น ซึ่งสิ่งนี้เองยังสามารถใช้ในการแก้ปัญหาการใช้ซ้ำ (doble-spending) ได้</p>
<p>ศาสตร์ของการเข้ารหัสนั้นเริ่มเป็นที่แพร่หลายในช่วงปลายของทศวรรษที่ 1980 นักวิจัยหลายคนเริ่มพยายามใช้การเข้ารหัสเพื่อสร้างสกุลเงินดิจิทัล โดยโครงการเงินดิจิทัลในยุคแรก ๆ นั้นมักจะออกเงินดิจิทัลที่มีการสนับสนุนโดยสกุลเงินของชาติหรือโลหะมีค่าอย่างเช่น ทองคำ</p>
<p>ซึ่งแม้ว่าสกุลเงินดิจิทัลยุคแรกเหล่านี้จะทำงานได้ แต่ก็มีปัญหาที่การรวมศูนย์ของระบบ เนื่องจากมันทำให้ระบบเป็นเป้าหมายที่ง่ายต่อการโจมตีโดยรัฐบาลและเหล่าแฮกเกอร์ สกุลเงินดิจิทัลยุคแรกใช้ศูนย์กลางในการชำระธุรกรรมทั้งหมดเป็นระยะ ๆ เช่นเดียวกับระบบธนาคารทั่วไป เป็นที่น่าเสียดายที่สกุลเงินดิจิทัลเหล่านี้ส่วนใหญ่ถูกกำหนดเป้าหมายโดยรัฐบาลที่กังวลและมักจะถูกฟ้องร้องจนล้มเหลว บางส่วนล้มเหลวอย่างรวดเร็วเมื่อบริษัทผู้ก่อตั้งปิดตัวลงอย่างกะทันหัน และเพื่อให้สกุลเงินดิจิทัลมีความแข็งแกร่งต่อต้านการแทรกแซงจากศัตรู ไม่ว่าจะเป็นรัฐบาลที่ถูกกฎหมายหรืออาชญากรรม เราจึงจำเป็นต้องมีสกุลเงินดิจิทัลที่กระจายศูนย์ เพื่อป้องกันปัญหาดังกล่าว ซึ่งบิตคอยน์คือระบบแบบนั้น ระบบที่ถูกออกแบบให้กระจายศูนย์ และปราศจากอำนาจหรือจุดควบคุมกลางใด ๆ ที่สามารถถูกโจมตีหรือทำให้เสียหายได้</p>
<h2>ประวัติของบิตคอยน์</h2>
<p>บิตคอยน์ได้ปรากฏครั้งแรกในปี 2008 บนเอกสารที่มีชื่อว่า “Bitcoin: A Peer-to-Peer Electronic Cash System” ซึ่งถูกเขียนโดยบุคคลหรือกลุ่มคนนิรนามที่ใช้นามแฝงว่า ซาโตชิ นากาโมโตะ ซึ่งได้มีการนำนวัตกรรมหลาย ๆ อย่างมารวมเข้าด้วยกัน ไม่ว่าจะเป็นลายเซ็นดิจิทัล และ Hashcash มาสร้างระบบเงินสดอิเล็กทรอนิกส์ที่กระจายศูนย์อย่างสมบูรณ์ ซึ่งไม่ต้องพึ่งพาหน่วยงานกลางในการออกสกุลเงินหรือการชำระและตรวจสอบธุรกรรม โดยนวัตกรรมสำคัญคือการใช้ระบบคำนวณแบบกระจายศูนย์ (Proof-of-work) เพื่อทำสิ่งที่คล้าย ๆ กับการจับฉลากทุก ๆ 10 นาที ทำให้เครือข่ายที่กระจายศูนย์สามารถมีฉันทามติในสถานะของธุรกรรมได้ และสิ่งนี้เองยังสามารถแก้ไขปัญหาการทำธุรกรรมซ้ำซ้อน ซึ่งเป็นข้อบกพร่องของสกุลเงินดิจิทัลที่เคยต้องใช้หน่วยงานกลางในการตรวจสอบธุรกรรมทั้งหมดได้อีกด้วย</p>
<p>เครือข่ายของบิตคอยน์นั้นเริ่มต้นขึ้นในปี 2009 โดยอ้างอิงจากซอฟแวร์ที่เผยแพร่โดย ซาโตชิ และได้ถูกปรับปรุงโดยโปรแกรมเมอร์คนอื่น ๆ มากมายนับไม่ถ้วนมานับตั้งแต่นั้น จำนวนและกำลังของอุปกรณ์ที่ใช้ประมวลผล Proof of Work algorithm (การขุด) เองนั้นก็เพิ่มขึ้นอย่างมหาศาล จนในปัจจุบันนี้พลังการคำนวณรวมกันของเครือข่ายนี้มีมากกว่าจำนวนการคำนวณของซุปเปอร์คอมพิวเตอร์ชั้นนำของโลกทั้งหมดรวมกันเสียอีก ซึ่งสิ่งนี้เองได้ช่วยรักษาความปลอดภัยและความเสถียรของเครือข่ายของบิตคอยน์ได้เป็นอย่างดี</p>
<p>ซาโตชิ นากาโมโตะ ได้ทำการถอนตัวและหายตัวไปในเดือนเมษายนในปี 2011 และมอบหมายความรับผิดชอบในการพัฒนาโค้ดและเครือข่ายให้กับกลุ่มอาสาสมัครที่เติบโตขึ้นเรื่อย ๆ ซึ่งตัวตนของบุคคลหรือกลุ่มคนที่อยู่เบื้องหลังบิตคอยน์นั้นยังไม่เป็นที่รู้จัก แต่อย่างไรก็ตาม ไม่ว่าจะเป็นซาโตชิ นากาโมโตะ หรือใครหน้าไหนก็ตามก็ไม่สามารถควบคุมเครือข่ายของบิตคอยน์ได้ตามลำพัง เนื่องจากมันอยู่บนหลักการทางคณิตศาสตร์ที่โปร่งใส โค้ดโอเพนซอร์ส และฉันทามติจากผู้ที่เข้าร่วม โดยนวัตกรรมนี้ถือเป็นการเปลี่ยนแปลงครั้งใหญ่และได้ก่อให้เกิดวิทยาการใหม่ในด้านการคำนวณแบบกระจายศูนย์ เศรษฐศาสตร์ และเศรษฐมิติอีกด้วย</p>
<h3>การแก้ปัญหาในระบบคำนวณแบบกระจายศูนย์</h3>
<p>นวัตกรรมของซาโตชิ นากาโมโตะ ยังเป็นการแก้ไขปัญหาที่มีประสิทธิภาพและแปลกใหม่สำหรับปัญหาในระบบคำนวณแบบกระจายศูนย์ที่เรียกว่า "Byzantine Generals' Problem" ซึ่งปัญหานี้เกี่ยวข้องกับการพยายามทำให้ผู้เข้าร่วมหลายคนที่ไม่มีผู้นำสามารถตกลงกันในแผนการดำเนินการได้โดยการแลกเปลี่ยนข้อมูลในเครือข่ายที่ไม่น่าเชื่อถือและอาจถูกโจมตีได้ โดยการแก้ปัญหาของซาโตชินั้นได้ใช้แนวคิด proof of work เพื่อหาฉันทามติโดยไม่ต้องมีผู้ควบคุมที่น่าเชื่อถือ ถือเป็นความก้าวหน้าในด้านการคำนวณแบบกระจายศูนย์</p>
<h2>เปิดประตูสู่บิตคอยน์</h2>
<p>บิตคอยน์เป็นโปรโตคอลที่สามารถเข้าถึงได้ผ่านทางแอปพลิเคชันที่มีการรับรองโปรโตคอลนี้ Bitcoin wallet นั้นเป็นช่องทางหลักที่ผู้ใช้งานส่วนใหญ่เลือกใช้เพื่อเข้าถึงโปรโตคอลของบิตคอยน์ เช่นเดียวกันกับที่ผู้ใช้งานอินเตอร์เน็ตส่วนใหญ่ใช้เว็บบราวเซอร์เป็นช่องทางในการเข้าถึงโปรโตคอลอย่าง HTTP นั่นเอง Bitcoin wallet เองก็มีหลากหลายยี่ห้อเฉกเช่นเดียวกับเว็บบราวเซอร์ อาทิเช่น chorme, safari, firefox ฯลฯ Bitcoin wallet เองก็เช่นกัน แต่ละยี่ห้อเองก็มีความแตกต่างกันในด้านต่าง ๆ ไม่ว่าจะเป็นในด้านคุณภาพ ประสิทธิภาพ ความปลอดภัย ความเป็นส่วนตัว และความน่าเชื่อถือ อีกทั้งยังมี Bitcoin wallet ที่ถูกสร้างขึ้นมาคู่กับโปรโตคอลของบิตคอยน์อย่าง “Bitcoin Core” ซึ่งมีการพัฒนาต่อมาจากเวอร์ชันที่เขียนโดยซาโตชิ</p>
<h3>การเลือก Bitcoin wallet</h3>
<p>Bitcoin wallet เป็นหนึ่งในประเภทของแอปพลิเคชันที่มีการพัฒนาอย่างต่อเนื่องมากที่สุดในระบบนิเวศของบิตคอยน์ และแน่นอนว่ามีการแข่งขันกันสูงที่สุดด้วย อาจมี Bitcoin wallet ใหม่ ๆ ที่กำลังพัฒนาอยู่ในขณะนี้ Bitcoin wallet เก่า ๆ บางตัวจากปีที่แล้วก็อาจไม่มีการพัฒนาอย่างต่อเนื่องอีกต่อไป Bitcoin wallet หลาย ๆ ตัวเน้นไปที่แพลตฟอร์มหรือการใช้งานเฉพาะ และบางตัวเหมาะสำหรับผู้เริ่มต้น ในขณะที่บางตัวเต็มไปด้วยฟีเจอร์สำหรับผู้ใช้ขั้นสูง การเลือก Bitcoin wallet นั้นจึงขึ้นอยู่กับความต้องการและระดับความเชี่ยวชาญของผู้ใช้ ดังนั้นการที่เราจะแนะนำยี่ห้อหรือ Bitcoin wallet เฉพาะจึงอาจจะไม่เกิดประโยชน์เท่าไหร่ แต่อย่างไรก็ตาม เราสามารถแบ่งประเภท Bitcoin wallet ได้ตามแพลตฟอร์มและการใช้งานได้ดังนี้</p>
<h4>ประเภทของ Bitcoin wallet</h4>
<ul>
<li><strong>Desktop wallet:</strong> กระเป๋าเงินแบบเดสก์ท็อปเป็น Bitcoin wallet ประเภทแรกที่ถูกพัฒนาขึ้นและผู้ใช้ส่วนใหญ่มักจะเลือกใช้ Bitcoin wallet ประเภทนี้เพราะฟีเจอร์ของมัน เช่นความความเป็นอิสระในการใช้งาน ความสามารถในการควบคุมบิตคอยน์ในกระเป๋า แต่อย่างไรก็ตาม การใช้งานบนระบบปฏิบัติการทั่วไป อย่างเช่น Windows และ macOS อาจมีข้อเสียด้านความปลอดภัย เนื่องจากแพลตฟอร์มเหล่านี้มักไม่มีความปลอดภัยเพียงพอและอาจถูกตั้งค่ามาอย่างไม่เหมาะสม </li>
<li><strong>Mobile wallet:</strong> กระเป๋าเงินแบบมือถือเป็น Bitcoin wallet ประเภทที่พบเจอได้มากที่สุด โดยทำงานบนระบบปฏิบัติการสมาร์ทโฟน เช่น Apple iOS และ Android กระเป๋าเงินเหล่านี้มักเป็นตัวเลือกที่ดีสำหรับผู้ใช้ใหม่ เพราะออกแบบมาให้ใช้งานง่ายและสะดวก นอกจากนี้ยังมีกระเป๋าเงินมือถือที่มีฟีเจอร์ครบครันสำหรับผู้ใช้ที่มีความเชี่ยวชาญ แต่เพื่อหลีกเลี่ยงการดาวน์โหลดและจัดเก็บข้อมูลปริมาณมาก กระเป๋าเงินมือถือส่วนใหญ่จะดึงข้อมูลจากเซิร์ฟเวอร์ระยะไกล ซึ่งอาจลดความเป็นส่วนตัวของผู้ใช้เนื่องจากต้องเปิดเผยข้อมูลเกี่ยวกับ address และจำนวนบิตคอยน์ Bitcoin ต่อบุคคลที่สาม</li>
<li><strong>Web wallet:</strong> กระเป๋าเงินแบบเว็บสามารถเข้าถึงได้ผ่านเว็บเบราว์เซอร์และเก็บกระเป๋าเงินของผู้ใช้ไว้บนเซิร์ฟเวอร์ที่บุคคลที่สามเป็นเจ้าของ คล้ายกับบริการอีเมลบนเว็บที่พึ่งพาเซิร์ฟเวอร์ของบุคคลที่สามโดยสมบูรณ์ โดยบางบริการใช้โค้ดฝั่งไคลเอนต์ที่ทำงานในเบราว์เซอร์ของผู้ใช้ และเพื่อให้ผู้ใช้สามารถควบคุมคีย์ของบิตคอยน์ได้เอง แต่การพึ่งพาเซิร์ฟเวอร์ยังคงส่งผลกระทบต่อความเป็นส่วนตัว อย่างไรก็ตาม บริการส่วนใหญ่จะควบคุมคีย์ของบิตคอยน์แทนผู้ใช้เพื่อแลกกับความสะดวกสบาย เราจึงไม่แนะนำให้เก็บ <strong>บิตคอยน์จำนวนมากบนระบบของบุคคลที่สาม</strong></li>
<li><strong>Hardware Signing Devices:</strong> อุปกรณ์สำหรับเซ็นดิจิทัลเป็นอุปกรณ์ที่สามารถจัดเก็บคีย์และเซ็นธุรกรรมโดยใช้ฮาร์ดแวร์และเฟิร์มแวร์เฉพาะทาง ซึ่งโดยทั่วไปแล้วจะเชื่อมต่อกับกระเป๋าเงินเดสก์ท็อป มือถือ หรือเว็บ ผ่านสาย USB การสื่อสารระยะใกล้ (NFC) หรือกล้องที่รองรับ QR code แต่เนื่องจากการดำเนินการที่เกี่ยวข้องกับบิตคอยน์ ทั้งหมดถูกจัดการบนฮาร์ดแวร์เฉพาะ อุปกรณ์เหล่านี้จึงปลอดภัยจากการโจมตีหลายรูปแบบ อย่างไรก็ตาม อุปกรณ์เซ็นดิจิทัลมักถูกเรียกว่า hardware wallet แต่ต้องใช้งานร่วมกับกระเป๋าเงินที่มีฟีเจอร์ครบครันเพื่อส่งและรับธุรกรรม ความปลอดภัยและความเป็นส่วนตัวที่ได้จากกระเป๋าเงินที่ใช้งานร่วมกันก็มีบทบาทสำคัญต่อความปลอดภัยและความเป็นส่วนตัวโดยรวมของผู้ใช้อุปกรณ์เซ็นดิจิทัล</li>
</ul>
<h4>ประเภทของการเชื่อมต่อกับโปรโตคอลของบิตคอยน์</h4>
<ul>
<li><strong>Full node:</strong> บิตคอยน์ฟลูโหนดเป็นโปรแกรมที่ตรวจสอบความถูกต้องของประวัติธุรกรรมทั้งหมดของบิตคอยน์ (ทุกธุรกรรมที่เคยเกิดขึ้นโดยผู้ใช้ทุกคน) และนอกจากนี้ บิตคอยน์ฟลูโหนดยังสามารถเลือกเก็บข้อมูลธุรกรรมที่ได้รับการตรวจสอบแล้วก่อนหน้า และให้บริการข้อมูลแก่โปรแกรมบิตคอยน์อื่น ๆ ได้ ไม่ว่าจะเป็นบนคอมพิวเตอร์เดียวกันหรือผ่านอินเทอร์เน็ต แต่แม้ว่าบิตคอยน์ฟลูโหนดเองก็ใช้ทรัพยากรคอมพิวเตอร์ในปริมาณมาก (​ประมาณเท่ากับการดูวิดีโอสตรีมมิ่งหนึ่งชั่วโมงต่อวันสำหรับธุรกรรมบิตคอยน์ในแต่ละวัน) บิตคอยน์ฟลูโหนดเองก็มอบความเป็นอิสระอย่างสมบูรณ์แก่ผู้ใช้</li>
<li><strong>Lightweight Client:</strong> lightweight client หรือที่เรียกกันอีกชื่อว่าไคลเอนต์การตรวจสอบการชำระเงินแบบง่าย (Simplified-Payment-Verification: SPV) ซึ่งจะเชื่อมต่อกับโหนดแบบเต็มหรือเซิร์ฟเวอร์ระยะไกลอื่น ๆ เพื่อรับและส่งข้อมูลธุรกรรมของบิตคอยน์แต่เก็บกระเป๋าเงินของผู้ใช้ไว้ในเครื่อง โดยสามารถตรวจสอบธุรกรรมที่ได้รับบางส่วน และสร้างธุรกรรมขาออกอย่างอิสระอีกด้วย</li>
<li><strong>ไคลเอนต์ API ของบุคคลที่สาม (Third-Party API Client):</strong> ไคลเอนต์ API ของบุคคลที่สามเป็นโปรแกรมที่เชื่อมต่อกับระบบบิตคอยน์ผ่าน API ของบุคคลที่สาม แทนที่จะเชื่อมต่อกับเครือข่ายบิตคอยน์โดยตรง กระเป๋าเงินนี้อาจถูกจัดเก็บโดยผู้ใช้เองหรือบนเซิร์ฟเวอร์ของบุคคลที่สาม แต่ไคลเอนต์จะต้องไว้วางใจเซิร์ฟเวอร์ระยะไกลในการให้ข้อมูลที่ถูกต้องและปกป้องความเป็นส่วนตัวของตน</li>
</ul>
<blockquote>
<p>บิตคอยน์เป็นเครือข่ายแบบเพียร์ทูเพียร์(Peer-to-Peer หรือ P2P) โดยที่บิตคอยน์ฟลูโหนด ทำหน้าที่เป็นเพียร์ในเครือข่าย เพียร์แต่ละตัวจะตรวจสอบความถูกต้องของธุรกรรมที่ยืนยันแล้วทุกธุรกรรมอย่างอิสระ และสามารถให้ข้อมูลที่เชื่อถือได้แก่ผู้ใช้ Lightweight Wallets และซอฟต์แวร์อื่น ๆ เองก็เป็นลูกข่ายที่ต้องพึ่งพาเพียร์หนึ่งหรือหลายตัวในการรับข้อมูลที่ถูกต้อง ไคลเอนต์สามารถตรวจสอบข้อมูลบางส่วนที่ได้รับเพิ่มเติมและเชื่อมต่อกับเพียร์หลายตัวเพื่อลดการพึ่งพาเพียร์ตัวเดียว แต่ในท้ายที่สุดความปลอดภัยของไคลเอนต์ยังคงขึ้นอยู่กับความน่าเชื่อถือของเพียร์ที่เชื่อมต่อด้วย</p>
</blockquote>
<h4>ใครควบคุมคีย์</h4>
<p>อีกหนึ่งในประเด็นสำคัญที่ควรพิจารณาเพิ่มเติมคือใครเป็นผู้ควบคุมคีย์ (Private key) เนื่องจากเป็นสิ่งที่มีบทบาทสำคัญในการควบคุมการเข้าถึงบิตคอยน์ โดยคีย์เหล่านี้เองเปรียบเสมือน PIN ที่ยาวมาก ซึ่งหากคุณเป็นผู้ควบคุมคีย์ของคุณเองด้วยตัวเอง คุณก็เป็นผู้ควบคุมบิตคอยน์ของคุณด้วยเช่นกัน แต่หากไม่ใช่ ก็จะแปลว่ากุญแจเหล่านั้นจะถูกดูแลโดยบุคคลที่สาม ซึ่งจะเป็นผู้จัดการเงินของคุณในนามของคุณ</p>
<p>ซอฟแวร์ในการจัดการกุญแจนั้นถูกแบ่งออกเป็นสองประเภทหลัก ๆ คือ wallet ที่คุณจำเป็นต้องดูแลคีย์ของตัวเองและ บัญชีที่มีผู้ดูแล (Custodian Accounts) ซึ่งจะมีบุคคลที่สามเป็นผู้ควบคุมกุญแจ </p>
<blockquote>
<p>“Your keys, your coins. Not your keys, not your coins.”</p>
</blockquote>
<h3>มาอยู่ตัวอย่างเพื่อความเข้าใจที่มาขึ้นกันเถอะ</h3>
<p>สมมุติว่าอลิซเป็นผู้ใช้งานที่ไม่ได้เชี่ยวชาญด้านเทคนิค และเพิ่งได้ยินเกี่ยวกับบิตคอยน์จากเพื่อนสนิทของเขา โจ ระหว่างปาร์ตี้ โจกำลังอธิบายเกี่ยวกับบิตคอยน์อย่างกระตือรือร้นให้ทุกคนฟังและสาธิตวิธีการใช้งานต่าง ๆ ให้ดู อลิซเองได้มีความสนใจในบิตคอยน์หลังจากได้ฟังโจอธิบาย จึงได้ถามโจว่าเธอจะเริ่มต้นใช้งานบิตคอยน์ได้อย่างไร โจจึงแนะนำให้อลิซดาวน์โหลด Mobile wallet ตัวโปรดของเขาเนื่องจากมันเหมาะสมกับมือใหม่ อลิซจึงดาวน์โหลดและติดตั้งแอปพลิเคชันกระเป๋าเงินที่โจแนะนำบนโทรศัพท์ของเธอ</p>
<p>เมื่ออลิซเปิดแอปพลิเคชันครั้งแรก เธอได้เลือกสร้างกระเป๋าใหม่และเนื่องจากกระเป๋าที่เธอเลือกนั้นเป็นแบบที่ไม่ได้อยู่ภายใต้การควบคุมบุคคลที่สาม (Noncustodial Wallet) อลิซจึงเป็นผู้ควบคุมคีย์เพียงคนเดียว ซึ่งหมายความว่าเธอต้องรับผิดชอบในการสำรองข้อมูลด้วยตัวของเธอเอง และหากเธอได้ทำคีย์สูญหายไป เธอจะไม่สามารถเข้าถึงบิตคอยน์ของเธอได้อีกไปตลอดกาล และเพื่อเพื่อช่วยในเรื่องนี้ Bitcoin wallet ต่าง ๆ จึงมักจะสร้างรหัสการกู้คืน (Recovery Code) ให้ซึ่งสามารถใช้ในการกู้คืน Bitcoin wallet อันนั้น ๆ</p>
<h4>Recovery Code (รหัสในการกู้คืน)</h4>
<p>Bitcoin wallet แบบที่ไม่ได้อยู่ภายใต้การควบคุมของบุคคลที่สามนั้นส่วนใหญ่จะให้รหัสการกู้คืนแก่ผู้ใช้งานเพื่อสำรองข้อมูล และรหัสการกู้คืนนี้มักประกอบด้วยตัวเลข ตัวอักษร หรือคำที่ถูกเลือกแบบสุ่มโดยซอฟต์แวร์ และใช้เป็นพื้นฐานสำหรับการสร้าง Bitcoin wallet โดยแต่ละยี่ห้อก็อาจมีความแตกต่างกัน เช่น</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1733022493439-YAKIHONNES3.png" alt="image"></p>
<blockquote>
<p>รหัสการกู้คืนมักเรียกว่า "mnemonic" หรือ "mnemonic phrase" หรือในภาษาไทยว่าวลีช่วยจำ ซึ่งบ่งบอกว่าคุณควรจดจำวลีนั้น แต่การจดวลีนี้ลงบนกระดาษใช้เวลาน้อยกว่าและมักจะเชื่อถือได้มากกว่าความจำของคนส่วนใหญ่ เพราะฉนั้นผมเลยแนะนำว่าจดเถอะ จะได้ไม่เกิดปัญหาที่ไม่คาดคิดในอนาคต</p>
</blockquote>
<p>หาก bitcoin wallet ของอลิซมีปัญหา เธอสามารถดาวน์โหลดซอฟแวร์ใหม่และใส่รหัสในการกู้คืนลงไป เพื่อสร้างฐานข้อมูลของ bitcoin wallet ใหม่ที่บันทึกธุรกรรมบนเชนทั้งหมดที่เธอเคยรับหรือส่ง แต่อย่างไรก็ตาม การกู้คืนจากการใช้รหัสการกู้คืนเพียงอย่างเดียวนั้นอาจจะไม่สามารถกู้คืนข้อมูลเพิ่มเติมที่อลิซเคยบันทึกไว้ใน wallet นั้น ๆ ได้ เช่น ป้ายกำกับที่เธอเชื่อมโยงกับที่อยู่หรือธุรกรรมต่าง ๆ แม้ว่าการสูญเสียข้อมูลเมตานี้จะไม่สำคัญเท่ากับการสูญเสียเงิน แต่ก็ยังมีความสำคัญในบางแง่มุม เช่น หากคุณต้องตรวจสอบรายการธนาคารหรือบัตรเครดิตเก่า แต่ชื่อของผู้ที่คุณชำระเงินหรือผู้ที่จ่ายเงินให้คุณถูกลบออกไป ดังนั้นเพื่อป้องกันการสูญเสียข้อมูลเมตา wallet หลาย ๆ ยี่ห้อจึงมีฟีเจอร์สำรองข้อมูลเพิ่มเติมนอกเหนือจากรหัสการกู้คืน</p>
<p>สำหรับ wallet บางประเภทนั้น ฟีเจอร์สำรองข้อมูลเพิ่มเติมนี้ถือว่ามีความสำคัญมาก เนื่องจากการชำระเงินเงินด้วยบิตคอยน์จำนวนมากในปัจจุบันทำผ่านเทคโนโลยีที่อยู่นอกเชน (Offchain) ซึ่งธุรกรรมไม่ได้ถูกบันทึกลงในบล็อกเชนสาธารณะ เนื่องจากการชำระเงินแบบนี้ช่วยลดค่าใช้จ่ายของผู้ใช้และเพิ่มความเป็นส่วนตัวได้บ้าง แต่นั่นก็หมายความว่ากลไกอย่างรหัสการกู้คืนที่พึ่งพาข้อมูลบนเชนไม่สามารถรับประกันการกู้คืนบิตคอยน์ทั้งหมดของผู้ใช้ได้ ดังนั้นสำหรับแอปพลิเคชันที่รองรับการใช้งาน Offchain การสำรองข้อมูลฐานข้อมูล wallet บ่อยครั้งจึงเป็นสิ่งที่มีความสำคัญมาก</p>
<p>นอกจากนี้ เมื่อได้รับบิตคอยน์ครั้งแรกใน moblie wallet หลาย ๆ wallet มักจะตรวจสอบอีกครั้งว่าคุณได้สำรองรหัสการกู้คืนไว้อย่างปลอดภัยแล้ว การตรวจสอบนี้อาจเป็นเพียงการแจ้งเตือน หรืออาจถึงขั้นให้ผู้ใช้ป้อนรหัสนั้นซ้ำด้วยตัวเอง</p>
<blockquote>
<p><em>คำเตือน</em>  แม้ว่า Bitcoin Wallet หลาย ๆ ตัวอาจจะมีการให้คุณต้องกรอกรหัสในการกู้คืนใหม่ในบางกรณี แต่มันก็มักจะมีแอปพลิเคชันมัลแวร์จำนวนมากที่เลียนแบบการออกแบบของ wallet ต่าง ๆ โดยมันจะบังคับให้คุณป้อนรหัสการกู้คืน จากนั้นมันจะส่งรหัสที่ป้อนไปยังผู้พัฒนามัลแวร์เพื่อขโมยบิตคอยน์ของคุณ นี่เปรียบเสมือนเว็บไซต์ฟิชชิงที่พยายามหลอกให้คุณให้รหัสผ่านธนาคารของคุณ สำหรับ Bitcoin wallet ส่วนใหญ่ เวลาที่พวกเขาจะขอรหัสการกู้คืนคือในระหว่างการตั้งค่าเริ่มต้น (ก่อนที่คุณจะได้รับบิตคอยน์) และระหว่างการกู้คืน (หลังจากที่คุณสูญเสียการเข้าถึง wallet เดิม) หากแอปพลิเคชันขอรหัสการกู้คืนในช่วงเวลาอื่น คุณควรปรึกษาผู้เชี่ยวชาญเพื่อให้แน่ใจว่าคุณไม่ได้ตกเป็นเหยื่อของการฟิชชิง </p>
</blockquote>
<h4>Bitcoin Addresses (ที่อยู่ในการรับหรือส่งบิตคอยน์)</h4>
<p>ในตอนนี้อลิซพร้อมแล้วสำหรับการสร้าง Bitcoin wallet ใหม่ของเธอ Bitcoin wallet ที่เธอเลือกได้ทำการสร้าง private key แบบสุ่มให้เธอ ซึ่งจะเชื่อมโยงกับ Bitcoin Address ทั้งหมดที่มีใน Bitcoin wallet ของเธอ แต่ ณ ขณะนี้ยังไม่มีใครรู้ Bitcoin address ของเธอ (แม้แต่ Bitcoin network ก็ไม่รู้) นอกจากตัวเธอเอง Bitcoin address เหล่านี้เป็นเพียงตัวเลขที่เชื่อมโยงกับ Private key ของเธอ ซึ่งเธอสามารถใช้ควบคุมการเข้าถึง Bitcoin ใดกระเป๋าได้ Bitcoin address เหล่านี้ถูกสร้างขึ้นโดยอิสระจากกระเป๋าของเธอโดยไม่ต้องอ้างอิงหรือเชื่อมต่อกับบริการใด ๆ</p>
<p>คำแนะนำ: Bitcoin address และ Invoice นั้นมีหลากหลายรูปแบบที่แตกต่างกัน และทั้งหมดนี้สามารถแชร์ให้กับคนอื่น ๆ ได้ เพื่อเป็นการอณุญาติให้พวกเขาส่งบิตคอยน์เข้ามาในกระเป๋าคุณตรง ๆ คุณสามารถแชร์ Bitcoin address และ Invoice ให้คนอื่นได้โดยไม่ต้องกังวลเกี่ยวกับความปลอดภัยของบิตคอยน์ของคุณ เนื่องจากผู้ที่รู้ Bitcion address ของคุณไม่สามารถถอนเงินออกจาก address นั้น ๆ ได้แม้เขาจะสามารถรู้จำนวนเงินใน address นั้น ๆ ก็ตาม เพราะฉะนั้นเพื่อปกป้องความเป็นส่วนตัวของคุณ คุณจึงควรสร้าง Invoice จาก Bitcoin address ใหม่ทุกครั้งที่จะส่งให้ผู้อื่น</p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<h2>บทที่ 1: เกริ่นนำ</h2>
<h2>เกริ่นนำเรื่องราวของบิตคอยน์แบบกระทัดรัด</h2>
<p>บิตคอยน์ (Bitcoin) เป็นชุดแนวคิดและเทคโนโลยีที่เข้ามาผสมผสานรวมกันจนได้กลายเป็นระบบเงินสดอิเล็กทรอนิกส์ หน่วยเงินที่เรียกว่าบิตคอยน์นั้น ใช้เพื่อเก็บและส่งต่อมูลค่าให้กับผู้ใช้คนอื่น ๆ ในระบบ ผู้ใช้ทั้งระบบสื่อสารกันบนโปรโตคอลของบิตคอยน์ โดยผู้ใช้ส่วนใหญ่ก็เข้าถึงกันผ่านอินเตอร์เน็ต แต่ก็ไม่ได้หมายความว่าระบบนี้ไม่สามารถใช้เครือข่ายการสื่อสารรูปแบบอื่นได้ ซอฟต์แวร์ของโปรโตคอลนี้เป็นโอเพนซอร์สและสามารถรันได้บนอุปกรณ์คอมพิวเตอร์หลายประเภท เช่น แล็ปท็อปและสมาร์ทโฟน และสิ่งนี้เองที่ทำให้เทคโนโลยีนี้สามารถเข้าถึงได้ง่าย</p>
<p>ผู้ใช้งานสามารถส่งบิตคอยน์ให้กันผ่านเครือข่ายของบิตคอยน์เพื่อทำกิจกรรมต่าง ๆ เช่น ซื้อ-ขายแลกเปลี่ยนสินค้าและบริการ หรือใช้เพื่อแลกเปลี่ยนเป็นสกุลเงินต่าง ๆ ซึ่งถือว่าเหมาะสมเป็นอย่างมากสำหรับการใช้งานบนอินเทอร์เน็ต เพราะมีทั้งความรวดเร็ว ความปลอดภัย และยังข้อจำกัดเรื่องพรมแดน</p>
<p>ซึ่งบิตคอยน์นั้นแตกต่างจากสกุลเงินโดยทั่วไป เนื่องจากเป็นระบบเงินอิเล็กทรอนิกส์ จึงไม่มีเหรียญหรือธนบัตรจริง ๆ ให้ได้จับต้อง แต่คำว่าเหรียญที่มักใช้กันในสังคมของบิตคอยน์จะหมายถึงในธุรกรรมที่ผู้ใช้รายหนึ่งโอนมูลค่าไปยังผู้ใช้อีกรายหนึ่ง ผู้ใช้งานบิตคอยน์จะควบคุมคีย์ (Private Key) ที่ใช้พิสูจน์ความเป็นเจ้าของในบิตคอยน์นั้น ๆ ในเครือข่าย และด้วยคีย์นี้เองทำให้พวกเขาสามารถเซ็นชื่อในธุรกรรมเพื่อปลดล็อกมูลค่าและทำการส่งมันต่อไปยังผู้รับอีกรายหนึ่ง ซึ่งมักจะถูกเก็บอยู่ในกระเป๋าเงินดิจิทัล หรือสมาร์ทโฟนของผู้ใช้งาน การครอบครองคีย์ที่สามารถเซ็นชื่อในธุรกรรมได้เป็นสิ่งเดียวที่จำเป็นในการใช้จ่ายในระบบของบิตคอยน์ และนั่นเป็นเหตุผลที่ทำให้ความสามารถในการควบคุมบิตคอยน์อยู่ในมือผู้ใช้แต่ละคน</p>
<blockquote>
<p>เข้าใจว่าในบริบทนี้น่าจะหมายถึง Hot-wallet เพราะงั้นผมไม่ได้แนะนำให้เก็บคีย์คอมพิวเตอร์หรือมือถือนะครับ ส่วนถ้าคุณอยากทำก็เรื่องของคุณจ้าแนะนำเฉย ๆ อยากทำไรทำ</p>
</blockquote>
<p>บิตคอยน์นั้นเป็นระบบแบบกระจายศูนย์และทำงานแบบเพียร์-ทู-เพียร์ (Peer-to-Peer) หรือเอาภาษาบ้าน ๆ ว่า เป็นระบบการทำงานแบบบุคคลสู่บุลคลที่ไม่มีตัวกลางระหว่างการทำงาน ดังนั้นจึงไม่มีเซิร์ฟเวอร์กลางหรือจุดควบคุม บิตคอยน์นั้นถูกสร้างขึ้นโดยกระบวนการที่เรียกว่าการขุด ซึ่งเป็นการทำงานทางการคำนวณซ้ำ ๆ ที่อ้างอิงกับรายการธุรกรรมบิตคอยน์ล่าสุด (จริง ๆ ก็มี hash ของบล็อกก่อนหน้าด้วย) ซึ่งผู้ใช้งานบิตคอยน์ทุกคนสามารถที่จะขุดบิตคอยน์ได้ โดยใช้อุปกรณ์คอมพิวเตอร์ของตนเพื่อช่วยรักษาความปลอดภัยในธุรกรรม โดยทุก ๆ สิบนาทีโดยเฉลี่ยนั้น จะมีนักขุดคนหนึ่งที่ได้ช่วยเพิ่มความปลอดภัยให้กับธุรกรรมในอดีต และจะได้รับรางวัลเป็นบิตคอยน์ใหม่และค่าธรรมเนียมจากธุรกรรมชุดล่าสุด ซึ่งกระบวนการนี้ทำให้การออกสกุลเงินและการชำระธุรกรรมไม่จำเป็นต้องมีธนาคารกลาง</p>
<p>โปรโตคอลของบิตคอยน์ มีอัลกอรึทึมที่คอยควบคุมความยากง่ายในการการขุดให้อยู่ในระดับที่เหมาะสม โดยความยากง่ายในการขุดจะขึ้นจะถูกปรับตามระยะเวลาเฉลี่ยของการขุดในช่วงก่อนหน้านี้เพื่อให้การขุดนั้นมีโอกาสสำเร็จเฉลี่ยในทุก ๆ 10 นาที ไม่ว่ามีจำนวนผู้ขุดและการประมวลผลเท่าใดก็ตาม และนอกจากนี้เองโปรโตคอลของบิตคอยน์นั้นยังลดจำนวนของบิตคอยน์ที่นักขุดจะได้เป็นรางวัลลงเรื่อย ๆ ซึ่งจะทำให้บิตคอยน์ที่สร้างได้ในระบบนั้นมีไม่เกิน 21,000,000 ล้านบิตคอยน์ ซึ่งผลลัพธ์ที่ได้ก็คือ จำนวนบิตคอยน์ที่หมุนเวียนในระบบนั้นจะสามารถคาดเดาได้อย่างง่ายดาย ซึ่งอีกครึ่งหนึ่งของบิตคอยน์ที่เหลืออยู่จะถูกเพิ่มเข้าไปในระบบทุก ๆ 4 ปี และที่บล๊อกประมาณ  1,411,200 ซึ่งคาดว่าจะเกิดประมาณปี 2035 จะมีบิตคอยน์เป็นจำนวน 99 % ของที่สามารถเกิดขึ้นได้ในระบบ เนื่องจากอัตราการการผลิตของบิตคอยน์ที่น้อยลงเรื่อย ๆ ทำให้บิตคอยน์มีลักษณะของเงินฝืดในระยะยาว นอกจากนี้ยังไม่มีใครที่สามารถบังคับให้คุณรับบิตคอยน์ที่ถูกผลิตมานอกเหนือจากชุดกฎที่คุณเลือกได้</p>
<p>เบื้องหลังต่าง ๆ ของโปรโตคอลบิตคอยน์ที่ทำให้มันเป็น เครือข่ายแบบบุคคลถึงบุคคล และการคำนวณแบบกระจายศูนย์นั้น ถูกสร้างขึ้นมาบนพื้นฐานของงานวิจัยในด้านการเข้ารหัสและระบบกระจายศูนย์มาเนิ่นนานหลายทศวรรษ โดยมีการรวมเอานวัตกรรมสำคัญ ๆ 4 อย่างนี้มารวมเข้าด้วยกัน:</p>
<ul>
<li>เครือข่ายเพียร์ทูเพียร์ที่กระจายศูนย์ (ฺBitcoin protocol)</li>
<li>บัญชีธุรกรรมสาธารณะ (Blockchain)</li>
<li>ชุดของกฎในการตรวจสอบธุรกรรมอย่างอิสระและการออกสกุลเงิน ( consensus rules )</li>
<li>กลไกในการหาข้อตกลงร่วมกันทั่วโลกเกี่ยวกับบล็อกเชนที่ถูกต้อง (PoW algorithm)</li>
</ul>
<blockquote>
<p> ในมุมมองของนักพัฒนา นาย Andreas M. Antonopoulos and David A. Harding ( ไม่ใช่ผมจ้าา ถึงจะเห็นด้วยก็ตาม) พวกเขามองว่าบิตคอยน์นั้นคล้ายกับอินเทอร์เน็ตของเงิน เป็นเครือข่ายสำหรับการกระจายมูลค่าและการรักษาความเป็นเจ้าของสินทรัพย์ดิจิทัลผ่านการคำนวณแบบกระจายศูนย์ ซึ่งบิตคอยน์มีรายระเอียดเยอะกว่าที่พวกเขาเห็นในตอนแรกมาก ๆ</p>
</blockquote>
<p>ในบทนี้เองจะเป็นการอธิบายแนวคิด และคำศัพท์หลัก ๆ รวมทั้งการติดตั้งซอฟแวร์ต่าง ๆ ที่จำเป็นในการทอดลองใช้บิตคอยน์สำหรับทำธุรกรรมง่าย ๆ และสำหรับในบทถัดไป เราจะทำการดำดิ่งลงไปในเทคโนโลยีต่าง ๆ ที่ประกอบรวมกันเป็นบิตคอยน์ว่าทำไมมันถึงเป็นไปได้ และตรวจสอบการทำงานภายในของเครือข่ายและโปรโตคอล</p>
<h3>ก่อนการมาถึงของบิตคอยน์</h3>
<p>สกุลเงินดิจิทัลที่ใช้งานได้จริงในอดีตนั้นมักเกี่ยวข้องกับพัฒนาการในด้านการเข้ารหัส ซึ่งนั่นก็ไม่ได้แปลกอะไรหากเราพิจารณาถึงปัญหาพื้นฐานในการใช้ข้อมูลเพื่อแทนมูลค่าที่สามารถแลกเปลี่ยนเป็นสินค้าและบริการ โดยการที่เงินดิจิทัลจะถูกยอมรับได้นั้นมักจะต้องสามารถตอบคำถามทั้งสามข้อนี้ได้เสียก่อน:</p>
<ul>
<li>ฉันจะเชื่อได้อย่างไรว่าเงินนั้นเป็นของจริงและไม่ใช่ของปลอม?</li>
<li>ฉันจะเชื่อได้อย่างไรว่าเงินดิจิทัลสามารถใช้ได้เพียงครั้งเดียว (ปัญหาการใช้ซ้ำหรือ "double-spend")?</li>
<li>ฉันจะมั่นใจได้อย่างไรว่าไม่มีใครสามารถอ้างสิทธิ์ว่าเงินนี้เป็นของพวกเขาไม่ใช่ของฉัน?</li>
</ul>
<p>ผู้ที่ออกเงินกระดาษเองก็พยายามต่อสู้กับปัญหาการปลอมแปลงโดยการใช้เทคโนโลยีการพิมพ์ที่ซับซ้อนมากขึ้นเรื่อย ๆ และเงินกายภาพเองก็จัดการปัญหาการใช้ซ้ำได้ง่ายเพราะธนบัตรเดียวกันไม่สามารถอยู่ในสองที่พร้อมกันได้ แน่นอนละว่าเงินทั่วไปก็ถูกเก็บและส่งแบบดิจิทัลเช่นกัน ในกรณีเหล่านี้ ปัญหาการปลอมแปลงและการใช้ซ้ำจะถูกจัดการโดยการเคลียร์ธุรกรรมทางอิเล็กทรอนิกส์ทั้งหมดผ่านหน่วยงานกลางที่สามารถตรวจสอบสถานะของเงินได้ แต่สำหรับเงินดิจิทัลที่ไม่สามารถใช้หมึกพิเศษหรือแถบโฮโลแกรมได้ การเข้ารหัสจึงเป็นพื้นฐานสำคัญในการยืนยันความถูกต้องของการอ้างสิทธิ์ในมูลค่าของผู้ใช้ โดยเฉพาะอย่างยิ่ง การเซ็นชื่อดิจิทัลที่เข้ารหัสช่วยให้ผู้ใช้สามารถเซ็นชื่อในสินทรัพย์ดิจิทัลหรือธุรกรรมเพื่อยืนยันการเป็นเจ้าของสินทรัพย์นั้น ซึ่งสิ่งนี้เองยังสามารถใช้ในการแก้ปัญหาการใช้ซ้ำ (doble-spending) ได้</p>
<p>ศาสตร์ของการเข้ารหัสนั้นเริ่มเป็นที่แพร่หลายในช่วงปลายของทศวรรษที่ 1980 นักวิจัยหลายคนเริ่มพยายามใช้การเข้ารหัสเพื่อสร้างสกุลเงินดิจิทัล โดยโครงการเงินดิจิทัลในยุคแรก ๆ นั้นมักจะออกเงินดิจิทัลที่มีการสนับสนุนโดยสกุลเงินของชาติหรือโลหะมีค่าอย่างเช่น ทองคำ</p>
<p>ซึ่งแม้ว่าสกุลเงินดิจิทัลยุคแรกเหล่านี้จะทำงานได้ แต่ก็มีปัญหาที่การรวมศูนย์ของระบบ เนื่องจากมันทำให้ระบบเป็นเป้าหมายที่ง่ายต่อการโจมตีโดยรัฐบาลและเหล่าแฮกเกอร์ สกุลเงินดิจิทัลยุคแรกใช้ศูนย์กลางในการชำระธุรกรรมทั้งหมดเป็นระยะ ๆ เช่นเดียวกับระบบธนาคารทั่วไป เป็นที่น่าเสียดายที่สกุลเงินดิจิทัลเหล่านี้ส่วนใหญ่ถูกกำหนดเป้าหมายโดยรัฐบาลที่กังวลและมักจะถูกฟ้องร้องจนล้มเหลว บางส่วนล้มเหลวอย่างรวดเร็วเมื่อบริษัทผู้ก่อตั้งปิดตัวลงอย่างกะทันหัน และเพื่อให้สกุลเงินดิจิทัลมีความแข็งแกร่งต่อต้านการแทรกแซงจากศัตรู ไม่ว่าจะเป็นรัฐบาลที่ถูกกฎหมายหรืออาชญากรรม เราจึงจำเป็นต้องมีสกุลเงินดิจิทัลที่กระจายศูนย์ เพื่อป้องกันปัญหาดังกล่าว ซึ่งบิตคอยน์คือระบบแบบนั้น ระบบที่ถูกออกแบบให้กระจายศูนย์ และปราศจากอำนาจหรือจุดควบคุมกลางใด ๆ ที่สามารถถูกโจมตีหรือทำให้เสียหายได้</p>
<h2>ประวัติของบิตคอยน์</h2>
<p>บิตคอยน์ได้ปรากฏครั้งแรกในปี 2008 บนเอกสารที่มีชื่อว่า “Bitcoin: A Peer-to-Peer Electronic Cash System” ซึ่งถูกเขียนโดยบุคคลหรือกลุ่มคนนิรนามที่ใช้นามแฝงว่า ซาโตชิ นากาโมโตะ ซึ่งได้มีการนำนวัตกรรมหลาย ๆ อย่างมารวมเข้าด้วยกัน ไม่ว่าจะเป็นลายเซ็นดิจิทัล และ Hashcash มาสร้างระบบเงินสดอิเล็กทรอนิกส์ที่กระจายศูนย์อย่างสมบูรณ์ ซึ่งไม่ต้องพึ่งพาหน่วยงานกลางในการออกสกุลเงินหรือการชำระและตรวจสอบธุรกรรม โดยนวัตกรรมสำคัญคือการใช้ระบบคำนวณแบบกระจายศูนย์ (Proof-of-work) เพื่อทำสิ่งที่คล้าย ๆ กับการจับฉลากทุก ๆ 10 นาที ทำให้เครือข่ายที่กระจายศูนย์สามารถมีฉันทามติในสถานะของธุรกรรมได้ และสิ่งนี้เองยังสามารถแก้ไขปัญหาการทำธุรกรรมซ้ำซ้อน ซึ่งเป็นข้อบกพร่องของสกุลเงินดิจิทัลที่เคยต้องใช้หน่วยงานกลางในการตรวจสอบธุรกรรมทั้งหมดได้อีกด้วย</p>
<p>เครือข่ายของบิตคอยน์นั้นเริ่มต้นขึ้นในปี 2009 โดยอ้างอิงจากซอฟแวร์ที่เผยแพร่โดย ซาโตชิ และได้ถูกปรับปรุงโดยโปรแกรมเมอร์คนอื่น ๆ มากมายนับไม่ถ้วนมานับตั้งแต่นั้น จำนวนและกำลังของอุปกรณ์ที่ใช้ประมวลผล Proof of Work algorithm (การขุด) เองนั้นก็เพิ่มขึ้นอย่างมหาศาล จนในปัจจุบันนี้พลังการคำนวณรวมกันของเครือข่ายนี้มีมากกว่าจำนวนการคำนวณของซุปเปอร์คอมพิวเตอร์ชั้นนำของโลกทั้งหมดรวมกันเสียอีก ซึ่งสิ่งนี้เองได้ช่วยรักษาความปลอดภัยและความเสถียรของเครือข่ายของบิตคอยน์ได้เป็นอย่างดี</p>
<p>ซาโตชิ นากาโมโตะ ได้ทำการถอนตัวและหายตัวไปในเดือนเมษายนในปี 2011 และมอบหมายความรับผิดชอบในการพัฒนาโค้ดและเครือข่ายให้กับกลุ่มอาสาสมัครที่เติบโตขึ้นเรื่อย ๆ ซึ่งตัวตนของบุคคลหรือกลุ่มคนที่อยู่เบื้องหลังบิตคอยน์นั้นยังไม่เป็นที่รู้จัก แต่อย่างไรก็ตาม ไม่ว่าจะเป็นซาโตชิ นากาโมโตะ หรือใครหน้าไหนก็ตามก็ไม่สามารถควบคุมเครือข่ายของบิตคอยน์ได้ตามลำพัง เนื่องจากมันอยู่บนหลักการทางคณิตศาสตร์ที่โปร่งใส โค้ดโอเพนซอร์ส และฉันทามติจากผู้ที่เข้าร่วม โดยนวัตกรรมนี้ถือเป็นการเปลี่ยนแปลงครั้งใหญ่และได้ก่อให้เกิดวิทยาการใหม่ในด้านการคำนวณแบบกระจายศูนย์ เศรษฐศาสตร์ และเศรษฐมิติอีกด้วย</p>
<h3>การแก้ปัญหาในระบบคำนวณแบบกระจายศูนย์</h3>
<p>นวัตกรรมของซาโตชิ นากาโมโตะ ยังเป็นการแก้ไขปัญหาที่มีประสิทธิภาพและแปลกใหม่สำหรับปัญหาในระบบคำนวณแบบกระจายศูนย์ที่เรียกว่า "Byzantine Generals' Problem" ซึ่งปัญหานี้เกี่ยวข้องกับการพยายามทำให้ผู้เข้าร่วมหลายคนที่ไม่มีผู้นำสามารถตกลงกันในแผนการดำเนินการได้โดยการแลกเปลี่ยนข้อมูลในเครือข่ายที่ไม่น่าเชื่อถือและอาจถูกโจมตีได้ โดยการแก้ปัญหาของซาโตชินั้นได้ใช้แนวคิด proof of work เพื่อหาฉันทามติโดยไม่ต้องมีผู้ควบคุมที่น่าเชื่อถือ ถือเป็นความก้าวหน้าในด้านการคำนวณแบบกระจายศูนย์</p>
<h2>เปิดประตูสู่บิตคอยน์</h2>
<p>บิตคอยน์เป็นโปรโตคอลที่สามารถเข้าถึงได้ผ่านทางแอปพลิเคชันที่มีการรับรองโปรโตคอลนี้ Bitcoin wallet นั้นเป็นช่องทางหลักที่ผู้ใช้งานส่วนใหญ่เลือกใช้เพื่อเข้าถึงโปรโตคอลของบิตคอยน์ เช่นเดียวกันกับที่ผู้ใช้งานอินเตอร์เน็ตส่วนใหญ่ใช้เว็บบราวเซอร์เป็นช่องทางในการเข้าถึงโปรโตคอลอย่าง HTTP นั่นเอง Bitcoin wallet เองก็มีหลากหลายยี่ห้อเฉกเช่นเดียวกับเว็บบราวเซอร์ อาทิเช่น chorme, safari, firefox ฯลฯ Bitcoin wallet เองก็เช่นกัน แต่ละยี่ห้อเองก็มีความแตกต่างกันในด้านต่าง ๆ ไม่ว่าจะเป็นในด้านคุณภาพ ประสิทธิภาพ ความปลอดภัย ความเป็นส่วนตัว และความน่าเชื่อถือ อีกทั้งยังมี Bitcoin wallet ที่ถูกสร้างขึ้นมาคู่กับโปรโตคอลของบิตคอยน์อย่าง “Bitcoin Core” ซึ่งมีการพัฒนาต่อมาจากเวอร์ชันที่เขียนโดยซาโตชิ</p>
<h3>การเลือก Bitcoin wallet</h3>
<p>Bitcoin wallet เป็นหนึ่งในประเภทของแอปพลิเคชันที่มีการพัฒนาอย่างต่อเนื่องมากที่สุดในระบบนิเวศของบิตคอยน์ และแน่นอนว่ามีการแข่งขันกันสูงที่สุดด้วย อาจมี Bitcoin wallet ใหม่ ๆ ที่กำลังพัฒนาอยู่ในขณะนี้ Bitcoin wallet เก่า ๆ บางตัวจากปีที่แล้วก็อาจไม่มีการพัฒนาอย่างต่อเนื่องอีกต่อไป Bitcoin wallet หลาย ๆ ตัวเน้นไปที่แพลตฟอร์มหรือการใช้งานเฉพาะ และบางตัวเหมาะสำหรับผู้เริ่มต้น ในขณะที่บางตัวเต็มไปด้วยฟีเจอร์สำหรับผู้ใช้ขั้นสูง การเลือก Bitcoin wallet นั้นจึงขึ้นอยู่กับความต้องการและระดับความเชี่ยวชาญของผู้ใช้ ดังนั้นการที่เราจะแนะนำยี่ห้อหรือ Bitcoin wallet เฉพาะจึงอาจจะไม่เกิดประโยชน์เท่าไหร่ แต่อย่างไรก็ตาม เราสามารถแบ่งประเภท Bitcoin wallet ได้ตามแพลตฟอร์มและการใช้งานได้ดังนี้</p>
<h4>ประเภทของ Bitcoin wallet</h4>
<ul>
<li><strong>Desktop wallet:</strong> กระเป๋าเงินแบบเดสก์ท็อปเป็น Bitcoin wallet ประเภทแรกที่ถูกพัฒนาขึ้นและผู้ใช้ส่วนใหญ่มักจะเลือกใช้ Bitcoin wallet ประเภทนี้เพราะฟีเจอร์ของมัน เช่นความความเป็นอิสระในการใช้งาน ความสามารถในการควบคุมบิตคอยน์ในกระเป๋า แต่อย่างไรก็ตาม การใช้งานบนระบบปฏิบัติการทั่วไป อย่างเช่น Windows และ macOS อาจมีข้อเสียด้านความปลอดภัย เนื่องจากแพลตฟอร์มเหล่านี้มักไม่มีความปลอดภัยเพียงพอและอาจถูกตั้งค่ามาอย่างไม่เหมาะสม </li>
<li><strong>Mobile wallet:</strong> กระเป๋าเงินแบบมือถือเป็น Bitcoin wallet ประเภทที่พบเจอได้มากที่สุด โดยทำงานบนระบบปฏิบัติการสมาร์ทโฟน เช่น Apple iOS และ Android กระเป๋าเงินเหล่านี้มักเป็นตัวเลือกที่ดีสำหรับผู้ใช้ใหม่ เพราะออกแบบมาให้ใช้งานง่ายและสะดวก นอกจากนี้ยังมีกระเป๋าเงินมือถือที่มีฟีเจอร์ครบครันสำหรับผู้ใช้ที่มีความเชี่ยวชาญ แต่เพื่อหลีกเลี่ยงการดาวน์โหลดและจัดเก็บข้อมูลปริมาณมาก กระเป๋าเงินมือถือส่วนใหญ่จะดึงข้อมูลจากเซิร์ฟเวอร์ระยะไกล ซึ่งอาจลดความเป็นส่วนตัวของผู้ใช้เนื่องจากต้องเปิดเผยข้อมูลเกี่ยวกับ address และจำนวนบิตคอยน์ Bitcoin ต่อบุคคลที่สาม</li>
<li><strong>Web wallet:</strong> กระเป๋าเงินแบบเว็บสามารถเข้าถึงได้ผ่านเว็บเบราว์เซอร์และเก็บกระเป๋าเงินของผู้ใช้ไว้บนเซิร์ฟเวอร์ที่บุคคลที่สามเป็นเจ้าของ คล้ายกับบริการอีเมลบนเว็บที่พึ่งพาเซิร์ฟเวอร์ของบุคคลที่สามโดยสมบูรณ์ โดยบางบริการใช้โค้ดฝั่งไคลเอนต์ที่ทำงานในเบราว์เซอร์ของผู้ใช้ และเพื่อให้ผู้ใช้สามารถควบคุมคีย์ของบิตคอยน์ได้เอง แต่การพึ่งพาเซิร์ฟเวอร์ยังคงส่งผลกระทบต่อความเป็นส่วนตัว อย่างไรก็ตาม บริการส่วนใหญ่จะควบคุมคีย์ของบิตคอยน์แทนผู้ใช้เพื่อแลกกับความสะดวกสบาย เราจึงไม่แนะนำให้เก็บ <strong>บิตคอยน์จำนวนมากบนระบบของบุคคลที่สาม</strong></li>
<li><strong>Hardware Signing Devices:</strong> อุปกรณ์สำหรับเซ็นดิจิทัลเป็นอุปกรณ์ที่สามารถจัดเก็บคีย์และเซ็นธุรกรรมโดยใช้ฮาร์ดแวร์และเฟิร์มแวร์เฉพาะทาง ซึ่งโดยทั่วไปแล้วจะเชื่อมต่อกับกระเป๋าเงินเดสก์ท็อป มือถือ หรือเว็บ ผ่านสาย USB การสื่อสารระยะใกล้ (NFC) หรือกล้องที่รองรับ QR code แต่เนื่องจากการดำเนินการที่เกี่ยวข้องกับบิตคอยน์ ทั้งหมดถูกจัดการบนฮาร์ดแวร์เฉพาะ อุปกรณ์เหล่านี้จึงปลอดภัยจากการโจมตีหลายรูปแบบ อย่างไรก็ตาม อุปกรณ์เซ็นดิจิทัลมักถูกเรียกว่า hardware wallet แต่ต้องใช้งานร่วมกับกระเป๋าเงินที่มีฟีเจอร์ครบครันเพื่อส่งและรับธุรกรรม ความปลอดภัยและความเป็นส่วนตัวที่ได้จากกระเป๋าเงินที่ใช้งานร่วมกันก็มีบทบาทสำคัญต่อความปลอดภัยและความเป็นส่วนตัวโดยรวมของผู้ใช้อุปกรณ์เซ็นดิจิทัล</li>
</ul>
<h4>ประเภทของการเชื่อมต่อกับโปรโตคอลของบิตคอยน์</h4>
<ul>
<li><strong>Full node:</strong> บิตคอยน์ฟลูโหนดเป็นโปรแกรมที่ตรวจสอบความถูกต้องของประวัติธุรกรรมทั้งหมดของบิตคอยน์ (ทุกธุรกรรมที่เคยเกิดขึ้นโดยผู้ใช้ทุกคน) และนอกจากนี้ บิตคอยน์ฟลูโหนดยังสามารถเลือกเก็บข้อมูลธุรกรรมที่ได้รับการตรวจสอบแล้วก่อนหน้า และให้บริการข้อมูลแก่โปรแกรมบิตคอยน์อื่น ๆ ได้ ไม่ว่าจะเป็นบนคอมพิวเตอร์เดียวกันหรือผ่านอินเทอร์เน็ต แต่แม้ว่าบิตคอยน์ฟลูโหนดเองก็ใช้ทรัพยากรคอมพิวเตอร์ในปริมาณมาก (​ประมาณเท่ากับการดูวิดีโอสตรีมมิ่งหนึ่งชั่วโมงต่อวันสำหรับธุรกรรมบิตคอยน์ในแต่ละวัน) บิตคอยน์ฟลูโหนดเองก็มอบความเป็นอิสระอย่างสมบูรณ์แก่ผู้ใช้</li>
<li><strong>Lightweight Client:</strong> lightweight client หรือที่เรียกกันอีกชื่อว่าไคลเอนต์การตรวจสอบการชำระเงินแบบง่าย (Simplified-Payment-Verification: SPV) ซึ่งจะเชื่อมต่อกับโหนดแบบเต็มหรือเซิร์ฟเวอร์ระยะไกลอื่น ๆ เพื่อรับและส่งข้อมูลธุรกรรมของบิตคอยน์แต่เก็บกระเป๋าเงินของผู้ใช้ไว้ในเครื่อง โดยสามารถตรวจสอบธุรกรรมที่ได้รับบางส่วน และสร้างธุรกรรมขาออกอย่างอิสระอีกด้วย</li>
<li><strong>ไคลเอนต์ API ของบุคคลที่สาม (Third-Party API Client):</strong> ไคลเอนต์ API ของบุคคลที่สามเป็นโปรแกรมที่เชื่อมต่อกับระบบบิตคอยน์ผ่าน API ของบุคคลที่สาม แทนที่จะเชื่อมต่อกับเครือข่ายบิตคอยน์โดยตรง กระเป๋าเงินนี้อาจถูกจัดเก็บโดยผู้ใช้เองหรือบนเซิร์ฟเวอร์ของบุคคลที่สาม แต่ไคลเอนต์จะต้องไว้วางใจเซิร์ฟเวอร์ระยะไกลในการให้ข้อมูลที่ถูกต้องและปกป้องความเป็นส่วนตัวของตน</li>
</ul>
<blockquote>
<p>บิตคอยน์เป็นเครือข่ายแบบเพียร์ทูเพียร์(Peer-to-Peer หรือ P2P) โดยที่บิตคอยน์ฟลูโหนด ทำหน้าที่เป็นเพียร์ในเครือข่าย เพียร์แต่ละตัวจะตรวจสอบความถูกต้องของธุรกรรมที่ยืนยันแล้วทุกธุรกรรมอย่างอิสระ และสามารถให้ข้อมูลที่เชื่อถือได้แก่ผู้ใช้ Lightweight Wallets และซอฟต์แวร์อื่น ๆ เองก็เป็นลูกข่ายที่ต้องพึ่งพาเพียร์หนึ่งหรือหลายตัวในการรับข้อมูลที่ถูกต้อง ไคลเอนต์สามารถตรวจสอบข้อมูลบางส่วนที่ได้รับเพิ่มเติมและเชื่อมต่อกับเพียร์หลายตัวเพื่อลดการพึ่งพาเพียร์ตัวเดียว แต่ในท้ายที่สุดความปลอดภัยของไคลเอนต์ยังคงขึ้นอยู่กับความน่าเชื่อถือของเพียร์ที่เชื่อมต่อด้วย</p>
</blockquote>
<h4>ใครควบคุมคีย์</h4>
<p>อีกหนึ่งในประเด็นสำคัญที่ควรพิจารณาเพิ่มเติมคือใครเป็นผู้ควบคุมคีย์ (Private key) เนื่องจากเป็นสิ่งที่มีบทบาทสำคัญในการควบคุมการเข้าถึงบิตคอยน์ โดยคีย์เหล่านี้เองเปรียบเสมือน PIN ที่ยาวมาก ซึ่งหากคุณเป็นผู้ควบคุมคีย์ของคุณเองด้วยตัวเอง คุณก็เป็นผู้ควบคุมบิตคอยน์ของคุณด้วยเช่นกัน แต่หากไม่ใช่ ก็จะแปลว่ากุญแจเหล่านั้นจะถูกดูแลโดยบุคคลที่สาม ซึ่งจะเป็นผู้จัดการเงินของคุณในนามของคุณ</p>
<p>ซอฟแวร์ในการจัดการกุญแจนั้นถูกแบ่งออกเป็นสองประเภทหลัก ๆ คือ wallet ที่คุณจำเป็นต้องดูแลคีย์ของตัวเองและ บัญชีที่มีผู้ดูแล (Custodian Accounts) ซึ่งจะมีบุคคลที่สามเป็นผู้ควบคุมกุญแจ </p>
<blockquote>
<p>“Your keys, your coins. Not your keys, not your coins.”</p>
</blockquote>
<h3>มาอยู่ตัวอย่างเพื่อความเข้าใจที่มาขึ้นกันเถอะ</h3>
<p>สมมุติว่าอลิซเป็นผู้ใช้งานที่ไม่ได้เชี่ยวชาญด้านเทคนิค และเพิ่งได้ยินเกี่ยวกับบิตคอยน์จากเพื่อนสนิทของเขา โจ ระหว่างปาร์ตี้ โจกำลังอธิบายเกี่ยวกับบิตคอยน์อย่างกระตือรือร้นให้ทุกคนฟังและสาธิตวิธีการใช้งานต่าง ๆ ให้ดู อลิซเองได้มีความสนใจในบิตคอยน์หลังจากได้ฟังโจอธิบาย จึงได้ถามโจว่าเธอจะเริ่มต้นใช้งานบิตคอยน์ได้อย่างไร โจจึงแนะนำให้อลิซดาวน์โหลด Mobile wallet ตัวโปรดของเขาเนื่องจากมันเหมาะสมกับมือใหม่ อลิซจึงดาวน์โหลดและติดตั้งแอปพลิเคชันกระเป๋าเงินที่โจแนะนำบนโทรศัพท์ของเธอ</p>
<p>เมื่ออลิซเปิดแอปพลิเคชันครั้งแรก เธอได้เลือกสร้างกระเป๋าใหม่และเนื่องจากกระเป๋าที่เธอเลือกนั้นเป็นแบบที่ไม่ได้อยู่ภายใต้การควบคุมบุคคลที่สาม (Noncustodial Wallet) อลิซจึงเป็นผู้ควบคุมคีย์เพียงคนเดียว ซึ่งหมายความว่าเธอต้องรับผิดชอบในการสำรองข้อมูลด้วยตัวของเธอเอง และหากเธอได้ทำคีย์สูญหายไป เธอจะไม่สามารถเข้าถึงบิตคอยน์ของเธอได้อีกไปตลอดกาล และเพื่อเพื่อช่วยในเรื่องนี้ Bitcoin wallet ต่าง ๆ จึงมักจะสร้างรหัสการกู้คืน (Recovery Code) ให้ซึ่งสามารถใช้ในการกู้คืน Bitcoin wallet อันนั้น ๆ</p>
<h4>Recovery Code (รหัสในการกู้คืน)</h4>
<p>Bitcoin wallet แบบที่ไม่ได้อยู่ภายใต้การควบคุมของบุคคลที่สามนั้นส่วนใหญ่จะให้รหัสการกู้คืนแก่ผู้ใช้งานเพื่อสำรองข้อมูล และรหัสการกู้คืนนี้มักประกอบด้วยตัวเลข ตัวอักษร หรือคำที่ถูกเลือกแบบสุ่มโดยซอฟต์แวร์ และใช้เป็นพื้นฐานสำหรับการสร้าง Bitcoin wallet โดยแต่ละยี่ห้อก็อาจมีความแตกต่างกัน เช่น</p>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1733022493439-YAKIHONNES3.png" alt="image"></p>
<blockquote>
<p>รหัสการกู้คืนมักเรียกว่า "mnemonic" หรือ "mnemonic phrase" หรือในภาษาไทยว่าวลีช่วยจำ ซึ่งบ่งบอกว่าคุณควรจดจำวลีนั้น แต่การจดวลีนี้ลงบนกระดาษใช้เวลาน้อยกว่าและมักจะเชื่อถือได้มากกว่าความจำของคนส่วนใหญ่ เพราะฉนั้นผมเลยแนะนำว่าจดเถอะ จะได้ไม่เกิดปัญหาที่ไม่คาดคิดในอนาคต</p>
</blockquote>
<p>หาก bitcoin wallet ของอลิซมีปัญหา เธอสามารถดาวน์โหลดซอฟแวร์ใหม่และใส่รหัสในการกู้คืนลงไป เพื่อสร้างฐานข้อมูลของ bitcoin wallet ใหม่ที่บันทึกธุรกรรมบนเชนทั้งหมดที่เธอเคยรับหรือส่ง แต่อย่างไรก็ตาม การกู้คืนจากการใช้รหัสการกู้คืนเพียงอย่างเดียวนั้นอาจจะไม่สามารถกู้คืนข้อมูลเพิ่มเติมที่อลิซเคยบันทึกไว้ใน wallet นั้น ๆ ได้ เช่น ป้ายกำกับที่เธอเชื่อมโยงกับที่อยู่หรือธุรกรรมต่าง ๆ แม้ว่าการสูญเสียข้อมูลเมตานี้จะไม่สำคัญเท่ากับการสูญเสียเงิน แต่ก็ยังมีความสำคัญในบางแง่มุม เช่น หากคุณต้องตรวจสอบรายการธนาคารหรือบัตรเครดิตเก่า แต่ชื่อของผู้ที่คุณชำระเงินหรือผู้ที่จ่ายเงินให้คุณถูกลบออกไป ดังนั้นเพื่อป้องกันการสูญเสียข้อมูลเมตา wallet หลาย ๆ ยี่ห้อจึงมีฟีเจอร์สำรองข้อมูลเพิ่มเติมนอกเหนือจากรหัสการกู้คืน</p>
<p>สำหรับ wallet บางประเภทนั้น ฟีเจอร์สำรองข้อมูลเพิ่มเติมนี้ถือว่ามีความสำคัญมาก เนื่องจากการชำระเงินเงินด้วยบิตคอยน์จำนวนมากในปัจจุบันทำผ่านเทคโนโลยีที่อยู่นอกเชน (Offchain) ซึ่งธุรกรรมไม่ได้ถูกบันทึกลงในบล็อกเชนสาธารณะ เนื่องจากการชำระเงินแบบนี้ช่วยลดค่าใช้จ่ายของผู้ใช้และเพิ่มความเป็นส่วนตัวได้บ้าง แต่นั่นก็หมายความว่ากลไกอย่างรหัสการกู้คืนที่พึ่งพาข้อมูลบนเชนไม่สามารถรับประกันการกู้คืนบิตคอยน์ทั้งหมดของผู้ใช้ได้ ดังนั้นสำหรับแอปพลิเคชันที่รองรับการใช้งาน Offchain การสำรองข้อมูลฐานข้อมูล wallet บ่อยครั้งจึงเป็นสิ่งที่มีความสำคัญมาก</p>
<p>นอกจากนี้ เมื่อได้รับบิตคอยน์ครั้งแรกใน moblie wallet หลาย ๆ wallet มักจะตรวจสอบอีกครั้งว่าคุณได้สำรองรหัสการกู้คืนไว้อย่างปลอดภัยแล้ว การตรวจสอบนี้อาจเป็นเพียงการแจ้งเตือน หรืออาจถึงขั้นให้ผู้ใช้ป้อนรหัสนั้นซ้ำด้วยตัวเอง</p>
<blockquote>
<p><em>คำเตือน</em>  แม้ว่า Bitcoin Wallet หลาย ๆ ตัวอาจจะมีการให้คุณต้องกรอกรหัสในการกู้คืนใหม่ในบางกรณี แต่มันก็มักจะมีแอปพลิเคชันมัลแวร์จำนวนมากที่เลียนแบบการออกแบบของ wallet ต่าง ๆ โดยมันจะบังคับให้คุณป้อนรหัสการกู้คืน จากนั้นมันจะส่งรหัสที่ป้อนไปยังผู้พัฒนามัลแวร์เพื่อขโมยบิตคอยน์ของคุณ นี่เปรียบเสมือนเว็บไซต์ฟิชชิงที่พยายามหลอกให้คุณให้รหัสผ่านธนาคารของคุณ สำหรับ Bitcoin wallet ส่วนใหญ่ เวลาที่พวกเขาจะขอรหัสการกู้คืนคือในระหว่างการตั้งค่าเริ่มต้น (ก่อนที่คุณจะได้รับบิตคอยน์) และระหว่างการกู้คืน (หลังจากที่คุณสูญเสียการเข้าถึง wallet เดิม) หากแอปพลิเคชันขอรหัสการกู้คืนในช่วงเวลาอื่น คุณควรปรึกษาผู้เชี่ยวชาญเพื่อให้แน่ใจว่าคุณไม่ได้ตกเป็นเหยื่อของการฟิชชิง </p>
</blockquote>
<h4>Bitcoin Addresses (ที่อยู่ในการรับหรือส่งบิตคอยน์)</h4>
<p>ในตอนนี้อลิซพร้อมแล้วสำหรับการสร้าง Bitcoin wallet ใหม่ของเธอ Bitcoin wallet ที่เธอเลือกได้ทำการสร้าง private key แบบสุ่มให้เธอ ซึ่งจะเชื่อมโยงกับ Bitcoin Address ทั้งหมดที่มีใน Bitcoin wallet ของเธอ แต่ ณ ขณะนี้ยังไม่มีใครรู้ Bitcoin address ของเธอ (แม้แต่ Bitcoin network ก็ไม่รู้) นอกจากตัวเธอเอง Bitcoin address เหล่านี้เป็นเพียงตัวเลขที่เชื่อมโยงกับ Private key ของเธอ ซึ่งเธอสามารถใช้ควบคุมการเข้าถึง Bitcoin ใดกระเป๋าได้ Bitcoin address เหล่านี้ถูกสร้างขึ้นโดยอิสระจากกระเป๋าของเธอโดยไม่ต้องอ้างอิงหรือเชื่อมต่อกับบริการใด ๆ</p>
<p>คำแนะนำ: Bitcoin address และ Invoice นั้นมีหลากหลายรูปแบบที่แตกต่างกัน และทั้งหมดนี้สามารถแชร์ให้กับคนอื่น ๆ ได้ เพื่อเป็นการอณุญาติให้พวกเขาส่งบิตคอยน์เข้ามาในกระเป๋าคุณตรง ๆ คุณสามารถแชร์ Bitcoin address และ Invoice ให้คนอื่นได้โดยไม่ต้องกังวลเกี่ยวกับความปลอดภัยของบิตคอยน์ของคุณ เนื่องจากผู้ที่รู้ Bitcion address ของคุณไม่สามารถถอนเงินออกจาก address นั้น ๆ ได้แม้เขาจะสามารถรู้จำนวนเงินใน address นั้น ๆ ก็ตาม เพราะฉะนั้นเพื่อปกป้องความเป็นส่วนตัวของคุณ คุณจึงควรสร้าง Invoice จาก Bitcoin address ใหม่ทุกครั้งที่จะส่งให้ผู้อื่น</p>
]]></itunes:summary>
      <itunes:image href="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1733022903046-YAKIHONNES3.jpg"/>
      </item>
      
      <item>
      <title><![CDATA[nOStr the series :Nostr Web Services ]]></title>
      <description><![CDATA[ปลดล็อกการเชื่อมต่อสู่โลกโดยไม่ต้องใช้ที่อยู่ IP สาธารณะบน Nostr
]]></description>
             <itunes:subtitle><![CDATA[ปลดล็อกการเชื่อมต่อสู่โลกโดยไม่ต้องใช้ที่อยู่ IP สาธารณะบน Nostr
]]></itunes:subtitle>
      <pubDate>Thu, 12 Sep 2024 11:16:45 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/byjh9iwzfudbgzosbsp/</link>
      <comments>https://learnbn.npub.pro/post/byjh9iwzfudbgzosbsp/</comments>
      <guid isPermaLink="false">naddr1qq2ky7t2fqukja66ge6kgcn80fhhxcjn2qkj6q3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wt0u5m8</guid>
      <category>ลองฟอร์มของไดโน</category>
      
        <media:content url="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1726139805814-YAKIHONNES3.jpg" medium="image"/>
        <enclosure 
          url="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1726139805814-YAKIHONNES3.jpg" length="0" 
          type="image/jpeg" 
        />
      <noteId>naddr1qq2ky7t2fqukja66ge6kgcn80fhhxcjn2qkj6q3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wt0u5m8</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<p><strong>" ผมตื่นเต้นที่จะประกาศเปิดตัว NWS ครั้งแรก นี่เป็นคำตอบของการเชื่อมต่อออกไปยังโลกของอินเตอร์เน็ต โดยใช้ NOSTR เข้าไปแทรกระหว่าง transport layer และ network layer ที่อยู่บน TCP/IP โมเดล NWS นั้นจะเข้ามาช่วยให้การสื่อสารระหว่างอุปกรณ์ต่างๆ ให้เป็นไปอย่างราบรื่น มีความเป็นส่วนตัวเพิ่มขึ้น และทำให้เราสามารถท่องโลกของอินเตอร์เน็ตโดยไม่จำเป็นต้องใช้ Public IP "</strong> -asmogo </p>
<h2>NostrWebServices (NWS) คืออะไร?</h2>
<p>NWS คือการนำ Nostr เข้ามาช่วยในการเข้าถึงบริการของเว็บไซต์ต่าง ๆ โดยยังสามารถส่งข้อมูลขึ้นไปยัง transport layer บน TCP/IP ซึ่งด้วยวิธีนี้เองเลยทำให้เราสามารถสร้างการเชื่อมต่อได้โดยไม่จำเป็นต้องมี Public IP โดยส่วนที่จำเป็นหลัก ๆ ในการทำงานนี้เราจำเป็นต้องเตรียม</p>
<ul>
<li><p><strong>Entry node</strong>: SOCKS5 proxy ที่คอยส่งต่อ TCP packets ที่เข้ารหัสผ่านทาง event ของ Nostr ก่อนส่งส่งผ่านรีเลย์ต่าง ๆ ไปยัง Exit node</p>
</li>
<li><p><strong>Exit node</strong>:  TCP reverse proxy ที่คอยรอรับข้อมูลมาจาก Entry node และส่งต่อข้อมูลต่าง ๆ ไปยังบริการอื่น ๆ ต่อไป</p>
</li>
</ul>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1726136393181-YAKIHONNES3.png" alt="image"></p>
<p>ในส่วนของการทำงานนั้นสามารถดูได้จากในรูปที่ได้แนบไว้ข้างต้นได้เลย<br>อย่างที่เห็นเลยว่ามันเริ่มจากแอพต่าง ๆ เหมือนที่เรามีการใช้งานกันอยู่ในปัจจุบัน เพียงแต่แทนที่เราจะส่งข้อมูลต่าง ๆ ผ่าน IP layer ตามปกติ เราสามารถส่งเข้าไปยัง Entry node และหลังจากนั้นข้อมูลจะถูกส่งผ่าน relay ต่าง ๆ ก่อนที่จะวิ่งไปยัง Exit node และ Exit node จะคอยส่งข้อมูลต่าง ๆ ไปยังบริการหลังบ้านที่เราต้องการจะเชื่อมต่อ </p>
<p>เราจะเห็นได้ว่าการทำงานของ NWS นั้น สำหรับผู้ใช้งานโดยทั่วไปแล้วแทบจะไม่แตกต่างอะไรกับในปัจจุบันเลย นั่นก็เพราะว่าเรายังทำการใช้งานแอพต่าง ๆ ตามปกติ แต่ประโยชน์ที่เราจะได้รับเพิ่มเติมนั้นคือความเป็นส่วนตัวในการใช้บริการเบื้องหลังอื่น ๆ </p>
<p>นอกจากนี้ยังมีในส่วนของ NWS domain names ใน NWS นั้นมีการรับรอง domain สองตัวนั้นคือ </p>
<ol>
<li>".nostr" ซึ่งใช้ชื่อโฮสต์เป็นกุญแจสาธารณะที่เข้ารหัสด้วย base32 และ รีเลย์ที่เข้ารหัสด้วย base32 เป็นโดเมนย่อย</li>
<li>"nprofiles" ซึ่งเป็นการผสมผสานกันระหว่างกุญแจสาธารณะของNostrและรีเลย์หลายตัว</li>
</ol>
<p>ซึ่งโดเมนทั้งสองประเภทจะถูกสร้างและปรากฏอยู่บนคอนโซลเมื่อเริ่มต้นใช้งาน</p>
<h2>หัวใจหลักในการทำงานของ NWS</h2>
<p>อย่างที่ได้กล่าวไว้ข้างต้นว่า NWS เข้ามาช่วยเหลือในการเพิ่มความเป็นส่วนตัวได้ แล้วถ้าเราไม่ได้ต้องการเข้ารหัส หรือถ้าเราอยากจะเปิด Entry node แล้วเราไม่ต้องการให้คนที่จะเชื่อมต่อเข้ามาเข้ารหัสข้อมูลเราสามารถทำได้เช่นกัน โดยทั้งสองระบบที่ NWS ทำได้มีดังนี้</p>
<ul>
<li><p>แบบไม่เข้ารหัส: เราจำเป็นต้องรันโหนดไว้ในเครื่องที่เราใช้รัน client แล้วแปลง client ให้ส่งข้อความใส่โหนดปลายทางตรง ๆ</p>
</li>
<li><p>แบบเข้ารหัส เริ่มจากการเชื่อมไปที่โหนดที่ต้องการ (อารมณ์ ssh เข้าไป) แต่วิธีนี้ยังติดที่บางเว็บที่เป็น https จะเชื่อมไม่ได้หาก cert ของโหนดที่เราเชื่อมมีปัญหา ส่วนข้อมูลที่ส่งจะถูก encrypt ไว้ด้วย Sphinx (เข้ารหัสแบบหนึ่งในมาตรฐาน RSA) ฉนั้นมั่นใจได้ว่าโหนดที่เราไปยืมจมูกเขาหายใจก็ไม่รู้ว่าเราส่งอะไรไป</p>
</li>
</ul>
<h2>การตรวจสอบตัวตนของเซิร์ฟเวอร์ปลายทาง</h2>
<p>การตรวจสอบตัวตนของเซิร์ฟเวอร์ปลายทางของ NWS ทำโดยการใช้ประโยชน์จาก nostr โดยให้โหนดปลายทางปล่อย cert (TLS) บน nostr และเซ็นรับรองด้วยตนเองและอณุญาติให้ไคลเอนต์สามารถดึงใบรับรองนี้มาก่อนเชื่อมต่อกับโหนดที่เป็นจุดเริ่มที่เราใช้</p>
<p>และนอกจากนี้ในอนาคตของการพัฒนา NWS กำลังพัฒนาให้ NWS สามารถกำหนดให้โหนดปลายทางสามารถกำหนดค่าให้เข้าถึงอินเทอร์เน็ตได้ (ไม่ใช่แค่บริการภายใน) ทำให้ NWS ทำงานคล้าย VPN โดยสามารถเข้าเว็บไซต์ปกติได้ เช่น พิมพ์ "https google dot com" ก็เข้า google ได้</p>
<p>และทั้งหมดที่กล่าวไว้ข้างต้นเป็นเพียงการเริ่มต้น ยังมีคุณสมบัติอย่างอื่นอีกมากมายที่จะเข้ามาปรับปรุงปัญหาต่าง ๆ ในการใช้งานอินเตอร์เน็ต โดยส่วนตัวผมรู้สึกตื่นเต้นกับอนาคตของ NWS มาก ๆ และคาดหวังที่จะได้เห็นคนหันมาให้ความสนใจและใช้งานมัน ทั้งนี้หากใครอยากทดลองใช้งานก็สามารถติดตามได้ที่ </p>
<p>   GitHub: <np-embed url="https://github.com/asmogo/nws"><a href="https://github.com/asmogo/nws">https://github.com/asmogo/nws</a></np-embed></p>
<h2>ส่งท้าย</h2>
<p>สำหรับ series nOStr ผมตั้งใจจะหาเรื่องราวเกี่ยวกับ other stuff ที่น่าสนใจ ให้ทุกคน ๆ ได้ศึกษาไปพร้อม ๆ กัน เพราะว่า nostr ไม่ได้มีแค่โน๊ต </p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<p><strong>" ผมตื่นเต้นที่จะประกาศเปิดตัว NWS ครั้งแรก นี่เป็นคำตอบของการเชื่อมต่อออกไปยังโลกของอินเตอร์เน็ต โดยใช้ NOSTR เข้าไปแทรกระหว่าง transport layer และ network layer ที่อยู่บน TCP/IP โมเดล NWS นั้นจะเข้ามาช่วยให้การสื่อสารระหว่างอุปกรณ์ต่างๆ ให้เป็นไปอย่างราบรื่น มีความเป็นส่วนตัวเพิ่มขึ้น และทำให้เราสามารถท่องโลกของอินเตอร์เน็ตโดยไม่จำเป็นต้องใช้ Public IP "</strong> -asmogo </p>
<h2>NostrWebServices (NWS) คืออะไร?</h2>
<p>NWS คือการนำ Nostr เข้ามาช่วยในการเข้าถึงบริการของเว็บไซต์ต่าง ๆ โดยยังสามารถส่งข้อมูลขึ้นไปยัง transport layer บน TCP/IP ซึ่งด้วยวิธีนี้เองเลยทำให้เราสามารถสร้างการเชื่อมต่อได้โดยไม่จำเป็นต้องมี Public IP โดยส่วนที่จำเป็นหลัก ๆ ในการทำงานนี้เราจำเป็นต้องเตรียม</p>
<ul>
<li><p><strong>Entry node</strong>: SOCKS5 proxy ที่คอยส่งต่อ TCP packets ที่เข้ารหัสผ่านทาง event ของ Nostr ก่อนส่งส่งผ่านรีเลย์ต่าง ๆ ไปยัง Exit node</p>
</li>
<li><p><strong>Exit node</strong>:  TCP reverse proxy ที่คอยรอรับข้อมูลมาจาก Entry node และส่งต่อข้อมูลต่าง ๆ ไปยังบริการอื่น ๆ ต่อไป</p>
</li>
</ul>
<p><img src="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1726136393181-YAKIHONNES3.png" alt="image"></p>
<p>ในส่วนของการทำงานนั้นสามารถดูได้จากในรูปที่ได้แนบไว้ข้างต้นได้เลย<br>อย่างที่เห็นเลยว่ามันเริ่มจากแอพต่าง ๆ เหมือนที่เรามีการใช้งานกันอยู่ในปัจจุบัน เพียงแต่แทนที่เราจะส่งข้อมูลต่าง ๆ ผ่าน IP layer ตามปกติ เราสามารถส่งเข้าไปยัง Entry node และหลังจากนั้นข้อมูลจะถูกส่งผ่าน relay ต่าง ๆ ก่อนที่จะวิ่งไปยัง Exit node และ Exit node จะคอยส่งข้อมูลต่าง ๆ ไปยังบริการหลังบ้านที่เราต้องการจะเชื่อมต่อ </p>
<p>เราจะเห็นได้ว่าการทำงานของ NWS นั้น สำหรับผู้ใช้งานโดยทั่วไปแล้วแทบจะไม่แตกต่างอะไรกับในปัจจุบันเลย นั่นก็เพราะว่าเรายังทำการใช้งานแอพต่าง ๆ ตามปกติ แต่ประโยชน์ที่เราจะได้รับเพิ่มเติมนั้นคือความเป็นส่วนตัวในการใช้บริการเบื้องหลังอื่น ๆ </p>
<p>นอกจากนี้ยังมีในส่วนของ NWS domain names ใน NWS นั้นมีการรับรอง domain สองตัวนั้นคือ </p>
<ol>
<li>".nostr" ซึ่งใช้ชื่อโฮสต์เป็นกุญแจสาธารณะที่เข้ารหัสด้วย base32 และ รีเลย์ที่เข้ารหัสด้วย base32 เป็นโดเมนย่อย</li>
<li>"nprofiles" ซึ่งเป็นการผสมผสานกันระหว่างกุญแจสาธารณะของNostrและรีเลย์หลายตัว</li>
</ol>
<p>ซึ่งโดเมนทั้งสองประเภทจะถูกสร้างและปรากฏอยู่บนคอนโซลเมื่อเริ่มต้นใช้งาน</p>
<h2>หัวใจหลักในการทำงานของ NWS</h2>
<p>อย่างที่ได้กล่าวไว้ข้างต้นว่า NWS เข้ามาช่วยเหลือในการเพิ่มความเป็นส่วนตัวได้ แล้วถ้าเราไม่ได้ต้องการเข้ารหัส หรือถ้าเราอยากจะเปิด Entry node แล้วเราไม่ต้องการให้คนที่จะเชื่อมต่อเข้ามาเข้ารหัสข้อมูลเราสามารถทำได้เช่นกัน โดยทั้งสองระบบที่ NWS ทำได้มีดังนี้</p>
<ul>
<li><p>แบบไม่เข้ารหัส: เราจำเป็นต้องรันโหนดไว้ในเครื่องที่เราใช้รัน client แล้วแปลง client ให้ส่งข้อความใส่โหนดปลายทางตรง ๆ</p>
</li>
<li><p>แบบเข้ารหัส เริ่มจากการเชื่อมไปที่โหนดที่ต้องการ (อารมณ์ ssh เข้าไป) แต่วิธีนี้ยังติดที่บางเว็บที่เป็น https จะเชื่อมไม่ได้หาก cert ของโหนดที่เราเชื่อมมีปัญหา ส่วนข้อมูลที่ส่งจะถูก encrypt ไว้ด้วย Sphinx (เข้ารหัสแบบหนึ่งในมาตรฐาน RSA) ฉนั้นมั่นใจได้ว่าโหนดที่เราไปยืมจมูกเขาหายใจก็ไม่รู้ว่าเราส่งอะไรไป</p>
</li>
</ul>
<h2>การตรวจสอบตัวตนของเซิร์ฟเวอร์ปลายทาง</h2>
<p>การตรวจสอบตัวตนของเซิร์ฟเวอร์ปลายทางของ NWS ทำโดยการใช้ประโยชน์จาก nostr โดยให้โหนดปลายทางปล่อย cert (TLS) บน nostr และเซ็นรับรองด้วยตนเองและอณุญาติให้ไคลเอนต์สามารถดึงใบรับรองนี้มาก่อนเชื่อมต่อกับโหนดที่เป็นจุดเริ่มที่เราใช้</p>
<p>และนอกจากนี้ในอนาคตของการพัฒนา NWS กำลังพัฒนาให้ NWS สามารถกำหนดให้โหนดปลายทางสามารถกำหนดค่าให้เข้าถึงอินเทอร์เน็ตได้ (ไม่ใช่แค่บริการภายใน) ทำให้ NWS ทำงานคล้าย VPN โดยสามารถเข้าเว็บไซต์ปกติได้ เช่น พิมพ์ "https google dot com" ก็เข้า google ได้</p>
<p>และทั้งหมดที่กล่าวไว้ข้างต้นเป็นเพียงการเริ่มต้น ยังมีคุณสมบัติอย่างอื่นอีกมากมายที่จะเข้ามาปรับปรุงปัญหาต่าง ๆ ในการใช้งานอินเตอร์เน็ต โดยส่วนตัวผมรู้สึกตื่นเต้นกับอนาคตของ NWS มาก ๆ และคาดหวังที่จะได้เห็นคนหันมาให้ความสนใจและใช้งานมัน ทั้งนี้หากใครอยากทดลองใช้งานก็สามารถติดตามได้ที่ </p>
<p>   GitHub: <np-embed url="https://github.com/asmogo/nws"><a href="https://github.com/asmogo/nws">https://github.com/asmogo/nws</a></np-embed></p>
<h2>ส่งท้าย</h2>
<p>สำหรับ series nOStr ผมตั้งใจจะหาเรื่องราวเกี่ยวกับ other stuff ที่น่าสนใจ ให้ทุกคน ๆ ได้ศึกษาไปพร้อม ๆ กัน เพราะว่า nostr ไม่ได้มีแค่โน๊ต </p>
]]></itunes:summary>
      <itunes:image href="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1726139805814-YAKIHONNES3.jpg"/>
      </item>
      
      <item>
      <title><![CDATA[การขยายตัวของ Nostr และอนาคตของรีเลย์]]></title>
      <description><![CDATA[อนาคตของ Nostr ยังกระจายศูนย์ได้อยู่หรือไม่ การจัดการปัญหาของสแปม และปัญหาของการขยายตัวของระบบ ]]></description>
             <itunes:subtitle><![CDATA[อนาคตของ Nostr ยังกระจายศูนย์ได้อยู่หรือไม่ การจัดการปัญหาของสแปม และปัญหาของการขยายตัวของระบบ ]]></itunes:subtitle>
      <pubDate>Mon, 02 Sep 2024 04:15:57 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/da6j4xfhegep-kxqoqfoi/</link>
      <comments>https://learnbn.npub.pro/post/da6j4xfhegep-kxqoqfoi/</comments>
      <guid isPermaLink="false">naddr1qq25gcfkdg68sejgg4rk2updddv9zmm3geh5jq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wwue65p</guid>
      <category>ลองฟอร์มของไดโน</category>
      
        <media:content url="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1725250559344-YAKIHONNES3.png" medium="image"/>
        <enclosure 
          url="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1725250559344-YAKIHONNES3.png" length="0" 
          type="image/png" 
        />
      <noteId>naddr1qq25gcfkdg68sejgg4rk2updddv9zmm3geh5jq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wwue65p</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<h2>การขยายตัวของ Nostr</h2>
<p>อย่างที่เราทราบกันอยู่แล้ว Nostr เป็นเครือข่ายที่กระจายศูนย์ และมีความสามารถในการต่อต้านการเซ็นเซอร์และควบคุมผู้ใช้งานได้เป็นอย่างมาก แต่เมื่อเครือข่ายของ Nostr ขยายใหญ่ขึ้น คำถามเกี่ยวกับความยั่งยืนและความสามารถในการทนทานการแทรกแซงรวมไปถึงความสามารถในการกระจายศูนย์จะยังคงสามารถทำได้อย่างที่เป็นอยู่ตอนนี้หรือไม่? เนื่องจากทั้งหมดที่กล่าวมานั้นเกี่ยวกับความสามารถของรีเลย์ทั้งสิ้น ดังนั้นอนาคตของรีเลย์จึงเป็นสิ่งที่ต้องคำนึงเป็นอย่างมาก</p>
<h2>ข้อกังวลของรีเลย์ต่าง ๆ ในปัจจุบัน</h2>
<p>ข้อกังวลหลัก ๆ ประการแรกของรีเลย์คือ การรวมศูนย์จริงอยู่ที่เหล่าผู้ใช้งานบน Nostr นั้นสามารถที่จะเลือกรีเลย์ที่ตนต้องการเชื่อมต่อ จำนวนรีเลย์ที่จะเชื่อม แต่ปัญหาของเรื่องนี้กับอยู่ที่อีกฝั่งหนึ่ง นั้นคือฝั่งของซอฟแวร์ ดังที่ได้เห็นได้ในปัจจุบัน relay จำนวนมากในระบบเลือกใช้ software เพียงไม่กี่ตัวเท่านั้น ซึ่งสิ่งนี้เองที่อาจทำให้เกิดการครอบงำเครือข่าย และก่อให้เกิดความเสี่ยงต่อค่านิยมหลักของ Nostr การครอบงำนี้อาจนำไปสู่การเซนเซอร์ การเปลี่ยนแปลงกฎโดยพลการ และหากยังดำเนินไปในทางนี้ซอฟแวร์นั้นจะกลายเป็นจุดอ่อนใหญ่ของระบบ Nostr</p>
<p>ข้อกังวลอีกประการหนึ่งคือการป้องกันสแปม สิ่งนี้เป็นเรื่องที่น่ากังวลเนื่องจากหาก Nostr ยังสามารถขยายตัวต่อไปเรื่อย ๆ แน่นอนว่ามันจะไปดึงดูดเหล่าผู้ที่ไม่หวังดีเข้ามาในระบบด้วยอย่างหลีกเลี่ยงไม่ได้ด้วยเช่นกัน และหากเราดูวิธีที่เหล่า social media ต่าง ๆ เลือกใช้ในการป้องกันอย่างการกรองข้อมูลแบบรวมศูนย์ แน่นอนละว่าบน Nostr เราไม่สามารถใช้วิธีนั้นได้ เพราะ Nostr ต้องการการกระจายศูนย์ โดยทางออกในปัจจุบันที่รีเลย์ต่าง ๆ เลือกใช้มีดังนี้</p>
<ul>
<li><p>รีเลย์แบบจ่ายเงิน: แน่นอนว่าวิธีนี้สามารถป้องกันสแปมได้ในระดับหนึ่งและยังเป็นรูปแบบธุรกิจที่ยั่งยืนสำหรับผู้ให้บริการรีเลย์ แต่อย่างไรก็ตามหากจำนวนเงินที่ต้องจ่ายให้กับผู้ให้บริการนั้นคุ้มค่ากับผลลัพธ์ที่ได้จากการโจมตี ก็ไม่มีเหตุผลใด ๆ ที่ผู้ประสงค์ร้ายจะทำการโจมตี และหากรีเลย์ต่าง ๆ ขึ้นค่าบริการเพื่อป้องกันสิ่งนี้ ก็จะกลายเป็นการสร้างแรงเสียดทานให้กับการขยายตัวของระบบ เนื่องจากจะส่งผลกระทบต่อผู้ใช้ทั่วไปมากกว่า</p>
</li>
<li><p>การใช้ POW: แน่นอนว่าการกำหนดให้ผู้ใช้มีการใช้พลังงานในการคำนวณก่อนโพสต์ อาจทำให้การส่งสแปมมีค่าใช้จ่ายสูงขึ้นและมีความน่าสนใจน้อยลง แต่ในปัจจุบันนี้การใช้ POW ยังไม่แพร่หลาย และยังมีการใช้แค่กับ event ที่เป็นโพสต์เท่าน้ัน ยังไม่สามารถป้องกันการหลอกลวงที่จะมาผ่านทาง DM ได้</p>
</li>
<li><p>ระบบ Web Of Trust: จริงอยู่ที่การใช้ประโยชน์จากความสัมพันธ์ที่มีอยู่และคะแนนชื่อเสียงสามารถช่วยระบุและจำกัดกิจกรรมสแปมได้ แต่การใช้วิธีนี้จะเกิดปัญหาเมื่อคุณต้องการเชื่อมต่อกับกลุ่มคนที่คุณ เหล่าคนที่คุณติดตาม และผู้ติดตามของคุณไม่ได้มีการเชื่อมต่อกันมาก่อน เนื่องจากมันจะทำให้คะแนนของบุคคลนั้น ๆ ต่ำมากจนอาจถูกจัดว่าเป็น spam รวมทั้งบอทต่าง ๆ ที่ช่วยในการให้บริการบางอย่างก็อาจจะถูกจัดเป็นสแปมเช่นกัน</p>
</li>
</ul>
<p>นอกจากนี้ยังมีความเสี่ยงในเรื่องของการใช้ประโยชน์จากข้อมูลที่อาจจะเกิดขึ้นได้ในรีเลย์ขนาดใหญ่และฟรี หากผู้ใช้หันไปใช้รีเลย์เหล่านี้เพื่อความสะดวก ก็อาจจะทำให้เกิดข้อกังวลเกี่ยวกับความเป็นส่วนตัวและศักยภาพในการหาประโยชน์จากข้อมูลได้</p>
<p>อย่างไรก็ตาม ก็ยังมีวิธีต่าง ๆ ในการพยายามแก้ไขปัญหานี้อีกมากมายไม่ว่าจะเป็นการทำ outbox-relay ซึ่งทางไคล์เอนต์จะเชื่อมต่อกับรีเลย์ต่าง ๆ และรับ/ส่งข้อมูลประเภทต่าง ๆ ไปยังรีเลย์ที่แตกต่างกัน ตามที่ผู้ใช้กำหนดไว้ ซึ่งวิธีนี้เองก็ได้เข้ามามีบทบาทสำคัญในการลดการรวมศูนย์ และต่อต้านการเซ็นเซอร์ </p>
<h2>ความเห็นส่วนตัว</h2>
<p>บางทีปัญหาต่าง ๆ เหล่านี้อาจจะถูกแก้ง่าย ๆ ด้วยวิธีออร์แกนิกอย่างการแข่งขันกันภายในระบบนิเวศของรีเลย์ โดยเหล่าผู้ใช้จะเรียกละทิ้งรีเลย์ที่ไม่ซื่อสัตว์ ขาดซึ่งความน่าเชื่อถือ รวมถึงการปล่อยให้มีสแปมจำนวนมากเข้ามาใช้งาน ผู้ใช้งานจะทำการนำรีเลย์เหล่านั้นออกไปเอง </p>
<p>แต่ทั้งนี้ก็ยังมีปัญหาอื่น ๆ อีกประปรายในระบบนิเวศของ Nostr อย่างเช่นในปัจจุบันนี้ถึง Nostr จะยอดเยี่ยมในการใช้งานแบบชั่วคราว การสื่อสารของนักพัฒนาและการประสานงานชุมชน ซึ่งความคงอยู่ของข้อมูลมีความสำคัญน้อยกว่า อย่างไรก็ตาม ความท้าทายที่แท้จริงอยู่ที่การทำซ้ำความสำเร็จนี้สำหรับข้อมูลถาวรและการสร้างความมั่นใจในความยั่งยืนในระยะยาว</p>
<p>แต่ทั้งนี้ทั้งนั้นผมมองว่าอนาคตของ Nostr ขึ้นอยู่กับการหาจุดสมดุลที่เหมาะสมระหว่างการกระจายอำนาจ ความสามารถในการขยายตัว และความยั่งยืน แม้ว่าข้อกังวลเกี่ยวกับการรวมศูนย์ของรีเลย์และสแปมจะเป็นสิ่งที่ถูกต้อง แต่ความเต็มใจของชุมชนในการอภิปรายและสำรวจแนวทางแก้ไข เช่น รูปแบบ outbox-relay รูปแบบธุรกิจที่หลากหลาย และการป้องกันทางเทคนิค เป็นแรงบันดาลใจให้เกิดการมองโลกในแง่ดีสำหรับเครือข่ายสังคมออนไลน์ที่แข็งแกร่งและกระจายอำนาจอย่างแท้จริง</p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<h2>การขยายตัวของ Nostr</h2>
<p>อย่างที่เราทราบกันอยู่แล้ว Nostr เป็นเครือข่ายที่กระจายศูนย์ และมีความสามารถในการต่อต้านการเซ็นเซอร์และควบคุมผู้ใช้งานได้เป็นอย่างมาก แต่เมื่อเครือข่ายของ Nostr ขยายใหญ่ขึ้น คำถามเกี่ยวกับความยั่งยืนและความสามารถในการทนทานการแทรกแซงรวมไปถึงความสามารถในการกระจายศูนย์จะยังคงสามารถทำได้อย่างที่เป็นอยู่ตอนนี้หรือไม่? เนื่องจากทั้งหมดที่กล่าวมานั้นเกี่ยวกับความสามารถของรีเลย์ทั้งสิ้น ดังนั้นอนาคตของรีเลย์จึงเป็นสิ่งที่ต้องคำนึงเป็นอย่างมาก</p>
<h2>ข้อกังวลของรีเลย์ต่าง ๆ ในปัจจุบัน</h2>
<p>ข้อกังวลหลัก ๆ ประการแรกของรีเลย์คือ การรวมศูนย์จริงอยู่ที่เหล่าผู้ใช้งานบน Nostr นั้นสามารถที่จะเลือกรีเลย์ที่ตนต้องการเชื่อมต่อ จำนวนรีเลย์ที่จะเชื่อม แต่ปัญหาของเรื่องนี้กับอยู่ที่อีกฝั่งหนึ่ง นั้นคือฝั่งของซอฟแวร์ ดังที่ได้เห็นได้ในปัจจุบัน relay จำนวนมากในระบบเลือกใช้ software เพียงไม่กี่ตัวเท่านั้น ซึ่งสิ่งนี้เองที่อาจทำให้เกิดการครอบงำเครือข่าย และก่อให้เกิดความเสี่ยงต่อค่านิยมหลักของ Nostr การครอบงำนี้อาจนำไปสู่การเซนเซอร์ การเปลี่ยนแปลงกฎโดยพลการ และหากยังดำเนินไปในทางนี้ซอฟแวร์นั้นจะกลายเป็นจุดอ่อนใหญ่ของระบบ Nostr</p>
<p>ข้อกังวลอีกประการหนึ่งคือการป้องกันสแปม สิ่งนี้เป็นเรื่องที่น่ากังวลเนื่องจากหาก Nostr ยังสามารถขยายตัวต่อไปเรื่อย ๆ แน่นอนว่ามันจะไปดึงดูดเหล่าผู้ที่ไม่หวังดีเข้ามาในระบบด้วยอย่างหลีกเลี่ยงไม่ได้ด้วยเช่นกัน และหากเราดูวิธีที่เหล่า social media ต่าง ๆ เลือกใช้ในการป้องกันอย่างการกรองข้อมูลแบบรวมศูนย์ แน่นอนละว่าบน Nostr เราไม่สามารถใช้วิธีนั้นได้ เพราะ Nostr ต้องการการกระจายศูนย์ โดยทางออกในปัจจุบันที่รีเลย์ต่าง ๆ เลือกใช้มีดังนี้</p>
<ul>
<li><p>รีเลย์แบบจ่ายเงิน: แน่นอนว่าวิธีนี้สามารถป้องกันสแปมได้ในระดับหนึ่งและยังเป็นรูปแบบธุรกิจที่ยั่งยืนสำหรับผู้ให้บริการรีเลย์ แต่อย่างไรก็ตามหากจำนวนเงินที่ต้องจ่ายให้กับผู้ให้บริการนั้นคุ้มค่ากับผลลัพธ์ที่ได้จากการโจมตี ก็ไม่มีเหตุผลใด ๆ ที่ผู้ประสงค์ร้ายจะทำการโจมตี และหากรีเลย์ต่าง ๆ ขึ้นค่าบริการเพื่อป้องกันสิ่งนี้ ก็จะกลายเป็นการสร้างแรงเสียดทานให้กับการขยายตัวของระบบ เนื่องจากจะส่งผลกระทบต่อผู้ใช้ทั่วไปมากกว่า</p>
</li>
<li><p>การใช้ POW: แน่นอนว่าการกำหนดให้ผู้ใช้มีการใช้พลังงานในการคำนวณก่อนโพสต์ อาจทำให้การส่งสแปมมีค่าใช้จ่ายสูงขึ้นและมีความน่าสนใจน้อยลง แต่ในปัจจุบันนี้การใช้ POW ยังไม่แพร่หลาย และยังมีการใช้แค่กับ event ที่เป็นโพสต์เท่าน้ัน ยังไม่สามารถป้องกันการหลอกลวงที่จะมาผ่านทาง DM ได้</p>
</li>
<li><p>ระบบ Web Of Trust: จริงอยู่ที่การใช้ประโยชน์จากความสัมพันธ์ที่มีอยู่และคะแนนชื่อเสียงสามารถช่วยระบุและจำกัดกิจกรรมสแปมได้ แต่การใช้วิธีนี้จะเกิดปัญหาเมื่อคุณต้องการเชื่อมต่อกับกลุ่มคนที่คุณ เหล่าคนที่คุณติดตาม และผู้ติดตามของคุณไม่ได้มีการเชื่อมต่อกันมาก่อน เนื่องจากมันจะทำให้คะแนนของบุคคลนั้น ๆ ต่ำมากจนอาจถูกจัดว่าเป็น spam รวมทั้งบอทต่าง ๆ ที่ช่วยในการให้บริการบางอย่างก็อาจจะถูกจัดเป็นสแปมเช่นกัน</p>
</li>
</ul>
<p>นอกจากนี้ยังมีความเสี่ยงในเรื่องของการใช้ประโยชน์จากข้อมูลที่อาจจะเกิดขึ้นได้ในรีเลย์ขนาดใหญ่และฟรี หากผู้ใช้หันไปใช้รีเลย์เหล่านี้เพื่อความสะดวก ก็อาจจะทำให้เกิดข้อกังวลเกี่ยวกับความเป็นส่วนตัวและศักยภาพในการหาประโยชน์จากข้อมูลได้</p>
<p>อย่างไรก็ตาม ก็ยังมีวิธีต่าง ๆ ในการพยายามแก้ไขปัญหานี้อีกมากมายไม่ว่าจะเป็นการทำ outbox-relay ซึ่งทางไคล์เอนต์จะเชื่อมต่อกับรีเลย์ต่าง ๆ และรับ/ส่งข้อมูลประเภทต่าง ๆ ไปยังรีเลย์ที่แตกต่างกัน ตามที่ผู้ใช้กำหนดไว้ ซึ่งวิธีนี้เองก็ได้เข้ามามีบทบาทสำคัญในการลดการรวมศูนย์ และต่อต้านการเซ็นเซอร์ </p>
<h2>ความเห็นส่วนตัว</h2>
<p>บางทีปัญหาต่าง ๆ เหล่านี้อาจจะถูกแก้ง่าย ๆ ด้วยวิธีออร์แกนิกอย่างการแข่งขันกันภายในระบบนิเวศของรีเลย์ โดยเหล่าผู้ใช้จะเรียกละทิ้งรีเลย์ที่ไม่ซื่อสัตว์ ขาดซึ่งความน่าเชื่อถือ รวมถึงการปล่อยให้มีสแปมจำนวนมากเข้ามาใช้งาน ผู้ใช้งานจะทำการนำรีเลย์เหล่านั้นออกไปเอง </p>
<p>แต่ทั้งนี้ก็ยังมีปัญหาอื่น ๆ อีกประปรายในระบบนิเวศของ Nostr อย่างเช่นในปัจจุบันนี้ถึง Nostr จะยอดเยี่ยมในการใช้งานแบบชั่วคราว การสื่อสารของนักพัฒนาและการประสานงานชุมชน ซึ่งความคงอยู่ของข้อมูลมีความสำคัญน้อยกว่า อย่างไรก็ตาม ความท้าทายที่แท้จริงอยู่ที่การทำซ้ำความสำเร็จนี้สำหรับข้อมูลถาวรและการสร้างความมั่นใจในความยั่งยืนในระยะยาว</p>
<p>แต่ทั้งนี้ทั้งนั้นผมมองว่าอนาคตของ Nostr ขึ้นอยู่กับการหาจุดสมดุลที่เหมาะสมระหว่างการกระจายอำนาจ ความสามารถในการขยายตัว และความยั่งยืน แม้ว่าข้อกังวลเกี่ยวกับการรวมศูนย์ของรีเลย์และสแปมจะเป็นสิ่งที่ถูกต้อง แต่ความเต็มใจของชุมชนในการอภิปรายและสำรวจแนวทางแก้ไข เช่น รูปแบบ outbox-relay รูปแบบธุรกิจที่หลากหลาย และการป้องกันทางเทคนิค เป็นแรงบันดาลใจให้เกิดการมองโลกในแง่ดีสำหรับเครือข่ายสังคมออนไลน์ที่แข็งแกร่งและกระจายอำนาจอย่างแท้จริง</p>
]]></itunes:summary>
      <itunes:image href="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1725250559344-YAKIHONNES3.png"/>
      </item>
      
      <item>
      <title><![CDATA[Nostr101 ไอเจ้านกกระจอกเทศมันมีอะไรดี]]></title>
      <description><![CDATA[Nostr101 รวมเนื้อหาเบื้องต้นบน Nostr ที่ควรรู้]]></description>
             <itunes:subtitle><![CDATA[Nostr101 รวมเนื้อหาเบื้องต้นบน Nostr ที่ควรรู้]]></itunes:subtitle>
      <pubDate>Mon, 19 Aug 2024 02:48:23 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/i1famkjy7sijovh9e4p_a/</link>
      <comments>https://learnbn.npub.pro/post/i1famkjy7sijovh9e4p_a/</comments>
      <guid isPermaLink="false">naddr1qq2kjvtxg9kkk6nexafkj6j02e5rj3f5wp0kzq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wfnwum3</guid>
      <category>ลองฟอร์มของไดโน</category>
      
        <media:content url="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1724035705683-YAKIHONNES3.png" medium="image"/>
        <enclosure 
          url="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1724035705683-YAKIHONNES3.png" length="0" 
          type="image/png" 
        />
      <noteId>naddr1qq2kjvtxg9kkk6nexafkj6j02e5rj3f5wp0kzq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wfnwum3</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<h2>Nostr: โปรโตคอลทางเลือกใหม่สำหรับโซเชียลมีเดียที่เป็นอิสระ ปลอดภัย และไร้การควบคุม</h2>
<p>Nostr คือโปรโตคอลแบบเปิดที่เรียบง่าย ซึ่งช่วยให้สามารถสร้างโซเชียลมีเดียระดับโลกที่กระจายอำนาจและป้องกันการเซ็นเซอร์ได้ </p>
<p>จากที่กล่าวข้างต้น เราสามารถพูดได้ว่า Nostr นั้นถูกออกแบบมาให้ใช้งานง่าย โดยมีเป้าหมายหลัก ๆ เพื่อสร้างเครือข่ายโซเชียลระดับโลกที่ปราศจากการเซ็นเซอร์ แล้วทำไมมันถึงทำอย่างนั้นได้? ในจุดนี้เราก็ต้องมาเจาะดูคุณสมบัติหลัก ๆ ของโปรโตคอลที่เรียกว่า Nostr กันก่อน:</p>
<p><strong>เรียบง่าย</strong></p>
<ul>
<li><p>โปรโตคอลนี้ใช้โครงสร้างข้อมูลแบบ Event Object ที่เรียบง่ายและยืดหยุ่น (ซึ่งส่งเป็น JSON ธรรมดา) และใช้การเข้ารหัสแบบ Elliptic-curve มาตรฐานสำหรับคีย์และลายเซ็น</p>
</li>
<li><p>ช่องทางการสื่อสารที่รองรับเพียงอย่างเดียวคือการเชื่อมต่อ WebSockets จากไคลเอนต์ไปยังรีเลย์</p>
</li>
<li><p>การออกแบบนี้ทำให้ง่ายต่อการพัฒนาไม่ว่าจะไคลเอนต์หรือรีเลย์ และยังช่วยส่งเสริมความหลากหลายของซอฟต์แวร์</p>
</li>
</ul>
<p><strong>ยืดหยุ่น</strong></p>
<ul>
<li><p>เนื่องจาก Nostr ไม่ได้พึ่งพาเซิร์ฟเวอร์ที่เชื่อถือได้เพียงจำนวนหยิบมือ สำหรับการเคลื่อนย้ายหรือจัดเก็บข้อมูล แต่ใช้เซิร์ฟเวอร์จำนวนมหาศาลและกระจายตัวอยู่ทั่วโลก จึงมีความยืดหยุ่นสูง และมีการกระจายศูนย์อย่างแท้จริง</p>
</li>
<li><p>โปรโตคอลนี้ถูกออกแบบมาโดยคำนึงถึงความเป็นไปได้ที่รีเลย์จะหายไป และอนุญาตให้ผู้ใช้เชื่อมต่อและเผยแพร่ข้อมูลไปยังรีเลย์จำนวนมากได้ตามต้องการ และยังสามารถเปลี่ยนแปลงได้ตลอดเวลาอีกด้วย</p>
</li>
</ul>
<p><strong>ตรวจสอบได้</strong></p>
<ul>
<li>เนื่องจากบัญชี Nostr ใช้การเข้ารหัสแบบ PKE จึงง่ายต่อการตรวจสอบว่าข้อความถูกส่งมาจากผู้ใช้ที่ระบุจริงหรือไม่</li>
</ul>
<p>เช่นเดียวกับ HTTP หรือ TCP-IP Nostr เป็นโปรโตคอลหรือมาตรฐานแบบเปิดที่ทุกคนสามารถนำไปสร้างต่อยอดได้ มันไม่ใช่แอปหรือบริการที่คุณจำเป็นต้องลงทะเบียน</p>
<h2>แล้วทำไมเราถึงต้องการ Nostr?</h2>
<p>ถึงในปัจจุบันโซเชียลมีเดียจะได้พัฒนามาเป็นช่องทางสำคัญในการไหลเวียนของข้อมูลทั่วโลก กลายเป็นช่องทางหลักในการติดต่อสื่อสาร แต่น่าเสียดายที่ระบบโซเชียลมีเดียในปัจจุบันของเรานั้นมีข้อบกพร่องมากมาย:</p>
<ol>
<li>ใช้ความสนใจของคุณเพื่อขายโฆษณา</li>
<li>ใช้เทคนิคแปลกๆ เพื่อทำให้คุณเสพติด (อ้างอิงจากข้อ 1)</li>
<li>ตัดสินใจว่าจะแสดงเนื้อหาใดให้คุณเห็นโดยใช้อัลกอริทึมลับที่คุณไม่สามารถตรวจสอบหรือเปลี่ยนแปลงได้</li>
<li>ควบคุมอย่างเต็มที่ว่าใครสามารถเข้าร่วมและใครถูกเซ็นเซอร์</li>
<li>เต็มไปด้วยสแปมและบอท</li>
</ol>
<p>ด้วยข้อจำกัดเหล่านี้ Nostr จึงเป็นทางเลือกที่น่าสนใจในการสร้างโซเชียลมีเดียที่เป็นอิสระ ปลอดภัย และไร้การควบคุม</p>
<h2>องค์ประกอบของโปรโตคอลที่ชื่อว่า Nostr</h2>
<p>หลังจากได้ทำความรู้จัก Nostr กันไปแล้วเมื่อคราวก่อน คราวนี้เรามาเจาะดูองค์ประกอบของโปรโตคอลนี้กันดีกว่า</p>
<p><strong>Keys ระบบบัญชีผู้ใช้และรหัสผ่านสำหรับ Nostr</strong></p>
<ul>
<li><p>บัญชี Nostr แต่ละบัญชีจะใช้คู่กุญแจสาธารณะ/ส่วนตัว (Public/Private Key ) เปรียบเทียบง่าย ๆ คือ กุญแจสาธารณะของคุณคือชื่อผู้ใช้ และกุญแจส่วนตัวก็เป็นรหัสผ่าน แต่ว่า ก็มีข้อแตกต่างที่สำคัญอยู่ นั่นคือ กุญแจส่วนตัวของคุณนั้นจะไม่สามารถรีเซ็ตได้หากเกิดการสูญหายขึ้น คุณจะเสียบัญชีนั้นไปตลอดกาล</p>
</li>
<li><p>โดยทั่วไปแล้ว กุญแจสาธารณะจะแสดงเป็นข้อความที่ขึ้นต้นด้วย npub1 และกุญแจส่วนตัวจะขึ้นต้นด้วย nsec1</p>
</li>
<li><p>ทั้งนี้คุณควรที่จะตรวจสอบให้แน่ใจว่าคุณได้เก็บกุญแจส่วนตัวของคุณไว้ในที่ปลอดภัย เช่น โปรแกรมจัดการรหัสผ่านอย่างเช่น Bitwarden</p>
</li>
</ul>
<p><strong>โปรโตคอลกับไคลเอนต์ ต่างกันอย่างไร?</strong></p>
<p>Nostr เองเป็นเพียงโปรโตคอล หมายความว่า Nostr นั้นเป็นเพียงกระบวนการที่ตกลงกันไว้สำหรับการส่งข้อความผ่านอินเทอร์เน็ต (เหมือนข้อกำหนด)</p>
<p>ซึ่งการที่คุณจะเข้าถึง Nostr (โปรโตคอล) นั้น ผู้ใช้ส่วนใหญ่จะใช้งานผ่านไคลเอนต์  ซึ่งตัวของไคลเอนต์นั้นอาจเป็นเว็บ แอปพลิเคชันเดสก์ท็อป หรือ แอปพลิเคชันมือถือ โดยไคลเอนต์สามารถดึงข้อมูลจากรีเลย์ และสร้างข้อมูลใหม่ และส่งข้อมูลนั้นไปยังรีเลย์เพื่อให้ผู้ใช้คนอื่น ๆ สามารถเรียกอ่าน ข้อมูลนั้น ๆ ได้ โดย "ข้อมูล" เพียงรูปแบบเดียวที่มีอยู่ใน Nostr คือสิ่งที่เราเรียกกันว่า event</p>
<p><strong>การพิสูจน์ความเป็นเจ้าของข้อมูลบน Nostr</strong></p>
<p>บน Nostr นั้นการพิสูจน์ตัวตนเป็นเรื่องที่ง่ายมากเนื่องจากทุก ๆ event ที่เกิดขึ้น <strong>จำเป็น</strong>ต้องมีลายเซ็นดิจิทัล (Digital Signature) โดยลายเซ็นนั้นจะช่วยให้มั่นใจได้ว่า ใครเป็นผู้สร้าง event นั้น ๆ ขึ้นมา โดยการพิสูจน์ทางคณิตศาสตร์</p>
<p>โดยในการสร้างลายเซ็นแต่ละครั้ง ไคลเอนต์จะจำเป็นต้องใช้กุญแจส่วนตัวของคุณ โดยทั่วไปแล้ว แอปพลิเคชันเจะมีที่ให้คุณใส่กุญแจส่วนตัวของคุณ เมื่อเปิดแอปพลิเคชันครั้งแรก พวกเขาสามารถคำนวณกุญแจสาธารณะของคุณได้จากกุญแจส่วนตัวเช่นกัน</p>
<p>ส่วนในกรณีที่คุณใช้งานผ่านเว็บแอป ผมไม่แนะนำให้ใส่กุญแจส่วนตัวลงไป แต่แนะนำให้ใช้ส่วนขยายของเบราว์เซอร์ ที่ใช้งานฟังก์ชันที่เกี่ยวข้องกับ Nostr ซึ่งอนุญาตให้เว็บไคลเอ็นต์ส่ง event ที่ยังไม่ถูกเซ็นมาให้ส่วนขยายและส่วนขยายจะทำหน้าที่เซ็น สำหรับวิธีนี้ เว็บไคลเอ็นต์ต่าง ๆ ไม่จำเป็นต้องรู้กุญแจส่วนตัวของคุณ แต่คุณก็ยังสามารถลงนามใน event ต่าง ๆ ได้ตามปกติ โดยส่วนขยายที่ได้รับความนิยมก็จะเป็น <strong>Flamingo</strong>, <strong>Alby</strong> และ <strong>nos2x</strong> </p>
<h2>ไคลเอนต์ &amp; รีเลย์</h2>
<p><strong>ไคลเอนต์คืออะไร?</strong></p>
<p>หากจะอธิบายให้เห็นภาพอยากให้มองว่าไคลเอ็นต์ Nostr นั้นเป็นเหมือนกับแอปที่คุณใช้งานเพื่อเข้าถึง Twitter, Facebook, youtube เป็นต้น พวกมันคือ แอปพลิเคชัน, เว็บแอป ที่เชื่อมต่อคุณกับโลกของ Twitter, Facebook, youtube โดยตัวของไคลเอนต์ใน Nostr เองก็เปรียบเสมือนแอปต่าง ๆ ที่คุณใช้ดูหน้าฟีดนั่นเอง แต่ข้อดีของ Nostr ที่เหนือแอปพลิเคชันอื่น ๆ คือความเรียบง่ายและยืดหยุ่น ส่งผลให้ไคลเอ็นต์แต่ละตัวมีวิธีนำเสนอและใช้งานที่แตกต่างกันไป บางไคลเอ็นต์อาจออกแบบให้ใช้งานง่ายเหมือน Twitter บางตัวเน้นให้เห็นบทบาทสำคัญของรีเลย์ หรือโหนดที่กระจายข้อมูลอยู่ทั่วโลก บางตัวใช้ระบบอัลกอริทึมเพื่อให้แน่ใจว่าข้อมูลไม่ถูกปิดกั้น โดยไม่ทำให้ผู้ใช้งานรู้สึกยุ่งยาก</p>
<p><strong>เรียบง่ายและยืดหยุ่น?</strong></p>
<p>เนื่องจากการออกแบบของโปรโตคอลที่ทำการแยกข้อมูลของผู้ใช้ทั้งหมดออกจากไคลเอนต์ ทำให้ตัวของผู้ใช้งานเองนั้นมีอิสระเต็มที่ที่จะเลือกใช้ไคลเอนต์ต่าง ๆ เพื่อเข้าใช้งาน Nostr และแน่นอนว่า ผู้ใช้งานสามารถสลับหรือลงชื่อเข้าใช้ ไคลเอ็นต์ได้หลายตัวตามต้องการ ตราบใดที่ไคลเอ็นต์ทั้งหมดเชื่อมต่อกับชุดรีเลย์เดียวกัน คุณก็จะเห็นข้อมูลเดียวกันในทุก ๆ ไคลเอ็นต์</p>
<p><strong>ลงชื่อเข้าใช้ ไคลเอ็นต์หลาย ๆ ตัวแล้วจะกระทบต่อความปลอดภัยของแอคเคาร์ไหม?</strong></p>
<p>คำตอบของคำถามนี้นั้นขึ้นอยู่กับวิธีการที่คุณลงชื่อเข้าใช้ หากคุณลงชื่อเข้าใช้ด้วยกุญแจส่วนตัว ถึงแม้ว่าไคลเอ็นต์ส่วนใหญ่จะพยายามรักษาความปลอดภัยของกุญแจส่วนตัวอย่างดีที่สุด แต่ด้วยข้อจำกัดของซอฟต์แวร์ ย่อมมีความเสี่ยงที่จะเกิดช่องโหว่ การเจาะระบบ และข้อผิดพลาด ที่อาจทำให้กุญแจส่วนตัวของคุณรั่วไหลออกไปได้ ส่วนวิธีการป้องกันเกี่ยวกับเรื่องนี้คือการใช้ส่วนขยายของเว็บเบราว์เซอร์ เพราะการเข้าสู่ระบบในไคลเอนต์ต่าง ๆ ผ่านส่วนขยายนั้นจะใช้เพียงกุญแจสาธารณะในการเข้าสู่ระบบและทุกครั้งที่เราต้องการจะโพสต์หรือสร้าง event บน Nostr ไคลเอนต์จะทำการร่าง event นั้น ๆ และเว้นช่องของลายเซ็นเอาไว้จากนั้นเราจะต้องทำการเซ็นผ่านส่วนขยาย ด้วยวิธีนี้ทำให้กุญแจส่วนตัวของเราไม่หลุดออกไปไหนตลอดการใช้งาน</p>
<p><strong>รีเลย์คืออะไร?</strong></p>
<p>รีเลย์เปรียบเสมือนเซิร์ฟเวอร์ที่อยู่เบื้องหลังของ Nostr และทำหน้าที่รับ event ต่าง ๆ มาจากไคลเอนต์ Nostr และอาจจะจัดเก็บและกระจายข้อความเหล่านั้นไปยังไคลเอนต์อื่น ๆ ที่มีการเชื่อมต่ออยู่</p>
<p>เทคโนโลยีของรีเลย์นั้นเปลี่ยนแปลงอย่างรวดเร็ว ดังนั้นคาดว่าจะมีการเปลี่ยนแปลงอีกมากมายในอนาคต อย่างในปัจจุบันที่มีการนำเสนอ bostr หรือ รีเลย์ที่จะคอยส่ง event ของเราต่อให้กับรีเลย์อื่น ๆ ที่มีการเชื่อมต่อ เพื่อช่วยลดภาระของไคลเอนต์ในการรับส่งข้อมูลจากหลาย ๆ รีเลย์พร้อม ๆ กัน หรืออย่างการป้องกันสแปมด้วย POW หรือประเภทที่สามารถเก็บรูปหรือวิดีโอที่มีขนาดใหญ่ได้</p>
<p>แต่สิ่งหนึ่งที่ควรทราบก็คือ การที่ Nostr นั้นพยายามจะกระจายศูนย์และเหตุผลหลัก ๆ ที่สามารถทำแบบนั้นได้ก็ขึ้นอยู่กับรีเลย์ในการจัดเก็บและดึงข้อมูล ดังนั้น หากคุณรู้สึกว่าไคลเอนต์ Nostr ของคุณทำงานช้า ส่วนใหญ่ก็มักเกิดจากรีเลย์ที่คุณกำลังเชื่อมต่ออยู่ คุณอาจลองแก้ไขปัญญาโดยการเปลี่ยนหรือเพิ่มรีเลย์อีกสองสามรายการในไคลเอนต์ที่คุณใช้</p>
<p><strong>แล้วจะสามารถหารายการรีเลย์ได้จากไหน?</strong></p>
<p>การที่เราจะหารายการรีเลย์ที่เราควรเชื่อมต่อนั้น ๆ จริงแล้ว ๆ สามารถทำได้หลายวิธี แต่วิธีที่ผมแนะนำที่สุดจะเป็นการใช้ตามคนที่เราติดตามอยู่ เพราะจะเป็นวิธีที่เราสามารถเห็น event ต่าง ๆ ของคนที่เราติดตามได้ง่ายที่สุด และเช่นเดียวกัน เพื่อน ๆ หรือคนที่เราติดตามก็จะสามารถเห็น event ของเราได้เช่นกัน และสำหรับในประเทศไทย เรามีรีเลย์ที่คนไทยส่วนใหญ่นิยมใช้กันอยู่สองอัน นั้นคือ wss://relay.siamstr.com/ และ  wss://relay.notoshi.win/ ถ้าหากว่าอยากเห็นคนไทยเยอะ ๆ บนหน้าไทม์ไลน์ ผมแนะนำเป็นอย่างยิ่งว่าควรเพิ่ม รายการรีเลย์เหล่านี้ลงไปในบัชญีหรือไคลเอนต์ต่าง ๆ ที่คุณใช้ด้วย </p>
<p>สำหรับอีกวิธีหนึ่งผมแนะนำให้เข้าไปในเว็บไซต์ nostr.watch เนื่องจากในเว็บไซต์นี้เป็นแหล่งข้อมูลที่ดีที่สุดสำหรับการค้นหาและประเมินความเร็วของรีเลย์ต่าง ๆ </p>
<p><strong>จะเกิดอะไรขึ้นถ้ารีเลย์ทั้งหมดที่ฉันเชื่อมต่ออยู่หยุดให้บริการ?</strong></p>
<p>สิ่งนี้เป็นสิ่งที่คุณต้องระวังมากที่สุดในการใช้งาน nostr เนื่องจากหากรีเลย์ทั้งหมดที่คุณเก็บข้อมูลไว้หยุดให้บริการทั้งหมดและคุณไม่มีการสำรองข้อมูล event ของคุณเก็บไว้เลย มันแปลว่าโพสต์ทั้งหมดของคุณ ผู้ติดตาม และรายการต่าง ๆ ที่คุณสรรค์สร้างไว้จะไม่สามารถกู้คืนได้ไปตลอดการ นี่จึงเป็นเหตุผลหลัก ๆ ที่ Nostr อนุญาตให้ผู้ใช้งานนั้นสามารถเชื่อมต่อกับรีเลย์ได้เป็นจำนวนมาก ก็เพื่อให้แน่ใจว่ามีข้อมูลสำรองเก็บไว้อยู่ที่ใดที่หนึ่งในระบบเสมอ แต่อย่างไรก็ตาม หากคุณต้องการที่จะมั่นใจได้ว่าข้อมูลต่าง ๆ ของคุณจะไม่ถูกเซ็นเซอร์ สิ่งที่คุณสามารถสามารถทำได้คือการใช้รีเลย์ส่วนตัวของคุณและกำหนดนโยบายต่าง ๆ ภายในรีเลย์ของคุณด้วยตัวคุณเอง</p>
<p><strong>แล้วฉันจะสามารถใช้รีเลย์ส่วนตัวได้อย่างไร?</strong></p>
<p><strong>อะแฮ่ม ๆ</strong> ขอบอกไว้ก่อนว่ามันไม่คุ้มค่ากับความยุ่งยากสำหรับคนโดยทั่ว ๆ ไป ถึงในปัจจุบันจะมีเทคโนโลยีบางตัวที่เข้ามาช่วยให้มันทำได้ง่ายขึ้นแล้วก็ตาม<br>หากคุณต้องการที่จะสำรองข้อมูลนั้น การที่จะมีรีเลย์ส่วนตัวที่ออนไลน์ตลอดเวลาอาจเป็นเรื่องที่ไม่ได้จำเป็นขนาดนั้น เนื่องจากเราสามารถใช้งานบริการอย่าง <np-embed url="https://nostrsync.live/"><a href="https://nostrsync.live/">https://nostrsync.live/</a></np-embed> ในการดาวน์โหลดข้อมูลของเราจากรีเลย์ต่าง ๆ ได้ หรือการติดตั้งรีเลย์ส่วนตัวอย่าง nostr-relay-tray: <np-embed url="https://github.com/CodyTseng/nostr-relay-tray"><a href="https://github.com/CodyTseng/nostr-relay-tray">https://github.com/CodyTseng/nostr-relay-tray</a></np-embed> ที่ช่วยให้เราสามารถมีรีเลย์ส่วนตัวที่ใช้สำหรับสำรองข้อมูลได้ </p>
<h2>Nostr Implementation Possibilities (NIPs)<br>NIP คืออะไร?</h2>
<p>NIP มีไว้เพื่อส่งเสริมความสามารถในการทำงานของ Nostr และเป็นตัวคอยกำหนดให้ เหล่านักพัฒนาทำสิ่งต่าง ๆ ที่เหมือนกันในรูปแบบเดียวกัน เพราะมันคงไม่ใช่ความคิดที่ดีนัก หากนักพัฒนาแต่ละคนจะคิดค้นวิธีแก้ปัญหาทั่วไปของตัวเองและนำไปใช้ในแอปของตัวเองเท่านั้น และคงจะเป็นการดีกว่า ถ้าหากทุกคนใช้วิธีแก้ปัญหาที่เหมือนกัน นั่นคือเหตุผลที่ต้องมี NIP อยู่ในโปรโตคอลของ Nostr และในทำนองเดียวกัน แนวคิดใหม่อาจดูดีในแอปของนักพัฒนาบางราย แต่จะดูดียิ่งขึ้นอย่างแน่นอนหากแอปอื่น ๆ อีกมากมายใช้มาตรฐานเดียวกันและสามารถทำงานร่วมกันได้อย่างราบรื่น</p>
<p><strong>ทำไมมันถึงหน้าสนใจ?</strong></p>
<p>อย่าลืมว่า Nostr เป็นระบบแบบกระจายอำนาจและไม่ได้มีบริษัทหรือใครที่เป็นเจ้าของมัน อย่างเช่นโซเชียลมีเดียอื่น ๆ เช่น ทวิตเตอร์ อ่อไม่สิตอนนี้คงต้องเรียกมันว่า X สินะ ซึ่งหมายความว่าทิศทางของโพรโทคอล Nostr นั้นขึ้นอยู่กับพวกเราทุกคน! ไม่ว่าใคร ๆ ก็สามารถเสนอแนะและสนับสนุนการเปลี่ยนแปลงและให้ข้อเสนอแนะเกี่ยวกับแนวคิดที่ผู้อื่นเสนอ และการที่คุณเป็นส่วนหนึ่งของชุมชนนี้ ก็ทำให้คุณมีส่วนร่วมในทิศทางของ Nostr อีกด้วย</p>
<p>จากที่ส่งหากันได้แค่ข้อความ มาเป็นรูปภาพ มาเป็นวิดีโอ และมาเป็น”เงิน” นี่คือเส้นทางการเดินทางของโปรโตคอลนี้ในอดีต แล้วในอนาคตมันจะพัฒนาไปยังไงต่อก็ขึ้นอยู่กับเหล่าผู้ใช้งานและนักพัฒนาในอนาคต แล้วทำไมสิ่งนี้ถึงจะไม่น่าสนใจละ ? </p>
<h2>Event</h2>
<p><strong>Event คืออะไร?</strong></p>
<p>Event เป็น object เพียงประเภทเดียวที่มีอยู่บน Nostr โดยมีโครงสร้างประมาณนี้</p>
<pre><code>{"id":"84d5d3dc9c388a702f39cad6360d41ebb804e809fb822f110ff8a14dfd35fc6c",
"pubkey":"66df60562d939ada8612436489945a4ecf1d62346b3d9478dea8a338f3203c64",
"created_at":1722315959,
"kind":1,
"tags":[["t","siamstr"]],
"content":"ไปสั่งกาแฟเมื่อกี้ พส เจ้าของร้านชมว่าเดี๋ยวนี้คล่องภาษาญี่ปุ่นแล้วนะ ไอเราก็ดีใจ พอเดินกลับถึงที่ทำงานละก็ตระหนักได้ว่า ตะกี้เราสั่ง “ไอซ์โคฮี โอเนไงชิมัส” “เทคเอาส์” “คาโดะเดสส” ไอบ้าไหนญี่ปุ่นก่อนอังกฤษทั้งนั้น 🤣🤣\n\n#siamstr",
"sig":"8f066a0099a5f580b605ebdb220179c4eca298947c38b855a0a8bf2783f28ddb537cb74a7f61d3ce8891189f719870efdf320ea4f895e03cdac44284c450c5c4"}
</code></pre>
<p>อย่าง Event ข้างต้นนี้มี kind เป็น 1 ซึ่งหมายถึง "ข้อความโน้ต" ซึ่งก็คือข้อความธรรมดา สั้น ๆ คล้ายกับที่ใช้กันใน Twitter เช่น บนฟีด การตอบกลับ และการโควท</p>
<p><strong>ประเภทของ Event (Event Kinds)</strong></p>
<p>หมายเลขของ kind แต่ละตัวมีความหมายแตกต่างกัน ตัวอย่างเช่น 0 หมายถึงอีเวนต์ "ข้อมูลเมตา" ใช้สำหรับให้รายละเอียดเกี่ยวกับผู้ใช้ เช่น ชื่อและรูปโปรไฟล์ รีเลย์ (Relays) สามารถจัดการกับ kind ที่แตกต่างกันได้ เช่น รีเลย์มักจะลบอีเวนต์ kind:0 เวอร์ชันเก่ากว่าออกไป และเก็บไว้เฉพาะเวอร์ชันล่าสุด ในขณะที่โดยทั่วไปจะเก็บอีเวนต์ kind:1 ไว้หลายรายการสำหรับแต่ละคีย์</p>
<p>โดยทั่วไปแล้ว คุณไม่จำเป็นต้องใช้ kind เกินกว่า 0 และ 1 ในการสร้างแอปพลิเคชันโซเชียลมีเดียบน Nostr แต่ kind อื่น ๆ ถูกคิดค้นขึ้นโดยไคลเอนต์ เพื่อมอบฟังก์ชันการทำงานอื่น ๆ ตามที่ระบุไว้ใน NIP บาง kind ไม่เกี่ยวข้องกับเครือข่าย และให้บริการตามความต้องการอื่น ๆ ของไคลเอนต์ที่เฉพาะเจาะจงกับฟังก์ชันการทำงานเหล่านั้น ซึ่งแนวคิดก็คือ สำหรับกรณีการใช้งานใหม่ ๆ แต่ละกรณี จะต้องมีการพิจารณาและเสนอซับโปรโตคอลเป็น NIP เพื่อให้สามารถทำงานร่วมกับไคลเอนต์ที่มีอยู่และในอนาคต ซึ่งอาจสนใจที่จะนำฟังก์ชันการทำงานนั้นไปใช้ ขณะเดียวกันก็มั่นใจได้ถึงความเข้ากันได้ย้อนหลัง และการรองรับสิ่งต่าง ๆ ที่มีอยู่และไม่ต้องการเปลี่ยนแปลง</p>
<p><strong>คุณสมบัติอื่น ๆ ของ Event</strong></p>
<p>created_at: เป็น Timestamp ของ UNIX ที่กำหนดโดยผู้สร้างอีเวนต์ โดยปกติจะเป็นเวลาที่สร้าง แม้ว่าจะไม่มีการตรวจสอบ แต่ก็ไม่ใช่ปัญหา</p>
<p>content: ขึ้นอยู่กับความหมายของ kind ในกรณีของ kind:1 จะเป็นเพียงสตริงข้อความธรรมดาที่คนอื่น ๆ อ่านได้<br>tags: ขึ้นอยู่กับ kind เช่นกัน แต่แท็กทั่วไปบางอย่างที่มักปรากฏใน event kind:1 และ kind อื่น ๆ คือ "p" ซึ่งใช้เพื่อกล่าวถึงกุญแจสาธารณะ และ "e" ใช้เพื่ออ้างถึง event อื่น</p>
<h2>อยากมีส่วนร่วมในการพัฒนาของ Nostr ?</h2>
<p>จริง ๆ แล้วใคร ๆ ก็สามารถเข้ามามีส่วนร่วมในการพัฒนา Nostr ได้ ไม่จำเป็นต้องเป็น dev หรือมีความรู้ด้านคอมพิวเตอร์ก็สามารถทำได้ ไม่ว่าจะเป็นการให้ feedback กับ dev ของ client ที่คุณใช้, การสร้างคอนเทนต์ต่าง ๆ บน Nostr การสร้างชุมชน รวมไปถึงการช่วย client ต่าง ๆ ในการทำ UI ให้เป็นภาษาท้องถิ่น และอื่น ๆ อีกมากมาย ใคร ๆ ก็สามารถช่วยได้ตามความสามารถที่แต่ละคนมี มันเลยทำให้ Nostr โครตน่าอยู่ :)</p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<h2>Nostr: โปรโตคอลทางเลือกใหม่สำหรับโซเชียลมีเดียที่เป็นอิสระ ปลอดภัย และไร้การควบคุม</h2>
<p>Nostr คือโปรโตคอลแบบเปิดที่เรียบง่าย ซึ่งช่วยให้สามารถสร้างโซเชียลมีเดียระดับโลกที่กระจายอำนาจและป้องกันการเซ็นเซอร์ได้ </p>
<p>จากที่กล่าวข้างต้น เราสามารถพูดได้ว่า Nostr นั้นถูกออกแบบมาให้ใช้งานง่าย โดยมีเป้าหมายหลัก ๆ เพื่อสร้างเครือข่ายโซเชียลระดับโลกที่ปราศจากการเซ็นเซอร์ แล้วทำไมมันถึงทำอย่างนั้นได้? ในจุดนี้เราก็ต้องมาเจาะดูคุณสมบัติหลัก ๆ ของโปรโตคอลที่เรียกว่า Nostr กันก่อน:</p>
<p><strong>เรียบง่าย</strong></p>
<ul>
<li><p>โปรโตคอลนี้ใช้โครงสร้างข้อมูลแบบ Event Object ที่เรียบง่ายและยืดหยุ่น (ซึ่งส่งเป็น JSON ธรรมดา) และใช้การเข้ารหัสแบบ Elliptic-curve มาตรฐานสำหรับคีย์และลายเซ็น</p>
</li>
<li><p>ช่องทางการสื่อสารที่รองรับเพียงอย่างเดียวคือการเชื่อมต่อ WebSockets จากไคลเอนต์ไปยังรีเลย์</p>
</li>
<li><p>การออกแบบนี้ทำให้ง่ายต่อการพัฒนาไม่ว่าจะไคลเอนต์หรือรีเลย์ และยังช่วยส่งเสริมความหลากหลายของซอฟต์แวร์</p>
</li>
</ul>
<p><strong>ยืดหยุ่น</strong></p>
<ul>
<li><p>เนื่องจาก Nostr ไม่ได้พึ่งพาเซิร์ฟเวอร์ที่เชื่อถือได้เพียงจำนวนหยิบมือ สำหรับการเคลื่อนย้ายหรือจัดเก็บข้อมูล แต่ใช้เซิร์ฟเวอร์จำนวนมหาศาลและกระจายตัวอยู่ทั่วโลก จึงมีความยืดหยุ่นสูง และมีการกระจายศูนย์อย่างแท้จริง</p>
</li>
<li><p>โปรโตคอลนี้ถูกออกแบบมาโดยคำนึงถึงความเป็นไปได้ที่รีเลย์จะหายไป และอนุญาตให้ผู้ใช้เชื่อมต่อและเผยแพร่ข้อมูลไปยังรีเลย์จำนวนมากได้ตามต้องการ และยังสามารถเปลี่ยนแปลงได้ตลอดเวลาอีกด้วย</p>
</li>
</ul>
<p><strong>ตรวจสอบได้</strong></p>
<ul>
<li>เนื่องจากบัญชี Nostr ใช้การเข้ารหัสแบบ PKE จึงง่ายต่อการตรวจสอบว่าข้อความถูกส่งมาจากผู้ใช้ที่ระบุจริงหรือไม่</li>
</ul>
<p>เช่นเดียวกับ HTTP หรือ TCP-IP Nostr เป็นโปรโตคอลหรือมาตรฐานแบบเปิดที่ทุกคนสามารถนำไปสร้างต่อยอดได้ มันไม่ใช่แอปหรือบริการที่คุณจำเป็นต้องลงทะเบียน</p>
<h2>แล้วทำไมเราถึงต้องการ Nostr?</h2>
<p>ถึงในปัจจุบันโซเชียลมีเดียจะได้พัฒนามาเป็นช่องทางสำคัญในการไหลเวียนของข้อมูลทั่วโลก กลายเป็นช่องทางหลักในการติดต่อสื่อสาร แต่น่าเสียดายที่ระบบโซเชียลมีเดียในปัจจุบันของเรานั้นมีข้อบกพร่องมากมาย:</p>
<ol>
<li>ใช้ความสนใจของคุณเพื่อขายโฆษณา</li>
<li>ใช้เทคนิคแปลกๆ เพื่อทำให้คุณเสพติด (อ้างอิงจากข้อ 1)</li>
<li>ตัดสินใจว่าจะแสดงเนื้อหาใดให้คุณเห็นโดยใช้อัลกอริทึมลับที่คุณไม่สามารถตรวจสอบหรือเปลี่ยนแปลงได้</li>
<li>ควบคุมอย่างเต็มที่ว่าใครสามารถเข้าร่วมและใครถูกเซ็นเซอร์</li>
<li>เต็มไปด้วยสแปมและบอท</li>
</ol>
<p>ด้วยข้อจำกัดเหล่านี้ Nostr จึงเป็นทางเลือกที่น่าสนใจในการสร้างโซเชียลมีเดียที่เป็นอิสระ ปลอดภัย และไร้การควบคุม</p>
<h2>องค์ประกอบของโปรโตคอลที่ชื่อว่า Nostr</h2>
<p>หลังจากได้ทำความรู้จัก Nostr กันไปแล้วเมื่อคราวก่อน คราวนี้เรามาเจาะดูองค์ประกอบของโปรโตคอลนี้กันดีกว่า</p>
<p><strong>Keys ระบบบัญชีผู้ใช้และรหัสผ่านสำหรับ Nostr</strong></p>
<ul>
<li><p>บัญชี Nostr แต่ละบัญชีจะใช้คู่กุญแจสาธารณะ/ส่วนตัว (Public/Private Key ) เปรียบเทียบง่าย ๆ คือ กุญแจสาธารณะของคุณคือชื่อผู้ใช้ และกุญแจส่วนตัวก็เป็นรหัสผ่าน แต่ว่า ก็มีข้อแตกต่างที่สำคัญอยู่ นั่นคือ กุญแจส่วนตัวของคุณนั้นจะไม่สามารถรีเซ็ตได้หากเกิดการสูญหายขึ้น คุณจะเสียบัญชีนั้นไปตลอดกาล</p>
</li>
<li><p>โดยทั่วไปแล้ว กุญแจสาธารณะจะแสดงเป็นข้อความที่ขึ้นต้นด้วย npub1 และกุญแจส่วนตัวจะขึ้นต้นด้วย nsec1</p>
</li>
<li><p>ทั้งนี้คุณควรที่จะตรวจสอบให้แน่ใจว่าคุณได้เก็บกุญแจส่วนตัวของคุณไว้ในที่ปลอดภัย เช่น โปรแกรมจัดการรหัสผ่านอย่างเช่น Bitwarden</p>
</li>
</ul>
<p><strong>โปรโตคอลกับไคลเอนต์ ต่างกันอย่างไร?</strong></p>
<p>Nostr เองเป็นเพียงโปรโตคอล หมายความว่า Nostr นั้นเป็นเพียงกระบวนการที่ตกลงกันไว้สำหรับการส่งข้อความผ่านอินเทอร์เน็ต (เหมือนข้อกำหนด)</p>
<p>ซึ่งการที่คุณจะเข้าถึง Nostr (โปรโตคอล) นั้น ผู้ใช้ส่วนใหญ่จะใช้งานผ่านไคลเอนต์  ซึ่งตัวของไคลเอนต์นั้นอาจเป็นเว็บ แอปพลิเคชันเดสก์ท็อป หรือ แอปพลิเคชันมือถือ โดยไคลเอนต์สามารถดึงข้อมูลจากรีเลย์ และสร้างข้อมูลใหม่ และส่งข้อมูลนั้นไปยังรีเลย์เพื่อให้ผู้ใช้คนอื่น ๆ สามารถเรียกอ่าน ข้อมูลนั้น ๆ ได้ โดย "ข้อมูล" เพียงรูปแบบเดียวที่มีอยู่ใน Nostr คือสิ่งที่เราเรียกกันว่า event</p>
<p><strong>การพิสูจน์ความเป็นเจ้าของข้อมูลบน Nostr</strong></p>
<p>บน Nostr นั้นการพิสูจน์ตัวตนเป็นเรื่องที่ง่ายมากเนื่องจากทุก ๆ event ที่เกิดขึ้น <strong>จำเป็น</strong>ต้องมีลายเซ็นดิจิทัล (Digital Signature) โดยลายเซ็นนั้นจะช่วยให้มั่นใจได้ว่า ใครเป็นผู้สร้าง event นั้น ๆ ขึ้นมา โดยการพิสูจน์ทางคณิตศาสตร์</p>
<p>โดยในการสร้างลายเซ็นแต่ละครั้ง ไคลเอนต์จะจำเป็นต้องใช้กุญแจส่วนตัวของคุณ โดยทั่วไปแล้ว แอปพลิเคชันเจะมีที่ให้คุณใส่กุญแจส่วนตัวของคุณ เมื่อเปิดแอปพลิเคชันครั้งแรก พวกเขาสามารถคำนวณกุญแจสาธารณะของคุณได้จากกุญแจส่วนตัวเช่นกัน</p>
<p>ส่วนในกรณีที่คุณใช้งานผ่านเว็บแอป ผมไม่แนะนำให้ใส่กุญแจส่วนตัวลงไป แต่แนะนำให้ใช้ส่วนขยายของเบราว์เซอร์ ที่ใช้งานฟังก์ชันที่เกี่ยวข้องกับ Nostr ซึ่งอนุญาตให้เว็บไคลเอ็นต์ส่ง event ที่ยังไม่ถูกเซ็นมาให้ส่วนขยายและส่วนขยายจะทำหน้าที่เซ็น สำหรับวิธีนี้ เว็บไคลเอ็นต์ต่าง ๆ ไม่จำเป็นต้องรู้กุญแจส่วนตัวของคุณ แต่คุณก็ยังสามารถลงนามใน event ต่าง ๆ ได้ตามปกติ โดยส่วนขยายที่ได้รับความนิยมก็จะเป็น <strong>Flamingo</strong>, <strong>Alby</strong> และ <strong>nos2x</strong> </p>
<h2>ไคลเอนต์ &amp; รีเลย์</h2>
<p><strong>ไคลเอนต์คืออะไร?</strong></p>
<p>หากจะอธิบายให้เห็นภาพอยากให้มองว่าไคลเอ็นต์ Nostr นั้นเป็นเหมือนกับแอปที่คุณใช้งานเพื่อเข้าถึง Twitter, Facebook, youtube เป็นต้น พวกมันคือ แอปพลิเคชัน, เว็บแอป ที่เชื่อมต่อคุณกับโลกของ Twitter, Facebook, youtube โดยตัวของไคลเอนต์ใน Nostr เองก็เปรียบเสมือนแอปต่าง ๆ ที่คุณใช้ดูหน้าฟีดนั่นเอง แต่ข้อดีของ Nostr ที่เหนือแอปพลิเคชันอื่น ๆ คือความเรียบง่ายและยืดหยุ่น ส่งผลให้ไคลเอ็นต์แต่ละตัวมีวิธีนำเสนอและใช้งานที่แตกต่างกันไป บางไคลเอ็นต์อาจออกแบบให้ใช้งานง่ายเหมือน Twitter บางตัวเน้นให้เห็นบทบาทสำคัญของรีเลย์ หรือโหนดที่กระจายข้อมูลอยู่ทั่วโลก บางตัวใช้ระบบอัลกอริทึมเพื่อให้แน่ใจว่าข้อมูลไม่ถูกปิดกั้น โดยไม่ทำให้ผู้ใช้งานรู้สึกยุ่งยาก</p>
<p><strong>เรียบง่ายและยืดหยุ่น?</strong></p>
<p>เนื่องจากการออกแบบของโปรโตคอลที่ทำการแยกข้อมูลของผู้ใช้ทั้งหมดออกจากไคลเอนต์ ทำให้ตัวของผู้ใช้งานเองนั้นมีอิสระเต็มที่ที่จะเลือกใช้ไคลเอนต์ต่าง ๆ เพื่อเข้าใช้งาน Nostr และแน่นอนว่า ผู้ใช้งานสามารถสลับหรือลงชื่อเข้าใช้ ไคลเอ็นต์ได้หลายตัวตามต้องการ ตราบใดที่ไคลเอ็นต์ทั้งหมดเชื่อมต่อกับชุดรีเลย์เดียวกัน คุณก็จะเห็นข้อมูลเดียวกันในทุก ๆ ไคลเอ็นต์</p>
<p><strong>ลงชื่อเข้าใช้ ไคลเอ็นต์หลาย ๆ ตัวแล้วจะกระทบต่อความปลอดภัยของแอคเคาร์ไหม?</strong></p>
<p>คำตอบของคำถามนี้นั้นขึ้นอยู่กับวิธีการที่คุณลงชื่อเข้าใช้ หากคุณลงชื่อเข้าใช้ด้วยกุญแจส่วนตัว ถึงแม้ว่าไคลเอ็นต์ส่วนใหญ่จะพยายามรักษาความปลอดภัยของกุญแจส่วนตัวอย่างดีที่สุด แต่ด้วยข้อจำกัดของซอฟต์แวร์ ย่อมมีความเสี่ยงที่จะเกิดช่องโหว่ การเจาะระบบ และข้อผิดพลาด ที่อาจทำให้กุญแจส่วนตัวของคุณรั่วไหลออกไปได้ ส่วนวิธีการป้องกันเกี่ยวกับเรื่องนี้คือการใช้ส่วนขยายของเว็บเบราว์เซอร์ เพราะการเข้าสู่ระบบในไคลเอนต์ต่าง ๆ ผ่านส่วนขยายนั้นจะใช้เพียงกุญแจสาธารณะในการเข้าสู่ระบบและทุกครั้งที่เราต้องการจะโพสต์หรือสร้าง event บน Nostr ไคลเอนต์จะทำการร่าง event นั้น ๆ และเว้นช่องของลายเซ็นเอาไว้จากนั้นเราจะต้องทำการเซ็นผ่านส่วนขยาย ด้วยวิธีนี้ทำให้กุญแจส่วนตัวของเราไม่หลุดออกไปไหนตลอดการใช้งาน</p>
<p><strong>รีเลย์คืออะไร?</strong></p>
<p>รีเลย์เปรียบเสมือนเซิร์ฟเวอร์ที่อยู่เบื้องหลังของ Nostr และทำหน้าที่รับ event ต่าง ๆ มาจากไคลเอนต์ Nostr และอาจจะจัดเก็บและกระจายข้อความเหล่านั้นไปยังไคลเอนต์อื่น ๆ ที่มีการเชื่อมต่ออยู่</p>
<p>เทคโนโลยีของรีเลย์นั้นเปลี่ยนแปลงอย่างรวดเร็ว ดังนั้นคาดว่าจะมีการเปลี่ยนแปลงอีกมากมายในอนาคต อย่างในปัจจุบันที่มีการนำเสนอ bostr หรือ รีเลย์ที่จะคอยส่ง event ของเราต่อให้กับรีเลย์อื่น ๆ ที่มีการเชื่อมต่อ เพื่อช่วยลดภาระของไคลเอนต์ในการรับส่งข้อมูลจากหลาย ๆ รีเลย์พร้อม ๆ กัน หรืออย่างการป้องกันสแปมด้วย POW หรือประเภทที่สามารถเก็บรูปหรือวิดีโอที่มีขนาดใหญ่ได้</p>
<p>แต่สิ่งหนึ่งที่ควรทราบก็คือ การที่ Nostr นั้นพยายามจะกระจายศูนย์และเหตุผลหลัก ๆ ที่สามารถทำแบบนั้นได้ก็ขึ้นอยู่กับรีเลย์ในการจัดเก็บและดึงข้อมูล ดังนั้น หากคุณรู้สึกว่าไคลเอนต์ Nostr ของคุณทำงานช้า ส่วนใหญ่ก็มักเกิดจากรีเลย์ที่คุณกำลังเชื่อมต่ออยู่ คุณอาจลองแก้ไขปัญญาโดยการเปลี่ยนหรือเพิ่มรีเลย์อีกสองสามรายการในไคลเอนต์ที่คุณใช้</p>
<p><strong>แล้วจะสามารถหารายการรีเลย์ได้จากไหน?</strong></p>
<p>การที่เราจะหารายการรีเลย์ที่เราควรเชื่อมต่อนั้น ๆ จริงแล้ว ๆ สามารถทำได้หลายวิธี แต่วิธีที่ผมแนะนำที่สุดจะเป็นการใช้ตามคนที่เราติดตามอยู่ เพราะจะเป็นวิธีที่เราสามารถเห็น event ต่าง ๆ ของคนที่เราติดตามได้ง่ายที่สุด และเช่นเดียวกัน เพื่อน ๆ หรือคนที่เราติดตามก็จะสามารถเห็น event ของเราได้เช่นกัน และสำหรับในประเทศไทย เรามีรีเลย์ที่คนไทยส่วนใหญ่นิยมใช้กันอยู่สองอัน นั้นคือ wss://relay.siamstr.com/ และ  wss://relay.notoshi.win/ ถ้าหากว่าอยากเห็นคนไทยเยอะ ๆ บนหน้าไทม์ไลน์ ผมแนะนำเป็นอย่างยิ่งว่าควรเพิ่ม รายการรีเลย์เหล่านี้ลงไปในบัชญีหรือไคลเอนต์ต่าง ๆ ที่คุณใช้ด้วย </p>
<p>สำหรับอีกวิธีหนึ่งผมแนะนำให้เข้าไปในเว็บไซต์ nostr.watch เนื่องจากในเว็บไซต์นี้เป็นแหล่งข้อมูลที่ดีที่สุดสำหรับการค้นหาและประเมินความเร็วของรีเลย์ต่าง ๆ </p>
<p><strong>จะเกิดอะไรขึ้นถ้ารีเลย์ทั้งหมดที่ฉันเชื่อมต่ออยู่หยุดให้บริการ?</strong></p>
<p>สิ่งนี้เป็นสิ่งที่คุณต้องระวังมากที่สุดในการใช้งาน nostr เนื่องจากหากรีเลย์ทั้งหมดที่คุณเก็บข้อมูลไว้หยุดให้บริการทั้งหมดและคุณไม่มีการสำรองข้อมูล event ของคุณเก็บไว้เลย มันแปลว่าโพสต์ทั้งหมดของคุณ ผู้ติดตาม และรายการต่าง ๆ ที่คุณสรรค์สร้างไว้จะไม่สามารถกู้คืนได้ไปตลอดการ นี่จึงเป็นเหตุผลหลัก ๆ ที่ Nostr อนุญาตให้ผู้ใช้งานนั้นสามารถเชื่อมต่อกับรีเลย์ได้เป็นจำนวนมาก ก็เพื่อให้แน่ใจว่ามีข้อมูลสำรองเก็บไว้อยู่ที่ใดที่หนึ่งในระบบเสมอ แต่อย่างไรก็ตาม หากคุณต้องการที่จะมั่นใจได้ว่าข้อมูลต่าง ๆ ของคุณจะไม่ถูกเซ็นเซอร์ สิ่งที่คุณสามารถสามารถทำได้คือการใช้รีเลย์ส่วนตัวของคุณและกำหนดนโยบายต่าง ๆ ภายในรีเลย์ของคุณด้วยตัวคุณเอง</p>
<p><strong>แล้วฉันจะสามารถใช้รีเลย์ส่วนตัวได้อย่างไร?</strong></p>
<p><strong>อะแฮ่ม ๆ</strong> ขอบอกไว้ก่อนว่ามันไม่คุ้มค่ากับความยุ่งยากสำหรับคนโดยทั่ว ๆ ไป ถึงในปัจจุบันจะมีเทคโนโลยีบางตัวที่เข้ามาช่วยให้มันทำได้ง่ายขึ้นแล้วก็ตาม<br>หากคุณต้องการที่จะสำรองข้อมูลนั้น การที่จะมีรีเลย์ส่วนตัวที่ออนไลน์ตลอดเวลาอาจเป็นเรื่องที่ไม่ได้จำเป็นขนาดนั้น เนื่องจากเราสามารถใช้งานบริการอย่าง <np-embed url="https://nostrsync.live/"><a href="https://nostrsync.live/">https://nostrsync.live/</a></np-embed> ในการดาวน์โหลดข้อมูลของเราจากรีเลย์ต่าง ๆ ได้ หรือการติดตั้งรีเลย์ส่วนตัวอย่าง nostr-relay-tray: <np-embed url="https://github.com/CodyTseng/nostr-relay-tray"><a href="https://github.com/CodyTseng/nostr-relay-tray">https://github.com/CodyTseng/nostr-relay-tray</a></np-embed> ที่ช่วยให้เราสามารถมีรีเลย์ส่วนตัวที่ใช้สำหรับสำรองข้อมูลได้ </p>
<h2>Nostr Implementation Possibilities (NIPs)<br>NIP คืออะไร?</h2>
<p>NIP มีไว้เพื่อส่งเสริมความสามารถในการทำงานของ Nostr และเป็นตัวคอยกำหนดให้ เหล่านักพัฒนาทำสิ่งต่าง ๆ ที่เหมือนกันในรูปแบบเดียวกัน เพราะมันคงไม่ใช่ความคิดที่ดีนัก หากนักพัฒนาแต่ละคนจะคิดค้นวิธีแก้ปัญหาทั่วไปของตัวเองและนำไปใช้ในแอปของตัวเองเท่านั้น และคงจะเป็นการดีกว่า ถ้าหากทุกคนใช้วิธีแก้ปัญหาที่เหมือนกัน นั่นคือเหตุผลที่ต้องมี NIP อยู่ในโปรโตคอลของ Nostr และในทำนองเดียวกัน แนวคิดใหม่อาจดูดีในแอปของนักพัฒนาบางราย แต่จะดูดียิ่งขึ้นอย่างแน่นอนหากแอปอื่น ๆ อีกมากมายใช้มาตรฐานเดียวกันและสามารถทำงานร่วมกันได้อย่างราบรื่น</p>
<p><strong>ทำไมมันถึงหน้าสนใจ?</strong></p>
<p>อย่าลืมว่า Nostr เป็นระบบแบบกระจายอำนาจและไม่ได้มีบริษัทหรือใครที่เป็นเจ้าของมัน อย่างเช่นโซเชียลมีเดียอื่น ๆ เช่น ทวิตเตอร์ อ่อไม่สิตอนนี้คงต้องเรียกมันว่า X สินะ ซึ่งหมายความว่าทิศทางของโพรโทคอล Nostr นั้นขึ้นอยู่กับพวกเราทุกคน! ไม่ว่าใคร ๆ ก็สามารถเสนอแนะและสนับสนุนการเปลี่ยนแปลงและให้ข้อเสนอแนะเกี่ยวกับแนวคิดที่ผู้อื่นเสนอ และการที่คุณเป็นส่วนหนึ่งของชุมชนนี้ ก็ทำให้คุณมีส่วนร่วมในทิศทางของ Nostr อีกด้วย</p>
<p>จากที่ส่งหากันได้แค่ข้อความ มาเป็นรูปภาพ มาเป็นวิดีโอ และมาเป็น”เงิน” นี่คือเส้นทางการเดินทางของโปรโตคอลนี้ในอดีต แล้วในอนาคตมันจะพัฒนาไปยังไงต่อก็ขึ้นอยู่กับเหล่าผู้ใช้งานและนักพัฒนาในอนาคต แล้วทำไมสิ่งนี้ถึงจะไม่น่าสนใจละ ? </p>
<h2>Event</h2>
<p><strong>Event คืออะไร?</strong></p>
<p>Event เป็น object เพียงประเภทเดียวที่มีอยู่บน Nostr โดยมีโครงสร้างประมาณนี้</p>
<pre><code>{"id":"84d5d3dc9c388a702f39cad6360d41ebb804e809fb822f110ff8a14dfd35fc6c",
"pubkey":"66df60562d939ada8612436489945a4ecf1d62346b3d9478dea8a338f3203c64",
"created_at":1722315959,
"kind":1,
"tags":[["t","siamstr"]],
"content":"ไปสั่งกาแฟเมื่อกี้ พส เจ้าของร้านชมว่าเดี๋ยวนี้คล่องภาษาญี่ปุ่นแล้วนะ ไอเราก็ดีใจ พอเดินกลับถึงที่ทำงานละก็ตระหนักได้ว่า ตะกี้เราสั่ง “ไอซ์โคฮี โอเนไงชิมัส” “เทคเอาส์” “คาโดะเดสส” ไอบ้าไหนญี่ปุ่นก่อนอังกฤษทั้งนั้น 🤣🤣\n\n#siamstr",
"sig":"8f066a0099a5f580b605ebdb220179c4eca298947c38b855a0a8bf2783f28ddb537cb74a7f61d3ce8891189f719870efdf320ea4f895e03cdac44284c450c5c4"}
</code></pre>
<p>อย่าง Event ข้างต้นนี้มี kind เป็น 1 ซึ่งหมายถึง "ข้อความโน้ต" ซึ่งก็คือข้อความธรรมดา สั้น ๆ คล้ายกับที่ใช้กันใน Twitter เช่น บนฟีด การตอบกลับ และการโควท</p>
<p><strong>ประเภทของ Event (Event Kinds)</strong></p>
<p>หมายเลขของ kind แต่ละตัวมีความหมายแตกต่างกัน ตัวอย่างเช่น 0 หมายถึงอีเวนต์ "ข้อมูลเมตา" ใช้สำหรับให้รายละเอียดเกี่ยวกับผู้ใช้ เช่น ชื่อและรูปโปรไฟล์ รีเลย์ (Relays) สามารถจัดการกับ kind ที่แตกต่างกันได้ เช่น รีเลย์มักจะลบอีเวนต์ kind:0 เวอร์ชันเก่ากว่าออกไป และเก็บไว้เฉพาะเวอร์ชันล่าสุด ในขณะที่โดยทั่วไปจะเก็บอีเวนต์ kind:1 ไว้หลายรายการสำหรับแต่ละคีย์</p>
<p>โดยทั่วไปแล้ว คุณไม่จำเป็นต้องใช้ kind เกินกว่า 0 และ 1 ในการสร้างแอปพลิเคชันโซเชียลมีเดียบน Nostr แต่ kind อื่น ๆ ถูกคิดค้นขึ้นโดยไคลเอนต์ เพื่อมอบฟังก์ชันการทำงานอื่น ๆ ตามที่ระบุไว้ใน NIP บาง kind ไม่เกี่ยวข้องกับเครือข่าย และให้บริการตามความต้องการอื่น ๆ ของไคลเอนต์ที่เฉพาะเจาะจงกับฟังก์ชันการทำงานเหล่านั้น ซึ่งแนวคิดก็คือ สำหรับกรณีการใช้งานใหม่ ๆ แต่ละกรณี จะต้องมีการพิจารณาและเสนอซับโปรโตคอลเป็น NIP เพื่อให้สามารถทำงานร่วมกับไคลเอนต์ที่มีอยู่และในอนาคต ซึ่งอาจสนใจที่จะนำฟังก์ชันการทำงานนั้นไปใช้ ขณะเดียวกันก็มั่นใจได้ถึงความเข้ากันได้ย้อนหลัง และการรองรับสิ่งต่าง ๆ ที่มีอยู่และไม่ต้องการเปลี่ยนแปลง</p>
<p><strong>คุณสมบัติอื่น ๆ ของ Event</strong></p>
<p>created_at: เป็น Timestamp ของ UNIX ที่กำหนดโดยผู้สร้างอีเวนต์ โดยปกติจะเป็นเวลาที่สร้าง แม้ว่าจะไม่มีการตรวจสอบ แต่ก็ไม่ใช่ปัญหา</p>
<p>content: ขึ้นอยู่กับความหมายของ kind ในกรณีของ kind:1 จะเป็นเพียงสตริงข้อความธรรมดาที่คนอื่น ๆ อ่านได้<br>tags: ขึ้นอยู่กับ kind เช่นกัน แต่แท็กทั่วไปบางอย่างที่มักปรากฏใน event kind:1 และ kind อื่น ๆ คือ "p" ซึ่งใช้เพื่อกล่าวถึงกุญแจสาธารณะ และ "e" ใช้เพื่ออ้างถึง event อื่น</p>
<h2>อยากมีส่วนร่วมในการพัฒนาของ Nostr ?</h2>
<p>จริง ๆ แล้วใคร ๆ ก็สามารถเข้ามามีส่วนร่วมในการพัฒนา Nostr ได้ ไม่จำเป็นต้องเป็น dev หรือมีความรู้ด้านคอมพิวเตอร์ก็สามารถทำได้ ไม่ว่าจะเป็นการให้ feedback กับ dev ของ client ที่คุณใช้, การสร้างคอนเทนต์ต่าง ๆ บน Nostr การสร้างชุมชน รวมไปถึงการช่วย client ต่าง ๆ ในการทำ UI ให้เป็นภาษาท้องถิ่น และอื่น ๆ อีกมากมาย ใคร ๆ ก็สามารถช่วยได้ตามความสามารถที่แต่ละคนมี มันเลยทำให้ Nostr โครตน่าอยู่ :)</p>
]]></itunes:summary>
      <itunes:image href="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1724035705683-YAKIHONNES3.png"/>
      </item>
      
      <item>
      <title><![CDATA[อ่าน bitcoin whitepaper ไปกับไดโน]]></title>
      <description><![CDATA[Bitcoin white paper ที่ถูกทำให้เป็นภาษาไทยเอามารวมให้อ่านทีเดียวแบบจบ ๆ]]></description>
             <itunes:subtitle><![CDATA[Bitcoin white paper ที่ถูกทำให้เป็นภาษาไทยเอามารวมให้อ่านทีเดียวแบบจบ ๆ]]></itunes:subtitle>
      <pubDate>Fri, 09 Aug 2024 05:18:28 GMT</pubDate>
      <link>https://learnbn.npub.pro/post/qjbtomsnkbiegwyagab22/</link>
      <comments>https://learnbn.npub.pro/post/qjbtomsnkbiegwyagab22/</comments>
      <guid isPermaLink="false">naddr1qq2hz6nz238k6umwdd3yje282av5ze6pvgeryq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wvv92jw</guid>
      <category>ลองฟอร์มของไดโน</category>
      
        <media:content url="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1723180709624-YAKIHONNES3.png" medium="image"/>
        <enclosure 
          url="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1723180709624-YAKIHONNES3.png" length="0" 
          type="image/png" 
        />
      <noteId>naddr1qq2hz6nz238k6umwdd3yje282av5ze6pvgeryq3q0yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2sxpqqqp65wvv92jw</noteId>
      <npub>npub10yqgu7q6mmrk0nywywd4x0kukx029cnqly5p4yf9ay6zthavjw2syrhcl3</npub>
      <dc:creator><![CDATA[Learning_BTC&NOSTR]]></dc:creator>
      <content:encoded><![CDATA[<h2>ระบบเงินอิเล็กทรอนิกส์แบบ peer-to-peer </h2>
<p>ระบบเงินอิเล็กทรอนิกส์แบบ peer-to-peer นั้นจะช่วยให้เราสามารถชำระเงินผ่านทางออนไลน์ได้โดยตรงจากฝ่ายหนึ่งไปยังอีกฝ่ายหนึ่งโดยไม่ต้องผ่านตัวกลางอย่างพวกสถาบันการเงิน โดยใช้ digital signature เป็นส่วนหนึ่งในการแก้ปัญหานี้ แต่มันจะไม่มีประโยชน์ใด ๆ เลยหากยังคงต้องอาศัยตัวกลางที่เชื่อถือได้มาแก้ปัญหา double spending เราขอเสนอวิธีแก้ปัญหา double spending โดยใช้เครือข่ายแบบ peer-to-peer ให้เครือข่ายคอยประทับเวลาธุรกรรมต่าง ๆ ในระบบและนำมาเรียงร้อยกันเป็นเส้นสายของ proof-of-work ที่ใช้ hash เพื่อสร้างธุรกรรมที่ไม่สามารถเปลี่ยนแปลงได้ โดยไม่ต้องทำ proof-of-work ใหม่ โดยให้เส้นสายที่ยาวที่สุดนั้น ไม่เพียงแต่ทำหน้าที่เป็นลำดับของธุรกรรมที่เกิดขึ้นเท่านั้น แต่ยังเป็นสิ่งที่พิสูจน์ได้ว่ามาจากกำลังประมวลผล CPU ที่มากที่สุด และตราบใดที่ nodes ส่วนใหญ่ไม่ได้ร่วมมือกันโจมตีเครือข่ายและยังคงควบคุมกำลังประมวลผลส่วนใหญ่ในระบบไว้ พวกเขาก็จะสร้างเส้นสายที่ยาวที่สุดและสามารถเอาชนะผู้ประสงค์ร้ายที่จะโจมตีระบบได้ ตัวเครือข่ายเองไม่ได้ต้องมีโครงสร้างอะไรที่ซับซ้อน ข้อมูลต่าง ๆ ในเครือข่ายจะถูกกระจายส่งต่อโดยไม่ต้องสนใจว่าผู้รับจะได้รับหรือไม่ และ nodes ต่าง ๆ เองก็สามารถที่จะออกจากเครือข่ายและกลับเข้าร่วมใหม่ได้ตามที่ต้องการ โดยยอมรับเส้น proof-of-work ที่ยาวที่สุด เป็นหลักฐานของสิ่งที่เกิดขึ้นในขณะที่ node นั้น ๆ ไม่ได้อยู่ในเครือข่าย</p>
<h2>1.บทนำ (Introduction)</h2>
<p>ไม่ว่าใครจะใคร่ซื้อใคร่ขายอะไรใด ๆ บนอินเตอร์เน็ตนั้น ก็จำเป็นต้องพึ่งพาสถาบันการเงินในฐานะของบุคคลที่สามเพื่อดำเนินการชำระเงินทางอิเล็กทรอนิกส์เสมอ ๆ  ซึ่งถึงแม้ว่าระบบนี้มันจะทำงานได้ดีสำหรับธุรกรรมส่วนใหญ่ ๆ แต่ระบบก็ก็มีจุดอ่อนอยู่ที่ยังต้องอาศัยความไว้เนื้อเชื่อใจ (trust) ในระบบนี้การทำธุรกรรมที่ไม่สามารถย้อนกลับได้อย่างสมบูรณ์นั้นมันแทบจะเป็นไปไม่ได้เลย เนื่องจากสถาบันการเงินไม่สามารถหลีกเลี่ยงการเป็นตัวกลางในการไกล่เกลี่ยข้อพิพาทต่าง ๆ ที่อาจเกิดขึ้นได้ มิหนำซ้ำต้นทุนในการไกล่เกลี่ยยังทำให้ต้นทุนการทำธุรกรรมเพิ่มสูงขึ้น และเมื่อต้นทุนสูงขึ้นขนาดของธุรกรรมที่สามารถใช้งานได้จริงก็สูงขึ้นตามไปด้วย ธุรกรรมเล็ก ๆ น้อย ๆ ก็ไม่สามารถเกิดขึ้นได้ เมื่อมีความเป็นไปได้ที่ธุรกรรมจะเกิดการย้อนกลับ ความจำเป็นในการสร้างความไว้วางใจก็ยิ่งทวีคูณมากขึ้น ผู้ค้าก็จำเป็นต้องระมัดระวังลูกค้า ต้องเรียกร้องข้อมูลมากกว่าที่จำเป็น การฉ้อโกงกลายเป็นเรื่องที่หลีกเลี่ยงไม่ได้เพราะต้นทุนและความไม่แน่นอนในทำธุรกรรมเหล่านี้ แน่นอนว่าเราสามารถหลีกเลี่ยงมันได้โดยการใช้เงินสด แต่ก็ไม่มีกลไกใดที่ทำให้สามารถใช้เงินสดผ่านช่องทางการสื่อสาร (เอาให้เข้าใจง่ายก็อินเตอร์เน็ต)ได้ โดยไม่ต้องมีตัวกลาง ;-;</p>
<p>แปลว่าสิ่งที่จำเป็นสำหรับการแก้ไขปัญหานี้คือระบบการชำระเงินทางอิเล็กทรอนิกส์ ที่อยู่บนพื้นฐานของการพิสูจน์ด้วยการเข้ารหัสแทนที่จะเป็นความไว้วางใจ ซึ่งจะทำให้คู่สัญญาสองฝ่ายที่ยินยอมสามารถทำธุรกรรมร่วมกันได้โดยตรง โดยไม่จำเป็นต้องมีบุคคลที่สามมาคอยเป็นตัวกลาง ธุรกรรมที่ยากต่อการย้อนกลับจะช่วยปกป้องผู้ขายจากการฉ้อโกง และสามารถใช้กลไก escrow เพื่อปกป้องผู้ซื้อได้อีกด้วย ในเอกสารชุดนี้ เราขอเสนอวิธีแก้ปัญหาการใช้จ่ายซ้ำซ้อนโดยใช้เซิร์ฟเวอร์ timestamp กระจายศูนย์แบบ peer-to-peer เพื่อสร้างหลักฐานการคำนวณลำดับเวลาของธุรกรรม โดยระบบนี้จะปลอดภัยตราบใดที่กลุ่มของ node ที่ซื่อสัตย์ ยังคงมีกำลังประมวลผลที่มากกว่ากลุ่มที่ประสงค์ร้ายกับระบบ</p>
<h2>2.ธุรกรรม (Transactions) </h2>
<p>นิยามของเหรียญอิเล็กทรอนิกส์ในที่นี้ คือห่วงโซ่ที่คล้องเกี่ยวกันของ digital signature โดยที่เจ้าของเหรียญอิเล็กทรอนิกส์จะโอนเหรียญไปยังเจ้าของคนถัดไป ด้วยการลง digital signature บน hash ของธุรกรรมก่อนหน้ารวมถึงกุญแจสาธารณะของเจ้าของคนถัดไป และผนวกมันไว้ที่ส่วนท้ายของธุรกรรม และผู้รับเงินเองก็สามารถตรวจสอบลายเซ็นเพื่อยืนยันความเป็นเจ้าของได้ </p>
<p><a href="https://image.nostr.build/a467896797a9fb9f98c3c234f0adb4df2376f2c3d9a7cc9d8672d7a9f5aa9efa.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/a467896797a9fb9f98c3c234f0adb4df2376f2c3d9a7cc9d8672d7a9f5aa9efa.png"></a></p>
<p>แน่นอนว่าปัญหาก็คือผู้รับเงินไม่สามารถตรวจสอบได้ว่าเจ้าของคนใดคนหนึ่งก่อนหน้าเขาได้ใช้เหรียญดังกล่าวซ้ำซ้อนมากกว่าหนึ่งครั้งหรือไม่ และวิธีการแก้ไขปัญหานี้โดยทั่วไปก็คงเป็นการกำหนดตัวกลางที่มีความน่าเชื่อถือมาเป็นคนตรวจสอบทุกธุรกรรมเพื่อป้องกันการใช้จ่ายซ้ำซ้อน และหลังจากการทำธุรกรรมแต่ละครั้ง เหรียญจะต้องถูกส่งกลับไปยังตัวกลางเพื่อออกเหรียญใหม่ และจะมีเพียงเหรียญที่ออกจากตัวกลางโดยตรงเท่านั้นที่จะเชื่อถือได้ว่าจะไม่ถูกใช้จ่ายซ้ำซ้อน แต่ปัญหาก็คือ ชะตากรรมของระบบเงินทั้งหมดจะขึ้นอยู่กับตัวกลางตัวนี้ เพราะทุกธุรกรรมจำเป็นจะต้องผ่านพวกเขา ซึ่งก็ไม่ต่างอะไรกับธนาคาร</p>
<p>เราจึงต้องการวิธีการที่ทำให้ผู้รับเงินทราบได้ว่าเจ้าของคนก่อน ๆ ไม่ได้ลงนามในธุรกรรมใด ๆ มาก่อน เพื่อให้บรรลุวัตถุประสงค์นี้ เราจะทำการนับว่าธุรกรรมที่เกิดขึ้นก่อนเป็นธุรกรรมที่ถูกต้อง และจะไม่สนใจความพยายามใด ๆ ในการที่จะใช้เหรียญนั้น ๆ ซ้ำอีก และวิธีเดียวที่ทำแบบนี้ได้ คือการรับรู้ถึงธุรกรรมทั้งหมด เช่นเดียวกับโมเดลที่ได้กล่าวข้างต้น ที่ตัวกลางจะรับรู้ถึงธุรกรรมทั้งหมดและตัดสินว่าธุรกรรมใดมาก่อนมาหลัง เพื่อให้บรรลุเป้าหมายนี้โดยไม่ต้องมีบุคคลที่สามที่เชื่อถือได้ ธุรกรรมทั้งหมดจะต้องถูกประกาศต่อสาธารณะ [1] และเราต้องการระบบที่ผู้เข้าร่วมเห็นพ้องในประวัติธุรกรรมชุดเดียวกันตามลำดับที่ได้รับ ส่วนผู้รับเงินก็จำเป็นจะต้องมีหลักฐานว่า ในขณะที่ทำธุรกรรม "โหนด" ส่วนใหญ่ในระบบเห็นพ้องต้องกันว่าธุรกรรมนั้นได้รับเป็นลำดับแรก(ไม่มีธุรกรรมที่ใช้เหรียญพวกนี้มาก่อน) </p>
<h2>3.ระบบบันทึกเวลา (Timestamp Server)</h2>
<p>สำหรับแนวทางการแก้ปัญหาในครั้งนี้ เราจะใช้ประโยชน์จาก timestamp server ที่จะทำหน้าที่บันทึก hash ของบล๊อกที่ต้องการให้มีการบันทึกเวลา และจากนั้นจะทำการเผยแพร่ hash ดังกล่าว เหมือนกับหนังสือพิมพ์หรือโพสต์ใน Usenet [2-5] (ฟีลแบบทุกคนจะเห็นโพสต์นี้น้าา ประมาณนั้น) การบันทึกเวลานี้จะพิสูจน์ได้ว่าข้อมูลที่ถูก hash นั้นจะต้องมีอยู่จริงในเวลานั้นเพื่อให้ได้มาซึ่ง hash ดังกล่าว แต่ละการบันทึกเวลาจะรวมการบันทึกเวลาของหน้านี้ไว้ใน hash ของมันเพื่อสร้างเป็น chain โดยการบันทึกเวลาแต่ละครั้งจะยืนยันความถูกต้องของการบันทึกก่อนหน้าได้อีกด้วยด้วย</p>
<p> <a href="https://image.nostr.build/ddf92417c45dbb6e25da0af80a10d4cdbc3e725d047d65f54a3e3bfcf358c4d6.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/ddf92417c45dbb6e25da0af80a10d4cdbc3e725d047d65f54a3e3bfcf358c4d6.png"></a></p>
<h2>4.พรูฟ-ออฟ-เวิร์ค (Proof-of-Work)</h2>
<p>ในการสร้าง Timestamp Server แบบกระจายศูนย์บนพื้นฐานแบบ peer to peer เราจำเป็นต้องใช้ระบบ Proof-of-Work (PoW) ที่คล้ายกับ Hashcash ของ Adam Back [6] แทนที่จะใช้วิธีการแบบเดิม ๆ อย่างการประกาศในหนังสือพิมพ์หรือ Usenet โดย PoW ใช้ในการตรวจสอบค่าที่มาจากกระบวนการ hash เช่น SHA-256 แล้ว ผลลัพธ์ที่ได้ (Hash) จะขึ้นต้นด้วยเลขศูนย์จำนวนหนึ่ง โดยที่ work (ประมาณว่าพลังประมวลผล) ที่ต้องใช้จะเพิ่มขึ้นแบบทวีคูณตามจำนวนเลขศูนย์ที่ต้องการ และสามารถตรวจสอบได้โดยการรัน Hash เพียงครั้งเดียว</p>
<p>ซึ่งสำหรับ timestamp network ของเรานั้น เราใช้ PoW โดยการเพิ่มค่า Nonce ในบล็อกไปเรื่อย ๆ จนกว่าจะพบค่าที่ทำให้ Hash ของบล็อกนั้นมีเลขศูนย์ตามที่กำหนด และเมื่อใช้กำลังประมวลผลของ CPU ไปกับการทำ PoW จนสำเร็จแล้ว บล็อกจะไม่สามารถเปลี่ยนแปลงได้ หากไม่มีการทำงานซ้ำใหม่ เนื่องจากบล็อกที่สร้างขึ้นภายหลังจะเชื่อมโยงกับบล็อกก่อนหน้า การเปลี่ยนแปลงบล็อกใด ๆ จะต้องทำ PoW ของบล็อกนั้นและบล็อกที่ตามมาใหม่ทั้งหมด</p>
<p> <a href="https://image.nostr.build/c039ef4ca6833cb1ecee65ac5991df2406be9b7e490b86b3b19f94f267767182.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/c039ef4ca6833cb1ecee65ac5991df2406be9b7e490b86b3b19f94f267767182.png"></a> </p>
<p>นอกจากนี้ PoW ยังช่วยแก้ปัญหาของเสียงส่วนมากที่มาตัดสินใจในระบบนี้ เพราะหากเสียงข้างมากอ้างอิงจากหลักการหนึ่ง IP หนึ่งเสียง ใครก็ตามที่สามารถสร้าง IP ได้จำนวนมากก็จะสามารถควบคุมระบบได้ จึงใช้หลักการหนึ่ง CPU หนึ่งเสียงแทน การตัดสินใจของเสียงข้างมากจะแสดงด้วย Chain ที่ยาวที่สุด ซึ่งบ่งบอกถึงความพยายามในการคำนวณ (Proof-of-Work) ที่มากที่สุด หาก Node ที่ซื่อสัตย์ (Honest nodes) มีกำลังประมวลผลของ CPU ส่วนใหญ่อยู่ในการควบคุม Honest Chain ก็จะเติบโตเร็วที่สุดและแซงหน้า Chain อื่น ๆ ได้ ผู้โจมตีที่ต้องการแก้ไขบล็อกในอดีตจะต้องทำ Proof-of-Work ของบล็อกนั้นและบล็อกที่ตามมาใหม่ทั้งหมด และต้องทำงานให้เร็วกว่า Honest Node ด้วย ซึ่งโอกาสที่ผู้โจมตีจะตามทันนั้นจะลดลงแบบทวีคูณเมื่อมีการเพิ่มบล็อกมากขึ้น </p>
<p>เพื่อชดเชยความเร็วของฮาร์ดแวร์ที่เพิ่มขึ้นและความสนใจในการรัน Node ที่ผันผวน ระดับความยากของ Proof-of-Work จะถูกกำหนดโดยค่าเฉลี่ย โดยตั้งเป้าไว้ที่จำนวนบล็อกเฉลี่ยต่อชั่วโมง หากสร้างบล็อกได้เร็วเกินไป ระดับความยากก็จะเพิ่มขึ้น</p>
<h2>5.เครือข่าย (Network) </h2>
<p>เครือข่ายนั้นมีการทำงาน ดังนี้</p>
<ol>
<li>การประกาศธุรกรรมใหม่: ธุรกรรมใหม่จะถูกประกาศ (broadcast) ไปยังทุก node ในเครือข่าย</li>
<li>การรวบรวมธุรกรรม: แต่ละ node จะรวบรวมธุรกรรมใหม่ ๆ เหล่านี้ ไว้ในบล็อก</li>
<li>การค้นหา Proof-of-Work: แต่ละ node จะทำการคำนวณ เพื่อค้นหา Proof-of-Work ตามค่า difficulty สำหรับบล็อกนั้น ๆ </li>
<li>การประกาศบล็อก: เมื่อ node ใดค้นหา Proof-of-Work ได้แล้ว node นั้นจะทำการประกาศบล็อกไปยังทุก node ในเครือข่าย</li>
<li>การตรวจสอบและยอมรับบล็อก: node อื่น ๆ จะทำการตรวจสอบและยอมรับบล็อกนั้น เฉพาะเมื่อธุรกรรมทั้งหมดภายในบล็อกนั้นถูกต้องและยังไม่ถูกใช้มาก่อน</li>
<li>การสร้างบล็อกถัดไป: node ต่าง ๆ แสดงการยอมรับบล็อกโดยการเริ่มต้นสร้างบล็อกถัดไปใน chain ด้วย hash ของบล็อกที่ยอมรับ เป็น hash ก่อนหน้าในโครงสร้างของบล๊อกใหม่ที่กำลังสร้าง</li>
</ol>
<p>node ต่าง ๆ จะถือว่า chain ที่ยาวที่สุดเป็น chain ที่ถูกต้องและจะทำงานเพื่อขยาย chain นั้นต่อไป หากมีสอง node ที่ได้ประกาศบล็อกเวอร์ชันที่แตกต่างกันในเวลาพร้อมกัน node บาง node อาจได้รับบล็อกหนึ่งก่อน อีกบล็อกหนึ่ง ในกรณีนี้ node เหล่านั้น จะทำงานบนบล็อกที่ได้รับก่อน แต่จะเก็บสำเนาของบล็อกอีกอันหนึ่งไว้ ในกรณีที่บล็อกนั้น กลายเป็นบล็อกที่อยู่ใน chain ที่ยาวกว่าปัญหาข้อโต้แย้งนี้ก็จะได้รับการแก้ไข เมื่อพบ Proof-of-Work อันถัดไปและ chain ใด chain หนึ่งยาวขึ้น node ที่กำลังทำงานอยู่บน chain ที่สั้นกว่าก็จะเปลี่ยนไปทำงานบน chain ที่ยาวกว่าแทน</p>
<p>การประกาศธุรกรรมใหม่ ไม่จำเป็นต้องไปถึงทุก node ในเครือข่าย ตราบใดที่พวกเขายังไปถึง node ส่วนใหญ่ในระบบได้ ธุรกรรมเหล่านั้นก็จะถูกบรรจุอยู่ในบล็อกในไม่ช้า นอกจากนี้การประกาศบล็อกยังไม่ต้องกังวลเรื่องจะมีบล๊อกที่สูญหาย เนื่องจากหากว่า node ไม่ได้รับบล็อกใด ๆ  node ก็จะตระหนักได้ว่าพลาดบล็อกก่อนหน้าไปเมื่อได้รับบล๊อกใหม่มา และ node จะทำการร้องขอ block ที่ขาดไปจากเครือข่าย </p>
<h2>6.แรงจูงใจ(Incentive)</h2>
<p>โดยปกติแล้ว ธุรกรรมแรกของแต่ละบล๊อกนั้นจะเป็นธุรกรรมพิเศษที่จะขุดเหรียญที่สร้างขึ้นใหม่ซึ่งเป็นกรรมสิทธิ์ของผู้สร้างบล็อกนั้น ๆ ซึ่งจะเป็นการเพิ่มแรงจูงใจให้กับ node ต่าง ๆ ในการสนับสนุนเครือข่าย และเป็นวิธีการกระจายเหรียญให้หมุนเวียน เนื่องจากไม่มีหน่วยงานส่วนกลางที่ทำหน้าที่ในการออกเหรียญ การเพิ่มเหรียญใหม่ในปริมาณคงที่อย่างต่อเนื่องนั้นคล้ายคลึงกับการที่คนงานเหมืองทองคำใช้แรง และ เวลา เพื่อเพิ่มทองคำให้หมุนเวียน ในกรณีนี้ คือ เวลา กำลังประมวลผล และไฟฟ้าที่ถูกใช้ไป </p>
<p>นอกจากนี้แรงจูงใจจะมาจากค่าธรรมเนียมการทำธุรกรรม หากมูลค่าผลลัพธ์ของธุรกรรมน้อยกว่ามูลค่าที่ใส่เข้ามา ส่วนต่างนั้นก็คือค่าธรรมเนียมการทำธุรกรรมที่จะเพิ่มเข้าไปในมูลค่าแรงจูงใจของบล็อกที่มีธุรกรรมนั้น เมื่อเหรียญทั้งหมดในระบบมีจำนวนเท่ากับที่กำหนดไว้แล้ว  แรงจูงใจหลักก็จะถูกเปลี่ยนมาเป็นค่าธรรมเนียมการทำธุรกรรม และปราศจากภาวะเงินเฟ้อโดยสิ้นเชิง</p>
<p>แรงจูงใจอาจช่วยกระตุ้นให้ node ต่าง ๆ ยังคงซื่อสัตย์ หากผู้โจมตีที่ละโมบสามารถรวบรวมกำลังประมวลผล ได้มากกว่า node ที่ซื่อสัตย์ทั้งหมด เขาจะต้องเลือกระหว่างการใช้มันเพื่อฉ้อโกงผู้อื่นโดยการใช้จ่ายซ้ำซ้อน หรือใช้มันเพื่อสร้างเหรียญใหม่ พวกเขาจะพบว่าการเล่นตามกฎ กฎที่เอื้อประโยชน์ให้กับเขาด้วยเหรียญใหม่มากกว่าคนอื่น ๆ รวมกันนั้นทำกำไรได้มากกว่าการบ่อนทำลายระบบและความถูกต้องของทรัพย์สินของเขาเอง</p>
<h2>7.การจัดการพื้นที่ดิสก์(Reclaiming Disk Space)</h2>
<p>เมื่อธุรกรรมถูกบรรจุลงในบล๊อกแล้ว สามารถกำจัดธุรกรรมที่ใช้ไปแล้วก่อนหน้านั้นออกได้เพื่อประหยัดพื้นที่ดิสก์ แต่การจะทำอย่างนี้ได้โดยไม่ให้เลข hash ของบล๊อกมีการเปลี่ยนแปลงนั้น ธุรกรรมจึงจำเป็นต้องถูก hash ในรูปแบบของ Merkle Tree [7][2][5] โดยมีแค่ root node ของ tree เท่านั้นที่จะรวมอยู่ใน hash ของบล๊อก นี่เป็นวิธีที่ทำให้สามารถบีบอัดข้อมูลในบล๊อกเก่า ๆ ได้โดยการตัดพวก hash ส่วนอื่น ๆ ของ tree ที่ไม่ใช่ root node ออก (ไม่จำเป็นต้องเก็บ hash ในชั้นอื่น ๆ ของ tree)</p>
<p><a href="https://image.nostr.build/3ed95334891d91baca3f3f6f624a7ae22620be4ebfe0db5eb652cfce11255b9a.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/3ed95334891d91baca3f3f6f624a7ae22620be4ebfe0db5eb652cfce11255b9a.png"></a></p>
<p>โดยในส่วน header ของบล็อกที่ไม่มีธุรกรรมจะมีขนาดประมาณ 80 ไบต์ หากเราสมมติว่าบล็อกถูกสร้างขึ้นทุก ๆ 10 นาที 80 ไบต์ * 6 * 24 * 365 = 4.2MB ต่อปี โดยที่ระบบคอมพิวเตอร์ทั่วไปที่วางขายในปี 2551 มี RAM 2GB และกฎของมัวร์ทำนายการเติบโตในปัจจุบันที่ 1.2GB ต่อปี การจัดเก็บข้อมูลไม่น่าจะเป็นปัญหาแม้ว่าส่วนหัวของบล็อกจะต้องถูกเก็บไว้ในหน่วยความจำก็ตาม</p>
<h2>8.การตรวจสอบธุรกรรม (Simplified Payment Verification)</h2>
<p>การที่จะยืนยันการชำระเงินโดยไม่จำเป็นต้องรัน full node ได้นั้น ผู้ใช้เพียงแค่เก็บสำเนาของส่วนหัวบล็อก (block header) ของสายบล็อก (chain) ที่ยาวที่สุด ซึ่งสามารถรับได้โดยการสอบถามจาก node อื่น ๆ ในเครือข่ายจนมั่นใจว่าได้รับสายที่ยาวที่สุด และรับ Merkle branch ที่เชื่อมโยงธุรกรรมกับบล็อกที่มีการประทับเวลา (Timestamp) อยู่ ถึงแม้ผู้ใช้จะไม่สามารถตรวจสอบธุรกรรมด้วยตัวเองได้ แต่การเชื่อมโยงธุรกรรมกับตำแหน่งในสายบล็อกจะทำให้เห็นว่า node ในเครือข่ายยอมรับแล้ว และบล็อกที่เพิ่มเข้ามาหลังจากนั้นเป็นการยืนยันเพิ่มเติมว่าเครือข่ายยอมรับธุรกรรมนี้แล้ว</p>
<p><a href="https://i.imgur.com/VXtLpRF.png" class="vbx-media" target="_blank"><img class="venobox" src="https://i.imgur.com/VXtLpRF.png"></a></p>
<p>การตรวจสอบดังกล่าวจะเชื่อถือได้ตราบใดที่ node ที่ซื่อสัตย์ยังคงควบคุมเครือข่าย แต่จะมีความเสี่ยงมากขึ้นหากเครือข่ายถูกโจมตีและถูกควบคุม ในขณะที่ node ในเครือข่ายสามารถตรวจสอบธุรกรรมได้ด้วยตัวเอง แต่วิธีการแบบง่ายนี้อาจถูกหลอกลวงโดยการใช้ธุรกรรมปลอมของผู้โจมตี ตราบใดที่ผู้โจมตียังคงสามารถควบคุมเครือข่ายได้ กลยุทธ์หนึ่งในการป้องกันปัญหานี้คือ การรับการแจ้งเตือนจาก node อื่น ๆ ในเครือข่ายเมื่อตรวจพบบล็อกที่ไม่ถูกต้อง ซึ่งจะแจ้งให้ซอฟต์แวร์ของผู้ใช้ดาวน์โหลดบล็อกแบบเต็มและธุรกรรมที่แจ้งเตือน เพื่อยืนยันความไม่สอดคล้องกัน ธุรกิจที่ได้รับการชำระเงินบ่อยครั้งอาจยังคงต้องการรัน node ของตนเอง เพื่อความปลอดภัยที่เป็นอิสระและการตรวจสอบที่รวดเร็วยิ่งขึ้น</p>
<h2>9.การควบรวมและแบ่งย่อยมูลค่า(Combining and Splitting Value)</h2>
<p>แม้ว่าการจัดการเหรียญหลาย ๆ เหรียญจะเป็นสิ่งที่สามารถทำได้ แต่การจัดการธุรกรรมแยกต่างหากสำหรับแต่ละเหรียญในการโอนก็คงเป็นเรื่องที่น่าปวดหัวอยู่ดี ฉะนั้นแล้วเพื่อให้สามารถแยกและรวมมูลค่ากันได้ ธุรกรรมจึงสามารถมี input และ output ได้หลายรายการ ซึ่งโดยปกติแล้วจะมี input เดียวจากธุรกรรมก่อนหน้าที่มีขนาดใหญ่กว่า หรือ input จำนวนเล็ก ๆ หลาย ๆ รายการ และ output ไม่เกินสองรายการ คือ รายการหนึ่งสำหรับการชำระเงิน และอีกหนึ่งรายการสำหรับการส่งเงินทอน หากมีกลับไปยังผู้ส่ง </p>
<p> <a href="https://image.nostr.build/9c6d3ce0e9f08c5b3fa3b82c2088ac6235603e5c0df3469060e6c9f74bce32fc.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/9c6d3ce0e9f08c5b3fa3b82c2088ac6235603e5c0df3469060e6c9f74bce32fc.png"></a> </p>
<p>ควรสังเกตว่า fan-out (กระจายของธุรกรรม) ซึ่งเป็นกรณีที่ธุรกรรม ธุรกรรมหนึ่งนั้นขึ้นอยู่กับหลายธุรกรรม และธุรกรรมเหล่านั้นเองก็ขึ้นอยู่กับอีกหลายธุรกรรม แต่ไม่ใช่ปัญหาในที่นี้ เพราะไม่มีความจำเป็นในการดึงประวัติการทำธุรกรรมทั้งหมดออกมาเป็นสำเนา</p>
<h2>10.ความเป็นส่วนตัว(Privacy)</h2>
<p>ในรูปแบบธนาคารแบบดั้งเดิมนั้น ความเป็นส่วนตัวเกิดขึ้นได้ด้วยการจำกัดการเข้าถึงข้อมูล โดยให้เฉพาะผู้ที่เกี่ยวข้องและบุคคลที่สามที่ได้รับความไว้วางใจเท่านั้น แต่เนื่องจากในระบบนี้เรามีความจำเป็นในการประกาศธุรกรรมทั้งหมดต่อสาธารณะ ทำให้ไม่สามารถใช้วิธีนี้ได้ แต่ยังจำเป็นต้องคงความเป็นส่วนตัวไว้ โดยการแบ่งการไหลของข้อมูล ด้วยการไม่เปิดเผยตัวตนของเจ้าของ public key คนทั่วไปสามารถเห็นว่ามีคนกำลังส่งเงินจำนวนหนึ่งให้กับคนอื่น แต่จะไม่ทราบข้อมูลที่เชื่อมโยงธุรกรรมนั้นกับบุคคลใด ๆ ซึ่งคล้ายกับระดับข้อมูลที่เปิดเผยโดยตลาดหลักทรัพย์ ซึ่งมีการเปิดเผยเวลาและขนาดของการซื้อขายแต่ละครั้งต่อสาธารณะ แต่ไม่ได้ระบุว่าคู่สัญญาคือใคร</p>
<p> <a href="https://image.nostr.build/6ec3c84c7878dbd4558d2045518384daf5a341e86f4194cf367cc8426c2d72a7.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/6ec3c84c7878dbd4558d2045518384daf5a341e86f4194cf367cc8426c2d72a7.png"></a> </p>
<p>เพื่อเสริมในเรื่องของความปลอดภัย ควรใช้ key pair ใหม่สำหรับการทำธุรกรรมในแต่ละครั้ง เพื่อป้องกันไม่ให้เชื่อมโยงกับเจ้าของคนเดียวกันได้ อย่างไรก็ตาม การเชื่อมโยงบางอย่างยังคงหลีกเลี่ยงไม่ได้ ในธุรกรรมที่มี input หลายรายการ ซึ่งจำเป็นต้องเปิดเผยว่า input เหล่านั้นเป็นของเจ้าของคนเดียวกัน ความเสี่ยงก็คือ หากมีการเปิดเผยตัวตนของเจ้าของคีย์ การเชื่อมโยงอาจเปิดเผยธุรกรรมอื่น ๆ ที่เป็นของเจ้าของรายเดียวกันได้</p>
<h2>11.การคำนวณ(Calculations)</h2>
<p>หากลองพิจารณาสถานการณ์ที่ผู้โจมตีพยายามสร้าง chain ปลอมให้เร็วกว่า chain จริง แม้ว่าจะทำได้สำเร็จ แต่มันก็ไม่สามารถทำให้ระบบเปิดรับการเปลี่ยนแปลงตามอำเภอใจได้อยู่ดี เช่น การสร้างมูลค่าจากอากาศธาตุ หรือการรับเงินที่ไม่เคยเป็นของผู้โจมตีมาก่อน Node ต่าง ๆ จะไม่ยอมรับธุรกรรมที่ไม่ถูกต้องเป็นการชำระเงิน และ Node ที่สุจริตก็จะไม่ยอมรับบล็อกที่มีธุรกรรมเหล่านั้นอย่างแน่นอน ผู้โจมตีทำได้เพียงพยายามเปลี่ยนแปลงธุรกรรมของตนเอง เพื่อนำเงินที่ใช้ไปแล้วกลับคืนมาเท่านั้น</p>
<p>การแข่งขันระหว่าง chain สุจริตกับ chain ของผู้โจมตี สามารถอธิบายได้ด้วยแบบจำลองการเดินสุ่มทวินาม (Binomial Random Walk) โดยเหตุการณ์ที่สำเร็จ หมายถึง chain ที่สุจริตถูกขยายออกไปอีกหนึ่งบล็อก เพิ่มความยาวนำหน้าไป +1 และเหตุการณ์ที่ล้มเหลว หมายถึง chain ของผู้โจมตีถูกขยายออกไปหนึ่งบล็อก ลดช่องว่างลง -1</p>
<p>ความน่าจะเป็นที่ผู้โจมตีจะไล่ตามทันจากช่องว่างที่กำหนด สามารถเปรียบเทียบด้วย Gambler's Ruin problem โดยสมมติว่านักพนันที่มีเครดิตไม่จำกัด เริ่มต้นด้วยการขาดทุน และเล่นพนันไปเรื่อย ๆ เพื่อให้ถึงจุดคุ้มทุน เราสามารถคำนวณความน่าจะเป็นที่เขาจะกลับมาถึงจุดคุ้มทุนได้ หรือความน่าจะเป็นที่ผู้โจมตีจะไล่ทัน chain ที่สุจริตได้ ดังนี้ [8]:</p>
<p>p = ความน่าจะเป็นที่ Node ที่สุจริตจะพบบล็อกถัดไป<br>q = ความน่าจะเป็นที่ผู้โจมตีจะพบบล็อกถัดไป<br>qz = ความน่าจะเป็นที่ผู้โจมตีจะไล่ทัน จากที่ตามหลังอยู่ z บล็อก</p>
<p><a href="https://i.imgur.com/vePe255.png" class="vbx-media" target="_blank"><img class="venobox" src="https://i.imgur.com/vePe255.png"></a></p>
<p>จากสมมติฐานที่ว่า p &gt; q ความน่าจะเป็นจะลดลงแบบเอกซ์โพเนนเชียล เมื่อจำนวนบล็อกที่ผู้โจมตีต้องไล่ตามทันเพิ่มขึ้น หากเขาไม่สามารถพุ่งขึ้นนำได้อย่างรวดเร็วตั้งแต่แรก โอกาสของเขาก็จะลดลงจนน้อยมาก ๆ เมื่อเขาตามหลังมากขึ้นเรื่อย ๆ</p>
<p>ทีนี้ลองพิจารณาว่า ผู้รับธุรกรรมใหม่ต้องรอเป็นเวลานานเท่าใด จึงจะแน่ใจได้ว่าผู้ส่งไม่สามารถเปลี่ยนแปลงธุรกรรมได้แล้ว เราสมมติว่าผู้ส่งเป็นผู้โจมตี ที่ต้องการให้ผู้รับเชื่อว่าเขาได้รับเงินไปแล้ว จากนั้นจึงเปลี่ยนให้เงินกลับเข้าหาตัวเองหลังจากเวลาผ่านไประยะหนึ่ง ผู้รับจะได้รับแจ้งเมื่อเกิดเหตุการณ์นี้ขึ้น แต่ผู้ส่งหวังว่ามันจะสายเกินไปแล้ว</p>
<p>ผู้รับจะสร้างคู่กุญแจใหม่ และให้กุญแจสาธารณะแก่ผู้ส่งไม่นานก่อนที่จะลงนาม ซึ่งจะป้องกันไม่ให้ผู้ส่งเตรียมบล็อกเชนปลอมไว้ล่วงหน้า โดยการทำงานอย่างต่อเนื่องจนกว่าเขาจะมีโอกาสได้บล็อกที่ยาวพอ จากนั้นจึงดำเนินธุรกรรมในทันที เมื่อส่งธุรกรรมแล้ว ผู้ส่งที่ไม่สุจริตจะเริ่มทำงานอย่างลับ ๆ บนบล็อกเชนคู่ขนาน ที่มีธุรกรรมในเวอร์ชันของเขาเองอยู่</p>
<p>ผู้รับจะรอจนกว่าธุรกรรมจะถูกเพิ่มลงในบล็อก และมีบล็อกที่ถูกเชื่อมต่อตามหลังมาอีก z บล็อก เขาไม่ทราบจำนวนความคืบหน้าที่แน่นอนที่ผู้โจมตีได้ทำไปแล้ว แต่สมมติว่าบล็อกที่สุจริตใช้เวลาเฉลี่ยต่อบล็อกตามที่คาดไว้ ความคืบหน้าที่อาจเกิดขึ้นได้ของผู้โจมตีจะเป็นการแจกแจงแบบปัวซง (Poisson distribution) ซึ่งมีค่าคาดหวังดังนี้:</p>
<p><a href="https://i.imgur.com/mYsb48i.png" class="vbx-media" target="_blank"><img class="venobox" src="https://i.imgur.com/mYsb48i.png"></a></p>
<p>เพื่อให้ได้ความน่าจะเป็นที่ผู้โจมตียังคงสามารถไล่ทันได้ เราจะคูณความหนาแน่นของปัวซง สำหรับความคืบหน้าแต่ละระดับที่เขาสามารถทำได้ ด้วยความน่าจะเป็นที่เขาสามารถไล่ทันจากจุดนั้น:</p>
<p><a href="https://i.imgur.com/jQGkQ8r.png" class="vbx-media" target="_blank"><img class="venobox" src="https://i.imgur.com/jQGkQ8r.png"></a></p>
<p>จัดเรียงใหม่เพื่อหลีกเลี่ยง infinite tail ของการแจกแจง</p>
<p><a href="https://i.imgur.com/OOO6Gm9.png" class="vbx-media" target="_blank"><img class="venobox" src="https://i.imgur.com/OOO6Gm9.png"></a></p>
<p>แปลงมันให้เป็น C code</p>
<p>#include &lt;math.h&gt;<br>double AttackerSuccessProbability(double q, int z)<br>{<br>     double p = 1.0 - q;<br>     double lambda = z * (q / p);<br>     double sum = 1.0;<br>     int i, k;<br>         for (k = 0; k &lt;= z; k++)<br>         {<br>             double poisson = exp(-lambda);<br>             for (i = 1; i &lt;= k; i++)<br>                 poisson *= lambda / i;<br>                 sum -= poisson * (1 - pow(q / p, z - k));<br>         }<br> return sum;<br>}</p>
<p>เมื่อรันผลลัพธ์บางส่วน เราจะเห็นว่าความน่าจะเป็นลดลงแบบเอกซ์โพเนนเชียลเมื่อ z เพิ่มขึ้น</p>
<p>q=0.1<br>z=0 P=1.0000000<br>z=1 P=0.2045873<br>z=2 P=0.0509779<br>z=3 P=0.0131722<br>z=4 P=0.0034552<br>z=5 P=0.0009137<br>z=6 P=0.0002428<br>z=7 P=0.0000647<br>z=8 P=0.0000173<br>z=9 P=0.0000046<br>z=10 P=0.0000012<br>q=0.3<br>z=0 P=1.0000000<br>z=5 P=0.1773523<br>z=10 P=0.0416605<br>z=15 P=0.0101008<br>z=20 P=0.0024804<br>z=25 P=0.0006132<br>z=30 P=0.0001522<br>z=35 P=0.0000379<br>z=40 P=0.0000095<br>z=45 P=0.0000024<br>z=50 P=0.0000006</p>
<p>การแก้หาค่า P ที่น้อยกว่า 0.1%...</p>
<p>P &lt; 0.001<br>q=0.10 z=5<br>q=0.15 z=8<br>q=0.20 z=11<br>q=0.25 z=15<br>q=0.30 z=24<br>q=0.35 z=41<br>q=0.40 z=89<br>q=0.45 z=340</p>
<p>12.สรุป(Conclusion)</p>
<p>เราได้นำเสนอระบบธุรกรรมอิเล็กทรอนิกส์ที่ไม่ต้องพึ่งพาความไว้วางใจ เริ่มต้นจากกรอบแนวคิดของเหรียญที่สร้างจากลายเซ็นดิจิทัล ซึ่งช่วยควบคุมความเป็นเจ้าของได้อย่างดีแต่ก็ยังไม่สมบูรณ์ หากปราศจากวิธีการป้องกันการใช้จ่ายซ้ำซ้อน เพื่อแก้ปัญหานี้ เราจึงเสนอเครือข่ายแบบเพียร์ทูเพียร์ที่ใช้ proof-of-work ในการบันทึกประวัติธุรกรรมสาธารณะ ซึ่งจะกลายเป็นเรื่องยากอย่างมากสำหรับผู้โจมตีที่จะเปลี่ยนแปลง หาก node ที่ซื่อสัตย์ควบคุมพลังประมวลผล CPU ส่วนใหญ่ เครือข่ายนี้มีความแข็งแกร่งในความเรียบง่ายที่ไม่มีโครงสร้างใด ๆ ที่ซับซ้อน node ต่าง ๆ ทำงานพร้อมกันโดยประสานงานกันเพียงเล็กน้อย ไม่จำเป็นต้องระบุตัวตน เนื่องจากข้อความไม่ได้ถูกส่งไปยังสถานที่ใดสถานที่หนึ่งโดยเฉพาะ และเพียงแค่ต้องส่งมอบให้ถึงมือผู้รับอย่างดีที่สุด  node สามารถออกจากและเข้าร่วมเครือข่ายได้ตามต้องการ โดยยอมรับ chain ที่มี proof-of-work มากที่สุดเป็นสิ่งที่เกิดขึ้นในขณะที่ไม่ได้เชื่อมต่อ พวกเขาโหวตด้วยพลังประมวลผล CPU แสดงการยอมรับบล็อกที่ถูกต้องโดยการทำงานเพื่อขยายบล็อก และปฏิเสธบล็อกที่ไม่ถูกต้องโดยการปฏิเสธที่จะทำงานกับบล็อกเหล่านั้น กฎและแรงจูงใจใด ๆ ที่จำเป็นสามารถบังคับใช้ได้ด้วยกลไกฉันทามตินี้</p>
<h2>ไปอ่านต่อกันเองเด้ออ</h2>
<p>[1] W. Dai, "b-money," <np-embed url="http://www.weidai.com/bmoney.txt"><a href="http://www.weidai.com/bmoney.txt">http://www.weidai.com/bmoney.txt</a></np-embed>, 1998.<br>[2] H. Massias, X.S. Avila, and J.-J. Quisquater, "Design of a secure timestamping service with minimal<br>trust requirements," In 20th Symposium on Information Theory in the Benelux, May 1999.<br>[3] S. Haber, W.S. Stornetta, "How to time-stamp a digital document," In Journal of Cryptology, vol 3, no<br>2, pages 99-111, 1991.<br>[4] D. Bayer, S. Haber, W.S. Stornetta, "Improving the efficiency and reliability of digital time-stamping,"<br>In Sequences II: Methods in Communication, Security and Computer Science, pages 329-334, 1993.<br>[5] S. Haber, W.S. Stornetta, "Secure names for bit-strings," In Proceedings of the 4th ACM Conference<br>on Computer and Communications Security, pages 28-35, April 1997.<br>[6] A. Back, "Hashcash - a denial of service counter-measure,"<br><np-embed url="http://www.hashcash.org/papers/hashcash.pdf"><a href="http://www.hashcash.org/papers/hashcash.pdf">http://www.hashcash.org/papers/hashcash.pdf</a></np-embed>, 2002.<br>[7] R.C. Merkle, "Protocols for public key cryptosystems," In Proc. 1980 Symposium on Security and<br>Privacy, IEEE Computer Society, pages 122-133, April 1980.<br>[8] W. Feller, "An introduction to probability theory and its applications," 1957.</p>
]]></content:encoded>
      <itunes:author><![CDATA[Learning_BTC&NOSTR]]></itunes:author>
      <itunes:summary><![CDATA[<h2>ระบบเงินอิเล็กทรอนิกส์แบบ peer-to-peer </h2>
<p>ระบบเงินอิเล็กทรอนิกส์แบบ peer-to-peer นั้นจะช่วยให้เราสามารถชำระเงินผ่านทางออนไลน์ได้โดยตรงจากฝ่ายหนึ่งไปยังอีกฝ่ายหนึ่งโดยไม่ต้องผ่านตัวกลางอย่างพวกสถาบันการเงิน โดยใช้ digital signature เป็นส่วนหนึ่งในการแก้ปัญหานี้ แต่มันจะไม่มีประโยชน์ใด ๆ เลยหากยังคงต้องอาศัยตัวกลางที่เชื่อถือได้มาแก้ปัญหา double spending เราขอเสนอวิธีแก้ปัญหา double spending โดยใช้เครือข่ายแบบ peer-to-peer ให้เครือข่ายคอยประทับเวลาธุรกรรมต่าง ๆ ในระบบและนำมาเรียงร้อยกันเป็นเส้นสายของ proof-of-work ที่ใช้ hash เพื่อสร้างธุรกรรมที่ไม่สามารถเปลี่ยนแปลงได้ โดยไม่ต้องทำ proof-of-work ใหม่ โดยให้เส้นสายที่ยาวที่สุดนั้น ไม่เพียงแต่ทำหน้าที่เป็นลำดับของธุรกรรมที่เกิดขึ้นเท่านั้น แต่ยังเป็นสิ่งที่พิสูจน์ได้ว่ามาจากกำลังประมวลผล CPU ที่มากที่สุด และตราบใดที่ nodes ส่วนใหญ่ไม่ได้ร่วมมือกันโจมตีเครือข่ายและยังคงควบคุมกำลังประมวลผลส่วนใหญ่ในระบบไว้ พวกเขาก็จะสร้างเส้นสายที่ยาวที่สุดและสามารถเอาชนะผู้ประสงค์ร้ายที่จะโจมตีระบบได้ ตัวเครือข่ายเองไม่ได้ต้องมีโครงสร้างอะไรที่ซับซ้อน ข้อมูลต่าง ๆ ในเครือข่ายจะถูกกระจายส่งต่อโดยไม่ต้องสนใจว่าผู้รับจะได้รับหรือไม่ และ nodes ต่าง ๆ เองก็สามารถที่จะออกจากเครือข่ายและกลับเข้าร่วมใหม่ได้ตามที่ต้องการ โดยยอมรับเส้น proof-of-work ที่ยาวที่สุด เป็นหลักฐานของสิ่งที่เกิดขึ้นในขณะที่ node นั้น ๆ ไม่ได้อยู่ในเครือข่าย</p>
<h2>1.บทนำ (Introduction)</h2>
<p>ไม่ว่าใครจะใคร่ซื้อใคร่ขายอะไรใด ๆ บนอินเตอร์เน็ตนั้น ก็จำเป็นต้องพึ่งพาสถาบันการเงินในฐานะของบุคคลที่สามเพื่อดำเนินการชำระเงินทางอิเล็กทรอนิกส์เสมอ ๆ  ซึ่งถึงแม้ว่าระบบนี้มันจะทำงานได้ดีสำหรับธุรกรรมส่วนใหญ่ ๆ แต่ระบบก็ก็มีจุดอ่อนอยู่ที่ยังต้องอาศัยความไว้เนื้อเชื่อใจ (trust) ในระบบนี้การทำธุรกรรมที่ไม่สามารถย้อนกลับได้อย่างสมบูรณ์นั้นมันแทบจะเป็นไปไม่ได้เลย เนื่องจากสถาบันการเงินไม่สามารถหลีกเลี่ยงการเป็นตัวกลางในการไกล่เกลี่ยข้อพิพาทต่าง ๆ ที่อาจเกิดขึ้นได้ มิหนำซ้ำต้นทุนในการไกล่เกลี่ยยังทำให้ต้นทุนการทำธุรกรรมเพิ่มสูงขึ้น และเมื่อต้นทุนสูงขึ้นขนาดของธุรกรรมที่สามารถใช้งานได้จริงก็สูงขึ้นตามไปด้วย ธุรกรรมเล็ก ๆ น้อย ๆ ก็ไม่สามารถเกิดขึ้นได้ เมื่อมีความเป็นไปได้ที่ธุรกรรมจะเกิดการย้อนกลับ ความจำเป็นในการสร้างความไว้วางใจก็ยิ่งทวีคูณมากขึ้น ผู้ค้าก็จำเป็นต้องระมัดระวังลูกค้า ต้องเรียกร้องข้อมูลมากกว่าที่จำเป็น การฉ้อโกงกลายเป็นเรื่องที่หลีกเลี่ยงไม่ได้เพราะต้นทุนและความไม่แน่นอนในทำธุรกรรมเหล่านี้ แน่นอนว่าเราสามารถหลีกเลี่ยงมันได้โดยการใช้เงินสด แต่ก็ไม่มีกลไกใดที่ทำให้สามารถใช้เงินสดผ่านช่องทางการสื่อสาร (เอาให้เข้าใจง่ายก็อินเตอร์เน็ต)ได้ โดยไม่ต้องมีตัวกลาง ;-;</p>
<p>แปลว่าสิ่งที่จำเป็นสำหรับการแก้ไขปัญหานี้คือระบบการชำระเงินทางอิเล็กทรอนิกส์ ที่อยู่บนพื้นฐานของการพิสูจน์ด้วยการเข้ารหัสแทนที่จะเป็นความไว้วางใจ ซึ่งจะทำให้คู่สัญญาสองฝ่ายที่ยินยอมสามารถทำธุรกรรมร่วมกันได้โดยตรง โดยไม่จำเป็นต้องมีบุคคลที่สามมาคอยเป็นตัวกลาง ธุรกรรมที่ยากต่อการย้อนกลับจะช่วยปกป้องผู้ขายจากการฉ้อโกง และสามารถใช้กลไก escrow เพื่อปกป้องผู้ซื้อได้อีกด้วย ในเอกสารชุดนี้ เราขอเสนอวิธีแก้ปัญหาการใช้จ่ายซ้ำซ้อนโดยใช้เซิร์ฟเวอร์ timestamp กระจายศูนย์แบบ peer-to-peer เพื่อสร้างหลักฐานการคำนวณลำดับเวลาของธุรกรรม โดยระบบนี้จะปลอดภัยตราบใดที่กลุ่มของ node ที่ซื่อสัตย์ ยังคงมีกำลังประมวลผลที่มากกว่ากลุ่มที่ประสงค์ร้ายกับระบบ</p>
<h2>2.ธุรกรรม (Transactions) </h2>
<p>นิยามของเหรียญอิเล็กทรอนิกส์ในที่นี้ คือห่วงโซ่ที่คล้องเกี่ยวกันของ digital signature โดยที่เจ้าของเหรียญอิเล็กทรอนิกส์จะโอนเหรียญไปยังเจ้าของคนถัดไป ด้วยการลง digital signature บน hash ของธุรกรรมก่อนหน้ารวมถึงกุญแจสาธารณะของเจ้าของคนถัดไป และผนวกมันไว้ที่ส่วนท้ายของธุรกรรม และผู้รับเงินเองก็สามารถตรวจสอบลายเซ็นเพื่อยืนยันความเป็นเจ้าของได้ </p>
<p><a href="https://image.nostr.build/a467896797a9fb9f98c3c234f0adb4df2376f2c3d9a7cc9d8672d7a9f5aa9efa.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/a467896797a9fb9f98c3c234f0adb4df2376f2c3d9a7cc9d8672d7a9f5aa9efa.png"></a></p>
<p>แน่นอนว่าปัญหาก็คือผู้รับเงินไม่สามารถตรวจสอบได้ว่าเจ้าของคนใดคนหนึ่งก่อนหน้าเขาได้ใช้เหรียญดังกล่าวซ้ำซ้อนมากกว่าหนึ่งครั้งหรือไม่ และวิธีการแก้ไขปัญหานี้โดยทั่วไปก็คงเป็นการกำหนดตัวกลางที่มีความน่าเชื่อถือมาเป็นคนตรวจสอบทุกธุรกรรมเพื่อป้องกันการใช้จ่ายซ้ำซ้อน และหลังจากการทำธุรกรรมแต่ละครั้ง เหรียญจะต้องถูกส่งกลับไปยังตัวกลางเพื่อออกเหรียญใหม่ และจะมีเพียงเหรียญที่ออกจากตัวกลางโดยตรงเท่านั้นที่จะเชื่อถือได้ว่าจะไม่ถูกใช้จ่ายซ้ำซ้อน แต่ปัญหาก็คือ ชะตากรรมของระบบเงินทั้งหมดจะขึ้นอยู่กับตัวกลางตัวนี้ เพราะทุกธุรกรรมจำเป็นจะต้องผ่านพวกเขา ซึ่งก็ไม่ต่างอะไรกับธนาคาร</p>
<p>เราจึงต้องการวิธีการที่ทำให้ผู้รับเงินทราบได้ว่าเจ้าของคนก่อน ๆ ไม่ได้ลงนามในธุรกรรมใด ๆ มาก่อน เพื่อให้บรรลุวัตถุประสงค์นี้ เราจะทำการนับว่าธุรกรรมที่เกิดขึ้นก่อนเป็นธุรกรรมที่ถูกต้อง และจะไม่สนใจความพยายามใด ๆ ในการที่จะใช้เหรียญนั้น ๆ ซ้ำอีก และวิธีเดียวที่ทำแบบนี้ได้ คือการรับรู้ถึงธุรกรรมทั้งหมด เช่นเดียวกับโมเดลที่ได้กล่าวข้างต้น ที่ตัวกลางจะรับรู้ถึงธุรกรรมทั้งหมดและตัดสินว่าธุรกรรมใดมาก่อนมาหลัง เพื่อให้บรรลุเป้าหมายนี้โดยไม่ต้องมีบุคคลที่สามที่เชื่อถือได้ ธุรกรรมทั้งหมดจะต้องถูกประกาศต่อสาธารณะ [1] และเราต้องการระบบที่ผู้เข้าร่วมเห็นพ้องในประวัติธุรกรรมชุดเดียวกันตามลำดับที่ได้รับ ส่วนผู้รับเงินก็จำเป็นจะต้องมีหลักฐานว่า ในขณะที่ทำธุรกรรม "โหนด" ส่วนใหญ่ในระบบเห็นพ้องต้องกันว่าธุรกรรมนั้นได้รับเป็นลำดับแรก(ไม่มีธุรกรรมที่ใช้เหรียญพวกนี้มาก่อน) </p>
<h2>3.ระบบบันทึกเวลา (Timestamp Server)</h2>
<p>สำหรับแนวทางการแก้ปัญหาในครั้งนี้ เราจะใช้ประโยชน์จาก timestamp server ที่จะทำหน้าที่บันทึก hash ของบล๊อกที่ต้องการให้มีการบันทึกเวลา และจากนั้นจะทำการเผยแพร่ hash ดังกล่าว เหมือนกับหนังสือพิมพ์หรือโพสต์ใน Usenet [2-5] (ฟีลแบบทุกคนจะเห็นโพสต์นี้น้าา ประมาณนั้น) การบันทึกเวลานี้จะพิสูจน์ได้ว่าข้อมูลที่ถูก hash นั้นจะต้องมีอยู่จริงในเวลานั้นเพื่อให้ได้มาซึ่ง hash ดังกล่าว แต่ละการบันทึกเวลาจะรวมการบันทึกเวลาของหน้านี้ไว้ใน hash ของมันเพื่อสร้างเป็น chain โดยการบันทึกเวลาแต่ละครั้งจะยืนยันความถูกต้องของการบันทึกก่อนหน้าได้อีกด้วยด้วย</p>
<p> <a href="https://image.nostr.build/ddf92417c45dbb6e25da0af80a10d4cdbc3e725d047d65f54a3e3bfcf358c4d6.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/ddf92417c45dbb6e25da0af80a10d4cdbc3e725d047d65f54a3e3bfcf358c4d6.png"></a></p>
<h2>4.พรูฟ-ออฟ-เวิร์ค (Proof-of-Work)</h2>
<p>ในการสร้าง Timestamp Server แบบกระจายศูนย์บนพื้นฐานแบบ peer to peer เราจำเป็นต้องใช้ระบบ Proof-of-Work (PoW) ที่คล้ายกับ Hashcash ของ Adam Back [6] แทนที่จะใช้วิธีการแบบเดิม ๆ อย่างการประกาศในหนังสือพิมพ์หรือ Usenet โดย PoW ใช้ในการตรวจสอบค่าที่มาจากกระบวนการ hash เช่น SHA-256 แล้ว ผลลัพธ์ที่ได้ (Hash) จะขึ้นต้นด้วยเลขศูนย์จำนวนหนึ่ง โดยที่ work (ประมาณว่าพลังประมวลผล) ที่ต้องใช้จะเพิ่มขึ้นแบบทวีคูณตามจำนวนเลขศูนย์ที่ต้องการ และสามารถตรวจสอบได้โดยการรัน Hash เพียงครั้งเดียว</p>
<p>ซึ่งสำหรับ timestamp network ของเรานั้น เราใช้ PoW โดยการเพิ่มค่า Nonce ในบล็อกไปเรื่อย ๆ จนกว่าจะพบค่าที่ทำให้ Hash ของบล็อกนั้นมีเลขศูนย์ตามที่กำหนด และเมื่อใช้กำลังประมวลผลของ CPU ไปกับการทำ PoW จนสำเร็จแล้ว บล็อกจะไม่สามารถเปลี่ยนแปลงได้ หากไม่มีการทำงานซ้ำใหม่ เนื่องจากบล็อกที่สร้างขึ้นภายหลังจะเชื่อมโยงกับบล็อกก่อนหน้า การเปลี่ยนแปลงบล็อกใด ๆ จะต้องทำ PoW ของบล็อกนั้นและบล็อกที่ตามมาใหม่ทั้งหมด</p>
<p> <a href="https://image.nostr.build/c039ef4ca6833cb1ecee65ac5991df2406be9b7e490b86b3b19f94f267767182.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/c039ef4ca6833cb1ecee65ac5991df2406be9b7e490b86b3b19f94f267767182.png"></a> </p>
<p>นอกจากนี้ PoW ยังช่วยแก้ปัญหาของเสียงส่วนมากที่มาตัดสินใจในระบบนี้ เพราะหากเสียงข้างมากอ้างอิงจากหลักการหนึ่ง IP หนึ่งเสียง ใครก็ตามที่สามารถสร้าง IP ได้จำนวนมากก็จะสามารถควบคุมระบบได้ จึงใช้หลักการหนึ่ง CPU หนึ่งเสียงแทน การตัดสินใจของเสียงข้างมากจะแสดงด้วย Chain ที่ยาวที่สุด ซึ่งบ่งบอกถึงความพยายามในการคำนวณ (Proof-of-Work) ที่มากที่สุด หาก Node ที่ซื่อสัตย์ (Honest nodes) มีกำลังประมวลผลของ CPU ส่วนใหญ่อยู่ในการควบคุม Honest Chain ก็จะเติบโตเร็วที่สุดและแซงหน้า Chain อื่น ๆ ได้ ผู้โจมตีที่ต้องการแก้ไขบล็อกในอดีตจะต้องทำ Proof-of-Work ของบล็อกนั้นและบล็อกที่ตามมาใหม่ทั้งหมด และต้องทำงานให้เร็วกว่า Honest Node ด้วย ซึ่งโอกาสที่ผู้โจมตีจะตามทันนั้นจะลดลงแบบทวีคูณเมื่อมีการเพิ่มบล็อกมากขึ้น </p>
<p>เพื่อชดเชยความเร็วของฮาร์ดแวร์ที่เพิ่มขึ้นและความสนใจในการรัน Node ที่ผันผวน ระดับความยากของ Proof-of-Work จะถูกกำหนดโดยค่าเฉลี่ย โดยตั้งเป้าไว้ที่จำนวนบล็อกเฉลี่ยต่อชั่วโมง หากสร้างบล็อกได้เร็วเกินไป ระดับความยากก็จะเพิ่มขึ้น</p>
<h2>5.เครือข่าย (Network) </h2>
<p>เครือข่ายนั้นมีการทำงาน ดังนี้</p>
<ol>
<li>การประกาศธุรกรรมใหม่: ธุรกรรมใหม่จะถูกประกาศ (broadcast) ไปยังทุก node ในเครือข่าย</li>
<li>การรวบรวมธุรกรรม: แต่ละ node จะรวบรวมธุรกรรมใหม่ ๆ เหล่านี้ ไว้ในบล็อก</li>
<li>การค้นหา Proof-of-Work: แต่ละ node จะทำการคำนวณ เพื่อค้นหา Proof-of-Work ตามค่า difficulty สำหรับบล็อกนั้น ๆ </li>
<li>การประกาศบล็อก: เมื่อ node ใดค้นหา Proof-of-Work ได้แล้ว node นั้นจะทำการประกาศบล็อกไปยังทุก node ในเครือข่าย</li>
<li>การตรวจสอบและยอมรับบล็อก: node อื่น ๆ จะทำการตรวจสอบและยอมรับบล็อกนั้น เฉพาะเมื่อธุรกรรมทั้งหมดภายในบล็อกนั้นถูกต้องและยังไม่ถูกใช้มาก่อน</li>
<li>การสร้างบล็อกถัดไป: node ต่าง ๆ แสดงการยอมรับบล็อกโดยการเริ่มต้นสร้างบล็อกถัดไปใน chain ด้วย hash ของบล็อกที่ยอมรับ เป็น hash ก่อนหน้าในโครงสร้างของบล๊อกใหม่ที่กำลังสร้าง</li>
</ol>
<p>node ต่าง ๆ จะถือว่า chain ที่ยาวที่สุดเป็น chain ที่ถูกต้องและจะทำงานเพื่อขยาย chain นั้นต่อไป หากมีสอง node ที่ได้ประกาศบล็อกเวอร์ชันที่แตกต่างกันในเวลาพร้อมกัน node บาง node อาจได้รับบล็อกหนึ่งก่อน อีกบล็อกหนึ่ง ในกรณีนี้ node เหล่านั้น จะทำงานบนบล็อกที่ได้รับก่อน แต่จะเก็บสำเนาของบล็อกอีกอันหนึ่งไว้ ในกรณีที่บล็อกนั้น กลายเป็นบล็อกที่อยู่ใน chain ที่ยาวกว่าปัญหาข้อโต้แย้งนี้ก็จะได้รับการแก้ไข เมื่อพบ Proof-of-Work อันถัดไปและ chain ใด chain หนึ่งยาวขึ้น node ที่กำลังทำงานอยู่บน chain ที่สั้นกว่าก็จะเปลี่ยนไปทำงานบน chain ที่ยาวกว่าแทน</p>
<p>การประกาศธุรกรรมใหม่ ไม่จำเป็นต้องไปถึงทุก node ในเครือข่าย ตราบใดที่พวกเขายังไปถึง node ส่วนใหญ่ในระบบได้ ธุรกรรมเหล่านั้นก็จะถูกบรรจุอยู่ในบล็อกในไม่ช้า นอกจากนี้การประกาศบล็อกยังไม่ต้องกังวลเรื่องจะมีบล๊อกที่สูญหาย เนื่องจากหากว่า node ไม่ได้รับบล็อกใด ๆ  node ก็จะตระหนักได้ว่าพลาดบล็อกก่อนหน้าไปเมื่อได้รับบล๊อกใหม่มา และ node จะทำการร้องขอ block ที่ขาดไปจากเครือข่าย </p>
<h2>6.แรงจูงใจ(Incentive)</h2>
<p>โดยปกติแล้ว ธุรกรรมแรกของแต่ละบล๊อกนั้นจะเป็นธุรกรรมพิเศษที่จะขุดเหรียญที่สร้างขึ้นใหม่ซึ่งเป็นกรรมสิทธิ์ของผู้สร้างบล็อกนั้น ๆ ซึ่งจะเป็นการเพิ่มแรงจูงใจให้กับ node ต่าง ๆ ในการสนับสนุนเครือข่าย และเป็นวิธีการกระจายเหรียญให้หมุนเวียน เนื่องจากไม่มีหน่วยงานส่วนกลางที่ทำหน้าที่ในการออกเหรียญ การเพิ่มเหรียญใหม่ในปริมาณคงที่อย่างต่อเนื่องนั้นคล้ายคลึงกับการที่คนงานเหมืองทองคำใช้แรง และ เวลา เพื่อเพิ่มทองคำให้หมุนเวียน ในกรณีนี้ คือ เวลา กำลังประมวลผล และไฟฟ้าที่ถูกใช้ไป </p>
<p>นอกจากนี้แรงจูงใจจะมาจากค่าธรรมเนียมการทำธุรกรรม หากมูลค่าผลลัพธ์ของธุรกรรมน้อยกว่ามูลค่าที่ใส่เข้ามา ส่วนต่างนั้นก็คือค่าธรรมเนียมการทำธุรกรรมที่จะเพิ่มเข้าไปในมูลค่าแรงจูงใจของบล็อกที่มีธุรกรรมนั้น เมื่อเหรียญทั้งหมดในระบบมีจำนวนเท่ากับที่กำหนดไว้แล้ว  แรงจูงใจหลักก็จะถูกเปลี่ยนมาเป็นค่าธรรมเนียมการทำธุรกรรม และปราศจากภาวะเงินเฟ้อโดยสิ้นเชิง</p>
<p>แรงจูงใจอาจช่วยกระตุ้นให้ node ต่าง ๆ ยังคงซื่อสัตย์ หากผู้โจมตีที่ละโมบสามารถรวบรวมกำลังประมวลผล ได้มากกว่า node ที่ซื่อสัตย์ทั้งหมด เขาจะต้องเลือกระหว่างการใช้มันเพื่อฉ้อโกงผู้อื่นโดยการใช้จ่ายซ้ำซ้อน หรือใช้มันเพื่อสร้างเหรียญใหม่ พวกเขาจะพบว่าการเล่นตามกฎ กฎที่เอื้อประโยชน์ให้กับเขาด้วยเหรียญใหม่มากกว่าคนอื่น ๆ รวมกันนั้นทำกำไรได้มากกว่าการบ่อนทำลายระบบและความถูกต้องของทรัพย์สินของเขาเอง</p>
<h2>7.การจัดการพื้นที่ดิสก์(Reclaiming Disk Space)</h2>
<p>เมื่อธุรกรรมถูกบรรจุลงในบล๊อกแล้ว สามารถกำจัดธุรกรรมที่ใช้ไปแล้วก่อนหน้านั้นออกได้เพื่อประหยัดพื้นที่ดิสก์ แต่การจะทำอย่างนี้ได้โดยไม่ให้เลข hash ของบล๊อกมีการเปลี่ยนแปลงนั้น ธุรกรรมจึงจำเป็นต้องถูก hash ในรูปแบบของ Merkle Tree [7][2][5] โดยมีแค่ root node ของ tree เท่านั้นที่จะรวมอยู่ใน hash ของบล๊อก นี่เป็นวิธีที่ทำให้สามารถบีบอัดข้อมูลในบล๊อกเก่า ๆ ได้โดยการตัดพวก hash ส่วนอื่น ๆ ของ tree ที่ไม่ใช่ root node ออก (ไม่จำเป็นต้องเก็บ hash ในชั้นอื่น ๆ ของ tree)</p>
<p><a href="https://image.nostr.build/3ed95334891d91baca3f3f6f624a7ae22620be4ebfe0db5eb652cfce11255b9a.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/3ed95334891d91baca3f3f6f624a7ae22620be4ebfe0db5eb652cfce11255b9a.png"></a></p>
<p>โดยในส่วน header ของบล็อกที่ไม่มีธุรกรรมจะมีขนาดประมาณ 80 ไบต์ หากเราสมมติว่าบล็อกถูกสร้างขึ้นทุก ๆ 10 นาที 80 ไบต์ * 6 * 24 * 365 = 4.2MB ต่อปี โดยที่ระบบคอมพิวเตอร์ทั่วไปที่วางขายในปี 2551 มี RAM 2GB และกฎของมัวร์ทำนายการเติบโตในปัจจุบันที่ 1.2GB ต่อปี การจัดเก็บข้อมูลไม่น่าจะเป็นปัญหาแม้ว่าส่วนหัวของบล็อกจะต้องถูกเก็บไว้ในหน่วยความจำก็ตาม</p>
<h2>8.การตรวจสอบธุรกรรม (Simplified Payment Verification)</h2>
<p>การที่จะยืนยันการชำระเงินโดยไม่จำเป็นต้องรัน full node ได้นั้น ผู้ใช้เพียงแค่เก็บสำเนาของส่วนหัวบล็อก (block header) ของสายบล็อก (chain) ที่ยาวที่สุด ซึ่งสามารถรับได้โดยการสอบถามจาก node อื่น ๆ ในเครือข่ายจนมั่นใจว่าได้รับสายที่ยาวที่สุด และรับ Merkle branch ที่เชื่อมโยงธุรกรรมกับบล็อกที่มีการประทับเวลา (Timestamp) อยู่ ถึงแม้ผู้ใช้จะไม่สามารถตรวจสอบธุรกรรมด้วยตัวเองได้ แต่การเชื่อมโยงธุรกรรมกับตำแหน่งในสายบล็อกจะทำให้เห็นว่า node ในเครือข่ายยอมรับแล้ว และบล็อกที่เพิ่มเข้ามาหลังจากนั้นเป็นการยืนยันเพิ่มเติมว่าเครือข่ายยอมรับธุรกรรมนี้แล้ว</p>
<p><a href="https://i.imgur.com/VXtLpRF.png" class="vbx-media" target="_blank"><img class="venobox" src="https://i.imgur.com/VXtLpRF.png"></a></p>
<p>การตรวจสอบดังกล่าวจะเชื่อถือได้ตราบใดที่ node ที่ซื่อสัตย์ยังคงควบคุมเครือข่าย แต่จะมีความเสี่ยงมากขึ้นหากเครือข่ายถูกโจมตีและถูกควบคุม ในขณะที่ node ในเครือข่ายสามารถตรวจสอบธุรกรรมได้ด้วยตัวเอง แต่วิธีการแบบง่ายนี้อาจถูกหลอกลวงโดยการใช้ธุรกรรมปลอมของผู้โจมตี ตราบใดที่ผู้โจมตียังคงสามารถควบคุมเครือข่ายได้ กลยุทธ์หนึ่งในการป้องกันปัญหานี้คือ การรับการแจ้งเตือนจาก node อื่น ๆ ในเครือข่ายเมื่อตรวจพบบล็อกที่ไม่ถูกต้อง ซึ่งจะแจ้งให้ซอฟต์แวร์ของผู้ใช้ดาวน์โหลดบล็อกแบบเต็มและธุรกรรมที่แจ้งเตือน เพื่อยืนยันความไม่สอดคล้องกัน ธุรกิจที่ได้รับการชำระเงินบ่อยครั้งอาจยังคงต้องการรัน node ของตนเอง เพื่อความปลอดภัยที่เป็นอิสระและการตรวจสอบที่รวดเร็วยิ่งขึ้น</p>
<h2>9.การควบรวมและแบ่งย่อยมูลค่า(Combining and Splitting Value)</h2>
<p>แม้ว่าการจัดการเหรียญหลาย ๆ เหรียญจะเป็นสิ่งที่สามารถทำได้ แต่การจัดการธุรกรรมแยกต่างหากสำหรับแต่ละเหรียญในการโอนก็คงเป็นเรื่องที่น่าปวดหัวอยู่ดี ฉะนั้นแล้วเพื่อให้สามารถแยกและรวมมูลค่ากันได้ ธุรกรรมจึงสามารถมี input และ output ได้หลายรายการ ซึ่งโดยปกติแล้วจะมี input เดียวจากธุรกรรมก่อนหน้าที่มีขนาดใหญ่กว่า หรือ input จำนวนเล็ก ๆ หลาย ๆ รายการ และ output ไม่เกินสองรายการ คือ รายการหนึ่งสำหรับการชำระเงิน และอีกหนึ่งรายการสำหรับการส่งเงินทอน หากมีกลับไปยังผู้ส่ง </p>
<p> <a href="https://image.nostr.build/9c6d3ce0e9f08c5b3fa3b82c2088ac6235603e5c0df3469060e6c9f74bce32fc.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/9c6d3ce0e9f08c5b3fa3b82c2088ac6235603e5c0df3469060e6c9f74bce32fc.png"></a> </p>
<p>ควรสังเกตว่า fan-out (กระจายของธุรกรรม) ซึ่งเป็นกรณีที่ธุรกรรม ธุรกรรมหนึ่งนั้นขึ้นอยู่กับหลายธุรกรรม และธุรกรรมเหล่านั้นเองก็ขึ้นอยู่กับอีกหลายธุรกรรม แต่ไม่ใช่ปัญหาในที่นี้ เพราะไม่มีความจำเป็นในการดึงประวัติการทำธุรกรรมทั้งหมดออกมาเป็นสำเนา</p>
<h2>10.ความเป็นส่วนตัว(Privacy)</h2>
<p>ในรูปแบบธนาคารแบบดั้งเดิมนั้น ความเป็นส่วนตัวเกิดขึ้นได้ด้วยการจำกัดการเข้าถึงข้อมูล โดยให้เฉพาะผู้ที่เกี่ยวข้องและบุคคลที่สามที่ได้รับความไว้วางใจเท่านั้น แต่เนื่องจากในระบบนี้เรามีความจำเป็นในการประกาศธุรกรรมทั้งหมดต่อสาธารณะ ทำให้ไม่สามารถใช้วิธีนี้ได้ แต่ยังจำเป็นต้องคงความเป็นส่วนตัวไว้ โดยการแบ่งการไหลของข้อมูล ด้วยการไม่เปิดเผยตัวตนของเจ้าของ public key คนทั่วไปสามารถเห็นว่ามีคนกำลังส่งเงินจำนวนหนึ่งให้กับคนอื่น แต่จะไม่ทราบข้อมูลที่เชื่อมโยงธุรกรรมนั้นกับบุคคลใด ๆ ซึ่งคล้ายกับระดับข้อมูลที่เปิดเผยโดยตลาดหลักทรัพย์ ซึ่งมีการเปิดเผยเวลาและขนาดของการซื้อขายแต่ละครั้งต่อสาธารณะ แต่ไม่ได้ระบุว่าคู่สัญญาคือใคร</p>
<p> <a href="https://image.nostr.build/6ec3c84c7878dbd4558d2045518384daf5a341e86f4194cf367cc8426c2d72a7.png" class="vbx-media" target="_blank"><img class="venobox" src="https://image.nostr.build/6ec3c84c7878dbd4558d2045518384daf5a341e86f4194cf367cc8426c2d72a7.png"></a> </p>
<p>เพื่อเสริมในเรื่องของความปลอดภัย ควรใช้ key pair ใหม่สำหรับการทำธุรกรรมในแต่ละครั้ง เพื่อป้องกันไม่ให้เชื่อมโยงกับเจ้าของคนเดียวกันได้ อย่างไรก็ตาม การเชื่อมโยงบางอย่างยังคงหลีกเลี่ยงไม่ได้ ในธุรกรรมที่มี input หลายรายการ ซึ่งจำเป็นต้องเปิดเผยว่า input เหล่านั้นเป็นของเจ้าของคนเดียวกัน ความเสี่ยงก็คือ หากมีการเปิดเผยตัวตนของเจ้าของคีย์ การเชื่อมโยงอาจเปิดเผยธุรกรรมอื่น ๆ ที่เป็นของเจ้าของรายเดียวกันได้</p>
<h2>11.การคำนวณ(Calculations)</h2>
<p>หากลองพิจารณาสถานการณ์ที่ผู้โจมตีพยายามสร้าง chain ปลอมให้เร็วกว่า chain จริง แม้ว่าจะทำได้สำเร็จ แต่มันก็ไม่สามารถทำให้ระบบเปิดรับการเปลี่ยนแปลงตามอำเภอใจได้อยู่ดี เช่น การสร้างมูลค่าจากอากาศธาตุ หรือการรับเงินที่ไม่เคยเป็นของผู้โจมตีมาก่อน Node ต่าง ๆ จะไม่ยอมรับธุรกรรมที่ไม่ถูกต้องเป็นการชำระเงิน และ Node ที่สุจริตก็จะไม่ยอมรับบล็อกที่มีธุรกรรมเหล่านั้นอย่างแน่นอน ผู้โจมตีทำได้เพียงพยายามเปลี่ยนแปลงธุรกรรมของตนเอง เพื่อนำเงินที่ใช้ไปแล้วกลับคืนมาเท่านั้น</p>
<p>การแข่งขันระหว่าง chain สุจริตกับ chain ของผู้โจมตี สามารถอธิบายได้ด้วยแบบจำลองการเดินสุ่มทวินาม (Binomial Random Walk) โดยเหตุการณ์ที่สำเร็จ หมายถึง chain ที่สุจริตถูกขยายออกไปอีกหนึ่งบล็อก เพิ่มความยาวนำหน้าไป +1 และเหตุการณ์ที่ล้มเหลว หมายถึง chain ของผู้โจมตีถูกขยายออกไปหนึ่งบล็อก ลดช่องว่างลง -1</p>
<p>ความน่าจะเป็นที่ผู้โจมตีจะไล่ตามทันจากช่องว่างที่กำหนด สามารถเปรียบเทียบด้วย Gambler's Ruin problem โดยสมมติว่านักพนันที่มีเครดิตไม่จำกัด เริ่มต้นด้วยการขาดทุน และเล่นพนันไปเรื่อย ๆ เพื่อให้ถึงจุดคุ้มทุน เราสามารถคำนวณความน่าจะเป็นที่เขาจะกลับมาถึงจุดคุ้มทุนได้ หรือความน่าจะเป็นที่ผู้โจมตีจะไล่ทัน chain ที่สุจริตได้ ดังนี้ [8]:</p>
<p>p = ความน่าจะเป็นที่ Node ที่สุจริตจะพบบล็อกถัดไป<br>q = ความน่าจะเป็นที่ผู้โจมตีจะพบบล็อกถัดไป<br>qz = ความน่าจะเป็นที่ผู้โจมตีจะไล่ทัน จากที่ตามหลังอยู่ z บล็อก</p>
<p><a href="https://i.imgur.com/vePe255.png" class="vbx-media" target="_blank"><img class="venobox" src="https://i.imgur.com/vePe255.png"></a></p>
<p>จากสมมติฐานที่ว่า p &gt; q ความน่าจะเป็นจะลดลงแบบเอกซ์โพเนนเชียล เมื่อจำนวนบล็อกที่ผู้โจมตีต้องไล่ตามทันเพิ่มขึ้น หากเขาไม่สามารถพุ่งขึ้นนำได้อย่างรวดเร็วตั้งแต่แรก โอกาสของเขาก็จะลดลงจนน้อยมาก ๆ เมื่อเขาตามหลังมากขึ้นเรื่อย ๆ</p>
<p>ทีนี้ลองพิจารณาว่า ผู้รับธุรกรรมใหม่ต้องรอเป็นเวลานานเท่าใด จึงจะแน่ใจได้ว่าผู้ส่งไม่สามารถเปลี่ยนแปลงธุรกรรมได้แล้ว เราสมมติว่าผู้ส่งเป็นผู้โจมตี ที่ต้องการให้ผู้รับเชื่อว่าเขาได้รับเงินไปแล้ว จากนั้นจึงเปลี่ยนให้เงินกลับเข้าหาตัวเองหลังจากเวลาผ่านไประยะหนึ่ง ผู้รับจะได้รับแจ้งเมื่อเกิดเหตุการณ์นี้ขึ้น แต่ผู้ส่งหวังว่ามันจะสายเกินไปแล้ว</p>
<p>ผู้รับจะสร้างคู่กุญแจใหม่ และให้กุญแจสาธารณะแก่ผู้ส่งไม่นานก่อนที่จะลงนาม ซึ่งจะป้องกันไม่ให้ผู้ส่งเตรียมบล็อกเชนปลอมไว้ล่วงหน้า โดยการทำงานอย่างต่อเนื่องจนกว่าเขาจะมีโอกาสได้บล็อกที่ยาวพอ จากนั้นจึงดำเนินธุรกรรมในทันที เมื่อส่งธุรกรรมแล้ว ผู้ส่งที่ไม่สุจริตจะเริ่มทำงานอย่างลับ ๆ บนบล็อกเชนคู่ขนาน ที่มีธุรกรรมในเวอร์ชันของเขาเองอยู่</p>
<p>ผู้รับจะรอจนกว่าธุรกรรมจะถูกเพิ่มลงในบล็อก และมีบล็อกที่ถูกเชื่อมต่อตามหลังมาอีก z บล็อก เขาไม่ทราบจำนวนความคืบหน้าที่แน่นอนที่ผู้โจมตีได้ทำไปแล้ว แต่สมมติว่าบล็อกที่สุจริตใช้เวลาเฉลี่ยต่อบล็อกตามที่คาดไว้ ความคืบหน้าที่อาจเกิดขึ้นได้ของผู้โจมตีจะเป็นการแจกแจงแบบปัวซง (Poisson distribution) ซึ่งมีค่าคาดหวังดังนี้:</p>
<p><a href="https://i.imgur.com/mYsb48i.png" class="vbx-media" target="_blank"><img class="venobox" src="https://i.imgur.com/mYsb48i.png"></a></p>
<p>เพื่อให้ได้ความน่าจะเป็นที่ผู้โจมตียังคงสามารถไล่ทันได้ เราจะคูณความหนาแน่นของปัวซง สำหรับความคืบหน้าแต่ละระดับที่เขาสามารถทำได้ ด้วยความน่าจะเป็นที่เขาสามารถไล่ทันจากจุดนั้น:</p>
<p><a href="https://i.imgur.com/jQGkQ8r.png" class="vbx-media" target="_blank"><img class="venobox" src="https://i.imgur.com/jQGkQ8r.png"></a></p>
<p>จัดเรียงใหม่เพื่อหลีกเลี่ยง infinite tail ของการแจกแจง</p>
<p><a href="https://i.imgur.com/OOO6Gm9.png" class="vbx-media" target="_blank"><img class="venobox" src="https://i.imgur.com/OOO6Gm9.png"></a></p>
<p>แปลงมันให้เป็น C code</p>
<p>#include &lt;math.h&gt;<br>double AttackerSuccessProbability(double q, int z)<br>{<br>     double p = 1.0 - q;<br>     double lambda = z * (q / p);<br>     double sum = 1.0;<br>     int i, k;<br>         for (k = 0; k &lt;= z; k++)<br>         {<br>             double poisson = exp(-lambda);<br>             for (i = 1; i &lt;= k; i++)<br>                 poisson *= lambda / i;<br>                 sum -= poisson * (1 - pow(q / p, z - k));<br>         }<br> return sum;<br>}</p>
<p>เมื่อรันผลลัพธ์บางส่วน เราจะเห็นว่าความน่าจะเป็นลดลงแบบเอกซ์โพเนนเชียลเมื่อ z เพิ่มขึ้น</p>
<p>q=0.1<br>z=0 P=1.0000000<br>z=1 P=0.2045873<br>z=2 P=0.0509779<br>z=3 P=0.0131722<br>z=4 P=0.0034552<br>z=5 P=0.0009137<br>z=6 P=0.0002428<br>z=7 P=0.0000647<br>z=8 P=0.0000173<br>z=9 P=0.0000046<br>z=10 P=0.0000012<br>q=0.3<br>z=0 P=1.0000000<br>z=5 P=0.1773523<br>z=10 P=0.0416605<br>z=15 P=0.0101008<br>z=20 P=0.0024804<br>z=25 P=0.0006132<br>z=30 P=0.0001522<br>z=35 P=0.0000379<br>z=40 P=0.0000095<br>z=45 P=0.0000024<br>z=50 P=0.0000006</p>
<p>การแก้หาค่า P ที่น้อยกว่า 0.1%...</p>
<p>P &lt; 0.001<br>q=0.10 z=5<br>q=0.15 z=8<br>q=0.20 z=11<br>q=0.25 z=15<br>q=0.30 z=24<br>q=0.35 z=41<br>q=0.40 z=89<br>q=0.45 z=340</p>
<p>12.สรุป(Conclusion)</p>
<p>เราได้นำเสนอระบบธุรกรรมอิเล็กทรอนิกส์ที่ไม่ต้องพึ่งพาความไว้วางใจ เริ่มต้นจากกรอบแนวคิดของเหรียญที่สร้างจากลายเซ็นดิจิทัล ซึ่งช่วยควบคุมความเป็นเจ้าของได้อย่างดีแต่ก็ยังไม่สมบูรณ์ หากปราศจากวิธีการป้องกันการใช้จ่ายซ้ำซ้อน เพื่อแก้ปัญหานี้ เราจึงเสนอเครือข่ายแบบเพียร์ทูเพียร์ที่ใช้ proof-of-work ในการบันทึกประวัติธุรกรรมสาธารณะ ซึ่งจะกลายเป็นเรื่องยากอย่างมากสำหรับผู้โจมตีที่จะเปลี่ยนแปลง หาก node ที่ซื่อสัตย์ควบคุมพลังประมวลผล CPU ส่วนใหญ่ เครือข่ายนี้มีความแข็งแกร่งในความเรียบง่ายที่ไม่มีโครงสร้างใด ๆ ที่ซับซ้อน node ต่าง ๆ ทำงานพร้อมกันโดยประสานงานกันเพียงเล็กน้อย ไม่จำเป็นต้องระบุตัวตน เนื่องจากข้อความไม่ได้ถูกส่งไปยังสถานที่ใดสถานที่หนึ่งโดยเฉพาะ และเพียงแค่ต้องส่งมอบให้ถึงมือผู้รับอย่างดีที่สุด  node สามารถออกจากและเข้าร่วมเครือข่ายได้ตามต้องการ โดยยอมรับ chain ที่มี proof-of-work มากที่สุดเป็นสิ่งที่เกิดขึ้นในขณะที่ไม่ได้เชื่อมต่อ พวกเขาโหวตด้วยพลังประมวลผล CPU แสดงการยอมรับบล็อกที่ถูกต้องโดยการทำงานเพื่อขยายบล็อก และปฏิเสธบล็อกที่ไม่ถูกต้องโดยการปฏิเสธที่จะทำงานกับบล็อกเหล่านั้น กฎและแรงจูงใจใด ๆ ที่จำเป็นสามารถบังคับใช้ได้ด้วยกลไกฉันทามตินี้</p>
<h2>ไปอ่านต่อกันเองเด้ออ</h2>
<p>[1] W. Dai, "b-money," <np-embed url="http://www.weidai.com/bmoney.txt"><a href="http://www.weidai.com/bmoney.txt">http://www.weidai.com/bmoney.txt</a></np-embed>, 1998.<br>[2] H. Massias, X.S. Avila, and J.-J. Quisquater, "Design of a secure timestamping service with minimal<br>trust requirements," In 20th Symposium on Information Theory in the Benelux, May 1999.<br>[3] S. Haber, W.S. Stornetta, "How to time-stamp a digital document," In Journal of Cryptology, vol 3, no<br>2, pages 99-111, 1991.<br>[4] D. Bayer, S. Haber, W.S. Stornetta, "Improving the efficiency and reliability of digital time-stamping,"<br>In Sequences II: Methods in Communication, Security and Computer Science, pages 329-334, 1993.<br>[5] S. Haber, W.S. Stornetta, "Secure names for bit-strings," In Proceedings of the 4th ACM Conference<br>on Computer and Communications Security, pages 28-35, April 1997.<br>[6] A. Back, "Hashcash - a denial of service counter-measure,"<br><np-embed url="http://www.hashcash.org/papers/hashcash.pdf"><a href="http://www.hashcash.org/papers/hashcash.pdf">http://www.hashcash.org/papers/hashcash.pdf</a></np-embed>, 2002.<br>[7] R.C. Merkle, "Protocols for public key cryptosystems," In Proc. 1980 Symposium on Security and<br>Privacy, IEEE Computer Society, pages 122-133, April 1980.<br>[8] W. Feller, "An introduction to probability theory and its applications," 1957.</p>
]]></itunes:summary>
      <itunes:image href="https://yakihonne.s3.ap-east-1.amazonaws.com/79008e781adec767cc8e239b533edcb19ea2e260f9281a9125e93425dfac9395/files/1723180709624-YAKIHONNES3.png"/>
      </item>
      
      </channel>
      </rss>
    