Segregated-Witness

比特幣 - P2PKH 和 P2SH 地址生成之間的技術區別?

  • May 16, 2018

我確信以 ‘1’ 和 ‘3’ 開頭的地址生成之間的唯一區別只是將添加到摘要中的前綴從 0x00 更改為 0x05 在成熟md160 部分之後。

雖然我得到的地址與來自比特幣核心錢包的地址不匹配,但在導入相同的私鑰時,以及來自<https://segwitaddress.org/>的地址。前綴 04 是保持不變還是也發生了變化?我缺少一些東西。能否請你幫忙?謝謝你。

[編輯]

這是我目前的方法,但仍然不起作用。我肯定誤解了一些東西..

def getPublicAddress(self, digest):

   oSk = ecdsa.SigningKey.from_string(digest, curve=ecdsa.SECP256k1)                    
   oVk = oSk.get_verifying_key()

   hexlify = codecs.getencoder('hex')             
   self.pubkey = str(hexlify(b'\04' + oVk.to_string())[0].decode('utf-8'))

   ripemd160 = hashlib.new('ripemd160')
   keyhash = hashlib.sha256(codecs.decode(self.pubkey, "hex")).digest()
   ripemd160.update(keyhash)


   redeem_script = hashlib.new('ripemd160')
   redeem_script.update(b'\x00\x14' + ripemd160.digest())

   prefix = b'\x05' 
   m = prefix + redeem_script.digest()
   checksum = hashlib.sha256(hashlib.sha256(m).digest()).digest()[:4]        

   return base58.b58encode(m + checksum)

P2PKH、P2SH 和 Segwit 都是不同的地址類型。Segwit 和 P2SH 地址不一樣。

P2PKH 和 P2SH 地址以類似的方式生成。P2PKH 獲取公鑰的 hash160(公鑰的 SHA256 的 RIPMED160),將版本字節附加0x00到 hash160,Base58 Check 對其進行編碼。

P2SH 地址是腳本的 hash160 的 Base58 Check 編碼(稱為redeemScript)。它使用版本字節0x05代替。其餘編碼相同,只是Base58 Check編碼。

對於隔離見證地址,有多種類型。有遵循 Bech32 標準的本地隔離見證地址。還有 P2SH 包裝的隔離見證地址。

對於包裹在 P2SH 地址中的 P2WPKH(付費見證公鑰雜湊),redeemScript 是0x0014 &lt;hash 160 of the pubkey&gt;. 該redeemScript 以典型的P2SH 方式進行散列和編碼。

對於包裹在 P2SH 地址中的 P2WSH(支付見證腳本雜湊),首先使用 SHA256 對見證腳本(redeemScript,但用於隔離見證地址)進行雜湊處理。那麼 P2SH 的兌換腳本就是0x0020 &lt;SHA256 of witnessScript&gt;. 這個redeemScript 的hash160 然後以典型的P2SH 方式編碼。


至於您的程式碼,您將附加0x04到您的公鑰,這根本不正確。不是地址編碼的0x04一部分,它是公鑰編碼本身的一部分。您的公鑰生成器應該已經為您執行此操作。請注意,如果公鑰被壓縮,則前綴字節將為0x020x03(取決於公鑰的 Y 值),而不是0x04未壓縮的公鑰。


[技術差異 - 範例解決方案]

`

   def hash160(self, v):
       r = hashlib.new('ripemd160')
       r.update(hashlib.sha256(v).digest())
       return r


   def doublehash256(self, v):
       return hashlib.sha256(hashlib.sha256(v).digest())


   def ecdsaSECP256k1(self, digest):
       # SECP256k1 - Bitcoin elliptic curve 
       sk = ecdsa.SigningKey.from_string(digest, curve=ecdsa.SECP256k1)                    
       return sk.get_verifying_key()

  def publicaddress1(self):

       prefix_a = b'\x04'
       prefix_b = b'\x00'

       digest = self.privkeyhex.digest()

       p = prefix_a + self.ecdsaSECP256k1(digest).to_string() # 1 + 32 bytes + 32 bytes
       self.pubkey = str(binascii.hexlify(p).decode('utf-8'))

       hash160 = self.hash160(p)

       m = prefix_b + hash160.digest()
       checksum = self.doublehash256(m).digest()[:4]        

       self.pubaddr1 = base58.b58encode(m + checksum)                  


   def publicaddress3(self):

       prefix_even = b'\x02'
       prefix_odd = b'\x03'
       prefix_a = prefix_odd
       prefix_b = b'\x05'
       prefix_redeem = b'\x00\x14'


       digest = self.privkeyhex.digest()

       ecdsa_digest = self.ecdsaSECP256k1(digest).to_string()

       x_coord = ecdsa_digest[:int(len(ecdsa_digest)/2)]
       y_coord = ecdsa_digest[int(len(ecdsa_digest)/2):]            

       if (int(binascii.hexlify(y_coord),16) % 2 == 0): prefix_a = prefix_even

       p = prefix_a + x_coord

       self.pubkeycompressed = str(binascii.hexlify(p).decode('utf-8'))


       redeem_script = self.hash160(prefix_redeem + self.hash160(p).digest()).digest() # 20 bytes

       m = prefix_b + redeem_script
       checksum = self.doublehash256(m).digest()[:4]        

       self.pubaddr3 = base58.b58encode(m + checksum)`

引用自:https://bitcoin.stackexchange.com/questions/75047