Merge pull request #61 from zk-passport/dynamic_dg_support

Support for variable number of datagroups in circuit
This commit is contained in:
turboblitz
2024-02-20 20:12:33 -07:00
committed by GitHub
23 changed files with 1317 additions and 169 deletions

View File

@@ -13,14 +13,12 @@ import {
DEFAULT_DOB,
DEFAULT_DOE
} from '@env';
import { DataHash, PassportData } from '../common/src/utils/types';
import { AWS_ENDPOINT } from '../common/src/constants/constants';
import { PassportData } from '../common/src/utils/types';
import { AWS_ENDPOINT, MAX_DATAHASHES_LEN } from '../common/src/constants/constants';
import {
hash,
toUnsignedByte,
bytesToBigDecimal,
dataHashesObjToArray,
formatAndConcatenateDataHashes,
formatMrz,
splitToWords,
hexStringToSignedIntArray,
@@ -28,6 +26,7 @@ import {
formatInputsIOS
} from '../common/src/utils/utils';
import { samplePassportData } from '../common/src/utils/passportDataStatic';
import { sha256Pad } from '../common/src/utils/sha256Pad';
import "@ethersproject/shims"
import { ethers, ZeroAddress } from "ethers";
@@ -143,7 +142,6 @@ function App(): JSX.Element {
console.log('isChipAuthenticationSupported', parsed.isChipAuthenticationSupported)
console.log('residenceAddress', parsed.residenceAddress)
console.log('passportPhoto', parsed.passportPhoto.substring(0, 100) + '...')
console.log('parsed.documentSigningCertificate', parsed.documentSigningCertificate)
const pem = JSON.parse(parsed.documentSigningCertificate).PEM.replace(/\\\\n/g, '\n')
console.log('pem', pem)
@@ -180,6 +178,7 @@ function App(): JSX.Element {
console.log('dataGroupHashes', passportData.dataGroupHashes);
console.log('eContent', passportData.eContent);
console.log('encryptedDigest', passportData.encryptedDigest);
console.log("photoBase64", passportData.photoBase64.substring(0, 100) + '...')
setPassportData(passportData);
setStep(Steps.NFC_SCAN_COMPLETED);
@@ -192,10 +191,15 @@ function App(): JSX.Element {
modulus,
curveName,
publicKeyQ,
dataGroupHashes,
eContent,
encryptedDigest,
photo
photo,
digestAlgorithm,
signerInfoDigestAlgorithm,
digestEncryptionAlgorithm,
LDSVersion,
unicodeVersion,
encapContent
} = response;
const passportData: PassportData = {
@@ -206,7 +210,7 @@ function App(): JSX.Element {
curveName: curveName,
publicKeyQ: publicKeyQ,
},
dataGroupHashes: dataHashesObjToArray(JSON.parse(dataGroupHashes)),
dataGroupHashes: JSON.parse(encapContent),
eContent: JSON.parse(eContent),
encryptedDigest: JSON.parse(encryptedDigest),
photoBase64: photo.base64,
@@ -219,6 +223,12 @@ function App(): JSX.Element {
console.log('eContent', passportData.eContent);
console.log('encryptedDigest', passportData.encryptedDigest);
console.log("photoBase64", passportData.photoBase64.substring(0, 100) + '...')
console.log("digestAlgorithm", digestAlgorithm)
console.log("signerInfoDigestAlgorithm", signerInfoDigestAlgorithm)
console.log("digestEncryptionAlgorithm", digestEncryptionAlgorithm)
console.log("LDSVersion", LDSVersion)
console.log("unicodeVersion", unicodeVersion)
console.log("encapContent", encapContent)
setPassportData(passportData);
setStep(Steps.NFC_SCAN_COMPLETED);
@@ -296,16 +306,6 @@ function App(): JSX.Element {
// 2. Format all the data as inputs for the circuit
const formattedMrz = formatMrz(passportData.mrz);
const mrzHash = hash(formatMrz(passportData.mrz));
const concatenatedDataHashes =
Array.isArray(passportData.dataGroupHashes[0])
? formatAndConcatenateDataHashes(
mrzHash,
passportData.dataGroupHashes as DataHash[],
)
: passportData.dataGroupHashes
const reveal_bitmap = Array.from({ length: 88 }, (_) => '0');
@@ -318,16 +318,29 @@ function App(): JSX.Element {
}
}
if (!["SHA256withRSA", "sha256WithRSAEncryption"].includes(passportData.signatureAlgorithm)) {
console.log(`${passportData.signatureAlgorithm} not supported for proof right now.`);
setError(`${passportData.signatureAlgorithm} not supported for proof right now.`);
return;
}
// if (!["SHA256withRSA", "sha256WithRSAEncryption"].includes(passportData.signatureAlgorithm)) {
// console.log(`${passportData.signatureAlgorithm} not supported for proof right now.`);
// setError(`${passportData.signatureAlgorithm} not supported for proof right now.`);
// return;
// }
console.log('passportData.dataGroupHashes', passportData.dataGroupHashes);
const dataGroupHashesUint8Array = new Uint8Array(passportData.dataGroupHashes);
console.log('dataGroupHashesUint8Array', dataGroupHashesUint8Array);
const [messagePadded, messagePaddedLen] = sha256Pad(
dataGroupHashesUint8Array,
MAX_DATAHASHES_LEN
);
console.log('messagePadded', messagePadded);
const inputs = {
mrz: Array.from(formattedMrz).map(byte => String(byte)),
reveal_bitmap: reveal_bitmap.map(byte => String(byte)),
dataHashes: Array.from((concatenatedDataHashes as number[]).map(toUnsignedByte)).map(byte => String(byte)),
dataHashes: Array.from(messagePadded).map((x) => (x as number).toString()),
datahashes_padded_length: messagePaddedLen.toString(),
eContentBytes: Array.from(passportData.eContent.map(toUnsignedByte)).map(byte => String(byte)),
signature: splitToWords(
BigInt(bytesToBigDecimal(passportData.encryptedDigest)),
@@ -396,6 +409,7 @@ function App(): JSX.Element {
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
address: [BigInt(address).toString()]
})
console.log('proof response:', response)
@@ -404,6 +418,10 @@ function App(): JSX.Element {
const endTime = Date.now();
setProofTime(endTime - startTime);
// console.log('running mopro verify action')
// const res = await NativeModules.Prover.runVerifyAction()
// console.log('verify response:', res)
setProof({
proof: JSON.stringify(formatProofIOS(parsedResponse.proof)),
inputs: JSON.stringify(formatInputsIOS(parsedResponse.inputs)),

View File

@@ -35,7 +35,13 @@ You might need to set the rust-toolchain rust version as global default. Example
rustup default 1.67.0
```
For macOs users you might also need to set-up the path to sdk:
Then, to generate the arkzkey, install arkzkey-util globally from the [mopro](https://github.com/oskarth/mopro) repo, then run:
```
cd ark-circom-passport/passport
arkzkey-util proof_of_passport_final.zkey
```
For macOS users you might also need to set-up the path to sdk:
in /app/android create local.properties
Add the following line:

View File

@@ -45,6 +45,9 @@ import org.bouncycastle.asn1.cms.SignedData
import org.bouncycastle.asn1.ASN1Primitive
import org.bouncycastle.asn1.ASN1Sequence
import org.bouncycastle.asn1.ASN1Set
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.icao.DataGroupHash;
import org.bouncycastle.asn1.icao.LDSSecurityObject;
import org.bouncycastle.asn1.x509.Certificate
import org.bouncycastle.jce.spec.ECNamedCurveSpec
import org.bouncycastle.jce.interfaces.ECPublicKey
@@ -85,6 +88,8 @@ import java.text.ParseException
import java.security.interfaces.RSAPublicKey
import java.text.SimpleDateFormat
import java.util.*
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.PublicKey
import java.security.spec.X509EncodedKeySpec
import javax.crypto.Cipher
@@ -516,8 +521,8 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
val gson = Gson()
val signedDataField = SODFile::class.java.getDeclaredField("signedData")
signedDataField.isAccessible = true
// val signedDataField = SODFile::class.java.getDeclaredField("signedData")
// signedDataField.isAccessible = true
// val signedData = signedDataField.get(sodFile) as SignedData
@@ -546,15 +551,38 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
// passport.putString("curveName", ecParams.getName())
// }
// Old one, probably wrong:
// passport.putString("curveName", (publicKey.parameters as ECNamedCurveSpec).name)
// passport.putString("curveName", (publicKey.parameters.algorithm)) or maybe this
// Old one, probably wrong:
// passport.putString("curveName", (publicKey.parameters as ECNamedCurveSpec).name)
// passport.putString("curveName", (publicKey.parameters.algorithm)) or maybe this
passport.putString("publicKeyQ", publicKey.q.toString())
}
passport.putString("dataGroupHashes", gson.toJson(sodFile.dataGroupHashes))
passport.putString("eContent", gson.toJson(sodFile.eContent))
passport.putString("encryptedDigest", gson.toJson(sodFile.encryptedDigest))
// passport.putString("encapContentInfo", gson.toJson(sodFile.encapContentInfo))
// passport.putString("contentInfo", gson.toJson(sodFile.contentInfo))
passport.putString("digestAlgorithm", gson.toJson(sodFile.digestAlgorithm))
passport.putString("signerInfoDigestAlgorithm", gson.toJson(sodFile.signerInfoDigestAlgorithm))
passport.putString("digestEncryptionAlgorithm", gson.toJson(sodFile.digestEncryptionAlgorithm))
passport.putString("LDSVersion", gson.toJson(sodFile.getLDSVersion()))
passport.putString("unicodeVersion", gson.toJson(sodFile.unicodeVersion))
// Get EncapContent (data group hashes) using reflection in Kotlin
val getENC: Method = SODFile::class.java.getDeclaredMethod("getLDSSecurityObject", SignedData::class.java)
getENC.isAccessible = true
val signedDataField: Field = sodFile::class.java.getDeclaredField("signedData")
signedDataField.isAccessible = true
val signedData: SignedData = signedDataField.get(sodFile) as SignedData
val ldsso: LDSSecurityObject = getENC.invoke(sodFile, signedData) as LDSSecurityObject
passport.putString("encapContent", gson.toJson(ldsso.encoded))
// passport.putString("getDocSigningCertificate", gson.toJson(sodFile.getDocSigningCertificate))
// passport.putString("getIssuerX500Principal", gson.toJson(sodFile.getIssuerX500Principal))
// passport.putString("getSerialNumber", gson.toJson(sodFile.getSerialNumber))
// Another way to get signing time is to get into signedData.signerInfos, then search for the ICO identifier 1.2.840.113549.1.9.5
@@ -608,6 +636,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
mrz: List<String>,
reveal_bitmap: List<String>,
dataHashes: List<String>,
datahashes_padded_length: String,
eContentBytes: List<String>,
signature: List<String>,
pubkey: List<String>,
@@ -622,6 +651,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
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 pubkey = inputs.getArray("pubkey")?.toArrayList()?.map { it as String } ?: listOf()
@@ -631,6 +661,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
mrz,
reveal_bitmap,
data_hashes,
datahashes_padded_length,
e_content_bytes,
signature,
pubkey,

View File

@@ -101,6 +101,7 @@ pub extern "C" fn Java_io_tradle_nfc_RNPassportReaderModule_provePassport(
mrz: JObject,
reveal_bitmap: JObject,
data_hashes: JObject,
datahashes_padded_length: JString,
e_content_bytes: JObject,
signature: JObject,
pubkey: JObject,
@@ -113,6 +114,7 @@ pub extern "C" fn Java_io_tradle_nfc_RNPassportReaderModule_provePassport(
mrz: JObject,
reveal_bitmap: JObject,
data_hashes: JObject,
datahashes_padded_length: JString,
e_content_bytes: JObject,
signature: JObject,
pubkey: JObject,
@@ -136,6 +138,7 @@ pub extern "C" fn Java_io_tradle_nfc_RNPassportReaderModule_provePassport(
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 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);
@@ -144,6 +147,7 @@ pub extern "C" fn Java_io_tradle_nfc_RNPassportReaderModule_provePassport(
log::error!("PROOF OF PASSPORT ---- signature_vec {:?}", signature_vec);
log::error!("PROOF OF PASSPORT ---- pubkey_vec {:?}", pubkey_vec);
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()
@@ -161,6 +165,9 @@ pub extern "C" fn Java_io_tradle_nfc_RNPassportReaderModule_provePassport(
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();
@@ -259,6 +266,7 @@ pub extern "C" fn Java_io_tradle_nfc_RNPassportReaderModule_provePassport(
mrz,
reveal_bitmap,
data_hashes,
datahashes_padded_length,
e_content_bytes,
signature,
pubkey,
@@ -446,14 +454,15 @@ mod tests {
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", "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"].iter().map(|&s| s.to_string()).collect();
let reveal_bitmap_vec: Vec<String> = vec!["0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "1", "1", "1", "1", "1", "1", "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"].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", "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"].iter().map(|&s| s.to_string()).collect();
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", "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"].iter().map(|&s| s.to_string()).collect();
let signature_vec: Vec<String> = vec!["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"].iter().map(|&s| s.to_string()).collect();
let pubkey_vec: Vec<String> = vec!["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"].iter().map(|&s| s.to_string()).collect();
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()))
@@ -471,6 +480,10 @@ mod tests {
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()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"ProofOfPassport":"0x50c47Be849dFac1FCbEDa031425896AF49d9FDFC","Groth16Verifier":"0xD6F5CA79b90a9E20B38df773122B4f50a1fda317"}
{"ProofOfPassport":"0x7AB5B112b09816617048482230C6Ea9629AF2349","Groth16Verifier":"0x764f40848eBD343da6595b0624c9480cfBA0668e"}

View File

@@ -60,7 +60,7 @@ const ProveScreen: React.FC<ProveScreenProps> = ({
try {
console.log('Downloading file...')
const result = await NativeModules.RNPassportReader.downloadFile(
'https://current-pop-zkey.s3.eu-north-1.amazonaws.com/proof_of_passport_final.arkzkey',
'https://current-pop-zkey.s3.eu-north-1.amazonaws.com/proof_of_passport_final_dynamic_dg_support.arkzkey',
fileName
);
console.log("Download successful");
@@ -222,7 +222,7 @@ const ProveScreen: React.FC<ProveScreenProps> = ({
<XStack f={1} />
<XStack f={1} />
<XStack f={1} />
{(!keyboardVisible || Platform.OS == "ios") && <Button disabled={address == ethers.ZeroAddress} borderRadius={100} onPress={() => {!zkeyLoaded ? downloadZkey() : handleProve(path)}} mt="$8" backgroundColor={address == ethers.ZeroAddress ? "#cecece" : "#3185FC"} alignSelf='center' >
{(!keyboardVisible || Platform.OS == "ios") && <Button disabled={address == ethers.ZeroAddress} borderRadius={100} onPress={() => {(!zkeyLoaded && Platform.OS != "ios") ? downloadZkey() : handleProve(path)}} mt="$8" backgroundColor={address == ethers.ZeroAddress ? "#cecece" : "#3185FC"} alignSelf='center' >
{!zkeyLoaded && Platform.OS != "ios" ? (
<Text color="white" fow="bold">Download zkey</Text>

View File

@@ -3,9 +3,9 @@ pragma circom 2.1.5;
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/sha256/sha256.circom";
template Sha256Bytes(max_num_bytes) {
// Static length sha256 bytes, adapted from zk-email
template Sha256BytesStatic(max_num_bytes) {
signal input in_padded[max_num_bytes];
// signal input in_len_padded_bytes;
signal output out[256];
var num_bits = max_num_bytes * 8;
@@ -19,7 +19,6 @@ template Sha256Bytes(max_num_bytes) {
sha.in[i*8+j] <== bytes[i].out[7-j];
}
}
// sha.in_len_padded_bits <== in_len_padded_bytes * 8;
for (var i = 0; i < 256; i++) {
out[i] <== sha.out[i];

View File

@@ -2,18 +2,20 @@ pragma circom 2.1.5;
include "@zk-email/circuits/helpers/rsa.circom";
include "@zk-email/circuits/helpers/extract.circom";
include "./sha256Bytes.circom";
include "@zk-email/circuits/helpers/sha.circom";
include "./Sha256BytesStatic.circom";
template PassportVerifier(n, k) {
template PassportVerifier(n, k, max_datahashes_bytes) {
signal input mrz[93]; // formatted mrz (5 + 88) chars
signal input dataHashes[297];
signal input dataHashes[max_datahashes_bytes];
signal input datahashes_padded_length;
signal input eContentBytes[104];
signal input pubkey[k];
signal input signature[k];
// compute sha256 of formatted mrz
signal mrzSha[256] <== Sha256Bytes(93)(mrz);
signal mrzSha[256] <== Sha256BytesStatic(93)(mrz);
// get output of sha256 into bytes to check against dataHashes
component sha256_bytes[32];
@@ -29,8 +31,8 @@ template PassportVerifier(n, k) {
dataHashes[31 + i] === sha256_bytes[i].out;
}
// hash dataHashes
signal dataHashesSha[256] <== Sha256Bytes(297)(dataHashes);
// hash dataHashes dynamically
signal dataHashesSha[256] <== Sha256Bytes(max_datahashes_bytes)(dataHashes, datahashes_padded_length);
// get output of dataHashes sha256 into bytes to check against eContent
component dataHashes_sha256_bytes[32];
@@ -47,7 +49,7 @@ template PassportVerifier(n, k) {
}
// hash eContentBytes
signal eContentSha[256] <== Sha256Bytes(104)(eContentBytes);
signal eContentSha[256] <== Sha256BytesStatic(104)(eContentBytes);
// get output of eContentBytes sha256 into k chunks of n bits each
var msg_len = (256 + n) \ n;

View File

@@ -4,9 +4,10 @@ include "circomlib/circuits/poseidon.circom";
include "@zk-email/circuits/helpers/extract.circom";
include "./passport_verifier.circom";
template ProofOfPassport(n, k) {
template ProofOfPassport(n, k, max_datahashes_bytes) {
signal input mrz[93]; // formatted mrz (5 + 88) chars
signal input dataHashes[297];
signal input dataHashes[max_datahashes_bytes];
signal input datahashes_padded_length;
signal input eContentBytes[104];
signal input pubkey[k];
signal input signature[k];
@@ -15,9 +16,10 @@ template ProofOfPassport(n, k) {
signal input address;
// Verify passport
component PV = PassportVerifier(n, k);
component PV = PassportVerifier(n, k, max_datahashes_bytes);
PV.mrz <== mrz;
PV.dataHashes <== dataHashes;
PV.datahashes_padded_length <== datahashes_padded_length;
PV.eContentBytes <== eContentBytes;
PV.pubkey <== pubkey;
PV.signature <== signature;
@@ -45,7 +47,7 @@ template ProofOfPassport(n, k) {
}
}
component main { public [ address ] } = ProofOfPassport(64, 32);
component main { public [ address ] } = ProofOfPassport(64, 32, 320);
// Us:
// 11 + 1 + 3 + 1

View File

@@ -11,7 +11,9 @@
"@types/node": "^20.6.3",
"@types/node-forge": "^1.3.5",
"@zk-email/circuits": "^3.2.2",
"@zk-email/helpers": "^3.1.3",
"chai-as-promised": "^7.1.1",
"circom_tester": "^0.0.20",
"circomlib": "^2.0.5",
"js-sha256": "^0.10.1",
"node-forge": "^1.3.1",

View File

@@ -1,5 +1,8 @@
#!/bin/bash
# Record the start time
START_TIME=$(date +%s)
# Check if the first argument is "app-only"
if [ "$1" == "app-only" ]; then
echo "Building only for the app"
@@ -39,4 +42,9 @@ yarn snarkjs zkey export verificationkey build/proof_of_passport_final.zkey buil
yarn snarkjs zkey export solidityverifier build/proof_of_passport_final.zkey build/Verifier.sol
cp build/Verifier.sol ../contracts/contracts/Verifier.sol
echo "copied Verifier.sol to contracts"
echo "copied Verifier.sol to contracts"
# Calculate and print the time taken by the whole script
END_TIME=$(date +%s)
ELAPSED_TIME=$(($END_TIME - $START_TIME))
echo "Build completed in $ELAPSED_TIME seconds"

View File

@@ -1,12 +1,14 @@
import { describe } from 'mocha'
import chai, { assert, expect } from 'chai'
import chaiAsPromised from 'chai-as-promised'
import { hash, toUnsignedByte, arraysAreEqual, bytesToBigDecimal, formatAndConcatenateDataHashes, formatMrz, splitToWords } from '../../common/src/utils/utils'
import { hash, toUnsignedByte, arraysAreEqual, bytesToBigDecimal, formatMrz, splitToWords } from '../../common/src/utils/utils'
import { groth16 } from 'snarkjs'
import { DataHash } from '../../common/src/utils/types'
import { getPassportData } from '../../common/src/utils/passportData'
import { attributeToPosition } from '../../common/src/constants/constants'
import { MAX_DATAHASHES_LEN, attributeToPosition } from '../../common/src/constants/constants'
import { sha256Pad } from '@zk-email/helpers'
import path from "path";
const fs = require('fs');
const wasm_tester = require("circom_tester").wasm;
chai.use(chaiAsPromised)
@@ -21,13 +23,9 @@ describe('Circuit tests', function () {
const passportData = getPassportData();
const formattedMrz = formatMrz(passportData.mrz);
const mrzHash = hash(formatMrz(passportData.mrz));
const concatenatedDataHashes = formatAndConcatenateDataHashes(
mrzHash,
passportData.dataGroupHashes as DataHash[],
);
const concatenatedDataHashesHashDigest = hash(concatenatedDataHashes);
const concatenatedDataHashesHashDigest = hash(passportData.dataGroupHashes);
console.log('concatenatedDataHashesHashDigest', concatenatedDataHashesHashDigest);
assert(
arraysAreEqual(passportData.eContent.slice(72, 72 + 32), concatenatedDataHashesHashDigest),
@@ -36,10 +34,16 @@ describe('Circuit tests', function () {
const reveal_bitmap = Array(88).fill('1');
const [messagePadded, messagePaddedLen] = sha256Pad(
new Uint8Array(passportData.dataGroupHashes),
MAX_DATAHASHES_LEN
);
inputs = {
mrz: formattedMrz.map(byte => String(byte)),
reveal_bitmap: reveal_bitmap.map(byte => String(byte)),
dataHashes: concatenatedDataHashes.map(toUnsignedByte).map(byte => String(byte)),
dataHashes: Array.from(messagePadded).map((x) => x.toString()),
datahashes_padded_length: messagePaddedLen.toString(),
eContentBytes: passportData.eContent.map(toUnsignedByte).map(byte => String(byte)),
pubkey: splitToWords(
BigInt(passportData.pubKey.modulus),
@@ -53,7 +57,8 @@ describe('Circuit tests', function () {
),
address: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", // sample address
}
console.log('inputs', inputs);
})
describe('Proof', function() {
@@ -210,6 +215,19 @@ describe('Circuit tests', function () {
})
// use these tests with .only to check changes without rebuilding the zkey
describe('Circom tester tests', function() {
it('should prove and verify with valid inputs', async function () {
const circuit = await wasm_tester(
path.join(__dirname, `../circuits/proof_of_passport.circom`),
{ include: ["node_modules"] },
);
const w = await circuit.calculateWitness(inputs);
await circuit.checkConstraints(w);
})
})
})

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@ export const attributeToPosition: { [key: string]: number[] } = {
expiry_date: [65, 70],
};
export const MAX_DATAHASHES_LEN = 320; // max formatted and concatenated datagroup hashes length in bytes
export const countryCodes = {
"AFG": "Afghanistan",

View File

@@ -1,4 +1,4 @@
import { DataHash, PassportData } from "./types";
import { PassportData } from "./types";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal } from "./utils";
import * as forge from 'node-forge';
const fs = require('fs');
@@ -38,7 +38,7 @@ export function genSampleData(): PassportData {
sampleDataHashes.unshift([1, mrzHash]);
const concatenatedDataHashes = formatAndConcatenateDataHashes(
mrzHash,
sampleDataHashes as DataHash[],
sampleDataHashes as [number, number[]][],
);
const eContent = assembleEContent(
hash(concatenatedDataHashes),
@@ -55,24 +55,16 @@ export function genSampleData(): PassportData {
const signature = privKey.sign(md)
const signatureBytes = Array.from(signature, (c: string) => c.charCodeAt(0));
// Signature verification
// const hashOfEContent = md.digest().getBytes();
// const publicKey = rsa.setPublicKey(
// new forge.jsbn.BigInteger(modulus, 16),
// new forge.jsbn.BigInteger("10001", 16),
// );
// const valid = publicKey.verify(hashOfEContent, signature);
// console.log('valid ?', valid)
return {
mrz: sampleMRZ,
signatureAlgorithm: 'SHA256withRSA', // sha256WithRSAEncryption
pubKey: {
modulus: hexToDecimal(modulus),
},
dataGroupHashes: sampleDataHashes as DataHash[],
dataGroupHashes: concatenatedDataHashes,
eContent: eContent,
encryptedDigest: signatureBytes,
photoBase64: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3" // meaningless for now
}
}

View File

@@ -1,6 +1,5 @@
import { PassportData } from "./types";
// export const samplePassportData = {
// "mrz":"P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02",
// "signatureAlgorithm":"SHA256withRSA",
@@ -10,10 +9,58 @@ import { PassportData } from "./types";
// "encryptedDigest":[35,76,28,227,212,141,111,134,230,196,96,116,211,137,66,36,193,89,118,85,247,107,239,228,229,86,134,71,247,88,48,232,173,172,80,223,44,146,97,248,103,82,33,114,87,80,255,13,24,129,48,30,162,233,32,107,108,229,199,248,215,187,5,72,112,185,114,80,178,117,203,63,6,231,104,72,89,158,77,232,82,147,35,57,119,151,60,235,210,216,86,76,164,16,203,111,60,20,0,100,174,175,95,8,150,248,65,207,55,251,206,141,26,30,49,218,160,56,92,45,212,121,61,231,174,175,171,234,83,17,225,249,52,208,223,8,234,208,152,168,146,187,0,80,25,235,145,196,157,113,38,65,71,214,143,36,82,212,45,0,242,120,73,54,24,115,24,157,188,79,59,60,202,74,129,47,245,202,141,15,135,7,34,18,56,24,85,173,125,205,71,127,103,236,77,176,100,35,59,179,123,84,158,84,195,113,98,202,218,2,1,170,194,243,245,174,205,102,28,118,156,57,106,37,244,45,174,157,202,217,38,179,126,94,205,74,100,64,225,183,145,157,148,213,45,228,170,122,190,239,11,135,24,239,17,252]
// } as PassportData // not working for some reason
export const samplePassportData = {
"mrz":"P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02",
"signatureAlgorithm":"SHA256withRSA",
"pubKey":{"modulus":"27753994424842443894245786782525308860959074811630074275687092737154570193632490725867032155150260554771168206321835563490551248035290893473617891334580992862631549002795628558031117970107680315966672387663922543753771000203286710765623272481585597066810453899915515725100524233057337421264922943787074825558632263475983266815680559554396939901695379704841007360145443136768496914184384265135937789216999239019764915126071941382094849289770921106079335274789472186657871647693785381678061690538186504807895527639676843719555029569743949997938238439702614424217784475162038335863063315103644827846898314629359021121163"},
"dataGroupHashes":[[1,[-80,-33,31,-123,108,84,-98,102,70,11,-91,-81,-60,12,-55,-126,25,-125,46,125,-100,-62,28,23,55,-123,-99,-92,-121,-120,-36,78]],[2,[-66,82,-76,-21,-34,33,79,50,-104,-120,-114,35,116,-32,6,-14,-100,-115,-128,-8,10,61,98,86,-8,45,-49,-46,90,-24,-81,38]],[3,[0,-62,104,108,-19,-10,97,-26,116,-58,69,110,26,87,17,89,110,-57,108,-6,36,21,39,87,110,102,-6,-43,-82,-125,-85,-82]],[11,[-120,-101,87,-112,111,15,-104,127,85,25,-102,81,20,58,51,75,-63,116,-22,0,60,30,29,30,-73,-115,72,-9,-1,-53,100,124]],[12,[41,-22,106,78,31,11,114,-119,-19,17,92,71,-122,47,62,78,-67,-23,-55,-42,53,4,47,-67,-55,-123,6,121,34,-125,64,-114]],[13,[91,-34,-46,-63,62,-34,104,82,36,41,-118,-3,70,15,-108,-48,-100,45,105,-85,-15,-61,-71,43,-39,-94,-110,-55,-34,89,-18,38]],[14,[76,123,-40,13,51,-29,72,-11,59,-63,-18,-90,103,49,23,-92,-85,-68,-62,-59,-100,-69,-7,28,-58,95,69,15,-74,56,54,38]]],
"eContent":[49,102,48,21,6,9,42,-122,72,-122,-9,13,1,9,3,49,8,6,6,103,-127,8,1,1,1,48,28,6,9,42,-122,72,-122,-9,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,-122,72,-122,-9,13,1,9,4,49,34,4,32,32,85,108,-82,127,112,-78,-74,8,43,-122,123,-64,-45,-125,66,-72,-16,-44,-75,-16,-76,106,-61,24,117,54,-127,19,10,-6,53],
"encryptedDigest":[75,38,146,115,39,182,117,54,54,210,123,175,120,2,192,161,4,95,215,96,181,238,178,2,228,31,135,28,151,187,17,28,127,71,108,224,207,180,75,237,108,85,103,115,141,94,95,117,167,89,69,182,24,100,154,168,188,176,221,182,102,174,113,187,207,82,146,21,124,207,87,239,148,209,129,187,247,245,50,37,208,152,209,204,42,219,163,63,138,79,73,229,179,58,208,232,48,43,203,122,160,37,19,213,231,179,165,204,124,143,157,198,110,230,138,9,115,93,85,94,12,120,44,206,93,27,52,240,142,103,10,199,221,189,229,43,157,129,187,187,248,12,219,186,145,147,226,177,111,180,87,107,27,222,110,92,246,176,123,17,201,118,4,217,246,248,15,22,255,75,42,101,189,203,22,253,197,91,227,187,206,2,106,14,154,222,145,202,15,106,237,158,254,79,244,234,118,5,245,212,45,45,217,170,144,93,44,129,190,180,33,13,123,120,145,100,157,198,178,177,197,93,2,62,2,49,197,23,198,150,249,19,118,239,22,211,116,205,101,141,250,21,19,229,26,201,241,226,109,249,221,9,20,242,21,250]
}
mrz: "P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02",
signatureAlgorithm: "SHA256withRSA",
pubKey: {
modulus:
"25765736223988998667840500778189949868451613342077606460859210922511052625759496119999327689569971597023682649195203990693368929496225818878431536656524613749134155885566243710074017849156387160630116071644605393154527561104329314133650925802529202493002281004186898817134780029845600308376449076243160628443612875871696451909631444284612538876146775788454905886375392424559872753930863026490112290338742311706592933371007008127621682785088607674884944461624900996663751897866140822800320086882377049066596330978938181261694513943840546157351331784368336520946815362357363027160374987439808774582633894814729403608773",
},
dataGroupHashes: [
48, -126, 1, 37, 2, 1, 0, 48, 11, 6, 9, 96, -122, 72, 1, 101, 3, 4, 2, 1,
48, -126, 1, 17, 48, 37, 2, 1, 1, 4, 32, -80, -33, 31, -123, 108, 84, -98,
102, 70, 11, -91, -81, -60, 12, -55, -126, 25, -125, 46, 125, -100, -62, 28,
23, 55, -123, -99, -92, -121, -120, -36, 78, 48, 37, 2, 1, 2, 4, 32, -66,
82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100,
-115, -128, -8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38, 48, 37,
2, 1, 3, 4, 32, 0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26,
87, 17, 89, 110, -57, 108, -6, 36, 21, 39, 87, 110, 102, -6, -43, -82, -125,
-85, -82, 48, 37, 2, 1, 11, 4, 32, -120, -101, 87, -112, 111, 15, -104, 127,
85, 25, -102, 81, 20, 58, 51, 75, -63, 116, -22, 0, 60, 30, 29, 30, -73,
-115, 72, -9, -1, -53, 100, 124, 48, 37, 2, 1, 12, 4, 32, 41, -22, 106, 78,
31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42,
53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114, 48, 37, 2, 1, 13, 4,
32, 91, -34, -46, -63, 62, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108,
-48, -100, 45, 105, -85, -15, -61, -71, 43, -39, -94, -110, -55, -34, 89,
-18, 38, 48, 37, 2, 1, 14, 4, 32, 76, 123, -40, 13, 51, -29, 72, -11, 59,
-63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58,
95, 69, 15, -74, 56, 54, 38,
],
eContent: [
49, 102, 48, 21, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 3, 49, 8, 6, 6,
103, -127, 8, 1, 1, 1, 48, 28, 6, 9, 42, -122, 72, -122, -9, 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, -122, 72, -122, -9, 13, 1, 9, 4, 49, 34, 4, 32, 32, 85, 108, -82,
127, 112, -78, -74, 8, 43, -122, 123, -64, -45, -125, 66, -72, -16, -44,
-75, -16, -76, 106, -61, 24, 117, 54, -127, 19, 10, -6, 53,
],
encryptedDigest: [
106, 37, 43, 211, 248, 15, 89, 233, 214, 213, 175, 251, 124, 21, 199, 184,
123, 40, 130, 167, 156, 177, 103, 237, 234, 71, 198, 47, 32, 189, 212, 157,
238, 88, 183, 46, 152, 216, 89, 160, 64, 159, 193, 189, 45, 222, 64, 23,
222, 28, 189, 2, 56, 82, 141, 104, 191, 65, 99, 38, 124, 95, 53, 149, 133,
202, 22, 203, 65, 44, 153, 208, 10, 62, 59, 5, 238, 60, 112, 118, 208, 114,
230, 203, 17, 118, 114, 78, 136, 244, 243, 219, 138, 251, 243, 28, 168, 217,
251, 147, 93, 114, 8, 3, 63, 79, 114, 14, 64, 173, 90, 233, 92, 91, 156,
167, 59, 68, 158, 136, 153, 38, 134, 128, 209, 231, 20, 16, 35, 241, 186,
186, 185, 40, 68, 250, 185, 36, 239, 195, 27, 234, 233, 38, 237, 167, 97,
107, 255, 187, 118, 247, 231, 233, 234, 56, 182, 181, 237, 210, 20, 185, 11,
0, 5, 158, 197, 141, 200, 70, 40, 70, 87, 92, 227, 63, 144, 229, 45, 136,
29, 239, 47, 193, 0, 184, 97, 161, 239, 105, 87, 124, 55, 54, 208, 68, 161,
152, 108, 4, 32, 255, 210, 159, 6, 10, 64, 96, 19, 183, 93, 149, 212, 178,
185, 135, 208, 62, 139, 42, 241, 210, 124, 164, 222, 172, 136, 16, 88, 99,
59, 100, 114, 123, 119, 86, 20, 190, 107, 152, 106, 244, 223, 112, 83, 110,
215, 104, 183, 109, 43, 19, 159, 165, 105, 25,
],
photoBase64:
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gIoSUNDX1BST0ZJTEUAAQEAAAIYAAAAAAIQAABtbnRyUkdCI",
};

View File

@@ -0,0 +1,53 @@
// Copied from zk-email cuz it uses crypto so can't import it here.
// Puts an end selector, a bunch of 0s, then the length, then fill the rest with 0s.
export function sha256Pad(prehash_prepad_m: Uint8Array, maxShaBytes: number): [Uint8Array, number] {
let length_bits = prehash_prepad_m.length * 8; // bytes to bits
let length_in_bytes = int64toBytes(length_bits);
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, int8toBytes(2 ** 7)); // Add the 1 on the end, length 505
// while ((prehash_prepad_m.length * 8 + length_in_bytes.length * 8) % 512 !== 0) {
while ((prehash_prepad_m.length * 8 + length_in_bytes.length * 8) % 512 !== 0) {
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, int8toBytes(0));
}
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, length_in_bytes);
assert((prehash_prepad_m.length * 8) % 512 === 0, "Padding did not complete properly!");
let messageLen = prehash_prepad_m.length;
while (prehash_prepad_m.length < maxShaBytes) {
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, int64toBytes(0));
}
assert(
prehash_prepad_m.length === maxShaBytes,
`Padding to max length did not complete properly! Your padded message is ${prehash_prepad_m.length} long but max is ${maxShaBytes}!`
);
return [prehash_prepad_m, messageLen];
}
// Works only on 32 bit sha text lengths
export function int64toBytes(num: number): Uint8Array {
let arr = new ArrayBuffer(8); // an Int32 takes 4 bytes
let view = new DataView(arr);
view.setInt32(4, num, false); // byteOffset = 0; litteEndian = false
return new Uint8Array(arr);
}
export function mergeUInt8Arrays(a1: Uint8Array, a2: Uint8Array): Uint8Array {
// sum of individual array lengths
var mergedArray = new Uint8Array(a1.length + a2.length);
mergedArray.set(a1);
mergedArray.set(a2, a1.length);
return mergedArray;
}
// Works only on 32 bit sha text lengths
export function int8toBytes(num: number): Uint8Array {
let arr = new ArrayBuffer(1); // an Int8 takes 4 bytes
let view = new DataView(arr);
view.setUint8(0, num); // byteOffset = 0; litteEndian = false
return new Uint8Array(arr);
}
export function assert(cond: boolean, errorMessage: string) {
if (!cond) {
throw new Error(errorMessage);
}
}

View File

@@ -1,10 +1,8 @@
export type DataHash = [number, number[]];
export type PassportData = {
mrz: string;
signatureAlgorithm: string;
pubKey: {modulus?: string, curveName?: string, publicKeyQ?: string};
dataGroupHashes: DataHash[] | number[];
dataGroupHashes: number[];
eContent: number[];
encryptedDigest: number[];
photoBase64: string;

View File

@@ -1,17 +1,5 @@
import { DataHash } from './types';
import {sha256} from 'js-sha256';
export function dataHashesObjToArray(dataHashes: {
[key: string]: number[];
}): DataHash[] {
return Object.keys(dataHashes)
.map(key => {
const dataHash = dataHashes[key as keyof typeof dataHashes];
return [Number(key), dataHash];
})
.sort((a, b) => (a[0] as number) - (b[0] as number)) as DataHash[];
}
export function formatMrz(mrz: string) {
const mrzCharcodes = [...mrz].map(char => char.charCodeAt(0));
@@ -49,7 +37,7 @@ export function parsePubKeyString(pubKeyString: string) {
export function formatAndConcatenateDataHashes(
mrzHash: number[],
dataHashes: DataHash[],
dataHashes: [number, number[]][],
) {
// Let's replace the first array with the MRZ hash
dataHashes.shift();
@@ -58,13 +46,19 @@ export function formatAndConcatenateDataHashes(
let concat: number[] = []
// Starting sequence. Should be the same for everybody, but not sure
concat.push(...[
const startingSequence = [
48, -126, 1, 37, 2, 1, 0, 48, 11, 6, 9, 96, -122, 72, 1, 101, 3, 4, 2, 1,
48, -126, 1, 17,
])
]
// console.log(`startingSequence`, startingSequence.map(byte => (byte < 0 ? byte + 256 : byte).toString(16).padStart(2, '0')).join(''));
// Starting sequence. Should be the same for everybody, but not sure
concat.push(...startingSequence)
for(const dataHash of dataHashes) {
// console.log(`dataHash ${dataHash[0]}`, dataHash[1].map(byte => (byte < 0 ? byte + 256 : byte).toString(16).padStart(2, '0')).join(''));
concat.push(...[48, 37, 2, 1, dataHash[0], 4, 32, ...dataHash[1]])
}

View File

@@ -37,62 +37,62 @@ contract Groth16Verifier {
uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
uint256 constant deltax1 = 13332829983292634874659240068294550011141456103652018916224391594481625590699;
uint256 constant deltax2 = 21775687996720864507552980920389387944496604814608793381435179673741251662482;
uint256 constant deltay1 = 15444510239488592734510692256596834816736560818857866493410444065736122722029;
uint256 constant deltay2 = 12213750345729207307537910743738626761327252153590563067440130819625419372191;
uint256 constant deltax1 = 16090324046277950763125527339669418696671049354395814480064931285811122806311;
uint256 constant deltax2 = 3388099228861510190666544830708887154365907975269339500324023869932463737360;
uint256 constant deltay1 = 7688431508550838758465114907962417900351853161896492863208774910610509616095;
uint256 constant deltay2 = 19762866886998123074420483823472417678987136556701471933476486373337630235866;
uint256 constant IC0x = 4897812530436581420070048815704719785256466787655503857610889333796081821201;
uint256 constant IC0y = 21324217308758963004039464033551222626995062428505595457846546072979649950535;
uint256 constant IC0x = 12358371560351339950261746817829615662864648250224246579760823479801160726966;
uint256 constant IC0y = 8941502525560997533107244888678697046415829976829277437144304248888506926598;
uint256 constant IC1x = 3402067829842345916430895428185245090645621522198317090797379965574771542636;
uint256 constant IC1y = 15689341079133962080137763365487039194375030636040098473539254350433970371666;
uint256 constant IC1x = 3392609077893666393818373788632729347394100296009683175444785824084696943023;
uint256 constant IC1y = 15778475214327229583146197018054931792117795500362679219822006631962765425084;
uint256 constant IC2x = 17395362500217368985868893090734905039167826866091632900857231867723495577602;
uint256 constant IC2y = 7930260148586132748363663695528567251481992615924576457603406418853534765181;
uint256 constant IC2x = 8099776627791518876029724839541619668524168243683543215181264127561560866378;
uint256 constant IC2y = 13957298841388220900071014236692228557278984690959800731798739560589103260217;
uint256 constant IC3x = 585494952178863414068208567603839798093905284375122061973360892129986520320;
uint256 constant IC3y = 9052106461455604192832593945466435172808609013430707922648579604917214395471;
uint256 constant IC3x = 6867144446394518543541509416020662846352658926638580312202993008656043735722;
uint256 constant IC3y = 20361100619082527644543330176105343018113961431298631122109940433281427191335;
uint256 constant IC4x = 7009544555987721721525965879762930953012066717281509356647068054408609863246;
uint256 constant IC4y = 9820829334259318510794834811753840115411696228971683399345859623869811549881;
uint256 constant IC4x = 7820262163570764148713607342549403510616534732388680563758448525457856266041;
uint256 constant IC4y = 17427646703250487254100654670394303917427848369600540774960876444848655648790;
uint256 constant IC5x = 14238418207024939545815829157744718461870627038741425938816007286311574134474;
uint256 constant IC5y = 281828200475697177916593309667507636329345262293367509851063337891478088781;
uint256 constant IC5x = 9329038096752685892195458886791344390985266132226910745197610004790817081243;
uint256 constant IC5y = 17633606162637893141834852474543311873554106055343324203721189043258518542986;
uint256 constant IC6x = 2588875801176981985506740691573068253787601389179711941209167172577223524972;
uint256 constant IC6y = 15518320710469760878810555468816349074382837865578096899468878146062509663814;
uint256 constant IC6x = 15214972039132546074990559591905856279100817712638264680172391278670552836943;
uint256 constant IC6y = 17793931839829884897490767708362461073405286327564854852321755412397701882051;
uint256 constant IC7x = 17316533695265131380437649603796400699657451230738779001098608159520582988369;
uint256 constant IC7y = 8192809588256960378913803069056080395056022087843425771582496472786713726350;
uint256 constant IC7x = 16432451118675554466944501175190419802495200895264935959505007091630391748307;
uint256 constant IC7y = 17005455758161268740259966336931374444292463497649856761950776907003856006158;
uint256 constant IC8x = 7407001681033909392094003743482787694603426004447721439357204522366208646546;
uint256 constant IC8y = 14678011064151490372018354732758508739891026527348606433971585164806457243690;
uint256 constant IC8x = 16566084605942179954484095659462642108428050412914361949529099255053163336577;
uint256 constant IC8y = 11348847474900901532074632045897840328394652876808508608277201509162617389226;
uint256 constant IC9x = 14324550585252189304511012915310919737099760521255841560510202883547241215550;
uint256 constant IC9y = 17843516173433864891394764190574725294294272661192260445890002683170043518436;
uint256 constant IC9x = 20432721442439987594811029579638507905558963238303258423962968887055079318014;
uint256 constant IC9y = 17630633329984044021525868813160201090283137867464472918574994399246772391534;
uint256 constant IC10x = 7539891259658208616633326740578026995822087197681333710337145994575633967330;
uint256 constant IC10y = 11252528180616460725708054390959401682257312545535188972038868508936671228701;
uint256 constant IC10x = 5699789224797518651982187895765852840229524263129270266806855312076243175369;
uint256 constant IC10y = 5575685047942777136027938128867511021185787087783710620156009601989720400423;
uint256 constant IC11x = 13300379642556942794398405666278194834327040509717856013516915921151482858342;
uint256 constant IC11y = 3765685546823952453740511654773017065896884149593650080085427606727523849353;
uint256 constant IC11x = 7474962396815226656505783226184398885932429996968198991602177469258624227676;
uint256 constant IC11y = 13295953383787032296147156727696765949284856824641801644998677571719156809710;
uint256 constant IC12x = 9268919849281685133024784239234560640021437913056581963083327429501365255031;
uint256 constant IC12y = 11222912618976361984001818562665888490194957370177999142904578411305511279126;
uint256 constant IC12x = 7125408302133541426096601033611287561635809191011183803473287615455611004055;
uint256 constant IC12y = 2993824677580561931899725088290448751828842746446863028131844542431810217534;
uint256 constant IC13x = 2597478889552428352737130179687206531821645186216868965539289093449836402726;
uint256 constant IC13y = 757968852987628828382971340903318389342984851650872494795704692702408158904;
uint256 constant IC13x = 13104153687587252960029187345356816832922284531311953051216743085545221973160;
uint256 constant IC13y = 7405322578735061472878628039827056816271101505201175316717177556683750653196;
uint256 constant IC14x = 16147563600769233454259564579865458680953713847620754688678964339139397943562;
uint256 constant IC14y = 3229058257062194976564868360849873757615447419031013710509312378420932332089;
uint256 constant IC14x = 9070340003155622806917979397122180030817945108774043344801622013416220642839;
uint256 constant IC14y = 6448142239834215464348644080211718417532770711627875088279288533854718074854;
uint256 constant IC15x = 11276405747528923910383092138862864843497716277810279291090775583122182049041;
uint256 constant IC15y = 17478497004985764197329627914040721906294759410027200889688899456335265284727;
uint256 constant IC15x = 19115296167742895190557430003566978073320550923055046533289349069129250085692;
uint256 constant IC15y = 14023194747126190791090505626051096268998429680184461960003071238543625728369;
uint256 constant IC16x = 7537276704716430448981792598508402432998887447285614055846784939499149706536;
uint256 constant IC16y = 13397681836333574838145763582606233729786782316119672353292568940401561429759;
uint256 constant IC16x = 3205179961068657974791317429435230052576637598837700853958154288779815988964;
uint256 constant IC16y = 13962036792812653197816813268344534136187601501933782827315669353329176964877;
// Memory data

View File

@@ -1,14 +1,14 @@
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { expect, assert } from "chai";
import { ethers } from "hardhat";
import { DataHash } from "../../common/src/utils/types";
import { getPassportData } from "../../common/src/utils/passportData";
import { attributeToPosition } from "../../common/src/constants/constants";
import { MAX_DATAHASHES_LEN, attributeToPosition } from "../../common/src/constants/constants";
import { formatMrz, splitToWords, formatAndConcatenateDataHashes, toUnsignedByte, hash, bytesToBigDecimal } from "../../common/src/utils/utils";
import { groth16 } from 'snarkjs'
import { countryCodes } from "../../common/src/constants/constants";
import { time } from "@nomicfoundation/hardhat-toolbox/network-helpers";
import axios from 'axios';
import { sha256Pad } from "../../common/src/utils/sha256Pad";
const fs = require('fs');
describe("Proof of Passport", function () {
@@ -18,13 +18,8 @@ describe("Proof of Passport", function () {
before(async function generateProof() {
passportData = getPassportData();
const formattedMrz = formatMrz(passportData.mrz);
const mrzHash = hash(formatMrz(passportData.mrz));
const concatenatedDataHashes = formatAndConcatenateDataHashes(
mrzHash,
passportData.dataGroupHashes as DataHash[],
);
const attributeToReveal = {
issuing_state: true,
@@ -36,19 +31,25 @@ describe("Proof of Passport", function () {
expiry_date: true,
}
const bitmap = Array(88).fill('0');
const reveal_bitmap = Array(88).fill('0');
Object.entries(attributeToReveal).forEach(([attribute, reveal]) => {
if (reveal) {
const [start, end] = attributeToPosition[attribute as keyof typeof attributeToPosition];
bitmap.fill('1', start, end + 1);
reveal_bitmap.fill('1', start, end + 1);
}
});
const [messagePadded, messagePaddedLen] = sha256Pad(
new Uint8Array(passportData.dataGroupHashes),
MAX_DATAHASHES_LEN
);
inputs = {
mrz: formattedMrz.map(byte => String(byte)),
reveal_bitmap: bitmap.map(byte => String(byte)),
dataHashes: concatenatedDataHashes.map(toUnsignedByte).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(),
eContentBytes: passportData.eContent.map(toUnsignedByte).map(byte => String(byte)),
pubkey: splitToWords(
BigInt(passportData.pubKey.modulus as string),
@@ -226,7 +227,7 @@ describe("Proof of Passport", function () {
describe("Minting on mumbai", function () {
it.skip("Should allow minting using a proof generated by ark-circom", async function () {
const newCallDataFromArkCircom = [["0x089e5850e432d76f949cedc26527a7fb093194dd4026d5efb07c8ce6093fa977", "0x0154b01b5698e6249638be776d3641392cf89a5ad687beb2932c0ccf33f271d4"], [["0x2692dbce207361b048e6eff874fdc5d50433baa546fa754348a87373710044c0", "0x1db8ddab0dc204d41728efc05d2dae690bebb782b6088d92dda23a87b6bed0a2"], ["0x106be642690f0fe3562d139ed09498d979c8b35ecfb04e5a49422015cafa2705", "0x0b133e53cd0b4944ce2d34652488a16d1a020905dc1972ccc883d364dd3bb4ee"]], ["0x09eda5d551b150364ecb3efb432e4568b2be8f83c2db1dd1e1285c45a428b32b", "0x008ee9e870e5416849b3c94b8b9e4759580659f5a6535652d0a6634df23db2f5"], ["0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x000000000000000000000000000000006df9dd0914f215fafa1513e51ac9f1e2", "0x00000000000000000000000000000000000000000000093e703cd030e286890e", "0x0000000000000000000000000000000000000000000004770a914f3ae4e1288b", "0x000000000000000000000000000000000000000000000bf7e8ecb4e9609a489d", "0x00000000000000000000000000000000000000000000035762de41038bc2dcf1", "0x00000000000000000000000000000000000000000000050442c4055d62e9c4af", "0x0000000000000000000000000000000000000000000004db2bdc79a477a0fce0", "0x000000000000000000000000000000000000000000000acdbf649c76ec3df9ad", "0x000000000000000000000000000000000000000000000aaa0e6798ee3694f5ca", "0x000000000000000000000000000000000000000000000a1eaac37f80dd5e2879", "0x00000000000000000000000000000000000000000000033e063fba83c27efbce", "0x00000000000000000000000000000000000000000000045b9b05cab95025b000", "0x000000000000000000000000e6e4b6a802f2e0aee5676f6010e0af5c9cdd0a50"]];
const newCallDataFromArkCircom = [["0x1b705a58553cffb9bc3a8db59a697b2fe74b8f2543656a3dbfe445697ae8ba8e", "0x1ce8c0f6a50a82184b0f1ca42136a20ba8cc97b57fdcdd2c6b229ca42137390b"], [["0x1702629fd4c1dedc03f91cf86dce3247c4f865829a031513123becf8f2bcd6f7", "0x1511f6385ddd0fcdda2469aa365de2ed6317c2a86ae2de0a41675ccd7ce716e9"], ["0x05ac0906dd573bc5aa47878267c2297792a93ae07d5970c30504e86f24c876af", "0x29efb34eb0e176460a8c5797660093abe95d005e90d6dae1d1b3e4d15c54ad3e"]], ["0x24bc6bb9a9eba6bcf0790e91c027be7c123b8896efcc82aa8e161fb14c8a7eb8", "0x06f667003028a257bf19fb38ae1124f53e0ac9a9736af469611d770e6c684f11"], ["0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x00000000000000000000000000000000f8b23bcf3ecb363ff9b3333b34c2dcb4", "0x00000000000000000000000000000000000000000000016d536c78e55b684d93", "0x000000000000000000000000000000000000000000000518776d3dc80018d102", "0x0000000000000000000000000000000000000000000002e4fbc5d4e68d6c9bf7", "0x0000000000000000000000000000000000000000000003873a30e9d962126f82", "0x000000000000000000000000000000000000000000000388a0d69ac0f1995668", "0x000000000000000000000000000000000000000000000c3cbf461924e4e645ef", "0x000000000000000000000000000000000000000000000a59ec146b8f392105e8", "0x0000000000000000000000000000000000000000000000742acc4c0c6e9b1b20", "0x0000000000000000000000000000000000000000000006f010a5ce0929d0b84b", "0x0000000000000000000000000000000000000000000002cfd0895be937a6ccb7", "0x0000000000000000000000000000000000000000000005a1d397686d1b4ad000", "0x000000000000000000000000e6e4b6a802f2e0aee5676f6010e0af5c9cdd0a50"]];
// const callDataFromArkCircomGeneratedInTest = [ [ '0x07a378ec2b5bafc15a21fb9c549ba2554a4ef22cfca3d835f44d270f547d0913', '0x089bb81fb68200ef64652ada5edf71a98dcc8a931a54162b03b61647acbae1fe' ], [ [ '0x2127ae75494aed0c384567cc890639d7609040373d0a549e665a26a39b264449', '0x2f0ea6c99648171b7e166086108131c9402f9c5ac4a3759705a9c9217852e328' ], [ '0x04efcb825be258573ffe8c9149dd2b040ea3b8a9fa3dfa1c57a87b11c20c21ec', '0x2b500aece0e5a5a64a5c7262ec379efc1a23f4e46d968aebd42337642ea2bd3e' ] ], [ '0x1964dc2231bcd1e0de363c3d2a790346b7e634b5878498ce6e8db0ac972b8125', '0x0d94cd74a89b0ed777bb309ce960191acd23d5e9c5f418722d03f80944c5e3ed' ], [ '0x000000000000000000544e45524f4c4600000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000000', '0x000000000000000000000000000000000df267467de87516584863641a75504b', '0x00000000000000000000000000000000000000000000084c754a8650038f4c82', '0x000000000000000000000000000000000000000000000d38447935bb72a5193c', '0x000000000000000000000000000000000000000000000cac133b01f78ab24970', '0x0000000000000000000000000000000000000000000006064295cda88310ce6e', '0x000000000000000000000000000000000000000000001026cd8776cbd52df4b0', '0x000000000000000000000000000000000000000000000d4748d254334ce92b36', '0x0000000000000000000000000000000000000000000005c1b0ba7159834b0bf1', '0x00000000000000000000000000000000000000000000029d91f03395b916792a', '0x000000000000000000000000000000000000000000000bcfbb30f8ea70a224df', '0x00000000000000000000000000000000000000000000003dcd943c93e565aa3e', '0x0000000000000000000000000000000000000000000009e8ce7916ab0fb0b000', '0x000000000000000000000000ede0fa5a7b196f512204f286666e5ec03e1005d2' ] ];
const proofOfPassportOnMumbaiAddress = '0x7D459347d092D35f043f73021f06c19f834f8c3E';