Skip to content

Conversation

@transphorm
Copy link
Member

@transphorm transphorm commented Aug 13, 2025

Summary

  • port register TEE input generator accepting environment and DSC tree
  • port disclose TEE input generator using passed OFAC and commitment trees
  • expose helpers via package index and add unit tests

Testing

  • yarn workspace @selfxyz/mobile-sdk-alpha nice
  • yarn workspace @selfxyz/mobile-sdk-alpha build
  • yarn workspace @selfxyz/mobile-sdk-alpha types
  • yarn workspace @selfxyz/mobile-sdk-alpha test
  • yarn lint
  • yarn build

https://chatgpt.com/codex/tasks/task_b_689c068145d8832d9c9c7425db710527

Summary by CodeRabbit

  • New Features

    • Added APIs to generate TEE inputs for disclose and register flows, expanding the mobile SDK’s proving capabilities. Supports multiple document types and returns inputs with circuit and endpoint metadata.
  • Tests

    • Added unit tests validating the new disclose and register input generators, including environment-specific endpoint handling.
  • Chores

    • Added dependencies to support ZK components, shared workspace utilities, and hashing, improving cryptographic and tree-handling capabilities without altering existing behavior.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 13, 2025

Walkthrough

Adds zk-kit and shared workspace dependencies. Extends the mobile SDK public API by exporting two new TEE input generators. Implements generateTEEInputsDisclose and generateTEEInputsRegister to assemble circuit inputs and endpoint metadata. Introduces unit tests for both functions with mocked dependencies. No removals or breaking API changes.

Changes

Cohort / File(s) Summary
Dependencies
packages/mobile-sdk-alpha/package.json
Adds dependencies: @openpassport/zk-kit-lean-imt, @openpassport/zk-kit-smt, @selfxyz/common (workspace), poseidon-lite.
Public API Barrel
packages/mobile-sdk-alpha/src/index.ts
Re-exports generateTEEInputsDisclose and generateTEEInputsRegister.
Proving Input Generators
packages/mobile-sdk-alpha/src/proving/discloseInputs.ts, packages/mobile-sdk-alpha/src/proving/registerInputs.ts
New modules to build TEE inputs for disclose and register circuits, selecting circuit names, endpoint types, and integrating SMT/IMT trees and hashing utilities.
Tests
packages/mobile-sdk-alpha/tests/proving/*
New Vitest suites for discloseInputs and registerInputs with mocks, asserting output shape and calls.

Sequence Diagram(s)

sequenceDiagram
  actor App
  participant Disclose as generateTEEInputsDisclose
  participant Utils as Hash/Selectors Utils
  participant Trees as SMT/LeanIMT
  participant Circuit as generateCircuitInputsVCandDisclose

  App->>Disclose: (secret, passportData, selfApp, ofacTrees, commitmentTree)
  Disclose->>Utils: calculateUserIdentifierHash / hashEndpointWithScope
  Disclose->>Utils: build DG1 selectors (doc-type specific)
  Disclose->>Trees: Import OFAC SMTs + commitment LeanIMT
  Disclose->>Circuit: generateCircuitInputsVCandDisclose(...)
  Circuit-->>Disclose: inputs
  Disclose-->>App: { inputs, circuitName, endpointType, endpoint }
Loading
sequenceDiagram
  actor App
  participant Register as generateTEEInputsRegister
  participant Circuit as generateCircuitInputsRegister
  participant Utils as getCircuitNameFromPassportData

  App->>Register: (secret, passportData, dscTree, env)
  Register->>Circuit: generateCircuitInputsRegister(...)
  Circuit-->>Register: inputs
  Register->>Utils: getCircuitNameFromPassportData(passportData, "register")
  Register-->>App: { inputs, circuitName, endpointType(env), endpoint }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • fix euid #685: Parallel change adding env parameter to generateTEEInputsRegister to derive endpointType.
  • App/eu id updates #638: Implements related hashing, selector logic, and circuit naming used by the new disclose/register inputs.

Suggested reviewers

  • seshanthS
  • motemotech
  • remicolin

Poem

New circuits hum with hashed intent,
Selectors map what we present.
Trees import roots, secrets flow,
Endpoints set where proofs will go.
Tests stand guard, concise and bright—
Disclose and Register take flight. ✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/work-on-proof-input-generation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@transphorm transphorm marked this pull request as ready for review August 13, 2025 03:50
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (6)
packages/mobile-sdk-alpha/src/index.ts (1)

40-41: Optional: Export typed return aliases for API stability.

Consider exporting a shared return type (e.g., TEEInputsResponse) from the helpers and re-export it here. It hardens API contracts and improves DX.

packages/mobile-sdk-alpha/tests/proving/discloseInputs.test.ts (1)

26-53: Expand coverage: test non-passport flow, age/OFAC selectors, and tree/SMT wiring.

Current test validates the happy-path for passport. Add:

  • An id_card path asserting circuitName = 'vc_and_disclose_id'.
  • Minimum age selector toggling (selector_older_than and majority).
  • OFAC selector on/off behavior.
  • Basic assertions that LeanIMT.import is invoked with a hash function and commitmentTree and SMT instances import provided trees.

Apply this diff to enhance coverage (imports plus additional tests):

@@
-import { generateTEEInputsDisclose } from '../../src';
+import { generateTEEInputsDisclose } from '../../src';
+import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
+import { SMT } from '@openpassport/zk-kit-smt';
@@
   it('builds disclose inputs with endpoint info', () => {
@@
   });
+
+  it('builds disclose inputs for id_card (no passport SMT)', () => {
+    const passportData = { documentCategory: 'id_card' } as PassportData;
+    const selfApp = {
+      scope: 's',
+      disclosures: {},
+      endpoint: 'https://e',
+      endpointType: 'https',
+      userId: 'u',
+      userDefinedData: '0x0',
+      chainID: 1,
+    } as any;
+    const ofacTrees = { nameAndDob: [], nameAndYob: [] } as any;
+    const commitmentTree = [['0']];
+    const result = generateTEEInputsDisclose('sec', passportData, selfApp as SelfApp, ofacTrees, commitmentTree as any);
+    expect(result.circuitName).toBe('vc_and_disclose_id');
+    expect(result.endpointType).toBe('https');
+    expect(result.endpoint).toBe('https://e');
+  });
+
+  it('respects minimumAge and ofac disclosures', () => {
+    const passportData = { documentCategory: 'passport' } as PassportData;
+    const selfApp = {
+      scope: 's',
+      disclosures: { minimumAge: 21, ofac: true, excludedCountries: ['IR'] },
+      endpoint: 'https://e',
+      endpointType: 'https',
+      userId: 'u',
+      userDefinedData: '0x0',
+      chainID: 1,
+    } as any;
+    const ofacTrees = {
+      passportNoAndNationality: [],
+      nameAndDob: [],
+      nameAndYob: [],
+    } as any;
+    const commitmentTree = [['0']];
+    const result = generateTEEInputsDisclose('sec', passportData, selfApp as SelfApp, ofacTrees, commitmentTree as any);
+    expect(result.circuitName).toBe('vc_and_disclose');
+    // Lightly assert internals wiring without over-coupling:
+    expect(LeanIMT.import).toHaveBeenCalledWith(expect.any(Function), commitmentTree);
+    expect((SMT as any).mock.calls.length).toBeGreaterThanOrEqual(3);
+  });
packages/mobile-sdk-alpha/tests/proving/registerInputs.test.ts (1)

13-26: Add prod-path test to cover endpointType mapping.

Currently only 'stg' is covered. Add a test with env 'prod' expecting endpointType 'celo'.

Apply this diff to add the extra case:

@@
 describe('generateTEEInputsRegister', () => {
   it('builds register inputs with endpoint info', () => {
@@
   });
+
+  it('maps env=prod to celo endpointType', () => {
+    const passportData = { documentCategory: 'passport' } as PassportData;
+    const result = generateTEEInputsRegister('sec', passportData, 'tree', 'prod');
+    expect(result.endpointType).toBe('celo');
+    expect(result.endpoint).toBe('https://self.xyz');
+  });
 });
packages/mobile-sdk-alpha/src/proving/registerInputs.ts (1)

10-14: Consider centralizing endpoint/env mapping.

If other helpers (e.g., disclose) expose the same metadata, factor endpoint and endpointType resolution into a shared util to avoid drift.

packages/mobile-sdk-alpha/src/proving/discloseInputs.ts (2)

88-100: Consider extracting the special attributes list as a constant

The list of special attributes ['ofac', 'excludedCountries', 'minimumAge'] is duplicated in both getSelectorDg1Passport and getSelectorDg1IdCard. This violates the DRY principle.

+const SPECIAL_DISCLOSURE_ATTRIBUTES = ['ofac', 'excludedCountries', 'minimumAge'] as const;
+
 function getSelectorDg1Passport(disclosures: SelfAppDisclosureConfig) {
   const selector_dg1 = Array(88).fill('0');
   Object.entries(disclosures).forEach(([attribute, reveal]) => {
-    if (['ofac', 'excludedCountries', 'minimumAge'].includes(attribute)) {
+    if (SPECIAL_DISCLOSURE_ATTRIBUTES.includes(attribute as any)) {
       return;
     }

And apply the same change to getSelectorDg1IdCard on line 105.


44-52: Memory optimization opportunity for SMT initialization

The SMT objects are always created even when not needed (e.g., passportNoAndNationalitySMT for ID cards). Consider lazy initialization.

-  let passportNoAndNationalitySMT: SMT | null = null;
-  const nameAndDobSMT = new SMT(poseidon2, true);
-  const nameAndYobSMT = new SMT(poseidon2, true);
-  if (document === 'passport') {
-    passportNoAndNationalitySMT = new SMT(poseidon2, true);
-    passportNoAndNationalitySMT.import(ofacTrees.passportNoAndNationality);
-  }
-  nameAndDobSMT.import(ofacTrees.nameAndDob);
-  nameAndYobSMT.import(ofacTrees.nameAndYob);
+  // Initialize SMTs only when needed
+  const nameAndDobSMT = new SMT(poseidon2, true);
+  nameAndDobSMT.import(ofacTrees.nameAndDob);
+  
+  const nameAndYobSMT = new SMT(poseidon2, true);
+  nameAndYobSMT.import(ofacTrees.nameAndYob);
+  
+  let passportNoAndNationalitySMT: SMT | null = null;
+  if (document === 'passport') {
+    passportNoAndNationalitySMT = new SMT(poseidon2, true);
+    passportNoAndNationalitySMT.import(ofacTrees.passportNoAndNationality);
+  }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35281ad and 7ba8051.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (6)
  • packages/mobile-sdk-alpha/package.json (1 hunks)
  • packages/mobile-sdk-alpha/src/index.ts (1 hunks)
  • packages/mobile-sdk-alpha/src/proving/discloseInputs.ts (1 hunks)
  • packages/mobile-sdk-alpha/src/proving/registerInputs.ts (1 hunks)
  • packages/mobile-sdk-alpha/tests/proving/discloseInputs.test.ts (1 hunks)
  • packages/mobile-sdk-alpha/tests/proving/registerInputs.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{test,spec}.{ts,js,tsx,jsx}

⚙️ CodeRabbit Configuration File

**/*.{test,spec}.{ts,js,tsx,jsx}: Review test files for:

  • Test coverage completeness
  • Test case quality and edge cases
  • Mock usage appropriateness
  • Test readability and maintainability

Files:

  • packages/mobile-sdk-alpha/tests/proving/registerInputs.test.ts
  • packages/mobile-sdk-alpha/tests/proving/discloseInputs.test.ts
🧬 Code Graph Analysis (4)
packages/mobile-sdk-alpha/tests/proving/registerInputs.test.ts (2)
packages/mobile-sdk-alpha/src/index.ts (1)
  • generateTEEInputsRegister (41-41)
packages/mobile-sdk-alpha/src/proving/registerInputs.ts (1)
  • generateTEEInputsRegister (4-15)
packages/mobile-sdk-alpha/src/proving/registerInputs.ts (1)
packages/mobile-sdk-alpha/src/index.ts (1)
  • generateTEEInputsRegister (41-41)
packages/mobile-sdk-alpha/tests/proving/discloseInputs.test.ts (2)
packages/mobile-sdk-alpha/src/index.ts (1)
  • generateTEEInputsDisclose (40-40)
packages/mobile-sdk-alpha/src/proving/discloseInputs.ts (1)
  • generateTEEInputsDisclose (21-77)
packages/mobile-sdk-alpha/src/proving/discloseInputs.ts (1)
packages/mobile-sdk-alpha/src/index.ts (1)
  • generateTEEInputsDisclose (40-40)
🪛 GitHub Check: lint
packages/mobile-sdk-alpha/tests/proving/discloseInputs.test.ts

[warning] 44-44:
Delete ··


[warning] 37-37:
Delete ··


[warning] 36-36:
Delete ··


[warning] 35-35:
Delete ··


[warning] 34-34:
Delete ··


[warning] 33-33:
Delete ··


[warning] 32-32:
Delete ··


[warning] 31-31:
Replace ········ with ······


[warning] 30-30:
Delete ··


[warning] 29-29:
Delete ··

🪛 GitHub Actions: Mobile SDK CI
packages/mobile-sdk-alpha/tests/proving/discloseInputs.test.ts

[warning] 1-1: Prettier formatting issues detected. Run 'prettier --write' to fix.

🔇 Additional comments (3)
packages/mobile-sdk-alpha/package.json (1)

56-56: Confirm workspace dependency publishability.

"@selfxyz/common": "workspace:*" will be rewritten on publish only if it’s part of the same release and versioned in lockstep. Ensure:

  • @selfxyz/common is published publicly alongside this package.
  • validate-exports/verify-conditions scripts catch mismatches in version publishing.

Would you like a script that checks for "workspace:*" across publishable packages and ensures corresponding public versions exist?

packages/mobile-sdk-alpha/src/index.ts (1)

40-41: LGTM: Publicly re-exporting the TEE input helpers.

The barrel now surfaces generateTEEInputsDisclose and generateTEEInputsRegister as part of the public API. This aligns with the PR objective.

packages/mobile-sdk-alpha/tests/proving/discloseInputs.test.ts (1)

29-37: Fix Prettier/ESLint formatting to unblock CI.

The pipeline flagged spacing/indentation. Run:

  • yarn workspace @selfxyz/mobile-sdk-alpha nice
  • or: yarn lint:fix && yarn fmt:fix

Here’s a minimal diff reducing indentation around the selfApp and result lines:

-      const selfApp = {
+    const selfApp = {
@@
-      const result = generateTEEInputsDisclose('sec', passportData, selfApp as SelfApp, ofacTrees, commitmentTree as any);
+    const result = generateTEEInputsDisclose('sec', passportData, selfApp as SelfApp, ofacTrees, commitmentTree as any);

Also applies to: 44-44

Comment on lines +54 to +57
"@openpassport/zk-kit-lean-imt": "^0.0.6",
"@openpassport/zk-kit-smt": "^0.0.1",
"@selfxyz/common": "workspace:*",
"poseidon-lite": "^0.2.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify RN/Hermes compatibility and bundling for new crypto-heavy deps (poseidon-lite, zk-kit IMT/SMT).

These packages are BigInt- and hashing-heavy. In React Native, some crypto libs target Node or require specific polyfills. Confirm they are ESM-friendly for tsup, tree-shakeable for web, and don’t rely on Node built-ins at runtime.

  • Risk areas:
    • poseidon-lite runtime in RN (Hermes BigInt support and any WASM/native bindings).
    • @openpassport/zk-kit-lean-imt and @openpassport/zk-kit-smt bundling in RN/Web (no Node APIs).
    • Side-effect-free modules for tree-shaking under "sideEffects": false.

Please run the test matrix on both RN and web targets. If helpful, here are web queries to cross-check RN support:


🌐 Web query:

Is the npm package "poseidon-lite" compatible with React Native (Hermes) without Node polyfills?

💡 Result:

The npm package poseidon-lite is not confirmed to be compatible with React Native running on Hermes without Node polyfills; available information indicates likely incompatibility without extra configuration.

Key details:

  • The npm documentation[6] for poseidon-lite does not specify React Native (Hermes) support or note whether it avoids dependencies on Node.js built-in modules. This is critical because most npm cryptography libraries—Poseidon is a hashing algorithm—commonly depend on modules like Buffer, crypto, or others that are not available in React Native or Hermes environments without polyfills.
  • Hermes is a JavaScript engine optimized for React Native and is designed for improved launch times and memory usage, but it intentionally omits Node.js APIs and browser shims[1][3][4][5][7]. React Native (with Hermes) does not provide standard Node.js modules natively.
  • If a package like poseidon-lite references any Node core modules (e.g., crypto, stream, Buffer in Node mode), it will not work out-of-the-box with React Native unless you install and correctly configure suitable polyfills or shims for these modules. Doing so is possible, but can be complex and may not always guarantee security or performance.
  • Search results and the official React Native and Hermes documentation do not list poseidon-lite as a compatible or officially supported package[1][2][3][4][5][7].

Recommended next steps:

  • Inspect poseidon-lite dependencies and source code: If it directly or indirectly imports any Node.js built-in modules, polyfills are required. Without them, it is incompatible with React Native (Hermes).
  • Alternative: Look for cryptographic libraries explicitly written for (and tested on) React Native with Hermes, such as those based purely on JavaScript or using the expo-crypto module or other React Native-specific cryptography solutions.
  • If you must use poseidon-lite, prepare for significant manual configuration of polyfills, and note that this may impact your app’s security, performance, or maintenance burden.

Summary:
poseidon-lite is not natively compatible with React Native (Hermes) without Node polyfills, and there is no official support or ready-to-use solution indicated in upstream documentation[6]. Before using it, audit its code for Node dependencies and evaluate alternatives designed for React Native/Hermes environments.

Citations:


🌐 Web query:

Do "@openpassport/zk-kit-lean-imt" and "@openpassport/zk-kit-smt" support bundling in React Native environments?

💡 Result:

Short answer

  • There’s no published statement that either package explicitly targets React Native. Both are TypeScript / JavaScript libraries published to npm, and LeanIMT is generally usable in JS environments (so it will usually bundle in React Native). (npmjs.com, github.com)
  • Sparse Merkle Tree (smt) in the zk‑kit repo is flagged in the repo metadata as having bundling issues (the repo lists some packages as not bundle‑friendly). That means smt is more likely to require Metro polyfills or extra configuration in RN. (github.com)

What that practically means

  • @openpassport/zk-kit-lean-imt appears to be a pure TypeScript/JS implementation and will most often work out-of-the-box in a React Native app (no native binaries in the package). Try importing it — most likely it will bundle fine. (npmjs.com)
  • @openpassport/zk-kit-smt may import hashing/crypto code (the README examples show usage of crypto-js / poseidon-lite). If one of its transitive deps expects Node built-ins (crypto, fs, etc.) Metro will fail to resolve them and you’ll need polyfills/config. The zk‑kit repo’s package list marks smt as problematic for bundling, so expect to do extra bundler work if you hit errors. (github.com)

How to test quickly in your React Native app

  1. yarn add @openpassport/zk-kit-lean-imt @openpassport/zk-kit-smt
  2. In your RN project run Metro / start the app and import a minimal usage (create an instance and call a simple method). If Metro succeeds and the JS runs, the package bundled successfully.

If Metro fails (common error: “Unable to resolve module 'crypto'” or similar)

  • Typical fixes:
    • Use node-libs-react-native or explicit extraNodeModules to polyfill Node built-ins. Example metro.config.js pattern:
      • resolver.extraNodeModules -> map builtins (crypto, stream, buffer, etc.) to RN-friendly shims.
    • Install the recommended polyfills (examples used in the community): node-libs-react-native, buffer, react-native-get-random-values (or react-native-crypto + react-native-randombytes depending on approach). Then add any required global shims (e.g. global.Buffer = require('buffer').Buffer). (stackoverflow.com, gist.github.com)
  • If you use Expo, prefer the Expo crypto APIs (expo-crypto) or customize metro via the Expo docs; Expo also has guidance for node builtins. (docs.expo.dev)

Concrete quick troubleshooting recipe (one of the common community approaches)

  1. npm/yarn add node-libs-react-native buffer react-native-get-random-values
  2. Edit metro.config.js:
    • resolver.extraNodeModules = require('node-libs-react-native')
    • add watchFolders if you need to include linked packages
  3. In your app entry (e.g. index.js):
    • require('react-native-get-random-values')
    • global.Buffer = require('buffer').Buffer
  4. Restart Metro / clear cache (react-native start --reset-cache) and rebuild. (If you still see missing modules, add targeted extraNodeModules mappings for the problematic module.) (stackoverflow.com, gist.github.com)

Summary / recommendation

  • Try lean-imt first — it’s very likely to bundle without work. (npmjs.com)
  • Expect smt to possibly need extra Metro polyfills (the repo metadata suggests it’s more likely to be bundle-problematic). If you get Metro errors, follow the polyfill/metro.config approaches above. (github.com)

If you want, I can:

  • Check a specific error you’re seeing (paste the Metro error output) and give an exact metro.config.js + list of packages to install; or
  • Produce a ready-to-drop metro.config.js and index.js bootstrap snippet tailored to Expo vs. bare React Native.

Citations:


Ensure React Native (Hermes) compatibility and bundler config for crypto dependencies

Based on upstream docs and community feedback, these new packages will need extra configuration in a React Native (Hermes) environment:

• poseidon-lite
– Not confirmed to run out-of-the-box on RN/Hermes (Hermes omits Node.js built-ins like crypto, Buffer).
Action: Either swap for an RN-compatible Poseidon implementation (e.g. expo-crypto based) or add Node polyfills:
• yarn add node-libs-react-native buffer react-native-get-random-values
• metro.config.js → resolver.extraNodeModules = require('node-libs-react-native')
• In your entry (index.js):
js import 'react-native-get-random-values'; global.Buffer = require('buffer').Buffer;
• Clear Metro cache and rebuild.

• @openpassport/zk-kit-lean-imt
– Pure TypeScript/JS, no native binaries. Should bundle cleanly under Metro.
Action: Import a minimal API call in RN and confirm Metro starts without errors.

• @openpassport/zk-kit-smt
– Repo metadata flags this as “bundle-problematic.” It pulls in hashing libs (crypto-js, poseidon-lite), so Metro may throw “Unable to resolve module 'crypto'” or similar.
Action: Treat like poseidon-lite above—polyfill Node built-ins via node-libs-react-native, buffer, etc., or follow the troubleshooting recipe from the zk-kit issue tracker.

Additional web bundling checks:
• Confirm each package’s package.json exports an ESM entrypoint (module/exports) so tsup can tree-shake under sideEffects: false.
• On your web target, run a production build and inspect bundle size to ensure dead code is pruned.

Next Steps

  1. In a demo RN project, yarn add poseidon-lite @openpassport/zk-kit-lean-imt @openpassport/zk-kit-smt
  2. Attempt a minimal import/use of each. Note any Metro errors.
  3. Apply polyfills and Metro tweaks as above.
  4. Re-run Metro and Web (tsup) builds; verify no Node-built-ins errors and that tree-shaking works.
🤖 Prompt for AI Agents
In packages/mobile-sdk-alpha/package.json around lines 54-57, adding
poseidon-lite and the zk-kit packages can break React Native/Hermes bundling
because Hermes omits Node built-ins (crypto, Buffer) and
@openpassport/zk-kit-smt pulls hashing deps; fix by either swapping
poseidon-lite for an RN-compatible Poseidon implementation or adding Node
polyfills and bundler tweaks: install node-libs-react-native, buffer and
react-native-get-random-values; set metro.config.js resolver.extraNodeModules =
require('node-libs-react-native'); import 'react-native-get-random-values' and
set global.Buffer = require('buffer').Buffer in the app entry; verify
@openpassport/zk-kit-lean-imt imports cleanly in RN and treat
@openpassport/zk-kit-smt like poseidon-lite (polyfill or replace), then clear
Metro cache and rebuild; additionally confirm package.json for these packages
exposes ESM entrypoints (module/exports) for web tsup tree-shaking and run
production web build to inspect bundle size.

Comment on lines +21 to +31
export function generateTEEInputsDisclose(
secret: string,
passportData: PassportData,
selfApp: SelfApp,
ofacTrees: {
passportNoAndNationality: any;
nameAndDob: any;
nameAndYob: any;
},
commitmentTree: any,
) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding input validation for the TEE input generator parameters

The function accepts several critical parameters without validating their structure or required properties. For a security-sensitive TEE context, consider adding validation to ensure:

  • secret is not empty
  • passportData contains required fields and valid documentCategory
  • selfApp has all required properties
  • Tree structures are properly formatted

Add validation at the beginning of the function:

 export function generateTEEInputsDisclose(
   secret: string,
   passportData: PassportData,
   selfApp: SelfApp,
   ofacTrees: {
     passportNoAndNationality: any;
     nameAndDob: any;
     nameAndYob: any;
   },
   commitmentTree: any,
 ) {
+  // Validate critical inputs
+  if (!secret || typeof secret !== 'string') {
+    throw new Error('Invalid secret: must be a non-empty string');
+  }
+  if (!passportData?.documentCategory || !['passport', 'id_card'].includes(passportData.documentCategory)) {
+    throw new Error('Invalid passportData: documentCategory must be "passport" or "id_card"');
+  }
+  if (!selfApp?.scope || !selfApp?.endpoint || !selfApp?.disclosures) {
+    throw new Error('Invalid selfApp: missing required properties');
+  }
+  if (!ofacTrees?.nameAndDob || !ofacTrees?.nameAndYob) {
+    throw new Error('Invalid ofacTrees: missing required trees');
+  }
+
   const { scope, disclosures, endpoint, userId, userDefinedData, chainID } = selfApp;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function generateTEEInputsDisclose(
secret: string,
passportData: PassportData,
selfApp: SelfApp,
ofacTrees: {
passportNoAndNationality: any;
nameAndDob: any;
nameAndYob: any;
},
commitmentTree: any,
) {
export function generateTEEInputsDisclose(
secret: string,
passportData: PassportData,
selfApp: SelfApp,
ofacTrees: {
passportNoAndNationality: any;
nameAndDob: any;
nameAndYob: any;
},
commitmentTree: any,
) {
// Validate critical inputs
if (!secret || typeof secret !== 'string') {
throw new Error('Invalid secret: must be a non-empty string');
}
if (!passportData?.documentCategory || !['passport', 'id_card'].includes(passportData.documentCategory)) {
throw new Error('Invalid passportData: documentCategory must be "passport" or "id_card"');
}
if (!selfApp?.scope || !selfApp?.endpoint || !selfApp?.disclosures) {
throw new Error('Invalid selfApp: missing required properties');
}
if (!ofacTrees?.nameAndDob || !ofacTrees?.nameAndYob) {
throw new Error('Invalid ofacTrees: missing required trees');
}
const { scope, disclosures, endpoint, userId, userDefinedData, chainID } = selfApp;
// ...rest of the function...
}

Comment on lines +25 to +30
ofacTrees: {
passportNoAndNationality: any;
nameAndDob: any;
nameAndYob: any;
},
commitmentTree: any,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Type safety concern: Using any type for tree parameters

The OFAC trees and commitment tree parameters use any type, which bypasses TypeScript's type checking. This could lead to runtime errors if incorrect data structures are passed.

Consider defining proper types for the tree structures:

+import type { SMTData, IMTData } from '@openpassport/zk-kit-smt';
+
 export function generateTEEInputsDisclose(
   secret: string,
   passportData: PassportData,
   selfApp: SelfApp,
   ofacTrees: {
-    passportNoAndNationality: any;
-    nameAndDob: any;
-    nameAndYob: any;
+    passportNoAndNationality: SMTData;
+    nameAndDob: SMTData;
+    nameAndYob: SMTData;
   },
-  commitmentTree: any,
+  commitmentTree: IMTData,
 ) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ofacTrees: {
passportNoAndNationality: any;
nameAndDob: any;
nameAndYob: any;
},
commitmentTree: any,
import type { SMTData, IMTData } from '@openpassport/zk-kit-smt';
export function generateTEEInputsDisclose(
secret: string,
passportData: PassportData,
selfApp: SelfApp,
ofacTrees: {
passportNoAndNationality: SMTData;
nameAndDob: SMTData;
nameAndYob: SMTData;
},
commitmentTree: IMTData,
) {
// …
}
🤖 Prompt for AI Agents
In packages/mobile-sdk-alpha/src/proving/discloseInputs.ts around lines 25 to
30, the OFAC trees and commitmentTree are typed as `any`, which disables
TypeScript checks; replace `any` with precise interfaces/types that model the
tree nodes and APIs (e.g., node value type, children, proof/serialize methods)
or use a generic Tree<T> type used across the codebase, update the function and
related signatures to use those types, import or declare the interfaces near the
top of the file (or in a shared types file) and run the typechecker to fix all
resulting errors and ensure callers are updated to provide the correctly typed
trees.

Comment on lines +79 to +86
function getSelectorDg1(document: DocumentCategory, disclosures: SelfAppDisclosureConfig) {
switch (document) {
case 'passport':
return getSelectorDg1Passport(disclosures);
case 'id_card':
return getSelectorDg1IdCard(disclosures);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add exhaustive check for document category switch

The switch statement doesn't have a default case, which could lead to undefined behavior if new document categories are added in the future.

 function getSelectorDg1(document: DocumentCategory, disclosures: SelfAppDisclosureConfig) {
   switch (document) {
     case 'passport':
       return getSelectorDg1Passport(disclosures);
     case 'id_card':
       return getSelectorDg1IdCard(disclosures);
+    default:
+      // Exhaustive check - this should never be reached if DocumentCategory is properly typed
+      const exhaustiveCheck: never = document;
+      throw new Error(`Unsupported document category: ${exhaustiveCheck}`);
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function getSelectorDg1(document: DocumentCategory, disclosures: SelfAppDisclosureConfig) {
switch (document) {
case 'passport':
return getSelectorDg1Passport(disclosures);
case 'id_card':
return getSelectorDg1IdCard(disclosures);
}
}
function getSelectorDg1(document: DocumentCategory, disclosures: SelfAppDisclosureConfig) {
switch (document) {
case 'passport':
return getSelectorDg1Passport(disclosures);
case 'id_card':
return getSelectorDg1IdCard(disclosures);
default:
// Exhaustive check - this should never be reached if DocumentCategory is properly typed
const exhaustiveCheck: never = document;
throw new Error(`Unsupported document category: ${exhaustiveCheck}`);
}
}
🤖 Prompt for AI Agents
In packages/mobile-sdk-alpha/src/proving/discloseInputs.ts around lines 79 to
86, the switch over DocumentCategory is missing a default/exhaustive branch
which can return undefined if a new category is added; update the switch to be
exhaustive by adding a default that either throws a descriptive Error (e.g.,
`throw new Error("Unsupported document category: " + document)`) or use the
TypeScript exhaustive-check pattern (assign `document` to a `never` typed
variable and throw) so the compiler errors on new categories and runtime
behavior is explicit.

Comment on lines +95 to +96
const [start, end] = attributeToPosition[attribute as keyof typeof attributeToPosition];
selector_dg1.fill('1', start, end + 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add boundary validation for attribute positions

The code assumes attributeToPosition and attributeToPosition_ID will always return valid array indices, but doesn't validate the boundaries against the selector array length.

Add validation to prevent potential array out-of-bounds errors:

 function getSelectorDg1Passport(disclosures: SelfAppDisclosureConfig) {
   const selector_dg1 = Array(88).fill('0');
   Object.entries(disclosures).forEach(([attribute, reveal]) => {
     if (['ofac', 'excludedCountries', 'minimumAge'].includes(attribute)) {
       return;
     }
     if (reveal) {
       const [start, end] = attributeToPosition[attribute as keyof typeof attributeToPosition];
+      if (start < 0 || end >= selector_dg1.length) {
+        throw new Error(`Invalid position range for attribute ${attribute}: [${start}, ${end}]`);
+      }
       selector_dg1.fill('1', start, end + 1);
     }
   });
   return selector_dg1;
 }

Apply similar validation to getSelectorDg1IdCard:

 function getSelectorDg1IdCard(disclosures: SelfAppDisclosureConfig) {
   const selector_dg1 = Array(90).fill('0');
   Object.entries(disclosures).forEach(([attribute, reveal]) => {
     if (['ofac', 'excludedCountries', 'minimumAge'].includes(attribute)) {
       return;
     }
     if (reveal) {
       const [start, end] = attributeToPosition_ID[attribute as keyof typeof attributeToPosition_ID];
+      if (start < 0 || end >= selector_dg1.length) {
+        throw new Error(`Invalid position range for attribute ${attribute}: [${start}, ${end}]`);
+      }
       selector_dg1.fill('1', start, end + 1);
     }
   });
   return selector_dg1;
 }

Also applies to: 109-110

🤖 Prompt for AI Agents
In packages/mobile-sdk-alpha/src/proving/discloseInputs.ts around lines 95-96
(and similarly for lines 109-110 / getSelectorDg1IdCard), the code reads
start/end from attributeToPosition (and attributeToPosition_ID) and uses them to
fill selector_dg1 without validating boundaries; add explicit validation that
start and end are numbers, start >= 0, end >= start, and end <
selector_dg1.length before calling selector_dg1.fill(...); if validation fails,
throw or return a clear error (or skip filling) to avoid out-of-bounds access;
apply the same checks to the getSelectorDg1IdCard usage and any other places
that use positions from those maps.

Comment on lines +4 to +15
export function generateTEEInputsRegister(
secret: string,
passportData: PassportData,
dscTree: string,
env: 'prod' | 'stg',
) {
const inputs = generateCircuitInputsRegister(secret, passportData, dscTree);
const circuitName = getCircuitNameFromPassportData(passportData, 'register');
const endpointType = env === 'stg' ? 'staging_celo' : 'celo';
const endpoint = 'https://self.xyz';
return { inputs, circuitName, endpointType, endpoint };
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Strengthen types and defaults; keep API shape stable.

  • Add an explicit return type alias for stability and clearer DX.
  • Default env to 'prod' to reduce call-site footguns.
  • Optional: Document with JSDoc.

Apply this diff:

@@
-import type { PassportData } from '@selfxyz/common/types';
+import type { PassportData } from '@selfxyz/common/types';
@@
-export function generateTEEInputsRegister(
+export type TEEInputsResponse = {
+  inputs: unknown;
+  circuitName: string;
+  endpointType: 'staging_celo' | 'celo';
+  endpoint: string;
+};
+
+/**
+ * Build TEE inputs for the register circuit.
+ */
+export function generateTEEInputsRegister(
   secret: string,
   passportData: PassportData,
   dscTree: string,
-  env: 'prod' | 'stg',
-) {
+  env: 'prod' | 'stg' = 'prod',
+): TEEInputsResponse {
   const inputs = generateCircuitInputsRegister(secret, passportData, dscTree);
   const circuitName = getCircuitNameFromPassportData(passportData, 'register');
   const endpointType = env === 'stg' ? 'staging_celo' : 'celo';
   const endpoint = 'https://self.xyz';
   return { inputs, circuitName, endpointType, endpoint };
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function generateTEEInputsRegister(
secret: string,
passportData: PassportData,
dscTree: string,
env: 'prod' | 'stg',
) {
const inputs = generateCircuitInputsRegister(secret, passportData, dscTree);
const circuitName = getCircuitNameFromPassportData(passportData, 'register');
const endpointType = env === 'stg' ? 'staging_celo' : 'celo';
const endpoint = 'https://self.xyz';
return { inputs, circuitName, endpointType, endpoint };
}
import type { PassportData } from '@selfxyz/common/types';
export type TEEInputsResponse = {
inputs: unknown;
circuitName: string;
endpointType: 'staging_celo' | 'celo';
endpoint: string;
};
/**
* Build TEE inputs for the register circuit.
*/
export function generateTEEInputsRegister(
secret: string,
passportData: PassportData,
dscTree: string,
env: 'prod' | 'stg' = 'prod',
): TEEInputsResponse {
const inputs = generateCircuitInputsRegister(secret, passportData, dscTree);
const circuitName = getCircuitNameFromPassportData(passportData, 'register');
const endpointType = env === 'stg' ? 'staging_celo' : 'celo';
const endpoint = 'https://self.xyz';
return { inputs, circuitName, endpointType, endpoint };
}
🤖 Prompt for AI Agents
In packages/mobile-sdk-alpha/src/proving/registerInputs.ts around lines 4 to 15,
the function lacks an explicit return type and the env parameter is required;
update the function signature to use a named return type alias (define and
export a suitable type/interface capturing inputs, circuitName, endpointType,
endpoint), set env to default to 'prod' (env: 'prod' | 'stg' = 'prod'), and add
a brief JSDoc above the function describing parameters and return shape to
preserve API stability and improve DX.

@transphorm
Copy link
Member Author

closing this pr in favor of - #917

@transphorm transphorm closed this Aug 19, 2025
@transphorm transphorm deleted the codex/work-on-proof-input-generation branch August 20, 2025 00:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants