From 82d5840e385e84876bd3628d6ec7d908f8934f42 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sun, 14 Jan 2024 19:45:19 +0100 Subject: [PATCH 01/12] working by compiling and coping /mopro-core and /mopro-ios to /ios/mopro - TODO clean and understand exactly what to copy --- app/App.tsx | 30 + app/ios/Podfile | 17 +- app/ios/Podfile.lock | 7 +- .../ProofOfPassport.xcodeproj/project.pbxproj | 125 +-- .../ProofOfPassport/LaunchScreen.storyboard | 17 +- app/ios/Prover.m | 22 + app/ios/Prover.swift | 173 ++++ app/ios/mopro/mopro-core/.gitignore | 14 + app/ios/mopro/mopro-core/Cargo.toml | 51 ++ app/ios/mopro/mopro-core/README.md | 47 + app/ios/mopro/mopro-core/build.rs | 104 +++ app/ios/mopro/mopro-core/examples/circom.rs | 41 + .../mopro-core/examples/circom/.gitignore | 2 + .../mopro-core/examples/circom/README.md | 9 + .../examples/circom/keccak256/.gitignore | 2 + .../examples/circom/keccak256/README.md | 7 + .../examples/circom/keccak256/keccak.circom | 186 ++++ .../keccak256/keccak256_256_test.circom | 5 + .../circom/keccak256/package-lock.json | 21 + .../examples/circom/keccak256/package.json | 9 + .../circom/keccak256/permutations.circom | 799 ++++++++++++++++ .../examples/circom/keccak256/utils.circom | 118 +++ .../examples/circom/multiplier2/.gitignore | 2 + .../examples/circom/multiplier2/compile.sh | 4 + .../circom/multiplier2/multiplier2.circom | 16 + .../mopro-core/examples/circom/rsa/.gitignore | 2 + .../mopro-core/examples/circom/rsa/LICENSE | 21 + .../mopro-core/examples/circom/rsa/README.md | 5 + .../examples/circom/rsa/bigint.circom | 561 ++++++++++++ .../examples/circom/rsa/bigint_func.circom | 442 +++++++++ .../mopro-core/examples/circom/rsa/fp.circom | 144 +++ .../examples/circom/rsa/main.circom | 5 + .../examples/circom/rsa/package-lock.json | 21 + .../mopro-core/examples/circom/rsa/rsa.circom | 156 ++++ .../examples/circom/scripts/compile.sh | 19 + .../circom/scripts/generate_arkzkey.sh | 41 + .../examples/circom/scripts/trusted_setup.sh | 47 + app/ios/mopro/mopro-core/src/lib.rs | 8 + .../mopro-core/src/middleware/circom/mod.rs | 860 ++++++++++++++++++ .../src/middleware/circom/serialization.rs | 106 +++ .../mopro-core/src/middleware/circom/utils.rs | 33 + .../mopro/mopro-core/src/middleware/mod.rs | 1 + app/ios/mopro/mopro-ios/.gitignore | 35 + .../MoproBindings.xcframework/Info.plist | 43 + .../ios-arm64-simulator/Headers/moproFFI.h | 96 ++ .../Headers/moproFFI.modulemap | 6 + .../ios-arm64-simulator/Sources/mopro.swift | 411 +++++++++ .../ios-arm64/Headers/moproFFI.h | 96 ++ .../ios-arm64/Headers/moproFFI.modulemap | 6 + .../ios-arm64/Sources/mopro.swift | 411 +++++++++ app/ios/mopro/mopro-ios/MoproKit/.gitignore | 36 + app/ios/mopro/mopro-ios/MoproKit/.travis.yml | 14 + .../mopro-ios/MoproKit/Bindings/mopro.swift | 805 ++++++++++++++++ .../MoproKit.xcodeproj/project.pbxproj | 670 ++++++++++++++ .../xcschemes/MoproKit-Example.xcscheme | 129 +++ .../MoproKit/AnonAadhaarViewController.swift | 192 ++++ .../Example/MoproKit/AppDelegate.swift | 52 ++ .../MoproKit/Base.lproj/LaunchScreen.xib | 46 + .../MoproKit/Base.lproj/Main.storyboard | 30 + .../AppIcon.appiconset/Contents.json | 53 ++ .../MoproKit/Example/MoproKit/Info.plist | 39 + .../MoproKit/KeccakSetupViewController.swift | 186 ++++ .../MoproKit/KeccakZkeyViewController.swift | 147 +++ .../Example/MoproKit/RSAViewController.swift | 235 +++++ .../Example/MoproKit/ViewController.swift | 100 ++ .../mopro/mopro-ios/MoproKit/Example/Podfile | 24 + .../MoproKit/Example/Tests/CircomTests.swift | 109 +++ .../Example/Tests/CircomUITests.swift | 13 + .../MoproKit/Example/Tests/Info.plist | 24 + .../mopro-ios/MoproKit/Include/moproFFI.h | 238 +++++ app/ios/mopro/mopro-ios/MoproKit/LICENSE | 19 + .../mopro/mopro-ios/MoproKit/Libs/.gitkeep | 0 .../mopro/mopro-ios/MoproKit/MoproKit.podspec | 50 + .../MoproKit/MoproKit/Assets/.gitkeep | 0 app/ios/mopro/mopro-ios/MoproKit/README.md | 29 + .../MoproKit/Resources/moproFFI.modulemap | 6 + .../mopro/mopro-ios/MoproKit/_Pods.xcodeproj | 1 + app/ios/mopro/mopro-ios/README.md | 51 ++ app/ios/mopro/mopro-ios/Sources/mopro.swift | 411 +++++++++ app/ios/mopro/mopro-ios/headers/moproFFI.h | 96 ++ .../mopro-ios/headers/moproFFI.modulemap | 6 + 81 files changed, 9155 insertions(+), 60 deletions(-) create mode 100644 app/ios/Prover.m create mode 100644 app/ios/Prover.swift create mode 100644 app/ios/mopro/mopro-core/.gitignore create mode 100644 app/ios/mopro/mopro-core/Cargo.toml create mode 100644 app/ios/mopro/mopro-core/README.md create mode 100644 app/ios/mopro/mopro-core/build.rs create mode 100644 app/ios/mopro/mopro-core/examples/circom.rs create mode 100644 app/ios/mopro/mopro-core/examples/circom/.gitignore create mode 100644 app/ios/mopro/mopro-core/examples/circom/README.md create mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/.gitignore create mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/README.md create mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/keccak.circom create mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/keccak256_256_test.circom create mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/package-lock.json create mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/package.json create mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/permutations.circom create mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/utils.circom create mode 100644 app/ios/mopro/mopro-core/examples/circom/multiplier2/.gitignore create mode 100755 app/ios/mopro/mopro-core/examples/circom/multiplier2/compile.sh create mode 100644 app/ios/mopro/mopro-core/examples/circom/multiplier2/multiplier2.circom create mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/.gitignore create mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/LICENSE create mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/README.md create mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/bigint.circom create mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/bigint_func.circom create mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/fp.circom create mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/main.circom create mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/package-lock.json create mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/rsa.circom create mode 100755 app/ios/mopro/mopro-core/examples/circom/scripts/compile.sh create mode 100755 app/ios/mopro/mopro-core/examples/circom/scripts/generate_arkzkey.sh create mode 100755 app/ios/mopro/mopro-core/examples/circom/scripts/trusted_setup.sh create mode 100644 app/ios/mopro/mopro-core/src/lib.rs create mode 100644 app/ios/mopro/mopro-core/src/middleware/circom/mod.rs create mode 100644 app/ios/mopro/mopro-core/src/middleware/circom/serialization.rs create mode 100644 app/ios/mopro/mopro-core/src/middleware/circom/utils.rs create mode 100644 app/ios/mopro/mopro-core/src/middleware/mod.rs create mode 100644 app/ios/mopro/mopro-ios/.gitignore create mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/Info.plist create mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.h create mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.modulemap create mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Sources/mopro.swift create mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.h create mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.modulemap create mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Sources/mopro.swift create mode 100644 app/ios/mopro/mopro-ios/MoproKit/.gitignore create mode 100644 app/ios/mopro/mopro-ios/MoproKit/.travis.yml create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Bindings/mopro.swift create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/xcshareddata/xcschemes/MoproKit-Example.xcscheme create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AnonAadhaarViewController.swift create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AppDelegate.swift create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/LaunchScreen.xib create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/Main.storyboard create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Info.plist create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakZkeyViewController.swift create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/RSAViewController.swift create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/ViewController.swift create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/Podfile create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomTests.swift create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomUITests.swift create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Example/Tests/Info.plist create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Include/moproFFI.h create mode 100644 app/ios/mopro/mopro-ios/MoproKit/LICENSE create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Libs/.gitkeep create mode 100644 app/ios/mopro/mopro-ios/MoproKit/MoproKit.podspec create mode 100644 app/ios/mopro/mopro-ios/MoproKit/MoproKit/Assets/.gitkeep create mode 100644 app/ios/mopro/mopro-ios/MoproKit/README.md create mode 100644 app/ios/mopro/mopro-ios/MoproKit/Resources/moproFFI.modulemap create mode 120000 app/ios/mopro/mopro-ios/MoproKit/_Pods.xcodeproj create mode 100644 app/ios/mopro/mopro-ios/README.md create mode 100644 app/ios/mopro/mopro-ios/Sources/mopro.swift create mode 100644 app/ios/mopro/mopro-ios/headers/moproFFI.h create mode 100644 app/ios/mopro/mopro-ios/headers/moproFFI.modulemap diff --git a/app/App.tsx b/app/App.tsx index 4231f77df..947aa83d1 100644 --- a/app/App.tsx +++ b/app/App.tsx @@ -650,6 +650,36 @@ function App(): JSX.Element { Call arkworks lib {testResult && {testResult}} + + + + + + diff --git a/app/ios/Podfile b/app/ios/Podfile index 0c644c887..4c0f60b29 100644 --- a/app/ios/Podfile +++ b/app/ios/Podfile @@ -1,3 +1,5 @@ +use_frameworks! + # Resolve react_native_pods.rb with node to allow for hoisting require Pod::Executable.execute_command('node', ['-p', 'require.resolve( @@ -5,7 +7,7 @@ require Pod::Executable.execute_command('node', ['-p', {paths: [process.argv[1]]}, )', __dir__]).strip -platform :ios, min_ios_version_supported +platform :ios, '13.0' prepare_react_native_project! # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. @@ -33,6 +35,11 @@ target 'ProofOfPassport' do use_frameworks! pod 'NFCPassportReader', git: 'https://github.com/0xturboblitz/NFCPassportReader.git', commit: '07b3662702834676b547718998fa377fe5f00776' + pod 'MoproKit', :path => './mopro/mopro-ios/MoproKit' + + # pod 'MoproKit', :podspec => 'https://raw.githubusercontent.com/0xturboblitz/mopro/main/MoproKit.podspec' + # pod 'MoproKit', git: 'https://github.com/0xturboblitz/MoproKit.git' + use_react_native!( :path => config[:reactNativePath], @@ -54,6 +61,14 @@ target 'ProofOfPassport' do end post_install do |installer| + installer.generated_projects.each do |project| + project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' + end + end + end + # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 react_native_post_install( installer, diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index 548a67239..579d60f9a 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -11,6 +11,7 @@ PODS: - ReactCommon/turbomodule/core (= 0.72.3) - fmt (6.2.1) - glog (0.3.5) + - MoproKit (0.1.0) - NFCPassportReader (2.0.3): - OpenSSL-Universal (= 1.1.1100) - OpenSSL-Universal (1.1.1100) @@ -401,6 +402,7 @@ DEPENDENCIES: - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) + - MoproKit (from `./mopro/mopro-ios/MoproKit`) - NFCPassportReader (from `https://github.com/0xturboblitz/NFCPassportReader.git`, commit `07b3662702834676b547718998fa377fe5f00776`) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) @@ -455,6 +457,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/React/FBReactNativeSpec" glog: :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" + MoproKit: + :path: "./mopro/mopro-ios/MoproKit" NFCPassportReader: :commit: 07b3662702834676b547718998fa377fe5f00776 :git: https://github.com/0xturboblitz/NFCPassportReader.git @@ -539,6 +543,7 @@ SPEC CHECKSUMS: FBReactNativeSpec: c6bd9e179757b3c0ecf815864fae8032377903ef fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b + MoproKit: d1faf8f9495e8e84d085f6c4e57e36f951e6f07e NFCPassportReader: a160b80e3df3b5325c13902f90405f5eef7520b3 OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 @@ -577,6 +582,6 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Yoga: 8796b55dba14d7004f980b54bcc9833ee45b28ce -PODFILE CHECKSUM: acc6adf64ac3a7e8523f30353c4753716d98ea06 +PODFILE CHECKSUM: 26d95ec475f9d1b46c82166c123fd279bf69045f COCOAPODS: 1.14.3 diff --git a/app/ios/ProofOfPassport.xcodeproj/project.pbxproj b/app/ios/ProofOfPassport.xcodeproj/project.pbxproj index 39d7f817d..f45272981 100644 --- a/app/ios/ProofOfPassport.xcodeproj/project.pbxproj +++ b/app/ios/ProofOfPassport.xcodeproj/project.pbxproj @@ -8,15 +8,18 @@ /* Begin PBXBuildFile section */ 00E356F31AD99517003FC87E /* ProofOfPassportTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ProofOfPassportTests.m */; }; + 05A0773C2B5332040037E489 /* mopro in Resources */ = {isa = PBXBuildFile; fileRef = 05A0773B2B5332040037E489 /* mopro */; }; + 05EDEDC62B52D25D00AA51AD /* Prover.m in Sources */ = {isa = PBXBuildFile; fileRef = 05EDEDC42B52D25D00AA51AD /* Prover.m */; }; + 05EDEDC72B52D25D00AA51AD /* Prover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05EDEDC52B52D25D00AA51AD /* Prover.swift */; }; + 0651723A94C70A2B31E3E4F8 /* Pods_ProofOfPassport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAAF621B99F62C9ED35AA07 /* Pods_ProofOfPassport.framework */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 1ADA5CBFFFB043C12B3C4011 /* Pods_ProofOfPassport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F81894AE401F61E2393104D /* Pods_ProofOfPassport.framework */; }; + 75E785E6A486EA107852C8A6 /* Pods_ProofOfPassport_ProofOfPassportTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFAE0EE7E1942128592D0CC4 /* Pods_ProofOfPassport_ProofOfPassportTests.framework */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; 905B70052A72767900AFA232 /* PassportReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 905B70042A72767900AFA232 /* PassportReader.swift */; }; 905B70072A72774000AFA232 /* PassportReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 905B70062A72774000AFA232 /* PassportReader.m */; }; 905B700B2A72A5E900AFA232 /* masterList.pem in Resources */ = {isa = PBXBuildFile; fileRef = 905B700A2A72A5E900AFA232 /* masterList.pem */; }; - D5B4CD952178B51C14F77614 /* Pods_ProofOfPassport_ProofOfPassportTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455B3F561C1D3D833AB15B26 /* Pods_ProofOfPassport_ProofOfPassportTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -33,24 +36,28 @@ 00E356EE1AD99517003FC87E /* ProofOfPassportTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProofOfPassportTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 00E356F21AD99517003FC87E /* ProofOfPassportTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProofOfPassportTests.m; sourceTree = ""; }; - 0D05C085F8CBAC104F72E160 /* Pods-ProofOfPassport-ProofOfPassportTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProofOfPassport-ProofOfPassportTests.release.xcconfig"; path = "Target Support Files/Pods-ProofOfPassport-ProofOfPassportTests/Pods-ProofOfPassport-ProofOfPassportTests.release.xcconfig"; sourceTree = ""; }; + 05A0773B2B5332040037E489 /* mopro */ = {isa = PBXFileReference; lastKnownFileType = folder; path = mopro; sourceTree = ""; }; + 05A0773D2B5333CE0037E489 /* MoproKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MoproKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 05EDEDC42B52D25D00AA51AD /* Prover.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Prover.m; sourceTree = ""; }; + 05EDEDC52B52D25D00AA51AD /* Prover.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Prover.swift; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* ProofOfPassport.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ProofOfPassport.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ProofOfPassport/AppDelegate.h; sourceTree = ""; }; 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = ProofOfPassport/AppDelegate.mm; sourceTree = ""; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ProofOfPassport/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ProofOfPassport/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ProofOfPassport/main.m; sourceTree = ""; }; - 26A432E0434B89485C7E3765 /* Pods-ProofOfPassport.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProofOfPassport.debug.xcconfig"; path = "Target Support Files/Pods-ProofOfPassport/Pods-ProofOfPassport.debug.xcconfig"; sourceTree = ""; }; - 455B3F561C1D3D833AB15B26 /* Pods_ProofOfPassport_ProofOfPassportTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ProofOfPassport_ProofOfPassportTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 22FDF2ADA5789E09558ADB4E /* Pods-ProofOfPassport-ProofOfPassportTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProofOfPassport-ProofOfPassportTests.release.xcconfig"; path = "Target Support Files/Pods-ProofOfPassport-ProofOfPassportTests/Pods-ProofOfPassport-ProofOfPassportTests.release.xcconfig"; sourceTree = ""; }; + 2B01EC4981C171CA304E6D2B /* Pods-ProofOfPassport.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProofOfPassport.release.xcconfig"; path = "Target Support Files/Pods-ProofOfPassport/Pods-ProofOfPassport.release.xcconfig"; sourceTree = ""; }; + 3DAAF621B99F62C9ED35AA07 /* Pods_ProofOfPassport.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ProofOfPassport.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = ProofOfPassport/LaunchScreen.storyboard; sourceTree = ""; }; 905B70032A72767800AFA232 /* ProofOfPassport-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ProofOfPassport-Bridging-Header.h"; sourceTree = ""; }; 905B70042A72767900AFA232 /* PassportReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassportReader.swift; sourceTree = ""; }; 905B70062A72774000AFA232 /* PassportReader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PassportReader.m; sourceTree = ""; }; 905B70082A729CD400AFA232 /* ProofOfPassport.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = ProofOfPassport.entitlements; path = ProofOfPassport/ProofOfPassport.entitlements; sourceTree = ""; }; 905B700A2A72A5E900AFA232 /* masterList.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = masterList.pem; path = ProofOfPassport/masterList.pem; sourceTree = ""; }; - 9F81894AE401F61E2393104D /* Pods_ProofOfPassport.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ProofOfPassport.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - A1B7A34F7E4C3F2D19C5D973 /* Pods-ProofOfPassport.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProofOfPassport.release.xcconfig"; path = "Target Support Files/Pods-ProofOfPassport/Pods-ProofOfPassport.release.xcconfig"; sourceTree = ""; }; - BCC787E0FDFB928F9DA23E3F /* Pods-ProofOfPassport-ProofOfPassportTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProofOfPassport-ProofOfPassportTests.debug.xcconfig"; path = "Target Support Files/Pods-ProofOfPassport-ProofOfPassportTests/Pods-ProofOfPassport-ProofOfPassportTests.debug.xcconfig"; sourceTree = ""; }; + 918081ECA23C8F232594E334 /* Pods-ProofOfPassport-ProofOfPassportTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProofOfPassport-ProofOfPassportTests.debug.xcconfig"; path = "Target Support Files/Pods-ProofOfPassport-ProofOfPassportTests/Pods-ProofOfPassport-ProofOfPassportTests.debug.xcconfig"; sourceTree = ""; }; + CE0B085EC65BAFEB61DD9C49 /* Pods-ProofOfPassport.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProofOfPassport.debug.xcconfig"; path = "Target Support Files/Pods-ProofOfPassport/Pods-ProofOfPassport.debug.xcconfig"; sourceTree = ""; }; + CFAE0EE7E1942128592D0CC4 /* Pods_ProofOfPassport_ProofOfPassportTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ProofOfPassport_ProofOfPassportTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ @@ -59,7 +66,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D5B4CD952178B51C14F77614 /* Pods_ProofOfPassport_ProofOfPassportTests.framework in Frameworks */, + 75E785E6A486EA107852C8A6 /* Pods_ProofOfPassport_ProofOfPassportTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -67,7 +74,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1ADA5CBFFFB043C12B3C4011 /* Pods_ProofOfPassport.framework in Frameworks */, + 0651723A94C70A2B31E3E4F8 /* Pods_ProofOfPassport.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -94,6 +101,8 @@ 13B07FAE1A68108700A75B9A /* ProofOfPassport */ = { isa = PBXGroup; children = ( + 05EDEDC42B52D25D00AA51AD /* Prover.m */, + 05EDEDC52B52D25D00AA51AD /* Prover.swift */, 905B700A2A72A5E900AFA232 /* masterList.pem */, 905B70082A729CD400AFA232 /* ProofOfPassport.entitlements */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, @@ -103,6 +112,7 @@ 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, 13B07FB71A68108700A75B9A /* main.m */, 905B70042A72767900AFA232 /* PassportReader.swift */, + 05A0773B2B5332040037E489 /* mopro */, 905B70032A72767800AFA232 /* ProofOfPassport-Bridging-Header.h */, 905B70062A72774000AFA232 /* PassportReader.m */, ); @@ -112,9 +122,10 @@ 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { isa = PBXGroup; children = ( + 05A0773D2B5333CE0037E489 /* MoproKit.framework */, ED297162215061F000B7C4FE /* JavaScriptCore.framework */, - 9F81894AE401F61E2393104D /* Pods_ProofOfPassport.framework */, - 455B3F561C1D3D833AB15B26 /* Pods_ProofOfPassport_ProofOfPassportTests.framework */, + 3DAAF621B99F62C9ED35AA07 /* Pods_ProofOfPassport.framework */, + CFAE0EE7E1942128592D0CC4 /* Pods_ProofOfPassport_ProofOfPassportTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -153,10 +164,10 @@ BBD78D7AC51CEA395F1C20DB /* Pods */ = { isa = PBXGroup; children = ( - 26A432E0434B89485C7E3765 /* Pods-ProofOfPassport.debug.xcconfig */, - A1B7A34F7E4C3F2D19C5D973 /* Pods-ProofOfPassport.release.xcconfig */, - BCC787E0FDFB928F9DA23E3F /* Pods-ProofOfPassport-ProofOfPassportTests.debug.xcconfig */, - 0D05C085F8CBAC104F72E160 /* Pods-ProofOfPassport-ProofOfPassportTests.release.xcconfig */, + CE0B085EC65BAFEB61DD9C49 /* Pods-ProofOfPassport.debug.xcconfig */, + 2B01EC4981C171CA304E6D2B /* Pods-ProofOfPassport.release.xcconfig */, + 918081ECA23C8F232594E334 /* Pods-ProofOfPassport-ProofOfPassportTests.debug.xcconfig */, + 22FDF2ADA5789E09558ADB4E /* Pods-ProofOfPassport-ProofOfPassportTests.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -168,11 +179,11 @@ isa = PBXNativeTarget; buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ProofOfPassportTests" */; buildPhases = ( - 2CEEDB4F696405D4E4B0CA04 /* [CP] Check Pods Manifest.lock */, + 30EF76FEB71F2239D12E988C /* [CP] Check Pods Manifest.lock */, 00E356EA1AD99517003FC87E /* Sources */, 00E356EB1AD99517003FC87E /* Frameworks */, 00E356EC1AD99517003FC87E /* Resources */, - 4786C99960C198CBC0841652 /* [CP] Embed Pods Frameworks */, + 3407A7677F910117EC6ADA91 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -188,13 +199,13 @@ isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ProofOfPassport" */; buildPhases = ( - 141C3B9CB8F4134662795CF4 /* [CP] Check Pods Manifest.lock */, + CC47E87AFD57D7866D1463AC /* [CP] Check Pods Manifest.lock */, FD10A7F022414F080027D42C /* Start Packager */, 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - FAF2988CBB80C1B370711DF7 /* [CP] Embed Pods Frameworks */, + A8CC45FE941CED993895A21C /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -255,6 +266,7 @@ files = ( 905B700B2A72A5E900AFA232 /* masterList.pem in Resources */, 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, + 05A0773C2B5332040037E489 /* mopro in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -278,29 +290,7 @@ shellPath = /bin/sh; shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; }; - 141C3B9CB8F4134662795CF4 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-ProofOfPassport-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 2CEEDB4F696405D4E4B0CA04 /* [CP] Check Pods Manifest.lock */ = { + 30EF76FEB71F2239D12E988C /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -322,7 +312,7 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 4786C99960C198CBC0841652 /* [CP] Embed Pods Frameworks */ = { + 3407A7677F910117EC6ADA91 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -339,7 +329,7 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ProofOfPassport-ProofOfPassportTests/Pods-ProofOfPassport-ProofOfPassportTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - FAF2988CBB80C1B370711DF7 /* [CP] Embed Pods Frameworks */ = { + A8CC45FE941CED993895A21C /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -356,6 +346,28 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ProofOfPassport/Pods-ProofOfPassport-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + CC47E87AFD57D7866D1463AC /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ProofOfPassport-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; FD10A7F022414F080027D42C /* Start Packager */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -391,9 +403,11 @@ buildActionMask = 2147483647; files = ( 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, + 05EDEDC72B52D25D00AA51AD /* Prover.swift in Sources */, 13B07FC11A68108700A75B9A /* main.m in Sources */, 905B70072A72774000AFA232 /* PassportReader.m in Sources */, 905B70052A72767900AFA232 /* PassportReader.swift in Sources */, + 05EDEDC62B52D25D00AA51AD /* Prover.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -410,7 +424,7 @@ /* Begin XCBuildConfiguration section */ 00E356F61AD99517003FC87E /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = BCC787E0FDFB928F9DA23E3F /* Pods-ProofOfPassport-ProofOfPassportTests.debug.xcconfig */; + baseConfigurationReference = 918081ECA23C8F232594E334 /* Pods-ProofOfPassport-ProofOfPassportTests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -438,7 +452,7 @@ }; 00E356F71AD99517003FC87E /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 0D05C085F8CBAC104F72E160 /* Pods-ProofOfPassport-ProofOfPassportTests.release.xcconfig */; + baseConfigurationReference = 22FDF2ADA5789E09558ADB4E /* Pods-ProofOfPassport-ProofOfPassportTests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -463,7 +477,7 @@ }; 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 26A432E0434B89485C7E3765 /* Pods-ProofOfPassport.debug.xcconfig */; + baseConfigurationReference = CE0B085EC65BAFEB61DD9C49 /* Pods-ProofOfPassport.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -476,6 +490,12 @@ LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", + "$(PROJECT_DIR)/../../cargo/target/universal/release", + ); + LIBRARY_SEARCH_PATHS = ( + "$(SDKROOT)/usr/lib/swift", + "$(inherited)", + "$(PROJECT_DIR)", ); MARKETING_VERSION = 1.0; OTHER_LDFLAGS = ( @@ -485,7 +505,6 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.warroom.proofofpassport; PRODUCT_NAME = ProofOfPassport; - SWIFT_OBJC_BRIDGING_HEADER = "ProofOfPassport-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -494,7 +513,7 @@ }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = A1B7A34F7E4C3F2D19C5D973 /* Pods-ProofOfPassport.release.xcconfig */; + baseConfigurationReference = 2B01EC4981C171CA304E6D2B /* Pods-ProofOfPassport.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -507,6 +526,11 @@ "$(inherited)", "@executable_path/Frameworks", ); + LIBRARY_SEARCH_PATHS = ( + "$(SDKROOT)/usr/lib/swift", + "$(inherited)", + "$(PROJECT_DIR)", + ); MARKETING_VERSION = 1.0; OTHER_LDFLAGS = ( "$(inherited)", @@ -515,7 +539,6 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.warroom.proofofpassport; PRODUCT_NAME = ProofOfPassport; - SWIFT_OBJC_BRIDGING_HEADER = "ProofOfPassport-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; diff --git a/app/ios/ProofOfPassport/LaunchScreen.storyboard b/app/ios/ProofOfPassport/LaunchScreen.storyboard index f6470609c..029abec98 100644 --- a/app/ios/ProofOfPassport/LaunchScreen.storyboard +++ b/app/ios/ProofOfPassport/LaunchScreen.storyboard @@ -1,10 +1,11 @@ - + - + + @@ -22,16 +23,13 @@ - + + - - - - @@ -39,4 +37,9 @@ + + + + + diff --git a/app/ios/Prover.m b/app/ios/Prover.m new file mode 100644 index 000000000..53723c13b --- /dev/null +++ b/app/ios/Prover.m @@ -0,0 +1,22 @@ +// +// Prover.m +// ProofOfPassport +// +// Created by Florent on 13/01/2024. +// + +#import +#import "React/RCTBridgeModule.h" + +@interface RCT_EXTERN_MODULE(Prover, NSObject) + +RCT_EXTERN_METHOD(runInitAction:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(runProveAction:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(runVerifyAction:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) + +@end \ No newline at end of file diff --git a/app/ios/Prover.swift b/app/ios/Prover.swift new file mode 100644 index 000000000..aad19bfac --- /dev/null +++ b/app/ios/Prover.swift @@ -0,0 +1,173 @@ + +// Prover.swift +// ProofOfPassport + +// Created by Florent on 13/01/2024. + + +import Foundation +import React +import Security +import MoproKit + +@available(iOS 15, *) +@objc(Prover) +class Prover: NSObject { + + let moproCircom = MoproKit.MoproCircom() + var generatedProof: Data? + var publicInputs: Data? + + @objc(runInitAction:reject:) + func runInitAction(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { // Update the textView on the main thread + print("Initializing library") + + // Execute long-running tasks in the background + DispatchQueue.global(qos: .userInitiated).async { + // Record start time + let start = CFAbsoluteTimeGetCurrent() + + do { + try initializeMopro() + + // Record end time and compute duration + let end = CFAbsoluteTimeGetCurrent() + let timeTaken = end - start + + // Log the time taken for initialization + print("Initializing arkzkey took \(timeTaken) seconds.") + } catch { + // Log any errors that occurred during initialization + print("An error occurred during initialization: \(error)") + } + } + } + + @objc(runProveAction:reject:) + func runProveAction(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { + // Logic for prove (generate_proof2) + do { + // Prepare inputs + let signature: [String] = [ + "3582320600048169363", + "7163546589759624213", + "18262551396327275695", + "4479772254206047016", + "1970274621151677644", + "6547632513799968987", + "921117808165172908", + "7155116889028933260", + "16769940396381196125", + "17141182191056257954", + "4376997046052607007", + "17471823348423771450", + "16282311012391954891", + "70286524413490741", + "1588836847166444745", + "15693430141227594668", + "13832254169115286697", + "15936550641925323613", + "323842208142565220", + "6558662646882345749", + "15268061661646212265", + "14962976685717212593", + "15773505053543368901", + "9586594741348111792", + "1455720481014374292", + "13945813312010515080", + "6352059456732816887", + "17556873002865047035", + "2412591065060484384", + "11512123092407778330", + "8499281165724578877", + "12768005853882726493", + ] + + let modulus: [String] = [ + "13792647154200341559", + "12773492180790982043", + "13046321649363433702", + "10174370803876824128", + "7282572246071034406", + "1524365412687682781", + "4900829043004737418", + "6195884386932410966", + "13554217876979843574", + "17902692039595931737", + "12433028734895890975", + "15971442058448435996", + "4591894758077129763", + "11258250015882429548", + "16399550288873254981", + "8246389845141771315", + "14040203746442788850", + "7283856864330834987", + "12297563098718697441", + "13560928146585163504", + "7380926829734048483", + "14591299561622291080", + "8439722381984777599", + "17375431987296514829", + "16727607878674407272", + "3233954801381564296", + "17255435698225160983", + "15093748890170255670", + "15810389980847260072", + "11120056430439037392", + "5866130971823719482", + "13327552690270163501", + ] + + let base_message: [String] = ["18114495772705111902", "2254271930739856077", + "2068851770", "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","0", + ] + + var inputs = [String: [String]]() + inputs["signature"] = signature; + inputs["modulus"] = modulus; + inputs["base_message"] = base_message; + + let start = CFAbsoluteTimeGetCurrent() + + // Generate Proof + let generateProofResult = try generateProof2(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 + + print("Proof generation took \(timeTaken) seconds.") + } catch let error as MoproError { + print("MoproError: \(error)") + } catch { + print("Unexpected error: \(error)") + } + } + + @objc(runVerifyAction:reject:) + func runVerifyAction(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { + // Logic for verify + guard let proof = generatedProof, + let publicInputs = publicInputs else { + print("Proof has not been generated yet.") + return + } + do { + // Verify Proof + let isValid = try verifyProof2(proof: proof, publicInput: publicInputs) + assert(isValid, "Proof verification should succeed") + + print("Proof verification succeeded.") + } catch let error as MoproError { + print("MoproError: \(error)") + } catch { + print("Unexpected error: \(error)") + } + } +} diff --git a/app/ios/mopro/mopro-core/.gitignore b/app/ios/mopro/mopro-core/.gitignore new file mode 100644 index 000000000..6985cf1bd --- /dev/null +++ b/app/ios/mopro/mopro-core/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/app/ios/mopro/mopro-core/Cargo.toml b/app/ios/mopro/mopro-core/Cargo.toml new file mode 100644 index 000000000..1a63a4d30 --- /dev/null +++ b/app/ios/mopro/mopro-core/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "mopro-core" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[patch.crates-io] +# NOTE: Forked wasmer to work around memory limits +# See https://github.com/wasmerio/wasmer/commit/09c7070 +wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" } + +[features] +default = [] +dylib = ["wasmer/dylib"] + +[dependencies] +ark-circom = { git = "https://github.com/arkworks-rs/circom-compat.git" } +serde = { version = "1.0", features = ["derive"] } +ark-serialize = { version = "=0.4.1", features = ["derive"] } +num-bigint = { version = "=0.4.3", default-features = false, features = [ + "rand", +] } +instant = "0.1" +wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" } +once_cell = "1.8" + +# ZKP generation +ark-ec = { version = "=0.4.1", default-features = false, features = [ + "parallel", +] } +ark-crypto-primitives = { version = "=0.4.0" } +ark-std = { version = "=0.4.0", default-features = false, features = [ + "parallel", +] } +ark-bn254 = { version = "=0.4.0" } +ark-groth16 = { version = "=0.4.0", default-features = false, features = [ + "parallel", +] } +ark-relations = { version = "0.4", default-features = false } +ark-zkey = { path = "../ark-zkey" } + +# Error handling +thiserror = "=1.0.39" +color-eyre = "=0.6.2" +criterion = "=0.3.6" + +[build-dependencies] +color-eyre = "0.6" +enumset = "1.0.8" +wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" } diff --git a/app/ios/mopro/mopro-core/README.md b/app/ios/mopro/mopro-core/README.md new file mode 100644 index 000000000..452109f1d --- /dev/null +++ b/app/ios/mopro/mopro-core/README.md @@ -0,0 +1,47 @@ +# mopro-core + +Core mobile Rust library. For FFI, see `mopro-ffi` which is a thin wrapper for exposing UniFFI bindings around this library. + +## Overview + +TBD. + +## Examples + +Run `cargo run --example circom`. Also see `examples/circom/README.md` for more information. + +## Build dylib + +Experimental support. + +Turns `.wasm` file into a dynamic library (`.dylib`). + +Run: + +`cargo build --features dylib` + +After that you'll see location of the dylib file: + +``` +warning: Building dylib for aarch64-apple-darwin +warning: Dylib location: /Users/user/repos/github.com/oskarth/mopro/mopro-core/target/debug/aarch64-apple-darwin/keccak256.dylib +``` + +Right now this is hardcoded for `rsa`. + +Note that: +- It has to be built for the right architecture +- Have to run `install_name_tool` to adjust install name +- Run `codesign` to sign dylib for use on iOS + +### Script + +Add third argument: `dylib`: + +`./scripts/update_bindings.sh device release dylib` + +Note that `APPLE_SIGNING_IDENTITY` must be set. + +## To use ark-zkey + +Experimental support for significantly faster zkey loading. See `../ark-zkey` README for how to build arkzkey. \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/build.rs b/app/ios/mopro/mopro-core/build.rs new file mode 100644 index 000000000..2205e80a3 --- /dev/null +++ b/app/ios/mopro/mopro-core/build.rs @@ -0,0 +1,104 @@ +use color_eyre::eyre::Result; +use std::env; +use std::path::PathBuf; + +fn prepare_env(zkey_path: String, wasm_path: String, arkzkey_path: String) -> Result<()> { + let project_dir = env::var("CARGO_MANIFEST_DIR")?; + let zkey_file = PathBuf::from(&project_dir).join(zkey_path); + let wasm_file = PathBuf::from(&project_dir).join(wasm_path); + let arkzkey_file = PathBuf::from(&project_dir).join(arkzkey_path); + + // TODO: Right now emitting as warnings for visibility, figure out better way to do this? + println!("cargo:warning=zkey_file: {}", zkey_file.display()); + println!("cargo:warning=wasm_file: {}", wasm_file.display()); + println!("cargo:warning=arkzkey_file: {}", arkzkey_file.display()); + + // Set BUILD_RS_ZKEY_FILE and BUILD_RS_WASM_FILE env var + println!("cargo:rustc-env=BUILD_RS_ZKEY_FILE={}", zkey_file.display()); + println!("cargo:rustc-env=BUILD_RS_WASM_FILE={}", wasm_file.display()); + println!( + "cargo:rustc-env=BUILD_RS_ARKZKEY_FILE={}", + arkzkey_file.display() + ); + + Ok(()) +} + +#[cfg(feature = "dylib")] +fn build_dylib(wasm_path: String, dylib_name: String) -> Result<()> { + use std::path::Path; + use std::{fs, str::FromStr}; + + use color_eyre::eyre::eyre; + use enumset::enum_set; + use enumset::EnumSet; + + use wasmer::Cranelift; + use wasmer::Dylib; + use wasmer::Target; + use wasmer::{Module, Store, Triple}; + + let out_dir = env::var("OUT_DIR")?; + let project_dir = env::var("CARGO_MANIFEST_DIR")?; + let build_mode = env::var("PROFILE")?; + let target_arch = env::var("TARGET")?; + + let out_dir = Path::new(&out_dir).to_path_buf(); + let wasm_file = Path::new(&wasm_path).to_path_buf(); + let dylib_file = out_dir.join(&dylib_name); + let final_dir = PathBuf::from(&project_dir) + .join("target") + .join(&target_arch) + .join(build_mode); + + // if dylib_file.exists() { + // return Ok(()); + // } + + // Create a WASM engine for the target that can compile + let triple = Triple::from_str(&target_arch).map_err(|e| eyre!(e))?; + let cpu_features = enum_set!(); + let target = Target::new(triple, cpu_features); + let engine = Dylib::new(Cranelift::default()).target(target).engine(); + println!("cargo:warning=Building dylib for {}", target_arch); + + // Compile the WASM module + let store = Store::new(&engine); + let module = Module::from_file(&store, &wasm_file).unwrap(); + module.serialize_to_file(&dylib_file).unwrap(); + assert!(dylib_file.exists()); + + // Copy dylib to a more predictable path + fs::create_dir_all(&final_dir)?; + let final_path = final_dir.join(dylib_name); + fs::copy(&dylib_file, &final_path)?; + println!("cargo:warning=Dylib location: {}", final_path.display()); + + Ok(()) +} + +fn main() -> Result<()> { + // TODO: build_circuit function to builds all related artifacts, instead of doing this externally + let dir = "examples/circom/keccak256"; + let circuit = "keccak256_256_test"; + + // XXX: Use RSA + // let dir = "examples/circom/rsa"; + // let circuit = "main"; + + let zkey_path = format!("{}/target/{}_final.zkey", dir, circuit); + let wasm_path = format!("{}/target/{}_js/{}.wasm", dir, circuit, circuit); + // TODO: Need to modify script for this + let arkzkey_path = format!("{}/target/{}_final.arkzkey", dir, circuit); + + prepare_env(zkey_path, wasm_path.clone(), arkzkey_path)?; + + #[cfg(feature = "dylib")] + { + // TODO: This should depends on the circuit name + //let dylib_name = "keccak256.dylib"; + let dylib_name = "rsa.dylib"; + build_dylib(wasm_path.clone(), dylib_name.to_string())?; + } + Ok(()) +} diff --git a/app/ios/mopro/mopro-core/examples/circom.rs b/app/ios/mopro/mopro-core/examples/circom.rs new file mode 100644 index 000000000..949ee191b --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom.rs @@ -0,0 +1,41 @@ +use mopro_core::middleware::circom::CircomState; +use num_bigint::BigInt; +use std::collections::HashMap; + +fn main() { + let wasm_path = "./examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"; + let r1cs_path = "./examples/circom/multiplier2/target/multiplier2.r1cs"; + + // Instantiate CircomState + let mut circom_state = CircomState::new(); + + // Setup + let setup_res = circom_state.setup(wasm_path, r1cs_path); + assert!(setup_res.is_ok()); + + let _serialized_pk = setup_res.unwrap(); + + // Deserialize the proving key and inputs if necessary + + // Prepare inputs + let mut inputs = HashMap::new(); + inputs.insert("a".to_string(), vec![BigInt::from(3)]); + inputs.insert("b".to_string(), vec![BigInt::from(5)]); + + // Proof generation + let generate_proof_res = circom_state.generate_proof(inputs); + + // Check and print the error if there is one + if let Err(e) = &generate_proof_res { + println!("Error: {:?}", e); + } + + assert!(generate_proof_res.is_ok()); + + let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); + + // Proof verification + let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs); + assert!(verify_res.is_ok()); + assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified +} diff --git a/app/ios/mopro/mopro-core/examples/circom/.gitignore b/app/ios/mopro/mopro-core/examples/circom/.gitignore new file mode 100644 index 000000000..f1d902a10 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/.gitignore @@ -0,0 +1,2 @@ +!target +*.ptau diff --git a/app/ios/mopro/mopro-core/examples/circom/README.md b/app/ios/mopro/mopro-core/examples/circom/README.md new file mode 100644 index 000000000..facfeedf0 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/README.md @@ -0,0 +1,9 @@ +# Circom examples + + Example circuits written in Circom used for testing. One basic, multiplier2, and another one slightly more involved, keccak256. The former is a good minimal circuit to test things end to end. The latter is useful for benchmarking. + + To compile circuits, run `./scripts/compile.sh `. For example, `./scripts/compile.sh multiplier2 multiplier2.circom`. + + To run a trusted setup, run `./scripts/trusted_setup.sh `. For example, `./scripts/trusted_setup.sh multiplier2 08 multiplier2`. + +Both of these actions are done as part of the `./scripts/prepare.sh` script in the root directory `multiplier2` and `keccak256`. \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/examples/circom/keccak256/.gitignore b/app/ios/mopro/mopro-core/examples/circom/keccak256/.gitignore new file mode 100644 index 000000000..5feb90786 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/keccak256/.gitignore @@ -0,0 +1,2 @@ +target +node_modules \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/examples/circom/keccak256/README.md b/app/ios/mopro/mopro-core/examples/circom/keccak256/README.md new file mode 100644 index 000000000..6537653d9 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/keccak256/README.md @@ -0,0 +1,7 @@ +# README + +Basic test of Keccak256 in Circom, around 150k constraints. + +Used as a non-trivial circuit for initial benchmarking. + +Taken from https://github.com/vocdoni/keccak256-circom diff --git a/app/ios/mopro/mopro-core/examples/circom/keccak256/keccak.circom b/app/ios/mopro/mopro-core/examples/circom/keccak256/keccak.circom new file mode 100644 index 000000000..f4a1b2fc0 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/keccak256/keccak.circom @@ -0,0 +1,186 @@ +// Keccak256 hash function (ethereum version). +// For LICENSE check https://github.com/vocdoni/keccak256-circom/blob/master/LICENSE + +pragma circom 2.0.0; + +include "./utils.circom"; +include "./permutations.circom"; + +template Pad(nBits) { + signal input in[nBits]; + + var blockSize=136*8; + signal output out[blockSize]; + signal out2[blockSize]; + + var i; + + for (i=0; i> i) & 1; + } + for (i=nBits+8; i> i) & 1; + } + for (i=0; i<8; i++) { + out[blockSize-8+i] <== aux.out[i]; + } + for (i=0; i>shr) + signal input a[n]; + signal input b[n]; + signal output out[n]; + var i; + + component aux0 = ShR(64, shr); + for (i=0; i<64; i++) { + aux0.in[i] <== a[i]; + } + component aux1 = ShL(64, shl); + for (i=0; i<64; i++) { + aux1.in[i] <== a[i]; + } + component aux2 = OrArray(64); + for (i=0; i<64; i++) { + aux2.a[i] <== aux0.out[i]; + aux2.b[i] <== aux1.out[i]; + } + component aux3 = XorArray(64); + for (i=0; i<64; i++) { + aux3.a[i] <== b[i]; + aux3.b[i] <== aux2.out[i]; + } + for (i=0; i<64; i++) { + out[i] <== aux3.out[i]; + } +} + +template Theta() { + signal input in[25*64]; + signal output out[25*64]; + + var i; + + component c0 = Xor5(64); + for (i=0; i<64; i++) { + c0.a[i] <== in[i]; + c0.b[i] <== in[5*64+i]; + c0.c[i] <== in[10*64+i]; + c0.d[i] <== in[15*64+i]; + c0.e[i] <== in[20*64+i]; + } + + component c1 = Xor5(64); + for (i=0; i<64; i++) { + c1.a[i] <== in[1*64+i]; + c1.b[i] <== in[6*64+i]; + c1.c[i] <== in[11*64+i]; + c1.d[i] <== in[16*64+i]; + c1.e[i] <== in[21*64+i]; + } + + component c2 = Xor5(64); + for (i=0; i<64; i++) { + c2.a[i] <== in[2*64+i]; + c2.b[i] <== in[7*64+i]; + c2.c[i] <== in[12*64+i]; + c2.d[i] <== in[17*64+i]; + c2.e[i] <== in[22*64+i]; + } + + component c3 = Xor5(64); + for (i=0; i<64; i++) { + c3.a[i] <== in[3*64+i]; + c3.b[i] <== in[8*64+i]; + c3.c[i] <== in[13*64+i]; + c3.d[i] <== in[18*64+i]; + c3.e[i] <== in[23*64+i]; + } + + component c4 = Xor5(64); + for (i=0; i<64; i++) { + c4.a[i] <== in[4*64+i]; + c4.b[i] <== in[9*64+i]; + c4.c[i] <== in[14*64+i]; + c4.d[i] <== in[19*64+i]; + c4.e[i] <== in[24*64+i]; + } + + // d = c4 ^ (c1<<1 | c1>>(64-1)) + component d0 = D(64, 1, 64-1); + for (i=0; i<64; i++) { + d0.a[i] <== c1.out[i]; + d0.b[i] <== c4.out[i]; + } + // r[0] = a[0] ^ d + component r0 = XorArray(64); + for (i=0; i<64; i++) { + r0.a[i] <== in[i]; + r0.b[i] <== d0.out[i]; + } + for (i=0; i<64; i++) { + out[i] <== r0.out[i]; + } + // r[5] = a[5] ^ d + component r5 = XorArray(64); + for (i=0; i<64; i++) { + r5.a[i] <== in[5*64+i]; + r5.b[i] <== d0.out[i]; + } + for (i=0; i<64; i++) { + out[5*64+i] <== r5.out[i]; + } + // r[10] = a[10] ^ d + component r10 = XorArray(64); + for (i=0; i<64; i++) { + r10.a[i] <== in[10*64+i]; + r10.b[i] <== d0.out[i]; + } + for (i=0; i<64; i++) { + out[10*64+i] <== r10.out[i]; + } + // r[15] = a[15] ^ d + component r15 = XorArray(64); + for (i=0; i<64; i++) { + r15.a[i] <== in[15*64+i]; + r15.b[i] <== d0.out[i]; + } + for (i=0; i<64; i++) { + out[15*64+i] <== r15.out[i]; + } + // r[20] = a[20] ^ d + component r20 = XorArray(64); + for (i=0; i<64; i++) { + r20.a[i] <== in[20*64+i]; + r20.b[i] <== d0.out[i]; + } + for (i=0; i<64; i++) { + out[20*64+i] <== r20.out[i]; + } + + // d = c0 ^ (c2<<1 | c2>>(64-1)) + component d1 = D(64, 1, 64-1); + for (i=0; i<64; i++) { + d1.a[i] <== c2.out[i]; + d1.b[i] <== c0.out[i]; + } + // r[1] = a[1] ^ d + component r1 = XorArray(64); + for (i=0; i<64; i++) { + r1.a[i] <== in[1*64+i]; + r1.b[i] <== d1.out[i]; + } + for (i=0; i<64; i++) { + out[1*64+i] <== r1.out[i]; + } + // r[6] = a[6] ^ d + component r6 = XorArray(64); + for (i=0; i<64; i++) { + r6.a[i] <== in[6*64+i]; + r6.b[i] <== d1.out[i]; + } + for (i=0; i<64; i++) { + out[6*64+i] <== r6.out[i]; + } + // r[11] = a[11] ^ d + component r11 = XorArray(64); + for (i=0; i<64; i++) { + r11.a[i] <== in[11*64+i]; + r11.b[i] <== d1.out[i]; + } + for (i=0; i<64; i++) { + out[11*64+i] <== r11.out[i]; + } + // r[16] = a[16] ^ d + component r16 = XorArray(64); + for (i=0; i<64; i++) { + r16.a[i] <== in[16*64+i]; + r16.b[i] <== d1.out[i]; + } + for (i=0; i<64; i++) { + out[16*64+i] <== r16.out[i]; + } + // r[21] = a[21] ^ d + component r21 = XorArray(64); + for (i=0; i<64; i++) { + r21.a[i] <== in[21*64+i]; + r21.b[i] <== d1.out[i]; + } + for (i=0; i<64; i++) { + out[21*64+i] <== r21.out[i]; + } + + // d = c1 ^ (c3<<1 | c3>>(64-1)) + component d2 = D(64, 1, 64-1); + for (i=0; i<64; i++) { + d2.a[i] <== c3.out[i]; + d2.b[i] <== c1.out[i]; + } + // r[2] = a[2] ^ d + component r2 = XorArray(64); + for (i=0; i<64; i++) { + r2.a[i] <== in[2*64+i]; + r2.b[i] <== d2.out[i]; + } + for (i=0; i<64; i++) { + out[2*64+i] <== r2.out[i]; + } + // r[7] = a[7] ^ d + component r7 = XorArray(64); + for (i=0; i<64; i++) { + r7.a[i] <== in[7*64+i]; + r7.b[i] <== d2.out[i]; + } + for (i=0; i<64; i++) { + out[7*64+i] <== r7.out[i]; + } + // r[12] = a[12] ^ d + component r12 = XorArray(64); + for (i=0; i<64; i++) { + r12.a[i] <== in[12*64+i]; + r12.b[i] <== d2.out[i]; + } + for (i=0; i<64; i++) { + out[12*64+i] <== r12.out[i]; + } + // r[17] = a[17] ^ d + component r17 = XorArray(64); + for (i=0; i<64; i++) { + r17.a[i] <== in[17*64+i]; + r17.b[i] <== d2.out[i]; + } + for (i=0; i<64; i++) { + out[17*64+i] <== r17.out[i]; + } + // r[22] = a[22] ^ d + component r22 = XorArray(64); + for (i=0; i<64; i++) { + r22.a[i] <== in[22*64+i]; + r22.b[i] <== d2.out[i]; + } + for (i=0; i<64; i++) { + out[22*64+i] <== r22.out[i]; + } + + // d = c2 ^ (c4<<1 | c4>>(64-1)) + component d3 = D(64, 1, 64-1); + for (i=0; i<64; i++) { + d3.a[i] <== c4.out[i]; + d3.b[i] <== c2.out[i]; + } + // r[3] = a[3] ^ d + component r3 = XorArray(64); + for (i=0; i<64; i++) { + r3.a[i] <== in[3*64+i]; + r3.b[i] <== d3.out[i]; + } + for (i=0; i<64; i++) { + out[3*64+i] <== r3.out[i]; + } + // r[8] = a[8] ^ d + component r8 = XorArray(64); + for (i=0; i<64; i++) { + r8.a[i] <== in[8*64+i]; + r8.b[i] <== d3.out[i]; + } + for (i=0; i<64; i++) { + out[8*64+i] <== r8.out[i]; + } + // r[13] = a[13] ^ d + component r13 = XorArray(64); + for (i=0; i<64; i++) { + r13.a[i] <== in[13*64+i]; + r13.b[i] <== d3.out[i]; + } + for (i=0; i<64; i++) { + out[13*64+i] <== r13.out[i]; + } + // r[18] = a[18] ^ d + component r18 = XorArray(64); + for (i=0; i<64; i++) { + r18.a[i] <== in[18*64+i]; + r18.b[i] <== d3.out[i]; + } + for (i=0; i<64; i++) { + out[18*64+i] <== r18.out[i]; + } + // r[23] = a[23] ^ d + component r23 = XorArray(64); + for (i=0; i<64; i++) { + r23.a[i] <== in[23*64+i]; + r23.b[i] <== d3.out[i]; + } + for (i=0; i<64; i++) { + out[23*64+i] <== r23.out[i]; + } + + // d = c3 ^ (c0<<1 | c0>>(64-1)) + component d4 = D(64, 1, 64-1); + for (i=0; i<64; i++) { + d4.a[i] <== c0.out[i]; + d4.b[i] <== c3.out[i]; + } + // r[4] = a[4] ^ d + component r4 = XorArray(64); + for (i=0; i<64; i++) { + r4.a[i] <== in[4*64+i]; + r4.b[i] <== d4.out[i]; + } + for (i=0; i<64; i++) { + out[4*64+i] <== r4.out[i]; + } + // r[9] = a[9] ^ d + component r9 = XorArray(64); + for (i=0; i<64; i++) { + r9.a[i] <== in[9*64+i]; + r9.b[i] <== d4.out[i]; + } + for (i=0; i<64; i++) { + out[9*64+i] <== r9.out[i]; + } + // r[14] = a[14] ^ d + component r14 = XorArray(64); + for (i=0; i<64; i++) { + r14.a[i] <== in[14*64+i]; + r14.b[i] <== d4.out[i]; + } + for (i=0; i<64; i++) { + out[14*64+i] <== r14.out[i]; + } + // r[19] = a[19] ^ d + component r19 = XorArray(64); + for (i=0; i<64; i++) { + r19.a[i] <== in[19*64+i]; + r19.b[i] <== d4.out[i]; + } + for (i=0; i<64; i++) { + out[19*64+i] <== r19.out[i]; + } + // r[24] = a[24] ^ d + component r24 = XorArray(64); + for (i=0; i<64; i++) { + r24.a[i] <== in[24*64+i]; + r24.b[i] <== d4.out[i]; + } + for (i=0; i<64; i++) { + out[24*64+i] <== r24.out[i]; + } +} + +// RhoPi + +template stepRhoPi(shl, shr) { + // out = a<>shr + signal input a[64]; + signal output out[64]; + var i; + + component aux0 = ShR(64, shr); + for (i=0; i<64; i++) { + aux0.in[i] <== a[i]; + } + component aux1 = ShL(64, shl); + for (i=0; i<64; i++) { + aux1.in[i] <== a[i]; + } + component aux2 = OrArray(64); + for (i=0; i<64; i++) { + aux2.a[i] <== aux0.out[i]; + aux2.b[i] <== aux1.out[i]; + } + for (i=0; i<64; i++) { + out[i] <== aux2.out[i]; + } +} +template RhoPi() { + signal input in[25*64]; + signal output out[25*64]; + + var i; + + // r[10] = a[1]<<1|a[1]>>(64-1) + component s10 = stepRhoPi(1, 64-1); + for (i=0; i<64; i++) { + s10.a[i] <== in[1*64+i]; + } + // r[7] = a[10]<<3|a[10]>>(64-3) + component s7 = stepRhoPi(3, 64-3); + for (i=0; i<64; i++) { + s7.a[i] <== in[10*64+i]; + } + // r[11] = a[7]<<6|a[7]>>(64-6) + component s11 = stepRhoPi(6, 64-6); + for (i=0; i<64; i++) { + s11.a[i] <== in[7*64+i]; + } + // r[17] = a[11]<<10|a[11]>>(64-10) + component s17 = stepRhoPi(10, 64-10); + for (i=0; i<64; i++) { + s17.a[i] <== in[11*64+i]; + } + // r[18] = a[17]<<15|a[17]>>(64-15) + component s18 = stepRhoPi(15, 64-15); + for (i=0; i<64; i++) { + s18.a[i] <== in[17*64+i]; + } + // r[3] = a[18]<<21|a[18]>>(64-21) + component s3 = stepRhoPi(21, 64-21); + for (i=0; i<64; i++) { + s3.a[i] <== in[18*64+i]; + } + // r[5] = a[3]<<28|a[3]>>(64-28) + component s5 = stepRhoPi(28, 64-28); + for (i=0; i<64; i++) { + s5.a[i] <== in[3*64+i]; + } + // r[16] = a[5]<<36|a[5]>>(64-36) + component s16 = stepRhoPi(36, 64-36); + for (i=0; i<64; i++) { + s16.a[i] <== in[5*64+i]; + } + // r[8] = a[16]<<45|a[16]>>(64-45) + component s8 = stepRhoPi(45, 64-45); + for (i=0; i<64; i++) { + s8.a[i] <== in[16*64+i]; + } + // r[21] = a[8]<<55|a[8]>>(64-55) + component s21 = stepRhoPi(55, 64-55); + for (i=0; i<64; i++) { + s21.a[i] <== in[8*64+i]; + } + // r[24] = a[21]<<2|a[21]>>(64-2) + component s24 = stepRhoPi(2, 64-2); + for (i=0; i<64; i++) { + s24.a[i] <== in[21*64+i]; + } + // r[4] = a[24]<<14|a[24]>>(64-14) + component s4 = stepRhoPi(14, 64-14); + for (i=0; i<64; i++) { + s4.a[i] <== in[24*64+i]; + } + // r[15] = a[4]<<27|a[4]>>(64-27) + component s15 = stepRhoPi(27, 64-27); + for (i=0; i<64; i++) { + s15.a[i] <== in[4*64+i]; + } + // r[23] = a[15]<<41|a[15]>>(64-41) + component s23 = stepRhoPi(41, 64-41); + for (i=0; i<64; i++) { + s23.a[i] <== in[15*64+i]; + } + // r[19] = a[23]<<56|a[23]>>(64-56) + component s19 = stepRhoPi(56, 64-56); + for (i=0; i<64; i++) { + s19.a[i] <== in[23*64+i]; + } + // r[13] = a[19]<<8|a[19]>>(64-8) + component s13 = stepRhoPi(8, 64-8); + for (i=0; i<64; i++) { + s13.a[i] <== in[19*64+i]; + } + // r[12] = a[13]<<25|a[13]>>(64-25) + component s12 = stepRhoPi(25, 64-25); + for (i=0; i<64; i++) { + s12.a[i] <== in[13*64+i]; + } + // r[2] = a[12]<<43|a[12]>>(64-43) + component s2 = stepRhoPi(43, 64-43); + for (i=0; i<64; i++) { + s2.a[i] <== in[12*64+i]; + } + // r[20] = a[2]<<62|a[2]>>(64-62) + component s20 = stepRhoPi(62, 64-62); + for (i=0; i<64; i++) { + s20.a[i] <== in[2*64+i]; + } + // r[14] = a[20]<<18|a[20]>>(64-18) + component s14 = stepRhoPi(18, 64-18); + for (i=0; i<64; i++) { + s14.a[i] <== in[20*64+i]; + } + // r[22] = a[14]<<39|a[14]>>(64-39) + component s22 = stepRhoPi(39, 64-39); + for (i=0; i<64; i++) { + s22.a[i] <== in[14*64+i]; + } + // r[9] = a[22]<<61|a[22]>>(64-61) + component s9 = stepRhoPi(61, 64-61); + for (i=0; i<64; i++) { + s9.a[i] <== in[22*64+i]; + } + // r[6] = a[9]<<20|a[9]>>(64-20) + component s6 = stepRhoPi(20, 64-20); + for (i=0; i<64; i++) { + s6.a[i] <== in[9*64+i]; + } + // r[1] = a[6]<<44|a[6]>>(64-44) + component s1 = stepRhoPi(44, 64-44); + for (i=0; i<64; i++) { + s1.a[i] <== in[6*64+i]; + } + + for (i=0; i<64; i++) { + out[i] <== in[i]; + out[10*64+i] <== s10.out[i]; + out[7*64+i] <== s7.out[i]; + out[11*64+i] <== s11.out[i]; + out[17*64+i] <== s17.out[i]; + out[18*64+i] <== s18.out[i]; + out[3*64+i] <== s3.out[i]; + out[5*64+i] <== s5.out[i]; + out[16*64+i] <== s16.out[i]; + out[8*64+i] <== s8.out[i]; + out[21*64+i] <== s21.out[i]; + out[24*64+i] <== s24.out[i]; + out[4*64+i] <== s4.out[i]; + out[15*64+i] <== s15.out[i]; + out[23*64+i] <== s23.out[i]; + out[19*64+i] <== s19.out[i]; + out[13*64+i] <== s13.out[i]; + out[12*64+i] <== s12.out[i]; + out[2*64+i] <== s2.out[i]; + out[20*64+i] <== s20.out[i]; + out[14*64+i] <== s14.out[i]; + out[22*64+i] <== s22.out[i]; + out[9*64+i] <== s9.out[i]; + out[6*64+i] <== s6.out[i]; + out[1*64+i] <== s1.out[i]; + } +} + + +// Chi + +template stepChi() { + // out = a ^ (^b) & c + signal input a[64]; + signal input b[64]; + signal input c[64]; + signal output out[64]; + var i; + + // ^b + component bXor = XorArraySingle(64); + for (i=0; i<64; i++) { + bXor.a[i] <== b[i]; + } + // (^b)&c + component bc = AndArray(64); + for (i=0; i<64; i++) { + bc.a[i] <== bXor.out[i]; + bc.b[i] <== c[i]; + } + // a^(^b)&c + component abc = XorArray(64); + for (i=0; i<64; i++) { + abc.a[i] <== a[i]; + abc.b[i] <== bc.out[i]; + } + for (i=0; i<64; i++) { + out[i] <== abc.out[i]; + } +} + +template Chi() { + signal input in[25*64]; + signal output out[25*64]; + + var i; + + component r0 = stepChi(); + for (i=0; i<64; i++) { + r0.a[i] <== in[i]; + r0.b[i] <== in[1*64+i]; + r0.c[i] <== in[2*64+i]; + } + component r1 = stepChi(); + for (i=0; i<64; i++) { + r1.a[i] <== in[1*64+i]; + r1.b[i] <== in[2*64+i]; + r1.c[i] <== in[3*64+i]; + } + component r2 = stepChi(); + for (i=0; i<64; i++) { + r2.a[i] <== in[2*64+i]; + r2.b[i] <== in[3*64+i]; + r2.c[i] <== in[4*64+i]; + } + component r3 = stepChi(); + for (i=0; i<64; i++) { + r3.a[i] <== in[3*64+i]; + r3.b[i] <== in[4*64+i]; + r3.c[i] <== in[0*64+i]; + } + component r4 = stepChi(); + for (i=0; i<64; i++) { + r4.a[i] <== in[4*64+i]; + r4.b[i] <== in[i]; + r4.c[i] <== in[1*64+i]; + } + + component r5 = stepChi(); + for (i=0; i<64; i++) { + r5.a[i] <== in[5*64+i]; + r5.b[i] <== in[6*64+i]; + r5.c[i] <== in[7*64+i]; + } + component r6 = stepChi(); + for (i=0; i<64; i++) { + r6.a[i] <== in[6*64+i]; + r6.b[i] <== in[7*64+i]; + r6.c[i] <== in[8*64+i]; + } + component r7 = stepChi(); + for (i=0; i<64; i++) { + r7.a[i] <== in[7*64+i]; + r7.b[i] <== in[8*64+i]; + r7.c[i] <== in[9*64+i]; + } + component r8 = stepChi(); + for (i=0; i<64; i++) { + r8.a[i] <== in[8*64+i]; + r8.b[i] <== in[9*64+i]; + r8.c[i] <== in[5*64+i]; + } + component r9 = stepChi(); + for (i=0; i<64; i++) { + r9.a[i] <== in[9*64+i]; + r9.b[i] <== in[5*64+i]; + r9.c[i] <== in[6*64+i]; + } + + component r10 = stepChi(); + for (i=0; i<64; i++) { + r10.a[i] <== in[10*64+i]; + r10.b[i] <== in[11*64+i]; + r10.c[i] <== in[12*64+i]; + } + component r11 = stepChi(); + for (i=0; i<64; i++) { + r11.a[i] <== in[11*64+i]; + r11.b[i] <== in[12*64+i]; + r11.c[i] <== in[13*64+i]; + } + component r12 = stepChi(); + for (i=0; i<64; i++) { + r12.a[i] <== in[12*64+i]; + r12.b[i] <== in[13*64+i]; + r12.c[i] <== in[14*64+i]; + } + component r13 = stepChi(); + for (i=0; i<64; i++) { + r13.a[i] <== in[13*64+i]; + r13.b[i] <== in[14*64+i]; + r13.c[i] <== in[10*64+i]; + } + component r14 = stepChi(); + for (i=0; i<64; i++) { + r14.a[i] <== in[14*64+i]; + r14.b[i] <== in[10*64+i]; + r14.c[i] <== in[11*64+i]; + } + + component r15 = stepChi(); + for (i=0; i<64; i++) { + r15.a[i] <== in[15*64+i]; + r15.b[i] <== in[16*64+i]; + r15.c[i] <== in[17*64+i]; + } + component r16 = stepChi(); + for (i=0; i<64; i++) { + r16.a[i] <== in[16*64+i]; + r16.b[i] <== in[17*64+i]; + r16.c[i] <== in[18*64+i]; + } + component r17 = stepChi(); + for (i=0; i<64; i++) { + r17.a[i] <== in[17*64+i]; + r17.b[i] <== in[18*64+i]; + r17.c[i] <== in[19*64+i]; + } + component r18 = stepChi(); + for (i=0; i<64; i++) { + r18.a[i] <== in[18*64+i]; + r18.b[i] <== in[19*64+i]; + r18.c[i] <== in[15*64+i]; + } + component r19 = stepChi(); + for (i=0; i<64; i++) { + r19.a[i] <== in[19*64+i]; + r19.b[i] <== in[15*64+i]; + r19.c[i] <== in[16*64+i]; + } + + component r20 = stepChi(); + for (i=0; i<64; i++) { + r20.a[i] <== in[20*64+i]; + r20.b[i] <== in[21*64+i]; + r20.c[i] <== in[22*64+i]; + } + component r21 = stepChi(); + for (i=0; i<64; i++) { + r21.a[i] <== in[21*64+i]; + r21.b[i] <== in[22*64+i]; + r21.c[i] <== in[23*64+i]; + } + component r22 = stepChi(); + for (i=0; i<64; i++) { + r22.a[i] <== in[22*64+i]; + r22.b[i] <== in[23*64+i]; + r22.c[i] <== in[24*64+i]; + } + component r23 = stepChi(); + for (i=0; i<64; i++) { + r23.a[i] <== in[23*64+i]; + r23.b[i] <== in[24*64+i]; + r23.c[i] <== in[20*64+i]; + } + component r24 = stepChi(); + for (i=0; i<64; i++) { + r24.a[i] <== in[24*64+i]; + r24.b[i] <== in[20*64+i]; + r24.c[i] <== in[21*64+i]; + } + + for (i=0; i<64; i++) { + out[i] <== r0.out[i]; + out[1*64+i] <== r1.out[i]; + out[2*64+i] <== r2.out[i]; + out[3*64+i] <== r3.out[i]; + out[4*64+i] <== r4.out[i]; + + out[5*64+i] <== r5.out[i]; + out[6*64+i] <== r6.out[i]; + out[7*64+i] <== r7.out[i]; + out[8*64+i] <== r8.out[i]; + out[9*64+i] <== r9.out[i]; + + out[10*64+i] <== r10.out[i]; + out[11*64+i] <== r11.out[i]; + out[12*64+i] <== r12.out[i]; + out[13*64+i] <== r13.out[i]; + out[14*64+i] <== r14.out[i]; + + out[15*64+i] <== r15.out[i]; + out[16*64+i] <== r16.out[i]; + out[17*64+i] <== r17.out[i]; + out[18*64+i] <== r18.out[i]; + out[19*64+i] <== r19.out[i]; + + out[20*64+i] <== r20.out[i]; + out[21*64+i] <== r21.out[i]; + out[22*64+i] <== r22.out[i]; + out[23*64+i] <== r23.out[i]; + out[24*64+i] <== r24.out[i]; + } +} + +// Iota + +template RC(r) { + signal output out[64]; + var rc[24] = [ + 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, + 0x8000000080008000, 0x000000000000808B, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008A, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000A, + 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800A, 0x800000008000000A, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + ]; + for (var i=0; i<64; i++) { + out[i] <== (rc[r] >> i) & 1; + } +} + +template Iota(r) { + signal input in[25*64]; + signal output out[25*64]; + var i; + + component rc = RC(r); + + component iota = XorArray(64); + for (var i=0; i<64; i++) { + iota.a[i] <== in[i]; + iota.b[i] <== rc.out[i]; + } + for (i=0; i<64; i++) { + out[i] <== iota.out[i]; + } + for (i=64; i<25*64; i++) { + out[i] <== in[i]; + } +} + diff --git a/app/ios/mopro/mopro-core/examples/circom/keccak256/utils.circom b/app/ios/mopro/mopro-core/examples/circom/keccak256/utils.circom new file mode 100644 index 000000000..6a66fb257 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/keccak256/utils.circom @@ -0,0 +1,118 @@ +// Keccak256 hash function (ethereum version). +// For LICENSE check https://github.com/vocdoni/keccak256-circom/blob/master/LICENSE + +pragma circom 2.0.0; + +include "node_modules/circomlib/circuits/gates.circom"; +include "node_modules/circomlib/circuits/sha256/xor3.circom"; +include "node_modules/circomlib/circuits/sha256/shift.circom"; // contains ShiftRight + +template Xor5(n) { + signal input a[n]; + signal input b[n]; + signal input c[n]; + signal input d[n]; + signal input e[n]; + signal output out[n]; + var i; + + component xor3 = Xor3(n); + for (i=0; i= 0 +template ModSubThree(n) { + assert(n + 2 <= 253); + signal input a; + signal input b; + signal input c; + assert(a - b - c + (1 << n) >= 0); + signal output out; + signal output borrow; + signal b_plus_c; + b_plus_c <== b + c; + component lt = LessThan(n + 1); + lt.in[0] <== a; + lt.in[1] <== b_plus_c; + borrow <== lt.out; + out <== borrow * (1 << n) + a - b_plus_c; +} + +template ModSumThree(n) { + assert(n + 2 <= 253); + signal input a; + signal input b; + signal input c; + signal output sum; + signal output carry; + + component n2b = Num2Bits(n + 2); + n2b.in <== a + b + c; + carry <== n2b.out[n] + 2 * n2b.out[n + 1]; + sum <== a + b + c - carry * (1 << n); +} + +template ModSumFour(n) { + assert(n + 2 <= 253); + signal input a; + signal input b; + signal input c; + signal input d; + signal output sum; + signal output carry; + + component n2b = Num2Bits(n + 2); + n2b.in <== a + b + c + d; + carry <== n2b.out[n] + 2 * n2b.out[n + 1]; + sum <== a + b + c + d - carry * (1 << n); +} + +// product mod 2**n with carry +template ModProd(n) { + assert(n <= 126); + signal input a; + signal input b; + signal output prod; + signal output carry; + + component n2b = Num2Bits(2 * n); + n2b.in <== a * b; + + component b2n1 = Bits2Num(n); + component b2n2 = Bits2Num(n); + var i; + for (i = 0; i < n; i++) { + b2n1.in[i] <== n2b.out[i]; + b2n2.in[i] <== n2b.out[i + n]; + } + prod <== b2n1.out; + carry <== b2n2.out; +} + +// split a n + m bit input into two outputs +template Split(n, m) { + assert(n <= 126); + signal input in; + signal output small; + signal output big; + + small <-- in % (1 << n); + big <-- in \ (1 << n); + + component n2b_small = Num2Bits(n); + n2b_small.in <== small; + component n2b_big = Num2Bits(m); + n2b_big.in <== big; + + in === small + big * (1 << n); +} + +// split a n + m + k bit input into three outputs +template SplitThree(n, m, k) { + assert(n <= 126); + signal input in; + signal output small; + signal output medium; + signal output big; + + small <-- in % (1 << n); + medium <-- (in \ (1 << n)) % (1 << m); + big <-- in \ (1 << n + m); + + component n2b_small = Num2Bits(n); + n2b_small.in <== small; + component n2b_medium = Num2Bits(m); + n2b_medium.in <== medium; + component n2b_big = Num2Bits(k); + n2b_big.in <== big; + + in === small + medium * (1 << n) + big * (1 << n + m); +} + +// a[i], b[i] in 0... 2**n-1 +// represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k) +template BigAdd(n, k) { + assert(n <= 252); + signal input a[k]; + signal input b[k]; + signal output out[k + 1]; + + component unit0 = ModSum(n); + unit0.a <== a[0]; + unit0.b <== b[0]; + out[0] <== unit0.sum; + + component unit[k - 1]; + for (var i = 1; i < k; i++) { + unit[i - 1] = ModSumThree(n); + unit[i - 1].a <== a[i]; + unit[i - 1].b <== b[i]; + if (i == 1) { + unit[i - 1].c <== unit0.carry; + } else { + unit[i - 1].c <== unit[i - 2].carry; + } + out[i] <== unit[i - 1].sum; + } + out[k] <== unit[k - 2].carry; +} + +// a and b have n-bit registers +// a has ka registers, each with NONNEGATIVE ma-bit values (ma can be > n) +// b has kb registers, each with NONNEGATIVE mb-bit values (mb can be > n) +// out has ka + kb - 1 registers, each with (ma + mb + ceil(log(max(ka, kb))))-bit values +template BigMultNoCarry(n, ma, mb, ka, kb) { + assert(ma + mb <= 253); + signal input a[ka]; + signal input b[kb]; + signal output out[ka + kb - 1]; + + var prod_val[ka + kb - 1]; + for (var i = 0; i < ka + kb - 1; i++) { + prod_val[i] = 0; + } + for (var i = 0; i < ka; i++) { + for (var j = 0; j < kb; j++) { + prod_val[i + j] += a[i] * b[j]; + } + } + for (var i = 0; i < ka + kb - 1; i++) { + out[i] <-- prod_val[i]; + } + + var a_poly[ka + kb - 1]; + var b_poly[ka + kb - 1]; + var out_poly[ka + kb - 1]; + for (var i = 0; i < ka + kb - 1; i++) { + out_poly[i] = 0; + a_poly[i] = 0; + b_poly[i] = 0; + for (var j = 0; j < ka + kb - 1; j++) { + out_poly[i] = out_poly[i] + out[j] * (i ** j); + } + for (var j = 0; j < ka; j++) { + a_poly[i] = a_poly[i] + a[j] * (i ** j); + } + for (var j = 0; j < kb; j++) { + b_poly[i] = b_poly[i] + b[j] * (i ** j); + } + } + for (var i = 0; i < ka + kb - 1; i++) { + out_poly[i] === a_poly[i] * b_poly[i]; + } +} + + +// in[i] contains longs +// out[i] contains shorts +template LongToShortNoEndCarry(n, k) { + assert(n <= 126); + signal input in[k]; + signal output out[k+1]; + + var split[k][3]; + for (var i = 0; i < k; i++) { + split[i] = SplitThreeFn(in[i], n, n, n); + } + + var carry[k]; + carry[0] = 0; + out[0] <-- split[0][0]; + if (k == 1) { + out[1] <-- split[0][1]; + } + if (k > 1) { + var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], n, n); + out[1] <-- sumAndCarry[0]; + carry[1] = sumAndCarry[1]; + } + if (k == 2) { + out[2] <-- split[1][1] + split[0][2] + carry[1]; + } + if (k > 2) { + for (var i = 2; i < k; i++) { + var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], n, n); + out[i] <-- sumAndCarry[0]; + carry[i] = sumAndCarry[1]; + } + out[k] <-- split[k-1][1] + split[k-2][2] + carry[k-1]; + } + + component outRangeChecks[k+1]; + for (var i = 0; i < k+1; i++) { + outRangeChecks[i] = Num2Bits(n); + outRangeChecks[i].in <== out[i]; + } + + signal runningCarry[k]; + component runningCarryRangeChecks[k]; + runningCarry[0] <-- (in[0] - out[0]) / (1 << n); + runningCarryRangeChecks[0] = Num2Bits(n + log_ceil(k)); + runningCarryRangeChecks[0].in <== runningCarry[0]; + runningCarry[0] * (1 << n) === in[0] - out[0]; + for (var i = 1; i < k; i++) { + runningCarry[i] <-- (in[i] - out[i] + runningCarry[i-1]) / (1 << n); + runningCarryRangeChecks[i] = Num2Bits(n + log_ceil(k)); + runningCarryRangeChecks[i].in <== runningCarry[i]; + runningCarry[i] * (1 << n) === in[i] - out[i] + runningCarry[i-1]; + } + runningCarry[k-1] === out[k]; +} + +template BigMult(n, k) { + signal input a[k]; + signal input b[k]; + signal output out[2 * k]; + + component mult = BigMultNoCarry(n, n, n, k, k); + for (var i = 0; i < k; i++) { + mult.a[i] <== a[i]; + mult.b[i] <== b[i]; + } + + // no carry is possible in the highest order register + component longshort = LongToShortNoEndCarry(n, 2 * k - 1); + for (var i = 0; i < 2 * k - 1; i++) { + longshort.in[i] <== mult.out[i]; + } + for (var i = 0; i < 2 * k; i++) { + out[i] <== longshort.out[i]; + } +} + +template BigLessThan(n, k){ + signal input a[k]; + signal input b[k]; + signal output out; + + component lt[k]; + component eq[k]; + for (var i = 0; i < k; i++) { + lt[i] = LessThan(n); + lt[i].in[0] <== a[i]; + lt[i].in[1] <== b[i]; + eq[i] = IsEqual(); + eq[i].in[0] <== a[i]; + eq[i].in[1] <== b[i]; + } + + // ors[i] holds (lt[k - 1] || (eq[k - 1] && lt[k - 2]) .. || (eq[k - 1] && .. && lt[i])) + // ands[i] holds (eq[k - 1] && .. && lt[i]) + // eq_ands[i] holds (eq[k - 1] && .. && eq[i]) + component ors[k - 1]; + component ands[k - 1]; + component eq_ands[k - 1]; + for (var i = k - 2; i >= 0; i--) { + ands[i] = AND(); + eq_ands[i] = AND(); + ors[i] = OR(); + + if (i == k - 2) { + ands[i].a <== eq[k - 1].out; + ands[i].b <== lt[k - 2].out; + eq_ands[i].a <== eq[k - 1].out; + eq_ands[i].b <== eq[k - 2].out; + ors[i].a <== lt[k - 1].out; + ors[i].b <== ands[i].out; + } else { + ands[i].a <== eq_ands[i + 1].out; + ands[i].b <== lt[i].out; + eq_ands[i].a <== eq_ands[i + 1].out; + eq_ands[i].b <== eq[i].out; + ors[i].a <== ors[i + 1].out; + ors[i].b <== ands[i].out; + } + } + out <== ors[0].out; +} + +template BigIsEqual(k){ + signal input in[2][k]; + signal output out; + component isEqual[k+1]; + var sum = 0; + for(var i = 0; i < k; i++){ + isEqual[i] = IsEqual(); + isEqual[i].in[0] <== in[0][i]; + isEqual[i].in[1] <== in[1][i]; + sum = sum + isEqual[i].out; + } + + isEqual[k] = IsEqual(); + isEqual[k].in[0] <== sum; + isEqual[k].in[1] <== k; + out <== isEqual[k].out; +} + +// leading register of b should be non-zero +template BigMod(n, k) { + assert(n <= 126); + signal input a[2 * k]; + signal input b[k]; + + signal output div[k + 1]; + signal output mod[k]; + + var longdiv[2][100] = long_div(n, k, k, a, b); + for (var i = 0; i < k; i++) { + div[i] <-- longdiv[0][i]; + mod[i] <-- longdiv[1][i]; + } + div[k] <-- longdiv[0][k]; + component range_checks[k + 1]; + for (var i = 0; i <= k; i++) { + range_checks[i] = Num2Bits(n); + range_checks[i].in <== div[i]; + } + + component mul = BigMult(n, k + 1); + for (var i = 0; i < k; i++) { + mul.a[i] <== div[i]; + mul.b[i] <== b[i]; + } + mul.a[k] <== div[k]; + mul.b[k] <== 0; + + component add = BigAdd(n, 2 * k + 2); + for (var i = 0; i < 2 * k; i++) { + add.a[i] <== mul.out[i]; + if (i < k) { + add.b[i] <== mod[i]; + } else { + add.b[i] <== 0; + } + } + add.a[2 * k] <== mul.out[2 * k]; + add.a[2 * k + 1] <== mul.out[2 * k + 1]; + add.b[2 * k] <== 0; + add.b[2 * k + 1] <== 0; + + for (var i = 0; i < 2 * k; i++) { + add.out[i] === a[i]; + } + add.out[2 * k] === 0; + add.out[2 * k + 1] === 0; + + component lt = BigLessThan(n, k); + for (var i = 0; i < k; i++) { + lt.a[i] <== mod[i]; + lt.b[i] <== b[i]; + } + lt.out === 1; +} + +// a[i], b[i] in 0... 2**n-1 +// represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k) +// assume a >= b +template BigSub(n, k) { + assert(n <= 252); + signal input a[k]; + signal input b[k]; + signal output out[k]; + signal output underflow; + + component unit0 = ModSub(n); + unit0.a <== a[0]; + unit0.b <== b[0]; + out[0] <== unit0.out; + + component unit[k - 1]; + for (var i = 1; i < k; i++) { + unit[i - 1] = ModSubThree(n); + unit[i - 1].a <== a[i]; + unit[i - 1].b <== b[i]; + if (i == 1) { + unit[i - 1].c <== unit0.borrow; + } else { + unit[i - 1].c <== unit[i - 2].borrow; + } + out[i] <== unit[i - 1].out; + } + underflow <== unit[k - 2].borrow; +} + +// calculates (a - b) % p, where a, b < p +// note: does not assume a >= b +template BigSubModP(n, k){ + assert(n <= 252); + signal input a[k]; + signal input b[k]; + signal input p[k]; + signal output out[k]; + component sub = BigSub(n, k); + for (var i = 0; i < k; i++){ + sub.a[i] <== a[i]; + sub.b[i] <== b[i]; + } + signal flag; + flag <== sub.underflow; + component add = BigAdd(n, k); + for (var i = 0; i < k; i++){ + add.a[i] <== sub.out[i]; + add.b[i] <== flag * p[i]; + } + for (var i = 0; i < k; i++){ + out[i] <== add.out[i]; + } +} + +template BigMultModP(n, k) { + assert(n <= 252); + signal input a[k]; + signal input b[k]; + signal input p[k]; + signal output out[k]; + + component big_mult = BigMult(n, k); + for (var i = 0; i < k; i++) { + big_mult.a[i] <== a[i]; + big_mult.b[i] <== b[i]; + } + component big_mod = BigMod(n, k); + for (var i = 0; i < 2 * k; i++) { + big_mod.a[i] <== big_mult.out[i]; + } + for (var i = 0; i < k; i++) { + big_mod.b[i] <== p[i]; + } + for (var i = 0; i < k; i++) { + out[i] <== big_mod.mod[i]; + } +} + +template BigModInv(n, k) { + assert(n <= 252); + signal input in[k]; + signal input p[k]; + signal output out[k]; + + // length k + var inv[100] = mod_inv(n, k, in, p); + for (var i = 0; i < k; i++) { + out[i] <-- inv[i]; + } + component range_checks[k]; + for (var i = 0; i < k; i++) { + range_checks[i] = Num2Bits(n); + range_checks[i].in <== out[i]; + } + + component mult = BigMult(n, k); + for (var i = 0; i < k; i++) { + mult.a[i] <== in[i]; + mult.b[i] <== out[i]; + } + component mod = BigMod(n, k); + for (var i = 0; i < 2 * k; i++) { + mod.a[i] <== mult.out[i]; + } + for (var i = 0; i < k; i++) { + mod.b[i] <== p[i]; + } + mod.mod[0] === 1; + for (var i = 1; i < k; i++) { + mod.mod[i] === 0; + } +} + +// in[i] contains values in the range -2^(m-1) to 2^(m-1) +// constrain that in[] as a big integer is zero +// each limbs is n bits +template CheckCarryToZero(n, m, k) { + assert(k >= 2); + + var EPSILON = 3; + + assert(m + EPSILON <= 253); + + signal input in[k]; + + signal carry[k]; + component carryRangeChecks[k]; + for (var i = 0; i < k-1; i++){ + carryRangeChecks[i] = Num2Bits(m + EPSILON - n); + if( i == 0 ){ + carry[i] <-- in[i] / (1< 10944121435919637611123202872628637544274182200208017171849102093287904247808 ? 1 : 0; +} + +function div_ceil(m, n) { + var ret = 0; + if (m % n == 0) { + ret = m \ n; + } else { + ret = m \ n + 1; + } + return ret; +} + +function log_ceil(n) { + var n_temp = n; + for (var i = 0; i < 254; i++) { + if (n_temp == 0) { + return i; + } + n_temp = n_temp \ 2; + } + return 254; +} + +function SplitFn(in, n, m) { + return [in % (1 << n), (in \ (1 << n)) % (1 << m)]; +} + +function SplitThreeFn(in, n, m, k) { + return [in % (1 << n), (in \ (1 << n)) % (1 << m), (in \ (1 << n + m)) % (1 << k)]; +} + +// m bits per overflowed register (values are potentially negative) +// n bits per properly-sized register +// in has k registers +// out has k + ceil(m/n) - 1 + 1 registers. highest-order potentially negative, +// all others are positive +// - 1 since the last register is included in the last ceil(m/n) array +// + 1 since the carries from previous registers could push you over +function getProperRepresentation(m, n, k, in) { + var ceilMN = div_ceil(m, n); + + var out[100]; // should be out[k + ceilMN] + assert(k + ceilMN < 100); + for (var i = 0; i < k; i++) { + out[i] = in[i]; + } + for (var i = k; i < 100; i++) { + out[i] = 0; + } + assert(n <= m); + for (var i = 0; i+1 < k + ceilMN; i++) { + assert((1 << m) >= out[i] && out[i] >= -(1 << m)); + var shifted_val = out[i] + (1 << m); + assert(0 <= shifted_val && shifted_val <= (1 << (m+1))); + out[i] = shifted_val & ((1 << n) - 1); + out[i+1] += (shifted_val >> n) - (1 << (m - n)); + } + + return out; +} + +// Evaluate polynomial a at point x +function poly_eval(len, a, x) { + var v = 0; + for (var i = 0; i < len; i++) { + v += a[i] * (x ** i); + } + return v; +} + +// Interpolate a degree len-1 polynomial given its evaluations at 0..len-1 +function poly_interp(len, v) { + assert(len <= 200); + var out[200]; + for (var i = 0; i < len; i++) { + out[i] = 0; + } + + // Product_{i=0..len-1} (x-i) + var full_poly[201]; + full_poly[0] = 1; + for (var i = 0; i < len; i++) { + full_poly[i+1] = 0; + for (var j = i; j >= 0; j--) { + full_poly[j+1] += full_poly[j]; + full_poly[j] *= -i; + } + } + + for (var i = 0; i < len; i++) { + var cur_v = 1; + for (var j = 0; j < len; j++) { + if (i == j) { + // do nothing + } else { + cur_v *= i-j; + } + } + cur_v = v[i] / cur_v; + + var cur_rem = full_poly[len]; + for (var j = len-1; j >= 0; j--) { + out[j] += cur_v * cur_rem; + cur_rem = full_poly[j] + i * cur_rem; + } + assert(cur_rem == 0); + } + + return out; +} + +// 1 if true, 0 if false +function long_gt(n, k, a, b) { + for (var i = k - 1; i >= 0; i--) { + if (a[i] > b[i]) { + return 1; + } + if (a[i] < b[i]) { + return 0; + } + } + return 0; +} + +// n bits per register +// a has k registers +// b has k registers +// a >= b +function long_sub(n, k, a, b) { + var diff[100]; + var borrow[100]; + for (var i = 0; i < k; i++) { + if (i == 0) { + if (a[i] >= b[i]) { + diff[i] = a[i] - b[i]; + borrow[i] = 0; + } else { + diff[i] = a[i] - b[i] + (1 << n); + borrow[i] = 1; + } + } else { + if (a[i] >= b[i] + borrow[i - 1]) { + diff[i] = a[i] - b[i] - borrow[i - 1]; + borrow[i] = 0; + } else { + diff[i] = (1 << n) + a[i] - b[i] - borrow[i - 1]; + borrow[i] = 1; + } + } + } + return diff; +} + +// a is a n-bit scalar +// b has k registers +function long_scalar_mult(n, k, a, b) { + var out[100]; + for (var i = 0; i < 100; i++) { + out[i] = 0; + } + for (var i = 0; i < k; i++) { + var temp = out[i] + (a * b[i]); + out[i] = temp % (1 << n); + out[i + 1] = out[i + 1] + temp \ (1 << n); + } + return out; +} + + +// n bits per register +// a has k + m registers +// b has k registers +// out[0] has length m + 1 -- quotient +// out[1] has length k -- remainder +// implements algorithm of https://people.eecs.berkeley.edu/~fateman/282/F%20Wright%20notes/week4.pdf +function long_div(n, k, m, a, b){ + var out[2][100]; + m += k; + while (b[k-1] == 0) { + out[1][k] = 0; + k--; + assert(k > 0); + } + m -= k; + + var remainder[200]; + for (var i = 0; i < m + k; i++) { + remainder[i] = a[i]; + } + + var mult[200]; + var dividend[200]; + for (var i = m; i >= 0; i--) { + if (i == m) { + dividend[k] = 0; + for (var j = k - 1; j >= 0; j--) { + dividend[j] = remainder[j + m]; + } + } else { + for (var j = k; j >= 0; j--) { + dividend[j] = remainder[j + i]; + } + } + + out[0][i] = short_div(n, k, dividend, b); + + var mult_shift[100] = long_scalar_mult(n, k, out[0][i], b); + var subtrahend[200]; + for (var j = 0; j < m + k; j++) { + subtrahend[j] = 0; + } + for (var j = 0; j <= k; j++) { + if (i + j < m + k) { + subtrahend[i + j] = mult_shift[j]; + } + } + remainder = long_sub(n, m + k, remainder, subtrahend); + } + for (var i = 0; i < k; i++) { + out[1][i] = remainder[i]; + } + out[1][k] = 0; + + return out; +} + +// n bits per register +// a has k + 1 registers +// b has k registers +// assumes leading digit of b is at least 2 ** (n - 1) +// 0 <= a < (2**n) * b +function short_div_norm(n, k, a, b) { + var qhat = (a[k] * (1 << n) + a[k - 1]) \ b[k - 1]; + if (qhat > (1 << n) - 1) { + qhat = (1 << n) - 1; + } + + var mult[100] = long_scalar_mult(n, k, qhat, b); + if (long_gt(n, k + 1, mult, a) == 1) { + mult = long_sub(n, k + 1, mult, b); + if (long_gt(n, k + 1, mult, a) == 1) { + return qhat - 2; + } else { + return qhat - 1; + } + } else { + return qhat; + } +} + +// n bits per register +// a has k + 1 registers +// b has k registers +// assumes leading digit of b is non-zero +// 0 <= a < (2**n) * b +function short_div(n, k, a, b) { + var scale = (1 << n) \ (1 + b[k - 1]); + + // k + 2 registers now + var norm_a[200] = long_scalar_mult(n, k + 1, scale, a); + // k + 1 registers now + var norm_b[200] = long_scalar_mult(n, k, scale, b); + + var ret; + if (norm_b[k] != 0) { + ret = short_div_norm(n, k + 1, norm_a, norm_b); + } else { + ret = short_div_norm(n, k, norm_a, norm_b); + } + return ret; +} + +// n bits per register +// a and b both have k registers +// out[0] has length 2 * k +// adapted from BigMulShortLong and LongToShortNoEndCarry2 witness computation +function prod(n, k, a, b) { + // first compute the intermediate values. taken from BigMulShortLong + var prod_val[100]; // length is 2 * k - 1 + for (var i = 0; i < 2 * k - 1; i++) { + prod_val[i] = 0; + if (i < k) { + for (var a_idx = 0; a_idx <= i; a_idx++) { + prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; + } + } else { + for (var a_idx = i - k + 1; a_idx < k; a_idx++) { + prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; + } + } + } + + // now do a bunch of carrying to make sure registers not overflowed. taken from LongToShortNoEndCarry2 + var out[100]; // length is 2 * k + + var split[100][3]; // first dimension has length 2 * k - 1 + for (var i = 0; i < 2 * k - 1; i++) { + split[i] = SplitThreeFn(prod_val[i], n, n, n); + } + + var carry[100]; // length is 2 * k - 1 + carry[0] = 0; + out[0] = split[0][0]; + if (2 * k - 1 > 1) { + var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], n, n); + out[1] = sumAndCarry[0]; + carry[1] = sumAndCarry[1]; + } + if (2 * k - 1 > 2) { + for (var i = 2; i < 2 * k - 1; i++) { + var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], n, n); + out[i] = sumAndCarry[0]; + carry[i] = sumAndCarry[1]; + } + out[2 * k - 1] = split[2*k-2][1] + split[2*k-3][2] + carry[2*k-2]; + } + return out; +} + +// n bits per register +// a has k registers +// p has k registers +// e has k registers +// k * n <= 500 +// p is a prime +// computes a^e mod p +function mod_exp(n, k, a, p, e) { + var eBits[500]; // length is k * n + for (var i = 0; i < k; i++) { + for (var j = 0; j < n; j++) { + eBits[j + n * i] = (e[i] >> j) & 1; + } + } + + var out[100]; // length is k + for (var i = 0; i < 100; i++) { + out[i] = 0; + } + out[0] = 1; + + // repeated squaring + for (var i = k * n - 1; i >= 0; i--) { + // multiply by a if bit is 0 + if (eBits[i] == 1) { + var temp[200]; // length 2 * k + temp = prod(n, k, out, a); + var temp2[2][100]; + temp2 = long_div(n, k, k, temp, p); + out = temp2[1]; + } + + // square, unless we're at the end + if (i > 0) { + var temp[200]; // length 2 * k + temp = prod(n, k, out, out); + var temp2[2][100]; + temp2 = long_div(n, k, k, temp, p); + out = temp2[1]; + } + + } + return out; +} + +// n bits per register +// a has k registers +// p has k registers +// k * n <= 500 +// p is a prime +// if a == 0 mod p, returns 0 +// else computes inv = a^(p-2) mod p +function mod_inv(n, k, a, p) { + var isZero = 1; + for (var i = 0; i < k; i++) { + if (a[i] != 0) { + isZero = 0; + } + } + if (isZero == 1) { + var ret[100]; + for (var i = 0; i < k; i++) { + ret[i] = 0; + } + return ret; + } + + var pCopy[100]; + for (var i = 0; i < 100; i++) { + if (i < k) { + pCopy[i] = p[i]; + } else { + pCopy[i] = 0; + } + } + + var two[100]; + for (var i = 0; i < 100; i++) { + two[i] = 0; + } + two[0] = 2; + + var pMinusTwo[100]; + pMinusTwo = long_sub(n, k, pCopy, two); // length k + var out[100]; + out = mod_exp(n, k, a, pCopy, pMinusTwo); + return out; +} + +// a, b and out are all n bits k registers +function long_sub_mod_p(n, k, a, b, p){ + var gt = long_gt(n, k, a, b); + var tmp[100]; + if(gt){ + tmp = long_sub(n, k, a, b); + } + else{ + tmp = long_sub(n, k, b, a); + } + var out[2][100]; + for(var i = k;i < 2 * k; i++){ + tmp[i] = 0; + } + out = long_div(n, k, k, tmp, p); + if(gt==0){ + tmp = long_sub(n, k, p, out[1]); + } + return tmp; +} + +// a, b, p and out are all n bits k registers +function prod_mod_p(n, k, a, b, p){ + var tmp[100]; + var result[2][100]; + tmp = prod(n, k, a, b); + result = long_div(n, k, k, tmp, p); + return result[1]; +} diff --git a/app/ios/mopro/mopro-core/examples/circom/rsa/fp.circom b/app/ios/mopro/mopro-core/examples/circom/rsa/fp.circom new file mode 100644 index 000000000..224625168 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/rsa/fp.circom @@ -0,0 +1,144 @@ +pragma circom 2.1.5; + +include "./node_modules/circomlib/circuits/bitify.circom"; +include "./node_modules/circomlib/circuits/comparators.circom"; +include "./node_modules/circomlib/circuits/sign.circom"; +include "./bigint.circom"; +include "./bigint_func.circom"; + +// These functions operate over values in Z/Zp for some integer p (typically, +// but not necessarily prime). Values are stored as standard bignums with k +// chunks of n bits, but intermediate values often have "overflow" bits inside +// various chunks. +// +// These Fp functions will always correctly generate witnesses mod p, but they +// do not *check* that values are normalized to < p; they only check that +// values are correct mod p. This is to save the comparison circuit. +// They *will* always check for intended results mod p (soundness), but it may +// not have a unique intermediate signal. +// +// Conversely, some templates may not be satisfiable if the input witnesses are +// not < p. This does not break completeness, as honest provers will always +// generate witnesses which are canonical (between 0 and p). + +// a * b = r mod p +// a * b - p * q - r for some q +template FpMul(n, k) { + assert(n + n + log_ceil(k) + 2 <= 252); + signal input a[k]; + signal input b[k]; + signal input p[k]; + + signal output out[k]; + + signal v_ab[2*k-1]; + for (var x = 0; x < 2*k-1; x++) { + var v_a = poly_eval(k, a, x); + var v_b = poly_eval(k, b, x); + v_ab[x] <== v_a * v_b; + } + + var ab[200] = poly_interp(2*k-1, v_ab); + // ab_proper has length 2*k + var ab_proper[200] = getProperRepresentation(n + n + log_ceil(k), n, 2*k-1, ab); + + var long_div_out[2][100] = long_div(n, k, k, ab_proper, p); + + // Since we're only computing a*b, we know that q < p will suffice, so we + // know it fits into k chunks and can do size n range checks. + signal q[k]; + component q_range_check[k]; + signal r[k]; + component r_range_check[k]; + for (var i = 0; i < k; i++) { + q[i] <-- long_div_out[0][i]; + q_range_check[i] = Num2Bits(n); + q_range_check[i].in <== q[i]; + + r[i] <-- long_div_out[1][i]; + r_range_check[i] = Num2Bits(n); + r_range_check[i].in <== r[i]; + } + + signal v_pq_r[2*k-1]; + for (var x = 0; x < 2*k-1; x++) { + var v_p = poly_eval(k, p, x); + var v_q = poly_eval(k, q, x); + var v_r = poly_eval(k, r, x); + v_pq_r[x] <== v_p * v_q + v_r; + } + + signal v_t[2*k-1]; + for (var x = 0; x < 2*k-1; x++) { + v_t[x] <== v_ab[x] - v_pq_r[x]; + } + + var t[200] = poly_interp(2*k-1, v_t); + component tCheck = CheckCarryToZero(n, n + n + log_ceil(k) + 2, 2*k-1); + for (var i = 0; i < 2*k-1; i++) { + tCheck.in[i] <== t[i]; + } + + for (var i = 0; i < k; i++) { + out[i] <== r[i]; + } +} + +// Lifted from https://sourcegraph.com/github.com/darkforest-eth/circuits/-/blob/range_proof/circuit.circom +// NB: RangeProof is inclusive. +// input: field element, whose abs is claimed to be less than max_abs_value +// output: none +// we also want something like 4 * (abs(in) + max_abs_value) < 2 ** bits +// and bits << 256 +// NB: RangeProof is inclusive. +// input: field element, whose abs is claimed to be <= than max_abs_value +// output: none +// also checks that both max and abs(in) are expressible in `bits` bits +template RangeProof(bits) { + signal input in; + signal input max_abs_value; + + /* check that both max and abs(in) are expressible in `bits` bits */ + component n2b1 = Num2Bits(bits+1); + n2b1.in <== in + (1 << bits); + component n2b2 = Num2Bits(bits); + n2b2.in <== max_abs_value; + + /* check that in + max is between 0 and 2*max */ + component lowerBound = LessThan(bits+1); + component upperBound = LessThan(bits+1); + + lowerBound.in[0] <== max_abs_value + in; + lowerBound.in[1] <== 0; + lowerBound.out === 0; + + upperBound.in[0] <== 2 * max_abs_value; + upperBound.in[1] <== max_abs_value + in; + upperBound.out === 0; +} + +// input: n field elements, whose abs are claimed to be less than max_abs_value +// output: none +template MultiRangeProof(n, bits) { + signal input in[n]; + signal input max_abs_value; + component rangeProofs[n]; + + for (var i = 0; i < n; i++) { + rangeProofs[i] = RangeProof(bits); + rangeProofs[i].in <== in[i]; + rangeProofs[i].max_abs_value <== max_abs_value; + } +} + +template IsNegative(){ + signal input in; + signal output out; + component n2b = Num2Bits(254); + component sign = Sign(); + in ==> n2b.in; + for (var i = 0; i<254; i++) { + n2b.out[i] ==> sign.in[i]; + } + sign.sign ==> out; +} diff --git a/app/ios/mopro/mopro-core/examples/circom/rsa/main.circom b/app/ios/mopro/mopro-core/examples/circom/rsa/main.circom new file mode 100644 index 000000000..c612ef873 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/rsa/main.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.5; + +include "./rsa.circom"; + +component main{public [modulus]} = RSAVerify65537(64, 32); diff --git a/app/ios/mopro/mopro-core/examples/circom/rsa/package-lock.json b/app/ios/mopro/mopro-core/examples/circom/rsa/package-lock.json new file mode 100644 index 000000000..123c85535 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/rsa/package-lock.json @@ -0,0 +1,21 @@ +{ + "name": "circom", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "circom", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "circomlib": "^2.0.5" + } + }, + "node_modules/circomlib": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/circomlib/-/circomlib-2.0.5.tgz", + "integrity": "sha512-O7NQ8OS+J4eshBuoy36z/TwQU0YHw8W3zxZcs4hVwpEll3e4hDm3mgkIPqItN8FDeLEKZFK3YeT/+k8TiLF3/A==" + } + } +} diff --git a/app/ios/mopro/mopro-core/examples/circom/rsa/rsa.circom b/app/ios/mopro/mopro-core/examples/circom/rsa/rsa.circom new file mode 100644 index 000000000..64fda6719 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/rsa/rsa.circom @@ -0,0 +1,156 @@ +pragma circom 2.1.5; + +include "./fp.circom"; + +// Computes base^65537 mod modulus +// Does not necessarily reduce fully mod modulus (the answer could be +// too big by a multiple of modulus) +template FpPow65537Mod(n, k) { + signal input base[k]; + // Exponent is hardcoded at 65537 + signal input modulus[k]; + signal output out[k]; + + component doublers[16]; + component adder = FpMul(n, k); + for (var i = 0; i < 16; i++) { + doublers[i] = FpMul(n, k); + } + + for (var j = 0; j < k; j++) { + adder.p[j] <== modulus[j]; + for (var i = 0; i < 16; i++) { + doublers[i].p[j] <== modulus[j]; + } + } + for (var j = 0; j < k; j++) { + doublers[0].a[j] <== base[j]; + doublers[0].b[j] <== base[j]; + } + for (var i = 0; i + 1 < 16; i++) { + for (var j = 0; j < k; j++) { + doublers[i + 1].a[j] <== doublers[i].out[j]; + doublers[i + 1].b[j] <== doublers[i].out[j]; + } + } + for (var j = 0; j < k; j++) { + adder.a[j] <== base[j]; + adder.b[j] <== doublers[15].out[j]; + } + for (var j = 0; j < k; j++) { + out[j] <== adder.out[j]; + } +} + +template RSAPad(n, k) { + signal input modulus[k]; + signal input base_message[k]; + signal output padded_message[k]; + + var base_len = 280; + var msg_len = 160; + + signal padded_message_bits[n*k]; + + component modulus_n2b[k]; + component base_message_n2b[k]; + signal modulus_bits[n*k]; + signal base_message_bits[n*k]; + for (var i = 0; i < k; i++) { + base_message_n2b[i] = Num2Bits(n); + base_message_n2b[i].in <== base_message[i]; + for (var j = 0; j < n; j++) { + base_message_bits[i*n+j] <== base_message_n2b[i].out[j]; + } + modulus_n2b[i] = Num2Bits(n); + modulus_n2b[i].in <== modulus[i]; + for (var j = 0; j < n; j++) { + modulus_bits[i*n+j] <== modulus_n2b[i].out[j]; + } + } + + for (var i = msg_len; i < n*k; i++) { + base_message_bits[i] === 0; + } + + for (var i = 0; i < msg_len; i++) { + padded_message_bits[i] <== base_message_bits[i]; + } + + for (var i = base_len; i < base_len + 8; i++) { + padded_message_bits[i] <== 0; + } + + for (var i = msg_len; i < base_len; i++) { + padded_message_bits[i] <== (0x3021300906052b0e03021a05000414 >> (i - msg_len)) & 1; + } + + component modulus_zero[(n*k + 7 - (base_len + 8))\8]; + { + var modulus_prefix = 0; + for (var i = n*k - 1; i >= base_len + 8; i--) { + if (i+8 < n*k) { + modulus_prefix += modulus_bits[i+8]; + if (i % 8 == 0) { + var idx = (i - (base_len + 8)) / 8; + modulus_zero[idx] = IsZero(); + modulus_zero[idx].in <== modulus_prefix; + padded_message_bits[i] <== 1-modulus_zero[idx].out; + } else { + padded_message_bits[i] <== padded_message_bits[i+1]; + } + } else { + padded_message_bits[i] <== 0; + } + } + } + + // The RFC guarantees at least 8 octets of 0xff padding. + assert(base_len + 8 + 65 <= n*k); + for (var i = base_len + 8; i < base_len + 8 + 65; i++) { + padded_message_bits[i] === 1; + } + + component padded_message_b2n[k]; + for (var i = 0; i < k; i++) { + padded_message_b2n[i] = Bits2Num(n); + for (var j = 0; j < n; j++) { + padded_message_b2n[i].in[j] <== padded_message_bits[i*n+j]; + } + padded_message[i] <== padded_message_b2n[i].out; + } +} + +template RSAVerify65537(n, k) { + signal input signature[k]; + signal input modulus[k]; + signal input base_message[k]; + + component padder = RSAPad(n, k); + for (var i = 0; i < k; i++) { + padder.modulus[i] <== modulus[i]; + padder.base_message[i] <== base_message[i]; + } + + // Check that the signature is in proper form and reduced mod modulus. + component signatureRangeCheck[k]; + component bigLessThan = BigLessThan(n, k); + for (var i = 0; i < k; i++) { + signatureRangeCheck[i] = Num2Bits(n); + signatureRangeCheck[i].in <== signature[i]; + bigLessThan.a[i] <== signature[i]; + bigLessThan.b[i] <== modulus[i]; + } + bigLessThan.out === 1; + + component bigPow = FpPow65537Mod(n, k); + for (var i = 0; i < k; i++) { + bigPow.base[i] <== signature[i]; + bigPow.modulus[i] <== modulus[i]; + } + // By construction of the padding, the padded message is necessarily + // smaller than the modulus. Thus, we don't have to check that bigPow is fully reduced. + for (var i = 0; i < k; i++) { + bigPow.out[i] === padder.padded_message[i]; + } +} diff --git a/app/ios/mopro/mopro-core/examples/circom/scripts/compile.sh b/app/ios/mopro/mopro-core/examples/circom/scripts/compile.sh new file mode 100755 index 000000000..8d8dd82be --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/scripts/compile.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Example usage: +# ./scripts/compile.sh multiplier2 multiplier2.circom + +# Deal with errors +set -euo pipefail + +# Check if arguments are provided +if [ "$#" -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi + +DIR="$1" +CIRCUIT="$2" + +mkdir -p ${DIR}/target +circom ./${DIR}/${CIRCUIT} --r1cs --wasm --sym --output ./${DIR}/target \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/examples/circom/scripts/generate_arkzkey.sh b/app/ios/mopro/mopro-core/examples/circom/scripts/generate_arkzkey.sh new file mode 100755 index 000000000..d80db52f8 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/scripts/generate_arkzkey.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Example usage: +# ./scripts/generate_arkzkey.sh multiplier2 multiplier2 + +# Assumes inside target directory + +# Deal with errors +set -euo pipefail + +# Check if arguments are provided +if [ "$#" -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi + +DIR="$1" +CIRCUIT="$2" +ZKEY_PATH="${DIR}/target/${CIRCUIT}_final.zkey" +ARKZKEY_PATH="${DIR}/target/${CIRCUIT}_final.arkzkey" + +# Check if ZKEY_PATH exists +if [ ! -f "$ZKEY_PATH" ]; then + echo "Error: ZKEY_PATH does not exist at ${ZKEY_PATH}" + exit 1 +fi + +# Check if arkzkey-util command exists +if ! command -v arkzkey-util &> /dev/null; then + echo "Error: arkzkey-util command is not available." + exit 1 +fi + +echo "Generate arkzkey file for ${CIRCUIT}..." +if [ ! -f "${ARKZKEY_PATH}" ]; then + arkzkey-util ${ZKEY_PATH} +else + echo "File ${ARKZKEY_PATH} already exists, skipping." +fi + +echo "arkzkey file generation done, arkzkey file is in ${ARKZKEY_PATH}" \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/examples/circom/scripts/trusted_setup.sh b/app/ios/mopro/mopro-core/examples/circom/scripts/trusted_setup.sh new file mode 100755 index 000000000..312e43675 --- /dev/null +++ b/app/ios/mopro/mopro-core/examples/circom/scripts/trusted_setup.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# Example usage: +# ./scripts/trusted_setup.sh multiplier2 08 multiplier2 + +# Deal with errors +set -euo pipefail + +# Change this is if you keep your Powers of Tau files elsewhere +PTAU_DIR="ptau" + +# Check if arguments are provided +if [ "$#" -ne 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +DIR="$1" +PTAU="$2" +CIRCUIT="$3" +PTAU_PATH="${PTAU_DIR}/powersOfTau28_hez_final_${PTAU}.ptau" + +# Phase 1 - Perpetual Powers of Tau +# From https://github.com/iden3/snarkjs + +if [ ! -f "$PTAU_PATH" ]; then + echo "Downloading Powers of Tau file..." + wget -P $PTAU_DIR https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_${PTAU}.ptau +else + echo "File $PTAU_PATH already exists, skipping download." +fi + +# Phase 2 - Circuit specific setup +# Toy example, not for production use +# For a real deployment with Groth16 use a tool like p0tion for phase 2 trusted setup +# See https://github.com/privacy-scaling-explorations/p0tion + +echo "Generate zkey file for ${CIRCUIT}..." +if [ ! -f "${DIR}/target/${CIRCUIT}_final.zkey" ]; then + snarkjs groth16 setup ${DIR}/target/${CIRCUIT}.r1cs ${PTAU_PATH} ${DIR}/target/${CIRCUIT}_0000.zkey + snarkjs zkey contribute ${DIR}/target/${CIRCUIT}_0000.zkey ${DIR}/target/${CIRCUIT}_final.zkey \ + --name="Demo contribution" -e="0xdeadbeef" +else + echo "File ${DIR}/target/${CIRCUIT}_final.zkey already exists, skipping." +fi + +echo "Trusted setup done, zkey file is in ${DIR}/target/${CIRCUIT}_final.zkey" \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/src/lib.rs b/app/ios/mopro/mopro-core/src/lib.rs new file mode 100644 index 000000000..2ac7b546f --- /dev/null +++ b/app/ios/mopro/mopro-core/src/lib.rs @@ -0,0 +1,8 @@ +pub mod middleware; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum MoproError { + #[error("CircomError: {0}")] + CircomError(String), +} diff --git a/app/ios/mopro/mopro-core/src/middleware/circom/mod.rs b/app/ios/mopro/mopro-core/src/middleware/circom/mod.rs new file mode 100644 index 000000000..0cf497fc9 --- /dev/null +++ b/app/ios/mopro/mopro-core/src/middleware/circom/mod.rs @@ -0,0 +1,860 @@ +use self::{ + serialization::{SerializableInputs, SerializableProof, SerializableProvingKey}, + utils::{assert_paths_exists, bytes_to_bits}, +}; +use crate::MoproError; + +use std::collections::HashMap; +//use std::io::Cursor; +use std::sync::Mutex; +use std::time::Instant; + +use ark_bn254::{Bn254, Fr}; +use ark_circom::{ + CircomBuilder, + CircomCircuit, + CircomConfig, + CircomReduction, + WitnessCalculator, //read_zkey, +}; +use ark_crypto_primitives::snark::SNARK; +use ark_groth16::{prepare_verifying_key, Groth16, ProvingKey}; +use ark_std::UniformRand; + +use ark_relations::r1cs::ConstraintMatrices; +use ark_std::rand::thread_rng; +use color_eyre::Result; +use core::include_bytes; +use num_bigint::BigInt; +use once_cell::sync::{Lazy, OnceCell}; + +use wasmer::{Module, Store}; + +use ark_zkey::read_arkzkey_from_bytes; //SerializableConstraintMatrices + +#[cfg(feature = "dylib")] +use { + std::{env, path::Path}, + wasmer::Dylib, +}; + +pub mod serialization; +pub mod utils; + +type GrothBn = Groth16; + +type CircuitInputs = HashMap>; + +// TODO: Split up this namespace a bit, right now quite a lot of things going on + +pub struct CircomState { + builder: Option>, + circuit: Option>, + params: Option>, +} + +impl Default for CircomState { + fn default() -> Self { + Self::new() + } +} + +// NOTE: A lot of the contents of this file is inspired by github.com/worldcoin/semaphore-rs + +// TODO: Replace printlns with logging + +//const ZKEY_BYTES: &[u8] = include_bytes!(env!("BUILD_RS_ZKEY_FILE")); + +const ARKZKEY_BYTES: &[u8] = include_bytes!(env!("BUILD_RS_ARKZKEY_FILE")); + +// static ZKEY: Lazy<(ProvingKey, ConstraintMatrices)> = Lazy::new(|| { +// let mut reader = Cursor::new(ZKEY_BYTES); +// read_zkey(&mut reader).expect("Failed to read zkey") +// }); + +static ARKZKEY: Lazy<(ProvingKey, ConstraintMatrices)> = Lazy::new(|| { + //let mut reader = Cursor::new(ARKZKEY_BYTES); + // TODO: Use reader? More flexible; unclear if perf diff + read_arkzkey_from_bytes(ARKZKEY_BYTES).expect("Failed to read arkzkey") +}); + +const WASM: &[u8] = include_bytes!(env!("BUILD_RS_WASM_FILE")); + +/// `WITNESS_CALCULATOR` is a lazily initialized, thread-safe singleton of type `WitnessCalculator`. +/// `OnceCell` ensures that the initialization occurs exactly once, and `Mutex` allows safe shared +/// access from multiple threads. +static WITNESS_CALCULATOR: OnceCell> = OnceCell::new(); + +/// Initializes the `WITNESS_CALCULATOR` singleton with a `WitnessCalculator` instance created from +/// a specified dylib file (WASM circuit). Also initialize `ZKEY`. +#[cfg(feature = "dylib")] +pub fn initialize(dylib_path: &Path) { + println!("Initializing dylib: {:?}", dylib_path); + + WITNESS_CALCULATOR + .set(from_dylib(dylib_path)) + .expect("Failed to set WITNESS_CALCULATOR"); + + // Initialize ARKZKEY + // TODO: Speed this up even more + let now = std::time::Instant::now(); + Lazy::force(&ARKZKEY); + println!("Initializing arkzkey took: {:.2?}", now.elapsed()); +} + +#[cfg(not(feature = "dylib"))] +pub fn initialize() { + println!("Initializing library with arkzkey"); + + // Initialize ARKZKEY + // TODO: Speed this up even more! + let now = std::time::Instant::now(); + Lazy::force(&ARKZKEY); + println!("Initializing arkzkey took: {:.2?}", now.elapsed()); +} + +/// Creates a `WitnessCalculator` instance from a dylib file. +#[cfg(feature = "dylib")] +fn from_dylib(path: &Path) -> Mutex { + let store = Store::new(&Dylib::headless().engine()); + let module = unsafe { + Module::deserialize_from_file(&store, path).expect("Failed to load dylib module") + }; + let result = + WitnessCalculator::from_module(module).expect("Failed to create WitnessCalculator"); + + Mutex::new(result) +} + +// #[must_use] +// pub fn zkey() -> &'static (ProvingKey, ConstraintMatrices) { +// &ZKEY +// } + +// Experimental +#[must_use] +pub fn arkzkey() -> &'static (ProvingKey, ConstraintMatrices) { + &ARKZKEY +} + +/// Provides access to the `WITNESS_CALCULATOR` singleton, initializing it if necessary. +/// It expects the path to the dylib file to be set in the `CIRCUIT_WASM_DYLIB` environment variable. +#[cfg(feature = "dylib")] +#[must_use] +pub fn witness_calculator() -> &'static Mutex { + let var_name = "CIRCUIT_WASM_DYLIB"; + + WITNESS_CALCULATOR.get_or_init(|| { + let path = env::var(var_name).unwrap_or_else(|_| { + panic!( + "Mopro circuit WASM Dylib not initialized. \ + Please set {} environment variable to the path of the dylib file", + var_name + ) + }); + from_dylib(Path::new(&path)) + }) +} + +#[cfg(not(feature = "dylib"))] +#[must_use] +pub fn witness_calculator() -> &'static Mutex { + WITNESS_CALCULATOR.get_or_init(|| { + let store = Store::default(); + let module = Module::from_binary(&store, WASM).expect("WASM should be valid"); + let result = + WitnessCalculator::from_module(module).expect("Failed to create WitnessCalculator"); + Mutex::new(result) + }) +} + +pub fn generate_proof2( + inputs: CircuitInputs, +) -> Result<(SerializableProof, SerializableInputs), MoproError> { + let mut rng = thread_rng(); + let rng = &mut rng; + + let r = ark_bn254::Fr::rand(rng); + let s = ark_bn254::Fr::rand(rng); + + println!("Generating proof 2"); + + let now = std::time::Instant::now(); + let full_assignment = witness_calculator() + .lock() + .expect("Failed to lock witness calculator") + .calculate_witness_element::(inputs, false) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + println!("Witness generation took: {:.2?}", now.elapsed()); + + let now = std::time::Instant::now(); + //let zkey = zkey(); + let zkey = arkzkey(); + println!("Loading arkzkey took: {:.2?}", now.elapsed()); + + let public_inputs = full_assignment.as_slice()[1..zkey.1.num_instance_variables].to_vec(); + + let now = std::time::Instant::now(); + let ark_proof = Groth16::<_, CircomReduction>::create_proof_with_reduction_and_matrices( + &zkey.0, + r, + s, + &zkey.1, + zkey.1.num_instance_variables, + zkey.1.num_constraints, + full_assignment.as_slice(), + ); + + let proof = ark_proof.map_err(|e| MoproError::CircomError(e.to_string()))?; + + println!("proof generation took: {:.2?}", now.elapsed()); + + // TODO: Add SerializableInputs(inputs))) + Ok((SerializableProof(proof), SerializableInputs(public_inputs))) +} + +pub fn verify_proof2( + serialized_proof: SerializableProof, + serialized_inputs: SerializableInputs, +) -> Result { + let start = Instant::now(); + let zkey = arkzkey(); + let pvk = prepare_verifying_key(&zkey.0.vk); + + let proof_verified = + GrothBn::verify_with_processed_vk(&pvk, &serialized_inputs.0, &serialized_proof.0) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + let verification_duration = start.elapsed(); + println!("Verification time 2: {:?}", verification_duration); + Ok(proof_verified) +} + +impl CircomState { + pub fn new() -> Self { + Self { + builder: None, + circuit: None, + params: None, + } + } + + pub fn setup( + &mut self, + wasm_path: &str, + r1cs_path: &str, + ) -> Result { + assert_paths_exists(wasm_path, r1cs_path)?; + println!("Setup"); + let start = Instant::now(); + + // Load the WASM and R1CS for witness and proof generation + let cfg = self.load_config(wasm_path, r1cs_path)?; + + // Create an empty instance for setup + self.builder = Some(CircomBuilder::new(cfg)); + + // Run a trusted setup using the rng in the state + let params = self.run_trusted_setup()?; + + self.params = Some(params.clone()); + + let setup_duration = start.elapsed(); + println!("Setup time: {:?}", setup_duration); + + Ok(SerializableProvingKey(params)) + } + + // NOTE: Consider generate_proof> API + // XXX: BigInt might present problems for UniFFI + pub fn generate_proof( + &mut self, + inputs: CircuitInputs, + ) -> Result<(SerializableProof, SerializableInputs), MoproError> { + let start = Instant::now(); + println!("Generating proof"); + + let mut rng = thread_rng(); + + let builder = self.builder.as_mut().ok_or(MoproError::CircomError( + "Builder has not been set up".to_string(), + ))?; + + // Insert our inputs as key value pairs + for (key, values) in &inputs { + for value in values { + builder.push_input(&key, value.clone()); + } + } + + // Clone the builder, then build the circuit + let circom = builder + .clone() + .build() + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + // Update the circuit in self + self.circuit = Some(circom.clone()); + + let params = self.params.as_ref().ok_or(MoproError::CircomError( + "Parameters have not been set up".to_string(), + ))?; + + let inputs = circom.get_public_inputs().ok_or(MoproError::CircomError( + "Failed to get public inputs".to_string(), + ))?; + + let proof = GrothBn::prove(params, circom.clone(), &mut rng) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + let proof_duration = start.elapsed(); + println!("Proof generation time: {:?}", proof_duration); + + Ok((SerializableProof(proof), SerializableInputs(inputs))) + } + + pub fn verify_proof( + &self, + serialized_proof: SerializableProof, + serialized_inputs: SerializableInputs, + ) -> Result { + let start = Instant::now(); + + println!("Verifying proof"); + + let params = self.params.as_ref().ok_or(MoproError::CircomError( + "Parameters have not been set up".to_string(), + ))?; + + let pvk = + GrothBn::process_vk(¶ms.vk).map_err(|e| MoproError::CircomError(e.to_string()))?; + + let proof_verified = + GrothBn::verify_with_processed_vk(&pvk, &serialized_inputs.0, &serialized_proof.0) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + let verification_duration = start.elapsed(); + println!("Verification time: {:?}", verification_duration); + Ok(proof_verified) + } + + fn load_config( + &self, + wasm_path: &str, + r1cs_path: &str, + ) -> Result, MoproError> { + CircomConfig::::new(wasm_path, r1cs_path) + .map_err(|e| MoproError::CircomError(e.to_string())) + } + + fn run_trusted_setup(&mut self) -> Result, MoproError> { + let circom_setup = self + .builder + .as_mut() + .ok_or(MoproError::CircomError( + "Builder has not been set up".to_string(), + ))? + .setup(); + + let mut rng = thread_rng(); + + GrothBn::generate_random_parameters_with_reduction(circom_setup, &mut rng) + .map_err(|e| MoproError::CircomError(e.to_string())) + } +} + +// Helper function for Keccak256 example +pub fn bytes_to_circuit_inputs(bytes: &[u8]) -> CircuitInputs { + let bits = bytes_to_bits(bytes); + let big_int_bits = bits + .into_iter() + .map(|bit| BigInt::from(bit as u8)) + .collect(); + let mut inputs = HashMap::new(); + inputs.insert("in".to_string(), big_int_bits); + inputs +} + +pub fn strings_to_circuit_inputs(strings: &[&str]) -> Vec { + strings + .iter() + .map(|&value| BigInt::parse_bytes(value.as_bytes(), 10).unwrap()) + .collect() +} + +pub fn bytes_to_circuit_outputs(bytes: &[u8]) -> SerializableInputs { + let bits = bytes_to_bits(bytes); + let field_bits = bits.into_iter().map(|bit| Fr::from(bit as u8)).collect(); + SerializableInputs(field_bits) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_setup_prove_verify_simple() { + let wasm_path = "./examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"; + let r1cs_path = "./examples/circom/multiplier2/target/multiplier2.r1cs"; + + // Instantiate CircomState + let mut circom_state = CircomState::new(); + + // Setup + let setup_res = circom_state.setup(wasm_path, r1cs_path); + assert!(setup_res.is_ok()); + + let _serialized_pk = setup_res.unwrap(); + + // Deserialize the proving key and inputs if necessary + + // Prepare inputs + let mut inputs = HashMap::new(); + let a = 3; + let b = 5; + let c = a * b; + inputs.insert("a".to_string(), vec![BigInt::from(a)]); + inputs.insert("b".to_string(), vec![BigInt::from(b)]); + // output = [public output c, public input a] + let expected_output = vec![Fr::from(c), Fr::from(a)]; + let serialized_outputs = SerializableInputs(expected_output); + + // Proof generation + let generate_proof_res = circom_state.generate_proof(inputs); + + // Check and print the error if there is one + if let Err(e) = &generate_proof_res { + println!("Error: {:?}", e); + } + + assert!(generate_proof_res.is_ok()); + + let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); + + // Check output + assert_eq!(serialized_inputs, serialized_outputs); + + // Proof verification + let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs); + assert!(verify_res.is_ok()); + assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified + } + + #[test] + fn test_setup_prove_verify_keccak() { + let wasm_path = + "./examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm"; + let r1cs_path = "./examples/circom/keccak256/target/keccak256_256_test.r1cs"; + + // Instantiate CircomState + let mut circom_state = CircomState::new(); + + // Setup + let setup_res = circom_state.setup(wasm_path, r1cs_path); + assert!(setup_res.is_ok()); + + let _serialized_pk = setup_res.unwrap(); + + // Deserialize the proving key and inputs if necessary + + // Prepare inputs + let input_vec = vec![ + 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, + ]; + + // Expected output + let expected_output_vec = vec![ + 37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, + 212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, + ]; + + let inputs = bytes_to_circuit_inputs(&input_vec); + let serialized_outputs = bytes_to_circuit_outputs(&expected_output_vec); + + // Proof generation + let generate_proof_res = circom_state.generate_proof(inputs); + + // Check and print the error if there is one + if let Err(e) = &generate_proof_res { + println!("Error: {:?}", e); + } + + assert!(generate_proof_res.is_ok()); + + let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); + + // Check output + assert_eq!(serialized_inputs, serialized_outputs); + + // Proof verification + let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs); + assert!(verify_res.is_ok()); + + assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified + } + + #[test] + fn test_setup_error() { + // Arrange: Create a new CircomState instance + let mut circom_state = CircomState::new(); + + let wasm_path = "badpath/multiplier2.wasm"; + let r1cs_path = "badpath/multiplier2.r1cs"; + + // Act: Call the setup method + let result = circom_state.setup(wasm_path, r1cs_path); + + // Assert: Check that the method returns an error + assert!(result.is_err()); + } + + #[cfg(feature = "dylib")] + #[test] + fn test_dylib_init_and_generate_witness() { + // Assumes that the dylib file has been built and is in the following location + let dylib_path = "target/debug/aarch64-apple-darwin/keccak256.dylib"; + + // Initialize libray + initialize(Path::new(&dylib_path)); + + let input_vec = vec![ + 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 inputs = bytes_to_circuit_inputs(&input_vec); + let now = std::time::Instant::now(); + let full_assignment = witness_calculator() + .lock() + .expect("Failed to lock witness calculator") + .calculate_witness_element::(inputs, false) + .map_err(|e| MoproError::CircomError(e.to_string())); + + println!("Witness generation took: {:.2?}", now.elapsed()); + + assert!(full_assignment.is_ok()); + } + + #[test] + fn test_generate_proof2() { + // XXX: This can be done better + #[cfg(feature = "dylib")] + { + // Assumes that the dylib file has been built and is in the following location + let dylib_path = "target/debug/aarch64-apple-darwin/keccak256.dylib"; + + // Initialize libray + initialize(Path::new(&dylib_path)); + } + + let input_vec = vec![ + 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 expected_output_vec = vec![ + 37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, + 212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, + ]; + let inputs = bytes_to_circuit_inputs(&input_vec); + let serialized_outputs = bytes_to_circuit_outputs(&expected_output_vec); + + let generate_proof_res = generate_proof2(inputs); + let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); + assert_eq!(serialized_inputs, serialized_outputs); + + // Proof verification + let verify_res = verify_proof2(serialized_proof, serialized_inputs); + assert!(verify_res.is_ok()); + assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified + } + + #[ignore = "ignore for ci"] + #[test] + fn test_setup_prove_rsa() { + let wasm_path = "./examples/circom/rsa/target/main_js/main.wasm"; + let r1cs_path = "./examples/circom/rsa/target/main.r1cs"; + + // Instantiate CircomState + let mut circom_state = CircomState::new(); + + // Setup + let setup_res = circom_state.setup(wasm_path, r1cs_path); + assert!(setup_res.is_ok()); + + let _serialized_pk = setup_res.unwrap(); + + // Deserialize the proving key and inputs if necessary + + // Prepare inputs + let signature = [ + "3582320600048169363", + "7163546589759624213", + "18262551396327275695", + "4479772254206047016", + "1970274621151677644", + "6547632513799968987", + "921117808165172908", + "7155116889028933260", + "16769940396381196125", + "17141182191056257954", + "4376997046052607007", + "17471823348423771450", + "16282311012391954891", + "70286524413490741", + "1588836847166444745", + "15693430141227594668", + "13832254169115286697", + "15936550641925323613", + "323842208142565220", + "6558662646882345749", + "15268061661646212265", + "14962976685717212593", + "15773505053543368901", + "9586594741348111792", + "1455720481014374292", + "13945813312010515080", + "6352059456732816887", + "17556873002865047035", + "2412591065060484384", + "11512123092407778330", + "8499281165724578877", + "12768005853882726493", + ]; + let modulus = [ + "13792647154200341559", + "12773492180790982043", + "13046321649363433702", + "10174370803876824128", + "7282572246071034406", + "1524365412687682781", + "4900829043004737418", + "6195884386932410966", + "13554217876979843574", + "17902692039595931737", + "12433028734895890975", + "15971442058448435996", + "4591894758077129763", + "11258250015882429548", + "16399550288873254981", + "8246389845141771315", + "14040203746442788850", + "7283856864330834987", + "12297563098718697441", + "13560928146585163504", + "7380926829734048483", + "14591299561622291080", + "8439722381984777599", + "17375431987296514829", + "16727607878674407272", + "3233954801381564296", + "17255435698225160983", + "15093748890170255670", + "15810389980847260072", + "11120056430439037392", + "5866130971823719482", + "13327552690270163501", + ]; + let base_message = [ + "18114495772705111902", + "2254271930739856077", + "2068851770", + "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", + "0", + ]; + + let mut inputs: HashMap> = HashMap::new(); + inputs.insert( + "signature".to_string(), + strings_to_circuit_inputs(&signature), + ); + inputs.insert("modulus".to_string(), strings_to_circuit_inputs(&modulus)); + inputs.insert( + "base_message".to_string(), + strings_to_circuit_inputs(&base_message), + ); + + // Proof generation + let generate_proof_res = circom_state.generate_proof(inputs); + + // Check and print the error if there is one + if let Err(e) = &generate_proof_res { + println!("Error: {:?}", e); + } + + assert!(generate_proof_res.is_ok()); + + let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); + + // Proof verification + let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs); + assert!(verify_res.is_ok()); + + assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified + } + + #[ignore = "ignore for ci"] + #[test] + fn test_setup_prove_rsa2() { + // Prepare inputs + let signature = [ + "3582320600048169363", + "7163546589759624213", + "18262551396327275695", + "4479772254206047016", + "1970274621151677644", + "6547632513799968987", + "921117808165172908", + "7155116889028933260", + "16769940396381196125", + "17141182191056257954", + "4376997046052607007", + "17471823348423771450", + "16282311012391954891", + "70286524413490741", + "1588836847166444745", + "15693430141227594668", + "13832254169115286697", + "15936550641925323613", + "323842208142565220", + "6558662646882345749", + "15268061661646212265", + "14962976685717212593", + "15773505053543368901", + "9586594741348111792", + "1455720481014374292", + "13945813312010515080", + "6352059456732816887", + "17556873002865047035", + "2412591065060484384", + "11512123092407778330", + "8499281165724578877", + "12768005853882726493", + ]; + let modulus = [ + "13792647154200341559", + "12773492180790982043", + "13046321649363433702", + "10174370803876824128", + "7282572246071034406", + "1524365412687682781", + "4900829043004737418", + "6195884386932410966", + "13554217876979843574", + "17902692039595931737", + "12433028734895890975", + "15971442058448435996", + "4591894758077129763", + "11258250015882429548", + "16399550288873254981", + "8246389845141771315", + "14040203746442788850", + "7283856864330834987", + "12297563098718697441", + "13560928146585163504", + "7380926829734048483", + "14591299561622291080", + "8439722381984777599", + "17375431987296514829", + "16727607878674407272", + "3233954801381564296", + "17255435698225160983", + "15093748890170255670", + "15810389980847260072", + "11120056430439037392", + "5866130971823719482", + "13327552690270163501", + ]; + let base_message = [ + "18114495772705111902", + "2254271930739856077", + "2068851770", + "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", + "0", + ]; + + let mut inputs: HashMap> = HashMap::new(); + inputs.insert( + "signature".to_string(), + strings_to_circuit_inputs(&signature), + ); + inputs.insert("modulus".to_string(), strings_to_circuit_inputs(&modulus)); + inputs.insert( + "base_message".to_string(), + strings_to_circuit_inputs(&base_message), + ); + + // Proof generation + let generate_proof_res = generate_proof2(inputs); + + // Check and print the error if there is one + if let Err(e) = &generate_proof_res { + println!("Error: {:?}", e); + } + + assert!(generate_proof_res.is_ok()); + + let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); + + // Proof verification + let verify_res = verify_proof2(serialized_proof, serialized_inputs); + assert!(verify_res.is_ok()); + + assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified + } +} diff --git a/app/ios/mopro/mopro-core/src/middleware/circom/serialization.rs b/app/ios/mopro/mopro-core/src/middleware/circom/serialization.rs new file mode 100644 index 000000000..47fa40088 --- /dev/null +++ b/app/ios/mopro/mopro-core/src/middleware/circom/serialization.rs @@ -0,0 +1,106 @@ +use ark_bn254::Bn254; +use ark_ec::pairing::Pairing; +use ark_groth16::{Proof, ProvingKey}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use color_eyre::Result; + +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] +pub struct SerializableProvingKey(pub ProvingKey); + +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] +pub struct SerializableProof(pub Proof); + +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq)] +pub struct SerializableInputs(pub Vec<::ScalarField>); + +pub fn serialize_proof(proof: &SerializableProof) -> Vec { + let mut serialized_data = Vec::new(); + proof + .serialize_uncompressed(&mut serialized_data) + .expect("Serialization failed"); + serialized_data +} + +pub fn deserialize_proof(data: Vec) -> SerializableProof { + SerializableProof::deserialize_uncompressed(&mut &data[..]).expect("Deserialization failed") +} + +pub fn serialize_proving_key(pk: &SerializableProvingKey) -> Vec { + let mut serialized_data = Vec::new(); + pk.serialize_uncompressed(&mut serialized_data) + .expect("Serialization failed"); + serialized_data +} + +pub fn deserialize_proving_key(data: Vec) -> SerializableProvingKey { + SerializableProvingKey::deserialize_uncompressed(&mut &data[..]) + .expect("Deserialization failed") +} + +pub fn serialize_inputs(inputs: &SerializableInputs) -> Vec { + let mut serialized_data = Vec::new(); + inputs + .serialize_uncompressed(&mut serialized_data) + .expect("Serialization failed"); + serialized_data +} + +pub fn deserialize_inputs(data: Vec) -> SerializableInputs { + SerializableInputs::deserialize_uncompressed(&mut &data[..]).expect("Deserialization failed") +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::middleware::circom::serialization::SerializableProvingKey; + use crate::middleware::circom::utils::assert_paths_exists; + use crate::MoproError; + use ark_bn254::Bn254; + use ark_circom::{CircomBuilder, CircomConfig}; + use ark_groth16::Groth16; + use ark_std::rand::thread_rng; + use color_eyre::Result; + + type GrothBn = Groth16; + + fn generate_serializable_proving_key( + wasm_path: &str, + r1cs_path: &str, + ) -> Result { + assert_paths_exists(wasm_path, r1cs_path)?; + + let cfg = CircomConfig::::new(wasm_path, r1cs_path) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + let builder = CircomBuilder::new(cfg); + let circom = builder.setup(); + + let mut rng = thread_rng(); + let raw_params = GrothBn::generate_random_parameters_with_reduction(circom, &mut rng) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + Ok(SerializableProvingKey(raw_params)) + } + + #[test] + fn test_serialization_deserialization() { + let wasm_path = "./examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"; + let r1cs_path = "./examples/circom/multiplier2/target/multiplier2.r1cs"; + + // Generate a serializable proving key for testing + let serializable_pk = generate_serializable_proving_key(wasm_path, r1cs_path) + .expect("Failed to generate serializable proving key"); + + // Serialize + let serialized_data = serialize_proving_key(&serializable_pk); + + // Deserialize + let deserialized_pk = deserialize_proving_key(serialized_data); + + // Assert that the original and deserialized ProvingKeys are the same + assert_eq!( + serializable_pk.0, deserialized_pk.0, + "Original and deserialized proving keys do not match" + ); + } +} diff --git a/app/ios/mopro/mopro-core/src/middleware/circom/utils.rs b/app/ios/mopro/mopro-core/src/middleware/circom/utils.rs new file mode 100644 index 000000000..31d6122c0 --- /dev/null +++ b/app/ios/mopro/mopro-core/src/middleware/circom/utils.rs @@ -0,0 +1,33 @@ +use crate::MoproError; + +use std::path::Path; + +pub fn assert_paths_exists(wasm_path: &str, r1cs_path: &str) -> Result<(), MoproError> { + // Check that the files exist - ark-circom should probably do this instead and not panic + if !Path::new(wasm_path).exists() { + return Err(MoproError::CircomError(format!( + "Path does not exist: {}", + wasm_path + ))); + } + + if !Path::new(r1cs_path).exists() { + return Err(MoproError::CircomError(format!( + "Path does not exist: {}", + r1cs_path + ))); + }; + + Ok(()) +} + +pub fn bytes_to_bits(bytes: &[u8]) -> Vec { + let mut bits = Vec::new(); + for &byte in bytes { + for j in 0..8 { + let bit = (byte >> j) & 1; + bits.push(bit == 1); + } + } + bits +} diff --git a/app/ios/mopro/mopro-core/src/middleware/mod.rs b/app/ios/mopro/mopro-core/src/middleware/mod.rs new file mode 100644 index 000000000..d18079a10 --- /dev/null +++ b/app/ios/mopro/mopro-core/src/middleware/mod.rs @@ -0,0 +1 @@ +pub mod circom; diff --git a/app/ios/mopro/mopro-ios/.gitignore b/app/ios/mopro/mopro-ios/.gitignore new file mode 100644 index 000000000..e5d2c0bce --- /dev/null +++ b/app/ios/mopro/mopro-ios/.gitignore @@ -0,0 +1,35 @@ +.DS_Store + +# Xcode +# +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate + +# CocoaPods +Podfile.lock +Pods +*.xcworkspace + +# Ignore static libs +*.a + diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/Info.plist b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/Info.plist new file mode 100644 index 000000000..180e5579f --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/Info.plist @@ -0,0 +1,43 @@ + + + + + AvailableLibraries + + + HeadersPath + Headers + LibraryIdentifier + ios-arm64 + LibraryPath + libmopro_ffi.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + HeadersPath + Headers + LibraryIdentifier + ios-arm64-simulator + LibraryPath + libmopro_ffi.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.h b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.h new file mode 100644 index 000000000..0d7647eb0 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.h @@ -0,0 +1,96 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +#pragma once + +#include +#include +#include + +// The following structs are used to implement the lowest level +// of the FFI, and thus useful to multiple uniffied crates. +// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. +#ifdef UNIFFI_SHARED_H + // We also try to prevent mixing versions of shared uniffi header structs. + // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 + #ifndef UNIFFI_SHARED_HEADER_V4 + #error Combining helper code from multiple versions of uniffi is not supported + #endif // ndef UNIFFI_SHARED_HEADER_V4 +#else +#define UNIFFI_SHARED_H +#define UNIFFI_SHARED_HEADER_V4 +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ + +typedef struct RustBuffer +{ + int32_t capacity; + int32_t len; + uint8_t *_Nullable data; +} RustBuffer; + +typedef int32_t (*ForeignCallback)(uint64_t, int32_t, const uint8_t *_Nonnull, int32_t, RustBuffer *_Nonnull); + +// Task defined in Rust that Swift executes +typedef void (*UniFfiRustTaskCallback)(const void * _Nullable); + +// Callback to execute Rust tasks using a Swift Task +// +// Args: +// executor: ForeignExecutor lowered into a size_t value +// delay: Delay in MS +// task: UniFfiRustTaskCallback to call +// task_data: data to pass the task callback +typedef void (*UniFfiForeignExecutorCallback)(size_t, uint32_t, UniFfiRustTaskCallback _Nullable, const void * _Nullable); + +typedef struct ForeignBytes +{ + int32_t len; + const uint8_t *_Nullable data; +} ForeignBytes; + +// Error definitions +typedef struct RustCallStatus { + int8_t code; + RustBuffer errorBuf; +} RustCallStatus; + +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ +#endif // def UNIFFI_SHARED_H + +// Callbacks for UniFFI Futures +typedef void (*UniFfiFutureCallbackUInt8)(const void * _Nonnull, uint8_t, RustCallStatus); +typedef void (*UniFfiFutureCallbackUInt32)(const void * _Nonnull, uint32_t, RustCallStatus); +typedef void (*UniFfiFutureCallbackRustBuffer)(const void * _Nonnull, RustBuffer, RustCallStatus); + +// Scaffolding functions +uint32_t uniffi_mopro_fn_func_add(uint32_t a, uint32_t b, RustCallStatus *_Nonnull out_status +); +RustBuffer uniffi_mopro_fn_func_hello(RustCallStatus *_Nonnull out_status + +); +void uniffi_mopro_fn_func_run(RustCallStatus *_Nonnull out_status + +); +RustBuffer ffi_mopro_rustbuffer_alloc(int32_t size, RustCallStatus *_Nonnull out_status +); +RustBuffer ffi_mopro_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status +); +RustBuffer ffi_mopro_rustbuffer_reserve(RustBuffer buf, int32_t additional, RustCallStatus *_Nonnull out_status +); +uint16_t uniffi_mopro_checksum_func_add(void + +); +uint16_t uniffi_mopro_checksum_func_hello(void + +); +uint16_t uniffi_mopro_checksum_func_run(void + +); +uint32_t ffi_mopro_uniffi_contract_version(void + +); + diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.modulemap b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.modulemap new file mode 100644 index 000000000..93b8adffb --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.modulemap @@ -0,0 +1,6 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +module moproFFI { + header "moproFFI.h" + export * +} \ No newline at end of file diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Sources/mopro.swift b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Sources/mopro.swift new file mode 100644 index 000000000..59edffd02 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Sources/mopro.swift @@ -0,0 +1,411 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +import Foundation + +// Depending on the consumer's build setup, the low-level FFI code +// might be in a separate module, or it might be compiled inline into +// this module. This is a bit of light hackery to work with both. +#if canImport(moproFFI) + import moproFFI +#endif + +private extension RustBuffer { + // Allocate a new buffer, copying the contents of a `UInt8` array. + init(bytes: [UInt8]) { + let rbuf = bytes.withUnsafeBufferPointer { ptr in + RustBuffer.from(ptr) + } + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) + } + + static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { + try! rustCall { ffi_mopro_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + } + + // Frees the buffer in place. + // The buffer must not be used after this is called. + func deallocate() { + try! rustCall { ffi_mopro_rustbuffer_free(self, $0) } + } +} + +private extension ForeignBytes { + init(bufferPointer: UnsafeBufferPointer) { + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) + } +} + +// For every type used in the interface, we provide helper methods for conveniently +// lifting and lowering that type from C-compatible data, and for reading and writing +// values of that type in a buffer. + +// Helper classes/extensions that don't change. +// Someday, this will be in a library of its own. + +private extension Data { + init(rustBuffer: RustBuffer) { + // TODO: This copies the buffer. Can we read directly from a + // Rust buffer? + self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) + } +} + +// Define reader functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. +// +// With external types, one swift source file needs to be able to call the read +// method on another source file's FfiConverter, but then what visibility +// should Reader have? +// - If Reader is fileprivate, then this means the read() must also +// be fileprivate, which doesn't work with external types. +// - If Reader is internal/public, we'll get compile errors since both source +// files will try define the same type. +// +// Instead, the read() method and these helper functions input a tuple of data + +private func createReader(data: Data) -> (data: Data, offset: Data.Index) { + (data: data, offset: 0) +} + +// Reads an integer at the current offset, in big-endian order, and advances +// the offset on success. Throws if reading the integer would move the +// offset past the end of the buffer. +private func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { + let range = reader.offset ..< reader.offset + MemoryLayout.size + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = reader.data[reader.offset] + reader.offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value) { reader.data.copyBytes(to: $0, from: range) } + reader.offset = range.upperBound + return value.bigEndian +} + +// Reads an arbitrary number of bytes, to be used to read +// raw bytes, this is useful when lifting strings +private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> [UInt8] { + let range = reader.offset ..< (reader.offset + count) + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer { buffer in + reader.data.copyBytes(to: buffer, from: range) + } + reader.offset = range.upperBound + return value +} + +// Reads a float at the current offset. +private func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { + return try Float(bitPattern: readInt(&reader)) +} + +// Reads a float at the current offset. +private func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { + return try Double(bitPattern: readInt(&reader)) +} + +// Indicates if the offset has reached the end of the buffer. +private func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { + return reader.offset < reader.data.count +} + +// Define writer functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. See the above discussion on Readers for details. + +private func createWriter() -> [UInt8] { + return [] +} + +private func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { + writer.append(contentsOf: byteArr) +} + +// Writes an integer in big-endian order. +// +// Warning: make sure what you are trying to write +// is in the correct type! +private func writeInt(_ writer: inout [UInt8], _ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } +} + +private func writeFloat(_ writer: inout [UInt8], _ value: Float) { + writeInt(&writer, value.bitPattern) +} + +private func writeDouble(_ writer: inout [UInt8], _ value: Double) { + writeInt(&writer, value.bitPattern) +} + +// Protocol for types that transfer other types across the FFI. This is +// analogous go the Rust trait of the same name. +private protocol FfiConverter { + associatedtype FfiType + associatedtype SwiftType + + static func lift(_ value: FfiType) throws -> SwiftType + static func lower(_ value: SwiftType) -> FfiType + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType + static func write(_ value: SwiftType, into buf: inout [UInt8]) +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +private protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType {} + +extension FfiConverterPrimitive { + public static func lift(_ value: FfiType) throws -> SwiftType { + return value + } + + public static func lower(_ value: SwiftType) -> FfiType { + return value + } +} + +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. +// Used for complex types where it's hard to write a custom lift/lower. +private protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} + +extension FfiConverterRustBuffer { + public static func lift(_ buf: RustBuffer) throws -> SwiftType { + var reader = createReader(data: Data(rustBuffer: buf)) + let value = try read(from: &reader) + if hasRemaining(reader) { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + + public static func lower(_ value: SwiftType) -> RustBuffer { + var writer = createWriter() + write(value, into: &writer) + return RustBuffer(bytes: writer) + } +} + +// An error type for FFI errors. These errors occur at the UniFFI level, not +// the library level. +private enum UniffiInternalError: LocalizedError { + case bufferOverflow + case incompleteData + case unexpectedOptionalTag + case unexpectedEnumCase + case unexpectedNullPointer + case unexpectedRustCallStatusCode + case unexpectedRustCallError + case unexpectedStaleHandle + case rustPanic(_ message: String) + + public var errorDescription: String? { + switch self { + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" + case .incompleteData: return "The buffer still has data after lifting its containing value" + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" + case .unexpectedNullPointer: return "Raw pointer value was null" + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" + case let .rustPanic(message): return message + } + } +} + +private let CALL_SUCCESS: Int8 = 0 +private let CALL_ERROR: Int8 = 1 +private let CALL_PANIC: Int8 = 2 + +private extension RustCallStatus { + init() { + self.init( + code: CALL_SUCCESS, + errorBuf: RustBuffer( + capacity: 0, + len: 0, + data: nil + ) + ) + } +} + +private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: nil) +} + +private func rustCallWithError( + _ errorHandler: @escaping (RustBuffer) throws -> Error, + _ callback: (UnsafeMutablePointer) -> T +) throws -> T { + try makeRustCall(callback, errorHandler: errorHandler) +} + +private func makeRustCall( + _ callback: (UnsafeMutablePointer) -> T, + errorHandler: ((RustBuffer) throws -> Error)? +) throws -> T { + uniffiEnsureInitialized() + var callStatus = RustCallStatus() + let returnedVal = callback(&callStatus) + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) + return returnedVal +} + +private func uniffiCheckCallStatus( + callStatus: RustCallStatus, + errorHandler: ((RustBuffer) throws -> Error)? +) throws { + switch callStatus.code { + case CALL_SUCCESS: + return + + case CALL_ERROR: + if let errorHandler = errorHandler { + throw try errorHandler(callStatus.errorBuf) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.unexpectedRustCallError + } + + case CALL_PANIC: + // When the rust code sees a panic, it tries to construct a RustBuffer + // with the message. But if that code panics, then it just sends back + // an empty buffer. + if callStatus.errorBuf.len > 0 { + throw try UniffiInternalError.rustPanic(FfiConverterString.lift(callStatus.errorBuf)) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.rustPanic("Rust panic") + } + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} + +// Public interface members begin here. + +private struct FfiConverterUInt32: FfiConverterPrimitive { + typealias FfiType = UInt32 + typealias SwiftType = UInt32 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +private struct FfiConverterString: FfiConverter { + typealias SwiftType = String + typealias FfiType = RustBuffer + + public static func lift(_ value: RustBuffer) throws -> String { + defer { + value.deallocate() + } + if value.data == nil { + return String() + } + let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len)) + return String(bytes: bytes, encoding: String.Encoding.utf8)! + } + + public static func lower(_ value: String) -> RustBuffer { + return value.utf8CString.withUnsafeBufferPointer { ptr in + // The swift string gives us int8_t, we want uint8_t. + ptr.withMemoryRebound(to: UInt8.self) { ptr in + // The swift string gives us a trailing null byte, we don't want it. + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) + return RustBuffer.from(buf) + } + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { + let len: Int32 = try readInt(&buf) + return try String(bytes: readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! + } + + public static func write(_ value: String, into buf: inout [UInt8]) { + let len = Int32(value.utf8.count) + writeInt(&buf, len) + writeBytes(&buf, value.utf8) + } +} + +public func add(a: UInt32, b: UInt32) -> UInt32 { + return try! FfiConverterUInt32.lift( + try! rustCall { + uniffi_mopro_fn_func_add( + FfiConverterUInt32.lower(a), + FfiConverterUInt32.lower(b), $0 + ) + } + ) +} + +public func hello() -> String { + return try! FfiConverterString.lift( + try! rustCall { + uniffi_mopro_fn_func_hello($0) + } + ) +} + +public func run() { + try! rustCall { + uniffi_mopro_fn_func_run($0) + } +} + +private enum InitializationResult { + case ok + case contractVersionMismatch + case apiChecksumMismatch +} + +// Use a global variables to perform the versioning checks. Swift ensures that +// the code inside is only computed once. +private var initializationResult: InitializationResult { + // Get the bindings contract version from our ComponentInterface + let bindings_contract_version = 22 + // Get the scaffolding contract version by calling the into the dylib + let scaffolding_contract_version = ffi_mopro_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version { + return InitializationResult.contractVersionMismatch + } + if uniffi_mopro_checksum_func_add() != 19178 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_mopro_checksum_func_hello() != 309 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_mopro_checksum_func_run() != 17009 { + return InitializationResult.apiChecksumMismatch + } + + return InitializationResult.ok +} + +private func uniffiEnsureInitialized() { + switch initializationResult { + case .ok: + break + case .contractVersionMismatch: + fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + case .apiChecksumMismatch: + fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.h b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.h new file mode 100644 index 000000000..0d7647eb0 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.h @@ -0,0 +1,96 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +#pragma once + +#include +#include +#include + +// The following structs are used to implement the lowest level +// of the FFI, and thus useful to multiple uniffied crates. +// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. +#ifdef UNIFFI_SHARED_H + // We also try to prevent mixing versions of shared uniffi header structs. + // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 + #ifndef UNIFFI_SHARED_HEADER_V4 + #error Combining helper code from multiple versions of uniffi is not supported + #endif // ndef UNIFFI_SHARED_HEADER_V4 +#else +#define UNIFFI_SHARED_H +#define UNIFFI_SHARED_HEADER_V4 +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ + +typedef struct RustBuffer +{ + int32_t capacity; + int32_t len; + uint8_t *_Nullable data; +} RustBuffer; + +typedef int32_t (*ForeignCallback)(uint64_t, int32_t, const uint8_t *_Nonnull, int32_t, RustBuffer *_Nonnull); + +// Task defined in Rust that Swift executes +typedef void (*UniFfiRustTaskCallback)(const void * _Nullable); + +// Callback to execute Rust tasks using a Swift Task +// +// Args: +// executor: ForeignExecutor lowered into a size_t value +// delay: Delay in MS +// task: UniFfiRustTaskCallback to call +// task_data: data to pass the task callback +typedef void (*UniFfiForeignExecutorCallback)(size_t, uint32_t, UniFfiRustTaskCallback _Nullable, const void * _Nullable); + +typedef struct ForeignBytes +{ + int32_t len; + const uint8_t *_Nullable data; +} ForeignBytes; + +// Error definitions +typedef struct RustCallStatus { + int8_t code; + RustBuffer errorBuf; +} RustCallStatus; + +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ +#endif // def UNIFFI_SHARED_H + +// Callbacks for UniFFI Futures +typedef void (*UniFfiFutureCallbackUInt8)(const void * _Nonnull, uint8_t, RustCallStatus); +typedef void (*UniFfiFutureCallbackUInt32)(const void * _Nonnull, uint32_t, RustCallStatus); +typedef void (*UniFfiFutureCallbackRustBuffer)(const void * _Nonnull, RustBuffer, RustCallStatus); + +// Scaffolding functions +uint32_t uniffi_mopro_fn_func_add(uint32_t a, uint32_t b, RustCallStatus *_Nonnull out_status +); +RustBuffer uniffi_mopro_fn_func_hello(RustCallStatus *_Nonnull out_status + +); +void uniffi_mopro_fn_func_run(RustCallStatus *_Nonnull out_status + +); +RustBuffer ffi_mopro_rustbuffer_alloc(int32_t size, RustCallStatus *_Nonnull out_status +); +RustBuffer ffi_mopro_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status +); +RustBuffer ffi_mopro_rustbuffer_reserve(RustBuffer buf, int32_t additional, RustCallStatus *_Nonnull out_status +); +uint16_t uniffi_mopro_checksum_func_add(void + +); +uint16_t uniffi_mopro_checksum_func_hello(void + +); +uint16_t uniffi_mopro_checksum_func_run(void + +); +uint32_t ffi_mopro_uniffi_contract_version(void + +); + diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.modulemap b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.modulemap new file mode 100644 index 000000000..93b8adffb --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.modulemap @@ -0,0 +1,6 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +module moproFFI { + header "moproFFI.h" + export * +} \ No newline at end of file diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Sources/mopro.swift b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Sources/mopro.swift new file mode 100644 index 000000000..59edffd02 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Sources/mopro.swift @@ -0,0 +1,411 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +import Foundation + +// Depending on the consumer's build setup, the low-level FFI code +// might be in a separate module, or it might be compiled inline into +// this module. This is a bit of light hackery to work with both. +#if canImport(moproFFI) + import moproFFI +#endif + +private extension RustBuffer { + // Allocate a new buffer, copying the contents of a `UInt8` array. + init(bytes: [UInt8]) { + let rbuf = bytes.withUnsafeBufferPointer { ptr in + RustBuffer.from(ptr) + } + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) + } + + static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { + try! rustCall { ffi_mopro_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + } + + // Frees the buffer in place. + // The buffer must not be used after this is called. + func deallocate() { + try! rustCall { ffi_mopro_rustbuffer_free(self, $0) } + } +} + +private extension ForeignBytes { + init(bufferPointer: UnsafeBufferPointer) { + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) + } +} + +// For every type used in the interface, we provide helper methods for conveniently +// lifting and lowering that type from C-compatible data, and for reading and writing +// values of that type in a buffer. + +// Helper classes/extensions that don't change. +// Someday, this will be in a library of its own. + +private extension Data { + init(rustBuffer: RustBuffer) { + // TODO: This copies the buffer. Can we read directly from a + // Rust buffer? + self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) + } +} + +// Define reader functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. +// +// With external types, one swift source file needs to be able to call the read +// method on another source file's FfiConverter, but then what visibility +// should Reader have? +// - If Reader is fileprivate, then this means the read() must also +// be fileprivate, which doesn't work with external types. +// - If Reader is internal/public, we'll get compile errors since both source +// files will try define the same type. +// +// Instead, the read() method and these helper functions input a tuple of data + +private func createReader(data: Data) -> (data: Data, offset: Data.Index) { + (data: data, offset: 0) +} + +// Reads an integer at the current offset, in big-endian order, and advances +// the offset on success. Throws if reading the integer would move the +// offset past the end of the buffer. +private func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { + let range = reader.offset ..< reader.offset + MemoryLayout.size + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = reader.data[reader.offset] + reader.offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value) { reader.data.copyBytes(to: $0, from: range) } + reader.offset = range.upperBound + return value.bigEndian +} + +// Reads an arbitrary number of bytes, to be used to read +// raw bytes, this is useful when lifting strings +private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> [UInt8] { + let range = reader.offset ..< (reader.offset + count) + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer { buffer in + reader.data.copyBytes(to: buffer, from: range) + } + reader.offset = range.upperBound + return value +} + +// Reads a float at the current offset. +private func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { + return try Float(bitPattern: readInt(&reader)) +} + +// Reads a float at the current offset. +private func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { + return try Double(bitPattern: readInt(&reader)) +} + +// Indicates if the offset has reached the end of the buffer. +private func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { + return reader.offset < reader.data.count +} + +// Define writer functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. See the above discussion on Readers for details. + +private func createWriter() -> [UInt8] { + return [] +} + +private func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { + writer.append(contentsOf: byteArr) +} + +// Writes an integer in big-endian order. +// +// Warning: make sure what you are trying to write +// is in the correct type! +private func writeInt(_ writer: inout [UInt8], _ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } +} + +private func writeFloat(_ writer: inout [UInt8], _ value: Float) { + writeInt(&writer, value.bitPattern) +} + +private func writeDouble(_ writer: inout [UInt8], _ value: Double) { + writeInt(&writer, value.bitPattern) +} + +// Protocol for types that transfer other types across the FFI. This is +// analogous go the Rust trait of the same name. +private protocol FfiConverter { + associatedtype FfiType + associatedtype SwiftType + + static func lift(_ value: FfiType) throws -> SwiftType + static func lower(_ value: SwiftType) -> FfiType + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType + static func write(_ value: SwiftType, into buf: inout [UInt8]) +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +private protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType {} + +extension FfiConverterPrimitive { + public static func lift(_ value: FfiType) throws -> SwiftType { + return value + } + + public static func lower(_ value: SwiftType) -> FfiType { + return value + } +} + +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. +// Used for complex types where it's hard to write a custom lift/lower. +private protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} + +extension FfiConverterRustBuffer { + public static func lift(_ buf: RustBuffer) throws -> SwiftType { + var reader = createReader(data: Data(rustBuffer: buf)) + let value = try read(from: &reader) + if hasRemaining(reader) { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + + public static func lower(_ value: SwiftType) -> RustBuffer { + var writer = createWriter() + write(value, into: &writer) + return RustBuffer(bytes: writer) + } +} + +// An error type for FFI errors. These errors occur at the UniFFI level, not +// the library level. +private enum UniffiInternalError: LocalizedError { + case bufferOverflow + case incompleteData + case unexpectedOptionalTag + case unexpectedEnumCase + case unexpectedNullPointer + case unexpectedRustCallStatusCode + case unexpectedRustCallError + case unexpectedStaleHandle + case rustPanic(_ message: String) + + public var errorDescription: String? { + switch self { + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" + case .incompleteData: return "The buffer still has data after lifting its containing value" + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" + case .unexpectedNullPointer: return "Raw pointer value was null" + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" + case let .rustPanic(message): return message + } + } +} + +private let CALL_SUCCESS: Int8 = 0 +private let CALL_ERROR: Int8 = 1 +private let CALL_PANIC: Int8 = 2 + +private extension RustCallStatus { + init() { + self.init( + code: CALL_SUCCESS, + errorBuf: RustBuffer( + capacity: 0, + len: 0, + data: nil + ) + ) + } +} + +private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: nil) +} + +private func rustCallWithError( + _ errorHandler: @escaping (RustBuffer) throws -> Error, + _ callback: (UnsafeMutablePointer) -> T +) throws -> T { + try makeRustCall(callback, errorHandler: errorHandler) +} + +private func makeRustCall( + _ callback: (UnsafeMutablePointer) -> T, + errorHandler: ((RustBuffer) throws -> Error)? +) throws -> T { + uniffiEnsureInitialized() + var callStatus = RustCallStatus() + let returnedVal = callback(&callStatus) + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) + return returnedVal +} + +private func uniffiCheckCallStatus( + callStatus: RustCallStatus, + errorHandler: ((RustBuffer) throws -> Error)? +) throws { + switch callStatus.code { + case CALL_SUCCESS: + return + + case CALL_ERROR: + if let errorHandler = errorHandler { + throw try errorHandler(callStatus.errorBuf) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.unexpectedRustCallError + } + + case CALL_PANIC: + // When the rust code sees a panic, it tries to construct a RustBuffer + // with the message. But if that code panics, then it just sends back + // an empty buffer. + if callStatus.errorBuf.len > 0 { + throw try UniffiInternalError.rustPanic(FfiConverterString.lift(callStatus.errorBuf)) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.rustPanic("Rust panic") + } + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} + +// Public interface members begin here. + +private struct FfiConverterUInt32: FfiConverterPrimitive { + typealias FfiType = UInt32 + typealias SwiftType = UInt32 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +private struct FfiConverterString: FfiConverter { + typealias SwiftType = String + typealias FfiType = RustBuffer + + public static func lift(_ value: RustBuffer) throws -> String { + defer { + value.deallocate() + } + if value.data == nil { + return String() + } + let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len)) + return String(bytes: bytes, encoding: String.Encoding.utf8)! + } + + public static func lower(_ value: String) -> RustBuffer { + return value.utf8CString.withUnsafeBufferPointer { ptr in + // The swift string gives us int8_t, we want uint8_t. + ptr.withMemoryRebound(to: UInt8.self) { ptr in + // The swift string gives us a trailing null byte, we don't want it. + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) + return RustBuffer.from(buf) + } + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { + let len: Int32 = try readInt(&buf) + return try String(bytes: readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! + } + + public static func write(_ value: String, into buf: inout [UInt8]) { + let len = Int32(value.utf8.count) + writeInt(&buf, len) + writeBytes(&buf, value.utf8) + } +} + +public func add(a: UInt32, b: UInt32) -> UInt32 { + return try! FfiConverterUInt32.lift( + try! rustCall { + uniffi_mopro_fn_func_add( + FfiConverterUInt32.lower(a), + FfiConverterUInt32.lower(b), $0 + ) + } + ) +} + +public func hello() -> String { + return try! FfiConverterString.lift( + try! rustCall { + uniffi_mopro_fn_func_hello($0) + } + ) +} + +public func run() { + try! rustCall { + uniffi_mopro_fn_func_run($0) + } +} + +private enum InitializationResult { + case ok + case contractVersionMismatch + case apiChecksumMismatch +} + +// Use a global variables to perform the versioning checks. Swift ensures that +// the code inside is only computed once. +private var initializationResult: InitializationResult { + // Get the bindings contract version from our ComponentInterface + let bindings_contract_version = 22 + // Get the scaffolding contract version by calling the into the dylib + let scaffolding_contract_version = ffi_mopro_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version { + return InitializationResult.contractVersionMismatch + } + if uniffi_mopro_checksum_func_add() != 19178 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_mopro_checksum_func_hello() != 309 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_mopro_checksum_func_run() != 17009 { + return InitializationResult.apiChecksumMismatch + } + + return InitializationResult.ok +} + +private func uniffiEnsureInitialized() { + switch initializationResult { + case .ok: + break + case .contractVersionMismatch: + fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + case .apiChecksumMismatch: + fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} diff --git a/app/ios/mopro/mopro-ios/MoproKit/.gitignore b/app/ios/mopro/mopro-ios/MoproKit/.gitignore new file mode 100644 index 000000000..805ffc7dd --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/.gitignore @@ -0,0 +1,36 @@ +# macOS +.DS_Store + +# Xcode +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa + +# Bundler +.bundle + +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build + +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control +# +# Note: if you ignore the Pods directory, make sure to uncomment +# `pod install` in .travis.yml +# +# Pods/ diff --git a/app/ios/mopro/mopro-ios/MoproKit/.travis.yml b/app/ios/mopro/mopro-ios/MoproKit/.travis.yml new file mode 100644 index 000000000..b2d81587a --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/.travis.yml @@ -0,0 +1,14 @@ +# references: +# * https://www.objc.io/issues/6-build-tools/travis-ci/ +# * https://github.com/supermarin/xcpretty#usage + +osx_image: xcode7.3 +language: objective-c +# cache: cocoapods +# podfile: Example/Podfile +# before_install: +# - gem install cocoapods # Since Travis is not always on latest version +# - pod install --project-directory=Example +script: +- set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/MoproKit.xcworkspace -scheme MoproKit-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty +- pod lib lint diff --git a/app/ios/mopro/mopro-ios/MoproKit/Bindings/mopro.swift b/app/ios/mopro/mopro-ios/MoproKit/Bindings/mopro.swift new file mode 100644 index 000000000..32127caf7 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Bindings/mopro.swift @@ -0,0 +1,805 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +import Foundation + +// Depending on the consumer's build setup, the low-level FFI code +// might be in a separate module, or it might be compiled inline into +// this module. This is a bit of light hackery to work with both. +#if canImport(moproFFI) +import moproFFI +#endif + +fileprivate extension RustBuffer { + // Allocate a new buffer, copying the contents of a `UInt8` array. + init(bytes: [UInt8]) { + let rbuf = bytes.withUnsafeBufferPointer { ptr in + RustBuffer.from(ptr) + } + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) + } + + static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { + try! rustCall { ffi_mopro_ffi_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + } + + // Frees the buffer in place. + // The buffer must not be used after this is called. + func deallocate() { + try! rustCall { ffi_mopro_ffi_rustbuffer_free(self, $0) } + } +} + +fileprivate extension ForeignBytes { + init(bufferPointer: UnsafeBufferPointer) { + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) + } +} + +// For every type used in the interface, we provide helper methods for conveniently +// lifting and lowering that type from C-compatible data, and for reading and writing +// values of that type in a buffer. + +// Helper classes/extensions that don't change. +// Someday, this will be in a library of its own. + +fileprivate extension Data { + init(rustBuffer: RustBuffer) { + // TODO: This copies the buffer. Can we read directly from a + // Rust buffer? + self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) + } +} + +// Define reader functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. +// +// With external types, one swift source file needs to be able to call the read +// method on another source file's FfiConverter, but then what visibility +// should Reader have? +// - If Reader is fileprivate, then this means the read() must also +// be fileprivate, which doesn't work with external types. +// - If Reader is internal/public, we'll get compile errors since both source +// files will try define the same type. +// +// Instead, the read() method and these helper functions input a tuple of data + +fileprivate func createReader(data: Data) -> (data: Data, offset: Data.Index) { + (data: data, offset: 0) +} + +// Reads an integer at the current offset, in big-endian order, and advances +// the offset on success. Throws if reading the integer would move the +// offset past the end of the buffer. +fileprivate func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { + let range = reader.offset...size + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = reader.data[reader.offset] + reader.offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value, { reader.data.copyBytes(to: $0, from: range)}) + reader.offset = range.upperBound + return value.bigEndian +} + +// Reads an arbitrary number of bytes, to be used to read +// raw bytes, this is useful when lifting strings +fileprivate func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> Array { + let range = reader.offset..<(reader.offset+count) + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer({ buffer in + reader.data.copyBytes(to: buffer, from: range) + }) + reader.offset = range.upperBound + return value +} + +// Reads a float at the current offset. +fileprivate func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { + return Float(bitPattern: try readInt(&reader)) +} + +// Reads a float at the current offset. +fileprivate func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { + return Double(bitPattern: try readInt(&reader)) +} + +// Indicates if the offset has reached the end of the buffer. +fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { + return reader.offset < reader.data.count +} + +// Define writer functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. See the above discussion on Readers for details. + +fileprivate func createWriter() -> [UInt8] { + return [] +} + +fileprivate func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { + writer.append(contentsOf: byteArr) +} + +// Writes an integer in big-endian order. +// +// Warning: make sure what you are trying to write +// is in the correct type! +fileprivate func writeInt(_ writer: inout [UInt8], _ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } +} + +fileprivate func writeFloat(_ writer: inout [UInt8], _ value: Float) { + writeInt(&writer, value.bitPattern) +} + +fileprivate func writeDouble(_ writer: inout [UInt8], _ value: Double) { + writeInt(&writer, value.bitPattern) +} + +// Protocol for types that transfer other types across the FFI. This is +// analogous go the Rust trait of the same name. +fileprivate protocol FfiConverter { + associatedtype FfiType + associatedtype SwiftType + + static func lift(_ value: FfiType) throws -> SwiftType + static func lower(_ value: SwiftType) -> FfiType + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType + static func write(_ value: SwiftType, into buf: inout [UInt8]) +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { } + +extension FfiConverterPrimitive { + public static func lift(_ value: FfiType) throws -> SwiftType { + return value + } + + public static func lower(_ value: SwiftType) -> FfiType { + return value + } +} + +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. +// Used for complex types where it's hard to write a custom lift/lower. +fileprivate protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} + +extension FfiConverterRustBuffer { + public static func lift(_ buf: RustBuffer) throws -> SwiftType { + var reader = createReader(data: Data(rustBuffer: buf)) + let value = try read(from: &reader) + if hasRemaining(reader) { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + + public static func lower(_ value: SwiftType) -> RustBuffer { + var writer = createWriter() + write(value, into: &writer) + return RustBuffer(bytes: writer) + } +} +// An error type for FFI errors. These errors occur at the UniFFI level, not +// the library level. +fileprivate enum UniffiInternalError: LocalizedError { + case bufferOverflow + case incompleteData + case unexpectedOptionalTag + case unexpectedEnumCase + case unexpectedNullPointer + case unexpectedRustCallStatusCode + case unexpectedRustCallError + case unexpectedStaleHandle + case rustPanic(_ message: String) + + public var errorDescription: String? { + switch self { + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" + case .incompleteData: return "The buffer still has data after lifting its containing value" + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" + case .unexpectedNullPointer: return "Raw pointer value was null" + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" + case let .rustPanic(message): return message + } + } +} + +fileprivate let CALL_SUCCESS: Int8 = 0 +fileprivate let CALL_ERROR: Int8 = 1 +fileprivate let CALL_PANIC: Int8 = 2 +fileprivate let CALL_CANCELLED: Int8 = 3 + +fileprivate extension RustCallStatus { + init() { + self.init( + code: CALL_SUCCESS, + errorBuf: RustBuffer.init( + capacity: 0, + len: 0, + data: nil + ) + ) + } +} + +private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: nil) +} + +private func rustCallWithError( + _ errorHandler: @escaping (RustBuffer) throws -> Error, + _ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: errorHandler) +} + +private func makeRustCall( + _ callback: (UnsafeMutablePointer) -> T, + errorHandler: ((RustBuffer) throws -> Error)? +) throws -> T { + uniffiEnsureInitialized() + var callStatus = RustCallStatus.init() + let returnedVal = callback(&callStatus) + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) + return returnedVal +} + +private func uniffiCheckCallStatus( + callStatus: RustCallStatus, + errorHandler: ((RustBuffer) throws -> Error)? +) throws { + switch callStatus.code { + case CALL_SUCCESS: + return + + case CALL_ERROR: + if let errorHandler = errorHandler { + throw try errorHandler(callStatus.errorBuf) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.unexpectedRustCallError + } + + case CALL_PANIC: + // When the rust code sees a panic, it tries to construct a RustBuffer + // with the message. But if that code panics, then it just sends back + // an empty buffer. + if callStatus.errorBuf.len > 0 { + throw UniffiInternalError.rustPanic(try FfiConverterString.lift(callStatus.errorBuf)) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.rustPanic("Rust panic") + } + + case CALL_CANCELLED: + throw CancellationError() + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} + +// Public interface members begin here. + + +fileprivate struct FfiConverterUInt32: FfiConverterPrimitive { + typealias FfiType = UInt32 + typealias SwiftType = UInt32 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +fileprivate struct FfiConverterBool : FfiConverter { + typealias FfiType = Int8 + typealias SwiftType = Bool + + public static func lift(_ value: Int8) throws -> Bool { + return value != 0 + } + + public static func lower(_ value: Bool) -> Int8 { + return value ? 1 : 0 + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bool { + return try lift(readInt(&buf)) + } + + public static func write(_ value: Bool, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +fileprivate struct FfiConverterString: FfiConverter { + typealias SwiftType = String + typealias FfiType = RustBuffer + + public static func lift(_ value: RustBuffer) throws -> String { + defer { + value.deallocate() + } + if value.data == nil { + return String() + } + let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len)) + return String(bytes: bytes, encoding: String.Encoding.utf8)! + } + + public static func lower(_ value: String) -> RustBuffer { + return value.utf8CString.withUnsafeBufferPointer { ptr in + // The swift string gives us int8_t, we want uint8_t. + ptr.withMemoryRebound(to: UInt8.self) { ptr in + // The swift string gives us a trailing null byte, we don't want it. + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) + return RustBuffer.from(buf) + } + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { + let len: Int32 = try readInt(&buf) + return String(bytes: try readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! + } + + public static func write(_ value: String, into buf: inout [UInt8]) { + let len = Int32(value.utf8.count) + writeInt(&buf, len) + writeBytes(&buf, value.utf8) + } +} + +fileprivate struct FfiConverterData: FfiConverterRustBuffer { + typealias SwiftType = Data + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Data { + let len: Int32 = try readInt(&buf) + return Data(try readBytes(&buf, count: Int(len))) + } + + public static func write(_ value: Data, into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + writeBytes(&buf, value) + } +} + + +public protocol MoproCircomProtocol { + func generateProof(circuitInputs: [String: [String]]) throws -> GenerateProofResult + func setup(wasmPath: String, r1csPath: String) throws -> SetupResult + func verifyProof(proof: Data, publicInput: Data) throws -> Bool + +} + +public class MoproCircom: MoproCircomProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + public convenience init() { + self.init(unsafeFromRawPointer: try! rustCall() { + uniffi_mopro_ffi_fn_constructor_moprocircom_new($0) +}) + } + + deinit { + try! rustCall { uniffi_mopro_ffi_fn_free_moprocircom(pointer, $0) } + } + + + + + + + public func generateProof(circuitInputs: [String: [String]]) throws -> GenerateProofResult { + return try FfiConverterTypeGenerateProofResult.lift( + try + rustCallWithError(FfiConverterTypeMoproError.lift) { + uniffi_mopro_ffi_fn_method_moprocircom_generate_proof(self.pointer, + FfiConverterDictionaryStringSequenceString.lower(circuitInputs),$0 + ) +} + ) + } + + public func setup(wasmPath: String, r1csPath: String) throws -> SetupResult { + return try FfiConverterTypeSetupResult.lift( + try + rustCallWithError(FfiConverterTypeMoproError.lift) { + uniffi_mopro_ffi_fn_method_moprocircom_setup(self.pointer, + FfiConverterString.lower(wasmPath), + FfiConverterString.lower(r1csPath),$0 + ) +} + ) + } + + public func verifyProof(proof: Data, publicInput: Data) throws -> Bool { + return try FfiConverterBool.lift( + try + rustCallWithError(FfiConverterTypeMoproError.lift) { + uniffi_mopro_ffi_fn_method_moprocircom_verify_proof(self.pointer, + FfiConverterData.lower(proof), + FfiConverterData.lower(publicInput),$0 + ) +} + ) + } +} + +public struct FfiConverterTypeMoproCircom: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = MoproCircom + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MoproCircom { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: MoproCircom, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> MoproCircom { + return MoproCircom(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: MoproCircom) -> UnsafeMutableRawPointer { + return value.pointer + } +} + + +public func FfiConverterTypeMoproCircom_lift(_ pointer: UnsafeMutableRawPointer) throws -> MoproCircom { + return try FfiConverterTypeMoproCircom.lift(pointer) +} + +public func FfiConverterTypeMoproCircom_lower(_ value: MoproCircom) -> UnsafeMutableRawPointer { + return FfiConverterTypeMoproCircom.lower(value) +} + + +public struct GenerateProofResult { + public var proof: Data + public var inputs: Data + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(proof: Data, inputs: Data) { + self.proof = proof + self.inputs = inputs + } +} + + +extension GenerateProofResult: Equatable, Hashable { + public static func ==(lhs: GenerateProofResult, rhs: GenerateProofResult) -> Bool { + if lhs.proof != rhs.proof { + return false + } + if lhs.inputs != rhs.inputs { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(proof) + hasher.combine(inputs) + } +} + + +public struct FfiConverterTypeGenerateProofResult: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> GenerateProofResult { + return try GenerateProofResult( + proof: FfiConverterData.read(from: &buf), + inputs: FfiConverterData.read(from: &buf) + ) + } + + public static func write(_ value: GenerateProofResult, into buf: inout [UInt8]) { + FfiConverterData.write(value.proof, into: &buf) + FfiConverterData.write(value.inputs, into: &buf) + } +} + + +public func FfiConverterTypeGenerateProofResult_lift(_ buf: RustBuffer) throws -> GenerateProofResult { + return try FfiConverterTypeGenerateProofResult.lift(buf) +} + +public func FfiConverterTypeGenerateProofResult_lower(_ value: GenerateProofResult) -> RustBuffer { + return FfiConverterTypeGenerateProofResult.lower(value) +} + + +public struct SetupResult { + public var provingKey: Data + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(provingKey: Data) { + self.provingKey = provingKey + } +} + + +extension SetupResult: Equatable, Hashable { + public static func ==(lhs: SetupResult, rhs: SetupResult) -> Bool { + if lhs.provingKey != rhs.provingKey { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(provingKey) + } +} + + +public struct FfiConverterTypeSetupResult: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SetupResult { + return try SetupResult( + provingKey: FfiConverterData.read(from: &buf) + ) + } + + public static func write(_ value: SetupResult, into buf: inout [UInt8]) { + FfiConverterData.write(value.provingKey, into: &buf) + } +} + + +public func FfiConverterTypeSetupResult_lift(_ buf: RustBuffer) throws -> SetupResult { + return try FfiConverterTypeSetupResult.lift(buf) +} + +public func FfiConverterTypeSetupResult_lower(_ value: SetupResult) -> RustBuffer { + return FfiConverterTypeSetupResult.lower(value) +} + +public enum MoproError { + + + + // Simple error enums only carry a message + case CircomError(message: String) + + + fileprivate static func uniffiErrorHandler(_ error: RustBuffer) throws -> Error { + return try FfiConverterTypeMoproError.lift(error) + } +} + + +public struct FfiConverterTypeMoproError: FfiConverterRustBuffer { + typealias SwiftType = MoproError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MoproError { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .CircomError( + message: try FfiConverterString.read(from: &buf) + ) + + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: MoproError, into buf: inout [UInt8]) { + switch value { + + + + + case .CircomError(_ /* message is ignored*/): + writeInt(&buf, Int32(1)) + + + } + } +} + + +extension MoproError: Equatable, Hashable {} + +extension MoproError: Error { } + +fileprivate struct FfiConverterSequenceString: FfiConverterRustBuffer { + typealias SwiftType = [String] + + public static func write(_ value: [String], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterString.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String] { + let len: Int32 = try readInt(&buf) + var seq = [String]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterString.read(from: &buf)) + } + return seq + } +} + +fileprivate struct FfiConverterDictionaryStringSequenceString: FfiConverterRustBuffer { + public static func write(_ value: [String: [String]], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for (key, value) in value { + FfiConverterString.write(key, into: &buf) + FfiConverterSequenceString.write(value, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String: [String]] { + let len: Int32 = try readInt(&buf) + var dict = [String: [String]]() + dict.reserveCapacity(Int(len)) + for _ in 0.. UInt32 { + return try! FfiConverterUInt32.lift( + try! rustCall() { + uniffi_mopro_ffi_fn_func_add( + FfiConverterUInt32.lower(a), + FfiConverterUInt32.lower(b),$0) +} + ) +} + +public func generateProof2(circuitInputs: [String: [String]]) throws -> GenerateProofResult { + return try FfiConverterTypeGenerateProofResult.lift( + try rustCallWithError(FfiConverterTypeMoproError.lift) { + uniffi_mopro_ffi_fn_func_generate_proof2( + FfiConverterDictionaryStringSequenceString.lower(circuitInputs),$0) +} + ) +} + +public func hello() -> String { + return try! FfiConverterString.lift( + try! rustCall() { + uniffi_mopro_ffi_fn_func_hello($0) +} + ) +} + +public func initializeMopro() throws { + try rustCallWithError(FfiConverterTypeMoproError.lift) { + uniffi_mopro_ffi_fn_func_initialize_mopro($0) +} +} + + + +public func initializeMoproDylib(dylibPath: String) throws { + try rustCallWithError(FfiConverterTypeMoproError.lift) { + uniffi_mopro_ffi_fn_func_initialize_mopro_dylib( + FfiConverterString.lower(dylibPath),$0) +} +} + + + +public func verifyProof2(proof: Data, publicInput: Data) throws -> Bool { + return try FfiConverterBool.lift( + try rustCallWithError(FfiConverterTypeMoproError.lift) { + uniffi_mopro_ffi_fn_func_verify_proof2( + FfiConverterData.lower(proof), + FfiConverterData.lower(publicInput),$0) +} + ) +} + +private enum InitializationResult { + case ok + case contractVersionMismatch + case apiChecksumMismatch +} +// Use a global variables to perform the versioning checks. Swift ensures that +// the code inside is only computed once. +private var initializationResult: InitializationResult { + // Get the bindings contract version from our ComponentInterface + let bindings_contract_version = 24 + // Get the scaffolding contract version by calling the into the dylib + let scaffolding_contract_version = ffi_mopro_ffi_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version { + return InitializationResult.contractVersionMismatch + } + if (uniffi_mopro_ffi_checksum_func_add() != 8411) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_mopro_ffi_checksum_func_generate_proof2() != 40187) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_mopro_ffi_checksum_func_hello() != 46136) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_mopro_ffi_checksum_func_initialize_mopro() != 17540) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_mopro_ffi_checksum_func_initialize_mopro_dylib() != 64476) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_mopro_ffi_checksum_func_verify_proof2() != 37192) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_mopro_ffi_checksum_method_moprocircom_generate_proof() != 64602) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_mopro_ffi_checksum_method_moprocircom_setup() != 57700) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_mopro_ffi_checksum_method_moprocircom_verify_proof() != 61522) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_mopro_ffi_checksum_constructor_moprocircom_new() != 42205) { + return InitializationResult.apiChecksumMismatch + } + + return InitializationResult.ok +} + +private func uniffiEnsureInitialized() { + switch initializationResult { + case .ok: + break + case .contractVersionMismatch: + fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + case .apiChecksumMismatch: + fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} \ No newline at end of file diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj new file mode 100644 index 000000000..5c436abc2 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj @@ -0,0 +1,670 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 2A418AB02AF4B1200004B747 /* CircomUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A418AAF2AF4B1200004B747 /* CircomUITests.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 */; }; + 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* ViewController.swift */; }; + 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; }; + 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; }; + 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; }; + 7A38AEC233A3880A843B0133 /* Pods_MoproKit_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BE5A40EAC7D019B9C7566CA /* Pods_MoproKit_Example.framework */; }; + CE2C1B8C2AFFCC5E002AF8BC /* main.wasm in Resources */ = {isa = PBXBuildFile; fileRef = CE2C1B8B2AFFCC5E002AF8BC /* main.wasm */; }; + CE2C1B8D2AFFCC5E002AF8BC /* main.wasm in Resources */ = {isa = PBXBuildFile; fileRef = CE2C1B8B2AFFCC5E002AF8BC /* main.wasm */; }; + CE5A5C062AD43A790074539D /* keccak256_256_test.wasm in Resources */ = {isa = PBXBuildFile; fileRef = CE5A5C052AD43A790074539D /* keccak256_256_test.wasm */; }; + CE5A5C072AD43A790074539D /* keccak256_256_test.wasm in Resources */ = {isa = PBXBuildFile; fileRef = CE5A5C052AD43A790074539D /* keccak256_256_test.wasm */; }; + CE5A5C092AD43A860074539D /* keccak256_256_test.r1cs in Resources */ = {isa = PBXBuildFile; fileRef = CE5A5C082AD43A860074539D /* keccak256_256_test.r1cs */; }; + CE5A5C0A2AD43A860074539D /* keccak256_256_test.r1cs in Resources */ = {isa = PBXBuildFile; fileRef = CE5A5C082AD43A860074539D /* keccak256_256_test.r1cs */; }; + CEA2D12F2AB96A7A00F292D2 /* multiplier2.wasm in Resources */ = {isa = PBXBuildFile; fileRef = CEA2D12E2AB96A7A00F292D2 /* multiplier2.wasm */; }; + CEA2D1302AB96A7A00F292D2 /* multiplier2.wasm in Resources */ = {isa = PBXBuildFile; fileRef = CEA2D12E2AB96A7A00F292D2 /* multiplier2.wasm */; }; + CEA2D1322AB96AB500F292D2 /* multiplier2.r1cs in Resources */ = {isa = PBXBuildFile; fileRef = CEA2D1312AB96AB500F292D2 /* multiplier2.r1cs */; }; + CEA2D1332AB96AB500F292D2 /* multiplier2.r1cs in Resources */ = {isa = PBXBuildFile; fileRef = CEA2D1312AB96AB500F292D2 /* multiplier2.r1cs */; }; + CEB804502AFF81960063F091 /* KeccakSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB8044F2AFF81960063F091 /* KeccakSetupViewController.swift */; }; + CEB804562AFF81AF0063F091 /* KeccakZkeyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB804552AFF81AF0063F091 /* KeccakZkeyViewController.swift */; }; + CEB804582AFF81BF0063F091 /* RSAViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB804572AFF81BF0063F091 /* RSAViewController.swift */; }; + E69338642AFFDB1A00B80312 /* AnonAadhaarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69338632AFFDB1A00B80312 /* AnonAadhaarViewController.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 607FACC81AFB9204008FA782 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 607FACCF1AFB9204008FA782; + remoteInfo = MoproKit; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 1E5E014D70B48C9A59F14658 /* Pods-MoproKit_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MoproKit_Example.release.xcconfig"; path = "Target Support Files/Pods-MoproKit_Example/Pods-MoproKit_Example.release.xcconfig"; sourceTree = ""; }; + 2A418AAF2AF4B1200004B747 /* CircomUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircomUITests.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 = ""; }; + 607FACD01AFB9204008FA782 /* MoproKit_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MoproKit_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 607FACD71AFB9204008FA782 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 607FACE51AFB9204008FA782 /* MoproKit_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MoproKit_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 78B0F9CBE5DD22576996A993 /* Pods_MoproKit_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MoproKit_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8BE5A40EAC7D019B9C7566CA /* Pods_MoproKit_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MoproKit_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 90EAF1BEF8AD3C193665DBED /* Pods-MoproKit_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MoproKit_Tests.release.xcconfig"; path = "Target Support Files/Pods-MoproKit_Tests/Pods-MoproKit_Tests.release.xcconfig"; sourceTree = ""; }; + 92580ABC3B6DBAD1A9544456 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; + B4016A34BBB20BC381CCFC2D /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; + C61628A63419B5C140B24AF7 /* Pods-MoproKit_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MoproKit_Example.debug.xcconfig"; path = "Target Support Files/Pods-MoproKit_Example/Pods-MoproKit_Example.debug.xcconfig"; sourceTree = ""; }; + CE2C1B8B2AFFCC5E002AF8BC /* main.wasm */ = {isa = PBXFileReference; lastKnownFileType = file; name = main.wasm; path = "../../../../../mopro-core/examples/circom/rsa/target/main_js/main.wasm"; sourceTree = ""; }; + CE5A5C052AD43A790074539D /* keccak256_256_test.wasm */ = {isa = PBXFileReference; lastKnownFileType = file; name = keccak256_256_test.wasm; path = "../../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm"; sourceTree = ""; }; + CE5A5C082AD43A860074539D /* keccak256_256_test.r1cs */ = {isa = PBXFileReference; lastKnownFileType = file; name = keccak256_256_test.r1cs; path = "../../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test.r1cs"; sourceTree = ""; }; + CEA2D12E2AB96A7A00F292D2 /* multiplier2.wasm */ = {isa = PBXFileReference; lastKnownFileType = file; name = multiplier2.wasm; path = "../../../../../mopro-core/examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"; sourceTree = ""; }; + CEA2D1312AB96AB500F292D2 /* multiplier2.r1cs */ = {isa = PBXFileReference; lastKnownFileType = file; name = multiplier2.r1cs; path = "../../../../../mopro-core/examples/circom/multiplier2/target/multiplier2.r1cs"; sourceTree = ""; }; + CEB8044F2AFF81960063F091 /* KeccakSetupViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeccakSetupViewController.swift; sourceTree = ""; }; + CEB804552AFF81AF0063F091 /* KeccakZkeyViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeccakZkeyViewController.swift; sourceTree = ""; }; + CEB804572AFF81BF0063F091 /* RSAViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RSAViewController.swift; sourceTree = ""; }; + E69338632AFFDB1A00B80312 /* AnonAadhaarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnonAadhaarViewController.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 607FACCD1AFB9204008FA782 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7A38AEC233A3880A843B0133 /* Pods_MoproKit_Example.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 607FACE21AFB9204008FA782 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4384FD09A96F702A375841EE /* Pods_MoproKit_Tests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 164B820D208F5EFE221D6A86 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 8BE5A40EAC7D019B9C7566CA /* Pods_MoproKit_Example.framework */, + 78B0F9CBE5DD22576996A993 /* Pods_MoproKit_Tests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 607FACC71AFB9204008FA782 = { + isa = PBXGroup; + children = ( + 607FACF51AFB993E008FA782 /* Podspec Metadata */, + 607FACD21AFB9204008FA782 /* Example for MoproKit */, + 607FACE81AFB9204008FA782 /* Tests */, + 607FACD11AFB9204008FA782 /* Products */, + EEB809FA0FFBEC7559BC7169 /* Pods */, + 164B820D208F5EFE221D6A86 /* Frameworks */, + ); + sourceTree = ""; + }; + 607FACD11AFB9204008FA782 /* Products */ = { + isa = PBXGroup; + children = ( + 607FACD01AFB9204008FA782 /* MoproKit_Example.app */, + 607FACE51AFB9204008FA782 /* MoproKit_Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 607FACD21AFB9204008FA782 /* Example for MoproKit */ = { + isa = PBXGroup; + children = ( + CEB804572AFF81BF0063F091 /* RSAViewController.swift */, + E69338632AFFDB1A00B80312 /* AnonAadhaarViewController.swift */, + CEB804552AFF81AF0063F091 /* KeccakZkeyViewController.swift */, + CEB8044F2AFF81960063F091 /* KeccakSetupViewController.swift */, + CEA2D1282AB9681E00F292D2 /* Resources */, + 607FACD51AFB9204008FA782 /* AppDelegate.swift */, + 607FACD71AFB9204008FA782 /* ViewController.swift */, + 607FACD91AFB9204008FA782 /* Main.storyboard */, + 607FACDC1AFB9204008FA782 /* Images.xcassets */, + 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */, + 607FACD31AFB9204008FA782 /* Supporting Files */, + ); + name = "Example for MoproKit"; + path = MoproKit; + sourceTree = ""; + }; + 607FACD31AFB9204008FA782 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 607FACD41AFB9204008FA782 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 607FACE81AFB9204008FA782 /* Tests */ = { + isa = PBXGroup; + children = ( + 2A418AAF2AF4B1200004B747 /* CircomUITests.swift */, + 607FACE91AFB9204008FA782 /* Supporting Files */, + 2A6E5BAE2AF499460052A601 /* CircomTests.swift */, + ); + path = Tests; + sourceTree = ""; + }; + 607FACE91AFB9204008FA782 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 607FACEA1AFB9204008FA782 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 607FACF51AFB993E008FA782 /* Podspec Metadata */ = { + isa = PBXGroup; + children = ( + 47F8ADB0AC4168C6E874818D /* MoproKit.podspec */, + B4016A34BBB20BC381CCFC2D /* README.md */, + 92580ABC3B6DBAD1A9544456 /* LICENSE */, + ); + name = "Podspec Metadata"; + sourceTree = ""; + }; + CEA2D1282AB9681E00F292D2 /* Resources */ = { + isa = PBXGroup; + children = ( + CE2C1B8B2AFFCC5E002AF8BC /* main.wasm */, + CE5A5C082AD43A860074539D /* keccak256_256_test.r1cs */, + CE5A5C052AD43A790074539D /* keccak256_256_test.wasm */, + CEA2D12E2AB96A7A00F292D2 /* multiplier2.wasm */, + CEA2D1312AB96AB500F292D2 /* multiplier2.r1cs */, + ); + path = Resources; + sourceTree = ""; + }; + EEB809FA0FFBEC7559BC7169 /* Pods */ = { + isa = PBXGroup; + children = ( + C61628A63419B5C140B24AF7 /* Pods-MoproKit_Example.debug.xcconfig */, + 1E5E014D70B48C9A59F14658 /* Pods-MoproKit_Example.release.xcconfig */, + 5DAF212A114DFA0C9F4282B2 /* Pods-MoproKit_Tests.debug.xcconfig */, + 90EAF1BEF8AD3C193665DBED /* Pods-MoproKit_Tests.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 607FACCF1AFB9204008FA782 /* MoproKit_Example */ = { + isa = PBXNativeTarget; + buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "MoproKit_Example" */; + buildPhases = ( + C880BC635097821F74482E9F /* [CP] Check Pods Manifest.lock */, + 607FACCC1AFB9204008FA782 /* Sources */, + 607FACCD1AFB9204008FA782 /* Frameworks */, + 607FACCE1AFB9204008FA782 /* Resources */, + AE90EE4FFCA95237FBC047A3 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MoproKit_Example; + productName = MoproKit; + productReference = 607FACD01AFB9204008FA782 /* MoproKit_Example.app */; + productType = "com.apple.product-type.application"; + }; + 607FACE41AFB9204008FA782 /* MoproKit_Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "MoproKit_Tests" */; + buildPhases = ( + 2A673A4155C4EBC1B609897B /* [CP] Check Pods Manifest.lock */, + 607FACE11AFB9204008FA782 /* Sources */, + 607FACE21AFB9204008FA782 /* Frameworks */, + 607FACE31AFB9204008FA782 /* Resources */, + 2B1BB55A83D0E5B7D03D5DA0 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 607FACE71AFB9204008FA782 /* PBXTargetDependency */, + ); + name = MoproKit_Tests; + productName = Tests; + productReference = 607FACE51AFB9204008FA782 /* MoproKit_Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 607FACC81AFB9204008FA782 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 0830; + ORGANIZATIONNAME = CocoaPods; + TargetAttributes = { + 607FACCF1AFB9204008FA782 = { + CreatedOnToolsVersion = 6.3.1; + DevelopmentTeam = 5B29R5LYHQ; + LastSwiftMigration = 0900; + }; + 607FACE41AFB9204008FA782 = { + CreatedOnToolsVersion = 6.3.1; + DevelopmentTeam = 5B29R5LYHQ; + LastSwiftMigration = 0900; + TestTargetID = 607FACCF1AFB9204008FA782; + }; + }; + }; + buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "MoproKit" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + en, + Base, + ); + mainGroup = 607FACC71AFB9204008FA782; + productRefGroup = 607FACD11AFB9204008FA782 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 607FACCF1AFB9204008FA782 /* MoproKit_Example */, + 607FACE41AFB9204008FA782 /* MoproKit_Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 607FACCE1AFB9204008FA782 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CEA2D1322AB96AB500F292D2 /* multiplier2.r1cs in Resources */, + 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */, + 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */, + CE5A5C062AD43A790074539D /* keccak256_256_test.wasm in Resources */, + CE2C1B8C2AFFCC5E002AF8BC /* main.wasm in Resources */, + 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */, + CEA2D12F2AB96A7A00F292D2 /* multiplier2.wasm in Resources */, + CE5A5C092AD43A860074539D /* keccak256_256_test.r1cs in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 607FACE31AFB9204008FA782 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CE5A5C0A2AD43A860074539D /* keccak256_256_test.r1cs in Resources */, + CE5A5C072AD43A790074539D /* keccak256_256_test.wasm in Resources */, + CE2C1B8D2AFFCC5E002AF8BC /* main.wasm in Resources */, + CEA2D1332AB96AB500F292D2 /* multiplier2.r1cs in Resources */, + CEA2D1302AB96A7A00F292D2 /* multiplier2.wasm in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2A673A4155C4EBC1B609897B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-MoproKit_Tests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 2B1BB55A83D0E5B7D03D5DA0 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-MoproKit_Tests/Pods-MoproKit_Tests-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Nimble/Nimble.framework", + "${BUILT_PRODUCTS_DIR}/Quick/Quick.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimble.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Quick.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MoproKit_Tests/Pods-MoproKit_Tests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + AE90EE4FFCA95237FBC047A3 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-MoproKit_Example/Pods-MoproKit_Example-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/MoproKit/MoproKit.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MoproKit.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MoproKit_Example/Pods-MoproKit_Example-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + C880BC635097821F74482E9F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-MoproKit_Example-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 607FACCC1AFB9204008FA782 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CEB804582AFF81BF0063F091 /* RSAViewController.swift in Sources */, + CEB804562AFF81AF0063F091 /* KeccakZkeyViewController.swift in Sources */, + 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */, + CEB804502AFF81960063F091 /* KeccakSetupViewController.swift in Sources */, + 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, + E69338642AFFDB1A00B80312 /* AnonAadhaarViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 607FACE11AFB9204008FA782 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2A6E5BAF2AF499460052A601 /* CircomTests.swift in Sources */, + 2A418AB02AF4B1200004B747 /* CircomUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 607FACE71AFB9204008FA782 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 607FACCF1AFB9204008FA782 /* MoproKit_Example */; + targetProxy = 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 607FACD91AFB9204008FA782 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 607FACDA1AFB9204008FA782 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 607FACDF1AFB9204008FA782 /* Base */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 607FACED1AFB9204008FA782 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 607FACEE1AFB9204008FA782 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 607FACF01AFB9204008FA782 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C61628A63419B5C140B24AF7 /* Pods-MoproKit_Example.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 5B29R5LYHQ; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + INFOPLIST_FILE = MoproKit/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MODULE_NAME = ExampleApp; + PRODUCT_BUNDLE_IDENTIFIER = org.mopro.examples; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 607FACF11AFB9204008FA782 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1E5E014D70B48C9A59F14658 /* Pods-MoproKit_Example.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 5B29R5LYHQ; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + INFOPLIST_FILE = MoproKit/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MODULE_NAME = ExampleApp; + PRODUCT_BUNDLE_IDENTIFIER = org.mopro.examples; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; + 607FACF31AFB9204008FA782 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5DAF212A114DFA0C9F4282B2 /* Pods-MoproKit_Tests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/MoproKit_Example.app/MoproKit_Example"; + DEVELOPMENT_TEAM = 5B29R5LYHQ; + FRAMEWORK_SEARCH_PATHS = ( + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.mopro.examples.test; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MoproKit_Example.app/MoproKit_Example"; + }; + name = Debug; + }; + 607FACF41AFB9204008FA782 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 90EAF1BEF8AD3C193665DBED /* Pods-MoproKit_Tests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/MoproKit_Example.app/MoproKit_Example"; + DEVELOPMENT_TEAM = 5B29R5LYHQ; + FRAMEWORK_SEARCH_PATHS = ( + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.mopro.examples.test; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MoproKit_Example.app/MoproKit_Example"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "MoproKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 607FACED1AFB9204008FA782 /* Debug */, + 607FACEE1AFB9204008FA782 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "MoproKit_Example" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 607FACF01AFB9204008FA782 /* Debug */, + 607FACF11AFB9204008FA782 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "MoproKit_Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 607FACF31AFB9204008FA782 /* Debug */, + 607FACF41AFB9204008FA782 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 607FACC81AFB9204008FA782 /* Project object */; +} diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/xcshareddata/xcschemes/MoproKit-Example.xcscheme b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/xcshareddata/xcschemes/MoproKit-Example.xcscheme new file mode 100644 index 000000000..6db6dc2f9 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/xcshareddata/xcschemes/MoproKit-Example.xcscheme @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AnonAadhaarViewController.swift b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AnonAadhaarViewController.swift new file mode 100644 index 000000000..636041410 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AnonAadhaarViewController.swift @@ -0,0 +1,192 @@ +// +// AnonAadhaarViewController.swift +// MoproKit_Example +// +// Created by Yanis Meziane on 11/11/2023. +// Copyright © 2023 CocoaPods. All rights reserved. +// + +import UIKit +import WebKit +import MoproKit + +class AnonAadhaarViewController: UIViewController, WKScriptMessageHandler, WKNavigationDelegate { + let webView = WKWebView() + let moproCircom = MoproKit.MoproCircom() + //var setupResult: SetupResult? + var generatedProof: Data? + var publicInputs: Data? + let containerView = UIView() + var textView = UITextView() + + override func viewDidLoad() { + super.viewDidLoad() + runInitAction() + setupUI() + + let contentController = WKUserContentController() + contentController.add(self, name: "startProvingHandler") + contentController.add(self, name: "messageHandler") + + let configuration = WKWebViewConfiguration() + configuration.userContentController = contentController + configuration.preferences.javaScriptEnabled = true + + // Assign the configuration to the WKWebView + let webView = WKWebView(frame: view.bounds, configuration: configuration) + webView.navigationDelegate = self + + view.addSubview(webView) + view.addSubview(textView) + + guard let url = URL(string: "https://webview-anon-adhaar.vercel.app/") else { return } + webView.load(URLRequest(url: url)) + } + + func setupUI() { + textView.isEditable = false + + textView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(textView) + + // Make text view visible + textView.heightAnchor.constraint(equalToConstant: 200).isActive = true + + NSLayoutConstraint.activate([ + textView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + textView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20) + ]) + } + + + + @objc func runInitAction() { + // Update the textView on the main thread + DispatchQueue.main.async { + self.textView.text += "Initializing library\n" + } + + // Execute long-running tasks in the background + DispatchQueue.global(qos: .userInitiated).async { + // Record start time + let start = CFAbsoluteTimeGetCurrent() + + do { + try initializeMopro() + + // Record end time and compute duration + let end = CFAbsoluteTimeGetCurrent() + let timeTaken = end - start + + // Again, update the UI on the main thread + DispatchQueue.main.async { + self.textView.text += "Initializing arkzkey took \(timeTaken) seconds.\n" + } + } catch { + // Handle errors - update UI on main thread + DispatchQueue.main.async { + self.textView.text += "An error occurred during initialization: \(error)\n" + } + } + } + } + + @objc func runProveAction(inputs: [String: [String]]) { + // Logic for prove (generate_proof2) + do { + textView.text += "Starts proving...\n" + // Record start time + let start = CFAbsoluteTimeGetCurrent() + + // Generate Proof + let generateProofResult = try generateProof2(circuitInputs: inputs) + assert(!generateProofResult.proof.isEmpty, "Proof should not be empty") + //assert(Data(expectedOutput) == generateProofResult.inputs, "Circuit outputs mismatch the expected outputs") + + // 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 + + print("Proof generation took \(timeTaken) seconds.\n") + + textView.text += "Proof generated!!! \n" + textView.text += "Proof generation took \(timeTaken) seconds.\n" + textView.text += "---\n" + runVerifyAction() + } catch let error as MoproError { + print("MoproError: \(error)") + } catch { + print("Unexpected error: \(error)") + } + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + webView.frame = view.bounds + } + + struct Witness { + let signature: [String] + let modulus: [String] + let base_message: [String] + } + + // Implement WKScriptMessageHandler method + func provingContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + if message.name == "messageHandler" { + // Handle messages for "messageHandler" + print("Received message from JavaScript:", message.body) + } + } + + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + if message.name == "startProvingHandler", let data = message.body as? [String: Any] { + // Check for the "witness" key in the received data + if let witnessData = data["witness"] as? [String: [String]] { + if let signature = witnessData["signature"], + let modulus = witnessData["modulus"], + let baseMessage = witnessData["base_message"] { + + let inputs: [String: [String]] = [ + "signature": signature, + "modulus": modulus, + "base_message": baseMessage + ] + + // Call your Swift function with the received witness data + runProveAction(inputs: inputs) + } + } else if let error = data["error"] as? String { + // Handle error data + print("Received error value from JavaScript:", error) + } else { + print("No valid data keys found in the message data.") + } + } + } + + @objc func runVerifyAction() { + // Logic for verify + guard let proof = generatedProof, + let publicInputs = publicInputs else { + print("Proof has not been generated yet.") + return + } + do { + // Verify Proof + let isValid = try verifyProof2(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)") + } + } +} diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AppDelegate.swift b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AppDelegate.swift new file mode 100644 index 000000000..bd6ad93e3 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AppDelegate.swift @@ -0,0 +1,52 @@ +// +// AppDelegate.swift +// MoproKit +// +// Created by 1552237 on 09/16/2023. +// Copyright (c) 2023 1552237. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + + window = UIWindow(frame: UIScreen.main.bounds) + let viewController = ViewController() + let navigationController = UINavigationController(rootViewController: viewController) + window?.rootViewController = navigationController + window?.makeKeyAndVisible() + + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/LaunchScreen.xib b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/LaunchScreen.xib new file mode 100644 index 000000000..32e97361f --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/LaunchScreen.xib @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/Main.storyboard b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/Main.storyboard new file mode 100644 index 000000000..2709ffc6e --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/Main.storyboard @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Images.xcassets/AppIcon.appiconset/Contents.json b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..7006c9eeb --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Info.plist b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Info.plist new file mode 100644 index 000000000..eb18faac5 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + + + diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift new file mode 100644 index 000000000..51936e437 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift @@ -0,0 +1,186 @@ +// +// ViewController.swift +// MoproKit +// +// Created by 1552237 on 09/16/2023. +// Copyright (c) 2023 1552237. All rights reserved. +// + +import UIKit +import MoproKit + +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 setupResult: SetupResult? + 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() { + 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) + ]) + } + + @objc func runSetupAction() { + // Logic for setup + if let wasmPath = Bundle.main.path(forResource: "keccak256_256_test", ofType: "wasm"), + let r1csPath = Bundle.main.path(forResource: "keccak256_256_test", ofType: "r1cs") { + + // Multiplier example + // if let wasmPath = Bundle.main.path(forResource: "multiplier2", ofType: "wasm"), + // let r1csPath = Bundle.main.path(forResource: "multiplier2", ofType: "r1cs") { + + do { + setupResult = try moproCircom.setup(wasmPath: wasmPath, r1csPath: r1csPath) + proveButton.isEnabled = true // Enable the Prove button upon successful setup + } 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 let setupResult = setupResult 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 runVerifyAction() { + // Logic for verify + guard let setupResult = setupResult, + 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)) + } + } + return bits +} diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakZkeyViewController.swift b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakZkeyViewController.swift new file mode 100644 index 000000000..ceca744d7 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakZkeyViewController.swift @@ -0,0 +1,147 @@ +// +// ViewController.swift +// MoproKit +// +// Created by 1552237 on 09/16/2023. +// Copyright (c) 2023 1552237. All rights reserved. +// + +import UIKit +import MoproKit + +class KeccakZkeyViewController: UIViewController { + + var initButton = UIButton(type: .system) + var proveButton = UIButton(type: .system) + var verifyButton = UIButton(type: .system) + var textView = UITextView() + + let moproCircom = MoproKit.MoproCircom() + //var setupResult: SetupResult? + var generatedProof: Data? + var publicInputs: Data? + + override func viewDidLoad() { + super.viewDidLoad() + + // Set title + let title = UILabel() + title.text = "Keccak256 (Zkey)" + title.textColor = .white + title.textAlignment = .center + navigationItem.titleView = title + navigationController?.navigationBar.isHidden = false + navigationController?.navigationBar.prefersLargeTitles = true + + setupUI() + } + + func setupUI() { + initButton.setTitle("Init", for: .normal) + proveButton.setTitle("Prove", for: .normal) + verifyButton.setTitle("Verify", for: .normal) + + // Uncomment once init separate + //proveButton.isEnabled = false + proveButton.isEnabled = true + verifyButton.isEnabled = false + textView.isEditable = false + + // Setup actions for buttons + initButton.addTarget(self, action: #selector(runInitAction), for: .touchUpInside) + proveButton.addTarget(self, action: #selector(runProveAction), for: .touchUpInside) + verifyButton.addTarget(self, action: #selector(runVerifyAction), for: .touchUpInside) + + initButton.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: [initButton, 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 runInitAction() { + // Logic for init + do { + textView.text += "Initializing library\n" + // Record start time + let start = CFAbsoluteTimeGetCurrent() + + try initializeMopro() + + // Record end time and compute duration + let end = CFAbsoluteTimeGetCurrent() + let timeTaken = end - start + + textView.text += "Initializing arkzkey took \(timeTaken) seconds.\n" + } catch let error as MoproError { + print("MoproError: \(error)") + } catch { + print("Unexpected error: \(error)") + } + } + + @objc func runProveAction() { + // Logic for prove (generate_proof2) + 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 + + // Expected outputs + let outputVec: [UInt8] = [ + 37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, + 212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, + ] + let outputBits: [String] = bytesToBits(bytes: outputVec) + // let expectedOutput: [UInt8] = serializeOutputs(outputBits) + + // Record start time + let start = CFAbsoluteTimeGetCurrent() + + // Generate Proof + let generateProofResult = try generateProof2(circuitInputs: inputs) + assert(!generateProofResult.proof.isEmpty, "Proof should not be empty") + //assert(Data(expectedOutput) == generateProofResult.inputs, "Circuit outputs mismatch the expected outputs") + + // 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" + // TODO: Enable verify + verifyButton.isEnabled = false + //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 runVerifyAction() { + // Logic for verify + } +} diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/RSAViewController.swift b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/RSAViewController.swift new file mode 100644 index 000000000..80ddadc93 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/RSAViewController.swift @@ -0,0 +1,235 @@ +// +// ViewController.swift +// MoproKit +// +// Created by 1552237 on 09/16/2023. +// Copyright (c) 2023 1552237. All rights reserved. +// + +import UIKit +import MoproKit + +class RSAViewController: UIViewController { + + var initButton = UIButton(type: .system) + var proveButton = UIButton(type: .system) + var verifyButton = UIButton(type: .system) + var textView = UITextView() + + let moproCircom = MoproKit.MoproCircom() + //var setupResult: SetupResult? + var generatedProof: Data? + var publicInputs: Data? + + override func viewDidLoad() { + super.viewDidLoad() + + // Set title + let title = UILabel() + title.text = "RSA (Zkey)" + title.textColor = .white + title.textAlignment = .center + navigationItem.titleView = title + navigationController?.navigationBar.isHidden = false + navigationController?.navigationBar.prefersLargeTitles = true + + setupUI() + } + + func setupUI() { + initButton.setTitle("Init", for: .normal) + proveButton.setTitle("Prove", for: .normal) + verifyButton.setTitle("Verify", for: .normal) + + // Uncomment once init separate + //proveButton.isEnabled = false + proveButton.isEnabled = true + verifyButton.isEnabled = false + textView.isEditable = false + + // Setup actions for buttons + initButton.addTarget(self, action: #selector(runInitAction), for: .touchUpInside) + proveButton.addTarget(self, action: #selector(runProveAction), for: .touchUpInside) + verifyButton.addTarget(self, action: #selector(runVerifyAction), for: .touchUpInside) + + initButton.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: [initButton, 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 runInitAction() { + // Update the textView on the main thread + DispatchQueue.main.async { + self.textView.text += "Initializing library\n" + } + + // Execute long-running tasks in the background + DispatchQueue.global(qos: .userInitiated).async { + // Record start time + let start = CFAbsoluteTimeGetCurrent() + + do { + try initializeMopro() + + // Record end time and compute duration + let end = CFAbsoluteTimeGetCurrent() + let timeTaken = end - start + + // Again, update the UI on the main thread + DispatchQueue.main.async { + self.textView.text += "Initializing arkzkey took \(timeTaken) seconds.\n" + } + } catch { + // Handle errors - update UI on main thread + DispatchQueue.main.async { + self.textView.text += "An error occurred during initialization: \(error)\n" + } + } + } + } + + @objc func runProveAction() { + // Logic for prove (generate_proof2) + do { + // Prepare inputs + let signature: [String] = [ + "3582320600048169363", + "7163546589759624213", + "18262551396327275695", + "4479772254206047016", + "1970274621151677644", + "6547632513799968987", + "921117808165172908", + "7155116889028933260", + "16769940396381196125", + "17141182191056257954", + "4376997046052607007", + "17471823348423771450", + "16282311012391954891", + "70286524413490741", + "1588836847166444745", + "15693430141227594668", + "13832254169115286697", + "15936550641925323613", + "323842208142565220", + "6558662646882345749", + "15268061661646212265", + "14962976685717212593", + "15773505053543368901", + "9586594741348111792", + "1455720481014374292", + "13945813312010515080", + "6352059456732816887", + "17556873002865047035", + "2412591065060484384", + "11512123092407778330", + "8499281165724578877", + "12768005853882726493", + ] + + let modulus: [String] = [ + "13792647154200341559", + "12773492180790982043", + "13046321649363433702", + "10174370803876824128", + "7282572246071034406", + "1524365412687682781", + "4900829043004737418", + "6195884386932410966", + "13554217876979843574", + "17902692039595931737", + "12433028734895890975", + "15971442058448435996", + "4591894758077129763", + "11258250015882429548", + "16399550288873254981", + "8246389845141771315", + "14040203746442788850", + "7283856864330834987", + "12297563098718697441", + "13560928146585163504", + "7380926829734048483", + "14591299561622291080", + "8439722381984777599", + "17375431987296514829", + "16727607878674407272", + "3233954801381564296", + "17255435698225160983", + "15093748890170255670", + "15810389980847260072", + "11120056430439037392", + "5866130971823719482", + "13327552690270163501", + ] + + let base_message: [String] = ["18114495772705111902", "2254271930739856077", + "2068851770", "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","0", + ] + + var inputs = [String: [String]]() + inputs["signature"] = signature; + inputs["modulus"] = modulus; + inputs["base_message"] = base_message; + + let start = CFAbsoluteTimeGetCurrent() + + // Generate Proof + let generateProofResult = try generateProof2(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 + } catch let error as MoproError { + print("MoproError: \(error)") + textView.text += "MoproError: \(error)\n" + } catch { + print("Unexpected error: \(error)") + textView.text += "Unexpected error: \(error)\n" + } + } + + @objc func runVerifyAction() { + // Logic for verify + guard let proof = generatedProof, + let publicInputs = publicInputs else { + print("Proof has not been generated yet.") + return + } + do { + // Verify Proof + let isValid = try verifyProof2(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)") + } + } +} diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/ViewController.swift b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/ViewController.swift new file mode 100644 index 000000000..934e2266a --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/ViewController.swift @@ -0,0 +1,100 @@ +// +// ViewController.swift +// MoproKit +// +// Created by 1552237 on 09/16/2023. +// Copyright (c) 2023 1552237. All rights reserved. +// + +import UIKit +import MoproKit + + +// Main ViewController +class ViewController: UIViewController { + + let keccakSetupButton = UIButton(type: .system) + let keccakZkeyButton = UIButton(type: .system) + let rsaButton = UIButton(type: .system) + let aadhaarButton = UIButton(type: .system) + + override func viewDidLoad() { + super.viewDidLoad() + // TODO: Improve style + + // Set title + let title = UILabel() + title.text = "Mopro Examples" + title.textColor = .white + title.textAlignment = .center + navigationItem.titleView = title + navigationController?.navigationBar.isHidden = false + navigationController?.navigationBar.prefersLargeTitles = true + + setupMainUI() + } + + func setupMainUI() { + keccakSetupButton.setTitle("Keccak (Setup)", for: .normal) + keccakSetupButton.addTarget(self, action: #selector(openKeccakSetup), for: .touchUpInside) + + keccakZkeyButton.setTitle("Keccak (Zkey)", for: .normal) + keccakZkeyButton.addTarget(self, action: #selector(openKeccakZkey), for: .touchUpInside) + + rsaButton.setTitle("RSA", for: .normal) + rsaButton.addTarget(self, action: #selector(openRSA), for: .touchUpInside) + + aadhaarButton.setTitle("Anon Aadhaar", for: .normal) + aadhaarButton.addTarget(self, action: #selector(openAnonAadhaar), for: .touchUpInside) + + + keccakSetupButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) + keccakZkeyButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) + rsaButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) + +// self.title = "Mopro Examples" +// navigationController?.navigationBar.prefersLargeTitles = true + + + let stackView = UIStackView(arrangedSubviews: [keccakSetupButton, keccakZkeyButton, rsaButton, aadhaarButton]) + stackView.axis = .vertical + stackView.spacing = 20 + stackView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(stackView) + + NSLayoutConstraint.activate([ + stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor) + ]) + } + + @objc func openKeccakSetup() { + let keccakSetupVC = KeccakSetupViewController() + navigationController?.pushViewController(keccakSetupVC, animated: true) + } + + @objc func openKeccakZkey() { + let keccakZkeyVC = KeccakZkeyViewController() + navigationController?.pushViewController(keccakZkeyVC, animated: true) + } + + @objc func openRSA() { + let rsaVC = RSAViewController() + navigationController?.pushViewController(rsaVC, animated: true) + } + + @objc func openAnonAadhaar() { + let anonAadhaarVC = AnonAadhaarViewController() + navigationController?.pushViewController(anonAadhaarVC, animated: true) + } +} + +// // Make buttons bigger +// proveButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) +// verifyButton.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) + +// NSLayoutConstraint.activate([ +// stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), +// stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), +// stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20) +// ]) diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/Podfile b/app/ios/mopro/mopro-ios/MoproKit/Example/Podfile new file mode 100644 index 000000000..e27037177 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/Podfile @@ -0,0 +1,24 @@ +use_frameworks! + +platform :ios, '13.0' + +target 'MoproKit_Example' do + pod 'MoproKit', :path => '../' + + target 'MoproKit_Tests' do + inherit! :search_paths + + pod 'Quick', '~> 2.2.0' + pod 'Nimble', '~> 10.0.0' + end +end + +post_install do |installer| + installer.generated_projects.each do |project| + project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' + end + end + end +end \ No newline at end of file diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomTests.swift b/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomTests.swift new file mode 100644 index 000000000..03e60a908 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomTests.swift @@ -0,0 +1,109 @@ +@testable import MoproKit +import XCTest + +final class CircomTests: XCTestCase { + + let moproCircom = MoproKit.MoproCircom() + + func testMultiplier() { + let wasmPath = Bundle.main.path(forResource: "multiplier2", ofType: "wasm")! + let r1csPath = Bundle.main.path(forResource: "multiplier2", ofType: "r1cs")! + XCTAssertNoThrow(try moproCircom.setup(wasmPath: wasmPath, r1csPath: r1csPath), "Mopro circom setup failed") + + do { + var inputs = [String: [String]]() + let a = 3 + let b = 5 + let c = a*b + inputs["a"] = [String(a)] + inputs["b"] = [String(b)] + let outputs: [String] = [String(c), String(a)] + let expectedOutput: [UInt8] = serializeOutputs(outputs) + + // Generate Proof + let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs) + XCTAssertFalse(generateProofResult.proof.isEmpty, "Proof should not be empty") + XCTAssertEqual(Data(expectedOutput), generateProofResult.inputs, "Circuit outputs mismatch the expected outputs") + + let isValid = try moproCircom.verifyProof(proof: generateProofResult.proof, publicInput: generateProofResult.inputs) + XCTAssertTrue(isValid, "Proof verification should succeed") + } catch let error as MoproError { + print("MoproError: \(error)") + } catch { + print("Unexpected error: \(error)") + } + } + + func testKeccak256() { + let wasmPath = Bundle.main.path(forResource: "keccak256_256_test", ofType: "wasm")! + let r1csPath = Bundle.main.path(forResource: "keccak256_256_test", ofType: "r1cs")! + XCTAssertNoThrow(try moproCircom.setup(wasmPath: wasmPath, r1csPath: r1csPath), "Mopro circom setup failed") + + 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 + + // Expected outputs + let outputVec: [UInt8] = [ + 37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, + 212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, + ] + let outputBits: [String] = bytesToBits(bytes: outputVec) + let expectedOutput: [UInt8] = serializeOutputs(outputBits) + + // Generate Proof + let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs) + XCTAssertFalse(generateProofResult.proof.isEmpty, "Proof should not be empty") + XCTAssertEqual(Data(expectedOutput), generateProofResult.inputs, "Circuit outputs mismatch the expected outputs") + + let isValid = try moproCircom.verifyProof(proof: generateProofResult.proof, publicInput: generateProofResult.inputs) + XCTAssertTrue(isValid, "Proof verification should succeed") + } catch let error as MoproError { + print("MoproError: \(error)") + } catch { + print("Unexpected error: \(error)") + } + } +} + +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)) + } + } + return bits +} + +func serializeOutputs(_ stringArray: [String]) -> [UInt8] { + var bytesArray: [UInt8] = [] + let length = stringArray.count + var littleEndianLength = length.littleEndian + let targetLength = 32 + withUnsafeBytes(of: &littleEndianLength) { + bytesArray.append(contentsOf: $0) + } + for value in stringArray { + // TODO: should handle 254-bit input + var littleEndian = Int32(value)!.littleEndian + var byteLength = 0 + withUnsafeBytes(of: &littleEndian) { + bytesArray.append(contentsOf: $0) + byteLength = byteLength + $0.count + } + if byteLength < targetLength { + let paddingCount = targetLength - byteLength + let paddingArray = [UInt8](repeating: 0, count: paddingCount) + bytesArray.append(contentsOf: paddingArray) + } + } + return bytesArray +} diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomUITests.swift b/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomUITests.swift new file mode 100644 index 000000000..e5e5d1e32 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomUITests.swift @@ -0,0 +1,13 @@ +import XCTest +@testable import MoproKit_Example + +final class CircomUITests: XCTestCase { + + let ui = KeccakSetupViewController() + + func testSuccessUI() { + XCTAssertNoThrow(ui.setupUI(), "Setup UI failed") + XCTAssertNoThrow(ui.runProveAction(), "Prove action failed") + XCTAssertNoThrow(ui.runVerifyAction(), "Verify action failed") + } +} diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/Info.plist b/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/app/ios/mopro/mopro-ios/MoproKit/Include/moproFFI.h b/app/ios/mopro/mopro-ios/MoproKit/Include/moproFFI.h new file mode 100644 index 000000000..745221d87 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Include/moproFFI.h @@ -0,0 +1,238 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +#pragma once + +#include +#include +#include + +// The following structs are used to implement the lowest level +// of the FFI, and thus useful to multiple uniffied crates. +// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. +#ifdef UNIFFI_SHARED_H + // We also try to prevent mixing versions of shared uniffi header structs. + // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 + #ifndef UNIFFI_SHARED_HEADER_V4 + #error Combining helper code from multiple versions of uniffi is not supported + #endif // ndef UNIFFI_SHARED_HEADER_V4 +#else +#define UNIFFI_SHARED_H +#define UNIFFI_SHARED_HEADER_V4 +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ + +typedef struct RustBuffer +{ + int32_t capacity; + int32_t len; + uint8_t *_Nullable data; +} RustBuffer; + +typedef int32_t (*ForeignCallback)(uint64_t, int32_t, const uint8_t *_Nonnull, int32_t, RustBuffer *_Nonnull); + +// Task defined in Rust that Swift executes +typedef void (*UniFfiRustTaskCallback)(const void * _Nullable, int8_t); + +// Callback to execute Rust tasks using a Swift Task +// +// Args: +// executor: ForeignExecutor lowered into a size_t value +// delay: Delay in MS +// task: UniFfiRustTaskCallback to call +// task_data: data to pass the task callback +typedef int8_t (*UniFfiForeignExecutorCallback)(size_t, uint32_t, UniFfiRustTaskCallback _Nullable, const void * _Nullable); + +typedef struct ForeignBytes +{ + int32_t len; + const uint8_t *_Nullable data; +} ForeignBytes; + +// Error definitions +typedef struct RustCallStatus { + int8_t code; + RustBuffer errorBuf; +} RustCallStatus; + +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ +#endif // def UNIFFI_SHARED_H + +// Continuation callback for UniFFI Futures +typedef void (*UniFfiRustFutureContinuation)(void * _Nonnull, int8_t); + +// Scaffolding functions +void uniffi_mopro_ffi_fn_free_moprocircom(void*_Nonnull ptr, RustCallStatus *_Nonnull out_status +); +void*_Nonnull uniffi_mopro_ffi_fn_constructor_moprocircom_new(RustCallStatus *_Nonnull out_status + +); +RustBuffer uniffi_mopro_ffi_fn_method_moprocircom_generate_proof(void*_Nonnull ptr, RustBuffer circuit_inputs, RustCallStatus *_Nonnull out_status +); +RustBuffer uniffi_mopro_ffi_fn_method_moprocircom_setup(void*_Nonnull ptr, RustBuffer wasm_path, RustBuffer r1cs_path, RustCallStatus *_Nonnull out_status +); +int8_t uniffi_mopro_ffi_fn_method_moprocircom_verify_proof(void*_Nonnull ptr, RustBuffer proof, RustBuffer public_input, RustCallStatus *_Nonnull out_status +); +uint32_t uniffi_mopro_ffi_fn_func_add(uint32_t a, uint32_t b, RustCallStatus *_Nonnull out_status +); +RustBuffer uniffi_mopro_ffi_fn_func_generate_proof2(RustBuffer circuit_inputs, RustCallStatus *_Nonnull out_status +); +RustBuffer uniffi_mopro_ffi_fn_func_hello(RustCallStatus *_Nonnull out_status + +); +void uniffi_mopro_ffi_fn_func_initialize_mopro(RustCallStatus *_Nonnull out_status + +); +void uniffi_mopro_ffi_fn_func_initialize_mopro_dylib(RustBuffer dylib_path, RustCallStatus *_Nonnull out_status +); +int8_t uniffi_mopro_ffi_fn_func_verify_proof2(RustBuffer proof, RustBuffer public_input, RustCallStatus *_Nonnull out_status +); +RustBuffer ffi_mopro_ffi_rustbuffer_alloc(int32_t size, RustCallStatus *_Nonnull out_status +); +RustBuffer ffi_mopro_ffi_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status +); +RustBuffer ffi_mopro_ffi_rustbuffer_reserve(RustBuffer buf, int32_t additional, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_continuation_callback_set(UniFfiRustFutureContinuation _Nonnull callback +); +void ffi_mopro_ffi_rust_future_poll_u8(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_u8(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_u8(void* _Nonnull handle +); +uint8_t ffi_mopro_ffi_rust_future_complete_u8(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_i8(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_i8(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_i8(void* _Nonnull handle +); +int8_t ffi_mopro_ffi_rust_future_complete_i8(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_u16(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_u16(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_u16(void* _Nonnull handle +); +uint16_t ffi_mopro_ffi_rust_future_complete_u16(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_i16(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_i16(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_i16(void* _Nonnull handle +); +int16_t ffi_mopro_ffi_rust_future_complete_i16(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_u32(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_u32(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_u32(void* _Nonnull handle +); +uint32_t ffi_mopro_ffi_rust_future_complete_u32(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_i32(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_i32(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_i32(void* _Nonnull handle +); +int32_t ffi_mopro_ffi_rust_future_complete_i32(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_u64(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_u64(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_u64(void* _Nonnull handle +); +uint64_t ffi_mopro_ffi_rust_future_complete_u64(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_i64(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_i64(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_i64(void* _Nonnull handle +); +int64_t ffi_mopro_ffi_rust_future_complete_i64(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_f32(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_f32(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_f32(void* _Nonnull handle +); +float ffi_mopro_ffi_rust_future_complete_f32(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_f64(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_f64(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_f64(void* _Nonnull handle +); +double ffi_mopro_ffi_rust_future_complete_f64(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_pointer(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_pointer(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_pointer(void* _Nonnull handle +); +void*_Nonnull ffi_mopro_ffi_rust_future_complete_pointer(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_rust_buffer(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_rust_buffer(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_rust_buffer(void* _Nonnull handle +); +RustBuffer ffi_mopro_ffi_rust_future_complete_rust_buffer(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_ffi_rust_future_poll_void(void* _Nonnull handle, void* _Nonnull uniffi_callback +); +void ffi_mopro_ffi_rust_future_cancel_void(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_free_void(void* _Nonnull handle +); +void ffi_mopro_ffi_rust_future_complete_void(void* _Nonnull handle, RustCallStatus *_Nonnull out_status +); +uint16_t uniffi_mopro_ffi_checksum_func_add(void + +); +uint16_t uniffi_mopro_ffi_checksum_func_generate_proof2(void + +); +uint16_t uniffi_mopro_ffi_checksum_func_hello(void + +); +uint16_t uniffi_mopro_ffi_checksum_func_initialize_mopro(void + +); +uint16_t uniffi_mopro_ffi_checksum_func_initialize_mopro_dylib(void + +); +uint16_t uniffi_mopro_ffi_checksum_func_verify_proof2(void + +); +uint16_t uniffi_mopro_ffi_checksum_method_moprocircom_generate_proof(void + +); +uint16_t uniffi_mopro_ffi_checksum_method_moprocircom_setup(void + +); +uint16_t uniffi_mopro_ffi_checksum_method_moprocircom_verify_proof(void + +); +uint16_t uniffi_mopro_ffi_checksum_constructor_moprocircom_new(void + +); +uint32_t ffi_mopro_ffi_uniffi_contract_version(void + +); + diff --git a/app/ios/mopro/mopro-ios/MoproKit/LICENSE b/app/ios/mopro/mopro-ios/MoproKit/LICENSE new file mode 100644 index 000000000..46df76b78 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2023 1552237 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/app/ios/mopro/mopro-ios/MoproKit/Libs/.gitkeep b/app/ios/mopro/mopro-ios/MoproKit/Libs/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/app/ios/mopro/mopro-ios/MoproKit/MoproKit.podspec b/app/ios/mopro/mopro-ios/MoproKit/MoproKit.podspec new file mode 100644 index 000000000..a7be6ace4 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/MoproKit.podspec @@ -0,0 +1,50 @@ +# +# Be sure to run `pod lib lint MoproKit.podspec' to ensure this is a +# valid spec before submitting. +# +# Any lines starting with a # are optional, but their use is encouraged +# To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html +# + +Pod::Spec.new do |s| + s.name = 'MoproKit' + s.version = '0.1.0' + s.summary = 'A short description of MoproKit.' + +# This description is used to generate tags and improve search results. +# * Think: What does it do? Why did you write it? What is the focus? +# * Try to keep it short, snappy and to the point. +# * Write the description between the DESC delimiters below. +# * Finally, don't worry about the indent, CocoaPods strips it! + + s.description = <<-DESC +TODO: Add long description of the pod here. + DESC + + s.homepage = 'https://github.com/1552237/MoproKit' + # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' + s.license = { :type => 'MIT', :file => 'LICENSE' } + s.author = { '1552237' => 'oskarth@titanproxy.com' } + s.source = { :git => 'https://github.com/1552237/MoproKit.git', :tag => s.version.to_s } + # s.social_media_url = 'https://twitter.com/' + + s.ios.deployment_target = '13.0' + + s.source_files = 'MoproKit/Classes/**/*' + + # libmopro library, headers and modulemap + # XXX: static library is not in source control, and needs to be inlcuded manually + # Have to be mindful of architecture and simulator or not here, should be improved + s.preserve_paths = 'Libs/libmopro_uniffi.a' + s.vendored_libraries = 'Libs/libmopro_uniffi.a' + s.source_files = 'Include/*.h', 'Bindings/*.swift' + s.resource = 'Resources/moproFFI.modulemap' + + # s.resource_bundles = { + # 'MoproKit' => ['MoproKit/Assets/*.png'] + # } + + # s.public_header_files = 'Pod/Classes/**/*.h' + # s.frameworks = 'UIKit', 'MapKit' + # s.dependency 'AFNetworking', '~> 2.3' +end diff --git a/app/ios/mopro/mopro-ios/MoproKit/MoproKit/Assets/.gitkeep b/app/ios/mopro/mopro-ios/MoproKit/MoproKit/Assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/app/ios/mopro/mopro-ios/MoproKit/README.md b/app/ios/mopro/mopro-ios/MoproKit/README.md new file mode 100644 index 000000000..98e7a94eb --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/README.md @@ -0,0 +1,29 @@ +# MoproKit + +[![CI Status](https://img.shields.io/travis/1552237/MoproKit.svg?style=flat)](https://travis-ci.org/1552237/MoproKit) +[![Version](https://img.shields.io/cocoapods/v/MoproKit.svg?style=flat)](https://cocoapods.org/pods/MoproKit) +[![License](https://img.shields.io/cocoapods/l/MoproKit.svg?style=flat)](https://cocoapods.org/pods/MoproKit) +[![Platform](https://img.shields.io/cocoapods/p/MoproKit.svg?style=flat)](https://cocoapods.org/pods/MoproKit) + +## Example + +To run the example project, clone the repo, and run `pod install` from the Example directory first. + +## Requirements + +## Installation + +MoproKit is available through [CocoaPods](https://cocoapods.org). To install +it, simply add the following line to your Podfile: + +```ruby +pod 'MoproKit' +``` + +## Author + +1552237, oskarth@titanproxy.com + +## License + +MoproKit is available under the MIT license. See the LICENSE file for more info. diff --git a/app/ios/mopro/mopro-ios/MoproKit/Resources/moproFFI.modulemap b/app/ios/mopro/mopro-ios/MoproKit/Resources/moproFFI.modulemap new file mode 100644 index 000000000..93b8adffb --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/Resources/moproFFI.modulemap @@ -0,0 +1,6 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +module moproFFI { + header "moproFFI.h" + export * +} \ No newline at end of file diff --git a/app/ios/mopro/mopro-ios/MoproKit/_Pods.xcodeproj b/app/ios/mopro/mopro-ios/MoproKit/_Pods.xcodeproj new file mode 120000 index 000000000..3c5a8e715 --- /dev/null +++ b/app/ios/mopro/mopro-ios/MoproKit/_Pods.xcodeproj @@ -0,0 +1 @@ +Example/Pods/Pods.xcodeproj \ No newline at end of file diff --git a/app/ios/mopro/mopro-ios/README.md b/app/ios/mopro/mopro-ios/README.md new file mode 100644 index 000000000..6c53f57e5 --- /dev/null +++ b/app/ios/mopro/mopro-ios/README.md @@ -0,0 +1,51 @@ +# mopro-ios + +## Prepare + + + +Check the [Prepare](../README.md#prepare) and [Build Bindings](../README.md#build-bindings) steps in the root directory. + +## Execute + +Open the `MoproKit/Example/MoproKit.xcworkspace` in Xcode. +Use `command`+`R` to execute a simulator. + +## Linker problems? + +Add the following settings after + +1. `MoproKit/Example/Pods/Target Support Files/MoproKit/MoproKit.debug.xcconfig` +2. `MoproKit/Example/Pods/Target Support Files/MoproKit/MoproKit.release.xcconfig` + +files + +``` +LIBRARY_SEARCH_PATHS=${SRCROOT}/../../Libs +OTHER_LDFLAGS=-lmopro_ffi +USER_HEADER_SEARCH_PATHS=${SRCROOT}/../../include +``` + +## Tests for the example app + +There are two ways to run tests for the example app: + +1. Xcode + Open the `MoproKit/Example/MoproKit.xcworkspace` in Xcode. + Use `command`+`U` to run tests. + +2. CLI + Run tests with command line: + + ```sh + cd MoproKit/Example + xcodebuild test -scheme MoproKit-Example \ + -workspace MoproKit.xcworkspace \ + -destination "platform=iOS Simulator,OS=17.0.1,name=iPhone 15 Pro" + ``` + + Check your simulator version and the OS with: + + ```sh + xcodebuild -showdestinations -workspace MoproKit.xcworkspace -scheme MoproKit-Example + ``` diff --git a/app/ios/mopro/mopro-ios/Sources/mopro.swift b/app/ios/mopro/mopro-ios/Sources/mopro.swift new file mode 100644 index 000000000..59edffd02 --- /dev/null +++ b/app/ios/mopro/mopro-ios/Sources/mopro.swift @@ -0,0 +1,411 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +import Foundation + +// Depending on the consumer's build setup, the low-level FFI code +// might be in a separate module, or it might be compiled inline into +// this module. This is a bit of light hackery to work with both. +#if canImport(moproFFI) + import moproFFI +#endif + +private extension RustBuffer { + // Allocate a new buffer, copying the contents of a `UInt8` array. + init(bytes: [UInt8]) { + let rbuf = bytes.withUnsafeBufferPointer { ptr in + RustBuffer.from(ptr) + } + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) + } + + static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { + try! rustCall { ffi_mopro_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + } + + // Frees the buffer in place. + // The buffer must not be used after this is called. + func deallocate() { + try! rustCall { ffi_mopro_rustbuffer_free(self, $0) } + } +} + +private extension ForeignBytes { + init(bufferPointer: UnsafeBufferPointer) { + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) + } +} + +// For every type used in the interface, we provide helper methods for conveniently +// lifting and lowering that type from C-compatible data, and for reading and writing +// values of that type in a buffer. + +// Helper classes/extensions that don't change. +// Someday, this will be in a library of its own. + +private extension Data { + init(rustBuffer: RustBuffer) { + // TODO: This copies the buffer. Can we read directly from a + // Rust buffer? + self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) + } +} + +// Define reader functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. +// +// With external types, one swift source file needs to be able to call the read +// method on another source file's FfiConverter, but then what visibility +// should Reader have? +// - If Reader is fileprivate, then this means the read() must also +// be fileprivate, which doesn't work with external types. +// - If Reader is internal/public, we'll get compile errors since both source +// files will try define the same type. +// +// Instead, the read() method and these helper functions input a tuple of data + +private func createReader(data: Data) -> (data: Data, offset: Data.Index) { + (data: data, offset: 0) +} + +// Reads an integer at the current offset, in big-endian order, and advances +// the offset on success. Throws if reading the integer would move the +// offset past the end of the buffer. +private func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { + let range = reader.offset ..< reader.offset + MemoryLayout.size + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = reader.data[reader.offset] + reader.offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value) { reader.data.copyBytes(to: $0, from: range) } + reader.offset = range.upperBound + return value.bigEndian +} + +// Reads an arbitrary number of bytes, to be used to read +// raw bytes, this is useful when lifting strings +private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> [UInt8] { + let range = reader.offset ..< (reader.offset + count) + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer { buffer in + reader.data.copyBytes(to: buffer, from: range) + } + reader.offset = range.upperBound + return value +} + +// Reads a float at the current offset. +private func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { + return try Float(bitPattern: readInt(&reader)) +} + +// Reads a float at the current offset. +private func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { + return try Double(bitPattern: readInt(&reader)) +} + +// Indicates if the offset has reached the end of the buffer. +private func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { + return reader.offset < reader.data.count +} + +// Define writer functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. See the above discussion on Readers for details. + +private func createWriter() -> [UInt8] { + return [] +} + +private func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { + writer.append(contentsOf: byteArr) +} + +// Writes an integer in big-endian order. +// +// Warning: make sure what you are trying to write +// is in the correct type! +private func writeInt(_ writer: inout [UInt8], _ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } +} + +private func writeFloat(_ writer: inout [UInt8], _ value: Float) { + writeInt(&writer, value.bitPattern) +} + +private func writeDouble(_ writer: inout [UInt8], _ value: Double) { + writeInt(&writer, value.bitPattern) +} + +// Protocol for types that transfer other types across the FFI. This is +// analogous go the Rust trait of the same name. +private protocol FfiConverter { + associatedtype FfiType + associatedtype SwiftType + + static func lift(_ value: FfiType) throws -> SwiftType + static func lower(_ value: SwiftType) -> FfiType + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType + static func write(_ value: SwiftType, into buf: inout [UInt8]) +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +private protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType {} + +extension FfiConverterPrimitive { + public static func lift(_ value: FfiType) throws -> SwiftType { + return value + } + + public static func lower(_ value: SwiftType) -> FfiType { + return value + } +} + +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. +// Used for complex types where it's hard to write a custom lift/lower. +private protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} + +extension FfiConverterRustBuffer { + public static func lift(_ buf: RustBuffer) throws -> SwiftType { + var reader = createReader(data: Data(rustBuffer: buf)) + let value = try read(from: &reader) + if hasRemaining(reader) { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + + public static func lower(_ value: SwiftType) -> RustBuffer { + var writer = createWriter() + write(value, into: &writer) + return RustBuffer(bytes: writer) + } +} + +// An error type for FFI errors. These errors occur at the UniFFI level, not +// the library level. +private enum UniffiInternalError: LocalizedError { + case bufferOverflow + case incompleteData + case unexpectedOptionalTag + case unexpectedEnumCase + case unexpectedNullPointer + case unexpectedRustCallStatusCode + case unexpectedRustCallError + case unexpectedStaleHandle + case rustPanic(_ message: String) + + public var errorDescription: String? { + switch self { + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" + case .incompleteData: return "The buffer still has data after lifting its containing value" + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" + case .unexpectedNullPointer: return "Raw pointer value was null" + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" + case let .rustPanic(message): return message + } + } +} + +private let CALL_SUCCESS: Int8 = 0 +private let CALL_ERROR: Int8 = 1 +private let CALL_PANIC: Int8 = 2 + +private extension RustCallStatus { + init() { + self.init( + code: CALL_SUCCESS, + errorBuf: RustBuffer( + capacity: 0, + len: 0, + data: nil + ) + ) + } +} + +private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: nil) +} + +private func rustCallWithError( + _ errorHandler: @escaping (RustBuffer) throws -> Error, + _ callback: (UnsafeMutablePointer) -> T +) throws -> T { + try makeRustCall(callback, errorHandler: errorHandler) +} + +private func makeRustCall( + _ callback: (UnsafeMutablePointer) -> T, + errorHandler: ((RustBuffer) throws -> Error)? +) throws -> T { + uniffiEnsureInitialized() + var callStatus = RustCallStatus() + let returnedVal = callback(&callStatus) + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) + return returnedVal +} + +private func uniffiCheckCallStatus( + callStatus: RustCallStatus, + errorHandler: ((RustBuffer) throws -> Error)? +) throws { + switch callStatus.code { + case CALL_SUCCESS: + return + + case CALL_ERROR: + if let errorHandler = errorHandler { + throw try errorHandler(callStatus.errorBuf) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.unexpectedRustCallError + } + + case CALL_PANIC: + // When the rust code sees a panic, it tries to construct a RustBuffer + // with the message. But if that code panics, then it just sends back + // an empty buffer. + if callStatus.errorBuf.len > 0 { + throw try UniffiInternalError.rustPanic(FfiConverterString.lift(callStatus.errorBuf)) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.rustPanic("Rust panic") + } + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} + +// Public interface members begin here. + +private struct FfiConverterUInt32: FfiConverterPrimitive { + typealias FfiType = UInt32 + typealias SwiftType = UInt32 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +private struct FfiConverterString: FfiConverter { + typealias SwiftType = String + typealias FfiType = RustBuffer + + public static func lift(_ value: RustBuffer) throws -> String { + defer { + value.deallocate() + } + if value.data == nil { + return String() + } + let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len)) + return String(bytes: bytes, encoding: String.Encoding.utf8)! + } + + public static func lower(_ value: String) -> RustBuffer { + return value.utf8CString.withUnsafeBufferPointer { ptr in + // The swift string gives us int8_t, we want uint8_t. + ptr.withMemoryRebound(to: UInt8.self) { ptr in + // The swift string gives us a trailing null byte, we don't want it. + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) + return RustBuffer.from(buf) + } + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { + let len: Int32 = try readInt(&buf) + return try String(bytes: readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! + } + + public static func write(_ value: String, into buf: inout [UInt8]) { + let len = Int32(value.utf8.count) + writeInt(&buf, len) + writeBytes(&buf, value.utf8) + } +} + +public func add(a: UInt32, b: UInt32) -> UInt32 { + return try! FfiConverterUInt32.lift( + try! rustCall { + uniffi_mopro_fn_func_add( + FfiConverterUInt32.lower(a), + FfiConverterUInt32.lower(b), $0 + ) + } + ) +} + +public func hello() -> String { + return try! FfiConverterString.lift( + try! rustCall { + uniffi_mopro_fn_func_hello($0) + } + ) +} + +public func run() { + try! rustCall { + uniffi_mopro_fn_func_run($0) + } +} + +private enum InitializationResult { + case ok + case contractVersionMismatch + case apiChecksumMismatch +} + +// Use a global variables to perform the versioning checks. Swift ensures that +// the code inside is only computed once. +private var initializationResult: InitializationResult { + // Get the bindings contract version from our ComponentInterface + let bindings_contract_version = 22 + // Get the scaffolding contract version by calling the into the dylib + let scaffolding_contract_version = ffi_mopro_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version { + return InitializationResult.contractVersionMismatch + } + if uniffi_mopro_checksum_func_add() != 19178 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_mopro_checksum_func_hello() != 309 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_mopro_checksum_func_run() != 17009 { + return InitializationResult.apiChecksumMismatch + } + + return InitializationResult.ok +} + +private func uniffiEnsureInitialized() { + switch initializationResult { + case .ok: + break + case .contractVersionMismatch: + fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + case .apiChecksumMismatch: + fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} diff --git a/app/ios/mopro/mopro-ios/headers/moproFFI.h b/app/ios/mopro/mopro-ios/headers/moproFFI.h new file mode 100644 index 000000000..0d7647eb0 --- /dev/null +++ b/app/ios/mopro/mopro-ios/headers/moproFFI.h @@ -0,0 +1,96 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +#pragma once + +#include +#include +#include + +// The following structs are used to implement the lowest level +// of the FFI, and thus useful to multiple uniffied crates. +// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. +#ifdef UNIFFI_SHARED_H + // We also try to prevent mixing versions of shared uniffi header structs. + // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 + #ifndef UNIFFI_SHARED_HEADER_V4 + #error Combining helper code from multiple versions of uniffi is not supported + #endif // ndef UNIFFI_SHARED_HEADER_V4 +#else +#define UNIFFI_SHARED_H +#define UNIFFI_SHARED_HEADER_V4 +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ + +typedef struct RustBuffer +{ + int32_t capacity; + int32_t len; + uint8_t *_Nullable data; +} RustBuffer; + +typedef int32_t (*ForeignCallback)(uint64_t, int32_t, const uint8_t *_Nonnull, int32_t, RustBuffer *_Nonnull); + +// Task defined in Rust that Swift executes +typedef void (*UniFfiRustTaskCallback)(const void * _Nullable); + +// Callback to execute Rust tasks using a Swift Task +// +// Args: +// executor: ForeignExecutor lowered into a size_t value +// delay: Delay in MS +// task: UniFfiRustTaskCallback to call +// task_data: data to pass the task callback +typedef void (*UniFfiForeignExecutorCallback)(size_t, uint32_t, UniFfiRustTaskCallback _Nullable, const void * _Nullable); + +typedef struct ForeignBytes +{ + int32_t len; + const uint8_t *_Nullable data; +} ForeignBytes; + +// Error definitions +typedef struct RustCallStatus { + int8_t code; + RustBuffer errorBuf; +} RustCallStatus; + +// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ +// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ +#endif // def UNIFFI_SHARED_H + +// Callbacks for UniFFI Futures +typedef void (*UniFfiFutureCallbackUInt8)(const void * _Nonnull, uint8_t, RustCallStatus); +typedef void (*UniFfiFutureCallbackUInt32)(const void * _Nonnull, uint32_t, RustCallStatus); +typedef void (*UniFfiFutureCallbackRustBuffer)(const void * _Nonnull, RustBuffer, RustCallStatus); + +// Scaffolding functions +uint32_t uniffi_mopro_fn_func_add(uint32_t a, uint32_t b, RustCallStatus *_Nonnull out_status +); +RustBuffer uniffi_mopro_fn_func_hello(RustCallStatus *_Nonnull out_status + +); +void uniffi_mopro_fn_func_run(RustCallStatus *_Nonnull out_status + +); +RustBuffer ffi_mopro_rustbuffer_alloc(int32_t size, RustCallStatus *_Nonnull out_status +); +RustBuffer ffi_mopro_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status +); +void ffi_mopro_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status +); +RustBuffer ffi_mopro_rustbuffer_reserve(RustBuffer buf, int32_t additional, RustCallStatus *_Nonnull out_status +); +uint16_t uniffi_mopro_checksum_func_add(void + +); +uint16_t uniffi_mopro_checksum_func_hello(void + +); +uint16_t uniffi_mopro_checksum_func_run(void + +); +uint32_t ffi_mopro_uniffi_contract_version(void + +); + diff --git a/app/ios/mopro/mopro-ios/headers/moproFFI.modulemap b/app/ios/mopro/mopro-ios/headers/moproFFI.modulemap new file mode 100644 index 000000000..93b8adffb --- /dev/null +++ b/app/ios/mopro/mopro-ios/headers/moproFFI.modulemap @@ -0,0 +1,6 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +module moproFFI { + header "moproFFI.h" + export * +} \ No newline at end of file From bd2f0dece62494a478699e6ae2647e319b8c33e2 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sun, 14 Jan 2024 22:01:00 +0100 Subject: [PATCH 02/12] deleted mopro-core, can't run mopro example anymore --- app/ios/Podfile | 4 - app/ios/Prover.swift | 2 +- app/ios/mopro/mopro-core/.gitignore | 14 - app/ios/mopro/mopro-core/Cargo.toml | 51 -- app/ios/mopro/mopro-core/README.md | 47 - app/ios/mopro/mopro-core/build.rs | 104 --- app/ios/mopro/mopro-core/examples/circom.rs | 41 - .../mopro-core/examples/circom/.gitignore | 2 - .../mopro-core/examples/circom/README.md | 9 - .../examples/circom/keccak256/.gitignore | 2 - .../examples/circom/keccak256/README.md | 7 - .../examples/circom/keccak256/keccak.circom | 186 ---- .../keccak256/keccak256_256_test.circom | 5 - .../circom/keccak256/package-lock.json | 21 - .../examples/circom/keccak256/package.json | 9 - .../circom/keccak256/permutations.circom | 799 ---------------- .../examples/circom/keccak256/utils.circom | 118 --- .../examples/circom/multiplier2/.gitignore | 2 - .../examples/circom/multiplier2/compile.sh | 4 - .../circom/multiplier2/multiplier2.circom | 16 - .../mopro-core/examples/circom/rsa/.gitignore | 2 - .../mopro-core/examples/circom/rsa/LICENSE | 21 - .../mopro-core/examples/circom/rsa/README.md | 5 - .../examples/circom/rsa/bigint.circom | 561 ------------ .../examples/circom/rsa/bigint_func.circom | 442 --------- .../mopro-core/examples/circom/rsa/fp.circom | 144 --- .../examples/circom/rsa/main.circom | 5 - .../examples/circom/rsa/package-lock.json | 21 - .../mopro-core/examples/circom/rsa/rsa.circom | 156 ---- .../examples/circom/scripts/compile.sh | 19 - .../circom/scripts/generate_arkzkey.sh | 41 - .../examples/circom/scripts/trusted_setup.sh | 47 - app/ios/mopro/mopro-core/src/lib.rs | 8 - .../mopro-core/src/middleware/circom/mod.rs | 860 ------------------ .../src/middleware/circom/serialization.rs | 106 --- .../mopro-core/src/middleware/circom/utils.rs | 33 - .../mopro/mopro-core/src/middleware/mod.rs | 1 - 37 files changed, 1 insertion(+), 3914 deletions(-) delete mode 100644 app/ios/mopro/mopro-core/.gitignore delete mode 100644 app/ios/mopro/mopro-core/Cargo.toml delete mode 100644 app/ios/mopro/mopro-core/README.md delete mode 100644 app/ios/mopro/mopro-core/build.rs delete mode 100644 app/ios/mopro/mopro-core/examples/circom.rs delete mode 100644 app/ios/mopro/mopro-core/examples/circom/.gitignore delete mode 100644 app/ios/mopro/mopro-core/examples/circom/README.md delete mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/.gitignore delete mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/README.md delete mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/keccak.circom delete mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/keccak256_256_test.circom delete mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/package-lock.json delete mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/package.json delete mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/permutations.circom delete mode 100644 app/ios/mopro/mopro-core/examples/circom/keccak256/utils.circom delete mode 100644 app/ios/mopro/mopro-core/examples/circom/multiplier2/.gitignore delete mode 100755 app/ios/mopro/mopro-core/examples/circom/multiplier2/compile.sh delete mode 100644 app/ios/mopro/mopro-core/examples/circom/multiplier2/multiplier2.circom delete mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/.gitignore delete mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/LICENSE delete mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/README.md delete mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/bigint.circom delete mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/bigint_func.circom delete mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/fp.circom delete mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/main.circom delete mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/package-lock.json delete mode 100644 app/ios/mopro/mopro-core/examples/circom/rsa/rsa.circom delete mode 100755 app/ios/mopro/mopro-core/examples/circom/scripts/compile.sh delete mode 100755 app/ios/mopro/mopro-core/examples/circom/scripts/generate_arkzkey.sh delete mode 100755 app/ios/mopro/mopro-core/examples/circom/scripts/trusted_setup.sh delete mode 100644 app/ios/mopro/mopro-core/src/lib.rs delete mode 100644 app/ios/mopro/mopro-core/src/middleware/circom/mod.rs delete mode 100644 app/ios/mopro/mopro-core/src/middleware/circom/serialization.rs delete mode 100644 app/ios/mopro/mopro-core/src/middleware/circom/utils.rs delete mode 100644 app/ios/mopro/mopro-core/src/middleware/mod.rs diff --git a/app/ios/Podfile b/app/ios/Podfile index 4c0f60b29..fbdaee9b9 100644 --- a/app/ios/Podfile +++ b/app/ios/Podfile @@ -37,10 +37,6 @@ target 'ProofOfPassport' do pod 'NFCPassportReader', git: 'https://github.com/0xturboblitz/NFCPassportReader.git', commit: '07b3662702834676b547718998fa377fe5f00776' pod 'MoproKit', :path => './mopro/mopro-ios/MoproKit' - # pod 'MoproKit', :podspec => 'https://raw.githubusercontent.com/0xturboblitz/mopro/main/MoproKit.podspec' - # pod 'MoproKit', git: 'https://github.com/0xturboblitz/MoproKit.git' - - use_react_native!( :path => config[:reactNativePath], # Hermes is now enabled by default. Disable by setting this flag to false. diff --git a/app/ios/Prover.swift b/app/ios/Prover.swift index aad19bfac..21eef4a01 100644 --- a/app/ios/Prover.swift +++ b/app/ios/Prover.swift @@ -165,7 +165,7 @@ class Prover: NSObject { print("Proof verification succeeded.") } catch let error as MoproError { - print("MoproError: \(error)") + print("MoproError: \(error)") } catch { print("Unexpected error: \(error)") } diff --git a/app/ios/mopro/mopro-core/.gitignore b/app/ios/mopro/mopro-core/.gitignore deleted file mode 100644 index 6985cf1bd..000000000 --- a/app/ios/mopro/mopro-core/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb diff --git a/app/ios/mopro/mopro-core/Cargo.toml b/app/ios/mopro/mopro-core/Cargo.toml deleted file mode 100644 index 1a63a4d30..000000000 --- a/app/ios/mopro/mopro-core/Cargo.toml +++ /dev/null @@ -1,51 +0,0 @@ -[package] -name = "mopro-core" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[patch.crates-io] -# NOTE: Forked wasmer to work around memory limits -# See https://github.com/wasmerio/wasmer/commit/09c7070 -wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" } - -[features] -default = [] -dylib = ["wasmer/dylib"] - -[dependencies] -ark-circom = { git = "https://github.com/arkworks-rs/circom-compat.git" } -serde = { version = "1.0", features = ["derive"] } -ark-serialize = { version = "=0.4.1", features = ["derive"] } -num-bigint = { version = "=0.4.3", default-features = false, features = [ - "rand", -] } -instant = "0.1" -wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" } -once_cell = "1.8" - -# ZKP generation -ark-ec = { version = "=0.4.1", default-features = false, features = [ - "parallel", -] } -ark-crypto-primitives = { version = "=0.4.0" } -ark-std = { version = "=0.4.0", default-features = false, features = [ - "parallel", -] } -ark-bn254 = { version = "=0.4.0" } -ark-groth16 = { version = "=0.4.0", default-features = false, features = [ - "parallel", -] } -ark-relations = { version = "0.4", default-features = false } -ark-zkey = { path = "../ark-zkey" } - -# Error handling -thiserror = "=1.0.39" -color-eyre = "=0.6.2" -criterion = "=0.3.6" - -[build-dependencies] -color-eyre = "0.6" -enumset = "1.0.8" -wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" } diff --git a/app/ios/mopro/mopro-core/README.md b/app/ios/mopro/mopro-core/README.md deleted file mode 100644 index 452109f1d..000000000 --- a/app/ios/mopro/mopro-core/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# mopro-core - -Core mobile Rust library. For FFI, see `mopro-ffi` which is a thin wrapper for exposing UniFFI bindings around this library. - -## Overview - -TBD. - -## Examples - -Run `cargo run --example circom`. Also see `examples/circom/README.md` for more information. - -## Build dylib - -Experimental support. - -Turns `.wasm` file into a dynamic library (`.dylib`). - -Run: - -`cargo build --features dylib` - -After that you'll see location of the dylib file: - -``` -warning: Building dylib for aarch64-apple-darwin -warning: Dylib location: /Users/user/repos/github.com/oskarth/mopro/mopro-core/target/debug/aarch64-apple-darwin/keccak256.dylib -``` - -Right now this is hardcoded for `rsa`. - -Note that: -- It has to be built for the right architecture -- Have to run `install_name_tool` to adjust install name -- Run `codesign` to sign dylib for use on iOS - -### Script - -Add third argument: `dylib`: - -`./scripts/update_bindings.sh device release dylib` - -Note that `APPLE_SIGNING_IDENTITY` must be set. - -## To use ark-zkey - -Experimental support for significantly faster zkey loading. See `../ark-zkey` README for how to build arkzkey. \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/build.rs b/app/ios/mopro/mopro-core/build.rs deleted file mode 100644 index 2205e80a3..000000000 --- a/app/ios/mopro/mopro-core/build.rs +++ /dev/null @@ -1,104 +0,0 @@ -use color_eyre::eyre::Result; -use std::env; -use std::path::PathBuf; - -fn prepare_env(zkey_path: String, wasm_path: String, arkzkey_path: String) -> Result<()> { - let project_dir = env::var("CARGO_MANIFEST_DIR")?; - let zkey_file = PathBuf::from(&project_dir).join(zkey_path); - let wasm_file = PathBuf::from(&project_dir).join(wasm_path); - let arkzkey_file = PathBuf::from(&project_dir).join(arkzkey_path); - - // TODO: Right now emitting as warnings for visibility, figure out better way to do this? - println!("cargo:warning=zkey_file: {}", zkey_file.display()); - println!("cargo:warning=wasm_file: {}", wasm_file.display()); - println!("cargo:warning=arkzkey_file: {}", arkzkey_file.display()); - - // Set BUILD_RS_ZKEY_FILE and BUILD_RS_WASM_FILE env var - println!("cargo:rustc-env=BUILD_RS_ZKEY_FILE={}", zkey_file.display()); - println!("cargo:rustc-env=BUILD_RS_WASM_FILE={}", wasm_file.display()); - println!( - "cargo:rustc-env=BUILD_RS_ARKZKEY_FILE={}", - arkzkey_file.display() - ); - - Ok(()) -} - -#[cfg(feature = "dylib")] -fn build_dylib(wasm_path: String, dylib_name: String) -> Result<()> { - use std::path::Path; - use std::{fs, str::FromStr}; - - use color_eyre::eyre::eyre; - use enumset::enum_set; - use enumset::EnumSet; - - use wasmer::Cranelift; - use wasmer::Dylib; - use wasmer::Target; - use wasmer::{Module, Store, Triple}; - - let out_dir = env::var("OUT_DIR")?; - let project_dir = env::var("CARGO_MANIFEST_DIR")?; - let build_mode = env::var("PROFILE")?; - let target_arch = env::var("TARGET")?; - - let out_dir = Path::new(&out_dir).to_path_buf(); - let wasm_file = Path::new(&wasm_path).to_path_buf(); - let dylib_file = out_dir.join(&dylib_name); - let final_dir = PathBuf::from(&project_dir) - .join("target") - .join(&target_arch) - .join(build_mode); - - // if dylib_file.exists() { - // return Ok(()); - // } - - // Create a WASM engine for the target that can compile - let triple = Triple::from_str(&target_arch).map_err(|e| eyre!(e))?; - let cpu_features = enum_set!(); - let target = Target::new(triple, cpu_features); - let engine = Dylib::new(Cranelift::default()).target(target).engine(); - println!("cargo:warning=Building dylib for {}", target_arch); - - // Compile the WASM module - let store = Store::new(&engine); - let module = Module::from_file(&store, &wasm_file).unwrap(); - module.serialize_to_file(&dylib_file).unwrap(); - assert!(dylib_file.exists()); - - // Copy dylib to a more predictable path - fs::create_dir_all(&final_dir)?; - let final_path = final_dir.join(dylib_name); - fs::copy(&dylib_file, &final_path)?; - println!("cargo:warning=Dylib location: {}", final_path.display()); - - Ok(()) -} - -fn main() -> Result<()> { - // TODO: build_circuit function to builds all related artifacts, instead of doing this externally - let dir = "examples/circom/keccak256"; - let circuit = "keccak256_256_test"; - - // XXX: Use RSA - // let dir = "examples/circom/rsa"; - // let circuit = "main"; - - let zkey_path = format!("{}/target/{}_final.zkey", dir, circuit); - let wasm_path = format!("{}/target/{}_js/{}.wasm", dir, circuit, circuit); - // TODO: Need to modify script for this - let arkzkey_path = format!("{}/target/{}_final.arkzkey", dir, circuit); - - prepare_env(zkey_path, wasm_path.clone(), arkzkey_path)?; - - #[cfg(feature = "dylib")] - { - // TODO: This should depends on the circuit name - //let dylib_name = "keccak256.dylib"; - let dylib_name = "rsa.dylib"; - build_dylib(wasm_path.clone(), dylib_name.to_string())?; - } - Ok(()) -} diff --git a/app/ios/mopro/mopro-core/examples/circom.rs b/app/ios/mopro/mopro-core/examples/circom.rs deleted file mode 100644 index 949ee191b..000000000 --- a/app/ios/mopro/mopro-core/examples/circom.rs +++ /dev/null @@ -1,41 +0,0 @@ -use mopro_core::middleware::circom::CircomState; -use num_bigint::BigInt; -use std::collections::HashMap; - -fn main() { - let wasm_path = "./examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"; - let r1cs_path = "./examples/circom/multiplier2/target/multiplier2.r1cs"; - - // Instantiate CircomState - let mut circom_state = CircomState::new(); - - // Setup - let setup_res = circom_state.setup(wasm_path, r1cs_path); - assert!(setup_res.is_ok()); - - let _serialized_pk = setup_res.unwrap(); - - // Deserialize the proving key and inputs if necessary - - // Prepare inputs - let mut inputs = HashMap::new(); - inputs.insert("a".to_string(), vec![BigInt::from(3)]); - inputs.insert("b".to_string(), vec![BigInt::from(5)]); - - // Proof generation - let generate_proof_res = circom_state.generate_proof(inputs); - - // Check and print the error if there is one - if let Err(e) = &generate_proof_res { - println!("Error: {:?}", e); - } - - assert!(generate_proof_res.is_ok()); - - let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); - - // Proof verification - let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs); - assert!(verify_res.is_ok()); - assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified -} diff --git a/app/ios/mopro/mopro-core/examples/circom/.gitignore b/app/ios/mopro/mopro-core/examples/circom/.gitignore deleted file mode 100644 index f1d902a10..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -!target -*.ptau diff --git a/app/ios/mopro/mopro-core/examples/circom/README.md b/app/ios/mopro/mopro-core/examples/circom/README.md deleted file mode 100644 index facfeedf0..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Circom examples - - Example circuits written in Circom used for testing. One basic, multiplier2, and another one slightly more involved, keccak256. The former is a good minimal circuit to test things end to end. The latter is useful for benchmarking. - - To compile circuits, run `./scripts/compile.sh `. For example, `./scripts/compile.sh multiplier2 multiplier2.circom`. - - To run a trusted setup, run `./scripts/trusted_setup.sh `. For example, `./scripts/trusted_setup.sh multiplier2 08 multiplier2`. - -Both of these actions are done as part of the `./scripts/prepare.sh` script in the root directory `multiplier2` and `keccak256`. \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/examples/circom/keccak256/.gitignore b/app/ios/mopro/mopro-core/examples/circom/keccak256/.gitignore deleted file mode 100644 index 5feb90786..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/keccak256/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -node_modules \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/examples/circom/keccak256/README.md b/app/ios/mopro/mopro-core/examples/circom/keccak256/README.md deleted file mode 100644 index 6537653d9..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/keccak256/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# README - -Basic test of Keccak256 in Circom, around 150k constraints. - -Used as a non-trivial circuit for initial benchmarking. - -Taken from https://github.com/vocdoni/keccak256-circom diff --git a/app/ios/mopro/mopro-core/examples/circom/keccak256/keccak.circom b/app/ios/mopro/mopro-core/examples/circom/keccak256/keccak.circom deleted file mode 100644 index f4a1b2fc0..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/keccak256/keccak.circom +++ /dev/null @@ -1,186 +0,0 @@ -// Keccak256 hash function (ethereum version). -// For LICENSE check https://github.com/vocdoni/keccak256-circom/blob/master/LICENSE - -pragma circom 2.0.0; - -include "./utils.circom"; -include "./permutations.circom"; - -template Pad(nBits) { - signal input in[nBits]; - - var blockSize=136*8; - signal output out[blockSize]; - signal out2[blockSize]; - - var i; - - for (i=0; i> i) & 1; - } - for (i=nBits+8; i> i) & 1; - } - for (i=0; i<8; i++) { - out[blockSize-8+i] <== aux.out[i]; - } - for (i=0; i>shr) - signal input a[n]; - signal input b[n]; - signal output out[n]; - var i; - - component aux0 = ShR(64, shr); - for (i=0; i<64; i++) { - aux0.in[i] <== a[i]; - } - component aux1 = ShL(64, shl); - for (i=0; i<64; i++) { - aux1.in[i] <== a[i]; - } - component aux2 = OrArray(64); - for (i=0; i<64; i++) { - aux2.a[i] <== aux0.out[i]; - aux2.b[i] <== aux1.out[i]; - } - component aux3 = XorArray(64); - for (i=0; i<64; i++) { - aux3.a[i] <== b[i]; - aux3.b[i] <== aux2.out[i]; - } - for (i=0; i<64; i++) { - out[i] <== aux3.out[i]; - } -} - -template Theta() { - signal input in[25*64]; - signal output out[25*64]; - - var i; - - component c0 = Xor5(64); - for (i=0; i<64; i++) { - c0.a[i] <== in[i]; - c0.b[i] <== in[5*64+i]; - c0.c[i] <== in[10*64+i]; - c0.d[i] <== in[15*64+i]; - c0.e[i] <== in[20*64+i]; - } - - component c1 = Xor5(64); - for (i=0; i<64; i++) { - c1.a[i] <== in[1*64+i]; - c1.b[i] <== in[6*64+i]; - c1.c[i] <== in[11*64+i]; - c1.d[i] <== in[16*64+i]; - c1.e[i] <== in[21*64+i]; - } - - component c2 = Xor5(64); - for (i=0; i<64; i++) { - c2.a[i] <== in[2*64+i]; - c2.b[i] <== in[7*64+i]; - c2.c[i] <== in[12*64+i]; - c2.d[i] <== in[17*64+i]; - c2.e[i] <== in[22*64+i]; - } - - component c3 = Xor5(64); - for (i=0; i<64; i++) { - c3.a[i] <== in[3*64+i]; - c3.b[i] <== in[8*64+i]; - c3.c[i] <== in[13*64+i]; - c3.d[i] <== in[18*64+i]; - c3.e[i] <== in[23*64+i]; - } - - component c4 = Xor5(64); - for (i=0; i<64; i++) { - c4.a[i] <== in[4*64+i]; - c4.b[i] <== in[9*64+i]; - c4.c[i] <== in[14*64+i]; - c4.d[i] <== in[19*64+i]; - c4.e[i] <== in[24*64+i]; - } - - // d = c4 ^ (c1<<1 | c1>>(64-1)) - component d0 = D(64, 1, 64-1); - for (i=0; i<64; i++) { - d0.a[i] <== c1.out[i]; - d0.b[i] <== c4.out[i]; - } - // r[0] = a[0] ^ d - component r0 = XorArray(64); - for (i=0; i<64; i++) { - r0.a[i] <== in[i]; - r0.b[i] <== d0.out[i]; - } - for (i=0; i<64; i++) { - out[i] <== r0.out[i]; - } - // r[5] = a[5] ^ d - component r5 = XorArray(64); - for (i=0; i<64; i++) { - r5.a[i] <== in[5*64+i]; - r5.b[i] <== d0.out[i]; - } - for (i=0; i<64; i++) { - out[5*64+i] <== r5.out[i]; - } - // r[10] = a[10] ^ d - component r10 = XorArray(64); - for (i=0; i<64; i++) { - r10.a[i] <== in[10*64+i]; - r10.b[i] <== d0.out[i]; - } - for (i=0; i<64; i++) { - out[10*64+i] <== r10.out[i]; - } - // r[15] = a[15] ^ d - component r15 = XorArray(64); - for (i=0; i<64; i++) { - r15.a[i] <== in[15*64+i]; - r15.b[i] <== d0.out[i]; - } - for (i=0; i<64; i++) { - out[15*64+i] <== r15.out[i]; - } - // r[20] = a[20] ^ d - component r20 = XorArray(64); - for (i=0; i<64; i++) { - r20.a[i] <== in[20*64+i]; - r20.b[i] <== d0.out[i]; - } - for (i=0; i<64; i++) { - out[20*64+i] <== r20.out[i]; - } - - // d = c0 ^ (c2<<1 | c2>>(64-1)) - component d1 = D(64, 1, 64-1); - for (i=0; i<64; i++) { - d1.a[i] <== c2.out[i]; - d1.b[i] <== c0.out[i]; - } - // r[1] = a[1] ^ d - component r1 = XorArray(64); - for (i=0; i<64; i++) { - r1.a[i] <== in[1*64+i]; - r1.b[i] <== d1.out[i]; - } - for (i=0; i<64; i++) { - out[1*64+i] <== r1.out[i]; - } - // r[6] = a[6] ^ d - component r6 = XorArray(64); - for (i=0; i<64; i++) { - r6.a[i] <== in[6*64+i]; - r6.b[i] <== d1.out[i]; - } - for (i=0; i<64; i++) { - out[6*64+i] <== r6.out[i]; - } - // r[11] = a[11] ^ d - component r11 = XorArray(64); - for (i=0; i<64; i++) { - r11.a[i] <== in[11*64+i]; - r11.b[i] <== d1.out[i]; - } - for (i=0; i<64; i++) { - out[11*64+i] <== r11.out[i]; - } - // r[16] = a[16] ^ d - component r16 = XorArray(64); - for (i=0; i<64; i++) { - r16.a[i] <== in[16*64+i]; - r16.b[i] <== d1.out[i]; - } - for (i=0; i<64; i++) { - out[16*64+i] <== r16.out[i]; - } - // r[21] = a[21] ^ d - component r21 = XorArray(64); - for (i=0; i<64; i++) { - r21.a[i] <== in[21*64+i]; - r21.b[i] <== d1.out[i]; - } - for (i=0; i<64; i++) { - out[21*64+i] <== r21.out[i]; - } - - // d = c1 ^ (c3<<1 | c3>>(64-1)) - component d2 = D(64, 1, 64-1); - for (i=0; i<64; i++) { - d2.a[i] <== c3.out[i]; - d2.b[i] <== c1.out[i]; - } - // r[2] = a[2] ^ d - component r2 = XorArray(64); - for (i=0; i<64; i++) { - r2.a[i] <== in[2*64+i]; - r2.b[i] <== d2.out[i]; - } - for (i=0; i<64; i++) { - out[2*64+i] <== r2.out[i]; - } - // r[7] = a[7] ^ d - component r7 = XorArray(64); - for (i=0; i<64; i++) { - r7.a[i] <== in[7*64+i]; - r7.b[i] <== d2.out[i]; - } - for (i=0; i<64; i++) { - out[7*64+i] <== r7.out[i]; - } - // r[12] = a[12] ^ d - component r12 = XorArray(64); - for (i=0; i<64; i++) { - r12.a[i] <== in[12*64+i]; - r12.b[i] <== d2.out[i]; - } - for (i=0; i<64; i++) { - out[12*64+i] <== r12.out[i]; - } - // r[17] = a[17] ^ d - component r17 = XorArray(64); - for (i=0; i<64; i++) { - r17.a[i] <== in[17*64+i]; - r17.b[i] <== d2.out[i]; - } - for (i=0; i<64; i++) { - out[17*64+i] <== r17.out[i]; - } - // r[22] = a[22] ^ d - component r22 = XorArray(64); - for (i=0; i<64; i++) { - r22.a[i] <== in[22*64+i]; - r22.b[i] <== d2.out[i]; - } - for (i=0; i<64; i++) { - out[22*64+i] <== r22.out[i]; - } - - // d = c2 ^ (c4<<1 | c4>>(64-1)) - component d3 = D(64, 1, 64-1); - for (i=0; i<64; i++) { - d3.a[i] <== c4.out[i]; - d3.b[i] <== c2.out[i]; - } - // r[3] = a[3] ^ d - component r3 = XorArray(64); - for (i=0; i<64; i++) { - r3.a[i] <== in[3*64+i]; - r3.b[i] <== d3.out[i]; - } - for (i=0; i<64; i++) { - out[3*64+i] <== r3.out[i]; - } - // r[8] = a[8] ^ d - component r8 = XorArray(64); - for (i=0; i<64; i++) { - r8.a[i] <== in[8*64+i]; - r8.b[i] <== d3.out[i]; - } - for (i=0; i<64; i++) { - out[8*64+i] <== r8.out[i]; - } - // r[13] = a[13] ^ d - component r13 = XorArray(64); - for (i=0; i<64; i++) { - r13.a[i] <== in[13*64+i]; - r13.b[i] <== d3.out[i]; - } - for (i=0; i<64; i++) { - out[13*64+i] <== r13.out[i]; - } - // r[18] = a[18] ^ d - component r18 = XorArray(64); - for (i=0; i<64; i++) { - r18.a[i] <== in[18*64+i]; - r18.b[i] <== d3.out[i]; - } - for (i=0; i<64; i++) { - out[18*64+i] <== r18.out[i]; - } - // r[23] = a[23] ^ d - component r23 = XorArray(64); - for (i=0; i<64; i++) { - r23.a[i] <== in[23*64+i]; - r23.b[i] <== d3.out[i]; - } - for (i=0; i<64; i++) { - out[23*64+i] <== r23.out[i]; - } - - // d = c3 ^ (c0<<1 | c0>>(64-1)) - component d4 = D(64, 1, 64-1); - for (i=0; i<64; i++) { - d4.a[i] <== c0.out[i]; - d4.b[i] <== c3.out[i]; - } - // r[4] = a[4] ^ d - component r4 = XorArray(64); - for (i=0; i<64; i++) { - r4.a[i] <== in[4*64+i]; - r4.b[i] <== d4.out[i]; - } - for (i=0; i<64; i++) { - out[4*64+i] <== r4.out[i]; - } - // r[9] = a[9] ^ d - component r9 = XorArray(64); - for (i=0; i<64; i++) { - r9.a[i] <== in[9*64+i]; - r9.b[i] <== d4.out[i]; - } - for (i=0; i<64; i++) { - out[9*64+i] <== r9.out[i]; - } - // r[14] = a[14] ^ d - component r14 = XorArray(64); - for (i=0; i<64; i++) { - r14.a[i] <== in[14*64+i]; - r14.b[i] <== d4.out[i]; - } - for (i=0; i<64; i++) { - out[14*64+i] <== r14.out[i]; - } - // r[19] = a[19] ^ d - component r19 = XorArray(64); - for (i=0; i<64; i++) { - r19.a[i] <== in[19*64+i]; - r19.b[i] <== d4.out[i]; - } - for (i=0; i<64; i++) { - out[19*64+i] <== r19.out[i]; - } - // r[24] = a[24] ^ d - component r24 = XorArray(64); - for (i=0; i<64; i++) { - r24.a[i] <== in[24*64+i]; - r24.b[i] <== d4.out[i]; - } - for (i=0; i<64; i++) { - out[24*64+i] <== r24.out[i]; - } -} - -// RhoPi - -template stepRhoPi(shl, shr) { - // out = a<>shr - signal input a[64]; - signal output out[64]; - var i; - - component aux0 = ShR(64, shr); - for (i=0; i<64; i++) { - aux0.in[i] <== a[i]; - } - component aux1 = ShL(64, shl); - for (i=0; i<64; i++) { - aux1.in[i] <== a[i]; - } - component aux2 = OrArray(64); - for (i=0; i<64; i++) { - aux2.a[i] <== aux0.out[i]; - aux2.b[i] <== aux1.out[i]; - } - for (i=0; i<64; i++) { - out[i] <== aux2.out[i]; - } -} -template RhoPi() { - signal input in[25*64]; - signal output out[25*64]; - - var i; - - // r[10] = a[1]<<1|a[1]>>(64-1) - component s10 = stepRhoPi(1, 64-1); - for (i=0; i<64; i++) { - s10.a[i] <== in[1*64+i]; - } - // r[7] = a[10]<<3|a[10]>>(64-3) - component s7 = stepRhoPi(3, 64-3); - for (i=0; i<64; i++) { - s7.a[i] <== in[10*64+i]; - } - // r[11] = a[7]<<6|a[7]>>(64-6) - component s11 = stepRhoPi(6, 64-6); - for (i=0; i<64; i++) { - s11.a[i] <== in[7*64+i]; - } - // r[17] = a[11]<<10|a[11]>>(64-10) - component s17 = stepRhoPi(10, 64-10); - for (i=0; i<64; i++) { - s17.a[i] <== in[11*64+i]; - } - // r[18] = a[17]<<15|a[17]>>(64-15) - component s18 = stepRhoPi(15, 64-15); - for (i=0; i<64; i++) { - s18.a[i] <== in[17*64+i]; - } - // r[3] = a[18]<<21|a[18]>>(64-21) - component s3 = stepRhoPi(21, 64-21); - for (i=0; i<64; i++) { - s3.a[i] <== in[18*64+i]; - } - // r[5] = a[3]<<28|a[3]>>(64-28) - component s5 = stepRhoPi(28, 64-28); - for (i=0; i<64; i++) { - s5.a[i] <== in[3*64+i]; - } - // r[16] = a[5]<<36|a[5]>>(64-36) - component s16 = stepRhoPi(36, 64-36); - for (i=0; i<64; i++) { - s16.a[i] <== in[5*64+i]; - } - // r[8] = a[16]<<45|a[16]>>(64-45) - component s8 = stepRhoPi(45, 64-45); - for (i=0; i<64; i++) { - s8.a[i] <== in[16*64+i]; - } - // r[21] = a[8]<<55|a[8]>>(64-55) - component s21 = stepRhoPi(55, 64-55); - for (i=0; i<64; i++) { - s21.a[i] <== in[8*64+i]; - } - // r[24] = a[21]<<2|a[21]>>(64-2) - component s24 = stepRhoPi(2, 64-2); - for (i=0; i<64; i++) { - s24.a[i] <== in[21*64+i]; - } - // r[4] = a[24]<<14|a[24]>>(64-14) - component s4 = stepRhoPi(14, 64-14); - for (i=0; i<64; i++) { - s4.a[i] <== in[24*64+i]; - } - // r[15] = a[4]<<27|a[4]>>(64-27) - component s15 = stepRhoPi(27, 64-27); - for (i=0; i<64; i++) { - s15.a[i] <== in[4*64+i]; - } - // r[23] = a[15]<<41|a[15]>>(64-41) - component s23 = stepRhoPi(41, 64-41); - for (i=0; i<64; i++) { - s23.a[i] <== in[15*64+i]; - } - // r[19] = a[23]<<56|a[23]>>(64-56) - component s19 = stepRhoPi(56, 64-56); - for (i=0; i<64; i++) { - s19.a[i] <== in[23*64+i]; - } - // r[13] = a[19]<<8|a[19]>>(64-8) - component s13 = stepRhoPi(8, 64-8); - for (i=0; i<64; i++) { - s13.a[i] <== in[19*64+i]; - } - // r[12] = a[13]<<25|a[13]>>(64-25) - component s12 = stepRhoPi(25, 64-25); - for (i=0; i<64; i++) { - s12.a[i] <== in[13*64+i]; - } - // r[2] = a[12]<<43|a[12]>>(64-43) - component s2 = stepRhoPi(43, 64-43); - for (i=0; i<64; i++) { - s2.a[i] <== in[12*64+i]; - } - // r[20] = a[2]<<62|a[2]>>(64-62) - component s20 = stepRhoPi(62, 64-62); - for (i=0; i<64; i++) { - s20.a[i] <== in[2*64+i]; - } - // r[14] = a[20]<<18|a[20]>>(64-18) - component s14 = stepRhoPi(18, 64-18); - for (i=0; i<64; i++) { - s14.a[i] <== in[20*64+i]; - } - // r[22] = a[14]<<39|a[14]>>(64-39) - component s22 = stepRhoPi(39, 64-39); - for (i=0; i<64; i++) { - s22.a[i] <== in[14*64+i]; - } - // r[9] = a[22]<<61|a[22]>>(64-61) - component s9 = stepRhoPi(61, 64-61); - for (i=0; i<64; i++) { - s9.a[i] <== in[22*64+i]; - } - // r[6] = a[9]<<20|a[9]>>(64-20) - component s6 = stepRhoPi(20, 64-20); - for (i=0; i<64; i++) { - s6.a[i] <== in[9*64+i]; - } - // r[1] = a[6]<<44|a[6]>>(64-44) - component s1 = stepRhoPi(44, 64-44); - for (i=0; i<64; i++) { - s1.a[i] <== in[6*64+i]; - } - - for (i=0; i<64; i++) { - out[i] <== in[i]; - out[10*64+i] <== s10.out[i]; - out[7*64+i] <== s7.out[i]; - out[11*64+i] <== s11.out[i]; - out[17*64+i] <== s17.out[i]; - out[18*64+i] <== s18.out[i]; - out[3*64+i] <== s3.out[i]; - out[5*64+i] <== s5.out[i]; - out[16*64+i] <== s16.out[i]; - out[8*64+i] <== s8.out[i]; - out[21*64+i] <== s21.out[i]; - out[24*64+i] <== s24.out[i]; - out[4*64+i] <== s4.out[i]; - out[15*64+i] <== s15.out[i]; - out[23*64+i] <== s23.out[i]; - out[19*64+i] <== s19.out[i]; - out[13*64+i] <== s13.out[i]; - out[12*64+i] <== s12.out[i]; - out[2*64+i] <== s2.out[i]; - out[20*64+i] <== s20.out[i]; - out[14*64+i] <== s14.out[i]; - out[22*64+i] <== s22.out[i]; - out[9*64+i] <== s9.out[i]; - out[6*64+i] <== s6.out[i]; - out[1*64+i] <== s1.out[i]; - } -} - - -// Chi - -template stepChi() { - // out = a ^ (^b) & c - signal input a[64]; - signal input b[64]; - signal input c[64]; - signal output out[64]; - var i; - - // ^b - component bXor = XorArraySingle(64); - for (i=0; i<64; i++) { - bXor.a[i] <== b[i]; - } - // (^b)&c - component bc = AndArray(64); - for (i=0; i<64; i++) { - bc.a[i] <== bXor.out[i]; - bc.b[i] <== c[i]; - } - // a^(^b)&c - component abc = XorArray(64); - for (i=0; i<64; i++) { - abc.a[i] <== a[i]; - abc.b[i] <== bc.out[i]; - } - for (i=0; i<64; i++) { - out[i] <== abc.out[i]; - } -} - -template Chi() { - signal input in[25*64]; - signal output out[25*64]; - - var i; - - component r0 = stepChi(); - for (i=0; i<64; i++) { - r0.a[i] <== in[i]; - r0.b[i] <== in[1*64+i]; - r0.c[i] <== in[2*64+i]; - } - component r1 = stepChi(); - for (i=0; i<64; i++) { - r1.a[i] <== in[1*64+i]; - r1.b[i] <== in[2*64+i]; - r1.c[i] <== in[3*64+i]; - } - component r2 = stepChi(); - for (i=0; i<64; i++) { - r2.a[i] <== in[2*64+i]; - r2.b[i] <== in[3*64+i]; - r2.c[i] <== in[4*64+i]; - } - component r3 = stepChi(); - for (i=0; i<64; i++) { - r3.a[i] <== in[3*64+i]; - r3.b[i] <== in[4*64+i]; - r3.c[i] <== in[0*64+i]; - } - component r4 = stepChi(); - for (i=0; i<64; i++) { - r4.a[i] <== in[4*64+i]; - r4.b[i] <== in[i]; - r4.c[i] <== in[1*64+i]; - } - - component r5 = stepChi(); - for (i=0; i<64; i++) { - r5.a[i] <== in[5*64+i]; - r5.b[i] <== in[6*64+i]; - r5.c[i] <== in[7*64+i]; - } - component r6 = stepChi(); - for (i=0; i<64; i++) { - r6.a[i] <== in[6*64+i]; - r6.b[i] <== in[7*64+i]; - r6.c[i] <== in[8*64+i]; - } - component r7 = stepChi(); - for (i=0; i<64; i++) { - r7.a[i] <== in[7*64+i]; - r7.b[i] <== in[8*64+i]; - r7.c[i] <== in[9*64+i]; - } - component r8 = stepChi(); - for (i=0; i<64; i++) { - r8.a[i] <== in[8*64+i]; - r8.b[i] <== in[9*64+i]; - r8.c[i] <== in[5*64+i]; - } - component r9 = stepChi(); - for (i=0; i<64; i++) { - r9.a[i] <== in[9*64+i]; - r9.b[i] <== in[5*64+i]; - r9.c[i] <== in[6*64+i]; - } - - component r10 = stepChi(); - for (i=0; i<64; i++) { - r10.a[i] <== in[10*64+i]; - r10.b[i] <== in[11*64+i]; - r10.c[i] <== in[12*64+i]; - } - component r11 = stepChi(); - for (i=0; i<64; i++) { - r11.a[i] <== in[11*64+i]; - r11.b[i] <== in[12*64+i]; - r11.c[i] <== in[13*64+i]; - } - component r12 = stepChi(); - for (i=0; i<64; i++) { - r12.a[i] <== in[12*64+i]; - r12.b[i] <== in[13*64+i]; - r12.c[i] <== in[14*64+i]; - } - component r13 = stepChi(); - for (i=0; i<64; i++) { - r13.a[i] <== in[13*64+i]; - r13.b[i] <== in[14*64+i]; - r13.c[i] <== in[10*64+i]; - } - component r14 = stepChi(); - for (i=0; i<64; i++) { - r14.a[i] <== in[14*64+i]; - r14.b[i] <== in[10*64+i]; - r14.c[i] <== in[11*64+i]; - } - - component r15 = stepChi(); - for (i=0; i<64; i++) { - r15.a[i] <== in[15*64+i]; - r15.b[i] <== in[16*64+i]; - r15.c[i] <== in[17*64+i]; - } - component r16 = stepChi(); - for (i=0; i<64; i++) { - r16.a[i] <== in[16*64+i]; - r16.b[i] <== in[17*64+i]; - r16.c[i] <== in[18*64+i]; - } - component r17 = stepChi(); - for (i=0; i<64; i++) { - r17.a[i] <== in[17*64+i]; - r17.b[i] <== in[18*64+i]; - r17.c[i] <== in[19*64+i]; - } - component r18 = stepChi(); - for (i=0; i<64; i++) { - r18.a[i] <== in[18*64+i]; - r18.b[i] <== in[19*64+i]; - r18.c[i] <== in[15*64+i]; - } - component r19 = stepChi(); - for (i=0; i<64; i++) { - r19.a[i] <== in[19*64+i]; - r19.b[i] <== in[15*64+i]; - r19.c[i] <== in[16*64+i]; - } - - component r20 = stepChi(); - for (i=0; i<64; i++) { - r20.a[i] <== in[20*64+i]; - r20.b[i] <== in[21*64+i]; - r20.c[i] <== in[22*64+i]; - } - component r21 = stepChi(); - for (i=0; i<64; i++) { - r21.a[i] <== in[21*64+i]; - r21.b[i] <== in[22*64+i]; - r21.c[i] <== in[23*64+i]; - } - component r22 = stepChi(); - for (i=0; i<64; i++) { - r22.a[i] <== in[22*64+i]; - r22.b[i] <== in[23*64+i]; - r22.c[i] <== in[24*64+i]; - } - component r23 = stepChi(); - for (i=0; i<64; i++) { - r23.a[i] <== in[23*64+i]; - r23.b[i] <== in[24*64+i]; - r23.c[i] <== in[20*64+i]; - } - component r24 = stepChi(); - for (i=0; i<64; i++) { - r24.a[i] <== in[24*64+i]; - r24.b[i] <== in[20*64+i]; - r24.c[i] <== in[21*64+i]; - } - - for (i=0; i<64; i++) { - out[i] <== r0.out[i]; - out[1*64+i] <== r1.out[i]; - out[2*64+i] <== r2.out[i]; - out[3*64+i] <== r3.out[i]; - out[4*64+i] <== r4.out[i]; - - out[5*64+i] <== r5.out[i]; - out[6*64+i] <== r6.out[i]; - out[7*64+i] <== r7.out[i]; - out[8*64+i] <== r8.out[i]; - out[9*64+i] <== r9.out[i]; - - out[10*64+i] <== r10.out[i]; - out[11*64+i] <== r11.out[i]; - out[12*64+i] <== r12.out[i]; - out[13*64+i] <== r13.out[i]; - out[14*64+i] <== r14.out[i]; - - out[15*64+i] <== r15.out[i]; - out[16*64+i] <== r16.out[i]; - out[17*64+i] <== r17.out[i]; - out[18*64+i] <== r18.out[i]; - out[19*64+i] <== r19.out[i]; - - out[20*64+i] <== r20.out[i]; - out[21*64+i] <== r21.out[i]; - out[22*64+i] <== r22.out[i]; - out[23*64+i] <== r23.out[i]; - out[24*64+i] <== r24.out[i]; - } -} - -// Iota - -template RC(r) { - signal output out[64]; - var rc[24] = [ - 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, - 0x8000000080008000, 0x000000000000808B, 0x0000000080000001, - 0x8000000080008081, 0x8000000000008009, 0x000000000000008A, - 0x0000000000000088, 0x0000000080008009, 0x000000008000000A, - 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, - 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, - 0x000000000000800A, 0x800000008000000A, 0x8000000080008081, - 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 - ]; - for (var i=0; i<64; i++) { - out[i] <== (rc[r] >> i) & 1; - } -} - -template Iota(r) { - signal input in[25*64]; - signal output out[25*64]; - var i; - - component rc = RC(r); - - component iota = XorArray(64); - for (var i=0; i<64; i++) { - iota.a[i] <== in[i]; - iota.b[i] <== rc.out[i]; - } - for (i=0; i<64; i++) { - out[i] <== iota.out[i]; - } - for (i=64; i<25*64; i++) { - out[i] <== in[i]; - } -} - diff --git a/app/ios/mopro/mopro-core/examples/circom/keccak256/utils.circom b/app/ios/mopro/mopro-core/examples/circom/keccak256/utils.circom deleted file mode 100644 index 6a66fb257..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/keccak256/utils.circom +++ /dev/null @@ -1,118 +0,0 @@ -// Keccak256 hash function (ethereum version). -// For LICENSE check https://github.com/vocdoni/keccak256-circom/blob/master/LICENSE - -pragma circom 2.0.0; - -include "node_modules/circomlib/circuits/gates.circom"; -include "node_modules/circomlib/circuits/sha256/xor3.circom"; -include "node_modules/circomlib/circuits/sha256/shift.circom"; // contains ShiftRight - -template Xor5(n) { - signal input a[n]; - signal input b[n]; - signal input c[n]; - signal input d[n]; - signal input e[n]; - signal output out[n]; - var i; - - component xor3 = Xor3(n); - for (i=0; i= 0 -template ModSubThree(n) { - assert(n + 2 <= 253); - signal input a; - signal input b; - signal input c; - assert(a - b - c + (1 << n) >= 0); - signal output out; - signal output borrow; - signal b_plus_c; - b_plus_c <== b + c; - component lt = LessThan(n + 1); - lt.in[0] <== a; - lt.in[1] <== b_plus_c; - borrow <== lt.out; - out <== borrow * (1 << n) + a - b_plus_c; -} - -template ModSumThree(n) { - assert(n + 2 <= 253); - signal input a; - signal input b; - signal input c; - signal output sum; - signal output carry; - - component n2b = Num2Bits(n + 2); - n2b.in <== a + b + c; - carry <== n2b.out[n] + 2 * n2b.out[n + 1]; - sum <== a + b + c - carry * (1 << n); -} - -template ModSumFour(n) { - assert(n + 2 <= 253); - signal input a; - signal input b; - signal input c; - signal input d; - signal output sum; - signal output carry; - - component n2b = Num2Bits(n + 2); - n2b.in <== a + b + c + d; - carry <== n2b.out[n] + 2 * n2b.out[n + 1]; - sum <== a + b + c + d - carry * (1 << n); -} - -// product mod 2**n with carry -template ModProd(n) { - assert(n <= 126); - signal input a; - signal input b; - signal output prod; - signal output carry; - - component n2b = Num2Bits(2 * n); - n2b.in <== a * b; - - component b2n1 = Bits2Num(n); - component b2n2 = Bits2Num(n); - var i; - for (i = 0; i < n; i++) { - b2n1.in[i] <== n2b.out[i]; - b2n2.in[i] <== n2b.out[i + n]; - } - prod <== b2n1.out; - carry <== b2n2.out; -} - -// split a n + m bit input into two outputs -template Split(n, m) { - assert(n <= 126); - signal input in; - signal output small; - signal output big; - - small <-- in % (1 << n); - big <-- in \ (1 << n); - - component n2b_small = Num2Bits(n); - n2b_small.in <== small; - component n2b_big = Num2Bits(m); - n2b_big.in <== big; - - in === small + big * (1 << n); -} - -// split a n + m + k bit input into three outputs -template SplitThree(n, m, k) { - assert(n <= 126); - signal input in; - signal output small; - signal output medium; - signal output big; - - small <-- in % (1 << n); - medium <-- (in \ (1 << n)) % (1 << m); - big <-- in \ (1 << n + m); - - component n2b_small = Num2Bits(n); - n2b_small.in <== small; - component n2b_medium = Num2Bits(m); - n2b_medium.in <== medium; - component n2b_big = Num2Bits(k); - n2b_big.in <== big; - - in === small + medium * (1 << n) + big * (1 << n + m); -} - -// a[i], b[i] in 0... 2**n-1 -// represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k) -template BigAdd(n, k) { - assert(n <= 252); - signal input a[k]; - signal input b[k]; - signal output out[k + 1]; - - component unit0 = ModSum(n); - unit0.a <== a[0]; - unit0.b <== b[0]; - out[0] <== unit0.sum; - - component unit[k - 1]; - for (var i = 1; i < k; i++) { - unit[i - 1] = ModSumThree(n); - unit[i - 1].a <== a[i]; - unit[i - 1].b <== b[i]; - if (i == 1) { - unit[i - 1].c <== unit0.carry; - } else { - unit[i - 1].c <== unit[i - 2].carry; - } - out[i] <== unit[i - 1].sum; - } - out[k] <== unit[k - 2].carry; -} - -// a and b have n-bit registers -// a has ka registers, each with NONNEGATIVE ma-bit values (ma can be > n) -// b has kb registers, each with NONNEGATIVE mb-bit values (mb can be > n) -// out has ka + kb - 1 registers, each with (ma + mb + ceil(log(max(ka, kb))))-bit values -template BigMultNoCarry(n, ma, mb, ka, kb) { - assert(ma + mb <= 253); - signal input a[ka]; - signal input b[kb]; - signal output out[ka + kb - 1]; - - var prod_val[ka + kb - 1]; - for (var i = 0; i < ka + kb - 1; i++) { - prod_val[i] = 0; - } - for (var i = 0; i < ka; i++) { - for (var j = 0; j < kb; j++) { - prod_val[i + j] += a[i] * b[j]; - } - } - for (var i = 0; i < ka + kb - 1; i++) { - out[i] <-- prod_val[i]; - } - - var a_poly[ka + kb - 1]; - var b_poly[ka + kb - 1]; - var out_poly[ka + kb - 1]; - for (var i = 0; i < ka + kb - 1; i++) { - out_poly[i] = 0; - a_poly[i] = 0; - b_poly[i] = 0; - for (var j = 0; j < ka + kb - 1; j++) { - out_poly[i] = out_poly[i] + out[j] * (i ** j); - } - for (var j = 0; j < ka; j++) { - a_poly[i] = a_poly[i] + a[j] * (i ** j); - } - for (var j = 0; j < kb; j++) { - b_poly[i] = b_poly[i] + b[j] * (i ** j); - } - } - for (var i = 0; i < ka + kb - 1; i++) { - out_poly[i] === a_poly[i] * b_poly[i]; - } -} - - -// in[i] contains longs -// out[i] contains shorts -template LongToShortNoEndCarry(n, k) { - assert(n <= 126); - signal input in[k]; - signal output out[k+1]; - - var split[k][3]; - for (var i = 0; i < k; i++) { - split[i] = SplitThreeFn(in[i], n, n, n); - } - - var carry[k]; - carry[0] = 0; - out[0] <-- split[0][0]; - if (k == 1) { - out[1] <-- split[0][1]; - } - if (k > 1) { - var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], n, n); - out[1] <-- sumAndCarry[0]; - carry[1] = sumAndCarry[1]; - } - if (k == 2) { - out[2] <-- split[1][1] + split[0][2] + carry[1]; - } - if (k > 2) { - for (var i = 2; i < k; i++) { - var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], n, n); - out[i] <-- sumAndCarry[0]; - carry[i] = sumAndCarry[1]; - } - out[k] <-- split[k-1][1] + split[k-2][2] + carry[k-1]; - } - - component outRangeChecks[k+1]; - for (var i = 0; i < k+1; i++) { - outRangeChecks[i] = Num2Bits(n); - outRangeChecks[i].in <== out[i]; - } - - signal runningCarry[k]; - component runningCarryRangeChecks[k]; - runningCarry[0] <-- (in[0] - out[0]) / (1 << n); - runningCarryRangeChecks[0] = Num2Bits(n + log_ceil(k)); - runningCarryRangeChecks[0].in <== runningCarry[0]; - runningCarry[0] * (1 << n) === in[0] - out[0]; - for (var i = 1; i < k; i++) { - runningCarry[i] <-- (in[i] - out[i] + runningCarry[i-1]) / (1 << n); - runningCarryRangeChecks[i] = Num2Bits(n + log_ceil(k)); - runningCarryRangeChecks[i].in <== runningCarry[i]; - runningCarry[i] * (1 << n) === in[i] - out[i] + runningCarry[i-1]; - } - runningCarry[k-1] === out[k]; -} - -template BigMult(n, k) { - signal input a[k]; - signal input b[k]; - signal output out[2 * k]; - - component mult = BigMultNoCarry(n, n, n, k, k); - for (var i = 0; i < k; i++) { - mult.a[i] <== a[i]; - mult.b[i] <== b[i]; - } - - // no carry is possible in the highest order register - component longshort = LongToShortNoEndCarry(n, 2 * k - 1); - for (var i = 0; i < 2 * k - 1; i++) { - longshort.in[i] <== mult.out[i]; - } - for (var i = 0; i < 2 * k; i++) { - out[i] <== longshort.out[i]; - } -} - -template BigLessThan(n, k){ - signal input a[k]; - signal input b[k]; - signal output out; - - component lt[k]; - component eq[k]; - for (var i = 0; i < k; i++) { - lt[i] = LessThan(n); - lt[i].in[0] <== a[i]; - lt[i].in[1] <== b[i]; - eq[i] = IsEqual(); - eq[i].in[0] <== a[i]; - eq[i].in[1] <== b[i]; - } - - // ors[i] holds (lt[k - 1] || (eq[k - 1] && lt[k - 2]) .. || (eq[k - 1] && .. && lt[i])) - // ands[i] holds (eq[k - 1] && .. && lt[i]) - // eq_ands[i] holds (eq[k - 1] && .. && eq[i]) - component ors[k - 1]; - component ands[k - 1]; - component eq_ands[k - 1]; - for (var i = k - 2; i >= 0; i--) { - ands[i] = AND(); - eq_ands[i] = AND(); - ors[i] = OR(); - - if (i == k - 2) { - ands[i].a <== eq[k - 1].out; - ands[i].b <== lt[k - 2].out; - eq_ands[i].a <== eq[k - 1].out; - eq_ands[i].b <== eq[k - 2].out; - ors[i].a <== lt[k - 1].out; - ors[i].b <== ands[i].out; - } else { - ands[i].a <== eq_ands[i + 1].out; - ands[i].b <== lt[i].out; - eq_ands[i].a <== eq_ands[i + 1].out; - eq_ands[i].b <== eq[i].out; - ors[i].a <== ors[i + 1].out; - ors[i].b <== ands[i].out; - } - } - out <== ors[0].out; -} - -template BigIsEqual(k){ - signal input in[2][k]; - signal output out; - component isEqual[k+1]; - var sum = 0; - for(var i = 0; i < k; i++){ - isEqual[i] = IsEqual(); - isEqual[i].in[0] <== in[0][i]; - isEqual[i].in[1] <== in[1][i]; - sum = sum + isEqual[i].out; - } - - isEqual[k] = IsEqual(); - isEqual[k].in[0] <== sum; - isEqual[k].in[1] <== k; - out <== isEqual[k].out; -} - -// leading register of b should be non-zero -template BigMod(n, k) { - assert(n <= 126); - signal input a[2 * k]; - signal input b[k]; - - signal output div[k + 1]; - signal output mod[k]; - - var longdiv[2][100] = long_div(n, k, k, a, b); - for (var i = 0; i < k; i++) { - div[i] <-- longdiv[0][i]; - mod[i] <-- longdiv[1][i]; - } - div[k] <-- longdiv[0][k]; - component range_checks[k + 1]; - for (var i = 0; i <= k; i++) { - range_checks[i] = Num2Bits(n); - range_checks[i].in <== div[i]; - } - - component mul = BigMult(n, k + 1); - for (var i = 0; i < k; i++) { - mul.a[i] <== div[i]; - mul.b[i] <== b[i]; - } - mul.a[k] <== div[k]; - mul.b[k] <== 0; - - component add = BigAdd(n, 2 * k + 2); - for (var i = 0; i < 2 * k; i++) { - add.a[i] <== mul.out[i]; - if (i < k) { - add.b[i] <== mod[i]; - } else { - add.b[i] <== 0; - } - } - add.a[2 * k] <== mul.out[2 * k]; - add.a[2 * k + 1] <== mul.out[2 * k + 1]; - add.b[2 * k] <== 0; - add.b[2 * k + 1] <== 0; - - for (var i = 0; i < 2 * k; i++) { - add.out[i] === a[i]; - } - add.out[2 * k] === 0; - add.out[2 * k + 1] === 0; - - component lt = BigLessThan(n, k); - for (var i = 0; i < k; i++) { - lt.a[i] <== mod[i]; - lt.b[i] <== b[i]; - } - lt.out === 1; -} - -// a[i], b[i] in 0... 2**n-1 -// represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k) -// assume a >= b -template BigSub(n, k) { - assert(n <= 252); - signal input a[k]; - signal input b[k]; - signal output out[k]; - signal output underflow; - - component unit0 = ModSub(n); - unit0.a <== a[0]; - unit0.b <== b[0]; - out[0] <== unit0.out; - - component unit[k - 1]; - for (var i = 1; i < k; i++) { - unit[i - 1] = ModSubThree(n); - unit[i - 1].a <== a[i]; - unit[i - 1].b <== b[i]; - if (i == 1) { - unit[i - 1].c <== unit0.borrow; - } else { - unit[i - 1].c <== unit[i - 2].borrow; - } - out[i] <== unit[i - 1].out; - } - underflow <== unit[k - 2].borrow; -} - -// calculates (a - b) % p, where a, b < p -// note: does not assume a >= b -template BigSubModP(n, k){ - assert(n <= 252); - signal input a[k]; - signal input b[k]; - signal input p[k]; - signal output out[k]; - component sub = BigSub(n, k); - for (var i = 0; i < k; i++){ - sub.a[i] <== a[i]; - sub.b[i] <== b[i]; - } - signal flag; - flag <== sub.underflow; - component add = BigAdd(n, k); - for (var i = 0; i < k; i++){ - add.a[i] <== sub.out[i]; - add.b[i] <== flag * p[i]; - } - for (var i = 0; i < k; i++){ - out[i] <== add.out[i]; - } -} - -template BigMultModP(n, k) { - assert(n <= 252); - signal input a[k]; - signal input b[k]; - signal input p[k]; - signal output out[k]; - - component big_mult = BigMult(n, k); - for (var i = 0; i < k; i++) { - big_mult.a[i] <== a[i]; - big_mult.b[i] <== b[i]; - } - component big_mod = BigMod(n, k); - for (var i = 0; i < 2 * k; i++) { - big_mod.a[i] <== big_mult.out[i]; - } - for (var i = 0; i < k; i++) { - big_mod.b[i] <== p[i]; - } - for (var i = 0; i < k; i++) { - out[i] <== big_mod.mod[i]; - } -} - -template BigModInv(n, k) { - assert(n <= 252); - signal input in[k]; - signal input p[k]; - signal output out[k]; - - // length k - var inv[100] = mod_inv(n, k, in, p); - for (var i = 0; i < k; i++) { - out[i] <-- inv[i]; - } - component range_checks[k]; - for (var i = 0; i < k; i++) { - range_checks[i] = Num2Bits(n); - range_checks[i].in <== out[i]; - } - - component mult = BigMult(n, k); - for (var i = 0; i < k; i++) { - mult.a[i] <== in[i]; - mult.b[i] <== out[i]; - } - component mod = BigMod(n, k); - for (var i = 0; i < 2 * k; i++) { - mod.a[i] <== mult.out[i]; - } - for (var i = 0; i < k; i++) { - mod.b[i] <== p[i]; - } - mod.mod[0] === 1; - for (var i = 1; i < k; i++) { - mod.mod[i] === 0; - } -} - -// in[i] contains values in the range -2^(m-1) to 2^(m-1) -// constrain that in[] as a big integer is zero -// each limbs is n bits -template CheckCarryToZero(n, m, k) { - assert(k >= 2); - - var EPSILON = 3; - - assert(m + EPSILON <= 253); - - signal input in[k]; - - signal carry[k]; - component carryRangeChecks[k]; - for (var i = 0; i < k-1; i++){ - carryRangeChecks[i] = Num2Bits(m + EPSILON - n); - if( i == 0 ){ - carry[i] <-- in[i] / (1< 10944121435919637611123202872628637544274182200208017171849102093287904247808 ? 1 : 0; -} - -function div_ceil(m, n) { - var ret = 0; - if (m % n == 0) { - ret = m \ n; - } else { - ret = m \ n + 1; - } - return ret; -} - -function log_ceil(n) { - var n_temp = n; - for (var i = 0; i < 254; i++) { - if (n_temp == 0) { - return i; - } - n_temp = n_temp \ 2; - } - return 254; -} - -function SplitFn(in, n, m) { - return [in % (1 << n), (in \ (1 << n)) % (1 << m)]; -} - -function SplitThreeFn(in, n, m, k) { - return [in % (1 << n), (in \ (1 << n)) % (1 << m), (in \ (1 << n + m)) % (1 << k)]; -} - -// m bits per overflowed register (values are potentially negative) -// n bits per properly-sized register -// in has k registers -// out has k + ceil(m/n) - 1 + 1 registers. highest-order potentially negative, -// all others are positive -// - 1 since the last register is included in the last ceil(m/n) array -// + 1 since the carries from previous registers could push you over -function getProperRepresentation(m, n, k, in) { - var ceilMN = div_ceil(m, n); - - var out[100]; // should be out[k + ceilMN] - assert(k + ceilMN < 100); - for (var i = 0; i < k; i++) { - out[i] = in[i]; - } - for (var i = k; i < 100; i++) { - out[i] = 0; - } - assert(n <= m); - for (var i = 0; i+1 < k + ceilMN; i++) { - assert((1 << m) >= out[i] && out[i] >= -(1 << m)); - var shifted_val = out[i] + (1 << m); - assert(0 <= shifted_val && shifted_val <= (1 << (m+1))); - out[i] = shifted_val & ((1 << n) - 1); - out[i+1] += (shifted_val >> n) - (1 << (m - n)); - } - - return out; -} - -// Evaluate polynomial a at point x -function poly_eval(len, a, x) { - var v = 0; - for (var i = 0; i < len; i++) { - v += a[i] * (x ** i); - } - return v; -} - -// Interpolate a degree len-1 polynomial given its evaluations at 0..len-1 -function poly_interp(len, v) { - assert(len <= 200); - var out[200]; - for (var i = 0; i < len; i++) { - out[i] = 0; - } - - // Product_{i=0..len-1} (x-i) - var full_poly[201]; - full_poly[0] = 1; - for (var i = 0; i < len; i++) { - full_poly[i+1] = 0; - for (var j = i; j >= 0; j--) { - full_poly[j+1] += full_poly[j]; - full_poly[j] *= -i; - } - } - - for (var i = 0; i < len; i++) { - var cur_v = 1; - for (var j = 0; j < len; j++) { - if (i == j) { - // do nothing - } else { - cur_v *= i-j; - } - } - cur_v = v[i] / cur_v; - - var cur_rem = full_poly[len]; - for (var j = len-1; j >= 0; j--) { - out[j] += cur_v * cur_rem; - cur_rem = full_poly[j] + i * cur_rem; - } - assert(cur_rem == 0); - } - - return out; -} - -// 1 if true, 0 if false -function long_gt(n, k, a, b) { - for (var i = k - 1; i >= 0; i--) { - if (a[i] > b[i]) { - return 1; - } - if (a[i] < b[i]) { - return 0; - } - } - return 0; -} - -// n bits per register -// a has k registers -// b has k registers -// a >= b -function long_sub(n, k, a, b) { - var diff[100]; - var borrow[100]; - for (var i = 0; i < k; i++) { - if (i == 0) { - if (a[i] >= b[i]) { - diff[i] = a[i] - b[i]; - borrow[i] = 0; - } else { - diff[i] = a[i] - b[i] + (1 << n); - borrow[i] = 1; - } - } else { - if (a[i] >= b[i] + borrow[i - 1]) { - diff[i] = a[i] - b[i] - borrow[i - 1]; - borrow[i] = 0; - } else { - diff[i] = (1 << n) + a[i] - b[i] - borrow[i - 1]; - borrow[i] = 1; - } - } - } - return diff; -} - -// a is a n-bit scalar -// b has k registers -function long_scalar_mult(n, k, a, b) { - var out[100]; - for (var i = 0; i < 100; i++) { - out[i] = 0; - } - for (var i = 0; i < k; i++) { - var temp = out[i] + (a * b[i]); - out[i] = temp % (1 << n); - out[i + 1] = out[i + 1] + temp \ (1 << n); - } - return out; -} - - -// n bits per register -// a has k + m registers -// b has k registers -// out[0] has length m + 1 -- quotient -// out[1] has length k -- remainder -// implements algorithm of https://people.eecs.berkeley.edu/~fateman/282/F%20Wright%20notes/week4.pdf -function long_div(n, k, m, a, b){ - var out[2][100]; - m += k; - while (b[k-1] == 0) { - out[1][k] = 0; - k--; - assert(k > 0); - } - m -= k; - - var remainder[200]; - for (var i = 0; i < m + k; i++) { - remainder[i] = a[i]; - } - - var mult[200]; - var dividend[200]; - for (var i = m; i >= 0; i--) { - if (i == m) { - dividend[k] = 0; - for (var j = k - 1; j >= 0; j--) { - dividend[j] = remainder[j + m]; - } - } else { - for (var j = k; j >= 0; j--) { - dividend[j] = remainder[j + i]; - } - } - - out[0][i] = short_div(n, k, dividend, b); - - var mult_shift[100] = long_scalar_mult(n, k, out[0][i], b); - var subtrahend[200]; - for (var j = 0; j < m + k; j++) { - subtrahend[j] = 0; - } - for (var j = 0; j <= k; j++) { - if (i + j < m + k) { - subtrahend[i + j] = mult_shift[j]; - } - } - remainder = long_sub(n, m + k, remainder, subtrahend); - } - for (var i = 0; i < k; i++) { - out[1][i] = remainder[i]; - } - out[1][k] = 0; - - return out; -} - -// n bits per register -// a has k + 1 registers -// b has k registers -// assumes leading digit of b is at least 2 ** (n - 1) -// 0 <= a < (2**n) * b -function short_div_norm(n, k, a, b) { - var qhat = (a[k] * (1 << n) + a[k - 1]) \ b[k - 1]; - if (qhat > (1 << n) - 1) { - qhat = (1 << n) - 1; - } - - var mult[100] = long_scalar_mult(n, k, qhat, b); - if (long_gt(n, k + 1, mult, a) == 1) { - mult = long_sub(n, k + 1, mult, b); - if (long_gt(n, k + 1, mult, a) == 1) { - return qhat - 2; - } else { - return qhat - 1; - } - } else { - return qhat; - } -} - -// n bits per register -// a has k + 1 registers -// b has k registers -// assumes leading digit of b is non-zero -// 0 <= a < (2**n) * b -function short_div(n, k, a, b) { - var scale = (1 << n) \ (1 + b[k - 1]); - - // k + 2 registers now - var norm_a[200] = long_scalar_mult(n, k + 1, scale, a); - // k + 1 registers now - var norm_b[200] = long_scalar_mult(n, k, scale, b); - - var ret; - if (norm_b[k] != 0) { - ret = short_div_norm(n, k + 1, norm_a, norm_b); - } else { - ret = short_div_norm(n, k, norm_a, norm_b); - } - return ret; -} - -// n bits per register -// a and b both have k registers -// out[0] has length 2 * k -// adapted from BigMulShortLong and LongToShortNoEndCarry2 witness computation -function prod(n, k, a, b) { - // first compute the intermediate values. taken from BigMulShortLong - var prod_val[100]; // length is 2 * k - 1 - for (var i = 0; i < 2 * k - 1; i++) { - prod_val[i] = 0; - if (i < k) { - for (var a_idx = 0; a_idx <= i; a_idx++) { - prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; - } - } else { - for (var a_idx = i - k + 1; a_idx < k; a_idx++) { - prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; - } - } - } - - // now do a bunch of carrying to make sure registers not overflowed. taken from LongToShortNoEndCarry2 - var out[100]; // length is 2 * k - - var split[100][3]; // first dimension has length 2 * k - 1 - for (var i = 0; i < 2 * k - 1; i++) { - split[i] = SplitThreeFn(prod_val[i], n, n, n); - } - - var carry[100]; // length is 2 * k - 1 - carry[0] = 0; - out[0] = split[0][0]; - if (2 * k - 1 > 1) { - var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], n, n); - out[1] = sumAndCarry[0]; - carry[1] = sumAndCarry[1]; - } - if (2 * k - 1 > 2) { - for (var i = 2; i < 2 * k - 1; i++) { - var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], n, n); - out[i] = sumAndCarry[0]; - carry[i] = sumAndCarry[1]; - } - out[2 * k - 1] = split[2*k-2][1] + split[2*k-3][2] + carry[2*k-2]; - } - return out; -} - -// n bits per register -// a has k registers -// p has k registers -// e has k registers -// k * n <= 500 -// p is a prime -// computes a^e mod p -function mod_exp(n, k, a, p, e) { - var eBits[500]; // length is k * n - for (var i = 0; i < k; i++) { - for (var j = 0; j < n; j++) { - eBits[j + n * i] = (e[i] >> j) & 1; - } - } - - var out[100]; // length is k - for (var i = 0; i < 100; i++) { - out[i] = 0; - } - out[0] = 1; - - // repeated squaring - for (var i = k * n - 1; i >= 0; i--) { - // multiply by a if bit is 0 - if (eBits[i] == 1) { - var temp[200]; // length 2 * k - temp = prod(n, k, out, a); - var temp2[2][100]; - temp2 = long_div(n, k, k, temp, p); - out = temp2[1]; - } - - // square, unless we're at the end - if (i > 0) { - var temp[200]; // length 2 * k - temp = prod(n, k, out, out); - var temp2[2][100]; - temp2 = long_div(n, k, k, temp, p); - out = temp2[1]; - } - - } - return out; -} - -// n bits per register -// a has k registers -// p has k registers -// k * n <= 500 -// p is a prime -// if a == 0 mod p, returns 0 -// else computes inv = a^(p-2) mod p -function mod_inv(n, k, a, p) { - var isZero = 1; - for (var i = 0; i < k; i++) { - if (a[i] != 0) { - isZero = 0; - } - } - if (isZero == 1) { - var ret[100]; - for (var i = 0; i < k; i++) { - ret[i] = 0; - } - return ret; - } - - var pCopy[100]; - for (var i = 0; i < 100; i++) { - if (i < k) { - pCopy[i] = p[i]; - } else { - pCopy[i] = 0; - } - } - - var two[100]; - for (var i = 0; i < 100; i++) { - two[i] = 0; - } - two[0] = 2; - - var pMinusTwo[100]; - pMinusTwo = long_sub(n, k, pCopy, two); // length k - var out[100]; - out = mod_exp(n, k, a, pCopy, pMinusTwo); - return out; -} - -// a, b and out are all n bits k registers -function long_sub_mod_p(n, k, a, b, p){ - var gt = long_gt(n, k, a, b); - var tmp[100]; - if(gt){ - tmp = long_sub(n, k, a, b); - } - else{ - tmp = long_sub(n, k, b, a); - } - var out[2][100]; - for(var i = k;i < 2 * k; i++){ - tmp[i] = 0; - } - out = long_div(n, k, k, tmp, p); - if(gt==0){ - tmp = long_sub(n, k, p, out[1]); - } - return tmp; -} - -// a, b, p and out are all n bits k registers -function prod_mod_p(n, k, a, b, p){ - var tmp[100]; - var result[2][100]; - tmp = prod(n, k, a, b); - result = long_div(n, k, k, tmp, p); - return result[1]; -} diff --git a/app/ios/mopro/mopro-core/examples/circom/rsa/fp.circom b/app/ios/mopro/mopro-core/examples/circom/rsa/fp.circom deleted file mode 100644 index 224625168..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/rsa/fp.circom +++ /dev/null @@ -1,144 +0,0 @@ -pragma circom 2.1.5; - -include "./node_modules/circomlib/circuits/bitify.circom"; -include "./node_modules/circomlib/circuits/comparators.circom"; -include "./node_modules/circomlib/circuits/sign.circom"; -include "./bigint.circom"; -include "./bigint_func.circom"; - -// These functions operate over values in Z/Zp for some integer p (typically, -// but not necessarily prime). Values are stored as standard bignums with k -// chunks of n bits, but intermediate values often have "overflow" bits inside -// various chunks. -// -// These Fp functions will always correctly generate witnesses mod p, but they -// do not *check* that values are normalized to < p; they only check that -// values are correct mod p. This is to save the comparison circuit. -// They *will* always check for intended results mod p (soundness), but it may -// not have a unique intermediate signal. -// -// Conversely, some templates may not be satisfiable if the input witnesses are -// not < p. This does not break completeness, as honest provers will always -// generate witnesses which are canonical (between 0 and p). - -// a * b = r mod p -// a * b - p * q - r for some q -template FpMul(n, k) { - assert(n + n + log_ceil(k) + 2 <= 252); - signal input a[k]; - signal input b[k]; - signal input p[k]; - - signal output out[k]; - - signal v_ab[2*k-1]; - for (var x = 0; x < 2*k-1; x++) { - var v_a = poly_eval(k, a, x); - var v_b = poly_eval(k, b, x); - v_ab[x] <== v_a * v_b; - } - - var ab[200] = poly_interp(2*k-1, v_ab); - // ab_proper has length 2*k - var ab_proper[200] = getProperRepresentation(n + n + log_ceil(k), n, 2*k-1, ab); - - var long_div_out[2][100] = long_div(n, k, k, ab_proper, p); - - // Since we're only computing a*b, we know that q < p will suffice, so we - // know it fits into k chunks and can do size n range checks. - signal q[k]; - component q_range_check[k]; - signal r[k]; - component r_range_check[k]; - for (var i = 0; i < k; i++) { - q[i] <-- long_div_out[0][i]; - q_range_check[i] = Num2Bits(n); - q_range_check[i].in <== q[i]; - - r[i] <-- long_div_out[1][i]; - r_range_check[i] = Num2Bits(n); - r_range_check[i].in <== r[i]; - } - - signal v_pq_r[2*k-1]; - for (var x = 0; x < 2*k-1; x++) { - var v_p = poly_eval(k, p, x); - var v_q = poly_eval(k, q, x); - var v_r = poly_eval(k, r, x); - v_pq_r[x] <== v_p * v_q + v_r; - } - - signal v_t[2*k-1]; - for (var x = 0; x < 2*k-1; x++) { - v_t[x] <== v_ab[x] - v_pq_r[x]; - } - - var t[200] = poly_interp(2*k-1, v_t); - component tCheck = CheckCarryToZero(n, n + n + log_ceil(k) + 2, 2*k-1); - for (var i = 0; i < 2*k-1; i++) { - tCheck.in[i] <== t[i]; - } - - for (var i = 0; i < k; i++) { - out[i] <== r[i]; - } -} - -// Lifted from https://sourcegraph.com/github.com/darkforest-eth/circuits/-/blob/range_proof/circuit.circom -// NB: RangeProof is inclusive. -// input: field element, whose abs is claimed to be less than max_abs_value -// output: none -// we also want something like 4 * (abs(in) + max_abs_value) < 2 ** bits -// and bits << 256 -// NB: RangeProof is inclusive. -// input: field element, whose abs is claimed to be <= than max_abs_value -// output: none -// also checks that both max and abs(in) are expressible in `bits` bits -template RangeProof(bits) { - signal input in; - signal input max_abs_value; - - /* check that both max and abs(in) are expressible in `bits` bits */ - component n2b1 = Num2Bits(bits+1); - n2b1.in <== in + (1 << bits); - component n2b2 = Num2Bits(bits); - n2b2.in <== max_abs_value; - - /* check that in + max is between 0 and 2*max */ - component lowerBound = LessThan(bits+1); - component upperBound = LessThan(bits+1); - - lowerBound.in[0] <== max_abs_value + in; - lowerBound.in[1] <== 0; - lowerBound.out === 0; - - upperBound.in[0] <== 2 * max_abs_value; - upperBound.in[1] <== max_abs_value + in; - upperBound.out === 0; -} - -// input: n field elements, whose abs are claimed to be less than max_abs_value -// output: none -template MultiRangeProof(n, bits) { - signal input in[n]; - signal input max_abs_value; - component rangeProofs[n]; - - for (var i = 0; i < n; i++) { - rangeProofs[i] = RangeProof(bits); - rangeProofs[i].in <== in[i]; - rangeProofs[i].max_abs_value <== max_abs_value; - } -} - -template IsNegative(){ - signal input in; - signal output out; - component n2b = Num2Bits(254); - component sign = Sign(); - in ==> n2b.in; - for (var i = 0; i<254; i++) { - n2b.out[i] ==> sign.in[i]; - } - sign.sign ==> out; -} diff --git a/app/ios/mopro/mopro-core/examples/circom/rsa/main.circom b/app/ios/mopro/mopro-core/examples/circom/rsa/main.circom deleted file mode 100644 index c612ef873..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/rsa/main.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.5; - -include "./rsa.circom"; - -component main{public [modulus]} = RSAVerify65537(64, 32); diff --git a/app/ios/mopro/mopro-core/examples/circom/rsa/package-lock.json b/app/ios/mopro/mopro-core/examples/circom/rsa/package-lock.json deleted file mode 100644 index 123c85535..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/rsa/package-lock.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "circom", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "circom", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "circomlib": "^2.0.5" - } - }, - "node_modules/circomlib": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/circomlib/-/circomlib-2.0.5.tgz", - "integrity": "sha512-O7NQ8OS+J4eshBuoy36z/TwQU0YHw8W3zxZcs4hVwpEll3e4hDm3mgkIPqItN8FDeLEKZFK3YeT/+k8TiLF3/A==" - } - } -} diff --git a/app/ios/mopro/mopro-core/examples/circom/rsa/rsa.circom b/app/ios/mopro/mopro-core/examples/circom/rsa/rsa.circom deleted file mode 100644 index 64fda6719..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/rsa/rsa.circom +++ /dev/null @@ -1,156 +0,0 @@ -pragma circom 2.1.5; - -include "./fp.circom"; - -// Computes base^65537 mod modulus -// Does not necessarily reduce fully mod modulus (the answer could be -// too big by a multiple of modulus) -template FpPow65537Mod(n, k) { - signal input base[k]; - // Exponent is hardcoded at 65537 - signal input modulus[k]; - signal output out[k]; - - component doublers[16]; - component adder = FpMul(n, k); - for (var i = 0; i < 16; i++) { - doublers[i] = FpMul(n, k); - } - - for (var j = 0; j < k; j++) { - adder.p[j] <== modulus[j]; - for (var i = 0; i < 16; i++) { - doublers[i].p[j] <== modulus[j]; - } - } - for (var j = 0; j < k; j++) { - doublers[0].a[j] <== base[j]; - doublers[0].b[j] <== base[j]; - } - for (var i = 0; i + 1 < 16; i++) { - for (var j = 0; j < k; j++) { - doublers[i + 1].a[j] <== doublers[i].out[j]; - doublers[i + 1].b[j] <== doublers[i].out[j]; - } - } - for (var j = 0; j < k; j++) { - adder.a[j] <== base[j]; - adder.b[j] <== doublers[15].out[j]; - } - for (var j = 0; j < k; j++) { - out[j] <== adder.out[j]; - } -} - -template RSAPad(n, k) { - signal input modulus[k]; - signal input base_message[k]; - signal output padded_message[k]; - - var base_len = 280; - var msg_len = 160; - - signal padded_message_bits[n*k]; - - component modulus_n2b[k]; - component base_message_n2b[k]; - signal modulus_bits[n*k]; - signal base_message_bits[n*k]; - for (var i = 0; i < k; i++) { - base_message_n2b[i] = Num2Bits(n); - base_message_n2b[i].in <== base_message[i]; - for (var j = 0; j < n; j++) { - base_message_bits[i*n+j] <== base_message_n2b[i].out[j]; - } - modulus_n2b[i] = Num2Bits(n); - modulus_n2b[i].in <== modulus[i]; - for (var j = 0; j < n; j++) { - modulus_bits[i*n+j] <== modulus_n2b[i].out[j]; - } - } - - for (var i = msg_len; i < n*k; i++) { - base_message_bits[i] === 0; - } - - for (var i = 0; i < msg_len; i++) { - padded_message_bits[i] <== base_message_bits[i]; - } - - for (var i = base_len; i < base_len + 8; i++) { - padded_message_bits[i] <== 0; - } - - for (var i = msg_len; i < base_len; i++) { - padded_message_bits[i] <== (0x3021300906052b0e03021a05000414 >> (i - msg_len)) & 1; - } - - component modulus_zero[(n*k + 7 - (base_len + 8))\8]; - { - var modulus_prefix = 0; - for (var i = n*k - 1; i >= base_len + 8; i--) { - if (i+8 < n*k) { - modulus_prefix += modulus_bits[i+8]; - if (i % 8 == 0) { - var idx = (i - (base_len + 8)) / 8; - modulus_zero[idx] = IsZero(); - modulus_zero[idx].in <== modulus_prefix; - padded_message_bits[i] <== 1-modulus_zero[idx].out; - } else { - padded_message_bits[i] <== padded_message_bits[i+1]; - } - } else { - padded_message_bits[i] <== 0; - } - } - } - - // The RFC guarantees at least 8 octets of 0xff padding. - assert(base_len + 8 + 65 <= n*k); - for (var i = base_len + 8; i < base_len + 8 + 65; i++) { - padded_message_bits[i] === 1; - } - - component padded_message_b2n[k]; - for (var i = 0; i < k; i++) { - padded_message_b2n[i] = Bits2Num(n); - for (var j = 0; j < n; j++) { - padded_message_b2n[i].in[j] <== padded_message_bits[i*n+j]; - } - padded_message[i] <== padded_message_b2n[i].out; - } -} - -template RSAVerify65537(n, k) { - signal input signature[k]; - signal input modulus[k]; - signal input base_message[k]; - - component padder = RSAPad(n, k); - for (var i = 0; i < k; i++) { - padder.modulus[i] <== modulus[i]; - padder.base_message[i] <== base_message[i]; - } - - // Check that the signature is in proper form and reduced mod modulus. - component signatureRangeCheck[k]; - component bigLessThan = BigLessThan(n, k); - for (var i = 0; i < k; i++) { - signatureRangeCheck[i] = Num2Bits(n); - signatureRangeCheck[i].in <== signature[i]; - bigLessThan.a[i] <== signature[i]; - bigLessThan.b[i] <== modulus[i]; - } - bigLessThan.out === 1; - - component bigPow = FpPow65537Mod(n, k); - for (var i = 0; i < k; i++) { - bigPow.base[i] <== signature[i]; - bigPow.modulus[i] <== modulus[i]; - } - // By construction of the padding, the padded message is necessarily - // smaller than the modulus. Thus, we don't have to check that bigPow is fully reduced. - for (var i = 0; i < k; i++) { - bigPow.out[i] === padder.padded_message[i]; - } -} diff --git a/app/ios/mopro/mopro-core/examples/circom/scripts/compile.sh b/app/ios/mopro/mopro-core/examples/circom/scripts/compile.sh deleted file mode 100755 index 8d8dd82be..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/scripts/compile.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# Example usage: -# ./scripts/compile.sh multiplier2 multiplier2.circom - -# Deal with errors -set -euo pipefail - -# Check if arguments are provided -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " - exit 1 -fi - -DIR="$1" -CIRCUIT="$2" - -mkdir -p ${DIR}/target -circom ./${DIR}/${CIRCUIT} --r1cs --wasm --sym --output ./${DIR}/target \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/examples/circom/scripts/generate_arkzkey.sh b/app/ios/mopro/mopro-core/examples/circom/scripts/generate_arkzkey.sh deleted file mode 100755 index d80db52f8..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/scripts/generate_arkzkey.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# Example usage: -# ./scripts/generate_arkzkey.sh multiplier2 multiplier2 - -# Assumes inside target directory - -# Deal with errors -set -euo pipefail - -# Check if arguments are provided -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " - exit 1 -fi - -DIR="$1" -CIRCUIT="$2" -ZKEY_PATH="${DIR}/target/${CIRCUIT}_final.zkey" -ARKZKEY_PATH="${DIR}/target/${CIRCUIT}_final.arkzkey" - -# Check if ZKEY_PATH exists -if [ ! -f "$ZKEY_PATH" ]; then - echo "Error: ZKEY_PATH does not exist at ${ZKEY_PATH}" - exit 1 -fi - -# Check if arkzkey-util command exists -if ! command -v arkzkey-util &> /dev/null; then - echo "Error: arkzkey-util command is not available." - exit 1 -fi - -echo "Generate arkzkey file for ${CIRCUIT}..." -if [ ! -f "${ARKZKEY_PATH}" ]; then - arkzkey-util ${ZKEY_PATH} -else - echo "File ${ARKZKEY_PATH} already exists, skipping." -fi - -echo "arkzkey file generation done, arkzkey file is in ${ARKZKEY_PATH}" \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/examples/circom/scripts/trusted_setup.sh b/app/ios/mopro/mopro-core/examples/circom/scripts/trusted_setup.sh deleted file mode 100755 index 312e43675..000000000 --- a/app/ios/mopro/mopro-core/examples/circom/scripts/trusted_setup.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -# Example usage: -# ./scripts/trusted_setup.sh multiplier2 08 multiplier2 - -# Deal with errors -set -euo pipefail - -# Change this is if you keep your Powers of Tau files elsewhere -PTAU_DIR="ptau" - -# Check if arguments are provided -if [ "$#" -ne 3 ]; then - echo "Usage: $0 " - exit 1 -fi - -DIR="$1" -PTAU="$2" -CIRCUIT="$3" -PTAU_PATH="${PTAU_DIR}/powersOfTau28_hez_final_${PTAU}.ptau" - -# Phase 1 - Perpetual Powers of Tau -# From https://github.com/iden3/snarkjs - -if [ ! -f "$PTAU_PATH" ]; then - echo "Downloading Powers of Tau file..." - wget -P $PTAU_DIR https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_${PTAU}.ptau -else - echo "File $PTAU_PATH already exists, skipping download." -fi - -# Phase 2 - Circuit specific setup -# Toy example, not for production use -# For a real deployment with Groth16 use a tool like p0tion for phase 2 trusted setup -# See https://github.com/privacy-scaling-explorations/p0tion - -echo "Generate zkey file for ${CIRCUIT}..." -if [ ! -f "${DIR}/target/${CIRCUIT}_final.zkey" ]; then - snarkjs groth16 setup ${DIR}/target/${CIRCUIT}.r1cs ${PTAU_PATH} ${DIR}/target/${CIRCUIT}_0000.zkey - snarkjs zkey contribute ${DIR}/target/${CIRCUIT}_0000.zkey ${DIR}/target/${CIRCUIT}_final.zkey \ - --name="Demo contribution" -e="0xdeadbeef" -else - echo "File ${DIR}/target/${CIRCUIT}_final.zkey already exists, skipping." -fi - -echo "Trusted setup done, zkey file is in ${DIR}/target/${CIRCUIT}_final.zkey" \ No newline at end of file diff --git a/app/ios/mopro/mopro-core/src/lib.rs b/app/ios/mopro/mopro-core/src/lib.rs deleted file mode 100644 index 2ac7b546f..000000000 --- a/app/ios/mopro/mopro-core/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod middleware; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum MoproError { - #[error("CircomError: {0}")] - CircomError(String), -} diff --git a/app/ios/mopro/mopro-core/src/middleware/circom/mod.rs b/app/ios/mopro/mopro-core/src/middleware/circom/mod.rs deleted file mode 100644 index 0cf497fc9..000000000 --- a/app/ios/mopro/mopro-core/src/middleware/circom/mod.rs +++ /dev/null @@ -1,860 +0,0 @@ -use self::{ - serialization::{SerializableInputs, SerializableProof, SerializableProvingKey}, - utils::{assert_paths_exists, bytes_to_bits}, -}; -use crate::MoproError; - -use std::collections::HashMap; -//use std::io::Cursor; -use std::sync::Mutex; -use std::time::Instant; - -use ark_bn254::{Bn254, Fr}; -use ark_circom::{ - CircomBuilder, - CircomCircuit, - CircomConfig, - CircomReduction, - WitnessCalculator, //read_zkey, -}; -use ark_crypto_primitives::snark::SNARK; -use ark_groth16::{prepare_verifying_key, Groth16, ProvingKey}; -use ark_std::UniformRand; - -use ark_relations::r1cs::ConstraintMatrices; -use ark_std::rand::thread_rng; -use color_eyre::Result; -use core::include_bytes; -use num_bigint::BigInt; -use once_cell::sync::{Lazy, OnceCell}; - -use wasmer::{Module, Store}; - -use ark_zkey::read_arkzkey_from_bytes; //SerializableConstraintMatrices - -#[cfg(feature = "dylib")] -use { - std::{env, path::Path}, - wasmer::Dylib, -}; - -pub mod serialization; -pub mod utils; - -type GrothBn = Groth16; - -type CircuitInputs = HashMap>; - -// TODO: Split up this namespace a bit, right now quite a lot of things going on - -pub struct CircomState { - builder: Option>, - circuit: Option>, - params: Option>, -} - -impl Default for CircomState { - fn default() -> Self { - Self::new() - } -} - -// NOTE: A lot of the contents of this file is inspired by github.com/worldcoin/semaphore-rs - -// TODO: Replace printlns with logging - -//const ZKEY_BYTES: &[u8] = include_bytes!(env!("BUILD_RS_ZKEY_FILE")); - -const ARKZKEY_BYTES: &[u8] = include_bytes!(env!("BUILD_RS_ARKZKEY_FILE")); - -// static ZKEY: Lazy<(ProvingKey, ConstraintMatrices)> = Lazy::new(|| { -// let mut reader = Cursor::new(ZKEY_BYTES); -// read_zkey(&mut reader).expect("Failed to read zkey") -// }); - -static ARKZKEY: Lazy<(ProvingKey, ConstraintMatrices)> = Lazy::new(|| { - //let mut reader = Cursor::new(ARKZKEY_BYTES); - // TODO: Use reader? More flexible; unclear if perf diff - read_arkzkey_from_bytes(ARKZKEY_BYTES).expect("Failed to read arkzkey") -}); - -const WASM: &[u8] = include_bytes!(env!("BUILD_RS_WASM_FILE")); - -/// `WITNESS_CALCULATOR` is a lazily initialized, thread-safe singleton of type `WitnessCalculator`. -/// `OnceCell` ensures that the initialization occurs exactly once, and `Mutex` allows safe shared -/// access from multiple threads. -static WITNESS_CALCULATOR: OnceCell> = OnceCell::new(); - -/// Initializes the `WITNESS_CALCULATOR` singleton with a `WitnessCalculator` instance created from -/// a specified dylib file (WASM circuit). Also initialize `ZKEY`. -#[cfg(feature = "dylib")] -pub fn initialize(dylib_path: &Path) { - println!("Initializing dylib: {:?}", dylib_path); - - WITNESS_CALCULATOR - .set(from_dylib(dylib_path)) - .expect("Failed to set WITNESS_CALCULATOR"); - - // Initialize ARKZKEY - // TODO: Speed this up even more - let now = std::time::Instant::now(); - Lazy::force(&ARKZKEY); - println!("Initializing arkzkey took: {:.2?}", now.elapsed()); -} - -#[cfg(not(feature = "dylib"))] -pub fn initialize() { - println!("Initializing library with arkzkey"); - - // Initialize ARKZKEY - // TODO: Speed this up even more! - let now = std::time::Instant::now(); - Lazy::force(&ARKZKEY); - println!("Initializing arkzkey took: {:.2?}", now.elapsed()); -} - -/// Creates a `WitnessCalculator` instance from a dylib file. -#[cfg(feature = "dylib")] -fn from_dylib(path: &Path) -> Mutex { - let store = Store::new(&Dylib::headless().engine()); - let module = unsafe { - Module::deserialize_from_file(&store, path).expect("Failed to load dylib module") - }; - let result = - WitnessCalculator::from_module(module).expect("Failed to create WitnessCalculator"); - - Mutex::new(result) -} - -// #[must_use] -// pub fn zkey() -> &'static (ProvingKey, ConstraintMatrices) { -// &ZKEY -// } - -// Experimental -#[must_use] -pub fn arkzkey() -> &'static (ProvingKey, ConstraintMatrices) { - &ARKZKEY -} - -/// Provides access to the `WITNESS_CALCULATOR` singleton, initializing it if necessary. -/// It expects the path to the dylib file to be set in the `CIRCUIT_WASM_DYLIB` environment variable. -#[cfg(feature = "dylib")] -#[must_use] -pub fn witness_calculator() -> &'static Mutex { - let var_name = "CIRCUIT_WASM_DYLIB"; - - WITNESS_CALCULATOR.get_or_init(|| { - let path = env::var(var_name).unwrap_or_else(|_| { - panic!( - "Mopro circuit WASM Dylib not initialized. \ - Please set {} environment variable to the path of the dylib file", - var_name - ) - }); - from_dylib(Path::new(&path)) - }) -} - -#[cfg(not(feature = "dylib"))] -#[must_use] -pub fn witness_calculator() -> &'static Mutex { - WITNESS_CALCULATOR.get_or_init(|| { - let store = Store::default(); - let module = Module::from_binary(&store, WASM).expect("WASM should be valid"); - let result = - WitnessCalculator::from_module(module).expect("Failed to create WitnessCalculator"); - Mutex::new(result) - }) -} - -pub fn generate_proof2( - inputs: CircuitInputs, -) -> Result<(SerializableProof, SerializableInputs), MoproError> { - let mut rng = thread_rng(); - let rng = &mut rng; - - let r = ark_bn254::Fr::rand(rng); - let s = ark_bn254::Fr::rand(rng); - - println!("Generating proof 2"); - - let now = std::time::Instant::now(); - let full_assignment = witness_calculator() - .lock() - .expect("Failed to lock witness calculator") - .calculate_witness_element::(inputs, false) - .map_err(|e| MoproError::CircomError(e.to_string()))?; - - println!("Witness generation took: {:.2?}", now.elapsed()); - - let now = std::time::Instant::now(); - //let zkey = zkey(); - let zkey = arkzkey(); - println!("Loading arkzkey took: {:.2?}", now.elapsed()); - - let public_inputs = full_assignment.as_slice()[1..zkey.1.num_instance_variables].to_vec(); - - let now = std::time::Instant::now(); - let ark_proof = Groth16::<_, CircomReduction>::create_proof_with_reduction_and_matrices( - &zkey.0, - r, - s, - &zkey.1, - zkey.1.num_instance_variables, - zkey.1.num_constraints, - full_assignment.as_slice(), - ); - - let proof = ark_proof.map_err(|e| MoproError::CircomError(e.to_string()))?; - - println!("proof generation took: {:.2?}", now.elapsed()); - - // TODO: Add SerializableInputs(inputs))) - Ok((SerializableProof(proof), SerializableInputs(public_inputs))) -} - -pub fn verify_proof2( - serialized_proof: SerializableProof, - serialized_inputs: SerializableInputs, -) -> Result { - let start = Instant::now(); - let zkey = arkzkey(); - let pvk = prepare_verifying_key(&zkey.0.vk); - - let proof_verified = - GrothBn::verify_with_processed_vk(&pvk, &serialized_inputs.0, &serialized_proof.0) - .map_err(|e| MoproError::CircomError(e.to_string()))?; - - let verification_duration = start.elapsed(); - println!("Verification time 2: {:?}", verification_duration); - Ok(proof_verified) -} - -impl CircomState { - pub fn new() -> Self { - Self { - builder: None, - circuit: None, - params: None, - } - } - - pub fn setup( - &mut self, - wasm_path: &str, - r1cs_path: &str, - ) -> Result { - assert_paths_exists(wasm_path, r1cs_path)?; - println!("Setup"); - let start = Instant::now(); - - // Load the WASM and R1CS for witness and proof generation - let cfg = self.load_config(wasm_path, r1cs_path)?; - - // Create an empty instance for setup - self.builder = Some(CircomBuilder::new(cfg)); - - // Run a trusted setup using the rng in the state - let params = self.run_trusted_setup()?; - - self.params = Some(params.clone()); - - let setup_duration = start.elapsed(); - println!("Setup time: {:?}", setup_duration); - - Ok(SerializableProvingKey(params)) - } - - // NOTE: Consider generate_proof> API - // XXX: BigInt might present problems for UniFFI - pub fn generate_proof( - &mut self, - inputs: CircuitInputs, - ) -> Result<(SerializableProof, SerializableInputs), MoproError> { - let start = Instant::now(); - println!("Generating proof"); - - let mut rng = thread_rng(); - - let builder = self.builder.as_mut().ok_or(MoproError::CircomError( - "Builder has not been set up".to_string(), - ))?; - - // Insert our inputs as key value pairs - for (key, values) in &inputs { - for value in values { - builder.push_input(&key, value.clone()); - } - } - - // Clone the builder, then build the circuit - let circom = builder - .clone() - .build() - .map_err(|e| MoproError::CircomError(e.to_string()))?; - - // Update the circuit in self - self.circuit = Some(circom.clone()); - - let params = self.params.as_ref().ok_or(MoproError::CircomError( - "Parameters have not been set up".to_string(), - ))?; - - let inputs = circom.get_public_inputs().ok_or(MoproError::CircomError( - "Failed to get public inputs".to_string(), - ))?; - - let proof = GrothBn::prove(params, circom.clone(), &mut rng) - .map_err(|e| MoproError::CircomError(e.to_string()))?; - - let proof_duration = start.elapsed(); - println!("Proof generation time: {:?}", proof_duration); - - Ok((SerializableProof(proof), SerializableInputs(inputs))) - } - - pub fn verify_proof( - &self, - serialized_proof: SerializableProof, - serialized_inputs: SerializableInputs, - ) -> Result { - let start = Instant::now(); - - println!("Verifying proof"); - - let params = self.params.as_ref().ok_or(MoproError::CircomError( - "Parameters have not been set up".to_string(), - ))?; - - let pvk = - GrothBn::process_vk(¶ms.vk).map_err(|e| MoproError::CircomError(e.to_string()))?; - - let proof_verified = - GrothBn::verify_with_processed_vk(&pvk, &serialized_inputs.0, &serialized_proof.0) - .map_err(|e| MoproError::CircomError(e.to_string()))?; - - let verification_duration = start.elapsed(); - println!("Verification time: {:?}", verification_duration); - Ok(proof_verified) - } - - fn load_config( - &self, - wasm_path: &str, - r1cs_path: &str, - ) -> Result, MoproError> { - CircomConfig::::new(wasm_path, r1cs_path) - .map_err(|e| MoproError::CircomError(e.to_string())) - } - - fn run_trusted_setup(&mut self) -> Result, MoproError> { - let circom_setup = self - .builder - .as_mut() - .ok_or(MoproError::CircomError( - "Builder has not been set up".to_string(), - ))? - .setup(); - - let mut rng = thread_rng(); - - GrothBn::generate_random_parameters_with_reduction(circom_setup, &mut rng) - .map_err(|e| MoproError::CircomError(e.to_string())) - } -} - -// Helper function for Keccak256 example -pub fn bytes_to_circuit_inputs(bytes: &[u8]) -> CircuitInputs { - let bits = bytes_to_bits(bytes); - let big_int_bits = bits - .into_iter() - .map(|bit| BigInt::from(bit as u8)) - .collect(); - let mut inputs = HashMap::new(); - inputs.insert("in".to_string(), big_int_bits); - inputs -} - -pub fn strings_to_circuit_inputs(strings: &[&str]) -> Vec { - strings - .iter() - .map(|&value| BigInt::parse_bytes(value.as_bytes(), 10).unwrap()) - .collect() -} - -pub fn bytes_to_circuit_outputs(bytes: &[u8]) -> SerializableInputs { - let bits = bytes_to_bits(bytes); - let field_bits = bits.into_iter().map(|bit| Fr::from(bit as u8)).collect(); - SerializableInputs(field_bits) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_setup_prove_verify_simple() { - let wasm_path = "./examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"; - let r1cs_path = "./examples/circom/multiplier2/target/multiplier2.r1cs"; - - // Instantiate CircomState - let mut circom_state = CircomState::new(); - - // Setup - let setup_res = circom_state.setup(wasm_path, r1cs_path); - assert!(setup_res.is_ok()); - - let _serialized_pk = setup_res.unwrap(); - - // Deserialize the proving key and inputs if necessary - - // Prepare inputs - let mut inputs = HashMap::new(); - let a = 3; - let b = 5; - let c = a * b; - inputs.insert("a".to_string(), vec![BigInt::from(a)]); - inputs.insert("b".to_string(), vec![BigInt::from(b)]); - // output = [public output c, public input a] - let expected_output = vec![Fr::from(c), Fr::from(a)]; - let serialized_outputs = SerializableInputs(expected_output); - - // Proof generation - let generate_proof_res = circom_state.generate_proof(inputs); - - // Check and print the error if there is one - if let Err(e) = &generate_proof_res { - println!("Error: {:?}", e); - } - - assert!(generate_proof_res.is_ok()); - - let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); - - // Check output - assert_eq!(serialized_inputs, serialized_outputs); - - // Proof verification - let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs); - assert!(verify_res.is_ok()); - assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified - } - - #[test] - fn test_setup_prove_verify_keccak() { - let wasm_path = - "./examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm"; - let r1cs_path = "./examples/circom/keccak256/target/keccak256_256_test.r1cs"; - - // Instantiate CircomState - let mut circom_state = CircomState::new(); - - // Setup - let setup_res = circom_state.setup(wasm_path, r1cs_path); - assert!(setup_res.is_ok()); - - let _serialized_pk = setup_res.unwrap(); - - // Deserialize the proving key and inputs if necessary - - // Prepare inputs - let input_vec = vec![ - 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, - ]; - - // Expected output - let expected_output_vec = vec![ - 37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, - 212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, - ]; - - let inputs = bytes_to_circuit_inputs(&input_vec); - let serialized_outputs = bytes_to_circuit_outputs(&expected_output_vec); - - // Proof generation - let generate_proof_res = circom_state.generate_proof(inputs); - - // Check and print the error if there is one - if let Err(e) = &generate_proof_res { - println!("Error: {:?}", e); - } - - assert!(generate_proof_res.is_ok()); - - let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); - - // Check output - assert_eq!(serialized_inputs, serialized_outputs); - - // Proof verification - let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs); - assert!(verify_res.is_ok()); - - assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified - } - - #[test] - fn test_setup_error() { - // Arrange: Create a new CircomState instance - let mut circom_state = CircomState::new(); - - let wasm_path = "badpath/multiplier2.wasm"; - let r1cs_path = "badpath/multiplier2.r1cs"; - - // Act: Call the setup method - let result = circom_state.setup(wasm_path, r1cs_path); - - // Assert: Check that the method returns an error - assert!(result.is_err()); - } - - #[cfg(feature = "dylib")] - #[test] - fn test_dylib_init_and_generate_witness() { - // Assumes that the dylib file has been built and is in the following location - let dylib_path = "target/debug/aarch64-apple-darwin/keccak256.dylib"; - - // Initialize libray - initialize(Path::new(&dylib_path)); - - let input_vec = vec![ - 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 inputs = bytes_to_circuit_inputs(&input_vec); - let now = std::time::Instant::now(); - let full_assignment = witness_calculator() - .lock() - .expect("Failed to lock witness calculator") - .calculate_witness_element::(inputs, false) - .map_err(|e| MoproError::CircomError(e.to_string())); - - println!("Witness generation took: {:.2?}", now.elapsed()); - - assert!(full_assignment.is_ok()); - } - - #[test] - fn test_generate_proof2() { - // XXX: This can be done better - #[cfg(feature = "dylib")] - { - // Assumes that the dylib file has been built and is in the following location - let dylib_path = "target/debug/aarch64-apple-darwin/keccak256.dylib"; - - // Initialize libray - initialize(Path::new(&dylib_path)); - } - - let input_vec = vec![ - 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 expected_output_vec = vec![ - 37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, - 212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, - ]; - let inputs = bytes_to_circuit_inputs(&input_vec); - let serialized_outputs = bytes_to_circuit_outputs(&expected_output_vec); - - let generate_proof_res = generate_proof2(inputs); - let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); - assert_eq!(serialized_inputs, serialized_outputs); - - // Proof verification - let verify_res = verify_proof2(serialized_proof, serialized_inputs); - assert!(verify_res.is_ok()); - assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified - } - - #[ignore = "ignore for ci"] - #[test] - fn test_setup_prove_rsa() { - let wasm_path = "./examples/circom/rsa/target/main_js/main.wasm"; - let r1cs_path = "./examples/circom/rsa/target/main.r1cs"; - - // Instantiate CircomState - let mut circom_state = CircomState::new(); - - // Setup - let setup_res = circom_state.setup(wasm_path, r1cs_path); - assert!(setup_res.is_ok()); - - let _serialized_pk = setup_res.unwrap(); - - // Deserialize the proving key and inputs if necessary - - // Prepare inputs - let signature = [ - "3582320600048169363", - "7163546589759624213", - "18262551396327275695", - "4479772254206047016", - "1970274621151677644", - "6547632513799968987", - "921117808165172908", - "7155116889028933260", - "16769940396381196125", - "17141182191056257954", - "4376997046052607007", - "17471823348423771450", - "16282311012391954891", - "70286524413490741", - "1588836847166444745", - "15693430141227594668", - "13832254169115286697", - "15936550641925323613", - "323842208142565220", - "6558662646882345749", - "15268061661646212265", - "14962976685717212593", - "15773505053543368901", - "9586594741348111792", - "1455720481014374292", - "13945813312010515080", - "6352059456732816887", - "17556873002865047035", - "2412591065060484384", - "11512123092407778330", - "8499281165724578877", - "12768005853882726493", - ]; - let modulus = [ - "13792647154200341559", - "12773492180790982043", - "13046321649363433702", - "10174370803876824128", - "7282572246071034406", - "1524365412687682781", - "4900829043004737418", - "6195884386932410966", - "13554217876979843574", - "17902692039595931737", - "12433028734895890975", - "15971442058448435996", - "4591894758077129763", - "11258250015882429548", - "16399550288873254981", - "8246389845141771315", - "14040203746442788850", - "7283856864330834987", - "12297563098718697441", - "13560928146585163504", - "7380926829734048483", - "14591299561622291080", - "8439722381984777599", - "17375431987296514829", - "16727607878674407272", - "3233954801381564296", - "17255435698225160983", - "15093748890170255670", - "15810389980847260072", - "11120056430439037392", - "5866130971823719482", - "13327552690270163501", - ]; - let base_message = [ - "18114495772705111902", - "2254271930739856077", - "2068851770", - "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", - "0", - ]; - - let mut inputs: HashMap> = HashMap::new(); - inputs.insert( - "signature".to_string(), - strings_to_circuit_inputs(&signature), - ); - inputs.insert("modulus".to_string(), strings_to_circuit_inputs(&modulus)); - inputs.insert( - "base_message".to_string(), - strings_to_circuit_inputs(&base_message), - ); - - // Proof generation - let generate_proof_res = circom_state.generate_proof(inputs); - - // Check and print the error if there is one - if let Err(e) = &generate_proof_res { - println!("Error: {:?}", e); - } - - assert!(generate_proof_res.is_ok()); - - let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); - - // Proof verification - let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs); - assert!(verify_res.is_ok()); - - assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified - } - - #[ignore = "ignore for ci"] - #[test] - fn test_setup_prove_rsa2() { - // Prepare inputs - let signature = [ - "3582320600048169363", - "7163546589759624213", - "18262551396327275695", - "4479772254206047016", - "1970274621151677644", - "6547632513799968987", - "921117808165172908", - "7155116889028933260", - "16769940396381196125", - "17141182191056257954", - "4376997046052607007", - "17471823348423771450", - "16282311012391954891", - "70286524413490741", - "1588836847166444745", - "15693430141227594668", - "13832254169115286697", - "15936550641925323613", - "323842208142565220", - "6558662646882345749", - "15268061661646212265", - "14962976685717212593", - "15773505053543368901", - "9586594741348111792", - "1455720481014374292", - "13945813312010515080", - "6352059456732816887", - "17556873002865047035", - "2412591065060484384", - "11512123092407778330", - "8499281165724578877", - "12768005853882726493", - ]; - let modulus = [ - "13792647154200341559", - "12773492180790982043", - "13046321649363433702", - "10174370803876824128", - "7282572246071034406", - "1524365412687682781", - "4900829043004737418", - "6195884386932410966", - "13554217876979843574", - "17902692039595931737", - "12433028734895890975", - "15971442058448435996", - "4591894758077129763", - "11258250015882429548", - "16399550288873254981", - "8246389845141771315", - "14040203746442788850", - "7283856864330834987", - "12297563098718697441", - "13560928146585163504", - "7380926829734048483", - "14591299561622291080", - "8439722381984777599", - "17375431987296514829", - "16727607878674407272", - "3233954801381564296", - "17255435698225160983", - "15093748890170255670", - "15810389980847260072", - "11120056430439037392", - "5866130971823719482", - "13327552690270163501", - ]; - let base_message = [ - "18114495772705111902", - "2254271930739856077", - "2068851770", - "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", - "0", - ]; - - let mut inputs: HashMap> = HashMap::new(); - inputs.insert( - "signature".to_string(), - strings_to_circuit_inputs(&signature), - ); - inputs.insert("modulus".to_string(), strings_to_circuit_inputs(&modulus)); - inputs.insert( - "base_message".to_string(), - strings_to_circuit_inputs(&base_message), - ); - - // Proof generation - let generate_proof_res = generate_proof2(inputs); - - // Check and print the error if there is one - if let Err(e) = &generate_proof_res { - println!("Error: {:?}", e); - } - - assert!(generate_proof_res.is_ok()); - - let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); - - // Proof verification - let verify_res = verify_proof2(serialized_proof, serialized_inputs); - assert!(verify_res.is_ok()); - - assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified - } -} diff --git a/app/ios/mopro/mopro-core/src/middleware/circom/serialization.rs b/app/ios/mopro/mopro-core/src/middleware/circom/serialization.rs deleted file mode 100644 index 47fa40088..000000000 --- a/app/ios/mopro/mopro-core/src/middleware/circom/serialization.rs +++ /dev/null @@ -1,106 +0,0 @@ -use ark_bn254::Bn254; -use ark_ec::pairing::Pairing; -use ark_groth16::{Proof, ProvingKey}; -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use color_eyre::Result; - -#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] -pub struct SerializableProvingKey(pub ProvingKey); - -#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] -pub struct SerializableProof(pub Proof); - -#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq)] -pub struct SerializableInputs(pub Vec<::ScalarField>); - -pub fn serialize_proof(proof: &SerializableProof) -> Vec { - let mut serialized_data = Vec::new(); - proof - .serialize_uncompressed(&mut serialized_data) - .expect("Serialization failed"); - serialized_data -} - -pub fn deserialize_proof(data: Vec) -> SerializableProof { - SerializableProof::deserialize_uncompressed(&mut &data[..]).expect("Deserialization failed") -} - -pub fn serialize_proving_key(pk: &SerializableProvingKey) -> Vec { - let mut serialized_data = Vec::new(); - pk.serialize_uncompressed(&mut serialized_data) - .expect("Serialization failed"); - serialized_data -} - -pub fn deserialize_proving_key(data: Vec) -> SerializableProvingKey { - SerializableProvingKey::deserialize_uncompressed(&mut &data[..]) - .expect("Deserialization failed") -} - -pub fn serialize_inputs(inputs: &SerializableInputs) -> Vec { - let mut serialized_data = Vec::new(); - inputs - .serialize_uncompressed(&mut serialized_data) - .expect("Serialization failed"); - serialized_data -} - -pub fn deserialize_inputs(data: Vec) -> SerializableInputs { - SerializableInputs::deserialize_uncompressed(&mut &data[..]).expect("Deserialization failed") -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::middleware::circom::serialization::SerializableProvingKey; - use crate::middleware::circom::utils::assert_paths_exists; - use crate::MoproError; - use ark_bn254::Bn254; - use ark_circom::{CircomBuilder, CircomConfig}; - use ark_groth16::Groth16; - use ark_std::rand::thread_rng; - use color_eyre::Result; - - type GrothBn = Groth16; - - fn generate_serializable_proving_key( - wasm_path: &str, - r1cs_path: &str, - ) -> Result { - assert_paths_exists(wasm_path, r1cs_path)?; - - let cfg = CircomConfig::::new(wasm_path, r1cs_path) - .map_err(|e| MoproError::CircomError(e.to_string()))?; - - let builder = CircomBuilder::new(cfg); - let circom = builder.setup(); - - let mut rng = thread_rng(); - let raw_params = GrothBn::generate_random_parameters_with_reduction(circom, &mut rng) - .map_err(|e| MoproError::CircomError(e.to_string()))?; - - Ok(SerializableProvingKey(raw_params)) - } - - #[test] - fn test_serialization_deserialization() { - let wasm_path = "./examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"; - let r1cs_path = "./examples/circom/multiplier2/target/multiplier2.r1cs"; - - // Generate a serializable proving key for testing - let serializable_pk = generate_serializable_proving_key(wasm_path, r1cs_path) - .expect("Failed to generate serializable proving key"); - - // Serialize - let serialized_data = serialize_proving_key(&serializable_pk); - - // Deserialize - let deserialized_pk = deserialize_proving_key(serialized_data); - - // Assert that the original and deserialized ProvingKeys are the same - assert_eq!( - serializable_pk.0, deserialized_pk.0, - "Original and deserialized proving keys do not match" - ); - } -} diff --git a/app/ios/mopro/mopro-core/src/middleware/circom/utils.rs b/app/ios/mopro/mopro-core/src/middleware/circom/utils.rs deleted file mode 100644 index 31d6122c0..000000000 --- a/app/ios/mopro/mopro-core/src/middleware/circom/utils.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::MoproError; - -use std::path::Path; - -pub fn assert_paths_exists(wasm_path: &str, r1cs_path: &str) -> Result<(), MoproError> { - // Check that the files exist - ark-circom should probably do this instead and not panic - if !Path::new(wasm_path).exists() { - return Err(MoproError::CircomError(format!( - "Path does not exist: {}", - wasm_path - ))); - } - - if !Path::new(r1cs_path).exists() { - return Err(MoproError::CircomError(format!( - "Path does not exist: {}", - r1cs_path - ))); - }; - - Ok(()) -} - -pub fn bytes_to_bits(bytes: &[u8]) -> Vec { - let mut bits = Vec::new(); - for &byte in bytes { - for j in 0..8 { - let bit = (byte >> j) & 1; - bits.push(bit == 1); - } - } - bits -} diff --git a/app/ios/mopro/mopro-core/src/middleware/mod.rs b/app/ios/mopro/mopro-core/src/middleware/mod.rs deleted file mode 100644 index d18079a10..000000000 --- a/app/ios/mopro/mopro-core/src/middleware/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod circom; From c3f6a3de8dd0a5a1d20312f6e09e3c9e4e707442 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sun, 14 Jan 2024 22:47:26 +0100 Subject: [PATCH 03/12] deleted unused elements of mopro/mopro-ios --- .../{mopro/mopro-ios => }/MoproKit/.gitignore | 16 + .../mopro-ios => }/MoproKit/.travis.yml | 0 .../MoproKit/Bindings/mopro.swift | 0 .../MoproKit.xcodeproj/project.pbxproj | 0 .../xcschemes/MoproKit-Example.xcscheme | 0 .../MoproKit/AnonAadhaarViewController.swift | 0 .../Example/MoproKit/AppDelegate.swift | 0 .../MoproKit/Base.lproj/LaunchScreen.xib | 0 .../MoproKit/Base.lproj/Main.storyboard | 0 .../AppIcon.appiconset/Contents.json | 0 .../MoproKit/Example/MoproKit/Info.plist | 0 .../MoproKit/KeccakSetupViewController.swift | 0 .../MoproKit/KeccakZkeyViewController.swift | 0 .../Example/MoproKit/RSAViewController.swift | 0 .../Example/MoproKit/ViewController.swift | 0 .../mopro-ios => }/MoproKit/Example/Podfile | 0 .../MoproKit/Example/Tests/CircomTests.swift | 0 .../Example/Tests/CircomUITests.swift | 0 .../MoproKit/Example/Tests/Info.plist | 0 .../MoproKit/Include/moproFFI.h | 0 .../{mopro/mopro-ios => }/MoproKit/LICENSE | 0 .../mopro-ios => }/MoproKit/Libs/.gitkeep | 0 .../mopro-ios => }/MoproKit/MoproKit.podspec | 0 .../MoproKit/MoproKit/Assets/.gitkeep | 0 .../{mopro/mopro-ios => }/MoproKit/README.md | 0 .../Resources}/moproFFI.modulemap | 0 app/ios/Podfile | 2 +- app/ios/Podfile.lock | 6 +- .../ProofOfPassport.xcodeproj/project.pbxproj | 8 +- app/ios/mopro/mopro-ios/.gitignore | 35 -- .../MoproBindings.xcframework/Info.plist | 43 -- .../ios-arm64-simulator/Headers/moproFFI.h | 96 ---- .../ios-arm64-simulator/Sources/mopro.swift | 411 ------------------ .../ios-arm64/Headers/moproFFI.h | 96 ---- .../ios-arm64/Headers/moproFFI.modulemap | 6 - .../ios-arm64/Sources/mopro.swift | 411 ------------------ .../MoproKit/Resources/moproFFI.modulemap | 6 - .../mopro/mopro-ios/MoproKit/_Pods.xcodeproj | 1 - app/ios/mopro/mopro-ios/README.md | 51 --- app/ios/mopro/mopro-ios/Sources/mopro.swift | 411 ------------------ app/ios/mopro/mopro-ios/headers/moproFFI.h | 96 ---- .../mopro-ios/headers/moproFFI.modulemap | 6 - 42 files changed, 24 insertions(+), 1677 deletions(-) rename app/ios/{mopro/mopro-ios => }/MoproKit/.gitignore (79%) rename app/ios/{mopro/mopro-ios => }/MoproKit/.travis.yml (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Bindings/mopro.swift (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit.xcodeproj/xcshareddata/xcschemes/MoproKit-Example.xcscheme (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit/AnonAadhaarViewController.swift (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit/AppDelegate.swift (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit/Base.lproj/LaunchScreen.xib (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit/Base.lproj/Main.storyboard (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit/Images.xcassets/AppIcon.appiconset/Contents.json (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit/Info.plist (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit/KeccakSetupViewController.swift (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit/KeccakZkeyViewController.swift (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit/RSAViewController.swift (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/MoproKit/ViewController.swift (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/Podfile (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/Tests/CircomTests.swift (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/Tests/CircomUITests.swift (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Example/Tests/Info.plist (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Include/moproFFI.h (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/LICENSE (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/Libs/.gitkeep (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/MoproKit.podspec (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/MoproKit/Assets/.gitkeep (100%) rename app/ios/{mopro/mopro-ios => }/MoproKit/README.md (100%) rename app/ios/{mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers => MoproKit/Resources}/moproFFI.modulemap (100%) delete mode 100644 app/ios/mopro/mopro-ios/.gitignore delete mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/Info.plist delete mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.h delete mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Sources/mopro.swift delete mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.h delete mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.modulemap delete mode 100644 app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Sources/mopro.swift delete mode 100644 app/ios/mopro/mopro-ios/MoproKit/Resources/moproFFI.modulemap delete mode 120000 app/ios/mopro/mopro-ios/MoproKit/_Pods.xcodeproj delete mode 100644 app/ios/mopro/mopro-ios/README.md delete mode 100644 app/ios/mopro/mopro-ios/Sources/mopro.swift delete mode 100644 app/ios/mopro/mopro-ios/headers/moproFFI.h delete mode 100644 app/ios/mopro/mopro-ios/headers/moproFFI.modulemap diff --git a/app/ios/mopro/mopro-ios/MoproKit/.gitignore b/app/ios/MoproKit/.gitignore similarity index 79% rename from app/ios/mopro/mopro-ios/MoproKit/.gitignore rename to app/ios/MoproKit/.gitignore index 805ffc7dd..49c016dd7 100644 --- a/app/ios/mopro/mopro-ios/MoproKit/.gitignore +++ b/app/ios/MoproKit/.gitignore @@ -17,6 +17,7 @@ xcuserdata/ DerivedData *.hmap *.ipa +*.xcuserstate # Bundler .bundle @@ -34,3 +35,18 @@ Carthage/Build # `pod install` in .travis.yml # # Pods/ + +# Xcode +# +/.build +/Packages +/*.xcodeproj +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata + +# CocoaPods +Podfile.lock +Pods +*.xcworkspace + +# Ignore static libs +*.a \ No newline at end of file diff --git a/app/ios/mopro/mopro-ios/MoproKit/.travis.yml b/app/ios/MoproKit/.travis.yml similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/.travis.yml rename to app/ios/MoproKit/.travis.yml diff --git a/app/ios/mopro/mopro-ios/MoproKit/Bindings/mopro.swift b/app/ios/MoproKit/Bindings/mopro.swift similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Bindings/mopro.swift rename to app/ios/MoproKit/Bindings/mopro.swift diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj b/app/ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj rename to app/ios/MoproKit/Example/MoproKit.xcodeproj/project.pbxproj diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/xcshareddata/xcschemes/MoproKit-Example.xcscheme b/app/ios/MoproKit/Example/MoproKit.xcodeproj/xcshareddata/xcschemes/MoproKit-Example.xcscheme similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit.xcodeproj/xcshareddata/xcschemes/MoproKit-Example.xcscheme rename to app/ios/MoproKit/Example/MoproKit.xcodeproj/xcshareddata/xcschemes/MoproKit-Example.xcscheme diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AnonAadhaarViewController.swift b/app/ios/MoproKit/Example/MoproKit/AnonAadhaarViewController.swift similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AnonAadhaarViewController.swift rename to app/ios/MoproKit/Example/MoproKit/AnonAadhaarViewController.swift diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AppDelegate.swift b/app/ios/MoproKit/Example/MoproKit/AppDelegate.swift similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/AppDelegate.swift rename to app/ios/MoproKit/Example/MoproKit/AppDelegate.swift diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/LaunchScreen.xib b/app/ios/MoproKit/Example/MoproKit/Base.lproj/LaunchScreen.xib similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/LaunchScreen.xib rename to app/ios/MoproKit/Example/MoproKit/Base.lproj/LaunchScreen.xib diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/Main.storyboard b/app/ios/MoproKit/Example/MoproKit/Base.lproj/Main.storyboard similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Base.lproj/Main.storyboard rename to app/ios/MoproKit/Example/MoproKit/Base.lproj/Main.storyboard diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Images.xcassets/AppIcon.appiconset/Contents.json b/app/ios/MoproKit/Example/MoproKit/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Images.xcassets/AppIcon.appiconset/Contents.json rename to app/ios/MoproKit/Example/MoproKit/Images.xcassets/AppIcon.appiconset/Contents.json diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Info.plist b/app/ios/MoproKit/Example/MoproKit/Info.plist similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/Info.plist rename to app/ios/MoproKit/Example/MoproKit/Info.plist diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift b/app/ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift rename to app/ios/MoproKit/Example/MoproKit/KeccakSetupViewController.swift diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakZkeyViewController.swift b/app/ios/MoproKit/Example/MoproKit/KeccakZkeyViewController.swift similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/KeccakZkeyViewController.swift rename to app/ios/MoproKit/Example/MoproKit/KeccakZkeyViewController.swift diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/RSAViewController.swift b/app/ios/MoproKit/Example/MoproKit/RSAViewController.swift similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/RSAViewController.swift rename to app/ios/MoproKit/Example/MoproKit/RSAViewController.swift diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/ViewController.swift b/app/ios/MoproKit/Example/MoproKit/ViewController.swift similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/MoproKit/ViewController.swift rename to app/ios/MoproKit/Example/MoproKit/ViewController.swift diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/Podfile b/app/ios/MoproKit/Example/Podfile similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/Podfile rename to app/ios/MoproKit/Example/Podfile diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomTests.swift b/app/ios/MoproKit/Example/Tests/CircomTests.swift similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomTests.swift rename to app/ios/MoproKit/Example/Tests/CircomTests.swift diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomUITests.swift b/app/ios/MoproKit/Example/Tests/CircomUITests.swift similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/Tests/CircomUITests.swift rename to app/ios/MoproKit/Example/Tests/CircomUITests.swift diff --git a/app/ios/mopro/mopro-ios/MoproKit/Example/Tests/Info.plist b/app/ios/MoproKit/Example/Tests/Info.plist similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Example/Tests/Info.plist rename to app/ios/MoproKit/Example/Tests/Info.plist diff --git a/app/ios/mopro/mopro-ios/MoproKit/Include/moproFFI.h b/app/ios/MoproKit/Include/moproFFI.h similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Include/moproFFI.h rename to app/ios/MoproKit/Include/moproFFI.h diff --git a/app/ios/mopro/mopro-ios/MoproKit/LICENSE b/app/ios/MoproKit/LICENSE similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/LICENSE rename to app/ios/MoproKit/LICENSE diff --git a/app/ios/mopro/mopro-ios/MoproKit/Libs/.gitkeep b/app/ios/MoproKit/Libs/.gitkeep similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/Libs/.gitkeep rename to app/ios/MoproKit/Libs/.gitkeep diff --git a/app/ios/mopro/mopro-ios/MoproKit/MoproKit.podspec b/app/ios/MoproKit/MoproKit.podspec similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/MoproKit.podspec rename to app/ios/MoproKit/MoproKit.podspec diff --git a/app/ios/mopro/mopro-ios/MoproKit/MoproKit/Assets/.gitkeep b/app/ios/MoproKit/MoproKit/Assets/.gitkeep similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/MoproKit/Assets/.gitkeep rename to app/ios/MoproKit/MoproKit/Assets/.gitkeep diff --git a/app/ios/mopro/mopro-ios/MoproKit/README.md b/app/ios/MoproKit/README.md similarity index 100% rename from app/ios/mopro/mopro-ios/MoproKit/README.md rename to app/ios/MoproKit/README.md diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.modulemap b/app/ios/MoproKit/Resources/moproFFI.modulemap similarity index 100% rename from app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.modulemap rename to app/ios/MoproKit/Resources/moproFFI.modulemap diff --git a/app/ios/Podfile b/app/ios/Podfile index fbdaee9b9..721152643 100644 --- a/app/ios/Podfile +++ b/app/ios/Podfile @@ -35,7 +35,7 @@ target 'ProofOfPassport' do use_frameworks! pod 'NFCPassportReader', git: 'https://github.com/0xturboblitz/NFCPassportReader.git', commit: '07b3662702834676b547718998fa377fe5f00776' - pod 'MoproKit', :path => './mopro/mopro-ios/MoproKit' + pod 'MoproKit', :path => './MoproKit' use_react_native!( :path => config[:reactNativePath], diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index 579d60f9a..50ed760f8 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -402,7 +402,7 @@ DEPENDENCIES: - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - - MoproKit (from `./mopro/mopro-ios/MoproKit`) + - MoproKit (from `./MoproKit`) - NFCPassportReader (from `https://github.com/0xturboblitz/NFCPassportReader.git`, commit `07b3662702834676b547718998fa377fe5f00776`) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) @@ -458,7 +458,7 @@ EXTERNAL SOURCES: glog: :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" MoproKit: - :path: "./mopro/mopro-ios/MoproKit" + :path: "./MoproKit" NFCPassportReader: :commit: 07b3662702834676b547718998fa377fe5f00776 :git: https://github.com/0xturboblitz/NFCPassportReader.git @@ -582,6 +582,6 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Yoga: 8796b55dba14d7004f980b54bcc9833ee45b28ce -PODFILE CHECKSUM: 26d95ec475f9d1b46c82166c123fd279bf69045f +PODFILE CHECKSUM: 52f9302a4d936d9bacb79ef5417142b1e96c5f0e COCOAPODS: 1.14.3 diff --git a/app/ios/ProofOfPassport.xcodeproj/project.pbxproj b/app/ios/ProofOfPassport.xcodeproj/project.pbxproj index f45272981..234daae04 100644 --- a/app/ios/ProofOfPassport.xcodeproj/project.pbxproj +++ b/app/ios/ProofOfPassport.xcodeproj/project.pbxproj @@ -8,7 +8,7 @@ /* Begin PBXBuildFile section */ 00E356F31AD99517003FC87E /* ProofOfPassportTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ProofOfPassportTests.m */; }; - 05A0773C2B5332040037E489 /* mopro in Resources */ = {isa = PBXBuildFile; fileRef = 05A0773B2B5332040037E489 /* mopro */; }; + 05BD9DCC2B548AA900823023 /* MoproKit in Resources */ = {isa = PBXBuildFile; fileRef = 05BD9DCB2B548AA900823023 /* MoproKit */; }; 05EDEDC62B52D25D00AA51AD /* Prover.m in Sources */ = {isa = PBXBuildFile; fileRef = 05EDEDC42B52D25D00AA51AD /* Prover.m */; }; 05EDEDC72B52D25D00AA51AD /* Prover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05EDEDC52B52D25D00AA51AD /* Prover.swift */; }; 0651723A94C70A2B31E3E4F8 /* Pods_ProofOfPassport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAAF621B99F62C9ED35AA07 /* Pods_ProofOfPassport.framework */; }; @@ -36,8 +36,8 @@ 00E356EE1AD99517003FC87E /* ProofOfPassportTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProofOfPassportTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 00E356F21AD99517003FC87E /* ProofOfPassportTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProofOfPassportTests.m; sourceTree = ""; }; - 05A0773B2B5332040037E489 /* mopro */ = {isa = PBXFileReference; lastKnownFileType = folder; path = mopro; sourceTree = ""; }; 05A0773D2B5333CE0037E489 /* MoproKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MoproKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 05BD9DCB2B548AA900823023 /* MoproKit */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MoproKit; sourceTree = ""; }; 05EDEDC42B52D25D00AA51AD /* Prover.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Prover.m; sourceTree = ""; }; 05EDEDC52B52D25D00AA51AD /* Prover.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Prover.swift; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* ProofOfPassport.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ProofOfPassport.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -106,13 +106,13 @@ 905B700A2A72A5E900AFA232 /* masterList.pem */, 905B70082A729CD400AFA232 /* ProofOfPassport.entitlements */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 05BD9DCB2B548AA900823023 /* MoproKit */, 13B07FB01A68108700A75B9A /* AppDelegate.mm */, 13B07FB51A68108700A75B9A /* Images.xcassets */, 13B07FB61A68108700A75B9A /* Info.plist */, 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, 13B07FB71A68108700A75B9A /* main.m */, 905B70042A72767900AFA232 /* PassportReader.swift */, - 05A0773B2B5332040037E489 /* mopro */, 905B70032A72767800AFA232 /* ProofOfPassport-Bridging-Header.h */, 905B70062A72774000AFA232 /* PassportReader.m */, ); @@ -265,8 +265,8 @@ buildActionMask = 2147483647; files = ( 905B700B2A72A5E900AFA232 /* masterList.pem in Resources */, + 05BD9DCC2B548AA900823023 /* MoproKit in Resources */, 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, - 05A0773C2B5332040037E489 /* mopro in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/app/ios/mopro/mopro-ios/.gitignore b/app/ios/mopro/mopro-ios/.gitignore deleted file mode 100644 index e5d2c0bce..000000000 --- a/app/ios/mopro/mopro-ios/.gitignore +++ /dev/null @@ -1,35 +0,0 @@ -.DS_Store - -# Xcode -# -/.build -/Packages -/*.xcodeproj -xcuserdata/ -DerivedData/ -.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata -build/ -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata -*.xccheckout -*.moved-aside -DerivedData -*.hmap -*.ipa -*.xcuserstate - -# CocoaPods -Podfile.lock -Pods -*.xcworkspace - -# Ignore static libs -*.a - diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/Info.plist b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/Info.plist deleted file mode 100644 index 180e5579f..000000000 --- a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/Info.plist +++ /dev/null @@ -1,43 +0,0 @@ - - - - - AvailableLibraries - - - HeadersPath - Headers - LibraryIdentifier - ios-arm64 - LibraryPath - libmopro_ffi.a - SupportedArchitectures - - arm64 - - SupportedPlatform - ios - - - HeadersPath - Headers - LibraryIdentifier - ios-arm64-simulator - LibraryPath - libmopro_ffi.a - SupportedArchitectures - - arm64 - - SupportedPlatform - ios - SupportedPlatformVariant - simulator - - - CFBundlePackageType - XFWK - XCFrameworkFormatVersion - 1.0 - - diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.h b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.h deleted file mode 100644 index 0d7647eb0..000000000 --- a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Headers/moproFFI.h +++ /dev/null @@ -1,96 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! - -#pragma once - -#include -#include -#include - -// The following structs are used to implement the lowest level -// of the FFI, and thus useful to multiple uniffied crates. -// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. -#ifdef UNIFFI_SHARED_H - // We also try to prevent mixing versions of shared uniffi header structs. - // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 - #ifndef UNIFFI_SHARED_HEADER_V4 - #error Combining helper code from multiple versions of uniffi is not supported - #endif // ndef UNIFFI_SHARED_HEADER_V4 -#else -#define UNIFFI_SHARED_H -#define UNIFFI_SHARED_HEADER_V4 -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ - -typedef struct RustBuffer -{ - int32_t capacity; - int32_t len; - uint8_t *_Nullable data; -} RustBuffer; - -typedef int32_t (*ForeignCallback)(uint64_t, int32_t, const uint8_t *_Nonnull, int32_t, RustBuffer *_Nonnull); - -// Task defined in Rust that Swift executes -typedef void (*UniFfiRustTaskCallback)(const void * _Nullable); - -// Callback to execute Rust tasks using a Swift Task -// -// Args: -// executor: ForeignExecutor lowered into a size_t value -// delay: Delay in MS -// task: UniFfiRustTaskCallback to call -// task_data: data to pass the task callback -typedef void (*UniFfiForeignExecutorCallback)(size_t, uint32_t, UniFfiRustTaskCallback _Nullable, const void * _Nullable); - -typedef struct ForeignBytes -{ - int32_t len; - const uint8_t *_Nullable data; -} ForeignBytes; - -// Error definitions -typedef struct RustCallStatus { - int8_t code; - RustBuffer errorBuf; -} RustCallStatus; - -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ -#endif // def UNIFFI_SHARED_H - -// Callbacks for UniFFI Futures -typedef void (*UniFfiFutureCallbackUInt8)(const void * _Nonnull, uint8_t, RustCallStatus); -typedef void (*UniFfiFutureCallbackUInt32)(const void * _Nonnull, uint32_t, RustCallStatus); -typedef void (*UniFfiFutureCallbackRustBuffer)(const void * _Nonnull, RustBuffer, RustCallStatus); - -// Scaffolding functions -uint32_t uniffi_mopro_fn_func_add(uint32_t a, uint32_t b, RustCallStatus *_Nonnull out_status -); -RustBuffer uniffi_mopro_fn_func_hello(RustCallStatus *_Nonnull out_status - -); -void uniffi_mopro_fn_func_run(RustCallStatus *_Nonnull out_status - -); -RustBuffer ffi_mopro_rustbuffer_alloc(int32_t size, RustCallStatus *_Nonnull out_status -); -RustBuffer ffi_mopro_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status -); -void ffi_mopro_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status -); -RustBuffer ffi_mopro_rustbuffer_reserve(RustBuffer buf, int32_t additional, RustCallStatus *_Nonnull out_status -); -uint16_t uniffi_mopro_checksum_func_add(void - -); -uint16_t uniffi_mopro_checksum_func_hello(void - -); -uint16_t uniffi_mopro_checksum_func_run(void - -); -uint32_t ffi_mopro_uniffi_contract_version(void - -); - diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Sources/mopro.swift b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Sources/mopro.swift deleted file mode 100644 index 59edffd02..000000000 --- a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64-simulator/Sources/mopro.swift +++ /dev/null @@ -1,411 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! -import Foundation - -// Depending on the consumer's build setup, the low-level FFI code -// might be in a separate module, or it might be compiled inline into -// this module. This is a bit of light hackery to work with both. -#if canImport(moproFFI) - import moproFFI -#endif - -private extension RustBuffer { - // Allocate a new buffer, copying the contents of a `UInt8` array. - init(bytes: [UInt8]) { - let rbuf = bytes.withUnsafeBufferPointer { ptr in - RustBuffer.from(ptr) - } - self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) - } - - static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { - try! rustCall { ffi_mopro_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } - } - - // Frees the buffer in place. - // The buffer must not be used after this is called. - func deallocate() { - try! rustCall { ffi_mopro_rustbuffer_free(self, $0) } - } -} - -private extension ForeignBytes { - init(bufferPointer: UnsafeBufferPointer) { - self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) - } -} - -// For every type used in the interface, we provide helper methods for conveniently -// lifting and lowering that type from C-compatible data, and for reading and writing -// values of that type in a buffer. - -// Helper classes/extensions that don't change. -// Someday, this will be in a library of its own. - -private extension Data { - init(rustBuffer: RustBuffer) { - // TODO: This copies the buffer. Can we read directly from a - // Rust buffer? - self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) - } -} - -// Define reader functionality. Normally this would be defined in a class or -// struct, but we use standalone functions instead in order to make external -// types work. -// -// With external types, one swift source file needs to be able to call the read -// method on another source file's FfiConverter, but then what visibility -// should Reader have? -// - If Reader is fileprivate, then this means the read() must also -// be fileprivate, which doesn't work with external types. -// - If Reader is internal/public, we'll get compile errors since both source -// files will try define the same type. -// -// Instead, the read() method and these helper functions input a tuple of data - -private func createReader(data: Data) -> (data: Data, offset: Data.Index) { - (data: data, offset: 0) -} - -// Reads an integer at the current offset, in big-endian order, and advances -// the offset on success. Throws if reading the integer would move the -// offset past the end of the buffer. -private func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { - let range = reader.offset ..< reader.offset + MemoryLayout.size - guard reader.data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - if T.self == UInt8.self { - let value = reader.data[reader.offset] - reader.offset += 1 - return value as! T - } - var value: T = 0 - let _ = withUnsafeMutableBytes(of: &value) { reader.data.copyBytes(to: $0, from: range) } - reader.offset = range.upperBound - return value.bigEndian -} - -// Reads an arbitrary number of bytes, to be used to read -// raw bytes, this is useful when lifting strings -private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> [UInt8] { - let range = reader.offset ..< (reader.offset + count) - guard reader.data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - var value = [UInt8](repeating: 0, count: count) - value.withUnsafeMutableBufferPointer { buffer in - reader.data.copyBytes(to: buffer, from: range) - } - reader.offset = range.upperBound - return value -} - -// Reads a float at the current offset. -private func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { - return try Float(bitPattern: readInt(&reader)) -} - -// Reads a float at the current offset. -private func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { - return try Double(bitPattern: readInt(&reader)) -} - -// Indicates if the offset has reached the end of the buffer. -private func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { - return reader.offset < reader.data.count -} - -// Define writer functionality. Normally this would be defined in a class or -// struct, but we use standalone functions instead in order to make external -// types work. See the above discussion on Readers for details. - -private func createWriter() -> [UInt8] { - return [] -} - -private func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { - writer.append(contentsOf: byteArr) -} - -// Writes an integer in big-endian order. -// -// Warning: make sure what you are trying to write -// is in the correct type! -private func writeInt(_ writer: inout [UInt8], _ value: T) { - var value = value.bigEndian - withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } -} - -private func writeFloat(_ writer: inout [UInt8], _ value: Float) { - writeInt(&writer, value.bitPattern) -} - -private func writeDouble(_ writer: inout [UInt8], _ value: Double) { - writeInt(&writer, value.bitPattern) -} - -// Protocol for types that transfer other types across the FFI. This is -// analogous go the Rust trait of the same name. -private protocol FfiConverter { - associatedtype FfiType - associatedtype SwiftType - - static func lift(_ value: FfiType) throws -> SwiftType - static func lower(_ value: SwiftType) -> FfiType - static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType - static func write(_ value: SwiftType, into buf: inout [UInt8]) -} - -// Types conforming to `Primitive` pass themselves directly over the FFI. -private protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType {} - -extension FfiConverterPrimitive { - public static func lift(_ value: FfiType) throws -> SwiftType { - return value - } - - public static func lower(_ value: SwiftType) -> FfiType { - return value - } -} - -// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. -// Used for complex types where it's hard to write a custom lift/lower. -private protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} - -extension FfiConverterRustBuffer { - public static func lift(_ buf: RustBuffer) throws -> SwiftType { - var reader = createReader(data: Data(rustBuffer: buf)) - let value = try read(from: &reader) - if hasRemaining(reader) { - throw UniffiInternalError.incompleteData - } - buf.deallocate() - return value - } - - public static func lower(_ value: SwiftType) -> RustBuffer { - var writer = createWriter() - write(value, into: &writer) - return RustBuffer(bytes: writer) - } -} - -// An error type for FFI errors. These errors occur at the UniFFI level, not -// the library level. -private enum UniffiInternalError: LocalizedError { - case bufferOverflow - case incompleteData - case unexpectedOptionalTag - case unexpectedEnumCase - case unexpectedNullPointer - case unexpectedRustCallStatusCode - case unexpectedRustCallError - case unexpectedStaleHandle - case rustPanic(_ message: String) - - public var errorDescription: String? { - switch self { - case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" - case .incompleteData: return "The buffer still has data after lifting its containing value" - case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" - case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" - case .unexpectedNullPointer: return "Raw pointer value was null" - case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" - case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" - case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" - case let .rustPanic(message): return message - } - } -} - -private let CALL_SUCCESS: Int8 = 0 -private let CALL_ERROR: Int8 = 1 -private let CALL_PANIC: Int8 = 2 - -private extension RustCallStatus { - init() { - self.init( - code: CALL_SUCCESS, - errorBuf: RustBuffer( - capacity: 0, - len: 0, - data: nil - ) - ) - } -} - -private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { - try makeRustCall(callback, errorHandler: nil) -} - -private func rustCallWithError( - _ errorHandler: @escaping (RustBuffer) throws -> Error, - _ callback: (UnsafeMutablePointer) -> T -) throws -> T { - try makeRustCall(callback, errorHandler: errorHandler) -} - -private func makeRustCall( - _ callback: (UnsafeMutablePointer) -> T, - errorHandler: ((RustBuffer) throws -> Error)? -) throws -> T { - uniffiEnsureInitialized() - var callStatus = RustCallStatus() - let returnedVal = callback(&callStatus) - try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) - return returnedVal -} - -private func uniffiCheckCallStatus( - callStatus: RustCallStatus, - errorHandler: ((RustBuffer) throws -> Error)? -) throws { - switch callStatus.code { - case CALL_SUCCESS: - return - - case CALL_ERROR: - if let errorHandler = errorHandler { - throw try errorHandler(callStatus.errorBuf) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.unexpectedRustCallError - } - - case CALL_PANIC: - // When the rust code sees a panic, it tries to construct a RustBuffer - // with the message. But if that code panics, then it just sends back - // an empty buffer. - if callStatus.errorBuf.len > 0 { - throw try UniffiInternalError.rustPanic(FfiConverterString.lift(callStatus.errorBuf)) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.rustPanic("Rust panic") - } - - default: - throw UniffiInternalError.unexpectedRustCallStatusCode - } -} - -// Public interface members begin here. - -private struct FfiConverterUInt32: FfiConverterPrimitive { - typealias FfiType = UInt32 - typealias SwiftType = UInt32 - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { - return try lift(readInt(&buf)) - } - - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { - writeInt(&buf, lower(value)) - } -} - -private struct FfiConverterString: FfiConverter { - typealias SwiftType = String - typealias FfiType = RustBuffer - - public static func lift(_ value: RustBuffer) throws -> String { - defer { - value.deallocate() - } - if value.data == nil { - return String() - } - let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len)) - return String(bytes: bytes, encoding: String.Encoding.utf8)! - } - - public static func lower(_ value: String) -> RustBuffer { - return value.utf8CString.withUnsafeBufferPointer { ptr in - // The swift string gives us int8_t, we want uint8_t. - ptr.withMemoryRebound(to: UInt8.self) { ptr in - // The swift string gives us a trailing null byte, we don't want it. - let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) - return RustBuffer.from(buf) - } - } - } - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { - let len: Int32 = try readInt(&buf) - return try String(bytes: readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! - } - - public static func write(_ value: String, into buf: inout [UInt8]) { - let len = Int32(value.utf8.count) - writeInt(&buf, len) - writeBytes(&buf, value.utf8) - } -} - -public func add(a: UInt32, b: UInt32) -> UInt32 { - return try! FfiConverterUInt32.lift( - try! rustCall { - uniffi_mopro_fn_func_add( - FfiConverterUInt32.lower(a), - FfiConverterUInt32.lower(b), $0 - ) - } - ) -} - -public func hello() -> String { - return try! FfiConverterString.lift( - try! rustCall { - uniffi_mopro_fn_func_hello($0) - } - ) -} - -public func run() { - try! rustCall { - uniffi_mopro_fn_func_run($0) - } -} - -private enum InitializationResult { - case ok - case contractVersionMismatch - case apiChecksumMismatch -} - -// Use a global variables to perform the versioning checks. Swift ensures that -// the code inside is only computed once. -private var initializationResult: InitializationResult { - // Get the bindings contract version from our ComponentInterface - let bindings_contract_version = 22 - // Get the scaffolding contract version by calling the into the dylib - let scaffolding_contract_version = ffi_mopro_uniffi_contract_version() - if bindings_contract_version != scaffolding_contract_version { - return InitializationResult.contractVersionMismatch - } - if uniffi_mopro_checksum_func_add() != 19178 { - return InitializationResult.apiChecksumMismatch - } - if uniffi_mopro_checksum_func_hello() != 309 { - return InitializationResult.apiChecksumMismatch - } - if uniffi_mopro_checksum_func_run() != 17009 { - return InitializationResult.apiChecksumMismatch - } - - return InitializationResult.ok -} - -private func uniffiEnsureInitialized() { - switch initializationResult { - case .ok: - break - case .contractVersionMismatch: - fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") - case .apiChecksumMismatch: - fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } -} diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.h b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.h deleted file mode 100644 index 0d7647eb0..000000000 --- a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.h +++ /dev/null @@ -1,96 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! - -#pragma once - -#include -#include -#include - -// The following structs are used to implement the lowest level -// of the FFI, and thus useful to multiple uniffied crates. -// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. -#ifdef UNIFFI_SHARED_H - // We also try to prevent mixing versions of shared uniffi header structs. - // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 - #ifndef UNIFFI_SHARED_HEADER_V4 - #error Combining helper code from multiple versions of uniffi is not supported - #endif // ndef UNIFFI_SHARED_HEADER_V4 -#else -#define UNIFFI_SHARED_H -#define UNIFFI_SHARED_HEADER_V4 -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ - -typedef struct RustBuffer -{ - int32_t capacity; - int32_t len; - uint8_t *_Nullable data; -} RustBuffer; - -typedef int32_t (*ForeignCallback)(uint64_t, int32_t, const uint8_t *_Nonnull, int32_t, RustBuffer *_Nonnull); - -// Task defined in Rust that Swift executes -typedef void (*UniFfiRustTaskCallback)(const void * _Nullable); - -// Callback to execute Rust tasks using a Swift Task -// -// Args: -// executor: ForeignExecutor lowered into a size_t value -// delay: Delay in MS -// task: UniFfiRustTaskCallback to call -// task_data: data to pass the task callback -typedef void (*UniFfiForeignExecutorCallback)(size_t, uint32_t, UniFfiRustTaskCallback _Nullable, const void * _Nullable); - -typedef struct ForeignBytes -{ - int32_t len; - const uint8_t *_Nullable data; -} ForeignBytes; - -// Error definitions -typedef struct RustCallStatus { - int8_t code; - RustBuffer errorBuf; -} RustCallStatus; - -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ -#endif // def UNIFFI_SHARED_H - -// Callbacks for UniFFI Futures -typedef void (*UniFfiFutureCallbackUInt8)(const void * _Nonnull, uint8_t, RustCallStatus); -typedef void (*UniFfiFutureCallbackUInt32)(const void * _Nonnull, uint32_t, RustCallStatus); -typedef void (*UniFfiFutureCallbackRustBuffer)(const void * _Nonnull, RustBuffer, RustCallStatus); - -// Scaffolding functions -uint32_t uniffi_mopro_fn_func_add(uint32_t a, uint32_t b, RustCallStatus *_Nonnull out_status -); -RustBuffer uniffi_mopro_fn_func_hello(RustCallStatus *_Nonnull out_status - -); -void uniffi_mopro_fn_func_run(RustCallStatus *_Nonnull out_status - -); -RustBuffer ffi_mopro_rustbuffer_alloc(int32_t size, RustCallStatus *_Nonnull out_status -); -RustBuffer ffi_mopro_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status -); -void ffi_mopro_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status -); -RustBuffer ffi_mopro_rustbuffer_reserve(RustBuffer buf, int32_t additional, RustCallStatus *_Nonnull out_status -); -uint16_t uniffi_mopro_checksum_func_add(void - -); -uint16_t uniffi_mopro_checksum_func_hello(void - -); -uint16_t uniffi_mopro_checksum_func_run(void - -); -uint32_t ffi_mopro_uniffi_contract_version(void - -); - diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.modulemap b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.modulemap deleted file mode 100644 index 93b8adffb..000000000 --- a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Headers/moproFFI.modulemap +++ /dev/null @@ -1,6 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! -module moproFFI { - header "moproFFI.h" - export * -} \ No newline at end of file diff --git a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Sources/mopro.swift b/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Sources/mopro.swift deleted file mode 100644 index 59edffd02..000000000 --- a/app/ios/mopro/mopro-ios/MoproBindings.xcframework/ios-arm64/Sources/mopro.swift +++ /dev/null @@ -1,411 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! -import Foundation - -// Depending on the consumer's build setup, the low-level FFI code -// might be in a separate module, or it might be compiled inline into -// this module. This is a bit of light hackery to work with both. -#if canImport(moproFFI) - import moproFFI -#endif - -private extension RustBuffer { - // Allocate a new buffer, copying the contents of a `UInt8` array. - init(bytes: [UInt8]) { - let rbuf = bytes.withUnsafeBufferPointer { ptr in - RustBuffer.from(ptr) - } - self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) - } - - static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { - try! rustCall { ffi_mopro_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } - } - - // Frees the buffer in place. - // The buffer must not be used after this is called. - func deallocate() { - try! rustCall { ffi_mopro_rustbuffer_free(self, $0) } - } -} - -private extension ForeignBytes { - init(bufferPointer: UnsafeBufferPointer) { - self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) - } -} - -// For every type used in the interface, we provide helper methods for conveniently -// lifting and lowering that type from C-compatible data, and for reading and writing -// values of that type in a buffer. - -// Helper classes/extensions that don't change. -// Someday, this will be in a library of its own. - -private extension Data { - init(rustBuffer: RustBuffer) { - // TODO: This copies the buffer. Can we read directly from a - // Rust buffer? - self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) - } -} - -// Define reader functionality. Normally this would be defined in a class or -// struct, but we use standalone functions instead in order to make external -// types work. -// -// With external types, one swift source file needs to be able to call the read -// method on another source file's FfiConverter, but then what visibility -// should Reader have? -// - If Reader is fileprivate, then this means the read() must also -// be fileprivate, which doesn't work with external types. -// - If Reader is internal/public, we'll get compile errors since both source -// files will try define the same type. -// -// Instead, the read() method and these helper functions input a tuple of data - -private func createReader(data: Data) -> (data: Data, offset: Data.Index) { - (data: data, offset: 0) -} - -// Reads an integer at the current offset, in big-endian order, and advances -// the offset on success. Throws if reading the integer would move the -// offset past the end of the buffer. -private func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { - let range = reader.offset ..< reader.offset + MemoryLayout.size - guard reader.data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - if T.self == UInt8.self { - let value = reader.data[reader.offset] - reader.offset += 1 - return value as! T - } - var value: T = 0 - let _ = withUnsafeMutableBytes(of: &value) { reader.data.copyBytes(to: $0, from: range) } - reader.offset = range.upperBound - return value.bigEndian -} - -// Reads an arbitrary number of bytes, to be used to read -// raw bytes, this is useful when lifting strings -private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> [UInt8] { - let range = reader.offset ..< (reader.offset + count) - guard reader.data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - var value = [UInt8](repeating: 0, count: count) - value.withUnsafeMutableBufferPointer { buffer in - reader.data.copyBytes(to: buffer, from: range) - } - reader.offset = range.upperBound - return value -} - -// Reads a float at the current offset. -private func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { - return try Float(bitPattern: readInt(&reader)) -} - -// Reads a float at the current offset. -private func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { - return try Double(bitPattern: readInt(&reader)) -} - -// Indicates if the offset has reached the end of the buffer. -private func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { - return reader.offset < reader.data.count -} - -// Define writer functionality. Normally this would be defined in a class or -// struct, but we use standalone functions instead in order to make external -// types work. See the above discussion on Readers for details. - -private func createWriter() -> [UInt8] { - return [] -} - -private func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { - writer.append(contentsOf: byteArr) -} - -// Writes an integer in big-endian order. -// -// Warning: make sure what you are trying to write -// is in the correct type! -private func writeInt(_ writer: inout [UInt8], _ value: T) { - var value = value.bigEndian - withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } -} - -private func writeFloat(_ writer: inout [UInt8], _ value: Float) { - writeInt(&writer, value.bitPattern) -} - -private func writeDouble(_ writer: inout [UInt8], _ value: Double) { - writeInt(&writer, value.bitPattern) -} - -// Protocol for types that transfer other types across the FFI. This is -// analogous go the Rust trait of the same name. -private protocol FfiConverter { - associatedtype FfiType - associatedtype SwiftType - - static func lift(_ value: FfiType) throws -> SwiftType - static func lower(_ value: SwiftType) -> FfiType - static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType - static func write(_ value: SwiftType, into buf: inout [UInt8]) -} - -// Types conforming to `Primitive` pass themselves directly over the FFI. -private protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType {} - -extension FfiConverterPrimitive { - public static func lift(_ value: FfiType) throws -> SwiftType { - return value - } - - public static func lower(_ value: SwiftType) -> FfiType { - return value - } -} - -// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. -// Used for complex types where it's hard to write a custom lift/lower. -private protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} - -extension FfiConverterRustBuffer { - public static func lift(_ buf: RustBuffer) throws -> SwiftType { - var reader = createReader(data: Data(rustBuffer: buf)) - let value = try read(from: &reader) - if hasRemaining(reader) { - throw UniffiInternalError.incompleteData - } - buf.deallocate() - return value - } - - public static func lower(_ value: SwiftType) -> RustBuffer { - var writer = createWriter() - write(value, into: &writer) - return RustBuffer(bytes: writer) - } -} - -// An error type for FFI errors. These errors occur at the UniFFI level, not -// the library level. -private enum UniffiInternalError: LocalizedError { - case bufferOverflow - case incompleteData - case unexpectedOptionalTag - case unexpectedEnumCase - case unexpectedNullPointer - case unexpectedRustCallStatusCode - case unexpectedRustCallError - case unexpectedStaleHandle - case rustPanic(_ message: String) - - public var errorDescription: String? { - switch self { - case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" - case .incompleteData: return "The buffer still has data after lifting its containing value" - case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" - case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" - case .unexpectedNullPointer: return "Raw pointer value was null" - case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" - case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" - case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" - case let .rustPanic(message): return message - } - } -} - -private let CALL_SUCCESS: Int8 = 0 -private let CALL_ERROR: Int8 = 1 -private let CALL_PANIC: Int8 = 2 - -private extension RustCallStatus { - init() { - self.init( - code: CALL_SUCCESS, - errorBuf: RustBuffer( - capacity: 0, - len: 0, - data: nil - ) - ) - } -} - -private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { - try makeRustCall(callback, errorHandler: nil) -} - -private func rustCallWithError( - _ errorHandler: @escaping (RustBuffer) throws -> Error, - _ callback: (UnsafeMutablePointer) -> T -) throws -> T { - try makeRustCall(callback, errorHandler: errorHandler) -} - -private func makeRustCall( - _ callback: (UnsafeMutablePointer) -> T, - errorHandler: ((RustBuffer) throws -> Error)? -) throws -> T { - uniffiEnsureInitialized() - var callStatus = RustCallStatus() - let returnedVal = callback(&callStatus) - try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) - return returnedVal -} - -private func uniffiCheckCallStatus( - callStatus: RustCallStatus, - errorHandler: ((RustBuffer) throws -> Error)? -) throws { - switch callStatus.code { - case CALL_SUCCESS: - return - - case CALL_ERROR: - if let errorHandler = errorHandler { - throw try errorHandler(callStatus.errorBuf) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.unexpectedRustCallError - } - - case CALL_PANIC: - // When the rust code sees a panic, it tries to construct a RustBuffer - // with the message. But if that code panics, then it just sends back - // an empty buffer. - if callStatus.errorBuf.len > 0 { - throw try UniffiInternalError.rustPanic(FfiConverterString.lift(callStatus.errorBuf)) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.rustPanic("Rust panic") - } - - default: - throw UniffiInternalError.unexpectedRustCallStatusCode - } -} - -// Public interface members begin here. - -private struct FfiConverterUInt32: FfiConverterPrimitive { - typealias FfiType = UInt32 - typealias SwiftType = UInt32 - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { - return try lift(readInt(&buf)) - } - - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { - writeInt(&buf, lower(value)) - } -} - -private struct FfiConverterString: FfiConverter { - typealias SwiftType = String - typealias FfiType = RustBuffer - - public static func lift(_ value: RustBuffer) throws -> String { - defer { - value.deallocate() - } - if value.data == nil { - return String() - } - let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len)) - return String(bytes: bytes, encoding: String.Encoding.utf8)! - } - - public static func lower(_ value: String) -> RustBuffer { - return value.utf8CString.withUnsafeBufferPointer { ptr in - // The swift string gives us int8_t, we want uint8_t. - ptr.withMemoryRebound(to: UInt8.self) { ptr in - // The swift string gives us a trailing null byte, we don't want it. - let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) - return RustBuffer.from(buf) - } - } - } - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { - let len: Int32 = try readInt(&buf) - return try String(bytes: readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! - } - - public static func write(_ value: String, into buf: inout [UInt8]) { - let len = Int32(value.utf8.count) - writeInt(&buf, len) - writeBytes(&buf, value.utf8) - } -} - -public func add(a: UInt32, b: UInt32) -> UInt32 { - return try! FfiConverterUInt32.lift( - try! rustCall { - uniffi_mopro_fn_func_add( - FfiConverterUInt32.lower(a), - FfiConverterUInt32.lower(b), $0 - ) - } - ) -} - -public func hello() -> String { - return try! FfiConverterString.lift( - try! rustCall { - uniffi_mopro_fn_func_hello($0) - } - ) -} - -public func run() { - try! rustCall { - uniffi_mopro_fn_func_run($0) - } -} - -private enum InitializationResult { - case ok - case contractVersionMismatch - case apiChecksumMismatch -} - -// Use a global variables to perform the versioning checks. Swift ensures that -// the code inside is only computed once. -private var initializationResult: InitializationResult { - // Get the bindings contract version from our ComponentInterface - let bindings_contract_version = 22 - // Get the scaffolding contract version by calling the into the dylib - let scaffolding_contract_version = ffi_mopro_uniffi_contract_version() - if bindings_contract_version != scaffolding_contract_version { - return InitializationResult.contractVersionMismatch - } - if uniffi_mopro_checksum_func_add() != 19178 { - return InitializationResult.apiChecksumMismatch - } - if uniffi_mopro_checksum_func_hello() != 309 { - return InitializationResult.apiChecksumMismatch - } - if uniffi_mopro_checksum_func_run() != 17009 { - return InitializationResult.apiChecksumMismatch - } - - return InitializationResult.ok -} - -private func uniffiEnsureInitialized() { - switch initializationResult { - case .ok: - break - case .contractVersionMismatch: - fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") - case .apiChecksumMismatch: - fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } -} diff --git a/app/ios/mopro/mopro-ios/MoproKit/Resources/moproFFI.modulemap b/app/ios/mopro/mopro-ios/MoproKit/Resources/moproFFI.modulemap deleted file mode 100644 index 93b8adffb..000000000 --- a/app/ios/mopro/mopro-ios/MoproKit/Resources/moproFFI.modulemap +++ /dev/null @@ -1,6 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! -module moproFFI { - header "moproFFI.h" - export * -} \ No newline at end of file diff --git a/app/ios/mopro/mopro-ios/MoproKit/_Pods.xcodeproj b/app/ios/mopro/mopro-ios/MoproKit/_Pods.xcodeproj deleted file mode 120000 index 3c5a8e715..000000000 --- a/app/ios/mopro/mopro-ios/MoproKit/_Pods.xcodeproj +++ /dev/null @@ -1 +0,0 @@ -Example/Pods/Pods.xcodeproj \ No newline at end of file diff --git a/app/ios/mopro/mopro-ios/README.md b/app/ios/mopro/mopro-ios/README.md deleted file mode 100644 index 6c53f57e5..000000000 --- a/app/ios/mopro/mopro-ios/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# mopro-ios - -## Prepare - - - -Check the [Prepare](../README.md#prepare) and [Build Bindings](../README.md#build-bindings) steps in the root directory. - -## Execute - -Open the `MoproKit/Example/MoproKit.xcworkspace` in Xcode. -Use `command`+`R` to execute a simulator. - -## Linker problems? - -Add the following settings after - -1. `MoproKit/Example/Pods/Target Support Files/MoproKit/MoproKit.debug.xcconfig` -2. `MoproKit/Example/Pods/Target Support Files/MoproKit/MoproKit.release.xcconfig` - -files - -``` -LIBRARY_SEARCH_PATHS=${SRCROOT}/../../Libs -OTHER_LDFLAGS=-lmopro_ffi -USER_HEADER_SEARCH_PATHS=${SRCROOT}/../../include -``` - -## Tests for the example app - -There are two ways to run tests for the example app: - -1. Xcode - Open the `MoproKit/Example/MoproKit.xcworkspace` in Xcode. - Use `command`+`U` to run tests. - -2. CLI - Run tests with command line: - - ```sh - cd MoproKit/Example - xcodebuild test -scheme MoproKit-Example \ - -workspace MoproKit.xcworkspace \ - -destination "platform=iOS Simulator,OS=17.0.1,name=iPhone 15 Pro" - ``` - - Check your simulator version and the OS with: - - ```sh - xcodebuild -showdestinations -workspace MoproKit.xcworkspace -scheme MoproKit-Example - ``` diff --git a/app/ios/mopro/mopro-ios/Sources/mopro.swift b/app/ios/mopro/mopro-ios/Sources/mopro.swift deleted file mode 100644 index 59edffd02..000000000 --- a/app/ios/mopro/mopro-ios/Sources/mopro.swift +++ /dev/null @@ -1,411 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! -import Foundation - -// Depending on the consumer's build setup, the low-level FFI code -// might be in a separate module, or it might be compiled inline into -// this module. This is a bit of light hackery to work with both. -#if canImport(moproFFI) - import moproFFI -#endif - -private extension RustBuffer { - // Allocate a new buffer, copying the contents of a `UInt8` array. - init(bytes: [UInt8]) { - let rbuf = bytes.withUnsafeBufferPointer { ptr in - RustBuffer.from(ptr) - } - self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) - } - - static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { - try! rustCall { ffi_mopro_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } - } - - // Frees the buffer in place. - // The buffer must not be used after this is called. - func deallocate() { - try! rustCall { ffi_mopro_rustbuffer_free(self, $0) } - } -} - -private extension ForeignBytes { - init(bufferPointer: UnsafeBufferPointer) { - self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) - } -} - -// For every type used in the interface, we provide helper methods for conveniently -// lifting and lowering that type from C-compatible data, and for reading and writing -// values of that type in a buffer. - -// Helper classes/extensions that don't change. -// Someday, this will be in a library of its own. - -private extension Data { - init(rustBuffer: RustBuffer) { - // TODO: This copies the buffer. Can we read directly from a - // Rust buffer? - self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) - } -} - -// Define reader functionality. Normally this would be defined in a class or -// struct, but we use standalone functions instead in order to make external -// types work. -// -// With external types, one swift source file needs to be able to call the read -// method on another source file's FfiConverter, but then what visibility -// should Reader have? -// - If Reader is fileprivate, then this means the read() must also -// be fileprivate, which doesn't work with external types. -// - If Reader is internal/public, we'll get compile errors since both source -// files will try define the same type. -// -// Instead, the read() method and these helper functions input a tuple of data - -private func createReader(data: Data) -> (data: Data, offset: Data.Index) { - (data: data, offset: 0) -} - -// Reads an integer at the current offset, in big-endian order, and advances -// the offset on success. Throws if reading the integer would move the -// offset past the end of the buffer. -private func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { - let range = reader.offset ..< reader.offset + MemoryLayout.size - guard reader.data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - if T.self == UInt8.self { - let value = reader.data[reader.offset] - reader.offset += 1 - return value as! T - } - var value: T = 0 - let _ = withUnsafeMutableBytes(of: &value) { reader.data.copyBytes(to: $0, from: range) } - reader.offset = range.upperBound - return value.bigEndian -} - -// Reads an arbitrary number of bytes, to be used to read -// raw bytes, this is useful when lifting strings -private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> [UInt8] { - let range = reader.offset ..< (reader.offset + count) - guard reader.data.count >= range.upperBound else { - throw UniffiInternalError.bufferOverflow - } - var value = [UInt8](repeating: 0, count: count) - value.withUnsafeMutableBufferPointer { buffer in - reader.data.copyBytes(to: buffer, from: range) - } - reader.offset = range.upperBound - return value -} - -// Reads a float at the current offset. -private func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { - return try Float(bitPattern: readInt(&reader)) -} - -// Reads a float at the current offset. -private func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { - return try Double(bitPattern: readInt(&reader)) -} - -// Indicates if the offset has reached the end of the buffer. -private func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { - return reader.offset < reader.data.count -} - -// Define writer functionality. Normally this would be defined in a class or -// struct, but we use standalone functions instead in order to make external -// types work. See the above discussion on Readers for details. - -private func createWriter() -> [UInt8] { - return [] -} - -private func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { - writer.append(contentsOf: byteArr) -} - -// Writes an integer in big-endian order. -// -// Warning: make sure what you are trying to write -// is in the correct type! -private func writeInt(_ writer: inout [UInt8], _ value: T) { - var value = value.bigEndian - withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } -} - -private func writeFloat(_ writer: inout [UInt8], _ value: Float) { - writeInt(&writer, value.bitPattern) -} - -private func writeDouble(_ writer: inout [UInt8], _ value: Double) { - writeInt(&writer, value.bitPattern) -} - -// Protocol for types that transfer other types across the FFI. This is -// analogous go the Rust trait of the same name. -private protocol FfiConverter { - associatedtype FfiType - associatedtype SwiftType - - static func lift(_ value: FfiType) throws -> SwiftType - static func lower(_ value: SwiftType) -> FfiType - static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType - static func write(_ value: SwiftType, into buf: inout [UInt8]) -} - -// Types conforming to `Primitive` pass themselves directly over the FFI. -private protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType {} - -extension FfiConverterPrimitive { - public static func lift(_ value: FfiType) throws -> SwiftType { - return value - } - - public static func lower(_ value: SwiftType) -> FfiType { - return value - } -} - -// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. -// Used for complex types where it's hard to write a custom lift/lower. -private protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} - -extension FfiConverterRustBuffer { - public static func lift(_ buf: RustBuffer) throws -> SwiftType { - var reader = createReader(data: Data(rustBuffer: buf)) - let value = try read(from: &reader) - if hasRemaining(reader) { - throw UniffiInternalError.incompleteData - } - buf.deallocate() - return value - } - - public static func lower(_ value: SwiftType) -> RustBuffer { - var writer = createWriter() - write(value, into: &writer) - return RustBuffer(bytes: writer) - } -} - -// An error type for FFI errors. These errors occur at the UniFFI level, not -// the library level. -private enum UniffiInternalError: LocalizedError { - case bufferOverflow - case incompleteData - case unexpectedOptionalTag - case unexpectedEnumCase - case unexpectedNullPointer - case unexpectedRustCallStatusCode - case unexpectedRustCallError - case unexpectedStaleHandle - case rustPanic(_ message: String) - - public var errorDescription: String? { - switch self { - case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" - case .incompleteData: return "The buffer still has data after lifting its containing value" - case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" - case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" - case .unexpectedNullPointer: return "Raw pointer value was null" - case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" - case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" - case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" - case let .rustPanic(message): return message - } - } -} - -private let CALL_SUCCESS: Int8 = 0 -private let CALL_ERROR: Int8 = 1 -private let CALL_PANIC: Int8 = 2 - -private extension RustCallStatus { - init() { - self.init( - code: CALL_SUCCESS, - errorBuf: RustBuffer( - capacity: 0, - len: 0, - data: nil - ) - ) - } -} - -private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { - try makeRustCall(callback, errorHandler: nil) -} - -private func rustCallWithError( - _ errorHandler: @escaping (RustBuffer) throws -> Error, - _ callback: (UnsafeMutablePointer) -> T -) throws -> T { - try makeRustCall(callback, errorHandler: errorHandler) -} - -private func makeRustCall( - _ callback: (UnsafeMutablePointer) -> T, - errorHandler: ((RustBuffer) throws -> Error)? -) throws -> T { - uniffiEnsureInitialized() - var callStatus = RustCallStatus() - let returnedVal = callback(&callStatus) - try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) - return returnedVal -} - -private func uniffiCheckCallStatus( - callStatus: RustCallStatus, - errorHandler: ((RustBuffer) throws -> Error)? -) throws { - switch callStatus.code { - case CALL_SUCCESS: - return - - case CALL_ERROR: - if let errorHandler = errorHandler { - throw try errorHandler(callStatus.errorBuf) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.unexpectedRustCallError - } - - case CALL_PANIC: - // When the rust code sees a panic, it tries to construct a RustBuffer - // with the message. But if that code panics, then it just sends back - // an empty buffer. - if callStatus.errorBuf.len > 0 { - throw try UniffiInternalError.rustPanic(FfiConverterString.lift(callStatus.errorBuf)) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.rustPanic("Rust panic") - } - - default: - throw UniffiInternalError.unexpectedRustCallStatusCode - } -} - -// Public interface members begin here. - -private struct FfiConverterUInt32: FfiConverterPrimitive { - typealias FfiType = UInt32 - typealias SwiftType = UInt32 - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { - return try lift(readInt(&buf)) - } - - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { - writeInt(&buf, lower(value)) - } -} - -private struct FfiConverterString: FfiConverter { - typealias SwiftType = String - typealias FfiType = RustBuffer - - public static func lift(_ value: RustBuffer) throws -> String { - defer { - value.deallocate() - } - if value.data == nil { - return String() - } - let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len)) - return String(bytes: bytes, encoding: String.Encoding.utf8)! - } - - public static func lower(_ value: String) -> RustBuffer { - return value.utf8CString.withUnsafeBufferPointer { ptr in - // The swift string gives us int8_t, we want uint8_t. - ptr.withMemoryRebound(to: UInt8.self) { ptr in - // The swift string gives us a trailing null byte, we don't want it. - let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) - return RustBuffer.from(buf) - } - } - } - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { - let len: Int32 = try readInt(&buf) - return try String(bytes: readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! - } - - public static func write(_ value: String, into buf: inout [UInt8]) { - let len = Int32(value.utf8.count) - writeInt(&buf, len) - writeBytes(&buf, value.utf8) - } -} - -public func add(a: UInt32, b: UInt32) -> UInt32 { - return try! FfiConverterUInt32.lift( - try! rustCall { - uniffi_mopro_fn_func_add( - FfiConverterUInt32.lower(a), - FfiConverterUInt32.lower(b), $0 - ) - } - ) -} - -public func hello() -> String { - return try! FfiConverterString.lift( - try! rustCall { - uniffi_mopro_fn_func_hello($0) - } - ) -} - -public func run() { - try! rustCall { - uniffi_mopro_fn_func_run($0) - } -} - -private enum InitializationResult { - case ok - case contractVersionMismatch - case apiChecksumMismatch -} - -// Use a global variables to perform the versioning checks. Swift ensures that -// the code inside is only computed once. -private var initializationResult: InitializationResult { - // Get the bindings contract version from our ComponentInterface - let bindings_contract_version = 22 - // Get the scaffolding contract version by calling the into the dylib - let scaffolding_contract_version = ffi_mopro_uniffi_contract_version() - if bindings_contract_version != scaffolding_contract_version { - return InitializationResult.contractVersionMismatch - } - if uniffi_mopro_checksum_func_add() != 19178 { - return InitializationResult.apiChecksumMismatch - } - if uniffi_mopro_checksum_func_hello() != 309 { - return InitializationResult.apiChecksumMismatch - } - if uniffi_mopro_checksum_func_run() != 17009 { - return InitializationResult.apiChecksumMismatch - } - - return InitializationResult.ok -} - -private func uniffiEnsureInitialized() { - switch initializationResult { - case .ok: - break - case .contractVersionMismatch: - fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") - case .apiChecksumMismatch: - fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } -} diff --git a/app/ios/mopro/mopro-ios/headers/moproFFI.h b/app/ios/mopro/mopro-ios/headers/moproFFI.h deleted file mode 100644 index 0d7647eb0..000000000 --- a/app/ios/mopro/mopro-ios/headers/moproFFI.h +++ /dev/null @@ -1,96 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! - -#pragma once - -#include -#include -#include - -// The following structs are used to implement the lowest level -// of the FFI, and thus useful to multiple uniffied crates. -// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H. -#ifdef UNIFFI_SHARED_H - // We also try to prevent mixing versions of shared uniffi header structs. - // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4 - #ifndef UNIFFI_SHARED_HEADER_V4 - #error Combining helper code from multiple versions of uniffi is not supported - #endif // ndef UNIFFI_SHARED_HEADER_V4 -#else -#define UNIFFI_SHARED_H -#define UNIFFI_SHARED_HEADER_V4 -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ - -typedef struct RustBuffer -{ - int32_t capacity; - int32_t len; - uint8_t *_Nullable data; -} RustBuffer; - -typedef int32_t (*ForeignCallback)(uint64_t, int32_t, const uint8_t *_Nonnull, int32_t, RustBuffer *_Nonnull); - -// Task defined in Rust that Swift executes -typedef void (*UniFfiRustTaskCallback)(const void * _Nullable); - -// Callback to execute Rust tasks using a Swift Task -// -// Args: -// executor: ForeignExecutor lowered into a size_t value -// delay: Delay in MS -// task: UniFfiRustTaskCallback to call -// task_data: data to pass the task callback -typedef void (*UniFfiForeignExecutorCallback)(size_t, uint32_t, UniFfiRustTaskCallback _Nullable, const void * _Nullable); - -typedef struct ForeignBytes -{ - int32_t len; - const uint8_t *_Nullable data; -} ForeignBytes; - -// Error definitions -typedef struct RustCallStatus { - int8_t code; - RustBuffer errorBuf; -} RustCallStatus; - -// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️ -// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ -#endif // def UNIFFI_SHARED_H - -// Callbacks for UniFFI Futures -typedef void (*UniFfiFutureCallbackUInt8)(const void * _Nonnull, uint8_t, RustCallStatus); -typedef void (*UniFfiFutureCallbackUInt32)(const void * _Nonnull, uint32_t, RustCallStatus); -typedef void (*UniFfiFutureCallbackRustBuffer)(const void * _Nonnull, RustBuffer, RustCallStatus); - -// Scaffolding functions -uint32_t uniffi_mopro_fn_func_add(uint32_t a, uint32_t b, RustCallStatus *_Nonnull out_status -); -RustBuffer uniffi_mopro_fn_func_hello(RustCallStatus *_Nonnull out_status - -); -void uniffi_mopro_fn_func_run(RustCallStatus *_Nonnull out_status - -); -RustBuffer ffi_mopro_rustbuffer_alloc(int32_t size, RustCallStatus *_Nonnull out_status -); -RustBuffer ffi_mopro_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status -); -void ffi_mopro_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status -); -RustBuffer ffi_mopro_rustbuffer_reserve(RustBuffer buf, int32_t additional, RustCallStatus *_Nonnull out_status -); -uint16_t uniffi_mopro_checksum_func_add(void - -); -uint16_t uniffi_mopro_checksum_func_hello(void - -); -uint16_t uniffi_mopro_checksum_func_run(void - -); -uint32_t ffi_mopro_uniffi_contract_version(void - -); - diff --git a/app/ios/mopro/mopro-ios/headers/moproFFI.modulemap b/app/ios/mopro/mopro-ios/headers/moproFFI.modulemap deleted file mode 100644 index 93b8adffb..000000000 --- a/app/ios/mopro/mopro-ios/headers/moproFFI.modulemap +++ /dev/null @@ -1,6 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! -module moproFFI { - header "moproFFI.h" - export * -} \ No newline at end of file From 650345416cecb8e251b09b6e9c798f206fcc8560 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Mon, 15 Jan 2024 13:57:22 +0100 Subject: [PATCH 04/12] working with proof of passport proof --- app/README.md | 20 ++++- .../ProofOfPassport.xcodeproj/project.pbxproj | 6 ++ app/ios/Prover.swift | 89 +++---------------- app/ios/post_install.sh | 22 +++++ 4 files changed, 60 insertions(+), 77 deletions(-) create mode 100755 app/ios/post_install.sh diff --git a/app/README.md b/app/README.md index 291b70206..dec87f5d0 100644 --- a/app/README.md +++ b/app/README.md @@ -21,7 +21,7 @@ yarn Go to the `circuit` folder of the monorepo and build the circuit. -#### Build native lib +#### Build on Android In `/script`, run: ``` @@ -52,3 +52,21 @@ cd android ./gradlew assembleRelease ``` The built apk it located at `android/app/build/outputs/apk/release/app-release.apk` + +#### Build on iOS + +The iOS app uses [mopro](https://github.com/oskarth/mopro), which is under development. +It does not provide a pod/cli right now, so we will pull it and build it. Make sure you have space on your disk. + +Go to [our fork](https://github.com/0xturboblitz/mopro) of mopro and follow the build instructions. +Once you have built `mopro/mopro-ffi/target/${ARCHITECTURE}/${LIB_DIR}/libmopro_ffi.a` copy it here to `app/ios/MoproKit/Libs` + +Now: +``` +cd ios +pod install +./post_install.sh +``` + + + diff --git a/app/ios/ProofOfPassport.xcodeproj/project.pbxproj b/app/ios/ProofOfPassport.xcodeproj/project.pbxproj index 234daae04..09e5ac29c 100644 --- a/app/ios/ProofOfPassport.xcodeproj/project.pbxproj +++ b/app/ios/ProofOfPassport.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 00E356F31AD99517003FC87E /* ProofOfPassportTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ProofOfPassportTests.m */; }; 05BD9DCC2B548AA900823023 /* MoproKit in Resources */ = {isa = PBXBuildFile; fileRef = 05BD9DCB2B548AA900823023 /* MoproKit */; }; + 05BD9DCE2B554FA300823023 /* libmopro_ffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 05BD9DCD2B554FA300823023 /* libmopro_ffi.a */; }; 05EDEDC62B52D25D00AA51AD /* Prover.m in Sources */ = {isa = PBXBuildFile; fileRef = 05EDEDC42B52D25D00AA51AD /* Prover.m */; }; 05EDEDC72B52D25D00AA51AD /* Prover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05EDEDC52B52D25D00AA51AD /* Prover.swift */; }; 0651723A94C70A2B31E3E4F8 /* Pods_ProofOfPassport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAAF621B99F62C9ED35AA07 /* Pods_ProofOfPassport.framework */; }; @@ -38,6 +39,7 @@ 00E356F21AD99517003FC87E /* ProofOfPassportTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProofOfPassportTests.m; sourceTree = ""; }; 05A0773D2B5333CE0037E489 /* MoproKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MoproKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 05BD9DCB2B548AA900823023 /* MoproKit */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MoproKit; sourceTree = ""; }; + 05BD9DCD2B554FA300823023 /* libmopro_ffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmopro_ffi.a; path = MoproKit/Libs/libmopro_ffi.a; sourceTree = ""; }; 05EDEDC42B52D25D00AA51AD /* Prover.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Prover.m; sourceTree = ""; }; 05EDEDC52B52D25D00AA51AD /* Prover.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Prover.swift; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* ProofOfPassport.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ProofOfPassport.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -75,6 +77,7 @@ buildActionMask = 2147483647; files = ( 0651723A94C70A2B31E3E4F8 /* Pods_ProofOfPassport.framework in Frameworks */, + 05BD9DCE2B554FA300823023 /* libmopro_ffi.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -110,6 +113,7 @@ 13B07FB01A68108700A75B9A /* AppDelegate.mm */, 13B07FB51A68108700A75B9A /* Images.xcassets */, 13B07FB61A68108700A75B9A /* Info.plist */, + 05BD9DCD2B554FA300823023 /* libmopro_ffi.a */, 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, 13B07FB71A68108700A75B9A /* main.m */, 905B70042A72767900AFA232 /* PassportReader.swift */, @@ -496,6 +500,7 @@ "$(SDKROOT)/usr/lib/swift", "$(inherited)", "$(PROJECT_DIR)", + "$(PROJECT_DIR)/MoproKit/Libs", ); MARKETING_VERSION = 1.0; OTHER_LDFLAGS = ( @@ -530,6 +535,7 @@ "$(SDKROOT)/usr/lib/swift", "$(inherited)", "$(PROJECT_DIR)", + "$(PROJECT_DIR)/MoproKit/Libs", ); MARKETING_VERSION = 1.0; OTHER_LDFLAGS = ( diff --git a/app/ios/Prover.swift b/app/ios/Prover.swift index 21eef4a01..54b09ece2 100644 --- a/app/ios/Prover.swift +++ b/app/ios/Prover.swift @@ -48,85 +48,22 @@ class Prover: NSObject { // Logic for prove (generate_proof2) do { // Prepare inputs - let signature: [String] = [ - "3582320600048169363", - "7163546589759624213", - "18262551396327275695", - "4479772254206047016", - "1970274621151677644", - "6547632513799968987", - "921117808165172908", - "7155116889028933260", - "16769940396381196125", - "17141182191056257954", - "4376997046052607007", - "17471823348423771450", - "16282311012391954891", - "70286524413490741", - "1588836847166444745", - "15693430141227594668", - "13832254169115286697", - "15936550641925323613", - "323842208142565220", - "6558662646882345749", - "15268061661646212265", - "14962976685717212593", - "15773505053543368901", - "9586594741348111792", - "1455720481014374292", - "13945813312010515080", - "6352059456732816887", - "17556873002865047035", - "2412591065060484384", - "11512123092407778330", - "8499281165724578877", - "12768005853882726493", - ] - - let modulus: [String] = [ - "13792647154200341559", - "12773492180790982043", - "13046321649363433702", - "10174370803876824128", - "7282572246071034406", - "1524365412687682781", - "4900829043004737418", - "6195884386932410966", - "13554217876979843574", - "17902692039595931737", - "12433028734895890975", - "15971442058448435996", - "4591894758077129763", - "11258250015882429548", - "16399550288873254981", - "8246389845141771315", - "14040203746442788850", - "7283856864330834987", - "12297563098718697441", - "13560928146585163504", - "7380926829734048483", - "14591299561622291080", - "8439722381984777599", - "17375431987296514829", - "16727607878674407272", - "3233954801381564296", - "17255435698225160983", - "15093748890170255670", - "15810389980847260072", - "11120056430439037392", - "5866130971823719482", - "13327552690270163501", - ] - - let base_message: [String] = ["18114495772705111902", "2254271930739856077", - "2068851770", "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","0", - ] + let mrz: [String] = ["97","91","95","31","88","80","60","70","82","65","68","85","80","79","78","84","60","60","65","76","80","72","79","78","83","69","60","72","85","71","85","69","83","60","65","76","66","69","82","84","60","60","60","60","60","60","60","60","60","50","52","72","66","56","49","56","51","50","52","70","82","65","48","52","48","50","49","49","49","77","51","49","49","49","49","49","53","60","60","60","60","60","60","60","60","60","60","60","60","60","60","48","50"] + let reveal_bitmap: [String] = ["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","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","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","0","0","0","0"] + let dataHashes: [String] = ["48","130","1","37","2","1","0","48","11","6","9","96","134","72","1","101","3","4","2","1","48","130","1","17","48","37","2","1","1","4","32","176","223","31","133","108","84","158","102","70","11","165","175","196","12","201","130","25","131","46","125","156","194","28","23","55","133","157","164","135","136","220","78","48","37","2","1","2","4","32","190","82","180","235","222","33","79","50","152","136","142","35","116","224","6","242","156","141","128","248","10","61","98","86","248","45","207","210","90","232","175","38","48","37","2","1","3","4","32","0","194","104","108","237","246","97","230","116","198","69","110","26","87","17","89","110","199","108","250","36","21","39","87","110","102","250","213","174","131","171","174","48","37","2","1","11","4","32","136","155","87","144","111","15","152","127","85","25","154","81","20","58","51","75","193","116","234","0","60","30","29","30","183","141","72","247","255","203","100","124","48","37","2","1","12","4","32","41","234","106","78","31","11","114","137","237","17","92","71","134","47","62","78","189","233","201","214","53","4","47","189","201","133","6","121","34","131","64","142","48","37","2","1","13","4","32","91","222","210","193","62","222","104","82","36","41","138","253","70","15","148","208","156","45","105","171","241","195","185","43","217","162","146","201","222","89","238","38","48","37","2","1","14","4","32","76","123","216","13","51","227","72","245","59","193","238","166","103","49","23","164","171","188","194","197","156","187","249","28","198","95","69","15","182","56","54","38"] + let eContentBytes: [String] = ["49","102","48","21","6","9","42","134","72","134","247","13","1","9","3","49","8","6","6","103","129","8","1","1","1","48","28","6","9","42","134","72","134","247","13","1","9","5","49","15","23","13","49","57","49","50","49","54","49","55","50","50","51","56","90","48","47","6","9","42","134","72","134","247","13","1","9","4","49","34","4","32","32","85","108","174","127","112","178","182","8","43","134","123","192","211","131","66","184","240","212","181","240","180","106","195","24","117","54","129","19","10","250","53"] + let signature: [String] = ["7924608050410952186","18020331358710788578","8570093713362871693","158124167841380627","11368970785933558334","13741644704804016484","3255497432248429697","18325134696633464276","11159517223698754974","14221210644107127310","18395843719389189885","14516795783073238806","2008163829408627473","10489977208787195755","11349558951945231290","10261182129521943851","898517390497363184","7991226362010359134","16695870541274258886","3471091665352332245","9966265751297511656","15030994431171601215","10723494832064770597","14939163534927288303","13596611050508022203","12058746125656824488","7806259275107295093","9171418878976478189","16438005721800053020","315207309308375554","3950355816720285857","5415176625244763446"] + let pubkey: [String] = ["10501872816920780427","9734403015003984321","14411195268255541454","5140370262757446136","442944543003039303","2084906169692591819","13619051978156646232","11308439966240653768","11784026229075891869","3619707049269329199","14678094225574041482","13372281921787791985","5760458619375959191","1351001273751492154","9127780359628047919","5377643070972775368","14145972494784958946","295160036043261024","12244573192558293296","13273111070076476096","15787778596745267629","12026125372525341435","17186889501189543072","1678833675164196298","11525741336698300342","9004411014119053043","3653149686233893817","3525782291631180893","13397424121878903415","12208454420188007950","5024240771370648155","15842149209258762075"] + let address: [String] = ["897585614395172552642670145532424661022951192962"] // decimal of 0x9D392187c08fc28A86e1354aD63C70897165b982 var inputs = [String: [String]]() + inputs["mrz"] = mrz; + inputs["reveal_bitmap"] = reveal_bitmap; + inputs["dataHashes"] = dataHashes; + inputs["eContentBytes"] = eContentBytes; inputs["signature"] = signature; - inputs["modulus"] = modulus; - inputs["base_message"] = base_message; + inputs["pubkey"] = pubkey; + inputs["address"] = address; let start = CFAbsoluteTimeGetCurrent() diff --git a/app/ios/post_install.sh b/app/ios/post_install.sh new file mode 100755 index 000000000..1f28dad6a --- /dev/null +++ b/app/ios/post_install.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# update xcconfig +MODES="debug release" +XCCONFIG_PATH=Pods/Target\ Support\ Files/MoproKit +CONFIGS=" +LIBRARY_SEARCH_PATHS=\${SRCROOT}/../MoproKit/Libs +OTHER_LDFLAGS=-lmopro_ffi +USER_HEADER_SEARCH_PATHS=\${SRCROOT}/../MoproKit/include +" +for mode in ${MODES} +do + FILE_NAME=${XCCONFIG_PATH}/MoproKit.${mode}.xcconfig + for config in ${CONFIGS}; do + EXIST=$(grep -c "${config}" "${FILE_NAME}") + if [[ $EXIST -eq 0 ]]; then + echo "${config}" >> "${FILE_NAME}" + fi + done +done + +echo "Finished updating xcconfig" \ No newline at end of file From e8e34315bb978d571f387401d7033d5a1767d5f1 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Mon, 15 Jan 2024 18:21:40 +0100 Subject: [PATCH 05/12] add ark-zkey, mopro-core and mopro-ffi --- app/ark-zkey/.gitignore | 14 + app/ark-zkey/Cargo.toml | 32 + app/ark-zkey/README.md | 52 ++ app/ark-zkey/src/bin/arkzkey_util.rs | 36 + app/ark-zkey/src/lib.rs | 247 +++++ app/mopro-core/.gitignore | 14 + app/mopro-core/Cargo.toml | 51 ++ app/mopro-core/README.md | 47 + app/mopro-core/build.rs | 95 ++ app/mopro-core/src/lib.rs | 8 + app/mopro-core/src/middleware/circom/mod.rs | 860 ++++++++++++++++++ .../src/middleware/circom/serialization.rs | 106 +++ app/mopro-core/src/middleware/circom/utils.rs | 33 + app/mopro-core/src/middleware/mod.rs | 1 + app/mopro-ffi/.gitignore | 18 + app/mopro-ffi/Cargo.toml | 47 + app/mopro-ffi/Makefile | 16 + app/mopro-ffi/README.md | 48 + app/mopro-ffi/build.rs | 3 + app/mopro-ffi/src/lib.rs | 295 ++++++ app/mopro-ffi/src/mopro.udl | 43 + app/mopro-ffi/tests/bindings/test_mopro.kts | 21 + app/mopro-ffi/tests/bindings/test_mopro.swift | 65 ++ .../tests/bindings/test_mopro_keccak.kts | 279 ++++++ .../tests/bindings/test_mopro_keccak.swift | 82 ++ .../tests/bindings/test_mopro_keccak2.kts | 273 ++++++ .../tests/bindings/test_mopro_keccak2.swift | 86 ++ .../tests/bindings/test_mopro_rsa.kts | 115 +++ .../tests/bindings/test_mopro_rsa.swift | 174 ++++ .../tests/bindings/test_mopro_rsa2.swift | 167 ++++ .../tests/test_generated_bindings.rs | 13 + app/mopro-ffi/uniffi-bindgen.rs | 3 + app/mopro-ffi/uniffi.toml | 2 + 33 files changed, 3346 insertions(+) create mode 100644 app/ark-zkey/.gitignore create mode 100644 app/ark-zkey/Cargo.toml create mode 100644 app/ark-zkey/README.md create mode 100644 app/ark-zkey/src/bin/arkzkey_util.rs create mode 100644 app/ark-zkey/src/lib.rs create mode 100644 app/mopro-core/.gitignore create mode 100644 app/mopro-core/Cargo.toml create mode 100644 app/mopro-core/README.md create mode 100644 app/mopro-core/build.rs create mode 100644 app/mopro-core/src/lib.rs create mode 100644 app/mopro-core/src/middleware/circom/mod.rs create mode 100644 app/mopro-core/src/middleware/circom/serialization.rs create mode 100644 app/mopro-core/src/middleware/circom/utils.rs create mode 100644 app/mopro-core/src/middleware/mod.rs create mode 100644 app/mopro-ffi/.gitignore create mode 100644 app/mopro-ffi/Cargo.toml create mode 100644 app/mopro-ffi/Makefile create mode 100644 app/mopro-ffi/README.md create mode 100644 app/mopro-ffi/build.rs create mode 100644 app/mopro-ffi/src/lib.rs create mode 100644 app/mopro-ffi/src/mopro.udl create mode 100644 app/mopro-ffi/tests/bindings/test_mopro.kts create mode 100644 app/mopro-ffi/tests/bindings/test_mopro.swift create mode 100644 app/mopro-ffi/tests/bindings/test_mopro_keccak.kts create mode 100644 app/mopro-ffi/tests/bindings/test_mopro_keccak.swift create mode 100644 app/mopro-ffi/tests/bindings/test_mopro_keccak2.kts create mode 100644 app/mopro-ffi/tests/bindings/test_mopro_keccak2.swift create mode 100644 app/mopro-ffi/tests/bindings/test_mopro_rsa.kts create mode 100644 app/mopro-ffi/tests/bindings/test_mopro_rsa.swift create mode 100644 app/mopro-ffi/tests/bindings/test_mopro_rsa2.swift create mode 100644 app/mopro-ffi/tests/test_generated_bindings.rs create mode 100644 app/mopro-ffi/uniffi-bindgen.rs create mode 100644 app/mopro-ffi/uniffi.toml diff --git a/app/ark-zkey/.gitignore b/app/ark-zkey/.gitignore new file mode 100644 index 000000000..6985cf1bd --- /dev/null +++ b/app/ark-zkey/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/app/ark-zkey/Cargo.toml b/app/ark-zkey/Cargo.toml new file mode 100644 index 000000000..97c4985d0 --- /dev/null +++ b/app/ark-zkey/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "ark-zkey" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[[bin]] +name = "arkzkey-util" +path = "src/bin/arkzkey_util.rs" + +# XXX: Shouldn't be necessary, but this way we stay consistent with wasmer version and fix +# error[E0432]: unresolved import `wasmer` error +# (likely due to other packages) +[patch.crates-io] +# NOTE: Forked wasmer to work around memory limits +# See https://github.com/wasmerio/wasmer/commit/09c7070 +wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" } + +[dependencies] +color-eyre = "0.6" +memmap2 = "0.9" +flame = "0.2" +flamer = "0.5" + +ark-serialize = { version = "=0.4.1", features = ["derive"] } +ark-bn254 = { version = "=0.4.0" } +ark-groth16 = { version = "=0.4.0" } +ark-circom = { git = "https://github.com/arkworks-rs/circom-compat.git" } +ark-relations = { version = "=0.4.0" } +ark-ff = { version = "=0.4.1" } +ark-ec = { version = "=0.4.1" } diff --git a/app/ark-zkey/README.md b/app/ark-zkey/README.md new file mode 100644 index 000000000..4fda435a9 --- /dev/null +++ b/app/ark-zkey/README.md @@ -0,0 +1,52 @@ +# ark-zkey + +Library to read `zkey` faster by serializing to `arkworks` friendly format. + +See https://github.com/oskarth/mopro/issues/25 for context. + +## How to use + +Run the following to convert a `zkey` to an `arkzkey`. This should be done as a pre-processing step. + +`cargo run --bin arkzkey-util --release -- ../mopro-core/examples/circom/keccak256/target/keccak256_256_test_final.zkey` + +This will generate and place an `arkzkey` file in the same directory as the original zkey. + +You can also install it locally: + +`cargo install --bin arkzkey-util --path . --release` + +## Tests + +``` +cargo test multiplier2 --release -- --nocapture +cargo test keccak256 --release -- --nocapture +cargo test rsa --release -- --nocapture +``` + +## Benchmark (Keccak) + +`cargo test keccak256 --release -- --nocapture` + +``` +[build] Processing zkey data... +test tests::test_keccak256_serialization_deserialization has been running for over 60 seconds +[build]Time to process zkey data: 158.753181958s +[build] Serializing proving key and constraint matrices +[build] Time to serialize proving key and constraint matrices: 42ns +[build] Writing arkzkey to: ../mopro-core/examples/circom/keccak256/target/keccak256_256_test_final.arkzkey +[build] Time to write arkzkey: 16.204274125s +Reading arkzkey from: ../mopro-core/examples/circom/keccak256/target/keccak256_256_test_final.arkzkey +Time to open arkzkey file: 51.75µs +Time to mmap arkzkey: 17.25µs +Time to deserialize proving key: 18.323550083s +Time to deserialize matrices: 46.935792ms +Time to read arkzkey: 18.3730695s +test tests::test_keccak256_serialization_deserialization ... ok +``` + +Vs naive: + +`[build] Time to process zkey data: 158.753181958s` + +**Result: 18s vs 158s** \ No newline at end of file diff --git a/app/ark-zkey/src/bin/arkzkey_util.rs b/app/ark-zkey/src/bin/arkzkey_util.rs new file mode 100644 index 000000000..130a93a2b --- /dev/null +++ b/app/ark-zkey/src/bin/arkzkey_util.rs @@ -0,0 +1,36 @@ +use std::env; +use std::path::{Path, PathBuf}; + +extern crate ark_zkey; +use ark_zkey::{convert_zkey, read_proving_key_and_matrices_from_zkey}; + +fn main() -> color_eyre::eyre::Result<()> { + color_eyre::install()?; + + let args: Vec = env::args().collect(); + if args.len() != 2 { + eprintln!("Usage: zkey_to_arkzkey "); + std::process::exit(1); + } + + let zkey_path = &args[1]; + let (proving_key, constraint_matrices) = read_proving_key_and_matrices_from_zkey(zkey_path)?; + + let arkzkey_path = get_arkzkey_path(zkey_path); + let arkzkey_path_str = arkzkey_path + .to_str() + .ok_or_else(|| color_eyre::eyre::eyre!("Failed to convert arkzkey path to string"))?; + + convert_zkey(proving_key, constraint_matrices, &arkzkey_path_str)?; + + println!("Converted zkey file saved to: {}", arkzkey_path.display()); + + Ok(()) +} + +fn get_arkzkey_path(zkey_path: &str) -> PathBuf { + let path = Path::new(zkey_path); + let mut arkzkey_path = path.to_path_buf(); + arkzkey_path.set_extension("arkzkey"); + arkzkey_path +} diff --git a/app/ark-zkey/src/lib.rs b/app/ark-zkey/src/lib.rs new file mode 100644 index 000000000..a41c84a92 --- /dev/null +++ b/app/ark-zkey/src/lib.rs @@ -0,0 +1,247 @@ +use ark_bn254::{Bn254, Fr}; +use ark_circom::read_zkey; +//use ark_ec::pairing::Pairing; +use ark_ff::Field; +use ark_groth16::ProvingKey; +//use ark_groth16::VerifyingKey; +use ark_relations::r1cs::ConstraintMatrices; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use color_eyre::eyre::{Result, WrapErr}; +use memmap2::Mmap; +use std::fs::File; +//use std::io::Cursor; +//use std::io::{Read,self}; +use std::io::BufReader; +use std::path::PathBuf; +use std::time::Instant; + +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq)] +pub struct SerializableProvingKey(pub ProvingKey); + +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq)] +pub struct SerializableMatrix { + pub data: Vec>, +} + +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq)] +pub struct SerializableConstraintMatrices { + pub num_instance_variables: usize, + pub num_witness_variables: usize, + pub num_constraints: usize, + pub a_num_non_zero: usize, + pub b_num_non_zero: usize, + pub c_num_non_zero: usize, + pub a: SerializableMatrix, + pub b: SerializableMatrix, + pub c: SerializableMatrix, +} + +impl From>> for SerializableMatrix { + fn from(matrix: Vec>) -> Self { + SerializableMatrix { data: matrix } + } +} + +impl From> for Vec> { + fn from(serializable_matrix: SerializableMatrix) -> Self { + serializable_matrix.data + } +} + +pub fn serialize_proving_key(pk: &SerializableProvingKey) -> Vec { + let mut serialized_data = Vec::new(); + pk.serialize_compressed(&mut serialized_data) + .expect("Serialization failed"); + serialized_data +} + +pub fn deserialize_proving_key(data: Vec) -> SerializableProvingKey { + SerializableProvingKey::deserialize_compressed_unchecked(&mut &data[..]) + .expect("Deserialization failed") +} + +pub fn read_arkzkey( + arkzkey_path: &str, +) -> Result<(SerializableProvingKey, SerializableConstraintMatrices)> { + let now = std::time::Instant::now(); + let arkzkey_file_path = PathBuf::from(arkzkey_path); + let arkzkey_file = File::open(arkzkey_file_path).wrap_err("Failed to open arkzkey file")?; + println!("Time to open arkzkey file: {:?}", now.elapsed()); + + //let mut buf_reader = BufReader::new(arkzkey_file); + + // Using mmap + let now = std::time::Instant::now(); + let mmap = unsafe { Mmap::map(&arkzkey_file)? }; + let mut cursor = std::io::Cursor::new(mmap); + println!("Time to mmap arkzkey: {:?}", now.elapsed()); + + // Was &mut buf_reader + let now = std::time::Instant::now(); + let proving_key = SerializableProvingKey::deserialize_compressed_unchecked(&mut cursor) + .wrap_err("Failed to deserialize proving key")?; + println!("Time to deserialize proving key: {:?}", now.elapsed()); + + let now = std::time::Instant::now(); + let constraint_matrices = + SerializableConstraintMatrices::deserialize_compressed_unchecked(&mut cursor) + .wrap_err("Failed to deserialize constraint matrices")?; + println!("Time to deserialize matrices: {:?}", now.elapsed()); + + Ok((proving_key, constraint_matrices)) +} + +// TODO: Return ProvingKey, ConstraintMatrices? +pub fn read_arkzkey_from_bytes( + arkzkey_bytes: &[u8], +) -> Result<(ProvingKey, ConstraintMatrices)> { + let mut cursor = std::io::Cursor::new(arkzkey_bytes); + + let now = std::time::Instant::now(); + let serialized_proving_key = + SerializableProvingKey::deserialize_compressed_unchecked(&mut cursor) + .wrap_err("Failed to deserialize proving key")?; + println!("Time to deserialize proving key: {:?}", now.elapsed()); + + let now = std::time::Instant::now(); + let serialized_constraint_matrices = + SerializableConstraintMatrices::deserialize_compressed_unchecked(&mut cursor) + .wrap_err("Failed to deserialize constraint matrices")?; + println!("Time to deserialize matrices: {:?}", now.elapsed()); + + // Get on right form for API + let proving_key: ProvingKey = serialized_proving_key.0; + let constraint_matrices: ConstraintMatrices = ConstraintMatrices { + num_instance_variables: serialized_constraint_matrices.num_instance_variables, + num_witness_variables: serialized_constraint_matrices.num_witness_variables, + num_constraints: serialized_constraint_matrices.num_constraints, + a_num_non_zero: serialized_constraint_matrices.a_num_non_zero, + b_num_non_zero: serialized_constraint_matrices.b_num_non_zero, + c_num_non_zero: serialized_constraint_matrices.c_num_non_zero, + a: serialized_constraint_matrices.a.data, + b: serialized_constraint_matrices.b.data, + c: serialized_constraint_matrices.c.data, + }; + + Ok((proving_key, constraint_matrices)) +} + +pub fn read_proving_key_and_matrices_from_zkey( + zkey_path: &str, +) -> Result<(SerializableProvingKey, SerializableConstraintMatrices)> { + println!("Reading zkey from: {}", zkey_path); + let now = Instant::now(); + let zkey_file_path = PathBuf::from(zkey_path); + let zkey_file = File::open(zkey_file_path).wrap_err("Failed to open zkey file")?; + + let mut buf_reader = BufReader::new(zkey_file); + + let (proving_key, matrices) = + read_zkey(&mut buf_reader).wrap_err("Failed to read zkey file")?; + println!("Time to read zkey: {:?}", now.elapsed()); + + println!("Serializing proving key and constraint matrices"); + let now = Instant::now(); + let serializable_proving_key = SerializableProvingKey(proving_key); + let serializable_constrain_matrices = SerializableConstraintMatrices { + num_instance_variables: matrices.num_instance_variables, + num_witness_variables: matrices.num_witness_variables, + num_constraints: matrices.num_constraints, + a_num_non_zero: matrices.a_num_non_zero, + b_num_non_zero: matrices.b_num_non_zero, + c_num_non_zero: matrices.c_num_non_zero, + a: SerializableMatrix { data: matrices.a }, + b: SerializableMatrix { data: matrices.b }, + c: SerializableMatrix { data: matrices.c }, + }; + println!( + "Time to serialize proving key and constraint matrices: {:?}", + now.elapsed() + ); + + Ok((serializable_proving_key, serializable_constrain_matrices)) +} + +pub fn convert_zkey( + proving_key: SerializableProvingKey, + constraint_matrices: SerializableConstraintMatrices, + arkzkey_path: &str, +) -> Result<()> { + let arkzkey_file_path = PathBuf::from(arkzkey_path); + + let serialized_path = PathBuf::from(arkzkey_file_path); + + let mut file = + File::create(&serialized_path).wrap_err("Failed to create serialized proving key file")?; + + proving_key + .serialize_compressed(&mut file) + .wrap_err("Failed to serialize proving key")?; + + constraint_matrices + .serialize_compressed(&mut file) + .wrap_err("Failed to serialize constraint matrices")?; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::time::Instant; + + fn test_circuit_serialization_deserialization(zkey_path: &str) -> Result<()> { + let arkzkey_path = zkey_path.replace(".zkey", ".arkzkey"); + + let (original_proving_key, original_constraint_matrices) = + read_proving_key_and_matrices_from_zkey(zkey_path)?; + + println!("[build] Writing arkzkey to: {}", arkzkey_path); + let now = Instant::now(); + convert_zkey( + original_proving_key.clone(), + original_constraint_matrices.clone(), + &arkzkey_path, + )?; + println!("[build] Time to write arkzkey: {:?}", now.elapsed()); + + println!("Reading arkzkey from: {}", arkzkey_path); + let now = Instant::now(); + let (deserialized_proving_key, deserialized_constraint_matrices) = + read_arkzkey(&arkzkey_path)?; + println!("Time to read arkzkey: {:?}", now.elapsed()); + + assert_eq!( + original_proving_key, deserialized_proving_key, + "Original and deserialized proving keys do not match" + ); + + assert_eq!( + original_constraint_matrices, deserialized_constraint_matrices, + "Original and deserialized constraint matrices do not match" + ); + + Ok(()) + } + + #[test] + fn test_multiplier2_serialization_deserialization() -> Result<()> { + test_circuit_serialization_deserialization( + "../mopro-core/examples/circom/multiplier2/target/multiplier2_final.zkey", + ) + } + + #[test] + fn test_keccak256_serialization_deserialization() -> Result<()> { + test_circuit_serialization_deserialization( + "../mopro-core/examples/circom/keccak256/target/keccak256_256_test_final.zkey", + ) + } + + #[test] + fn test_rsa_serialization_deserialization() -> Result<()> { + test_circuit_serialization_deserialization( + "../mopro-core/examples/circom/rsa/target/main_final.zkey", + ) + } +} diff --git a/app/mopro-core/.gitignore b/app/mopro-core/.gitignore new file mode 100644 index 000000000..6985cf1bd --- /dev/null +++ b/app/mopro-core/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/app/mopro-core/Cargo.toml b/app/mopro-core/Cargo.toml new file mode 100644 index 000000000..1a63a4d30 --- /dev/null +++ b/app/mopro-core/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "mopro-core" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[patch.crates-io] +# NOTE: Forked wasmer to work around memory limits +# See https://github.com/wasmerio/wasmer/commit/09c7070 +wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" } + +[features] +default = [] +dylib = ["wasmer/dylib"] + +[dependencies] +ark-circom = { git = "https://github.com/arkworks-rs/circom-compat.git" } +serde = { version = "1.0", features = ["derive"] } +ark-serialize = { version = "=0.4.1", features = ["derive"] } +num-bigint = { version = "=0.4.3", default-features = false, features = [ + "rand", +] } +instant = "0.1" +wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" } +once_cell = "1.8" + +# ZKP generation +ark-ec = { version = "=0.4.1", default-features = false, features = [ + "parallel", +] } +ark-crypto-primitives = { version = "=0.4.0" } +ark-std = { version = "=0.4.0", default-features = false, features = [ + "parallel", +] } +ark-bn254 = { version = "=0.4.0" } +ark-groth16 = { version = "=0.4.0", default-features = false, features = [ + "parallel", +] } +ark-relations = { version = "0.4", default-features = false } +ark-zkey = { path = "../ark-zkey" } + +# Error handling +thiserror = "=1.0.39" +color-eyre = "=0.6.2" +criterion = "=0.3.6" + +[build-dependencies] +color-eyre = "0.6" +enumset = "1.0.8" +wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" } diff --git a/app/mopro-core/README.md b/app/mopro-core/README.md new file mode 100644 index 000000000..452109f1d --- /dev/null +++ b/app/mopro-core/README.md @@ -0,0 +1,47 @@ +# mopro-core + +Core mobile Rust library. For FFI, see `mopro-ffi` which is a thin wrapper for exposing UniFFI bindings around this library. + +## Overview + +TBD. + +## Examples + +Run `cargo run --example circom`. Also see `examples/circom/README.md` for more information. + +## Build dylib + +Experimental support. + +Turns `.wasm` file into a dynamic library (`.dylib`). + +Run: + +`cargo build --features dylib` + +After that you'll see location of the dylib file: + +``` +warning: Building dylib for aarch64-apple-darwin +warning: Dylib location: /Users/user/repos/github.com/oskarth/mopro/mopro-core/target/debug/aarch64-apple-darwin/keccak256.dylib +``` + +Right now this is hardcoded for `rsa`. + +Note that: +- It has to be built for the right architecture +- Have to run `install_name_tool` to adjust install name +- Run `codesign` to sign dylib for use on iOS + +### Script + +Add third argument: `dylib`: + +`./scripts/update_bindings.sh device release dylib` + +Note that `APPLE_SIGNING_IDENTITY` must be set. + +## To use ark-zkey + +Experimental support for significantly faster zkey loading. See `../ark-zkey` README for how to build arkzkey. \ No newline at end of file diff --git a/app/mopro-core/build.rs b/app/mopro-core/build.rs new file mode 100644 index 000000000..ae72e15cf --- /dev/null +++ b/app/mopro-core/build.rs @@ -0,0 +1,95 @@ +use color_eyre::eyre::Result; +use std::env; +use std::path::PathBuf; + +fn prepare_env(zkey_path: String, wasm_path: String, arkzkey_path: String) -> Result<()> { + let project_dir = env::var("CARGO_MANIFEST_DIR")?; + let zkey_file = PathBuf::from(&project_dir).join(zkey_path); + let wasm_file = PathBuf::from(&project_dir).join(wasm_path); + let arkzkey_file = PathBuf::from(&project_dir).join(arkzkey_path); + + // TODO: Right now emitting as warnings for visibility, figure out better way to do this? + println!("cargo:warning=zkey_file: {}", zkey_file.display()); + println!("cargo:warning=wasm_file: {}", wasm_file.display()); + println!("cargo:warning=arkzkey_file: {}", arkzkey_file.display()); + + // Set BUILD_RS_ZKEY_FILE and BUILD_RS_WASM_FILE env var + println!("cargo:rustc-env=BUILD_RS_ZKEY_FILE={}", zkey_file.display()); + println!("cargo:rustc-env=BUILD_RS_WASM_FILE={}", wasm_file.display()); + println!( + "cargo:rustc-env=BUILD_RS_ARKZKEY_FILE={}", + arkzkey_file.display() + ); + + Ok(()) +} + +#[cfg(feature = "dylib")] +fn build_dylib(wasm_path: String, dylib_name: String) -> Result<()> { + use std::path::Path; + use std::{fs, str::FromStr}; + + use color_eyre::eyre::eyre; + use enumset::enum_set; + use enumset::EnumSet; + + use wasmer::Cranelift; + use wasmer::Dylib; + use wasmer::Target; + use wasmer::{Module, Store, Triple}; + + let out_dir = env::var("OUT_DIR")?; + let project_dir = env::var("CARGO_MANIFEST_DIR")?; + let build_mode = env::var("PROFILE")?; + let target_arch = env::var("TARGET")?; + + let out_dir = Path::new(&out_dir).to_path_buf(); + let wasm_file = Path::new(&wasm_path).to_path_buf(); + let dylib_file = out_dir.join(&dylib_name); + let final_dir = PathBuf::from(&project_dir) + .join("target") + .join(&target_arch) + .join(build_mode); + + // if dylib_file.exists() { + // return Ok(()); + // } + + // Create a WASM engine for the target that can compile + let triple = Triple::from_str(&target_arch).map_err(|e| eyre!(e))?; + let cpu_features = enum_set!(); + let target = Target::new(triple, cpu_features); + let engine = Dylib::new(Cranelift::default()).target(target).engine(); + println!("cargo:warning=Building dylib for {}", target_arch); + + // Compile the WASM module + let store = Store::new(&engine); + let module = Module::from_file(&store, &wasm_file).unwrap(); + module.serialize_to_file(&dylib_file).unwrap(); + assert!(dylib_file.exists()); + + // Copy dylib to a more predictable path + fs::create_dir_all(&final_dir)?; + let final_path = final_dir.join(dylib_name); + fs::copy(&dylib_file, &final_path)?; + println!("cargo:warning=Dylib location: {}", final_path.display()); + + Ok(()) +} + +fn main() -> Result<()> { + // TODO: build_circuit function to builds all related artifacts, instead of doing this externally + let dir = "../../circuits"; + let circuit = "proof_of_passport"; + + let zkey_path = format!("{}/build/{}_final.zkey", dir, circuit); + let wasm_path = format!("{}/build/{}_js/{}.wasm", dir, circuit, circuit); + // TODO: Need to modify script for this + let arkzkey_path = format!("{}/build/{}_final.arkzkey", dir, circuit); + + println!("cargo:warning=arkzkey_path: {}", arkzkey_path); + + prepare_env(zkey_path, wasm_path, arkzkey_path)?; + + Ok(()) +} diff --git a/app/mopro-core/src/lib.rs b/app/mopro-core/src/lib.rs new file mode 100644 index 000000000..2ac7b546f --- /dev/null +++ b/app/mopro-core/src/lib.rs @@ -0,0 +1,8 @@ +pub mod middleware; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum MoproError { + #[error("CircomError: {0}")] + CircomError(String), +} diff --git a/app/mopro-core/src/middleware/circom/mod.rs b/app/mopro-core/src/middleware/circom/mod.rs new file mode 100644 index 000000000..0cf497fc9 --- /dev/null +++ b/app/mopro-core/src/middleware/circom/mod.rs @@ -0,0 +1,860 @@ +use self::{ + serialization::{SerializableInputs, SerializableProof, SerializableProvingKey}, + utils::{assert_paths_exists, bytes_to_bits}, +}; +use crate::MoproError; + +use std::collections::HashMap; +//use std::io::Cursor; +use std::sync::Mutex; +use std::time::Instant; + +use ark_bn254::{Bn254, Fr}; +use ark_circom::{ + CircomBuilder, + CircomCircuit, + CircomConfig, + CircomReduction, + WitnessCalculator, //read_zkey, +}; +use ark_crypto_primitives::snark::SNARK; +use ark_groth16::{prepare_verifying_key, Groth16, ProvingKey}; +use ark_std::UniformRand; + +use ark_relations::r1cs::ConstraintMatrices; +use ark_std::rand::thread_rng; +use color_eyre::Result; +use core::include_bytes; +use num_bigint::BigInt; +use once_cell::sync::{Lazy, OnceCell}; + +use wasmer::{Module, Store}; + +use ark_zkey::read_arkzkey_from_bytes; //SerializableConstraintMatrices + +#[cfg(feature = "dylib")] +use { + std::{env, path::Path}, + wasmer::Dylib, +}; + +pub mod serialization; +pub mod utils; + +type GrothBn = Groth16; + +type CircuitInputs = HashMap>; + +// TODO: Split up this namespace a bit, right now quite a lot of things going on + +pub struct CircomState { + builder: Option>, + circuit: Option>, + params: Option>, +} + +impl Default for CircomState { + fn default() -> Self { + Self::new() + } +} + +// NOTE: A lot of the contents of this file is inspired by github.com/worldcoin/semaphore-rs + +// TODO: Replace printlns with logging + +//const ZKEY_BYTES: &[u8] = include_bytes!(env!("BUILD_RS_ZKEY_FILE")); + +const ARKZKEY_BYTES: &[u8] = include_bytes!(env!("BUILD_RS_ARKZKEY_FILE")); + +// static ZKEY: Lazy<(ProvingKey, ConstraintMatrices)> = Lazy::new(|| { +// let mut reader = Cursor::new(ZKEY_BYTES); +// read_zkey(&mut reader).expect("Failed to read zkey") +// }); + +static ARKZKEY: Lazy<(ProvingKey, ConstraintMatrices)> = Lazy::new(|| { + //let mut reader = Cursor::new(ARKZKEY_BYTES); + // TODO: Use reader? More flexible; unclear if perf diff + read_arkzkey_from_bytes(ARKZKEY_BYTES).expect("Failed to read arkzkey") +}); + +const WASM: &[u8] = include_bytes!(env!("BUILD_RS_WASM_FILE")); + +/// `WITNESS_CALCULATOR` is a lazily initialized, thread-safe singleton of type `WitnessCalculator`. +/// `OnceCell` ensures that the initialization occurs exactly once, and `Mutex` allows safe shared +/// access from multiple threads. +static WITNESS_CALCULATOR: OnceCell> = OnceCell::new(); + +/// Initializes the `WITNESS_CALCULATOR` singleton with a `WitnessCalculator` instance created from +/// a specified dylib file (WASM circuit). Also initialize `ZKEY`. +#[cfg(feature = "dylib")] +pub fn initialize(dylib_path: &Path) { + println!("Initializing dylib: {:?}", dylib_path); + + WITNESS_CALCULATOR + .set(from_dylib(dylib_path)) + .expect("Failed to set WITNESS_CALCULATOR"); + + // Initialize ARKZKEY + // TODO: Speed this up even more + let now = std::time::Instant::now(); + Lazy::force(&ARKZKEY); + println!("Initializing arkzkey took: {:.2?}", now.elapsed()); +} + +#[cfg(not(feature = "dylib"))] +pub fn initialize() { + println!("Initializing library with arkzkey"); + + // Initialize ARKZKEY + // TODO: Speed this up even more! + let now = std::time::Instant::now(); + Lazy::force(&ARKZKEY); + println!("Initializing arkzkey took: {:.2?}", now.elapsed()); +} + +/// Creates a `WitnessCalculator` instance from a dylib file. +#[cfg(feature = "dylib")] +fn from_dylib(path: &Path) -> Mutex { + let store = Store::new(&Dylib::headless().engine()); + let module = unsafe { + Module::deserialize_from_file(&store, path).expect("Failed to load dylib module") + }; + let result = + WitnessCalculator::from_module(module).expect("Failed to create WitnessCalculator"); + + Mutex::new(result) +} + +// #[must_use] +// pub fn zkey() -> &'static (ProvingKey, ConstraintMatrices) { +// &ZKEY +// } + +// Experimental +#[must_use] +pub fn arkzkey() -> &'static (ProvingKey, ConstraintMatrices) { + &ARKZKEY +} + +/// Provides access to the `WITNESS_CALCULATOR` singleton, initializing it if necessary. +/// It expects the path to the dylib file to be set in the `CIRCUIT_WASM_DYLIB` environment variable. +#[cfg(feature = "dylib")] +#[must_use] +pub fn witness_calculator() -> &'static Mutex { + let var_name = "CIRCUIT_WASM_DYLIB"; + + WITNESS_CALCULATOR.get_or_init(|| { + let path = env::var(var_name).unwrap_or_else(|_| { + panic!( + "Mopro circuit WASM Dylib not initialized. \ + Please set {} environment variable to the path of the dylib file", + var_name + ) + }); + from_dylib(Path::new(&path)) + }) +} + +#[cfg(not(feature = "dylib"))] +#[must_use] +pub fn witness_calculator() -> &'static Mutex { + WITNESS_CALCULATOR.get_or_init(|| { + let store = Store::default(); + let module = Module::from_binary(&store, WASM).expect("WASM should be valid"); + let result = + WitnessCalculator::from_module(module).expect("Failed to create WitnessCalculator"); + Mutex::new(result) + }) +} + +pub fn generate_proof2( + inputs: CircuitInputs, +) -> Result<(SerializableProof, SerializableInputs), MoproError> { + let mut rng = thread_rng(); + let rng = &mut rng; + + let r = ark_bn254::Fr::rand(rng); + let s = ark_bn254::Fr::rand(rng); + + println!("Generating proof 2"); + + let now = std::time::Instant::now(); + let full_assignment = witness_calculator() + .lock() + .expect("Failed to lock witness calculator") + .calculate_witness_element::(inputs, false) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + println!("Witness generation took: {:.2?}", now.elapsed()); + + let now = std::time::Instant::now(); + //let zkey = zkey(); + let zkey = arkzkey(); + println!("Loading arkzkey took: {:.2?}", now.elapsed()); + + let public_inputs = full_assignment.as_slice()[1..zkey.1.num_instance_variables].to_vec(); + + let now = std::time::Instant::now(); + let ark_proof = Groth16::<_, CircomReduction>::create_proof_with_reduction_and_matrices( + &zkey.0, + r, + s, + &zkey.1, + zkey.1.num_instance_variables, + zkey.1.num_constraints, + full_assignment.as_slice(), + ); + + let proof = ark_proof.map_err(|e| MoproError::CircomError(e.to_string()))?; + + println!("proof generation took: {:.2?}", now.elapsed()); + + // TODO: Add SerializableInputs(inputs))) + Ok((SerializableProof(proof), SerializableInputs(public_inputs))) +} + +pub fn verify_proof2( + serialized_proof: SerializableProof, + serialized_inputs: SerializableInputs, +) -> Result { + let start = Instant::now(); + let zkey = arkzkey(); + let pvk = prepare_verifying_key(&zkey.0.vk); + + let proof_verified = + GrothBn::verify_with_processed_vk(&pvk, &serialized_inputs.0, &serialized_proof.0) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + let verification_duration = start.elapsed(); + println!("Verification time 2: {:?}", verification_duration); + Ok(proof_verified) +} + +impl CircomState { + pub fn new() -> Self { + Self { + builder: None, + circuit: None, + params: None, + } + } + + pub fn setup( + &mut self, + wasm_path: &str, + r1cs_path: &str, + ) -> Result { + assert_paths_exists(wasm_path, r1cs_path)?; + println!("Setup"); + let start = Instant::now(); + + // Load the WASM and R1CS for witness and proof generation + let cfg = self.load_config(wasm_path, r1cs_path)?; + + // Create an empty instance for setup + self.builder = Some(CircomBuilder::new(cfg)); + + // Run a trusted setup using the rng in the state + let params = self.run_trusted_setup()?; + + self.params = Some(params.clone()); + + let setup_duration = start.elapsed(); + println!("Setup time: {:?}", setup_duration); + + Ok(SerializableProvingKey(params)) + } + + // NOTE: Consider generate_proof> API + // XXX: BigInt might present problems for UniFFI + pub fn generate_proof( + &mut self, + inputs: CircuitInputs, + ) -> Result<(SerializableProof, SerializableInputs), MoproError> { + let start = Instant::now(); + println!("Generating proof"); + + let mut rng = thread_rng(); + + let builder = self.builder.as_mut().ok_or(MoproError::CircomError( + "Builder has not been set up".to_string(), + ))?; + + // Insert our inputs as key value pairs + for (key, values) in &inputs { + for value in values { + builder.push_input(&key, value.clone()); + } + } + + // Clone the builder, then build the circuit + let circom = builder + .clone() + .build() + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + // Update the circuit in self + self.circuit = Some(circom.clone()); + + let params = self.params.as_ref().ok_or(MoproError::CircomError( + "Parameters have not been set up".to_string(), + ))?; + + let inputs = circom.get_public_inputs().ok_or(MoproError::CircomError( + "Failed to get public inputs".to_string(), + ))?; + + let proof = GrothBn::prove(params, circom.clone(), &mut rng) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + let proof_duration = start.elapsed(); + println!("Proof generation time: {:?}", proof_duration); + + Ok((SerializableProof(proof), SerializableInputs(inputs))) + } + + pub fn verify_proof( + &self, + serialized_proof: SerializableProof, + serialized_inputs: SerializableInputs, + ) -> Result { + let start = Instant::now(); + + println!("Verifying proof"); + + let params = self.params.as_ref().ok_or(MoproError::CircomError( + "Parameters have not been set up".to_string(), + ))?; + + let pvk = + GrothBn::process_vk(¶ms.vk).map_err(|e| MoproError::CircomError(e.to_string()))?; + + let proof_verified = + GrothBn::verify_with_processed_vk(&pvk, &serialized_inputs.0, &serialized_proof.0) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + let verification_duration = start.elapsed(); + println!("Verification time: {:?}", verification_duration); + Ok(proof_verified) + } + + fn load_config( + &self, + wasm_path: &str, + r1cs_path: &str, + ) -> Result, MoproError> { + CircomConfig::::new(wasm_path, r1cs_path) + .map_err(|e| MoproError::CircomError(e.to_string())) + } + + fn run_trusted_setup(&mut self) -> Result, MoproError> { + let circom_setup = self + .builder + .as_mut() + .ok_or(MoproError::CircomError( + "Builder has not been set up".to_string(), + ))? + .setup(); + + let mut rng = thread_rng(); + + GrothBn::generate_random_parameters_with_reduction(circom_setup, &mut rng) + .map_err(|e| MoproError::CircomError(e.to_string())) + } +} + +// Helper function for Keccak256 example +pub fn bytes_to_circuit_inputs(bytes: &[u8]) -> CircuitInputs { + let bits = bytes_to_bits(bytes); + let big_int_bits = bits + .into_iter() + .map(|bit| BigInt::from(bit as u8)) + .collect(); + let mut inputs = HashMap::new(); + inputs.insert("in".to_string(), big_int_bits); + inputs +} + +pub fn strings_to_circuit_inputs(strings: &[&str]) -> Vec { + strings + .iter() + .map(|&value| BigInt::parse_bytes(value.as_bytes(), 10).unwrap()) + .collect() +} + +pub fn bytes_to_circuit_outputs(bytes: &[u8]) -> SerializableInputs { + let bits = bytes_to_bits(bytes); + let field_bits = bits.into_iter().map(|bit| Fr::from(bit as u8)).collect(); + SerializableInputs(field_bits) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_setup_prove_verify_simple() { + let wasm_path = "./examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"; + let r1cs_path = "./examples/circom/multiplier2/target/multiplier2.r1cs"; + + // Instantiate CircomState + let mut circom_state = CircomState::new(); + + // Setup + let setup_res = circom_state.setup(wasm_path, r1cs_path); + assert!(setup_res.is_ok()); + + let _serialized_pk = setup_res.unwrap(); + + // Deserialize the proving key and inputs if necessary + + // Prepare inputs + let mut inputs = HashMap::new(); + let a = 3; + let b = 5; + let c = a * b; + inputs.insert("a".to_string(), vec![BigInt::from(a)]); + inputs.insert("b".to_string(), vec![BigInt::from(b)]); + // output = [public output c, public input a] + let expected_output = vec![Fr::from(c), Fr::from(a)]; + let serialized_outputs = SerializableInputs(expected_output); + + // Proof generation + let generate_proof_res = circom_state.generate_proof(inputs); + + // Check and print the error if there is one + if let Err(e) = &generate_proof_res { + println!("Error: {:?}", e); + } + + assert!(generate_proof_res.is_ok()); + + let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); + + // Check output + assert_eq!(serialized_inputs, serialized_outputs); + + // Proof verification + let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs); + assert!(verify_res.is_ok()); + assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified + } + + #[test] + fn test_setup_prove_verify_keccak() { + let wasm_path = + "./examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm"; + let r1cs_path = "./examples/circom/keccak256/target/keccak256_256_test.r1cs"; + + // Instantiate CircomState + let mut circom_state = CircomState::new(); + + // Setup + let setup_res = circom_state.setup(wasm_path, r1cs_path); + assert!(setup_res.is_ok()); + + let _serialized_pk = setup_res.unwrap(); + + // Deserialize the proving key and inputs if necessary + + // Prepare inputs + let input_vec = vec![ + 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, + ]; + + // Expected output + let expected_output_vec = vec![ + 37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, + 212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, + ]; + + let inputs = bytes_to_circuit_inputs(&input_vec); + let serialized_outputs = bytes_to_circuit_outputs(&expected_output_vec); + + // Proof generation + let generate_proof_res = circom_state.generate_proof(inputs); + + // Check and print the error if there is one + if let Err(e) = &generate_proof_res { + println!("Error: {:?}", e); + } + + assert!(generate_proof_res.is_ok()); + + let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); + + // Check output + assert_eq!(serialized_inputs, serialized_outputs); + + // Proof verification + let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs); + assert!(verify_res.is_ok()); + + assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified + } + + #[test] + fn test_setup_error() { + // Arrange: Create a new CircomState instance + let mut circom_state = CircomState::new(); + + let wasm_path = "badpath/multiplier2.wasm"; + let r1cs_path = "badpath/multiplier2.r1cs"; + + // Act: Call the setup method + let result = circom_state.setup(wasm_path, r1cs_path); + + // Assert: Check that the method returns an error + assert!(result.is_err()); + } + + #[cfg(feature = "dylib")] + #[test] + fn test_dylib_init_and_generate_witness() { + // Assumes that the dylib file has been built and is in the following location + let dylib_path = "target/debug/aarch64-apple-darwin/keccak256.dylib"; + + // Initialize libray + initialize(Path::new(&dylib_path)); + + let input_vec = vec![ + 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 inputs = bytes_to_circuit_inputs(&input_vec); + let now = std::time::Instant::now(); + let full_assignment = witness_calculator() + .lock() + .expect("Failed to lock witness calculator") + .calculate_witness_element::(inputs, false) + .map_err(|e| MoproError::CircomError(e.to_string())); + + println!("Witness generation took: {:.2?}", now.elapsed()); + + assert!(full_assignment.is_ok()); + } + + #[test] + fn test_generate_proof2() { + // XXX: This can be done better + #[cfg(feature = "dylib")] + { + // Assumes that the dylib file has been built and is in the following location + let dylib_path = "target/debug/aarch64-apple-darwin/keccak256.dylib"; + + // Initialize libray + initialize(Path::new(&dylib_path)); + } + + let input_vec = vec![ + 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 expected_output_vec = vec![ + 37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, + 212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, + ]; + let inputs = bytes_to_circuit_inputs(&input_vec); + let serialized_outputs = bytes_to_circuit_outputs(&expected_output_vec); + + let generate_proof_res = generate_proof2(inputs); + let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); + assert_eq!(serialized_inputs, serialized_outputs); + + // Proof verification + let verify_res = verify_proof2(serialized_proof, serialized_inputs); + assert!(verify_res.is_ok()); + assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified + } + + #[ignore = "ignore for ci"] + #[test] + fn test_setup_prove_rsa() { + let wasm_path = "./examples/circom/rsa/target/main_js/main.wasm"; + let r1cs_path = "./examples/circom/rsa/target/main.r1cs"; + + // Instantiate CircomState + let mut circom_state = CircomState::new(); + + // Setup + let setup_res = circom_state.setup(wasm_path, r1cs_path); + assert!(setup_res.is_ok()); + + let _serialized_pk = setup_res.unwrap(); + + // Deserialize the proving key and inputs if necessary + + // Prepare inputs + let signature = [ + "3582320600048169363", + "7163546589759624213", + "18262551396327275695", + "4479772254206047016", + "1970274621151677644", + "6547632513799968987", + "921117808165172908", + "7155116889028933260", + "16769940396381196125", + "17141182191056257954", + "4376997046052607007", + "17471823348423771450", + "16282311012391954891", + "70286524413490741", + "1588836847166444745", + "15693430141227594668", + "13832254169115286697", + "15936550641925323613", + "323842208142565220", + "6558662646882345749", + "15268061661646212265", + "14962976685717212593", + "15773505053543368901", + "9586594741348111792", + "1455720481014374292", + "13945813312010515080", + "6352059456732816887", + "17556873002865047035", + "2412591065060484384", + "11512123092407778330", + "8499281165724578877", + "12768005853882726493", + ]; + let modulus = [ + "13792647154200341559", + "12773492180790982043", + "13046321649363433702", + "10174370803876824128", + "7282572246071034406", + "1524365412687682781", + "4900829043004737418", + "6195884386932410966", + "13554217876979843574", + "17902692039595931737", + "12433028734895890975", + "15971442058448435996", + "4591894758077129763", + "11258250015882429548", + "16399550288873254981", + "8246389845141771315", + "14040203746442788850", + "7283856864330834987", + "12297563098718697441", + "13560928146585163504", + "7380926829734048483", + "14591299561622291080", + "8439722381984777599", + "17375431987296514829", + "16727607878674407272", + "3233954801381564296", + "17255435698225160983", + "15093748890170255670", + "15810389980847260072", + "11120056430439037392", + "5866130971823719482", + "13327552690270163501", + ]; + let base_message = [ + "18114495772705111902", + "2254271930739856077", + "2068851770", + "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", + "0", + ]; + + let mut inputs: HashMap> = HashMap::new(); + inputs.insert( + "signature".to_string(), + strings_to_circuit_inputs(&signature), + ); + inputs.insert("modulus".to_string(), strings_to_circuit_inputs(&modulus)); + inputs.insert( + "base_message".to_string(), + strings_to_circuit_inputs(&base_message), + ); + + // Proof generation + let generate_proof_res = circom_state.generate_proof(inputs); + + // Check and print the error if there is one + if let Err(e) = &generate_proof_res { + println!("Error: {:?}", e); + } + + assert!(generate_proof_res.is_ok()); + + let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); + + // Proof verification + let verify_res = circom_state.verify_proof(serialized_proof, serialized_inputs); + assert!(verify_res.is_ok()); + + assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified + } + + #[ignore = "ignore for ci"] + #[test] + fn test_setup_prove_rsa2() { + // Prepare inputs + let signature = [ + "3582320600048169363", + "7163546589759624213", + "18262551396327275695", + "4479772254206047016", + "1970274621151677644", + "6547632513799968987", + "921117808165172908", + "7155116889028933260", + "16769940396381196125", + "17141182191056257954", + "4376997046052607007", + "17471823348423771450", + "16282311012391954891", + "70286524413490741", + "1588836847166444745", + "15693430141227594668", + "13832254169115286697", + "15936550641925323613", + "323842208142565220", + "6558662646882345749", + "15268061661646212265", + "14962976685717212593", + "15773505053543368901", + "9586594741348111792", + "1455720481014374292", + "13945813312010515080", + "6352059456732816887", + "17556873002865047035", + "2412591065060484384", + "11512123092407778330", + "8499281165724578877", + "12768005853882726493", + ]; + let modulus = [ + "13792647154200341559", + "12773492180790982043", + "13046321649363433702", + "10174370803876824128", + "7282572246071034406", + "1524365412687682781", + "4900829043004737418", + "6195884386932410966", + "13554217876979843574", + "17902692039595931737", + "12433028734895890975", + "15971442058448435996", + "4591894758077129763", + "11258250015882429548", + "16399550288873254981", + "8246389845141771315", + "14040203746442788850", + "7283856864330834987", + "12297563098718697441", + "13560928146585163504", + "7380926829734048483", + "14591299561622291080", + "8439722381984777599", + "17375431987296514829", + "16727607878674407272", + "3233954801381564296", + "17255435698225160983", + "15093748890170255670", + "15810389980847260072", + "11120056430439037392", + "5866130971823719482", + "13327552690270163501", + ]; + let base_message = [ + "18114495772705111902", + "2254271930739856077", + "2068851770", + "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", + "0", + ]; + + let mut inputs: HashMap> = HashMap::new(); + inputs.insert( + "signature".to_string(), + strings_to_circuit_inputs(&signature), + ); + inputs.insert("modulus".to_string(), strings_to_circuit_inputs(&modulus)); + inputs.insert( + "base_message".to_string(), + strings_to_circuit_inputs(&base_message), + ); + + // Proof generation + let generate_proof_res = generate_proof2(inputs); + + // Check and print the error if there is one + if let Err(e) = &generate_proof_res { + println!("Error: {:?}", e); + } + + assert!(generate_proof_res.is_ok()); + + let (serialized_proof, serialized_inputs) = generate_proof_res.unwrap(); + + // Proof verification + let verify_res = verify_proof2(serialized_proof, serialized_inputs); + assert!(verify_res.is_ok()); + + assert!(verify_res.unwrap()); // Verifying that the proof was indeed verified + } +} diff --git a/app/mopro-core/src/middleware/circom/serialization.rs b/app/mopro-core/src/middleware/circom/serialization.rs new file mode 100644 index 000000000..47fa40088 --- /dev/null +++ b/app/mopro-core/src/middleware/circom/serialization.rs @@ -0,0 +1,106 @@ +use ark_bn254::Bn254; +use ark_ec::pairing::Pairing; +use ark_groth16::{Proof, ProvingKey}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use color_eyre::Result; + +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] +pub struct SerializableProvingKey(pub ProvingKey); + +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] +pub struct SerializableProof(pub Proof); + +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq)] +pub struct SerializableInputs(pub Vec<::ScalarField>); + +pub fn serialize_proof(proof: &SerializableProof) -> Vec { + let mut serialized_data = Vec::new(); + proof + .serialize_uncompressed(&mut serialized_data) + .expect("Serialization failed"); + serialized_data +} + +pub fn deserialize_proof(data: Vec) -> SerializableProof { + SerializableProof::deserialize_uncompressed(&mut &data[..]).expect("Deserialization failed") +} + +pub fn serialize_proving_key(pk: &SerializableProvingKey) -> Vec { + let mut serialized_data = Vec::new(); + pk.serialize_uncompressed(&mut serialized_data) + .expect("Serialization failed"); + serialized_data +} + +pub fn deserialize_proving_key(data: Vec) -> SerializableProvingKey { + SerializableProvingKey::deserialize_uncompressed(&mut &data[..]) + .expect("Deserialization failed") +} + +pub fn serialize_inputs(inputs: &SerializableInputs) -> Vec { + let mut serialized_data = Vec::new(); + inputs + .serialize_uncompressed(&mut serialized_data) + .expect("Serialization failed"); + serialized_data +} + +pub fn deserialize_inputs(data: Vec) -> SerializableInputs { + SerializableInputs::deserialize_uncompressed(&mut &data[..]).expect("Deserialization failed") +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::middleware::circom::serialization::SerializableProvingKey; + use crate::middleware::circom::utils::assert_paths_exists; + use crate::MoproError; + use ark_bn254::Bn254; + use ark_circom::{CircomBuilder, CircomConfig}; + use ark_groth16::Groth16; + use ark_std::rand::thread_rng; + use color_eyre::Result; + + type GrothBn = Groth16; + + fn generate_serializable_proving_key( + wasm_path: &str, + r1cs_path: &str, + ) -> Result { + assert_paths_exists(wasm_path, r1cs_path)?; + + let cfg = CircomConfig::::new(wasm_path, r1cs_path) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + let builder = CircomBuilder::new(cfg); + let circom = builder.setup(); + + let mut rng = thread_rng(); + let raw_params = GrothBn::generate_random_parameters_with_reduction(circom, &mut rng) + .map_err(|e| MoproError::CircomError(e.to_string()))?; + + Ok(SerializableProvingKey(raw_params)) + } + + #[test] + fn test_serialization_deserialization() { + let wasm_path = "./examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"; + let r1cs_path = "./examples/circom/multiplier2/target/multiplier2.r1cs"; + + // Generate a serializable proving key for testing + let serializable_pk = generate_serializable_proving_key(wasm_path, r1cs_path) + .expect("Failed to generate serializable proving key"); + + // Serialize + let serialized_data = serialize_proving_key(&serializable_pk); + + // Deserialize + let deserialized_pk = deserialize_proving_key(serialized_data); + + // Assert that the original and deserialized ProvingKeys are the same + assert_eq!( + serializable_pk.0, deserialized_pk.0, + "Original and deserialized proving keys do not match" + ); + } +} diff --git a/app/mopro-core/src/middleware/circom/utils.rs b/app/mopro-core/src/middleware/circom/utils.rs new file mode 100644 index 000000000..31d6122c0 --- /dev/null +++ b/app/mopro-core/src/middleware/circom/utils.rs @@ -0,0 +1,33 @@ +use crate::MoproError; + +use std::path::Path; + +pub fn assert_paths_exists(wasm_path: &str, r1cs_path: &str) -> Result<(), MoproError> { + // Check that the files exist - ark-circom should probably do this instead and not panic + if !Path::new(wasm_path).exists() { + return Err(MoproError::CircomError(format!( + "Path does not exist: {}", + wasm_path + ))); + } + + if !Path::new(r1cs_path).exists() { + return Err(MoproError::CircomError(format!( + "Path does not exist: {}", + r1cs_path + ))); + }; + + Ok(()) +} + +pub fn bytes_to_bits(bytes: &[u8]) -> Vec { + let mut bits = Vec::new(); + for &byte in bytes { + for j in 0..8 { + let bit = (byte >> j) & 1; + bits.push(bit == 1); + } + } + bits +} diff --git a/app/mopro-core/src/middleware/mod.rs b/app/mopro-core/src/middleware/mod.rs new file mode 100644 index 000000000..d18079a10 --- /dev/null +++ b/app/mopro-core/src/middleware/mod.rs @@ -0,0 +1 @@ +pub mod circom; diff --git a/app/mopro-ffi/.gitignore b/app/mopro-ffi/.gitignore new file mode 100644 index 000000000..8648243db --- /dev/null +++ b/app/mopro-ffi/.gitignore @@ -0,0 +1,18 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# kotlin generated file +jniLibs/ +src/uniffi/mopro/ \ No newline at end of file diff --git a/app/mopro-ffi/Cargo.toml b/app/mopro-ffi/Cargo.toml new file mode 100644 index 000000000..e8fbd1111 --- /dev/null +++ b/app/mopro-ffi/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "mopro-ffi" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["lib", "cdylib", "staticlib"] +name = "mopro_ffi" + +[[bin]] +name = "uniffi-bindgen" +path = "uniffi-bindgen.rs" + +[features] +default = [] + +# If we enable dylib here it should be enabled in mopro-core as well +dylib = ["mopro-core/dylib"] + +[patch.crates-io] +# NOTE: Forked wasmer to work around memory limits +# See https://github.com/wasmerio/wasmer/commit/09c7070 +wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" } + +[dependencies] +mopro-core = { path = "../mopro-core" } +uniffi = { version = "0.25", features = ["cli"] } +serde = { version = "1", features = ["derive"] } +bincode = "1" +ark-serialize = { version = "=0.4.1", features = ["derive"] } +num-bigint = { version = "=0.4.3", default-features = false, features = [ + "rand", +] } + +# Error handling +thiserror = "=1.0.39" +color-eyre = "=0.6.2" +criterion = "=0.3.6" + +[build-dependencies] +uniffi = { version = "0.25", features = ["build"] } + +[dev-dependencies] +uniffi = { version = "0.25", features = ["bindgen-tests"] } +ark-bn254 = { version = "=0.4.0" } diff --git a/app/mopro-ffi/Makefile b/app/mopro-ffi/Makefile new file mode 100644 index 000000000..072c25bb8 --- /dev/null +++ b/app/mopro-ffi/Makefile @@ -0,0 +1,16 @@ +TARGETS = x86_64-apple-ios aarch64-apple-ios aarch64-apple-ios-sim +BUILD_TYPES = debug release + +all: $(BUILD_TYPES) + +debug: $(TARGETS) + for target in $(TARGETS); do \ + cargo build --target $$target; \ + done + +release: + for target in $(TARGETS); do \ + cargo build --release --target $$target; \ + done + +.PHONY: all $(BUILD_TYPES) $(TARGETS) \ No newline at end of file diff --git a/app/mopro-ffi/README.md b/app/mopro-ffi/README.md new file mode 100644 index 000000000..ec8eb6e62 --- /dev/null +++ b/app/mopro-ffi/README.md @@ -0,0 +1,48 @@ +# mopro-ffi + +Thin wrapper around `mopro-core`, exposes UniFFI bindings to be used by `rust-ios`, etc. + +## Overview + +TBD. + +## Development + +### Prerequisites + +1. Ensure you have Rust installed +2. Add platform targets `rustup target add x86_64-apple-ios aarch64-apple-ios aarch64-apple-ios-sim` +3. Install `uniffi-bindgen` locally with `cargo install --bin uniffi-bindgen --path .` +4. In order to locally run the bindings tests, you will need + * Kotlin: + * `kotlinc`, the [Kotlin command-line compiler](https://kotlinlang.org/docs/command-line.html). + * `ktlint`, the [Kotlin linter used to format the generated bindings](https://ktlint.github.io/). + * The [Java Native Access](https://github.com/java-native-access/jna#download) JAR downloaded and its path + added to your `$CLASSPATH` environment variable. + * Swift: + * `swift` and `swiftc`, the [Swift command-line tools](https://swift.org/download/). + * The Swift `Foundation` package. + +### Platforms supported + +Currently iOS is the main target, but Android will soon follow. PRs welcome. + +### Building + +Run `make` to build debug and release static libraries for supported platforms. + +### Generate UniFFI bindings + +The following command generates Swift bindings: + +`uniffi-bindgen generate src/mopro.udl --language swift --out-dir target/SwiftBindings` + +## Test bindings + +To test bindings: + +`cargo test --test test_generated_bindings` + +To test bindings in release mode without warning: + +`cargo test --test test_generated_bindings --release 2>/dev/null` diff --git a/app/mopro-ffi/build.rs b/app/mopro-ffi/build.rs new file mode 100644 index 000000000..ca4b249f7 --- /dev/null +++ b/app/mopro-ffi/build.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi::generate_scaffolding("src/mopro.udl").expect("Building the UDL file failed"); +} diff --git a/app/mopro-ffi/src/lib.rs b/app/mopro-ffi/src/lib.rs new file mode 100644 index 000000000..94c5c9b1b --- /dev/null +++ b/app/mopro-ffi/src/lib.rs @@ -0,0 +1,295 @@ +use mopro_core::middleware::circom; +use mopro_core::MoproError; + +use num_bigint::BigInt; +use std::collections::HashMap; +use std::path::Path; +use std::str::FromStr; +use std::sync::RwLock; + +#[derive(Debug)] +pub enum FFIError { + MoproError(mopro_core::MoproError), + SerializationError(String), +} + +#[derive(Debug, Clone)] +pub struct GenerateProofResult { + pub proof: Vec, + pub inputs: Vec, +} + +// NOTE: Make UniFFI and Rust happy, can maybe do some renaming here +#[allow(non_snake_case)] +#[derive(Debug, Clone)] +pub struct SetupResult { + pub provingKey: Vec, +} + +// pub inputs: Vec, + +impl From for FFIError { + fn from(error: mopro_core::MoproError) -> Self { + FFIError::MoproError(error) + } +} + +pub struct MoproCircom { + state: RwLock, +} + +impl Default for MoproCircom { + fn default() -> Self { + Self::new() + } +} + +#[cfg(not(feature = "dylib"))] +pub fn initialize_mopro() -> Result<(), MoproError> { + // TODO: Error handle / panic? + circom::initialize(); + Ok(()) +} + +#[cfg(feature = "dylib")] +pub fn initialize_mopro() -> Result<(), MoproError> { + println!("need to use dylib to init!"); + panic!("need to use dylib to init!"); +} + +#[cfg(feature = "dylib")] +pub fn initialize_mopro_dylib(dylib_path: String) -> Result<(), MoproError> { + // TODO: Error handle / panic? + let dylib_path = Path::new(dylib_path.as_str()); + circom::initialize(dylib_path); + Ok(()) +} + +#[cfg(not(feature = "dylib"))] +pub fn initialize_mopro_dylib(dylib_path: String) -> Result<(), MoproError> { + println!("dylib feature not enabled!"); + panic!("dylib feature not enabled!"); +} + +pub fn generate_proof2( + inputs: HashMap>, +) -> Result { + // Convert inputs to BigInt + let bigint_inputs = inputs + .into_iter() + .map(|(k, v)| { + ( + k, + v.into_iter() + .map(|i| BigInt::from_str(&i).unwrap()) + .collect(), + ) + }) + .collect(); + + let (proof, inputs) = circom::generate_proof2(bigint_inputs)?; + + let serialized_proof = circom::serialization::serialize_proof(&proof); + let serialized_inputs = circom::serialization::serialize_inputs(&inputs); + Ok(GenerateProofResult { + proof: serialized_proof, + inputs: serialized_inputs, + }) +} + +pub fn verify_proof2(proof: Vec, public_input: Vec) -> Result { + let deserialized_proof = circom::serialization::deserialize_proof(proof); + let deserialized_public_input = circom::serialization::deserialize_inputs(public_input); + let is_valid = circom::verify_proof2(deserialized_proof, deserialized_public_input)?; + Ok(is_valid) +} + +// TODO: Use FFIError::SerializationError instead +impl MoproCircom { + pub fn new() -> Self { + Self { + state: RwLock::new(circom::CircomState::new()), + } + } + + pub fn setup(&self, wasm_path: String, r1cs_path: String) -> Result { + let mut state_guard = self.state.write().unwrap(); + let pk = state_guard.setup(wasm_path.as_str(), r1cs_path.as_str())?; + Ok(SetupResult { + provingKey: circom::serialization::serialize_proving_key(&pk), + }) + } + + // inputs: circom::serialization::serialize_inputs(&inputs), + + pub fn generate_proof( + &self, + inputs: HashMap>, + ) -> Result { + let mut state_guard = self.state.write().unwrap(); + + // Convert inputs to BigInt + let bigint_inputs = inputs + .into_iter() + .map(|(k, v)| { + ( + k, + v.into_iter() + .map(|i| BigInt::from_str(&i).unwrap()) + .collect(), + ) + }) + .collect(); + + let (proof, inputs) = state_guard.generate_proof(bigint_inputs)?; + + Ok(GenerateProofResult { + proof: circom::serialization::serialize_proof(&proof), + inputs: circom::serialization::serialize_inputs(&inputs), + }) + } + + pub fn verify_proof(&self, proof: Vec, public_input: Vec) -> Result { + let state_guard = self.state.read().unwrap(); + let deserialized_proof = circom::serialization::deserialize_proof(proof); + let deserialized_public_input = circom::serialization::deserialize_inputs(public_input); + let is_valid = state_guard.verify_proof(deserialized_proof, deserialized_public_input)?; + Ok(is_valid) + } +} + +fn add(a: u32, b: u32) -> u32 { + a + b +} + +fn hello() -> String { + "Hello World from Rust".to_string() +} + +// TODO: Remove me +// UniFFI expects String type +// See https://mozilla.github.io/uniffi-rs/udl/builtin_types.html +// fn run_example(wasm_path: String, r1cs_path: String) -> Result<(), MoproError> { +// circom::run_example(wasm_path.as_str(), r1cs_path.as_str()) +// } + +uniffi::include_scaffolding!("mopro"); + +#[cfg(test)] +mod tests { + use super::*; + use ark_bn254::Fr; + use num_bigint::BigUint; + + fn bytes_to_circuit_inputs(input_vec: &Vec) -> HashMap> { + let bits = circom::utils::bytes_to_bits(&input_vec); + let converted_vec: Vec = bits + .into_iter() + .map(|bit| (bit as i32).to_string()) + .collect(); + let mut inputs = HashMap::new(); + inputs.insert("in".to_string(), converted_vec); + inputs + } + + fn bytes_to_circuit_outputs(bytes: &[u8]) -> Vec { + let bits = circom::utils::bytes_to_bits(bytes); + let field_bits = bits.into_iter().map(|bit| Fr::from(bit as u8)).collect(); + let circom_outputs = circom::serialization::SerializableInputs(field_bits); + circom::serialization::serialize_inputs(&circom_outputs) + } + + #[test] + fn add_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } + + #[test] + fn test_end_to_end() -> Result<(), MoproError> { + // Paths to your wasm and r1cs files + let wasm_path = + "./../mopro-core/examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"; + let r1cs_path = "./../mopro-core/examples/circom/multiplier2/target/multiplier2.r1cs"; + + // Create a new MoproCircom instance + let mopro_circom = MoproCircom::new(); + + // Step 1: Setup + let setup_result = mopro_circom.setup(wasm_path.to_string(), r1cs_path.to_string())?; + assert!(setup_result.provingKey.len() > 0); + + let mut inputs = HashMap::new(); + let a = BigUint::from_str( + "21888242871839275222246405745257275088548364400416034343698204186575808495616", + ) + .unwrap(); + let b = BigUint::from(1u8); + let c = a.clone() * b.clone(); + inputs.insert("a".to_string(), vec![a.to_string()]); + inputs.insert("b".to_string(), vec![b.to_string()]); + // output = [public output c, public input a] + let expected_output = vec![Fr::from(c), Fr::from(a)]; + let circom_outputs = circom::serialization::SerializableInputs(expected_output); + let serialized_outputs = circom::serialization::serialize_inputs(&circom_outputs); + + // Step 2: Generate Proof + let generate_proof_result = mopro_circom.generate_proof(inputs)?; + let serialized_proof = generate_proof_result.proof; + let serialized_inputs = generate_proof_result.inputs; + + assert!(serialized_proof.len() > 0); + assert_eq!(serialized_inputs, serialized_outputs); + + // Step 3: Verify Proof + let is_valid = mopro_circom.verify_proof(serialized_proof, serialized_inputs)?; + assert!(is_valid); + + Ok(()) + } + + #[test] + fn test_end_to_end_keccak() -> Result<(), MoproError> { + // Paths to your wasm and r1cs files + let wasm_path = + "./../mopro-core/examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm"; + let r1cs_path = "./../mopro-core/examples/circom/keccak256/target/keccak256_256_test.r1cs"; + + // Create a new MoproCircom instance + let mopro_circom = MoproCircom::new(); + + // Step 1: Setup + let setup_result = mopro_circom.setup(wasm_path.to_string(), r1cs_path.to_string())?; + assert!(setup_result.provingKey.len() > 0); + + // Prepare inputs + let input_vec = vec![ + 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, + ]; + + // Expected output + let expected_output_vec = vec![ + 37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, + 212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, + ]; + + let inputs = bytes_to_circuit_inputs(&input_vec); + let serialized_outputs = bytes_to_circuit_outputs(&expected_output_vec); + + // Step 2: Generate Proof + let generate_proof_result = mopro_circom.generate_proof(inputs)?; + let serialized_proof = generate_proof_result.proof; + let serialized_inputs = generate_proof_result.inputs; + + assert!(serialized_proof.len() > 0); + assert_eq!(serialized_inputs, serialized_outputs); + + // Step 3: Verify Proof + + let is_valid = mopro_circom.verify_proof(serialized_proof, serialized_inputs)?; + assert!(is_valid); + + Ok(()) + } +} diff --git a/app/mopro-ffi/src/mopro.udl b/app/mopro-ffi/src/mopro.udl new file mode 100644 index 000000000..875a5b1b8 --- /dev/null +++ b/app/mopro-ffi/src/mopro.udl @@ -0,0 +1,43 @@ +namespace mopro { + u32 add(u32 a, u32 b); + string hello(); + + [Throws=MoproError] + void initialize_mopro(); + + [Throws=MoproError] + void initialize_mopro_dylib(string dylib_path); + + [Throws=MoproError] + GenerateProofResult generate_proof2(record> circuit_inputs); + + [Throws=MoproError] + boolean verify_proof2(bytes proof, bytes public_input); +}; + +dictionary SetupResult { + bytes provingKey; +}; + +dictionary GenerateProofResult { + bytes proof; + bytes inputs; +}; + +[Error] +enum MoproError { + "CircomError", +}; + +interface MoproCircom { + constructor(); + + [Throws=MoproError] + SetupResult setup(string wasm_path, string r1cs_path); + + [Throws=MoproError] + GenerateProofResult generate_proof(record> circuit_inputs); + + [Throws=MoproError] + boolean verify_proof(bytes proof, bytes public_input); +}; diff --git a/app/mopro-ffi/tests/bindings/test_mopro.kts b/app/mopro-ffi/tests/bindings/test_mopro.kts new file mode 100644 index 000000000..838e72fe2 --- /dev/null +++ b/app/mopro-ffi/tests/bindings/test_mopro.kts @@ -0,0 +1,21 @@ +import uniffi.mopro.* + +var wasmPath = "../mopro-core/examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm" +var r1csPath = "../mopro-core/examples/circom/multiplier2/target/multiplier2.r1cs" + +try { + var moproCircom = MoproCircom() + var setupResult = moproCircom.setup(wasmPath, r1csPath) + assert(setupResult.provingKey.size > 0) { "Proving key should not be empty" } + + val inputs = mutableMapOf>() + inputs["a"] = listOf("3") + inputs["b"] = listOf("5") + + var generateProofResult = moproCircom.generateProof(inputs) + assert(generateProofResult.proof.size > 0) { "Proof is empty" } + var isValid = moproCircom.verifyProof(generateProofResult.proof, generateProofResult.inputs) + assert(isValid) { "Proof is invalid" } +} catch (e: Exception) { + println(e) +} diff --git a/app/mopro-ffi/tests/bindings/test_mopro.swift b/app/mopro-ffi/tests/bindings/test_mopro.swift new file mode 100644 index 000000000..7193618a7 --- /dev/null +++ b/app/mopro-ffi/tests/bindings/test_mopro.swift @@ -0,0 +1,65 @@ +import mopro +import Foundation + +let moproCircom = MoproCircom() + +let wasmPath = "./../../../../mopro-core/examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm" +let r1csPath = "./../../../../mopro-core/examples/circom/multiplier2/target/multiplier2.r1cs" + +func serializeOutputs(_ stringArray: [String]) -> [UInt8] { + var bytesArray: [UInt8] = [] + let length = stringArray.count + var littleEndianLength = length.littleEndian + let targetLength = 32 + withUnsafeBytes(of: &littleEndianLength) { + bytesArray.append(contentsOf: $0) + } + for value in stringArray { + // TODO: should handle 254-bit input + var littleEndian = Int32(value)!.littleEndian + var byteLength = 0 + withUnsafeBytes(of: &littleEndian) { + bytesArray.append(contentsOf: $0) + byteLength = byteLength + $0.count + } + if byteLength < targetLength { + let paddingCount = targetLength - byteLength + let paddingArray = [UInt8](repeating: 0, count: paddingCount) + bytesArray.append(contentsOf: paddingArray) + } + } + return bytesArray +} + +do { + // Setup + let setupResult = try moproCircom.setup(wasmPath: wasmPath, r1csPath: r1csPath) + assert(!setupResult.provingKey.isEmpty, "Proving key should not be empty") + + // Prepare inputs + var inputs = [String: [String]]() + let a = 3 + let b = 5 + let c = a*b + inputs["a"] = [String(a)] + inputs["b"] = [String(b)] + + // Expected outputs + let outputs: [String] = [String(c), String(a)] + let expectedOutput: [UInt8] = serializeOutputs(outputs) + + // Generate Proof + let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs) + assert(!generateProofResult.proof.isEmpty, "Proof should not be empty") + + // Verify Proof + assert(Data(expectedOutput) == generateProofResult.inputs, "Circuit outputs mismatch the expected outputs") + + let isValid = try moproCircom.verifyProof(proof: generateProofResult.proof, publicInput: generateProofResult.inputs) + assert(isValid, "Proof verification should succeed") + +} catch let error as MoproError { + print("MoproError: \(error)") +} catch { + print("Unexpected error: \(error)") +} diff --git a/app/mopro-ffi/tests/bindings/test_mopro_keccak.kts b/app/mopro-ffi/tests/bindings/test_mopro_keccak.kts new file mode 100644 index 000000000..5fb5b30a8 --- /dev/null +++ b/app/mopro-ffi/tests/bindings/test_mopro_keccak.kts @@ -0,0 +1,279 @@ +import uniffi.mopro.* + +var wasmPath = + "../mopro-core/examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm" +var r1csPath = "../mopro-core/examples/circom/keccak256/target/keccak256_256_test.r1cs" + +try { + var moproCircom = MoproCircom() + var setupResult = moproCircom.setup(wasmPath, r1csPath) + assert(setupResult.provingKey.size > 0) { "Proving key should not be empty" } + + val inputs = mutableMapOf>() + inputs["in"] = + listOf( + "0", + "0", + "1", + "0", + "1", + "1", + "1", + "0", + "1", + "0", + "1", + "0", + "0", + "1", + "1", + "0", + "1", + "1", + "0", + "0", + "1", + "1", + "1", + "0", + "0", + "0", + "1", + "0", + "1", + "1", + "1", + "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", + "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", + "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", + "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", + "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", + "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", + "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", + "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", + "0" + ) + + var generateProofResult = moproCircom.generateProof(inputs) + assert(generateProofResult.proof.size > 0) { "Proof is empty" } + var isValid = moproCircom.verifyProof(generateProofResult.proof, generateProofResult.inputs) + assert(isValid) { "Proof is invalid" } +} catch (e: Exception) { + println(e) +} diff --git a/app/mopro-ffi/tests/bindings/test_mopro_keccak.swift b/app/mopro-ffi/tests/bindings/test_mopro_keccak.swift new file mode 100644 index 000000000..2ca7dc476 --- /dev/null +++ b/app/mopro-ffi/tests/bindings/test_mopro_keccak.swift @@ -0,0 +1,82 @@ +import mopro +import Foundation + +let moproCircom = MoproCircom() + +let wasmPath = "./../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm" +let r1csPath = "./../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test.r1cs" + +// Helper function to convert bytes to bits +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)) + } + } + return bits +} + +func serializeOutputs(_ stringArray: [String]) -> [UInt8] { + var bytesArray: [UInt8] = [] + let length = stringArray.count + var littleEndianLength = length.littleEndian + let targetLength = 32 + withUnsafeBytes(of: &littleEndianLength) { + bytesArray.append(contentsOf: $0) + } + for value in stringArray { + // TODO: should handle 254-bit input + var littleEndian = Int32(value)!.littleEndian + var byteLength = 0 + withUnsafeBytes(of: &littleEndian) { + bytesArray.append(contentsOf: $0) + byteLength = byteLength + $0.count + } + if byteLength < targetLength { + let paddingCount = targetLength - byteLength + let paddingArray = [UInt8](repeating: 0, count: paddingCount) + bytesArray.append(contentsOf: paddingArray) + } + } + return bytesArray +} + +do { + // Setup + let setupResult = try moproCircom.setup(wasmPath: wasmPath, r1csPath: r1csPath) + assert(!setupResult.provingKey.isEmpty, "Proving key should not be empty") + + // 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 + + // Expected outputs + let outputVec: [UInt8] = [ + 37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, + 212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, + ] + let outputBits: [String] = bytesToBits(bytes: outputVec) + let expectedOutput: [UInt8] = serializeOutputs(outputBits) + + // Generate Proof + let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs) + assert(!generateProofResult.proof.isEmpty, "Proof should not be empty") + + // Verify Proof + assert(Data(expectedOutput) == generateProofResult.inputs, "Circuit outputs mismatch the expected outputs") + + let isValid = try moproCircom.verifyProof(proof: generateProofResult.proof, publicInput: generateProofResult.inputs) + assert(isValid, "Proof verification should succeed") + +} catch let error as MoproError { + print("MoproError: \(error)") +} catch { + print("Unexpected error: \(error)") +} diff --git a/app/mopro-ffi/tests/bindings/test_mopro_keccak2.kts b/app/mopro-ffi/tests/bindings/test_mopro_keccak2.kts new file mode 100644 index 000000000..832628df9 --- /dev/null +++ b/app/mopro-ffi/tests/bindings/test_mopro_keccak2.kts @@ -0,0 +1,273 @@ +import uniffi.mopro.* + +try { + initializeMopro() + + val inputs = mutableMapOf>() + inputs["in"] = + listOf( + "0", + "0", + "1", + "0", + "1", + "1", + "1", + "0", + "1", + "0", + "1", + "0", + "0", + "1", + "1", + "0", + "1", + "1", + "0", + "0", + "1", + "1", + "1", + "0", + "0", + "0", + "1", + "0", + "1", + "1", + "1", + "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", + "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", + "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", + "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", + "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", + "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", + "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", + "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", + "0" + ) + + var generateProofResult = generateProof2(inputs) + assert(generateProofResult.proof.size > 0) { "Proof is empty" } + var isValid = verifyProof2(generateProofResult.proof, generateProofResult.inputs) + assert(isValid) { "Proof is invalid" } +} catch (e: Exception) { + println(e) +} diff --git a/app/mopro-ffi/tests/bindings/test_mopro_keccak2.swift b/app/mopro-ffi/tests/bindings/test_mopro_keccak2.swift new file mode 100644 index 000000000..a489bc98c --- /dev/null +++ b/app/mopro-ffi/tests/bindings/test_mopro_keccak2.swift @@ -0,0 +1,86 @@ +import Foundation +import mopro + +//let moproCircom = MoproCircom() + +// Using zkey and generate_proof2 + +// let wasmPath = "./../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test_js/keccak256_256_test.wasm" +// let r1csPath = "./../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test.r1cs" + +// Helper function to convert bytes to bits +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)) + } + } + return bits +} + +func serializeOutputs(_ stringArray: [String]) -> [UInt8] { + var bytesArray: [UInt8] = [] + let length = stringArray.count + var littleEndianLength = length.littleEndian + let targetLength = 32 + withUnsafeBytes(of: &littleEndianLength) { + bytesArray.append(contentsOf: $0) + } + for value in stringArray { + // TODO: should handle 254-bit input + var littleEndian = Int32(value)!.littleEndian + var byteLength = 0 + withUnsafeBytes(of: &littleEndian) { + bytesArray.append(contentsOf: $0) + byteLength = byteLength + $0.count + } + if byteLength < targetLength { + let paddingCount = targetLength - byteLength + let paddingArray = [UInt8](repeating: 0, count: paddingCount) + bytesArray.append(contentsOf: paddingArray) + } + } + return bytesArray +} + +do { + // // Setup + // let setupResult = try moproCircom.setup(wasmPath: wasmPath, r1csPath: r1csPath) + // assert(!setupResult.provingKey.isEmpty, "Proving key should not be empty") + + // 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 + + // Expected outputs + let outputVec: [UInt8] = [ + 37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88, + 212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21, + ] + let outputBits: [String] = bytesToBits(bytes: outputVec) + let expectedOutput: [UInt8] = serializeOutputs(outputBits) + + // // Generate Proof + let generateProofResult = try generateProof2(circuitInputs: inputs) + // let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs) + assert(!generateProofResult.proof.isEmpty, "Proof should not be empty") + + // // Verify Proof + assert(Data(expectedOutput) == generateProofResult.inputs, "Circuit outputs mismatch the expected outputs") + + let isValid = try verifyProof2( + proof: generateProofResult.proof, publicInput: generateProofResult.inputs) + assert(isValid, "Proof verification should succeed") + +} catch let error as MoproError { + print("MoproError: \(error)") +} catch { + print("Unexpected error: \(error)") +} diff --git a/app/mopro-ffi/tests/bindings/test_mopro_rsa.kts b/app/mopro-ffi/tests/bindings/test_mopro_rsa.kts new file mode 100644 index 000000000..15e770f08 --- /dev/null +++ b/app/mopro-ffi/tests/bindings/test_mopro_rsa.kts @@ -0,0 +1,115 @@ +import uniffi.mopro.*; + +var wasmPath = "../mopro-core/examples/circom/rsa/target/main_js/main.wasm" +var r1csPath = "../mopro-core/examples/circom/rsa/target/main.r1cs" + +try { + var moproCircom = MoproCircom() + var setupResult = moproCircom.setup(wasmPath, r1csPath) + assert(setupResult.provingKey.size > 0) { "Proving key should not be empty"} + + val inputs = mutableMapOf>() + inputs["signature"] = listOf("3582320600048169363", + "7163546589759624213", + "18262551396327275695", + "4479772254206047016", + "1970274621151677644", + "6547632513799968987", + "921117808165172908", + "7155116889028933260", + "16769940396381196125", + "17141182191056257954", + "4376997046052607007", + "17471823348423771450", + "16282311012391954891", + "70286524413490741", + "1588836847166444745", + "15693430141227594668", + "13832254169115286697", + "15936550641925323613", + "323842208142565220", + "6558662646882345749", + "15268061661646212265", + "14962976685717212593", + "15773505053543368901", + "9586594741348111792", + "1455720481014374292", + "13945813312010515080", + "6352059456732816887", + "17556873002865047035", + "2412591065060484384", + "11512123092407778330", + "8499281165724578877", + "12768005853882726493") + inputs["modulus"] = listOf("13792647154200341559", + "12773492180790982043", + "13046321649363433702", + "10174370803876824128", + "7282572246071034406", + "1524365412687682781", + "4900829043004737418", + "6195884386932410966", + "13554217876979843574", + "17902692039595931737", + "12433028734895890975", + "15971442058448435996", + "4591894758077129763", + "11258250015882429548", + "16399550288873254981", + "8246389845141771315", + "14040203746442788850", + "7283856864330834987", + "12297563098718697441", + "13560928146585163504", + "7380926829734048483", + "14591299561622291080", + "8439722381984777599", + "17375431987296514829", + "16727607878674407272", + "3233954801381564296", + "17255435698225160983", + "15093748890170255670", + "15810389980847260072", + "11120056430439037392", + "5866130971823719482", + "13327552690270163501",) + inputs["base_message"] = listOf("18114495772705111902", + "2254271930739856077", + "2068851770", + "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", + "0",) + + var generateProofResult = moproCircom.generateProof(inputs) + assert(generateProofResult.proof.size > 0) { "Proof is empty"} + var isValid = moproCircom.verifyProof(generateProofResult.proof, generateProofResult.inputs) + assert(isValid) { "Proof is invalid"} +} catch (e: Exception) { + println(e); +} diff --git a/app/mopro-ffi/tests/bindings/test_mopro_rsa.swift b/app/mopro-ffi/tests/bindings/test_mopro_rsa.swift new file mode 100644 index 000000000..917fbbe0f --- /dev/null +++ b/app/mopro-ffi/tests/bindings/test_mopro_rsa.swift @@ -0,0 +1,174 @@ +import mopro +import Foundation + +let moproCircom = MoproCircom() + +let wasmPath = "./../../../../mopro-core/examples/circom/rsa/target/main_js/main.wasm" +let r1csPath = "./../../../../mopro-core/examples/circom/rsa/target/main.r1cs" + +// Helper function to convert bytes to bits +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)) + } + } + return bits +} + +func serializeOutputs(_ stringArray: [String]) -> [UInt8] { + var bytesArray: [UInt8] = [] + let length = stringArray.count + var littleEndianLength = length.littleEndian + let targetLength = 32 + withUnsafeBytes(of: &littleEndianLength) { + bytesArray.append(contentsOf: $0) + } + for value in stringArray { + // TODO: should handle 254-bit input + var littleEndian = Int32(value)!.littleEndian + var byteLength = 0 + withUnsafeBytes(of: &littleEndian) { + bytesArray.append(contentsOf: $0) + byteLength = byteLength + $0.count + } + if byteLength < targetLength { + let paddingCount = targetLength - byteLength + let paddingArray = [UInt8](repeating: 0, count: paddingCount) + bytesArray.append(contentsOf: paddingArray) + } + } + return bytesArray +} + +do { + // Setup + let setupResult = try moproCircom.setup(wasmPath: wasmPath, r1csPath: r1csPath) + assert(!setupResult.provingKey.isEmpty, "Proving key should not be empty") + + // Prepare inputs + let signature: [String] = [ + "3582320600048169363", + "7163546589759624213", + "18262551396327275695", + "4479772254206047016", + "1970274621151677644", + "6547632513799968987", + "921117808165172908", + "7155116889028933260", + "16769940396381196125", + "17141182191056257954", + "4376997046052607007", + "17471823348423771450", + "16282311012391954891", + "70286524413490741", + "1588836847166444745", + "15693430141227594668", + "13832254169115286697", + "15936550641925323613", + "323842208142565220", + "6558662646882345749", + "15268061661646212265", + "14962976685717212593", + "15773505053543368901", + "9586594741348111792", + "1455720481014374292", + "13945813312010515080", + "6352059456732816887", + "17556873002865047035", + "2412591065060484384", + "11512123092407778330", + "8499281165724578877", + "12768005853882726493", + ] + + let modulus: [String] = [ + "13792647154200341559", + "12773492180790982043", + "13046321649363433702", + "10174370803876824128", + "7282572246071034406", + "1524365412687682781", + "4900829043004737418", + "6195884386932410966", + "13554217876979843574", + "17902692039595931737", + "12433028734895890975", + "15971442058448435996", + "4591894758077129763", + "11258250015882429548", + "16399550288873254981", + "8246389845141771315", + "14040203746442788850", + "7283856864330834987", + "12297563098718697441", + "13560928146585163504", + "7380926829734048483", + "14591299561622291080", + "8439722381984777599", + "17375431987296514829", + "16727607878674407272", + "3233954801381564296", + "17255435698225160983", + "15093748890170255670", + "15810389980847260072", + "11120056430439037392", + "5866130971823719482", + "13327552690270163501", + ] + let base_message: [String] = [ + "18114495772705111902", + "2254271930739856077", + "2068851770", + "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", + "0", + ] + + var inputs = [String: [String]]() + inputs["signature"] = signature; + inputs["modulus"] = modulus; + inputs["base_message"] = base_message; + + + // Generate Proof + let generateProofResult = try moproCircom.generateProof(circuitInputs: inputs) + assert(!generateProofResult.proof.isEmpty, "Proof should not be empty") + + // Verifying the Proof + let isValid = try moproCircom.verifyProof(proof: generateProofResult.proof, publicInput: generateProofResult.inputs) + assert(isValid, "Proof verification should succeed") + +} catch let error as MoproError { + print("MoproError: \(error)") +} catch { + print("Unexpected error: \(error)") +} diff --git a/app/mopro-ffi/tests/bindings/test_mopro_rsa2.swift b/app/mopro-ffi/tests/bindings/test_mopro_rsa2.swift new file mode 100644 index 000000000..70998bd08 --- /dev/null +++ b/app/mopro-ffi/tests/bindings/test_mopro_rsa2.swift @@ -0,0 +1,167 @@ +import mopro +import Foundation + +// Helper function to convert bytes to bits +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)) + } + } + return bits +} + +func serializeOutputs(_ stringArray: [String]) -> [UInt8] { + var bytesArray: [UInt8] = [] + let length = stringArray.count + var littleEndianLength = length.littleEndian + let targetLength = 32 + withUnsafeBytes(of: &littleEndianLength) { + bytesArray.append(contentsOf: $0) + } + for value in stringArray { + // TODO: should handle 254-bit input + var littleEndian = Int32(value)!.littleEndian + var byteLength = 0 + withUnsafeBytes(of: &littleEndian) { + bytesArray.append(contentsOf: $0) + byteLength = byteLength + $0.count + } + if byteLength < targetLength { + let paddingCount = targetLength - byteLength + let paddingArray = [UInt8](repeating: 0, count: paddingCount) + bytesArray.append(contentsOf: paddingArray) + } + } + return bytesArray +} + +do { + // Initialize + try initializeMopro() + + // Prepare inputs + let signature: [String] = [ + "3582320600048169363", + "7163546589759624213", + "18262551396327275695", + "4479772254206047016", + "1970274621151677644", + "6547632513799968987", + "921117808165172908", + "7155116889028933260", + "16769940396381196125", + "17141182191056257954", + "4376997046052607007", + "17471823348423771450", + "16282311012391954891", + "70286524413490741", + "1588836847166444745", + "15693430141227594668", + "13832254169115286697", + "15936550641925323613", + "323842208142565220", + "6558662646882345749", + "15268061661646212265", + "14962976685717212593", + "15773505053543368901", + "9586594741348111792", + "1455720481014374292", + "13945813312010515080", + "6352059456732816887", + "17556873002865047035", + "2412591065060484384", + "11512123092407778330", + "8499281165724578877", + "12768005853882726493", + ] + + let modulus: [String] = [ + "13792647154200341559", + "12773492180790982043", + "13046321649363433702", + "10174370803876824128", + "7282572246071034406", + "1524365412687682781", + "4900829043004737418", + "6195884386932410966", + "13554217876979843574", + "17902692039595931737", + "12433028734895890975", + "15971442058448435996", + "4591894758077129763", + "11258250015882429548", + "16399550288873254981", + "8246389845141771315", + "14040203746442788850", + "7283856864330834987", + "12297563098718697441", + "13560928146585163504", + "7380926829734048483", + "14591299561622291080", + "8439722381984777599", + "17375431987296514829", + "16727607878674407272", + "3233954801381564296", + "17255435698225160983", + "15093748890170255670", + "15810389980847260072", + "11120056430439037392", + "5866130971823719482", + "13327552690270163501", + ] + let base_message: [String] = [ + "18114495772705111902", + "2254271930739856077", + "2068851770", + "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", + "0", + ] + + var inputs = [String: [String]]() + inputs["signature"] = signature; + inputs["modulus"] = modulus; + inputs["base_message"] = base_message; + + // Generate Proof + let generateProofResult = try generateProof2(circuitInputs: inputs) + assert(!generateProofResult.proof.isEmpty, "Proof should not be empty") + + // Verifying the Proof + let isValid = try verifyProof2(proof: generateProofResult.proof, publicInput: generateProofResult.inputs) + assert(isValid, "Proof verification should succeed") + +} catch let error as MoproError { + print("MoproError: \(error)") +} catch { + print("Unexpected error: \(error)") +} diff --git a/app/mopro-ffi/tests/test_generated_bindings.rs b/app/mopro-ffi/tests/test_generated_bindings.rs new file mode 100644 index 000000000..d88f82a2c --- /dev/null +++ b/app/mopro-ffi/tests/test_generated_bindings.rs @@ -0,0 +1,13 @@ +uniffi::build_foreign_language_testcases!( + "tests/bindings/test_mopro.swift", + "tests/bindings/test_mopro.kts", + // "tests/bindings/test_mopro.rb", + // "tests/bindings/test_mopro.py", + "tests/bindings/test_mopro_keccak.swift", + // "tests/bindings/test_mopro_keccak.kts", // FIXME: java.lang.OutOfMemoryError: Java heap space + "tests/bindings/test_mopro_keccak2.swift", + "tests/bindings/test_mopro_keccak2.kts", + "tests/bindings/test_mopro_rsa.swift", + // "tests/bindings/test_mopro_rsa.kts", // FIXME: java.lang.OutOfMemoryError: Java heap space + // "tests/bindings/test_mopro_rsa2.swift", +); diff --git a/app/mopro-ffi/uniffi-bindgen.rs b/app/mopro-ffi/uniffi-bindgen.rs new file mode 100644 index 000000000..f6cff6cf1 --- /dev/null +++ b/app/mopro-ffi/uniffi-bindgen.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi::uniffi_bindgen_main() +} diff --git a/app/mopro-ffi/uniffi.toml b/app/mopro-ffi/uniffi.toml new file mode 100644 index 000000000..f14925e0c --- /dev/null +++ b/app/mopro-ffi/uniffi.toml @@ -0,0 +1,2 @@ +[bindings.swift] +module_name = "mopro" From f6c89a357b36ff083bf67b8ecac9b076e84a2d76 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Mon, 15 Jan 2024 18:23:45 +0100 Subject: [PATCH 06/12] proof inputs comming from TS frontend --- app/App.tsx | 4 +++- app/ios/Prover.m | 3 ++- app/ios/Prover.swift | 40 ++++++++++++++++++++++------------------ 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/app/App.tsx b/app/App.tsx index 947aa83d1..fd5ace5dc 100644 --- a/app/App.tsx +++ b/app/App.tsx @@ -663,7 +663,9 @@ function App(): JSX.Element { {testResult && {testResult}} - - - - - diff --git a/app/ios/PassportReader.swift b/app/ios/PassportReader.swift index 9bdfe6567..96a82876f 100644 --- a/app/ios/PassportReader.swift +++ b/app/ios/PassportReader.swift @@ -194,10 +194,16 @@ class PassportReader: NSObject{ do { let sod = passport.getDataGroup(DataGroupId.SOD) as! SOD - ret["eContentBase64"] = try sod.getEncapsulatedContent().base64EncodedString() + // ret["concatenatedDataHashes"] = try sod.getEncapsulatedContent().base64EncodedString() // this is what we call concatenatedDataHashes, not the true eContent + ret["eContentBase64"] = try sod.getEncapsulatedContent().base64EncodedString() // this is what we call concatenatedDataHashes, not the true eContent ret["signatureAlgorithm"] = try sod.getSignatureAlgorithm() + + let messageDigestFromSignedAttributes = try sod.getMessageDigestFromSignedAttributes() + let signedAttributes = try sod.getSignedAttributes() + print("messageDigestFromSignedAttributes", messageDigestFromSignedAttributes) + ret["signedAttributes"] = signedAttributes.base64EncodedString() // if let pubKey = convertOpaquePointerToSecKey(opaquePointer: sod.pubKey), // let serializedPublicKey = serializePublicKey(pubKey) { // ret["publicKeyBase64"] = serializedPublicKey diff --git a/app/ios/Podfile b/app/ios/Podfile index 721152643..54addf801 100644 --- a/app/ios/Podfile +++ b/app/ios/Podfile @@ -34,7 +34,7 @@ target 'ProofOfPassport' do flags = get_default_flags() use_frameworks! - pod 'NFCPassportReader', git: 'https://github.com/0xturboblitz/NFCPassportReader.git', commit: '07b3662702834676b547718998fa377fe5f00776' + pod 'NFCPassportReader', git: 'https://github.com/0xturboblitz/NFCPassportReader.git', commit: 'd36952eeaa2025ff1a9c9abbc244bd5ff53eb0f9' pod 'MoproKit', :path => './MoproKit' use_react_native!( diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index 50ed760f8..afdcabe3b 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -403,7 +403,7 @@ DEPENDENCIES: - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - MoproKit (from `./MoproKit`) - - NFCPassportReader (from `https://github.com/0xturboblitz/NFCPassportReader.git`, commit `07b3662702834676b547718998fa377fe5f00776`) + - NFCPassportReader (from `https://github.com/0xturboblitz/NFCPassportReader.git`, commit `d36952eeaa2025ff1a9c9abbc244bd5ff53eb0f9`) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) @@ -460,7 +460,7 @@ EXTERNAL SOURCES: MoproKit: :path: "./MoproKit" NFCPassportReader: - :commit: 07b3662702834676b547718998fa377fe5f00776 + :commit: d36952eeaa2025ff1a9c9abbc244bd5ff53eb0f9 :git: https://github.com/0xturboblitz/NFCPassportReader.git RCT-Folly: :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" @@ -533,7 +533,7 @@ EXTERNAL SOURCES: CHECKOUT OPTIONS: NFCPassportReader: - :commit: 07b3662702834676b547718998fa377fe5f00776 + :commit: d36952eeaa2025ff1a9c9abbc244bd5ff53eb0f9 :git: https://github.com/0xturboblitz/NFCPassportReader.git SPEC CHECKSUMS: @@ -582,6 +582,6 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Yoga: 8796b55dba14d7004f980b54bcc9833ee45b28ce -PODFILE CHECKSUM: 52f9302a4d936d9bacb79ef5417142b1e96c5f0e +PODFILE CHECKSUM: d401e6efe0c933985349c8c115c7edca8fef3182 COCOAPODS: 1.14.3 diff --git a/app/ios/ProofOfPassport.xcodeproj/project.pbxproj b/app/ios/ProofOfPassport.xcodeproj/project.pbxproj index 09e5ac29c..b9f442f7f 100644 --- a/app/ios/ProofOfPassport.xcodeproj/project.pbxproj +++ b/app/ios/ProofOfPassport.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 00E356F31AD99517003FC87E /* ProofOfPassportTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ProofOfPassportTests.m */; }; + 057DFC5F2B56DC0D003D24A3 /* libmopro_ffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 057DFC5E2B56DC0D003D24A3 /* libmopro_ffi.a */; }; 05BD9DCC2B548AA900823023 /* MoproKit in Resources */ = {isa = PBXBuildFile; fileRef = 05BD9DCB2B548AA900823023 /* MoproKit */; }; 05BD9DCE2B554FA300823023 /* libmopro_ffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 05BD9DCD2B554FA300823023 /* libmopro_ffi.a */; }; 05EDEDC62B52D25D00AA51AD /* Prover.m in Sources */ = {isa = PBXBuildFile; fileRef = 05EDEDC42B52D25D00AA51AD /* Prover.m */; }; @@ -37,6 +38,7 @@ 00E356EE1AD99517003FC87E /* ProofOfPassportTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProofOfPassportTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 00E356F21AD99517003FC87E /* ProofOfPassportTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProofOfPassportTests.m; sourceTree = ""; }; + 057DFC5E2B56DC0D003D24A3 /* libmopro_ffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmopro_ffi.a; path = MoproKit/Libs/libmopro_ffi.a; sourceTree = ""; }; 05A0773D2B5333CE0037E489 /* MoproKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MoproKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 05BD9DCB2B548AA900823023 /* MoproKit */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MoproKit; sourceTree = ""; }; 05BD9DCD2B554FA300823023 /* libmopro_ffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmopro_ffi.a; path = MoproKit/Libs/libmopro_ffi.a; sourceTree = ""; }; @@ -78,6 +80,7 @@ files = ( 0651723A94C70A2B31E3E4F8 /* Pods_ProofOfPassport.framework in Frameworks */, 05BD9DCE2B554FA300823023 /* libmopro_ffi.a in Frameworks */, + 057DFC5F2B56DC0D003D24A3 /* libmopro_ffi.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -108,6 +111,7 @@ 05EDEDC52B52D25D00AA51AD /* Prover.swift */, 905B700A2A72A5E900AFA232 /* masterList.pem */, 905B70082A729CD400AFA232 /* ProofOfPassport.entitlements */, + 057DFC5E2B56DC0D003D24A3 /* libmopro_ffi.a */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 05BD9DCB2B548AA900823023 /* MoproKit */, 13B07FB01A68108700A75B9A /* AppDelegate.mm */, diff --git a/app/ios/Prover.swift b/app/ios/Prover.swift index 4892cd745..e4aea8688 100644 --- a/app/ios/Prover.swift +++ b/app/ios/Prover.swift @@ -36,9 +36,11 @@ class Prover: NSObject { // Log the time taken for initialization print("Initializing arkzkey took \(timeTaken) seconds.") + resolve("Done") } catch { // Log any errors that occurred during initialization print("An error occurred during initialization: \(error)") + reject("PROVER", "An error occurred during initialization", error) } } } @@ -47,8 +49,9 @@ class Prover: NSObject { func runProveAction(_ inputs: [String: [String]], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { // Logic for prove (generate_proof2) do { - // format of inputs, if you want to manage it manually: + + // WORKING, SAMPLE DATA: // let mrz: [String] = ["97","91","95","31","88","80","60","70","82","65","68","85","80","79","78","84","60","60","65","76","80","72","79","78","83","69","60","72","85","71","85","69","83","60","65","76","66","69","82","84","60","60","60","60","60","60","60","60","60","50","52","72","66","56","49","56","51","50","52","70","82","65","48","52","48","50","49","49","49","77","51","49","49","49","49","49","53","60","60","60","60","60","60","60","60","60","60","60","60","60","60","48","50"] // let reveal_bitmap: [String] = ["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","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","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","0","0","0","0"] // let dataHashes: [String] = ["48","130","1","37","2","1","0","48","11","6","9","96","134","72","1","101","3","4","2","1","48","130","1","17","48","37","2","1","1","4","32","176","223","31","133","108","84","158","102","70","11","165","175","196","12","201","130","25","131","46","125","156","194","28","23","55","133","157","164","135","136","220","78","48","37","2","1","2","4","32","190","82","180","235","222","33","79","50","152","136","142","35","116","224","6","242","156","141","128","248","10","61","98","86","248","45","207","210","90","232","175","38","48","37","2","1","3","4","32","0","194","104","108","237","246","97","230","116","198","69","110","26","87","17","89","110","199","108","250","36","21","39","87","110","102","250","213","174","131","171","174","48","37","2","1","11","4","32","136","155","87","144","111","15","152","127","85","25","154","81","20","58","51","75","193","116","234","0","60","30","29","30","183","141","72","247","255","203","100","124","48","37","2","1","12","4","32","41","234","106","78","31","11","114","137","237","17","92","71","134","47","62","78","189","233","201","214","53","4","47","189","201","133","6","121","34","131","64","142","48","37","2","1","13","4","32","91","222","210","193","62","222","104","82","36","41","138","253","70","15","148","208","156","45","105","171","241","195","185","43","217","162","146","201","222","89","238","38","48","37","2","1","14","4","32","76","123","216","13","51","227","72","245","59","193","238","166","103","49","23","164","171","188","194","197","156","187","249","28","198","95","69","15","182","56","54","38"] @@ -77,17 +80,37 @@ class Prover: NSObject { // Record end time and compute duration let end = CFAbsoluteTimeGetCurrent() let timeTaken = end - start + print("Proof generation took \(timeTaken) seconds.") // Store the generated proof and public inputs for later verification + print("generateProofResult", generateProofResult) generatedProof = generateProofResult.proof publicInputs = generateProofResult.inputs - print("Proof generation took \(timeTaken) seconds.") - resolve(generateProofResult) + // Convert Data to array of bytes + let proofBytes = [UInt8](generateProofResult.proof) + let inputsBytes = [UInt8](generateProofResult.inputs) + + print("proofBytes", proofBytes) + print("inputsBytes", inputsBytes) + + // Create a dictionary with byte arrays + let resultDict: [String: [UInt8]] = [ + "proof": proofBytes, + "inputs": inputsBytes + ] + + // Serialize dictionary to JSON + let jsonData = try JSONSerialization.data(withJSONObject: resultDict, options: []) + let jsonString = String(data: jsonData, encoding: .utf8)! + + resolve(jsonString) } catch let error as MoproError { print("MoproError: \(error)") + reject("PROVER", "An error occurred during proof generation", error) } catch { print("Unexpected error: \(error)") + reject("PROVER", "An error occurred during proof generation", error) } } @@ -105,10 +128,13 @@ class Prover: NSObject { assert(isValid, "Proof verification should succeed") print("Proof verification succeeded.") + resolve(isValid) } catch let error as MoproError { - print("MoproError: \(error)") + print("MoproError: \(error)") + reject("PROVER", "An error occurred during proof verification", error) } catch { print("Unexpected error: \(error)") + reject("PROVER", "An error occurred during proof verification", error) } } } diff --git a/common/src/utils/types.ts b/common/src/utils/types.ts index 7fb011bf3..5379310b9 100644 --- a/common/src/utils/types.ts +++ b/common/src/utils/types.ts @@ -4,7 +4,7 @@ export type PassportData = { mrz: string; signatureAlgorithm: string; pubKey: {modulus?: string, curveName?: string, publicKeyQ?: string}; - dataGroupHashes: DataHash[]; + dataGroupHashes: DataHash[] | number[]; eContent: number[]; encryptedDigest: number[]; }; diff --git a/common/src/utils/utils.ts b/common/src/utils/utils.ts index 62f0b686a..476289763 100644 --- a/common/src/utils/utils.ts +++ b/common/src/utils/utils.ts @@ -185,4 +185,46 @@ export function hexStringToSignedIntArray(hexString: string) { result.push(byte > 127 ? byte - 256 : byte); } return result; -}; \ No newline at end of file +}; + +function bytesToBigInt(bytes: number[]) { + let hex = bytes.reverse().map(byte => byte.toString(16).padStart(2, '0')).join(''); + // console.log('hex', hex) + return BigInt(`0x${hex}`).toString(); +} + +function splitInto(arr: number[], size: number) { + const res = []; + for(let i = 0; i < arr.length; i += size) { + res.push(arr.slice(i, i + size)); + } + return res; +} + +function setFirstBitOfLastByteToZero(bytes: number[]) { + bytes[bytes.length - 1] &= 0x7F; // AND with 01111111 to set the first bit of the last byte to 0 + return bytes; +} + +// from reverse engineering ark-serialize. +export function formatProofIOS(proof: number[]) { + const splittedProof = splitInto(proof, 32); + splittedProof[1] = setFirstBitOfLastByteToZero(splittedProof[1]); + splittedProof[5] = setFirstBitOfLastByteToZero(splittedProof[5]); // We might need to do the same for input 3 + splittedProof[7] = setFirstBitOfLastByteToZero(splittedProof[7]); + const proooof = splittedProof.map(bytesToBigInt); + + return { + "a": [proooof[0], proooof[1]], + "b": [ + [proooof[2], proooof[3]], + [proooof[4], proooof[5]] + ], + "c": [proooof[6], proooof[7]] + } +} + +export function formatInputsIOS(inputs: number[]) { + const splitted = splitInto(inputs.slice(8), 32); + return splitted.map(bytesToBigInt); +} \ No newline at end of file