@zkproofport-app/sdk 0.2.6 → 0.2.8

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 ZKProofport
3
+ Copyright (c) 2026 Masse Labs Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
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.
6
+ TypeScript SDK for requesting zero-knowledge proofs from the [ZKProofport](https://zkproofport.com) mobile app and verifying them on-chain. Supports Coinbase KYC/Country attestations and OIDC domain attestations (Google, Microsoft 365).
7
7
 
8
8
  ## How It Works
9
9
 
@@ -163,6 +163,56 @@ const relay = await sdk.createRelayRequest('oidc_domain_attestation', {
163
163
 
164
164
  > When `provider` is set, the mobile app verifies the user's account is managed by the specified workspace provider (e.g., Google Workspace `hd` claim, Microsoft 365 `tid` claim). Without `provider`, only the email domain is verified.
165
165
 
166
+ ### `mdl_kr_ownership`
167
+
168
+ 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 signature is required.
169
+
170
+ | Field | Type | Required | Description |
171
+ |-------|------|----------|-------------|
172
+ | `scope` | `string` | Yes | Application-specific identifier for proof uniqueness |
173
+ | `discloseFlags` | `number` | No | Attribute disclosure bitmask `0x00`–`0x0F` (`0x01` name, `0x02` birth, `0x04` sex, `0x08` phone). Omit or `0` for a fully anonymous ownership proof. |
174
+
175
+ ```typescript
176
+ // Anonymous "holds a valid Korean mobile ID" proof
177
+ const relay = await sdk.createRelayRequest('mdl_kr_ownership', {
178
+ scope: 'myapp.com',
179
+ });
180
+ ```
181
+
182
+ ### `mdl_kr_age`
183
+
184
+ Proves the user is at least `ageThreshold` years old according to their Korean mobile driver's license, without revealing the birth date.
185
+
186
+ | Field | Type | Required | Description |
187
+ |-------|------|----------|-------------|
188
+ | `scope` | `string` | Yes | Application-specific identifier |
189
+ | `ageThreshold` | `number` | Yes | Minimum age to prove (integer 1–150, e.g. `19` for Korean adult verification) |
190
+
191
+ ```typescript
192
+ const relay = await sdk.createRelayRequest('mdl_kr_age', {
193
+ scope: 'myapp.com',
194
+ ageThreshold: 19,
195
+ });
196
+ ```
197
+
198
+ ### `mdl_kr_region`
199
+
200
+ Proves the user's registered address is in the specified si/do region without revealing the full address.
201
+
202
+ | Field | Type | Required | Description |
203
+ |-------|------|----------|-------------|
204
+ | `scope` | `string` | Yes | Application-specific identifier |
205
+ | `targetRegion` | `string` | Yes | Region (si/do) to prove residency in, in Korean (e.g. `'경기도'`, `'서울특별시'`) |
206
+
207
+ ```typescript
208
+ const relay = await sdk.createRelayRequest('mdl_kr_region', {
209
+ scope: 'myapp.com',
210
+ targetRegion: '경기도',
211
+ });
212
+ ```
213
+
214
+ > 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(result.publicInputs, result.circuit)` for sybil-resistant user identification.
215
+
166
216
  ## Integration Guide
167
217
 
168
218
  ### Step 1: Initialize
@@ -373,9 +423,9 @@ if (result.status === 'completed') {
373
423
  const verification = await sdk.verifyResponseOnChain(response);
374
424
  ```
375
425
 
376
- ### Step 7: Extract Scope and Nullifier
426
+ ### Step 7: Extract Scope, Nullifier, and Domain
377
427
 
378
- After verification, extract the scope and nullifier from the public inputs:
428
+ After verification, extract data from the public inputs:
379
429
 
380
430
  ```typescript
381
431
  if (result.status === 'completed') {
@@ -388,6 +438,12 @@ if (result.status === 'completed') {
388
438
 
389
439
  console.log('Scope:', scope); // '0x7a6b70726f...'
390
440
  console.log('Nullifier:', nullifier); // '0xabc123...'
441
+
442
+ // Extract domain — only for OIDC Domain Attestation
443
+ if (result.circuit === 'oidc_domain_attestation') {
444
+ const domain = sdk.extractDomain(result.publicInputs, result.circuit);
445
+ console.log('Domain:', domain); // 'example.com'
446
+ }
391
447
  }
392
448
  ```
393
449
 
@@ -398,16 +454,31 @@ The **nullifier** serves as a privacy-preserving user identifier:
398
454
 
399
455
  > **OIDC Domain:** The nullifier is a hash of the user's email and scope. The same email + scope always produces the same nullifier, enabling Sybil resistance without revealing the email address.
400
456
 
457
+ The **domain** (OIDC Domain Attestation only) is the email domain the user proved:
458
+ - Extracted from the circuit's public inputs
459
+ - Matches the domain parameter provided during proof request
460
+ - Available only for `oidc_domain_attestation` circuits
461
+
401
462
  **Standalone utility functions** are also available for use outside the SDK class:
402
463
 
403
464
  ```typescript
404
465
  import {
405
466
  extractScopeFromPublicInputs,
406
467
  extractNullifierFromPublicInputs,
468
+ extractDomainFromPublicInputs,
407
469
  } from '@zkproofport-app/sdk';
408
470
 
471
+ // Works with all circuits: coinbase_attestation, coinbase_country_attestation, oidc_domain_attestation, mdl_kr_ownership, mdl_kr_age, mdl_kr_region
409
472
  const scope = extractScopeFromPublicInputs(publicInputs, 'coinbase_attestation');
410
473
  const nullifier = extractNullifierFromPublicInputs(publicInputs, 'coinbase_attestation');
474
+
475
+ // OIDC domain attestation uses a different public input layout (148 fields)
476
+ const oidcScope = extractScopeFromPublicInputs(publicInputs, 'oidc_domain_attestation');
477
+ const oidcNullifier = extractNullifierFromPublicInputs(publicInputs, 'oidc_domain_attestation');
478
+
479
+ // Extract domain from OIDC Domain Attestation
480
+ const domain = extractDomainFromPublicInputs(publicInputs, 'oidc_domain_attestation');
481
+ // domain: 'example.com' or null if circuit doesn't match or inputs insufficient
411
482
  ```
412
483
 
413
484
  ## Complete Example
@@ -524,6 +595,72 @@ interface OidcDomainInputs {
524
595
  }
525
596
  ```
526
597
 
598
+ ## Public Input Layout Constants
599
+
600
+ The SDK exports constants defining the field positions in each circuit's public inputs array. These are useful when working with standalone extraction functions or building custom verification logic.
601
+
602
+ ```typescript
603
+ import {
604
+ COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT,
605
+ COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT,
606
+ OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT,
607
+ } from '@zkproofport-app/sdk';
608
+ ```
609
+
610
+ **Coinbase KYC Attestation** (128 fields total):
611
+ ```typescript
612
+ COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT = {
613
+ SIGNAL_HASH_START: 0, // RSA modulus limbs (Coinbase signer)
614
+ SIGNAL_HASH_END: 31,
615
+ MERKLE_ROOT_START: 32, // Merkle root of signers
616
+ MERKLE_ROOT_END: 63,
617
+ SCOPE_START: 64, // keccak256 hash of scope string
618
+ SCOPE_END: 95,
619
+ NULLIFIER_START: 96, // Unique identifier per user+scope
620
+ NULLIFIER_END: 127,
621
+ }
622
+ ```
623
+
624
+ **Coinbase Country Attestation** (150 fields total):
625
+ ```typescript
626
+ COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT = {
627
+ SIGNAL_HASH_START: 0,
628
+ SIGNAL_HASH_END: 31,
629
+ MERKLE_ROOT_START: 32,
630
+ MERKLE_ROOT_END: 63,
631
+ COUNTRY_LIST_START: 64, // Packed country codes
632
+ COUNTRY_LIST_END: 83,
633
+ COUNTRY_LIST_LENGTH: 84, // Number of countries
634
+ IS_INCLUDED: 85, // Boolean: user in list or not
635
+ SCOPE_START: 86,
636
+ SCOPE_END: 117,
637
+ NULLIFIER_START: 118,
638
+ NULLIFIER_END: 149,
639
+ }
640
+ ```
641
+
642
+ **OIDC Domain Attestation** (148 fields total):
643
+ ```typescript
644
+ OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT = {
645
+ PUBKEY_MODULUS_START: 0, // RSA modulus limbs (JWT issuer key)
646
+ PUBKEY_MODULUS_END: 17,
647
+ DOMAIN_STORAGE_START: 18, // Domain bytes (up to 64 ASCII characters)
648
+ DOMAIN_STORAGE_END: 81,
649
+ DOMAIN_LEN: 82, // Domain string length
650
+ SCOPE_START: 83, // keccak256 hash of scope string
651
+ SCOPE_END: 114,
652
+ NULLIFIER_START: 115, // Unique identifier per user+scope
653
+ NULLIFIER_END: 146,
654
+ PROVIDER: 147, // OIDC provider code (0=none, 1=Google, 2=Microsoft)
655
+
656
+ // Deprecated aliases (use new names above)
657
+ DOMAIN_START: 18, // @deprecated Use DOMAIN_STORAGE_START
658
+ DOMAIN_END: 82, // @deprecated Use DOMAIN_LEN
659
+ }
660
+ ```
661
+
662
+ > **Note on field positions:** Each position in the public inputs array corresponds to a field element in the circuit. For bytes32 values (scope, nullifier, signal hash), 32 consecutive fields are concatenated to form the final value.
663
+
527
664
  ## Error Handling
528
665
 
529
666
  All async SDK methods throw standard `Error` objects:
@@ -168,6 +168,22 @@ export declare class ProofportSDK {
168
168
  * ```
169
169
  */
170
170
  private createProofRequest;
171
+ /**
172
+ * @internal
173
+ * Creates a Korea Mobile ID (mDL) proof request for any of the three
174
+ * mDL predicate circuits (ownership / age / region).
175
+ *
176
+ * The mobile app collects the license data on-device; the dapp only
177
+ * supplies the predicate parameters validated here. No wallet signature
178
+ * is required for mDL circuits.
179
+ *
180
+ * @param circuit - 'mdl_kr_ownership' | 'mdl_kr_age' | 'mdl_kr_region'
181
+ * @param inputs - Predicate inputs (see MdlKr*Inputs types)
182
+ * @param options - Request configuration options
183
+ *
184
+ * @throws Error if the predicate inputs fail validation
185
+ */
186
+ private createMdlKrRequest;
171
187
  /**
172
188
  * @internal
173
189
  * Generates a deep link URL for a proof request.
@@ -916,5 +932,24 @@ export declare class ProofportSDK {
916
932
  * ```
917
933
  */
918
934
  extractNullifier(publicInputs: string[], circuit: CircuitType): string | null;
935
+ /**
936
+ * Extracts the domain string from OIDC Domain Attestation proof public inputs.
937
+ *
938
+ * Only works with 'oidc_domain_attestation' circuit. Returns null for other circuits.
939
+ *
940
+ * @param publicInputs - Array of hex-encoded field elements from proof result
941
+ * @param circuit - Circuit type that produced the public inputs
942
+ * @returns Domain as ASCII string (e.g., 'example.com'), or null if not applicable
943
+ *
944
+ * @example
945
+ * ```typescript
946
+ * const result = await sdk.waitForProof(relay.requestId);
947
+ * if (result.status === 'completed') {
948
+ * const domain = sdk.extractDomain(result.publicInputs, result.circuit);
949
+ * console.log('Domain:', domain); // 'example.com'
950
+ * }
951
+ * ```
952
+ */
953
+ extractDomain(publicInputs: string[], circuit: CircuitType): string | null;
919
954
  }
920
955
  export default ProofportSDK;
@@ -183,6 +183,36 @@ export declare const COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT: {
183
183
  readonly NULLIFIER_START: 118;
184
184
  readonly NULLIFIER_END: 149;
185
185
  };
186
+ /**
187
+ * Korea Mobile ID (mDL) circuit public input layout (field offsets).
188
+ * All three mDL circuits share the same prefix: scope [0..31] and
189
+ * nullifier_value [32..63], each stored one byte per field element.
190
+ * The suffix differs per predicate circuit:
191
+ * - mdl_kr_ownership (97 inputs): disclose_flags [64], owner_commit [65..96]
192
+ * - mdl_kr_age (66 inputs): age_threshold [64], current_year [65]
193
+ * - mdl_kr_region (96 inputs): region_code [64..95]
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * const nullifier = publicInputs.slice(
198
+ * MDL_KR_PUBLIC_INPUT_LAYOUT.NULLIFIER_START,
199
+ * MDL_KR_PUBLIC_INPUT_LAYOUT.NULLIFIER_END + 1
200
+ * );
201
+ * ```
202
+ */
203
+ export declare const MDL_KR_PUBLIC_INPUT_LAYOUT: {
204
+ readonly SCOPE_START: 0;
205
+ readonly SCOPE_END: 31;
206
+ readonly NULLIFIER_START: 32;
207
+ readonly NULLIFIER_END: 63;
208
+ readonly OWNERSHIP_DISCLOSE_FLAGS: 64;
209
+ readonly OWNERSHIP_OWNER_COMMIT_START: 65;
210
+ readonly OWNERSHIP_OWNER_COMMIT_END: 96;
211
+ readonly AGE_THRESHOLD: 64;
212
+ readonly AGE_CURRENT_YEAR: 65;
213
+ readonly REGION_CODE_START: 64;
214
+ readonly REGION_CODE_END: 95;
215
+ };
186
216
  /**
187
217
  * OIDC Domain Attestation circuit public input layout (field offsets).
188
218
  * Defines the field positions in the flattened public inputs array (148 fields total).
@@ -205,12 +235,16 @@ export declare const COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT: {
205
235
  export declare const OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT: {
206
236
  readonly PUBKEY_MODULUS_START: 0;
207
237
  readonly PUBKEY_MODULUS_END: 17;
208
- readonly DOMAIN_LEN: 18;
209
- readonly DOMAIN_START: 19;
210
- readonly DOMAIN_END: 82;
238
+ readonly DOMAIN_STORAGE_START: 18;
239
+ readonly DOMAIN_STORAGE_END: 81;
240
+ readonly DOMAIN_LEN: 82;
211
241
  readonly SCOPE_START: 83;
212
242
  readonly SCOPE_END: 114;
213
243
  readonly NULLIFIER_START: 115;
214
244
  readonly NULLIFIER_END: 146;
215
245
  readonly PROVIDER: 147;
246
+ /** @deprecated Use DOMAIN_STORAGE_START */
247
+ readonly DOMAIN_START: 18;
248
+ /** @deprecated Use DOMAIN_LEN */
249
+ readonly DOMAIN_END: 82;
216
250
  };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Deep Link utilities for ZKProofport SDK
3
3
  */
4
- import type { ProofRequest, ProofResponse, DeepLinkComponents } from './types';
4
+ import type { ProofRequest, ProofResponse, CircuitInputs, DeepLinkComponents } from './types';
5
5
  /**
6
6
  * Generates a unique request ID for proof requests.
7
7
  *
@@ -171,21 +171,22 @@ export declare function parseDeepLink(url: string): DeepLinkComponents | null;
171
171
  */
172
172
  export declare function isProofportDeepLink(url: string, scheme?: string): boolean;
173
173
  /**
174
- * @internal
175
- * Validates a proof request for completeness and correctness.
176
- *
177
- * Performs comprehensive validation including:
178
- * - Required fields (requestId, circuit, callbackUrl)
179
- * - Circuit type validity (must be a supported circuit)
180
- * - Circuit-specific input validation (e.g., userAddress format, countryList structure)
181
- * - Expiration check (if expiresAt is provided)
182
- *
183
- * Note: userAddress is optional for both circuits - the mobile app will prompt
184
- * for wallet connection if not provided.
185
- *
186
- * @param request - Proof request to validate
187
- * @returns Validation result with `valid` flag and optional `error` message
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
188
  */
189
+ export declare function validateMdlInputs(circuit: 'mdl_kr_ownership' | 'mdl_kr_age' | 'mdl_kr_region', inputs: CircuitInputs): string | null;
189
190
  export declare function validateProofRequest(request: ProofRequest): {
190
191
  valid: boolean;
191
192
  error?: string;
package/dist/index.d.ts CHANGED
@@ -26,6 +26,6 @@
26
26
  * ```
27
27
  */
28
28
  export { ProofportSDK, default } from './ProofportSDK';
29
- export { extractScopeFromPublicInputs, extractNullifierFromPublicInputs, } from './verifier';
30
- export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, } from './constants';
31
- export type { CircuitType, ProofRequestStatus, CoinbaseKycInputs, CoinbaseCountryInputs, OidcDomainInputs, CircuitInputs, ProofRequest, ProofResponse, QRCodeOptions, VerifierContract, ProofportConfig, ChallengeResponse, WalletSigner, RelayProofRequest, RelayProofResult, SDKEnvironment, } from './types';
29
+ export { extractScopeFromPublicInputs, extractNullifierFromPublicInputs, extractDomainFromPublicInputs, } from './verifier';
30
+ export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, MDL_KR_PUBLIC_INPUT_LAYOUT, } from './constants';
31
+ export type { CircuitType, ProofRequestStatus, CoinbaseKycInputs, CoinbaseCountryInputs, OidcDomainInputs, MdlKrOwnershipInputs, MdlKrAgeInputs, MdlKrRegionInputs, CircuitInputs, ProofRequest, ProofResponse, QRCodeOptions, VerifierContract, ProofportConfig, ChallengeResponse, WalletSigner, RelayProofRequest, RelayProofResult, SDKEnvironment, } from './types';