DID-SDK-Swift 1.1.0

DID-SDK-Swift 1.1.0

jinsikhan 维护。



  • 作者:
  • jinsik

Metadium DID SDK for iOS(Swift)

DID-SDK 为 iOS 提供了*DID*生成及密钥管理功能,以及*可验证凭证*的签名和验证功能。

术语解释

  • DID(去中心化身份:Decentralized Identity)

    • 一个概念,使得个人数据可以在不通过中心化机构的情况下进行验证。
    • W3C DID 规范
  • 索赔

    • 整体数据的各个单元数据。
    • 例如,在数字身份信息中,姓名、生日、性别等每个值被称为索赔。
    • W3C VC 索赔
  • 可验证凭证

    • 包含发行者、有效期、用于验证的发行者的公钥以及索赔集和签名的验证可证 Credential。
    • 无法篡改,例如,手机实名认证、电子证件等身份认证。
    • 发行者验证用户信息并发送给用户。
    • W3C VC 凭证
  • 可验证展示

    • 包含一个或多个可验证凭证和所有者的公钥和签名的验证可证 Presentation。
    • 所有者在向验证者提交凭证时使用。
    • W3C VC 展示

DID 工作流程

Workflow

  1. 发行者和所有者会提前创建 DID 来颁发凭证和展示。
  2. 用户提供凭证签发请求。通过传递 DID 以验证用户是想要签发的凭证的所有者。
    • 如果需要验证传递的 DID,则传递不包含凭证的展示。
    • 展示签发
  3. 发行者验证用户的 DID
    • DID 作为展示提交时对其进行验证。
    • 展示验证
  4. 颁发包含已验证的索赔的凭证。使用户接收到的凭证被安全地存储。
  5. 验证者根据请求查找凭证来创建展示。
  6. 验证者是用户发送的以及是否为请求的发行者的凭证进行验证。

整个测试代码

SDK 安装

DID-SDK-Swift 通过 CocoaPods 提供使用。要安装它,只需将以下行添加到您的 Podfile 中

source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/METADIUM/Web3Swift-iOS'

target 'project' do
    pod 'DID-SDK-Swift', :git => 'https://github.com/METADIUM/did-sdk-swift.git'
end

Swift 包(推荐)

Swift_Package_Manager

dependencies: [
    .package(url: "https://github.com/METADIUM/did-sdk-swift.git", .upToNextMajor(from: "1.0.7"))
]

使用方法

设置网络

设置为创建和使用 DID 的网络。

设置 Delegator、Node、Resolver 的端点和 did 前缀。

另外,如果使用 Metadium mainnet、testnet,则需要从 Metadium 获取 apiKey。

    //Metadium Mainnet 설정
    let delegator = MetaDelegator(api_key: "")
    
    //Metadium Testnet 설정
    let delegator = MetaDelegator(delegatorUrl: "https://testdelegator.metadium.com", nodeUrl: "https://api.metadium.com/dev", resolverUrl: "https://resolver.metadium.com/1.0/identifiers/", didPrefix: "did:meta:testnet:", api_key: "")
    
    //Custom network 설정, private network일 때 해당 네크워크에 각 end-point를 설정합니다.
    let delegator = MetaDelegator(delegatorUrl: "https://custom.delegator.metadium.com", nodeUrl: "https://custom.api.metadium.com", resolverUrl: "https://custom.resolver.metadium.com/1.0/", didPrefix: "did:meta:custom:") 

DID 操作

解释了 DID 创建/删除功能。

创建 DID

创建 Secp256k1 密钥对并使用该密钥创建 DID。

    let wallet = MetaWallet(delegator: delegator)
    wallet.createDID {
        DispatchQueue.main.asyncAfter(deadline: .now()) {
            let did = wallet.getDid()                       // 생성된 DID ex) did:meta:00000000000000000000000000000000000000000000000000000000000432a0 
            let kid = wallet.getKid()                       // 생성된 private key의 id ex) did:meta:00000000000000000000000000000000000000000000000000000000000432a0#MetaManagementKey#234f9445cd405a2a454245b94f7bc5e9286912eb
            
            let key = wallet.getKey()
            let priateKey = key?.privateKey
        }
    }
    

删除 DID

删除 DID。

    wallet.deleteDID { finished in
        
    }
}

获取 DID 文档

    let didDocument = try? MetaWallet.getDiDDocument(did: did, resolverUrl: delegator.resolverUrl)

检查 DID

检查 DID 是否存在于区块链上。

    try? wallet.existDid()

存储钱包

    let walletJson = wallet.toJson()
    
// wallet json을 SecKey로 암호화하여 Userdefaults 혹은 키체인에 저장한다.

加载钱包

// UserDefaults 혹은 키체인에서 가져온 Wallet json string을 복호화

    let wallet = MetaWallet(delegator: delegator, jsonStr: walletJson)
    

签名

DID 的密钥进行签名(使用 椭圆曲线数字签名算法)。

    let signatureData = wallet.getSignature(data: Data())
    
    let signature = String(data: (signatureData?.signData)!, encoding: .utf8)?.withHexPrefix
    
    let r = signatureData?.r
    let s = signatureData?.s
    let v = signatureData?.v

可验证凭证

描述如何颁发和验证可验证凭证。

颁发凭证

颁发可验证凭证。
发行者(issuer)必须有创建的 DID,凭证的类型(types)、接收者(holder)的 DID、要颁发的内容(claims)是必需的。

    let claims = ["name": "YoungBaeJeon", "birth": "19800101", "id": "800101xxxxxxxx"]
    let vc = try? wallet.issueCredential(types: ["PersonalIdCredential"],                            // types : credential 의 이름. "Credential" 로 끝나야 함.
                                            id: "http://aa.metadium.com/credential/name/343",         // id : credential을 검증할 수 있는 고유 URL 을 입력해야 하며 필수는 아님.
                                            nonce: nil,                                               
                                            issuanceDate: issuanceDate,                               // issuance date
                                            expirationDate: expirationDate,                           // expiration date
                                            ownerDid: "did:meta:0000000...00002f4c",                  // ownerDid (holder의 did)
                                            subjects: claims)!                                        // claims
                                                   
   let personalIdVC = try? vc!.serialize()

与上述情况相同,如果收到凭证,验证者需要将凭证原样转交,因此不能选择性地仅发送特定的声明或隐藏无关的声明。

为了选择性地只发送特定的声明,需要按照如下方式操作:将凭证按声明单元进行分割,并由发放者分发给验证者。

    let vc = try? wallet.issueCredential(types: ["PersonalIdCredential", "NameCredential"],      // 표현할 credential 의 이름을 나열. PersonalIdCredential의 NameCredential
                                            id: "http://aa.metadium.com/credential/name/343",         
                                            nonce: nil,                                            
                                            issuanceDate: issuanceDate,                               
                                            expirationDate: expirationDate,                           
                                            ownerDid: "did:meta:0000000...00002f4c",                 
                                            subjects: ["name": "YoungBaeJeon"])!                  // name
                                            
    let nameVC = try? vc!.serialize()
    
    let vc = try? wallet.issueCredential(types: ["PersonalIdCredential", "BirthCredential"],     // 표현할 credential 의 이름을 나열. PersonalIdCredential의 BirthCredential
                                        id: "http://aa.metadium.com/credential/name/343",         
                                        nonce: nil,                                            
                                        issuanceDate: issuanceDate,                               
                                        expirationDate: expirationDate,                           
                                        ownerDid: "did:meta:0000000...00002f4c",                 
                                        subjects: ["birth": "19800101"])!                         // birth
                                        
    let birthVC = try? vc!.serialize()
    
    let vc = try? wallet.issueCredential(types: ["PersonalIdCredential", "IdCredential"],        // 표현할 credential 의 이름을 나열. PersonalIdCredential의 IdCredential
                                    id: "http://aa.metadium.com/credential/name/343",         
                                    nonce: nil,                                            
                                    issuanceDate: issuanceDate,                               
                                    expirationDate: expirationDate,                           
                                    ownerDid: "did:meta:0000000...00002f4c",                 
                                    subjects: ["id": "800101xxxxxxxx"])!                          // id
                                        
    let birthVC = try? vc!.serialize()

发布呈现

包含需传递的凭证列表的呈现由发放者发出。验证者必须将需传递的凭证类型告知持证人,持证人必须将相应的凭证以呈现的形式交付,并交给了验证者进行验证。

验证者请求2个凭证,持证人发出呈现并传递的示例(要求居民身份证和驾照)

    //검증자 요청 예제 : {"types":["TestPresentation"], "vc":[["PersonalIdCredential", "NameCredential"], ["PersonalIdCredential", "IdCredential"]]}
    let holderAllVc = [] // 소유자의 전체 credential 목록
    
    let vp = try? wallet.issuePresentation(types: ["TestPresentation"],
                                       id: "http://aa.metadium.com/credential/name/343",
                                       nonce: nil,
                                       issuanceDate: issuanceDate,
                                       expirationDate: expirationDate,
                                       vcList: foundVcList)
        
    let serializedVP = try? vp!.serialize()

从持证人的凭证列表中查找验证者所需的凭证的示例

    func findVC(holderVcList: [String], typesOfRequiresVcs: [[String]]) {
        
        var ret: [String] = []
        
        for serializedVc in holderVcList {
            
            let credential = try! VerifiableCredential.init(jws: JWSObject.init(string: serializedVc))
            
            for types in typesOfRequiresVcs {
                
                if credential.getTypes()!.contains(array: types) {
                    ret.append(serializedVc)
                }
            }
        }
    }
extension Array where Element: Equatable {
    func contains(array: [Element]) -> Bool {
        for item in array {
            if !self.contains(item) { return false }
        }
        return true
    }
}

验证凭证或呈现

如果网络不在主网上,则 resolver URL 需要配置,才能进行正常的验证。请参见设置网络

验证收到的凭证或呈现。

    let jws = try? JWSObject.init(string: serializedVC)
    let jwt = try? JWT.init(jsonData: jws!.payload)

    let expireDate = jwt!.expirationTime


    do {
        let verified = try! MetaWallet.verify(jwt: JWSObject(string: vpForIssueCredential!!), resolverUrl: delegator.resolverUrl)
        
        if !verified {
            //검증실패
            XCTAssert(false, "vpForIssueCredential 검증 실패")
        }
        
    } catch verifyError.noneDidDocument {
        //todo
    } catch verifyError.nonePublicKey {
        //todo
    }
    
    if (expireDate != nil && expireDate! < Date()) {
        // 유효기간 초과
    }

从呈现中获取可验证的凭证

检查呈现中列出的凭证详情。

    let vpObj = try? VerifiablePresentation.init(jws: JWSObject.init(string: serializedVp))
    let holDerDid = vpObj.holder                    //Presentation 제출
    let vpId = vpObj.id                             //Presentation ID
    
    for serializedVc in vpObj.verifiableCredentials() {
        
    }

从凭证中获取声明

检查凭证中列出的声明的详情。

    let credential = try? VerifiableCredential(jws: JWSObject.init(string: "serializedVc"))
    
    if let subjects = credential.credentialSubject as? [String : Any] {
                    
        for (key, value) in subjects {
            let claimName = key
            let claimValue = value
                        
            print("\(claimName) = \(claimValue)")
        }
    }
    

示例

要运行示例项目,请先克隆仓库,然后从示例目录中运行 pod install

需求

作者

jinsik,[email protected]

许可

DID-SDK-Swift可在MIT许可下使用。查看LICENSE文件获取更多信息。