Confidential Receive Descriptor and Invisible Protocol Entry Design v1¶
Status: design note for TKT-P4-03
Scope: recipient addressing and wallet UX on the frozen trustless fixed-statement path
This note does not change verifier semantics, artifact shape, or the frozen host/kernel split. It answers whether normal user-facing protocol entry can be hidden behind a confidential receive surface while preserving the merged trustless contract.
1. Executive recommendation¶
The best current model is:
- canonical protocol object: a recipient descriptor
- canonical user-shareable bundle: a descriptor bundle carrying the confidential descriptor plus an optional standard BCH fallback address
- copy/paste / QR UX: an address-like encoding of that descriptor later if desired
- session-based richer flows: a payment request that embeds the same descriptor plus amount/memo/expiry metadata
Why:
- a plain BCH-style "address" implies "any wallet can pay this output format correctly"
- that is not true for the current confidential protocol path
- the sender must understand protocol entry, confidential transition planning, and receiver recovery bindings
- the current frozen contract already has the right internal protocol objects for this, but it does not make the receive surface a generic BCH address
So the honest recommendation is:
- descriptor now
- descriptor bundle for real wallet UX
- address-like encoding later
- payment request wrapper where richer sender-side context is helpful
2. Frozen baseline¶
This design assumes all of the following stay unchanged:
backendId=2- trustless
TRQ1 - chunked proof transport as the BCH-scale rule
- Stage-B structural/kernel-facing verifier lane only
- Stage-A host duties unchanged
- wallet artifact parity remains fail-closed
- no ABI widening
- no verifier-visible witness aliases
- no host/public-shell drift
3. Product cases that must stay separate¶
3.1 Wallet-native confidential receive descriptor¶
The sender wallet understands the protocol and can:
- parse the descriptor
- derive receiver identity material
- perform protocol entry if needed
- construct the confidential transition
- emit the existing frozen trustless artifacts
- leave receiver recovery unchanged
This case is viable now on the frozen contract, with the caveat that "invisible entry" may still be an internally orchestrated multi-step wallet flow rather than a new single-transaction protocol shape.
3.2 Wallet-connect / handshake-based request flow¶
The sender and receiver exchange richer context through an app/session:
- recipient descriptor
- optional amount request
- optional memo or merchant label
- optional expiry / network / policy hints
This case is also viable now, and is a clean place to wrap the same descriptor in a richer request without redefining the protocol.
The important point is that the descriptor remains the protocol identity object. The payment request is only a transport/wrapper for richer UX.
3.3 Ordinary BCH wallet with no protocol support¶
This case is not viable for confidential receive on the frozen path.
An ordinary BCH wallet cannot:
- construct protocol entry into covenant-controlled state cells
- produce the trustless confidential transition artifacts
- enforce the protocol’s receiver recovery bindings
- reason about
RRE1,PIv1,PBv1, orSCv2
So ordinary BCH wallet behavior must fail closed.
Acceptable fallback behavior is:
- use a separate transparent BCH address or paycode surface
- or route through a protocol-aware wallet/application
Current Phase-2 compatibility commands (pool, shard, stage, import) should remain legacy/dev tooling, not the ordinary-user receive model.
4. Recommended protocol object¶
Define a reusable ConfidentialReceiveDescriptorV1 as the canonical recipient object.
It should contain:
- protocol/version marker
- network marker
- receiver identity transport payload
- either a protocol-tagged paycode / scan pubkey transport that yields
(A, B) - or explicitly encoded receiver scan/spend public keys
- profile lock for the frozen path
backendId=2- trustless
TRQ1 - optional user-facing label / capabilities metadata
It should not contain:
- amount
- tx hex
- source note ids
- proof bytes
- witness material
- current state cell pointers
- verifier-only or host-side recomputation data
If a richer request is needed, wrap the descriptor in a payment request object rather than widening the descriptor itself.
4.1 Recommended bundled receive model¶
The recommended wallet-facing receive object is:
- ConfidentialReceiveBundleV1
It packages together:
confidentialDescriptor- the protocol-native recipient descriptor used by protocol-aware wallets
fallbackBchAddress- an optional standard BCH address for non-supporting wallets
preferencepreferConfidential- optional display metadata
- receiver label
- network
- explanatory text for fallback handling
This is the cleanest honest model because:
- protocol-aware senders need more than a BCH address
- non-supporting wallets need a real standard BCH destination
- the bundle makes the capability split explicit instead of pretending one string can mean both paths
Recommended minimal shape:
type ConfidentialReceiveBundleV1 = {
version: 1;
network: 'chipnet' | 'mainnet';
confidentialDescriptor: ConfidentialReceiveDescriptorV1;
fallbackBchAddress?: string;
preference: 'prefer-confidential';
labels?: {
confidential?: string;
fallback?: string;
};
};
4.2 Packaging recommendation¶
Recommendation across the three packaging candidates:
- best canonical packaging: descriptor bundle
- best richer transport: payment request wrapping the descriptor bundle
- not recommended as the primary model yet: address-like encoding with fallback metadata
Why the descriptor bundle wins:
- it cleanly carries both the protocol path and the fallback path
- it matches the actual sender capability split
- it avoids overloading the word "address" with semantics that ordinary BCH wallets cannot satisfy
Why a payment request is still useful:
- it can wrap the same bundle for wallet-connect/session flows
- it can add amount, memo, expiry, or merchant context without redefining the protocol object
Why an address-like encoding is not the primary answer yet:
- a single address-like string suggests universal wallet compatibility
- fallback metadata and capability routing are more naturally expressed as a structured bundle
- address-like encoding can still be added later as a human-shareable representation of either the confidential descriptor or the whole bundle
5. Exact protocol object mapping¶
The correct mapping on the current frozen path is:
5.1 Receiver publishes descriptor¶
Receiver wallet exports:
ConfidentialReceiveDescriptorV1- whose identity payload yields receiver
(A, B)or the public material needed to derive it
Current protocol anchors:
- receiver identity
(A, B)is the normative ownership model in spec/protocol-terminology.md - paycodes/RPA are optional identity-distribution transports, not protocol requirements
5.2 Sender wallet resolves receiver identity¶
Sender wallet parses the descriptor and resolves:
receiverScanPub33receiverSpendPub33
This is exactly the public information the current planner uses.
Current code anchor:
- confidential_transfer_planner_v1.ts derives the receiver note, nullifier context, encrypted payload, and
RRE1hints from sender state plus receiver scan/spend public keys
5.2.1 Sender capability decision tree¶
The correct sender behavior for ConfidentialReceiveBundleV1 is:
- Parse bundle.
- If wallet supports the confidential protocol path and can consume
confidentialDescriptor: - default to Send Confidentially
- if sender already has confidential balance, run the existing confidential transition
- if sender only has transparent BCH, perform automatic protocol entry first, then run the confidential transition
- If wallet does not support the confidential protocol path:
- ignore
confidentialDescriptor - if
fallbackBchAddressis present, offer only a standard BCH payment to that address - do not claim or imply that the payment creates a confidential note
- If wallet does not support the protocol path and no fallback BCH address is present:
- fail closed and report that the receiver requires a protocol-aware wallet
This keeps the confidentiality claim aligned with actual sender capability.
5.3 Sender funding mode check¶
Sender wallet checks whether it already has at least one spendable confidential note:
- inspect wallet notes first
- treat protocol state cells only as the backing state for a wallet note
Current code anchor:
- note-first preflight in chipnet_profiles.ts
5.4 If sender already has confidential balance¶
Then the wallet runs the existing confidential transition path directly:
- source
WalletNoteRecordV1 - backing
SCv2state cell - current deterministic planner
- current
PIv1/PBv1/RRE1/EPv1
Objects produced:
stateIn32stateOut32outputFingerprint32PIv1PBv1(backendId=2, TRQ1, encrypted payload + hints)RRE1WNPay1payload encrypted inEPv1
5.5 If sender only has transparent BCH¶
Then the wallet performs invisible protocol entry as an internal orchestration step:
- spend ordinary BCH into at least one protocol state cell
- materialize a sender-owned wallet note backed by that state cell
- immediately continue with the standard confidential transition path
This preserves the current protocol model:
- entry remains entry
- transition remains transition
- the user simply does not see
stage/importas a manual workflow
Important honesty rule:
under the current frozen contract, this is best modeled as wallet-orchestrated invisible entry, not as a new one-step protocol action.
5.6 Receiver recovery remains unchanged¶
Receiver later scans the transition transaction and recovers the note using the same current rules:
- parse host unlock carrier
- parse
PIv1/PBv1 - verify output fingerprint binding
- parse
RRE1 - derive shared secret from scan key and
txEphemeralPubkeyR33 - decrypt
EPv1 - decode
WNPay1 - validate note root / null root / witness / note commitment
- persist
WalletNoteRecordV1
Current code anchor:
6. Why this is compatible with the frozen trustless contract¶
This addressing layer is compatible with the merged path because it only changes how the sender obtains receiver identity and entry intent.
It does not change:
- the proof artifact
- the public input boundary
- the host/kernel split
- the recovery payload format
- the receiver scan rules
The descriptor feeds the existing planner boundary.
That planner boundary is already defined as:
- source wallet note
- source protocol state cell
- sender wallet context
- receiver wallet context
(A, B)
See spec/confidential-transfer-planner-v1.md.
7. What is viable now vs later¶
7.1 Viable now¶
Invisible protocol entry is viable now if the sender wallet is protocol-aware and the product requirement is:
- one recipient descriptor
- one "Send Confidentially" action in the wallet
- internal orchestration that may perform entry first if needed
- no manual
stage/importUX
This can be done without contract drift.
7.2 Viable later¶
An address-like encoding for copy/paste or QR is viable later as a transport wrapper for the same descriptor.
That is a wallet UX/encoding problem, not a verifier problem.
7.3 Not viable now under the current boundary¶
The following stronger claims are not viable now without future work:
- "any ordinary BCH wallet can pay this and produce a confidential receive"
- "transparent BCH can become a receiver note in one new universal address payment without protocol-aware sender support"
- "protocol entry and confidential transition collapse into one new universal receive semantic under the current fixed planner without additional planning work"
8. Exact blocker for the stronger version¶
If the desired product is:
- a single universal address
- payable by non-protocol BCH wallets
- or a one-step transparent-BCH-to-recipient-note flow with no sender-side protocol orchestration
then the blocker is:
- the current frozen path assumes protocol-aware sender planning
- the current confidential transition planner starts from an existing sender wallet note + backing state cell
- the current protocol entry path is still distinct from the transition path
That is a wallet/planner/orchestration blocker, not a verifier blocker.
9. Recommended user-facing UX¶
Recommended ordinary-user language:
Confidential BalanceReceive ConfidentiallySend ConfidentiallyScanMove to Standard BCH
What becomes invisible:
poolshardstageimport- manual state-cell selection
What remains advanced/dev-only:
- compatibility entry commands
- direct state-cell inspection
- manual import/stage overrides
- debug selectors such as
shardIndex
9.1 Receiver UX flow¶
Recommended receiver-facing flow:
Confidential receive¶
Primary action:
Receive Confidentially
Display:
- a shareable confidential receive bundle
- explanatory text such as:
For wallets that support Confidential BCH, use this to send directly into my confidential balance.
Fallback BCH receive¶
Secondary action:
Fallback BCH Address
Display:
- a standard BCH address
- explicit warning text such as:
For wallets that do not support Confidential BCH. Payments here are standard BCH only and are not confidential notes.
Later move-to-confidential flow¶
If fallback BCH is used:
- wallet shows the received funds under standard BCH balance
- wallet offers a follow-up action such as:
Move to Confidential Balance
That follow-up flow is an explicit wallet-side protocol entry from transparent BCH into confidential balance.
Important honesty rule:
- fallback BCH receive is transparent BCH, full stop
- it is not a confidential receive
- it only becomes confidential after a later protocol entry step
10. Recommendation summary¶
10.1 Address vs descriptor vs payment request¶
Recommendation:
- best canonical protocol identity model now: descriptor
- best receiver-facing packaging now: descriptor bundle
- best wallet-connect/session wrapper: payment request carrying the descriptor bundle
- best future human-shareable encoding: address-like string for the confidential descriptor or bundle
10.2 Viability¶
Invisible protocol entry is viable now on the frozen contract for protocol-aware sender wallets.
It is not currently a generic BCH address capability.
10.3 Optional spike need¶
No spike is required to answer the design question honestly.
The current planner, receive scan, and note-first preflight seams already show that:
- receiver identity transport is separable from verifier mechanics
- sender-side descriptor interpretation can feed the current planner boundary
- invisible entry is primarily an orchestration/UX problem under the existing contract