JS `Distributed Identifiers (DIDs)` `Verifiable Credentials (VCs)` `Presentation Exchange`

各位观众老爷,大家好!今天咱们来聊聊DIDs、VCs 和 Presentation Exchange 这三个家伙,它们可是构建下一代互联网信任体系的关键角色。这三个玩意儿听起来唬人,其实没那么复杂,咱们用大白话 + 代码的方式,保证你听完能上手。

一、DID:数字身份的身份证

想象一下,在网上冲浪,你得注册各种账号,密码记都记不过来,还得担心被盗号。DID 就是来解决这个问题的,它给你一个去中心化的数字身份,你自己说了算,不用依赖任何中心机构。

  • 啥是 DID?

    DID (Distributed Identifier) 是一种新型的标识符,它具有以下特点:

    • 去中心化 (Decentralized): 不依赖于中心化的身份提供商。
    • 可控性 (Controllable): 你自己控制你的 DID。
    • 可验证性 (Verifiable): 可以通过密码学方法验证 DID 的所有权。
    • 持久性 (Persistent): 即使你离开某个平台,DID 仍然存在。
  • DID 的结构

    一个 DID 通常长这样:did:method:identifier

    • did: 固定前缀,表示这是一个 DID。
    • method: DID 方法,指定了如何创建、解析和更新 DID。常见的 DID 方法有 did:key, did:web, did:pkh 等。
    • identifier: 方法特定的标识符,用于唯一标识一个 DID。
  • DID 方法举例

    • did:key

      最简单的 DID 方法,直接使用公钥作为标识符。

      // 生成一个随机的 Ed25519 密钥对 (需要导入相关库,比如 tweetnacl)
      const keyPair = nacl.sign.keyPair();
      const publicKeyBase58 = bs58.encode(keyPair.publicKey); // 将公钥编码为 Base58
      
      const didKey = `did:key:z${publicKeyBase58}`; // 构建 did:key
      console.log("did:key:", didKey); // 输出类似: did:key:z6MkpTHR3DQTU99YvNVnbKogJx2uhJvE2DiAcjVzZVMR

      这个例子中,我们生成了一个Ed25519密钥对,然后将公钥编码为Base58格式,最后拼接到 did:key: 后面,就得到了一个 did:key 类型的 DID。 注意 z 前缀是 Multibase 编码的一部分,用于指示编码类型。

    • did:web

      使用一个 HTTPS URL 作为标识符,DID 文档托管在这个 URL 上。

      did:web:example.com

      要解析这个 DID,我们需要去 https://example.com/.well-known/did.json 获取 DID 文档。

    • did:pkh

      使用区块链地址作为标识符 (Public Key Hash)。

      did:pkh:eip155:1:0x1234567890123456789012345678901234567890

      这个例子中,eip155:1 表示以太坊主网,0x123... 是一个以太坊地址。

  • DID 文档

    DID 文档是一个 JSON-LD 文档,包含了关于 DID 的元数据,例如:

    • id: DID 本身。
    • verificationMethod: 用于验证 DID 所有者的公钥。
    • authentication: 用于身份验证的验证方法。
    • assertionMethod: 用于声明的验证方法。
    • capabilityInvocation: 用于调用能力的验证方法。
    • capabilityDelegation: 用于委托能力的验证方法。
    • service: 用于发现与 DID 相关的服务的端点。

    一个简单的 DID 文档示例:

    {
      "@context": [
        "https://www.w3.org/ns/did/v1",
        "https://w3id.org/security/suites/ed25519-2020/v1"
      ],
      "id": "did:example:123456789abcdefghi",
      "verificationMethod": [
        {
          "id": "did:example:123456789abcdefghi#key-1",
          "type": "Ed25519VerificationKey2020",
          "controller": "did:example:123456789abcdefghi",
          "publicKeyMultibase": "z6MkpTHR3DQTU99YvNVnbKogJx2uhJvE2DiAcjVzZVMR"
        }
      ],
      "authentication": [
        "did:example:123456789abcdefghi#key-1"
      ],
      "assertionMethod": [
        "did:example:123456789abcdefghi#key-1"
      ]
    }

    这个文档声明了 DID did:example:123456789abcdefghi 的所有者有一个 Ed25519 公钥,可以用于身份验证和声明。

二、VC:你的数字证书

有了 DID,我们就能证明“我是我”,但是怎么证明“我是个好人”、“我毕业了”、“我年满 18 岁”呢? 这时候就轮到 Verifiable Credentials (VCs) 出场了。 VC 相当于数字世界的证书,可以证明关于你的各种信息。

  • 啥是 VC?

    VC 是一种数字化的凭证,由一个 Issuer (颁发者) 颁发给一个 Subject (主体),用于证明关于 Subject 的某些信息。 VC 具有以下特点:

    • 可验证性 (Verifiable): 可以通过密码学方法验证 VC 的真实性和完整性。
    • 可移植性 (Portable): 可以被 Subject 在不同的场景中使用。
    • 可选择性披露 (Selective Disclosure): Subject 可以选择性地披露 VC 中的部分信息。
  • VC 的结构

    一个 VC 通常是一个 JSON-LD 文档,包含了以下关键字段:

    • @context: JSON-LD 上下文,定义了 VC 中使用的术语。
    • type: VC 的类型,例如 VerifiableCredential, UniversityDegreeCredential 等。
    • issuer: 颁发者的 DID 或其他标识符。
    • issuanceDate: 颁发日期。
    • expirationDate: 过期日期 (可选)。
    • credentialSubject: 关于 Subject 的信息。
    • proof: 用于验证 VC 的密码学证明。

    一个简单的 VC 示例:

    {
      "@context": [
        "https://www.w3.org/2018/credentials/v1",
        "https://example.org/credentials/v1"
      ],
      "type": [
        "VerifiableCredential",
        "UniversityDegreeCredential"
      ],
      "issuer": "did:example:issuer",
      "issuanceDate": "2023-10-27T12:00:00Z",
      "credentialSubject": {
        "id": "did:example:subject",
        "name": "Alice Smith",
        "degree": {
          "type": "BachelorDegree",
          "university": "Example University",
          "major": "Computer Science"
        }
      },
      "proof": {
        "type": "Ed25519Signature2020",
        "created": "2023-10-27T12:00:00Z",
        "verificationMethod": "did:example:issuer#key-1",
        "proofPurpose": "assertionMethod",
        "jws": "..." // JWT 签名
      }
    }

    这个 VC 证明了 Alice Smith 在 Example University 获得了计算机科学专业的学士学位。

  • 颁发 VC 的流程

    1. Issuer 创建 VC: Issuer 根据 Subject 的信息创建一个 VC 对象。
    2. Issuer 签名 VC: Issuer 使用自己的私钥对 VC 进行签名,生成 proof 字段。
    3. Issuer 将 VC 发给 Subject: Subject 获得 VC。

    代码示例(简化版,没有包含完整的密钥管理和错误处理):

    // 假设我们已经有了 Issuer 的 DID 和密钥对
    const issuerDid = "did:example:issuer";
    const issuerPrivateKey = nacl.sign.keyPair().secretKey; // 简化,实际需要安全地存储和访问私钥
    
    async function issueCredential(subjectDid, subjectName, degree) {
      const credential = {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://example.org/credentials/v1"
        ],
        "type": [
          "VerifiableCredential",
          "UniversityDegreeCredential"
        ],
        "issuer": issuerDid,
        "issuanceDate": new Date().toISOString(),
        "credentialSubject": {
          "id": subjectDid,
          "name": subjectName,
          "degree": degree
        }
      };
    
      // 使用 JWT 签名 VC (需要导入 jose 库)
      const jws = await new jose.SignJWT(credential)
        .setProtectedHeader({ alg: 'EdDSA', kid: `${issuerDid}#key-1` }) // 假设 DID 文档中定义了 key-1
        .setIssuer(issuerDid)
        .sign(issuerPrivateKey); // 使用私钥签名
    
      credential.proof = {
        type: "Ed25519Signature2020",
        created: new Date().toISOString(),
        verificationMethod: `${issuerDid}#key-1`,
        proofPurpose: "assertionMethod",
        jws: jws
      };
    
      return credential;
    }
    
    // 示例:颁发一个学位证书给 Alice
    issueCredential("did:example:alice", "Alice Smith", {
      type: "BachelorDegree",
      university: "Example University",
      major: "Computer Science"
    }).then(vc => {
      console.log("颁发的 VC:", vc);
    });
  • 验证 VC 的流程

    1. Verifier 获取 VC: Verifier 从 Subject 那里获取 VC。
    2. Verifier 获取 Issuer 的 DID 文档: Verifier 通过 Issuer 的 DID 解析出 DID 文档,获取 Issuer 的公钥。
    3. Verifier 验证 VC 的签名: Verifier 使用 Issuer 的公钥验证 VC 的 proof 字段的签名。
    4. Verifier 验证 VC 的有效性: Verifier 检查 VC 的 issuanceDateexpirationDate 是否有效。
    5. Verifier 验证 VC 的内容: Verifier 根据自己的需求验证 VC 的 credentialSubject 字段的内容。

    代码示例(简化版):

    async function verifyCredential(credential) {
      try {
        // 1. 验证 JWS 签名 (需要 jose 库)
        const { payload, protectedHeader } = await jose.jwtVerify(
          credential.proof.jws,
          async (protectedHeader, credential) => {
            // 模拟从 DID 文档中获取公钥 (实际需要根据 credential.issuer 从 DID Registry 解析 DID 文档)
            const issuerDid = credential.issuer;
            const publicKey = nacl.sign.keyPair().publicKey; // 假设我们能拿到 issuer 的公钥
            return publicKey;
          },
          {
            issuer: credential.issuer,
            algorithms: ['EdDSA'] // 验证算法
          }
        );
    
        // 2. 验证 VC 的有效性
        const issuanceDate = new Date(credential.issuanceDate);
        const expirationDate = credential.expirationDate ? new Date(credential.expirationDate) : null;
        const now = new Date();
    
        if (issuanceDate > now) {
          throw new Error("VC 还未生效");
        }
    
        if (expirationDate && expirationDate < now) {
          throw new Error("VC 已过期");
        }
    
        // 3. 其他自定义验证逻辑... (例如,验证学位是否符合要求)
    
        console.log("VC 验证成功!");
        return true;
    
      } catch (error) {
        console.error("VC 验证失败:", error);
        return false;
      }
    }
    
    // 示例:验证之前颁发的 VC
    issueCredential("did:example:alice", "Alice Smith", {
      type: "BachelorDegree",
      university: "Example University",
      major: "Computer Science"
    }).then(vc => {
      verifyCredential(vc);
    });

三、Presentation Exchange:选择性地展示你的 VC

有了 VC,Alice 就可以把她的学位证书给任何想看的人。但是,如果 Alice 只是想证明自己毕业于某所大学,而不想透露自己的姓名和专业呢? 这时候 Presentation Exchange (PX) 就派上用场了。 PX 允许 Alice 选择性地披露 VC 中的部分信息。

  • 啥是 Presentation Exchange?

    Presentation Exchange 是一种标准,用于定义 Verifier 如何向 Holder 请求凭证,以及 Holder 如何创建和提交满足 Verifier 要求的 Presentation。 Presentation Exchange 允许 Verifier 指定它需要的凭证类型、属性和约束,而 Holder 可以选择性地披露满足这些要求的凭证。

  • Presentation Definition

    Presentation Definition 是一个 JSON 对象,定义了 Verifier 需要的凭证类型、属性和约束。 它就像一份详细的“需求清单”。

    一个简单的 Presentation Definition 示例:

    {
      "id": "32f54163-716f-42d0-a19b-0466b4d5e59c",
      "definition": {
        "input_descriptors": [
          {
            "id": "degree_credential",
            "name": "University Degree",
            "purpose": "We need your degree to verify your education level.",
            "constraints": {
              "fields": [
                {
                  "path": [
                    "$.type"
                  ],
                  "filter": {
                    "type": "string",
                    "const": "UniversityDegreeCredential"
                  }
                },
                {
                  "path": [
                    "$.credentialSubject.degree.university"
                  ],
                  "filter": {
                    "type": "string",
                    "const": "Example University"
                  }
                }
              ]
            }
          }
        ]
      }
    }

    这个 Presentation Definition 要求 Holder 提供一个 UniversityDegreeCredential 类型的 VC,并且 VC 中的 credentialSubject.degree.university 字段必须是 "Example University"。

  • Presentation

    Presentation 是 Holder 根据 Presentation Definition 创建的 JSON 对象,包含了满足 Verifier 要求的 VC。 Presentation 必须包含 Verifier 需要的所有信息,并且不能包含 Verifier 没有要求的信息。

    一个简单的 Presentation 示例:

    {
      "verifiableCredential": [
        {
          "@context": [
            "https://www.w3.org/2018/credentials/v1",
            "https://example.org/credentials/v1"
          ],
          "type": [
            "VerifiableCredential",
            "UniversityDegreeCredential"
          ],
          "issuer": "did:example:issuer",
          "issuanceDate": "2023-10-27T12:00:00Z",
          "credentialSubject": {
            "id": "did:example:alice",
            "name": "Alice Smith",
            "degree": {
              "type": "BachelorDegree",
              "university": "Example University",
              "major": "Computer Science"
            }
          },
          "proof": {
            "type": "Ed25519Signature2020",
            "created": "2023-10-27T12:00:00Z",
            "verificationMethod": "did:example:issuer#key-1",
            "proofPurpose": "assertionMethod",
            "jws": "..." // JWT 签名
          }
        }
      ],
      "presentation_submission": {
        "id": "a47c8255-6368-4999-8cb8-0a5f2683698a",
        "definition_id": "32f54163-716f-42d0-a19b-0466b4d5e59c",
        "descriptor_map": [
          {
            "id": "degree_credential",
            "format": "vc+jwt",
            "path": "$.verifiableCredential[0]"
          }
        ]
      }
    }

    这个 Presentation 包含了之前颁发的 UniversityDegreeCredential,并且通过 presentation_submission 字段指定了哪个 VC 满足哪个 input_descriptor 的要求。

  • Presentation Exchange 的流程

    1. Verifier 创建 Presentation Definition: Verifier 根据自己的需求创建一个 Presentation Definition。
    2. Verifier 将 Presentation Definition 发给 Holder: Verifier 将 Presentation Definition 发给 Holder。
    3. Holder 根据 Presentation Definition 创建 Presentation: Holder 根据 Presentation Definition 从自己的 VC 中选择满足要求的 VC,并创建一个 Presentation。
    4. Holder 将 Presentation 发给 Verifier: Holder 将 Presentation 发给 Verifier。
    5. Verifier 验证 Presentation: Verifier 验证 Presentation 是否满足 Presentation Definition 的要求,以及 VC 的有效性。

    代码示例(简化版):

    // 1. Verifier 创建 Presentation Definition (同上)
    const presentationDefinition = {
      "id": "32f54163-716f-42d0-a19b-0466b4d5e59c",
      "definition": {
        "input_descriptors": [
          {
            "id": "degree_credential",
            "name": "University Degree",
            "purpose": "We need your degree to verify your education level.",
            "constraints": {
              "fields": [
                {
                  "path": [
                    "$.type"
                  ],
                  "filter": {
                    "type": "string",
                    "const": "UniversityDegreeCredential"
                  }
                },
                {
                  "path": [
                    "$.credentialSubject.degree.university"
                  ],
                  "filter": {
                    "type": "string",
                    "const": "Example University"
                  }
                }
              ]
            }
          }
        ]
      }
    };
    
    // 2. (模拟) Holder 收到 Presentation Definition,  并创建 Presentation
    async function createPresentation(credential, presentationDefinition) {
      const presentation = {
        verifiableCredential: [credential],
        presentation_submission: {
          id: "a47c8255-6368-4999-8cb8-0a5f2683698a",
          definition_id: presentationDefinition.id,
          descriptor_map: [
            {
              id: "degree_credential",
              format: "vc+jwt",
              path: "$.verifiableCredential[0]"
            }
          ]
        }
      };
      return presentation;
    }
    
    // 3. (模拟) Verifier 验证 Presentation
    async function verifyPresentation(presentation, presentationDefinition) {
        // 简化验证逻辑,实际需要根据 presentationDefinition 完整验证
        try {
            if (presentation.presentation_submission.definition_id !== presentationDefinition.id) {
                throw new Error("Presentation Definition ID 不匹配");
            }
    
            const credential = presentation.verifiableCredential[0];
            if (!credential) {
                throw new Error("未找到 verifiableCredential");
            }
    
            //  简单验证 credential 类型
            if (!credential.type.includes("UniversityDegreeCredential")) {
                throw new Error("credential 类型不匹配");
            }
    
            console.log("Presentation 验证成功!");
            return true;
        } catch (error) {
            console.error("Presentation 验证失败:", error);
            return false;
        }
    }
    
    // 示例:完整的流程
    issueCredential("did:example:alice", "Alice Smith", {
      type: "BachelorDegree",
      university: "Example University",
      major: "Computer Science"
    }).then(vc => {
      createPresentation(vc, presentationDefinition).then(presentation => {
          verifyPresentation(presentation, presentationDefinition).then(verified => {
              console.log("Presentation 验证结果:", verified);
          });
      });
    });

四、总结

技术 作用 优点 缺点
DID 提供去中心化的数字身份 去中心化,可控性,可验证性,持久性 复杂性,需要 DID 方法的支持
Verifiable Credentials 提供数字化的凭证,用于证明关于 Subject 的信息 可验证性,可移植性,可选择性披露 需要可信的 Issuer,隐私问题,需要标准化
Presentation Exchange 允许 Verifier 向 Holder 请求凭证,并允许 Holder 选择性地披露满足 Verifier 要求的凭证 保护隐私,提高效率,支持各种场景 需要标准化,复杂性

总的来说,DIDs、VCs 和 Presentation Exchange 是一套强大的工具,可以构建一个更加安全、可信和用户友好的互联网。 虽然现在还处于发展初期,但它们代表了未来的方向。 希望今天的讲解能让你对这三个家伙有个初步的了解,也欢迎大家深入研究,一起推动这个领域的发展!

好了,今天的讲座就到这里,散会! 记住,代码要多敲,才能真正掌握这些技术。 咱们下期再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注