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 type | Underlying 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
- Start from the public key(s)
- Moonlight: a single point in the
BLS12-381
G2
group. - Phoenix: two points (
A
andB
) on theJubjub
curve.
- Moonlight: a single point in the
- Compress each point using the curve’s compressed representation (
x
-coordinate plus sign-bit). - Concatenate and serialize → raw byte string.
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:
public address:qe1FbZxf6YaCAeFNSvL1G82cBhG4Q4gBf4vKYo527Vws3b23jdbBuzKSFsdUHnZeBgsTnyNJLkApEpRyJw87sdzR9g9iESJrG5ZgpCs9jq88m6d4qMY5txGpaXskRQmkzE3public key:PublicKey(G2Affine { x: 0x1376dca3359fcf084a904343591c9c6d420dea1e576a957120af2ea4c46ef9d3bb1394ad3cbc92413c59b1ce518c0850 + 0x0d31d41cb190cb54fab965d3edba820a8e8fc5cdf5df2ef0b17ed7b318c290808564ec96651502cb086f4e2317de8844*u, y: 0x05be43f1835f4e56e3678af726e4e92bfab8fb1fbb2eb8f862027915d33a0aeca65fd805087209bbc2b830cefba14527 + 0x056d8a47bdddda58ceea71ebd6804f45f9a16de9fa1f6c9ff8de510a1d3b6e024c56ee0bdd6113f12686bfd9c92f8689*u, infinity: Choice(0) })
shielded address:ivmscertKgRyX8wNMJJsQcSVEyPsfSMUQXSAgeAPQXsndqFq9Pmknzhm61QvcEEdxPaGgxDS4RHpb6KKccrnSKNshielded 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:
- The example program.
rusk_wallet::address
for the full parsing routine.