DID-SDK 为 iOS 提供了*DID*生成及密钥管理功能,以及*可验证凭证*的签名和验证功能。
-
DID(去中心化身份:Decentralized Identity)
- 一个概念,使得个人数据可以在不通过中心化机构的情况下进行验证。
- W3C DID 规范
-
索赔
- 整体数据的各个单元数据。
- 例如,在数字身份信息中,姓名、生日、性别等每个值被称为索赔。
- W3C VC 索赔
-
可验证凭证
- 包含发行者、有效期、用于验证的发行者的公钥以及索赔集和签名的验证可证 Credential。
- 无法篡改,例如,手机实名认证、电子证件等身份认证。
- 发行者验证用户信息并发送给用户。
- W3C VC 凭证
-
可验证展示
- 包含一个或多个可验证凭证和所有者的公钥和签名的验证可证 Presentation。
- 所有者在向验证者提交凭证时使用。
- W3C VC 展示
- 发行者和所有者会提前创建 DID 来颁发凭证和展示。
- 用户提供凭证签发请求。通过传递 DID 以验证用户是想要签发的凭证的所有者。
- 如果需要验证传递的 DID,则传递不包含凭证的展示。
- 展示签发
- 发行者验证用户的 DID
- DID 作为展示提交时对其进行验证。
- 展示验证
- 颁发包含已验证的索赔的凭证。使用户接收到的凭证被安全地存储。
- 验证者根据请求查找凭证来创建展示。
- 验证者是用户发送的以及是否为请求的发行者的凭证进行验证。
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
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 创建/删除功能。
创建 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。
wallet.deleteDID { finished in
}
}
let didDocument = try? MetaWallet.getDiDDocument(did: did, resolverUrl: delegator.resolverUrl)
检查 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文件获取更多信息。