-
Notifications
You must be signed in to change notification settings - Fork 29
feat(ffi): add provekit-ffi #198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Bisht13
wants to merge
9
commits into
main
Choose a base branch
from
feat/provekit-ffi
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
021ceab
feat: add verifier server
Bisht13 1b32cbc
feat(ffi): add provekit-ffi
Bisht13 bdbe701
chore: update README
Bisht13 8ef2a97
docs(ffi): fix doc comment formatting
Bisht13 c3e590f
revert: undo unrelated docker-compose formatting change
Bisht13 b5da517
fix: restore debug symbols and bench harness settings
Bisht13 b499388
fix: update CI toolchain and resolve clippy warnings
Bisht13 35ccf13
perf(ffi): add panic catching for FFI safety
Bisht13 934c00e
feat(ffi): add custom allocator support via pk_set_allocator
Bisht13 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| [package] | ||
| name = "provekit-ffi" | ||
| version = "0.1.0" | ||
| edition.workspace = true | ||
| rust-version.workspace = true | ||
| authors.workspace = true | ||
| license.workspace = true | ||
| homepage.workspace = true | ||
| repository.workspace = true | ||
|
|
||
| [lib] | ||
| crate-type = ["staticlib"] | ||
|
|
||
| [dependencies] | ||
| # Workspace crates | ||
| provekit-common.workspace = true | ||
| provekit-prover.workspace = true | ||
|
|
||
| # Noir language | ||
| acir.workspace = true | ||
| noirc_abi.workspace = true | ||
|
|
||
| # 3rd party | ||
| anyhow.workspace = true | ||
| serde.workspace = true | ||
| serde_json.workspace = true | ||
| postcard.workspace = true | ||
| tracing.workspace = true | ||
|
|
||
| [lints] | ||
| workspace = true | ||
|
|
||
| [features] | ||
| default = [] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,318 @@ | ||
| # ProveKit FFI | ||
|
|
||
| This crate provides C-compatible FFI bindings for ProveKit, enabling integration with multiple programming languages and platforms including mobile (iOS, Android), desktop, web, and embedded systems. | ||
|
|
||
| ## Features | ||
|
|
||
| - **C ABI Compatibility**: All functions use C-compatible types and calling conventions | ||
| - **Memory Management**: Safe buffer management with explicit allocation/deallocation | ||
| - **Multiple Output Formats**: Support for binary, JSON, and file outputs | ||
| - **Error Handling**: Comprehensive error codes and messages | ||
| - **Cross-Platform**: Can be compiled as a static library for mobile, desktop, and embedded platforms | ||
|
|
||
| ## Building | ||
|
|
||
| ### For Development (Host Platform) | ||
| ```bash | ||
| cargo build --release -p provekit-ffi | ||
| ``` | ||
|
|
||
| ### For Mobile Platforms | ||
|
|
||
| #### iOS | ||
| ```bash | ||
| # Install iOS targets | ||
| rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios | ||
|
|
||
| # Build for device (ARM64) | ||
| cargo build --release --target aarch64-apple-ios -p provekit-ffi | ||
|
|
||
| # Build for simulator (ARM64) | ||
| cargo build --release --target aarch64-apple-ios-sim -p provekit-ffi | ||
|
|
||
| # Build for simulator (x86_64, Intel Macs) | ||
| cargo build --release --target x86_64-apple-ios -p provekit-ffi | ||
| ``` | ||
|
|
||
| #### Android | ||
| ```bash | ||
| # Install Android targets | ||
| rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android | ||
|
|
||
| # Build for ARM64 | ||
| cargo build --release --target aarch64-linux-android -p provekit-ffi | ||
|
|
||
| # Build for ARM32 | ||
| cargo build --release --target armv7-linux-androideabi -p provekit-ffi | ||
|
|
||
| # Build for x86_64 | ||
| cargo build --release --target x86_64-linux-android -p provekit-ffi | ||
| ``` | ||
|
|
||
| ### Create Platform-Specific Packages | ||
|
|
||
| #### iOS XCFramework | ||
| ```bash | ||
| xcodebuild -create-xcframework \ | ||
| -library target/aarch64-apple-ios/release/libprovekit_ffi.a -headers tooling/provekit-ffi/include \ | ||
| -library target/aarch64-apple-ios-sim/release/libprovekit_ffi.a -headers tooling/provekit-ffi/include \ | ||
| -library target/x86_64-apple-ios/release/libprovekit_ffi.a -headers tooling/provekit-ffi/include \ | ||
| -output ProvekitFFI.xcframework | ||
| ``` | ||
|
|
||
| #### Android AAR (requires additional setup) | ||
| ```bash | ||
| # Copy libraries to Android project structure | ||
| mkdir -p android/src/main/jniLibs/{arm64-v8a,armeabi-v7a,x86_64} | ||
| cp target/aarch64-linux-android/release/libprovekit_ffi.a android/src/main/jniLibs/arm64-v8a/ | ||
| cp target/armv7-linux-androideabi/release/libprovekit_ffi.a android/src/main/jniLibs/armeabi-v7a/ | ||
| cp target/x86_64-linux-android/release/libprovekit_ffi.a android/src/main/jniLibs/x86_64/ | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| ### C/C++ | ||
| ```c | ||
| #include "provekit_ffi.h" | ||
|
|
||
| int main() { | ||
| // Initialize the library | ||
| if (pk_init() != PK_SUCCESS) { | ||
| return 1; | ||
| } | ||
|
|
||
| // Option 1: Prove and write to file | ||
| int result = pk_prove_to_file( | ||
| "/path/to/scheme.pkp", | ||
| "/path/to/input.toml", | ||
| "/path/to/output.np" | ||
| ); | ||
|
|
||
| if (result == PK_SUCCESS) { | ||
| printf("Proof written to file successfully\n"); | ||
| } | ||
|
|
||
| // Option 2: Prove and get JSON in memory | ||
| PKBuf proof_buf; | ||
| result = pk_prove_to_json( | ||
| "/path/to/scheme.pkp", | ||
| "/path/to/input.toml", | ||
| &proof_buf | ||
| ); | ||
|
|
||
| if (result == PK_SUCCESS) { | ||
| // Use proof_buf.ptr and proof_buf.len as JSON string | ||
| printf("JSON proof generated: %zu bytes\n", proof_buf.len); | ||
| printf("Proof JSON: %.*s\n", (int)proof_buf.len, proof_buf.ptr); | ||
|
|
||
| // Free the buffer | ||
| pk_free_buf(proof_buf); | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
| ``` | ||
|
|
||
| ### Swift | ||
| ```swift | ||
| import Foundation | ||
| import ProvekitFFI | ||
|
|
||
| // Initialize ProveKit | ||
| guard pk_init() == PK_SUCCESS else { | ||
| fatalError("Failed to initialize ProveKit") | ||
| } | ||
|
|
||
| // Option 1: Prove and write to file | ||
| let fileResult = pk_prove_to_file( | ||
| proverPath, | ||
| inputPath, | ||
| outputPath | ||
| ) | ||
|
|
||
| guard fileResult == PK_SUCCESS else { | ||
| fatalError("File proving failed with error: \(fileResult)") | ||
| } | ||
|
|
||
| // Option 2: Prove and get JSON in memory | ||
| var proofBuf = PKBuf(ptr: nil, len: 0) | ||
| let jsonResult = pk_prove_to_json( | ||
| proverPath, | ||
| inputPath, | ||
| &proofBuf | ||
| ) | ||
|
|
||
| guard jsonResult == PK_SUCCESS else { | ||
| fatalError("JSON proving failed with error: \(jsonResult)") | ||
| } | ||
|
|
||
| // Convert to Swift String (JSON) | ||
| let jsonString = String( | ||
| bytesNoCopy: proofBuf.ptr, | ||
| length: proofBuf.len, | ||
| encoding: .utf8, | ||
| freeWhenDone: false | ||
| ) | ||
|
|
||
| print("Proof JSON: \(jsonString ?? "Invalid UTF-8")") | ||
|
|
||
| // Free the buffer | ||
| pk_free_buf(proofBuf) | ||
| ``` | ||
|
|
||
| ### Kotlin (Android) | ||
| ```kotlin | ||
| // Load the native library | ||
| System.loadLibrary("provekit_ffi") | ||
|
|
||
| // Initialize ProveKit | ||
| if (pk_init() != PK_SUCCESS) { | ||
| throw RuntimeException("Failed to initialize ProveKit") | ||
| } | ||
|
|
||
| // Option 1: Prove and write to file | ||
| val fileResult = pk_prove_to_file( | ||
| proverPath, | ||
| inputPath, | ||
| outputPath | ||
| ) | ||
|
|
||
| if (fileResult != PK_SUCCESS) { | ||
| throw RuntimeException("File proving failed with error: $fileResult") | ||
| } | ||
|
|
||
| // Option 2: Prove and get JSON in memory | ||
| val proofBuf = PKBuf() | ||
| val jsonResult = pk_prove_to_json( | ||
| proverPath, | ||
| inputPath, | ||
| proofBuf | ||
| ) | ||
|
|
||
| if (jsonResult != PK_SUCCESS) { | ||
| throw RuntimeException("JSON proving failed with error: $jsonResult") | ||
| } | ||
|
|
||
| // Convert to String (JSON) | ||
| val jsonBytes = ByteArray(proofBuf.len.toInt()) | ||
| // Copy memory from native buffer to Java byte array | ||
| // (implementation depends on JNI wrapper) | ||
| val jsonString = String(jsonBytes, Charsets.UTF_8) | ||
| println("Proof JSON: $jsonString") | ||
|
|
||
| // Free the buffer | ||
| pk_free_buf(proofBuf) | ||
| ``` | ||
|
|
||
| ### Python (via ctypes) | ||
| ```python | ||
| import ctypes | ||
| from ctypes import Structure, c_char_p, c_int, c_size_t, POINTER | ||
|
|
||
| # Load the library | ||
| lib = ctypes.CDLL('./libprovekit_ffi.so') # or .dylib on macOS, .dll on Windows | ||
|
|
||
| # Define structures | ||
| class PKBuf(Structure): | ||
| _fields_ = [("ptr", POINTER(ctypes.c_uint8)), ("len", c_size_t)] | ||
|
|
||
| # Define function signatures | ||
| lib.pk_init.restype = c_int | ||
| lib.pk_prove_to_file.argtypes = [c_char_p, c_char_p, c_char_p] | ||
| lib.pk_prove_to_file.restype = c_int | ||
| lib.pk_prove_to_json.argtypes = [c_char_p, c_char_p, POINTER(PKBuf)] | ||
| lib.pk_prove_to_json.restype = c_int | ||
| lib.pk_free_buf.argtypes = [PKBuf] | ||
|
|
||
| # Initialize ProveKit | ||
| if lib.pk_init() != 0: # PK_SUCCESS = 0 | ||
| raise RuntimeError("Failed to initialize ProveKit") | ||
|
|
||
| # Option 1: Prove and write to file | ||
| file_result = lib.pk_prove_to_file( | ||
| prover_path.encode('utf-8'), | ||
| input_path.encode('utf-8'), | ||
| output_path.encode('utf-8') | ||
| ) | ||
|
|
||
| if file_result != 0: | ||
| raise RuntimeError(f"File proving failed with error: {file_result}") | ||
|
|
||
| # Option 2: Prove and get JSON in memory | ||
| proof_buf = PKBuf() | ||
| json_result = lib.pk_prove_to_json( | ||
| prover_path.encode('utf-8'), | ||
| input_path.encode('utf-8'), | ||
| ctypes.byref(proof_buf) | ||
| ) | ||
|
|
||
| if json_result != 0: | ||
| raise RuntimeError(f"JSON proving failed with error: {json_result}") | ||
|
|
||
| # Convert to string (JSON) | ||
| json_bytes = ctypes.string_at(proof_buf.ptr, proof_buf.len) | ||
| json_string = json_bytes.decode('utf-8') | ||
| print(f"Proof JSON: {json_string}") | ||
|
|
||
| # Free the buffer | ||
| lib.pk_free_buf(proof_buf) | ||
| ``` | ||
|
|
||
| ## API Reference | ||
|
|
||
| ### Functions | ||
|
|
||
| - `pk_init()` - Initialize the library (call once) | ||
| - `pk_prove_to_file()` - Generate proof and write to file | ||
| - `pk_prove_to_json()` - Generate proof and return as JSON string in memory buffer | ||
| - `pk_free_buf()` - Free buffers returned by ProveKit functions | ||
| - `pk_set_allocator()` - Set custom allocator functions for memory management (optional) | ||
|
|
||
| ### Error Codes | ||
|
|
||
| - `PK_SUCCESS` (0) - Operation successful | ||
| - `PK_INVALID_INPUT` (1) - Invalid input parameters | ||
| - `PK_SCHEME_READ_ERROR` (2) - Failed to read scheme file | ||
| - `PK_WITNESS_READ_ERROR` (3) - Failed to read witness/input file | ||
| - `PK_PROOF_ERROR` (4) - Failed to generate proof | ||
| - `PK_SERIALIZATION_ERROR` (5) - Failed to serialize output | ||
| - `PK_UTF8_ERROR` (6) - UTF-8 conversion error | ||
| - `PK_FILE_WRITE_ERROR` (7) - File write error | ||
|
|
||
| ## File Formats | ||
|
|
||
| ### Input Files | ||
| - **Prover files**: `.pkp` (binary) or `.json` (JSON format) - prepared proof scheme | ||
| - **Witness files**: `.toml` (TOML format with input values) | ||
|
|
||
| ### Output Files | ||
| - **Proof files**: `.np` (binary) or `.json` (JSON format) | ||
|
|
||
| ## Memory Management | ||
|
|
||
| All buffers returned by ProveKit functions must be freed using `pk_free_buf()`. Failure to do so will result in memory leaks. | ||
|
|
||
| ### Custom Allocator | ||
|
|
||
| By default, ProveKit uses the system allocator. To use a custom allocator (e.g., for iOS memory tracking), call `pk_set_allocator()` before any other ProveKit functions: | ||
|
|
||
| ```c | ||
| void* my_alloc(size_t size, size_t align) { | ||
| // Custom allocation logic | ||
| } | ||
|
|
||
| void my_dealloc(void* ptr, size_t size, size_t align) { | ||
| // Custom deallocation logic | ||
| } | ||
|
|
||
| // Set custom allocator (call once, before pk_init) | ||
| pk_set_allocator(my_alloc, my_dealloc); | ||
| ``` | ||
|
|
||
| If `pk_set_allocator()` is not called, the system allocator is used. | ||
|
|
||
| ## Thread Safety | ||
|
|
||
| The FFI functions are not guaranteed to be thread-safe. If you need to call ProveKit functions from multiple threads, ensure proper synchronization. | ||
|
|
||
|
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused dependency