Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"install-app": "yarn install-app:setup && yarn clean:xcode-env-local",
"install-app:mobile-deploy": "yarn install && yarn build:deps && yarn clean:xcode-env-local",
"install-app:setup": "yarn install && yarn build:deps && yarn setup:android-deps && cd ios && bundle install && scripts/pod-install-with-cache-fix.sh && cd ..",
"ios": "yarn build:deps && react-native run-ios --scheme OpenPassport",
"ios": "yarn build:deps && node scripts/run-ios-simulator.cjs",
"ios:fastlane-debug": "yarn reinstall && bundle exec fastlane --verbose ios internal_test",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
Expand Down
52 changes: 52 additions & 0 deletions app/scripts/run-ios-simulator.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.

const { execSync } = require('child_process');

try {
// Get list of available simulators
const output = execSync('xcrun simctl list devices available --json', {
encoding: 'utf8',
});

const devices = JSON.parse(output).devices;

// Find first available iPhone simulator (prefer latest iOS version)
let firstSimulator = null;

// Get iOS runtime keys sorted in reverse (latest first)
const runtimeKeys = Object.keys(devices)
.filter(key => key.includes('iOS'))
.sort()
.reverse();

for (const runtime of runtimeKeys) {
const iPhones = devices[runtime].filter(
device => device.name.startsWith('iPhone') && device.isAvailable,
);

if (iPhones.length > 0) {
firstSimulator = iPhones[0].name;
break;
}
}

if (!firstSimulator) {
console.error('No available iPhone simulators found');
process.exit(1);
}

console.log(`Using simulator: ${firstSimulator}`);

// Run the iOS build with the selected simulator
execSync(
`react-native run-ios --scheme OpenPassport --simulator="${firstSimulator}"`,
{
stdio: 'inherit',
},
);
} catch (error) {
console.error('Failed to run iOS simulator:', error.message);
process.exit(1);
}
3 changes: 1 addition & 2 deletions app/src/screens/prove/ProofRequestStatusScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ const SuccessScreen: React.FC = () => {
}
} catch {
console.warn(
'Invalid deep link URL provided:',
selfApp.deeplinkCallback,
'Invalid deep link URL provided (URL sanitized for security)',
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/version.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"ios": {
"build": 175,
"build": 176,
"lastDeployed": "2025-09-30T16:35:10Z"
},
"android": {
Expand Down
10 changes: 6 additions & 4 deletions common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ export type {
UserIdType,
} from './src/utils/index.js';

// Additional type exports
export type { Environment } from './src/utils/types.js';

// Constants exports
export type { Country3LetterCode } from './src/constants/index.js';


// Additional type exports
export type { Environment } from './src/utils/types.js';

// Utils exports
export {
API_URL,
Expand Down Expand Up @@ -73,19 +75,19 @@ export {
genAndInitMockPassportData,
genMockIdDoc,
genMockIdDocAndInitDataParsing,
fetchOfacTrees,
generateCircuitInputsDSC,
generateCircuitInputsRegister,
generateCircuitInputsRegisterForTests,
generateCircuitInputsVCandDisclose,
generateCommitment,
generateMockDSC,
generateNullifier,
generateTEEInputsDiscloseStateless,
getCircuitNameFromPassportData,
getLeafCscaTree,
getLeafDscTree,
fetchOfacTrees,
getSKIPEM,
generateTEEInputsDiscloseStateless,
getSolidityPackedUserContextData,
getUniversalLink,
hashEndpointWithScope,
Expand Down
4 changes: 2 additions & 2 deletions common/src/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,15 @@ export const MAX_PADDED_ECONTENT_LEN: Partial<Record<(typeof hashAlgos)[number],
sha512: 896,
};

export const MAX_PADDED_SIGNED_ATTR_LEN_FOR_TESTS: Record<(typeof hashAlgos)[number], number> = {
export const MAX_PADDED_SIGNED_ATTR_LEN: Record<(typeof hashAlgos)[number], number> = {
sha1: 128,
sha224: 128,
sha256: 256,
sha384: 256,
sha512: 256,
};

export const MAX_PADDED_SIGNED_ATTR_LEN: Record<(typeof hashAlgos)[number], number> = {
export const MAX_PADDED_SIGNED_ATTR_LEN_FOR_TESTS: Record<(typeof hashAlgos)[number], number> = {
sha1: 128,
sha224: 128,
sha256: 256,
Expand Down
7 changes: 6 additions & 1 deletion common/src/polyfills/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ function createHmac(algorithm: string, key: string | Uint8Array) {
throw new Error(`Unsupported HMAC algorithm: ${algorithm}`);
}

const keyBytes = typeof key === 'string' ? new TextEncoder().encode(key) : key;
const keyBytes =
typeof key === 'string'
? new TextEncoder().encode(key)
: ArrayBuffer.isView(key) && !(key instanceof Uint8Array && key.constructor === Uint8Array)
? new Uint8Array(key.buffer, key.byteOffset, key.byteLength)
: key;
const hmacState = hmac.create(hashFn, keyBytes);
let finalized = false;

Expand Down
108 changes: 56 additions & 52 deletions common/src/utils/aadhaar/mockData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,20 @@ function computeUppercasePaddedName(name: string): number[] {
.map((char) => char.charCodeAt(0));
}

export function convertByteArrayToBigInt(byteArray: Uint8Array | number[]): bigint {
let result = 0n;
for (let i = 0; i < byteArray.length; i++) {
result = result * 256n + BigInt(byteArray[i]);
}
return result;

// Helper function to compute final commitment
export function computeCommitment(
secret: bigint,
qrHash: bigint,
nullifier: bigint,
packedCommitment: bigint,
photoHash: bigint
): bigint {
return poseidon5([secret, qrHash, nullifier, packedCommitment, photoHash]);
}



// Helper function to compute packed commitment
export function computePackedCommitment(
extractedFields: ReturnType<typeof extractQRDataFields>
Expand All @@ -71,15 +77,13 @@ export function computePackedCommitment(
return BigInt(packBytesAndPoseidon(packedCommitmentArgs));
}

// Helper function to compute final commitment
export function computeCommitment(
secret: bigint,
qrHash: bigint,
nullifier: bigint,
packedCommitment: bigint,
photoHash: bigint
): bigint {
return poseidon5([secret, qrHash, nullifier, packedCommitment, photoHash]);

export function convertByteArrayToBigInt(byteArray: Uint8Array | number[]): bigint {
let result = 0n;
for (let i = 0; i < byteArray.length; i++) {
result = result * 256n + BigInt(byteArray[i]);
}
return result;
}

interface SharedQRData {
Expand Down Expand Up @@ -108,43 +112,6 @@ export function nullifierHash(extractedFields: ReturnType<typeof extractQRDataFi
return BigInt(packBytesAndPoseidon(personalInfoHashArgs));
}

export function processQRDataSimple(qrData: string) {
const qrDataBytes = convertBigIntToByteArray(BigInt(qrData));
const decodedData = decompressByteArray(qrDataBytes);
const signedData = decodedData.slice(0, decodedData.length - 256);
const [qrDataPaddedNumber, qrDataPaddedLen] = shaPad(signedData, 512 * 3);
const qrDataPadded = new Uint8Array(qrDataPaddedNumber);
let photoEOI = 0;
for (let i = 0; i < qrDataPadded.length - 1; i++) {
if (qrDataPadded[i + 1] === 217 && qrDataPadded[i] === 255) {
photoEOI = i + 1;
}
}
if (photoEOI === 0) {
throw new Error('Photo EOI not found');
}

// Extract actual fields from QR data instead of using hardcoded values
const extractedFields = extractQRDataFields(qrDataBytes);

const qrHash = packBytesAndPoseidon(Array.from(qrDataPadded));
const photo = extractPhoto(Array.from(qrDataPadded), photoEOI + 1);

const photoHash = packBytesAndPoseidon(photo.bytes.map(Number));

return {
qrDataBytes,
decodedData,
signedData,
qrDataPadded,
qrDataPaddedLen,
extractedFields,
qrHash: BigInt(qrHash),
photo,
photoHash: BigInt(photoHash),
};
}

export function prepareAadhaarDiscloseData(
qrData: string,
identityTree: LeanIMT,
Expand Down Expand Up @@ -593,3 +560,40 @@ export function processQRData(

return processQRDataSimple(QRData);
}

export function processQRDataSimple(qrData: string) {
const qrDataBytes = convertBigIntToByteArray(BigInt(qrData));
const decodedData = decompressByteArray(qrDataBytes);
const signedData = decodedData.slice(0, decodedData.length - 256);
const [qrDataPaddedNumber, qrDataPaddedLen] = shaPad(signedData, 512 * 3);
const qrDataPadded = new Uint8Array(qrDataPaddedNumber);
let photoEOI = 0;
for (let i = 0; i < qrDataPadded.length - 1; i++) {
if (qrDataPadded[i + 1] === 217 && qrDataPadded[i] === 255) {
photoEOI = i + 1;
}
}
if (photoEOI === 0) {
throw new Error('Photo EOI not found');
}

// Extract actual fields from QR data instead of using hardcoded values
const extractedFields = extractQRDataFields(qrDataBytes);

const qrHash = packBytesAndPoseidon(Array.from(qrDataPadded));
const photo = extractPhoto(Array.from(qrDataPadded), photoEOI + 1);

const photoHash = packBytesAndPoseidon(photo.bytes.map(Number));

return {
qrDataBytes,
decodedData,
signedData,
qrDataPadded,
qrDataPaddedLen,
extractedFields,
qrHash: BigInt(qrHash),
photo,
photoHash: BigInt(photoHash),
};
}
8 changes: 4 additions & 4 deletions common/src/utils/circuits/generateInputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export function generateCircuitInputsOfac(
};
}

export function generateCircuitInputsRegisterForTests(
export function generateCircuitInputsRegister(
secret: string,
passportData: PassportData,
serializedDscTree: string
Expand Down Expand Up @@ -230,7 +230,7 @@ export function generateCircuitInputsRegisterForTests(
);
const [signedAttrPadded, signedAttrPaddedLen] = pad(passportMetadata.signedAttrHashFunction)(
signedAttr,
MAX_PADDED_SIGNED_ATTR_LEN_FOR_TESTS[passportMetadata.eContentHashFunction]
MAX_PADDED_SIGNED_ATTR_LEN[passportMetadata.eContentHashFunction]
);

const dsc_leaf = getLeafDscTree(dscParsed, passportData.csca_parsed); // TODO: WRONG
Expand Down Expand Up @@ -273,7 +273,7 @@ export function generateCircuitInputsRegisterForTests(
.reduce((acc, curr) => ({ ...acc, ...curr }), {});
}

export function generateCircuitInputsRegister(
export function generateCircuitInputsRegisterForTests(
secret: string,
passportData: PassportData,
serializedDscTree: string
Expand Down Expand Up @@ -302,7 +302,7 @@ export function generateCircuitInputsRegister(
);
const [signedAttrPadded, signedAttrPaddedLen] = pad(passportMetadata.signedAttrHashFunction)(
signedAttr,
MAX_PADDED_SIGNED_ATTR_LEN[passportMetadata.eContentHashFunction]
MAX_PADDED_SIGNED_ATTR_LEN_FOR_TESTS[passportMetadata.eContentHashFunction]
);

const dsc_leaf = getLeafDscTree(dscParsed, passportData.csca_parsed); // TODO: WRONG
Expand Down
2 changes: 1 addition & 1 deletion common/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ export {
getWSDbRelayerUrl,
} from './proving.js';
export { extractQRDataFields, getAadharRegistrationWindow } from './aadhaar/utils.js';
export { formatMrz } from './passports/format.js';
export { fetchOfacTrees } from './ofac.js';
export { formatMrz } from './passports/format.js';
export { genAndInitMockPassportData } from './passports/genMockPassportData.js';
export {
genMockIdDoc,
Expand Down
8 changes: 4 additions & 4 deletions common/src/utils/passports/genMockIdDoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import forge from 'node-forge';
import type { hashAlgosTypes } from '../../constants/constants.js';
import { API_URL_STAGING } from '../../constants/constants.js';
import { countries } from '../../constants/countries.js';
import {
AADHAAR_MOCK_PRIVATE_KEY_PEM,
AADHAAR_MOCK_PUBLIC_KEY_PEM,
} from '../../mock_certificates/aadhaar/mockAadhaarCert.js';
import { convertByteArrayToBigInt, processQRData } from '../aadhaar/mockData.js';
import { extractQRDataFields } from '../aadhaar/utils.js';
import { getCurveForElliptic } from '../certificate_parsing/curves.js';
Expand All @@ -21,10 +25,6 @@ import { genDG1 } from './dg1.js';
import { formatAndConcatenateDataHashes, formatMrz, generateSignedAttr } from './format.js';
import { getMockDSC } from './getMockDSC.js';
import { initPassportDataParsing } from './passport.js';
import {
AADHAAR_MOCK_PRIVATE_KEY_PEM,
AADHAAR_MOCK_PUBLIC_KEY_PEM,
} from '../../mock_certificates/aadhaar/mockAadhaarCert.js';

export interface IdDocInput {
idType: 'mock_passport' | 'mock_id_card' | 'mock_aadhaar';
Expand Down
1 change: 1 addition & 0 deletions common/tests/cryptoHash.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.

import { createHash } from '../src/polyfills/crypto';

import { sha256 } from '@noble/hashes/sha256';

describe('Hash Finalization', () => {
Expand Down
1 change: 1 addition & 0 deletions common/tests/cryptoHmac.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.

import { createHmac } from '../src/polyfills/crypto';

import { hmac } from '@noble/hashes/hmac';
import { sha256 } from '@noble/hashes/sha256';

Expand Down
Loading
Loading