基本概念:比特币的P2SH地址类型(Pay-to-Script-Hash,支付到脚本哈希)是一种常见的比特币地址类型,用于支持更复杂的交易条件。P2SH地址通过使用脚本哈希来实现不同的条件支付方式,最常见的应用是多签名地址和时间锁等。
比特币的P2SH地址类型(Pay-to-Script-Hash,支付到脚本哈希)是一种常见的比特币地址类型,用于支持更复杂的交易条件。P2SH地址通过使用脚本哈希来实现不同的条件支付方式,最常见的应用是多签名地址和时间锁等。
3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy
。前缀:地址以3开头。
用途:这种地址类型主要是为了兼容目的,将隔离见证(SegWit)功能引入到现有的支持P2SH的基础设施中。这允许使用旧版钱包和服务也能发送比特币到隔离见证地址,并处理这些用户的支付。
结构:具体来说,这是一种P2SH地址,其脚本哈希是一个指向隔离见证(SegWit)输出的脚本,即P2WPKH。这意味着该地址在交易上表现为P2SH,但其解锁脚本是一个内嵌的P2WPKH。
验证过程:
外层(P2SH层) :在所有者花费比特币时,需要提供指定的解锁脚本哈希对应的实际脚本,它会解锁一个嵌套的P2WPKH。
优势:
兼容性好:使得SegWit功能可以被不支持完全SegWit的旧版钱包和服务所使用,因为这些钱包和服务仍然可以识别和处理P2SH类型的地址。
普通P2SH地址:广泛用于复杂的交易脚本,如多重签名、条件脚本等,其解锁脚本完全由用户自定义。P2SH-P2WPKH地址:为了向后兼容而设计的隔离见证地址,方便用旧版钱包和服务进行交易。同时利用SegWit的优势(如较低的交易费用和改进的结构),但表现为普通P2SH地址。P2SH-P2WPKH可以被看作是向SegWit过渡的一种桥梁,在新旧基础设施之间提供了必要的兼容性与过渡支持。
import { createHash } from 'crypto';
import bs58 from 'bs58';
export function generateNestedSegWitAddress(pubKeyHex: string): string {
// 将公钥的十六进制字符串转成字节数组
const pubKeyBytes = Buffer.from(pubKeyHex, 'hex');
// 对公钥进行 SHA-256 哈希运算
const sha256Hasher = createHash('sha256');
sha256Hasher.update(pubKeyBytes);
const pubKeySHA256 = sha256Hasher.digest();
// 对 SHA-256 哈希值进行 RIPEMD-160 哈希运算
const ripemd160Hasher = createHash('ripemd160');
ripemd160Hasher.update(pubKeySHA256);
const pubKeyHash = ripemd160Hasher.digest();
// 构建 P2WPKH 的见证程序(Witness Program)
// 其中 0x00 表示版本号,0x14 表示长度(20 字节)
const witnessProgram = Buffer.concat([Buffer.from([0x00, 0x14]), pubKeyHash]);
// 对见证程序进行 SHA-256 哈希运算
const witnessProgramSHA256Hasher = createHash('sha256');
witnessProgramSHA256Hasher.update(witnessProgram);
const witnessProgramSHA256 = witnessProgramSHA256Hasher.digest();
// 对 SHA-256 哈希值进行 RIPEMD-160 哈希运算
const witnessProgramRipemd160Hasher = createHash('ripemd160');
witnessProgramRipemd160Hasher.update(witnessProgramSHA256);
const witnessProgramHash = witnessProgramRipemd160Hasher.digest();
// 添加 P2SH 前缀
const version = Buffer.from([0x05]);
const versionedHash = Buffer.concat([version, witnessProgramHash]);
// 计算校验和
const firstSHA256 = createHash('sha256').update(versionedHash).digest();
const checksum = createHash('sha256')
.update(firstSHA256)
.digest()
.slice(0, 4);
// 拼接版本前缀、见证程序哈希和校验和
const fullHash = Buffer.concat([versionedHash, checksum]);
// 转换到 Base58
const address = bs58.encode(fullHash);
return address;
}
package utils
import (
"crypto/sha256"
"encoding/hex"
"github.com/btcsuite/btcutil/base58"
"golang.org/x/crypto/ripemd160"
)
func GenerateNestedSigwitddress(pubKeyHex string) (string, error) {
// 将公钥的十六进制字符串转成字节数组
pubKeyBytes, err := hex.DecodeString(pubKeyHex)
if err != nil {
return "", err
}
// 对公钥进行 SHA-256 哈希运算
hasherSHA256 := sha256.New()
hasherSHA256.Write(pubKeyBytes)
pubKeySHA256 := hasherSHA256.Sum(nil)
// 对 SHA-256 哈希值进行 RIPEMD-160 哈希运算
hasherRIPEMD160 := ripemd160.New()
hasherRIPEMD160.Write(pubKeySHA256)
pubKeyHash := hasherRIPEMD160.Sum(nil)
// 构建 P2WPKH 的见证程序(Witness Program)
// 其中 0x00 表示版本号,0x14 表示长度(20 字节)
witnessProgram := append([]byte{0x00, 0x14}, pubKeyHash...)
// 对见证程序进行 SHA-256 哈希运算
hasherSHA256.Reset()
hasherSHA256.Write(witnessProgram)
witnessProgramSHA256 := hasherSHA256.Sum(nil)
// 对 SHA-256 哈希值进行 RIPEMD-160 哈希运算
hasherRIPEMD160.Reset()
hasherRIPEMD160.Write(witnessProgramSHA256)
witnessProgramHash := hasherRIPEMD160.Sum(nil)
// 添加 P2SH 前缀
version := []byte{0x05}
versionedHash := append(version, witnessProgramHash...)
// 计算校验和
hasherDoubleSHA256 := sha256.New()
hasherDoubleSHA256.Write(versionedHash)
checksum := hasherDoubleSHA256.Sum(nil)
hasherDoubleSHA256.Reset()
hasherDoubleSHA256.Write(checksum)
checksum = hasherDoubleSHA256.Sum(nil)
finalChecksum := checksum[:4]
// 拼接版本前缀、赎回脚本哈希和校验和
fullHash := append(versionedHash, finalChecksum...)
// 转换到 Base58
address := base58.Encode(fullHash)
return address, nil
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!