Files
self/common/src/utils/circuits/registerInputs.ts
Justin Hernandez 431f556542 chore: centralize license header checks (#952)
* chore: centralize license header scripts

* chore: run license header checks from root

* add header to other files

* add header to bundle

* add migration script and update check license headers

* convert license to mobile sdk

* migrate license headers

* remove headers from common; convert remaining

* fix headers

* add license header checks
2025-08-25 11:30:23 -07:00

161 lines
5.3 KiB
TypeScript

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;
}