From b902587f395431263926bcd0348afa56305feb96 Mon Sep 17 00:00:00 2001 From: Artem <48178500+ElusAegis@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:32:24 +0100 Subject: [PATCH] (feat: android) Added a sample of using Halo2 in Android, as well as improved the UI to visually switch between Circom and Halo2 --- .../app/src/main/assets/fibonacci_pk.bin | 1 + .../app/src/main/assets/fibonacci_srs.bin | 1 + .../app/src/main/assets/fibonacci_vk.bin | 1 + .../com/mopro/mopro_app/FibonacciComponent.kt | 76 +++++++++++++++++++ .../java/com/mopro/mopro_app/MainActivity.kt | 73 +++++++++++------- .../mopro/mopro_app/MultiplierComponent.kt | 20 ++--- 6 files changed, 131 insertions(+), 41 deletions(-) create mode 120000 test-e2e/android/app/src/main/assets/fibonacci_pk.bin create mode 120000 test-e2e/android/app/src/main/assets/fibonacci_srs.bin create mode 120000 test-e2e/android/app/src/main/assets/fibonacci_vk.bin create mode 100644 test-e2e/android/app/src/main/java/com/mopro/mopro_app/FibonacciComponent.kt diff --git a/test-e2e/android/app/src/main/assets/fibonacci_pk.bin b/test-e2e/android/app/src/main/assets/fibonacci_pk.bin new file mode 120000 index 00000000..9544aea4 --- /dev/null +++ b/test-e2e/android/app/src/main/assets/fibonacci_pk.bin @@ -0,0 +1 @@ +../../../../../../test-vectors/halo2/fibonacci_pk.bin \ No newline at end of file diff --git a/test-e2e/android/app/src/main/assets/fibonacci_srs.bin b/test-e2e/android/app/src/main/assets/fibonacci_srs.bin new file mode 120000 index 00000000..3195e6ec --- /dev/null +++ b/test-e2e/android/app/src/main/assets/fibonacci_srs.bin @@ -0,0 +1 @@ +../../../../../../test-vectors/halo2/fibonacci_srs.bin \ No newline at end of file diff --git a/test-e2e/android/app/src/main/assets/fibonacci_vk.bin b/test-e2e/android/app/src/main/assets/fibonacci_vk.bin new file mode 120000 index 00000000..2b51e9e8 --- /dev/null +++ b/test-e2e/android/app/src/main/assets/fibonacci_vk.bin @@ -0,0 +1 @@ +../../../../../../test-vectors/halo2/fibonacci_vk.bin \ No newline at end of file diff --git a/test-e2e/android/app/src/main/java/com/mopro/mopro_app/FibonacciComponent.kt b/test-e2e/android/app/src/main/java/com/mopro/mopro_app/FibonacciComponent.kt new file mode 100644 index 00000000..87f239e3 --- /dev/null +++ b/test-e2e/android/app/src/main/java/com/mopro/mopro_app/FibonacciComponent.kt @@ -0,0 +1,76 @@ +package com.mopro.mopro_app + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import uniffi.mopro.GenerateProofResult +import uniffi.mopro.generateHalo2Proof +import uniffi.mopro.verifyHalo2Proof + +@Composable +fun FibonacciComponent() { + var provingTime by remember { mutableStateOf("proving time:") } + var verifyingTime by remember { mutableStateOf("verifying time: ") } + var valid by remember { mutableStateOf("valid:") } + var res by remember { + mutableStateOf( + GenerateProofResult(proof = ByteArray(size = 0), inputs = ByteArray(size = 0)) + ) + } + + val srsPath = getFilePathFromAssets("fibonacci_srs.bin") + val provingKeyPath = getFilePathFromAssets("fibonacci_pk.bin") + val verifyingKeyPath = getFilePathFromAssets("fibonacci_vk.bin") + + + val inputs = mutableMapOf>() + inputs["out"] = listOf("55") + + Box(modifier = Modifier.fillMaxSize().padding(16.dp), contentAlignment = Alignment.Center) { + Button( + onClick = { + Thread { + val startTime = System.currentTimeMillis() + res = generateHalo2Proof(srsPath, provingKeyPath, inputs) + val endTime = System.currentTimeMillis() + provingTime = + "proving time: " + + (endTime - startTime).toString() + + " ms" + } + .start() + }, + modifier = Modifier.padding(top = 20.dp) + ) { Text(text = "generate proof") } + Button( + onClick = { + val startTime = System.currentTimeMillis() + valid = "valid: " + verifyHalo2Proof(srsPath, verifyingKeyPath, res.proof, res.inputs).toString() + val endTime = System.currentTimeMillis() + verifyingTime = "verifying time: " + (endTime - startTime).toString() + " ms" + }, + modifier = Modifier.padding(top = 120.dp) + ) { Text(text = "verify proof") } + Text( + text = "Halo2 Fibonacci proof", + modifier = Modifier.padding(bottom = 180.dp), + fontWeight = FontWeight.Bold + ) + + Text(text = provingTime, modifier = Modifier.padding(top = 250.dp).width(200.dp)) + Text(text = valid, modifier = Modifier.padding(top = 300.dp).width(200.dp)) + Text(text = verifyingTime, modifier = Modifier.padding(top = 350.dp).width(200.dp)) + } +} \ No newline at end of file diff --git a/test-e2e/android/app/src/main/java/com/mopro/mopro_app/MainActivity.kt b/test-e2e/android/app/src/main/java/com/mopro/mopro_app/MainActivity.kt index 4428d723..2db15c00 100644 --- a/test-e2e/android/app/src/main/java/com/mopro/mopro_app/MainActivity.kt +++ b/test-e2e/android/app/src/main/java/com/mopro/mopro_app/MainActivity.kt @@ -4,15 +4,16 @@ import MultiplierComponent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp import com.mopro.mopro_app.ui.theme.MoproappTheme import java.io.File import java.io.IOException @@ -20,45 +21,61 @@ import java.io.InputStream import java.io.OutputStream @Throws(IOException::class) -private fun copyFile(`in`: InputStream, out: OutputStream) { +fun copyFile(inputStream: InputStream, outputStream: OutputStream) { val buffer = ByteArray(1024) var read: Int - while ((`in`.read(buffer).also { read = it }) != -1) { - out.write(buffer, 0, read) + while (inputStream.read(buffer).also { read = it } != -1) { + outputStream.write(buffer, 0, read) + } +} + +@Composable +fun getFilePathFromAssets(name: String): String { + val context = LocalContext.current + return remember { + val assetManager = context.assets + val inputStream = assetManager.open(name) + val file = File(context.filesDir, name) + copyFile(inputStream, file.outputStream()) + file.absolutePath } } class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - enableEdgeToEdge() setContent { MoproappTheme { - Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> - val s = assets.open("multiplier2_final.zkey") - val f = File(filesDir, "multiplier2_final.zkey") - copyFile(s, f.outputStream()) - Column(modifier = Modifier.fillMaxSize().padding(paddingValues = innerPadding)) { - MultiplierComponent(f.absolutePath) - } - } + MainScreen() } } } } @Composable -fun Greeting(name: String, modifier: Modifier = Modifier) { - Text( - text = "Hello $name!", - modifier = modifier - ) -} +fun MainScreen() { + var selectedTab by remember { mutableStateOf(0) } + val tabs = listOf("Circom", "Halo2") -@Preview(showBackground = true) -@Composable -fun GreetingPreview() { - MoproappTheme { - Greeting("Android") + Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> + Column(modifier = Modifier + .fillMaxSize() + .padding(innerPadding) + ) { + TabRow(selectedTabIndex = selectedTab) { + tabs.forEachIndexed { index, title -> + Tab( + text = { Text(title) }, + selected = selectedTab == index, + onClick = { selectedTab = index } + ) + } + } + Spacer(modifier = Modifier.height(16.dp)) + when (selectedTab) { + 0 -> MultiplierComponent() + 1 -> FibonacciComponent() + } + } } } \ No newline at end of file diff --git a/test-e2e/android/app/src/main/java/com/mopro/mopro_app/MultiplierComponent.kt b/test-e2e/android/app/src/main/java/com/mopro/mopro_app/MultiplierComponent.kt index a1876628..23fdfeed 100644 --- a/test-e2e/android/app/src/main/java/com/mopro/mopro_app/MultiplierComponent.kt +++ b/test-e2e/android/app/src/main/java/com/mopro/mopro_app/MultiplierComponent.kt @@ -4,22 +4,18 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.Button import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp +import com.mopro.mopro_app.getFilePathFromAssets import uniffi.mopro.GenerateProofResult import uniffi.mopro.generateCircomProof import uniffi.mopro.verifyCircomProof -import java.nio.file.Paths @Composable -fun MultiplierComponent(zkeyPath: String) { +fun MultiplierComponent() { var initTime by remember { mutableStateOf("init time:") } var provingTime by remember { mutableStateOf("proving time:") } var verifyingTime by remember { mutableStateOf("verifying time: ") } @@ -35,6 +31,8 @@ fun MultiplierComponent(zkeyPath: String) { inputs["a"] = listOf("3") inputs["b"] = listOf("5") + val zkeyPath = getFilePathFromAssets("multiplier2_final.zkey") + Box(modifier = Modifier.fillMaxSize().padding(16.dp), contentAlignment = Alignment.Center) { Button( onClick = { @@ -43,13 +41,9 @@ fun MultiplierComponent(zkeyPath: String) { val startTime = System.currentTimeMillis() res = generateCircomProof(zkeyPath, inputs) val endTime = System.currentTimeMillis() - provingTime = - "proving time: " + - (endTime - startTime).toString() + - " ms" + provingTime = "proving time: " + (endTime - startTime).toString() + " ms" } - ) - .start() + ).start() }, modifier = Modifier.padding(top = 20.dp) ) { Text(text = "generate proof") }