// ring signatures on ed25519

One of these signed. Nobody can say which.

Status: Engine: loading…
// the working app

Build a ring. Sign inside it. Verify from outside.

A ring signature (AOS / Back-style LSAG) chains a challenge through every public key in the ring. Only someone holding one of the private keys can close the loop — but the closed loop looks the same whichever member closed it.

1 Assemble the ring anyone

Generate member keys here (each is a real ed25519 keypair — its public key is a valid Solana address format, never funded), and optionally paste real Solana wallet public addresses as extra members.

Ring is empty.
Only in-page members can sign: the app holds their keys. A pasted wallet can be a ring member but cannot sign here — that would need its private key, which this app will never ask for.

2 Sign as one member signer · private

Pick which in-page member you are, write a message, and choose the mode. Linkable adds a key image I = x·Hp(P) so a second signature by the same member is detectable. Unlinkable omits it.

3 Verify verifier · public data only

The verifier gets the ring, the message, and the signature — nothing else. It walks the challenge around the ring; the signature is valid only if the walk lands back on c₀.

4 One-per-member board linkable mode

A poll that accepts only valid ring signatures and refuses a second post with the same key image. The board learns “this member already posted” — never which member.

Nothing posted yet. Sign in linkable mode, then “Verify & post”.
// how it works

A challenge that has to come full circle

  1. Ring. Public keys P₀ … Pₙ₋₁ on edwards25519, the curve behind Solana addresses. The signer is member π with secret scalar x, Pπ = x·G. Every key is checked to be a valid, torsion-free curve point; off-curve addresses (such as PDAs) are rejected.
  2. Open the ring. Pick random α; set c_{π+1} = Hs(ring, I, m, α·G, α·Hp(Pπ)). Hs is SHA-512 reduced mod ℓ; Hp is RFC 9380 hash-to-curve for edwards25519.
  3. Walk around. For every other member i, pick a random response sᵢ and compute c_{i+1} = Hs(…, sᵢ·G + cᵢ·Pᵢ, sᵢ·Hp(Pᵢ) + cᵢ·I). No secret is needed for these hops.
  4. Close it. Back at the signer, set sπ = α − cπ·x mod ℓ. That makes sπ·G + cπ·Pπ = α·G, so the hash chain closes. Only the holder of x can do this step.
  5. Verify. Starting from c₀, recompute every hop. If the final challenge equals c₀, some member closed the ring. Each sᵢ is uniformly random either way, so the signature does not point to anyone.
  6. Linkability. The key image I = x·Hp(Pπ) depends only on the signer's key, so two signatures from one member share I. The verifier also checks I is in the prime-order subgroup — without that check, cofactor-8 tricks let one key produce several key images (a real bug Monero fixed in 2017).
// privacy model

What each party sees

The verifier sees

  • The full ring of public keys and their order
  • The message and the signature numbers c₀, s₀…sₙ₋₁
  • In linkable mode, the key image I
  • That some ring member signed — a 1-in-n guess at best

The signer keeps

  • Their secret scalar and the nonce α
  • Which index they are
  • Members never need to cooperate or even know they are in the ring

Still exposed

  • Who is in the ring — choose it carefully; a ring of one real person is no cover
  • Linkable mode: posts by the same member are linked to each other
  • Network metadata: IP, timing, and how the signature reached the verifier

Solana angle: a Solana address is an ed25519 public key, so any set of wallets can form a ring and a statement like “one of these holders wrote this” becomes checkable. Today's wallets only expose ordinary signatures (signMessage), not ring signatures, so in this demo only keys generated in the page can sign. The optional member lookup reads balance and owner program from mainnet through this site's read-only RPC proxy; the ring signature itself never touches the chain.

Known limitations — please read

  • Reduces linkability, not anonymity. The signature hides the signer within the ring. It does not hide your IP address, timing, writing style, or how you shared the signature.
  • The ring is the anonymity set. If only one member is plausibly active, or if the other members are known bystanders, the cover is thin. Anyone can add anyone's public key without consent — a ring proves “one of these keys”, not that every member agreed to be included.
  • Pasted wallets cannot sign here. Real Solana wallets do not expose ring signing. A pasted address is a member for cover only; the signing key is always one generated in this tab.
  • Linkable mode links your own posts. The same member produces the same key image across every message in every ring that contains its key with this scheme.
  • Unaudited teaching code. The curve maths comes from @noble/curves 1.4.0 (loaded from jsDelivr), but the ring protocol on top is custom and unreviewed. Do not use these keys or this code to protect anything of value.
  • No on-chain component and no token. There is no deployed program and the ticker is a placeholder label.