mirror of
https://github.com/selfxyz/self.git
synced 2026-01-09 06:38:09 -05:00
Bringing openpassport/main (#19)
Co-authored-by: seshanthS <seshanth@protonmail.com> Co-authored-by: turnoffthiscomputer <colin.remi07@gmail.com> Co-authored-by: thomas-senechal <thomas.senechal@pm.me> Co-authored-by: motemotech <i.am.nicoshark@gmail.com> Co-authored-by: turnoffthiscomputer <98749896+remicolin@users.noreply.github.com> Co-authored-by: ayman <aymanshaik1015@gmail.com>
This commit is contained in:
2
.github/workflows/action.yml
vendored
2
.github/workflows/action.yml
vendored
@@ -62,7 +62,7 @@ jobs:
|
||||
- name: Run Tests (Circuits)
|
||||
working-directory: ./circuits
|
||||
env:
|
||||
FULL_TEST_SUITE: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/openpassportv2' }}
|
||||
FULL_TEST_SUITE: false
|
||||
run: yarn test
|
||||
|
||||
- name: Run Tests (Common)
|
||||
|
||||
69
app/App.tsx
69
app/App.tsx
@@ -1,8 +1,13 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import 'react-native-get-random-values';
|
||||
|
||||
import * as amplitude from '@amplitude/analytics-react-native';
|
||||
import { AMPLITUDE_KEY } from '@env';
|
||||
import { SEGMENT_KEY } from '@env';
|
||||
import {
|
||||
EventPlugin,
|
||||
PluginType,
|
||||
SegmentEvent,
|
||||
createClient,
|
||||
} from '@segment/analytics-react-native';
|
||||
import '@ethersproject/shims';
|
||||
import { Buffer } from 'buffer';
|
||||
import { YStack } from 'tamagui';
|
||||
@@ -15,6 +20,57 @@ import { setupUniversalLinkListener } from './src/utils/qrCode';
|
||||
|
||||
global.Buffer = Buffer;
|
||||
|
||||
// Adjust the import path as needed
|
||||
|
||||
export class DisableTrackingPlugin extends EventPlugin {
|
||||
type = PluginType.before;
|
||||
|
||||
execute(event: SegmentEvent): SegmentEvent {
|
||||
// Ensure context exists
|
||||
if (!event.context) {
|
||||
event.context = {};
|
||||
}
|
||||
|
||||
// Ensure device context exists
|
||||
if (!event.context.device) {
|
||||
event.context.device = {};
|
||||
}
|
||||
|
||||
// Force tracking related fields to be disabled
|
||||
event.context.device.adTrackingEnabled = false;
|
||||
event.context.device.advertisingId = undefined;
|
||||
event.context.device.trackingStatus = 'not-authorized';
|
||||
event.context.device.id = undefined;
|
||||
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
export const createSegmentClient = () => {
|
||||
if (!SEGMENT_KEY) return null;
|
||||
|
||||
const client = createClient({
|
||||
writeKey: SEGMENT_KEY,
|
||||
trackAppLifecycleEvents: true,
|
||||
debug: true,
|
||||
collectDeviceId: false,
|
||||
defaultSettings: {
|
||||
integrations: {
|
||||
'Segment.io': {
|
||||
apiKey: SEGMENT_KEY,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
client.add({ plugin: new DisableTrackingPlugin() });
|
||||
|
||||
return client;
|
||||
};
|
||||
|
||||
// Export the client variable (will be initialized later)
|
||||
export let segmentClient: ReturnType<typeof createClient> | null = null;
|
||||
|
||||
function App(): React.JSX.Element {
|
||||
// const toast = useToastController();
|
||||
// const setToast = useNavigationStore(state => state.setToast);
|
||||
@@ -34,14 +90,13 @@ function App(): React.JSX.Element {
|
||||
// }, [setSelectedTab]);
|
||||
|
||||
useEffect(() => {
|
||||
if (AMPLITUDE_KEY) {
|
||||
amplitude.init(AMPLITUDE_KEY);
|
||||
}
|
||||
const cleanup = setupUniversalLinkListener();
|
||||
return cleanup;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const cleanup = setupUniversalLinkListener();
|
||||
return cleanup;
|
||||
// Initialize segment directly without any tracking checks
|
||||
segmentClient = createSegmentClient();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -85,8 +85,8 @@ android {
|
||||
applicationId "com.proofofpassportapp"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 16
|
||||
versionName "1.5"
|
||||
versionCode 19
|
||||
versionName "1.8"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags += "-fexceptions -frtti -std=c++11"
|
||||
|
||||
@@ -362,11 +362,13 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
eventMessageEmitter("Reading DG1.....")
|
||||
val dg1In = service.getInputStream(PassportService.EF_DG1)
|
||||
dg1File = DG1File(dg1In)
|
||||
val dg2In = service.getInputStream(PassportService.EF_DG2)
|
||||
dg2File = DG2File(dg2In)
|
||||
dg1File = DG1File(dg1In)
|
||||
// eventMessageEmitter("Reading DG2.....")
|
||||
// val dg2In = service.getInputStream(PassportService.EF_DG2)
|
||||
// dg2File = DG2File(dg2In)
|
||||
eventMessageEmitter("Reading SOD.....")
|
||||
val sodIn = service.getInputStream(PassportService.EF_SOD)
|
||||
sodFile = SODFile(sodIn)
|
||||
|
||||
@@ -406,20 +408,20 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
|
||||
// sendDataToJS(PassportData(dg1File, dg2File, sodFile))
|
||||
// Log.d(TAG, "============DATA SENT TO JS=============")
|
||||
|
||||
val allFaceImageInfo: MutableList<FaceImageInfo> = ArrayList()
|
||||
dg2File.faceInfos.forEach {
|
||||
allFaceImageInfo.addAll(it.faceImageInfos)
|
||||
}
|
||||
if (allFaceImageInfo.isNotEmpty()) {
|
||||
val faceImageInfo = allFaceImageInfo.first()
|
||||
val imageLength = faceImageInfo.imageLength
|
||||
val dataInputStream = DataInputStream(faceImageInfo.imageInputStream)
|
||||
val buffer = ByteArray(imageLength)
|
||||
dataInputStream.readFully(buffer, 0, imageLength)
|
||||
val inputStream: InputStream = ByteArrayInputStream(buffer, 0, imageLength)
|
||||
bitmap = decodeImage(reactContext, faceImageInfo.mimeType, inputStream)
|
||||
imageBase64 = Base64.encodeToString(buffer, Base64.DEFAULT)
|
||||
}
|
||||
// val allFaceImageInfo: MutableList<FaceImageInfo> = ArrayList()
|
||||
// dg2File.faceInfos.forEach {
|
||||
// allFaceImageInfo.addAll(it.faceImageInfos)
|
||||
// }
|
||||
// if (allFaceImageInfo.isNotEmpty()) {
|
||||
// val faceImageInfo = allFaceImageInfo.first()
|
||||
// val imageLength = faceImageInfo.imageLength
|
||||
// val dataInputStream = DataInputStream(faceImageInfo.imageInputStream)
|
||||
// val buffer = ByteArray(imageLength)
|
||||
// dataInputStream.readFully(buffer, 0, imageLength)
|
||||
// val inputStream: InputStream = ByteArrayInputStream(buffer, 0, imageLength)
|
||||
// bitmap = decodeImage(reactContext, faceImageInfo.mimeType, inputStream)
|
||||
// imageBase64 = Base64.encodeToString(buffer, Base64.DEFAULT)
|
||||
// }
|
||||
} catch (e: Exception) {
|
||||
eventMessageEmitter(Messages.RESET)
|
||||
return e
|
||||
@@ -429,6 +431,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
|
||||
|
||||
private fun doChipAuth(service: PassportService) {
|
||||
try {
|
||||
eventMessageEmitter("Reading DG14.....")
|
||||
val dg14In = service.getInputStream(PassportService.EF_DG14)
|
||||
dg14Encoded = IOUtils.toByteArray(dg14In)
|
||||
val dg14InByte = ByteArrayInputStream(dg14Encoded)
|
||||
@@ -459,11 +462,8 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
|
||||
|
||||
val dataHashes = sodFile.dataGroupHashes
|
||||
|
||||
eventMessageEmitter("Reading DG14.....")
|
||||
val dg14Hash = if (chipAuthSucceeded) digest.digest(dg14Encoded) else ByteArray(0)
|
||||
eventMessageEmitter("Reading DG1.....")
|
||||
val dg1Hash = digest.digest(dg1File.encoded)
|
||||
eventMessageEmitter("Reading DG2.....")
|
||||
val dg2Hash = digest.digest(dg2File.encoded)
|
||||
|
||||
// val gson = Gson()
|
||||
@@ -486,7 +486,8 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
|
||||
|
||||
Log.d(TAG, "Comparing data group hashes...")
|
||||
eventMessageEmitter(Messages.COMPARING)
|
||||
if (Arrays.equals(dg1Hash, dataHashes[1]) && Arrays.equals(dg2Hash, dataHashes[2])
|
||||
// if (Arrays.equals(dg1Hash, dataHashes[1]) && Arrays.equals(dg2Hash, dataHashes[2])
|
||||
if (Arrays.equals(dg1Hash, dataHashes[1])
|
||||
&& (!chipAuthSucceeded || Arrays.equals(dg14Hash, dataHashes[14]))) {
|
||||
|
||||
Log.d(TAG, "Data group hashes match.")
|
||||
@@ -660,13 +661,13 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
|
||||
// Log.d(TAG, "signedData.signerInfos: ${gson.toJson(signedData.signerInfos)}")
|
||||
// Log.d(TAG, "signedData.certificates: ${gson.toJson(signedData.certificates)}")
|
||||
|
||||
var quality = 100
|
||||
val base64 = bitmap?.let { toBase64(it, quality) }
|
||||
val photo = Arguments.createMap()
|
||||
photo.putString("base64", base64 ?: "")
|
||||
photo.putInt("width", bitmap?.width ?: 0)
|
||||
photo.putInt("height", bitmap?.height ?: 0)
|
||||
passport.putMap("photo", photo)
|
||||
// var quality = 100
|
||||
// val base64 = bitmap?.let { toBase64(it, quality) }
|
||||
// val photo = Arguments.createMap()
|
||||
// photo.putString("base64", base64 ?: "")
|
||||
// photo.putInt("width", bitmap?.width ?: 0)
|
||||
// photo.putInt("height", bitmap?.height ?: 0)
|
||||
// passport.putMap("photo", photo)
|
||||
// passport.putString("dg2File", gson.toJson(dg2File))
|
||||
|
||||
eventMessageEmitter(Messages.COMPLETED)
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
1686F0E02C500FBD00841CDE /* QRScannerBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 1686F0DF2C500FBD00841CDE /* QRScannerBridge.m */; };
|
||||
16E6646E2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16E6646D2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift */; };
|
||||
16E884A52C5BD764003B7125 /* passport.json in Resources */ = {isa = PBXBuildFile; fileRef = 16E884A42C5BD764003B7125 /* passport.json */; };
|
||||
1B904271B8E1DB8434EF0613 /* Pods_OpenPassport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3435ED6D988B5E2DE0DE8101 /* Pods_OpenPassport.framework */; };
|
||||
4A1791A6108347E5A635DB1C /* Inter-ThinItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = EEA2A4D24A8F4B10A5ECA607 /* Inter-ThinItalic.otf */; };
|
||||
5008C8140A304ED79DB817C5 /* slkscrb.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B4E7218406B64A95BCE0DFE4 /* slkscrb.ttf */; };
|
||||
5C66B65890614C638590DC8A /* Inter-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 8CE3CC4CFFC24314A22F1391 /* Inter-ExtraBold.otf */; };
|
||||
@@ -61,6 +60,7 @@
|
||||
EBECCA4983EC6929A7722578 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = E56E082698598B41447667BB /* PrivacyInfo.xcprivacy */; };
|
||||
EEF3331B93C24D6482021BA2 /* Inter-ExtraLightItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = 090474A3F07B4FFA82C9A751 /* Inter-ExtraLightItalic.otf */; };
|
||||
F1961109CC004035884F79D9 /* Inter-ExtraBoldItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = 37A4DECF3A824D5BAA8863FD /* Inter-ExtraBoldItalic.otf */; };
|
||||
F2B6CAF95CEE1D3F94541B0F /* Pods_OpenPassport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF34842C3AD0E76B7A7D5C5E /* Pods_OpenPassport.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -142,12 +142,12 @@
|
||||
16E6646D2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QKMRZScannerViewRepresentable.swift; sourceTree = "<group>"; };
|
||||
16E884A42C5BD764003B7125 /* passport.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = passport.json; sourceTree = "<group>"; };
|
||||
276287D0D37B4E8EBD7A1ABD /* Inter-SemiBold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-SemiBold.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-SemiBold.otf"; sourceTree = "<group>"; };
|
||||
3435ED6D988B5E2DE0DE8101 /* Pods_OpenPassport.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OpenPassport.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
37A4DECF3A824D5BAA8863FD /* Inter-ExtraBoldItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-ExtraBoldItalic.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-ExtraBoldItalic.otf"; sourceTree = "<group>"; };
|
||||
3BF771EA645241D9A28A3AE9 /* Inter-Bold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-Bold.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-Bold.otf"; sourceTree = "<group>"; };
|
||||
4B261C28061D47B7B3BB3E37 /* Inter-Black.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-Black.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-Black.otf"; sourceTree = "<group>"; };
|
||||
64F386964AAE4C1E8F2DF789 /* Inter-ExtraLight.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-ExtraLight.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-ExtraLight.otf"; sourceTree = "<group>"; };
|
||||
6CF8D6DF98634423ACD5D630 /* Inter-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-Regular.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-Regular.otf"; sourceTree = "<group>"; };
|
||||
73A8B182B1187BFE180CBB44 /* Pods-OpenPassport.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenPassport.release.xcconfig"; path = "Target Support Files/Pods-OpenPassport/Pods-OpenPassport.release.xcconfig"; sourceTree = "<group>"; };
|
||||
7CCB5F83F57540E88D54B34A /* slkscr.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = slkscr.ttf; path = "../node_modules/@tamagui/font-silkscreen/files/slkscr.ttf"; sourceTree = "<group>"; };
|
||||
7E5C3CEF7EDA4871B3D0EBE1 /* Advercase-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Advercase-Regular.otf"; path = "../src/assets/fonts/Advercase-Regular.otf"; sourceTree = "<group>"; };
|
||||
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = OpenPassport/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
@@ -158,10 +158,10 @@
|
||||
905B70062A72774000AFA232 /* PassportReader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PassportReader.m; sourceTree = "<group>"; };
|
||||
905B70082A729CD400AFA232 /* OpenPassport.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = OpenPassport.entitlements; path = OpenPassport/OpenPassport.entitlements; sourceTree = "<group>"; };
|
||||
9BF744D9A73A4BAC96EC569A /* DINOT-Medium.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "DINOT-Medium.otf"; path = "../src/assets/fonts/DINOT-Medium.otf"; sourceTree = "<group>"; };
|
||||
A239B1BBD7EF208EB51EF7DE /* Pods-OpenPassport.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenPassport.release.xcconfig"; path = "Target Support Files/Pods-OpenPassport/Pods-OpenPassport.release.xcconfig"; sourceTree = "<group>"; };
|
||||
AF34842C3AD0E76B7A7D5C5E /* Pods_OpenPassport.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OpenPassport.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B4E7218406B64A95BCE0DFE4 /* slkscrb.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = slkscrb.ttf; path = "../node_modules/@tamagui/font-silkscreen/files/slkscrb.ttf"; sourceTree = "<group>"; };
|
||||
BB9316819FB038104D42933E /* Pods-OpenPassport.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenPassport.debug.xcconfig"; path = "Target Support Files/Pods-OpenPassport/Pods-OpenPassport.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
C56F122245594D6DA9B7570A /* slkscr.woff */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = slkscr.woff; path = "../node_modules/@tamagui/font-silkscreen/files/slkscr.woff"; sourceTree = "<group>"; };
|
||||
CA67A75B161A05334E3E9402 /* Pods-OpenPassport.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenPassport.debug.xcconfig"; path = "Target Support Files/Pods-OpenPassport/Pods-OpenPassport.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
D58C0CED91AE4265A5A406A0 /* Inter-BlackItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-BlackItalic.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-BlackItalic.otf"; sourceTree = "<group>"; };
|
||||
DD642F4F3A114B43A22296D7 /* Inter-Thin.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-Thin.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-Thin.otf"; sourceTree = "<group>"; };
|
||||
E56E082698598B41447667BB /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = OpenPassport/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
@@ -186,7 +186,7 @@
|
||||
05D985F62BB331AB00F58EEA /* libfr.a in Frameworks */,
|
||||
167D934A2C91D2EA00530E6B /* libwitnesscalc_prove_rsa_65537_sha256.a in Frameworks */,
|
||||
167D93462C91B1E100530E6B /* libwitnesscalc_register_rsa_65537_sha1.a in Frameworks */,
|
||||
1B904271B8E1DB8434EF0613 /* Pods_OpenPassport.framework in Frameworks */,
|
||||
F2B6CAF95CEE1D3F94541B0F /* Pods_OpenPassport.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -273,7 +273,7 @@
|
||||
0569F35E2BBC98C9006670BD /* libfq.a */,
|
||||
0569F35A2BBC900D006670BD /* librapidsnark.a */,
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
|
||||
3435ED6D988B5E2DE0DE8101 /* Pods_OpenPassport.framework */,
|
||||
AF34842C3AD0E76B7A7D5C5E /* Pods_OpenPassport.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -343,8 +343,8 @@
|
||||
BBD78D7AC51CEA395F1C20DB /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BB9316819FB038104D42933E /* Pods-OpenPassport.debug.xcconfig */,
|
||||
A239B1BBD7EF208EB51EF7DE /* Pods-OpenPassport.release.xcconfig */,
|
||||
CA67A75B161A05334E3E9402 /* Pods-OpenPassport.debug.xcconfig */,
|
||||
73A8B182B1187BFE180CBB44 /* Pods-OpenPassport.release.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
@@ -356,15 +356,15 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "OpenPassport" */;
|
||||
buildPhases = (
|
||||
62212FE980074600640A3F2F /* [CP] Check Pods Manifest.lock */,
|
||||
1C3B778186C749AEAB10A0B1 /* [CP] Check Pods Manifest.lock */,
|
||||
FD10A7F022414F080027D42C /* Start Packager */,
|
||||
13B07F871A680F5B00A75B9A /* Sources */,
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
054340D12C71B2980014B445 /* Embed App Clips */,
|
||||
19B6B230BF58128B7603B834 /* [CP] Embed Pods Frameworks */,
|
||||
CCF107224BF9CF7E8A4F57B7 /* [CP] Copy Pods Resources */,
|
||||
0C6411FE06C61E7F495D9204 /* [CP] Embed Pods Frameworks */,
|
||||
DAB2FFB78D69B620A585FF8C /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -461,7 +461,7 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
|
||||
};
|
||||
19B6B230BF58128B7603B834 /* [CP] Embed Pods Frameworks */ = {
|
||||
0C6411FE06C61E7F495D9204 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -478,7 +478,7 @@
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-OpenPassport/Pods-OpenPassport-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
62212FE980074600640A3F2F /* [CP] Check Pods Manifest.lock */ = {
|
||||
1C3B778186C749AEAB10A0B1 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -500,7 +500,7 @@
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
CCF107224BF9CF7E8A4F57B7 /* [CP] Copy Pods Resources */ = {
|
||||
DAB2FFB78D69B620A585FF8C /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -584,7 +584,7 @@
|
||||
/* Begin XCBuildConfiguration section */
|
||||
13B07F941A680F5B00A75B9A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = BB9316819FB038104D42933E /* Pods-OpenPassport.debug.xcconfig */;
|
||||
baseConfigurationReference = CA67A75B161A05334E3E9402 /* Pods-OpenPassport.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
@@ -592,7 +592,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = OpenPassport/OpenPassportDebug.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 67;
|
||||
CURRENT_PROJECT_VERSION = 72;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 5B29R5LYHQ;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -707,7 +707,7 @@
|
||||
"$(PROJECT_DIR)",
|
||||
"$(PROJECT_DIR)/MoproKit/Libs",
|
||||
);
|
||||
MARKETING_VERSION = 2.0.0;
|
||||
MARKETING_VERSION = 2.0.6;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -725,13 +725,13 @@
|
||||
};
|
||||
13B07F951A680F5B00A75B9A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = A239B1BBD7EF208EB51EF7DE /* Pods-OpenPassport.release.xcconfig */;
|
||||
baseConfigurationReference = 73A8B182B1187BFE180CBB44 /* Pods-OpenPassport.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = OpenPassport/OpenPassport.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 67;
|
||||
CURRENT_PROJECT_VERSION = 72;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 5B29R5LYHQ;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@@ -845,7 +845,7 @@
|
||||
"$(PROJECT_DIR)",
|
||||
"$(PROJECT_DIR)/MoproKit/Libs",
|
||||
);
|
||||
MARKETING_VERSION = 2.0.0;
|
||||
MARKETING_VERSION = 2.0.6;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
|
||||
@@ -97,7 +97,7 @@ class PassportReader: NSObject{
|
||||
// let masterListURL = Bundle.main.url(forResource: "masterList", withExtension: ".pem")
|
||||
// passportReader.setMasterListURL( masterListURL! )
|
||||
|
||||
let passport = try await passportReader.readPassport( mrzKey: mrzKey, customDisplayMessage: customMessageHandler)
|
||||
let passport = try await passportReader.readPassport( mrzKey: mrzKey, tags: [.COM, .DG1, .SOD], customDisplayMessage: customMessageHandler)
|
||||
|
||||
var ret = [String:String]()
|
||||
print("documentType", passport.documentType)
|
||||
@@ -118,13 +118,13 @@ class PassportReader: NSObject{
|
||||
ret["phoneNumber"] = passport.phoneNumber
|
||||
ret["personalNumber"] = passport.personalNumber
|
||||
|
||||
let passportPhotoData = passport.passportPhoto // [UInt8]
|
||||
if let passportPhotoData = passport.passportPhoto {
|
||||
let data = Data(passportPhotoData)
|
||||
let base64String = data.base64EncodedString()
|
||||
// let passportPhotoData = passport.passportPhoto // [UInt8]
|
||||
// if let passportPhotoData = passport.passportPhoto {
|
||||
// let data = Data(passportPhotoData)
|
||||
// let base64String = data.base64EncodedString()
|
||||
|
||||
ret["passportPhoto"] = base64String
|
||||
}
|
||||
// ret["passportPhoto"] = base64String
|
||||
// }
|
||||
|
||||
// documentSigningCertificate
|
||||
// countrySigningCertificate
|
||||
|
||||
@@ -24,7 +24,7 @@ target 'OpenPassport' do
|
||||
config = use_native_modules!
|
||||
|
||||
use_frameworks!
|
||||
pod 'NFCPassportReader', git: 'https://github.com/0xturboblitz/NFCPassportReader.git', commit: '0a8e26d56f5f85f698b67c5df5ea9ecbb53cbc45'
|
||||
pod 'NFCPassportReader', git: 'https://github.com/zk-passport/NFCPassportReader', commit: '8e72f0a2d3ca3bede00304bd22ed10829535dd53'
|
||||
pod 'QKMRZScanner'
|
||||
pod 'RNFS', :path => '../node_modules/react-native-fs'
|
||||
pod 'lottie-ios'
|
||||
|
||||
@@ -7,9 +7,9 @@ PODS:
|
||||
- fmt (9.1.0)
|
||||
- glog (0.3.5)
|
||||
- lottie-ios (4.5.0)
|
||||
- NFCPassportReader (2.0.3):
|
||||
- OpenSSL-Universal (= 1.1.1100)
|
||||
- OpenSSL-Universal (1.1.1100)
|
||||
- NFCPassportReader (2.1.1):
|
||||
- OpenSSL-Universal (= 1.1.1900)
|
||||
- OpenSSL-Universal (1.1.1900)
|
||||
- QKMRZParser (2.0.0)
|
||||
- QKMRZScanner (3.0.0):
|
||||
- QKMRZParser (~> 2.0.0)
|
||||
@@ -1227,6 +1227,10 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-nfc-manager (3.16.1):
|
||||
- React-Core
|
||||
- react-native-safe-area-context (5.1.0):
|
||||
- React-Core
|
||||
- react-native-tracking-transparency (0.1.2):
|
||||
- React
|
||||
- React-nativeconfig (0.75.4)
|
||||
- React-NativeModulesApple (0.75.4):
|
||||
- glog
|
||||
@@ -1474,6 +1478,27 @@ PODS:
|
||||
- React-Core
|
||||
- RNFS (2.20.0):
|
||||
- React-Core
|
||||
- RNGestureHandler (2.22.1):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2024.01.01.00)
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
- React-Core
|
||||
- React-debug
|
||||
- React-Fabric
|
||||
- React-featureflags
|
||||
- React-graphics
|
||||
- React-ImageManager
|
||||
- React-jsi
|
||||
- React-NativeModulesApple
|
||||
- React-RCTFabric
|
||||
- React-rendererdebug
|
||||
- React-utils
|
||||
- ReactCodegen
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- RNKeychain (8.2.0):
|
||||
- React-Core
|
||||
- RNSVG (13.4.0):
|
||||
@@ -1485,7 +1510,12 @@ PODS:
|
||||
- RNZipArchive/Core (6.1.2):
|
||||
- React-Core
|
||||
- SSZipArchive (~> 2.2)
|
||||
- segment-analytics-react-native (2.20.3):
|
||||
- React-Core
|
||||
- sovran-react-native
|
||||
- SocketRocket (0.7.0)
|
||||
- sovran-react-native (1.1.3):
|
||||
- React-Core
|
||||
- SSZipArchive (2.4.3)
|
||||
- SwiftQRScanner (1.1.6)
|
||||
- SwiftyTesseract (3.1.3)
|
||||
@@ -1499,7 +1529,7 @@ DEPENDENCIES:
|
||||
- fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`)
|
||||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- lottie-ios
|
||||
- NFCPassportReader (from `https://github.com/0xturboblitz/NFCPassportReader.git`, commit `0a8e26d56f5f85f698b67c5df5ea9ecbb53cbc45`)
|
||||
- NFCPassportReader (from `https://github.com/zk-passport/NFCPassportReader`, commit `8e72f0a2d3ca3bede00304bd22ed10829535dd53`)
|
||||
- QKMRZScanner
|
||||
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
|
||||
- RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
|
||||
@@ -1536,6 +1566,8 @@ DEPENDENCIES:
|
||||
- react-native-get-random-values (from `../node_modules/react-native-get-random-values`)
|
||||
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
||||
- react-native-nfc-manager (from `../node_modules/react-native-nfc-manager`)
|
||||
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
|
||||
- react-native-tracking-transparency (from `../node_modules/react-native-tracking-transparency`)
|
||||
- React-nativeconfig (from `../node_modules/react-native/ReactCommon`)
|
||||
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
|
||||
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
|
||||
@@ -1563,9 +1595,12 @@ DEPENDENCIES:
|
||||
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
||||
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
||||
- RNFS (from `../node_modules/react-native-fs`)
|
||||
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
||||
- RNKeychain (from `../node_modules/react-native-keychain`)
|
||||
- RNSVG (from `../node_modules/react-native-svg`)
|
||||
- RNZipArchive (from `../node_modules/react-native-zip-archive`)
|
||||
- "segment-analytics-react-native (from `../node_modules/@segment/analytics-react-native`)"
|
||||
- "sovran-react-native (from `../node_modules/@segment/sovran-react-native`)"
|
||||
- SwiftQRScanner (from `https://github.com/vinodiOS/SwiftQRScanner`)
|
||||
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
|
||||
@@ -1593,8 +1628,8 @@ EXTERNAL SOURCES:
|
||||
glog:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
|
||||
NFCPassportReader:
|
||||
:commit: 0a8e26d56f5f85f698b67c5df5ea9ecbb53cbc45
|
||||
:git: https://github.com/0xturboblitz/NFCPassportReader.git
|
||||
:commit: 8e72f0a2d3ca3bede00304bd22ed10829535dd53
|
||||
:git: https://github.com/zk-passport/NFCPassportReader
|
||||
RCT-Folly:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
|
||||
RCTDeprecation:
|
||||
@@ -1661,6 +1696,10 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/@react-native-community/netinfo"
|
||||
react-native-nfc-manager:
|
||||
:path: "../node_modules/react-native-nfc-manager"
|
||||
react-native-safe-area-context:
|
||||
:path: "../node_modules/react-native-safe-area-context"
|
||||
react-native-tracking-transparency:
|
||||
:path: "../node_modules/react-native-tracking-transparency"
|
||||
React-nativeconfig:
|
||||
:path: "../node_modules/react-native/ReactCommon"
|
||||
React-NativeModulesApple:
|
||||
@@ -1715,12 +1754,18 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/@react-native-async-storage/async-storage"
|
||||
RNFS:
|
||||
:path: "../node_modules/react-native-fs"
|
||||
RNGestureHandler:
|
||||
:path: "../node_modules/react-native-gesture-handler"
|
||||
RNKeychain:
|
||||
:path: "../node_modules/react-native-keychain"
|
||||
RNSVG:
|
||||
:path: "../node_modules/react-native-svg"
|
||||
RNZipArchive:
|
||||
:path: "../node_modules/react-native-zip-archive"
|
||||
segment-analytics-react-native:
|
||||
:path: "../node_modules/@segment/analytics-react-native"
|
||||
sovran-react-native:
|
||||
:path: "../node_modules/@segment/sovran-react-native"
|
||||
SwiftQRScanner:
|
||||
:git: https://github.com/vinodiOS/SwiftQRScanner
|
||||
Yoga:
|
||||
@@ -1728,8 +1773,8 @@ EXTERNAL SOURCES:
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
NFCPassportReader:
|
||||
:commit: 0a8e26d56f5f85f698b67c5df5ea9ecbb53cbc45
|
||||
:git: https://github.com/0xturboblitz/NFCPassportReader.git
|
||||
:commit: 8e72f0a2d3ca3bede00304bd22ed10829535dd53
|
||||
:git: https://github.com/zk-passport/NFCPassportReader
|
||||
SwiftQRScanner:
|
||||
:commit: fddcabcb431cd6110cea0394660082661dbafa7e
|
||||
:git: https://github.com/vinodiOS/SwiftQRScanner
|
||||
@@ -1742,8 +1787,8 @@ SPEC CHECKSUMS:
|
||||
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
|
||||
glog: 69ef571f3de08433d766d614c73a9838a06bf7eb
|
||||
lottie-ios: a881093fab623c467d3bce374367755c272bdd59
|
||||
NFCPassportReader: a160b80e3df3b5325c13902f90405f5eef7520b3
|
||||
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
|
||||
NFCPassportReader: e931c61c189e08a4b4afa0ed4014af19eab2f129
|
||||
OpenSSL-Universal: 84efb8a29841f2764ac5403e0c4119a28b713346
|
||||
QKMRZParser: 6b419b6f07d6bff6b50429b97de10846dc902c29
|
||||
QKMRZScanner: cf2348fd6ce441e758328da4adf231ef2b51d769
|
||||
RCT-Folly: 4464f4d875961fce86008d45f4ecf6cef6de0740
|
||||
@@ -1779,6 +1824,8 @@ SPEC CHECKSUMS:
|
||||
react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06
|
||||
react-native-netinfo: f0a9899081c185db1de5bb2fdc1c88c202a059ac
|
||||
react-native-nfc-manager: 5213321cf6c18d879c8092c0bf56806b771ec5ac
|
||||
react-native-safe-area-context: 04803a01f39f31cc6605a5531280b477b48f8a88
|
||||
react-native-tracking-transparency: 25ff1ff866e338c137c818bdec20526bb05ffcc1
|
||||
React-nativeconfig: 31072ab0146e643594f6959c7f970a04b6c9ddd0
|
||||
React-NativeModulesApple: 5df767d9a2197ac25f4d8dd2d4ae1af3624022e2
|
||||
React-perflogger: 59e1a3182dca2cee7b9f1f7aab204018d46d1914
|
||||
@@ -1806,15 +1853,18 @@ SPEC CHECKSUMS:
|
||||
ReactCommon: 03d2d48fcd1329fe3bc4e428a78a0181b68068c2
|
||||
RNCAsyncStorage: ec53e44dc3e75b44aa2a9f37618a49c3bc080a7a
|
||||
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
|
||||
RNGestureHandler: e705387b01bba53f4643bdff381ee08c7b9679a1
|
||||
RNKeychain: bfe3d12bf4620fe488771c414530bf16e88f3678
|
||||
RNSVG: 07dbd870b0dcdecc99b3a202fa37c8ca163caec2
|
||||
RNZipArchive: 6d736ee4e286dbbd9d81206b7a4da355596ca04a
|
||||
segment-analytics-react-native: d57ed4971cbb995706babf29215ebdbf242ecdab
|
||||
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
|
||||
sovran-react-native: eec37f82e4429f0e3661f46aaf4fcd85d1b54f60
|
||||
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
|
||||
SwiftQRScanner: e85a25f9b843e9231dab89a96e441472fe54a724
|
||||
SwiftyTesseract: 1f3d96668ae92dc2208d9842c8a59bea9fad2cbb
|
||||
Yoga: b05994d1933f507b0a28ceaa4fdb968dc18da178
|
||||
|
||||
PODFILE CHECKSUM: cc6778e0dcd4c510b705f4dc458411547dc1d00c
|
||||
PODFILE CHECKSUM: a5761927116120f511f409f5249a18a8c626545c
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
COCOAPODS: 1.15.2
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
"@react-navigation/elements": "^2.2.5",
|
||||
"@react-navigation/native": "^7.0.14",
|
||||
"@react-navigation/stack": "^7.1.1",
|
||||
"@segment/analytics-react-native": "^2.20.3",
|
||||
"@segment/sovran-react-native": "^1.1.3",
|
||||
"@tamagui/colors": "1.110.0",
|
||||
"@tamagui/config": "1.110.0",
|
||||
"@tamagui/core": "1.110.0",
|
||||
@@ -57,6 +59,7 @@
|
||||
"react-native-passport-reader": "^1.0.3",
|
||||
"react-native-safe-area-context": "^5.1.0",
|
||||
"react-native-svg": "13.4.0",
|
||||
"react-native-tracking-transparency": "^0.1.2",
|
||||
"react-native-zip-archive": "^6.1.0",
|
||||
"socket.io-client": "^4.7.5",
|
||||
"tamagui": "1.110.0",
|
||||
|
||||
@@ -19,7 +19,8 @@ import {
|
||||
} from 'tamagui';
|
||||
|
||||
import { countryCodes } from '../../../common/src/constants/constants';
|
||||
import { genMockPassportData } from '../../../common/src/utils/genMockPassportData';
|
||||
import { genMockPassportData } from '../../../common/src/utils/passports/genMockPassportData';
|
||||
import { parsePassportData } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
|
||||
import CustomButton from '../components/CustomButton';
|
||||
import useUserStore from '../stores/userStore';
|
||||
import {
|
||||
@@ -77,20 +78,38 @@ const MockDataScreen: React.FC<MockDataScreenProps> = ({}) => {
|
||||
.toUpperCase();
|
||||
await new Promise(resolve =>
|
||||
setTimeout(() => {
|
||||
let mockPassportData;
|
||||
const hashAlgo = selectedAlgorithm === 'rsa sha1' ? 'sha1' : 'sha256';
|
||||
const mockPassportData = genMockPassportData(
|
||||
hashAlgo,
|
||||
hashAlgo,
|
||||
signatureAlgorithmToStrictSignatureAlgorithm[
|
||||
selectedAlgorithm as keyof typeof signatureAlgorithmToStrictSignatureAlgorithm
|
||||
],
|
||||
selectedCountry as keyof typeof countryCodes,
|
||||
castDate(-age),
|
||||
castDate(expiryYears),
|
||||
randomPassportNumber,
|
||||
...(isInOfacList ? ['HENAO MONTOYA', 'ARCANGEL DE JESUS'] : []),
|
||||
);
|
||||
if (isInOfacList) {
|
||||
mockPassportData = genMockPassportData(
|
||||
hashAlgo,
|
||||
hashAlgo,
|
||||
signatureAlgorithmToStrictSignatureAlgorithm[
|
||||
selectedAlgorithm as keyof typeof signatureAlgorithmToStrictSignatureAlgorithm
|
||||
],
|
||||
selectedCountry as keyof typeof countryCodes,
|
||||
castDate(-age),
|
||||
castDate(expiryYears),
|
||||
randomPassportNumber,
|
||||
'HENAO MONTOYA', // this name is the OFAC list
|
||||
'ARCANGEL DE JESUS',
|
||||
);
|
||||
} else {
|
||||
mockPassportData = genMockPassportData(
|
||||
hashAlgo,
|
||||
hashAlgo,
|
||||
signatureAlgorithmToStrictSignatureAlgorithm[
|
||||
selectedAlgorithm as keyof typeof signatureAlgorithmToStrictSignatureAlgorithm
|
||||
],
|
||||
selectedCountry as keyof typeof countryCodes,
|
||||
castDate(-age),
|
||||
castDate(expiryYears),
|
||||
randomPassportNumber,
|
||||
);
|
||||
}
|
||||
useUserStore.getState().registerPassportData(mockPassportData);
|
||||
const parsedPassportData = parsePassportData(mockPassportData);
|
||||
useUserStore.getState().setPassportMetadata(parsedPassportData);
|
||||
useUserStore.getState().setRegistered(true);
|
||||
resolve(null);
|
||||
}, 0),
|
||||
|
||||
@@ -50,9 +50,10 @@ const NextScreen: React.FC = () => {
|
||||
h={height > 750 ? 190 : 130}
|
||||
borderRadius={height > 750 ? '$7' : '$6'}
|
||||
source={{
|
||||
uri: passportData.mockUser
|
||||
? USER_PROFILE
|
||||
: passportData.photoBase64 ?? USER_PROFILE,
|
||||
uri:
|
||||
passportData?.mockUser || !!!passportData?.photoBase64
|
||||
? USER_PROFILE
|
||||
: passportData?.photoBase64 ?? USER_PROFILE,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -78,16 +79,34 @@ const NextScreen: React.FC = () => {
|
||||
const key_ = key;
|
||||
const indexes =
|
||||
attributeToPosition[key_ as keyof typeof attributeToPosition];
|
||||
if (!passportData?.mrz || !indexes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const keyFormatted = key_
|
||||
.replace(/_/g, ' ')
|
||||
.split(' ')
|
||||
.map((word: string) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' ');
|
||||
|
||||
if (
|
||||
indexes[0] >= passportData.mrz.length ||
|
||||
indexes[1] >= passportData.mrz.length
|
||||
) {
|
||||
console.warn(
|
||||
`Invalid indexes for key ${key_}: [${indexes[0]}, ${indexes[1]}]`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const mrzAttribute = passportData.mrz.slice(
|
||||
indexes[0],
|
||||
indexes[1] + 1,
|
||||
);
|
||||
const mrzAttributeFormatted = formatAttribute(key_, mrzAttribute);
|
||||
const mrzAttributeFormatted = formatAttribute(
|
||||
key_,
|
||||
mrzAttribute ?? '',
|
||||
);
|
||||
|
||||
return (
|
||||
<Fieldset horizontal key={key} gap="$3" alignItems="center">
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import io, { Socket } from 'socket.io-client';
|
||||
import { Text, YStack } from 'tamagui';
|
||||
|
||||
import {
|
||||
DEVELOPMENT_MODE,
|
||||
max_cert_bytes,
|
||||
MAX_CERT_BYTES,
|
||||
} from '../../../../common/src/constants/constants';
|
||||
import {
|
||||
ArgumentsProveOffChain,
|
||||
@@ -16,13 +14,15 @@ import {
|
||||
getCircuitNameOld,
|
||||
parseCertificateSimple,
|
||||
} from '../../../../common/src/utils/certificate_parsing/parseCertificateSimple';
|
||||
// import {
|
||||
// getCSCAFromSKI,
|
||||
// sendCSCARequest,
|
||||
// } from '../../../../common/src/utils/csca';
|
||||
import {
|
||||
generateCircuitInputsDSC,
|
||||
getCSCAFromSKI,
|
||||
sendCSCARequest,
|
||||
} from '../../../../common/src/utils/csca';
|
||||
} from '../../../../common/src/utils/circuits/generateInputs';
|
||||
import { buildAttestation } from '../../../../common/src/utils/openPassportAttestation';
|
||||
import { parsePassportData } from '../../../../common/src/utils/parsePassportData';
|
||||
import { parsePassportData } from '../../../../common/src/utils/passports/passport_parsing/parsePassportData';
|
||||
import Disclosures from '../../components/Disclosures';
|
||||
import { PrimaryButton } from '../../components/buttons/PrimaryButton';
|
||||
import { BodyText } from '../../components/typography/BodyText';
|
||||
@@ -31,7 +31,7 @@ import { ExpandableBottomLayout } from '../../layouts/ExpandableBottomLayout';
|
||||
import useNavigationStore from '../../stores/navigationStore';
|
||||
import useUserStore from '../../stores/userStore';
|
||||
import { black, slate300, white } from '../../utils/colors';
|
||||
import { generateCircuitInputsInApp } from '../../utils/generateInputsInApp';
|
||||
// import { generateCircuitInputsInApp } from '../../utils/generateInputsInApp';
|
||||
import { generateProof } from '../../utils/prover';
|
||||
import { CircuitName } from '../../utils/zkeyDownload';
|
||||
|
||||
@@ -188,34 +188,34 @@ const ProveScreen: React.FC = () => {
|
||||
switch (selectedApp.mode) {
|
||||
case 'prove_onchain':
|
||||
case 'register':
|
||||
const cscaInputs = generateCircuitInputsDSC(
|
||||
dscSecret as string,
|
||||
passportData.dsc,
|
||||
max_cert_bytes,
|
||||
selectedApp.devMode,
|
||||
);
|
||||
[dscProof, proof] = await Promise.all([
|
||||
sendCSCARequest(cscaInputs),
|
||||
generateProof(circuitName, inputs),
|
||||
]);
|
||||
const cscaPem = getCSCAFromSKI(
|
||||
authorityKeyIdentifier,
|
||||
DEVELOPMENT_MODE,
|
||||
);
|
||||
const { signatureAlgorithm: signatureAlgorithmDsc } =
|
||||
parseCertificateSimple(cscaPem);
|
||||
attestation = buildAttestation({
|
||||
mode: selectedApp.mode,
|
||||
proof: proof.proof,
|
||||
publicSignals: proof.publicSignals,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
hashFunction: parsedPassportData.signedAttrHashFunction,
|
||||
userIdType: selectedApp.userIdType,
|
||||
dscProof: (dscProof as any).proof,
|
||||
dscPublicSignals: (dscProof as any).pub_signals,
|
||||
signatureAlgorithmDsc: signatureAlgorithmDsc,
|
||||
hashFunctionDsc: parsedPassportData.signedAttrHashFunction,
|
||||
});
|
||||
// const cscaInputs = generateCircuitInputsDSC(
|
||||
// dscSecret as string,
|
||||
// passportData.dsc,
|
||||
// MAX_CERT_BYTES,
|
||||
// selectedApp.devMode,
|
||||
// );
|
||||
// [dscProof, proof] = await Promise.all([
|
||||
// sendCSCARequest(cscaInputs),
|
||||
// generateProof(circuitName, inputs),
|
||||
// ]);
|
||||
// const cscaPem = getCSCAFromSKI(
|
||||
// authorityKeyIdentifier,
|
||||
// DEVELOPMENT_MODE,
|
||||
// );
|
||||
// const { signatureAlgorithm: signatureAlgorithmDsc } =
|
||||
// parseCertificateSimple(cscaPem);
|
||||
// attestation = buildAttestation({
|
||||
// mode: selectedApp.mode,
|
||||
// proof: proof.proof,
|
||||
// publicSignals: proof.publicSignals,
|
||||
// signatureAlgorithm: signatureAlgorithm,
|
||||
// hashFunction: parsedPassportData.signedAttrHashFunction,
|
||||
// userIdType: selectedApp.userIdType,
|
||||
// dscProof: (dscProof as any).proof,
|
||||
// dscPublicSignals: (dscProof as any).pub_signals,
|
||||
// signatureAlgorithmDsc: signatureAlgorithmDsc,
|
||||
// hashFunctionDsc: parsedPassportData.signedAttrHashFunction,
|
||||
// });
|
||||
break;
|
||||
default:
|
||||
proof = await generateProof(circuitName, inputs);
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
|
||||
import { ScrollView, Separator, Text, XStack, YStack } from 'tamagui';
|
||||
|
||||
import { parsePassportData } from '../../../common/src/utils/parsePassportData';
|
||||
import { parsePassportData } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
|
||||
import useUserStore from '../stores/userStore';
|
||||
import { separatorColor, textBlack } from '../utils/colors';
|
||||
|
||||
@@ -126,7 +126,7 @@ const UserInfo: React.FC = () => {
|
||||
|
||||
<InfoRow
|
||||
label="CSCA Signature Algorithm"
|
||||
value={passportMetaData?.cscaSignature || 'None'}
|
||||
value={passportMetaData?.cscaSignatureAlgorithm || 'None'}
|
||||
/>
|
||||
<Separator borderColor={separatorColor} />
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useToastController } from '@tamagui/toast';
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { OpenPassportApp } from '../../../common/src/utils/appType';
|
||||
import { segmentClient } from '../../App';
|
||||
import {
|
||||
IsZkeyDownloading,
|
||||
ShowWarningModalProps,
|
||||
@@ -24,10 +25,12 @@ interface NavigationState {
|
||||
setNfcSheetIsOpen: (isOpen: boolean) => void;
|
||||
zkeyDownloadedPercentage: number;
|
||||
setZkeyDownloadedPercentage: (percentage: number) => void;
|
||||
trackEvent: (eventName: string, properties?: Record<string, any>) => void;
|
||||
trackNavigation: (tab: string) => void;
|
||||
}
|
||||
|
||||
const useNavigationStore = create<NavigationState>((set, get) => ({
|
||||
zkeyDownloadedPercentage: 100,
|
||||
zkeyDownloadedPercentage: 0,
|
||||
setZkeyDownloadedPercentage: (percentage: number) =>
|
||||
set({ zkeyDownloadedPercentage: percentage }),
|
||||
isZkeyDownloading: {
|
||||
@@ -54,7 +57,10 @@ const useNavigationStore = create<NavigationState>((set, get) => ({
|
||||
setToast: toast => set({ toast }),
|
||||
setSelectedApp: app => set({ selectedApp: app }),
|
||||
|
||||
setSelectedTab: tab => set({ selectedTab: tab }),
|
||||
setSelectedTab: (tab: string) => {
|
||||
const { trackNavigation } = get();
|
||||
trackNavigation(tab);
|
||||
},
|
||||
|
||||
update: patch => {
|
||||
set({
|
||||
@@ -64,6 +70,21 @@ const useNavigationStore = create<NavigationState>((set, get) => ({
|
||||
},
|
||||
nfcSheetIsOpen: false,
|
||||
setNfcSheetIsOpen: isOpen => set({ nfcSheetIsOpen: isOpen }),
|
||||
|
||||
trackEvent: (eventName: string, properties?: Record<string, any>) => {
|
||||
if (segmentClient) {
|
||||
segmentClient.track(eventName, properties);
|
||||
}
|
||||
},
|
||||
|
||||
trackNavigation: (tab: string) => {
|
||||
if (segmentClient) {
|
||||
segmentClient.track('Navigation Change', {
|
||||
tab,
|
||||
});
|
||||
}
|
||||
set({ selectedTab: tab });
|
||||
},
|
||||
}));
|
||||
|
||||
export default useNavigationStore;
|
||||
|
||||
@@ -3,12 +3,15 @@ import { resetGenericPassword } from 'react-native-keychain';
|
||||
import { DEFAULT_DOB, DEFAULT_DOE, DEFAULT_PNUMBER } from '@env';
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { generateDscSecret } from '../../../common/src/utils/csca';
|
||||
// import { generateDscSecret } from '../../../common/src/utils/csca';
|
||||
import { PassportMetadata } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
|
||||
import { PassportData, Proof } from '../../../common/src/utils/types';
|
||||
import {
|
||||
loadPassportData,
|
||||
loadPassportMetadata,
|
||||
loadSecretOrCreateIt,
|
||||
storePassportData,
|
||||
storePassportMetadata,
|
||||
} from '../utils/keychain';
|
||||
|
||||
interface UserState {
|
||||
@@ -18,6 +21,7 @@ interface UserState {
|
||||
countryCode: string;
|
||||
registered: boolean;
|
||||
passportData: PassportData | null;
|
||||
passportMetadata: PassportMetadata | null;
|
||||
secret: string;
|
||||
cscaProof: Proof | null;
|
||||
localProof: Proof | null;
|
||||
@@ -35,6 +39,8 @@ interface UserState {
|
||||
setUserLoaded: (userLoaded: boolean) => void;
|
||||
proofVerificationResult: string;
|
||||
setProofVerificationResult: (proofVerificationResult: string) => void;
|
||||
setPassportMetadata: (metadata: PassportMetadata) => void;
|
||||
clearPassportMetadataFromStorage: () => void;
|
||||
}
|
||||
|
||||
const useUserStore = create<UserState>((set, get) => ({
|
||||
@@ -46,6 +52,7 @@ const useUserStore = create<UserState>((set, get) => ({
|
||||
dscSecret: null,
|
||||
registered: false,
|
||||
passportData: null,
|
||||
passportMetadata: null,
|
||||
secret: '',
|
||||
cscaProof: null,
|
||||
localProof: null,
|
||||
@@ -58,6 +65,10 @@ const useUserStore = create<UserState>((set, get) => ({
|
||||
setUserLoaded: (userLoaded: boolean) => {
|
||||
set({ userLoaded });
|
||||
},
|
||||
setPassportMetadata: async (metadata: PassportMetadata) => {
|
||||
await storePassportMetadata(metadata);
|
||||
set({ passportMetadata: metadata });
|
||||
},
|
||||
proofVerificationResult: 'null',
|
||||
setProofVerificationResult: (proofVerificationResult: string) => {
|
||||
set({ proofVerificationResult });
|
||||
@@ -68,16 +79,18 @@ const useUserStore = create<UserState>((set, get) => ({
|
||||
// - If the commitment is present in the tree, proceed to main screen
|
||||
// - If the commitment is not present in the tree, proceed to main screen AND try registering it in the background
|
||||
initUserStore: async () => {
|
||||
// download zkeys if they are not already downloaded
|
||||
|
||||
const secret = await loadSecretOrCreateIt();
|
||||
set({ secret });
|
||||
const dscSecret = await generateDscSecret();
|
||||
set({ dscSecret });
|
||||
// const dscSecret = await generateDscSecret();
|
||||
// set({ dscSecret });
|
||||
|
||||
const passportDataString = await loadPassportData();
|
||||
if (!passportDataString) {
|
||||
console.log('No passport data found, starting onboarding flow');
|
||||
const passportMetadataString = await loadPassportMetadata();
|
||||
|
||||
if (!passportDataString || !passportMetadataString) {
|
||||
console.log(
|
||||
'No passport data or metadata found, starting onboarding flow',
|
||||
);
|
||||
set({
|
||||
userLoaded: true,
|
||||
});
|
||||
@@ -87,6 +100,9 @@ const useUserStore = create<UserState>((set, get) => ({
|
||||
// const isAlreadyRegistered = await isCommitmentRegistered(secret, JSON.parse(passportData));
|
||||
const isAlreadyRegistered = true;
|
||||
const passportData: PassportData = JSON.parse(passportDataString);
|
||||
const passportMetadata: PassportMetadata = JSON.parse(
|
||||
passportMetadataString,
|
||||
);
|
||||
|
||||
if (!isAlreadyRegistered) {
|
||||
console.log(
|
||||
@@ -94,9 +110,9 @@ const useUserStore = create<UserState>((set, get) => ({
|
||||
);
|
||||
set({
|
||||
passportData: passportData,
|
||||
passportMetadata: passportMetadata,
|
||||
userLoaded: true,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -105,9 +121,10 @@ const useUserStore = create<UserState>((set, get) => ({
|
||||
);
|
||||
set({
|
||||
passportData: passportData,
|
||||
passportMetadata: passportMetadata,
|
||||
registered: true,
|
||||
userLoaded: true,
|
||||
});
|
||||
set({ userLoaded: true });
|
||||
},
|
||||
|
||||
// When reading passport for the first time:
|
||||
@@ -152,6 +169,11 @@ const useUserStore = create<UserState>((set, get) => ({
|
||||
dateOfBirth: '',
|
||||
dateOfExpiry: '',
|
||||
}),
|
||||
|
||||
clearPassportMetadataFromStorage: async () => {
|
||||
await resetGenericPassword({ service: 'passportMetadata' });
|
||||
set({ passportMetadata: null });
|
||||
},
|
||||
}));
|
||||
|
||||
export default useUserStore;
|
||||
|
||||
@@ -15,11 +15,11 @@ import {
|
||||
OpenPassportApp,
|
||||
} from '../../../common/src/utils/appType';
|
||||
import {
|
||||
generateCircuitInputsDisclose,
|
||||
generateCircuitInputsProve,
|
||||
} from '../../../common/src/utils/generateInputs';
|
||||
import { fetchTreeFromUrl } from '../../../common/src/utils/pubkeyTree';
|
||||
import { revealBitmapFromAttributes } from '../../../common/src/utils/revealBitmap';
|
||||
generateCircuitInputsRegister,
|
||||
generateCircuitInputsVCandDisclose,
|
||||
} from '../../../common/src/utils/circuits/generateInputs';
|
||||
import { fetchTreeFromUrl } from '../../../common/src/utils/trees';
|
||||
import { revealBitmapFromAttributes } from '../../../common/src/utils/circuits/formatOutputs';
|
||||
import { PassportData } from '../../../common/src/utils/types';
|
||||
import useUserStore from '../stores/userStore';
|
||||
|
||||
@@ -99,7 +99,7 @@ export const generateCircuitInputsInApp = async (
|
||||
disclosureOptionsDisclose.excludedCountries.value.map(country =>
|
||||
getCountryCode(country),
|
||||
);
|
||||
return generateCircuitInputsDisclose(
|
||||
return generateCircuitInputsVCandDisclose(
|
||||
secret,
|
||||
PASSPORT_ATTESTATION_ID,
|
||||
passportData,
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as Keychain from 'react-native-keychain';
|
||||
|
||||
import { ethers } from 'ethers';
|
||||
|
||||
import { PassportMetadata } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
|
||||
import { PassportData } from '../../../common/src/utils/types';
|
||||
|
||||
export async function loadSecretOrCreateIt() {
|
||||
@@ -36,3 +37,18 @@ export async function storePassportData(passportData: PassportData) {
|
||||
{ service: 'passportData' },
|
||||
);
|
||||
}
|
||||
|
||||
export async function loadPassportMetadata() {
|
||||
const metadataCreds = await Keychain.getGenericPassword({
|
||||
service: 'passportMetadata',
|
||||
});
|
||||
return metadataCreds === false ? false : metadataCreds.password;
|
||||
}
|
||||
|
||||
export async function storePassportMetadata(metadata: PassportMetadata) {
|
||||
await Keychain.setGenericPassword(
|
||||
'passportMetadata',
|
||||
JSON.stringify(metadata),
|
||||
{ service: 'passportMetadata' },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,9 @@ import { NativeModules, Platform } from 'react-native';
|
||||
import PassportReader from 'react-native-passport-reader';
|
||||
|
||||
// @ts-ignore
|
||||
import * as amplitude from '@amplitude/analytics-react-native';
|
||||
import { Buffer } from 'buffer';
|
||||
|
||||
import { parsePassportData } from '../../../common/src/utils/parsePassportData';
|
||||
import { parsePassportData } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
|
||||
import { PassportData } from '../../../common/src/utils/types';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import useUserStore from '../stores/userStore';
|
||||
@@ -16,12 +15,15 @@ export const scan = async (
|
||||
) => {
|
||||
const { passportNumber, dateOfBirth, dateOfExpiry } = useUserStore.getState();
|
||||
|
||||
const { toast } = useNavigationStore.getState();
|
||||
const { toast, trackEvent } = useNavigationStore.getState();
|
||||
|
||||
const check = checkInputs(passportNumber, dateOfBirth, dateOfExpiry);
|
||||
|
||||
if (!check.success) {
|
||||
amplitude.track('inputs_invalid', { error: check.message });
|
||||
trackEvent('Inputs Failed', {
|
||||
success: false,
|
||||
error: check.message,
|
||||
});
|
||||
toast.show('Unvailable', {
|
||||
message: check.message,
|
||||
customData: {
|
||||
@@ -31,20 +33,26 @@ export const scan = async (
|
||||
return;
|
||||
}
|
||||
|
||||
trackEvent('NFC Started', {
|
||||
success: true,
|
||||
});
|
||||
|
||||
console.log('scanning...');
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
scanAndroid(setModalProofStep);
|
||||
scanAndroid(setModalProofStep, Date.now());
|
||||
} else {
|
||||
scanIOS(setModalProofStep);
|
||||
scanIOS(setModalProofStep, Date.now());
|
||||
}
|
||||
};
|
||||
|
||||
const scanAndroid = async (
|
||||
setModalProofStep: (modalProofStep: number) => void,
|
||||
startTime: number,
|
||||
) => {
|
||||
const { passportNumber, dateOfBirth, dateOfExpiry } = useUserStore.getState();
|
||||
const { toast, setNfcSheetIsOpen } = useNavigationStore.getState();
|
||||
const { toast, setNfcSheetIsOpen, trackEvent } =
|
||||
useNavigationStore.getState();
|
||||
setNfcSheetIsOpen(true);
|
||||
|
||||
try {
|
||||
@@ -55,12 +63,15 @@ const scanAndroid = async (
|
||||
});
|
||||
console.log('scanned');
|
||||
setNfcSheetIsOpen(false);
|
||||
amplitude.track('nfc_scan_successful');
|
||||
handleResponseAndroid(response, setModalProofStep);
|
||||
|
||||
trackEvent('NFC Success', {
|
||||
success: true,
|
||||
duration_ms: Date.now() - startTime,
|
||||
});
|
||||
} catch (e: any) {
|
||||
console.log('error during scan:', e);
|
||||
setNfcSheetIsOpen(false);
|
||||
amplitude.track('nfc_scan_unsuccessful', { error: e.message });
|
||||
if (e.message.includes('InvalidMRZKey')) {
|
||||
toast.show('Error', {
|
||||
message:
|
||||
@@ -70,6 +81,10 @@ const scanAndroid = async (
|
||||
},
|
||||
timeout: 5000,
|
||||
});
|
||||
trackEvent('Invalid Key', {
|
||||
success: false,
|
||||
error: e.message,
|
||||
});
|
||||
useNavigationStore.getState().setSelectedTab('scan');
|
||||
} else {
|
||||
toast.show('Error', {
|
||||
@@ -78,13 +93,21 @@ const scanAndroid = async (
|
||||
type: 'error',
|
||||
},
|
||||
});
|
||||
trackEvent('NFC Failed', {
|
||||
success: false,
|
||||
error: e.message,
|
||||
duration_ms: Date.now() - startTime,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const scanIOS = async (setModalProofStep: (modalProofStep: number) => void) => {
|
||||
const scanIOS = async (
|
||||
setModalProofStep: (modalProofStep: number) => void,
|
||||
startTime: number,
|
||||
) => {
|
||||
const { passportNumber, dateOfBirth, dateOfExpiry } = useUserStore.getState();
|
||||
const { toast } = useNavigationStore.getState();
|
||||
const { toast, trackEvent } = useNavigationStore.getState();
|
||||
|
||||
console.log('passportNumber', passportNumber);
|
||||
console.log('dateOfBirth', dateOfBirth);
|
||||
@@ -98,18 +121,13 @@ const scanIOS = async (setModalProofStep: (modalProofStep: number) => void) => {
|
||||
);
|
||||
console.log('scanned');
|
||||
handleResponseIOS(response, setModalProofStep);
|
||||
amplitude.track('nfc_scan_successful');
|
||||
|
||||
trackEvent('NFC Success', {
|
||||
success: true,
|
||||
duration_ms: Date.now() - startTime,
|
||||
});
|
||||
} catch (e: any) {
|
||||
console.log('error during scan:', e);
|
||||
amplitude.track('nfc_scan_unsuccessful', { error: e.message });
|
||||
// if (!e.message.includes("UserCanceled")) {
|
||||
// toast.show('Failed to read passport', {
|
||||
// message: e.message,
|
||||
// customData: {
|
||||
// type: "error",
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
if (e.message.includes('InvalidMRZKey')) {
|
||||
toast.show('Error', {
|
||||
message:
|
||||
@@ -120,6 +138,10 @@ const scanIOS = async (setModalProofStep: (modalProofStep: number) => void) => {
|
||||
timeout: 5000,
|
||||
});
|
||||
useNavigationStore.getState().setSelectedTab('scan');
|
||||
trackEvent('Invalid Key', {
|
||||
success: false,
|
||||
error: e.message,
|
||||
});
|
||||
} else {
|
||||
toast.show('Error', {
|
||||
message: e.message,
|
||||
@@ -127,6 +149,10 @@ const scanIOS = async (setModalProofStep: (modalProofStep: number) => void) => {
|
||||
type: 'error',
|
||||
},
|
||||
});
|
||||
trackEvent('NFC Failed', {
|
||||
success: false,
|
||||
error: e.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -135,7 +161,7 @@ const handleResponseIOS = async (
|
||||
response: any,
|
||||
_setModalProofStep: (modalProofStep: number) => void,
|
||||
) => {
|
||||
const { toast } = useNavigationStore.getState();
|
||||
const { toast, trackEvent } = useNavigationStore.getState();
|
||||
|
||||
const parsed = JSON.parse(response);
|
||||
|
||||
@@ -149,21 +175,16 @@ const handleResponseIOS = async (
|
||||
const signedAttributes = parsed?.signedAttributes; // this is what we call eContent in android world
|
||||
const mrz = parsed?.passportMRZ;
|
||||
const signatureBase64 = parsed?.signatureBase64;
|
||||
console.log('dataGroupsPresent', parsed?.dataGroupsPresent);
|
||||
console.log('placeOfBirth', parsed?.placeOfBirth);
|
||||
console.log('activeAuthenticationPassed', parsed?.activeAuthenticationPassed);
|
||||
console.log('isPACESupported', parsed?.isPACESupported);
|
||||
console.log(
|
||||
'isChipAuthenticationSupported',
|
||||
parsed?.isChipAuthenticationSupported,
|
||||
);
|
||||
console.log('residenceAddress', parsed?.residenceAddress);
|
||||
console.log('passportPhoto', parsed?.passportPhoto.substring(0, 100) + '...');
|
||||
console.log(
|
||||
'encapsulatedContentDigestAlgorithm',
|
||||
parsed?.encapsulatedContentDigestAlgorithm,
|
||||
);
|
||||
console.log('documentSigningCertificate', parsed?.documentSigningCertificate);
|
||||
const pem = JSON.parse(parsed?.documentSigningCertificate).PEM.replace(
|
||||
/\n/g,
|
||||
'',
|
||||
@@ -186,18 +207,6 @@ const handleResponseIOS = async (
|
||||
Buffer.from(signatureBase64, 'base64'),
|
||||
).map(byte => (byte > 127 ? byte - 256 : byte));
|
||||
|
||||
// amplitude.track('nfc_response_parsed', {
|
||||
// dataGroupsPresent: parsed?.dataGroupsPresent,
|
||||
// eContentLength: signedEContentArray?.length,
|
||||
// concatenatedDataHashesLength: concatenatedDataHashesArraySigned?.length,
|
||||
// encryptedDigestLength: encryptedDigestArray?.length,
|
||||
// activeAuthenticationPassed: parsed?.activeAuthenticationPassed,
|
||||
// isPACESupported: parsed?.isPACESupported,
|
||||
// isChipAuthenticationSupported: parsed?.isChipAuthenticationSupported,
|
||||
// encapsulatedContentDigestAlgorithm: parsed?.encapsulatedContentDigestAlgorithm,
|
||||
// dsc: pem,
|
||||
// });
|
||||
|
||||
const passportData = {
|
||||
mrz,
|
||||
dsc: pem,
|
||||
@@ -207,24 +216,28 @@ const handleResponseIOS = async (
|
||||
eContent: concatenatedDataHashesArraySigned,
|
||||
signedAttr: signedEContentArray,
|
||||
encryptedDigest: encryptedDigestArray,
|
||||
photoBase64: 'data:image/jpeg;base64,' + parsed.passportPhoto,
|
||||
photoBase64: parsed?.passportPhoto
|
||||
? 'data:image/jpeg;base64,' + parsed?.passportPhoto
|
||||
: '',
|
||||
mockUser: false,
|
||||
parsed: false,
|
||||
};
|
||||
const parsedPassportData = parsePassportData(passportData);
|
||||
amplitude.track('nfc_response_parsed', parsedPassportData);
|
||||
|
||||
try {
|
||||
useUserStore.getState().registerPassportData(passportData);
|
||||
useNavigationStore.getState().setSelectedTab('next');
|
||||
parsePassportDataAsync(passportData);
|
||||
} catch (e: any) {
|
||||
console.log('error during parsing:', e);
|
||||
amplitude.track('error_parsing_nfc_response', { error: e.message });
|
||||
toast.show('Error', {
|
||||
toast.show('Error during passport data parsing', {
|
||||
message: e.message,
|
||||
customData: {
|
||||
type: 'error',
|
||||
},
|
||||
});
|
||||
|
||||
trackEvent('Passport ParseFailed', {
|
||||
success: false,
|
||||
error: e.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -232,18 +245,18 @@ const handleResponseAndroid = async (
|
||||
response: any,
|
||||
_setModalProofStep: (modalProofStep: number) => void,
|
||||
) => {
|
||||
const { toast } = useNavigationStore.getState();
|
||||
const { toast, trackEvent } = useNavigationStore.getState();
|
||||
|
||||
const {
|
||||
mrz,
|
||||
eContent,
|
||||
encryptedDigest,
|
||||
photo,
|
||||
digestAlgorithm,
|
||||
signerInfoDigestAlgorithm,
|
||||
digestEncryptionAlgorithm,
|
||||
LDSVersion,
|
||||
unicodeVersion,
|
||||
// digestAlgorithm,
|
||||
// signerInfoDigestAlgorithm,
|
||||
// digestEncryptionAlgorithm,
|
||||
// LDSVersion,
|
||||
// unicodeVersion,
|
||||
encapContent,
|
||||
documentSigningCertificate,
|
||||
dataGroupHashes,
|
||||
@@ -272,8 +285,9 @@ const handleResponseAndroid = async (
|
||||
eContent: JSON.parse(encapContent),
|
||||
signedAttr: JSON.parse(eContent),
|
||||
encryptedDigest: JSON.parse(encryptedDigest),
|
||||
photoBase64: photo.base64,
|
||||
photoBase64: photo?.base64 ?? '',
|
||||
mockUser: false,
|
||||
parsed: false,
|
||||
};
|
||||
|
||||
console.log(
|
||||
@@ -287,7 +301,7 @@ const handleResponseAndroid = async (
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
/***
|
||||
console.log('mrz', passportData?.mrz);
|
||||
console.log('dataGroupHashes', passportData?.eContent);
|
||||
console.log('eContent', passportData?.eContent);
|
||||
@@ -303,31 +317,56 @@ const handleResponseAndroid = async (
|
||||
console.log('unicodeVersion', unicodeVersion);
|
||||
console.log('encapContent', encapContent);
|
||||
console.log('documentSigningCertificate', documentSigningCertificate);
|
||||
|
||||
const parsedPassportData = parsePassportData(passportData);
|
||||
amplitude.track('nfc_response_parsed', parsedPassportData);
|
||||
// amplitude.track('nfc_response_parsed', {
|
||||
// dataGroupHashesLength: passportData?.eContent?.length,
|
||||
// eContentLength: passportData?.eContent?.length,
|
||||
// encryptedDigestLength: passportData?.encryptedDigest?.length,
|
||||
// digestAlgorithm: digestAlgorithm,
|
||||
// signerInfoDigestAlgorithm: signerInfoDigestAlgorithm,
|
||||
// digestEncryptionAlgorithm: digestEncryptionAlgorithm,
|
||||
// dsc: pem,
|
||||
// mockUser: false
|
||||
// });
|
||||
***/
|
||||
|
||||
try {
|
||||
await useUserStore.getState().registerPassportData(passportData);
|
||||
useNavigationStore.getState().setSelectedTab('next');
|
||||
parsePassportDataAsync(passportData);
|
||||
} catch (e: any) {
|
||||
console.log('error during parsing:', e);
|
||||
amplitude.track('error_parsing_nfc_response', { error: e.message });
|
||||
toast.show('Error', {
|
||||
message: e.message,
|
||||
customData: {
|
||||
type: 'error',
|
||||
},
|
||||
});
|
||||
|
||||
trackEvent('Passport ParseFailed', {
|
||||
success: false,
|
||||
error: e.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
async function parsePassportDataAsync(passportData: PassportData) {
|
||||
const { trackEvent } = useNavigationStore.getState();
|
||||
const parsedPassportData = parsePassportData(passportData);
|
||||
useUserStore.getState().setPassportMetadata(parsedPassportData);
|
||||
await useUserStore.getState().registerPassportData(passportData);
|
||||
trackEvent('Passport Parsed', {
|
||||
success: true,
|
||||
data_groups: parsedPassportData.dataGroups,
|
||||
dg1_hash_function: parsedPassportData.dg1HashFunction,
|
||||
dg1_hash_offset: parsedPassportData.dg1HashOffset,
|
||||
dg_padding_bytes: parsedPassportData.dgPaddingBytes,
|
||||
e_content_size: parsedPassportData.eContentSize,
|
||||
e_content_hash_function: parsedPassportData.eContentHashFunction,
|
||||
e_content_hash_offset: parsedPassportData.eContentHashOffset,
|
||||
signed_attr_size: parsedPassportData.signedAttrSize,
|
||||
signed_attr_hash_function: parsedPassportData.signedAttrHashFunction,
|
||||
signature_algorithm: parsedPassportData.signatureAlgorithm,
|
||||
salt_length: parsedPassportData.saltLength,
|
||||
curve_or_exponent: parsedPassportData.curveOrExponent,
|
||||
signature_algorithm_bits: parsedPassportData.signatureAlgorithmBits,
|
||||
country_code: parsedPassportData.countryCode,
|
||||
csca_found: parsedPassportData.cscaFound,
|
||||
csca_hash_function: parsedPassportData.cscaHashFunction,
|
||||
csca_signature_algorithm: parsedPassportData.cscaSignatureAlgorithm,
|
||||
csca_salt_length: parsedPassportData.cscaSaltLength,
|
||||
csca_curve_or_exponent: parsedPassportData.cscaCurveOrExponent,
|
||||
csca_signature_algorithm_bits:
|
||||
parsedPassportData.cscaSignatureAlgorithmBits,
|
||||
dsc: parsedPassportData.dsc,
|
||||
});
|
||||
|
||||
useNavigationStore.getState().setSelectedTab('next');
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as amplitude from '@amplitude/analytics-react-native';
|
||||
import '@react-navigation/native';
|
||||
import { Buffer } from 'buffer';
|
||||
|
||||
import { parsePassportData } from '../../../common/src/utils/parsePassportData';
|
||||
import { parsePassportData } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
|
||||
import { PassportData } from '../../../common/src/utils/types';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import useUserStore from '../stores/userStore';
|
||||
@@ -179,6 +179,7 @@ const handleResponseIOS = async (response: any) => {
|
||||
encryptedDigest: encryptedDigestArray,
|
||||
photoBase64: 'data:image/jpeg;base64,' + parsed.passportPhoto,
|
||||
mockUser: false,
|
||||
parsed: false,
|
||||
};
|
||||
const parsedPassportData = parsePassportData(passportData);
|
||||
amplitude.track('nfc_response_parsed', parsedPassportData);
|
||||
@@ -238,6 +239,7 @@ const handleResponseAndroid = async (response: any) => {
|
||||
encryptedDigest: JSON.parse(encryptedDigest),
|
||||
photoBase64: photo.base64,
|
||||
mockUser: false,
|
||||
parsed: false,
|
||||
};
|
||||
|
||||
console.log(
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
import { NativeModules, Platform } from 'react-native';
|
||||
import RNFS from 'react-native-fs';
|
||||
|
||||
import * as amplitude from '@amplitude/analytics-react-native';
|
||||
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import { parseProofAndroid } from './utils';
|
||||
|
||||
export const generateProof = async (circuit: string, inputs: any) => {
|
||||
console.log('launching generateProof function');
|
||||
console.log('inputs in prover.ts', inputs);
|
||||
console.log('circuit', circuit);
|
||||
const startTime = Date.now();
|
||||
const { trackEvent } = useNavigationStore.getState();
|
||||
|
||||
trackEvent('Proof Started', {
|
||||
success: true,
|
||||
circuit: circuit,
|
||||
});
|
||||
|
||||
// Example: "/data/user/0/com.proofofpassportapp/files/register_sha256WithRSAEncryption_65537.zkey" on android
|
||||
const zkey_path = `${RNFS.DocumentDirectoryPath}/${circuit}.zkey`;
|
||||
const dat_path = `${RNFS.DocumentDirectoryPath}/${circuit}.dat`;
|
||||
|
||||
const witness_calculator = circuit;
|
||||
|
||||
if (!zkey_path || !witness_calculator || !dat_path) {
|
||||
trackEvent('Proof Failed', {
|
||||
success: false,
|
||||
error: 'Required parameters are missing',
|
||||
circuit: circuit,
|
||||
});
|
||||
throw new Error('Required parameters are missing');
|
||||
}
|
||||
console.log('zkey_path', zkey_path);
|
||||
console.log('witness_calculator', witness_calculator);
|
||||
console.log('dat_path', dat_path);
|
||||
|
||||
try {
|
||||
const response = await NativeModules.Prover.runProveAction(
|
||||
@@ -31,15 +34,24 @@ export const generateProof = async (circuit: string, inputs: any) => {
|
||||
inputs,
|
||||
);
|
||||
|
||||
// console.log('local proof:', response);
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
const parsedResponse = parseProofAndroid(response);
|
||||
console.log('parsedResponse', parsedResponse);
|
||||
|
||||
trackEvent('Proof Generated', {
|
||||
success: true,
|
||||
duration_ms: Date.now() - startTime,
|
||||
circuit: circuit,
|
||||
});
|
||||
|
||||
return formatProof(parsedResponse);
|
||||
} else {
|
||||
const parsedResponse = JSON.parse(response);
|
||||
console.log('parsedResponse', parsedResponse);
|
||||
|
||||
trackEvent('Proof Generated', {
|
||||
success: true,
|
||||
duration_ms: Date.now() - startTime,
|
||||
circuit: circuit,
|
||||
});
|
||||
|
||||
return formatProof({
|
||||
proof: parsedResponse.proof,
|
||||
@@ -47,31 +59,47 @@ export const generateProof = async (circuit: string, inputs: any) => {
|
||||
});
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.log('err', err);
|
||||
amplitude.track('error_generating_proof', {
|
||||
trackEvent('Proof Failed', {
|
||||
success: false,
|
||||
error: err.message,
|
||||
duration_ms: Date.now() - startTime,
|
||||
circuit: circuit,
|
||||
zkey_path: zkey_path,
|
||||
witness_calculator: witness_calculator,
|
||||
dat_path: dat_path,
|
||||
});
|
||||
|
||||
throw new Error(err);
|
||||
}
|
||||
};
|
||||
|
||||
export const formatProof = (rawProof: any): any => {
|
||||
return {
|
||||
proof: {
|
||||
pi_a: [rawProof.proof.a[0], rawProof.proof.a[1], '1'],
|
||||
pi_b: [
|
||||
[rawProof.proof.b[0][0], rawProof.proof.b[0][1]],
|
||||
[rawProof.proof.b[1][0], rawProof.proof.b[1][1]],
|
||||
['1', '0'],
|
||||
],
|
||||
pi_c: [rawProof.proof.c[0], rawProof.proof.c[1], '1'],
|
||||
protocol: 'groth16',
|
||||
curve: 'bn128',
|
||||
},
|
||||
publicSignals: (rawProof as any).pub_signals,
|
||||
};
|
||||
const { trackEvent } = useNavigationStore.getState();
|
||||
try {
|
||||
const formattedProof = {
|
||||
proof: {
|
||||
pi_a: [rawProof.proof.a[0], rawProof.proof.a[1], '1'],
|
||||
pi_b: [
|
||||
[rawProof.proof.b[0][0], rawProof.proof.b[0][1]],
|
||||
[rawProof.proof.b[1][0], rawProof.proof.b[1][1]],
|
||||
['1', '0'],
|
||||
],
|
||||
pi_c: [rawProof.proof.c[0], rawProof.proof.c[1], '1'],
|
||||
protocol: 'groth16',
|
||||
curve: 'bn128',
|
||||
},
|
||||
publicSignals: (rawProof as any).pub_signals,
|
||||
};
|
||||
trackEvent('Proof Formatted', {
|
||||
success: true,
|
||||
});
|
||||
|
||||
return formattedProof;
|
||||
} catch (err: any) {
|
||||
trackEvent('Proof FormatFailed', {
|
||||
success: false,
|
||||
error: err.message,
|
||||
});
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@ import pako from 'pako';
|
||||
|
||||
import { Mode, OpenPassportApp } from '../../../common/src/utils/appType';
|
||||
import { getCircuitNameOld } from '../../../common/src/utils/certificate_parsing/parseCertificateSimple';
|
||||
import { parsePassportData } from '../../../common/src/utils/parsePassportData';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import useUserStore from '../stores/userStore';
|
||||
import { downloadZkey } from './zkeyDownload';
|
||||
@@ -26,81 +25,66 @@ export const scanQRCode = () => {
|
||||
const { toast, setSelectedApp, setSelectedTab } =
|
||||
useNavigationStore.getState();
|
||||
|
||||
Linking.getInitialURL()
|
||||
.then(url => {
|
||||
if (url) {
|
||||
handleUniversalLink(url);
|
||||
} else {
|
||||
if (Platform.OS === 'ios') {
|
||||
console.log('Scanning QR code on iOS without Universal Link');
|
||||
|
||||
const qrScanner = NativeModules.QRScannerBridge;
|
||||
if (qrScanner && qrScanner.scanQRCode) {
|
||||
qrScanner
|
||||
.scanQRCode()
|
||||
.then((result: string) => {
|
||||
const params = parseUrlParams(result);
|
||||
const encodedData = params.get('data');
|
||||
handleQRCodeScan(
|
||||
encodedData as string,
|
||||
toast,
|
||||
setSelectedApp,
|
||||
setSelectedTab,
|
||||
);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error('QR Scanner Error:', error);
|
||||
toast.show('Error', {
|
||||
message: 'Failed to scan QR code',
|
||||
type: 'error',
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.error('QR Scanner module not found for iOS');
|
||||
toast.show('Error', {
|
||||
message: 'QR Scanner not available',
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
} else if (Platform.OS === 'android') {
|
||||
const qrScanner = NativeModules.QRCodeScanner;
|
||||
if (qrScanner && qrScanner.scanQRCode) {
|
||||
qrScanner
|
||||
.scanQRCode()
|
||||
.then((result: string) => {
|
||||
const params = parseUrlParams(result);
|
||||
const encodedData = params.get('data');
|
||||
handleQRCodeScan(
|
||||
encodedData as string,
|
||||
toast,
|
||||
setSelectedApp,
|
||||
setSelectedTab,
|
||||
);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error('QR Scanner Error:', error);
|
||||
toast.show('Error', {
|
||||
message: 'Failed to scan QR code',
|
||||
type: 'error',
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.error('QR Scanner module not found for Android');
|
||||
toast.show('Error', {
|
||||
message: 'QR Scanner not available',
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('An error occurred while getting initial URL', err);
|
||||
if (Platform.OS === 'ios') {
|
||||
console.log('Scanning QR code on iOS');
|
||||
const qrScanner = NativeModules.QRScannerBridge;
|
||||
if (qrScanner && qrScanner.scanQRCode) {
|
||||
qrScanner
|
||||
.scanQRCode()
|
||||
.then((result: string) => {
|
||||
const params = parseUrlParams(result);
|
||||
const encodedData = params.get('data');
|
||||
handleQRCodeScan(
|
||||
encodedData as string,
|
||||
toast,
|
||||
setSelectedApp,
|
||||
setSelectedTab,
|
||||
);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error('QR Scanner Error:', error);
|
||||
toast.show('Error', {
|
||||
message: 'Failed to scan QR code',
|
||||
type: 'error',
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.error('QR Scanner module not found for iOS');
|
||||
toast.show('Error', {
|
||||
message: 'Failed to process initial link',
|
||||
message: 'QR Scanner not available',
|
||||
type: 'error',
|
||||
});
|
||||
});
|
||||
}
|
||||
} else if (Platform.OS === 'android') {
|
||||
const qrScanner = NativeModules.QRCodeScanner;
|
||||
if (qrScanner && qrScanner.scanQRCode) {
|
||||
qrScanner
|
||||
.scanQRCode()
|
||||
.then((result: string) => {
|
||||
const params = parseUrlParams(result);
|
||||
const encodedData = params.get('data');
|
||||
handleQRCodeScan(
|
||||
encodedData as string,
|
||||
toast,
|
||||
setSelectedApp,
|
||||
setSelectedTab,
|
||||
);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error('QR Scanner Error:', error);
|
||||
toast.show('Error', {
|
||||
message: 'Failed to scan QR code',
|
||||
type: 'error',
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.error('QR Scanner module not found for Android');
|
||||
toast.show('Error', {
|
||||
message: 'QR Scanner not available',
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleQRCodeScan = (
|
||||
@@ -110,8 +94,8 @@ const handleQRCodeScan = (
|
||||
setSelectedTab: any,
|
||||
) => {
|
||||
try {
|
||||
const passportData = useUserStore.getState().passportData;
|
||||
if (passportData) {
|
||||
const { passportData, passportMetadata } = useUserStore.getState();
|
||||
if (passportData && passportMetadata) {
|
||||
const decodedResult = atob(result);
|
||||
const uint8Array = new Uint8Array(
|
||||
decodedResult.split('').map(char => char.charCodeAt(0)),
|
||||
@@ -120,7 +104,6 @@ const handleQRCodeScan = (
|
||||
const unpackedData = msgpack.decode(decompressedData);
|
||||
const openPassportApp: OpenPassportApp = unpackedData;
|
||||
setSelectedApp(openPassportApp);
|
||||
const passportMetadata = parsePassportData(passportData);
|
||||
|
||||
const circuitName =
|
||||
openPassportApp.mode === 'vc_and_disclose'
|
||||
|
||||
@@ -5,7 +5,7 @@ import pako from 'pako';
|
||||
|
||||
import { Mode, OpenPassportApp } from '../../../common/src/utils/appType';
|
||||
import { getCircuitNameOld } from '../../../common/src/utils/certificate_parsing/parseCertificateSimple';
|
||||
import { parsePassportData } from '../../../common/src/utils/parsePassportData';
|
||||
import { parsePassportData } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import useUserStore from '../stores/userStore';
|
||||
import { downloadZkey } from './zkeyDownload';
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
import { LeanIMT, LeanIMTHashFunction } from '@openpassport/zk-kit-lean-imt';
|
||||
import axios from 'axios';
|
||||
import { poseidon2 } from 'poseidon-lite';
|
||||
|
||||
import {
|
||||
COMMITMENT_TREE_TRACKER_URL,
|
||||
PASSPORT_ATTESTATION_ID,
|
||||
} from '../../../common/src/constants/constants';
|
||||
import { findIndexInTree } from '../../../common/src/utils/generateInputs';
|
||||
import {
|
||||
generateCommitment,
|
||||
getLeaf,
|
||||
} from '../../../common/src/utils/pubkeyTree';
|
||||
import { PassportData } from '../../../common/src/utils/types';
|
||||
import { formatMrz, packBytes } from '../../../common/src/utils/utils';
|
||||
|
||||
export async function isCommitmentRegistered(
|
||||
secret: string,
|
||||
passportData: PassportData,
|
||||
) {
|
||||
let response;
|
||||
|
||||
console.log(COMMITMENT_TREE_TRACKER_URL);
|
||||
try {
|
||||
response = await axios.get(COMMITMENT_TREE_TRACKER_URL);
|
||||
} catch (error) {
|
||||
console.error('Error fetching commitment tree:', error);
|
||||
throw error; // rethrow the error after logging
|
||||
}
|
||||
console.log('response.data:', response.data);
|
||||
|
||||
const hashFunction: LeanIMTHashFunction = (a: bigint, b: bigint) =>
|
||||
poseidon2([a, b]);
|
||||
const imt = LeanIMT.import(hashFunction, response.data);
|
||||
|
||||
const pubkey_leaf = getLeaf(passportData.dsc);
|
||||
|
||||
const formattedMrz = formatMrz(passportData.mrz);
|
||||
const mrz_bytes = packBytes(formattedMrz);
|
||||
const commitment = generateCommitment(
|
||||
secret,
|
||||
PASSPORT_ATTESTATION_ID,
|
||||
pubkey_leaf,
|
||||
mrz_bytes,
|
||||
passportData.dg2Hash?.map(x => x.toString()) || [],
|
||||
);
|
||||
|
||||
console.log('commitment', commitment.toString());
|
||||
|
||||
try {
|
||||
findIndexInTree(imt as any, commitment); // this will throw if not found
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { ethers } from 'ethers';
|
||||
|
||||
import {
|
||||
CHAIN_NAME,
|
||||
RELAYER_URL,
|
||||
RPC_URL,
|
||||
SignatureAlgorithmIndex,
|
||||
} from '../../../common/src/constants/constants';
|
||||
import {
|
||||
formatCallData_disclose,
|
||||
formatCallData_dsc,
|
||||
formatCallData_register,
|
||||
} from '../../../common/src/utils/formatCallData';
|
||||
import { Proof } from '../../../common/src/utils/types';
|
||||
import registerArtefacts from '../../deployments/artifacts/Deploy_Registry#OpenPassportRegister.json';
|
||||
import sbtArtefacts from '../../deployments/artifacts/Deploy_Registry#SBT.json';
|
||||
import contractAddresses from '../../deployments/deployed_addresses.json';
|
||||
import groth16ExportSolidityCallData from './snarkjs';
|
||||
|
||||
export const sendRegisterTransaction = async (
|
||||
proof: Proof,
|
||||
cscaProof: Proof,
|
||||
sigAlgIndex: SignatureAlgorithmIndex,
|
||||
) => {
|
||||
const provider = new ethers.JsonRpcProvider(RPC_URL);
|
||||
|
||||
if (
|
||||
!contractAddresses['Deploy_Registry#OpenPassportRegister'] ||
|
||||
!registerArtefacts.abi
|
||||
) {
|
||||
console.log('contracts addresses or abi not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// Format the proof and publicInputs as calldata for the verifier contract
|
||||
//console.log("exporting local proof:", proof, proof.proof, proof.pub_signals);
|
||||
const cd = groth16ExportSolidityCallData(proof.proof, proof.pub_signals);
|
||||
const callData = JSON.parse(`[${cd}]`);
|
||||
//console.log('callData', callData);
|
||||
const formattedCallData_register = formatCallData_register(callData);
|
||||
console.log('formattedCallData_register', formattedCallData_register);
|
||||
|
||||
//console.log("exporting csca proof", cscaProof, cscaProof.proof, cscaProof.pub_signals)
|
||||
const cd_csca = groth16ExportSolidityCallData(
|
||||
cscaProof.proof,
|
||||
cscaProof.pub_signals,
|
||||
);
|
||||
const callData_csca = JSON.parse(`[${cd_csca}]`);
|
||||
//console.log('callData_csca', callData_csca);
|
||||
const formattedCallData_csca = formatCallData_dsc(callData_csca);
|
||||
console.log('formattedCallData_csca', formattedCallData_csca);
|
||||
|
||||
try {
|
||||
const registerContract = new ethers.Contract(
|
||||
contractAddresses['Deploy_Registry#OpenPassportRegister'],
|
||||
registerArtefacts.abi,
|
||||
provider,
|
||||
);
|
||||
|
||||
const transactionRequest =
|
||||
await registerContract.validateProof.populateTransaction(
|
||||
formattedCallData_register,
|
||||
formattedCallData_csca,
|
||||
sigAlgIndex,
|
||||
sigAlgIndex,
|
||||
);
|
||||
console.log('transactionRequest', transactionRequest);
|
||||
|
||||
const response = await axios.post(RELAYER_URL, {
|
||||
chain: CHAIN_NAME,
|
||||
tx_data: transactionRequest,
|
||||
});
|
||||
console.log('response status', response.status);
|
||||
console.log('response data', response.data);
|
||||
return response;
|
||||
} catch (err: any) {
|
||||
console.log('err', err);
|
||||
if (err.isAxiosError && err.response) {
|
||||
const errorMessage = err.response.data.error;
|
||||
console.log('Server error message:', errorMessage);
|
||||
|
||||
// parse blockchain error and show it
|
||||
const match = errorMessage.match(/execution reverted: "([^"]*)"/);
|
||||
if (match && match[1]) {
|
||||
console.log('Parsed blockchain error:', match[1]);
|
||||
throw new Error(match[1]);
|
||||
} else {
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const mintSBT = async (proof: Proof) => {
|
||||
const provider = new ethers.JsonRpcProvider(RPC_URL);
|
||||
|
||||
if (!contractAddresses['Deploy_Registry#SBT'] || !sbtArtefacts.abi) {
|
||||
console.log('contracts addresses or abi not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// Format the proof and publicInputs as calldata for the verifier contract
|
||||
const cd = groth16ExportSolidityCallData(proof.proof, proof.pub_signals);
|
||||
const parsedCallData_disclose = JSON.parse(`[${cd}]`);
|
||||
console.log('parsedCallData_disclose', parsedCallData_disclose);
|
||||
|
||||
const formattedCallData_disclose = formatCallData_disclose(
|
||||
parsedCallData_disclose,
|
||||
);
|
||||
|
||||
try {
|
||||
const proofOfPassportContract = new ethers.Contract(
|
||||
contractAddresses['Deploy_Registry#SBT'],
|
||||
sbtArtefacts.abi,
|
||||
provider,
|
||||
);
|
||||
|
||||
const transactionRequest =
|
||||
await proofOfPassportContract.mint.populateTransaction(
|
||||
formattedCallData_disclose,
|
||||
);
|
||||
console.log('transactionRequest', transactionRequest);
|
||||
|
||||
const response = await axios.post(RELAYER_URL, {
|
||||
chain: CHAIN_NAME,
|
||||
tx_data: transactionRequest,
|
||||
});
|
||||
console.log('response status', response.status);
|
||||
console.log('response data', response.data);
|
||||
return response;
|
||||
} catch (err: any) {
|
||||
console.log('err', err);
|
||||
if (err.isAxiosError && err.response) {
|
||||
const errorMessage = err.response.data.error;
|
||||
console.log('Server error message:', errorMessage);
|
||||
|
||||
// parse blockchain error and show it
|
||||
const match = errorMessage.match(/execution reverted: "([^"]*)"/);
|
||||
if (match && match[1]) {
|
||||
console.log('Parsed blockchain error:', match[1]);
|
||||
throw new Error(match[1]);
|
||||
} else {
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -85,10 +85,14 @@ export const parseProofAndroid = (response: string) => {
|
||||
};
|
||||
|
||||
export function getFirstName(mrz: string): string {
|
||||
const names = mrz.split('<<');
|
||||
const firstName = names[1].split('<')[0].trim();
|
||||
const capitalized = firstName.charAt(0) + firstName.slice(1).toLowerCase();
|
||||
return capitalized || 'Unknown';
|
||||
try {
|
||||
const names = mrz.split('<<');
|
||||
const firstName = names[1].split('<')[0].trim();
|
||||
const capitalized = firstName.charAt(0) + firstName.slice(1).toLowerCase();
|
||||
return capitalized || 'Unknown';
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function checkInputs(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import RNFS from 'react-native-fs';
|
||||
import { unzip } from 'react-native-zip-archive';
|
||||
|
||||
import * as amplitude from '@amplitude/analytics-react-native';
|
||||
import NetInfo from '@react-native-community/netinfo';
|
||||
import axios from 'axios';
|
||||
|
||||
@@ -54,33 +53,59 @@ export type IsZkeyDownloading = {
|
||||
// => this should be fine is the function is never called after the commitment is registered.
|
||||
|
||||
export async function downloadZkey(circuit: CircuitName) {
|
||||
const { isZkeyDownloading, update } = useNavigationStore.getState();
|
||||
const { isZkeyDownloading, update, trackEvent } =
|
||||
useNavigationStore.getState();
|
||||
const startTime = Date.now();
|
||||
|
||||
trackEvent('Download Started', {
|
||||
success: true,
|
||||
circuit: circuit,
|
||||
});
|
||||
|
||||
const downloadRequired = await isDownloadRequired(circuit, isZkeyDownloading);
|
||||
if (!downloadRequired) {
|
||||
console.log(`zkey and dat for ${circuit} already downloaded`);
|
||||
amplitude.track('zkey_already_downloaded', { circuit: circuit });
|
||||
trackEvent('Download Skipped', {
|
||||
success: true,
|
||||
circuit: circuit,
|
||||
reason: 'already_downloaded',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const networkInfo = await NetInfo.fetch();
|
||||
console.log('Network type:', networkInfo.type);
|
||||
if (networkInfo.type === 'wifi') {
|
||||
fetchZkeyAndDat(circuit);
|
||||
} else {
|
||||
const zkeyResponse = await axios.head(zkeyZipUrls[circuit]);
|
||||
const datResponse = await axios.head(datZipUrls[circuit]);
|
||||
const expectedSize =
|
||||
parseInt(zkeyResponse.headers['content-length'], 10) +
|
||||
parseInt(datResponse.headers['content-length'], 10);
|
||||
try {
|
||||
const networkInfo = await NetInfo.fetch();
|
||||
if (networkInfo.type === 'wifi') {
|
||||
fetchZkeyAndDat(circuit);
|
||||
} else {
|
||||
const zkeyResponse = await axios.head(zkeyZipUrls[circuit]);
|
||||
const datResponse = await axios.head(datZipUrls[circuit]);
|
||||
const expectedSize =
|
||||
parseInt(zkeyResponse.headers['content-length'], 10) +
|
||||
parseInt(datResponse.headers['content-length'], 10);
|
||||
|
||||
update({
|
||||
showWarningModal: {
|
||||
show: true,
|
||||
update({
|
||||
showWarningModal: {
|
||||
show: true,
|
||||
circuit: circuit,
|
||||
size: expectedSize,
|
||||
},
|
||||
});
|
||||
|
||||
trackEvent('Download Paused', {
|
||||
success: true,
|
||||
circuit: circuit,
|
||||
size: expectedSize,
|
||||
},
|
||||
reason: 'no_wifi',
|
||||
expected_size: expectedSize,
|
||||
});
|
||||
}
|
||||
} catch (error: any) {
|
||||
trackEvent('Download Failed', {
|
||||
success: false,
|
||||
error: error.message,
|
||||
circuit: circuit,
|
||||
duration_ms: Date.now() - startTime,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,11 +161,19 @@ export async function isDownloadRequired(
|
||||
}
|
||||
|
||||
export async function fetchZkeyAndDat(circuit: CircuitName) {
|
||||
console.log(`fetching zkey and dat for ${circuit} ...`);
|
||||
amplitude.track('fetching_zkey_and_dat', { circuit: circuit });
|
||||
const startTime = Date.now();
|
||||
const {
|
||||
isZkeyDownloading,
|
||||
toast,
|
||||
update,
|
||||
setZkeyDownloadedPercentage,
|
||||
trackEvent,
|
||||
} = useNavigationStore.getState();
|
||||
|
||||
const { isZkeyDownloading, toast, update, setZkeyDownloadedPercentage } =
|
||||
useNavigationStore.getState();
|
||||
trackEvent('Files Download Started', {
|
||||
success: true,
|
||||
circuit: circuit,
|
||||
});
|
||||
|
||||
update({
|
||||
isZkeyDownloading: {
|
||||
@@ -149,7 +182,6 @@ export async function fetchZkeyAndDat(circuit: CircuitName) {
|
||||
},
|
||||
});
|
||||
|
||||
const startTime = Date.now();
|
||||
let previousPercentComplete = -1;
|
||||
|
||||
const downloadFile = async (url: string, fileName: string) => {
|
||||
@@ -158,7 +190,11 @@ export async function fetchZkeyAndDat(circuit: CircuitName) {
|
||||
toFile: `${RNFS.DocumentDirectoryPath}/${fileName}`,
|
||||
background: false,
|
||||
begin: () => {
|
||||
console.log(`Download of ${fileName} has begun`);
|
||||
trackEvent('File Download Started', {
|
||||
success: true,
|
||||
circuit: circuit,
|
||||
file_type: fileName.includes('zkey') ? 'zkey' : 'dat',
|
||||
});
|
||||
},
|
||||
progress: (res: any) => {
|
||||
if (fileName.endsWith('.zkey.zip')) {
|
||||
@@ -169,7 +205,6 @@ export async function fetchZkeyAndDat(circuit: CircuitName) {
|
||||
percentComplete % 5 === 0 &&
|
||||
percentComplete !== previousPercentComplete
|
||||
) {
|
||||
console.log(`${percentComplete}%`);
|
||||
previousPercentComplete = percentComplete;
|
||||
setZkeyDownloadedPercentage(percentComplete);
|
||||
}
|
||||
@@ -178,9 +213,11 @@ export async function fetchZkeyAndDat(circuit: CircuitName) {
|
||||
};
|
||||
|
||||
await RNFS.downloadFile(options).promise;
|
||||
console.log(`Download of ${fileName} complete`);
|
||||
RNFS.readDir(RNFS.DocumentDirectoryPath).then(result => {
|
||||
console.log('Directory contents before unzipping:', result);
|
||||
|
||||
trackEvent('File Download Completed', {
|
||||
success: true,
|
||||
circuit: circuit,
|
||||
file_type: fileName.includes('zkey') ? 'zkey' : 'dat',
|
||||
});
|
||||
};
|
||||
|
||||
@@ -198,60 +235,88 @@ export async function fetchZkeyAndDat(circuit: CircuitName) {
|
||||
},
|
||||
});
|
||||
|
||||
console.log(
|
||||
'zkey and dat download succeeded, took ' +
|
||||
(Date.now() - startTime) / 1000 +
|
||||
' seconds',
|
||||
);
|
||||
|
||||
await saveFileSize(circuit, 'zkey');
|
||||
await saveFileSize(circuit, 'dat');
|
||||
|
||||
await RNFS.unlink(`${RNFS.DocumentDirectoryPath}/${circuit}.zkey.zip`);
|
||||
await RNFS.unlink(`${RNFS.DocumentDirectoryPath}/${circuit}.dat.zip`);
|
||||
console.log('zip files deleted');
|
||||
|
||||
const result = await RNFS.readDir(RNFS.DocumentDirectoryPath);
|
||||
console.log('Directory contents at the end:', result);
|
||||
trackEvent('Files Download Completed', {
|
||||
success: true,
|
||||
circuit: circuit,
|
||||
duration_ms: Date.now() - startTime,
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
update({
|
||||
isZkeyDownloading: {
|
||||
...isZkeyDownloading,
|
||||
[circuit]: false,
|
||||
},
|
||||
});
|
||||
|
||||
trackEvent('Files Download Failed', {
|
||||
success: false,
|
||||
error: error.message,
|
||||
circuit: circuit,
|
||||
duration_ms: Date.now() - startTime,
|
||||
});
|
||||
|
||||
toast.show('Error', {
|
||||
message: `Error: ${error.message}`,
|
||||
customData: {
|
||||
type: 'error',
|
||||
},
|
||||
customData: { type: 'error' },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function unzipFile(circuit: CircuitName, fileType: 'zkey' | 'dat') {
|
||||
const unzipPath = `${RNFS.DocumentDirectoryPath}/${circuit}_temp`;
|
||||
await unzip(
|
||||
`${RNFS.DocumentDirectoryPath}/${circuit}.${fileType}.zip`,
|
||||
unzipPath,
|
||||
);
|
||||
const files = await RNFS.readDir(unzipPath);
|
||||
const targetFile = files.find(file => file.name.endsWith(`.${fileType}`));
|
||||
if (targetFile) {
|
||||
const destinationPath = `${RNFS.DocumentDirectoryPath}/${circuit}.${fileType}`;
|
||||
if (await RNFS.exists(destinationPath)) {
|
||||
await RNFS.unlink(destinationPath);
|
||||
console.log(`Old ${fileType} file deleted`);
|
||||
}
|
||||
await RNFS.moveFile(targetFile.path, destinationPath);
|
||||
console.log(`File moved to ${circuit}.${fileType}`);
|
||||
} else {
|
||||
throw new Error(
|
||||
`${fileType.toUpperCase()} file not found in the unzipped directory`,
|
||||
const { trackEvent } = useNavigationStore.getState();
|
||||
const startTime = Date.now();
|
||||
|
||||
trackEvent('File Unzip Started', {
|
||||
success: true,
|
||||
circuit: circuit,
|
||||
file_type: fileType,
|
||||
});
|
||||
|
||||
try {
|
||||
const unzipPath = `${RNFS.DocumentDirectoryPath}/${circuit}_temp`;
|
||||
await unzip(
|
||||
`${RNFS.DocumentDirectoryPath}/${circuit}.${fileType}.zip`,
|
||||
unzipPath,
|
||||
);
|
||||
const files = await RNFS.readDir(unzipPath);
|
||||
const targetFile = files.find(file => file.name.endsWith(`.${fileType}`));
|
||||
if (targetFile) {
|
||||
const destinationPath = `${RNFS.DocumentDirectoryPath}/${circuit}.${fileType}`;
|
||||
if (await RNFS.exists(destinationPath)) {
|
||||
await RNFS.unlink(destinationPath);
|
||||
console.log(`Old ${fileType} file deleted`);
|
||||
}
|
||||
await RNFS.moveFile(targetFile.path, destinationPath);
|
||||
console.log(`File moved to ${circuit}.${fileType}`);
|
||||
} else {
|
||||
throw new Error(
|
||||
`${fileType.toUpperCase()} file not found in the unzipped directory`,
|
||||
);
|
||||
}
|
||||
await RNFS.unlink(unzipPath);
|
||||
|
||||
trackEvent('File Unzip Completed', {
|
||||
success: true,
|
||||
circuit: circuit,
|
||||
file_type: fileType,
|
||||
duration_ms: Date.now() - startTime,
|
||||
});
|
||||
} catch (error: any) {
|
||||
trackEvent('File Unzip Failed', {
|
||||
success: false,
|
||||
error: error.message,
|
||||
circuit: circuit,
|
||||
file_type: fileType,
|
||||
duration_ms: Date.now() - startTime,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
await RNFS.unlink(unzipPath);
|
||||
}
|
||||
|
||||
async function saveFileSize(circuit: CircuitName, fileType: 'zkey' | 'dat') {
|
||||
|
||||
1330
app/yarn.lock
1330
app/yarn.lock
File diff suppressed because it is too large
Load Diff
3
circuits/.gitignore
vendored
3
circuits/.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
inputs
|
||||
build
|
||||
build/
|
||||
!scripts/build/
|
||||
node_modules/
|
||||
err.log
|
||||
.env
|
||||
@@ -1,64 +1,115 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../utils/passport/disclose/verify_commitment.circom";
|
||||
include "../utils/passport/disclose/disclose.circom";
|
||||
include "../utils/passport/disclose/proveCountryIsNotInList.circom";
|
||||
include "../utils/passport/ofac/ofac_name.circom";
|
||||
include "../utils/passport/disclose/verify_commitment.circom";
|
||||
include "../utils/passport/date/isValid.circom";
|
||||
|
||||
template VC_AND_DISCLOSE( nLevels,FORBIDDEN_COUNTRIES_LIST_LENGTH) {
|
||||
|
||||
/// @title VC_AND_DISCLOSE
|
||||
/// @notice Verify user's commitment is part of the merkle tree and optionally disclose data from DG1
|
||||
/// @param nLevels Maximum number of levels in the merkle tree
|
||||
/// @param MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH Maximum number of countries present in the forbidden countries list
|
||||
/// @input secret Secret of the user — used to reconstruct commitment and generate nullifier
|
||||
/// @input attestation_id Attestation ID of the credential used to generate the commitment
|
||||
/// @input dg1 Data group 1 of the passport
|
||||
/// @input eContent_shaBytes_packed_hash Hash of the eContent packed
|
||||
/// @input dsc_tree_leaf Leaf of the DSC tree, to keep a record of the full CSCA and DSC that were used
|
||||
/// @input merkle_root Root of the commitment merkle tree
|
||||
/// @input leaf_depth Actual size of the merkle tree
|
||||
/// @input path Path of the commitment in the merkle tree
|
||||
/// @input siblings Siblings of the commitment in the merkle tree
|
||||
/// @input selector_dg1 bitmap used which bytes from the dg1 are revealed
|
||||
/// @input majority Majority user wants to prove he is older than: YY — ASCII
|
||||
/// @input current_date Current date: YYMMDD — number
|
||||
/// @input selector_older_than bitmap used to reveal the majority
|
||||
/// @input forbidden_countries_list Forbidden countries list user wants to prove he is not from
|
||||
/// @input smt_leaf_key value of the leaf of the smt corresponding to his path
|
||||
/// @input smt_root root of the smt
|
||||
/// @input smt_siblings siblings of the smt
|
||||
/// @input selector_ofac bitmap used to reveal the OFAC verification result
|
||||
/// @input scope Scope of the application users generates the proof for
|
||||
/// @input user_identifier User identifier — address or UUID
|
||||
/// @output revealedData_packed Packed revealed data
|
||||
/// @output forbidden_countries_list_packed Packed forbidden countries list
|
||||
/// @output nullifier Scope nullifier - not deterministic on the passport data
|
||||
template VC_AND_DISCLOSE(nLevels, MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH) {
|
||||
signal input secret;
|
||||
signal input attestation_id;
|
||||
signal input pubkey_leaf;
|
||||
signal input dg1[93];
|
||||
signal input dg2_hash[64];
|
||||
signal input eContent_shaBytes_packed_hash;
|
||||
signal input dsc_tree_leaf;
|
||||
|
||||
signal input merkle_root;
|
||||
signal input merkletree_size;
|
||||
signal input leaf_depth;
|
||||
signal input path[nLevels];
|
||||
signal input siblings[nLevels];
|
||||
|
||||
signal input selector_dg1[88]; // 88 for MRZ
|
||||
signal input selector_older_than;
|
||||
signal input scope;
|
||||
signal input current_date[6]; // YYMMDD - num
|
||||
signal input majority[2]; // YY - ASCII
|
||||
signal input user_identifier;
|
||||
signal input selector_dg1[88];
|
||||
|
||||
signal input majority[2];
|
||||
signal input current_date[6];
|
||||
signal input selector_older_than;
|
||||
|
||||
signal input forbidden_countries_list[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3];
|
||||
|
||||
// ofac check
|
||||
signal input smt_leaf_key;
|
||||
signal input smt_root;
|
||||
signal input smt_siblings[256];
|
||||
signal input selector_ofac;
|
||||
// forbidden countries list
|
||||
signal input forbidden_countries_list[FORBIDDEN_COUNTRIES_LIST_LENGTH * 3];
|
||||
|
||||
signal input scope;
|
||||
signal input user_identifier;
|
||||
|
||||
// verify commitment is part of the merkle tree
|
||||
VERIFY_COMMITMENT(nLevels)(secret, attestation_id, pubkey_leaf, dg1, dg2_hash, merkle_root, merkletree_size, path, siblings);
|
||||
VERIFY_COMMITMENT(nLevels)(
|
||||
secret,
|
||||
attestation_id,
|
||||
dg1,
|
||||
eContent_shaBytes_packed_hash,
|
||||
dsc_tree_leaf,
|
||||
merkle_root,
|
||||
leaf_depth,
|
||||
path,
|
||||
siblings
|
||||
);
|
||||
|
||||
// verify passport validity and disclose optional data
|
||||
component disclose = DISCLOSE();
|
||||
// verify passport validity
|
||||
signal validity_ASCII[6];
|
||||
for (var i = 0; i < 6; i++) {
|
||||
validity_ASCII[i] <== dg1[70 +i];
|
||||
}
|
||||
|
||||
IsValid()(current_date,validity_ASCII);
|
||||
|
||||
// disclose optional data
|
||||
component disclose = DISCLOSE(10);
|
||||
disclose.dg1 <== dg1;
|
||||
disclose.selector_dg1 <== selector_dg1;
|
||||
disclose.selector_older_than <== selector_older_than;
|
||||
disclose.current_date <== current_date;
|
||||
disclose.majority <== majority;
|
||||
|
||||
// generate scope nullifier
|
||||
component poseidon_nullifier = Poseidon(2);
|
||||
poseidon_nullifier.inputs[0] <== secret;
|
||||
poseidon_nullifier.inputs[1] <== scope;
|
||||
signal output nullifier <== poseidon_nullifier.out;
|
||||
disclose.smt_leaf_key <== smt_leaf_key;
|
||||
disclose.smt_root <== smt_root;
|
||||
disclose.smt_siblings <== smt_siblings;
|
||||
disclose.selector_ofac <== selector_ofac;
|
||||
disclose.forbidden_countries_list <== forbidden_countries_list;
|
||||
|
||||
signal output revealedData_packed[3] <== disclose.revealedData_packed;
|
||||
signal output older_than[2] <== disclose.older_than;
|
||||
|
||||
// COUNTRY IS IN LIST
|
||||
signal output forbidden_countries_list_packed_disclosed[2] <== ProveCountryIsNotInList(FORBIDDEN_COUNTRIES_LIST_LENGTH)(dg1, forbidden_countries_list);
|
||||
var chunkLength = computeIntChunkLength(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3);
|
||||
signal output forbidden_countries_list_packed[chunkLength] <== disclose.forbidden_countries_list_packed;
|
||||
|
||||
// OFAC
|
||||
signal ofacCheckResult <== OFAC_NAME()(dg1,smt_leaf_key,smt_root,smt_siblings);
|
||||
signal ofacIntermediaryOutput <== ofacCheckResult * selector_ofac;
|
||||
signal output ofac_result <== ofacIntermediaryOutput;
|
||||
signal output nullifier <== Poseidon(2)([secret, scope]);
|
||||
}
|
||||
|
||||
component main { public [ merkle_root, smt_root, scope, user_identifier, current_date, attestation_id] } = VC_AND_DISCLOSE(16,20);
|
||||
component main {
|
||||
public [
|
||||
merkle_root,
|
||||
smt_root,
|
||||
scope,
|
||||
user_identifier,
|
||||
current_date,
|
||||
attestation_id
|
||||
]
|
||||
} = VC_AND_DISCLOSE(33, 10);
|
||||
@@ -9,57 +9,132 @@ include "@zk-kit/binary-merkle-root.circom/src/binary-merkle-root.circom";
|
||||
include "../utils/passport/customHashers.circom";
|
||||
include "../utils/passport/signatureAlgorithm.circom";
|
||||
include "../utils/passport/signatureVerifier.circom";
|
||||
include "@openpassport/zk-email-circuits/utils/bytes.circom";
|
||||
include "../utils/passport/checkPubkeysEqual.circom";
|
||||
include "../utils/passport/constants.circom";
|
||||
include "../utils/crypto/bitify/bytes.circom";
|
||||
include "../utils/passport/BytesToNum.circom";
|
||||
|
||||
/// @title DSC
|
||||
/// @notice Circuit for verifying DSC certificate signature using CSCA certificate
|
||||
/// @param signatureAlgorithm Algorithm used for DSC signature verification - contains the information about the final hash algorithm
|
||||
/// @param n_csca Number of bits per chunk the CSCA key is split into
|
||||
/// @param k_csca Number of chunks the CSCA key is split into
|
||||
/// @input raw_csca Raw CSCA certificate data
|
||||
/// @input raw_csca_actual_length Actual length of CSCA certificate
|
||||
/// @input csca_pubKey_offset Offset of CSCA public key in certificate
|
||||
/// @input csca_pubKey_actual_size Actual size of CSCA public key in bytes
|
||||
/// @input raw_dsc Raw DSC certificate data
|
||||
/// @input raw_dsc_padded_length Actual length of DSC certificate
|
||||
/// @input csca_pubKey CSCA public key for signature verification
|
||||
/// @input signature DSC signature
|
||||
/// @input merkle_root Root of CSCA Merkle tree
|
||||
/// @input path Path indices for CSCA Merkle proof
|
||||
/// @input siblings Sibling hashes for CSCA Merkle proof
|
||||
/// @output dsc_tree_leaf Leaf to be added to the DSC Merkle tree
|
||||
template DSC(
|
||||
signatureAlgorithm,
|
||||
n_csca,
|
||||
k_csca
|
||||
) {
|
||||
var MAX_CSCA_LENGTH = getMaxCSCALength();
|
||||
var MAX_DSC_LENGTH = getMaxDSCLength();
|
||||
var nLevels = getMaxCSCALevels();
|
||||
|
||||
template DSC(signatureAlgorithm, n_dsc, k_dsc, n_csca, k_csca, max_cert_bytes, dscPubkeyBytesLength, nLevels) {
|
||||
|
||||
// variables verification
|
||||
assert(max_cert_bytes % 64 == 0);
|
||||
assert(n_csca * k_csca > max_cert_bytes);
|
||||
assert(MAX_CSCA_LENGTH % 64 == 0);
|
||||
assert(MAX_DSC_LENGTH % 64 == 0);
|
||||
// assert(n_csca * k_csca > max_dsc_bytes); // not sure what this is for
|
||||
assert(n_csca <= (255 \ 2));
|
||||
|
||||
var hashLength = getHashLength(signatureAlgorithm);
|
||||
var minKeyLength = getMinKeyLength(signatureAlgorithm);
|
||||
var kLengthFactor = getKLengthFactor(signatureAlgorithm);
|
||||
var kScaled = k_csca * kLengthFactor;
|
||||
var hashLength = getHashLength(signatureAlgorithm);
|
||||
|
||||
var MAX_CSCA_PUBKEY_LENGTH = n_csca * kScaled / 8;
|
||||
|
||||
signal input raw_csca[MAX_CSCA_LENGTH];
|
||||
signal input raw_csca_actual_length;
|
||||
signal input csca_pubKey_offset;
|
||||
signal input csca_pubKey_actual_size;
|
||||
|
||||
signal input raw_dsc[MAX_DSC_LENGTH];
|
||||
signal input raw_dsc_padded_length;
|
||||
|
||||
signal input raw_dsc_cert[max_cert_bytes];
|
||||
signal input raw_dsc_cert_padded_bytes;
|
||||
signal input csca_pubKey[kScaled];
|
||||
signal input signature[kScaled];
|
||||
signal input dsc_pubKey[k_dsc];
|
||||
signal input dsc_pubKey_offset;
|
||||
signal input secret;
|
||||
|
||||
signal input merkle_root;
|
||||
signal input path[nLevels];
|
||||
signal input siblings[nLevels];
|
||||
|
||||
// first, compute raw_dsc_actual_length
|
||||
// by getting the values of the last 4 bytes of the padded length
|
||||
// cf sha padding
|
||||
signal last_four_bytes_of_padded_length[4] <== SelectSubArray(MAX_DSC_LENGTH, 4)(raw_dsc, raw_dsc_padded_length - 4, 4);
|
||||
signal computed_length_bits <== BytesToNum()(last_four_bytes_of_padded_length);
|
||||
signal raw_dsc_actual_length <== computed_length_bits / 8;
|
||||
|
||||
// leaf
|
||||
signal leaf <== LeafHasher(kScaled)(csca_pubKey, signatureAlgorithm);
|
||||
// sanity check: raw_dsc[raw_dsc_actual_length] should be 128
|
||||
signal raw_dsc_at_actual_length <== ItemAtIndex(MAX_DSC_LENGTH)(raw_dsc, raw_dsc_actual_length);
|
||||
signal isByte128 <== IsEqual()([raw_dsc_at_actual_length, 128]);
|
||||
isByte128 === 1;
|
||||
|
||||
signal computed_merkle_root <== BinaryMerkleRoot(nLevels)(leaf, nLevels, path, siblings);
|
||||
merkle_root === computed_merkle_root;
|
||||
|
||||
// verify certificate signature
|
||||
signal hashedCertificate[hashLength] <== ShaBytesDynamic(hashLength, max_cert_bytes)(raw_dsc_cert, raw_dsc_cert_padded_bytes);
|
||||
|
||||
SignatureVerifier(signatureAlgorithm, n_csca, k_csca)(hashedCertificate, csca_pubKey, signature);
|
||||
|
||||
// verify DSC csca_pubKey
|
||||
component shiftLeft = VarShiftLeft(max_cert_bytes, dscPubkeyBytesLength); // use select subarray for dscPubKey variable length
|
||||
shiftLeft.in <== raw_dsc_cert;
|
||||
shiftLeft.shift <== dsc_pubKey_offset;
|
||||
component spbt_1 = SplitBytesToWords(dscPubkeyBytesLength, n_dsc, k_dsc);
|
||||
spbt_1.in <== shiftLeft.out;
|
||||
for (var i = 0; i < k_dsc; i++) {
|
||||
dsc_pubKey[i] === spbt_1.out[i];
|
||||
// check that raw_dsc is padded with 0s after the sha padding
|
||||
// this should guarantee the dsc commitment is unique for each commitment
|
||||
component byte_checks[MAX_DSC_LENGTH];
|
||||
for (var i = 0; i < MAX_DSC_LENGTH; i++) {
|
||||
byte_checks[i] = GreaterThan(12);
|
||||
byte_checks[i].in[0] <== i;
|
||||
byte_checks[i].in[1] <== raw_dsc_padded_length;
|
||||
|
||||
// If i >= raw_dsc_padded_length, the byte must be 0
|
||||
raw_dsc[i] * byte_checks[i].out === 0;
|
||||
}
|
||||
|
||||
// check csca_pubKey_actual_size is at least the minimum key length
|
||||
signal csca_pubKey_actual_size_in_range <== GreaterEqThan(12)([
|
||||
csca_pubKey_actual_size,
|
||||
minKeyLength * kLengthFactor / 8
|
||||
]);
|
||||
csca_pubKey_actual_size_in_range === 1;
|
||||
|
||||
// blinded dsc commitment
|
||||
signal pubkeyHash <== CustomHasher(k_dsc)(dsc_pubKey);
|
||||
signal output blinded_dsc_commitment <== Poseidon(2)([secret, pubkeyHash]);
|
||||
}
|
||||
// check offsets refer to valid ranges
|
||||
signal csca_pubKey_offset_in_range <== LessEqThan(12)([
|
||||
csca_pubKey_offset + csca_pubKey_actual_size,
|
||||
raw_csca_actual_length
|
||||
]);
|
||||
csca_pubKey_offset_in_range === 1;
|
||||
|
||||
// compute leaf in the CSCA Merkle tree and verify inclusion
|
||||
signal csca_hash <== PackBytesAndPoseidon(MAX_CSCA_LENGTH)(raw_csca);
|
||||
signal csca_tree_leaf <== Poseidon(2)([csca_hash, raw_csca_actual_length]);
|
||||
signal computed_merkle_root <== BinaryMerkleRoot(nLevels)(csca_tree_leaf, nLevels, path, siblings);
|
||||
merkle_root === computed_merkle_root;
|
||||
|
||||
// get CSCA public key from the certificate
|
||||
signal extracted_csca_pubKey[MAX_CSCA_PUBKEY_LENGTH] <== SelectSubArray(MAX_CSCA_LENGTH, MAX_CSCA_PUBKEY_LENGTH)(
|
||||
raw_csca,
|
||||
csca_pubKey_offset,
|
||||
csca_pubKey_actual_size
|
||||
);
|
||||
|
||||
// check if the CSCA public key is the same as the one in the certificate
|
||||
// If we end up adding the pubkey in the CSCA leaf, we'll be able to remove this check
|
||||
CheckPubkeysEqual(n_csca, kScaled, kLengthFactor, MAX_CSCA_PUBKEY_LENGTH)(
|
||||
csca_pubKey,
|
||||
extracted_csca_pubKey,
|
||||
csca_pubKey_actual_size
|
||||
);
|
||||
|
||||
// verify DSC signature
|
||||
// raw_dsc_padded_length is constrained because an incorrect one
|
||||
// would yield hashes that have not been signed
|
||||
signal hashedCertificate[hashLength] <== ShaBytesDynamic(hashLength, MAX_DSC_LENGTH)(raw_dsc, raw_dsc_padded_length);
|
||||
SignatureVerifier(signatureAlgorithm, n_csca, k_csca)(hashedCertificate, csca_pubKey, signature);
|
||||
|
||||
// generate DSC leaf as poseidon(dsc_hash_with_actual_length, csca_tree_leaf)
|
||||
signal dsc_hash <== PackBytesAndPoseidon(MAX_DSC_LENGTH)(raw_dsc);
|
||||
signal dsc_hash_with_actual_length <== Poseidon(2)([dsc_hash, raw_dsc_actual_length]);
|
||||
signal output dsc_tree_leaf <== Poseidon(2)([dsc_hash_with_actual_length, csca_tree_leaf]);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = DSC(11, 120, 35, 120, 35, 1664, 256, 12);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = DSC(10, 120, 35, 120, 35, 1664, 256, 12);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = DSC(12, 120, 35, 120, 35, 1664, 256, 12);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root] } = DSC(36, 64, 4);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = DSC(11, 120, 35);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root] } = DSC(21, 64, 4);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root] } = DSC(37, 64, 6);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root] } = DSC(8, 64, 4);
|
||||
@@ -0,0 +1,6 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root] } = DSC(23, 64, 6);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root] } = DSC(40, 64, 8);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = DSC(10, 120, 35);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = DSC(16, 120, 35);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = DSC(19, 120, 35);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = DSC(12, 120, 35);
|
||||
@@ -0,0 +1,7 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root] } = DSC(22, 64, 6);
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root] } = DSC(38, 64, 8);
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root] } = DSC(9, 64, 6);
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root] } = DSC(29, 64, 8);
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root] } = DSC(41, 66, 8);
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = DSC(15, 120, 35);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../dsc.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = DSC(39, 120, 35);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(160, 160, 27, 32, 7, 320, 128);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(160, 160, 7, 64, 4, 320, 128);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(160, 160 , 3, 64, 32, 320, 128);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = REGISTER(160, 160, 3, 120, 35, 384, 128);
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(160, 256 , 1, 120, 35, 320, 128);
|
||||
component main { public [ merkle_root ] } = REGISTER(160, 256, 1, 120, 35, 384, 128);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = REGISTER(224, 224, 30, 32, 7, 512, 128);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(256, 224, 30, 32, 7, 448, 128);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = REGISTER(256, 224, 44, 32, 7, 512, 128);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(256, 256, 28, 32, 7, 448, 128);
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(256, 256, 21, 64, 4, 448, 128);
|
||||
component main { public [ merkle_root ] } = REGISTER(256, 256, 21, 64, 4, 512, 128);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = REGISTER(256, 256, 37, 64, 6, 512, 128);
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(256, 256, 8, 64, 4, 448, 128);
|
||||
component main { public [ merkle_root ] } = REGISTER(256, 256, 8, 64, 4, 512, 128);
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(256, 256, 23, 64, 6, 448, 128);
|
||||
component main { public [ merkle_root ] } = REGISTER(256, 256, 23, 64, 6, 512, 128);
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(256, 256, 13, 120, 35, 448, 128);
|
||||
component main { public [ merkle_root ] } = REGISTER(256, 256, 13, 120, 35, 512, 128);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main { public [ scope, user_identifier, current_date ] } = REGISTER(256, 256, 14, 96, 32, 448, 128);
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(256 ,256 ,1, 120, 35, 448, 128);
|
||||
component main { public [ merkle_root ] } = REGISTER(256, 256, 1, 120, 35, 512, 128);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = REGISTER(256, 256, 43, 120, 35, 512, 128);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(256,256, 17, 120, 35, 448, 128);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = REGISTER(256, 256, 4, 120, 35, 512, 128);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = REGISTER(256, 256, 19, 120, 35, 512, 128);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(256, 256, 12, 120, 35, 448, 128);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(384, 384, 24, 64, 4, 640, 256);
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(384, 384, 22, 64, 6, 640, 256);
|
||||
component main { public [ merkle_root ] } = REGISTER(384, 384, 22, 64, 6, 768, 256);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = REGISTER(384, 384, 38, 64, 8, 768, 256);
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(384, 384, 9, 64, 6, 640, 256);
|
||||
component main { public [ merkle_root ] } = REGISTER(384, 384, 9, 64, 6, 768, 256);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(512, 512, 25, 64, 4, 768, 256);
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(512, 512, 26, 64, 6, 768, 256);
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(512, 512, 29, 64, 8, 768, 256);
|
||||
component main { public [ merkle_root ] } = REGISTER(512, 512, 29, 64, 8, 896, 256);
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main = REGISTER(512, 512, 15, 120, 35, 768, 256);
|
||||
component main { public [ merkle_root ] } = REGISTER(512, 512, 15, 120, 35, 896, 256);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../register.circom";
|
||||
|
||||
component main { public [ merkle_root ] } = REGISTER(512, 512, 42, 120, 35, 896, 256);
|
||||
@@ -1,78 +1,164 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../utils/passport/customHashers.circom";
|
||||
include "../utils/passport/computeCommitment.circom";
|
||||
include "../utils/passport/signatureAlgorithm.circom";
|
||||
include "../utils/passport/date/isValid.circom";
|
||||
include "circomlib/circuits/poseidon.circom";
|
||||
include "../utils/passport/passportVerifier.circom";
|
||||
include "../utils/passport/disclose/disclose.circom";
|
||||
include "../utils/passport/disclose/proveCountryIsNotInList.circom";
|
||||
include "../utils/passport/ofac/ofac_name.circom";
|
||||
include "../utils/passport/constants.circom";
|
||||
include "../utils/crypto/bitify/splitWordsToBytes.circom";
|
||||
include "../utils/crypto/bitify/bytes.circom";
|
||||
include "@zk-kit/binary-merkle-root.circom/src/binary-merkle-root.circom";
|
||||
include "../utils/passport/checkPubkeysEqual.circom";
|
||||
|
||||
/// @title REGISTER
|
||||
/// @notice Main circuit to verify passport data and be used to several purposes to enable passport
|
||||
/// @dev Handles passport verification, OFAC checks, selective disclosure, and commitment generation
|
||||
/// @param DG_HASH_ALGO Hash algorithm used for DG (Document Group) hashing
|
||||
/// @notice Main circuit — verifies the integrity of the passport data, the signature, and generates commitment and nullifier
|
||||
/// @param DG_HASH_ALGO Hash algorithm used for DG hashing
|
||||
/// @param ECONTENT_HASH_ALGO Hash algorithm used for eContent
|
||||
/// @param signatureAlgorithm Algorithm used for passport signature verification
|
||||
/// @param signatureAlgorithm Algorithm used for passport signature verification - contains the information about the final hash algorithm
|
||||
/// @param n Number of bits per chunk the key is split into.
|
||||
/// @param k Number of chunks the key is split into.
|
||||
/// @param MAX_ECONTENT_PADDED_LEN Maximum length of padded eContent
|
||||
/// @param MAX_SIGNED_ATTR_PADDED_LEN Maximum length of padded signed attributes
|
||||
/// @input raw_dsc Raw DSC certificate data
|
||||
/// @input raw_dsc_actual_length Actual length of DSC certificate
|
||||
/// @input dsc_pubKey_offset Offset of DSC public key in certificate
|
||||
/// @input dsc_pubKey_actual_size Actual size of DSC public key
|
||||
/// @input dg1 Document Group 1 data (93 bytes)
|
||||
/// @input dg1_hash_offset Offset for DG1 hash
|
||||
/// @input dg2_hash Document Group 2 hash (64 bytes)
|
||||
/// @input eContent eContent data
|
||||
/// @input eContent eContent data - contains all DG hashes
|
||||
/// @input eContent_padded_length Padded length of eContent
|
||||
/// @input signed_attr Signed attributes data
|
||||
/// @input signed_attr Signed attributes
|
||||
/// @input signed_attr_padded_length Padded length of signed attributes
|
||||
/// @input signed_attr_econtent_hash_offset Offset for eContent hash in signed attributes
|
||||
/// @input pubKey Public key for signature verification
|
||||
/// @input signature Passport signature
|
||||
/// @input user_identifier User identifier for commitment
|
||||
/// @input secret Secret for commitment generation. Supposed to be saved by the user to access this commitment.
|
||||
/// @input dsc_secret One time secret data to generate the blinded commitment. This blinded dsc commitment is used to find the link between a proof from this circuit and a proof from the dsc circuit.
|
||||
/// @output nullifier Generated nullifier
|
||||
/// @output commitment Unique commitment for the passport data and their secret
|
||||
/// @output blinded_dsc_commitment To find the link between a proof from this circuit and a proof from the dsc circuit.
|
||||
/// @input pubKey_dsc DSC public key for signature verification
|
||||
/// @input signature_passport Passport signature
|
||||
/// @input merkle_root Root of DSC Merkle tree
|
||||
/// @input leaf_depth Actual size of the merkle tree
|
||||
/// @input path Path indices for DSC Merkle proof
|
||||
/// @input siblings Sibling hashes for DSC Merkle proof
|
||||
/// @input csca_tree_leaf Leaf of CSCA Merkle tree
|
||||
/// @input secret Secret for commitment generation. Saved by the user to access their commitment
|
||||
/// @output nullifier Generated nullifier - deterministic on the passport data
|
||||
/// @output commitment Commitment that will be added to the onchain registration tree
|
||||
template REGISTER(
|
||||
DG_HASH_ALGO,
|
||||
ECONTENT_HASH_ALGO,
|
||||
signatureAlgorithm,
|
||||
n,
|
||||
k,
|
||||
MAX_ECONTENT_PADDED_LEN,
|
||||
MAX_SIGNED_ATTR_PADDED_LEN
|
||||
) {
|
||||
var MAX_DSC_LENGTH = getMaxDSCLength();
|
||||
var nLevels = getMaxDSCLevels();
|
||||
|
||||
template REGISTER(DG_HASH_ALGO, ECONTENT_HASH_ALGO, signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN) {
|
||||
assert(MAX_DSC_LENGTH % 64 == 0);
|
||||
|
||||
// This means the attestation is a passport
|
||||
var attestation_id = 1;
|
||||
|
||||
var minKeyLength = getMinKeyLength(signatureAlgorithm);
|
||||
var kLengthFactor = getKLengthFactor(signatureAlgorithm);
|
||||
var kScaled = k * kLengthFactor;
|
||||
|
||||
var HASH_LEN_BITS = getHashLength(signatureAlgorithm);
|
||||
var HASH_LEN_BYTES = HASH_LEN_BITS / 8;
|
||||
var ECONTENT_HASH_ALGO_BYTES = ECONTENT_HASH_ALGO / 8;
|
||||
|
||||
var MAX_DSC_PUBKEY_LENGTH = n * kScaled / 8;
|
||||
|
||||
signal input raw_dsc[MAX_DSC_LENGTH];
|
||||
signal input raw_dsc_actual_length;
|
||||
signal input dsc_pubKey_offset;
|
||||
signal input dsc_pubKey_actual_size;
|
||||
|
||||
signal input dg1[93];
|
||||
signal input dg1_hash_offset;
|
||||
signal input dg2_hash[64];
|
||||
signal input eContent[MAX_ECONTENT_PADDED_LEN];
|
||||
signal input eContent_padded_length;
|
||||
signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN];
|
||||
signal input signed_attr_padded_length;
|
||||
signal input signed_attr_econtent_hash_offset;
|
||||
signal input pubKey[kScaled];
|
||||
signal input signature[kScaled];
|
||||
signal input pubKey_dsc[kScaled];
|
||||
signal input signature_passport[kScaled];
|
||||
|
||||
signal input merkle_root;
|
||||
signal input leaf_depth;
|
||||
signal input path[nLevels];
|
||||
signal input siblings[nLevels];
|
||||
|
||||
signal input csca_tree_leaf;
|
||||
|
||||
signal input secret;
|
||||
signal input dsc_secret;
|
||||
|
||||
signal attestation_id <== 1;
|
||||
// check dsc_pubKey_actual_size is at least the minimum key length
|
||||
signal dsc_pubKey_actual_size_in_range <== GreaterEqThan(12)([
|
||||
dsc_pubKey_actual_size,
|
||||
minKeyLength * kLengthFactor / 8
|
||||
]);
|
||||
dsc_pubKey_actual_size_in_range === 1;
|
||||
|
||||
// check offsets refer to valid ranges
|
||||
signal dsc_pubKey_offset_in_range <== LessEqThan(12)([
|
||||
dsc_pubKey_offset + dsc_pubKey_actual_size,
|
||||
raw_dsc_actual_length
|
||||
]);
|
||||
dsc_pubKey_offset_in_range === 1;
|
||||
|
||||
// generate DSC leaf as poseidon(dsc_hash, csca_tree_leaf)
|
||||
signal dsc_hash <== PackBytesAndPoseidon(MAX_DSC_LENGTH)(raw_dsc);
|
||||
signal dsc_hash_with_actual_length <== Poseidon(2)([dsc_hash, raw_dsc_actual_length]);
|
||||
signal dsc_tree_leaf <== Poseidon(2)([dsc_hash_with_actual_length, csca_tree_leaf]);
|
||||
signal computed_merkle_root <== BinaryMerkleRoot(nLevels)(dsc_tree_leaf, leaf_depth, path, siblings);
|
||||
merkle_root === computed_merkle_root;
|
||||
|
||||
// get DSC public key from the certificate
|
||||
signal extracted_dsc_pubKey[MAX_DSC_PUBKEY_LENGTH] <== SelectSubArray(MAX_DSC_LENGTH, MAX_DSC_PUBKEY_LENGTH)(
|
||||
raw_dsc,
|
||||
dsc_pubKey_offset,
|
||||
dsc_pubKey_actual_size
|
||||
);
|
||||
|
||||
// check if the DSC public key is the same as the one in the certificate
|
||||
CheckPubkeysEqual(n, kScaled, kLengthFactor, MAX_DSC_PUBKEY_LENGTH)(
|
||||
pubKey_dsc,
|
||||
extracted_dsc_pubKey,
|
||||
dsc_pubKey_actual_size
|
||||
);
|
||||
|
||||
// verify passport signature
|
||||
signal signedAttrShaBytes[HASH_LEN_BYTES] <== PassportVerifier(DG_HASH_ALGO, ECONTENT_HASH_ALGO, signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, eContent,eContent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature);
|
||||
component passportVerifier = PassportVerifier(
|
||||
DG_HASH_ALGO,
|
||||
ECONTENT_HASH_ALGO,
|
||||
signatureAlgorithm,
|
||||
n,
|
||||
k,
|
||||
MAX_ECONTENT_PADDED_LEN,
|
||||
MAX_SIGNED_ATTR_PADDED_LEN
|
||||
);
|
||||
|
||||
// nulifier
|
||||
component passportDataHashed = CustomHasher(HASH_LEN_BYTES);
|
||||
passportDataHashed.in <== signedAttrShaBytes;
|
||||
signal output nullifier <== passportDataHashed.out;
|
||||
passportVerifier.dg1 <== dg1;
|
||||
passportVerifier.dg1_hash_offset <== dg1_hash_offset;
|
||||
passportVerifier.eContent <== eContent;
|
||||
passportVerifier.eContent_padded_length <== eContent_padded_length;
|
||||
passportVerifier.signed_attr <== signed_attr;
|
||||
passportVerifier.signed_attr_padded_length <== signed_attr_padded_length;
|
||||
passportVerifier.signed_attr_econtent_hash_offset <== signed_attr_econtent_hash_offset;
|
||||
passportVerifier.pubKey_dsc <== pubKey_dsc;
|
||||
passportVerifier.signature_passport <== signature_passport;
|
||||
|
||||
// // REGISTRATION (optional)
|
||||
// // generate the commitment
|
||||
signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm);
|
||||
signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, dg1, dg2_hash);
|
||||
signal output nullifier <== PackBytesAndPoseidon(HASH_LEN_BYTES)(passportVerifier.signedAttrShaBytes);
|
||||
|
||||
// blinded dsc commitment
|
||||
signal pubkeyHash <== CustomHasher(kScaled)(pubKey);
|
||||
signal output blinded_dsc_commitment <== Poseidon(2)([dsc_secret, pubkeyHash]);
|
||||
}
|
||||
// generate commitment
|
||||
signal dg1_packed_hash <== PackBytesAndPoseidon(93)(dg1);
|
||||
signal eContent_shaBytes_packed_hash <== PackBytesAndPoseidon(ECONTENT_HASH_ALGO_BYTES)(passportVerifier.eContentShaBytes);
|
||||
|
||||
signal output commitment <== Poseidon(5)([
|
||||
secret,
|
||||
attestation_id,
|
||||
dg1_packed_hash,
|
||||
eContent_shaBytes_packed_hash,
|
||||
dsc_tree_leaf
|
||||
]);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
pragma circom 2.1.6;
|
||||
|
||||
include "../../utils/passport/computeCommitment.circom";
|
||||
|
||||
component main = ComputeCommitment();
|
||||
13
circuits/circuits/tests/utils/ecdsa/test_p521.circom
Normal file
13
circuits/circuits/tests/utils/ecdsa/test_p521.circom
Normal file
@@ -0,0 +1,13 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../../../utils/crypto/signature/ecdsa/ecdsaVerifier.circom";
|
||||
|
||||
template VerifyP521r1Sha512() {
|
||||
signal input signature[2 * 8];
|
||||
signal input pubKey[2 * 8];
|
||||
signal input hashParsed[512];
|
||||
|
||||
EcdsaVerifier(41, 66, 8)(signature, pubKey, hashParsed);
|
||||
}
|
||||
|
||||
component main = VerifyP521r1Sha512();
|
||||
@@ -1,3 +1,3 @@
|
||||
pragma circom 2.1.9;
|
||||
include "../../utils/passport/disclose/proveCountryIsNotInList.circom";
|
||||
component main { public [ forbidden_countries_list ] } = ProveCountryIsNotInList(20);
|
||||
component main { public [ forbidden_countries_list ] } = ProveCountryIsNotInList(10);
|
||||
|
||||
3
circuits/circuits/tests/utils/wordsToBytes_tester.circom
Normal file
3
circuits/circuits/tests/utils/wordsToBytes_tester.circom
Normal file
@@ -0,0 +1,3 @@
|
||||
include "../../utils/crypto/bitify/splitWordsToBytes.circom";
|
||||
|
||||
component main = WordsToBytesPadded(120,35,120 * 35 / 8, 525);
|
||||
@@ -1,34 +1,29 @@
|
||||
// NOTE: this circuit is unaudited and should not be used in production
|
||||
/// @title SplitBytesToWords
|
||||
/// @notice split an array of bytes into an array of words
|
||||
/// @notice useful for casting a message or modulus before RSA verification
|
||||
/// @param l: number of bytes in the input array
|
||||
/// @param n: number of bits in a word
|
||||
/// @param k: number of words
|
||||
/// @input in: array of bytes
|
||||
/// @output out: array of words
|
||||
template SplitBytesToWords (l,n,k) {
|
||||
signal input in[l];
|
||||
signal output out[k];
|
||||
pragma circom 2.1.9;
|
||||
|
||||
component num2bits[l];
|
||||
for (var i = 0 ; i < l ; i++){
|
||||
num2bits[i] = Num2Bits(8);
|
||||
num2bits[i].in <== in[i];
|
||||
template BitsToBytesArray(bits_len){
|
||||
var bytes_len = bits_len / 8;
|
||||
component b2n[bytes_len];
|
||||
signal input in[bits_len];
|
||||
signal output out[bytes_len];
|
||||
for (var i = 0; i < bytes_len; i++) {
|
||||
b2n[i] = Bits2Num(8);
|
||||
for (var j = 0; j < 8; j++) {
|
||||
b2n[i].in[7 - j] <== in[i * 8 + j];
|
||||
}
|
||||
out[i] <== b2n[i].out;
|
||||
}
|
||||
component bits2num[k];
|
||||
for (var i = 0 ; i < k ; i++){
|
||||
bits2num[i] = Bits2Num(n);
|
||||
for(var j = 0 ; j < n ; j++){
|
||||
if(i*n + j >= 8 * l){
|
||||
bits2num[i].in[j] <== 0;
|
||||
}
|
||||
else{
|
||||
bits2num[i].in[j] <== num2bits[l - (( i * n + j) \ 8) - 1].out[ ((i * n + j) % 8)];
|
||||
}
|
||||
}
|
||||
|
||||
template BytesToBitsArray(bytes_len){
|
||||
var bits_len = bytes_len * 8;
|
||||
signal input in[bytes_len];
|
||||
signal output out[bits_len];
|
||||
component n2b[bytes_len];
|
||||
for (var i = 0; i < bytes_len; i++) {
|
||||
n2b[i] = Num2Bits(8);
|
||||
n2b[i].in <== in[i];
|
||||
for (var j = 0; j < 8; j++) {
|
||||
out[i * 8 + j] <== n2b[i].out[7 - j];
|
||||
}
|
||||
}
|
||||
for( var i = 0 ; i< k ; i++){
|
||||
out[i] <== bits2num[i].out;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
pragma circom 2.1.9;
|
||||
include "circomlib/circuits/bitify.circom";
|
||||
|
||||
template WordsToBytes(n_words, k_words, maxBytesLength) {
|
||||
assert(n_words * k_words == maxBytesLength * 8);
|
||||
|
||||
signal input words[k_words];
|
||||
signal output bytes[maxBytesLength];
|
||||
|
||||
component num2bits[k_words];
|
||||
signal word_bits[k_words * n_words];
|
||||
|
||||
// Convert words to bits
|
||||
for (var i = 0; i < k_words; i++) {
|
||||
num2bits[i] = Num2Bits(n_words);
|
||||
num2bits[i].in <== words[i];
|
||||
}
|
||||
for (var i = 0; i < k_words; i++) {
|
||||
for (var j = 0; j < n_words; j++) {
|
||||
word_bits[i * n_words + j] <== num2bits[i].out[j];
|
||||
}
|
||||
}
|
||||
|
||||
// Convert bits back to bytes
|
||||
component bits2Num[maxBytesLength];
|
||||
for (var i = 0; i < maxBytesLength; i++) {
|
||||
bits2Num[i] = Bits2Num(8);
|
||||
for (var j = 0; j < 8; j++) {
|
||||
bits2Num[i].in[j] <== word_bits[i * 8 + j];
|
||||
}
|
||||
bytes[i] <== bits2Num[i].out;
|
||||
}
|
||||
}
|
||||
|
||||
template WordsToBytesPadded(n_words, k_words, maxBytesLength, paddedLength) {
|
||||
assert(n_words * k_words == maxBytesLength * 8);
|
||||
|
||||
signal input words[k_words];
|
||||
signal bytes[maxBytesLength];
|
||||
signal output paddedBytes[paddedLength];
|
||||
|
||||
component num2bits[k_words];
|
||||
signal word_bits[k_words * n_words];
|
||||
|
||||
// Convert words to bits
|
||||
for (var i = 0; i < k_words; i++) {
|
||||
num2bits[i] = Num2Bits(n_words);
|
||||
num2bits[i].in <== words[i];
|
||||
}
|
||||
for (var i = 0; i < k_words; i++) {
|
||||
for (var j = 0; j < n_words; j++) {
|
||||
word_bits[i * n_words + j] <== num2bits[i].out[j];
|
||||
}
|
||||
}
|
||||
|
||||
// Convert bits back to bytes
|
||||
component bits2Num[maxBytesLength];
|
||||
for (var i = 0; i < maxBytesLength; i++) {
|
||||
bits2Num[i] = Bits2Num(8);
|
||||
for (var j = 0; j < 8; j++) {
|
||||
bits2Num[i].in[j] <== word_bits[i * 8 + j];
|
||||
}
|
||||
bytes[i] <== bits2Num[i].out;
|
||||
}
|
||||
|
||||
for (var i = 0; i < paddedLength; i++) {
|
||||
paddedBytes[i] <== bytes[maxBytesLength - i - 1];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,29 +9,30 @@ include "./dynamic/sha512Bytes.circom";
|
||||
/// @title ShaBytesDynamic
|
||||
/// @notice Computes the hash of an input message using a specified hash length and padded input
|
||||
/// @param hashLen Desired length of the hash in bits (e.g., 512, 384, 256, 224, 160)
|
||||
/// @param max_num_bits Maximum number of bits in the padded input
|
||||
/// @param max_num_bytes Maximum number of bytes in the padded input
|
||||
/// @input in_padded Padded input message, represented as an array of bits
|
||||
/// @input in_len_padded_bytes Length of the padded input in bytes
|
||||
/// @output hash The computed hash of the input message, with length specified by `hashLen`
|
||||
template ShaBytesDynamic(hashLen, max_num_bits) {
|
||||
signal input in_padded[max_num_bits];
|
||||
template ShaBytesDynamic(hashLen, max_num_bytes) {
|
||||
signal input in_padded[max_num_bytes];
|
||||
signal input in_len_padded_bytes;
|
||||
|
||||
signal output hash[hashLen];
|
||||
signal output hash_bits[hashLen];
|
||||
|
||||
if (hashLen == 512) {
|
||||
hash <== Sha512Bytes(max_num_bits)(in_padded, in_len_padded_bytes);
|
||||
hash_bits <== Sha512Bytes(max_num_bytes)(in_padded, in_len_padded_bytes);
|
||||
}
|
||||
if (hashLen == 384) {
|
||||
hash <== Sha384Bytes(max_num_bits)(in_padded, in_len_padded_bytes);
|
||||
hash_bits <== Sha384Bytes(max_num_bytes)(in_padded, in_len_padded_bytes);
|
||||
}
|
||||
if (hashLen == 256) {
|
||||
hash <== Sha256Bytes(max_num_bits)(in_padded, in_len_padded_bytes);
|
||||
hash_bits <== Sha256Bytes(max_num_bytes)(in_padded, in_len_padded_bytes);
|
||||
}
|
||||
if (hashLen == 224) {
|
||||
hash <== Sha224Bytes(max_num_bits)(in_padded, in_len_padded_bytes);
|
||||
hash_bits <== Sha224Bytes(max_num_bytes)(in_padded, in_len_padded_bytes);
|
||||
}
|
||||
if (hashLen == 160) {
|
||||
hash <== Sha1Bytes(max_num_bits)(in_padded, in_len_padded_bytes);
|
||||
hash_bits <== Sha1Bytes(max_num_bytes)(in_padded, in_len_padded_bytes);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "./static/Sha256BytesStatic.circom";
|
||||
include "./static/Sha1BytesStatic.circom";
|
||||
include "./static/Sha384BytesStatic.circom";
|
||||
include "./static/Sha512BytesStatic.circom";
|
||||
|
||||
template ShaBytesStatic(hashLen, dataLen) {
|
||||
signal input data[dataLen];
|
||||
signal output hash[hashLen];
|
||||
|
||||
if (hashLen == 512) {
|
||||
hash <== Sha512BytesStatic(dataLen)(data);
|
||||
}
|
||||
if (hashLen == 384) {
|
||||
hash <== Sha384BytesStatic(dataLen)(data);
|
||||
}
|
||||
if (hashLen == 256) {
|
||||
hash <== Sha256BytesStatic(dataLen)(data);
|
||||
}
|
||||
if (hashLen == 160) {
|
||||
hash <== Sha1BytesStatic(dataLen)(data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "circomlib/circuits/bitify.circom";
|
||||
include "../../sha2/sha384/sha384_hash_bits.circom";
|
||||
|
||||
template Sha384BytesStatic(max_num_bytes) {
|
||||
signal input in_padded[max_num_bytes];
|
||||
signal output out[384];
|
||||
|
||||
var num_bits = max_num_bytes * 8;
|
||||
|
||||
component sha = Sha384HashBitsStatic(num_bits);
|
||||
|
||||
component bytes[max_num_bytes];
|
||||
for (var i = 0; i < max_num_bytes; i++) {
|
||||
bytes[i] = Num2Bits(8);
|
||||
bytes[i].in <== in_padded[i];
|
||||
|
||||
for (var j = 0; j < 8; j++) {
|
||||
sha.in[i*8+j] <== bytes[i].out[7-j];
|
||||
}
|
||||
}
|
||||
|
||||
// Connect output bits
|
||||
for (var i = 0; i < 384; i++) {
|
||||
out[i] <== sha.out[i];
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "circomlib/circuits/bitify.circom";
|
||||
include "../../sha2/sha512/sha512_hash_bits.circom";
|
||||
|
||||
template Sha512BytesStatic(max_num_bytes) {
|
||||
signal input in_padded[max_num_bytes];
|
||||
signal output out[512];
|
||||
|
||||
var num_bits = max_num_bytes * 8;
|
||||
|
||||
component sha = Sha512HashBitsStatic(num_bits);
|
||||
|
||||
component bytes[max_num_bytes];
|
||||
for (var i = 0; i < max_num_bytes; i++) {
|
||||
bytes[i] = Num2Bits(8);
|
||||
bytes[i].in <== in_padded[i];
|
||||
|
||||
for (var j = 0; j < 8; j++) {
|
||||
sha.in[i*8+j] <== bytes[i].out[7-j];
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 512; i++) {
|
||||
out[i] <== sha.out[i];
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ template EcdsaVerifier(signatureAlgorithm, n, k) {
|
||||
}
|
||||
|
||||
function get_a(signatureAlgorithm) {
|
||||
if (signatureAlgorithm == 7 || signatureAlgorithm == 8) {
|
||||
if (signatureAlgorithm == 7 || signatureAlgorithm == 8) { //secp256r1
|
||||
return [
|
||||
18446744073709551612,
|
||||
4294967295,
|
||||
@@ -74,7 +74,7 @@ function get_a(signatureAlgorithm) {
|
||||
18446744069414584321
|
||||
];
|
||||
}
|
||||
if (signatureAlgorithm == 9 || signatureAlgorithm == 23) {
|
||||
if (signatureAlgorithm == 9 || signatureAlgorithm == 23) { //secp384r1
|
||||
return [
|
||||
4294967292,
|
||||
18446744069414584320,
|
||||
@@ -84,7 +84,7 @@ function get_a(signatureAlgorithm) {
|
||||
18446744073709551615
|
||||
];
|
||||
}
|
||||
if (signatureAlgorithm == 21 || signatureAlgorithm == 24 || signatureAlgorithm == 25) {
|
||||
if (signatureAlgorithm == 21 || signatureAlgorithm == 24 || signatureAlgorithm == 25 || signatureAlgorithm == 36) { //brainpoolP256r1
|
||||
return [
|
||||
16810331318623712729,
|
||||
18122579188607900780,
|
||||
@@ -92,7 +92,7 @@ function get_a(signatureAlgorithm) {
|
||||
9032542404991529047
|
||||
];
|
||||
}
|
||||
if (signatureAlgorithm == 22 || signatureAlgorithm == 26) {
|
||||
if (signatureAlgorithm == 22 || signatureAlgorithm == 26 || signatureAlgorithm == 37) { // brainpoolP384r1
|
||||
return [
|
||||
335737924824737830,
|
||||
9990533504564909291,
|
||||
@@ -103,7 +103,7 @@ function get_a(signatureAlgorithm) {
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 27 || signatureAlgorithm == 28 || signatureAlgorithm == 30) {
|
||||
if (signatureAlgorithm == 27 || signatureAlgorithm == 28 || signatureAlgorithm == 30) { // brainpoolP224r1
|
||||
return [
|
||||
3402800963,
|
||||
2953063001,
|
||||
@@ -115,7 +115,7 @@ function get_a(signatureAlgorithm) {
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 29) {
|
||||
if (signatureAlgorithm == 29 || signatureAlgorithm == 38) { // brainpoolP512r1
|
||||
return [
|
||||
16699818341992010954,
|
||||
9156125524185237433,
|
||||
@@ -128,11 +128,36 @@ function get_a(signatureAlgorithm) {
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 41) { //p521
|
||||
return [
|
||||
73786976294838206460,
|
||||
73786976294838206463,
|
||||
73786976294838206463,
|
||||
73786976294838206463,
|
||||
73786976294838206463,
|
||||
73786976294838206463,
|
||||
73786976294838206463,
|
||||
576460752303423487
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 44) { //p224
|
||||
return [
|
||||
4294967294,
|
||||
4294967295,
|
||||
4294967295,
|
||||
4294967294,
|
||||
4294967295,
|
||||
4294967295,
|
||||
4294967295
|
||||
];
|
||||
}
|
||||
|
||||
return [0];
|
||||
}
|
||||
|
||||
function get_b(signatureAlgorithm) {
|
||||
if (signatureAlgorithm == 7 || signatureAlgorithm == 8) {
|
||||
if (signatureAlgorithm == 7 || signatureAlgorithm == 8) { //secp256r1
|
||||
return [
|
||||
4309448131093880907,
|
||||
7285987128567378166,
|
||||
@@ -150,7 +175,7 @@ function get_b(signatureAlgorithm) {
|
||||
12912154004749740004
|
||||
];
|
||||
}
|
||||
if (signatureAlgorithm == 21 || signatureAlgorithm == 24 || signatureAlgorithm == 25) {
|
||||
if (signatureAlgorithm == 21 || signatureAlgorithm == 24 || signatureAlgorithm == 25 || signatureAlgorithm == 36) { //brainpoolP256r1
|
||||
return [
|
||||
7767825457231955894,
|
||||
10773760575486288334,
|
||||
@@ -158,7 +183,7 @@ function get_b(signatureAlgorithm) {
|
||||
2800214691157789508
|
||||
];
|
||||
}
|
||||
if (signatureAlgorithm == 22 || signatureAlgorithm == 26) {
|
||||
if (signatureAlgorithm == 22 || signatureAlgorithm == 26 || signatureAlgorithm == 37) { //brainpoolP384r1
|
||||
return [
|
||||
4230998357940653073,
|
||||
8985869839777909140,
|
||||
@@ -169,7 +194,7 @@ function get_b(signatureAlgorithm) {
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 27 || signatureAlgorithm == 28 || signatureAlgorithm == 30) {
|
||||
if (signatureAlgorithm == 27 || signatureAlgorithm == 28 || signatureAlgorithm == 30) { // brainpoolP224r1
|
||||
return [
|
||||
946618379,
|
||||
1725674354,
|
||||
@@ -181,7 +206,7 @@ function get_b(signatureAlgorithm) {
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 29) {
|
||||
if (signatureAlgorithm == 29 || signatureAlgorithm == 38) { // brainpoolP512r1
|
||||
return [
|
||||
2885045271355914019,
|
||||
10970857440773072349,
|
||||
@@ -194,11 +219,36 @@ function get_b(signatureAlgorithm) {
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 41) { //p521
|
||||
return [
|
||||
35687965819361312512,
|
||||
33244719099633405244,
|
||||
68122903767798193136,
|
||||
64948772962036742733,
|
||||
36008729323586384137,
|
||||
4298886627987975365,
|
||||
30118149759215298644,
|
||||
91854278977009778
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 44) { //p224
|
||||
return [
|
||||
592838580,
|
||||
655046979,
|
||||
3619674298,
|
||||
1346678967,
|
||||
4114690646,
|
||||
201634731,
|
||||
3020229253
|
||||
];
|
||||
}
|
||||
|
||||
return [0];
|
||||
}
|
||||
|
||||
function get_p(signatureAlgorithm) {
|
||||
if (signatureAlgorithm == 7 || signatureAlgorithm == 8) {
|
||||
if (signatureAlgorithm == 7 || signatureAlgorithm == 8) { //secp256r1
|
||||
return [
|
||||
18446744073709551615,
|
||||
4294967295,
|
||||
@@ -206,7 +256,7 @@ function get_p(signatureAlgorithm) {
|
||||
18446744069414584321
|
||||
];
|
||||
}
|
||||
if (signatureAlgorithm == 9 || signatureAlgorithm == 23) {
|
||||
if (signatureAlgorithm == 9 || signatureAlgorithm == 23) { //secp384r1
|
||||
return [
|
||||
4294967295,
|
||||
18446744069414584320,
|
||||
@@ -216,7 +266,7 @@ function get_p(signatureAlgorithm) {
|
||||
18446744073709551615
|
||||
];
|
||||
}
|
||||
if (signatureAlgorithm == 21 || signatureAlgorithm == 24 || signatureAlgorithm == 25) {
|
||||
if (signatureAlgorithm == 21 || signatureAlgorithm == 24 || signatureAlgorithm == 25 || signatureAlgorithm == 36) { //brainpoolP256r1
|
||||
return [
|
||||
2311270323689771895,
|
||||
7943213001558335528,
|
||||
@@ -224,7 +274,7 @@ function get_p(signatureAlgorithm) {
|
||||
12248480212390422972
|
||||
];
|
||||
}
|
||||
if (signatureAlgorithm == 22 || signatureAlgorithm == 26) {
|
||||
if (signatureAlgorithm == 22 || signatureAlgorithm == 26 || signatureAlgorithm == 37) { //brainpoolP384r1
|
||||
return [
|
||||
9747760000893709395,
|
||||
12453481191562877553,
|
||||
@@ -235,7 +285,7 @@ function get_p(signatureAlgorithm) {
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 27 || signatureAlgorithm == 28 || signatureAlgorithm == 30) {
|
||||
if (signatureAlgorithm == 27 || signatureAlgorithm == 28 || signatureAlgorithm == 30) { //brainpoolP224r1
|
||||
return [
|
||||
2127085823,
|
||||
2547681781,
|
||||
@@ -247,7 +297,7 @@ function get_p(signatureAlgorithm) {
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 29) {
|
||||
if (signatureAlgorithm == 29 || signatureAlgorithm == 38) { //brainpoolP512r1
|
||||
return [
|
||||
2930260431521597683,
|
||||
2918894611604883077,
|
||||
@@ -260,5 +310,30 @@ function get_p(signatureAlgorithm) {
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 41) { //p521
|
||||
return [
|
||||
73786976294838206463,
|
||||
73786976294838206463,
|
||||
73786976294838206463,
|
||||
73786976294838206463,
|
||||
73786976294838206463,
|
||||
73786976294838206463,
|
||||
73786976294838206463,
|
||||
576460752303423487
|
||||
];
|
||||
}
|
||||
|
||||
if (signatureAlgorithm == 44) { // p224
|
||||
return [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
4294967295,
|
||||
4294967295,
|
||||
4294967295,
|
||||
4294967295
|
||||
];
|
||||
}
|
||||
|
||||
return [0];
|
||||
}
|
||||
@@ -157,6 +157,21 @@ template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LEN
|
||||
db[i] <== xor.out[i];
|
||||
}
|
||||
}
|
||||
|
||||
//Step -10 of https://datatracker.ietf.org/doc/html/rfc8017#section-9.1.2
|
||||
component db2Num[DB_MASK_LEN];
|
||||
for (var i = 0; i < DB_MASK_LEN; i++) {
|
||||
db2Num[i] = Bits2Num(8);
|
||||
for (var j = 0; j < 8; j++) {
|
||||
db2Num[i].in[7 - j] <== db[i*8 + j];
|
||||
}
|
||||
}
|
||||
// Check leading zeros
|
||||
for (var i = 0; i < DB_MASK_LEN - SALT_LEN - 1; i++) {
|
||||
db2Num[i].out === 0;
|
||||
}
|
||||
// Check 0x01 byte
|
||||
db2Num[DB_MASK_LEN - SALT_LEN - 1].out === 1;
|
||||
|
||||
//inserting salt
|
||||
for (var i = 0; i < SALT_LEN_BITS; i++) {
|
||||
|
||||
@@ -57,7 +57,7 @@ include "../FpPowMod.circom";
|
||||
/// @input signature The RSA signature split into chunks
|
||||
/// @input hashed The hash of the original message
|
||||
template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LENGTH) {
|
||||
assert((HASH_TYPE == 384 && SALT_LEN == 48) || (HASH_TYPE == 256 && SALT_LEN == 64) || (HASH_TYPE == 256 && SALT_LEN == 32));
|
||||
assert((HASH_TYPE == 384 && SALT_LEN == 48) || (HASH_TYPE == 256 && SALT_LEN == 64) || (HASH_TYPE == 256 && SALT_LEN == 32) || (HASH_TYPE == 512 && SALT_LEN == 64));
|
||||
|
||||
signal input pubkey[CHUNK_NUMBER];
|
||||
signal input signature[CHUNK_NUMBER];
|
||||
@@ -114,7 +114,7 @@ template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY
|
||||
assert(EM_LEN >= HASH_LEN + SALT_LEN + 2);
|
||||
|
||||
//should end with 0xBC (188 in decimal)
|
||||
assert(eM[0] == 188);
|
||||
eM[0] === 188;
|
||||
|
||||
var DB_MASK_LEN = EM_LEN - HASH_LEN - 1;
|
||||
|
||||
@@ -159,6 +159,21 @@ template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY
|
||||
db[i] <== xor.out[i];
|
||||
}
|
||||
}
|
||||
|
||||
//Step -10 of https://datatracker.ietf.org/doc/html/rfc8017#section-9.1.2
|
||||
component db2Num[DB_MASK_LEN];
|
||||
for (var i = 0; i < DB_MASK_LEN; i++) {
|
||||
db2Num[i] = Bits2Num(8);
|
||||
for (var j = 0; j < 8; j++) {
|
||||
db2Num[i].in[7 - j] <== db[i*8 + j];
|
||||
}
|
||||
}
|
||||
// Check leading zeros
|
||||
for (var i = 0; i < DB_MASK_LEN - SALT_LEN - 1; i++) {
|
||||
db2Num[i].out === 0;
|
||||
}
|
||||
// Check 0x01 byte
|
||||
db2Num[DB_MASK_LEN - SALT_LEN - 1].out === 1;
|
||||
|
||||
//inserting salt
|
||||
for (var i = 0; i < SALT_LEN_BITS; i++) {
|
||||
|
||||
35
circuits/circuits/utils/passport/BytesToNum.circom
Normal file
35
circuits/circuits/utils/passport/BytesToNum.circom
Normal file
@@ -0,0 +1,35 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "circomlib/circuits/bitify.circom";
|
||||
|
||||
// Converts 4 bytes into a single number
|
||||
// Each byte must be in range [0,255]
|
||||
template BytesToNum() {
|
||||
signal input bytes[4]; // Assuming MSB first ordering
|
||||
signal output out;
|
||||
|
||||
// First convert each byte to bits
|
||||
component byte0 = Num2Bits(8);
|
||||
component byte1 = Num2Bits(8);
|
||||
component byte2 = Num2Bits(8);
|
||||
component byte3 = Num2Bits(8);
|
||||
|
||||
byte0.in <== bytes[0];
|
||||
byte1.in <== bytes[1];
|
||||
byte2.in <== bytes[2];
|
||||
byte3.in <== bytes[3];
|
||||
|
||||
// Now combine all bits into a single number
|
||||
component bits2Num = Bits2Num(32);
|
||||
|
||||
// Connect in LSB to MSB order (reverse byte order from before)
|
||||
for (var i = 0; i < 8; i++) {
|
||||
bits2Num.in[i] <== byte3.out[i]; // Least significant byte
|
||||
bits2Num.in[8+i] <== byte2.out[i]; // Third byte
|
||||
bits2Num.in[16+i] <== byte1.out[i]; // Second byte
|
||||
bits2Num.in[24+i] <== byte0.out[i]; // Most significant byte
|
||||
}
|
||||
|
||||
// The final output
|
||||
out <== bits2Num.out;
|
||||
}
|
||||
55
circuits/circuits/utils/passport/checkPubkeysEqual.circom
Normal file
55
circuits/circuits/utils/passport/checkPubkeysEqual.circom
Normal file
@@ -0,0 +1,55 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../crypto/bitify/bytes.circom";
|
||||
include "../crypto/bitify/splitWordsToBytes.circom";
|
||||
|
||||
/// @title CheckPubkeysEqual
|
||||
/// @notice Checks if the CSCA public key given is the same as the one in the certificate
|
||||
/// @param kScaled Number of chunks the given key is split into.
|
||||
/// @param MAX_CSCA_PUBKEY_LENGTH Maximum length of the parsed CSCA public key
|
||||
/// @input csca_pubKey CSCA public key given by the user, formatted for signature verification
|
||||
/// @input extracted_csca_pubKey CSCA public key extracted from the certificate
|
||||
template CheckPubkeysEqual(n, kScaled, kLengthFactor, MAX_CSCA_PUBKEY_LENGTH) {
|
||||
signal input csca_pubKey[kScaled];
|
||||
signal input extracted_csca_pubKey[MAX_CSCA_PUBKEY_LENGTH];
|
||||
signal input csca_pubKey_actual_size;
|
||||
|
||||
signal csca_pubKey_bytes[MAX_CSCA_PUBKEY_LENGTH] <== WordsToBytes(n, kScaled, n * kScaled / 8)(csca_pubKey);
|
||||
|
||||
// reverse bytes order
|
||||
signal reversed_csca_pubKey_bytes[MAX_CSCA_PUBKEY_LENGTH];
|
||||
for (var i = 0; i < MAX_CSCA_PUBKEY_LENGTH; i++) {
|
||||
reversed_csca_pubKey_bytes[i] <== csca_pubKey_bytes[MAX_CSCA_PUBKEY_LENGTH - i - 1];
|
||||
}
|
||||
|
||||
signal shifted_csca_pubKey_bytes[MAX_CSCA_PUBKEY_LENGTH] <== VarShiftLeft(MAX_CSCA_PUBKEY_LENGTH, MAX_CSCA_PUBKEY_LENGTH)(
|
||||
reversed_csca_pubKey_bytes,
|
||||
MAX_CSCA_PUBKEY_LENGTH - csca_pubKey_actual_size
|
||||
);
|
||||
|
||||
// if kLengthFactor = 1 it's rsa, if kLengthFactor = 2 it's ecdsa
|
||||
// if it's ecdsa, the position of the x and y coordinates are swapped
|
||||
// in ecdsa, MAX_CSCA_PUBKEY_LENGTH is always the size of the key
|
||||
if (kLengthFactor == 2) {
|
||||
for (var i = 0; i < MAX_CSCA_PUBKEY_LENGTH / 2; i++) {
|
||||
shifted_csca_pubKey_bytes[i] === extracted_csca_pubKey[MAX_CSCA_PUBKEY_LENGTH / 2 + i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < MAX_CSCA_PUBKEY_LENGTH / 2; i++) {
|
||||
shifted_csca_pubKey_bytes[MAX_CSCA_PUBKEY_LENGTH / 2 + i] === extracted_csca_pubKey[i];
|
||||
}
|
||||
// if it's rsa, we just check if the keys are the same
|
||||
// in rsa, csca_pubKey_actual_size is the size of the key in bytes
|
||||
} else {
|
||||
component lessThans[MAX_CSCA_PUBKEY_LENGTH];
|
||||
for (var i = 0; i < MAX_CSCA_PUBKEY_LENGTH; i++) {
|
||||
lessThans[i] = LessThan(14);
|
||||
lessThans[i].in[0] <== i;
|
||||
lessThans[i].in[1] <== csca_pubKey_actual_size;
|
||||
|
||||
// If i < csca_pubKey_actual_size => must match
|
||||
// If i >= csca_pubKey_actual_size => no constraint
|
||||
(shifted_csca_pubKey_bytes[i] - extracted_csca_pubKey[i]) * lessThans[i].out === 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "circomlib/circuits/poseidon.circom";
|
||||
include "@openpassport/zk-email-circuits/utils/bytes.circom";
|
||||
include "./customHashers.circom";
|
||||
|
||||
template ComputeCommitment() {
|
||||
|
||||
signal input secret;
|
||||
signal input attestation_id;
|
||||
signal input leaf;
|
||||
signal input dg1[93];
|
||||
signal input dg2_hash[64];
|
||||
signal output out;
|
||||
|
||||
component poseidon_hasher = Poseidon(7);
|
||||
poseidon_hasher.inputs[0] <== secret;
|
||||
poseidon_hasher.inputs[1] <== attestation_id;
|
||||
poseidon_hasher.inputs[2] <== leaf;
|
||||
|
||||
signal dg1_packed[3] <== PackBytes(93)(dg1);
|
||||
for (var i = 0; i < 3; i++) {
|
||||
poseidon_hasher.inputs[i + 3] <== dg1_packed[i];
|
||||
}
|
||||
|
||||
signal dg2Hash2 <== CustomHasher(64)(dg2_hash);
|
||||
|
||||
poseidon_hasher.inputs[6] <== dg2Hash2;
|
||||
|
||||
out <== poseidon_hasher.out;
|
||||
}
|
||||
26
circuits/circuits/utils/passport/constants.circom
Normal file
26
circuits/circuits/utils/passport/constants.circom
Normal file
@@ -0,0 +1,26 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
/// @title Constants
|
||||
/// @notice Contains constants for the passport circuit
|
||||
|
||||
/// @notice Maximum length of DSC certificate — currently 1792 bytes
|
||||
/// @dev Empirically, we saw DSCs up to 1591 bytes.
|
||||
function getMaxDSCLength(){
|
||||
return 1792;
|
||||
}
|
||||
|
||||
/// @notice Maximum length of CSCA certificate — currently 1792 bytes.
|
||||
/// @dev Empirically, we saw CSCAs up to 1671 bytes in the master list.
|
||||
function getMaxCSCALength(){
|
||||
return 1792;
|
||||
}
|
||||
|
||||
/// @notice Maximum number of levels in the CSCA Merkle tree — currently 12
|
||||
function getMaxCSCALevels(){
|
||||
return 12;
|
||||
}
|
||||
|
||||
/// @notice Maximum number of levels in the DSC Merkle tree — currently 12
|
||||
function getMaxDSCLevels(){
|
||||
return 21;
|
||||
}
|
||||
@@ -1,41 +1,60 @@
|
||||
pragma circom 2.1.9;
|
||||
include "../crypto/bigInt/bigIntFunc.circom";
|
||||
include "circomlib/circuits/poseidon.circom";
|
||||
include "@openpassport/zk-email-circuits/utils/bytes.circom";
|
||||
|
||||
/// @notice CutomHasher circuit - used to Poseidon up to 256 signals
|
||||
/// @param k Number of signals to hash
|
||||
/// @input in Input signals
|
||||
/// @output out Output hash
|
||||
|
||||
template CustomHasher(k) {
|
||||
signal input in[k];
|
||||
var rounds = div_ceil(k, 16);
|
||||
assert(rounds < 17);
|
||||
|
||||
component hash[rounds];
|
||||
for (var i = 0; i < rounds ; i ++){
|
||||
hash[i] = Poseidon(16);
|
||||
signal output out;
|
||||
|
||||
if (k < 16){ // if k is less than 16, we can use a single poseidon hash
|
||||
component hash = Poseidon(k);
|
||||
for (var i = 0; i < k; i++){
|
||||
hash.inputs[i] <== in[i];
|
||||
}
|
||||
out <== hash.out;
|
||||
}
|
||||
|
||||
for (var i = 0; i < rounds ; i ++){
|
||||
for (var j = 0; j < 16 ; j ++){
|
||||
if (i * 16 + j < k){
|
||||
hash[i].inputs[j] <== in[i * 16 + j];
|
||||
} else {
|
||||
hash[i].inputs[j] <== 0;
|
||||
|
||||
else{
|
||||
// do up to 16 rounds of poseidon
|
||||
var rounds = div_ceil(k, 16);
|
||||
assert(rounds < 17);
|
||||
component hash[rounds];
|
||||
for (var i = 0; i < rounds ; i ++){
|
||||
hash[i] = Poseidon(16);
|
||||
}
|
||||
|
||||
for (var i = 0; i < rounds ; i ++){
|
||||
for (var j = 0; j < 16 ; j ++){
|
||||
if (i * 16 + j < k){
|
||||
hash[i].inputs[j] <== in[i * 16 + j];
|
||||
} else {
|
||||
hash[i].inputs[j] <== 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component finalHash = Poseidon(rounds);
|
||||
for (var i = 0 ; i < rounds ; i++) {
|
||||
finalHash.inputs[i] <== hash[i].out;
|
||||
component finalHash = Poseidon(rounds);
|
||||
for (var i = 0 ; i < rounds ; i++) {
|
||||
finalHash.inputs[i] <== hash[i].out;
|
||||
}
|
||||
out <== finalHash.out;
|
||||
}
|
||||
signal output out <== finalHash.out;
|
||||
}
|
||||
|
||||
template LeafHasher(k) {
|
||||
/// @notice PackBytesAndPoseidon circuit — used to pack a byte array and hash it
|
||||
/// @param k Size of the array to pack
|
||||
/// @param in Input array
|
||||
/// @param out Output hash
|
||||
template PackBytesAndPoseidon(k) {
|
||||
var packed_length = computeIntChunkLength(k);
|
||||
|
||||
signal input in[k];
|
||||
signal input sigAlg;
|
||||
component leafHasher = CustomHasher(k+1);
|
||||
leafHasher.in[0] <== sigAlg;
|
||||
for (var i = 0; i < k; i++){
|
||||
leafHasher.in[i+1] <== in[i];
|
||||
}
|
||||
signal output out <== leafHasher.out;
|
||||
signal packed[packed_length] <== PackBytes(k)(in);
|
||||
signal output out <== CustomHasher(packed_length)(packed);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user