一文读懂 zklogin

zklogin 是 sui foundation 最新力作,它能够让用户直接通过 google,facebook,apple id (支持 openid connect 即可)登录来创建并控制 sui 钱包,且隐藏了具体的登录信息(用户名,邮箱等)。登录后,可像正常区块链钱包一样发起交易。

本文力图摒弃各种专业术语和底层细节,保留关键的信息要素,缕清 zklogin 怎么实现上述功能。非水文,请坐稳小板凳。

使用场景

我们先描述一个典型的使用场景。后文会依据该场景介绍相关操作所设计的底层技术。

假设 sueet 是一款纯本地的 web 钱包应用,可以通过 http://localhost:3000 访问。

  • 登录页面是一个 Sign in with Google 的大按钮。
  • 用户点击 Sign in with Google ,浏览器跳转到 google oauth 登录页面。
  • 用户用 google 的账户密码登录后,页面跳转回 sueet 钱包的页面 http://localhost:3000

  • 此时,sueet 页面在 loading 10秒后,显示登录成功,展示用户的钱包地址,钱包余额等等,如同登录 metamask 后的界面。

  • 用户可以在这个界面,发起转账等各种交易。

上述使用场景是不是相当丝滑。我们来逐步分析流程中的这几个操作。

登录准备

用户进入登录页面后, sueet 调用 zklogin 生成以下信息:

  • 临时的密钥对:(eph_sk, eph_pk)。

  • 登录后的最长有效时间: max_epoch

  • 一个随机数据:jwt_randomness

然后,将 eph_pk, max_epoch, jwt_randomness 放在一起哈希,生成 nonce = H(eph_pk, max_epoch, jwt_randomness)

Sign in with Google 本质上一个调用 google oauth 接口的链接 ,sueet 将生成的 nonce 信息放进链接中,传递给 google。比如:

https://accounts.google.com/o/oauth2/v2/auth?client_id=$CLIENT_ID&response_type=id_token&redirect_uri=$REDIRECT_URL&scope=openid&nonce=$NONCE

用户点击 Sign in with Google 后, 会跳转到 Google 的登录鉴权页面。这一步用户直接和 Google 交互,与 sueet 无关。

获取用户信息

当用户成功授权后,google 会跳转到 sueet 页面 http://localhost:3000 并将用户的 jwt_token 数据放在跳转链接中,从而让 sueet 可以拿到该数据。jwt_token 包含了以下信息,payload 中包含了 iss, aud, sub,以及被原封不动返回来的 nonce

{
  header: {
    alg: "RS256",
    kid:  "c3afe7a9bda46bae6ef97e46c95cda48912e5979", // Identifies the JWK that should be used to verify the JWT.
    typ: "JWT"
  },
  payload: {
    iss: "https://accounts.google.com", // OpenID 提供商,这里是 谷歌 
    aud: "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", // 谷歌给 sueet 分配的应用标识
    sub: "110463452167303000000", // 用户在谷歌里的唯一标识
    nonce: "hTPpgF7XAKbW37rEUS6pEVZqmoI" // 前述构造的nonce,google 原封不动返回
  },
  signature: "3Thp81rDFrKXr3WrY1MyMnNK8kKoZBX9lg-JwFznR-M" // header+payload 的签名数据
}

生成链上地址

sueet 拿到 jwt_token 后,本地生成一个随机数 user_salt (或者由用户输入决定)。

这个时候,sueet 有了足够的信息,来为用户生成 sui 的链上地址:

address = H(iss, H(user_salt,aud, sub))

对于一个用户来说,(iss , aud, sub) 是固定的,因此,地址基本上是由 user_salt 决定。user_salt 不同,生成的地址也不一样。

生成地址证明

接着,sueet 将数据 user_salt, jwt_token, eph_pk, max_epoch, jwt_randomness , sub 作为隐私参数传递给外部服务 ZK proving service,让其生成 address proof。(如果不信任外部服务,也可以本地生成 proof,可能耗时较长)。证明系统会证明:

  1. jwt_token 的合法性,证明它确实是由 google 签署的。

  2. nonce 的生成符合预期的规则。即: jwt_token.payload.nonce = H(eph_pk, max_epoch, jwt_randomness)

  3. 传入 的 sub 确实等于 jwt_token 中 的sub。即: jwt_token.payload.sub = sub

  4. 地址的生成符合预期的规则。即:address = H(jwt_token.payload.iss, H(user_salt, jwt_token.payload.aud, jwt_token.payload.sub))

说人话就是:proof 可以证明,生成的 address 确实关联一个 google 用户,而且这个 google 账户关联了一个有效期是 max_epoch 的密钥对,这个密钥对的公钥是 eph_pk

从而,如果一个从 address 发起的交易是用 eph_pk 对应的私钥签署的, 就可以证明这个交易确实是这个 address 对应的 google 用户发起的。因为只有这个 google 用户掌握了 eph_pk 对应的私钥。

除了生成 proof 之外,prover 还会生成公开信息,以便验证 prove 时使用,比如eph_pk, iss, address_seed = H(user_salt, aud, sub)。另外比较重要的一点是,proof 生成后,sueet 可以将其缓存在本地,有效期内不用重复生成。

用户交易

拥有了地址证明,用户可以用 (eph_sk, eph_pk) 签署交易,并附带上缓存的地址证明,提交给 sui 区块链节点。

节点校验

节点收到此类交易,会校验:

  • 交易发起地址的生成规则,符合 :sender_address ==H(iss, address_seed)

  • 交易签名的有效性。 eph_pk.verify(tx_signature, tx_data)

  • 交易签名用的公钥确实和 zkproof 里使用的 eph_pk 一致。

  • 最后就是,地址证明的验证。这一步需要用到 OpenID 提供商公开的 JWK,比如 google 的是 https://www.googleapis.com/oauth2/v3/certs 。侧面来讲,sui 的节点需要对支持的 openid 服务商的 JWK 达成共识。(比如说,将这些 JWKs 当作一种 resource,发起一个写入交易,走一遍全局共识即可)

这样就校验了:交易是由这个 address 关联的 google 账户关联的 (eph_sk, eph_pk) 签署发布的!

安全性

理论情况下,整套流程是非常安全的。应用是本地应用,user_saltproof 生成都可以在本地实现。用户要么和应用打交道,要么和 google 服务打交道。

目前尚不清楚地址证明的生成效率如何。如果电脑端或手机端,能够在30秒或者更短的时间内生成证明,可能大多数用户会选择本地生成(等待时间不长),安全系数比较高。否则需要依赖三方的证明服务,将敏感信息传递出去,安全性降低。

实际应用场景下,还要解决 user_salt 如何保存 的问题。

  • 要么 由用户自行承担,登陆时手动输入,缺点是,用户还是需要记一个密码(虽然可能比较简单),而且用户输入的 salt 可能比较单一,反而降低了安全性。

  • 要么 应用本地随机生成并缓存。缺点是,不能多端登录,salt 不一样会导致地址也不一样。

  • 要么 交由三方服务。缺点是,需要将部分信息传递给三方服务,且三方服务知晓了 salt 信息,有泄漏风险。

使用 salt 也有不少优点。比如,用户在换设备后,依旧可以用同一个账户登录,输入相同的 salt(相当于密码),即可恢复账户地址,无需私钥。同时,只要输入不同 salt,就可以生成不同的地址,达到切换账户的效果,从而实现多账户功能。

结语

zklogin 实现优雅,在保证隐私的情况下,实现免密钥登录,确实拥有 onboarding billions of users 的实力。

短期内,zklogin 无法被其他区块链复制。因为这套方案依赖区块链支持这种独特的交易,并且能够验证地址证明,目前只有 sui 的区块链节点实现了,这是它的独特优势。

但目前 AA 钱包也做的如火如荼,长期来看,类似 zklogin 的方案一定会出现在不同的区块链生态里。拭目以待吧!

如果这篇文章对你有帮助,欢迎在推特转发评论加关注!

参考链接

以及官方出品的流程图

Subscribe to nanne007
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.