import React, {useEffect, useState} from 'react'; import { SafeAreaView, ScrollView, StatusBar, StyleSheet, Text, useColorScheme, View, Button, NativeModules, DeviceEventEmitter, TextInput, ActivityIndicator, } from 'react-native'; import { Colors, DebugInstructions, Header, LearnMoreLinks, ReloadInstructions, } from 'react-native/Libraries/NewAppScreen'; // @ts-ignore import PassportReader from 'react-native-passport-reader'; import {checkInputs, getFirstName} from './utils/checks'; import { DEFAULT_PNUMBER, DEFAULT_DOB, DEFAULT_DOE, DEFAULT_ADDRESS, LOCAL_IP, } from '@env'; import {DataHash, PassportData} from './types/passportData'; import {arraysAreEqual, bytesToBigDecimal, dataHashesObjToArray, formatAndConcatenateDataHashes, formatMrz, splitToWords} from './utils/utils'; import {hash, toUnsignedByte} from './utils/computeEContent'; console.log('DEFAULT_PNUMBER', DEFAULT_PNUMBER); const CACHE_DATA_IN_LOCAL_SERVER = true; const SKIP_SCAN = true; function App(): JSX.Element { const isDarkMode = useColorScheme() === 'dark'; const [passportNumber, setPassportNumber] = useState(DEFAULT_PNUMBER ?? ''); const [dateOfBirth, setDateOfBirth] = useState(DEFAULT_DOB ?? ''); const [dateOfExpiry, setDateOfExpiry] = useState(DEFAULT_DOE ?? ''); const [address, setAddress] = useState(DEFAULT_ADDRESS ?? ''); const [passportData, setPassportData] = useState(null); const [step, setStep] = useState('enterDetails'); const [result, setResult] = useState(''); const [proofResult, setProofResult] = useState(''); const backgroundStyle = { backgroundColor: isDarkMode ? Colors.darker : Colors.lighter, }; useEffect(() => { const logEventListener = DeviceEventEmitter.addListener('LOG_EVENT', e => { console.log(e); }); return () => { logEventListener.remove(); }; }, []); if (SKIP_SCAN && passportData === null) { console.log('skipping scan step...'); try { fetch(`${LOCAL_IP}/passportData`) .then(response => response.json()) .then(data => { console.log('passport data fetched'); setPassportData(data); setStep('scanCompleted'); }); } catch(e) { console.log('error fetching passport data', e); } } async function handleResponse(response: any) { const { mrz, modulus, dataGroupHashes, eContent, encryptedDigest, } = response; const passportData: PassportData = { mrz: mrz.replace(/\n/g, ''), modulus: modulus, dataGroupHashes: dataHashesObjToArray(JSON.parse(dataGroupHashes)), eContent: JSON.parse(eContent), encryptedDigest: JSON.parse(encryptedDigest), }; console.log('mrz', passportData.mrz); console.log('modulus', passportData.modulus); console.log('dataGroupHashes', passportData.dataGroupHashes); console.log('eContent', passportData.eContent); console.log('encryptedDigest', passportData.encryptedDigest); setPassportData(passportData); if (CACHE_DATA_IN_LOCAL_SERVER) { // Caches data in local server to avoid having to scan the passport each time // For development purposes only fetch(`${LOCAL_IP}/post`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(passportData), }) .then(response => response.json()) .then(data => console.log(data.message)) .catch(error => { console.log('error caching data in local server', error); }); } setStep('scanCompleted'); } async function scan() { checkInputs(passportNumber, dateOfBirth, dateOfExpiry); // 1. start a scan // 2. press the back of your android phone against the passport // 3. wait for the scan(...) Promise to get resolved/rejected console.log('scanning...'); setStep('scanning'); try { const response = await PassportReader.scan({ documentNumber: passportNumber, dateOfBirth: dateOfBirth, dateOfExpiry: dateOfExpiry, }); console.log('response', response); console.log('scanned'); handleResponse(response); } catch (e) { console.log('error :', e); } } const handleProve = async () => { if (passportData === null) { console.log('passport data is null'); return; } // 1. TODO check signature to make sure the proof will work // 2. Format all the data as inputs for the circuit const formattedMrz = formatMrz(passportData.mrz); const mrzHash = hash(formatMrz(passportData.mrz)); const concatenatedDataHashes = formatAndConcatenateDataHashes( mrzHash, passportData.dataGroupHashes as DataHash[], ); const reveal_bitmap = Array.from({ length: 88 }, (_, i) => (i >= 16 && i <= 22) ? '1' : '0'); const inputs = { mrz: Array.from(formattedMrz).map(byte => String(byte)), reveal_bitmap: Array.from(reveal_bitmap).map(byte => String(byte)), dataHashes: Array.from(concatenatedDataHashes.map(toUnsignedByte)).map(byte => String(byte)), eContentBytes: Array.from(passportData.eContent.map(toUnsignedByte)).map(byte => String(byte)), signature: splitToWords( BigInt(bytesToBigDecimal(passportData.encryptedDigest)), BigInt(64), BigInt(32) ), pubkey: splitToWords( BigInt(passportData.modulus), BigInt(64), BigInt(32) ), address, } // 3. Generate a proof of passport const start = Date.now(); NativeModules.RNPassportReader.provePassport(inputs, (err: any, res: any) => { const end = Date.now(); if (err) { console.error(err); setProofResult( "res:" + err.toString() + ' time elapsed: ' + (end - start) + 'ms', ); } else { console.log(res); setProofResult( "res:" + res.toString() + ' time elapsed: ' + (end - start) + 'ms', ); } }); }; const handleMint = () => { // 5. Format the proof and publicInputs as calldata for the verifier contract // 6. Call the verifier contract with the calldata }; const callRustLib = async () => { NativeModules.RNPassportReader.callRustLib((err: any, res: any) => { if (err) { console.error(err); setResult(err.toString()); } else { console.log(res); // Should log "5" setResult(res.toString()); } }); }; const proveRust = async () => { const start = Date.now(); NativeModules.RNPassportReader.proveRust((err: any, res: any) => { const end = Date.now(); if (err) { console.error(err); setProofResult( "res:" + err.toString() + ' time elapsed: ' + (end - start) + 'ms', ); } else { console.log(res); setProofResult( "res:" + res.toString() + ' time elapsed: ' + (end - start) + 'ms', ); } }); }; const handleNative = async () => { const value = await NativeModules.PassportReader.scanPassport('', '', ''); console.log(`native tells us ${value}`); }; return ( {step === 'enterDetails' ? ( Enter Your Passport Details