adding prover functions and cpp dir similar to FreedomTool

This commit is contained in:
0xturboblitz
2024-04-05 18:57:38 -07:00
parent 355cffd6b5
commit 2f09783c87
9 changed files with 478 additions and 49 deletions

View File

@@ -140,6 +140,8 @@ dependencies {
implementation("net.java.dev.jna:jna:5.13.0@aar")
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android'
implementation project(':react-native-fs')
implementation 'com.google.code.gson:gson:2.8.9'
}
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

View File

@@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.22.1)
project("proofofpassport")
set(JDK_DIR "/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home")
# Include the JDK header files
include_directories(${JDK_DIR}/include)
include_directories(${JDK_DIR}/include/darwin)
include_directories(include)
link_directories(lib)
add_library(rapidsnark SHARED IMPORTED)
set_target_properties(rapidsnark PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/lib/librapidsnark.so)
add_library(proof_of_passport SHARED IMPORTED)
set_target_properties(proof_of_passport PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/lib/libwitnesscalc_proof_of_passport.so)
add_library(${CMAKE_PROJECT_NAME} SHARED
proofofpassport.cpp)
target_link_libraries(${CMAKE_PROJECT_NAME}
rapidsnark proof_of_passport)
# android log fq fr gmp rapidsnark proof_of_passport rapidsnark-fr-fq)

View File

@@ -0,0 +1,39 @@
#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 buffer size in bytes or 0 in case of an error
*/
unsigned long CalcPublicBufferSize(const void *zkey_buffer, unsigned long zkey_size);
/**
* 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);
#ifdef __cplusplus
}
#endif
#endif // PROVER_HPP

View File

@@ -0,0 +1,39 @@
#ifndef WITNESSCALC_PROOFOFPASSPORT_H
#define WITNESSCALC_PROOFOFPASSPORT_H
#ifdef __cplusplus
extern "C" {
#endif
#define WITNESSCALC_OK 0x0
#define WITNESSCALC_ERROR 0x1
#define WITNESSCALC_ERROR_SHORT_BUFFER 0x2
/**
*
* @return error code:
* WITNESSCALC_OK - in case of success.
* WITNESSCALC_ERROR - in case of an error.
*
* On success wtns_buffer is filled with witness data and
* wtns_size contains the number bytes copied to wtns_buffer.
*
* If wtns_buffer is too small then the function returns WITNESSCALC_ERROR_SHORT_BUFFER
* and the minimum size for wtns_buffer in wtns_size.
*
*/
int
witnesscalc_proof_of_passport(
const char *circuit_buffer, unsigned long circuit_size,
const char *json_buffer, unsigned long json_size,
char *wtns_buffer, unsigned long *wtns_size,
char *error_msg, unsigned long error_msg_maxsize);
#ifdef __cplusplus
}
#endif
#endif // WITNESSCALC_PROOFOFPASSPORT_H

Binary file not shown.

View File

@@ -0,0 +1,95 @@
#include "include/prover.h"
#include "include/witnesscalc_proof_of_passport.h"
#include <jni.h>
#include <iostream>
using namespace std;
extern "C"
JNIEXPORT jlong JNICALL
Java_com_proofofpassport_prover_ZKPTools_CalcPublicBufferSize(JNIEnv *env, jobject thiz,
jbyteArray zkey_buffer, jlong zkey_size) {
const void *zkeyBuffer = env->GetByteArrayElements(zkey_buffer, nullptr);
jlong result = CalcPublicBufferSize(zkeyBuffer, static_cast<unsigned long>(zkey_size));
env->ReleaseByteArrayElements(zkey_buffer,
reinterpret_cast<jbyte *>(const_cast<void *>(zkeyBuffer)), 0);
return result;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_proofofpassport_prover_ZKPTools_groth16_1prover(JNIEnv *env, jobject thiz,
jbyteArray zkey_buffer, jlong zkey_size,
jbyteArray wtns_buffer, jlong wtns_size,
jbyteArray proof_buffer, jlongArray proof_size,
jbyteArray public_buffer,
jlongArray public_size, jbyteArray error_msg,
jlong error_msg_max_size) {
const void *zkeyBuffer = env->GetByteArrayElements(zkey_buffer, nullptr);
const void *wtnsBuffer = env->GetByteArrayElements(wtns_buffer, nullptr);
char *proofBuffer = reinterpret_cast<char *>(env->GetByteArrayElements(proof_buffer,
nullptr));
char *publicBuffer = reinterpret_cast<char *>(env->GetByteArrayElements(public_buffer,
nullptr));
char *errorMsg = reinterpret_cast<char *>(env->GetByteArrayElements(error_msg, nullptr));
unsigned long proofSize = env->GetLongArrayElements(proof_size, nullptr)[0];
unsigned long publicSize = env->GetLongArrayElements(public_size, nullptr)[0];
int result = groth16_prover(zkeyBuffer, static_cast<unsigned long>(zkey_size),
wtnsBuffer, static_cast<unsigned long>(wtns_size),
proofBuffer, &proofSize,
publicBuffer, &publicSize,
errorMsg, static_cast<unsigned long>(error_msg_max_size));
env->SetLongArrayRegion(proof_size, 0, 1, reinterpret_cast<const jlong *>(&proofSize));
env->SetLongArrayRegion(public_size, 0, 1, reinterpret_cast<const jlong *>(&publicSize));
env->ReleaseByteArrayElements(zkey_buffer,
reinterpret_cast<jbyte *>(const_cast<void *>(zkeyBuffer)), 0);
env->ReleaseByteArrayElements(wtns_buffer,
reinterpret_cast<jbyte *>(const_cast<void *>(wtnsBuffer)), 0);
env->ReleaseByteArrayElements(proof_buffer, reinterpret_cast<jbyte *>(proofBuffer), 0);
env->ReleaseByteArrayElements(public_buffer, reinterpret_cast<jbyte *>(publicBuffer), 0);
env->ReleaseByteArrayElements(error_msg, reinterpret_cast<jbyte *>(errorMsg), 0);
return result;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_proofofpassport_prover_ZKPTools_witnesscalc_1proof_1of_1passport(JNIEnv *env, jobject thiz,
jbyteArray circuit_buffer,
jlong circuit_size, jbyteArray json_buffer,
jlong json_size, jbyteArray wtns_buffer,
jlongArray wtns_size, jbyteArray error_msg,
jlong error_msg_max_size) {
const char *circuitBuffer = reinterpret_cast<const char *>(env->GetByteArrayElements(
circuit_buffer, nullptr));
const char *jsonBuffer = reinterpret_cast<const char *>(env->GetByteArrayElements(json_buffer,
nullptr));
char *wtnsBuffer = reinterpret_cast<char *>(env->GetByteArrayElements(wtns_buffer, nullptr));
char *errorMsg = reinterpret_cast<char *>(env->GetByteArrayElements(error_msg, nullptr));
unsigned long wtnsSize = env->GetLongArrayElements(wtns_size, nullptr)[0];
int result = witnesscalc_proof_of_passport(
circuitBuffer, static_cast<unsigned long>(circuit_size),
jsonBuffer, static_cast<unsigned long>(json_size),
wtnsBuffer, &wtnsSize,
errorMsg, static_cast<unsigned long>(error_msg_max_size));
// Set the result and release the resources
env->SetLongArrayRegion(wtns_size, 0, 1, reinterpret_cast<jlong *>(&wtnsSize));
env->ReleaseByteArrayElements(circuit_buffer,
reinterpret_cast<jbyte *>(const_cast<char *>(circuitBuffer)), 0);
env->ReleaseByteArrayElements(json_buffer,
reinterpret_cast<jbyte *>(const_cast<char *>(jsonBuffer)), 0);
env->ReleaseByteArrayElements(wtns_buffer, reinterpret_cast<jbyte *>(wtnsBuffer), 0);
env->ReleaseByteArrayElements(error_msg, reinterpret_cast<jbyte *>(errorMsg), 0);
return result;
}

View File

@@ -6,6 +6,8 @@ import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.Promise
import android.util.Log
import android.content.Context
import java.io.ByteArrayOutputStream
import com.facebook.react.bridge.ReadableMap
import uniffi.mopro.GenerateProofResult
@@ -14,42 +16,41 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.proofofpassport.R
class ProverModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
private val TAG = "ProverModule"
lateinit var res: GenerateProofResult
override fun getName(): String {
return "Prover"
}
@ReactMethod
fun runInitAction(promise: Promise) {
// Launch a coroutine in the IO dispatcher for background tasks
CoroutineScope(Dispatchers.IO).launch {
try {
val startTime = System.currentTimeMillis()
uniffi.mopro.initializeMopro()
val endTime = System.currentTimeMillis()
val initTime = "init time: " + (endTime - startTime).toString() + " ms"
// Since the promise needs to be resolved in the main thread
withContext(Dispatchers.Main) {
promise.resolve(initTime)
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
promise.reject(e)
}
}
}
}
@ReactMethod
// fun runProveAction(inputs: ReadableMap, zkeypath: String, promise: Promise) {
fun runProveAction(inputs: ReadableMap, promise: Promise) {
Log.e(TAG, "inputs in provePassport kotlin: " + inputs.toString())
val formattedInputs = mutableMapOf<String, Any?>(
"mrz" to inputs.getArray("mrz")?.toArrayList()?.map { it.toString() },
"reveal_bitmap" to inputs.getArray("reveal_bitmap")?.toArrayList()?.map { it.toString() },
"dataHashes" to inputs.getArray("dataHashes")?.toArrayList()?.map { it.toString() },
"datahashes_padded_length" to inputs.getArray("datahashes_padded_length")?.toArrayList()?.map { it.toString() }?.firstOrNull(),
"eContentBytes" to inputs.getArray("eContentBytes")?.toArrayList()?.map { it.toString() },
"signature" to inputs.getArray("signature")?.toArrayList()?.map { it.toString() },
"signatureAlgorithm" to inputs.getArray("signatureAlgorithm")?.toArrayList()?.map { it.toString() }?.firstOrNull(),
"pubkey" to inputs.getArray("pubkey")?.toArrayList()?.map { it.toString() },
"pathIndices" to inputs.getArray("pathIndices")?.toArrayList()?.map { it.toString() },
"siblings" to inputs.getArray("siblings")?.toArrayList()?.map { it.toString() },
"root" to inputs.getArray("root")?.toArrayList()?.map { it.toString() }?.firstOrNull(),
"address" to inputs.getArray("address")?.toArrayList()?.map { it.toString() }?.firstOrNull(),
)
val gson = GsonBuilder().setPrettyPrinting().create()
Log.e(TAG, gson.toJson(formattedInputs))
// working example
// val inputs = mutableMapOf<String, List<String>>(
// "mrz" to listOf("97","91","95","31","88","80","60","70","82","65","84","65","86","69","82","78","73","69","82","60","60","70","76","79","82","69","78","84","60","72","85","71","85","69","83","60","74","69","65","78","60","60","60","60","60","60","60","60","60","49","57","72","65","51","52","56","50","56","52","70","82","65","48","48","48","55","49","57","49","77","50","57","49","50","48","57","53","60","60","60","60","60","60","60","60","60","60","60","60","60","60","48","50"),
@@ -66,35 +67,258 @@ class ProverModule(reactContext: ReactApplicationContext) : ReactContextBaseJava
// "address" to listOf("642829559307850963015472508762062935916233390536")
// )
val convertedInputs = mutableMapOf<String, List<String>>()
// data class InputsPassport(
// val `in`: List<Int>,
// val currDateYear: Int,
// val currDateMonth: Int,
// val currDateDay: Int,
// val credValidYear: Int,
// val credValidMonth: Int,
// val credValidDay: Int,
// val ageLowerbound: Int
// )
for ((key, value) in inputs.toHashMap()) {
val parsedArray = inputs.getArray(key)?.toArrayList()?.map { item ->
item.toString()
} ?: emptyList()
convertedInputs[key] = parsedArray
}
// val formattedInputs = InputsPassport(
// `in` = (dg1!!).toBitArray().toCharArray().map { it1 -> it1.digitToInt() },
// currDateDay = current.dayOfMonth,
// credValidDay = nextDate.dayOfMonth,
// credValidMonth = nextDate.month.value,
// credValidYear = nextDate.year.toString().takeLast(2).toInt(),
// currDateMonth = current.month.value,
// currDateYear = current.year.toString().takeLast(2).toInt(),
// ageLowerbound = 18
// )
Log.e(TAG, "convertedInputs: $convertedInputs")
val jsonInputs = gson.toJson(formattedInputs).toByteArray()
val zkpTools = ZKPTools(reactApplicationContext) // <== same thing here
// reactContext or context???
val zkp: ZkProof = ZKPUseCase(reactApplicationContext).generateZKP(
R.raw.proof_of_passport_zkey, //zkeyID as Int
R.raw.proof_of_passport_dat, // datID as Int
jsonInputs,
zkpTools::witnesscalc_proof_of_passport
)
val startTime = System.currentTimeMillis()
res = uniffi.mopro.generateProof2(convertedInputs)
val endTime = System.currentTimeMillis()
val provingTime = "proving time: " + (endTime - startTime).toString() + " ms"
Log.e(TAG, provingTime)
Log.e("ZKP", gson.toJson(zkp))
promise.resolve(zkp.toString())
// val convertedInputs = mutableMapOf<String, List<String>>()
// for ((key, value) in inputs.toHashMap()) {
// val parsedArray = inputs.getArray(key)?.toArrayList()?.map { item ->
// item.toString()
// } ?: emptyList()
// convertedInputs[key] = parsedArray
// }
// Log.e(TAG, "convertedInputs: $convertedInputs")
// val startTime = System.currentTimeMillis()
// res = uniffi.mopro.generateProof2(convertedInputs)
// val endTime = System.currentTimeMillis()
// val provingTime = "proving time: " + (endTime - startTime).toString() + " ms"
// Log.e(TAG, provingTime)
Log.e(TAG, "res: " + res.toString())
// Log.e(TAG, "res: " + res.toString())
promise.resolve(res.toString())
}
@ReactMethod
fun runVerifyAction(promise: Promise) {
val startTime = System.currentTimeMillis()
val valid = "valid: " + uniffi.mopro.verifyProof2(res.proof, res.inputs).toString()
val endTime = System.currentTimeMillis()
val verifyingTime = "verifying time: " + (endTime - startTime).toString() + " ms"
Log.e(TAG, verifyingTime)
promise.resolve(valid)
// promise.resolve(res.toString())
}
}
data class Proof(
val pi_a: List<String>,
val pi_b: List<List<String>>,
val pi_c: List<String>,
val protocol: String,
var curve: String = "bn128"
) {
companion object {
fun fromJson(jsonString: String): Proof {
val json = Gson().fromJson(jsonString, Proof::class.java)
json.curve = getDefaultCurve()
return json
}
private fun getDefaultCurve(): String {
return "bn128"
}
}
}
data class ZkProof(
val proof: Proof,
val pub_signals: List<String>
)
class ZKPTools(val context: Context) {
external fun witnesscalc_proof_of_passport(circuitBuffer: ByteArray,
circuitSize: Long,
jsonBuffer: ByteArray,
jsonSize: Long,
wtnsBuffer: ByteArray,
wtnsSize: LongArray,
errorMsg: ByteArray,
errorMsgMaxSize: Long): Int
external fun CalcPublicBufferSize(zkeyBuffer: ByteArray, zkeySize: Long): Long
external fun groth16_prover(
zkeyBuffer: ByteArray, zkeySize: Long,
wtnsBuffer: ByteArray, wtnsSize: Long,
proofBuffer: ByteArray, proofSize: LongArray,
publicBuffer: ByteArray, publicSize: LongArray,
errorMsg: ByteArray, errorMsgMaxSize: Long
): Int
init {
System.loadLibrary("rapidsnark");
System.loadLibrary("witnesscalc_proof_of_passport") // moonshot to avoid CMakeLists.txt and proofofpassport.cpp
// System.loadLibrary("proofofpassport")
}
fun openRawResourceAsByteArray(resourceName: Int): ByteArray {
val inputStream = context.resources.openRawResource(resourceName)
val byteArrayOutputStream = ByteArrayOutputStream()
try {
val buffer = ByteArray(1024)
var length: Int
while (inputStream.read(buffer).also { length = it } != -1) {
byteArrayOutputStream.write(buffer, 0, length)
}
return byteArrayOutputStream.toByteArray()
} finally {
byteArrayOutputStream.close()
inputStream.close()
}
}
}
class ZKPUseCase(val context: Context) {
fun generateZKP(
zkpId: Int, datFile: Int, inputs: ByteArray, proofFunction: (
circuitBuffer: ByteArray,
circuitSize: Long,
jsonBuffer: ByteArray,
jsonSize: Long,
wtnsBuffer: ByteArray,
wtnsSize: LongArray,
errorMsg: ByteArray,
errorMsgMaxSize: Long
) -> Int
): ZkProof {
val zkpTool = ZKPTools(context)
val zkp = zkpTool.openRawResourceAsByteArray(zkpId)
val datFile = zkpTool.openRawResourceAsByteArray(datFile)
val msg = ByteArray(256)
val witnessLen = LongArray(1)
witnessLen[0] = 100 * 1024 * 1024
val byteArr = ByteArray(100 * 1024 * 1024)
val res = proofFunction(
datFile,
datFile.size.toLong(),
inputs,
inputs.size.toLong(),
byteArr,
witnessLen,
msg,
256
)
Log.e("ZKPUseCase", "Witness gen res: $res")
Log.e("ZKPUseCase", "Witness gen return length: ${byteArr.size}")
Log.e("ZKPUseCase", "witnessLen: $witnessLen")
if (res == 2) {
throw Exception("Not enough memory for zkp")
}
if (res == 1) {
throw Exception("Error during zkp ${msg.decodeToString()}")
}
// val pubData = ByteArray(4 *1024 *1024)
// val pubLen = LongArray(1)
// pubLen[0] = pubData.size.toLong()
// val proofData = ByteArray(4*1024*1024)
// val proofLen = LongArray(1)
// proofLen[0] = proofData.size.toLong()
// val witnessData = byteArr.copyOfRange(0, witnessLen[0].toInt())
// val verification = zkpTool.groth16_prover(
// zkp,
// zkp.size.toLong(),
// witnessData,
// witnessLen[0],
// proofData,
// proofLen,
// pubData,
// pubLen,
// msg,
// 256
// )
// if (verification == 2) {
// throw Exception("Not enough memory for verification ${msg.decodeToString()}")
// }
// if (verification == 1) {
// throw Exception("Error during verification ${msg.decodeToString()}")
// }
// val proofDataZip = proofData.copyOfRange(0, proofLen[0].toInt())
// val index = findLastIndexOfSubstring(
// proofDataZip.toString(Charsets.UTF_8),
// "\"protocol\":\"groth16\"}"
// )
// val indexPubData = findLastIndexOfSubstring(
// pubData.decodeToString(),
// "]"
// )
// val formatedPubData = pubData.decodeToString().slice(0..indexPubData)
// val foramtedProof = proofDataZip.toString(Charsets.UTF_8).slice(0..index)
// val proof = Proof.fromJson(foramtedProof)
// return ZkProof(
// proof = proof,
// pub_signals = getPubSignals(formatedPubData).toList()
// )
return ZkProof(
proof = Proof.fromJson(""),
pub_signals = emptyList()
)
}
private fun findLastIndexOfSubstring(mainString: String, searchString: String): Int {
val index = mainString.lastIndexOf(searchString)
if (index != -1) {
// If substring is found, calculate the last index of the substring
return index + searchString.length - 1
}
return -1
}
private fun getPubSignals(jsonString: String): List<String> {
val gson = Gson()
val stringArray = gson.fromJson(jsonString, Array<String>::class.java)
return stringArray.toList()
}
}

View File

@@ -76,3 +76,5 @@ build_witnesscalc_ios
package*
.idea/
build_witnesscalc_android