diff --git a/.gitignore b/.gitignore index 0023a53..af075cc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ DerivedData/ .swiftpm/configuration/registries.json .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata .netrc +.idea diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/rapidsnark.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/rapidsnark.xcscheme new file mode 100644 index 0000000..3fc8096 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/rapidsnark.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Libs/Rapidsnark.xcframework/Info.plist b/Libs/Rapidsnark.xcframework/Info.plist new file mode 100644 index 0000000..c1fd302 --- /dev/null +++ b/Libs/Rapidsnark.xcframework/Info.plist @@ -0,0 +1,49 @@ + + + + + AvailableLibraries + + + BinaryPath + librapidsnarkmerged.a + HeadersPath + Headers + LibraryIdentifier + ios-arm64 + LibraryPath + librapidsnarkmerged.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + BinaryPath + librapidsnarkmerged.a + HeadersPath + Headers + LibraryIdentifier + ios-arm64_arm64e_x86_64-simulator + LibraryPath + librapidsnarkmerged.a + SupportedArchitectures + + arm64 + arm64e + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Libs/Rapidsnark.xcframework/ios-arm64/Headers/RapidsnarkFramework.h b/Libs/Rapidsnark.xcframework/ios-arm64/Headers/RapidsnarkFramework.h new file mode 100644 index 0000000..751d7b3 --- /dev/null +++ b/Libs/Rapidsnark.xcframework/ios-arm64/Headers/RapidsnarkFramework.h @@ -0,0 +1,2 @@ +#import "verifier.h" +#import "prover.h" diff --git a/Libs/Rapidsnark.xcframework/ios-arm64/Headers/prover.h b/Libs/Rapidsnark.xcframework/ios-arm64/Headers/prover.h new file mode 100644 index 0000000..4257699 --- /dev/null +++ b/Libs/Rapidsnark.xcframework/ios-arm64/Headers/prover.h @@ -0,0 +1,70 @@ +#ifndef PROVER_HPP +#define PROVER_HPP + +#ifdef __cplusplus +extern "C" { +#endif + +//Error codes returned by the functions. +#define PROVER_OK 0x0 +#define PROVER_ERROR 0x1 +#define PROVER_ERROR_SHORT_BUFFER 0x2 +#define PROVER_INVALID_WITNESS_LENGTH 0x3 + +/** + * Calculates buffer size to output public signals as json string + * @returns PROVER_OK in case of success, and the size of public buffer is written to public_size + */ +int +groth16_public_size_for_zkey_buf(const void *zkey_buffer, unsigned long zkey_size, + size_t *public_size, + char *error_msg, unsigned long error_msg_maxsize); + +/** + * groth16_public_size_for_zkey_file calculates minimum buffer size for + * JSON-formatted public signals. The calculated buffer size is written + * to the public_size variable. + * + * @return error code: + * PROVER_OK (0) - in case of success + * PROVER_ERROR - in case of an error, error_msg contains the error message + */ +int +groth16_public_size_for_zkey_file(const char *zkey_fname, + unsigned long *public_size, + char *error_msg, unsigned long error_msg_maxsize); + +/** + * groth16_prover + * @return error code: + * PROVER_OK - in case of success + * PPOVER_ERROR - in case of an error + * PROVER_ERROR_SHORT_BUFFER - in case of a short buffer error, also updates proof_size and public_size with actual proof and public sizess + */ +int +groth16_prover(const void *zkey_buffer, unsigned long zkey_size, + const void *wtns_buffer, unsigned long wtns_size, + char *proof_buffer, unsigned long *proof_size, + char *public_buffer, unsigned long *public_size, + char *error_msg, unsigned long error_msg_maxsize); + +/** + * groth16_prover + * @return error code: + * PROVER_OK - in case of success + * PPOVER_ERROR - in case of an error + * PROVER_ERROR_SHORT_BUFFER - in case of a short buffer error, also updates proof_size and public_size with actual proof and public sizess + */ +int +groth16_prover_zkey_file(const char *zkey_file_path, + const void *wtns_buffer, unsigned long wtns_size, + char *proof_buffer, unsigned long *proof_size, + char *public_buffer, unsigned long *public_size, + char *error_msg, unsigned long error_msg_maxsize); + +#ifdef __cplusplus +} +#endif + + +#endif // PROVER_HPP diff --git a/Libs/Rapidsnark.xcframework/ios-arm64/Headers/verifier.h b/Libs/Rapidsnark.xcframework/ios-arm64/Headers/verifier.h new file mode 100644 index 0000000..5e684c5 --- /dev/null +++ b/Libs/Rapidsnark.xcframework/ios-arm64/Headers/verifier.h @@ -0,0 +1,34 @@ +#ifndef VERIFIER_HPP +#define VERIFIER_HPP + +#ifdef __cplusplus +extern "C" { +#endif + +//Error codes returned by the functions. +#define VERIFIER_VALID_PROOF 0x0 +#define VERIFIER_INVALID_PROOF 0x1 +#define VERIFIER_ERROR 0x2 + +/** + * 'proof', 'inputs' and 'verification_key' are null-terminated json strings. + * + * @return error code: + * VERIFIER_VALID_PROOF - in case of valid 'proof'. + * VERIFIER_INVALID_PROOF - in case of invalid 'proof'. + VERIFIER_ERROR - in case of an error + */ + +int +groth16_verify(const char *proof, + const char *inputs, + const char *verification_key, + char *error_msg, + unsigned long error_msg_maxsize); + +#ifdef __cplusplus +} +#endif + + +#endif // VERIFIER_HPP diff --git a/Libs/Rapidsnark.xcframework/ios-arm64/librapidsnarkmerged.a b/Libs/Rapidsnark.xcframework/ios-arm64/librapidsnarkmerged.a new file mode 100644 index 0000000..422428a Binary files /dev/null and b/Libs/Rapidsnark.xcframework/ios-arm64/librapidsnarkmerged.a differ diff --git a/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/Headers/RapidsnarkFramework.h b/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/Headers/RapidsnarkFramework.h new file mode 100644 index 0000000..751d7b3 --- /dev/null +++ b/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/Headers/RapidsnarkFramework.h @@ -0,0 +1,2 @@ +#import "verifier.h" +#import "prover.h" diff --git a/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/Headers/prover.h b/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/Headers/prover.h new file mode 100644 index 0000000..4257699 --- /dev/null +++ b/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/Headers/prover.h @@ -0,0 +1,70 @@ +#ifndef PROVER_HPP +#define PROVER_HPP + +#ifdef __cplusplus +extern "C" { +#endif + +//Error codes returned by the functions. +#define PROVER_OK 0x0 +#define PROVER_ERROR 0x1 +#define PROVER_ERROR_SHORT_BUFFER 0x2 +#define PROVER_INVALID_WITNESS_LENGTH 0x3 + +/** + * Calculates buffer size to output public signals as json string + * @returns PROVER_OK in case of success, and the size of public buffer is written to public_size + */ +int +groth16_public_size_for_zkey_buf(const void *zkey_buffer, unsigned long zkey_size, + size_t *public_size, + char *error_msg, unsigned long error_msg_maxsize); + +/** + * groth16_public_size_for_zkey_file calculates minimum buffer size for + * JSON-formatted public signals. The calculated buffer size is written + * to the public_size variable. + * + * @return error code: + * PROVER_OK (0) - in case of success + * PROVER_ERROR - in case of an error, error_msg contains the error message + */ +int +groth16_public_size_for_zkey_file(const char *zkey_fname, + unsigned long *public_size, + char *error_msg, unsigned long error_msg_maxsize); + +/** + * groth16_prover + * @return error code: + * PROVER_OK - in case of success + * PPOVER_ERROR - in case of an error + * PROVER_ERROR_SHORT_BUFFER - in case of a short buffer error, also updates proof_size and public_size with actual proof and public sizess + */ +int +groth16_prover(const void *zkey_buffer, unsigned long zkey_size, + const void *wtns_buffer, unsigned long wtns_size, + char *proof_buffer, unsigned long *proof_size, + char *public_buffer, unsigned long *public_size, + char *error_msg, unsigned long error_msg_maxsize); + +/** + * groth16_prover + * @return error code: + * PROVER_OK - in case of success + * PPOVER_ERROR - in case of an error + * PROVER_ERROR_SHORT_BUFFER - in case of a short buffer error, also updates proof_size and public_size with actual proof and public sizess + */ +int +groth16_prover_zkey_file(const char *zkey_file_path, + const void *wtns_buffer, unsigned long wtns_size, + char *proof_buffer, unsigned long *proof_size, + char *public_buffer, unsigned long *public_size, + char *error_msg, unsigned long error_msg_maxsize); + +#ifdef __cplusplus +} +#endif + + +#endif // PROVER_HPP diff --git a/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/Headers/verifier.h b/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/Headers/verifier.h new file mode 100644 index 0000000..5e684c5 --- /dev/null +++ b/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/Headers/verifier.h @@ -0,0 +1,34 @@ +#ifndef VERIFIER_HPP +#define VERIFIER_HPP + +#ifdef __cplusplus +extern "C" { +#endif + +//Error codes returned by the functions. +#define VERIFIER_VALID_PROOF 0x0 +#define VERIFIER_INVALID_PROOF 0x1 +#define VERIFIER_ERROR 0x2 + +/** + * 'proof', 'inputs' and 'verification_key' are null-terminated json strings. + * + * @return error code: + * VERIFIER_VALID_PROOF - in case of valid 'proof'. + * VERIFIER_INVALID_PROOF - in case of invalid 'proof'. + VERIFIER_ERROR - in case of an error + */ + +int +groth16_verify(const char *proof, + const char *inputs, + const char *verification_key, + char *error_msg, + unsigned long error_msg_maxsize); + +#ifdef __cplusplus +} +#endif + + +#endif // VERIFIER_HPP diff --git a/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/librapidsnarkmerged.a b/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/librapidsnarkmerged.a new file mode 100644 index 0000000..210cc67 Binary files /dev/null and b/Libs/Rapidsnark.xcframework/ios-arm64_arm64e_x86_64-simulator/librapidsnarkmerged.a differ diff --git a/Package.swift b/Package.swift index e00ce88..a18d14d 100644 --- a/Package.swift +++ b/Package.swift @@ -4,20 +4,34 @@ import PackageDescription let package = Package( - name: "rapidsnark-ios", + name: "rapidsnark", + platforms: [ + .iOS(.v12) + ], products: [ // Products define the executables and libraries a package produces, making them visible to other packages. .library( - name: "rapidsnark-ios", - targets: ["rapidsnark-ios"]), + name: "rapidsnark", + targets: ["rapidsnark"]), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. // Targets can depend on other targets in this package and products from dependencies. .target( - name: "rapidsnark-ios"), + name: "rapidsnark", + dependencies: ["C"], + path: "Sources/rapidsnark", + sources: ["rapidsnark.swift"] + ), + .target( + name: "C", + dependencies: ["Rapidsnark"], + path: "Sources/C"), + .binaryTarget( + name: "Rapidsnark", + path: "Libs/Rapidsnark.xcframework"), .testTarget( - name: "rapidsnark-iosTests", - dependencies: ["rapidsnark-ios"]), + name: "rapidsnarkTests", + dependencies: ["rapidsnark"]) ] ) diff --git a/Sources/C/include/C-Bridging-Header.h b/Sources/C/include/C-Bridging-Header.h new file mode 100644 index 0000000..2056bee --- /dev/null +++ b/Sources/C/include/C-Bridging-Header.h @@ -0,0 +1,13 @@ +// +// C-Bridging-Header.h +// +// +// Created by Yaroslav Moria on 04.04.2024. +// + +#ifndef Header_h +#define Header_h + +#endif /* Header_h */ + +#import "rapidsnark_bridge.h" diff --git a/Sources/C/include/rapidsnark_bridge.h b/Sources/C/include/rapidsnark_bridge.h new file mode 100644 index 0000000..178b913 --- /dev/null +++ b/Sources/C/include/rapidsnark_bridge.h @@ -0,0 +1,14 @@ +// +// rapidsnark_bridge.h +// +// +// Created by Yaroslav Moria on 04.04.2024. +// + +#ifndef rapidsnark_bridge_h +#define rapidsnark_bridge_h + +#endif /* rapidsnark_bridge_h */ + +#include +#import "RapidsnarkFramework.h" diff --git a/Sources/C/rapidsnark_bridge.c b/Sources/C/rapidsnark_bridge.c new file mode 100644 index 0000000..9850a61 --- /dev/null +++ b/Sources/C/rapidsnark_bridge.c @@ -0,0 +1,12 @@ +// +// rapidsnark_bridge.c +// +// +// Created by Yaroslav Moria on 04.04.2024. +// + +#include "rapidsnark_bridge.h" + +void __dummy() { + +} diff --git a/Sources/rapidsnark-ios/rapidsnark_ios.swift b/Sources/rapidsnark-ios/rapidsnark_ios.swift deleted file mode 100644 index 08b22b8..0000000 --- a/Sources/rapidsnark-ios/rapidsnark_ios.swift +++ /dev/null @@ -1,2 +0,0 @@ -// The Swift Programming Language -// https://docs.swift.org/swift-book diff --git a/Sources/rapidsnark/rapidsnark.swift b/Sources/rapidsnark/rapidsnark.swift new file mode 100644 index 0000000..1167288 --- /dev/null +++ b/Sources/rapidsnark/rapidsnark.swift @@ -0,0 +1,227 @@ +import C +import Foundation.NSString + +let DEFAULT_PROOF_BUFFER_SIZE = 1024; +let DEFAULT_ERROR_BUFFER_SIZE = 256; + +let empty: NSString = ""; + +func groth16Prove( + zkey: String, + witness: String, + proofBufferSize: Int = DEFAULT_PROOF_BUFFER_SIZE, + publicBufferSize: Int?, + errorBufferSize: Int = DEFAULT_ERROR_BUFFER_SIZE +) throws -> (proof: String, pub_signals: String) { + let zkeyBuf = zkey.toBuffer() + let witnessBuf = witness.toBuffer() + + var public_buffer_size : Int; + if let publicBufferSize { + public_buffer_size = publicBufferSize; + } else { + public_buffer_size = try! groth16PublicSizeForZkeyBuf(zkey: zkey, errorBufferSize: errorBufferSize); + } + + var proof_buffer_size = UInt(proofBufferSize); + var proofBuffer = Array(repeating: 0, count: proofBufferSize); + + var public_buffer_size_uint = UInt(public_buffer_size) + var publicBuffer = Array(repeating: 0, count: public_buffer_size) + + let error_buffer_size = UInt(errorBufferSize) + var errorMessageBuffer: [CChar] = Array(repeating: 0, count: errorBufferSize) + + let statusCode = groth16_prover( + zkeyBuf, UInt(zkey.count), + witnessBuf, UInt(witness.count), + &proofBuffer, &proof_buffer_size, + &publicBuffer, &public_buffer_size_uint, + &errorMessageBuffer, error_buffer_size + ); + + if (statusCode == PROVER_OK) { + let proof = String(cString: proofBuffer) + let publicSignals = String(cString: publicBuffer) + + return (proof, publicSignals) + } + + let error = String(cString: errorMessageBuffer) + + if (statusCode == PROVER_ERROR) { + throw RapidsnarkProverError.error(message: error); + } else if (statusCode == PROVER_ERROR_SHORT_BUFFER) { + throw RapidsnarkProverError.shortBuffer(message: error); + } else if (statusCode == PROVER_INVALID_WITNESS_LENGTH) { + throw RapidsnarkProverError.invalidWitnessLength(message: error); + } + + throw RapidsnarkUnknownStatusError() +} + +func groth16ProveWithZKeyFilePath( + zkeyPath: String, + witness: String, + proofBufferSize: Int = DEFAULT_PROOF_BUFFER_SIZE, + publicBufferSize: Int?, + errorBufferSize: Int = DEFAULT_ERROR_BUFFER_SIZE +) throws -> (proof: String, pub_signals: String) { + let zkeyPathBuf = zkeyPath.toBuffer() + let witnessBuf = witness.toBuffer() + + var public_buffer_size : Int; + if let publicBufferSize { + public_buffer_size = publicBufferSize; + } else { + public_buffer_size = try! groth16PublicSizeForZkeyFile(zkeyPath: zkeyPath, errorBufferSize: errorBufferSize); + } + + var proof_buffer_size = UInt(proofBufferSize); + var proofBuffer = Array(repeating: 0, count: proofBufferSize); + + var public_buffer_size_uint = UInt(public_buffer_size) + var publicBuffer = Array(repeating: 0, count: public_buffer_size) + + let error_buffer_size = UInt(errorBufferSize) + var errorMessageBuffer: [CChar] = Array(repeating: 0, count: errorBufferSize) + + let statusCode = groth16_prover_zkey_file( + zkeyPathBuf, + witnessBuf, UInt(witness.count), + &proofBuffer, &proof_buffer_size, + &publicBuffer, &public_buffer_size_uint, + &errorMessageBuffer, error_buffer_size + ); + + if (statusCode == PROVER_OK) { + let proof = String(cString: proofBuffer) + let publicSignals = String(cString: publicBuffer) + + return (proof, publicSignals) + } + + let error = String(cString: errorMessageBuffer) + + if (statusCode == PROVER_ERROR) { + throw RapidsnarkProverError.error(message: error); + } else if (statusCode == PROVER_ERROR_SHORT_BUFFER) { + throw RapidsnarkProverError.shortBuffer(message: error); + } else if (statusCode == PROVER_INVALID_WITNESS_LENGTH) { + throw RapidsnarkProverError.invalidWitnessLength(message: error); + } + + throw RapidsnarkUnknownStatusError() +} + +func groth16Verify( + proof: String, + inputs: String, + verificationKey: String, + errorBufferSize: Int = DEFAULT_ERROR_BUFFER_SIZE +) throws -> Bool { + let proofBuf = proof.toBuffer() + let inputsBuf = inputs.toBuffer() + let verificationKeyBuf = verificationKey.toBuffer() + + var errorMessageBuffer: [CChar] = Array(repeating: 0, count: errorBufferSize) + + let result = groth16_verify( + proofBuf, + inputsBuf, + verificationKeyBuf, + &errorMessageBuffer, + UInt(errorBufferSize) + ); + + if (result == VERIFIER_VALID_PROOF) { + return true; + } + + let error = String(cString: errorMessageBuffer) + + if (result == VERIFIER_INVALID_PROOF) { + throw RapidsnarkVerifierError.invalidProof(message: error) + } else if (result == VERIFIER_ERROR) { + throw RapidsnarkVerifierError.error(message: error) + } + + throw RapidsnarkUnknownStatusError() +} + +func groth16PublicSizeForZkeyBuf( + zkey: String, + errorBufferSize: Int = DEFAULT_ERROR_BUFFER_SIZE +) throws -> Int { + let zkeyBuffer = zkey.toBuffer() + + var errorMessageBuffer: [CChar] = Array(repeating: 0, count: errorBufferSize) + + var publicSize = 0 + + let statusCode = groth16_public_size_for_zkey_buf( + zkeyBuffer, + UInt(zkey.count), + &publicSize, + &errorMessageBuffer, + UInt(errorBufferSize) + ); + + if (statusCode == PROVER_OK) { + return publicSize + } else { + let error = String(cString: errorMessageBuffer) + throw RapidsnarkProverError.error(message: error) + } +} + +func groth16PublicSizeForZkeyFile( + zkeyPath: String, + errorBufferSize: Int = DEFAULT_ERROR_BUFFER_SIZE +) throws -> Int { + let zkeyPathBuffer = zkeyPath.toBuffer() + + var errorMessageBuffer: [CChar] = Array(repeating: 0, count: errorBufferSize) + + var publicSize = 0 + + let statusCode = groth16_public_size_for_zkey_file( + zkeyPathBuffer, + &publicSize, + &errorMessageBuffer, + UInt(errorBufferSize) + ); + + if (statusCode == PROVER_OK) { + return publicSize + } else { + let error = String(cString: errorMessageBuffer) + throw RapidsnarkProverError.error(message: error) + } +} + + +extension String { + func toBuffer() -> [CChar] { + var buffer: [CChar] = Array(repeating: 0, count: count) + strcpy(&buffer, self) + return buffer + } +} + +public protocol RapidsnarkError : Error { +} + +enum RapidsnarkProverError : RapidsnarkError { + case error(message: String) + case shortBuffer(message: String) + case invalidWitnessLength(message: String) +} + +enum RapidsnarkVerifierError : RapidsnarkError { + case error(message: String) + case invalidProof(message: String) +} + +class RapidsnarkUnknownStatusError : RapidsnarkError { +} diff --git a/Tests/rapidsnark-iosTests/rapidsnark_iosTests.swift b/Tests/rapidsnarkTests/rapidsnarkTests.swift similarity index 78% rename from Tests/rapidsnark-iosTests/rapidsnark_iosTests.swift rename to Tests/rapidsnarkTests/rapidsnarkTests.swift index 092c8bf..644d809 100644 --- a/Tests/rapidsnark-iosTests/rapidsnark_iosTests.swift +++ b/Tests/rapidsnarkTests/rapidsnarkTests.swift @@ -1,7 +1,7 @@ import XCTest -@testable import rapidsnark_ios +@testable import rapidsnark -final class rapidsnark_iosTests: XCTestCase { +final class rapidsnarkTests: XCTestCase { func testExample() throws { // XCTest Documentation // https://developer.apple.com/documentation/xctest