Skip to content

Address format

In Dusk, an address is nothing more than the account’s public-key, which is compressed and serialized as raw bytes, and then encoded with Base58. As the compressed-point representation is injected into Base58, every address maps uniquely to its key(s). The encoding is human-readable while remaining compact and safe.

Quick reference

Address typeUnderlying key(s)Alphabet
Moonlight (public)1 × BLS12-381 G2
compressed (96 B)
Base58
Phoenix (shielded)2 × Jubjub points (A,B)
compressed (2 × 32 B)
Base58

Encoding steps

  1. Start from the public key(s)
    • Moonlight: a single point in the BLS12-381 G2 group.
    • Phoenix: two points (A and B) on the Jubjub curve.
  2. Compress each point using the curve’s compressed representation (x-coordinate plus sign-bit).
  3. Concatenate and serialize → raw byte string.
  4. Base58-encode the byte string → wallet‐friendly address.

Because the y-coordinate is not stored, it is recomputed on the fly when decoding, guaranteeing that any address that passes Address::from_str() is a valid point on its curve.


Decoding & validation

The following program can be taken as a reference:

use rusk_wallet::{Address, Error};
use std::str::FromStr;
fn main() -> Result<(), Error> {
// These are valid example address strings as they would be shown in our wallet
// They are generated by serializing the respective public keys and encode them
// With bs58 to make the strings small(ish)
let public_address_str =
"qe1FbZxf6YaCAeFNSvL1G82cBhG4Q4gBf4vKYo527Vws3b23jdbBuzKSFsdUHnZeBgsTnyNJLkApEpRyJw87sdzR9g9iESJrG5ZgpCs9jq88m6d4qMY5txGpaXskRQmkzE3";
let shielded_address_str =
"ivmscertKgRyX8wNMJJsQcSVEyPsfSMUQXSAgeAPQXsndqFq9Pmknzhm61QvcEEdxPaGgxDS4RHpb6KKccrnSKN";
// Create a public address from an address string
let public_address = Address::from_str(public_address_str)?;
println!("public address:\n{:?}", public_address);
println!("public key:\n{:?}", public_address.public_key()?);
println!("");
// Create a shielded address from an address string
let shielded_address = Address::from_str(shielded_address_str)?;
println!("shielded address:\n{:?}", shielded_address);
println!(
"shielded key A:\n{:?}",
shielded_address.shielded_key()?.A()
);
println!(
"shielded key B:\n{:?}",
shielded_address.shielded_key()?.B()
);
Ok(())
}

This would give the following result:

Terminal window
public address:
qe1FbZxf6YaCAeFNSvL1G82cBhG4Q4gBf4vKYo527Vws3b23jdbBuzKSFsdUHnZeBgsTnyNJLkApEpRyJw87sdzR9g9iESJrG5ZgpCs9jq88m6d4qMY5txGpaXskRQmkzE3
public key:
PublicKey(G2Affine { x: 0x1376dca3359fcf084a904343591c9c6d420dea1e576a957120af2ea4c46ef9d3bb1394ad3cbc92413c59b1ce518c0850 + 0x0d31d41cb190cb54fab965d3edba820a8e8fc5cdf5df2ef0b17ed7b318c290808564ec96651502cb086f4e2317de8844*u, y: 0x05be43f1835f4e56e3678af726e4e92bfab8fb1fbb2eb8f862027915d33a0aeca65fd805087209bbc2b830cefba14527 + 0x056d8a47bdddda58ceea71ebd6804f45f9a16de9fa1f6c9ff8de510a1d3b6e024c56ee0bdd6113f12686bfd9c92f8689*u, infinity: Choice(0) })
shielded address:
ivmscertKgRyX8wNMJJsQcSVEyPsfSMUQXSAgeAPQXsndqFq9Pmknzhm61QvcEEdxPaGgxDS4RHpb6KKccrnSKN
shielded key A:
ExtendedPoint { u: 0x10c2c9b0d8139578fedc0fb7483050375829a91cdc1f0639b9ce335a6bef1640, v: 0x330343b6cde96d4ba72416ba53f7228c940c929bc675ea86107bafc2af072824, z: 0x0000000000000000000000000000000000000000000000000000000000000001, t1: 0x10c2c9b0d8139578fedc0fb7483050375829a91cdc1f0639b9ce335a6bef1640, t2: 0x330343b6cde96d4ba72416ba53f7228c940c929bc675ea86107bafc2af072824 }
shielded key B:
ExtendedPoint { u: 0x522c0be0e1314820427fd17742e027ec7977e8c8e92e5e917ff97e954f447888, v: 0x65065117420942dc7f73de113a5308d4134b52e84191efdf47b28b6aefee5159, z: 0x0000000000000000000000000000000000000000000000000000000000000001, t1: 0x522c0be0e1314820427fd17742e027ec7977e8c8e92e5e917ff97e954f447888, t2: 0x65065117420942dc7f73de113a5308d4134b52e84191efdf47b28b6aefee5159 }

More specifically, the Address::from_str() performs:

  • Base58 decoding
  • Curve-point decompression (reconstructing y)
  • Structural checks (expected byte length)
  • Error return if any step fails.

Resources

For further reference, you can look at: