Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.0.1-beta.5 (2025-10-13)

Added SPM support for iOS.
Made plugin run proof generation on a concurrent background queue.

## 0.0.1-beta.4 (2025-06-09)

Proof generation now works in background task queue.
Expand Down
4 changes: 2 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ group 'com.rapidsnark.flutter_rapidsnark'
version '1.0-SNAPSHOT'

buildscript {
ext.kotlin_version = '1.9.0'
ext.kotlin_version = '2.1.0'
repositories {
google()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:7.3.0'
classpath 'com.android.tools.build:gradle:8.9.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand Down
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,26 @@ import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.StandardMethodCodec
import io.iden3.rapidsnark.*
import java.util.concurrent.Executors
import android.os.Handler
import android.os.Looper

/** FlutterRapidsnarkPlugin */
class FlutterRapidsnarkPlugin : FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel: MethodChannel

// Executor to allow multiple proving / verifying operations to run concurrently
private val executor = Executors.newCachedThreadPool()
private val mainHandler = Handler(Looper.getMainLooper())

override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
val taskQueue = flutterPluginBinding.binaryMessenger.makeBackgroundTaskQueue()
channel = MethodChannel(flutterPluginBinding.binaryMessenger,
channel = MethodChannel(
flutterPluginBinding.binaryMessenger,
"com.rapidsnark.flutter_rapidsnark",
StandardMethodCodec.INSTANCE,
taskQueue)
taskQueue
)
channel.setMethodCallHandler(this)
}

Expand All @@ -36,6 +41,16 @@ class FlutterRapidsnarkPlugin : FlutterPlugin, MethodCallHandler {

override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
executor.shutdown()
}

// Helper to finish results safely on main thread
private fun complete(result: Result, block: () -> Unit) {
if (Looper.myLooper() == Looper.getMainLooper()) {
block()
} else {
mainHandler.post { block() }
}
}

private fun callGroth16Prove(call: MethodCall, result: Result) {
Expand All @@ -49,23 +64,33 @@ class FlutterRapidsnarkPlugin : FlutterPlugin, MethodCallHandler {
val publicBufferSize = arguments["publicBufferSize"] as Int?
val errorBufferSize = arguments["errorBufferSize"] as Int

// Call the heavy computation function
val proof = groth16Prove(
zkeyPath,
witnessBytes,
proofBufferSize,
publicBufferSize,
errorBufferSize,
)

result.success(
mapOf(
"proof" to proof.proof,
"publicSignals" to proof.publicSignals
)
)
// Dispatch heavy native call asynchronously to allow concurrency
executor.execute {
try {
val proof = groth16Prove(
zkeyPath,
witnessBytes,
proofBufferSize,
publicBufferSize,
errorBufferSize,
)
complete(result) {
result.success(
mapOf(
"proof" to proof.proof,
"publicSignals" to proof.publicSignals
)
)
}
} catch (e: RapidsnarkProverError) {
complete(result) { result.error("groth16Prove", e.message, null) }
} catch (e: Exception) {
complete(result) { result.error("groth16Prove", e.message, null) }
}
}
} catch (e: Exception) {
result.error("groth16ProveWithZKeyFilePath", e.message, null)
result.error("groth16Prove", "Failed to prove: ${e.message}", null)
return
}
}

Expand All @@ -74,17 +99,28 @@ class FlutterRapidsnarkPlugin : FlutterPlugin, MethodCallHandler {
val arguments: Map<String, Any> = call.arguments<Map<String, Any>>()!!

val zkeyPath = arguments["zkeyPath"] as String

val errorBufferSize = arguments["errorBufferSize"] as Int

val publicSize = groth16PublicBufferSize(
zkeyPath,
errorBufferSize,
)

result.success(publicSize)
executor.execute {
try {
val publicSize = groth16PublicBufferSize(
zkeyPath,
errorBufferSize,
)
complete(result) { result.success(publicSize) }
} catch (e: RapidsnarkProverError) {
complete(result) { result.error("groth16PublicBufferSize", e.message, null) }
} catch (e: Exception) {
complete(result) { result.error("groth16PublicBufferSize", e.message, null) }
}
}
} catch (e: Exception) {
result.error("groth16PublicSizeForZkeyFile", e.message, null)
result.error(
"groth16PublicBufferSize",
"Failed to calculate public buffer size: ${e.message}",
null
)
return
}
}

Expand All @@ -98,16 +134,24 @@ class FlutterRapidsnarkPlugin : FlutterPlugin, MethodCallHandler {

val errorBufferSize = arguments["errorBufferSize"] as Int

val isValid = groth16Verify(
proof,
inputs,
verificationKey,
errorBufferSize,
)

result.success(isValid)
executor.execute {
try {
val isValid = groth16Verify(
proof,
inputs,
verificationKey,
errorBufferSize,
)
complete(result) { result.success(isValid) }
} catch (e: RapidsnarkVerifierError) {
complete(result) { result.error("groth16Verify", e.message, null) }
} catch (e: Exception) {
complete(result) { result.error("groth16Verify", e.message, null) }
}
}
} catch (e: Exception) {
result.error("groth16Verify", e.message, null)
result.error("groth16Verify", "Invalid arguments type: ${e.message}", null)
return
}
}
}
2 changes: 1 addition & 1 deletion example/android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
4 changes: 2 additions & 2 deletions example/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ pluginManagement {

plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.2.1" apply false
id "org.jetbrains.kotlin.android" version "1.9.0" apply false
id "com.android.application" version "8.9.0" apply false
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
}

include ":app"
2 changes: 1 addition & 1 deletion example/ios/Flutter/AppFrameworkInfo.plist
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
<string>13.0</string>
</dict>
</plist>
2 changes: 1 addition & 1 deletion example/ios/Podfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
platform :ios, '12.0'
platform :ios, '13.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
Expand Down
6 changes: 3 additions & 3 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,15 @@ SPEC CHECKSUMS:
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_rapidsnark: 842c3ddde387254b6f8a36e1a0f403560ee169ca
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_rapidsnark: 943da7b717fd3435ce80d3422c64c12a0dd18be4
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
rapidsnark: da1c1d74a36ba8376700286d45707574d9d1afcb
SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4

PODFILE CHECKSUM: 095d9af8b13ecba9b7619a234542d1b32779cac5
PODFILE CHECKSUM: 92906b04914919e75004799b609448ddd7c0a72e

COCOAPODS: 1.16.2
Loading