DID 学习日记 - PolygonID - 数据/操作流程 + 协议细节

  • 获取 schema 列表, 或者 build 一个自己的 https://schema-builder.polygonid.me

  • 复制 Schema Url, 例如 ipfs://QmPt89E3QRjbFDHZRKmNXLoTssreHH4uiz44XWNMdPFN4e

  • import schema https://issuer-ui.polygonid.me/schemas/import-schema

  • issue credential https://issuer-ui.polygonid.me/credentials/issue

    • 如果选择了 MTP 类型,需要去https://issuer-ui.polygonid.me/issuer-state点击 publish 一下

      把 issuer 的 state 同步到智能合约里(因为插入了 claims,所以 claims tree 变化导致 state 变化了)

  • https://issuer-ui.polygonid.me/credentials/issued找到刚 issue 的 credential, 点击右边的三个点按钮, 选择 Details

  • 在打开的https://issuer-ui.polygonid.me/credentials/issued/xxxxxx页面中赋值 qrcode link,例如https://issuer-ui.polygonid.me/credentials/scan-issued/xxxxxx

  • 识别这个二维码, 会得到如下格式的链接:<iden3comm://?request_uri=https://issuer-admin.polygonid.me/v1/qr-store?id=db20325f-15da-41c1-926c-a4c133f389c5>

  • 访问其中的https://issuer-admin.polygonid.me/v1/qr-store?id=db20325f-15da-41c1-926c-a4c133f389c5

    内容格式如下

    {
      "id": "bff72926-340e-4632-acdb-088f74c89aae",
      "typ": "application/iden3comm-plain-json",
      "type": "https://iden3-communication.io/credentials/1.0/offer",
      "thid": "bff72926-340e-4632-acdb-088f74c89aae",
      "body": {
        "url": "https://issuer-admin.polygonid.me/v1/agent",
        "credentials": [
          {
            "id": "88a96d42-c636-11ee-93b5-0242ac120009",
            "description": "KYCAgeCredential"
          }
        ]
      },
      "from": "did:polygonid:polygon:mumbai:2qMCebtitXNzau92r4JNV3y162hkzVZPn75UPMiE1G",
      "to": "did:polygonid:polygon:mumbai:2qKuqAopNFKhy7s6W9xHN3sP4sVHrDHLwrnTPVYJna"
    }
    
  • 这个数据可以用来传递到 PolygonID SDK 的 fetchAndSaveClaims 接口中 https://devs.polygonid.com/docs/wallet/wallet-sdk/polygonid-sdk/iden3comm/api/fetch-and-save/#fetch-and-save-credentials

    其中 Iden3MessageEntity 的定义如下

    abstract class Iden3MessageEntity {
    final String id;
    final String typ;
    final String type;
    final Iden3MessageType messageType;
    final String thid;
    abstract final body;
    final String from;
    final String? to;
    
    const Iden3MessageEntity(
        {required this.id,
        required this.typ,
        required this.type,
        this.messageType = Iden3MessageType.unknown,
        required this.thid,
        required this.from,
        this.to});
    
    @override
    String toString() =>
        "[Iden3MessageEntity] {id: $id, typ: $typ, type: $type, messageType: $messageType, thid: $thid, body: $body, from: $from, to: $to}";
    
    @override
    Map<String, dynamic> toJson() => {
          'id': id,
          'typ': typ,
          'type': type,
          'messageType': messageType.name,
          'thid': thid,
          'body': body.toJson(),
          'from': from,
          'to': to,
        }..removeWhere(
            (dynamic key, dynamic value) => key == null || value == null);
    
    @override
    bool operator ==(Object other) =>
        identical(this, other) ||
        other is Iden3MessageEntity &&
            runtimeType == other.runtimeType &&
            id == other.id &&
            typ == other.typ &&
            type == other.type &&
            messageType == other.messageType &&
            thid == other.thid &&
            body == other.body &&
            from == other.from &&
            to == other.to;
    
    @override
    int get hashCode => runtimeType.hashCode;
    }
    
  • fetchAndSaveClaims 返回的数据为 List<ClaimEntity>

    
    class ClaimEntity {
    final String id;
    final String issuer;
    final String did;
    final ClaimState state;
    final String? expiration;
    final Map<String, dynamic>? schema;
    final String type;
    final Map<String, dynamic> info;
    
    ClaimEntity(
    {required this.id,
    required this.issuer,
    required this.did,
    required this.state,
    this.expiration,
    this.schema,
    required this.type,
    required this.info});
    
    factory ClaimEntity.fromJson(Map<String, dynamic> json) {
    return ClaimEntity(
    id: json['id'],
    issuer: json['issuer'],
    did: json['did'],
    state: ClaimState.values.firstWhere((e) => e.name == json['state']),
    expiration: json['expiration'],
    schema: json['schema'],
    type: json['type'],
    info: json['info'],
    );
    }
    
    @override
    Map<String, dynamic> toJson() => {
    'id': id,
    'issuer': issuer,
    'did': did,
    'state': state.name,
    'expiration': expiration,
    'schema': schema,
    'type': type,
    'info': info,
    };
    
    @override
    String toString() => "[ClaimEntity] {id: $id, "
    "issuer: $issuer, did: $did, state: $state, "
    "expiration: $expiration, schema: $schema, type: $type, info: $info}";
    
    @override
    bool operator ==(Object other) =>
    identical(this, other) ||
    other is ClaimEntity &&
    runtimeType == other.runtimeType &&
    id == other.id &&
    issuer == other.issuer &&
    did == other.did &&
    state == other.state &&
    expiration == other.expiration &&
    schema == other.schema &&
    type == other.type &&
    info.toString() == other.info.toString();
    
    @override
    int get hashCode => runtimeType.hashCode;
    }
    
  • 生成 Sdr 的网页为https://verifier-demo.polygonid.me

  • 生成对应 credential 的 sdr 二维码之后解析二维码

    格式为

    {
      "id": "46bd4f92-84ed-4276-a610-f1b4cdcec68e",
      "typ": "application/iden3comm-plain-json",
      "type": "https://iden3-communication.io/authorization/1.0/request",
      "thid": "46bd4f92-84ed-4276-a610-f1b4cdcec68e",
      "body": {
        "callbackUrl": "https://self-hosted-demo-backend-platform.polygonid.me/api/callback?sessionId=77396",
        "reason": "test flow",
        "scope": [
          {
            "id": 1,
            "circuitId": "credentialAtomicQuerySigV2",
            "query": {
              "allowedIssuers": ["*"],
              "context": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v4.jsonld",
              "credentialSubject": {
                "birthday": {
                  "$lt": 20000101
                }
              },
              "type": "KYCAgeCredential"
            }
          }
        ]
      },
      "from": "did:polygonid:polygon:mumbai:2qH7TstpRRJHXNN4o49Fu9H2Qismku8hQeUxDVrjqT"
    }
    
  • 这个数据可以被送到 Get Proofs 里生成 proof https://devs.polygonid.com/docs/wallet/wallet-sdk/polygonid-sdk/iden3comm/api/get-proofs/#get-proof

  • GetProofs 的返回值为 List<Iden3commProofEntity>

    class Iden3commProofEntity extends ZKProofEntity {
      final int id;
      final String circuitId;
    }
    
    class ZKProofEntity {
      final ZKProofBaseEntity proof;
      final List<String> pubSignals;
    }
    
    class ZKProofEntity {
      final ZKProofBaseEntity proof;
      final List<String> pubSignals;
    }
    
    class ZKProofBaseEntity {
      final List<String> piA;
      final List<List<String>> piB;
      final List<String> piC;
      final String protocol;
      final String curve;
    }
    
  • 这个 proof 还需要加上 authToken 并 encode 为 JWZ

    这个接口 PolygonID 没有直接开发,而是包含在了 authenticate 接口中 https://devs.polygonid.com/docs/wallet/wallet-sdk/polygonid-sdk/iden3comm/api/authenticate/

    也就是说可以把 proof 作为 authenticate 的 message 发送

    也可以自己调用GetJWZUseCase来封装