docs(specs): identity digests and disclosure for the Google profile - #45
Open
SupremaLex wants to merge 8 commits into
Open
SupremaLex wants to merge 8 commits into
SupremaLex wants to merge 8 commits into
Conversation
A design proposal, nothing built: how a Google binding can reach the chain as a hash of the normalized email instead of the address, with the address disclosed only when its owner sends it. The note maps where the address is published today, lays out the options on each axis (what the circuit exposes, where normalization runs, which hash, where the mode lives, defaults and transitions, downstream readers, spec changes), measures the gate cost of the two viable hashes on the pinned toolchain, recommends one combination, and lists what it does not protect against and the decisions it leaves open. Assisted-by: Claude Fable 5.1 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
A digest profile's Proving Circuit exposes the handle and the canonical userId as keccak256 digests instead of bytes, and the Consumer keys the binding on them, so an identity resolves for whoever knows it and is published only when its owner sends the plaintext. Google is the launch digest profile, at Platform Ceremony Version 2. platform-ceremonies.md: REQ-PLAT-08A and 08B admit a circuit that normalizes what it digests and a Consumer that keys on digests; §2.1b adds REQ-PLAT-08D to 08F (keys from the digests, plaintext accepted only when it hashes to them, the disclosure call and what it refuses, the event's disclosed flag) with TEST-PLAT-20A; REQ-PLAT-16B lists the two digests as public inputs; REQ-PLAT-16C returns them and passes plaintext through unchecked; REQ-PLAT-16D moves the sub and email validation into the circuit; TEST-PLAT-06A exercises the three; §9 states what the digests protect and what they do not. ceremony-common.md: ASM-HASH-01 (preimage resistance, with the enumeration caveat), SP-PRIV-01, REQ-COMMON-05E returns digests where a profile exposes them, and §12 replaces the statement that every handle is published deliberately with the digest profile's confidentiality and its limits. libid.md names the guarantee among the enforceable ones. The design note carries the rationale and now points at this text. Assisted-by: Claude Fable 5.1 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
SupremaLex
marked this pull request as ready for review
September 22, 2026 15:22
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
libid | 328b7d8 | Sep 22 2026, 03:20 PM |
Nothing is released, so the digest statement replaces version 1 in place rather than arriving as version 2 beside it: platformCeremonyVersion stays 1, and the prose on version 1 exposing raw bytes and on a Consumer accepting version 2 only is gone. §9 says the handle rules are part of the profile's proof statement instead of prescribing a new version for every rules change. The design note drops its version-2 references and the old-version claim. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: SupremaLex <georglutsenko@gmail.com>
…r chooses §2.1b defines the two facts it had used without defining: an identity is disclosed once any transaction has carried its plaintext, and a name is published while the Consumer holds one to display. - REQ-PLAT-08D: the Consumer's Authorized Transaction Data for a binding carries whether the Submission discloses, so the choice is the user's and committed in the digest; a Submission carrying one of the two plaintexts, or plaintext its data does not authorize, is rejected; a private Submission keeps the published name when it re-proves the same handle and clears it otherwise (moved here from 08E, and narrowed). - REQ-PLAT-08E: the disclosure call publishes, and requires the identity and handle keys to be each other's current pair, in both directions, and the caller to own both, which refuses a handle another account of the same wallet took over; its necessity says a refusal protects the display, not the plaintext. - REQ-PLAT-08F: events carry the normalized handle. - REQ-PLAT-08A/08B: the digesting circuit refuses where the table trims; the Consumer normalizes whatever handle bytes it receives, taking none as already normalized. - TEST-PLAT-20A exercises each new rule. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- REQ-COMMON-05E returns the plaintext a Submission carried, marked unverified; the Consumer trusts it only once it hashes to the digests, and the Proof Verifier forwards it with the rest under REQ-COMMON-06. - REQ-PLAT-03: for a digest profile the Canonical Runtime derives the local fields from the signed ID Token, places them in the Submission exactly when the authorized operation discloses them, and never returns them to the application otherwise. - SP-PRIV-01 says what it holds: plaintext reaches the chain only in a Submission whose digest commits its disclosure or in a disclosure call, and a transaction carrying plaintext publishes it when sent, accepted or not. It depends on the new ASM-ZK-01, and REQ-COMMON-45 has governance select only zero-knowledge artifacts for a digest profile. - Common §12 and libid.md follow. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- REQ-PLAT-04 and 16D refuse a backslash in `sub`: every JSON escape begins with one, so no value the circuit digests holds an escaped byte; the email alphabet already lacks it. The old claim that an escaped value fails the byte comparison was false for `sub`. - REQ-PLAT-16D states the Google buffers, 31 bytes of `sub` and 62 of `email` (the handle rules' own maximum), so TEST-PLAT-06A's over-length cases are writable. - REQ-PLAT-08G: a digest profile's Consumer holds its handle rules equal to the circuit's and refuses to change them once it has bound an identity, since it cannot re-key digests; §9 points to it. - REQ-PLAT-16B lists SP-PRIV-01. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- The mode lives in the operation the user authorizes: `disclose` joins the claim's Authorized Transaction Data, the Canonical Runtime hands the email to the application only for a disclosing claim, and choosing by plaintext presence alone is recorded as the rejected alternative. - `publish` checks the pairing in both directions, with the two-account case that needs it; a private claim of the published handle keeps the publication; a refused `publish` still publishes its calldata. - The ENS gateway reads the indexer's store, keyed by the handle string, so private names resolve only once that lookup is keyed by node; the earlier "no change at all" and the RPC fallback it named were wrong. - The public-input count is stated once, per digest; the status line points at the spec map instead of repeating it; the map, the implementation steps and the decided list carry the new rules. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: SupremaLex <georglutsenko@gmail.com>
…kslash - REQ-PLAT-08D: the claim's Authorized Transaction Data carries the disclosure choice for every platform, one encoding per transaction kind, so a profile that exposes bytes rejects a Submission that does not disclose; TEST-PLAT-20A exercises it. - REQ-COMMON-45: governance selects artifacts that verify zero-knowledge proofs. - The design note lists the backslash refusal among the circuit's `sub` checks and in its done criteria: today's circuit accepts one. The digest vectors use opaque transactionData, so the new field leaves them as they are. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: SupremaLex <georglutsenko@gmail.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A private mode for Gmail handles. The Google profile's Proving Circuit exposes the handle and the canonical
userIdas keccak256 digests instead of bytes, and the Consumer keys the binding on those digests. The plaintext reaches the chain only in a transaction that discloses it: a claim whose authorized operation says so, or a later disclosure call from the owner. Whoever knows an address still resolves it; nobody reads it off the chain.The design note (
design/private-gmail-handle.md) holds the rationale, the options considered, the measured circuit cost, and every decision taken. The rest is the specification text it graduates into, followed by the review fixes.The specification
specs/platform-ceremonies.mdsubis refused, so nothing the circuit digests holds an escaped byte.sub/emailvalidation moves into the circuit, with 31- and 62-byte buffers. TEST-PLAT-06A exercises them.specs/ceremony-common.mdspecs/libid.md: one sentence among the enforceable guarantees.Decisions carried
subis hidden with the handle.disclosejoins the claim's Authorized Transaction Data, committed in the digest like the fee, so the choice is fixed before proving. Making a private binding public later is apublishcall.publish: refused for a handle retired by a later claim, or taken over by another account of the same wallet.Review
/code-review xhighraised 15 findings plus 5 smaller ones. All are addressed, in the commits after543b6c5:subbytes;The version-2 finding went away when the digest profile became version 1.
Measured
Gate counts on scratch copies of the circuit at the pinned toolchain (nargo 1.0.0-beta.25, bb 5.2.0):
The
noir-lang/keccak256library compiles under the pinned Noir at v0.1.3, not at the vendored v0.1.1.Verification
The authoring skill's linter (
.agents/skills/trust-min-protocol-specs/scripts/lint_spec.py, run by hand) gives the same count as the pre-existing baseline, with no finding in the changed text. The digest vectors use opaquetransactionData, so the newdisclosefield leaves them valid. Spec references in the note are againstorigin/mainat002c201; contract, indexer and deployer references are against theirorigin/main.Based on
main.🤖 Generated with Claude Code