KPOP — questions, and where it goes next
Working notes. The first half is what the app does today and why; the second half is a family of flows it does not do yet — the ones where custody itself moves — kept here so they have a home while the shape settles.
The app
What is a check?
A signature over a challenge that cannot be a transaction. Every challenge starts with the bytes KPOP1 — the first byte, read as a protobuf tag, is field 9 with a wire type no Hedera decoder accepts — followed by 16 random bytes. Signing one proves the key is available and can move nothing. KSIGN shows it as undecodable body — verify checksum out of band, which is correct.
Why four states and not three?
Current, due soon, overdue, unconfirmed. Overdue is not lost — a key that has not answered for a month still exists; there is just less evidence it is available. Unconfirmed is where consequences live: the key is treated as unavailable for planning. The app never records "lost"; it records "possession not demonstrated within policy". That wording matters once anything automatic depends on it.
What sets the policy?
The key's authority — how consequential it is where it is used. The check falls somewhere in the last part of each cycle, picked from a hash of the key and its cycle, so it is stable but not readable off a calendar. Nothing is checked more often than fortnightly: weekly was judged too intense for any key.
| Authority | Cadence | Window | Answer within | Unconfirmed after | Extra |
|---|---|---|---|---|---|
| Practice | monthly | last 7 days | 48 h | 30 days overdue | — |
| Low | annual | last 60 days | 72 h | 60 days | — |
| Medium | quarterly | last 21 days | 48 h | 30 days | — |
| High | monthly | last 7 days | 24 h | 14 days | random day |
| Critical | fortnightly | last 4 days | 4 h | 7 days | random day, biometric |
What does the storage grade mean?
A number out of 100 and a letter, from the storage questionnaire on the key card, meant to read like a password-strength meter. It starts at 100 and loses points for each finding, in three sections each with a cap so one bad section cannot zero the whole thing:
| Section | Up to | What costs |
|---|---|---|
| Copies | 50 | no copy recorded at all (40); no offline copy (30); a single copy (10); each digital or fragile copy by its kind (a cloud copy 40, a photo 35, an online file 30, a password manager 15); an unencrypted digital copy (10); a copy an organisation can reach (10) or nobody is sure who can (20); a copy nobody is sure where it is (15) |
| History | 40 | each "yes" to the secret's past — in a cloud or a message (30), typed into an untrusted site (25), on a connected device or photographed (20), still possibly on that device (15), shown on a visible screen or printed on a shared printer (10); each question left unanswered (3) |
| Origin | 20 | created by someone else (20); made on a connected device (10); origin unknown (10); not sure every copy is accounted for (25, or 5 if merely unconfirmed) |
Letters: A 85 and above, B 70, C 55, D 40, F below 40. Below 55, or any cloud, message or untrusted-site exposure, the card suggests rotating. The card's "Storage grade F — 10 of 100. Lost to:" block lists exactly which findings took the points, biggest first.
What are a key's "copies"?
A key is usually held as more than one copy of the same secret: a sealed envelope in a safe, the same words in a wallet on a phone, a second envelope with someone else. The card lists each copy as one line — a custodian (a person, a place, a vault reference; the same names the fragments use, offered back as a dropdown) and free-text notes on how that copy manifests: "sealed envelope", "HashPack", "paper, unsealed, in the desk", "metal plate". Sealed matters: a sealed copy can be inspected now and then and seen never to have been opened, which an unsealed one cannot claim. Add as many lines as copies were made — when minting, that is the number KGEN printed. Removing a line asks first, because a copy you cannot account for is exactly what the list is there to catch; two lines with the same custodian and notes is a mistake, say which is which. The earlier tick-boxes (every place the secret exists, what unlocks it, hardware-backed and attested) were dropped on 2026-09-16: they could say what a copy was but never where it was. The storage questionnaire still grades copies by class.
Do fragments work the same way?
Yes, since 2026-09-16 they are the same list, edited the same way: a line per copy, two fields saved when you click away, + copy to add one and ✕ to remove one after a confirm. A fragment keeps one thing a key does not — each copy is marked sealed or opened, and the chip toggles it, because a sealed copy that has never been opened is a stronger claim than a note saying so. A fragment's column is where rather than custodian, but the names come from the same pool, so a place you have already used is offered back on either.
What does "exposed" on a master key mean?
A key with salted children on the accounts list is a master, and the whole point of salting was that the master's public key never appears on chain — anyone holding it can enumerate the children by trying account numbers as salts. If the mirror node finds the master itself on an account, or it sits on a listed account as itself, that linkage has been given away. It is a privacy loss, not a key compromise, but it is the privacy the children were bought for, so the card says so and offers it as a reason to rotate.
What does KPOP hold?
Public keys, names, custody notes, receipts. No seeds, no private keys, nothing that can sign. All of it in this browser's storage; Back up hands it to you as one line. Places in the storage questionnaire are classes (home, safe, bank), never addresses.
Why did my key vanish when I switched the toggle?
Because it is declared for the other network. The toggle filters: on mainnet you see keys declared mainnet, keys the mirror node found on mainnet, and keys not declared at all. A key declared testnet only shows on testnet — unless it is in conflict, in which case it shows everywhere, loudly.
What is the network rule?
Look up accounts asks both mirror nodes every time, precisely so a key cannot hide on the network you are not looking at. It is the one network call KPOP makes, and only when pressed.
How does KPOP know a key is a salted child of one of mine?
It cannot see it on chain — a child leaves no link to its master, which is the point. What it can do is work forwards: KSIG-SALT-v1 is additive on ed25519, so the child's public key follows from the master's public key and the salt, with no secret involved. KSUB salts each account's key with the account number, so for every ed25519 key in the ledger and every account on the Accounts tab, KPOP derives child(master, number) and compares it to the account's key leaves. A hit is shown as salted child, salt N. An account whose keys were salted with something else is pasted as 0.0.N(salt), KSUB's notation; the salt is kept on the account and tried as well as the number, so a master that arrives later is still matched. That is why the Accounts tab matters: without a candidate list of accounts there is nothing to test against, short of walking every account on the network.
And a hardened child?
Cannot be found that way, by design. A hardened derivation hashes the master's private key into each child, so the master public key says nothing about them, and a child says nothing about its siblings or the master. Two consequences worth holding onto:
- If the master's secret leaks, every hardened child is still derivable — the attacker has what the derivation needs. Hardened protects against the child-plus-master-public leak (the BIP-32 weakness), not against losing the master. Which accounts those children sit on is then a brute-force question: derive candidates for likely salts, look each up by public key. With account-number salts that is cheap.
- Whoever holds the master can always sign for the child. If someone issued you a hardened child key, you have full control of the account and so do they, and nothing on chain shows it. That is a custody fact, not a chain fact — record it: the questionnaire's salted child of a master is the place, and a field naming the master's holder is the obvious addition.
Non-hardened has the opposite trade: anyone holding the master public key can link every child by enumerating salts (privacy), and a child's secret plus the master public key recovers the master (the BIP-32 leak). KSIGN treats the master public key as a secret for exactly that reason.
Why do I get an old version after a deploy?
The app keeps a copy of itself so it opens with no network. A new build is picked up on the next visit and a banner offers it; Get a fresh copy on About forces it. Neither touches your keys. An incognito window always shows the live build.
Rotation
Rotation keeps custody where it is and changes the key. That is KPOP's home ground, and the reason categories on the questionnaire are the reasons you rotate:
| Why | Urgency | Typically |
|---|---|---|
| Leak or suspected exposure | urgent | anything on the storage questionnaire's history list answered "yes" |
| On a break-glass key | urgent | a single device holds it — temporary by design, see below |
| On an interim 1-of-1 | — | safe, but not the policy the asset deserves |
| Storage grade too low | — | sloppy custody: copies unaccounted for, digital copies, unknown access |
| Test key | — | printed to kick the tyres; would not survive as a mainnet key |
| Policy or asset value changed | — | the thing it protects grew; the key needs more cover than one signer |
| Custody moving to another party | — | not really a rotation — a transfer, below |
| Routine | — | hygiene |
Transitions — where custody moves
Rotation is one family. The other is where the arrangement changes: who holds the key, on what, under what policy. These are workflows with steps, not a flag on a card. KPOP does not run them today; this is the list, so they are not lost.
The break-glass flow
Three transitions, in order, each a real rotation:
A key's current stage on this path — break-glass, interim, policy — is a fact worth recording per key. Today the closest thing is the rotation reason; a first-class stage is the obvious next field.
The others
| Scenario | What changes | Notes |
|---|---|---|
| Uplift | Asset value rose; policy tightens | a single key becomes a threshold; new keyholders join; cadence shortens. Reverse it when an asset is retired. |
| Onboarding | Wallet-made key → managed policy | the wallet key becomes the interim; the storage questionnaire is the entry gate |
| Hand-over | Custody to a third party | you rotate them in, they rotate you out. Two ledgers, one receipt trail. |
| Sale | Assets and keys change together | a batch: swap the assets and update the keys atomically, so no moment exists where one side has both |
| Structural | A keyholder leaves a threshold | the natural end of Unconfirmed: the group rotates the absent key out; the absentee sees it on their own ledger when they wake up |
| Network hygiene | A key found on both networks | rotate it out of one side — the only fix for the rule above |
Does this belong in KPOP?
Partly. KPOP is the ledger and the flag: which stage each key is at, which are marked, what the receipts say. Executing a transition — raising the account updates, collecting signatures, submitting — is KSUB and KSIGN's, and should stay there. The seam is a plan: a named flow (break-glass, uplift, hand-over) with its steps, attached to a set of keys, that KPOP tracks and KSUB carries out. That is a tab's worth of work, and the right time for it is after the stage field and the reason categories have been used for real.
Growing the accounts list: crawling
The accounts you care about are connected on chain — one testnet portal account spawns the rest. So rather than pasting hundreds of ids, pick an account and a category of relation, see the candidates, and choose which to add. Each added account's note records how it got here (created by 0.0.1532, crawl) — a default you can edit, not a locked field. Categories, each one mirror-node query:
| Category | Query | Guard |
|---|---|---|
| Accounts it created | transactions by this payer, type CRYPTOCREATEACCOUNT → the entity ids | bounded by the payer's own history; the safest crawl |
| Accounts it sent to | CRYPTOTRANSFER where it is a debit; the credited accounts | can explode on an exchange or a faucet — cap and confirm |
| Accounts that sent to it | the credits into it | spam airdrops make this the noisiest; never auto-add |
| Same operator | other accounts whose creating payer was the same account | one hop only |
| Token treasury / token holders | tokens it is treasury of; accounts holding those tokens | holders can be millions — show the count first, add only on selection |
| Same key | /accounts?account.publickey= for each of its leaves | already what Look up accounts on a key does |
Every crawl is one hop, shows its results as a list with a count before anything is added, and adds nothing without a selection. The one hop that matters most — accounts it created — is also the one that cannot run away, so it is the one to build first.
Open questions
- Is stage per key or per account? A key on break-glass is one thing; an account whose policy is a 3-of-5 across five keys is another. Probably both, with the account view coming from the mirror node.
- A node rather than a person: one place of operation, one device, one ledger. The app is already per device; naming it makes hand-over and vouching cleaner.
- A device that self-expires would wipe the only copy of the custody notes. Backups become mandatory, not advisory, before that exists.
- The storage questionnaire as a conversation rather than a form — same structured answers underneath, easier to give honestly.