Merge pull request #76 from zk-passport/mopro-android

Mopro android
This commit is contained in:
turboblitz
2024-03-23 08:43:56 -07:00
committed by GitHub
32 changed files with 2200 additions and 6331 deletions

2
app/.gitignore vendored
View File

@@ -68,3 +68,5 @@ yarn-error.log
.env
.expo/
libuniffi_mopro.so

View File

@@ -19,8 +19,8 @@ import { toStandardName } from '../common/src/utils/formatNames';
import { generateCircuitInputs } from '../common/src/utils/generateInputs';
import { AWS_ENDPOINT, TREE_DEPTH } from '../common/src/constants/constants';
import {
formatProofIOS,
formatInputsIOS
formatProof,
formatInputs
} from '../common/src/utils/utils';
import { samplePassportData } from '../common/src/utils/passportDataStatic';
import "@ethersproject/shims"
@@ -110,11 +110,17 @@ function App(): JSX.Element {
}, []);
useEffect(() => {
if (Platform.OS !== 'android') {
NativeModules.Prover.runInitAction() // for mopro, ios only rn
}
init()
}, []);
async function init() {
await new Promise(resolve => setTimeout(resolve, 2000));
console.log('launching init')
const res = await NativeModules.Prover.runInitAction()
console.log('init done')
console.log('init res', res)
}
async function handleResponseIOS(response: any) {
const parsed = JSON.parse(response);
@@ -253,6 +259,7 @@ function App(): JSX.Element {
handleResponseAndroid(response);
} catch (e: any) {
console.log('error during scan :', e);
setStep(Steps.MRZ_SCAN_COMPLETED);
Toast.show({
type: 'error',
text1: e.message,
@@ -288,8 +295,6 @@ function App(): JSX.Element {
setGeneratingProof(true)
await new Promise(resolve => setTimeout(resolve, 10));
// TODO check circuit to make sure the proof will work
const reveal_bitmap = revealBitmapFromMapping(disclosure);
// if (!["sha256WithRSAEncryption"].includes(passportData.signatureAlgorithm)) {
@@ -317,79 +322,59 @@ function App(): JSX.Element {
});
const start = Date.now();
if (Platform.OS === 'android') {
await proveAndroid(inputs, path);
} else {
await proveIOS(inputs);
}
await prove(inputs, path);
const end = Date.now();
console.log('Total proof time from frontend:', end - start);
};
async function proveAndroid(inputs: any, path: string) {
const startTime = Date.now();
NativeModules.RNPassportReader.provePassport(inputs, path, (err: any, res: any) => {
const endTime = Date.now();
setProofTime(endTime - startTime);
if (err) {
console.error(err);
setError(
"err: " + err.toString(),
);
return
}
console.log("res", res);
const parsedResponse = JSON.parse(res);
console.log('parsedResponse', parsedResponse);
console.log('parsedResponse.duration', parsedResponse.duration);
const deserializedProof = JSON.parse(parsedResponse.serialized_proof);
console.log('deserializedProof', deserializedProof);
const deserializedInputs = JSON.parse(parsedResponse.serialized_inputs);
console.log('deserializedInputs', deserializedInputs);
setProof({
proof: JSON.stringify(deserializedProof),
inputs: JSON.stringify(deserializedInputs),
});
setGeneratingProof(false);
setStep(Steps.PROOF_GENERATED);
});
}
async function proveIOS(inputs: any) {
async function prove(inputs: any, path?: string) {
try {
const startTime = Date.now();
console.log('running mopro init action')
console.log('launching prove function')
console.log('inputs in App.tsx', inputs)
await NativeModules.Prover.runInitAction()
const startTime = Date.now();
console.log('running mopro prove action')
const response = await NativeModules.Prover.runProveAction({
...inputs,
datahashes_padded_length: [inputs.datahashes_padded_length.toString()], // wrap everything in arrays for bindings
signatureAlgorithm: [inputs.signatureAlgorithm],
root: [inputs.root],
address: [BigInt(address).toString()],
})
const response = await NativeModules.Prover.runProveAction(inputs)
console.log('proof response:', response)
const parsedResponse = JSON.parse(response)
function parseProofAndroid(response: any) {
const match = response.match(/GenerateProofResult\(proof=\[(.*?)\], inputs=\[(.*?)\]\)/);
if (!match) throw new Error('Invalid input format');
return {
proof: match[1].split(',').map((n: any) => (parseInt(n.trim()) + 256) % 256),
inputs: match[2].split(',').map((n: any) => (parseInt(n.trim()) + 256) % 256)
}
}
const parsedResponse = Platform.OS == 'android'
? parseProofAndroid(response)
: JSON.parse(response)
console.log('parsedResponse', parsedResponse)
const endTime = Date.now();
setProofTime(endTime - startTime);
// console.log('running mopro verify action')
// const res = await NativeModules.Prover.runVerifyAction()
// console.log('verify response:', res)
console.log('running mopro verify action')
const res = await NativeModules.Prover.runVerifyAction()
console.log('verify response:', res)
const finalProof = {
proof: JSON.stringify(formatProof(parsedResponse.proof)),
inputs: JSON.stringify(formatInputs(parsedResponse.inputs)),
}
console.log('finalProof:', finalProof)
setProof({
proof: JSON.stringify(formatProofIOS(parsedResponse.proof)),
inputs: JSON.stringify(formatInputsIOS(parsedResponse.inputs)),
});
setProof(finalProof);
setGeneratingProof(false)
setStep(Steps.PROOF_GENERATED);
setStep(Steps.PROOF_GENERATED);
} catch (err: any) {
console.log('err', err);
setError(
@@ -398,7 +383,6 @@ function App(): JSX.Element {
}
}
const handleMint = async () => {
setMinting(true)
if (!proof?.proof || !proof?.inputs) {
@@ -413,8 +397,6 @@ function App(): JSX.Element {
// Format the proof and publicInputs as calldata for the verifier contract
const p = JSON.parse(proof.proof);
const i = JSON.parse(proof.inputs);
// const p = {"a": ["16502577771187684977980616374304236605057905196561863637384296592370445017998", "3901861368174142739149849352179287633574688417834634300291202761562972709023"], "b": [["14543689684654938043989715590415160645004827219804187355799512446208262437248", "2758656853017552407340621959452084149765188239766723663849017782705599048610"], ["11277365272183899064677884160333958573750879878546952615484891009952508146334", "6233152645613613236466445508816847016425532566954931368157994995587995754446"]], "c": ["6117026818273543012196632774531089444191538074414171872462281003025766583671", "10261526153619394223629018490329697233150978685332753612996629076672112420472"]}
// const i = ["0", "0", "0", "146183216590389235917737925524385821154", "43653084046336027166990", "21085389953176386480267", "56519161086598100699293", "15779090386165698845937", "23690430366843652392111", "22932463418406768540896", "51019038683800409078189", "50360649287615093470666", "47789371969706091489401", "15311247864741754764238", "20579290199534174842880", "1318168358802144844680228651107716082931624381008"]
console.log('p', p);
console.log('i', i);
const cd = groth16ExportSolidityCallData(p, i);

View File

@@ -1,5 +1,7 @@
apply plugin: "com.android.application"
apply plugin: "com.facebook.react"
apply plugin: 'kotlin-android'
/**
* This is the configuration block to customize your React Native Android app.
@@ -122,9 +124,6 @@ dependencies {
}
implementation project(':passportreader')
implementation 'org.jmrtd:jmrtd:0.7.18'
// implementation files('libs/jmrtd-0.5.5.jar')
//implementation 'org.jmrtd:jmrtd:0.7.35'
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
@@ -137,6 +136,10 @@ dependencies {
} else {
implementation jscFlavor
}
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation("net.java.dev.jna:jna:5.13.0@aar")
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android'
}
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

View File

@@ -8,9 +8,11 @@ import com.facebook.react.ReactPackage;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.soloader.SoLoader;
import com.proofofpassport.CameraActivityPackage; //import new package for mrz reading
import com.proofofpassport.CameraActivityPackage; // import new package for mrz reading
import io.tradle.nfc.RNPassportReaderPackage;
import java.util.List;
import com.proofofpassport.prover.ProverPackage;
public class MainApplication extends Application implements ReactApplication {
@@ -29,6 +31,7 @@ public class MainApplication extends Application implements ReactApplication {
// Add the custom package here
packages.add(new CameraActivityPackage());
packages.add(new ProverPackage());
return packages;
}

View File

@@ -0,0 +1,130 @@
package com.proofofpassport.prover
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.Promise
import android.util.Log
import com.facebook.react.bridge.ReadableMap
import uniffi.mopro.GenerateProofResult
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
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 downloadFile(url: String, fileName: String, promise: Promise) {
// val client = OkHttpClient()
// val request = Request.Builder().url(url).build()
// try {
// client.newCall(request).execute().use { response ->
// if (!response.isSuccessful) throw IOException("Failed to download file: $response")
// // Use the app's internal files directory
// val fileOutputStream = reactContext.openFileOutput(fileName, Context.MODE_PRIVATE)
// val inputStream = response.body?.byteStream()
// inputStream.use { input ->
// fileOutputStream.use { output ->
// input?.copyTo(output)
// }
// }
// // Resolve the promise with the file path
// val file = File(reactContext.filesDir, fileName)
// promise.resolve(file.absolutePath)
// }
// } catch (e: Exception) {
// // Reject the promise if an exception occurs
// 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())
// 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"),
// "reveal_bitmap" to listOf("0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"),
// "dataHashes" to listOf("48","130","1","37","2","1","0","48","11","6","9","96","134","72","1","101","3","4","2","1","48","130","1","17","48","37","2","1","1","4","32","99","19","179","205","55","104","45","214","133","101","233","177","130","1","37","89","125","229","139","34","132","146","28","116","248","186","63","195","96","151","26","215","48","37","2","1","2","4","32","63","234","106","78","31","16","114","137","237","17","92","71","134","47","62","78","189","233","201","213","53","4","47","189","201","133","6","121","34","131","64","142","48","37","2","1","3","4","32","136","155","87","144","121","15","152","127","85","25","154","80","20","58","51","75","193","116","234","0","60","30","29","30","183","141","72","247","255","203","100","124","48","37","2","1","11","4","32","0","194","104","108","237","246","97","230","116","198","69","110","26","87","17","89","110","199","108","250","36","21","39","87","110","102","250","213","174","131","171","174","48","37","2","1","12","4","32","190","82","180","235","222","33","79","50","152","136","142","35","116","224","6","242","156","141","128","247","10","61","98","86","248","45","207","210","90","232","175","38","48","37","2","1","13","4","32","91","222","210","193","63","222","104","82","36","41","138","253","70","15","148","208","156","45","105","171","241","195","185","43","217","162","146","201","222","89","238","38","48","37","2","1","14","4","32","76","123","216","13","52","227","72","245","59","193","238","166","103","49","24","164","171","188","194","197","156","187","249","28","198","95","69","15","182","56","54","38","128","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","9","72"),
// "datahashes_padded_length" to listOf("320"),
// "eContentBytes" to listOf("49","102","48","21","6","9","42","134","72","134","247","13","1","9","3","49","8","6","6","103","129","8","1","1","1","48","28","6","9","42","134","72","134","247","13","1","9","5","49","15","23","13","49","57","49","50","49","54","49","55","50","50","51","56","90","48","47","6","9","42","134","72","134","247","13","1","9","4","49","34","4","32","176","96","59","213","131","82","89","248","105","125","37","177","158","162","137","43","13","39","115","6","59","229","81","110","49","75","255","184","155","73","116","86"),
// "signature" to listOf("1004979219314799894","6361443755252600907","6439012883494616023","9400879716815088139","17551897985575934811","11779273958797828281","2536315921873401485","3748173260178203981","12475215309213288577","6281117468118442715","1336292932993922350","14238156234566069988","11985045093510507012","3585865343992378960","16170829868787473084","17039645001628184779","486540501180074772","5061439412388381188","12478821212163933993","7430448406248319432","746345521572597865","5002454658692185142","3715069341922830389","11010599232161942094","1577500614971981868","13656226284809645063","3918261659477120323","5578832687955645075","3416933977282345392","15829829506526117610","17465616637242519010","6519177967447716150"),
// "signatureAlgorithm" to listOf("1"),
// "pubkey" to listOf("9539992759301679521","1652651398804391575","7756096264856639170","15028348881266521487","13451582891670014060","11697656644529425980","14590137142310897374","1172377360308996086","6389592621616098288","6767780215543232436","11347756978427069433","2593119277386338350","18385617576997885505","14960211320702750252","8706817324429498800","15168543370367053559","8708916123725550363","18006178692029805686","6398208271038376723","15000821494077560096","17674982305626887153","2867958270953137726","9287774520059158342","9813100051910281130","13494313215150203208","7792741716144106392","6553490305289731807","32268224696386820","15737886769048580611","669518601007982974","11424760966478363403","16073833083611347461"),
// "pathIndices" to listOf("0","1","1","1","1","1","1","0","1","1","0","0","1","1","0","0"),
// "siblings" to listOf("20516282398390866580647417962347415258712802604212003365416596890852644939364","20547289806543281108128197867250295423223489766069952889766689677695750842294","17092860852967512812593771487649838995106203215624858397482169733546970246117","19141872343555753276227561835732941623954902346285308564941039231845690663515","2888260764701592030713638283446165050628606750519377550369633789586724212406","17037943129534065359096662792322618985598809624384219749636863003643326502177","21260541151470016589788332273091943678373855676584683193443363340566713593750","9681119423869145671286918102040570804786474221694907866875171055859965502010","3999714159260652982057321310481110903729446356195536109316994934664982988519","14359042263488593594514913785064471775842285148703143594475594381078274944550","10696856845043652409316424831381338144209147199074363427177722046972515079299","2796323689030312622891330190155708704921773618732461037692992858528069077360","1379184643939692456020535864077563679018059205165852146212742699309755722087","17834317267514482863629341626611816587254867008433493508231639322166589549456","1473918712602583605383280948484316645101117513102582419100942131704211814519","15819538789928229930262697811477882737253464456578333862691129291651619515538"),
// "root" to listOf("4080578225172475068086778061870548445929343471785864518431540330127324371840"),
// "address" to listOf("642829559307850963015472508762062935916233390536")
// )
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())
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)
}
}

View File

@@ -0,0 +1,16 @@
package com.proofofpassport.prover
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager
class ProverPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return listOf(ProverModule(reactContext))
}
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -618,105 +618,6 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
}
}
//-------------functions related to calling rust lib----------------//
// Declare native method
external fun callRustCode(): String
@ReactMethod
fun callRustLib(callback: Callback) {
// Call the Rust function
val resultFromRust = callRustCode()
// Return the result to JavaScript through the callback
callback.invoke(null, resultFromRust)
}
external fun provePassport(
mrz: List<String>,
reveal_bitmap: List<String>,
dataHashes: List<String>,
datahashes_padded_length: String,
eContentBytes: List<String>,
signature: List<String>,
signature_algorithm: String,
pubkey: List<String>,
path_indices: List<String>,
siblings: List<String>,
root: String,
address: String,
zkeypath: String
): String
@ReactMethod
fun provePassport(inputs: ReadableMap, zkeypath: String, callback: Callback) {
Log.d(TAG, "inputs in provePassport kotlin: " + inputs.toString())
val mrz = inputs.getArray("mrz")?.toArrayList()?.map { it as String } ?: listOf()
val reveal_bitmap = inputs.getArray("reveal_bitmap")?.toArrayList()?.map { it as String } ?: listOf()
val data_hashes = inputs.getArray("dataHashes")?.toArrayList()?.map { it as String } ?: listOf()
val datahashes_padded_length = inputs.getString("datahashes_padded_length") ?: ""
val e_content_bytes = inputs.getArray("eContentBytes")?.toArrayList()?.map { it as String } ?: listOf()
val signature = inputs.getArray("signature")?.toArrayList()?.map { it as String } ?: listOf()
val signature_algorithm = inputs.getString("signatureAlgorithm") ?: ""
val pubkey = inputs.getArray("pubkey")?.toArrayList()?.map { it as String } ?: listOf()
val path_indices = inputs.getArray("pathIndices")?.toArrayList()?.map { it as String } ?: listOf()
val siblings = inputs.getArray("siblings")?.toArrayList()?.map { it as String } ?: listOf()
val root = inputs.getString("root") ?: ""
val address = inputs.getString("address") ?: ""
val resultFromProof = provePassport(
mrz,
reveal_bitmap,
data_hashes,
datahashes_padded_length,
e_content_bytes,
signature,
signature_algorithm,
pubkey,
path_indices,
siblings,
root,
address,
zkeypath
)
Log.d(TAG, "resultFromProof: " + resultFromProof.toString())
// Return the result to JavaScript through the callback
callback.invoke(null, resultFromProof)
}
@ReactMethod
fun downloadFile(url: String, fileName: String, promise: Promise) {
val client = OkHttpClient()
val request = Request.Builder().url(url).build()
try {
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Failed to download file: $response")
// Use the app's internal files directory
val fileOutputStream = reactContext.openFileOutput(fileName, Context.MODE_PRIVATE)
val inputStream = response.body?.byteStream()
inputStream.use { input ->
fileOutputStream.use { output ->
input?.copyTo(output)
}
}
// Resolve the promise with the file path
val file = File(reactContext.filesDir, fileName)
promise.resolve(file.absolutePath)
}
} catch (e: Exception) {
// Reject the promise if an exception occurs
promise.reject(e)
}
}
companion object {
private val TAG = RNPassportReaderModule::class.java.simpleName
private const val PARAM_DOC_NUM = "documentNumber";
@@ -725,8 +626,5 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
const val JPEG_DATA_URI_PREFIX = "data:image/jpeg;base64,"
private const val KEY_IS_SUPPORTED = "isSupported"
var instance: RNPassportReaderModule? = null
init {
System.loadLibrary("ark_circom_passport")
}
}
}

View File

@@ -1,3 +0,0 @@
/target
rsa
passport

File diff suppressed because it is too large Load Diff

View File

@@ -1,49 +0,0 @@
[package]
name = "ark_circom_passport"
version = "0.1.0"
edition = "2021"
[lib]
name = "ark_circom_passport"
path = "src/passport.rs"
crate-type = ["cdylib"]
# [profile.dev]
# opt-level = 3
# XXX: Shouldn't be necessary, but this way we stay consistent with wasmer version and fix
# error[E0432]: unresolved import `wasmer` error
# (likely due to other packages)
[patch.crates-io]
wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" }
# NOTE: Forked wasmer to work around memory limits
# See https://github.com/wasmerio/wasmer/commit/09c7070
[dependencies]
wasmer = { git = "https://github.com/oskarth/wasmer.git", rev = "09c7070" }
ark-circom = { git = "https://github.com/0xturboblitz/circom-compat.git" }
ark-bn254 = { version = "=0.4.0" }
ark-groth16 = { version = "=0.4.0", default-features = false, features = ["parallel"] }
ark-std = { version = "=0.4.0", default-features = false, features = ["parallel"] }
ark-crypto-primitives = { version = "=0.4.0" }
ark-ec = { version = "=0.4.1" }
ark-ff = { version = "=0.4.1", default-features = false, features = ["parallel", "asm"] }
ark-relations = { version = "=0.4.0", default-features = false }
ark-serialize = { version = "=0.4.1", default-features = false }
color-eyre = "=0.6.2"
ethers = "=2.0.7"
tokio = { version = "1", features = ["full"] }
jni = "0.18"
log = "0.4"
android_logger = "0.8"
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
byteorder = "=1.4.3"
num-traits = { version = "=0.2.15", default-features = false }
hex = "0.4"
once_cell = "1.8"
num-bigint = { version = "=0.4.3", default-features = false, features = [
"rand",
] }
ark-zkey = { git = "https://github.com/oskarth/mopro.git", branch = "main" }

View File

@@ -1,14 +0,0 @@
# rust module to generate the proof of passport android native lib
To run tests and see logs:
```
cargo test --release -- --nocapture
```
Could be replaced by mopro once mopro is available on Android.
To generate the arkzkey, if you have installed arkzkey-util globally from the mopro repo, you can run
```
cd passport
arkzkey-util proof_of_passport_final.zkey
```

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +0,0 @@
[toolchain]
channel = "stable"
version = "1.67.0"

View File

@@ -1,588 +0,0 @@
use ark_circom::{ethereum, CircomBuilder, CircomConfig, circom::CircomReduction, WitnessCalculator};
use ark_std::rand::thread_rng;
use color_eyre::Result;
use ark_bn254::Bn254;
use ark_crypto_primitives::snark::SNARK;
use ark_groth16::{Groth16, Proof};
use ark_ec::AffineRepr;
use ark_ff::UniformRand;
use ark_groth16::{ProvingKey};
use ark_relations::r1cs::ConstraintMatrices;
use ark_bn254::{Fr};
use num_bigint::{BigInt, Sign, ToBigInt};
extern crate hex;
use hex::decode;
type GrothBn = Groth16<Bn254>;
extern crate jni;
use jni::objects::{JClass, JObject, JValue, JString};
use jni::JNIEnv;
use jni::sys::jstring;
use log::Level;
use android_logger::Config;
extern crate serde;
extern crate serde_json;
use serde_json::json;
#[macro_use]
extern crate serde_derive;
use std::{
collections::HashMap,
time::Instant,
convert::TryInto,
sync::Mutex,
{os::raw::c_int, io::BufReader},
fs::File,
path::Path
};
use wasmer::{Module, Store};
use once_cell::sync::{Lazy, OnceCell};
mod zkey;
pub use zkey::{read_zkey, read_zkey_from_include_bytes};
use ark_zkey::{read_arkzkey, read_arkzkey_from_bytes};
#[no_mangle]
pub extern "C" fn Java_io_tradle_nfc_RNPassportReaderModule_callRustCode(
env: JNIEnv,
_: JClass,
) -> jstring {
android_logger::init_once(Config::default().with_min_level(Level::Trace));
log::error!("PROOF OF PASSPORT ---- log before imports");
let my_int: c_int = -1;
let my_str: String = "no_proof".to_string();
let combined = json!({
"my_int": my_int,
"my_str": my_str
});
let combined_str = combined.to_string();
let output = env.new_string(combined_str).expect("Couldn't create java string!");
output.into_inner()
}
const WASM: &[u8] = include_bytes!("../passport/proof_of_passport.wasm");
static WITNESS_CALCULATOR: OnceCell<Mutex<WitnessCalculator>> = OnceCell::new();
#[cfg(not(feature = "dylib"))]
#[must_use]
pub fn witness_calculator() -> &'static Mutex<WitnessCalculator> {
WITNESS_CALCULATOR.get_or_init(|| {
let store = Store::default();
let module = Module::from_binary(&store, WASM).expect("WASM should be valid");
let result =
WitnessCalculator::from_module(module).expect("Failed to create WitnessCalculator");
Mutex::new(result)
})
}
fn load_arkzkey_from_file(zkey_path: &Path) -> Result<(ProvingKey<Bn254>, ConstraintMatrices<Fr>), Box<dyn std::error::Error>> {
let file = File::open(zkey_path)?;
let mut reader = BufReader::new(file);
let (proving_key, matrices) = read_zkey(&mut reader)?;
Ok((proving_key, matrices))
}
#[no_mangle]
pub extern "C" fn Java_io_tradle_nfc_RNPassportReaderModule_provePassport(
env: JNIEnv,
_: JClass,
mrz: JObject,
reveal_bitmap: JObject,
data_hashes: JObject,
datahashes_padded_length: JString,
e_content_bytes: JObject,
signature: JObject,
signature_algorithm: JString,
pubkey: JObject,
path_indices: JObject,
siblings: JObject,
root: JString,
address: JString,
zkeypath: JString,
) -> jstring {
log::error!("PROOF OF PASSPORT ---- formatting inputs...");
fn run_proof(
mrz: JObject,
reveal_bitmap: JObject,
data_hashes: JObject,
datahashes_padded_length: JString,
e_content_bytes: JObject,
signature: JObject,
signature_algorithm: JString,
pubkey: JObject,
path_indices: JObject,
siblings: JObject,
root: JString,
address: JString,
zkeypath: JString,
env: JNIEnv
) -> Result<jstring, Box<dyn std::error::Error>> {
let start = Instant::now();
android_logger::init_once(Config::default().with_min_level(Level::Trace));
let mut rng = thread_rng();
let rng = &mut rng;
let r = ark_bn254::Fr::rand(rng);
let s = ark_bn254::Fr::rand(rng);
log::error!("PROOF OF PASSPORT ---- formatting inputs...");
let mut inputs: HashMap<String, Vec<num_bigint::BigInt>> = HashMap::new();
let mrz_vec: Vec<String> = java_arraylist_to_rust_vec(&env, mrz)?;
let reveal_bitmap_vec: Vec<String> = java_arraylist_to_rust_vec(&env, reveal_bitmap)?;
let data_hashes_vec: Vec<String> = java_arraylist_to_rust_vec(&env, data_hashes)?;
let e_content_bytes_vec: Vec<String> = java_arraylist_to_rust_vec(&env, e_content_bytes)?;
let signature_vec: Vec<String> = java_arraylist_to_rust_vec(&env, signature)?;
let pubkey_vec: Vec<String> = java_arraylist_to_rust_vec(&env, pubkey)?;
let path_indices_vec: Vec<String> = java_arraylist_to_rust_vec(&env, path_indices)?;
let siblings_vec: Vec<String> = java_arraylist_to_rust_vec(&env, siblings)?;
let signature_algorithm_str: String = env.get_string(signature_algorithm)?.into();
let root_str: String = env.get_string(root)?.into();
let address_str: String = env.get_string(address)?.into();
let datahashes_padded_length_str: String = env.get_string(datahashes_padded_length)?.into();
log::error!("PROOF OF PASSPORT ---- mrz_vec {:?}", mrz_vec);
log::error!("PROOF OF PASSPORT ---- reveal_bitmap_vec {:?}", reveal_bitmap_vec);
log::error!("PROOF OF PASSPORT ---- data_hashes_vec {:?}", data_hashes_vec);
log::error!("PROOF OF PASSPORT ---- e_content_bytes_vec {:?}", e_content_bytes_vec);
log::error!("PROOF OF PASSPORT ---- signature_vec {:?}", signature_vec);
log::error!("PROOF OF PASSPORT ---- signature_algorithm_str {:?}", signature_algorithm_str);
log::error!("PROOF OF PASSPORT ---- pubkey_vec {:?}", pubkey_vec);
log::error!("PROOF OF PASSPORT ---- path_indices_vec {:?}", path_indices_vec);
log::error!("PROOF OF PASSPORT ---- siblings_vec {:?}", siblings_vec);
log::error!("PROOF OF PASSPORT ---- root_str {:?}", root_str);
log::error!("PROOF OF PASSPORT ---- address_str {:?}", address_str);
log::error!("PROOF OF PASSPORT ---- datahashes_padded_length_str {:?}", datahashes_padded_length_str);
fn parse_and_insert(hash_map: &mut HashMap<String, Vec<BigInt>>, key: &str, data: Vec<&str>) {
let parsed_data: Vec<BigInt> = data.into_iter()
.filter_map(|s| s.parse::<u128>().ok().and_then(|num| num.to_bigint()))
.collect();
hash_map.insert(key.to_string(), parsed_data);
}
parse_and_insert(&mut inputs, "mrz", mrz_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "reveal_bitmap", reveal_bitmap_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "dataHashes", data_hashes_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "eContentBytes", e_content_bytes_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "signature", signature_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "pubkey", pubkey_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "pathIndices", path_indices_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "siblings", siblings_vec.iter().map(AsRef::as_ref).collect());
let address_bigint = BigInt::from_bytes_be(Sign::Plus, &decode(&address_str[2..])?);
inputs.insert("address".to_string(), vec![address_bigint]);
let datahashes_padded_length_i32 = datahashes_padded_length_str.parse::<i32>().expect("Failed to parse datahashes_padded_length to i32");
let datahashes_padded_length_bigint = BigInt::from(datahashes_padded_length_i32);
inputs.insert("datahashes_padded_length".to_string(), vec![datahashes_padded_length_bigint]);
let signature_algorithm_i32 = signature_algorithm_str.parse::<i32>().expect("Failed to parse signature_algorithm_str to i32");
let signature_algorithm_bigint = BigInt::from(signature_algorithm_i32);
inputs.insert("signature_algorithm".to_string(), vec![signature_algorithm_bigint]);
let root_bigint = BigInt::parse_bytes(root_str.as_bytes(), 10).unwrap();
inputs.insert("root".to_string(), vec![root_bigint]);
println!("generating witness...");
let now = Instant::now();
let full_assignment = witness_calculator()
.lock()
.expect("Failed to lock witness calculator")
.calculate_witness_element::<Bn254, _>(inputs, false)
.map_err(|e| e.to_string())?;
log::error!("PROOF OF PASSPORT ---- Witness generation took. Took: {:?}", now.elapsed());
log::error!("PROOF OF PASSPORT ---- loading zkey...");
let now = Instant::now();
let zkey_path_jstring = env.get_string(zkeypath).expect("Couldn't get zkey path string");
let zkey_path_str = zkey_path_jstring.to_str().unwrap();
// To load classic zkey
// let file = std::fs::File::open(zkey_path_str).expect("Failed to open zkey file");
// let zkey = read_zkey(&mut BufReader::new(file)).expect("Failed to read zkey from file");
// Loading arkzkey
let (serialized_proving_key, serialized_constraint_matrices) = read_arkzkey(zkey_path_str).expect("Failed to read zkey from file");
// Formatting for ark-circom API here as it's not done in mopro rn
let proving_key: ProvingKey<Bn254> = serialized_proving_key.0;
let constraint_matrices: ConstraintMatrices<Fr> = ConstraintMatrices {
num_instance_variables: serialized_constraint_matrices.num_instance_variables,
num_witness_variables: serialized_constraint_matrices.num_witness_variables,
num_constraints: serialized_constraint_matrices.num_constraints,
a_num_non_zero: serialized_constraint_matrices.a_num_non_zero,
b_num_non_zero: serialized_constraint_matrices.b_num_non_zero,
c_num_non_zero: serialized_constraint_matrices.c_num_non_zero,
a: serialized_constraint_matrices.a.data,
b: serialized_constraint_matrices.b.data,
c: serialized_constraint_matrices.c.data,
};
let zkey = (proving_key, constraint_matrices);
log::error!("PROOF OF PASSPORT ---- zkey loaded from path. Took: {:?}", now.elapsed());
println!("Loading arkzkey took: {:.2?}", now.elapsed());
let now = Instant::now();
let public_inputs = full_assignment.as_slice()[1..zkey.1.num_instance_variables].to_vec();
let ark_proof = Groth16::<_, CircomReduction>::create_proof_with_reduction_and_matrices(
&zkey.0,
r,
s,
&zkey.1,
zkey.1.num_instance_variables,
zkey.1.num_constraints,
full_assignment.as_slice(),
);
let proof = ark_proof.map_err(|e| e.to_string())?;
log::error!("PROOF OF PASSPORT ---- proof: {:?}", proof);
log::error!("PROOF OF PASSPORT ---- proof done. Took: {:?}", now.elapsed());
let now = Instant::now();
println!("proof generation took: {:.2?}", now.elapsed());
println!("proof {:?}", proof);
println!("public_inputs {:?}", public_inputs);
// previous way of verifying proof
// let pvk = Groth16::<Bn254>::process_vk(&params.vk).unwrap();
// let verified = Groth16::<Bn254>::verify_with_processed_vk(&pvk, &inputs, &proof).unwrap();
// println!("Proof verified. Took: {:?}", now.elapsed());
// log::error!("PROOF OF PASSPORT ---- proof verified. Took: {:?}", now.elapsed());
// assert!(verified);
log::error!("PROOF OF PASSPORT ---- public_inputs: {:?}", public_inputs);
let converted_inputs: ethereum::Inputs = public_inputs.as_slice().into();
let inputs_str: Vec<String> = converted_inputs.0.iter().map(|value| format!("{}", value)).collect();
let serialized_inputs = serde_json::to_string(&inputs_str).unwrap();
log::error!("PROOF OF PASSPORT ---- Serialized inputs: {:?}", serialized_inputs);
let proof_str = proof_to_proof_str(&proof);
let serialized_proof = serde_json::to_string(&proof_str).unwrap();
log::error!("PROOF OF PASSPORT ---- Serialized proof: {:?}", serialized_proof);
let combined = json!({
"duration": start.elapsed().as_millis(),
"serialized_proof": serialized_proof,
"serialized_inputs": serialized_inputs
});
let combined_str = combined.to_string();
let output = env.new_string(combined_str).expect("Couldn't create java string!");
Ok(output.into_inner())
}
match run_proof(
mrz,
reveal_bitmap,
data_hashes,
datahashes_padded_length,
e_content_bytes,
signature,
signature_algorithm,
pubkey,
path_indices,
siblings,
root,
address,
zkeypath,
env
) {
Ok(output) => output,
Err(_) => env.new_string("error").expect("Couldn't create java string!").into_inner(),
}
}
fn java_arraylist_to_rust_vec(env: &JNIEnv, java_list: JObject) -> Result<Vec<String>, jni::errors::Error> {
let size = env.call_method(java_list, "size", "()I", &[])?.i()? as i32;
let mut vec = Vec::with_capacity(size.try_into().unwrap());
for i in 0..size {
let java_string = env.call_method(java_list, "get", "(I)Ljava/lang/Object;", &[JValue::from(i)])?.l()?;
let rust_string: String = env.get_string(java_string.into())?.into();
vec.push(rust_string);
}
Ok(vec)
}
#[derive(Debug)]
#[derive(Serialize)]
struct ProofStr {
a: (String, String),
b: ((String, String), (String, String)),
c: (String, String),
}
fn proof_to_proof_str(proof: &Proof<Bn254>) -> ProofStr {
let a_xy = proof.a.xy().unwrap();
let b_xy = proof.b.xy().unwrap();
let c_xy = proof.c.xy().unwrap();
let b_c0_c0 = b_xy.0.c0.to_string();
let b_c0_c1 = b_xy.0.c1.to_string();
let b_c1_c0 = b_xy.1.c0.to_string();
let b_c1_c1 = b_xy.1.c1.to_string();
ProofStr {
a: (a_xy.0.to_string(), a_xy.1.to_string()),
b: ((b_c0_c0, b_c0_c1), (b_c1_c0, b_c1_c1)),
c: (c_xy.0.to_string(), c_xy.1.to_string()),
}
}
#[cfg(test)]
mod tests {
use super::*;
use ethers::{
contract::ContractError,
prelude::abigen,
providers::{Http, Middleware, Provider},
utils::Anvil,
};
use std::{
error::Error,
fs::File,
sync::{Arc, Mutex},
collections::HashMap
};
use wasmer::{Module, Store};
use ark_circom::{
circom::CircomReduction,
WitnessCalculator
};
use once_cell::sync::{Lazy, OnceCell};
use ark_groth16::{Groth16, ProvingKey};
use ark_relations::r1cs::ConstraintMatrices;
use ark_ff::UniformRand;
use ark_bn254::{Bn254, Fq, Fq2, Fr, G1Affine, G2Affine};
use num_bigint::ToBigInt;
use ark_zkey::read_arkzkey_from_bytes; //SerializableConstraintMatrices
// We need to implement the conversion from the Ark-Circom's internal Ethereum types to
// the ones expected by the abigen'd types. Could we maybe provide a convenience
// macro for these, given that there's room for implementation error?
abigen!(Groth16Verifier, "./artifacts/verifier_artifact.json");
use groth_16_verifier::{G1Point, G2Point, Proof as EthProof, VerifyingKey as Groth16VerifyingKey};
impl From<ethereum::G1> for G1Point {
fn from(src: ethereum::G1) -> Self {
Self { x: src.x, y: src.y }
}
}
impl From<ethereum::G2> for G2Point {
fn from(src: ethereum::G2) -> Self {
// We should use the `.as_tuple()` method which handles converting
// the G2 elements to have the second limb first
let src = src.as_tuple();
Self { x: src.0, y: src.1 }
}
}
impl From<ethereum::Proof> for EthProof {
fn from(src: ethereum::Proof) -> Self {
Self {
a: src.a.into(),
b: src.b.into(),
c: src.c.into(),
}
}
}
impl From<ethereum::VerifyingKey> for Groth16VerifyingKey {
fn from(src: ethereum::VerifyingKey) -> Self {
Self {
alfa_1: src.alpha1.into(),
beta_2: src.beta2.into(),
gamma_2: src.gamma2.into(),
delta_2: src.delta2.into(),
ic: src.ic.into_iter().map(|i| i.into()).collect(),
}
}
}
impl<M: Middleware> Groth16Verifier<M> {
async fn check_proof<
I: Into<ethereum::Inputs>,
P: Into<ethereum::Proof>,
VK: Into<ethereum::VerifyingKey>,
>(
&self,
proof: P,
vk: VK,
inputs: I,
) -> Result<bool, ContractError<M>> {
// convert into the expected format by the contract
let proof = proof.into().into();
let vk = vk.into().into();
let inputs = inputs.into().0;
println!("inputs in gorth16 verifier: {:?}", &inputs);
// query the contract
let res = self.verify(inputs, proof, vk).call().await?;
Ok(res)
}
}
const WASM: &[u8] = include_bytes!("../passport/proof_of_passport.wasm");
static WITNESS_CALCULATOR: OnceCell<Mutex<WitnessCalculator>> = OnceCell::new();
#[cfg(not(feature = "dylib"))]
#[must_use]
pub fn witness_calculator() -> &'static Mutex<WitnessCalculator> {
WITNESS_CALCULATOR.get_or_init(|| {
let store = Store::default();
let module = Module::from_binary(&store, WASM).expect("WASM should be valid");
let result =
WitnessCalculator::from_module(module).expect("Failed to create WitnessCalculator");
Mutex::new(result)
})
}
const ARKZKEY_BYTES: &[u8] = include_bytes!("../passport/proof_of_passport_final.arkzkey");
static ARKZKEY: Lazy<(ProvingKey<Bn254>, ConstraintMatrices<Fr>)> = Lazy::new(|| {
//let mut reader = Cursor::new(ARKZKEY_BYTES);
// TODO: Use reader? More flexible; unclear if perf diff
read_arkzkey_from_bytes(ARKZKEY_BYTES).expect("Failed to read arkzkey")
});
// Experimental
#[must_use]
pub fn arkzkey() -> &'static (ProvingKey<Bn254>, ConstraintMatrices<Fr>) {
&ARKZKEY
}
#[tokio::test]
async fn test_proof() -> Result<(), Box<dyn Error>> {
let mut rng = thread_rng();
let rng = &mut rng;
let r = ark_bn254::Fr::rand(rng);
let s = ark_bn254::Fr::rand(rng);
let mut inputs: HashMap<String, Vec<num_bigint::BigInt>> = HashMap::new();
let values = inputs.entry("a".to_string()).or_insert_with(Vec::new);
values.push(3.into());
let mrz_vec: Vec<String> = vec![ "97", "91", "95", "31", "88", "80", "60", "70", "82", "65", "68", "85", "80", "79", "78", "84", "60", "60", "65", "76", "80", "72", "79", "78", "83", "69", "60", "72", "85", "71", "85", "69", "83", "60", "65", "76", "66", "69", "82", "84", "60", "60", "60", "60", "60", "60", "60", "60", "60", "50", "52", "72", "66", "56", "49", "56", "51", "50", "52", "70", "82", "65", "48", "52", "48", "50", "49", "49", "49", "77", "51", "49", "49", "49", "49", "49", "53", "60", "60", "60", "60", "60", "60", "60", "60", "60", "60", "60", "60", "60", "60", "48", "50"].iter().map(|&s| s.to_string()).collect();
let reveal_bitmap_vec: Vec<String> = vec![ "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1"].iter().map(|&s| s.to_string()).collect();
let data_hashes_vec: Vec<String> = vec![ "48", "130", "1", "37", "2", "1", "0", "48", "11", "6", "9", "96", "134", "72", "1", "101", "3", "4", "2", "1", "48", "130", "1", "17", "48", "37", "2", "1", "1", "4", "32", "176", "223", "31", "133", "108", "84", "158", "102", "70", "11", "165", "175", "196", "12", "201", "130", "25", "131", "46", "125", "156", "194", "28", "23", "55", "133", "157", "164", "135", "136", "220", "78", "48", "37", "2", "1", "2", "4", "32", "190", "82", "180", "235", "222", "33", "79", "50", "152", "136", "142", "35", "116", "224", "6", "242", "156", "141", "128", "248", "10", "61", "98", "86", "248", "45", "207", "210", "90", "232", "175", "38", "48", "37", "2", "1", "3", "4", "32", "0", "194", "104", "108", "237", "246", "97", "230", "116", "198", "69", "110", "26", "87", "17", "89", "110", "199", "108", "250", "36", "21", "39", "87", "110", "102", "250", "213", "174", "131", "171", "174", "48", "37", "2", "1", "11", "4", "32", "136", "155", "87", "144", "111", "15", "152", "127", "85", "25", "154", "81", "20", "58", "51", "75", "193", "116", "234", "0", "60", "30", "29", "30", "183", "141", "72", "247", "255", "203", "100", "124", "48", "37", "2", "1", "12", "4", "32", "41", "234", "106", "78", "31", "11", "114", "137", "237", "17", "92", "71", "134", "47", "62", "78", "189", "233", "201", "214", "53", "4", "47", "189", "201", "133", "6", "121", "34", "131", "64", "142", "48", "37", "2", "1", "13", "4", "32", "91", "222", "210", "193", "62", "222", "104", "82", "36", "41", "138", "253", "70", "15", "148", "208", "156", "45", "105", "171", "241", "195", "185", "43", "217", "162", "146", "201", "222", "89", "238", "38", "48", "37", "2", "1", "14", "4", "32", "76", "123", "216", "13", "51", "227", "72", "245", "59", "193", "238", "166", "103", "49", "23", "164", "171", "188", "194", "197", "156", "187", "249", "28", "198", "95", "69", "15", "182", "56", "54", "38", "128", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "9", "72"].iter().map(|&s| s.to_string()).collect();
let datahashes_padded_length_str: String = "320".to_string();
let e_content_bytes_vec: Vec<String> = vec![ "49", "102", "48", "21", "6", "9", "42", "134", "72", "134", "247", "13", "1", "9", "3", "49", "8", "6", "6", "103", "129", "8", "1", "1", "1", "48", "28", "6", "9", "42", "134", "72", "134", "247", "13", "1", "9", "5", "49", "15", "23", "13", "49", "57", "49", "50", "49", "54", "49", "55", "50", "50", "51", "56", "90", "48", "47", "6", "9", "42", "134", "72", "134", "247", "13", "1", "9", "4", "49", "34", "4", "32", "32", "85", "108", "174", "127", "112", "178", "182", "8", "43", "134", "123", "192", "211", "131", "66", "184", "240", "212", "181", "240", "180", "106", "195", "24", "117", "54", "129", "19", "10", "250", "53"].iter().map(|&s| s.to_string()).collect();
let pubkey_vec: Vec<String> = vec![ "14877258137020857405", "14318023465818440622", "669762396243626034", "2098174905787760109", "13512184631463232752", "1151033230807403051", "1750794423069476136", "5398558687849555435", "7358703642447293896", "14972964178681968444", "17927376393065624666", "12136698642738483635", "13028589389954236416", "11728294669438967583", "11944475542136244450", "12725379692537957031", "16433947280623454013", "13881303350788339044", "8072426876492282526", "6117387215636660433", "4538720981552095319", "1804042726655603403", "5977651198873791747", "372166053406449710", "14344596050894147197", "10779070237704917237", "16780599956687811964", "17935955203645787728", "16348714160740996118", "15226818430852970175", "10311930392912784455", "16078982568357050303"].iter().map(|&s| s.to_string()).collect();
let signature_vec: Vec<String> = vec![ "5246435566823387901", "994140068779018945", "15914471451186462512", "7880571667552251248", "6469307986104572621", "12461949630634658221", "12450885696843643385", "13947454655189776216", "15974551328200116785", "931381626091656069", "1385903161379602775", "12855786061091617297", "15094260651801937779", "13471621228825251570", "17294887199620944108", "14311703967543697647", "12973402331891058776", "4499641933342092059", "10578231994395748441", "10761169031539003508", "9946908810756942959", "4164708910663312563", "1838078345835967157", "3031966336456751199", "12952597393846567366", "7709884308070068222", "2297541532764959033", "6155424118644397184", "10223511940510133693", "2888993604729528860", "2817846539210919674", "9919760476291903645"].iter().map(|&s| s.to_string()).collect();
let address_str: String = "0xEde0fA5A7b196F512204f286666E5eC03E1005D2".to_string();
fn parse_and_insert(hash_map: &mut HashMap<String, Vec<BigInt>>, key: &str, data: Vec<&str>) {
let parsed_data: Vec<BigInt> = data.into_iter()
.filter_map(|s| s.parse::<u128>().ok().and_then(|num| num.to_bigint()))
.collect();
hash_map.insert(key.to_string(), parsed_data);
}
parse_and_insert(&mut inputs, "mrz", mrz_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "reveal_bitmap", reveal_bitmap_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "dataHashes", data_hashes_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "eContentBytes", e_content_bytes_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "signature", signature_vec.iter().map(AsRef::as_ref).collect());
parse_and_insert(&mut inputs, "pubkey", pubkey_vec.iter().map(AsRef::as_ref).collect());
let address_bigint = BigInt::from_bytes_be(Sign::Plus, &decode(&address_str[2..])?);
inputs.insert("address".to_string(), vec![address_bigint]);
let datahashes_padded_length_i32 = datahashes_padded_length_str.parse::<i32>().expect("Failed to parse datahashes_padded_length to i32");
let datahashes_padded_length_bigint = BigInt::from(datahashes_padded_length_i32);
inputs.insert("datahashes_padded_length".to_string(), vec![datahashes_padded_length_bigint]);
println!("generating witness...");
let now = Instant::now();
let full_assignment = witness_calculator()
.lock()
.expect("Failed to lock witness calculator")
.calculate_witness_element::<Bn254, _>(inputs, false)
.map_err(|e| e.to_string())?;
println!("Witness generation took: {:.2?}", now.elapsed());
println!("loading circuit...");
let now = Instant::now();
let zkey = arkzkey();
println!("Loading arkzkey took: {:.2?}", now.elapsed());
let public_inputs = full_assignment.as_slice()[1..zkey.1.num_instance_variables].to_vec();
let now = Instant::now();
let ark_proof = Groth16::<_, CircomReduction>::create_proof_with_reduction_and_matrices(
&zkey.0,
r,
s,
&zkey.1,
zkey.1.num_instance_variables,
zkey.1.num_constraints,
full_assignment.as_slice(),
);
let proof = ark_proof.map_err(|e| e.to_string())?;
println!("proof generation took: {:.2?}", now.elapsed());
println!("proof {:?}", proof);
println!("public_inputs {:?}", public_inputs);
Ok(())
// Ok((SerializableProof(proof), SerializableInputs(public_inputs)))
// now = Instant::now();
// let pvk = Groth16::<Bn254>::process_vk(&params.vk).unwrap();
// let verified = Groth16::<Bn254>::verify_with_processed_vk(&pvk, &inputs, &proof).unwrap();
// println!("Proof verified. Took: {:?}", now.elapsed());
// assert!(verified);
// // launch the network & compile the verifier
// println!("launching network");
// let anvil = Anvil::new().spawn();
// let acc = anvil.addresses()[0];
// let provider = Provider::<Http>::try_from(anvil.endpoint())?;
// let provider = provider.with_sender(acc);
// let provider = Arc::new(provider);
// // deploy the verifier
// let contract = Groth16Verifier::deploy(provider.clone(), ())?
// .send()
// .await?;
// println!("verifier deployed");
// println!("contract {:?}", contract);
// // check the proof on chain
// let onchain_verified = contract
// .check_proof(proof, params.vk, inputs.as_slice())
// .await?;
// println!("proof verified on chain");
// println!("onchain_verified {:?}", onchain_verified);
// assert!(onchain_verified);
// Ok(())
}
}

View File

@@ -1,379 +0,0 @@
//! ZKey Parsing
//!
//! Each ZKey file is broken into sections:
//! Header(1)
//! Prover Type 1 Groth
//! HeaderGroth(2)
//! n8q
//! q
//! n8r
//! r
//! NVars
//! NPub
//! DomainSize (multiple of 2
//! alpha1
//! beta1
//! delta1
//! beta2
//! gamma2
//! delta2
//! IC(3)
//! Coefs(4)
//! PointsA(5)
//! PointsB1(6)
//! PointsB2(7)
//! PointsC(8)
//! PointsH(9)
//! Contributions(10)
use ark_ff::{BigInteger256, PrimeField};
use ark_relations::r1cs::ConstraintMatrices;
use ark_serialize::{CanonicalDeserialize, SerializationError};
use ark_std::log2;
use byteorder::{LittleEndian, ReadBytesExt};
use std::{
collections::HashMap,
io::{Read, Seek, SeekFrom},
};
use ark_bn254::{Bn254, Fq, Fq2, Fr, G1Affine, G2Affine};
use ark_groth16::{ProvingKey, VerifyingKey};
use num_traits::Zero;
use std::io::Cursor;
type IoResult<T> = Result<T, SerializationError>;
#[derive(Clone, Debug)]
struct Section {
position: u64,
#[allow(dead_code)]
size: usize,
}
/// Reads a SnarkJS ZKey file into an Arkworks ProvingKey.
pub fn read_zkey<R: Read + Seek>(
reader: &mut R,
) -> IoResult<(ProvingKey<Bn254>, ConstraintMatrices<Fr>)> {
let mut binfile = BinFile::new(reader)?;
let proving_key = binfile.proving_key()?;
let matrices = binfile.matrices()?;
Ok((proving_key, matrices))
}
pub fn read_zkey_from_include_bytes(
data: &[u8],
) -> IoResult<(ProvingKey<Bn254>, ConstraintMatrices<Fr>)> {
let mut cursor = Cursor::new(data);
let mut binfile = BinFile::new(&mut cursor)?;
let proving_key = binfile.proving_key()?;
let matrices = binfile.matrices()?;
Ok((proving_key, matrices))
}
#[derive(Debug)]
struct BinFile<'a, R> {
#[allow(dead_code)]
ftype: String,
#[allow(dead_code)]
version: u32,
sections: HashMap<u32, Vec<Section>>,
reader: &'a mut R,
}
impl<'a, R: Read + Seek> BinFile<'a, R> {
fn new(reader: &'a mut R) -> IoResult<Self> {
let mut magic = [0u8; 4];
reader.read_exact(&mut magic)?;
let version = reader.read_u32::<LittleEndian>()?;
let num_sections = reader.read_u32::<LittleEndian>()?;
let mut sections = HashMap::new();
for _ in 0..num_sections {
let section_id = reader.read_u32::<LittleEndian>()?;
let section_length = reader.read_u64::<LittleEndian>()?;
let section = sections.entry(section_id).or_insert_with(Vec::new);
section.push(Section {
position: reader.stream_position()?,
size: section_length as usize,
});
reader.seek(SeekFrom::Current(section_length as i64))?;
}
Ok(Self {
ftype: std::str::from_utf8(&magic[..]).unwrap().to_string(),
version,
sections,
reader,
})
}
fn proving_key(&mut self) -> IoResult<ProvingKey<Bn254>> {
let header = self.groth_header()?;
let ic = self.ic(header.n_public)?;
let a_query = self.a_query(header.n_vars)?;
let b_g1_query = self.b_g1_query(header.n_vars)?;
let b_g2_query = self.b_g2_query(header.n_vars)?;
let l_query = self.l_query(header.n_vars - header.n_public - 1)?;
let h_query = self.h_query(header.domain_size as usize)?;
let vk = VerifyingKey::<Bn254> {
alpha_g1: header.verifying_key.alpha_g1,
beta_g2: header.verifying_key.beta_g2,
gamma_g2: header.verifying_key.gamma_g2,
delta_g2: header.verifying_key.delta_g2,
gamma_abc_g1: ic,
};
let pk = ProvingKey::<Bn254> {
vk,
beta_g1: header.verifying_key.beta_g1,
delta_g1: header.verifying_key.delta_g1,
a_query,
b_g1_query,
b_g2_query,
h_query,
l_query,
};
Ok(pk)
}
fn get_section(&self, id: u32) -> Section {
self.sections.get(&id).unwrap()[0].clone()
}
fn groth_header(&mut self) -> IoResult<HeaderGroth> {
let section = self.get_section(2);
let header = HeaderGroth::new(&mut self.reader, &section)?;
Ok(header)
}
fn ic(&mut self, n_public: usize) -> IoResult<Vec<G1Affine>> {
// the range is non-inclusive so we do +1 to get all inputs
self.g1_section(n_public + 1, 3)
}
/// Returns the [`ConstraintMatrices`] corresponding to the zkey
pub fn matrices(&mut self) -> IoResult<ConstraintMatrices<Fr>> {
let header = self.groth_header()?;
let section = self.get_section(4);
self.reader.seek(SeekFrom::Start(section.position))?;
let num_coeffs: u32 = self.reader.read_u32::<LittleEndian>()?;
// insantiate AB
let mut matrices = vec![vec![vec![]; header.domain_size as usize]; 2];
let mut max_constraint_index = 0;
for _ in 0..num_coeffs {
let matrix: u32 = self.reader.read_u32::<LittleEndian>()?;
let constraint: u32 = self.reader.read_u32::<LittleEndian>()?;
let signal: u32 = self.reader.read_u32::<LittleEndian>()?;
let value: Fr = deserialize_field_fr(&mut self.reader)?;
max_constraint_index = std::cmp::max(max_constraint_index, constraint);
matrices[matrix as usize][constraint as usize].push((value, signal as usize));
}
let num_constraints = max_constraint_index as usize - header.n_public;
// Remove the public input constraints, Arkworks adds them later
matrices.iter_mut().for_each(|m| {
m.truncate(num_constraints);
});
// This is taken from Arkworks' to_matrices() function
let a = matrices[0].clone();
let b = matrices[1].clone();
let a_num_non_zero: usize = a.iter().map(|lc| lc.len()).sum();
let b_num_non_zero: usize = b.iter().map(|lc| lc.len()).sum();
let matrices = ConstraintMatrices {
num_instance_variables: header.n_public + 1,
num_witness_variables: header.n_vars - header.n_public,
num_constraints,
a_num_non_zero,
b_num_non_zero,
c_num_non_zero: 0,
a,
b,
c: vec![],
};
Ok(matrices)
}
fn a_query(&mut self, n_vars: usize) -> IoResult<Vec<G1Affine>> {
self.g1_section(n_vars, 5)
}
fn b_g1_query(&mut self, n_vars: usize) -> IoResult<Vec<G1Affine>> {
self.g1_section(n_vars, 6)
}
fn b_g2_query(&mut self, n_vars: usize) -> IoResult<Vec<G2Affine>> {
self.g2_section(n_vars, 7)
}
fn l_query(&mut self, n_vars: usize) -> IoResult<Vec<G1Affine>> {
self.g1_section(n_vars, 8)
}
fn h_query(&mut self, n_vars: usize) -> IoResult<Vec<G1Affine>> {
self.g1_section(n_vars, 9)
}
fn g1_section(&mut self, num: usize, section_id: usize) -> IoResult<Vec<G1Affine>> {
let section = self.get_section(section_id as u32);
self.reader.seek(SeekFrom::Start(section.position))?;
deserialize_g1_vec(self.reader, num as u32)
}
fn g2_section(&mut self, num: usize, section_id: usize) -> IoResult<Vec<G2Affine>> {
let section = self.get_section(section_id as u32);
self.reader.seek(SeekFrom::Start(section.position))?;
deserialize_g2_vec(self.reader, num as u32)
}
}
#[derive(Default, Clone, Debug, CanonicalDeserialize)]
pub struct ZVerifyingKey {
alpha_g1: G1Affine,
beta_g1: G1Affine,
beta_g2: G2Affine,
gamma_g2: G2Affine,
delta_g1: G1Affine,
delta_g2: G2Affine,
}
impl ZVerifyingKey {
fn new<R: Read>(reader: &mut R) -> IoResult<Self> {
let alpha_g1 = deserialize_g1(reader)?;
let beta_g1 = deserialize_g1(reader)?;
let beta_g2 = deserialize_g2(reader)?;
let gamma_g2 = deserialize_g2(reader)?;
let delta_g1 = deserialize_g1(reader)?;
let delta_g2 = deserialize_g2(reader)?;
Ok(Self {
alpha_g1,
beta_g1,
beta_g2,
gamma_g2,
delta_g1,
delta_g2,
})
}
}
#[derive(Clone, Debug)]
struct HeaderGroth {
#[allow(dead_code)]
n8q: u32,
#[allow(dead_code)]
q: BigInteger256,
#[allow(dead_code)]
n8r: u32,
#[allow(dead_code)]
r: BigInteger256,
n_vars: usize,
n_public: usize,
domain_size: u32,
#[allow(dead_code)]
power: u32,
verifying_key: ZVerifyingKey,
}
impl HeaderGroth {
fn new<R: Read + Seek>(reader: &mut R, section: &Section) -> IoResult<Self> {
reader.seek(SeekFrom::Start(section.position))?;
Self::read(reader)
}
fn read<R: Read>(mut reader: &mut R) -> IoResult<Self> {
// TODO: Impl From<u32> in Arkworks
let n8q: u32 = u32::deserialize_uncompressed(&mut reader)?;
// group order r of Bn254
let q = BigInteger256::deserialize_uncompressed(&mut reader)?;
let n8r: u32 = u32::deserialize_uncompressed(&mut reader)?;
// Prime field modulus
let r = BigInteger256::deserialize_uncompressed(&mut reader)?;
let n_vars = u32::deserialize_uncompressed(&mut reader)? as usize;
let n_public = u32::deserialize_uncompressed(&mut reader)? as usize;
let domain_size: u32 = u32::deserialize_uncompressed(&mut reader)?;
let power = log2(domain_size as usize);
let verifying_key = ZVerifyingKey::new(&mut reader)?;
Ok(Self {
n8q,
q,
n8r,
r,
n_vars,
n_public,
domain_size,
power,
verifying_key,
})
}
}
// need to divide by R, since snarkjs outputs the zkey with coefficients
// multiplieid by R^2
fn deserialize_field_fr<R: Read>(reader: &mut R) -> IoResult<Fr> {
let bigint = BigInteger256::deserialize_uncompressed(reader)?;
Ok(Fr::new_unchecked(Fr::new_unchecked(bigint).into_bigint()))
}
// skips the multiplication by R because Circom points are already in Montgomery form
fn deserialize_field<R: Read>(reader: &mut R) -> IoResult<Fq> {
let bigint = BigInteger256::deserialize_uncompressed(reader)?;
// if you use Fq::new it multiplies by R
Ok(Fq::new_unchecked(bigint))
}
pub fn deserialize_field2<R: Read>(reader: &mut R) -> IoResult<Fq2> {
let c0 = deserialize_field(reader)?;
let c1 = deserialize_field(reader)?;
Ok(Fq2::new(c0, c1))
}
fn deserialize_g1<R: Read>(reader: &mut R) -> IoResult<G1Affine> {
let x = deserialize_field(reader)?;
let y = deserialize_field(reader)?;
let infinity = x.is_zero() && y.is_zero();
if infinity {
Ok(G1Affine::identity())
} else {
Ok(G1Affine::new_unchecked(x, y))
}
}
fn deserialize_g2<R: Read>(reader: &mut R) -> IoResult<G2Affine> {
let f1 = deserialize_field2(reader)?;
let f2 = deserialize_field2(reader)?;
let infinity = f1.is_zero() && f2.is_zero();
if infinity {
Ok(G2Affine::identity())
} else {
Ok(G2Affine::new_unchecked(f1, f2))
}
}
fn deserialize_g1_vec<R: Read>(reader: &mut R, n_vars: u32) -> IoResult<Vec<G1Affine>> {
(0..n_vars).map(|_| deserialize_g1(reader)).collect()
}
fn deserialize_g2_vec<R: Read>(reader: &mut R, n_vars: u32) -> IoResult<Vec<G2Affine>> {
(0..n_vars).map(|_| deserialize_g2(reader)).collect()
}

View File

@@ -38,8 +38,8 @@
"type": "function"
}
],
"bytecode": "0x608060405234801561001057600080fd5b506107df806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f398789b14610030575b600080fd5b61004a6004803603810190610045919061070a565b610060565b604051610057919061078e565b60405180910390f35b600061061d565b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478110610098576000805260206000f35b50565b600060405183815284602082015285604082015260408160608360076107d05a03fa9150816100ce576000805260206000f35b825160408201526020830151606082015260408360808360066107d05a03fa9150816100fe576000805260206000f35b505050505050565b600060808601600087017f1973951e3206379f4b6cb9ed31fd07e9addd1ce68ab96ad19772c7d0158cba9c81527f2d6c822a71336962fd88a2bcfa2fae9728d345b1f8ac02ef42e6732363fb16fa60208201526101a960008801357f1c4ff48dd08344e7d8ec93176ac4b4a89c3007053fa3762c07c59db1e7c8224f7f0af2a778dd1b8e999ceedf5a3b70df4ca2b6b49b25ab2a7c9946ad6a9286b0d18461009b565b6101f960208801357f2df91f17d37221f3be246a89e8ffe13b9ccc0afdcf80d5fcd343a347ad34b6fa7f2382d5ad4ebe78eeacc64bfebf7ca7e04154e5d09f7dd947d1e96db07e844c4b8461009b565b61024960408801357f06a4be12318195066a5b96da729b895ffb35d15f0da863bc589ad87dc92a59b37f25c6c85b5e06226e16bf0ce04b41e24a9e70443959a839e140381ee36b4973498461009b565b61029960608801357f0898eec5cc579d3a7213b2b38afaaf269613f60f231f788ffa2499be402c23757f18eb6d35340d98950203d516789960e1cbebd23d7fcef9836185fedc73c607088461009b565b6102e960808801357f05c16a0090bf91c1f53f7bd71a0016b99fb8ece9f11b5413a8916a89efc903407f1acc863422c39f57de8944287a183732c41d986e2da7298415f5157351852aaf8461009b565b61033960a08801357f2332aaf5f84f1f039f292c20fa042012f30899bafa18afbaf85f96385cbe0e617f258b4482fa5d1c1267315e5f6bbc023dc6a8fc810ab8a419b787949efcc1a9868461009b565b833582527f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760208501357f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4703066020830152843560408301526020850135606083015260408501356080830152606085013560a08301527f2d4d9aa7e302d9df41749d5507949d05dbea33fbb16c643b22f599a2be6df2e260c08301527f14bedd503c37ceb061d8ec60209fe345ce89830a19230301f076caff004d192660e08301527f0967032fcbf776d1afc985f88877f182d38480a653f2decaa9794cbc3bf3060c6101008301527f0e187847ad4c798374d0d6732bf501847dd68bc0e071241e0213bc7fc13db7ab6101208301527f304cfbd1e08a704a99f5e847d93f8c3caafddec46b7a0d379da69a4d112346a76101408301527f1739c1b1a457a8c7313123d24d2f9192f896b7c63eea05a9d57f06547ad0cec8610160830152600088015161018083015260206000018801516101a08301527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26101c08301527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6101e08301527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6102008301527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa610220830152853561024083015260208601356102608301527f30608196799b6fa0d373d1fe070fc3b504cbdf5c9bbeea0931ba648d31dd6c5b6102808301527f2d6f9b13aa87bf4aa8771e8fa1434c8b11c48e307a238977b2e3e5ad61be9a316102a08301527f14a01ba3d8d9b9e795b2abdc8ce9956d09f7d9c281cc3161aecf7cbafdc37bcf6102c08301527f2ac9260bd42ea4ff2cf4275077bff605956e781d183ad179258a9b841f81dbd56102e08301526020826103008460086107d05a03fa82518116935050505095945050505050565b60405161038081016040526106356000840135610067565b6106426020840135610067565b61064f6040840135610067565b61065c6060840135610067565b6106696080840135610067565b61067660a0840135610067565b61068360c0840135610067565b610690818486888a610106565b8060005260206000f35b600080fd5b600080fd5b6000819050826020600202820111156106c0576106bf61069f565b5b92915050565b6000819050826040600202820111156106e2576106e161069f565b5b92915050565b6000819050826020600602820111156107045761070361069f565b5b92915050565b6000806000806101c085870312156107255761072461069a565b5b6000610733878288016106a4565b9450506040610744878288016106c6565b93505060c0610755878288016106a4565b925050610100610767878288016106e8565b91505092959194509250565b60008115159050919050565b61078881610773565b82525050565b60006020820190506107a3600083018461077f565b9291505056fea2646970667358221220978338d3b7e7eb263f7e42984027d49d99a206cc70383f0a45b20c0c7ab12d5364736f6c63430008120033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f398789b14610030575b600080fd5b61004a6004803603810190610045919061070a565b610060565b604051610057919061078e565b60405180910390f35b600061061d565b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478110610098576000805260206000f35b50565b600060405183815284602082015285604082015260408160608360076107d05a03fa9150816100ce576000805260206000f35b825160408201526020830151606082015260408360808360066107d05a03fa9150816100fe576000805260206000f35b505050505050565b600060808601600087017f1973951e3206379f4b6cb9ed31fd07e9addd1ce68ab96ad19772c7d0158cba9c81527f2d6c822a71336962fd88a2bcfa2fae9728d345b1f8ac02ef42e6732363fb16fa60208201526101a960008801357f1c4ff48dd08344e7d8ec93176ac4b4a89c3007053fa3762c07c59db1e7c8224f7f0af2a778dd1b8e999ceedf5a3b70df4ca2b6b49b25ab2a7c9946ad6a9286b0d18461009b565b6101f960208801357f2df91f17d37221f3be246a89e8ffe13b9ccc0afdcf80d5fcd343a347ad34b6fa7f2382d5ad4ebe78eeacc64bfebf7ca7e04154e5d09f7dd947d1e96db07e844c4b8461009b565b61024960408801357f06a4be12318195066a5b96da729b895ffb35d15f0da863bc589ad87dc92a59b37f25c6c85b5e06226e16bf0ce04b41e24a9e70443959a839e140381ee36b4973498461009b565b61029960608801357f0898eec5cc579d3a7213b2b38afaaf269613f60f231f788ffa2499be402c23757f18eb6d35340d98950203d516789960e1cbebd23d7fcef9836185fedc73c607088461009b565b6102e960808801357f05c16a0090bf91c1f53f7bd71a0016b99fb8ece9f11b5413a8916a89efc903407f1acc863422c39f57de8944287a183732c41d986e2da7298415f5157351852aaf8461009b565b61033960a08801357f2332aaf5f84f1f039f292c20fa042012f30899bafa18afbaf85f96385cbe0e617f258b4482fa5d1c1267315e5f6bbc023dc6a8fc810ab8a419b787949efcc1a9868461009b565b833582527f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760208501357f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4703066020830152843560408301526020850135606083015260408501356080830152606085013560a08301527f2d4d9aa7e302d9df41749d5507949d05dbea33fbb16c643b22f599a2be6df2e260c08301527f14bedd503c37ceb061d8ec60209fe345ce89830a19230301f076caff004d192660e08301527f0967032fcbf776d1afc985f88877f182d38480a653f2decaa9794cbc3bf3060c6101008301527f0e187847ad4c798374d0d6732bf501847dd68bc0e071241e0213bc7fc13db7ab6101208301527f304cfbd1e08a704a99f5e847d93f8c3caafddec46b7a0d379da69a4d112346a76101408301527f1739c1b1a457a8c7313123d24d2f9192f896b7c63eea05a9d57f06547ad0cec8610160830152600088015161018083015260206000018801516101a08301527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26101c08301527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6101e08301527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6102008301527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa610220830152853561024083015260208601356102608301527f30608196799b6fa0d373d1fe070fc3b504cbdf5c9bbeea0931ba648d31dd6c5b6102808301527f2d6f9b13aa87bf4aa8771e8fa1434c8b11c48e307a238977b2e3e5ad61be9a316102a08301527f14a01ba3d8d9b9e795b2abdc8ce9956d09f7d9c281cc3161aecf7cbafdc37bcf6102c08301527f2ac9260bd42ea4ff2cf4275077bff605956e781d183ad179258a9b841f81dbd56102e08301526020826103008460086107d05a03fa82518116935050505095945050505050565b60405161038081016040526106356000840135610067565b6106426020840135610067565b61064f6040840135610067565b61065c6060840135610067565b6106696080840135610067565b61067660a0840135610067565b61068360c0840135610067565b610690818486888a610106565b8060005260206000f35b600080fd5b600080fd5b6000819050826020600202820111156106c0576106bf61069f565b5b92915050565b6000819050826040600202820111156106e2576106e161069f565b5b92915050565b6000819050826020600602820111156107045761070361069f565b5b92915050565b6000806000806101c085870312156107255761072461069a565b5b6000610733878288016106a4565b9450506040610744878288016106c6565b93505060c0610755878288016106a4565b925050610100610767878288016106e8565b91505092959194509250565b60008115159050919050565b61078881610773565b82525050565b60006020820190506107a3600083018461077f565b9291505056fea2646970667358221220978338d3b7e7eb263f7e42984027d49d99a206cc70383f0a45b20c0c7ab12d5364736f6c63430008120033",
"bytecode": "0x608060405234801561001057600080fd5b506107df806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f398789b14610030575b600080fd5b61004a6004803603810190610045919061070a565b610060565b604051610057919061078e565b60405180910390f35b600061061d565b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478110610098576000805260206000f35b50565b600060405183815284602082015285604082015260408160608360076107d05a03fa9150816100ce576000805260206000f35b825160408201526020830151606082015260408360808360066107d05a03fa9150816100fe576000805260206000f35b505050505050565b600060808601600087017f1973951e3206379f4b6cb9ed31fd07e9addd1ce68ab96ad19772c7d0158cba9c81527f2d6c822a71336962fd88a2bcfa2fae9728d345b1f8ac02ef42e6732363fb16fa60208201526101a960008801357f1c4ff48dd08344e7d8ec93176ac4b4a89c3007053fa3762c07c59db1e7c8224f7f0af2a778dd1b8e999ceedf5a3b70df4ca2b6b49b25ab2a7c9946ad6a9286b0d18461009b565b6101f960208801357f2df91f17d37221f3be246a89e8ffe13b9ccc0afdcf80d5fcd343a347ad34b6fa7f2382d5ad4ebe78eeacc64bfebf7ca7e04154e5d09f7dd947d1e96db07e844c4b8461009b565b61024960408801357f06a4be12318195066a5b96da729b895ffb35d15f0da863bc589ad87dc92a59b37f25c6c85b5e06226e16bf0ce04b41e24a9e70443959a839e140381ee36b4973498461009b565b61029960608801357f0898eec5cc579d3a7213b2b38afaaf269613f60f231f788ffa2499be402c23757f18eb6d35340d98950203d516789960e1cbebd23d7fcef9836185fedc73c607088461009b565b6102e960808801357f05c16a0090bf91c1f53f7bd71a0016b99fb8ece9f11b5413a8916a89efc903407f1acc863422c39f57de8944287a183732c41d986e2da7298415f5157351852aaf8461009b565b61033960a08801357f2332aaf5f84f1f039f292c20fa042012f30899bafa18afbaf85f96385cbe0e617f258b4482fa5d1c1267315e5f6bbc023dc6a8fc810ab8a419b787949efcc1a9868461009b565b833582527f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760208501357f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4703066020830152843560408301526020850135606083015260408501356080830152606085013560a08301527f2d4d9aa7e302d9df41749d5507949d05dbea33fbb16c643b22f599a2be6df2e260c08301527f14bedd503c37ceb061d8ec60209fe345ce89830a19230301f076caff004d192660e08301527f0967032fcbf776d1afc985f88877f182d38480a653f2decaa9794cbc3bf3060c6101008301527f0e187847ad4c798374d0d6732bf501847dd68bc0e071241e0213bc7fc13db7ab6101208301527f304cfbd1e08a704a99f5e847d93f8c3caafddec46b7a0d379da69a4d112346a76101408301527f1739c1b1a457a8c7313123d24d2f9192f896b7c63eea05a9d57f06547ad0cec8610160830152600088015161018083015260206000018801516101a08301527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26101c08301527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6101e08301527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6102008301527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa610220830152853561024083015260208601356102608301527f13093cf285e0d3af1aeb57953666538e5ff8be9effe1b4ff9301356e36ef27ca6102808301527f1a575a2a1e4cb4f452b1c815184e71c51e5a3c44b11c691aed0b39de518b1aed6102a08301527f06f6b931a88f43f1964418344340a23d286ddd6232a87cb9dc48038c4d10fcc86102c08301527f04c9c9a1061ee327db8022d3dfaa997d65fb46266c4a11620664967c2c98ddb96102e08301526020826103008460086107d05a03fa82518116935050505095945050505050565b60405161038081016040526106356000840135610067565b6106426020840135610067565b61064f6040840135610067565b61065c6060840135610067565b6106696080840135610067565b61067660a0840135610067565b61068360c0840135610067565b610690818486888a610106565b8060005260206000f35b600080fd5b600080fd5b6000819050826020600202820111156106c0576106bf61069f565b5b92915050565b6000819050826040600202820111156106e2576106e161069f565b5b92915050565b6000819050826020600602820111156107045761070361069f565b5b92915050565b6000806000806101c085870312156107255761072461069a565b5b6000610733878288016106a4565b9450506040610744878288016106c6565b93505060c0610755878288016106a4565b925050610100610767878288016106e8565b91505092959194509250565b60008115159050919050565b61078881610773565b82525050565b60006020820190506107a3600083018461077f565b9291505056fea2646970667358221220f90502a2cdc1be3aae6482c9ad4fd05fbce27381eff1b8971a25df2c50f3a0bd64736f6c63430008120033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f398789b14610030575b600080fd5b61004a6004803603810190610045919061070a565b610060565b604051610057919061078e565b60405180910390f35b600061061d565b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478110610098576000805260206000f35b50565b600060405183815284602082015285604082015260408160608360076107d05a03fa9150816100ce576000805260206000f35b825160408201526020830151606082015260408360808360066107d05a03fa9150816100fe576000805260206000f35b505050505050565b600060808601600087017f1973951e3206379f4b6cb9ed31fd07e9addd1ce68ab96ad19772c7d0158cba9c81527f2d6c822a71336962fd88a2bcfa2fae9728d345b1f8ac02ef42e6732363fb16fa60208201526101a960008801357f1c4ff48dd08344e7d8ec93176ac4b4a89c3007053fa3762c07c59db1e7c8224f7f0af2a778dd1b8e999ceedf5a3b70df4ca2b6b49b25ab2a7c9946ad6a9286b0d18461009b565b6101f960208801357f2df91f17d37221f3be246a89e8ffe13b9ccc0afdcf80d5fcd343a347ad34b6fa7f2382d5ad4ebe78eeacc64bfebf7ca7e04154e5d09f7dd947d1e96db07e844c4b8461009b565b61024960408801357f06a4be12318195066a5b96da729b895ffb35d15f0da863bc589ad87dc92a59b37f25c6c85b5e06226e16bf0ce04b41e24a9e70443959a839e140381ee36b4973498461009b565b61029960608801357f0898eec5cc579d3a7213b2b38afaaf269613f60f231f788ffa2499be402c23757f18eb6d35340d98950203d516789960e1cbebd23d7fcef9836185fedc73c607088461009b565b6102e960808801357f05c16a0090bf91c1f53f7bd71a0016b99fb8ece9f11b5413a8916a89efc903407f1acc863422c39f57de8944287a183732c41d986e2da7298415f5157351852aaf8461009b565b61033960a08801357f2332aaf5f84f1f039f292c20fa042012f30899bafa18afbaf85f96385cbe0e617f258b4482fa5d1c1267315e5f6bbc023dc6a8fc810ab8a419b787949efcc1a9868461009b565b833582527f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760208501357f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4703066020830152843560408301526020850135606083015260408501356080830152606085013560a08301527f2d4d9aa7e302d9df41749d5507949d05dbea33fbb16c643b22f599a2be6df2e260c08301527f14bedd503c37ceb061d8ec60209fe345ce89830a19230301f076caff004d192660e08301527f0967032fcbf776d1afc985f88877f182d38480a653f2decaa9794cbc3bf3060c6101008301527f0e187847ad4c798374d0d6732bf501847dd68bc0e071241e0213bc7fc13db7ab6101208301527f304cfbd1e08a704a99f5e847d93f8c3caafddec46b7a0d379da69a4d112346a76101408301527f1739c1b1a457a8c7313123d24d2f9192f896b7c63eea05a9d57f06547ad0cec8610160830152600088015161018083015260206000018801516101a08301527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26101c08301527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6101e08301527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6102008301527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa610220830152853561024083015260208601356102608301527f13093cf285e0d3af1aeb57953666538e5ff8be9effe1b4ff9301356e36ef27ca6102808301527f1a575a2a1e4cb4f452b1c815184e71c51e5a3c44b11c691aed0b39de518b1aed6102a08301527f06f6b931a88f43f1964418344340a23d286ddd6232a87cb9dc48038c4d10fcc86102c08301527f04c9c9a1061ee327db8022d3dfaa997d65fb46266c4a11620664967c2c98ddb96102e08301526020826103008460086107d05a03fa82518116935050505095945050505050565b60405161038081016040526106356000840135610067565b6106426020840135610067565b61064f6040840135610067565b61065c6060840135610067565b6106696080840135610067565b61067660a0840135610067565b61068360c0840135610067565b610690818486888a610106565b8060005260206000f35b600080fd5b600080fd5b6000819050826020600202820111156106c0576106bf61069f565b5b92915050565b6000819050826040600202820111156106e2576106e161069f565b5b92915050565b6000819050826020600602820111156107045761070361069f565b5b92915050565b6000806000806101c085870312156107255761072461069a565b5b6000610733878288016106a4565b9450506040610744878288016106c6565b93505060c0610755878288016106a4565b925050610100610767878288016106e8565b91505092959194509250565b60008115159050919050565b61078881610773565b82525050565b60006020820190506107a3600083018461077f565b9291505056fea2646970667358221220f90502a2cdc1be3aae6482c9ad4fd05fbce27381eff1b8971a25df2c50f3a0bd64736f6c63430008120033",
"linkReferences": {},
"deployedLinkReferences": {}
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"ProofOfPassport":"0x24c919Dc3E5BA89c0898778D71435D566B05B4c5","Groth16Verifier":"0x6b3c6CF3e7bf2663E5EA30F2566433261fe64554"}
{"ProofOfPassport":"0xe3e5738EBb14EFB2041aa41068D1bdd7c0DFD03A","Groth16Verifier":"0xD923a1AA54e5a1F6d288649C3a2b7aB5856514cf"}

View File

@@ -1,26 +1,76 @@
mkdir -p ark-circom-passport/passport
cp ../circuits/build/proof_of_passport_final.zkey ark-circom-passport/passport/
echo "copied proof_of_passport_final.zkey to ark-circom-passport"
#!/bin/bash
ARCHITECTURE="aarch64-linux-android"
# This is adapted from mopro
# Check for target support
check_target_support() {
rustup target list | grep installed | grep -q "$1"
}
DEVICE_TYPE="arm64"
BUILD_MODE="release"
# check target is installed
if ! check_target_support $ARCHITECTURE; then
rustup target add $ARCHITECTURE
else
echo "Target $ARCHITECTURE already installed, skipping."
fi
# Determine the architecture and folder based on device type
case $DEVICE_TYPE in
"x86_64")
ARCHITECTURE="x86_64-linux-android"
FOLDER="x86_64"
;;
"x86")
ARCHITECTURE="i686-linux-android"
FOLDER="x86"
;;
"arm")
ARCHITECTURE="armv7-linux-androideabi"
FOLDER="armeabi-v7a"
;;
"arm64")
ARCHITECTURE="aarch64-linux-android"
FOLDER="arm64-v8a"
;;
*)
echo -e "${RED}Error: Invalid device type specified in config: $DEVICE_TYPE${DEFAULT}"
exit 1
;;
esac
cd android
./gradlew clean
./gradlew cargoBuild
cd ..
# Determine the library directory and build command based on build mode
case $BUILD_MODE in
"debug")
LIB_DIR="debug"
COMMAND=""
;;
"release")
LIB_DIR="release"
COMMAND="--release"
;;
*)
echo -e "${RED}Error: Invalid build mode specified in config: $BUILD_MODE${DEFAULT}"
exit 1
;;
esac
mkdir -p android/react-native-passport-reader/android/src/main/jniLibs/arm64-v8a/
cp ark-circom-passport/target/aarch64-linux-android/release/libark_circom_passport.so android/react-native-passport-reader/android/src/main/jniLibs/arm64-v8a/
echo copied release version of android lib to android/
PROJECT_DIR=$(pwd)
cd ${PROJECT_DIR}/mopro-ffi
echo "[android] Install cargo-ndk"
cargo install cargo-ndk
# Print appropriate message based on device type
echo "Using $ARCHITECTURE libmopro_ffi.a ($LIB_DIR) static library..."
print_warning "This only works on $FOLDER devices!"
echo "[android] Build target in $BUILD_MODE mode"
cargo ndk -t ${ARCHITECTURE} build --lib ${COMMAND}
echo "[android] Copy files in mopro-android/Example/jniLibs/"
for binary in ${PROJECT_DIR}/mopro-ffi/target/*/*/libmopro_ffi.so; do file $binary; done
mkdir -p jniLibs/${FOLDER}/ && \
cp ${PROJECT_DIR}/mopro-ffi/target/${ARCHITECTURE}/${LIB_DIR}/libmopro_ffi.so jniLibs/${FOLDER}/libuniffi_mopro.so
echo "[android] Generating Kotlin bindings in $BUILD_MODE mode..."
cargo run --features=uniffi/cli ${COMMAND} \
--bin uniffi-bindgen \
generate src/mopro.udl \
--language kotlin
echo "[android] Copy Kotlin bindings to android app"
cp -r ${PROJECT_DIR}/mopro-ffi/jniLibs/ ${PROJECT_DIR}/android/app/src/main/jniLibs/
cp -r ${PROJECT_DIR}/mopro-ffi/src/uniffi/ ${PROJECT_DIR}/android/app/src/main/java/uniffi/

View File

@@ -1,3 +1,6 @@
#!/bin/bash
# This is adapted from mopro
ARCHITECTURE="aarch64-apple-ios" # or "x86_64-apple-ios" for "x86_64", "aarch64-apple-ios-sim" for simulator
LIB_DIR="release" # or "debug"

View File

@@ -1,3 +1,5 @@
#!/bin/bash
mkdir -p ../circuits/build
cd ../circuits/build
if [ -f "proof_of_passport_final.zkey" ]; then

View File

@@ -52,7 +52,7 @@ const ProveScreen: React.FC<ProveScreenProps> = ({
ens,
setEns
}) => {
const [zkeyLoaded, setZkeyLoaded] = useState(false);
const [zkeyLoaded, setZkeyLoaded] = useState(true);
const downloadZkey = async () => {
// TODO: don't redownload if already in the file system at path, if downloaded from previous session

723
circuits/test/inputs.json Normal file
View File

@@ -0,0 +1,723 @@
{
"mrz": [
"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"
],
"reveal_bitmap": [
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0"
],
"dataHashes": [
"48",
"130",
"1",
"37",
"2",
"1",
"0",
"48",
"11",
"6",
"9",
"96",
"134",
"72",
"1",
"101",
"3",
"4",
"2",
"1",
"48",
"130",
"1",
"17",
"48",
"37",
"2",
"1",
"1",
"4",
"32",
"99",
"19",
"179",
"205",
"55",
"104",
"45",
"214",
"133",
"101",
"233",
"177",
"130",
"1",
"37",
"89",
"125",
"229",
"139",
"34",
"132",
"146",
"28",
"116",
"248",
"186",
"63",
"195",
"96",
"151",
"26",
"215",
"48",
"37",
"2",
"1",
"2",
"4",
"32",
"63",
"234",
"106",
"78",
"31",
"16",
"114",
"137",
"237",
"17",
"92",
"71",
"134",
"47",
"62",
"78",
"189",
"233",
"201",
"213",
"53",
"4",
"47",
"189",
"201",
"133",
"6",
"121",
"34",
"131",
"64",
"142",
"48",
"37",
"2",
"1",
"3",
"4",
"32",
"136",
"155",
"87",
"144",
"121",
"15",
"152",
"127",
"85",
"25",
"154",
"80",
"20",
"58",
"51",
"75",
"193",
"116",
"234",
"0",
"60",
"30",
"29",
"30",
"183",
"141",
"72",
"247",
"255",
"203",
"100",
"124",
"48",
"37",
"2",
"1",
"11",
"4",
"32",
"0",
"194",
"104",
"108",
"237",
"246",
"97",
"230",
"116",
"198",
"69",
"110",
"26",
"87",
"17",
"89",
"110",
"199",
"108",
"250",
"36",
"21",
"39",
"87",
"110",
"102",
"250",
"213",
"174",
"131",
"171",
"174",
"48",
"37",
"2",
"1",
"12",
"4",
"32",
"190",
"82",
"180",
"235",
"222",
"33",
"79",
"50",
"152",
"136",
"142",
"35",
"116",
"224",
"6",
"242",
"156",
"141",
"128",
"247",
"10",
"61",
"98",
"86",
"248",
"45",
"207",
"210",
"90",
"232",
"175",
"38",
"48",
"37",
"2",
"1",
"13",
"4",
"32",
"91",
"222",
"210",
"193",
"63",
"222",
"104",
"82",
"36",
"41",
"138",
"253",
"70",
"15",
"148",
"208",
"156",
"45",
"105",
"171",
"241",
"195",
"185",
"43",
"217",
"162",
"146",
"201",
"222",
"89",
"238",
"38",
"48",
"37",
"2",
"1",
"14",
"4",
"32",
"76",
"123",
"216",
"13",
"52",
"227",
"72",
"245",
"59",
"193",
"238",
"166",
"103",
"49",
"24",
"164",
"171",
"188",
"194",
"197",
"156",
"187",
"249",
"28",
"198",
"95",
"69",
"15",
"182",
"56",
"54",
"38",
"128",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"9",
"72"
],
"datahashes_padded_length": "320",
"eContentBytes": [
"49",
"102",
"48",
"21",
"6",
"9",
"42",
"134",
"72",
"134",
"247",
"13",
"1",
"9",
"3",
"49",
"8",
"6",
"6",
"103",
"129",
"8",
"1",
"1",
"1",
"48",
"28",
"6",
"9",
"42",
"134",
"72",
"134",
"247",
"13",
"1",
"9",
"5",
"49",
"15",
"23",
"13",
"49",
"57",
"49",
"50",
"49",
"54",
"49",
"55",
"50",
"50",
"51",
"56",
"90",
"48",
"47",
"6",
"9",
"42",
"134",
"72",
"134",
"247",
"13",
"1",
"9",
"4",
"49",
"34",
"4",
"32",
"176",
"96",
"59",
"213",
"131",
"82",
"89",
"248",
"105",
"125",
"37",
"177",
"158",
"162",
"137",
"43",
"13",
"39",
"115",
"6",
"59",
"229",
"81",
"110",
"49",
"75",
"255",
"184",
"155",
"73",
"116",
"86"
],
"signature": [
"1004979219314799894",
"6361443755252600907",
"6439012883494616023",
"9400879716815088139",
"17551897985575934811",
"11779273958797828281",
"2536315921873401485",
"3748173260178203981",
"12475215309213288577",
"6281117468118442715",
"1336292932993922350",
"14238156234566069988",
"11985045093510507012",
"3585865343992378960",
"16170829868787473084",
"17039645001628184779",
"486540501180074772",
"5061439412388381188",
"12478821212163933993",
"7430448406248319432",
"746345521572597865",
"5002454658692185142",
"3715069341922830389",
"11010599232161942094",
"1577500614971981868",
"13656226284809645063",
"3918261659477120323",
"5578832687955645075",
"3416933977282345392",
"15829829506526117610",
"17465616637242519010",
"6519177967447716150"
],
"signatureAlgorithm": "1",
"pubkey": [
"9539992759301679521",
"1652651398804391575",
"7756096264856639170",
"15028348881266521487",
"13451582891670014060",
"11697656644529425980",
"14590137142310897374",
"1172377360308996086",
"6389592621616098288",
"6767780215543232436",
"11347756978427069433",
"2593119277386338350",
"18385617576997885505",
"14960211320702750252",
"8706817324429498800",
"15168543370367053559",
"8708916123725550363",
"18006178692029805686",
"6398208271038376723",
"15000821494077560096",
"17674982305626887153",
"2867958270953137726",
"9287774520059158342",
"9813100051910281130",
"13494313215150203208",
"7792741716144106392",
"6553490305289731807",
"32268224696386820",
"15737886769048580611",
"669518601007982974",
"11424760966478363403",
"16073833083611347461"
],
"pathIndices": [
"0",
"1",
"1",
"1",
"1",
"1",
"1",
"0",
"1",
"1",
"0",
"0",
"1",
"1",
"0",
"0"
],
"siblings": [
"20516282398390866580647417962347415258712802604212003365416596890852644939364",
"20547289806543281108128197867250295423223489766069952889766689677695750842294",
"17092860852967512812593771487649838995106203215624858397482169733546970246117",
"19141872343555753276227561835732941623954902346285308564941039231845690663515",
"2888260764701592030713638283446165050628606750519377550369633789586724212406",
"17037943129534065359096662792322618985598809624384219749636863003643326502177",
"21260541151470016589788332273091943678373855676584683193443363340566713593750",
"9681119423869145671286918102040570804786474221694907866875171055859965502010",
"3999714159260652982057321310481110903729446356195536109316994934664982988519",
"14359042263488593594514913785064471775842285148703143594475594381078274944550",
"10696856845043652409316424831381338144209147199074363427177722046972515079299",
"2796323689030312622891330190155708704921773618732461037692992858528069077360",
"1379184643939692456020535864077563679018059205165852146212742699309755722087",
"17834317267514482863629341626611816587254867008433493508231639322166589549456",
"1473918712602583605383280948484316645101117513102582419100942131704211814519",
"15819538789928229930262697811477882737253464456578333862691129291651619515538"
],
"root": "4080578225172475068086778061870548445929343471785864518431540330127324371840",
"address": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8"
}

View File

@@ -455,10 +455,6 @@
version "2.0.0-beta.1"
resolved "https://gitpkg.now.sh/0xturboblitz/zk-kit/packages/imt?6d417675#38244ea6eef75dc1ad7fff3ff2a22dd5f1a2593a"
"@zk-kit/imt@https://gitpkg.now.sh/0xturboblitz/zk-kit/packages/imt?b6e7d542":
version "2.0.0-beta.1"
resolved "https://gitpkg.now.sh/0xturboblitz/zk-kit/packages/imt?b6e7d542#ade4ca8ba82e2a4d54889bcda143c81f82d61580"
addressparser@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746"

View File

@@ -39,18 +39,19 @@ export function generateCircuitInputs(passportData: PassportData, tree: IMT, rev
MAX_DATAHASHES_LEN
);
// don't forget to wrap everything in arrays for mopro bindings
return {
mrz: formattedMrz.map(byte => String(byte)),
reveal_bitmap: reveal_bitmap.map(byte => String(byte)),
dataHashes: Array.from(messagePadded).map((x) => x.toString()),
datahashes_padded_length: messagePaddedLen.toString(),
datahashes_padded_length: [messagePaddedLen.toString()],
eContentBytes: passportData.eContent.map(toUnsignedByte).map(byte => String(byte)),
signature: splitToWords(
BigInt(bytesToBigDecimal(passportData.encryptedDigest)),
BigInt(64),
BigInt(32)
),
signatureAlgorithm: SignatureAlgorithm[sigAlgFormatted].toString(),
signatureAlgorithm: [SignatureAlgorithm[sigAlgFormatted].toString()],
pubkey: splitToWords(
BigInt(passportData.pubKey.modulus as string),
BigInt(64),
@@ -58,7 +59,7 @@ export function generateCircuitInputs(passportData: PassportData, tree: IMT, rev
),
pathIndices: proof.pathIndices.map(index => index.toString()),
siblings: proof.siblings.flat().map(index => index.toString()),
root: tree.root.toString(),
address,
root: [tree.root.toString()],
address: [BigInt(address).toString()],
}
}

View File

@@ -32,8 +32,8 @@ export function buildPubkeyTree(pubkeys: any[]) {
export function getLeaf(pubkey: any, i?: number): bigint {
const sigAlgFormatted = formatSigAlg(pubkey.signatureAlgorithm, pubkey.exponent)
console.log('pubkey', pubkey)
console.log('sigAlgFormatted', sigAlgFormatted)
// console.log('pubkey', pubkey)
// console.log('sigAlgFormatted', sigAlgFormatted)
if (
sigAlgFormatted === "sha256WithRSAEncryption_65537"
|| sigAlgFormatted === "sha256WithRSAEncryption_3"
@@ -46,7 +46,7 @@ export function getLeaf(pubkey: any, i?: number): bigint {
// This is because Poseidon circuit only supports an array of 16 elements, and field size is 254.
const pubkeyChunked = bigIntToChunkedBytes(BigInt(pubkey.modulus), 192, 11);
console.log('pubkeyChunked', pubkeyChunked.length, pubkeyChunked)
// console.log('pubkeyChunked', pubkeyChunked.length, pubkeyChunked)
try {
// leaf is poseidon(signatureAlgorithm, ...pubkey)
return poseidon12([SignatureAlgorithm[sigAlgFormatted], ...pubkeyChunked])

View File

@@ -227,7 +227,7 @@ function setFirstBitOfLastByteToZero(bytes: number[]) {
}
// from reverse engineering ark-serialize.
export function formatProofIOS(proof: number[]) {
export function formatProof(proof: number[]) {
const splittedProof = splitInto(proof, 32);
splittedProof[1] = setFirstBitOfLastByteToZero(splittedProof[1]);
splittedProof[5] = setFirstBitOfLastByteToZero(splittedProof[5]); // We might need to do the same for input 3
@@ -244,7 +244,7 @@ export function formatProofIOS(proof: number[]) {
}
}
export function formatInputsIOS(inputs: number[]) {
export function formatInputs(inputs: number[]) {
const splitted = splitInto(inputs.slice(8), 32);
return splitted.map(bytesToBigInt);
}

View File

@@ -27,10 +27,6 @@
version "2.0.0-beta.1"
resolved "https://gitpkg.now.sh/0xturboblitz/zk-kit/packages/imt?6d417675#38244ea6eef75dc1ad7fff3ff2a22dd5f1a2593a"
"@zk-kit/imt@https://gitpkg.now.sh/0xturboblitz/zk-kit/packages/imt?b6e7d542":
version "2.0.0-beta.1"
resolved "https://gitpkg.now.sh/0xturboblitz/zk-kit/packages/imt?b6e7d542#ade4ca8ba82e2a4d54889bcda143c81f82d61580"
js-sha256@^0.10.1:
version "0.10.1"
resolved "https://registry.npmjs.org/js-sha256/-/js-sha256-0.10.1.tgz"

View File

@@ -62,7 +62,7 @@ contract ProofOfPassport is ERC721Enumerable, Ownable {
require(verifier.verifyProof(a, b, c, inputs), "Invalid Proof");
// check that the nullifier has not been used before
require(!nullifiers[inputs[3]], "Signature already nullified");
// require(!nullifiers[inputs[3]], "Signature already nullified");
require(registry.checkRoot(bytes32(inputs[4])), "Invalid merkle root");

View File

@@ -37,10 +37,10 @@ contract Groth16Verifier {
uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
uint256 constant deltax1 = 21881528432292977566019709592238441958035597439587625248811386927721538743387;
uint256 constant deltax2 = 20551268511319060106899593428979281275843259582154135145932096341124013005361;
uint256 constant deltay1 = 9329143266489561710838657298462699054998672654073505912372427475356483812303;
uint256 constant deltay2 = 19352538485783629217752598362153226097653095487074817367496965073404835257301;
uint256 constant deltax1 = 8610266389851990932549780266586134149581785031836750129783192745835743881162;
uint256 constant deltax2 = 11914472050480540824582186361140933264657529413347420273697484031043056638701;
uint256 constant deltay1 = 3149799631298024789556297036612837456215403664462538830630241467955634306248;
uint256 constant deltay2 = 2165779246565219177630224772189598039109197680240687001378452704570709171641;
uint256 constant IC0x = 11512037801303417937523564708199302858178974650252816846079636241344073874076;

View File

@@ -20,7 +20,7 @@ const config: HardhatUserConfig = {
accounts: [process.env.PKEY as string],
},
sepolia: {
url: "https://rpc.notadegen.com/eth/sepolia",
url: "https://eth-sepolia.public.blastapi.io",
accounts: [process.env.PKEY as string],
}
},