mirror of
https://github.com/selfxyz/self.git
synced 2026-01-09 14:48:06 -05:00
Move proving inputs to the common package (#937)
* create ofactTree type to share * move proving inputs from app to register inputs in common * missed reexport * ok * add some validations as suggested by our ai overlords
This commit is contained in:
@@ -1 +1,162 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1; Copyright (c) 2025 Social Connect Labs, Inc.; Licensed under BUSL-1.1 (see LICENSE); Apache-2.0 from 2029-06-11
|
||||
|
||||
import { poseidon2 } from 'poseidon-lite';
|
||||
|
||||
import {
|
||||
attributeToPosition,
|
||||
attributeToPosition_ID,
|
||||
DEFAULT_MAJORITY,
|
||||
ID_CARD_ATTESTATION_ID,
|
||||
PASSPORT_ATTESTATION_ID,
|
||||
} from '../../constants/constants.js';
|
||||
import type { DocumentCategory, PassportData } from '../../types/index.js';
|
||||
import type { SelfApp, SelfAppDisclosureConfig } from '../../utils/appType.js';
|
||||
import {
|
||||
calculateUserIdentifierHash,
|
||||
generateCircuitInputsDSC,
|
||||
generateCircuitInputsRegister,
|
||||
generateCircuitInputsVCandDisclose,
|
||||
getCircuitNameFromPassportData,
|
||||
hashEndpointWithScope,
|
||||
} from '../../utils/index.js';
|
||||
import type { OfacTree } from '../../utils/types.js';
|
||||
|
||||
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
|
||||
import { SMT } from '@openpassport/zk-kit-smt';
|
||||
|
||||
export { generateCircuitInputsRegister } from './generateInputs.js';
|
||||
|
||||
export function generateTEEInputsDSC(
|
||||
passportData: PassportData,
|
||||
cscaTree: string[][],
|
||||
env: 'prod' | 'stg'
|
||||
) {
|
||||
const inputs = generateCircuitInputsDSC(passportData, cscaTree);
|
||||
const circuitName = getCircuitNameFromPassportData(passportData, 'dsc');
|
||||
const endpointType = env === 'stg' ? 'staging_celo' : 'celo';
|
||||
const endpoint = 'https://self.xyz';
|
||||
return { inputs, circuitName, endpointType, endpoint };
|
||||
}
|
||||
|
||||
export function generateTEEInputsDiscloseStateless(
|
||||
secret: string,
|
||||
passportData: PassportData,
|
||||
selfApp: SelfApp,
|
||||
getTree: <T extends 'ofac' | 'commitment'>(
|
||||
doc: DocumentCategory,
|
||||
tree: T
|
||||
) => T extends 'ofac' ? OfacTree : any
|
||||
) {
|
||||
const { scope, disclosures, endpoint, userId, userDefinedData, chainID } = selfApp;
|
||||
const userIdentifierHash = calculateUserIdentifierHash(chainID, userId, userDefinedData);
|
||||
const scope_hash = hashEndpointWithScope(endpoint, scope);
|
||||
const document: DocumentCategory = passportData.documentCategory;
|
||||
|
||||
const selector_dg1 = getSelectorDg1(document, disclosures);
|
||||
|
||||
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 ofac_trees = getTree(document, 'ofac');
|
||||
if (!ofac_trees) {
|
||||
throw new Error('OFAC trees not loaded');
|
||||
}
|
||||
|
||||
// Validate OFAC tree structure
|
||||
if (!ofac_trees.nameAndDob || !ofac_trees.nameAndYob) {
|
||||
throw new Error('Invalid OFAC tree structure: missing required fields');
|
||||
}
|
||||
if (document === 'passport' && !ofac_trees.passportNoAndNationality) {
|
||||
throw new Error('Invalid OFAC tree structure: missing passportNoAndNationality for passport');
|
||||
}
|
||||
|
||||
let passportNoAndNationalitySMT: SMT | null = null;
|
||||
const nameAndDobSMT = new SMT(poseidon2, true);
|
||||
const nameAndYobSMT = new SMT(poseidon2, true);
|
||||
if (document === 'passport') {
|
||||
passportNoAndNationalitySMT = new SMT(poseidon2, true);
|
||||
passportNoAndNationalitySMT.import(ofac_trees.passportNoAndNationality);
|
||||
}
|
||||
nameAndDobSMT.import(ofac_trees.nameAndDob);
|
||||
nameAndYobSMT.import(ofac_trees.nameAndYob);
|
||||
|
||||
const serialized_tree = getTree(document, 'commitment');
|
||||
const tree = LeanIMT.import((a, b) => poseidon2([a, b]), serialized_tree);
|
||||
const inputs = generateCircuitInputsVCandDisclose(
|
||||
secret,
|
||||
document === 'passport' ? PASSPORT_ATTESTATION_ID : ID_CARD_ATTESTATION_ID,
|
||||
passportData,
|
||||
scope_hash,
|
||||
selector_dg1,
|
||||
selector_older_than,
|
||||
tree,
|
||||
majority,
|
||||
passportNoAndNationalitySMT,
|
||||
nameAndDobSMT,
|
||||
nameAndYobSMT,
|
||||
selector_ofac,
|
||||
disclosures.excludedCountries ?? [],
|
||||
userIdentifierHash.toString()
|
||||
);
|
||||
return {
|
||||
inputs,
|
||||
circuitName:
|
||||
passportData.documentCategory === 'passport' ? 'vc_and_disclose' : 'vc_and_disclose_id',
|
||||
endpointType: selfApp.endpointType,
|
||||
endpoint: selfApp.endpoint,
|
||||
};
|
||||
}
|
||||
|
||||
export function generateTEEInputsRegister(
|
||||
secret: string,
|
||||
passportData: PassportData,
|
||||
dscTree: string,
|
||||
env: 'prod' | 'stg'
|
||||
) {
|
||||
const inputs = generateCircuitInputsRegister(secret, passportData, dscTree);
|
||||
const circuitName = getCircuitNameFromPassportData(passportData, 'register');
|
||||
const endpointType = env === 'stg' ? 'staging_celo' : 'celo';
|
||||
const endpoint = 'https://self.xyz';
|
||||
return { inputs, circuitName, endpointType, endpoint };
|
||||
}
|
||||
|
||||
/*** DISCLOSURE ***/
|
||||
|
||||
function getSelectorDg1(document: DocumentCategory, disclosures: SelfAppDisclosureConfig) {
|
||||
switch (document) {
|
||||
case 'passport':
|
||||
return getSelectorDg1Passport(disclosures);
|
||||
case 'id_card':
|
||||
return getSelectorDg1IdCard(disclosures);
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectorDg1Passport(disclosures: SelfAppDisclosureConfig) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
return selector_dg1;
|
||||
}
|
||||
|
||||
function getSelectorDg1IdCard(disclosures: SelfAppDisclosureConfig) {
|
||||
const selector_dg1 = Array(90).fill('0');
|
||||
Object.entries(disclosures).forEach(([attribute, reveal]) => {
|
||||
if (['ofac', 'excludedCountries', 'minimumAge'].includes(attribute)) {
|
||||
return;
|
||||
}
|
||||
if (reveal) {
|
||||
const [start, end] = attributeToPosition_ID[attribute as keyof typeof attributeToPosition_ID];
|
||||
selector_dg1.fill('1', start, end + 1);
|
||||
}
|
||||
});
|
||||
return selector_dg1;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,13 @@ import type { PassportMetadata } from './passports/passport_parsing/parsePasspor
|
||||
export type DocumentCategory = 'passport' | 'id_card';
|
||||
|
||||
export type DocumentType = 'passport' | 'id_card' | 'mock_passport' | 'mock_id_card';
|
||||
|
||||
export type OfacTree = {
|
||||
passportNoAndNationality: any;
|
||||
nameAndDob: any;
|
||||
nameAndYob: any;
|
||||
};
|
||||
|
||||
export type PassportData = {
|
||||
mrz: string;
|
||||
dg1Hash?: number[];
|
||||
|
||||
Reference in New Issue
Block a user