Co-authored-by: Aaron DeRuvo <aaron.deruvo@clabs.co>
This commit is contained in:
turnoffthiscomputer
2025-02-10 11:54:02 +01:00
committed by GitHub
parent 2362be8b88
commit 451b99496f
13 changed files with 348 additions and 187 deletions

View File

@@ -4,3 +4,5 @@ ios/
node_modules/
src/assets/animations/
witnesscalc/
vendor/
android/

View File

@@ -22,6 +22,7 @@
"dependencies": {
"@amplitude/analytics-react-native": "^1.4.7",
"@ethersproject/shims": "^5.7.0",
"@openpassport/zk-kit-lean-imt": "^0.0.6",
"@openpassport/zk-kit-smt": "^0.0.1",
"@peculiar/asn1-schema": "^2.3.15",
"@peculiar/x509": "^1.12.3",

View File

@@ -10,7 +10,7 @@ import USER_PROFILE from '../images/user_profile.png';
import useUserStore from '../stores/userStore';
import { bgGreen, textBlack } from '../utils/colors';
import { confirmTap } from '../utils/haptic';
import { sendRegisterPayload } from '../utils/proving/payload';
import { sendDscPayload, sendRegisterPayload } from '../utils/proving/payload';
import { formatAttribute, getFirstName, maskString } from '../utils/utils';
const NextScreen: React.FC = () => {
@@ -135,7 +135,15 @@ const NextScreen: React.FC = () => {
confirmTap();
passportData && (await sendRegisterPayload(passportData));
}}
text="TEE PROVING"
text="TEE PROVING REGISTER"
Icon={<Cpu color={textBlack} />}
/>
<CustomButton
onPress={async () => {
confirmTap();
passportData && (await sendDscPayload(passportData));
}}
text="TEE PROVING DSC"
Icon={<Cpu color={textBlack} />}
/>

View File

@@ -4,25 +4,10 @@ import { useNavigation } from '@react-navigation/native';
import io, { Socket } from 'socket.io-client';
import { Text, YStack } from 'tamagui';
// import {
// DEVELOPMENT_MODE,
// MAX_CERT_BYTES,
// } from '../../../../common/src/constants/constants';
import {
ArgumentsProveOffChain,
OpenPassportApp,
} from '../../../../common/src/utils/appType';
import {
getCircuitNameOld,
parseCertificateSimple,
} from '../../../../common/src/utils/certificate_parsing/parseCertificateSimple';
// import {
// getCSCAFromSKI,
// sendCSCARequest,
// } from '../../../../common/src/utils/csca';
// import { generateCircuitInputsDSC } from '../../../../common/src/utils/circuits/generateInputs';
// import { buildAttestation } from '../../../../common/src/utils/openPassportAttestation';
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';
@@ -32,13 +17,10 @@ import useNavigationStore from '../../stores/navigationStore';
import useUserStore from '../../stores/userStore';
import { black, slate300, white } from '../../utils/colors';
import { buttonTap } from '../../utils/haptic';
// import { generateCircuitInputsInApp } from '../../utils/generateInputsInApp';
// import { generateProof } from '../../utils/prover';
import { CircuitName } from '../../utils/zkeyDownload';
import { sendVcAndDisclosePayload } from '../../utils/proving/payload';
const ProveScreen: React.FC = () => {
const { navigate } = useNavigation();
const [generatingProof, setGeneratingProof] = useState(false);
const selectedApp = useNavigationStore(
state => state.selectedApp || { args: {} },
) as OpenPassportApp;
@@ -46,12 +28,10 @@ const ProveScreen: React.FC = () => {
selectedApp.mode === 'register'
? {}
: (selectedApp.args as ArgumentsProveOffChain).disclosureOptions || {};
const { isZkeyDownloading } = useNavigationStore();
const { setProofVerificationResult, passportData } = useUserStore();
const [socket, setSocket] = useState<Socket | null>(null);
const [isConnecting, setIsConnecting] = useState(false);
const [_socket, setSocket] = useState<Socket | null>(null);
if (!passportData) {
return (
@@ -61,25 +41,12 @@ const ProveScreen: React.FC = () => {
);
}
const { signatureAlgorithm } = parseCertificateSimple(passportData.dsc);
const parsedPassportData = parsePassportData(passportData);
const circuitName = getCircuitNameOld(
selectedApp.mode,
signatureAlgorithm,
parsedPassportData.signedAttrHashFunction,
);
const waitForSocketConnection = (socketInstance: Socket): Promise<void> => {
return new Promise(resolve => {
if (socketInstance.connected) {
resolve();
} else {
socketInstance.once('connect', () => {
resolve();
});
}
});
};
function onVerify() {
buttonTap();
sendVcAndDisclosePayload(passportData).catch(e =>
console.log('Error sending VC and disclose payload', e),
);
}
function goToErrorScreen() {
navigate('WrongProofScreen');
@@ -159,101 +126,6 @@ const ProveScreen: React.FC = () => {
};
}, [selectedApp.userId]);
const handleProve = async () => {
buttonTap();
try {
setIsConnecting(true);
setGeneratingProof(true);
if (!socket) {
throw new Error('Socket not initialized');
}
await waitForSocketConnection(socket);
setIsConnecting(false);
socket.emit('proof_generation_start', {
sessionId: selectedApp.sessionId,
});
// const inputs = await generateCircuitInputsInApp(
// passportData,
// selectedApp,
// );
// let attestation;
// let proof;
// let dscProof;
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,
// });
// break;
// default:
// proof = await generateProof(circuitName, inputs);
// attestation = buildAttestation({
// userIdType: selectedApp.userIdType,
// mode: selectedApp.mode,
// proof: proof.proof,
// publicSignals: proof.publicSignals,
// signatureAlgorithm: signatureAlgorithm,
// hashFunction: parsedPassportData.signedAttrHashFunction,
// dsc: passportData.dsc,
// });
// break;
}
// console.log('\x1b[90mattestation\x1b[0m', attestation);
// socket.emit('proof_generated', {
// sessionId: selectedApp.sessionId,
// proof: attestation,
// });
} catch (error) {
console.log('Error', {
message: String(error),
customData: {
type: 'error',
},
});
console.error('Error in handleProve:', error);
goToErrorScreen();
if (socket) {
socket.emit('proof_generation_failed', {
sessionId: selectedApp.sessionId,
});
}
} finally {
setGeneratingProof(false);
setIsConnecting(false);
}
};
return (
<ExpandableBottomLayout.Layout>
<ExpandableBottomLayout.TopSection>
@@ -276,16 +148,7 @@ const ProveScreen: React.FC = () => {
Self will confirm that these details are accurate and none of your
confidential info will be revealed to {selectedApp.appName}
</Caption>
<PrimaryButton
onPress={handleProve}
disabled={
generatingProof ||
isConnecting ||
isZkeyDownloading[circuitName as CircuitName]
}
>
Verify with Passcode
</PrimaryButton>
<PrimaryButton onLongPress={onVerify}>Hold To Verify</PrimaryButton>
</ExpandableBottomLayout.BottomSection>
</ExpandableBottomLayout.Layout>
);

View File

@@ -2,15 +2,18 @@ import { X509Certificate } from '@peculiar/x509';
import { decode } from '@stablelib/cbor';
//@ts-ignore
import * as asn1 from 'asn1.js';
import * as asn1js from 'asn1js';
import { Buffer } from 'buffer';
import elliptic from 'elliptic';
import { Certificate } from 'pkijs';
import { getCurveForElliptic } from '../../../../common/src/utils/certificate_parsing/curves';
import { PublicKeyDetailsECDSA } from '../../../../common/src/utils/certificate_parsing/dataStructure';
import { parseCertificateSimple } from '../../../../common/src/utils/certificate_parsing/parseCertificateSimple';
import { IMAGE_HASH } from '../../../../common/src/constants/constants';
import { AWS_ROOT_PEM } from './awsRootPem';
import cose from './cose';
// The required fields for a valid attestation
/**
* @notice An array specifying the required fields for a valid attestation.
*/
export const requiredFields = [
'module_id',
'digest',
@@ -20,7 +23,9 @@ export const requiredFields = [
'cabundle',
];
// Define an interface for the ASN.1 context used with asn1.js
/**
* @notice ASN.1 context interface for use with asn1js.js.
*/
interface ASN1Context {
seq(): ASN1Context;
obj(...args: any[]): ASN1Context;
@@ -29,7 +34,9 @@ interface ASN1Context {
bitstr(): ASN1Context;
}
// Update the ASN.1 definition with proper typing for ECPublicKey
/**
* @notice ASN.1 definition for an Elliptic Curve Public Key.
*/
export const ECPublicKeyASN = asn1.define(
'ECPublicKey',
function (this: ASN1Context) {
@@ -42,7 +49,13 @@ export const ECPublicKeyASN = asn1.define(
},
);
// Utility function to check if a number is within (start, end] range
/**
* @notice Utility function to check if a number is within (start, end] range.
* @param start The start of the range (exclusive).
* @param end The end of the range (inclusive).
* @param value The number to check.
* @return True if value is within the range; otherwise, false.
*/
export const numberInRange = (
start: number,
end: number,
@@ -51,6 +64,12 @@ export const numberInRange = (
return value > start && value <= end;
};
/**
* @notice Verifies a certificate chain against a provided trusted root certificate.
* @param rootPem The trusted root certificate in PEM format.
* @param certChainStr An array of certificates in PEM format, ordered from leaf to root.
* @return True if the certificate chain is valid, false otherwise.
*/
export const verifyCertChain = (
rootPem: string,
certChainStr: string[],
@@ -93,6 +112,12 @@ export const verifyCertChain = (
}
};
/**
* @notice Verifies a TEE attestation document encoded as a COSE_Sign1 structure.
* @param attestation An array of numbers representing the COSE_Sign1 encoded attestation document.
* @return A promise that resolves to true if the attestation is verified successfully.
* @throws Error if the attestation document is improperly formatted or missing required fields.
*/
export const verifyAttestation = async (attestation: Array<number>) => {
const coseSign1 = await decode(Buffer.from(attestation));
@@ -123,7 +148,7 @@ export const verifyAttestation = async (attestation: Array<number>) => {
throw new Error('Invalid timestamp');
}
//for each key, value in pcts
// for each key, value in pcrs
for (const [key, value] of Object.entries(attestationDoc.pcrs)) {
if (parseInt(key, 10) < 0 || parseInt(key, 10) >= 32) {
throw new Error('Invalid pcr index');
@@ -167,18 +192,17 @@ export const verifyAttestation = async (attestation: Array<number>) => {
);
const cert = derToPem(attestationDoc.certificate);
const imageHash = getImageHash(attestation);
if (imageHash !== IMAGE_HASH) {
throw new Error('Invalid image hash');
}
console.log('TEE image hash verified');
if (!verifyCertChain(AWS_ROOT_PEM, [...certChain, cert])) {
throw new Error('Invalid certificate chain');
}
const parsed = parseCertificateSimple(cert);
const publicKeyDetails = parsed.publicKeyDetails as PublicKeyDetailsECDSA;
const curve = getCurveForElliptic(publicKeyDetails.curve);
const x = publicKeyDetails.x;
const y = publicKeyDetails.y;
const { x, y, curve } = getPublicKeyFromPem(cert);
const verifier = {
key: {
@@ -187,12 +211,18 @@ export const verifyAttestation = async (attestation: Array<number>) => {
curve,
},
};
console.log('verifier', verifier);
await cose.sign.verify(Buffer.from(attestation), verifier, {
defaultType: 18,
});
return true;
};
/**
* @notice Extracts the public key from a TEE attestation document.
* @param attestation An array of numbers representing the COSE_Sign1 encoded attestation document.
* @return The public key as a string.
*/
export function getPublicKey(attestation: Array<number>) {
const coseSign1 = decode(Buffer.from(attestation));
const [_protectedHeaderBytes, _unprotectedHeader, payload, _signature] =
@@ -201,19 +231,12 @@ export function getPublicKey(attestation: Array<number>) {
return attestationDoc.public_key;
}
// Update the type definition to match the actual data structure
type AttestationDoc = {
module_id: string;
digest: string;
timestamp: number;
pcrs: { [key: number]: Buffer }; // Changed from Map to object
certificate: Buffer;
cabundle: Array<Buffer>;
public_key: string | null;
user_data: string | null;
nonce: string | null;
};
/**
* @notice Converts a DER-encoded certificate to PEM format.
* @param der A Buffer containing the DER-encoded certificate.
* @return The PEM-formatted certificate string.
* @throws Error if the conversion fails.
*/
export function derToPem(der: Buffer): string {
try {
const base64 = Buffer.from(der).toString('base64');
@@ -227,3 +250,98 @@ export function derToPem(der: Buffer): string {
throw error;
}
}
/**
* @notice Extracts the image hash (PCR0) from the attestation document.
* @param attestation An array of numbers representing the COSE_Sign1 encoded attestation document.
* @return The image hash (PCR0) as a hexadecimal string.
* @throws Error if the COSE_Sign1 format is invalid or PCR0 is missing/incorrect.
* @see https://docs.aws.amazon.com/enclaves/latest/user/set-up-attestation.html
*/
export function getImageHash(attestation: Array<number>) {
const coseSign1 = decode(Buffer.from(attestation));
if (!Array.isArray(coseSign1) || coseSign1.length !== 4) {
throw new Error('Invalid COSE_Sign1 format');
}
const [_protectedHeaderBytes, _unprotectedHeader, payload, _signature] =
coseSign1;
const attestationDoc = decode(payload);
if (!attestationDoc.pcrs) {
throw new Error('Missing required field: pcrs');
}
const pcr0 = attestationDoc.pcrs[0];
if (!pcr0) {
throw new Error('PCR0 (image hash) is missing in the attestation document');
}
if (pcr0.length !== 48) {
// SHA384 produces a 48-byte hash
throw new Error(
`Invalid PCR0 length - expected 48 bytes, got ${pcr0.length} bytes`,
);
}
return Buffer.from(pcr0).toString('hex');
}
type AttestationDoc = {
module_id: string;
digest: string;
timestamp: number;
pcrs: { [key: number]: Buffer };
certificate: Buffer;
cabundle: Array<Buffer>;
public_key: string | null;
user_data: string | null;
nonce: string | null;
};
/**
* @notice Extracts the public key from a PEM formatted certificate.
* @param pem A string containing the PEM formatted certificate.
* @return An object with the x and y coordinates of the public key and the curve used.
* @see https://docs.aws.amazon.com/enclaves/latest/user/set-up-attestation.html for p384 usage
* @dev This function parses the certificate using getCertificateFromPem(), then uses the elliptic library
* on the "p384" curve to derive the public key's x and y coordinates. This public key is then returned,
* ensuring it is padded correctly.
*/
function getPublicKeyFromPem(pem: string) {
const cert = getCertificateFromPem(pem);
const curve = 'p384';
const publicKeyBuffer =
cert.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
const ec = new elliptic.ec(curve);
const key = ec.keyFromPublic(publicKeyBuffer);
const x_point = key.getPublic().getX().toString('hex');
const y_point = key.getPublic().getY().toString('hex');
const x = x_point.length % 2 === 0 ? x_point : '0' + x_point;
const y = y_point.length % 2 === 0 ? y_point : '0' + y_point;
return { x, y, curve };
}
/**
* @notice Converts a PEM formatted certificate to a PKI.js Certificate object.
* @param pemContent A string containing the PEM formatted certificate including header/footer markers.
* @return A Certificate object parsed from the PEM content.
* @dev The function strips the PEM header/footer and line breaks, decodes the base64 content into binary,
* creates an ArrayBuffer, and then parses the ASN.1 structure using asn1js.fromBER. Throws an error if parsing fails.
*/
export function getCertificateFromPem(pemContent: string): Certificate {
const pemFormatted = pemContent.replace(
/(-----(BEGIN|END) CERTIFICATE-----|\n|\r)/g,
'',
);
const binary = Buffer.from(pemFormatted, 'base64');
const arrayBuffer = new ArrayBuffer(binary.length);
const view = new Uint8Array(arrayBuffer);
for (let i = 0; i < binary.length; i++) {
view[i] = binary[i];
}
const asn1Data = asn1js.fromBER(arrayBuffer);
if (asn1.offset === -1) {
throw new Error(`ASN.1 parsing error: ${asn1Data.result.error}`);
}
return new Certificate({ schema: asn1Data.result });
}

View File

@@ -3,6 +3,20 @@ import { Buffer } from 'buffer';
import { ec as EC } from 'elliptic';
import { sha384 } from 'js-sha512';
/**
* @notice Verifies a COSE_Sign1 message signature against the provided ECDSA public key.
* @param data A Buffer containing the COSE_Sign1 encoded message.
* @param verifier An object providing the signature verification properties:
* - key.x: The hexadecimal string for the x-coordinate of the public key.
* - key.y: The hexadecimal string for the y-coordinate of the public key.
* - key.curve: The elliptic curve identifier (e.g., 'p256', 'p384') to be used.
* @param _options An object containing options for verification. Currently supports:
* - defaultType: The expected type identifier (not actively used in the verification flow).
* @return A Promise that resolves if the signature is valid; otherwise, it throws an error.
* @notice This function is typically invoked by the attestation verification process in @attest.ts
* to ensure that the TEE's COSE_Sign1 attestation document has not been tampered with.
* @see https://docs.aws.amazon.com/enclaves/latest/user/set-up-attestation.html for p384 sha384 usage
*/
export const cose = {
sign: {
verify: async (

View File

@@ -1,8 +1,21 @@
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
import { SMT } from '@openpassport/zk-kit-smt';
import { poseidon2 } from 'poseidon-lite';
import namejson from '../../../../common/ofacdata/outputs/nameSMT.json';
import { PASSPORT_ATTESTATION_ID } from '../../../../common/src/constants/constants';
import { getCircuitNameFromPassportData } from '../../../../common/src/utils/circuits/circuitsName';
import { generateCircuitInputsRegister } from '../../../../common/src/utils/circuits/generateInputs';
import {
generateCircuitInputsDSC,
generateCircuitInputsRegister,
generateCircuitInputsVCandDisclose,
} from '../../../../common/src/utils/circuits/generateInputs';
import { generateCommitment } from '../../../../common/src/utils/passports/passport';
import { PassportData } from '../../../../common/src/utils/types';
import { sendPayload } from './tee';
const mock_secret = '0'; //TODO: retrieve the secret from keychain
function generateTeeInputsRegister(secret: string, passportData: PassportData) {
const inputs = generateCircuitInputsRegister(secret, passportData);
const circuitName = getCircuitNameFromPassportData(passportData, 'register');
@@ -41,8 +54,84 @@ export async function sendRegisterPayload(passportData: PassportData) {
return;
}
const { inputs, circuitName } = generateTeeInputsRegister(
'0', //TODO: retrieve the secret from keychain
mock_secret,
passportData,
);
await sendPayload(inputs, circuitName);
}
function generateTeeInputsDsc(passportData: PassportData) {
const inputs = generateCircuitInputsDSC(passportData.dsc);
const circuitName = getCircuitNameFromPassportData(passportData, 'dsc');
if (circuitName == null) {
throw new Error('Circuit name is null');
}
return { inputs, circuitName };
}
export async function sendDscPayload(passportData: PassportData) {
if (!passportData) {
return null;
}
const isSupported = checkPassportSupported(passportData);
if (!isSupported) {
// TODO: show a screen explaining that the passport is not supported.
return;
}
const { inputs, circuitName } = generateTeeInputsDsc(passportData);
console.log('circuitName', circuitName);
await sendPayload(inputs, circuitName);
}
function generateTeeInputsVCAndDisclose(passportData: PassportData) {
const majority = '18';
const user_identifier = crypto.randomUUID();
const selector_dg1 = Array(88).fill('1');
const selector_older_than = '1';
const scope = '@coboyApp';
const attestation_id = PASSPORT_ATTESTATION_ID;
const commitment = generateCommitment(
mock_secret,
attestation_id,
passportData,
);
const tree = new LeanIMT<bigint>((a, b) => poseidon2([a, b]), []);
tree.insert(BigInt(commitment));
let smt = new SMT(poseidon2, true);
smt.import(namejson);
const selector_ofac = 1;
const forbidden_countries_list = ['ABC', 'DEF'];
const inputs = generateCircuitInputsVCandDisclose(
mock_secret,
PASSPORT_ATTESTATION_ID,
passportData,
scope,
selector_dg1,
selector_older_than,
tree,
majority,
smt,
selector_ofac,
forbidden_countries_list,
user_identifier,
);
return { inputs, circuitName: 'vc_and_disclose' };
}
export async function sendVcAndDisclosePayload(
passportData: PassportData | null,
) {
if (!passportData) {
return null;
}
const isSupported = checkPassportSupported(passportData);
if (!isSupported) {
// TODO: show a screen explaining that the passport is not supported.
return;
}
const { inputs, circuitName } = generateTeeInputsVCAndDisclose(passportData);
await sendPayload(inputs, circuitName);
}

View File

@@ -7,6 +7,12 @@ import { getPublicKey, verifyAttestation } from './attest';
const { ec: EC } = elliptic;
/**
* @notice Encrypts plaintext using AES-256-GCM encryption.
* @param plaintext The string to be encrypted.
* @param key The encryption key as a forge ByteStringBuffer.
* @return An object containing the nonce, cipher_text, and auth_tag as arrays of numbers.
*/
function encryptAES256GCM(plaintext: string, key: forge.util.ByteStringBuffer) {
const iv = forge.random.getBytesSync(12);
const cipher = forge.cipher.createCipher('AES-GCM', key);
@@ -28,6 +34,15 @@ const pubkey =
key1.getPublic().getX().toString('hex').padStart(64, '0') +
key1.getPublic().getY().toString('hex').padStart(64, '0');
/**
* @notice Sends a payload over WebSocket connecting to the TEE server, processes the attestation,
* and submits a registration request encrypted via a shared key derived using ECDH.
* @param inputs The circuit input parameters.
* @param circuitName The name of the circuit.
* @param timeoutMs The timeout in milliseconds (default is 1200000 ms).
* @return A promise that resolves when the request completes or rejects on error/timeout.
* @dev This function sets up two WebSocket connections: one for RPC and one for subscription updates.
*/
export async function sendPayload(
inputs: any,
circuitName: string,
@@ -59,7 +74,6 @@ export async function sendPayload(
ws.addEventListener('message', async event => {
try {
const result = JSON.parse(event.data);
console.log('Received message:', result);
if (result.result?.attestation !== undefined) {
await processAttestation(result);
} else {

View File

@@ -1963,6 +1963,15 @@ __metadata:
languageName: node
linkType: hard
"@openpassport/zk-kit-lean-imt@npm:^0.0.6":
version: 0.0.6
resolution: "@openpassport/zk-kit-lean-imt@npm:0.0.6"
dependencies:
"@openpassport/zk-kit-utils": "npm:0.0.1"
checksum: 10c0/2cb3f99e216391a325a7050290cccfa12323dc057d7cf4a26baeafe79a34c4ed3013da035fdbe9985395d5a668e37fd81f2b060834b67895bd3f82e7edfe0601
languageName: node
linkType: hard
"@openpassport/zk-kit-smt@npm:^0.0.1":
version: 0.0.1
resolution: "@openpassport/zk-kit-smt@npm:0.0.1"
@@ -1970,6 +1979,15 @@ __metadata:
languageName: node
linkType: hard
"@openpassport/zk-kit-utils@npm:0.0.1":
version: 0.0.1
resolution: "@openpassport/zk-kit-utils@npm:0.0.1"
dependencies:
buffer: "npm:^6.0.3"
checksum: 10c0/3a9adb279cfd5096c44934bb6c73979f21247eb0119a65f8b5c0bb1f457f5500de761fc627e0bd9e72a7cbf5ca65696c144bfffe3dbd1f1ce37a300c239a8e3f
languageName: node
linkType: hard
"@peculiar/asn1-cms@npm:^2.3.13, @peculiar/asn1-cms@npm:^2.3.15":
version: 2.3.15
resolution: "@peculiar/asn1-cms@npm:2.3.15"
@@ -7210,6 +7228,16 @@ __metadata:
languageName: node
linkType: hard
"buffer@npm:^6.0.3":
version: 6.0.3
resolution: "buffer@npm:6.0.3"
dependencies:
base64-js: "npm:^1.3.1"
ieee754: "npm:^1.2.1"
checksum: 10c0/2a905fbbcde73cc5d8bd18d1caa23715d5f83a5935867c2329f0ac06104204ba7947be098fe1317fbd8830e26090ff8e764f08cd14fefc977bb248c3487bcbd0
languageName: node
linkType: hard
"burnt@npm:^0.12.2":
version: 0.12.2
resolution: "burnt@npm:0.12.2"
@@ -9678,7 +9706,7 @@ __metadata:
languageName: node
linkType: hard
"ieee754@npm:^1.1.13, ieee754@npm:^1.1.4, ieee754@npm:^1.1.8":
"ieee754@npm:^1.1.13, ieee754@npm:^1.1.4, ieee754@npm:^1.1.8, ieee754@npm:^1.2.1":
version: 1.2.1
resolution: "ieee754@npm:1.2.1"
checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb
@@ -12362,6 +12390,7 @@ __metadata:
"@babel/core": "npm:^7.20.0"
"@babel/plugin-transform-private-methods": "npm:^7.23.3"
"@ethersproject/shims": "npm:^5.7.0"
"@openpassport/zk-kit-lean-imt": "npm:^0.0.6"
"@openpassport/zk-kit-smt": "npm:^0.0.1"
"@peculiar/asn1-schema": "npm:^2.3.15"
"@peculiar/x509": "npm:^1.12.3"
@@ -13089,7 +13118,7 @@ __metadata:
peerDependencies:
react: ">= 17.0.1"
react-native: ">= 0.64.3"
checksum: 10c0/ebb3dfb9a111bf6082866999d31e10f952fcd12bcf2a81210ff9f44a4cb4d25e1b4caac5fdec512b367685e56a37e61de3e6648c2af45b93fcbaf704355dbaa6
checksum: 10c0/0e3f83f59dadc337ab46fa0c59bb2b80eb91d4756f0ac67d7b11e0d97044d58bbaca7ee5c7dcd1e0a389af3f16b0eaca12122d59905013a6f5a2f4423ead49d0
languageName: node
linkType: hard