From 7a7c467c7797121f11c7dfca04a709fcac5aece1 Mon Sep 17 00:00:00 2001 From: "Ya-wen, Jeng" Date: Thu, 22 Feb 2024 20:10:07 +0800 Subject: [PATCH] feat(ios): download arkzkey and wasm from server and generate proof --- .../MoproKit.xcodeproj/project.pbxproj | 6 + .../Example/MoproKit/FileDownloader.swift | 95 +++++ .../MoproKit/KeccakSetupViewController.swift | 367 ++++++++++-------- 3 files changed, 300 insertions(+), 168 deletions(-) create mode 100644 mopro-ios/MoproKit/Example/MoproKit/FileDownloader.swift diff --git a/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj b/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj index b45a2dae..b302ba87 100644 --- a/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj +++ b/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ 2A5149C82B87616600B57A44 /* multiplier2_final.arkzkey in Resources */ = {isa = PBXBuildFile; fileRef = 2A5149C62B87616600B57A44 /* multiplier2_final.arkzkey */; }; 2A5149CA2B87618000B57A44 /* main_final.arkzkey in Resources */ = {isa = PBXBuildFile; fileRef = 2A5149C92B87618000B57A44 /* main_final.arkzkey */; }; 2A5149CB2B87618000B57A44 /* main_final.arkzkey in Resources */ = {isa = PBXBuildFile; fileRef = 2A5149C92B87618000B57A44 /* main_final.arkzkey */; }; + 2A5149CD2B8766DA00B57A44 /* FileDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5149CC2B8766DA00B57A44 /* FileDownloader.swift */; }; + 2A5149CE2B8766DA00B57A44 /* FileDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5149CC2B8766DA00B57A44 /* FileDownloader.swift */; }; 2A6E5BAF2AF499460052A601 /* CircomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A6E5BAE2AF499460052A601 /* CircomTests.swift */; }; 4384FD09A96F702A375841EE /* Pods_MoproKit_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78B0F9CBE5DD22576996A993 /* Pods_MoproKit_Tests.framework */; }; 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; }; @@ -58,6 +60,7 @@ 2A5149C32B87615900B57A44 /* keccak256_256_test_final.arkzkey */ = {isa = PBXFileReference; lastKnownFileType = file; name = keccak256_256_test_final.arkzkey; path = "../../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test_final.arkzkey"; sourceTree = ""; }; 2A5149C62B87616600B57A44 /* multiplier2_final.arkzkey */ = {isa = PBXFileReference; lastKnownFileType = file; name = multiplier2_final.arkzkey; path = "../../../../../mopro-core/examples/circom/multiplier2/target/multiplier2_final.arkzkey"; sourceTree = ""; }; 2A5149C92B87618000B57A44 /* main_final.arkzkey */ = {isa = PBXFileReference; lastKnownFileType = file; name = main_final.arkzkey; path = "../../../../../mopro-core/examples/circom/rsa/target/main_final.arkzkey"; sourceTree = ""; }; + 2A5149CC2B8766DA00B57A44 /* FileDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileDownloader.swift; sourceTree = ""; }; 2A6E5BAE2AF499460052A601 /* CircomTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircomTests.swift; sourceTree = ""; }; 47F8ADB0AC4168C6E874818D /* MoproKit.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = MoproKit.podspec; path = ../MoproKit.podspec; sourceTree = ""; }; 5DAF212A114DFA0C9F4282B2 /* Pods-MoproKit_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MoproKit_Tests.debug.xcconfig"; path = "Target Support Files/Pods-MoproKit_Tests/Pods-MoproKit_Tests.debug.xcconfig"; sourceTree = ""; }; @@ -146,6 +149,7 @@ CEB804572AFF81BF0063F091 /* RSAViewController.swift */, E6E6F42D2B5860F7002F5F18 /* AnonAadhaarViewControllerNew.swift */, E69338632AFFDB1A00B80312 /* AnonAadhaarViewController.swift */, + 2A5149CC2B8766DA00B57A44 /* FileDownloader.swift */, CEB804552AFF81AF0063F091 /* KeccakZkeyViewController.swift */, E6D848582B766C8C00DBAF30 /* ComplexZkeyViewController.swift */, CEB8044F2AFF81960063F091 /* KeccakSetupViewController.swift */, @@ -441,6 +445,7 @@ CEB804502AFF81960063F091 /* KeccakSetupViewController.swift in Sources */, E6D848592B766C8C00DBAF30 /* ComplexZkeyViewController.swift in Sources */, E6E6F42E2B5860F7002F5F18 /* AnonAadhaarViewControllerNew.swift in Sources */, + 2A5149CD2B8766DA00B57A44 /* FileDownloader.swift in Sources */, 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, E69338642AFFDB1A00B80312 /* AnonAadhaarViewController.swift in Sources */, ); @@ -450,6 +455,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2A5149CE2B8766DA00B57A44 /* FileDownloader.swift in Sources */, 2A6E5BAF2AF499460052A601 /* CircomTests.swift in Sources */, 2A418AB02AF4B1200004B747 /* CircomUITests.swift in Sources */, ); diff --git a/mopro-ios/MoproKit/Example/MoproKit/FileDownloader.swift b/mopro-ios/MoproKit/Example/MoproKit/FileDownloader.swift new file mode 100644 index 00000000..b6560353 --- /dev/null +++ b/mopro-ios/MoproKit/Example/MoproKit/FileDownloader.swift @@ -0,0 +1,95 @@ +// +// FileDownloader.swift +// MoproKit +// +// Copyright © 2024 CocoaPods. All rights reserved. +// + +import Foundation + +class FileDownloader { + + static func loadFileSync(url: URL, completion: @escaping (String?, Error?) -> Void) + { + let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + + let destinationUrl = documentsUrl.appendingPathComponent(url.lastPathComponent) + + if FileManager().fileExists(atPath: destinationUrl.path) + { + print("File already exists [\(destinationUrl.path)]") + completion(destinationUrl.path, nil) + } + else if let dataFromURL = NSData(contentsOf: url) + { + if dataFromURL.write(to: destinationUrl, atomically: true) + { + print("file saved [\(destinationUrl.path)]") + completion(destinationUrl.path, nil) + } + else + { + print("error saving file") + let error = NSError(domain:"Error saving file", code:1001, userInfo:nil) + completion(destinationUrl.path, error) + } + } + else + { + let error = NSError(domain:"Error downloading file", code:1002, userInfo:nil) + completion(destinationUrl.path, error) + } + } + + static func loadFileAsync(url: URL, completion: @escaping (String?, Error?) -> Void) + { + let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + + let destinationUrl = documentsUrl.appendingPathComponent(url.lastPathComponent) + + if FileManager().fileExists(atPath: destinationUrl.path) + { + print("File already exists [\(destinationUrl.path)]") + completion(destinationUrl.path, nil) + } + else + { + let session = URLSession(configuration: URLSessionConfiguration.default, delegate: nil, delegateQueue: nil) + var request = URLRequest(url: url) + request.httpMethod = "GET" + let task = session.dataTask(with: request, completionHandler: + { + data, response, error in + if error == nil + { + if let response = response as? HTTPURLResponse + { + if response.statusCode == 200 + { + if let data = data + { + if let _ = try? data.write(to: destinationUrl, options: Data.WritingOptions.atomic) + { + completion(destinationUrl.path, error) + } + else + { + completion(destinationUrl.path, error) + } + } + else + { + completion(destinationUrl.path, error) + } + } + } + } + else + { + completion(destinationUrl.path, error) + } + }) + task.resume() + } + } +} diff --git a/mopro-ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift b/mopro-ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift index 14df1c52..558f9224 100644 --- a/mopro-ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift +++ b/mopro-ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift @@ -6,189 +6,220 @@ // Copyright (c) 2023 1552237. All rights reserved. // -import UIKit import MoproKit +import UIKit class KeccakSetupViewController: UIViewController { - var setupButton = UIButton(type: .system) - var proveButton = UIButton(type: .system) - var verifyButton = UIButton(type: .system) - var textView = UITextView() - - let moproCircom = MoproKit.MoproCircom() - var generatedProof: Data? - var publicInputs: Data? - - override func viewDidLoad() { - super.viewDidLoad() - - // Set title - let title = UILabel() - title.text = "Keccak256 (setup)" - title.textColor = .white - title.textAlignment = .center - navigationItem.titleView = title - navigationController?.navigationBar.isHidden = false - navigationController?.navigationBar.prefersLargeTitles = true - - // view.backgroundColor = .white - // navigationController?.navigationBar.prefersLargeTitles = true - // navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black] - // navigationController?.navigationBar.barTintColor = UIColor.white // or any other contrasting color - // self.title = "Keccak256 (setup)" - - setupUI() + let arkzkeyUrl = URL(string: "https://mopro.vivianjeng.xyz/keccak256_256_test_final.arkzkey") + let wasmUrl = URL(string: "https://mopro.vivianjeng.xyz/keccak256_256_test.wasm") + + var downloadButton = UIButton(type: .system) + var setupButton = UIButton(type: .system) + var proveButton = UIButton(type: .system) + var verifyButton = UIButton(type: .system) + var textView = UITextView() + + let moproCircom = MoproKit.MoproCircom() + var generatedProof: Data? + var publicInputs: Data? + + override func viewDidLoad() { + super.viewDidLoad() + + // Set title + let title = UILabel() + title.text = "Keccak256 (setup)" + title.textColor = .white + title.textAlignment = .center + navigationItem.titleView = title + navigationController?.navigationBar.isHidden = false + navigationController?.navigationBar.prefersLargeTitles = true + + // view.backgroundColor = .white + // navigationController?.navigationBar.prefersLargeTitles = true + // navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black] + // navigationController?.navigationBar.barTintColor = UIColor.white // or any other contrasting color + // self.title = "Keccak256 (setup)" + + setupUI() + } + + func setupUI() { + downloadButton.setTitle("Download Ark Zkey", for: .normal) + setupButton.setTitle("Setup", for: .normal) + proveButton.setTitle("Prove", for: .normal) + verifyButton.setTitle("Verify", for: .normal) + + textView.isEditable = false + + //self.title = "Keccak256 (setup)" + //view.backgroundColor = .black + + // Setup actions for buttons + downloadButton.addTarget(self, action: #selector(runDownloadAction), for: .touchUpInside) + setupButton.addTarget(self, action: #selector(runSetupAction), for: .touchUpInside) + proveButton.addTarget(self, action: #selector(runProveAction), for: .touchUpInside) + verifyButton.addTarget(self, action: #selector(runVerifyAction), for: .touchUpInside) + + downloadButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) + setupButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) + proveButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) + verifyButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) + + let stackView = UIStackView(arrangedSubviews: [ + downloadButton, setupButton, proveButton, verifyButton, textView, + ]) + stackView.axis = .vertical + stackView.spacing = 10 + stackView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(stackView) + + // Make text view visible + textView.heightAnchor.constraint(equalToConstant: 200).isActive = true + + NSLayoutConstraint.activate([ + stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor), + stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + ]) + } + + @objc func runDownloadAction() { + let arkzkeyStart = CFAbsoluteTimeGetCurrent() + FileDownloader.loadFileAsync(url: self.arkzkeyUrl!) { (path, error) in + print("Ark zkey File downloaded to : \(path!)") + let arkzkeyEnd = CFAbsoluteTimeGetCurrent() + print("Download ark key took:", arkzkeyEnd - arkzkeyStart) } - func setupUI() { - setupButton.setTitle("Setup", for: .normal) - proveButton.setTitle("Prove", for: .normal) - verifyButton.setTitle("Verify", for: .normal) - - textView.isEditable = false - - //self.title = "Keccak256 (setup)" - //view.backgroundColor = .black - - // Setup actions for buttons - setupButton.addTarget(self, action: #selector(runSetupAction), for: .touchUpInside) - proveButton.addTarget(self, action: #selector(runProveAction), for: .touchUpInside) - verifyButton.addTarget(self, action: #selector(runVerifyAction), for: .touchUpInside) - - setupButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) - proveButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) - verifyButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) - - let stackView = UIStackView(arrangedSubviews: [setupButton, proveButton, verifyButton, textView]) - stackView.axis = .vertical - stackView.spacing = 10 - stackView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(stackView) - - // Make text view visible - textView.heightAnchor.constraint(equalToConstant: 200).isActive = true - - NSLayoutConstraint.activate([ - stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor), - stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor), - stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), - stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20) - ]) + let wasmStart = CFAbsoluteTimeGetCurrent() + FileDownloader.loadFileAsync(url: self.wasmUrl!) { (path, error) in + print("wasm File downloaded to : \(path!)") + let wasmEnd = CFAbsoluteTimeGetCurrent() + print("Download wasm took:", wasmEnd - wasmStart) } - @objc func runSetupAction() { - // Logic for setup - if let arkzkeyPath = Bundle.main.path(forResource: "keccak256_256_test_final", ofType: "arkzkey"), - let wasmPath = Bundle.main.path(forResource: "keccak256_256_test", ofType: "wasm") { - - // Multiplier example - // if let wasmPath = Bundle.main.path(forResource: "multiplier2", ofType: "wasm"), - // let r1csPath = Bundle.main.path(forResource: "multiplier2", ofType: "r1cs") { - - do { - textView.text += "Initializing library\n" - // Record start time - let start = CFAbsoluteTimeGetCurrent() - - try moproCircom.initialize(arkzkeyPath: arkzkeyPath, wasmPath: wasmPath) - proveButton.isEnabled = true // Enable the Prove button upon successful setup - - // Record end time and compute duration - let end = CFAbsoluteTimeGetCurrent() - let timeTaken = end - start - - textView.text += "Initializing arkzkey and wasm took \(timeTaken) seconds.\n" - } catch let error as MoproError { - print("MoproError: \(error)") - } catch { - print("Unexpected error: \(error)") - } - } else { - print("Error getting paths for resources") - } + } + + @objc func runSetupAction() { + // Logic for setup + if let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) + .first + { + + let arkzkeyPath = documentsUrl.appendingPathComponent((arkzkeyUrl!).lastPathComponent) + let wasmPath = documentsUrl.appendingPathComponent((wasmUrl!).lastPathComponent) + + // Multiplier example + // if let wasmPath = Bundle.main.path(forResource: "multiplier2", ofType: "wasm"), + // let r1csPath = Bundle.main.path(forResource: "multiplier2", ofType: "r1cs") { + + do { + textView.text += "Initializing library\n" + // Record start time + let start = CFAbsoluteTimeGetCurrent() + + try moproCircom.initialize(arkzkeyPath: arkzkeyPath.path, wasmPath: wasmPath.path) + proveButton.isEnabled = true // Enable the Prove button upon successful setup + + // Record end time and compute duration + let end = CFAbsoluteTimeGetCurrent() + let timeTaken = end - start + + textView.text += "Initializing arkzkey and wasm took \(timeTaken) seconds.\n" + } catch let error as MoproError { + print("MoproError: \(error)") + } catch { + print("Unexpected error: \(error)") + } + } else { + print("Error getting paths for resources") } + } - @objc func runProveAction() { - // Logic for prove - guard proveButton.isEnabled else { - print("Setup is not completed yet.") - return - } - do { - // Prepare inputs - let inputVec: [UInt8] = [ - 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ] - let bits = bytesToBits(bytes: inputVec) - var inputs = [String: [String]]() - inputs["in"] = bits - - // Multiplier example - // var inputs = [String: [String]]() - // let a = 3 - // let b = 5 - // inputs["a"] = [String(a)] - // inputs["b"] = [String(b)] - - // Record start time - let start = CFAbsoluteTimeGetCurrent() - - // Generate Proof - let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs) - assert(!generateProofResult.proof.isEmpty, "Proof should not be empty") - - // Record end time and compute duration - let end = CFAbsoluteTimeGetCurrent() - let timeTaken = end - start - - // Store the generated proof and public inputs for later verification - generatedProof = generateProofResult.proof - publicInputs = generateProofResult.inputs - - textView.text += "Proof generation took \(timeTaken) seconds.\n" - verifyButton.isEnabled = true // Enable the Verify button once proof has been generated - } catch let error as MoproError { - print("MoproError: \(error)") - } catch { - print("Unexpected error: \(error)") - } + @objc func runProveAction() { + // Logic for prove + guard proveButton.isEnabled else { + print("Setup is not completed yet.") + return } - - @objc func runVerifyAction() { - // Logic for verify - guard let proof = generatedProof, - let publicInputs = publicInputs else { - print("Setup is not completed or proof has not been generated yet.") - return - } - do { - // Verify Proof - let isValid = try moproCircom.verifyProof(proof: proof, publicInput: publicInputs) - assert(isValid, "Proof verification should succeed") - - textView.text += "Proof verification succeeded.\n" - } catch let error as MoproError { - print("MoproError: \(error)") - } catch { - print("Unexpected error: \(error)") - } + do { + // Prepare inputs + let inputVec: [UInt8] = [ + 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + ] + let bits = bytesToBits(bytes: inputVec) + var inputs = [String: [String]]() + inputs["in"] = bits + + // Multiplier example + // var inputs = [String: [String]]() + // let a = 3 + // let b = 5 + // inputs["a"] = [String(a)] + // inputs["b"] = [String(b)] + + // Record start time + let start = CFAbsoluteTimeGetCurrent() + + // Generate Proof + let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs) + assert(!generateProofResult.proof.isEmpty, "Proof should not be empty") + + // Record end time and compute duration + let end = CFAbsoluteTimeGetCurrent() + let timeTaken = end - start + + // Store the generated proof and public inputs for later verification + generatedProof = generateProofResult.proof + publicInputs = generateProofResult.inputs + + textView.text += "Proof generation took \(timeTaken) seconds.\n" + verifyButton.isEnabled = true // Enable the Verify button once proof has been generated + } catch let error as MoproError { + print("MoproError: \(error)") + } catch { + print("Unexpected error: \(error)") } - - override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - // Dispose of any resources that can be recreated. + } + + @objc func runVerifyAction() { + // Logic for verify + guard let proof = generatedProof, + let publicInputs = publicInputs + else { + print("Setup is not completed or proof has not been generated yet.") + return + } + do { + // Verify Proof + let isValid = try moproCircom.verifyProof(proof: proof, publicInput: publicInputs) + assert(isValid, "Proof verification should succeed") + + textView.text += "Proof verification succeeded.\n" + } catch let error as MoproError { + print("MoproError: \(error)") + } catch { + print("Unexpected error: \(error)") } + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } } func bytesToBits(bytes: [UInt8]) -> [String] { - var bits = [String]() - for byte in bytes { - for j in 0..<8 { - let bit = (byte >> j) & 1 - bits.append(String(bit)) - } + var bits = [String]() + for byte in bytes { + for j in 0..<8 { + let bit = (byte >> j) & 1 + bits.append(String(bit)) } - return bits + } + return bits }