Я был убежден, что единственная разница между генерацией адресов, начинающихся с «1» и «3», заключалась в простом изменении префикса, добавляемого в дайджест, с 0x00 на 0x05 после частиripemd160.
Хотя адреса, которые я получаю, не совпадают с адресами из кошелька Bitcoin Core при импорте того же приватного ключа, а также из 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 берет хэш160 открытого ключа (RIPMED160 из SHA256 открытого ключа), добавляет байт версии 0x00
к хэшу160, и проверка Base58 кодирует его.
Адреса P2SH представляют собой кодировку Base58 Check для хэша160 скрипта (известного как redeemScript). 0x05
Вместо этого используется байт версии . Остальная кодировка такая же, только кодировка Base58 Check.
Для адресов Segwit существует несколько типов. Существуют собственные адреса segwit, соответствующие стандарту Bech32. Существуют также адреса segwit, обернутые P2SH.
Для P2WPKH (хэш публичного ключа с оплатой за свидетеля), заключенного в адрес P2SH, redeemScript имеет вид 0x0014 <hash 160 of the pubkey>
. Этот redeemScript хешируется и кодируется обычным способом P2SH.
Для P2WSH (хэш сценария с оплатой за свидетель), обернутый в адрес P2SH, свидетельский скрипт (скрипт redeemScript, но для адресов segwit) сначала хешируется с помощью SHA256. Тогда сценарий выкупа P2SH — это 0x0020 <SHA256 of witnessScript>
. Хэш160 этого redeemScript затем кодируется обычным способом P2SH.
Что касается вашего кода, вы добавляете 0x04
свой открытый ключ, что просто неверно. Это 0x04
не часть кодировки адреса, это часть самой кодировки открытого ключа. Ваш генератор открытых ключей уже должен делать это за вас. Обратите внимание, что если открытый ключ сжат, байт префикса будет либо 0x02
( 0x03
зависит от значения 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)`
Сегвит внутри P2SH:
redeem_script = hash160(b'\x00\x14' + hash160(public_key))
0x00 -> версия-свидетель, 0x14 -> 20 (или 32) байт кода операции push
prefix = b'\x05'
-> Основная сеть P2SH
checksum = double_sha256(prefix + redeem_script)[:4]
address = base58(prefix + redeem_script + checksum)
фортесп
assert len(string) == curve.baselen, (len(string), curve.baselen) AssertionError: (38, 32)
он ожидает размер 32 байта. Должен ли я просто ввести дайджест закрытого ключа, как классический P2PKH? Тем временем я перейду к части значения Y. Большое спасибо.Эндрю Чоу
фортесп