Skip to content

Commit

Permalink
feat(pollux): zkp verification
Browse files Browse the repository at this point in the history
  • Loading branch information
goncalo-frade-iohk committed Jan 17, 2024
1 parent 32bdfbd commit af7f39e
Show file tree
Hide file tree
Showing 20 changed files with 150 additions and 84 deletions.
7 changes: 6 additions & 1 deletion AtalaPrismSDK/Domain/Sources/BBs/Pluto.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ public protocol Pluto {
credential: StorableCredential
) -> AnyPublisher<Void, Error>

/// Stores a link secret in the data store.
/// - Parameter secret: The storable key link secret.
/// - Returns: A publisher that completes when the operation finishes.
func storeLinkSecret(secret: StorableKey) -> AnyPublisher<Void, Error>

/// Returns all stored PRISM DIDs, along with their associated key pair indices and aliases (if any).
Expand Down Expand Up @@ -217,5 +220,7 @@ public protocol Pluto {
/// - Returns: A publisher that emits an array of stored verifiable credentials.
func getAllCredentials() -> AnyPublisher<[StorableCredential], Error>

func getLinkSecret() -> AnyPublisher<[StorableKey], Error>
/// Returns the stored link secret.
/// - Returns: A publisher that emits an optonal `StorableKey` that represents the link secret.
func getLinkSecret() -> AnyPublisher<StorableKey?, Error>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ import Domain
import Foundation

protocol LinkSecretProvider {
func getAll() -> AnyPublisher<[StorableKey], Error>
func getLinkSecret() -> AnyPublisher<StorableKey?, Error>
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyProvider {
try $0.map {
(
DID(from: $0),
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychain) },
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychainDao.keychain) },
$0.alias
)
}
Expand All @@ -24,7 +24,7 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyProvider {
try $0.map {
(
DID(from: $0),
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychain) },
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychainDao.keychain) },
$0.alias
)
}
Expand All @@ -41,7 +41,7 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyProvider {
try $0.map {
(
DID(from: $0),
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychain) },
try $0.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychainDao.keychain) },
$0.alias
)
}
Expand All @@ -52,7 +52,7 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyProvider {
func getPrivateKeys(did: DID) -> AnyPublisher<[StorableKey]?, Error> {
fetchByIDsPublisher(did.string, context: readContext)
.tryMap {
try $0?.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychain) }
try $0?.keys.map { try $0.parseToStorableKey(keychain: self.keyDao.keychainDao.keychain) }
}
.eraseToAnyPublisher()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ extension CDDIDPrivateKeyDAO: DIDPrivateKeyStore {
try storeKeychainKey(
did: did,
keychainKey: keychainKey,
service: self.keyDao.keychainService,
service: self.keyDao.keychainDao.keychainService,
account: identifier,
keychain: self.keyDao.keychain
keychain: self.keyDao.keychainDao.keychain
)
let cdkey = CDKeychainKey(entity: CDKeychainKey.entity(), insertInto: context)
cdkey.parseFromStorableKey(
keychainKey,
did: cdobj,
identifier: identifier,
service: self.keyDao.keychainService
service: self.keyDao.keychainDao.keychainService
)
return cdkey as CDKey
default:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Combine
import CoreData
import Domain

struct CDDatabaseKeyDAO: CoreDataDAO {
typealias CoreDataObject = CDDatabaseKey
let readContext: NSManagedObjectContext
let writeContext: NSManagedObjectContext
let identifierKey: String? = "identifier"
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import Foundation
import Domain

extension CDKeyDAO: LinkSecretProvider {
func getAll() -> AnyPublisher<[StorableKey], Error> {
fetchController(context: readContext)
.tryMap { try $0.map { try $0.parseToStorableKey(keychain: self.keychain) } }
func getLinkSecret() -> AnyPublisher<StorableKey?, Error> {
fetchByIDsPublisher("linkSecret", context: readContext)
.tryMap {
try $0?.parseToStorableKey(keychain: self.keychainDao.keychain)
}
.eraseToAnyPublisher()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,33 @@ import Domain

extension CDKeyDAO: LinkSecretStore {
func addLinkSecret(_ linkSecret: StorableKey) -> AnyPublisher<Void, Error> {
updateOrCreate("linkSecret", context: writeContext) { cdobj, context in
switch linkSecret {
case let keychainKey as KeychainStorableKey:
switch linkSecret {
case let keychainKey as KeychainStorableKey:
return keychainDao.updateOrCreate("linkSecret", context: writeContext) { cdobj, context in
try storeKeychainKey(
keychainKey: keychainKey,
service: self.keychainService,
service: self.keychainDao.keychainService,
account: "linkSecret",
keychain: self.keychain
keychain: self.keychainDao.keychain
)
let cdkey = CDKeychainKey(entity: CDKeychainKey.entity(), insertInto: context)
cdkey.parseFromStorableKey(
cdobj.parseFromStorableKey(
keychainKey,
identifier: "linkSecret",
service: self.keychainService
service: self.keychainDao.keychainService
)
default:
let cdkey = CDDatabaseKey(entity: CDDatabaseKey.entity(), insertInto: context)
cdkey.parseFromStorableKey(
}
.map { _ in }
.eraseToAnyPublisher()
default:
return databaseDAO.updateOrCreate("linkSecret", context: writeContext) { cdobj, context in
cdobj.parseFromStorableKey(
linkSecret,
identifier: "linkSecret"
)
}
.map { _ in }
.eraseToAnyPublisher()
}
.map { _ in }
.eraseToAnyPublisher()
}
}

Expand Down
24 changes: 22 additions & 2 deletions AtalaPrismSDK/Pluto/Sources/PersistentStorage/DAO/CDKeyDAO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,31 @@ import Domain

struct CDKeyDAO: CoreDataDAO {
typealias CoreDataObject = CDKey
let keychain: KeychainStore & KeychainProvider
let keychainService: String
let keychainDao: CDKeychainKeyDAO
let databaseDAO: CDDatabaseKeyDAO
let readContext: NSManagedObjectContext
let writeContext: NSManagedObjectContext
let identifierKey: String? = "identifier"

init(
keychain: KeychainStore & KeychainProvider,
keychainService: String,
readContext: NSManagedObjectContext,
writeContext: NSManagedObjectContext
) {
self.keychainDao = CDKeychainKeyDAO(
keychain: keychain,
keychainService: keychainService,
readContext: readContext,
writeContext: writeContext
)
self.databaseDAO = CDDatabaseKeyDAO(
readContext: readContext,
writeContext: writeContext
)
self.readContext = readContext
self.writeContext = writeContext
}
}

extension CDKey {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Combine
import CoreData
import Domain

struct CDKeychainKeyDAO: CoreDataDAO {
typealias CoreDataObject = CDKeychainKey
let keychain: KeychainStore & KeychainProvider
let keychainService: String
let readContext: NSManagedObjectContext
let writeContext: NSManagedObjectContext
let identifierKey: String? = "identifier"
}
4 changes: 2 additions & 2 deletions AtalaPrismSDK/Pluto/Sources/PlutoImpl+Public.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ extension PlutoImpl: Pluto {
keyDao.addLinkSecret(secret)
}

public func getLinkSecret() -> AnyPublisher<[StorableKey], Error> {
keyDao.getAll()
public func getLinkSecret() -> AnyPublisher<StorableKey?, Error> {
keyDao.getLinkSecret()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ struct AnonCredentialSchema: Codable {
let attrNames: [String]
let issuerId: String
}

struct SchemaAnonCredentialSchema: Codable {
let schema: AnonCredentialSchema
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ struct ParseAnoncredsCredentialFromMessage {

let processedCredentialJson = try processedCredential.getJson().tryData(using: .utf8)
let finalCredential = try JSONDecoder().decode(AnonCredential.self, from: processedCredentialJson)

return AnoncredsCredentialStack(
schema: try JSONDecoder.didComm().decode(AnonCredentialSchema.self, from: schemaData),
definition: try JSONDecoder.didComm().decode(AnonCredentialDefinition.self, from: credentialDefinitionData),
Expand Down
4 changes: 2 additions & 2 deletions AtalaPrismSDK/Pollux/Tests/Mocks/MockPluto.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ class MockPluto: Pluto {
self.credentials.publisher.collect().tryMap { $0 }.eraseToAnyPublisher()
}

func getLinkSecret() -> AnyPublisher<[StorableKey], Error> {
return Just([]).tryMap { $0 }.eraseToAnyPublisher()
func getLinkSecret() -> AnyPublisher<StorableKey?, Error> {
return Just(nil).tryMap { $0 }.eraseToAnyPublisher()
}
}
8 changes: 4 additions & 4 deletions AtalaPrismSDK/PrismAgent/Sources/PrismAgent+Credentials.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public extension PrismAgent {
func verifiableCredentials() -> AnyPublisher<[Credential], Error> {
let pollux = self.pollux
return pluto.getAllCredentials().tryMap {
try $0.map {
try pollux.restoreCredential(
$0.compactMap {
try? pollux.restoreCredential(
restorationIdentifier: $0.recoveryId,
credentialData: $0.credentialData
)
Expand All @@ -31,7 +31,7 @@ public extension PrismAgent {
/// - Throws: PrismAgentError, if there is a problem parsing the credential.
func processIssuedCredentialMessage(message: IssueCredential3_0) async throws -> Credential {
guard
let linkSecret = try await pluto.getLinkSecret().first().await().first
let linkSecret = try await pluto.getLinkSecret().first().await()
else { throw PrismAgentError.cannotFindDIDKeyPairIndex }

let restored = try await self.apollo.restoreKey(linkSecret)
Expand Down Expand Up @@ -79,7 +79,7 @@ public extension PrismAgent {

guard
let exporting = privateKey.exporting,
let linkSecret = try await pluto.getLinkSecret().first().await().first
let linkSecret = try await pluto.getLinkSecret().first().await()
else { throw PrismAgentError.cannotFindDIDKeyPairIndex }

let restored = try await self.apollo.restoreKey(linkSecret)
Expand Down
77 changes: 51 additions & 26 deletions AtalaPrismSDK/PrismAgent/Sources/PrismAgent+Proof.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,40 +20,65 @@ public extension PrismAgent {
) async throws -> Presentation {
guard let proofableCredential = credential.proof else { throw UnknownError.somethingWentWrongError() }

guard
let subjectDIDString = credential.subject
else {
throw PolluxError.invalidPrismDID
guard let requestType = request.attachments.first?.format else {
throw UnknownError.somethingWentWrongError(customMessage: nil, underlyingErrors: nil)
}

let subjectDID = try DID(string: subjectDIDString)
let presentationString: String
switch requestType {
case "anoncreds/[email protected]":
guard
let linkSecret = try await pluto.getLinkSecret().first().await()
else { throw PrismAgentError.cannotFindDIDKeyPairIndex }

let didInfo = try await pluto
.getDIDInfo(did: subjectDID)
.first()
.await()
let restored = try await self.apollo.restoreKey(linkSecret)
guard
let linkSecretString = String(data: restored.raw, encoding: .utf8)
else { throw PrismAgentError.cannotFindDIDKeyPairIndex }
presentationString = try proofableCredential.presentation(
request: request.makeMessage(),
options: [
.linkSecret(id: "", secret: linkSecretString)
]
)
case "prism/jwt":
guard
let subjectDIDString = credential.subject
else {
throw PolluxError.invalidPrismDID
}

guard
let storedPrivateKey = didInfo?.privateKeys.first
else { throw PrismAgentError.cannotFindDIDKeyPairIndex }
let subjectDID = try DID(string: subjectDIDString)

let privateKey = try await apollo.restorePrivateKey(storedPrivateKey)
let didInfo = try await pluto
.getDIDInfo(did: subjectDID)
.first()
.await()

guard
let storedPrivateKey = didInfo?.privateKeys.first
else { throw PrismAgentError.cannotFindDIDKeyPairIndex }

let privateKey = try await apollo.restorePrivateKey(storedPrivateKey)

guard
let exporting = privateKey.exporting
else { throw PrismAgentError.cannotFindDIDKeyPairIndex }

presentationString = try proofableCredential.presentation(
request: request.makeMessage(),
options: [
.exportableKey(exporting),
.subjectDID(subjectDID)
]
)
default:
throw UnknownError.somethingWentWrongError(customMessage: nil, underlyingErrors: nil)
}

guard
let exporting = privateKey.exporting
else { throw PrismAgentError.cannotFindDIDKeyPairIndex }

let presentationString = try proofableCredential.presentation(
request: request.makeMessage(),
options: [
.exportableKey(exporting),
.subjectDID(subjectDID)
]
)

guard let base64String = presentationString.data(using: .utf8)?.base64EncodedString() else {
throw CommonError.invalidCoding(message: "Could not encode to base64")
}

return Presentation(
body: .init(
goalCode: request.body.goalCode,
Expand Down
2 changes: 1 addition & 1 deletion AtalaPrismSDK/PrismAgent/Sources/PrismAgent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ public class PrismAgent {
}

private func firstLinkSecretSetup() async throws {
if try await pluto.getLinkSecret().first().await().first == nil {
if try await pluto.getLinkSecret().first().await() == nil {
let secret = try apollo.createNewLinkSecret()
guard let storableSecret = secret.storable else {
throw UnknownError
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public struct DownloadDataWithResolver: Downloader {

public func downloadFromEndpoint(urlOrDID: String) async throws -> Data {
let url: URL

if let did = try? castor.parseDID(str: urlOrDID) {
let document = try await castor.resolveDID(did: did)
guard
Expand All @@ -20,7 +20,7 @@ public struct DownloadDataWithResolver: Downloader {
throw CommonError.invalidURLError(url: "Could not find any URL on DID")
}
url = validUrl
} else if let validUrl = URL(string: urlOrDID) {
} else if let validUrl = URL(string: urlOrDID.replacingOccurrences(of: "host.docker.internal", with: "localhost")) {
url = validUrl
} else {
throw CommonError.invalidURLError(url: urlOrDID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,7 @@ final class SetupPrismAgentViewModelImpl: ObservableObject, SetupPrismAgentViewM
_ = try issued.attachments.compactMap {
switch $0.data {
case let data as AttachmentBase64:
let b64 = Data(base64URLEncoded: data.base64)!
let apollo = ApolloBuilder().build()
let castor = CastorBuilder(apollo: apollo).build()
let pollux = PolluxBuilder().build()
// let credential = try pollux.parseCredential(data: b64)
break
default:
return
}
Expand Down
Loading

0 comments on commit af7f39e

Please sign in to comment.