zkLogin是Sui区块链上的原生功能,允许用户使用OAuth凭证(如Google账户)生成Sui地址并签署交易,而无需管理私钥或助记词。结合多重签名(Multisig)技术,可以创建更灵活、更安全的资产管理方案。本文将深入解析基于zkLogin的公钥多签钱包开发全流程。
zkLogin核心概念解析
什么是zkLogin?
zkLogin是Sui的原语(primitive),使用户能够通过OAuth凭证从Sui地址发送交易,同时通过零知识证明技术保护用户隐私,避免公开关联OAuth身份与链上地址。
zkLogin的设计目标
- 简化入门流程:使用熟悉的OAuth登录流程,避免记忆私钥或助记词
- 自我托管:交易需用户批准,OAuth提供商无法代表用户操作
- 增强安全性:采用双因子认证方案,同时需要OAuth凭证和用户盐值
- 隐私保护:零知识证明防止第三方将Sui地址与OAuth标识关联
- 灵活集成:与其他Sui原语(如赞助交易和多重签名)无缝协作
zkLogin多签钱包开发实战
环境准备与配置
开发zkLogin多签钱包需要配置以下环境要素:
- Sui TypeScript SDK
- OAuth提供商配置(如Google Cloud Console)
- 临时密钥对生成机制
- JWT处理库
- 零知识证明服务连接
多签钱包创建流程
获取JWT凭证
通过OAuth流程获取三个Google账户的JWT凭证:
// 创建临时密钥对和随机数
const ekp1 = createEphemeralKeyPair("SK1");
const jwtRandomness1 = createJWTRandomness("JWT_RANDOMNESS1");
// 生成OAuth认证URL
async function getOAuthURL(epk: Ed25519PublicKey, jwtRandomness: string) {
const { epoch } = await SUI_CLIENT.getLatestSuiSystemState();
const maxEpoch = Number(epoch) + 2;
const nonce = generateNonce(epk, maxEpoch, jwtRandomness);
const params = new URLSearchParams({
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URL,
response_type: "id_token",
scope: "openid email",
nonce: nonce,
});
return `${OPENID_AUTHORIZATION_ENDPOINT}?${params.toString()}`;
}构建多签钱包
创建权重分别为1、1、2,阈值为2的多签方案:
function createMultisigAddressWithZKLogin(): MultiSigPublicKey {
const multiSigPublicKey = MultiSigPublicKey.fromPublicKeys({
threshold: 2,
publicKeys: [
{
publicKey: getZkLoginPk(JWT1, "1001"),
weight: 1,
},
{
publicKey: getZkLoginPk(JWT2, "1002"),
weight: 1,
},
{
publicKey: getZkLoginPk(JWT3, "1003"),
weight: 2,
},
],
});
return multiSigPublicKey;
}零知识证明获取
从证明服务获取zkLogin签名所需的零知识证明:
async function getPartialZkLoginSignature(
keyPair: Ed25519Keypair,
jwt: string,
jwtRandomness: string,
userSalt: string
) {
const extendedEphemeralPublicKey = getExtendedEphemeralPublicKey(
keyPair.getPublicKey()
);
const verificationPayload = {
jwt: jwt,
extendedEphemeralPublicKey,
maxEpoch: process.env.MAX_EPOCH as string,
jwtRandomness: jwtRandomness,
salt: userSalt,
keyClaimName: "sub",
};
return await verifyPartialZkLoginSignature(verificationPayload);
}多签交易执行
场景一:单签名未达阈值
用户1(权重1)单独签名,因未达到阈值2而失败:
const userSignature1 = (await ekp1.signTransaction(txBytes)).signature;
const zkLoginSignature1 = await generateZkLoginSignature(
partialZkLoginSignature1,
"1001",
JWT1,
userSignature1
);
// 错误:Signature is not valid: Insufficient weight=1 threshold=2场景二:双签名达到阈值
用户1和用户2(权重各1)联合签名,达到阈值2:
const combinedSignature = multiSigPublicKey.combinePartialSignatures([
zkLoginSignature1,
zkLoginSignature2,
]);
// 交易成功执行场景三:高权重单签名
用户3(权重2)单独签名,达到阈值2:
const combinedSignature = multiSigPublicKey.combinePartialSignatures([
zkLoginSignature3,
]);
// 交易成功执行最佳实践与注意事项
- 盐值管理:确保每个用户的盐值唯一且安全存储
- 临时密钥轮换:定期更新临时密钥对增强安全性
- 错误处理:妥善处理JWT过期、证明服务不可用等异常情况
- gas费优化:预估多签交易的gas消耗并做好相应准备
常见问题
zkLogin多签钱包与传统多签有何区别?
zkLogin多签钱包使用基于OAuth的身份派生公钥,而传统多签使用常规加密算法生成的公钥。zkLogin版本提供了更好的用户体验和隐私保护,但依赖第三方OAuth提供商。
是否支持混合类型公钥的多签?
是的,Sui支持混合使用zkLogin公钥和普通公钥创建多签钱包,开发者可以根据具体需求灵活配置公钥类型和权重分配。
zkLogin多签交易的成本如何?
zkLogin交易需要生成零知识证明,因此gas费用略高于常规交易。多签机制本身不会显著增加成本,但多个签名需要组合验证。
如果OAuth账户被盗怎么办?
zkLogin采用双因子安全方案,攻击者仅获取OAuth账户无法完成交易,还需要用户盐值。建议用户启用OAuth提供商的双重认证功能。
哪些OAuth提供商目前受支持?
目前支持Google、Facebook、Twitch和Apple等主流提供商,具体支持情况需查看Sui官方文档的最新更新。
如何确保零知识证明服务的可靠性?
建议使用官方推荐的证明服务或自行部署证明服务实例,确保服务的可用性和响应速度。对于生产环境,应实施服务监控和故障转移机制。
总结
zkLogin多签钱包结合了便捷的OAuth登录体验和强大的多签安全机制,为Sui生态系统提供了创新的资产管理解决方案。通过合理的权重配置和阈值设置,可以满足个人和机构多样化的安全需求。开发者可以在此基础上构建更复杂的DeFi应用和资产管理工具。