mirror of
https://github.com/selfxyz/self.git
synced 2026-01-09 14:48:06 -05:00
Feat/aadhaar (#949)
* make contract sdk simpler (#514) * make contract sdk simpler * reduce root inputs * delete convert function * summarize our library * update npm package * update package version * update attestation id * add util function to get revealed data * Revert "make contract sdk simpler (#514)" (#518) This reverts commit847b88d5ec. * merge dev into main (#576) * Feat: Show error code in SDK (#500) * feat: emit `error_code` and `reason` in app * feat: add `onError` in sdk * feat: Display reason in app * lint & fmt * feat: add scrollview in ProofRequestStatusScreen for long reasons * Fix input generation for 521bit curves (#481) * fix EC point padding for 521 bit curves * rename modulus to point in findStartIndexEC as it is a point * simplify matching logic * simplify padding logic * remove comment * remove log removing .only so the CI/CD runs circuit tests fix disclosure test fix scope in test fix scope error in circuit tests remove .only fix test * run ci/cd * Feat/simpler contract sdk (#519) * make contract sdk simpler * reduce root inputs * delete convert function * summarize our library * update npm package * update package version * update attestation id * add util function to get revealed data --------- Co-authored-by: motemotech <i.am.nicoshark@gmail.com> * forgot to include package update (#521) * Bump version to 2.5.1 (#522) * bump version * update fastlane * fix bump version * bump build and add todo * disable commit for now * [SEL-154] Step 1: Scan your passport (#511) * simplify navigation logic * use aesop design hook * save wip * add new aesop redesign screens * save wip design * refactor nav bar logic * fix paths * save wip * stub progress navbar and save wip * save wip progress bar animation * save wip progress bar, almost done with design * fix progress bar design * fix bottom padding * disable git commit for now * fix flaky android downloads that causes pipeline to crash * update lock for ci * [SEL-46] FE: Add minimum bottom padding (#510) * fix bottom padding for smaller screens * fix podfile post install hook permissions check * update pod lock and disable git commit action step for now * update lock * fix flaky android downloads that causes pipeline to crash * fix: improve error handling for forbidden countries list mismatch (#494) * Update SelfBackendVerifier.ts * Update constants.ts * Update formatInputs.ts * Update formatCallData.ts * DX: Auto format on save (#526) * save wip * use elint instead of prettier to sort imports * set imports to warn * sync prettier settigns * update prettier settings * save working version * fix export and disable mobile pipeline for now * limit auto formatting to the app folder * remove artefacts * SEL-187: Make bottom layout scrollable on smaller screens (#525) * fix design check * add an option to disable local sending of sentry events * better sentry enable / disable * fix scan passport height * make bottom layout scrollable so it doesn't squish top screen * simpler logic check. don't create new env var * fix internet connection issues * readd comment * use isConnected instead of internet reachable * use a dynamic bottom panel height * add missing recovery screens * move aesop below * remove dupe export * fix rebase * fix android package download issue * Feat/extend id support (#517) * refactor proving impleting xstate, speedup proving * add disclosure proof support * keep refactoring provingMachine, clean old implementation * call init method when switching from dsc to register * rebase with dev to display why the proof verification failed * refactor ws connexion between front-end and mobile to retrieve self-app * update the webclient at proofVerification and use selfAppStore in provingMachine * fix provintStore.init in ProveScreen * yarn nice * fetch data correctly in splash screen * Bump build versions for 2.5.1 (#531) * release new builds * fix app and build versions * fix env check * display error animation on failure on loading screen (#532) * display error animation on failure on loading screen * remove log --------- Co-authored-by: Justin Hernandez <transphorm@gmail.com> * ci: bump actions/checkout to v4 (#529) * make contract sdk simpler (#514) * make contract sdk simpler * reduce root inputs * delete convert function * summarize our library * update npm package * update package version * update attestation id * add util function to get revealed data * Revert "make contract sdk simpler (#514)" (#518) This reverts commit847b88d5ec. * ci: bump actions/checkout to v4 --------- Co-authored-by: nicoshark <i.am.nicoshark@gmail.com> Co-authored-by: turnoffthiscomputer <98749896+remicolin@users.noreply.github.com> * fix italy (#530) * Fix/proving machine endpoint type (#538) * store endpoint type in proving machine * yarn nice * fix splash screen error (#539) * New bug fix build for v2.5.1 (#540) * bump new build for dev fixes * update lock * reinstall before running local deploy * SEL-178: Improve haptic feedback library (#535) * fix dev settings typing * add dev screens file * save haptic feedback progress * change ordedr * fix initial route and add haptic feedback screen to dev settings options * add delete scripts (#542) * update staging registry address (#545) * feat: Add Disclose history (#533) * feat: Add Disclose history * fix: Duplicate history in list * fix: Outdated disclosures * Delete app/ios/Self copy-Info.plist * allow a scale of up to 1.3 (#546) * allow a scale of up to 1.3 * update lock files * clean up unused imports * fix settings * add common sdk (#537) * add common sdk * remove sdk backend api * remove registry * regenerate sha256 rsa dsc each time * download ski-pem dynamically on staging, refactor initpassportDataParsing * add state machine for button on prove screen, improve ux on splash screen * fetch ski-pem in production * fix linter issues * fix prove screen button bugs * update podfile.lock and yarn.lock * run linter in circuits repo * bump build * bump version for sentry debugging * bump ios to version 118 --------- Co-authored-by: Justin Hernandez <transphorm@gmail.com> * better connection check (#548) * Clean up navigation and setup Jest (#549) * remove dupe account screens and prefer the term home * organize screen loading better * sort keys * rename screen files wip * fix deleted directory issues * rename folders * fix paths and naming * save working jest import test * save base working jest navigation test * finalize navigation refactor and jest test * update test name and podfile lock * remove unused packages * use the correct version of react test renderer * bump build (#552) * Eth dublin (#554) * add mock id card generator * add genMockIdDoc in common/sdk exports * onboard developer id using deeplink, allow custom birthdate on mockpassport * log more dsc info (#558) * Push notification (#536) * add push notification feature * merge new app impl * change dsc key * import * reverse mock dsc * worked in the ios * checked in android * update url and delete console * delete small changes * lint * add yarn.lock * fix warning message * add mock notification service for test code * fix path for the mock implementation * add mock deeplink to the test code * nice notificationServiceMock.js * delete unused firebase related implementation * fix wording and UI related to notification service * hotfix on mockdatascreen --------- Co-authored-by: turnoffthiscomputer <colin.remi07@gmail.com> * Fix deeplink 2 (#560) * fix deeplink * fix deeplink * yarn nice * feat: Use vision for MRZ scanning (SEL-47) (#557) * feat: Use vision for MRZ scanning * modify label to position the smartphone during the OCR scan --------- Co-authored-by: turnoffthiscomputer <colin.remi07@gmail.com> * SEL-255: improved loading screen with estimated wait times (#550) * create new loading screen and rename static to misc * fix route * save wip loading screen * save wip animation * save static wip design * continue * splash * add a loading screen text helper * add test for loading screen text * save wip. almost there * update haptic logic * better feedback and add dev scren * save current work * update text logic and tests * load passport metadata in loading screen * simplify and fix tests * test for additional exponents * add new animation * rename file * consolidate ui useEffect and fix loading screen layout * fix current state * remove mockPassportFlow param * merge new loading screen and new notification logic * simplify * update lock * use passportMetadata instead of metadata * save simplification * update loading text based on pr feedback and tests * Bump v2.5.1: ios 122; android 60 (#561) * increment build to 120 * bump builds for 2.5.1. ios 121; android 60 * clean up logic * upgrade react native firebase for privacy manifests * update react native keychain to fix could not recover issue (#564) * fix: update ocr corrections (#563) * Chore: Polish proof history to prep for release (#566) * clean up nav and home boundaries, passport data screen insets * migrate proof history screen out of settings * minor clean up * save wip * add new ibm plex mono font and clean up proof detail screen * remove test data * remove extra loading screen text * remove unnecessary ceil * Bump v2.5.1; ios 123; android 62 (#565) * bump to build 61 * bump ios version * update version * Feature/add prettier formatter (#568) * Add Prettier configuration and ignore files for code formatting - Created .prettierignore to exclude specific directories and files from formatting. - Added .prettierrc.yml with custom settings for print width and trailing commas. - Updated package.json to include Prettier and its Solidity plugin as dependencies, along with scripts for formatting and checking code. * Run prettier formatting * fix nationality using mock passports * SEL-181 & SEL-252: Update mobile app events (#570) * improve analytics handling * add error boundary that flushes segment events before error occurs * upgrade segment analytics package * flush analytics when user encounters error screen * track all click events * add tracking to loading screen * better init and click event names * track cloud backup and modal actions * use __DEV__ for debugging * add tracking to account recovery, auth, mock data * return false instead of throwing * add more tracking events * save wip event updating * abstract analytic event names * update click events * clean up * move reasons comment * add unsupported passport event * Feature/enhance self verification root (#569) * Add SelfVerificationConsumer contract for self-verification logic - Introduced an abstract contract, SelfVerificationConsumer, that extends SelfVerificationRoot. - Implemented nullifier tracking, verification success events, and customizable validation and update methods for nullifiers. - Added error handling for nullifier check failures and hooks for derived contracts to implement custom logic after successful verification. * Add SelfHappyBirthday contract example using SelfVerificationConsumer - Introduced SelfHappyBirthday contract that allows users to claim USDC on their birthday. - Integrated SelfVerificationConsumer for handling verification and nullifier tracking. - Added functions to set claimable amount and window, along with event emissions for state changes. - Implemented logic to check if the claim is within the user's birthday window and transfer USDC accordingly. * Refactor imports in HappyBirthday contract for better organization - Updated import statements in HappyBirthday.sol to use relative paths for ISelfVerificationRoot, SelfCircuitLibrary, and SelfVerificationConsumer. - Improved code readability and maintainability by organizing imports more logically. * Refactor Airdrop contract to use SelfVerificationConsumer for registration logic - Updated Airdrop contract to inherit from SelfVerificationConsumer instead of SelfVerificationRoot. - Refactored mappings for user identifiers and nullifiers for improved clarity and functionality. - Enhanced error handling and updated function parameters for consistency. - Implemented new validation and update methods for nullifiers, streamlining the registration process. - Removed deprecated verifySelfProof function and integrated logic into new methods. * Add events and refactor SelfVerificationRoot and related contracts - Introduced new events in SelfVerificationRoot for verification configuration updates, scope changes, and attestation ID management. - Updated Airdrop contract to remove deprecated events and added a new event for Merkle root updates. - Refactored SelfPassportERC721 to inherit from SelfVerificationConsumer, enhancing verification logic and event handling. - Improved function parameters for consistency and clarity across contracts. * Refactor contracts to use SelfVerificationRoot and enhance verification logic - Removed SelfVerificationConsumer contract and updated related contracts to inherit from SelfVerificationRoot. - Refactored mappings and event emissions in Airdrop, HappyBirthday, and SelfPassportERC721 for improved clarity and functionality. - Enhanced verification success hooks to include user identifiers and nullifiers for better tracking. - Updated constructor parameters for consistency across contracts and improved error handling for user registration and claims. * Refactor constructor in SelfPassportERC721 for improved readability * Refactor function parameters in SelfVerificationRoot and related contracts * Refactor constructor parameter names in IdentityVerificationHub, Airdrop, IdentityRegistry, and ProxyRoot contracts for improved clarity and consistency * fix getCircuitName function (#575) * fix getCircuitName function * fix getCircuitName function * feat: Read ID cards (#571) * Update GitHub checkout action from v3 to v4 (#544) * Bump build version 2.5.2 to test react native keychain (#572) * bump build and version * bump version 2.5.2 * don't downgrade react native keychain * update app/README.md toolchain instructions (#140) * bump build (#580) --------- Co-authored-by: Seshanth.S🐺 <35675963+seshanthS@users.noreply.github.com> Co-authored-by: turboblitz <florent.tavernier@gmail.com> Co-authored-by: motemotech <i.am.nicoshark@gmail.com> Co-authored-by: Justin Hernandez <transphorm@gmail.com> Co-authored-by: crStiv <cryptostiv7@gmail.com> Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz> Co-authored-by: James Niken <danylonepritvoreniy@gmail.com> Co-authored-by: Kevin Lin <86810837+kevinsslin@users.noreply.github.com> Co-authored-by: leopardracer <136604165+leopardracer@users.noreply.github.com> Co-authored-by: Olof Andersson <olof.andersson@gmail.com> * feat(wip): register circuit for aadhaar * chore: add anon aadhar circuits * chore: remove sc and disclose selfrica test * feat: extract aadhaar qr data * test: aadhaar qr data extract circuit * test: aadhaar register circuit * feat: extract pincode and ph no last 4 digit * fix: register aadhaar nullifier and commitment * test: Verify commitment circuit of aadhaar * feat: add photoHash inside commitment * feat: build Aadhaar OFAC SMT * feat: ofac check and reveal data (test done) * test: qr extractor for custom data input * feat: add state as reveal data inside VC and disclose * chore: add comments * fix: num2Ceil component * chore: review changes * chore: use passport SignatureVerifier * fix: signatureVerifier inputs * feat: extract ascii values of fields * feat: provide users the flexibility to reveal specific characters of a field * chore: refactor * test: register aadhaar for tampered data * test(wip): should return 0 if in ofac list * test: ofac check * test: register aadhaar circuit for different qr data * merge dev into main (#683) * remove sdk/tests (#622) * remove sdk/tests * chore: update yarn.lock --------- Co-authored-by: Ayman <aymanshaik1015@gmail.com> * fix: add range check on paddedInLength of shaBytesDynamic (#623) * fix ci (#626) * implement self uups upgradeable (#592) * implement self uups upgradeable * small changes in identityVerificationHubImplV2 * delete aderyn.toml * chore: add custom verifier * chnage return output * feat: use self structs and a Generic output struct * feat: add userIdentifier, nullifier, forbiddencountries to returned output * add root view functions from registry * fix: build and compilation errors * add userDefined data into selfVerificationRoot * "resolve conflicts" * fix compilation problem * fix how to register verification config * test: CustomVerifier * fix verification root and hub integration * add scope check in hub impl * replace poseidon hash to ripemd+sha256 * add todo list * feat: refactor and add test cases for generic formatter * add performUserIdentifierCheck in basicVerification * change how to handle additionalData and fix stack too deep * start adding test codes * fix dependency problems in monorepo * fix: forbidden countries (#612) LGTM! * able to run test code * pass happy path * delete unused codes * change error code name, add caller address validation and add scripts to run test and build in monorepo * add all test cases in vcAndDisclose flow * remove comment out * chore: use actual user identifier outputs * success in registration tests * cover all cases * pass contractVersion instead of circuitVersion * fix disclose test * chore: add natspecs for ImplHubV2, CustomVerifier and GenericFormatter * change val name and remove unused lines * add val name change * remove userIdentifier from return data * feat: use GenericDiscloseOutput struct in verfication hook fix test cases for user identifier * chore: change the function order for Hub Impl V2 (#625) * fix nat specs * add nat spec in SelfStructs --------- Co-authored-by: Ayman <aymanshaik1015@gmail.com> Co-authored-by: Nesopie <87437291+Nesopie@users.noreply.github.com> * prettier (#629) * CAN auth - android (#613) * add missed files * add NFCMethodSelectionScreen * bump android build --------- Co-authored-by: Justin Hernandez <transphorm@gmail.com> * feat: add MRZ correction method to NFCMethodSelectionScreen (#627) * add npm auth token env (#632) * bump sdk version (#633) * publish npm package when merging on dev * bump common sdk version * replace yarn publish by npm publish * update common package version * Simplify dev mode gesture (#635) * Simplify developer mode gesture * Enable dev mode on MockData screen with five taps * add build smt function to common sdk * update vc_and_disclose_id test (dev branch) (#641) * fix: vc_and_disclose_id test * chore: yarn prettier * Show modal on NFC scan error (#642) * Add help button and error modal actions * fix the screen management * yarn nice * Bump build v2.5.4: ios 132; android 71 (#631) * bump version and build numbers * remove tamagui/toast * fix marketing version * fix: update TD1 and TD3 checks (#643) * bum yarn.lock * Bump build: ios 133; android 72 and build fixes (#654) * update gesture version and bump android build * bump and fix ios build * update lock files * fixes * fix fotoapparat library source * Update example contracts to include EUID usage (#656) * refactor: update HappyBirthday contract to V2 with support for E-Passport and EUID cards, introduce bonus multipliers, and enhance verification logic * refactor: update Airdrop contract to V2 with support for E-Passport and EU ID Card attestations * refactor: remove BASIS_POINTS constant from Airdrop contract * feat: introduce SelfIdentityERC721 contract for issuing NFTs based on verified identity credentials, replacing SelfPassportERC721 * fix: update verification functions in Airdrop, HappyBirthday, and SelfIdentityERC721 contracts to use customVerificationHook * cherry pick commit from add-test-self-verification... * block non-dev pr to main branch * audit fixes (#645) * merge dev branch into main (#624) * remove sdk/tests (#622) * remove sdk/tests * chore: update yarn.lock --------- Co-authored-by: Ayman <aymanshaik1015@gmail.com> * fix: add range check on paddedInLength of shaBytesDynamic (#623) * fix ci (#626) --------- Co-authored-by: Ayman <aymanshaik1015@gmail.com> Co-authored-by: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> * update contracts (#628) * remove sdk/tests (#622) * remove sdk/tests * chore: update yarn.lock --------- Co-authored-by: Ayman <aymanshaik1015@gmail.com> * fix: add range check on paddedInLength of shaBytesDynamic (#623) * fix ci (#626) * implement self uups upgradeable (#592) * implement self uups upgradeable * small changes in identityVerificationHubImplV2 * delete aderyn.toml * chore: add custom verifier * chnage return output * feat: use self structs and a Generic output struct * feat: add userIdentifier, nullifier, forbiddencountries to returned output * add root view functions from registry * fix: build and compilation errors * add userDefined data into selfVerificationRoot * "resolve conflicts" * fix compilation problem * fix how to register verification config * test: CustomVerifier * fix verification root and hub integration * add scope check in hub impl * replace poseidon hash to ripemd+sha256 * add todo list * feat: refactor and add test cases for generic formatter * add performUserIdentifierCheck in basicVerification * change how to handle additionalData and fix stack too deep * start adding test codes * fix dependency problems in monorepo * fix: forbidden countries (#612) LGTM! * able to run test code * pass happy path * delete unused codes * change error code name, add caller address validation and add scripts to run test and build in monorepo * add all test cases in vcAndDisclose flow * remove comment out * chore: use actual user identifier outputs * success in registration tests * cover all cases * pass contractVersion instead of circuitVersion * fix disclose test * chore: add natspecs for ImplHubV2, CustomVerifier and GenericFormatter * change val name and remove unused lines * add val name change * remove userIdentifier from return data * feat: use GenericDiscloseOutput struct in verfication hook fix test cases for user identifier * chore: change the function order for Hub Impl V2 (#625) * fix nat specs * add nat spec in SelfStructs --------- Co-authored-by: Ayman <aymanshaik1015@gmail.com> Co-authored-by: Nesopie <87437291+Nesopie@users.noreply.github.com> * prettier (#629) --------- Co-authored-by: Ayman <aymanshaik1015@gmail.com> Co-authored-by: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> Co-authored-by: nicoshark <i.am.nicoshark@gmail.com> Co-authored-by: Nesopie <87437291+Nesopie@users.noreply.github.com> * fix: vc_and_disclose_id test (#640) * fix: vc_and_disclose_id test * chore: yarn prettier * fix: check if a config id exists * chore: change the function where the config not set verification is happening * fix: add await * feat: add getConfigId function in SelfVerificationRoot (#650) * feat: add getConfigId function in SelfVerificationRoot * update comment --------- Co-authored-by: motemotech <i.am.nicoshark@gmail.com> * chore: fix ofac end index in eu id cards * chore: fix tests * fix: example contracts and tests --------- Co-authored-by: turnoffthiscomputer <98749896+remicolin@users.noreply.github.com> Co-authored-by: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> Co-authored-by: nicoshark <i.am.nicoshark@gmail.com> * Update deployment module for Identity Verification Hub V2 with detailed documentation and library linkage for CustomVerifier. Update initialization process to reflect changes in V2 implementation, ensuring proper setup for proxy deployment. (#658) * publish npm-package (#651) * App/eu id updates (#638) * fix build issues * generate disclosure proof with euids * generate disclosure proof with euids * Eu id updates 2 (#648) * update vc_and_disclose_id test (dev branch) (#641) * fix: vc_and_disclose_id test * chore: yarn prettier * Show modal on NFC scan error (#642) * Add help button and error modal actions * fix the screen management * yarn nice * Bump build v2.5.4: ios 132; android 71 (#631) * bump version and build numbers * remove tamagui/toast * fix marketing version * fix: update TD1 and TD3 checks (#643) * bum yarn.lock * add version and user defined data --------- Co-authored-by: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz> Co-authored-by: Seshanth.S🐺 <35675963+seshanthS@users.noreply.github.com> * remove the mock user define data * get the useridentifier as a hash from the user defined data * chore: add version and userDefinedData * feat: use the version in register / dsc proofs as well * update calculateUserIdentifierHash * yarn nice * refactor: consolidate user context data handling and update payload structure * fix typing issues on sha1 * remove console.log(sha1) * fix sha1 import * refactor: streamline userDefinedData handling and adjust payload type for circuit * refactor: update sha1 usage and enhance logging in calculateUserIdentifierHash * yarn nice * yarn lint common * use ts-ignore for sha1 import * fix app ci tests * fix typing issue * remove unused ts-ignore * cast uuid before calling generateinputs * bump qrcode version * add tsup on the qrcode sdk * fix: exports on selfxyz/qrcode * update how we define config.version * fix yarn imports * yarn format --------- Co-authored-by: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz> Co-authored-by: Seshanth.S🐺 <35675963+seshanthS@users.noreply.github.com> Co-authored-by: Ayman <aymanshaik1015@gmail.com> * Hotfix contract compile error (#660) * Fix previous rebase error * Refactor deployment module for Identity Verification Hub V2. * Fix/sdk (#652) * fix: sdk build configs * chore: SelfBackendVerifier (WIP) * feat: add custom verification * feat: consider destination chain in user defined data * chore: export attestation id * chore: export attestation id * chore: export config storage * chore: don't throw an error if the proof is not valid * chore: trim abi and rm typechain types * refactor * chore: rm unnecessary exports * 📝 Add docstrings to `fix/sdk` (#653) Docstrings generation was requested by @remicolin. * https://github.com/selfxyz/self/pull/652#issuecomment-2992046545 The following files were modified: * `sdk/core/src/utils/hash.ts` * `sdk/core/src/utils/proof.ts` * `sdk/core/src/utils/utils.ts` Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * review fixes * chore: fix package.json cjs types * chore: add minor changes to checks * feat: add InMemoryConfigStore, allIds constant and verificationResult type * chore: export Verification config * feat: change the verification config types * fix: throw issues early if verification config is null * fix: update yarn.lock file * chore: lint * fix: rm ts expect error directive * fix: contract tests * use excluded countries instead forbidden countries list * chore: change types in constnats --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update npm-publish workflow and bump core package version to 1.0.0 (#661) * update import * Update get verification config visibility (#664) * Update deployment module for Identity Verification Hub V2 to correct file paths and module name for deployment commands. * Add troubleshooting documentation for verification issues in deployHubV2.ts. Include manual verification steps and common failure reasons to assist users during deployment. * Change visibility of getVerificationConfigV2 function from internal to public in IdentityVerificationHubImplV2 contract to allow external access. * Apply BUSL v1.1 license headers to app (#665) * Add BSL license headers to app sources * prettier * fix license reference - https://spdx.org/licenses/BUSL-1.1.html * bump build: android 73 (#659) * Contracts/deploy staging (#668) * update scripts * deploy vc and disclose id * fix the deployment scripts on staging * update yarn.lock * bump ios build and version (#669) * configure coderabbitai (#670) * tweak coderabbit * bump * more thorough test spec * Apply BSL to app codebase (#639) * Clean up root license wording * Simplify SPDX header * simplify license and rename BSL to BUSL * fix merge issues * fix missing method --------- Co-authored-by: Justin Hernandez <transphorm@gmail.com> * SEL-423 apply xcode build suggestions (#671) * apply recommended app settings from xcode * stick to portrait orientation and update target settings * remove app clip references * Circuit audit fixes (#644) * feat: add range checks before use of LessEqThan and SelectSubArray * fix: Num2Bits_strict to constrain virtualKey * bump core version * bump core version and fix ci * chore: use npm_auth_token in yarnrc * chroe: rm yarnrc changes * chore: update npm publish * chore: run npm publish manually * chore: change hub contract address (#675) * Update npm-publish.yml * chore: use proper secret when publishing * feat: enable publishing if workflow was triggered manually * Contracts/update verifier (#673) * update hardhat config * update vc and disclose verifier * update vc and disclose verifier script and run it * update test self verification root * update verifier * bump sdk version and use new hub address * chore: update zk-kit binary merkle root dep (#674) * refactor deployment scripts (#678) * feat: add register eu id instances (#682) * feat: add register eu id instances * feat: add new instances * chore: update scripts * chore: fix sig alg * chore: rm circuits --------- Co-authored-by: Ayman <aymanshaik1015@gmail.com> Co-authored-by: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> Co-authored-by: nicoshark <i.am.nicoshark@gmail.com> Co-authored-by: Nesopie <87437291+Nesopie@users.noreply.github.com> Co-authored-by: Seshanth.S🐺 <35675963+seshanthS@users.noreply.github.com> Co-authored-by: Justin Hernandez <transphorm@gmail.com> Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz> Co-authored-by: Kevin Lin <86810837+kevinsslin@users.noreply.github.com> Co-authored-by: kevinsslin <kk123750964@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Eric Nakagawa <ericnakagawa@gmail.com> * fix: commitment hash * fix: register aadhaar test * chore: refactor * feat: reveal data in packed bytes * feat: add constrain on delimiterIndices * feat: reveal timestamp * merge main to feat/aadhaar * fix: tests * feat: hash pubKey * feat: add registry contract * feat: Update HubImplV2 (WIP) * add functions to generate aadhaar data (WIP) * modularize aadhaar data generation (WIP) * fix(wip): register test * fix: test qr extractor * fix * chore: refactor functions * feat: add age extractor and tested * feat: add isMiniumAge check * fix: prepareAadhaarTestData func * registry contract tests * feat: registry contract tests * feat: extract fields from qr data bytes * chore: refactor mockData * feat: move minimum age to revealPackedData * feat: create a constant.ts to retrive fields from unpacked bytes * chore: refactor * fix: exports * rebase * rebase * feat: add public signal ,indices mapping * chore: add public output to indices mapping * fix:AADHAAR_PUBLIC_SIGNAL_INDICES * feat: make nullifier public * fix: nullifier cal for disclose circuits * feat: merge isMiniumAgeValid and miniumAge signal * fix: disclsoe test * feat: support for user identifier and secret * chore :refactor * feat: ofac test last name , firstname * feat: add forbidden_countries_list check * feat: add tests for aadhaar (WIP) * failing ofac tests * feat: finish contract tests * fix: merge conflicts * update the common package to be usable in circuits and contracts * lint everything * coderabbit fixes * chore: update name dob,yob aadhaar ofac tree * feat: merge ofac and reverse ofac check into one * test: merged ofac constrain * SELF-253 feat: add user email feedback (#889) * feat: add sentry feedback * add sentry feedback to web * feat: add custom feedback modal & fix freeze on IOS * yarn nice * update lock * feat: show feedback widget on NFC scan issues (#948) * feat: show feedback widget on NFC scan issues * fix ref * clean up * fix report issue screen * abstract send user feedback email logic * fixes * change text to Report Issue * sanitize email and track event messge * remove unnecessary sanitization * add sanitize error message tests * fix tests * save wip. almost done * fix screen test * fix screen test * remove non working test --------- Co-authored-by: Justin Hernandez <transphorm@gmail.com> Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz> * 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 * update unsupported passport screen (#953) * update unsupported passport screen * yarn nice * feat: support new ofac trees * fix: qr extractor tests * chore: remove unassigned age signal * chore: modify timestamp func comment * fix: add constrain on photo bytes delimiter * fix: add range check on minimumAge within 2^7 * fix: range check for country not in list * chore: remove dummy constrain * fix: assert lessthan * fix: check is photoEOI valid * fix: replace maxDataLength with qrPaddedLength for valid del indices * feat: update forbidden countries in disclose and disclose id * feat: convert name to uppercase * fix: add constrain between delimiter and photoEOI * feat: support for phno len 4 and 10 * chore: hard-code attestaion_ID to 3 * feat: calculate nullifier using uppercase name * feat: add real id support * fix: rebase error * chore: refactor * add new nullifier and commitment calc * fix: reuse uppercase name from verify commitment * feat: add a function that will iterate though all pubkeys * chore: skip real id test * chore: yarn format * chore: update yarn.lock * chore: rm trailing / from import * chore: add support for issuing state * chore: linting and types * chore: rm types script from circuits * chore: add license header --------- Co-authored-by: nicoshark <i.am.nicoshark@gmail.com> Co-authored-by: turnoffthiscomputer <98749896+remicolin@users.noreply.github.com> Co-authored-by: Seshanth.S🐺 <35675963+seshanthS@users.noreply.github.com> Co-authored-by: turboblitz <florent.tavernier@gmail.com> Co-authored-by: Justin Hernandez <transphorm@gmail.com> Co-authored-by: crStiv <cryptostiv7@gmail.com> Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz> Co-authored-by: James Niken <danylonepritvoreniy@gmail.com> Co-authored-by: Kevin Lin <86810837+kevinsslin@users.noreply.github.com> Co-authored-by: leopardracer <136604165+leopardracer@users.noreply.github.com> Co-authored-by: Olof Andersson <olof.andersson@gmail.com> Co-authored-by: vishal <vishalkoolkarni0045@gmail.com> Co-authored-by: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> Co-authored-by: kevinsslin <kk123750964@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Eric Nakagawa <ericnakagawa@gmail.com>
This commit is contained in:
@@ -9,3 +9,4 @@ IS_TEST_BUILD=
|
||||
MIXPANEL_NFC_PROJECT_TOKEN=
|
||||
SEGMENT_KEY=
|
||||
SENTRY_DSN=
|
||||
IS_TEST_BUILD=
|
||||
|
||||
@@ -91,7 +91,6 @@ class CameraViewController: UIViewController, AVCaptureVideoDataOutputSampleBuff
|
||||
let minY = visibleRect.minY
|
||||
let boxY = max(minY, min(maxY - boxHeight, maxY - boxHeight))
|
||||
// let boxY = visibleRect.maxY - boxHeight
|
||||
|
||||
return CGRect(x: boxX, y: boxY, width: boxWidth, height: boxHeight)
|
||||
}
|
||||
|
||||
@@ -99,13 +98,11 @@ class CameraViewController: UIViewController, AVCaptureVideoDataOutputSampleBuff
|
||||
guard let previewLayer = previewLayer else { return .zero }
|
||||
let videoRect = previewLayer.layerRectConverted(fromMetadataOutputRect: CGRect(x: 0, y: 0, width: 1, height: 1))
|
||||
let greenBox = calculateGreenBoxFrame()
|
||||
|
||||
// map greenBox to normalized coordinates within videoRect
|
||||
let normX = (greenBox.minX - videoRect.minX) / videoRect.width
|
||||
let normY = (greenBox.minY - videoRect.minY) / videoRect.height
|
||||
let normWidth = greenBox.width / videoRect.width
|
||||
let normHeight = greenBox.height / videoRect.height
|
||||
|
||||
// Ensure normalized coordinates are within [0,1] bounds as vision's max ROI is (0,0) to (1,1)
|
||||
let clampedX = max(0, min(1, normX))
|
||||
let clampedY = max(0, min(1, normY))
|
||||
|
||||
@@ -17,7 +17,6 @@ struct MRZScanner {
|
||||
if let error = error {
|
||||
print("Vision error: \(error)")
|
||||
}
|
||||
|
||||
guard let observations = request.results as? [VNRecognizedTextObservation] else {
|
||||
print("No text observations found")
|
||||
completion("No text found", [])
|
||||
@@ -47,7 +46,6 @@ struct MRZScanner {
|
||||
// print("Matched MRZ pattern: \(text)")
|
||||
mrzLines.append(text)
|
||||
boxes.append(obs.boundingBox)
|
||||
|
||||
// Check if we have a complete MRZ
|
||||
if (mrzLines.count == 2 && mrzLines.allSatisfy { $0.count == 44 }) || // TD3 - passport
|
||||
(mrzLines.count == 3 && mrzLines.allSatisfy { $0.count == 30 }) { // TD1 - ID card
|
||||
|
||||
@@ -152,7 +152,6 @@ const items = [
|
||||
'DocumentCameraTrouble',
|
||||
'DocumentNFCTrouble',
|
||||
] satisfies (keyof RootStackParamList)[];
|
||||
|
||||
const ScreenSelector = ({}) => {
|
||||
const navigation = useNavigation();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
23
app/src/stores/databaseProvider.tsx
Normal file
23
app/src/stores/databaseProvider.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
|
||||
|
||||
import React, { createContext, useEffect } from 'react';
|
||||
|
||||
import { useProofHistoryStore } from '@/stores/proofHistoryStore';
|
||||
|
||||
export const DatabaseContext = createContext(null);
|
||||
|
||||
export const DatabaseProvider: React.FC<{ children: React.ReactNode }> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { initDatabase } = useProofHistoryStore();
|
||||
|
||||
useEffect(() => {
|
||||
initDatabase();
|
||||
}, [initDatabase]);
|
||||
|
||||
return (
|
||||
<DatabaseContext.Provider value={null}>{children}</DatabaseContext.Provider>
|
||||
);
|
||||
};
|
||||
215
circuits/circuits/disclose/vc_and_disclose_aadhaar.circom
Normal file
215
circuits/circuits/disclose/vc_and_disclose_aadhaar.circom
Normal file
@@ -0,0 +1,215 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "circomlib/circuits/bitify.circom";
|
||||
include "circomlib/circuits/comparators.circom";
|
||||
include "../utils/aadhaar/disclose/verify_commitment.circom";
|
||||
include "@openpassport/zk-email-circuits/utils/bytes.circom";
|
||||
include "../utils/aadhaar/extractQrData.circom";
|
||||
include "../utils/aadhaar/ofac/ofac_name_dob.circom";
|
||||
include "../utils/aadhaar/ofac/ofac_name_yob.circom";
|
||||
include "../utils/aadhaar/disclose/country_not_in_list.circom";
|
||||
|
||||
/// @title VC_AND_DISCLOSE_Aadhaar
|
||||
/// @notice Verify user's commitment is part of the merkle tree and optionally disclose data from Aadhaar
|
||||
/// @param nLevels Maximum number of levels in the merkle tree
|
||||
/// @param namedobTreeLevels Maximum number of levels in the name-dob SMT tree
|
||||
/// @param nameyobTreeLevels Maximum number of levels in the name-yob SMT tree
|
||||
/// @input attestation_id Attestation ID of the credential used to generate the commitment
|
||||
/// @input secret Secret of the user — used to reconstruct commitment
|
||||
/// @input qrDataHash Hash of the QR data
|
||||
/// @input gender Gender of the user
|
||||
/// @input yob Year of birth
|
||||
/// @input mob Month of birth
|
||||
/// @input dob Day of birth
|
||||
/// @input name[2] Name of the user (packed into 2 field elements)
|
||||
/// @input aadhaar_last_4digits Last 4 digits of Aadhaar number
|
||||
/// @input pincode Pincode of user's address
|
||||
/// @input state State(PackedBytes) of user's address
|
||||
/// @input ph_no_last_4digits Last 4 digits of phone number
|
||||
/// @input photoHash Hash of user's photo
|
||||
/// @input ofac_name_dob_smt_leaf_key Leaf key for name-DOB SMT verification
|
||||
/// @input ofac_name_dob_smt_root Root of name-DOB SMT
|
||||
/// @input ofac_name_dob_smt_siblings Siblings for name-DOB SMT proof
|
||||
/// @input ofac_name_yob_smt_leaf_key Leaf key for name-YOB SMT verification
|
||||
/// @input ofac_name_yob_smt_root Root of name-YOB SMT
|
||||
/// @input ofac_name_yob_smt_siblings Siblings for name-YOB SMT proof
|
||||
/// @input merkle_root Root of the commitment merkle tree
|
||||
/// @input leaf_depth Actual size of the merkle tree
|
||||
/// @input path Path of the commitment in the merkle tree
|
||||
/// @input siblings Siblings of the commitment in the merkle tree
|
||||
/// @input selector Bitmap indicating which fields to reveal
|
||||
template VC_AND_DISCLOSE_Aadhaar(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH,nLevels, namedobTreeLevels, nameyobTreeLevels){
|
||||
signal input attestation_id;
|
||||
signal input secret;
|
||||
signal input qrDataHash;
|
||||
signal input gender;
|
||||
signal input yob[4];
|
||||
signal input mob[2];
|
||||
signal input dob[2];
|
||||
signal input name[nameMaxLength()];
|
||||
signal input aadhaar_last_4digits[4];
|
||||
signal input pincode[6];
|
||||
signal input state[maxFieldByteSize()];
|
||||
signal input ph_no_last_4digits[4];
|
||||
signal input photoHash;
|
||||
|
||||
signal input minimumAge;
|
||||
signal input currentYear;
|
||||
signal input currentMonth;
|
||||
signal input currentDay;
|
||||
|
||||
signal input ofac_name_dob_smt_leaf_key;
|
||||
signal input ofac_name_dob_smt_root;
|
||||
signal input ofac_name_dob_smt_siblings[namedobTreeLevels];
|
||||
|
||||
|
||||
signal input ofac_name_yob_smt_leaf_key;
|
||||
signal input ofac_name_yob_smt_root;
|
||||
signal input ofac_name_yob_smt_siblings[nameyobTreeLevels];
|
||||
|
||||
signal input merkle_root;
|
||||
signal input leaf_depth;
|
||||
signal input path[nLevels];
|
||||
signal input siblings[nLevels];
|
||||
|
||||
signal input selector;
|
||||
signal input scope;
|
||||
signal input user_identifier;
|
||||
|
||||
signal input forbidden_countries_list[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3];
|
||||
// convert selector to 119 bits which acts as a bitmap for the fields to reveal
|
||||
signal sel_bits[119] <== Num2Bits(119)(selector);
|
||||
|
||||
signal output nullifier <== Poseidon(2)([secret, scope]);
|
||||
|
||||
// verify commitment is part of the merkle tree
|
||||
signal uppercase_name[nameMaxLength()] <== VERIFY_COMMITMENT(nLevels)(
|
||||
attestation_id,
|
||||
secret,
|
||||
qrDataHash,
|
||||
gender,
|
||||
yob,
|
||||
mob,
|
||||
dob,
|
||||
name,
|
||||
aadhaar_last_4digits,
|
||||
pincode,
|
||||
state,
|
||||
ph_no_last_4digits,
|
||||
photoHash,
|
||||
merkle_root,
|
||||
leaf_depth,
|
||||
path,
|
||||
siblings
|
||||
);
|
||||
|
||||
signal name_packed[2] <== PackBytes(nameMaxLength())(uppercase_name);
|
||||
signal yob_integer <== DigitBytesToInt(4)(yob);
|
||||
signal mob_integer <== DigitBytesToInt(2)(mob);
|
||||
signal dob_integer <== DigitBytesToInt(2)(dob);
|
||||
|
||||
// verify name-DOB in OFAC list
|
||||
component ofac_name_dob = OFAC_NAME_DOB_AADHAAR(namedobTreeLevels);
|
||||
ofac_name_dob.name <== name_packed;
|
||||
ofac_name_dob.YOB <== yob_integer;
|
||||
ofac_name_dob.MOB <== mob_integer;
|
||||
ofac_name_dob.DOB <== dob_integer;
|
||||
ofac_name_dob.smt_leaf_key <== ofac_name_dob_smt_leaf_key;
|
||||
ofac_name_dob.smt_root <== ofac_name_dob_smt_root;
|
||||
ofac_name_dob.smt_siblings <== ofac_name_dob_smt_siblings;
|
||||
|
||||
// verify name-YOB in OFAC list
|
||||
component ofac_name_yob = OFAC_NAME_YOB_AADHAAR(nameyobTreeLevels);
|
||||
ofac_name_yob.name <== name_packed;
|
||||
ofac_name_yob.YOB <== yob_integer;
|
||||
ofac_name_yob.smt_leaf_key <== ofac_name_yob_smt_leaf_key;
|
||||
ofac_name_yob.smt_root <== ofac_name_yob_smt_root;
|
||||
ofac_name_yob.smt_siblings <== ofac_name_yob_smt_siblings;
|
||||
|
||||
//Range-check for minimumAge
|
||||
component range_check_minimumAge = Num2Bits(7);
|
||||
range_check_minimumAge.in <== minimumAge;
|
||||
|
||||
// verify age is greater than minimum age
|
||||
signal age <== AgeExtractor()(yob, mob, dob, currentYear, currentMonth, currentDay);
|
||||
|
||||
signal isAgeGreaterThanMinimumAge <== GreaterEqThan(7)([age, minimumAge]);
|
||||
|
||||
signal isMinimumAgeValid <== isAgeGreaterThanMinimumAge * minimumAge ;
|
||||
|
||||
// reveal fields based on selector
|
||||
|
||||
signal revealData[119];
|
||||
revealData[0] <== gender * sel_bits[0];
|
||||
|
||||
|
||||
for (var i = 0; i < 4; i++){
|
||||
revealData[i + 1] <== yob[i] * sel_bits[i + 1];
|
||||
}
|
||||
|
||||
|
||||
for (var i = 0; i < 2; i++){
|
||||
revealData[i + 5] <== mob[i] * sel_bits[i + 5];
|
||||
}
|
||||
|
||||
|
||||
for (var i = 0; i < 2; i++){
|
||||
revealData[i + 7] <== dob[i] * sel_bits[i + 7];
|
||||
}
|
||||
|
||||
for (var i = 0; i < nameMaxLength(); i++){
|
||||
revealData[i + 9] <== name[i] * sel_bits[i + 9];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4; i++){
|
||||
revealData[i + 71] <== aadhaar_last_4digits[i] * sel_bits[i + 71];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 6; i++){
|
||||
revealData[i + 75] <== pincode[i] * sel_bits[i + 75];
|
||||
}
|
||||
|
||||
for (var i = 0; i < maxFieldByteSize(); i++){
|
||||
revealData[i + 81] <== state[i] * sel_bits[i + 81];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4; i++){
|
||||
revealData[i + 112] <== ph_no_last_4digits[i] * sel_bits[i + 112];
|
||||
}
|
||||
|
||||
signal output reveal_photoHash <== photoHash * sel_bits[116];
|
||||
|
||||
revealData[116] <== ofac_name_dob.ofacCheckResult * sel_bits[117];
|
||||
revealData[117] <== ofac_name_yob.ofacCheckResult * sel_bits[118];
|
||||
revealData[118] <== isMinimumAgeValid;
|
||||
|
||||
var revealed_data_packed_chunk_length = computeIntChunkLength(119);
|
||||
signal output revealData_packed[revealed_data_packed_chunk_length] <== PackBytes(119)(revealData);
|
||||
|
||||
component country_not_in_list_circuit = CountryNotInList(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH);
|
||||
|
||||
country_not_in_list_circuit.country[0] <== 73;
|
||||
country_not_in_list_circuit.country[1] <== 78;
|
||||
country_not_in_list_circuit.country[2] <== 68;
|
||||
|
||||
country_not_in_list_circuit.forbidden_countries_list <== forbidden_countries_list;
|
||||
|
||||
var chunkLength = computeIntChunkLength(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3);
|
||||
signal output forbidden_countries_list_packed[chunkLength] <== country_not_in_list_circuit.forbidden_countries_list_packed;
|
||||
|
||||
attestation_id === 3;
|
||||
}
|
||||
|
||||
component main { public
|
||||
[
|
||||
attestation_id,
|
||||
currentYear,
|
||||
currentMonth,
|
||||
currentDay,
|
||||
ofac_name_dob_smt_root,
|
||||
ofac_name_yob_smt_root,
|
||||
merkle_root,
|
||||
scope,
|
||||
user_identifier
|
||||
]
|
||||
} = VC_AND_DISCLOSE_Aadhaar(40, 33, 64, 64);
|
||||
@@ -0,0 +1,4 @@
|
||||
pragma circom 2.1.9;
|
||||
include "../register_aadhaar.circom";
|
||||
|
||||
component main = REGISTER_AADHAAR(121, 17, 512 * 3);
|
||||
148
circuits/circuits/register/register_aadhaar.circom
Normal file
148
circuits/circuits/register/register_aadhaar.circom
Normal file
@@ -0,0 +1,148 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "circomlib/circuits/bitify.circom";
|
||||
include "circomlib/circuits/poseidon.circom";
|
||||
include "../utils/aadhaar/extractQrData.circom";
|
||||
include "../utils/passport/signatureVerifier.circom";
|
||||
include "../utils/passport/customHashers.circom";
|
||||
include "@openpassport/zk-email-circuits/utils/array.circom";
|
||||
include "@openpassport/zk-email-circuits/lib/sha.circom";
|
||||
|
||||
|
||||
/// @title: AadhaarRegister
|
||||
/// @notice Main circuit — verifies the integrity of the aadhaar data, the signature, and generates commitment and nullifier
|
||||
/// @param n RSA pubic key size per chunk
|
||||
/// @param k Number of chunks the RSA public key is split into
|
||||
/// @param maxDataLength Maximum length of the data
|
||||
/// @input qrDataPadded QR data without the signature; assumes elements to be bytes; remaining space is padded with 0
|
||||
/// @input qrDataPaddedLength Length of padded QR data
|
||||
/// @input delimiterIndices Indices of delimiters (255) in the QR text data. 18 delimiters including photo
|
||||
/// @input signature RSA signature split into k chunks of n bits each
|
||||
/// @input pubKey RSA public key(of the government) split into k chunks of n bits each
|
||||
/// @input secret Secret for commitment generation. Saved by the user to access their commitment
|
||||
/// @input attestation_id Attestation ID of the credential used to generate the commitment
|
||||
/// @output nullifier Generated nullifier - deterministic on the Aadhaar data
|
||||
/// @output commitment Commitment that will be added to the onchain registration tree
|
||||
/// @output pubKeyHash Hash of the public key
|
||||
/// @output timestamp Timestamp of the QR data
|
||||
template REGISTER_AADHAAR(n, k, maxDataLength){
|
||||
signal input qrDataPadded[maxDataLength];
|
||||
signal input qrDataPaddedLength;
|
||||
signal input delimiterIndices[18];
|
||||
signal input pubKey[k];
|
||||
signal input signature[k];
|
||||
|
||||
signal input secret;
|
||||
signal input photoEOI;
|
||||
|
||||
signal attestation_id <== 3;
|
||||
|
||||
|
||||
// Assert `qrDataPaddedLength` fits in `ceil(log2(maxDataLength))`
|
||||
component n2bHeaderLength = Num2Bits(log2Ceil(maxDataLength));
|
||||
n2bHeaderLength.in <== qrDataPaddedLength;
|
||||
|
||||
// Hash the data
|
||||
component shaHasher = Sha256Bytes(maxDataLength);
|
||||
shaHasher.paddedIn <== qrDataPadded;
|
||||
shaHasher.paddedInLength <== qrDataPaddedLength;
|
||||
|
||||
// Verify the RSA signature
|
||||
component signatureVerifier = SignatureVerifier(1, n, k);
|
||||
signatureVerifier.hash <== shaHasher.out;
|
||||
signatureVerifier.pubKey <== pubKey;
|
||||
signatureVerifier.signature <== signature;
|
||||
|
||||
// Assert data between qrDataPaddedLength and maxDataLength is zero
|
||||
AssertZeroPadding(maxDataLength)(qrDataPadded, qrDataPaddedLength);
|
||||
|
||||
// Extract data from QR data
|
||||
component qrDataExtractor = EXTRACT_QR_DATA(maxDataLength);
|
||||
qrDataExtractor.data <== qrDataPadded;
|
||||
qrDataExtractor.qrDataPaddedLength <== qrDataPaddedLength;
|
||||
qrDataExtractor.delimiterIndices <== delimiterIndices;
|
||||
qrDataExtractor.photoEOI <== photoEOI;
|
||||
|
||||
//convert name lowercase to uppercase
|
||||
//value >= 97 AND value <= 122
|
||||
component is_gt_97[nameMaxLength()];
|
||||
component is_lt_122[nameMaxLength()];
|
||||
signal uppercase_name[nameMaxLength()];
|
||||
signal is_lowercase[nameMaxLength()];
|
||||
|
||||
for (var i = 0; i < nameMaxLength(); i++){
|
||||
is_gt_97[i] = GreaterEqThan(8);
|
||||
is_gt_97[i].in[0] <== qrDataExtractor.name[i];
|
||||
is_gt_97[i].in[1] <== 97;
|
||||
|
||||
is_lt_122[i] = LessEqThan(8);
|
||||
is_lt_122[i].in[0] <== qrDataExtractor.name[i];
|
||||
is_lt_122[i].in[1] <== 122;
|
||||
|
||||
is_lowercase[i] <== is_gt_97[i].out * is_lt_122[i].out;
|
||||
|
||||
uppercase_name[i] <== qrDataExtractor.name[i] - 32 * is_lowercase[i];
|
||||
}
|
||||
|
||||
signal output pubKeyHash <== CustomHasher(k)(pubKey);
|
||||
|
||||
//Calculate nullifier
|
||||
component nullifierHasher = PackBytesAndPoseidon(75);
|
||||
nullifierHasher.in[0] <== qrDataExtractor.gender;
|
||||
|
||||
for (var i = 0; i < 4 ; i++){
|
||||
nullifierHasher.in[i + 1] <== qrDataExtractor.yob[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 2 ; i++){
|
||||
nullifierHasher.in[i + 5] <== qrDataExtractor.mob[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 2 ; i++){
|
||||
nullifierHasher.in[i + 7] <== qrDataExtractor.dob[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 62 ; i++){
|
||||
nullifierHasher.in[i + 9] <== uppercase_name[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4 ; i++){
|
||||
nullifierHasher.in[i + 71] <== qrDataExtractor.aadhaar_last_4digits[i];
|
||||
}
|
||||
|
||||
signal output nullifier <== nullifierHasher.out;
|
||||
|
||||
|
||||
signal qrDataHash <== PackBytesAndPoseidon(maxDataLength)(qrDataPadded);
|
||||
|
||||
// Generate commitment
|
||||
component packedCommitment = PackBytesAndPoseidon(42 + 62);
|
||||
packedCommitment.in[0] <== attestation_id;
|
||||
|
||||
for (var i = 0; i < 6 ; i++){
|
||||
packedCommitment.in[i + 1] <== qrDataExtractor.pincode[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < maxFieldByteSize() ; i++){
|
||||
packedCommitment.in[i + 7] <== qrDataExtractor.state[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4 ; i++){
|
||||
packedCommitment.in[i + 38] <== qrDataExtractor.ph_no_last_4digits[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 62 ; i++){
|
||||
packedCommitment.in[i + 42] <== qrDataExtractor.name[i];
|
||||
}
|
||||
|
||||
component commitmentHasher = Poseidon(5);
|
||||
|
||||
commitmentHasher.inputs[0] <== secret;
|
||||
commitmentHasher.inputs[1] <== qrDataHash;
|
||||
commitmentHasher.inputs[2] <== nullifierHasher.out;
|
||||
commitmentHasher.inputs[3] <== packedCommitment.out;
|
||||
commitmentHasher.inputs[4] <== qrDataExtractor.photoHash;
|
||||
|
||||
signal output commitment <== commitmentHasher.out;
|
||||
signal output timestamp <== qrDataExtractor.timestamp;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "../../utils/aadhaar/extractQrData.circom";
|
||||
|
||||
component main = EXTRACT_QR_DATA(512 * 3);
|
||||
@@ -0,0 +1,32 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "circomlib/circuits/comparators.circom";
|
||||
include "@openpassport/zk-email-circuits/utils/bytes.circom";
|
||||
|
||||
/// @notice CountryNotInList template — used to prove that the user is not from a list of forbidden countries
|
||||
/// @param MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH Maximum number of countries present in the forbidden countries list
|
||||
/// @input country Country of the user
|
||||
/// @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 CountryNotInList(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH) {
|
||||
signal input country[3];
|
||||
signal input forbidden_countries_list[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3];
|
||||
|
||||
//Range-check for forbidden_countries_list
|
||||
AssertBytes(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3)(forbidden_countries_list);
|
||||
|
||||
signal equality_result[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH][4];
|
||||
signal is_equal[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH][3];
|
||||
for (var i = 0; i < MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH; i++) {
|
||||
equality_result[i][0] <== 1;
|
||||
for (var j = 1; j < 3 + 1; j++) {
|
||||
is_equal[i][j - 1] <== IsEqual()([country[j - 1], forbidden_countries_list[i * 3 + j - 1]]);
|
||||
equality_result[i][j] <== is_equal[i][j - 1] * equality_result[i][j - 1];
|
||||
}
|
||||
0 === equality_result[i][3];
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "@openpassport/zk-email-circuits/utils/bytes.circom";
|
||||
include "@zk-kit/binary-merkle-root.circom/src/binary-merkle-root.circom";
|
||||
include "circomlib/circuits/poseidon.circom";
|
||||
include "../../passport/customHashers.circom";
|
||||
include "../extractQrData.circom";
|
||||
|
||||
/// @notice VerifyCommitment template — verifies user's commitment is included in the merkle tree
|
||||
/// @param nLevels Maximum size of the merkle tree
|
||||
/// @input secret Secret for commitment generation
|
||||
/// @input attestation_id Attestation ID
|
||||
/// @input merkle_root Root of the commitment merkle tree
|
||||
/// @input merkletree_size Actual size of the merkle tree
|
||||
/// @input path Path to the user's commitment in the merkle tree
|
||||
/// @input siblings Siblings of the user's commitment in the merkle tree
|
||||
template VERIFY_COMMITMENT(nLevels) {
|
||||
signal input attestation_id;
|
||||
signal input secret;
|
||||
signal input qrDataHash;
|
||||
signal input gender;
|
||||
signal input yob[4];
|
||||
signal input mob[2];
|
||||
signal input dob[2];
|
||||
signal input name[nameMaxLength()];
|
||||
signal input aadhaar_last_4digits[4];
|
||||
signal input pincode[6];
|
||||
signal input state[maxFieldByteSize()];
|
||||
signal input ph_no_last_4digits[4];
|
||||
signal input photoHash;
|
||||
|
||||
signal input merkle_root;
|
||||
signal input merkletree_size;
|
||||
signal input path[nLevels];
|
||||
signal input siblings[nLevels];
|
||||
|
||||
|
||||
component is_gt_97[nameMaxLength()];
|
||||
component is_lt_122[nameMaxLength()];
|
||||
signal output uppercase_name[nameMaxLength()];
|
||||
signal is_lowercase[nameMaxLength()];
|
||||
|
||||
for (var i = 0; i < nameMaxLength(); i++){
|
||||
is_gt_97[i] = GreaterEqThan(8);
|
||||
is_gt_97[i].in[0] <== name[i];
|
||||
is_gt_97[i].in[1] <== 97;
|
||||
|
||||
is_lt_122[i] = LessEqThan(8);
|
||||
is_lt_122[i].in[0] <== name[i];
|
||||
is_lt_122[i].in[1] <== 122;
|
||||
|
||||
is_lowercase[i] <== is_gt_97[i].out * is_lt_122[i].out;
|
||||
|
||||
uppercase_name[i] <== name[i] - 32 * is_lowercase[i];
|
||||
}
|
||||
|
||||
component nullifierHasher = PackBytesAndPoseidon(75);
|
||||
nullifierHasher.in[0] <== gender;
|
||||
|
||||
for (var i = 0; i < 4 ; i++){
|
||||
nullifierHasher.in[i + 1] <== yob[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 2 ; i++){
|
||||
nullifierHasher.in[i + 5] <== mob[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 2 ; i++){
|
||||
nullifierHasher.in[i + 7] <== dob[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 62 ; i++){
|
||||
nullifierHasher.in[i + 9] <== uppercase_name[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4 ; i++){
|
||||
nullifierHasher.in[i + 71] <== aadhaar_last_4digits[i];
|
||||
}
|
||||
|
||||
signal nullifier <== nullifierHasher.out;
|
||||
|
||||
component packedCommitment = PackBytesAndPoseidon(42 + 62);
|
||||
packedCommitment.in[0] <== attestation_id;
|
||||
|
||||
for (var i = 0; i < 6 ; i++){
|
||||
packedCommitment.in[i + 1] <== pincode[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < maxFieldByteSize() ; i++){
|
||||
packedCommitment.in[i + 7] <== state[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4 ; i++){
|
||||
packedCommitment.in[i + 38] <== ph_no_last_4digits[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 62 ; i++){
|
||||
packedCommitment.in[i + 42] <== name[i];
|
||||
}
|
||||
|
||||
component commitmentHasher = Poseidon(5);
|
||||
commitmentHasher.inputs[0] <== secret;
|
||||
commitmentHasher.inputs[1] <== qrDataHash;
|
||||
commitmentHasher.inputs[2] <== nullifier;
|
||||
commitmentHasher.inputs[3] <== packedCommitment.out;
|
||||
commitmentHasher.inputs[4] <== photoHash;
|
||||
|
||||
signal commitment <== commitmentHasher.out;
|
||||
|
||||
// Verify commitment inclusion
|
||||
signal computedRoot <== BinaryMerkleRoot(nLevels)(commitment, merkletree_size, path, siblings);
|
||||
merkle_root === computedRoot;
|
||||
}
|
||||
517
circuits/circuits/utils/aadhaar/extractQrData.circom
Normal file
517
circuits/circuits/utils/aadhaar/extractQrData.circom
Normal file
@@ -0,0 +1,517 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "anon-aadhaar-circuits/src/helpers/constants.circom";
|
||||
include "circomlib/circuits/comparators.circom";
|
||||
include "circomlib/circuits/bitify.circom";
|
||||
include "circomlib/circuits/poseidon.circom";
|
||||
include "../passport/customHashers.circom";
|
||||
include "./pack.circom";
|
||||
|
||||
/// @notice Position of the phone number in the QR data
|
||||
function phnoPosition() {
|
||||
return 17;
|
||||
}
|
||||
|
||||
/// @notice Maximum length (62) of the name in the QR data
|
||||
function nameMaxLength() {
|
||||
return 2 * maxFieldByteSize();
|
||||
}
|
||||
|
||||
/// @title DOBExtractor
|
||||
/// @notice Extract date of birth from the Aadhaar QR data
|
||||
/// @param maxDataLength - Maximum length of the data
|
||||
/// @input nDelimitedData[maxDataLength] - QR data where each delimiter is 255 * n where n is order of the data
|
||||
/// @input startDelimiterIndex - index of the delimiter after which the date of birth start
|
||||
/// @output year - year of birth in ascii format
|
||||
/// @output month - month of birth in ascii format
|
||||
/// @output day - day of birth in ascii format
|
||||
template DOBExtractor(maxDataLength) {
|
||||
signal input nDelimitedData[maxDataLength];
|
||||
signal input startDelimiterIndex;
|
||||
|
||||
signal output nDelimitedDataShiftedToDob[maxDataLength];
|
||||
|
||||
// Shift the data to the right to until the DOB index
|
||||
// We are not using SubArraySelector as the shifted data is an output
|
||||
component shifter = VarShiftLeft(maxDataLength, maxDataLength);
|
||||
shifter.in <== nDelimitedData;
|
||||
shifter.shift <== startDelimiterIndex; // We want delimiter to be the first byte
|
||||
|
||||
signal shiftedBytes[maxDataLength] <== shifter.out;
|
||||
|
||||
// Assert delimiters around the data is correct
|
||||
shiftedBytes[0] === dobPosition() * 255;
|
||||
shiftedBytes[11] === (dobPosition() + 1) * 255;
|
||||
|
||||
// Convert DOB bytes to unix timestamp.
|
||||
// Get year, month, day as int (DD-MM-YYYY format)
|
||||
signal output year[4] <== [shiftedBytes[7], shiftedBytes[8], shiftedBytes[9], shiftedBytes[10]];
|
||||
signal output month[2] <== [shiftedBytes[4], shiftedBytes[5]];
|
||||
signal output day[2] <== [shiftedBytes[1], shiftedBytes[2]];
|
||||
|
||||
nDelimitedDataShiftedToDob <== shiftedBytes;
|
||||
}
|
||||
|
||||
|
||||
template AgeExtractor() {
|
||||
signal input DOB_year[4];
|
||||
signal input DOB_month[2];
|
||||
signal input DOB_day[2];
|
||||
|
||||
signal input currentYear;
|
||||
signal input currentMonth;
|
||||
signal input currentDay;
|
||||
|
||||
// Convert DOB bytes to unix timestamp.
|
||||
signal year <== DigitBytesToInt(4)([DOB_year[0], DOB_year[1], DOB_year[2], DOB_year[3]]);
|
||||
signal month <== DigitBytesToInt(2)([DOB_month[0], DOB_month[1]]);
|
||||
signal day <== DigitBytesToInt(2)([DOB_day[0], DOB_day[1]]);
|
||||
|
||||
// Completed age based on year value
|
||||
signal ageByYear <== currentYear - year - 1;
|
||||
|
||||
// +1 to age if month is above currentMonth, or if months are same and day is higher
|
||||
signal monthGt <== GreaterThan(4)([currentMonth, month]);
|
||||
|
||||
signal monthEq <== IsEqual()([currentMonth, month]);
|
||||
|
||||
signal dayGt <== GreaterThan(5)([currentDay + 1, day]);
|
||||
|
||||
signal isHigherDayOnSameMonth <== monthEq * dayGt;
|
||||
|
||||
signal output age <== ageByYear + (monthGt + isHigherDayOnSameMonth);
|
||||
}
|
||||
|
||||
/// @title TimestampExtractor
|
||||
/// @notice Extracts the timestamp when the QR was signed rounded to nearest hour
|
||||
/// @dev We ignore seconds to avoid identifying the user based on the precise timestamp
|
||||
/// @input nDelimitedData[maxDataLength] - QR data where each delimiter is 255 * n where n is order of the data
|
||||
/// @output timestamp - Unix timestamp on signature
|
||||
/// @output year - Year of the signature
|
||||
/// @output month - Month of the signature
|
||||
/// @output day - Day of the signature
|
||||
template TimestampExtractor(maxDataLength) {
|
||||
signal input nDelimitedData[maxDataLength];
|
||||
|
||||
signal output timestamp;
|
||||
signal output year <== DigitBytesToInt(4)([nDelimitedData[9], nDelimitedData[10], nDelimitedData[11], nDelimitedData[12]]);
|
||||
signal output month <== DigitBytesToInt(2)([nDelimitedData[13], nDelimitedData[14]]);
|
||||
signal output day <== DigitBytesToInt(2)([nDelimitedData[15], nDelimitedData[16]]);
|
||||
signal hour <== DigitBytesToInt(2)([nDelimitedData[17], nDelimitedData[18]]);
|
||||
signal minute <== DigitBytesToInt(2)([nDelimitedData[19], nDelimitedData[20]]);
|
||||
|
||||
component dateToUnixTime = DigitBytesToTimestamp(2032);
|
||||
dateToUnixTime.year <== year;
|
||||
dateToUnixTime.month <== month;
|
||||
dateToUnixTime.day <== day;
|
||||
dateToUnixTime.hour <== hour;
|
||||
dateToUnixTime.minute <== minute;
|
||||
dateToUnixTime.second <== 0;
|
||||
|
||||
timestamp <== dateToUnixTime.out - 19800; // 19800 is the offset for IST
|
||||
}
|
||||
|
||||
/// @title NameExtractor
|
||||
/// @notice Extracts Name
|
||||
/// @notice This assumes max name length 62 bytes
|
||||
/// @param maxDataLength - Maximum length of the data
|
||||
/// @input nDelimitedData[maxDataLength] - QR data where each delimiter is 255 * n where n is order of the data
|
||||
/// @input delimiterIndices - indices of the delimiters in the QR data
|
||||
/// @output out - name in ascii format
|
||||
template NameExtractor(maxDataLength) {
|
||||
signal input nDelimitedData[maxDataLength];
|
||||
signal input delimiterIndices[18];
|
||||
|
||||
signal startDelimiterIndex <== delimiterIndices[namePosition() - 1];
|
||||
signal endDelimiterIndex <== delimiterIndices[namePosition()];
|
||||
|
||||
var nameMaxLength = 2 * maxFieldByteSize();
|
||||
var byteLength = nameMaxLength + 1;
|
||||
|
||||
signal output out[nameMaxLength];
|
||||
|
||||
// Shift the data to the right till the the delimiter start
|
||||
component subArraySelector = SelectSubArray(maxDataLength, byteLength);
|
||||
subArraySelector.in <== nDelimitedData;
|
||||
subArraySelector.startIndex <== startDelimiterIndex; // We want delimiter to be the first byte
|
||||
subArraySelector.length <== endDelimiterIndex - startDelimiterIndex;
|
||||
signal shiftedBytes[byteLength] <== subArraySelector.out;
|
||||
|
||||
// Assert that the first byte is the delimiter (255 * namePosition())
|
||||
shiftedBytes[0] === namePosition() * 255;
|
||||
|
||||
// Assert that last byte is the delimiter (255 * (namePosition() + 1))
|
||||
component endDelimiterSelector = ItemAtIndex(maxDataLength);
|
||||
endDelimiterSelector.in <== nDelimitedData;
|
||||
endDelimiterSelector.index <== endDelimiterIndex;
|
||||
endDelimiterSelector.out === (namePosition() + 1) * 255;
|
||||
|
||||
for (var i = 0; i < nameMaxLength; i ++) {
|
||||
out[i] <== shiftedBytes[i + 1]; // +1 to skip the delimiter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @title GenderExtractor
|
||||
/// @notice Extracts the Gender from the Aadhaar QR data
|
||||
/// @input nDelimitedDataShiftedToDob[maxDataLength] - QR data where each delimiter is 255 * n
|
||||
/// where n is order of the data shifted till DOB index
|
||||
/// @input startDelimiterIndex - index of the delimiter after
|
||||
/// @output out Single byte number representing gender
|
||||
template GenderExtractor(maxDataLength) {
|
||||
signal input nDelimitedDataShiftedToDob[maxDataLength];
|
||||
|
||||
signal output out;
|
||||
|
||||
// Gender is always 1 byte and is immediate after DOB
|
||||
// We use nDelimitedDataShiftedToDob and start after 10 + 1 bytes of DOB data
|
||||
// This is more efficient than using ItemAtIndex thrice (for startIndex, gender, endIndex)
|
||||
// saves around 14k constraints
|
||||
nDelimitedDataShiftedToDob[11] === genderPosition() * 255;
|
||||
nDelimitedDataShiftedToDob[13] === (genderPosition() + 1) * 255;
|
||||
|
||||
out <== nDelimitedDataShiftedToDob[12];
|
||||
}
|
||||
|
||||
/// @title PinCodeExtractor
|
||||
/// @notice Extracts the pin code from the Aadhaar QR data
|
||||
/// @input nDelimitedData[maxDataLength] - QR data where each delimiter is 255 * n where n is order of the data
|
||||
/// @input startDelimiterIndex - index of the delimiter after which the pin code start
|
||||
/// @input endDelimiterIndex - index of the delimiter up to which the pin code is present
|
||||
/// @output out - pinCode in ascii format
|
||||
template PinCodeExtractor(maxDataLength) {
|
||||
signal input nDelimitedData[maxDataLength];
|
||||
signal input startDelimiterIndex;
|
||||
signal input endDelimiterIndex;
|
||||
|
||||
signal output out[6];
|
||||
|
||||
var pinCodeMaxLength = 6;
|
||||
var byteLength = pinCodeMaxLength + 2; // 2 delimiters
|
||||
|
||||
component subArraySelector = SelectSubArray(maxDataLength, byteLength);
|
||||
subArraySelector.in <== nDelimitedData;
|
||||
subArraySelector.startIndex <== startDelimiterIndex;
|
||||
subArraySelector.length <== endDelimiterIndex - startDelimiterIndex + 1;
|
||||
|
||||
signal shiftedBytes[byteLength] <== subArraySelector.out;
|
||||
|
||||
// Assert delimiters around the data is correct
|
||||
shiftedBytes[0] === pinCodePosition() * 255;
|
||||
shiftedBytes[7] === (pinCodePosition() + 1) * 255;
|
||||
|
||||
out <== [shiftedBytes[1], shiftedBytes[2], shiftedBytes[3], shiftedBytes[4], shiftedBytes[5], shiftedBytes[6]];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @title PhnoLast4DigitCodeExtractor
|
||||
/// @notice Extracts the last 4 digits of the phone number from the Aadhaar QR data
|
||||
/// @input nDelimitedData[maxDataLength] - QR data where each delimiter is 255 * n where n is order of the data
|
||||
/// @input startDelimiterIndex - index of the delimiter after which the phone number start
|
||||
/// @input endDelimiterIndex - index of the delimiter up to which the phone number is present
|
||||
/// @output out - last 4 digits of the phone number in ascii format
|
||||
template PhnoLast4DigitCodeExtractor(maxDataLength) {
|
||||
signal input nDelimitedData[maxDataLength];
|
||||
signal input startDelimiterIndex;
|
||||
signal input endDelimiterIndex;
|
||||
|
||||
signal output out[4];
|
||||
|
||||
var phnoMaxLength = 10;
|
||||
var byteLength = phnoMaxLength + 2; // 2 delimiters
|
||||
|
||||
signal length <== endDelimiterIndex - startDelimiterIndex + 1;
|
||||
|
||||
component subArraySelector = SelectSubArray(maxDataLength, byteLength);
|
||||
subArraySelector.in <== nDelimitedData;
|
||||
subArraySelector.startIndex <== startDelimiterIndex;
|
||||
subArraySelector.length <== length;
|
||||
|
||||
signal shiftedBytes[byteLength] <== subArraySelector.out;
|
||||
|
||||
component isLessThan7 = LessThan(4);
|
||||
isLessThan7.in[0] <== length;
|
||||
isLessThan7.in[1] <== 7;
|
||||
|
||||
shiftedBytes[0] === phnoPosition() * 255;
|
||||
// Assert delimiters around the data is correct for phno length 4
|
||||
isLessThan7.out * shiftedBytes[5] === isLessThan7.out * (phnoPosition() + 1) * 255;
|
||||
|
||||
signal isNotLessThan7 <== 1 - isLessThan7.out;
|
||||
|
||||
// Assert delimiters around the data is correct for phno length 10
|
||||
isNotLessThan7 * shiftedBytes[11] === isNotLessThan7 * (phnoPosition() + 1) * 255;
|
||||
|
||||
signal out4[4] <== [shiftedBytes[1], shiftedBytes[2], shiftedBytes[3], shiftedBytes[4]];
|
||||
signal out10[4] <== [shiftedBytes[7], shiftedBytes[8], shiftedBytes[9], shiftedBytes[10]];
|
||||
|
||||
for (var i = 0; i < 4; i ++) {
|
||||
out[i] <== isLessThan7.out * out4[i] + out10[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @title ExtractData
|
||||
/// @notice Helper function to extract data at a position
|
||||
/// @dev This is only used for state now;
|
||||
/// @param maxDataLength - Maximum length of the data
|
||||
/// @param extractPosition - Position of the data to extract (after which delimiter does the data start)
|
||||
/// @input nDelimitedData[maxDataLength] - QR data where each delimiter is 255 * n where n is order of the data
|
||||
/// @input delimiterIndices - indices of the delimiters in the QR data
|
||||
/// @output out - data in ascii format
|
||||
template ExtractData(maxDataLength, extractPosition) {
|
||||
signal input nDelimitedData[maxDataLength];
|
||||
signal input delimiterIndices[18];
|
||||
|
||||
signal startDelimiterIndex <== delimiterIndices[extractPosition - 1];
|
||||
signal endDelimiterIndex <== delimiterIndices[extractPosition];
|
||||
|
||||
var extractMaxLength = maxFieldByteSize();
|
||||
var byteLength = extractMaxLength + 1;
|
||||
|
||||
signal output out[extractMaxLength];
|
||||
|
||||
// Shift the data to the right till the the delimiter start
|
||||
component subArraySelector = SelectSubArray(maxDataLength, byteLength);
|
||||
subArraySelector.in <== nDelimitedData;
|
||||
subArraySelector.startIndex <== startDelimiterIndex; // We want delimiter to be the first byte
|
||||
subArraySelector.length <== endDelimiterIndex - startDelimiterIndex;
|
||||
signal shiftedBytes[byteLength] <== subArraySelector.out;
|
||||
|
||||
// Assert that the first byte is the delimiter (255 * position of the field)
|
||||
shiftedBytes[0] === extractPosition * 255;
|
||||
|
||||
// Assert that last byte is the delimiter (255 * (position of the field + 1))
|
||||
component endDelimiterSelector = ItemAtIndex(maxDataLength);
|
||||
endDelimiterSelector.in <== nDelimitedData;
|
||||
endDelimiterSelector.index <== endDelimiterIndex;
|
||||
endDelimiterSelector.out === (extractPosition + 1) * 255;
|
||||
|
||||
for (var i = 0; i < extractMaxLength; i ++) {
|
||||
out[i] <== shiftedBytes[i + 1]; // +1 to skip the delimiter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @title PhotoExtractor
|
||||
/// @notice Extracts the photo from the Aadhaar QR data
|
||||
/// @dev Not reusing ExtractAndPackAsInt as there is no endDelimiter (photo is last item)
|
||||
/// @input nDelimitedData[maxDataLength] - QR data where each delimiter is 255 * n where n is order of the data
|
||||
/// @input startDelimiterIndex - index of the delimiter after which the photo start
|
||||
/// @input endIndex - index of the last byte of the photo
|
||||
/// @output out - Hash of the photo
|
||||
template PhotoExtractor(maxDataLength) {
|
||||
signal input nDelimitedData[maxDataLength];
|
||||
signal input startDelimiterIndex;
|
||||
signal input endIndex;
|
||||
|
||||
signal output out;
|
||||
|
||||
var photoMaxLength = photoPackSize() * maxFieldByteSize();
|
||||
var bytesLength = photoMaxLength + 1;
|
||||
|
||||
// Shift the data to the right to until the photo index
|
||||
component subArraySelector = SelectSubArray(maxDataLength, bytesLength);
|
||||
subArraySelector.in <== nDelimitedData;
|
||||
subArraySelector.startIndex <== startDelimiterIndex; // We want delimiter to be the first byte
|
||||
subArraySelector.length <== endIndex - startDelimiterIndex + 1;
|
||||
|
||||
signal shiftedBytes[bytesLength] <== subArraySelector.out;
|
||||
|
||||
// Assert that the first byte is the delimiter (255 * position of name field)
|
||||
shiftedBytes[0] === photoPosition() * 255;
|
||||
|
||||
// Assert that last byte is the EOI (217)
|
||||
component EOIDelimiterSelector = ItemAtIndex(maxDataLength);
|
||||
EOIDelimiterSelector.in <== nDelimitedData;
|
||||
EOIDelimiterSelector.index <== endIndex;
|
||||
EOIDelimiterSelector.out === 217;
|
||||
|
||||
// Assert that last second byte is the (255)
|
||||
component DelimiterSelector = ItemAtIndex(maxDataLength);
|
||||
DelimiterSelector.in <== nDelimitedData;
|
||||
DelimiterSelector.index <== endIndex - 1;
|
||||
DelimiterSelector.out === 255;
|
||||
|
||||
// Pack byte[] to int[] where int is field element which take up to 31 bytes
|
||||
// When packing like this the trailing 0s in each chunk would be removed as they are LSB
|
||||
// This is ok for being used in nullifiers as the behaviour would be consistent
|
||||
component outInt = PackBytesAndPoseidon(photoMaxLength);
|
||||
for (var i = 0; i < photoMaxLength; i ++) {
|
||||
outInt.in[i] <== shiftedBytes[i + 1]; // +1 to skip the delimiter
|
||||
}
|
||||
|
||||
out <== outInt.out;
|
||||
}
|
||||
|
||||
/// @title ValidateDelimiterIndices
|
||||
/// @notice Validates the delimiter indices
|
||||
/// @input delimiterIndices[18] - Delimiter indices
|
||||
template ValidateDelimiterIndices() {
|
||||
signal input delimiterIndices[18];
|
||||
signal input photoEOI;
|
||||
|
||||
component range_check[19];
|
||||
component delimiter_idx_less_than_nxt_idx[17];
|
||||
|
||||
for(var i = 0; i < 17; i++) {
|
||||
range_check[i] = Num2Bits(12);
|
||||
range_check[i].in <== delimiterIndices[i];
|
||||
|
||||
delimiter_idx_less_than_nxt_idx[i] = LessThan(12);
|
||||
delimiter_idx_less_than_nxt_idx[i].in[0] <== delimiterIndices[i];
|
||||
delimiter_idx_less_than_nxt_idx[i].in[1] <== delimiterIndices[i + 1];
|
||||
delimiter_idx_less_than_nxt_idx[i].out === 1;
|
||||
}
|
||||
|
||||
range_check[17] = Num2Bits(12);
|
||||
range_check[17].in <== delimiterIndices[17];
|
||||
|
||||
range_check[18] = Num2Bits(12);
|
||||
range_check[18].in <== photoEOI;
|
||||
|
||||
component is_last_delimiter_idx_valid = LessThan(12);
|
||||
is_last_delimiter_idx_valid.in[0] <== delimiterIndices[17];
|
||||
is_last_delimiter_idx_valid.in[1] <== photoEOI;
|
||||
is_last_delimiter_idx_valid.out === 1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//TODO: Currently we use state to be 31 bytes , but this can be reduced to MAX LENGTH OF STATE
|
||||
|
||||
/// @title EXTRACT_QR_DATA
|
||||
/// @notice Extracts the data from the Aadhaar QR data
|
||||
/// @input data[maxDataLength] - QR data without the signature padded
|
||||
/// @input qrDataPaddedLength - length of the QR data
|
||||
/// @input delimiterIndices - indices of the delimiters in the QR data
|
||||
/// @output name[2] - name of the user
|
||||
/// @output yob - year of birth
|
||||
/// @output mob - month of birth
|
||||
/// @output dob - day of birth
|
||||
/// @output gender - gender of the user
|
||||
/// @output pincode - pincode of the user
|
||||
/// @output state - state of the user
|
||||
/// @output aadhaar_last_4digits - last 4 digits of the Aadhaar number
|
||||
/// @output ph_no_last_4digits - last 4 digits of the phone number
|
||||
template EXTRACT_QR_DATA(maxDataLength) {
|
||||
signal input data[maxDataLength];
|
||||
signal input qrDataPaddedLength;
|
||||
signal input delimiterIndices[18];
|
||||
signal input photoEOI;
|
||||
|
||||
|
||||
// Outputs are in ascii format
|
||||
signal output name[nameMaxLength()];
|
||||
signal output yob[4];
|
||||
signal output mob[2];
|
||||
signal output dob[2];
|
||||
signal output gender;
|
||||
signal output pincode[6];
|
||||
signal output state[maxFieldByteSize()];
|
||||
signal output aadhaar_last_4digits[4];
|
||||
signal output ph_no_last_4digits[4];
|
||||
signal output photoHash;
|
||||
signal output timestamp;
|
||||
|
||||
// Create `nDelimitedData` - same as `data` but each delimiter is replaced with n * 255
|
||||
// where n means the nth occurrence of 255
|
||||
// This is to verify `delimiterIndices` is correctly set for each extraction
|
||||
component is255[maxDataLength];
|
||||
component indexBeforePhoto[maxDataLength];
|
||||
signal is255AndIndexBeforePhoto[maxDataLength];
|
||||
signal nDelimitedData[maxDataLength];
|
||||
signal n255Filter[maxDataLength + 1];
|
||||
n255Filter[0] <== 0;
|
||||
|
||||
component validateDelimiterIndices = ValidateDelimiterIndices();
|
||||
validateDelimiterIndices.delimiterIndices <== delimiterIndices;
|
||||
validateDelimiterIndices.photoEOI <== photoEOI;
|
||||
|
||||
component photoEOI_valid = LessThan(12);
|
||||
photoEOI_valid.in[0] <== photoEOI;
|
||||
photoEOI_valid.in[1] <== qrDataPaddedLength;
|
||||
photoEOI_valid.out === 1;
|
||||
|
||||
|
||||
|
||||
for (var i = 0; i < maxDataLength; i++) {
|
||||
is255[i] = IsEqual();
|
||||
is255[i].in[0] <== 255;
|
||||
is255[i].in[1] <== data[i];
|
||||
|
||||
indexBeforePhoto[i] = LessThan(12);
|
||||
indexBeforePhoto[i].in[0] <== i;
|
||||
indexBeforePhoto[i].in[1] <== delimiterIndices[photoPosition() - 1] + 1;
|
||||
|
||||
is255AndIndexBeforePhoto[i] <== is255[i].out * indexBeforePhoto[i].out;
|
||||
|
||||
// Each value is n * 255 where n the count of 255s before it
|
||||
n255Filter[i + 1] <== is255AndIndexBeforePhoto[i] * 255 + n255Filter[i];
|
||||
|
||||
nDelimitedData[i] <== is255AndIndexBeforePhoto[i] * n255Filter[i] + data[i];
|
||||
}
|
||||
|
||||
//Extract name and hash
|
||||
component nameExtractor = NameExtractor(maxDataLength);
|
||||
nameExtractor.nDelimitedData <== nDelimitedData;
|
||||
nameExtractor.delimiterIndices <== delimiterIndices;
|
||||
name <== nameExtractor.out;
|
||||
|
||||
|
||||
//Extract last 4 digit of Aadhar no
|
||||
aadhaar_last_4digits <== [nDelimitedData[5],nDelimitedData[6],nDelimitedData[7],nDelimitedData[8]];
|
||||
|
||||
// Extract date of birth
|
||||
component dobExtractor = DOBExtractor(maxDataLength);
|
||||
dobExtractor.nDelimitedData <== nDelimitedData;
|
||||
dobExtractor.startDelimiterIndex <== delimiterIndices[dobPosition() - 1];
|
||||
|
||||
yob <== dobExtractor.year;
|
||||
mob <== dobExtractor.month;
|
||||
dob <== dobExtractor.day;
|
||||
|
||||
// Extract gender
|
||||
// dobExtractor returns data shifted till DOB. Since size for DOB data is fixed,
|
||||
// we can use the same shifted data to extract gender.
|
||||
component genderExtractor = GenderExtractor(maxDataLength);
|
||||
genderExtractor.nDelimitedDataShiftedToDob <== dobExtractor.nDelimitedDataShiftedToDob;
|
||||
gender <== genderExtractor.out;
|
||||
|
||||
// Extract pin code
|
||||
component pinCodeExtractor = PinCodeExtractor(maxDataLength);
|
||||
pinCodeExtractor.nDelimitedData <== nDelimitedData;
|
||||
pinCodeExtractor.startDelimiterIndex <== delimiterIndices[pinCodePosition() - 1];
|
||||
pinCodeExtractor.endDelimiterIndex <== delimiterIndices[pinCodePosition()];
|
||||
pincode <== pinCodeExtractor.out;
|
||||
|
||||
// Extract last 4 digits of phone number
|
||||
component phnoLast4DigitCodeExtractor = PhnoLast4DigitCodeExtractor(maxDataLength);
|
||||
phnoLast4DigitCodeExtractor.nDelimitedData <== nDelimitedData;
|
||||
phnoLast4DigitCodeExtractor.startDelimiterIndex <== delimiterIndices[phnoPosition() - 1];
|
||||
phnoLast4DigitCodeExtractor.endDelimiterIndex <== delimiterIndices[phnoPosition()];
|
||||
ph_no_last_4digits <== phnoLast4DigitCodeExtractor.out;
|
||||
|
||||
// Extract state
|
||||
component stateExtractor = ExtractData(maxDataLength, statePosition());
|
||||
stateExtractor.nDelimitedData <== nDelimitedData;
|
||||
stateExtractor.delimiterIndices <== delimiterIndices;
|
||||
state <== stateExtractor.out;
|
||||
|
||||
// Extract photo
|
||||
component photoExtractor = PhotoExtractor(maxDataLength);
|
||||
photoExtractor.nDelimitedData <== nDelimitedData;
|
||||
photoExtractor.startDelimiterIndex <== delimiterIndices[photoPosition() - 1];
|
||||
photoExtractor.endIndex <== photoEOI;
|
||||
photoHash <== photoExtractor.out;
|
||||
|
||||
// Extract timestamp
|
||||
component timestampExtractor = TimestampExtractor(maxDataLength);
|
||||
timestampExtractor.nDelimitedData <== nDelimitedData;
|
||||
timestamp <== timestampExtractor.timestamp;
|
||||
|
||||
}
|
||||
31
circuits/circuits/utils/aadhaar/ofac/ofac_name_dob.circom
Normal file
31
circuits/circuits/utils/aadhaar/ofac/ofac_name_dob.circom
Normal file
@@ -0,0 +1,31 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "circomlib/circuits/poseidon.circom";
|
||||
include "../../crypto/merkle-trees/smt.circom";
|
||||
|
||||
/// @title OFAC_NAME_DOB_AADHAAR
|
||||
/// @notice Verify if the name-DOB is in the OFAC list
|
||||
/// @param nLevels Maximum number of levels in the merkle tree
|
||||
/// @input name[2] Name of the user(packed into 2 field elements)
|
||||
/// @input YOB Year of birth
|
||||
/// @input MOB Month of birth
|
||||
/// @input DOB Day of birth
|
||||
/// @input smt_leaf_key Leaf key for name-DOB SMT verification
|
||||
/// @input smt_root Root of name-DOB SMT
|
||||
/// @input smt_siblings Siblings for name-DOB SMT proof
|
||||
/// @output ofacCheckResult Result of the OFAC check
|
||||
template OFAC_NAME_DOB_AADHAAR(nLevels) {
|
||||
signal input name[2];
|
||||
|
||||
signal input YOB;
|
||||
signal input MOB;
|
||||
signal input DOB;
|
||||
|
||||
signal input smt_leaf_key;
|
||||
signal input smt_root;
|
||||
signal input smt_siblings[nLevels];
|
||||
|
||||
signal name_dob_hash <== Poseidon(5)([name[0], name[1], YOB, MOB, DOB]);
|
||||
|
||||
signal output ofacCheckResult <== SMTVerify(nLevels)(name_dob_hash, smt_leaf_key, smt_root, smt_siblings, 0);
|
||||
}
|
||||
26
circuits/circuits/utils/aadhaar/ofac/ofac_name_yob.circom
Normal file
26
circuits/circuits/utils/aadhaar/ofac/ofac_name_yob.circom
Normal file
@@ -0,0 +1,26 @@
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "circomlib/circuits/poseidon.circom";
|
||||
include "../../crypto/merkle-trees/smt.circom";
|
||||
|
||||
/// @title OFAC_NAME_YOB_AADHAAR
|
||||
/// @notice Verify if the name-YOB is in the OFAC list
|
||||
/// @param nLevels Maximum number of levels in the merkle tree
|
||||
/// @input name[2] Name of the user(packed into 2 field elements)
|
||||
/// @input YOB Year of birth
|
||||
/// @input smt_leaf_key Leaf key for name-YOB SMT verification
|
||||
/// @input smt_root Root of name-YOB SMT
|
||||
/// @input smt_siblings Siblings for name-YOB SMT proof
|
||||
/// @output ofacCheckResult Result of the OFAC check
|
||||
template OFAC_NAME_YOB_AADHAAR(nLevels) {
|
||||
signal input name[2];
|
||||
signal input YOB;
|
||||
|
||||
signal input smt_leaf_key;
|
||||
signal input smt_root;
|
||||
signal input smt_siblings[nLevels];
|
||||
|
||||
signal name_yob_hash <== Poseidon(3)([name[0], name[1], YOB]);
|
||||
|
||||
signal output ofacCheckResult <== SMTVerify(nLevels)(name_yob_hash, smt_leaf_key, smt_root, smt_siblings, 0);
|
||||
}
|
||||
92
circuits/circuits/utils/aadhaar/pack.circom
Normal file
92
circuits/circuits/utils/aadhaar/pack.circom
Normal file
@@ -0,0 +1,92 @@
|
||||
//THIS CODE WAS TAKEN FROM https://github.com/anon-aadhaar/anon-aadhaar/blob/main/packages/circuits/src/utils/pack.circom
|
||||
|
||||
|
||||
pragma circom 2.1.9;
|
||||
|
||||
include "circomlib/circuits/comparators.circom";
|
||||
|
||||
/// @title DigitBytesToTimestamp
|
||||
/// @notice Converts a date string of format YYYYMMDDHHMMSS to a unix time
|
||||
/// @notice Each byte is expected to be a ASCII character representing a digit
|
||||
/// @notice Assumes the input time is in UTC
|
||||
/// @dev Does not work for time before unix epoch (negative timestamps)
|
||||
/// @dev Inputs are not sanity checked in this template (eg: month <= 12?, year >= 1970?)
|
||||
/// @param maxYears The maximum year that can be represented
|
||||
/// @param includeHours 1 to include hours, 0 to round down to day
|
||||
/// @param includeMinutes 1 to include minutes, 0 to round down to hour
|
||||
/// @param includeSeconds 1 to include seconds, 0 to round down to minute
|
||||
/// @input in The input byte array
|
||||
/// @output out The output integer representing the unix time
|
||||
template DigitBytesToTimestamp(maxYears) {
|
||||
signal input year;
|
||||
signal input month;
|
||||
signal input day;
|
||||
signal input hour;
|
||||
signal input minute;
|
||||
signal input second;
|
||||
|
||||
signal output out;
|
||||
|
||||
|
||||
// These does not add constraints, but can help to catch errors during witness generation
|
||||
assert(year >= 1970);
|
||||
assert(year <= maxYears);
|
||||
assert(month >= 1);
|
||||
assert(month <= 12);
|
||||
assert(day >= 1);
|
||||
assert(day <= 31);
|
||||
assert(hour >= 0);
|
||||
assert(hour <= 23);
|
||||
assert(minute >= 0);
|
||||
assert(minute <= 59);
|
||||
assert(second >= 0);
|
||||
assert(second <= 59);
|
||||
|
||||
|
||||
signal daysTillPreviousMonth[12] <== [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
|
||||
|
||||
var maxLeapYears = (maxYears - 1972) \ 4; // 1972 is first leap year since epoch
|
||||
var arrLength = 14 + maxLeapYears + maxLeapYears;
|
||||
|
||||
signal daysPassed[arrLength];
|
||||
daysPassed[0] <== (year - 1970) * 365;
|
||||
daysPassed[1] <== day - 1;
|
||||
|
||||
component isCurrentMonth[12];
|
||||
for (var i = 0; i < 12; i++) {
|
||||
isCurrentMonth[i] = IsEqual();
|
||||
isCurrentMonth[i].in[0] <== month - 1;
|
||||
isCurrentMonth[i].in[1] <== i;
|
||||
|
||||
daysPassed[i + 2] <== isCurrentMonth[i].out * daysTillPreviousMonth[i]; // Add days till previous month
|
||||
}
|
||||
|
||||
component isLeapYearCurrentYear[maxLeapYears]; // ith leap year is current year
|
||||
component isLeapYearLessThanCurrentYear[maxLeapYears]; // ith leap after 1970 is below current year
|
||||
component isCurrentMonthAfterFeb[maxLeapYears];
|
||||
|
||||
for (var i = 0; i < maxLeapYears; i++) {
|
||||
isLeapYearLessThanCurrentYear[i] = GreaterThan(8);
|
||||
isLeapYearLessThanCurrentYear[i].in[0] <== year - 1972;
|
||||
isLeapYearLessThanCurrentYear[i].in[1] <== i * 4;
|
||||
|
||||
isLeapYearCurrentYear[i] = IsEqual();
|
||||
isLeapYearCurrentYear[i].in[0] <== year - 1972;
|
||||
isLeapYearCurrentYear[i].in[1] <== i * 4;
|
||||
|
||||
daysPassed[14 + i] <== isLeapYearLessThanCurrentYear[i].out; // Add 1 day for each leap year
|
||||
|
||||
isCurrentMonthAfterFeb[i] = GreaterThan(4);
|
||||
isCurrentMonthAfterFeb[i].in[0] <== month;
|
||||
isCurrentMonthAfterFeb[i].in[1] <== 2;
|
||||
daysPassed[14 + maxLeapYears + i] <== isLeapYearCurrentYear[i].out * isCurrentMonthAfterFeb[i].out; // Add 1 days if current year is leap and date is after Feb
|
||||
}
|
||||
|
||||
signal totalDaysPassed[arrLength];
|
||||
totalDaysPassed[0] <== daysPassed[0];
|
||||
for (var i = 1; i < arrLength; i++) {
|
||||
totalDaysPassed[i] <== totalDaysPassed[i - 1] + daysPassed[i];
|
||||
}
|
||||
|
||||
out <== totalDaysPassed[arrLength -1] * 86400 + hour * 3600 + minute * 60 + second;
|
||||
}
|
||||
@@ -2,6 +2,7 @@ pragma circom 2.1.9;
|
||||
|
||||
include "@openpassport/zk-email-circuits/utils/bytes.circom";
|
||||
include "../date/isOlderThan.circom";
|
||||
include "../../aadhaar/disclose/country_not_in_list.circom";
|
||||
|
||||
/// @notice Disclosure circuit — used after user registration
|
||||
/// @param MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH Maximum number of countries present in the forbidden countries list
|
||||
@@ -44,9 +45,9 @@ template DISCLOSE(
|
||||
signal input ofac_nameyob_smt_leaf_key;
|
||||
signal input ofac_nameyob_smt_root;
|
||||
signal input ofac_nameyob_smt_siblings[nameyobTreeLevels];
|
||||
|
||||
|
||||
signal input selector_ofac;
|
||||
|
||||
|
||||
// assert selectors are 0 or 1
|
||||
for (var i = 0; i < 88; i++) {
|
||||
selector_dg1[i] * (selector_dg1[i] - 1) === 0;
|
||||
@@ -70,7 +71,7 @@ template DISCLOSE(
|
||||
for (var i = 0; i < 88; i++) {
|
||||
revealedData[i] <== dg1[5+i] * selector_dg1[i];
|
||||
}
|
||||
|
||||
|
||||
revealedData[88] <== older_than_verified[0] * selector_older_than;
|
||||
revealedData[89] <== older_than_verified[1] * selector_older_than;
|
||||
|
||||
@@ -94,12 +95,17 @@ template DISCLOSE(
|
||||
ofac_nameyob_smt_root,
|
||||
ofac_nameyob_smt_siblings
|
||||
);
|
||||
|
||||
|
||||
revealedData[90] <== ofacCheckResultPassportNo * selector_ofac;
|
||||
revealedData[91] <== ofacCheckResultNameDob * selector_ofac;
|
||||
revealedData[92] <== ofacCheckResultNameYob * selector_ofac;
|
||||
signal output revealedData_packed[3] <== PackBytes(93)(revealedData);
|
||||
|
||||
var chunkLength = computeIntChunkLength(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3);
|
||||
signal output forbidden_countries_list_packed[chunkLength] <== ProveCountryIsNotInList(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH)(dg1, forbidden_countries_list);
|
||||
}
|
||||
component proveCountryIsNotInList = CountryNotInList(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;
|
||||
signal output forbidden_countries_list_packed[chunkLength] <== proveCountryIsNotInList.forbidden_countries_list_packed;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ include "@openpassport/zk-email-circuits/utils/bytes.circom";
|
||||
include "../date/isOlderThan.circom";
|
||||
include "../ofac/ofac_name_dob_id.circom";
|
||||
include "../ofac/ofac_name_yob_id.circom";
|
||||
include "../../aadhaar/disclose/country_not_in_list.circom";
|
||||
|
||||
/// @notice Disclosure circuit — used after user registration
|
||||
/// @param MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH Maximum number of countries present in the forbidden countries list
|
||||
@@ -90,5 +91,10 @@ template DISCLOSE_ID(
|
||||
signal output revealedData_packed[4] <== PackBytes(94)(revealedData);
|
||||
|
||||
var chunkLength = computeIntChunkLength(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH * 3);
|
||||
signal output forbidden_countries_list_packed[chunkLength] <== ProveCountryIsNotInList_ID(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH)(dg1, forbidden_countries_list);
|
||||
component proveCountryIsNotInList = CountryNotInList(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;
|
||||
signal output forbidden_countries_list_packed[chunkLength] <== proveCountryIsNotInList.forbidden_countries_list_packed;
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ template VERIFY_COMMITMENT(nLevels, DG1_LEN) {
|
||||
eContent_shaBytes_packed_hash,
|
||||
dsc_tree_leaf
|
||||
]);
|
||||
|
||||
|
||||
// Verify commitment inclusion
|
||||
signal computedRoot <== BinaryMerkleRoot(nLevels)(commitment, merkletree_size, path, siblings);
|
||||
merkle_root === computedRoot;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
"format": "prettier --write .",
|
||||
"install-circuits": "yarn workspaces focus @selfxyz/circuits",
|
||||
"lint": "prettier --check .",
|
||||
"test-qr-extractor": "yarn test-base 'tests/other_circuits/qrdata_extractor.test.ts' --exit",
|
||||
"test-disclose-aadhaar": "yarn test-base 'tests/disclose/vc_and_disclose_aadhaar.test.ts' --exit",
|
||||
"test-register-aadhaar": "yarn test-base 'tests/register/register_aadhaar.test.ts' --exit",
|
||||
"nice": "prettier --write .",
|
||||
"test": "yarn test-base 'tests/**/*.test.ts' --exit",
|
||||
"test-base": "yarn ts-mocha -n import=tsx --max-old-space-size=8192 --paths -p tsconfig.spec.json",
|
||||
@@ -55,10 +58,10 @@
|
||||
"test-register": "yarn test-base --max-old-space-size=40960 'tests/register/register.test.ts' --exit",
|
||||
"test-register-id": "yarn test-base --max-old-space-size=40960 'tests/register_id/register_id.test.ts' --exit",
|
||||
"test-rsa": "yarn test-base 'tests/utils/rsaPkcs1v1_5.test.ts' --exit",
|
||||
"test-rsa-pss": "yarn test-base 'tests/utils/rsapss.test.ts' --exit",
|
||||
"types": "yarn build --noEmit"
|
||||
"test-rsa-pss": "yarn test-base 'tests/utils/rsapss.test.ts' --exit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anon-aadhaar/core": "^2.4.3",
|
||||
"@noble/curves": "^1.4.2",
|
||||
"@openpassport/zk-email-circuits": "^6.1.2",
|
||||
"@openpassport/zk-kit-imt": "^0.0.4",
|
||||
@@ -70,6 +73,7 @@
|
||||
"@zk-email/zk-regex-circom": "^1.2.1",
|
||||
"@zk-kit/binary-merkle-root.circom": "https://gitpkg.vercel.app/Vishalkulkarni45/zk-kit.circom/packages/binary-merkle-root?fix/bin-merkle-tree",
|
||||
"@zk-kit/circuits": "^1.0.0-beta",
|
||||
"anon-aadhaar-circuits": "https://gitpkg.vercel.app/selfxyz/anon-aadhaar/packages/circuits?main",
|
||||
"asn1": "^0.2.6",
|
||||
"asn1.js": "^5.4.1",
|
||||
"asn1js": "^3.0.5",
|
||||
|
||||
@@ -15,8 +15,9 @@ OUTPUT_DIR="build/${CIRCUIT_TYPE}"
|
||||
# Define circuits and their configurations
|
||||
# format: name:poweroftau:build_flag
|
||||
CIRCUITS=(
|
||||
"vc_and_disclose:20:true"
|
||||
"vc_and_disclose_id:20:true"
|
||||
# "vc_and_disclose:20:true"
|
||||
# "vc_and_disclose_id:20:true"
|
||||
"vc_and_disclose_aadhaar:20:true"
|
||||
)
|
||||
|
||||
build_circuits "$CIRCUIT_TYPE" "$OUTPUT_DIR" "${CIRCUITS[@]}"
|
||||
|
||||
24
circuits/scripts/build/build_register_aadhaar.sh
Executable file
24
circuits/scripts/build/build_register_aadhaar.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
source "scripts/build/common.sh"
|
||||
|
||||
# Set environment (change this value as needed)
|
||||
# ENV="prod"
|
||||
ENV="staging"
|
||||
|
||||
echo -e "${GREEN}Building register circuits for $ENV environment${NC}"
|
||||
|
||||
# Circuit-specific configurations
|
||||
CIRCUIT_TYPE="register"
|
||||
OUTPUT_DIR="build/${CIRCUIT_TYPE}"
|
||||
|
||||
# Define circuits and their configurations
|
||||
# format: name:poweroftau:build_flag
|
||||
CIRCUITS=(
|
||||
"register_aadhaar:21:true"
|
||||
)
|
||||
|
||||
build_circuits "$CIRCUIT_TYPE" "$OUTPUT_DIR" "${CIRCUITS[@]}"
|
||||
|
||||
echo -e "${GREEN}Register circuits build completed for $ENV environment!${NC}"
|
||||
echo -e "${YELLOW}Generated files are located in: contracts/verifiers/local/${ENV}/${CIRCUIT_TYPE}/${NC}"
|
||||
@@ -85,10 +85,10 @@ build_circuit() {
|
||||
${OUTPUT_DIR}/${CIRCUIT_NAME}/${CIRCUIT_NAME}.zkey
|
||||
|
||||
# Generate and contribute random string
|
||||
# local RAND_STR=$(get_random_string)
|
||||
# echo $RAND_STR | yarn snarkjs zkey contribute \
|
||||
# ${OUTPUT_DIR}/${CIRCUIT_NAME}/${CIRCUIT_NAME}.zkey \
|
||||
# ${OUTPUT_DIR}/${CIRCUIT_NAME}/${CIRCUIT_NAME}_final.zkey
|
||||
local RAND_STR=$(get_random_string)
|
||||
echo $RAND_STR | yarn snarkjs zkey contribute \
|
||||
${OUTPUT_DIR}/${CIRCUIT_NAME}/${CIRCUIT_NAME}.zkey \
|
||||
${OUTPUT_DIR}/${CIRCUIT_NAME}/${CIRCUIT_NAME}_final.zkey
|
||||
|
||||
echo -e "${BLUE}Building vkey${NC}"
|
||||
yarn snarkjs zkey export verificationkey \
|
||||
|
||||
1
circuits/tests/consts/ofac/nameAndDobAadhaarSMT.json
Normal file
1
circuits/tests/consts/ofac/nameAndDobAadhaarSMT.json
Normal file
File diff suppressed because one or more lines are too long
1
circuits/tests/consts/ofac/nameAndYobAadhaarSMT.json
Normal file
1
circuits/tests/consts/ofac/nameAndYobAadhaarSMT.json
Normal file
File diff suppressed because one or more lines are too long
283
circuits/tests/disclose/vc_and_disclose_aadhaar.test.ts
Normal file
283
circuits/tests/disclose/vc_and_disclose_aadhaar.test.ts
Normal file
@@ -0,0 +1,283 @@
|
||||
import { expect } from 'chai';
|
||||
import { wasm as wasmTester } from 'circom_tester';
|
||||
import path from 'path';
|
||||
|
||||
import assert from 'assert';
|
||||
import { formatInput } from '@selfxyz/common/utils/circuits/generateInputs';
|
||||
import { unpackReveal } from '@selfxyz/common/utils/circuits/formatOutputs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { createSelector, extractField } from '@selfxyz/common/utils/aadhaar/constants';
|
||||
import { prepareAadhaarDiscloseTestData } from '@selfxyz/common';
|
||||
import { SMT } from '@openpassport/zk-kit-smt';
|
||||
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
|
||||
import { poseidon2 } from 'poseidon-lite';
|
||||
import nameAndDobAadhaarjson from '../consts/ofac/nameAndDobAadhaarSMT.json' with { type: 'json' };
|
||||
import nameAndYobAadhaarjson from '../consts/ofac/nameAndYobAadhaarSMT.json' with { type: 'json' };
|
||||
|
||||
import fs from 'fs';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
// const privateKeyPath = path.join(__dirname, '../../../node_modules/anon-aadhaar-circuits/assets/testPrivateKey.pem');
|
||||
const privateKeyPem = fs.readFileSync(
|
||||
path.join(__dirname, '../../../node_modules/anon-aadhaar-circuits/assets/testPrivateKey.pem'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
// Create SMTs at module level
|
||||
const nameAndDob_smt = new SMT(poseidon2, true);
|
||||
nameAndDob_smt.import(nameAndDobAadhaarjson as any);
|
||||
|
||||
const nameAndYob_smt = new SMT(poseidon2, true);
|
||||
nameAndYob_smt.import(nameAndYobAadhaarjson as any);
|
||||
|
||||
// Create Merkle tree at module level
|
||||
const tree: any = new LeanIMT((a, b) => poseidon2([a, b]), []);
|
||||
|
||||
// Helper function to get packed reveal data from circuit output
|
||||
function getPackedRevealData(revealedData: any): string[] {
|
||||
return [
|
||||
revealedData['revealData_packed[0]'],
|
||||
revealedData['revealData_packed[1]'],
|
||||
revealedData['revealData_packed[2]'],
|
||||
revealedData['revealData_packed[3]'],
|
||||
];
|
||||
}
|
||||
|
||||
describe(' VC and Disclose Aadhaar Circuit Tests', function () {
|
||||
let circuit: any;
|
||||
this.beforeAll(async function () {
|
||||
this.timeout(0);
|
||||
circuit = await wasmTester(
|
||||
path.join(__dirname, '../../circuits/disclose/vc_and_disclose_aadhaar.circom'),
|
||||
{
|
||||
verbose: true,
|
||||
logOutput: true,
|
||||
include: ['../node_modules', '../node_modules/circomlib/circuits'],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should compile and load the circuit', async function () {
|
||||
this.timeout(0);
|
||||
expect(circuit).to.not.be.undefined;
|
||||
});
|
||||
|
||||
it('should calculate witness and pass constrain check', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs } = prepareAadhaarDiscloseTestData(
|
||||
privateKeyPem,
|
||||
tree,
|
||||
nameAndDob_smt,
|
||||
nameAndYob_smt,
|
||||
'333',
|
||||
'1234',
|
||||
'585225',
|
||||
'0',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
await circuit.checkConstraints(w);
|
||||
});
|
||||
|
||||
it('should reveal gender only', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs } = prepareAadhaarDiscloseTestData(
|
||||
privateKeyPem,
|
||||
tree,
|
||||
nameAndDob_smt,
|
||||
nameAndYob_smt,
|
||||
'333',
|
||||
'1234',
|
||||
'585225',
|
||||
'0',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
// Use createSelector to generate selector for revealing only gender
|
||||
const selector = createSelector(['GENDER']);
|
||||
inputs.selector = formatInput(selector)[0];
|
||||
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
await circuit.checkConstraints(w);
|
||||
|
||||
const revealedData = await circuit.getOutput(w, [`revealData_packed[4]`]);
|
||||
|
||||
const revealedData_packed = getPackedRevealData(revealedData);
|
||||
const revealedDataUnpacked = unpackReveal(revealedData_packed, 'id');
|
||||
|
||||
// Use extractField to get field values
|
||||
const gender = extractField(revealedDataUnpacked, 'GENDER');
|
||||
const minimumAge = extractField(revealedDataUnpacked, 'MINIMUM_AGE_VALID');
|
||||
|
||||
assert(gender === 'M', 'Gender should be Male');
|
||||
assert(minimumAge.toString() === inputs.minimumAge[0], 'Minimum Age should be 0');
|
||||
});
|
||||
|
||||
it('should reveal yob, mob, dob, reveal_ofac_name_yob only', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs } = prepareAadhaarDiscloseTestData(
|
||||
privateKeyPem,
|
||||
tree,
|
||||
nameAndDob_smt,
|
||||
nameAndYob_smt,
|
||||
'333',
|
||||
'1234',
|
||||
'585225',
|
||||
'0',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
// Use createSelector to generate selector for revealing birth date and OFAC check
|
||||
const selector = createSelector([
|
||||
'YEAR_OF_BIRTH',
|
||||
'MONTH_OF_BIRTH',
|
||||
'DAY_OF_BIRTH',
|
||||
'OFAC_NAME_YOB_CHECK',
|
||||
]);
|
||||
inputs.selector = formatInput(selector)[0];
|
||||
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
await circuit.checkConstraints(w);
|
||||
|
||||
const revealedData = await circuit.getOutput(w, [`revealData_packed[4]`, 'reveal_photoHash']);
|
||||
|
||||
const revealedData_packed = getPackedRevealData(revealedData);
|
||||
const revealedDataUnpacked = unpackReveal(revealedData_packed, 'id');
|
||||
|
||||
// Use extractField to get field values
|
||||
const yearOfBirth = extractField(revealedDataUnpacked, 'YEAR_OF_BIRTH');
|
||||
const monthOfBirth = extractField(revealedDataUnpacked, 'MONTH_OF_BIRTH');
|
||||
const dayOfBirth = extractField(revealedDataUnpacked, 'DAY_OF_BIRTH');
|
||||
const ofacNameYobCheck = extractField(revealedDataUnpacked, 'OFAC_NAME_YOB_CHECK');
|
||||
const minimumAge = extractField(revealedDataUnpacked, 'MINIMUM_AGE_VALID');
|
||||
|
||||
// Verify extracted values
|
||||
assert(yearOfBirth === '1984', 'YOB should be 1984');
|
||||
assert(monthOfBirth === '01', 'MOB should be 01');
|
||||
assert(dayOfBirth === '01', 'DOB should be 01');
|
||||
assert(ofacNameYobCheck === 1, 'OFAC Name YOB should be 1 (not in OFAC list)');
|
||||
|
||||
// Verify non-revealed fields are null
|
||||
for (let i = 9; i < 116; i++) {
|
||||
assert(revealedDataUnpacked[i] === '\0', `Output ${i} should be null character`);
|
||||
}
|
||||
|
||||
assert(revealedData.reveal_photoHash === '0', 'Photo Hash should be 0');
|
||||
assert(minimumAge.toString() === inputs.minimumAge[0], 'Minimum Age should be 0');
|
||||
});
|
||||
|
||||
it('ofac_check_result should be 0 if exists in ofac_name_dob_smt and ofac_name_yob_smt', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs } = prepareAadhaarDiscloseTestData(
|
||||
privateKeyPem,
|
||||
tree,
|
||||
nameAndDob_smt,
|
||||
nameAndYob_smt,
|
||||
'333',
|
||||
'1234',
|
||||
'585225',
|
||||
'0',
|
||||
'Abu ABBAS',
|
||||
'10-12-1948',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
// Use createSelector to generate selector for revealing OFAC checks
|
||||
const selector = createSelector(['OFAC_NAME_DOB_CHECK', 'OFAC_NAME_YOB_CHECK']);
|
||||
inputs.selector = formatInput(selector)[0];
|
||||
inputs.minimumAge = ['100'];
|
||||
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
await circuit.checkConstraints(w);
|
||||
|
||||
const revealedData = await circuit.getOutput(w, [`revealData_packed[4]`]);
|
||||
|
||||
const revealedData_packed = getPackedRevealData(revealedData);
|
||||
const revealedDataUnpacked = unpackReveal(revealedData_packed, 'id');
|
||||
|
||||
// Use extractField to get field values
|
||||
const ofacNameDobCheck = extractField(revealedDataUnpacked, 'OFAC_NAME_DOB_CHECK');
|
||||
const ofacNameYobCheck = extractField(revealedDataUnpacked, 'OFAC_NAME_YOB_CHECK');
|
||||
const minimumAge = extractField(revealedDataUnpacked, 'MINIMUM_AGE_VALID');
|
||||
|
||||
// Verify non-revealed fields are null
|
||||
for (let i = 0; i < 115; i++) {
|
||||
assert(revealedDataUnpacked[i] === '\0', `Output ${i} should be null character`);
|
||||
}
|
||||
|
||||
// Verify OFAC checks show person is in OFAC list
|
||||
assert(ofacNameYobCheck === 0, 'OFAC Name YOB should be 0 (in OFAC list)');
|
||||
assert(ofacNameDobCheck === 0, 'OFAC Name DOB should be 0 (in OFAC list)');
|
||||
assert(minimumAge.toString() === '0', 'Minimum Age should be 0');
|
||||
});
|
||||
it('ofac_check_result should be 0 if exists in ofac_name_dob_reverse_smt and ofac_name_yob_reverse_smt', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs } = prepareAadhaarDiscloseTestData(
|
||||
privateKeyPem,
|
||||
tree,
|
||||
nameAndDob_smt,
|
||||
nameAndYob_smt,
|
||||
'333',
|
||||
'1234',
|
||||
'585225',
|
||||
'0',
|
||||
'ABBAS ABU',
|
||||
'10-12-1948',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
// Use createSelector to generate selector for revealing OFAC checks
|
||||
const selector = createSelector(['OFAC_NAME_DOB_CHECK', 'OFAC_NAME_YOB_CHECK']);
|
||||
inputs.selector = formatInput(selector)[0];
|
||||
inputs.minimumAge = ['100'];
|
||||
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
await circuit.checkConstraints(w);
|
||||
|
||||
const revealedData = await circuit.getOutput(w, [`revealData_packed[4]`]);
|
||||
|
||||
const revealedData_packed = getPackedRevealData(revealedData);
|
||||
const revealedDataUnpacked = unpackReveal(revealedData_packed, 'id');
|
||||
|
||||
// Use extractField to get field values
|
||||
const ofacNameDobCheck = extractField(revealedDataUnpacked, 'OFAC_NAME_DOB_CHECK');
|
||||
const ofacNameYobCheck = extractField(revealedDataUnpacked, 'OFAC_NAME_YOB_CHECK');
|
||||
const minimumAge = extractField(revealedDataUnpacked, 'MINIMUM_AGE_VALID');
|
||||
|
||||
// Verify non-revealed fields are null
|
||||
for (let i = 0; i < 115; i++) {
|
||||
assert(revealedDataUnpacked[i] === '\0', `Output ${i} should be null character`);
|
||||
}
|
||||
|
||||
// Verify OFAC checks show person is in OFAC list
|
||||
assert(ofacNameYobCheck === 0, 'OFAC Name YOB should be 0 (in OFAC list)');
|
||||
assert(ofacNameDobCheck === 0, 'OFAC Name DOB should be 0 (in OFAC list)');
|
||||
assert(minimumAge.toString() === '0', 'Minimum Age should be 0');
|
||||
});
|
||||
});
|
||||
253
circuits/tests/other_circuits/qrdata_extractor.test.ts
Normal file
253
circuits/tests/other_circuits/qrdata_extractor.test.ts
Normal file
@@ -0,0 +1,253 @@
|
||||
import { expect } from 'chai';
|
||||
import path from 'path';
|
||||
import { wasm as wasm_tester } from 'circom_tester';
|
||||
import { testQRData } from '../../../common/src/utils/aadhaar/assets/dataInput.js';
|
||||
import { sha256Pad } from '@zk-email/helpers/dist/sha-utils.js';
|
||||
import { Uint8ArrayToCharArray } from '@zk-email/helpers/dist/binary-format.js';
|
||||
import { convertBigIntToByteArray, decompressByteArray } from '@anon-aadhaar/core';
|
||||
import { assert } from 'chai';
|
||||
import { testCustomData } from '../utils/aadhaar/generateTestData.js';
|
||||
import { generateTestData } from '@selfxyz/common';
|
||||
import { fileURLToPath } from 'url';
|
||||
import fs from 'fs';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const privateKeyPem = fs.readFileSync(
|
||||
path.join(__dirname, '../../../node_modules/anon-aadhaar-circuits/assets/testPrivateKey.pem'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
describe('Aadhaar QR Data Extractor1', function () {
|
||||
let circuit: any;
|
||||
this.beforeAll(async function () {
|
||||
this.timeout(0);
|
||||
circuit = await wasm_tester(
|
||||
path.join(__dirname, '../../circuits/tests/utils/extractQrData_tester.circom'),
|
||||
{
|
||||
verbose: true,
|
||||
logOutput: true,
|
||||
include: [
|
||||
'../node_modules',
|
||||
'../node_modules/anon-aadhaar-circuits/src/helpers/constants.circom',
|
||||
'../node_modules/circomlib/circuits',
|
||||
],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should compile and load the circuit', async function () {
|
||||
this.timeout(0);
|
||||
expect(circuit).to.not.be.undefined;
|
||||
});
|
||||
|
||||
it('should extract qr data', async function () {
|
||||
this.timeout(0);
|
||||
const QRDataBytes = convertBigIntToByteArray(BigInt(testQRData.testQRData));
|
||||
const QRDataDecode = decompressByteArray(QRDataBytes);
|
||||
|
||||
const signedData = QRDataDecode.slice(0, QRDataDecode.length - 256);
|
||||
|
||||
const [qrDataPadded, qrDataPaddedLen] = sha256Pad(signedData, 512 * 3);
|
||||
|
||||
const delimiterIndices: number[] = [];
|
||||
for (let i = 0; i < qrDataPadded.length; i++) {
|
||||
if (qrDataPadded[i] === 255) {
|
||||
delimiterIndices.push(i);
|
||||
}
|
||||
if (delimiterIndices.length === 18) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let photoEOI = 0;
|
||||
for (let i = delimiterIndices[17]; i < qrDataPadded.length - 1; i++) {
|
||||
if (qrDataPadded[i + 1] === 217 && qrDataPadded[i] === 255) {
|
||||
photoEOI = i + 1;
|
||||
}
|
||||
}
|
||||
if (photoEOI === 0) {
|
||||
throw new Error('Photo EOI not found');
|
||||
}
|
||||
|
||||
const witness: any[] = await circuit.calculateWitness({
|
||||
data: Uint8ArrayToCharArray(qrDataPadded),
|
||||
qrDataPaddedLength: qrDataPaddedLen,
|
||||
delimiterIndices: delimiterIndices,
|
||||
photoEOI: photoEOI,
|
||||
});
|
||||
|
||||
const out = await circuit.getOutput(witness, [
|
||||
'name[62]',
|
||||
'yob[4]',
|
||||
'mob[2]',
|
||||
'dob[2]',
|
||||
'gender',
|
||||
'pincode[6]',
|
||||
'state[31]',
|
||||
'aadhaar_last_4digits[4]',
|
||||
'ph_no_last_4digits[4]',
|
||||
'timestamp',
|
||||
]);
|
||||
|
||||
await circuit.checkConstraints(witness);
|
||||
|
||||
const paddedName = 'Sumit Kumar'
|
||||
.padEnd(62, '\0')
|
||||
.split('')
|
||||
.map((char) => char.charCodeAt(0));
|
||||
|
||||
for (let i = 0; i < 62; i++) {
|
||||
assert(Number(out[`name[${i}]`]) === paddedName[i], `Name mismatch at index ${i}`);
|
||||
}
|
||||
|
||||
const yearAscii = '1984'.split('').map((char) => char.charCodeAt(0));
|
||||
for (let i = 0; i < 4; i++) {
|
||||
assert(Number(out[`yob[${i}]`]) === yearAscii[i], `YOB mismatch at index ${i}`);
|
||||
}
|
||||
|
||||
const monthAscii = '01'.split('').map((char) => char.charCodeAt(0));
|
||||
for (let i = 0; i < 2; i++) {
|
||||
assert(Number(out[`mob[${i}]`]) === monthAscii[i], `MOB mismatch at index ${i}`);
|
||||
}
|
||||
|
||||
const dayAscii = '01'.split('').map((char) => char.charCodeAt(0));
|
||||
for (let i = 0; i < 2; i++) {
|
||||
assert(Number(out[`dob[${i}]`]) === dayAscii[i], `DOB mismatch at index ${i}`);
|
||||
}
|
||||
|
||||
assert(Number(out.gender) === 77);
|
||||
|
||||
const pincodeAscii = '110051'.split('').map((char) => char.charCodeAt(0));
|
||||
for (let i = 0; i < 6; i++) {
|
||||
assert(Number(out[`pincode[${i}]`]) === pincodeAscii[i], `PINCODE mismatch at index ${i}`);
|
||||
}
|
||||
|
||||
const aadhaarLast4DigitsAscii = '2697'.split('').map((char) => char.charCodeAt(0));
|
||||
for (let i = 0; i < 4; i++) {
|
||||
assert(
|
||||
Number(out[`aadhaar_last_4digits[${i}]`]) === aadhaarLast4DigitsAscii[i],
|
||||
`AADHAAR mismatch at index ${i}`
|
||||
);
|
||||
}
|
||||
|
||||
const phNoLast4DigitsAscii = '1234'.split('').map((char) => char.charCodeAt(0));
|
||||
for (let i = 0; i < 4; i++) {
|
||||
assert(
|
||||
Number(out[`ph_no_last_4digits[${i}]`]) === phNoLast4DigitsAscii[i],
|
||||
`PHONE mismatch at index ${i}`
|
||||
);
|
||||
}
|
||||
|
||||
for (let i = 0; i < 31; i++) {
|
||||
assert(
|
||||
Number(out[`state[${i}]`]) ===
|
||||
'Delhi'
|
||||
.padEnd(31, '\0')
|
||||
.split('')
|
||||
.map((char) => char.charCodeAt(0))[i],
|
||||
`STATE mismatch at index ${i}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should extract qr data from the new test data', async function () {
|
||||
this.timeout(0);
|
||||
const newTestData = generateTestData({
|
||||
privKeyPem: privateKeyPem,
|
||||
data: testCustomData,
|
||||
gender: 'F',
|
||||
dob: '15-12-2012',
|
||||
pincode: '554587',
|
||||
state: 'Karnataka',
|
||||
name: 'KL RAHUL',
|
||||
});
|
||||
const QRDataBytes = convertBigIntToByteArray(BigInt(newTestData.testQRData));
|
||||
const QRDataDecode = decompressByteArray(QRDataBytes);
|
||||
|
||||
const signedData = QRDataDecode.slice(0, QRDataDecode.length - 256);
|
||||
const [qrDataPadded, qrDataPaddedLen] = sha256Pad(signedData, 512 * 3);
|
||||
|
||||
const delimiterIndices: number[] = [];
|
||||
for (let i = 0; i < qrDataPadded.length; i++) {
|
||||
if (qrDataPadded[i] === 255) {
|
||||
delimiterIndices.push(i);
|
||||
}
|
||||
if (delimiterIndices.length === 18) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let photoEOI = 0;
|
||||
for (let i = delimiterIndices[17]; i < qrDataPadded.length - 1; i++) {
|
||||
if (qrDataPadded[i + 1] === 217 && qrDataPadded[i] === 255) {
|
||||
photoEOI = i + 1;
|
||||
}
|
||||
}
|
||||
if (photoEOI === 0) {
|
||||
throw new Error('Photo EOI not found');
|
||||
}
|
||||
|
||||
const witness: any[] = await circuit.calculateWitness({
|
||||
data: Uint8ArrayToCharArray(qrDataPadded),
|
||||
qrDataPaddedLength: qrDataPaddedLen,
|
||||
delimiterIndices: delimiterIndices,
|
||||
photoEOI: photoEOI,
|
||||
});
|
||||
|
||||
const out = await circuit.getOutput(witness, [
|
||||
'name[62]',
|
||||
'yob[4]',
|
||||
'mob[2]',
|
||||
'dob[2]',
|
||||
'gender',
|
||||
'pincode[6]',
|
||||
'state[31]',
|
||||
'aadhaar_last_4digits[4]',
|
||||
'ph_no_last_4digits[4]',
|
||||
'timestamp',
|
||||
]);
|
||||
|
||||
await circuit.checkConstraints(witness);
|
||||
|
||||
const nameAscii = 'KL RAHUL'
|
||||
.padEnd(62, '\0')
|
||||
.split('')
|
||||
.map((char) => char.charCodeAt(0));
|
||||
for (let i = 0; i < 62; i++) {
|
||||
assert(Number(out[`name[${i}]`]) === nameAscii[i], `NAME mismatch at index ${i}`);
|
||||
}
|
||||
|
||||
const yearAscii = '2012'.split('').map((char) => char.charCodeAt(0));
|
||||
for (let i = 0; i < 4; i++) {
|
||||
assert(Number(out[`yob[${i}]`]) === yearAscii[i], `YOB mismatch at index ${i}`);
|
||||
}
|
||||
|
||||
const monthAscii = '12'.split('').map((char) => char.charCodeAt(0));
|
||||
for (let i = 0; i < 2; i++) {
|
||||
assert(Number(out[`mob[${i}]`]) === monthAscii[i], `MOB mismatch at index ${i}`);
|
||||
}
|
||||
|
||||
const dayAscii = '15'.split('').map((char) => char.charCodeAt(0));
|
||||
for (let i = 0; i < 2; i++) {
|
||||
assert(Number(out[`dob[${i}]`]) === dayAscii[i], `DOB mismatch at index ${i}`);
|
||||
}
|
||||
|
||||
assert(Number(out.gender) === 70);
|
||||
|
||||
const pincodeAscii = '554587'.split('').map((char) => char.charCodeAt(0));
|
||||
for (let i = 0; i < 6; i++) {
|
||||
assert(Number(out[`pincode[${i}]`]) === pincodeAscii[i], `PINCODE mismatch at index ${i}`);
|
||||
}
|
||||
|
||||
for (let i = 0; i < 31; i++) {
|
||||
assert(
|
||||
Number(out[`state[${i}]`]) ===
|
||||
'Karnataka'
|
||||
.padEnd(31, '\0')
|
||||
.split('')
|
||||
.map((char) => char.charCodeAt(0))[i],
|
||||
`STATE mismatch at index ${i}`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
161
circuits/tests/register/pubkeys.ts
Normal file
161
circuits/tests/register/pubkeys.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
export const pubkeys = [
|
||||
`-----BEGIN CERTIFICATE-----
|
||||
MIIHwjCCBqqgAwIBAgIEU5laMzANBgkqhkiG9w0BAQsFADCB/DELMAkGA1UEBhMC
|
||||
SU4xQTA/BgNVBAoTOEd1amFyYXQgTmFybWFkYSBWYWxsZXkgRmVydGlsaXplcnMg
|
||||
YW5kIENoZW1pY2FscyBMaW1pdGVkMR0wGwYDVQQLExRDZXJ0aWZ5aW5nIEF1dGhv
|
||||
cml0eTEPMA0GA1UEERMGMzgwMDU0MRAwDgYDVQQIEwdHdWphcmF0MSYwJAYDVQQJ
|
||||
Ex1Cb2Rha2RldiwgUyBHIFJvYWQsIEFobWVkYWJhZDEcMBoGA1UEMxMTMzAxLCBH
|
||||
TkZDIEluZm90b3dlcjEiMCAGA1UEAxMZKG4pQ29kZSBTb2x1dGlvbnMgQ0EgMjAx
|
||||
NDAeFw0yMTAyMjYxMTU0MjRaFw0yNDAyMjcwMDI3MTFaMIHdMQswCQYDVQQGEwJJ
|
||||
TjExMC8GA1UEChMoVU5JUVVFIElERU5USUZJQ0FUSU9OIEFVVEhPUklUWSBPRiBJ
|
||||
TkRJQTEPMA0GA1UEERMGMTEwMDAxMQ4wDAYDVQQIEwVEZWxoaTEbMBkGA1UECRMS
|
||||
QkVISU5EIEtBTEkgTUFORElSMSQwIgYDVQQzExtBQURIQVIgSFEgQkFOR0xBIFNB
|
||||
SElCIFJPQUQxNzA1BgNVBAMTLkRTIFVOSVFVRSBJREVOVElGSUNBVElPTiBBVVRI
|
||||
T1JJVFkgT0YgSU5ESUEgMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
||||
AQCiciwOXy3lunB+2T8DbsKx8LlVkyOQ+swPC8vyDIChXAiLSIaGa3LrJasL9Vov
|
||||
4Gtp7b1cyDt0x3CdshQebAfGi834WdPa9/P87SQdByBV3BVIhHS0XCyYL6lUqlKq
|
||||
b/+ySBhhxlCF2EtkFY6fQ9nzXKabSM6TAFIhAqTK4JO//UdLCNMtHQQG9of35VvS
|
||||
JqI4S/WKQcOEw5dPHHxRFYGckm3jrfPsu5kExIbx9dUwOXe+pjWENnMptcFor9yV
|
||||
Ehcx9/SNQ6988x9pseO755Sdx6ixDAvd66ur3r6gdqHPgWat8GqKQd7fFDv/g129
|
||||
K9W7C2HSRywjSm1EEbybU2CVAgMBAAGjggNnMIIDYzAOBgNVHQ8BAf8EBAMCBsAw
|
||||
KgYDVR0lBCMwIQYIKwYBBQUHAwQGCisGAQQBgjcKAwwGCSqGSIb3LwEBBTCCAQIG
|
||||
A1UdIASB+jCB9zCBhgYGYIJkZAICMHwwegYIKwYBBQUHAgIwbgxsQ2xhc3MgMiBj
|
||||
ZXJ0aWZpY2F0ZXMgYXJlIHVzZWQgZm9yIGZvcm0gc2lnbmluZywgZm9ybSBhdXRo
|
||||
ZW50aWNhdGlvbiBhbmQgc2lnbmluZyBvdGhlciBsb3cgcmlzayB0cmFuc2FjdGlv
|
||||
bnMuMGwGBmCCZGQKATBiMGAGCCsGAQUFBwICMFQMUlRoaXMgY2VydGlmaWNhdGUg
|
||||
cHJvdmlkZXMgaGlnaGVyIGxldmVsIG9mIGFzc3VyYW5jZSBmb3IgZG9jdW1lbnQg
|
||||
c2lnbmluZyBmdW5jdGlvbi4wDAYDVR0TAQH/BAIwADAjBgNVHREEHDAagRhyYWh1
|
||||
bC5rdW1hckB1aWRhaS5uZXQuaW4wggFuBgNVHR8EggFlMIIBYTCCAR6gggEaoIIB
|
||||
FqSCARIwggEOMQswCQYDVQQGEwJJTjFBMD8GA1UEChM4R3VqYXJhdCBOYXJtYWRh
|
||||
IFZhbGxleSBGZXJ0aWxpemVycyBhbmQgQ2hlbWljYWxzIExpbWl0ZWQxHTAbBgNV
|
||||
BAsTFENlcnRpZnlpbmcgQXV0aG9yaXR5MQ8wDQYDVQQREwYzODAwNTQxEDAOBgNV
|
||||
BAgTB0d1amFyYXQxJjAkBgNVBAkTHUJvZGFrZGV2LCBTIEcgUm9hZCwgQWhtZWRh
|
||||
YmFkMRwwGgYDVQQzExMzMDEsIEdORkMgSW5mb3Rvd2VyMSIwIAYDVQQDExkobilD
|
||||
b2RlIFNvbHV0aW9ucyBDQSAyMDE0MRAwDgYDVQQDEwdDUkw1Njk0MD2gO6A5hjdo
|
||||
dHRwczovL3d3dy5uY29kZXNvbHV0aW9ucy5jb20vcmVwb3NpdG9yeS9uY29kZWNh
|
||||
MTQuY3JsMCsGA1UdEAQkMCKADzIwMjEwMjI2MTE1NDI0WoEPMjAyNDAyMjcwMDI3
|
||||
MTFaMBMGA1UdIwQMMAqACE0HvvGenfu9MB0GA1UdDgQWBBTpS5Cfqf2zdwqjupLA
|
||||
qMwk/bqX9DAZBgkqhkiG9n0HQQAEDDAKGwRWOC4xAwIDKDANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAbTlOC4sonzb44+u5+VZ3wGz3OFg0uJGsufbBu5efh7kO2DlYnx7okdEf
|
||||
ayQQs6AUzDvsH1yBSBjsaZo3fwBgQUIMaNKdKSrRI0eOTDqilizldHqj113f4eUz
|
||||
U2j4okcNSF7TxQWMjxwyM86QsQ6vxZK7arhBhVjwp443+pxfSIdFUu428K6yH4JB
|
||||
GhZSzWuqD6GNhOhDzS+sS23MkwHFq0GX4erhVfN/W7XLeSjzF4zmjg+O77vTySCN
|
||||
e2VRYDrfFS8EAOcO4q7szc7+6xdg8RlgzoZHoRG/GqUp9inpJUn7OIzhHi2e8Mll
|
||||
aMdtXo0nbr150tMe8ZSvY2fMiTCY1w==
|
||||
-----END CERTIFICATE-----`,
|
||||
`-----BEGIN CERTIFICATE-----
|
||||
MIIHCjCCBfKgAwIBAgIEYklh9TANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UEBhMC
|
||||
SU4xQTA/BgNVBAoTOEd1amFyYXQgTmFybWFkYSBWYWxsZXkgRmVydGlsaXplcnMg
|
||||
YW5kIENoZW1pY2FscyBMaW1pdGVkMQ8wDQYDVQQLEwZTdWItQ0ExLjAsBgNVBAMT
|
||||
JShuKUNvZGUgU29sdXRpb25zIFN1Yi1DQSBmb3IgRFNDIDIwMjIwHhcNMjQwMjIx
|
||||
MTIyMzE5WhcNMjYwMjE2MjIyNzQwWjCB8zELMAkGA1UEBhMCSU4xMTAvBgNVBAoT
|
||||
KFVOSVFVRSBJREVOVElGSUNBVElPTiBBVVRIT1JJVFkgT0YgSU5ESUExDzANBgNV
|
||||
BBETBjExMDAwMTEOMAwGA1UECBMFRGVsaGkxODA2BgNVBAkTL0JhbmdsYSBTYWhp
|
||||
YiBSb2FkIEJlaGluZCBLYWxpIE1hbmRpciBHb2xlTWFya2V0MR0wGwYDVQQzExRB
|
||||
YWRoYWFyIEhlYWRxdWFydGVyczE3MDUGA1UEAxMuRFMgVW5pcXVlIElkZW50aWZp
|
||||
Y2F0aW9uIEF1dGhvcml0eSBvZiBJbmRpYSAwNTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAJjCCSo9vCXEzdQe9qdv6YMwwqILobP62yF4Df8mzTYdDVTq
|
||||
2VdipZa5k+VTmJTKwAabyKeyVP5+oZmt/zteJ+5754Cf8t3KJYfK5O5rA8FQDu2b
|
||||
lQ/hgs32mDyy5FEvsKh+zOxThyJ/6ciaNUZMZvfJTt3cqMeUbixtlKpuyX1SKJpt
|
||||
Le0CiaDOa3/CTbz13cLMTfPXlpU9gX+wRf/xtxSohe2R37yMsqrXv96K0URvzPNE
|
||||
Ki6wz9USHjmud2U4CC13MkDm9smTqjR94jdrkikbLrDTte06ORTm9ifR3ecCDLg7
|
||||
988ODFk6ygFrk2KJ/dEEnhkSr9XeQEDUbdMeXUsCAwEAAaOCAwQwggMAMA4GA1Ud
|
||||
DwEB/wQEAwIGwDAqBgNVHSUEIzAhBggrBgEFBQcDBAYKKwYBBAGCNwoDDAYJKoZI
|
||||
hvcvAQEFMIIBAgYDVR0gBIH6MIH3MIGGBgZggmRkAgIwfDB6BggrBgEFBQcCAjBu
|
||||
DGxDbGFzcyAyIGNlcnRpZmljYXRlcyBhcmUgdXNlZCBmb3IgZm9ybSBzaWduaW5n
|
||||
LCBmb3JtIGF1dGhlbnRpY2F0aW9uIGFuZCBzaWduaW5nIG90aGVyIGxvdyByaXNr
|
||||
IHRyYW5zYWN0aW9ucy4wbAYGYIJkZAoBMGIwYAYIKwYBBQUHAgIwVAxSVGhpcyBj
|
||||
ZXJ0aWZpY2F0ZSBwcm92aWRlcyBoaWdoZXIgbGV2ZWwgb2YgYXNzdXJhbmNlIGZv
|
||||
ciBkb2N1bWVudCBzaWduaW5nIGZ1bmN0aW9uLjAMBgNVHRMBAf8EAjAAMCIGA1Ud
|
||||
EQQbMBmBF2Rpci5sY2ktaHFAdWlkYWkubmV0LmluMIIBAAYDVR0fBIH4MIH1MEKg
|
||||
QKA+hjxodHRwOi8vd3d3Lm5jb2Rlc29sdXRpb25zLmNvbS9yZXBvc2l0b3J5L25j
|
||||
b2RlY2EyMnN1YmNhMS5jcmwwga6ggauggaikgaUwgaIxCzAJBgNVBAYTAklOMUEw
|
||||
PwYDVQQKEzhHdWphcmF0IE5hcm1hZGEgVmFsbGV5IEZlcnRpbGl6ZXJzIGFuZCBD
|
||||
aGVtaWNhbHMgTGltaXRlZDEPMA0GA1UECxMGU3ViLUNBMS4wLAYDVQQDEyUobilD
|
||||
b2RlIFNvbHV0aW9ucyBTdWItQ0EgZm9yIERTQyAyMDIyMQ8wDQYDVQQDEwZDUkwx
|
||||
ODMwKwYDVR0QBCQwIoAPMjAyNDAyMjExMjIzMTlagQ8yMDI2MDIxNjIyMjc0MFow
|
||||
HwYDVR0jBBgwFoAURsE2obZEOWzewDFm8UhoheJjvzswHQYDVR0OBBYEFKzhXAem
|
||||
Tyikhe8ZRfMcBEnWfEfTMBkGCSqGSIb2fQdBAAQMMAobBFY4LjMDAgMoMA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQAw7POBP18z1+IG4bjBk6vgfIyTH6Vz+e1j7jcmG+sUfY0E
|
||||
GVKonznB87M4hNcVcylDrwZscJwZxKaYUAt/q1Uph46v37jRjZyAvawZBD/oL1lS
|
||||
qUmIGQxI+zqUFYrc5dWSHROoCGfkyHAskr60Y3tN489NKo+AsFC1iu1dY29FW2hK
|
||||
Wt1dQEDYkTeYJu8WPf/XaOR562gq566IFgL6cpYujNrMuKOGj+5o2UbjmCTjkbTp
|
||||
HdTU+Mja3mYfUDdBia4YVQwDXB07xZD7FiMbhm1oYsATfjiFA1jCy3X8q9dsFkMe
|
||||
tMjs/7td7cCA1L45savQhcL7+c902NZMolXgRnFx
|
||||
-----END CERTIFICATE-----`,
|
||||
`-----BEGIN CERTIFICATE-----
|
||||
MIIHzzCCBregAwIBAgIEU5Sx5TANBgkqhkiG9w0BAQsFADCB/DELMAkGA1UEBhMCSU4xQTA/BgNV
|
||||
BAoTOEd1amFyYXQgTmFybWFkYSBWYWxsZXkgRmVydGlsaXplcnMgYW5kIENoZW1pY2FscyBMaW1p
|
||||
dGVkMR0wGwYDVQQLExRDZXJ0aWZ5aW5nIEF1dGhvcml0eTEPMA0GA1UEERMGMzgwMDU0MRAwDgYD
|
||||
VQQIEwdHdWphcmF0MSYwJAYDVQQJEx1Cb2Rha2RldiwgUyBHIFJvYWQsIEFobWVkYWJhZDEcMBoG
|
||||
A1UEMxMTMzAxLCBHTkZDIEluZm90b3dlcjEiMCAGA1UEAxMZKG4pQ29kZSBTb2x1dGlvbnMgQ0Eg
|
||||
MjAxNDAeFw0xOTAzMTUwODQ0NDFaFw0yMTAyMjgxNzM0MzZaMIHpMQswCQYDVQQGEwJJTjExMC8G
|
||||
A1UEChMoVU5JUVVFIElERU5USUZJQ0FUSU9OIEFVVEhPUklUWSBPRiBJTkRJQTEPMA0GA1UEERMG
|
||||
MTEwMDAxMQ4wDAYDVQQIEwVEZWxoaTEnMCUGA1UECRMeQkVISU5EIEtBTEkgTUFORElSIEdPTEUg
|
||||
TUFSS0VUMSQwIgYDVQQzExs2dGggRkxPT1IgQkFOR0xBIFNBSElCIFJPQUQxNzA1BgNVBAMTLkRT
|
||||
IFVOSVFVRSBJREVOVElGSUNBVElPTiBBVVRIT1JJVFkgT0YgSU5ESUEgMDQwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQCbdqONzc5CFOQ/3YKeZgSNcDBUbQoTkAe7p7mGXHW3bOnrKz2k
|
||||
5WXNVMt1EVaPfItFtJ497vl7ZRN63QlQKtoXv82tewBE/KMOhVxNOXKP4kRw5gjtVTCD17flenjs
|
||||
AM2yjofMeEbUUn0MzKVYw/t7Chv9nQudunUzhlgZMET9tnCt85GZmOXxkrMTF3a7NIMa72pxfQHp
|
||||
sIu/GXApKht8K1OBYihk/Tr4dwq4nnvR+Lpnxbt6lsv849/3Z4pTLLf1bTQplx64cUaifCEsIX/i
|
||||
3tozJKulV/rnCVrx07Y29fKVZHJXuPqtHoOdRIVBlI6Bm4nI/EwtLd8TMgQ53zZZAgMBAAGjggNo
|
||||
MIIDZDAOBgNVHQ8BAf8EBAMCBsAwKgYDVR0lBCMwIQYIKwYBBQUHAwQGCisGAQQBgjcKAwwGCSqG
|
||||
SIb3LwEBBTCCAQIGA1UdIASB+jCB9zCBhgYGYIJkZAICMHwwegYIKwYBBQUHAgIwbgxsQ2xhc3Mg
|
||||
MiBjZXJ0aWZpY2F0ZXMgYXJlIHVzZWQgZm9yIGZvcm0gc2lnbmluZywgZm9ybSBhdXRoZW50aWNh
|
||||
dGlvbiBhbmQgc2lnbmluZyBvdGhlciBsb3cgcmlzayB0cmFuc2FjdGlvbnMuMGwGBmCCZGQKATBi
|
||||
MGAGCCsGAQUFBwICMFQMUlRoaXMgY2VydGlmaWNhdGUgcHJvdmlkZXMgaGlnaGVyIGxldmVsIG9m
|
||||
IGFzc3VyYW5jZSBmb3IgZG9jdW1lbnQgc2lnbmluZyBmdW5jdGlvbi4wDAYDVR0TAQH/BAIwADAk
|
||||
BgNVHREEHTAbgRlhamFpLmNoYW5kcmFAdWlkYWkubmV0LmluMIIBbgYDVR0fBIIBZTCCAWEwggEe
|
||||
oIIBGqCCARakggESMIIBDjELMAkGA1UEBhMCSU4xQTA/BgNVBAoTOEd1amFyYXQgTmFybWFkYSBW
|
||||
YWxsZXkgRmVydGlsaXplcnMgYW5kIENoZW1pY2FscyBMaW1pdGVkMR0wGwYDVQQLExRDZXJ0aWZ5
|
||||
aW5nIEF1dGhvcml0eTEPMA0GA1UEERMGMzgwMDU0MRAwDgYDVQQIEwdHdWphcmF0MSYwJAYDVQQJ
|
||||
Ex1Cb2Rha2RldiwgUyBHIFJvYWQsIEFobWVkYWJhZDEcMBoGA1UEMxMTMzAxLCBHTkZDIEluZm90
|
||||
b3dlcjEiMCAGA1UEAxMZKG4pQ29kZSBTb2x1dGlvbnMgQ0EgMjAxNDEQMA4GA1UEAxMHQ1JMNTUw
|
||||
ODA9oDugOYY3aHR0cHM6Ly93d3cubmNvZGVzb2x1dGlvbnMuY29tL3JlcG9zaXRvcnkvbmNvZGVj
|
||||
YTE0LmNybDArBgNVHRAEJDAigA8yMDE5MDMxNTA4NDQ0MVqBDzIwMjEwMjI4MTczNDM2WjATBgNV
|
||||
HSMEDDAKgAhNB77xnp37vTAdBgNVHQ4EFgQUPVMv6SCRjsMNXoJoTys9LxJ2dDAwGQYJKoZIhvZ9
|
||||
B0EABAwwChsEVjguMQMCAygwDQYJKoZIhvcNAQELBQADggEBAJ378HWZ4HdVxMioDWNrWrnWi29D
|
||||
TOhEEGnBTLuKVBkgxT+MDJIdbDb6fXcPJH16BczZ6cauGKmRhkAb7/d74a/Vhro6mf9qMhbxMxE4
|
||||
/FgXQk4MSqhJR9+9u7sAXVEUu8UE3XPsl+NaBTRfha1hegypDSkmlBVMJH4uYNB09zRXPieO1CLY
|
||||
CMJExuZ18n0KJ7/QfrxNgcp9Hkwcib044PfvIXIzjU+O7LUlwk5x5jbVEtwECwPGyQV6O9OInh2H
|
||||
d5PKhaNTJUCnoF6djlW8cf6eten7l21iBtFNAvKBfikmBOMZXe6cB+9ShOCOKz5zSzUwW+eZHSM4
|
||||
3qCQ9G39img=
|
||||
-----END CERTIFICATE-----`,
|
||||
`-----BEGIN CERTIFICATE-----
|
||||
MIIHbjCCBlagAwIBAgIEU2dtwjANBgkqhkiG9w0BAQsFADCB/DELMAkGA1UEBhMCSU4xQTA/BgNV
|
||||
BAoTOEd1amFyYXQgTmFybWFkYSBWYWxsZXkgRmVydGlsaXplcnMgYW5kIENoZW1pY2FscyBMaW1p
|
||||
dGVkMR0wGwYDVQQLExRDZXJ0aWZ5aW5nIEF1dGhvcml0eTEPMA0GA1UEERMGMzgwMDU0MRAwDgYD
|
||||
VQQIEwdHdWphcmF0MSYwJAYDVQQJEx1Cb2Rha2RldiwgUyBHIFJvYWQsIEFobWVkYWJhZDEcMBoG
|
||||
A1UEMxMTMzAxLCBHTkZDIEluZm90b3dlcjEiMCAGA1UEAxMZKG4pQ29kZSBTb2x1dGlvbnMgQ0Eg
|
||||
MjAxNDAeFw0xNzA0MjcwNTMzMDFaFw0xOTA0MDkyMTE5MDVaMIHoMQswCQYDVQQGEwJJTjExMC8G
|
||||
A1UEChMoVU5JUVVFIElERU5USUZJQ0FUSU9OIEFVVEhPUklUWSBPRiBJTkRJQTEPMA0GA1UEERMG
|
||||
MTEwMDAxMQ4wDAYDVQQIEwVERUxISTEZMBcGA1UECRMQQ09OTkFVR0hUIENJUkNVUzExMC8GA1UE
|
||||
MxMoOVRIIEZMT09SIFRPV0VSIDEgSkVFVkFOIEJIQVJUSSBCVUlMRElORzE3MDUGA1UEAxMuRFMg
|
||||
VU5JUVVFIElERU5USUZJQ0FUSU9OIEFVVEhPUklUWSBPRiBJTkRJQSAwMzCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBAL1VPb8KX4uUMP+ym6hXkFiLvpqK2v5shgdna77WIPmFlOxn6V4U
|
||||
2HngL2l5XxYq9Yz6CEC14FCGd0OghzxF2wHXU9/5Bd7RyGegNUaxWa9k/tFSaZOkAI/JGMMjsFMG
|
||||
c70Bayk1eV7x/Alixogsu37DAaMKjaaDfpQVQ9Zr5zXJDhENlrXFjJ+ZMUVhqgAj0UJm4qGROhTy
|
||||
adGWsTvOMQN5eUz+fdKl4/Rtn/6sWjZrlJuPz/Evk+oMYWZVnwVXh/WpdjEe+1XnThckZuPgGD1M
|
||||
x6GO51WyQHSMThgOxztMHBw8jDnilgLArsS3BNVgkhJy3g4mvydtUAlqyggZ1x8CAwEAAaOCAwgw
|
||||
ggMEMA4GA1UdDwEB/wQEAwIGwDCCAQIGA1UdIASB+jCB9zCBhgYGYIJkZAICMHwwegYIKwYBBQUH
|
||||
AgIwbgxsQ2xhc3MgMiBjZXJ0aWZpY2F0ZXMgYXJlIHVzZWQgZm9yIGZvcm0gc2lnbmluZywgZm9y
|
||||
bSBhdXRoZW50aWNhdGlvbiBhbmQgc2lnbmluZyBvdGhlciBsb3cgcmlzayB0cmFuc2FjdGlvbnMu
|
||||
MGwGBmCCZGQKATBiMGAGCCsGAQUFBwICMFQMUlRoaXMgY2VydGlmaWNhdGUgcHJvdmlkZXMgaGln
|
||||
aGVyIGxldmVsIG9mIGFzc3VyYW5jZSBmb3IgZG9jdW1lbnQgc2lnbmluZyBmdW5jdGlvbi4wggFu
|
||||
BgNVHR8EggFlMIIBYTCCAR6gggEaoIIBFqSCARIwggEOMQswCQYDVQQGEwJJTjFBMD8GA1UEChM4
|
||||
R3VqYXJhdCBOYXJtYWRhIFZhbGxleSBGZXJ0aWxpemVycyBhbmQgQ2hlbWljYWxzIExpbWl0ZWQx
|
||||
HTAbBgNVBAsTFENlcnRpZnlpbmcgQXV0aG9yaXR5MQ8wDQYDVQQREwYzODAwNTQxEDAOBgNVBAgT
|
||||
B0d1amFyYXQxJjAkBgNVBAkTHUJvZGFrZGV2LCBTIEcgUm9hZCwgQWhtZWRhYmFkMRwwGgYDVQQz
|
||||
ExMzMDEsIEdORkMgSW5mb3Rvd2VyMSIwIAYDVQQDExkobilDb2RlIFNvbHV0aW9ucyBDQSAyMDE0
|
||||
MRAwDgYDVQQDEwdDUkwzNTYxMD2gO6A5hjdodHRwczovL3d3dy5uY29kZXNvbHV0aW9ucy5jb20v
|
||||
cmVwb3NpdG9yeS9uY29kZWNhMTQuY3JsMCsGA1UdEAQkMCKADzIwMTcwNDI3MDUzMzAxWoEPMjAx
|
||||
OTA0MDkyMTE5MDVaMBMGA1UdIwQMMAqACE0HvvGenfu9MB0GA1UdDgQWBBSZN5Cc6fcvvOnkX6CW
|
||||
zOgsdUIY2jAZBgkqhkiG9n0HQQAEDDAKGwRWOC4xAwIDKDANBgkqhkiG9w0BAQsFAAOCAQEAAkGD
|
||||
0GQmTnjiSxHIvdpgw9OYiRtT5eZ/vf4EY3U8pWDUTeWdBMUWozbY4ic1Z+KV8KlzKy7AJvDwrAX7
|
||||
a3tpCovnI7T83YEiOUxiYd5tgS353EpEhA8BFG/IFRaTkUgs2AaU0L9G3+q4FEZFCmGM1EzsU0Dg
|
||||
GnFUNKvCr0C7fdMY/S9zNny2L84+Km807Nbk1voRc7uv/j1kprYSpSV7Bru++2v5iL+aOYq/hkGQ
|
||||
Mr+7aekDj/As2OJW793WNdJ6Xx4hPQt5TYsS1UvL9Q6ykuIXd9njj/KjMsw1RvJ5prvugdPqNOMp
|
||||
Rf63zec3hTCKWm5YI7NBirwrBd1K14DVBQ==
|
||||
-----END CERTIFICATE-----
|
||||
`,
|
||||
];
|
||||
191
circuits/tests/register/register_aadhaar.test.ts
Normal file
191
circuits/tests/register/register_aadhaar.test.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
import { expect } from 'chai';
|
||||
import { wasm as wasmTester } from 'circom_tester';
|
||||
import path from 'path';
|
||||
import { sha256Pad } from '@zk-email/helpers/dist/sha-utils.js';
|
||||
import { bufferToHex, Uint8ArrayToCharArray } from '@zk-email/helpers/dist/binary-format.js';
|
||||
import { convertBigIntToByteArray, decompressByteArray, splitToWords } from '@anon-aadhaar/core';
|
||||
import assert from 'assert';
|
||||
import { customHasher } from '@selfxyz/common/utils/hash';
|
||||
import {
|
||||
prepareAadhaarRegisterTestData,
|
||||
generateTestData,
|
||||
testCustomData,
|
||||
prepareAadhaarRegisterData,
|
||||
} from '@selfxyz/common';
|
||||
import fs from 'fs';
|
||||
import { pubkeys } from './pubkeys.js';
|
||||
|
||||
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
||||
|
||||
const privateKeyPem = fs.readFileSync(
|
||||
path.join(__dirname, '../../../node_modules/anon-aadhaar-circuits/assets/testPrivateKey.pem'),
|
||||
'utf8'
|
||||
);
|
||||
const publicKeyPem = fs.readFileSync(
|
||||
path.join(__dirname, '../../../common/src/utils/aadhaar/assets/testPublicKey.pem'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
describe('REGISTER AADHAAR Circuit Tests', function () {
|
||||
let circuit: any;
|
||||
this.beforeAll(async function () {
|
||||
this.timeout(0);
|
||||
circuit = await wasmTester(
|
||||
path.join(__dirname, '../../circuits/register/instances/register_aadhaar.circom'),
|
||||
{
|
||||
verbose: true,
|
||||
logOutput: true,
|
||||
include: ['../node_modules'],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should compile and load the circuit', async function () {
|
||||
this.timeout(0);
|
||||
expect(circuit).to.not.be.undefined;
|
||||
});
|
||||
it('should pass constrain check for circuit with Sha256RSA signature', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs } = prepareAadhaarRegisterTestData(privateKeyPem, publicKeyPem, '1234');
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
await circuit.checkConstraints(w);
|
||||
});
|
||||
it('should pass constrain and output correct nullifier and commitment', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs, nullifier, commitment } = prepareAadhaarRegisterTestData(
|
||||
privateKeyPem,
|
||||
publicKeyPem,
|
||||
'1234'
|
||||
);
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
await circuit.checkConstraints(w);
|
||||
|
||||
const out = await circuit.getOutput(w, ['nullifier', 'commitment']);
|
||||
assert(BigInt(out.nullifier) === BigInt(nullifier));
|
||||
assert(BigInt(out.commitment) === BigInt(commitment));
|
||||
});
|
||||
|
||||
it('should not verify the signature of created from different key', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs } = prepareAadhaarRegisterTestData(privateKeyPem, publicKeyPem, '1234');
|
||||
const newTestData = generateTestData({ privKeyPem: privateKeyPem, data: testCustomData });
|
||||
const QRDataBytes = convertBigIntToByteArray(BigInt(newTestData.testQRData));
|
||||
const decodedData = decompressByteArray(QRDataBytes);
|
||||
|
||||
const signatureBytes = decodedData.slice(decodedData.length - 256, decodedData.length);
|
||||
const newSignature = BigInt('0x' + bufferToHex(Buffer.from(signatureBytes)).toString());
|
||||
inputs.signature = splitToWords(newSignature, BigInt(121), BigInt(17));
|
||||
|
||||
try {
|
||||
await circuit.calculateWitness(inputs);
|
||||
expect.fail('Expected circuit.calculateWitness to throw an error, but it succeeded');
|
||||
} catch (error) {
|
||||
expect(error).to.exist;
|
||||
}
|
||||
});
|
||||
|
||||
it('should fail when qrdata is tampered', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs } = prepareAadhaarRegisterTestData(privateKeyPem, publicKeyPem, '1234');
|
||||
|
||||
const newTestData = generateTestData({
|
||||
privKeyPem: privateKeyPem,
|
||||
data: testCustomData,
|
||||
gender: 'F',
|
||||
});
|
||||
const QRDataBytes = convertBigIntToByteArray(BigInt(newTestData.testQRData));
|
||||
const decodedData = decompressByteArray(QRDataBytes);
|
||||
|
||||
const signedData = decodedData.slice(0, decodedData.length - 256);
|
||||
|
||||
const [qrDataPadded, qrDataPaddedLen] = sha256Pad(signedData, 512 * 3);
|
||||
|
||||
inputs.qrDataPadded = Uint8ArrayToCharArray(qrDataPadded);
|
||||
inputs.qrDataPaddedLength = qrDataPaddedLen;
|
||||
|
||||
try {
|
||||
await circuit.calculateWitness(inputs);
|
||||
expect.fail('Expected circuit.calculateWitness to throw an error, but it succeeded');
|
||||
} catch (error) {
|
||||
expect(error).to.exist;
|
||||
}
|
||||
});
|
||||
|
||||
it('should return different commitment when secret is tampered', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs, commitment } = prepareAadhaarRegisterTestData(
|
||||
privateKeyPem,
|
||||
publicKeyPem,
|
||||
'1234'
|
||||
);
|
||||
inputs.secret = '1235';
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
|
||||
const out = await circuit.getOutput(w, ['commitment']);
|
||||
assert(BigInt(out.commitment) !== BigInt(commitment));
|
||||
});
|
||||
|
||||
it('should pass for different qr data', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs, nullifier, commitment } = prepareAadhaarRegisterTestData(
|
||||
privateKeyPem,
|
||||
publicKeyPem,
|
||||
'1234',
|
||||
'KL RAHUL',
|
||||
'18-04-1992'
|
||||
);
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
await circuit.checkConstraints(w);
|
||||
|
||||
const out = await circuit.getOutput(w, ['nullifier', 'commitment']);
|
||||
assert(BigInt(out.nullifier) === BigInt(nullifier));
|
||||
assert(BigInt(out.commitment) === BigInt(commitment));
|
||||
});
|
||||
|
||||
it('should create the pubkey commitment correctly', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs } = prepareAadhaarRegisterTestData(privateKeyPem, publicKeyPem, '1234');
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
await circuit.checkConstraints(w);
|
||||
|
||||
const expectedPubKeyCommitment = customHasher(inputs.pubKey);
|
||||
|
||||
const out = await circuit.getOutput(w, ['pubKeyHash']);
|
||||
assert(BigInt(out.pubKeyHash) === BigInt(expectedPubKeyCommitment));
|
||||
});
|
||||
|
||||
it('should create the timestamp correctly', async function () {
|
||||
this.timeout(0);
|
||||
const { inputs } = prepareAadhaarRegisterTestData(
|
||||
privateKeyPem,
|
||||
publicKeyPem,
|
||||
'1234',
|
||||
'Some Guy',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
new Date(Date.now() - 30 * 60 * 1000).getTime().toString()
|
||||
);
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
await circuit.checkConstraints(w);
|
||||
|
||||
const out = await circuit.getOutput(w, ['timestamp']);
|
||||
});
|
||||
|
||||
it.skip('should work for a real id', async function () {
|
||||
this.timeout(0);
|
||||
const actualQrData = '';
|
||||
const { inputs, nullifier, commitment } = await prepareAadhaarRegisterData(
|
||||
actualQrData,
|
||||
'1234',
|
||||
pubkeys
|
||||
);
|
||||
const w = await circuit.calculateWitness(inputs);
|
||||
await circuit.checkConstraints(w);
|
||||
|
||||
const out = await circuit.getOutput(w, ['nullifier', 'commitment']);
|
||||
assert(BigInt(out.nullifier) === BigInt(nullifier));
|
||||
assert(BigInt(out.commitment) === BigInt(commitment));
|
||||
});
|
||||
});
|
||||
231
circuits/tests/utils/aadhaar/generateTestData.ts
Normal file
231
circuits/tests/utils/aadhaar/generateTestData.ts
Normal file
@@ -0,0 +1,231 @@
|
||||
import {
|
||||
convertBigIntToByteArray,
|
||||
decompressByteArray,
|
||||
returnFullId,
|
||||
rawDataToCompressedQR,
|
||||
returnNewDateString,
|
||||
replaceBytesBetween,
|
||||
IdFields,
|
||||
extractPhoto,
|
||||
getRandomBytes,
|
||||
getEndIndex,
|
||||
} from '@anon-aadhaar/core';
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
||||
|
||||
// This is the official test data issued by the UIDAI
|
||||
// In this script we'll change the signed data to emulate the specs of the Aadhaar QR V2
|
||||
// and sign the data again with our own certificates.
|
||||
// data on https://uidai.gov.in/en/ecosystem/authentication-devices-documents/qr-code-reader.html
|
||||
// This data is copied from https://github.dev/anon-aadhaar/anon-aadhaar/blob/main/packages/circuits/src/helpers/extractor.circom
|
||||
export const testCustomData =
|
||||
'2374971804270526477833002468783965837992554564899874087591661303561346432389832047870524302186901344489362368642972767716416349990805756094923115719687656090691368051627957878187788907419297818953295185555346288172578594637886352753543271000481717080003254556962148594350559820352806251787713278744047402230989238559317351232114240089849934148895256488140236015024800731753594740948640957680138566468247224859669467819596919398964809164399637893729212452791889199675715949918925838319591794702333094022248132120531152523331442741730158840977243402215102904932650832502847295644794421419704633765033761284508863534321317394686768650111457751139630853448637215423705157211510636160227953566227527799608082928846103264491539001327407775670834868948113753614112563650255058316849200536533335903554984254814901522086937767458409075617572843449110393213525925388131214952874629655799772119820372255291052673056372346072235458198199995637720424196884145247220163810790179386390283738429482893152518286247124911446073389185062482901364671389605727763080854673156754021728522287806275420847159574631844674460263574901590412679291518508010087116598357407343835408554094619585212373168435612645646129147973594416508676872819776522537778717985070402222824965034768103900739105784663244748432502180989441389718131079445941981681118258324511923246198334046020123727749408128519721102477302359413240175102907322619462289965085963377744024233678337951462006962521823224880199210318367946130004264196899778609815012001799773327514133268825910089483612283510244566484854597156100473055413090101948456959122378865704840756793122956663218517626099291311352417342899623681483097817511136427210593032393600010728324905512596767095096153856032112835755780472808814199620390836980020899858288860556611564167406292139646289142056168261133256777093245980048335918156712295254776487472431445495668303900536289283098315798552328294391152828182614909451410115516297083658174657554955228963550255866282688308751041517464999930825273776417639569977754844191402927594739069037851707477839207593911886893016618794870530622356073909077832279869798641545167528509966656120623184120128052588408742941658045827255866966100249857968956536613250770326334844204927432961924987891433020671754710428050564671868464658436926086493709176888821257183419013229795869757265111599482263223604228286513011751601176504567030118257385997460972803240338899836840030438830725520798480181575861397469056536579877274090338750406459700907704031830137890544492015701251066934352867527112361743047684237105216779177819594030160887368311805926405114938744235859610328064947158936962470654636736991567663705830950312548447653861922078087824048793236971354828540758657075837209006713701763902429652486225300535997260665898927924843608750347193892239342462507130025307878412116604096773706728162016134101751551184021079984480254041743057914746472840768175369369852937574401874295943063507273467384747124843744395375119899278823903202010381949145094804675442110869084589592876721655764753871572233276245590041302887094585204427900634246823674277680009401177473636685542700515621164233992970974893989913447733956146698563285998205950467321954304';
|
||||
|
||||
// Will sign the data with the keys generated for test
|
||||
const signNewTestData = (newSignedData: Uint8Array, privateKeyPath: string) => {
|
||||
const privateKey = fs.readFileSync(path.resolve(privateKeyPath), {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
|
||||
const bufferData = Buffer.from(newSignedData);
|
||||
|
||||
const sign = crypto.createSign('sha256');
|
||||
sign.update(bufferData);
|
||||
sign.end();
|
||||
|
||||
const signature = sign.sign({
|
||||
key: privateKey,
|
||||
});
|
||||
|
||||
return signature;
|
||||
};
|
||||
|
||||
export const generateTestData = ({
|
||||
privKeyPem,
|
||||
data,
|
||||
dob,
|
||||
gender,
|
||||
pincode,
|
||||
state,
|
||||
photo,
|
||||
name,
|
||||
}: {
|
||||
privKeyPem: string;
|
||||
data: string;
|
||||
dob?: string;
|
||||
gender?: string;
|
||||
pincode?: string;
|
||||
state?: string;
|
||||
photo?: boolean;
|
||||
name?: string;
|
||||
}) => {
|
||||
const qrDataBytes = convertBigIntToByteArray(BigInt(data));
|
||||
const decodedData = decompressByteArray(qrDataBytes);
|
||||
|
||||
// Turning test data V1 into V2
|
||||
// Adding the version specifier prefix,
|
||||
// the last 4 digits of phone number and timestamp to now
|
||||
const dataToSign = createCustomV2TestData({
|
||||
signedData: decodedData.slice(0, decodedData.length - 256),
|
||||
dob,
|
||||
pincode,
|
||||
gender,
|
||||
state,
|
||||
photo,
|
||||
name,
|
||||
});
|
||||
|
||||
// Signing the newly generated testData
|
||||
const signature = signNewTestData(dataToSign, privKeyPem);
|
||||
|
||||
// Reconstructing the whole QR data
|
||||
const tempData = Buffer.concat([dataToSign, signature]);
|
||||
|
||||
// Compressing the data to have it in the same format as the QR code
|
||||
const newCompressedData = rawDataToCompressedQR(tempData);
|
||||
const newQrData = {
|
||||
testQRData: newCompressedData.toString(),
|
||||
...returnFullId(dataToSign),
|
||||
};
|
||||
|
||||
return newQrData;
|
||||
};
|
||||
// This modify the test data to make it compliant with the secure Aadhaar QR V2 2022
|
||||
// - Adds the version specifier at the beginning 'V2'
|
||||
// - Mocks last 4 digits of phone number '1234' after VTC
|
||||
// - Refresh timestamp data to now
|
||||
// - Optionally it can take parameters to change the test data fields (dob, pinCode, gender, state)
|
||||
export const createCustomV2TestData = ({
|
||||
signedData,
|
||||
dob,
|
||||
pincode,
|
||||
gender,
|
||||
state,
|
||||
photo,
|
||||
name,
|
||||
}: {
|
||||
signedData: Uint8Array;
|
||||
dob?: string;
|
||||
pincode?: string;
|
||||
gender?: string;
|
||||
state?: string;
|
||||
photo?: boolean;
|
||||
name?: string;
|
||||
}) => {
|
||||
const allDataParsed: number[][] = [];
|
||||
const delimiterIndices: number[] = [];
|
||||
let countDelimiter = 0;
|
||||
let temp: number[] = [];
|
||||
for (let i = 0; i < signedData.length; i++) {
|
||||
if (countDelimiter < 16) {
|
||||
if (signedData[i] !== 255) {
|
||||
temp.push(signedData[i]);
|
||||
} else {
|
||||
countDelimiter += 1;
|
||||
allDataParsed.push(temp);
|
||||
delimiterIndices.push(i);
|
||||
temp = [];
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set new timestamp to the time of the signature
|
||||
const newDateString = returnNewDateString();
|
||||
const newTimestamp = new TextEncoder().encode(newDateString);
|
||||
const signedDataWithNewTimestamp = replaceBytesBetween(
|
||||
signedData,
|
||||
newTimestamp,
|
||||
6,
|
||||
5 + newTimestamp.length
|
||||
);
|
||||
|
||||
let modifiedSignedData: Uint8Array = signedDataWithNewTimestamp;
|
||||
|
||||
if (dob) {
|
||||
const newDOB = new TextEncoder().encode(dob);
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
newDOB,
|
||||
delimiterIndices[IdFields.DOB - 1] + 1,
|
||||
delimiterIndices[IdFields.DOB - 1] + allDataParsed[IdFields.DOB].length
|
||||
);
|
||||
}
|
||||
|
||||
if (gender) {
|
||||
const newGender = new TextEncoder().encode(gender);
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
newGender,
|
||||
delimiterIndices[IdFields.Gender - 1] + 1,
|
||||
delimiterIndices[IdFields.Gender - 1] + allDataParsed[IdFields.Gender].length
|
||||
);
|
||||
}
|
||||
|
||||
if (pincode) {
|
||||
const newPincode = new TextEncoder().encode(pincode);
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
newPincode,
|
||||
delimiterIndices[IdFields.PinCode - 1] + 1,
|
||||
delimiterIndices[IdFields.PinCode - 1] + allDataParsed[IdFields.PinCode].length
|
||||
);
|
||||
}
|
||||
|
||||
if (state) {
|
||||
const newState = new TextEncoder().encode(state);
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
newState,
|
||||
delimiterIndices[IdFields.State - 1] + 1,
|
||||
delimiterIndices[IdFields.State - 1] + allDataParsed[IdFields.State].length
|
||||
);
|
||||
}
|
||||
|
||||
if (name) {
|
||||
const newName = new TextEncoder().encode(name);
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
newName,
|
||||
delimiterIndices[IdFields.Name - 1] + 1,
|
||||
delimiterIndices[IdFields.Name - 1] + allDataParsed[IdFields.Name].length
|
||||
);
|
||||
}
|
||||
|
||||
if (photo) {
|
||||
const { begin, dataLength } = extractPhoto(
|
||||
Array.from(modifiedSignedData),
|
||||
modifiedSignedData.length
|
||||
);
|
||||
const photoLength = dataLength - begin;
|
||||
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
getRandomBytes(photoLength - 1),
|
||||
begin + 1,
|
||||
begin + photoLength - 1
|
||||
);
|
||||
}
|
||||
|
||||
const versionSpecifier = new Uint8Array([86, 50, 255]); // 'V2' in ASCII followed by 255
|
||||
const number1234 = new Uint8Array([49, 50, 51, 52, 255]); // '1234' in ASCII followed by 255
|
||||
const beforeInsertion = new Uint8Array(
|
||||
modifiedSignedData.slice(0, getEndIndex(modifiedSignedData))
|
||||
);
|
||||
const afterInsertion = new Uint8Array(modifiedSignedData.slice(getEndIndex(modifiedSignedData)));
|
||||
|
||||
// Combine all parts together
|
||||
const newData = new Uint8Array(
|
||||
versionSpecifier.length + beforeInsertion.length + number1234.length + afterInsertion.length
|
||||
);
|
||||
newData.set(versionSpecifier, 0);
|
||||
newData.set(beforeInsertion, versionSpecifier.length);
|
||||
newData.set(number1234, versionSpecifier.length + beforeInsertion.length);
|
||||
newData.set(afterInsertion, versionSpecifier.length + beforeInsertion.length + number1234.length);
|
||||
|
||||
return newData;
|
||||
};
|
||||
3
circuits/tests/utils/aadhaar/utils.ts
Normal file
3
circuits/tests/utils/aadhaar/utils.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function stringToAsciiArray(str: string) {
|
||||
return str.split('').map((char) => char.charCodeAt(0));
|
||||
}
|
||||
@@ -55,14 +55,10 @@ export {
|
||||
SelfAppBuilder,
|
||||
bigIntToString,
|
||||
brutforceSignatureAlgorithmDsc,
|
||||
buildSMT,
|
||||
calculateUserIdentifierHash,
|
||||
findStartPubKeyIndex,
|
||||
formatEndpoint,
|
||||
formatMrz,
|
||||
genAndInitMockPassportData,
|
||||
genMockIdDoc,
|
||||
genMockIdDocAndInitDataParsing,
|
||||
generateCircuitInputsDSC,
|
||||
generateCircuitInputsRegister,
|
||||
generateCircuitInputsVCandDisclose,
|
||||
@@ -73,16 +69,28 @@ export {
|
||||
getLeafCscaTree,
|
||||
getLeafDscTree,
|
||||
getSKIPEM,
|
||||
getSolidityPackedUserContextData,
|
||||
getUniversalLink,
|
||||
hashEndpointWithScope,
|
||||
initElliptic,
|
||||
initPassportDataParsing,
|
||||
parseCertificateSimple,
|
||||
parseDscCertificateData,
|
||||
genMockIdDoc,
|
||||
genMockIdDocAndInitDataParsing,
|
||||
buildSMT,
|
||||
calculateUserIdentifierHash,
|
||||
getSolidityPackedUserContextData,
|
||||
stringToBigInt,
|
||||
} from './src/utils/index.js';
|
||||
|
||||
export {
|
||||
prepareAadhaarRegisterTestData,
|
||||
prepareAadhaarDiscloseTestData,
|
||||
prepareAadhaarRegisterData,
|
||||
} from './src/utils/aadhaar/mockData.js';
|
||||
export { generateTestData, testCustomData } from './src/utils/aadhaar/utils.js';
|
||||
export { createSelector } from './src/utils/aadhaar/constants.js';
|
||||
|
||||
// Hash utilities
|
||||
export {
|
||||
customHasher,
|
||||
|
||||
@@ -14,192 +14,387 @@
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/esm/index.d.ts",
|
||||
"import": "./dist/esm/index.js",
|
||||
"require": "./dist/cjs/index.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/index.d.ts",
|
||||
"default": "./dist/esm/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/index.d.ts",
|
||||
"default": "./dist/cjs/index.cjs"
|
||||
}
|
||||
},
|
||||
"./constants": {
|
||||
"types": "./dist/esm/src/constants/index.d.ts",
|
||||
"import": "./dist/esm/src/constants/index.js",
|
||||
"require": "./dist/cjs/src/constants/index.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/constants/index.d.ts",
|
||||
"default": "./dist/esm/src/constants/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/constants/index.d.ts",
|
||||
"default": "./dist/cjs/src/constants/index.cjs"
|
||||
}
|
||||
},
|
||||
"./constants/constants": {
|
||||
"types": "./dist/esm/src/constants/constants.d.ts",
|
||||
"import": "./dist/esm/src/constants/constants.js",
|
||||
"require": "./dist/cjs/src/constants/constants.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/constants/constants.d.ts",
|
||||
"default": "./dist/esm/src/constants/constants.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/constants/constants.d.ts",
|
||||
"default": "./dist/cjs/src/constants/constants.cjs"
|
||||
}
|
||||
},
|
||||
"./constants/countries": {
|
||||
"types": "./dist/esm/src/constants/countries.d.ts",
|
||||
"import": "./dist/esm/src/constants/countries.js",
|
||||
"require": "./dist/cjs/src/constants/countries.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/constants/countries.d.ts",
|
||||
"default": "./dist/esm/src/constants/countries.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/constants/countries.d.ts",
|
||||
"default": "./dist/cjs/src/constants/countries.cjs"
|
||||
}
|
||||
},
|
||||
"./constants/sampleDataHashes": {
|
||||
"types": "./dist/esm/src/constants/sampleDataHashes.d.ts",
|
||||
"import": "./dist/esm/src/constants/sampleDataHashes.js",
|
||||
"require": "./dist/cjs/src/constants/sampleDataHashes.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/constants/sampleDataHashes.d.ts",
|
||||
"default": "./dist/esm/src/constants/sampleDataHashes.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/constants/sampleDataHashes.d.ts",
|
||||
"default": "./dist/cjs/src/constants/sampleDataHashes.cjs"
|
||||
}
|
||||
},
|
||||
"./constants/mockCertificates": {
|
||||
"types": "./dist/esm/src/constants/mockCertificates.d.ts",
|
||||
"import": "./dist/esm/src/constants/mockCertificates.js",
|
||||
"require": "./dist/cjs/src/constants/mockCertificates.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/constants/mockCertificates.d.ts",
|
||||
"default": "./dist/esm/src/constants/mockCertificates.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/constants/mockCertificates.d.ts",
|
||||
"default": "./dist/cjs/src/constants/mockCertificates.cjs"
|
||||
}
|
||||
},
|
||||
"./constants/skiPem": {
|
||||
"types": "./dist/esm/src/constants/skiPem.d.ts",
|
||||
"import": "./dist/esm/src/constants/skiPem.js",
|
||||
"require": "./dist/cjs/src/constants/skiPem.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/constants/skiPem.d.ts",
|
||||
"default": "./dist/esm/src/constants/skiPem.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/constants/skiPem.d.ts",
|
||||
"default": "./dist/cjs/src/constants/skiPem.cjs"
|
||||
}
|
||||
},
|
||||
"./constants/vkey": {
|
||||
"types": "./dist/esm/src/constants/vkey.d.ts",
|
||||
"import": "./dist/esm/src/constants/vkey.js",
|
||||
"require": "./dist/cjs/src/constants/vkey.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/constants/vkey.d.ts",
|
||||
"default": "./dist/esm/src/constants/vkey.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/constants/vkey.d.ts",
|
||||
"default": "./dist/cjs/src/constants/vkey.cjs"
|
||||
}
|
||||
},
|
||||
"./mock_certificates/*": "./src/mock_certificates/*",
|
||||
"./mock_certificates/**/*": "./src/mock_certificates/**/*",
|
||||
"./pubkeys/serialized_dsc_tree.json": "./pubkeys/serialized_dsc_tree.json",
|
||||
"./types": {
|
||||
"types": "./dist/esm/src/types/index.d.ts",
|
||||
"import": "./dist/esm/src/types/index.js",
|
||||
"require": "./dist/cjs/src/types/index.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/types/index.d.ts",
|
||||
"default": "./dist/esm/src/types/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/types/index.d.ts",
|
||||
"default": "./dist/cjs/src/types/index.cjs"
|
||||
}
|
||||
},
|
||||
"./types/app": {
|
||||
"types": "./dist/esm/src/types/app.d.ts",
|
||||
"import": "./dist/esm/src/types/app.js",
|
||||
"require": "./dist/cjs/src/types/app.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/types/app.d.ts",
|
||||
"default": "./dist/esm/src/types/app.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/types/app.d.ts",
|
||||
"default": "./dist/cjs/src/types/app.cjs"
|
||||
}
|
||||
},
|
||||
"./types/certificates": {
|
||||
"types": "./dist/esm/src/types/certificates.d.ts",
|
||||
"import": "./dist/esm/src/types/certificates.js",
|
||||
"require": "./dist/cjs/src/types/certificates.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/types/certificates.d.ts",
|
||||
"default": "./dist/esm/src/types/certificates.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/types/certificates.d.ts",
|
||||
"default": "./dist/cjs/src/types/certificates.cjs"
|
||||
}
|
||||
},
|
||||
"./types/circuits": {
|
||||
"types": "./dist/esm/src/types/circuits.d.ts",
|
||||
"import": "./dist/esm/src/types/circuits.js",
|
||||
"require": "./dist/cjs/src/types/circuits.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/types/circuits.d.ts",
|
||||
"default": "./dist/esm/src/types/circuits.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/types/circuits.d.ts",
|
||||
"default": "./dist/cjs/src/types/circuits.cjs"
|
||||
}
|
||||
},
|
||||
"./types/passport": {
|
||||
"types": "./dist/esm/src/types/passport.d.ts",
|
||||
"import": "./dist/esm/src/types/passport.js",
|
||||
"require": "./dist/cjs/src/types/passport.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/types/passport.d.ts",
|
||||
"default": "./dist/esm/src/types/passport.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/types/passport.d.ts",
|
||||
"default": "./dist/cjs/src/types/passport.cjs"
|
||||
}
|
||||
},
|
||||
"./utils": {
|
||||
"types": "./dist/esm/src/utils/index.d.ts",
|
||||
"import": "./dist/esm/src/utils/index.js",
|
||||
"require": "./dist/cjs/src/utils/index.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/index.d.ts",
|
||||
"default": "./dist/esm/src/utils/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/index.d.ts",
|
||||
"default": "./dist/cjs/src/utils/index.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/aadhaar/constants": {
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/aadhaar/constants.d.ts",
|
||||
"default": "./dist/esm/src/utils/aadhaar/constants.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/aadhaar/constants.d.ts",
|
||||
"default": "./dist/cjs/src/utils/aadhaar/constants.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/appType": {
|
||||
"types": "./dist/esm/src/utils/appType.d.ts",
|
||||
"import": "./dist/esm/src/utils/appType.js",
|
||||
"require": "./dist/cjs/src/utils/appType.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/appType.d.ts",
|
||||
"default": "./dist/esm/src/utils/appType.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/appType.d.ts",
|
||||
"default": "./dist/cjs/src/utils/appType.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/types": {
|
||||
"types": "./dist/esm/src/utils/types.d.ts",
|
||||
"import": "./dist/esm/src/utils/types.js",
|
||||
"require": "./dist/cjs/src/utils/types.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/types.d.ts",
|
||||
"default": "./dist/esm/src/utils/types.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/types.d.ts",
|
||||
"default": "./dist/cjs/src/utils/types.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/arrays": {
|
||||
"types": "./dist/esm/src/utils/arrays.d.ts",
|
||||
"import": "./dist/esm/src/utils/arrays.js",
|
||||
"require": "./dist/cjs/src/utils/arrays.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/arrays.d.ts",
|
||||
"default": "./dist/esm/src/utils/arrays.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/arrays.d.ts",
|
||||
"default": "./dist/cjs/src/utils/arrays.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/bytes": {
|
||||
"types": "./dist/esm/src/utils/bytes.d.ts",
|
||||
"import": "./dist/esm/src/utils/bytes.js",
|
||||
"require": "./dist/cjs/src/utils/bytes.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/bytes.d.ts",
|
||||
"default": "./dist/esm/src/utils/bytes.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/bytes.d.ts",
|
||||
"default": "./dist/cjs/src/utils/bytes.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/certificate_parsing": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/index.d.ts",
|
||||
"import": "./dist/esm/src/utils/certificate_parsing/index.js",
|
||||
"require": "./dist/cjs/src/utils/certificate_parsing/index.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/index.d.ts",
|
||||
"default": "./dist/esm/src/utils/certificate_parsing/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/certificate_parsing/index.d.ts",
|
||||
"default": "./dist/cjs/src/utils/certificate_parsing/index.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/certificate_parsing/elliptic": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/elliptic.d.ts",
|
||||
"import": "./dist/esm/src/utils/certificate_parsing/elliptic.js",
|
||||
"require": "./dist/cjs/src/utils/certificate_parsing/elliptic.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/elliptic.d.ts",
|
||||
"default": "./dist/esm/src/utils/certificate_parsing/elliptic.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/certificate_parsing/elliptic.d.ts",
|
||||
"default": "./dist/cjs/src/utils/certificate_parsing/elliptic.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/certificate_parsing/parseCertificateSimple": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/parseCertificateSimple.d.ts",
|
||||
"import": "./dist/esm/src/utils/certificate_parsing/parseCertificateSimple.js",
|
||||
"require": "./dist/cjs/src/utils/certificate_parsing/parseCertificateSimple.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/parseCertificateSimple.d.ts",
|
||||
"default": "./dist/esm/src/utils/certificate_parsing/parseCertificateSimple.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/certificate_parsing/parseCertificateSimple.d.ts",
|
||||
"default": "./dist/cjs/src/utils/certificate_parsing/parseCertificateSimple.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/certificate_parsing/parseNode": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/parseNode.d.ts",
|
||||
"import": "./dist/esm/src/utils/certificate_parsing/parseNode.js",
|
||||
"require": "./dist/cjs/src/utils/certificate_parsing/parseNode.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/parseNode.d.ts",
|
||||
"default": "./dist/esm/src/utils/certificate_parsing/parseNode.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/certificate_parsing/parseNode.d.ts",
|
||||
"default": "./dist/cjs/src/utils/certificate_parsing/parseNode.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/certificate_parsing/parseSimple": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/parseSimple.d.ts",
|
||||
"import": "./dist/esm/src/utils/certificate_parsing/parseSimple.js",
|
||||
"require": "./dist/cjs/src/utils/certificate_parsing/parseSimple.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/parseSimple.d.ts",
|
||||
"default": "./dist/esm/src/utils/certificate_parsing/parseSimple.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/certificate_parsing/parseSimple.d.ts",
|
||||
"default": "./dist/cjs/src/utils/certificate_parsing/parseSimple.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/circuits": {
|
||||
"types": "./dist/esm/src/utils/circuits/index.d.ts",
|
||||
"import": "./dist/esm/src/utils/circuits/index.js",
|
||||
"require": "./dist/cjs/src/utils/circuits/index.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/circuits/index.d.ts",
|
||||
"default": "./dist/esm/src/utils/circuits/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/circuits/index.d.ts",
|
||||
"default": "./dist/cjs/src/utils/circuits/index.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/circuits/circuitsName": {
|
||||
"types": "./dist/esm/src/utils/circuits/circuitsName.d.ts",
|
||||
"import": "./dist/esm/src/utils/circuits/circuitsName.js",
|
||||
"require": "./dist/cjs/src/utils/circuits/circuitsName.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/circuits/circuitsName.d.ts",
|
||||
"default": "./dist/esm/src/utils/circuits/circuitsName.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/circuits/circuitsName.d.ts",
|
||||
"default": "./dist/cjs/src/utils/circuits/circuitsName.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/circuits/discloseInputs": {
|
||||
"types": "./dist/esm/src/utils/circuits/discloseInputs.d.ts",
|
||||
"import": "./dist/esm/src/utils/circuits/discloseInputs.js",
|
||||
"require": "./dist/cjs/src/utils/circuits/discloseInputs.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/circuits/discloseInputs.d.ts",
|
||||
"default": "./dist/esm/src/utils/circuits/discloseInputs.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/circuits/discloseInputs.d.ts",
|
||||
"default": "./dist/cjs/src/utils/circuits/discloseInputs.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/circuits/dscInputs": {
|
||||
"types": "./dist/esm/src/utils/circuits/dscInputs.d.ts",
|
||||
"import": "./dist/esm/src/utils/circuits/dscInputs.js",
|
||||
"require": "./dist/cjs/src/utils/circuits/dscInputs.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/circuits/dscInputs.d.ts",
|
||||
"default": "./dist/esm/src/utils/circuits/dscInputs.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/circuits/dscInputs.d.ts",
|
||||
"default": "./dist/cjs/src/utils/circuits/dscInputs.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/circuits/formatOutputs": {
|
||||
"types": "./dist/esm/src/utils/circuits/formatOutputs.d.ts",
|
||||
"import": "./dist/esm/src/utils/circuits/formatOutputs.js",
|
||||
"require": "./dist/cjs/src/utils/circuits/formatOutputs.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/circuits/formatOutputs.d.ts",
|
||||
"default": "./dist/esm/src/utils/circuits/formatOutputs.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/circuits/formatOutputs.d.ts",
|
||||
"default": "./dist/cjs/src/utils/circuits/formatOutputs.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/circuits/ofacInputs": {
|
||||
"types": "./dist/esm/src/utils/circuits/ofacInputs.d.ts",
|
||||
"import": "./dist/esm/src/utils/circuits/ofacInputs.js",
|
||||
"require": "./dist/cjs/src/utils/circuits/ofacInputs.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/circuits/ofacInputs.d.ts",
|
||||
"default": "./dist/esm/src/utils/circuits/ofacInputs.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/circuits/ofacInputs.d.ts",
|
||||
"default": "./dist/cjs/src/utils/circuits/ofacInputs.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/circuits/registerInputs": {
|
||||
"types": "./dist/esm/src/utils/circuits/registerInputs.d.ts",
|
||||
"import": "./dist/esm/src/utils/circuits/registerInputs.js",
|
||||
"require": "./dist/cjs/src/utils/circuits/registerInputs.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/circuits/registerInputs.d.ts",
|
||||
"default": "./dist/esm/src/utils/circuits/registerInputs.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/circuits/registerInputs.d.ts",
|
||||
"default": "./dist/cjs/src/utils/circuits/registerInputs.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/circuits/uuid": {
|
||||
"types": "./dist/esm/src/utils/circuits/uuid.d.ts",
|
||||
"import": "./dist/esm/src/utils/circuits/uuid.js",
|
||||
"require": "./dist/cjs/src/utils/circuits/uuid.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/circuits/uuid.d.ts",
|
||||
"default": "./dist/esm/src/utils/circuits/uuid.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/circuits/uuid.d.ts",
|
||||
"default": "./dist/cjs/src/utils/circuits/uuid.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/circuits/generateInputs": {
|
||||
"types": "./dist/esm/src/utils/circuits/generateInputs.d.ts",
|
||||
"import": "./dist/esm/src/utils/circuits/generateInputs.js",
|
||||
"require": "./dist/cjs/src/utils/circuits/generateInputs.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/circuits/generateInputs.d.ts",
|
||||
"default": "./dist/esm/src/utils/circuits/generateInputs.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/circuits/generateInputs.d.ts",
|
||||
"default": "./dist/cjs/src/utils/circuits/generateInputs.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/circuits/formatInputs": {
|
||||
"types": "./dist/esm/src/utils/circuits/formatInputs.d.ts",
|
||||
"import": "./dist/esm/src/utils/circuits/formatInputs.js",
|
||||
"require": "./dist/cjs/src/utils/circuits/formatInputs.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/circuits/formatInputs.d.ts",
|
||||
"default": "./dist/esm/src/utils/circuits/formatInputs.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/circuits/formatInputs.d.ts",
|
||||
"default": "./dist/cjs/src/utils/circuits/formatInputs.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/contracts": {
|
||||
"types": "./dist/esm/src/utils/contracts/index.d.ts",
|
||||
"import": "./dist/esm/src/utils/contracts/index.js",
|
||||
"require": "./dist/cjs/src/utils/contracts/index.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/contracts/index.d.ts",
|
||||
"default": "./dist/esm/src/utils/contracts/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/contracts/index.d.ts",
|
||||
"default": "./dist/cjs/src/utils/contracts/index.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/contracts/forbiddenCountries": {
|
||||
"types": "./dist/esm/src/utils/contracts/forbiddenCountries.d.ts",
|
||||
"import": "./dist/esm/src/utils/contracts/forbiddenCountries.js",
|
||||
"require": "./dist/cjs/src/utils/contracts/forbiddenCountries.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/contracts/forbiddenCountries.d.ts",
|
||||
"default": "./dist/esm/src/utils/contracts/forbiddenCountries.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/contracts/forbiddenCountries.d.ts",
|
||||
"default": "./dist/cjs/src/utils/contracts/forbiddenCountries.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/csca": {
|
||||
"types": "./dist/esm/src/utils/csca.d.ts",
|
||||
"import": "./dist/esm/src/utils/csca.js",
|
||||
"require": "./dist/cjs/src/utils/csca.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/csca.d.ts",
|
||||
"default": "./dist/esm/src/utils/csca.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/csca.d.ts",
|
||||
"default": "./dist/cjs/src/utils/csca.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/date": {
|
||||
"types": "./dist/esm/src/utils/date.d.ts",
|
||||
"import": "./dist/esm/src/utils/date.js",
|
||||
"require": "./dist/cjs/src/utils/date.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/date.d.ts",
|
||||
"default": "./dist/esm/src/utils/date.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/date.d.ts",
|
||||
"default": "./dist/cjs/src/utils/date.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/attest": {
|
||||
"types": "./dist/esm/src/utils/attest.d.ts",
|
||||
@@ -207,69 +402,134 @@
|
||||
"require": "./dist/cjs/src/utils/attest.cjs"
|
||||
},
|
||||
"./utils/hash": {
|
||||
"types": "./dist/esm/src/utils/hash.d.ts",
|
||||
"import": "./dist/esm/src/utils/hash.js",
|
||||
"require": "./dist/cjs/src/utils/hash.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/hash.d.ts",
|
||||
"default": "./dist/esm/src/utils/hash.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/hash.d.ts",
|
||||
"default": "./dist/cjs/src/utils/hash.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/hash/custom": {
|
||||
"types": "./dist/esm/src/utils/hash/custom.d.ts",
|
||||
"import": "./dist/esm/src/utils/hash/custom.js",
|
||||
"require": "./dist/cjs/src/utils/hash/custom.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/hash/custom.d.ts",
|
||||
"default": "./dist/esm/src/utils/hash/custom.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/hash/custom.d.ts",
|
||||
"default": "./dist/cjs/src/utils/hash/custom.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/hash/poseidon": {
|
||||
"types": "./dist/esm/src/utils/hash/poseidon.d.ts",
|
||||
"import": "./dist/esm/src/utils/hash/poseidon.js",
|
||||
"require": "./dist/cjs/src/utils/hash/poseidon.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/hash/poseidon.d.ts",
|
||||
"default": "./dist/esm/src/utils/hash/poseidon.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/hash/poseidon.d.ts",
|
||||
"default": "./dist/cjs/src/utils/hash/poseidon.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/hash/sha": {
|
||||
"types": "./dist/esm/src/utils/hash/sha.d.ts",
|
||||
"import": "./dist/esm/src/utils/hash/sha.js",
|
||||
"require": "./dist/cjs/src/utils/hash/sha.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/hash/sha.d.ts",
|
||||
"default": "./dist/esm/src/utils/hash/sha.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/hash/sha.d.ts",
|
||||
"default": "./dist/cjs/src/utils/hash/sha.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports": {
|
||||
"types": "./dist/esm/src/utils/passports/index.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/index.js",
|
||||
"require": "./dist/cjs/src/utils/passports/index.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/index.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/index.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/index.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports/format": {
|
||||
"types": "./dist/esm/src/utils/passports/format.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/format.js",
|
||||
"require": "./dist/cjs/src/utils/passports/format.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/format.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/format.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/format.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/format.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports/commitment": {
|
||||
"types": "./dist/esm/src/utils/passports/commitment.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/commitment.js",
|
||||
"require": "./dist/cjs/src/utils/passports/commitment.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/commitment.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/commitment.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/commitment.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/commitment.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports/core": {
|
||||
"types": "./dist/esm/src/utils/passports/core.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/core.js",
|
||||
"require": "./dist/cjs/src/utils/passports/core.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/core.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/core.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/core.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/core.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports/mockDsc": {
|
||||
"types": "./dist/esm/src/utils/passports/mockDsc.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/mockDsc.js",
|
||||
"require": "./dist/cjs/src/utils/passports/mockDsc.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/mockDsc.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/mockDsc.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/mockDsc.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/mockDsc.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports/mockGeneration": {
|
||||
"types": "./dist/esm/src/utils/passports/mockGeneration.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/mockGeneration.js",
|
||||
"require": "./dist/cjs/src/utils/passports/mockGeneration.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/mockGeneration.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/mockGeneration.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/mockGeneration.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/mockGeneration.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports/parsing": {
|
||||
"types": "./dist/esm/src/utils/passports/parsing.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/parsing.js",
|
||||
"require": "./dist/cjs/src/utils/passports/parsing.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/parsing.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/parsing.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/parsing.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/parsing.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports/signature": {
|
||||
"types": "./dist/esm/src/utils/passports/signature.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/signature.js",
|
||||
"require": "./dist/cjs/src/utils/passports/signature.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/signature.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/signature.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/signature.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/signature.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports/passport": {
|
||||
"types": "./dist/esm/src/utils/passports/passport.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/passport.js",
|
||||
"require": "./dist/cjs/src/utils/passports/passport.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/passport.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/passport.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/passport.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/passport.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports/validate": {
|
||||
"types": "./dist/esm/src/utils/passports/validate.d.ts",
|
||||
@@ -277,49 +537,94 @@
|
||||
"require": "./dist/cjs/src/utils/passports/validate.cjs"
|
||||
},
|
||||
"./utils/passports/genMockIdDoc": {
|
||||
"types": "./dist/esm/src/utils/passports/genMockIdDoc.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/genMockIdDoc.js",
|
||||
"require": "./dist/cjs/src/utils/passports/genMockIdDoc.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/genMockIdDoc.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/genMockIdDoc.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/genMockIdDoc.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/genMockIdDoc.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports/genMockPassportData": {
|
||||
"types": "./dist/esm/src/utils/passports/genMockPassportData.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/genMockPassportData.js",
|
||||
"require": "./dist/cjs/src/utils/passports/genMockPassportData.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/genMockPassportData.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/genMockPassportData.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/genMockPassportData.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/genMockPassportData.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passports/passport_parsing/parseDscCertificateData": {
|
||||
"types": "./dist/esm/src/utils/passports/passport_parsing/parseDscCertificateData.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/passport_parsing/parseDscCertificateData.js",
|
||||
"require": "./dist/cjs/src/utils/passports/passport_parsing/parseDscCertificateData.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/passport_parsing/parseDscCertificateData.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/passport_parsing/parseDscCertificateData.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/passport_parsing/parseDscCertificateData.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/passport_parsing/parseDscCertificateData.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/proving": {
|
||||
"types": "./dist/esm/src/utils/proving.d.ts",
|
||||
"import": "./dist/esm/src/utils/proving.js",
|
||||
"require": "./dist/cjs/src/utils/proving.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/proving.d.ts",
|
||||
"default": "./dist/esm/src/utils/proving.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/proving.d.ts",
|
||||
"default": "./dist/cjs/src/utils/proving.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/scope": {
|
||||
"types": "./dist/esm/src/utils/scope.d.ts",
|
||||
"import": "./dist/esm/src/utils/scope.js",
|
||||
"require": "./dist/cjs/src/utils/scope.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/scope.d.ts",
|
||||
"default": "./dist/esm/src/utils/scope.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/scope.d.ts",
|
||||
"default": "./dist/cjs/src/utils/scope.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/trees": {
|
||||
"types": "./dist/esm/src/utils/trees.d.ts",
|
||||
"import": "./dist/esm/src/utils/trees.js",
|
||||
"require": "./dist/cjs/src/utils/trees.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/trees.d.ts",
|
||||
"default": "./dist/esm/src/utils/trees.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/trees.d.ts",
|
||||
"default": "./dist/cjs/src/utils/trees.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/certificates/parseSimple": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/parseSimple.d.ts",
|
||||
"import": "./dist/esm/src/utils/certificate_parsing/parseSimple.js",
|
||||
"require": "./dist/cjs/src/utils/certificate_parsing/parseSimple.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/certificate_parsing/parseSimple.d.ts",
|
||||
"default": "./dist/esm/src/utils/certificate_parsing/parseSimple.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/certificate_parsing/parseSimple.d.ts",
|
||||
"default": "./dist/cjs/src/utils/certificate_parsing/parseSimple.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/circuitNames": {
|
||||
"types": "./dist/esm/src/utils/circuits/circuitsName.d.ts",
|
||||
"import": "./dist/esm/src/utils/circuits/circuitsName.js",
|
||||
"require": "./dist/cjs/src/utils/circuits/circuitsName.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/circuits/circuitsName.d.ts",
|
||||
"default": "./dist/esm/src/utils/circuits/circuitsName.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/circuits/circuitsName.d.ts",
|
||||
"default": "./dist/cjs/src/utils/circuits/circuitsName.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/passportFormat": {
|
||||
"types": "./dist/esm/src/utils/passports/format.d.ts",
|
||||
"import": "./dist/esm/src/utils/passports/format.js",
|
||||
"require": "./dist/cjs/src/utils/passports/format.cjs"
|
||||
"import": {
|
||||
"types": "./dist/esm/src/utils/passports/format.d.ts",
|
||||
"default": "./dist/esm/src/utils/passports/format.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/cjs/src/utils/passports/format.d.ts",
|
||||
"default": "./dist/cjs/src/utils/passports/format.cjs"
|
||||
}
|
||||
},
|
||||
"./utils/ofac": {
|
||||
"types": "./dist/esm/src/utils/ofac.d.ts",
|
||||
@@ -338,7 +643,7 @@
|
||||
"scripts": {
|
||||
"build": "tsup && yarn build:types && yarn postbuild",
|
||||
"postbuild": "node ./scripts/postBuild.mjs",
|
||||
"build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
|
||||
"build:types": "tsc -p tsconfig.json --emitDeclarationOnly && tsc -p tsconfig.cjs.json --emitDeclarationOnly",
|
||||
"build:watch": "tsup --watch",
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check .",
|
||||
@@ -355,6 +660,7 @@
|
||||
"types": "tsc -p tsconfig.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anon-aadhaar/core": "https://gitpkg.vercel.app/selfxyz/anon-aadhaar/packages/core?1b9efa501cff3cf25dc260b060bf611229e316a4",
|
||||
"@openpassport/zk-kit-imt": "^0.0.5",
|
||||
"@openpassport/zk-kit-lean-imt": "^0.0.6",
|
||||
"@openpassport/zk-kit-smt": "^0.0.1",
|
||||
@@ -369,6 +675,7 @@
|
||||
"elliptic": "^6.5.5",
|
||||
"ethers": "^6.14.4",
|
||||
"fs": "^0.0.1-security",
|
||||
"hash.js": "^1.1.7",
|
||||
"i18n-iso-countries": "^7.13.0",
|
||||
"js-sha1": "^0.7.0",
|
||||
"js-sha256": "^0.11.0",
|
||||
|
||||
@@ -54,6 +54,11 @@ export const shimConfigs = [
|
||||
|
||||
// ===== UTILS =====
|
||||
{ shimPath: 'utils', targetPath: '../esm/src/utils/index.js', name: 'utils' },
|
||||
{
|
||||
shimPath: 'utils/aadhaar/constants',
|
||||
targetPath: '../../../esm/src/utils/aadhaar/constants.js',
|
||||
name: 'utils/aadhaar/constants',
|
||||
},
|
||||
{
|
||||
shimPath: 'utils/appType',
|
||||
targetPath: '../../esm/src/utils/appType.js',
|
||||
|
||||
@@ -42,6 +42,9 @@ export const CSCA_TREE_URL_STAGING = 'https://tree.staging.self.xyz/csca';
|
||||
|
||||
export const CSCA_TREE_URL_STAGING_ID_CARD = 'https://tree.staging.self.xyz/csca-id';
|
||||
|
||||
export const AADHAAR_ATTESTATION_ID = '3';
|
||||
|
||||
// we make it global here because passing it to generateCircuitInputsRegister caused trouble
|
||||
export const DEFAULT_MAJORITY = '18';
|
||||
|
||||
export const DEFAULT_RPC_URL = 'https://mainnet.optimism.io';
|
||||
|
||||
4
common/src/utils/aadhaar/assets/dataInput.ts
Normal file
4
common/src/utils/aadhaar/assets/dataInput.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const testQRData = {
|
||||
testQRData:
|
||||
'8259163575998395410294216884136380576185817320339145460288951755287582961380611852552428987321584902318624273479337130653734982789439199350807739714406680256506601030028361685736660257517232716829232450159251789263870750283214820475102793105777087762238893090228084052270739203426767272062178826235941508196284529472654271516164224874687419158221021213944829682919423174703783469927383220474654008065915029614141226522064062660593170425792840873655513538373377850112144063189928583588899889878172757870400281696669604010659786496608127700010264443115263361656744433002559396889060190428705316366290450741550935385486607346514118464415324976934593027192262025619948063647667007927187736245772179085671658409804311603784752615097922989017361163561315974008304022542448394278143245816470881130080719485003834016131185071765229491892891069788319670287394271744730364788949609836924781874523936880888005883165757273872375006288978183466996520618718348187182821516617721340861010989807614756396013627238651856164981477576514065364628430139194213240602981419233621531616776712580234318576148789862972873366521755587675635811636464535551028275057950562020714225333126426609311459495088802145911084644641596208432517247324679678535859879970296810837735288916946197174410518342751033634782712968162882714769666441813893046220965525694847349131353986974388432968669605721975441870936552792275255624723251162192468002453471184713983574359601113515796454264270501379717344206777921353459767049560942843350534472442799601294637063232419543855742825887931841338302499933012059977947394755335155868283405337181095220998277373266658634859632929226320059674299759100792654417315629048732480315019941928105082550091217622422743467170706956093632228513797781797454779203616427853022505097310749994766657051986303478622173767936568165644251615127773430128638507677775244195799780291921828512257290767451475181728141544788756907393883042588060697683541401090581157249784874529424005078918452607589129440476242749110421616270676359722523229311894327359615548588038186027827017569331332262329182564217789843145105509621002324556840213928256545454178891208004109769624959566302976213521762873815749009289995208912424872527724417047936432945498377307452190302923489092664437908497749093491199476080757200233878726847198496754472664256996743796092233459542884818717466621372105594672115988382565552756801323160697003960485232732393383241422077506009076922303757067128564302338914230360252223406874457414109774901980252709597099278192874164252010830754720603092419792069707099362278082792090307065378744856387301364608460967253691290230861162587170799141457093188189022390589265654613500974699477990974878105678883229707694455342266695530373994049224098435972125150350136428446936271698977517627416435999970351222450833295217051468307037908262231982382247410542334757724852032521780157518474618653527191342825230455100778913195115477763082159513429761573752871477695723697689470263993132596482716347199834315782099668846081963760553679915994617396376870314998926788197388410764535427795200340714967872713095483294486407886767431404892448155562283436571050452251042117926586451385682519188252281397',
|
||||
};
|
||||
9
common/src/utils/aadhaar/assets/testPublicKey.pem
Normal file
9
common/src/utils/aadhaar/assets/testPublicKey.pem
Normal file
@@ -0,0 +1,9 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlegfdQZZXMJirdz93TXY
|
||||
BAVbKt9G3HGcVrWO7hmZle+hoyVHEGIKx4Ael29E475FTbDxkOP31ONZiXIRc0Te
|
||||
Uvz3gm+ElIipWaez0h623QNFFmLqiD7u796ImhSZuaR/lQTF8JbCYrltI9GXUDMt
|
||||
npfrYUHSYd6XmU1MQWPKnL4+B3IhtEJT3PgWCUKLaDUe4+m2DSs1H9qm7owoqEUj
|
||||
n5fefMD+XRROR0gT+0PsWD+BtO4yjCIWczSJjSELoBeibsaJQPBd8ivZzIa7w6Q1
|
||||
Q5I3LVZhZ3abc1uhLKNYD5GcG9i6cMTCqwrPKwm8L66YHzwClabh6fJI9QBzCU/6
|
||||
8QIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
50
common/src/utils/aadhaar/build_aadhaar_ofac_smt.ts
Normal file
50
common/src/utils/aadhaar/build_aadhaar_ofac_smt.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import * as fs from 'fs';
|
||||
import { buildAadhaarSMT } from '../trees.js';
|
||||
|
||||
async function build_aadhaar_ofac_smt() {
|
||||
let startTime = performance.now();
|
||||
const baseInputPath = '../../../ofacdata/inputs/';
|
||||
const baseOutputPath = '../../../ofacdata/outputs/';
|
||||
|
||||
const names = JSON.parse(fs.readFileSync(`${baseInputPath}names.json`) as unknown as string);
|
||||
|
||||
// -----PASSPORT DATA-----
|
||||
console.log(`Reading data from ${baseInputPath}`);
|
||||
const passports = JSON.parse(
|
||||
fs.readFileSync(`${baseInputPath}passports.json`) as unknown as string
|
||||
);
|
||||
|
||||
// -----Aadhaar DATA-----
|
||||
console.log('\nBuilding Aadhaar Card SMTs...');
|
||||
const nameAndDobAadhaarTree = buildAadhaarSMT(names, 'name_and_dob');
|
||||
const nameAndYobAadhaarTree = buildAadhaarSMT(names, 'name_and_yob');
|
||||
|
||||
console.log('\n--- Results ---');
|
||||
console.log(
|
||||
`Aadhaar - Name & DOB Tree: Processed ${nameAndDobAadhaarTree[0]}/${names.length} entries in ${nameAndDobAadhaarTree[1].toFixed(2)} ms`
|
||||
);
|
||||
console.log(
|
||||
`Aadhaar - Name & YOB Tree: Processed ${nameAndYobAadhaarTree[0]}/${names.length} entries in ${nameAndYobAadhaarTree[1].toFixed(2)} ms`
|
||||
);
|
||||
console.log('Total Time:', (performance.now() - startTime).toFixed(2), 'ms');
|
||||
|
||||
console.log(`\nExporting SMTs to ${baseOutputPath}...`);
|
||||
const nameAndDobAadhaarOfacJSON = nameAndDobAadhaarTree[2].export();
|
||||
const nameAndYobAadhaarOfacJSON = nameAndYobAadhaarTree[2].export();
|
||||
|
||||
fs.writeFileSync(
|
||||
`${baseOutputPath}nameAndDobAadhaarSMT.json`,
|
||||
JSON.stringify(nameAndDobAadhaarOfacJSON)
|
||||
);
|
||||
fs.writeFileSync(
|
||||
`${baseOutputPath}nameAndYobAadhaarSMT.json`,
|
||||
JSON.stringify(nameAndYobAadhaarOfacJSON)
|
||||
);
|
||||
|
||||
console.log('✅ SMT export complete.');
|
||||
}
|
||||
|
||||
build_aadhaar_ofac_smt().catch((error) => {
|
||||
console.error('Error building Aadhaar OFAC SMTs:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
247
common/src/utils/aadhaar/constants.ts
Normal file
247
common/src/utils/aadhaar/constants.ts
Normal file
@@ -0,0 +1,247 @@
|
||||
export const MAX_FIELD_BYTE_SIZE = 31;
|
||||
export const NAME_MAX_LENGTH = 2 * MAX_FIELD_BYTE_SIZE; // 62 bytes
|
||||
export const TOTAL_REVEAL_DATA_LENGTH = 119;
|
||||
|
||||
// Public signal indices for vc_and_disclose_aadhaar circuit
|
||||
export const AADHAAR_PUBLIC_SIGNAL_INDICES = {
|
||||
// Public inputs (0-10)
|
||||
ATTESTATION_ID: 0,
|
||||
CURRENT_YEAR: 1,
|
||||
CURRENT_MONTH: 2,
|
||||
CURRENT_DAY: 3,
|
||||
OFAC_NAME_DOB_SMT_ROOT: 4,
|
||||
OFAC_NAME_YOB_SMT_ROOT: 5,
|
||||
MERKLE_ROOT: 6,
|
||||
SCOPE: 7,
|
||||
USER_IDENTIFIER: 8,
|
||||
|
||||
// Outputs (11+)
|
||||
NULLIFIER: 9,
|
||||
REVEAL_PHOTO_HASH: 10,
|
||||
REVEAL_DATA_PACKED_START: 11,
|
||||
REVEAL_DATA_PACKED_END: 14,
|
||||
FORBIDDEN_COUNTRIES_LIST_PACKED_START: 15,
|
||||
FORBIDDEN_COUNTRIES_LIST_PACKED_END: 18,
|
||||
} as const;
|
||||
|
||||
export const getRevealDataPackedIndex = (chunkIndex: number): number => {
|
||||
if (chunkIndex < 0 || chunkIndex > 3) {
|
||||
throw new Error('revealData_packed chunk index must be 0-3');
|
||||
}
|
||||
return AADHAAR_PUBLIC_SIGNAL_INDICES.REVEAL_DATA_PACKED_START + chunkIndex;
|
||||
};
|
||||
|
||||
export const getForbiddenCountriesListPackedIndex = (chunkIndex: number): number => {
|
||||
if (chunkIndex < 0 || chunkIndex > 3) {
|
||||
throw new Error('forbidden_countries_list_packed chunk index must be 0-3');
|
||||
}
|
||||
return AADHAAR_PUBLIC_SIGNAL_INDICES.FORBIDDEN_COUNTRIES_LIST_PACKED_START + chunkIndex;
|
||||
};
|
||||
|
||||
export type AadhaarPublicSignal = keyof typeof AADHAAR_PUBLIC_SIGNAL_INDICES;
|
||||
|
||||
export function getPublicSignalValue(
|
||||
publicSignals: string[],
|
||||
signalName: AadhaarPublicSignal
|
||||
): string {
|
||||
const index = AADHAAR_PUBLIC_SIGNAL_INDICES[signalName];
|
||||
if (index >= publicSignals.length) {
|
||||
throw new Error(`Public signal ${signalName} not found at index ${index}`);
|
||||
}
|
||||
return publicSignals[index];
|
||||
}
|
||||
|
||||
export function getRevealDataPackedChunks(publicSignals: string[]): string[] {
|
||||
return publicSignals.slice(
|
||||
AADHAAR_PUBLIC_SIGNAL_INDICES.REVEAL_DATA_PACKED_START,
|
||||
AADHAAR_PUBLIC_SIGNAL_INDICES.REVEAL_DATA_PACKED_END + 1
|
||||
);
|
||||
}
|
||||
|
||||
export function getForbiddenCountriesListPackedChunks(publicSignals: string[]): string[] {
|
||||
return publicSignals.slice(
|
||||
AADHAAR_PUBLIC_SIGNAL_INDICES.FORBIDDEN_COUNTRIES_LIST_PACKED_START,
|
||||
AADHAAR_PUBLIC_SIGNAL_INDICES.FORBIDDEN_COUNTRIES_LIST_PACKED_END + 1
|
||||
);
|
||||
}
|
||||
|
||||
// Field lengths
|
||||
export const FIELD_LENGTHS = {
|
||||
GENDER: 1,
|
||||
YEAR_OF_BIRTH: 4,
|
||||
MONTH_OF_BIRTH: 2,
|
||||
DAY_OF_BIRTH: 2,
|
||||
NAME: NAME_MAX_LENGTH, // 62
|
||||
AADHAAR_LAST_4_DIGITS: 4,
|
||||
PINCODE: 6,
|
||||
STATE: MAX_FIELD_BYTE_SIZE, // 31
|
||||
PHONE_LAST_4_DIGITS: 4,
|
||||
OFAC_NAME_DOB_CHECK: 1,
|
||||
OFAC_NAME_YOB_CHECK: 1,
|
||||
MINIMUM_AGE_VALID: 1,
|
||||
} as const;
|
||||
|
||||
export const REVEAL_DATA_INDICES = {
|
||||
GENDER: 0,
|
||||
YEAR_OF_BIRTH_START: 1,
|
||||
MONTH_OF_BIRTH_START: 5,
|
||||
DAY_OF_BIRTH_START: 7,
|
||||
NAME_START: 9,
|
||||
AADHAAR_LAST_4_DIGITS_START: 71,
|
||||
PINCODE_START: 75,
|
||||
STATE_START: 81,
|
||||
PHONE_LAST_4_DIGITS_START: 112,
|
||||
OFAC_NAME_DOB_CHECK: 116,
|
||||
OFAC_NAME_YOB_CHECK: 117,
|
||||
MINIMUM_AGE_VALID: 118, // Note: Always revealed, no selector control
|
||||
OFAC_NAME_DOB_REVERSE_CHECK: 119,
|
||||
OFAC_NAME_YOB_REVERSE_CHECK: 120,
|
||||
} as const;
|
||||
|
||||
// End indices (exclusive) for each field in revealedDataPacked array
|
||||
export const REVEAL_DATA_END_INDICES = {
|
||||
GENDER: REVEAL_DATA_INDICES.GENDER + FIELD_LENGTHS.GENDER,
|
||||
YEAR_OF_BIRTH_END: REVEAL_DATA_INDICES.YEAR_OF_BIRTH_START + FIELD_LENGTHS.YEAR_OF_BIRTH,
|
||||
MONTH_OF_BIRTH_END: REVEAL_DATA_INDICES.MONTH_OF_BIRTH_START + FIELD_LENGTHS.MONTH_OF_BIRTH,
|
||||
DAY_OF_BIRTH_END: REVEAL_DATA_INDICES.DAY_OF_BIRTH_START + FIELD_LENGTHS.DAY_OF_BIRTH,
|
||||
NAME_END: REVEAL_DATA_INDICES.NAME_START + FIELD_LENGTHS.NAME,
|
||||
AADHAAR_LAST_4_DIGITS_END:
|
||||
REVEAL_DATA_INDICES.AADHAAR_LAST_4_DIGITS_START + FIELD_LENGTHS.AADHAAR_LAST_4_DIGITS,
|
||||
PINCODE_END: REVEAL_DATA_INDICES.PINCODE_START + FIELD_LENGTHS.PINCODE,
|
||||
STATE_END: REVEAL_DATA_INDICES.STATE_START + FIELD_LENGTHS.STATE,
|
||||
PHONE_LAST_4_DIGITS_END:
|
||||
REVEAL_DATA_INDICES.PHONE_LAST_4_DIGITS_START + FIELD_LENGTHS.PHONE_LAST_4_DIGITS,
|
||||
OFAC_NAME_DOB_CHECK_END:
|
||||
REVEAL_DATA_INDICES.OFAC_NAME_DOB_CHECK + FIELD_LENGTHS.OFAC_NAME_DOB_CHECK,
|
||||
OFAC_NAME_YOB_CHECK_END:
|
||||
REVEAL_DATA_INDICES.OFAC_NAME_YOB_CHECK + FIELD_LENGTHS.OFAC_NAME_YOB_CHECK,
|
||||
MINIMUM_AGE_VALID_END: REVEAL_DATA_INDICES.MINIMUM_AGE_VALID + FIELD_LENGTHS.MINIMUM_AGE_VALID,
|
||||
} as const;
|
||||
|
||||
// Range definitions for easy array slicing
|
||||
export const REVEAL_DATA_RANGES = {
|
||||
GENDER: [REVEAL_DATA_INDICES.GENDER, REVEAL_DATA_END_INDICES.GENDER] as const,
|
||||
YEAR_OF_BIRTH: [
|
||||
REVEAL_DATA_INDICES.YEAR_OF_BIRTH_START,
|
||||
REVEAL_DATA_END_INDICES.YEAR_OF_BIRTH_END,
|
||||
] as const,
|
||||
MONTH_OF_BIRTH: [
|
||||
REVEAL_DATA_INDICES.MONTH_OF_BIRTH_START,
|
||||
REVEAL_DATA_END_INDICES.MONTH_OF_BIRTH_END,
|
||||
] as const,
|
||||
DAY_OF_BIRTH: [
|
||||
REVEAL_DATA_INDICES.DAY_OF_BIRTH_START,
|
||||
REVEAL_DATA_END_INDICES.DAY_OF_BIRTH_END,
|
||||
] as const,
|
||||
NAME: [REVEAL_DATA_INDICES.NAME_START, REVEAL_DATA_END_INDICES.NAME_END] as const,
|
||||
AADHAAR_LAST_4_DIGITS: [
|
||||
REVEAL_DATA_INDICES.AADHAAR_LAST_4_DIGITS_START,
|
||||
REVEAL_DATA_END_INDICES.AADHAAR_LAST_4_DIGITS_END,
|
||||
] as const,
|
||||
PINCODE: [REVEAL_DATA_INDICES.PINCODE_START, REVEAL_DATA_END_INDICES.PINCODE_END] as const,
|
||||
STATE: [REVEAL_DATA_INDICES.STATE_START, REVEAL_DATA_END_INDICES.STATE_END] as const,
|
||||
PHONE_LAST_4_DIGITS: [
|
||||
REVEAL_DATA_INDICES.PHONE_LAST_4_DIGITS_START,
|
||||
REVEAL_DATA_END_INDICES.PHONE_LAST_4_DIGITS_END,
|
||||
] as const,
|
||||
OFAC_NAME_DOB_CHECK: [
|
||||
REVEAL_DATA_INDICES.OFAC_NAME_DOB_CHECK,
|
||||
REVEAL_DATA_END_INDICES.OFAC_NAME_DOB_CHECK_END,
|
||||
] as const,
|
||||
OFAC_NAME_YOB_CHECK: [
|
||||
REVEAL_DATA_INDICES.OFAC_NAME_YOB_CHECK,
|
||||
REVEAL_DATA_END_INDICES.OFAC_NAME_YOB_CHECK_END,
|
||||
] as const,
|
||||
MINIMUM_AGE_VALID: [
|
||||
REVEAL_DATA_INDICES.MINIMUM_AGE_VALID,
|
||||
REVEAL_DATA_END_INDICES.MINIMUM_AGE_VALID_END,
|
||||
] as const,
|
||||
} as const;
|
||||
|
||||
// Selector bit positions corresponding to each field (for creating selector bitmap)
|
||||
export const SELECTOR_BITS = {
|
||||
GENDER: [0] as const,
|
||||
YEAR_OF_BIRTH: [1, 2, 3, 4] as const,
|
||||
MONTH_OF_BIRTH: [5, 6] as const,
|
||||
DAY_OF_BIRTH: [7, 8] as const,
|
||||
NAME: Array.from({ length: NAME_MAX_LENGTH }, (_, i) => i + 9) as number[], // indices 9-70
|
||||
AADHAAR_LAST_4_DIGITS: [71, 72, 73, 74] as const,
|
||||
PINCODE: [75, 76, 77, 78, 79, 80] as const,
|
||||
STATE: Array.from({ length: MAX_FIELD_BYTE_SIZE }, (_, i) => i + 81) as number[], // indices 81-111
|
||||
PHONE_LAST_4_DIGITS: [112, 113, 114, 115] as const,
|
||||
PHOTO_HASH: [116] as const, // This uses sel_bits[116] for reveal_photoHash output
|
||||
OFAC_NAME_DOB_CHECK: [117] as const, // revealData[116] uses sel_bits[117]
|
||||
OFAC_NAME_YOB_CHECK: [118] as const, // revealData[117] uses sel_bits[118]
|
||||
// Note: MINIMUM_AGE_VALID has NO selector bit - always revealed (revealData[118])
|
||||
} as const;
|
||||
|
||||
export type AadhaarField = keyof typeof FIELD_LENGTHS;
|
||||
|
||||
/**
|
||||
* Helper function to extract a specific field from unpacked reveal data
|
||||
* @param unpackedData - The unpacked reveal data array (119 elements)
|
||||
* @param field - The field to extract
|
||||
* @returns The extracted field data as a string or number
|
||||
*/
|
||||
export function extractField(unpackedData: string[], field: AadhaarField): string | number {
|
||||
const range = REVEAL_DATA_RANGES[field];
|
||||
if (range[1] - range[0] === 1) {
|
||||
// Single value field
|
||||
const value = unpackedData[range[0]];
|
||||
// Handle special cases for numeric/boolean fields
|
||||
if (
|
||||
field === 'OFAC_NAME_DOB_CHECK' ||
|
||||
field === 'OFAC_NAME_YOB_CHECK' ||
|
||||
field === 'MINIMUM_AGE_VALID'
|
||||
) {
|
||||
return value.charCodeAt(0);
|
||||
}
|
||||
return value;
|
||||
} else {
|
||||
return unpackedData.slice(range[0], range[1]).join('').replace(/\0+$/, '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a selector field for revealing specific data
|
||||
* @param fieldsToReveal - Array of field names to reveal
|
||||
* @returns Selector value as bigint
|
||||
*/
|
||||
export function createSelector(fieldsToReveal: AadhaarField[]): bigint {
|
||||
const bits = Array(119).fill(0);
|
||||
|
||||
for (const field of fieldsToReveal) {
|
||||
// MINIMUM_AGE_VALID has no selector bit - it's always revealed
|
||||
if (field === 'MINIMUM_AGE_VALID') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const selectorBits = SELECTOR_BITS[field as keyof typeof SELECTOR_BITS];
|
||||
for (const bit of selectorBits) {
|
||||
bits[bit] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
let result = 0n;
|
||||
for (let i = 0; i < 121; i++) {
|
||||
if (bits[i]) {
|
||||
result += 1n << BigInt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Commonly used field combinations
|
||||
export const COMMON_FIELD_COMBINATIONS = {
|
||||
BASIC_INFO: ['GENDER', 'YEAR_OF_BIRTH', 'MONTH_OF_BIRTH', 'DAY_OF_BIRTH'] as AadhaarField[],
|
||||
IDENTITY: ['NAME', 'YEAR_OF_BIRTH', 'MONTH_OF_BIRTH', 'DAY_OF_BIRTH'] as AadhaarField[],
|
||||
LOCATION: ['STATE', 'PINCODE'] as AadhaarField[],
|
||||
CONTACT: ['PHONE_LAST_4_DIGITS'] as AadhaarField[],
|
||||
OFAC_CHECKS: ['OFAC_NAME_DOB_CHECK', 'OFAC_NAME_YOB_CHECK'] as AadhaarField[],
|
||||
// Note: ALL_FIELDS excludes MINIMUM_AGE_VALID since it's always revealed and has no selector bit
|
||||
ALL_SELECTABLE_FIELDS: Object.keys(FIELD_LENGTHS).filter(
|
||||
(field) => field !== 'MINIMUM_AGE_VALID'
|
||||
) as AadhaarField[],
|
||||
ALL_FIELDS: Object.keys(FIELD_LENGTHS) as AadhaarField[],
|
||||
} as const;
|
||||
446
common/src/utils/aadhaar/mockData.ts
Normal file
446
common/src/utils/aadhaar/mockData.ts
Normal file
@@ -0,0 +1,446 @@
|
||||
import { calculateAge, generateTestData, testCustomData } from './utils.js';
|
||||
import {
|
||||
convertBigIntToByteArray,
|
||||
decompressByteArray,
|
||||
splitToWords,
|
||||
extractPhoto,
|
||||
} from '@anon-aadhaar/core';
|
||||
import { bufferToHex, Uint8ArrayToCharArray } from '@zk-email/helpers/dist/binary-format.js';
|
||||
import { sha256Pad } from '@zk-email/helpers/dist/sha-utils.js';
|
||||
import { testQRData } from './assets/dataInput.js';
|
||||
import { stringToAsciiArray } from './utils.js';
|
||||
import { packBytesAndPoseidon } from '../hash.js';
|
||||
import { poseidon5 } from 'poseidon-lite';
|
||||
import forge from 'node-forge';
|
||||
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
|
||||
import { SMT } from '@openpassport/zk-kit-smt';
|
||||
import { findIndexInTree, formatInput } from '../circuits/generateInputs.js';
|
||||
import {
|
||||
generateMerkleProof,
|
||||
generateSMTProof,
|
||||
getNameDobLeafAadhaar,
|
||||
getNameYobLeafAahaar,
|
||||
} from '../trees.js';
|
||||
|
||||
import { COMMITMENT_TREE_DEPTH } from '../../constants/constants.js';
|
||||
import { extractQRDataFields } from './utils.js';
|
||||
|
||||
// Helper function to compute padded name
|
||||
function computePaddedName(name: string): number[] {
|
||||
return name
|
||||
.padEnd(62, '\0')
|
||||
.split('')
|
||||
.map((char) => char.charCodeAt(0));
|
||||
}
|
||||
|
||||
function computeUppercasePaddedName(name: string): number[] {
|
||||
return name
|
||||
.toUpperCase()
|
||||
.padEnd(62, '\0')
|
||||
.split('')
|
||||
.map((char) => char.charCodeAt(0));
|
||||
}
|
||||
|
||||
// Helper function to compute nullifier
|
||||
function nullifierHash(extractedFields: ReturnType<typeof extractQRDataFields>): bigint {
|
||||
const genderAscii = stringToAsciiArray(extractedFields.gender)[0];
|
||||
const personalInfoHashArgs = [
|
||||
genderAscii,
|
||||
...stringToAsciiArray(extractedFields.yob),
|
||||
...stringToAsciiArray(extractedFields.mob),
|
||||
...stringToAsciiArray(extractedFields.dob),
|
||||
...stringToAsciiArray(extractedFields.name.toUpperCase().padEnd(62, '\0')),
|
||||
...stringToAsciiArray(extractedFields.aadhaarLast4Digits),
|
||||
];
|
||||
return BigInt(packBytesAndPoseidon(personalInfoHashArgs));
|
||||
}
|
||||
|
||||
// Helper function to compute packed commitment
|
||||
function computePackedCommitment(extractedFields: ReturnType<typeof extractQRDataFields>): bigint {
|
||||
const packedCommitmentArgs = [
|
||||
3,
|
||||
...stringToAsciiArray(extractedFields.pincode),
|
||||
...stringToAsciiArray(extractedFields.state.padEnd(31, '\0')),
|
||||
...stringToAsciiArray(extractedFields.phoneNoLast4Digits),
|
||||
...stringToAsciiArray(extractedFields.name.padEnd(62, '\0')),
|
||||
];
|
||||
return BigInt(packBytesAndPoseidon(packedCommitmentArgs));
|
||||
}
|
||||
|
||||
// Helper function to compute final commitment
|
||||
function computeCommitment(
|
||||
secret: bigint,
|
||||
qrHash: bigint,
|
||||
nullifier: bigint,
|
||||
packedCommitment: bigint,
|
||||
photoHash: bigint
|
||||
): bigint {
|
||||
return poseidon5([secret, qrHash, nullifier, packedCommitment, photoHash]);
|
||||
}
|
||||
|
||||
interface SharedQRData {
|
||||
qrDataBytes: any;
|
||||
decodedData: Uint8Array;
|
||||
signedData: Uint8Array;
|
||||
qrDataPadded: Uint8Array;
|
||||
qrDataPaddedLen: number;
|
||||
extractedFields: ReturnType<typeof extractQRDataFields>;
|
||||
qrHash: bigint;
|
||||
photo: { bytes: number[] };
|
||||
photoHash: bigint;
|
||||
}
|
||||
|
||||
function processQRData(
|
||||
privKeyPem: string,
|
||||
name?: string,
|
||||
dateOfBirth?: string,
|
||||
gender?: string,
|
||||
pincode?: string,
|
||||
state?: string,
|
||||
timestamp?: string
|
||||
): SharedQRData {
|
||||
const finalName = name ?? 'Sumit Kumar';
|
||||
const finalDateOfBirth = dateOfBirth ?? '01-01-1984';
|
||||
const finalGender = gender ?? 'M';
|
||||
const finalPincode = pincode ?? '110051';
|
||||
const finalState = state ?? 'Delhi';
|
||||
|
||||
let QRData: string;
|
||||
if (name || dateOfBirth || gender || pincode || state) {
|
||||
const newTestData = generateTestData({
|
||||
privKeyPem,
|
||||
data: testCustomData,
|
||||
name: finalName,
|
||||
dob: finalDateOfBirth,
|
||||
gender: finalGender,
|
||||
pincode: finalPincode,
|
||||
state: finalState,
|
||||
timestamp: timestamp,
|
||||
});
|
||||
QRData = newTestData.testQRData;
|
||||
} else {
|
||||
QRData = testQRData.testQRData;
|
||||
}
|
||||
|
||||
return processQRDataSimple(QRData);
|
||||
}
|
||||
|
||||
function processQRDataSimple(qrData: string) {
|
||||
const qrDataBytes = convertBigIntToByteArray(BigInt(qrData));
|
||||
const decodedData = decompressByteArray(qrDataBytes);
|
||||
const signedData = decodedData.slice(0, decodedData.length - 256);
|
||||
|
||||
const [qrDataPadded, qrDataPaddedLen] = sha256Pad(signedData, 512 * 3);
|
||||
|
||||
let photoEOI = 0;
|
||||
for (let i = 0; i < qrDataPadded.length - 1; i++) {
|
||||
if (qrDataPadded[i + 1] === 217 && qrDataPadded[i] === 255) {
|
||||
photoEOI = i + 1;
|
||||
}
|
||||
}
|
||||
if (photoEOI === 0) {
|
||||
throw new Error('Photo EOI not found');
|
||||
}
|
||||
|
||||
// Extract actual fields from QR data instead of using hardcoded values
|
||||
const extractedFields = extractQRDataFields(qrDataBytes);
|
||||
|
||||
const qrHash = packBytesAndPoseidon(Array.from(qrDataPadded));
|
||||
const photo = extractPhoto(Array.from(qrDataPadded), photoEOI + 1);
|
||||
|
||||
const photoHash = packBytesAndPoseidon(photo.bytes.map(Number));
|
||||
|
||||
return {
|
||||
qrDataBytes,
|
||||
decodedData,
|
||||
signedData,
|
||||
qrDataPadded,
|
||||
qrDataPaddedLen,
|
||||
extractedFields,
|
||||
qrHash: BigInt(qrHash),
|
||||
photo,
|
||||
photoHash: BigInt(photoHash),
|
||||
};
|
||||
}
|
||||
|
||||
export function prepareAadhaarRegisterTestData(
|
||||
privKeyPem: string,
|
||||
pubkeyPem: string,
|
||||
secret: string,
|
||||
name?: string,
|
||||
dateOfBirth?: string,
|
||||
gender?: string,
|
||||
pincode?: string,
|
||||
state?: string,
|
||||
timestamp?: string
|
||||
) {
|
||||
const sharedData = processQRData(
|
||||
privKeyPem,
|
||||
name,
|
||||
dateOfBirth,
|
||||
gender,
|
||||
pincode,
|
||||
state,
|
||||
timestamp
|
||||
);
|
||||
|
||||
const delimiterIndices: number[] = [];
|
||||
for (let i = 0; i < sharedData.qrDataPadded.length; i++) {
|
||||
if (sharedData.qrDataPadded[i] === 255) {
|
||||
delimiterIndices.push(i);
|
||||
}
|
||||
if (delimiterIndices.length === 18) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let photoEOI = 0;
|
||||
for (let i = delimiterIndices[17]; i < sharedData.qrDataPadded.length - 1; i++) {
|
||||
if (sharedData.qrDataPadded[i + 1] === 217 && sharedData.qrDataPadded[i] === 255) {
|
||||
photoEOI = i + 1;
|
||||
}
|
||||
}
|
||||
if (photoEOI === 0) {
|
||||
throw new Error('Photo EOI not found');
|
||||
}
|
||||
|
||||
const signatureBytes = sharedData.decodedData.slice(
|
||||
sharedData.decodedData.length - 256,
|
||||
sharedData.decodedData.length
|
||||
);
|
||||
const signature = BigInt('0x' + bufferToHex(Buffer.from(signatureBytes)).toString());
|
||||
|
||||
const publicKey = forge.pki.publicKeyFromPem(pubkeyPem);
|
||||
|
||||
const modulusHex = publicKey.n.toString(16);
|
||||
const pubKey = BigInt('0x' + modulusHex);
|
||||
|
||||
const nullifier = nullifierHash(sharedData.extractedFields);
|
||||
const packedCommitment = computePackedCommitment(sharedData.extractedFields);
|
||||
const commitment = computeCommitment(
|
||||
BigInt(secret),
|
||||
BigInt(sharedData.qrHash),
|
||||
nullifier,
|
||||
packedCommitment,
|
||||
BigInt(sharedData.photoHash)
|
||||
);
|
||||
|
||||
const inputs = {
|
||||
qrDataPadded: Uint8ArrayToCharArray(sharedData.qrDataPadded),
|
||||
qrDataPaddedLength: sharedData.qrDataPaddedLen,
|
||||
delimiterIndices: delimiterIndices,
|
||||
signature: splitToWords(signature, BigInt(121), BigInt(17)),
|
||||
pubKey: splitToWords(pubKey, BigInt(121), BigInt(17)),
|
||||
secret: secret,
|
||||
photoEOI: photoEOI,
|
||||
};
|
||||
|
||||
return {
|
||||
inputs,
|
||||
nullifier,
|
||||
commitment,
|
||||
};
|
||||
}
|
||||
|
||||
export async function prepareAadhaarRegisterData(qrData: string, secret: string, certs: string[]) {
|
||||
const sharedData = processQRDataSimple(qrData);
|
||||
const delimiterIndices: number[] = [];
|
||||
for (let i = 0; i < sharedData.qrDataPadded.length; i++) {
|
||||
if (sharedData.qrDataPadded[i] === 255) {
|
||||
delimiterIndices.push(i);
|
||||
}
|
||||
if (delimiterIndices.length === 18) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let photoEOI = 0;
|
||||
for (let i = delimiterIndices[17]; i < sharedData.qrDataPadded.length - 1; i++) {
|
||||
if (sharedData.qrDataPadded[i + 1] === 217 && sharedData.qrDataPadded[i] === 255) {
|
||||
photoEOI = i + 1;
|
||||
}
|
||||
}
|
||||
if (photoEOI === 0) {
|
||||
throw new Error('Photo EOI not found');
|
||||
}
|
||||
|
||||
const signatureBytes = sharedData.decodedData.slice(
|
||||
sharedData.decodedData.length - 256,
|
||||
sharedData.decodedData.length
|
||||
);
|
||||
const signature = BigInt('0x' + bufferToHex(Buffer.from(signatureBytes)).toString());
|
||||
|
||||
//do promise.all for all certs and pick the one that is valid
|
||||
const certificates = await Promise.all(
|
||||
certs.map(async (cert) => {
|
||||
const certificate = forge.pki.certificateFromPem(cert);
|
||||
const publicKey = certificate.publicKey as forge.pki.rsa.PublicKey;
|
||||
|
||||
try {
|
||||
const md = forge.md.sha256.create();
|
||||
md.update(forge.util.binary.raw.encode(sharedData.signedData));
|
||||
|
||||
const isValid = publicKey.verify(md.digest().getBytes(), signatureBytes);
|
||||
return isValid;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
//find the valid cert
|
||||
const validCert = certificates.indexOf(true);
|
||||
if (validCert === -1) {
|
||||
throw new Error('No valid certificate found');
|
||||
}
|
||||
const certPem = certs[validCert];
|
||||
const cert = forge.pki.certificateFromPem(certPem);
|
||||
const modulusHex = (cert.publicKey as forge.pki.rsa.PublicKey).n.toString(16);
|
||||
const pubKey = BigInt('0x' + modulusHex);
|
||||
|
||||
const nullifier = nullifierHash(sharedData.extractedFields);
|
||||
const packedCommitment = computePackedCommitment(sharedData.extractedFields);
|
||||
const commitment = computeCommitment(
|
||||
BigInt(secret),
|
||||
BigInt(sharedData.qrHash),
|
||||
nullifier,
|
||||
packedCommitment,
|
||||
BigInt(sharedData.photoHash)
|
||||
);
|
||||
|
||||
const inputs = {
|
||||
qrDataPadded: Uint8ArrayToCharArray(sharedData.qrDataPadded),
|
||||
qrDataPaddedLength: sharedData.qrDataPaddedLen,
|
||||
delimiterIndices: delimiterIndices,
|
||||
signature: splitToWords(signature, BigInt(121), BigInt(17)),
|
||||
pubKey: splitToWords(pubKey, BigInt(121), BigInt(17)),
|
||||
secret: secret,
|
||||
photoEOI: photoEOI,
|
||||
};
|
||||
|
||||
return {
|
||||
inputs,
|
||||
nullifier,
|
||||
commitment,
|
||||
};
|
||||
}
|
||||
|
||||
export function prepareAadhaarDiscloseTestData(
|
||||
privateKeyPem: string,
|
||||
merkletree: LeanIMT,
|
||||
nameAndDob_smt: SMT,
|
||||
nameAndYob_smt: SMT,
|
||||
scope: string,
|
||||
secret: string,
|
||||
user_identifier: string,
|
||||
selector: string,
|
||||
name?: string,
|
||||
dateOfBirth?: string,
|
||||
gender?: string,
|
||||
pincode?: string,
|
||||
state?: string,
|
||||
timestamp?: string,
|
||||
updateTree?: boolean
|
||||
) {
|
||||
const sharedData = processQRData(
|
||||
privateKeyPem,
|
||||
name,
|
||||
dateOfBirth,
|
||||
gender,
|
||||
pincode,
|
||||
state,
|
||||
timestamp
|
||||
);
|
||||
|
||||
const { age, currentYear, currentMonth, currentDay } = calculateAge(
|
||||
sharedData.extractedFields.dob,
|
||||
sharedData.extractedFields.mob,
|
||||
sharedData.extractedFields.yob
|
||||
);
|
||||
|
||||
const uppercaseName = computeUppercasePaddedName(sharedData.extractedFields.name);
|
||||
const genderAscii = stringToAsciiArray(sharedData.extractedFields.gender)[0];
|
||||
const nullifier = nullifierHash(sharedData.extractedFields);
|
||||
const packedCommitment = computePackedCommitment(sharedData.extractedFields);
|
||||
const commitment = computeCommitment(
|
||||
BigInt(secret),
|
||||
BigInt(sharedData.qrHash),
|
||||
nullifier,
|
||||
packedCommitment,
|
||||
BigInt(sharedData.photoHash)
|
||||
);
|
||||
|
||||
const paddedName = computePaddedName(sharedData.extractedFields.name);
|
||||
|
||||
if (updateTree) {
|
||||
merkletree.insert(BigInt(commitment));
|
||||
}
|
||||
|
||||
const index = findIndexInTree(merkletree, BigInt(commitment));
|
||||
const {
|
||||
siblings,
|
||||
path: merkle_path,
|
||||
leaf_depth,
|
||||
} = generateMerkleProof(merkletree, index, COMMITMENT_TREE_DEPTH);
|
||||
|
||||
const namedob_leaf = getNameDobLeafAadhaar(
|
||||
sharedData.extractedFields.name,
|
||||
sharedData.extractedFields.yob,
|
||||
sharedData.extractedFields.mob,
|
||||
sharedData.extractedFields.dob
|
||||
);
|
||||
const nameyob_leaf = getNameYobLeafAahaar(
|
||||
sharedData.extractedFields.name,
|
||||
sharedData.extractedFields.yob
|
||||
);
|
||||
|
||||
const {
|
||||
root: ofac_name_dob_smt_root,
|
||||
closestleaf: ofac_name_dob_smt_leaf_key,
|
||||
siblings: ofac_name_dob_smt_siblings,
|
||||
} = generateSMTProof(nameAndDob_smt, namedob_leaf);
|
||||
|
||||
const {
|
||||
root: ofac_name_yob_smt_root,
|
||||
closestleaf: ofac_name_yob_smt_leaf_key,
|
||||
siblings: ofac_name_yob_smt_siblings,
|
||||
} = generateSMTProof(nameAndYob_smt, nameyob_leaf);
|
||||
|
||||
const inputs = {
|
||||
attestation_id: '3',
|
||||
secret: secret,
|
||||
qrDataHash: BigInt(sharedData.qrHash).toString(),
|
||||
gender: genderAscii.toString(),
|
||||
yob: stringToAsciiArray(sharedData.extractedFields.yob),
|
||||
mob: stringToAsciiArray(sharedData.extractedFields.mob),
|
||||
dob: stringToAsciiArray(sharedData.extractedFields.dob),
|
||||
name: formatInput(paddedName),
|
||||
aadhaar_last_4digits: stringToAsciiArray(sharedData.extractedFields.aadhaarLast4Digits),
|
||||
pincode: stringToAsciiArray(sharedData.extractedFields.pincode),
|
||||
state: stringToAsciiArray(sharedData.extractedFields.state.padEnd(31, '\0')),
|
||||
ph_no_last_4digits: stringToAsciiArray(sharedData.extractedFields.phoneNoLast4Digits),
|
||||
photoHash: formatInput(BigInt(sharedData.photoHash)),
|
||||
merkle_root: formatInput(BigInt(merkletree.root)),
|
||||
leaf_depth: formatInput(leaf_depth),
|
||||
path: formatInput(merkle_path),
|
||||
siblings: formatInput(siblings),
|
||||
ofac_name_dob_smt_leaf_key: formatInput(BigInt(ofac_name_dob_smt_leaf_key)),
|
||||
ofac_name_dob_smt_root: formatInput(BigInt(ofac_name_dob_smt_root)),
|
||||
ofac_name_dob_smt_siblings: formatInput(ofac_name_dob_smt_siblings),
|
||||
ofac_name_yob_smt_leaf_key: formatInput(BigInt(ofac_name_yob_smt_leaf_key)),
|
||||
ofac_name_yob_smt_root: formatInput(BigInt(ofac_name_yob_smt_root)),
|
||||
ofac_name_yob_smt_siblings: formatInput(ofac_name_yob_smt_siblings),
|
||||
selector,
|
||||
minimumAge: formatInput(age - 2),
|
||||
currentYear: formatInput(currentYear),
|
||||
currentMonth: formatInput(currentMonth),
|
||||
currentDay: formatInput(currentDay),
|
||||
scope: formatInput(BigInt(scope)),
|
||||
user_identifier: formatInput(BigInt(user_identifier)),
|
||||
forbidden_countries_list: [...Array(120)].map((x) => '0'),
|
||||
};
|
||||
|
||||
return {
|
||||
inputs,
|
||||
nullifier,
|
||||
commitment,
|
||||
};
|
||||
}
|
||||
430
common/src/utils/aadhaar/utils.ts
Normal file
430
common/src/utils/aadhaar/utils.ts
Normal file
@@ -0,0 +1,430 @@
|
||||
import {
|
||||
convertBigIntToByteArray,
|
||||
decompressByteArray,
|
||||
returnFullId,
|
||||
rawDataToCompressedQR,
|
||||
replaceBytesBetween,
|
||||
IdFields,
|
||||
extractPhoto,
|
||||
getRandomBytes,
|
||||
getEndIndex,
|
||||
} from '@anon-aadhaar/core';
|
||||
import forge from 'node-forge';
|
||||
|
||||
export function stringToAsciiArray(str: string) {
|
||||
return str.split('').map((char) => char.charCodeAt(0));
|
||||
}
|
||||
|
||||
// This is the official test data issued by the UIDAI
|
||||
// In this script we'll change the signed data to emulate the specs of the Aadhaar QR V2
|
||||
// and sign the data again with our own certificates.
|
||||
// data on https://uidai.gov.in/en/ecosystem/authentication-devices-documents/qr-code-reader.html
|
||||
// This data is copied from https://github.dev/anon-aadhaar/anon-aadhaar/blob/main/packages/circuits/src/helpers/extractor.circom
|
||||
export const testCustomData =
|
||||
'2374971804270526477833002468783965837992554564899874087591661303561346432389832047870524302186901344489362368642972767716416349990805756094923115719687656090691368051627957878187788907419297818953295185555346288172578594637886352753543271000481717080003254556962148594350559820352806251787713278744047402230989238559317351232114240089849934148895256488140236015024800731753594740948640957680138566468247224859669467819596919398964809164399637893729212452791889199675715949918925838319591794702333094022248132120531152523331442741730158840977243402215102904932650832502847295644794421419704633765033761284508863534321317394686768650111457751139630853448637215423705157211510636160227953566227527799608082928846103264491539001327407775670834868948113753614112563650255058316849200536533335903554984254814901522086937767458409075617572843449110393213525925388131214952874629655799772119820372255291052673056372346072235458198199995637720424196884145247220163810790179386390283738429482893152518286247124911446073389185062482901364671389605727763080854673156754021728522287806275420847159574631844674460263574901590412679291518508010087116598357407343835408554094619585212373168435612645646129147973594416508676872819776522537778717985070402222824965034768103900739105784663244748432502180989441389718131079445941981681118258324511923246198334046020123727749408128519721102477302359413240175102907322619462289965085963377744024233678337951462006962521823224880199210318367946130004264196899778609815012001799773327514133268825910089483612283510244566484854597156100473055413090101948456959122378865704840756793122956663218517626099291311352417342899623681483097817511136427210593032393600010728324905512596767095096153856032112835755780472808814199620390836980020899858288860556611564167406292139646289142056168261133256777093245980048335918156712295254776487472431445495668303900536289283098315798552328294391152828182614909451410115516297083658174657554955228963550255866282688308751041517464999930825273776417639569977754844191402927594739069037851707477839207593911886893016618794870530622356073909077832279869798641545167528509966656120623184120128052588408742941658045827255866966100249857968956536613250770326334844204927432961924987891433020671754710428050564671868464658436926086493709176888821257183419013229795869757265111599482263223604228286513011751601176504567030118257385997460972803240338899836840030438830725520798480181575861397469056536579877274090338750406459700907704031830137890544492015701251066934352867527112361743047684237105216779177819594030160887368311805926405114938744235859610328064947158936962470654636736991567663705830950312548447653861922078087824048793236971354828540758657075837209006713701763902429652486225300535997260665898927924843608750347193892239342462507130025307878412116604096773706728162016134101751551184021079984480254041743057914746472840768175369369852937574401874295943063507273467384747124843744395375119899278823903202010381949145094804675442110869084589592876721655764753871572233276245590041302887094585204427900634246823674277680009401177473636685542700515621164233992970974893989913447733956146698563285998205950467321954304';
|
||||
|
||||
// Will sign the data with the keys generated for test
|
||||
const signNewTestData = (newSignedData: Uint8Array, privKeyPem: string) => {
|
||||
try {
|
||||
// Parse private key from PEM using forge
|
||||
const privateKey = forge.pki.privateKeyFromPem(privKeyPem);
|
||||
|
||||
// Create message digest (SHA-256)
|
||||
const md = forge.md.sha256.create();
|
||||
md.update(forge.util.binary.raw.encode(newSignedData));
|
||||
|
||||
// Sign the hash with the private key
|
||||
const signature = privateKey.sign(md);
|
||||
|
||||
// Convert signature to Uint8Array
|
||||
const signatureBytes = forge.util.binary.raw.decode(signature);
|
||||
return new Uint8Array(signatureBytes);
|
||||
} catch (error) {
|
||||
console.error('Failed to sign data with forge:', error);
|
||||
throw new Error(`Signing failed: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const generateTestData = ({
|
||||
privKeyPem,
|
||||
data,
|
||||
dob,
|
||||
gender,
|
||||
pincode,
|
||||
state,
|
||||
photo,
|
||||
name,
|
||||
timestamp,
|
||||
}: {
|
||||
privKeyPem: string;
|
||||
data: string;
|
||||
dob?: string;
|
||||
gender?: string;
|
||||
pincode?: string;
|
||||
state?: string;
|
||||
photo?: boolean;
|
||||
name?: string;
|
||||
timestamp?: string;
|
||||
}) => {
|
||||
const qrDataBytes = convertBigIntToByteArray(BigInt(data));
|
||||
const decodedData = decompressByteArray(qrDataBytes);
|
||||
|
||||
// Turning test data V1 into V2
|
||||
// Adding the version specifier prefix,
|
||||
// the last 4 digits of phone number and timestamp to now
|
||||
const dataToSign = createCustomV2TestData({
|
||||
signedData: decodedData.slice(0, decodedData.length - 256),
|
||||
dob,
|
||||
pincode,
|
||||
gender,
|
||||
state,
|
||||
photo,
|
||||
name,
|
||||
timestamp,
|
||||
});
|
||||
|
||||
// Signing the newly generated testData
|
||||
const signature = signNewTestData(dataToSign, privKeyPem);
|
||||
|
||||
// Reconstructing the whole QR data
|
||||
const tempData = Buffer.concat([dataToSign, signature]);
|
||||
|
||||
// Compressing the data to have it in the same format as the QR code
|
||||
const newCompressedData = rawDataToCompressedQR(tempData);
|
||||
const newQrData = {
|
||||
testQRData: newCompressedData.toString(),
|
||||
...returnFullId(dataToSign),
|
||||
};
|
||||
|
||||
return newQrData;
|
||||
};
|
||||
|
||||
// This modify the test data to make it compliant with the secure Aadhaar QR V2 2022
|
||||
// - Adds the version specifier at the beginning 'V2'
|
||||
// - Mocks last 4 digits of phone number '1234' after VTC
|
||||
// - Refresh timestamp data to now
|
||||
// - Optionally it can take parameters to change the test data fields (dob, pinCode, gender, state)
|
||||
export const createCustomV2TestData = ({
|
||||
signedData,
|
||||
dob,
|
||||
pincode,
|
||||
gender,
|
||||
state,
|
||||
photo,
|
||||
name,
|
||||
timestamp,
|
||||
}: {
|
||||
signedData: Uint8Array;
|
||||
dob?: string;
|
||||
pincode?: string;
|
||||
gender?: string;
|
||||
state?: string;
|
||||
photo?: boolean;
|
||||
name?: string;
|
||||
timestamp?: string;
|
||||
}) => {
|
||||
const allDataParsed: number[][] = [];
|
||||
const delimiterIndices: number[] = [];
|
||||
let countDelimiter = 0;
|
||||
let temp: number[] = [];
|
||||
for (let i = 0; i < signedData.length; i++) {
|
||||
if (countDelimiter < 16) {
|
||||
if (signedData[i] !== 255) {
|
||||
temp.push(signedData[i]);
|
||||
} else {
|
||||
countDelimiter += 1;
|
||||
allDataParsed.push(temp);
|
||||
delimiterIndices.push(i);
|
||||
temp = [];
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set new timestamp to the time of the signature
|
||||
const newDateString = returnNewDateString(timestamp);
|
||||
const newTimestamp = new TextEncoder().encode(newDateString);
|
||||
const signedDataWithNewTimestamp = replaceBytesBetween(
|
||||
signedData,
|
||||
newTimestamp,
|
||||
6,
|
||||
5 + newTimestamp.length
|
||||
);
|
||||
|
||||
let modifiedSignedData: Uint8Array = signedDataWithNewTimestamp;
|
||||
|
||||
if (dob) {
|
||||
const newDOB = new TextEncoder().encode(dob);
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
newDOB,
|
||||
delimiterIndices[IdFields.DOB - 1] + 1,
|
||||
delimiterIndices[IdFields.DOB - 1] + allDataParsed[IdFields.DOB].length
|
||||
);
|
||||
}
|
||||
|
||||
if (gender) {
|
||||
const newGender = new TextEncoder().encode(gender);
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
newGender,
|
||||
delimiterIndices[IdFields.Gender - 1] + 1,
|
||||
delimiterIndices[IdFields.Gender - 1] + allDataParsed[IdFields.Gender].length
|
||||
);
|
||||
}
|
||||
|
||||
if (pincode) {
|
||||
const newPincode = new TextEncoder().encode(pincode);
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
newPincode,
|
||||
delimiterIndices[IdFields.PinCode - 1] + 1,
|
||||
delimiterIndices[IdFields.PinCode - 1] + allDataParsed[IdFields.PinCode].length
|
||||
);
|
||||
}
|
||||
|
||||
if (state) {
|
||||
const newState = new TextEncoder().encode(state);
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
newState,
|
||||
delimiterIndices[IdFields.State - 1] + 1,
|
||||
delimiterIndices[IdFields.State - 1] + allDataParsed[IdFields.State].length
|
||||
);
|
||||
}
|
||||
|
||||
if (name) {
|
||||
const newName = new TextEncoder().encode(name);
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
newName,
|
||||
delimiterIndices[IdFields.Name - 1] + 1,
|
||||
delimiterIndices[IdFields.Name - 1] + allDataParsed[IdFields.Name].length
|
||||
);
|
||||
}
|
||||
|
||||
if (photo) {
|
||||
const { begin, dataLength } = extractPhoto(
|
||||
Array.from(modifiedSignedData),
|
||||
modifiedSignedData.length
|
||||
);
|
||||
const photoLength = dataLength - begin;
|
||||
|
||||
modifiedSignedData = replaceBytesBetween(
|
||||
modifiedSignedData,
|
||||
getRandomBytes(photoLength - 1),
|
||||
begin + 1,
|
||||
begin + photoLength - 1
|
||||
);
|
||||
}
|
||||
|
||||
const versionSpecifier = new Uint8Array([86, 50, 255]); // 'V2' in ASCII followed by 255
|
||||
const number1234 = new Uint8Array([49, 50, 51, 52, 255]); // '1234' in ASCII followed by 255
|
||||
const beforeInsertion = new Uint8Array(
|
||||
modifiedSignedData.slice(0, getEndIndex(modifiedSignedData))
|
||||
);
|
||||
const afterInsertion = new Uint8Array(modifiedSignedData.slice(getEndIndex(modifiedSignedData)));
|
||||
|
||||
// Combine all parts together
|
||||
const newData = new Uint8Array(
|
||||
versionSpecifier.length + beforeInsertion.length + number1234.length + afterInsertion.length
|
||||
);
|
||||
newData.set(versionSpecifier, 0);
|
||||
newData.set(beforeInsertion, versionSpecifier.length);
|
||||
newData.set(number1234, versionSpecifier.length + beforeInsertion.length);
|
||||
newData.set(afterInsertion, versionSpecifier.length + beforeInsertion.length + number1234.length);
|
||||
|
||||
return newData;
|
||||
};
|
||||
|
||||
export function calculateAge(
|
||||
dob: string,
|
||||
mob: string,
|
||||
yob: string
|
||||
): { age: number; currentYear: number; currentMonth: number; currentDay: number } {
|
||||
const currentDate = new Date();
|
||||
const currentYear = currentDate.getFullYear();
|
||||
const currentMonth = currentDate.getMonth() + 1; // getMonth() returns 0-11
|
||||
const currentDay = currentDate.getDate();
|
||||
|
||||
const birthYear = parseInt(yob);
|
||||
const birthMonth = parseInt(mob);
|
||||
const birthDay = parseInt(dob);
|
||||
|
||||
let age = currentYear - birthYear;
|
||||
|
||||
if (currentMonth < birthMonth || (currentMonth === birthMonth && currentDay < birthDay)) {
|
||||
age--;
|
||||
}
|
||||
return {
|
||||
age,
|
||||
currentYear,
|
||||
currentMonth,
|
||||
currentDay,
|
||||
};
|
||||
}
|
||||
|
||||
export function returnNewDateString(timestamp?: string): string {
|
||||
const newDate = timestamp ? new Date(+timestamp) : new Date();
|
||||
|
||||
// Convert the UTC date to IST by adding 5 hours and 30 minutes
|
||||
const offsetHours = 5;
|
||||
const offsetMinutes = 30;
|
||||
newDate.setUTCHours(newDate.getUTCHours() + offsetHours);
|
||||
newDate.setUTCMinutes(newDate.getUTCMinutes() + offsetMinutes);
|
||||
|
||||
return (
|
||||
newDate.getUTCFullYear().toString() +
|
||||
(newDate.getUTCMonth() + 1).toString().padStart(2, '0') +
|
||||
newDate.getUTCDate().toString().padStart(2, '0') +
|
||||
newDate.getUTCHours().toString().padStart(2, '0') +
|
||||
newDate.getUTCMinutes().toString().padStart(2, '0') +
|
||||
newDate.getUTCSeconds().toString().padStart(2, '0') +
|
||||
newDate.getUTCMilliseconds().toString().padStart(3, '0')
|
||||
);
|
||||
}
|
||||
export const FIELD_POSITIONS = {
|
||||
REFERENCE_ID: 2,
|
||||
NAME: 3,
|
||||
DOB: 4,
|
||||
GENDER: 5,
|
||||
PINCODE: 11,
|
||||
STATE: 13,
|
||||
PHONE_NO: 17,
|
||||
PHOTO: 18,
|
||||
} as const;
|
||||
|
||||
function asciiArrayToString(asciiArray: number[]): string {
|
||||
return asciiArray
|
||||
.filter((byte) => byte !== 0)
|
||||
.map((byte) => String.fromCharCode(byte))
|
||||
.join('');
|
||||
}
|
||||
|
||||
function extractFieldData(
|
||||
data: Uint8Array,
|
||||
delimiterIndices: number[],
|
||||
position: number
|
||||
): number[] {
|
||||
const startIndex = delimiterIndices[position - 1] + 1;
|
||||
const endIndex = delimiterIndices[position];
|
||||
|
||||
const fieldData: number[] = [];
|
||||
for (let i = startIndex; i < endIndex; i++) {
|
||||
fieldData.push(data[i]);
|
||||
}
|
||||
|
||||
return fieldData;
|
||||
}
|
||||
|
||||
export interface ExtractedQRData {
|
||||
name: string;
|
||||
yob: string;
|
||||
mob: string;
|
||||
dob: string;
|
||||
gender: string;
|
||||
pincode: string;
|
||||
state: string;
|
||||
aadhaarLast4Digits: string;
|
||||
phoneNoLast4Digits: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export function extractQRDataFields(qrData: string | Uint8Array): ExtractedQRData {
|
||||
let qrDataBytes: Uint8Array;
|
||||
|
||||
if (typeof qrData === 'string') {
|
||||
qrDataBytes = convertBigIntToByteArray(BigInt(qrData));
|
||||
} else {
|
||||
qrDataBytes = qrData;
|
||||
}
|
||||
|
||||
const decodedData = decompressByteArray(qrDataBytes);
|
||||
const signedData = decodedData.slice(0, decodedData.length - 256);
|
||||
|
||||
const delimiterIndices: number[] = [];
|
||||
for (let i = 0; i < signedData.length; i++) {
|
||||
if (signedData[i] === 255) {
|
||||
delimiterIndices.push(i);
|
||||
if (delimiterIndices.length === 18) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delimiterIndices.length < 18) {
|
||||
throw new Error(`Insufficient delimiters found: ${delimiterIndices.length}/18`);
|
||||
}
|
||||
|
||||
const aadhaarLast4Digits = asciiArrayToString([
|
||||
signedData[5],
|
||||
signedData[6],
|
||||
signedData[7],
|
||||
signedData[8],
|
||||
]);
|
||||
|
||||
const nameData = extractFieldData(signedData, delimiterIndices, FIELD_POSITIONS.NAME);
|
||||
const name = asciiArrayToString(nameData).trim();
|
||||
|
||||
const dobData = extractFieldData(signedData, delimiterIndices, FIELD_POSITIONS.DOB);
|
||||
const dob = asciiArrayToString([dobData[0], dobData[1]]); // day
|
||||
const mob = asciiArrayToString([dobData[3], dobData[4]]); // month
|
||||
const yob = asciiArrayToString([dobData[6], dobData[7], dobData[8], dobData[9]]); // year
|
||||
|
||||
const genderData = extractFieldData(signedData, delimiterIndices, FIELD_POSITIONS.GENDER);
|
||||
const gender = asciiArrayToString(genderData);
|
||||
|
||||
// Extract pincode
|
||||
const pincodeData = extractFieldData(signedData, delimiterIndices, FIELD_POSITIONS.PINCODE);
|
||||
const pincode = asciiArrayToString(pincodeData);
|
||||
|
||||
// Extract state
|
||||
const stateData = extractFieldData(signedData, delimiterIndices, FIELD_POSITIONS.STATE);
|
||||
const state = asciiArrayToString(stateData).trim();
|
||||
|
||||
// Extract phone number last 4 digits
|
||||
const phoneData = extractFieldData(signedData, delimiterIndices, FIELD_POSITIONS.PHONE_NO);
|
||||
const phoneNoLast4Digits = asciiArrayToString(phoneData.slice(phoneData.length - 4));
|
||||
|
||||
// Extract timestamp (from position after first delimiter)
|
||||
// Timestamp format: YYYYMMDDHHMM (similar to circom implementation)
|
||||
const timestampStartIndex = delimiterIndices[0] + 1;
|
||||
const timestampYear = asciiArrayToString([
|
||||
signedData[timestampStartIndex + 8],
|
||||
signedData[timestampStartIndex + 9],
|
||||
signedData[timestampStartIndex + 10],
|
||||
signedData[timestampStartIndex + 11],
|
||||
]);
|
||||
const timestampMonth = asciiArrayToString([
|
||||
signedData[timestampStartIndex + 12],
|
||||
signedData[timestampStartIndex + 13],
|
||||
]);
|
||||
const timestampDay = asciiArrayToString([
|
||||
signedData[timestampStartIndex + 14],
|
||||
signedData[timestampStartIndex + 15],
|
||||
]);
|
||||
const timestampHour = asciiArrayToString([
|
||||
signedData[timestampStartIndex + 16],
|
||||
signedData[timestampStartIndex + 17],
|
||||
]);
|
||||
const timestampMinute = asciiArrayToString([
|
||||
signedData[timestampStartIndex + 18],
|
||||
signedData[timestampStartIndex + 19],
|
||||
]);
|
||||
|
||||
const timestamp = `${timestampYear}-${timestampMonth}-${timestampDay} ${timestampHour}:${timestampMinute}`;
|
||||
|
||||
return {
|
||||
name,
|
||||
yob,
|
||||
mob,
|
||||
dob,
|
||||
gender,
|
||||
pincode,
|
||||
state,
|
||||
aadhaarLast4Digits,
|
||||
phoneNoLast4Digits,
|
||||
timestamp,
|
||||
};
|
||||
}
|
||||
@@ -327,9 +327,11 @@ export const verifyAttestation = async (attestation: Array<number>) => {
|
||||
const cert = derToPem(attestationDoc.certificate);
|
||||
const isPCR0Set = await checkPCR0Mapping(attestation);
|
||||
console.log('isPCR0Set', isPCR0Set);
|
||||
//@ts-ignore
|
||||
if (!isPCR0Set && !__DEV__) {
|
||||
throw new Error('Invalid image hash');
|
||||
}
|
||||
//@ts-ignore
|
||||
if (__DEV__ && !isPCR0Set) {
|
||||
console.warn('\x1b[31m%s\x1b[0m', '⚠️ WARNING: PCR0 CHECK SKIPPED ⚠️');
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export function mergeUInt8Arrays(a1: Uint8Array, a2: Uint8Array): Uint8Array {
|
||||
const mergedArray = new Uint8Array(a1.length + a2.length);
|
||||
mergedArray.set(a1);
|
||||
mergedArray.set(a2, a1.length);
|
||||
return mergedArray;
|
||||
return new Uint8Array(mergedArray.buffer);
|
||||
}
|
||||
|
||||
export function sha384_512Pad(
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import countries from 'i18n-iso-countries';
|
||||
// @ts-ignore
|
||||
import en from 'i18n-iso-countries/langs/en.json' with { type: 'json' };
|
||||
import { poseidon2, poseidon3, poseidon6, poseidon10, poseidon12, poseidon13 } from 'poseidon-lite';
|
||||
|
||||
import {
|
||||
poseidon12,
|
||||
poseidon13,
|
||||
poseidon2,
|
||||
poseidon3,
|
||||
poseidon5,
|
||||
poseidon6,
|
||||
poseidon10,
|
||||
} from 'poseidon-lite';
|
||||
import {
|
||||
CSCA_TREE_DEPTH,
|
||||
DSC_TREE_DEPTH,
|
||||
@@ -15,8 +22,11 @@ import { parseCertificateSimple } from './certificate_parsing/parseCertificateSi
|
||||
import { stringToAsciiBigIntArray } from './circuits/uuid.js';
|
||||
import { packBytesAndPoseidon } from './hash.js';
|
||||
import { pad } from './passports/passport.js';
|
||||
import type { DscCertificateMetaData } from './passports/passport_parsing/parseDscCertificateData.js';
|
||||
import { parseDscCertificateData } from './passports/passport_parsing/parseDscCertificateData.js';
|
||||
import {
|
||||
DscCertificateMetaData,
|
||||
parseDscCertificateData,
|
||||
} from './passports/passport_parsing/parseDscCertificateData.js';
|
||||
import { packBytes } from './bytes.js';
|
||||
|
||||
import { IMT } from '@openpassport/zk-kit-imt';
|
||||
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
|
||||
@@ -554,3 +564,145 @@ export function getPassportNumberAndNationalityLeaf(
|
||||
console.log('err : passport', err, i, passport);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------
|
||||
|
||||
// AADHAAR
|
||||
|
||||
//---------------------------
|
||||
|
||||
export function buildAadhaarSMT(field: any[], treetype: string): [number, number, SMT] {
|
||||
let count = 0;
|
||||
let startTime = performance.now();
|
||||
|
||||
const hash2 = (childNodes: ChildNodes) =>
|
||||
childNodes.length === 2 ? poseidon2(childNodes) : poseidon3(childNodes);
|
||||
const tree = new SMT(hash2, true);
|
||||
|
||||
for (let i = 0; i < field.length; i++) {
|
||||
const entry = field[i];
|
||||
|
||||
if (i !== 0) {
|
||||
console.log('Processing', treetype, 'number', i, 'out of', field.length);
|
||||
}
|
||||
|
||||
let leaf = BigInt(0);
|
||||
let reverse_leaf = BigInt(0);
|
||||
if (treetype == 'name_and_dob') {
|
||||
leaf = processNameAndDobAadhaar(entry, i);
|
||||
reverse_leaf = processNameAndDobAadhaar(entry, i, true);
|
||||
} else if (treetype == 'name_and_yob') {
|
||||
leaf = processNameAndYobAadhaar(entry, i);
|
||||
reverse_leaf = processNameAndYobAadhaar(entry, i, true);
|
||||
}
|
||||
|
||||
if (leaf == BigInt(0) || tree.createProof(leaf).membership) {
|
||||
console.log('This entry already exists in the tree, skipping...');
|
||||
continue;
|
||||
}
|
||||
|
||||
count += 1;
|
||||
tree.add(leaf, BigInt(1));
|
||||
if (reverse_leaf == BigInt(0) || tree.createProof(reverse_leaf).membership) {
|
||||
console.log('This entry already exists in the tree, skipping...');
|
||||
continue;
|
||||
}
|
||||
tree.add(reverse_leaf, BigInt(1));
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return [count, performance.now() - startTime, tree];
|
||||
}
|
||||
|
||||
const processNameAndDobAadhaar = (entry: any, i: number, reverse: boolean = false): bigint => {
|
||||
let firstName = entry.First_Name;
|
||||
let lastName = entry.Last_Name;
|
||||
if (reverse) {
|
||||
firstName = entry.Last_Name;
|
||||
lastName = entry.First_Name;
|
||||
}
|
||||
|
||||
const day = entry.day;
|
||||
const month = entry.month;
|
||||
const year = entry.year;
|
||||
|
||||
if (day == null || month == null || year == null) {
|
||||
console.log('dob is null', i, entry);
|
||||
return BigInt(0);
|
||||
}
|
||||
|
||||
const name = processNameAadhaar(firstName, lastName);
|
||||
const dob = processDobAadhaar(year, month, day);
|
||||
|
||||
return generateSmallKey(poseidon5([name[0], name[1], dob[0], dob[1], dob[2]]));
|
||||
};
|
||||
|
||||
const processNameAndYobAadhaar = (entry: any, i: number, reverse: boolean = false): bigint => {
|
||||
let firstName = entry.First_Name;
|
||||
let lastName = entry.Last_Name;
|
||||
if (reverse) {
|
||||
firstName = entry.Last_Name;
|
||||
lastName = entry.First_Name;
|
||||
}
|
||||
|
||||
const year = entry.year;
|
||||
if (year == null) {
|
||||
console.log('year is null', i, entry);
|
||||
return BigInt(0);
|
||||
}
|
||||
|
||||
const name = processNameAadhaar(firstName, lastName);
|
||||
return generateSmallKey(poseidon3([name[0], name[1], BigInt(year)]));
|
||||
};
|
||||
|
||||
const processNameAadhaar = (firstName: string, lastName: string): bigint[] => {
|
||||
const nameArr = (firstName + ' ' + lastName)
|
||||
.padEnd(62, '\0')
|
||||
.split('')
|
||||
.map((char) => char.charCodeAt(0));
|
||||
return packBytes(nameArr);
|
||||
};
|
||||
|
||||
const processDobAadhaar = (year: string, month: string, day: string): bigint[] => {
|
||||
const monthMap: { [key: string]: string } = {
|
||||
jan: '01',
|
||||
feb: '02',
|
||||
mar: '03',
|
||||
apr: '04',
|
||||
may: '05',
|
||||
jun: '06',
|
||||
jul: '07',
|
||||
aug: '08',
|
||||
sep: '09',
|
||||
oct: '10',
|
||||
nov: '11',
|
||||
dec: '12',
|
||||
};
|
||||
|
||||
month = monthMap[month.toLowerCase()];
|
||||
|
||||
return [year, month, day].map(BigInt);
|
||||
};
|
||||
|
||||
export const getNameDobLeafAadhaar = (name: string, year: string, month: string, day: string) => {
|
||||
const paddedName = name
|
||||
.toUpperCase()
|
||||
.padEnd(62, '\0')
|
||||
.split('')
|
||||
.map((char) => char.charCodeAt(0));
|
||||
const namePacked = packBytes(paddedName);
|
||||
return generateSmallKey(
|
||||
poseidon5([namePacked[0], namePacked[1], BigInt(year), BigInt(month), BigInt(day)])
|
||||
);
|
||||
};
|
||||
|
||||
export const getNameYobLeafAahaar = (name: string, year: string) => {
|
||||
const paddedName = name
|
||||
.toUpperCase()
|
||||
.padEnd(62, '\0')
|
||||
.split('')
|
||||
.map((char) => char.charCodeAt(0));
|
||||
const namePacked = packBytes(paddedName);
|
||||
|
||||
return generateSmallKey(poseidon3([namePacked[0], namePacked[1], BigInt(year)]));
|
||||
};
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
"composite": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.js",
|
||||
"index.ts"
|
||||
"src/**/*",
|
||||
"index.ts",
|
||||
"ofacdata/**/*.json"
|
||||
],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"node_modules"
|
||||
"node_modules",
|
||||
"src/**/*.test.ts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ const entry = {
|
||||
'src/constants/mockCertificates': 'src/constants/mockCertificates.ts',
|
||||
'src/constants/sampleDataHashes': 'src/constants/sampleDataHashes.ts',
|
||||
// Granular utils exports
|
||||
'src/utils/aadhaar/constants': 'src/utils/aadhaar/constants.ts',
|
||||
'src/utils/attest': 'src/utils/attest.ts',
|
||||
'src/utils/hash': 'src/utils/hash.ts',
|
||||
'src/utils/bytes': 'src/utils/bytes.ts',
|
||||
@@ -101,6 +102,8 @@ export default defineConfig([
|
||||
platform: 'neutral',
|
||||
external: [
|
||||
/^@openpassport/,
|
||||
/^@zk-email/,
|
||||
/^@anon-aadhaar/,
|
||||
/^asn1/,
|
||||
/^axios/,
|
||||
/^buffer/,
|
||||
@@ -138,6 +141,8 @@ export default defineConfig([
|
||||
platform: 'neutral',
|
||||
external: [
|
||||
/^@openpassport/,
|
||||
/^@zk-email/,
|
||||
/^@anon-aadhaar/,
|
||||
/^asn1/,
|
||||
/^axios/,
|
||||
/^buffer/,
|
||||
|
||||
@@ -504,12 +504,12 @@ contract IdentityVerificationHubImplV1 is IdentityVerificationHubStorageV1, IIde
|
||||
}
|
||||
|
||||
// verify current date
|
||||
uint[6] memory dateNum;
|
||||
uint256[6] memory dateNum;
|
||||
for (uint256 i = 0; i < 6; i++) {
|
||||
dateNum[i] = proof.vcAndDiscloseProof.pubSignals[CircuitConstants.VC_AND_DISCLOSE_CURRENT_DATE_INDEX + i];
|
||||
}
|
||||
|
||||
uint currentTimestamp = Formatter.proofDateToUnixTimestamp(dateNum);
|
||||
uint256 currentTimestamp = Formatter.proofDateToUnixTimestamp(dateNum);
|
||||
if (
|
||||
currentTimestamp < _getStartOfDayTimestamp() - 1 days + 1 ||
|
||||
currentTimestamp > _getStartOfDayTimestamp() + 1 days - 1
|
||||
|
||||
@@ -3,14 +3,18 @@ pragma solidity 0.8.28;
|
||||
|
||||
import {ImplRoot} from "./upgradeable/ImplRoot.sol";
|
||||
import {SelfStructs} from "./libraries/SelfStructs.sol";
|
||||
import {GenericProofStruct} from "./interfaces/IRegisterCircuitVerifier.sol";
|
||||
import {CustomVerifier} from "./libraries/CustomVerifier.sol";
|
||||
import {GenericFormatter} from "./libraries/GenericFormatter.sol";
|
||||
import {AttestationId} from "./constants/AttestationId.sol";
|
||||
import {IVcAndDiscloseCircuitVerifier} from "./interfaces/IVcAndDiscloseCircuitVerifier.sol";
|
||||
import {IVcAndDiscloseAadhaarCircuitVerifier} from "./interfaces/IVcAndDiscloseCircuitVerifier.sol";
|
||||
import {ISelfVerificationRoot} from "./interfaces/ISelfVerificationRoot.sol";
|
||||
import {IIdentityRegistryV1} from "./interfaces/IIdentityRegistryV1.sol";
|
||||
import {IIdentityRegistryIdCardV1} from "./interfaces/IIdentityRegistryIdCardV1.sol";
|
||||
import {IIdentityRegistryAadhaarV1} from "./interfaces/IIdentityRegistryAadhaarV1.sol";
|
||||
import {IRegisterCircuitVerifier} from "./interfaces/IRegisterCircuitVerifier.sol";
|
||||
import {IAadhaarRegisterCircuitVerifier} from "./interfaces/IRegisterCircuitVerifier.sol";
|
||||
import {IDscCircuitVerifier} from "./interfaces/IDscCircuitVerifier.sol";
|
||||
import {CircuitConstantsV2} from "./constants/CircuitConstantsV2.sol";
|
||||
import {Formatter} from "./libraries/Formatter.sol";
|
||||
@@ -165,6 +169,18 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
/// @dev Ensures that the verification config is set before performing verification.
|
||||
error ConfigNotSet();
|
||||
|
||||
/// @notice Thrown when the pubkey is not valid.
|
||||
/// @dev Ensures that the pubkey is valid.
|
||||
error InvalidPubkey();
|
||||
|
||||
/// @notice Thrown when the timestamp is invalid.
|
||||
/// @dev Ensures that the timestamp is within 20 minutes of the current block timestamp.
|
||||
error InvalidUidaiTimestamp();
|
||||
|
||||
/// @notice Thrown when the attestationId in the proof doesn't match the header.
|
||||
/// @dev Ensures that the attestationId in the proof matches the header.
|
||||
error AttestationIdMismatch();
|
||||
|
||||
// ====================================================
|
||||
// Constructor
|
||||
// ====================================================
|
||||
@@ -212,7 +228,7 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
function registerCommitment(
|
||||
bytes32 attestationId,
|
||||
uint256 registerCircuitVerifierId,
|
||||
IRegisterCircuitVerifier.RegisterCircuitProof memory registerCircuitProof
|
||||
GenericProofStruct memory registerCircuitProof
|
||||
) external virtual onlyProxy {
|
||||
_verifyRegisterProof(attestationId, registerCircuitVerifierId, registerCircuitProof);
|
||||
IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage();
|
||||
@@ -228,6 +244,11 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
registerCircuitProof.pubSignals[CircuitConstantsV2.REGISTER_NULLIFIER_INDEX],
|
||||
registerCircuitProof.pubSignals[CircuitConstantsV2.REGISTER_COMMITMENT_INDEX]
|
||||
);
|
||||
} else if (attestationId == AttestationId.AADHAAR) {
|
||||
IIdentityRegistryAadhaarV1($._registries[attestationId]).registerCommitment(
|
||||
registerCircuitProof.pubSignals[CircuitConstantsV2.AADHAAR_NULLIFIER_INDEX],
|
||||
registerCircuitProof.pubSignals[CircuitConstantsV2.AADHAAR_COMMITMENT_INDEX]
|
||||
);
|
||||
} else {
|
||||
revert InvalidAttestationId();
|
||||
}
|
||||
@@ -454,11 +475,12 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
function rootTimestamp(bytes32 attestationId, uint256 root) external view virtual onlyProxy returns (uint256) {
|
||||
IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage();
|
||||
address registryAddress = $._registries[attestationId];
|
||||
|
||||
if (attestationId == AttestationId.E_PASSPORT) {
|
||||
return IIdentityRegistryV1(registryAddress).rootTimestamps(root);
|
||||
} else if (attestationId == AttestationId.EU_ID_CARD) {
|
||||
return IIdentityRegistryIdCardV1(registryAddress).rootTimestamps(root);
|
||||
} else if (attestationId == AttestationId.AADHAAR) {
|
||||
return IIdentityRegistryAadhaarV1(registryAddress).rootTimestamps(root);
|
||||
} else {
|
||||
revert InvalidAttestationId();
|
||||
}
|
||||
@@ -477,6 +499,8 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
return IIdentityRegistryV1(registryAddress).getIdentityCommitmentMerkleRoot();
|
||||
} else if (attestationId == AttestationId.EU_ID_CARD) {
|
||||
return IIdentityRegistryIdCardV1(registryAddress).getIdentityCommitmentMerkleRoot();
|
||||
} else if (attestationId == AttestationId.AADHAAR) {
|
||||
return IIdentityRegistryAadhaarV1(registryAddress).getIdentityCommitmentMerkleRoot();
|
||||
} else {
|
||||
revert InvalidAttestationId();
|
||||
}
|
||||
@@ -585,26 +609,26 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
*/
|
||||
function _basicVerification(
|
||||
SelfStructs.HubInputHeader memory header,
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof,
|
||||
GenericProofStruct memory vcAndDiscloseProof,
|
||||
bytes calldata userContextData,
|
||||
uint256 userIdentifier
|
||||
) internal returns (bytes memory output) {
|
||||
// Scope 1: Basic checks (scope and user identifier)
|
||||
CircuitConstantsV2.DiscloseIndices memory indices = CircuitConstantsV2.getDiscloseIndices(header.attestationId);
|
||||
{
|
||||
CircuitConstantsV2.DiscloseIndices memory indices = CircuitConstantsV2.getDiscloseIndices(
|
||||
header.attestationId
|
||||
);
|
||||
_performAttestationIdCheck(header.attestationId, vcAndDiscloseProof, indices);
|
||||
_performScopeCheck(header.scope, vcAndDiscloseProof, indices);
|
||||
_performUserIdentifierCheck(userContextData, vcAndDiscloseProof, header.attestationId, indices);
|
||||
}
|
||||
|
||||
// Scope 2: Root and date checks
|
||||
{
|
||||
CircuitConstantsV2.DiscloseIndices memory indices = CircuitConstantsV2.getDiscloseIndices(
|
||||
header.attestationId
|
||||
);
|
||||
_performRootCheck(header.attestationId, vcAndDiscloseProof, indices);
|
||||
_performCurrentDateCheck(vcAndDiscloseProof, indices);
|
||||
if (header.attestationId == AttestationId.AADHAAR) {
|
||||
_performNumericCurrentDateCheck(vcAndDiscloseProof, indices);
|
||||
} else {
|
||||
_performCurrentDateCheck(vcAndDiscloseProof, indices);
|
||||
}
|
||||
}
|
||||
|
||||
// Scope 3: Groth16 proof verification
|
||||
@@ -612,9 +636,6 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
|
||||
// Scope 4: Create and return output
|
||||
{
|
||||
CircuitConstantsV2.DiscloseIndices memory indices = CircuitConstantsV2.getDiscloseIndices(
|
||||
header.attestationId
|
||||
);
|
||||
return _createVerificationOutput(header.attestationId, vcAndDiscloseProof, indices, userIdentifier);
|
||||
}
|
||||
}
|
||||
@@ -658,7 +679,7 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
function _verifyRegisterProof(
|
||||
bytes32 attestationId,
|
||||
uint256 registerCircuitVerifierId,
|
||||
IRegisterCircuitVerifier.RegisterCircuitProof memory registerCircuitProof
|
||||
GenericProofStruct memory registerCircuitProof
|
||||
) internal view {
|
||||
IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage();
|
||||
address verifier = $._registerCircuitVerifiers[attestationId][registerCircuitVerifierId];
|
||||
@@ -682,19 +703,63 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
) {
|
||||
revert InvalidDscCommitmentRoot();
|
||||
}
|
||||
} else if (attestationId == AttestationId.AADHAAR) {
|
||||
uint256 timestamp = registerCircuitProof.pubSignals[CircuitConstantsV2.AADHAAR_TIMESTAMP_INDEX];
|
||||
if (timestamp < block.timestamp - 20 minutes) {
|
||||
revert InvalidUidaiTimestamp();
|
||||
}
|
||||
|
||||
if (timestamp > block.timestamp + 20 minutes) {
|
||||
revert InvalidUidaiTimestamp();
|
||||
}
|
||||
|
||||
if (
|
||||
!IIdentityRegistryAadhaarV1($._registries[attestationId]).checkUidaiPubkey(
|
||||
registerCircuitProof.pubSignals[CircuitConstantsV2.AADHAAR_UIDAI_PUBKEY_COMMITMENT_INDEX]
|
||||
)
|
||||
) {
|
||||
revert InvalidPubkey();
|
||||
}
|
||||
} else {
|
||||
revert InvalidAttestationId();
|
||||
}
|
||||
|
||||
if (
|
||||
!IRegisterCircuitVerifier(verifier).verifyProof(
|
||||
registerCircuitProof.a,
|
||||
registerCircuitProof.b,
|
||||
registerCircuitProof.c,
|
||||
registerCircuitProof.pubSignals
|
||||
)
|
||||
) {
|
||||
revert InvalidRegisterProof();
|
||||
if (attestationId == AttestationId.E_PASSPORT || attestationId == AttestationId.EU_ID_CARD) {
|
||||
require(registerCircuitProof.pubSignals.length == 3, "Invalid pubSignals length");
|
||||
uint256[3] memory pubSignals = [
|
||||
registerCircuitProof.pubSignals[0],
|
||||
registerCircuitProof.pubSignals[1],
|
||||
registerCircuitProof.pubSignals[2]
|
||||
];
|
||||
if (
|
||||
!IRegisterCircuitVerifier(verifier).verifyProof(
|
||||
registerCircuitProof.a,
|
||||
registerCircuitProof.b,
|
||||
registerCircuitProof.c,
|
||||
pubSignals
|
||||
)
|
||||
) {
|
||||
revert InvalidRegisterProof();
|
||||
}
|
||||
} else if (attestationId == AttestationId.AADHAAR) {
|
||||
require(registerCircuitProof.pubSignals.length == 4, "Invalid pubSignals length");
|
||||
uint256[4] memory pubSignals = [
|
||||
registerCircuitProof.pubSignals[0],
|
||||
registerCircuitProof.pubSignals[1],
|
||||
registerCircuitProof.pubSignals[2],
|
||||
registerCircuitProof.pubSignals[3]
|
||||
];
|
||||
|
||||
if (
|
||||
!IAadhaarRegisterCircuitVerifier(verifier).verifyProof(
|
||||
registerCircuitProof.a,
|
||||
registerCircuitProof.b,
|
||||
registerCircuitProof.c,
|
||||
pubSignals
|
||||
)
|
||||
) {
|
||||
revert InvalidRegisterProof();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,12 +821,25 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
return block.timestamp - (block.timestamp % 1 days);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Performs attestationId check
|
||||
*/
|
||||
function _performAttestationIdCheck(
|
||||
bytes32 attestationId,
|
||||
GenericProofStruct memory vcAndDiscloseProof,
|
||||
CircuitConstantsV2.DiscloseIndices memory indices
|
||||
) internal pure {
|
||||
if (vcAndDiscloseProof.pubSignals[indices.attestationIdIndex] != uint256(attestationId)) {
|
||||
revert AttestationIdMismatch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Performs scope validation
|
||||
*/
|
||||
function _performScopeCheck(
|
||||
uint256 headerScope,
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof,
|
||||
GenericProofStruct memory vcAndDiscloseProof,
|
||||
CircuitConstantsV2.DiscloseIndices memory indices
|
||||
) internal view {
|
||||
// Get scope from proof using the scope index from indices
|
||||
@@ -777,7 +855,7 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
*/
|
||||
function _performRootCheck(
|
||||
bytes32 attestationId,
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof,
|
||||
GenericProofStruct memory vcAndDiscloseProof,
|
||||
CircuitConstantsV2.DiscloseIndices memory indices
|
||||
) internal view {
|
||||
IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage();
|
||||
@@ -797,6 +875,10 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
if (!IIdentityRegistryIdCardV1($._registries[attestationId]).checkIdentityCommitmentRoot(merkleRoot)) {
|
||||
revert InvalidIdentityCommitmentRoot();
|
||||
}
|
||||
} else if (attestationId == AttestationId.AADHAAR) {
|
||||
if (!IIdentityRegistryAadhaarV1($._registries[attestationId]).checkIdentityCommitmentRoot(merkleRoot)) {
|
||||
revert InvalidIdentityCommitmentRoot();
|
||||
}
|
||||
} else {
|
||||
revert InvalidAttestationId();
|
||||
}
|
||||
@@ -806,16 +888,34 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
* @notice Performs current date validation
|
||||
*/
|
||||
function _performCurrentDateCheck(
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof,
|
||||
GenericProofStruct memory vcAndDiscloseProof,
|
||||
CircuitConstantsV2.DiscloseIndices memory indices
|
||||
) internal view {
|
||||
uint[6] memory dateNum;
|
||||
uint256[6] memory dateNum;
|
||||
for (uint256 i = 0; i < 6; i++) {
|
||||
dateNum[i] = vcAndDiscloseProof.pubSignals[indices.currentDateIndex + i];
|
||||
}
|
||||
|
||||
uint currentTimestamp = Formatter.proofDateToUnixTimestamp(dateNum);
|
||||
uint startOfDay = _getStartOfDayTimestamp();
|
||||
uint256 currentTimestamp = Formatter.proofDateToUnixTimestamp(dateNum);
|
||||
uint256 startOfDay = _getStartOfDayTimestamp();
|
||||
|
||||
if (currentTimestamp < startOfDay - 1 days + 1 || currentTimestamp > startOfDay + 1 days - 1) {
|
||||
revert CurrentDateNotInValidRange();
|
||||
}
|
||||
}
|
||||
|
||||
function _performNumericCurrentDateCheck(
|
||||
GenericProofStruct memory vcAndDiscloseProof,
|
||||
CircuitConstantsV2.DiscloseIndices memory indices
|
||||
) internal view {
|
||||
// date is going to be 2025, 12, 13
|
||||
uint256[3] memory dateNum;
|
||||
dateNum[0] = vcAndDiscloseProof.pubSignals[indices.currentDateIndex];
|
||||
dateNum[1] = vcAndDiscloseProof.pubSignals[indices.currentDateIndex + 1];
|
||||
dateNum[2] = vcAndDiscloseProof.pubSignals[indices.currentDateIndex + 2];
|
||||
|
||||
uint256 currentTimestamp = Formatter.proofDateToUnixTimestampNumeric(dateNum);
|
||||
uint256 startOfDay = _getStartOfDayTimestamp();
|
||||
|
||||
if (currentTimestamp < startOfDay - 1 days + 1 || currentTimestamp > startOfDay + 1 days - 1) {
|
||||
revert CurrentDateNotInValidRange();
|
||||
@@ -827,19 +927,43 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
*/
|
||||
function _performGroth16ProofVerification(
|
||||
bytes32 attestationId,
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof
|
||||
GenericProofStruct memory vcAndDiscloseProof
|
||||
) internal view {
|
||||
IdentityVerificationHubStorage storage $ = _getIdentityVerificationHubStorage();
|
||||
|
||||
if (
|
||||
!IVcAndDiscloseCircuitVerifier($._discloseVerifiers[attestationId]).verifyProof(
|
||||
vcAndDiscloseProof.a,
|
||||
vcAndDiscloseProof.b,
|
||||
vcAndDiscloseProof.c,
|
||||
vcAndDiscloseProof.pubSignals
|
||||
)
|
||||
) {
|
||||
revert InvalidVcAndDiscloseProof();
|
||||
if (attestationId == AttestationId.E_PASSPORT || attestationId == AttestationId.EU_ID_CARD) {
|
||||
uint256[21] memory pubSignals;
|
||||
for (uint256 i = 0; i < 21; i++) {
|
||||
pubSignals[i] = vcAndDiscloseProof.pubSignals[i];
|
||||
}
|
||||
if (
|
||||
!IVcAndDiscloseCircuitVerifier($._discloseVerifiers[attestationId]).verifyProof(
|
||||
vcAndDiscloseProof.a,
|
||||
vcAndDiscloseProof.b,
|
||||
vcAndDiscloseProof.c,
|
||||
pubSignals
|
||||
)
|
||||
) {
|
||||
revert InvalidVcAndDiscloseProof();
|
||||
}
|
||||
} else if (attestationId == AttestationId.AADHAAR) {
|
||||
uint256[19] memory pubSignals;
|
||||
for (uint256 i = 0; i < 19; i++) {
|
||||
pubSignals[i] = vcAndDiscloseProof.pubSignals[i];
|
||||
}
|
||||
|
||||
if (
|
||||
!IVcAndDiscloseAadhaarCircuitVerifier($._discloseVerifiers[attestationId]).verifyProof(
|
||||
vcAndDiscloseProof.a,
|
||||
vcAndDiscloseProof.b,
|
||||
vcAndDiscloseProof.c,
|
||||
pubSignals
|
||||
)
|
||||
) {
|
||||
revert InvalidVcAndDiscloseProof();
|
||||
}
|
||||
} else {
|
||||
revert InvalidAttestationId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -916,7 +1040,7 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
*/
|
||||
function _createVerificationOutput(
|
||||
bytes32 attestationId,
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof,
|
||||
GenericProofStruct memory vcAndDiscloseProof,
|
||||
CircuitConstantsV2.DiscloseIndices memory indices,
|
||||
uint256 userIdentifier
|
||||
) internal pure returns (bytes memory) {
|
||||
@@ -924,6 +1048,8 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
return _createPassportOutput(vcAndDiscloseProof, indices, attestationId, userIdentifier);
|
||||
} else if (attestationId == AttestationId.EU_ID_CARD) {
|
||||
return _createEuIdOutput(vcAndDiscloseProof, indices, attestationId, userIdentifier);
|
||||
} else if (attestationId == AttestationId.AADHAAR) {
|
||||
return _createAadhaarOutput(vcAndDiscloseProof, indices, attestationId, userIdentifier);
|
||||
} else {
|
||||
revert InvalidAttestationId();
|
||||
}
|
||||
@@ -939,7 +1065,7 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
* @return The encoded PassportOutput struct.
|
||||
*/
|
||||
function _createPassportOutput(
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof,
|
||||
GenericProofStruct memory vcAndDiscloseProof,
|
||||
CircuitConstantsV2.DiscloseIndices memory indices,
|
||||
bytes32 attestationId,
|
||||
uint256 userIdentifier
|
||||
@@ -976,7 +1102,7 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
* @return The encoded EuIdOutput struct.
|
||||
*/
|
||||
function _createEuIdOutput(
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof,
|
||||
GenericProofStruct memory vcAndDiscloseProof,
|
||||
CircuitConstantsV2.DiscloseIndices memory indices,
|
||||
bytes32 attestationId,
|
||||
uint256 userIdentifier
|
||||
@@ -1003,16 +1129,34 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
return abi.encode(euIdOutput);
|
||||
}
|
||||
|
||||
function _createAadhaarOutput(
|
||||
GenericProofStruct memory vcAndDiscloseProof,
|
||||
CircuitConstantsV2.DiscloseIndices memory indices,
|
||||
bytes32 attestationId,
|
||||
uint256 userIdentifier
|
||||
) internal pure returns (bytes memory) {
|
||||
SelfStructs.AadhaarOutput memory aadhaarOutput;
|
||||
aadhaarOutput.attestationId = uint256(attestationId);
|
||||
aadhaarOutput.userIdentifier = userIdentifier;
|
||||
aadhaarOutput.nullifier = vcAndDiscloseProof.pubSignals[indices.nullifierIndex];
|
||||
|
||||
uint256[4] memory revealedDataPacked;
|
||||
for (uint256 i = 0; i < 4; i++) {
|
||||
revealedDataPacked[i] = vcAndDiscloseProof.pubSignals[indices.revealedDataPackedIndex + i];
|
||||
}
|
||||
aadhaarOutput.revealedDataPacked = Formatter.fieldElementsToBytesAadhaar(revealedDataPacked);
|
||||
|
||||
return abi.encode(aadhaarOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Decodes VC and Disclose proof from bytes data.
|
||||
* @dev Simple wrapper around abi.decode for type safety and clarity.
|
||||
* @param data The encoded proof data.
|
||||
* @return The decoded VcAndDiscloseProof struct.
|
||||
*/
|
||||
function _decodeVcAndDiscloseProof(
|
||||
bytes memory data
|
||||
) internal pure returns (IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory) {
|
||||
return abi.decode(data, (IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof));
|
||||
function _decodeVcAndDiscloseProof(bytes memory data) internal pure returns (GenericProofStruct memory) {
|
||||
return abi.decode(data, (GenericProofStruct));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1026,7 +1170,7 @@ contract IdentityVerificationHubImplV2 is ImplRoot {
|
||||
*/
|
||||
function _performUserIdentifierCheck(
|
||||
bytes calldata userContextData,
|
||||
IVcAndDiscloseCircuitVerifier.VcAndDiscloseProof memory vcAndDiscloseProof,
|
||||
GenericProofStruct memory vcAndDiscloseProof,
|
||||
bytes32 attestationId,
|
||||
CircuitConstantsV2.DiscloseIndices memory indices
|
||||
) internal pure {
|
||||
|
||||
@@ -123,10 +123,7 @@ abstract contract SelfVerificationRoot is ISelfVerificationRoot {
|
||||
bytes31(0),
|
||||
// 32 bytes scope
|
||||
_scope,
|
||||
// 32 bytes attestationId
|
||||
attestationId,
|
||||
// proof data (starts after 32 bytes attestationId)
|
||||
proofPayload[32:]
|
||||
proofPayload
|
||||
);
|
||||
|
||||
// Call hub V2 verification
|
||||
|
||||
@@ -15,4 +15,5 @@ library AttestationId {
|
||||
*/
|
||||
bytes32 constant E_PASSPORT = bytes32(uint256(1));
|
||||
bytes32 constant EU_ID_CARD = bytes32(uint256(2));
|
||||
bytes32 constant AADHAAR = bytes32(uint256(3));
|
||||
}
|
||||
|
||||
@@ -43,6 +43,17 @@ library CircuitConstantsV2 {
|
||||
*/
|
||||
uint256 constant DSC_CSCA_ROOT_INDEX = 1;
|
||||
|
||||
// ---------------------------
|
||||
// Aadhaar Circuit Constants
|
||||
// ---------------------------
|
||||
/**
|
||||
* @notice Index to access the pubkey commitment in the Aadhaar circuit public signals.
|
||||
*/
|
||||
uint256 constant AADHAAR_UIDAI_PUBKEY_COMMITMENT_INDEX = 0;
|
||||
uint256 constant AADHAAR_NULLIFIER_INDEX = 1;
|
||||
uint256 constant AADHAAR_COMMITMENT_INDEX = 2;
|
||||
uint256 constant AADHAAR_TIMESTAMP_INDEX = 3;
|
||||
|
||||
// -------------------------------------
|
||||
// VC and Disclose Circuit Constants
|
||||
// -------------------------------------
|
||||
@@ -61,7 +72,7 @@ library CircuitConstantsV2 {
|
||||
uint256 nameyobSmtRootIndex;
|
||||
uint256 scopeIndex;
|
||||
uint256 userIdentifierIndex;
|
||||
uint256 passportNoSmtRootIndex; // Only for passport, 99 for ID card
|
||||
uint256 passportNoSmtRootIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,6 +111,21 @@ library CircuitConstantsV2 {
|
||||
userIdentifierIndex: 20,
|
||||
passportNoSmtRootIndex: 99
|
||||
});
|
||||
} else if (attestationId == AttestationId.AADHAAR) {
|
||||
return
|
||||
DiscloseIndices({
|
||||
revealedDataPackedIndex: 2,
|
||||
forbiddenCountriesListPackedIndex: 6,
|
||||
nullifierIndex: 0,
|
||||
attestationIdIndex: 10,
|
||||
merkleRootIndex: 16,
|
||||
currentDateIndex: 11,
|
||||
namedobSmtRootIndex: 14,
|
||||
nameyobSmtRootIndex: 15,
|
||||
scopeIndex: 17,
|
||||
userIdentifierIndex: 18,
|
||||
passportNoSmtRootIndex: 99
|
||||
});
|
||||
} else {
|
||||
revert("Invalid attestation ID");
|
||||
}
|
||||
|
||||
155
contracts/contracts/example/SelfPassportERC721.sol
Normal file
155
contracts/contracts/example/SelfPassportERC721.sol
Normal file
@@ -0,0 +1,155 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.28;
|
||||
|
||||
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
|
||||
import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol";
|
||||
import {AttestationId} from "../constants/AttestationId.sol";
|
||||
import {CircuitAttributeHandlerV2} from "../libraries/CircuitAttributeHandlerV2.sol";
|
||||
|
||||
import {SelfVerificationRoot} from "../abstract/SelfVerificationRoot.sol";
|
||||
|
||||
/**
|
||||
* @title SelfIdentityERC721 V2
|
||||
* @notice This contract issues ERC721 tokens based on verified identity credentials supporting both E-Passport and EUID cards
|
||||
* @dev Inherits from SelfVerificationRoot V2 for verification logic and ERC721 for NFT functionality
|
||||
*/
|
||||
contract SelfIdentityERC721 is SelfVerificationRoot, ERC721, Ownable {
|
||||
// ====================================================
|
||||
// Storage Variables
|
||||
// ====================================================
|
||||
|
||||
/// @notice Counter for token IDs
|
||||
uint256 private _tokenIdCounter;
|
||||
|
||||
/// @notice Mapping from token ID to identity attributes
|
||||
mapping(uint256 tokenId => ISelfVerificationRoot.GenericDiscloseOutputV2 identityAttributes)
|
||||
private _identityAttributes;
|
||||
|
||||
/// @notice Mapping to track minted user identifiers to prevent double minting
|
||||
mapping(uint256 userIdentifier => bool minted) private _mintedUserIdentifiers;
|
||||
|
||||
// ====================================================
|
||||
// Events
|
||||
// ====================================================
|
||||
|
||||
event IdentityNFTMinted(
|
||||
uint256 indexed tokenId,
|
||||
address indexed owner,
|
||||
bytes32 attestationId,
|
||||
ISelfVerificationRoot.GenericDiscloseOutputV2 attributes
|
||||
);
|
||||
|
||||
// ====================================================
|
||||
// Errors
|
||||
// ====================================================
|
||||
|
||||
error UserIdentifierAlreadyMinted();
|
||||
error InvalidUserIdentifier();
|
||||
|
||||
// ====================================================
|
||||
// Constructor
|
||||
// ====================================================
|
||||
|
||||
/**
|
||||
* @notice Constructor for the SelfIdentityERC721 V2 contract
|
||||
* @param identityVerificationHubAddress The address of the Identity Verification Hub V2
|
||||
* @param scopeValue The expected proof scope for user registration
|
||||
* @param name The name of the NFT collection
|
||||
* @param symbol The symbol of the NFT collection
|
||||
*/
|
||||
constructor(
|
||||
address identityVerificationHubAddress,
|
||||
uint256 scopeValue,
|
||||
string memory name,
|
||||
string memory symbol
|
||||
) SelfVerificationRoot(identityVerificationHubAddress, scopeValue) ERC721(name, symbol) Ownable(_msgSender()) {}
|
||||
|
||||
// ====================================================
|
||||
// External/Public Functions
|
||||
// ====================================================
|
||||
|
||||
/**
|
||||
* @notice Updates the scope used for verification
|
||||
* @dev Only callable by the contract owner
|
||||
* @param newScope The new scope to set
|
||||
*/
|
||||
function setScope(uint256 newScope) external onlyOwner {
|
||||
_setScope(newScope);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get identity attributes for a specific token ID
|
||||
* @param tokenId The token ID to query
|
||||
* @return The identity attributes associated with the token
|
||||
*/
|
||||
function getIdentityAttributes(
|
||||
uint256 tokenId
|
||||
) external view returns (ISelfVerificationRoot.GenericDiscloseOutputV2 memory) {
|
||||
require(_exists(tokenId), "Token does not exist");
|
||||
return _identityAttributes[tokenId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Check if a user identifier has already minted an NFT
|
||||
* @param userIdentifier The user identifier to check
|
||||
* @return True if the user identifier has already minted, false otherwise
|
||||
*/
|
||||
function isUserIdentifierMinted(uint256 userIdentifier) external view returns (bool) {
|
||||
return _mintedUserIdentifiers[userIdentifier];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the current scope value
|
||||
* @return The current scope value
|
||||
*/
|
||||
function getScope() external view returns (uint256) {
|
||||
return _scope;
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// Override Functions from SelfVerificationRoot
|
||||
// ====================================================
|
||||
|
||||
/**
|
||||
* @notice Hook called after successful verification - handles NFT minting
|
||||
* @dev Validates user identifier and mints identity NFT with extracted attributes for both E-Passport and EUID
|
||||
* @param output The verification output containing user data
|
||||
*/
|
||||
function customVerificationHook(
|
||||
ISelfVerificationRoot.GenericDiscloseOutputV2 memory output,
|
||||
bytes memory /* userData */
|
||||
) internal override {
|
||||
// Check if user identifier is valid
|
||||
if (output.userIdentifier == 0) {
|
||||
revert InvalidUserIdentifier();
|
||||
}
|
||||
|
||||
// Check if user identifier has already minted an NFT
|
||||
if (_mintedUserIdentifiers[output.userIdentifier]) {
|
||||
revert UserIdentifierAlreadyMinted();
|
||||
}
|
||||
|
||||
// Mint NFT
|
||||
uint256 tokenId = _tokenIdCounter++;
|
||||
_mint(msg.sender, tokenId);
|
||||
_identityAttributes[tokenId] = output;
|
||||
_mintedUserIdentifiers[output.userIdentifier] = true;
|
||||
|
||||
emit IdentityNFTMinted(tokenId, msg.sender, output.attestationId, output);
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// Internal Functions
|
||||
// ====================================================
|
||||
|
||||
/**
|
||||
* @notice Check if a token exists
|
||||
* @param tokenId The token ID to check
|
||||
* @return True if the token exists, false otherwise
|
||||
*/
|
||||
function _exists(uint256 tokenId) internal view returns (bool) {
|
||||
return _ownerOf(tokenId) != address(0);
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,10 @@ interface IDscCircuitVerifier {
|
||||
* @param pubSignals An array of two unsigned integers representing the public signals associated with the proof.
|
||||
*/
|
||||
struct DscCircuitProof {
|
||||
uint[2] a;
|
||||
uint[2][2] b;
|
||||
uint[2] c;
|
||||
uint[2] pubSignals;
|
||||
uint256[2] a;
|
||||
uint256[2][2] b;
|
||||
uint256[2] c;
|
||||
uint256[2] pubSignals;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,9 +31,9 @@ interface IDscCircuitVerifier {
|
||||
* @return A boolean value indicating whether the provided proof is valid (true) or not (false).
|
||||
*/
|
||||
function verifyProof(
|
||||
uint[2] calldata pA,
|
||||
uint[2][2] calldata pB,
|
||||
uint[2] calldata pC,
|
||||
uint[2] calldata pubSignals
|
||||
uint256[2] calldata pA,
|
||||
uint256[2][2] calldata pB,
|
||||
uint256[2] calldata pC,
|
||||
uint256[2] calldata pubSignals
|
||||
) external view returns (bool);
|
||||
}
|
||||
|
||||
113
contracts/contracts/interfaces/IIdentityRegistryAadhaarV1.sol
Normal file
113
contracts/contracts/interfaces/IIdentityRegistryAadhaarV1.sol
Normal file
@@ -0,0 +1,113 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.28;
|
||||
|
||||
/**
|
||||
* @title IIdentityRegistryV1
|
||||
* @notice Interface for the Identity Registry v1.
|
||||
* @dev This interface exposes only the external functions accessible by regular callers,
|
||||
* i.e. functions that are not owner-restricted.
|
||||
*/
|
||||
interface IIdentityRegistryAadhaarV1 {
|
||||
/**
|
||||
* @notice Retrieves the address of the registered identity verification hub.
|
||||
* @return The address of the hub.
|
||||
*/
|
||||
function hub() external view returns (address);
|
||||
|
||||
/**
|
||||
* @notice Checks if a specific nullifier is already registered for the given attestation.
|
||||
* @param nullifier The nullifier to check.
|
||||
* @return True if the nullifier is registered; otherwise, false.
|
||||
*/
|
||||
function nullifiers(uint256 nullifier) external view returns (bool);
|
||||
|
||||
/**
|
||||
* @notice Checks whether a UIDAI pubkey commitment is registered.
|
||||
* @param commitment The UIDAI pubkey commitment to check.
|
||||
* @return True if the commitment is registered, false otherwise.
|
||||
*/
|
||||
function isRegisteredUidaiPubkeyCommitment(uint256 commitment) external view returns (bool);
|
||||
|
||||
/**
|
||||
* @notice Retrieves the timestamp of the identity commitment Merkle tree root.
|
||||
* @param root The Merkle tree root to check.
|
||||
* @return The timestamp of the root.
|
||||
*/
|
||||
function rootTimestamps(uint256 root) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Checks if the identity commitment Merkle tree contains the specified root.
|
||||
* @param root The Merkle tree root to check.
|
||||
* @return True if the root exists in the tree, false otherwise.
|
||||
*/
|
||||
function checkIdentityCommitmentRoot(uint256 root) external view returns (bool);
|
||||
|
||||
/**
|
||||
* @notice Retrieves the total number of identity commitments in the Merkle tree.
|
||||
* @return The size (i.e., count) of the identity commitment Merkle tree.
|
||||
*/
|
||||
function getIdentityCommitmentMerkleTreeSize() external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Retrieves the current Merkle root of the identity commitments.
|
||||
* @return The current identity commitment Merkle root.
|
||||
*/
|
||||
function getIdentityCommitmentMerkleRoot() external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Retrieves the index of a specific identity commitment in the Merkle tree.
|
||||
* @param commitment The identity commitment to locate.
|
||||
* @return The index position of the provided commitment.
|
||||
*/
|
||||
function getIdentityCommitmentIndex(uint256 commitment) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Retrieves the current name and date of birth OFAC root.
|
||||
* @return The current name and date of birth OFAC root value.
|
||||
*/
|
||||
function getNameAndDobOfacRoot() external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Retrieves the current name and year of birth OFAC root.
|
||||
* @return The current name and year of birth OFAC root value.
|
||||
*/
|
||||
function getNameAndYobOfacRoot() external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Checks if the provided OFAC roots match the stored OFAC roots.
|
||||
* @param nameAndDobRoot The name and date of birth OFAC root to verify.
|
||||
* @param nameAndYobRoot The name and year of birth OFAC root to verify.
|
||||
* @param nameAndDobReverseRoot The name and date of birth OFAC root to verify.
|
||||
* @param nameAndYobReverseRoot The name and year of birth OFAC root to verify.
|
||||
* @return True if all provided roots match the stored values, false otherwise.
|
||||
*/
|
||||
function checkOfacRoots(
|
||||
uint256 nameAndDobRoot,
|
||||
uint256 nameAndYobRoot,
|
||||
uint256 nameAndDobReverseRoot,
|
||||
uint256 nameAndYobReverseRoot
|
||||
) external view returns (bool);
|
||||
|
||||
/**
|
||||
* @notice Checks if the provided UIDAI pubkey is stored in the registry and also if it's not expired.
|
||||
* @param commitment The UIDAI pubkey commitment to verify.
|
||||
* @return True if the given pubkey is stored in the registry and also if it's not expired, otherwise false.
|
||||
*/
|
||||
function checkUidaiPubkey(uint256 commitment) external view returns (bool);
|
||||
|
||||
/**
|
||||
* @notice Registers a new identity commitment.
|
||||
* @dev Must be called by the identity verification hub. Reverts if the nullifier has already been used.
|
||||
* @param nullifier A unique nullifier to prevent double registration.
|
||||
* @param commitment The identity commitment to register.
|
||||
*/
|
||||
function registerCommitment(uint256 nullifier, uint256 commitment) external;
|
||||
|
||||
/**
|
||||
* @notice Registers a new UIDAI pubkey commitment.
|
||||
* @dev Must be called by the identity verification hub. Reverts if the UIDAI pubkey commitment is already registered.
|
||||
* @param commitment The UIDAI pubkey commitment to register.
|
||||
* @param expiryTimestamp The expiry timestamp of the commitment.
|
||||
*/
|
||||
function registerUidaiPubkeyCommitment(uint256 commitment, uint256 expiryTimestamp) external;
|
||||
}
|
||||
@@ -5,6 +5,14 @@ pragma solidity 0.8.28;
|
||||
* @notice Interface for verifying register circuit proofs.
|
||||
* @dev This interface defines the structure of a register circuit proof and exposes a function to verify such proofs.
|
||||
*/
|
||||
|
||||
struct GenericProofStruct {
|
||||
uint256[2] a;
|
||||
uint256[2][2] b;
|
||||
uint256[2] c;
|
||||
uint256[] pubSignals;
|
||||
}
|
||||
|
||||
interface IRegisterCircuitVerifier {
|
||||
/**
|
||||
* @notice Represents a register circuit proof.
|
||||
@@ -15,10 +23,10 @@ interface IRegisterCircuitVerifier {
|
||||
* @param pubSignals An array of three unsigned integers representing the public signals associated with the proof.
|
||||
*/
|
||||
struct RegisterCircuitProof {
|
||||
uint[2] a;
|
||||
uint[2][2] b;
|
||||
uint[2] c;
|
||||
uint[3] pubSignals;
|
||||
uint256[2] a;
|
||||
uint256[2][2] b;
|
||||
uint256[2] c;
|
||||
uint256[3] pubSignals;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,9 +39,27 @@ interface IRegisterCircuitVerifier {
|
||||
* @return isValid A boolean value indicating whether the provided proof is valid (true) or not (false).
|
||||
*/
|
||||
function verifyProof(
|
||||
uint[2] calldata a,
|
||||
uint[2][2] calldata b,
|
||||
uint[2] calldata c,
|
||||
uint[3] calldata pubSignals
|
||||
uint256[2] calldata a,
|
||||
uint256[2][2] calldata b,
|
||||
uint256[2] calldata c,
|
||||
uint256[3] calldata pubSignals
|
||||
) external view returns (bool isValid);
|
||||
}
|
||||
|
||||
interface IAadhaarRegisterCircuitVerifier {
|
||||
/**
|
||||
* @notice Verifies a given register circuit proof.
|
||||
* @dev This function checks the validity of the provided proof parameters.
|
||||
* @param a The 'a' component of the proof.
|
||||
* @param b The 'b' component of the proof.
|
||||
* @param c The 'c' component of the proof.
|
||||
* @param pubSignals The public signals associated with the proof.
|
||||
* @return isValid A boolean value indicating whether the provided proof is valid (true) or not (false).
|
||||
*/
|
||||
function verifyProof(
|
||||
uint256[2] calldata a,
|
||||
uint256[2][2] calldata b,
|
||||
uint256[2] calldata c,
|
||||
uint256[4] calldata pubSignals
|
||||
) external view returns (bool isValid);
|
||||
}
|
||||
|
||||
@@ -6,19 +6,13 @@ pragma solidity 0.8.28;
|
||||
* @notice Interface for verifying zero-knowledge proofs related to VC and Disclose circuits.
|
||||
* @dev This interface defines the structure of a VC and Disclose proof and a function to verify such proofs.
|
||||
*/
|
||||
|
||||
interface IVcAndDiscloseCircuitVerifier {
|
||||
/**
|
||||
* @notice Represents a VC and Disclose proof.
|
||||
* @param a An array of two unsigned integers representing the proof component 'a'.
|
||||
* @param b A 2x2 array of unsigned integers representing the proof component 'b'.
|
||||
* @param c An array of two unsigned integers representing the proof component 'c'.
|
||||
* @param pubSignals An array of 16 unsigned integers representing the public signals associated with the proof.
|
||||
*/
|
||||
struct VcAndDiscloseProof {
|
||||
uint[2] a;
|
||||
uint[2][2] b;
|
||||
uint[2] c;
|
||||
uint[21] pubSignals;
|
||||
uint256[2] a;
|
||||
uint256[2][2] b;
|
||||
uint256[2] c;
|
||||
uint256[21] pubSignals;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,9 +25,27 @@ interface IVcAndDiscloseCircuitVerifier {
|
||||
* @return A boolean value indicating whether the proof is valid (true) or not (false).
|
||||
*/
|
||||
function verifyProof(
|
||||
uint[2] calldata a,
|
||||
uint[2][2] calldata b,
|
||||
uint[2] calldata c,
|
||||
uint[21] calldata pubSignals
|
||||
uint256[2] calldata a,
|
||||
uint256[2][2] calldata b,
|
||||
uint256[2] calldata c,
|
||||
uint256[21] calldata pubSignals
|
||||
) external view returns (bool);
|
||||
}
|
||||
|
||||
interface IVcAndDiscloseAadhaarCircuitVerifier {
|
||||
/**
|
||||
* @notice Verifies a given VC and Disclose zero-knowledge proof.
|
||||
* @dev This function checks the validity of the provided proof parameters.
|
||||
* @param a The 'a' component of the proof.
|
||||
* @param b The 'b' component of the proof.
|
||||
* @param c The 'c' component of the proof.
|
||||
* @param pubSignals The public signals associated with the proof.
|
||||
* @return A boolean value indicating whether the proof is valid (true) or not (false).
|
||||
*/
|
||||
function verifyProof(
|
||||
uint256[2] calldata a,
|
||||
uint256[2][2] calldata b,
|
||||
uint256[2] calldata c,
|
||||
uint256[19] calldata pubSignals
|
||||
) external view returns (bool);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ pragma solidity 0.8.28;
|
||||
import {Formatter} from "./Formatter.sol";
|
||||
import {AttestationId} from "../constants/AttestationId.sol";
|
||||
import {SelfStructs} from "./SelfStructs.sol";
|
||||
|
||||
/**
|
||||
* @title UnifiedAttributeHandler Library
|
||||
* @notice Provides functions for extracting and formatting attributes from both passport and ID card byte arrays.
|
||||
@@ -90,6 +89,28 @@ library CircuitAttributeHandlerV2 {
|
||||
ofacStart: 92,
|
||||
ofacEnd: 93
|
||||
});
|
||||
} else if (attestationId == AttestationId.AADHAAR) {
|
||||
return
|
||||
FieldPositions({
|
||||
issuingStateStart: 81,
|
||||
issuingStateEnd: 111,
|
||||
nameStart: 9,
|
||||
nameEnd: 70,
|
||||
documentNumberStart: 71,
|
||||
documentNumberEnd: 74,
|
||||
nationalityStart: 999,
|
||||
nationalityEnd: 999,
|
||||
dateOfBirthStart: 1,
|
||||
dateOfBirthEnd: 8,
|
||||
genderStart: 0,
|
||||
genderEnd: 0,
|
||||
expiryDateStart: 999,
|
||||
expiryDateEnd: 999,
|
||||
olderThanStart: 118,
|
||||
olderThanEnd: 118,
|
||||
ofacStart: 116,
|
||||
ofacEnd: 117
|
||||
});
|
||||
} else {
|
||||
revert("Invalid attestation ID");
|
||||
}
|
||||
@@ -114,6 +135,12 @@ library CircuitAttributeHandlerV2 {
|
||||
*/
|
||||
function getName(bytes32 attestationId, bytes memory charcodes) internal pure returns (string[] memory) {
|
||||
FieldPositions memory positions = getFieldPositions(attestationId);
|
||||
if (attestationId == AttestationId.AADHAAR) {
|
||||
string memory fullName = extractStringAttribute(charcodes, positions.nameStart, positions.nameEnd);
|
||||
string[] memory nameParts = new string[](2);
|
||||
nameParts[0] = fullName;
|
||||
return nameParts;
|
||||
}
|
||||
return Formatter.formatName(extractStringAttribute(charcodes, positions.nameStart, positions.nameEnd));
|
||||
}
|
||||
|
||||
@@ -153,6 +180,17 @@ library CircuitAttributeHandlerV2 {
|
||||
);
|
||||
}
|
||||
|
||||
function getDateOfBirthFullYear(
|
||||
bytes32 attestationId,
|
||||
bytes memory charcodes
|
||||
) internal pure returns (string memory) {
|
||||
FieldPositions memory positions = getFieldPositions(attestationId);
|
||||
return
|
||||
Formatter.formatDateFullYear(
|
||||
extractStringAttribute(charcodes, positions.dateOfBirthStart, positions.dateOfBirthEnd)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Retrieves the gender from the encoded attribute byte array.
|
||||
* @param attestationId The attestation identifier.
|
||||
@@ -281,6 +319,16 @@ library CircuitAttributeHandlerV2 {
|
||||
return getOlderThan(attestationId, charcodes) >= olderThan;
|
||||
}
|
||||
|
||||
function compareOlderThanNumeric(
|
||||
bytes32 attestationId,
|
||||
bytes memory charcodes,
|
||||
uint256 olderThan
|
||||
) internal pure returns (bool) {
|
||||
FieldPositions memory positions = getFieldPositions(attestationId);
|
||||
uint256 extractedAge = uint8(charcodes[positions.olderThanStart]);
|
||||
return extractedAge >= olderThan;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Extracts a substring from a specified range in the byte array.
|
||||
* @param charcodes The byte array containing the encoded attribute.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.4;
|
||||
pragma solidity 0.8.28;
|
||||
|
||||
import {CircuitAttributeHandlerV2} from "./CircuitAttributeHandlerV2.sol";
|
||||
import {AttestationId} from "../constants/AttestationId.sol";
|
||||
import {SelfStructs} from "./SelfStructs.sol";
|
||||
import {CircuitAttributeHandlerV2} from "./CircuitAttributeHandlerV2.sol";
|
||||
import {Formatter} from "./Formatter.sol";
|
||||
import {GenericFormatter} from "./GenericFormatter.sol";
|
||||
|
||||
@@ -35,6 +35,9 @@ library CustomVerifier {
|
||||
} else if (attestationId == AttestationId.EU_ID_CARD) {
|
||||
SelfStructs.EuIdOutput memory idCardOutput = abi.decode(proofOutput, (SelfStructs.EuIdOutput));
|
||||
return CustomVerifier.verifyIdCard(verificationConfig, idCardOutput);
|
||||
} else if (attestationId == AttestationId.AADHAAR) {
|
||||
SelfStructs.AadhaarOutput memory aadhaarOutput = abi.decode(proofOutput, (SelfStructs.AadhaarOutput));
|
||||
return CustomVerifier.verifyAadhaar(verificationConfig, aadhaarOutput);
|
||||
} else {
|
||||
revert InvalidAttestationId();
|
||||
}
|
||||
@@ -154,7 +157,6 @@ library CustomVerifier {
|
||||
revert InvalidOfacCheck();
|
||||
}
|
||||
}
|
||||
|
||||
if (verificationConfig.forbiddenCountriesEnabled) {
|
||||
for (uint256 i = 0; i < 4; i++) {
|
||||
if (
|
||||
@@ -214,4 +216,82 @@ library CustomVerifier {
|
||||
|
||||
return genericDiscloseOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Verifies an Aadhaar output.
|
||||
* @param verificationConfig The verification configuration.
|
||||
* @param aadhaarOutput The Aadhaar output from the circuit.
|
||||
* @return genericDiscloseOutput The generic disclose output.
|
||||
*/
|
||||
function verifyAadhaar(
|
||||
SelfStructs.VerificationConfigV2 memory verificationConfig,
|
||||
SelfStructs.AadhaarOutput memory aadhaarOutput
|
||||
) internal pure returns (SelfStructs.GenericDiscloseOutputV2 memory) {
|
||||
if (verificationConfig.ofacEnabled[1] || verificationConfig.ofacEnabled[2]) {
|
||||
if (
|
||||
!CircuitAttributeHandlerV2.compareOfac(
|
||||
AttestationId.AADHAAR,
|
||||
aadhaarOutput.revealedDataPacked,
|
||||
false,
|
||||
verificationConfig.ofacEnabled[1],
|
||||
verificationConfig.ofacEnabled[2]
|
||||
)
|
||||
) {
|
||||
revert InvalidOfacCheck();
|
||||
}
|
||||
}
|
||||
|
||||
if (verificationConfig.forbiddenCountriesEnabled) {
|
||||
for (uint256 i = 0; i < 4; i++) {
|
||||
if (
|
||||
aadhaarOutput.forbiddenCountriesListPacked[i] != verificationConfig.forbiddenCountriesListPacked[i]
|
||||
) {
|
||||
revert InvalidForbiddenCountries();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (verificationConfig.olderThanEnabled) {
|
||||
if (
|
||||
!CircuitAttributeHandlerV2.compareOlderThanNumeric(
|
||||
AttestationId.AADHAAR,
|
||||
aadhaarOutput.revealedDataPacked,
|
||||
verificationConfig.olderThan
|
||||
)
|
||||
) {
|
||||
revert InvalidOlderThan();
|
||||
}
|
||||
}
|
||||
|
||||
SelfStructs.GenericDiscloseOutputV2 memory genericDiscloseOutput = SelfStructs.GenericDiscloseOutputV2({
|
||||
attestationId: AttestationId.AADHAAR,
|
||||
userIdentifier: aadhaarOutput.userIdentifier,
|
||||
nullifier: aadhaarOutput.nullifier,
|
||||
forbiddenCountriesListPacked: verificationConfig.forbiddenCountriesListPacked,
|
||||
issuingState: CircuitAttributeHandlerV2.getIssuingState(
|
||||
AttestationId.AADHAAR,
|
||||
aadhaarOutput.revealedDataPacked
|
||||
),
|
||||
name: CircuitAttributeHandlerV2.getName(AttestationId.AADHAAR, aadhaarOutput.revealedDataPacked),
|
||||
idNumber: CircuitAttributeHandlerV2.getDocumentNumber(
|
||||
AttestationId.AADHAAR,
|
||||
aadhaarOutput.revealedDataPacked
|
||||
),
|
||||
nationality: "IND",
|
||||
dateOfBirth: CircuitAttributeHandlerV2.getDateOfBirthFullYear(
|
||||
AttestationId.AADHAAR,
|
||||
aadhaarOutput.revealedDataPacked
|
||||
),
|
||||
gender: CircuitAttributeHandlerV2.getGender(AttestationId.AADHAAR, aadhaarOutput.revealedDataPacked),
|
||||
expiryDate: "UNAVAILABLE",
|
||||
olderThan: verificationConfig.olderThan,
|
||||
ofac: [
|
||||
false,
|
||||
CircuitAttributeHandlerV2.getNameAndDobOfac(AttestationId.AADHAAR, aadhaarOutput.revealedDataPacked),
|
||||
CircuitAttributeHandlerV2.getNameAndYobOfac(AttestationId.AADHAAR, aadhaarOutput.revealedDataPacked)
|
||||
]
|
||||
});
|
||||
|
||||
return genericDiscloseOutput;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ library Formatter {
|
||||
bytes memory lastNameBytes;
|
||||
string[] memory names = new string[](2);
|
||||
|
||||
uint i = 0;
|
||||
uint256 i = 0;
|
||||
// Extract last name
|
||||
while (i < inputBytes.length && inputBytes[i] != "<") {
|
||||
lastNameBytes = abi.encodePacked(lastNameBytes, inputBytes[i]);
|
||||
@@ -85,6 +85,34 @@ library Formatter {
|
||||
return string(abi.encodePacked(day, "-", month, "-", year));
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Formats a full year date string into a human-readable date.
|
||||
* @dev Expects the input date string to have exactly 8 characters in YYYYMMDD format.
|
||||
* Returns the date in "YYYY-MM-DD" format.
|
||||
* @param date A string representing the date in YYYYMMDD format.
|
||||
* @return A formatted date string in the format "YYYY-MM-DD".
|
||||
*/
|
||||
function formatDateFullYear(string memory date) internal pure returns (string memory) {
|
||||
bytes memory dateBytes = bytes(date);
|
||||
if (dateBytes.length != 8) {
|
||||
revert InvalidDateLength();
|
||||
}
|
||||
|
||||
if (dateBytes[4] > "1" || (dateBytes[4] == "1" && dateBytes[5] > "2")) {
|
||||
revert InvalidMonthRange();
|
||||
}
|
||||
|
||||
if (dateBytes[6] > "3" || (dateBytes[6] == "3" && dateBytes[7] > "1")) {
|
||||
revert InvalidDayRange();
|
||||
}
|
||||
|
||||
string memory year = substring(date, 0, 4);
|
||||
string memory month = substring(date, 4, 6);
|
||||
string memory day = substring(date, 6, 8);
|
||||
|
||||
return string(abi.encodePacked(day, "-", month, "-", year));
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Converts an ASCII numeral code to its corresponding unsigned integer.
|
||||
* @dev The input must represent an ASCII code for digits (0-9), i.e. between 48 and 57.
|
||||
@@ -147,6 +175,28 @@ library Formatter {
|
||||
return bytesArray;
|
||||
}
|
||||
|
||||
function fieldElementsToBytesAadhaar(uint256[4] memory publicSignals) internal pure returns (bytes memory) {
|
||||
for (uint256 i = 0; i < 4; i++) {
|
||||
if (publicSignals[i] >= SNARK_SCALAR_FIELD) {
|
||||
revert InvalidFieldElement();
|
||||
}
|
||||
}
|
||||
|
||||
uint8[4] memory bytesCount = [31, 31, 31, 26];
|
||||
bytes memory bytesArray = new bytes(119);
|
||||
|
||||
uint256 index = 0;
|
||||
for (uint256 i = 0; i < 4; i++) {
|
||||
uint256 element = publicSignals[i];
|
||||
for (uint8 j = 0; j < bytesCount[i]; j++) {
|
||||
bytesArray[index++] = bytes1(uint8(element & 0xff));
|
||||
element = element >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
return bytesArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Extracts forbidden country codes from a packed uint256.
|
||||
* @dev Each forbidden country is represented by 3 bytes in the packed data.
|
||||
@@ -154,7 +204,6 @@ library Formatter {
|
||||
* @param publicSignals A packed uint256 containing encoded forbidden country data.
|
||||
* @return forbiddenCountries An array of strings representing the forbidden country codes.
|
||||
*/
|
||||
// TODO: look at this function a bit
|
||||
function extractForbiddenCountriesFromPacked(
|
||||
uint256[4] memory publicSignals
|
||||
) internal pure returns (string[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH] memory forbiddenCountries) {
|
||||
@@ -234,6 +283,19 @@ library Formatter {
|
||||
return currentTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Converts an array of 3 numerical values representing a date into a Unix timestamp.
|
||||
* @dev The input is expected to be in the format [year, month, day] and is not padded with 0s.
|
||||
* @param dateNum An array of 3 unsigned integers representing a date in YYMMDD format.
|
||||
* @return timestamp The Unix timestamp corresponding to the provided date.
|
||||
*/
|
||||
function proofDateToUnixTimestampNumeric(uint256[3] memory dateNum) internal pure returns (uint256) {
|
||||
if (dateNum[1] > 12 || dateNum[2] > 31) {
|
||||
revert InvalidDateDigit();
|
||||
}
|
||||
return toTimestamp(dateNum[0], dateNum[1], dateNum[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Converts a date string in YYMMDD format into a Unix timestamp.
|
||||
* @dev Parses the date string by extracting year, month, and day components using substring,
|
||||
@@ -271,11 +333,11 @@ library Formatter {
|
||||
* @param endIndex The ending index of the substring (exclusive).
|
||||
* @return The resulting substring.
|
||||
*/
|
||||
function substring(string memory str, uint startIndex, uint endIndex) internal pure returns (string memory) {
|
||||
function substring(string memory str, uint256 startIndex, uint256 endIndex) internal pure returns (string memory) {
|
||||
bytes memory strBytes = bytes(str);
|
||||
bytes memory result = new bytes(endIndex - startIndex);
|
||||
|
||||
for (uint i = startIndex; i < endIndex; i++) {
|
||||
for (uint256 i = startIndex; i < endIndex; i++) {
|
||||
result[i - startIndex] = strBytes[i];
|
||||
}
|
||||
|
||||
@@ -288,15 +350,15 @@ library Formatter {
|
||||
* @param value The string representing a number.
|
||||
* @return result The parsed unsigned integer.
|
||||
*/
|
||||
function parseDatePart(string memory value) internal pure returns (uint) {
|
||||
function parseDatePart(string memory value) internal pure returns (uint256) {
|
||||
bytes memory tempEmptyStringTest = bytes(value);
|
||||
if (tempEmptyStringTest.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint digit;
|
||||
uint result;
|
||||
for (uint i = 0; i < tempEmptyStringTest.length; i++) {
|
||||
uint256 digit;
|
||||
uint256 result;
|
||||
for (uint256 i = 0; i < tempEmptyStringTest.length; i++) {
|
||||
digit = uint8(tempEmptyStringTest[i]) - 48;
|
||||
result = result * 10 + digit;
|
||||
}
|
||||
@@ -312,7 +374,7 @@ library Formatter {
|
||||
* @param day The day of the month.
|
||||
* @return timestamp The Unix timestamp corresponding to the given date.
|
||||
*/
|
||||
function toTimestamp(uint256 year, uint256 month, uint256 day) internal pure returns (uint timestamp) {
|
||||
function toTimestamp(uint256 year, uint256 month, uint256 day) internal pure returns (uint256 timestamp) {
|
||||
uint16 i;
|
||||
|
||||
if (year < 1970 || year > 2100) {
|
||||
|
||||
@@ -51,6 +51,21 @@ library SelfStructs {
|
||||
uint256[4] forbiddenCountriesListPacked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Output structure for Aadhaar verification results
|
||||
* @param attestationId Unique identifier for the attestation
|
||||
* @param revealedDataPacked Packed binary data of revealed information
|
||||
* @param userIdentifier Unique identifier for the user
|
||||
* @param nullifier Cryptographic nullifier to prevent double-spending
|
||||
*/
|
||||
struct AadhaarOutput {
|
||||
uint256 attestationId;
|
||||
bytes revealedDataPacked;
|
||||
uint256 userIdentifier;
|
||||
uint256 nullifier;
|
||||
uint256[4] forbiddenCountriesListPacked;
|
||||
}
|
||||
|
||||
/// @dev OFAC verification mode: Passport number only
|
||||
uint256 constant passportNoOfac = 0;
|
||||
/// @dev OFAC verification mode: Name and date of birth
|
||||
|
||||
428
contracts/contracts/registry/IdentityRegistryAadhaarImplV1.sol
Normal file
428
contracts/contracts/registry/IdentityRegistryAadhaarImplV1.sol
Normal file
@@ -0,0 +1,428 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.28;
|
||||
|
||||
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
||||
import {InternalLeanIMT, LeanIMTData} from "@zk-kit/imt.sol/internal/InternalLeanIMT.sol";
|
||||
import {IIdentityRegistryAadhaarV1} from "../interfaces/IIdentityRegistryAadhaarV1.sol";
|
||||
import {ImplRoot} from "../upgradeable/ImplRoot.sol";
|
||||
import {AttestationId} from "../constants/AttestationId.sol";
|
||||
|
||||
/**
|
||||
* @notice ⚠️ CRITICAL STORAGE LAYOUT WARNING ⚠️
|
||||
* =============================================
|
||||
*
|
||||
* This contract uses the UUPS upgradeable pattern which makes storage layout EXTREMELY SENSITIVE.
|
||||
*
|
||||
* 🚫 NEVER MODIFY OR REORDER existing storage variables
|
||||
* 🚫 NEVER INSERT new variables between existing ones
|
||||
* 🚫 NEVER CHANGE THE TYPE of existing variables
|
||||
*
|
||||
* ✅ New storage variables MUST be added in one of these two ways ONLY:
|
||||
* 1. At the END of the storage layout
|
||||
* 2. In a new V2 contract that inherits from this V1
|
||||
* ✅ It is safe to rename variables (e.g., changing 'variable' to 'oldVariable')
|
||||
* as long as the type and order remain the same
|
||||
*
|
||||
* Examples of forbidden changes:
|
||||
* - Changing uint256 to uint128
|
||||
* - Changing bytes32 to bytes
|
||||
* - Changing array type to mapping
|
||||
*
|
||||
* For more detailed information about forbidden changes, please refer to:
|
||||
* https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#modifying-your-contracts
|
||||
*
|
||||
* ⚠️ VIOLATION OF THESE RULES WILL CAUSE CATASTROPHIC STORAGE COLLISIONS IN FUTURE UPGRADES ⚠️
|
||||
* =============================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* @title IdentityRegistryAadhaarStorageV1
|
||||
* @dev Abstract contract for storage layout of IdentityRegistryAadhaarImplV1.
|
||||
* Inherits from ImplRoot to provide upgradeable functionality.
|
||||
*/
|
||||
abstract contract IdentityRegistryAadhaarStorageV1 is ImplRoot {
|
||||
// ====================================================
|
||||
// Storage Variables
|
||||
|
||||
/// @notice Address of the identity verification hub.
|
||||
address internal _hub;
|
||||
|
||||
/// @notice Merkle tree data structure for identity commitments.
|
||||
LeanIMTData internal _identityCommitmentIMT;
|
||||
|
||||
/// @notice Mapping from Merkle tree root to its creation timestamp.
|
||||
mapping(uint256 => uint256) internal _rootTimestamps;
|
||||
|
||||
/// @notice Mapping from nullifier to a boolean indicating registration.
|
||||
mapping(uint256 => bool) internal _nullifiers;
|
||||
|
||||
/// @notice Mapping from UIDAI pubkey to the expirty timestamp.
|
||||
mapping(uint256 => uint256) internal _uidaiPubkeyExpiryTimestamps;
|
||||
|
||||
/// @notice Current name and date of birth OFAC root.
|
||||
uint256 internal _nameAndDobOfacRoot;
|
||||
|
||||
/// @notice Current name and year of birth OFAC root.
|
||||
uint256 internal _nameAndYobOfacRoot;
|
||||
|
||||
/// @notice Current name and date of birth reverse OFAC root.
|
||||
uint256 internal _nameAndDobReverseOfacRoot;
|
||||
|
||||
/// @notice Current name and year of birth reverse OFAC root.
|
||||
uint256 internal _nameAndYobReverseOfacRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title IdentityRegistryAadhaarImplV1
|
||||
* @notice Provides functions to register and manage identity commitments using a Merkle tree structure.
|
||||
* @dev Inherits from IdentityRegistryAadhaarStorageV1 and implements IIdentityRegistryAadhaarV1.
|
||||
*/
|
||||
contract IdentityRegistryAadhaarImplV1 is IdentityRegistryAadhaarStorageV1, IIdentityRegistryAadhaarV1 {
|
||||
using InternalLeanIMT for LeanIMTData;
|
||||
|
||||
// ====================================================
|
||||
// Events
|
||||
// ====================================================
|
||||
|
||||
/// @notice Emitted when the registry is initialized.
|
||||
event RegistryInitialized(address hub);
|
||||
/// @notice Emitted when the hub address is updated.
|
||||
event HubUpdated(address hub);
|
||||
/// @notice Emitted when the name and date of birth OFAC root is updated.
|
||||
event NameAndDobOfacRootUpdated(uint256 nameAndDobOfacRoot);
|
||||
/// @notice Emitted when the name and year of birth OFAC root is updated.
|
||||
event NameAndYobOfacRootUpdated(uint256 nameAndYobOfacRoot);
|
||||
/// @notice Emitted when the name and date of birth reverse OFAC root is updated.
|
||||
event NameAndDobReverseOfacRootUpdated(uint256 nameAndDobReverseOfacRoot);
|
||||
/// @notice Emitted when the name and year of birth reverse OFAC root is updated.
|
||||
event NameAndYobReverseOfacRootUpdated(uint256 nameAndYobReverseOfacRoot);
|
||||
/// @notice Emitted when an identity commitment is successfully registered.
|
||||
event CommitmentRegistered(
|
||||
bytes32 indexed attestationId,
|
||||
uint256 indexed nullifier,
|
||||
uint256 indexed commitment,
|
||||
uint256 timestamp,
|
||||
uint256 imtRoot,
|
||||
uint256 imtIndex
|
||||
);
|
||||
/// @notice Emitted when a UIDAI pubkey commitment is successfully registered.
|
||||
event UidaiPubkeyCommitmentRegistered(uint256 indexed commitment, uint256 timestamp);
|
||||
|
||||
/// @notice Emitted when a UIDAI pubkey commitment is successfully updated.
|
||||
event UidaiPubkeyCommitmentUpdated(uint256 indexed commitment, uint256 timestamp);
|
||||
|
||||
/// @notice Emitted when a UIDAI pubkey commitment is successfully removed.
|
||||
event UidaiPubkeyCommitmentRemoved(uint256 indexed commitment, uint256 timestamp);
|
||||
|
||||
/// @notice Emitted when a identity commitment is added by dev team.
|
||||
event DevCommitmentRegistered(
|
||||
bytes32 indexed attestationId,
|
||||
uint256 indexed nullifier,
|
||||
uint256 indexed commitment,
|
||||
uint256 timestamp,
|
||||
uint256 imtRoot,
|
||||
uint256 imtIndex
|
||||
);
|
||||
/// @notice Emitted when a identity commitment is updated by dev team.
|
||||
event DevCommitmentUpdated(uint256 indexed oldLeaf, uint256 indexed newLeaf, uint256 imtRoot, uint256 timestamp);
|
||||
/// @notice Emitted when a identity commitment is removed by dev team.
|
||||
event DevCommitmentRemoved(uint256 indexed oldLeaf, uint256 imtRoot, uint256 timestamp);
|
||||
|
||||
// ====================================================
|
||||
// Errors
|
||||
// ====================================================
|
||||
|
||||
/// @notice Thrown when the hub is not set.
|
||||
error HUB_NOT_SET();
|
||||
/// @notice Thrown when a function is accessed by an address other than the designated hub.
|
||||
error ONLY_HUB_CAN_ACCESS();
|
||||
/// @notice Thrown when attempting to register a commitment that has already been registered.
|
||||
error REGISTERED_COMMITMENT();
|
||||
/// @notice Thrown when the expiry timestamp is in the past.
|
||||
error EXPIRY_IN_PAST();
|
||||
/// @notice Thrown when the hub address is set to the zero address.
|
||||
error HUB_ADDRESS_ZERO();
|
||||
|
||||
// ====================================================
|
||||
// Modifiers
|
||||
// ====================================================
|
||||
|
||||
/// @notice Modifier to restrict access to functions to only the hub.
|
||||
modifier onlyHub() {
|
||||
if (address(_hub) == address(0)) revert HUB_NOT_SET();
|
||||
if (msg.sender != address(_hub)) revert ONLY_HUB_CAN_ACCESS();
|
||||
_;
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// Constructor
|
||||
// ====================================================
|
||||
|
||||
/// @notice Constructor for the IdentityRegistryAadhaarImplV1 contract.
|
||||
constructor() {
|
||||
_disableInitializers();
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// Initializer
|
||||
// ====================================================
|
||||
|
||||
/// @notice Initializes the registry implementation.
|
||||
/// @dev Sets the hub address and initializes the UUPS upgradeable feature.
|
||||
/// @param _hub The address of the identity verification hub.
|
||||
function initialize(address _hub) external initializer {
|
||||
__ImplRoot_init();
|
||||
_hub = _hub;
|
||||
emit RegistryInitialized(_hub);
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// External Functions - View & Checks
|
||||
// ====================================================
|
||||
|
||||
/// @notice Retrieves the hub address.
|
||||
/// @return The current identity verification hub address.
|
||||
function hub() external view virtual onlyProxy returns (address) {
|
||||
return _hub;
|
||||
}
|
||||
|
||||
/// @notice Checks if a specific nullifier is registered for a given attestation.
|
||||
/// @param nullifier The nullifier to be checked.
|
||||
/// @return True if the nullifier has been registered, false otherwise.
|
||||
function nullifiers(uint256 nullifier) external view virtual onlyProxy returns (bool) {
|
||||
return _nullifiers[nullifier];
|
||||
}
|
||||
|
||||
/// @notice Retrieves the timestamp of the identity commitment Merkle tree root.
|
||||
/// @param root The Merkle tree root to check.
|
||||
/// @return The timestamp of the root.
|
||||
function rootTimestamps(uint256 root) external view virtual onlyProxy returns (uint256) {
|
||||
return _rootTimestamps[root];
|
||||
}
|
||||
|
||||
/// @notice Checks if a UIDAI pubkey commitment is registered.
|
||||
/// @param commitment The UIDAI pubkey commitment to check.
|
||||
/// @return True if the commitment is registered, false otherwise.
|
||||
function isRegisteredUidaiPubkeyCommitment(uint256 commitment) external view virtual onlyProxy returns (bool) {
|
||||
uint256 expiryTimestamp = _uidaiPubkeyExpiryTimestamps[commitment];
|
||||
return expiryTimestamp > block.timestamp;
|
||||
}
|
||||
|
||||
/// @notice Retrieves the expiry timestamp of a UIDAI pubkey commitment.
|
||||
/// @param commitment The UIDAI pubkey commitment to check.
|
||||
/// @return The expiry timestamp of the commitment.
|
||||
function getUidaiPubkeyExpiryTimestamp(uint256 commitment) external view virtual onlyProxy returns (uint256) {
|
||||
return _uidaiPubkeyExpiryTimestamps[commitment];
|
||||
}
|
||||
|
||||
/// @notice Checks if the identity commitment Merkle tree contains the specified root.
|
||||
/// @param root The Merkle tree root to check.
|
||||
/// @return True if the root exists in the tree, false otherwise.
|
||||
function checkIdentityCommitmentRoot(uint256 root) external view virtual onlyProxy returns (bool) {
|
||||
return _rootTimestamps[root] > 0;
|
||||
}
|
||||
|
||||
/// @notice Retrieves the total number of identity commitments in the Merkle tree.
|
||||
/// @return The size (i.e., count) of the identity commitment Merkle tree.
|
||||
function getIdentityCommitmentMerkleTreeSize() external view virtual onlyProxy returns (uint256) {
|
||||
return _identityCommitmentIMT.size;
|
||||
}
|
||||
|
||||
/// @notice Retrieves the current Merkle root of the identity commitments.
|
||||
/// @return The current identity commitment Merkle root.
|
||||
function getIdentityCommitmentMerkleRoot() external view virtual onlyProxy returns (uint256) {
|
||||
return _identityCommitmentIMT._root();
|
||||
}
|
||||
|
||||
/// @notice Retrieves the index of a specific identity commitment in the Merkle tree.
|
||||
/// @param commitment The identity commitment to locate.
|
||||
/// @return The index position of the provided commitment.
|
||||
function getIdentityCommitmentIndex(uint256 commitment) external view virtual onlyProxy returns (uint256) {
|
||||
return _identityCommitmentIMT._indexOf(commitment);
|
||||
}
|
||||
|
||||
/// @notice Retrieves the current name and date of birth OFAC root.
|
||||
/// @return The current name and date of birth OFAC root value.
|
||||
function getNameAndDobOfacRoot() external view virtual onlyProxy returns (uint256) {
|
||||
return _nameAndDobOfacRoot;
|
||||
}
|
||||
|
||||
/// @notice Retrieves the current name and year of birth OFAC root.
|
||||
/// @return The current name and year of birth OFAC root value.
|
||||
function getNameAndYobOfacRoot() external view virtual onlyProxy returns (uint256) {
|
||||
return _nameAndYobOfacRoot;
|
||||
}
|
||||
|
||||
/// @notice Retrieves the current name and date of birth reverse OFAC root.
|
||||
/// @return The current name and date of birth reverse OFAC root value.
|
||||
function getNameAndDobReverseOfacRoot() external view virtual onlyProxy returns (uint256) {
|
||||
return _nameAndDobReverseOfacRoot;
|
||||
}
|
||||
|
||||
/// @notice Retrieves the current name and year of birth reverse OFAC root.
|
||||
/// @return The current name and year of birth reverse OFAC root value.
|
||||
function getNameAndYobReverseOfacRoot() external view virtual onlyProxy returns (uint256) {
|
||||
return _nameAndYobReverseOfacRoot;
|
||||
}
|
||||
|
||||
/// @notice Validates whether the provided OFAC roots match the stored values.
|
||||
/// @param nameAndDobRoot The name and date of birth OFAC root to validate.
|
||||
/// @param nameAndYobRoot The name and year of birth OFAC root to validate.
|
||||
/// @return True if all provided roots match the stored values, false otherwise.
|
||||
function checkOfacRoots(
|
||||
uint256 nameAndDobRoot,
|
||||
uint256 nameAndYobRoot,
|
||||
uint256 nameAndDobReverseRoot,
|
||||
uint256 nameAndYobReverseRoot
|
||||
) external view virtual onlyProxy returns (bool) {
|
||||
return
|
||||
_nameAndDobOfacRoot == nameAndDobRoot &&
|
||||
_nameAndYobOfacRoot == nameAndYobRoot &&
|
||||
_nameAndDobReverseOfacRoot == nameAndDobReverseRoot &&
|
||||
_nameAndYobReverseOfacRoot == nameAndYobReverseRoot;
|
||||
}
|
||||
|
||||
/// @notice Checks if the provided UIDAI pubkey is stored in the registry and also if it's not expired.
|
||||
/// @param pubkey The UIDAI pubkey to verify.
|
||||
/// @return True if the given pubkey is stored in the registry and also if it's not expired, otherwise false.
|
||||
function checkUidaiPubkey(uint256 pubkey) external view virtual onlyProxy returns (bool) {
|
||||
uint256 expiryTimestamp = _uidaiPubkeyExpiryTimestamps[pubkey];
|
||||
return expiryTimestamp > block.timestamp;
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// External Functions - Registration
|
||||
// ====================================================
|
||||
|
||||
/// @notice Registers a new identity commitment.
|
||||
/// @dev Caller must be the hub. Reverts if the nullifier is already registered.
|
||||
/// @param nullifier The nullifier associated with the identity commitment.
|
||||
/// @param commitment The identity commitment to register.
|
||||
function registerCommitment(uint256 nullifier, uint256 commitment) external onlyProxy onlyHub {
|
||||
if (_nullifiers[nullifier]) revert REGISTERED_COMMITMENT();
|
||||
|
||||
_nullifiers[nullifier] = true;
|
||||
uint256 index = _identityCommitmentIMT.size;
|
||||
uint256 imt_root = _identityCommitmentIMT._insert(commitment);
|
||||
_rootTimestamps[imt_root] = block.timestamp;
|
||||
emit CommitmentRegistered(AttestationId.AADHAAR, nullifier, commitment, block.timestamp, imt_root, index);
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// External Functions - Only Owner
|
||||
// ====================================================
|
||||
|
||||
/// @notice Updates the hub address.
|
||||
/// @dev Callable only via a proxy and restricted to the contract owner.
|
||||
/// @param newHubAddress The new address of the hub.
|
||||
function updateHub(address newHubAddress) external onlyProxy onlyOwner {
|
||||
if (newHubAddress == address(0)) revert HUB_ADDRESS_ZERO();
|
||||
_hub = newHubAddress;
|
||||
emit HubUpdated(newHubAddress);
|
||||
}
|
||||
|
||||
/// @notice Updates the name and date of birth OFAC root.
|
||||
/// @dev Callable only via a proxy and restricted to the contract owner.
|
||||
/// @param newNameAndDobOfacRoot The new name and date of birth OFAC root value.
|
||||
function updateNameAndDobOfacRoot(uint256 newNameAndDobOfacRoot) external onlyProxy onlyOwner {
|
||||
_nameAndDobOfacRoot = newNameAndDobOfacRoot;
|
||||
emit NameAndDobOfacRootUpdated(newNameAndDobOfacRoot);
|
||||
}
|
||||
|
||||
/// @notice Updates the name and year of birth OFAC root.
|
||||
/// @dev Callable only via a proxy and restricted to the contract owner.
|
||||
/// @param newNameAndYobOfacRoot The new name and year of birth OFAC root value.
|
||||
function updateNameAndYobOfacRoot(uint256 newNameAndYobOfacRoot) external onlyProxy onlyOwner {
|
||||
_nameAndYobOfacRoot = newNameAndYobOfacRoot;
|
||||
emit NameAndYobOfacRootUpdated(newNameAndYobOfacRoot);
|
||||
}
|
||||
|
||||
/// @notice Updates the name and date of birth reverse OFAC root.
|
||||
/// @dev Callable only via a proxy and restricted to the contract owner.
|
||||
/// @param newNameAndDobReverseOfacRoot The new name and date of birth reverse OFAC root value.
|
||||
function updateNameAndDobReverseOfacRoot(uint256 newNameAndDobReverseOfacRoot) external onlyProxy onlyOwner {
|
||||
_nameAndDobReverseOfacRoot = newNameAndDobReverseOfacRoot;
|
||||
emit NameAndDobReverseOfacRootUpdated(newNameAndDobReverseOfacRoot);
|
||||
}
|
||||
|
||||
/// @notice Updates the name and year of birth reverse OFAC root.
|
||||
/// @dev Callable only via a proxy and restricted to the contract owner.
|
||||
/// @param newNameAndYobReverseOfacRoot The new name and year of birth reverse OFAC root value.
|
||||
function updateNameAndYobReverseOfacRoot(uint256 newNameAndYobReverseOfacRoot) external onlyProxy onlyOwner {
|
||||
_nameAndYobReverseOfacRoot = newNameAndYobReverseOfacRoot;
|
||||
emit NameAndYobReverseOfacRootUpdated(newNameAndYobReverseOfacRoot);
|
||||
}
|
||||
|
||||
/// @notice Registers a new UIDAI pubkey commitment.
|
||||
/// @dev Callable only via a proxy and restricted to the contract owner.
|
||||
/// @param commitment The UIDAI pubkey commitment to register.
|
||||
/// @param expiryTimestamp The expiry timestamp of the commitment.
|
||||
function registerUidaiPubkeyCommitment(uint256 commitment, uint256 expiryTimestamp) external onlyProxy onlyOwner {
|
||||
if (expiryTimestamp < block.timestamp) revert EXPIRY_IN_PAST();
|
||||
_uidaiPubkeyExpiryTimestamps[commitment] = expiryTimestamp;
|
||||
emit UidaiPubkeyCommitmentRegistered(commitment, expiryTimestamp);
|
||||
}
|
||||
|
||||
/// @notice Removes a UIDAI pubkey commitment.
|
||||
/// @dev Callable only via a proxy and restricted to the contract owner.
|
||||
/// @param commitment The UIDAI pubkey commitment to remove.
|
||||
function removeUidaiPubkeyCommitment(uint256 commitment) external onlyProxy onlyOwner {
|
||||
delete _uidaiPubkeyExpiryTimestamps[commitment];
|
||||
emit UidaiPubkeyCommitmentRemoved(commitment, block.timestamp);
|
||||
}
|
||||
|
||||
/// @notice Updates the expiry timestamp of a UIDAI pubkey commitment.
|
||||
/// @dev Callable only via a proxy and restricted to the contract owner.
|
||||
/// @param commitment The UIDAI pubkey commitment to update.
|
||||
/// @param expiryTimestamp The new expiry timestamp of the commitment.
|
||||
function updateUidaiPubkeyCommitmentExpiryTimestamp(
|
||||
uint256 commitment,
|
||||
uint256 expiryTimestamp
|
||||
) external onlyProxy onlyOwner {
|
||||
if (expiryTimestamp < block.timestamp) revert EXPIRY_IN_PAST();
|
||||
_uidaiPubkeyExpiryTimestamps[commitment] = expiryTimestamp;
|
||||
emit UidaiPubkeyCommitmentUpdated(commitment, expiryTimestamp);
|
||||
}
|
||||
|
||||
/// @notice (DEV) Force-adds an identity commitment.
|
||||
/// @dev Callable only by the owner for testing or administration.
|
||||
/// @param attestationId The identifier for the attestation.
|
||||
/// @param nullifier The nullifier associated with the identity commitment.
|
||||
/// @param commitment The identity commitment to add.
|
||||
function devAddIdentityCommitment(
|
||||
bytes32 attestationId,
|
||||
uint256 nullifier,
|
||||
uint256 commitment
|
||||
) external onlyProxy onlyOwner {
|
||||
_nullifiers[nullifier] = true;
|
||||
uint256 imt_root = _identityCommitmentIMT._insert(commitment);
|
||||
_rootTimestamps[imt_root] = block.timestamp;
|
||||
uint256 index = _identityCommitmentIMT._indexOf(commitment);
|
||||
emit DevCommitmentRegistered(attestationId, nullifier, commitment, block.timestamp, imt_root, index);
|
||||
}
|
||||
|
||||
/// @notice (DEV) Updates an existing identity commitment.
|
||||
/// @dev Caller must be the owner. Provides sibling nodes for proof of position.
|
||||
/// @param oldLeaf The current identity commitment to update.
|
||||
/// @param newLeaf The new identity commitment.
|
||||
/// @param siblingNodes An array of sibling nodes for Merkle proof generation.
|
||||
function devUpdateCommitment(
|
||||
uint256 oldLeaf,
|
||||
uint256 newLeaf,
|
||||
uint256[] calldata siblingNodes
|
||||
) external onlyProxy onlyOwner {
|
||||
uint256 imt_root = _identityCommitmentIMT._update(oldLeaf, newLeaf, siblingNodes);
|
||||
_rootTimestamps[imt_root] = block.timestamp;
|
||||
emit DevCommitmentUpdated(oldLeaf, newLeaf, imt_root, block.timestamp);
|
||||
}
|
||||
|
||||
/// @notice (DEV) Removes an existing identity commitment.
|
||||
/// @dev Caller must be the owner. Provides sibling nodes for proof of position.
|
||||
/// @param oldLeaf The identity commitment to remove.
|
||||
/// @param siblingNodes An array of sibling nodes for Merkle proof generation.
|
||||
function devRemoveCommitment(uint256 oldLeaf, uint256[] calldata siblingNodes) external onlyProxy onlyOwner {
|
||||
uint256 imt_root = _identityCommitmentIMT._remove(oldLeaf, siblingNodes);
|
||||
_rootTimestamps[imt_root] = block.timestamp;
|
||||
emit DevCommitmentRemoved(oldLeaf, imt_root, block.timestamp);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/U
|
||||
import {InternalLeanIMT, LeanIMTData} from "@zk-kit/imt.sol/internal/InternalLeanIMT.sol";
|
||||
import {IIdentityRegistryIdCardV1} from "../interfaces/IIdentityRegistryIdCardV1.sol";
|
||||
import {ImplRoot} from "../upgradeable/ImplRoot.sol";
|
||||
|
||||
/**
|
||||
* @notice ⚠️ CRITICAL STORAGE LAYOUT WARNING ⚠️
|
||||
* =============================================
|
||||
|
||||
@@ -81,11 +81,12 @@ contract TestSelfVerificationRoot is SelfVerificationRoot {
|
||||
|
||||
function setVerificationConfig(SelfStructs.VerificationConfigV2 memory config) external {
|
||||
verificationConfig = config;
|
||||
_identityVerificationHubV2.setVerificationConfigV2(verificationConfig);
|
||||
verificationConfigId = _identityVerificationHubV2.setVerificationConfigV2(verificationConfig);
|
||||
}
|
||||
|
||||
function setVerificationConfigNoHub(SelfStructs.VerificationConfigV2 memory config) external {
|
||||
verificationConfig = config;
|
||||
verificationConfigId = bytes32(uint256(1));
|
||||
}
|
||||
|
||||
function setConfigId(bytes32 configId) external {
|
||||
|
||||
@@ -34,15 +34,19 @@ contract TestFormatter {
|
||||
return Formatter.dateToUnixTimestamp(date);
|
||||
}
|
||||
|
||||
function testSubstring(string memory str, uint startIndex, uint endIndex) external pure returns (string memory) {
|
||||
function testSubstring(
|
||||
string memory str,
|
||||
uint256 startIndex,
|
||||
uint256 endIndex
|
||||
) external pure returns (string memory) {
|
||||
return Formatter.substring(str, startIndex, endIndex);
|
||||
}
|
||||
|
||||
function testParseDatePart(string memory value) external pure returns (uint) {
|
||||
function testParseDatePart(string memory value) external pure returns (uint256) {
|
||||
return Formatter.parseDatePart(value);
|
||||
}
|
||||
|
||||
function testToTimestamp(uint256 year, uint256 month, uint256 day) external pure returns (uint) {
|
||||
function testToTimestamp(uint256 year, uint256 month, uint256 day) external pure returns (uint256) {
|
||||
return Formatter.toTimestamp(year, month, day);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha1_ecdsa_brainpoolP256r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha1_ecdsa_secp256r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha1_rsa_65537_4096 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha256_ecdsa_brainpoolP256r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha256_ecdsa_brainpoolP384r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha256_ecdsa_secp256r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha256_ecdsa_secp384r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha256_ecdsa_secp521r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha256_rsa_65537_4096 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha256_rsapss_3_32_3072 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha256_rsapss_65537_32_3072 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha256_rsapss_65537_32_4096 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha384_ecdsa_brainpoolP384r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha384_ecdsa_brainpoolP512r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha384_ecdsa_secp384r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha512_ecdsa_brainpoolP512r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha512_ecdsa_secp521r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha512_rsa_65537_4096 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -58,10 +58,10 @@ contract Verifier_dsc_sha512_rsapss_65537_64_4096 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[2] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha1_sha1_sha1_ecdsa_brainpoolP224r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha1_sha1_sha1_ecdsa_secp256r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha1_sha1_sha1_rsa_65537_4096 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha1_sha256_sha256_rsa_65537_4096 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha224_sha224_sha224_ecdsa_brainpoolP224r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha256_sha224_sha224_ecdsa_secp224r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha256_sha256_sha256_ecdsa_brainpoolP256r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha256_sha256_sha256_ecdsa_brainpoolP384r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha256_sha256_sha256_ecdsa_secp256r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha256_sha256_sha256_ecdsa_secp384r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha256_sha256_sha256_rsa_3_4096 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha256_sha256_sha256_rsa_65537_4096 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha256_sha256_sha256_rsapss_3_32_2048 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha256_sha256_sha256_rsapss_65537_32_2048 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha256_sha256_sha256_rsapss_65537_32_3072 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha256_sha256_sha256_rsapss_65537_64_2048 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha384_sha384_sha384_ecdsa_brainpoolP384r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
@@ -61,10 +61,10 @@ contract Verifier_register_sha384_sha384_sha384_ecdsa_brainpoolP512r1 {
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint[2] calldata _pA,
|
||||
uint[2][2] calldata _pB,
|
||||
uint[2] calldata _pC,
|
||||
uint[3] calldata _pubSignals
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[3] calldata _pubSignals
|
||||
) public view returns (bool) {
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user