Ergo Address Encoding
In [85]:
Copied!
# Necessary imports
# Credit: lgd#5847
# This is just an academic exercise to understand what's going on, you would use AppKit in practice.
# I created a jupyter notebook to show how you could create a P2S address if you had the ErgoTree.
# I used my GuapSwap proxy address as an example.
# Since the box on the explorer tells you the P2S address in base58 as well as the serialized ErgoTree encoded in base16,
# I tried to reproduce the P2S address using the ErgoTree.
# I came really close, only off by 4 bytes due to the checksum, since I don't know all the parameters Ergo uses in the blake2b256() hash function.
# If someone can figure out/find it somewhere, then it should end up producing the same result.
from hashlib import blake2b
from baseconv import base16, base58
# Necessary imports
# Credit: lgd#5847
# This is just an academic exercise to understand what's going on, you would use AppKit in practice.
# I created a jupyter notebook to show how you could create a P2S address if you had the ErgoTree.
# I used my GuapSwap proxy address as an example.
# Since the box on the explorer tells you the P2S address in base58 as well as the serialized ErgoTree encoded in base16,
# I tried to reproduce the P2S address using the ErgoTree.
# I came really close, only off by 4 bytes due to the checksum, since I don't know all the parameters Ergo uses in the blake2b256() hash function.
# If someone can figure out/find it somewhere, then it should end up producing the same result.
from hashlib import blake2b
from baseconv import base16, base58
In [125]:
Copied!
# ErgoTree encoded in base16
content_ergotree_base16 = '100f0500053205a09c0108cd0279aed8dea2b2a25316d5d49d13bf51c0b2c1dc696974bb4b0c07b5894e998e5605aa9105040004020580ade20404000ef301100a04000500058092f40105060402040408cd03c6543ac8e8059748b1c6209ee419dd49a19ffaf5712a2f34a9412016a3a1d96708cd035b736bebf0c5393f78329f6894af84d1864c7496cc65ddc250ef60cdd75df52008cd021b63e19ab452c84cdc6687242e8494957b1f11e3750c8c184a8425f8a8171d9b0580a8d6b907d805d601b2a5730000d602b0a47301d9010241639a8c720201c18c720202d6039d99720273027303d604b2a5730400d605b2a5730500d1968304019683020193c17201720393c27201d073069683020193c17204720393c27204d073079683020193c17205720393c27205d073089272027309040605b40a04000580ade2040100d804d601e4e30005d602b0a47300d9010241639a8c720201c18c720202d6039d9c730172027302d6047303959372017304d803d605e4e30105d606b2a5730500d607b2a5730600d196830301968303019272029a9a72037307720592c17206997202720593c2720674e4e3020e830104730883010872049683020192c17207720393c27207730993b1a5730a95937201730bd801d605b2a5730c00d19683020192c17205997202730d93c27205d07204d1730e'.upper()
content_ergotree_base16
# ErgoTree encoded in base16
content_ergotree_base16 = '100f0500053205a09c0108cd0279aed8dea2b2a25316d5d49d13bf51c0b2c1dc696974bb4b0c07b5894e998e5605aa9105040004020580ade20404000ef301100a04000500058092f40105060402040408cd03c6543ac8e8059748b1c6209ee419dd49a19ffaf5712a2f34a9412016a3a1d96708cd035b736bebf0c5393f78329f6894af84d1864c7496cc65ddc250ef60cdd75df52008cd021b63e19ab452c84cdc6687242e8494957b1f11e3750c8c184a8425f8a8171d9b0580a8d6b907d805d601b2a5730000d602b0a47301d9010241639a8c720201c18c720202d6039d99720273027303d604b2a5730400d605b2a5730500d1968304019683020193c17201720393c27201d073069683020193c17204720393c27204d073079683020193c17205720393c27205d073089272027309040605b40a04000580ade2040100d804d601e4e30005d602b0a47300d9010241639a8c720201c18c720202d6039d9c730172027302d6047303959372017304d803d605e4e30105d606b2a5730500d607b2a5730600d196830301968303019272029a9a72037307720592c17206997202720593c2720674e4e3020e830104730883010872049683020192c17207720393c27207730993b1a5730a95937201730bd801d605b2a5730c00d19683020192c17205997202730d93c27205d07204d1730e'.upper()
content_ergotree_base16
Out[125]:
'100F0500053205A09C0108CD0279AED8DEA2B2A25316D5D49D13BF51C0B2C1DC696974BB4B0C07B5894E998E5605AA9105040004020580ADE20404000EF301100A04000500058092F40105060402040408CD03C6543AC8E8059748B1C6209EE419DD49A19FFAF5712A2F34A9412016A3A1D96708CD035B736BEBF0C5393F78329F6894AF84D1864C7496CC65DDC250EF60CDD75DF52008CD021B63E19AB452C84CDC6687242E8494957B1F11E3750C8C184A8425F8A8171D9B0580A8D6B907D805D601B2A5730000D602B0A47301D9010241639A8C720201C18C720202D6039D99720273027303D604B2A5730400D605B2A5730500D1968304019683020193C17201720393C27201D073069683020193C17204720393C27204D073079683020193C17205720393C27205D073089272027309040605B40A04000580ADE2040100D804D601E4E30005D602B0A47300D9010241639A8C720201C18C720202D6039D9C730172027302D6047303959372017304D803D605E4E30105D606B2A5730500D607B2A5730600D196830301968303019272029A9A72037307720592C17206997202720593C2720674E4E3020E830104730883010872049683020192C17207720393C27207730993B1A5730A95937201730BD801D605B2A5730C00D19683020192C17205997202730D93C27205D07204D1730E'
In [126]:
Copied!
# P2S address of the above ErgoTree, in base58
p2s_address_base58 = '3Gax9E764DUmwJKhMrG69fuUHqaBp59WqnVfnU8sLx8kFEVg59sVvxY5LWyZ4rkBYS9MWSZxqRVC55YwEzvYycCCroq9jUYKew6LpQxJUQyu8TbXJUjCLPBCpji3E66vv7PBwb53eWFgf2NrtA98CR5ucZASJEQMfbm4nvUuBEipZVDA3r9HHnh1WnnQiuL5qEzQNHGUothszfq17JRX8Dby511iZD9VKpWSNu5fMcfFCtuEzSKZtUb1a4ndaF8TLyG87ZxMzvniBPFFtYLjVdGytbZteA95vZVMeRAy8wB2J9deLf1frADaNBeeKkbN7gZYoZeq57QGd5jzLY7Nsw4vRLTwASbeoPLTkkFHtRgZmWv2UsF5QgHGuy8osHPpUHcJEUkVSNMSSGbw3YbRkzA9SDLJXdmdZwGeFgRMWSAb5Pp3Xb6UtmxUKGowgHprcmNpct9UTwCSHhNP1jmE8sVSCAnjzLJpUkrrh2VFmcCM4jV3Zmx92H68NjVFrAmt7g71rnsXsNn9RmuN6iQYAGKDSZ8KGBPhJ2uY5e65MZiGV5HHDv6xHHrh3fK9JXCju3fRLynGuNZoBiKCCRDi4iSLcHDPgpc11SY39fv5R4j38KxeJxLDCyyPKRn9dA9wzJz6FL25Xd4xYEKCTVJCfDGn2a5XU4iCV8DojcACG9BBS5m4'
p2s_address_base58
# P2S address of the above ErgoTree, in base58
p2s_address_base58 = '3Gax9E764DUmwJKhMrG69fuUHqaBp59WqnVfnU8sLx8kFEVg59sVvxY5LWyZ4rkBYS9MWSZxqRVC55YwEzvYycCCroq9jUYKew6LpQxJUQyu8TbXJUjCLPBCpji3E66vv7PBwb53eWFgf2NrtA98CR5ucZASJEQMfbm4nvUuBEipZVDA3r9HHnh1WnnQiuL5qEzQNHGUothszfq17JRX8Dby511iZD9VKpWSNu5fMcfFCtuEzSKZtUb1a4ndaF8TLyG87ZxMzvniBPFFtYLjVdGytbZteA95vZVMeRAy8wB2J9deLf1frADaNBeeKkbN7gZYoZeq57QGd5jzLY7Nsw4vRLTwASbeoPLTkkFHtRgZmWv2UsF5QgHGuy8osHPpUHcJEUkVSNMSSGbw3YbRkzA9SDLJXdmdZwGeFgRMWSAb5Pp3Xb6UtmxUKGowgHprcmNpct9UTwCSHhNP1jmE8sVSCAnjzLJpUkrrh2VFmcCM4jV3Zmx92H68NjVFrAmt7g71rnsXsNn9RmuN6iQYAGKDSZ8KGBPhJ2uY5e65MZiGV5HHDv6xHHrh3fK9JXCju3fRLynGuNZoBiKCCRDi4iSLcHDPgpc11SY39fv5R4j38KxeJxLDCyyPKRn9dA9wzJz6FL25Xd4xYEKCTVJCfDGn2a5XU4iCV8DojcACG9BBS5m4'
p2s_address_base58
Out[126]:
'3Gax9E764DUmwJKhMrG69fuUHqaBp59WqnVfnU8sLx8kFEVg59sVvxY5LWyZ4rkBYS9MWSZxqRVC55YwEzvYycCCroq9jUYKew6LpQxJUQyu8TbXJUjCLPBCpji3E66vv7PBwb53eWFgf2NrtA98CR5ucZASJEQMfbm4nvUuBEipZVDA3r9HHnh1WnnQiuL5qEzQNHGUothszfq17JRX8Dby511iZD9VKpWSNu5fMcfFCtuEzSKZtUb1a4ndaF8TLyG87ZxMzvniBPFFtYLjVdGytbZteA95vZVMeRAy8wB2J9deLf1frADaNBeeKkbN7gZYoZeq57QGd5jzLY7Nsw4vRLTwASbeoPLTkkFHtRgZmWv2UsF5QgHGuy8osHPpUHcJEUkVSNMSSGbw3YbRkzA9SDLJXdmdZwGeFgRMWSAb5Pp3Xb6UtmxUKGowgHprcmNpct9UTwCSHhNP1jmE8sVSCAnjzLJpUkrrh2VFmcCM4jV3Zmx92H68NjVFrAmt7g71rnsXsNn9RmuN6iQYAGKDSZ8KGBPhJ2uY5e65MZiGV5HHDv6xHHrh3fK9JXCju3fRLynGuNZoBiKCCRDi4iSLcHDPgpc11SY39fv5R4j38KxeJxLDCyyPKRn9dA9wzJz6FL25Xd4xYEKCTVJCfDGn2a5XU4iCV8DojcACG9BBS5m4'
In [179]:
Copied!
# network type byte for mainnet in base16
networktype_mainnet_base16 = '00'
# network type byte for mainnet in base16
networktype_mainnet_base16 = '00'
In [180]:
Copied!
# address type byte for P2S in base16
addresstype_p2s_base16 = '03'
# address type byte for P2S in base16
addresstype_p2s_base16 = '03'
In [189]:
Copied!
# prefix byte in base16, 0x00 + 0x03
prefix_base16 = networktype_mainnet_base16 + addresstype_p2s_base16
prefix_base16
# prefix byte in base16, 0x00 + 0x03
prefix_base16 = networktype_mainnet_base16 + addresstype_p2s_base16
prefix_base16
Out[189]:
'03'
In [190]:
Copied!
# prefix prepended to content bytes
prefix_with_content_base16 = prefix_base16 + content_ergotree_base16
prefix_with_content_base16
# prefix prepended to content bytes
prefix_with_content_base16 = prefix_base16 + content_ergotree_base16
prefix_with_content_base16
Out[190]:
'03100F0500053205A09C0108CD0279AED8DEA2B2A25316D5D49D13BF51C0B2C1DC696974BB4B0C07B5894E998E5605AA9105040004020580ADE20404000EF301100A04000500058092F40105060402040408CD03C6543AC8E8059748B1C6209EE419DD49A19FFAF5712A2F34A9412016A3A1D96708CD035B736BEBF0C5393F78329F6894AF84D1864C7496CC65DDC250EF60CDD75DF52008CD021B63E19AB452C84CDC6687242E8494957B1F11E3750C8C184A8425F8A8171D9B0580A8D6B907D805D601B2A5730000D602B0A47301D9010241639A8C720201C18C720202D6039D99720273027303D604B2A5730400D605B2A5730500D1968304019683020193C17201720393C27201D073069683020193C17204720393C27204D073079683020193C17205720393C27205D073089272027309040605B40A04000580ADE2040100D804D601E4E30005D602B0A47300D9010241639A8C720201C18C720202D6039D9C730172027302D6047303959372017304D803D605E4E30105D606B2A5730500D607B2A5730600D196830301968303019272029A9A72037307720592C17206997202720593C2720674E4E3020E830104730883010872049683020192C17207720393C27207730993B1A5730A95937201730BD801D605B2A5730C00D19683020192C17205997202730D93C27205D07204D1730E'
In [203]:
Copied!
# blake2b256 hash => digest size is 32 bytes == 256 bits
blake2b256_base16 = blake2b(b'03100F0500053205A09C0108CD0279AED8DEA2B2A25316D5D49D13BF51C0B2C1DC696974BB4B0C07B5894E998E5605AA9105040004020580ADE20404000EF301100A04000500058092F40105060402040408CD03C6543AC8E8059748B1C6209EE419DD49A19FFAF5712A2F34A9412016A3A1D96708CD035B736BEBF0C5393F78329F6894AF84D1864C7496CC65DDC250EF60CDD75DF52008CD021B63E19AB452C84CDC6687242E8494957B1F11E3750C8C184A8425F8A8171D9B0580A8D6B907D805D601B2A5730000D602B0A47301D9010241639A8C720201C18C720202D6039D99720273027303D604B2A5730400D605B2A5730500D1968304019683020193C17201720393C27201D073069683020193C17204720393C27204D073079683020193C17205720393C27205D073089272027309040605B40A04000580ADE2040100D804D601E4E30005D602B0A47300D9010241639A8C720201C18C720202D6039D9C730172027302D6047303959372017304D803D605E4E30105D606B2A5730500D607B2A5730600D196830301968303019272029A9A72037307720592C17206997202720593C2720674E4E3020E830104730883010872049683020192C17207720393C27207730993B1A5730A95937201730BD801D605B2A5730C00D19683020192C17205997202730D93C27205D07204D1730E',
digest_size=32).hexdigest().upper()
blake2b256_base16
# blake2b256 hash => digest size is 32 bytes == 256 bits
blake2b256_base16 = blake2b(b'03100F0500053205A09C0108CD0279AED8DEA2B2A25316D5D49D13BF51C0B2C1DC696974BB4B0C07B5894E998E5605AA9105040004020580ADE20404000EF301100A04000500058092F40105060402040408CD03C6543AC8E8059748B1C6209EE419DD49A19FFAF5712A2F34A9412016A3A1D96708CD035B736BEBF0C5393F78329F6894AF84D1864C7496CC65DDC250EF60CDD75DF52008CD021B63E19AB452C84CDC6687242E8494957B1F11E3750C8C184A8425F8A8171D9B0580A8D6B907D805D601B2A5730000D602B0A47301D9010241639A8C720201C18C720202D6039D99720273027303D604B2A5730400D605B2A5730500D1968304019683020193C17201720393C27201D073069683020193C17204720393C27204D073079683020193C17205720393C27205D073089272027309040605B40A04000580ADE2040100D804D601E4E30005D602B0A47300D9010241639A8C720201C18C720202D6039D9C730172027302D6047303959372017304D803D605E4E30105D606B2A5730500D607B2A5730600D196830301968303019272029A9A72037307720592C17206997202720593C2720674E4E3020E830104730883010872049683020192C17207720393C27207730993B1A5730A95937201730BD801D605B2A5730C00D19683020192C17205997202730D93C27205D07204D1730E',
digest_size=32).hexdigest().upper()
blake2b256_base16
Out[203]:
'CC9663DF4AA48873E5EDA6E7BB68BF0531DAF2C4828D1E71F63F7F8322783853'
In [204]:
Copied!
# checksum is the first 4 most-significant bytes => the first 8 chars
checksum_base16 = blake2b256_base16[:8]
checksum_base16
# checksum is the first 4 most-significant bytes => the first 8 chars
checksum_base16 = blake2b256_base16[:8]
checksum_base16
Out[204]:
'CC9663DF'
In [205]:
Copied!
# address in base 16: prefix byte || content bytes || checksum bytes
address_base16 = prefix_base16 + content_ergotree_base16 + checksum_base16
address_base16
# address in base 16: prefix byte || content bytes || checksum bytes
address_base16 = prefix_base16 + content_ergotree_base16 + checksum_base16
address_base16
Out[205]:
'03100F0500053205A09C0108CD0279AED8DEA2B2A25316D5D49D13BF51C0B2C1DC696974BB4B0C07B5894E998E5605AA9105040004020580ADE20404000EF301100A04000500058092F40105060402040408CD03C6543AC8E8059748B1C6209EE419DD49A19FFAF5712A2F34A9412016A3A1D96708CD035B736BEBF0C5393F78329F6894AF84D1864C7496CC65DDC250EF60CDD75DF52008CD021B63E19AB452C84CDC6687242E8494957B1F11E3750C8C184A8425F8A8171D9B0580A8D6B907D805D601B2A5730000D602B0A47301D9010241639A8C720201C18C720202D6039D99720273027303D604B2A5730400D605B2A5730500D1968304019683020193C17201720393C27201D073069683020193C17204720393C27204D073079683020193C17205720393C27205D073089272027309040605B40A04000580ADE2040100D804D601E4E30005D602B0A47300D9010241639A8C720201C18C720202D6039D9C730172027302D6047303959372017304D803D605E4E30105D606B2A5730500D607B2A5730600D196830301968303019272029A9A72037307720592C17206997202720593C2720674E4E3020E830104730883010872049683020192C17207720393C27207730993B1A5730A95937201730BD801D605B2A5730C00D19683020192C17205997202730D93C27205D07204D1730ECC9663DF'
In [199]:
Copied!
# address in base 58
address_base58 = base58.encode(base16.decode(address_base16))
address_base58, p2s_address_base58
# address in base 58
address_base58 = base58.encode(base16.decode(address_base16))
address_base58, p2s_address_base58
Out[199]:
('3Gax9E764DUmwJKhMrG69fuUHqaBp59WqnVfnU8sLx8kFEVg59sVvxY5LWyZ4rkBYS9MWSZxqRVC55YwEzvYycCCroq9jUYKew6LpQxJUQyu8TbXJUjCLPBCpji3E66vv7PBwb53eWFgf2NrtA98CR5ucZASJEQMfbm4nvUuBEipZVDA3r9HHnh1WnnQiuL5qEzQNHGUothszfq17JRX8Dby511iZD9VKpWSNu5fMcfFCtuEzSKZtUb1a4ndaF8TLyG87ZxMzvniBPFFtYLjVdGytbZteA95vZVMeRAy8wB2J9deLf1frADaNBeeKkbN7gZYoZeq57QGd5jzLY7Nsw4vRLTwASbeoPLTkkFHtRgZmWv2UsF5QgHGuy8osHPpUHcJEUkVSNMSSGbw3YbRkzA9SDLJXdmdZwGeFgRMWSAb5Pp3Xb6UtmxUKGowgHprcmNpct9UTwCSHhNP1jmE8sVSCAnjzLJpUkrrh2VFmcCM4jV3Zmx92H68NjVFrAmt7g71rnsXsNn9RmuN6iQYAGKDSZ8KGBPhJ2uY5e65MZiGV5HHDv6xHHrh3fK9JXCju3fRLynGuNZoBiKCCRDi4iSLcHDPgpc11SY39fv5R4j38KxeJxLDCyyPKRn9dA9wzJz6FL25Xd4xYEKCTVJCfDGn2a5XU4iCV8DojcACG9Cfr1GJ', '3Gax9E764DUmwJKhMrG69fuUHqaBp59WqnVfnU8sLx8kFEVg59sVvxY5LWyZ4rkBYS9MWSZxqRVC55YwEzvYycCCroq9jUYKew6LpQxJUQyu8TbXJUjCLPBCpji3E66vv7PBwb53eWFgf2NrtA98CR5ucZASJEQMfbm4nvUuBEipZVDA3r9HHnh1WnnQiuL5qEzQNHGUothszfq17JRX8Dby511iZD9VKpWSNu5fMcfFCtuEzSKZtUb1a4ndaF8TLyG87ZxMzvniBPFFtYLjVdGytbZteA95vZVMeRAy8wB2J9deLf1frADaNBeeKkbN7gZYoZeq57QGd5jzLY7Nsw4vRLTwASbeoPLTkkFHtRgZmWv2UsF5QgHGuy8osHPpUHcJEUkVSNMSSGbw3YbRkzA9SDLJXdmdZwGeFgRMWSAb5Pp3Xb6UtmxUKGowgHprcmNpct9UTwCSHhNP1jmE8sVSCAnjzLJpUkrrh2VFmcCM4jV3Zmx92H68NjVFrAmt7g71rnsXsNn9RmuN6iQYAGKDSZ8KGBPhJ2uY5e65MZiGV5HHDv6xHHrh3fK9JXCju3fRLynGuNZoBiKCCRDi4iSLcHDPgpc11SY39fv5R4j38KxeJxLDCyyPKRn9dA9wzJz6FL25Xd4xYEKCTVJCfDGn2a5XU4iCV8DojcACG9BBS5m4')
In [202]:
Copied!
# decode p2s address into hex
p2s_address_base16 = base16.encode(base58.decode(p2s_address_base58))
p2s_address_base16
# decode p2s address into hex
p2s_address_base16 = base16.encode(base58.decode(p2s_address_base58))
p2s_address_base16
Out[202]:
'3100F0500053205A09C0108CD0279AED8DEA2B2A25316D5D49D13BF51C0B2C1DC696974BB4B0C07B5894E998E5605AA9105040004020580ADE20404000EF301100A04000500058092F40105060402040408CD03C6543AC8E8059748B1C6209EE419DD49A19FFAF5712A2F34A9412016A3A1D96708CD035B736BEBF0C5393F78329F6894AF84D1864C7496CC65DDC250EF60CDD75DF52008CD021B63E19AB452C84CDC6687242E8494957B1F11E3750C8C184A8425F8A8171D9B0580A8D6B907D805D601B2A5730000D602B0A47301D9010241639A8C720201C18C720202D6039D99720273027303D604B2A5730400D605B2A5730500D1968304019683020193C17201720393C27201D073069683020193C17204720393C27204D073079683020193C17205720393C27205D073089272027309040605B40A04000580ADE2040100D804D601E4E30005D602B0A47300D9010241639A8C720201C18C720202D6039D9C730172027302D6047303959372017304D803D605E4E30105D606B2A5730500D607B2A5730600D196830301968303019272029A9A72037307720592C17206997202720593C2720674E4E3020E830104730883010872049683020192C17207720393C27207730993B1A5730A95937201730BD801D605B2A5730C00D19683020192C17205997202730D93C27205D07204D1730E924D07D3'
In [209]:
Copied!
"""
Comments:
As we can see, the base16 P2S address is off by the last 4 bytes
when compared to the actual decoded proxy address. This is the checksum,
unfortunately some of the parameters of the hashing function are
not know to us, so we cannot compute it correctly. However,
the rest of the address is exactly the same.
"""
"""
Comments:
As we can see, the base16 P2S address is off by the last 4 bytes
when compared to the actual decoded proxy address. This is the checksum,
unfortunately some of the parameters of the hashing function are
not know to us, so we cannot compute it correctly. However,
the rest of the address is exactly the same.
"""