Mo Tawfik Khalifa · Product leader and builder

All notes · Identity

How to prove who someone is without seeing who they are

Try it below

Over many years I’ve been asked the same question three times. A game the size of Earth needed to know its players were real. Another game needed a login that never touched the player’s keys. Nurses and doctors needed to prove their licence without handing every employer their whole file. Each time the answer was the same: prove the fact, not the person. Here’s how I built all three, in plain words. It’s long, but worth it, I promise.

First, the idea

A zero-knowledge proof in one picture

Somewhere on this busy page is Pip, in a blue striped bobble hat. Say you’ve found him and a friend doesn’t believe you. If you point at him, your friend learns where he is too.

So you take a sheet of card much bigger than the page, cut one small hole in it, and lay it over the page with the hole right on Pip. Your friend sees Pip, and nothing else.

Pip is somewhere on this page. Find him and tap him, then lower the sheet.

Or pull the tab down. With a keyboard, use the arrow keys.

Your friend is now sure of one thing, and has learned nothing else. That is a zero-knowledge proof. Software does it with maths instead of card. The first story below uses one. The other two chase the same idea, proving only the fact, with keys and encryption instead.

The sheet and the hole come from ‘Applied Kid Cryptography’, by Moni Naor, Yael Naor and Omer Reingold.

Three projects

  1. 01One player, one proofA zero-knowledge ID at PLAYERUNKNOWN Productions: the game learns a player is real, not who they are.
  2. 02A login that never touched the player’s keysNOR, at Consortium9: the player’s browser held the keys, and a wallet came in only when money moved.
  3. 03Prove the licence. Keep the file.Nurses and doctors send only the fields a job needs, through a server that can’t read them.

Then five rules I start every privacy product with, and the questions people ask me.

01PLAYERUNKNOWN Productions

One player, one proof

I was blockchain lead at PLAYERUNKNOWN Productions, Brendan Greene’s studio in Amsterdam. Brendan created PUBG. His next plan was a world the size of Earth, filled with things its players make and own.

A world like that has to know three things about each player:

  • Is this a real player?
  • Is it one player, or one person with fifty accounts?
  • Do they own what they say they own?

The usual answers give too much away. An email or a phone number leads back to your real name. A wallet pop-up is worse, because most crypto wallets are see-through. Once someone knows a wallet is yours, they can see everything in it, and everything that ever went in or out.

Step one: a login with no email and no phone

The first step was small on purpose. PP Vote was an iPhone and iPad app for quick polls. I wrote the spec. Here is the whole flow:

  1. The first time you open the app, it makes a random device ID. The server stores it with your new account. The rule was one phone, one account.
  2. You pick a username and a six-digit PIN. Nobody asks for an email or a phone number.
  3. The app gives you a 12-digit ID to keep safe. If you forget your PIN, that ID lets you set a new one.
  4. From then on, the app opens on the login screen only. On that phone, the sign-up screen never comes back.
  5. You answer the poll. The test poll asked “How do you feel working here?” (great, indifferent or bad) and had a box for suggestions.
  6. The results show as a pie chart. Suggestions appear under your username, or as “Anonymous” if you turn your name off.
An iPhone and an iPad on a desk in front of a monitor showing Xcode. Both run the PP Vote login screen: a username, a PIN, Forgot PIN and a red Login button.
PP Vote running on an iPhone and an iPad. You sign in with a username and a PIN. No email, no phone number.
Flowchart. A login screen that notes only one registration is allowed per device, with Register and Forgot PIN. Register leads to a username and PIN screen, then a poll: how do you feel about working here, great, indifferent or bad, with a box for suggestions. A note says to keep the 12-digit ID safe to reset the password. Results show as a chart with each suggestion under a username. Forgot PIN leads to a screen to enter your user ID and a new PIN. A note says once a device registers a user, the sign-up page never appears again.
My flowchart for PP Vote: one sign-up per device, a username and PIN, and a 12-digit ID for resetting the PIN. Open it full size

It worked, and it showed me where it stopped working. Nobody was asked for a name, an email or a phone number. But every answer came from a logged-in account, and the server kept a device ID next to every account. You had to trust whoever ran the server not to join those dots. And one person with two phones could still have two accounts.

So step two had to let the game spot a repeat player without the game, or anyone else, holding that link.

Step two: a zero-knowledge ID for players and wallets

Next I designed a zero-knowledge ID for players and their wallets. It made it into the studio’s game. The design belongs to the studio, so here is how this kind of ID works in general.

A zero-knowledge proof lets you show that a sentence is true without showing anything else. It’s the sheet of card from Pip’s page: your friend can see you found him, but not where he is on the page.

For a player, the sentence is: “I’m one of the registered players, and I control a wallet that holds this item.” The player sends a proof, the game checks it with maths, and the answer is yes or no. Making a proof that passes for a sentence that isn’t true would mean breaking the maths. A yes tells the game nothing about which player you are, which wallet is yours, or what else is in it.

One person can’t pretend to be many. Every proof carries a short code called a tag. The tag is made from a secret number only you hold, plus the game’s name, so it comes out the same every time you prove yourself to that game. The proof also shows the tag was made honestly from that secret, so you can’t swap in a made-up one. Try to join twice and the game sees the same tag. That is also why a ban sticks. Inside one game, the tag works like a nickname: the game can tell it’s the same player each time, just not who. Take the same ID to a different game and the tag comes out different, so two games can’t match you up by comparing tags.

The wallet stays private. The game never gets your wallet address. It gets a proof it can check and a tag. With no address, there is no see-through wallet to look into.

What a proof can’t do. It can’t stop someone getting two IDs in the first place. That is decided when IDs are handed out. In PP Vote, the phone decided it. A proof makes that check private, but it doesn’t make it stronger. A proof also hides you only among the people who could have made it, so if just four people own the item, the game knows you are one of four. And it doesn’t hide your internet address or your device. Anything you later do in the open on a public blockchain can be seen by anyone.

Try it

One player, one proof

Your side

The line. Only what crosses it is shared.

Game side

This tag is already inside.

Castle game

Gold Pass owners only.

What the game knows

  • Nothing yet

Two IDs make two tags. Making sure each person gets one ID happens at sign-up, not in the proof.

Here, four wallets hold a Gold Pass, so the game knows you are one of four. A bigger crowd hides you better.

IP 203.0.113.7

A proof doesn’t hide your internet address or your device. Anything you later do on a public blockchain is public.

The Castle game only lets in players who own a Gold Pass. How will you show yours?

A simple model of how a zero-knowledge ID works. Not the studio’s code.

How this toy works

The tag is a real SHA-256 hash of a secret made in your browser plus the game’s name. The proof check is acted out. In real systems the proof is checked by maths, the same proof shows the tag was worked out correctly, and the tag is called a nullifier.

Not hidden by a proof: your internet address and device, unless you hide them some other way.

What crosses the line, and what stays with you.

What I learned

“One person” is decided at sign-up. The maths can keep a check private. It can’t make a weak check strong.

Hide the link, not just the name. PP Vote hid names. The proof hides the link.

Recovery is the hard part. With no email, there is no reset email. PP Vote’s answer was the 12-digit ID, and the app had no other way back in. Both projects that came after this had to answer the same question.

02NOR, at Consortium9

A login that never touched the player’s keys

I led technology there, first as Director, then VP, then CTO. NOR was a platform for competitive games and tournaments. Our first game, FASTER, shipped on Steam.

The problem

Players hate wallet pop-ups. They hate being handed twelve or twenty-four secret words and told never to lose them. Every pop-up is a place to quit.

Stores have rules too. Steam does not take apps built on blockchain that issue crypto or NFTs, or let players trade them. So our rule was simple: the account system had no direct tie to web3. Inside the game, it was a plain login.

We still wanted real ownership. Your name, your record and your prizes should belong to you, not to us.

What we built on Holochain

NOR’s login, on the web, looked like any other. An email, a password, then a player name. Behind it, nothing worked like a normal account.

The form sat in a sealed box on the page, run by Holo, the hosting network built on Holochain. Inside that box, your browser turned your email and password into a key. The password never left the box. Neither did the key. Not to us, not to Holo. Our own page could not look inside.

Every time you did something that counted, the box signed it with your key. A signature is like a wax seal that only your key can make. Anyone can check it. Nobody can fake it without your key. Our server saw your player name, your public key (the half that is safe to share) and your signatures. It never had your private key, so it could not sign anything in your name.

The server did not need to know who you are. It only needed to know that a request came from the same key as last time.

“Login looks like web2 but actually connects to your local keys.”

Me, in NOR’s technology update.

NOR web page titled Technology update from our CTO.
NOR’s technology update. My line: the login looks like web2 but connects to your local keys.

Holochain held your identity, matchmaking and match results. How it differs from a blockchain, in two sentences:

A blockchain

A blockchain is one shared notebook that every computer copies, and they all have to agree on each new page.

Holochain

Holochain gives each player their own signed notebook that only they can write in, and each line they share goes to a random set of other computers, which check it against the game’s rules and keep copies.

Players installed nothing extra to log in: no wallet, no browser add-on. A Holo host ran each player’s notebook for them, so it could read what was in it. It could not sign a line itself. It had to ask the box in the player’s browser.

Try it

Who holds the key

Flip the login, then try each action.

The usual login: the game’s server holds your account, keys and all.

What the server can do
Usual loginNOR’s login
Sees your passwordYes, at every login. It keeps a scrambled copyNever
Holds your private keyYes, in its vaultNo. It stays in your browser
Can sign as youYesNo
Can reset your passwordYesNo. Nobody can
Can refuse your player nameYesYes. It vouches for names

Simplified. In NOR a Holo host ran your Holochain node and could read what it stored. Your key stayed in your browser, and the host had to ask the box for each signature.

“I’m very proud of our identity system where users get to truly control their own info, data, and more.”

Brooks Brown’s LinkedIn post: The wonderful Mohamed Tawfik Khalifa has been with us for a while now, so it’s nice to be able to center the amazing work he’s been doing as we finally get towards launch! I’m very proud of our identity system where users get to truly control their own info, data, and more. Aside from the clear advantages for users when it comes to not having their data mined for profit, it also means for us we get to save money on the over-wrought infrastructure central to such data mining implementations.
Brooks Brown, NOR’s CEO, on LinkedIn.

A wallet only when money moves

You met a wallet only when money or owned items were involved: buying a tournament ticket, claiming winnings, or proving you own a collectible. Tournaments ran on Rain Protocol, as rules on Ethereum.

To get paid, your browser asked our server for a fresh one-time code. Your key signed it, and you told us which wallet to pay. We checked the signature, then handed back a signed voucher. Your wallet took the voucher to the tournament contract and collected. That claim wrote your NOR key onto Ethereum, sent from your wallet.

How NOR fit together

Your browser, held by the player, runs nor.gg. Inside it, the Holo sign-in box makes your key from email and password, signs every action, and keeps the password and key. The box sends a signed one-time code to the NOR server. The NOR server, central and run by us, vouches for player names, hands out one-time codes and signs prize vouchers. It sends a signed prize voucher back to your browser, and its name vouching goes to the Holochain network, readable by every player. The Holochain network is shared and run by Holo hosts. It holds your NOR ID, matchmaking, match results, and player names that every player can read. A Holo host runs your node, can read what it stores, and asks the box for signatures, which the box sends when the host asks. Your wallet, used only when money moves, buys tickets and claims with the voucher at the Rain tournament contracts on Ethereum, which hold tickets and winnings. That claim is public: your NOR key next to your wallet.

Your browser nor.gg Holo sign-in box makes your key from email + password signs every action password and key stay here NOR server vouches for player names hands out one-time codes signs prize vouchers signed one-time code signed prize voucher name vouching,readable by every player Holochain network, run by Holo hosts your NOR ID matchmaking match results player names, readable by every player Holo host runs your node, can read what it stores, asks the box for signatures signatures,when the host asks Your wallet only when money moves Ethereum: Rain tournament contracts tickets winnings buy ticket, claim with voucher public: your NOR key next to your wallet Your browser nor.gg Holo sign-in box makes your key from email + password signs every action password and key stay here signed one-time code signed prize voucher NOR server vouches for player names hands out one-time codes signs prize vouchers signatures,when thehost asks name vouching,readable by every player Holochain network run by Holo hosts your NOR ID matchmaking match results player names, readable by every player Holo host runs your node, can read what it stores, asks the box for signatures Your wallet only when money moves buy ticket, claim with voucher public: your NOR keynext to your wallet Ethereum Rain tournament contracts tickets winnings
  • Solid: held by the player.
  • Dots: shared network.
  • Grey dashed: central, run by us.
How NOR fit together: what the player held, what we ran, and where money moved.

“Nor is the first Holo.Host customer … using Holochain for the distributed identity, matchmaking, game data.”

David Atkinson’s LinkedIn post: It’s been a pleasure and a blast working with Brooks B., Mohamed Tawfik Khalifa and Matt Gabrenya on the Nor platform and Faster integration. Nor is the first Holo.Host customer, choosing to use truly distributed hosting to serve its web platform, is using Holochain for the distributed identity, matchmaking, game data and Rain Protocol for the onchain tournament system and metagaming rules engine. It’s a small step towards an amazing future for the game industry.
David Atkinson, Holochain and Rain Protocol, on LinkedIn. More in Holochain’s own review.

As CTO I owned how the pieces fit together. We built it with the Holochain and Rain teams.

What it cost

It was a hybrid. Our server vouched for every player name. That is a central part. If it said no, you had no name.

Money still needed a wallet. We kept the wallet out of the login, not out of the game. Entering a tournament tied your ticket, and so the wallet that bought it, to your NOR key in records other players could read. Claiming a prize put your NOR key and your wallet address side by side on Ethereum, where anyone can read them, and player names were public inside NOR. That public link was the price of paying the right player.

Hosts were trusted while you played. A host could not sign in your name on its own. But the sign-in box signed what the host asked for, without asking you, for as long as you were signed in. The box’s own code also loaded from the web on each visit, like any page.

The first load was slower. The sign-in box had to find a host and connect to your node. Our loading screen said so.

Phone screen reading Welcome to NOR, Connecting, NOR is built on new decentralized technologies, loading may take a few seconds longer than expected.
nor.gg on a phone. The loading screen told players the truth: new tech, slower start.

There was no reset button. Your key is made from your email and password, so the same details rebuild the same key on any browser. Forget the password and nobody can reset it, not us and not Holo. A key made from a password is also only as strong as that password.

What I kept

The login is not the wallet. Keep the key with the player. Bring in money only when money moves. And say plainly which part is still central, and which links are public.

03Nurses and doctors

Prove the licence. Keep the file.

Nurses and doctors prove the same licence again for every hospital and agency they work with. Each one checks it from scratch and keeps its own copy of their documents. It’s slow, and every copy is one more place those documents can leak.

Here the employer does need to know who you are. A hospital can’t hire an anonymous nurse. So the job isn’t hiding the person. It’s sending only what the job needs.

I led this product for a client, first the product and design, then the engineering. The idea: check a licence once, keep it on the nurse’s phone, and let the nurse show each employer only the parts they ask for.

Three parties, and a server that can’t read

  1. Verification companyThe issuer
  2. encrypted to the nurse’s key
  3. Nurse’s phoneThe holder
  4. a link and a code
  5. Employer’s browserThe verifier
Our serverHolds a copy it can’t read
Checked once at the source, held by the nurse, shown to the employer.

These are the three roles of any verifiable credential. The issuer is a verification company that checks the licence with the board that granted it. The holder is the nurse. The verifier is the employer.

The issuer checks once, at the source. Then it encrypts the result to the nurse’s own key: the file is scrambled, and only that key can turn it back. The nurse’s key is worked out on the nurse’s own phone, from the nurse’s wallet, and never uploaded. We store the encrypted copy. We can’t read it.

Tick what to send. The rest is gone, not hidden.

When an employer asks, the nurse ticks the fields to send. Everything left unticked is deleted from the copy before it’s encrypted. It isn’t blurred or covered over. Its value isn’t in the file at all. The employer can tell that something was left out. The issuer’s signature over the whole licence still travels with the file, so a field with few possible values, like a status, could be guessed and checked against it.

That takes more care than it sounds. Credential files often repeat a detail, like the licence number, in a second place the screen never shows. Deleting it from the list isn’t enough, so the app removes those repeats too before anything leaves the phone.

Try it

Untick a field

Watch it leave the file, then take the link apart.

This demo encrypts for real, in your browser, and sends nothing anywhere. The issuer’s signature check is acted out.

Nurse’s phone

Always sent

Credential
Nursing licence
Checked by
Verification company

Also always sent: the check’s status and dates.

Every field starts ticked. Untick anything you want to keep back.

Fields to send

Sending 6 of 6 fields.

Employer’s browser
Show the employer’s

No link yet

Preview. Nothing sent yet.

Nothing shared yet

The issuer’s signature is checked when the employer opens a link.

Nursing licence

Checked by Verification company

The link, taken apart

No link yet

Our server

Our server keeps

  • Press Create link to make a share.

Pick a case

Create a link first.

The app’s share screen, headed Fields to Share: All fields are included by default. Untick anything you want to withhold. Six licence fields are ticked; the issue date and effective date are unticked.
The real share screen. Every field starts ticked; untick what to keep back.

A link with the key inside, and a code sent apart

Each share is a link plus a 9-digit code.

The link carries a new key made for this one share. It sits after the # sign. When a browser opens a link, it doesn’t send the part after the # to the website. So our server stores an encrypted copy it has no key for.

Whoever carries the link can see the key, like the email or chat service it travels through. That’s why the code goes by a different route, like a text or a call. The server won’t hand over the encrypted copy without it, and after eight wrong codes it stops accepting tries for half an hour. A stolen link on its own gets nothing. The code on its own gets scrambled bytes and no key.

Every share ends when the nurse chooses: from one hour up to 30 days, or never. The nurse can withdraw a share at any time, and the link stops working at once.

Opening a share doesn’t call the issuer or the licensing board.

The employer’s page asking for the code: Enter PIN. This credential is PIN-protected. Enter the 9-digit PIN that was shared with you separately. A box for nine digits and a Verify PIN button.
What the employer sees first: a request for the 9-digit code that came separately.

Signing in without an email

The client asked for a way in that needed no email address. I built one.

The first time, the phone makes its own key and keeps it in the phone’s protected storage, left out of cloud backups. To sign in, the sign-in service sends a one-time message and the phone signs it with that key. The signature only works once, and there’s no password to steal or phish.

Signing in this way asks for nothing about you: no email, no phone number, no name. The account starts as just the key. Getting a licence verified still takes an identity check and a phone number, because that’s what makes the result worth anything to an employer.

A button reading Continue without an email, with the line: This phone becomes your key. Nothing to type and no address on file. It starts a new, empty account, separate from any you already have.
The phone becomes the key. Nothing to type, no address on file.

What it doesn’t do

  • Lost keys stay lost. The keys come from the nurse’s wallet. If that wallet is lost, nobody can recover the credentials, us included. With the no-email sign-in, losing the phone loses the account. The issuer keeps its own copy, so the licence can be issued again.
  • The wallet comes from an outside provider. The keys are worked out on the phone and never sent anywhere, but the wallet they come from is run with an outside wallet provider, so that provider is part of what you trust.
  • A partial share can’t be checked against the issuer. The issuer signs the whole licence, not each line. Send part of it and that signature can’t be checked on the part, so the employer’s page says so instead of showing a green tick. For those lines, the employer has only the nurse’s word. Formats that let each line be checked on its own, like SD-JWT or BBS, fix this. We haven’t built that.
  • The link isn’t tied to one person. Anyone with the full link and the code can open it until it ends or is withdrawn.
  • The server sees the outside. It can’t read a share, but it knows whose share it is, which credential, who it was for, when it was made, how often it was opened.
  • You trust the page that opens it. That page comes from our server, so you’re trusting its code with the key. That’s the usual trade for a key in a link.
  • Screens can be photographed. An employer can still take a screenshot.
  • It isn’t zero-knowledge. This is encryption the nurse controls. The employer sees the real values the nurse chose to send.

My part: I led the product and the design, then the engineering. I wrote the encrypted share link, the field picking, the no-email sign-in, and the security hardening that came from trying hard to break it ourselves. That testing was our own, not an independent audit.

Across all three

Five rules for any privacy product

Three projects, three different stacks, and the same five rules kept coming up.

  1. Prove the fact, not the person

    Ask for the one fact the moment needs, and nothing that comes with it.

    At PLAYERUNKNOWN Productions the game needed to know a player was real, not who they were, so I designed an ID that answers with a proof instead of a name.

  2. Keep the server blind, and say what it still sees

    If a server can read something, it can leak it.

    The credential platform stored only sealed copies it had no key for. It still saw who shared with whom, and when, and I’d rather say that than hide it.

  3. Make the wallet a payout step, not a login step

    A wallet usually shows the same address to every site, so logging in with it links you everywhere.

    On NOR, sign-in looked like any website and the player’s browser held the keys. An Ethereum wallet only came in for tickets, winnings and owned items.

    From the nor.gg code

    "Connect your Ethereum Wallet to buy tickets""Connect an Ethereum wallet to claim winnings"POST identity/verify/holochain { agentpubkey }
    Two strings and one API call from the nor.gg site code, as archived. The wallet only appears when money moves. The call is the central check that vouched for usernames.
  4. Design recovery first

    Whoever can recover an account can also take it, so decide who that is before anything else.

    PP Vote handed you a 12-digit recovery ID the moment you signed up. On NOR your browser rebuilt your key from your email and password, so a forgotten password meant a lost account, and the tech under it says so plainly.

  5. Make the trust moment visible

    When someone shares, show them exactly what is going out, to whom, and for how long.

    In the credential app the professional unticks what to keep back, picks how long the link lives, and can see how often it was opened.

    Phone screen reading Credential Shared Successfully, License in TX, Purpose: Credentialing, Expires in 23h, with a nine-digit share code.
    The trust moment: what is going out, why, and when it expires. The code travels separately from the link.

Here are rules one and two in your hands. Pick how you’d prove you’re over 18, and see who learns what.

Try it

Who learns what?

Same fact, three ways to prove it.

WhoUpload a photoSigned credentialZero-knowledge proof
The websiteName, date of birth, home address, ID number, face photo“Over 18: yes”, the issuer’s signature, sealed codes for the lines you didn’t open“Over 18: yes”, proof that a real issuer signed it
The ID issuerNot involvedNothing. If the site calls it to check: which site you used, and when.Nothing. If the site calls it to check: that this site checked someone, and when. Not who, because the proof doesn’t say.
Someone who breaks in laterEverything above“Over 18: yes” and the signed part. No name.A proof that only says “someone here was over 18”. It can’t be reused, because it’s tied to that one visit.
Two websites comparing notesMatch you at once: same name, same ID numberCan match you: the signed part is identical, unless the issuer gave you a fresh copy for each siteCan’t match the proof, because each one looks new. They can still match your internet address, device or account.

None of these hide your internet address or your device. That’s a network problem, not a proof problem.

Sources: Discord’s incident update; RFC 9901, section 10.1; Google’s zero-knowledge age proofs; the EFF on what proofs don’t hide.

Most of this is standard cryptography. The skill is putting it where it removes a link between a person and their data, not where it adds a ledger. And most privacy is decided on one screen: the moment a person chooses what to share. That’s the screen I design first.

Plain answers

Questions people ask me

How can I prove I’m over 18 without uploading my ID?

Someone trusted checks your ID once, such as a government, a bank or your phone’s wallet, and gives you a signed credential. When a site asks, your phone shows only “over 18: yes”, and a zero-knowledge proof lets the site check that a real issuer signed it without seeing your name, your birth date or the credential itself. Google has open-sourced code for exactly this, and the EU’s age verification app includes it. The credential app follows the same first steps without the zero-knowledge part: check once at the source, seal it to the person’s own key, share only what’s asked.

What happens to my ID after I upload it?

It gets stored, by the site or by a vendor it hires, and anything stored can leak. Discord said about 70,000 users may have had government ID photos exposed through a customer service vendor that had used them to review age appeals. The fix is to stop collecting: in the credential app, the employer opens a licence record checked at the source instead of needing to collect and store its own copies, and the platform only holds copies it can’t open. Before you upload anything, ask who keeps the photo, for how long, and which vendors see it.

What is a zero-knowledge proof, in plain words?

It’s a way to prove something is true without showing anything else. The classic picture: cover a Where’s Waldo page, like Pip’s above, with a card much bigger than the book, with one small hole, and line the hole up with Waldo while nobody watches. People see you found Waldo but not where he is on the page. In software the card is maths: a checker runs a quick test, is convinced, and learns nothing beyond “true”. It’s the picture I use whenever I explain it.

Does zero-knowledge mean nobody can track me?

No. A proof hides what’s inside the credential, but the site still sees your internet address and device, and can still ask too often or for too much. Formats without zero-knowledge can also be matched: show the same signed credential to two sites and they can link you, unless the issuer gave you a fresh copy for each. On NOR the login and the wallet were kept apart until money moved. Claiming a prize put the player’s NOR key next to their wallet address on Ethereum, where anyone can see it.

How does selective disclosure work?

The issuer seals each line of your credential in its own envelope, mixes in a random “salt” so nobody can guess what’s inside, and signs the list of sealed envelopes. You open only the envelopes you choose, and the checker re-seals each opened line to confirm it matches the signed list. That’s how SD-JWT works, mobile driving licences use the same trick, and BBS signatures go further, so every showing looks new and two checks can’t be matched by the proof alone. In the credential app we removed unticked fields before sealing each share; next time I’d have the issuer make each field checkable on its own from day one.

Try it

Sealed envelopes

Pick which lines to show, then check them the way an employer would. The salts, the hashes and the signature are made for real, in your browser.

What the issuer signs

  • NoDk0KzwXB…
  • QgnGbhnDt8…
  • TTWqmTRT0r…
  • oTasAz1icH…
  • xaaR6m4bLr…
  • yPmWUPoM1V…

What the employer sees

  • Licence type: Registered nurse
  • Status: Active
  • Issuing board: Demo Licensing Board
  • NoDk0KzwXB… sealed
  • QgnGbhnDt8… sealed
  • oTasAz1icH… sealed
  • Show this same card to two employers and they can match the signed list. Fixes: a fresh copy per employer, or BBS signatures, where every showing looks new.
  • This is SD-JWT, an internet standard. In the credential app we removed unticked lines before sealing each share; having the issuer sign a sealed envelope for every line, as here, is what I’d do from day one.

Is a passkey a wallet?

No, though both are built on a key pair: a secret half you keep and a public half you share. A passkey only signs you in, and it’s a different key for every site, so sites can’t use it to match you. A wallet signs for money and data, and it usually shows the same address to every site, which is why I keep wallets out of the login. In the credential app I built a sign-in with no email: the phone makes its own key, keeps it in its own keystore, and signs a one-time challenge, close to how a passkey works.

What’s the difference between Holochain and a blockchain?

A blockchain is one shared ledger that every node has to agree on, in order. Holochain gives each person their own signed chain of actions, and peers check each new entry against the app’s rules before storing it, with no global agreement step. On NOR we used it for identity and login, and the keys were made and kept in the player’s browser, so hosts never held them, though they ran each player’s node and could read what it stored. It was a hybrid, too: a central service vouched for usernames, and players still needed an ordinary Ethereum wallet for tickets and winnings.

Can a game stop bots without collecting ID?

Yes, mostly. Make fake accounts cost something: tie each account to a device, the way PP Vote allowed one sign-up per phone (a sturdy version also has the phone prove it’s a real device), or accept a proof from someone else that you’re a real, unique person, usable only a set number of times a day. The game checks the proof, not the person, which is the idea behind the zero-knowledge player ID I designed at PLAYERUNKNOWN Productions. Nothing stops every bot, so aim to make cheating cost more than it earns, not to know everyone’s name.

Read next

See all notes