├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ └── issue-report.md ├── dependabot.yml └── workflows │ ├── ci.yaml │ ├── issues.yaml │ └── npm-publish.yml ├── .gitignore ├── .mocharc.json ├── .npmrc ├── .nvmrc ├── .prettierrc ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── config └── api-extractor.json ├── index.html ├── package-lock.json ├── package.json ├── rollup.config.mjs ├── scripts ├── doc-documenter.ts ├── doc-extract.ts └── doc-watch.ts ├── src ├── blockchain │ ├── index.ts │ └── transaction-service.ts ├── circuits │ ├── atomic-query-mtp-v2-on-chain.ts │ ├── atomic-query-mtp-v2.ts │ ├── atomic-query-sig-v2-on-chain.ts │ ├── atomic-query-sig-v2.ts │ ├── atomic-query-v3-on-chain.ts │ ├── atomic-query-v3.ts │ ├── auth-v2.ts │ ├── common.ts │ ├── comparer.ts │ ├── index.ts │ ├── linked-multi-query.ts │ ├── models.ts │ └── state-transition.ts ├── credentials │ ├── credential-wallet.ts │ ├── index.ts │ ├── models.ts │ ├── rhs.ts │ ├── status │ │ ├── agent-revocation.ts │ │ ├── credential-status-publisher.ts │ │ ├── did-resolver-revocation.ts │ │ ├── on-chain-revocation.ts │ │ ├── resolver.ts │ │ ├── reverse-sparse-merkle-tree.ts │ │ └── sparse-merkle-tree.ts │ └── utils.ts ├── iden3comm │ ├── constants.ts │ ├── errors.ts │ ├── handlers │ │ ├── auth.ts │ │ ├── common.ts │ │ ├── contract-request.ts │ │ ├── credential-proposal.ts │ │ ├── discovery-protocol.ts │ │ ├── fetch.ts │ │ ├── index.ts │ │ ├── message-handler.ts │ │ ├── payment.ts │ │ ├── problem-report.ts │ │ ├── refresh.ts │ │ └── revocation-status.ts │ ├── index.ts │ ├── packageManager.ts │ ├── packers │ │ ├── index.ts │ │ ├── jws.ts │ │ ├── plain.ts │ │ └── zkp.ts │ ├── types │ │ ├── index.ts │ │ ├── models.ts │ │ ├── packageManager.ts │ │ ├── packer.ts │ │ └── protocol │ │ │ ├── accept-profile.ts │ │ │ ├── auth.ts │ │ │ ├── contract-request.ts │ │ │ ├── credentials.ts │ │ │ ├── discovery-protocol.ts │ │ │ ├── messages.ts │ │ │ ├── payment.ts │ │ │ ├── problem-report.ts │ │ │ ├── proof.ts │ │ │ ├── proposal-request.ts │ │ │ └── revocation.ts │ └── utils │ │ ├── accept-profile.ts │ │ ├── did.ts │ │ ├── envelope.ts │ │ ├── index.ts │ │ └── message.ts ├── identity │ ├── common.ts │ ├── identity-wallet.ts │ └── index.ts ├── index.ts ├── kms │ ├── index.ts │ ├── key-providers │ │ ├── bjj-provider.ts │ │ ├── ed25519-provider.ts │ │ ├── index.ts │ │ └── secp256k1-provider.ts │ ├── kms.ts │ ├── provider-helpers.ts │ └── store │ │ ├── abstract-key-store.ts │ │ ├── index.ts │ │ ├── indexed-db-key-store.ts │ │ ├── local-storage-key-store.ts │ │ ├── memory-key-store.ts │ │ └── types.ts ├── proof │ ├── common.ts │ ├── index.ts │ ├── proof-service.ts │ ├── provers │ │ ├── index.ts │ │ ├── inputs-generator.ts │ │ ├── prover.ts │ │ └── witness_calculator.ts │ └── verifiers │ │ ├── index.ts │ │ ├── pub-signals-verifier.ts │ │ ├── query-hash.ts │ │ └── query.ts ├── schema-processor │ ├── index.ts │ ├── json │ │ ├── index.ts │ │ ├── parser.ts │ │ └── validator.ts │ ├── jsonld │ │ ├── cache.ts │ │ ├── index.ts │ │ └── parser.ts │ └── utils.ts ├── storage │ ├── blockchain │ │ ├── abi │ │ │ ├── CredentialStatusResolver.json │ │ │ ├── ERC20.json │ │ │ ├── ERC20Permit.json │ │ │ ├── IdentityBase.json │ │ │ ├── State.json │ │ │ └── ZkpVerifier.json │ │ ├── common.ts │ │ ├── did-resolver-readonly-storage.ts │ │ ├── erc20-helper.ts │ │ ├── index.ts │ │ ├── onchain-issuer-adapter │ │ │ └── non-merklized │ │ │ │ └── version │ │ │ │ └── v0.0.1 │ │ │ │ └── onchain-non-merklized-issuer-adapter.ts │ │ ├── onchain-issuer.ts │ │ ├── onchain-revocation.ts │ │ ├── onchain-zkp-verifier.ts │ │ └── state.ts │ ├── entities │ │ ├── circuitData.ts │ │ ├── identity.ts │ │ ├── index.ts │ │ ├── mt.ts │ │ └── state.ts │ ├── errors.ts │ ├── filters │ │ ├── index.ts │ │ └── jsonQuery.ts │ ├── fs │ │ ├── circuits-storage.ts │ │ └── index.ts │ ├── index.ts │ ├── indexed-db │ │ ├── data-source.ts │ │ ├── index.ts │ │ └── merkletree.ts │ ├── interfaces │ │ ├── circuits.ts │ │ ├── credentials.ts │ │ ├── data-source.ts │ │ ├── data-storage.ts │ │ ├── identity.ts │ │ ├── index.ts │ │ ├── merkletree.ts │ │ ├── onchain-issuer.ts │ │ ├── onchain-revocation.ts │ │ ├── onchain-zkp-verifier.ts │ │ └── state.ts │ ├── local-storage │ │ ├── data-source.ts │ │ ├── index.ts │ │ └── merkletree.ts │ ├── memory │ │ ├── data-source.ts │ │ ├── index.ts │ │ └── merkletree.ts │ ├── shared │ │ ├── circuit-storage.ts │ │ ├── credential-storage.ts │ │ ├── identity-storage.ts │ │ └── index.ts │ └── utils.ts ├── utils │ ├── compare-func.ts │ ├── did-helper.ts │ ├── encoding.ts │ ├── index.ts │ ├── message-bus.ts │ └── object.ts └── verifiable │ ├── constants.ts │ ├── core-utils.ts │ ├── credential.ts │ ├── index.ts │ ├── presentation.ts │ ├── proof.ts │ └── schema.ts ├── tests ├── adapter │ ├── onchain-issuer.test.ts │ └── onchain-non-merklized-issuer-adapter.test.ts ├── circuits │ ├── atomic-query-mtp-v2-on-chain.test.ts │ ├── atomic-query-mtp-v2.test.ts │ ├── atomic-query-sig-v2-on-chain.test.ts │ ├── atomic-query-sig-v2.test.ts │ ├── atomic-query-v3-on-chain.test.ts │ ├── atomic-query-v3.test.ts │ ├── auth-v2.test.ts │ ├── data │ │ ├── atomic-query-v3-mtp-on-chain.json │ │ ├── atomic-query-v3-mtp.json │ │ ├── atomic-query-v3-sig-on-chain.json │ │ ├── atomic-query-v3-sig.json │ │ ├── auth-v2-inputs.json │ │ ├── linked-multi-query-inputs.json │ │ ├── mtp-v2-inputs.json │ │ ├── mtp-v2-on-chain-inputs.json │ │ ├── sig-v2-inputs.json │ │ └── sig-v2-on-chain-inputs.json │ ├── linked-multi-query.test.ts │ ├── state-transition.test.ts │ └── utils.ts ├── credentials │ ├── credential-statuses │ │ ├── did-resolver-revocation.test.ts │ │ ├── on-chain-revocation.test.ts │ │ ├── rhs.test.ts │ │ └── sparse-merkle-tree-proof.test.ts │ ├── credential-validation.test.ts │ ├── credential-wallet.test.ts │ └── mock.ts ├── handlers │ ├── auth.test.ts │ ├── contract-request.test.ts │ ├── credential-proposal.test.ts │ ├── discover-protocol.test.ts │ ├── fetch.test.ts │ ├── mock.ts │ ├── payment.test.ts │ ├── problem-report.test.ts │ ├── readonly-storage.test.ts │ ├── refresh.test.ts │ └── revocation-status.test.ts ├── helpers.ts ├── iden3comm │ ├── accept-profile.test.ts │ ├── jws.test.ts │ ├── message-handler.test.ts │ ├── mock │ │ └── proving.ts │ ├── packageManager.test.ts │ └── zkp.test.ts ├── identity │ └── id.test.ts ├── kms │ └── kms.test.ts ├── mocks │ └── schema.ts ├── proofs │ ├── common.test.ts │ ├── mtp-onchain.test.ts │ ├── mtp.test.ts │ ├── sig-onchain.test.ts │ └── sig.test.ts ├── schema-processor │ ├── data │ │ ├── credential-merklized.json │ │ ├── json-validator-data.ts │ │ ├── jsonld │ │ │ ├── credentials-v1.json │ │ │ ├── non-merklized-1.json │ │ │ └── schema-delivery-address.json │ │ ├── kyc.json │ │ ├── list-of-ld-contexts.json │ │ ├── list-with-single-ld-context.json │ │ ├── single-ld-context-2.json │ │ └── single-ld-context.json │ ├── json-ld.test.ts │ ├── json-validator.test.ts │ └── parser.test.ts └── utils │ └── utils.test.ts ├── tsconfig.json ├── tsconfig.test.json └── types ├── ffjavascript.d.ts ├── jsonld └── index.d.ts └── snarkjs.d.ts /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const iden3Config = require('@iden3/eslint-config'); 2 | const { spellcheckerRule, cspellConfig } = require('@iden3/eslint-config/cspell'); 3 | 4 | module.exports = { 5 | ...iden3Config, 6 | rules: { 7 | '@cspell/spellchecker': [ 8 | 1, 9 | { 10 | ...spellcheckerRule, 11 | cspell: { 12 | ...cspellConfig, 13 | ignoreWords: ['unmarshal', 'JUvpllMEYUZ2joO59UNui_XYDqxVqiFLLAJ8klWuPBw', 'gdwj', 'fwor', 'multichain', "ETHWEI", "ETHGWEI", "didcomm", "pthid"] 14 | } 15 | } 16 | ] 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: Kolezhniuk, vmidyllic 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Install SDK 16 | 2. call function with param 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Screenshots** 22 | If applicable, add screenshots to help explain your problem. 23 | 24 | ** Environment info (please complete the following information):** 25 | - OS version [e.g. Mac OS] 26 | - Node version: [e.g. 18.16] 27 | - Browser [e.g. chrome, safari] 28 | - Package version [e.g. 1.0.0] 29 | - Build [e.g. umd, cjs] 30 | 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | allow: 8 | - dependency-name: "@iden3*" 9 | reviewers: 10 | - "Kolezhniuk" 11 | - "vmidyllic" 12 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: Build, Lint and Test 2 | on: push 3 | jobs: 4 | build: 5 | timeout-minutes: 15 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout 9 | uses: actions/checkout@v4 10 | 11 | - name: Setup Node.js 12 | uses: actions/setup-node@v4 13 | with: 14 | node-version: 'lts/*' 15 | 16 | - name: Cache node modules 17 | uses: actions/cache@v4 18 | with: 19 | # npm cache files are stored in `~/.npm` on Linux/macOS 20 | path: ~/.npm 21 | key: cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} 22 | 23 | - name: Install dependencies 24 | run: npm ci 25 | 26 | - name: Run Prettier 27 | run: npm run format:check 28 | 29 | - name: Run ESLint 30 | run: npm run lint:check 31 | 32 | - name: Build 33 | run: npm run build 34 | 35 | - name: Download regular circuits for CI 'latest.zip' from S3 36 | run: mkdir ./tests/proofs/testdata && wget https://circuits.privado.id/latest.zip -P ./tests/proofs/testdata 37 | 38 | - name: Unzip circuits to folder 39 | run: cd ./tests/proofs/testdata && unzip latest.zip && cd - && pwd 40 | 41 | - name: Run Tests 42 | env: 43 | IPFS_URL: ${{ secrets.IPFS_URL }} 44 | WALLET_KEY: ${{ secrets.WALLET_KEY }} 45 | RPC_URL: ${{ secrets.RPC_URL }} 46 | RHS_URL: ${{ secrets.RHS_URL }} 47 | STATE_CONTRACT_ADDRESS: ${{ secrets.STATE_CONTRACT_ADDRESS }} 48 | RHS_CONTRACT_ADDRESS: ${{ secrets.RHS_CONTRACT_ADDRESS }} 49 | run: npm run test 50 | -------------------------------------------------------------------------------- /.github/workflows/issues.yaml: -------------------------------------------------------------------------------- 1 | name: Close inactive issues 2 | on: 3 | schedule: 4 | - cron: "30 1 * * *" 5 | 6 | jobs: 7 | close-issues: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | issues: write 11 | pull-requests: write 12 | steps: 13 | - uses: actions/stale@v5 14 | with: 15 | days-before-issue-stale: 14 16 | days-before-issue-close: 21 17 | stale-issue-label: "stale" 18 | exempt-issue-labels: "enhancement" 19 | stale-issue-message: "This issue is stale because it has been open for 14 days with no activity." 20 | close-issue-message: "This issue was closed because it has been inactive for 7 days since being marked as stale." 21 | days-before-pr-stale: -1 22 | days-before-pr-close: -1 23 | repo-token: ${{ secrets.GITHUB_TOKEN }} 24 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish package to NPM 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | publish-npm: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v4 13 | with: 14 | node-version-file: '.nvmrc' 15 | registry-url: https://registry.npmjs.org/ 16 | cache: 'npm' 17 | - run: npm ci 18 | - run: npm run build 19 | - run: npm publish 20 | env: 21 | NODE_AUTH_TOKEN: ${{secrets.POLYGONID_NPM_PUBLISH_TOKEN}} 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | coverage 3 | dist 4 | docs 5 | temp 6 | .DS_Store 7 | .idea 8 | .vscode 9 | /tests/proofs/testdata 10 | .env 11 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extension": [ 3 | "ts" 4 | ], 5 | "spec": "tests/**/*.test.ts", 6 | "require": "ts-node/register", 7 | "timeout": "400000", 8 | "maxDiffSize": "10000" 9 | } 10 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20.11.1 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | "@iden3/eslint-config/prettier" -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2024 ZKID Labs AG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Privado ID JS SDK 2 | 3 | SDK to work with Privado ID using JavaScript and TypeScript languages. 4 | 5 | ## Usage 6 | 7 | Installation: 8 | 9 | ```bash 10 | npm install @0xpolygonid/js-sdk 11 | ``` 12 | 13 | ## Circuits 14 | 15 | And place actual circuits to `test/proofs/testdata` 16 | 17 | ```bash 18 | curl -LO https://circuits.privado.id/latest.zip 19 | ``` 20 | 21 | ## Tests 22 | 23 | Run unit tests: 24 | 25 | ```bash 26 | npm run test 27 | ``` 28 | 29 | Note: mtp / sig / auth / rhs files contain integration tests! 30 | 31 | To run them, please set following variables: 32 | 33 | ```bash 34 | export WALLET_KEY="...key in hex format" 35 | export RPC_URL="...url to network rpc node" 36 | export RHS_URL="..reverse hash service url" 37 | export IPFS_URL="url for ipfs" 38 | export STATE_CONTRACT_ADDRESS="state contract address" 39 | export RHS_CONTRACT_ADDRESS="reverse hash service contract address" 40 | ``` 41 | 42 | ## Examples 43 | 44 | Please see [examples](https://github.com/0xPolygonID/js-sdk-examples) for visit examples information. 45 | 46 | ## Documentation 47 | 48 | ### Generate documentation 49 | 50 | 1. Define path where documentation repository is located, for example: 51 | 52 | ```typescript 53 | const DOCS_DIR = '../js-sdk-tutorials/docs/api'; 54 | ``` 55 | 56 | 2. ```bash 57 | npm run tsc:declaration:watch 58 | ``` 59 | 60 | 3. ```bash 61 | npm run doc:watch:website 62 | ``` 63 | 64 | Documentation can be found [here](https://0xpolygonid.github.io/js-sdk-tutorials/) 65 | 66 | ## License 67 | 68 | js-sdk is part of the 0xPolygonID project copyright 2024 ZKID Labs AG 69 | 70 | This project is licensed under either of 71 | 72 | - [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) ([`LICENSE-APACHE`](LICENSE-APACHE)) 73 | - [MIT license](https://opensource.org/licenses/MIT) ([`LICENSE-MIT`](LICENSE-MIT)) 74 | 75 | at your option. 76 | -------------------------------------------------------------------------------- /config/api-extractor.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", 3 | "apiReport": { 4 | "enabled": true, 5 | "reportFolder": "../temp", 6 | "reportTempFolder": "../temp" 7 | }, 8 | 9 | "docModel": { 10 | "enabled": true, 11 | "apiJsonFilePath": "../temp/.api.json" 12 | }, 13 | 14 | "dtsRollup": { 15 | "enabled": false 16 | }, 17 | "tsdocMetadata": { 18 | "enabled": false 19 | }, 20 | "mainEntryPointFilePath": "/dist/types/index.d.ts" 21 | } 22 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import commonJS from '@rollup/plugin-commonjs'; 2 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 3 | import typescript from '@rollup/plugin-typescript'; 4 | import packageJson from './package.json' with { type: 'json' }; 5 | import tsConfig from './tsconfig.json' with { type: 'json' }; 6 | import virtual from '@rollup/plugin-virtual'; 7 | import json from '@rollup/plugin-json'; 8 | const empty = 'export default {}'; 9 | 10 | const config = { 11 | input: 'src/index.ts', 12 | external: [ 13 | ...Object.keys(packageJson.peerDependencies).filter((key) => key.startsWith('@iden3/')), 14 | 'snarkjs', 15 | 'ffjavascript' 16 | ], 17 | output: { 18 | format: 'es', 19 | file: packageJson.exports['.'].browser, 20 | sourcemap: true 21 | }, 22 | context: 'window', 23 | plugins: [ 24 | typescript({ 25 | compilerOptions: tsConfig.compilerOptions 26 | }), 27 | commonJS(), 28 | nodeResolve({ 29 | browser: true 30 | }), 31 | json(), 32 | virtual({ 33 | fs: empty 34 | }) 35 | ], 36 | treeshake: { 37 | preset: 'smallest' 38 | } 39 | }; 40 | 41 | export default [ 42 | config, 43 | { 44 | ...config, 45 | external: [], 46 | output: { 47 | ...config.output, 48 | format: 'iife', 49 | file: packageJson.exports['.'].umd, 50 | name: 'PolygonIdSdk' 51 | } 52 | } 53 | ]; 54 | -------------------------------------------------------------------------------- /scripts/doc-documenter.ts: -------------------------------------------------------------------------------- 1 | import { readdir, createReadStream, writeFile } from 'fs-extra' 2 | import { createInterface } from 'readline' 3 | import { join, parse } from 'path' 4 | import { exec } from 'child_process' 5 | import * as fs from 'fs' 6 | 7 | const DOCS_DIR = './docs/api' 8 | 9 | async function main() { 10 | const outputFolder = './temp'; 11 | await fs.promises.mkdir(outputFolder, { recursive: true }) 12 | await fs.promises.mkdir(DOCS_DIR, { recursive: true }) 13 | 14 | await new Promise((resolve, reject) => 15 | exec(`api-documenter markdown -i ./temp -o ${DOCS_DIR}`, (err, stdout, stderr) => { 16 | console.log(stdout) 17 | console.error(stderr) 18 | if (err) { 19 | reject(err) 20 | } else { 21 | resolve('') 22 | } 23 | }), 24 | ) 25 | 26 | const docFiles = await readdir(DOCS_DIR) 27 | for (const docFile of docFiles) { 28 | try { 29 | const { name: id, ext } = parse(docFile) 30 | if (ext !== '.md') { 31 | continue 32 | } 33 | 34 | const docPath = join(DOCS_DIR, docFile) 35 | const input = createReadStream(docPath) 36 | const output: string[] = [] 37 | const lines = createInterface({ 38 | input, 39 | crlfDelay: Infinity, 40 | }) 41 | 42 | let title = '' 43 | lines.on('line', (line) => { 44 | let skip = false 45 | if (!title) { 46 | const titleLine = line.match(/## (.*)/) 47 | if (titleLine) { 48 | title = titleLine[1] 49 | } 50 | } 51 | const indexHomeLink = line.match(/\[Home]\(.\/index\.md\)/) 52 | const homeLink = line.match(/\[Home]\(.\/index\.md\) > (.*)/) 53 | if (homeLink) { 54 | line = line.replace('Home', 'Packages') 55 | } 56 | 57 | if (indexHomeLink) { 58 | // Skip the breadcrumb for the toplevel index file. 59 | if (id === 'index') { 60 | skip = true 61 | } 62 | 63 | skip = true 64 | } 65 | 66 | // See issue #4. api-documenter expects \| to escape table 67 | // column delimiters, but docusaurus uses a markdown processor 68 | // that doesn't support this. Replace with an escape sequence 69 | // that renders |. 70 | if (line.startsWith('|')) { 71 | line = line.replace(/\\\|/g, '|') 72 | } 73 | 74 | // MDX cries when you put commects in there :( 75 | line = replaceAll(line, '', '') 76 | 77 | if (id === 'core') { 78 | line = line.replace('core package', 'Veramo Core') 79 | } 80 | 81 | if (!skip) { 82 | output.push(line) 83 | } 84 | }) 85 | 86 | await new Promise((resolve) => lines.once('close', resolve)) 87 | input.close() 88 | 89 | const header = ['---', `id: ${id}`, `title: ${title}`, `hide_title: true`, '---'] 90 | let outputString = header.concat(output).join('\n') 91 | 92 | outputString = outputString.replace(/}` 22 | */ 23 | async resolve( 24 | credentialStatus: CredentialStatus, 25 | credentialStatusResolveOptions?: CredentialStatusResolveOptions 26 | ): Promise { 27 | if (!credentialStatusResolveOptions?.issuerDID) { 28 | throw new Error('IssuerDID is not set in options'); 29 | } 30 | if (!credentialStatusResolveOptions?.userDID) { 31 | throw new Error('UserDID is not set in options'); 32 | } 33 | 34 | if (typeof credentialStatus.revocationNonce !== 'number') { 35 | throw new Error('Revocation nonce is not set in credential status'); 36 | } 37 | 38 | const from = credentialStatusResolveOptions.userDID.string(); 39 | const to = credentialStatusResolveOptions.issuerDID.string(); 40 | const msg = buildRevocationMessageRequest(from, to, credentialStatus.revocationNonce); 41 | const response = await fetch(credentialStatus.id, { 42 | method: 'POST', 43 | body: JSON.stringify(msg), 44 | headers: { 45 | 'Content-Type': 'application/json' 46 | } 47 | }); 48 | const agentResponse = await response.json(); 49 | return toRevocationStatus(agentResponse.body); 50 | } 51 | } 52 | 53 | function buildRevocationMessageRequest( 54 | from: string, 55 | to: string, 56 | revocationNonce: number 57 | ): RevocationStatusRequestMessage { 58 | return { 59 | id: uuid.v4(), 60 | typ: MediaType.PlainMessage, 61 | type: PROTOCOL_MESSAGE_TYPE.REVOCATION_STATUS_REQUEST_MESSAGE_TYPE, 62 | body: { 63 | revocation_nonce: revocationNonce 64 | }, 65 | thid: uuid.v4(), 66 | from: from, 67 | to: to 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /src/credentials/status/did-resolver-revocation.ts: -------------------------------------------------------------------------------- 1 | import { CredentialStatus, RevocationStatus } from '../../verifiable'; 2 | import { CredentialStatusResolveOptions, CredentialStatusResolver } from './resolver'; 3 | 4 | export class DidDocumentCredentialStatusResolver implements CredentialStatusResolver { 5 | constructor(private readonly didResolverUrl: string) {} 6 | async resolve( 7 | credentialStatus: CredentialStatus, 8 | opts?: CredentialStatusResolveOptions | undefined 9 | ): Promise { 10 | if (!opts?.issuerDID) { 11 | throw new Error('IssuerDID is not set in options'); 12 | } 13 | 14 | const url = `${this.didResolverUrl}/1.0/credential-status/${encodeURIComponent( 15 | opts.issuerDID.string() 16 | )}`; 17 | const resp = await fetch(url, { 18 | method: 'POST', 19 | body: JSON.stringify(credentialStatus) 20 | }); 21 | const data = await resp.json(); 22 | return data; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/credentials/status/resolver.ts: -------------------------------------------------------------------------------- 1 | import { DID } from '@iden3/js-iden3-core'; 2 | import { State, RevocationStatus, CredentialStatus, CredentialStatusType } from '../../verifiable'; 3 | 4 | /** 5 | * CredentialStatusResolveOptions is a set of options that can be passed to CredentialStatusResolver 6 | * 7 | * @public 8 | * @interface CredentialStatusResolveOptions 9 | */ 10 | export interface CredentialStatusResolveOptions { 11 | /** 12 | @deprecated it was used only for state in case issuer has a issuerGenesisState state 13 | */ 14 | issuerData?: { 15 | state: { 16 | rootOfRoots: string; 17 | claimsTreeRoot: string; 18 | revocationTreeRoot: string; 19 | value: string; 20 | }; 21 | }; 22 | 23 | issuerGenesisState?: State; 24 | issuerDID?: DID; 25 | userDID?: DID; 26 | } 27 | 28 | /** 29 | * CredentialStatusResolver is an interface that allows to interact with different types of credential status 30 | * to resolve revocation status 31 | * 32 | * @public 33 | * @interface CredentialStatusResolver 34 | */ 35 | export interface CredentialStatusResolver { 36 | /** 37 | * resolve is a method to resolve a credential status from the the specific source. 38 | * 39 | * @public 40 | * @param {CredentialStatus} credentialStatus - credential status to resolve 41 | * @param {CredentialStatusResolveOptions} credentialStatusResolveOptions - options for resolver 42 | * @returns `{Promise}` 43 | */ 44 | resolve( 45 | credentialStatus: CredentialStatus, 46 | opts?: CredentialStatusResolveOptions 47 | ): Promise; 48 | } 49 | 50 | /** 51 | * CredentialStatusResolverRegistry is a registry of CredentialStatusResolver 52 | * 53 | * @public 54 | * @interface CredentialStatusResolverRegistry 55 | */ 56 | export class CredentialStatusResolverRegistry { 57 | private resolvers: Map = new Map(); 58 | 59 | /** 60 | * register is a method to add a credential status resolver for specific credential status type 61 | * 62 | * @public 63 | * @param {CredentialStatusType} type - one of the credential status types 64 | * @param {CredentialStatusResolver} resolver - resolver 65 | */ 66 | register(type: CredentialStatusType, resolver: CredentialStatusResolver) { 67 | this.resolvers.set(type, resolver); 68 | } 69 | 70 | /** 71 | * resolve is a method to resolve a credential status from the the specific source. 72 | * 73 | * @public 74 | * @param {CredentialStatus} credentialStatus - credential status to resolve 75 | * @param {CredentialStatusResolveOptions} credentialStatusResolveOptions - options for resolver 76 | * @returns `{Promise}` 77 | */ 78 | get(type: CredentialStatusType): CredentialStatusResolver | undefined { 79 | return this.resolvers.get(type); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/credentials/status/sparse-merkle-tree.ts: -------------------------------------------------------------------------------- 1 | import { CredentialStatus, RevocationStatus, Issuer } from '../../verifiable'; 2 | import { CredentialStatusResolver } from './resolver'; 3 | import { Proof, ProofJSON } from '@iden3/js-merkletree'; 4 | 5 | /** 6 | * IssuerResolver is a class that allows to interact with the issuer's http endpoint to get revocation status. 7 | * 8 | * @public 9 | * @class IssuerResolver 10 | */ 11 | 12 | export class IssuerResolver implements CredentialStatusResolver { 13 | /** 14 | * resolve is a method to resolve a credential status directly from the issuer. 15 | * 16 | * @public 17 | * @param {CredentialStatus} credentialStatus - credential status to resolve 18 | * @param {CredentialStatusResolveOptions} credentialStatusResolveOptions - options for resolver 19 | * @returns `{Promise}` 20 | */ 21 | async resolve(credentialStatus: CredentialStatus): Promise { 22 | const revStatusResp = await fetch(credentialStatus.id); 23 | const revStatus = await revStatusResp.json(); 24 | return toRevocationStatus(revStatus); 25 | } 26 | } 27 | 28 | /** 29 | * RevocationStatusResponse is a response of fetching credential status with type SparseMerkleTreeProof 30 | * 31 | * @export 32 | * @interface RevocationStatusResponse 33 | */ 34 | export interface RevocationStatusResponse { 35 | issuer: Issuer; 36 | mtp: ProofJSON; 37 | } 38 | 39 | /** 40 | * toRevocationStatus is a result of fetching credential status with type SparseMerkleTreeProof converts to RevocationStatus 41 | * 42 | * @param {RevocationStatusResponse} { issuer, mtp } 43 | * @returns {RevocationStatus} RevocationStatus 44 | */ 45 | export const toRevocationStatus = ({ issuer, mtp }: RevocationStatusResponse): RevocationStatus => { 46 | return { 47 | mtp: Proof.fromJSON(mtp), 48 | issuer 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /src/credentials/utils.ts: -------------------------------------------------------------------------------- 1 | import { DID } from '@iden3/js-iden3-core'; 2 | import { W3CCredential } from '../verifiable'; 3 | import { PublicKey } from '@iden3/js-crypto'; 4 | import { KmsKeyId, KmsKeyType, keyPath } from '../kms'; 5 | 6 | /** 7 | * Retrieves the user DID from a given credential. 8 | * If the credential does not have a credentialSubject.id property, the issuer DID is returned. 9 | * If the credentialSubject.id is not a string, an error is thrown. 10 | * @param issuerDID The DID of the issuer. 11 | * @param credential The credential object. 12 | * @returns The user DID parsed from the credential. 13 | * @throws Error if the credentialSubject.id is not a string. 14 | */ 15 | export const getUserDIDFromCredential = (issuerDID: DID, credential: W3CCredential) => { 16 | if (!credential.credentialSubject.id) { 17 | return issuerDID; 18 | } 19 | 20 | if (typeof credential.credentialSubject.id !== 'string') { 21 | throw new Error('credential subject `id` is not a string'); 22 | } 23 | return DID.parse(credential.credentialSubject.id); 24 | }; 25 | 26 | export const getKMSIdByAuthCredential = (credential: W3CCredential): KmsKeyId => { 27 | if (!credential.type.includes('AuthBJJCredential')) { 28 | throw new Error("can't sign with not AuthBJJCredential credential"); 29 | } 30 | const x = credential.credentialSubject['x'] as string; 31 | const y = credential.credentialSubject['y'] as string; 32 | 33 | const pb: PublicKey = new PublicKey([BigInt(x), BigInt(y)]); 34 | const kp = keyPath(KmsKeyType.BabyJubJub, pb.hex()); 35 | return { type: KmsKeyType.BabyJubJub, id: kp }; 36 | }; 37 | -------------------------------------------------------------------------------- /src/iden3comm/errors.ts: -------------------------------------------------------------------------------- 1 | // Envelope Errors 2 | export const ErrNotProtocolMessage = 'the envelope is not a protocol message'; 3 | export const ErrNotEnvelopeStub = "the envelope doesn't contain field protected"; 4 | export const ErrNotHeaderStub = "the envelope doesn't contain field typ"; 5 | 6 | // Token Errors 7 | export const ErrUnknownCircuitID = "unknown circuit ID. can't verify msg sender"; 8 | export const ErrSenderNotUsedTokenCreation = 'sender of message is not used for jwz token creation'; 9 | 10 | // ZKP-Packer Errors 11 | export const ErrPackedWithUnsupportedCircuit = 'message was packed with unsupported circuit'; 12 | export const ErrProofIsInvalid = 'message proof is invalid'; 13 | export const ErrStateVerificationFailed = 'message state verification failed'; 14 | export const ErrNoProvingMethodAlg = 'unknown proving method algorithm'; 15 | -------------------------------------------------------------------------------- /src/iden3comm/handlers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth'; 2 | export * from './fetch'; 3 | export * from './contract-request'; 4 | export * from './refresh'; 5 | export * from './revocation-status'; 6 | export * from './common'; 7 | export * from './credential-proposal'; 8 | export * from './message-handler'; 9 | export * from './payment'; 10 | export * from './discovery-protocol'; 11 | export * from './problem-report'; 12 | -------------------------------------------------------------------------------- /src/iden3comm/handlers/problem-report.ts: -------------------------------------------------------------------------------- 1 | import * as uuid from 'uuid'; 2 | import { ProblemReportMessage } from '../types/protocol/problem-report'; 3 | import { MediaType, PROTOCOL_MESSAGE_TYPE } from '../constants'; 4 | 5 | /** 6 | * @beta 7 | * createProblemReportMessage is a function to create didcomm protocol problem report message 8 | * @param pthid - parent thread id 9 | * @param code - problem report code 10 | * @param opts - problem report options 11 | * @returns `ProblemReportMessage` 12 | */ 13 | export function createProblemReportMessage( 14 | pthid: string, 15 | code: string, 16 | opts?: { 17 | comment?: string; 18 | ack?: string[]; 19 | args?: string[]; 20 | escalate_to?: string; 21 | from?: string; 22 | to?: string; 23 | } 24 | ): ProblemReportMessage { 25 | const uuidv4 = uuid.v4(); 26 | return { 27 | id: uuidv4, 28 | pthid: pthid, 29 | typ: MediaType.PlainMessage, 30 | type: PROTOCOL_MESSAGE_TYPE.PROBLEM_REPORT_MESSAGE_TYPE, 31 | ack: opts?.ack, 32 | body: { 33 | code: code, 34 | comment: opts?.comment, 35 | args: opts?.args, 36 | escalate_to: opts?.escalate_to 37 | }, 38 | from: opts?.from, 39 | to: opts?.to 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /src/iden3comm/index.ts: -------------------------------------------------------------------------------- 1 | export * from './packageManager'; 2 | export * from './packers'; 3 | export * from './types'; 4 | export * from './handlers'; 5 | export * from './utils/did'; 6 | export * from './utils/accept-profile'; 7 | 8 | import * as PROTOCOL_CONSTANTS from './constants'; 9 | export { PROTOCOL_CONSTANTS }; 10 | -------------------------------------------------------------------------------- /src/iden3comm/packers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './zkp'; 2 | export * from './plain'; 3 | export * from './jws'; 4 | -------------------------------------------------------------------------------- /src/iden3comm/packers/plain.ts: -------------------------------------------------------------------------------- 1 | import { BasicMessage, IPacker } from '../types'; 2 | import { MediaType, ProtocolVersion } from '../constants'; 3 | import { byteDecoder, byteEncoder } from '../../utils'; 4 | import { parseAcceptProfile } from '../utils'; 5 | 6 | /** 7 | * Plain packer just serializes bytes to JSON and adds media type 8 | * 9 | * @public 10 | * @class PlainPacker 11 | * @implements implements IPacker interface 12 | */ 13 | export class PlainPacker implements IPacker { 14 | private readonly supportedProtocolVersions = [ProtocolVersion.V1]; 15 | 16 | /** 17 | * Packs a basic message using the specified parameters. 18 | * 19 | * @param msg - The basic message to pack. 20 | * @param param - The packer parameters. 21 | * @returns A promise that resolves to a Uint8Array representing the packed message. 22 | * @throws An error if the method is not implemented. 23 | */ 24 | packMessage(msg: BasicMessage): Promise { 25 | msg.typ = MediaType.PlainMessage; 26 | return Promise.resolve(byteEncoder.encode(JSON.stringify(msg))); 27 | } 28 | /** 29 | * Pack returns packed message to transport envelope 30 | * 31 | * @param {Uint8Array} payload - json message serialized 32 | * @param {PlainPackerParams} _params - not used here 33 | * @returns `Promise` 34 | */ 35 | async pack(payload: Uint8Array): Promise { 36 | const msg = JSON.parse(byteDecoder.decode(payload)); 37 | msg.typ = MediaType.PlainMessage; 38 | return Promise.resolve(byteEncoder.encode(JSON.stringify(msg))); 39 | } 40 | 41 | /** 42 | * Unpack returns unpacked message from transport envelope 43 | * 44 | * @param {Uint8Array} envelope - packed envelope (serialized json with media type) 45 | * @returns `Promise` 46 | */ 47 | async unpack(envelope: Uint8Array): Promise { 48 | return JSON.parse(byteDecoder.decode(envelope)); 49 | } 50 | 51 | /** 52 | * returns media type for plain message 53 | * 54 | * @returns MediaType 55 | */ 56 | mediaType(): MediaType { 57 | return MediaType.PlainMessage; 58 | } 59 | 60 | /** {@inheritDoc IPacker.getSupportedProfiles} */ 61 | getSupportedProfiles(): string[] { 62 | return this.supportedProtocolVersions.map((v) => `${v};env=${this.mediaType()}`); 63 | } 64 | 65 | /** {@inheritDoc IPacker.isProfileSupported} */ 66 | isProfileSupported(profile: string) { 67 | const { protocolVersion, env, circuits, alg } = parseAcceptProfile(profile); 68 | 69 | if (!this.supportedProtocolVersions.includes(protocolVersion)) { 70 | return false; 71 | } 72 | if (env !== this.mediaType()) { 73 | return false; 74 | } 75 | 76 | if (circuits) { 77 | throw new Error(`Circuits are not supported for ${env} media type`); 78 | } 79 | 80 | if (alg) { 81 | throw new Error(`Algorithms are not supported for ${env} media type`); 82 | } 83 | 84 | return true; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/iden3comm/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './protocol/auth'; 2 | export * from './protocol/credentials'; 3 | export * from './protocol/messages'; 4 | export * from './protocol/proof'; 5 | export * from './protocol/revocation'; 6 | export * from './protocol/contract-request'; 7 | export * from './protocol/proposal-request'; 8 | export * from './protocol/payment'; 9 | export * from './protocol/accept-profile'; 10 | export * from './protocol/discovery-protocol'; 11 | export * from './protocol/problem-report'; 12 | 13 | export * from './packer'; 14 | export * from './models'; 15 | export * from './packageManager'; 16 | -------------------------------------------------------------------------------- /src/iden3comm/types/models.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * State verification options 3 | */ 4 | export type StateVerificationOpts = { 5 | // acceptedStateTransitionDelay is the period of time in milliseconds that a revoked state remains valid. 6 | acceptedStateTransitionDelay?: number; 7 | }; 8 | -------------------------------------------------------------------------------- /src/iden3comm/types/packageManager.ts: -------------------------------------------------------------------------------- 1 | import { BasicMessage, IPacker, PackerParams } from './packer'; 2 | import { MediaType } from '../constants'; 3 | 4 | /** 5 | * Interface for defining the registry of packers 6 | * 7 | * @public 8 | * @interface IPackageManager 9 | */ 10 | export interface IPackageManager { 11 | /** 12 | * Map of packers key is media type, value is packer implementation 13 | * 14 | * @type {Map} 15 | */ 16 | packers: Map; 17 | 18 | /** 19 | * registers new packer in the manager 20 | * 21 | * @param {Array} packers 22 | */ 23 | registerPackers(packers: Array): void; 24 | 25 | /** 26 | * packs payload with a packer that is assigned to media type 27 | * forwards packer params to implementation 28 | * 29 | * @param {MediaType} mediaType 30 | * @param {Uint8Array} payload 31 | * @param {PackerParams} params 32 | * @returns `Promise` 33 | */ 34 | pack(mediaType: MediaType, payload: Uint8Array, params: PackerParams): Promise; 35 | 36 | /** 37 | * packs payload with a packer that is assigned to media type 38 | * forwards packer params to implementation 39 | * 40 | * @param {MediaType} mediaType 41 | * @param {BasicMessage} protocolMessage 42 | * @param {PackerParams} params 43 | * @returns `Promise` 44 | */ 45 | packMessage( 46 | mediaType: MediaType, 47 | protocolMessage: BasicMessage, 48 | params: PackerParams 49 | ): Promise; 50 | 51 | /** 52 | * unpacks packed envelope to basic protocol message and returns media type of the envelope 53 | * 54 | * @param {Uint8Array} envelope - bytes envelope 55 | * @returns `Promise<{ unpackedMessage: BasicMessage; unpackedMediaType: MediaType }` 56 | */ 57 | unpack( 58 | envelope: Uint8Array 59 | ): Promise<{ unpackedMessage: BasicMessage; unpackedMediaType: MediaType }>; 60 | 61 | /** 62 | * unpacks an envelope with a known media type 63 | * 64 | * @param {MediaType} mediaType 65 | * @param {Uint8Array} envelope 66 | * @returns `Promise` 67 | */ 68 | unpackWithType(mediaType: MediaType, envelope: Uint8Array): Promise; 69 | 70 | /** 71 | * gets media type from an envelope 72 | * 73 | * @param {string} envelope 74 | * @returns MediaType 75 | */ 76 | getMediaType(envelope: string): MediaType; 77 | 78 | /** 79 | * gets supported media types by packer manager 80 | * 81 | * @returns MediaType[] 82 | */ 83 | getSupportedMediaTypes(): MediaType[]; 84 | 85 | /** 86 | * gets supported accept profiles by packer manager 87 | * 88 | * @returns string[] 89 | */ 90 | getSupportedProfiles(): string[]; 91 | 92 | /** 93 | * returns true if media type and algorithms supported by packer manager 94 | * 95 | * @param {MediaType} mediaType 96 | * @param {string} profile 97 | * @returns {boolean} 98 | */ 99 | isProfileSupported(mediaType: MediaType, profile: string): boolean; 100 | } 101 | /** 102 | * EnvelopeStub is used to stub the jwt based envelops 103 | */ 104 | export type EnvelopeStub = { 105 | protected: string; 106 | }; 107 | /** 108 | * HeaderStub is used to stub the jwt based envelops 109 | */ 110 | export type HeaderStub = { 111 | typ: MediaType; 112 | }; 113 | -------------------------------------------------------------------------------- /src/iden3comm/types/protocol/accept-profile.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AcceptAuthCircuits, 3 | AcceptJwsAlgorithms, 4 | AcceptJwzAlgorithms, 5 | MediaType, 6 | ProtocolVersion 7 | } from '../../constants'; 8 | 9 | export type AcceptProfile = { 10 | protocolVersion: ProtocolVersion; 11 | env: MediaType; 12 | circuits?: AcceptAuthCircuits[]; 13 | alg?: AcceptJwsAlgorithms[] | AcceptJwzAlgorithms[]; 14 | }; 15 | -------------------------------------------------------------------------------- /src/iden3comm/types/protocol/auth.ts: -------------------------------------------------------------------------------- 1 | import { ZKProof } from '@iden3/js-jwz'; 2 | import { BasicMessage, JsonDocumentObject } from '../packer'; 3 | import { PROTOCOL_MESSAGE_TYPE } from '../../constants'; 4 | import { ProofType } from '../../../verifiable'; 5 | import { CircuitId } from '../../../circuits'; 6 | import { 7 | DIDDocument as DidResolverDidDocument, 8 | VerificationMethod as DidResolverVerificationMethod 9 | } from 'did-resolver'; 10 | import { RootInfo, StateInfo } from '../../../storage'; 11 | import { AuthProof, CrossChainProof } from './contract-request'; 12 | 13 | /** AuthorizationResponseMessage is struct the represents iden3message authorization response */ 14 | export type AuthorizationResponseMessage = BasicMessage & { 15 | body: AuthorizationMessageResponseBody; 16 | from: string; 17 | to: string; 18 | type: typeof PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_RESPONSE_MESSAGE_TYPE; 19 | }; 20 | 21 | /** AuthorizationMessageResponseBody is struct the represents authorization response data */ 22 | export type AuthorizationMessageResponseBody = { 23 | did_doc?: DIDDocument; 24 | message?: string; 25 | scope: Array; 26 | }; 27 | 28 | /** AuthorizationRequestMessage is struct the represents iden3message authorization request */ 29 | export type AuthorizationRequestMessage = BasicMessage & { 30 | body: AuthorizationRequestMessageBody; 31 | from: string; 32 | type: typeof PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE; 33 | }; 34 | 35 | /** AuthorizationRequestMessageBody is body for authorization request */ 36 | export type AuthorizationRequestMessageBody = { 37 | callbackUrl: string; 38 | reason?: string; 39 | message?: string; 40 | did_doc?: DIDDocument; 41 | scope: Array; 42 | accept?: string[]; 43 | }; 44 | 45 | /** ZeroKnowledgeProofRequest represents structure of zkp request object */ 46 | export type ZeroKnowledgeProofRequest = { 47 | id: number | string; 48 | circuitId: CircuitId; 49 | optional?: boolean; 50 | query: ZeroKnowledgeProofQuery; 51 | params?: { 52 | nullifierSessionId?: string | number; 53 | }; 54 | }; 55 | 56 | /** ZeroKnowledgeProofQuery represents structure of zkp request query object */ 57 | export type ZeroKnowledgeProofQuery = { 58 | allowedIssuers: string[]; 59 | context: string; 60 | credentialSubject?: JsonDocumentObject; 61 | proofType?: ProofType; 62 | skipClaimRevocationCheck?: boolean; 63 | groupId?: number; 64 | type: string; 65 | }; 66 | 67 | export type ZeroKnowledgeInvokeResponse = { 68 | responses: ZeroKnowledgeProofResponse[]; 69 | crossChainProof?: CrossChainProof; 70 | authProof?: AuthProof; 71 | }; 72 | 73 | /** ZeroKnowledgeProofResponse represents structure of zkp response */ 74 | export type ZeroKnowledgeProofResponse = { 75 | id: number | string; 76 | circuitId: string; 77 | vp?: VerifiablePresentation; 78 | } & ZKProof; 79 | 80 | /** ZeroKnowledgeProofAuthResponse represents structure of zkp auth response */ 81 | export type ZeroKnowledgeProofAuthResponse = Omit; 82 | 83 | /** VerifiablePresentation represents structure of Verifiable Presentation */ 84 | export type VerifiablePresentation = { 85 | '@context': string | (string | object)[]; 86 | '@type': string; 87 | verifiableCredential: { 88 | '@context': string | string[]; 89 | '@type': string | string[]; 90 | credentialSubject: JsonDocumentObject; 91 | }; 92 | }; 93 | 94 | /** DIDDocument represents structure of DID Document */ 95 | export type DIDDocument = DidResolverDidDocument & { 96 | verificationMethod?: VerificationMethod[]; 97 | }; 98 | 99 | /** VerificationMethod represents structure of Verification Method */ 100 | export type VerificationMethod = DidResolverVerificationMethod & { 101 | published?: boolean; 102 | info?: StateInfo; 103 | global?: RootInfo; 104 | }; 105 | -------------------------------------------------------------------------------- /src/iden3comm/types/protocol/contract-request.ts: -------------------------------------------------------------------------------- 1 | import { GlobalStateUpdate, IdentityStateUpdate } from '../../../storage/entities/state'; 2 | import { PROTOCOL_MESSAGE_TYPE } from '../../constants'; 3 | import { BasicMessage } from '../packer'; 4 | import { 5 | DIDDocument, 6 | ZeroKnowledgeProofAuthResponse, 7 | ZeroKnowledgeProofRequest, 8 | ZeroKnowledgeProofResponse 9 | } from './auth'; 10 | import { DID } from '@iden3/js-iden3-core'; 11 | 12 | /** ContractInvokeRequest represents structure of contract invoke request object */ 13 | export type ContractInvokeRequest = BasicMessage & { 14 | body: ContractInvokeRequestBody; 15 | type: typeof PROTOCOL_MESSAGE_TYPE.CONTRACT_INVOKE_REQUEST_MESSAGE_TYPE; 16 | }; 17 | 18 | /** ContractInvokeRequestBody represents structure of contract invoke request body object */ 19 | export type ContractInvokeRequestBody = { 20 | reason?: string; 21 | transaction_data: ContractInvokeTransactionData; 22 | scope: Array; 23 | did_doc?: DIDDocument; 24 | accept?: string[]; 25 | }; 26 | 27 | /** ContractInvokeResponse represents structure of contract invoke response object */ 28 | export type ContractInvokeResponse = BasicMessage & { 29 | body: ContractInvokeResponseBody; 30 | type: typeof PROTOCOL_MESSAGE_TYPE.CONTRACT_INVOKE_RESPONSE_MESSAGE_TYPE; 31 | }; 32 | 33 | /** ContractInvokeResponseBody represents structure of contract invoke response body object */ 34 | export type ContractInvokeResponseBody = { 35 | scope: Array; 36 | transaction_data: ContractInvokeTransactionData; 37 | did_doc?: DIDDocument; 38 | crossChainProof?: CrossChainProof; 39 | authProof?: AuthProof; 40 | }; 41 | 42 | /** OnChainZeroKnowledgeProofResponse represents structure of onchain zero knowledge proof response */ 43 | export type OnChainZeroKnowledgeProofResponse = ZeroKnowledgeProofResponse & { 44 | txHash?: string; 45 | }; 46 | 47 | /** ContractInvokeTransactionData represents structure of contract invoke transaction data object */ 48 | export type ContractInvokeTransactionData = { 49 | contract_address: string; 50 | method_id: string; 51 | chain_id: number; 52 | network?: string; 53 | txHash?: string; 54 | }; 55 | 56 | export type AuthProofEthIdentity = { 57 | userDid: DID; 58 | }; 59 | export type AuthProofZKP = { 60 | zkp: ZeroKnowledgeProofAuthResponse; 61 | }; 62 | 63 | /** AuthProofResponse represents structure of zkp response */ 64 | export type AuthProof = { 65 | authMethod: AuthMethod; 66 | } & (AuthProofEthIdentity | AuthProofZKP); 67 | 68 | export type CrossChainProof = { 69 | globalStateProofs: GlobalStateUpdate[]; 70 | identityStateProofs: IdentityStateUpdate[]; 71 | }; 72 | 73 | export enum AuthMethod { 74 | AUTHV2 = 'authV2', 75 | ETH_IDENTITY = 'ethIdentity' 76 | } 77 | -------------------------------------------------------------------------------- /src/iden3comm/types/protocol/credentials.ts: -------------------------------------------------------------------------------- 1 | import { W3CCredential } from '../../../verifiable'; 2 | import { PROTOCOL_MESSAGE_TYPE } from '../../constants'; 3 | import { BasicMessage, JsonDocumentObject, RequiredBasicMessage } from '../packer'; 4 | import { ContractInvokeTransactionData } from './contract-request'; 5 | 6 | /** CredentialIssuanceRequestMessageBody represents data for credential issuance request */ 7 | export type CredentialIssuanceRequestMessageBody = { 8 | schema: Schema; 9 | data: JsonDocumentObject; 10 | expiration: number; 11 | }; 12 | 13 | /** CredentialIssuanceRequestMessage represent Iden3message for credential request */ 14 | export type CredentialIssuanceRequestMessage = RequiredBasicMessage & { 15 | body: CredentialIssuanceRequestMessageBody; 16 | type: typeof PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_REQUEST_MESSAGE_TYPE; 17 | }; 18 | 19 | /** CredentialsOfferMessage represent Iden3message for credential offer */ 20 | export type CredentialsOfferMessage = RequiredBasicMessage & { 21 | body: CredentialsOfferMessageBody; 22 | type: typeof PROTOCOL_MESSAGE_TYPE.CREDENTIAL_OFFER_MESSAGE_TYPE; 23 | }; 24 | 25 | /** CredentialsOfferMessageBody is struct the represents offer message */ 26 | export type CredentialsOfferMessageBody = { 27 | url: string; 28 | credentials: CredentialOffer[]; 29 | }; 30 | 31 | /** CredentialsOnchainOfferMessage represent Iden3message for credential onchain offer message */ 32 | export type CredentialsOnchainOfferMessage = RequiredBasicMessage & { 33 | body: CredentialsOnchainOfferMessageBody; 34 | type: typeof PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE; 35 | }; 36 | 37 | /** CredentialsOnchainOfferMessageBody is struct the represents onchain offer message body */ 38 | export type CredentialsOnchainOfferMessageBody = { 39 | credentials: CredentialOffer[]; 40 | transaction_data: ContractInvokeTransactionData; 41 | }; 42 | 43 | /** CredentialOfferStatus is list of possible statuses for credential offer message */ 44 | export enum CredentialOfferStatus { 45 | Pending = 'pending', 46 | Completed = 'completed', 47 | Rejected = 'rejected' 48 | } 49 | 50 | /** CredentialOffer is structure to fetch credential */ 51 | export type CredentialOffer = { 52 | id: string; 53 | description: string; 54 | status?: CredentialOfferStatus; 55 | }; 56 | 57 | /** CredentialIssuanceMessage represent Iden3message for credential issuance */ 58 | export type CredentialIssuanceMessage = RequiredBasicMessage & { 59 | body: IssuanceMessageBody; 60 | type: typeof PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE; 61 | }; 62 | 63 | /** IssuanceMessageBody is struct the represents message when credential is issued */ 64 | export type IssuanceMessageBody = { 65 | credential: W3CCredential; 66 | }; 67 | 68 | /** CredentialFetchRequestMessage represent Iden3message for credential fetch request */ 69 | export type CredentialFetchRequestMessage = BasicMessage & { 70 | body: CredentialFetchRequestMessageBody; 71 | type: typeof PROTOCOL_MESSAGE_TYPE.CREDENTIAL_FETCH_REQUEST_MESSAGE_TYPE; 72 | }; 73 | 74 | /** CredentialFetchRequestMessageBody is msg body for fetch request */ 75 | export type CredentialFetchRequestMessageBody = { 76 | id: string; 77 | }; 78 | 79 | /** Schema represents location and type where it's stored */ 80 | export type Schema = { 81 | hash?: string; 82 | url: string; 83 | type: string; 84 | }; 85 | 86 | /** CredentialRefreshMessage represent Iden3message for credential refresh request */ 87 | export type CredentialRefreshMessage = RequiredBasicMessage & { 88 | body: CredentialRefreshMessageBody; 89 | type: typeof PROTOCOL_MESSAGE_TYPE.CREDENTIAL_REFRESH_MESSAGE_TYPE; 90 | }; 91 | 92 | /** CredentialRefreshMessageBody is msg body for refresh request */ 93 | export type CredentialRefreshMessageBody = { 94 | id: string; 95 | reason: string; 96 | }; 97 | -------------------------------------------------------------------------------- /src/iden3comm/types/protocol/discovery-protocol.ts: -------------------------------------------------------------------------------- 1 | import { PROTOCOL_MESSAGE_TYPE } from '../../constants'; 2 | import { BasicMessage } from '../packer'; 3 | 4 | /** @beta DiscoverFeatureQueryType is enum for query type fields */ 5 | export enum DiscoverFeatureQueryType { 6 | FeatureType = 'feature-type' 7 | } 8 | 9 | /** @beta DiscoveryProtocolFeatureType is enum for supported feature-types */ 10 | export enum DiscoveryProtocolFeatureType { 11 | Accept = 'accept', 12 | Protocol = 'protocol', 13 | GoalCode = 'goal-code', 14 | Header = 'header' 15 | } 16 | 17 | /** @beta DiscoverFeatureQueriesMessage is struct the represents discover feature queries message */ 18 | export type DiscoverFeatureQueriesMessage = BasicMessage & { 19 | body: DiscoverFeatureQueriesBody; 20 | type: typeof PROTOCOL_MESSAGE_TYPE.DISCOVERY_PROTOCOL_QUERIES_MESSAGE_TYPE; 21 | }; 22 | 23 | /** @beta DiscoverFeatureQueriesBody is struct the represents discover feature queries body */ 24 | export type DiscoverFeatureQueriesBody = { 25 | queries: DiscoverFeatureQuery[]; 26 | }; 27 | 28 | /** @beta DiscoverFeatureQuery is struct the represents discover feature query */ 29 | export type DiscoverFeatureQuery = { 30 | [DiscoverFeatureQueryType.FeatureType]: DiscoveryProtocolFeatureType; 31 | match?: string; 32 | }; 33 | 34 | /** @beta DiscoverFeatureDiscloseMessage is struct the represents discover feature disclose message */ 35 | export type DiscoverFeatureDiscloseMessage = BasicMessage & { 36 | body: DiscoverFeatureDiscloseBody; 37 | type: typeof PROTOCOL_MESSAGE_TYPE.DISCOVERY_PROTOCOL_DISCLOSE_MESSAGE_TYPE; 38 | }; 39 | 40 | /** @beta DiscoverFeatureDiscloseBody is struct the represents discover feature disclose body */ 41 | export type DiscoverFeatureDiscloseBody = { 42 | disclosures: DiscoverFeatureDisclosure[]; 43 | }; 44 | 45 | /** @beta DiscoverFeatureDisclosure is struct the represents discover feature disclosure */ 46 | export type DiscoverFeatureDisclosure = { 47 | [DiscoverFeatureQueryType.FeatureType]: DiscoveryProtocolFeatureType; 48 | id: string; 49 | }; 50 | -------------------------------------------------------------------------------- /src/iden3comm/types/protocol/messages.ts: -------------------------------------------------------------------------------- 1 | import { RequiredBasicMessage } from '../'; 2 | import { PROTOCOL_MESSAGE_TYPE } from '../../constants'; 3 | 4 | /** MessageFetchRequestMessage represent Iden3message for message fetch request. */ 5 | export type MessageFetchRequestMessage = RequiredBasicMessage & { 6 | body: MessageFetchRequestMessageBody; 7 | type: typeof PROTOCOL_MESSAGE_TYPE.CREDENTIAL_FETCH_REQUEST_MESSAGE_TYPE; 8 | }; 9 | 10 | /** MessageFetchRequestMessageBody is struct the represents body for message fetch request. */ 11 | export type MessageFetchRequestMessageBody = { 12 | id: string; 13 | }; 14 | -------------------------------------------------------------------------------- /src/iden3comm/types/protocol/problem-report.ts: -------------------------------------------------------------------------------- 1 | import { PROTOCOL_MESSAGE_TYPE } from '../../constants'; 2 | import { BasicMessage } from '../packer'; 3 | 4 | /** ProblemReportMessage is struct for problem report message */ 5 | export type ProblemReportMessage = BasicMessage & { 6 | body: ProblemReportMessageBody; 7 | pthid: string; 8 | ack?: string[]; 9 | type: typeof PROTOCOL_MESSAGE_TYPE.PROBLEM_REPORT_MESSAGE_TYPE; 10 | }; 11 | 12 | /** ProblemReportMessageBody is struct for problem report message body */ 13 | export type ProblemReportMessageBody = { 14 | code: string; 15 | comment?: string; 16 | args?: string[]; 17 | escalate_to?: string; 18 | }; 19 | -------------------------------------------------------------------------------- /src/iden3comm/types/protocol/proof.ts: -------------------------------------------------------------------------------- 1 | import { RequiredBasicMessage } from '../'; 2 | import { PROTOCOL_MESSAGE_TYPE } from '../../constants'; 3 | import { ZeroKnowledgeProofRequest, ZeroKnowledgeProofResponse } from './auth'; 4 | 5 | /** ProofGenerationRequestMessage is struct the represents body for proof generation request */ 6 | export type ProofGenerationRequestMessage = RequiredBasicMessage & { 7 | body: ProofGenerationRequestMessageBody; 8 | type: typeof PROTOCOL_MESSAGE_TYPE.PROOF_GENERATION_REQUEST_MESSAGE_TYPE; 9 | }; 10 | 11 | /** ProofGenerationRequestMessageBody is struct the represents body for proof generation request */ 12 | export type ProofGenerationRequestMessageBody = { 13 | scope: Array; 14 | }; 15 | 16 | /** ProofGenerationResponseMessage is struct the represents body for proof generation request */ 17 | export type ProofGenerationResponseMessage = RequiredBasicMessage & { 18 | body: ResponseMessageBody; 19 | type: typeof PROTOCOL_MESSAGE_TYPE.PROOF_GENERATION_RESPONSE_MESSAGE_TYPE; 20 | }; 21 | 22 | /** ResponseMessageBody is struct the represents request for revocation status */ 23 | export type ResponseMessageBody = { 24 | scope: Array; 25 | }; 26 | -------------------------------------------------------------------------------- /src/iden3comm/types/protocol/proposal-request.ts: -------------------------------------------------------------------------------- 1 | import { BasicMessage, DIDDocument, JsonDocumentObject } from '../'; 2 | import { PROTOCOL_MESSAGE_TYPE } from '../../constants'; 3 | 4 | /** @beta ProposalRequestMessage is struct the represents proposal-request message */ 5 | export type ProposalRequestMessage = BasicMessage & { 6 | body: ProposalRequestMessageBody; 7 | type: typeof PROTOCOL_MESSAGE_TYPE.PROPOSAL_REQUEST_MESSAGE_TYPE; 8 | }; 9 | 10 | /** @beta ProposalRequestMessageBody is struct the represents body for proposal-request */ 11 | export type ProposalRequestMessageBody = { 12 | credentials: ProposalRequestCredential[]; 13 | metadata?: { type: string; data?: JsonDocumentObject }; 14 | did_doc?: DIDDocument; 15 | }; 16 | 17 | /** @beta ProposalMessage is struct the represents proposal message */ 18 | export type ProposalMessage = BasicMessage & { 19 | body: ProposalMessageBody; 20 | type: typeof PROTOCOL_MESSAGE_TYPE.PROPOSAL_MESSAGE_TYPE; 21 | }; 22 | 23 | /** @beta ProposalMessageBody is struct the represents body for proposal message */ 24 | export type ProposalMessageBody = { 25 | proposals: Proposal[]; 26 | }; 27 | 28 | /** @beta ProposalRequestCredential is struct the represents proposal request credential */ 29 | export type ProposalRequestCredential = { 30 | type: string; 31 | context: string; 32 | }; 33 | 34 | /** @beta Proposal is struct the represents proposal inside proposal protocol message */ 35 | export type Proposal = { 36 | credentials: ProposalRequestCredential[]; 37 | type: string; 38 | url?: string; 39 | expiration?: string; 40 | description?: string; 41 | }; 42 | -------------------------------------------------------------------------------- /src/iden3comm/types/protocol/revocation.ts: -------------------------------------------------------------------------------- 1 | import { BasicMessage, RequiredBasicMessage } from '../'; 2 | import { RevocationStatus } from '../../../verifiable'; 3 | import { PROTOCOL_MESSAGE_TYPE } from '../../constants'; 4 | 5 | /** RevocationStatusRequestMessage is struct the represents body for proof generation request */ 6 | export type RevocationStatusRequestMessage = BasicMessage & { 7 | body: RevocationStatusRequestMessageBody; 8 | type: typeof PROTOCOL_MESSAGE_TYPE.REVOCATION_STATUS_REQUEST_MESSAGE_TYPE; 9 | }; 10 | 11 | /** RevocationStatusRequestMessageBody is struct the represents request for revocation status */ 12 | export type RevocationStatusRequestMessageBody = { 13 | revocation_nonce: number; 14 | }; 15 | 16 | /** RevocationStatusResponseMessage is struct the represents body for proof generation request */ 17 | export type RevocationStatusResponseMessage = RequiredBasicMessage & { 18 | body: RevocationStatusResponseMessageBody; 19 | type: typeof PROTOCOL_MESSAGE_TYPE.REVOCATION_STATUS_RESPONSE_MESSAGE_TYPE; 20 | }; 21 | 22 | /** RevocationStatusResponseMessageBody is struct the represents request for revocation status */ 23 | export type RevocationStatusResponseMessageBody = RevocationStatus; 24 | -------------------------------------------------------------------------------- /src/iden3comm/utils/did.ts: -------------------------------------------------------------------------------- 1 | import { SUPPORTED_PUBLIC_KEY_TYPES } from '../constants'; 2 | import { DIDDocument, VerificationMethod } from 'did-resolver'; 3 | import { secp256k1 as sec } from '@noble/curves/secp256k1'; 4 | 5 | import { KmsKeyType } from '../../kms'; 6 | import { base58ToBytes, base64UrlToBytes, bytesToHex, hexToBytes } from '../../utils'; 7 | 8 | const DIDAuthenticationSection = 'authentication'; 9 | export const resolveVerificationMethods = (didDocument: DIDDocument): VerificationMethod[] => { 10 | const vms: VerificationMethod[] = didDocument.verificationMethod || []; 11 | 12 | // prioritize: first verification methods to be chosen are from `authentication` section. 13 | const sortedVerificationMethods = (didDocument[DIDAuthenticationSection] || []) 14 | .map((verificationMethod) => { 15 | if (typeof verificationMethod === 'string') { 16 | return vms.find((i) => i.id === verificationMethod); 17 | } 18 | return verificationMethod as VerificationMethod; 19 | }) 20 | .filter((key) => key) as VerificationMethod[]; 21 | 22 | // add all other verification methods 23 | for (let index = 0; index < vms.length; index++) { 24 | const id = vms[index].id; 25 | if (sortedVerificationMethods.findIndex((vm) => vm.id === id) === -1) { 26 | sortedVerificationMethods.push(vms[index]); 27 | } 28 | } 29 | return sortedVerificationMethods; 30 | }; 31 | 32 | export const extractPublicKeyBytes = ( 33 | vm: VerificationMethod 34 | ): { publicKeyBytes: Uint8Array | null; kmsKeyType?: KmsKeyType } => { 35 | const isSupportedVmType = Object.keys(SUPPORTED_PUBLIC_KEY_TYPES).some((key) => 36 | SUPPORTED_PUBLIC_KEY_TYPES[key as keyof typeof SUPPORTED_PUBLIC_KEY_TYPES].includes(vm.type) 37 | ); 38 | if (vm.publicKeyBase58 && isSupportedVmType) { 39 | return { publicKeyBytes: base58ToBytes(vm.publicKeyBase58), kmsKeyType: KmsKeyType.Secp256k1 }; 40 | } 41 | if (vm.publicKeyBase64 && isSupportedVmType) { 42 | return { 43 | publicKeyBytes: base64UrlToBytes(vm.publicKeyBase64), 44 | kmsKeyType: KmsKeyType.Secp256k1 45 | }; 46 | } 47 | if (vm.publicKeyHex && isSupportedVmType) { 48 | return { publicKeyBytes: hexToBytes(vm.publicKeyHex), kmsKeyType: KmsKeyType.Secp256k1 }; 49 | } 50 | if ( 51 | vm.publicKeyJwk && 52 | vm.publicKeyJwk.crv === 'secp256k1' && 53 | vm.publicKeyJwk.x && 54 | vm.publicKeyJwk.y 55 | ) { 56 | const [xHex, yHex] = [ 57 | base64UrlToBytes(vm.publicKeyJwk.x), 58 | base64UrlToBytes(vm.publicKeyJwk.y) 59 | ].map(bytesToHex); 60 | const x = xHex.includes('0x') ? BigInt(xHex) : BigInt(`0x${xHex}`); 61 | const y = yHex.includes('0x') ? BigInt(yHex) : BigInt(`0x${yHex}`); 62 | return { 63 | publicKeyBytes: sec.ProjectivePoint.fromAffine({ 64 | x, 65 | y 66 | }).toRawBytes(false), 67 | kmsKeyType: KmsKeyType.Secp256k1 68 | }; 69 | } 70 | return { publicKeyBytes: null }; 71 | }; 72 | -------------------------------------------------------------------------------- /src/iden3comm/utils/envelope.ts: -------------------------------------------------------------------------------- 1 | import { BasicMessage, EnvelopeStub, HeaderStub } from '../types'; 2 | import { basicMessageFactory, envelopeStubFactory, headerStubFactory } from './message'; 3 | import { ErrNotEnvelopeStub, ErrNotHeaderStub, ErrNotProtocolMessage } from '../errors'; 4 | import { Token } from '@iden3/js-jwz'; 5 | import { byteDecoder, byteEncoder } from '../../utils'; 6 | 7 | const objectIs = ( 8 | obj: { [key in string]: any }, //eslint-disable-line @typescript-eslint/no-explicit-any 9 | targetObj: { [key in string]: any } //eslint-disable-line @typescript-eslint/no-explicit-any 10 | ): boolean => { 11 | Object.keys(targetObj).forEach((prop) => { 12 | if (!obj[prop]) { 13 | return false; 14 | } 15 | if (typeof targetObj[prop as keyof typeof targetObj] !== typeof obj[prop as keyof typeof obj]) { 16 | return false; 17 | } 18 | }); 19 | return true; 20 | }; 21 | 22 | //eslint-disable-next-line @typescript-eslint/no-explicit-any 23 | const isProtocolMessage = (message: { [key in string]: any }): boolean => { 24 | const basicMessage = basicMessageFactory(); 25 | Object.keys(basicMessage).forEach((prop) => { 26 | if (!message[prop]) { 27 | return false; 28 | } 29 | if (prop !== 'body') { 30 | const res = 31 | typeof basicMessage[prop as keyof typeof basicMessage] === 32 | typeof (message[prop as keyof typeof message] as any); //eslint-disable-line @typescript-eslint/no-explicit-any 33 | if (!res) { 34 | return false; 35 | } 36 | } 37 | }); 38 | 39 | return true; 40 | }; 41 | 42 | /** 43 | * 44 | * @param {Uint8Array} e 45 | * @returns Promise 46 | */ 47 | export const envelopeToProtocolMessage = async (e: Uint8Array): Promise => { 48 | const t = await Token.parse(byteDecoder.decode(e)); 49 | const pBytes = byteEncoder.encode(t.getPayload()); 50 | return bytesToProtocolMessage(pBytes); 51 | }; 52 | 53 | /** 54 | * helper function to convert serialized JSON bytes to protocol message 55 | * 56 | * @param {Uint8Array} bytes 57 | * @returns {BasicMessage} 58 | */ 59 | export const bytesToProtocolMessage = (bytes: Uint8Array): BasicMessage => { 60 | const str = byteDecoder.decode(bytes); 61 | const message = JSON.parse(str); 62 | if (!isProtocolMessage(message)) { 63 | throw new Error(ErrNotProtocolMessage); 64 | } 65 | return message as BasicMessage; 66 | }; 67 | 68 | /** 69 | * helper function to convert serialized JSON bytes to envelop stub 70 | * so we can work with protected field of jwt token 71 | * 72 | * 73 | * @param {Uint8Array} envelope 74 | * @returns {EnvelopeStub} 75 | */ 76 | export const bytesToEnvelopeStub = (envelope: Uint8Array): EnvelopeStub => { 77 | const tmpObj = envelopeStubFactory(); 78 | const str = byteDecoder.decode(envelope); 79 | const message = JSON.parse(str); 80 | if (!objectIs(message, tmpObj)) { 81 | throw new Error(ErrNotEnvelopeStub); 82 | } 83 | return message as EnvelopeStub; 84 | }; 85 | 86 | /** 87 | * helper function to convert serialized JSON bytes to header stub 88 | * so we can work with know the media type of the message 89 | * 90 | * @param {Uint8Array} envelope 91 | * @returns {HeaderStub} 92 | */ 93 | export const bytesToHeaderStub = (envelope: Uint8Array): HeaderStub => { 94 | const tmpObj = headerStubFactory(); 95 | const str = byteDecoder.decode(envelope); 96 | const message = JSON.parse(str); 97 | if (!objectIs(message, tmpObj)) { 98 | throw new Error(ErrNotHeaderStub); 99 | } 100 | return message as HeaderStub; 101 | }; 102 | -------------------------------------------------------------------------------- /src/iden3comm/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './envelope'; 2 | export * from './message'; 3 | export * from './did'; 4 | export * from './accept-profile'; 5 | -------------------------------------------------------------------------------- /src/iden3comm/utils/message.ts: -------------------------------------------------------------------------------- 1 | import { MediaType } from '../constants'; 2 | import { BasicMessage, EnvelopeStub, HeaderStub, ProtocolMessage } from '../types'; 3 | 4 | /** 5 | * creates empty basic message 6 | * 7 | * @returns BasicMessage 8 | */ 9 | export const basicMessageFactory = (): BasicMessage => { 10 | return { 11 | id: '', 12 | typ: '' as MediaType, 13 | thid: '', 14 | type: '' as ProtocolMessage, 15 | body: {}, 16 | from: '', 17 | to: '' 18 | }; 19 | }; 20 | 21 | /** 22 | * create empty envelope stub 23 | * 24 | * @returns EnvelopeStub 25 | */ 26 | export const envelopeStubFactory = (): EnvelopeStub => { 27 | return { 28 | protected: '' 29 | }; 30 | }; 31 | 32 | /** 33 | * create empty header stub 34 | * 35 | * @returns {HeaderStub} 36 | */ 37 | export const headerStubFactory = (): HeaderStub => { 38 | return { 39 | typ: '' as MediaType 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /src/identity/common.ts: -------------------------------------------------------------------------------- 1 | import { DID, Id, IdPosition, MerklizedRootPosition } from '@iden3/js-iden3-core'; 2 | import { SchemaMetadata } from '../schema-processor'; 3 | import { SubjectPosition } from '../verifiable'; 4 | 5 | /** 6 | * Determines subject position 7 | * 8 | * @param {IdPosition} idPosition - index / none / value 9 | * @returns {SubjectPosition} 10 | */ 11 | export const subjectPositionIndex = (idPosition: IdPosition): SubjectPosition => { 12 | switch (idPosition) { 13 | case IdPosition.Index: 14 | return SubjectPosition.Index; 15 | case IdPosition.Value: 16 | return SubjectPosition.Value; 17 | default: 18 | return SubjectPosition.None; 19 | } 20 | }; 21 | 22 | /** 23 | * Returns merklized root position based on schema serialization metadata and expected position 24 | * 25 | * @param {SchemaMetadata} [metadata] - schema metadata 26 | * @param {MerklizedRootPosition} [position] - expected mt root position 27 | * @returns {MerklizedRootPosition} 28 | */ 29 | export const defineMerklizedRootPosition = ( 30 | metadata?: SchemaMetadata, 31 | position?: MerklizedRootPosition 32 | ): MerklizedRootPosition => { 33 | if (!metadata?.serialization) { 34 | return MerklizedRootPosition.None; 35 | } 36 | 37 | if (position != null && position !== MerklizedRootPosition.None) { 38 | return position; 39 | } 40 | 41 | return MerklizedRootPosition.Index; 42 | }; 43 | 44 | /** 45 | * Returns profile DID based on did and profile nonce 46 | * 47 | * @param {DID} [did] - did from which profile will be derived 48 | * @param {number | string} [profileNonce] - profile nonce 49 | * @returns {DID} 50 | */ 51 | export const generateProfileDID = (did: DID, profileNonce?: number | string): DID => { 52 | const id = DID.idFromDID(did); 53 | 54 | profileNonce = profileNonce ?? 0; 55 | 56 | if (!isBigInt(profileNonce)) { 57 | throw new Error('profile must be number or decimal string'); 58 | } 59 | const profile = Id.profileId(id, BigInt(profileNonce)); 60 | return DID.parseFromId(profile); 61 | }; 62 | 63 | const isBigInt = (x: number | string): boolean => { 64 | try { 65 | return BigInt(x).toString() === x.toString(); 66 | } catch { 67 | return false; // conversion to BigInt failed, surely it is not a BigInt 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /src/identity/index.ts: -------------------------------------------------------------------------------- 1 | export * from './identity-wallet'; 2 | export * from './common'; 3 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './identity'; 2 | export * from './credentials'; 3 | export * from './kms'; 4 | export * from './storage'; 5 | export * from './verifiable'; 6 | export * from './schema-processor'; 7 | export * from './proof'; 8 | export * from './iden3comm'; 9 | export * from './circuits'; 10 | export * from './iden3comm'; 11 | export * from './utils'; 12 | export * from './blockchain'; 13 | import * as core from '@iden3/js-iden3-core'; 14 | import * as jsonLDMerklizer from '@iden3/js-jsonld-merklization'; 15 | export { core }; 16 | export { jsonLDMerklizer }; 17 | -------------------------------------------------------------------------------- /src/kms/index.ts: -------------------------------------------------------------------------------- 1 | export * from './kms'; 2 | export * from './key-providers'; 3 | export * from './store'; 4 | export * from './provider-helpers'; 5 | -------------------------------------------------------------------------------- /src/kms/key-providers/bjj-provider.ts: -------------------------------------------------------------------------------- 1 | import { Hex, PrivateKey, PublicKey, Signature } from '@iden3/js-crypto'; 2 | import { BytesHelper, checkBigIntInField } from '@iden3/js-iden3-core'; 3 | import { IKeyProvider } from '../kms'; 4 | import { AbstractPrivateKeyStore, KmsKeyId, KmsKeyType } from '../store'; 5 | 6 | import * as providerHelpers from '../provider-helpers'; 7 | import { hexToBytes } from '../../utils'; 8 | 9 | /** 10 | * Provider for Baby Jub Jub keys 11 | * @public 12 | * @class BjjProvider 13 | * @implements implements IKeyProvider interface 14 | */ 15 | export class BjjProvider implements IKeyProvider { 16 | /** 17 | * key type that is handled by BJJ Provider 18 | * @type {KmsKeyType} 19 | */ 20 | keyType: KmsKeyType; 21 | private keyStore: AbstractPrivateKeyStore; 22 | /** 23 | * Creates an instance of BjjProvider. 24 | * @param {KmsKeyType} keyType - kms key type 25 | * @param {AbstractPrivateKeyStore} keyStore - key store for kms 26 | */ 27 | constructor(keyType: KmsKeyType, keyStore: AbstractPrivateKeyStore) { 28 | if (keyType !== KmsKeyType.BabyJubJub) { 29 | throw new Error('Key type must be BabyJubJub'); 30 | } 31 | this.keyType = keyType; 32 | this.keyStore = keyStore; 33 | } 34 | /** 35 | * get all keys 36 | * @returns list of keys 37 | */ 38 | async list(): Promise< 39 | { 40 | alias: string; 41 | key: string; 42 | }[] 43 | > { 44 | const allKeysFromKeyStore = await this.keyStore.list(); 45 | return allKeysFromKeyStore.filter((key) => key.alias.startsWith(this.keyType)); 46 | } 47 | 48 | /** 49 | * generates a baby jub jub key from a seed phrase 50 | * @param {Uint8Array} seed - byte array seed 51 | * @returns kms key identifier 52 | */ 53 | async newPrivateKeyFromSeed(seed: Uint8Array): Promise { 54 | const newKey: Uint8Array = new Uint8Array(32); 55 | newKey.set(Uint8Array.from(seed), 0); 56 | newKey.fill(seed.length, 32, 0); 57 | const privateKey: PrivateKey = new PrivateKey(seed); 58 | 59 | const publicKey = privateKey.public(); 60 | 61 | const kmsId = { 62 | type: this.keyType, 63 | id: providerHelpers.keyPath(this.keyType, publicKey.hex()) 64 | }; 65 | await this.keyStore.importKey({ alias: kmsId.id, key: privateKey.hex() }); 66 | 67 | return kmsId; 68 | } 69 | 70 | /** 71 | * Gets public key by kmsKeyId 72 | * 73 | * @param {KmsKeyId} keyId - key identifier 74 | */ 75 | async publicKey(keyId: KmsKeyId): Promise { 76 | const privateKey: PrivateKey = await this.privateKey(keyId); 77 | return privateKey.public().hex(); 78 | } 79 | 80 | /** 81 | * signs prepared payload of size, 82 | * with a key id 83 | * 84 | * @param {KmsKeyId} keyId - key identifier 85 | * @param {Uint8Array} data - data to sign (32 bytes) 86 | * @returns Uint8Array signature 87 | */ 88 | async sign(keyId: KmsKeyId, data: Uint8Array): Promise { 89 | if (data.length != 32) { 90 | throw new Error('data to sign is too large'); 91 | } 92 | 93 | const i = BytesHelper.bytesToInt(data); 94 | if (!checkBigIntInField(i)) { 95 | throw new Error('data to sign is too large'); 96 | } 97 | const privateKey = await this.privateKey(keyId); 98 | 99 | const signature = privateKey.signPoseidon(i); 100 | 101 | return signature.compress(); 102 | } 103 | 104 | private async privateKey(keyId: KmsKeyId): Promise { 105 | const privateKeyHex = await this.keyStore.get({ alias: keyId.id }); 106 | 107 | return new PrivateKey(Hex.decodeString(privateKeyHex)); 108 | } 109 | 110 | async verify(message: Uint8Array, signatureHex: string, keyId: KmsKeyId): Promise { 111 | const publicKey = await this.publicKey(keyId); 112 | 113 | return PublicKey.newFromCompressed(hexToBytes(publicKey)).verifyPoseidon( 114 | BytesHelper.bytesToInt(message), 115 | Signature.newFromCompressed(hexToBytes(signatureHex)) 116 | ); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/kms/key-providers/ed25519-provider.ts: -------------------------------------------------------------------------------- 1 | import { IKeyProvider } from '../kms'; 2 | import { AbstractPrivateKeyStore, KmsKeyId, KmsKeyType } from '../store'; 3 | import * as providerHelpers from '../provider-helpers'; 4 | import { ed25519 } from '@noble/curves/ed25519'; 5 | import { bytesToHex } from '../../utils'; 6 | 7 | /** 8 | * Provider for Ed25519 keys 9 | * @public 10 | * @class Ed25519Provider 11 | * @implements IKeyProvider interface 12 | */ 13 | export class Ed25519Provider implements IKeyProvider { 14 | /** 15 | * Creates an instance of Ed25519Provider. 16 | * @param {KmsKeyType} keyType - kms key type 17 | * @param {AbstractPrivateKeyStore} keyStore - key store for kms 18 | */ 19 | constructor( 20 | public readonly keyType: KmsKeyType, 21 | private readonly _keyStore: AbstractPrivateKeyStore 22 | ) {} 23 | 24 | /** 25 | * get all keys 26 | * @returns list of keys 27 | */ 28 | async list(): Promise< 29 | { 30 | alias: string; 31 | key: string; 32 | }[] 33 | > { 34 | const allKeysFromKeyStore = await this._keyStore.list(); 35 | return allKeysFromKeyStore.filter((key) => key.alias.startsWith(this.keyType)); 36 | } 37 | 38 | /** 39 | * generates a ed25519 key from a seed phrase 40 | * @param {Uint8Array} seed - byte array seed 41 | * @returns {Promise} kms key identifier 42 | */ 43 | async newPrivateKeyFromSeed(seed: Uint8Array): Promise { 44 | if (seed.length !== 32) { 45 | throw new Error('Seed should be 32 bytes'); 46 | } 47 | 48 | const publicKey = ed25519.getPublicKey(seed); 49 | const kmsId = { 50 | type: this.keyType, 51 | id: providerHelpers.keyPath(this.keyType, bytesToHex(publicKey)) 52 | }; 53 | 54 | await this._keyStore.importKey({ 55 | alias: kmsId.id, 56 | key: bytesToHex(seed) 57 | }); 58 | 59 | return kmsId; 60 | } 61 | 62 | /** 63 | * Gets public key by kmsKeyId 64 | * @param {KmsKeyId} keyId - key identifier 65 | * @returns {Promise} Public key as a hex string 66 | */ 67 | async publicKey(keyId: KmsKeyId): Promise { 68 | const privateKeyHex = await this.privateKey(keyId); 69 | const publicKey = ed25519.getPublicKey(privateKeyHex); 70 | return bytesToHex(publicKey); 71 | } 72 | 73 | /** 74 | * signs prepared payload of size, 75 | * with a key id 76 | * @param {KmsKeyId} keyId - key identifier 77 | * @param {Uint8Array} digest - data to sign (32 bytes) 78 | * @returns {Promise} signature 79 | */ 80 | async sign(keyId: KmsKeyId, digest: Uint8Array): Promise { 81 | const privateKeyHex = await this.privateKey(keyId); 82 | return ed25519.sign(digest, privateKeyHex); 83 | } 84 | 85 | /** 86 | * Verifies a signature for the given message and key identifier. 87 | * @param digest - The message to verify the signature against. 88 | * @param signatureHex - The signature to verify, as a hexadecimal string. 89 | * @param keyId - The key identifier to use for verification. 90 | * @returns A Promise that resolves to a boolean indicating whether the signature is valid. 91 | */ 92 | async verify(digest: Uint8Array, signatureHex: string, keyId: KmsKeyId): Promise { 93 | const publicKeyHex = await this.publicKey(keyId); 94 | return ed25519.verify(signatureHex, digest, publicKeyHex); 95 | } 96 | 97 | /** 98 | * Retrieves the private key for a given keyId from the key store. 99 | * @param {KmsKeyId} keyId - The identifier of the key to retrieve. 100 | * @returns {Promise} The private key associated with the keyId. 101 | */ 102 | private async privateKey(keyId: KmsKeyId): Promise { 103 | return this._keyStore.get({ alias: keyId.id }); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/kms/key-providers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './bjj-provider'; 2 | export * from './ed25519-provider'; 3 | export * from './secp256k1-provider'; 4 | -------------------------------------------------------------------------------- /src/kms/provider-helpers.ts: -------------------------------------------------------------------------------- 1 | import { KmsKeyType } from './store'; 2 | 3 | /** 4 | * builds key path 5 | * 6 | * @param {KmsKeyType} keyType - key type 7 | * @param {string} keyID - key id 8 | * @returns string path 9 | */ 10 | export function keyPath(keyType: KmsKeyType, keyID: string): string { 11 | const basePath = ''; 12 | return basePath + String(keyType) + ':' + keyID; 13 | } 14 | -------------------------------------------------------------------------------- /src/kms/store/abstract-key-store.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * KeyStore that allows to import and get keys by alias. 3 | * 4 | * @abstract 5 | * @public 6 | * @class AbstractPrivateKeyStore 7 | */ 8 | export abstract class AbstractPrivateKeyStore { 9 | /** 10 | * imports key by alias 11 | * 12 | * @abstract 13 | * @param {{ alias: string; key: string }} args - key alias and hex representation 14 | * @returns `Promise` 15 | */ 16 | abstract importKey(args: { alias: string; key: string }): Promise; 17 | 18 | /** 19 | * get key by alias 20 | * 21 | * @abstract 22 | * @param {{ alias: string }} args -key alias 23 | * @returns `Promise` 24 | */ 25 | abstract get(args: { alias: string }): Promise; 26 | 27 | /** 28 | * get all keys 29 | * 30 | * @abstract 31 | * @returns `Promise<{ alias: string; key: string }[]>` 32 | */ 33 | abstract list(): Promise<{ alias: string; key: string }[]>; 34 | } 35 | -------------------------------------------------------------------------------- /src/kms/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './abstract-key-store'; 2 | export * from './memory-key-store'; 3 | export * from './types'; 4 | export * from './local-storage-key-store'; 5 | export * from './indexed-db-key-store'; 6 | -------------------------------------------------------------------------------- /src/kms/store/indexed-db-key-store.ts: -------------------------------------------------------------------------------- 1 | import { UseStore, createStore, get, set, entries } from 'idb-keyval'; 2 | import { AbstractPrivateKeyStore } from './abstract-key-store'; 3 | 4 | /** 5 | * Allows storing keys in the indexed db storage of the browser 6 | * (NOT ENCRYPTED: DO NOT USE IN THE PRODUCTION) 7 | * 8 | * @public 9 | * @class IndexedDBPrivateKeyStore 10 | * @implements implements AbstractPrivateKeyStore interface 11 | */ 12 | export class IndexedDBPrivateKeyStore implements AbstractPrivateKeyStore { 13 | static readonly storageKey = 'keystore'; 14 | private readonly _store: UseStore; 15 | 16 | constructor() { 17 | this._store = createStore( 18 | `${IndexedDBPrivateKeyStore.storageKey}-db`, 19 | IndexedDBPrivateKeyStore.storageKey 20 | ); 21 | } 22 | 23 | /** 24 | * get all keys 25 | * 26 | * @abstract 27 | * @returns `Promise<{ alias: string; key: string }[]>` 28 | */ 29 | async list(): Promise<{ alias: string; key: string }[]> { 30 | const allEntries = await entries(this._store); 31 | return allEntries.map(([alias, key]) => ({ alias, key: key.value })) as unknown as { 32 | alias: string; 33 | key: string; 34 | }[]; 35 | } 36 | 37 | /** 38 | * Gets key from the indexed db storage 39 | * 40 | * @param {{ alias: string }} args 41 | * @returns hex string 42 | */ 43 | async get(args: { alias: string }): Promise { 44 | const key = await get(args.alias, this._store); 45 | if (!key) { 46 | throw new Error('no key under given alias'); 47 | } 48 | return key.value; 49 | } 50 | 51 | /** 52 | * Import key to the indexed db storage 53 | * 54 | * @param {{ alias: string; key: string }} args - alias and private key in the hex 55 | * @returns void 56 | */ 57 | async importKey(args: { alias: string; key: string }): Promise { 58 | await set(args.alias, { value: args.key }, this._store); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/kms/store/local-storage-key-store.ts: -------------------------------------------------------------------------------- 1 | import { AbstractPrivateKeyStore } from './abstract-key-store'; 2 | import { KmsKeyId } from './types'; 3 | 4 | /** 5 | * Allows storing keys in the local storage of the browser 6 | * (NOT ENCRYPTED: DO NOT USE IN THE PRODUCTION) 7 | * 8 | * @public 9 | * @class LocalStoragePrivateKeyStore 10 | * @implements implements AbstractPrivateKeyStore interface 11 | */ 12 | export class LocalStoragePrivateKeyStore implements AbstractPrivateKeyStore { 13 | static readonly storageKey = 'keystore'; 14 | 15 | /** 16 | * get all keys 17 | * 18 | * @abstract 19 | * @returns `Promise<{ alias: string; key: string }[]>` 20 | */ 21 | list(): Promise<{ alias: string; key: string }[]> { 22 | const dataStr = localStorage.getItem(LocalStoragePrivateKeyStore.storageKey); 23 | if (!dataStr) { 24 | throw new Error('no key under given alias'); 25 | } 26 | const data = JSON.parse(dataStr); 27 | return data.map((i: { id: string; value: string }) => ({ alias: i.id, key: i.value })); 28 | } 29 | /** 30 | * Gets key from the local storage 31 | * 32 | * @param {{ alias: string }} args 33 | * @returns hex string 34 | */ 35 | async get(args: { alias: string }): Promise { 36 | const dataStr = localStorage.getItem(LocalStoragePrivateKeyStore.storageKey); 37 | if (!dataStr) { 38 | throw new Error('no key under given alias'); 39 | } 40 | const data = JSON.parse(dataStr); 41 | const privateKey = data.find((d: KmsKeyId) => d.id === args.alias); 42 | if (!privateKey) { 43 | throw new Error('no key under given alias'); 44 | } 45 | return privateKey.value; 46 | } 47 | 48 | /** 49 | * Import key to the local storage 50 | * 51 | * @param {{ alias: string; key: string }} args - alias and private key in the hex 52 | * @returns void 53 | */ 54 | async importKey(args: { alias: string; key: string }): Promise { 55 | const dataStr = localStorage.getItem(LocalStoragePrivateKeyStore.storageKey); 56 | let data = []; 57 | if (dataStr) { 58 | data = JSON.parse(dataStr); 59 | } 60 | 61 | const index = data.findIndex((d: KmsKeyId) => d.id === args.alias); 62 | if (index > -1) { 63 | data[index].value = args.key; 64 | } else { 65 | data.push({ id: args.alias, value: args.key }); 66 | } 67 | localStorage.setItem(LocalStoragePrivateKeyStore.storageKey, JSON.stringify(data)); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/kms/store/memory-key-store.ts: -------------------------------------------------------------------------------- 1 | import { AbstractPrivateKeyStore } from './abstract-key-store'; 2 | 3 | /** 4 | * Key Store to use in memory 5 | * 6 | * @public 7 | * @class InMemoryPrivateKeyStore 8 | * @implements implements AbstractPrivateKeyStore interface 9 | */ 10 | export class InMemoryPrivateKeyStore implements AbstractPrivateKeyStore { 11 | private _data: Map; 12 | constructor() { 13 | this._data = new Map(); 14 | } 15 | list(): Promise<{ alias: string; key: string }[]> { 16 | return Promise.resolve(Array.from(this._data).map(([alias, key]) => ({ alias, key }))); 17 | } 18 | async get(args: { alias: string }): Promise { 19 | const privateKey = this._data.get(args.alias); 20 | if (!privateKey) { 21 | throw new Error('no key under given alias'); 22 | } 23 | return privateKey; 24 | } 25 | 26 | async importKey(args: { alias: string; key: string }): Promise { 27 | this._data.set(args.alias, args.key); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/kms/store/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Key type that can be used in the key management system 3 | * 4 | * @enum {number} 5 | */ 6 | export enum KmsKeyType { 7 | BabyJubJub = 'BJJ', 8 | Secp256k1 = 'Secp256k1', 9 | Ed25519 = 'Ed25519' 10 | } 11 | 12 | /** 13 | * ID of the key that describe contain key type 14 | * 15 | * @public 16 | * @interface KmsKeyId 17 | */ 18 | export interface KmsKeyId { 19 | type: KmsKeyType; 20 | id: string; 21 | } 22 | -------------------------------------------------------------------------------- /src/proof/index.ts: -------------------------------------------------------------------------------- 1 | export * from './proof-service'; 2 | export * from './provers'; 3 | export * from './common'; 4 | export * from './verifiers'; 5 | -------------------------------------------------------------------------------- /src/proof/provers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './inputs-generator'; 2 | export * from './prover'; 3 | export * from './witness_calculator'; 4 | -------------------------------------------------------------------------------- /src/proof/provers/prover.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | import { ZKProof } from '@iden3/js-jwz'; 3 | import { witnessBuilder } from './witness_calculator'; 4 | import { groth16 } from 'snarkjs'; 5 | import { getCurveFromName } from 'ffjavascript'; 6 | import { ICircuitStorage } from '../../storage'; 7 | import { CircuitId } from '../../circuits'; 8 | import { byteDecoder } from '../../utils'; 9 | 10 | /** 11 | * ZKProver is responsible for proof generation and verification 12 | * 13 | * @public 14 | * @interface ZKProver 15 | */ 16 | export interface IZKProver { 17 | /** 18 | * generates zero knowledge proof 19 | * 20 | * @param {Uint8Array} inputs - inputs that will be used for proof generation 21 | * @param {string} circuitId - circuit id for proof generation 22 | * @returns `Promise` 23 | */ 24 | generate(inputs: Uint8Array, circuitId: string): Promise; 25 | /** 26 | * verifies zero knowledge proof 27 | * 28 | * @param {ZKProof} zkp - zero knowledge proof that will be verified 29 | * @param {string} circuitId - circuit id for proof verification 30 | * @returns `Promise` 31 | */ 32 | verify(zkp: ZKProof, circuitId: string): Promise; 33 | } 34 | 35 | /** 36 | * NativeProver service responsible for zk generation and verification of groth16 algorithm with bn128 curve 37 | * @public 38 | * @class NativeProver 39 | * @implements implements IZKProver interface 40 | */ 41 | export class NativeProver implements IZKProver { 42 | private static readonly curveName = 'bn128'; 43 | constructor(private readonly _circuitStorage: ICircuitStorage) {} 44 | 45 | /** 46 | * verifies zero knowledge proof 47 | * 48 | * @param {ZKProof} zkp - zero knowledge proof that will be verified 49 | * @param {string} circuitId - circuit id for proof verification 50 | * @returns `Promise` 51 | */ 52 | async verify(zkp: ZKProof, circuitId: CircuitId): Promise { 53 | try { 54 | const circuitData = await this._circuitStorage.loadCircuitData(circuitId); 55 | 56 | if (!circuitData.verificationKey) { 57 | throw new Error(`verification file doesn't exist for circuit ${circuitId}`); 58 | } 59 | 60 | const result = await groth16.verify( 61 | JSON.parse(byteDecoder.decode(circuitData.verificationKey)), 62 | zkp.pub_signals, 63 | zkp.proof 64 | ); 65 | 66 | // we need to terminate curve manually 67 | await this.terminateCurve(); 68 | 69 | return result; 70 | } catch (e) { 71 | // eslint-disable-next-line no-console 72 | console.log(e); 73 | return false; 74 | } 75 | } 76 | 77 | /** 78 | * generates zero knowledge proof 79 | * 80 | * @param {Uint8Array} inputs - inputs that will be used for proof generation 81 | * @param {string} circuitId - circuit id for proof generation 82 | * @returns `Promise` 83 | */ 84 | async generate(inputs: Uint8Array, circuitId: CircuitId): Promise { 85 | const circuitData = await this._circuitStorage.loadCircuitData(circuitId); 86 | if (!circuitData.wasm) { 87 | throw new Error(`wasm file doesn't exist for circuit ${circuitId}`); 88 | } 89 | 90 | const witnessCalculator = await witnessBuilder(circuitData.wasm); 91 | 92 | const parsedData = JSON.parse(byteDecoder.decode(inputs)); 93 | 94 | const wtnsBytes: Uint8Array = await witnessCalculator.calculateWTNSBin(parsedData, 0); 95 | 96 | if (!circuitData.provingKey) { 97 | throw new Error(`proving file doesn't exist for circuit ${circuitId}`); 98 | } 99 | const { proof, publicSignals } = await groth16.prove(circuitData.provingKey, wtnsBytes); 100 | 101 | // we need to terminate curve manually 102 | await this.terminateCurve(); 103 | 104 | return { 105 | proof, 106 | pub_signals: publicSignals 107 | }; 108 | } 109 | 110 | private async terminateCurve(): Promise { 111 | const curve = await getCurveFromName(NativeProver.curveName); 112 | curve.terminate(); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/proof/verifiers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './pub-signals-verifier'; 2 | export * from './query'; 3 | export * from './query-hash'; 4 | -------------------------------------------------------------------------------- /src/proof/verifiers/query-hash.ts: -------------------------------------------------------------------------------- 1 | import { poseidon } from '@iden3/js-crypto'; 2 | import { SchemaHash } from '@iden3/js-iden3-core'; 3 | import { defaultValueArraySize, prepareCircuitArrayValues } from '../../circuits'; 4 | 5 | export function calculateQueryHashV2( 6 | values: bigint[], 7 | schema: SchemaHash, 8 | slotIndex: string | number, 9 | operator: string | number, 10 | claimPathKey: string | number, 11 | claimPathNotExists: string | number 12 | ): bigint { 13 | const expValue = prepareCircuitArrayValues(values, 64); 14 | const valueHash = poseidon.spongeHashX(expValue, 6); 15 | return poseidon.hash([ 16 | schema.bigInt(), 17 | BigInt(slotIndex), 18 | BigInt(operator), 19 | BigInt(claimPathKey), 20 | BigInt(claimPathNotExists), 21 | valueHash 22 | ]); 23 | } 24 | 25 | export function calculateQueryHashV3( 26 | values: bigint[], 27 | schema: SchemaHash, 28 | slotIndex: string | number, 29 | operator: string | number, 30 | claimPathKey: string | number, 31 | valueArraySize: string | number, 32 | merklized: string | number, 33 | isRevocationChecked: string | number, 34 | verifierID: string | number, 35 | nullifierSessionID: string | number 36 | ): bigint { 37 | const expValue = prepareCircuitArrayValues(values, defaultValueArraySize); 38 | const valueHash = poseidon.spongeHashX(expValue, 6); 39 | const firstPartQueryHash = poseidon.hash([ 40 | schema.bigInt(), 41 | BigInt(slotIndex), 42 | BigInt(operator), 43 | BigInt(claimPathKey), 44 | BigInt(merklized), 45 | valueHash 46 | ]); 47 | 48 | const queryHash = poseidon.hash([ 49 | firstPartQueryHash, 50 | BigInt(valueArraySize), 51 | BigInt(isRevocationChecked), 52 | BigInt(verifierID), 53 | BigInt(nullifierSessionID), 54 | 0n 55 | ]); 56 | return queryHash; 57 | } 58 | -------------------------------------------------------------------------------- /src/schema-processor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './utils'; 2 | export * from './json'; 3 | export * from './jsonld'; 4 | -------------------------------------------------------------------------------- /src/schema-processor/json/index.ts: -------------------------------------------------------------------------------- 1 | export * from './parser'; 2 | export * from './validator'; 3 | -------------------------------------------------------------------------------- /src/schema-processor/json/validator.ts: -------------------------------------------------------------------------------- 1 | // or ESM/TypeScript import 2 | import Ajv from 'ajv'; 3 | import { byteDecoder } from '../../utils'; 4 | import Ajv2020 from 'ajv/dist/2020'; 5 | import Ajv2019 from 'ajv/dist/2019'; 6 | import addFormats from 'ajv-formats'; 7 | 8 | const defaultOpts = { verbose: true, strict: false }; 9 | const defaultJSONSchemaValidator = new Ajv(defaultOpts); 10 | 11 | /** JSON SCHEMA VALIDATOR REGISTRY */ 12 | export const JSON_SCHEMA_VALIDATORS_REGISTRY = { 13 | 'http://json-schema.org/draft-07/schema': defaultJSONSchemaValidator, 14 | 'https://json-schema.org/draft/2019-09/schema': new Ajv2019(defaultOpts), 15 | 'https://json-schema.org/draft/2020-12/schema': new Ajv2020(defaultOpts) 16 | }; 17 | 18 | /** 19 | * JSON Schema Validator 20 | * 21 | * @public 22 | * @class JsonSchemaValidator 23 | */ 24 | export class JsonSchemaValidator { 25 | /** 26 | * Validate data according to the given schema 27 | * 28 | * @param {Uint8Array} dataBytes - payload to validate 29 | * @param {Uint8Array} schemaBytes - schema to process 30 | * @returns `Promise` 31 | */ 32 | async validate(dataBytes: Uint8Array, schemaBytes: Uint8Array): Promise { 33 | const schema = JSON.parse(byteDecoder.decode(schemaBytes)); 34 | const data = JSON.parse(byteDecoder.decode(dataBytes)); 35 | const draft = schema['$schema']?.replaceAll('#', ''); 36 | let validator: Ajv | Ajv2020; 37 | if (!draft) { 38 | validator = defaultJSONSchemaValidator; 39 | } 40 | const ajv = 41 | JSON_SCHEMA_VALIDATORS_REGISTRY[draft as keyof typeof JSON_SCHEMA_VALIDATORS_REGISTRY]; 42 | validator = ajv ?? defaultJSONSchemaValidator; 43 | if (validator.formats && !Object.keys(validator.formats).length) { 44 | addFormats(validator); 45 | } 46 | const validate = 47 | (schema.$id ? validator.getSchema(schema.$id) : undefined) || validator.compile(schema); 48 | const valid = validate(data); 49 | if (!valid) { 50 | // TODO: extract correct error messages 51 | throw new Error(validate.errors?.map((e) => e.message).join(', ')); 52 | } 53 | return true; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/schema-processor/jsonld/cache.ts: -------------------------------------------------------------------------------- 1 | import { DocumentLoader, Options, getDocumentLoader } from '@iden3/js-jsonld-merklization'; 2 | import { RemoteDocument, Url } from 'jsonld/jsonld-spec'; 3 | import { VerifiableConstants } from '../../verifiable'; 4 | 5 | /** 6 | * cacheLoader returns a remote document with additional logic for caching the urls remote documents. 7 | * If the same url is called more then once, remote document will be not downloaded again but will returned from memory cache. 8 | * @param {Options } context - JSONLD loader options 9 | * @returns Promise 10 | */ 11 | 12 | const doc = JSON.parse(VerifiableConstants.JSONLD_SCHEMA.W3C_VC_DOCUMENT_2018); 13 | const docIden3Proofs = JSON.parse( 14 | VerifiableConstants.JSONLD_SCHEMA.IDEN3_PROOFS_DEFINITION_DOCUMENT 15 | ); 16 | const docIden3DisplayMethod = JSON.parse( 17 | VerifiableConstants.JSONLD_SCHEMA.IDEN3_DISPLAY_METHOD_DEFINITION_DOCUMENT 18 | ); 19 | const docIden3AuthBJJ = JSON.parse(VerifiableConstants.AUTH.AUTH_BJJ_CREDENTIAL_SCHEMA_JSONLD); 20 | 21 | export const cacheLoader = (opts?: Options): DocumentLoader => { 22 | const cache = new Map(); 23 | cache.set(VerifiableConstants.JSONLD_SCHEMA.W3C_CREDENTIAL_2018, { 24 | document: doc, 25 | documentUrl: VerifiableConstants.JSONLD_SCHEMA.W3C_CREDENTIAL_2018 26 | }); 27 | cache.set(VerifiableConstants.JSONLD_SCHEMA.IDEN3_CREDENTIAL, { 28 | document: docIden3Proofs, 29 | documentUrl: VerifiableConstants.JSONLD_SCHEMA.IDEN3_PROOFS_DEFINITION_DOCUMENT 30 | }); 31 | cache.set(VerifiableConstants.JSONLD_SCHEMA.IDEN3_DISPLAY_METHOD, { 32 | document: docIden3DisplayMethod, 33 | documentUrl: VerifiableConstants.JSONLD_SCHEMA.IDEN3_DISPLAY_METHOD_DEFINITION_DOCUMENT 34 | }); 35 | cache.set(VerifiableConstants.AUTH.AUTH_BJJ_CREDENTIAL_SCHEMA_JSONLD_URL, { 36 | document: docIden3AuthBJJ, 37 | documentUrl: VerifiableConstants.AUTH.AUTH_BJJ_CREDENTIAL_SCHEMA_JSONLD 38 | }); 39 | 40 | return async (url: Url): Promise => { 41 | let remoteDoc = cache.get(url); 42 | if (remoteDoc) { 43 | return remoteDoc; 44 | } 45 | remoteDoc = await getDocumentLoader(opts)(url); 46 | cache.set(url, remoteDoc); 47 | return remoteDoc; 48 | }; 49 | }; 50 | -------------------------------------------------------------------------------- /src/schema-processor/jsonld/index.ts: -------------------------------------------------------------------------------- 1 | export * from './parser'; 2 | export * from './cache'; 3 | -------------------------------------------------------------------------------- /src/schema-processor/jsonld/parser.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | import * as jsonld from 'jsonld/lib'; 3 | import * as ldcontext from 'jsonld/lib/context'; 4 | 5 | /** 6 | * LDParser can parse JSONLD schema according to specification 7 | * 8 | * @public 9 | * @class LDParser 10 | */ 11 | export class LDParser { 12 | /** 13 | * ExtractTerms returns the terms definitions from the JSON-LD context 14 | * 15 | * @param {string} context - JSONLD context 16 | * @returns Promise> 17 | */ 18 | public static async extractTerms(context: string | JSON): Promise> { 19 | let data; 20 | let res; 21 | try { 22 | data = typeof context === 'string' ? JSON.parse(context) : context; 23 | res = await jsonld.processContext(ldcontext.getInitialContext({}), data, {}); 24 | } catch (e) { 25 | throw new Error(`Failed process LD context. Error ${e}`); 26 | } 27 | 28 | const terms = res.mappings; 29 | return terms; 30 | } 31 | 32 | /** 33 | * GetPrefixes returns a map of potential RDF prefixes based on the JSON-LD Term Definitions 34 | * in this context. No guarantees of the prefixes are given, beyond that it will not contain ":". 35 | * 36 | * onlyCommonPrefixes: If true, the result will not include "not so useful" prefixes, such as 37 | * "term1": "http://example.com/term1", e.g. all IRIs will end with "/" or "#". 38 | * If false, all potential prefixes are returned. 39 | * @param {string | JSON} context - JSONLD context 40 | * @param {boolean} onlyCommonPrefixes - only common prefixes 41 | * @param {Array} properties - available properties in type definition 42 | * @returns Promise<> 43 | */ 44 | public static async getPrefixes( 45 | context: string | JSON, 46 | onlyCommonPrefixes: boolean, 47 | properties?: Array 48 | ): Promise> { 49 | const prefixes: Map = new Map(); 50 | const data = await this.extractTerms(context); 51 | 52 | for (const [term, termDefinition] of data) { 53 | if (term.includes(':')) { 54 | continue; 55 | } 56 | if (!termDefinition) { 57 | continue; 58 | } 59 | const termDefinitionMap = termDefinition as Record; 60 | const id = termDefinitionMap['@id'] as string; 61 | if (!id) { 62 | continue; 63 | } 64 | if (term.startsWith('@') || id.startsWith('@')) { 65 | continue; 66 | } 67 | if (!onlyCommonPrefixes || id.endsWith('/') || id.endsWith('#')) { 68 | prefixes.set(term, id); 69 | } 70 | 71 | if (properties) { 72 | const c = termDefinitionMap['@context'] as Record; 73 | if (!c) { 74 | prefixes.delete(term); 75 | continue; 76 | } 77 | if (!this.isKeysInMap(properties, c)) { 78 | prefixes.delete(term); 79 | continue; 80 | } 81 | } 82 | } 83 | 84 | return prefixes; 85 | } 86 | 87 | private static isKeysInMap(keys: string[], rec: Record): boolean { 88 | for (const key of keys) { 89 | if (!rec[key]) { 90 | return false; 91 | } 92 | } 93 | return true; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/schema-processor/utils.ts: -------------------------------------------------------------------------------- 1 | import { BytesHelper, checkBigIntInField, SchemaHash } from '@iden3/js-iden3-core'; 2 | import { Merklizer } from '@iden3/js-jsonld-merklization'; 3 | import { calculateCoreSchemaHash, fillCoreClaimSlot } from '../verifiable'; 4 | 5 | /** 6 | * SwapEndianness swaps the endianness of the value encoded in buf. If buf is 7 | * Big-Endian, the result will be Little-Endian and vice-versa. 8 | * 9 | * @param {Uint8Array} buf - bytes to swap 10 | * @returns Uint8Array - swapped bytes 11 | */ 12 | export const swapEndianness = (buf: Uint8Array): Uint8Array => buf.reverse(); 13 | 14 | /** 15 | * FieldToByteArray convert fields to byte representation based on type 16 | * 17 | * @param {unknown} field - field to convert 18 | * @returns Uint8Array 19 | */ 20 | export function fieldToByteArray(field: unknown): Uint8Array { 21 | let bigIntField: bigint; 22 | 23 | if (typeof field === 'string') { 24 | bigIntField = BigInt(field); 25 | } else if (typeof field === 'number') { 26 | bigIntField = BigInt(Math.trunc(field)); 27 | } else { 28 | throw new Error('field type is not supported'); 29 | } 30 | return BytesHelper.intToBytes(bigIntField); 31 | } 32 | 33 | /** 34 | * checks if data fills into slot capacity () 35 | * 36 | * @param {Uint8Array} slot - current slot data 37 | * @param {Uint8Array} newData - new slot data 38 | * @returns boolean 39 | */ 40 | export function dataFillsSlot(slot: Uint8Array, newData: Uint8Array): boolean { 41 | return checkBigIntInField(BytesHelper.bytesToInt(Uint8Array.from([...slot, ...newData]))); 42 | } 43 | 44 | /** 45 | * check if byte data is in Q field 46 | * 47 | * @param {Uint8Array} data - bytes payload 48 | * @returns boolean 49 | */ 50 | export function checkDataInField(data: Uint8Array): boolean { 51 | return checkBigIntInField(BytesHelper.bytesToInt(data)); 52 | } 53 | 54 | /** 55 | * 56 | * @deprecated The method should not be used. Use calculateCoreSchemaHash from verifiable. 57 | * Calculates schema hash 58 | * 59 | * @param {Uint8Array} schemaId 60 | * @returns {*} {SchemaHash} 61 | */ 62 | export const createSchemaHash = (schemaId: Uint8Array): SchemaHash => { 63 | return calculateCoreSchemaHash(schemaId); 64 | }; 65 | 66 | /** 67 | * 68 | * @deprecated The method should not be used. Use fillCoreClaimSlot from verifiable. 69 | * checks if data can fill the slot 70 | * 71 | * @param {Uint8Array} slotData - slot data 72 | * @param {Merklizer} mz - merklizer 73 | * @param {string} path - path 74 | * @returns {void} 75 | */ 76 | export const fillSlot = async ( 77 | slotData: Uint8Array, 78 | mz: Merklizer, 79 | path: string 80 | ): Promise => { 81 | return fillCoreClaimSlot(slotData, mz, path); 82 | }; 83 | 84 | export const credentialSubjectKey = 'credentialSubject'; 85 | -------------------------------------------------------------------------------- /src/storage/blockchain/abi/CredentialStatusResolver.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[],"name":"MAX_SMT_DEPTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"key","type":"uint256"}],"name":"getNode","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"name":"getRevocationStatus","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"state","type":"uint256"},{"internalType":"uint256","name":"claimsTreeRoot","type":"uint256"},{"internalType":"uint256","name":"revocationTreeRoot","type":"uint256"},{"internalType":"uint256","name":"rootOfRoots","type":"uint256"}],"internalType":"struct IOnchainCredentialStatusResolver.IdentityStateRoots","name":"issuer","type":"tuple"},{"components":[{"internalType":"uint256","name":"root","type":"uint256"},{"internalType":"bool","name":"existence","type":"bool"},{"internalType":"uint256[]","name":"siblings","type":"uint256[]"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bool","name":"auxExistence","type":"bool"},{"internalType":"uint256","name":"auxIndex","type":"uint256"},{"internalType":"uint256","name":"auxValue","type":"uint256"}],"internalType":"struct IOnchainCredentialStatusResolver.Proof","name":"mtp","type":"tuple"}],"internalType":"struct IOnchainCredentialStatusResolver.CredentialStatus","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"state","type":"uint256"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"name":"getRevocationStatusByIdAndState","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"state","type":"uint256"},{"internalType":"uint256","name":"claimsTreeRoot","type":"uint256"},{"internalType":"uint256","name":"revocationTreeRoot","type":"uint256"},{"internalType":"uint256","name":"rootOfRoots","type":"uint256"}],"internalType":"struct IOnchainCredentialStatusResolver.IdentityStateRoots","name":"issuer","type":"tuple"},{"components":[{"internalType":"uint256","name":"root","type":"uint256"},{"internalType":"bool","name":"existence","type":"bool"},{"internalType":"uint256[]","name":"siblings","type":"uint256[]"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bool","name":"auxExistence","type":"bool"},{"internalType":"uint256","name":"auxIndex","type":"uint256"},{"internalType":"uint256","name":"auxValue","type":"uint256"}],"internalType":"struct IOnchainCredentialStatusResolver.Proof","name":"mtp","type":"tuple"}],"internalType":"struct IOnchainCredentialStatusResolver.CredentialStatus","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[][]","name":"nodes","type":"uint256[][]"}],"name":"saveNodes","outputs":[],"stateMutability":"nonpayable","type":"function"}] 2 | -------------------------------------------------------------------------------- /src/storage/blockchain/abi/ERC20.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"uint256","name":"initialSupply","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] -------------------------------------------------------------------------------- /src/storage/blockchain/common.ts: -------------------------------------------------------------------------------- 1 | import { ProofData } from '@iden3/js-jwz'; 2 | import { ethers } from 'ethers'; 3 | 4 | export const packZkpProof = (inputs: string[], a: string[], b: string[][], c: string[]): string => { 5 | return new ethers.AbiCoder().encode( 6 | ['uint256[] inputs', 'uint256[2]', 'uint256[2][2]', 'uint256[2]'], 7 | [inputs, a, b, c] 8 | ); 9 | }; 10 | 11 | export const prepareZkpProof = (proof: ProofData): { a: string[]; b: string[][]; c: string[] } => { 12 | return { 13 | a: proof.pi_a.slice(0, 2), 14 | b: [ 15 | [proof.pi_b[0][1], proof.pi_b[0][0]], 16 | [proof.pi_b[1][1], proof.pi_b[1][0]] 17 | ], 18 | c: proof.pi_c.slice(0, 2) 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /src/storage/blockchain/did-resolver-readonly-storage.ts: -------------------------------------------------------------------------------- 1 | import { Hash } from '@iden3/js-merkletree'; 2 | import { DIDDocument, VerificationMethod } from '../../iden3comm'; 3 | import { resolveDidDocument } from '../../utils'; 4 | import { RootInfo, StateInfo, StateProof } from '../entities'; 5 | import { IStateStorage } from '../interfaces'; 6 | import { DID, Id } from '@iden3/js-iden3-core'; 7 | import { JsonRpcProvider } from 'ethers'; 8 | 9 | export class DidResolverStateReadonlyStorage implements IStateStorage { 10 | constructor(private readonly resolverUrl: string) {} 11 | async getLatestStateById(id: bigint): Promise { 12 | return this.getStateInfo(id); 13 | } 14 | async getStateInfoByIdAndState(id: bigint, state: bigint): Promise { 15 | return this.getStateInfo(id, state); 16 | } 17 | 18 | async getGISTProof(id: bigint): Promise { 19 | const { didDocument } = await resolveDidDocument( 20 | DID.parseFromId(Id.fromBigInt(id)), 21 | this.resolverUrl 22 | ); 23 | const { global } = this.getIden3StateInfo2023(didDocument); 24 | if (!global) { 25 | throw new Error('GIST root not found'); 26 | } 27 | const { proof } = global; 28 | if (!proof) { 29 | throw new Error('GIST proof not found'); 30 | } 31 | return { 32 | root: global.root, 33 | existence: proof.existence, 34 | siblings: proof.siblings?.map((sibling) => BigInt(sibling)), 35 | index: BigInt(0), 36 | value: BigInt(0), 37 | auxExistence: !!proof.node_aux, 38 | auxIndex: proof.node_aux ? BigInt(proof.node_aux.key) : BigInt(0), 39 | auxValue: proof.node_aux ? BigInt(proof.node_aux.value) : BigInt(0) 40 | }; 41 | } 42 | 43 | async getGISTRootInfo(root: bigint, userId: bigint): Promise { 44 | const { didDocument } = await resolveDidDocument( 45 | DID.parseFromId(Id.fromBigInt(userId)), 46 | this.resolverUrl, 47 | { 48 | gist: Hash.fromBigInt(root) 49 | } 50 | ); 51 | const { global } = this.getIden3StateInfo2023(didDocument); 52 | if (!global) { 53 | throw new Error('GIST root not found'); 54 | } 55 | return global; 56 | } 57 | 58 | getRpcProvider(): JsonRpcProvider { 59 | return new JsonRpcProvider(); 60 | } 61 | 62 | publishState(): Promise { 63 | throw new Error('publishState method not implemented.'); 64 | } 65 | 66 | publishStateGeneric(): Promise { 67 | throw new Error('publishStateGeneric method not implemented.'); 68 | } 69 | 70 | private async getStateInfo(id: bigint, state?: bigint): Promise { 71 | const opts = state ? { state: Hash.fromBigInt(state) } : undefined; 72 | const { didDocument } = await resolveDidDocument( 73 | DID.parseFromId(Id.fromBigInt(id)), 74 | this.resolverUrl, 75 | opts 76 | ); 77 | const { info } = this.getIden3StateInfo2023(didDocument); 78 | return { ...info }; 79 | } 80 | 81 | private getIden3StateInfo2023(didDocument: DIDDocument): VerificationMethod { 82 | const vm: VerificationMethod | undefined = didDocument.verificationMethod?.find( 83 | (i: VerificationMethod) => i.type === 'Iden3StateInfo2023' 84 | ); 85 | if (!vm) { 86 | throw new Error('Iden3StateInfo2023 verification method not found'); 87 | } 88 | return vm; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/storage/blockchain/erc20-helper.ts: -------------------------------------------------------------------------------- 1 | import { Contract, Signer, ethers } from 'ethers'; 2 | 3 | import permitAbi from './abi/ERC20Permit.json'; 4 | import erc20Abi from './abi/ERC20.json'; 5 | 6 | /** 7 | * @beta 8 | * getPermitSignature is a function to create EIP712 Permit signature 9 | * @param {Signer} signer - User who owns the tokens 10 | * @param {string} tokenAddress - EIP-2612 contract address 11 | * @param {string} spender - The contract address that will spend tokens 12 | * @param {bigint} value - Amount of tokens to approve 13 | * @param {number} deadline - Timestamp when the permit expires 14 | * @returns {Promise} 15 | */ 16 | export async function getPermitSignature( 17 | signer: Signer, 18 | tokenAddress: string, 19 | spender: string, 20 | value: bigint, 21 | deadline: number 22 | ) { 23 | const erc20PermitContract = new Contract(tokenAddress, permitAbi, signer); 24 | const nonce = await erc20PermitContract.nonces(await signer.getAddress()); 25 | const domainData = await erc20PermitContract.eip712Domain(); 26 | const domain = { 27 | name: domainData[1], 28 | version: domainData[2], 29 | chainId: domainData[3], 30 | verifyingContract: tokenAddress 31 | }; 32 | 33 | const types = { 34 | Permit: [ 35 | { name: 'owner', type: 'address' }, 36 | { name: 'spender', type: 'address' }, 37 | { name: 'value', type: 'uint256' }, 38 | { name: 'nonce', type: 'uint256' }, 39 | { name: 'deadline', type: 'uint256' } 40 | ] 41 | }; 42 | 43 | const message = { 44 | owner: await signer.getAddress(), 45 | spender: spender, 46 | value: value, 47 | nonce: nonce, 48 | deadline: deadline 49 | }; 50 | 51 | return signer.signTypedData(domain, types, message); 52 | } 53 | 54 | /** 55 | * @beta 56 | * getERC20Decimals is a function to retrieve the number of decimals of an ERC20 token 57 | * @param {string} tokenAddress - Token address 58 | * @param {ethers.ContractRunner} runner - Contract runner 59 | */ 60 | export async function getERC20Decimals( 61 | tokenAddress: string, 62 | runner: ethers.ContractRunner 63 | ): Promise { 64 | const erc20Contract = new Contract(tokenAddress, erc20Abi, runner); 65 | return erc20Contract.decimals(); 66 | } 67 | -------------------------------------------------------------------------------- /src/storage/blockchain/index.ts: -------------------------------------------------------------------------------- 1 | export * from './state'; 2 | export * from './onchain-zkp-verifier'; 3 | export * from './onchain-revocation'; 4 | export * from './onchain-issuer'; 5 | export * from './did-resolver-readonly-storage'; 6 | export * from './erc20-helper'; 7 | -------------------------------------------------------------------------------- /src/storage/entities/circuitData.ts: -------------------------------------------------------------------------------- 1 | /** Circuit data that includes id, wasm file, verification key and proving key */ 2 | export type CircuitData = { 3 | circuitId: string; 4 | wasm: Uint8Array | null; 5 | verificationKey: Uint8Array | null; 6 | provingKey: Uint8Array | null; 7 | }; 8 | -------------------------------------------------------------------------------- /src/storage/entities/identity.ts: -------------------------------------------------------------------------------- 1 | import { Hash } from '@iden3/js-merkletree'; 2 | 3 | /** Identity structure that can be used for identity storage */ 4 | export type Identity = { 5 | did: string; 6 | state?: Hash; 7 | isStatePublished?: boolean; 8 | isStateGenesis?: boolean; 9 | }; 10 | 11 | /** Profile structure that can be used for profiles storage */ 12 | export type Profile = { 13 | id: string; 14 | nonce: number | string; 15 | genesisIdentifier: string; 16 | verifier: string; 17 | }; 18 | -------------------------------------------------------------------------------- /src/storage/entities/index.ts: -------------------------------------------------------------------------------- 1 | export * from './identity'; 2 | export * from './mt'; 3 | export * from './state'; 4 | export * from './circuitData'; 5 | -------------------------------------------------------------------------------- /src/storage/entities/mt.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Interface to store metadata about merkle tree 3 | * 4 | * @public 5 | * @interface IdentityMerkleTreeMetaInformation 6 | */ 7 | export interface IdentityMerkleTreeMetaInformation { 8 | treeId: string; 9 | identifier: string; 10 | type: MerkleTreeType; 11 | } 12 | 13 | /** 14 | * Type of MerkleTree 15 | * 16 | * @enum {number} 17 | */ 18 | export enum MerkleTreeType { 19 | // Claims is merkle tree type for claims tree 20 | Claims = 0, 21 | // Revocations is merkle tree type for revocations tree 22 | Revocations = 1, 23 | // Roots is merkle tree type for roots tree 24 | Roots = 2 25 | } 26 | -------------------------------------------------------------------------------- /src/storage/entities/state.ts: -------------------------------------------------------------------------------- 1 | import { ProofJSON } from '@iden3/js-merkletree'; 2 | /** 3 | * state information of identity from chain. 4 | * 5 | * @public 6 | * @interface StateInfo 7 | */ 8 | export interface StateInfo { 9 | id?: bigint; 10 | state?: bigint; 11 | replacedByState?: bigint; 12 | createdAtTimestamp?: bigint; 13 | replacedAtTimestamp?: bigint; 14 | createdAtBlock?: bigint; 15 | replacedAtBlock?: bigint; 16 | } 17 | 18 | /** 19 | * state proof of identity from chain 20 | * 21 | * @public 22 | * @interface StateProof 23 | */ 24 | export interface StateProof { 25 | root: bigint; 26 | existence: boolean; 27 | siblings: bigint[]; 28 | index: bigint; 29 | value: bigint; 30 | auxExistence: boolean; 31 | auxIndex: bigint; 32 | auxValue: bigint; 33 | } 34 | 35 | /** 36 | * global identity state root info from chain 37 | * 38 | * @public 39 | * @interface RootInfo 40 | */ 41 | export interface RootInfo { 42 | root: bigint; 43 | replacedByRoot: bigint; 44 | createdAtTimestamp: bigint; 45 | replacedAtTimestamp: bigint; 46 | createdAtBlock: bigint; 47 | replacedAtBlock: bigint; 48 | proof?: ProofJSON; 49 | } 50 | 51 | /** 52 | * identity state message 53 | * 54 | * @public 55 | * @interface IdentityStateMsg 56 | */ 57 | export interface IdentityStateMsg { 58 | timestamp: number; 59 | id: bigint; 60 | state: bigint; 61 | replacedAtTimestamp: number; 62 | } 63 | 64 | /** 65 | * global state message 66 | * 67 | * @public 68 | * @interface GlobalStateMsg 69 | */ 70 | export interface GlobalStateMsg { 71 | timestamp: number; 72 | idType: string; 73 | root: bigint; 74 | replacedAtTimestamp: number; 75 | } 76 | 77 | /** 78 | * identity state update 79 | * 80 | * @public 81 | * @interface IdentityStateUpdate 82 | */ 83 | export interface IdentityStateUpdate { 84 | idStateMsg: IdentityStateMsg; 85 | signature: string; 86 | } 87 | 88 | /** 89 | * global state update 90 | * 91 | * @public 92 | * @interface GlobalStateUpdate 93 | */ 94 | export interface GlobalStateUpdate { 95 | globalStateMsg: GlobalStateMsg; 96 | signature: string; 97 | } 98 | -------------------------------------------------------------------------------- /src/storage/errors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Storage Errors definition 3 | * 4 | * @enum {number} 5 | */ 6 | export enum StorageErrors { 7 | ItemNotFound = 'item not found' 8 | } 9 | -------------------------------------------------------------------------------- /src/storage/filters/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jsonQuery'; 2 | -------------------------------------------------------------------------------- /src/storage/fs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './circuits-storage'; 2 | -------------------------------------------------------------------------------- /src/storage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './interfaces'; 2 | export * from './blockchain'; 3 | export * from './entities'; 4 | export * from './filters'; 5 | export * from './memory'; 6 | export * from './local-storage'; 7 | export * from './indexed-db'; 8 | export * from './shared'; 9 | export * from './fs'; 10 | -------------------------------------------------------------------------------- /src/storage/indexed-db/data-source.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | import { IDataSource } from '../interfaces/data-source'; 3 | import { set, get, del, values, createStore, UseStore } from 'idb-keyval'; 4 | 5 | /** 6 | * Storage in the browser, uses indexed db storage 7 | * 8 | * @public 9 | * @class IndexedDBDataSource 10 | * @template Type 11 | */ 12 | export class IndexedDBDataSource implements IDataSource { 13 | /** 14 | * Creates an instance of IndexedDBDataSource. 15 | * 16 | * @param {string} _storageKey - key string to put storage name 17 | */ 18 | private readonly _store: UseStore; 19 | constructor(private _storageKey: string) { 20 | this._store = createStore(`${_storageKey}-db`, _storageKey); 21 | } 22 | 23 | /** 24 | * Saves value to the indexed db storage 25 | * 26 | * @param {string} key - key value 27 | * @param {Type} value - value to store 28 | * @param {string} [keyName='id'] - key name 29 | */ 30 | async save(key: string, value: Type, keyName = 'id'): Promise { 31 | return set(key, value, this._store); 32 | } 33 | 34 | /** 35 | * Gets value from the indexed db storage by given key 36 | * 37 | * @param {string} key - key value 38 | * @param {string} [keyName='id'] - key name 39 | */ 40 | async get(key: string, keyName = 'id'): Promise { 41 | return get(key, this._store); 42 | } 43 | 44 | /** 45 | * loads all from the indexed db storage 46 | */ 47 | async load(): Promise { 48 | return values(this._store); 49 | } 50 | /** 51 | * deletes item from the indexed db storage 52 | * @param {string} key - key value 53 | * @param {string} [keyName='id'] - key name 54 | */ 55 | async delete(key: string, keyName = 'id'): Promise { 56 | return del(key, this._store); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/storage/indexed-db/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-source'; 2 | export * from './merkletree'; 3 | -------------------------------------------------------------------------------- /src/storage/interfaces/circuits.ts: -------------------------------------------------------------------------------- 1 | import { CircuitId } from '../../circuits'; 2 | import { CircuitData } from '../entities/circuitData'; 3 | 4 | /** 5 | * Interface to work with circuit files 6 | * 7 | * @public 8 | * @interface ICircuitStorage 9 | */ 10 | export interface ICircuitStorage { 11 | /** 12 | * load circuit keys by id 13 | * 14 | * @param {CircuitId} circuitId - circuit id 15 | * @returns `{Promise}` 16 | */ 17 | loadCircuitData(circuitId: CircuitId): Promise; 18 | 19 | /** 20 | * saves circuit files by circuit id 21 | * 22 | * @param {CircuitId} circuitId - circuit id 23 | * @param {CircuitData} circuitData - circuit keys 24 | * @returns `Promise` 25 | */ 26 | saveCircuitData(circuitId: CircuitId, circuitData: CircuitData): Promise; 27 | } 28 | -------------------------------------------------------------------------------- /src/storage/interfaces/credentials.ts: -------------------------------------------------------------------------------- 1 | import { ProofQuery, W3CCredential } from '../../verifiable'; 2 | 3 | /** 4 | * Interface for credential storages 5 | * 6 | * @public 7 | * @interface ICredentialStorage 8 | */ 9 | export interface ICredentialStorage { 10 | /** 11 | * 12 | * save credential to the storage 13 | * 14 | * @param {W3CCredential} credential - credential to save 15 | * @returns `{Promise}` 16 | */ 17 | saveCredential(credential: W3CCredential): Promise; 18 | /** 19 | * 20 | * save all credential (upsert) to the storage 21 | * 22 | * @param {W3CCredential[]} credentials - credentials to save 23 | * @returns `Promise` 24 | */ 25 | saveAllCredentials(credentials: W3CCredential[]): Promise; 26 | /** 27 | * returns all credentials in the storage 28 | * 29 | * @returns `Promise` 30 | */ 31 | listCredentials(): Promise; 32 | /** 33 | * Removes credential from storage 34 | * 35 | * @param {string} id - id of credential 36 | * @returns `Promise` 37 | */ 38 | removeCredential(id: string): Promise; 39 | /** 40 | * finds credential in the storage for given query 41 | * 42 | * @param {ProofQuery} query - query to apply 43 | * @returns `{Promise}` 44 | */ 45 | findCredentialsByQuery(query: ProofQuery): Promise; 46 | /** 47 | * finds credential by identifier 48 | * 49 | * @param {string} id - id of credential 50 | * @returns `{(Promise)}` 51 | */ 52 | findCredentialById(id: string): Promise; 53 | } 54 | -------------------------------------------------------------------------------- /src/storage/interfaces/data-source.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Generic Key/Value Data Source for crud operation 3 | * 4 | * @public 5 | * @interface IDataSource 6 | * @template Type - generic type 7 | */ 8 | export interface IDataSource { 9 | /** 10 | * load all object with Type from data source 11 | * 12 | * @returns `{Type[]}` 13 | */ 14 | load(): Promise; 15 | 16 | /** 17 | * Save value under the key with optional key name 18 | * 19 | * @param {string} key - key value 20 | * @param {Type} value - value to store 21 | * @param {string} [keyName] - key name 22 | */ 23 | save(key: string, value: Type, keyName?: string): Promise; 24 | 25 | /** 26 | * returns data value for key value and optional key name 27 | * 28 | * @param {string} key - key value 29 | * @param {string} [keyName] - key name 30 | * @returns ` {(Type | undefined)}` 31 | */ 32 | get(key: string, keyName?: string): Promise; 33 | 34 | /** 35 | * deletes data value for given key with an optional key name 36 | * 37 | * @param {string} key - key value 38 | * @param {string} [keyName] - key name 39 | */ 40 | delete(key: string, keyName?: string): Promise; 41 | } 42 | -------------------------------------------------------------------------------- /src/storage/interfaces/data-storage.ts: -------------------------------------------------------------------------------- 1 | import { ICredentialStorage } from './credentials'; 2 | import { IIdentityStorage } from './identity'; 3 | import { IMerkleTreeStorage } from './merkletree'; 4 | import { IStateStorage } from './state'; 5 | 6 | /** 7 | * General Data storage interface that union identity, credential, merkletree and states storage. 8 | * 9 | * @public 10 | * @interface IDataStorage 11 | */ 12 | export interface IDataStorage { 13 | credential: ICredentialStorage; 14 | identity: IIdentityStorage; 15 | mt: IMerkleTreeStorage; 16 | states: IStateStorage; 17 | } 18 | -------------------------------------------------------------------------------- /src/storage/interfaces/identity.ts: -------------------------------------------------------------------------------- 1 | import { Identity } from '../entities'; 2 | import { Profile } from '../entities'; 3 | 4 | /** 5 | * storage for identities and profiles 6 | * 7 | * @public 8 | * @interface IIdentityStorage 9 | */ 10 | export interface IIdentityStorage { 11 | /** 12 | * saves identity to the data source 13 | * 14 | * @param {Identity} identity 15 | * @returns `{Promise}` 16 | */ 17 | saveIdentity(identity: Identity): Promise; 18 | /** 19 | * gets identity from the the data source 20 | * 21 | * 22 | * @param {string} identifier - id of identity 23 | * @returns `{(Promise)}` 24 | */ 25 | getIdentity(identifier: string): Promise; 26 | /** 27 | * 28 | * gets all identity from the data source 29 | * 30 | * @returns `{Promise}` 31 | */ 32 | getAllIdentities(): Promise; 33 | 34 | /** 35 | * 36 | * saves profile identity to data 37 | * 38 | * @param {Profile} profile - identity profile 39 | * @returns `{Promise}` 40 | */ 41 | saveProfile(profile: Profile): Promise; 42 | /** 43 | * gets profile by verifier 44 | * 45 | * @param {string} verifier - verifier to which profile has been shared 46 | * @returns `{Promise}` 47 | */ 48 | getProfileByVerifier(verifier: string): Promise; 49 | /** 50 | * gets profile by identifier 51 | * 52 | * @param {string} identifier - profile id 53 | * @returns `{Promise}` 54 | */ 55 | getProfileById(identifier: string): Promise; 56 | /** 57 | * 58 | * gets profile identity by genesis identifiers 59 | * 60 | * @param {string} genesisIdentifier - genesis identifier from which profile has been derived 61 | * @returns `{Promise}` 62 | */ 63 | getProfilesByGenesisIdentifier(genesisIdentifier: string): Promise; 64 | } 65 | -------------------------------------------------------------------------------- /src/storage/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './credentials'; 2 | export * from './identity'; 3 | export * from './merkletree'; 4 | export * from './state'; 5 | export * from './data-storage'; 6 | export * from './data-source'; 7 | export * from './circuits'; 8 | export * from './onchain-zkp-verifier'; 9 | export * from './onchain-revocation'; 10 | export * from './onchain-issuer'; 11 | -------------------------------------------------------------------------------- /src/storage/interfaces/merkletree.ts: -------------------------------------------------------------------------------- 1 | import { Merkletree } from '@iden3/js-merkletree'; 2 | import { IdentityMerkleTreeMetaInformation, MerkleTreeType } from '../entities/mt'; 3 | 4 | /** 5 | * Interface to work with a merkle tree storage 6 | * 7 | * @public 8 | * @interface IMerkleTreeStorage 9 | */ 10 | export interface IMerkleTreeStorage { 11 | /** 12 | * creates merkle tree in the storage 13 | * 14 | * @param {string} identifier 15 | * @returns `Promise` 16 | */ 17 | createIdentityMerkleTrees(identifier: string): Promise; 18 | 19 | /** 20 | * adds entry to merkle tree 21 | * 22 | * @param {string} identifier - identifier to which tree belongs 23 | * @param {MerkleTreeType} mtType - merkle tree type 24 | * @param {bigint} hindex - hash index 25 | * @param {bigint} hvalue - hash value 26 | * @returns `Promise` 27 | */ 28 | addToMerkleTree( 29 | identifier: string, 30 | mtType: MerkleTreeType, 31 | hindex: bigint, 32 | hvalue: bigint 33 | ): Promise; 34 | 35 | /** 36 | * gets merkle tree by identifier and type 37 | * 38 | * @param {string} identifier - identifier for tree 39 | * @param {MerkleTreeType} mtType - merkle tree type 40 | * @returns `{Promise}` 41 | */ 42 | getMerkleTreeByIdentifierAndType(identifier: string, mtType: MerkleTreeType): Promise; 43 | 44 | /** 45 | * binding to be able to update identifier that belongs to tree 46 | * 47 | * @param {string} oldIdentifier - 48 | * @param {string} newIdentifier - 49 | * @returns `{Promise}` 50 | */ 51 | bindMerkleTreeToNewIdentifier(oldIdentifier: string, newIdentifier: string): Promise; 52 | } 53 | -------------------------------------------------------------------------------- /src/storage/interfaces/onchain-issuer.ts: -------------------------------------------------------------------------------- 1 | import { DID } from '@iden3/js-iden3-core'; 2 | import { W3CCredential } from '../../verifiable'; 3 | 4 | /** 5 | * Interface that allows the processing of the on-chain issuer 6 | * 7 | * @beta 8 | * @interface IOnchainIssuer 9 | */ 10 | export interface IOnchainIssuer { 11 | getCredential(issuerDID: DID, userDID: DID, credentialId: bigint): Promise; 12 | getUserCredentialIds(issuerDID: DID, userDID: DID): Promise; 13 | } 14 | -------------------------------------------------------------------------------- /src/storage/interfaces/onchain-revocation.ts: -------------------------------------------------------------------------------- 1 | import { RevocationStatus } from '../../verifiable'; 2 | /** 3 | * Interface that defines methods for onchain revocation store 4 | * 5 | * @public 6 | * @interface IOnchainRevocationStore 7 | */ 8 | export interface IOnchainRevocationStore { 9 | /** 10 | * gets latest state of identity 11 | * 12 | * @param {bigint} issuerID - issuer id 13 | * @param {bigint} state - issuer state 14 | * @param {number} nonce - revocation nonce 15 | * @returns `Promise` 16 | */ 17 | getRevocationStatusByIdAndState( 18 | issuerID: bigint, 19 | state: bigint, 20 | nonce: number 21 | ): Promise; 22 | } 23 | -------------------------------------------------------------------------------- /src/storage/interfaces/onchain-zkp-verifier.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers'; 2 | import { 3 | AuthProof, 4 | ContractInvokeTransactionData, 5 | JsonDocumentObjectValue, 6 | ZeroKnowledgeInvokeResponse, 7 | ZeroKnowledgeProofResponse 8 | } from '../../iden3comm'; 9 | import { TxPreparationResultSubmitResponse } from '../blockchain/onchain-zkp-verifier'; 10 | 11 | /** 12 | * Interface that defines methods for ZKP verifier 13 | * 14 | * @beta 15 | * @interface IOnChainZKPVerifier 16 | */ 17 | export interface IOnChainZKPVerifier { 18 | /** 19 | * Submit ZKP Responses to OnChainZKPVerifier contract. 20 | * @beta 21 | * @param {Signer} ethSigner - tx signer 22 | * @param {txData} ContractInvokeTransactionData - transaction data 23 | * @param {ZeroKnowledgeProofResponse[]} zkProofResponses - zkProofResponses 24 | * @returns {Promise>} - map of transaction hash - ZeroKnowledgeProofResponse 25 | */ 26 | submitZKPResponse( 27 | ethSigner: Signer, 28 | txData: ContractInvokeTransactionData, 29 | zkProofResponses: ZeroKnowledgeProofResponse[] 30 | ): Promise>; 31 | 32 | /** 33 | * Submit ZKP Response V2 to OnChainZKPVerifier contract. 34 | * @beta 35 | * @param {Signer} ethSigner - tx signer 36 | * @param {txData} ContractInvokeTransactionData - transaction data 37 | * @param {ZeroKnowledgeProofResponse[]} zkProofResponses - zkProofResponses 38 | * @returns {Promise>} - map of transaction hash - ZeroKnowledgeProofResponse[] 39 | */ 40 | submitZKPResponseV2( 41 | ethSigner: Signer, 42 | txData: ContractInvokeTransactionData, 43 | zkProofResponses: ZeroKnowledgeProofResponse[] 44 | ): Promise>; 45 | 46 | /** 47 | * Submit Response to OnChainZKPVerifier contract. 48 | * @beta 49 | * @param {Signer} ethSigner - tx signer 50 | * @param {txData} ContractInvokeTransactionData - transaction data 51 | * @param {AuthProofResponse} authResponse - authResponse 52 | * @param {ZeroKnowledgeProofMultiQueryResponse[]} responses - singleResponses and groupedResponses 53 | * @param {ZeroKnowledgeProofAuthResponse} [authProof] - authProof in case of authV2 54 | * @returns {Promise>} - map of transaction hash - ZeroKnowledgeInvokeResponse 55 | */ 56 | submitResponse( 57 | ethSigner: Signer, 58 | txData: ContractInvokeTransactionData, 59 | responses: ZeroKnowledgeProofResponse[], 60 | authProof: AuthProof 61 | ): Promise>; 62 | 63 | /** 64 | * Returns tx args for the ZKP verifier contract submission (singe tx args for each response). 65 | * @param txData 66 | * @param zkProofResponse 67 | */ 68 | prepareTxArgsSubmitV1( 69 | txData: ContractInvokeTransactionData, 70 | zkProofResponse: ZeroKnowledgeProofResponse 71 | ): Promise; 72 | 73 | /** 74 | * Returns args for the ZKP verifier contract submission V2 (single tx args for an array of responses). 75 | * @param txData 76 | * @param zkProofResponses 77 | */ 78 | prepareTxArgsSubmitV2( 79 | txData: ContractInvokeTransactionData, 80 | zkProofResponses: ZeroKnowledgeProofResponse[] 81 | ): Promise; 82 | 83 | /** 84 | * Returns args for the verifier multi-query contract submission (single tx args for an array of responses). 85 | * @param {txData} ContractInvokeTransactionData - transaction data 86 | * @param {authProof} AuthProof - AuthProof 87 | * @param {ZeroKnowledgeProofMultiQueryResponse[]} responses - singleResponses and groupedResponses 88 | */ 89 | prepareTxArgsSubmit( 90 | txData: ContractInvokeTransactionData, 91 | responses: ZeroKnowledgeProofResponse[], 92 | authProof: AuthProof 93 | ): Promise<{ result: TxPreparationResultSubmitResponse; txDataArgs: JsonDocumentObjectValue[] }>; 94 | } 95 | -------------------------------------------------------------------------------- /src/storage/interfaces/state.ts: -------------------------------------------------------------------------------- 1 | import { ZKProof } from '@iden3/js-jwz'; 2 | import { JsonRpcProvider, Signer } from 'ethers'; 3 | import { RootInfo, StateInfo, StateProof } from '../entities/state'; 4 | import { Id } from '@iden3/js-iden3-core'; 5 | import { Hash } from '@iden3/js-merkletree'; 6 | 7 | export interface UserStateTransitionInfo { 8 | userId: Id; // Identity id 9 | oldUserState: Hash; // Previous identity state 10 | newUserState: Hash; // New identity state 11 | isOldStateGenesis: boolean; // Is the previous state genesis? 12 | methodId: bigint; // State transition method id 13 | methodParams: string; // State transition method-specific params 14 | } 15 | 16 | /** 17 | * Interface that defines methods for state storage 18 | * 19 | * @public 20 | * @interface IStateStorage 21 | */ 22 | export interface IStateStorage { 23 | /** 24 | * gets latest state of identity 25 | * 26 | * @param {bigint} id - id to check 27 | * @returns `Promise` 28 | */ 29 | getLatestStateById(id: bigint): Promise; 30 | 31 | /** 32 | * gets state info of identity by id and state 33 | * 34 | * @param {bigint} id - id to check 35 | * @param {bigint} state - state to check 36 | * @returns `Promise` 37 | */ 38 | getStateInfoByIdAndState(id: bigint, state: bigint): Promise; 39 | /** 40 | * method to publish state onchain 41 | * 42 | * @param {ZKProof} proof - proof to publish 43 | * @param {Signer} signer - signer of transaction 44 | * @returns `Promise` - transaction identifier 45 | */ 46 | publishState(proof: ZKProof | undefined, signer: Signer): Promise; 47 | /** 48 | * method to publish state onchain 49 | * 50 | * @param {Signer} signer - signer of transaction 51 | * @param {UserStateTransitionInfo} userStateTransitionInfo - user state transition information 52 | * @returns `Promise` - transaction identifier 53 | */ 54 | publishStateGeneric( 55 | signer: Signer, 56 | userStateTransitionInfo?: UserStateTransitionInfo 57 | ): Promise; 58 | /** 59 | * generates proof of inclusion / non-inclusion to global identity state for given identity 60 | * 61 | * @param {bigint} id - id to check 62 | * @returns `Promise` 63 | */ 64 | getGISTProof(id: bigint): Promise; 65 | 66 | /** 67 | * gets root info of global identity state tree 68 | * 69 | * @param {bigint} root - root to check 70 | * @param {bigint} userId - user id 71 | * @returns `Promise` 72 | */ 73 | getGISTRootInfo(root: bigint, userId: bigint): Promise; 74 | 75 | /** 76 | * gets RPC provider 77 | * 78 | * @returns `Promise` 79 | */ 80 | getRpcProvider(): JsonRpcProvider; 81 | } 82 | -------------------------------------------------------------------------------- /src/storage/local-storage/data-source.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import { StorageErrors } from '../errors'; 3 | import { IDataSource } from '../interfaces/data-source'; 4 | 5 | /** 6 | * Storage in the browser, uses local storage 7 | * 8 | * @public 9 | * @class BrowserDataSource 10 | * @template Type 11 | */ 12 | export class BrowserDataSource implements IDataSource { 13 | /** 14 | * Creates an instance of BrowserDataSource. 15 | * @param {string} _localStorageKey - key string to put storage name in the local storage 16 | */ 17 | constructor(private _localStorageKey: string) { 18 | const data = localStorage.getItem(this._localStorageKey); 19 | if (!data) { 20 | localStorage.setItem(_localStorageKey, JSON.stringify([])); 21 | } 22 | } 23 | 24 | /** 25 | * 26 | * saves value to the local storage 27 | * @param {string} key - key value 28 | * @param {Type} value - value to store 29 | * @param {string} [keyName='id'] - key name 30 | */ 31 | async save(key: string, value: Type, keyName = 'id'): Promise { 32 | if (localStorage) { 33 | const data = localStorage.getItem(this._localStorageKey); 34 | let items: Type[] = []; 35 | if (data) { 36 | items = JSON.parse(data) as Type[]; 37 | } 38 | const itemIndex = items.findIndex((i: any): boolean => i[keyName] === key); 39 | if (itemIndex === -1) { 40 | items.push(value); 41 | } else { 42 | items[itemIndex] = value; 43 | } 44 | localStorage.setItem(this._localStorageKey, JSON.stringify(items)); 45 | } 46 | } 47 | 48 | /** 49 | * gets value from the local storage by given key 50 | * @param {string} key - key value 51 | * @param {string} [keyName='id'] - key name 52 | */ 53 | 54 | async get(key: string, keyName = 'id'): Promise { 55 | const data = localStorage.getItem(this._localStorageKey); 56 | let parsedData: Type[] = []; 57 | if (data) { 58 | parsedData = JSON.parse(data) as Type[]; 59 | } 60 | return parsedData.find((t: any) => t[keyName] === key); 61 | } 62 | 63 | /** 64 | * loads all from the local storage 65 | */ 66 | async load(): Promise { 67 | const data = localStorage.getItem(this._localStorageKey); 68 | return data && JSON.parse(data); 69 | } 70 | /** 71 | * deletes item from the local storage 72 | * @param {string} key - key value 73 | * @param {string} [keyName='id'] - key name 74 | */ 75 | async delete(key: string, keyName = 'id'): Promise { 76 | const dataStr = localStorage.getItem(this._localStorageKey); 77 | let data: Type[] = []; 78 | if (dataStr) { 79 | data = JSON.parse(dataStr) as Type[]; 80 | } 81 | const items = data.filter((i: any) => i[keyName] !== key); 82 | if (data.length === items.length) { 83 | throw new Error(`${StorageErrors.ItemNotFound} to delete: ${key}`); 84 | } 85 | localStorage.setItem(this._localStorageKey, JSON.stringify(items)); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/storage/local-storage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-source'; 2 | export * from './merkletree'; 3 | -------------------------------------------------------------------------------- /src/storage/memory/data-source.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import { StorageErrors } from '../errors'; 3 | import { IDataSource } from '../interfaces/data-source'; 4 | 5 | /** 6 | * Generic Memory Data Source 7 | * 8 | * @public 9 | * @class InMemoryDataSource - class 10 | * @template Type 11 | */ 12 | export class InMemoryDataSource implements IDataSource { 13 | private _data: Type[] = []; 14 | 15 | /** saves in the memory */ 16 | async save(key: string, value: Type, keyName = 'id'): Promise { 17 | const itemIndex = this._data.findIndex((i: any) => i[keyName] === key); 18 | if (itemIndex === -1) { 19 | this._data.push(value); 20 | } else { 21 | this._data[itemIndex] = value; 22 | } 23 | } 24 | 25 | /** gets value from from the memory */ 26 | async get(key: string, keyName = 'id'): Promise { 27 | return this._data.find((t: any) => t[keyName] === key); 28 | } 29 | 30 | /** loads from value from the memory */ 31 | async load(): Promise { 32 | return this._data; 33 | } 34 | 35 | /** deletes from value from the memory */ 36 | async delete(key: string, keyName = 'id'): Promise { 37 | const newData = this._data.filter((i: any) => i[keyName] !== key); 38 | 39 | if (newData.length === this._data.length) { 40 | throw new Error(`${StorageErrors.ItemNotFound} to delete: ${key}`); 41 | } 42 | 43 | this._data = newData; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/storage/memory/index.ts: -------------------------------------------------------------------------------- 1 | export * from './merkletree'; 2 | export * from './data-source'; 3 | -------------------------------------------------------------------------------- /src/storage/memory/merkletree.ts: -------------------------------------------------------------------------------- 1 | import { InMemoryDB, Merkletree, str2Bytes } from '@iden3/js-merkletree'; 2 | import { IdentityMerkleTreeMetaInformation, MerkleTreeType } from '../entities/mt'; 3 | import * as uuid from 'uuid'; 4 | 5 | import { IMerkleTreeStorage } from '../interfaces/merkletree'; 6 | import { MERKLE_TREE_TYPES } from '../utils'; 7 | 8 | export interface TreeWithMetaInfo { 9 | tree: Merkletree; 10 | metaInfo: IdentityMerkleTreeMetaInformation; 11 | } 12 | 13 | /** 14 | * 15 | * 16 | * @public 17 | * @class InMemoryMerkleTreeStorage 18 | * @implements implements IMerkleTreeStorage interface 19 | */ 20 | export class InMemoryMerkleTreeStorage implements IMerkleTreeStorage { 21 | /** 22 | * key value storage for trees where key is identifier 23 | * 24 | * @type {{ 25 | * [v in string]: TreeWithMetaInfo[]; 26 | * }} 27 | */ 28 | _data: { 29 | [v in string]: TreeWithMetaInfo[]; 30 | }; 31 | /** 32 | * tree depth 33 | * 34 | * @type {number} 35 | */ 36 | mtDepth: number; 37 | /** 38 | * Creates an instance of InMemoryMerkleTreeStorage. 39 | * @param {number} _mtDepth 40 | */ 41 | constructor(_mtDepth: number) { 42 | this.mtDepth = _mtDepth; 43 | this._data = {}; 44 | } 45 | 46 | /** create trees in the memory*/ 47 | async createIdentityMerkleTrees( 48 | identifier: string 49 | ): Promise { 50 | if (!identifier) { 51 | identifier = `${uuid.v4()}`; 52 | } 53 | if (this._data[identifier]) { 54 | throw new Error( 55 | `Present merkle tree meta information in the store for current identifier ${identifier}` 56 | ); 57 | } 58 | this._data[identifier] = []; 59 | 60 | const treesMeta: IdentityMerkleTreeMetaInformation[] = []; 61 | MERKLE_TREE_TYPES.forEach((t) => { 62 | const treeId = identifier.concat('+' + t.toString()); 63 | const tree = new Merkletree(new InMemoryDB(str2Bytes(treeId)), true, this.mtDepth); 64 | 65 | const metaInfo = { treeId, identifier: identifier, type: t }; 66 | this._data[identifier].push({ tree, metaInfo }); 67 | 68 | treesMeta.push(metaInfo); 69 | }); 70 | return treesMeta; 71 | } 72 | 73 | /** get trees meta info from the memory */ 74 | async getIdentityMerkleTreesInfo( 75 | identifier: string 76 | ): Promise { 77 | return this._data[identifier].map((treeWithInfo) => treeWithInfo.metaInfo); 78 | } 79 | /** get merkle tree by identifier and type from memory */ 80 | async getMerkleTreeByIdentifierAndType( 81 | identifier: string, 82 | mtType: MerkleTreeType 83 | ): Promise { 84 | const treeWithMeta = this._data[identifier].find( 85 | (treeWithInfo) => treeWithInfo.metaInfo.type == mtType 86 | ); 87 | if (!treeWithMeta) { 88 | throw new Error(`Merkle tree not found for identifier ${identifier} and type ${mtType}`); 89 | } 90 | 91 | return treeWithMeta.tree; 92 | } 93 | /** adds entry to merkle tree in the memory */ 94 | async addToMerkleTree( 95 | identifier: string, 96 | mtType: MerkleTreeType, 97 | hindex: bigint, 98 | hvalue: bigint 99 | ): Promise { 100 | for (let index = 0; index < this._data[identifier].length; index++) { 101 | if (this._data[identifier][index].metaInfo.type === mtType) { 102 | await this._data[identifier][index].tree.add(hindex, hvalue); 103 | } 104 | } 105 | } 106 | 107 | /** bind merkle tree identifier in memory */ 108 | async bindMerkleTreeToNewIdentifier(oldIdentifier: string, newIdentifier: string): Promise { 109 | this._data[newIdentifier] = [...this._data[oldIdentifier]]; 110 | delete this._data[oldIdentifier]; 111 | 112 | this._data[newIdentifier].forEach((treeWithMeta) => { 113 | treeWithMeta.metaInfo.identifier = newIdentifier; 114 | }); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/storage/shared/circuit-storage.ts: -------------------------------------------------------------------------------- 1 | import { CircuitId } from '../../circuits'; 2 | import { CircuitData } from '../entities/circuitData'; 3 | import { StorageErrors } from '../errors'; 4 | import { ICircuitStorage } from '../interfaces/circuits'; 5 | import { IDataSource } from '../interfaces/data-source'; 6 | 7 | /** 8 | * Implementation of ICircuitStorage to store keys data 9 | * 10 | * @public 11 | * @class CircuitStorage 12 | * @implements implements ICircuitStorage interface 13 | */ 14 | export class CircuitStorage implements ICircuitStorage { 15 | /** 16 | * storage key for circuits 17 | */ 18 | static readonly storageKey = 'circuits'; 19 | /** 20 | * Creates an instance of CircuitStorage. 21 | * @param {IDataSource} _dataSource - data source to store circuit keys 22 | */ 23 | constructor(private readonly _dataSource: IDataSource) {} 24 | 25 | /** 26 | * loads circuit data by id 27 | * {@inheritdoc ICircuitStorage.loadCircuitData} 28 | * @param {CircuitId} circuitId - id of the circuit 29 | * @returns `Promise` 30 | */ 31 | async loadCircuitData(circuitId: CircuitId): Promise { 32 | const circuitData = await this._dataSource.get(circuitId.toString(), 'circuitId'); 33 | if (!circuitData) { 34 | throw new Error(`${StorageErrors.ItemNotFound}: ${circuitId}`); 35 | } 36 | return circuitData; 37 | } 38 | 39 | /** 40 | * {@inheritdoc ICircuitStorage.loadCircuitData} 41 | * saves circuit data for circuit id 42 | * @param {CircuitId} circuitId - id of the circuit 43 | * @param {CircuitData} circuitData - circuit keys 44 | * @returns `Promise` 45 | */ 46 | async saveCircuitData(circuitId: CircuitId, circuitData: CircuitData): Promise { 47 | await this._dataSource.save(circuitId.toString(), circuitData, 'circuitId'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/storage/shared/credential-storage.ts: -------------------------------------------------------------------------------- 1 | import { ProofQuery, W3CCredential } from '../../verifiable'; 2 | import { StandardJSONCredentialsQueryFilter } from '../filters'; 3 | import { ICredentialStorage } from '../interfaces/credentials'; 4 | import { IDataSource } from '../interfaces/data-source'; 5 | 6 | /** 7 | * Implementation of ICredentialStorage with KV Data source 8 | * 9 | * @public 10 | * @class CredentialStorage 11 | * @implements {ICredentialStorage} 12 | */ 13 | export class CredentialStorage implements ICredentialStorage { 14 | /** 15 | * key for storage 16 | * 17 | * @static 18 | */ 19 | static readonly storageKey = 'credentials'; 20 | /** 21 | * Creates an instance of CredentialStorage. 22 | * @param {IDataSource} _dataSource - W3CCredential credential KV data source 23 | */ 24 | constructor(private readonly _dataSource: IDataSource) {} 25 | 26 | /** {@inheritdoc ICredentialStorage.listCredentials } */ 27 | async listCredentials(): Promise { 28 | const creds = await this._dataSource.load(); 29 | return creds.filter((i) => i !== undefined).map((cred) => cred && W3CCredential.fromJSON(cred)); 30 | } 31 | 32 | /** @inheritdoc */ 33 | async saveCredential(credential: W3CCredential): Promise { 34 | return this._dataSource.save(credential.id, credential.toJSON()); 35 | } 36 | 37 | /** {@inheritdoc ICredentialStorage.listCredentials } */ 38 | async saveAllCredentials(credentials: W3CCredential[]): Promise { 39 | for (const credential of credentials) { 40 | await this.saveCredential(credential); 41 | } 42 | } 43 | 44 | /** {@inheritdoc ICredentialStorage.listCredentials } */ 45 | async removeCredential(id: string): Promise { 46 | return this._dataSource.delete(id); 47 | } 48 | 49 | /** {@inheritdoc ICredentialStorage.listCredentials } */ 50 | async findCredentialById(id: string): Promise { 51 | const cred = await this._dataSource.get(id); 52 | return cred && W3CCredential.fromJSON(cred); 53 | } 54 | 55 | /** {@inheritdoc ICredentialStorage.listCredentials } 56 | * uses JSON query 57 | */ 58 | async findCredentialsByQuery(query: ProofQuery): Promise { 59 | const filters = StandardJSONCredentialsQueryFilter(query); 60 | const creds = (await this._dataSource.load()).filter((credential) => 61 | filters.every((filter) => filter.execute(credential)) 62 | ); 63 | 64 | const mappedCreds = creds 65 | .filter((i) => i !== undefined) 66 | .map((cred) => W3CCredential.fromJSON(cred)); 67 | 68 | return mappedCreds; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/storage/shared/identity-storage.ts: -------------------------------------------------------------------------------- 1 | import { Identity, Profile } from '../entities'; 2 | import { IDataSource } from '../interfaces/data-source'; 3 | import { IIdentityStorage } from '../interfaces/identity'; 4 | 5 | /** 6 | * Implementation of the IIdentityStorage with KV data source 7 | * 8 | * @public 9 | * @class IdentityStorage 10 | * @implements implements IIdentityStorage interface 11 | */ 12 | export class IdentityStorage implements IIdentityStorage { 13 | /** 14 | * storage key for identities 15 | * 16 | * @static 17 | */ 18 | static readonly identitiesStorageKey = 'identities'; 19 | /** 20 | * storage key for profiles 21 | * 22 | * @static 23 | */ 24 | static readonly profilesStorageKey = 'profiles'; 25 | 26 | /** 27 | * Creates an instance of IdentityStorage. 28 | * @param {IDataSource} _identityDataSource - data source for identities 29 | * @param {IDataSource} _profileDataSource - data source for profiles 30 | */ 31 | constructor( 32 | private readonly _identityDataSource: IDataSource, 33 | private readonly _profileDataSource: IDataSource 34 | ) {} 35 | 36 | async saveProfile(profile: Profile): Promise { 37 | const profiles = await this._profileDataSource.load(); 38 | const identityProfiles = profiles.filter( 39 | (p) => p.genesisIdentifier === profile.genesisIdentifier 40 | ); 41 | const toSave = identityProfiles.length ? [...identityProfiles, profile] : [profile]; 42 | for (let index = 0; index < toSave.length; index++) { 43 | const element = toSave[index]; 44 | await this._profileDataSource.save(element.id, element); 45 | } 46 | } 47 | 48 | async getProfileByVerifier(verifier: string): Promise { 49 | return this._profileDataSource.get(verifier, 'verifier'); 50 | } 51 | 52 | async getProfileById(profileId: string): Promise { 53 | return this._profileDataSource.get(profileId); 54 | } 55 | 56 | async getProfilesByGenesisIdentifier(genesisIdentifier: string): Promise { 57 | return (await this._profileDataSource.load()).filter( 58 | (p) => p.genesisIdentifier === genesisIdentifier 59 | ); 60 | } 61 | 62 | async getAllIdentities(): Promise { 63 | return this._identityDataSource.load(); 64 | } 65 | 66 | async saveIdentity(identity: Identity): Promise { 67 | return this._identityDataSource.save(identity.did, identity, 'did'); 68 | } 69 | 70 | async getIdentity(identifier: string): Promise { 71 | return this._identityDataSource.get(identifier, 'did'); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/storage/shared/index.ts: -------------------------------------------------------------------------------- 1 | export * from './circuit-storage'; 2 | export * from './credential-storage'; 3 | export * from './identity-storage'; 4 | -------------------------------------------------------------------------------- /src/storage/utils.ts: -------------------------------------------------------------------------------- 1 | import { IdentityMerkleTreeMetaInformation, MerkleTreeType } from './entities'; 2 | 3 | export const MERKLE_TREE_TYPES: MerkleTreeType[] = [ 4 | MerkleTreeType.Claims, 5 | MerkleTreeType.Revocations, 6 | MerkleTreeType.Roots 7 | ]; 8 | 9 | export const createMerkleTreeMetaInfo = ( 10 | identifier: string 11 | ): IdentityMerkleTreeMetaInformation[] => { 12 | const treesMeta: IdentityMerkleTreeMetaInformation[] = []; 13 | for (let index = 0; index < MERKLE_TREE_TYPES.length; index++) { 14 | const mType = MERKLE_TREE_TYPES[index]; 15 | const treeId = `${identifier}+${mType}`; 16 | treesMeta.push({ treeId, identifier, type: mType }); 17 | } 18 | return treesMeta; 19 | }; 20 | -------------------------------------------------------------------------------- /src/utils/compare-func.ts: -------------------------------------------------------------------------------- 1 | export const bigIntCompare = (a: bigint, b: bigint): number => { 2 | if (a < b) return -1; 3 | if (a > b) return 1; 4 | return 0; 5 | }; 6 | -------------------------------------------------------------------------------- /src/utils/encoding.ts: -------------------------------------------------------------------------------- 1 | import { base58FromBytes, base58ToBytes as b58ToBytes, Hex } from '@iden3/js-crypto'; 2 | import { base64url, base64 } from 'rfc4648'; 3 | 4 | export const byteEncoder = new TextEncoder(); 5 | export const byteDecoder = new TextDecoder(); 6 | 7 | export function bytesToBase64url(b: Uint8Array, opts = { pad: false }): string { 8 | return base64url.stringify(b, opts); 9 | } 10 | 11 | export function base64ToBytes(s: string, opts = { loose: true }): Uint8Array { 12 | return base64.parse(s, opts); 13 | } 14 | 15 | export function bytesToBase64(b: Uint8Array, opts = { pad: false }): string { 16 | return base64.stringify(b, opts); 17 | } 18 | 19 | export function base64UrlToBytes(s: string, opts = { loose: true }): Uint8Array { 20 | const inputBase64Url = s.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); 21 | return base64url.parse(inputBase64Url, opts); 22 | } 23 | 24 | export function base58ToBytes(s: string): Uint8Array { 25 | return b58ToBytes(s); 26 | } 27 | 28 | export function bytesToBase58(b: Uint8Array): string { 29 | return base58FromBytes(b); 30 | } 31 | 32 | export function hexToBytes(s: string): Uint8Array { 33 | const input = s.startsWith('0x') ? s.substring(2) : s; 34 | return Hex.decodeString(input.toLowerCase()); 35 | } 36 | 37 | export function encodeBase64url(s: string, opts = { pad: false }): string { 38 | return base64url.stringify(byteEncoder.encode(s), opts); 39 | } 40 | 41 | export function decodeBase64url(s: string, opts = { loose: true }): string { 42 | return byteDecoder.decode(base64url.parse(s, opts)); 43 | } 44 | 45 | export function bytesToHex(b: Uint8Array): string { 46 | return Hex.encodeString(b); 47 | } 48 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './encoding'; 2 | export * from './object'; 3 | export * from './did-helper'; 4 | export * from './message-bus'; 5 | export * from './compare-func'; 6 | -------------------------------------------------------------------------------- /src/utils/message-bus.ts: -------------------------------------------------------------------------------- 1 | import PubSub from 'pubsub-js'; 2 | 3 | /** 4 | * Represents an event in the SDK. 5 | */ 6 | type SdkEvent = string; 7 | 8 | export const SDK_EVENTS: { [k: SdkEvent]: SdkEvent } = { 9 | TX_RECEIPT_ACCEPTED: 'TX_RECEIPT_ACCEPTED' 10 | }; 11 | 12 | /** 13 | * Represents a topic in the SDK message bus. 14 | */ 15 | export type SdkTopic = keyof typeof SDK_EVENTS; 16 | 17 | /** 18 | * Represents a message bus that allows publishing and subscribing to topics. 19 | */ 20 | export class MessageBus { 21 | /** 22 | * The singleton instance of the MessageBus class. 23 | */ 24 | private static instance: MessageBus; 25 | 26 | /** 27 | * Private constructor for the MessageBus class. 28 | */ 29 | // eslint-disable-next-line @typescript-eslint/no-empty-function 30 | private constructor() {} 31 | 32 | /** 33 | * Returns the singleton instance of the MessageBus class. 34 | * If the instance doesn't exist, it creates a new one. 35 | * @returns The singleton instance of the MessageBus class. 36 | */ 37 | public static getInstance(): MessageBus { 38 | // If the instance doesn't exist, create it 39 | if (!MessageBus.instance) { 40 | MessageBus.instance = new MessageBus(); 41 | } 42 | // Return the instance 43 | return MessageBus.instance; 44 | } 45 | 46 | /** 47 | * Publishes a message to the specified topic. 48 | * 49 | * @template T - The type of data being published. 50 | * @param {SdkTopic} topic - The topic to publish the message to. 51 | * @param {T} data - The data to be published. 52 | * @returns {boolean} - Returns true if the message was successfully published, false otherwise. 53 | */ 54 | public publish(topic: SdkTopic, data: T): boolean { 55 | return PubSub.publish(topic.toString(), data); 56 | } 57 | 58 | /** 59 | * Subscribes to a specific topic and registers a callback function to be executed when a message is published. 60 | * 61 | * @param topic - The topic to subscribe to. 62 | * @param callback - The callback function to be executed when a message is published. 63 | */ 64 | public subscribe(topic: SdkTopic, callback: (data: T) => void): string { 65 | return PubSub.subscribe(topic.toString(), (_, data) => callback(data)); 66 | } 67 | 68 | /** 69 | * Subscribes to a specific topic and registers a callback function to be executed when a message is published. 70 | * The callback function is executed only once. 71 | * 72 | * @param topic - The topic to subscribe to. 73 | * @param callback - The callback function to be executed when a message is published. 74 | */ 75 | public subscribeOnce(topic: SdkTopic, callback: (data: T) => void): void { 76 | PubSub.subscribeOnce(topic.toString(), (_, data) => callback(data)); 77 | } 78 | 79 | /** 80 | * Unsubscribes from a specific topic in the message bus. 81 | * 82 | * @param topic - The topic to unsubscribe from. 83 | * @returns A string or boolean indicating the success of the unsubscribe operation. 84 | */ 85 | public unsubscribe(topic: SdkTopic): string | boolean { 86 | return PubSub.unsubscribe(topic.toString()); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/utils/object.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Merges two objects together, prioritizing the properties of the second object. 3 | * If a property exists in both objects, the value from the second object will be used. 4 | * @param credSubject - The first object to merge. 5 | * @param otherCredSubject - The second object to merge. 6 | * @returns A new object with the merged properties. 7 | */ 8 | 9 | import { JsonDocumentObject } from '../iden3comm'; 10 | 11 | export function mergeObjects( 12 | credSubject: JsonDocumentObject, 13 | otherCredSubject: JsonDocumentObject 14 | ) { 15 | let result = {} as JsonDocumentObject; 16 | const credSubjectKeys = Object.keys(credSubject); 17 | 18 | for (const key of credSubjectKeys) { 19 | if (typeof otherCredSubject[key] !== 'undefined') { 20 | if (typeof credSubject[key] !== 'object' && typeof otherCredSubject[key] !== 'object') { 21 | throw new Error('Invalid query'); 22 | } 23 | const subjectProperty = credSubject[key] as JsonDocumentObject; 24 | const otherSubjectProperty = otherCredSubject[key] as JsonDocumentObject; 25 | const propertyOperators = Object.keys(subjectProperty); 26 | const subjectPropertyResult: JsonDocumentObject = {}; 27 | for (const operatorKey of propertyOperators) { 28 | if (typeof otherSubjectProperty[operatorKey] !== 'undefined') { 29 | const operatorValue1 = subjectProperty[operatorKey] as JsonDocumentObject; 30 | const operatorValue2 = otherSubjectProperty[operatorKey]; 31 | subjectPropertyResult[operatorKey] = [ 32 | ...new Set([ 33 | ...((subjectPropertyResult[operatorKey] as Array) ?? []), 34 | operatorValue1, 35 | ...(Array.isArray(operatorValue2) ? operatorValue2 : [operatorValue2]) 36 | ]) 37 | ]; 38 | } else { 39 | subjectPropertyResult[operatorKey] = subjectProperty[operatorKey]; 40 | } 41 | } 42 | result[key] = { 43 | ...(otherCredSubject[key] as JsonDocumentObject), 44 | ...subjectPropertyResult 45 | }; 46 | } 47 | } 48 | 49 | // Add remaining keys from obj2 50 | result = { ...credSubject, ...otherCredSubject, ...result }; 51 | return result; 52 | } 53 | -------------------------------------------------------------------------------- /src/verifiable/index.ts: -------------------------------------------------------------------------------- 1 | export * from './credential'; 2 | export * from './presentation'; 3 | export * from './proof'; 4 | export * from './schema'; 5 | export * from './constants'; 6 | export * from './core-utils'; 7 | -------------------------------------------------------------------------------- /src/verifiable/presentation.ts: -------------------------------------------------------------------------------- 1 | import { VerifiableConstants } from './constants'; 2 | import { Options, Path } from '@iden3/js-jsonld-merklization'; 3 | import { W3CCredential } from './credential'; 4 | import { QueryMetadata } from '../proof'; 5 | import { VerifiablePresentation, JsonDocumentObject } from '../iden3comm'; 6 | 7 | export const stringByPath = (obj: { [key: string]: unknown }, path: string): string => { 8 | const parts = path.split('.'); 9 | 10 | let value = obj; 11 | for (let index = 0; index < parts.length; index++) { 12 | const key = parts[index]; 13 | if (!key) { 14 | throw new Error('path is empty'); 15 | } 16 | value = value[key] as { [key: string]: unknown }; 17 | if (value === undefined) { 18 | throw new Error('path not found'); 19 | } 20 | } 21 | return value.toString(); 22 | }; 23 | 24 | export const buildFieldPath = async ( 25 | ldSchema: string, 26 | contextType: string, 27 | field: string, 28 | opts?: Options 29 | ): Promise => { 30 | let path = new Path(); 31 | 32 | if (field) { 33 | path = await Path.getContextPathKey(ldSchema, contextType, field, opts); 34 | } 35 | path.prepend([VerifiableConstants.CREDENTIAL_SUBJECT_PATH]); 36 | return path; 37 | }; 38 | 39 | export const findValue = (fieldName: string, credential: W3CCredential): JsonDocumentObject => { 40 | const [first, ...rest] = fieldName.split('.'); 41 | let v = credential.credentialSubject[first]; 42 | for (const part of rest) { 43 | v = (v as JsonDocumentObject)[part]; 44 | } 45 | return v as JsonDocumentObject; 46 | }; 47 | 48 | export const createVerifiablePresentation = ( 49 | context: string, 50 | tp: string, 51 | credential: W3CCredential, 52 | queries: QueryMetadata[] 53 | ): VerifiablePresentation => { 54 | const baseContext = [VerifiableConstants.JSONLD_SCHEMA.W3C_CREDENTIAL_2018]; 55 | const ldContext = baseContext[0] === context ? baseContext : [...baseContext, context]; 56 | 57 | const vc = VerifiableConstants.CREDENTIAL_TYPE.W3C_VERIFIABLE_CREDENTIAL; 58 | const vcTypes = [vc]; 59 | if (tp !== vc) { 60 | vcTypes.push(tp); 61 | } 62 | 63 | const skeleton = { 64 | '@context': baseContext, 65 | '@type': VerifiableConstants.CREDENTIAL_TYPE.W3C_VERIFIABLE_PRESENTATION, 66 | verifiableCredential: { 67 | '@context': ldContext, 68 | '@type': vcTypes, 69 | credentialSubject: { 70 | '@type': tp 71 | } 72 | } 73 | }; 74 | 75 | let result: JsonDocumentObject = {}; 76 | for (const query of queries) { 77 | const parts = query.fieldName.split('.'); 78 | const current: JsonDocumentObject = parts.reduceRight( 79 | (acc: JsonDocumentObject, part: string) => { 80 | if (result[part]) { 81 | return { [part]: { ...(result[part] as JsonDocumentObject), ...acc } }; 82 | } 83 | return { [part]: acc }; 84 | }, 85 | findValue(query.fieldName, credential) as JsonDocumentObject 86 | ); 87 | 88 | result = { ...result, ...current }; 89 | } 90 | 91 | skeleton.verifiableCredential.credentialSubject = { 92 | ...skeleton.verifiableCredential.credentialSubject, 93 | ...result 94 | }; 95 | 96 | return skeleton; 97 | }; 98 | -------------------------------------------------------------------------------- /tests/circuits/auth-v2.test.ts: -------------------------------------------------------------------------------- 1 | import { AuthV2PubSignals } from './../../src/circuits/auth-v2'; 2 | import { Id } from '@iden3/js-iden3-core'; 3 | import { Hash } from '@iden3/js-merkletree'; 4 | import { AuthV2Inputs } from '../../src/circuits'; 5 | import { IdentityTest, userPK, issuerPK, globalTree } from './utils'; 6 | import expectedJson from './data/auth-v2-inputs.json'; 7 | import { expect } from 'chai'; 8 | import { byteDecoder, byteEncoder } from '../../src'; 9 | 10 | describe('auth-v2', () => { 11 | it('TestAuthV2Inputs_InputsMarshal', async () => { 12 | const challenge = BigInt(10); 13 | const user = await IdentityTest.newIdentity(userPK); 14 | 15 | const nonce = BigInt(0); 16 | const user2 = await IdentityTest.newIdentity(issuerPK); 17 | 18 | const gTree = globalTree(); 19 | 20 | await gTree.add(user2.id.bigInt(), (await user2.state()).bigInt()); 21 | const globalProof = await gTree.generateProof(user.id.bigInt()); 22 | 23 | const authClaimIncMTP = await user.claimMTPRaw(user.authClaim); 24 | const authClaimNonRevMTP = await user.claimRevMTPRaw(user.authClaim); 25 | 26 | const signature = user.signBJJ(challenge); 27 | const inputs = new AuthV2Inputs(); 28 | 29 | inputs.genesisID = user.id; 30 | inputs.profileNonce = nonce; 31 | inputs.authClaim = user.authClaim; 32 | inputs.authClaimIncMtp = authClaimIncMTP.proof; 33 | inputs.authClaimNonRevMtp = authClaimNonRevMTP.proof; 34 | inputs.treeState = { 35 | state: await user.state(), 36 | claimsRoot: await user.clt.root(), 37 | revocationRoot: await user.ret.root(), 38 | rootOfRoots: await user.rot.root() 39 | }; 40 | inputs.signature = signature; 41 | inputs.challenge = challenge; 42 | inputs.gistProof = { 43 | root: await gTree.root(), 44 | proof: globalProof.proof 45 | }; 46 | 47 | const bytesInputs = inputs.inputsMarshal(); 48 | 49 | const actualJson = JSON.parse(byteDecoder.decode(bytesInputs)); 50 | 51 | expect(actualJson).to.deep.equal(expectedJson); 52 | }); 53 | 54 | it('authV2Outputs_CircuitUnmarshal', () => { 55 | // generate mock Data. 56 | const intID = BigInt( 57 | '19224224881555258540966250468059781351205177043309252290095510834143232000' 58 | ); 59 | const identifier = Id.fromBigInt(intID); 60 | 61 | const challenge = BigInt(1); 62 | 63 | const stateInt = BigInt( 64 | '18656147546666944484453899241916469544090258810192803949522794490493271005313' 65 | ); 66 | const state = Hash.fromBigInt(stateInt); 67 | 68 | const out = byteEncoder.encode( 69 | JSON.stringify([ 70 | identifier.bigInt().toString(), 71 | challenge.toString(), 72 | state.bigInt().toString() 73 | ]) 74 | ); 75 | 76 | const ao = new AuthV2PubSignals(); 77 | ao.pubSignalsUnmarshal(out); 78 | expect(challenge.toString()).to.deep.equal(ao.challenge.toString()); 79 | expect(state.bigInt().toString()).to.deep.equal(ao.GISTRoot.bigInt().toString()); 80 | expect(identifier.string()).to.deep.equal(ao.userID.string()); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /tests/circuits/data/auth-v2-inputs.json: -------------------------------------------------------------------------------- 1 | { 2 | "genesisID": "26109404700696283154998654512117952420503675471097392618762221546565140481", 3 | "profileNonce": "0", 4 | "authClaim": [ 5 | "80551937543569765027552589160822318028", 6 | "0", 7 | "17640206035128972995519606214765283372613874593503528180869261482403155458945", 8 | "20634138280259599560273310290025659992320584624461316485434108770067472477956", 9 | "15930428023331155902", 10 | "0", 11 | "0", 12 | "0" 13 | ], 14 | "authClaimIncMtp": [ 15 | "0", 16 | "0", 17 | "0", 18 | "0", 19 | "0", 20 | "0", 21 | "0", 22 | "0", 23 | "0", 24 | "0", 25 | "0", 26 | "0", 27 | "0", 28 | "0", 29 | "0", 30 | "0", 31 | "0", 32 | "0", 33 | "0", 34 | "0", 35 | "0", 36 | "0", 37 | "0", 38 | "0", 39 | "0", 40 | "0", 41 | "0", 42 | "0", 43 | "0", 44 | "0", 45 | "0", 46 | "0", 47 | "0", 48 | "0", 49 | "0", 50 | "0", 51 | "0", 52 | "0", 53 | "0", 54 | "0" 55 | ], 56 | "authClaimNonRevMtp": [ 57 | "0", 58 | "0", 59 | "0", 60 | "0", 61 | "0", 62 | "0", 63 | "0", 64 | "0", 65 | "0", 66 | "0", 67 | "0", 68 | "0", 69 | "0", 70 | "0", 71 | "0", 72 | "0", 73 | "0", 74 | "0", 75 | "0", 76 | "0", 77 | "0", 78 | "0", 79 | "0", 80 | "0", 81 | "0", 82 | "0", 83 | "0", 84 | "0", 85 | "0", 86 | "0", 87 | "0", 88 | "0", 89 | "0", 90 | "0", 91 | "0", 92 | "0", 93 | "0", 94 | "0", 95 | "0", 96 | "0" 97 | ], 98 | "challenge": "10", 99 | "challengeSignatureR8x": "2436614617352067078274240654647841101298221663194055411539273018411814965042", 100 | "challengeSignatureR8y": "18597752099468941062473075570139025288787892531282848931228194191266230422780", 101 | "challengeSignatureS": "1642466479083925938589665711747519202726798003514101885795868643287098549939", 102 | "claimsTreeRoot": "9860409408344985873118363460916733946840214387455464863344022463808838582364", 103 | "revTreeRoot": "0", 104 | "rootsTreeRoot": "0", 105 | "state": "1648710229725601204870171311149827592640182384459240511403224642152766848235", 106 | "gistRoot": "11098939821764568131087645431296528907277253709936443029379587475821759259406", 107 | "gistMtp": [ 108 | "0", 109 | "0", 110 | "0", 111 | "0", 112 | "0", 113 | "0", 114 | "0", 115 | "0", 116 | "0", 117 | "0", 118 | "0", 119 | "0", 120 | "0", 121 | "0", 122 | "0", 123 | "0", 124 | "0", 125 | "0", 126 | "0", 127 | "0", 128 | "0", 129 | "0", 130 | "0", 131 | "0", 132 | "0", 133 | "0", 134 | "0", 135 | "0", 136 | "0", 137 | "0", 138 | "0", 139 | "0", 140 | "0", 141 | "0", 142 | "0", 143 | "0", 144 | "0", 145 | "0", 146 | "0", 147 | "0", 148 | "0", 149 | "0", 150 | "0", 151 | "0", 152 | "0", 153 | "0", 154 | "0", 155 | "0", 156 | "0", 157 | "0", 158 | "0", 159 | "0", 160 | "0", 161 | "0", 162 | "0", 163 | "0", 164 | "0", 165 | "0", 166 | "0", 167 | "0", 168 | "0", 169 | "0", 170 | "0", 171 | "0" 172 | ], 173 | "authClaimNonRevMtpAuxHi": "0", 174 | "authClaimNonRevMtpAuxHv": "0", 175 | "authClaimNonRevMtpNoAux": "1", 176 | "gistMtpAuxHi": "27918766665310231445021466320959318414450284884582375163563581940319453185", 177 | "gistMtpAuxHv": "20177832565449474772630743317224985532862797657496372535616634430055981993180", 178 | "gistMtpNoAux": "0" 179 | } 180 | -------------------------------------------------------------------------------- /tests/circuits/linked-multi-query.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LinkedMultiQueryInputs, 3 | LinkedMultiQueryPubSignals, 4 | Operators, 5 | Query 6 | } from '../../src/circuits'; 7 | import { IdentityTest, defaultUserClaim, userPK } from './utils'; 8 | import expectedJson from './data/linked-multi-query-inputs.json'; 9 | import { expect } from 'chai'; 10 | import { byteDecoder, byteEncoder } from '../../src'; 11 | 12 | describe('linked-multi-query', () => { 13 | it('TestLinkedMultiQueryInputs_InputsMarshal', async () => { 14 | const user = await IdentityTest.newIdentity(userPK); 15 | const id = user.id; 16 | const claim = defaultUserClaim(id); 17 | 18 | const query1 = new Query(); 19 | query1.operator = Operators.EQ; 20 | query1.slotIndex = 2; 21 | query1.values = [BigInt(10)]; 22 | 23 | const query2 = new Query(); 24 | query2.operator = Operators.LT; 25 | query2.slotIndex = 2; 26 | query2.values = [BigInt(133)]; 27 | 28 | const query3 = new Query(); 29 | query3.operator = Operators.LTE; 30 | query3.slotIndex = 2; 31 | query3.values = [BigInt(555)]; 32 | 33 | const inputs = new LinkedMultiQueryInputs(); 34 | inputs.linkNonce = BigInt('35346346369657418'); 35 | inputs.claim = claim; 36 | inputs.query = [query1, query2, query3]; 37 | const bytesInputs = inputs.inputsMarshal(); 38 | const actualJson = JSON.parse(byteDecoder.decode(bytesInputs)); 39 | 40 | expect(actualJson).to.deep.equal(expectedJson); 41 | }); 42 | 43 | it('LinkedLinkedMultiQueryPubSignals_CircuitUnmarshal', () => { 44 | // generate mock Data. 45 | const out = byteEncoder.encode( 46 | `[ 47 | "443", 48 | "1", 49 | "1", 50 | "2", 51 | "3", 52 | "4", 53 | "5", 54 | "0", 55 | "0", 56 | "0", 57 | "0", 58 | "0", 59 | "100", 60 | "200", 61 | "300", 62 | "400", 63 | "500", 64 | "0", 65 | "0", 66 | "0", 67 | "0", 68 | "0" 69 | ]` 70 | ); 71 | 72 | const ao = new LinkedMultiQueryPubSignals(); 73 | ao.pubSignalsUnmarshal(out); 74 | 75 | const exp = new LinkedMultiQueryPubSignals(); 76 | exp.linkID = BigInt(443); 77 | exp.merklized = 1; 78 | 79 | const operatorOutput: bigint[] = []; 80 | const circuitQueryHash: bigint[] = []; 81 | const valueArraySize: number[] = []; 82 | for (let i = 1; i <= 10; i++) { 83 | const indx = i - 1; 84 | operatorOutput[indx] = BigInt(i); 85 | circuitQueryHash[indx] = BigInt(i * 100); 86 | valueArraySize[indx] = 1; 87 | 88 | if (i > 5) { 89 | operatorOutput[indx] = BigInt(0); 90 | circuitQueryHash[indx] = BigInt(0); 91 | valueArraySize[indx] = 0; 92 | } 93 | } 94 | 95 | exp.operatorOutput = operatorOutput; 96 | exp.circuitQueryHash = circuitQueryHash; 97 | 98 | const expJson = JSON.stringify(exp, (_, value) => 99 | typeof value === 'bigint' ? value.toString() : value 100 | ); 101 | 102 | const actualJson = JSON.stringify(ao, (_, value) => 103 | typeof value === 'bigint' ? value.toString() : value 104 | ); 105 | 106 | expect(expJson).to.deep.equal(actualJson); 107 | }); 108 | }); 109 | -------------------------------------------------------------------------------- /tests/credentials/credential-statuses/did-resolver-revocation.test.ts: -------------------------------------------------------------------------------- 1 | import { DID } from '@iden3/js-iden3-core'; 2 | import { 3 | CredentialStatusResolver, 4 | CredentialStatusType, 5 | DidDocumentCredentialStatusResolver 6 | } from '../../../src'; 7 | 8 | import chai from 'chai'; 9 | import spies from 'chai-spies'; 10 | import nock from 'nock'; 11 | 12 | chai.use(spies); 13 | const expect = chai.expect; 14 | 15 | describe('did document revocation checks', () => { 16 | let credentialStatusResolver: CredentialStatusResolver; 17 | 18 | beforeEach(async () => { 19 | credentialStatusResolver = new DidDocumentCredentialStatusResolver( 20 | 'http://my-universal-resolver' 21 | ); 22 | }); 23 | 24 | it('resolver works', async () => { 25 | nock('http://my-universal-resolver') 26 | .post( 27 | // eslint-disable-next-line @cspell/spellchecker 28 | '/1.0/credential-status/did%3Aiden3%3Alinea%3Asepolia%3A28qZMExF5v2HevdLP7utHnAQazQHetsa7tsc4NCwyT' 29 | ) 30 | .reply( 31 | 200, 32 | `{ 33 | "issuer": { 34 | "state": "ce589b4e97b58202088feb0a9de25b53df78fcf7032d4bec0390a562302b4a1e", 35 | "rootOfRoots": "27735a9562a6b148e52fa9872e705b56b48f0b52dc2e9b6f1d063cf594c54f26", 36 | "claimsTreeRoot": "74730fecdb52486ffc7050496f253ac9ed12032ec29378be99f59d9fe5ba6f24", 37 | "revocationTreeRoot": "0000000000000000000000000000000000000000000000000000000000000000" 38 | }, 39 | "mtp": { 40 | "existence": false, 41 | "siblings": [] 42 | } 43 | }` 44 | ); 45 | 46 | const revocationStatus = await credentialStatusResolver.resolve( 47 | { 48 | id: 'did:iden3:linea:sepolia:28qZMExF5v2HevdLP7utHnAQazQHetsa7tsc4NCwyT/credentialStatus?revocationNonce=1000&contractAddress=59141:0x7dF78ED37d0B39Ffb6d4D527Bb1865Bf85B60f81&state=cc17961a8e92bc3836cecee42b7812d67c0d8a7829076337260c4782df124c03', 49 | type: CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023, 50 | revocationNonce: 1000 51 | }, 52 | { issuerDID: DID.parse('did:iden3:linea:sepolia:28qZMExF5v2HevdLP7utHnAQazQHetsa7tsc4NCwyT') } 53 | ); 54 | 55 | expect(revocationStatus).to.be.an('object'); 56 | expect(revocationStatus).to.have.property('issuer'); 57 | expect(revocationStatus).to.have.property('mtp'); 58 | expect(revocationStatus.issuer.state).to.be.not.empty; 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /tests/credentials/credential-statuses/sparse-merkle-tree-proof.test.ts: -------------------------------------------------------------------------------- 1 | import { IdentityWallet } from '../../../src'; 2 | import { IDataStorage } from '../../../src/storage/interfaces'; 3 | import { CredentialRequest, CredentialWallet } from '../../../src/credentials'; 4 | import { CredentialStatusType } from '../../../src/verifiable'; 5 | import { expect } from 'chai'; 6 | import { 7 | MOCK_STATE_STORAGE, 8 | SEED_USER, 9 | createIdentity, 10 | getInMemoryDataStorage, 11 | registerKeyProvidersInMemoryKMS 12 | } from '../../helpers'; 13 | import { DID } from '@iden3/js-iden3-core'; 14 | import { schemaLoaderForTests } from '../../mocks/schema'; 15 | 16 | describe('SparseMerkleTreeProof', () => { 17 | let idWallet: IdentityWallet; 18 | let credWallet: CredentialWallet; 19 | 20 | let dataStorage: IDataStorage; 21 | 22 | let userDID: DID; 23 | let issuerDID: DID; 24 | const walletUrl = 'https://user-wallet.com'; 25 | const issuerWalletUrl = 'https://issuer.com'; 26 | const merklizeOpts = { 27 | documentLoader: schemaLoaderForTests() 28 | }; 29 | 30 | beforeEach(async () => { 31 | const kms = registerKeyProvidersInMemoryKMS(); 32 | dataStorage = getInMemoryDataStorage(MOCK_STATE_STORAGE); 33 | 34 | credWallet = new CredentialWallet(dataStorage); 35 | idWallet = new IdentityWallet(kms, dataStorage, credWallet); 36 | 37 | const { did: didUser, credential: userAuthCredential } = await createIdentity(idWallet, { 38 | seed: SEED_USER, 39 | revocationOpts: { 40 | type: CredentialStatusType.SparseMerkleTreeProof, 41 | id: walletUrl 42 | } 43 | }); 44 | userDID = didUser; 45 | 46 | expect(userAuthCredential).not.to.be.undefined; 47 | 48 | const { did: didIssuer, credential: issuerAuthCredential } = await createIdentity(idWallet, { 49 | revocationOpts: { 50 | type: CredentialStatusType.SparseMerkleTreeProof, 51 | id: issuerWalletUrl 52 | } 53 | }); 54 | expect(issuerAuthCredential).not.to.be.undefined; 55 | issuerDID = didIssuer; 56 | }); 57 | 58 | it('issue credential', async () => { 59 | const credRequest: CredentialRequest = { 60 | credentialSchema: 61 | 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/kyc-nonmerklized.json', 62 | type: 'KYCAgeCredential', 63 | credentialSubject: { 64 | id: userDID.string(), 65 | birthday: 19960424, 66 | documentType: 99 67 | }, 68 | expiration: 2793526400, 69 | revocationOpts: { 70 | type: CredentialStatusType.SparseMerkleTreeProof, 71 | id: walletUrl 72 | } 73 | }; 74 | const issuedCredential = await idWallet.issueCredential(issuerDID, credRequest, merklizeOpts); 75 | 76 | await credWallet.save(issuedCredential); 77 | 78 | expect(issuedCredential).not.to.be.undefined; 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /tests/handlers/mock.ts: -------------------------------------------------------------------------------- 1 | import { DocumentLoader } from '@iden3/js-jsonld-merklization'; 2 | import { DIDResolutionResult } from 'did-resolver'; 3 | import { cacheLoader } from '../../src'; 4 | 5 | export const exampleDidDoc = { 6 | '@context': [ 7 | 'https://www.w3.org/ns/did/v1', 8 | { 9 | EcdsaSecp256k1RecoveryMethod2020: 10 | 'https://identity.foundation/EcdsaSecp256k1RecoverySignature2020#EcdsaSecp256k1RecoveryMethod2020', 11 | blockchainAccountId: 'https://w3id.org/security#blockchainAccountId' 12 | } 13 | ], 14 | id: 'did:pkh:poly:0x7141E4d20F7644DC8c0AdCA8a520EC83C6cABD65', 15 | verificationMethod: [ 16 | { 17 | id: 'did:pkh:poly:0x7141E4d20F7644DC8c0AdCA8a520EC83C6cABD65#Recovery2020', 18 | type: 'EcdsaSecp256k1RecoveryMethod2020', 19 | controller: 'did:pkh:poly:0x7141E4d20F7644DC8c0AdCA8a520EC83C6cABD65', 20 | blockchainAccountId: 'eip155:137:0x7141E4d20F7644DC8c0AdCA8a520EC83C6cABD65' 21 | } 22 | ], 23 | authentication: ['did:pkh:poly:0x7141E4d20F7644DC8c0AdCA8a520EC83C6cABD65#Recovery2020'], 24 | assertionMethod: ['did:pkh:poly:0x7141E4d20F7644DC8c0AdCA8a520EC83C6cABD65#Recovery2020'] 25 | }; 26 | 27 | export const resolveDIDDocument = { 28 | resolve: () => Promise.resolve({ didDocument: exampleDidDoc } as DIDResolutionResult) 29 | }; 30 | 31 | export const schemaLoader: DocumentLoader = cacheLoader({ 32 | ipfsNodeURL: process.env.IPFS_URL ?? 'https://ipfs.io' 33 | }); 34 | -------------------------------------------------------------------------------- /tests/handlers/problem-report.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'mocha'; 2 | import { createProblemReportMessage } from '../../src'; 3 | import { expect } from 'chai'; 4 | 5 | describe('Problem Report Handler', () => { 6 | it('should create problem report', () => { 7 | const example = `{ 8 | "typ": "application/iden3comm-plain-json", 9 | "type": "https://didcomm.org/report-problem/2.0/problem-report", 10 | "pthid": "5333207e-7338-4ab3-ac34-bf9a20dab6ab", 11 | "ack": [ 12 | "23b610b3-aec8-4d1c-8a75-3b22e5483fb0", 13 | "86fe7cc6-adcd-4530-8e07-92c060b427c8" 14 | ], 15 | "body": { 16 | "code": "e.me.remote-server-down", 17 | "comment": "Remote server {1} is down when connecting from {2}", 18 | "args": [ 19 | "https://remote-server.org", 20 | "https://my-server.org" 21 | ], 22 | "escalate_to": "admin@remote-server.org" 23 | }, 24 | "from": "did:polygonid:polygon:mumbai:2qJG6RYgN1u6v7JAYSdfixSwktnZ7hMzd4t21SCdNu", 25 | "to": "did:polygonid:polygon:mumbai:2qFroxB5kwgCxgVrNGUM6EW3khJgCdHHnKTr3VnTcp" 26 | }`; 27 | const problemReport = createProblemReportMessage( 28 | '5333207e-7338-4ab3-ac34-bf9a20dab6ab', 29 | 'e.me.remote-server-down', 30 | { 31 | from: 'did:polygonid:polygon:mumbai:2qJG6RYgN1u6v7JAYSdfixSwktnZ7hMzd4t21SCdNu', 32 | to: 'did:polygonid:polygon:mumbai:2qFroxB5kwgCxgVrNGUM6EW3khJgCdHHnKTr3VnTcp', 33 | args: ['https://remote-server.org', 'https://my-server.org'], 34 | escalate_to: 'admin@remote-server.org', 35 | ack: ['23b610b3-aec8-4d1c-8a75-3b22e5483fb0', '86fe7cc6-adcd-4530-8e07-92c060b427c8'], 36 | comment: 'Remote server {1} is down when connecting from {2}' 37 | } 38 | ); 39 | delete problemReport.id; 40 | const expected = JSON.parse(example); 41 | expect(problemReport).to.be.deep.equal(expected); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /tests/handlers/refresh.test.ts: -------------------------------------------------------------------------------- 1 | import { PackageManager, RefreshHandler } from '../../src'; 2 | import { credWithRefreshService } from '../credentials/mock'; 3 | import { initZKPPacker } from '../iden3comm/mock/proving'; 4 | import nock from 'nock'; 5 | import { expect } from 'chai'; 6 | 7 | describe('refresh-service', () => { 8 | it('refresh service returns cred', async () => { 9 | const credToRefresh = credWithRefreshService; 10 | 11 | const packageManager = new PackageManager(); 12 | const zkpPacker = await initZKPPacker({ alg: 'groth16' }); 13 | packageManager.registerPackers([zkpPacker]); 14 | const refreshService = new RefreshHandler({ 15 | packageManager 16 | }); 17 | 18 | const refreshedCred = JSON.parse(JSON.stringify(credWithRefreshService)); 19 | refreshedCred.expirationDate = new Date().setMinutes(new Date().getMinutes() + 1); 20 | const refreshedId = 'test1_refreshed'; 21 | refreshedCred.id = refreshedId; 22 | 23 | nock('http://test-refresh.com') 24 | .post('/refresh') 25 | .reply(200, { 26 | // CredentialIssuanceMessage 27 | id: 'uuid', 28 | body: { 29 | credential: refreshedCred 30 | } 31 | }); 32 | 33 | const newCred = await refreshService.refreshCredential(credToRefresh, { reason: 'expired' }); 34 | nock.cleanAll(); 35 | expect(newCred.id).to.be.equal(refreshedId); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /tests/iden3comm/accept-profile.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { parseAcceptProfile, buildAccept } from '../../src/iden3comm/utils/accept-profile'; 3 | import { 4 | ProtocolVersion, 5 | MediaType, 6 | AcceptAuthCircuits, 7 | AcceptJwzAlgorithms, 8 | AcceptJwsAlgorithms 9 | } from '../../src/iden3comm/constants'; 10 | 11 | describe('accept profile utils test', () => { 12 | it('parse accept profile', async () => { 13 | const accept = [ 14 | 'iden3comm/v1;env=application/iden3-zkp-json;circuitId=authV2,authV3;alg=groth16', 15 | 'iden3comm/v1;env=application/iden3comm-signed-json;alg=ES256K-R' 16 | ]; 17 | 18 | const { protocolVersion, env, circuits, alg } = parseAcceptProfile(accept[0]); 19 | expect(protocolVersion).to.be.eq('iden3comm/v1'); 20 | expect(env).to.be.eq('application/iden3-zkp-json'); 21 | expect(circuits).to.be.deep.eq(['authV2', 'authV3']); 22 | expect(alg).to.be.deep.eq(['groth16']); 23 | }); 24 | 25 | it('build accept profile', async () => { 26 | const expectedAccept = [ 27 | 'iden3comm/v1;env=application/iden3-zkp-json;circuitId=authV2,authV3;alg=groth16', 28 | 'iden3comm/v1;env=application/iden3comm-signed-json;alg=ES256K-R' 29 | ]; 30 | 31 | const accept = buildAccept([ 32 | { 33 | protocolVersion: ProtocolVersion.V1, 34 | env: MediaType.ZKPMessage, 35 | circuits: [AcceptAuthCircuits.AuthV2, AcceptAuthCircuits.AuthV3], 36 | alg: [AcceptJwzAlgorithms.Groth16] 37 | }, 38 | { 39 | protocolVersion: ProtocolVersion.V1, 40 | env: MediaType.SignedMessage, 41 | alg: [AcceptJwsAlgorithms.ES256KR] 42 | } 43 | ]); 44 | expect(expectedAccept).to.be.deep.eq(accept); 45 | }); 46 | 47 | it('not supported protocol version', async () => { 48 | const expectedAcceptProfile = 49 | 'iden3comm/v0.1;env=application/iden3-zkp-json;circuitId=authV2,authV3;alg=groth16'; 50 | expect(() => parseAcceptProfile(expectedAcceptProfile)).to.throw( 51 | `Protocol version 'iden3comm/v0.1' not supported` 52 | ); 53 | }); 54 | 55 | it('not supported envelop', async () => { 56 | const acceptProfile = 'iden3comm/v1;env=application/iden3-zkt-json'; 57 | expect(() => parseAcceptProfile(acceptProfile)).to.throw( 58 | `Envelop 'application/iden3-zkt-json' not supported` 59 | ); 60 | }); 61 | 62 | it('invalid alg for jwz', async () => { 63 | const acceptProfile = 'iden3comm/v1;env=application/iden3-zkp-json;alg=ES256K-R'; 64 | expect(() => parseAcceptProfile(acceptProfile)).to.throw( 65 | `Algorithm 'ES256K-R' not supported for 'application/iden3-zkp-json` 66 | ); 67 | }); 68 | 69 | it('circuits for jws', async () => { 70 | const acceptProfile = 'iden3comm/v1;env=application/iden3comm-signed-json;circuitId=authV2'; 71 | expect(() => parseAcceptProfile(acceptProfile)).to.throw( 72 | `Circuits not supported for env 'application/iden3comm-signed-json'` 73 | ); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /tests/iden3comm/packageManager.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DataPrepareHandlerFunc, 3 | PackageManager, 4 | PlainPacker, 5 | VerificationHandlerFunc, 6 | ZKPPacker 7 | } from '../../src/iden3comm/index'; 8 | import { mockPrepareAuthInputs, mockVerifyState, ProvingMethodGroth16Authv2 } from './mock/proving'; 9 | import { proving, ProvingMethodAlg, ProvingMethod } from '@iden3/js-jwz'; 10 | import { DID } from '@iden3/js-iden3-core'; 11 | import { 12 | CredentialFetchRequestMessage, 13 | ProvingParams, 14 | VerificationParams 15 | } from '../../src/iden3comm/types'; 16 | import { MediaType, PROTOCOL_MESSAGE_TYPE } from '../../src/iden3comm/constants'; 17 | import { byteDecoder, byteEncoder } from '../../src'; 18 | 19 | const { registerProvingMethod } = proving; 20 | import { expect } from 'chai'; 21 | describe('tests packageManager with ZKP Packer', () => { 22 | it('tests package manager with zkp packer', async () => { 23 | const pm = new PackageManager(); 24 | const mockAuthInputsHandler = new DataPrepareHandlerFunc(mockPrepareAuthInputs); 25 | 26 | const mockProvingMethod = new ProvingMethodGroth16Authv2( 27 | new ProvingMethodAlg('groth16-mock', 'authV2') 28 | ); 29 | 30 | await registerProvingMethod(mockProvingMethod.methodAlg, (): ProvingMethod => { 31 | return mockProvingMethod; 32 | }); 33 | 34 | const verificationFn = new VerificationHandlerFunc(mockVerifyState); 35 | const mapKey = mockProvingMethod.methodAlg.toString(); 36 | 37 | const mockVerificationParamMap: Map = new Map(); 38 | mockVerificationParamMap.set(mapKey, { 39 | key: new Uint8Array([]), 40 | verificationFn 41 | }); 42 | 43 | const mockProvingParamMap: Map = new Map(); 44 | mockProvingParamMap.set(mapKey, { 45 | dataPreparer: mockAuthInputsHandler, 46 | provingKey: new Uint8Array([]), 47 | wasm: new Uint8Array([]) 48 | }); 49 | 50 | const p = new ZKPPacker(mockProvingParamMap, mockVerificationParamMap); 51 | 52 | pm.registerPackers([p]); 53 | 54 | const identifier = 'did:iden3:polygon:mumbai:x4jcHP4XHTK3vX58AHZPyHE8kYjneyE6FZRfz7K29'; 55 | const senderDID = DID.parse(identifier); 56 | 57 | const targetIdentifier = 'did:iden3:polygon:mumbai:wzWeGdtjvKtUP1oTxQP5t5iZGDX3HNfEU5xR8MZAt'; 58 | const targetID = DID.parse(targetIdentifier); 59 | 60 | const msgBytes = byteEncoder.encode( 61 | JSON.stringify(createFetchCredentialMessage(MediaType.ZKPMessage, senderDID, targetID)) 62 | ); 63 | 64 | const e = await pm.pack(MediaType.ZKPMessage, msgBytes, { 65 | senderDID, 66 | provingMethodAlg: new ProvingMethodAlg('groth16-mock', 'authV2') 67 | }); 68 | 69 | const { unpackedMessage, unpackedMediaType } = await pm.unpack(e); 70 | expect(unpackedMediaType).to.deep.equal(MediaType.ZKPMessage); 71 | expect(senderDID.string()).to.deep.equal(unpackedMessage.from); 72 | expect(byteDecoder.decode(msgBytes)).to.deep.equal(JSON.stringify(unpackedMessage)); 73 | }); 74 | 75 | it('test getSupportedProfiles', () => { 76 | const pm = new PackageManager(); 77 | pm.registerPackers([new ZKPPacker(new Map(), new Map()), new PlainPacker()]); 78 | const supportedProfiles = pm.getSupportedProfiles(); 79 | expect(supportedProfiles.length).to.be.eq(2); 80 | expect(supportedProfiles).to.include( 81 | `iden3comm/v1;env=${MediaType.ZKPMessage};alg=groth16;circuitIds=authV2` 82 | ); 83 | expect(supportedProfiles).to.include(`iden3comm/v1;env=${MediaType.PlainMessage}`); 84 | }); 85 | }); 86 | 87 | const createFetchCredentialMessage = (typ: MediaType, from: DID, to: DID) => { 88 | const msg: CredentialFetchRequestMessage = { 89 | id: '', 90 | from: from.string(), 91 | to: to.string(), 92 | typ: typ, 93 | type: PROTOCOL_MESSAGE_TYPE.CREDENTIAL_FETCH_REQUEST_MESSAGE_TYPE, 94 | body: { 95 | id: '' 96 | } 97 | }; 98 | 99 | return msg; 100 | }; 101 | -------------------------------------------------------------------------------- /tests/kms/kms.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { 3 | AbstractPrivateKeyStore, 4 | InMemoryPrivateKeyStore, 5 | KmsKeyType, 6 | Sec256k1Provider, 7 | Ed25519Provider, 8 | IKeyProvider, 9 | bytesToHex, 10 | BjjProvider 11 | } from '../../src'; 12 | import { getRandomBytes } from '@iden3/js-crypto'; 13 | import { BytesHelper, Constants } from '@iden3/js-iden3-core'; 14 | 15 | const testFlow = async (provider: IKeyProvider) => { 16 | const seed1 = getRandomBytes(32); 17 | const seed2 = getRandomBytes(32); 18 | expect(seed1).to.not.deep.equal(seed2); 19 | let dataToSign1 = getRandomBytes(32); 20 | let dataToSign2 = getRandomBytes(32); 21 | if (provider instanceof BjjProvider) { 22 | // because challenge should be in the finite field of Constant.Q 23 | dataToSign1 = BytesHelper.intToBytes(Constants.Q - 1n); 24 | dataToSign2 = BytesHelper.intToBytes(Constants.Q - 100n); 25 | } 26 | const [keyId1, keyId2, keyId3] = await Promise.all([ 27 | provider.newPrivateKeyFromSeed(seed1), 28 | provider.newPrivateKeyFromSeed(seed2), 29 | provider.newPrivateKeyFromSeed(seed1) 30 | ]); 31 | 32 | const providerKeys = await provider.list(); 33 | expect(providerKeys.length).to.equal(2); 34 | expect(providerKeys[0].alias).to.include(provider.keyType); 35 | expect(providerKeys[1].alias).to.include(provider.keyType); 36 | 37 | const [signature1, signature2, signature3] = await Promise.all([ 38 | provider.sign(keyId1, dataToSign1), 39 | provider.sign(keyId2, dataToSign2), 40 | provider.sign(keyId3, dataToSign1) 41 | ]); 42 | const [isPublicKey1Valid, isPublicKey2Valid, isPublicKey3Valid] = await Promise.all([ 43 | provider.verify(dataToSign1, bytesToHex(signature1), keyId1), 44 | provider.verify(dataToSign2, bytesToHex(signature2), keyId2), 45 | provider.verify(dataToSign1, bytesToHex(signature3), keyId3) 46 | ]); 47 | expect(signature1).to.not.deep.equal(signature2); 48 | expect(signature1).to.deep.equal(signature3); 49 | expect(isPublicKey1Valid).to.be.true; 50 | expect(isPublicKey2Valid).to.be.true; 51 | expect(isPublicKey3Valid).to.be.true; 52 | }; 53 | 54 | describe('Key store providers', () => { 55 | it('should signatures be valid and equal for the same data and private key', async () => { 56 | const keyStore: AbstractPrivateKeyStore = new InMemoryPrivateKeyStore(); 57 | const ed25519Provider = new Ed25519Provider(KmsKeyType.Ed25519, keyStore); 58 | const secp256k1Provider = new Sec256k1Provider(KmsKeyType.Secp256k1, keyStore); 59 | const bjjProvider = new BjjProvider(KmsKeyType.BabyJubJub, keyStore); 60 | await Promise.all([ 61 | testFlow(bjjProvider), 62 | testFlow(ed25519Provider), 63 | testFlow(secp256k1Provider) 64 | ]); 65 | const allKeys = await keyStore.list(); 66 | expect(allKeys.length).to.equal(6); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /tests/proofs/common.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { parseQueryMetadata } from '../../src'; 3 | import { schemaLoaderForTests } from '../mocks/schema'; 4 | 5 | describe('parseQueryMetadata', () => { 6 | const ldContext = 7 | '{"@context":[{"@version":1.1,"@protected":true,"id":"@id","type":"@type","KYCAgeCredential":{"@id":"https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld#KYCAgeCredential","@context":{"@version":1.1,"@protected":true,"id":"@id","type":"@type","kyc-vocab":"https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#","xsd":"http://www.w3.org/2001/XMLSchema#","birthday":{"@id":"kyc-vocab:birthday","@type":"xsd:integer"},"documentType":{"@id":"kyc-vocab:documentType","@type":"xsd:integer"}}},"KYCCountryOfResidenceCredential":{"@id":"https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld#KYCCountryOfResidenceCredential","@context":{"@version":1.1,"@protected":true,"id":"@id","type":"@type","kyc-vocab":"https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#","xsd":"http://www.w3.org/2001/XMLSchema#","countryCode":{"@id":"kyc-vocab:countryCode","@type":"xsd:integer"},"documentType":{"@id":"kyc-vocab:documentType","@type":"xsd:integer"}}}}]}'; 8 | const ipfsNodeURL = process.env.IPFS_URL as string; 9 | const merklizeOpts = { 10 | documentLoader: schemaLoaderForTests({ 11 | ipfsNodeURL 12 | }) 13 | }; 14 | it('parseQueryMetadata with NOOP/SD operators and "" as operatorValue should return 0 arr values', async () => { 15 | const { values } = await parseQueryMetadata( 16 | { 17 | fieldName: '', 18 | operator: 0, 19 | operatorValue: '' 20 | }, 21 | ldContext, 22 | 'KYCAgeCredential', 23 | merklizeOpts 24 | ); 25 | 26 | expect(values.length).to.be.eq(0); 27 | 28 | const { values: valuesFromSd } = await parseQueryMetadata( 29 | { 30 | fieldName: 'documentType', 31 | operator: 16, 32 | operatorValue: '' 33 | }, 34 | ldContext, 35 | 'KYCAgeCredential', 36 | merklizeOpts 37 | ); 38 | 39 | expect(valuesFromSd.length).to.be.eq(0); 40 | }); 41 | 42 | it('parseQueryMetadata with NOOP/SD operators and not empty operatorValue should throw', async () => { 43 | await expect( 44 | parseQueryMetadata( 45 | { 46 | fieldName: '', 47 | operator: 0, 48 | operatorValue: '123' 49 | }, 50 | ldContext, 51 | 'KYCAgeCredential', 52 | merklizeOpts 53 | ) 54 | ).to.be.rejectedWith('operator value should be undefined for 0 operator'); 55 | 56 | await expect( 57 | parseQueryMetadata( 58 | { 59 | fieldName: 'documentType', 60 | operator: 16, 61 | operatorValue: '123' 62 | }, 63 | ldContext, 64 | 'KYCAgeCredential', 65 | merklizeOpts 66 | ) 67 | ).to.be.rejectedWith('operator value should be undefined for 16 operator'); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /tests/schema-processor/data/jsonld/non-merklized-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "http://example.edu/credentials/3732", 3 | "@context": [ 4 | "https://www.w3.org/2018/credentials/v1", 5 | "https://example.com/schema-delivery-address.json-ld" 6 | ], 7 | "type": [ 8 | "VerifiableCredential", 9 | "DeliverAddressMultiTestForked" 10 | ], 11 | "credentialSubject": { 12 | "type": "DeliverAddressMultiTestForked", 13 | "price": "123.52", 14 | "isPostalProvider": false, 15 | "postalProviderInformation": { 16 | "insured": true, 17 | "weight": "1.3" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/schema-processor/data/jsonld/schema-delivery-address.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | { 4 | "@protected": true, 5 | "@version": 1.1, 6 | "id": "@id", 7 | "type": "@type", 8 | "DeliverAddressMultiTestForked": { 9 | "@context": { 10 | "@propagate": true, 11 | "@protected": true, 12 | "iden3_serialization": "iden3:v1:slotIndexA=price&slotValueB=postalProviderInformation.insured", 13 | "polygon-vocab": "urn:uuid:77157331-176d-4b84-814b-98ac52a1b870#", 14 | "xsd": "http://www.w3.org/2001/XMLSchema#", 15 | "operatorId": { 16 | "@id": "polygon-vocab:operatorId", 17 | "@type": "xsd:integer" 18 | }, 19 | "country": { 20 | "@id": "polygon-vocab:country", 21 | "@type": "xsd:string" 22 | }, 23 | "price": { 24 | "@id": "polygon-vocab:price", 25 | "@type": "xsd:double" 26 | }, 27 | "deliveryTime": { 28 | "@id": "polygon-vocab:deliveryTime", 29 | "@type": "xsd:dateTime" 30 | }, 31 | "isPostalProvider": { 32 | "@id": "polygon-vocab:isPostalProvider", 33 | "@type": "xsd:boolean" 34 | }, 35 | "postalProviderInformation": { 36 | "@context": { 37 | "insured": { 38 | "@id": "polygon-vocab:insured", 39 | "@type": "xsd:boolean" 40 | }, 41 | "weight": { 42 | "@id": "polygon-vocab:weight", 43 | "@type": "xsd:double" 44 | }, 45 | "name": { 46 | "@id": "polygon-vocab:name", 47 | "@type": "xsd:string" 48 | }, 49 | "officeNo": { 50 | "@id": "polygon-vocab:officeNo", 51 | "@type": "xsd:integer" 52 | }, 53 | "expectedExpirationDate": { 54 | "@id": "polygon-vocab:expectedExpirationDate", 55 | "@type": "xsd:dateTime" 56 | }, 57 | "isPerishable": { 58 | "@id": "polygon-vocab:isPerishable", 59 | "@type": "xsd:boolean" 60 | } 61 | }, 62 | "@id": "polygon-vocab:postalProviderInformation" 63 | }, 64 | "homeAddress": { 65 | "@context": { 66 | "expectedFrom": { 67 | "@id": "polygon-vocab:expectedFrom", 68 | "@type": "xsd:dateTime" 69 | }, 70 | "line2": { 71 | "@id": "polygon-vocab:line2", 72 | "@type": "xsd:string" 73 | }, 74 | "line1": { 75 | "@id": "polygon-vocab:line1", 76 | "@type": "xsd:string" 77 | } 78 | }, 79 | "@id": "polygon-vocab:homeAddress" 80 | } 81 | }, 82 | "@id": "urn:uuid:ac2ede19-b3b9-454d-b1a9-a7b3d5763100" 83 | } 84 | } 85 | ] 86 | } 87 | -------------------------------------------------------------------------------- /tests/schema-processor/data/kyc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "$metadata": { 5 | "uris": { 6 | "jsonLdContext": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld", 7 | "jsonSchema": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCEmployee-v101.json" 8 | } 9 | }, 10 | "required": [ 11 | "@context", 12 | "id", 13 | "type", 14 | "issuanceDate", 15 | "credentialSubject", 16 | "credentialSchema", 17 | "credentialStatus", 18 | "issuer" 19 | ], 20 | "properties": { 21 | "@context": { 22 | "type": [ 23 | "string", 24 | "array", 25 | "object" 26 | ] 27 | }, 28 | "id": { 29 | "type": "string" 30 | }, 31 | "type": { 32 | "type": [ 33 | "string", 34 | "array" 35 | ], 36 | "items": { 37 | "type": "string" 38 | } 39 | }, 40 | "issuer": { 41 | "type": [ 42 | "string", 43 | "object" 44 | ], 45 | "format": "uri", 46 | "required": [ 47 | "id" 48 | ], 49 | "properties": { 50 | "id": { 51 | "type": "string", 52 | "format": "uri" 53 | } 54 | } 55 | }, 56 | "issuanceDate": { 57 | "type": "string", 58 | "format": "date-time" 59 | }, 60 | "expirationDate": { 61 | "type": "string", 62 | "format": "date-time" 63 | }, 64 | "credentialSchema": { 65 | "type": "object", 66 | "required": [ 67 | "id", 68 | "type" 69 | ], 70 | "properties": { 71 | "id": { 72 | "type": "string", 73 | "format": "uri" 74 | }, 75 | "type": { 76 | "type": "string" 77 | } 78 | } 79 | }, 80 | "subjectPosition": { 81 | "type": "string", 82 | "enum": [ 83 | "none", 84 | "index", 85 | "value" 86 | ] 87 | }, 88 | "merklizationRootPosition": { 89 | "type": "string", 90 | "enum": [ 91 | "none", 92 | "index", 93 | "value" 94 | ] 95 | }, 96 | "revNonce": { 97 | "type": "integer" 98 | }, 99 | "version": { 100 | "type": "integer" 101 | }, 102 | "updatable": { 103 | "type": "boolean" 104 | }, 105 | "credentialSubject": { 106 | "type": "object", 107 | "required": [ 108 | "id", 109 | "documentType" 110 | ], 111 | "properties": { 112 | "id": { 113 | "title": "Credential Subject ID", 114 | "type": "string", 115 | "format": "uri" 116 | }, 117 | "ZKPexperiance": { 118 | "type": "boolean" 119 | }, 120 | "hireDate": { 121 | "type": "string" 122 | }, 123 | "position": { 124 | "type": "string" 125 | }, 126 | "salary": { 127 | "type": "number" 128 | }, 129 | "documentType": { 130 | "type": "integer" 131 | } 132 | } 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /tests/schema-processor/data/list-of-ld-contexts.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | { 4 | "@version": 1.1, 5 | "@protected": true, 6 | "id": "@id", 7 | "type": "@type", 8 | "KYCAgeCredential": { 9 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCAgeCredential", 10 | "@context": { 11 | "@version": 1.1, 12 | "@protected": true, 13 | "id": "@id", 14 | "type": "@type", 15 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 16 | "xsd": "http://www.w3.org/2001/XMLSchema#", 17 | "birthday": { 18 | "@id": "kyc-vocab:birthday", 19 | "@type": "xsd:integer" 20 | }, 21 | "documentType": { 22 | "@id": "kyc-vocab:documentType", 23 | "@type": "xsd:integer" 24 | } 25 | } 26 | }, 27 | "KYCCountryOfResidenceCredential": { 28 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCCountryOfResidenceCredential", 29 | "@context": { 30 | "@version": 1.1, 31 | "@protected": true, 32 | "id": "@id", 33 | "type": "@type", 34 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 35 | "xsd": "http://www.w3.org/2001/XMLSchema#", 36 | "countryCode": { 37 | "@id": "kyc-vocab:countryCode", 38 | "@type": "xsd:integer" 39 | }, 40 | "documentType": { 41 | "@id": "kyc-vocab:documentType", 42 | "@type": "xsd:integer" 43 | } 44 | } 45 | }, 46 | "KYCEmployee": { 47 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCEmployee", 48 | "@context": { 49 | "@version": 1.1, 50 | "@protected": true, 51 | "id": "@id", 52 | "type": "@type", 53 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 54 | "xsd": "http://www.w3.org/2001/XMLSchema#", 55 | "documentType": { 56 | "@id": "kyc-vocab:documentType", 57 | "@type": "xsd:integer" 58 | }, 59 | "ZKPexperiance": { 60 | "@id": "kyc-vocab:hasZKPexperiance", 61 | "@type": "xsd:boolean" 62 | }, 63 | "hireDate": { 64 | "@id": "kyc-vocab:hireDate", 65 | "@type": "xsd:dateTime" 66 | }, 67 | "position": { 68 | "@id": "kyc-vocab:position", 69 | "@type": "xsd:string" 70 | }, 71 | "salary": { 72 | "@id": "kyc-vocab:salary", 73 | "@type": "xsd:double" 74 | } 75 | } 76 | } 77 | } 78 | ] 79 | } -------------------------------------------------------------------------------- /tests/schema-processor/data/list-with-single-ld-context.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | { 4 | "@version": 1.1, 5 | "@protected": true, 6 | "id": "@id", 7 | "type": "@type", 8 | "KYCAgeCredential": { 9 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCAgeCredential", 10 | "@context": { 11 | "@version": 1.1, 12 | "@protected": true, 13 | "id": "@id", 14 | "type": "@type", 15 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 16 | "xsd": "http://www.w3.org/2001/XMLSchema#", 17 | "birthday": { 18 | "@id": "kyc-vocab:birthday", 19 | "@type": "xsd:integer" 20 | }, 21 | "documentType": { 22 | "@id": "kyc-vocab:documentType", 23 | "@type": "xsd:integer" 24 | } 25 | } 26 | } 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /tests/schema-processor/data/single-ld-context.json: -------------------------------------------------------------------------------- 1 | { 2 | "@version": 1.1, 3 | "@protected": true, 4 | "id": "@id", 5 | "type": "@type", 6 | "KYCAgeCredential": { 7 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCAgeCredential", 8 | "@context": { 9 | "@version": 1.1, 10 | "@protected": true, 11 | "id": "@id", 12 | "type": "@type", 13 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 14 | "xsd": "http://www.w3.org/2001/XMLSchema#", 15 | "birthday": { 16 | "@id": "kyc-vocab:birthday", 17 | "@type": "xsd:integer" 18 | }, 19 | "documentType": { 20 | "@id": "kyc-vocab:documentType", 21 | "@type": "xsd:integer" 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /tests/schema-processor/json-validator.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-floating-promises */ 2 | import { DIDDocumentJSONSchema, JsonSchemaValidator, byteEncoder } from '../../src'; 3 | import chai from 'chai'; 4 | import chaiAsPromised from 'chai-as-promised'; 5 | import { cred07, cred20, schema07, schema2020 } from './data/json-validator-data'; 6 | 7 | chai.use(chaiAsPromised); 8 | const { expect } = chai; 9 | 10 | describe('json validator', () => { 11 | it('test validator validate', async () => { 12 | const jsonDIDDocument = `{"service":[{"id":"did:example:123#linked-domain","type":"LinkedDomains","serviceEndpoint":"https://bar.example.com"},{"id":"did:example:123#linked-domain","type":"push-notification","metadata":{"devices":[{"ciphertext":"base64encoded","alg":"rsa"}]},"serviceEndpoint":"https://bar.example.com"}],"id":"did:example:123#linked-domain"}`; 13 | const v = new JsonSchemaValidator(); 14 | const jsonDIDDocumentBytes = byteEncoder.encode(jsonDIDDocument); 15 | const dataBytes = byteEncoder.encode(DIDDocumentJSONSchema); 16 | const result = await v.validate(jsonDIDDocumentBytes, dataBytes); 17 | expect(result).to.be.true; 18 | }); 19 | 20 | it('test validator validateNoTypeInService', () => { 21 | // no type in did document service 22 | const jsonDIDDocument = `{"service":[{"id":"did:example:123#linked-domain","serviceEndpoint":"https://bar.example.com"},{"id":"did:example:123#linked-domain","type":"push-notification","metadata":{"devices":[{"ciphertext":"base64encoded","alg":"rsa"}]},"serviceEndpoint":"https://bar.example.com"}],"id":"did:example:123#linked-domain"}`; 23 | 24 | const v = new JsonSchemaValidator(); 25 | const jsonDIDDocumentBytes = byteEncoder.encode(jsonDIDDocument); 26 | const dataBytes = byteEncoder.encode(DIDDocumentJSONSchema); 27 | expect(v.validate(jsonDIDDocumentBytes, dataBytes)).to.be.rejectedWith( 28 | "should have required property 'type'" 29 | ); 30 | }); 31 | 32 | it('test validator validateNoIDinDocument', () => { 33 | // no type in did document service 34 | const jsonDIDDocument = `{"service":[{"id":"did:example:123#linked-domain","type":"LinkedDomains","serviceEndpoint":"https://bar.example.com"},{"id":"did:example:123#linked-domain","type":"push-notification","metadata":{"devices":[{"ciphertext":"base64encoded","alg":"rsa"}]},"serviceEndpoint":"https://bar.example.com"}]}`; 35 | const v = new JsonSchemaValidator(); 36 | const jsonDIDDocumentBytes = byteEncoder.encode(jsonDIDDocument); 37 | const dataBytes = byteEncoder.encode(DIDDocumentJSONSchema); 38 | expect(v.validate(jsonDIDDocumentBytes, dataBytes)).to.be.rejectedWith( 39 | "should have required property 'id'" 40 | ); 41 | }); 42 | it('TestValidator_ValidateDraft07', async () => { 43 | const v = new JsonSchemaValidator(); 44 | const result = await v.validate(byteEncoder.encode(cred07), byteEncoder.encode(schema07)); 45 | expect(result).to.be.true; 46 | }); 47 | 48 | it('TestValidator_ValidateDraft2020', async () => { 49 | const v = new JsonSchemaValidator(); 50 | const result = await v.validate(byteEncoder.encode(cred20), byteEncoder.encode(schema2020)); 51 | expect(result).to.be.true; 52 | }); 53 | 54 | it('TestValidatorWithInvalidField', async () => { 55 | const schema = byteEncoder.encode( 56 | '{"type":"object","required":["documentType","birthday"],"properties":{"documentType":{"type":"integer"},"birthday":{"type":"integer"}}}' 57 | ); 58 | 59 | const data = byteEncoder.encode(`{"documentType": 1}`); 60 | const validator = new JsonSchemaValidator(); 61 | await expect(validator.validate(data, schema)).to.be.rejectedWith( 62 | `must have required property 'birthday'` 63 | ); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist/cjs", 4 | "module": "ES2020", 5 | "target": "es2020", 6 | "moduleResolution": "Node", 7 | "resolveJsonModule": true, 8 | "allowSyntheticDefaultImports": true, 9 | "allowJs": true, 10 | "esModuleInterop": true, 11 | "skipLibCheck": true, 12 | "strict": true, 13 | "typeRoots": ["node_modules/@types"] 14 | }, 15 | "include": ["src", "types"] 16 | } 17 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src", "tests"] 4 | } 5 | -------------------------------------------------------------------------------- /types/ffjavascript.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'ffjavascript' { 2 | export function getCurveFromName(name: string): Promise<{ terminate: () => void }>; 3 | } 4 | -------------------------------------------------------------------------------- /types/jsonld/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'jsonld/lib' { 2 | function processContext( 3 | activeCtx: unknown, 4 | localCtx: unknown, 5 | opts: unknown 6 | ): Promise<{ mappings: Map> }>; 7 | } 8 | 9 | declare module 'jsonld/lib/context' { 10 | function getInitialContext(opts: unknown): Map; 11 | } 12 | -------------------------------------------------------------------------------- /types/snarkjs.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'snarkjs' { 2 | export namespace groth16 { 3 | export function verify(verKey: object, pubSignals: string[], proof: object): Promise; 4 | 5 | export function prove( 6 | provingKey: object, 7 | wtnsBytes: object 8 | ): Promise<{ 9 | proof: { pi_a: string[]; pi_b: string[][]; pi_c: string[]; protocol: string }; 10 | publicSignals: string[]; 11 | }>; 12 | } 13 | } 14 | --------------------------------------------------------------------------------