切換語言為:簡體

一文詳解比特幣的Native SegWit(P2WPKH)地址型別

  • 爱糖宝
  • 2024-10-17
  • 2048
  • 0
  • 0

基本定義:

比特幣中的P2WPKH地址(Pay-to-Witness-Public-Key-Hash)是Segregated Witness(隔離見證,簡稱SegWit)的一種地址型別。生成比特幣的 Native SegWit 地址(也稱為 bech32 地址),SegWit是對比特幣協議的一項更新,旨在改善交易吞吐量、降低交易費用並提高安全性和靈活性。P2WPKH地址通常以“bc1”開頭,且直接嵌入見證資料,不再佔用區塊的常規部分,從而減小交易大小和費用。

地址生成步驟

Native SegWit (P2WPKH) 是比特幣的一種地址型別,它支援隔離見證(Segregated Witness),最佳化了交易簽名和儲存效率。生成 Native SegWit 地址的過程可以概括為以下步驟:

1. 生成金鑰對

首先,你需要生成一個橢圓曲線(Elliptic Curve)金鑰對,這是基於 secp256k1 演算法的。這個過程包括生成一個私鑰和一個對應的公鑰。(也可以透過公鑰直接生成地址,這種方式可以驗證函式是否正確)

  • 私鑰:從一個隨機數生成 32 位元組長度的數值。

  • 公鑰:使用 secp256k1 演算法從私鑰推匯出壓縮公鑰(33 位元組,字首為 0x020x03 )。

2. 生成公鑰雜湊(PubKeyHash)

使用 SHA256 和 RIPEMD160 雜湊演算法生成公鑰的雜湊值。

  • 先對壓縮公鑰進行 SHA256 雜湊。

  • 再對 SHA256 的結果進行 RIPEMD160 雜湊,得到 20 位元組的公鑰雜湊(PubKeyHash)。

3. 建立Witness Program

Native SegWit 地址的 Witness Program 由版本號和公鑰雜湊組成:

  • 版本號是 0(表示 P2WPKH)。

  • 公鑰雜湊(20 位元組)。

所以 Witness Program 是 0x00 後跟 20 位元組的公鑰雜湊。

4. Bech32 編碼

使用 Bech32 編碼將 Witness Program 轉換為人類可讀的比特幣地址格式。Bech32 編碼包括兩部分:

  • 地址字首:對於比特幣主網是 bc,測試網是 tb

  • Witness Program:轉換為 Base32 格式並進行 Bech32 校驗和編碼。

5. 最終的 Native SegWit 地址

經過 Bech32 編碼後的字串就是 Native SegWit 地址,它通常以 bc1 開頭(主網)或 tb1 開頭(測試網)。

程式碼示例:

ts 版本:

import { createHash } from 'crypto';
import { bech32 } from 'bech32';

// 計算 SHA256 + RIPEMD160
function hash160(data: Buffer): Buffer {
  // Step 1: SHA-256
  const sha256Hash = createHash('sha256').update(data).digest();

  // Step 2: RIPEMD-160
  const ripemd160Hash = createHash('ripemd160').update(sha256Hash).digest();

  return ripemd160Hash;
}

export function generateNativeSegWitAddress(publicKeyHex: string): string {
  // Step 1: 解碼 16 進位制公鑰
  const pubKeyBytes = Buffer.from(publicKeyHex, 'hex');

  // Step 2: 計算公鑰雜湊
  const pubKeyHash = hash160(pubKeyBytes);

  // Step 3: Bech32 編碼
  const witnessVersion = 0x00; // P2WPKH 的版本號為 0

  // 將 witness version 轉換為 Bech32 words
  const words = [witnessVersion, ...bech32.toWords(pubKeyHash)];

  // Bech32 編碼
  const address = bech32.encode('bc', words);

  // 返回結果
  return address;
}

go 版本:

package utils

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"github.com/btcsuite/btcutil/bech32"
	"golang.org/x/crypto/ripemd160"
)

// Hash160 計算 SHA256 + RIPEMD160
func hash160(data []byte) []byte {
	sha256Hash := sha256.Sum256(data)
	ripemd160Hasher := ripemd160.New()
	ripemd160Hasher.Write(sha256Hash[:])
	return ripemd160Hasher.Sum(nil)
}

func GenerateNativeSegWitAddress(publicKeyHex string) (string, error) {
	// Step 1: 解碼 16 進位制公鑰
	pubKeyBytes, err := hex.DecodeString(publicKeyHex)
	if err != nil {
		return "", fmt.Errorf("failed to decode public key: %v", err)
	}

	// Step 2: 計算公鑰雜湊
	pubKeyHash := hash160(pubKeyBytes)

	// Step 3: 準備 SegWit 地址編碼資料
	witnessVersion := byte(0x00) // P2WPKH 的版本號為 0

	// Step 4: 使用 bech32 庫進行編碼
	data, err := bech32.ConvertBits(pubKeyHash, 8, 5, true) // 將 8-bit 轉換為 5-bit
	if err != nil {
		return "", fmt.Errorf("failed to convert bits: %v", err)
	}

	// 將版本號和轉換後的資料合併
	combinedData := append([]byte{witnessVersion}, data...)

	// Bech32 編碼
	address, err := bech32.Encode("bc", combinedData)
	if err != nil {
		return "", fmt.Errorf("failed to encode Bech32 address: %v", err)
	}

	// 返回 Bech32 編碼的地址
	return address, nil
}

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.