Ich war überzeugt, dass der einzige Unterschied zwischen der Generierung von Adressen, die mit '1' und '3' beginnen, einfach darin bestand, das dem Digest hinzugefügte Präfix von 0x00 auf 0x05 nach dem Teil von ricemd160 zu ändern.
Obwohl die Adressen, die ich bekomme, nicht mit den Adressen aus der Bitcoin Core-Brieftasche übereinstimmen, wenn derselbe private Schlüssel importiert wird, und auch von https://segwitaddress.org/ . Bleibt das Präfix 04 gleich oder ändert es sich auch? Da fehlt mir etwas. Kannst du bitte helfen? Danke dir.
[BEARBEITEN]
Dies ist die Methode, die ich im Moment habe und immer noch nicht funktioniert. Irgendwas interpretiere ich sicher falsch..
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 und Segwit sind alle unterschiedliche Adresstypen. Segwit- und P2SH-Adressen sind nicht identisch.
P2PKH- und P2SH-Adressen werden auf ähnliche Weise generiert. P2PKH nimmt den Hash160 eines öffentlichen Schlüssels (RIPMED160 des SHA256 des öffentlichen Schlüssels), hängt das Versionsbyte 0x00
an den Hash160 an und Base58 Check codiert es.
P2SH-Adressen sind die Base58-Check-Kodierung des Hash160 eines Skripts (bekannt als RedeemScript). 0x05
Es verwendet stattdessen ein Versionsbyte von . Der Rest der Codierung ist die gleiche, nur die Base58-Check-Codierung.
Für Segwit-Adressen gibt es mehrere Typen. Es gibt native Segwit-Adressen, die dem Bech32-Standard folgen. Es gibt auch P2SH-umschlossene Segwit-Adressen.
Für einen P2WPKH (Pay-to-Witness-Pubkey-Hash), der in eine P2SH-Adresse verpackt ist, lautet das Einlöseskript 0x0014 <hash 160 of the pubkey>
. Dieses RedeemScript wird auf die typische P2SH-Weise gehasht und codiert.
Für einen P2WSH (Pay-to-Witness-Skript-Hash), der in eine P2SH-Adresse verpackt ist, wird das WitnessScript (RedeemScript, außer für Segwit-Adressen) zuerst mit SHA256 gehasht. Dann ist das P2SH-Einlöseskript 0x0020 <SHA256 of witnessScript>
. Der Hash160 dieses RedeemScripts wird dann auf die typische P2SH-Weise kodiert.
Was Ihren Code betrifft, hängen Sie 0x04
an Ihren öffentlichen Schlüssel an, der einfach falsch ist. Das 0x04
ist nicht Teil der Adresscodierung, sondern Teil der Codierung des öffentlichen Schlüssels selbst. Ihr Public-Key-Generator sollte dies bereits für Sie tun. Beachten Sie, dass, wenn der öffentliche Schlüssel komprimiert ist, das Präfix-Byte entweder 0x02
oder 0x03
(abhängig vom Y-Wert des öffentlichen Schlüssels) ist, anstatt 0x04
dass es für unkomprimierte öffentliche Schlüssel gilt.
[Technischer Unterschied - Beispiellösung]
`
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)`
Segwit in P2SH:
redeem_script = hash160(b'\x00\x14' + hash160(public_key))
0x00 -> Witness-Version, 0x14 -> 20 (oder 32) Bytes Push-Opcode
prefix = b'\x05'
-> P2SH Hauptnetz
checksum = double_sha256(prefix + redeem_script)[:4]
address = base58(prefix + redeem_script + checksum)
fortesp
assert len(string) == curve.baselen, (len(string), curve.baselen) AssertionError: (38, 32)
Er erwartet eine Größe von 32 Byte. Soll ich einfach den Digest des privaten Schlüssels wie beim klassischen P2PKH eingeben? Ich werde in der Zwischenzeit in den Y-Wert-Teil springen. Vielen Dank.Andreas Chow
fortesp