关于 inco-svm
inco-svm 是面向 Solana 开发者的技能,介绍如何借助 Inco Lightning 和 TEE 对加密数据进行计算,目前处于 beta 阶段。内容涵盖加密运算、解密权限管理和机密 SPL 代币。
主要功能
- 01加密整数与布尔值句柄
- 02算术、比较和位运算
- 03按句柄管理解密权限
- 04TEE 证明的解密
- 05机密 SPL 代币功能
- 06Rust 与 JavaScript SDK 指引
适用场景
- 01构建处理加密值的 Solana 程序
- 02控制哪些地址可以解密结果
- 03创建余额与转账均加密的代币
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ sendaifun/ skills --skill inco-svm安装后在 Claude Code 中输入/inco-svm确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
docs/troubleshooting.mdexamples/basic-operations/encrypted-operations.tsexamples/confidential-spl-token/mint-and-transfer.tsreveal-balance.tsexamples/private-raffle/raffle-client.tsresources/access-control.mdconfidential-spl-token.mdjs-sdk-reference.mdrust-sdk-reference.mdtemplates/inco-svm-setup.ts详细介绍
Inco SVM — Solana 上的机密计算
Inco Lightning 是 Solana 的机密性层,让开发者能够构建敏感数据即使在计算过程中也始终保持加密的应用。它使用可信执行环境(TEE)提供可验证的机密计算——无需新链,也无需新钱包。
注意: Inco SVM 目前处于 Solana devnet 上的 beta 阶段。功能可能会发生变化。
概览
- 加密类型 —
Euint128和Ebool句柄,表示存储在链下的加密值 - 同态运算 — 通过 CPI 对加密数据执行算术、比较、位运算和控制流操作
- 访问控制 — 使用 Allowance PDA 系统授予针对每个句柄的解密权限
- 认证解密 — 通过 TEE 共验证器进行 Ed25519 签名验证式解密
- 机密 SPL Token — 采用加密余额和转账的隐私保护型代币标准
- 客户端 SDK —
@inco/solana-sdk,用于加密、解密和实用辅助功能
架构
Client Solana Program Inco Covalidator (TEE)
│ │ │
├─ encryptValue() ──────────►│ │
│ ├─ CPI: new_euint128 ─────────►│
│ │◄─── handle (u128) ──────────┤
│ ├─ CPI: e_add / e_sub / ... ──►│
│ │◄─── result handle ──────────┤
│ ├─ CPI: allow() ──────────────►│
│ │ │
├─ decrypt([handle]) ───────────────────────────────────────►│
│◄─── plaintext + Ed25519 attestation ──────────────────────┤
Inco Lightning 程序 ID: 5sjEbPiqgZrYwR31ahR6Uk9wf5awoX61YGg7jExQSwaj
快速开始
安装
Rust Crate(链上):
添加到 Cargo.toml:
[dependencies]
inco-lightning = { version = "0.1", features = ["cpi"] }
添加到 Anchor.toml:
[programs.devnet]
inco_lightning = "5sjEbPiqgZrYwR31ahR6Uk9wf5awoX61YGg7jExQSwaj"
JavaScript SDK(客户端):
npm install @inco/solana-sdk
基本程序设置
use anchor_lang::prelude::*;
use inco_lightning::cpi::accounts::Operation;
use inco_lightning::cpi::{e_add, e_sub, e_ge, e_select, new_euint128, as_euint128};
use inco_lightning::types::{Euint128, Ebool};
use inco_lightning::ID as INCO_LIGHTNING_ID;
declare_id!("YOUR_PROGRAM_ID");
#[program]
pub mod my_confidential_program {
use super::*;
pub fn deposit(ctx: Context<Deposit>, ciphertext: Vec<u8>) -> Result<()> {
let cpi_ctx = CpiContext::new(
ctx.accounts.inco_lightning_program.to_account_info(),
Operation {
signer: ctx.accounts.authority.to_account_info(),
},
);
// Create encrypted handle from client ciphertext
let amount: Euint128 = new_euint128(cpi_ctx.clone(), ciphertext, 0)?;
// Add to existing balance
let new_balance = e_add(cpi_ctx, ctx.accounts.vault.balance, amount, 0)?;
ctx.accounts.vault.balance = new_balance;
Ok(())
}
}
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut)]
pub authority: Signer<'info>,
#[account(mut)]
pub vault: Account<'info, Vault>,
/// CHECK: Inco Lightning program
#[account(address = INCO_LIGHTNING_ID)]
pub inco_lightning_program: AccountInfo<'info>,
}
#[account]
pub struct Vault {
pub balance: Euint128,
}
基本客户端用法
import { encryptValue } from "@inco/solana-sdk/encryption";
import { decrypt } from "@inco/solana-sdk/attested-decrypt";
// Encrypt a value before sending to program
const encrypted = await encryptValue(1000n);
await program.methods
.deposit(Buffer.from(encrypted, "hex"))
.accounts({ authority: wallet.publicKey, vault: vaultPda, incoLightningProgram: INCO_LIGHTNING_ID })
.rpc();
// Decrypt a handle (requires wallet signature)
const result = await decrypt([handleString], {
address: wallet.publicKey,
signMessage: wallet.signMessage,
});
console.log("Decrypted:", result.plaintexts[0]);
加密类型与句柄
句柄是对存储在共验证器网络中的加密值的 128 位引用。
| 类型 | 描述 | Rust 定义 |
|---|---|---|
Euint128 | 加密的无符号 128 位整数 | pub struct Euint128(pub u128) |
Ebool | 加密的布尔值 | pub struct Ebool(pub u128) |
将句柄直接存储在账户结构体中:
#[account]
pub struct ConfidentialAccount {
pub balance: Euint128,
pub is_active: Ebool,
}
输入函数
| 函数 | 描述 |
|---|---|
new_euint128(ctx, ciphertext, input_type) | 从客户端加密的密文创建 |
new_ebool(ctx, ciphertext, input_type) | 从密文创建加密布尔值 |
as_euint128(ctx, value) | 对明文 u128 进行简单加密(用于零等常量) |
as_ebool(ctx, value) | 对明文布尔值进行简单加密 |
加密数据上的运算
所有运算都需要 CPI 上下文,并返回新的句柄。
let cpi_ctx = CpiContext::new(
ctx.accounts.inco_lightning_program.to_account_info(),
Operation { signer: ctx.accounts.authority.to_account_info() },
);
let result = e_add(cpi_ctx, a, b, 0)?;
最后一个参数(scalar_byte)在加密值与加密值运算时为 0,在左操作数为明文时为 1。
算术运算 → Euint128
e_add、e_sub、e_mul、e_rem
比较运算 → Ebool
e_ge、e_gt、e_le、e_lt、e_eq
位运算 → Euint128
e_and、e_or、e_not、e_shl、e_shr
控制流(多路复用器)
// Cannot use if/else on encrypted values — use e_select instead
let result = e_select(cpi_ctx, condition, if_true, if_false, 0)?;
随机数生成
let random_value = e_rand(cpi_ctx, 0)?;
完整 API 参见 resources/rust-sdk-reference.md。
访问控制
解密权限通过 Allowance PDA 管理,该 PDA 根据 [handle.to_le_bytes(), allowed_address] 派生。
use inco_lightning::cpi::accounts::Allow;
use inco_lightning::cpi::allow;
let cpi_ctx = CpiContext::new(
ctx.accounts.inco_lightning_program.to_account_info(),
Allow {
allowance_account: ctx.accounts.allowance_account.to_account_info(),
signer: ctx.accounts.authority.to_account_info(),
allowed_address: ctx.accounts.user.to_account_info(),
system_program: ctx.accounts.system_program.to_account_info(),
},
);
allow(cpi_ctx, handle.0, true, user_pubkey)?;
重要: 运算会产生新的句柄,Allowance PDA 取决于句柄值。你必须先模拟交易以获取结果句柄,再派生 PDA,随后使用 remaining_accounts 提交交易。
完整的“先模拟,再提交”流程参见 resources/access-control.md。
认证解密
两种模式:
| 模式 | 用途 | 返回值 |
|---|---|---|
| 认证揭示 | 在 UI 中显示值 | result.plaintexts |
| 认证解密 | 在链上验证值 | result.ed25519Instructions + 程序 IX |
import { decrypt } from "@inco/solana-sdk/attested-decrypt";
const result = await decrypt([handle], {
address: wallet.publicKey,
signMessage: wallet.signMessage,
});
// Reveal: use plaintext directly
console.log(result.plaintexts[0]);
// Decrypt: verify on-chain
const tx = new Transaction();
result.ed25519Instructions.forEach(ix => tx.add(ix));
tx.add(yourProgramVerifyInstruction);
await sendTransaction(tx);
链上验证:
use inco_lightning::cpi::is_validsignature;
use inco_lightning::cpi::accounts::VerifySignature;
let cpi_ctx = CpiContext::new(
ctx.accounts.inco_lightning_program.to_account_info(),
VerifySignature {
instructions: ctx.accounts.instructions.to_account_info(),
signer: ctx.accounts.authority.to_account_info(),
},
);
is_validsignature(cpi_ctx, 1, Some(handles), Some(plaintext_values))?;
机密 SPL Token
完整的隐私保护型代币实现。参见 resources/confidential-spl-token.md。
关键函数:initialize_mint、create_account、mint_to、transfer、approve
// Encrypt and transfer
const encrypted = await encryptValue(500_000_000n);
await program.methods
.transfer(Buffer.from(encrypted, "hex"), 0)
.accounts({ source: srcAta, destination: destAta, authority: wallet.publicKey })
.rpc();
最佳实践
- 执行操作后,始终调用
allow(),以便稍后解密生成的句柄 - 使用
remaining_accounts传递授权 PDA,并在同一笔交易中授予访问权限 - 仅授予最小权限——只允许特定地址解密其所需的内容
- 使用多路复用模式(
e_select),而不是对加密条件使用 if/else - 仅对常量使用简单加密(如零)——对敏感值使用客户端加密
- 在证明中验证预期的句柄,防止句柄替换攻击
- 先模拟交易,以获取结果句柄,然后再派生授权 PDA
资源
- Inco SVM 文档
- Rust SDK 参考
- JS SDK 参考
- 概念指南
- Confidential SPL Token
- Private Raffle 教程
- Next.js 模板仓库
- Lightning Rod Solana 仓库
技能结构
inco/
├── SKILL.md # This file — main reference
├── docs/
│ └── troubleshooting.md # Common issues and solutions
├── examples/
│ ├── basic-operations/
│ │ └── encrypted-operations.ts # Arithmetic, comparison, select
│ ├── confidential-spl-token/
│ │ ├── mint-and-transfer.ts # Mint & transfer confidential tokens
│ │ └── reveal-balance.ts # Decrypt and reveal token balance
│ └── private-raffle/
│ └── raffle-client.ts # Full raffle lifecycle client
├── resources/
│ ├── rust-sdk-reference.md # Complete Rust CPI API
│ ├── js-sdk-reference.md # JS SDK encryption & decryption
│ ├── access-control.md # Allowance PDAs & simulation pattern
│ └── confidential-spl-token.md # SPL token program reference
└── templates/
└── inco-svm-setup.ts # Starter template with helpers