Skip to content

docs(confidential): specify the client SDK layer - #822

Draft
brozorec wants to merge 8 commits into
mainfrom
worktree-confidential-sdk-spec
Draft

docs(confidential): specify the client SDK layer#822
brozorec wants to merge 8 commits into
mainfrom
worktree-confidential-sdk-spec

Conversation

@brozorec

Copy link
Copy Markdown
Collaborator

Adds packages/tokens/src/confidential/docs/SDK.md, filling the SDK (to be added) placeholder in DESIGN.md's Project Documents register — the last unwritten document in the confidential-token set.

Why a normative document

The client is load-bearing here, not convenience tooling. Commitment openings (v, r) exist only off-chain, so a client that loses or mis-derives one makes funds permanently unspendable while the commitment sits visibly on-chain. Three requirements were also stranded — stated as obligations on "wallets and SDKs" in documents that don't own the client layer (DESIGN.md §5.2, DESIGN_cont.md §9.5, INDEXER.md §1/§7, SELECTIVE_DISCLOSURE.md §15.2). SDK.md cites and discharges them rather than restating them at their current sites.

Registered in the same style as INDEXER.md: RFC-2119, explicit normative audience, conformance section. Requirements are language-neutral; the @ctd/sdk prototype is named as the reference implementation.

Two substantive additions

§5 — sk derivation. DESIGN.md §4 begins from sk without saying where it comes from, while three documents describe recovery "from the master secret". A docs-wide grep for BIP-39/BIP-32/SLIP-0010/SEP-0005/mnemonic returns zero hits, and the prototype samples sk from a bare CSPRNG. §5 specifies one derivation — rejection-sampled HKDF-SHA-512 over the BIP-39 seed, bound to addr_f and acct_f. Notably, binding acct_f is a privacy MUST, not hygiene: vk depends only on (sk, addr_f), so the same sk registered under two addresses publishes identical Y and PVK under both, linking two otherwise-unlinkable addresses at zero cost to an observer.

§4.3 — the Poseidon2 sponge convention. DESIGN.md §2.5 cites external references for the permutation but fixes neither the sponge construction nor the padding rule; the only authority is circuits/lib/src/lib.nr. An implementer who follows §2.5 and reaches for a general-purpose Poseidon2 hash gets different digests for every derivation and fails every proof. §4.3 pins it.

Verification

  • All 13 sponge-derived vectors in circuits/lib/testdata/ were reproduced from §4.3 and §4.8's prose alone, using only a raw permutation and no code from the reference implementation — including the self-check that lane 0 of the two-lane squeeze equals poseidon_with_domain(d, [s, sigma]).
  • Every cross-document §N reference and relative link resolves (checked programmatically; the docs use hand-maintained numbering).
  • Numeric claims in §4.1/§4.7 recomputed rather than asserted. One figure was corrected in the process: the modular-reduction bias is stated as "20% more likely" (6 preimages vs 5), which is exact, rather than an ambiguous "relative bias".
  • NonCanonicalEncoding = 3514 and the §16.5 interface-drift claim verified against mod.rs.
  • Docs-only — no Rust touched, so cargo test / clippy are unaffected.

§16 — protocol questions this surfaced

Drafting turned up six places where the protocol docs are silent, mutually inconsistent, or behind the circuits. Each is recorded with the assumption SDK.md makes in the meantime, so implementations agree in the interim, but each needs a decision in the document that owns it. The two that most need a maintainer call:

  • r_e sampling is specified two opposite ways. DESIGN.md §7.6 step 1 says sample it; SELECTIVE_DISCLOSURE.md §7/§15.2 says derive it as Poseidon2(δ_eph, vk, σ). A client built to §7.6 alone permanently forecloses sender-side disclosure. §10.5 adopts derivation (matching the prototype). Adopting it protocol-wide also revises DESIGN_cont.md §9.4 — a vk holder can then construct openings, retroactively, of every transfer commitment the account created — and §8.2's scoping of that capability to the recipient's auditor.
  • δ_eph, δ_disc, δ_disc_bind have no assigned values, though §13 requires implementations to hardcode exact numbers. §4.8 pins them at 14–16 to match the prototype, which also documents repairing a real collision (δ_disc was at 13, colliding with δ_ecdh).

The others: the §2.5 "sequential squeezes" wording versus the single-permutation implementation; DESIGN_cont.md §11's read methods versus the contract's typed returns and get_spender_delegation name; and an optional hardening (binding acct_f into vk) that would make the linkage above structurally impossible at the cost of R2 and every VK.

No issue number — this completes an existing documented placeholder rather than introducing a feature.

PR Checklist

  • Documentation
  • Tests — n/a, docs-only

🤖 Generated with Claude Code

Fills the `SDK (to be added)` placeholder in the design doc's register. The
client is load-bearing here — commitment openings exist only off-chain, so a
client that mis-derives one makes funds permanently unspendable — but three
requirements were stranded as obligations on "wallets and SDKs" in documents
that do not own the client layer, and the seed-to-`sk` derivation the recovery
guarantee depends on was never specified at all.

Also records, in §16, six places where the protocol docs are silent, mutually
inconsistent, or behind the circuits, each with the assumption this document
makes in the meantime.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bdec8947-4ab7-4afb-a089-7d69dc6464a3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-confidential-sdk-spec

Comment @coderabbitai help to get the list of available commands.

brozorec added 5 commits July 28, 2026 16:43
Removes amplification, second-register restatements, rhetorical framing, and
paragraph-closing punchlines throughout, and repairs the three inbound §16
references left stale by that section's renumbering.
…_field vector

Distinct domain tags are not sufficient: SpongeSqueeze_2(d, s, sigma)[0] equals
poseidon_with_domain(d, [s, sigma]), so a tag used in both modes over the same
inputs reproduces the other mode's pad. address_to_field is the only primitive
implemented twice, on-chain and per client, and had no conformance vector.
Specifies the sponge construction in §2.5, replaces the n-squeeze phrasing
with the two-lane form, and requires each domain tag to be confined to a
single sponge mode. Also types the read methods' return values and renames
`get_spender` to `get_spender_delegation`.
Replaces the prohibition on the SEP-0005 signing key with two root classes —
the BIP-39 seed and a SEP-0053 signature by a signer on the account — keyed to
custody shape, with the tradeoff comparison in §5.2. Also trims §4 to defer to
DESIGN.md now that the sponge construction is normative there.
@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

brozorec added 2 commits July 29, 2026 11:45
Uses RFC 5869's `IKM` throughout §5, pins the exact byte string each root
class supplies (BIP-39 seed output, RFC 8032 `R ‖ S` signature, raw 32 bytes),
and states that it is passed verbatim rather than hashed or re-encoded.
An ed25519-controlled address now derives sk from a SEP-0053 signature by its
signer, and an address with no ed25519 key of its own from raw bytes supplied
by whatever custody mechanism controls it. A seed root added no reach a signer
root lacks and made an irreversible per-client commitment out of a class the
address should determine.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant