4、DID与区块链:主流公链上的DID实现

好,咱们进入正题。前面聊了DID的规范、文档结构,那这些东西到底存哪儿?怎么保证它不被篡改?答案就是——链上锚定。

说白了,DID的核心价值就是「去中心化」。你想想看,如果DID文档存在某个中心服务器上,那跟传统账号有啥区别?所以,我们需要把DID的「根」锚定到区块链上。今天我就带大家看看,在以太坊、Polygon、Solana这三条主流公链上,DID是怎么落地的。

4.1 为什么需要链上锚定?

先回答一个基础问题:为什么非得把DID跟区块链绑在一起?

我个人习惯把DID比作「数字身份证的根」。这个根必须满足三个条件:

  • 不可篡改——谁也不能偷偷改你的身份信息
  • 全球可验证——任何人在任何地方都能查到这个根
  • 无单点故障——没有哪个公司能关掉你的身份

区块链天然满足这三点。所以,DID的「锚定」操作,就是把DID文档的哈希、或者关键控制权信息,写到链上的一笔交易里。嗯,这里要注意:不是把整个DID文档存上链,那样太贵了。我们只存一个「指纹」——哈希值。

核心原则:链上存证明,链下存数据。

DID文档本身存在IPFS或中心化存储里,链上只存文档的哈希和DID Controller的公钥信息。

4.2 以太坊上的DID实现

以太坊是DID生态最成熟的公链。ERC-1056(以太坊DID方法)是事实标准。我在项目中用过好几次,说实话,它的设计很巧妙。

4.2.1 ERC-1056 核心机制

ERC-1056不依赖智能合约存储DID文档,而是利用以太坊账户本身。每个以太坊地址天然就是一个DID:did:ethr:0x1234...

为什么可以这样?因为以太坊地址本身就带有公钥信息。你只要用私钥签个名,就能证明你是这个DID的拥有者。

具体实现上,ERC-1056用了一个轻量级的注册合约,只记录三件事:

  • DID所有者的变更历史
  • 委托控制人的公钥
  • DID文档的哈希值

来看一个实际的解析流程:

// 使用 ethers.js 解析 did:ethr
import { EthrDID } from 'ethr-did'
import { Resolver } from 'did-resolver'
import { getResolver } from 'ethr-did-resolver'

// 配置以太坊网络
const providerConfig = {
  rpcUrl: 'https://mainnet.infura.io/v3/YOUR_PROJECT_ID',
  registry: '0xdca7ef03e98e0dc2b855be647c39abe984fcf21b' // ERC-1056主网合约
}

// 创建解析器
const resolver = new Resolver(getResolver(providerConfig))

// 解析DID
async function resolveDID(did) {
  const doc = await resolver.resolve(did)
  console.log('DID文档:', JSON.stringify(doc, null, 2))
  return doc
}

// 调用示例
resolveDID('did:ethr:0x1234567890abcdef...')

我曾经在一个供应链金融项目里用过这套方案。当时有个坑:以太坊主网交易费太贵了,每次更新DID文档哈希要花几十美元。后来我们改用了Polygon,成本直接降到几分钱。

小技巧:在以太坊上,如果你只是验证身份(不更新文档),完全不需要花Gas。因为验证只需要检查链上已有的记录,是只读操作。

4.3 Polygon上的DID实现

Polygon作为以太坊的侧链,兼容EVM,所以ERC-1056可以直接部署上去。但Polygon有自己的特色——Polygon ID。

4.3.1 Polygon ID 的独特设计

Polygon ID不只是简单的DID注册,它集成了零知识证明(ZKP)。这意味着你可以「证明你拥有某个属性,而不暴露属性本身」。比如,证明你年龄大于18岁,但不用告诉对方你具体几岁。

Polygon上的DID格式是:did:polygonid:polygon:mumbai:2qD...xyz

它的链上锚定逻辑是这样的:

  1. 用户生成一个身份钱包(包含公钥和私钥)
  2. 身份哈希被提交到Polygon上的智能合约
  3. 用户用私钥签发可验证凭证(VC)
  4. 验证者通过链上合约验证凭证的有效性

来看一个实际的状态发布代码:

// Polygon ID 状态发布示例(简化版)
const { Identity } = require('@polygonid/js-sdk')

async function publishState() {
  // 创建身份
  const identity = new Identity()
  await identity.create()
  
  // 生成状态信息
  const state = identity.getState()
  
  // 发布到链上(需要Gas)
  const tx = await identity.publishStateToPolygon(
    '0x...合约地址',
    state
  )
  
  console.log('状态已发布,交易哈希:', tx.hash)
}

// 验证凭证
async function verifyCredential(credential) {
  const isValid = await identity.verifyCredential(credential)
  console.log('凭证有效:', isValid)
}

说实话,Polygon ID的ZK方案确实牛,但学习曲线有点陡。我刚开始搞的时候,被那个「Merkle Tree证明」绕晕了好几天。后来发现,其实你不需要完全理解ZK的数学原理,只要会用SDK就行。

避坑指南:我曾经在生产环境遇到过一个问题——Polygon的RPC节点偶尔会超时,导致状态发布失败。解决方案是:在代码里加重试机制,并且使用多个RPC端点做负载均衡。

4.4 Solana上的DID实现

Solana跟以太坊完全不同。它用的是历史证明(PoH)加权益证明(PoS),交易速度快、费用极低。Solana上的DID标准是 did:sol

4.4.1 Solana DID 的账户模型

Solana没有智能合约存储DID,而是利用它的「账户模型」。每个Solana账户都可以存储数据,DID文档就存在账户的「数据区」里。

DID格式:did:sol:9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin

解析流程跟以太坊不太一样:

// Solana DID 解析示例
import { Connection, PublicKey } from '@solana/web3.js'
import { SolDID } from '@solana/did'

const connection = new Connection('https://api.mainnet-beta.solana.com')

async function resolveSolDID(did) {
  // 从DID中提取公钥
  const pubkey = new PublicKey(did.split(':')[2])
  
  // 读取账户数据
  const accountInfo = await connection.getAccountInfo(pubkey)
  
  if (!accountInfo) {
    throw new Error('DID账户不存在')
  }
  
  // 解析DID文档
  const didDoc = SolDID.parse(accountInfo.data)
  return didDoc
}

// 创建新的DID
async function createSolDID() {
  const did = await SolDID.create(connection)
  console.log('新DID:', did.toString())
  return did
}

Solana最大的优势是快。我在一个游戏项目里用过,用户注册DID几乎秒确认,费用不到0.00001 SOL。但缺点也很明显——Solana网络偶尔会「卡住」(我记得2022年就宕机过好几次),这时候DID解析也会受影响。

4.5 三条公链的对比

我整理了一个表格,方便你对比选择:

特性 以太坊 (ERC-1056) Polygon (Polygon ID) Solana (did:sol)
交易费用 高($5-$50) 低($0.01-$0.1) 极低(<$0.001)
确认时间 12-15秒 2-3秒 0.4-1秒
隐私保护 基础(无ZK) 强(内置ZK) 基础(无ZK)
生态成熟度 最成熟 中等 早期
开发难度 低(文档多) 中(ZK有门槛) 中(Solana独特)
适用场景 高价值身份 隐私敏感应用 高频低价值场景

4.6 链上解析的通用流程

不管用哪条链,DID解析的流程都差不多。我画个逻辑图给你:

  1. 输入DID:比如 did:ethr:0x...
  2. 解析DID方法:提取 ethr 部分,找到对应的解析器
  3. 读取链上数据:调用对应链的RPC,获取DID文档哈希和控制人信息
  4. 验证签名:检查返回的数据是否由DID Controller签名
  5. 返回DID文档:组装成标准的DID文档格式

这里有个关键点:解析器必须信任它连接的RPC节点。如果RPC节点作恶,返回假数据,那解析结果就是错的。所以,我建议在生产环境里,自己运行一个全节点,或者用多个RPC做交叉验证。

核心总结:

  • 以太坊:稳定、成熟,适合高价值身份场景
  • Polygon:成本低、有ZK隐私保护,适合合规应用
  • Solana:极快、极便宜,适合高频交互场景
  • 选哪条链,取决于你的业务需求、预算和隐私要求

好了,这一章的内容就到这儿。下一章我们会深入DID文档的详细结构,包括怎么用JSON-LD做扩展、怎么添加服务端点。到时候我会拿一个真实的DID文档拆开给你看,保证你一看就懂。