@zkproofport-app/sdk 0.5.0-beta.3 → 0.5.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@zkproofport-app/sdk)](https://www.npmjs.com/package/@zkproofport-app/sdk)
4
4
  [![license](https://img.shields.io/npm/l/@zkproofport-app/sdk)](./LICENSE)
5
5
 
6
- TypeScript SDK for requesting zero-knowledge proofs from the [ZKProofport](https://zkproofport.com) mobile app and verifying them on-chain. Three circuits are officially supported today — Coinbase KYC, Coinbase country attestation, and OIDC email-domain attestation (Google, Microsoft 365). Two more prove today against a testnet deployment and are marked experimental: GIWA attestation and Dojang Playground. The three Korean mobile ID (mDL) identifiers are reserved and planned. [Circuit Identifiers](#circuit-identifiers) has the full list and what each status means.
6
+ TypeScript SDK for requesting zero-knowledge proofs from the [ZKProofport](https://zkproofport.com) mobile app and verifying them on-chain. Three circuits are officially supported today — Coinbase KYC, Coinbase country attestation, and OIDC email-domain attestation (Google, Microsoft 365). Two more prove today against a testnet deployment and are marked experimental: GIWA attestation and Dojang Playground. [Circuit Identifiers](#circuit-identifiers) has the full list and what each status means.
7
7
 
8
8
  ## How It Works
9
9
 
@@ -33,7 +33,7 @@ TypeScript SDK for requesting zero-knowledge proofs from the [ZKProofport](https
33
33
  ```
34
34
 
35
35
  1. Your app creates a proof request through the SDK
36
- 2. The SDK asks the relay for a one-time challenge and a tracked request ID. For the Coinbase circuits it also signs that challenge with your wallet signer (EIP-191); the OIDC and mDL circuits need no signature
36
+ 2. The SDK asks the relay for a one-time challenge and a tracked request ID. For the Coinbase circuits it also signs that challenge with your wallet signer (EIP-191); the OIDC circuit needs no signature
37
37
  3. Your app shows the returned deep link as a QR code (desktop) or navigates to it (mobile)
38
38
  4. The user opens the ZKProofport app, which generates the ZK proof on-device
39
39
  5. The proof result flows back through the relay to your app over WebSocket (HTTP polling as fallback)
@@ -90,6 +90,7 @@ if (result.status === 'completed') {
90
90
  publicInputs: result.publicInputs,
91
91
  verifierAddress: result.verifierAddress,
92
92
  chainId: result.chainId,
93
+ signerVariant: result.signerVariant,
93
94
  };
94
95
 
95
96
  const verification = await sdk.verifyResponseOnChain(response);
@@ -99,7 +100,7 @@ if (result.status === 'completed') {
99
100
 
100
101
  ## Circuit Identifiers
101
102
 
102
- Circuit IDs are canonical, lowercase and case-sensitive: each one is the `name` field of that circuit's `Nargo.toml`, verbatim. Hyphenated spellings such as `coinbase-kyc` or `mdl-kr-age` are route and directory names from elsewhere — they are not circuit IDs, and passing one does not fail with a clear error. It produces a nullifier mismatch or a verifier lookup that finds nothing.
103
+ Circuit IDs are canonical, lowercase and case-sensitive: each one is the `name` field of that circuit's `Nargo.toml`, verbatim. Hyphenated spellings such as `coinbase-kyc` or `oidc-domain` are route and directory names from elsewhere — they are not circuit IDs, and passing one does not fail with a clear error. It produces a nullifier mismatch or a verifier lookup that finds nothing.
103
104
 
104
105
  This SDK is the single source of truth for that list. Import the constants rather than typing the strings, and a rename becomes a compile error instead of a runtime surprise:
105
106
 
@@ -126,28 +127,23 @@ import { CIRCUIT_IDS, CIRCUIT_SUPPORT_STATUS } from '@zkproofport-app/sdk/circui
126
127
  | `CIRCUIT_IDS.OIDC_DOMAIN_ATTESTATION` | `oidc_domain_attestation` | **Supported** |
127
128
  | `CIRCUIT_IDS.GIWA_ATTESTATION` | `giwa_attestation` | _Experimental_ |
128
129
  | `CIRCUIT_IDS.DOJANG_PLAYGROUND` | `dojang_playground` | _Experimental_ |
129
- | `CIRCUIT_IDS.MDL_KR_OWNERSHIP` | `mdl_kr_ownership` | Planned |
130
- | `CIRCUIT_IDS.MDL_KR_AGE` | `mdl_kr_age` | Planned |
131
- | `CIRCUIT_IDS.MDL_KR_REGION` | `mdl_kr_region` | Planned |
132
130
 
133
131
  **Supported** means generally available — build a product on it.
134
132
 
135
133
  **Experimental** means you can prove it today and it verifies, but only against a testnet deployment. Inputs, public-input layout and the verifier address can change without a major version bump, and there is no mainnet to point at. Try it; do not ship on it.
136
134
 
137
- **Planned** means the identifier is reserved and the circuit exists, but it is not officially supported yet: availability, inputs and public-input layout can change without a major version bump.
135
+ **Planned** marks an identifier reserved ahead of official support; inputs and public-input layout can change without a major version bump. No circuit has this status today.
138
136
 
139
- Every ID appears in `CircuitType` and in `sdk.getSupportedCircuits()`, planned ones included, so being assignable is not a support guarantee. Gate on the status, not on the type:
137
+ Every ID appears in `CircuitType` and in `sdk.getSupportedCircuits()`, experimental ones included, so being assignable is not a support guarantee. Gate on the status, not on the type:
140
138
 
141
139
  ```typescript
142
140
  import { CIRCUIT_SUPPORT_STATUS, isSupportedCircuitId } from '@zkproofport-app/sdk';
143
141
 
144
142
  CIRCUIT_SUPPORT_STATUS.coinbase_attestation; // 'supported'
145
143
  CIRCUIT_SUPPORT_STATUS.giwa_attestation; // 'experimental'
146
- CIRCUIT_SUPPORT_STATUS.mdl_kr_age; // 'planned'
147
144
 
148
145
  isSupportedCircuitId('oidc_domain_attestation'); // true
149
146
  isSupportedCircuitId('giwa_attestation'); // false — experimental is not supported
150
- isSupportedCircuitId('mdl_kr_age'); // false
151
147
  isSupportedCircuitId('coinbase-kyc'); // false — not an ID at all
152
148
  ```
153
149
 
@@ -163,14 +159,14 @@ isSupportedCircuitId('coinbase-kyc'); // false — not an ID at all
163
159
  | `isCircuitId(value)` | `value is CircuitId` | Narrows an unknown value; `false` for hyphenated names |
164
160
  | `isSupportedCircuitId(value)` | `value is CircuitId` | The same, and additionally requires `supported` |
165
161
  | `getCircuitSupportStatus(id)` | `CircuitSupportStatus` | Status of one ID; throws on an unknown one |
166
- | `CircuitId` | type | Union of the eight IDs. `CircuitType` is an alias of it |
167
- | `CircuitSupportStatus` | type | `'supported' \| 'planned'` |
162
+ | `CircuitId` | type | Union of the five IDs. `CircuitType` is an alias of it |
163
+ | `CircuitSupportStatus` | type | `'supported' \| 'experimental' \| 'planned'` |
168
164
 
169
165
  Both objects and all three arrays are frozen. `ALL_CIRCUIT_IDS`, `SUPPORTED_CIRCUIT_IDS` and `PLANNED_CIRCUIT_IDS` are derived from `CIRCUIT_SUPPORT_STATUS` at load time, so they cannot disagree with it.
170
166
 
171
167
  ## Supported Circuits
172
168
 
173
- The circuits below are officially supported. Pass their IDs exactly as written, or use the `CIRCUIT_IDS` constants. `sdk.getSupportedCircuits()` returns every known ID at runtime, planned ones included — see [Circuit Identifiers](#circuit-identifiers).
169
+ The circuits below are officially supported. Pass their IDs exactly as written, or use the `CIRCUIT_IDS` constants. `sdk.getSupportedCircuits()` returns every known ID at runtime, experimental ones included — see [Circuit Identifiers](#circuit-identifiers).
174
170
 
175
171
  ### `coinbase_attestation`
176
172
 
@@ -334,7 +330,7 @@ circuit names are special:
334
330
  | What the circuit does with an action | Circuits |
335
331
  |---|---|
336
332
  | Signs it when present, signs the signal hash when not | `giwa_attestation`, `dojang_playground` |
337
- | Has no action inputs — sending one is refused, not ignored | Coinbase KYC, Coinbase country, OIDC domain, the three mDL circuits |
333
+ | Has no action inputs — sending one is refused, not ignored | Coinbase KYC, Coinbase country, OIDC domain |
338
334
 
339
335
  ```typescript
340
336
  import { circuitActionBinding } from '@zkproofport-app/sdk';
@@ -347,62 +343,6 @@ Sending an action to a circuit that cannot prove one is an error rather than a
347
343
  silent drop: a dropped action would leave you believing a proof authorized
348
344
  something the circuit never saw.
349
345
 
350
- ## Planned Circuits
351
-
352
- ZKProofport is registered with the Ministry of the Interior and Safety as a Korea Mobile ID integration service (모바일 신분증 연계서비스). The three circuits below are in beta: `CIRCUIT_SUPPORT_STATUS` reports each of them as `planned`, and their input shape and public-input layout can change without a major version bump.
353
-
354
- ### `mdl_kr_ownership`
355
-
356
- Proves the user holds a valid Korean mobile driver's license (모바일 신분증). The license data stays on-device; only the attributes selected by `discloseFlags` are revealed. No wallet signer is required.
357
-
358
- | Field | Type | Required | Description |
359
- |-------|------|----------|-------------|
360
- | `scope` | `string` | Yes | Application-specific identifier for proof uniqueness. Non-empty, 256 characters or fewer, no control characters. |
361
- | `discloseFlags` | `number` | No | Attribute disclosure bitmask, integer 0–15 (`0x01` name, `0x02` birth, `0x04` sex, `0x08` phone). Omit or `0` for a fully anonymous ownership proof. |
362
-
363
- ```typescript
364
- // Anonymous "holds a valid Korean mobile ID" proof
365
- const relay = await sdk.createRelayRequest('mdl_kr_ownership', {
366
- scope: 'myapp.com',
367
- });
368
- ```
369
-
370
- ### `mdl_kr_age`
371
-
372
- Proves the user is at least `ageThreshold` years old according to their Korean mobile driver's license, without revealing the birth date. No wallet signer is required.
373
-
374
- | Field | Type | Required | Description |
375
- |-------|------|----------|-------------|
376
- | `scope` | `string` | Yes | Application-specific identifier (same rules as above) |
377
- | `ageThreshold` | `number` | Yes | Minimum age to prove — integer between 1 and 150 (e.g. `19` for Korean adult verification) |
378
-
379
- ```typescript
380
- const relay = await sdk.createRelayRequest('mdl_kr_age', {
381
- scope: 'myapp.com',
382
- ageThreshold: 19,
383
- });
384
- ```
385
-
386
- ### `mdl_kr_region`
387
-
388
- Proves the user's registered address is in the specified si/do region without revealing the full address. No wallet signer is required.
389
-
390
- | Field | Type | Required | Description |
391
- |-------|------|----------|-------------|
392
- | `scope` | `string` | Yes | Application-specific identifier (same rules as above) |
393
- | `targetRegion` | `string` | Yes | Region (si/do) to prove residency in, in Korean (e.g. `'경기도'`, `'서울특별시'`). Non-empty, 256 characters or fewer, no control characters. |
394
-
395
- ```typescript
396
- const relay = await sdk.createRelayRequest('mdl_kr_region', {
397
- scope: 'myapp.com',
398
- targetRegion: '경기도',
399
- });
400
- ```
401
-
402
- > mDL inputs are checked before the request leaves your process: a missing `scope`, an out-of-range `discloseFlags`, a non-integer `ageThreshold` or an empty `targetRegion` throws locally instead of coming back as a relay error.
403
-
404
- > The mDL circuits do not require `setSigner()` — the proof is bound to the license via an on-device nullifier (`nullifier_value` public input), not a wallet address. Use `sdk.extractNullifier(publicInputs, circuit)` for sybil-resistant user identification.
405
-
406
346
  ## Integration Guide
407
347
 
408
348
  ### Step 1: Initialize
@@ -438,7 +378,7 @@ interface WalletSigner {
438
378
 
439
379
  Any ethers v5/v6 `Signer` is compatible.
440
380
 
441
- > **When you can skip this step:** the OIDC Domain and the three mDL circuits never sign a challenge. Calling `createRelayRequest` for those circuits without a signer works. Calling it for a Coinbase circuit without one throws `Signer not set. Call setSigner() first. Wallet signature is required for this circuit.`
381
+ > **When you can skip this step:** the OIDC Domain circuit never signs a challenge. Calling `createRelayRequest` for it without a signer works. Calling it for a Coinbase circuit without one throws `Signer not set. Call setSigner() first. Wallet signature is required for this circuit.`
442
382
 
443
383
  #### About challenge-signature
444
384
 
@@ -625,7 +565,7 @@ if (ProofportSDK.isMobile()) {
625
565
 
626
566
  ```typescript
627
567
  const result = await sdk.waitForProof(relay.requestId, {
628
- timeoutMs: 300000, // 5 minutes (default)
568
+ timeoutMs: 600000, // 10 minutes (default)
629
569
  onStatusChange: (update) => {
630
570
  console.log('Status:', update.status);
631
571
  },
@@ -658,7 +598,7 @@ const once = await sdk.pollResult(relay.requestId);
658
598
  // Poll until terminal state
659
599
  const result = await sdk.waitForResult(relay.requestId, {
660
600
  intervalMs: 2000,
661
- timeoutMs: 300000,
601
+ timeoutMs: 600000,
662
602
  onStatusChange: (result) => console.log(result.status),
663
603
  });
664
604
  ```
@@ -738,7 +678,7 @@ switch (result.status) {
738
678
 
739
679
  `isTerminalRelayStatus(status)` and `RELAY_TERMINAL_STATUSES` are exported for code that drives `pollResult()` in a loop of its own.
740
680
 
741
- The relay answers `'expired'` before the SDK's default `timeoutMs` (300 000 ms) runs out, so with the defaults you get a result to branch on rather than a thrown timeout. If you pass a much shorter `timeoutMs`, the SDK's own timeout can still fire first and the promise rejects.
681
+ The relay answers `'expired'` before the SDK's default `timeoutMs` (600 000 ms) runs out, so with the defaults you get a result to branch on rather than a thrown timeout. If you pass a much shorter `timeoutMs`, the SDK's own timeout can still fire first and the promise rejects.
742
682
 
743
683
  #### What is not on the result
744
684
 
@@ -772,6 +712,7 @@ The relay answers `'expired'` before the SDK's default `timeoutMs` (300 000 ms)
772
712
  | `publicInputs` | `string[]` | When completed | `result.publicInputs` |
773
713
  | `verifierAddress` | `string` | No | `result.verifierAddress`. Optional. When present it must match the SDK's own verifier for the circuit, or verification is refused |
774
714
  | `chainId` | `number` | No | `result.chainId`. Optional. When present it must match the network the SDK verifies the circuit on, or verification is refused |
715
+ | `signerVariant` | `string` | No | `result.signerVariant`. Copy it unchanged whenever the relay sends it: some circuits are proved by more than one package, each with its own verifier, and this field says which one made the proof (`standard`, `android` or `android_factory`). When it is absent the circuit's standard verifier is used, and a proof that has another package's size is refused; an unrecognised value is refused by name |
775
716
  | `numPublicInputs` | `number` | No | Never delivered by the relay, and never read during verification — `publicInputs.length` is used instead. Omit it |
776
717
  | `timestamp` | `number` | No | Not delivered by the relay. Omit it |
777
718
  | `error` | `string` | On failure | `result.error`. Carried for your own logging; verification ignores it |
@@ -790,7 +731,7 @@ The SDK also checks that the proof was made with a signing key Google or Microso
790
731
 
791
732
  For Coinbase KYC, Coinbase country and GIWA proofs the SDK checks that the attestation's signer belongs to the published signer set: the proof carries the root of the signer list it was made against, and a proof made against any other list is refused with `{ valid: false, error }`. This too runs in every verify method.
792
733
 
793
- The one limit: a proof made with a key the provider has already withdrawn, which this process never saw while it was published, cannot be checked and is refused. Keys seen while published stay acceptable for 24 hours after they disappear.
734
+ The one limit: a proof made with a key the provider has already withdrawn, which this process never saw while it was published, cannot be checked and is refused. Keys seen while published stay acceptable for 1 hour after they were last listed.
794
735
 
795
736
 
796
737
 
@@ -806,6 +747,7 @@ if (result.status === 'completed') {
806
747
  publicInputs: result.publicInputs,
807
748
  verifierAddress: result.verifierAddress,
808
749
  chainId: result.chainId,
750
+ signerVariant: result.signerVariant,
809
751
  };
810
752
 
811
753
  const verification = await sdk.verifyResponseOnChain(response);
@@ -881,7 +823,7 @@ if (sdk.extractScope(publicInputs, circuit) !== expectedScope) {
881
823
  The nullifier is a deterministic hash over the user's credential and the scope:
882
824
 
883
825
  - **Deterministic** — same user, same scope, same nullifier, every time. That is what makes duplicate detection possible.
884
- - **Privacy-preserving** — the wallet address (Coinbase), the email (OIDC) and the licence (mDL) stay hidden. There is no way back from the nullifier to the person.
826
+ - **Privacy-preserving** — the wallet address (Coinbase) and the email (OIDC) stay hidden. There is no way back from the nullifier to the person.
885
827
  - **Scope-bound** — the same user proving to a different scope produces an unrelated nullifier, so your users cannot be correlated across apps.
886
828
 
887
829
  On your side, it is the primary key of a verified user. Store it once verification succeeds, with a unique constraint, and check it before granting anything:
@@ -929,7 +871,7 @@ import {
929
871
  extractDomainFromPublicInputs,
930
872
  } from '@zkproofport-app/sdk';
931
873
 
932
- // Scope and nullifier work for all six circuits — the layout is picked from the
874
+ // Scope and nullifier work for all five circuits — the layout is picked from the
933
875
  // circuit id, so always pass it:
934
876
  const scope = extractScopeFromPublicInputs(publicInputs, 'coinbase_attestation');
935
877
  const nullifier = extractNullifierFromPublicInputs(publicInputs, 'coinbase_attestation');
@@ -938,9 +880,6 @@ const nullifier = extractNullifierFromPublicInputs(publicInputs, 'coinbase_attes
938
880
  const oidcScope = extractScopeFromPublicInputs(publicInputs, 'oidc_domain_attestation');
939
881
  const oidcNullifier = extractNullifierFromPublicInputs(publicInputs, 'oidc_domain_attestation');
940
882
 
941
- // The three mDL circuits share one layout
942
- const mdlNullifier = extractNullifierFromPublicInputs(publicInputs, 'mdl_kr_age');
943
-
944
883
  // Extract domain from OIDC Domain Attestation
945
884
  const domain = extractDomainFromPublicInputs(publicInputs, 'oidc_domain_attestation');
946
885
  // domain: 'example.com', or null if the circuit doesn't match or inputs are insufficient
@@ -1051,9 +990,6 @@ import type {
1051
990
  OidcDomainInputs,
1052
991
  ActionBoundInputs,
1053
992
  TypedAction,
1054
- MdlKrOwnershipInputs,
1055
- MdlKrAgeInputs,
1056
- MdlKrRegionInputs,
1057
993
  CircuitInputs,
1058
994
  ProofRequest,
1059
995
  ProofResponse,
@@ -1069,20 +1005,17 @@ import type {
1069
1005
 
1070
1006
  | Type | Description |
1071
1007
  |------|-------------|
1072
- | `CircuitId` | Union of the eight canonical circuit IDs — `'coinbase_attestation' \| 'coinbase_country_attestation' \| 'oidc_domain_attestation' \| 'giwa_attestation' \| 'dojang_playground' \| 'mdl_kr_ownership' \| 'mdl_kr_age' \| 'mdl_kr_region'`. Also exported from `@zkproofport-app/sdk/circuits` |
1008
+ | `CircuitId` | Union of the five canonical circuit IDs — `'coinbase_attestation' \| 'coinbase_country_attestation' \| 'oidc_domain_attestation' \| 'giwa_attestation' \| 'dojang_playground'`. Also exported from `@zkproofport-app/sdk/circuits` |
1073
1009
  | `TypedAction` | The EIP-712 action a `giwa_attestation` proof binds to: `{ domain, types, primaryType, message }` — the same object `eth_signTypedData_v4` takes |
1074
- | `CircuitSupportStatus` | `'supported' \| 'planned'` — see [Circuit Identifiers](#circuit-identifiers) |
1010
+ | `CircuitSupportStatus` | `'supported' \| 'experimental' \| 'planned'` — see [Circuit Identifiers](#circuit-identifiers) |
1075
1011
  | `CircuitType` | Alias of `CircuitId`. Kept as the name used throughout `ProofRequest`, `ProofResponse` and the SDK methods |
1076
1012
  | `ProofRequestStatus` | `'pending' \| 'completed' \| 'error' \| 'cancelled'` — the status on a `ProofResponse` |
1077
1013
  | `CoinbaseKycInputs` | Inputs for `coinbase_attestation`: `{ scope, userAddress?, rawTransaction? }` |
1078
1014
  | `CoinbaseCountryInputs` | Inputs for `coinbase_country_attestation`: `{ scope, countryList, isIncluded, userAddress?, rawTransaction? }` |
1079
1015
  | `OidcDomainInputs` | Inputs for `oidc_domain_attestation`: `{ domain, scope, provider? }` |
1080
- | `MdlKrOwnershipInputs` | Inputs for `mdl_kr_ownership`: `{ scope, discloseFlags? }` |
1081
1016
  | `ActionBoundInputs` | Inputs for the circuits that can bind an EIP-712 action: `{ scope, action?, userAddress?, rawTransaction? }`. Whether the action is required is the circuit's property, in `CIRCUIT_ACTION_BINDING` — optional for `giwa_attestation` and `dojang_playground` |
1082
1017
  | `GiwaAttestationInputs` | Alias of `ActionBoundInputs`, for `giwa_attestation` |
1083
1018
  | `DojangPlaygroundInputs` | Alias of `ActionBoundInputs`, for `dojang_playground` |
1084
- | `MdlKrAgeInputs` | Inputs for `mdl_kr_age`: `{ scope, ageThreshold }` |
1085
- | `MdlKrRegionInputs` | Inputs for `mdl_kr_region`: `{ scope, targetRegion }` |
1086
1019
  | `CircuitInputs` | Union of every input type above (plus an empty-input form for circuits that need nothing from the dApp) |
1087
1020
  | `ProofRequest` | Request object: `requestId`, `circuit`, `inputs`, `createdAt`, plus optional `message`, `dappName`, `dappIcon`, `returnScheme` (a bare scheme such as `mydapp://`), `expiresAt` |
1088
1021
  | `ProofResponse` | What `verifyResponseOnChain()` takes: `requestId`, `circuit`, `status`, and — when completed — `proof`, `publicInputs`, `verifierAddress`, `chainId`; `error` when it failed. `numPublicInputs` and `timestamp` also exist but the relay never fills them, so omit them. Field by field in [Step 6](#step-6-read-the-result) |
@@ -1116,7 +1049,6 @@ import {
1116
1049
  COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT,
1117
1050
  COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT,
1118
1051
  OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT,
1119
- MDL_KR_PUBLIC_INPUT_LAYOUT,
1120
1052
  } from '@zkproofport-app/sdk';
1121
1053
  ```
1122
1054
 
@@ -1179,34 +1111,6 @@ Proofs from the earlier 148-entry version of this circuit bind no audience, expi
1179
1111
 
1180
1112
  Index 147 tells you which issuer signed the token, not whether the account belongs to an organisation. Workspace and Microsoft 365 membership is checked on-device only when you set `provider` in the request; if you did not set it, do not read a membership guarantee out of this field.
1181
1113
 
1182
- ### Korea Mobile ID (mDL) — one layout, three circuits
1183
-
1184
- All three mDL circuits share the same first 64 entries and differ after that. Entries are single bytes, except `age_threshold` and `current_year`, which each hold their whole value in one entry.
1185
-
1186
- | Index | Constants | Circuit field | Applies to |
1187
- |-------|-----------|---------------|------------|
1188
- | 0–31 | `SCOPE_START` / `_END` | `scope` | all three |
1189
- | 32–63 | `NULLIFIER_START` / `_END` | `nullifier_value` | all three |
1190
- | 64 | `OWNERSHIP_DISCLOSE_FLAGS` | `disclose_flags` | `mdl_kr_ownership` (97 entries) — the bitmask that was actually proved (`0x01` name, `0x02` birth, `0x04` sex, `0x08` phone) |
1191
- | 65–96 | `OWNERSHIP_OWNER_COMMIT_START` / `_END` | `owner_commit` | `mdl_kr_ownership` — `bytes32` commitment to the disclosed attributes. All zero when `disclose_flags` is `0`, which is the anonymous case |
1192
- | 64 | `AGE_THRESHOLD` | `age_threshold` | `mdl_kr_age` (66 entries) — the age the proof actually clears. Read it back; it is a public input, so confirm it is the threshold you asked for |
1193
- | 65 | `AGE_CURRENT_YEAR` | `current_year` | `mdl_kr_age` — the year the comparison was made in |
1194
- | 64–95 | `REGION_CODE_START` / `_END` | `region_code` | `mdl_kr_region` (96 entries) — `bytes32`, not a readable region name. See below |
1195
-
1196
- `region_code` is `keccak256` over the region name, UTF-8 and zero-padded to 64 bytes. The circuit proves that the region on the licence hashes to this value, but the value itself is a public input — so recompute it from the region you asked for and compare, exactly as you do with the scope:
1197
-
1198
- ```typescript
1199
- import { keccak256 } from 'ethers';
1200
-
1201
- const regionCodeFor = (region: string): string => {
1202
- const padded = new Uint8Array(64);
1203
- padded.set(new TextEncoder().encode(region));
1204
- return keccak256(padded);
1205
- };
1206
-
1207
- // regionCodeFor('경기도') — compare against indices 64–95, rebuilt with toBytes32()
1208
- ```
1209
-
1210
1114
  ## Error Handling
1211
1115
 
1212
1116
  Async SDK methods throw standard `Error` objects. The messages are stable enough to log, not to switch on:
@@ -1220,9 +1124,9 @@ try {
1220
1124
  }
1221
1125
 
1222
1126
  try {
1223
- await sdk.createRelayRequest('mdl_kr_age', { scope: 'app.com', ageThreshold: 0 });
1127
+ await sdk.createRelayRequest('coinbase-kyc', { scope: 'app.com' });
1224
1128
  } catch (err) {
1225
- // "ageThreshold is required and must be an integer between 1 and 150 (circuit: mdl_kr_age)"
1129
+ // "Unknown circuit 'coinbase-kyc'. Expected: coinbase_attestation, ..."
1226
1130
  }
1227
1131
 
1228
1132
  try {
@@ -189,22 +189,6 @@ export declare class ProofportSDK {
189
189
  * falling through to another circuit's builder.
190
190
  */
191
191
  private static readonly REQUEST_BUILDERS;
192
- /**
193
- * @internal
194
- * Creates a Korea Mobile ID (mDL) proof request for any of the three
195
- * mDL predicate circuits (ownership / age / region).
196
- *
197
- * The mobile app collects the license data on-device; the dapp only
198
- * supplies the predicate parameters validated here. No wallet signature
199
- * is required for mDL circuits.
200
- *
201
- * @param circuit - 'mdl_kr_ownership' | 'mdl_kr_age' | 'mdl_kr_region'
202
- * @param inputs - Predicate inputs (see MdlKr*Inputs types)
203
- * @param options - Request configuration options
204
- *
205
- * @throws Error if the predicate inputs fail validation
206
- */
207
- private createMdlKrRequest;
208
192
  /**
209
193
  * @internal
210
194
  * Generates a deep link URL for a proof request.
@@ -509,6 +493,7 @@ export declare class ProofportSDK {
509
493
  */
510
494
  verifyOnChain(circuit: CircuitType, proof: string, publicInputs: string[], providerOrSigner?: any, options?: {
511
495
  request?: OidcRequestContext;
496
+ signerVariant?: string;
512
497
  }): Promise<{
513
498
  valid: boolean;
514
499
  error?: string;
@@ -924,7 +909,7 @@ export declare class ProofportSDK {
924
909
  * @param requestId - The relay-issued request ID
925
910
  * @param options - Polling options
926
911
  * @param options.intervalMs - Polling interval in milliseconds (default: 2000)
927
- * @param options.timeoutMs - Maximum polling time in milliseconds (default: 300000 = 5 min)
912
+ * @param options.timeoutMs - Maximum polling time in milliseconds (default: 600000 = 10 min, `DEFAULT_RELAY_WAIT_MS`)
928
913
  * @param options.onStatusChange - Callback when status changes
929
914
  * @returns Promise resolving to final RelayProofResult
930
915
  * @throws Error if timeout or relay error
@@ -989,7 +974,7 @@ export declare class ProofportSDK {
989
974
  *
990
975
  * @param requestId - The relay-issued request ID
991
976
  * @param options - Configuration options
992
- * @param options.timeoutMs - Maximum wait time in ms (default: 300000 = 5 min)
977
+ * @param options.timeoutMs - Maximum wait time in ms (default: 600000 = 10 min, `DEFAULT_RELAY_WAIT_MS`)
993
978
  * @param options.onStatusChange - Callback for status updates
994
979
  * @returns Promise resolving to final RelayProofResult
995
980
  */
@@ -20,7 +20,7 @@ export declare const RELAY_URLS: Record<SDKEnvironment, string>;
20
20
  * Mirrors the mobile app's `CIRCUIT_NETWORKS` (proofport-app
21
21
  * src/config/contracts.ts), because a proof is checked where the app said its
22
22
  * verifier is: Base for the Coinbase and OIDC circuits, GIWA Sepolia for GIWA
23
- * and Dojang (testnet-only), Base Sepolia for Korea Mobile ID (testnet-only).
23
+ * and Dojang (testnet-only).
24
24
  * The ADDRESS on that chain always comes from core's pinned table, never from
25
25
  * a proof response.
26
26
  */
@@ -31,9 +31,6 @@ export declare const VERIFICATION_CHAINS: {
31
31
  readonly oidc_domain_attestation: 8453;
32
32
  readonly giwa_attestation: 91342;
33
33
  readonly dojang_playground: 91342;
34
- readonly mdl_kr_ownership: 84532;
35
- readonly mdl_kr_age: 84532;
36
- readonly mdl_kr_region: 84532;
37
34
  };
38
35
  readonly staging: {
39
36
  readonly coinbase_attestation: 84532;
@@ -41,9 +38,6 @@ export declare const VERIFICATION_CHAINS: {
41
38
  readonly oidc_domain_attestation: 84532;
42
39
  readonly giwa_attestation: 91342;
43
40
  readonly dojang_playground: 91342;
44
- readonly mdl_kr_ownership: 84532;
45
- readonly mdl_kr_age: 84532;
46
- readonly mdl_kr_region: 84532;
47
41
  };
48
42
  readonly local: {
49
43
  readonly coinbase_attestation: 84532;
@@ -51,9 +45,6 @@ export declare const VERIFICATION_CHAINS: {
51
45
  readonly oidc_domain_attestation: 84532;
52
46
  readonly giwa_attestation: 91342;
53
47
  readonly dojang_playground: 91342;
54
- readonly mdl_kr_ownership: 84532;
55
- readonly mdl_kr_age: 84532;
56
- readonly mdl_kr_region: 84532;
57
48
  };
58
49
  };
59
50
  /**
@@ -132,4 +123,4 @@ export declare const DEFAULT_REQUEST_EXPIRY_MS: number;
132
123
  * ```
133
124
  */
134
125
  export declare const MAX_QR_DATA_SIZE = 2953;
135
- export { VERIFIER_ABI, RPC_ENDPOINTS, COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, MDL_KR_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, } from '@zkproofport-app/core';
126
+ export { VERIFIER_ABI, RPC_ENDPOINTS, COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, } from '@zkproofport-app/core';
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Deep Link utilities for ZKProofport SDK
3
3
  */
4
- import type { ProofRequest, ProofResponse, CircuitInputs, DeepLinkComponents } from './types';
4
+ import type { ProofRequest, ProofResponse, DeepLinkComponents } from './types';
5
5
  /**
6
6
  * Generates a unique request ID for proof requests.
7
7
  *
@@ -170,23 +170,6 @@ export declare function parseDeepLink(url: string): DeepLinkComponents | null;
170
170
  * ```
171
171
  */
172
172
  export declare function isProofportDeepLink(url: string, scheme?: string): boolean;
173
- /**
174
- * Validates dapp-supplied inputs for the Korea Mobile ID (mDL) circuits.
175
- * Shared by deep-link request validation and relay request creation so the
176
- * same guards apply on every request path.
177
- *
178
- * Rules:
179
- * - `scope` — required non-empty string, ≤256 chars, no control characters
180
- * - `mdl_kr_ownership.discloseFlags` — optional integer 0–15 (0x0F bitmask)
181
- * - `mdl_kr_age.ageThreshold` — required integer 1–150
182
- * - `mdl_kr_region.targetRegion` — required non-empty string (Korean si/do),
183
- * ≤256 chars, no control characters
184
- *
185
- * @param circuit - One of the three mDL circuit identifiers
186
- * @param inputs - Dapp-supplied circuit inputs
187
- * @returns Error message string, or null when the inputs are valid
188
- */
189
- export declare function validateMdlInputs(circuit: 'mdl_kr_ownership' | 'mdl_kr_age' | 'mdl_kr_region', inputs: CircuitInputs): string | null;
190
173
  /**
191
174
  * Longest accepted `returnScheme` value.
192
175
  * Kept in sync with proofport-relay `src/returnScheme.ts`.
@@ -273,6 +256,22 @@ export declare function validateReturnScheme(value: unknown): string | null;
273
256
  * @internal
274
257
  */
275
258
  export declare function detectReturnScheme(userAgent?: string): string | undefined;
259
+ /**
260
+ * @internal
261
+ * Validates a proof request for completeness and correctness.
262
+ *
263
+ * Performs comprehensive validation including:
264
+ * - Required fields (requestId, circuit, callbackUrl)
265
+ * - Circuit type validity (must be a supported circuit)
266
+ * - Circuit-specific input validation (e.g., userAddress format, countryList structure)
267
+ * - Expiration check (if expiresAt is provided)
268
+ *
269
+ * Note: userAddress is optional for both circuits - the mobile app will prompt
270
+ * for wallet connection if not provided.
271
+ *
272
+ * @param request - Proof request to validate
273
+ * @returns Validation result with `valid` flag and optional `error` message
274
+ */
276
275
  export declare function validateProofRequest(request: ProofRequest): {
277
276
  valid: boolean;
278
277
  error?: string;
package/dist/index.d.ts CHANGED
@@ -27,17 +27,17 @@
27
27
  */
28
28
  export { ProofportSDK, default } from './ProofportSDK';
29
29
  export { extractScopeFromPublicInputs, extractNullifierFromPublicInputs, extractDomainFromPublicInputs, } from './verifier';
30
- export { CIRCUIT_IDS, CIRCUIT_SUPPORT_STATUS, ALL_CIRCUIT_IDS, SUPPORTED_CIRCUIT_IDS, EXPERIMENTAL_CIRCUIT_IDS, PLANNED_CIRCUIT_IDS, isCircuitId, isSupportedCircuitId, getCircuitSupportStatus, CIRCUIT_VK_PATHS, } from './circuits';
30
+ export { CIRCUIT_IDS, CIRCUIT_SUPPORT_STATUS, ALL_CIRCUIT_IDS, SUPPORTED_CIRCUIT_IDS, EXPERIMENTAL_CIRCUIT_IDS, PLANNED_CIRCUIT_IDS, isCircuitId, isSupportedCircuitId, getCircuitSupportStatus, CIRCUIT_VK_PATHS, CIRCUIT_PACKAGES, SIGNER_VARIANTS, isSignerVariant, signerVariantsOf, getCircuitPackage, resolveSignerVariant, evmProofByteLength, } from './circuits';
31
31
  export { verifyProofOffChain } from './offChainVerifier';
32
32
  export type { OffChainVerifyResult, OffChainVerifyOptions, } from './offChainVerifier';
33
- export { PINNED_VERIFIERS, getPinnedVerifier } from './verifier';
33
+ export { PINNED_VERIFIERS, PINNED_VARIANT_VERIFIERS, getPinnedVerifier, getPinnedVariantVerifier } from './verifier';
34
34
  export type { PinnedVerifier } from './verifier';
35
35
  export { checkOidcPolicy, deriveOidcNonceBinding, oidcAudienceHash, OIDC_ALLOWED_AUDIENCES, OIDC_NONCE_DOMAIN, OIDC_NOW_MAX_AGE_SECONDS, OIDC_NOW_MAX_FUTURE_SECONDS, OIDC_V1_PUBLIC_INPUT_COUNT, OIDC_V2_PUBLIC_INPUT_COUNT, } from './verifier';
36
36
  export type { OidcRequestContext, OidcAudience, OidcNonceMode } from './verifier';
37
- export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, MDL_KR_PUBLIC_INPUT_LAYOUT, } from './constants';
38
- export type { CircuitId, CircuitSupportStatus } from './circuits';
37
+ export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, } from './constants';
38
+ export type { CircuitId, CircuitSupportStatus, SignerVariant, CircuitPackage } from './circuits';
39
39
  export { CIRCUIT_ACTION_BINDING, circuitActionBinding, } from './circuits';
40
40
  export type { CircuitActionBinding } from './circuits';
41
- export type { CircuitType, ProofRequestStatus, CoinbaseKycInputs, ActionBoundInputs, GiwaAttestationInputs, DojangPlaygroundInputs, TypedAction, CoinbaseCountryInputs, OidcDomainInputs, MdlKrOwnershipInputs, MdlKrAgeInputs, MdlKrRegionInputs, CircuitInputs, ProofRequest, ProofResponse, QRCodeOptions, VerifierContract, ProofportConfig, ChallengeResponse, WalletSigner, RelayProofRequest, RelayProofResult, RelayProofStatus, RelayTerminalStatus, SDKEnvironment, } from './types';
42
- export { RELAY_TERMINAL_STATUSES, isTerminalRelayStatus } from './relayStatus';
41
+ export type { CircuitType, ProofRequestStatus, CoinbaseKycInputs, ActionBoundInputs, GiwaAttestationInputs, DojangPlaygroundInputs, TypedAction, CoinbaseCountryInputs, OidcDomainInputs, CircuitInputs, ProofRequest, ProofResponse, QRCodeOptions, VerifierContract, ProofportConfig, ChallengeResponse, WalletSigner, RelayProofRequest, RelayProofResult, RelayProofStatus, RelayTerminalStatus, SDKEnvironment, } from './types';
42
+ export { RELAY_TERMINAL_STATUSES, isTerminalRelayStatus, DEFAULT_RELAY_WAIT_MS } from './relayStatus';
43
43
  export { validateTypedAction, parseTypedAction } from './typedAction';