> ## Documentation Index
> Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Private Wallet

> 为现有的 Solana 钱包增加无许可机密 Ring 的隐私支持。创建私人钱包，接收和发送私人交易。

私人钱包由用于签名的 Solana 密钥对、一个空值密钥和一个用于加密的查看密钥组成，这些密钥合在一起形成了受保护的密钥对。
您的密钥管理中包含受保护的密钥对。
钱包代码使用 Privacy Interface 和 SDK 来构建私人交易。

<img src="https://mintcdn.com/helius/nNv9k5eJvwuxAzBn/images/privacy/stack.svg?fit=max&auto=format&n=nNv9k5eJvwuxAzBn&q=85&s=0e4087582b1d03c3d29d6a21f33149bb" alt="密钥管理和 Privacy SDK 通过 Privacy Interface 连接。Privacy SDK 调用 Privacy API。Privacy API 将交易提交到 Solana。" width="2156" height="270" data-path="images/privacy/stack.svg" />

该集成使您的用户能够：

1. 创建一个自我托管的私人钱包
2. 使用 Solana 地址接收私人转账
3. 将代币存入私人余额
4. 私密发送至 Solana 地址
5. 提现至任意 Solana 地址
6. 在本地解密私人余额和交易历史

该集成包括：

1. [**受保护的密钥对**](#集成受保护的密钥对) – 在您的密钥管理中用于加密
2. [**Privacy Interface 和 SDK**](#集成-privacy-interface-和-sdk) – 用于构建私人交易
3. [**用户流程**](#集成用户流程) – 集成到您的钱包中

## 您的 AI 的上下文

<Prompt description="Add a Private Wallet to an existing Solana wallet" actions={["copy", "cursor"]}>
  {`---
    description: Add a Private Wallet to an existing Solana wallet
    allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__helius-docs
    ---

    ## Add a Private Wallet to an existing Solana wallet

    Voice:
    - Point. Then a short, self-contained explanation in a real sentence.
    - No fill words.

    Current Page: https://www.helius.dev/docs/privacy/integration/wallet.md

    Implement in this sequence. Do not skip or rearrange:
    1. Shielded keypair derivation
    2. Privacy Interface in key management
    3. User flows.

    Context:
    - Docs index: https://www.helius.dev/docs/privacy.md
    - Spec: https://github.com/helius-labs/zolana/blob/main/docs/spec.md
    - MCP: https://www.helius.dev/docs/privacy/ai-tools.md
    - Packages: @heliuslabs/zolana, @solana/kit · zolana-client, zolana-interface, zolana-keypair, zolana-transaction
    - Examples: https://github.com/helius-labs/zolana-examples/tree/main/typescript-client · https://github.com/helius-labs/zolana-examples/tree/main/rust-client

    Key APIs: ShieldedKeypairLike, ViewingKeyLike, ShieldedKeypairTrait, ViewingKeyTrait, createZolanaClient. Flow APIs: the pages linked from the docs index.

    ### 1. Index project
    - Grep \`ShieldedKeypairLike|ViewingKeyLike|createZolanaClient|@heliuslabs/zolana|zolana-keypair|TSPP/derive\` across src/
    - Glob \`**/*.{ts,tsx,js,rs}\` · read package.json / Cargo.toml
    - Identify: existing Solana key management, seed vs hardware/MPC, account index, send path, balance/history UI
    - Task subagent if multiple packages

    ### 2. Read references
    - WebFetch the current page — both interface languages, both derivation tabs
    - WebFetch the docs index — follow the pages for the sequence above. Add on-/off-ramp only if selected in step 3
    - WebFetch the spec when protocol behavior is ambiguous (registry, spends, encryption)
    - TaskCreate one todo per phase below

    ### 3. Clarify intention
    - AskUserQuestion: Are you using TypeScript or Rust?
    - AskUserQuestion: Are you a seed-based wallet, creating tests, or a non-seed-based wallet?
    - Seed-based wallet → derive from the seed phrase
    - Tests → derive from a fixed message
    - Non-seed-based wallet → derive from a fixed message
    - AskUserQuestion: Do you want on-/off-ramp?
    - AskUserQuestion: Localnet or devnet?
    - Summarize. Wait for confirmation before planning

    ### 4. Create plan
    - Do not edit unrelated files. Do not add dead code.
    - Take existing code byte for byte. Do not invent APIs, files, or helpers that are not on the fetched pages or in the repo.
    - Every claimed path, symbol, and line number comes from step 1 or 2. If it was not read, do not write it.
    - ASCII tree of files to add or change. One line per file: path, then what that file does.
    - Follow the sequence. If unclear, AskUserQuestion. Present the plan. Wait for approval.

    ### 5. Implement
    - TS: Bash \`pnpm add @heliuslabs/zolana @solana/kit\` if missing
    - Rust: add the crates from the SDK page linked from the docs index
    - Follow the approved plan. Write/Edit. Do not replace the Solana keypair
    - TaskUpdate each step

    ### 6. Verify
    - Every interface method for the chosen language is implemented
    - No secrets in logs or network payloads
    - TS: Bash \`tsc --noEmit\` + existing tests
    - Rust: Bash \`cargo check\` + \`cargo test\` if tests exist
    - TaskUpdate complete

    ### Tools
    - mcp__helius-docs for docs pages
    - mcp__deepwiki__ask_question("helius-labs/zolana", "<q>")
    - WebFetch \`https://www.helius.dev/docs/<path>.md\`
    - Task subagent for parallel Grep/Read/WebFetch
    - TaskList for remaining work

    Invariants:
    - Wallet holds the shielded keypair. Never send key material to the Privacy API.
    - Implement every method on the chosen language's interface. Do not copy Rust-only methods (\`sign_hash\`, \`nullifier_key\`) onto TypeScript.
    - Viewing-key operations are local and synchronous. A sign-only custodian is invalid.
    - Use only APIs from the current page, the docs index, and the flow pages in the sequence. If an API is not there, stop and AskUserQuestion.
    - Do not log mnemonic, nullifier, viewing key, or the \`TSPP/derive/v1\` signature.
    - Language is TypeScript or Rust, not both.
    - Assets are SOL, SPL, and Token-2022.
    - Every Solana public key of the user can add a Private Wallet. One Solana address maps to one Shielded Address.
    - When the recipient of a private transfer does not have a Private Wallet, the Privacy API can resolve the transfer to a private-to-public withdrawal.
    We recommend requesting a separate user signature in the UI to ensure the user does not withdraw to a public balance by accident.`}
</Prompt>

<Accordion title="View prompt">
  ```text theme={"system"}
  description: Add a Private Wallet to an existing Solana wallet
  allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__helius-docs
  ---

  ## Add a Private Wallet to an existing Solana wallet

  Voice:
  - Point. Then a short, self-contained explanation in a real sentence.
  - No fill words.

  Current Page: https://www.helius.dev/docs/privacy/integration/wallet.md

  Implement in this sequence. Do not skip or rearrange:
  1. Shielded keypair derivation
  2. Privacy Interface in key management
  3. User flows.

  Context:
  - Docs index: https://www.helius.dev/docs/privacy.md
  - Spec: https://github.com/helius-labs/zolana/blob/main/docs/spec.md
  - MCP: https://www.helius.dev/docs/privacy/ai-tools.md
  - Packages: @heliuslabs/zolana, @solana/kit · zolana-client, zolana-interface, zolana-keypair, zolana-transaction
  - Examples: https://github.com/helius-labs/zolana-examples/tree/main/typescript-client · https://github.com/helius-labs/zolana-examples/tree/main/rust-client

  Key APIs: ShieldedKeypairLike, ViewingKeyLike, ShieldedKeypairTrait, ViewingKeyTrait, createZolanaClient. Flow APIs: the pages linked from the docs index.

  ### 1. Index project
  - Grep \`ShieldedKeypairLike|ViewingKeyLike|createZolanaClient|@heliuslabs/zolana|zolana-keypair|TSPP/derive\` across src/
  - Glob \`**/*.{ts,tsx,js,rs}\` · read package.json / Cargo.toml
  - Identify: existing Solana key management, seed vs hardware/MPC, account index, send path, balance/history UI
  - Task subagent if multiple packages

  ### 2. Read references
  - WebFetch the current page — both interface languages, both derivation tabs
  - WebFetch the docs index — follow the pages for the sequence above. Add on-/off-ramp only if selected in step 3
  - WebFetch the spec when protocol behavior is ambiguous (registry, spends, encryption)
  - TaskCreate one todo per phase below

  ### 3. Clarify intention
  - AskUserQuestion: Are you using TypeScript or Rust?
  - AskUserQuestion: Are you a seed-based wallet, creating tests, or a non-seed-based wallet?
    - Seed-based wallet → derive from the seed phrase
    - Tests → derive from a fixed message
    - Non-seed-based wallet → derive from a fixed message
  - AskUserQuestion: Do you want on-/off-ramp?
  - AskUserQuestion: Localnet or devnet?
  - Summarize. Wait for confirmation before planning

  ### 4. Create plan
  - Do not edit unrelated files. Do not add dead code.
  - Take existing code byte for byte. Do not invent APIs, files, or helpers that are not on the fetched pages or in the repo.
  - Every claimed path, symbol, and line number comes from step 1 or 2. If it was not read, do not write it.
  - ASCII tree of files to add or change. One line per file: path, then what that file does.
  - Follow the sequence. If unclear, AskUserQuestion. Present the plan. Wait for approval.

  ### 5. Implement
  - TS: Bash \`pnpm add @heliuslabs/zolana @solana/kit\` if missing
  - Rust: add the crates from the SDK page linked from the docs index
  - Follow the approved plan. Write/Edit. Do not replace the Solana keypair
  - TaskUpdate each step

  ### 6. Verify
  - Every interface method for the chosen language is implemented
  - No secrets in logs or network payloads
  - TS: Bash \`tsc --noEmit\` + existing tests
  - Rust: Bash \`cargo check\` + \`cargo test\` if tests exist
  - TaskUpdate complete

  ### Tools
  - mcp__helius-docs for docs pages
  - mcp__deepwiki__ask_question("helius-labs/zolana", "<q>")
  - WebFetch \`https://www.helius.dev/docs/<path>.md\`
  - Task subagent for parallel Grep/Read/WebFetch
  - TaskList for remaining work

  Invariants:
  - Wallet holds the shielded keypair. Never send key material to the Privacy API.
  - Implement every method on the chosen language's interface. Do not copy Rust-only methods (\`sign_hash\`, \`nullifier_key\`) onto TypeScript.
  - Viewing-key operations are local and synchronous. A sign-only custodian is invalid.
  - Use only APIs from the current page, the docs index, and the flow pages in the sequence. If an API is not there, stop and AskUserQuestion.
  - Do not log mnemonic, nullifier, viewing key, or the \`TSPP/derive/v1\` signature.
  - Language is TypeScript or Rust, not both.
  - Assets are SOL, SPL, and Token-2022.
  - Every Solana public key of the user can add a Private Wallet. One Solana address maps to one Shielded Address.
  - When the recipient of a private transfer does not have a Private Wallet, the Privacy API can resolve the transfer to a private-to-public withdrawal.
  We recommend requesting a separate user signature in the UI to ensure the user does not withdraw to a public balance by accident.
  ```
</Accordion>

<Steps>
  <Step>
    ## 集成受保护的密钥对

    私人钱包集成会在您的密钥管理中添加一个受保护的密钥对。
    受保护的密钥对用于签名、加密和解密交易。

    受保护的密钥对是签名、空值和查看密钥的集合。

    * **签名密钥：** 钱包的 Ed25519 Solana 密钥对用于签署交易。
    * **查看密钥：** 一个 P-256 密钥对，用于加密和解密交易。
    * **空值密钥：** <Tooltip tip="一个空值确保私人余额不能被重复消费。私人余额是由一个地址拥有的所有未消费交易输出（UTXO）的总和。每笔交易都会消费（作废）输入的 UTXO 并创建新的输出。">用于导出空值的密钥。</Tooltip>

    钱包可以通过两种方式创建受保护的密钥对：

    1. 对于基于种子的钱包，选择**从种子短语导出**。
    2. 对于非基于种子的钱包，选择**从 EdDSA 签名导出**。

    <Tabs>
      <Tab title="从种子短语导出" id="derive-from-seed-phrase">
        基于种子的钱包从一个 BIP-39 助记符和账户索引（`0`，`1`……）中导出受保护的密钥对。

        每个账户索引映射一个 Solana 密钥对到一个受保护的密钥对。
        您可以通过与恢复 Solana 密钥对相同的方式恢复受保护的密钥对。

        例如：

        * 账户 0: Solana 密钥对 0 和受保护的密钥对 0
        * 账户 1: Solana 密钥对 1 和受保护的密钥对 1

        | 密钥 | 导出路径                               | 方案                        |
        | -- | ---------------------------------- | ------------------------- |
        | 签名 | `m/44'/501'/account'/0'`           | SLIP-0010 Ed25519         |
        | 空值 | `m/44'/1392955331'/account'/1'/0'` | SLIP-0010 Ed25519\[1..32] |
        | 查看 | `m/44'/1392955331'/account'/2'/0'` | SLIP-0010 NIST P-256      |

        受保护的签名密钥就是该账户的 Solana Ed25519 密钥。
        空值和查看密钥是从同一个种子导出的附加密钥。

        <Info>
          示例实现： [TypeScript 示例](https://github.com/helius-labs/zolana/blob/cad0664e374f6a0e5c532169c5895203e366eb56/sdk-libs/ts/test/seed-based-keypair.test.ts#L60) · [Rust 示例](https://github.com/helius-labs/zolana/blob/cad0664e374f6a0e5c532169c5895203e366eb56/sdk-libs/keypair/tests/seed_based_keypair.rs#L111)
        </Info>
      </Tab>

      <Tab title="从 EdDSA 签名导出" id="derive-from-signature">
        从固定消息的 EdDSA 签名中导出受保护的密钥对。
        EdDSA 签名是确定性的，因此相同 Solana 密钥对为相同消息的签名总是产生相同的受保护密钥对。
        我们使用签名作为种子导出受保护的密钥对。

        固定消息负载为 `"TSPP/derive/v1"`，编码为 Solana 链下消息 v0。

        受保护的签名密钥是钱包的 Solana EdDSA 密钥。
        空值和查看密钥是从签名中导出的附加密钥。

        <Warning>
          签名是导出种子。
          拥有它的人可以导出空值和查看密钥，并且可以解密用户交易。
          拒绝来自第三方的 `"TSPP/derive/v1"` 消息签名请求。
        </Warning>

        从 Solana 签名导出受保护密钥对的伪代码：

        ```jsx theme={"system"}
        function deriveShieldedKeypair(solanaKeypair):
              solanaPubkey = solanaKeypair.publicKeyBytes() // 32 bytes
        	
              payload = UTF8("TSPP/derive/v1")

              // Solana off-chain message v0 envelope
              derivationMessage =
                  bytes("\xffsolana offchain")            // 16 bytes
                  || u8(0)                                // version
                  || SHA256(payload)                      // application domain
                  || u8(0)                                // restricted ASCII format
                  || u8(1)                                // one signer
                  || solanaPubkey
                  || u16LE(length(payload))
                  || payload

              // Ed25519 signatures are deterministic, so the same wallet produces
              // the same 64-byte seed every time.
              derivationSeed = ED25519_SIGN(
                  solanaKeypair.secretKey,
                  derivationMessage
              )

              // HKDF-Extract with no salt
              prk = HKDF_SHA256_EXTRACT(
                  salt = empty,
                  ikm  = derivationSeed
              )

              nullifierSecret = HKDF_SHA256_EXPAND(
                  prk,
                  info   = UTF8("TSPP/nf_key/ed25519/v1"),
                  length = 31
              )

              viewingKeyMaterial = HKDF_SHA256_EXPAND(
                  prk,
                  info   = UTF8("TSPP/view_key/ed25519/v1"),
                  length = 48
              )

              // RFC hash-to-field reduction into a non-zero P-256 scalar
              viewingSecret = P256_SCALAR_FROM_OKM(viewingKeyMaterial)

              return ShieldedKeypair {
                  signingKey:    solanaKeypair,
                  nullifierKey:  NullifierKey(nullifierSecret),
                  viewingKey:    P256Keypair(viewingSecret)
        }
        ```

        <Info>
          示例实现： [TypeScript](https://github.com/helius-labs/zolana/blob/cad0664e374f6a0e5c532169c5895203e366eb56/sdk-libs/ts/src/keypair/shielded.ts#L201) · [Rust](https://github.com/helius-labs/zolana/blob/cad0664e374f6a0e5c532169c5895203e366eb56/sdk-libs/keypair/src/shielded.rs#L126)
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step>
    ## 集成 Privacy Interface 和 SDK

    Privacy Interface 使您的代码能够使用 Privacy SDK 来构建私人交易，而无需直接访问密钥材料。
    您的密钥管理将 Privacy Interface 实现为两个部分。

    1. 使用 Privacy SDK 构建交易的签名接口。查看源码：[TypeScript](https://github.com/helius-labs/zolana/blob/236e6cd6cee4d07e567b316210e018f31dfa4d90/sdk-libs/ts/src/keypair/shielded.ts#L132)/ [Rust](https://github.com/helius-labs/zolana/blob/236e6cd6cee4d07e567b316210e018f31dfa4d90/sdk-libs/keypair/src/traits/shielded_keypair.rs)
    2. 加密和解密接口。查看源码：[TypeScript](https://github.com/helius-labs/zolana/blob/236e6cd6cee4d07e567b316210e018f31dfa4d90/sdk-libs/ts/src/keypair/shielded.ts#L154)/ [Rust](https://github.com/helius-labs/zolana/blob/236e6cd6cee4d07e567b316210e018f31dfa4d90/sdk-libs/keypair/src/traits/view_key.rs)

    <Info>
      Privacy Interface 是无状态的，因此不存储余额或交易历史。
      为了提高性能，我们建议在本地缓存用户余额和交易历史。
    </Info>

    ### 关于证明生成

    生成零知识证明需要完整用户交易数据和空值密钥的明文输入。

    目前，通过标准 Helius RPC URL 提供服务器证明生成。

    本地证明生成即将推出。
    计划在主网发布前在 AWS Nitro 上进行端到端加密的服务器证明生成。
  </Step>

  <Step>
    ## 集成用户流程

    ### 创建私人钱包

    私人钱包的创建分两步：

    1. 导出受保护的密钥对
    2. 在链上注册 Solana 地址。

    注册表将签名公钥链接到空值和查看公钥——这些公钥共同构成受保护的地址。

    ```mermaid theme={"system"}
    %%{init: {
      'theme': 'base',
      'themeVariables': {
        'lineColor':           '#FF6B35',
        'primaryTextColor':    '#737373',
        'primaryBorderColor':  '#9CA3AF',
        'actorBkg':            '#FFFFFF',
        'actorBorder':         '#9CA3AF',
        'actorTextColor':      '#737373',
        'signalColor':         '#FF6B35',
        'signalTextColor':     '#737373',
        'labelBoxBkgColor':    '#FF6B351F',
        'labelBoxBorderColor': '#FF6B35',
        'noteBkgColor':        '#F5F5F5',
        'noteTextColor':       '#737373',
        'noteBorderColor':     '#9CA3AF'
      }
    }}%%
    sequenceDiagram
        participant User
        participant Privacy SDK
        participant Solana

        User->>Privacy SDK: Create Private Wallet
        Privacy SDK->>Solana: Register Solana address

    ```

    <Info>
      每个注册记录是由 <Tooltip tip="regyS5rkAcw2YzDJCmTwCTHs2s246FXxbmuRZ42u2PD">[registry program](https://orbmarkets.io/address/regyS5rkAcw2YzDJCmTwCTHs2s246FXxbmuRZ42u2PD)</Tooltip> 拥有的 PDA，任何人都可以查找以确认 Solana 地址是否可以接收私人转账。
    </Info>

    ### 同步私人余额和交易历史

    余额同步从 RPC 获取加密状态并在钱包中解密。

    RPC 不负责解密。只有拥有查看密钥的所有者可以解密私人余额。

    <Info>
      在进行私人交易和运行回填时，钱包应在解锁、打开私人钱包、应用程序恢复、网络重新连接、流间隙或钱包恢复时解密并更新余额。
    </Info>

    <CardGroup cols={2}>
      <Card title="读取私人余额" icon="wallet" href="/docs/zh/privacy/guides/read-balance" horizontal />

      <Card title="读取私人交易历史" icon="clock-rotate-left" href="/docs/zh/privacy/guides/read-history" horizontal />
    </CardGroup>

    ### 存入私人余额

    用户可以通过两种方式将资金存入私人余额：

    1. 从法币余额进入私人加密余额
    2. 从公共 SPL 账户存入私人余额

    上坡通道与存款在隐私保证上有所不同。
    我们建议使用上坡通道而不是存款以获得更好的隐私。

    | 字段   | 从法币上坡 | 从 SPL 存款 |
    | ---- | ----- | -------- |
    | 资产   | 私人    | 公开       |
    | 数量   | 私人    | 公开       |
    | 来源   | 非链上   | 公开       |
    | 目标地址 | 公开    | 公开       |

    <CardGroup cols={2}>
      <Card title="上/下坡通道" icon="circle-dollar-to-slot" href="/docs/zh/privacy/integration/on-off-ramp">
        将法币直接上/下坡到私人余额。
      </Card>

      <Card title="存款" icon="arrow-down-to-bracket" href="/docs/zh/privacy/guides/deposit">
        从公共加密余额存入。
      </Card>
    </CardGroup>

    ### 私人转账

    用户可以向任何 Solana 钱包地址发送私人转账。

    对于每次私人转账，Privacy SDK 会在链上注册表中查找钱包地址，以检查接收者是否有私人钱包。

    当接收者没有私人钱包时，Privacy SDK 可以将私人转账解析为私到公的提现。

    <Info>
      我们建议在用户界面中将交易标记为提现，以确保用户不会意外提取到公共余额。
    </Info>

    | 字段     | 可见性 | 原因                      |
    | ------ | --- | ----------------------- |
    | 资产     | 私人  | 资产在链上加密                 |
    | 数量     | 私人  | 转移的金额在链上加密              |
    | 来源私人钱包 | 公开  | 在机密 Ring 中，来源私人钱包在链上可见。 |
    | 接收者    | 公开  | 在机密 Ring 中，接收者在链上可见。    |

    <Card title="私人转账" icon="arrow-right-arrow-left" href="/docs/zh/privacy/guides/transfer">
      私密转至私人余额。
    </Card>

    ### 提现至公共余额

    提现可以通过两种方式使用：

    1. 作为对没有私人钱包的接收者的私人转账的后备，或
    2. 直接提现到公共 SPL 代币账户。

    对于提现，我们建议清晰标记用户正在离开私人余额，类似于种子短语或私钥导出。

    | 字段     | 可见性 | 原因                      |
    | ------ | --- | ----------------------- |
    | 资产     | 公开  | 资产在链上可见                 |
    | 数量     | 公开  | 提现量在链上可见                |
    | 来源私人钱包 | 公开  | 在机密 Ring 中，来源私人钱包在链上可见。 |
    | 目标公共钱包 | 公开  | 目标钱包地址在链上可见             |
    | 目标公共余额 | 公开  | 最终的公共余额在链上可见            |
    | 剩余私人余额 | 私人  | 剩余余额在链上加密               |

    <Card title="提现" icon="arrow-up-to-bracket" href="/docs/zh/privacy/guides/withdraw">
      提现至公共加密余额。
    </Card>
  </Step>
</Steps>

## Didn't find what you were looking for?

<Callout type="info">
  Reach out! [Telegram](https://t.me/tilo_light) | [E-Mail](mailto:sales@helius.xyz) | [Contact](https://www.helius.dev/contact)
</Callout>
