diff --git a/circuits/circuits/disclose/vc_and_disclose.circom b/circuits/circuits/disclose/vc_and_disclose.circom index 95372aabe..850c7a680 100644 --- a/circuits/circuits/disclose/vc_and_disclose.circom +++ b/circuits/circuits/disclose/vc_and_disclose.circom @@ -82,6 +82,8 @@ template VC_AND_DISCLOSE( signal input scope; signal input user_identifier; + signal input should_be_included; + // verify commitment is part of the merkle tree VERIFY_COMMITMENT(nLevels, DG1_LEN)( secret, diff --git a/circuits/circuits/utils/passport/disclose/disclose.circom b/circuits/circuits/utils/passport/disclose/disclose.circom index 7e31958e3..bccc642de 100644 --- a/circuits/circuits/utils/passport/disclose/disclose.circom +++ b/circuits/circuits/utils/passport/disclose/disclose.circom @@ -49,6 +49,7 @@ template DISCLOSE( signal input ofac_nameyob_smt_siblings[nameyobTreeLevels]; signal input selector_ofac; + signal input should_be_included; // assert selectors are 0 or 1 for (var i = 0; i < 88; i++) { @@ -118,10 +119,11 @@ template DISCLOSE( signal output revealedData_packed[3] <== PackBytes(95)(revealedData); var chunkLength = computeIntChunkLength(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3); - component proveCountryIsNotInList = CountryNotInList(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH); + component proveCountryIsNotInList = ProveCountryIsInList(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH); proveCountryIsNotInList.country[0] <== dg1[7]; proveCountryIsNotInList.country[1] <== dg1[8]; proveCountryIsNotInList.country[2] <== dg1[9]; proveCountryIsNotInList.forbidden_countries_list <== forbidden_countries_list; + proveCountryIsNotInList.should_be_included <== should_be_included; signal output forbidden_countries_list_packed[chunkLength] <== proveCountryIsNotInList.forbidden_countries_list_packed; } diff --git a/circuits/circuits/utils/passport/disclose/proveCountryIsNotInList.circom b/circuits/circuits/utils/passport/disclose/proveCountryIsNotInList.circom index 03ff93a8d..26455548e 100644 --- a/circuits/circuits/utils/passport/disclose/proveCountryIsNotInList.circom +++ b/circuits/circuits/utils/passport/disclose/proveCountryIsNotInList.circom @@ -9,14 +9,38 @@ include "@openpassport/zk-email-circuits/utils/bytes.circom"; /// @input forbidden_countries_list Forbidden countries list user wants to prove he is not from /// @output forbidden_countries_list_packed Packed forbidden countries list — gas optimized -template ProveCountryIsNotInList(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH) { +template ProveCountryIsInList(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH) { signal input dg1[93]; - signal input forbidden_countries_list[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3]; + signal input forbidden_countries_list[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3]; + signal input should_be_included; + + should_be_included * (should_be_included - 1) === 0; + signal accumulator <== 0; signal equality_results[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH][4]; for (var i = 0; i < MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH; i++) { equality_results[i][0] <== IsEqual()([dg1[7], forbidden_countries_list[i * 3]]); - equality_results[i][1] <== IsEqual()([dg1[8], forbidden_countries_list[i * 3 + 1]]); + equality_results[i][1] <== IsEqual()([dg1[8], forbidden_countries_list[i * 3 + 1]]); + equality_results[i][2] <== IsEqual()([dg1[9], forbidden_countries_list[i * 3 + 2]]); + equality_results[i][3] <== equality_results[i][0] * equality_results[i][1]; + accumulator <== accumulator + equality_results[i][3] * equality_results[i][2]; + } + accumulator * (1 - should_be_included) === 0; + signal is_zero <== IsZero()(accumulator); + is_zero * should_be_included === 0; + + var chunkLength = computeIntChunkLength(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3); + signal output forbidden_countries_list_packed[chunkLength] <== PackBytes(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3)(forbidden_countries_list); +} + +template ProveCountryIsNotInList_ID(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH) { + signal input dg1[95]; + signal input forbidden_countries_list[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3]; + + signal equality_results[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH][4]; + for (var i = 0; i < MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH; i++) { + equality_results[i][0] <== IsEqual()([dg1[7], forbidden_countries_list[i * 3]]); + equality_results[i][1] <== IsEqual()([dg1[8], forbidden_countries_list[i * 3 + 1]]); equality_results[i][2] <== IsEqual()([dg1[9], forbidden_countries_list[i * 3 + 2]]); equality_results[i][3] <== equality_results[i][0] * equality_results[i][1]; 0 === equality_results[i][3] * equality_results[i][2]; @@ -25,20 +49,3 @@ template ProveCountryIsNotInList(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH) { var chunkLength = computeIntChunkLength(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3); signal output forbidden_countries_list_packed[chunkLength] <== PackBytes(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3)(forbidden_countries_list); } - -template ProveCountryIsNotInList_ID(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH) { - signal input dg1[95]; - signal input forbidden_countries_list[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3]; - - signal equality_results[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH][4]; - for (var i = 0; i < MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH; i++) { - equality_results[i][0] <== IsEqual()([dg1[7], forbidden_countries_list[i * 3]]); - equality_results[i][1] <== IsEqual()([dg1[8], forbidden_countries_list[i * 3 + 1]]); - equality_results[i][2] <== IsEqual()([dg1[9], forbidden_countries_list[i * 3 + 2]]); - equality_results[i][3] <== equality_results[i][0] * equality_results[i][1]; - 0 === equality_results[i][3] * equality_results[i][2]; - } - - var chunkLength = computeIntChunkLength(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3); - signal output forbidden_countries_list_packed[chunkLength] <== PackBytes(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3)(forbidden_countries_list); -} \ No newline at end of file diff --git a/common/src/utils/circuits/generateInputs.ts b/common/src/utils/circuits/generateInputs.ts index afb3948ea..edf299bc2 100644 --- a/common/src/utils/circuits/generateInputs.ts +++ b/common/src/utils/circuits/generateInputs.ts @@ -362,6 +362,7 @@ export function generateCircuitInputsVCandDisclose( user_identifier: string, upper_age_limit: string = '00', selector_younger_than: string | number = '0', + should_be_included: string | number = '0', ) { const { mrz, eContent, signedAttr, documentType } = passportData; const passportMetadata = passportData.passportMetadata; @@ -452,6 +453,7 @@ export function generateCircuitInputsVCandDisclose( user_identifier: formatInput(user_identifier), selector_ofac: formatInput(selector_ofac), forbidden_countries_list: formatInput(formatCountriesList(forbidden_countries_list)), + should_be_included: formatInput(should_be_included), }; const ofacNameInputs = {