mirror of
https://github.com/selfxyz/self.git
synced 2026-04-05 03:00:53 -04:00
Merge pull request #395 from selfxyz/feat/mock-passport
add staging proving flow
This commit is contained in:
@@ -3,12 +3,11 @@ import { TouchableOpacity } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { ChevronDown, Cpu, Minus, Plus, X } from '@tamagui/lucide-icons';
|
||||
import { ChevronDown, Minus, Plus, X } from '@tamagui/lucide-icons';
|
||||
import { flag } from 'country-emoji';
|
||||
import getCountryISO2 from 'country-iso-3-to-2';
|
||||
import {
|
||||
Button,
|
||||
Fieldset,
|
||||
ScrollView,
|
||||
Separator,
|
||||
Sheet,
|
||||
@@ -21,7 +20,13 @@ import {
|
||||
|
||||
import { countryCodes } from '../../../common/src/constants/constants';
|
||||
import { genMockPassportData } from '../../../common/src/utils/passports/genMockPassportData';
|
||||
import { usePassport } from '../stores/passportDataProvider';
|
||||
import { initPassportDataParsing } from '../../../common/src/utils/passports/passport';
|
||||
import ButtonsContainer from '../components/ButtonsContainer';
|
||||
import { PrimaryButton } from '../components/buttons/PrimaryButton';
|
||||
import { SecondaryButton } from '../components/buttons/SecondaryButton';
|
||||
import { BodyText } from '../components/typography/BodyText';
|
||||
import { Title } from '../components/typography/Title';
|
||||
import { storePassportData } from '../stores/passportDataProvider';
|
||||
import { borderColor, separatorColor, textBlack, white } from '../utils/colors';
|
||||
import { buttonTap, selectionChange } from '../utils/haptic';
|
||||
|
||||
@@ -42,8 +47,6 @@ const MockDataScreen: React.FC<MockDataScreenProps> = ({}) => {
|
||||
date.toISOString().slice(8, 10)
|
||||
).toString();
|
||||
};
|
||||
const { setData } = usePassport();
|
||||
|
||||
const [selectedCountry, setSelectedCountry] = useState('USA');
|
||||
const [selectedAlgorithm, setSelectedAlgorithm] = useState('rsa sha256');
|
||||
const [isCountrySheetOpen, setCountrySheetOpen] = useState(false);
|
||||
@@ -60,9 +63,20 @@ const MockDataScreen: React.FC<MockDataScreenProps> = ({}) => {
|
||||
};
|
||||
|
||||
const signatureAlgorithmToStrictSignatureAlgorithm = {
|
||||
'rsa sha256': 'rsa_sha256_65537_4096',
|
||||
'rsa sha1': 'rsa_sha1_65537_2048',
|
||||
'rsapss sha256': 'rsapss_sha256_65537_2048',
|
||||
'rsa sha256': ['sha256', 'sha256', 'rsa_sha256_65537_4096'],
|
||||
'rsa sha1': ['sha256', 'sha256', 'rsa_sha1_65537_2048'],
|
||||
'rsapss sha256': ['sha256', 'sha256', 'rsapss_sha256_65537_2048'],
|
||||
'sha256 brainpoolP256r1': [
|
||||
'sha256',
|
||||
'sha256',
|
||||
'ecdsa_sha384_brainpoolP256r1_256',
|
||||
],
|
||||
'sha384 brainpoolP384r1': [
|
||||
'sha384',
|
||||
'sha384',
|
||||
'ecdsa_sha384_brainpoolP384r1_384',
|
||||
],
|
||||
'sha384 secp384r1': ['sha384', 'sha384', 'ecdsa_sha384_secp384r1_384'],
|
||||
} as const;
|
||||
|
||||
const handleGenerate = useCallback(async () => {
|
||||
@@ -73,15 +87,18 @@ const MockDataScreen: React.FC<MockDataScreenProps> = ({}) => {
|
||||
.replace(/[^a-z0-9]/gi, '')
|
||||
.toUpperCase();
|
||||
await new Promise(resolve =>
|
||||
setTimeout(() => {
|
||||
setTimeout(async () => {
|
||||
let mockPassportData;
|
||||
const [hashFunction1, hashFunction2, signatureAlgorithm] =
|
||||
signatureAlgorithmToStrictSignatureAlgorithm[
|
||||
selectedAlgorithm as keyof typeof signatureAlgorithmToStrictSignatureAlgorithm
|
||||
];
|
||||
|
||||
if (isInOfacList) {
|
||||
mockPassportData = genMockPassportData(
|
||||
'sha1',
|
||||
'sha256',
|
||||
signatureAlgorithmToStrictSignatureAlgorithm[
|
||||
selectedAlgorithm as keyof typeof signatureAlgorithmToStrictSignatureAlgorithm
|
||||
],
|
||||
hashFunction1,
|
||||
hashFunction2,
|
||||
signatureAlgorithm,
|
||||
selectedCountry as keyof typeof countryCodes,
|
||||
// We disregard the age to stick with Arcangel's birth date
|
||||
'541007',
|
||||
@@ -92,19 +109,17 @@ const MockDataScreen: React.FC<MockDataScreenProps> = ({}) => {
|
||||
);
|
||||
} else {
|
||||
mockPassportData = genMockPassportData(
|
||||
'sha1',
|
||||
'sha256',
|
||||
signatureAlgorithmToStrictSignatureAlgorithm[
|
||||
selectedAlgorithm as keyof typeof signatureAlgorithmToStrictSignatureAlgorithm
|
||||
],
|
||||
hashFunction1,
|
||||
hashFunction2,
|
||||
signatureAlgorithm,
|
||||
selectedCountry as keyof typeof countryCodes,
|
||||
castDate(-age),
|
||||
castDate(expiryYears),
|
||||
randomPassportNumber,
|
||||
);
|
||||
}
|
||||
|
||||
setData(mockPassportData);
|
||||
mockPassportData = initPassportDataParsing(mockPassportData);
|
||||
await storePassportData(mockPassportData);
|
||||
resolve(null);
|
||||
}, 0),
|
||||
);
|
||||
@@ -117,172 +132,144 @@ const MockDataScreen: React.FC<MockDataScreenProps> = ({}) => {
|
||||
|
||||
const { top, bottom } = useSafeAreaInsets();
|
||||
return (
|
||||
<>
|
||||
<YStack
|
||||
f={1}
|
||||
gap="$4"
|
||||
px="$4"
|
||||
backgroundColor={white}
|
||||
paddingTop={top}
|
||||
paddingBottom={bottom}
|
||||
>
|
||||
<Text my="$9" textAlign="center" fontSize="$9" color={textBlack}>
|
||||
Generate passport data
|
||||
</Text>
|
||||
<XStack ai="center">
|
||||
<Text f={1} fontSize="$5">
|
||||
Encryption
|
||||
</Text>
|
||||
<Button
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setAlgorithmSheetOpen(true);
|
||||
}}
|
||||
p="$2"
|
||||
px="$3"
|
||||
bg="white"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$4"
|
||||
>
|
||||
<XStack ai="center" gap="$2">
|
||||
<Text fontSize="$4">{selectedAlgorithm}</Text>
|
||||
<ChevronDown size={20} />
|
||||
</XStack>
|
||||
</Button>
|
||||
</XStack>
|
||||
<XStack ai="center">
|
||||
<Text f={1} fontSize="$5">
|
||||
Nationality
|
||||
</Text>
|
||||
<Button
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setCountrySheetOpen(true);
|
||||
}}
|
||||
p="$2"
|
||||
px="$3"
|
||||
bg="white"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$4"
|
||||
>
|
||||
<XStack ai="center" gap="$2">
|
||||
<Text fontSize="$4">
|
||||
{countryCodes[selectedCountry as keyof typeof countryCodes]}{' '}
|
||||
{flag(getCountryISO2(selectedCountry))}
|
||||
</Text>
|
||||
<ChevronDown size={20} />
|
||||
</XStack>
|
||||
</Button>
|
||||
</XStack>
|
||||
<YStack f={1} bg={white} pt={top} pb={bottom}>
|
||||
<ScrollView showsVerticalScrollIndicator={false}>
|
||||
<YStack px="$4" pb="$4" gap="$5">
|
||||
<YStack ai="center" mb={'$10'}>
|
||||
<Title>Generate Passport Data</Title>
|
||||
<BodyText textAlign="center">
|
||||
Configure the passport data parameters below
|
||||
</BodyText>
|
||||
</YStack>
|
||||
|
||||
<Fieldset mt="$2" gap="$2" horizontal>
|
||||
<Text
|
||||
color={textBlack}
|
||||
width={160}
|
||||
justifyContent="flex-end"
|
||||
fontSize="$5"
|
||||
>
|
||||
Age (🎂)
|
||||
</Text>
|
||||
<XStack f={1} />
|
||||
|
||||
<Button
|
||||
h="$3.5"
|
||||
w="$3.5"
|
||||
bg="white"
|
||||
jc="center"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$10"
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setAge(age - 1);
|
||||
}}
|
||||
disabled={age <= 0 || isInOfacList}
|
||||
>
|
||||
<Minus />
|
||||
</Button>
|
||||
<Text textAlign="center" w="$6" color={textBlack} fontSize="$5">
|
||||
{isInOfacList ? 71 : age} yo
|
||||
</Text>
|
||||
<Button
|
||||
h="$3.5"
|
||||
w="$3.5"
|
||||
bg="white"
|
||||
jc="center"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$10"
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setAge(age + 1);
|
||||
}}
|
||||
disabled={isInOfacList}
|
||||
>
|
||||
<Plus />
|
||||
</Button>
|
||||
</Fieldset>
|
||||
|
||||
<Fieldset gap="$2" horizontal>
|
||||
<Text
|
||||
color={textBlack}
|
||||
width={160}
|
||||
justifyContent="flex-end"
|
||||
fontSize="$5"
|
||||
>
|
||||
Passport expires in
|
||||
</Text>
|
||||
<XStack f={1} />
|
||||
|
||||
<Button
|
||||
h="$3.5"
|
||||
w="$3.5"
|
||||
bg="white"
|
||||
jc="center"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$10"
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setExpiryYears(expiryYears - 1);
|
||||
}}
|
||||
disabled={expiryYears <= 0}
|
||||
>
|
||||
<Minus />
|
||||
</Button>
|
||||
<Text textAlign="center" w="$6" color={textBlack} fontSize="$5">
|
||||
{expiryYears} years
|
||||
</Text>
|
||||
<Button
|
||||
h="$3.5"
|
||||
w="$3.5"
|
||||
bg="white"
|
||||
jc="center"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$10"
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setExpiryYears(expiryYears + 1);
|
||||
}}
|
||||
>
|
||||
<Plus />
|
||||
</Button>
|
||||
</Fieldset>
|
||||
|
||||
<YStack>
|
||||
<Fieldset mt="$2" gap="$2" horizontal>
|
||||
<Text
|
||||
color={textBlack}
|
||||
width={160}
|
||||
justifyContent="flex-end"
|
||||
fontSize="$5"
|
||||
<XStack ai="center" jc="space-between">
|
||||
<BodyText>Encryption</BodyText>
|
||||
<Button
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setAlgorithmSheetOpen(true);
|
||||
}}
|
||||
p="$2"
|
||||
px="$3"
|
||||
bg="white"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$4"
|
||||
>
|
||||
Is in OFAC list
|
||||
</Text>
|
||||
<XStack f={1} />
|
||||
<XStack ai="center" gap="$2">
|
||||
<Text fontSize="$4">{selectedAlgorithm}</Text>
|
||||
<ChevronDown size={20} />
|
||||
</XStack>
|
||||
</Button>
|
||||
</XStack>
|
||||
|
||||
<XStack ai="center" jc="space-between">
|
||||
<BodyText>Nationality</BodyText>
|
||||
<Button
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setCountrySheetOpen(true);
|
||||
}}
|
||||
p="$2"
|
||||
px="$3"
|
||||
bg="white"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$4"
|
||||
>
|
||||
<XStack ai="center" gap="$2">
|
||||
<Text fontSize="$4">
|
||||
{countryCodes[selectedCountry as keyof typeof countryCodes]}{' '}
|
||||
{flag(getCountryISO2(selectedCountry))}
|
||||
</Text>
|
||||
<ChevronDown size={20} />
|
||||
</XStack>
|
||||
</Button>
|
||||
</XStack>
|
||||
|
||||
<XStack ai="center" jc="space-between">
|
||||
<BodyText>Age (🎂)</BodyText>
|
||||
<XStack ai="center" gap="$2">
|
||||
<Button
|
||||
h="$3.5"
|
||||
w="$3.5"
|
||||
bg="white"
|
||||
jc="center"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$10"
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setAge(age - 1);
|
||||
}}
|
||||
disabled={age <= 0 || isInOfacList}
|
||||
>
|
||||
<Minus />
|
||||
</Button>
|
||||
<Text textAlign="center" w="$6" color={textBlack} fontSize="$5">
|
||||
{isInOfacList ? 71 : age} yo
|
||||
</Text>
|
||||
<Button
|
||||
h="$3.5"
|
||||
w="$3.5"
|
||||
bg="white"
|
||||
jc="center"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$10"
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setAge(age + 1);
|
||||
}}
|
||||
disabled={isInOfacList}
|
||||
>
|
||||
<Plus />
|
||||
</Button>
|
||||
</XStack>
|
||||
</XStack>
|
||||
|
||||
<XStack ai="center" jc="space-between">
|
||||
<BodyText>Passport expires in</BodyText>
|
||||
<XStack ai="center" gap="$2">
|
||||
<Button
|
||||
h="$3.5"
|
||||
w="$3.5"
|
||||
bg="white"
|
||||
jc="center"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$10"
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setExpiryYears(expiryYears - 1);
|
||||
}}
|
||||
disabled={expiryYears <= 0}
|
||||
>
|
||||
<Minus />
|
||||
</Button>
|
||||
<Text textAlign="center" w="$6" color={textBlack} fontSize="$5">
|
||||
{expiryYears} years
|
||||
</Text>
|
||||
<Button
|
||||
h="$3.5"
|
||||
w="$3.5"
|
||||
bg="white"
|
||||
jc="center"
|
||||
borderColor={borderColor}
|
||||
borderWidth={1}
|
||||
borderRadius="$10"
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
setExpiryYears(expiryYears + 1);
|
||||
}}
|
||||
>
|
||||
<Plus />
|
||||
</Button>
|
||||
</XStack>
|
||||
</XStack>
|
||||
|
||||
<XStack ai="center" jc="space-between">
|
||||
<BodyText>In OFAC list</BodyText>
|
||||
<Switch
|
||||
size="$3.5"
|
||||
checked={isInOfacList}
|
||||
@@ -294,31 +281,32 @@ const MockDataScreen: React.FC<MockDataScreenProps> = ({}) => {
|
||||
>
|
||||
<Switch.Thumb animation="quick" bc="white" />
|
||||
</Switch>
|
||||
</Fieldset>
|
||||
<Text
|
||||
mt="$2"
|
||||
color="$red10"
|
||||
justifyContent="flex-end"
|
||||
fontSize="$3"
|
||||
style={{ opacity: isInOfacList ? 1 : 0 }}
|
||||
>
|
||||
OFAC list is a list of people who are suspected of being involved in
|
||||
terrorism or other illegal activities.
|
||||
</Text>
|
||||
</YStack>
|
||||
</XStack>
|
||||
|
||||
<YStack f={1} />
|
||||
|
||||
<YStack>
|
||||
<Text mb="$2" textAlign="center" fontSize="$4" color={textBlack}>
|
||||
These passport data are only for testing purposes.
|
||||
</Text>
|
||||
<Button onPress={handleGenerate} disabled={isGenerating}>
|
||||
{isGenerating ? <Spinner /> : <Cpu color={textBlack} />} Generate
|
||||
passport data
|
||||
</Button>
|
||||
{isInOfacList && (
|
||||
<Text color="$red10" fontSize="$3">
|
||||
OFAC list is a list of people who are suspected of being involved
|
||||
in terrorism or other illegal activities.
|
||||
</Text>
|
||||
)}
|
||||
</YStack>
|
||||
</ScrollView>
|
||||
|
||||
<YStack px="$4" pb="$4">
|
||||
<ButtonsContainer>
|
||||
<PrimaryButton onPress={handleGenerate} disabled={isGenerating}>
|
||||
{isGenerating ? (
|
||||
<Spinner color="white" size="small" />
|
||||
) : (
|
||||
'Generate Passport Data'
|
||||
)}
|
||||
</PrimaryButton>
|
||||
<SecondaryButton onPress={() => navigation.goBack()}>
|
||||
Cancel
|
||||
</SecondaryButton>
|
||||
</ButtonsContainer>
|
||||
</YStack>
|
||||
|
||||
<Sheet
|
||||
modal
|
||||
open={isCountrySheetOpen}
|
||||
@@ -399,7 +387,14 @@ const MockDataScreen: React.FC<MockDataScreenProps> = ({}) => {
|
||||
</XStack>
|
||||
<Separator borderColor={separatorColor} mb="$4" />
|
||||
<ScrollView showsVerticalScrollIndicator={false}>
|
||||
{['rsa sha256', 'rsa sha1', 'rsapss sha256'].map(algorithm => (
|
||||
{[
|
||||
'rsa sha256',
|
||||
'rsa sha1',
|
||||
'rsapss sha256',
|
||||
'sha256 brainpoolP256r1',
|
||||
'sha384 brainpoolP384r1',
|
||||
'sha384 secp384r1',
|
||||
].map(algorithm => (
|
||||
<TouchableOpacity
|
||||
key={algorithm}
|
||||
onPress={() => {
|
||||
@@ -417,7 +412,7 @@ const MockDataScreen: React.FC<MockDataScreenProps> = ({}) => {
|
||||
</YStack>
|
||||
</Sheet.Frame>
|
||||
</Sheet>
|
||||
</>
|
||||
</YStack>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -67,12 +67,11 @@ const routes = [
|
||||
|
||||
// get the actual type of the routes so we can use in the onMenuPress function so it
|
||||
// doesnt worry about us linking to screens with required props which we dont want to go to anyway
|
||||
type RouteLinks = (typeof routes)[number][2];
|
||||
type RouteLinks = (typeof routes)[number][2] | (typeof DEBUG_MENU)[number][2];
|
||||
|
||||
const DEBUG_MENU: [React.FC<SvgProps>, string, RouteOption] = [
|
||||
Bug as React.FC<SvgProps>,
|
||||
'Debug menu',
|
||||
'DevSettings',
|
||||
const DEBUG_MENU: [React.FC<SvgProps>, string, RouteOption][] = [
|
||||
[Data as React.FC<SvgProps>, 'Gen Mock Passport Data', 'CreateMock'],
|
||||
[Bug as React.FC<SvgProps>, 'Debug menu', 'DevSettings'],
|
||||
];
|
||||
|
||||
const social = [
|
||||
@@ -123,7 +122,7 @@ const SettingsScreen: React.FC<SettingsScreenProps> = ({}) => {
|
||||
const navigation = useNavigation();
|
||||
|
||||
const screenRoutes = useMemo(() => {
|
||||
return isDevMode ? [...routes, DEBUG_MENU] : routes;
|
||||
return isDevMode ? [...routes, ...DEBUG_MENU] : routes;
|
||||
}, [isDevMode]);
|
||||
|
||||
const twoFingerTap = Gesture.Tap()
|
||||
@@ -175,7 +174,7 @@ ${deviceInfo.map(([k, v]) => `${k}=${v}`).join('; ')}
|
||||
break;
|
||||
|
||||
default:
|
||||
navigation.navigate(menuRoute);
|
||||
navigation.navigate(menuRoute as any);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -89,7 +89,8 @@ const handleResponseIOS = (response: any) => {
|
||||
signedAttr: signedEContentArray,
|
||||
encryptedDigest: encryptedDigestArray,
|
||||
parsed: false,
|
||||
};
|
||||
documentType: 'passport',
|
||||
} as PassportData;
|
||||
};
|
||||
|
||||
const handleResponseAndroid = (response: any) => {
|
||||
@@ -131,5 +132,6 @@ const handleResponseAndroid = (response: any) => {
|
||||
eContent: JSON.parse(encapContent),
|
||||
signedAttr: JSON.parse(eContent),
|
||||
encryptedDigest: JSON.parse(encryptedDigest),
|
||||
documentType: 'passport',
|
||||
} as PassportData;
|
||||
};
|
||||
|
||||
131
app/src/utils/proving/inputs.ts
Normal file
131
app/src/utils/proving/inputs.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
|
||||
import { SMT } from '@openpassport/zk-kit-smt';
|
||||
import { poseidon2 } from 'poseidon-lite';
|
||||
|
||||
import nameAndDobSMTData from '../../../../common/ofacdata/outputs/nameAndDobSMT.json';
|
||||
import nameAndYobSMTData from '../../../../common/ofacdata/outputs/nameAndYobSMT.json';
|
||||
import passportNoAndNationalitySMTData from '../../../../common/ofacdata/outputs/passportNoAndNationalitySMT.json';
|
||||
import {
|
||||
DEFAULT_MAJORITY,
|
||||
PASSPORT_ATTESTATION_ID,
|
||||
attributeToPosition,
|
||||
} from '../../../../common/src/constants/constants';
|
||||
import { EndpointType, SelfApp } from '../../../../common/src/utils/appType';
|
||||
import { getCircuitNameFromPassportData } from '../../../../common/src/utils/circuits/circuitsName';
|
||||
import {
|
||||
generateCircuitInputsDSC,
|
||||
generateCircuitInputsRegister,
|
||||
generateCircuitInputsVCandDisclose,
|
||||
} from '../../../../common/src/utils/circuits/generateInputs';
|
||||
import {
|
||||
getCSCATree,
|
||||
getCommitmentTree,
|
||||
getDSCTree,
|
||||
} from '../../../../common/src/utils/trees';
|
||||
import { PassportData } from '../../../../common/src/utils/types';
|
||||
|
||||
export async function generateTeeInputsRegister(
|
||||
secret: string,
|
||||
passportData: PassportData,
|
||||
endpointType: EndpointType,
|
||||
) {
|
||||
const serialized_dsc_tree = await getDSCTree(endpointType);
|
||||
const inputs = generateCircuitInputsRegister(
|
||||
secret,
|
||||
passportData,
|
||||
serialized_dsc_tree,
|
||||
);
|
||||
const circuitName = getCircuitNameFromPassportData(passportData, 'register');
|
||||
if (circuitName == null) {
|
||||
throw new Error('Circuit name is null');
|
||||
}
|
||||
return { inputs, circuitName };
|
||||
}
|
||||
|
||||
export async function generateTeeInputsDsc(
|
||||
passportData: PassportData,
|
||||
endpointType: EndpointType,
|
||||
) {
|
||||
const serialized_csca_tree = await getCSCATree(endpointType);
|
||||
const inputs = generateCircuitInputsDSC(
|
||||
passportData.dsc,
|
||||
serialized_csca_tree,
|
||||
);
|
||||
const circuitName = getCircuitNameFromPassportData(passportData, 'dsc');
|
||||
if (circuitName == null) {
|
||||
throw new Error('Circuit name is null');
|
||||
}
|
||||
return { inputs, circuitName };
|
||||
}
|
||||
|
||||
export async function generateTeeInputsVCAndDisclose(
|
||||
secret: string,
|
||||
passportData: PassportData,
|
||||
selfApp: SelfApp,
|
||||
) {
|
||||
const { scope, userId, disclosures } = selfApp;
|
||||
|
||||
const selector_dg1 = Array(88).fill('0');
|
||||
|
||||
Object.entries(disclosures).forEach(([attribute, reveal]) => {
|
||||
if (['ofac', 'excludedCountries', 'minimumAge'].includes(attribute)) {
|
||||
return;
|
||||
}
|
||||
if (reveal) {
|
||||
const [start, end] =
|
||||
attributeToPosition[attribute as keyof typeof attributeToPosition];
|
||||
selector_dg1.fill('1', start, end + 1);
|
||||
}
|
||||
});
|
||||
|
||||
const majority = disclosures.minimumAge
|
||||
? disclosures.minimumAge.toString()
|
||||
: DEFAULT_MAJORITY;
|
||||
const selector_older_than = disclosures.minimumAge ? '1' : '0';
|
||||
|
||||
const selector_ofac = disclosures.ofac ? 1 : 0;
|
||||
|
||||
const { passportNoAndNationalitySMT, nameAndDobSMT, nameAndYobSMT } =
|
||||
await getOfacSMTs();
|
||||
const serialized_tree = await getCommitmentTree();
|
||||
const tree = LeanIMT.import((a, b) => poseidon2([a, b]), serialized_tree);
|
||||
console.log('tree', tree);
|
||||
// const commitment = generateCommitment(
|
||||
// secret,
|
||||
// PASSPORT_ATTESTATION_ID,
|
||||
// passportData,
|
||||
// );
|
||||
// tree.insert(BigInt(commitment));
|
||||
// Uncomment to add artificially the commitment to the tree
|
||||
|
||||
const inputs = generateCircuitInputsVCandDisclose(
|
||||
secret,
|
||||
PASSPORT_ATTESTATION_ID,
|
||||
passportData,
|
||||
scope,
|
||||
selector_dg1,
|
||||
selector_older_than,
|
||||
tree,
|
||||
majority,
|
||||
passportNoAndNationalitySMT,
|
||||
nameAndDobSMT,
|
||||
nameAndYobSMT,
|
||||
selector_ofac,
|
||||
disclosures.excludedCountries ?? [],
|
||||
userId,
|
||||
);
|
||||
return { inputs, circuitName: 'vc_and_disclose' };
|
||||
}
|
||||
|
||||
/*** DISCLOSURE ***/
|
||||
|
||||
async function getOfacSMTs() {
|
||||
// TODO: get the SMT from an endpoint
|
||||
const passportNoAndNationalitySMT = new SMT(poseidon2, true);
|
||||
passportNoAndNationalitySMT.import(passportNoAndNationalitySMTData);
|
||||
const nameAndDobSMT = new SMT(poseidon2, true);
|
||||
nameAndDobSMT.import(nameAndDobSMTData);
|
||||
const nameAndYobSMT = new SMT(poseidon2, true);
|
||||
nameAndYobSMT.import(nameAndYobSMTData);
|
||||
return { passportNoAndNationalitySMT, nameAndDobSMT, nameAndYobSMT };
|
||||
}
|
||||
@@ -1,55 +1,31 @@
|
||||
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
|
||||
import { SMT } from '@openpassport/zk-kit-smt';
|
||||
import { poseidon2 } from 'poseidon-lite';
|
||||
|
||||
import nameAndDobSMTData from '../../../../common/ofacdata/outputs/nameAndDobSMT.json';
|
||||
import nameAndYobSMTData from '../../../../common/ofacdata/outputs/nameAndYobSMT.json';
|
||||
import passportNoAndNationalitySMTData from '../../../../common/ofacdata/outputs/passportNoAndNationalitySMT.json';
|
||||
import {
|
||||
API_URL,
|
||||
DEFAULT_MAJORITY,
|
||||
PASSPORT_ATTESTATION_ID,
|
||||
WS_RPC_URL_VC_AND_DISCLOSE,
|
||||
attributeToPosition,
|
||||
} from '../../../../common/src/constants/constants';
|
||||
import { SelfApp } from '../../../../common/src/utils/appType';
|
||||
import { EndpointType, SelfApp } from '../../../../common/src/utils/appType';
|
||||
import { getCircuitNameFromPassportData } from '../../../../common/src/utils/circuits/circuitsName';
|
||||
import {
|
||||
generateCircuitInputsDSC,
|
||||
generateCircuitInputsRegister,
|
||||
generateCircuitInputsVCandDisclose,
|
||||
} from '../../../../common/src/utils/circuits/generateInputs';
|
||||
import {
|
||||
generateCommitment,
|
||||
generateNullifier,
|
||||
} from '../../../../common/src/utils/passports/passport';
|
||||
import {
|
||||
getCSCATree,
|
||||
getCommitmentTree,
|
||||
getDSCTree,
|
||||
getLeafDscTree,
|
||||
} from '../../../../common/src/utils/trees';
|
||||
import { PassportData } from '../../../../common/src/utils/types';
|
||||
import { ProofStatusEnum } from '../../stores/proofProvider';
|
||||
import {
|
||||
generateTeeInputsDsc,
|
||||
generateTeeInputsRegister,
|
||||
generateTeeInputsVCAndDisclose,
|
||||
} from './inputs';
|
||||
import { sendPayload } from './tee';
|
||||
|
||||
async function generateTeeInputsRegister(
|
||||
secret: string,
|
||||
passportData: PassportData,
|
||||
) {
|
||||
const serialized_dsc_tree = await getDSCTree();
|
||||
const inputs = generateCircuitInputsRegister(
|
||||
secret,
|
||||
passportData,
|
||||
serialized_dsc_tree,
|
||||
);
|
||||
const circuitName = getCircuitNameFromPassportData(passportData, 'register');
|
||||
if (circuitName == null) {
|
||||
throw new Error('Circuit name is null');
|
||||
}
|
||||
return { inputs, circuitName };
|
||||
}
|
||||
|
||||
export type PassportSupportStatus =
|
||||
| 'passport_metadata_missing'
|
||||
| 'csca_not_found'
|
||||
@@ -99,18 +75,20 @@ export async function sendRegisterPayload(
|
||||
passportData: PassportData,
|
||||
secret: string,
|
||||
circuitDNSMapping: Record<string, string>,
|
||||
endpointType: EndpointType,
|
||||
) {
|
||||
const { inputs, circuitName } = await generateTeeInputsRegister(
|
||||
secret,
|
||||
passportData,
|
||||
endpointType,
|
||||
);
|
||||
await sendPayload(
|
||||
inputs,
|
||||
'register',
|
||||
circuitName,
|
||||
'https',
|
||||
endpointType,
|
||||
'https://self.xyz',
|
||||
circuitDNSMapping[circuitName],
|
||||
(circuitDNSMapping as any).REGISTER[circuitName],
|
||||
undefined,
|
||||
{
|
||||
updateGlobalOnSuccess: true,
|
||||
@@ -120,23 +98,11 @@ export async function sendRegisterPayload(
|
||||
);
|
||||
}
|
||||
|
||||
async function generateTeeInputsDsc(passportData: PassportData) {
|
||||
const serialized_csca_tree = await getCSCATree();
|
||||
const inputs = generateCircuitInputsDSC(
|
||||
passportData.dsc,
|
||||
serialized_csca_tree,
|
||||
);
|
||||
const circuitName = getCircuitNameFromPassportData(passportData, 'dsc');
|
||||
if (circuitName == null) {
|
||||
throw new Error('Circuit name is null');
|
||||
}
|
||||
return { inputs, circuitName };
|
||||
}
|
||||
|
||||
async function checkIdPassportDscIsInTree(
|
||||
passportData: PassportData,
|
||||
dscTree: string,
|
||||
circuitDNSMapping: Record<string, string>,
|
||||
endpointType: EndpointType,
|
||||
): Promise<boolean> {
|
||||
const hashFunction = (a: any, b: any) => poseidon2([a, b]);
|
||||
const tree = LeanIMT.import(hashFunction, dscTree);
|
||||
@@ -148,7 +114,11 @@ async function checkIdPassportDscIsInTree(
|
||||
const index = tree.indexOf(BigInt(leaf));
|
||||
if (index === -1) {
|
||||
console.log('DSC is not found in the tree, sending DSC payload');
|
||||
const dscStatus = await sendDscPayload(passportData, circuitDNSMapping);
|
||||
const dscStatus = await sendDscPayload(
|
||||
passportData,
|
||||
circuitDNSMapping,
|
||||
endpointType,
|
||||
);
|
||||
if (dscStatus !== ProofStatusEnum.SUCCESS) {
|
||||
console.log('DSC proof failed');
|
||||
return false;
|
||||
@@ -168,6 +138,7 @@ async function checkIdPassportDscIsInTree(
|
||||
export async function sendDscPayload(
|
||||
passportData: PassportData,
|
||||
circuitDNSMapping: Record<string, string>,
|
||||
endpointType: EndpointType,
|
||||
): Promise<ProofStatusEnum | false> {
|
||||
if (!passportData) {
|
||||
return false;
|
||||
@@ -177,93 +148,24 @@ export async function sendDscPayload(
|
||||
// console.log('Passport not supported');
|
||||
// return false;
|
||||
// }
|
||||
const { inputs, circuitName } = await generateTeeInputsDsc(passportData);
|
||||
console.log('circuitName', circuitName);
|
||||
const { inputs, circuitName } = await generateTeeInputsDsc(
|
||||
passportData,
|
||||
endpointType,
|
||||
);
|
||||
|
||||
const dscStatus = await sendPayload(
|
||||
inputs,
|
||||
'dsc',
|
||||
circuitName,
|
||||
'https',
|
||||
endpointType,
|
||||
'https://self.xyz',
|
||||
circuitDNSMapping[circuitName],
|
||||
(circuitDNSMapping.DSC as any)[circuitName],
|
||||
undefined,
|
||||
{ updateGlobalOnSuccess: false },
|
||||
);
|
||||
return dscStatus;
|
||||
}
|
||||
|
||||
/*** DISCLOSURE ***/
|
||||
|
||||
async function getOfacSMTs() {
|
||||
// TODO: get the SMT from an endpoint
|
||||
const passportNoAndNationalitySMT = new SMT(poseidon2, true);
|
||||
passportNoAndNationalitySMT.import(passportNoAndNationalitySMTData);
|
||||
const nameAndDobSMT = new SMT(poseidon2, true);
|
||||
nameAndDobSMT.import(nameAndDobSMTData);
|
||||
const nameAndYobSMT = new SMT(poseidon2, true);
|
||||
nameAndYobSMT.import(nameAndYobSMTData);
|
||||
return { passportNoAndNationalitySMT, nameAndDobSMT, nameAndYobSMT };
|
||||
}
|
||||
|
||||
async function generateTeeInputsVCAndDisclose(
|
||||
secret: string,
|
||||
passportData: PassportData,
|
||||
selfApp: SelfApp,
|
||||
) {
|
||||
const { scope, userId, disclosures } = selfApp;
|
||||
|
||||
const selector_dg1 = Array(88).fill('0');
|
||||
|
||||
Object.entries(disclosures).forEach(([attribute, reveal]) => {
|
||||
if (['ofac', 'excludedCountries', 'minimumAge'].includes(attribute)) {
|
||||
return;
|
||||
}
|
||||
if (reveal) {
|
||||
const [start, end] =
|
||||
attributeToPosition[attribute as keyof typeof attributeToPosition];
|
||||
selector_dg1.fill('1', start, end + 1);
|
||||
}
|
||||
});
|
||||
|
||||
const majority = disclosures.minimumAge
|
||||
? disclosures.minimumAge.toString()
|
||||
: DEFAULT_MAJORITY;
|
||||
const selector_older_than = disclosures.minimumAge ? '1' : '0';
|
||||
|
||||
const selector_ofac = disclosures.ofac ? 1 : 0;
|
||||
|
||||
const { passportNoAndNationalitySMT, nameAndDobSMT, nameAndYobSMT } =
|
||||
await getOfacSMTs();
|
||||
const serialized_tree = await getCommitmentTree();
|
||||
const tree = LeanIMT.import((a, b) => poseidon2([a, b]), serialized_tree);
|
||||
console.log('tree', tree);
|
||||
// const commitment = generateCommitment(
|
||||
// secret,
|
||||
// PASSPORT_ATTESTATION_ID,
|
||||
// passportData,
|
||||
// );
|
||||
// tree.insert(BigInt(commitment));
|
||||
// Uncomment to add artificially the commitment to the tree
|
||||
|
||||
const inputs = generateCircuitInputsVCandDisclose(
|
||||
secret,
|
||||
PASSPORT_ATTESTATION_ID,
|
||||
passportData,
|
||||
scope,
|
||||
selector_dg1,
|
||||
selector_older_than,
|
||||
tree,
|
||||
majority,
|
||||
passportNoAndNationalitySMT,
|
||||
nameAndDobSMT,
|
||||
nameAndYobSMT,
|
||||
selector_ofac,
|
||||
disclosures.excludedCountries ?? [],
|
||||
userId,
|
||||
);
|
||||
return { inputs, circuitName: 'vc_and_disclose' };
|
||||
}
|
||||
|
||||
export async function sendVcAndDisclosePayload(
|
||||
secret: string,
|
||||
passportData: PassportData | null,
|
||||
@@ -331,20 +233,30 @@ export async function registerPassport(
|
||||
secret: string,
|
||||
) {
|
||||
// First get the mapping, then use it for the check
|
||||
const endpointType =
|
||||
passportData.documentType && passportData.documentType === 'mock_passport'
|
||||
? 'staging_celo'
|
||||
: 'celo';
|
||||
const [circuitDNSMapping, dscTree] = await Promise.all([
|
||||
getCircuitDNSMapping(),
|
||||
getDSCTree(),
|
||||
getDSCTree(endpointType),
|
||||
]);
|
||||
console.log('circuitDNSMapping', circuitDNSMapping);
|
||||
const dscOk = await checkIdPassportDscIsInTree(
|
||||
passportData,
|
||||
dscTree,
|
||||
circuitDNSMapping,
|
||||
endpointType,
|
||||
);
|
||||
if (!dscOk) {
|
||||
return;
|
||||
}
|
||||
await sendRegisterPayload(passportData, secret, circuitDNSMapping);
|
||||
await sendRegisterPayload(
|
||||
passportData,
|
||||
secret,
|
||||
circuitDNSMapping,
|
||||
endpointType,
|
||||
);
|
||||
}
|
||||
|
||||
export async function getDeployedCircuits() {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { v4 } from 'uuid';
|
||||
import {
|
||||
CIRCUIT_TYPES,
|
||||
WS_DB_RELAYER,
|
||||
WS_DB_RELAYER_STAGING,
|
||||
} from '../../../../common/src/constants/constants';
|
||||
import { EndpointType } from '../../../../common/src/utils/appType';
|
||||
import {
|
||||
@@ -168,7 +169,7 @@ export async function sendPayload(
|
||||
console.log('Received UUID:', receivedUuid);
|
||||
console.log(result);
|
||||
if (!socket) {
|
||||
socket = io(WS_DB_RELAYER, {
|
||||
socket = io(getWSDbRelayerUrl(endpointType), {
|
||||
path: '/',
|
||||
transports: ['websocket'],
|
||||
});
|
||||
@@ -259,6 +260,7 @@ export type TEEPayloadDisclose = {
|
||||
export type TEEPayload = {
|
||||
type: 'register' | 'dsc';
|
||||
onchain: true;
|
||||
endpointType: string;
|
||||
circuit: {
|
||||
name: string;
|
||||
inputs: string;
|
||||
@@ -287,6 +289,7 @@ export function getPayload(
|
||||
const payload: TEEPayload = {
|
||||
type: circuit as 'register' | 'dsc',
|
||||
onchain: true,
|
||||
endpointType: endpointType,
|
||||
circuit: {
|
||||
name: circuitName,
|
||||
inputs: JSON.stringify(inputs),
|
||||
@@ -295,3 +298,9 @@ export function getPayload(
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
|
||||
function getWSDbRelayerUrl(endpointType: EndpointType) {
|
||||
return endpointType === 'celo' || endpointType === 'https'
|
||||
? WS_DB_RELAYER
|
||||
: WS_DB_RELAYER_STAGING;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user