Increase forbidden country list size (#175)

Co-authored-by: nicoshark <i.am.nicoshark@gmail.com>
This commit is contained in:
turnoffthiscomputer
2025-02-20 05:34:43 +01:00
committed by GitHub
parent 81b870cc8a
commit a7dbd5c788
27 changed files with 3813 additions and 172 deletions

View File

@@ -101,7 +101,7 @@ template VC_AND_DISCLOSE(
// disclose optional data
component disclose = DISCLOSE(
10,
MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH,
passportNoTreeLevels,
namedobTreeLevels,
nameyobTreeLevels
@@ -142,4 +142,4 @@ component main {
current_date,
attestation_id
]
} = VC_AND_DISCLOSE(33, 10, 64, 64, 64);
} = VC_AND_DISCLOSE(33, 40, 64, 64, 64);

View File

@@ -1,3 +1,3 @@
pragma circom 2.1.9;
include "../../utils/passport/disclose/proveCountryIsNotInList.circom";
component main { public [ forbidden_countries_list ] } = ProveCountryIsNotInList(10);
component main { public [ forbidden_countries_list ] } = ProveCountryIsNotInList(40);

View File

@@ -38,7 +38,7 @@ describe('ProveCountryIsNotInList', function () {
const dg1 = formatMrz(passportData.mrz);
it('should succeed', async () => {
const forbiddenCountriesList = ['DZA'];
const forbiddenCountriesList = ['AAA', 'USA', 'ITA', 'ABC', 'DZA', 'USA', 'ITA', 'ABC', 'DZA', 'USA', 'ITA', 'ABC', 'DZA', 'USA', 'ITA', 'ABC', 'DZA', 'USA', 'ITA', 'ABC', 'DNK', 'USA', 'DNK', 'ABC', 'DNK', 'USA', 'DNK', 'ABC', 'DNK', 'USA', 'ITA', 'ABC', 'DZA', 'USA', 'ITA', 'XXX', 'DZA', 'USA', 'ITA', 'END'];
const inputs = {
dg1: formatInput(dg1),
@@ -46,7 +46,7 @@ describe('ProveCountryIsNotInList', function () {
};
const witness = await circuit.calculateWitness(inputs);
const forbidden_countries_list_packed = await circuit.getOutput(witness, [
'forbidden_countries_list_packed[1]',
'forbidden_countries_list_packed[4]',
]);
console.log(
'\x1b[34m%s\x1b[0m',

View File

@@ -4331,7 +4331,7 @@ __metadata:
"typescript@patch:typescript@npm%3A^5.3.3#optional!builtin<compat/typescript>":
version: 5.7.3
resolution: "typescript@patch:typescript@npm%3A5.7.3#optional!builtin<compat/typescript>::version=5.7.3&hash=8c6c40"
resolution: "typescript@patch:typescript@npm%3A5.7.3#optional!builtin<compat/typescript>::version=5.7.3&hash=cef18b"
bin:
tsc: bin/tsc
tsserver: bin/tsserver

View File

@@ -29,7 +29,7 @@ export const DEFAULT_MAJORITY = '18';
export const hashAlgos = ['sha512', 'sha384', 'sha256', 'sha224', 'sha1'];
export const saltLengths = [64, 48, 32];
export const MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH = 10;
export const MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH = 40;
export const DEPLOYED_CIRCUITS_REGISTER = [
'register_sha1_sha1_sha1_rsa_65537_4096',
@@ -236,15 +236,15 @@ export const CIRCUIT_CONSTANTS = {
VC_AND_DISCLOSE_REVEALED_DATA_PACKED_INDEX: 0,
VC_AND_DISCLOSE_FORBIDDEN_COUNTRIES_LIST_PACKED_INDEX: 3,
VC_AND_DISCLOSE_NULLIFIER_INDEX: 4,
VC_AND_DISCLOSE_ATTESTATION_ID_INDEX: 5,
VC_AND_DISCLOSE_MERKLE_ROOT_INDEX: 6,
VC_AND_DISCLOSE_CURRENT_DATE_INDEX: 7,
VC_AND_DISCLOSE_PASSPORT_NO_SMT_ROOT_INDEX: 13,
VC_AND_DISCLOSE_NAME_DOB_SMT_ROOT_INDEX: 14,
VC_AND_DISCLOSE_NAME_YOB_SMT_ROOT_INDEX: 15,
VC_AND_DISCLOSE_SCOPE_INDEX: 16,
VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX: 17,
VC_AND_DISCLOSE_NULLIFIER_INDEX: 7,
VC_AND_DISCLOSE_ATTESTATION_ID_INDEX: 8,
VC_AND_DISCLOSE_MERKLE_ROOT_INDEX: 9,
VC_AND_DISCLOSE_CURRENT_DATE_INDEX: 10,
VC_AND_DISCLOSE_PASSPORT_NO_SMT_ROOT_INDEX: 16,
VC_AND_DISCLOSE_NAME_DOB_SMT_ROOT_INDEX: 17,
VC_AND_DISCLOSE_NAME_YOB_SMT_ROOT_INDEX: 18,
VC_AND_DISCLOSE_SCOPE_INDEX: 19,
VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX: 20,
}
export const MAX_BYTES_IN_FIELD = 31;

View File

@@ -78,7 +78,10 @@ export function formatAndUnpackForbiddenCountriesList(
forbiddenCountriesList_packed: string[]
): string[] {
const forbiddenCountriesList_packed_formatted = [
forbiddenCountriesList_packed['forbidden_countries_list_packed[0]']
forbiddenCountriesList_packed['forbidden_countries_list_packed[0]'],
forbiddenCountriesList_packed['forbidden_countries_list_packed[1]'],
forbiddenCountriesList_packed['forbidden_countries_list_packed[2]'],
forbiddenCountriesList_packed['forbidden_countries_list_packed[3]'],
];
const trimmed = trimu0000(unpackReveal(forbiddenCountriesList_packed_formatted));
const countries: string[] = [];

View File

@@ -47,8 +47,10 @@ function brutforceHashAlgorithmDsc(
): any {
for (const hashFunction of hashAlgos) {
if (verifySignature(dsc, csca, signatureAlgorithm, hashFunction, saltLength)) {
// console.log(`✓ Success with hash function: ${hashFunction}, signatureAlgorithm: ${signatureAlgorithm}, saltLength: ${saltLength}`);
return hashFunction;
}
// console.log(`✗ Failed with hash function: ${hashFunction}, signatureAlgorithm: ${signatureAlgorithm}, saltLength: ${saltLength}`);
}
return false;
}

View File

@@ -112,7 +112,6 @@ export function getDscTreeInclusionProof(leaf: string, serialized_dsc_tree: stri
export function getCscaTreeInclusionProof(leaf: string, _serialized_csca_tree: any[][]) {
let tree = new IMT(poseidon2, CSCA_TREE_DEPTH, 0, 2);
console.log('serialized_csca_tree', _serialized_csca_tree);
tree.setNodes(_serialized_csca_tree);
const index = tree.indexOf(leaf);
if (index === -1) {

View File

@@ -76,7 +76,7 @@ contract IdentityVerificationHubImplV1 is
{
using Formatter for uint256;
uint256 constant MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH = 10;
uint256 constant MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH = 40;
// ====================================================
// Events
@@ -362,7 +362,7 @@ contract IdentityVerificationHubImplV1 is
* @return An array of strings with a maximum length of MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH.
*/
function getReadableForbiddenCountries(
uint256 forbiddenCountriesListPacked
uint256[4] memory forbiddenCountriesListPacked
)
external
virtual
@@ -395,7 +395,9 @@ contract IdentityVerificationHubImplV1 is
for (uint256 i = 0; i < 3; i++) {
result.revealedDataPacked[i] = proof.vcAndDiscloseProof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_REVEALED_DATA_PACKED_INDEX + i];
}
result.forbiddenCountriesListPacked = proof.vcAndDiscloseProof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_FORBIDDEN_COUNTRIES_LIST_PACKED_INDEX];
for (uint256 i = 0; i < 4; i++) {
result.forbiddenCountriesListPacked[i] = proof.vcAndDiscloseProof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_FORBIDDEN_COUNTRIES_LIST_PACKED_INDEX + i];
}
result.nullifier = proof.vcAndDiscloseProof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_NULLIFIER_INDEX];
result.attestationId = proof.vcAndDiscloseProof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_ATTESTATION_ID_INDEX];
result.userIdentifier = proof.vcAndDiscloseProof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX];
@@ -632,8 +634,12 @@ contract IdentityVerificationHubImplV1 is
}
}
if (proof.forbiddenCountriesEnabled) {
if (proof.forbiddenCountriesListPacked != proof.vcAndDiscloseProof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_FORBIDDEN_COUNTRIES_LIST_PACKED_INDEX]) {
revert INVALID_FORBIDDEN_COUNTRIES();
for (uint256 i = 0; i < 4; i++) {
if (
proof.forbiddenCountriesListPacked[i] != proof.vcAndDiscloseProof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_FORBIDDEN_COUNTRIES_LIST_PACKED_INDEX + i]
) {
revert INVALID_FORBIDDEN_COUNTRIES();
}
}
}

View File

@@ -89,7 +89,7 @@ abstract contract PassportAirdropRoot is
bool olderThanEnabled,
uint256 olderThan,
bool forbiddenCountriesEnabled,
uint256 forbiddenCountriesListPacked,
uint256[4] memory forbiddenCountriesListPacked,
bool[3] memory ofacEnabled
) {
_identityVerificationHub = IIdentityVerificationHubV1(identityVerificationHub);

View File

@@ -59,45 +59,45 @@ library CircuitConstants {
/**
* @notice Index to access the nullifier in the VC and Disclose circuit public signals.
*/
uint256 constant VC_AND_DISCLOSE_NULLIFIER_INDEX = 4;
uint256 constant VC_AND_DISCLOSE_NULLIFIER_INDEX = 7;
/**
* @notice Index to access the attestation ID in the VC and Disclose circuit public signals.
*/
uint256 constant VC_AND_DISCLOSE_ATTESTATION_ID_INDEX = 5;
uint256 constant VC_AND_DISCLOSE_ATTESTATION_ID_INDEX = 8;
/**
* @notice Index to access the Merkle root in the VC and Disclose circuit public signals.
*/
uint256 constant VC_AND_DISCLOSE_MERKLE_ROOT_INDEX = 6;
uint256 constant VC_AND_DISCLOSE_MERKLE_ROOT_INDEX = 9;
/**
* @notice Index to access the current date in the VC and Disclose circuit public signals.
*/
uint256 constant VC_AND_DISCLOSE_CURRENT_DATE_INDEX = 7;
uint256 constant VC_AND_DISCLOSE_CURRENT_DATE_INDEX = 10;
/**
* @notice Index to access the passport number SMT root in the VC and Disclose circuit public signals.
*/
uint256 constant VC_AND_DISCLOSE_PASSPORT_NO_SMT_ROOT_INDEX = 13;
uint256 constant VC_AND_DISCLOSE_PASSPORT_NO_SMT_ROOT_INDEX = 16;
/**
* @notice Index to access the name and date of birth SMT root in the VC and Disclose circuit public signals.
*/
uint256 constant VC_AND_DISCLOSE_NAME_DOB_SMT_ROOT_INDEX = 14;
uint256 constant VC_AND_DISCLOSE_NAME_DOB_SMT_ROOT_INDEX = 17;
/**
* @notice Index to access the name and year of birth SMT root in the VC and Disclose circuit public signals.
*/
uint256 constant VC_AND_DISCLOSE_NAME_YOB_SMT_ROOT_INDEX = 15;
uint256 constant VC_AND_DISCLOSE_NAME_YOB_SMT_ROOT_INDEX = 18;
/**
* @notice Index to access the scope in the VC and Disclose circuit public signals.
*/
uint256 constant VC_AND_DISCLOSE_SCOPE_INDEX = 16;
uint256 constant VC_AND_DISCLOSE_SCOPE_INDEX = 19;
/**
* @notice Index to access the user identifier in the VC and Disclose circuit public signals.
*/
uint256 constant VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX = 17;
uint256 constant VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX = 20;
}

View File

@@ -99,7 +99,7 @@ contract Airdrop is PassportAirdropRoot, Ownable {
bool _olderThanEnabled,
uint256 _olderThan,
bool _forbiddenCountriesEnabled,
uint256 _forbiddenCountriesListPacked,
uint256[4] memory _forbiddenCountriesListPacked,
bool[3] memory _ofacEnabled
)
PassportAirdropRoot(

View File

@@ -47,7 +47,7 @@ interface IIdentityVerificationHubV1 {
uint256 nullifier;
uint256 identityCommitmentRoot;
uint256[3] revealedDataPacked;
uint256 forbiddenCountriesListPacked;
uint256[4] forbiddenCountriesListPacked;
}
/**
@@ -91,7 +91,7 @@ interface IIdentityVerificationHubV1 {
bool olderThanEnabled;
uint256 olderThan;
bool forbiddenCountriesEnabled;
uint256 forbiddenCountriesListPacked;
uint256[4] forbiddenCountriesListPacked;
bool[3] ofacEnabled;
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof vcAndDiscloseProof;
}
@@ -131,11 +131,11 @@ interface IIdentityVerificationHubV1 {
* @return forbiddenCountries A fixed-size array (length defined by CircuitConstants.MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH) of strings representing forbidden countries.
*/
function getReadableForbiddenCountries(
uint256 forbiddenCountriesListPacked
uint256[4] memory forbiddenCountriesListPacked
)
external
view
returns (string[10] memory forbiddenCountries);
returns (string[40] memory forbiddenCountries);
/**
* @notice Registers a passport commitment using a register circuit proof.

View File

@@ -22,7 +22,7 @@ interface IPassportAirdropRoot {
bool olderThanEnabled;
uint256 olderThan;
bool forbiddenCountriesEnabled;
uint256 forbiddenCountriesListPacked;
uint256[4] forbiddenCountriesListPacked;
bool[3] ofacEnabled;
}

View File

@@ -19,7 +19,7 @@ interface IVcAndDiscloseCircuitVerifier {
uint[2] a;
uint[2][2] b;
uint[2] c;
uint[18] pubSignals;
uint[21] pubSignals;
}
/**
@@ -35,6 +35,6 @@ interface IVcAndDiscloseCircuitVerifier {
uint[2] calldata a,
uint[2][2] calldata b,
uint[2] calldata c,
uint[18] calldata pubSignals
uint[21] calldata pubSignals
) external view returns (bool);
}

View File

@@ -14,7 +14,7 @@ library Formatter {
error InvalidFieldElement();
error InvalidDateDigit();
uint256 constant MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH = 10;
uint256 constant MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH = 40;
uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
/**
@@ -147,11 +147,11 @@ library Formatter {
* @notice Extracts forbidden country codes from a packed uint256.
* @dev Each forbidden country is represented by 3 bytes in the packed data.
* The function extracts up to MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH forbidden countries.
* @param publicSignal A packed uint256 containing encoded forbidden country data.
* @param publicSignals A packed uint256 containing encoded forbidden country data.
* @return forbiddenCountries An array of strings representing the forbidden country codes.
*/
function extractForbiddenCountriesFromPacked(
uint256 publicSignal
uint256[4] memory publicSignals
)
internal
pure
@@ -159,20 +159,45 @@ library Formatter {
string[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH] memory forbiddenCountries
)
{
if (publicSignal >= SNARK_SCALAR_FIELD) {
revert InvalidFieldElement();
for (uint256 i = 0; i < 4; i++) {
if (publicSignals[i] >= SNARK_SCALAR_FIELD) {
revert InvalidFieldElement();
}
}
for (uint256 j = 0; j < MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH; j++) {
uint256 byteIndex = j * 3;
uint256 shift = byteIndex * 8;
uint256 mask = 0xFFFFFF;
uint256 packedData = (publicSignal >> shift) & mask;
forbiddenCountries[j] = string(abi.encodePacked(uint24(packedData)));
if (byteIndex + 2 < 32) {
uint256 shift = byteIndex * 8;
uint256 mask = 0xFFFFFF;
uint256 packedData = (publicSignals[0] >> shift) & mask;
forbiddenCountries[j] = string(abi.encodePacked(uint24(packedData)));
} else if (byteIndex < 32) {
uint256 bytesFrom0 = 32 - byteIndex;
uint256 bytesTo1 = 3 - bytesFrom0;
uint256 shift0 = byteIndex * 8;
uint256 mask0 = (1 << (bytesFrom0 * 8)) - 1;
uint256 part0 = (publicSignals[0] >> shift0) & mask0;
uint256 shift1 = 0;
uint256 mask1 = (1 << (bytesTo1 * 8)) - 1;
uint256 part1 = (publicSignals[1] >> shift1) & mask1;
uint256 combined = (part1 << (bytesFrom0 * 8)) | part0;
forbiddenCountries[j] = string(abi.encodePacked(uint24(combined)));
} else {
uint256 byteIndexIn1 = byteIndex - 32;
uint256 shift = byteIndexIn1 * 8;
uint256 mask = 0xFFFFFF;
uint256 packedData = (publicSignals[1] >> shift) & mask;
forbiddenCountries[j] = string(abi.encodePacked(uint24(packedData)));
}
}
return forbiddenCountries;
}
/**

View File

@@ -20,12 +20,12 @@ contract TestFormatter {
return Formatter.fieldElementsToBytes(publicSignals);
}
function testExtractForbiddenCountriesFromPacked(uint256 publicSignal)
function testExtractForbiddenCountriesFromPacked(uint256[4] memory publicSignals)
external
pure
returns (string[10] memory)
returns (string[40] memory)
{
return Formatter.extractForbiddenCountriesFromPacked(publicSignal);
return Formatter.extractForbiddenCountriesFromPacked(publicSignals);
}
function testProofDateToUnixTimestamp(uint256[6] memory dateNum) external pure returns (uint256) {

View File

@@ -8,7 +8,7 @@ import {generateVcAndDiscloseProof } from "../utils/generateProof";
import { LeanIMT } from "@openpassport/zk-kit-lean-imt";
import { poseidon2 } from "poseidon-lite";
import { generateCommitment } from "../../../common/src/utils/passports/passport";
import { generateRandomFieldElement } from "../utils/utils";
import { generateRandomFieldElement, splitHexFromBack } from "../utils/utils";
import BalanceTree from "../utils/example/balance-tree";
import { castFromScope } from "../../../common/src/utils/circuits/uuid";
import { formatCountriesList, reverseBytes } from '../../../common/src/utils/circuits/formatInputs';
@@ -70,7 +70,7 @@ describe("Airdrop", () => {
const root = await deployedActors.registry.getIdentityCommitmentMerkleRoot();
const timestamp = await deployedActors.registry.rootTimestamps(root);
countriesListPacked = reverseBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList))));
countriesListPacked = splitHexFromBack(reverseBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList)))));
const airdropFactory = await ethers.getContractFactory("Airdrop");
airdrop = await airdropFactory.connect(deployedActors.owner).deploy(
@@ -587,7 +587,9 @@ describe("Airdrop", () => {
expect(storedConfig.olderThanEnabled).to.equal(newVerificationConfig.olderThanEnabled);
expect(storedConfig.olderThan).to.equal(newVerificationConfig.olderThan);
expect(storedConfig.forbiddenCountriesEnabled).to.equal(newVerificationConfig.forbiddenCountriesEnabled);
expect(storedConfig.forbiddenCountriesListPacked).to.equal(newVerificationConfig.forbiddenCountriesListPacked);
for (let i = 0; i < 4; i++) {
expect(storedConfig.forbiddenCountriesListPacked[i]).to.equal(newVerificationConfig.forbiddenCountriesListPacked[i]);
}
expect(storedConfig.ofacEnabled).to.deep.equal(newVerificationConfig.ofacEnabled);
});
@@ -611,7 +613,9 @@ describe("Airdrop", () => {
expect(config.olderThanEnabled).to.equal(true);
expect(config.olderThan).to.equal(20);
expect(config.forbiddenCountriesEnabled).to.equal(true);
expect(config.forbiddenCountriesListPacked).to.equal(countriesListPacked);
for (let i = 0; i < 4; i++) {
expect(config.forbiddenCountriesListPacked[i]).to.equal(countriesListPacked[i]);
}
expect(config.ofacEnabled).to.deep.equal([true, true, true]);
});

View File

@@ -5,7 +5,7 @@ import { ethers } from "hardhat";
import { RegisterVerifierId, DscVerifierId, CIRCUIT_CONSTANTS } from "../../../common/src/constants/constants";
import { ATTESTATION_ID } from "../utils/constants";
import { generateRegisterProof, generateDscProof, generateVcAndDiscloseProof } from "../utils/generateProof";
import { generateRandomFieldElement } from "../utils/utils";
import { generateRandomFieldElement, splitHexFromBack } from "../utils/utils";
import { TransactionReceipt, ZeroAddress } from "ethers";
import serialized_dsc_tree from '../../../common/pubkeys/serialized_dsc_tree.json';
import { LeanIMT } from "@openpassport/zk-kit-lean-imt";
@@ -132,7 +132,7 @@ describe("End to End Tests", function () {
expect(identityNullifier).to.equal(true);
const forbiddenCountriesList = ['AAA', 'ABC', 'CBA'];
const countriesListPacked = reverseBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList))));
const countriesListPacked = splitHexFromBack(reverseBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList)))));
const vcAndDiscloseProof = await generateVcAndDiscloseProof(
registerSecret,
@@ -168,7 +168,9 @@ describe("End to End Tests", function () {
expect(result.attestationId).to.equal(vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_ATTESTATION_ID_INDEX]);
expect(result.userIdentifier).to.equal(vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX]);
expect(result.scope).to.equal(vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_SCOPE_INDEX]);
expect(result.forbiddenCountriesListPacked).to.equal(BigInt(countriesListPacked));
for (let i = 0; i < 4; i++) {
expect(result.forbiddenCountriesListPacked[i]).to.equal(BigInt(countriesListPacked[i]));
}
const tokenFactory = await ethers.getContractFactory("AirdropToken");
const token = await tokenFactory.connect(owner).deploy();

View File

@@ -9,7 +9,7 @@ import { LeanIMT } from "@openpassport/zk-kit-lean-imt";
import { poseidon2 } from "poseidon-lite";
import { generateCommitment } from "../../../common/src/utils/passports/passport";
import { BigNumberish } from "ethers";
import { generateRandomFieldElement, getStartOfDayTimestamp } from "../utils/utils";
import { generateRandomFieldElement, getStartOfDayTimestamp, splitHexFromBack } from "../utils/utils";
import { Formatter, CircuitAttributeHandler } from "../utils/formatter";
import { formatCountriesList, reverseBytes, reverseCountryBytes } from '../../../common/src/utils/circuits/formatInputs';
import fs from 'fs';
@@ -27,23 +27,32 @@ describe("VC and Disclose", () => {
let forbiddenCountriesList: string[];
let invalidForbiddenCountriesList: string[];
let forbiddenCountriesListPacked: string;
let invalidForbiddenCountriesListPacked: string;
let forbiddenCountriesListPacked: string[];
let invalidForbiddenCountriesListPacked: string[];
before(async () => {
deployedActors = await deploySystemFixtures();
registerSecret = generateRandomFieldElement();
nullifier = generateRandomFieldElement();
commitment = generateCommitment(registerSecret, ATTESTATION_ID.E_PASSPORT, deployedActors.mockPassport);
await deployedActors.registry.connect(deployedActors.owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]);
imt = new LeanIMT<bigint>(hashFunction);
await imt.insert(BigInt(commitment));
forbiddenCountriesList = ['AAA', 'ABC', 'CBA'];
forbiddenCountriesListPacked = reverseBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList))));
forbiddenCountriesList = ['AAA', 'ABC', 'CBA', 'AAA', 'AAA', 'ABC', 'CBA', 'AAA', 'ABC', 'CBA','AAA', 'ABC', 'CBA', 'AAA', 'ABC', 'CBA', 'AAA', 'ABC', 'CBA', 'AAA', 'ABC', 'CBA','AAA', 'ABC', 'CBA', 'AAA', 'ABC', 'CBA','AAA', 'ABC', 'CBA', 'AAA', 'ABC', 'CBA', 'AAA', 'ABC', 'CBA', 'AAA', 'ABC', 'CBA'];
const wholePacked = reverseBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList))));
forbiddenCountriesListPacked = splitHexFromBack(wholePacked);
invalidForbiddenCountriesList = ['AAA', 'ABC', 'CBA', 'CBA'];
invalidForbiddenCountriesListPacked = reverseBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(invalidForbiddenCountriesList))));
const invalidWholePacked = reverseBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(invalidForbiddenCountriesList))));
invalidForbiddenCountriesListPacked = splitHexFromBack(invalidWholePacked);
baseVcAndDiscloseProof = await generateVcAndDiscloseProof(
registerSecret,
@@ -77,12 +86,8 @@ describe("VC and Disclose", () => {
it("should verify and get result successfully", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
console.log(vcAndDiscloseProof.pubSignals);
// console.log("root in proof: ", vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_MERKLE_ROOT_INDEX]);
const vcAndDiscloseHubProof = {
olderThanEnabled: true,
@@ -101,18 +106,14 @@ describe("VC and Disclose", () => {
expect(result.attestationId).to.equal(vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_ATTESTATION_ID_INDEX]);
expect(result.userIdentifier).to.equal(vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_USER_IDENTIFIER_INDEX]);
expect(result.scope).to.equal(vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_SCOPE_INDEX]);
expect(result.forbiddenCountriesListPacked).to.equal(forbiddenCountriesListPacked);
for (let i = 0; i < 4; i++) {
expect(result.forbiddenCountriesListPacked[i]).to.equal(BigInt(forbiddenCountriesListPacked[i]));
}
});
it("should not call verifyVcAndDisclose with non-proxy address", async() => {
const {hubImpl, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
const vcAndDiscloseHubProof = {
olderThanEnabled: false,
olderThan: "20",
@@ -129,12 +130,6 @@ describe("VC and Disclose", () => {
it("should fail with invalid identity commitment root", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_MERKLE_ROOT_INDEX] = generateRandomFieldElement();
const vcAndDiscloseHubProof = {
olderThanEnabled: true,
@@ -153,11 +148,6 @@ describe("VC and Disclose", () => {
it("should fail with invalid passport number OFAC root", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_PASSPORT_NO_SMT_ROOT_INDEX] = generateRandomFieldElement();
const vcAndDiscloseHubProof = {
@@ -177,11 +167,6 @@ describe("VC and Disclose", () => {
it("should fail with invalid name and dob OFAC root", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_NAME_DOB_SMT_ROOT_INDEX] = generateRandomFieldElement();
const vcAndDiscloseHubProof = {
@@ -201,11 +186,6 @@ describe("VC and Disclose", () => {
it("should fail with invalid name and yob OFAC root", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
vcAndDiscloseProof.pubSignals[CIRCUIT_CONSTANTS.VC_AND_DISCLOSE_NAME_YOB_SMT_ROOT_INDEX] = generateRandomFieldElement();
const vcAndDiscloseHubProof = {
@@ -225,11 +205,6 @@ describe("VC and Disclose", () => {
it("should fail with invalid current date (more than + 1 day)", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
const currentBlock = await ethers.provider.getBlock('latest');
const oneDayAfter = getStartOfDayTimestamp(currentBlock!.timestamp) + 24 * 60 * 60;
@@ -264,11 +239,6 @@ describe("VC and Disclose", () => {
it("should not revert when current date is within + 1 day", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
const currentBlock = await ethers.provider.getBlock('latest');
const oneDayAfter = getStartOfDayTimestamp(currentBlock!.timestamp) + 24 * 60 * 60 - 1;
@@ -305,12 +275,6 @@ describe("VC and Disclose", () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
const vcAndDiscloseHubProof = {
olderThanEnabled: true,
olderThan: "20",
@@ -345,11 +309,6 @@ describe("VC and Disclose", () => {
it("should not revert when current date is slightly less than - 1 day", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
const currentBlock = await ethers.provider.getBlock('latest');
const oneDayBefore = getStartOfDayTimestamp(currentBlock!.timestamp);
@@ -384,12 +343,6 @@ describe("VC and Disclose", () => {
it("should succeed with bigger value than older than", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
const vcAndDiscloseHubProof = {
olderThanEnabled: true,
olderThan: "18",
@@ -407,12 +360,6 @@ describe("VC and Disclose", () => {
it("should fail with invalid older than", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
const vcAndDiscloseHubProof = {
olderThanEnabled: true,
olderThan: "21",
@@ -430,12 +377,6 @@ describe("VC and Disclose", () => {
it("should fail with if listed in OFAC", async () => {
const {hub, registry, owner, mockPassport} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]);
const imt = new LeanIMT<bigint>(hashFunction);
imt.insert(BigInt(commitment));
@@ -478,12 +419,6 @@ describe("VC and Disclose", () => {
it("should fail with invalid forbidden countries", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
const vcAndDiscloseHubProof = {
olderThanEnabled: true,
olderThan: "20",
@@ -501,12 +436,6 @@ describe("VC and Disclose", () => {
it("should not revert when all enablers are false", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
const vcAndDiscloseHubProof = {
olderThanEnabled: false,
olderThan: "40",
@@ -524,12 +453,6 @@ describe("VC and Disclose", () => {
it("should fail with invalid VC and Disclose proof", async () => {
const {hub, registry, owner} = deployedActors;
await registry.connect(owner).devAddIdentityCommitment(
ATTESTATION_ID.E_PASSPORT,
nullifier,
commitment
);
vcAndDiscloseProof.a[0] = generateRandomFieldElement();
const vcAndDiscloseHubProof = {
@@ -758,7 +681,7 @@ describe("VC and Disclose", () => {
it("should parse forbidden countries with CircuitAttributeHandler", async () => {
const { hub } = deployedActors;
const forbiddenCountriesListPacked = reverseCountryBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList))));
const forbiddenCountriesListPacked = splitHexFromBack(reverseCountryBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList)))));
const readableForbiddenCountries = await hub.getReadableForbiddenCountries(forbiddenCountriesListPacked);
expect(readableForbiddenCountries[0]).to.equal(forbiddenCountriesList[0]);
@@ -770,9 +693,9 @@ describe("VC and Disclose", () => {
const { hub } = deployedActors;
const forbiddenCountriesList = ['AAA', 'FRA', 'CBA', 'CBA', 'CBA', 'CBA', 'CBA', 'CBA', 'CBA', 'CBA'];
const forbiddenCountriesListPacked = reverseCountryBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList))));
const forbiddenCountriesListPacked = splitHexFromBack(reverseCountryBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList)))));
const readableForbiddenCountries = await hub.getReadableForbiddenCountries(forbiddenCountriesListPacked);
expect(readableForbiddenCountries.length).to.equal(10);
expect(readableForbiddenCountries.length).to.equal(40);
expect(readableForbiddenCountries[0]).to.equal(forbiddenCountriesList[0]);
expect(readableForbiddenCountries[1]).to.equal(forbiddenCountriesList[1]);
expect(readableForbiddenCountries[2]).to.equal(forbiddenCountriesList[2]);
@@ -788,7 +711,7 @@ describe("VC and Disclose", () => {
it("should fail when getReadableForbiddenCountries is called by non-proxy", async () => {
const {hubImpl} = deployedActors;
const forbiddenCountriesList = ['AAA', 'FRA', 'CBA', 'CBA', 'CBA', 'CBA', 'CBA', 'CBA', 'CBA', 'CBA'];
const forbiddenCountriesListPacked = reverseCountryBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList))));
const forbiddenCountriesListPacked = splitHexFromBack(reverseCountryBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList)))));
await expect(
hubImpl.getReadableForbiddenCountries(forbiddenCountriesListPacked)
).to.be.revertedWithCustomError(hubImpl, "UUPSUnauthorizedCallContext");

View File

@@ -2,7 +2,7 @@ import { expect } from "chai";
import { ethers } from "hardhat";
import { deploySystemFixtures } from "../utils/deployment";
import { DeployedActors } from "../utils/types";
import { generateRandomFieldElement } from "../utils/utils";
import { generateRandomFieldElement, splitHexFromBack } from "../utils/utils";
import { generateCommitment } from "../../../common/src/utils/passports/passport";
import { ATTESTATION_ID } from "../utils/constants";
import { CIRCUIT_CONSTANTS } from "../../../common/src/constants/constants";
@@ -26,11 +26,7 @@ describe("VerifyAll", () => {
let commitment: any;
let nullifier: any;
let forbiddenCountriesList: string[];
let forbiddenCountriesListPacked: string;
let rawProof: {
proof: Groth16Proof,
publicSignals: PublicSignals
};
let forbiddenCountriesListPacked: string[];
before(async () => {
deployedActors = await deploySystemFixtures();
@@ -49,7 +45,7 @@ describe("VerifyAll", () => {
await imt.insert(BigInt(commitment));
forbiddenCountriesList = ['AAA', 'ABC', 'CBA'];
forbiddenCountriesListPacked = reverseBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList))));
forbiddenCountriesListPacked = splitHexFromBack(reverseBytes(Formatter.bytesToHexString(new Uint8Array(formatCountriesList(forbiddenCountriesList)))));
baseVcAndDiscloseProof = await generateVcAndDiscloseProof(
registerSecret,

View File

@@ -2,6 +2,7 @@ import { expect } from "chai";
import { ethers } from "hardhat";
import { TestFormatter } from "../../typechain-types";
import { Formatter } from "../utils/formatter";
import { splitHexFromBack } from "../utils/utils";
describe("Formatter", function () {
let testFormatter: TestFormatter;
@@ -171,7 +172,14 @@ describe("Formatter", function () {
describe("extractForbiddenCountriesFromPacked", function () {
it("should match contract and ts implementation", async function () {
const input = "0x414141424242434343";
const contractResult = await testFormatter.testExtractForbiddenCountriesFromPacked(input);
const contractResult = await testFormatter.testExtractForbiddenCountriesFromPacked(
[
input,
0n,
0n,
0n,
]
);
const tsResult = Formatter.extractForbiddenCountriesFromPacked(BigInt(input));
expect(contractResult).to.deep.equal(tsResult);
expect(contractResult[0]).to.equal("CCC");
@@ -181,7 +189,14 @@ describe("Formatter", function () {
it("should revert when field element is out of range", async function () {
const input = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
await expect(testFormatter.testExtractForbiddenCountriesFromPacked(input))
await expect(testFormatter.testExtractForbiddenCountriesFromPacked([
input,
0n,
0n,
0n
]
))
.to.be.revertedWithCustomError(testFormatter, "InvalidFieldElement");
});
});

View File

@@ -1,5 +1,5 @@
export class Formatter {
static MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH = 10;
static MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH = 40;
static formatName(input: string): [string, string] {
let lastName = "";

View File

@@ -168,6 +168,7 @@ export async function generateVcAndDiscloseRawProof(
forbiddenCountriesList,
userIdentifier
);
console.log("forbiddenCountriesList: ", vcAndDiscloseCircuitInputs.forbidden_countries_list);
console.log(CYAN, "=== Start generateVcAndDiscloseRawProof ===", RESET);
const startTime = performance.now();
@@ -205,7 +206,7 @@ export async function generateVcAndDiscloseProof(
nameAndDob_smt?: SMT,
nameAndYob_smt?: SMT,
selectorOfac: string | number = "1",
forbiddenCountriesList: string[] = ["AAA"],
forbiddenCountriesList: string[] = ["AAA","000","000","000","000","000","000","000","000","000","AAA","000","000","000","000","000","000","000","000","000","AAA","000","000","000","000","000","000","000","000","000","AAA","000","000","000","000","000","000","000","000","000"],
userIdentifier: string = "0000000000000000000000000000000000000000"
): Promise<VcAndDiscloseProof> {
const rawProof = await generateVcAndDiscloseRawProof(

View File

@@ -13,4 +13,24 @@ export function generateRandomFieldElement(): string {
export function getStartOfDayTimestamp(timestamp: number): number {
const dayInSeconds = 86400;
return timestamp - (timestamp % dayInSeconds);
}
export function splitHexFromBack(hexString: string, bytesPerChunk: number = 31): string[] {
if (hexString.startsWith("0x")) {
hexString = hexString.slice(2);
}
const chunkSizeHex = bytesPerChunk * 2;
const chunks: string[] = [];
let remaining = hexString;
while (remaining.length > 0) {
const chunk = remaining.slice(-chunkSizeHex);
remaining = remaining.slice(0, -chunkSizeHex);
const paddedChunk = chunk.padStart(64, "0");
chunks.push("0x" + paddedChunk);
}
return chunks;
}

Binary file not shown.

3645
sdk/qrcode/yarn.lock Normal file

File diff suppressed because it is too large Load Diff