ika-move
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseIka Move Integration
Ika Move集成指南
Build Sui Move contracts integrating Ika dWallet 2PC-MPC for programmable cross-chain signing.
构建集成Ika dWallet 2PC-MPC的Sui Move合约,实现可编程跨链签名。
References (detailed patterns and complete code)
参考资料(详细模式与完整代码)
- - All coordinator function signatures with full parameter lists
references/protocols-detailed.md - - Complete integration patterns: treasury, DAO governance, imported key wallet, presign pool, events, enums
references/patterns.md - - Full TypeScript SDK flows: DKG prep, signing, key import, polling, IkaTransaction API
references/typescript-integration.md
- - 包含完整参数列表的所有协调器函数签名
references/protocols-detailed.md - - 完整集成模式:金库、DAO治理、导入密钥钱包、预签名池、事件、枚举
references/patterns.md - - 完整TypeScript SDK流程:DKG准备、签名、密钥导入、轮询、IkaTransaction API
references/typescript-integration.md
Setup
环境搭建
Move.toml
Move.toml
toml
[package]
name = "my_project"
edition = "2024.beta"
[dependencies]
Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" }
ika_dwallet_2pc_mpc = { git = "https://github.com/dwallet-labs/ika.git", subdir = "deployed_contracts/testnet/ika_dwallet_2pc_mpc", rev = "main" }
ika = { git = "https://github.com/dwallet-labs/ika.git", subdir = "deployed_contracts/testnet/ika", rev = "main" }
[addresses]
my_project = "0x0"For mainnet: change to in paths.
testnetmainnettoml
[package]
name = "my_project"
edition = "2024.beta"
[dependencies]
Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" }
ika_dwallet_2pc_mpc = { git = "https://github.com/dwallet-labs/ika.git", subdir = "deployed_contracts/testnet/ika_dwallet_2pc_mpc", rev = "main" }
ika = { git = "https://github.com/dwallet-labs/ika.git", subdir = "deployed_contracts/testnet/ika", rev = "main" }
[addresses]
my_project = "0x0"主网配置:将路径中的替换为。
testnetmainnetTypeScript SDK
TypeScript SDK
bash
pnpm add @ika.xyz/sdktypescript
import { getNetworkConfig, IkaClient } from '@ika.xyz/sdk';
import { getJsonRpcFullnodeUrl, SuiJsonRpcClient } from '@mysten/sui/jsonRpc';
const suiClient = new SuiJsonRpcClient({ url: getJsonRpcFullnodeUrl('testnet'), network: 'testnet' });
const ikaClient = new IkaClient({ suiClient, config: getNetworkConfig('testnet'), cache: true });
await ikaClient.initialize();bash
pnpm add @ika.xyz/sdktypescript
import { getNetworkConfig, IkaClient } from '@ika.xyz/sdk';
import { getJsonRpcFullnodeUrl, SuiJsonRpcClient } from '@mysten/sui/jsonRpc';
const suiClient = new SuiJsonRpcClient({ url: getJsonRpcFullnodeUrl('testnet'), network: 'testnet' });
const ikaClient = new IkaClient({ suiClient, config: getNetworkConfig('testnet'), cache: true });
await ikaClient.initialize();Crypto Constants
加密常量
Curves
曲线类型
- = SECP256K1 (Bitcoin, Ethereum)
0 - = SECP256R1 (WebAuthn)
1 - = ED25519 (Solana, Substrate)
2 - = RISTRETTO (Privacy)
3
- = SECP256K1(比特币、以太坊)
0 - = SECP256R1(WebAuthn)
1 - = ED25519(Solana、Substrate)
2 - = RISTRETTO(隐私场景)
3
Signature Algorithms (relative to curve)
签名算法(与曲线对应)
- SECP256K1: =ECDSA,
0=Taproot1 - SECP256R1: =ECDSA
0 - ED25519: =EdDSA
0 - RISTRETTO: =Schnorrkel
0
- SECP256K1: =ECDSA,
0=Taproot1 - SECP256R1: =ECDSA
0 - ED25519: =EdDSA
0 - RISTRETTO: =Schnorrkel
0
Hash Schemes (relative to curve+algo)
哈希方案(与曲线+算法对应)
- SECP256K1+ECDSA: =KECCAK256(Ethereum),
0=SHA256,1=DoubleSHA256(Bitcoin)2 - SECP256K1+Taproot: =SHA256
0 - SECP256R1+ECDSA: =SHA256
0 - ED25519+EdDSA: =SHA512
0 - RISTRETTO+Schnorrkel: =Merlin
0
- SECP256K1+ECDSA: =KECCAK256(以太坊),
0=SHA256,1=DoubleSHA256(比特币)2 - SECP256K1+Taproot: =SHA256
0 - SECP256R1+ECDSA: =SHA256
0 - ED25519+EdDSA: =SHA512
0 - RISTRETTO+Schnorrkel: =Merlin
0
Core Imports
核心导入
rust
use ika::ika::IKA;
use ika_dwallet_2pc_mpc::{
coordinator::DWalletCoordinator,
coordinator_inner::{
DWalletCap, ImportedKeyDWalletCap,
UnverifiedPresignCap, VerifiedPresignCap,
UnverifiedPartialUserSignatureCap, VerifiedPartialUserSignatureCap,
MessageApproval, ImportedKeyMessageApproval
},
sessions_manager::SessionIdentifier
};
use sui::{balance::Balance, coin::Coin, sui::SUI};rust
use ika::ika::IKA;
use ika_dwallet_2pc_mpc::{
coordinator::DWalletCoordinator,
coordinator_inner::{
DWalletCap, ImportedKeyDWalletCap,
UnverifiedPresignCap, VerifiedPresignCap,
UnverifiedPartialUserSignatureCap, VerifiedPartialUserSignatureCap,
MessageApproval, ImportedKeyMessageApproval
},
sessions_manager::SessionIdentifier
};
use sui::{balance::Balance, coin::Coin, sui::SUI};Contract Template
合约模板
rust
public struct MyContract has key, store {
id: UID,
dwallet_cap: DWalletCap,
presigns: vector<UnverifiedPresignCap>,
ika_balance: Balance<IKA>,
sui_balance: Balance<SUI>,
dwallet_network_encryption_key_id: ID,
}rust
public struct MyContract has key, store {
id: UID,
dwallet_cap: DWalletCap,
presigns: vector<UnverifiedPresignCap>,
ika_balance: Balance<IKA>,
sui_balance: Balance<SUI>,
dwallet_network_encryption_key_id: ID,
}Required Helpers
必备辅助函数
rust
fun random_session(coordinator: &mut DWalletCoordinator, ctx: &mut TxContext): SessionIdentifier {
coordinator.register_session_identifier(ctx.fresh_object_address().to_bytes(), ctx)
}
fun withdraw_payment_coins(self: &mut MyContract, ctx: &mut TxContext): (Coin<IKA>, Coin<SUI>) {
let ika = self.ika_balance.withdraw_all().into_coin(ctx);
let sui = self.sui_balance.withdraw_all().into_coin(ctx);
(ika, sui)
}
fun return_payment_coins(self: &mut MyContract, ika: Coin<IKA>, sui: Coin<SUI>) {
self.ika_balance.join(ika.into_balance());
self.sui_balance.join(sui.into_balance());
}
public fun add_ika_balance(self: &mut MyContract, coin: Coin<IKA>) {
self.ika_balance.join(coin.into_balance());
}
public fun add_sui_balance(self: &mut MyContract, coin: Coin<SUI>) {
self.sui_balance.join(coin.into_balance());
}rust
fun random_session(coordinator: &mut DWalletCoordinator, ctx: &mut TxContext): SessionIdentifier {
coordinator.register_session_identifier(ctx.fresh_object_address().to_bytes(), ctx)
}
fun withdraw_payment_coins(self: &mut MyContract, ctx: &mut TxContext): (Coin<IKA>, Coin<SUI>) {
let ika = self.ika_balance.withdraw_all().into_coin(ctx);
let sui = self.sui_balance.withdraw_all().into_coin(ctx);
(ika, sui)
}
fun return_payment_coins(self: &mut MyContract, ika: Coin<IKA>, sui: Coin<SUI>) {
self.ika_balance.join(ika.into_balance());
self.sui_balance.join(sui.into_balance());
}
public fun add_ika_balance(self: &mut MyContract, coin: Coin<IKA>) {
self.ika_balance.join(coin.into_balance());
}
public fun add_sui_balance(self: &mut MyContract, coin: Coin<SUI>) {
self.sui_balance.join(coin.into_balance());
}DWalletCoordinator
DWalletCoordinator
Central shared object for all operations. Pass as for mutations, for reads.
&mut DWalletCoordinator&DWalletCoordinatorGet ID in TypeScript:
ikaClient.ikaConfig.objects.ikaDWalletCoordinator.objectID所有操作的核心共享对象。变更操作传入,只读操作传入。
&mut DWalletCoordinator&DWalletCoordinator在TypeScript中获取ID:
ikaClient.ikaConfig.objects.ikaDWalletCoordinator.objectIDCapabilities
权限能力(Capabilities)
| Capability | Purpose | Created By |
|---|---|---|
| Authorize signing | DKG |
| Authorize imported key signing | Import verification |
| Presign reference (needs verify) | Presign request |
| Ready for signing | |
| Partial sig (needs verify) | Future sign |
| Ready for completion | |
| Auth to sign specific message | |
| Auth for imported keys | |
| 权限能力 | 用途 | 创建方式 |
|---|---|---|
| 授权签名 | DKG流程 |
| 授权导入密钥签名 | 导入验证流程 |
| 预签名引用(需验证) | 预签名请求 |
| 可用于签名 | |
| 部分签名(需验证) | 未来签名流程 |
| 可完成签名 | |
| 授权签署特定消息 | |
| 导入密钥的授权 | |
SessionIdentifier
SessionIdentifier
Every protocol op needs a unique . Create via:
SessionIdentifierrust
let session = coordinator.register_session_identifier(ctx.fresh_object_address().to_bytes(), ctx);Rules: create just before use, never reuse, one per operation.
每个协议操作都需要唯一的,创建方式:
SessionIdentifierrust
let session = coordinator.register_session_identifier(ctx.fresh_object_address().to_bytes(), ctx);规则:使用前创建,绝不重复使用,每个操作对应一个。
Payment Pattern
支付模式
All ops require IKA+SUI fees. Pattern: withdraw all -> perform ops (fees auto-deducted from ) -> return remainder.
&mut Coin所有操作都需要支付IKA+SUI费用。模式:取出全部费用 -> 执行操作(费用自动从中扣除) -> 返回剩余费用。
&mut CoinProtocol: DKG (Create dWallet)
协议:DKG(创建dWallet)
Shared dWallet (recommended for contracts)
共享dWallet(合约场景推荐)
Public user share, network signs without user interaction.
rust
let (dwallet_cap, _) = coordinator.request_dwallet_dkg_with_public_user_secret_key_share(
dwallet_network_encryption_key_id, curve,
centralized_public_key_share_and_proof, user_public_output, public_user_secret_key_share,
option::none(), // sign_during_dkg_request
session, &mut ika, &mut sui, ctx,
);用户密钥份额公开,无需用户交互即可由网络完成签名。
rust
let (dwallet_cap, _) = coordinator.request_dwallet_dkg_with_public_user_secret_key_share(
dwallet_network_encryption_key_id, curve,
centralized_public_key_share_and_proof, user_public_output, public_user_secret_key_share,
option::none(), // sign_during_dkg_request
session, &mut ika, &mut sui, ctx,
);Zero-Trust dWallet
零信任dWallet
Encrypted user share, user must participate in every signature.
rust
let (dwallet_cap, _) = coordinator.request_dwallet_dkg(
dwallet_network_encryption_key_id, curve,
centralized_public_key_share_and_proof, encrypted_centralized_secret_share_and_proof,
encryption_key_address, user_public_output, signer_public_key,
option::none(), session, &mut ika, &mut sui, ctx,
);Important: After zero-trust DKG (or key import), the dWallet is in state. The user must call to transition the dWallet to state before it can be used for signing:
AwaitingKeyHolderSignatureacceptEncryptedUserShareActivetypescript
// Wait for DKG to complete and dWallet to reach AwaitingKeyHolderSignature state
const awaitingDWallet = await ikaClient.getDWalletInParticularState(dwalletId, 'AwaitingKeyHolderSignature');
// The encrypted user secret key share ID comes from the DKG transaction event,
// NOT from the dWallet ID.
const encryptedShare = await ikaClient.getEncryptedUserSecretKeyShare(encryptedUserSecretKeyShareId);
const tx = new Transaction();
const ikaTx = new IkaTransaction({ ikaClient, transaction: tx, userShareEncryptionKeys: keys });
await ikaTx.acceptEncryptedUserShare({
dWallet: awaitingDWallet,
encryptedUserSecretKeyShareId: encryptedShare.id,
userPublicOutput: new Uint8Array(dkgData.userPublicOutput),
});
await suiClient.core.signAndExecuteTransaction({ transaction: tx, signer: keypair });
// dWallet is now Active and ready for signing
const activeDWallet = await ikaClient.getDWalletInParticularState(dwalletId, 'Active');This step is NOT needed for shared dWallets (created with ).
request_dwallet_dkg_with_public_user_secret_key_share用户密钥份额加密,每次签名都需要用户参与。
rust
let (dwallet_cap, _) = coordinator.request_dwallet_dkg(
dwallet_network_encryption_key_id, curve,
centralized_public_key_share_and_proof, encrypted_centralized_secret_share_and_proof,
encryption_key_address, user_public_output, signer_public_key,
option::none(), session, &mut ika, &mut sui, ctx,
);重要提示: 零信任DKG(或密钥导入)完成后,dWallet处于状态。用户必须调用将dWallet切换到状态后才能用于签名:
AwaitingKeyHolderSignatureacceptEncryptedUserShareActivetypescript
// 等待DKG完成,dWallet进入AwaitingKeyHolderSignature状态
const awaitingDWallet = await ikaClient.getDWalletInParticularState(dwalletId, 'AwaitingKeyHolderSignature');
// 加密的用户密钥份额ID来自DKG交易事件,而非dWallet ID
const encryptedShare = await ikaClient.getEncryptedUserSecretKeyShare(encryptedUserSecretKeyShareId);
const tx = new Transaction();
const ikaTx = new IkaTransaction({ ikaClient, transaction: tx, userShareEncryptionKeys: keys });
await ikaTx.acceptEncryptedUserShare({
dWallet: awaitingDWallet,
encryptedUserSecretKeyShareId: encryptedShare.id,
userPublicOutput: new Uint8Array(dkgData.userPublicOutput),
});
await suiClient.core.signAndExecuteTransaction({ transaction: tx, signer: keypair });
// dWallet现在处于Active状态,可用于签名
const activeDWallet = await ikaClient.getDWalletInParticularState(dwalletId, 'Active');共享dWallet(通过创建)无需此步骤。
request_dwallet_dkg_with_public_user_secret_key_shareTypeScript DKG Prep
TypeScript DKG准备流程
typescript
import { prepareDKGAsync, UserShareEncryptionKeys, Curve, createRandomSessionIdentifier } from '@ika.xyz/sdk';
const keys = await UserShareEncryptionKeys.fromRootSeedKey(seed, Curve.SECP256K1);
const bytesToHash = createRandomSessionIdentifier(); // bytes hashed to derive the session identifier
const dkgData = await prepareDKGAsync(ikaClient, Curve.SECP256K1, keys, bytesToHash, signerAddress);
const networkKey = await ikaClient.getLatestNetworkEncryptionKey();
// dkgData has: userDKGMessage, userPublicOutput, encryptedUserShareAndProof, userSecretKeySharetypescript
import { prepareDKGAsync, UserShareEncryptionKeys, Curve, createRandomSessionIdentifier } from '@ika.xyz/sdk';
const keys = await UserShareEncryptionKeys.fromRootSeedKey(seed, Curve.SECP256K1);
const bytesToHash = createRandomSessionIdentifier(); // 用于派生session identifier的字节数据
const dkgData = await prepareDKGAsync(ikaClient, Curve.SECP256K1, keys, bytesToHash, signerAddress);
const networkKey = await ikaClient.getLatestNetworkEncryptionKey();
// dkgData包含:userDKGMessage, userPublicOutput, encryptedUserShareAndProof, userSecretKeyShareSign During DKG (optional)
DKG期间签名(可选)
Pass existing presign to get signature during DKG:
rust
let sign_req = coordinator.sign_during_dkg_request(verified_presign, hash_scheme, message, msg_sig);
// Pass option::some(sign_req) instead of option::none() in DKG call传入已有的预签名,在DKG流程中同时获取签名:
rust
let sign_req = coordinator.sign_during_dkg_request(verified_presign, hash_scheme, message, msg_sig);
// 在DKG调用中传入option::some(sign_req)替代option::none()Protocol: Presigning
协议:预签名
Each signature consumes one presign. Manage a pool.
每个签名会消耗一个预签名,建议维护预签名池。
Global Presign (most common: Taproot, EdDSA, Schnorr, ECDSA)
全局预签名(最常用:Taproot、EdDSA、Schnorr、ECDSA)
rust
let cap = coordinator.request_global_presign(
dwallet_network_encryption_key_id, curve, signature_algorithm,
session, &mut ika, &mut sui, ctx,
);
self.presigns.push_back(cap);rust
let cap = coordinator.request_global_presign(
dwallet_network_encryption_key_id, curve, signature_algorithm,
session, &mut ika, &mut sui, ctx,
);
self.presigns.push_back(cap);dWallet-Specific Presign (ECDSA with imported keys)
特定dWallet预签名(导入密钥的ECDSA场景)
rust
let cap = coordinator.request_presign(
dwallet_id, signature_algorithm, session, &mut ika, &mut sui, ctx,
);rust
let cap = coordinator.request_presign(
dwallet_id, signature_algorithm, session, &mut ika, &mut sui, ctx,
);Verify Before Use
使用前验证
rust
let is_ready = coordinator.is_presign_valid(&unverified_cap);
let verified = coordinator.verify_presign_cap(unverified_cap, ctx); // fails if not readyrust
let is_ready = coordinator.is_presign_valid(&unverified_cap);
let verified = coordinator.verify_presign_cap(unverified_cap, ctx); // 验证失败则报错Pool Management
预签名池管理
rust
// Pop from pool
let unverified = self.presigns.swap_remove(0);
// Auto-replenish after signing
if (self.presigns.length() < MIN_POOL) {
let s = random_session(coordinator, ctx);
self.presigns.push_back(coordinator.request_global_presign(
self.dwallet_network_encryption_key_id, curve, sig_algo, s, &mut ika, &mut sui, ctx,
));
};
// Batch add
let mut i = 0;
while (i < count) {
let s = random_session(coordinator, ctx);
self.presigns.push_back(coordinator.request_global_presign(..., s, &mut ika, &mut sui, ctx));
i = i + 1;
};rust
// 从池中取出
let unverified = self.presigns.swap_remove(0);
// 签名后自动补充
if (self.presigns.length() < MIN_POOL) {
let s = random_session(coordinator, ctx);
self.presigns.push_back(coordinator.request_global_presign(
self.dwallet_network_encryption_key_id, curve, sig_algo, s, &mut ika, &mut sui, ctx,
));
};
// 批量添加
let mut i = 0;
while (i < count) {
let s = random_session(coordinator, ctx);
self.presigns.push_back(coordinator.request_global_presign(..., s, &mut ika, &mut sui, ctx));
i = i + 1;
};Protocol: Direct Signing
协议:直接签名
Single-phase, immediate signature. Use when no governance needed.
rust
// 1. Verify presign
let verified = coordinator.verify_presign_cap(self.presigns.swap_remove(0), ctx);
// 2. Approve message
let approval = coordinator.approve_message(&self.dwallet_cap, sig_algo, hash_scheme, message);
// 3. Sign
let sign_id = coordinator.request_sign_and_return_id(
verified, approval, message_centralized_signature, session, &mut ika, &mut sui, ctx,
);
// Also: coordinator.request_sign(...) without return ID单阶段、即时签名,适用于无需治理的场景。
rust
// 1. 验证预签名
let verified = coordinator.verify_presign_cap(self.presigns.swap_remove(0), ctx);
// 2. 授权消息
let approval = coordinator.approve_message(&self.dwallet_cap, sig_algo, hash_scheme, message);
// 3. 签名
let sign_id = coordinator.request_sign_and_return_id(
verified, approval, message_centralized_signature, session, &mut ika, &mut sui, ctx,
);
// 也可使用:coordinator.request_sign(...) 不返回IDTypeScript: Create User Signature
TypeScript:创建用户签名
typescript
import { createUserSignMessageWithPublicOutput, Curve, SignatureAlgorithm, Hash } from '@ika.xyz/sdk';
const completedPresign = await ikaClient.getPresignInParticularState(presignId, 'Completed');
const protocolPublicParameters = await ikaClient.getProtocolPublicParameters(undefined, Curve.SECP256K1);
const msgSig = await createUserSignMessageWithPublicOutput(
protocolPublicParameters,
dWallet.state.Active!.public_output,
dWallet.public_user_secret_key_share,
completedPresign.presign,
message,
Hash.SHA256,
SignatureAlgorithm.Taproot,
Curve.SECP256K1,
);
// Pass msgSig as message_centralized_signature to Movetypescript
import { createUserSignMessageWithPublicOutput, Curve, SignatureAlgorithm, Hash } from '@ika.xyz/sdk';
const completedPresign = await ikaClient.getPresignInParticularState(presignId, 'Completed');
const protocolPublicParameters = await ikaClient.getProtocolPublicParameters(undefined, Curve.SECP256K1);
const msgSig = await createUserSignMessageWithPublicOutput(
protocolPublicParameters,
dWallet.state.Active!.public_output,
dWallet.public_user_secret_key_share,
completedPresign.presign,
message,
Hash.SHA256,
SignatureAlgorithm.Taproot,
Curve.SECP256K1,
);
// 将msgSig作为message_centralized_signature传入Move合约Retrieve Signature
获取签名
typescript
const signSession = await ikaClient.getSignInParticularState(
signId, Curve.SECP256K1, SignatureAlgorithm.Taproot, 'Completed',
);
const sig = await parseSignatureFromSignOutput(Curve.SECP256K1, SignatureAlgorithm.Taproot, signSession.signature);typescript
const signSession = await ikaClient.getSignInParticularState(
signId, Curve.SECP256K1, SignatureAlgorithm.Taproot, 'Completed',
);
const sig = await parseSignatureFromSignOutput(Curve.SECP256K1, SignatureAlgorithm.Taproot, signSession.signature);Protocol: Future Signing (Two-Phase)
协议:未来签名(两阶段)
Separates commitment from execution. For governance/multisig/delayed signing.
将承诺与执行分离,适用于治理/多签/延迟签名场景。
Phase 1: Create Partial Signature
阶段1:创建部分签名
rust
let partial_cap = coordinator.request_future_sign(
self.dwallet_cap.dwallet_id(), verified_presign, message, hash_scheme,
message_centralized_signature, session, &mut ika, &mut sui, ctx,
);
// Store partial_cap with request for laterrust
let partial_cap = coordinator.request_future_sign(
self.dwallet_cap.dwallet_id(), verified_presign, message, hash_scheme,
message_centralized_signature, session, &mut ika, &mut sui, ctx,
);
// 将partial_cap与请求一起存储,留待后续使用Phase 2: Complete After Approval
阶段2:审批完成后执行
rust
// Verify partial sig
let verified_partial = coordinator.verify_partial_user_signature_cap(partial_cap, ctx);
// Create approval
let approval = coordinator.approve_message(&self.dwallet_cap, sig_algo, hash_scheme, message);
// Complete signature
let sign_id = coordinator.request_sign_with_partial_user_signature_and_return_id(
verified_partial, approval, session, &mut ika, &mut sui, ctx,
);rust
// 验证部分签名
let verified_partial = coordinator.verify_partial_user_signature_cap(partial_cap, ctx);
// 创建授权
let approval = coordinator.approve_message(&self.dwallet_cap, sig_algo, hash_scheme, message);
// 完成签名
let sign_id = coordinator.request_sign_with_partial_user_signature_and_return_id(
verified_partial, approval, session, &mut ika, &mut sui, ctx,
);Check/Match
检查/匹配
rust
let ready = coordinator.is_partial_user_signature_valid(&unverified_cap);
let matches = coordinator.match_partial_user_signature_with_message_approval(&verified, &approval);rust
let ready = coordinator.is_partial_user_signature_valid(&unverified_cap);
let matches = coordinator.match_partial_user_signature_with_message_approval(&verified, &approval);Protocol: Key Importing
协议:密钥导入
Import existing private key into dWallet system. Returns .
ImportedKeyDWalletCaprust
let imported_cap = coordinator.request_imported_key_dwallet_verification(
dwallet_network_encryption_key_id, curve, centralized_party_message,
encrypted_centralized_secret_share_and_proof, encryption_key_address,
user_public_output, signer_public_key, session, &mut ika, &mut sui, ctx,
);将现有私钥导入dWallet系统,返回。
ImportedKeyDWalletCaprust
let imported_cap = coordinator.request_imported_key_dwallet_verification(
dwallet_network_encryption_key_id, curve, centralized_party_message,
encrypted_centralized_secret_share_and_proof, encryption_key_address,
user_public_output, signer_public_key, session, &mut ika, &mut sui, ctx,
);Imported Key Differences
导入密钥的差异
- Use instead of
ImportedKeyDWalletCapDWalletCap - Use instead of
coordinator.approve_imported_key_message(...)approve_message - Use for signing
coordinator.request_imported_key_sign_and_return_id(...) - Use for ECDSA presigns (dWallet-specific)
coordinator.request_presign(dwallet_id, ...) - Future sign completion:
request_imported_key_sign_with_partial_user_signature_and_return_id
- 使用替代
ImportedKeyDWalletCapDWalletCap - 使用替代
coordinator.approve_imported_key_message(...)approve_message - 使用进行签名
coordinator.request_imported_key_sign_and_return_id(...) - 预签名使用(仅适用于ECDSA的特定dWallet场景)
coordinator.request_presign(dwallet_id, ...) - 未来签名完成使用:
request_imported_key_sign_with_partial_user_signature_and_return_id
Protocol: Convert Zero-Trust to Shared
协议:零信任转共享dWallet
Irreversible. Makes user secret key share public, enabling contract-owned signing.
rust
coordinator.request_make_dwallet_user_secret_key_shares_public(
dwallet_id, public_user_secret_key_shares, session, &mut ika, &mut sui, ctx,
);TypeScript: save during DKG for potential later conversion.
dkgData.userSecretKeyShare不可逆操作,将用户密钥份额公开,支持合约自主签名。
rust
coordinator.request_make_dwallet_user_secret_key_shares_public(
dwallet_id, public_user_secret_key_shares, session, &mut ika, &mut sui, ctx,
);TypeScript提示:DKG期间保存,以备后续转换使用。
dkgData.userSecretKeyShareComplete Example: Bitcoin Taproot Treasury
完整示例:比特币Taproot金库
rust
module my_protocol::treasury;
use ika::ika::IKA;
use ika_dwallet_2pc_mpc::{
coordinator::DWalletCoordinator,
coordinator_inner::{DWalletCap, UnverifiedPresignCap, UnverifiedPartialUserSignatureCap}
};
use sui::{balance::Balance, coin::Coin, sui::SUI, table::{Self, Table}};
const SECP256K1: u32 = 0;
const TAPROOT: u32 = 1;
const SHA256: u32 = 0;
const MIN_PRESIGNS: u64 = 3;
public struct Treasury has key, store {
id: UID,
dwallet_cap: DWalletCap,
presigns: vector<UnverifiedPresignCap>,
members: vector<address>,
approval_threshold: u64,
proposals: Table<u64, Proposal>,
next_id: u64,
ika_balance: Balance<IKA>,
sui_balance: Balance<SUI>,
dwallet_network_encryption_key_id: ID,
}
public struct Proposal has store {
message: vector<u8>,
partial_cap: Option<UnverifiedPartialUserSignatureCap>,
approvals: u64,
voters: Table<address, bool>,
executed: bool,
}
// Create treasury with shared dWallet
public fun create(
coordinator: &mut DWalletCoordinator,
mut ika: Coin<IKA>, mut sui: Coin<SUI>,
enc_key_id: ID,
dkg_msg: vector<u8>, user_output: vector<u8>, user_share: vector<u8>,
session_bytes: vector<u8>,
members: vector<address>, threshold: u64,
ctx: &mut TxContext,
) {
let session = coordinator.register_session_identifier(session_bytes, ctx);
let (dwallet_cap, _) = coordinator.request_dwallet_dkg_with_public_user_secret_key_share(
enc_key_id, SECP256K1, dkg_msg, user_output, user_share,
option::none(), session, &mut ika, &mut sui, ctx,
);
let treasury = Treasury {
id: object::new(ctx), dwallet_cap, presigns: vector::empty(),
members, approval_threshold: threshold,
proposals: table::new(ctx), next_id: 0,
ika_balance: ika.into_balance(), sui_balance: sui.into_balance(),
dwallet_network_encryption_key_id: enc_key_id,
};
transfer::public_share_object(treasury);
}
// Create proposal with future sign (Phase 1)
public fun propose(
self: &mut Treasury, coordinator: &mut DWalletCoordinator,
message: vector<u8>, msg_sig: vector<u8>, ctx: &mut TxContext,
): u64 {
assert!(self.members.contains(&ctx.sender()), 0);
let (mut ika, mut sui) = self.withdraw_payment_coins(ctx);
let verified = coordinator.verify_presign_cap(self.presigns.swap_remove(0), ctx);
let session = random_session(coordinator, ctx);
let partial = coordinator.request_future_sign(
self.dwallet_cap.dwallet_id(), verified, message, SHA256,
msg_sig, session, &mut ika, &mut sui, ctx,
);
let id = self.next_id;
self.next_id = id + 1;
self.proposals.add(id, Proposal {
message, partial_cap: option::some(partial),
approvals: 0, voters: table::new(ctx), executed: false,
});
// Auto-replenish
if (self.presigns.length() < MIN_PRESIGNS) {
let s = random_session(coordinator, ctx);
self.presigns.push_back(coordinator.request_global_presign(
self.dwallet_network_encryption_key_id, SECP256K1, TAPROOT, s,
&mut ika, &mut sui, ctx,
));
};
self.return_payment_coins(ika, sui);
id
}
// Vote
public fun vote(self: &mut Treasury, id: u64, approve: bool, ctx: &TxContext) {
assert!(self.members.contains(&ctx.sender()), 0);
let p = self.proposals.borrow_mut(id);
assert!(!p.voters.contains(ctx.sender()) && !p.executed, 1);
p.voters.add(ctx.sender(), approve);
if (approve) { p.approvals = p.approvals + 1; };
}
// Execute after approval (Phase 2)
public fun execute(
self: &mut Treasury, coordinator: &mut DWalletCoordinator,
id: u64, ctx: &mut TxContext,
): ID {
let p = self.proposals.borrow_mut(id);
assert!(p.approvals >= self.approval_threshold && !p.executed, 2);
let (mut ika, mut sui) = self.withdraw_payment_coins(ctx);
let verified = coordinator.verify_partial_user_signature_cap(p.partial_cap.extract(), ctx);
let approval = coordinator.approve_message(&self.dwallet_cap, TAPROOT, SHA256, p.message);
let session = random_session(coordinator, ctx);
let sign_id = coordinator.request_sign_with_partial_user_signature_and_return_id(
verified, approval, session, &mut ika, &mut sui, ctx,
);
p.executed = true;
self.return_payment_coins(ika, sui);
sign_id
}
fun random_session(c: &mut DWalletCoordinator, ctx: &mut TxContext): SessionIdentifier {
c.register_session_identifier(ctx.fresh_object_address().to_bytes(), ctx)
}
fun withdraw_payment_coins(self: &mut Treasury, ctx: &mut TxContext): (Coin<IKA>, Coin<SUI>) {
(self.ika_balance.withdraw_all().into_coin(ctx), self.sui_balance.withdraw_all().into_coin(ctx))
}
fun return_payment_coins(self: &mut Treasury, ika: Coin<IKA>, sui: Coin<SUI>) {
self.ika_balance.join(ika.into_balance());
self.sui_balance.join(sui.into_balance());
}rust
module my_protocol::treasury;
use ika::ika::IKA;
use ika_dwallet_2pc_mpc::{
coordinator::DWalletCoordinator,
coordinator_inner::{DWalletCap, UnverifiedPresignCap, UnverifiedPartialUserSignatureCap}
};
use sui::{balance::Balance, coin::Coin, sui::SUI, table::{Self, Table}};
const SECP256K1: u32 = 0;
const TAPROOT: u32 = 1;
const SHA256: u32 = 0;
const MIN_PRESIGNS: u64 = 3;
public struct Treasury has key, store {
id: UID,
dwallet_cap: DWalletCap,
presigns: vector<UnverifiedPresignCap>,
members: vector<address>,
approval_threshold: u64,
proposals: Table<u64, Proposal>,
next_id: u64,
ika_balance: Balance<IKA>,
sui_balance: Balance<SUI>,
dwallet_network_encryption_key_id: ID,
}
public struct Proposal has store {
message: vector<u8>,
partial_cap: Option<UnverifiedPartialUserSignatureCap>,
approvals: u64,
voters: Table<address, bool>,
executed: bool,
}
// 创建带共享dWallet的金库
public fun create(
coordinator: &mut DWalletCoordinator,
mut ika: Coin<IKA>, mut sui: Coin<SUI>,
enc_key_id: ID,
dkg_msg: vector<u8>, user_output: vector<u8>, user_share: vector<u8>,
session_bytes: vector<u8>,
members: vector<address>, threshold: u64,
ctx: &mut TxContext,
) {
let session = coordinator.register_session_identifier(session_bytes, ctx);
let (dwallet_cap, _) = coordinator.request_dwallet_dkg_with_public_user_secret_key_share(
enc_key_id, SECP256K1, dkg_msg, user_output, user_share,
option::none(), session, &mut ika, &mut sui, ctx,
);
let treasury = Treasury {
id: object::new(ctx), dwallet_cap, presigns: vector::empty(),
members, approval_threshold: threshold,
proposals: table::new(ctx), next_id: 0,
ika_balance: ika.into_balance(), sui_balance: sui.into_balance(),
dwallet_network_encryption_key_id: enc_key_id,
};
transfer::public_share_object(treasury);
}
// 创建未来签名提案(阶段1)
public fun propose(
self: &mut Treasury, coordinator: &mut DWalletCoordinator,
message: vector<u8>, msg_sig: vector<u8>, ctx: &mut TxContext,
): u64 {
assert!(self.members.contains(&ctx.sender()), 0);
let (mut ika, mut sui) = self.withdraw_payment_coins(ctx);
let verified = coordinator.verify_presign_cap(self.presigns.swap_remove(0), ctx);
let session = random_session(coordinator, ctx);
let partial = coordinator.request_future_sign(
self.dwallet_cap.dwallet_id(), verified, message, SHA256,
msg_sig, session, &mut ika, &mut sui, ctx,
);
let id = self.next_id;
self.next_id = id + 1;
self.proposals.add(id, Proposal {
message, partial_cap: option::some(partial),
approvals: 0, voters: table::new(ctx), executed: false,
});
// 自动补充预签名
if (self.presigns.length() < MIN_PRESIGNS) {
let s = random_session(coordinator, ctx);
self.presigns.push_back(coordinator.request_global_presign(
self.dwallet_network_encryption_key_id, SECP256K1, TAPROOT, s,
&mut ika, &mut sui, ctx,
));
};
self.return_payment_coins(ika, sui);
id
}
// 投票
public fun vote(self: &mut Treasury, id: u64, approve: bool, ctx: &TxContext) {
assert!(self.members.contains(&ctx.sender()), 0);
let p = self.proposals.borrow_mut(id);
assert!(!p.voters.contains(ctx.sender()) && !p.executed, 1);
p.voters.add(ctx.sender(), approve);
if (approve) { p.approvals = p.approvals + 1; };
}
// 审批通过后执行(阶段2)
public fun execute(
self: &mut Treasury, coordinator: &mut DWalletCoordinator,
id: u64, ctx: &mut TxContext,
): ID {
let p = self.proposals.borrow_mut(id);
assert!(p.approvals >= self.approval_threshold && !p.executed, 2);
let (mut ika, mut sui) = self.withdraw_payment_coins(ctx);
let verified = coordinator.verify_partial_user_signature_cap(p.partial_cap.extract(), ctx);
let approval = coordinator.approve_message(&self.dwallet_cap, TAPROOT, SHA256, p.message);
let session = random_session(coordinator, ctx);
let sign_id = coordinator.request_sign_with_partial_user_signature_and_return_id(
verified, approval, session, &mut ika, &mut sui, ctx,
);
p.executed = true;
self.return_payment_coins(ika, sui);
sign_id
}
fun random_session(c: &mut DWalletCoordinator, ctx: &mut TxContext): SessionIdentifier {
c.register_session_identifier(ctx.fresh_object_address().to_bytes(), ctx)
}
fun withdraw_payment_coins(self: &mut Treasury, ctx: &mut TxContext): (Coin<IKA>, Coin<SUI>) {
(self.ika_balance.withdraw_all().into_coin(ctx), self.sui_balance.withdraw_all().into_coin(ctx))
}
fun return_payment_coins(self: &mut Treasury, ika: Coin<IKA>, sui: Coin<SUI>) {
self.ika_balance.join(ika.into_balance());
self.sui_balance.join(sui.into_balance());
}TypeScript: Calling Move Functions
TypeScript:调用Move函数
typescript
const tx = new Transaction();
tx.moveCall({
target: `${PACKAGE_ID}::treasury::create`,
arguments: [
tx.object(coordinatorId),
tx.object(ikaCoinId),
tx.splitCoins(tx.gas, [1000000]),
tx.pure.id(networkKeyId),
tx.pure.vector('u8', Array.from(dkgData.userDKGMessage)),
tx.pure.vector('u8', Array.from(dkgData.userPublicOutput)),
tx.pure.vector('u8', Array.from(dkgData.userSecretKeyShare)),
tx.pure.vector('u8', Array.from(sessionIdentifier)),
tx.pure.vector('address', members),
tx.pure.u64(threshold),
],
});
await suiClient.core.signAndExecuteTransaction({ transaction: tx, signer: keypair });typescript
const tx = new Transaction();
tx.moveCall({
target: `${PACKAGE_ID}::treasury::create`,
arguments: [
tx.object(coordinatorId),
tx.object(ikaCoinId),
tx.splitCoins(tx.gas, [1000000]),
tx.pure.id(networkKeyId),
tx.pure.vector('u8', Array.from(dkgData.userDKGMessage)),
tx.pure.vector('u8', Array.from(dkgData.userPublicOutput)),
tx.pure.vector('u8', Array.from(dkgData.userSecretKeyShare)),
tx.pure.vector('u8', Array.from(sessionIdentifier)),
tx.pure.vector('address', members),
tx.pure.u64(threshold),
],
});
await suiClient.core.signAndExecuteTransaction({ transaction: tx, signer: keypair });Key Decision Points
关键决策点
- Shared vs Zero-Trust: Use shared for contract-owned signing (DAOs, treasuries, bots). Use zero-trust for user-held wallets.
- Direct vs Future Sign: Direct for immediate signing. Future for governance/multisig (two-phase).
- Global vs dWallet-Specific Presign: Global for most cases. dWallet-specific only for ECDSA with imported keys.
- DKG vs Import: DKG generates new distributed key (more secure). Import brings existing private key.
- 共享vs零信任dWallet:共享dWallet适用于合约自主签名场景(DAO、金库、机器人);零信任dWallet适用于用户自持钱包。
- 直接vs未来签名:直接签名适用于即时签名场景;未来签名适用于治理/多签场景(两阶段)。
- 全局vs特定dWallet预签名:全局预签名适用于大多数场景;特定dWallet预签名仅适用于导入密钥的ECDSA场景。
- DKGvs导入:DKG生成新的分布式密钥(更安全);导入用于接入现有私钥。
Constants Module Pattern (Bitcoin Taproot)
常量模块模式(比特币Taproot)
rust
module my_protocol::constants;
public macro fun curve(): u32 { 0 }
public macro fun signature_algorithm(): u32 { 1 }
public macro fun hash_scheme(): u32 { 0 }rust
module my_protocol::constants;
public macro fun curve(): u32 { 0 }
public macro fun signature_algorithm(): u32 { 1 }
public macro fun hash_scheme(): u32 { 0 }Chain-Specific Config Quick Reference
链特定配置速查
| Chain | Curve | Sig Algo | Hash |
|---|---|---|---|
| Bitcoin (Taproot) | 0 | 1 | 0 (SHA256) |
| Bitcoin (Legacy) | 0 | 0 | 2 (DoubleSHA256) |
| Ethereum | 0 | 0 | 0 (KECCAK256) |
| Solana | 2 | 0 | 0 (SHA512) |
| WebAuthn | 1 | 0 | 0 (SHA256) |
| Substrate | 3 | 0 | 0 (Merlin) |
| 链 | 曲线 | 签名算法 | 哈希 |
|---|---|---|---|
| 比特币(Taproot) | 0 | 1 | 0 (SHA256) |
| 比特币(Legacy) | 0 | 0 | 2 (DoubleSHA256) |
| 以太坊 | 0 | 0 | 0 (KECCAK256) |
| Solana | 2 | 0 | 0 (SHA512) |
| WebAuthn | 1 | 0 | 0 (SHA256) |
| Substrate | 3 | 0 | 0 (Merlin) |