Skip to main content

Stealth Addresses

A Platus user has one spending key but an unbounded family of payment addresses. Each address has a distinct on-chain footprint, so two payments to the same person are unlinkable, even to a payer who knows the recipient's full spending key.

A payment address

addr[i]=(d[i],  gd[i],  pkd[i]),plus the recipient’s mlkemPubkey\text{addr}[i] = (d[i],\; gd[i],\; pkd[i]), \qquad \text{plus the recipient's } mlkemPubkey
  • d[i] — an 11-byte diversifier, the index-i label of the address.
  • gd[i] — the diversified base point, DiversifyHash(d[i]), a BabyJubJub point in the prime-order subgroup.
  • pkd[i] — the diversified transmission key, [ivk]·gd[i].

A sender encrypts to (gd, pkd), the recipient recognizes the note because pkd = [ivk]·gd holds only for their ivk.

Deriving an address

DiversifyHash: hash-to-curve

DiversifyHash(d) maps a diversifier to a subgroup point by try-and-increment:

  1. y = Poseidon2(GD_HASH_DOMAIN, d_field, k) mod p for k = 0, 1, … (skip y ∈ {0, 1}).
  2. Solve the BabyJubJub Edwards equation x² = (1 − y²)/(a − d·y²); if is a quadratic residue, take x = √(x²).
  3. Cofactor-clear: multiply (x, y) by 8 to land in the prime-order subgroup; reject the identity.

Each iteration succeeds with probability ≈ ½, so it terminates in ~2 iterations on average. The result is deterministic given d.

Unlinkability properties

PropertyMechanism
Two payments to the same user are unlinkabledistinct d[i] ⇒ distinct (gd, pkd) on-chain
A payer cannot link your addresses to each otherd[i] derives from your private dk; the payer only ever sees one address
An observer cannot tell which ivk received a notepkd = [ivk]·gd is opaque; the view tag is uniform-random to non-recipients
Per-payment ephemeralityeach output also samples a fresh esk ⇒ fresh epk