@zkproofport-app/sdk 0.2.5 → 0.2.7

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.
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
 
@@ -373,9 +373,9 @@ if (result.status === 'completed') {
373
373
  const verification = await sdk.verifyResponseOnChain(response);
374
374
  ```
375
375
 
376
- ### Step 7: Extract Scope and Nullifier
376
+ ### Step 7: Extract Scope, Nullifier, and Domain
377
377
 
378
- After verification, extract the scope and nullifier from the public inputs:
378
+ After verification, extract data from the public inputs:
379
379
 
380
380
  ```typescript
381
381
  if (result.status === 'completed') {
@@ -388,6 +388,12 @@ if (result.status === 'completed') {
388
388
 
389
389
  console.log('Scope:', scope); // '0x7a6b70726f...'
390
390
  console.log('Nullifier:', nullifier); // '0xabc123...'
391
+
392
+ // Extract domain — only for OIDC Domain Attestation
393
+ if (result.circuit === 'oidc_domain_attestation') {
394
+ const domain = sdk.extractDomain(result.publicInputs, result.circuit);
395
+ console.log('Domain:', domain); // 'example.com'
396
+ }
391
397
  }
392
398
  ```
393
399
 
@@ -398,16 +404,31 @@ The **nullifier** serves as a privacy-preserving user identifier:
398
404
 
399
405
  > **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
406
 
407
+ The **domain** (OIDC Domain Attestation only) is the email domain the user proved:
408
+ - Extracted from the circuit's public inputs
409
+ - Matches the domain parameter provided during proof request
410
+ - Available only for `oidc_domain_attestation` circuits
411
+
401
412
  **Standalone utility functions** are also available for use outside the SDK class:
402
413
 
403
414
  ```typescript
404
415
  import {
405
416
  extractScopeFromPublicInputs,
406
417
  extractNullifierFromPublicInputs,
418
+ extractDomainFromPublicInputs,
407
419
  } from '@zkproofport-app/sdk';
408
420
 
421
+ // Works with all circuits: coinbase_attestation, coinbase_country_attestation, oidc_domain_attestation
409
422
  const scope = extractScopeFromPublicInputs(publicInputs, 'coinbase_attestation');
410
423
  const nullifier = extractNullifierFromPublicInputs(publicInputs, 'coinbase_attestation');
424
+
425
+ // OIDC domain attestation uses a different public input layout (148 fields)
426
+ const oidcScope = extractScopeFromPublicInputs(publicInputs, 'oidc_domain_attestation');
427
+ const oidcNullifier = extractNullifierFromPublicInputs(publicInputs, 'oidc_domain_attestation');
428
+
429
+ // Extract domain from OIDC Domain Attestation
430
+ const domain = extractDomainFromPublicInputs(publicInputs, 'oidc_domain_attestation');
431
+ // domain: 'example.com' or null if circuit doesn't match or inputs insufficient
411
432
  ```
412
433
 
413
434
  ## Complete Example
@@ -524,6 +545,72 @@ interface OidcDomainInputs {
524
545
  }
525
546
  ```
526
547
 
548
+ ## Public Input Layout Constants
549
+
550
+ 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.
551
+
552
+ ```typescript
553
+ import {
554
+ COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT,
555
+ COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT,
556
+ OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT,
557
+ } from '@zkproofport-app/sdk';
558
+ ```
559
+
560
+ **Coinbase KYC Attestation** (128 fields total):
561
+ ```typescript
562
+ COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT = {
563
+ SIGNAL_HASH_START: 0, // RSA modulus limbs (Coinbase signer)
564
+ SIGNAL_HASH_END: 31,
565
+ MERKLE_ROOT_START: 32, // Merkle root of signers
566
+ MERKLE_ROOT_END: 63,
567
+ SCOPE_START: 64, // keccak256 hash of scope string
568
+ SCOPE_END: 95,
569
+ NULLIFIER_START: 96, // Unique identifier per user+scope
570
+ NULLIFIER_END: 127,
571
+ }
572
+ ```
573
+
574
+ **Coinbase Country Attestation** (150 fields total):
575
+ ```typescript
576
+ COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT = {
577
+ SIGNAL_HASH_START: 0,
578
+ SIGNAL_HASH_END: 31,
579
+ MERKLE_ROOT_START: 32,
580
+ MERKLE_ROOT_END: 63,
581
+ COUNTRY_LIST_START: 64, // Packed country codes
582
+ COUNTRY_LIST_END: 83,
583
+ COUNTRY_LIST_LENGTH: 84, // Number of countries
584
+ IS_INCLUDED: 85, // Boolean: user in list or not
585
+ SCOPE_START: 86,
586
+ SCOPE_END: 117,
587
+ NULLIFIER_START: 118,
588
+ NULLIFIER_END: 149,
589
+ }
590
+ ```
591
+
592
+ **OIDC Domain Attestation** (148 fields total):
593
+ ```typescript
594
+ OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT = {
595
+ PUBKEY_MODULUS_START: 0, // RSA modulus limbs (JWT issuer key)
596
+ PUBKEY_MODULUS_END: 17,
597
+ DOMAIN_STORAGE_START: 18, // Domain bytes (up to 64 ASCII characters)
598
+ DOMAIN_STORAGE_END: 81,
599
+ DOMAIN_LEN: 82, // Domain string length
600
+ SCOPE_START: 83, // keccak256 hash of scope string
601
+ SCOPE_END: 114,
602
+ NULLIFIER_START: 115, // Unique identifier per user+scope
603
+ NULLIFIER_END: 146,
604
+ PROVIDER: 147, // OIDC provider code (0=none, 1=Google, 2=Microsoft)
605
+
606
+ // Deprecated aliases (use new names above)
607
+ DOMAIN_START: 18, // @deprecated Use DOMAIN_STORAGE_START
608
+ DOMAIN_END: 82, // @deprecated Use DOMAIN_LEN
609
+ }
610
+ ```
611
+
612
+ > **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.
613
+
527
614
  ## Error Handling
528
615
 
529
616
  All async SDK methods throw standard `Error` objects:
@@ -916,5 +916,24 @@ export declare class ProofportSDK {
916
916
  * ```
917
917
  */
918
918
  extractNullifier(publicInputs: string[], circuit: CircuitType): string | null;
919
+ /**
920
+ * Extracts the domain string from OIDC Domain Attestation proof public inputs.
921
+ *
922
+ * Only works with 'oidc_domain_attestation' circuit. Returns null for other circuits.
923
+ *
924
+ * @param publicInputs - Array of hex-encoded field elements from proof result
925
+ * @param circuit - Circuit type that produced the public inputs
926
+ * @returns Domain as ASCII string (e.g., 'example.com'), or null if not applicable
927
+ *
928
+ * @example
929
+ * ```typescript
930
+ * const result = await sdk.waitForProof(relay.requestId);
931
+ * if (result.status === 'completed') {
932
+ * const domain = sdk.extractDomain(result.publicInputs, result.circuit);
933
+ * console.log('Domain:', domain); // 'example.com'
934
+ * }
935
+ * ```
936
+ */
937
+ extractDomain(publicInputs: string[], circuit: CircuitType): string | null;
919
938
  }
920
939
  export default ProofportSDK;
@@ -184,14 +184,15 @@ export declare const COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT: {
184
184
  readonly NULLIFIER_END: 149;
185
185
  };
186
186
  /**
187
- * OIDC Domain Attestation circuit public input layout (byte offsets).
188
- * Defines the byte positions of each field in the flattened public inputs array.
187
+ * OIDC Domain Attestation circuit public input layout (field offsets).
188
+ * Defines the field positions in the flattened public inputs array (148 fields total).
189
189
  *
190
- * Public inputs are packed as individual field elements (one byte per element):
191
- * - pubkey_modulus_limbs: 18 x u128 = 18 x 16 bytes = 288 bytes → fields 0–287
192
- * - domain (BoundedVec<u8, 64>): 4-byte length (u32) + 64-byte storage = 68 fields → fields 288355
193
- * - scope: 32 bytes → fields 356387
194
- * - nullifier: 32 bytes → fields 388419
190
+ * Circuit public inputs (from main.nr):
191
+ * - pubkey_modulus_limbs: pub [u128; 18] 18 fields (0–17)
192
+ * - domain: pub BoundedVec<u8, 64> 1 len + 64 storage = 65 fields (1882)
193
+ * - scope: pub [u8; 32]32 fields (83114)
194
+ * - nullifier: pub [u8; 32]32 fields (115146)
195
+ * - provider: pub u8 → 1 field (147)
195
196
  *
196
197
  * @example
197
198
  * ```typescript
@@ -203,11 +204,17 @@ export declare const COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT: {
203
204
  */
204
205
  export declare const OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT: {
205
206
  readonly PUBKEY_MODULUS_START: 0;
206
- readonly PUBKEY_MODULUS_END: 287;
207
- readonly DOMAIN_START: 288;
208
- readonly DOMAIN_END: 355;
209
- readonly SCOPE_START: 356;
210
- readonly SCOPE_END: 387;
211
- readonly NULLIFIER_START: 388;
212
- readonly NULLIFIER_END: 419;
207
+ readonly PUBKEY_MODULUS_END: 17;
208
+ readonly DOMAIN_STORAGE_START: 18;
209
+ readonly DOMAIN_STORAGE_END: 81;
210
+ readonly DOMAIN_LEN: 82;
211
+ readonly SCOPE_START: 83;
212
+ readonly SCOPE_END: 114;
213
+ readonly NULLIFIER_START: 115;
214
+ readonly NULLIFIER_END: 146;
215
+ readonly PROVIDER: 147;
216
+ /** @deprecated Use DOMAIN_STORAGE_START */
217
+ readonly DOMAIN_START: 18;
218
+ /** @deprecated Use DOMAIN_LEN */
219
+ readonly DOMAIN_END: 82;
213
220
  };
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';
29
+ export { extractScopeFromPublicInputs, extractNullifierFromPublicInputs, extractDomainFromPublicInputs, } from './verifier';
30
30
  export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, } from './constants';
31
31
  export type { CircuitType, ProofRequestStatus, CoinbaseKycInputs, CoinbaseCountryInputs, OidcDomainInputs, CircuitInputs, ProofRequest, ProofResponse, QRCodeOptions, VerifierContract, ProofportConfig, ChallengeResponse, WalletSigner, RelayProofRequest, RelayProofResult, SDKEnvironment, } from './types';
package/dist/index.esm.js CHANGED
@@ -70,8 +70,8 @@ const CIRCUIT_METADATA = {
70
70
  oidc_domain_attestation: {
71
71
  name: 'OIDC Domain',
72
72
  description: 'Prove email domain affiliation via OIDC JWT',
73
- publicInputsCount: 420,
74
- publicInputNames: ['pubkey_modulus_limbs', 'domain', 'scope', 'nullifier'],
73
+ publicInputsCount: 148,
74
+ publicInputNames: ['pubkey_modulus_limbs', 'domain', 'scope', 'nullifier', 'provider'],
75
75
  },
76
76
  };
77
77
  /**
@@ -205,14 +205,15 @@ const COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT = {
205
205
  NULLIFIER_END: 149,
206
206
  };
207
207
  /**
208
- * OIDC Domain Attestation circuit public input layout (byte offsets).
209
- * Defines the byte positions of each field in the flattened public inputs array.
208
+ * OIDC Domain Attestation circuit public input layout (field offsets).
209
+ * Defines the field positions in the flattened public inputs array (148 fields total).
210
210
  *
211
- * Public inputs are packed as individual field elements (one byte per element):
212
- * - pubkey_modulus_limbs: 18 x u128 = 18 x 16 bytes = 288 bytes → fields 0–287
213
- * - domain (BoundedVec<u8, 64>): 4-byte length (u32) + 64-byte storage = 68 fields → fields 288355
214
- * - scope: 32 bytes → fields 356387
215
- * - nullifier: 32 bytes → fields 388419
211
+ * Circuit public inputs (from main.nr):
212
+ * - pubkey_modulus_limbs: pub [u128; 18] 18 fields (0–17)
213
+ * - domain: pub BoundedVec<u8, 64> 1 len + 64 storage = 65 fields (1882)
214
+ * - scope: pub [u8; 32]32 fields (83114)
215
+ * - nullifier: pub [u8; 32]32 fields (115146)
216
+ * - provider: pub u8 → 1 field (147)
216
217
  *
217
218
  * @example
218
219
  * ```typescript
@@ -224,13 +225,19 @@ const COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT = {
224
225
  */
225
226
  const OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT = {
226
227
  PUBKEY_MODULUS_START: 0,
227
- PUBKEY_MODULUS_END: 287,
228
- DOMAIN_START: 288,
229
- DOMAIN_END: 355,
230
- SCOPE_START: 356,
231
- SCOPE_END: 387,
232
- NULLIFIER_START: 388,
233
- NULLIFIER_END: 419,
228
+ PUBKEY_MODULUS_END: 17,
229
+ DOMAIN_STORAGE_START: 18,
230
+ DOMAIN_STORAGE_END: 81,
231
+ DOMAIN_LEN: 82,
232
+ SCOPE_START: 83,
233
+ SCOPE_END: 114,
234
+ NULLIFIER_START: 115,
235
+ NULLIFIER_END: 146,
236
+ PROVIDER: 147,
237
+ /** @deprecated Use DOMAIN_STORAGE_START */
238
+ DOMAIN_START: 18,
239
+ /** @deprecated Use DOMAIN_LEN */
240
+ DOMAIN_END: 82,
234
241
  };
235
242
 
236
243
  /**
@@ -3828,8 +3835,8 @@ function extractScopeFromPublicInputs(publicInputsHex, circuit) {
3828
3835
  end = 117;
3829
3836
  }
3830
3837
  else if (circuit === 'oidc_domain_attestation') {
3831
- start = 356;
3832
- end = 387;
3838
+ start = 83;
3839
+ end = 114;
3833
3840
  }
3834
3841
  else {
3835
3842
  start = 64;
@@ -3865,8 +3872,8 @@ function extractNullifierFromPublicInputs(publicInputsHex, circuit) {
3865
3872
  end = 149;
3866
3873
  }
3867
3874
  else if (circuit === 'oidc_domain_attestation') {
3868
- start = 388;
3869
- end = 419;
3875
+ start = 115;
3876
+ end = 146;
3870
3877
  }
3871
3878
  else {
3872
3879
  start = 96;
@@ -3877,6 +3884,38 @@ function extractNullifierFromPublicInputs(publicInputsHex, circuit) {
3877
3884
  const nullifierFields = publicInputsHex.slice(start, end + 1);
3878
3885
  return reconstructBytes32FromFields(nullifierFields);
3879
3886
  }
3887
+ /**
3888
+ * Extract domain string from OIDC Domain Attestation public inputs.
3889
+ *
3890
+ * The domain is stored as a Noir BoundedVec<u8, 64>, which serializes as
3891
+ * [storage[0..64], len]. Each storage element is a u8 value in a field element.
3892
+ *
3893
+ * @param publicInputsHex - Array of public input hex strings
3894
+ * @param circuit - Circuit identifier (must be 'oidc_domain_attestation')
3895
+ * @returns Domain as ASCII string, or null if circuit doesn't match or inputs are insufficient
3896
+ *
3897
+ * @example
3898
+ * ```typescript
3899
+ * const domain = extractDomainFromPublicInputs(publicInputs, 'oidc_domain_attestation');
3900
+ * console.log(domain); // 'example.com'
3901
+ * ```
3902
+ */
3903
+ function extractDomainFromPublicInputs(publicInputsHex, circuit) {
3904
+ if (circuit !== 'oidc_domain_attestation')
3905
+ return null;
3906
+ const layout = OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT;
3907
+ if (publicInputsHex.length <= layout.DOMAIN_LEN)
3908
+ return null;
3909
+ const len = Number(BigInt(publicInputsHex[layout.DOMAIN_LEN]) & 0xffn);
3910
+ if (len === 0 || len > 64)
3911
+ return null;
3912
+ const storageFields = publicInputsHex.slice(layout.DOMAIN_STORAGE_START, layout.DOMAIN_STORAGE_START + len);
3913
+ const chars = storageFields.map(f => {
3914
+ const byte = Number(BigInt(f) & 0xffn);
3915
+ return String.fromCharCode(byte);
3916
+ });
3917
+ return chars.join('');
3918
+ }
3880
3919
  /** @internal Reconstruct a bytes32 value from 32 individual field elements */
3881
3920
  function reconstructBytes32FromFields(fields) {
3882
3921
  if (fields.length !== 32) {
@@ -5054,6 +5093,27 @@ class ProofportSDK {
5054
5093
  extractNullifier(publicInputs, circuit) {
5055
5094
  return extractNullifierFromPublicInputs(publicInputs, circuit);
5056
5095
  }
5096
+ /**
5097
+ * Extracts the domain string from OIDC Domain Attestation proof public inputs.
5098
+ *
5099
+ * Only works with 'oidc_domain_attestation' circuit. Returns null for other circuits.
5100
+ *
5101
+ * @param publicInputs - Array of hex-encoded field elements from proof result
5102
+ * @param circuit - Circuit type that produced the public inputs
5103
+ * @returns Domain as ASCII string (e.g., 'example.com'), or null if not applicable
5104
+ *
5105
+ * @example
5106
+ * ```typescript
5107
+ * const result = await sdk.waitForProof(relay.requestId);
5108
+ * if (result.status === 'completed') {
5109
+ * const domain = sdk.extractDomain(result.publicInputs, result.circuit);
5110
+ * console.log('Domain:', domain); // 'example.com'
5111
+ * }
5112
+ * ```
5113
+ */
5114
+ extractDomain(publicInputs, circuit) {
5115
+ return extractDomainFromPublicInputs(publicInputs, circuit);
5116
+ }
5057
5117
  }
5058
5118
  /**
5059
5119
  * Creates a proof request through the relay server.
@@ -5092,5 +5152,5 @@ ProofportSDK.WALLET_SIGNATURE_CIRCUITS = [
5092
5152
  'coinbase_country_attestation',
5093
5153
  ];
5094
5154
 
5095
- export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, ProofportSDK, ProofportSDK as default, extractNullifierFromPublicInputs, extractScopeFromPublicInputs };
5155
+ export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, ProofportSDK, ProofportSDK as default, extractDomainFromPublicInputs, extractNullifierFromPublicInputs, extractScopeFromPublicInputs };
5096
5156
  //# sourceMappingURL=index.esm.js.map