Manipulation d'adresses SS58

Je partage certains outils utiles pour manipuler des adresse SS58 :

  • le site https://ss58.org/ pour des petites conversions à la main
  • l’outil en ligne de commande subkey pour génération, inspection, signature
  • l’appli polkadotjs app section developer/utilities pour le décodage

Ou en Julia pour extraire le préfixe et la clé publique :

using Base58
# clé publique en base58
pubkey(x) = String(base58encode(base58decode(Vector{UInt8}(x))[2:end-2]))
# préfixe sous forme d'entier
prefix(x) = Int(base58decode(Vector{UInt8}(x))[1])

julia> prefix("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
42
julia> pubkey("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
"FHNpKmJrUtusuvKPGomAygQqeiks98bdV6yD61Stb6vg"
5 Likes

Pour l’opération inverse en Julia :

using Blake2, Base58

# subkey inspect 5Dq8xjvkmbz7q4g2LbZgyExD26VSCutfEc6n4W4AfQeVHZqz
# Public Key URI `5Dq8xjvkmbz7q4g2LbZgyExD26VSCutfEc6n4W4AfQeVHZqz` is account:
#   Network ID/Version: substrate
#   Public key (hex):   0x4e1f8a8a639370952db38fef62a763e1b8eea5600b6ccafc60d6849f028ff70f
#   Account ID:         0x4e1f8a8a639370952db38fef62a763e1b8eea5600b6ccafc60d6849f028ff70f
#   Public key (SS58):  5Dq8xjvkmbz7q4g2LbZgyExD26VSCutfEc6n4W4AfQeVHZqz
#   SS58 Address:       5Dq8xjvkmbz7q4g2LbZgyExD26VSCutfEc6n4W4AfQeVHZqz

ss58prefix = codeunits("SS58PRE") # SS58 prefix
chainprefix = hex2bytes("2a") # 42 prefix
pubkey = hex2bytes("4e1f8a8a639370952db38fef62a763e1b8eea5600b6ccafc60d6849f028ff70f")

md = zeros(UInt8, 64)
key = zeros(UInt8, 0)
input::Vector{UInt8} = vcat(ss58prefix, chainprefix, pubkey)

output = Blake2.Blake2b!(md, length(md), key, 0, input, length(input))
checksum = output[1:2]

addrs = vcat(chainprefix, pubkey, checksum)
ss58 = String(base58encode(addrs))

# 5Dq8xjvkmbz7q4g2LbZgyExD26VSCutfEc6n4W4AfQeVHZqz
2 Likes

À noter que ma définition du préfixe n’est valable que pour un préfixe <64, cf le code de py-substrate-interface :

if ss58_format < 64:
  ss58_format_bytes = bytes([ss58_format])
else:
  ss58_format_bytes = bytes([
    ((ss58_format & 0b0000_0000_1111_1100) >> 2) | 0b0100_0000,
    (ss58_format >> 8) | ((ss58_format & 0b0000_0000_0000_0011) << 6)
  ])

En julia, ça donne :

# x est le préfixe ss58
[ UInt8(((x & 0b0000_0000_1111_1100) >> 2) | 0b0100_0000),
  UInt8((x >> 8) | ((x & 0b0000_0000_0000_0011) <<6)) ]